From f4511f6fa4c587c6f5fd3e945e4652d584a43a36 Mon Sep 17 00:00:00 2001
From: jdgleaver <james@leaver.myzen.co.uk>
Date: Mon, 26 Apr 2021 14:24:24 +0100
Subject: [PATCH] (core_info) Performance optimisations + code
 clean-ups/refactors

---
 core_info.c                                   | 935 ++++++++----------
 core_info.h                                   |  48 +-
 .../gfx_widget_load_content_animation.c       |  21 +-
 menu/cbs/menu_cbs_get_value.c                 |  47 +-
 menu/cbs/menu_cbs_ok.c                        |  84 +-
 menu/cbs/menu_cbs_start.c                     |  12 +-
 menu/cbs/menu_cbs_sublabel.c                  |  10 +-
 menu/cbs/menu_cbs_title.c                     |  29 +-
 menu/drivers/materialui.c                     |   2 +-
 menu/drivers/ozone/ozone.c                    |   2 +-
 menu/drivers/stripes.c                        |   2 +-
 menu/drivers/xmb.c                            |   2 +-
 menu/menu_displaylist.c                       |  26 +-
 playlist.c                                    |  18 +-
 retroarch.c                                   |  18 +-
 runtime_file.c                                |  11 +-
 tasks/task_core_backup.c                      |  28 +-
 tasks/task_playlist_manager.c                 |  11 +-
 ui/drivers/qt/qt_playlist.cpp                 |  11 +-
 ui/drivers/ui_qt.cpp                          |  46 +-
 20 files changed, 582 insertions(+), 781 deletions(-)

diff --git a/core_info.c b/core_info.c
index 3348d8956d..a2a6b1b5f3 100644
--- a/core_info.c
+++ b/core_info.c
@@ -50,6 +50,312 @@ enum compare_op
    COMPARE_OP_GREATER_EQUAL
 };
 
