mirror of
https://github.com/libretro/RetroArch
synced 2025-02-19 12:41:00 +00:00
(retrolaunch) cleanups
This commit is contained in:
parent
7ff8db3f69
commit
dd72443211
@ -15,7 +15,8 @@
|
||||
|
||||
#define MAGIC_LEN 16
|
||||
|
||||
struct MagicEntry {
|
||||
struct MagicEntry
|
||||
{
|
||||
const char* system_name;
|
||||
const char* magic;
|
||||
};
|
||||
@ -28,7 +29,8 @@ static struct MagicEntry MAGIC_NUMBERS[] = {
|
||||
};
|
||||
|
||||
static int find_first_data_track(const char* cue_path, int32_t* offset,
|
||||
char* track_path, size_t max_len) {
|
||||
char* track_path, size_t max_len)
|
||||
{
|
||||
int rv;
|
||||
int fd = -1;
|
||||
char tmp_token[MAX_TOKEN_LEN];
|
||||
@ -38,7 +40,8 @@ static int find_first_data_track(const char* cue_path, int32_t* offset,
|
||||
path_basedir(cue_dir);
|
||||
|
||||
fd = open(cue_path, O_RDONLY);
|
||||
if (fd < 0) {
|
||||
if (fd < 0)
|
||||
{
|
||||
LOG_WARN("Could not open CUE file '%s': %s", cue_path,
|
||||
strerror(errno));
|
||||
return -errno;
|
||||
@ -46,22 +49,26 @@ static int find_first_data_track(const char* cue_path, int32_t* offset,
|
||||
|
||||
LOG_DEBUG("Parsing CUE file '%s'...", cue_path);
|
||||
|
||||
while (get_token(fd, tmp_token, MAX_TOKEN_LEN) > 0) {
|
||||
if (strcmp(tmp_token, "FILE") == 0) {
|
||||
while (get_token(fd, tmp_token, MAX_TOKEN_LEN) > 0)
|
||||
{
|
||||
if (strcmp(tmp_token, "FILE") == 0)
|
||||
{
|
||||
get_token(fd, tmp_token, MAX_TOKEN_LEN);
|
||||
fill_pathname_join(track_path, cue_dir, tmp_token, max_len);
|
||||
|
||||
} else if (strcasecmp(tmp_token, "TRACK") == 0) {
|
||||
get_token(fd, tmp_token, MAX_TOKEN_LEN);
|
||||
get_token(fd, tmp_token, MAX_TOKEN_LEN);
|
||||
if (strcasecmp(tmp_token, "AUDIO") == 0) {
|
||||
continue;
|
||||
}
|
||||
else if (strcasecmp(tmp_token, "TRACK") == 0)
|
||||
{
|
||||
get_token(fd, tmp_token, MAX_TOKEN_LEN);
|
||||
get_token(fd, tmp_token, MAX_TOKEN_LEN);
|
||||
if (strcasecmp(tmp_token, "AUDIO") == 0)
|
||||
continue;
|
||||
|
||||
find_token(fd, "INDEX");
|
||||
get_token(fd, tmp_token, MAX_TOKEN_LEN);
|
||||
get_token(fd, tmp_token, MAX_TOKEN_LEN);
|
||||
if (sscanf(tmp_token, "%02d:%02d:%02d", &m, &s, &f) < 3) {
|
||||
if (sscanf(tmp_token, "%02d:%02d:%02d", &m, &s, &f) < 3)
|
||||
{
|
||||
LOG_WARN("Error parsing time stamp '%s'", tmp_token);
|
||||
return -errno;
|
||||
}
|
||||
@ -83,25 +90,27 @@ clean:
|
||||
}
|
||||
|
||||
static int find_ps1_canonical_name(const char* game_id, char* game_name,
|
||||
size_t max_len) {
|
||||
int fd;
|
||||
size_t max_len)
|
||||
{
|
||||
char tmp_token[MAX_TOKEN_LEN];
|
||||
int rv = 0;
|
||||
fd = open("cddb/ps1.idlst", O_RDONLY);
|
||||
if (fd < 0) {
|
||||
int fd = open("cddb/ps1.idlst", O_RDONLY);
|
||||
if (fd < 0)
|
||||
{
|
||||
LOG_WARN("Could not open id list: %s", strerror(errno));
|
||||
return -errno;
|
||||
}
|
||||
|
||||
while (get_token(fd, tmp_token, MAX_TOKEN_LEN) > 0) {
|
||||
if(strcasecmp(tmp_token, game_id) != 0) {
|
||||
while (get_token(fd, tmp_token, MAX_TOKEN_LEN) > 0)
|
||||
{
|
||||
if(strcasecmp(tmp_token, game_id) != 0)
|
||||
{
|
||||
get_token(fd, tmp_token, max_len);
|
||||
continue;
|
||||
}
|
||||
|
||||
if ((rv = get_token(fd, game_name, max_len)) < 0) {
|
||||
if ((rv = get_token(fd, game_name, max_len)) < 0)
|
||||
goto clean;
|
||||
}
|
||||
|
||||
rv = 0;
|
||||
goto clean;
|
||||
@ -114,7 +123,8 @@ clean:
|
||||
}
|
||||
|
||||
static int detect_ps1_game(const char* track_path, int32_t offset,
|
||||
char* game_name, size_t max_len) {
|
||||
char* game_name, size_t max_len)
|
||||
{
|
||||
int rv;
|
||||
char buff[4096];
|
||||
const char* pattern = "cdrom:";
|
||||
@ -124,51 +134,59 @@ static int detect_ps1_game(const char* track_path, int32_t offset,
|
||||
int i;
|
||||
|
||||
int fd = open(track_path, O_RDONLY);
|
||||
if (fd < 0) {
|
||||
if (fd < 0)
|
||||
{
|
||||
LOG_DEBUG("Could not open data track: %s", strerror(errno));
|
||||
return -errno;
|
||||
}
|
||||
|
||||
lseek(fd, 0x9340, SEEK_SET);
|
||||
if (read(fd, buff, 10) > 0) {
|
||||
if (read(fd, buff, 10) > 0)
|
||||
{
|
||||
buff[10] = '\0';
|
||||
buff[4] = '-';
|
||||
LOG_DEBUG("Found disk label '%s'", buff);
|
||||
rv = find_ps1_canonical_name(buff, game_name, max_len);
|
||||
if (rv == 0) {
|
||||
if (rv == 0)
|
||||
goto clean;
|
||||
}
|
||||
}
|
||||
|
||||
memset(buff, 0, sizeof(buff));
|
||||
pat_c = pattern;
|
||||
while (1) {
|
||||
|
||||
while (1)
|
||||
{
|
||||
rv = read(fd, buff, 4096);
|
||||
if (rv < 0) {
|
||||
if (rv < 0)
|
||||
{
|
||||
rv = -errno;
|
||||
goto clean;
|
||||
}
|
||||
|
||||
for (i = 0; i < rv; i++) {
|
||||
if (*pat_c == buff[i]) {
|
||||
for (i = 0; i < rv; i++)
|
||||
{
|
||||
if (*pat_c == buff[i])
|
||||
pat_c++;
|
||||
} else {
|
||||
else
|
||||
{
|
||||
pat_c = pattern;
|
||||
continue;
|
||||
}
|
||||
|
||||
if (*pat_c == '\0') {
|
||||
if (*pat_c == '\0')
|
||||
{
|
||||
id_start = &buff[i] + 1;
|
||||
c = strchr(id_start, ';');
|
||||
if (!c) {
|
||||
if (!c)
|
||||
{
|
||||
LOG_DEBUG("Invalid pattern in buffer.");
|
||||
rv = -EINVAL;
|
||||
goto clean;
|
||||
}
|
||||
*c = '\0';
|
||||
c = strrchr(id_start, '\\');
|
||||
if (c != NULL) {
|
||||
if (c != NULL)
|
||||
id_start = c + 1;
|
||||
}
|
||||
id_start[4] = '-';
|
||||
id_start[8] = id_start[9];
|
||||
id_start[9] = id_start[10];
|
||||
@ -186,7 +204,8 @@ clean:
|
||||
}
|
||||
|
||||
static int detect_system(const char* track_path, int32_t offset,
|
||||
const char** system_name) {
|
||||
const char** system_name)
|
||||
{
|
||||
int rv;
|
||||
char magic[MAGIC_LEN];
|
||||
int fd;
|
||||
@ -194,7 +213,8 @@ static int detect_system(const char* track_path, int32_t offset,
|
||||
int i;
|
||||
|
||||
fd = open(track_path, O_RDONLY);
|
||||
if (fd < 0) {
|
||||
if (fd < 0)
|
||||
{
|
||||
LOG_WARN("Could not open data track of file '%s': %s",
|
||||
track_path, strerror(errno));
|
||||
rv = -errno;
|
||||
@ -202,7 +222,8 @@ static int detect_system(const char* track_path, int32_t offset,
|
||||
}
|
||||
|
||||
lseek(fd, offset, SEEK_SET);
|
||||
if (read(fd, magic, MAGIC_LEN) < MAGIC_LEN) {
|
||||
if (read(fd, magic, MAGIC_LEN) < MAGIC_LEN)
|
||||
{
|
||||
LOG_WARN("Could not read data from file '%s' at offset %d: %s",
|
||||
track_path, offset, strerror(errno));
|
||||
rv = -errno;
|
||||
@ -210,8 +231,10 @@ static int detect_system(const char* track_path, int32_t offset,
|
||||
}
|
||||
|
||||
LOG_DEBUG("Comparing with known magic numbers...");
|
||||
for (i = 0; MAGIC_NUMBERS[i].system_name != NULL; i++) {
|
||||
if (memcmp(MAGIC_NUMBERS[i].magic, magic, MAGIC_LEN) == 0) {
|
||||
for (i = 0; MAGIC_NUMBERS[i].system_name != NULL; i++)
|
||||
{
|
||||
if (memcmp(MAGIC_NUMBERS[i].magic, magic, MAGIC_LEN) == 0)
|
||||
{
|
||||
*system_name = MAGIC_NUMBERS[i].system_name;
|
||||
rv = 0;
|
||||
goto clean;
|
||||
@ -225,13 +248,15 @@ clean:
|
||||
return rv;
|
||||
}
|
||||
|
||||
int find_first_cue(const char* m3u_path, char* cue_path, size_t max_len) {
|
||||
int find_first_cue(const char* m3u_path, char* cue_path, size_t max_len)
|
||||
{
|
||||
char c;
|
||||
int skip = 0;
|
||||
int midstream = 0;
|
||||
|
||||
int fd = open(m3u_path, O_RDONLY);
|
||||
if (fd < 0) {
|
||||
if (fd < 0)
|
||||
{
|
||||
LOG_WARN("Could not open m3u '%s': %s", m3u_path, strerror(errno));
|
||||
return -errno;
|
||||
}
|
||||
@ -242,28 +267,30 @@ int find_first_cue(const char* m3u_path, char* cue_path, size_t max_len) {
|
||||
cue_path[0] = '/';
|
||||
cue_path++;
|
||||
|
||||
while ((read(fd, &c, 1) > 0)) {
|
||||
switch (c) {
|
||||
while ((read(fd, &c, 1) > 0))
|
||||
{
|
||||
switch (c)
|
||||
{
|
||||
case '#':
|
||||
if (!midstream) {
|
||||
if (!midstream)
|
||||
skip = 1;
|
||||
}
|
||||
break;
|
||||
case '\n':
|
||||
if (skip) {
|
||||
if (skip)
|
||||
skip = 0;
|
||||
} else if(midstream) {
|
||||
else if(midstream)
|
||||
{
|
||||
cue_path[0] = '\0';
|
||||
close(fd);
|
||||
return 0;
|
||||
}
|
||||
break;
|
||||
case ' ':
|
||||
if (!midstream) {
|
||||
if (!midstream)
|
||||
break;
|
||||
}
|
||||
default:
|
||||
if (!skip) {
|
||||
if (!skip)
|
||||
{
|
||||
midstream = 1;
|
||||
cue_path[0] = c;
|
||||
cue_path++;
|
||||
@ -275,46 +302,48 @@ int find_first_cue(const char* m3u_path, char* cue_path, size_t max_len) {
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
int detect_cd_game(const char* target_path, char* game_name, size_t max_len) {
|
||||
int detect_cd_game(const char* target_path, char* game_name, size_t max_len)
|
||||
{
|
||||
char cue_path[PATH_MAX];
|
||||
char track_path[PATH_MAX];
|
||||
int32_t offset = 0;
|
||||
const char* system_name = NULL;
|
||||
int rv;
|
||||
if (strcasecmp(target_path + strlen(target_path) - 4, ".m3u") == 0) {
|
||||
if (strcasecmp(target_path + strlen(target_path) - 4, ".m3u") == 0)
|
||||
{
|
||||
rv = find_first_cue(target_path, cue_path, PATH_MAX);
|
||||
if (rv < 0) {
|
||||
if (rv < 0)
|
||||
{
|
||||
LOG_WARN("Could not parse m3u: %s", strerror(-rv));
|
||||
return rv;
|
||||
}
|
||||
|
||||
} else {
|
||||
strncpy(cue_path, target_path, max_len);
|
||||
}
|
||||
else
|
||||
strncpy(cue_path, target_path, max_len);
|
||||
|
||||
rv = find_first_data_track(cue_path, &offset, track_path, PATH_MAX);
|
||||
if (rv < 0) {
|
||||
if (rv < 0)
|
||||
{
|
||||
LOG_WARN("Could not find valid data track: %s", strerror(-rv));
|
||||
return rv;
|
||||
}
|
||||
|
||||
LOG_DEBUG("Reading 1st data track...");
|
||||
|
||||
if ((rv = detect_system(track_path, offset, &system_name)) < 0) {
|
||||
if ((rv = detect_system(track_path, offset, &system_name)) < 0)
|
||||
return rv;
|
||||
}
|
||||
|
||||
|
||||
LOG_DEBUG("Detected %s media", system_name);
|
||||
|
||||
snprintf(game_name, max_len, "%s.", system_name);
|
||||
game_name += strlen(system_name) + 1;
|
||||
max_len -= strlen(system_name) + 1;
|
||||
if (strcmp(system_name, "ps1") == 0) {
|
||||
if (detect_ps1_game(track_path, offset, game_name, max_len) == 0) {
|
||||
if (strcmp(system_name, "ps1") == 0)
|
||||
{
|
||||
if (detect_ps1_game(track_path, offset, game_name, max_len) == 0)
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
snprintf(game_name, max_len, "<unknown>");
|
||||
return 0;
|
||||
|
@ -26,69 +26,59 @@
|
||||
static int find_hash(int fd, const char *hash, char *game_name, size_t max_len)
|
||||
{
|
||||
char token[MAX_TOKEN_LEN] = {0};
|
||||
while (1) {
|
||||
if (find_token(fd, "game") < 0) {
|
||||
while (1)
|
||||
{
|
||||
if (find_token(fd, "game") < 0)
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (find_token(fd, "name") < 0) {
|
||||
if (find_token(fd, "name") < 0)
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (get_token(fd, game_name, max_len) < 0) {
|
||||
if (get_token(fd, game_name, max_len) < 0)
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (find_token(fd, "sha1") < 0) {
|
||||
if (find_token(fd, "sha1") < 0)
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (get_token(fd, token, MAX_TOKEN_LEN) < 0) {
|
||||
if (get_token(fd, token, MAX_TOKEN_LEN) < 0)
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (strcasecmp(hash, token) == 0) {
|
||||
if (strcasecmp(hash, token) == 0)
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static int
|
||||
find_rom_canonical_name(const char *hash, char *game_name, size_t max_len)
|
||||
{
|
||||
// TODO: Error handling
|
||||
size_t i;
|
||||
int rv;
|
||||
int fd;
|
||||
int offs;
|
||||
int rv, fd, offs;
|
||||
char *dat_path;
|
||||
const char *dat_name;
|
||||
const char *dat_name_dot;
|
||||
struct string_list *files;
|
||||
const char *dat_name, *dat_name_dot;
|
||||
struct string_list *files = dir_list_new("db", "dat", false);
|
||||
|
||||
files = dir_list_new("db", "dat", false);
|
||||
if (!files) {
|
||||
if (!files)
|
||||
return -1;
|
||||
}
|
||||
|
||||
for (i = 0; i < files->size; i++) {
|
||||
for (i = 0; i < files->size; i++)
|
||||
{
|
||||
dat_path = files->elems[i].data;
|
||||
dat_name = path_basename(dat_path);
|
||||
|
||||
dat_name_dot = strchr(dat_name, '.');
|
||||
if (!dat_name_dot) {
|
||||
if (!dat_name_dot)
|
||||
continue;
|
||||
}
|
||||
|
||||
offs = dat_name_dot - dat_name + 1;
|
||||
memcpy(game_name, dat_name, offs);
|
||||
|
||||
fd = open(dat_path, O_RDONLY);
|
||||
if (fd < 0) {
|
||||
if (fd < 0)
|
||||
continue;
|
||||
}
|
||||
|
||||
if (find_hash(fd, hash, game_name + offs, max_len - offs) == 0) {
|
||||
if (find_hash(fd, hash, game_name + offs, max_len - offs) == 0)
|
||||
{
|
||||
rv = 0;
|
||||
close(fd);
|
||||
goto clean;
|
||||
@ -109,15 +99,16 @@ static int get_sha1(const char *path, char *result)
|
||||
SHA1Context sha;
|
||||
|
||||
fd = open(path, O_RDONLY);
|
||||
if (fd < 0) {
|
||||
if (fd < 0)
|
||||
return -errno;
|
||||
}
|
||||
|
||||
SHA1Reset(&sha);
|
||||
rv = 1;
|
||||
while (rv > 0) {
|
||||
while (rv > 0)
|
||||
{
|
||||
rv = read(fd, buff, 4096);
|
||||
if (rv < 0) {
|
||||
if (rv < 0)
|
||||
{
|
||||
close(fd);
|
||||
return -errno;
|
||||
}
|
||||
@ -125,7 +116,8 @@ static int get_sha1(const char *path, char *result)
|
||||
SHA1Input(&sha, buff, rv);
|
||||
}
|
||||
|
||||
if (!SHA1Result(&sha)) {
|
||||
if (!SHA1Result(&sha))
|
||||
{
|
||||
close(fd);
|
||||
return -1;
|
||||
}
|
||||
@ -139,7 +131,8 @@ static int get_sha1(const char *path, char *result)
|
||||
return 0;
|
||||
}
|
||||
|
||||
struct RunInfo {
|
||||
struct RunInfo
|
||||
{
|
||||
char broken_cores[PATH_MAX];
|
||||
int multitap;
|
||||
int dualanalog;
|
||||
@ -152,19 +145,18 @@ static int read_launch_conf(struct RunInfo *info, const char *game_name)
|
||||
int rv;
|
||||
int bci = 0;
|
||||
char token[MAX_TOKEN_LEN];
|
||||
if (fd < 0) {
|
||||
if (fd < 0)
|
||||
return -errno;
|
||||
}
|
||||
|
||||
while (1) {
|
||||
if ((rv = get_token(fd, token, MAX_TOKEN_LEN)) < 0) {
|
||||
while (1)
|
||||
{
|
||||
if ((rv = get_token(fd, token, MAX_TOKEN_LEN)) < 0)
|
||||
goto clean;
|
||||
}
|
||||
|
||||
if (rl_fnmatch(token, game_name, 0) != 0) {
|
||||
if ((rv = find_token(fd, ";")) < 0) {
|
||||
if (rl_fnmatch(token, game_name, 0) != 0)
|
||||
{
|
||||
if ((rv = find_token(fd, ";")) < 0)
|
||||
goto clean;
|
||||
}
|
||||
continue;
|
||||
}
|
||||
|
||||
@ -172,39 +164,40 @@ static int read_launch_conf(struct RunInfo *info, const char *game_name)
|
||||
break;
|
||||
}
|
||||
|
||||
if ((rv = get_token(fd, token, MAX_TOKEN_LEN)) < 0) {
|
||||
if ((rv = get_token(fd, token, MAX_TOKEN_LEN)) < 0)
|
||||
goto clean;
|
||||
}
|
||||
|
||||
while (strcmp(token, ";") != 0) {
|
||||
if (strcmp(token, "multitap") == 0) {
|
||||
while (strcmp(token, ";") != 0)
|
||||
{
|
||||
if (strcmp(token, "multitap") == 0)
|
||||
info->multitap = 1;
|
||||
} else if (strcmp(token, "dualanalog") == 0) {
|
||||
else if (strcmp(token, "dualanalog") == 0)
|
||||
info->dualanalog = 1;
|
||||
} else if (token[0] == '!') {
|
||||
else if (token[0] == '!')
|
||||
{
|
||||
strncpy(&info->broken_cores[bci], &token[1], PATH_MAX - bci);
|
||||
bci += strnlen(&token[1], PATH_MAX) + 1;
|
||||
}
|
||||
|
||||
if ((rv = get_token(fd, token, MAX_TOKEN_LEN)) < 0) {
|
||||
if ((rv = get_token(fd, token, MAX_TOKEN_LEN)) < 0)
|
||||
goto clean;
|
||||
}
|
||||
|
||||
}
|
||||
rv = 0;
|
||||
clean:
|
||||
close(fd);
|
||||
return rv;
|
||||
}
|
||||
|
||||
static int get_run_info(struct RunInfo *info, const char *game_name) {
|
||||
memset(info, 0, sizeof(struct RunInfo));
|
||||
static int get_run_info(struct RunInfo *info, const char *game_name)
|
||||
{
|
||||
int i;
|
||||
|
||||
for (i = 0; i < 9; i++) {
|
||||
if (game_name[i] == '.') {
|
||||
memset(info, 0, sizeof(struct RunInfo));
|
||||
|
||||
for (i = 0; i < 9; i++)
|
||||
{
|
||||
if (game_name[i] == '.')
|
||||
break;
|
||||
}
|
||||
info->system[i] = game_name[i];
|
||||
}
|
||||
info->system[i] = '\0';
|
||||
@ -240,27 +233,29 @@ static int detect_rom_game(const char *path, char *game_name, size_t max_len)
|
||||
{
|
||||
char hash[HASH_LEN + 1];
|
||||
int rv;
|
||||
const char *suffix;
|
||||
const char **tmp_suffix;
|
||||
|
||||
suffix = strrchr(path, '.');
|
||||
if (!suffix) {
|
||||
const char *suffix = strrchr(path, '.');
|
||||
if (!suffix)
|
||||
{
|
||||
LOG_WARN("Could not find extension for: %s", path);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
memset(hash, 0, sizeof(hash));
|
||||
|
||||
if ((rv = get_sha1(path, hash)) < 0) {
|
||||
if ((rv = get_sha1(path, hash)) < 0)
|
||||
LOG_WARN("Could not calculate hash: %s", strerror(-rv));
|
||||
}
|
||||
|
||||
if (find_rom_canonical_name(hash, game_name, max_len) < 0) {
|
||||
if (find_rom_canonical_name(hash, game_name, max_len) < 0)
|
||||
{
|
||||
LOG_DEBUG("Could not detect rom with hash `%s` guessing", hash);
|
||||
|
||||
for (tmp_suffix = SUFFIX_MATCH; *tmp_suffix != NULL;
|
||||
tmp_suffix += 2) {
|
||||
if (strcasecmp(suffix, *tmp_suffix) == 0) {
|
||||
tmp_suffix += 2)
|
||||
{
|
||||
if (strcasecmp(suffix, *tmp_suffix) == 0)
|
||||
{
|
||||
snprintf(game_name, max_len, "%s.<unknown>",
|
||||
*(tmp_suffix + 1));
|
||||
return 0;
|
||||
@ -275,36 +270,39 @@ static int detect_rom_game(const char *path, char *game_name, size_t max_len)
|
||||
static int detect_game(const char *path, char *game_name, size_t max_len)
|
||||
{
|
||||
if ((strcasecmp(path + strlen(path) - 4, ".cue") == 0) ||
|
||||
(strcasecmp(path + strlen(path) - 4, ".m3u") == 0)) {
|
||||
(strcasecmp(path + strlen(path) - 4, ".m3u") == 0))
|
||||
{
|
||||
LOG_INFO("Starting CD game detection...");
|
||||
return detect_cd_game(path, game_name, max_len);
|
||||
} else {
|
||||
}
|
||||
else
|
||||
{
|
||||
LOG_INFO("Starting rom game detection...");
|
||||
return detect_rom_game(path, game_name, max_len);
|
||||
}
|
||||
}
|
||||
|
||||
static int select_core(char *core_path, size_t max_len,
|
||||
const struct RunInfo *info) {
|
||||
const struct RunInfo *info)
|
||||
{
|
||||
int fd = open("./cores.conf", O_RDONLY);
|
||||
int rv;
|
||||
int bci = 0;
|
||||
char token[MAX_TOKEN_LEN];
|
||||
int broken = 0;
|
||||
if (fd < 0) {
|
||||
if (fd < 0)
|
||||
return -errno;
|
||||
}
|
||||
|
||||
LOG_INFO("Selecting core for system '%s'", info->system);
|
||||
while (1) {
|
||||
if ((rv = get_token(fd, token, MAX_TOKEN_LEN)) < 0) {
|
||||
while (1)
|
||||
{
|
||||
if ((rv = get_token(fd, token, MAX_TOKEN_LEN)) < 0)
|
||||
goto clean;
|
||||
}
|
||||
|
||||
if (rl_fnmatch(token, info->system, 0) != 0) {
|
||||
if ((rv = find_token(fd, ";")) < 0) {
|
||||
if (rl_fnmatch(token, info->system, 0) != 0)
|
||||
{
|
||||
if ((rv = find_token(fd, ";")) < 0)
|
||||
goto clean;
|
||||
}
|
||||
continue;
|
||||
}
|
||||
|
||||
@ -313,17 +311,19 @@ static int select_core(char *core_path, size_t max_len,
|
||||
break;
|
||||
}
|
||||
|
||||
if ((rv = get_token(fd, token, MAX_TOKEN_LEN)) < 0) {
|
||||
if ((rv = get_token(fd, token, MAX_TOKEN_LEN)) < 0)
|
||||
goto clean;
|
||||
}
|
||||
|
||||
while (strcmp(token, ";") != 0) {
|
||||
while (strcmp(token, ";") != 0)
|
||||
{
|
||||
broken = 0;
|
||||
for (bci = 0; info->broken_cores[bci] != '\0';
|
||||
bci += strlen(&info->broken_cores[bci]) + 1) {
|
||||
bci += strlen(&info->broken_cores[bci]) + 1)
|
||||
{
|
||||
|
||||
LOG_DEBUG("%s, %s", &info->broken_cores[bci], token);
|
||||
if (strcmp(&info->broken_cores[bci], token) == 0) {
|
||||
if (strcmp(&info->broken_cores[bci], token) == 0)
|
||||
{
|
||||
broken = 1;
|
||||
LOG_DEBUG("Not using core %s because it is "
|
||||
"marked broken for this game",
|
||||
@ -332,15 +332,12 @@ static int select_core(char *core_path, size_t max_len,
|
||||
}
|
||||
}
|
||||
|
||||
if (!broken) {
|
||||
if (!broken)
|
||||
goto success;
|
||||
}
|
||||
|
||||
if ((rv = get_token(fd, token, MAX_TOKEN_LEN)) < 0) {
|
||||
if ((rv = get_token(fd, token, MAX_TOKEN_LEN)) < 0)
|
||||
goto clean;
|
||||
}
|
||||
|
||||
}
|
||||
rv = -EINVAL;
|
||||
goto clean;
|
||||
|
||||
@ -363,20 +360,24 @@ static int run_retroarch(const char *path, const struct RunInfo *info)
|
||||
};
|
||||
int argi = 3;
|
||||
|
||||
if ((rv = select_core(core_path, PATH_MAX, info)) < 0) {
|
||||
if ((rv = select_core(core_path, PATH_MAX, info)) < 0)
|
||||
{
|
||||
LOG_WARN("Could not find suitable core");
|
||||
return rv;
|
||||
}
|
||||
|
||||
LOG_INFO("Using core at '%s'", core_path);
|
||||
if (info->multitap) {
|
||||
if (info->multitap)
|
||||
{
|
||||
retro_argv[argi] = "-4";
|
||||
argi++;
|
||||
LOG_INFO("Game supports multitap");
|
||||
}
|
||||
|
||||
if (info->dualanalog) {
|
||||
for (i = 0; i < 8; i++) {
|
||||
if (info->dualanalog)
|
||||
{
|
||||
for (i = 0; i < 8; i++)
|
||||
{
|
||||
retro_argv[argi] = "-A";
|
||||
argi++;
|
||||
retro_argv[argi] = "1";
|
||||
@ -394,7 +395,8 @@ static int run_retroarch(const char *path, const struct RunInfo *info)
|
||||
|
||||
int main(int argc, char *argv[])
|
||||
{
|
||||
if (argc < 2) {
|
||||
if (argc < 2)
|
||||
{
|
||||
printf("usage: retrolaunch <ROM>\n");
|
||||
return -1;
|
||||
}
|
||||
@ -405,13 +407,15 @@ int main(int argc, char *argv[])
|
||||
int rv;
|
||||
|
||||
LOG_INFO("Analyzing '%s'", path);
|
||||
if ((rv = detect_game(path, game_name, MAX_TOKEN_LEN)) < 0) {
|
||||
if ((rv = detect_game(path, game_name, MAX_TOKEN_LEN)) < 0)
|
||||
{
|
||||
LOG_WARN("Could not detect game: %s", strerror(-rv));
|
||||
return -rv;
|
||||
}
|
||||
|
||||
LOG_INFO("Game is `%s`", game_name);
|
||||
if ((rv = get_run_info(&info, game_name)) < 0) {
|
||||
if ((rv = get_run_info(&info, game_name)) < 0)
|
||||
{
|
||||
LOG_WARN("Could not detect run info: %s", strerror(-rv));
|
||||
return -1;
|
||||
}
|
||||
|
@ -11,12 +11,15 @@ ssize_t get_token(int fd, char *token, size_t max_len)
|
||||
ssize_t len = 0;
|
||||
int in_string = 0;
|
||||
|
||||
while (1) {
|
||||
while (1)
|
||||
{
|
||||
rv = read(fd, c, 1);
|
||||
if (rv == 0) {
|
||||
if (rv == 0)
|
||||
return 0;
|
||||
} else if (rv < 1) {
|
||||
switch (errno) {
|
||||
else if (rv < 1)
|
||||
{
|
||||
switch (errno)
|
||||
{
|
||||
case EINTR:
|
||||
case EAGAIN:
|
||||
continue;
|
||||
@ -25,22 +28,24 @@ ssize_t get_token(int fd, char *token, size_t max_len)
|
||||
}
|
||||
}
|
||||
|
||||
switch (*c) {
|
||||
switch (*c)
|
||||
{
|
||||
case ' ':
|
||||
case '\t':
|
||||
case '\r':
|
||||
case '\n':
|
||||
if (c == token) {
|
||||
if (c == token)
|
||||
continue;
|
||||
}
|
||||
|
||||
if (!in_string) {
|
||||
if (!in_string)
|
||||
{
|
||||
*c = '\0';
|
||||
return len;
|
||||
}
|
||||
break;
|
||||
case '\"':
|
||||
if (c == token) {
|
||||
if (c == token)
|
||||
{
|
||||
in_string = 1;
|
||||
continue;
|
||||
}
|
||||
@ -51,7 +56,8 @@ ssize_t get_token(int fd, char *token, size_t max_len)
|
||||
|
||||
len++;
|
||||
c++;
|
||||
if (len == (ssize_t)max_len) {
|
||||
if (len == (ssize_t)max_len)
|
||||
{
|
||||
*c = '\0';
|
||||
return len;
|
||||
}
|
||||
@ -62,14 +68,13 @@ int find_token(int fd, const char *token)
|
||||
{
|
||||
int tmp_len = strlen(token);
|
||||
char *tmp_token = (char*)calloc(tmp_len, 1);
|
||||
if (!tmp_token) {
|
||||
if (!tmp_token)
|
||||
return -1;
|
||||
}
|
||||
while (strncmp(tmp_token, token, tmp_len) != 0) {
|
||||
if (get_token(fd, tmp_token, tmp_len) <= 0) {
|
||||
while (strncmp(tmp_token, token, tmp_len) != 0)
|
||||
{
|
||||
if (get_token(fd, tmp_token, tmp_len) <= 0)
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
@ -6,26 +6,27 @@
|
||||
|
||||
// Implemnentation of fnmatch(3) so it can be distributed to non *nix platforms
|
||||
// No flags are implemented ATM. We don't use them. Add flags as needed.
|
||||
int rl_fnmatch(const char *pattern, const char *string, int flags) {
|
||||
int rl_fnmatch(const char *pattern, const char *string, int flags)
|
||||
{
|
||||
const char *c;
|
||||
int charmatch = 0;
|
||||
int rv;
|
||||
for (c = pattern; *c != '\0'; c++) {
|
||||
for (c = pattern; *c != '\0'; c++)
|
||||
{
|
||||
// String ended before pattern
|
||||
if ((*c != '*') && (*string == '\0')) {
|
||||
if ((*c != '*') && (*string == '\0'))
|
||||
return FNM_NOMATCH;
|
||||
}
|
||||
|
||||
switch (*c) {
|
||||
switch (*c)
|
||||
{
|
||||
// Match any number of unknown chars
|
||||
case '*':
|
||||
// Find next node in the pattern ignoring multiple
|
||||
// asterixes
|
||||
do {
|
||||
c++;
|
||||
if (*c == '\0') {
|
||||
if (*c == '\0')
|
||||
return 0;
|
||||
}
|
||||
} while (*c == '*');
|
||||
|
||||
// Match the remaining pattern ingnoring more and more
|
||||
@ -36,9 +37,8 @@ int rl_fnmatch(const char *pattern, const char *string, int flags) {
|
||||
// calculating the minimum chars needed to
|
||||
// match the remaining pattern but I don't
|
||||
// think it is worth the work ATM.
|
||||
if (*string == '\0') {
|
||||
if (*string == '\0')
|
||||
return FNM_NOMATCH;
|
||||
}
|
||||
|
||||
rv = rl_fnmatch(c, string, flags);
|
||||
string++;
|
||||
@ -48,26 +48,23 @@ int rl_fnmatch(const char *pattern, const char *string, int flags) {
|
||||
// Match char from list
|
||||
case '[':
|
||||
charmatch = 0;
|
||||
for (c++; *c != ']'; c++) {
|
||||
for (c++; *c != ']'; c++)
|
||||
{
|
||||
// Bad formath
|
||||
if (*c == '\0') {
|
||||
if (*c == '\0')
|
||||
return FNM_NOMATCH;
|
||||
}
|
||||
|
||||
// Match already found
|
||||
if (charmatch) {
|
||||
if (charmatch)
|
||||
continue;
|
||||
}
|
||||
|
||||
if (*c == *string) {
|
||||
if (*c == *string)
|
||||
charmatch = 1;
|
||||
}
|
||||
}
|
||||
|
||||
// No match in list
|
||||
if (!charmatch) {
|
||||
if (!charmatch)
|
||||
return FNM_NOMATCH;
|
||||
}
|
||||
|
||||
string++;
|
||||
break;
|
||||
@ -79,27 +76,24 @@ int rl_fnmatch(const char *pattern, const char *string, int flags) {
|
||||
case '\\':
|
||||
c++;
|
||||
// Dangling escape at end of pattern
|
||||
if (*c == '\0') { // FIXME: Was c == '\0' (makes no sense). Not sure if c == NULL or *c == '\0' is intended. Assuming *c due to c++ right before.
|
||||
if (*c == '\0') // FIXME: Was c == '\0' (makes no sense). Not sure if c == NULL or *c == '\0' is intended. Assuming *c due to c++ right before.
|
||||
return FNM_NOMATCH;
|
||||
}
|
||||
default:
|
||||
if (*c != *string) {
|
||||
if (*c != *string)
|
||||
return FNM_NOMATCH;
|
||||
}
|
||||
string++;
|
||||
}
|
||||
}
|
||||
|
||||
// End of string and end of pattend
|
||||
if (*string == '\0') {
|
||||
if (*string == '\0')
|
||||
return 0;
|
||||
} else {
|
||||
return FNM_NOMATCH;
|
||||
}
|
||||
}
|
||||
|
||||
#if __TEST_FNMATCH__
|
||||
int main() {
|
||||
int main(void)
|
||||
{
|
||||
assert(rl_fnmatch("TEST", "TEST", 0) == 0);
|
||||
assert(rl_fnmatch("TE?T", "TEST", 0) == 0);
|
||||
assert(rl_fnmatch("TE[Ssa]T", "TEST", 0) == 0);
|
||||
|
@ -43,31 +43,8 @@
|
||||
/*
|
||||
* Define the circular shift macro
|
||||
*/
|
||||
#define SHA1CircularShift(bits,word) \
|
||||
((((word) << (bits)) & 0xFFFFFFFF) | \
|
||||
((word) >> (32-(bits))))
|
||||
#define SHA1CircularShift(bits,word) ((((word) << (bits)) & 0xFFFFFFFF) | ((word) >> (32-(bits))))
|
||||
|
||||
/* Function prototypes */
|
||||
void SHA1ProcessMessageBlock(SHA1Context *);
|
||||
void SHA1PadMessage(SHA1Context *);
|
||||
|
||||
/*
|
||||
* SHA1Reset
|
||||
*
|
||||
* Description:
|
||||
* This function will initialize the SHA1Context in preparation
|
||||
* for computing a new message digest.
|
||||
*
|
||||
* Parameters:
|
||||
* context: [in/out]
|
||||
* The context to reset.
|
||||
*
|
||||
* Returns:
|
||||
* Nothing.
|
||||
*
|
||||
* Comments:
|
||||
*
|
||||
*/
|
||||
void SHA1Reset(SHA1Context *context)
|
||||
{
|
||||
context->Length_Low = 0;
|
||||
@ -84,126 +61,6 @@ void SHA1Reset(SHA1Context *context)
|
||||
context->Corrupted = 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* SHA1Result
|
||||
*
|
||||
* Description:
|
||||
* This function will return the 160-bit message digest into the
|
||||
* Message_Digest array within the SHA1Context provided
|
||||
*
|
||||
* Parameters:
|
||||
* context: [in/out]
|
||||
* The context to use to calculate the SHA-1 hash.
|
||||
*
|
||||
* Returns:
|
||||
* 1 if successful, 0 if it failed.
|
||||
*
|
||||
* Comments:
|
||||
*
|
||||
*/
|
||||
int SHA1Result(SHA1Context *context)
|
||||
{
|
||||
|
||||
if (context->Corrupted)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (!context->Computed)
|
||||
{
|
||||
SHA1PadMessage(context);
|
||||
context->Computed = 1;
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
/*
|
||||
* SHA1Input
|
||||
*
|
||||
* Description:
|
||||
* This function accepts an array of octets as the next portion of
|
||||
* the message.
|
||||
*
|
||||
* Parameters:
|
||||
* context: [in/out]
|
||||
* The SHA-1 context to update
|
||||
* message_array: [in]
|
||||
* An array of characters representing the next portion of the
|
||||
* message.
|
||||
* length: [in]
|
||||
* The length of the message in message_array
|
||||
*
|
||||
* Returns:
|
||||
* Nothing.
|
||||
*
|
||||
* Comments:
|
||||
*
|
||||
*/
|
||||
void SHA1Input( SHA1Context *context,
|
||||
const unsigned char *message_array,
|
||||
unsigned length)
|
||||
{
|
||||
if (!length)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
if (context->Computed || context->Corrupted)
|
||||
{
|
||||
context->Corrupted = 1;
|
||||
return;
|
||||
}
|
||||
|
||||
while(length-- && !context->Corrupted)
|
||||
{
|
||||
context->Message_Block[context->Message_Block_Index++] =
|
||||
(*message_array & 0xFF);
|
||||
|
||||
context->Length_Low += 8;
|
||||
/* Force it to 32 bits */
|
||||
context->Length_Low &= 0xFFFFFFFF;
|
||||
if (context->Length_Low == 0)
|
||||
{
|
||||
context->Length_High++;
|
||||
/* Force it to 32 bits */
|
||||
context->Length_High &= 0xFFFFFFFF;
|
||||
if (context->Length_High == 0)
|
||||
{
|
||||
/* Message is too long */
|
||||
context->Corrupted = 1;
|
||||
}
|
||||
}
|
||||
|
||||
if (context->Message_Block_Index == 64)
|
||||
{
|
||||
SHA1ProcessMessageBlock(context);
|
||||
}
|
||||
|
||||
message_array++;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* SHA1ProcessMessageBlock
|
||||
*
|
||||
* Description:
|
||||
* This function will process the next 512 bits of the message
|
||||
* stored in the Message_Block array.
|
||||
*
|
||||
* Parameters:
|
||||
* None.
|
||||
*
|
||||
* Returns:
|
||||
* Nothing.
|
||||
*
|
||||
* Comments:
|
||||
* Many of the variable names in the SHAContext, especially the
|
||||
* single character names, were used because those were the names
|
||||
* used in the publication.
|
||||
*
|
||||
*
|
||||
*/
|
||||
void SHA1ProcessMessageBlock(SHA1Context *context)
|
||||
{
|
||||
const unsigned K[] = /* Constants defined in SHA-1 */
|
||||
@ -300,29 +157,6 @@ void SHA1ProcessMessageBlock(SHA1Context *context)
|
||||
context->Message_Block_Index = 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* SHA1PadMessage
|
||||
*
|
||||
* Description:
|
||||
* According to the standard, the message must be padded to an even
|
||||
* 512 bits. The first padding bit must be a '1'. The last 64
|
||||
* bits represent the length of the original message. All bits in
|
||||
* between should be 0. This function will pad the message
|
||||
* according to those rules by filling the Message_Block array
|
||||
* accordingly. It will also call SHA1ProcessMessageBlock()
|
||||
* appropriately. When it returns, it can be assumed that the
|
||||
* message digest has been computed.
|
||||
*
|
||||
* Parameters:
|
||||
* context: [in/out]
|
||||
* The context to pad
|
||||
*
|
||||
* Returns:
|
||||
* Nothing.
|
||||
*
|
||||
* Comments:
|
||||
*
|
||||
*/
|
||||
void SHA1PadMessage(SHA1Context *context)
|
||||
{
|
||||
/*
|
||||
@ -335,25 +169,19 @@ void SHA1PadMessage(SHA1Context *context)
|
||||
{
|
||||
context->Message_Block[context->Message_Block_Index++] = 0x80;
|
||||
while(context->Message_Block_Index < 64)
|
||||
{
|
||||
context->Message_Block[context->Message_Block_Index++] = 0;
|
||||
}
|
||||
|
||||
SHA1ProcessMessageBlock(context);
|
||||
|
||||
while(context->Message_Block_Index < 56)
|
||||
{
|
||||
context->Message_Block[context->Message_Block_Index++] = 0;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
context->Message_Block[context->Message_Block_Index++] = 0x80;
|
||||
while(context->Message_Block_Index < 56)
|
||||
{
|
||||
context->Message_Block[context->Message_Block_Index++] = 0;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Store the message length as the last 8 octets
|
||||
@ -369,3 +197,56 @@ void SHA1PadMessage(SHA1Context *context)
|
||||
|
||||
SHA1ProcessMessageBlock(context);
|
||||
}
|
||||
|
||||
int SHA1Result(SHA1Context *context)
|
||||
{
|
||||
if (context->Corrupted)
|
||||
return 0;
|
||||
|
||||
if (!context->Computed)
|
||||
{
|
||||
SHA1PadMessage(context);
|
||||
context->Computed = 1;
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
void SHA1Input( SHA1Context *context,
|
||||
const unsigned char *message_array,
|
||||
unsigned length)
|
||||
{
|
||||
if (!length)
|
||||
return;
|
||||
|
||||
if (context->Computed || context->Corrupted)
|
||||
{
|
||||
context->Corrupted = 1;
|
||||
return;
|
||||
}
|
||||
|
||||
while(length-- && !context->Corrupted)
|
||||
{
|
||||
context->Message_Block[context->Message_Block_Index++] =
|
||||
(*message_array & 0xFF);
|
||||
|
||||
context->Length_Low += 8;
|
||||
/* Force it to 32 bits */
|
||||
context->Length_Low &= 0xFFFFFFFF;
|
||||
if (context->Length_Low == 0)
|
||||
{
|
||||
context->Length_High++;
|
||||
/* Force it to 32 bits */
|
||||
context->Length_High &= 0xFFFFFFFF;
|
||||
if (context->Length_High == 0)
|
||||
context->Corrupted = 1; /* Message is too long */
|
||||
}
|
||||
|
||||
if (context->Message_Block_Index == 64)
|
||||
SHA1ProcessMessageBlock(context);
|
||||
|
||||
message_array++;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
Loading…
x
Reference in New Issue
Block a user