diff --git a/cheevos/cheevos.c b/cheevos/cheevos.c index 4005c6b621..a3ea1d03c1 100644 --- a/cheevos/cheevos.c +++ b/cheevos/cheevos.c @@ -1278,7 +1278,7 @@ static void* rc_hash_handle_chd_open_track( break; case RC_HASH_CDTRACK_LARGEST: - cdfs_track = cdfs_open_track(path, CHDSTREAM_TRACK_LAST); + cdfs_track = cdfs_open_track(path, CHDSTREAM_TRACK_PRIMARY); break; default: @@ -1304,11 +1304,23 @@ static size_t rc_hash_handle_chd_read_sector( void* buffer, size_t requested_bytes) { cdfs_file_t* file = (cdfs_file_t*)track_handle; + uint32_t track_sectors = cdfs_get_num_sectors(file); + + sector -= cdfs_get_first_sector(file); + if (sector >= track_sectors) + return 0; cdfs_seek_sector(file, sector); return cdfs_read_file(file, buffer, requested_bytes); } +static uint32_t rc_hash_handle_chd_first_track_sector( + void* track_handle) +{ + cdfs_file_t* file = (cdfs_file_t*)track_handle; + return cdfs_get_first_sector(file); +} + static void rc_hash_handle_chd_close_track(void* track_handle) { cdfs_file_t* file = (cdfs_file_t*)track_handle; @@ -1337,6 +1349,7 @@ static void* rc_hash_handle_cd_open_track( cdreader.open_track = rc_hash_handle_cd_open_track; cdreader.read_sector = rc_hash_handle_chd_read_sector; cdreader.close_track = rc_hash_handle_chd_close_track; + cdreader.first_track_sector = rc_hash_handle_chd_first_track_sector; rc_hash_init_custom_cdreader(&cdreader); return rc_hash_handle_chd_open_track(path, track); diff --git a/libretro-common/formats/cdfs/cdfs.c b/libretro-common/formats/cdfs/cdfs.c index f826dcd482..4995666ebf 100644 --- a/libretro-common/formats/cdfs/cdfs.c +++ b/libretro-common/formats/cdfs/cdfs.c @@ -58,30 +58,31 @@ static void cdfs_determine_sector_size(cdfs_track_t* track) track->stream_sector_size = 2352; track->stream_sector_header_size = 16; } - else - { - /* attempt to determine stream_sector_size from file size */ - size_t size = intfstream_get_size(track->stream); + } +} - if ((size % 2352) == 0) - { - /* raw tracks use all 2352 bytes and have a 24 byte header */ - track->stream_sector_size = 2352; - track->stream_sector_header_size = 24; - } - else if ((size % 2048) == 0) - { - /* cooked tracks eliminate all header/footer data */ - track->stream_sector_size = 2048; - track->stream_sector_header_size = 0; - } - else if ((size % 2336) == 0) - { - /* MODE 2 format without 16-byte sync data */ - track->stream_sector_size = 2336; - track->stream_sector_header_size = 8; - } - } +static void cdfs_determine_sector_size_from_file_size(cdfs_track_t* track) +{ + /* attempt to determine stream_sector_size from file size */ + size_t size = intfstream_get_size(track->stream); + + if ((size % 2352) == 0) + { + /* raw tracks use all 2352 bytes and have a 24 byte header */ + track->stream_sector_size = 2352; + track->stream_sector_header_size = 24; + } + else if ((size % 2048) == 0) + { + /* cooked tracks eliminate all header/footer data */ + track->stream_sector_size = 2048; + track->stream_sector_header_size = 0; + } + else if ((size % 2336) == 0) + { + /* MODE 2 format without 16-byte sync data */ + track->stream_sector_size = 2336; + track->stream_sector_header_size = 8; } } @@ -109,6 +110,23 @@ void cdfs_seek_sector(cdfs_file_t* file, unsigned int sector) } } +uint32_t cdfs_get_num_sectors(cdfs_file_t* file) +{ + uint32_t frame_size = intfstream_get_frame_size(file->track->stream); + if (frame_size == 0) + { + frame_size = file->track->stream_sector_size; + if (frame_size == 0) + frame_size = 1; /* prevent divide by 0 error if sector size is unknown */ + } + return intfstream_get_size(file->track->stream) / frame_size; +} + +uint32_t cdfs_get_first_sector(cdfs_file_t* file) +{ + return file->track->first_sector_index; +} + static int cdfs_find_file(cdfs_file_t* file, const char* path) { size_t path_length; @@ -356,7 +374,7 @@ static void cdfs_skip_spaces(const char** ptr) } static cdfs_track_t* cdfs_wrap_stream( - intfstream_t* stream, unsigned first_sector_offset) + intfstream_t* stream, unsigned first_sector_offset, unsigned first_sector_index) { cdfs_track_t* track = NULL; @@ -367,6 +385,7 @@ static cdfs_track_t* cdfs_wrap_stream( calloc(1, sizeof(*track)); track->stream = stream; track->first_sector_offset = first_sector_offset; + track->first_sector_index = first_sector_index; cdfs_determine_sector_size(track); @@ -507,9 +526,12 @@ static cdfs_track_t* cdfs_open_cue_track( if (string_is_empty(track_path)) return NULL; + /* NOTE: previous_index_sector_offset will only be valid if all tracks are in the same BIN file. + * Otherwise, we need to determine how many tracks are in each previous BIN file, which is not + * stored in the CUE file. This will affect cdfs_get_first_sector, which luckily isn't used much. */ track = cdfs_wrap_stream(intfstream_open_file( track_path, RETRO_VFS_FILE_ACCESS_READ, - RETRO_VFS_FILE_ACCESS_HINT_NONE), track_offset); + RETRO_VFS_FILE_ACCESS_HINT_NONE), track_offset, previous_index_sector_offset); if (track && track->stream_sector_size == 0) { @@ -537,7 +559,8 @@ static cdfs_track_t* cdfs_open_chd_track(const char* path, int32_t track_index) return NULL; track = cdfs_wrap_stream(intf_stream, - intfstream_get_offset_to_start(intf_stream)); + intfstream_get_offset_to_start(intf_stream), + intfstream_get_first_sector(intf_stream)); if (track && track->stream_sector_header_size == 0) { @@ -601,11 +624,15 @@ cdfs_track_t* cdfs_open_raw_track(const char* path) intfstream_t* file = intfstream_open_file(path, RETRO_VFS_FILE_ACCESS_READ, RETRO_VFS_FILE_ACCESS_HINT_NONE); - track = cdfs_wrap_stream(file, 0); + track = cdfs_wrap_stream(file, 0, 0); if (track != NULL && track->stream_sector_size == 0) { - cdfs_close_track(track); - track = NULL; + cdfs_determine_sector_size_from_file_size(track); + if (track->stream_sector_size == 0) + { + cdfs_close_track(track); + track = NULL; + } } } else diff --git a/libretro-common/include/formats/cdfs.h b/libretro-common/include/formats/cdfs.h index 9fba88ce89..ab4241e4ca 100644 --- a/libretro-common/include/formats/cdfs.h +++ b/libretro-common/include/formats/cdfs.h @@ -37,6 +37,7 @@ typedef struct cdfs_track_t unsigned int stream_sector_size; unsigned int stream_sector_header_size; unsigned int first_sector_offset; + unsigned int first_sector_index; } cdfs_track_t; typedef struct cdfs_file_t @@ -70,6 +71,10 @@ int64_t cdfs_seek(cdfs_file_t* file, int64_t offset, int whence); void cdfs_seek_sector(cdfs_file_t* file, unsigned int sector); +uint32_t cdfs_get_num_sectors(cdfs_file_t* file); + +uint32_t cdfs_get_first_sector(cdfs_file_t* file); + /* 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. * diff --git a/libretro-common/include/streams/chd_stream.h b/libretro-common/include/streams/chd_stream.h index 83c97acd7c..51fd4d3ee9 100644 --- a/libretro-common/include/streams/chd_stream.h +++ b/libretro-common/include/streams/chd_stream.h @@ -61,6 +61,8 @@ uint32_t chdstream_get_track_start(chdstream_t* stream); uint32_t chdstream_get_frame_size(chdstream_t* stream); +uint32_t chdstream_get_first_track_sector(chdstream_t* stream); + RETRO_END_DECLS #endif diff --git a/libretro-common/include/streams/interface_stream.h b/libretro-common/include/streams/interface_stream.h index 2070cc0724..b62552f219 100644 --- a/libretro-common/include/streams/interface_stream.h +++ b/libretro-common/include/streams/interface_stream.h @@ -106,6 +106,8 @@ uint32_t intfstream_get_offset_to_start(intfstream_internal_t *intf); uint32_t intfstream_get_frame_size(intfstream_internal_t *intf); +uint32_t intfstream_get_first_sector(intfstream_internal_t* intf); + bool intfstream_is_compressed(intfstream_internal_t *intf); bool intfstream_get_crc(intfstream_internal_t *intf, uint32_t *crc); diff --git a/libretro-common/streams/chd_stream.c b/libretro-common/streams/chd_stream.c index 6d934eac50..a13bf8705f 100644 --- a/libretro-common/streams/chd_stream.c +++ b/libretro-common/streams/chd_stream.c @@ -163,10 +163,7 @@ chdstream_find_special_track(chd_file *fd, int32_t track, metadata_t *meta) if (!chdstream_find_track_number(fd, i, &iter)) { if (track == CHDSTREAM_TRACK_LAST && i > 1) - { - *meta = iter; - return true; - } + return chdstream_find_track_number(fd, i - 1, meta); if (track == CHDSTREAM_TRACK_PRIMARY && largest_track != 0) return chdstream_find_track_number(fd, largest_track, meta); @@ -450,3 +447,22 @@ uint32_t chdstream_get_frame_size(chdstream_t *stream) { return stream->frame_size; } + +uint32_t chdstream_get_first_track_sector(chdstream_t* stream) +{ + uint32_t i; + metadata_t meta; + uint32_t frame_offset = 0; + uint32_t sector_offset = 0; + + for (i = 0; chdstream_get_meta(stream->chd, i, &meta); ++i) + { + if (stream->track_frame == frame_offset) + return sector_offset; + + sector_offset += meta.frames; + frame_offset += meta.frames + meta.extra; + } + + return 0; +} diff --git a/libretro-common/streams/interface_stream.c b/libretro-common/streams/interface_stream.c index 3852801cb7..5f65c491aa 100644 --- a/libretro-common/streams/interface_stream.c +++ b/libretro-common/streams/interface_stream.c @@ -604,6 +604,19 @@ uint32_t intfstream_get_frame_size(intfstream_internal_t *intf) return 0; } +uint32_t intfstream_get_first_sector(intfstream_internal_t* intf) +{ + if (intf) + { +#ifdef HAVE_CHD + if (intf->type == INTFSTREAM_CHD) + return chdstream_get_first_track_sector(intf->chd.fp); +#endif + } + + return 0; +} + bool intfstream_is_compressed(intfstream_internal_t *intf) { if (!intf)