(retrolaunch) cleanups

This commit is contained in:
twinaphex 2014-08-13 02:51:49 +02:00
parent 7ff8db3f69
commit dd72443211
5 changed files with 844 additions and 931 deletions

View File

@ -15,7 +15,8 @@
#define MAGIC_LEN 16 #define MAGIC_LEN 16
struct MagicEntry { struct MagicEntry
{
const char* system_name; const char* system_name;
const char* magic; const char* magic;
}; };
@ -28,294 +29,322 @@ static struct MagicEntry MAGIC_NUMBERS[] = {
}; };
static int find_first_data_track(const char* cue_path, int32_t* offset, 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; int rv;
char tmp_token[MAX_TOKEN_LEN]; int fd = -1;
int m, s, f; char tmp_token[MAX_TOKEN_LEN];
char cue_dir[PATH_MAX]; int m, s, f;
strlcpy(cue_dir, cue_path, PATH_MAX); char cue_dir[PATH_MAX];
path_basedir(cue_dir); strlcpy(cue_dir, cue_path, PATH_MAX);
path_basedir(cue_dir);
fd = open(cue_path, O_RDONLY); 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)); LOG_WARN("Could not open CUE file '%s': %s", cue_path,
return -errno; strerror(errno));
} return -errno;
}
LOG_DEBUG("Parsing CUE file '%s'...", cue_path); LOG_DEBUG("Parsing CUE file '%s'...", cue_path);
while (get_token(fd, tmp_token, MAX_TOKEN_LEN) > 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); if (strcmp(tmp_token, "FILE") == 0)
fill_pathname_join(track_path, cue_dir, tmp_token, max_len); {
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); else if (strcasecmp(tmp_token, "TRACK") == 0)
get_token(fd, tmp_token, MAX_TOKEN_LEN); {
if (strcasecmp(tmp_token, "AUDIO") == 0) { get_token(fd, tmp_token, MAX_TOKEN_LEN);
continue; get_token(fd, tmp_token, MAX_TOKEN_LEN);
} if (strcasecmp(tmp_token, "AUDIO") == 0)
continue;
find_token(fd, "INDEX"); find_token(fd, "INDEX");
get_token(fd, tmp_token, MAX_TOKEN_LEN); get_token(fd, tmp_token, MAX_TOKEN_LEN);
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; LOG_WARN("Error parsing time stamp '%s'", tmp_token);
} return -errno;
*offset = ((m * 60) * (s * 75) * f) * 25; }
*offset = ((m * 60) * (s * 75) * f) * 25;
LOG_DEBUG("Found 1st data track on file '%s+%d'", LOG_DEBUG("Found 1st data track on file '%s+%d'",
track_path, *offset); track_path, *offset);
rv = 0; rv = 0;
goto clean; goto clean;
} }
} }
rv = -EINVAL; rv = -EINVAL;
clean: clean:
close(fd); close(fd);
return rv; return rv;
} }
static int find_ps1_canonical_name(const char* game_id, char* game_name, static int find_ps1_canonical_name(const char* game_id, char* game_name,
size_t max_len) { size_t max_len)
int fd; {
char tmp_token[MAX_TOKEN_LEN]; char tmp_token[MAX_TOKEN_LEN];
int rv = 0; int rv = 0;
fd = open("cddb/ps1.idlst", O_RDONLY); int fd = open("cddb/ps1.idlst", O_RDONLY);
if (fd < 0) { if (fd < 0)
LOG_WARN("Could not open id list: %s", strerror(errno)); {
return -errno; LOG_WARN("Could not open id list: %s", strerror(errno));
} return -errno;
}
while (get_token(fd, tmp_token, MAX_TOKEN_LEN) > 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); if(strcasecmp(tmp_token, game_id) != 0)
continue; {
} 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; goto clean;
}
rv = 0; rv = 0;
goto clean; goto clean;
} }
rv = -ENOENT; rv = -ENOENT;
clean: clean:
close(fd); close(fd);
return rv; return rv;
} }
static int detect_ps1_game(const char* track_path, int32_t offset, 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]; int rv;
const char* pattern = "cdrom:"; char buff[4096];
const char* pat_c; const char* pattern = "cdrom:";
char* c; const char* pat_c;
char* id_start; char* c;
int i; char* id_start;
int i;
int fd = open(track_path, O_RDONLY); 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; LOG_DEBUG("Could not open data track: %s", strerror(errno));
} return -errno;
}
lseek(fd, 0x9340, SEEK_SET); lseek(fd, 0x9340, SEEK_SET);
if (read(fd, buff, 10) > 0) { if (read(fd, buff, 10) > 0)
buff[10] = '\0'; {
buff[4] = '-'; buff[10] = '\0';
LOG_DEBUG("Found disk label '%s'", buff); buff[4] = '-';
rv = find_ps1_canonical_name(buff, game_name, max_len); LOG_DEBUG("Found disk label '%s'", buff);
if (rv == 0) { rv = find_ps1_canonical_name(buff, game_name, max_len);
goto clean; if (rv == 0)
} goto clean;
} }
memset(buff, 0, sizeof(buff));
pat_c = pattern;
while (1) {
rv = read(fd, buff, 4096);
if (rv < 0) {
rv = -errno;
goto clean;
}
for (i = 0; i < rv; i++) { memset(buff, 0, sizeof(buff));
if (*pat_c == buff[i]) { pat_c = pattern;
pat_c++;
} else { while (1)
pat_c = pattern; {
continue; rv = read(fd, buff, 4096);
if (rv < 0)
{
rv = -errno;
goto clean;
}
for (i = 0; i < rv; i++)
{
if (*pat_c == buff[i])
pat_c++;
else
{
pat_c = pattern;
continue;
}
if (*pat_c == '\0')
{
id_start = &buff[i] + 1;
c = strchr(id_start, ';');
if (!c)
{
LOG_DEBUG("Invalid pattern in buffer.");
rv = -EINVAL;
goto clean;
} }
*c = '\0';
if (*pat_c == '\0') { c = strrchr(id_start, '\\');
id_start = &buff[i] + 1; if (c != NULL)
c = strchr(id_start, ';'); id_start = c + 1;
if (!c) { id_start[4] = '-';
LOG_DEBUG("Invalid pattern in buffer."); id_start[8] = id_start[9];
rv = -EINVAL; id_start[9] = id_start[10];
goto clean; id_start[10] = '\0';
} LOG_DEBUG("Found ps1 id %s", id_start);
*c = '\0'; rv = find_ps1_canonical_name(id_start, game_name, max_len);
c = strrchr(id_start, '\\'); goto clean;
if (c != NULL) { }
id_start = c + 1; }
} }
id_start[4] = '-'; rv = -EINVAL;
id_start[8] = id_start[9];
id_start[9] = id_start[10];
id_start[10] = '\0';
LOG_DEBUG("Found ps1 id %s", id_start);
rv = find_ps1_canonical_name(id_start, game_name, max_len);
goto clean;
}
}
}
rv = -EINVAL;
clean: clean:
close(fd); close(fd);
return rv; return rv;
} }
static int detect_system(const char* track_path, int32_t offset, 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 rv;
int fd; char magic[MAGIC_LEN];
//struct MagicEntry entry; int fd;
int i; //struct MagicEntry entry;
int i;
fd = open(track_path, O_RDONLY); 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)); LOG_WARN("Could not open data track of file '%s': %s",
rv = -errno; track_path, strerror(errno));
goto clean; rv = -errno;
} goto clean;
}
lseek(fd, offset, SEEK_SET); 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)); LOG_WARN("Could not read data from file '%s' at offset %d: %s",
rv = -errno; track_path, offset, strerror(errno));
goto clean; rv = -errno;
} goto clean;
}
LOG_DEBUG("Comparing with known magic numbers..."); LOG_DEBUG("Comparing with known magic numbers...");
for (i = 0; MAGIC_NUMBERS[i].system_name != NULL; i++) { 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; if (memcmp(MAGIC_NUMBERS[i].magic, magic, MAGIC_LEN) == 0)
rv = 0; {
goto clean; *system_name = MAGIC_NUMBERS[i].system_name;
} rv = 0;
} goto clean;
}
}
LOG_WARN("Could not find compatible system"); LOG_WARN("Could not find compatible system");
rv = -EINVAL; rv = -EINVAL;
clean: clean:
close(fd); close(fd);
return rv; 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; char c;
int midstream = 0; int skip = 0;
int midstream = 0;
int fd = open(m3u_path, O_RDONLY); 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; LOG_WARN("Could not open m3u '%s': %s", m3u_path, strerror(errno));
} return -errno;
}
strncpy(cue_path, m3u_path, PATH_MAX); strncpy(cue_path, m3u_path, PATH_MAX);
path_basedir(cue_path); path_basedir(cue_path);
cue_path += strlen(cue_path); cue_path += strlen(cue_path);
cue_path[0] = '/'; cue_path[0] = '/';
cue_path++; cue_path++;
while ((read(fd, &c, 1) > 0)) { while ((read(fd, &c, 1) > 0))
switch (c) { {
case '#': switch (c)
if (!midstream) { {
skip = 1; case '#':
} if (!midstream)
break; skip = 1;
case '\n': break;
if (skip) { case '\n':
skip = 0; if (skip)
} else if(midstream) { skip = 0;
cue_path[0] = '\0'; else if(midstream)
close(fd); {
return 0; cue_path[0] = '\0';
} close(fd);
break; return 0;
case ' ': }
if (!midstream) { break;
break; case ' ':
} if (!midstream)
default: break;
if (!skip) { default:
midstream = 1; if (!skip)
cue_path[0] = c; {
cue_path++; midstream = 1;
} cue_path[0] = c;
} cue_path++;
} }
}
}
close(fd); close(fd);
return -EINVAL; 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]; char cue_path[PATH_MAX];
int32_t offset = 0; char track_path[PATH_MAX];
const char* system_name = NULL; int32_t offset = 0;
int rv; const char* system_name = NULL;
if (strcasecmp(target_path + strlen(target_path) - 4, ".m3u") == 0) { int rv;
rv = find_first_cue(target_path, cue_path, PATH_MAX); if (strcasecmp(target_path + strlen(target_path) - 4, ".m3u") == 0)
if (rv < 0) { {
LOG_WARN("Could not parse m3u: %s", strerror(-rv)); rv = find_first_cue(target_path, cue_path, PATH_MAX);
return rv; 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); 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_WARN("Could not find valid data track: %s", strerror(-rv));
} return rv;
}
LOG_DEBUG("Reading 1st data track..."); 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; return rv;
}
LOG_DEBUG("Detected %s media", system_name);
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)
return 0;
}
snprintf(game_name, max_len, "%s.", system_name); snprintf(game_name, max_len, "<unknown>");
game_name += strlen(system_name) + 1; return 0;
max_len -= strlen(system_name) + 1;
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;
} }

