mirror of
https://github.com/libretro/RetroArch.git
synced 2024-11-23 16:09:47 +00:00
task_database: rework cd scanning
Support chd files. Fall back to using the CRC32 of the last track of CDs if a serial number is not available. This requires new database files, but is necessary for chd scanning to work.
This commit is contained in:
parent
08ce00d798
commit
5a3969d4fa
@ -24,6 +24,8 @@
|
||||
#include <file/file_path.h>
|
||||
#include <encodings/crc32.h>
|
||||
#include <streams/file_stream.h>
|
||||
#include <streams/chd_stream.h>
|
||||
#include <streams/interface_stream.h>
|
||||
#include "tasks_internal.h"
|
||||
|
||||
#include "../database_info.h"
|
||||
@ -69,13 +71,60 @@ typedef struct db_handle
|
||||
int find_first_data_track(const char* cue_path,
|
||||
int32_t* offset, char* track_path, size_t max_len);
|
||||
|
||||
int detect_system(const char* track_path, const char** system_name);
|
||||
int detect_system(intfstream_t *fd, const char** system_name);
|
||||
|
||||
int detect_ps1_game(const char *track_path, char *game_id);
|
||||
int detect_ps1_game(intfstream_t *fd, char *game_id);
|
||||
|
||||
int detect_psp_game(const char *track_path, char *game_id);
|
||||
int detect_psp_game(intfstream_t *fd, char *game_id);
|
||||
|
||||
int detect_serial_ascii_game(const char *track_path, char *game_id);
|
||||
int detect_serial_ascii_game(intfstream_t *fd, char *game_id);
|
||||
|
||||
static intfstream_t*
|
||||
open_file(const char *path)
|
||||
{
|
||||
intfstream_info_t info;
|
||||
intfstream_t *fd = NULL;
|
||||
|
||||
info.type = INTFSTREAM_FILE;
|
||||
|
||||
fd = intfstream_init(&info);
|
||||
if (!fd)
|
||||
{
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (!intfstream_open(fd, path, 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;
|
||||
|
||||
info.type = INTFSTREAM_CHD;
|
||||
info.chd.track = track;
|
||||
|
||||
fd = intfstream_init(&info);
|
||||
if (!fd)
|
||||
{
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (!intfstream_open(fd, path, RFILE_MODE_READ, -1))
|
||||
{
|
||||
intfstream_close(fd);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
return fd;
|
||||
}
|
||||
|
||||
static void database_info_set_type(database_info_handle_t *handle, enum database_type type)
|
||||
{
|
||||
@ -137,16 +186,16 @@ static int task_database_iterate_start(database_info_handle_t *db,
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int iso_get_serial(database_state_handle_t *db_state,
|
||||
database_info_handle_t *db, const char *name, char* serial)
|
||||
static int stream_get_serial(database_state_handle_t *db_state,
|
||||
database_info_handle_t *db, intfstream_t *fd, char* serial)
|
||||
{
|
||||
const char* system_name = NULL;
|
||||
|
||||
/* Check if the system was not auto-detected. */
|
||||
if (detect_system(name, &system_name) < 0)
|
||||
if (detect_system(fd, &system_name) < 0)
|
||||
{
|
||||
/* Attempt to read an ASCII serial, like Wii. */
|
||||
if (detect_serial_ascii_game(name, serial))
|
||||
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);
|
||||
@ -159,18 +208,38 @@ static int iso_get_serial(database_state_handle_t *db_state,
|
||||
|
||||
if (string_is_equal_fast(system_name, "psp", 3))
|
||||
{
|
||||
if (detect_psp_game(name, serial) == 0)
|
||||
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(name, serial) == 0)
|
||||
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 0;
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int iso_get_serial(database_state_handle_t *db_state,
|
||||
database_info_handle_t *db, const char *name, char* serial)
|
||||
{
|
||||
intfstream_t *fd = open_file(name);
|
||||
int rv;
|
||||
|
||||
if (!fd)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
rv = stream_get_serial(db_state, db, fd, serial);
|
||||
intfstream_close(fd);
|
||||
return rv;
|
||||
}
|
||||
|
||||
static int cue_get_serial(database_state_handle_t *db_state,
|
||||
@ -193,7 +262,7 @@ static int cue_get_serial(database_state_handle_t *db_state,
|
||||
msg_hash_to_str(MSG_COULD_NOT_FIND_VALID_DATA_TRACK),
|
||||
strerror(-rv));
|
||||
free(track_path);
|
||||
return rv;
|
||||
return 0;
|
||||
}
|
||||
|
||||
RARCH_LOG("%s\n", msg_hash_to_str(MSG_READING_FIRST_DATA_TRACK));
|
||||
@ -204,6 +273,23 @@ static int cue_get_serial(database_state_handle_t *db_state,
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int chd_get_serial(database_state_handle_t *db_state,
|
||||
database_info_handle_t *db, const char *name, char* serial)
|
||||
{
|
||||
intfstream_t *fd = NULL;
|
||||
int result;
|
||||
|
||||
fd = open_chd_track(name, CHDSTREAM_TRACK_FIRST_DATA);
|
||||
if (!fd)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
result = stream_get_serial(db_state, db, fd, serial);
|
||||
intfstream_close(fd);
|
||||
return result;
|
||||
}
|
||||
|
||||
static bool file_get_crc(database_state_handle_t *db_state,
|
||||
const char *name, uint32_t *crc)
|
||||
{
|
||||
@ -219,6 +305,37 @@ static bool file_get_crc(database_state_handle_t *db_state,
|
||||
return 1;
|
||||
}
|
||||
|
||||
static bool chd_get_crc(database_state_handle_t *db_state,
|
||||
const char *name, uint32_t *crc)
|
||||
{
|
||||
intfstream_t *fd = NULL;
|
||||
int result;
|
||||
uint32_t acc = 0;
|
||||
uint8_t buffer[4096];
|
||||
ssize_t size;
|
||||
|
||||
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);
|
||||
}
|
||||
if (size < 0)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
RARCH_LOG("CHD '%s' crc: %x\n", name, acc);
|
||||
|
||||
*crc = acc;
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int task_database_iterate_playlist(
|
||||
database_state_handle_t *db_state,
|
||||
database_info_handle_t *db, const char *name)
|
||||
@ -235,14 +352,33 @@ static int task_database_iterate_playlist(
|
||||
#endif
|
||||
case FILE_TYPE_CUE:
|
||||
db_state->serial[0] = '\0';
|
||||
cue_get_serial(db_state, db, name, db_state->serial);
|
||||
database_info_set_type(db, DATABASE_TYPE_SERIAL_LOOKUP);
|
||||
if (cue_get_serial(db_state, db, 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);
|
||||
}
|
||||
break;
|
||||
case FILE_TYPE_ISO:
|
||||
db_state->serial[0] = '\0';
|
||||
iso_get_serial(db_state, db, name, 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))
|
||||
{
|
||||
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);
|
||||
}
|
||||
break;
|
||||
case FILE_TYPE_LUTRO:
|
||||
database_info_set_type(db, DATABASE_TYPE_ITERATE_LUTRO);
|
||||
break;
|
||||
|
@ -25,6 +25,7 @@
|
||||
#include <file/file_path.h>
|
||||
#include <retro_endianness.h>
|
||||
#include <streams/file_stream.h>
|
||||
#include <streams/interface_stream.h>
|
||||
#include <string/stdstring.h>
|
||||
|
||||
#ifdef HAVE_CONFIG_H
|
||||
@ -63,7 +64,7 @@ static struct magic_entry MAGIC_NUMBERS[] = {
|
||||
{ 0, NULL, NULL}
|
||||
};
|
||||
|
||||
static ssize_t get_token(RFILE *fd, char *token, size_t max_len)
|
||||
static ssize_t get_token(intfstream_t *fd, char *token, size_t max_len)
|
||||
{
|
||||
char *c = token;
|
||||
ssize_t len = 0;
|
||||
@ -71,7 +72,7 @@ static ssize_t get_token(RFILE *fd, char *token, size_t max_len)
|
||||
|
||||
while (1)
|
||||
{
|
||||
int rv = (int)filestream_read(fd, c, 1);
|
||||
int rv = (int)intfstream_read(fd, c, 1);
|
||||
if (rv == 0)
|
||||
return 0;
|
||||
|
||||
@ -123,7 +124,7 @@ static ssize_t get_token(RFILE *fd, char *token, size_t max_len)
|
||||
}
|
||||
}
|
||||
|
||||
static int find_token(RFILE *fd, const char *token)
|
||||
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);
|
||||
@ -146,30 +147,26 @@ static int find_token(RFILE *fd, const char *token)
|
||||
}
|
||||
|
||||
|
||||
static int detect_ps1_game_sub(const char *track_path,
|
||||
static int detect_ps1_game_sub(intfstream_t *fp,
|
||||
char *game_id, int sub_channel_mixed)
|
||||
{
|
||||
uint8_t* tmp;
|
||||
uint8_t* boot_file;
|
||||
int skip, frame_size, is_mode1, cd_sector;
|
||||
uint8_t buffer[2048 * 2];
|
||||
RFILE *fp =
|
||||
filestream_open(track_path, RFILE_MODE_READ, -1);
|
||||
if (!fp)
|
||||
return 0;
|
||||
|
||||
buffer[0] = '\0';
|
||||
is_mode1 = 0;
|
||||
filestream_seek(fp, 0, SEEK_END);
|
||||
intfstream_seek(fp, 0, SEEK_END);
|
||||
|
||||
if (!sub_channel_mixed)
|
||||
{
|
||||
if (!(filestream_tell(fp) & 0x7FF))
|
||||
if (!(intfstream_tell(fp) & 0x7FF))
|
||||
{
|
||||
unsigned int mode_test = 0;
|
||||
|
||||
filestream_seek(fp, 0, SEEK_SET);
|
||||
filestream_read(fp, &mode_test, 4);
|
||||
intfstream_seek(fp, 0, SEEK_SET);
|
||||
intfstream_read(fp, &mode_test, 4);
|
||||
if (mode_test != MODETEST_VAL)
|
||||
is_mode1 = 1;
|
||||
}
|
||||
@ -178,12 +175,12 @@ static int detect_ps1_game_sub(const char *track_path,
|
||||
skip = is_mode1? 0: 24;
|
||||
frame_size = sub_channel_mixed? 2448: is_mode1? 2048: 2352;
|
||||
|
||||
filestream_seek(fp, 156 + skip + 16 * frame_size, SEEK_SET);
|
||||
filestream_read(fp, buffer, 6);
|
||||
intfstream_seek(fp, 156 + skip + 16 * frame_size, SEEK_SET);
|
||||
intfstream_read(fp, buffer, 6);
|
||||
|
||||
cd_sector = buffer[2] | (buffer[3] << 8) | (buffer[4] << 16);
|
||||
filestream_seek(fp, skip + cd_sector * frame_size, SEEK_SET);
|
||||
filestream_read(fp, buffer, 2048 * 2);
|
||||
intfstream_seek(fp, skip + cd_sector * frame_size, SEEK_SET);
|
||||
intfstream_read(fp, buffer, 2048 * 2);
|
||||
|
||||
tmp = buffer;
|
||||
while (tmp < (buffer + 2048 * 2))
|
||||
@ -201,8 +198,8 @@ static int detect_ps1_game_sub(const char *track_path,
|
||||
goto error;
|
||||
|
||||
cd_sector = tmp[2] | (tmp[3] << 8) | (tmp[4] << 16);
|
||||
filestream_seek(fp, skip + cd_sector * frame_size, SEEK_SET);
|
||||
filestream_read(fp, buffer, 256);
|
||||
intfstream_seek(fp, skip + cd_sector * frame_size, SEEK_SET);
|
||||
intfstream_read(fp, buffer, 256);
|
||||
buffer[256] = '\0';
|
||||
|
||||
tmp = buffer;
|
||||
@ -240,41 +237,30 @@ static int detect_ps1_game_sub(const char *track_path,
|
||||
|
||||
*game_id = 0;
|
||||
|
||||
filestream_close(fp);
|
||||
return 1;
|
||||
|
||||
error:
|
||||
filestream_close(fp);
|
||||
return 0;
|
||||
}
|
||||
|
||||
int detect_ps1_game(const char *track_path, char *game_id)
|
||||
int detect_ps1_game(intfstream_t *fd, char *game_id)
|
||||
{
|
||||
if (detect_ps1_game_sub(track_path, game_id, 0))
|
||||
if (detect_ps1_game_sub(fd, game_id, 0))
|
||||
return 1;
|
||||
|
||||
return detect_ps1_game_sub(track_path, game_id, 1);
|
||||
return detect_ps1_game_sub(fd, game_id, 1);
|
||||
}
|
||||
|
||||
int detect_psp_game(const char *track_path, char *game_id)
|
||||
int detect_psp_game(intfstream_t *fd, char *game_id)
|
||||
{
|
||||
unsigned pos;
|
||||
bool rv = false;
|
||||
RFILE *fd = filestream_open(track_path, RFILE_MODE_READ, -1);
|
||||
|
||||
if (!fd)
|
||||
{
|
||||
RARCH_LOG("%s: %s\n",
|
||||
msg_hash_to_str(MSG_COULD_NOT_OPEN_DATA_TRACK),
|
||||
strerror(errno));
|
||||
return -errno;
|
||||
}
|
||||
|
||||
for (pos = 0; pos < 100000; pos++)
|
||||
{
|
||||
filestream_seek(fd, pos, SEEK_SET);
|
||||
intfstream_seek(fd, pos, SEEK_SET);
|
||||
|
||||
if (filestream_read(fd, game_id, 5) > 0)
|
||||
if (intfstream_read(fd, game_id, 5) > 0)
|
||||
{
|
||||
game_id[5] = '\0';
|
||||
|
||||
@ -306,8 +292,8 @@ int detect_psp_game(const char *track_path, char *game_id)
|
||||
|| (string_is_equal(game_id, "NPJZ-"))
|
||||
)
|
||||
{
|
||||
filestream_seek(fd, pos, SEEK_SET);
|
||||
if (filestream_read(fd, game_id, 10) > 0)
|
||||
intfstream_seek(fd, pos, SEEK_SET);
|
||||
if (intfstream_read(fd, game_id, 10) > 0)
|
||||
{
|
||||
#if 0
|
||||
game_id[4] = '-';
|
||||
@ -324,34 +310,22 @@ int detect_psp_game(const char *track_path, char *game_id)
|
||||
break;
|
||||
}
|
||||
|
||||
filestream_close(fd);
|
||||
return rv;
|
||||
}
|
||||
|
||||
/**
|
||||
* Check for an ASCII serial in the first few bits of the ISO (Wii).
|
||||
*/
|
||||
int detect_serial_ascii_game(const char *track_path, char *game_id)
|
||||
int detect_serial_ascii_game(intfstream_t *fd, char *game_id)
|
||||
{
|
||||
unsigned pos;
|
||||
int numberOfAscii = 0;
|
||||
bool rv = false;
|
||||
RFILE *fd = filestream_open(track_path, RFILE_MODE_READ, -1);
|
||||
|
||||
/* Attempt to load the file. */
|
||||
if (!fd)
|
||||
{
|
||||
RARCH_LOG("%s: %s\n",
|
||||
msg_hash_to_str(MSG_COULD_NOT_OPEN_DATA_TRACK),
|
||||
strerror(errno));
|
||||
return -errno;
|
||||
}
|
||||
|
||||
for (pos = 0; pos < 10000; pos++)
|
||||
{
|
||||
filestream_seek(fd, pos, SEEK_SET);
|
||||
/* Current logic only requires 15 characters (max of 4096 per sizeof game_id). */
|
||||
if (filestream_read(fd, game_id, 15) > 0)
|
||||
intfstream_seek(fd, pos, SEEK_SET);
|
||||
if (intfstream_read(fd, game_id, 15) > 0)
|
||||
{
|
||||
unsigned i;
|
||||
game_id[15] = '\0';
|
||||
@ -378,34 +352,24 @@ int detect_serial_ascii_game(const char *track_path, char *game_id)
|
||||
}
|
||||
}
|
||||
|
||||
filestream_close(fd);
|
||||
return rv;
|
||||
}
|
||||
|
||||
int detect_system(const char *track_path, const char **system_name)
|
||||
int detect_system(intfstream_t *fd, const char **system_name)
|
||||
{
|
||||
int rv;
|
||||
char magic[MAGIC_LEN];
|
||||
int i;
|
||||
RFILE *fd = filestream_open(track_path, RFILE_MODE_READ, -1);
|
||||
|
||||
if (!fd)
|
||||
{
|
||||
RARCH_LOG("Could not open data track of file '%s': %s\n",
|
||||
track_path, strerror(errno));
|
||||
rv = -errno;
|
||||
goto clean;
|
||||
}
|
||||
|
||||
RARCH_LOG("%s\n", msg_hash_to_str(MSG_COMPARING_WITH_KNOWN_MAGIC_NUMBERS));
|
||||
for (i = 0; MAGIC_NUMBERS[i].system_name != NULL; i++)
|
||||
{
|
||||
filestream_seek(fd, MAGIC_NUMBERS[i].offset, SEEK_SET);
|
||||
intfstream_seek(fd, MAGIC_NUMBERS[i].offset, SEEK_SET);
|
||||
|
||||
if (filestream_read(fd, magic, MAGIC_LEN) < MAGIC_LEN)
|
||||
if (intfstream_read(fd, magic, MAGIC_LEN) < MAGIC_LEN)
|
||||
{
|
||||
RARCH_LOG("Could not read data from file '%s' at offset %d: %s\n",
|
||||
track_path, MAGIC_NUMBERS[i].offset, strerror(errno));
|
||||
RARCH_LOG("Could not read data at offset %d: %s\n",
|
||||
MAGIC_NUMBERS[i].offset, strerror(errno));
|
||||
rv = -errno;
|
||||
goto clean;
|
||||
}
|
||||
@ -418,8 +382,8 @@ int detect_system(const char *track_path, const char **system_name)
|
||||
}
|
||||
}
|
||||
|
||||
filestream_seek(fd, 0x8008, SEEK_SET);
|
||||
if (filestream_read(fd, magic, 8) > 0)
|
||||
intfstream_seek(fd, 0x8008, SEEK_SET);
|
||||
if (intfstream_read(fd, magic, 8) > 0)
|
||||
{
|
||||
magic[8] = '\0';
|
||||
if (!string_is_empty(magic) &&
|
||||
@ -435,7 +399,6 @@ int detect_system(const char *track_path, const char **system_name)
|
||||
rv = -EINVAL;
|
||||
|
||||
clean:
|
||||
filestream_close(fd);
|
||||
return rv;
|
||||
}
|
||||
|
||||
@ -443,11 +406,19 @@ int find_first_data_track(const char *cue_path,
|
||||
int32_t *offset, char *track_path, size_t max_len)
|
||||
{
|
||||
int rv;
|
||||
char * tmp_token = (char*)(MAX_TOKEN_LEN * sizeof(char));
|
||||
RFILE *fd =
|
||||
filestream_open(cue_path, RFILE_MODE_READ, -1);
|
||||
char * tmp_token = malloc(MAX_TOKEN_LEN * sizeof(char));
|
||||
intfstream_info_t info;
|
||||
intfstream_t *fd = NULL;
|
||||
|
||||
info.type = INTFSTREAM_FILE;
|
||||
|
||||
fd = intfstream_init(&info);
|
||||
if (!fd)
|
||||
{
|
||||
return -errno;
|
||||
}
|
||||
|
||||
if (!intfstream_open(fd, cue_path, RFILE_MODE_READ, -1))
|
||||
{
|
||||
RARCH_LOG("Could not open CUE file '%s': %s\n", cue_path,
|
||||
strerror(errno));
|
||||
@ -494,10 +465,6 @@ int find_first_data_track(const char *cue_path,
|
||||
|
||||
*offset = ((m * 60) * (s * 75) * f) * 25;
|
||||
|
||||
RARCH_LOG("%s '%s+%d'\n",
|
||||
msg_hash_to_str(MSG_FOUND_FIRST_DATA_TRACK_ON_FILE),
|
||||
track_path, *offset);
|
||||
|
||||
rv = 0;
|
||||
goto clean;
|
||||
}
|
||||
@ -507,12 +474,12 @@ int find_first_data_track(const char *cue_path,
|
||||
|
||||
clean:
|
||||
free(tmp_token);
|
||||
filestream_close(fd);
|
||||
intfstream_close(fd);
|
||||
return rv;
|
||||
|
||||
error:
|
||||
free(tmp_token);
|
||||
if (fd)
|
||||
filestream_close(fd);
|
||||
intfstream_close(fd);
|
||||
return -errno;
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user