Merge pull request #5447 from bkoropoff/scanning2

More scanning rework
This commit is contained in:
Twinaphex 2017-09-19 15:46:04 +02:00 committed by GitHub
commit ee06a8f175
7 changed files with 735 additions and 140 deletions

View File

@ -398,6 +398,31 @@ static int database_cursor_close(libretrodb_t *db, libretrodb_cursor_t *cur)
return 0;
}
static bool type_is_prioritized(enum msg_file_type type)
{
return (type == FILE_TYPE_CUE || type == FILE_TYPE_GDI);
}
static enum msg_file_type file_type(const char *path)
{
return msg_hash_to_file_type(msg_hash_calculate(path_get_extension(path)));
}
static int dir_entry_compare(const void *left, const void *right)
{
const struct string_list_elem *le = left;
const struct string_list_elem *re = right;
bool l = type_is_prioritized(file_type(le->data));
bool r = type_is_prioritized(file_type(re->data));
return (int) r - (int) l;
}
static void dir_list_prioritize(struct string_list *list)
{
qsort(list->elems, list->size, sizeof(*list->elems), dir_entry_compare);
}
database_info_handle_t *database_info_dir_init(const char *dir,
enum database_type type, retro_task_t *task)
{
@ -413,6 +438,8 @@ database_info_handle_t *database_info_dir_init(const char *dir,
if (!db->list)
goto error;
dir_list_prioritize(db->list);
db->list_ptr = 0;
db->status = DATABASE_STATUS_ITERATE;
db->type = type;

View File

@ -32,8 +32,12 @@ RETRO_BEGIN_DECLS
typedef struct chdstream chdstream_t;
// First data track
#define CHDSTREAM_TRACK_FIRST_DATA (-1)
// Last track
#define CHDSTREAM_TRACK_LAST (-2)
// Primary (largest) data track, used for CRC identification purposes
#define CHDSTREAM_TRACK_PRIMARY (-3)
chdstream_t *chdstream_open(const char *path, int32_t track);

View File

@ -82,10 +82,12 @@ chdstream_get_meta(chd_file *chd, int idx, metadata_t *md)
{
char meta[256];
uint32_t meta_size = 0;
chd_error err = chd_get_metadata(
chd, CDROM_TRACK_METADATA2_TAG, idx, meta,
sizeof(meta), &meta_size, NULL, NULL);
chd_error err;
memset(md, 0, sizeof(*md));
err = chd_get_metadata(chd, CDROM_TRACK_METADATA2_TAG, idx, meta,
sizeof(meta), &meta_size, NULL, NULL);
if (err == CHDERR_NONE)
{
sscanf(meta, CDROM_TRACK_METADATA2_FORMAT,
@ -101,8 +103,19 @@ chdstream_get_meta(chd_file *chd, int idx, metadata_t *md)
sizeof(meta), &meta_size, NULL, NULL);
if (err == CHDERR_NONE)
{
sscanf(meta, CDROM_TRACK_METADATA_FORMAT,
&md->track, md->type, md->subtype, &md->frames);
sscanf(meta, CDROM_TRACK_METADATA_FORMAT, &md->track, md->type,
md->subtype, &md->frames);
md->extra = padding_frames(md->frames);
return true;
}
err = chd_get_metadata(chd, GDROM_TRACK_METADATA_TAG, idx, meta,
sizeof(meta), &meta_size, NULL, NULL);
if (err == CHDERR_NONE)
{
sscanf(meta, GDROM_TRACK_METADATA_FORMAT, &md->track, md->type,
md->subtype, &md->frames, &md->pad, &md->pregap, md->pgtype,
md->pgsub, &md->postgap);
md->extra = padding_frames(md->frames);
return true;
}
@ -111,40 +124,84 @@ chdstream_get_meta(chd_file *chd, int idx, metadata_t *md)
}
static bool
chdstream_find_track(chd_file *fd, int32_t track, metadata_t *meta)
chdstream_find_track_number(chd_file *fd, int32_t track, metadata_t *meta)
{
uint32_t i;
memset(meta, 0, sizeof(*meta));
uint32_t frame_offset = 0;
for (i = 0; true; ++i)
{
if (!chdstream_get_meta(fd, i, meta))
{
if (track != CHDSTREAM_TRACK_LAST)
return false;
return false;
}
meta->frame_offset -= meta->frames + meta->extra;
if (track == meta->track)
{
meta->frame_offset = frame_offset;
return true;
}
if ((track == CHDSTREAM_TRACK_FIRST_DATA &&
strcmp(meta->type, "AUDIO")) ||
(track > 0 && track == meta->track))
return true;
frame_offset += meta->frames + meta->extra;
}
}
meta->frame_offset += meta->frames + meta->extra;
static bool
chdstream_find_special_track(chd_file *fd, int32_t track, metadata_t *meta)
{
int32_t i;
metadata_t iter;
int32_t largest_track = 0;
uint32_t largest_size = 0;
for (i = 1; true; ++i)
{
if (!chdstream_find_track_number(fd, i, &iter)) {
if (track == CHDSTREAM_TRACK_LAST && i > 1) {
*meta = iter;
return true;
} else if (track == CHDSTREAM_TRACK_PRIMARY && largest_track != 0) {
return chdstream_find_track_number(fd, largest_track, meta);
}
}
switch (track) {
case CHDSTREAM_TRACK_FIRST_DATA:
if (strcmp(iter.type, "AUDIO")) {
*meta = iter;
return true;
}
break;
case CHDSTREAM_TRACK_PRIMARY:
if (strcmp(iter.type, "AUDIO") && iter.frames > largest_size) {
largest_size = iter.frames;
largest_track = iter.track;
}
break;
default:
break;
}
}
}
static bool
chdstream_find_track(chd_file *fd, int32_t track, metadata_t *meta)
{
if (track < 0) {
return chdstream_find_special_track(fd, track, meta);
} else {
return chdstream_find_track_number(fd, track, meta);
}
}
chdstream_t *chdstream_open(const char *path, int32_t track)
{
metadata_t meta;
uint32_t pregap = 0;
const chd_header *hd = NULL;
chdstream_t *stream = NULL;
chd_file *chd = NULL;
chd_error err = chd_open(path, CHD_OPEN_READ, NULL, &chd);
metadata_t meta;
if (err != CHDERR_NONE)
goto error;

View File

@ -231,6 +231,8 @@ uint32_t msg_hash_calculate(const char *s)
#define HASH_EXTENSION_ZIP_UPP 0x0b883b78U
#define HASH_EXTENSION_CUE 0x0b886782U
#define HASH_EXTENSION_CUE_UPPERCASE 0x0b87db22U
#define HASH_EXTENSION_GDI 0x00b887659
#define HASH_EXTENSION_GDI_UPPERCASE 0x00b87e9f9
#define HASH_EXTENSION_ISO 0x0b8880d0U
#define HASH_EXTENSION_ISO_UPPERCASE 0x0b87f470U
#define HASH_EXTENSION_LUTRO 0x0fe37b7bU
@ -376,6 +378,9 @@ enum msg_file_type msg_hash_to_file_type(uint32_t hash)
case HASH_EXTENSION_CUE:
case HASH_EXTENSION_CUE_UPPERCASE:
return FILE_TYPE_CUE;
case HASH_EXTENSION_GDI:
case HASH_EXTENSION_GDI_UPPERCASE:
return FILE_TYPE_GDI;
case HASH_EXTENSION_ISO:
case HASH_EXTENSION_ISO_UPPERCASE:
return FILE_TYPE_ISO;

View File

@ -132,6 +132,7 @@ enum msg_file_type
FILE_TYPE_XM,
FILE_TYPE_CUE,
FILE_TYPE_GDI,
FILE_TYPE_ISO,
FILE_TYPE_LUTRO,
FILE_TYPE_CHD,

View File

@ -68,8 +68,14 @@ 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 cue_find_track(const char *cue_path, bool first, size_t *offset, size_t *size,
char *track_path, size_t max_len);
bool cue_next_file(intfstream_t *fd, const char *cue_path, char *path, size_t max_len);
int gdi_find_track(const char *gdi_path, bool first, char *track_path, size_t max_len);
bool gdi_next_file(intfstream_t *fd, const char *gdi_path, char *path, size_t max_len);
int detect_system(intfstream_t *fd, const char** system_name);
@ -99,7 +105,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;
@ -151,6 +184,12 @@ static const char *database_info_get_current_element_name(
{
if (!handle || !handle->list)
return NULL;
/* Skip pruned entries */
while (handle->list->elems[handle->list_ptr].data == NULL)
{
if (++handle->list_ptr >= handle->list->size)
return NULL;
}
return handle->list->elems[handle->list_ptr].data;
}
@ -186,75 +225,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 = cue_find_track(name, true, &offset, &size, track_path, PATH_MAX_LENGTH);
if (rv < 0)
{
@ -267,14 +329,41 @@ 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 gdi_get_serial(const char *name, char* serial)
{
char *track_path = (char*)malloc(PATH_MAX_LENGTH
* sizeof(char));
int ret = 0;
int rv = 0;
track_path[0] = '\0';
rv = gdi_find_track(name, true, 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("%s\n", msg_hash_to_str(MSG_READING_FIRST_DATA_TRACK));
ret = file_get_serial(track_path, 0, SIZE_MAX, serial);
free(track_path);
return ret;
}
static int chd_get_serial(const char *name, char* serial)
{
intfstream_t *fd = NULL;
int result;
@ -285,54 +374,206 @@ 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 = cue_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 int gdi_get_crc(const char *name, uint32_t *crc)
{
char *track_path = (char *)malloc(PATH_MAX_LENGTH);
int ret = 0;
int rv = 0;
track_path[0] = '\0';
rv = gdi_find_track(name, false, 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("GDI '%s' primary track: %s\n", name, track_path);
RARCH_LOG("%s\n", msg_hash_to_str(MSG_READING_FIRST_DATA_TRACK));
rv = file_get_crc(track_path, 0, SIZE_MAX, crc);
if (rv == 1) {
RARCH_LOG("GDI '%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);
rv = stream_get_crc(fd, crc);
if (rv == 1) {
RARCH_LOG("CHD '%s' crc: %x\n", name, *crc);
}
intfstream_close(fd);
return rv;
}
*crc = acc;
static void cue_prune(database_info_handle_t *db, const char *name)
{
char *path = (char *)malloc(PATH_MAX_LENGTH + 1);
intfstream_t *fd = open_file(name);
size_t i;
return 1;
if (!fd)
{
free(path);
return;
}
while (cue_next_file(fd, name, path, PATH_MAX_LENGTH))
{
for (i = db->list_ptr; i < db->list->size; ++i)
{
if (db->list->elems[i].data && !strcmp(path, db->list->elems[i].data))
{
RARCH_LOG("Pruning file referenced by cue: %s\n", path);
free(db->list->elems[i].data);
db->list->elems[i].data = NULL;
}
}
}
}
static void gdi_prune(database_info_handle_t *db, const char *name)
{
char *path = (char *)malloc(PATH_MAX_LENGTH + 1);
intfstream_t *fd = open_file(name);
size_t i;
if (!fd)
{
free(path);
return;
}
while (gdi_next_file(fd, name, path, PATH_MAX_LENGTH))
{
for (i = db->list_ptr; i < db->list->size; ++i)
{
if (db->list->elems[i].data && !strcmp(path, db->list->elems[i].data))
{
RARCH_LOG("Pruning file referenced by gdi: %s\n", path);
free(db->list->elems[i].data);
db->list->elems[i].data = NULL;
}
}
}
}
static int task_database_iterate_playlist(
@ -345,37 +586,53 @@ 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:
cue_prune(db, name);
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_GDI:
gdi_prune(db, name);
db_state->serial[0] = '\0';
/* There are no serial databases, so don't bother with
serials at the moment */
if (0 && gdi_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 gdi_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 +640,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;

View File

@ -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,21 +379,62 @@ 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 cue_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;
char *cue_dir = (char*)malloc(PATH_MAX_LENGTH);
cue_dir[0] = '\0';
fill_pathname_basedir(cue_dir, cue_path, PATH_MAX_LENGTH);
info.type = INTFSTREAM_FILE;
fd = intfstream_init(&info);
if (!fd)
{
free(tmp_token);
return -errno;
goto error;
}
if (!intfstream_open(fd, cue_path, RFILE_MODE_READ, -1))
@ -430,57 +448,283 @@ 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));
/* Set last index to last EOF */
if (file_size != -1) {
last_index = file_size;
}
cue_dir[0] = '\0';
fill_pathname_basedir(cue_dir, cue_path, PATH_MAX_LENGTH * sizeof(char));
/* 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;
}
}
get_token(fd, tmp_token, MAX_TOKEN_LEN);
fill_pathname_join(last_file, cue_dir, tmp_token, PATH_MAX_LENGTH);
file_size = get_file_size(last_file);
get_token(fd, tmp_token, MAX_TOKEN_LEN);
fill_pathname_join(track_path, cue_dir, tmp_token, max_len);
free(cue_dir);
}
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 (file_size != -1) {
last_index = file_size;
}
if (update_cand(&cand_index, &last_index, &largest, last_file, offset,
size, track_path, max_len)) {
rv = 0;
}
clean:
free(cue_dir);
free(tmp_token);
free(last_file);
intfstream_close(fd);
return rv;
error:
free(cue_dir);
free(tmp_token);
free(last_file);
if (fd)
intfstream_close(fd);
return -errno;
}
bool cue_next_file(intfstream_t *fd, const char *cue_path, char *path, size_t max_len)
{
bool rv = false;
char *tmp_token = malloc(MAX_TOKEN_LEN);
ssize_t volatile file_size = -1;
char *cue_dir = (char*)malloc(PATH_MAX_LENGTH);
cue_dir[0] = '\0';
fill_pathname_basedir(cue_dir, cue_path, PATH_MAX_LENGTH);
tmp_token[0] = '\0';
while (get_token(fd, tmp_token, MAX_TOKEN_LEN) > 0)
{
if (string_is_equal(tmp_token, "FILE"))
{
get_token(fd, tmp_token, MAX_TOKEN_LEN);
fill_pathname_join(path, cue_dir, tmp_token, max_len);
rv = true;
break;
}
}
free(cue_dir);
free(tmp_token);
return rv;
}
int gdi_find_track(const char *gdi_path, bool first, 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;
int32_t track = 0;
size_t largest = 0;
int size = -1;
int mode = -1;
ssize_t file_size = -1;
char *gdi_dir = (char*)malloc(PATH_MAX_LENGTH);
gdi_dir[0] = '\0';
fill_pathname_basedir(gdi_dir, gdi_path, PATH_MAX_LENGTH);
info.type = INTFSTREAM_FILE;
fd = intfstream_init(&info);
if (!fd)
{
goto error;
}
if (!intfstream_open(fd, gdi_path, RFILE_MODE_READ, -1))
{
RARCH_LOG("Could not open GDI file '%s': %s\n", gdi_path,
strerror(errno));
goto error;
}
RARCH_LOG("Parsing GDI file '%s'...\n", gdi_path);
tmp_token[0] = '\0';
rv = -EINVAL;
/* Skip track count */
get_token(fd, tmp_token, MAX_TOKEN_LEN);
/* Track number */
while (get_token(fd, tmp_token, MAX_TOKEN_LEN) > 0)
{
/* Offset */
if (get_token(fd, tmp_token, MAX_TOKEN_LEN) <= 0)
{
errno = EINVAL;
goto error;
}
/* Mode */
if (get_token(fd, tmp_token, MAX_TOKEN_LEN) <= 0)
{
errno = EINVAL;
goto error;
}
mode = atoi(tmp_token);
/* Sector size */
if (get_token(fd, tmp_token, MAX_TOKEN_LEN) <= 0)
{
errno = EINVAL;
goto error;
}
size = atoi(tmp_token);
/* File name */
if (get_token(fd, tmp_token, MAX_TOKEN_LEN) <= 0)
{
errno = EINVAL;
goto error;
}
/* Check for data track */
if (!(mode == 0 && size == 2352))
{
fill_pathname_join(last_file, gdi_dir, tmp_token, PATH_MAX_LENGTH);
file_size = get_file_size(last_file);
if (file_size < 0)
{
goto error;
}
if (file_size > largest)
{
strlcpy(track_path, last_file, max_len);
rv = 0;
largest = file_size;
if (first)
{
goto clean;
}
}
}
/* Disc offset (not used?) */
if (get_token(fd, tmp_token, MAX_TOKEN_LEN) <= 0)
{
errno = EINVAL;
goto error;
}
}
clean:
free(gdi_dir);
free(tmp_token);
free(last_file);
intfstream_close(fd);
return rv;
error:
free(gdi_dir);
free(tmp_token);
free(last_file);
if (fd)
intfstream_close(fd);
return -errno;
}
bool gdi_next_file(intfstream_t *fd, const char *gdi_path, char *path, size_t max_len)
{
bool rv = false;
char *tmp_token = malloc(MAX_TOKEN_LEN);
ssize_t offset = -1;
char *gdi_dir = (char*)malloc(PATH_MAX_LENGTH);
gdi_dir[0] = '\0';
tmp_token[0] = '\0';
fill_pathname_basedir(gdi_dir, gdi_path, PATH_MAX_LENGTH);
/* Skip initial track count */
offset = intfstream_tell(fd);
if (offset == 0)
{
get_token(fd, tmp_token, MAX_TOKEN_LEN);
}
/* Track number */
get_token(fd, tmp_token, MAX_TOKEN_LEN);
/* Offset */
get_token(fd, tmp_token, MAX_TOKEN_LEN);
/* Mode */
get_token(fd, tmp_token, MAX_TOKEN_LEN);
/* Sector size */
get_token(fd, tmp_token, MAX_TOKEN_LEN);
/* File name */
if (get_token(fd, tmp_token, MAX_TOKEN_LEN) > 0)
{
fill_pathname_join(path, gdi_dir, tmp_token, max_len);
rv = true;
/* Disc offset */
get_token(fd, tmp_token, MAX_TOKEN_LEN);
}
free(gdi_dir);
free(tmp_token);
return rv;
}