Backport leiradel PR - 'support need_fullpath; changed how md5 hashes

are tested'
This commit is contained in:
twinaphex 2015-11-02 17:17:34 +01:00
parent 869ebb3733
commit fa9ef5b021
3 changed files with 123 additions and 48 deletions

160
cheevos.c
View File

@ -18,6 +18,7 @@
#include <formats/jsonsax.h>
#include <rhash.h>
#include <retro_file.h>
#include <retro_log.h>
#include <rthreads/async_job.h>
@ -31,7 +32,7 @@
enum
{
CHEEVOS_VAR_SIZE_BIT_0,
CHEEVOS_VAR_SIZE_BIT_0 = 0,
CHEEVOS_VAR_SIZE_BIT_1,
CHEEVOS_VAR_SIZE_BIT_2,
CHEEVOS_VAR_SIZE_BIT_3,
@ -51,7 +52,7 @@ enum
enum
{
CHEEVOS_VAR_TYPE_ADDRESS, /* compare to the value of a live address in RAM */
CHEEVOS_VAR_TYPE_ADDRESS = 0, /* compare to the value of a live address in RAM */
CHEEVOS_VAR_TYPE_VALUE_COMP, /* a number. assume 32 bit */
CHEEVOS_VAR_TYPE_DELTA_MEM, /* the value last known at this address. */
CHEEVOS_VAR_TYPE_DYNAMIC_VAR, /* a custom user-set variable */
@ -61,7 +62,7 @@ enum
enum
{
CHEEVOS_COND_OP_EQUALS,
CHEEVOS_COND_OP_EQUALS = 0,
CHEEVOS_COND_OP_LESS_THAN,
CHEEVOS_COND_OP_LESS_THAN_OR_EQUAL,
CHEEVOS_COND_OP_GREATER_THAN,
@ -73,7 +74,7 @@ enum
enum
{
CHEEVOS_COND_TYPE_STANDARD,
CHEEVOS_COND_TYPE_STANDARD = 0,
CHEEVOS_COND_TYPE_PAUSE_IF,
CHEEVOS_COND_TYPE_RESET_IF,
@ -1502,51 +1503,126 @@ static int cheevos_deactivate_unlocks(unsigned game_id, retro_time_t *timeout)
#define CHEEVOS_EIGHT_MB (8 * 1024 * 1024)
int cheevos_load(const void *data, size_t size)
static size_t cheevos_eval_md5(const struct retro_game_info *info, MD5_CTX *ctx)
{
const char *json;
MD5_CTX ctx, saved_ctx;
retro_time_t timeout;
char buffer[4096];
size_t len;
unsigned char hash[16];
unsigned game_id;
MD5_Init(ctx);
if (info->data)
{
MD5_Update(ctx, info->data, info->size);
return info->size;
}
else
{
RFILE *file = retro_fopen(info->path, RFILE_MODE_READ, 0);
size_t size = 0;
if (!file)
return 0;
for (;;)
{
uint8_t buffer[4096];
ssize_t num_read = retro_fread(file, (void*)buffer, sizeof(buffer));
if (num_read <= 0)
break;
MD5_Update(ctx, (void*)buffer, num_read);
size += num_read;
}
retro_fclose(file);
return size;
}
}
static void cheevos_fill_md5(size_t size, size_t total, MD5_CTX *ctx)
{
ssize_t fill = total - size;
char buffer[4096];
memset((void*)buffer, 0, sizeof(buffer));
do
{
ssize_t len = sizeof(buffer);
if (len > fill)
len = fill;
MD5_Update(ctx, (void*)buffer, len);
fill -= len;
}
while (fill > 0);
}
typedef unsigned (*cheevos_id_finder_t)(const struct retro_game_info *, retro_time_t);
static unsigned cheevos_find_game_id_generic(const struct retro_game_info *info, retro_time_t timeout)
{
MD5_CTX ctx;
uint8_t hash[16];
retro_time_t to;
size_t size;
size = cheevos_eval_md5(info, &ctx);
MD5_Final(hash, &ctx);
if (!size)
return 0;
to = timeout;
return cheevos_get_game_id(hash, &to);
}
static unsigned cheevos_find_game_id_snes(const struct retro_game_info *info, retro_time_t timeout)
{
MD5_CTX ctx;
uint8_t hash[16];
retro_time_t to;
size_t size;
size = cheevos_eval_md5(info, &ctx);
if (!size)
{
MD5_Final(hash, &ctx);
return 0;
}
cheevos_fill_md5(size, CHEEVOS_EIGHT_MB, &ctx);
MD5_Final(hash, &ctx);
to = timeout;
return cheevos_get_game_id(hash, &to);
}
int cheevos_load(const struct retro_game_info *info)
{
static const cheevos_id_finder_t finders[] =
{
cheevos_find_game_id_generic,
cheevos_find_game_id_snes
};
retro_time_t timeout = 5000000;
unsigned game_id = 0;
int i;
const char *json;
/* Just return OK if cheevos are disabled. */
if (!config_get_ptr()->cheevos.enable)
return 0;
MD5_Init(&ctx);
MD5_Update(&ctx, data, size);
saved_ctx = ctx;
MD5_Final(hash, &ctx);
timeout = 15000000;
game_id = cheevos_get_game_id(hash, &timeout);
if (!game_id && size < CHEEVOS_EIGHT_MB)
for (i = 0; i < sizeof(finders) / sizeof(finders[0]); i++)
{
/* Maybe the content is a SNES game, continue MD5 with zeroes up to 8 MB. */
size = CHEEVOS_EIGHT_MB - size;
memset((void*)buffer, 0, sizeof(buffer));
do
{
len = sizeof(buffer);
if (len > size)
len = size;
MD5_Update(&saved_ctx, (void*)buffer, len);
size -= len;
}
while (size);
MD5_Final(hash, &saved_ctx);
game_id = cheevos_get_game_id(hash, &timeout);
game_id = finders[i](info, 5000000);
if (game_id)
break;
}
if (game_id)
{
cheevos_playing_activity(game_id, &timeout);

View File

@ -19,6 +19,8 @@
#include <stdint.h>
#include <stdlib.h>
#include "libretro.h"
typedef struct
{
int cheats_are_enabled;
@ -27,7 +29,7 @@ typedef struct
extern cheevos_globals_t cheevos_globals;
int cheevos_load(const void *data, size_t size);
int cheevos_load(const struct retro_game_info *info);
void cheevos_test(void);

View File

@ -518,11 +518,8 @@ static bool load_content(const struct retro_subsystem_info *special,
#ifdef HAVE_CHEEVOS
/* Load the achievements into memory if the game has content. */
if (*content->elems[0].data)
{
cheevos_globals.cheats_were_enabled = cheevos_globals.cheats_are_enabled;
cheevos_load(info->data, info->size);
}
cheevos_globals.cheats_were_enabled = cheevos_globals.cheats_are_enabled;
cheevos_load(*content->elems[0].data ? info : NULL);
#endif
ret = core.retro_load_game(*content->elems[0].data ? info : NULL);