View File

@ -26,124 +26,117 @@
static int find_hash(int fd, const char *hash, char *game_name, size_t max_len) static int find_hash(int fd, const char *hash, char *game_name, size_t max_len)
{ {
char token[MAX_TOKEN_LEN] = {0}; char token[MAX_TOKEN_LEN] = {0};
while (1) { while (1)
if (find_token(fd, "game") < 0) { {
return -1; if (find_token(fd, "game") < 0)
} return -1;
if (find_token(fd, "name") < 0) { if (find_token(fd, "name") < 0)
return -1; return -1;
}
if (get_token(fd, game_name, max_len) < 0) { if (get_token(fd, game_name, max_len) < 0)
return -1; return -1;
}
if (find_token(fd, "sha1") < 0) { if (find_token(fd, "sha1") < 0)
return -1; return -1;
}
if (get_token(fd, token, MAX_TOKEN_LEN) < 0) { if (get_token(fd, token, MAX_TOKEN_LEN) < 0)
return -1; return -1;
}
if (strcasecmp(hash, token) == 0) { if (strcasecmp(hash, token) == 0)
return 0; return 0;
} }
}
} }
static int static int
find_rom_canonical_name(const char *hash, char *game_name, size_t max_len) find_rom_canonical_name(const char *hash, char *game_name, size_t max_len)
{ {
// TODO: Error handling // TODO: Error handling
size_t i; size_t i;
int rv; int rv, fd, offs;
int fd; char *dat_path;
int offs; const char *dat_name, *dat_name_dot;
char *dat_path; struct string_list *files = dir_list_new("db", "dat", false);
const char *dat_name;
const char *dat_name_dot;
struct string_list *files;
files = dir_list_new("db", "dat", false); if (!files)
if (!files) { return -1;
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_path = files->elems[i].data;
dat_name = path_basename(dat_path);
dat_name_dot = strchr(dat_name, '.'); dat_name_dot = strchr(dat_name, '.');
if (!dat_name_dot) { if (!dat_name_dot)
continue; continue;
}
offs = dat_name_dot - dat_name + 1; offs = dat_name_dot - dat_name + 1;
memcpy(game_name, dat_name, offs); memcpy(game_name, dat_name, offs);
fd = open(dat_path, O_RDONLY); fd = open(dat_path, O_RDONLY);
if (fd < 0) { if (fd < 0)
continue; 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); rv = 0;
goto clean; close(fd);
} goto clean;
close(fd); }
} close(fd);
rv = -1; }
rv = -1;
clean: clean:
dir_list_free(files); dir_list_free(files);
return rv; return rv;
} }
static int get_sha1(const char *path, char *result) static int get_sha1(const char *path, char *result)
{ {
int fd; int fd;
int rv; int rv;
unsigned char buff[4096]; unsigned char buff[4096];
SHA1Context sha; SHA1Context sha;
fd = open(path, O_RDONLY); fd = open(path, O_RDONLY);
if (fd < 0) { if (fd < 0)
return -errno; return -errno;
}
SHA1Reset(&sha); SHA1Reset(&sha);
rv = 1; rv = 1;
while (rv > 0) { while (rv > 0)
rv = read(fd, buff, 4096); {
if (rv < 0) { rv = read(fd, buff, 4096);
close(fd); if (rv < 0)
return -errno; {
} close(fd);
return -errno;
}
SHA1Input(&sha, buff, rv); SHA1Input(&sha, buff, rv);
} }
if (!SHA1Result(&sha)) { if (!SHA1Result(&sha))
close(fd); {
return -1; close(fd);
} return -1;
}
sprintf(result, "%08X%08X%08X%08X%08X", sprintf(result, "%08X%08X%08X%08X%08X",
sha.Message_Digest[0], sha.Message_Digest[0],
sha.Message_Digest[1], sha.Message_Digest[1],
sha.Message_Digest[2], sha.Message_Digest[2],
sha.Message_Digest[3], sha.Message_Digest[4]); sha.Message_Digest[3], sha.Message_Digest[4]);
close(fd); close(fd);
return 0; return 0;
} }
struct RunInfo { struct RunInfo
char broken_cores[PATH_MAX]; {
int multitap; char broken_cores[PATH_MAX];
int dualanalog; int multitap;
char system[10]; int dualanalog;
char system[10];
}; };
static int read_launch_conf(struct RunInfo *info, const char *game_name) static int read_launch_conf(struct RunInfo *info, const char *game_name)
@ -152,19 +145,18 @@ static int read_launch_conf(struct RunInfo *info, const char *game_name)
int rv; int rv;
int bci = 0; int bci = 0;
char token[MAX_TOKEN_LEN]; char token[MAX_TOKEN_LEN];
if (fd < 0) { if (fd < 0)
return -errno; return -errno;
}
while (1) { while (1)
if ((rv = get_token(fd, token, MAX_TOKEN_LEN)) < 0) { {
if ((rv = get_token(fd, token, MAX_TOKEN_LEN)) < 0)
goto clean; goto clean;
}
if (rl_fnmatch(token, game_name, 0) != 0) { if (rl_fnmatch(token, game_name, 0) != 0)
if ((rv = find_token(fd, ";")) < 0) { {
if ((rv = find_token(fd, ";")) < 0)
goto clean; goto clean;
}
continue; continue;
} }
@ -172,47 +164,48 @@ static int read_launch_conf(struct RunInfo *info, const char *game_name)
break; break;
} }
if ((rv = get_token(fd, token, MAX_TOKEN_LEN)) < 0) { if ((rv = get_token(fd, token, MAX_TOKEN_LEN)) < 0)
goto clean; goto clean;
}
while (strcmp(token, ";") != 0) { while (strcmp(token, ";") != 0)
if (strcmp(token, "multitap") == 0) { {
info->multitap = 1; if (strcmp(token, "multitap") == 0)
} else if (strcmp(token, "dualanalog") == 0) { info->multitap = 1;
info->dualanalog = 1; else if (strcmp(token, "dualanalog") == 0)
} else if (token[0] == '!') { info->dualanalog = 1;
strncpy(&info->broken_cores[bci], &token[1], PATH_MAX - bci); else if (token[0] == '!')
bci += strnlen(&token[1], PATH_MAX) + 1; {
} 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; goto clean;
} }
}
rv = 0; rv = 0;
clean: clean:
close(fd); close(fd);
return rv; return rv;
} }
static int get_run_info(struct RunInfo *info, const char *game_name) { static int get_run_info(struct RunInfo *info, const char *game_name)
memset(info, 0, sizeof(struct RunInfo)); {
int i; int i;
for (i = 0; i < 9; i++) { memset(info, 0, sizeof(struct RunInfo));
if (game_name[i] == '.') {
break;
}
info->system[i] = game_name[i];
}
info->system[i] = '\0';
info->multitap = 0;
info->dualanalog = 0;
read_launch_conf(info, game_name); for (i = 0; i < 9; i++)
return 0; {
if (game_name[i] == '.')
break;
info->system[i] = game_name[i];
}
info->system[i] = '\0';
info->multitap = 0;
info->dualanalog = 0;
read_launch_conf(info, game_name);
return 0;
} }
@ -240,32 +233,34 @@ static int detect_rom_game(const char *path, char *game_name, size_t max_len)
{ {
char hash[HASH_LEN + 1]; char hash[HASH_LEN + 1];
int rv; int rv;
const char *suffix;
const char **tmp_suffix; const char **tmp_suffix;
suffix = strrchr(path, '.'); const char *suffix = strrchr(path, '.');
if (!suffix) { if (!suffix)
{
LOG_WARN("Could not find extension for: %s", path); LOG_WARN("Could not find extension for: %s", path);
return -EINVAL; return -EINVAL;
} }
memset(hash, 0, sizeof(hash)); 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)); 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); LOG_DEBUG("Could not detect rom with hash `%s` guessing", hash);
for (tmp_suffix = SUFFIX_MATCH; *tmp_suffix != NULL; for (tmp_suffix = SUFFIX_MATCH; *tmp_suffix != NULL;
tmp_suffix += 2) { tmp_suffix += 2)
if (strcasecmp(suffix, *tmp_suffix) == 0) { {
snprintf(game_name, max_len, "%s.<unknown>", if (strcasecmp(suffix, *tmp_suffix) == 0)
*(tmp_suffix + 1)); {
return 0; snprintf(game_name, max_len, "%s.<unknown>",
} *(tmp_suffix + 1));
} return 0;
}
}
return -EINVAL; return -EINVAL;
} }
@ -275,81 +270,83 @@ 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) static int detect_game(const char *path, char *game_name, size_t max_len)
{ {
if ((strcasecmp(path + strlen(path) - 4, ".cue") == 0) || 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..."); LOG_INFO("Starting CD game detection...");
return detect_cd_game(path, game_name, max_len); return detect_cd_game(path, game_name, max_len);
} else { }
else
{
LOG_INFO("Starting rom game detection..."); LOG_INFO("Starting rom game detection...");
return detect_rom_game(path, game_name, max_len); return detect_rom_game(path, game_name, max_len);
} }
} }
static int select_core(char *core_path, size_t 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 fd = open("./cores.conf", O_RDONLY);
int bci = 0; int rv;
char token[MAX_TOKEN_LEN]; int bci = 0;
int broken = 0; char token[MAX_TOKEN_LEN];
if (fd < 0) { int broken = 0;
return -errno; if (fd < 0)
} return -errno;
LOG_INFO("Selecting core for system '%s'", info->system); LOG_INFO("Selecting core for system '%s'", info->system);
while (1) { while (1)
if ((rv = get_token(fd, token, MAX_TOKEN_LEN)) < 0) { {
goto clean; if ((rv = get_token(fd, token, MAX_TOKEN_LEN)) < 0)
} goto clean;
if (rl_fnmatch(token, info->system, 0) != 0) { if (rl_fnmatch(token, info->system, 0) != 0)
if ((rv = find_token(fd, ";")) < 0) { {
goto clean; if ((rv = find_token(fd, ";")) < 0)
} goto clean;
continue; continue;
} }
LOG_INFO("Matched system '%s'", token); LOG_INFO("Matched system '%s'", token);
break; break;
} }
if ((rv = get_token(fd, token, MAX_TOKEN_LEN)) < 0) { if ((rv = get_token(fd, token, MAX_TOKEN_LEN)) < 0)
goto clean; goto clean;
}
while (strcmp(token, ";") != 0) { while (strcmp(token, ";") != 0)
broken = 0; {
for (bci = 0; info->broken_cores[bci] != '\0'; broken = 0;
bci += strlen(&info->broken_cores[bci]) + 1) { for (bci = 0; info->broken_cores[bci] != '\0';
bci += strlen(&info->broken_cores[bci]) + 1)
{
LOG_DEBUG("%s, %s", &info->broken_cores[bci], token); 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 " broken = 1;
"marked broken for this game", LOG_DEBUG("Not using core %s because it is "
&info->broken_cores[bci]); "marked broken for this game",
break; &info->broken_cores[bci]);
} break;
} }
}
if (!broken) { if (!broken)
goto success; goto success;
}
if ((rv = get_token(fd, token, MAX_TOKEN_LEN)) < 0) { if ((rv = get_token(fd, token, MAX_TOKEN_LEN)) < 0)
goto clean; goto clean;
} }
rv = -EINVAL;
} goto clean;
rv = -EINVAL;
goto clean;
success: success:
snprintf(core_path, max_len, "./cores/%s.so", token); snprintf(core_path, max_len, "./cores/%s.so", token);
rv = 0; rv = 0;
clean: clean:
close(fd); close(fd);
return rv; return rv;
} }
#ifndef RARCH_CONSOLE #ifndef RARCH_CONSOLE
@ -363,20 +360,24 @@ static int run_retroarch(const char *path, const struct RunInfo *info)
}; };
int argi = 3; 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"); LOG_WARN("Could not find suitable core");
return rv; return rv;
} }
LOG_INFO("Using core at '%s'", core_path); LOG_INFO("Using core at '%s'", core_path);
if (info->multitap) { if (info->multitap)
{
retro_argv[argi] = "-4"; retro_argv[argi] = "-4";
argi++; argi++;
LOG_INFO("Game supports multitap"); LOG_INFO("Game supports multitap");
} }
if (info->dualanalog) { if (info->dualanalog)
for (i = 0; i < 8; i++) { {
for (i = 0; i < 8; i++)
{
retro_argv[argi] = "-A"; retro_argv[argi] = "-A";
argi++; argi++;
retro_argv[argi] = "1"; retro_argv[argi] = "1";
@ -394,33 +395,36 @@ static int run_retroarch(const char *path, const struct RunInfo *info)
int main(int argc, char *argv[]) int main(int argc, char *argv[])
{ {
if (argc < 2) { if (argc < 2)
printf("usage: retrolaunch <ROM>\n"); {
return -1; printf("usage: retrolaunch <ROM>\n");
} return -1;
}
char game_name[MAX_TOKEN_LEN]; char game_name[MAX_TOKEN_LEN];
char *path = argv[1]; char *path = argv[1];
struct RunInfo info; struct RunInfo info;
int rv; int rv;
LOG_INFO("Analyzing '%s'", path); 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_WARN("Could not detect game: %s", strerror(-rv));
} return -rv;
}
LOG_INFO("Game is `%s`", game_name); 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; LOG_WARN("Could not detect run info: %s", strerror(-rv));
} return -1;
}
LOG_INFO("Launching '%s'", path); LOG_INFO("Launching '%s'", path);
rv = run_retroarch(path, &info); rv = run_retroarch(path, &info);
LOG_WARN("Could not launch retroarch: %s", strerror(-rv)); LOG_WARN("Could not launch retroarch: %s", strerror(-rv));
return -rv; return -rv;
} }
// Stub just so that it compiles // Stub just so that it compiles

