use PSX.EXE if SYSTEM.CNF cannot be found

This commit is contained in:
Jamiras 2019-11-16 08:36:13 -07:00
parent 0d284c42bc
commit 3b0cbc1e41

View File

@ -1215,18 +1215,139 @@ enum
RCHEEVOS_PCE_CD_MD5 = -17
};
static int rcheevos_hash_psx(rcheevos_coro_t* coro)
{
char exe_name_buffer[64];
size_t exe_name_size;
char* exe_name = NULL;
uint8_t* ptr = NULL;
const char* end = NULL;
char* scan = NULL;
char buffer[2048];
int success = 0;
size_t to_read = 0;
/* find the data track - it should be the first one */
coro->track = cdfs_open_data_track(coro->path);
if (!coro->track)
{
CHEEVOS_LOG(RCHEEVOS_TAG "could not open CD\n");
return false;
}
/* open the SYSTEM.CNF file and find the BOOT= record */
if (cdfs_open_file(&coro->cdfp, coro->track, "SYSTEM.CNF"))
{
cdfs_read_file(&coro->cdfp, buffer, sizeof(buffer));
for (scan = buffer; scan < &buffer[sizeof(buffer)] && *scan; ++scan)
{
if (strncmp(scan, "BOOT", 4) == 0)
{
exe_name = scan + 4;
while (isspace(*exe_name))
++exe_name;
if (*exe_name == '=')
{
++exe_name;
while (isspace(*exe_name))
++exe_name;
if (strncmp(exe_name, "cdrom:", 6) == 0)
exe_name += 6;
if (*exe_name == '\\')
++exe_name;
break;
}
}
while (*scan && *scan != '\n')
++scan;
}
cdfs_close_file(&coro->cdfp);
if (exe_name)
{
scan = exe_name;
while (!isspace(*scan) && *scan != ';')
++scan;
*scan = '\0';
}
}
else
{
/* no SYSTEM.CNF, check for a PSX.EXE */
exe_name = "PSX.EXE";
}
if (!exe_name || !cdfs_open_file(&coro->cdfp, coro->track, exe_name))
{
CHEEVOS_LOG(RCHEEVOS_TAG "could not locate primary executable\n");
}
else
{
/* store the exe name, we're about to overwrite buffer */
strncpy(exe_name_buffer, exe_name, sizeof(exe_name_buffer));
exe_name_buffer[sizeof(exe_name_buffer) - 1] = '\0';
exe_name_size = strlen(exe_name_buffer);
/* read the first sector of the executable */
cdfs_read_file(&coro->cdfp, buffer, sizeof(buffer));
/* the PSX-E header specifies the executable size as a 4-byte value 28 bytes into the header, which doesn't
* include the header itself. We want to include the header in the hash, so append another 2048 to that value.
* ASSERT: this results in the same value as coro->cdfp->size */
coro->count = 2048 + (((uint8_t)buffer[28 + 3] << 24) | ((uint8_t)buffer[28 + 2] << 16) |
((uint8_t)buffer[28 + 1] << 8) | (uint8_t)buffer[28]);
if (coro->count <= CHEEVOS_MB(16)) /* sanity check */
{
/* there's a few games that use a singular engine and only differ via their data files.
* luckily, they have unique serial numbers, and use the serial number as the boot file in the
* standard way. include the boot executable name in the hash */
coro->count += exe_name_size;
free(coro->data);
coro->data = (uint8_t*)malloc(coro->count);
memcpy(coro->data, exe_name_buffer, exe_name_size);
coro->len = exe_name_size;
memcpy((uint8_t*)coro->data + coro->len, buffer, sizeof(buffer));
coro->len += sizeof(buffer);
while (coro->len < coro->count)
{
to_read = coro->count - coro->len;
if (to_read > 2048)
to_read = 2048;
cdfs_read_file(&coro->cdfp, (uint8_t*)coro->data + coro->len, to_read);
coro->len += to_read;
};
success = 1;
}
cdfs_close_file(&coro->cdfp);
}
cdfs_close_track(coro->track);
coro->track = NULL;
return success;
}
static int rcheevos_iterate(rcheevos_coro_t* coro)
{
const int snes_header_len = 0x200;
const int lynx_header_len = 0x40;
ssize_t num_read = 0;
size_t to_read = 4096;
uint8_t *ptr = NULL;
const char *end = NULL;
size_t exe_name_size = 0;
char exe_name_buffer[64];
char* exe_name = NULL;
char* scan = NULL;
uint8_t* ptr = NULL;
const char* end = NULL;
char buffer[2048];
static const uint32_t snes_exts[] =
@ -1766,120 +1887,13 @@ found:
*************************************************************************/
CORO_SUB(RCHEEVOS_PSX_MD5)
{
MD5_Init(&coro->md5);
/* find the data track - it should be the first one */
coro->track = cdfs_open_data_track(coro->path);
if (coro->track)
if (rcheevos_hash_psx(coro))
{
/* open the SYSTEM.CNF file and find the BOOT= record */
if (cdfs_open_file(&coro->cdfp, coro->track, "SYSTEM.CNF"))
{
cdfs_read_file(&coro->cdfp, buffer, sizeof(buffer));
MD5_Init(&coro->md5);
CORO_GOSUB(RCHEEVOS_EVAL_MD5);
MD5_Final(coro->hash, &coro->md5);
for (scan = buffer; scan < &buffer[sizeof(buffer)] && *scan; ++scan)
{
if (strncmp(scan, "BOOT", 4) == 0)
{
exe_name = scan + 4;
while (isspace(*exe_name))
++exe_name;
if (*exe_name == '=')
{
++exe_name;
while (isspace(*exe_name))
++exe_name;
if (strncmp(exe_name, "cdrom:", 6) == 0)
exe_name += 6;
if (*exe_name == '\\')
++exe_name;
break;
}
}
while (*scan && *scan != '\n')
++scan;
}
cdfs_close_file(&coro->cdfp);
if (exe_name)
{
scan = exe_name;
while (*scan != '\n' && *scan != '\r' && *scan != ';' && *scan != ' ')
++scan;
*scan = '\0';
exe_name_size = scan - exe_name;
if (exe_name_size < sizeof(exe_name_buffer))
strcpy(exe_name_buffer, exe_name);
/* open the file pointed to by the BOOT= record */
if (exe_name_buffer[0] && cdfs_open_file(&coro->cdfp, coro->track, exe_name_buffer))
{
cdfs_read_file(&coro->cdfp, buffer, sizeof(buffer));
/* the PSX-E header specifies the executable size as a 4-byte value 28 bytes into the header, which doesn't
* include the header itself. We want to include the header in the hash, so append another 2048 to that value.
* ASSERT: this results in the same value as coro->cdfp->size */
coro->count = 2048 + (((uint8_t)buffer[28 + 3] << 24) | ((uint8_t)buffer[28 + 2] << 16) |
((uint8_t)buffer[28 + 1] << 8) | (uint8_t)buffer[28]);
if (coro->count > CHEEVOS_MB(16)) /* sanity check */
{
cdfs_close_file(&coro->cdfp);
}
else
{
/* there's a few games that are use a singular engine and only differ via their data files.
* luckily, they have unique serial numbers, and use the serial number as the boot file in the
* standard way. include the boot executable name in the hash */
coro->count += exe_name_size;
free(coro->data);
coro->data = (uint8_t*)malloc(coro->count);
memcpy(coro->data, exe_name_buffer, exe_name_size);
coro->len = exe_name_size;
memcpy((uint8_t*)coro->data + coro->len, buffer, sizeof(buffer));
coro->len += sizeof(buffer);
while (coro->len < coro->count)
{
CORO_YIELD();
to_read = coro->count - coro->len;
if (to_read > 2048)
to_read = 2048;
cdfs_read_file(&coro->cdfp, (uint8_t*)coro->data + coro->len, to_read);
coro->len += to_read;
};
CORO_GOSUB(RCHEEVOS_EVAL_MD5);
MD5_Final(coro->hash, &coro->md5);
cdfs_close_file(&coro->cdfp);
cdfs_close_track(coro->track);
coro->track = NULL;
CORO_GOTO(RCHEEVOS_GET_GAMEID);
}
}
}
}
CHEEVOS_LOG(RCHEEVOS_TAG "could not locate primary executable\n", coro->gameid);
cdfs_close_track(coro->track);
coro->track = NULL;
}
else
{
CHEEVOS_LOG(RCHEEVOS_TAG "could not open CD\n", coro->gameid);
CORO_GOTO(RCHEEVOS_GET_GAMEID);
}
coro->gameid = 0;