2019-06-25 02:51:51 -04:00
/* Copyright (C) 2010-2019 The RetroArch team
*
* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
* The following license statement only applies to this file ( vfs_implementation_cdrom . c ) .
* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
*
* Permission is hereby granted , free of charge ,
* to any person obtaining a copy of this software and associated documentation files ( the " Software " ) ,
* to deal in the Software without restriction , including without limitation the rights to
* use , copy , modify , merge , publish , distribute , sublicense , and / or sell copies of the Software ,
* and to permit persons to whom the Software is furnished to do so , subject to the following conditions :
*
* The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software .
*
* THE SOFTWARE IS PROVIDED " AS IS " , WITHOUT WARRANTY OF ANY KIND , EXPRESS OR IMPLIED ,
* INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY ,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT .
* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM , DAMAGES OR OTHER LIABILITY ,
* WHETHER IN AN ACTION OF CONTRACT , TORT OR OTHERWISE , ARISING FROM ,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE .
*/
2019-06-29 13:28:24 -04:00
# include <vfs/vfs_implementation.h>
2019-06-25 02:51:51 -04:00
# include <file/file_path.h>
# include <compat/fopen_utf8.h>
# include <string/stdstring.h>
2019-06-30 01:47:29 -04:00
# include <cdrom/cdrom.h>
2019-06-25 02:51:51 -04:00
2019-07-03 14:19:16 -04:00
# if defined(_WIN32) && !defined(_XBOX)
2019-06-26 21:45:00 -04:00
# include <windows.h>
# endif
2019-06-25 02:51:51 -04:00
static cdrom_toc_t vfs_cdrom_toc = { 0 } ;
2019-06-29 13:28:24 -04:00
const cdrom_toc_t * retro_vfs_file_get_cdrom_toc ( void )
{
return & vfs_cdrom_toc ;
}
2019-06-25 02:51:51 -04:00
int64_t retro_vfs_file_seek_cdrom ( libretro_vfs_implementation_file * stream , int64_t offset , int whence )
{
const char * ext = path_get_extension ( stream - > orig_path ) ;
if ( string_is_equal_noncase ( ext , " cue " ) )
{
switch ( whence )
{
case SEEK_SET :
2019-06-29 13:28:24 -04:00
stream - > cdrom . byte_pos = offset ;
2019-06-25 02:51:51 -04:00
break ;
case SEEK_CUR :
2019-06-29 13:28:24 -04:00
stream - > cdrom . byte_pos + = offset ;
2019-06-25 02:51:51 -04:00
break ;
case SEEK_END :
2019-06-29 13:28:24 -04:00
stream - > cdrom . byte_pos = ( stream - > cdrom . cue_len - 1 ) + offset ;
2019-06-25 02:51:51 -04:00
break ;
}
# ifdef CDROM_DEBUG
2019-06-29 13:28:24 -04:00
printf ( " CDROM Seek: Path %s Offset % " PRIu64 " is now at % " PRIu64 " \n " , stream - > orig_path , offset , stream - > cdrom . byte_pos ) ;
2019-06-28 18:14:04 -04:00
fflush ( stdout ) ;
2019-06-25 02:51:51 -04:00
# endif
}
else if ( string_is_equal_noncase ( ext , " bin " ) )
{
2019-06-30 01:47:29 -04:00
int lba = ( offset / 2352 ) ;
2019-06-25 02:51:51 -04:00
unsigned char min = 0 ;
unsigned char sec = 0 ;
unsigned char frame = 0 ;
const char * seek_type = " SEEK_SET " ;
2019-06-29 13:46:37 -04:00
( void ) seek_type ;
2019-06-25 02:51:51 -04:00
switch ( whence )
{
case SEEK_CUR :
{
2019-06-30 01:47:29 -04:00
unsigned new_lba ;
2019-06-25 02:51:51 -04:00
2019-06-29 13:28:24 -04:00
stream - > cdrom . byte_pos + = offset ;
2019-06-30 01:47:29 -04:00
new_lba = vfs_cdrom_toc . track [ stream - > cdrom . cur_track - 1 ] . lba + ( stream - > cdrom . byte_pos / 2352 ) ;
2019-06-25 02:51:51 -04:00
seek_type = " SEEK_CUR " ;
2019-07-04 23:05:28 -04:00
cdrom_lba_to_msf ( new_lba , & min , & sec , & frame ) ;
2019-06-30 01:47:29 -04:00
2019-06-25 02:51:51 -04:00
break ;
}
case SEEK_END :
{
2019-07-02 00:12:00 -04:00
ssize_t pregap_lba_len = ( vfs_cdrom_toc . track [ stream - > cdrom . cur_track - 1 ] . audio ? 0 : ( vfs_cdrom_toc . track [ stream - > cdrom . cur_track - 1 ] . lba - vfs_cdrom_toc . track [ stream - > cdrom . cur_track - 1 ] . lba_start ) ) ;
ssize_t lba_len = vfs_cdrom_toc . track [ stream - > cdrom . cur_track - 1 ] . track_size - pregap_lba_len ;
2019-06-25 02:51:51 -04:00
2019-07-04 23:05:28 -04:00
cdrom_lba_to_msf ( lba_len + lba , & min , & sec , & frame ) ;
2019-06-25 02:51:51 -04:00
2019-07-02 00:12:00 -04:00
stream - > cdrom . byte_pos = lba_len * 2352 ;
2019-06-25 02:51:51 -04:00
seek_type = " SEEK_END " ;
break ;
}
case SEEK_SET :
default :
{
seek_type = " SEEK_SET " ;
2019-06-29 13:28:24 -04:00
stream - > cdrom . byte_pos = offset ;
2019-07-04 23:05:28 -04:00
cdrom_lba_to_msf ( vfs_cdrom_toc . track [ stream - > cdrom . cur_track - 1 ] . lba + ( stream - > cdrom . byte_pos / 2352 ) , & min , & sec , & frame ) ;
2019-06-25 02:51:51 -04:00
break ;
}
}
2019-06-29 13:28:24 -04:00
stream - > cdrom . cur_min = min ;
stream - > cdrom . cur_sec = sec ;
stream - > cdrom . cur_frame = frame ;
2019-07-04 23:05:28 -04:00
stream - > cdrom . cur_lba = cdrom_msf_to_lba ( min , sec , frame ) ;
2019-06-25 02:51:51 -04:00
# ifdef CDROM_DEBUG
2019-07-02 00:12:00 -04:00
printf ( " CDROM Seek %s: Path %s Offset % " PRIu64 " is now at % " PRIu64 " (MSF %02u:%02u:%02u) (LBA %u)... \n " , seek_type , stream - > orig_path , offset , stream - > cdrom . byte_pos , ( unsigned ) stream - > cdrom . cur_min , ( unsigned ) stream - > cdrom . cur_sec , ( unsigned ) stream - > cdrom . cur_frame , stream - > cdrom . cur_lba ) ;
2019-06-28 18:14:04 -04:00
fflush ( stdout ) ;
2019-06-25 02:51:51 -04:00
# endif
}
else
return - 1 ;
return 0 ;
}
2019-06-26 21:45:00 -04:00
void retro_vfs_file_open_cdrom (
2019-06-25 02:51:51 -04:00
libretro_vfs_implementation_file * stream ,
const char * path , unsigned mode , unsigned hints )
{
2019-07-03 14:19:16 -04:00
# if defined(__linux__) && !defined(ANDROID)
2019-06-25 02:51:51 -04:00
char cdrom_path [ ] = " /dev/sg1 " ;
size_t path_len = strlen ( path ) ;
const char * ext = path_get_extension ( path ) ;
2019-06-30 03:05:44 -04:00
stream - > cdrom . cur_track = 1 ;
2019-06-25 02:51:51 -04:00
if ( ! string_is_equal_noncase ( ext , " cue " ) & & ! string_is_equal_noncase ( ext , " bin " ) )
2019-06-26 21:45:00 -04:00
return ;
2019-06-25 02:51:51 -04:00
2019-06-29 13:28:24 -04:00
if ( path_len > = strlen ( " drive1-track01.bin " ) )
{
if ( ! memcmp ( path , " drive " , strlen ( " drive " ) ) )
{
if ( ! memcmp ( path + 6 , " -track " , strlen ( " -track " ) ) )
{
2019-06-29 15:17:44 -04:00
if ( sscanf ( path + 12 , " %02u " , ( unsigned * ) & stream - > cdrom . cur_track ) )
2019-06-29 13:28:24 -04:00
{
# ifdef CDROM_DEBUG
printf ( " CDROM: Opening track %d \n " , stream - > cdrom . cur_track ) ;
fflush ( stdout ) ;
# endif
}
}
}
}
2019-06-25 02:51:51 -04:00
if ( path_len > = strlen ( " drive1.cue " ) )
{
if ( ! memcmp ( path , " drive " , strlen ( " drive " ) ) )
{
if ( path [ 5 ] > = ' 0 ' & & path [ 5 ] < = ' 9 ' )
{
cdrom_path [ 7 ] = path [ 5 ] ;
2019-06-29 13:28:24 -04:00
stream - > cdrom . drive = path [ 5 ] ;
vfs_cdrom_toc . drive = stream - > cdrom . drive ;
2019-06-25 02:51:51 -04:00
}
}
}
# ifdef CDROM_DEBUG
printf ( " CDROM Open: Path %s URI %s \n " , cdrom_path , path ) ;
2019-06-28 18:14:04 -04:00
fflush ( stdout ) ;
2019-06-25 02:51:51 -04:00
# endif
2019-06-26 21:45:00 -04:00
stream - > fp = ( FILE * ) fopen_utf8 ( cdrom_path , " r+b " ) ;
2019-06-25 02:51:51 -04:00
2019-07-04 00:21:41 -04:00
if ( ! stream - > fp )
2019-06-26 21:45:00 -04:00
return ;
2019-06-25 02:51:51 -04:00
if ( string_is_equal_noncase ( ext , " cue " ) )
{
2019-06-29 13:28:24 -04:00
if ( stream - > cdrom . cue_buf )
2019-06-25 02:51:51 -04:00
{
2019-06-29 13:28:24 -04:00
free ( stream - > cdrom . cue_buf ) ;
stream - > cdrom . cue_buf = NULL ;
2019-06-25 02:51:51 -04:00
}
2019-06-29 13:28:24 -04:00
cdrom_write_cue ( stream , & stream - > cdrom . cue_buf , & stream - > cdrom . cue_len , stream - > cdrom . drive , & vfs_cdrom_toc . num_tracks , & vfs_cdrom_toc ) ;
2019-06-25 02:51:51 -04:00
# ifdef CDROM_DEBUG
2019-06-29 13:28:24 -04:00
if ( string_is_empty ( stream - > cdrom . cue_buf ) )
2019-06-28 18:14:04 -04:00
{
2019-06-25 02:51:51 -04:00
printf ( " Error writing cue sheet. \n " ) ;
2019-06-28 18:14:04 -04:00
fflush ( stdout ) ;
}
2019-06-25 02:51:51 -04:00
else
{
2019-06-29 13:28:24 -04:00
printf ( " CDROM CUE Sheet: \n %s \n " , stream - > cdrom . cue_buf ) ;
2019-06-25 02:51:51 -04:00
fflush ( stdout ) ;
}
# endif
}
# endif
2019-07-03 14:19:16 -04:00
# if defined(_WIN32) && !defined(_XBOX)
2019-06-26 21:45:00 -04:00
char cdrom_path [ ] = " \\ \\ . \\ D: " ;
size_t path_len = strlen ( path ) ;
const char * ext = path_get_extension ( path ) ;
if ( ! string_is_equal_noncase ( ext , " cue " ) & & ! string_is_equal_noncase ( ext , " bin " ) )
return ;
2019-06-29 13:28:24 -04:00
if ( path_len > = strlen ( " d:/drive-track01.bin " ) )
{
if ( ! memcmp ( path + 1 , " :/drive-track " , strlen ( " :/drive-track " ) ) )
{
2019-06-29 15:17:44 -04:00
if ( sscanf ( path + 14 , " %02u " , ( unsigned * ) & stream - > cdrom . cur_track ) )
2019-06-29 13:28:24 -04:00
{
# ifdef CDROM_DEBUG
printf ( " CDROM: Opening track %d \n " , stream - > cdrom . cur_track ) ;
fflush ( stdout ) ;
# endif
}
}
}
if ( path_len > = strlen ( " d:/drive.cue " ) )
2019-06-26 21:45:00 -04:00
{
2019-06-29 13:28:24 -04:00
if ( ! memcmp ( path + 1 , " :/drive " , strlen ( " :/drive " ) ) )
2019-06-26 21:45:00 -04:00
{
if ( ( path [ 0 ] > = ' A ' & & path [ 0 ] < = ' Z ' ) | | ( path [ 0 ] > = ' a ' & & path [ 0 ] < = ' z ' ) )
{
cdrom_path [ 4 ] = path [ 0 ] ;
2019-06-29 13:28:24 -04:00
stream - > cdrom . drive = path [ 0 ] ;
vfs_cdrom_toc . drive = stream - > cdrom . drive ;
2019-06-26 21:45:00 -04:00
}
}
}
# ifdef CDROM_DEBUG
printf ( " CDROM Open: Path %s URI %s \n " , cdrom_path , path ) ;
2019-06-28 18:14:04 -04:00
fflush ( stdout ) ;
2019-06-26 21:45:00 -04:00
# endif
stream - > fh = CreateFile ( cdrom_path , GENERIC_READ | GENERIC_WRITE , FILE_SHARE_READ | FILE_SHARE_WRITE , NULL , OPEN_EXISTING , FILE_ATTRIBUTE_NORMAL , NULL ) ;
if ( stream - > fh = = INVALID_HANDLE_VALUE )
return ;
2019-06-25 02:51:51 -04:00
2019-06-26 21:45:00 -04:00
if ( string_is_equal_noncase ( ext , " cue " ) )
{
2019-06-29 13:28:24 -04:00
if ( stream - > cdrom . cue_buf )
2019-06-26 21:45:00 -04:00
{
2019-06-29 13:28:24 -04:00
free ( stream - > cdrom . cue_buf ) ;
stream - > cdrom . cue_buf = NULL ;
2019-06-26 21:45:00 -04:00
}
2019-06-29 13:28:24 -04:00
cdrom_write_cue ( stream , & stream - > cdrom . cue_buf , & stream - > cdrom . cue_len , stream - > cdrom . drive , & vfs_cdrom_toc . num_tracks , & vfs_cdrom_toc ) ;
2019-06-26 21:45:00 -04:00
# ifdef CDROM_DEBUG
2019-06-29 13:28:24 -04:00
if ( string_is_empty ( stream - > cdrom . cue_buf ) )
2019-06-28 18:14:04 -04:00
{
2019-06-26 21:45:00 -04:00
printf ( " Error writing cue sheet. \n " ) ;
2019-06-28 18:14:04 -04:00
fflush ( stdout ) ;
}
2019-06-26 21:45:00 -04:00
else
{
2019-06-29 13:28:24 -04:00
printf ( " CDROM CUE Sheet: \n %s \n " , stream - > cdrom . cue_buf ) ;
2019-06-26 21:45:00 -04:00
fflush ( stdout ) ;
}
# endif
}
# endif
2019-06-29 13:28:24 -04:00
if ( vfs_cdrom_toc . num_tracks > 1 & & stream - > cdrom . cur_track )
{
stream - > cdrom . cur_min = vfs_cdrom_toc . track [ stream - > cdrom . cur_track - 1 ] . min ;
stream - > cdrom . cur_sec = vfs_cdrom_toc . track [ stream - > cdrom . cur_track - 1 ] . sec ;
stream - > cdrom . cur_frame = vfs_cdrom_toc . track [ stream - > cdrom . cur_track - 1 ] . frame ;
2019-07-04 23:05:28 -04:00
stream - > cdrom . cur_lba = cdrom_msf_to_lba ( stream - > cdrom . cur_min , stream - > cdrom . cur_sec , stream - > cdrom . cur_frame ) ;
2019-06-29 13:28:24 -04:00
}
else
{
stream - > cdrom . cur_min = vfs_cdrom_toc . track [ 0 ] . min ;
stream - > cdrom . cur_sec = vfs_cdrom_toc . track [ 0 ] . sec ;
stream - > cdrom . cur_frame = vfs_cdrom_toc . track [ 0 ] . frame ;
2019-07-04 23:05:28 -04:00
stream - > cdrom . cur_lba = cdrom_msf_to_lba ( stream - > cdrom . cur_min , stream - > cdrom . cur_sec , stream - > cdrom . cur_frame ) ;
2019-06-29 13:28:24 -04:00
}
2019-06-25 02:51:51 -04:00
}
int retro_vfs_file_close_cdrom ( libretro_vfs_implementation_file * stream )
{
# ifdef CDROM_DEBUG
2019-06-28 18:14:04 -04:00
printf ( " CDROM Close: Path %s \n " , stream - > orig_path ) ;
fflush ( stdout ) ;
2019-06-25 02:51:51 -04:00
# endif
2019-07-03 14:19:16 -04:00
# if defined(_WIN32) && !defined(_XBOX)
2019-06-29 13:28:24 -04:00
if ( ! stream - > fh | | ! CloseHandle ( stream - > fh ) )
2019-06-26 21:45:00 -04:00
return - 1 ;
# else
2019-06-29 13:28:24 -04:00
if ( ! stream - > fp | | fclose ( stream - > fp ) )
2019-06-25 02:51:51 -04:00
return - 1 ;
2019-06-26 21:45:00 -04:00
# endif
2019-06-25 02:51:51 -04:00
return 0 ;
}
int64_t retro_vfs_file_tell_cdrom ( libretro_vfs_implementation_file * stream )
{
if ( ! stream )
return - 1 ;
const char * ext = path_get_extension ( stream - > orig_path ) ;
if ( string_is_equal_noncase ( ext , " cue " ) )
{
# ifdef CDROM_DEBUG
2019-06-29 13:28:24 -04:00
printf ( " CDROM (cue) Tell: Path %s Position % " PRIu64 " \n " , stream - > orig_path , stream - > cdrom . byte_pos ) ;
2019-06-28 18:14:04 -04:00
fflush ( stdout ) ;
2019-06-25 02:51:51 -04:00
# endif
2019-06-29 13:28:24 -04:00
return stream - > cdrom . byte_pos ;
2019-06-25 02:51:51 -04:00
}
else if ( string_is_equal_noncase ( ext , " bin " ) )
{
# ifdef CDROM_DEBUG
2019-06-30 01:47:29 -04:00
printf ( " CDROM (bin) Tell: Path %s Position % " PRId64 " \n " , stream - > orig_path , stream - > cdrom . byte_pos ) ;
2019-06-28 18:14:04 -04:00
fflush ( stdout ) ;
2019-06-25 02:51:51 -04:00
# endif
2019-06-30 01:47:29 -04:00
return stream - > cdrom . byte_pos ;
2019-06-25 02:51:51 -04:00
}
return - 1 ;
}
int64_t retro_vfs_file_read_cdrom ( libretro_vfs_implementation_file * stream ,
void * s , uint64_t len )
{
int rv ;
const char * ext = path_get_extension ( stream - > orig_path ) ;
if ( string_is_equal_noncase ( ext , " cue " ) )
{
2019-06-29 13:28:24 -04:00
if ( len < stream - > cdrom . cue_len - stream - > cdrom . byte_pos )
2019-06-25 02:51:51 -04:00
{
# ifdef CDROM_DEBUG
2019-06-29 13:28:24 -04:00
printf ( " CDROM Read: Reading % " PRIu64 " bytes from cuesheet starting at % " PRIu64 " ... \n " , len , stream - > cdrom . byte_pos ) ;
2019-06-28 18:14:04 -04:00
fflush ( stdout ) ;
2019-06-25 02:51:51 -04:00
# endif
2019-06-29 13:28:24 -04:00
memcpy ( s , stream - > cdrom . cue_buf + stream - > cdrom . byte_pos , len ) ;
stream - > cdrom . byte_pos + = len ;
2019-06-25 02:51:51 -04:00
return len ;
}
else
{
# ifdef CDROM_DEBUG
2019-06-29 13:28:24 -04:00
printf ( " CDROM Read: Reading % " PRIu64 " bytes from cuesheet starting at % " PRIu64 " failed. \n " , len , stream - > cdrom . byte_pos ) ;
2019-06-28 18:14:04 -04:00
fflush ( stdout ) ;
2019-06-25 02:51:51 -04:00
# endif
return 0 ;
}
}
else if ( string_is_equal_noncase ( ext , " bin " ) )
{
2019-06-29 13:28:24 -04:00
size_t skip = stream - > cdrom . byte_pos % 2352 ;
2019-06-25 02:51:51 -04:00
unsigned char min = 0 ;
unsigned char sec = 0 ;
unsigned char frame = 0 ;
2019-07-04 23:05:28 -04:00
cdrom_lba_to_msf ( stream - > cdrom . cur_lba , & min , & sec , & frame ) ;
2019-06-25 02:51:51 -04:00
# ifdef CDROM_DEBUG
2019-07-02 00:12:00 -04:00
printf ( " CDROM Read: Reading % " PRIu64 " bytes from %s starting at byte offset % " PRIu64 " (MSF %02u:%02u:%02u) (LBA %u) skip % " PRIu64 " ... \n " , len , stream - > orig_path , stream - > cdrom . byte_pos , ( unsigned ) min , ( unsigned ) sec , ( unsigned ) frame , stream - > cdrom . cur_lba , skip ) ;
2019-06-28 18:14:04 -04:00
fflush ( stdout ) ;
2019-06-25 02:51:51 -04:00
# endif
2019-07-04 22:42:42 -04:00
/*rv = cdrom_read(stream, min, sec, frame, s, (size_t)len, skip);*/
rv = cdrom_read_lba ( stream , stream - > cdrom . cur_lba - 150 , s , ( size_t ) len , skip ) ;
2019-06-25 02:51:51 -04:00
if ( rv )
{
# ifdef CDROM_DEBUG
2019-06-26 21:45:00 -04:00
printf ( " Failed to read % " PRIu64 " bytes from CD. \n " , len ) ;
2019-06-28 18:14:04 -04:00
fflush ( stdout ) ;
2019-06-25 02:51:51 -04:00
# endif
return 0 ;
}
2019-06-29 13:28:24 -04:00
stream - > cdrom . byte_pos + = len ;
2019-06-30 01:47:29 -04:00
stream - > cdrom . cur_lba = vfs_cdrom_toc . track [ stream - > cdrom . cur_track - 1 ] . lba + ( stream - > cdrom . byte_pos / 2352 ) ;
2019-07-04 23:05:28 -04:00
cdrom_lba_to_msf ( stream - > cdrom . cur_lba , & stream - > cdrom . cur_min , & stream - > cdrom . cur_sec , & stream - > cdrom . cur_frame ) ;
2019-06-25 02:51:51 -04:00
# ifdef CDROM_DEBUG
2019-07-04 23:05:28 -04:00
printf ( " CDROM read % " PRIu64 " bytes, position is now: % " PRIu64 " (MSF %02u:%02u:%02u) (LBA %u) \n " , len , stream - > cdrom . byte_pos , ( unsigned ) stream - > cdrom . cur_min , ( unsigned ) stream - > cdrom . cur_sec , ( unsigned ) stream - > cdrom . cur_frame , cdrom_msf_to_lba ( stream - > cdrom . cur_min , stream - > cdrom . cur_sec , stream - > cdrom . cur_frame ) ) ;
2019-06-28 18:14:04 -04:00
fflush ( stdout ) ;
2019-06-25 02:51:51 -04:00
# endif
return len ;
}
return 0 ;
}
2019-06-26 21:45:00 -04:00
int retro_vfs_file_error_cdrom ( libretro_vfs_implementation_file * stream )
{
return 0 ;
}
2019-06-29 20:03:59 -04:00
const vfs_cdrom_t * retro_vfs_file_get_cdrom_position ( const libretro_vfs_implementation_file * stream )
{
return & stream - > cdrom ;
}