mirror of
https://github.com/libretro/RetroArch.git
synced 2024-11-23 16:09:47 +00:00
task_database: more scanning rework
- Use the primary (largest data) track for CRC identification, as it seems least likely to be shared among multiple discs - CRC the primary track when importing a loose .cue file. - If multiple tracks are in the same file, CRC the correct chunk
This commit is contained in:
parent
5b20c13f92
commit
fa6d0fac67
@ -68,8 +68,8 @@ typedef struct db_handle
|
||||
bool scan_started;
|
||||
} db_handle_t;
|
||||
|
||||
int find_first_data_track(const char* cue_path,
|
||||
int32_t* offset, char* track_path, size_t max_len);
|
||||
int find_track(const char *cue_path, bool first, size_t *offset, size_t *size,
|
||||
char *track_path, size_t max_len);
|
||||
|
||||
int detect_system(intfstream_t *fd, const char** system_name);
|
||||
|
||||
@ -99,7 +99,34 @@ static intfstream_t* open_file(const char *path)
|
||||
return fd;
|
||||
}
|
||||
|
||||
static intfstream_t *open_chd_track(const char *path, int32_t track)
|
||||
static intfstream_t*
|
||||
open_memory(void *data, size_t size)
|
||||
{
|
||||
intfstream_info_t info;
|
||||
intfstream_t *fd = NULL;
|
||||
|
||||
info.type = INTFSTREAM_MEMORY;
|
||||
info.memory.buf.data = data;
|
||||
info.memory.buf.size = size;
|
||||
info.memory.writable = false;
|
||||
|
||||
fd = intfstream_init(&info);
|
||||
if (!fd)
|
||||
{
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (!intfstream_open(fd, NULL, RFILE_MODE_READ, -1))
|
||||
{
|
||||
intfstream_close(fd);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
return fd;
|
||||
}
|
||||
|
||||
static intfstream_t*
|
||||
open_chd_track(const char *path, int32_t track)
|
||||
{
|
||||
intfstream_info_t info;
|
||||
intfstream_t *fd = NULL;
|
||||
@ -186,75 +213,98 @@ static int task_database_iterate_start(database_info_handle_t *db,
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int stream_get_serial(database_state_handle_t *db_state,
|
||||
database_info_handle_t *db, intfstream_t *fd, char* serial)
|
||||
static int stream_get_serial(intfstream_t *fd, char *serial)
|
||||
{
|
||||
const char* system_name = NULL;
|
||||
const char *system_name = NULL;
|
||||
|
||||
/* Check if the system was not auto-detected. */
|
||||
if (detect_system(fd, &system_name) < 0)
|
||||
{
|
||||
/* Attempt to read an ASCII serial, like Wii. */
|
||||
if (detect_serial_ascii_game(fd, serial))
|
||||
{
|
||||
/* ASCII serial (Wii) was detected. */
|
||||
RARCH_LOG("%s '%s'\n",
|
||||
msg_hash_to_str(MSG_FOUND_DISK_LABEL), serial);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Any other non-system specific detection methods? */
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (string_is_equal_fast(system_name, "psp", 3))
|
||||
{
|
||||
if (detect_psp_game(fd, serial) == 0)
|
||||
return 0;
|
||||
/* Check if the system was not auto-detected. */
|
||||
if (detect_system(fd, &system_name) < 0)
|
||||
{
|
||||
/* Attempt to read an ASCII serial, like Wii. */
|
||||
if (detect_serial_ascii_game(fd, serial))
|
||||
{
|
||||
/* ASCII serial (Wii) was detected. */
|
||||
RARCH_LOG("%s '%s'\n", msg_hash_to_str(MSG_FOUND_DISK_LABEL), serial);
|
||||
}
|
||||
else if (string_is_equal_fast(system_name, "ps1", 3))
|
||||
{
|
||||
if (detect_ps1_game(fd, serial) == 0)
|
||||
return 0;
|
||||
RARCH_LOG("%s '%s'\n", msg_hash_to_str(MSG_FOUND_DISK_LABEL), serial);
|
||||
}
|
||||
else
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
return 1;
|
||||
/* Any other non-system specific detection methods? */
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (string_is_equal_fast(system_name, "psp", 3))
|
||||
{
|
||||
if (detect_psp_game(fd, serial) == 0)
|
||||
return 0;
|
||||
RARCH_LOG("%s '%s'\n", msg_hash_to_str(MSG_FOUND_DISK_LABEL), serial);
|
||||
}
|
||||
else if (string_is_equal_fast(system_name, "ps1", 3))
|
||||
{
|
||||
if (detect_ps1_game(fd, serial) == 0)
|
||||
return 0;
|
||||
RARCH_LOG("%s '%s'\n", msg_hash_to_str(MSG_FOUND_DISK_LABEL), serial);
|
||||
}
|
||||
else {
|
||||
return 0;
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int iso_get_serial(database_state_handle_t *db_state,
|
||||
database_info_handle_t *db, const char *name, char* serial)
|
||||
static bool file_get_serial(const char *name, size_t offset, size_t size, char *serial)
|
||||
{
|
||||
intfstream_t *fd = open_file(name);
|
||||
int rv;
|
||||
uint8_t *data = NULL;
|
||||
ssize_t file_size = -1;
|
||||
|
||||
if (!fd)
|
||||
return 0;
|
||||
|
||||
rv = stream_get_serial(db_state, db, fd, serial);
|
||||
intfstream_seek(fd, 0, SEEK_END);
|
||||
file_size = intfstream_tell(fd);
|
||||
intfstream_seek(fd, 0, SEEK_SET);
|
||||
if (file_size < 0) {
|
||||
intfstream_close(fd);
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (offset != 0 || size < (size_t) file_size)
|
||||
{
|
||||
data = malloc(size);
|
||||
intfstream_seek(fd, offset, SEEK_SET);
|
||||
if (intfstream_read(fd, data, size) != (ssize_t) size)
|
||||
{
|
||||
intfstream_close(fd);
|
||||
free(data);
|
||||
return 0;
|
||||
}
|
||||
intfstream_close(fd);
|
||||
fd = open_memory(data, size);
|
||||
if (!fd) {
|
||||
free(data);
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
rv = stream_get_serial(fd, serial);
|
||||
intfstream_close(fd);
|
||||
free(fd);
|
||||
free(data);
|
||||
return rv;
|
||||
}
|
||||
|
||||
static int cue_get_serial(database_state_handle_t *db_state,
|
||||
database_info_handle_t *db, const char *name, char* serial)
|
||||
static int cue_get_serial(const char *name, char* serial)
|
||||
{
|
||||
char *track_path = (char*)malloc(PATH_MAX_LENGTH
|
||||
* sizeof(char));
|
||||
int ret = 0;
|
||||
int32_t offset = 0;
|
||||
size_t offset = 0;
|
||||
size_t size = 0;
|
||||
int rv = 0;
|
||||
|
||||
track_path[0] = '\0';
|
||||
|
||||
rv = find_first_data_track(name,
|
||||
&offset, track_path, PATH_MAX_LENGTH);
|
||||
rv = find_track(name, true, &offset, &size, track_path, PATH_MAX_LENGTH);
|
||||
|
||||
if (rv < 0)
|
||||
{
|
||||
@ -267,14 +317,13 @@ static int cue_get_serial(database_state_handle_t *db_state,
|
||||
|
||||
RARCH_LOG("%s\n", msg_hash_to_str(MSG_READING_FIRST_DATA_TRACK));
|
||||
|
||||
ret = iso_get_serial(db_state, db, track_path, serial);
|
||||
ret = file_get_serial(track_path, offset, size, serial);
|
||||
free(track_path);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int chd_get_serial(database_state_handle_t *db_state,
|
||||
database_info_handle_t *db, const char *name, char* serial)
|
||||
static int chd_get_serial(const char *name, char* serial)
|
||||
{
|
||||
intfstream_t *fd = NULL;
|
||||
int result;
|
||||
@ -285,54 +334,125 @@ static int chd_get_serial(database_state_handle_t *db_state,
|
||||
return 0;
|
||||
}
|
||||
|
||||
result = stream_get_serial(db_state, db, fd, serial);
|
||||
result = stream_get_serial(fd, serial);
|
||||
intfstream_close(fd);
|
||||
return result;
|
||||
}
|
||||
|
||||
static bool file_get_crc(database_state_handle_t *db_state,
|
||||
const char *name, uint32_t *crc)
|
||||
static int stream_get_crc(intfstream_t *fd, uint32_t *crc)
|
||||
{
|
||||
ssize_t ret;
|
||||
int read_from = filestream_read_file(
|
||||
name, (void**)&db_state->buf, &ret);
|
||||
size_t read = 0;
|
||||
uint32_t acc = 0;
|
||||
uint8_t buffer[4096];
|
||||
|
||||
if (read_from != 1 || ret <= 0)
|
||||
while ((read = intfstream_read(fd, buffer, sizeof(buffer))) > 0)
|
||||
{
|
||||
acc = encoding_crc32(acc, buffer, read);
|
||||
}
|
||||
|
||||
if (read < 0)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
*crc = encoding_crc32(0, db_state->buf, ret);
|
||||
*crc = acc;
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
static bool chd_get_crc(database_state_handle_t *db_state,
|
||||
const char *name, uint32_t *crc)
|
||||
static bool file_get_crc(const char *name, size_t offset, size_t size, uint32_t *crc)
|
||||
{
|
||||
intfstream_t *fd = NULL;
|
||||
uint32_t acc = 0;
|
||||
uint8_t buffer[4096];
|
||||
ssize_t size;
|
||||
intfstream_t *fd = open_file(name);
|
||||
int rv;
|
||||
uint8_t *data = NULL;
|
||||
ssize_t file_size = -1;
|
||||
|
||||
fd = open_chd_track(name, CHDSTREAM_TRACK_FIRST_DATA);
|
||||
if (!fd)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
while ((size = intfstream_read(fd, buffer, sizeof(buffer))) > 0)
|
||||
{
|
||||
acc = encoding_crc32(acc, buffer, size);
|
||||
intfstream_seek(fd, 0, SEEK_END);
|
||||
file_size = intfstream_tell(fd);
|
||||
intfstream_seek(fd, 0, SEEK_SET);
|
||||
if (file_size < 0) {
|
||||
intfstream_close(fd);
|
||||
return 0;
|
||||
}
|
||||
if (size < 0)
|
||||
|
||||
if (offset != 0 || size < (size_t) file_size) {
|
||||
data = malloc(size);
|
||||
intfstream_seek(fd, offset, SEEK_SET);
|
||||
if (intfstream_read(fd, data, size) != (ssize_t) size) {
|
||||
intfstream_close(fd);
|
||||
free(data);
|
||||
return 0;
|
||||
}
|
||||
intfstream_close(fd);
|
||||
fd = open_memory(data, size);
|
||||
if (!fd) {
|
||||
free(data);
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
rv = stream_get_crc(fd, crc);
|
||||
intfstream_close(fd);
|
||||
free(data);
|
||||
return rv;
|
||||
}
|
||||
|
||||
static int cue_get_crc(const char *name, uint32_t *crc)
|
||||
{
|
||||
char *track_path = (char *)malloc(PATH_MAX_LENGTH);
|
||||
int ret = 0;
|
||||
size_t offset = 0;
|
||||
size_t size = 0;
|
||||
int rv = 0;
|
||||
|
||||
track_path[0] = '\0';
|
||||
|
||||
rv = find_track(name, false, &offset, &size, track_path, PATH_MAX_LENGTH);
|
||||
|
||||
if (rv < 0) {
|
||||
RARCH_LOG("%s: %s\n", msg_hash_to_str(MSG_COULD_NOT_FIND_VALID_DATA_TRACK),
|
||||
strerror(-rv));
|
||||
free(track_path);
|
||||
return 0;
|
||||
}
|
||||
|
||||
RARCH_LOG("CUE '%s' primary track: %s\n (%Zu, %Zu)", name, track_path, offset, size);
|
||||
|
||||
RARCH_LOG("%s\n", msg_hash_to_str(MSG_READING_FIRST_DATA_TRACK));
|
||||
|
||||
rv = file_get_crc(track_path, offset, size, crc);
|
||||
if (rv == 1) {
|
||||
RARCH_LOG("CUE '%s' crc: %x\n", name, *crc);
|
||||
}
|
||||
free(track_path);
|
||||
return rv;
|
||||
}
|
||||
|
||||
static bool chd_get_crc(const char *name, uint32_t *crc)
|
||||
{
|
||||
intfstream_t *fd = NULL;
|
||||
int rv;
|
||||
uint32_t acc = 0;
|
||||
uint8_t buffer[4096];
|
||||
ssize_t size;
|
||||
|
||||
fd = open_chd_track(name, CHDSTREAM_TRACK_PRIMARY);
|
||||
if (!fd)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
RARCH_LOG("CHD '%s' crc: %x\n", name, acc);
|
||||
|
||||
*crc = acc;
|
||||
|
||||
return 1;
|
||||
rv = stream_get_crc(fd, crc);
|
||||
if (rv == 1) {
|
||||
RARCH_LOG("CHD '%s' crc: %x\n", name, *crc);
|
||||
}
|
||||
intfstream_close(fd);
|
||||
return rv;
|
||||
}
|
||||
|
||||
static int task_database_iterate_playlist(
|
||||
@ -345,37 +465,37 @@ static int task_database_iterate_playlist(
|
||||
#ifdef HAVE_COMPRESSION
|
||||
database_info_set_type(db, DATABASE_TYPE_CRC_LOOKUP);
|
||||
/* first check crc of archive itself */
|
||||
return file_get_crc(db_state, name, &db_state->archive_crc);
|
||||
return file_get_crc(name, 0, SIZE_MAX, &db_state->archive_crc);
|
||||
#else
|
||||
break;
|
||||
#endif
|
||||
case FILE_TYPE_CUE:
|
||||
db_state->serial[0] = '\0';
|
||||
if (cue_get_serial(db_state, db, name, db_state->serial))
|
||||
if (cue_get_serial(name, db_state->serial))
|
||||
{
|
||||
database_info_set_type(db, DATABASE_TYPE_SERIAL_LOOKUP);
|
||||
}
|
||||
else
|
||||
{
|
||||
database_info_set_type(db, DATABASE_TYPE_CRC_LOOKUP);
|
||||
return file_get_crc(db_state, name, &db_state->crc);
|
||||
return cue_get_crc(name, &db_state->crc);
|
||||
}
|
||||
break;
|
||||
case FILE_TYPE_ISO:
|
||||
db_state->serial[0] = '\0';
|
||||
iso_get_serial(db_state, db, name, db_state->serial);
|
||||
file_get_serial(name, 0, SIZE_MAX, db_state->serial);
|
||||
database_info_set_type(db, DATABASE_TYPE_SERIAL_LOOKUP);
|
||||
break;
|
||||
case FILE_TYPE_CHD:
|
||||
db_state->serial[0] = '\0';
|
||||
if (chd_get_serial(db_state, db, name, db_state->serial))
|
||||
if (chd_get_serial(name, db_state->serial))
|
||||
{
|
||||
database_info_set_type(db, DATABASE_TYPE_SERIAL_LOOKUP);
|
||||
}
|
||||
else
|
||||
{
|
||||
database_info_set_type(db, DATABASE_TYPE_CRC_LOOKUP);
|
||||
return chd_get_crc(db_state, name, &db_state->crc);
|
||||
return chd_get_crc(name, &db_state->crc);
|
||||
}
|
||||
break;
|
||||
case FILE_TYPE_LUTRO:
|
||||
@ -383,7 +503,7 @@ static int task_database_iterate_playlist(
|
||||
break;
|
||||
default:
|
||||
database_info_set_type(db, DATABASE_TYPE_CRC_LOOKUP);
|
||||
return file_get_crc(db_state, name, &db_state->crc);
|
||||
return file_get_crc(name, 0, SIZE_MAX, &db_state->crc);
|
||||
}
|
||||
|
||||
return 1;
|
||||
|
@ -124,29 +124,6 @@ static ssize_t get_token(intfstream_t *fd, char *token, size_t max_len)
|
||||
}
|
||||
}
|
||||
|
||||
static int find_token(intfstream_t *fd, const char *token)
|
||||
{
|
||||
int tmp_len = (int)strlen(token);
|
||||
char *tmp_token = (char*)calloc(tmp_len+1, 1);
|
||||
|
||||
if (!tmp_token)
|
||||
return -1;
|
||||
|
||||
while (strncmp(tmp_token, token, tmp_len) != 0)
|
||||
{
|
||||
if (get_token(fd, tmp_token, tmp_len) <= 0)
|
||||
{
|
||||
free(tmp_token);
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
free(tmp_token);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
static int detect_ps1_game_sub(intfstream_t *fp,
|
||||
char *game_id, int sub_channel_mixed)
|
||||
{
|
||||
@ -402,13 +379,51 @@ clean:
|
||||
return rv;
|
||||
}
|
||||
|
||||
int find_first_data_track(const char *cue_path,
|
||||
int32_t *offset, char *track_path, size_t max_len)
|
||||
static ssize_t get_file_size(const char *path)
|
||||
{
|
||||
ssize_t rv;
|
||||
RFILE *fd = filestream_open(path, RFILE_MODE_READ, -1);
|
||||
if (fd == NULL) {
|
||||
return -1;
|
||||
}
|
||||
rv = filestream_get_size(fd);
|
||||
filestream_close(fd);
|
||||
return rv;
|
||||
}
|
||||
|
||||
static bool update_cand(ssize_t *cand_index, ssize_t *last_index,
|
||||
size_t *largest, char *last_file, size_t *offset,
|
||||
size_t *size, char *track_path, size_t max_len)
|
||||
{
|
||||
if (*cand_index != -1) {
|
||||
if (*last_index - *cand_index > *largest) {
|
||||
*largest = *last_index - *cand_index;
|
||||
strlcpy(track_path, last_file, max_len);
|
||||
*offset = *cand_index;
|
||||
*size = *largest;
|
||||
*cand_index = -1;
|
||||
return true;
|
||||
}
|
||||
*cand_index = -1;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
int find_track(const char *cue_path, bool first,
|
||||
size_t *offset, size_t *size, char *track_path, size_t max_len)
|
||||
{
|
||||
int rv;
|
||||
char *tmp_token = malloc(MAX_TOKEN_LEN);
|
||||
char *last_file = malloc(PATH_MAX_LENGTH + 1);
|
||||
intfstream_info_t info;
|
||||
intfstream_t *fd = NULL;
|
||||
char * tmp_token = malloc(MAX_TOKEN_LEN * sizeof(char));
|
||||
ssize_t last_index = -1;
|
||||
ssize_t cand_index = -1;
|
||||
int32_t cand_track = -1;
|
||||
int32_t track = 0;
|
||||
size_t largest = 0;
|
||||
ssize_t volatile file_size = -1;
|
||||
bool is_data = false;
|
||||
|
||||
info.type = INTFSTREAM_FILE;
|
||||
|
||||
@ -429,56 +444,94 @@ int find_first_data_track(const char *cue_path,
|
||||
|
||||
tmp_token[0] = '\0';
|
||||
|
||||
rv = -EINVAL;
|
||||
|
||||
while (get_token(fd, tmp_token, MAX_TOKEN_LEN) > 0)
|
||||
{
|
||||
if (string_is_equal(tmp_token, "FILE"))
|
||||
{
|
||||
char *cue_dir = (char*)malloc(PATH_MAX_LENGTH * sizeof(char));
|
||||
|
||||
char *cue_dir = (char*)malloc(PATH_MAX_LENGTH);
|
||||
cue_dir[0] = '\0';
|
||||
|
||||
fill_pathname_basedir(cue_dir, cue_path, PATH_MAX_LENGTH * sizeof(char));
|
||||
/* Set last index to last EOF */
|
||||
if (file_size != -1) {
|
||||
last_index = file_size;
|
||||
}
|
||||
|
||||
/* We're changing files since the candidate, update it */
|
||||
if (update_cand(&cand_index, &last_index, &largest, last_file, offset,
|
||||
size, track_path, max_len)) {
|
||||
rv = 0;
|
||||
if (first) {
|
||||
goto clean;
|
||||
}
|
||||
}
|
||||
|
||||
fill_pathname_basedir(cue_dir, cue_path, PATH_MAX_LENGTH);
|
||||
|
||||
get_token(fd, tmp_token, MAX_TOKEN_LEN);
|
||||
fill_pathname_join(track_path, cue_dir, tmp_token, max_len);
|
||||
fill_pathname_join(last_file, cue_dir, tmp_token, PATH_MAX_LENGTH);
|
||||
|
||||
file_size = get_file_size(last_file);
|
||||
|
||||
free(cue_dir);
|
||||
get_token(fd, tmp_token, MAX_TOKEN_LEN);
|
||||
|
||||
}
|
||||
else if (string_is_equal(tmp_token, "TRACK"))
|
||||
{
|
||||
get_token(fd, tmp_token, MAX_TOKEN_LEN);
|
||||
get_token(fd, tmp_token, MAX_TOKEN_LEN);
|
||||
is_data = !string_is_equal(tmp_token, "AUDIO");
|
||||
++track;
|
||||
} else if (string_is_equal(tmp_token, "INDEX")) {
|
||||
int m, s, f;
|
||||
get_token(fd, tmp_token, MAX_TOKEN_LEN);
|
||||
get_token(fd, tmp_token, MAX_TOKEN_LEN);
|
||||
|
||||
if (string_is_equal(tmp_token, "AUDIO"))
|
||||
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)
|
||||
{
|
||||
RARCH_LOG("Error parsing time stamp '%s'\n", tmp_token);
|
||||
goto error;
|
||||
}
|
||||
|
||||
*offset = ((m * 60) * (s * 75) * f) * 25;
|
||||
last_index = (size_t) (((m * 60 + s) * 75) + f) * 2352;
|
||||
|
||||
rv = 0;
|
||||
goto clean;
|
||||
/* If we've changed tracks since the candidate, update it */
|
||||
if (cand_track != -1 && track != cand_track &&
|
||||
update_cand(&cand_index, &last_index, &largest, last_file, offset,
|
||||
size, track_path, max_len)) {
|
||||
rv = 0;
|
||||
if (first) {
|
||||
goto clean;
|
||||
}
|
||||
}
|
||||
|
||||
if (!is_data) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (cand_index == -1) {
|
||||
cand_index = last_index;
|
||||
cand_track = track;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
rv = -EINVAL;
|
||||
if (update_cand(&cand_index, &last_index, &largest, last_file, offset,
|
||||
size, track_path, max_len)) {
|
||||
rv = 0;
|
||||
}
|
||||
|
||||
clean:
|
||||
free(tmp_token);
|
||||
free(last_file);
|
||||
intfstream_close(fd);
|
||||
return rv;
|
||||
|
||||
error:
|
||||
free(tmp_token);
|
||||
free(last_file);
|
||||
if (fd)
|
||||
intfstream_close(fd);
|
||||
return -errno;
|
||||
|
Loading…
Reference in New Issue
Block a user