update PCEngine-CD hash algorithm; pregap cdfs support for CUE and CHD files

This commit is contained in:
Jamiras 2019-10-10 20:21:46 -06:00
parent a723a833a8
commit 0b92224c36
8 changed files with 304 additions and 96 deletions

View file

@ -1127,6 +1127,7 @@ typedef struct
struct http_connection_t *conn;
struct http_t *http;
const rcheevos_cheevo_t *cheevo_end;
cdfs_track_t *track;
cdfs_file_t cdfp;
/* co-routine required fields */
@ -1151,7 +1152,8 @@ enum
RCHEEVOS_HTTP_GET = -13,
RCHEEVOS_DEACTIVATE = -14,
RCHEEVOS_PLAYING = -15,
RCHEEVOS_DELAY = -16
RCHEEVOS_DELAY = -16,
RCHEEVOS_PCE_CD_MD5 = -17
};
static int rcheevos_iterate(rcheevos_coro_t* coro)
@ -1212,6 +1214,13 @@ static int rcheevos_iterate(rcheevos_coro_t* coro)
0
};
static const uint32_t pce_cd_exts[] =
{
0x0b886782U, /* cue */
0x0b8865d4U, /* chd */
0
};
static const uint32_t arcade_exts[] =
{
0x0b88c7d8U, /* zip */
@ -1224,6 +1233,7 @@ static int rcheevos_iterate(rcheevos_coro_t* coro)
{RCHEEVOS_LYNX_MD5, "Atari Lynx (discards header)", lynx_exts},
{RCHEEVOS_NES_MD5, "NES (discards header)", nes_exts},
{RCHEEVOS_PSX_MD5, "Playstation (main executable)", psx_exts},
{RCHEEVOS_PCE_CD_MD5, "PC Engine CD (boot sector)", pce_cd_exts},
{RCHEEVOS_SEGACD_MD5, "Sega CD/Saturn (first sector)", segacd_exts},
{RCHEEVOS_ARCADE_MD5, "Arcade (filename)", arcade_exts},
{RCHEEVOS_GENERIC_MD5, "Generic (plain content)", NULL}
@ -1584,11 +1594,11 @@ found:
MD5_Init(&coro->md5);
/* find the data track - it should be the first one */
coro->stream = cdfs_open_data_track(coro->path);
if (coro->stream)
coro->track = cdfs_open_data_track(coro->path);
if (coro->track)
{
/* open the raw CD */
if (cdfs_open_file(&coro->cdfp, coro->stream, NULL))
if (cdfs_open_file(&coro->cdfp, coro->track, NULL))
{
coro->count = 512;
free(coro->data);
@ -1601,14 +1611,87 @@ found:
cdfs_close_file(&coro->cdfp);
intfstream_close(coro->stream);
CHEEVOS_FREE(coro->stream);
cdfs_close_track(coro->track);
coro->track = NULL;
CORO_GOTO(RCHEEVOS_GET_GAMEID);
}
intfstream_close(coro->stream);
CHEEVOS_FREE(coro->stream);
cdfs_close_track(coro->track);
coro->track = NULL;
}
CHEEVOS_LOG(RCHEEVOS_TAG "could not open CD\n", coro->gameid);
coro->gameid = 0;
CORO_RET();
}
/**************************************************************************
* Info Tries to identify a PC Engine CD game
* Input CHEEVOS_VAR_INFO the content info
* Output CHEEVOS_VAR_GAMEID the Retro Achievements game ID, or 0 if not found
*************************************************************************/
CORO_SUB(RCHEEVOS_PCE_CD_MD5)
{
MD5_Init(&coro->md5);
/* find the data track - it should be the second one */
coro->track = cdfs_open_data_track(coro->path);
if (coro->track)
{
/* open the raw CD */
if (cdfs_open_file(&coro->cdfp, coro->track, NULL))
{
/* the PC-Engine uses the second sector to specify boot information and program name.
* the string "PC Engine CD-ROM SYSTEM" should exist at 32 bytes into the sector
* http://shu.sheldows.com/shu/download/pcedocs/pce_cdrom.html
*/
cdfs_seek_sector(&coro->cdfp, 1);
cdfs_read_file(&coro->cdfp, buffer, 128);
if (strncmp("PC Engine CD-ROM SYSTEM", (const char*)& buffer[32], 23) != 0)
{
CHEEVOS_LOG(RCHEEVOS_TAG "not a PC Engine CD\n", coro->gameid);
cdfs_close_track(coro->track);
coro->track = NULL;
coro->gameid = 0;
CORO_RET();
}
{
/* the first three bytes specify the sector of the program data, and the fourth byte
* is the number of sectors.
*/
const unsigned int first_sector = buffer[0] * 65536 + buffer[1] * 256 + buffer[2];
cdfs_seek_sector(&coro->cdfp, first_sector);
to_read = buffer[3] * 2048;
}
coro->count = to_read + 22;
free(coro->data);
coro->data = (uint8_t*)malloc(coro->count);
memcpy(coro->data, &buffer[106], 22);
cdfs_read_file(&coro->cdfp, ((uint8_t*)coro->data) + 22, to_read);
coro->len = coro->count;
CORO_GOSUB(RCHEEVOS_EVAL_MD5);
MD5_Final(coro->hash, &coro->md5);
cdfs_close_file(&coro->cdfp);
cdfs_close_track(coro->track);
coro->track = NULL;
CORO_GOTO(RCHEEVOS_GET_GAMEID);
}
cdfs_close_track(coro->track);
coro->track = NULL;
}
CHEEVOS_LOG(RCHEEVOS_TAG "could not open CD\n", coro->gameid);
@ -1626,41 +1709,12 @@ found:
{
MD5_Init(&coro->md5);
/* if we're looking at an m3u file, get the first disc from the playlist */
end = path_get_extension(coro->path);
if (string_is_equal_noncase(end, "m3u"))
{
intfstream_t* m3u_stream = intfstream_open_file(coro->path, RETRO_VFS_FILE_ACCESS_READ, RETRO_VFS_FILE_ACCESS_HINT_NONE);
if (m3u_stream)
{
char disc_path[PATH_MAX_LENGTH];
char* tmp;
num_read = intfstream_read(m3u_stream, buffer, sizeof(buffer));
intfstream_close(m3u_stream);
buffer[num_read] = '\0';
tmp = buffer;
while (*tmp && *tmp != '\n')
++tmp;
if (tmp > buffer && tmp[-1] == '\r')
--tmp;
*tmp = '\0';
fill_pathname_basedir(disc_path, coro->path, sizeof(disc_path));
strlcat(disc_path, buffer, sizeof(disc_path));
free((void*)coro->path);
coro->path = strdup(disc_path);
}
}
/* find the data track - it should be the first one */
coro->stream = cdfs_open_data_track(coro->path);
if (coro->stream)
coro->track = cdfs_open_data_track(coro->path);
if (coro->track)
{
/* open the SYSTEM.CNF file and find the BOOT= record */
if (cdfs_open_file(&coro->cdfp, coro->stream, "SYSTEM.CNF"))
if (cdfs_open_file(&coro->cdfp, coro->track, "SYSTEM.CNF"))
{
cdfs_read_file(&coro->cdfp, buffer, sizeof(buffer));
@ -1703,7 +1757,7 @@ found:
strcpy(exe_name_buffer, exe_name);
/* open the file pointed to by the BOOT= record */
if (exe_name_buffer[0] && cdfs_open_file(&coro->cdfp, coro->stream, exe_name_buffer))
if (exe_name_buffer[0] && cdfs_open_file(&coro->cdfp, coro->track, exe_name_buffer))
{
cdfs_read_file(&coro->cdfp, buffer, sizeof(buffer));
@ -1750,8 +1804,8 @@ found:
cdfs_close_file(&coro->cdfp);
intfstream_close(coro->stream);
CHEEVOS_FREE(coro->stream);
cdfs_close_track(coro->track);
coro->track = NULL;
CORO_GOTO(RCHEEVOS_GET_GAMEID);
}
@ -1761,8 +1815,8 @@ found:
CHEEVOS_LOG(RCHEEVOS_TAG "could not locate primary executable\n", coro->gameid);
intfstream_close(coro->stream);
CHEEVOS_FREE(coro->stream);
cdfs_close_track(coro->track);
coro->track = NULL;
}
else
{
@ -2331,6 +2385,7 @@ bool rcheevos_load(const void *data)
CORO_SETUP();
info = (const struct retro_game_info*)data;
strncpy(buffer, path_get_extension(info->path), sizeof(buffer));
if (info->data)
{
@ -2356,9 +2411,41 @@ bool rcheevos_load(const void *data)
{
coro->data = NULL;
coro->path = strdup(info->path);
/* if we're looking at an m3u file, get the first disc from the playlist */
const char* end = path_get_extension(coro->path);
if (string_is_equal_noncase(end, "m3u"))
{
intfstream_t* m3u_stream = intfstream_open_file(coro->path, RETRO_VFS_FILE_ACCESS_READ, RETRO_VFS_FILE_ACCESS_HINT_NONE);
if (m3u_stream)
{
char m3u_contents[1024];
char disc_path[PATH_MAX_LENGTH];
char* tmp;
int64_t num_read;
num_read = intfstream_read(m3u_stream, m3u_contents, sizeof(m3u_contents) - 1);
intfstream_close(m3u_stream);
m3u_contents[num_read] = '\0';
tmp = m3u_contents;
while (*tmp && *tmp != '\n')
++tmp;
if (tmp > buffer && tmp[-1] == '\r')
--tmp;
*tmp = '\0';
fill_pathname_basedir(disc_path, coro->path, sizeof(disc_path));
strlcat(disc_path, m3u_contents, sizeof(disc_path));
free((void*)coro->path);
coro->path = strdup(disc_path);
strncpy(buffer, path_get_extension(disc_path), sizeof(buffer));
}
}
}
strncpy(buffer, path_get_extension(info->path), sizeof(buffer));
buffer[sizeof(buffer) - 1] = '\0';
string_to_lower(buffer);
coro->ext_hash = rcheevos_djb2(buffer, strlen(buffer));

View file

@ -5,10 +5,15 @@
#include <file/file_path.h>
#include <string/stdstring.h>
static void cdfs_determine_sector_size(cdfs_file_t* file)
#ifdef HAVE_CHD
#include <streams/chd_stream.h>
#endif
static void cdfs_determine_sector_size(cdfs_track_t* track)
{
uint8_t buffer[32];
int64_t stream_size;
const int toc_sector = track->pregap_sectors + 16;
/* MODE information is normally found in the CUE sheet, but we can try to determine it from the raw data.
*
@ -23,23 +28,23 @@ static void cdfs_determine_sector_size(cdfs_file_t* file)
*/
/* The boot record or primary volume descriptor is always at sector 16 and will contain a "CD001" marker */
intfstream_seek(file->stream, 16 * 2352, SEEK_SET);
if (intfstream_read(file->stream, buffer, sizeof(buffer)) < sizeof(buffer))
intfstream_seek(track->stream, toc_sector * 2352, SEEK_SET);
if (intfstream_read(track->stream, buffer, sizeof(buffer)) < sizeof(buffer))
return;
/* if this is a CDROM-XA data source, the "CD001" tag will be 25 bytes into the sector */
if (buffer[25] == 0x43 && buffer[26] == 0x44 &&
buffer[27] == 0x30 && buffer[28] == 0x30 && buffer[29] == 0x31)
{
file->stream_sector_size = 2352;
file->stream_sector_header_size = 24;
track->stream_sector_size = 2352;
track->stream_sector_header_size = 24;
}
/* otherwise it should be 17 bytes into the sector */
else if (buffer[17] == 0x43 && buffer[18] == 0x44 &&
buffer[19] == 0x30 && buffer[20] == 0x30 && buffer[21] == 0x31)
{
file->stream_sector_size = 2352;
file->stream_sector_header_size = 16;
track->stream_sector_size = 2352;
track->stream_sector_header_size = 16;
}
else
{
@ -48,40 +53,56 @@ static void cdfs_determine_sector_size(cdfs_file_t* file)
buffer[4] == 0xFF && buffer[5] == 0xFF && buffer[6] == 0xFF && buffer[7] == 0xFF &&
buffer[8] == 0xFF && buffer[9] == 0xFF && buffer[10] == 0xFF && buffer[11] == 0)
{
/* don't actually expect to get here - a properly headered sector should have had the CD001 tag */
/* if we didn't find a CD001 tag, this format may predate ISO-9660 */
/* after the 12 byte sync pattern is three bytes identifying the sector and then one byte for the mode (total 16 bytes) */
file->stream_sector_size = 2352;
file->stream_sector_header_size = 16;
track->stream_sector_size = 2352;
track->stream_sector_header_size = 16;
}
else
{
/* no recognizable header - attempt to determine sector size from stream size */
stream_size = intfstream_get_size(file->stream);
stream_size = intfstream_get_size(track->stream);
if ((stream_size % 2352) == 0)
{
/* audio tracks use all 2352 bytes without a header */
file->stream_sector_size = 2352;
track->stream_sector_size = 2352;
}
else if ((stream_size % 2048) == 0)
{
/* cooked tracks eliminate all header/footer data */
file->stream_sector_size = 2048;
track->stream_sector_size = 2048;
}
else if ((stream_size % 2336) == 0)
{
/* MODE 2 format without 16-byte sync data */
file->stream_sector_size = 2336;
file->stream_sector_header_size = 8;
track->stream_sector_size = 2336;
track->stream_sector_header_size = 8;
}
}
}
}
static void cdfs_seek_sector(cdfs_file_t* file, unsigned int sector)
static void cdfs_seek_track_sector(cdfs_track_t* track, unsigned int sector)
{
intfstream_seek(file->stream, sector * file->stream_sector_size + file->stream_sector_header_size, SEEK_SET);
intfstream_seek(track->stream, (sector + track->pregap_sectors) * track->stream_sector_size + track->stream_sector_header_size, SEEK_SET);
}
void cdfs_seek_sector(cdfs_file_t* file, unsigned int sector)
{
/* only allowed if open_file was called with a NULL path */
if (file->first_sector == 0)
{
if (sector != file->current_sector)
{
file->current_sector = sector;
file->sector_buffer_valid = 0;
}
file->pos = file->current_sector * 2048;
file->current_sector_offset = 0;
}
}
static int cdfs_find_file(cdfs_file_t* file, const char* path)
@ -108,8 +129,8 @@ static int cdfs_find_file(cdfs_file_t* file, const char* path)
int offset;
/* find the cd information (always 16 frames in) */
cdfs_seek_sector(file, 16);
intfstream_read(file->stream, buffer, sizeof(buffer));
cdfs_seek_track_sector(file->track, 16);
intfstream_read(file->track->stream, buffer, sizeof(buffer));
/* the directory_record starts at 156 bytes into the sector.
* the sector containing the root directory contents is a 3 byte value that is 2 bytes into the directory_record. */
@ -118,8 +139,8 @@ static int cdfs_find_file(cdfs_file_t* file, const char* path)
}
/* process the contents of the directory */
cdfs_seek_sector(file, sector);
intfstream_read(file->stream, buffer, sizeof(buffer));
cdfs_seek_track_sector(file->track, sector);
intfstream_read(file->track->stream, buffer, sizeof(buffer));
path_length = strlen(path);
tmp = buffer;
@ -149,25 +170,24 @@ static int cdfs_find_file(cdfs_file_t* file, const char* path)
return -1;
}
int cdfs_open_file(cdfs_file_t* file, intfstream_t* stream, const char* path)
int cdfs_open_file(cdfs_file_t* file, cdfs_track_t* track, const char* path)
{
if (!file || !stream)
if (!file || !track)
return 0;
memset(file, 0, sizeof(*file));
file->stream = stream;
cdfs_determine_sector_size(file);
file->track = track;
file->current_sector = -1;
if (path != NULL)
{
file->first_sector = cdfs_find_file(file, path);
}
else if (file->stream_sector_size)
else if (file->track->stream_sector_size)
{
file->first_sector = 0;
file->size = (intfstream_get_size(file->stream) / file->stream_sector_size) * 2048;
file->size = (intfstream_get_size(file->track->stream) / file->track->stream_sector_size) * 2048;
}
else
{
@ -222,8 +242,8 @@ int64_t cdfs_read_file(cdfs_file_t* file, void* buffer, uint64_t len)
while (len >= 2048)
{
cdfs_seek_sector(file, file->current_sector);
intfstream_read(file->stream, buffer, 2048);
cdfs_seek_track_sector(file->track, file->current_sector);
intfstream_read(file->track->stream, buffer, 2048);
buffer = (char*)buffer + 2048;
bytes_read += 2048;
@ -234,8 +254,8 @@ int64_t cdfs_read_file(cdfs_file_t* file, void* buffer, uint64_t len)
if (len > 0)
{
cdfs_seek_sector(file, file->current_sector);
intfstream_read(file->stream, file->sector_buffer, 2048);
cdfs_seek_track_sector(file->track, file->current_sector);
intfstream_read(file->track->stream, file->sector_buffer, 2048);
memcpy(buffer, file->sector_buffer, len);
file->current_sector_offset = len;
file->sector_buffer_valid = 1;
@ -322,7 +342,21 @@ static void cdfs_skip_spaces(const char** ptr)
++(*ptr);
}
static intfstream_t* cdfs_open_cue_track(const char* path, unsigned int track_index)
static cdfs_track_t* cdfs_wrap_stream(intfstream_t* stream, unsigned pregap_sectors)
{
cdfs_track_t* track;
if (stream == NULL)
return NULL;
track = (cdfs_track_t*)calloc(1, sizeof(*track));
track->stream = stream;
track->pregap_sectors = pregap_sectors;
cdfs_determine_sector_size(track);
return track;
}
static cdfs_track_t* cdfs_open_cue_track(const char* path, unsigned int track_index)
{
char* cue_contents = NULL;
char* cue = NULL;
@ -331,7 +365,9 @@ static intfstream_t* cdfs_open_cue_track(const char* path, unsigned int track_in
char current_track_path[PATH_MAX_LENGTH] = {0};
char track_path[PATH_MAX_LENGTH] = {0};
intfstream_t* cue_stream = NULL;
cdfs_track_t* track = NULL;
int64_t stream_size = 0;
unsigned int pregap_sectors = 0;
cue_stream = intfstream_open_file(path, RETRO_VFS_FILE_ACCESS_READ, RETRO_VFS_FILE_ACCESS_HINT_NONE);
@ -420,6 +456,14 @@ static intfstream_t* cdfs_open_cue_track(const char* path, unsigned int track_in
if (index_number == 1)
{
unsigned min = 0, sec = 0, frame = 0;
const char* ptr = index;
while (*ptr && *ptr != ' ' && *ptr != '\n')
++ptr;
cdfs_skip_spaces(&ptr);
sscanf(ptr, "%u:%u:%u", &min, &sec, &frame);
pregap_sectors = ((min * 60) + sec) * 75 + frame;
if (strstr(current_track_path, "/") || strstr(current_track_path, "\\"))
{
strncpy(track_path, current_track_path, sizeof(track_path));
@ -441,47 +485,80 @@ static intfstream_t* cdfs_open_cue_track(const char* path, unsigned int track_in
if (string_is_empty(track_path))
return NULL;
return intfstream_open_file(track_path, RETRO_VFS_FILE_ACCESS_READ, RETRO_VFS_FILE_ACCESS_HINT_NONE);
return cdfs_wrap_stream(intfstream_open_file(track_path, RETRO_VFS_FILE_ACCESS_READ, RETRO_VFS_FILE_ACCESS_HINT_NONE), pregap_sectors);
}
intfstream_t* cdfs_open_track(const char* path, unsigned int track_index)
#ifdef HAVE_CHD
static cdfs_track_t* cdfs_open_chd_track(const char* path, int32_t track_index)
{
intfstream_t* intf_stream;
cdfs_track_t* track;
unsigned int pregap_sectors;
intf_stream = intfstream_open_chd_track(path, RETRO_VFS_FILE_ACCESS_READ, RETRO_VFS_FILE_ACCESS_HINT_NONE, track_index);
if (!intf_stream)
return NULL;
pregap_sectors = intfstream_get_chd_pregap(intf_stream);
track = cdfs_wrap_stream(intf_stream, pregap_sectors);
/* CHD removes the markers from the header, so we can't detect the header size, just assume its 16 bytes */
if (track->stream_sector_header_size == 0)
track->stream_sector_header_size = 16;
return track;
}
#endif
struct cdfs_track_t* cdfs_open_track(const char* path, unsigned int track_index)
{
intfstream_t* stream = NULL;
const char* ext = path_get_extension(path);
if (string_is_equal_noncase(ext, "cue"))
return cdfs_open_cue_track(path, track_index);
#ifdef HAVE_CHD
if (string_is_equal_noncase(ext, "chd"))
return intfstream_open_chd_track(path, RETRO_VFS_FILE_ACCESS_READ, RETRO_VFS_FILE_ACCESS_HINT_NONE, track_index);
return cdfs_open_chd_track(path, track_index);
#endif
/* unsupported file type */
return NULL;
}
intfstream_t* cdfs_open_data_track(const char* path)
struct cdfs_track_t* cdfs_open_data_track(const char* path)
{
const char* ext = path_get_extension(path);
if (string_is_equal_noncase(ext, "cue"))
return cdfs_open_cue_track(path, 0);
#ifdef HAVE_CHD
if (string_is_equal_noncase(ext, "chd"))
{
/* TODO: determine data track */
return intfstream_open_chd_track(path, RETRO_VFS_FILE_ACCESS_READ, RETRO_VFS_FILE_ACCESS_HINT_NONE, 1);
}
return cdfs_open_chd_track(path, CHDSTREAM_TRACK_PRIMARY);
#endif
/* unsupported file type - try opening as a raw track */
return cdfs_open_raw_track(path);
}
intfstream_t* cdfs_open_raw_track(const char* path)
cdfs_track_t* cdfs_open_raw_track(const char* path)
{
const char* ext = path_get_extension(path);
if (string_is_equal_noncase(ext, "bin") || string_is_equal_noncase(ext, "iso"))
return intfstream_open_file(path, RETRO_VFS_FILE_ACCESS_READ, RETRO_VFS_FILE_ACCESS_HINT_NONE);
return cdfs_wrap_stream(intfstream_open_file(path, RETRO_VFS_FILE_ACCESS_READ, RETRO_VFS_FILE_ACCESS_HINT_NONE), 0);
/* unsupported file type */
return NULL;
}
void cdfs_close_track(cdfs_track_t* track)
{
if (track)
{
intfstream_close(track->stream);
free(track);
}
}

View file

@ -1682,6 +1682,8 @@ static chd_error hunk_read_into_memory(chd_file *chd, UINT32 hunknum, UINT8 *des
bytes = read_compressed(chd, blockoffs, blocklen);
if (bytes == NULL)
return CHDERR_READ_ERROR;
if (!chd->codecintf[rawmap[0]])
return CHDERR_UNSUPPORTED_FORMAT;
switch (chd->codecintf[rawmap[0]]->compression)
{
case CHD_CODEC_CD_LZMA:

View file

@ -31,25 +31,31 @@ RETRO_BEGIN_DECLS
* of a CD (following the ISO-9660 directory structure definition)
*/
typedef struct cdfs_track_t
{
intfstream_t* stream;
unsigned int stream_sector_size;
unsigned int stream_sector_header_size;
unsigned int pregap_sectors;
} cdfs_track_t;
typedef struct cdfs_file_t
{
int first_sector;
int current_sector;
unsigned int current_sector_offset;
int sector_buffer_valid;
unsigned int stream_sector_size;
unsigned int stream_sector_header_size;
unsigned int size;
unsigned int pos;
intfstream_t* stream;
uint8_t sector_buffer[2048];
struct cdfs_track_t* track;
} cdfs_file_t;
/* opens the specified file within the CD or virtual CD.
* if path is NULL, will open the raw CD (useful for reading CD without having to worry about sector sizes,
* headers, or checksum data)
*/
int cdfs_open_file(cdfs_file_t* file, intfstream_t* stream, const char* path);
int cdfs_open_file(cdfs_file_t* file, cdfs_track_t* stream, const char* path);
void cdfs_close_file(cdfs_file_t* file);
@ -61,6 +67,8 @@ int64_t cdfs_tell(cdfs_file_t* file);
int64_t cdfs_seek(cdfs_file_t* file, int64_t offset, int whence);
void cdfs_seek_sector(cdfs_file_t* file, unsigned int sector);
/* opens the specified track in a CD or virtual CD file - the resulting stream should be passed to
* cdfs_open_file to get access to a file within the CD.
*
@ -75,11 +83,11 @@ int64_t cdfs_seek(cdfs_file_t* file, int64_t offset, int whence);
* MODE1/2048 - untested
* MODE2/2336 - untested
*/
intfstream_t* cdfs_open_track(const char* path, unsigned int track_index);
cdfs_track_t* cdfs_open_track(const char* path, unsigned int track_index);
/* opens the first data track in a CD or virtual CD file. see cdfs_open_track for supported file formats
*/
intfstream_t* cdfs_open_data_track(const char* path);
cdfs_track_t* cdfs_open_data_track(const char* path);
/* opens a raw track file for a CD or virtual CD.
*
@ -89,7 +97,10 @@ intfstream_t* cdfs_open_data_track(const char* path);
* bin - path will point to the bin file
* iso - path will point to the iso file
*/
intfstream_t* cdfs_open_raw_track(const char* path);
cdfs_track_t* cdfs_open_raw_track(const char* path);
/* closes the CD or virtual CD track and frees the associated memory */
void cdfs_close_track(cdfs_track_t* track);
RETRO_END_DECLS

View file

@ -57,6 +57,8 @@ int64_t chdstream_seek(chdstream_t *stream, int64_t offset, int whence);
ssize_t chdstream_get_size(chdstream_t *stream);
uint32_t chdstream_get_pregap(chdstream_t* stream);
RETRO_END_DECLS
#endif

View file

@ -96,6 +96,8 @@ int64_t intfstream_get_size(intfstream_internal_t *intf);
int intfstream_flush(intfstream_internal_t *intf);
uint32_t intfstream_get_chd_pregap(intfstream_internal_t *intf);
intfstream_t* intfstream_open_file(const char *path,
unsigned mode, unsigned hints);

View file

@ -426,5 +426,22 @@ int64_t chdstream_seek(chdstream_t *stream, int64_t offset, int whence)
ssize_t chdstream_get_size(chdstream_t *stream)
{
return stream->track_end;
return stream->track_end;
}
uint32_t chdstream_get_pregap(chdstream_t *stream)
{
metadata_t meta;
uint32_t frame_offset = 0;
uint32_t i;
for (i = 0; chdstream_get_meta(stream->chd, i, &meta); ++i)
{
if (stream->track_frame == frame_offset)
return meta.pregap;
frame_offset += meta.frames + meta.extra;
}
return 0;
}

View file

@ -421,6 +421,16 @@ void intfstream_putc(intfstream_internal_t *intf, int c)
}
}
uint32_t intfstream_get_chd_pregap(intfstream_internal_t *intf)
{
#ifdef HAVE_CHD
if (intf->type == INTFSTREAM_CHD)
return chdstream_get_pregap(intf->chd.fp);
#endif
return 0;
}
intfstream_t* intfstream_open_file(const char *path,
unsigned mode, unsigned hints)
{