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-08-13 19:41:01 -06:00
|
|
|
#include <vfs/vfs_implementation_cdrom.h>
|
2019-06-25 02:51:51 -04:00
|
|
|
#include <file/file_path.h>
|
|
|
|
#include <compat/fopen_utf8.h>
|
|
|
|
#include <string/stdstring.h>
|
2019-08-13 19:41:01 -06:00
|
|
|
#include <retro_miscellaneous.h>
|
|
|
|
|
|
|
|
#ifdef HAVE_CDROM
|
2019-06-30 01:47:29 -04:00
|
|
|
#include <cdrom/cdrom.h>
|
2019-08-13 19:41:01 -06:00
|
|
|
#endif
|
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-08-13 19:41:01 -06:00
|
|
|
/*#define CDROM_CUE_PARSE_DEBUG*/
|
|
|
|
|
|
|
|
#ifdef HAVE_CDROM
|
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-08-13 19:41:01 -06:00
|
|
|
#endif
|
2019-06-29 13:28:24 -04:00
|
|
|
|
2019-08-13 19:41:01 -06:00
|
|
|
static void retro_vfs_file_seek_cdrom_track_sector(libretro_vfs_implementation_file* stream, unsigned sector)
|
2019-06-25 02:51:51 -04:00
|
|
|
{
|
2019-08-13 19:41:01 -06:00
|
|
|
retro_vfs_file_seek_cdrom_track(stream, sector * stream->track->sector_size, SEEK_SET);
|
|
|
|
}
|
2019-06-25 02:51:51 -04:00
|
|
|
|
2019-08-13 19:41:01 -06:00
|
|
|
static unsigned char retro_vs_file_get_sector_header_size(libretro_vfs_implementation_file* track_stream)
|
|
|
|
{
|
|
|
|
unsigned char buffer[32];
|
|
|
|
unsigned char sector_header_size = 0;
|
|
|
|
|
|
|
|
if (!track_stream || !track_stream->track)
|
|
|
|
return 0;
|
|
|
|
|
|
|
|
/* MODE information is normally found in the CUE sheet, but we can try to determine it from the raw data.
|
|
|
|
*
|
|
|
|
* MODE1/2048 - CDROM Mode1 Data (cooked) [no header, no footer]
|
|
|
|
* MODE1/2352 - CDROM Mode1 Data (raw) [16 byte header, 288 byte footer]
|
|
|
|
* MODE2/2336 - CDROM-XA Mode2 Data [8 byte header, 280 byte footer]
|
|
|
|
* MODE2/2352 - CDROM-XA Mode2 Data [24 byte header, 280 byte footer]
|
|
|
|
*
|
|
|
|
* Note that MODE is actually a property on each sector and can change between 1 and 2 depending on how much error
|
|
|
|
* correction the author desired. To support that, the data format must be "/2352" to include the full header and
|
|
|
|
* data without error correction information, at which point the CUE sheet information becomes just a hint.
|
|
|
|
* For simplicitly, we currently only handle "/2352" modes
|
|
|
|
*/
|
|
|
|
|
|
|
|
/* The boot record or primary volume descriptor is always at sector 16 and will contain a "CD001" marker */
|
|
|
|
retro_vfs_file_seek_cdrom_track_sector(track_stream, 16);
|
|
|
|
if (retro_vfs_file_read_cdrom_track(track_stream, buffer, sizeof(buffer)) == 0)
|
|
|
|
return 0;
|
|
|
|
|
|
|
|
/* ISO-9660 says the first twelve bytes of a sector should be the sync pattern 00 FF FF FF FF FF FF FF FF FF FF 00
|
|
|
|
* if it's not, then assume the track is audio data and has no header or MODE2/2336 which we don't support */
|
|
|
|
if (buffer[0] == 0 && buffer[1] == 0xFF && buffer[2] == 0xFF && buffer[3] == 0xFF &&
|
|
|
|
buffer[4] == 0xFF && buffer[5] == 0xFF && buffer[6] == 0xFF && buffer[7] == 0xFF &&
|
|
|
|
buffer[8] == 0xFF && buffer[9] == 0xFF && buffer[10] == 0xFF && buffer[11] == 0)
|
2019-06-25 02:51:51 -04:00
|
|
|
{
|
2019-08-13 19:41:01 -06:00
|
|
|
/* after the 12 byte sync pattern is three bytes identifying the sector and then one byte for the mode (total 16 bytes) */
|
|
|
|
sector_header_size = 16;
|
|
|
|
track_stream->track->mode = buffer[15];
|
|
|
|
|
|
|
|
/* if this is a CDROM-XA data source, the "CD001" tag will be offset by an additional 8 bytes */
|
|
|
|
if (buffer[25] == 0x43 && buffer[26] == 0x44 &&
|
|
|
|
buffer[27] == 0x30 && buffer[28] == 0x30 && buffer[29] == 0x31)
|
2019-06-25 02:51:51 -04:00
|
|
|
{
|
2019-08-13 19:41:01 -06:00
|
|
|
sector_header_size = 24;
|
2019-06-25 02:51:51 -04:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2019-08-13 19:41:01 -06:00
|
|
|
return sector_header_size;
|
|
|
|
}
|
2019-06-29 13:46:37 -04:00
|
|
|
|
2019-08-13 19:41:01 -06:00
|
|
|
#ifdef HAVE_CDROM
|
2019-06-25 02:51:51 -04:00
|
|
|
|
2019-08-13 19:41:01 -06:00
|
|
|
static bool retro_vfs_file_open_cdrom_handle(libretro_vfs_implementation_file* stream, const char* path, char drive)
|
|
|
|
{
|
|
|
|
#ifdef CDROM_DEBUG
|
|
|
|
printf("[CDROM] Open: Path %s\n", path);
|
|
|
|
fflush(stdout);
|
|
|
|
#endif
|
2019-06-25 02:51:51 -04:00
|
|
|
|
2019-08-13 19:41:01 -06:00
|
|
|
#if defined(__linux__) && !defined(ANDROID)
|
|
|
|
char cdrom_path[] = "/dev/sg1";
|
|
|
|
cdrom_path[7] = drive;
|
2019-06-30 01:47:29 -04:00
|
|
|
|
2019-08-13 19:41:01 -06:00
|
|
|
stream->fp = (FILE*)fopen_utf8(cdrom_path, "r+b");
|
2019-06-25 02:51:51 -04:00
|
|
|
|
2019-08-13 19:41:01 -06:00
|
|
|
if (!stream->fp)
|
|
|
|
return false;
|
|
|
|
#elif defined(_WIN32) && !defined(_XBOX)
|
|
|
|
char cdrom_path[] = "\\\\.\\D:";
|
|
|
|
cdrom_path[4] = drive;
|
2019-06-25 02:51:51 -04:00
|
|
|
|
2019-08-13 19:41:01 -06:00
|
|
|
stream->fh = CreateFile(cdrom_path, GENERIC_READ | GENERIC_WRITE, FILE_SHARE_READ | FILE_SHARE_WRITE, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
|
2019-06-25 02:51:51 -04:00
|
|
|
|
2019-08-13 19:41:01 -06:00
|
|
|
if (stream->fh == INVALID_HANDLE_VALUE)
|
|
|
|
{
|
|
|
|
stream->fh = NULL;
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
#endif
|
2019-06-25 02:51:51 -04:00
|
|
|
|
2019-08-13 19:41:01 -06:00
|
|
|
stream->orig_path = strdup(path);
|
2019-06-25 02:51:51 -04:00
|
|
|
|
2019-08-13 19:41:01 -06:00
|
|
|
cdrom_write_cue(stream, &stream->cdrom.cue_buf, &stream->cdrom.cue_len, stream->cdrom.drive, &vfs_cdrom_toc.num_tracks, &vfs_cdrom_toc);
|
|
|
|
cdrom_get_timeouts(stream, &vfs_cdrom_toc.timeouts);
|
2019-06-25 02:51:51 -04:00
|
|
|
|
2019-08-13 19:41:01 -06:00
|
|
|
return true;
|
2019-06-25 02:51:51 -04:00
|
|
|
}
|
|
|
|
|
2019-08-13 19:41:01 -06:00
|
|
|
#endif
|
|
|
|
|
|
|
|
bool retro_vfs_file_open_cdrom(
|
|
|
|
libretro_vfs_implementation_file* stream,
|
|
|
|
const char* path, unsigned mode, unsigned hints)
|
2019-06-25 02:51:51 -04:00
|
|
|
{
|
|
|
|
size_t path_len = strlen(path);
|
2019-08-13 19:41:01 -06:00
|
|
|
const char* ext = path_get_extension(path);
|
2019-06-30 03:05:44 -04:00
|
|
|
|
2019-08-13 19:41:01 -06:00
|
|
|
if (string_is_equal_noncase(ext, "cue"))
|
2019-06-29 13:28:24 -04:00
|
|
|
{
|
2019-08-13 19:41:01 -06:00
|
|
|
stream->cdrom.drive = '\0';
|
|
|
|
|
|
|
|
#ifdef HAVE_CDROM
|
|
|
|
#if defined(__linux__) && !defined(ANDROID)
|
|
|
|
if (path_len >= strlen("drive1.cue"))
|
2019-06-29 13:28:24 -04:00
|
|
|
{
|
2019-08-13 19:41:01 -06:00
|
|
|
if (!memcmp(path, "drive", strlen("drive")))
|
2019-06-29 13:28:24 -04:00
|
|
|
{
|
2019-08-13 19:41:01 -06:00
|
|
|
if (path[5] >= '0' && path[5] <= '9')
|
2019-06-29 13:28:24 -04:00
|
|
|
{
|
2019-08-13 19:41:01 -06:00
|
|
|
stream->cdrom.drive = path[5];
|
|
|
|
vfs_cdrom_toc.drive = stream->cdrom.drive;
|
|
|
|
|
|
|
|
return retro_vfs_file_open_cdrom_handle(stream, path, stream->cdrom.drive);
|
2019-06-29 13:28:24 -04:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2019-08-13 19:41:01 -06:00
|
|
|
#elif defined(_WIN32) && !defined(_XBOX)
|
|
|
|
if (path_len >= strlen("d:/drive.cue"))
|
2019-06-25 02:51:51 -04:00
|
|
|
{
|
2019-08-13 19:41:01 -06:00
|
|
|
if (!memcmp(path + 1, ":/drive", strlen(":/drive")))
|
2019-06-25 02:51:51 -04:00
|
|
|
{
|
2019-08-13 19:41:01 -06:00
|
|
|
if ((path[0] >= 'A' && path[0] <= 'Z') || (path[0] >= 'a' && path[0] <= 'z'))
|
|
|
|
{
|
|
|
|
stream->cdrom.drive = path[0];
|
|
|
|
vfs_cdrom_toc.drive = stream->cdrom.drive;
|
|
|
|
|
|
|
|
return retro_vfs_file_open_cdrom_handle(stream, path, stream->cdrom.drive);
|
|
|
|
}
|
2019-06-25 02:51:51 -04:00
|
|
|
}
|
|
|
|
}
|
|
|
|
#endif
|
2019-08-13 19:41:01 -06:00
|
|
|
#endif
|
2019-06-25 02:51:51 -04:00
|
|
|
|
2019-08-13 19:41:01 -06:00
|
|
|
stream->fp = (FILE*)fopen_utf8(path, "r+b");
|
|
|
|
if (stream->fp)
|
2019-06-28 18:14:04 -04:00
|
|
|
{
|
2019-08-13 19:41:01 -06:00
|
|
|
stream->scheme = VFS_SCHEME_CUE;
|
|
|
|
return true;
|
2019-06-25 02:51:51 -04:00
|
|
|
}
|
|
|
|
}
|
2019-08-13 19:41:01 -06:00
|
|
|
#ifdef HAVE_CDROM
|
|
|
|
else if (string_is_equal_noncase(ext, "bin"))
|
2019-06-29 13:28:24 -04:00
|
|
|
{
|
2019-08-13 19:41:01 -06:00
|
|
|
unsigned track = 0;
|
|
|
|
|
|
|
|
#if defined(__linux__) && !defined(ANDROID)
|
|
|
|
if (path_len >= strlen("drive1-track01.bin"))
|
2019-06-29 13:28:24 -04:00
|
|
|
{
|
2019-08-13 19:41:01 -06:00
|
|
|
if (!memcmp(path, "drive", strlen("drive")))
|
2019-06-29 13:28:24 -04:00
|
|
|
{
|
2019-08-13 19:41:01 -06:00
|
|
|
if (!memcmp(path + 6, "-track", strlen("-track")))
|
|
|
|
sscanf(path + 12, "%02u", (unsigned*)& track);
|
|
|
|
|
|
|
|
stream->cdrom.drive = path[5];
|
|
|
|
if (!retro_vfs_file_open_cdrom_handle(stream, path, stream->cdrom.drive))
|
|
|
|
return false;
|
2019-06-29 13:28:24 -04:00
|
|
|
}
|
|
|
|
}
|
2019-08-13 19:41:01 -06:00
|
|
|
#elif defined(_WIN32) && !defined(_XBOX)
|
|
|
|
if (path_len >= strlen("d:/drive-track01.bin"))
|
2019-06-26 21:45:00 -04:00
|
|
|
{
|
2019-08-13 19:41:01 -06:00
|
|
|
if (!memcmp(path + 1, ":/drive-track", strlen(":/drive-track")))
|
2019-06-26 21:45:00 -04:00
|
|
|
{
|
2019-08-13 19:41:01 -06:00
|
|
|
sscanf(path + 14, "%02u", (unsigned*)& track);
|
|
|
|
|
2019-06-29 13:28:24 -04:00
|
|
|
stream->cdrom.drive = path[0];
|
|
|
|
vfs_cdrom_toc.drive = stream->cdrom.drive;
|
2019-08-13 19:41:01 -06:00
|
|
|
|
|
|
|
if (!retro_vfs_file_open_cdrom_handle(stream, path, stream->cdrom.drive))
|
|
|
|
return false;
|
2019-06-26 21:45:00 -04:00
|
|
|
}
|
|
|
|
}
|
|
|
|
#endif
|
2019-06-25 02:51:51 -04:00
|
|
|
|
2019-08-13 19:41:01 -06:00
|
|
|
if (track)
|
2019-06-26 21:45:00 -04:00
|
|
|
{
|
|
|
|
#ifdef CDROM_DEBUG
|
2019-08-13 19:41:01 -06:00
|
|
|
printf("[CDROM] Opening track %u\n", track);
|
2019-06-26 21:45:00 -04:00
|
|
|
fflush(stdout);
|
|
|
|
#endif
|
2019-08-13 19:41:01 -06:00
|
|
|
|
|
|
|
if (track > vfs_cdrom_toc.num_tracks)
|
|
|
|
track = 1;
|
|
|
|
|
|
|
|
stream->scheme = VFS_SCHEME_CDROM_TRACK;
|
|
|
|
stream->parent = stream;
|
|
|
|
stream->size = vfs_cdrom_toc.track[track - 1].track_bytes;
|
|
|
|
stream->track = (vfs_cdrom_track_t*)calloc(1, sizeof(*stream->track));
|
|
|
|
stream->track->sector_size = 2352;
|
|
|
|
stream->track->cur_track = track;
|
|
|
|
stream->track->cur_min = vfs_cdrom_toc.track[track - 1].min;
|
|
|
|
stream->track->cur_sec = vfs_cdrom_toc.track[track - 1].sec;
|
|
|
|
stream->track->cur_frame = vfs_cdrom_toc.track[track - 1].frame;
|
|
|
|
stream->track->cur_lba = cdrom_msf_to_lba(stream->track->cur_min, stream->track->cur_sec, stream->track->cur_frame);
|
|
|
|
stream->track->last_frame_lba = (unsigned)-1;
|
|
|
|
return true;
|
|
|
|
}
|
2019-06-26 21:45:00 -04:00
|
|
|
}
|
|
|
|
#endif
|
2019-08-13 19:41:01 -06:00
|
|
|
|
|
|
|
return false;
|
2019-06-25 02:51:51 -04:00
|
|
|
}
|
|
|
|
|
|
|
|
int retro_vfs_file_close_cdrom(libretro_vfs_implementation_file *stream)
|
|
|
|
{
|
2019-08-13 19:41:01 -06:00
|
|
|
#ifdef HAVE_CDROM
|
2019-06-25 02:51:51 -04:00
|
|
|
#ifdef CDROM_DEBUG
|
2019-07-10 20:56:23 -04:00
|
|
|
printf("[CDROM] Close: Path %s\n", stream->orig_path);
|
2019-06-28 18:14:04 -04:00
|
|
|
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-08-13 19:41:01 -06: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-08-13 19:41:01 -06:00
|
|
|
#endif
|
2019-06-26 21:45:00 -04:00
|
|
|
#endif
|
2019-06-25 02:51:51 -04:00
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2019-08-13 19:41:01 -06:00
|
|
|
int64_t retro_vfs_file_seek_cdrom(libretro_vfs_implementation_file *stream, int64_t offset, int whence)
|
|
|
|
{
|
|
|
|
switch (whence)
|
|
|
|
{
|
|
|
|
case SEEK_SET:
|
|
|
|
stream->cdrom.cue_pos = offset;
|
|
|
|
break;
|
|
|
|
|
|
|
|
case SEEK_CUR:
|
|
|
|
stream->cdrom.cue_pos += offset;
|
|
|
|
break;
|
|
|
|
|
|
|
|
case SEEK_END:
|
|
|
|
stream->cdrom.cue_pos = stream->cdrom.cue_len - offset;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (stream->cdrom.cue_pos > stream->cdrom.cue_len)
|
|
|
|
stream->cdrom.cue_pos = stream->cdrom.cue_len;
|
|
|
|
if (stream->cdrom.cue_pos < 0)
|
|
|
|
stream->cdrom.cue_pos = 0;
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2019-06-25 02:51:51 -04:00
|
|
|
int64_t retro_vfs_file_tell_cdrom(libretro_vfs_implementation_file *stream)
|
|
|
|
{
|
2019-08-13 19:41:01 -06:00
|
|
|
return stream->cdrom.cue_pos;
|
|
|
|
}
|
|
|
|
|
|
|
|
int64_t retro_vfs_file_read_cdrom(libretro_vfs_implementation_file* stream,
|
|
|
|
void* s, uint64_t len)
|
|
|
|
{
|
|
|
|
size_t bytes_to_copy;
|
2019-06-25 02:51:51 -04:00
|
|
|
|
2019-08-13 19:41:01 -06:00
|
|
|
if (!stream->cdrom.cue_buf)
|
|
|
|
return 0;
|
2019-06-25 02:51:51 -04:00
|
|
|
|
2019-08-13 19:41:01 -06:00
|
|
|
bytes_to_copy = stream->cdrom.cue_len - stream->cdrom.cue_pos;
|
|
|
|
if (bytes_to_copy > len)
|
|
|
|
bytes_to_copy = len;
|
|
|
|
if (bytes_to_copy > 0)
|
2019-06-25 02:51:51 -04:00
|
|
|
{
|
2019-08-13 19:41:01 -06:00
|
|
|
memcpy(s, &stream->cdrom.cue_buf[stream->cdrom.cue_pos], bytes_to_copy);
|
|
|
|
stream->cdrom.cue_pos += bytes_to_copy;
|
2019-06-25 02:51:51 -04:00
|
|
|
}
|
2019-08-13 19:41:01 -06:00
|
|
|
|
|
|
|
return bytes_to_copy;
|
|
|
|
}
|
|
|
|
|
|
|
|
int retro_vfs_file_error_cdrom(libretro_vfs_implementation_file *stream)
|
|
|
|
{
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
static void retro_vfs_skip_spaces(const char **buf, size_t len)
|
|
|
|
{
|
|
|
|
if (!buf || !*buf)
|
|
|
|
return;
|
|
|
|
|
|
|
|
while (len-- && (**buf == ' ' || **buf == '\t'))
|
|
|
|
++(*buf);
|
|
|
|
}
|
|
|
|
|
|
|
|
static bool retro_vfs_file_get_cue_track_path(const char* cue_contents, const char* cue_path, unsigned track, char* track_path, size_t max_track_path, int* track_pregap_bytes, int* sector_size)
|
|
|
|
{
|
|
|
|
const char *line = NULL;
|
|
|
|
const char* cue = cue_contents;
|
|
|
|
char current_track_path[PATH_MAX_LENGTH] = {0};
|
|
|
|
char track_mode[11] = {0};
|
|
|
|
bool found_file = false;
|
|
|
|
unsigned found_track = 0;
|
|
|
|
|
|
|
|
if (!cue_contents)
|
|
|
|
return false;
|
|
|
|
|
|
|
|
track_path[0] = '\0';
|
|
|
|
|
|
|
|
while (*cue)
|
2019-06-25 02:51:51 -04:00
|
|
|
{
|
2019-08-13 19:41:01 -06:00
|
|
|
size_t len = 0;
|
|
|
|
|
|
|
|
while (*cue && (*cue == ' ' || *cue == '\t'))
|
|
|
|
++cue;
|
|
|
|
line = cue;
|
|
|
|
while (*cue && *cue != '\n')
|
|
|
|
++cue;
|
|
|
|
len = cue - line;
|
|
|
|
if (*cue)
|
|
|
|
++cue;
|
|
|
|
if (len == 0)
|
|
|
|
continue;
|
|
|
|
|
|
|
|
if (!found_file && !strncasecmp(line, "FILE", 4))
|
|
|
|
{
|
|
|
|
const char *file = line + 4;
|
|
|
|
retro_vfs_skip_spaces(&file, len - 4);
|
|
|
|
|
|
|
|
if (!string_is_empty(file))
|
|
|
|
{
|
|
|
|
const char *file_end = NULL;
|
|
|
|
size_t file_len = 0;
|
|
|
|
bool quoted = false;
|
|
|
|
|
|
|
|
if (file[0] == '"')
|
|
|
|
{
|
|
|
|
quoted = true;
|
|
|
|
file++;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (quoted)
|
|
|
|
file_end = strchr(file, '\"');
|
|
|
|
else
|
|
|
|
file_end = strchr(file, ' ');
|
|
|
|
|
|
|
|
if (file_end)
|
|
|
|
{
|
|
|
|
file_len = file_end - file;
|
|
|
|
memcpy(current_track_path, file, file_len);
|
|
|
|
found_file = true;
|
|
|
|
#ifdef CDROM_CUE_PARSE_DEBUG
|
|
|
|
printf("Found file: %s\n", current_track_path);
|
|
|
|
fflush(stdout);
|
2019-06-25 02:51:51 -04:00
|
|
|
#endif
|
2019-08-13 19:41:01 -06:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else if (found_file && !found_track && !strncasecmp(line, "TRACK", 5))
|
|
|
|
{
|
|
|
|
const char *track = line + 5;
|
|
|
|
retro_vfs_skip_spaces(&track, len - 5);
|
|
|
|
|
|
|
|
if (!string_is_empty(track))
|
|
|
|
{
|
|
|
|
unsigned track_number = 0;
|
|
|
|
sscanf(track, "%u", &track_number);
|
|
|
|
#ifdef CDROM_CUE_PARSE_DEBUG
|
|
|
|
printf("Found track: %d\n", track_number);
|
|
|
|
fflush(stdout);
|
|
|
|
#endif
|
|
|
|
track++;
|
|
|
|
|
|
|
|
if (track[0] && track[0] != ' ' && track[0] != '\t')
|
|
|
|
track++;
|
|
|
|
|
|
|
|
if (!string_is_empty(track))
|
|
|
|
{
|
|
|
|
retro_vfs_skip_spaces(&track, strlen(track));
|
|
|
|
#ifdef CDROM_CUE_PARSE_DEBUG
|
|
|
|
printf("Found track type: %s\n", track);
|
|
|
|
fflush(stdout);
|
|
|
|
#endif
|
|
|
|
if (!strncasecmp(track, "MODE", 4))
|
|
|
|
{
|
|
|
|
found_track = track_number;
|
|
|
|
strlcpy(track_mode, track, sizeof(track_mode));
|
|
|
|
}
|
|
|
|
else
|
|
|
|
found_track = 0;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else if (found_file && found_track == track && !strncasecmp(line, "INDEX", 5))
|
|
|
|
{
|
|
|
|
const char *index = line + 5;
|
|
|
|
retro_vfs_skip_spaces(&index, len - 5);
|
|
|
|
|
|
|
|
if (!string_is_empty(index))
|
|
|
|
{
|
|
|
|
unsigned index_number = 0;
|
|
|
|
sscanf(index, "%u", &index_number);
|
|
|
|
|
|
|
|
if (index_number == 1)
|
|
|
|
{
|
|
|
|
const char *pregap = index + 1;
|
|
|
|
if (pregap[0] && pregap[0] != ' ' && pregap[0] != '\t')
|
|
|
|
pregap++;
|
|
|
|
|
|
|
|
if (strstr(current_track_path, "/") || strstr(current_track_path, "\\"))
|
|
|
|
{
|
|
|
|
strncpy(track_path, current_track_path, max_track_path);
|
|
|
|
#ifdef CDROM_CUE_PARSE_DEBUG
|
|
|
|
printf("using path %s\n", track_path);
|
|
|
|
fflush(stdout);
|
|
|
|
#endif
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
fill_pathname_basedir(track_path, cue_path, max_track_path);
|
|
|
|
strlcat(track_path, current_track_path, max_track_path);
|
|
|
|
#ifdef CDROM_CUE_PARSE_DEBUG
|
|
|
|
printf("using absolute path %s\n", track_path);
|
|
|
|
fflush(stdout);
|
|
|
|
#endif
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!string_is_empty(pregap))
|
|
|
|
{
|
|
|
|
retro_vfs_skip_spaces(&pregap, strlen(pregap));
|
|
|
|
found_file = false;
|
|
|
|
found_track = false;
|
|
|
|
|
|
|
|
if (!string_is_empty(track_mode))
|
|
|
|
{
|
|
|
|
unsigned track_sector_size = 0;
|
|
|
|
unsigned track_mode_number = 0;
|
|
|
|
|
|
|
|
if (strlen(track_mode) == 10)
|
|
|
|
{
|
|
|
|
sscanf(track_mode, "MODE%u/%u", &track_mode_number, &track_sector_size);
|
|
|
|
#ifdef CDROM_CUE_PARSE_DEBUG
|
|
|
|
printf("Found track mode %d with sector size %d\n", track_mode_number, track_sector_size);
|
|
|
|
fflush(stdout);
|
|
|
|
#endif
|
|
|
|
if ((track_mode_number == 1 || track_mode_number == 2) && track_sector_size)
|
|
|
|
{
|
|
|
|
unsigned min = 0;
|
|
|
|
unsigned sec = 0;
|
|
|
|
unsigned frame = 0;
|
|
|
|
sscanf(pregap, "%02u:%02u:%02u", &min, &sec, &frame);
|
|
|
|
|
|
|
|
if (min || sec || frame || strstr(pregap, "00:00:00"))
|
|
|
|
{
|
|
|
|
if (sector_size)
|
|
|
|
*sector_size = track_sector_size;
|
|
|
|
if (track_pregap_bytes)
|
|
|
|
*track_pregap_bytes = ((min * 60 + sec) * 75 + frame) * track_sector_size;
|
|
|
|
#ifdef CDROM_CUE_PARSE_DEBUG
|
|
|
|
printf("Found pregap of %02u:%02u:%02u (bytes: %" PRIu64 ")\n", min, sec, frame, data_track_pregap_bytes);
|
|
|
|
fflush(stdout);
|
|
|
|
#endif
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2019-06-25 02:51:51 -04:00
|
|
|
}
|
|
|
|
|
2019-08-13 19:41:01 -06:00
|
|
|
return !string_is_empty(track_path);
|
2019-06-25 02:51:51 -04:00
|
|
|
}
|
|
|
|
|
2019-08-13 19:41:01 -06:00
|
|
|
libretro_vfs_implementation_file* retro_vfs_file_open_cdrom_track(libretro_vfs_implementation_file* stream, const char* track)
|
2019-06-25 02:51:51 -04:00
|
|
|
{
|
2019-08-13 19:41:01 -06:00
|
|
|
char track_path[PATH_MAX_LENGTH];
|
|
|
|
unsigned track_index = 0;
|
2019-06-25 02:51:51 -04:00
|
|
|
|
2019-08-13 19:41:01 -06:00
|
|
|
if (!stream->cdrom.cue_buf)
|
2019-06-25 02:51:51 -04:00
|
|
|
{
|
2019-08-13 19:41:01 -06:00
|
|
|
switch (stream->scheme)
|
2019-06-25 02:51:51 -04:00
|
|
|
{
|
2019-08-13 19:41:01 -06:00
|
|
|
case VFS_SCHEME_CUE:
|
|
|
|
stream->cdrom.cue_len = stream->size;
|
|
|
|
stream->cdrom.cue_buf = (char*)malloc(stream->size + 1);
|
|
|
|
if (stream->cdrom.cue_buf)
|
|
|
|
{
|
|
|
|
retro_vfs_file_seek_impl(stream, 0, RETRO_VFS_SEEK_POSITION_START);
|
|
|
|
retro_vfs_file_read_impl(stream, stream->cdrom.cue_buf, stream->cdrom.cue_len);
|
|
|
|
stream->cdrom.cue_buf[stream->cdrom.cue_len] = '\0';
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
|
|
|
|
#ifdef HAVE_CDROM
|
|
|
|
case VFS_SCHEME_CDROM:
|
|
|
|
cdrom_write_cue(stream, &stream->cdrom.cue_buf, &stream->cdrom.cue_len, stream->cdrom.drive, &vfs_cdrom_toc.num_tracks, &vfs_cdrom_toc);
|
|
|
|
cdrom_get_timeouts(stream, &vfs_cdrom_toc.timeouts);
|
|
|
|
|
2019-06-25 02:51:51 -04:00
|
|
|
#ifdef CDROM_DEBUG
|
2019-08-13 19:41:01 -06:00
|
|
|
if (string_is_empty(stream->cdrom.cue_buf))
|
|
|
|
{
|
|
|
|
printf("[CDROM] Error writing cue sheet.\n");
|
|
|
|
fflush(stdout);
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
printf("[CDROM] CUE Sheet:\n%s\n", stream->cdrom.cue_buf);
|
|
|
|
fflush(stdout);
|
|
|
|
}
|
|
|
|
#endif
|
|
|
|
break;
|
2019-06-25 02:51:51 -04:00
|
|
|
#endif
|
|
|
|
|
2019-08-13 19:41:01 -06:00
|
|
|
default:
|
|
|
|
return NULL;
|
2019-06-25 02:51:51 -04:00
|
|
|
}
|
2019-08-13 19:41:01 -06:00
|
|
|
|
|
|
|
if (!stream->cdrom.cue_buf)
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
while (*track && (*track < '0' || *track > '9'))
|
|
|
|
++track;
|
|
|
|
|
|
|
|
sscanf(track, "%u", &track_index);
|
|
|
|
|
|
|
|
if (track_index > 0)
|
|
|
|
{
|
|
|
|
int pregap_bytes = 0;
|
|
|
|
int sector_size = 2352;
|
|
|
|
if (retro_vfs_file_get_cue_track_path(stream->cdrom.cue_buf, stream->orig_path, track_index, track_path, PATH_MAX_LENGTH, &pregap_bytes, §or_size))
|
2019-06-25 02:51:51 -04:00
|
|
|
{
|
2019-08-13 19:41:01 -06:00
|
|
|
libretro_vfs_implementation_file* track_stream;
|
|
|
|
if (stream->scheme == VFS_SCHEME_CDROM)
|
|
|
|
{
|
|
|
|
#ifdef HAVE_CDROM
|
|
|
|
track_stream = (libretro_vfs_implementation_file*)calloc(1, sizeof(*stream));
|
|
|
|
track_stream->size = vfs_cdrom_toc.track[track_index - 1].track_bytes;
|
2019-06-25 02:51:51 -04:00
|
|
|
#endif
|
2019-08-13 19:41:01 -06:00
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
track_stream = retro_vfs_file_open_impl(track_path, RETRO_VFS_FILE_ACCESS_READ, stream->hints);
|
|
|
|
}
|
|
|
|
|
|
|
|
if (track_stream)
|
|
|
|
{
|
|
|
|
track_stream->scheme = VFS_SCHEME_CDROM_TRACK;
|
|
|
|
track_stream->cdrom.drive = stream->cdrom.drive;
|
|
|
|
track_stream->parent = stream;
|
|
|
|
track_stream->parent_offset = pregap_bytes;
|
|
|
|
|
|
|
|
track_stream->track = (vfs_cdrom_track_t*)calloc(1, sizeof(*track_stream->track));
|
|
|
|
track_stream->track->cur_track = track_index;
|
|
|
|
track_stream->track->last_frame_lba = (unsigned)-1;
|
|
|
|
track_stream->track->sector_size = sector_size;
|
|
|
|
track_stream->track->sector_header_size = retro_vs_file_get_sector_header_size(track_stream);
|
|
|
|
|
|
|
|
return track_stream;
|
|
|
|
}
|
2019-06-25 02:51:51 -04:00
|
|
|
}
|
|
|
|
}
|
2019-08-13 19:41:01 -06:00
|
|
|
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
int retro_vfs_file_close_cdrom_track(libretro_vfs_implementation_file* stream)
|
|
|
|
{
|
|
|
|
if (stream->track)
|
|
|
|
free(stream->track);
|
|
|
|
|
|
|
|
if (stream->parent == stream)
|
|
|
|
retro_vfs_file_close_cdrom(stream);
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
int64_t retro_vfs_file_seek_cdrom_track(libretro_vfs_implementation_file* stream, int64_t offset, int whence)
|
|
|
|
{
|
|
|
|
if (!stream->parent)
|
|
|
|
return -1;
|
|
|
|
|
|
|
|
switch (whence)
|
2019-06-25 02:51:51 -04:00
|
|
|
{
|
2019-08-13 19:41:01 -06:00
|
|
|
case SEEK_SET:
|
|
|
|
stream->track->byte_pos = offset;
|
|
|
|
break;
|
|
|
|
|
|
|
|
case SEEK_CUR:
|
|
|
|
stream->track->byte_pos += offset;
|
|
|
|
break;
|
|
|
|
|
|
|
|
case SEEK_END:
|
|
|
|
stream->track->byte_pos = stream->size - offset;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (stream->track->byte_pos >= stream->size)
|
|
|
|
stream->track->byte_pos = stream->size - 1;
|
|
|
|
if (stream->track->byte_pos < 0)
|
|
|
|
stream->track->byte_pos = 0;
|
|
|
|
|
|
|
|
if (stream->parent->scheme == VFS_SCHEME_CUE)
|
|
|
|
{
|
|
|
|
int64_t rv;
|
|
|
|
|
|
|
|
/* temporarily change scheme to prevent infinite recusion */
|
|
|
|
stream->scheme = VFS_SCHEME_NONE;
|
|
|
|
rv = retro_vfs_file_seek_impl(stream, stream->track->byte_pos + stream->parent_offset, SEEK_SET);
|
|
|
|
stream->scheme = VFS_SCHEME_CUE_BIN;
|
|
|
|
|
|
|
|
if (rv >= 0)
|
|
|
|
stream->track->cur_lba = stream->track->byte_pos / stream->track->sector_size;
|
|
|
|
|
|
|
|
return rv;
|
|
|
|
}
|
|
|
|
|
|
|
|
#ifdef HAVE_CDROM
|
|
|
|
stream->track->cur_lba = vfs_cdrom_toc.track[stream->track->cur_track - 1].lba + (stream->track->byte_pos / stream->track->sector_size);
|
|
|
|
cdrom_lba_to_msf(stream->track->cur_lba, &stream->track->cur_min, &stream->track->cur_sec, &stream->track->cur_frame);
|
|
|
|
|
|
|
|
#ifdef CDROM_DEBUG
|
|
|
|
printf("[CDROM] Seek: Path %s Offset %" PRIu64 " is now at %" PRIu64 " (MSF %02u:%02u:%02u) (LBA %u)...\n",
|
|
|
|
stream->orig_path, offset, stream->track->byte_pos, (unsigned)stream->track->cur_min, (unsigned)stream->track->cur_sec, (unsigned)stream->track->cur_frame, stream->track->cur_lba);
|
|
|
|
fflush(stdout);
|
|
|
|
#endif
|
|
|
|
#endif
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
static void retro_vfs_file_read_cdrom_track_sector(libretro_vfs_implementation_file* stream, void* s, uint64_t len)
|
|
|
|
{
|
|
|
|
if (stream->parent->scheme == VFS_SCHEME_CUE)
|
|
|
|
{
|
|
|
|
/* temporarily change the scheme to prevent recursion */
|
|
|
|
stream->scheme = VFS_SCHEME_NONE;
|
|
|
|
retro_vfs_file_read_impl(stream, s, len);
|
|
|
|
stream->scheme = VFS_SCHEME_CUE_BIN;
|
|
|
|
}
|
|
|
|
#ifdef HAVE_CDROM
|
|
|
|
else
|
|
|
|
{
|
|
|
|
int rv;
|
2019-06-25 02:51:51 -04:00
|
|
|
unsigned char min = 0;
|
|
|
|
unsigned char sec = 0;
|
|
|
|
unsigned char frame = 0;
|
2019-07-07 02:40:38 -04:00
|
|
|
unsigned char rmin = 0;
|
|
|
|
unsigned char rsec = 0;
|
|
|
|
unsigned char rframe = 0;
|
2019-08-13 19:41:01 -06:00
|
|
|
uint64_t byte_pos = stream->track->cur_lba * stream->track->sector_size;
|
2019-06-25 02:51:51 -04:00
|
|
|
|
2019-08-13 19:41:01 -06:00
|
|
|
if (byte_pos >= vfs_cdrom_toc.track[stream->track->cur_track - 1].track_bytes)
|
|
|
|
return;
|
2019-07-08 15:32:12 -04:00
|
|
|
|
2019-08-13 19:41:01 -06:00
|
|
|
if (byte_pos + len > vfs_cdrom_toc.track[stream->track->cur_track - 1].track_bytes)
|
|
|
|
len -= (byte_pos + len) - vfs_cdrom_toc.track[stream->track->cur_track - 1].track_bytes;
|
2019-07-08 15:32:12 -04:00
|
|
|
|
2019-08-13 19:41:01 -06:00
|
|
|
cdrom_lba_to_msf(stream->track->cur_lba, &min, &sec, &frame);
|
|
|
|
cdrom_lba_to_msf(stream->track->cur_lba - vfs_cdrom_toc.track[stream->track->cur_track - 1].lba, &rmin, &rsec, &rframe);
|
2019-06-25 02:51:51 -04:00
|
|
|
|
|
|
|
#ifdef CDROM_DEBUG
|
2019-08-13 19:41:01 -06:00
|
|
|
printf("[CDROM] Read: Reading %" PRIu64 " bytes from %s starting at byte offset %" PRIu64 " (rMSF %02u:%02u:%02u aMSF %02u:%02u:%02u) (LBA %u)...\n", len, stream->orig_path, byte_pos, (unsigned)rmin, (unsigned)rsec, (unsigned)rframe, (unsigned)min, (unsigned)sec, (unsigned)frame, stream->track->cur_lba);
|
2019-06-28 18:14:04 -04:00
|
|
|
fflush(stdout);
|
2019-06-25 02:51:51 -04:00
|
|
|
#endif
|
|
|
|
|
2019-08-13 19:41:01 -06:00
|
|
|
rv = cdrom_read(stream, &vfs_cdrom_toc.timeouts, min, sec, frame, s, (size_t)len, 0);
|
2019-07-05 11:08:52 -04:00
|
|
|
/*rv = cdrom_read_lba(stream, stream->cdrom.cur_lba, s, (size_t)len, skip);*/
|
2019-06-25 02:51:51 -04:00
|
|
|
|
|
|
|
if (rv)
|
|
|
|
{
|
|
|
|
#ifdef CDROM_DEBUG
|
2019-07-10 20:56:23 -04:00
|
|
|
printf("[CDROM] 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
|
|
|
|
}
|
2019-08-13 19:41:01 -06:00
|
|
|
}
|
|
|
|
#endif
|
|
|
|
}
|
2019-06-25 02:51:51 -04:00
|
|
|
|
2019-08-13 19:41:01 -06:00
|
|
|
int64_t retro_vfs_file_read_cdrom_track(libretro_vfs_implementation_file *stream, void *s, uint64_t len)
|
|
|
|
{
|
|
|
|
uint64_t bytes_read = 0;
|
2019-07-07 02:40:38 -04:00
|
|
|
|
2019-08-13 19:41:01 -06:00
|
|
|
if (!stream->parent)
|
|
|
|
return -1;
|
|
|
|
|
|
|
|
if (stream->track->last_frame_lba == stream->track->cur_lba)
|
|
|
|
{
|
|
|
|
const int used = stream->track->byte_pos % stream->track->sector_size;
|
|
|
|
int remaining = stream->track->sector_size - used;
|
|
|
|
if (remaining > len)
|
|
|
|
{
|
|
|
|
memcpy(s, stream->track->last_frame + used, len);
|
|
|
|
stream->track->byte_pos += len;
|
|
|
|
return len;
|
|
|
|
}
|
|
|
|
|
|
|
|
memcpy(s, stream->track->last_frame + used, remaining);
|
|
|
|
s = (char*)s + remaining;
|
|
|
|
len -= remaining;
|
|
|
|
bytes_read += remaining;
|
|
|
|
|
|
|
|
stream->track->cur_lba++;
|
|
|
|
retro_vfs_file_seek_cdrom_track_sector(stream, stream->track->cur_lba);
|
|
|
|
}
|
|
|
|
|
|
|
|
while (len >= stream->track->sector_size)
|
|
|
|
{
|
|
|
|
retro_vfs_file_read_cdrom_track_sector(stream, s, stream->track->sector_size);
|
|
|
|
s = (char*)s + 2352;
|
|
|
|
|
|
|
|
stream->track->cur_lba++;
|
|
|
|
|
|
|
|
bytes_read += 2352;
|
|
|
|
len -= 2352;
|
|
|
|
}
|
|
|
|
|
|
|
|
stream->track->byte_pos = stream->track->cur_lba * stream->track->sector_size;
|
|
|
|
|
|
|
|
if (len > 0)
|
|
|
|
{
|
|
|
|
retro_vfs_file_read_cdrom_track_sector(stream, stream->track->last_frame, stream->track->sector_size);
|
|
|
|
memcpy(s, stream->track->last_frame, len);
|
|
|
|
bytes_read += len;
|
|
|
|
|
|
|
|
stream->track->byte_pos += len;
|
|
|
|
stream->track->last_frame_lba = stream->track->cur_lba;
|
|
|
|
|
|
|
|
#ifdef HAVE_CDROM
|
|
|
|
cdrom_lba_to_msf(stream->track->cur_lba, &stream->track->cur_min, &stream->track->cur_sec, &stream->track->cur_frame);
|
|
|
|
#endif
|
|
|
|
}
|
|
|
|
|
|
|
|
return bytes_read;
|
|
|
|
}
|
|
|
|
|
|
|
|
int64_t retro_vfs_file_tell_cdrom_track(libretro_vfs_implementation_file* stream)
|
|
|
|
{
|
|
|
|
return stream->track->byte_pos;
|
|
|
|
}
|
|
|
|
|
|
|
|
static int retro_vfs_file_find_cdrom_file_sector(libretro_vfs_implementation_file* track_stream, const char* path, unsigned* file_size)
|
|
|
|
{
|
|
|
|
uint8_t buffer[2352], *tmp;
|
|
|
|
int sector, path_length;
|
|
|
|
|
|
|
|
const char* slash = strrchr(path, '\\');
|
|
|
|
if (slash)
|
|
|
|
{
|
|
|
|
/* navigate the path to the directory record for the file */
|
|
|
|
const int dir_length = (int)(slash - path);
|
|
|
|
memcpy(buffer, path, dir_length);
|
|
|
|
buffer[dir_length] = '\0';
|
|
|
|
|
|
|
|
sector = retro_vfs_file_find_cdrom_file_sector(track_stream, (const char*)buffer, NULL);
|
|
|
|
if (sector < 0)
|
|
|
|
return sector;
|
|
|
|
|
|
|
|
path += dir_length + 1;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
int offset;
|
|
|
|
|
|
|
|
/* find the cd information (always 16 frames in) */
|
|
|
|
retro_vfs_file_seek_cdrom_track_sector(track_stream, 16);
|
|
|
|
retro_vfs_file_read_cdrom_track(track_stream, buffer, sizeof(buffer));
|
|
|
|
|
|
|
|
/* the directory_record starts at 156 bytes into the sector.
|
|
|
|
* the sector containing the table of contents is a 3 byte value that is 2 bytes into the directory_record. */
|
|
|
|
offset = track_stream->track->sector_header_size + 156 + 2;
|
|
|
|
sector = buffer[offset] | (buffer[offset + 1] << 8) | (buffer[offset + 2] << 16);
|
|
|
|
}
|
|
|
|
|
|
|
|
/* process the table of contents */
|
|
|
|
retro_vfs_file_seek_cdrom_track_sector(track_stream, sector);
|
|
|
|
retro_vfs_file_read_cdrom_track(track_stream, buffer, sizeof(buffer));
|
|
|
|
|
|
|
|
path_length = strlen(path);
|
|
|
|
tmp = buffer + track_stream->track->sector_header_size;
|
|
|
|
while (tmp < buffer + sizeof(buffer))
|
|
|
|
{
|
|
|
|
/* the first byte of the record is the length of the record - if 0, we reached the end of the data */
|
|
|
|
if (!*tmp)
|
|
|
|
break;
|
|
|
|
|
|
|
|
/* filename is 33 bytes into the record and the format is "FILENAME;version" or "DIRECTORY" */
|
|
|
|
if ((tmp[33 + path_length] == ';' || tmp[33 + path_length] == '\0') &&
|
|
|
|
strncasecmp((const char*)(tmp + 33), path, path_length) == 0)
|
|
|
|
{
|
|
|
|
/* the file contents are in the sector identified in bytes 2-4 of the record */
|
|
|
|
sector = tmp[2] | (tmp[3] << 8) | (tmp[4] << 16);
|
|
|
|
retro_vfs_file_seek_cdrom_track_sector(track_stream, sector);
|
|
|
|
|
|
|
|
/* the file size is in bytes 10-13 of the record */
|
|
|
|
if (file_size)
|
|
|
|
*file_size = tmp[10] | (tmp[11] << 8) | (tmp[12] << 16) | (tmp[13] << 24);
|
2019-06-25 02:51:51 -04:00
|
|
|
|
|
|
|
#ifdef CDROM_DEBUG
|
2019-08-13 19:41:01 -06:00
|
|
|
{
|
|
|
|
unsigned char min, sec, frame;
|
|
|
|
cdrom_lba_to_msf(sector, &min, &sec, &frame);
|
|
|
|
printf("[CDROM] found %s (MSF %02u:%02u:%02u) (LBA %u)\n", path, (unsigned)min, (unsigned)sec, (unsigned)frame, sector);
|
|
|
|
fflush(stdout);
|
|
|
|
}
|
|
|
|
#endif
|
|
|
|
|
|
|
|
return sector;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* the first byte of the record is the length of the record */
|
|
|
|
tmp += tmp[0];
|
|
|
|
}
|
|
|
|
|
|
|
|
#ifdef CDROM_DEBUG
|
|
|
|
printf("[CDROM] did not find %s\n", path);
|
|
|
|
fflush(stdout);
|
2019-06-25 02:51:51 -04:00
|
|
|
#endif
|
|
|
|
|
2019-08-13 19:41:01 -06:00
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
|
|
|
libretro_vfs_implementation_file* retro_vfs_file_open_cdrom_file(libretro_vfs_implementation_file* track_stream, const char* path)
|
|
|
|
{
|
|
|
|
libretro_vfs_implementation_file* file_stream;
|
|
|
|
unsigned file_size = 0;
|
|
|
|
|
|
|
|
int sector = retro_vfs_file_find_cdrom_file_sector(track_stream, path, &file_size);
|
|
|
|
if (sector < 0)
|
|
|
|
return NULL;
|
|
|
|
|
|
|
|
file_stream = (libretro_vfs_implementation_file*)calloc(1, sizeof(*file_stream));
|
|
|
|
file_stream->scheme = (track_stream->scheme == VFS_SCHEME_CDROM_TRACK) ? VFS_SCHEME_CDROM_FILE : VFS_SCHEME_CUE_BIN_FILE;
|
|
|
|
file_stream->parent = track_stream;
|
|
|
|
file_stream->parent_offset = sector * 2352 + track_stream->track->sector_header_size;
|
|
|
|
file_stream->orig_path = strdup(path);
|
|
|
|
file_stream->size = file_size;
|
|
|
|
|
|
|
|
return file_stream;
|
|
|
|
}
|
|
|
|
|
|
|
|
int64_t retro_vfs_file_tell_cdrom_file(libretro_vfs_implementation_file* stream)
|
|
|
|
{
|
|
|
|
if (stream->parent != NULL && stream->parent->track)
|
|
|
|
{
|
|
|
|
const int64_t current_offset_raw = stream->parent->track->byte_pos - stream->parent_offset;
|
|
|
|
return (current_offset_raw / stream->parent->track->sector_size) * 2048 + (current_offset_raw % stream->parent->track->sector_size);
|
2019-06-25 02:51:51 -04:00
|
|
|
}
|
|
|
|
|
2019-08-13 19:41:01 -06:00
|
|
|
return -1;
|
2019-06-25 02:51:51 -04:00
|
|
|
}
|
2019-06-26 21:45:00 -04:00
|
|
|
|
2019-08-13 19:41:01 -06:00
|
|
|
int64_t retro_vfs_file_seek_cdrom_file(libretro_vfs_implementation_file* stream, int64_t offset, int whence)
|
2019-06-26 21:45:00 -04:00
|
|
|
{
|
2019-08-13 19:41:01 -06:00
|
|
|
int64_t offset_raw;
|
|
|
|
switch (whence)
|
|
|
|
{
|
|
|
|
case SEEK_CUR:
|
|
|
|
{
|
|
|
|
const int64_t current_offset_raw = stream->parent->track->byte_pos - stream->parent_offset;
|
|
|
|
const int64_t current_offset = (current_offset_raw / stream->parent->track->sector_size) * 2048 + (current_offset_raw % stream->parent->track->sector_size);
|
|
|
|
offset = current_offset + offset;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
case SEEK_END:
|
|
|
|
offset = stream->size - offset;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
offset_raw = (offset / 2048) * stream->parent->track->sector_size + (offset % 2048);
|
|
|
|
|
|
|
|
return retro_vfs_file_seek_cdrom_track(stream->parent, offset_raw, SEEK_SET);
|
2019-06-26 21:45:00 -04:00
|
|
|
}
|
2019-06-29 20:03:59 -04:00
|
|
|
|
2019-08-13 19:41:01 -06:00
|
|
|
int64_t retro_vfs_file_read_cdrom_file(libretro_vfs_implementation_file* stream, void* s, uint64_t len)
|
2019-06-29 20:03:59 -04:00
|
|
|
{
|
2019-08-13 19:41:01 -06:00
|
|
|
uint8_t buffer[2352];
|
|
|
|
int64_t bytes_read = 0;
|
|
|
|
|
|
|
|
if (!stream || !stream->parent || !stream->parent->track)
|
|
|
|
return 0;
|
|
|
|
|
|
|
|
if (stream->parent->track->last_frame_lba == stream->parent->track->cur_lba)
|
|
|
|
{
|
|
|
|
const int used = stream->parent->track->byte_pos % stream->parent->track->sector_size - stream->parent->track->sector_header_size;
|
|
|
|
int remaining = 2048 - used;
|
|
|
|
if (remaining > 0)
|
|
|
|
{
|
|
|
|
if (remaining > len)
|
|
|
|
{
|
|
|
|
retro_vfs_file_read_cdrom_track(stream->parent, s, len);
|
|
|
|
return len;
|
|
|
|
}
|
|
|
|
|
|
|
|
retro_vfs_file_read_cdrom_track(stream->parent, s, remaining);
|
|
|
|
s = (char*)s + remaining;
|
|
|
|
bytes_read += remaining;
|
|
|
|
}
|
|
|
|
|
|
|
|
stream->parent->track->cur_lba = stream->parent->track->last_frame_lba + 1;
|
|
|
|
}
|
|
|
|
|
|
|
|
while (len >= 2048)
|
|
|
|
{
|
|
|
|
retro_vfs_file_read_cdrom_track_sector(stream->parent, buffer, stream->parent->track->sector_size);
|
|
|
|
stream->parent->track->cur_lba++;
|
|
|
|
|
|
|
|
memcpy(s, buffer + stream->parent->track->sector_header_size, 2048);
|
|
|
|
s = (char*)s + 2048;
|
|
|
|
bytes_read += 2048;
|
|
|
|
len -= 2048;
|
|
|
|
}
|
|
|
|
|
|
|
|
stream->parent->track->byte_pos = stream->parent->track->cur_lba * stream->parent->track->sector_size;
|
|
|
|
|
|
|
|
if (len > 0)
|
|
|
|
{
|
|
|
|
retro_vfs_file_read_cdrom_track(stream->parent, buffer, len + stream->parent->track->sector_header_size);
|
|
|
|
memcpy(s, buffer + stream->parent->track->sector_header_size, len);
|
|
|
|
|
|
|
|
stream->parent->track->byte_pos += len;
|
|
|
|
bytes_read += len;
|
|
|
|
}
|
|
|
|
|
|
|
|
return bytes_read;
|
2019-06-29 20:03:59 -04:00
|
|
|
}
|