(Core Updater) Only download when new core is available + add option to update all installed cores

This commit is contained in:
jdgleaver 2019-12-23 17:34:44 +00:00
parent 305aee2c33
commit 695749f155
23 changed files with 2394 additions and 105 deletions

View File

@ -1760,6 +1760,7 @@ ifeq ($(HAVE_NETWORKING), 1)
$(LIBRETRO_COMM_DIR)/net/net_http_parse.o \
$(LIBRETRO_COMM_DIR)/net/net_socket.o \
$(LIBRETRO_COMM_DIR)/net/net_natt.o \
core_updater_list.o \
network/net_http_special.o \
tasks/task_http.o \
tasks/task_netplay_lan_scan.o \
@ -1769,7 +1770,8 @@ ifeq ($(HAVE_NETWORKING), 1)
ifeq ($(HAVE_MENU_COMMON), 1)
OBJ += tasks/task_pl_thumbnail_download.o \
menu/menu_networking.o
tasks/task_core_updater.o \
menu/menu_networking.o
endif
ifeq ($(HAVE_SSL), 1)

778
core_updater_list.c Normal file
View File

@ -0,0 +1,778 @@
/* Copyright (C) 2010-2019 The RetroArch team
*
* ---------------------------------------------------------------------------------------
* The following license statement only applies to this file (core_updater_list.c).
* ---------------------------------------------------------------------------------------
*
* Permission is hereby granted, free of charge,
* to any person obtaining a copy of this software and associated documentation files (the "Software"),
* to deal in the Software without restriction, including without limitation the rights to
* use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software,
* and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
* INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*/
#include <file/file_path.h>
#include <string/stdstring.h>
#include <lists/string_list.h>
#include <net/net_http.h>
#include <retro_miscellaneous.h>
#include "configuration.h"
#include "file_path_special.h"
#include "core_info.h"
#include "core_updater_list.h"
/* Holds all entries in a core updater list */
struct core_updater_list
{
size_t size;
size_t capacity;
core_updater_list_entry_t *entries;
};
/* Cached ('global') core updater list */
static core_updater_list_t *core_list_cached = NULL;
/**************************************/
/* Initialisation / De-Initialisation */
/**************************************/
/* Frees contents of specified core updater
* list entry */
static void core_updater_list_free_entry(core_updater_list_entry_t *entry)
{
if (!entry)
return;
if (entry->remote_filename)
{
free(entry->remote_filename);
entry->remote_filename = NULL;
}
if (entry->remote_core_path)
{
free(entry->remote_core_path);
entry->remote_core_path = NULL;
}
if (entry->local_core_path)
{
free(entry->local_core_path);
entry->local_core_path = NULL;
}
if (entry->local_info_path)
{
free(entry->local_info_path);
entry->local_info_path = NULL;
}
if (entry->display_name)
{
free(entry->display_name);
entry->display_name = NULL;
}
}
/* Creates a new, empty core updater list.
* Returns a handle to a new core_updater_list_t object
* on success, otherwise returns NULL. */
core_updater_list_t *core_updater_list_init(size_t max_size)
{
core_updater_list_t *core_list = NULL;
core_updater_list_entry_t *entries = NULL;
/* Sanity check */
if (max_size < 1)
return NULL;
/* Create core updater list */
core_list = (core_updater_list_t*)calloc(1, sizeof(*core_list));
if (!core_list)
return NULL;
/* Create entries array */
entries = (core_updater_list_entry_t*)calloc(max_size, sizeof(*entries));
if (!entries)
{
free(core_list);
return NULL;
}
/* Initial configuration */
core_list->size = 0;
core_list->capacity = max_size;
core_list->entries = entries;
return core_list;
}
/* Resets (removes all entries of) specified core
* updater list */
void core_updater_list_reset(core_updater_list_t *core_list)
{
size_t i;
if (!core_list)
return;
for (i = 0; i < core_list->size; i++)
{
core_updater_list_entry_t *entry = &core_list->entries[i];
if (entry)
core_updater_list_free_entry(entry);
}
core_list->size = 0;
}
/* Frees specified core updater list */
void core_updater_list_free(core_updater_list_t *core_list)
{
size_t i;
if (!core_list)
return;
for (i = 0; i < core_list->size; i++)
{
core_updater_list_entry_t *entry = &core_list->entries[i];
if (entry)
core_updater_list_free_entry(entry);
}
free(core_list->entries);
core_list->entries = NULL;
free(core_list);
}
/***************/
/* Cached List */
/***************/
/* Creates a new, empty cached core updater list
* (i.e. 'global' list).
* Returns false in the event of an error. */
bool core_updater_list_init_cached(size_t max_size)
{
/* Free any existing cached core updater list */
if (core_list_cached)
{
core_updater_list_free(core_list_cached);
core_list_cached = NULL;
}
core_list_cached = core_updater_list_init(max_size);
if (!core_list_cached)
return false;
return true;
}
/* Fetches cached core updater list */
core_updater_list_t *core_updater_list_get_cached(void)
{
if (core_list_cached)
return core_list_cached;
return NULL;
}
/* Frees cached core updater list */
void core_updater_list_free_cached(void)
{
core_updater_list_free(core_list_cached);
core_list_cached = NULL;
}
/***********/
/* Getters */
/***********/
/* Returns number of entries in core updater list */
size_t core_updater_list_size(core_updater_list_t *core_list)
{
if (!core_list)
return 0;
return core_list->size;
}
/* Returns maximum allowed number of entries in core
* updater list */
size_t core_updater_list_capacity(core_updater_list_t *core_list)
{
if (!core_list)
return 0;
return core_list->capacity;
}
/* Fetches core updater list entry corresponding
* to the specified entry index.
* Returns false if index is invalid. */
bool core_updater_list_get_index(
core_updater_list_t *core_list,
size_t idx,
const core_updater_list_entry_t **entry)
{
if (!core_list || !entry)
return false;
if (idx >= core_list->size)
return false;
if (entry)
*entry = &core_list->entries[idx];
return true;
}
/* Fetches core updater list entry corresponding
* to the specified remote core filename.
* Returns false if core is not found. */
bool core_updater_list_get_filename(
core_updater_list_t *core_list,
const char *remote_filename,
const core_updater_list_entry_t **entry)
{
size_t i;
if (!core_list || string_is_empty(remote_filename))
return false;
if (core_list->size < 1)
return false;
/* Search for specified filename */
for (i = 0; i < core_list->size; i++)
{
core_updater_list_entry_t *current_entry = &core_list->entries[i];
if (string_is_empty(current_entry->remote_filename))
continue;
if (string_is_equal(remote_filename, current_entry->remote_filename))
{
if (entry)
*entry = current_entry;
return true;
}
}
return false;
}
/* Fetches core updater list entry corresponding
* to the specified core.
* Returns false if core is not found. */
bool core_updater_list_get_core(
core_updater_list_t *core_list,
const char *local_core_path,
const core_updater_list_entry_t **entry)
{
size_t i;
char real_core_path[PATH_MAX_LENGTH];
real_core_path[0] = '\0';
if (!core_list || !entry || string_is_empty(local_core_path))
return false;
if (core_list->size < 1)
return false;
/* Resolve absolute pathname of local_core_path */
strlcpy(real_core_path, local_core_path, sizeof(real_core_path));
path_resolve_realpath(real_core_path, sizeof(real_core_path), true);
if (string_is_empty(real_core_path))
return false;
/* Search for specified core */
for (i = 0; i < core_list->size; i++)
{
core_updater_list_entry_t *current_entry = &core_list->entries[i];
if (string_is_empty(current_entry->local_core_path))
continue;
#ifdef _WIN32
/* Handle case-insensitive operating systems*/
if (string_is_equal_noncase(real_core_path, current_entry->local_core_path))
{
#else
if (string_is_equal(real_core_path, current_entry->local_core_path))
{
#endif
if (entry)
*entry = current_entry;
return true;
}
}
return false;
}
/***********/
/* Setters */
/***********/
/* Parses date string and adds contents to
* specified core updater list entry */
static bool core_updater_list_set_date(
core_updater_list_entry_t *entry, const char *date_str)
{
struct string_list *date_list = NULL;
if (!entry || string_is_empty(date_str))
goto error;
/* Split date string into component values */
date_list = string_split(date_str, "-");
if (!date_list)
goto error;
/* Date string must have 3 values:
* [year] [month] [day] */
if (date_list->size < 3)
goto error;
/* Convert date string values */
entry->date.year = string_to_unsigned(date_list->elems[0].data);
entry->date.month = string_to_unsigned(date_list->elems[1].data);
entry->date.day = string_to_unsigned(date_list->elems[2].data);
/* Clean up */
string_list_free(date_list);
return true;
error:
if (date_list)
string_list_free(date_list);
return false;
}
/* Parses crc string and adds value to
* specified core updater list entry */
static bool core_updater_list_set_crc(
core_updater_list_entry_t *entry, const char *crc_str)
{
uint32_t crc;
if (!entry || string_is_empty(crc_str))
return false;
crc = (uint32_t)string_hex_to_unsigned(crc_str);
if (crc == 0)
return false;
entry->crc = crc;
return true;
}
/* Parses core filename string and adds all
* associated paths to the specified core
* updater list entry */
static bool core_updater_list_set_paths(
core_updater_list_entry_t *entry, const char *filename_str)
{
settings_t *settings = config_get_ptr();
char *last_underscore = NULL;
char *tmp_url = NULL;
char remote_core_path[PATH_MAX_LENGTH];
char local_core_path[PATH_MAX_LENGTH];
char local_info_path[PATH_MAX_LENGTH];
char display_name[255];
bool is_archive;
remote_core_path[0] = '\0';
local_core_path[0] = '\0';
local_info_path[0] = '\0';
display_name[0] = '\0';
if (!entry || string_is_empty(filename_str) || !settings)
return false;
if (string_is_empty(settings->paths.directory_libretro) ||
string_is_empty(settings->paths.path_libretro_info) ||
string_is_empty(settings->paths.network_buildbot_url))
return false;
/* Check whether remote file is an archive */
is_archive = path_is_compressed_file(filename_str);
/* remote_filename */
if (entry->remote_filename)
{
free(entry->remote_filename);
entry->remote_filename = NULL;
}
entry->remote_filename = strdup(filename_str);
/* remote_core_path */
fill_pathname_join(
remote_core_path,
settings->paths.network_buildbot_url,
filename_str,
sizeof(remote_core_path));
/* > Apply proper URL encoding (messy...) */
tmp_url = strdup(remote_core_path);
remote_core_path[0] = '\0';
net_http_urlencode_full(
remote_core_path, tmp_url, sizeof(remote_core_path));
if (tmp_url)
free(tmp_url);
if (entry->remote_core_path)
{
free(entry->remote_core_path);
entry->remote_core_path = NULL;
}
entry->remote_core_path = strdup(remote_core_path);
/* local_core_path */
fill_pathname_join(
local_core_path,
settings->paths.directory_libretro,
filename_str,
sizeof(local_core_path));
if (is_archive)
path_remove_extension(local_core_path);
path_resolve_realpath(local_core_path, sizeof(local_core_path), true);
if (entry->local_core_path)
{
free(entry->local_core_path);
entry->local_core_path = NULL;
}
entry->local_core_path = strdup(local_core_path);
/* local_info_path */
fill_pathname_join_noext(
local_info_path,
settings->paths.path_libretro_info,
filename_str,
sizeof(local_info_path));
if (is_archive)
path_remove_extension(local_info_path);
/* > Remove any non-standard core filename
* additions (i.e. info files end with
* '_libretro' but core files may have
* a platform specific addendum,
* e.g. '_android')*/
last_underscore = (char*)strrchr(local_info_path, '_');
if (!string_is_empty(last_underscore))
{
if (string_is_not_equal_fast(last_underscore, "_libretro", 9))
*last_underscore = '\0';
}
/* > Add proper file extension */
strlcat(
local_info_path,
file_path_str(FILE_PATH_CORE_INFO_EXTENSION),
sizeof(local_info_path));
if (entry->local_info_path)
{
free(entry->local_info_path);
entry->local_info_path = NULL;
}
entry->local_info_path = strdup(local_info_path);
/* display_name
* > Note: It's a bit rubbish that we have to
* read the actual core info files here...
* Would be better to cache this globally
* (at present, we only cache info for
* *installed* cores...) */
if (path_is_valid(local_info_path))
if (!core_info_get_display_name(
local_info_path, display_name, sizeof(display_name)))
display_name[0] = '\0';
/* > If info file does not exist, just use
* core filename */
if (string_is_empty(display_name))
strlcpy(display_name, filename_str, sizeof(display_name));
if (entry->display_name)
{
free(entry->display_name);
entry->display_name = NULL;
}
entry->display_name = strdup(display_name);
return true;
}
/* Adds entry to the end of the specified core
* updater list
* NOTE: Entry string values are passed by
* reference - *do not free the entry passed
* to this function* */
static bool core_updater_list_push_entry(
core_updater_list_t *core_list, core_updater_list_entry_t *entry)
{
core_updater_list_entry_t *list_entry = NULL;
if (!core_list || !entry)
return false;
/* Ensure there is enough space for the new entry */
if (core_list->capacity <= core_list->size)
return false;
/* Get handle of new entry inside list */
list_entry = &core_list->entries[core_list->size];
if (!list_entry)
return false;
/* Ensure list entry is empty */
core_updater_list_free_entry(list_entry);
/* Assign paths */
list_entry->remote_filename = entry->remote_filename;
list_entry->remote_core_path = entry->remote_core_path;
list_entry->local_core_path = entry->local_core_path;
list_entry->local_info_path = entry->local_info_path;
list_entry->display_name = entry->display_name;
/* Copy crc */
list_entry->crc = entry->crc;
/* Copy date */
memcpy(&list_entry->date, &entry->date, sizeof(core_updater_list_date_t));
/* Increment list size */
core_list->size++;
return true;
}
/* Parses the contents of a single buildbot
* core listing and adds it to the specified
* core updater list */
static void core_updater_list_add_entry(
core_updater_list_t *core_list,
struct string_list *network_core_entry_list)
{
const char *date_str = NULL;
const char *crc_str = NULL;
const char *filename_str = NULL;
core_updater_list_entry_t entry = {0};
if (!core_list || !network_core_entry_list)
goto error;
/* > Listings must have 3 entries:
* [date] [crc] [filename] */
if (network_core_entry_list->size < 3)
goto error;
/* Get handles of the individual listing strings */
date_str = network_core_entry_list->elems[0].data;
crc_str = network_core_entry_list->elems[1].data;
filename_str = network_core_entry_list->elems[2].data;
if (string_is_empty(date_str) ||
string_is_empty(crc_str) ||
string_is_empty(filename_str))
goto error;
/* Check whether core file is already included
* in the list (this is *not* an error condition,
* it just means we can skip the current listing) */
if (core_updater_list_get_filename(core_list, filename_str, NULL))
goto error;
/* Parse individual listing strings */
if (!core_updater_list_set_date(&entry, date_str))
goto error;
if (!core_updater_list_set_crc(&entry, crc_str))
goto error;
if (!core_updater_list_set_paths(&entry, filename_str))
goto error;
/* Add entry to list */
if (!core_updater_list_push_entry(core_list, &entry))
goto error;
return;
error:
/* This is not a *fatal* error - it just
* means one of the following:
* - The current line of entry text received
* from the buildbot is broken somehow
* (could be the case that the network buffer
* wasn't large enough to cache the entire
* string, so the last line was truncated)
* - The core updater list struct is at capacity
* In either case, the current entry is discarded
* and we move on to the next one
* (network transfers are fishy business, so we
* choose to ignore this sort of error - don't
* want the whole fetch to fail because of a
* trivial glitch...) */
core_updater_list_free_entry(&entry);
}
/* Core updater list qsort helper function */
static int core_updater_list_qsort_func(
const core_updater_list_entry_t *a, const core_updater_list_entry_t *b)
{
if (!a || !b)
return 0;
if (string_is_empty(a->display_name) || string_is_empty(b->display_name))
return 0;
return strcasecmp(a->display_name, b->display_name);
}
/* Sorts core updater list into alphabetical order */
static void core_updater_list_qsort(core_updater_list_t *core_list)
{
if (!core_list)
return;
if (core_list->size < 2)
return;
qsort(
core_list->entries,
core_list->size,
sizeof(core_updater_list_entry_t),
(int (*)(const void *, const void *))
core_updater_list_qsort_func);
}
/* Reads the contents of a buildbot core list
* network request into the specified
* core_updater_list_t object.
* Returns false in the event of an error. */
bool core_updater_list_parse_network_data(
core_updater_list_t *core_list, const char *data, size_t len)
{
struct string_list *network_core_list = NULL;
struct string_list *network_core_entry_list = NULL;
char *data_buf = NULL;
size_t i;
/* Sanity check */
if (!core_list || string_is_empty(data) || (len < 1))
goto error;
/* We're populating a list 'from scratch' - remove
* any existing entries */
core_updater_list_reset(core_list);
/* Input data string is not terminated - have
* to copy it to a temporary buffer... */
data_buf = (char*)malloc((len + 1) * sizeof(char));
if (!data_buf)
goto error;
memcpy(data_buf, data, len * sizeof(char));
data_buf[len] = '\0';
/* Split network listing request into lines */
network_core_list = string_split(data_buf, "\n");
if (!network_core_list)
goto error;
if (network_core_list->size < 1)
goto error;
/* Temporary data buffer is no longer required */
free(data_buf);
/* Loop over lines */
for (i = 0; i < network_core_list->size; i++)
{
const char *line = network_core_list->elems[i].data;
if (string_is_empty(line))
continue;
/* Split line into listings info components */
network_core_entry_list = string_split(line, " ");
/* Parse listings info and add to core updater
* list */
core_updater_list_add_entry(
core_list, network_core_entry_list);
/* Clean up */
string_list_free(network_core_entry_list);
network_core_entry_list = NULL;
}
/* Sanity check */
if (core_list->size < 1)
goto error;
/* Clean up */
string_list_free(network_core_list);
/* Sort completed list */
core_updater_list_qsort(core_list);
return true;
error:
if (network_core_list)
string_list_free(network_core_list);
if (network_core_entry_list)
string_list_free(network_core_entry_list);
if (data_buf)
free(data_buf);
return false;
}

143
core_updater_list.h Normal file
View File

@ -0,0 +1,143 @@
/* Copyright (C) 2010-2019 The RetroArch team
*
* ---------------------------------------------------------------------------------------
* The following license statement only applies to this file (core_updater_list.h).
* ---------------------------------------------------------------------------------------
*
* Permission is hereby granted, free of charge,
* to any person obtaining a copy of this software and associated documentation files (the "Software"),
* to deal in the Software without restriction, including without limitation the rights to
* use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software,
* and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
* INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*/
#ifndef __CORE_UPDATER_LIST_H
#define __CORE_UPDATER_LIST_H
#include <retro_common_api.h>
#include <libretro.h>
#include <boolean.h>
RETRO_BEGIN_DECLS
/* Default maximum number of entries in
* a core updater list */
#define CORE_UPDATER_LIST_SIZE 9999
/* Holds all date info for a core file
* on the buildbot */
typedef struct
{
unsigned year;
unsigned month;
unsigned day;
} core_updater_list_date_t;
/* Holds all info related to a core
* file on the buildbot */
typedef struct
{
char *remote_filename;
char *remote_core_path;
char *local_core_path;
char *local_info_path;
char *display_name;
uint32_t crc;
core_updater_list_date_t date;
} core_updater_list_entry_t;
/* Prevent direct access to core_updater_list_t
* members */
typedef struct core_updater_list core_updater_list_t;
/**************************************/
/* Initialisation / De-Initialisation */
/**************************************/
/* Creates a new, empty core updater list with a
* maximum number of 'max_size' entries.
* Returns a handle to a new core_updater_list_t object
* on success, otherwise returns NULL. */
core_updater_list_t *core_updater_list_init(size_t max_size);
/* Resets (removes all entries of) specified core
* updater list */
void core_updater_list_reset(core_updater_list_t *core_list);
/* Frees specified core updater list */
void core_updater_list_free(core_updater_list_t *core_list);
/***************/
/* Cached List */
/***************/
/* Creates a new, empty cached core updater list
* (i.e. 'global' list).
* Returns false in the event of an error. */
bool core_updater_list_init_cached(size_t max_size);
/* Fetches cached core updater list */
core_updater_list_t *core_updater_list_get_cached(void);
/* Frees cached core updater list */
void core_updater_list_free_cached(void);
/***********/
/* Getters */
/***********/
/* Returns number of entries in core updater list */
size_t core_updater_list_size(core_updater_list_t *core_list);
/* Returns maximum allowed number of entries in core
* updater list */
size_t core_updater_list_capacity(core_updater_list_t *core_list);
/* Fetches core updater list entry corresponding
* to the specified entry index.
* Returns false if index is invalid. */
bool core_updater_list_get_index(
core_updater_list_t *core_list,
size_t idx,
const core_updater_list_entry_t **entry);
/* Fetches core updater list entry corresponding
* to the specified remote core filename.
* Returns false if core is not found. */
bool core_updater_list_get_filename(
core_updater_list_t *core_list,
const char *remote_filename,
const core_updater_list_entry_t **entry);
/* Fetches core updater list entry corresponding
* to the specified core.
* Returns false if core is not found. */
bool core_updater_list_get_core(
core_updater_list_t *core_list,
const char *local_core_path,
const core_updater_list_entry_t **entry);
/***********/
/* Setters */
/***********/
/* Reads the contents of a buildbot core list
* network request into the specified
* core_updater_list_t object.
* Returns false in the event of an error. */
bool core_updater_list_parse_network_data(
core_updater_list_t *core_list, const char *data, size_t len);
RETRO_END_DECLS
#endif

View File

@ -1084,6 +1084,10 @@ FRONTEND
#include "../core_info.c"
#if defined(HAVE_NETWORKING)
#include "../core_updater_list.c"
#endif
/*============================================================
UI
============================================================ */
@ -1235,6 +1239,7 @@ DATA RUNLOOP
#endif
#if defined(HAVE_NETWORKING) && defined(HAVE_MENU)
#include "../tasks/task_pl_thumbnail_download.c"
#include "../tasks/task_core_updater.c"
#endif
/*============================================================

View File

@ -487,6 +487,8 @@ MSG_HASH(MENU_ENUM_LABEL_DOWNLOAD_CORE_CONTENT,
"download_core_content")
MSG_HASH(MENU_ENUM_LABEL_DOWNLOAD_CORE_CONTENT_DIRS,
"download_core_content_dirs")
MSG_HASH(MENU_ENUM_LABEL_UPDATE_INSTALLED_CORES,
"update_installed_cores")
MSG_HASH(MENU_ENUM_LABEL_CONTENT_DIR,
"content_directory")
MSG_HASH(MENU_ENUM_LABEL_MENU_SCALE_FACTOR,

View File

@ -832,6 +832,54 @@ MSG_HASH(
MENU_ENUM_LABEL_VALUE_DOWNLOAD_CORE_CONTENT,
"Content Downloader"
)
MSG_HASH(
MENU_ENUM_LABEL_VALUE_UPDATE_INSTALLED_CORES,
"Update Installed Cores"
)
MSG_HASH(
MENU_ENUM_SUBLABEL_UPDATE_INSTALLED_CORES,
"Update all installed cores to the latest version available."
)
MSG_HASH(
MSG_FETCHING_CORE_LIST,
"Fetching core list..."
)
MSG_HASH(
MSG_CORE_LIST_FAILED,
"Failed to retrieve core list!"
)
MSG_HASH(
MSG_LATEST_CORE_INSTALLED,
"Latest version already installed: "
)
MSG_HASH(
MSG_UPDATING_CORE,
"Updating core: "
)
MSG_HASH(
MSG_DOWNLOADING_CORE,
"Downloading core: "
)
MSG_HASH(
MSG_EXTRACTING_CORE,
"Extracting core: "
)
MSG_HASH(
MSG_CORE_INSTALLED,
"Core installed: "
)
MSG_HASH(
MSG_SCANNING_CORES,
"Scanning cores..."
)
MSG_HASH(
MSG_CHECKING_CORE,
"Checking core: "
)
MSG_HASH(
MSG_ALL_CORES_UPDATED,
"All installed cores at latest version"
)
MSG_HASH(
MENU_ENUM_LABEL_VALUE_MENU_SCALE_FACTOR,
"Menu Scale Factor"

View File

@ -141,6 +141,11 @@ void string_replace_all_chars(char *str, char find, char replace);
* Returns 0 if string is invalid */
unsigned string_to_unsigned(const char *str);
/* Converts hexadecimal string to unsigned integer.
* Handles optional leading '0x'.
* Returns 0 if string is invalid */
unsigned string_hex_to_unsigned(const char *str);
RETRO_END_DECLS
#endif

View File

@ -349,3 +349,36 @@ unsigned string_to_unsigned(const char *str)
return (unsigned)strtoul(str, NULL, 10);
}
/* Converts hexadecimal string to unsigned integer.
* Handles optional leading '0x'.
* Returns 0 if string is invalid */
unsigned string_hex_to_unsigned(const char *str)
{
const char *hex_str = str;
const char *ptr = NULL;
size_t len;
if (string_is_empty(str))
return 0;
/* Remove leading '0x', if required */
len = strlen(str);
if (len >= 2)
if ((str[0] == '0') &&
((str[1] == 'x') || (str[1] == 'X')))
hex_str = str + 2;
if (string_is_empty(hex_str))
return 0;
/* Check for valid characters */
for (ptr = hex_str; *ptr != '\0'; ptr++)
{
if (!isxdigit(*ptr))
return 0;
}
return (unsigned)strtoul(hex_str, NULL, 16);
}

