From 2f4712d4b07df5f13c82bb2d016878bf55a47017 Mon Sep 17 00:00:00 2001 From: Themaister Date: Sat, 5 Oct 2013 13:37:38 +0200 Subject: [PATCH 01/10] Style nits to core_info. Compile it in. --- Makefile | 1 + Makefile.win | 1 + core_info.c | 44 +++++++++++++++++++++++++------------------- core_info.h | 22 ++++++++++++---------- 4 files changed, 39 insertions(+), 29 deletions(-) diff --git a/Makefile b/Makefile index 6011d5a5f5..08fd696eee 100644 --- a/Makefile +++ b/Makefile @@ -22,6 +22,7 @@ OBJ = frontend/frontend.o \ core_options.o \ compat/compat.o \ cheats.o \ + core_info.o \ conf/config_file.o \ screenshot.o \ gfx/scaler/scaler.o \ diff --git a/Makefile.win b/Makefile.win index 21570b6593..41cf028f4f 100644 --- a/Makefile.win +++ b/Makefile.win @@ -23,6 +23,7 @@ OBJ = frontend/frontend.o \ compat/compat.o \ screenshot.o \ cheats.o \ + core_info.o \ audio/utils.o \ input/overlay.o \ fifo_buffer.o \ diff --git a/core_info.c b/core_info.c index 6d3e1f0657..d10584bcc9 100644 --- a/core_info.c +++ b/core_info.c @@ -23,49 +23,52 @@ core_info_list_t *get_core_info_list(const char *modules_path) { struct string_list *contents = dir_list_new(modules_path, EXT_EXECUTABLES, false); - core_info_t *core_info; - core_info_list_t *core_info_list; - unsigned i; + core_info_t *core_info = NULL; + core_info_list_t *core_info_list = NULL; if (!contents) return NULL; - core_info = (core_info_t*)malloc(contents->size * sizeof(core_info_t)); - memset(core_info, 0, contents->size * sizeof(core_info_t)); + core_info_list = (core_info_list_t*)calloc(1, sizeof(*core_info_list)); + if (!core_info_list) + goto error; + + core_info = (core_info_t*)calloc(contents->size, sizeof(*core_info)); + if (!core_info) + goto error; - core_info_list = (core_info_list_t*)malloc(sizeof(core_info_list_t)); - memset(core_info_list, 0, sizeof(core_info_list_t)); core_info_list->list = core_info; core_info_list->count = contents->size; - for (i = 0; i < contents->size; i ++) + for (size_t i = 0; i < contents->size; i++) { char buffer[PATH_MAX]; char info_path[PATH_MAX]; - char *substr; core_info[i].path = strdup(contents->elems[i].data); + // FIXME: Need to do something about this logic. + // fill_pathname() *should* be sufficient. + // // NOTE: This assumes all modules are named module_name_{tag}.ext // {tag} must not contain an underscore. (This isn't true for PC versions) - snprintf(buffer, PATH_MAX, "%s", contents->elems[i].data); - substr = strrchr(buffer, '_'); + strlcpy(buffer, contents->elems[i].data, sizeof(buffer)); + char *substr = strrchr(buffer, '_'); if (substr) - *substr = 0; + *substr = '\0'; // NOTE: Can't just use fill_pathname on iOS as it will cut at RetroArch.app; // perhaps fill_pathname shouldn't cut before the last path element. if (substr) snprintf(info_path, PATH_MAX, "%s.info", buffer); else - fill_pathname(info_path, buffer, ".info", PATH_MAX); + fill_pathname(info_path, buffer, ".info", sizeof(info_path)); core_info[i].data = config_file_new(info_path); if (core_info[i].data) { config_get_string(core_info[i].data, "display_name", &core_info[i].display_name); - if (config_get_string(core_info[i].data, "supported_extensions", &core_info[i].supported_extensions) && core_info[i].supported_extensions) core_info[i].supported_extensions_list = string_split(core_info[i].supported_extensions, "|"); @@ -76,18 +79,21 @@ core_info_list_t *get_core_info_list(const char *modules_path) } dir_list_free(contents); - return core_info_list; + +error: + if (contents) + dir_list_free(contents); + free_core_info_list(core_info_list); + return NULL; } void free_core_info_list(core_info_list_t *core_info_list) { - int i; - if (!core_info_list) return; - for (i = 0; i < core_info_list->count; i++) + for (size_t i = 0; i < core_info_list->count; i++) { free(core_info_list->list[i].path); free(core_info_list->list[i].display_name); @@ -100,7 +106,7 @@ void free_core_info_list(core_info_list_t *core_info_list) free(core_info_list); } -bool does_core_support_file(core_info_t* core, const char *path) +bool does_core_support_file(core_info_t *core, const char *path) { if (!path || !core || !core->supported_extensions_list) return false; diff --git a/core_info.h b/core_info.h index 28f24ec9d5..3f68b2fa69 100644 --- a/core_info.h +++ b/core_info.h @@ -16,29 +16,31 @@ #ifndef CORE_INFO_H_ #define CORE_INFO_H_ +#include "conf/config_file.h" +#include "file.h" +#include + #ifdef __cplusplus extern "C" { #endif -#include "conf/config_file.h" - typedef struct { - char * path; - config_file_t* data; - char * display_name; - char * supported_extensions; - struct string_list * supported_extensions_list; + char *path; + config_file_t *data; + char *display_name; + char *supported_extensions; + struct string_list *supported_extensions_list; } core_info_t; typedef struct { core_info_t *list; - int count; + size_t count; } core_info_list_t; core_info_list_t *get_core_info_list(const char *modules_path); -void free_core_info_list(core_info_list_t * core_info_list); +void free_core_info_list(core_info_list_t *core_info_list); -bool does_core_support_file(core_info_t* core, const char *path); +bool does_core_support_file(core_info_t *core, const char *path); #ifdef __cplusplus } From a470ae0d04035fa111532f19d73c914b505383f7 Mon Sep 17 00:00:00 2001 From: Themaister Date: Sat, 5 Oct 2013 13:48:08 +0200 Subject: [PATCH 02/10] Use consistent namespace for core_list. --- apple/common/RAModuleInfo.m | 4 ++-- blackberry-qnx/bb10/src/RetroArch-Cascades.cpp | 4 ++-- core_info.c | 8 ++++---- core_info.h | 6 +++--- 4 files changed, 11 insertions(+), 11 deletions(-) diff --git a/apple/common/RAModuleInfo.m b/apple/common/RAModuleInfo.m index 581bd0d116..8a1cbf6984 100644 --- a/apple/common/RAModuleInfo.m +++ b/apple/common/RAModuleInfo.m @@ -26,7 +26,7 @@ NSArray* apple_get_modules() { if (!moduleList) { - coreList = get_core_info_list(apple_platform.coreDirectory.UTF8String); + coreList = core_info_list_new(apple_platform.coreDirectory.UTF8String); if (!coreList) return nil; @@ -182,4 +182,4 @@ static NSString* build_string_pair(NSString* stringA, NSString* stringB) @end -#endif \ No newline at end of file +#endif diff --git a/blackberry-qnx/bb10/src/RetroArch-Cascades.cpp b/blackberry-qnx/bb10/src/RetroArch-Cascades.cpp index e57e8a68ad..c2e14a16dc 100644 --- a/blackberry-qnx/bb10/src/RetroArch-Cascades.cpp +++ b/blackberry-qnx/bb10/src/RetroArch-Cascades.cpp @@ -87,7 +87,7 @@ RetroArch::RetroArch() //Get core DropDown reference to populate it in C++ coreSelection = mAppPane->findChild("dropdown_core"); connect(coreSelection, SIGNAL(selectedValueChanged(QVariant)), this, SLOT(onCoreSelected(QVariant))); - core_info_list = get_core_info_list(g_settings.libretro); + core_info_list = core_info_list_new(g_settings.libretro); populateCores(core_info_list); Application::instance()->setScene(mAppPane); @@ -112,7 +112,7 @@ RetroArch::RetroArch() RetroArch::~RetroArch() { - free_core_info_list(core_info_list); + core_info_list_free(core_info_list); } void RetroArch::aboutToQuit() diff --git a/core_info.c b/core_info.c index d10584bcc9..d7e8c5d593 100644 --- a/core_info.c +++ b/core_info.c @@ -19,7 +19,7 @@ #include "file_ext.h" #include "config.def.h" -core_info_list_t *get_core_info_list(const char *modules_path) +core_info_list_t *core_info_list_new(const char *modules_path) { struct string_list *contents = dir_list_new(modules_path, EXT_EXECUTABLES, false); @@ -84,11 +84,11 @@ core_info_list_t *get_core_info_list(const char *modules_path) error: if (contents) dir_list_free(contents); - free_core_info_list(core_info_list); + core_info_list_free(core_info_list); return NULL; } -void free_core_info_list(core_info_list_t *core_info_list) +void core_info_list_free(core_info_list_t *core_info_list) { if (!core_info_list) return; @@ -106,7 +106,7 @@ void free_core_info_list(core_info_list_t *core_info_list) free(core_info_list); } -bool does_core_support_file(core_info_t *core, const char *path) +bool core_info_list_does_support_file(core_info_t *core, const char *path) { if (!path || !core || !core->supported_extensions_list) return false; diff --git a/core_info.h b/core_info.h index 3f68b2fa69..4148f0db59 100644 --- a/core_info.h +++ b/core_info.h @@ -37,10 +37,10 @@ typedef struct { size_t count; } core_info_list_t; -core_info_list_t *get_core_info_list(const char *modules_path); -void free_core_info_list(core_info_list_t *core_info_list); +core_info_list_t *core_info_list_new(const char *modules_path); +void core_info_list_free(core_info_list_t *core_info_list); -bool does_core_support_file(core_info_t *core, const char *path); +bool core_info_list_does_support_file(core_info_t *core, const char *path); #ifdef __cplusplus } From 050e2375e34ea86367ea11be26f7bee593eea3ee Mon Sep 17 00:00:00 2001 From: Themaister Date: Sat, 5 Oct 2013 17:07:56 +0200 Subject: [PATCH 03/10] Begin implementing core autoselect. --- core_info.c | 65 +++++++++++++++++++- core_info.h | 9 ++- frontend/menu/menu_common.c | 6 ++ frontend/menu/menu_common.h | 7 +++ frontend/menu/menu_settings.c | 4 ++ frontend/menu/rgui.c | 103 +++++++++++++++++++++++++++++--- frontend/menu/rguidisp_bitmap.c | 11 ++-- 7 files changed, 188 insertions(+), 17 deletions(-) diff --git a/core_info.c b/core_info.c index d7e8c5d593..1fbee987a9 100644 --- a/core_info.c +++ b/core_info.c @@ -42,6 +42,7 @@ core_info_list_t *core_info_list_new(const char *modules_path) for (size_t i = 0; i < contents->size; i++) { +#if 0 char buffer[PATH_MAX]; char info_path[PATH_MAX]; @@ -63,6 +64,11 @@ core_info_list_t *core_info_list_new(const char *modules_path) snprintf(info_path, PATH_MAX, "%s.info", buffer); else fill_pathname(info_path, buffer, ".info", sizeof(info_path)); +#else + core_info[i].path = strdup(contents->elems[i].data); + char info_path[PATH_MAX]; + fill_pathname(info_path, core_info[i].path, ".info", sizeof(info_path)); +#endif core_info[i].data = config_file_new(info_path); @@ -78,6 +84,27 @@ core_info_list_t *core_info_list_new(const char *modules_path) core_info[i].display_name = strdup(path_basename(core_info[i].path)); } + size_t all_ext_len = 0; + for (size_t i = 0; i < core_info_list->count; i++) + { + all_ext_len += core_info_list->list[i].supported_extensions ? + (strlen(core_info_list->list[i].supported_extensions) + 2) : 0; + } + + if (all_ext_len) + core_info_list->all_ext = (char*)calloc(1, all_ext_len); + if (core_info_list->all_ext) + { + for (size_t i = 0; i < core_info_list->count; i++) + { + if (core_info_list->list[i].supported_extensions) + { + strlcat(core_info_list->all_ext, core_info_list->list[i].supported_extensions, all_ext_len); + strlcat(core_info_list->all_ext, "|", all_ext_len); + } + } + } + dir_list_free(contents); return core_info_list; @@ -102,11 +129,12 @@ void core_info_list_free(core_info_list_t *core_info_list) config_file_free(core_info_list->list[i].data); } + free(core_info_list->all_ext); free(core_info_list->list); free(core_info_list); } -bool core_info_list_does_support_file(core_info_t *core, const char *path) +bool core_info_does_support_file(const core_info_t *core, const char *path) { if (!path || !core || !core->supported_extensions_list) return false; @@ -114,3 +142,38 @@ bool core_info_list_does_support_file(core_info_t *core, const char *path) return string_list_find_elem_prefix(core->supported_extensions_list, ".", path_get_extension(path)); } +const char *core_info_list_get_all_extensions(core_info_list_t *core_info_list) +{ + return core_info_list->all_ext; +} + +static const char *core_info_tmp_path; // qsort_r() is not in standard C, sadly. +static int core_info_qsort_cmp(const void *a_, const void *b_) +{ + const core_info_t *a = (const core_info_t*)a_; + const core_info_t *b = (const core_info_t*)b_; + int support_a = core_info_does_support_file(a, core_info_tmp_path); + int support_b = core_info_does_support_file(b, core_info_tmp_path); + if (support_a != support_b) + return support_b - support_a; + else + return strcasecmp(a->display_name, b->display_name); +} + +void core_info_list_get_supported_cores(core_info_list_t *core_info_list, const char *path, + const core_info_t **infos, size_t *num_infos) +{ + core_info_tmp_path = path; + qsort(core_info_list->list, core_info_list->count, sizeof(core_info_t), core_info_qsort_cmp); + + size_t supported = 0; + for (size_t i = 0; i < core_info_list->count; i++, supported++) + { + if (!core_info_does_support_file(&core_info_list->list[i], path)) + break; + } + + *infos = core_info_list->list; + *num_infos = supported; +} + diff --git a/core_info.h b/core_info.h index 4148f0db59..cbf4f26d59 100644 --- a/core_info.h +++ b/core_info.h @@ -35,12 +35,19 @@ typedef struct { typedef struct { core_info_t *list; size_t count; + char *all_ext; } core_info_list_t; core_info_list_t *core_info_list_new(const char *modules_path); void core_info_list_free(core_info_list_t *core_info_list); -bool core_info_list_does_support_file(core_info_t *core, const char *path); +bool core_info_does_support_file(const core_info_t *core, const char *path); + +// Non-reentrant, does not allocate. Returns pointer to internal state. +void core_info_list_get_supported_cores(core_info_list_t *core_info_list, const char *path, + const core_info_t **infos, size_t *num_infos); + +const char *core_info_list_get_all_extensions(core_info_list_t *core_info_list); #ifdef __cplusplus } diff --git a/frontend/menu/menu_common.c b/frontend/menu/menu_common.c index 69b07a7278..aedde6103c 100644 --- a/frontend/menu/menu_common.c +++ b/frontend/menu/menu_common.c @@ -408,6 +408,11 @@ static void menu_update_libretro_info(void) #else retro_get_system_info(&rgui->info); #endif + + core_info_list_free(rgui->core_info); + rgui->core_info = NULL; + if (*rgui->libretro_dir) + rgui->core_info = core_info_list_new(rgui->libretro_dir); } bool load_menu_game(void) @@ -513,6 +518,7 @@ void menu_free(void) #endif rom_history_free(rgui->history); + core_info_list_free(rgui->core_info); free(rgui); } diff --git a/frontend/menu/menu_common.h b/frontend/menu/menu_common.h index 198b5f5e69..42b5a3ae8c 100644 --- a/frontend/menu/menu_common.h +++ b/frontend/menu/menu_common.h @@ -24,6 +24,7 @@ #endif #include "../../performance.h" +#include "../../core_info.h" #ifdef HAVE_RGUI #define MENU_TEXTURE_FULLSCREEN false @@ -98,8 +99,10 @@ typedef enum // settings options are done here too RGUI_SETTINGS_OPEN_FILEBROWSER, + RGUI_SETTINGS_OPEN_FILEBROWSER_DEFERRED_CORE, RGUI_SETTINGS_OPEN_HISTORY, RGUI_SETTINGS_CORE, + RGUI_SETTINGS_DEFERRED_CORE, RGUI_SETTINGS_CONFIG, RGUI_SETTINGS_SAVE_CONFIG, RGUI_SETTINGS_CORE_OPTIONS, @@ -288,6 +291,10 @@ typedef struct bool need_refresh; bool msg_force; + core_info_list_t *core_info; + bool defer_core; + char deferred_path[PATH_MAX]; + // Quick jumping indices with L/R. // Rebuilt when parsing directory. size_t scroll_indices[2 * (26 + 2) + 1]; diff --git a/frontend/menu/menu_settings.c b/frontend/menu/menu_settings.c index de739e1694..5031165990 100644 --- a/frontend/menu/menu_settings.c +++ b/frontend/menu/menu_settings.c @@ -610,7 +610,11 @@ int menu_set_settings(unsigned setting, unsigned action) #ifdef HAVE_DYNAMIC case RGUI_LIBRETRO_DIR_PATH: if (action == RGUI_ACTION_START) + { *rgui->libretro_dir = '\0'; + core_info_list_free(rgui->core_info); + rgui->core_info = NULL; + } break; #endif case RGUI_CONFIG_DIR_PATH: diff --git a/frontend/menu/rgui.c b/frontend/menu/rgui.c index 48fce55e8f..2c2cecf113 100644 --- a/frontend/menu/rgui.c +++ b/frontend/menu/rgui.c @@ -227,6 +227,18 @@ static void rgui_resolve_libretro_names(rgui_list_t *list, const char *dir) } } +static void rgui_resolve_supported_cores(rgui_handle_t *rgui) +{ + const core_info_t *info = NULL; + size_t cores = 0; + core_info_list_get_supported_cores(rgui->core_info, rgui->deferred_path, &info, &cores); + for (size_t i = 0; i < cores; i++) + { + rgui_list_push(rgui->selection_buf, info[i].path, RGUI_FILE_PLAIN, 0); + rgui_list_set_alt_at_offset(rgui->selection_buf, i, info[i].display_name); + } +} + static int rgui_settings_toggle_setting(rgui_handle_t *rgui, unsigned setting, rgui_action_t action, unsigned menu_type) { #ifdef HAVE_SHADER_MANAGER @@ -277,7 +289,18 @@ static void rgui_settings_populate_entries(rgui_handle_t *rgui) #endif if (rgui->history) rgui_list_push(rgui->selection_buf, "Load Game (History)", RGUI_SETTINGS_OPEN_HISTORY, 0); - rgui_list_push(rgui->selection_buf, "Load Game", RGUI_SETTINGS_OPEN_FILEBROWSER, 0); + + if (rgui->core_info) + rgui_list_push(rgui->selection_buf, "Load Game (Autodetect Core)", RGUI_SETTINGS_OPEN_FILEBROWSER_DEFERRED_CORE, 0); + + if (rgui->info.library_name || g_extern.system.info.library_name) + { + char load_game_core_msg[64]; + snprintf(load_game_core_msg, sizeof(load_game_core_msg), "Load Game (%s)", + rgui->info.library_name ? rgui->info.library_name : g_extern.system.info.library_name); + rgui_list_push(rgui->selection_buf, load_game_core_msg, RGUI_SETTINGS_OPEN_FILEBROWSER, 0); + } + rgui_list_push(rgui->selection_buf, "Core Options", RGUI_SETTINGS_CORE_OPTIONS, 0); rgui_list_push(rgui->selection_buf, "Video Options", RGUI_SETTINGS_VIDEO_OPTIONS, 0); rgui_list_push(rgui->selection_buf, "Audio Options", RGUI_SETTINGS_AUDIO_OPTIONS, 0); @@ -799,8 +822,10 @@ static int rgui_settings_iterate(rgui_handle_t *rgui, rgui_action_t action) case RGUI_ACTION_RIGHT: case RGUI_ACTION_OK: case RGUI_ACTION_START: - if (type == RGUI_SETTINGS_OPEN_FILEBROWSER && action == RGUI_ACTION_OK) + if ((type == RGUI_SETTINGS_OPEN_FILEBROWSER || type == RGUI_SETTINGS_OPEN_FILEBROWSER_DEFERRED_CORE) + && action == RGUI_ACTION_OK) { + rgui->defer_core = type == RGUI_SETTINGS_OPEN_FILEBROWSER_DEFERRED_CORE; rgui_list_push(rgui->menu_stack, rgui->base_path, RGUI_FILE_DIRECTORY, rgui->selection_ptr); rgui->selection_ptr = 0; rgui->need_refresh = true; @@ -1066,6 +1091,8 @@ static bool rgui_directory_parse(rgui_handle_t *rgui, const char *directory, uns #endif else if (menu_type_is_directory_browser(menu_type)) exts = ""; // we ignore files anyway + else if (rgui->defer_core) + exts = rgui->core_info ? core_info_list_get_all_extensions(rgui->core_info) : ""; else if (rgui->info.valid_extensions) { exts = ext_buf; @@ -1238,7 +1265,23 @@ static int rgui_iterate(void *data, unsigned action) } else #endif - if (menu_type == RGUI_SETTINGS_CORE) + if (menu_type == RGUI_SETTINGS_DEFERRED_CORE) + { + // FIXME: Add for consoles. +#ifdef HAVE_DYNAMIC + strlcpy(g_settings.libretro, path, sizeof(g_settings.libretro)); + libretro_free_system_info(&rgui->info); + libretro_get_system_info(g_settings.libretro, &rgui->info, + &rgui->load_no_rom); + + strlcpy(g_extern.fullpath, rgui->deferred_path, sizeof(g_extern.fullpath)); + g_extern.lifecycle_mode_state |= (1ULL << MODE_LOAD_GAME); + rgui->msg_force = true; + ret = -1; +#endif + rgui_flush_menu_stack_type(rgui, RGUI_SETTINGS); + } + else if (menu_type == RGUI_SETTINGS_CORE) { #if defined(HAVE_DYNAMIC) fill_pathname_join(g_settings.libretro, dir, path, sizeof(g_settings.libretro)); @@ -1346,6 +1389,10 @@ static int rgui_iterate(void *data, unsigned action) else if (menu_type == RGUI_LIBRETRO_DIR_PATH) { strlcpy(rgui->libretro_dir, dir, sizeof(rgui->libretro_dir)); + core_info_list_free(rgui->core_info); + rgui->core_info = NULL; + if (*rgui->libretro_dir) + rgui->core_info = core_info_list_new(rgui->libretro_dir); rgui_flush_menu_stack_type(rgui, RGUI_SETTINGS_PATH_OPTIONS); } else if (menu_type == RGUI_CONFIG_DIR_PATH) @@ -1366,12 +1413,47 @@ static int rgui_iterate(void *data, unsigned action) } else { - fill_pathname_join(g_extern.fullpath, dir, path, sizeof(g_extern.fullpath)); - g_extern.lifecycle_mode_state |= (1ULL << MODE_LOAD_GAME); + if (rgui->defer_core) + { + fill_pathname_join(rgui->deferred_path, dir, path, sizeof(rgui->deferred_path)); - rgui_flush_menu_stack_type(rgui, RGUI_SETTINGS); - rgui->msg_force = true; - ret = -1; + const core_info_t *info = NULL; + size_t supported = 0; + if (rgui->core_info) + core_info_list_get_supported_cores(rgui->core_info, rgui->deferred_path, &info, &supported); + + if (supported == 1) // Can make a decision right now. + { + strlcpy(g_extern.fullpath, rgui->deferred_path, sizeof(g_extern.fullpath)); + + strlcpy(g_settings.libretro, info->path, sizeof(g_settings.libretro)); + +#ifdef HAVE_DYNAMIC + libretro_free_system_info(&rgui->info); + libretro_get_system_info(g_settings.libretro, &rgui->info, + &rgui->load_no_rom); +#endif + + g_extern.lifecycle_mode_state |= (1ULL << MODE_LOAD_GAME); + rgui_flush_menu_stack_type(rgui, RGUI_SETTINGS); + rgui->msg_force = true; + ret = -1; + } + else // Present a selection. + { + rgui_list_push(rgui->menu_stack, rgui->libretro_dir, RGUI_SETTINGS_DEFERRED_CORE, 0); + rgui->need_refresh = true; + } + } + else + { + fill_pathname_join(g_extern.fullpath, dir, path, sizeof(g_extern.fullpath)); + g_extern.lifecycle_mode_state |= (1ULL << MODE_LOAD_GAME); + + rgui_flush_menu_stack_type(rgui, RGUI_SETTINGS); + rgui->msg_force = true; + ret = -1; + } } } break; @@ -1401,6 +1483,7 @@ static int rgui_iterate(void *data, unsigned action) #ifdef HAVE_OVERLAY menu_type == RGUI_SETTINGS_OVERLAY_PRESET || #endif + menu_type == RGUI_SETTINGS_DEFERRED_CORE || menu_type == RGUI_SETTINGS_CORE || menu_type == RGUI_SETTINGS_CONFIG || menu_type == RGUI_SETTINGS_OPEN_HISTORY || @@ -1412,11 +1495,13 @@ static int rgui_iterate(void *data, unsigned action) rgui->scroll_indices_size = 0; if (menu_type == RGUI_SETTINGS_OPEN_HISTORY) history_parse(rgui); - else + else if (menu_type != RGUI_SETTINGS_DEFERRED_CORE) rgui_directory_parse(rgui, dir, menu_type, rgui->selection_buf); if (menu_type == RGUI_SETTINGS_CORE) rgui_resolve_libretro_names(rgui->selection_buf, dir); + else if (menu_type == RGUI_SETTINGS_DEFERRED_CORE) + rgui_resolve_supported_cores(rgui); // Before a refresh, we could have deleted a file on disk, causing // selection_ptr to suddendly be out of range. Ensure it doesn't overflow. diff --git a/frontend/menu/rguidisp_bitmap.c b/frontend/menu/rguidisp_bitmap.c index 8b9332801d..dae7c08f0c 100644 --- a/frontend/menu/rguidisp_bitmap.c +++ b/frontend/menu/rguidisp_bitmap.c @@ -232,6 +232,8 @@ static void render_text(rgui_handle_t *rgui) if (menu_type == RGUI_SETTINGS_CORE) snprintf(title, sizeof(title), "CORE SELECTION %s", dir); + else if (menu_type == RGUI_SETTINGS_DEFERRED_CORE) + snprintf(title, sizeof(title), "DETECTED CORES %s", dir); else if (menu_type == RGUI_SETTINGS_CONFIG) snprintf(title, sizeof(title), "CONFIG %s", dir); else if (menu_type == RGUI_SETTINGS_DISK_APPEND) @@ -360,9 +362,8 @@ static void render_text(rgui_handle_t *rgui) } else #endif -#ifdef HAVE_DYNAMIC // Pretty-print libretro cores from menu. - if (menu_type == RGUI_SETTINGS_CORE) + if (menu_type == RGUI_SETTINGS_CORE || menu_type == RGUI_SETTINGS_DEFERRED_CORE) { if (type == RGUI_FILE_PLAIN) { @@ -377,10 +378,7 @@ static void render_text(rgui_handle_t *rgui) w = 5; } } - else -#endif - if (menu_type == RGUI_SETTINGS_CORE || - menu_type == RGUI_SETTINGS_CONFIG || + else if (menu_type == RGUI_SETTINGS_CONFIG || #ifdef HAVE_OVERLAY menu_type == RGUI_SETTINGS_OVERLAY_PRESET || #endif @@ -568,6 +566,7 @@ static void render_text(rgui_handle_t *rgui) strlcpy(type_str, "", sizeof(type_str)); break; case RGUI_SETTINGS_OPEN_FILEBROWSER: + case RGUI_SETTINGS_OPEN_FILEBROWSER_DEFERRED_CORE: case RGUI_SETTINGS_OPEN_HISTORY: case RGUI_SETTINGS_CORE_OPTIONS: case RGUI_SETTINGS_CUSTOM_VIEWPORT: From aab2d2015160c4baac7133d7aa1a04d382908cc3 Mon Sep 17 00:00:00 2001 From: Themaister Date: Sat, 5 Oct 2013 17:12:27 +0200 Subject: [PATCH 04/10] Some display tweaks. --- frontend/menu/rgui.c | 2 +- frontend/menu/rguidisp_bitmap.c | 18 +++++++++++------- 2 files changed, 12 insertions(+), 8 deletions(-) diff --git a/frontend/menu/rgui.c b/frontend/menu/rgui.c index 2c2cecf113..b47e95dd47 100644 --- a/frontend/menu/rgui.c +++ b/frontend/menu/rgui.c @@ -291,7 +291,7 @@ static void rgui_settings_populate_entries(rgui_handle_t *rgui) rgui_list_push(rgui->selection_buf, "Load Game (History)", RGUI_SETTINGS_OPEN_HISTORY, 0); if (rgui->core_info) - rgui_list_push(rgui->selection_buf, "Load Game (Autodetect Core)", RGUI_SETTINGS_OPEN_FILEBROWSER_DEFERRED_CORE, 0); + rgui_list_push(rgui->selection_buf, "Load Game (Detect Core)", RGUI_SETTINGS_OPEN_FILEBROWSER_DEFERRED_CORE, 0); if (rgui->info.library_name || g_extern.system.info.library_name) { diff --git a/frontend/menu/rguidisp_bitmap.c b/frontend/menu/rguidisp_bitmap.c index dae7c08f0c..7c3c5b3c12 100644 --- a/frontend/menu/rguidisp_bitmap.c +++ b/frontend/menu/rguidisp_bitmap.c @@ -293,13 +293,17 @@ static void render_text(rgui_handle_t *rgui) snprintf(title, sizeof(title), "SYSTEM DIR %s", dir); else { - const char *core_name = rgui->info.library_name; - if (!core_name) - core_name = g_extern.system.info.library_name; - if (!core_name) - core_name = "No Core"; - - snprintf(title, sizeof(title), "GAME (%s) %s", core_name, dir); + if (rgui->defer_core) + snprintf(title, sizeof(title), "GAME %s", dir); + else + { + const char *core_name = rgui->info.library_name; + if (!core_name) + core_name = g_extern.system.info.library_name; + if (!core_name) + core_name = "No Core"; + snprintf(title, sizeof(title), "GAME (%s) %s", core_name, dir); + } } char title_buf[256]; From 3d212c1d7c882b9d55f68b9091a4cb9236b461fa Mon Sep 17 00:00:00 2001 From: Themaister Date: Sat, 5 Oct 2013 18:07:38 +0200 Subject: [PATCH 05/10] Start refactoring file_extract. Add support for low-level parsing of zip contents. --- file.h | 2 + file_extract.c | 165 +++++++++++++++++++++++++++++++++++-------------- file_extract.h | 12 ++++ file_path.c | 4 +- 4 files changed, 135 insertions(+), 48 deletions(-) diff --git a/file.h b/file.h index 24e1cd9519..880734f715 100644 --- a/file.h +++ b/file.h @@ -68,6 +68,8 @@ void dir_list_free(struct string_list *list); bool string_list_find_elem(const struct string_list *list, const char *elem); bool string_list_find_elem_prefix(const struct string_list *list, const char *prefix, const char *elem); struct string_list *string_split(const char *str, const char *delim); +struct string_list *string_list_new(void); +bool string_list_append(struct string_list *list, const char *elem, union string_list_elem_attr attr); void string_list_free(struct string_list *list); bool path_is_directory(const char *path); diff --git a/file_extract.c b/file_extract.c index 74a9b5768d..3bb8dfbd47 100644 --- a/file_extract.c +++ b/file_extract.c @@ -18,6 +18,7 @@ #include "compat/strl.h" #include #include +#include #ifdef WANT_MINIZ #include "deps/miniz/zlib.h" @@ -46,7 +47,7 @@ static uint32_t read_le(const uint8_t *data, unsigned size) return val; } -static bool inflate_data_to_file(const char *path, uint8_t *cdata, +static bool inflate_data_to_file(const char *path, const uint8_t *cdata, uint32_t csize, uint32_t size, uint32_t crc32) { bool ret = true; @@ -60,7 +61,7 @@ static bool inflate_data_to_file(const char *path, uint8_t *cdata, if (inflateInit2(&stream, -MAX_WBITS) != Z_OK) GOTO_END_ERROR(); - stream.next_in = cdata; + stream.next_in = (uint8_t*)cdata; stream.avail_in = csize; stream.next_out = out_data; stream.avail_out = size; @@ -85,24 +86,14 @@ end: return ret; } -bool zlib_extract_first_rom(char *zip_path, size_t zip_path_size, const char *valid_exts) +bool zlib_parse_file(const char *file, zlib_file_cb file_cb, void *userdata) { const uint8_t *footer = NULL; const uint8_t *directory = NULL; bool ret = true; - if (!valid_exts) - { - RARCH_ERR("Libretro implementation does not have any valid extensions. Cannot unzip without knowing this.\n"); - return false; - } - - struct string_list *list = string_split(valid_exts, "|"); - if (!list) - return false; - uint8_t *data = NULL; - ssize_t zip_size = read_file(zip_path, (void**)&data); + ssize_t zip_size = read_file(file, (void**)&data); if (zip_size < 22) GOTO_END_ERROR(); @@ -150,44 +141,126 @@ bool zlib_extract_first_rom(char *zip_path, size_t zip_path_size, const char *va RARCH_LOG("OFFSET: %u, CSIZE: %u, SIZE: %u.\n", offset + 30 + offsetNL + offsetEL, csize, size); - // Extract first ROM that matches our list. - const char *ext = path_get_extension(filename); - if (ext && string_list_find_elem(list, ext)) - { - char new_path[PATH_MAX]; - fill_pathname_resolve_relative(new_path, zip_path, - path_basename(filename), sizeof(new_path)); - - switch (cmode) - { - case 0: // Uncompressed - if (!write_file(new_path, cdata, size)) - GOTO_END_ERROR(); - goto end; - - case 8: // Deflate - if (inflate_data_to_file(new_path, cdata, csize, size, crc32)) - { - strlcpy(zip_path, new_path, zip_path_size); - goto end; - } - else - GOTO_END_ERROR(); - - default: - GOTO_END_ERROR(); - } - } + if (!file_cb(filename, cdata, cmode, csize, size, crc32, userdata)) + break; directory += 46 + namelength + extralength + commentlength; } - RARCH_ERR("Didn't find any ROMS that matched valid extensions for libretro implementation.\n"); - GOTO_END_ERROR(); - end: free(data); - string_list_free(list); return ret; } +struct zip_extract_userdata +{ + char *zip_path; + size_t zip_path_size; + struct string_list *ext; + bool found_rom; +}; + +static bool zip_extract_cb(const char *name, const uint8_t *cdata, unsigned cmode, uint32_t csize, uint32_t size, + uint32_t crc32, void *userdata) +{ + struct zip_extract_userdata *data = (struct zip_extract_userdata*)userdata; + + // Extract first ROM that matches our list. + const char *ext = path_get_extension(name); + if (ext && string_list_find_elem(data->ext, ext)) + { + char new_path[PATH_MAX]; + fill_pathname_resolve_relative(new_path, data->zip_path, + path_basename(name), sizeof(new_path)); + + switch (cmode) + { + case 0: // Uncompressed + data->found_rom = write_file(new_path, cdata, size); + return false; + + case 8: // Deflate + if (inflate_data_to_file(new_path, cdata, csize, size, crc32)) + { + strlcpy(data->zip_path, new_path, data->zip_path_size); + data->found_rom = true; + return false; + } + else + return false; + + default: + return false; + } + } + + return true; +} + +bool zlib_extract_first_rom(char *zip_path, size_t zip_path_size, const char *valid_exts) +{ + if (!valid_exts) + { + RARCH_ERR("Libretro implementation does not have any valid extensions. Cannot unzip without knowing this.\n"); + return false; + } + + bool ret = true; + struct string_list *list = string_split(valid_exts, "|"); + if (!list) + GOTO_END_ERROR(); + + struct zip_extract_userdata userdata = {0}; + userdata.zip_path = zip_path; + userdata.zip_path_size = zip_path_size; + userdata.ext = list; + + if (!zlib_parse_file(zip_path, zip_extract_cb, &userdata)) + { + RARCH_ERR("Parsing ZIP failed.\n"); + GOTO_END_ERROR(); + } + + if (!userdata.found_rom) + { + RARCH_ERR("Didn't find any ROMS that matched valid extensions for libretro implementation.\n"); + GOTO_END_ERROR(); + } + +end: + if (list) + string_list_free(list); + return ret; +} + +static bool zlib_get_file_list_cb(const char *path, const uint8_t *cdata, unsigned cmode, + uint32_t csize, uint32_t size, + uint32_t crc32, void *userdata) +{ + (void)cdata; + (void)cmode; + (void)csize; + (void)size; + (void)crc32; + struct string_list *list = (struct string_list*)userdata; + union string_list_elem_attr attr; + memset(&attr, 0, sizeof(attr)); + return string_list_append(list, path, attr); +} + +struct string_list *zlib_get_file_list(const char *path) +{ + struct string_list *list = string_list_new(); + if (!list) + return NULL; + + if (!zlib_parse_file(path, zlib_get_file_list_cb, list)) + { + RARCH_ERR("Parsing ZIP failed.\n"); + string_list_free(list); + return NULL; + } + else + return list; +} + diff --git a/file_extract.h b/file_extract.h index 8c07e14604..460d23a14d 100644 --- a/file_extract.h +++ b/file_extract.h @@ -17,9 +17,21 @@ #define FILE_EXTRACT_H__ #include "boolean.h" +#include "file.h" #include +#include +// Returns true when parsing should continue. False to stop. +typedef bool (*zlib_file_cb)(const char *name, + const uint8_t *cdata, unsigned cmode, uint32_t csize, uint32_t size, + uint32_t crc32, void *userdata); + +// Low-level file parsing. Enumerates over all files and calls file_cb with userdata. +bool zlib_parse_file(const char *file, zlib_file_cb file_cb, void *userdata); + +// Built with zlib_parse_file. bool zlib_extract_first_rom(char *zip_path, size_t zip_path_size, const char *valid_exts); +struct string_list *zlib_get_file_list(const char *path); #endif diff --git a/file_path.c b/file_path.c index 35c1e5d142..c782585970 100644 --- a/file_path.c +++ b/file_path.c @@ -79,7 +79,7 @@ static bool string_list_capacity(struct string_list *list, size_t cap) return true; } -static struct string_list *string_list_new(void) +struct string_list *string_list_new(void) { struct string_list *list = (struct string_list*)calloc(1, sizeof(*list)); if (!list) @@ -94,7 +94,7 @@ static struct string_list *string_list_new(void) return list; } -static bool string_list_append(struct string_list *list, const char *elem, union string_list_elem_attr attr) +bool string_list_append(struct string_list *list, const char *elem, union string_list_elem_attr attr) { if (list->size >= list->cap && !string_list_capacity(list, list->cap * 2)) From bf0bce64b05ac24151735dbd1c0d5118a5b3538a Mon Sep 17 00:00:00 2001 From: Themaister Date: Sat, 5 Oct 2013 18:33:22 +0200 Subject: [PATCH 06/10] Poke into zip files as well to find matches. --- core_info.c | 51 ++++++++++++++++++++++++++++++++++++++++---- core_info.h | 1 + frontend/menu/rgui.c | 3 ++- 3 files changed, 50 insertions(+), 5 deletions(-) diff --git a/core_info.c b/core_info.c index 1fbee987a9..3d4ac890d2 100644 --- a/core_info.c +++ b/core_info.c @@ -17,8 +17,13 @@ #include "general.h" #include "file.h" #include "file_ext.h" +#include "file_extract.h" #include "config.def.h" +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + core_info_list_t *core_info_list_new(const char *modules_path) { struct string_list *contents = dir_list_new(modules_path, EXT_EXECUTABLES, false); @@ -92,7 +97,11 @@ core_info_list_t *core_info_list_new(const char *modules_path) } if (all_ext_len) + { + all_ext_len += strlen("|zip"); core_info_list->all_ext = (char*)calloc(1, all_ext_len); + } + if (core_info_list->all_ext) { for (size_t i = 0; i < core_info_list->count; i++) @@ -103,6 +112,7 @@ core_info_list_t *core_info_list_new(const char *modules_path) strlcat(core_info_list->all_ext, "|", all_ext_len); } } + strlcat(core_info_list->all_ext, "|zip", all_ext_len); } dir_list_free(contents); @@ -134,6 +144,17 @@ void core_info_list_free(core_info_list_t *core_info_list) free(core_info_list); } +bool core_info_does_support_any_file(const core_info_t *core, const struct string_list *list) +{ + if (!list || !core || !core->supported_extensions_list) + return false; + + for (size_t i = 0; i < list->size; i++) + if (string_list_find_elem_prefix(core->supported_extensions_list, ".", path_get_extension(list->elems[i].data))) + return true; + return false; +} + bool core_info_does_support_file(const core_info_t *core, const char *path) { if (!path || !core || !core->supported_extensions_list) @@ -147,13 +168,20 @@ const char *core_info_list_get_all_extensions(core_info_list_t *core_info_list) return core_info_list->all_ext; } -static const char *core_info_tmp_path; // qsort_r() is not in standard C, sadly. +// qsort_r() is not in standard C, sadly. +static const char *core_info_tmp_path; +static const struct string_list *core_info_tmp_list; + static int core_info_qsort_cmp(const void *a_, const void *b_) { const core_info_t *a = (const core_info_t*)a_; const core_info_t *b = (const core_info_t*)b_; - int support_a = core_info_does_support_file(a, core_info_tmp_path); - int support_b = core_info_does_support_file(b, core_info_tmp_path); + + int support_a = core_info_does_support_any_file(a, core_info_tmp_list) || + core_info_does_support_file(a, core_info_tmp_path); + int support_b = core_info_does_support_any_file(b, core_info_tmp_list) || + core_info_does_support_file(b, core_info_tmp_path); + if (support_a != support_b) return support_b - support_a; else @@ -164,15 +192,30 @@ void core_info_list_get_supported_cores(core_info_list_t *core_info_list, const const core_info_t **infos, size_t *num_infos) { core_info_tmp_path = path; + +#ifdef HAVE_ZLIB + struct string_list *list = NULL; + if (!strcasecmp(path_get_extension(path), "zip")) + list = zlib_get_file_list(path); + core_info_tmp_list = list; +#endif + + // Let supported core come first in list so we can return a pointer to them. qsort(core_info_list->list, core_info_list->count, sizeof(core_info_t), core_info_qsort_cmp); size_t supported = 0; for (size_t i = 0; i < core_info_list->count; i++, supported++) { - if (!core_info_does_support_file(&core_info_list->list[i], path)) + const core_info_t *core = &core_info_list->list[i]; + if (!core_info_does_support_file(core, path) && !core_info_does_support_any_file(core, list)) break; } +#ifdef HAVE_ZLIB + if (list) + string_list_free(list); +#endif + *infos = core_info_list->list; *num_infos = supported; } diff --git a/core_info.h b/core_info.h index cbf4f26d59..92325d6de7 100644 --- a/core_info.h +++ b/core_info.h @@ -42,6 +42,7 @@ core_info_list_t *core_info_list_new(const char *modules_path); void core_info_list_free(core_info_list_t *core_info_list); bool core_info_does_support_file(const core_info_t *core, const char *path); +bool core_info_does_support_any_file(const core_info_t *core, const struct string_list *list); // Non-reentrant, does not allocate. Returns pointer to internal state. void core_info_list_get_supported_cores(core_info_list_t *core_info_list, const char *path, diff --git a/frontend/menu/rgui.c b/frontend/menu/rgui.c index b47e95dd47..13ac67f6c0 100644 --- a/frontend/menu/rgui.c +++ b/frontend/menu/rgui.c @@ -1441,7 +1441,8 @@ static int rgui_iterate(void *data, unsigned action) } else // Present a selection. { - rgui_list_push(rgui->menu_stack, rgui->libretro_dir, RGUI_SETTINGS_DEFERRED_CORE, 0); + rgui_list_push(rgui->menu_stack, rgui->libretro_dir, RGUI_SETTINGS_DEFERRED_CORE, rgui->selection_ptr); + rgui->selection_ptr = 0; rgui->need_refresh = true; } } From fa42aaf9cba4c9c42794bfbbe6b8b1404456cf41 Mon Sep 17 00:00:00 2001 From: Themaister Date: Sat, 5 Oct 2013 18:40:12 +0200 Subject: [PATCH 07/10] Only create autodetect if we have info files. --- frontend/menu/rgui.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/frontend/menu/rgui.c b/frontend/menu/rgui.c index 13ac67f6c0..2909156d3a 100644 --- a/frontend/menu/rgui.c +++ b/frontend/menu/rgui.c @@ -290,7 +290,7 @@ static void rgui_settings_populate_entries(rgui_handle_t *rgui) if (rgui->history) rgui_list_push(rgui->selection_buf, "Load Game (History)", RGUI_SETTINGS_OPEN_HISTORY, 0); - if (rgui->core_info) + if (rgui->core_info && rgui->core_info->count) rgui_list_push(rgui->selection_buf, "Load Game (Detect Core)", RGUI_SETTINGS_OPEN_FILEBROWSER_DEFERRED_CORE, 0); if (rgui->info.library_name || g_extern.system.info.library_name) From 34ce65d9c41e87a0a28569931a22c22fa663b4c7 Mon Sep 17 00:00:00 2001 From: Themaister Date: Sun, 6 Oct 2013 12:16:44 +0200 Subject: [PATCH 08/10] Rework extension files to only consider basename. Only consider last '.' in the basename of a file. --- core_info.c | 21 ++++----------------- file.h | 6 +++++- file_path.c | 6 +++--- 3 files changed, 12 insertions(+), 21 deletions(-) diff --git a/core_info.c b/core_info.c index 3d4ac890d2..6ebf5cf510 100644 --- a/core_info.c +++ b/core_info.c @@ -47,31 +47,18 @@ core_info_list_t *core_info_list_new(const char *modules_path) for (size_t i = 0; i < contents->size; i++) { -#if 0 - char buffer[PATH_MAX]; char info_path[PATH_MAX]; - core_info[i].path = strdup(contents->elems[i].data); - // FIXME: Need to do something about this logic. - // fill_pathname() *should* be sufficient. - // - // NOTE: This assumes all modules are named module_name_{tag}.ext - // {tag} must not contain an underscore. (This isn't true for PC versions) +#if defined(IOS) || defined(HAVE_BB10) || defined(__QNX__) + // Libs are deployed with a suffix (*_ios.dylib, *_qnx.so, etc). + char buffer[PATH_MAX]; strlcpy(buffer, contents->elems[i].data, sizeof(buffer)); char *substr = strrchr(buffer, '_'); if (substr) *substr = '\0'; - - // NOTE: Can't just use fill_pathname on iOS as it will cut at RetroArch.app; - // perhaps fill_pathname shouldn't cut before the last path element. - if (substr) - snprintf(info_path, PATH_MAX, "%s.info", buffer); - else - fill_pathname(info_path, buffer, ".info", sizeof(info_path)); + fill_pathname(info_path, buffer, ".info", sizeof(info_path)); #else - core_info[i].path = strdup(contents->elems[i].data); - char info_path[PATH_MAX]; fill_pathname(info_path, core_info[i].path, ".info", sizeof(info_path)); #endif diff --git a/file.h b/file.h index 880734f715..854c515373 100644 --- a/file.h +++ b/file.h @@ -74,11 +74,14 @@ void string_list_free(struct string_list *list); bool path_is_directory(const char *path); bool path_file_exists(const char *path); + +// Gets extension of file. Only '.'s after the last slash are considered. const char *path_get_extension(const char *path); bool path_mkdir(const char *dir); -// Removes all text after and including the last '.' +// Removes all text after and including the last '.'. +// Only '.'s after the last slash are considered. char *path_remove_extension(char *path); // Returns basename from path. @@ -102,6 +105,7 @@ bool path_is_absolute(const char *path); // Replaces filename extension with 'replace' and outputs result to out_path. // The extension here is considered to be the string from the last '.' to the end. +// Only '.'s after the last slash are considered as extensions. // If no '.' is present, in_path and replace will simply be concatenated. // 'size' is buffer size of 'out_path'. // E.g.: in_path = "/foo/bar/baz/boo.c", replace = ".asm" => out_path = "/foo/bar/baz/boo.asm" diff --git a/file_path.c b/file_path.c index c782585970..a535cc21ae 100644 --- a/file_path.c +++ b/file_path.c @@ -180,7 +180,7 @@ bool string_list_find_elem_prefix(const struct string_list *list, const char *pr const char *path_get_extension(const char *path) { - const char *ext = strrchr(path, '.'); + const char *ext = strrchr(path_basename(path), '.'); if (ext) return ext + 1; else @@ -189,7 +189,7 @@ const char *path_get_extension(const char *path) char *path_remove_extension(char *path) { - char *last = strrchr(path, '.'); + char *last = strrchr(path_basename(path), '.'); if (*last) *last = '\0'; return last; @@ -417,7 +417,7 @@ void fill_pathname(char *out_path, const char *in_path, const char *replace, siz char tmp_path[PATH_MAX]; rarch_assert(strlcpy(tmp_path, in_path, sizeof(tmp_path)) < sizeof(tmp_path)); - char *tok = strrchr(tmp_path, '.'); + char *tok = strrchr(path_basename(tmp_path), '.'); if (tok) *tok = '\0'; From c813e787cb07348dbc216bee5d2581ffd27e7955 Mon Sep 17 00:00:00 2001 From: Themaister Date: Sun, 6 Oct 2013 12:27:08 +0200 Subject: [PATCH 09/10] Add core_info_list_get_display_name. Avoids duped code in RGUI. --- core_info.c | 17 +++++++++++++++++ core_info.h | 2 ++ frontend/menu/rgui.c | 11 +++-------- 3 files changed, 22 insertions(+), 8 deletions(-) diff --git a/core_info.c b/core_info.c index 6ebf5cf510..5be6ade2dd 100644 --- a/core_info.c +++ b/core_info.c @@ -49,6 +49,8 @@ core_info_list_t *core_info_list_new(const char *modules_path) { char info_path[PATH_MAX]; core_info[i].path = strdup(contents->elems[i].data); + if (!core_info[i].path) + break; #if defined(IOS) || defined(HAVE_BB10) || defined(__QNX__) // Libs are deployed with a suffix (*_ios.dylib, *_qnx.so, etc). @@ -131,6 +133,21 @@ void core_info_list_free(core_info_list_t *core_info_list) free(core_info_list); } +bool core_info_list_get_display_name(core_info_list_t *core_info_list, const char *path, char *buf, size_t size) +{ + for (size_t i = 0; i < core_info_list->count; i++) + { + const core_info_t *info = &core_info_list->list[i]; + if (!strcmp(info->path, path) && info->display_name) + { + strlcpy(buf, info->display_name, size); + return true; + } + } + + return false; +} + bool core_info_does_support_any_file(const core_info_t *core, const struct string_list *list) { if (!list || !core || !core->supported_extensions_list) diff --git a/core_info.h b/core_info.h index 92325d6de7..0b25ac56f8 100644 --- a/core_info.h +++ b/core_info.h @@ -50,6 +50,8 @@ void core_info_list_get_supported_cores(core_info_list_t *core_info_list, const const char *core_info_list_get_all_extensions(core_info_list_t *core_info_list); +bool core_info_list_get_display_name(core_info_list_t *core_info_list, const char *path, char *buf, size_t size); + #ifdef __cplusplus } #endif diff --git a/frontend/menu/rgui.c b/frontend/menu/rgui.c index 2909156d3a..29855ff54b 100644 --- a/frontend/menu/rgui.c +++ b/frontend/menu/rgui.c @@ -213,17 +213,12 @@ static void rgui_resolve_libretro_names(rgui_list_t *list, const char *dir) char core_path[PATH_MAX]; fill_pathname_join(core_path, dir, path, sizeof(core_path)); - char info_path[PATH_MAX]; - fill_pathname(info_path, core_path, ".info", sizeof(info_path)); - - config_file_t *conf = config_file_new(info_path); - if (!conf) - continue; char display_name[256]; - if (config_get_array(conf, "display_name", display_name, sizeof(display_name))) + if (rgui->core_info && + core_info_list_get_display_name(rgui->core_info, + core_path, display_name, sizeof(display_name))) rgui_list_set_alt_at_offset(list, i, display_name); - config_file_free(conf); } } From 8c768b0207f9e40ba022f78c873fec41beff27fb Mon Sep 17 00:00:00 2001 From: Themaister Date: Sun, 6 Oct 2013 12:31:04 +0200 Subject: [PATCH 10/10] Move core_info stuff to menu_common. --- frontend/menu/menu_common.c | 34 ++++++++++++++++++++++++++++++++++ frontend/menu/menu_common.h | 3 +++ frontend/menu/rgui.c | 37 ++----------------------------------- 3 files changed, 39 insertions(+), 35 deletions(-) diff --git a/frontend/menu/menu_common.c b/frontend/menu/menu_common.c index aedde6103c..909cc7da52 100644 --- a/frontend/menu/menu_common.c +++ b/frontend/menu/menu_common.c @@ -947,3 +947,37 @@ void menu_key_event(bool down, unsigned keycode, uint32_t character, uint16_t ke (void)key_modifiers; } +void menu_resolve_libretro_names(rgui_list_t *list, const char *dir) +{ + for (size_t i = 0; i < list->size; i++) + { + const char *path; + unsigned type = 0; + rgui_list_get_at_offset(list, i, &path, &type); + if (type != RGUI_FILE_PLAIN) + continue; + + char core_path[PATH_MAX]; + fill_pathname_join(core_path, dir, path, sizeof(core_path)); + + char display_name[256]; + if (rgui->core_info && + core_info_list_get_display_name(rgui->core_info, + core_path, display_name, sizeof(display_name))) + rgui_list_set_alt_at_offset(list, i, display_name); + } +} + +void menu_resolve_supported_cores(rgui_handle_t *rgui) +{ + const core_info_t *info = NULL; + size_t cores = 0; + core_info_list_get_supported_cores(rgui->core_info, rgui->deferred_path, &info, &cores); + for (size_t i = 0; i < cores; i++) + { + rgui_list_push(rgui->selection_buf, info[i].path, RGUI_FILE_PLAIN, 0); + rgui_list_set_alt_at_offset(rgui->selection_buf, i, info[i].display_name); + } +} + + diff --git a/frontend/menu/menu_common.h b/frontend/menu/menu_common.h index 42b5a3ae8c..e7a683bc5e 100644 --- a/frontend/menu/menu_common.h +++ b/frontend/menu/menu_common.h @@ -351,6 +351,9 @@ void shader_manager_set_preset(struct gfx_shader *shader, void menu_ticker_line(char *buf, size_t len, unsigned tick, const char *str, bool selected); +void menu_resolve_libretro_names(rgui_list_t *list, const char *dir); +void menu_resolve_supported_cores(rgui_handle_t *rgui); + void load_menu_game_prepare(void); bool load_menu_game(void); void load_menu_game_history(unsigned game_index); diff --git a/frontend/menu/rgui.c b/frontend/menu/rgui.c index 29855ff54b..d5d9dcc5ef 100644 --- a/frontend/menu/rgui.c +++ b/frontend/menu/rgui.c @@ -201,39 +201,6 @@ static int rgui_core_setting_toggle(unsigned setting, rgui_action_t action) return 0; } -static void rgui_resolve_libretro_names(rgui_list_t *list, const char *dir) -{ - for (size_t i = 0; i < list->size; i++) - { - const char *path; - unsigned type = 0; - rgui_list_get_at_offset(list, i, &path, &type); - if (type != RGUI_FILE_PLAIN) - continue; - - char core_path[PATH_MAX]; - fill_pathname_join(core_path, dir, path, sizeof(core_path)); - - char display_name[256]; - if (rgui->core_info && - core_info_list_get_display_name(rgui->core_info, - core_path, display_name, sizeof(display_name))) - rgui_list_set_alt_at_offset(list, i, display_name); - } -} - -static void rgui_resolve_supported_cores(rgui_handle_t *rgui) -{ - const core_info_t *info = NULL; - size_t cores = 0; - core_info_list_get_supported_cores(rgui->core_info, rgui->deferred_path, &info, &cores); - for (size_t i = 0; i < cores; i++) - { - rgui_list_push(rgui->selection_buf, info[i].path, RGUI_FILE_PLAIN, 0); - rgui_list_set_alt_at_offset(rgui->selection_buf, i, info[i].display_name); - } -} - static int rgui_settings_toggle_setting(rgui_handle_t *rgui, unsigned setting, rgui_action_t action, unsigned menu_type) { #ifdef HAVE_SHADER_MANAGER @@ -1495,9 +1462,9 @@ static int rgui_iterate(void *data, unsigned action) rgui_directory_parse(rgui, dir, menu_type, rgui->selection_buf); if (menu_type == RGUI_SETTINGS_CORE) - rgui_resolve_libretro_names(rgui->selection_buf, dir); + menu_resolve_libretro_names(rgui->selection_buf, dir); else if (menu_type == RGUI_SETTINGS_DEFERRED_CORE) - rgui_resolve_supported_cores(rgui); + menu_resolve_supported_cores(rgui); // Before a refresh, we could have deleted a file on disk, causing // selection_ptr to suddendly be out of range. Ensure it doesn't overflow.