View File

@ -6,70 +6,75 @@
ssize_t get_token(int fd, char *token, size_t max_len) ssize_t get_token(int fd, char *token, size_t max_len)
{ {
char *c = token; char *c = token;
int rv; int rv;
ssize_t len = 0; ssize_t len = 0;
int in_string = 0; int in_string = 0;
while (1) { while (1)
rv = read(fd, c, 1); {
if (rv == 0) { rv = read(fd, c, 1);
return 0; if (rv == 0)
} else if (rv < 1) { return 0;
switch (errno) { else if (rv < 1)
case EINTR: {
case EAGAIN: switch (errno)
continue; {
default: case EINTR:
return -errno; case EAGAIN:
} continue;
} default:
return -errno;
}
}
switch (*c) { switch (*c)
case ' ': {
case '\t': case ' ':
case '\r': case '\t':
case '\n': case '\r':
if (c == token) { case '\n':
continue; if (c == token)
} continue;
if (!in_string) { if (!in_string)
*c = '\0'; {
return len; *c = '\0';
} return len;
break; }
case '\"': break;
if (c == token) { case '\"':
in_string = 1; if (c == token)
continue; {
} in_string = 1;
continue;
}
*c = '\0'; *c = '\0';
return len; return len;
} }
len++; len++;
c++; c++;
if (len == (ssize_t)max_len) { if (len == (ssize_t)max_len)
*c = '\0'; {
return len; *c = '\0';
} return len;
} }
}
} }
int find_token(int fd, const char *token) int find_token(int fd, const char *token)
{ {
int tmp_len = strlen(token); int tmp_len = strlen(token);
char *tmp_token = (char*)calloc(tmp_len, 1); char *tmp_token = (char*)calloc(tmp_len, 1);
if (!tmp_token) { if (!tmp_token)
return -1; return -1;
} while (strncmp(tmp_token, token, tmp_len) != 0)
while (strncmp(tmp_token, token, tmp_len) != 0) { {
if (get_token(fd, tmp_token, tmp_len) <= 0) { if (get_token(fd, tmp_token, tmp_len) <= 0)
return -1; return -1;
} }
}
return 0; return 0;
} }

