Avoid allocating memory to compute the hash for NES ROMs when the core needs fullpath (fixed).

This commit is contained in:
Andre Leiradella 2016-10-26 20:09:17 +01:00
parent 58b3ef3ba4
commit 3d2cdbde98

172
cheevos.c
View File

@ -1811,34 +1811,52 @@ static INLINE unsigned cheevos_next_power_of_2(unsigned n)
static size_t cheevos_eval_md5(
const struct retro_game_info *info,
size_t offset,
size_t max_size,
MD5_CTX *ctx)
{
MD5_Init(ctx);
if (info->data)
{
MD5_Update(ctx, info->data, info->size);
return info->size;
if (max_size == 0)
max_size = info->size;
if (info->size - offset < max_size)
max_size = info->size - offset;
MD5_Update(ctx, (void*)(uint8_t*)info->data + offset, max_size);
return max_size;
}
else
{
RFILE *file = filestream_open(info->path, RFILE_MODE_READ, 0);
filestream_seek(file, offset, SEEK_SET);
size_t size = 0;
if (!file)
return 0;
if (max_size == 0)
max_size = (size_t)-1;
for (;;)
{
uint8_t buffer[4096];
size_t to_read = sizeof(buffer);
if (to_read > max_size)
to_read = max_size;
ssize_t num_read = filestream_read(file,
(void*)buffer, sizeof(buffer));
(void*)buffer, to_read);
if (num_read <= 0)
break;
MD5_Update(ctx, (void*)buffer, num_read);
size += num_read;
max_size -= num_read;
}
filestream_close(file);
@ -1846,22 +1864,21 @@ static size_t cheevos_eval_md5(
}
}
static void cheevos_fill_md5(size_t size, size_t total, MD5_CTX *ctx)
static void cheevos_fill_md5(size_t size, char fill, MD5_CTX *ctx)
{
char buffer[4096];
ssize_t fill = total - size;
buffer[0] = '\0';
memset((void*)buffer, fill, sizeof(buffer));
while (fill > 0)
while (size > 0)
{
ssize_t len = sizeof(buffer);
if (len > fill)
len = fill;
if (len > size)
len = size;
MD5_Update(ctx, (void*)buffer, len);
fill -= len;
size -= len;
}
}
@ -1872,7 +1889,7 @@ static unsigned cheevos_find_game_id_generic(
MD5_CTX ctx;
retro_time_t to;
uint8_t hash[16];
size_t size = cheevos_eval_md5(info, &ctx);
size_t size = cheevos_eval_md5(info, 0, 0, &ctx);
hash[0] = '\0';
@ -1890,23 +1907,19 @@ static unsigned cheevos_find_game_id_snes(
retro_time_t timeout)
{
MD5_CTX ctx;
retro_time_t to;
uint8_t hash[16];
size_t size = cheevos_eval_md5(info, &ctx);
size_t count = cheevos_eval_md5(info, 0, 0, &ctx);
hash[0] = '\0';
if (!size)
if (count == 0)
{
MD5_Final(hash, &ctx);
return 0;
}
cheevos_fill_md5(size, CHEEVOS_EIGHT_MB, &ctx);
cheevos_fill_md5(CHEEVOS_EIGHT_MB - count, 0, &ctx);
MD5_Final(hash, &ctx);
to = timeout;
return cheevos_get_game_id(hash, &to);
return cheevos_get_game_id(hash, &timeout);
}
static unsigned cheevos_find_game_id_genesis(
@ -1914,31 +1927,30 @@ static unsigned cheevos_find_game_id_genesis(
{
MD5_CTX ctx;
uint8_t hash[16];
retro_time_t to;
size_t size = cheevos_eval_md5(info, &ctx);
size_t count = cheevos_eval_md5(info, 0, 0, &ctx);
if (!size)
if (count == 0)
{
MD5_Final(hash, &ctx);
return 0;
}
cheevos_fill_md5(size, CHEEVOS_SIX_MB, &ctx);
cheevos_fill_md5(CHEEVOS_SIX_MB - count, 0, &ctx);
MD5_Final(hash, &ctx);
to = timeout;
return cheevos_get_game_id(hash, &to);
return cheevos_get_game_id(hash, &timeout);
}
static unsigned cheevos_find_game_id_nes(
const struct retro_game_info *info,
retro_time_t timeout)
{
static int not_power2[] =
{
53, 198, 228
};
/* Note about the references to the FCEU emulator below. There is no
* core-specific code in this function, it's rather Retro Achievements
* specific code that must be followed to the letter so we compute
* the correct ROM hash. Retro Achievements does indeed use some
* FCEU related method to compute the hash, since its NES emulator
* is based on it. */
struct
{
uint8_t id[4]; /* NES^Z */
@ -1949,16 +1961,15 @@ static unsigned cheevos_find_game_id_nes(
uint8_t reserve[8];
} header;
size_t rom_size;
size_t rom_size, offset, count;
MD5_CTX ctx;
uint8_t hash[16];
retro_time_t to;
unsigned bytes;
size_t bytes;
RFILE *file;
ssize_t num_read;
int i, mapper_no;
bool round = true;
uint8_t *data;
int mapper_no;
bool round;
if (info->data)
{
@ -1969,8 +1980,7 @@ static unsigned cheevos_find_game_id_nes(
}
else
{
ssize_t num_read;
RFILE *file = filestream_open(info->path, RFILE_MODE_READ, 0);
file = filestream_open(info->path, RFILE_MODE_READ, 0);
if (!file)
return 0;
@ -1993,83 +2003,27 @@ static unsigned cheevos_find_game_id_nes(
else
rom_size = 256;
data = (uint8_t *) malloc(rom_size << 14);
if (!data)
return 0;
/* from FCEU core - need it for a correctly md5 sum */
memset(data, 0xFF, rom_size << 14);
/* from FCEU core - compute size using the cart mapper */
mapper_no = (header.rom_type >> 4);
mapper_no |= (header.rom_type2 & 0xF0);
for (i = 0; i != ARRAY_SIZE(not_power2); ++i)
{
/* for games not to the power of 2, so we just read enough
* PRG rom from it, but we have to keep ROM_size to the power of 2
* since PRGCartMapping wants ROM_size to be to the power of 2
* so instead if not to power of 2, we just use head.ROM_size when
* we use FCEU_read. */
if (not_power2[i] == mapper_no)
{
round = false;
break;
}
}
mapper_no = (header.rom_type >> 4) | (header.rom_type2 & 0xF0);
/* for games not to the power of 2, so we just read enough
* PRG rom from it, but we have to keep ROM_size to the power of 2
* since PRGCartMapping wants ROM_size to be to the power of 2
* so instead if not to power of 2, we just use head.ROM_size when
* we use FCEU_read. */
round = mapper_no != 53 && mapper_no != 198 && mapper_no != 228;
bytes = (round) ? rom_size : header.rom_size;
/* from FCEU core - check if Trainer included in ROM data */
offset = sizeof(header) + (header.rom_type & 4 ? sizeof(header) : 0);
MD5_Init(&ctx);
if (info->data)
{
size_t offset = sizeof(header);
size_t count;
/* from FCEU core - check if Trainer included in ROM data */
if (header.rom_type & 4)
offset += sizeof(header);
count = info->size - offset;
if (count > 0x4000 * bytes)
count = 0x4000 * bytes;
memcpy(data, (void*)(uint8_t*)info->data + offset, count);
}
else
{
RFILE *file = filestream_open(info->path, RFILE_MODE_READ, 0);
if (!file)
{
free(data);
return 0;
}
filestream_seek(file, sizeof(header), SEEK_SET);
/* from FCEU core - check if Trainer included in ROM data */
if (header.rom_type & 4)
filestream_seek(file, sizeof(header), SEEK_CUR);
num_read = filestream_read(file, (void*)data, 0x4000 * bytes );
filestream_close(file);
if (num_read <= 0)
{
free(data);
return 0;
}
}
MD5_Update(&ctx, (void*) data, rom_size << 14);
count = cheevos_eval_md5(info, offset, 0x4000 * bytes, &ctx);
count = 0x4000 * bytes - count;
cheevos_fill_md5(count, 0xff, &ctx);
MD5_Final(hash, &ctx);
free(data);
to = timeout;
return cheevos_get_game_id(hash, &to);
return cheevos_get_game_id(hash, &timeout);
}
bool cheevos_load(const void *data)