Skip to content

Commit cc33520

Browse files
authored
Add scanner support for Philips CD-i disc images (#18424)
CD-i discs have a unique quirk: they store data in tracks labeled as AUDIO in both CUE and CHD formats. The scanner normally skips AUDIO tracks when looking for data, causing CD-i games to never match the database.
1 parent 12eebed commit cc33520

2 files changed

Lines changed: 79 additions & 4 deletions

File tree

tasks/task_database.c

Lines changed: 47 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -384,14 +384,50 @@ static int task_database_gdi_get_serial(const char *name, char *s, size_t len, u
384384
return intfstream_file_get_serial(track_path, 0, INT64_MAX, s, len, filesize);
385385
}
386386

387+
/* Helper function to detect if a CHD file is a CD-i disc
388+
* CD-i discs store data in AUDIO-labeled tracks, so we need
389+
* to explicitly open track 1 for scanning */
390+
static bool is_chd_file_cdi(const char *path)
391+
{
392+
intfstream_t *fd;
393+
uint8_t magic[12];
394+
bool is_cdi = false;
395+
const uint8_t cdi_magic[] = {0x00, 0xff, 0xff, 0xff, 0xff, 0xff,
396+
0xff, 0xff, 0xff, 0xff, 0xff, 0x00};
397+
398+
/* Try to open track 1 explicitly */
399+
fd = intfstream_open_chd_track(path,
400+
RETRO_VFS_FILE_ACCESS_READ,
401+
RETRO_VFS_FILE_ACCESS_HINT_NONE,
402+
1); /* Explicit track number, not CHDSTREAM_TRACK_FIRST_DATA */
403+
404+
if (!fd)
405+
return false;
406+
407+
/* Read and check CD-i magic bytes at offset 0 */
408+
if (intfstream_read(fd, magic, sizeof(magic)) == sizeof(magic))
409+
is_cdi = (memcmp(magic, cdi_magic, sizeof(cdi_magic)) == 0);
410+
411+
intfstream_close(fd);
412+
free(fd);
413+
return is_cdi;
414+
}
415+
387416
static int task_database_chd_get_serial(const char *name, char *serial, size_t len, uint64_t *filesize)
388417
{
389418
int result;
390-
intfstream_t *fd = intfstream_open_chd_track(
419+
int32_t track;
420+
intfstream_t *fd;
421+
422+
/* CD-i discs store data in AUDIO-labeled tracks, so we must
423+
* explicitly open track 1 instead of using CHDSTREAM_TRACK_FIRST_DATA */
424+
track = is_chd_file_cdi(name) ? 1 : CHDSTREAM_TRACK_FIRST_DATA;
425+
426+
fd = intfstream_open_chd_track(
391427
name,
392428
RETRO_VFS_FILE_ACCESS_READ,
393429
RETRO_VFS_FILE_ACCESS_HINT_NONE,
394-
CHDSTREAM_TRACK_FIRST_DATA);
430+
track);
395431
if (!fd)
396432
return 0;
397433

@@ -503,11 +539,18 @@ static int task_database_gdi_get_crc_and_size(const char *name, uint32_t *crc, u
503539
static bool task_database_chd_get_crc_and_size(const char *name, uint32_t *crc, uint64_t *size)
504540
{
505541
bool found_crc = false;
506-
intfstream_t *fd = intfstream_open_chd_track(
542+
int32_t track;
543+
intfstream_t *fd;
544+
545+
/* CD-i discs store data in AUDIO-labeled tracks, so we must
546+
* explicitly open track 1 instead of using CHDSTREAM_TRACK_PRIMARY */
547+
track = is_chd_file_cdi(name) ? 1 : CHDSTREAM_TRACK_PRIMARY;
548+
549+
fd = intfstream_open_chd_track(
507550
name,
508551
RETRO_VFS_FILE_ACCESS_READ,
509552
RETRO_VFS_FILE_ACCESS_HINT_NONE,
510-
CHDSTREAM_TRACK_PRIMARY);
553+
track);
511554
if (!fd)
512555
return 0;
513556

tasks/task_database_cue.c

Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -62,6 +62,7 @@ static struct magic_entry MAGIC_NUMBERS[] = {
6262
{ "Sony - PlayStation 2", "PLAYSTATION", 0x008008}, /* PS2 DVD */
6363
{ "Sony - PlayStation 2", " ", 0x008008}, /* PS2 DVD */
6464
{ "Sony - PlayStation Portable", "PSP GAME", 0x008008},
65+
{ "Philips - CD-i", "\x00\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\x00", 0x000000},
6566
{ NULL, NULL, 0}
6667
};
6768

@@ -1165,6 +1166,37 @@ int cue_find_track(const char *cue_path, bool first,
11651166
task_database_cue_get_token(fd, tmp_token, sizeof(tmp_token));
11661167
is_data = !string_is_equal_noncase(tmp_token, "AUDIO");
11671168
++track;
1169+
1170+
/* Special case: CD-i stores data in AUDIO-labeled tracks */
1171+
/* Check if track 1 is AUDIO but contains CD-i magic bytes */
1172+
if (!is_data && track == 1 && last_file[0] != '\0')
1173+
{
1174+
intfstream_t *track_fd = NULL;
1175+
intfstream_info_t track_info;
1176+
uint8_t magic_buf[12];
1177+
const uint8_t cdi_magic[] = {0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00};
1178+
1179+
track_info.type = INTFSTREAM_FILE;
1180+
if ((track_fd = (intfstream_t*)intfstream_init(&track_info)))
1181+
{
1182+
if (intfstream_open(track_fd, last_file,
1183+
RETRO_VFS_FILE_ACCESS_READ, RETRO_VFS_FILE_ACCESS_HINT_NONE))
1184+
{
1185+
if (intfstream_read(track_fd, magic_buf, sizeof(magic_buf)) == sizeof(magic_buf))
1186+
{
1187+
if (memcmp(magic_buf, cdi_magic, sizeof(cdi_magic)) == 0)
1188+
{
1189+
is_data = true; /* CD-i AUDIO track contains data */
1190+
#ifdef DEBUG
1191+
RARCH_LOG("[Scanner] Detected CD-i data in AUDIO track 1\n");
1192+
#endif
1193+
}
1194+
}
1195+
intfstream_close(track_fd);
1196+
}
1197+
free(track_fd);
1198+
}
1199+
}
11681200
}
11691201
else if (string_is_equal_noncase(tmp_token, "INDEX"))
11701202
{

0 commit comments

Comments
 (0)