View File

@ -6,127 +6,121 @@
// Implemnentation of fnmatch(3) so it can be distributed to non *nix platforms // 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. // 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; const char *c;
int rv; int charmatch = 0;
for (c = pattern; *c != '\0'; c++) { int rv;
// String ended before pattern for (c = pattern; *c != '\0'; c++)
if ((*c != '*') && (*string == '\0')) { {
return FNM_NOMATCH; // String ended before pattern
} if ((*c != '*') && (*string == '\0'))
return FNM_NOMATCH;
switch (*c) { switch (*c)
// Match any number of unknown chars {
case '*': // Match any number of unknown chars
// Find next node in the pattern ignoring multiple case '*':
// asterixes // Find next node in the pattern ignoring multiple
do { // asterixes
c++; do {
if (*c == '\0') { c++;
return 0; if (*c == '\0')
} return 0;
} while (*c == '*'); } while (*c == '*');
// Match the remaining pattern ingnoring more and more // Match the remaining pattern ingnoring more and more
// chars. // chars.
do { do {
// We reached the end of the string without a // We reached the end of the string without a
// match. There is a way to optimize this by // match. There is a way to optimize this by
// calculating the minimum chars needed to // calculating the minimum chars needed to
// match the remaining pattern but I don't // match the remaining pattern but I don't
// think it is worth the work ATM. // think it is worth the work ATM.
if (*string == '\0') { if (*string == '\0')
return FNM_NOMATCH; return FNM_NOMATCH;
}
rv = rl_fnmatch(c, string, flags); rv = rl_fnmatch(c, string, flags);
string++; string++;
} while (rv != 0); } while (rv != 0);
return 0; return 0;
// Match char from list // Match char from list
case '[': case '[':
charmatch = 0; charmatch = 0;
for (c++; *c != ']'; c++) { for (c++; *c != ']'; c++)
// Bad formath {
if (*c == '\0') { // Bad formath
return FNM_NOMATCH; if (*c == '\0')
} return FNM_NOMATCH;
// Match already found // Match already found
if (charmatch) { if (charmatch)
continue; continue;
}
if (*c == *string) { if (*c == *string)
charmatch = 1; charmatch = 1;
} }
}
// No match in list // No match in list
if (!charmatch) { if (!charmatch)
return FNM_NOMATCH; return FNM_NOMATCH;
}
string++; string++;
break; break;
// Has any char // Has any char
case '?': case '?':
string++; string++;
break; break;
// Match following char verbatim // Match following char verbatim
case '\\': case '\\':
c++; c++;
// Dangling escape at end of pattern // 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; return FNM_NOMATCH;
} default:
default: if (*c != *string)
if (*c != *string) { return FNM_NOMATCH;
return FNM_NOMATCH; string++;
} }
string++; }
}
}
// End of string and end of pattend // End of string and end of pattend
if (*string == '\0') { if (*string == '\0')
return 0; return 0;
} else { return FNM_NOMATCH;
return FNM_NOMATCH;
}
} }
#if __TEST_FNMATCH__ #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("TEST", "TEST", 0) == 0);
assert(rl_fnmatch("TE[Ssa]T", "TEST", 0) == 0); assert(rl_fnmatch("TE?T", "TEST", 0) == 0);
assert(rl_fnmatch("TE[Ssda]T", "TEsT", 0) == 0); assert(rl_fnmatch("TE[Ssa]T", "TEST", 0) == 0);
assert(rl_fnmatch("TE[Ssda]T", "TEdT", 0) == 0); assert(rl_fnmatch("TE[Ssda]T", "TEsT", 0) == 0);
assert(rl_fnmatch("TE[Ssda]T", "TEaT", 0) == 0); assert(rl_fnmatch("TE[Ssda]T", "TEdT", 0) == 0);
assert(rl_fnmatch("TEST*", "TEST", 0) == 0); assert(rl_fnmatch("TE[Ssda]T", "TEaT", 0) == 0);
assert(rl_fnmatch("TEST**", "TEST", 0) == 0); assert(rl_fnmatch("TEST*", "TEST", 0) == 0);
assert(rl_fnmatch("TE*ST*", "TEST", 0) == 0); assert(rl_fnmatch("TEST**", "TEST", 0) == 0);
assert(rl_fnmatch("TE**ST*", "TEST", 0) == 0); assert(rl_fnmatch("TE*ST*", "TEST", 0) == 0);
assert(rl_fnmatch("TE**ST*", "TExST", 0) == 0); assert(rl_fnmatch("TE**ST*", "TEST", 0) == 0);
assert(rl_fnmatch("TE**ST", "TEST", 0) == 0); assert(rl_fnmatch("TE**ST*", "TExST", 0) == 0);
assert(rl_fnmatch("TE**ST", "TExST", 0) == 0); assert(rl_fnmatch("TE**ST", "TEST", 0) == 0);
assert(rl_fnmatch("TE\\**ST", "TE*xST", 0) == 0); assert(rl_fnmatch("TE**ST", "TExST", 0) == 0);
assert(rl_fnmatch("*.*", "test.jpg", 0) == 0); assert(rl_fnmatch("TE\\**ST", "TE*xST", 0) == 0);
assert(rl_fnmatch("*.jpg", "test.jpg", 0) == 0); assert(rl_fnmatch("*.*", "test.jpg", 0) == 0);
assert(rl_fnmatch("*.[Jj][Pp][Gg]", "test.jPg", 0) == 0); assert(rl_fnmatch("*.jpg", "test.jpg", 0) == 0);
assert(rl_fnmatch("*.[Jj]*[Gg]", "test.jPg", 0) == 0); assert(rl_fnmatch("*.[Jj][Pp][Gg]", "test.jPg", 0) == 0);
assert(rl_fnmatch("TEST?", "TEST", 0) == FNM_NOMATCH); assert(rl_fnmatch("*.[Jj]*[Gg]", "test.jPg", 0) == 0);
assert(rl_fnmatch("TES[asd", "TEST", 0) == FNM_NOMATCH); assert(rl_fnmatch("TEST?", "TEST", 0) == FNM_NOMATCH);
assert(rl_fnmatch("TEST\\", "TEST", 0) == FNM_NOMATCH); assert(rl_fnmatch("TES[asd", "TEST", 0) == FNM_NOMATCH);
assert(rl_fnmatch("TEST*S", "TEST", 0) == FNM_NOMATCH); assert(rl_fnmatch("TEST\\", "TEST", 0) == FNM_NOMATCH);
assert(rl_fnmatch("TE**ST", "TExT", 0) == FNM_NOMATCH); assert(rl_fnmatch("TEST*S", "TEST", 0) == FNM_NOMATCH);
assert(rl_fnmatch("TE\\*T", "TExT", 0) == FNM_NOMATCH); assert(rl_fnmatch("TE**ST", "TExT", 0) == FNM_NOMATCH);
assert(rl_fnmatch("TES?", "TES", 0) == FNM_NOMATCH); assert(rl_fnmatch("TE\\*T", "TExT", 0) == FNM_NOMATCH);
assert(rl_fnmatch("TE", "TEST", 0) == FNM_NOMATCH); assert(rl_fnmatch("TES?", "TES", 0) == FNM_NOMATCH);
assert(rl_fnmatch("TEST!", "TEST", 0) == FNM_NOMATCH); assert(rl_fnmatch("TE", "TEST", 0) == FNM_NOMATCH);
assert(rl_fnmatch("DSAD", "TEST", 0) == FNM_NOMATCH); assert(rl_fnmatch("TEST!", "TEST", 0) == FNM_NOMATCH);
assert(rl_fnmatch("DSAD", "TEST", 0) == FNM_NOMATCH);
} }
#endif #endif