View File

@ -3797,12 +3797,11 @@ static void cb_decompressed(retro_task_t *task,
switch (type_hash)
{
case CB_CORE_UPDATER_DOWNLOAD:
generic_action_ok_command(CMD_EVENT_CORE_INFO_INIT);
break;
case CB_UPDATE_ASSETS:
generic_action_ok_command(CMD_EVENT_REINIT);
break;
default:
break;
}
}
@ -3820,6 +3819,37 @@ static void cb_decompressed(retro_task_t *task,
}
#endif
static int action_ok_core_updater_list(const char *path,
const char *label, unsigned type, size_t idx, size_t entry_idx)
{
core_updater_list_t *core_list = NULL;
bool refresh = true;
/* Get cached core updater list, initialising
* it if required */
core_list = core_updater_list_get_cached();
if (!core_list)
{
core_updater_list_init_cached(CORE_UPDATER_LIST_SIZE);
core_list = core_updater_list_get_cached();
if (!core_list)
return menu_cbs_exit();
}
/* Initial setup... */
menu_entries_ctl(MENU_ENTRIES_CTL_SET_REFRESH, &refresh);
generic_action_ok_command(CMD_EVENT_NETWORK_INIT);
/* Push core list update task */
task_push_get_core_updater_list(core_list, false, true);
return generic_action_ok_displaylist_push(
path, NULL, label, type, idx, entry_idx,
ACTION_OK_DL_CORE_UPDATER_LIST);
}
static int generic_action_ok_network(const char *path,
const char *label, unsigned type, size_t idx, size_t entry_idx,
enum msg_hash_enums enum_idx)
@ -3860,17 +3890,6 @@ static int generic_action_ok_network(const char *path,
callback = cb_net_generic;
suppress_msg = true;
break;
case MENU_ENUM_LABEL_CB_CORE_UPDATER_LIST:
if (string_is_empty(settings->paths.network_buildbot_url))
return menu_cbs_exit();
fill_pathname_join(url_path, settings->paths.network_buildbot_url,
".index-extended", sizeof(url_path));
url_label = msg_hash_to_str(enum_idx);
type_id2 = ACTION_OK_DL_CORE_UPDATER_LIST;
callback = cb_net_generic;
break;
case MENU_ENUM_LABEL_CB_THUMBNAILS_UPDATER_LIST:
fill_pathname_join(url_path,
"http://thumbnailpacks.libretro.com",
@ -3919,7 +3938,6 @@ static int (funcname)(const char *path, const char *label, unsigned type, size_t
default_action_ok_list(action_ok_core_content_list, MENU_ENUM_LABEL_CB_CORE_CONTENT_LIST)
default_action_ok_list(action_ok_core_content_dirs_list, MENU_ENUM_LABEL_CB_CORE_CONTENT_DIRS_LIST)
default_action_ok_list(action_ok_core_updater_list, MENU_ENUM_LABEL_CB_CORE_UPDATER_LIST)
default_action_ok_list(action_ok_thumbnails_updater_list, MENU_ENUM_LABEL_CB_THUMBNAILS_UPDATER_LIST)
default_action_ok_list(action_ok_lakka_list, MENU_ENUM_LABEL_CB_LAKKA_LIST)
@ -3952,7 +3970,7 @@ void cb_generic_download(retro_task_t *task,
settings_t *settings = config_get_ptr();
http_transfer_data_t *data = (http_transfer_data_t*)task_data;
if (!data || !data->data | !transf)
if (!data || !data->data || !transf)
goto finish;
output_path[0] = '\0';
@ -3965,9 +3983,6 @@ void cb_generic_download(retro_task_t *task,
case MENU_ENUM_LABEL_CB_CORE_THUMBNAILS_DOWNLOAD:
dir_path = settings->paths.directory_thumbnails;
break;
case MENU_ENUM_LABEL_CB_CORE_UPDATER_DOWNLOAD:
dir_path = settings->paths.directory_libretro;
break;
case MENU_ENUM_LABEL_CB_CORE_CONTENT_DOWNLOAD:
dir_path = settings->paths.directory_core_assets;
#if defined(HAVE_COMPRESSION) && defined(HAVE_ZLIB)
@ -4094,28 +4109,23 @@ void cb_generic_download(retro_task_t *task,
if (path_is_compressed_file(output_path))
{
void *frontend_userdata = task->frontend_userdata;
task->frontend_userdata = NULL;
retro_task_t *decompress_task = NULL;
void *frontend_userdata = task->frontend_userdata;
task->frontend_userdata = NULL;
if (!task_push_decompress(output_path, dir_path,
NULL, NULL, NULL,
cb_decompressed, (void*)(uintptr_t)
msg_hash_calculate(msg_hash_to_str(transf->enum_idx)),
frontend_userdata))
decompress_task = (retro_task_t*)task_push_decompress(
output_path, dir_path,
NULL, NULL, NULL,
cb_decompressed, (void*)(uintptr_t)
msg_hash_calculate(msg_hash_to_str(transf->enum_idx)),
frontend_userdata, false);
if (!decompress_task)
{
err = msg_hash_to_str(MSG_DECOMPRESSION_FAILED);
goto finish;
}
}
#else
switch (transf->enum_idx)
{
case MENU_ENUM_LABEL_CB_CORE_UPDATER_DOWNLOAD:
generic_action_ok_command(CMD_EVENT_CORE_INFO_INIT);
break;
default:
break;
}
#endif
finish:
@ -4249,6 +4259,36 @@ static int action_ok_core_content_download(const char *path,
MENU_ENUM_LABEL_CB_CORE_CONTENT_DOWNLOAD);
}
static int action_ok_core_updater_download(const char *path,
const char *label, unsigned type, size_t idx, size_t entry_idx)
{
#ifdef HAVE_NETWORKING
core_updater_list_t *core_list = core_updater_list_get_cached();
if (!core_list)
return menu_cbs_exit();
task_push_core_updater_download(
core_list, path, false, true);
#endif
return 0;
}
static int action_ok_update_installed_cores(const char *path,
const char *label, unsigned type, size_t idx, size_t entry_idx)
{
#ifdef HAVE_NETWORKING
/* Ensure networking is initialised */
generic_action_ok_command(CMD_EVENT_NETWORK_INIT);
/* Push update task */
task_push_update_installed_cores();
#endif
return 0;
}
#define default_action_ok_download(funcname, _id) \
static int (funcname)(const char *path, const char *label, unsigned type, size_t idx, size_t entry_idx) \
{ \
@ -4258,7 +4298,6 @@ static int (funcname)(const char *path, const char *label, unsigned type, size_t
default_action_ok_download(action_ok_core_content_thumbnails, MENU_ENUM_LABEL_CB_CORE_THUMBNAILS_DOWNLOAD)
default_action_ok_download(action_ok_thumbnails_updater_download, MENU_ENUM_LABEL_CB_THUMBNAILS_UPDATER_DOWNLOAD)
default_action_ok_download(action_ok_download_url, MENU_ENUM_LABEL_CB_DOWNLOAD_URL)
default_action_ok_download(action_ok_core_updater_download, MENU_ENUM_LABEL_CB_CORE_UPDATER_DOWNLOAD)
default_action_ok_download(action_ok_lakka_download, MENU_ENUM_LABEL_CB_LAKKA_DOWNLOAD)
default_action_ok_download(action_ok_update_assets, MENU_ENUM_LABEL_CB_UPDATE_ASSETS)
default_action_ok_download(action_ok_update_core_info_files, MENU_ENUM_LABEL_CB_UPDATE_CORE_INFO_FILES)
@ -6506,6 +6545,9 @@ static int menu_cbs_init_bind_ok_compare_label(menu_file_list_cbs_t *cbs,
case MENU_ENUM_LABEL_CORE_UPDATER_LIST:
BIND_ACTION_OK(cbs, action_ok_core_updater_list);
break;
case MENU_ENUM_LABEL_UPDATE_INSTALLED_CORES:
BIND_ACTION_OK(cbs, action_ok_update_installed_cores);
break;
case MENU_ENUM_LABEL_THUMBNAILS_UPDATER_LIST:
BIND_ACTION_OK(cbs, action_ok_thumbnails_updater_list);
break;

View File

@ -290,6 +290,7 @@ default_sublabel_macro(action_bind_sublabel_video_post_filter_record, MENU_
default_sublabel_macro(action_bind_sublabel_start_core, MENU_ENUM_SUBLABEL_START_CORE)
default_sublabel_macro(action_bind_sublabel_core_list, MENU_ENUM_SUBLABEL_CORE_LIST)
default_sublabel_macro(action_bind_sublabel_download_core, MENU_ENUM_SUBLABEL_DOWNLOAD_CORE)
default_sublabel_macro(action_bind_sublabel_update_installed_cores, MENU_ENUM_SUBLABEL_UPDATE_INSTALLED_CORES)
default_sublabel_macro(action_bind_sublabel_sideload_core_list, MENU_ENUM_SUBLABEL_SIDELOAD_CORE_LIST)
default_sublabel_macro(action_bind_sublabel_load_disc, MENU_ENUM_SUBLABEL_LOAD_DISC)
default_sublabel_macro(action_bind_sublabel_dump_disc, MENU_ENUM_SUBLABEL_DUMP_DISC)
@ -2423,6 +2424,9 @@ int menu_cbs_init_bind_sublabel(menu_file_list_cbs_t *cbs,
case MENU_ENUM_LABEL_CORE_UPDATER_LIST:
BIND_ACTION_SUBLABEL(cbs, action_bind_sublabel_download_core);
break;
case MENU_ENUM_LABEL_UPDATE_INSTALLED_CORES:
BIND_ACTION_SUBLABEL(cbs, action_bind_sublabel_update_installed_cores);
break;
case MENU_ENUM_LABEL_VIDEO_POST_FILTER_RECORD:
BIND_ACTION_SUBLABEL(cbs, action_bind_sublabel_video_post_filter_record);
break;

View File

@ -7615,6 +7615,7 @@ static void materialui_list_insert(
else if (
string_is_equal(label, msg_hash_to_str(MENU_ENUM_LABEL_ONLINE_UPDATER)) ||
string_is_equal(label, msg_hash_to_str(MENU_ENUM_LABEL_UPDATE_CORE_INFO_FILES)) ||
string_is_equal(label, msg_hash_to_str(MENU_ENUM_LABEL_UPDATE_INSTALLED_CORES)) ||
string_is_equal(label, msg_hash_to_str(MENU_ENUM_LABEL_UPDATE_AUTOCONFIG_PROFILES)) ||
string_is_equal(label, msg_hash_to_str(MENU_ENUM_LABEL_UPDATE_ASSETS)) ||
string_is_equal(label, msg_hash_to_str(MENU_ENUM_LABEL_UPDATE_CHEATS)) ||

View File

@ -112,6 +112,7 @@ menu_texture_item ozone_entries_icon_get_texture(ozone_handle_t *ozone,
case MENU_ENUM_LABEL_SIDELOAD_CORE_LIST:
case MENU_ENUM_LABEL_CORE_SETTINGS:
case MENU_ENUM_LABEL_CORE_UPDATER_LIST:
case MENU_ENUM_LABEL_UPDATE_INSTALLED_CORES:
case MENU_ENUM_LABEL_VIDEO_SHADER_PRESET_SAVE_CORE:
case MENU_ENUM_LABEL_SAVE_CURRENT_CONFIG_OVERRIDE_CORE:
case MENU_ENUM_LABEL_REMAP_FILE_SAVE_CORE:

View File

@ -2388,6 +2388,7 @@ static uintptr_t xmb_icon_get_id(xmb_handle_t *xmb,
case MENU_ENUM_LABEL_SIDELOAD_CORE_LIST:
case MENU_ENUM_LABEL_CORE_SETTINGS:
case MENU_ENUM_LABEL_CORE_UPDATER_LIST:
case MENU_ENUM_LABEL_UPDATE_INSTALLED_CORES:
case MENU_ENUM_LABEL_VIDEO_SHADER_PRESET_SAVE_CORE:
case MENU_ENUM_LABEL_SAVE_CURRENT_CONFIG_OVERRIDE_CORE:
case MENU_ENUM_LABEL_REMAP_FILE_SAVE_CORE:

View File

@ -46,6 +46,7 @@
#include <net/net_http_parse.h>
#include "../../network/netplay/netplay.h"
#include "../network/netplay/netplay_discovery.h"
#include "../core_updater_list.h"
#endif
#ifdef HAVE_LAKKA_SWITCH
@ -7922,9 +7923,35 @@ bool menu_displaylist_ctl(enum menu_displaylist_ctl_state type,
case DISPLAYLIST_CORES_UPDATER:
menu_entries_ctl(MENU_ENTRIES_CTL_CLEAR, info->list);
#ifdef HAVE_NETWORKING
count = print_buf_lines(info->list, menu->core_buf, "",
(int)menu->core_len, FILE_TYPE_DOWNLOAD_CORE, true, true);
{
core_updater_list_t *core_list = core_updater_list_get_cached();
if (core_list)
{
size_t i;
for (i = 0; i < core_updater_list_size(core_list); i++)
{
const core_updater_list_entry_t *entry = NULL;
if (core_updater_list_get_index(core_list, i, &entry))
{
if (menu_entries_append_enum(info->list,
entry->remote_filename,
"",
MENU_ENUM_LABEL_URL_ENTRY,
FILE_TYPE_DOWNLOAD_CORE, 0, 0))
{
file_list_set_alt_at_offset(
info->list, i, entry->display_name);
count++;
}
}
}
}
}
#endif
if (count == 0)
menu_entries_append_enum(info->list,
msg_hash_to_str(MENU_ENUM_LABEL_VALUE_NO_ENTRIES_TO_DISPLAY),
@ -7935,7 +7962,7 @@ bool menu_displaylist_ctl(enum menu_displaylist_ctl_state type,
info->need_push = true;
info->need_refresh = true;
info->need_clear = true;
#endif
break;
case DISPLAYLIST_THUMBNAILS_UPDATER:
#ifdef HAVE_NETWORKING
@ -8806,6 +8833,13 @@ bool menu_displaylist_ctl(enum menu_displaylist_ctl_state type,
MENU_ENUM_LABEL_CORE_UPDATER_LIST,
MENU_SETTING_ACTION, 0, 0))
count++;
if (menu_entries_append_enum(info->list,
msg_hash_to_str(MENU_ENUM_LABEL_VALUE_UPDATE_INSTALLED_CORES),
msg_hash_to_str(MENU_ENUM_LABEL_UPDATE_INSTALLED_CORES),
MENU_ENUM_LABEL_UPDATE_INSTALLED_CORES,
MENU_SETTING_ACTION, 0, 0))
count++;
}
#endif
#endif

View File

@ -67,6 +67,7 @@
#include "../ui/ui_companion_driver.h"
#include "../verbosity.h"
#include "../tasks/task_powerstate.h"
#include "../core_updater_list.h"
#define SCROLL_INDEX_SIZE (2 * (26 + 2) + 1)
@ -3277,7 +3278,7 @@ static bool menu_init(menu_handle_t *menu_data)
task_push_decompress(settings->arrays.bundle_assets_src,
settings->arrays.bundle_assets_dst,
NULL, settings->arrays.bundle_assets_dst_subdir,
NULL, bundle_decompressed, NULL, NULL);
NULL, bundle_decompressed, NULL, NULL, false);
#endif
}
@ -3596,6 +3597,7 @@ bool menu_driver_ctl(enum rarch_menu_ctl_state state, void *data)
#if defined(HAVE_CG) || defined(HAVE_GLSL) || defined(HAVE_SLANG) || defined(HAVE_HLSL)
menu_shader_manager_free();
#endif
core_updater_list_free_cached();
if (menu_driver_data)
{

View File

@ -47,7 +47,7 @@ unsigned print_buf_lines(file_list_t *list, char *buf,
{
char c;
unsigned count = 0;
int i, j = 0;
int i = 0;
char *line_start = buf;
if (!buf || !buf_size)
@ -123,55 +123,6 @@ unsigned print_buf_lines(file_list_t *list, char *buf,
}
}
switch (type)
{
case FILE_TYPE_DOWNLOAD_CORE:
{
settings_t *settings = config_get_ptr();
if (settings)
{
char display_name[255];
char core_path[PATH_MAX_LENGTH];
char *last = NULL;
display_name[0] = core_path[0] = '\0';
fill_pathname_join_noext(
core_path,
settings->paths.path_libretro_info,
(extended && !string_is_empty(core_pathname))
? core_pathname : line_start,
sizeof(core_path));
path_remove_extension(core_path);
last = (char*)strrchr(core_path, '_');
if (!string_is_empty(last))
{
if (string_is_not_equal_fast(last, "_libretro", 9))
*last = '\0';
}
strlcat(core_path,
file_path_str(FILE_PATH_CORE_INFO_EXTENSION),
sizeof(core_path));
if (
path_is_valid(core_path)
&& core_info_get_display_name(
core_path, display_name, sizeof(display_name)))
file_list_set_alt_at_offset(list, j, display_name);
}
}
break;
default:
case FILE_TYPE_NONE:
break;
}
j++;
string_list_free(str_list);
/* Restore the saved char */

View File

@ -384,6 +384,7 @@ void menu_widgets_msg_queue_push(
if (task)
{
msg_widget->msg = strdup(title);
msg_widget->msg_new = strdup(title);
msg_widget->msg_len = (unsigned)strlen(title);
msg_widget->task_error = task->error;
@ -449,7 +450,7 @@ void menu_widgets_msg_queue_push(
msg_widget->expiration_timer_started = false;
}
if (task->title != msg_widget->task_title_ptr)
if (!string_is_equal(task->title, msg_widget->msg_new))
{
unsigned len = (unsigned)strlen(task->title);
unsigned new_width = font_driver_get_message_width(font_regular, task->title, len, msg_queue_text_scale_factor);
@ -609,6 +610,9 @@ static void menu_widgets_msg_queue_free(menu_widget_msg_t *msg, bool touch_list)
if (msg->msg)
free(msg->msg);
if (msg->msg_new)
free(msg->msg_new);
/* Remove it from the list */
if (touch_list)
{

View File

@ -1882,6 +1882,21 @@ enum msg_hash_enums
MENU_LABEL(DISC_INFORMATION),
MENU_LABEL(CORE_DELETE),
/* Core updater */
MENU_LABEL(UPDATE_INSTALLED_CORES),
MSG_FETCHING_CORE_LIST,
MSG_CORE_LIST_FAILED,
MSG_LATEST_CORE_INSTALLED,
MSG_UPDATING_CORE,
MSG_DOWNLOADING_CORE,
MSG_EXTRACTING_CORE,
MSG_CORE_INSTALLED,
MSG_SCANNING_CORES,
MSG_CHECKING_CORE,
MSG_ALL_CORES_UPDATED,
MENU_LABEL(VIDEO_SHADER_PARAMETERS),
MENU_LABEL(VIDEO_SHADER_PRESET_PARAMETERS),
MENU_LABEL(DISK_OPTIONS),

1199
tasks/task_core_updater.c Normal file

File diff suppressed because it is too large Load Diff

View File

@ -261,7 +261,7 @@ bool task_check_decompress(const char *source_file)
return task_queue_find(&find_data);
}
bool task_push_decompress(
void *task_push_decompress(
const char *source_file,
const char *target_dir,
const char *target_file,
@ -269,7 +269,8 @@ bool task_push_decompress(
const char *valid_ext,
retro_task_callback_t cb,
void *user_data,
void *frontend_userdata)
void *frontend_userdata,
bool mute)
{
char tmp[PATH_MAX_LENGTH];
const char *ext = NULL;
@ -283,7 +284,7 @@ bool task_push_decompress(
RARCH_WARN(
"[decompress] Empty or null source file or"
" target directory arguments.\n");
return false;
return NULL;
}
ext = path_get_extension(source_file);
@ -304,7 +305,7 @@ bool task_push_decompress(
"[decompress] File '%s' does not exist"
" or is not a compressed file.\n",
source_file);
return false;
return NULL;
}
if (!valid_ext || !valid_ext[0])
@ -315,7 +316,7 @@ bool task_push_decompress(
RARCH_LOG(
"[decompress] File '%s' already being decompressed.\n",
source_file);
return false;
return NULL;
}
RARCH_LOG("[decompress] File '%s.\n", source_file);
@ -323,14 +324,14 @@ bool task_push_decompress(
s = (decompress_state_t*)calloc(1, sizeof(*s));
if (!s)
return false;
return NULL;
t = (retro_task_t*)calloc(1, sizeof(*t));
if (!t)
{
free(s);
return false;
return NULL;
}
s->source_file = strdup(source_file);
@ -365,8 +366,9 @@ bool task_push_decompress(
path_basename(source_file));
t->title = strdup(tmp);
t->mute = mute;
task_queue_push(t);
return true;
return t;
}

View File

@ -74,6 +74,7 @@ typedef struct
{
enum msg_hash_enums enum_idx;
char path[PATH_MAX_LENGTH];
void *user_data;
} file_transfer_t;
RETRO_END_DECLS

View File

@ -28,6 +28,10 @@
#include "../config.h"
#endif
#if defined(HAVE_NETWORKING)
#include "../core_updater_list.h"
#endif
#if defined(HAVE_NETWORKING) && defined(HAVE_MENU)
/* Required for task_push_pl_entry_thumbnail_download() */
#include "../playlist.h"
@ -71,6 +75,13 @@ bool task_push_netplay_lan_scan_rooms(retro_task_callback_t cb);
bool task_push_netplay_nat_traversal(void *nat_traversal_state, uint16_t port);
/* Core updater tasks */
void *task_push_get_core_updater_list(
core_updater_list_t* core_list, bool mute, bool refresh_menu);
void *task_push_core_updater_download(
core_updater_list_t* core_list, const char *filename, bool mute, bool check_crc);
void task_push_update_installed_cores(void);
#ifdef HAVE_MENU
bool task_push_pl_thumbnail_download(const char *system, const char *playlist_path);
bool task_push_pl_entry_thumbnail_download(
@ -113,7 +124,7 @@ bool task_push_overlay_load_default(
bool task_check_decompress(const char *source_file);
bool task_push_decompress(
void *task_push_decompress(
const char *source_file,
const char *target_dir,
const char *target_file,
@ -121,7 +132,8 @@ bool task_push_decompress(
const char *valid_ext,
retro_task_callback_t cb,
void *user_data,
void *frontend_userdata);
void *frontend_userdata,
bool mute);
void task_file_load_handler(retro_task_t *task);

View File

@ -3023,6 +3023,7 @@ int MainWindow::onExtractArchive(QString path, QString extractionDir, QString te
const char *dir = dirArray.constData();
struct string_list *file_list = file_archive_get_file_list(file, NULL);
bool returnerr = true;
retro_task_t *decompress_task = NULL;
if (!file_list || file_list->size == 0)
{
@ -3079,9 +3080,12 @@ int MainWindow::onExtractArchive(QString path, QString extractionDir, QString te
m_updateProgressDialog->setCancelButtonText(QString());
m_updateProgressDialog->show();
if (!task_push_decompress(file, dir,
NULL, NULL, NULL,
cb, this, NULL))
decompress_task = (retro_task_t*)task_push_decompress(
file, dir,
NULL, NULL, NULL,
cb, this, NULL, false);
if (!decompress_task)
{
m_updateProgressDialog->cancel();
return -1;