cheevos-new: update nes/snes/lynx hashing methods

This commit is contained in:
meleu 2019-01-19 15:29:54 -02:00
parent f78f447b12
commit b7acc33bda

View File

@ -1118,6 +1118,8 @@ enum
static int cheevos_iterate(coro_t* coro) static int cheevos_iterate(coro_t* coro)
{ {
const int snes_header_len = 0x200;
const int lynx_header_len = 0x40;
ssize_t num_read = 0; ssize_t num_read = 0;
size_t to_read = 4096; size_t to_read = 4096;
uint8_t *buffer = NULL; uint8_t *buffer = NULL;
@ -1159,10 +1161,10 @@ static int cheevos_iterate(coro_t* coro)
static cheevos_finder_t finders[] = static cheevos_finder_t finders[] =
{ {
{SNES_MD5, "SNES (8Mb padding)", snes_exts}, {SNES_MD5, "SNES (discards header)", snes_exts},
{GENESIS_MD5, "Genesis (6Mb padding)", genesis_exts}, {GENESIS_MD5, "Genesis (6Mb padding)", genesis_exts},
{LYNX_MD5, "Atari Lynx (only first 512 bytes)", lynx_exts}, {LYNX_MD5, "Atari Lynx (discards header)", lynx_exts},
{NES_MD5, "NES (discards VROM)", NULL}, {NES_MD5, "NES (discards header)", NULL},
{GENERIC_MD5, "Generic (plain content)", NULL}, {GENERIC_MD5, "Generic (plain content)", NULL},
{FILENAME_MD5, "Generic (filename)", NULL} {FILENAME_MD5, "Generic (filename)", NULL}
}; };
@ -1403,33 +1405,22 @@ found:
* Output CHEEVOS_VAR_GAMEID the Retro Achievements game ID, or 0 if not found * Output CHEEVOS_VAR_GAMEID the Retro Achievements game ID, or 0 if not found
*************************************************************************/ *************************************************************************/
CORO_SUB(SNES_MD5) CORO_SUB(SNES_MD5)
MD5_Init(&coro->md5); MD5_Init(&coro->md5);
coro->offset = 0; /* Checks for the existence of a headered SNES file.
coro->count = 0; Unheadered files fall back to GENERIC_MD5. */
if (coro->len < 0x2000 || coro->len % 0x2000 != snes_header_len)
CORO_GOSUB(EVAL_MD5);
if (coro->count == 0)
{ {
MD5_Final(coro->hash, &coro->md5);
coro->gameid = 0; coro->gameid = 0;
CORO_RET(); CORO_RET();
} }
if (coro->count < CHEEVOS_MB(8)) coro->offset = 512;
{ coro->count = 0;
/*
* Inputs: CHEEVOS_VAR_MD5, CHEEVOS_VAR_OFFSET, CHEEVOS_VAR_COUNT
* Outputs: CHEEVOS_VAR_MD5
*/
coro->offset = 0;
coro->count = CHEEVOS_MB(8) - coro->count;
CORO_GOSUB(FILL_MD5);
}
CORO_GOSUB(EVAL_MD5);
MD5_Final(coro->hash, &coro->md5); MD5_Final(coro->hash, &coro->md5);
CORO_GOTO(GET_GAMEID); CORO_GOTO(GET_GAMEID);
/************************************************************************** /**************************************************************************
@ -1469,16 +1460,18 @@ found:
*************************************************************************/ *************************************************************************/
CORO_SUB(LYNX_MD5) CORO_SUB(LYNX_MD5)
if (coro->len < 0x0240) /* Checks for the existence of a headered Lynx file.
Unheadered files fall back to GENERIC_MD5. */
if (coro->len <= lynx_header_len ||
memcmp("LYNX", (void *)coro->data, 5) != 0)
{ {
coro->gameid = 0; coro->gameid = 0;
CORO_RET(); CORO_RET();
} }
MD5_Init(&coro->md5); MD5_Init(&coro->md5);
coro->offset = lynx_header_len;
coro->offset = 0x0040; coro->count = coro->len - lynx_header_len;
coro->count = 0x0200;
CORO_GOSUB(EVAL_MD5); CORO_GOSUB(EVAL_MD5);
MD5_Final(coro->hash, &coro->md5); MD5_Final(coro->hash, &coro->md5);
@ -1491,13 +1484,8 @@ found:
*************************************************************************/ *************************************************************************/
CORO_SUB(NES_MD5) CORO_SUB(NES_MD5)
/* Note about the references to the FCEU emulator below. There is no /* Checks for the existence of a headered NES file.
* core-specific code in this function, it's rather Retro Achievements Unheadered files fall back to GENERIC_MD5. */
* 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. */
if (coro->len < sizeof(coro->header)) if (coro->len < sizeof(coro->header))
{ {
coro->gameid = 0; coro->gameid = 0;
@ -1507,83 +1495,22 @@ found:
memcpy((void*)&coro->header, coro->data, memcpy((void*)&coro->header, coro->data,
sizeof(coro->header)); sizeof(coro->header));
if (coro->header.id[0] == 'N' if ( coro->header.id[0] != 'N'
&& coro->header.id[1] == 'E' || coro->header.id[1] != 'E'
&& coro->header.id[2] == 'S' || coro->header.id[2] != 'S'
&& coro->header.id[3] == 0x1a) || coro->header.id[3] != 0x1a)
{ {
size_t romsize = 256; coro->gameid = 0;
/* from FCEU core - compute size using the cart mapper */ CORO_RET();
int mapper = (coro->header.rom_type >> 4) | (coro->header.rom_type2 & 0xF0);
if (coro->header.rom_size)
romsize = next_pow2(coro->header.rom_size);
/* 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. */
coro->round = mapper != 53 && mapper != 198 && mapper != 228;
coro->bytes = coro->round ? romsize : coro->header.rom_size;
coro->offset = sizeof(coro->header) + (coro->header.rom_type & 4
? sizeof(coro->header) : 0);
/* from FCEU core - check if Trainer included in ROM data */
MD5_Init(&coro->md5);
coro->count = 0x4000 * coro->bytes;
CORO_GOSUB(EVAL_MD5);
if (coro->count < 0x4000 * coro->bytes)
{
coro->offset = 0xff;
coro->count = 0x4000 * coro->bytes - coro->count;
CORO_GOSUB(FILL_MD5);
} }
MD5_Init(&coro->md5);
coro->offset = sizeof(coro->header);
coro->count = coro->len - coro->offset;
CORO_GOSUB(EVAL_MD5);
MD5_Final(coro->hash, &coro->md5); MD5_Final(coro->hash, &coro->md5);
CORO_GOTO(GET_GAMEID); CORO_GOTO(GET_GAMEID);
}
else
{
unsigned i;
size_t chunks = coro->len >> 14;
size_t chunk_size = 0x4000;
/* Fall back to headerless hashing
* PRG ROM size is unknown, so test by 16KB chunks */
coro->round = 0;
coro->offset = 0;
for (i = 0; i < chunks; i++)
{
MD5_Init(&coro->md5);
coro->bytes = i + 1;
coro->count = coro->bytes * chunk_size;
CORO_GOSUB(EVAL_MD5);
if (coro->count < 0x4000 * coro->bytes)
{
coro->offset = 0xff;
coro->count = 0x4000 * coro->bytes - coro->count;
CORO_GOSUB(FILL_MD5);
}
MD5_Final(coro->hash, &coro->md5);
CORO_GOSUB(GET_GAMEID);
if (coro->gameid > 0)
{
break;
}
}
CORO_RET();
}
/************************************************************************** /**************************************************************************
* Info Tries to identify a "generic" game * Info Tries to identify a "generic" game