View File

@ -43,329 +43,210 @@
/* /*
* Define the circular shift macro * Define the circular shift macro
*/ */
#define SHA1CircularShift(bits,word) \ #define SHA1CircularShift(bits,word) ((((word) << (bits)) & 0xFFFFFFFF) | ((word) >> (32-(bits))))
((((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) void SHA1Reset(SHA1Context *context)
{ {
context->Length_Low = 0; context->Length_Low = 0;
context->Length_High = 0; context->Length_High = 0;
context->Message_Block_Index = 0; context->Message_Block_Index = 0;
context->Message_Digest[0] = 0x67452301; context->Message_Digest[0] = 0x67452301;
context->Message_Digest[1] = 0xEFCDAB89; context->Message_Digest[1] = 0xEFCDAB89;
context->Message_Digest[2] = 0x98BADCFE; context->Message_Digest[2] = 0x98BADCFE;
context->Message_Digest[3] = 0x10325476; context->Message_Digest[3] = 0x10325476;
context->Message_Digest[4] = 0xC3D2E1F0; context->Message_Digest[4] = 0xC3D2E1F0;
context->Computed = 0; context->Computed = 0;
context->Corrupted = 0; context->Corrupted = 0;
}
void SHA1ProcessMessageBlock(SHA1Context *context)
{
const unsigned K[] = /* Constants defined in SHA-1 */
{
0x5A827999,
0x6ED9EBA1,
0x8F1BBCDC,
0xCA62C1D6
};
int t; /* Loop counter */
unsigned temp; /* Temporary word value */
unsigned W[80]; /* Word sequence */
unsigned A, B, C, D, E; /* Word buffers */
/*
* Initialize the first 16 words in the array W
*/
for(t = 0; t < 16; t++)
{
W[t] = ((unsigned) context->Message_Block[t * 4]) << 24;
W[t] |= ((unsigned) context->Message_Block[t * 4 + 1]) << 16;
W[t] |= ((unsigned) context->Message_Block[t * 4 + 2]) << 8;
W[t] |= ((unsigned) context->Message_Block[t * 4 + 3]);
}
for(t = 16; t < 80; t++)
{
W[t] = SHA1CircularShift(1,W[t-3] ^ W[t-8] ^ W[t-14] ^ W[t-16]);
}
A = context->Message_Digest[0];
B = context->Message_Digest[1];
C = context->Message_Digest[2];
D = context->Message_Digest[3];
E = context->Message_Digest[4];
for(t = 0; t < 20; t++)
{
temp = SHA1CircularShift(5,A) +
((B & C) | ((~B) & D)) + E + W[t] + K[0];
temp &= 0xFFFFFFFF;
E = D;
D = C;
C = SHA1CircularShift(30,B);
B = A;
A = temp;
}
for(t = 20; t < 40; t++)
{
temp = SHA1CircularShift(5,A) + (B ^ C ^ D) + E + W[t] + K[1];
temp &= 0xFFFFFFFF;
E = D;
D = C;
C = SHA1CircularShift(30,B);
B = A;
A = temp;
}
for(t = 40; t < 60; t++)
{
temp = SHA1CircularShift(5,A) +
((B & C) | (B & D) | (C & D)) + E + W[t] + K[2];
temp &= 0xFFFFFFFF;
E = D;
D = C;
C = SHA1CircularShift(30,B);
B = A;
A = temp;
}
for(t = 60; t < 80; t++)
{
temp = SHA1CircularShift(5,A) + (B ^ C ^ D) + E + W[t] + K[3];
temp &= 0xFFFFFFFF;
E = D;
D = C;
C = SHA1CircularShift(30,B);
B = A;
A = temp;
}
context->Message_Digest[0] =
(context->Message_Digest[0] + A) & 0xFFFFFFFF;
context->Message_Digest[1] =
(context->Message_Digest[1] + B) & 0xFFFFFFFF;
context->Message_Digest[2] =
(context->Message_Digest[2] + C) & 0xFFFFFFFF;
context->Message_Digest[3] =
(context->Message_Digest[3] + D) & 0xFFFFFFFF;
context->Message_Digest[4] =
(context->Message_Digest[4] + E) & 0xFFFFFFFF;
context->Message_Block_Index = 0;
}
void SHA1PadMessage(SHA1Context *context)
{
/*
* Check to see if the current message block is too small to hold
* the initial padding bits and length. If so, we will pad the
* block, process it, and then continue padding into a second
* block.
*/
if (context->Message_Block_Index > 55)
{
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
*/
context->Message_Block[56] = (context->Length_High >> 24) & 0xFF;
context->Message_Block[57] = (context->Length_High >> 16) & 0xFF;
context->Message_Block[58] = (context->Length_High >> 8) & 0xFF;
context->Message_Block[59] = (context->Length_High) & 0xFF;
context->Message_Block[60] = (context->Length_Low >> 24) & 0xFF;
context->Message_Block[61] = (context->Length_Low >> 16) & 0xFF;
context->Message_Block[62] = (context->Length_Low >> 8) & 0xFF;
context->Message_Block[63] = (context->Length_Low) & 0xFF;
SHA1ProcessMessageBlock(context);
} }
/*
* 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) int SHA1Result(SHA1Context *context)
{ {
if (context->Corrupted)
return 0;
if (context->Corrupted) if (!context->Computed)
{ {
return 0; SHA1PadMessage(context);
} context->Computed = 1;
}
if (!context->Computed) return 1;
{
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, void SHA1Input( SHA1Context *context,
const unsigned char *message_array, const unsigned char *message_array,
unsigned length) unsigned length)
{ {
if (!length) if (!length)
{ return;
return;
}
if (context->Computed || context->Corrupted) if (context->Computed || context->Corrupted)
{ {
context->Corrupted = 1; context->Corrupted = 1;
return; return;
} }
while(length-- && !context->Corrupted) while(length-- && !context->Corrupted)
{ {
context->Message_Block[context->Message_Block_Index++] = context->Message_Block[context->Message_Block_Index++] =
(*message_array & 0xFF); (*message_array & 0xFF);
context->Length_Low += 8; context->Length_Low += 8;
/* Force it to 32 bits */ /* Force it to 32 bits */
context->Length_Low &= 0xFFFFFFFF; context->Length_Low &= 0xFFFFFFFF;
if (context->Length_Low == 0) if (context->Length_Low == 0)
{ {
context->Length_High++; context->Length_High++;
/* Force it to 32 bits */ /* Force it to 32 bits */
context->Length_High &= 0xFFFFFFFF; context->Length_High &= 0xFFFFFFFF;
if (context->Length_High == 0) if (context->Length_High == 0)
{ context->Corrupted = 1; /* Message is too long */
/* Message is too long */ }
context->Corrupted = 1;
}
}
if (context->Message_Block_Index == 64) if (context->Message_Block_Index == 64)
{ SHA1ProcessMessageBlock(context);
SHA1ProcessMessageBlock(context);
}
message_array++; 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 */
{
0x5A827999,
0x6ED9EBA1,
0x8F1BBCDC,
0xCA62C1D6
};
int t; /* Loop counter */
unsigned temp; /* Temporary word value */
unsigned W[80]; /* Word sequence */
unsigned A, B, C, D, E; /* Word buffers */
/*
* Initialize the first 16 words in the array W
*/
for(t = 0; t < 16; t++)
{
W[t] = ((unsigned) context->Message_Block[t * 4]) << 24;
W[t] |= ((unsigned) context->Message_Block[t * 4 + 1]) << 16;
W[t] |= ((unsigned) context->Message_Block[t * 4 + 2]) << 8;
W[t] |= ((unsigned) context->Message_Block[t * 4 + 3]);
}
for(t = 16; t < 80; t++)
{
W[t] = SHA1CircularShift(1,W[t-3] ^ W[t-8] ^ W[t-14] ^ W[t-16]);
}
A = context->Message_Digest[0];
B = context->Message_Digest[1];
C = context->Message_Digest[2];
D = context->Message_Digest[3];
E = context->Message_Digest[4];
for(t = 0; t < 20; t++)
{
temp = SHA1CircularShift(5,A) +
((B & C) | ((~B) & D)) + E + W[t] + K[0];
temp &= 0xFFFFFFFF;
E = D;
D = C;
C = SHA1CircularShift(30,B);
B = A;
A = temp;
}
for(t = 20; t < 40; t++)
{
temp = SHA1CircularShift(5,A) + (B ^ C ^ D) + E + W[t] + K[1];
temp &= 0xFFFFFFFF;
E = D;
D = C;
C = SHA1CircularShift(30,B);
B = A;
A = temp;
}
for(t = 40; t < 60; t++)
{
temp = SHA1CircularShift(5,A) +
((B & C) | (B & D) | (C & D)) + E + W[t] + K[2];
temp &= 0xFFFFFFFF;
E = D;
D = C;
C = SHA1CircularShift(30,B);
B = A;
A = temp;
}
for(t = 60; t < 80; t++)
{
temp = SHA1CircularShift(5,A) + (B ^ C ^ D) + E + W[t] + K[3];
temp &= 0xFFFFFFFF;
E = D;
D = C;
C = SHA1CircularShift(30,B);
B = A;
A = temp;
}
context->Message_Digest[0] =
(context->Message_Digest[0] + A) & 0xFFFFFFFF;
context->Message_Digest[1] =
(context->Message_Digest[1] + B) & 0xFFFFFFFF;
context->Message_Digest[2] =
(context->Message_Digest[2] + C) & 0xFFFFFFFF;
context->Message_Digest[3] =
(context->Message_Digest[3] + D) & 0xFFFFFFFF;
context->Message_Digest[4] =
(context->Message_Digest[4] + E) & 0xFFFFFFFF;
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)
{
/*
* Check to see if the current message block is too small to hold
* the initial padding bits and length. If so, we will pad the
* block, process it, and then continue padding into a second
* block.
*/
if (context->Message_Block_Index > 55)
{
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
*/
context->Message_Block[56] = (context->Length_High >> 24) & 0xFF;
context->Message_Block[57] = (context->Length_High >> 16) & 0xFF;
context->Message_Block[58] = (context->Length_High >> 8) & 0xFF;
context->Message_Block[59] = (context->Length_High) & 0xFF;
context->Message_Block[60] = (context->Length_Low >> 24) & 0xFF;
context->Message_Block[61] = (context->Length_Low >> 16) & 0xFF;
context->Message_Block[62] = (context->Length_Low >> 8) & 0xFF;
context->Message_Block[63] = (context->Length_Low) & 0xFF;
SHA1ProcessMessageBlock(context);
}