Core info search optimisations + improved core selection logic + clean-ups

This commit is contained in:
jdgleaver 2020-06-06 13:49:34 +01:00
parent c1b3ef6661
commit 445921ac5d
17 changed files with 542 additions and 539 deletions

View file

@ -207,6 +207,8 @@ static void core_info_list_free(core_info_list_t *core_info_list)
free(info->firmware[j].desc);
}
free(info->firmware);
free(info->core_file_id.str);
}
free(core_info_list->all_ext);
@ -504,11 +506,43 @@ static core_info_list_t *core_info_list_new(const char *path,
}
if (!string_is_empty(base_path))
{
const char *core_filename = path_basename(base_path);
/* Cache core path */
core_info[i].path = strdup(base_path);
if (!core_info[i].display_name)
core_info[i].display_name =
strdup(path_basename(core_info[i].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))
{
#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);
}
}
}
if (core_info_list)
@ -529,7 +563,13 @@ bool core_info_list_get_info(core_info_list_t *core_info_list,
core_info_t *out_info, const char *path)
{
size_t i;
if (!core_info_list || !out_info)
const char *core_filename = NULL;
if (!core_info_list || !out_info || string_is_empty(path))
return false;
core_filename = path_basename(path);
if (string_is_empty(core_filename))
return false;
memset(out_info, 0, sizeof(*out_info));
@ -538,8 +578,10 @@ bool core_info_list_get_info(core_info_list_t *core_info_list,
{
const core_info_t *info = &core_info_list->list[i];
if (string_is_equal(path_basename(info->path),
path_basename(path)))
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;
@ -605,15 +647,23 @@ static core_info_t *core_info_find_internal(
const char *core)
{
size_t i;
const char *core_path_basename = path_basename(core);
const char *core_filename = NULL;
if (!list || string_is_empty(core))
return NULL;
core_filename = path_basename(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->path)
if (!info || (info->core_file_id.len == 0))
continue;
if (string_is_equal(path_basename(info->path), core_path_basename))
if (!strncmp(info->core_file_id.str, core_filename, info->core_file_id.len))
return info;
}
@ -753,14 +803,18 @@ bool core_info_load(core_info_ctx_find_t *info)
return true;
}
bool core_info_find(core_info_ctx_find_t *info, const char *core_path)
bool core_info_find(core_info_ctx_find_t *info)
{
core_info_state_t *p_coreinfo = coreinfo_get_ptr();
if (!info || !p_coreinfo->curr_list)
return false;
info->inf = core_info_find_internal(p_coreinfo->curr_list, core_path);
info->inf = core_info_find_internal(p_coreinfo->curr_list, info->path);
if (!info->inf)
return false;
return true;
}
@ -978,22 +1032,30 @@ bool core_info_list_get_display_name(core_info_list_t *core_info_list,
const char *path, char *s, size_t len)
{
size_t i;
const char *core_filename = NULL;
if (!core_info_list)
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++)
{
const core_info_t *info = &core_info_list->list[i];
if (!string_is_equal(path_basename(info->path), path_basename(path)))
if (!info || (info->core_file_id.len == 0))
continue;
if (!info->display_name)
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;

View file

@ -35,6 +35,23 @@ typedef struct
bool optional;
} core_info_firmware_t;
/* Simple container/convenience struct for
* holding the 'id' of a core file
* > 'id' 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 */
typedef struct
{
char *str;
size_t len;
} core_file_id_t;
typedef struct
{
bool supports_no_game;
@ -67,6 +84,7 @@ typedef struct
struct string_list *licenses_list;
struct string_list *required_hw_api_list;
core_info_firmware_t *firmware;
core_file_id_t core_file_id;
void *userdata;
} core_info_t;
@ -152,7 +170,7 @@ bool core_info_get_list(core_info_list_t **core);
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, const char *name);
bool core_info_find(core_info_ctx_find_t *info);
bool core_info_load(core_info_ctx_find_t *info);

View file

@ -462,7 +462,7 @@ static void menu_action_setting_disp_set_label_core_updater_entry(
core_info.inf = NULL;
core_info.path = entry->local_core_path;
if (core_info_find(&core_info, entry->local_core_path))
if (core_info_find(&core_info))
{
strlcpy(s, "[#]", len);
*w = (unsigned)STRLEN_CONST("[#]");

View file

@ -373,16 +373,18 @@ static int action_left_video_resolution(unsigned type, const char *label,
static int playlist_association_left(unsigned type, const char *label,
bool wraparound)
{
char core_path[PATH_MAX_LENGTH];
char core_filename[PATH_MAX_LENGTH];
size_t i, next, current = 0;
settings_t *settings = config_get_ptr();
bool playlist_use_old_format = settings->bools.playlist_use_old_format;
bool playlist_compression = settings->bools.playlist_compression;
playlist_t *playlist = playlist_get_cached();
const char *default_core_path = playlist_get_default_core_path(playlist);
bool default_core_set = false;
core_info_list_t *core_info_list = NULL;
core_info_t *core_info = NULL;
core_path[0] = '\0';
core_filename[0] = '\0';
if (!playlist)
return -1;
@ -392,52 +394,62 @@ static int playlist_association_left(unsigned type, const char *label,
return menu_cbs_exit();
/* Get current core path association */
if (string_is_empty(playlist_get_default_core_path(playlist)))
if (!string_is_empty(default_core_path) &&
!string_is_equal(default_core_path, "DETECT"))
{
core_path[0] = 'D';
core_path[1] = 'E';
core_path[2] = 'T';
core_path[3] = 'E';
core_path[4] = 'C';
core_path[5] = 'T';
core_path[6] = '\0';
const char *default_core_filename = path_basename(default_core_path);
if (!string_is_empty(default_core_filename))
{
strlcpy(core_filename, default_core_filename, sizeof(core_filename));
default_core_set = true;
}
}
else
strlcpy(core_path, playlist_get_default_core_path(playlist), sizeof(core_path));
/* Sort cores alphabetically */
core_info_qsort(core_info_list, CORE_INFO_LIST_SORT_DISPLAY_NAME);
/* Get the index of the currently associated core */
for (i = 0; i < core_info_list->count; i++)
/* If a core is currently associated... */
if (default_core_set)
{
core_info = NULL;
core_info = core_info_get(core_info_list, i);
if (!core_info)
return -1;
if (string_is_equal(core_info->path, core_path))
current = i;
/* ...get its index */
for (i = 0; i < core_info_list->count; i++)
{
core_info = NULL;
core_info = core_info_get(core_info_list, i);
if (!core_info)
continue;
if (string_starts_with(core_filename, core_info->core_file_id.str))
current = i;
}
/* ...then decrement it */
if (current == 0)
{
/* Unset core association (DETECT) */
next = 0;
default_core_set = false;
}
else
next = current - 1;
}
/* If a core is *not* currently associated and
* wraparound is enabled, select last core in
* the list */
else if (wraparound && (core_info_list->count > 1))
{
next = core_info_list->count - 1;
default_core_set = true;
}
/* Decrement core index */
if (current > 0)
next = current - 1;
else if (wraparound && (core_info_list->count > 1))
next = core_info_list->count - 1;
else
next = 0; /* Silence 'next' may be used uninitialized warning */
/* Get new core info */
/* If a core is now associated, get new core info */
core_info = NULL;
core_info = core_info_get(core_info_list, next);
if (!core_info)
return -1;
if (default_core_set)
core_info = core_info_get(core_info_list, next);
/* Update playlist */
playlist_set_default_core_path(playlist, core_info->path);
playlist_set_default_core_name(playlist, core_info->display_name);
playlist_write_file(
playlist, playlist_use_old_format, playlist_compression);
playlist_set_default_core_path(playlist, core_info ? core_info->path : "DETECT");
playlist_set_default_core_name(playlist, core_info ? core_info->display_name : "DETECT");
playlist_write_file(playlist, playlist_use_old_format, playlist_compression);
return 0;
}

View file

@ -1308,60 +1308,6 @@ int generic_action_ok_displaylist_push(const char *path,
return menu_cbs_exit();
}
/**
* menu_content_load_from_playlist:
* @playlist : Playlist handle.
* @idx : Index in playlist.
*
* Initializes core and loads content based on playlist entry.
**/
static bool menu_content_playlist_load(playlist_t *playlist, size_t idx)
{
char path[PATH_MAX_LENGTH];
const struct playlist_entry *entry = NULL;
path[0] = '\0';
playlist_get_index(playlist, idx, &entry);
if (!entry || string_is_empty(entry->path))
return false;
strlcpy(path, entry->path, sizeof(path));
playlist_resolve_path(PLAYLIST_LOAD, path, sizeof(path));
if (!string_is_empty(path))
{
unsigned i;
bool valid_path = false;
char *path_check = NULL;
char *path_tolower = strdup(path);
for (i = 0; i < strlen(path_tolower); ++i)
path_tolower[i] = tolower((unsigned char)path_tolower[i]);
if (strstr(path_tolower, ".zip"))
strstr(path_tolower, ".zip")[4] = '\0';
else if (strstr(path_tolower, ".7z"))
strstr(path_tolower, ".7z")[3] = '\0';
path_check = (char *)
calloc(strlen(path_tolower) + 1, sizeof(char));
strlcpy(path_check, path, strlen(path_tolower) + 1);
valid_path = path_is_valid(path_check);
free(path_tolower);
free(path_check);
if (valid_path)
return true;
}
return false;
}
/**
* menu_content_find_first_core:
* @core_info : Core info list handle.
@ -2034,17 +1980,66 @@ static int action_ok_file_load(const char *path,
CORE_TYPE_PLAIN);
}
static bool playlist_entry_path_is_valid(const char *entry_path)
{
char *archive_delim = NULL;
char *file_path = NULL;
if (string_is_empty(entry_path))
goto error;
file_path = strdup(entry_path);
/* We need to check whether the file referenced by the
* entry path actually exists. If it is a normal file,
* we can do this directly. If the path contains an
* archive delimiter, then we have to trim everything
* after the archive extension
* > Note: Have to do a nasty cast here, since
* path_get_archive_delim() returns a const char *
* (this cast is safe, though, and is done in many
* places throughout the codebase...) */
archive_delim = (char *)path_get_archive_delim(file_path);
if (archive_delim)
{
*archive_delim = '\0';
if (string_is_empty(file_path))
goto error;
}
/* Path is 'sanitised' - can now check if it exists */
if (!path_is_valid(file_path))
goto error;
/* File is valid */
free(file_path);
file_path = NULL;
return true;
error:
if (file_path)
{
free(file_path);
file_path = NULL;
}
return false;
}
static int action_ok_playlist_entry_collection(const char *path,
const char *label, unsigned type, size_t idx, size_t entry_idx)
{
char new_path[PATH_MAX_LENGTH];
char new_core_path[PATH_MAX_LENGTH];
size_t selection_ptr = 0;
char content_path[PATH_MAX_LENGTH];
char content_label[PATH_MAX_LENGTH];
char core_path[PATH_MAX_LENGTH];
size_t selection_ptr = entry_idx;
bool playlist_initialized = false;
playlist_t *playlist = NULL;
playlist_t *tmp_playlist = NULL;
const struct playlist_entry *entry = NULL;
unsigned i = 0;
core_info_t* core_info = NULL;
menu_handle_t *menu = menu_driver_get_ptr();
settings_t *settings = config_get_ptr();
bool playlist_use_old_format = settings->bools.playlist_use_old_format;
@ -2055,12 +2050,15 @@ static int action_ok_playlist_entry_collection(const char *path,
const char *path_content_video_history = settings->paths.path_content_video_history;
const char *path_content_image_history = settings->paths.path_content_image_history;
if (!menu)
return menu_cbs_exit();
content_path[0] = '\0';
content_label[0] = '\0';
core_path[0] = '\0';
new_path[0] = '\0';
new_core_path[0] = '\0';
tmp_playlist = playlist_get_cached();
if (!menu)
goto error;
/* Get playlist */
tmp_playlist = playlist_get_cached();
if (!tmp_playlist)
{
@ -2076,11 +2074,10 @@ static int action_ok_playlist_entry_collection(const char *path,
string_is_equal(menu->db_playlist_file, path_content_image_history);
enum playlist_sort_mode current_sort_mode;
tmp_playlist = playlist_init(
menu->db_playlist_file, COLLECTION_SIZE);
tmp_playlist = playlist_init(menu->db_playlist_file, COLLECTION_SIZE);
if (!tmp_playlist)
return menu_cbs_exit();
goto error;
current_sort_mode = playlist_get_sort_mode(tmp_playlist);
@ -2092,83 +2089,57 @@ static int action_ok_playlist_entry_collection(const char *path,
playlist_initialized = true;
}
playlist = tmp_playlist;
selection_ptr = entry_idx;
playlist = tmp_playlist;
/* Get playlist entry */
playlist_get_index(playlist, selection_ptr, &entry);
if (!entry)
goto error;
/* Subsystem codepath */
if (!string_is_empty(entry->subsystem_ident))
/* Cache entry path */
if (!string_is_empty(entry->path))
{
content_ctx_info_t content_info = {0};
task_push_load_new_core(entry->core_path, NULL,
&content_info, CORE_TYPE_PLAIN, NULL, NULL);
content_clear_subsystem();
if (!content_set_subsystem_by_name(entry->subsystem_ident))
{
RARCH_LOG("[playlist] subsystem not found in implementation\n");
/* TODO: Add OSD message telling users that content can't be loaded */
if (playlist_initialized)
playlist_free(tmp_playlist);
return 0;
}
for (i = 0; i < entry->subsystem_roms->size; i++)
content_add_subsystem(entry->subsystem_roms->elems[i].data);
task_push_load_subsystem_with_core_from_menu(
NULL, &content_info,
CORE_TYPE_PLAIN, NULL, NULL);
/* TODO: update playlist entry? move to first position I guess? */
if (playlist_initialized)
playlist_free(tmp_playlist);
return 1;
strlcpy(content_path, entry->path, sizeof(content_path));
playlist_resolve_path(PLAYLIST_LOAD, content_path, sizeof(content_path));
}
/* Check whether playlist already has core path/name
* assignments
* > Both core name and core path must be valid */
if ( string_is_empty(entry->core_path)
|| string_is_empty(entry->core_name)
|| string_is_equal(entry->core_path, "DETECT")
|| string_is_equal(entry->core_name, "DETECT"))
/* Cache entry label */
if (!string_is_empty(entry->label))
strlcpy(content_label, entry->label, sizeof(content_label));
/* Get core path */
if (!playlist_entry_has_core(entry))
{
core_info_ctx_find_t core_info;
const char *entry_path = NULL;
const char *default_core_path =
playlist_get_default_core_path(playlist);
bool found_associated_core = false;
struct playlist_entry update_entry = {0};
struct playlist_entry update_entry = {0};
if (!string_is_empty(default_core_path))
/* Entry core is not set - attempt to use
* playlist default */
core_info = playlist_get_default_core_info(playlist);
/* If default core is not set, prompt user
* to select one */
if (!core_info)
{
strlcpy(new_core_path, default_core_path, sizeof(new_core_path));
playlist_resolve_path(PLAYLIST_LOAD, new_core_path, sizeof(new_core_path));
found_associated_core = true;
}
core_info.inf = NULL;
core_info.path = new_core_path;
if (!core_info_find(&core_info, new_core_path))
found_associated_core = false;
if (!found_associated_core)
{
/* TODO: figure out if this should refer to the inner or outer entry_path */
/* TODO: make sure there's only one entry_path in this function */
int ret = action_ok_file_load_with_detect_core_collection(entry_path,
/* TODO: figure out if this should refer to the inner or outer content_path */
int ret = action_ok_file_load_with_detect_core_collection(content_path,
label, type, selection_ptr, entry_idx);
if (playlist_initialized)
if (playlist_initialized && tmp_playlist)
{
playlist_free(tmp_playlist);
tmp_playlist = NULL;
playlist = NULL;
}
return ret;
}
update_entry.core_path = (char*)default_core_path;
update_entry.core_name = core_info.inf->display_name;
/* Cache core path */
strlcpy(core_path, core_info->path, sizeof(core_path));
/* Update playlist entry */
update_entry.core_path = core_info->path;
update_entry.core_name = core_info->display_name;
command_playlist_update_write(
playlist,
@ -2179,208 +2150,90 @@ static int action_ok_playlist_entry_collection(const char *path,
}
else
{
strlcpy(new_core_path, entry->core_path, sizeof(new_core_path));
playlist_resolve_path(PLAYLIST_LOAD, new_core_path, sizeof(new_core_path));
}
/* Entry does have a core assignment - ensure
* it has corresponding core info entry */
core_info = playlist_entry_get_core_info(entry);
if (!playlist || !menu_content_playlist_load(playlist, selection_ptr))
{
runloop_msg_queue_push(
"File could not be loaded from playlist.\n",
1, 100, true,
NULL, MESSAGE_QUEUE_ICON_DEFAULT, MESSAGE_QUEUE_CATEGORY_INFO);
if (playlist_initialized)
playlist_free(tmp_playlist);
return menu_cbs_exit();
}
playlist_get_index(playlist, selection_ptr, &entry);
strlcpy(new_path, entry->path, sizeof(new_path));
playlist_resolve_path(PLAYLIST_LOAD, new_path, sizeof(new_path));
if (playlist_initialized)
playlist_free(tmp_playlist);
return default_action_ok_load_content_from_playlist_from_menu(
new_core_path, new_path, entry->label);
}
static int action_ok_playlist_entry(const char *path,
const char *label, unsigned type, size_t idx, size_t entry_idx)
{
char new_core_path[PATH_MAX_LENGTH];
size_t selection_ptr = 0;
const struct playlist_entry *entry = NULL;
const char *entry_label = NULL;
settings_t *settings = config_get_ptr();
playlist_t *playlist = playlist_get_cached();
menu_handle_t *menu = menu_driver_get_ptr();
bool playlist_use_old_format = settings->bools.playlist_use_old_format;
bool playlist_compression = settings->bools.playlist_compression;
new_core_path[0] = '\0';
if (!playlist || !menu)
return menu_cbs_exit();
selection_ptr = entry_idx;
playlist_get_index(playlist, selection_ptr, &entry);
entry_label = entry->label;
/* Check whether playlist already has core path/name
* assignments
* > Both core name and core path must be valid */
if ( string_is_empty(entry->core_path)
|| string_is_empty(entry->core_name)
|| string_is_equal(entry->core_path, "DETECT")
|| string_is_equal(entry->core_name, "DETECT"))
{
core_info_ctx_find_t core_info;
const char *default_core_path =
playlist_get_default_core_path(playlist);
bool found_associated_core = false;
if (!string_is_empty(default_core_path))
if (core_info && !string_is_empty(core_info->path))
strlcpy(core_path, core_info->path, sizeof(core_path));
else
{
strlcpy(new_core_path, default_core_path, sizeof(new_core_path));
playlist_resolve_path(PLAYLIST_LOAD, new_core_path, sizeof(new_core_path));
found_associated_core = true;
}
core_info.inf = NULL;
core_info.path = new_core_path;
if (!core_info_find(&core_info, new_core_path))
found_associated_core = false;
if (!found_associated_core)
/* TODO: figure out if this should refer to the inner or outer entry_path */
/* TODO: make sure there's only one entry_path in this function */
return action_ok_file_load_with_detect_core(entry->path,
label, type, selection_ptr, entry_idx);
{
struct playlist_entry entry = {0};
entry.core_path = (char*)default_core_path;
entry.core_name = core_info.inf->display_name;
command_playlist_update_write(NULL,
selection_ptr,
&entry,
playlist_use_old_format,
playlist_compression);
}
}
else
{
strlcpy(new_core_path, entry->core_path, sizeof(new_core_path));
playlist_resolve_path(PLAYLIST_LOAD, new_core_path, sizeof(new_core_path));
}
if (!playlist || !menu_content_playlist_load(playlist, selection_ptr))
{
runloop_msg_queue_push(
"File could not be loaded from playlist.\n",
1, 100, true,
NULL, MESSAGE_QUEUE_ICON_DEFAULT, MESSAGE_QUEUE_CATEGORY_INFO);
return menu_cbs_exit();
}
playlist_get_index(playlist,
selection_ptr, &entry);
return default_action_ok_load_content_from_playlist_from_menu(
new_core_path, entry->path, entry_label);
}
static int action_ok_playlist_entry_start_content(const char *path,
const char *label, unsigned type, size_t idx, size_t entry_idx)
{
size_t selection_ptr = 0;
const struct playlist_entry *entry = NULL;
settings_t *settings = config_get_ptr();
playlist_t *playlist = playlist_get_cached();
menu_handle_t *menu = menu_driver_get_ptr();
bool playlist_use_old_format = settings->bools.playlist_use_old_format;
bool playlist_compression = settings->bools.playlist_compression;
if (!playlist || !menu)
return menu_cbs_exit();
selection_ptr = menu->scratchpad.unsigned_var;
playlist_get_index(playlist, selection_ptr, &entry);
/* Check whether playlist already has core path/name
* assignments
* > Both core name and core path must be valid */
if ( string_is_empty(entry->core_path)
|| string_is_empty(entry->core_name)
|| string_is_equal(entry->core_path, "DETECT")
|| string_is_equal(entry->core_name, "DETECT"))
{
core_info_ctx_find_t core_info;
char new_core_path[PATH_MAX_LENGTH];
const char *entry_path = NULL;
const char *default_core_path =
playlist_get_default_core_path(playlist);
bool found_associated_core = false;
new_core_path[0] = '\0';
if (!string_is_empty(default_core_path))
{
strlcpy(new_core_path, default_core_path, sizeof(new_core_path));
found_associated_core = true;
}
core_info.inf = NULL;
core_info.path = new_core_path;
if (!core_info_find(&core_info, new_core_path))
found_associated_core = false;
/* TODO: figure out if this should refer to
* the inner or outer entry_path. */
/* TODO: make sure there's only one entry_path
* in this function. */
if (!found_associated_core)
return action_ok_file_load_with_detect_core(entry_path,
label, type, selection_ptr, entry_idx);
{
struct playlist_entry entry = {0};
entry.core_path = new_core_path;
entry.core_name = core_info.inf->display_name;
command_playlist_update_write(
playlist,
selection_ptr,
&entry,
playlist_use_old_format,
playlist_compression);
/* Core path is invalid - just copy what we have
* and hope for the best... */
strlcpy(core_path, entry->core_path, sizeof(core_path));
playlist_resolve_path(PLAYLIST_LOAD, core_path, sizeof(core_path));
}
}
if (!menu_content_playlist_load(playlist, selection_ptr))
{
runloop_msg_queue_push("File could not be loaded from playlist.\n",
1, 100, true, NULL, MESSAGE_QUEUE_ICON_DEFAULT,
MESSAGE_QUEUE_CATEGORY_INFO);
/* Ensure core path is valid */
if (string_is_empty(core_path) || !path_is_valid(core_path))
goto error;
/* Subsystem codepath */
if (!string_is_empty(entry->subsystem_ident))
{
content_ctx_info_t content_info = {0};
size_t i;
task_push_load_new_core(core_path, NULL,
&content_info, CORE_TYPE_PLAIN, NULL, NULL);
content_clear_subsystem();
if (!content_set_subsystem_by_name(entry->subsystem_ident))
{
RARCH_LOG("[playlist] subsystem not found in implementation\n");
goto error;
}
for (i = 0; i < entry->subsystem_roms->size; i++)
content_add_subsystem(entry->subsystem_roms->elems[i].data);
task_push_load_subsystem_with_core_from_menu(
NULL, &content_info,
CORE_TYPE_PLAIN, NULL, NULL);
/* TODO: update playlist entry? move to first position I guess? */
if (playlist_initialized && tmp_playlist)
{
playlist_free(tmp_playlist);
tmp_playlist = NULL;
playlist = NULL;
}
return 1;
}
playlist_get_index(playlist, selection_ptr, &entry);
/* Ensure entry path is valid */
if (!playlist_entry_path_is_valid(content_path))
goto error;
/* Free temporary playlist, if required */
if (playlist_initialized && tmp_playlist)
{
playlist_free(tmp_playlist);
tmp_playlist = NULL;
playlist = NULL;
}
/* Note: Have to use cached entry label, since entry
* may be free()'d by above playlist_free() - but need
* to pass NULL explicitly if label is empty */
return default_action_ok_load_content_from_playlist_from_menu(
entry->core_path, entry->path, entry->label);
core_path, content_path, string_is_empty(content_label) ? NULL : content_label);
error:
runloop_msg_queue_push(
"File could not be loaded from playlist.\n",
1, 100, true,
NULL, MESSAGE_QUEUE_ICON_DEFAULT, MESSAGE_QUEUE_CATEGORY_INFO);
if (playlist_initialized && tmp_playlist)
{
playlist_free(tmp_playlist);
tmp_playlist = NULL;
playlist = NULL;
}
return menu_cbs_exit();
}
@ -4674,7 +4527,7 @@ static int action_ok_add_to_favorites(const char *path,
core_info.inf = NULL;
core_info.path = core_path;
if (core_info_find(&core_info, 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));
}
@ -4803,7 +4656,7 @@ static int action_ok_add_to_favorites_playlist(const char *path,
core_info.inf = NULL;
core_info.path = entry->core_path;
if (core_info_find(&core_info, 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));
@ -7121,18 +6974,7 @@ static int menu_cbs_init_bind_ok_compare_type(menu_file_list_cbs_t *cbs,
BIND_ACTION_OK(cbs, action_ok_push_default);
break;
case FILE_TYPE_PLAYLIST_ENTRY:
if (string_is_equal(label, "collection"))
{
BIND_ACTION_OK(cbs, action_ok_playlist_entry_collection);
}
else if (string_is_equal(label, "rdb_entry_start_content"))
{
BIND_ACTION_OK(cbs, action_ok_playlist_entry_start_content);
}
else
{
BIND_ACTION_OK(cbs, action_ok_playlist_entry);
}
BIND_ACTION_OK(cbs, action_ok_playlist_entry_collection);
break;
#ifdef HAVE_LAKKA_SWITCH
case MENU_SET_SWITCH_GPU_PROFILE:

View file

@ -474,16 +474,18 @@ static int action_right_video_resolution(unsigned type, const char *label,
static int playlist_association_right(unsigned type, const char *label,
bool wraparound)
{
char core_path[PATH_MAX_LENGTH];
char core_filename[PATH_MAX_LENGTH];
size_t i, next, current = 0;
core_info_list_t *core_info_list = NULL;
core_info_t *core_info = NULL;
settings_t *settings = config_get_ptr();
playlist_t *playlist = playlist_get_cached();
const char *default_core_path = playlist_get_default_core_path(playlist);
bool default_core_set = false;
bool playlist_use_old_format = settings->bools.playlist_use_old_format;
bool playlist_compression = settings->bools.playlist_compression;
core_path[0] = '\0';
core_filename[0] = '\0';
if (!playlist)
return -1;
@ -493,59 +495,65 @@ static int playlist_association_right(unsigned type, const char *label,
return menu_cbs_exit();
/* Get current core path association */
if (string_is_empty(playlist_get_default_core_path(playlist)))
if (!string_is_empty(default_core_path) &&
!string_is_equal(default_core_path, "DETECT"))
{
core_path[0] = 'D';
core_path[1] = 'E';
core_path[2] = 'T';
core_path[3] = 'E';
core_path[4] = 'C';
core_path[5] = 'T';
core_path[6] = '\0';
const char *default_core_filename = path_basename(default_core_path);
if (!string_is_empty(default_core_filename))
{
strlcpy(core_filename, default_core_filename, sizeof(core_filename));
default_core_set = true;
}
}
else
strlcpy(core_path, playlist_get_default_core_path(playlist), sizeof(core_path));
/* Sort cores alphabetically */
core_info_qsort(core_info_list, CORE_INFO_LIST_SORT_DISPLAY_NAME);
/* Get the index of the currently associated core */
for (i = 0; i < core_info_list->count; i++)
/* If a core is currently associated... */
if (default_core_set)
{
core_info = NULL;
core_info = core_info_get(core_info_list, i);
if (!core_info)
return -1;
if (string_is_equal(core_info->path, core_path))
current = i;
}
/* Increment core index */
next = current + 1;
if (next >= core_info_list->count)
{
if (wraparound)
next = 0;
else
/* ...get its index */
for (i = 0; i < core_info_list->count; i++)
{
if (core_info_list->count > 0)
next = core_info_list->count - 1;
core_info = NULL;
core_info = core_info_get(core_info_list, i);
if (!core_info)
continue;
if (string_starts_with(core_filename, core_info->core_file_id.str))
current = i;
}
/* ...then increment it */
next = current + 1;
if (next >= core_info_list->count)
{
if (wraparound || (core_info_list->count < 1))
{
/* Unset core association (DETECT) */
next = 0;
default_core_set = false;
}
else
next = 0;
next = core_info_list->count - 1;
}
}
/* If a core is *not* currently associated,
* select first core in the list */
else
{
next = 0;
default_core_set = true;
}
/* Get new core info */
/* If a core is now associated, get new core info */
core_info = NULL;
core_info = core_info_get(core_info_list, next);
if (!core_info)
return -1;
if (default_core_set)
core_info = core_info_get(core_info_list, next);
/* Update playlist */
playlist_set_default_core_path(playlist, core_info->path);
playlist_set_default_core_name(playlist, core_info->display_name);
playlist_write_file(
playlist, playlist_use_old_format, playlist_compression);
playlist_set_default_core_path(playlist, core_info ? core_info->path : "DETECT");
playlist_set_default_core_name(playlist, core_info ? core_info->display_name : "DETECT");
playlist_write_file(playlist, playlist_use_old_format, playlist_compression);
return 0;
}

View file

@ -72,7 +72,7 @@ static int menu_action_sublabel_file_browser_core(file_list_t *list, unsigned ty
core_info.inf = NULL;
core_info.path = path;
if (core_info_find(&core_info, path) &&
if (core_info_find(&core_info) &&
core_info.inf->licenses_list)
{
char tmp[MENU_SUBLABEL_MAX_LENGTH];

View file

@ -347,7 +347,7 @@ static int action_get_title_deferred_core_backup_list(
core_info.path = core_path;
/* If core is found, add display name */
if (core_info_find(&core_info, core_path) &&
if (core_info_find(&core_info) &&
core_info.inf->display_name)
strlcat(s, core_info.inf->display_name, len);
else

View file

@ -157,7 +157,7 @@ static int menu_displaylist_parse_core_info(menu_displaylist_info_t *info)
core_info_finder.inf = NULL;
core_info_finder.path = core_path;
if (core_info_find(&core_info_finder, core_path))
if (core_info_find(&core_info_finder))
core_info = core_info_finder.inf;
}
else if (core_info_get_current_core(&core_info) && core_info)
@ -3282,7 +3282,7 @@ static unsigned menu_displaylist_parse_content_information(
core_info.inf = NULL;
core_info.path = core_path;
if (core_info_find(&core_info, 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));
}

View file

@ -2898,3 +2898,66 @@ void playlist_set_sort_mode(playlist_t *playlist, enum playlist_sort_mode sort_m
playlist->modified = true;
}
}
/* Returns true if specified entry has a valid
* core association (i.e. a non-empty string
* other than DETECT) */
bool playlist_entry_has_core(const struct playlist_entry *entry)
{
if (!entry ||
string_is_empty(entry->core_path) ||
string_is_empty(entry->core_name) ||
string_is_equal(entry->core_path, "DETECT") ||
string_is_equal(entry->core_name, "DETECT"))
return false;
return true;
}
/* Fetches core info object corresponding to the
* currently associated core of the specified
* playlist entry.
* Returns NULL if entry does not have a valid
* core association */
core_info_t *playlist_entry_get_core_info(const struct playlist_entry* entry)
{
core_info_ctx_find_t core_info;
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;
return NULL;
}
/* Fetches core info object corresponding to the
* currently associated default core of the
* specified playlist.
* Returns NULL if playlist does not have a valid
* default core association */
core_info_t *playlist_get_default_core_info(playlist_t* playlist)
{
core_info_ctx_find_t core_info;
if (!playlist ||
string_is_empty(playlist->default_core_path) ||
string_is_empty(playlist->default_core_name) ||
string_is_equal(playlist->default_core_path, "DETECT") ||
string_is_equal(playlist->default_core_name, "DETECT"))
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;
return NULL;
}

View file

@ -24,6 +24,8 @@
#include <boolean.h>
#include <lists/string_list.h>
#include "core_info.h"
RETRO_BEGIN_DECLS
/* Default maximum playlist size */
@ -317,6 +319,25 @@ void playlist_set_thumbnail_mode(
playlist_t *playlist, enum playlist_thumbnail_id thumbnail_id, enum playlist_thumbnail_mode thumbnail_mode);
void playlist_set_sort_mode(playlist_t *playlist, enum playlist_sort_mode sort_mode);
/* Returns true if specified entry has a valid
* core association (i.e. a non-empty string
* other than DETECT) */
bool playlist_entry_has_core(const struct playlist_entry *entry);
/* Fetches core info object corresponding to the
* currently associated core of the specified
* playlist entry.
* Returns NULL if entry does not have a valid
* core association */
core_info_t *playlist_entry_get_core_info(const struct playlist_entry* entry);
/* Fetches core info object corresponding to the
* currently associated default core of the
* specified playlist.
* Returns NULL if playlist does not have a valid
* default core association */
core_info_t *playlist_get_default_core_info(playlist_t* playlist);
RETRO_END_DECLS
#endif

View file

@ -281,15 +281,14 @@ 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_list_t *core_info = NULL;
runtime_log_t *runtime_log = NULL;
const char *core_path_basename = NULL;
core_info_ctx_find_t core_info;
runtime_log_t *runtime_log = NULL;
content_name[0] = '\0';
core_name[0] = '\0';
log_file_dir[0] = '\0';
log_file_path[0] = '\0';
tmp_buf[0] = '\0';
content_name[0] = '\0';
core_name[0] = '\0';
log_file_dir[0] = '\0';
log_file_path[0] = '\0';
tmp_buf[0] = '\0';
if ( string_is_empty(dir_runtime_log) &&
string_is_empty(dir_playlist))
@ -301,13 +300,8 @@ runtime_log_t *runtime_log_init(
if ( string_is_empty(core_path) ||
string_is_equal(core_path, "builtin") ||
string_is_equal(core_path, "DETECT"))
return NULL;
core_path_basename = path_basename(core_path);
if ( string_is_empty(content_path) ||
string_is_empty(core_path_basename))
string_is_equal(core_path, "DETECT") ||
string_is_empty(content_path))
return NULL;
/* Get core name
@ -315,24 +309,12 @@ 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_get_list(&core_info);
core_info.inf = NULL;
core_info.path = core_path;
if (!core_info)
return NULL;
for (i = 0; i < core_info->count; i++)
{
const char *entry_core_name = core_info->list[i].core_name;
if (!string_is_equal(
path_basename(core_info->list[i].path), core_path_basename))
continue;
if (string_is_empty(entry_core_name))
return NULL;
strlcpy(core_name, entry_core_name, sizeof(core_name));
break;
}
if (core_info_find(&core_info) &&
core_info.inf->core_name)
strlcpy(core_name, core_info.inf->core_name, sizeof(core_name));
if (string_is_empty(core_name))
return NULL;

View file

@ -1992,8 +1992,6 @@ static bool task_load_content_callback(content_ctx_info_t *content_info,
content_ctx.set_supports_no_game_enable = set_supports_no_game_enable;
if (!string_is_empty(path_dir_system))
content_ctx.directory_system = strdup(path_dir_system);
if (!string_is_empty(path_dir_cache))
content_ctx.directory_cache = strdup(path_dir_cache);
if (!string_is_empty(system->valid_extensions))

View file

@ -442,7 +442,7 @@ void *task_push_core_backup(const char *core_path,
core_info.path = core_path;
/* If core is found, use display name */
if (core_info_find(&core_info, core_path) &&
if (core_info_find(&core_info) &&
core_info.inf->display_name)
core_name = core_info.inf->display_name;
else
@ -881,7 +881,7 @@ bool task_push_core_restore(const char *backup_path, const char *dir_libretro,
core_info.path = core_path;
/* If core is found, use display name */
if (core_info_find(&core_info, core_path) &&
if (core_info_find(&core_info) &&
core_info.inf->display_name)
core_name = core_info.inf->display_name;
else

View file

@ -463,35 +463,19 @@ static void pl_manager_validate_core_association(
goto reset_core;
else
{
const char *core_path_basename = path_basename(core_path);
core_info_list_t *core_info = NULL;
char core_display_name[PATH_MAX_LENGTH];
size_t i;
core_info_ctx_find_t core_info;
core_display_name[0] = '\0';
if (string_is_empty(core_path_basename))
goto reset_core;
/* Search core info */
core_info.inf = NULL;
core_info.path = core_path;
/* Final check - search core info */
core_info_get_list(&core_info);
if (core_info)
{
for (i = 0; i < core_info->count; i++)
{
const char *info_display_name = core_info->list[i].display_name;
if (!string_is_equal(
path_basename(core_info->list[i].path), core_path_basename))
continue;
if (!string_is_empty(info_display_name))
strlcpy(core_display_name, info_display_name, sizeof(core_display_name));
break;
}
}
if (core_info_find(&core_info) &&
!string_is_empty(core_info.inf->display_name))
strlcpy(core_display_name, core_info.inf->display_name,
sizeof(core_display_name));
/* If core_display_name string is empty, it means the
* core wasn't found -> reset association */

View file

@ -988,7 +988,7 @@ void MainWindow::onPlaylistWidgetContextMenuRequested(const QPoint&)
coreInfo.inf = NULL;
coreInfo.path = corePath;
if (core_info_find(&coreInfo, corePath))
if (core_info_find(&coreInfo))
{
/* Set new core association */
playlist_set_default_core_path(playlist, coreInfo.inf->path);

View file

@ -1395,25 +1395,21 @@ QVector<QHash<QString, QString> > MainWindow::getCoreInfo()
{
unsigned i;
QVector<QHash<QString, QString> > infoList;
QByteArray currentCorePathArray;
core_info_ctx_find_t core_info_finder;
QHash<QString, QString> currentCore = getSelectedCore();
core_info_list_t *core_info_list = NULL;
const char *current_core_path_data = NULL;
const core_info_t *core_info = NULL;
core_info_get_list(&core_info_list);
currentCorePathArray = currentCore["core_path"].toUtf8();
current_core_path_data = currentCorePathArray.constData();
if (!core_info_list || core_info_list->count == 0)
return infoList;
/* Search for current core */
core_info_finder.inf = NULL;
core_info_finder.path = current_core_path_data;
for (i = 0; i < core_info_list->count; i++)
{
const core_info_t *core = &core_info_list->list[i];
if (currentCore["core_path"] == core->path)
{
core_info = core;
break;
}
}
if (core_info_find(&core_info_finder))
core_info = core_info_finder.inf;
if (currentCore["core_path"].isEmpty() || !core_info || !core_info->config_data)
{
@ -1865,6 +1861,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;
contentDbNameFull[0] = '\0';
@ -1958,6 +1955,15 @@ void MainWindow::loadContent(const QHash<QString, QString> &contentHash)
contentDbName = contentDbNameArray.constData();
contentCrc32 = contentCrc32Array.constData();
/* 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;
/* Add lpl extension to db_name, if required */
if (!string_is_empty(contentDbName))
{
@ -2127,11 +2133,15 @@ void MainWindow::setCoreActions()
if (!defaultCorePath.isEmpty())
{
QByteArray defaultCorePathArray;
QString currentPlaylistItemDataString;
bool allPlaylists = false;
int row = 0;
core_info_list_t *coreInfoList = NULL;
unsigned j = 0;
core_info_ctx_find_t core_info_finder;
const char *default_core_path_data = NULL;
bool allPlaylists = false;
int row = 0;
defaultCorePathArray = defaultCorePath.toUtf8();
default_core_path_data = defaultCorePathArray.constData();
if (currentPlaylistItem)
{
@ -2153,42 +2163,45 @@ void MainWindow::setCoreActions()
continue;
}
core_info_get_list(&coreInfoList);
/* Search for default core */
core_info_finder.inf = NULL;
core_info_finder.path = default_core_path_data;
if (coreInfoList)
if (core_info_find(&core_info_finder))
{
for (j = 0; j < coreInfoList->count; j++)
const core_info_t *info = core_info_finder.inf;
if (m_launchWithComboBox->findText(info->core_name) == -1)
{
const core_info_t *info = &coreInfoList->list[j];
int i = 0;
bool found_existing = false;
if (defaultCorePath == info->path)
for (i = 0; i < m_launchWithComboBox->count(); i++)
{
if (m_launchWithComboBox->findText(info->core_name) == -1)
QByteArray CorePathArray;
const char *core_path_data = NULL;
QVariantMap map = m_launchWithComboBox->itemData(i, Qt::UserRole).toMap();
CorePathArray = map.value("core_path").toString().toUtf8();
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)
{
int i = 0;
bool found_existing = false;
for (i = 0; i < m_launchWithComboBox->count(); i++)
{
QVariantMap map = m_launchWithComboBox->itemData(i, Qt::UserRole).toMap();
if (map.value("core_path").toString() == info->path || map.value("core_name").toString() == info->core_name)
{
found_existing = true;
break;
}
}
if (!found_existing)
{
QVariantMap comboBoxMap;
comboBoxMap["core_name"] = info->core_name;
comboBoxMap["core_path"] = info->path;
comboBoxMap["core_selection"] = CORE_SELECTION_PLAYLIST_DEFAULT;
m_launchWithComboBox->addItem(info->core_name, QVariant::fromValue(comboBoxMap));
}
found_existing = true;
break;
}
}
if (!found_existing)
{
QVariantMap comboBoxMap;
comboBoxMap["core_name"] = info->core_name;
comboBoxMap["core_path"] = info->path;
comboBoxMap["core_selection"] = CORE_SELECTION_PLAYLIST_DEFAULT;
m_launchWithComboBox->addItem(info->core_name, QVariant::fromValue(comboBoxMap));
}
}
}