Merge pull request #9521 from Jamiras/segacd_cheevos

(cheevos) support for Sega CD/Saturn; reduce hash calls to server
This commit is contained in:
Twinaphex 2019-09-29 19:33:36 +02:00 committed by GitHub
commit 38fe58e746
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
3 changed files with 259 additions and 178 deletions

View File

@ -1068,7 +1068,9 @@ static void rcheevos_unlock_cb(unsigned id, void* userdata)
#ifndef CHEEVOS_DONT_DEACTIVATE
cheevo->active &= ~*(unsigned*)userdata;
#endif
CHEEVOS_LOG(RCHEEVOS_TAG "cheevo %u deactivated: %s\n", id, cheevo->info->title);
CHEEVOS_LOG(RCHEEVOS_TAG "cheevo %u deactivated (%s): %s\n", id,
(*(unsigned*)userdata) == RCHEEVOS_ACTIVE_HARDCORE ? "hardcore" : "softcore",
cheevo->info->title);
return;
}
}
@ -1099,8 +1101,9 @@ typedef struct
char url[256];
char badge_basepath[PATH_MAX_LENGTH];
char badge_fullpath[PATH_MAX_LENGTH];
unsigned char last_hash[16];
unsigned char hash[16];
bool round;
unsigned ext_hash;
unsigned gameid;
unsigned i;
unsigned j;
@ -1133,14 +1136,14 @@ typedef struct
enum
{
/* Negative values because CORO_SUB generates positive values */
RCHEEVOS_SNES_MD5 = -1,
RCHEEVOS_GENESIS_MD5 = -2,
RCHEEVOS_GENERIC_MD5 = -1,
RCHEEVOS_SNES_MD5 = -2,
RCHEEVOS_LYNX_MD5 = -3,
RCHEEVOS_NES_MD5 = -4,
RCHEEVOS_GENERIC_MD5 = -5,
RCHEEVOS_FILENAME_MD5 = -6,
RCHEEVOS_PSX_MD5 = -5,
RCHEEVOS_ARCADE_MD5 = -6,
RCHEEVOS_EVAL_MD5 = -7,
RCHEEVOS_FILL_MD5 = -8,
RCHEEVOS_SEGACD_MD5 = -8,
RCHEEVOS_GET_GAMEID = -9,
RCHEEVOS_GET_CHEEVOS = -10,
RCHEEVOS_GET_BADGES = -11,
@ -1148,8 +1151,7 @@ enum
RCHEEVOS_HTTP_GET = -13,
RCHEEVOS_DEACTIVATE = -14,
RCHEEVOS_PLAYING = -15,
RCHEEVOS_DELAY = -16,
RCHEEVOS_PSX_MD5 = -17
RCHEEVOS_DELAY = -16
};
static int rcheevos_iterate(rcheevos_coro_t* coro)
@ -1166,21 +1168,6 @@ static int rcheevos_iterate(rcheevos_coro_t* coro)
char* scan = NULL;
char buffer[2048];
static const uint32_t genesis_exts[] =
{
0x0b888feeU, /* mdx */
0x005978b6U, /* md */
0x0b88aa89U, /* smd */
0x0b88767fU, /* gen */
0x0b8861beU, /* bin */
0x0b886782U, /* cue */
0x0b8880d0U, /* iso */
0x0b88aa98U, /* sms */
0x005977f3U, /* gg */
0x0059797fU, /* sg */
0
};
static const uint32_t snes_exts[] =
{
0x0b88aa88U, /* smc */
@ -1194,6 +1181,12 @@ static int rcheevos_iterate(rcheevos_coro_t* coro)
0
};
static const uint32_t nes_exts[] =
{
0x0b88944bU, /* nes */
0
};
static const uint32_t lynx_exts[] =
{
0x0b888cf7U, /* lnx */
@ -1211,15 +1204,29 @@ static int rcheevos_iterate(rcheevos_coro_t* coro)
0
};
static const uint32_t segacd_exts[] =
{
0x0b886782U, /* cue */
0x0b8880d0U, /* iso */
0x0b8865d4U, /* chd */
0
};
static const uint32_t arcade_exts[] =
{
0x0b88c7d8U, /* zip */
0
};
static rcheevos_finder_t finders[] =
{
{RCHEEVOS_SNES_MD5, "SNES (discards header)", snes_exts},
{RCHEEVOS_GENESIS_MD5, "Genesis (6Mb padding)", genesis_exts},
{RCHEEVOS_LYNX_MD5, "Atari Lynx (discards header)", lynx_exts},
{RCHEEVOS_NES_MD5, "NES (discards header)", NULL},
{RCHEEVOS_NES_MD5, "NES (discards header)", nes_exts},
{RCHEEVOS_PSX_MD5, "Playstation (main executable)", psx_exts},
{RCHEEVOS_GENERIC_MD5, "Generic (plain content)", NULL},
{RCHEEVOS_FILENAME_MD5, "Generic (filename)", NULL}
{RCHEEVOS_SEGACD_MD5, "Sega CD/Saturn (first sector)", segacd_exts},
{RCHEEVOS_ARCADE_MD5, "Arcade (filename)", arcade_exts},
{RCHEEVOS_GENERIC_MD5, "Generic (plain content)", NULL}
};
CORO_ENTER();
@ -1286,14 +1293,44 @@ static int rcheevos_iterate(rcheevos_coro_t* coro)
CHEEVOS_FREE(coro->stream);
}
/* Use the supported extensions as a hint
* to what method we should use. */
core_get_system_info(&coro->sysinfo);
/* Use the selected file's extension to determine which method to use */
for (coro->i = 0; coro->i < ARRAY_SIZE(finders); coro->i++)
{
if (finders[coro->i].ext_hashes)
{
for (coro->j = 0; finders[coro->i].ext_hashes[coro->j]; coro->j++)
{
if (finders[coro->i].ext_hashes[coro->j] == coro->ext_hash)
{
CHEEVOS_LOG(RCHEEVOS_TAG "testing %s\n", finders[coro->i].name);
CORO_GOSUB(finders[coro->i].label);
if (coro->gameid != 0)
goto found;
break;
}
}
}
}
/* Use the extensions supported by the core as a hint to what method we should use. */
core_get_system_info(&coro->sysinfo);
CHEEVOS_LOG(RCHEEVOS_TAG "no method for file extension, trying core supported extensions: %s\n", coro->sysinfo.valid_extensions);
for (coro->i = 0; coro->i < ARRAY_SIZE(finders); coro->i++)
{
if (finders[coro->i].ext_hashes)
{
for (coro->j = 0; finders[coro->i].ext_hashes[coro->j]; coro->j++)
{
if (finders[coro->i].ext_hashes[coro->j] == coro->ext_hash)
break;
}
/* did we already check this one? */
if (finders[coro->i].ext_hashes[coro->j] == coro->ext_hash)
continue;
coro->ext = coro->sysinfo.valid_extensions;
while (coro->ext)
@ -1316,13 +1353,7 @@ static int rcheevos_iterate(rcheevos_coro_t* coro)
{
if (finders[coro->i].ext_hashes[coro->j] == hash)
{
CHEEVOS_LOG(RCHEEVOS_TAG "testing %s\n",
finders[coro->i].name);
/*
* Inputs: CHEEVOS_VAR_INFO
* Outputs: CHEEVOS_VAR_GAMEID, the game was found if it's different from 0
*/
CHEEVOS_LOG(RCHEEVOS_TAG "testing %s\n", finders[coro->i].name);
CORO_GOSUB(finders[coro->i].label);
if (coro->gameid != 0)
@ -1336,18 +1367,13 @@ static int rcheevos_iterate(rcheevos_coro_t* coro)
}
}
/* Try hashing methods not specifically tied to a file extension */
for (coro->i = 0; coro->i < ARRAY_SIZE(finders); coro->i++)
{
if (finders[coro->i].ext_hashes)
continue;
CHEEVOS_LOG(RCHEEVOS_TAG "testing %s\n",
finders[coro->i].name);
/*
* Inputs: CHEEVOS_VAR_INFO
* Outputs: CHEEVOS_VAR_GAMEID
*/
CHEEVOS_LOG(RCHEEVOS_TAG "testing %s\n", finders[coro->i].name);
CORO_GOSUB(finders[coro->i].label);
if (coro->gameid != 0)
@ -1450,11 +1476,12 @@ found:
CORO_GOSUB(RCHEEVOS_GET_BADGES);
CORO_STOP();
/**************************************************************************
* Info Tries to identify a SNES game
* Input CHEEVOS_VAR_INFO the content info
* Output CHEEVOS_VAR_GAMEID the Retro Achievements game ID, or 0 if not found
*************************************************************************/
/**************************************************************************
* Info Tries to identify a SNES game
* Input CHEEVOS_VAR_INFO the content info
* Output CHEEVOS_VAR_GAMEID the Retro Achievements game ID, or 0 if not found
*************************************************************************/
CORO_SUB(RCHEEVOS_SNES_MD5)
MD5_Init(&coro->md5);
@ -1462,6 +1489,7 @@ found:
Unheadered files fall back to RCHEEVOS_GENERIC_MD5. */
if (coro->len < 0x2000 || coro->len % 0x2000 != snes_header_len)
{
CHEEVOS_LOG(RCHEEVOS_TAG "could not locate SNES header\n", coro->gameid);
coro->gameid = 0;
CORO_RET();
}
@ -1474,41 +1502,12 @@ found:
CORO_GOTO(RCHEEVOS_GET_GAMEID);
/**************************************************************************
* Info Tries to identify a Genesis game
* Input CHEEVOS_VAR_INFO the content info
* Output CHEEVOS_VAR_GAMEID the Retro Achievements game ID, or 0 if not found
*************************************************************************/
CORO_SUB(RCHEEVOS_GENESIS_MD5)
MD5_Init(&coro->md5);
coro->offset = 0;
coro->count = 0;
CORO_GOSUB(RCHEEVOS_EVAL_MD5);
if (coro->count == 0)
{
MD5_Final(coro->hash, &coro->md5);
coro->gameid = 0;
CORO_RET();
}
if (coro->count < CHEEVOS_MB(6))
{
coro->offset = 0;
coro->count = CHEEVOS_MB(6) - coro->count;
CORO_GOSUB(RCHEEVOS_FILL_MD5);
}
MD5_Final(coro->hash, &coro->md5);
CORO_GOTO(RCHEEVOS_GET_GAMEID);
/**************************************************************************
* Info Tries to identify an Atari Lynx game
* Input CHEEVOS_VAR_INFO the content info
* Output CHEEVOS_VAR_GAMEID the Retro Achievements game ID, or 0 if not found
*************************************************************************/
/**************************************************************************
* Info Tries to identify an Atari Lynx game
* Input CHEEVOS_VAR_INFO the content info
* Output CHEEVOS_VAR_GAMEID the Retro Achievements game ID, or 0 if not found
*************************************************************************/
CORO_SUB(RCHEEVOS_LYNX_MD5)
/* Checks for the existence of a headered Lynx file.
@ -1516,6 +1515,7 @@ found:
if (coro->len <= (unsigned)lynx_header_len ||
memcmp("LYNX", (void *)coro->data, 5) != 0)
{
CHEEVOS_LOG(RCHEEVOS_TAG "could not locate LYNX header\n", coro->gameid);
coro->gameid = 0;
CORO_RET();
}
@ -1528,11 +1528,12 @@ found:
MD5_Final(coro->hash, &coro->md5);
CORO_GOTO(RCHEEVOS_GET_GAMEID);
/**************************************************************************
* Info Tries to identify a NES game
* Input CHEEVOS_VAR_INFO the content info
* Output CHEEVOS_VAR_GAMEID the Retro Achievements game ID, or 0 if not found
*************************************************************************/
/**************************************************************************
* Info Tries to identify a NES game
* Input CHEEVOS_VAR_INFO the content info
* Output CHEEVOS_VAR_GAMEID the Retro Achievements game ID, or 0 if not found
*************************************************************************/
CORO_SUB(RCHEEVOS_NES_MD5)
/* Checks for the existence of a headered NES file.
@ -1552,6 +1553,7 @@ found:
|| coro->header.id[3] != 0x1a)
{
coro->gameid = 0;
CHEEVOS_LOG(RCHEEVOS_TAG "could not locate NES header\n", coro->gameid);
CORO_RET();
}
@ -1564,6 +1566,57 @@ found:
CORO_GOTO(RCHEEVOS_GET_GAMEID);
/**************************************************************************
* Info Tries to identify a Sega CD game
* Input CHEEVOS_VAR_INFO the content info
* Output CHEEVOS_VAR_GAMEID the Retro Achievements game ID, or 0 if not found
*************************************************************************/
CORO_SUB(RCHEEVOS_SEGACD_MD5)
{
/* ignore bin files less than 16MB - they're probably a ROM, not a CD */
if (coro->ext_hash == 0x0b8861beU && coro->len < CHEEVOS_MB(16))
{
CHEEVOS_LOG(RCHEEVOS_TAG "ignoring small BIN file - assuming not CD\n", coro->gameid);
coro->gameid = 0;
CORO_RET();
}
MD5_Init(&coro->md5);
/* find the data track - it should be the first one */
coro->stream = cdfs_open_data_track(coro->path);
if (coro->stream)
{
/* open the raw CD */
if (cdfs_open_file(&coro->cdfp, coro->stream, NULL))
{
coro->count = 512;
free(coro->data);
coro->data = (uint8_t*)malloc(coro->count);
cdfs_read_file(&coro->cdfp, coro->data, coro->count);
coro->len = coro->count;
CORO_GOSUB(RCHEEVOS_EVAL_MD5);
MD5_Final(coro->hash, &coro->md5);
cdfs_close_file(&coro->cdfp);
intfstream_close(coro->stream);
CHEEVOS_FREE(coro->stream);
CORO_GOTO(RCHEEVOS_GET_GAMEID);
}
intfstream_close(coro->stream);
CHEEVOS_FREE(coro->stream);
}
CHEEVOS_LOG(RCHEEVOS_TAG "could not open CD\n", coro->gameid);
coro->gameid = 0;
CORO_RET();
}
/**************************************************************************
* Info Tries to identify a Playstation game
* Input CHEEVOS_VAR_INFO the content info
@ -1706,20 +1759,26 @@ found:
}
}
CHEEVOS_LOG(RCHEEVOS_TAG "could not locate primary executable\n", coro->gameid);
intfstream_close(coro->stream);
CHEEVOS_FREE(coro->stream);
}
else
{
CHEEVOS_LOG(RCHEEVOS_TAG "could not open CD\n", coro->gameid);
}
coro->gameid = 0;
CORO_RET();
}
/**************************************************************************
* Info Tries to identify a "generic" game
* Input CHEEVOS_VAR_INFO the content info
* Output CHEEVOS_VAR_GAMEID the Retro Achievements game ID, or 0 if not found
*************************************************************************/
/**************************************************************************
* Info Tries to identify a game by examining the entire file (no special processing)
* Input CHEEVOS_VAR_INFO the content info
* Output CHEEVOS_VAR_GAMEID the Retro Achievements game ID, or 0 if not found
*************************************************************************/
CORO_SUB(RCHEEVOS_GENERIC_MD5)
MD5_Init(&coro->md5);
@ -1735,12 +1794,14 @@ found:
CORO_GOTO(RCHEEVOS_GET_GAMEID);
/**************************************************************************
* Info Tries to identify a game based on its filename (with no extension)
* Input CHEEVOS_VAR_INFO the content info
* Output CHEEVOS_VAR_GAMEID the Retro Achievements game ID, or 0 if not found
*************************************************************************/
CORO_SUB(RCHEEVOS_FILENAME_MD5)
/**************************************************************************
* Info Tries to identify an arcade game based on its filename (with no extension).
* An arcade game "rom" is a zip file containing many ROMs.
* Input CHEEVOS_VAR_INFO the content info
* Output CHEEVOS_VAR_GAMEID the Retro Achievements game ID, or 0 if not found
*************************************************************************/
CORO_SUB(RCHEEVOS_ARCADE_MD5)
if (!string_is_empty(coro->path))
{
char base_noext[PATH_MAX_LENGTH];
@ -1754,11 +1815,12 @@ found:
}
CORO_RET();
/**************************************************************************
* Info Evaluates the CHEEVOS_VAR_MD5 hash
* Inputs CHEEVOS_VAR_INFO, CHEEVOS_VAR_OFFSET, CHEEVOS_VAR_COUNT
* Outputs CHEEVOS_VAR_MD5, CHEEVOS_VAR_COUNT
*************************************************************************/
/**************************************************************************
* Info Evaluates the CHEEVOS_VAR_MD5 hash
* Inputs CHEEVOS_VAR_INFO, CHEEVOS_VAR_OFFSET, CHEEVOS_VAR_COUNT
* Outputs CHEEVOS_VAR_MD5, CHEEVOS_VAR_COUNT
*************************************************************************/
CORO_SUB(RCHEEVOS_EVAL_MD5)
if (coro->count == 0)
@ -1776,40 +1838,24 @@ found:
coro->count);
CORO_RET();
/**************************************************************************
* Info Updates the CHEEVOS_VAR_MD5 hash with a repeated value
* Inputs CHEEVOS_VAR_OFFSET, CHEEVOS_VAR_COUNT
* Outputs CHEEVOS_VAR_MD5
*************************************************************************/
CORO_SUB(RCHEEVOS_FILL_MD5)
{
char buffer[4096];
while (coro->count > 0)
{
size_t len = sizeof(buffer);
if (len > coro->count)
len = coro->count;
memset((void*)buffer, coro->offset, len);
MD5_Update(&coro->md5, (void*)buffer, len);
coro->count -= len;
}
}
CORO_RET();
/**************************************************************************
* Info Gets the achievements from Retro Achievements
* Inputs coro->hash
* Outputs CHEEVOS_VAR_GAMEID
*************************************************************************/
/**************************************************************************
* Info Gets the achievements from Retro Achievements
* Inputs coro->hash
* Outputs CHEEVOS_VAR_GAMEID
*************************************************************************/
CORO_SUB(RCHEEVOS_GET_GAMEID)
{
int size;
if (memcmp(coro->last_hash, coro->hash, sizeof(coro->hash)) == 0)
{
CHEEVOS_LOG(RCHEEVOS_TAG "hash did not change, returning %u\n", coro->gameid);
CORO_RET();
}
memcpy(coro->last_hash, coro->hash, sizeof(coro->hash));
size = rc_url_get_gameid(coro->url, sizeof(coro->url), coro->hash);
if (size < 0)
@ -1818,6 +1864,11 @@ found:
CORO_RET();
}
CHEEVOS_LOG(RCHEEVOS_TAG "checking %02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x\n",
coro->hash[0], coro->hash[1], coro->hash[2], coro->hash[3],
coro->hash[4], coro->hash[5], coro->hash[6], coro->hash[7],
coro->hash[8], coro->hash[9], coro->hash[10], coro->hash[11],
coro->hash[12], coro->hash[13], coro->hash[14], coro->hash[15]);
rcheevos_log_url(RCHEEVOS_TAG "rc_url_get_gameid: %s\n", coro->url);
CORO_GOSUB(RCHEEVOS_HTTP_GET);
@ -1831,11 +1882,12 @@ found:
CORO_RET();
}
/**************************************************************************
* Info Gets the achievements from Retro Achievements
* Inputs CHEEVOS_VAR_GAMEID
* Outputs CHEEVOS_VAR_JSON
*************************************************************************/
/**************************************************************************
* Info Gets the achievements from Retro Achievements
* Inputs CHEEVOS_VAR_GAMEID
* Outputs CHEEVOS_VAR_JSON
*************************************************************************/
CORO_SUB(RCHEEVOS_GET_CHEEVOS)
{
int ret;
@ -1863,11 +1915,12 @@ found:
CORO_RET();
}
/**************************************************************************
* Info Gets the achievements from Retro Achievements
* Inputs CHEEVOS_VAR_GAMEID
* Outputs CHEEVOS_VAR_JSON
*************************************************************************/
/**************************************************************************
* Info Gets the achievements from Retro Achievements
* Inputs CHEEVOS_VAR_GAMEID
* Outputs CHEEVOS_VAR_JSON
*************************************************************************/
CORO_SUB(RCHEEVOS_GET_BADGES)
badges_ctx = new_badges_ctx;
@ -1958,9 +2011,10 @@ found:
CORO_RET();
/**************************************************************************
* Info Logs in the user at Retro Achievements
*************************************************************************/
/**************************************************************************
* Info Logs in the user at Retro Achievements
*************************************************************************/
CORO_SUB(RCHEEVOS_LOGIN)
{
const char* username;
@ -2050,9 +2104,10 @@ found:
CORO_RET();
}
/**************************************************************************
* Info Pauses execution for five seconds
*************************************************************************/
/**************************************************************************
* Info Pauses execution for five seconds
*************************************************************************/
CORO_SUB(RCHEEVOS_DELAY)
{
@ -2068,11 +2123,12 @@ found:
CORO_RET();
/**************************************************************************
* Info Makes a HTTP GET request
* Inputs CHEEVOS_VAR_URL
* Outputs CHEEVOS_VAR_JSON
*************************************************************************/
/**************************************************************************
* Info Makes a HTTP GET request
* Inputs CHEEVOS_VAR_URL
* Outputs CHEEVOS_VAR_JSON
*************************************************************************/
CORO_SUB(RCHEEVOS_HTTP_GET)
for (coro->k = 0; coro->k < 5; coro->k++)
@ -2143,11 +2199,12 @@ found:
CHEEVOS_LOG(RCHEEVOS_TAG "Couldn't connect to server after 5 tries\n");
CORO_RET();
/**************************************************************************
* Info Deactivates the achievements already awarded
* Inputs CHEEVOS_VAR_GAMEID
* Outputs
*************************************************************************/
/**************************************************************************
* Info Deactivates the achievements already awarded
* Inputs CHEEVOS_VAR_GAMEID
* Outputs
*************************************************************************/
CORO_SUB(RCHEEVOS_DEACTIVATE)
CORO_GOSUB(RCHEEVOS_LOGIN);
@ -2155,6 +2212,7 @@ found:
int ret;
unsigned mode;
/* Two calls - one for softcore and one for hardcore */
for (coro->i = 0; coro->i < 2; coro->i++)
{
ret = rc_url_get_unlock_list(coro->url, sizeof(coro->url), coro->settings->arrays.cheevos_username, rcheevos_locals.token, coro->gameid, coro->i);
@ -2181,11 +2239,12 @@ found:
CORO_RET();
/**************************************************************************
* Info Posts the "playing" activity to Retro Achievements
* Inputs CHEEVOS_VAR_GAMEID
* Outputs
*************************************************************************/
/**************************************************************************
* Info Posts the "playing" activity to Retro Achievements
* Inputs CHEEVOS_VAR_GAMEID
* Outputs
*************************************************************************/
CORO_SUB(RCHEEVOS_PLAYING)
snprintf(
@ -2208,7 +2267,6 @@ found:
else
CHEEVOS_ERR(RCHEEVOS_TAG "error posting playing activity\n");
CHEEVOS_LOG(RCHEEVOS_TAG "posted playing activity\n");
CORO_RET();
CORO_LEAVE();
@ -2248,7 +2306,8 @@ bool rcheevos_load(const void *data)
{
retro_task_t *task;
const struct retro_game_info *info = NULL;
rcheevos_coro_t *coro = NULL;
rcheevos_coro_t *coro = NULL;
char buffer[32];
rcheevos_loaded = false;
rcheevos_hardcore_paused = false;
@ -2299,6 +2358,12 @@ bool rcheevos_load(const void *data)
coro->path = strdup(info->path);
}
strncpy(buffer, path_get_extension(info->path), sizeof(buffer));
buffer[sizeof(buffer) - 1] = '\0';
string_to_lower(buffer);
coro->ext_hash = rcheevos_djb2(buffer, strlen(buffer));
CHEEVOS_LOG(RCHEEVOS_TAG "ext_hash %08x ('%s')\n", coro->ext_hash, buffer);
task->handler = rcheevos_task_handler;
task->state = (void*)coro;
task->mute = true;

View File

@ -151,7 +151,7 @@ static int cdfs_find_file(cdfs_file_t* file, const char* path)
int cdfs_open_file(cdfs_file_t* file, intfstream_t* stream, const char* path)
{
if (!file || !stream || !path)
if (!file || !stream)
return 0;
memset(file, 0, sizeof(*file));
@ -160,16 +160,28 @@ int cdfs_open_file(cdfs_file_t* file, intfstream_t* stream, const char* path)
cdfs_determine_sector_size(file);
file->current_sector = -1;
file->first_sector = cdfs_find_file(file, path);
if (path != NULL)
{
file->first_sector = cdfs_find_file(file, path);
}
else if (file->stream_sector_size)
{
file->first_sector = 0;
file->size = (intfstream_get_size(file->stream) / file->stream_sector_size) * 2048;
}
else
{
file->first_sector = -1;
}
return (file->first_sector > 0);
return (file->first_sector >= 0);
}
int64_t cdfs_read_file(cdfs_file_t* file, void* buffer, uint64_t len)
{
int bytes_read = 0;
if (!file || !file->first_sector || !buffer)
if (!file || file->first_sector < 0 || !buffer)
return 0;
if (len > file->size - file->pos)
@ -240,13 +252,13 @@ void cdfs_close_file(cdfs_file_t* file)
if (file)
{
/* not really anything to do here, just clear out the first_sector so read() won't do anything */
file->first_sector = 0;
file->first_sector = -1;
}
}
int64_t cdfs_get_size(cdfs_file_t* file)
{
if (!file || !file->first_sector)
if (!file || file->first_sector < 0)
return 0;
return file->size;
@ -254,7 +266,7 @@ int64_t cdfs_get_size(cdfs_file_t* file)
int64_t cdfs_tell(cdfs_file_t* file)
{
if (!file || !file->first_sector)
if (!file || file->first_sector < 0)
return -1;
return file->pos;
@ -265,7 +277,7 @@ int64_t cdfs_seek(cdfs_file_t* file, int64_t offset, int whence)
int64_t new_pos;
int new_sector;
if (!file || !file->first_sector)
if (!file || file->first_sector < 0)
return -1;
switch (whence)
@ -459,8 +471,8 @@ intfstream_t* cdfs_open_data_track(const char* path)
return intfstream_open_chd_track(path, RETRO_VFS_FILE_ACCESS_READ, RETRO_VFS_FILE_ACCESS_HINT_NONE, 1);
}
/* unsupported file type */
return NULL;
/* unsupported file type - try opening as a raw track */
return cdfs_open_raw_track(path);
}
intfstream_t* cdfs_open_raw_track(const char* path)

View File

@ -45,6 +45,10 @@ typedef struct cdfs_file_t
uint8_t sector_buffer[2048];
} cdfs_file_t;
/* opens the specified file within the CD or virtual CD.
* if path is NULL, will open the raw CD (useful for reading CD without having to worry about sector sizes,
* headers, or checksum data)
*/
int cdfs_open_file(cdfs_file_t* file, intfstream_t* stream, const char* path);
void cdfs_close_file(cdfs_file_t* file);