+static uint32_t core_info_hash_string(const char *str)
+{
+   unsigned char c;
+   uint32_t hash = (uint32_t)0x811c9dc5;
+   while ((c = (unsigned char)*(str++)) != '\0')
+      hash = ((hash * (uint32_t)0x01000193) ^ (uint32_t)c);
+   return (hash ? hash : 1);
+}
+
+static bool core_info_get_file_id(const char *core_filename,
+      char *core_file_id, size_t len)
+{
+   char *last_underscore = NULL;
+
+   if (string_is_empty(core_filename))
+      return false;
+
+   /* Core file 'id' is filename without extension
+    * or platform-specific suffix */
+
+   /* > Remove extension */
+   strlcpy(core_file_id, core_filename, len);
+   path_remove_extension(core_file_id);
+
+   /* > Remove suffix */
+   last_underscore = (char*)strrchr(core_file_id, '_');
+
+   if (!string_is_empty(last_underscore) &&
+       !string_is_equal(last_underscore, "_libretro"))
+      *last_underscore = '\0';
+
+   return !string_is_empty(core_file_id);
+}
+
+static core_info_t *core_info_find_internal(
+      core_info_list_t *list,
+      const char *core_path)
+{
+   char core_file_id[256];
+   uint32_t hash;
+   size_t i;
+
+   core_file_id[0] = '\0';
+
+   if (!list ||
+       string_is_empty(core_path) ||
+       !core_info_get_file_id(path_basename_nocompression(core_path),
+            core_file_id, sizeof(core_file_id)))
+      return NULL;
+
+   hash = core_info_hash_string(core_file_id);
+
+   for (i = 0; i < list->count; i++)
+   {
+      core_info_t *info = &list->list[i];
+
+      if (info->core_file_id.hash == hash)
+         return info;
+   }
+
+   return NULL;
+}
+
+static void core_info_resolve_firmware(
+      core_info_t *info, config_file_t *conf)
+{
+   unsigned i;
+   unsigned firmware_count        = 0;
+   core_info_firmware_t *firmware = NULL;
+
+   if (!config_get_uint(conf, "firmware_count", &firmware_count))
+      return;
+
+   firmware = (core_info_firmware_t*)calloc(firmware_count, sizeof(*firmware));
+
+   if (!firmware)
+      return;
+
+   for (i = 0; i < firmware_count; i++)
+   {
+      char path_key[64];
+      char desc_key[64];
+      char opt_key[64];
+      struct config_entry_list *entry = NULL;
+      bool tmp_bool                   = false;
+
+      path_key[0] = '\0';
+      desc_key[0] = '\0';
+      opt_key[0]  = '\0';
+
+      snprintf(path_key, sizeof(path_key), "firmware%u_path", i);
+      snprintf(desc_key, sizeof(desc_key), "firmware%u_desc", i);
+      snprintf(opt_key,  sizeof(opt_key),  "firmware%u_opt",  i);
+
+      entry = config_get_entry(conf, path_key);
+
+      if (entry && !string_is_empty(entry->value))
+      {
+         firmware[i].path = entry->value;
+         entry->value     = NULL;
+      }
+
+      entry = config_get_entry(conf, desc_key);
+
+      if (entry && !string_is_empty(entry->value))
+      {
+         firmware[i].desc = entry->value;
+         entry->value     = NULL;
+      }
+
+      if (config_get_bool(conf, opt_key , &tmp_bool))
+         firmware[i].optional = tmp_bool;
+   }
+
+   info->firmware_count = firmware_count;
+   info->firmware       = firmware;
+}
+
+static config_file_t *core_info_get_config_file(
+      const char *core_file_id,
+      const char *info_dir)
+{
+   char info_path[PATH_MAX_LENGTH];
+
+   info_path[0] = '\0';
+
+   if (string_is_empty(info_dir))
+      strlcpy(info_path, core_file_id, sizeof(info_path));
+   else
+      fill_pathname_join(info_path, info_dir, core_file_id,
+            sizeof(info_path));
+
+   strlcat(info_path, ".info", sizeof(info_path));
+
+   return config_file_new_from_path_to_string(info_path);
+}
+
+static void core_info_parse_config_file(
+      core_info_list_t *list, core_info_t *info,
+      config_file_t *conf)
+{
+   struct config_entry_list *entry = NULL;
+   bool tmp_bool                   = false;
+
+   entry = config_get_entry(conf, "display_name");
+
+   if (entry && !string_is_empty(entry->value))
+   {
+      info->display_name = entry->value;
+      entry->value       = NULL;
+   }
+
+   entry = config_get_entry(conf, "display_version");
+
+   if (entry && !string_is_empty(entry->value))
+   {
+      info->display_version = entry->value;
+      entry->value          = NULL;
+   }
+
+   entry = config_get_entry(conf, "corename");
+
+   if (entry && !string_is_empty(entry->value))
+   {
+      info->core_name = entry->value;
+      entry->value    = NULL;
+   }
+
+   entry = config_get_entry(conf, "systemname");
+
+   if (entry && !string_is_empty(entry->value))
+   {
+      info->systemname = entry->value;
+      entry->value     = NULL;
+   }
+
+   entry = config_get_entry(conf, "systemid");
+
+   if (entry && !string_is_empty(entry->value))
+   {
+      info->system_id = entry->value;
+      entry->value    = NULL;
+   }
+
+   entry = config_get_entry(conf, "manufacturer");
+
+   if (entry && !string_is_empty(entry->value))
+   {
+      info->system_manufacturer = entry->value;
+      entry->value              = NULL;
+   }
+
+   entry = config_get_entry(conf, "supported_extensions");
+
+   if (entry && !string_is_empty(entry->value))
+   {
+      info->supported_extensions      = entry->value;
+      entry->value                    = NULL;
+
+      info->supported_extensions_list =
+            string_split(info->supported_extensions, "|");
+   }
+
+   entry = config_get_entry(conf, "authors");
+
+   if (entry && !string_is_empty(entry->value))
+   {
+      info->authors      = entry->value;
+      entry->value       = NULL;
+
+      info->authors_list =
+            string_split(info->authors, "|");
+   }
+
+   entry = config_get_entry(conf, "permissions");
+
+   if (entry && !string_is_empty(entry->value))
+   {
+      info->permissions      = entry->value;
+      entry->value           = NULL;
+
+      info->permissions_list =
+            string_split(info->permissions, "|");
+   }
+
+   entry = config_get_entry(conf, "license");
+
+   if (entry && !string_is_empty(entry->value))
+   {
+      info->licenses      = entry->value;
+      entry->value        = NULL;
+
+      info->licenses_list =
+            string_split(info->licenses, "|");
+   }
+
+   entry = config_get_entry(conf, "categories");
+
+   if (entry && !string_is_empty(entry->value))
+   {
+      info->categories      = entry->value;
+      entry->value          = NULL;
+
+      info->categories_list =
+            string_split(info->categories, "|");
+   }
+
+   entry = config_get_entry(conf, "database");
+
+   if (entry && !string_is_empty(entry->value))
+   {
+      info->databases      = entry->value;
+      entry->value         = NULL;
+
+      info->databases_list =
+            string_split(info->databases, "|");
+   }
+
+   entry = config_get_entry(conf, "notes");
+
+   if (entry && !string_is_empty(entry->value))
+   {
+      info->notes     = entry->value;
+      entry->value    = NULL;
+
+      info->note_list =
+            string_split(info->notes, "|");
+   }
+
+   entry = config_get_entry(conf, "required_hw_api");
+
+   if (entry && !string_is_empty(entry->value))
+   {
+      info->required_hw_api      = entry->value;
+      entry->value               = NULL;
+
+      info->required_hw_api_list =
+            string_split(info->required_hw_api, "|");
+   }
+
+   entry = config_get_entry(conf, "description");
+
+   if (entry && !string_is_empty(entry->value))
+   {
+      info->description = entry->value;
+      entry->value      = NULL;
+   }
+
+   if (config_get_bool(conf, "supports_no_game",
+            &tmp_bool))
+      info->supports_no_game = tmp_bool;
+
+   if (config_get_bool(conf, "database_match_archive_member",
+            &tmp_bool))
+      info->database_match_archive_member = tmp_bool;
+
+   if (config_get_bool(conf, "is_experimental",
+            &tmp_bool))
+      info->is_experimental = tmp_bool;
+
+   core_info_resolve_firmware(info, conf);
+
+   info->has_info = true;
+   list->info_count++;
+}
+
 static void core_info_list_resolve_all_extensions(
       core_info_list_t *core_info_list)
 {
@@ -90,59 +396,6 @@ static void core_info_list_resolve_all_extensions(
 #endif
 }
 
-static void core_info_list_resolve_all_firmware(
-      core_info_list_t *core_info_list)
-{
-   size_t i;
-   unsigned c;
-
-   for (i = 0; i < core_info_list->count; i++)
-   {
-      unsigned count                  = 0;
-      core_info_firmware_t *firmware  = NULL;
-      core_info_t *info               = (core_info_t*)&core_info_list->list[i];
-      config_file_t *config           = (config_file_t*)info->config_data;
-
-      if (!config || !config_get_uint(config, "firmware_count", &count))
-         continue;
-
-      firmware = (core_info_firmware_t*)calloc(count, sizeof(*firmware));
-
-      if (!firmware)
-         continue;
-
-      info->firmware = firmware;
-
-      for (c = 0; c < count; c++)
-      {
-         char path_key[64];
-         char desc_key[64];
-         char opt_key[64];
-         struct config_entry_list 
-            *entry         = NULL;
-         bool tmp_bool     = false;
-         path_key[0]       = desc_key[0] = opt_key[0] = '\0';
-
-         snprintf(path_key, sizeof(path_key), "firmware%u_path", c);
-         snprintf(desc_key, sizeof(desc_key), "firmware%u_desc", c);
-         snprintf(opt_key,  sizeof(opt_key),  "firmware%u_opt",  c);
-
-         entry             = config_get_entry(config, path_key);
-
-         if (entry && !string_is_empty(entry->value))
-            info->firmware[c].path = strdup(entry->value);
-
-         entry             = config_get_entry(config, desc_key);
-
-         if (entry && !string_is_empty(entry->value))
-            info->firmware[c].desc     = strdup(entry->value);
-
-         if (config_get_bool(config, opt_key , &tmp_bool))
-            info->firmware[c].optional = tmp_bool;
-      }
-   }
-}
-
 static void core_info_list_free(core_info_list_t *core_info_list)
 {
    size_t i, j;
@@ -178,7 +431,6 @@ static void core_info_list_free(core_info_list_t *core_info_list)
       string_list_free(info->categories_list);
       string_list_free(info->databases_list);
       string_list_free(info->required_hw_api_list);
-      config_file_free((config_file_t*)info->config_data);
 
       for (j = 0; j < info->firmware_count; j++)
       {
@@ -195,42 +447,6 @@ static void core_info_list_free(core_info_list_t *core_info_list)
    free(core_info_list);
 }
 
-static config_file_t *core_info_list_iterate(
-      const char *current_path,
-      const char *path_basedir)
-{
-   char info_path[PATH_MAX_LENGTH];
-   char info_path_base[PATH_MAX_LENGTH];
-
-   if (!current_path)
-      return NULL;
-
-   info_path     [0]          = '\0';
-   info_path_base[0]          = '\0';
-
-   fill_pathname_base_noext(info_path_base,
-         current_path,
-         sizeof(info_path_base));
-
-#if defined(RARCH_MOBILE) || (defined(RARCH_CONSOLE) && !defined(PSP) && !defined(_3DS) && !defined(VITA) && !defined(HW_WUP))
-   {
-      char *substr = strrchr(info_path_base, '_');
-      if (substr)
-         *substr = '\0';
-   }
-#endif
-
-   strlcat(info_path_base, ".info", sizeof(info_path_base));
-
-   fill_pathname_join(info_path,
-         path_basedir,
-         info_path_base, sizeof(info_path_base));
-
-   if (path_is_valid(info_path))
-      return config_file_new_from_path_to_string(info_path);
-   return NULL;
-}
-
 static core_info_list_t *core_info_list_new(const char *path,
       const char *libretro_info_dir,
       const char *exts,
@@ -240,14 +456,13 @@ static core_info_list_t *core_info_list_new(const char *path,
    struct string_list contents      = {0};
    core_info_t *core_info           = NULL;
    core_info_list_t *core_info_list = NULL;
-   const char       *path_basedir   = libretro_info_dir;
-   bool                          ok = false;
+   const char *info_dir             = libretro_info_dir;
+   bool ok                          = false;
 
    string_list_initialize(&contents);
 
-   if (dir_list_append(&contents, path, exts,
-         false, dir_show_hidden_files, false, false))
-      ok                            = true;
+   ok = dir_list_append(&contents, path, exts,
+         false, dir_show_hidden_files, false, false);
 
 #if defined(__WINRT__) || defined(WINAPI_FAMILY) && WINAPI_FAMILY == WINAPI_FAMILY_PHONE_APP
    {
@@ -264,7 +479,7 @@ static core_info_list_t *core_info_list_new(const char *path,
       }
    }
 #else
-   /* Keep the old 'directory not found' behavior */
+   /* Keep the old 'directory not found' behaviour */
    if (!ok)
       goto error;
 #endif
@@ -273,12 +488,12 @@ static core_info_list_t *core_info_list_new(const char *path,
    if (!core_info_list)
       goto error;
 
-   core_info_list->list    = NULL;
-   core_info_list->count   = 0;
-   core_info_list->all_ext = NULL;
+   core_info_list->list       = NULL;
+   core_info_list->count      = 0;
+   core_info_list->info_count = 0;
+   core_info_list->all_ext    = NULL;
 
-   core_info               = (core_info_t*)
-      calloc(contents.size, sizeof(*core_info));
+   core_info = (core_info_t*)calloc(contents.size, sizeof(*core_info));
 
    if (!core_info)
    {
@@ -286,192 +501,50 @@ static core_info_list_t *core_info_list_new(const char *path,
       goto error;
    }
 
-   core_info_list->list    = core_info;
-   core_info_list->count   = contents.size;
+   core_info_list->list  = core_info;
+   core_info_list->count = contents.size;
 
    for (i = 0; i < contents.size; i++)
    {
-      const char *base_path = contents.elems[i].data;
-      config_file_t *conf   = core_info_list_iterate(base_path,
-            path_basedir);
+      core_info_t *info         = &core_info[i];
+      const char *base_path     = contents.elems[i].data;
+      const char *core_filename = NULL;
+      config_file_t *conf       = NULL;
+      char core_file_id[256];
+
+      core_file_id[0] = '\0';
+
+      if (string_is_empty(base_path) ||
+          !(core_filename = path_basename_nocompression(base_path)) ||
+          !core_info_get_file_id(core_filename, core_file_id,
+               sizeof(core_file_id)))
+         continue;
+
+      /* Cache core path */
+      info->path = strdup(base_path);
+
+      /* Get core lock status */
+      info->is_locked = core_info_get_core_lock(info->path, false);
+
+      /* Cache core file 'id' */
+      info->core_file_id.str  = strdup(core_file_id);
+      info->core_file_id.hash = core_info_hash_string(core_file_id);
+
+      /* Parse core info file */
+      conf = core_info_get_config_file(core_file_id, info_dir);
 
       if (conf)
       {
-         bool tmp_bool      = false;
-         unsigned tmp_uint  = 0;
-         struct config_entry_list 
-            *entry = config_get_entry(conf, "display_name");
-
-         if (entry && !string_is_empty(entry->value))
-            core_info[i].display_name = strdup(entry->value);
-
-         entry = config_get_entry(conf, "display_version");
-
-         if (entry && !string_is_empty(entry->value))
-            core_info[i].display_version = strdup(entry->value);
-
-         entry = config_get_entry(conf, "corename");
-
-         if (entry && !string_is_empty(entry->value))
-            core_info[i].core_name = strdup(entry->value);
-
-         entry = config_get_entry(conf, "systemname");
-
-         if (entry && !string_is_empty(entry->value))
-               core_info[i].systemname = strdup(entry->value);
-
-         entry = config_get_entry(conf, "systemid");
-
-         if (entry && !string_is_empty(entry->value))
-            core_info[i].system_id = strdup(entry->value);
-
-         entry = config_get_entry(conf, "manufacturer");
-
-         if (entry && !string_is_empty(entry->value))
-            core_info[i].system_manufacturer = strdup(entry->value);
-
-         config_get_uint(conf, "firmware_count", &tmp_uint);
-         core_info[i].firmware_count = tmp_uint;
-
-         entry = config_get_entry(conf, "supported_extensions");
-
-         if (entry && !string_is_empty(entry->value))
-         {
-            core_info[i].supported_extensions      = strdup(entry->value);
-            core_info[i].supported_extensions_list =
-               string_split(core_info[i].supported_extensions, "|");
-         }
-
-         entry = config_get_entry(conf, "authors");
-
-         if (entry && !string_is_empty(entry->value))
-         {
-            core_info[i].authors      = strdup(entry->value);
-            core_info[i].authors_list =
-               string_split(core_info[i].authors, "|");
-         }
-
-         entry = config_get_entry(conf, "permissions");
-
-         if (entry && !string_is_empty(entry->value))
-         {
-            core_info[i].permissions      = strdup(entry->value);
-            core_info[i].permissions_list =
-               string_split(core_info[i].permissions, "|");
-         }
-
-         entry = config_get_entry(conf, "license");
-
-         if (entry && !string_is_empty(entry->value))
-         {
-            core_info[i].licenses      = strdup(entry->value);
-            core_info[i].licenses_list =
-               string_split(core_info[i].licenses, "|");
-         }
-
-         entry = config_get_entry(conf, "categories");
-
-         if (entry && !string_is_empty(entry->value))
-         {
-            core_info[i].categories      = strdup(entry->value);
-            core_info[i].categories_list =
-               string_split(core_info[i].categories, "|");
-         }
-
-         entry = config_get_entry(conf, "database");
-
-         if (entry && !string_is_empty(entry->value))
-         {
-            core_info[i].databases      = strdup(entry->value);
-            core_info[i].databases_list =
-               string_split(core_info[i].databases, "|");
-         }
-
-         entry = config_get_entry(conf, "notes");
-
-         if (entry && !string_is_empty(entry->value))
-         {
-            core_info[i].notes     = strdup(entry->value);
-            core_info[i].note_list =
-               string_split(core_info[i].notes, "|");
-         }
-
-         entry = config_get_entry(conf, "required_hw_api");
-
-         if (entry && !string_is_empty(entry->value))
-         {
-            core_info[i].required_hw_api      = strdup(entry->value);
-            core_info[i].required_hw_api_list =
-               string_split(core_info[i].required_hw_api, "|");
-         }
-
-         entry = config_get_entry(conf, "description");
-
-         if (entry && !string_is_empty(entry->value))
-            core_info[i].description = strdup(entry->value);
-
-         if (config_get_bool(conf, "supports_no_game",
-                  &tmp_bool))
-            core_info[i].supports_no_game = tmp_bool;
-
-         if (config_get_bool(conf, "database_match_archive_member",
-                  &tmp_bool))
-            core_info[i].database_match_archive_member = tmp_bool;
-
-         if (config_get_bool(conf, "is_experimental",
-                  &tmp_bool))
-            core_info[i].is_experimental = tmp_bool;
-
-         core_info[i].config_data = conf;
+         core_info_parse_config_file(core_info_list, info, conf);
+         config_file_free(conf);
       }
 
-      if (!string_is_empty(base_path))
-      {
-         const char *core_filename = path_basename(base_path);
-
-         /* Cache core path */
-         core_info[i].path = strdup(base_path);
-
-         /* Cache core file 'id'
-          * > Filename without extension or platform-specific suffix */
-         if (!string_is_empty(core_filename))
-         {
-            char *core_file_id = strdup(core_filename);
-            path_remove_extension(core_file_id);
-
-            if (!string_is_empty(core_file_id))
-            {
-               /* TODO/FIXME - we should find a cleaner way to do this
-                * instead of this preprocessor hackery */
-#if defined(RARCH_MOBILE) || (defined(RARCH_CONSOLE) && !defined(PSP) && !defined(_3DS) && !defined(VITA) && !defined(HW_WUP))
-               char *last_underscore = strrchr(core_file_id, '_');
-               if (last_underscore)
-                  *last_underscore = '\0';
-#endif
-               core_info[i].core_file_id.str = core_file_id;
-               core_info[i].core_file_id.len = strlen(core_file_id);
-
-               core_file_id = NULL;
-            }
-
-            if (core_file_id)
-            {
-               free(core_file_id);
-               core_file_id = NULL;
-            }
-
-            /* Get fallback display name, if required */
-            if (!core_info[i].display_name)
-               core_info[i].display_name = strdup(core_filename);
-         }
-      }
-
-      /* Get core lock status */
-      core_info[i].is_locked = core_info_get_core_lock(core_info[i].path, false);
+      /* Get fallback display name, if required */
+      if (!info->display_name)
+         info->display_name = strdup(core_filename);
    }
 
    core_info_list_resolve_all_extensions(core_info_list);
-   core_info_list_resolve_all_firmware(core_info_list);
 
    string_list_deinitialize(&contents);
    return core_info_list;
@@ -486,32 +559,20 @@ error:
  * Data in *info is invalidated when the
  * core_info_list is freed. */
 bool core_info_list_get_info(core_info_list_t *core_info_list,
-      core_info_t *out_info, const char *path)
+      core_info_t *out_info, const char *core_path)
 {
-   size_t i;
-   const char *core_filename = NULL;
+   core_info_t *info = core_info_find_internal(
+         core_info_list, core_path);
 
-   if (!core_info_list || !out_info || string_is_empty(path))
-      return false;
-
-   core_filename = path_basename(path);
-   if (string_is_empty(core_filename))
+   if (!out_info)
       return false;
 
    memset(out_info, 0, sizeof(*out_info));
 
-   for (i = 0; i < core_info_list->count; i++)
+   if (info)
    {
-      const core_info_t *info = &core_info_list->list[i];
-
-      if (!info || (info->core_file_id.len == 0))
-         continue;
-
-      if (!strncmp(info->core_file_id.str, core_filename, info->core_file_id.len))
-      {
-         *out_info = *info;
-         return true;
-      }
+      *out_info = *info;
+      return true;
    }
 
    return false;
@@ -568,37 +629,9 @@ static int core_info_qsort_cmp(const void *a_, const void *b_)
    return strcasecmp(a->display_name, b->display_name);
 }
 
-static core_info_t *core_info_find_internal(
-      core_info_list_t *list,
-      const char *core)
-{
-   size_t i;
-   const char *core_filename = NULL;
-
-   if (!list || string_is_empty(core))
-      return NULL;
-
-   core_filename = path_basename_nocompression(core);
-   if (string_is_empty(core_filename))
-      return NULL;
-
-   for (i = 0; i < list->count; i++)
-   {
-      core_info_t *info = core_info_get(list, i);
-
-      if (!info || (info->core_file_id.len == 0))
-         continue;
-
-      if (!strncmp(info->core_file_id.str, core_filename, info->core_file_id.len))
-         return info;
-   }
-
-   return NULL;
-}
-
 static bool core_info_list_update_missing_firmware_internal(
       core_info_list_t *core_info_list,
-      const char *core,
+      const char *core_path,
       const char *systemdir,
       bool *set_missing_bios)
 {
@@ -606,10 +639,10 @@ static bool core_info_list_update_missing_firmware_internal(
    char path[PATH_MAX_LENGTH];
    core_info_t      *info = NULL;
 
-   if (!core_info_list || !core)
+   if (!core_info_list)
       return false;
 
-   info                   = core_info_find_internal(core_info_list, core);
+   info                   = core_info_find_internal(core_info_list, core_path);
 
    if (!info)
       return false;
@@ -645,13 +678,13 @@ bool core_info_init_current_core(void)
       malloc(sizeof(*current));
    if (!current)
       return false;
+   current->has_info                      = false;
    current->supports_no_game              = false;
    current->database_match_archive_member = false;
    current->is_experimental               = false;
    current->is_locked                     = false;
    current->firmware_count                = 0;
    current->path                          = NULL;
-   current->config_data                   = NULL;
    current->display_name                  = NULL;
    current->display_version               = NULL;
    current->core_name                     = NULL;
@@ -677,8 +710,7 @@ bool core_info_init_current_core(void)
    current->required_hw_api_list          = NULL;
    current->firmware                      = NULL;
    current->core_file_id.str              = NULL;
-   current->core_file_id.len              = 0;
-   current->userdata                      = NULL;
+   current->core_file_id.hash             = 0;
 
    p_coreinfo->current                    = current;
    return true;
@@ -743,15 +775,11 @@ bool core_info_list_update_missing_firmware(core_info_ctx_firmware_t *info,
          set_missing_bios);
 }
 
-bool core_info_load(
-      core_info_ctx_find_t *info,
+bool core_info_load(const char *core_path,
       core_info_state_t *p_coreinfo)
 {
    core_info_t    *core_info     = NULL;
 
-   if (!info)
-      return false;
-
    if (!p_coreinfo->current)
       core_info_init_current_core();
 
@@ -761,24 +789,27 @@ bool core_info_load(
       return false;
 
    if (!core_info_list_get_info(p_coreinfo->curr_list,
-            core_info, info->path))
+            core_info, core_path))
       return false;
 
    return true;
 }
 
-bool core_info_find(core_info_ctx_find_t *info)
+bool core_info_find(const char *core_path,
+      core_info_t **core_info)
 {
    core_info_state_t *p_coreinfo = coreinfo_get_ptr();
+   core_info_t *info             = NULL;
 
-   if (!info || !p_coreinfo->curr_list)
+   if (!core_info || !p_coreinfo->curr_list)
       return false;
 
-   info->inf = core_info_find_internal(p_coreinfo->curr_list, info->path);
+   info = core_info_find_internal(p_coreinfo->curr_list, core_path);
 
-   if (!info->inf)
+   if (!info)
       return false;
 
+   *core_info = info;
    return true;
 }
 
@@ -786,7 +817,7 @@ core_info_t *core_info_get(core_info_list_t *list, size_t i)
 {
    core_info_t *info = NULL;
 
-   if (!list)
+   if (!list || (i >= list->count))
       return NULL;
    info = (core_info_t*)&list->list[i];
    if (!info || !info->path)
@@ -846,120 +877,31 @@ void core_info_list_get_supported_cores(core_info_list_t *core_info_list,
 }
 
 /*
- * Matches core path A and B "base" filename (ignoring 
- * everything after _libretro)
+ * Matches core A and B file IDs
  *
- * Ex:
+ * e.g.:
  *   snes9x_libretro.dll and snes9x_libretro_android.so are matched
  *   snes9x__2005_libretro.dll and snes9x_libretro_android.so are 
  *   NOT matched
  */
-bool core_info_core_file_id_is_equal(const char* core_path_a,
-      const char* core_path_b)
+bool core_info_core_file_id_is_equal(const char *core_path_a,
+      const char *core_path_b)
 {
-   const char *core_path_basename_a = NULL;
+   char core_file_id_a[256];
+   char core_file_id_b[256];
 
-   if (!core_path_a || !core_path_b)
+   core_file_id_a[0] = '\0';
+   core_file_id_b[0] = '\0';
+
+   if (string_is_empty(core_path_a) ||
+       string_is_empty(core_path_b) ||
+       !core_info_get_file_id(path_basename_nocompression(core_path_a),
+            core_file_id_a, sizeof(core_file_id_a)) ||
+       !core_info_get_file_id(path_basename_nocompression(core_path_b),
+            core_file_id_b, sizeof(core_file_id_b)))
       return false;
 
-   core_path_basename_a = path_basename_nocompression(core_path_a);
-
-   if (core_path_basename_a)
-   {
-      const char *extension_pos = strrchr(core_path_basename_a, '.');
-
-      if (extension_pos)
-      {
-         const char *underscore_pos = NULL;
-
-         /* Remove extension */
-         *((char*)extension_pos)    = '\0';
-
-         underscore_pos = strrchr(core_path_basename_a, '_');
-
-         /* Restore extension */
-         *((char*)extension_pos) = '.';
-
-         if (underscore_pos)
-         {
-            size_t core_base_file_id_length  = 
-               underscore_pos - core_path_basename_a;
-            const char* core_path_basename_b = 
-               path_basename_nocompression(
-                  core_path_b);
-
-            if (string_starts_with_size(
-                     core_path_basename_a, core_path_basename_b,
-                     core_base_file_id_length))
-               return true;
-         }
-      }
-   }
-
-   return false;
-}
-
-void core_info_get_name(const char *path, char *s, size_t len,
-      const char *path_info, const char *dir_cores,
-      const char *exts, bool dir_show_hidden_files,
-      bool get_display_name)
-{
-   size_t i;
-   struct string_list contents      = {0};
-   const char       *path_basedir   = !string_is_empty(path_info) ?
-      path_info : dir_cores;
-   const char *core_path_basename   = path_basename(path);
-
-   if (!dir_list_initialize(&contents,
-            dir_cores, exts, false, dir_show_hidden_files, false, false))
-      return;
-
-   for (i = 0; i < contents.size; i++)
-   {
-      struct config_entry_list 
-         *entry                       = NULL;
-      config_file_t *conf             = NULL;
-      const char *current_path        = contents.elems[i].data;
-
-      if (!string_is_equal(path_basename(current_path), core_path_basename))
-         continue;
-
-      conf = core_info_list_iterate(contents.elems[i].data,
-               path_basedir);
-
-      if (!conf)
-         continue;
-
-      if (get_display_name)
-         entry = config_get_entry(conf, "display_name");
-      else
-         entry = config_get_entry(conf, "corename");
-
-      if (entry && !string_is_empty(entry->value))
-         strlcpy(s, entry->value, len);
-
-      config_file_free(conf);
-      break;
-   }
-
-   dir_list_deinitialize(&contents);
-}
-
-size_t core_info_list_num_info_files(core_info_list_t *core_info_list)
-{
-   size_t i, num = 0;
-
-   if (!core_info_list)
-      return 0;
-
-   for (i = 0; i < core_info_list->count; i++)
-   {
-      config_file_t *conf = (config_file_t*)
-         core_info_list->list[i].config_data;
-      num += !!conf;
-   }
-
-   return num;
+   return string_is_equal(core_file_id_a, core_file_id_b);
 }
 
 bool core_info_database_match_archive_member(const char *database_path)
@@ -1041,62 +983,28 @@ bool core_info_database_supports_content_path(
 }
 
 bool core_info_list_get_display_name(core_info_list_t *core_info_list,
-      const char *path, char *s, size_t len)
+      const char *core_path, char *s, size_t len)
 {
-   size_t i;
-   const char *core_filename = NULL;
+   core_info_t *info = core_info_find_internal(
+         core_info_list, core_path);
 
-   if (!core_info_list || string_is_empty(path))
-      return false;
-
-   core_filename = path_basename(path);
-   if (string_is_empty(core_filename))
-      return false;
-
-   for (i = 0; i < core_info_list->count; i++)
+   if (s &&
+       info &&
+       !string_is_empty(info->display_name))
    {
-      const core_info_t *info = &core_info_list->list[i];
-
-      if (!info || (info->core_file_id.len == 0))
-         continue;
-
-      if (!strncmp(info->core_file_id.str, core_filename, info->core_file_id.len))
-      {
-         if (string_is_empty(info->display_name))
-            break;
-
-         strlcpy(s, info->display_name, len);
-         return true;
-      }
+      strlcpy(s, info->display_name, len);
+      return true;
    }
 
    return false;
 }
 
-bool core_info_get_display_name(const char *path, char *s, size_t len)
-{
-   struct config_entry_list 
-      *entry           = NULL;
-   config_file_t *conf = config_file_new_from_path_to_string(path);
-
-   if (!conf)
-      return false;
-
-   entry               = config_get_entry(conf, "display_name");
-
-   if (entry && !string_is_empty(entry->value))
-      strlcpy(s, entry->value, len);
-
-   config_file_free(conf);
-   return true;
-}
-
 /* Returns core_info parameters required for
  * core updater tasks, read from specified file.
  * Returned core_updater_info_t object must be
  * freed using core_info_free_core_updater_info().
  * Returns NULL if 'path' is invalid. */
-core_updater_info_t *core_info_get_core_updater_info(const char *path)
+core_updater_info_t *core_info_get_core_updater_info(const char *info_path)
 {
    struct config_entry_list 
       *entry                 = NULL;
@@ -1104,11 +1012,11 @@ core_updater_info_t *core_info_get_core_updater_info(const char *path)
    core_updater_info_t *info = NULL;
    config_file_t *conf       = NULL;
 
-   if (string_is_empty(path))
+   if (string_is_empty(info_path))
       return NULL;
 
    /* Read config file */
-   conf = config_file_new_from_path_to_string(path);
+   conf = config_file_new_from_path_to_string(info_path);
 
    if (!conf)
       return NULL;
@@ -1134,19 +1042,28 @@ core_updater_info_t *core_info_get_core_updater_info(const char *path)
    entry                     = config_get_entry(conf, "display_name");
 
    if (entry && !string_is_empty(entry->value))
-      info->display_name     = strdup(entry->value);
+   {
+      info->display_name     = entry->value;
+      entry->value           = NULL;
+   }
 
    /* > description */
    entry                     = config_get_entry(conf, "description");
 
    if (entry && !string_is_empty(entry->value))
-      info->description      = strdup(entry->value);
+   {
+      info->description      = entry->value;
+      entry->value           = NULL;
+   }
 
    /* > licenses */
    entry                     = config_get_entry(conf, "license");
 
    if (entry && !string_is_empty(entry->value))
-      info->licenses         = strdup(entry->value);
+   {
+      info->licenses         = entry->value;
+      entry->value           = NULL;
+   }
 
    /* Clean up */
    config_file_free(conf);
@@ -1538,9 +1455,9 @@ bool core_info_hw_api_supported(core_info_t *info)
  *   core info list this is *not* thread safe */
 bool core_info_set_core_lock(const char *core_path, bool lock)
 {
-   core_info_ctx_find_t core_info;
+   core_info_t *core_info = NULL;
+   bool lock_file_exists  = false;
    char lock_file_path[PATH_MAX_LENGTH];
-   bool lock_file_exists = false;
 
    lock_file_path[0] = '\0';
 
@@ -1555,17 +1472,14 @@ bool core_info_set_core_lock(const char *core_path, bool lock)
       return false;
 
    /* Search for specified core */
-   core_info.inf  = NULL;
-   core_info.path = core_path;
-
-   if (!core_info_find(&core_info))
+   if (!core_info_find(core_path, &core_info))
       return false;
 
-   if (string_is_empty(core_info.inf->path))
+   if (string_is_empty(core_info->path))
       return false;
 
    /* Get lock file path */
-   strlcpy(lock_file_path, core_info.inf->path,
+   strlcpy(lock_file_path, core_info->path,
          sizeof(lock_file_path));
    strlcat(lock_file_path, FILE_PATH_LOCK_EXTENSION,
          sizeof(lock_file_path));
@@ -1600,7 +1514,7 @@ bool core_info_set_core_lock(const char *core_path, bool lock)
 
    /* File operations were successful - update
     * core info entry */
-   core_info.inf->is_locked = lock;
+   core_info->is_locked = lock;
 
    return true;
 }
@@ -1616,10 +1530,10 @@ bool core_info_set_core_lock(const char *core_path, bool lock)
  *   must be checked externally */
 bool core_info_get_core_lock(const char *core_path, bool validate_path)
 {
-   char lock_file_path[PATH_MAX_LENGTH];
+   core_info_t *core_info     = NULL;
    const char *core_file_path = NULL;
    bool is_locked             = false;
-   core_info_ctx_find_t core_info;
+   char lock_file_path[PATH_MAX_LENGTH];
 
    lock_file_path[0] = '\0';
 
@@ -1633,16 +1547,11 @@ bool core_info_get_core_lock(const char *core_path, bool validate_path)
    if (string_is_empty(core_path))
       return false;
 
-   core_info.inf  = NULL;
-   core_info.path = NULL;
-
    /* Check whether core path is to be validated */
    if (validate_path)
    {
-      core_info.path = core_path;
-
-      if (core_info_find(&core_info))
-         core_file_path = core_info.inf->path;
+      if (core_info_find(core_path, &core_info))
+         core_file_path = core_info->path;
    }
    else
       core_file_path = core_path;
@@ -1665,8 +1574,8 @@ bool core_info_get_core_lock(const char *core_path, bool validate_path)
     * core info object is available), ensure
     * that core info 'is_locked' field is
     * up to date */
-   if (validate_path && core_info.inf)
-      core_info.inf->is_locked = is_locked;
+   if (validate_path && core_info)
+      core_info->is_locked = is_locked;
 
    return is_locked;
 }
diff --git a/core_info.h b/core_info.h
index 4a38dd4892..96205ee4e2 100644
--- a/core_info.h
+++ b/core_info.h
@@ -45,25 +45,19 @@ typedef struct
 
 /* Simple container/convenience struct for
  * holding the 'id' of a core file
- * > 'id' is the filename without extension or
+ * > 'str' is the filename without extension or
  *   platform-specific suffix
- * > 'id' is used for core info searches - enables
- *   matching regardless of core file base path,
- *   and is platform-independent (e.g. an Android
- *   core file will be correctly identified on Linux)
- * > 'len' is used to cache the length of 'str', for
- *   improved performance when performing string
- *   comparisons */
+ * > 'hash' is a hash key used for efficient core
+ *   list searches */
 typedef struct
 {
    char *str;
-   size_t len;
+   uint32_t hash;
 } core_file_id_t;
 
 typedef struct
 {
    char *path;
-   void *config_data;
    char *display_name;
    char *display_version;
    char *core_name;
@@ -89,8 +83,8 @@ typedef struct
    struct string_list *required_hw_api_list;
    core_info_firmware_t *firmware;
    core_file_id_t core_file_id; /* ptr alignment */
-   void *userdata;
    size_t firmware_count;
+   bool has_info;
    bool supports_no_game;
    bool database_match_archive_member;
    bool is_experimental;
@@ -112,6 +106,7 @@ typedef struct
    core_info_t *list;
    char *all_ext;
    size_t count;
+   size_t info_count;
 } core_info_list_t;
 
 typedef struct core_info_ctx_firmware
@@ -123,12 +118,6 @@ typedef struct core_info_ctx_firmware
    } directory;
 } core_info_ctx_firmware_t;
 
-typedef struct core_info_ctx_find
-{
-   core_info_t *inf;
-   const char *path;
-} core_info_ctx_find_t;
-
 struct core_info_state
 {
 #ifdef HAVE_COMPRESSION
@@ -141,30 +130,21 @@ struct core_info_state
 
 typedef struct core_info_state core_info_state_t;
 
-size_t core_info_list_num_info_files(core_info_list_t *list);
-
 /* Non-reentrant, does not allocate. Returns pointer to internal state. */
 void core_info_list_get_supported_cores(core_info_list_t *list,
       const char *path, const core_info_t **infos, size_t *num_infos);
 
 bool core_info_list_get_display_name(core_info_list_t *list,
-      const char *path, char *s, size_t len);
-
-bool core_info_get_display_name(const char *path, char *s, size_t len);
+      const char *core_path, char *s, size_t len);
 
 /* Returns core_info parameters required for
  * core updater tasks, read from specified file.
  * Returned core_updater_info_t object must be
  * freed using core_info_free_core_updater_info().
  * Returns NULL if 'path' is invalid. */
-core_updater_info_t *core_info_get_core_updater_info(const char *path);
+core_updater_info_t *core_info_get_core_updater_info(const char *info_path);
 void core_info_free_core_updater_info(core_updater_info_t *info);
 
-void core_info_get_name(const char *path, char *s, size_t len,
-      const char *path_info, const char *dir_cores,
-      const char *exts, bool show_hidden_files,
-      bool get_display_name);
-
 core_info_t *core_info_get(core_info_list_t *list, size_t i);
 
 void core_info_free_current_core(core_info_state_t *p_coreinfo);
@@ -186,22 +166,20 @@ size_t core_info_count(void);
 bool core_info_list_update_missing_firmware(core_info_ctx_firmware_t *info,
       bool *set_missing_bios);
 
-bool core_info_find(core_info_ctx_find_t *info);
+bool core_info_find(const char *core_path,
+      core_info_t **core_info);
 
-bool core_info_load(
-      core_info_ctx_find_t *info,
+bool core_info_load(const char *core_path,
       core_info_state_t *p_coreinfo);
 
 bool core_info_database_supports_content_path(const char *database_path, const char *path);
 
 bool core_info_database_match_archive_member(const char *database_path);
 
-bool core_info_unsupported_content_path(const char *path);
-
 void core_info_qsort(core_info_list_t *core_info_list, enum core_info_list_qsort_type qsort_type);
 
 bool core_info_list_get_info(core_info_list_t *core_info_list,
-      core_info_t *out_info, const char *path);
+      core_info_t *out_info, const char *core_path);
 
 bool core_info_hw_api_supported(core_info_t *info);
 
@@ -223,7 +201,7 @@ bool core_info_get_core_lock(const char *core_path, bool validate_path);
 
 core_info_state_t *coreinfo_get_ptr(void);
 
-bool core_info_core_file_id_is_equal(const char* core_path_a, const char* core_path_b);
+bool core_info_core_file_id_is_equal(const char *core_path_a, const char *core_path_b);
 
 RETRO_END_DECLS
 
diff --git a/gfx/widgets/gfx_widget_load_content_animation.c b/gfx/widgets/gfx_widget_load_content_animation.c
index fd2652e2a6..284ebb6cf2 100644
--- a/gfx/widgets/gfx_widget_load_content_animation.c
+++ b/gfx/widgets/gfx_widget_load_content_animation.c
@@ -284,13 +284,13 @@ bool gfx_widget_start_load_content_animation(void)
    const char *content_path                         = path_get(RARCH_PATH_CONTENT);
    const char *core_path                            = path_get(RARCH_PATH_CORE);
    playlist_t *playlist                             = playlist_get_cached();
+   core_info_t *core_info                           = NULL;
 
    bool playlist_entry_found                        = false;
    bool has_content                                 = false;
    bool has_system                                  = false;
    bool has_db_name                                 = false;
 
-   core_info_ctx_find_t core_info_finder;
    char icon_path[PATH_MAX_LENGTH];
 
    icon_path[0] = '\0';
@@ -314,13 +314,10 @@ bool gfx_widget_start_load_content_animation(void)
       return false;
 
    /* Check core validity */
-   core_info_finder.inf  = NULL;
-   core_info_finder.path = core_path;
-
-   if (!core_info_find(&core_info_finder))
+   if (!core_info_find(core_path, &core_info))
       return false;
 
-   core_path = core_info_finder.inf->path;
+   core_path = core_info->path;
 
    /* Parse content path
     * > If we have a cached playlist, attempt to find
@@ -357,10 +354,8 @@ bool gfx_widget_start_load_content_animation(void)
 
             /* Check whether core matches... */
             if (string_is_empty(entry_core_file) ||
-                !string_starts_with_size(
-                     entry_core_file,
-                     core_info_finder.inf->core_file_id.str,
-                     core_info_finder.inf->core_file_id.len))
+                !string_starts_with(entry_core_file,
+                     core_info->core_file_id.str))
                entry = NULL;
          }
       }
@@ -430,8 +425,8 @@ bool gfx_widget_start_load_content_animation(void)
    if (!has_system)
    {
       /* Use core display name, if available */
-      if (!string_is_empty(core_info_finder.inf->display_name))
-         strlcpy(state->system_name, core_info_finder.inf->display_name,
+      if (!string_is_empty(core_info->display_name))
+         strlcpy(state->system_name, core_info->display_name,
                sizeof(state->system_name));
       /* Otherwise, just use 'RetroArch' as a fallback */
       else
@@ -466,7 +461,7 @@ bool gfx_widget_start_load_content_animation(void)
    {
       const char *core_db_name           = NULL;
       struct string_list *databases_list =
-            core_info_finder.inf->databases_list;
+            core_info->databases_list;
 
       /* We can only use the core db_name if the
        * core is associated with exactly one database */
diff --git a/menu/cbs/menu_cbs_get_value.c b/menu/cbs/menu_cbs_get_value.c
index c734f81efe..9aea7fe040 100644
--- a/menu/cbs/menu_cbs_get_value.c
+++ b/menu/cbs/menu_cbs_get_value.c
@@ -451,19 +451,16 @@ static void menu_action_setting_disp_set_label_core_updater_entry(
        core_updater_list_get_filename(core_list, path, &entry) &&
        !string_is_empty(entry->local_core_path))
    {
-      core_info_ctx_find_t core_info;
+      core_info_t *core_info = NULL;
 
       /* Check whether core is installed
        * > Note: We search core_info here instead
        *   of calling path_is_valid() since we don't
        *   want to perform disk access every frame */
-      core_info.inf  = NULL;
-      core_info.path = entry->local_core_path;
-
-      if (core_info_find(&core_info))
+      if (core_info_find(entry->local_core_path, &core_info))
       {
          /* Highlight locked cores */
-         if (core_info.inf->is_locked)
+         if (core_info->is_locked)
          {
             s[0] = '[';
             s[1] = '#';
@@ -493,12 +490,12 @@ static void menu_action_setting_disp_set_label_core_manager_entry(
       const char *path,
       char *s2, size_t len2)
 {
-   core_info_ctx_find_t core_info;
-   const char *alt = list->list[i].alt
-      ? list->list[i].alt
-      : list->list[i].path;
-   *s              = '\0';
-   *w              = 0;
+   core_info_t *core_info = NULL;
+   const char *alt        = list->list[i].alt
+         ? list->list[i].alt
+         : list->list[i].path;
+   *s                     = '\0';
+   *w                     = 0;
 
    if (alt)
       strlcpy(s2, alt, len2);
@@ -507,11 +504,8 @@ static void menu_action_setting_disp_set_label_core_manager_entry(
     * > Note: We search core_info here instead of
     *   calling core_info_get_core_lock() since we
     *   don't want to perform disk access every frame */
-   core_info.inf  = NULL;
-   core_info.path = path;
-
-   if (core_info_find(&core_info) &&
-       core_info.inf->is_locked)
+   if (core_info_find(path, &core_info) &&
+       core_info->is_locked)
    {
       s[0] = '[';
       s[1] = '!';
@@ -529,12 +523,12 @@ static void menu_action_setting_disp_set_label_core_lock(
       const char *path,
       char *s2, size_t len2)
 {
-   core_info_ctx_find_t core_info;
-   const char *alt = list->list[i].alt
-      ? list->list[i].alt
-      : list->list[i].path;
-   *s              = '\0';
-   *w              = 0;
+   core_info_t *core_info = NULL;
+   const char *alt        = list->list[i].alt
+         ? list->list[i].alt
+         : list->list[i].path;
+   *s                     = '\0';
+   *w                     = 0;
 
    if (alt)
       strlcpy(s2, alt, len2);
@@ -543,11 +537,8 @@ static void menu_action_setting_disp_set_label_core_lock(
     * > Note: We search core_info here instead of
     *   calling core_info_get_core_lock() since we
     *   don't want to perform disk access every frame */
-   core_info.inf  = NULL;
-   core_info.path = path;
-
-   if (core_info_find(&core_info) &&
-       core_info.inf->is_locked)
+   if (core_info_find(path, &core_info) &&
+       core_info->is_locked)
       strlcpy(s, msg_hash_to_str(MENU_ENUM_LABEL_VALUE_ON), len);
    else
       strlcpy(s, msg_hash_to_str(MENU_ENUM_LABEL_VALUE_OFF), len);
diff --git a/menu/cbs/menu_cbs_ok.c b/menu/cbs/menu_cbs_ok.c
index c631cab8aa..e963e6d693 100644
--- a/menu/cbs/menu_cbs_ok.c
+++ b/menu/cbs/menu_cbs_ok.c
@@ -3556,44 +3556,36 @@ static int action_ok_path_manual_scan_directory(const char *path,
 static int action_ok_core_deferred_set(const char *new_core_path,
       const char *content_label, unsigned type, size_t idx, size_t entry_idx)
 {
-   char ext_name[255];
-   char core_display_name[PATH_MAX_LENGTH];
+   size_t selection              = menu_navigation_get_selection();
+   struct playlist_entry entry   = {0};
+   menu_handle_t *menu           = menu_driver_get_ptr();
+   core_info_t *core_info        = NULL;
+   const char *core_display_name = NULL;
    char resolved_core_path[PATH_MAX_LENGTH];
    char msg[PATH_MAX_LENGTH];
-   size_t selection                        = menu_navigation_get_selection();
-   struct playlist_entry entry             = {0};
-   menu_handle_t            *menu          = menu_driver_get_ptr();
-   settings_t *settings                    = config_get_ptr();
-   const char *path_libretro_info          = settings->paths.path_libretro_info;
-   const char *path_dir_libretro           = settings->paths.directory_libretro;
-   bool show_hidden_files                  = settings->bools.show_hidden_files;
 
-   ext_name[0]                             = '\0';
-   core_display_name[0]                    = '\0';
-   resolved_core_path[0]                   = '\0';
-   msg[0]                                  = '\0';
+   resolved_core_path[0] = '\0';
+   msg[0]                = '\0';
 
-   if (!menu)
+   if (!menu ||
+       string_is_empty(new_core_path))
       return menu_cbs_exit();
 
-   if (!frontend_driver_get_core_extension(ext_name, sizeof(ext_name)))
-      return menu_cbs_exit();
+   /* Get core display name */
+   if (core_info_find(new_core_path, &core_info))
+      core_display_name = core_info->display_name;
 
-   core_info_get_name(new_core_path,
-         core_display_name, sizeof(core_display_name),
-         path_libretro_info,
-         path_dir_libretro,
-         ext_name,
-         show_hidden_files,
-         true);
+   if (string_is_empty(core_display_name))
+      core_display_name = path_basename_nocompression(new_core_path);
 
+   /* Get 'real' core path */
    strlcpy(resolved_core_path, new_core_path, sizeof(resolved_core_path));
    playlist_resolve_path(PLAYLIST_SAVE, true, resolved_core_path, sizeof(resolved_core_path));
 
    /* the update function reads our entry
     * as const, so these casts are safe */
    entry.core_path = (char*)resolved_core_path;
-   entry.core_name = core_display_name;
+   entry.core_name = (char*)core_display_name;
 
    command_playlist_update_write(
          NULL,
@@ -5200,19 +5192,16 @@ static int action_ok_add_to_favorites(const char *path,
       {
          if (!string_is_empty(path_get(RARCH_PATH_CORE)))
          {
-            core_info_ctx_find_t core_info;
+            core_info_t *core_info = NULL;
 
             /* >> core_path */
             strlcpy(core_path, path_get(RARCH_PATH_CORE), sizeof(core_path));
 
             /* >> core_name
              * (always use display name, if available) */
-            core_info.inf  = NULL;
-            core_info.path = core_path;
-
-            if (core_info_find(&core_info))
-               if (!string_is_empty(core_info.inf->display_name))
-                  strlcpy(core_name, core_info.inf->display_name,
+            if (core_info_find(core_path, &core_info))
+               if (!string_is_empty(core_info->display_name))
+                  strlcpy(core_name, core_info->display_name,
                         sizeof(core_name));
          }
 
@@ -5336,19 +5325,16 @@ static int action_ok_add_to_favorites_playlist(const char *path,
       /* > core_path + core_name */
       if (!string_is_empty(entry->core_path) && !string_is_empty(entry->core_name))
       {
-         core_info_ctx_find_t core_info;
+         core_info_t *core_info = NULL;
 
          /* >> core_path */
          string_list_append(str_list, entry->core_path, attr);
 
          /* >> core_name
           * (always use display name, if available) */
-         core_info.inf  = NULL;
-         core_info.path = entry->core_path;
-
-         if (core_info_find(&core_info))
-            if (!string_is_empty(core_info.inf->display_name))
-               strlcpy(core_display_name, core_info.inf->display_name, sizeof(core_display_name));
+         if (core_info_find(entry->core_path, &core_info))
+            if (!string_is_empty(core_info->display_name))
+               strlcpy(core_display_name, core_info->display_name, sizeof(core_display_name));
 
          if (!string_is_empty(core_display_name))
             string_list_append(str_list, core_display_name, attr);
@@ -7181,19 +7167,17 @@ int action_ok_core_lock(const char *path,
    if (!core_info_set_core_lock(core_path, lock))
    {
       const char *core_name = NULL;
-      core_info_ctx_find_t core_info;
+      core_info_t *core_info = NULL;
       char msg[PATH_MAX_LENGTH];
 
       msg[0] = '\0';
 
       /* Need to fetch core name for error message */
-      core_info.inf  = NULL;
-      core_info.path = core_path;
 
       /* If core is found, use display name */
-      if (core_info_find(&core_info) &&
-          core_info.inf->display_name)
-         core_name = core_info.inf->display_name;
+      if (core_info_find(core_path, &core_info) &&
+          core_info->display_name)
+         core_name = core_info->display_name;
       /* If not, use core file name */
       else
          core_name = path_basename_nocompression(core_path);
@@ -7240,20 +7224,18 @@ static int action_ok_core_delete(const char *path,
    /* Check whether core is locked */
    if (core_info_get_core_lock(core_path, true))
    {
-      const char *core_name = NULL;
-      core_info_ctx_find_t core_info;
+      const char *core_name  = NULL;
+      core_info_t *core_info = NULL;
       char msg[PATH_MAX_LENGTH];
 
       msg[0] = '\0';
 
       /* Need to fetch core name for notification */
-      core_info.inf  = NULL;
-      core_info.path = core_path;
 
       /* If core is found, use display name */
-      if (core_info_find(&core_info) &&
-          core_info.inf->display_name)
-         core_name = core_info.inf->display_name;
+      if (core_info_find(core_path, &core_info) &&
+          core_info->display_name)
+         core_name = core_info->display_name;
       /* If not, use core file name */
       else
          core_name = path_basename_nocompression(core_path);
diff --git a/menu/cbs/menu_cbs_start.c b/menu/cbs/menu_cbs_start.c
index 567e4b3a20..10dd772b6d 100644
--- a/menu/cbs/menu_cbs_start.c
+++ b/menu/cbs/menu_cbs_start.c
@@ -571,20 +571,18 @@ static int action_start_core_lock(
    /* ...Otherwise, attempt to unlock it */
    if (!core_info_set_core_lock(core_path, false))
    {
-      const char *core_name = NULL;
-      core_info_ctx_find_t core_info;
+      const char *core_name  = NULL;
+      core_info_t *core_info = NULL;
       char msg[PATH_MAX_LENGTH];
 
       msg[0] = '\0';
 
       /* Need to fetch core name for error message */
-      core_info.inf  = NULL;
-      core_info.path = core_path;
 
       /* If core is found, use display name */
-      if (core_info_find(&core_info) &&
-          core_info.inf->display_name)
-         core_name = core_info.inf->display_name;
+      if (core_info_find(core_path, &core_info) &&
+          core_info->display_name)
+         core_name = core_info->display_name;
       /* If not, use core file name */
       else
          core_name = path_basename(core_path);
diff --git a/menu/cbs/menu_cbs_sublabel.c b/menu/cbs/menu_cbs_sublabel.c
index 6a6da555e9..0e1b0084b0 100644
--- a/menu/cbs/menu_cbs_sublabel.c
+++ b/menu/cbs/menu_cbs_sublabel.c
@@ -65,25 +65,23 @@
 
 static int menu_action_sublabel_file_browser_core(file_list_t *list, unsigned type, unsigned i, const char *label, const char *path, char *s, size_t len)
 {
-   core_info_ctx_find_t core_info;
+   core_info_t *core_info = NULL;
 
    /* Set sublabel prefix */
    strlcpy(s, msg_hash_to_str(MENU_ENUM_LABEL_VALUE_CORE_INFO_LICENSES), len);
    strlcat(s, ": ", len);
 
    /* Search for specified core */
-   core_info.inf  = NULL;
-   core_info.path = path;
 
-   if (core_info_find(&core_info) &&
-       core_info.inf->licenses_list)
+   if (core_info_find(path, &core_info) &&
+       core_info->licenses_list)
    {
       char tmp[MENU_SUBLABEL_MAX_LENGTH];
       tmp[0]  = '\0';
 
       /* Add license text */
       string_list_join_concat(tmp, sizeof(tmp),
-            core_info.inf->licenses_list, ", ");
+            core_info->licenses_list, ", ");
       strlcat(s, tmp, len);
       return 1;
    }
diff --git a/menu/cbs/menu_cbs_title.c b/menu/cbs/menu_cbs_title.c
index 06bdbcbcc5..359a7426f8 100644
--- a/menu/cbs/menu_cbs_title.c
+++ b/menu/cbs/menu_cbs_title.c
@@ -408,7 +408,7 @@ static int action_get_title_deferred_playlist_list(const char *path, const char
 static int action_get_title_deferred_core_backup_list(
       const char *core_path, const char *prefix, char *s, size_t len)
 {
-   core_info_ctx_find_t core_info;
+   core_info_t *core_info = NULL;
 
    if (string_is_empty(core_path) || string_is_empty(prefix))
       return 0;
@@ -417,17 +417,14 @@ static int action_get_title_deferred_core_backup_list(
    strlcpy(s, prefix, len);
    strlcat(s, ": ", len);
 
-   /* Search for specified core */
-   core_info.inf  = NULL;
-   core_info.path = core_path;
-
-   /* If core is found, add display name */
-   if (core_info_find(&core_info) &&
-       core_info.inf->display_name)
-      strlcat(s, core_info.inf->display_name, len);
+   /* Search for specified core
+    * > If core is found, add display name */
+   if (core_info_find(core_path, &core_info) &&
+       core_info->display_name)
+      strlcat(s, core_info->display_name, len);
    else
    {
-      /* If not, use core file name */
+      /* > If not, use core file name */
       const char *core_filename = path_basename_nocompression(core_path);
 
       if (!string_is_empty(core_filename))
@@ -463,19 +460,15 @@ static int action_get_core_information_list(
    if ((menu_type == FILE_TYPE_DOWNLOAD_CORE) ||
        (menu_type == MENU_SETTING_ACTION_CORE_MANAGER_OPTIONS))
    {
-      const char *core_path = path;
-      core_info_ctx_find_t core_info_finder;
+      core_info_t *core_info_menu = NULL;
 
-      if (string_is_empty(core_path))
+      if (string_is_empty(path))
          goto error;
 
       /* Core updater/manager entry - search for
        * corresponding core info */
-      core_info_finder.inf  = NULL;
-      core_info_finder.path = core_path;
-
-      if (core_info_find(&core_info_finder))
-         core_info = core_info_finder.inf;
+      if (core_info_find(path, &core_info_menu))
+         core_info = core_info_menu;
    }
    else
       core_info_get_current_core(&core_info);
diff --git a/menu/drivers/materialui.c b/menu/drivers/materialui.c
index 735ea932f8..9282df0fe9 100644
--- a/menu/drivers/materialui.c
+++ b/menu/drivers/materialui.c
@@ -9066,7 +9066,7 @@ static int materialui_list_push(void *data, void *userdata,
                   MENU_SETTING_ACTION_FAVORITES_DIR, 0, 0);
 
             core_info_get_list(&list);
-            if (core_info_list_num_info_files(list))
+            if (list->info_count > 0)
             {
                menu_entries_append_enum(info->list,
                      msg_hash_to_str(MENU_ENUM_LABEL_VALUE_DOWNLOADED_FILE_DETECT_CORE_LIST),
diff --git a/menu/drivers/ozone/ozone.c b/menu/drivers/ozone/ozone.c
index d671faa137..f736b7398d 100644
--- a/menu/drivers/ozone/ozone.c
+++ b/menu/drivers/ozone/ozone.c
@@ -1456,7 +1456,7 @@ static int ozone_list_push(void *data, void *userdata,
                   MENU_SETTING_ACTION_FAVORITES_DIR, 0, 0);
 
             core_info_get_list(&list);
-            if (core_info_list_num_info_files(list))
+            if (list->info_count > 0)
             {
                menu_entries_append_enum(info->list,
                      msg_hash_to_str(MENU_ENUM_LABEL_VALUE_DOWNLOADED_FILE_DETECT_CORE_LIST),
diff --git a/menu/drivers/stripes.c b/menu/drivers/stripes.c
index 155e448ba1..7c64a13d5d 100644
--- a/menu/drivers/stripes.c
+++ b/menu/drivers/stripes.c
@@ -4144,7 +4144,7 @@ static int stripes_list_push(void *data, void *userdata,
                   MENU_SETTING_ACTION_FAVORITES_DIR, 0, 0);
 
             core_info_get_list(&list);
-            if (core_info_list_num_info_files(list))
+            if (list->info_count > 0)
             {
                menu_entries_append_enum(info->list,
                      msg_hash_to_str(MENU_ENUM_LABEL_VALUE_DOWNLOADED_FILE_DETECT_CORE_LIST),
diff --git a/menu/drivers/xmb.c b/menu/drivers/xmb.c
index 0609ba0b33..c8725bbc39 100644
--- a/menu/drivers/xmb.c
+++ b/menu/drivers/xmb.c
@@ -6799,7 +6799,7 @@ static int xmb_list_push(void *data, void *userdata,
                MENU_SETTING_ACTION_FAVORITES_DIR, 0, 0);
 
          core_info_get_list(&list);
-         if (core_info_list_num_info_files(list))
+         if (list->info_count > 0)
             menu_entries_append_enum(info->list,
                   msg_hash_to_str(MENU_ENUM_LABEL_VALUE_DOWNLOADED_FILE_DETECT_CORE_LIST),
                   msg_hash_to_str(MENU_ENUM_LABEL_DOWNLOADED_FILE_DETECT_CORE_LIST),
diff --git a/menu/menu_displaylist.c b/menu/menu_displaylist.c
index 15bab6631c..7c1a90e13a 100644
--- a/menu/menu_displaylist.c
+++ b/menu/menu_displaylist.c
@@ -471,22 +471,19 @@ static int menu_displaylist_parse_core_info(menu_displaylist_info_t *info,
    if ((info->type == FILE_TYPE_DOWNLOAD_CORE) ||
        (info->type == MENU_SETTING_ACTION_CORE_MANAGER_OPTIONS))
    {
-      core_info_ctx_find_t core_info_finder;
+      core_info_t *core_info_menu = NULL;
 
       core_path = info->path;
 
       /* Core updater entry - search for corresponding
        * core info */
-      core_info_finder.inf  = NULL;
-      core_info_finder.path = core_path;
-
-      if (core_info_find(&core_info_finder))
-         core_info = core_info_finder.inf;
+      if (core_info_find(core_path, &core_info_menu))
+         core_info = core_info_menu;
    }
    else if (core_info_get_current_core(&core_info) && core_info)
       core_path = core_info->path;
 
-   if (!core_info || !core_info->config_data)
+   if (!core_info || !core_info->has_info)
    {
       if (menu_entries_append_enum(info->list,
             msg_hash_to_str(MENU_ENUM_LABEL_VALUE_NO_CORE_INFORMATION_AVAILABLE),
@@ -3074,7 +3071,7 @@ static unsigned menu_displaylist_parse_information_list(file_list_t *info_list)
           !string_is_equal(system->library_name,
              msg_hash_to_str(MENU_ENUM_LABEL_VALUE_NO_CORE))
          )
-         && core_info && core_info->config_data
+         && core_info && core_info->has_info
       )
       if (menu_entries_append_enum(info_list,
             msg_hash_to_str(MENU_ENUM_LABEL_VALUE_CORE_INFORMATION),
@@ -3843,18 +3840,15 @@ static unsigned menu_displaylist_parse_content_information(
    }
    else
    {
-      core_info_ctx_find_t core_info;
+      core_info_t *core_info = NULL;
 
       /* No playlist - just extract what we can... */
       content_path   = loaded_content_path;
       core_path      = loaded_core_path;
 
-      core_info.inf  = NULL;
-      core_info.path = core_path;
-
-      if (core_info_find(&core_info))
-         if (!string_is_empty(core_info.inf->display_name))
-            strlcpy(core_name, core_info.inf->display_name, sizeof(core_name));
+      if (core_info_find(core_path, &core_info))
+         if (!string_is_empty(core_info->display_name))
+            strlcpy(core_name, core_info->display_name, sizeof(core_name));
    }
 
    /* Content label */
@@ -6031,7 +6025,7 @@ unsigned menu_displaylist_build_list(
          {
             core_info_list_t *info_list        = NULL;
             core_info_get_list(&info_list);
-            if (core_info_list_num_info_files(info_list))
+            if (info_list->info_count > 0)
             {
                if (menu_entries_append_enum(list,
                         msg_hash_to_str(
diff --git a/playlist.c b/playlist.c
index 198732f91e..95376ba965 100644
--- a/playlist.c
+++ b/playlist.c
@@ -2866,17 +2866,14 @@ bool playlist_entry_has_core(const struct playlist_entry *entry)
  * core association */
 core_info_t *playlist_entry_get_core_info(const struct playlist_entry* entry)
 {
-   core_info_ctx_find_t core_info;
+   core_info_t *core_info = NULL;
 
    if (!playlist_entry_has_core(entry))
       return NULL;
 
    /* Search for associated core */
-   core_info.inf  = NULL;
-   core_info.path = entry->core_path;
-
-   if (core_info_find(&core_info))
-      return core_info.inf;
+   if (core_info_find(entry->core_path, &core_info))
+      return core_info;
 
    return NULL;
 }
@@ -2888,7 +2885,7 @@ core_info_t *playlist_entry_get_core_info(const struct playlist_entry* entry)
  * default core association */
 core_info_t *playlist_get_default_core_info(playlist_t* playlist)
 {
-   core_info_ctx_find_t core_info;
+   core_info_t *core_info = NULL;
 
    if (!playlist ||
        string_is_empty(playlist->default_core_path) ||
@@ -2898,11 +2895,8 @@ core_info_t *playlist_get_default_core_info(playlist_t* playlist)
       return NULL;
 
    /* Search for associated core */
-   core_info.inf  = NULL;
-   core_info.path = playlist->default_core_path;
-
-   if (core_info_find(&core_info))
-      return core_info.inf;
+   if (core_info_find(playlist->default_core_path, &core_info))
+      return core_info;
 
    return NULL;
 }
diff --git a/retroarch.c b/retroarch.c
index 3a13db7a34..08408ef136 100644
--- a/retroarch.c
+++ b/retroarch.c
@@ -1986,17 +1986,15 @@ static int generic_menu_iterate(
 #endif
                   case MENU_ENUM_LABEL_CORE_MANAGER_ENTRY:
                      {
-                        core_info_ctx_find_t core_info;
-                        const char *path = selection_buf->list[selection].path;
-                        /* Search for specified core */
-                        core_info.inf    = NULL;
-                        core_info.path   = path;
+                        core_info_t *core_info = NULL;
+                        const char *path       = selection_buf->list[selection].path;
 
+                        /* Search for specified core */
                         if (     path 
-                              && core_info_find(&core_info)
-                              && !string_is_empty(core_info.inf->description))
+                              && core_info_find(path, &core_info)
+                              && !string_is_empty(core_info->description))
                            strlcpy(menu->menu_state_msg,
-                                 core_info.inf->description,
+                                 core_info->description,
                                  sizeof(menu->menu_state_msg));
                         else
                            strlcpy(menu->menu_state_msg,
@@ -13618,7 +13616,6 @@ bool command_event(enum event_command cmd, void *data)
          break;
       case CMD_EVENT_LOAD_CORE_PERSIST:
          {
-            core_info_ctx_find_t info_find;
             rarch_system_info_t *system_info = &p_rarch->runloop_system;
             struct retro_system_info *system = &system_info->info;
             const char *core_path            = path_get(RARCH_PATH_CORE);
@@ -13634,9 +13631,8 @@ bool command_event(enum event_command cmd, void *data)
                      system,
                      &system_info->load_no_content))
                return false;
-            info_find.path = core_path;
 
-            if (!core_info_load(&info_find, &p_rarch->core_info_st))
+            if (!core_info_load(core_path, &p_rarch->core_info_st))
             {
 #ifdef HAVE_DYNAMIC
                return false;
diff --git a/runtime_file.c b/runtime_file.c
index 64d8dece3d..b90434f990 100644
--- a/runtime_file.c
+++ b/runtime_file.c
@@ -238,7 +238,7 @@ runtime_log_t *runtime_log_init(
    char log_file_dir[PATH_MAX_LENGTH];
    char log_file_path[PATH_MAX_LENGTH];
    char tmp_buf[PATH_MAX_LENGTH];
-   core_info_ctx_find_t core_info;
+   core_info_t *core_info     = NULL;
    runtime_log_t *runtime_log = NULL;
 
    content_name[0]            = '\0';
@@ -266,12 +266,9 @@ runtime_log_t *runtime_log_init(
     * we are performing aggregate (not per core) logging,
     * since content name is sometimes dependent upon core
     * (e.g. see TyrQuake below) */
-   core_info.inf  = NULL;
-   core_info.path = core_path;
-
-   if (core_info_find(&core_info) &&
-       core_info.inf->core_name)
-      strlcpy(core_name, core_info.inf->core_name, sizeof(core_name));
+   if (core_info_find(core_path, &core_info) &&
+       core_info->core_name)
+      strlcpy(core_name, core_info->core_name, sizeof(core_name));
 
    if (string_is_empty(core_name))
       return NULL;
diff --git a/tasks/task_core_backup.c b/tasks/task_core_backup.c
index 09c7752f00..1af84a64da 100644
--- a/tasks/task_core_backup.c
+++ b/tasks/task_core_backup.c
@@ -556,15 +556,12 @@ void *task_push_core_backup(
       core_name = core_display_name;
    else
    {
-      core_info_ctx_find_t core_info;
-
-      core_info.inf  = NULL;
-      core_info.path = core_path;
+      core_info_t *core_info = NULL;
 
       /* If core is found, use display name */
-      if (core_info_find(&core_info) &&
-          core_info.inf->display_name)
-         core_name = core_info.inf->display_name;
+      if (core_info_find(core_path, &core_info) &&
+          core_info->display_name)
+         core_name = core_info->display_name;
       else
       {
          /* If not, use core file name */
@@ -926,8 +923,8 @@ bool task_push_core_restore(const char *backup_path, const char *dir_libretro,
       bool *core_loaded)
 {
    task_finder_data_t find_data;
-   core_info_ctx_find_t core_info;
    enum core_backup_type backup_type;
+   core_info_t *core_info              = NULL;
    const char *core_name               = NULL;
    retro_task_t *task                  = NULL;
    core_backup_handle_t *backup_handle = NULL;
@@ -974,17 +971,14 @@ bool task_push_core_restore(const char *backup_path, const char *dir_libretro,
       goto error;
    }
 
-   /* Get core name */
-   core_info.inf  = NULL;
-   core_info.path = core_path;
-
-   /* If core is found, use display name */
-   if (core_info_find(&core_info) &&
-       core_info.inf->display_name)
-      core_name = core_info.inf->display_name;
+   /* Get core name
+    * > If core is found, use display name */
+   if (core_info_find(core_path, &core_info) &&
+       core_info->display_name)
+      core_name = core_info->display_name;
    else
    {
-      /* If not, use core file name */
+      /* > If not, use core file name */
       core_name = path_basename(core_path);
 
       if (string_is_empty(core_name))
diff --git a/tasks/task_playlist_manager.c b/tasks/task_playlist_manager.c
index c929ec38e1..8163279002 100644
--- a/tasks/task_playlist_manager.c
+++ b/tasks/task_playlist_manager.c
@@ -474,17 +474,14 @@ static void pl_manager_validate_core_association(
    else
    {
       char core_display_name[PATH_MAX_LENGTH];
-      core_info_ctx_find_t core_info;
+      core_info_t *core_info = NULL;
       
       core_display_name[0] = '\0';
       
       /* Search core info */
-      core_info.inf  = NULL;
-      core_info.path = core_path;
-      
-      if (core_info_find(&core_info) &&
-          !string_is_empty(core_info.inf->display_name))
-         strlcpy(core_display_name, core_info.inf->display_name,
+      if (core_info_find(core_path, &core_info) &&
+          !string_is_empty(core_info->display_name))
+         strlcpy(core_display_name, core_info->display_name,
                sizeof(core_display_name));
       
       /* If core_display_name string is empty, it means the
diff --git a/ui/drivers/qt/qt_playlist.cpp b/ui/drivers/qt/qt_playlist.cpp
index 5fb34742fc..41c09fc716 100644
--- a/ui/drivers/qt/qt_playlist.cpp
+++ b/ui/drivers/qt/qt_playlist.cpp
@@ -981,7 +981,7 @@ void MainWindow::onPlaylistWidgetContextMenuRequested(const QPoint&)
 
    if (!specialPlaylist && selectedAction->parent() == associateMenu.data())
    {
-      core_info_ctx_find_t coreInfo;
+      core_info_t *coreInfo                   = NULL;
       playlist_t *cachedPlaylist              = playlist_get_cached();
       playlist_t *playlist                    = NULL;
       bool loadPlaylist                       = true;
@@ -1010,14 +1010,11 @@ void MainWindow::onPlaylistWidgetContextMenuRequested(const QPoint&)
       if (playlist)
       {
          /* Get core info */
-         coreInfo.inf  = NULL;
-         coreInfo.path = corePath;
-
-         if (core_info_find(&coreInfo))
+         if (core_info_find(corePath, &coreInfo))
          {
             /* Set new core association */
-            playlist_set_default_core_path(playlist, coreInfo.inf->path);
-            playlist_set_default_core_name(playlist, coreInfo.inf->display_name);
+            playlist_set_default_core_path(playlist, coreInfo->path);
+            playlist_set_default_core_name(playlist, coreInfo->display_name);
          }
          else
          {
diff --git a/ui/drivers/ui_qt.cpp b/ui/drivers/ui_qt.cpp
index f605e6133d..d447a421c4 100644
--- a/ui/drivers/ui_qt.cpp
+++ b/ui/drivers/ui_qt.cpp
@@ -2308,22 +2308,17 @@ QVector<QHash<QString, QString> > MainWindow::getCoreInfo()
 {
    unsigned i;
    QVector<QHash<QString, QString> > infoList;
-   core_info_ctx_find_t core_info_finder;
    QHash<QString, QString> currentCore = getSelectedCore();
-   const core_info_t        *core_info = NULL;
+   core_info_t *core_info              = NULL;
    QByteArray currentCorePathArray     = currentCore["core_path"].toUtf8();
    const char *current_core_path_data  = currentCorePathArray.constData();
 
    /* Search for current core */
-   core_info_finder.inf                = NULL;
-   core_info_finder.path               = current_core_path_data;
-
-   if (core_info_find(&core_info_finder))
-      core_info                        = core_info_finder.inf;
+   core_info_find(current_core_path_data, &core_info);
 
    if (     currentCore["core_path"].isEmpty() 
          || !core_info 
-         || !core_info->config_data)
+         || !core_info->has_info)
    {
       QHash<QString, QString> hash;
 
@@ -2780,7 +2775,7 @@ void MainWindow::loadContent(const QHash<QString, QString> &contentHash)
    const char *contentCrc32    = NULL;
    QVariantMap coreMap         = m_launchWithComboBox->currentData(Qt::UserRole).value<QVariantMap>();
    core_selection coreSelection = static_cast<core_selection>(coreMap.value("core_selection").toInt());
-   core_info_ctx_find_t core_info;
+   core_info_t *coreInfo       = NULL;
 
    contentDbNameFull[0] = '\0';
 
@@ -2876,12 +2871,9 @@ void MainWindow::loadContent(const QHash<QString, QString> &contentHash)
 
    /* Search for specified core - ensures path
     * is 'sanitised' */
-   core_info.inf                       = NULL;
-   core_info.path                      = corePath;
-
-   if (core_info_find(&core_info) &&
-       !string_is_empty(core_info.inf->path))
-      corePath = core_info.inf->path;
+   if (core_info_find(corePath, &coreInfo) &&
+       !string_is_empty(coreInfo->path))
+      corePath = coreInfo->path;
 
    /* Add lpl extension to db_name, if required */
    if (!string_is_empty(contentDbName))
@@ -3056,7 +3048,6 @@ void MainWindow::setCoreActions()
       if (!defaultCorePath.isEmpty())
       {
          QString currentPlaylistItemDataString;
-         core_info_ctx_find_t core_info_finder;
          bool allPlaylists                  = false;
          int row                            = 0;
          QByteArray defaultCorePathArray    = defaultCorePath.toUtf8();
@@ -3071,6 +3062,8 @@ void MainWindow::setCoreActions()
 
          for (row = 0; row < m_listWidget->count(); row++)
          {
+            core_info_t *coreInfo = NULL;
+
             if (allPlaylists)
             {
                QFileInfo info;
@@ -3084,14 +3077,9 @@ void MainWindow::setCoreActions()
             }
 
             /* Search for default core */
-            core_info_finder.inf         = NULL;
-            core_info_finder.path        = default_core_path_data;
-
-            if (core_info_find(&core_info_finder))
+            if (core_info_find(default_core_path_data, &coreInfo))
             {
-               const core_info_t *info = core_info_finder.inf;
-
-               if (m_launchWithComboBox->findText(info->core_name) == -1)
+               if (m_launchWithComboBox->findText(coreInfo->core_name) == -1)
                {
                   int i               = 0;
                   bool found_existing = false;
@@ -3106,9 +3094,9 @@ void MainWindow::setCoreActions()
                      const char *core_path_data = CorePathArray.constData();
 
                      if (string_starts_with(path_basename(core_path_data),
-                              info->core_file_id.str) ||
-                           map.value("core_name").toString() == info->core_name ||
-                           map.value("core_name").toString() == info->display_name)
+                              coreInfo->core_file_id.str) ||
+                           map.value("core_name").toString() == coreInfo->core_name ||
+                           map.value("core_name").toString() == coreInfo->display_name)
                      {
                         found_existing = true;
                         break;
@@ -3118,10 +3106,10 @@ void MainWindow::setCoreActions()
                   if (!found_existing)
                   {
                      QVariantMap comboBoxMap;
-                     comboBoxMap["core_name"] = info->core_name;
-                     comboBoxMap["core_path"] = info->path;
+                     comboBoxMap["core_name"] = coreInfo->core_name;
+                     comboBoxMap["core_path"] = coreInfo->path;
                      comboBoxMap["core_selection"] = CORE_SELECTION_PLAYLIST_DEFAULT;
-                     m_launchWithComboBox->addItem(info->core_name, QVariant::fromValue(comboBoxMap));
+                     m_launchWithComboBox->addItem(coreInfo->core_name, QVariant::fromValue(comboBoxMap));
                   }
                }
             }