mirror of
https://github.com/PCSX2/pcsx2.git
synced 2026-10-11 22:49:56 +00:00
3rdparty: Update rcheevos to v12.5.0
This commit is contained in:
Vendored
+7
@@ -1,3 +1,10 @@
|
||||
# v12.5.0
|
||||
* fallback to file hashing for buffered m3u/cue files
|
||||
* fix crash caused by {recall} of constant appearing in multiple alts
|
||||
* fix validation warning message when redundancy appears after AndNext/OrNext chain
|
||||
* fix handling of SubSource chain starting with a float constant
|
||||
* fix several potential issues with malformed data
|
||||
|
||||
# v12.4.0
|
||||
* add avatar_last_updated field to rc_client_user_t and rc_api_login_response_t
|
||||
* add more fields to fetch_games_list API
|
||||
|
||||
+1
@@ -94,6 +94,7 @@ enum {
|
||||
RC_CONSOLE_TI83 = 79,
|
||||
RC_CONSOLE_UZEBOX = 80,
|
||||
RC_CONSOLE_FAMICOM_DISK_SYSTEM = 81,
|
||||
RC_CONSOLE_PLAYSTATION_3 = 82,
|
||||
|
||||
RC_CONSOLE_HUBS = 100,
|
||||
RC_CONSOLE_EVENTS = 101,
|
||||
|
||||
+128
-14
@@ -710,10 +710,15 @@ int rc_json_get_string(const char** out, rc_buffer_t* buffer, const rc_json_fiel
|
||||
}
|
||||
|
||||
*out = dst = (char*)rc_buffer_reserve(buffer, len - 1); /* -2 for quotes, +1 for null terminator */
|
||||
if (!dst)
|
||||
return 0;
|
||||
|
||||
do {
|
||||
while (src < field->value_end && *src != '\"') {
|
||||
if (*src == '\\') {
|
||||
++src;
|
||||
if (src >= field->value_end)
|
||||
return 0;
|
||||
|
||||
if (*src == 'n') {
|
||||
/* newline */
|
||||
++src;
|
||||
@@ -731,7 +736,7 @@ int rc_json_get_string(const char** out, rc_buffer_t* buffer, const rc_json_fiel
|
||||
if (*src == 'u') {
|
||||
/* unicode character */
|
||||
uint32_t ucs32_char;
|
||||
if (src + 5 >= field->value_end) /* incomplete unicode character */
|
||||
if ((size_t)(field->value_end - src) < 6) /* incomplete unicode character */
|
||||
return 0;
|
||||
|
||||
ucs32_char = rc_json_decode_hex4(src + 1);
|
||||
@@ -739,7 +744,7 @@ int rc_json_get_string(const char** out, rc_buffer_t* buffer, const rc_json_fiel
|
||||
|
||||
if (ucs32_char >= 0xD800 && ucs32_char < 0xE000) {
|
||||
/* surrogate lead - look for surrogate tail */
|
||||
if (ucs32_char < 0xDC00 && src[0] == '\\' && src[1] == 'u') {
|
||||
if (ucs32_char < 0xDC00 && (size_t)(field->value_end - src) >= 6 && src[0] == '\\' && src[1] == 'u') {
|
||||
const uint32_t surrogate = rc_json_decode_hex4(src + 2);
|
||||
src += 6;
|
||||
|
||||
@@ -770,10 +775,16 @@ int rc_json_get_string(const char** out, rc_buffer_t* buffer, const rc_json_fiel
|
||||
}
|
||||
|
||||
*dst++ = *src++;
|
||||
} while (*src != '\"');
|
||||
}
|
||||
|
||||
if (src >= field->value_end)
|
||||
return 0;
|
||||
|
||||
} else {
|
||||
*out = dst = (char*)rc_buffer_reserve(buffer, len + 1); /* +1 for null terminator */
|
||||
if (!dst)
|
||||
return 0;
|
||||
|
||||
memcpy(dst, src, len);
|
||||
dst += len;
|
||||
}
|
||||
@@ -990,6 +1001,116 @@ int rc_json_get_required_float(float* out, rc_api_response_t* response, const rc
|
||||
return rc_json_missing_field(response, field);
|
||||
}
|
||||
|
||||
/* Parses exactly count decimal digits without reading beyond end. */
|
||||
static int rc_json_parse_datetime_digits(const char** input, const char* end, int count, int* value) {
|
||||
int result = 0;
|
||||
|
||||
while (count > 0) {
|
||||
if (*input >= end || **input < '0' || **input > '9')
|
||||
return 0;
|
||||
|
||||
result *= 10;
|
||||
result += (**input - '0');
|
||||
(*input)++;
|
||||
count--;
|
||||
}
|
||||
|
||||
*value = result;
|
||||
return 1;
|
||||
}
|
||||
|
||||
/* Consumes an expected separator without reading beyond end. */
|
||||
static int rc_json_match_datetime_char(const char** input, const char* end, char expected) {
|
||||
if (*input >= end || **input != expected)
|
||||
return 0;
|
||||
|
||||
(*input)++;
|
||||
return 1;
|
||||
}
|
||||
|
||||
/* Valid suffixes are Z, fractional seconds, and numeric timezone offsets. */
|
||||
static int rc_json_validate_datetime_suffix(const char* input, const char* end) {
|
||||
int offset_hour;
|
||||
int offset_minute;
|
||||
|
||||
if (input == end)
|
||||
return 1;
|
||||
|
||||
if (*input == '.') {
|
||||
input++;
|
||||
if (input == end || *input < '0' || *input > '9')
|
||||
return 0;
|
||||
|
||||
do {
|
||||
input++;
|
||||
} while (input < end && *input >= '0' && *input <= '9');
|
||||
|
||||
if (input == end)
|
||||
return 1;
|
||||
}
|
||||
|
||||
if (*input == 'Z')
|
||||
return (++input == end);
|
||||
|
||||
if (*input != '+' && *input != '-')
|
||||
return 0;
|
||||
|
||||
++input;
|
||||
if (!rc_json_parse_datetime_digits(&input, end, 2, &offset_hour) ||
|
||||
!rc_json_match_datetime_char(&input, end, ':') ||
|
||||
!rc_json_parse_datetime_digits(&input, end, 2, &offset_minute) ||
|
||||
input != end) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
return (offset_hour <= 23 && offset_minute <= 59);
|
||||
}
|
||||
|
||||
/* Parses YYYY-MM-DD[ T]HH:MM:SS and only updates tm after the complete
|
||||
* bounded value, including any suffix, has been validated. */
|
||||
static int rc_json_parse_datetime(const char* input, const char* end, struct tm* tm) {
|
||||
static const unsigned char days_per_month[] = { 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 };
|
||||
int year, month, day, hour, minute, second;
|
||||
int days_in_month;
|
||||
|
||||
if (!rc_json_parse_datetime_digits(&input, end, 4, &year) ||
|
||||
!rc_json_match_datetime_char(&input, end, '-') ||
|
||||
!rc_json_parse_datetime_digits(&input, end, 2, &month) ||
|
||||
!rc_json_match_datetime_char(&input, end, '-') ||
|
||||
!rc_json_parse_datetime_digits(&input, end, 2, &day) ||
|
||||
input >= end || (*input != ' ' && *input != 'T')) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
input++;
|
||||
if (!rc_json_parse_datetime_digits(&input, end, 2, &hour) ||
|
||||
!rc_json_match_datetime_char(&input, end, ':') ||
|
||||
!rc_json_parse_datetime_digits(&input, end, 2, &minute) ||
|
||||
!rc_json_match_datetime_char(&input, end, ':') ||
|
||||
!rc_json_parse_datetime_digits(&input, end, 2, &second) ||
|
||||
!rc_json_validate_datetime_suffix(input, end)) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (month < 1 || month > 12 || hour > 23 || minute > 59 || second > 59)
|
||||
return 0;
|
||||
|
||||
days_in_month = days_per_month[month - 1];
|
||||
if (month == 2 && (year % 4 == 0) && (year % 100 != 0 || year % 400 == 0))
|
||||
days_in_month++;
|
||||
if (day < 1 || day > days_in_month)
|
||||
return 0;
|
||||
|
||||
memset(tm, 0, sizeof(*tm));
|
||||
tm->tm_year = year - 1900;
|
||||
tm->tm_mon = month - 1;
|
||||
tm->tm_mday = day;
|
||||
tm->tm_hour = hour;
|
||||
tm->tm_min = minute;
|
||||
tm->tm_sec = second;
|
||||
return 1;
|
||||
}
|
||||
|
||||
int rc_json_get_datetime(time_t* out, const rc_json_field_t* field, const char* field_name) {
|
||||
struct tm tm;
|
||||
|
||||
@@ -1000,15 +1121,9 @@ int rc_json_get_datetime(time_t* out, const rc_json_field_t* field, const char*
|
||||
(void)field_name;
|
||||
#endif
|
||||
|
||||
if (field->value_start && *field->value_start == '\"') {
|
||||
memset(&tm, 0, sizeof(tm));
|
||||
if (sscanf_s(field->value_start + 1, "%d-%d-%d %d:%d:%d", /* DB format "2013-10-20 22:12:21" */
|
||||
&tm.tm_year, &tm.tm_mon, &tm.tm_mday, &tm.tm_hour, &tm.tm_min, &tm.tm_sec) == 6 ||
|
||||
/* NOTE: relies on sscanf stopping when it sees a non-digit after the seconds. could be 'Z', '.', '+', or '-' */
|
||||
sscanf_s(field->value_start + 1, "%d-%d-%dT%d:%d:%d", /* ISO format "2013-10-20T22:12:21.000000Z */
|
||||
&tm.tm_year, &tm.tm_mon, &tm.tm_mday, &tm.tm_hour, &tm.tm_min, &tm.tm_sec) == 6) {
|
||||
tm.tm_mon--; /* 0-based */
|
||||
tm.tm_year -= 1900; /* 1900 based */
|
||||
if (field->value_start && field->value_end > field->value_start &&
|
||||
*field->value_start == '\"' && field->value_end[-1] == '\"' &&
|
||||
rc_json_parse_datetime(field->value_start + 1, field->value_end - 1, &tm)) {
|
||||
|
||||
/* mktime converts a struct tm to a time_t using the local timezone.
|
||||
* the input string is UTC. since timegm is not universally cross-platform,
|
||||
@@ -1026,7 +1141,6 @@ int rc_json_get_datetime(time_t* out, const rc_json_field_t* field, const char*
|
||||
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
|
||||
*out = 0;
|
||||
return 0;
|
||||
|
||||
+7
-5
@@ -140,7 +140,7 @@ static int rc_api_process_fetch_game_data_achievements(rc_api_response_t* respon
|
||||
while (rc_json_get_array_entry_object(achievement_fields, sizeof(achievement_fields) / sizeof(achievement_fields[0]), &iterator)) {
|
||||
if (!rc_json_get_required_unum(&achievement->id, response, &achievement_fields[0], "ID"))
|
||||
return RC_MISSING_VALUE;
|
||||
if (!rc_json_get_required_string(&achievement->title, response, &achievement_fields[1], "Title"))
|
||||
if (!rc_json_get_required_string(&achievement->title, response, &achievement_fields[1], "Title") || !achievement->title)
|
||||
return RC_MISSING_VALUE;
|
||||
if (!rc_json_get_required_string(&achievement->description, response, &achievement_fields[2], "Description"))
|
||||
return RC_MISSING_VALUE;
|
||||
@@ -197,16 +197,18 @@ static int rc_api_process_fetch_game_data_achievements(rc_api_response_t* respon
|
||||
achievement->type = RC_ACHIEVEMENT_TYPE_STANDARD;
|
||||
|
||||
/* legacy support : if title contains[m], change type to missable and remove[m] from title */
|
||||
if (memcmp(achievement->title, "[m]", 3) == 0) {
|
||||
/* since we're comparing a suffix, calculate the length in case it contains null bytes */
|
||||
len = strlen(achievement->title);
|
||||
if (len >= 3 && memcmp(achievement->title, "[m]", 3) == 0) {
|
||||
len = 3;
|
||||
while (achievement->title[len] == ' ')
|
||||
++len;
|
||||
achievement->title += len;
|
||||
achievement->type = RC_ACHIEVEMENT_TYPE_MISSABLE;
|
||||
}
|
||||
else if (achievement_fields[1].value_end && memcmp(achievement_fields[1].value_end - 4, "[m]", 3) == 0) {
|
||||
len = strlen(achievement->title) - 3;
|
||||
while (achievement->title[len - 1] == ' ')
|
||||
else if (len >= 3 && memcmp(achievement->title + len - 3, "[m]", 3) == 0) {
|
||||
len -= 3;
|
||||
while (len > 0 && achievement->title[len - 1] == ' ')
|
||||
--len;
|
||||
((char*)achievement->title)[len] = '\0';
|
||||
achievement->type = RC_ACHIEVEMENT_TYPE_MISSABLE;
|
||||
|
||||
+1
-1
@@ -455,7 +455,7 @@ int rc_api_process_fetch_all_user_progress_server_response(rc_api_fetch_all_user
|
||||
entry = response->entries;
|
||||
while (rc_json_get_next_object_field(&iterator, &field))
|
||||
{
|
||||
entry->game_id = strtol(field.name, &end, 10);
|
||||
entry->game_id = (uint32_t)strtol(field.name, &end, 10);
|
||||
|
||||
field.name = "";
|
||||
if (!rc_json_get_required_object(entry_fields, sizeof(entry_fields) / sizeof(entry_fields[0]),
|
||||
|
||||
Vendored
+2
-2
@@ -318,8 +318,6 @@ void rc_client_enable_logging(rc_client_t* client, int level, rc_client_message_
|
||||
|
||||
/* ===== Common ===== */
|
||||
|
||||
static rc_clock_t rc_client_clock_get_now_millisecs(const rc_client_t* client)
|
||||
{
|
||||
#if defined(__APPLE__) && defined(__MACH__)
|
||||
#ifdef CLOCK_MONOTONIC
|
||||
/* clock_gettime() was added to Darwin in iOS 10.0 and macOS 10.12.
|
||||
@@ -336,6 +334,8 @@ static rc_clock_t rc_client_clock_get_now_millisecs(const rc_client_t* client)
|
||||
#endif
|
||||
#endif
|
||||
|
||||
static rc_clock_t rc_client_clock_get_now_millisecs(const rc_client_t* client)
|
||||
{
|
||||
#if defined(CLOCK_MONOTONIC)
|
||||
struct timespec now;
|
||||
(void)client;
|
||||
|
||||
Vendored
+2
-2
@@ -1,4 +1,4 @@
|
||||
#if !defined(RC_NO_THREADS) && !defined(_WIN32) && !defined(GEKKO) && !defined(_3DS) && (!defined(_XOPEN_SOURCE) || (_XOPEN_SOURCE - 0) < 500)
|
||||
#if !defined(RC_NO_THREADS) && !defined(_WIN32) && !defined(GEKKO) && !defined(__3DS__) && !defined(_3DS) && (!defined(_XOPEN_SOURCE) || (_XOPEN_SOURCE - 0) < 500)
|
||||
/* We'll want to use pthread_mutexattr_settype/PTHREAD_MUTEX_RECURSIVE, but glibc only conditionally exposes pthread_mutexattr_settype and PTHREAD_MUTEX_RECURSIVE depending on feature flags
|
||||
* Defining _XOPEN_SOURCE must be done at the top of the source file, before including any headers
|
||||
* pthread_mutexattr_settype/PTHREAD_MUTEX_RECURSIVE are specified the Single UNIX Specification (Version 2, 1997), along with POSIX later on (IEEE Standard 1003.1-2008), so should cover practically any pthread implementation
|
||||
@@ -197,7 +197,7 @@ void rc_mutex_unlock(rc_mutex_t* mutex)
|
||||
LWP_MutexUnlock(mutex->handle);
|
||||
}
|
||||
|
||||
#elif defined(_3DS)
|
||||
#elif defined(__3DS__) || defined(_3DS)
|
||||
|
||||
void rc_mutex_init(rc_mutex_t* mutex)
|
||||
{
|
||||
|
||||
Vendored
+1
-1
@@ -102,7 +102,7 @@ RC_BEGIN_C_DECLS
|
||||
typedef struct rc_mutex_t {
|
||||
mutex_t handle;
|
||||
} rc_mutex_t;
|
||||
#elif defined(_3DS)
|
||||
#elif defined(__3DS__) || defined(_3DS)
|
||||
#include <3ds/synchronization.h>
|
||||
typedef RecursiveLock rc_mutex_t;
|
||||
#else
|
||||
|
||||
Vendored
+44
-37
@@ -25,6 +25,7 @@ typedef struct rc_disallowed_core_settings_t
|
||||
{
|
||||
const char* library_name;
|
||||
const rc_disallowed_setting_t* disallowed_settings;
|
||||
uint32_t system_id;
|
||||
} rc_disallowed_core_settings_t;
|
||||
|
||||
|
||||
@@ -100,6 +101,11 @@ static const rc_disallowed_setting_t _rc_disallowed_gpgx_wide_settings[] = {
|
||||
{ NULL, NULL }
|
||||
};
|
||||
|
||||
static const rc_disallowed_setting_t _rc_disallowed_melonds_ds_settings[] = {
|
||||
{ "melonds_console_mode", "dsi" },
|
||||
{ NULL, NULL }
|
||||
};
|
||||
|
||||
static const rc_disallowed_setting_t _rc_disallowed_mesen_settings[] = {
|
||||
{ "mesen_region", ",PAL,Dendy" },
|
||||
{ NULL, NULL }
|
||||
@@ -166,32 +172,33 @@ static const rc_disallowed_setting_t _rc_disallowed_virtual_jaguar_settings[] =
|
||||
};
|
||||
|
||||
static const rc_disallowed_core_settings_t rc_disallowed_core_settings[] = {
|
||||
{ "Beetle PSX", _rc_disallowed_beetle_psx_settings },
|
||||
{ "Beetle PSX HW", _rc_disallowed_beetle_psx_hw_settings },
|
||||
{ "bsnes-mercury", _rc_disallowed_bsnes_settings },
|
||||
{ "cap32", _rc_disallowed_cap32_settings },
|
||||
{ "dolphin-emu", _rc_disallowed_dolphin_settings },
|
||||
{ "DOSBox-pure", _rc_disallowed_dosbox_pure_settings },
|
||||
{ "DuckStation", _rc_disallowed_duckstation_settings },
|
||||
{ "ecwolf", _rc_disallowed_ecwolf_settings },
|
||||
{ "FCEUmm", _rc_disallowed_fceumm_settings },
|
||||
{ "FinalBurn Neo", _rc_disallowed_fbneo_settings },
|
||||
{ "Flycast", _rc_disallowed_flycast_settings },
|
||||
{ "Genesis Plus GX", _rc_disallowed_gpgx_settings },
|
||||
{ "Genesis Plus GX Wide", _rc_disallowed_gpgx_wide_settings },
|
||||
{ "Mesen", _rc_disallowed_mesen_settings },
|
||||
{ "Mesen-S", _rc_disallowed_mesen_s_settings },
|
||||
{ "NeoCD", _rc_disallowed_neocd_settings },
|
||||
{ "PPSSPP", _rc_disallowed_ppsspp_settings },
|
||||
{ "PCSX-ReARMed", _rc_disallowed_pcsx_rearmed_settings },
|
||||
{ "PicoDrive", _rc_disallowed_picodrive_settings },
|
||||
{ "QUASI88", _rc_disallowed_quasi88_settings },
|
||||
{ "SMS Plus GX", _rc_disallowed_smsplus_settings },
|
||||
{ "Snes9x", _rc_disallowed_snes9x_settings },
|
||||
{ "SwanStation", _rc_disallowed_swanstation_settings },
|
||||
{ "VICE x64", _rc_disallowed_vice_settings },
|
||||
{ "Virtual Jaguar", _rc_disallowed_virtual_jaguar_settings },
|
||||
{ NULL, NULL }
|
||||
{ "Beetle PSX", _rc_disallowed_beetle_psx_settings, 0 },
|
||||
{ "Beetle PSX HW", _rc_disallowed_beetle_psx_hw_settings, 0 },
|
||||
{ "bsnes-mercury", _rc_disallowed_bsnes_settings, 0 },
|
||||
{ "cap32", _rc_disallowed_cap32_settings, 0 },
|
||||
{ "dolphin-emu", _rc_disallowed_dolphin_settings, 0 },
|
||||
{ "DOSBox-pure", _rc_disallowed_dosbox_pure_settings, 0 },
|
||||
{ "DuckStation", _rc_disallowed_duckstation_settings, 0 },
|
||||
{ "ecwolf", _rc_disallowed_ecwolf_settings, 0 },
|
||||
{ "FCEUmm", _rc_disallowed_fceumm_settings, 0 },
|
||||
{ "FinalBurn Neo", _rc_disallowed_fbneo_settings, 0 },
|
||||
{ "Flycast", _rc_disallowed_flycast_settings, 0 },
|
||||
{ "Genesis Plus GX", _rc_disallowed_gpgx_settings, 0 },
|
||||
{ "Genesis Plus GX Wide", _rc_disallowed_gpgx_wide_settings, 0 },
|
||||
{ "melonDS", _rc_disallowed_melonds_ds_settings, RC_CONSOLE_NINTENDO_DS },
|
||||
{ "Mesen", _rc_disallowed_mesen_settings, 0 },
|
||||
{ "Mesen-S", _rc_disallowed_mesen_s_settings, 0 },
|
||||
{ "NeoCD", _rc_disallowed_neocd_settings, 0 },
|
||||
{ "PPSSPP", _rc_disallowed_ppsspp_settings, 0 },
|
||||
{ "PCSX-ReARMed", _rc_disallowed_pcsx_rearmed_settings, 0 },
|
||||
{ "PicoDrive", _rc_disallowed_picodrive_settings, 0 },
|
||||
{ "QUASI88", _rc_disallowed_quasi88_settings, 0 },
|
||||
{ "SMS Plus GX", _rc_disallowed_smsplus_settings, 0 },
|
||||
{ "Snes9x", _rc_disallowed_snes9x_settings, 0 },
|
||||
{ "SwanStation", _rc_disallowed_swanstation_settings, 0 },
|
||||
{ "VICE x64", _rc_disallowed_vice_settings, 0 },
|
||||
{ "Virtual Jaguar", _rc_disallowed_virtual_jaguar_settings, 0 },
|
||||
{ NULL, NULL, 0 }
|
||||
};
|
||||
|
||||
static int rc_libretro_string_equal_nocase_wildcard(const char* test, const char* match) {
|
||||
@@ -230,7 +237,7 @@ static int rc_libretro_match_token(const char* val, const char* token, size_t si
|
||||
}
|
||||
}
|
||||
|
||||
if (memcmp(token, val, size) == 0 && val[size] == 0) {
|
||||
if (strncmp(token, val, size) == 0 && val[size] == '\0') {
|
||||
/* exact match, match with result = true */
|
||||
*result = 1;
|
||||
return 1;
|
||||
@@ -292,13 +299,13 @@ int rc_libretro_is_setting_allowed(const rc_disallowed_setting_t* disallowed_set
|
||||
key_len = strlen(key);
|
||||
|
||||
if (key[key_len - 1] == '*') {
|
||||
if (memcmp(setting, key, key_len - 1) == 0) {
|
||||
if (strncmp(setting, key, key_len - 1) == 0) {
|
||||
if (rc_libretro_match_value(value, disallowed_settings->value))
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
else {
|
||||
if (memcmp(setting, key, key_len + 1) == 0) {
|
||||
if (strcmp(setting, key) == 0) {
|
||||
if (rc_libretro_match_value(value, disallowed_settings->value))
|
||||
return 0;
|
||||
}
|
||||
@@ -308,16 +315,14 @@ int rc_libretro_is_setting_allowed(const rc_disallowed_setting_t* disallowed_set
|
||||
return 1;
|
||||
}
|
||||
|
||||
const rc_disallowed_setting_t* rc_libretro_get_disallowed_settings(const char* library_name) {
|
||||
const rc_disallowed_setting_t* rc_libretro_get_disallowed_settings_for_system(const char* library_name, uint32_t system_id) {
|
||||
const rc_disallowed_core_settings_t* core_filter = rc_disallowed_core_settings;
|
||||
size_t library_name_length;
|
||||
|
||||
if (!library_name || !library_name[0])
|
||||
return NULL;
|
||||
|
||||
library_name_length = strlen(library_name) + 1;
|
||||
while (core_filter->library_name) {
|
||||
if (memcmp(core_filter->library_name, library_name, library_name_length) == 0)
|
||||
if (core_filter->system_id == system_id && strcmp(core_filter->library_name, library_name) == 0)
|
||||
return core_filter->disallowed_settings;
|
||||
|
||||
++core_filter;
|
||||
@@ -326,6 +331,10 @@ const rc_disallowed_setting_t* rc_libretro_get_disallowed_settings(const char* l
|
||||
return NULL;
|
||||
}
|
||||
|
||||
const rc_disallowed_setting_t* rc_libretro_get_disallowed_settings(const char* library_name) {
|
||||
return rc_libretro_get_disallowed_settings_for_system(library_name, 0);
|
||||
}
|
||||
|
||||
typedef struct rc_disallowed_core_systems_t
|
||||
{
|
||||
const char* library_name;
|
||||
@@ -340,15 +349,13 @@ static const rc_disallowed_core_systems_t rc_disallowed_core_systems[] = {
|
||||
|
||||
int rc_libretro_is_system_allowed(const char* library_name, uint32_t console_id) {
|
||||
const rc_disallowed_core_systems_t* core_filter = rc_disallowed_core_systems;
|
||||
size_t library_name_length;
|
||||
size_t i;
|
||||
|
||||
if (!library_name || !library_name[0])
|
||||
return 1;
|
||||
|
||||
library_name_length = strlen(library_name) + 1;
|
||||
while (core_filter->library_name) {
|
||||
if (memcmp(core_filter->library_name, library_name, library_name_length) == 0) {
|
||||
if (strcmp(core_filter->library_name, library_name) == 0) {
|
||||
for (i = 0; i < sizeof(core_filter->disallowed_consoles) / sizeof(core_filter->disallowed_consoles[0]); ++i) {
|
||||
if (core_filter->disallowed_consoles[i] == console_id)
|
||||
return 0;
|
||||
@@ -600,7 +607,7 @@ static void rc_libretro_memory_init_from_memory_map(rc_libretro_memory_regions_t
|
||||
/* if we need to extract a disconnect bit, the largest block we can read is up to
|
||||
* the next time that bit flips */
|
||||
/* https://stackoverflow.com/questions/12247186/find-the-lowest-set-bit */
|
||||
disconnect_size = (desc->disconnect & -((int)desc->disconnect));
|
||||
disconnect_size = (uint32_t)(desc->disconnect & -((int)desc->disconnect));
|
||||
desc_size = disconnect_size - (real_address & (disconnect_size - 1));
|
||||
}
|
||||
|
||||
|
||||
Vendored
+2
-1
@@ -25,8 +25,9 @@ typedef struct rc_disallowed_setting_t
|
||||
} rc_disallowed_setting_t;
|
||||
|
||||
RC_EXPORT const rc_disallowed_setting_t* RC_CCONV rc_libretro_get_disallowed_settings(const char* library_name);
|
||||
RC_EXPORT const rc_disallowed_setting_t* RC_CCONV rc_libretro_get_disallowed_settings_for_system(const char* library_name, uint32_t system_id);
|
||||
RC_EXPORT int RC_CCONV rc_libretro_is_setting_allowed(const rc_disallowed_setting_t* disallowed_settings, const char* setting, const char* value);
|
||||
RC_EXPORT int RC_CCONV rc_libretro_is_system_allowed(const char* library_name, uint32_t console_id);
|
||||
RC_EXPORT int RC_CCONV rc_libretro_is_system_allowed(const char* library_name, uint32_t system_id);
|
||||
|
||||
/*****************************************************************************\
|
||||
| Memory Mapping |
|
||||
|
||||
Vendored
+11
@@ -56,6 +56,11 @@ uint8_t* rc_buffer_reserve(rc_buffer_t* buffer, size_t amount)
|
||||
{
|
||||
rc_buffer_chunk_t* chunk = &buffer->chunk;
|
||||
size_t remaining;
|
||||
|
||||
/* we should never need 1GB of space for anything, and avoids any underflow below */
|
||||
if (amount >= 0x40000000)
|
||||
return NULL;
|
||||
|
||||
while (chunk)
|
||||
{
|
||||
remaining = chunk->end - chunk->write;
|
||||
@@ -112,6 +117,9 @@ void rc_buffer_consume(rc_buffer_t* buffer, const uint8_t* start, uint8_t* end)
|
||||
void* rc_buffer_alloc(rc_buffer_t* buffer, size_t amount)
|
||||
{
|
||||
uint8_t* ptr = rc_buffer_reserve(buffer, amount);
|
||||
if (!ptr)
|
||||
return NULL;
|
||||
|
||||
rc_buffer_consume(buffer, ptr, ptr + amount);
|
||||
return (void*)ptr;
|
||||
}
|
||||
@@ -119,6 +127,9 @@ void* rc_buffer_alloc(rc_buffer_t* buffer, size_t amount)
|
||||
char* rc_buffer_strncpy(rc_buffer_t* buffer, const char* src, size_t len)
|
||||
{
|
||||
uint8_t* dst = rc_buffer_reserve(buffer, len + 1);
|
||||
if (!dst)
|
||||
return NULL;
|
||||
|
||||
memcpy(dst, src, len);
|
||||
dst[len] = '\0';
|
||||
rc_buffer_consume(buffer, dst, dst + len + 1);
|
||||
|
||||
Vendored
+1
-1
@@ -8,7 +8,7 @@
|
||||
RC_BEGIN_C_DECLS
|
||||
|
||||
#define RCHEEVOS_VERSION_MAJOR 12
|
||||
#define RCHEEVOS_VERSION_MINOR 4
|
||||
#define RCHEEVOS_VERSION_MINOR 5
|
||||
#define RCHEEVOS_VERSION_PATCH 0
|
||||
|
||||
#define RCHEEVOS_MAKE_VERSION(major, minor, patch) (major * 1000000 + minor * 1000 + patch)
|
||||
|
||||
+11
-1
@@ -412,9 +412,19 @@ void rc_condition_update_parse_state(rc_condition_t* condition, rc_parse_state_t
|
||||
parse->addsource_parent.value.memref = (rc_memref_t*)negate;
|
||||
parse->addsource_parent.size = zero.size;
|
||||
|
||||
if (parse->addsource_parent.type == RC_OPERAND_CONST)
|
||||
if (parse->addsource_parent.type == RC_OPERAND_CONST) {
|
||||
parse->addsource_parent.value.num = rc_get_modified_memref_value(negate, NULL, NULL);
|
||||
}
|
||||
else if (parse->addsource_parent.type == RC_OPERAND_FP) {
|
||||
rc_typed_value_t typed_value;
|
||||
typed_value.value.u32 = rc_get_modified_memref_value(negate, NULL, NULL);
|
||||
parse->addsource_parent.value.dbl = (double)typed_value.value.f32;
|
||||
}
|
||||
else {
|
||||
/* not actually an address, just a non-delta memref read */
|
||||
parse->addsource_parent.type = parse->addsource_parent.memref_access_type = RC_OPERAND_ADDRESS;
|
||||
}
|
||||
}
|
||||
|
||||
/* subtract the condition from the chain */
|
||||
parse->addsource_oper = RC_OPERATOR_SUB_ACCUMULATOR;
|
||||
|
||||
+2
-1
@@ -363,7 +363,8 @@ rc_condset_t* rc_parse_condset(const char** memaddr, rc_parse_state_t* parse) {
|
||||
|
||||
classification = combining_classification;
|
||||
}
|
||||
else {
|
||||
else if (classification != RC_CONDITION_CLASSIFICATION_INDIRECT) {
|
||||
/* if it's not COMBINING or INDIRECT, reset so it will get recalculated for the next clause */
|
||||
combining_classification = RC_CONDITION_CLASSIFICATION_COMBINING;
|
||||
}
|
||||
|
||||
|
||||
+19
@@ -174,6 +174,9 @@ const char* rc_console_name(uint32_t console_id)
|
||||
case RC_CONSOLE_PLAYSTATION_2:
|
||||
return "PlayStation 2";
|
||||
|
||||
case RC_CONSOLE_PLAYSTATION_3:
|
||||
return "PlayStation 3";
|
||||
|
||||
case RC_CONSOLE_PSP:
|
||||
return "PlayStation Portable";
|
||||
|
||||
@@ -827,6 +830,19 @@ static const rc_memory_region_t _rc_memory_regions_psp[] = {
|
||||
};
|
||||
static const rc_memory_regions_t rc_memory_regions_psp = { _rc_memory_regions_psp, 3 };
|
||||
|
||||
/* ===== PlayStation 3 ===== */
|
||||
/* Address layout from RPCS3 vm.cpp _find_map allocation order: */
|
||||
/* sys_rsx_context_allocate allocates rsx_context first at 0x10000000 (256 MB). */
|
||||
/* sys_memory_allocate (64K) allocates user64k at 0x20000000 (512 MB). */
|
||||
/* sys_memory_allocate (1M) allocates user1m at 0x40000000 (256 MB). */
|
||||
static const rc_memory_region_t _rc_memory_regions_playstation3[] = {
|
||||
{ 0x00000000U, 0x0FFFFFFFU, 0x00000000U, RC_MEMORY_TYPE_SYSTEM_RAM, "Main RAM" },
|
||||
{ 0x10000000U, 0x2FFFFFFFU, 0x10000000U, RC_MEMORY_TYPE_SYSTEM_RAM, "RSX Context + User RAM (64K pages)" },
|
||||
{ 0x30000000U, 0x3FFFFFFFU, 0x30000000U, RC_MEMORY_TYPE_SYSTEM_RAM, "User RAM (64K pages)" },
|
||||
{ 0x40000000U, 0x4FFFFFFFU, 0x40000000U, RC_MEMORY_TYPE_SYSTEM_RAM, "User RAM (1M pages)" },
|
||||
};
|
||||
static const rc_memory_regions_t rc_memory_regions_playstation3 = { _rc_memory_regions_playstation3, 4 };
|
||||
|
||||
/* ===== Pokemon Mini ===== */
|
||||
/* https://www.pokemon-mini.net/documentation/memory-map/ */
|
||||
static const rc_memory_region_t _rc_memory_regions_pokemini[] = {
|
||||
@@ -1167,6 +1183,9 @@ const rc_memory_regions_t* rc_console_memory_regions(uint32_t console_id)
|
||||
case RC_CONSOLE_PSP:
|
||||
return &rc_memory_regions_psp;
|
||||
|
||||
case RC_CONSOLE_PLAYSTATION_3:
|
||||
return &rc_memory_regions_playstation3;
|
||||
|
||||
case RC_CONSOLE_POKEMON_MINI:
|
||||
return &rc_memory_regions_pokemini;
|
||||
|
||||
|
||||
+20
-4
@@ -319,13 +319,30 @@ int rc_operands_are_equal(const rc_operand_t* left, const rc_operand_t* right) {
|
||||
case RC_OPERAND_FP:
|
||||
return (left->value.dbl == right->value.dbl);
|
||||
case RC_OPERAND_RECALL:
|
||||
return (left->value.memref == right->value.memref);
|
||||
if (left->memref_access_type != right->memref_access_type)
|
||||
return 0;
|
||||
switch (left->memref_access_type) {
|
||||
case RC_OPERAND_CONST:
|
||||
return (left->value.num == right->value.num);
|
||||
case RC_OPERAND_FP:
|
||||
return (left->value.dbl == right->value.dbl);
|
||||
default:
|
||||
if (!left->value.memref || !right->value.memref) /* could not find remember */
|
||||
return 0;
|
||||
break; /* fallthrough to memref comparison */
|
||||
}
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
/* comparing two memrefs - look for exact matches on type and size */
|
||||
if (left->size != right->size || left->value.memref->value.memref_type != right->value.memref->value.memref_type)
|
||||
if (left->size != right->size)
|
||||
return 0;
|
||||
|
||||
if (left->value.memref == right->value.memref) /* quick match if pointing to same memref */
|
||||
return 1;
|
||||
|
||||
if (left->value.memref->value.memref_type != right->value.memref->value.memref_type)
|
||||
return 0;
|
||||
|
||||
switch (left->value.memref->value.memref_type) {
|
||||
@@ -336,8 +353,7 @@ int rc_operands_are_equal(const rc_operand_t* left, const rc_operand_t* right) {
|
||||
return (left_memref->modifier_type == right_memref->modifier_type &&
|
||||
left_memref->depth == right_memref->depth &&
|
||||
rc_operands_are_equal(&left_memref->modifier, &right_memref->modifier) &&
|
||||
rc_operands_are_equal(&left_memref->parent, &right_memref->parent) &&
|
||||
1 == 1
|
||||
rc_operands_are_equal(&left_memref->parent, &right_memref->parent)
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
+4
-4
@@ -127,7 +127,7 @@ RC_ALLOW_ALIGN(char)
|
||||
/* force alignment to 4 bytes on 32-bit systems, or 8 bytes on 64-bit systems */
|
||||
#define RC_ALIGN(n) (((n) + (sizeof(void*)-1)) & ~(sizeof(void*)-1))
|
||||
|
||||
typedef struct {
|
||||
typedef struct rc_scratch_t {
|
||||
rc_buffer_t buffer;
|
||||
rc_scratch_string_t* strings;
|
||||
|
||||
@@ -188,7 +188,7 @@ enum {
|
||||
RC_VALUE_TYPE_FLOAT
|
||||
};
|
||||
|
||||
typedef struct {
|
||||
typedef struct rc_typed_value_t {
|
||||
union {
|
||||
uint32_t u32;
|
||||
int32_t i32;
|
||||
@@ -208,7 +208,7 @@ enum {
|
||||
#define RC_MEASURED_UNKNOWN 0xFFFFFFFF
|
||||
#define RC_OPERAND_NONE 0xFF
|
||||
|
||||
typedef struct {
|
||||
typedef struct rc_eval_state_t {
|
||||
/* memory accessors */
|
||||
rc_peek_t peek;
|
||||
void* peek_userdata;
|
||||
@@ -236,7 +236,7 @@ typedef struct {
|
||||
}
|
||||
rc_eval_state_t;
|
||||
|
||||
typedef struct {
|
||||
typedef struct rc_parse_state_t {
|
||||
int32_t offset;
|
||||
|
||||
void* buffer;
|
||||
|
||||
+3
-1
@@ -1210,8 +1210,10 @@ static int rc_validate_conflicting_conditions(const rc_condset_t* conditions, co
|
||||
|
||||
/* combining field didn't match, or there's more unmatched combining fields. ignore this condition */
|
||||
if (!chain_matches || rc_validate_is_combining_condition(compare_condition)) {
|
||||
while (compare_condition->next && rc_validate_is_combining_condition(compare_condition))
|
||||
while (compare_condition->next && rc_validate_is_combining_condition(compare_condition)) {
|
||||
++state->cond_index;
|
||||
compare_condition = compare_condition->next;
|
||||
}
|
||||
continue;
|
||||
}
|
||||
|
||||
|
||||
+1
-1
@@ -802,7 +802,7 @@ static int rc_evaluate_richpresence_display(rc_richpresence_display_part_t* part
|
||||
value.value.u32 = '?';
|
||||
|
||||
tmp[chars++] = (char)value.value.u32;
|
||||
if (chars == sizeof(tmp) || !part->next || part->next->display_type != RC_FORMAT_ASCIICHAR)
|
||||
if (chars == sizeof(tmp) - 1 || !part->next || part->next->display_type != RC_FORMAT_ASCIICHAR)
|
||||
break;
|
||||
|
||||
part = part->next;
|
||||
|
||||
+7
-1
@@ -159,8 +159,14 @@ static void rc_parse_legacy_value(rc_value_t* self, const char** memaddr, rc_par
|
||||
/* if it looks like a floating point number, add the 'f' prefix */
|
||||
while (isdigit((unsigned char)*buffer_ptr))
|
||||
++buffer_ptr;
|
||||
if (*buffer_ptr == '.')
|
||||
if (*buffer_ptr == '.') {
|
||||
if (ptr == &buffer[sizeof(buffer)]) {
|
||||
parse->offset = RC_INVALID_VALUE;
|
||||
return;
|
||||
}
|
||||
|
||||
*ptr++ = 'f';
|
||||
}
|
||||
continue;
|
||||
|
||||
default:
|
||||
|
||||
Vendored
+29
-8
@@ -503,6 +503,19 @@ static int rc_hash_from_buffer(char hash[33], uint32_t console_id, const rc_hash
|
||||
{
|
||||
switch (console_id) {
|
||||
default:
|
||||
if (iterator->path) {
|
||||
const char* ext = rc_path_get_extension(iterator->path);
|
||||
if (strcasecmp(ext, "cue") == 0 ||
|
||||
strcasecmp(ext, "m3u") == 0 ||
|
||||
strcasecmp(ext, "iso") == 0 ||
|
||||
strcasecmp(ext, "chd") == 0) {
|
||||
/* These extensions are associated to CD media. If buffered data
|
||||
* was provided, ignore it and try to open the media directly. */
|
||||
if (rc_hash_from_file(hash, console_id, iterator))
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
|
||||
return rc_hash_iterator_error_formatted(iterator, "Unsupported console for buffer hash: %d", console_id);
|
||||
|
||||
case RC_CONSOLE_AMSTRAD_PC:
|
||||
@@ -949,6 +962,12 @@ static int rc_hash_from_file(char hash[33], uint32_t console_id, const rc_hash_i
|
||||
case RC_CONSOLE_PSP:
|
||||
return rc_hash_psp(hash, iterator);
|
||||
|
||||
case RC_CONSOLE_PLAYSTATION_3:
|
||||
if (rc_path_compare_extension(path, "m3u"))
|
||||
return rc_hash_generate_from_playlist(hash, console_id, iterator);
|
||||
|
||||
return rc_hash_ps3(hash, iterator);
|
||||
|
||||
case RC_CONSOLE_SEGA_CD:
|
||||
case RC_CONSOLE_SATURN:
|
||||
if (rc_path_compare_extension(path, "m3u"))
|
||||
@@ -1064,10 +1083,11 @@ static void rc_hash_initialize_iterator_chd(rc_hash_iterator_t* iterator, int da
|
||||
iterator->consoles[2] = RC_CONSOLE_DREAMCAST;
|
||||
iterator->consoles[3] = RC_CONSOLE_SEGA_CD; /* ASSERT: handles both Sega CD and Saturn */
|
||||
iterator->consoles[4] = RC_CONSOLE_PSP;
|
||||
iterator->consoles[5] = RC_CONSOLE_PC_ENGINE_CD;
|
||||
iterator->consoles[6] = RC_CONSOLE_3DO;
|
||||
iterator->consoles[7] = RC_CONSOLE_NEO_GEO_CD;
|
||||
iterator->consoles[8] = RC_CONSOLE_PCFX;
|
||||
iterator->consoles[5] = RC_CONSOLE_PLAYSTATION_3;
|
||||
iterator->consoles[6] = RC_CONSOLE_PC_ENGINE_CD;
|
||||
iterator->consoles[7] = RC_CONSOLE_3DO;
|
||||
iterator->consoles[8] = RC_CONSOLE_NEO_GEO_CD;
|
||||
iterator->consoles[9] = RC_CONSOLE_PCFX;
|
||||
}
|
||||
|
||||
static void rc_hash_initialize_iterator_cue(rc_hash_iterator_t* iterator, int data) {
|
||||
@@ -1137,10 +1157,11 @@ static void rc_hash_initialize_iterator_iso(rc_hash_iterator_t* iterator, int da
|
||||
|
||||
iterator->consoles[0] = RC_CONSOLE_PLAYSTATION_2;
|
||||
iterator->consoles[1] = RC_CONSOLE_PSP;
|
||||
iterator->consoles[2] = RC_CONSOLE_3DO;
|
||||
iterator->consoles[3] = RC_CONSOLE_SEGA_CD; /* ASSERT: handles both Sega CD and Saturn */
|
||||
iterator->consoles[4] = RC_CONSOLE_GAMECUBE;
|
||||
iterator->consoles[5] = RC_CONSOLE_WII;
|
||||
iterator->consoles[2] = RC_CONSOLE_PLAYSTATION_3;
|
||||
iterator->consoles[3] = RC_CONSOLE_3DO;
|
||||
iterator->consoles[4] = RC_CONSOLE_SEGA_CD; /* ASSERT: handles both Sega CD and Saturn */
|
||||
iterator->consoles[5] = RC_CONSOLE_GAMECUBE;
|
||||
iterator->consoles[6] = RC_CONSOLE_WII;
|
||||
}
|
||||
|
||||
static void rc_hash_initialize_iterator_m3u(rc_hash_iterator_t* iterator, int data) {
|
||||
|
||||
@@ -95,6 +95,7 @@ int rc_hash_buffered_file(char hash[33], uint32_t console_id, const rc_hash_iter
|
||||
int rc_hash_psx(char hash[33], const rc_hash_iterator_t* iterator);
|
||||
int rc_hash_ps2(char hash[33], const rc_hash_iterator_t* iterator);
|
||||
int rc_hash_psp(char hash[33], const rc_hash_iterator_t* iterator);
|
||||
int rc_hash_ps3(char hash[33], const rc_hash_iterator_t* iterator);
|
||||
int rc_hash_sega_cd(char hash[33], const rc_hash_iterator_t* iterator);
|
||||
int rc_hash_wii(char hash[33], const rc_hash_iterator_t* iterator);
|
||||
#endif
|
||||
|
||||
Reference in New Issue
Block a user