mirror of
https://github.com/libretro/RetroArch
synced 2025-03-29 22:20:21 +00:00
Merge pull request #9038 from bparker06/cdrom
initial CD reading support
This commit is contained in:
commit
e930221169
@ -1617,6 +1617,16 @@ ifeq ($(HAVE_ZLIB_COMMON), 1)
|
||||
endif
|
||||
endif
|
||||
|
||||
ifeq ($(HAVE_CDROM), 1)
|
||||
ifeq ($(CDROM_DEBUG), 1)
|
||||
DEFINES += -DCDROM_DEBUG
|
||||
endif
|
||||
|
||||
DEFINES += -DHAVE_CDROM
|
||||
OBJ += $(LIBRETRO_COMM_DIR)/cdrom/cdrom.o \
|
||||
$(LIBRETRO_COMM_DIR)/vfs/vfs_implementation_cdrom.o
|
||||
endif
|
||||
|
||||
ifeq ($(HAVE_RTGA), 1)
|
||||
DEFINES += -DHAVE_RTGA
|
||||
OBJ += $(LIBRETRO_COMM_DIR)/formats/tga/rtga.o
|
||||
|
@ -1,5 +1,6 @@
|
||||
/* RetroArch - A frontend for libretro.
|
||||
* Copyright (C) 2011-2017 - Daniel De Matteis
|
||||
* Copyright (C) 2016-2019 - Brad Parker
|
||||
*
|
||||
* RetroArch is free software: you can redistribute it and/or modify it under the terms
|
||||
* of the GNU General Public License as published by the Free Software Found-
|
||||
|
@ -1,6 +1,7 @@
|
||||
/* RetroArch - A frontend for libretro.
|
||||
* Copyright (C) 2010-2014 - Hans-Kristian Arntzen
|
||||
* Copyright (C) 2011-2017 - Daniel De Matteis
|
||||
* Copyright (C) 2016-2019 - Brad Parker
|
||||
*
|
||||
* RetroArch is free software: you can redistribute it and/or modify it under the terms
|
||||
* of the GNU General Public License as published by the Free Software Found-
|
||||
|
@ -1,6 +1,7 @@
|
||||
/* RetroArch - A frontend for libretro.
|
||||
* Copyright (C) 2010-2014 - Hans-Kristian Arntzen
|
||||
* Copyright (C) 2011-2017 - Daniel De Matteis
|
||||
* Copyright (C) 2016-2019 - Brad Parker
|
||||
*
|
||||
* RetroArch is free software: you can redistribute it and/or modify it under the terms
|
||||
* of the GNU General Public License as published by the Free Software Found-
|
||||
|
@ -1,5 +1,6 @@
|
||||
/* RetroArch - A frontend for libretro.
|
||||
* Copyright (C) 2011-2017 - Daniel De Matteis
|
||||
* Copyright (C) 2016-2019 - Brad Parker
|
||||
*
|
||||
* RetroArch is free software: you can redistribute it and/or modify it under the terms
|
||||
* of the GNU General Public License as published by the Free Software Found-
|
||||
|
@ -1,6 +1,7 @@
|
||||
/* RetroArch - A frontend for libretro.
|
||||
* Copyright (C) 2010-2014 - Hans-Kristian Arntzen
|
||||
* Copyright (C) 2011-2016 - Daniel De Matteis
|
||||
* Copyright (C) 2016-2019 - Brad Parker
|
||||
*
|
||||
* RetroArch is free software: you can redistribute it and/or modify it under the terms
|
||||
* of the GNU General Public License as published by the Free Software Found-
|
||||
|
@ -1,6 +1,7 @@
|
||||
/* RetroArch - A frontend for libretro.
|
||||
* Copyright (C) 2010-2014 - Hans-Kristian Arntzen
|
||||
* Copyright (C) 2011-2017 - Daniel De Matteis
|
||||
* Copyright (C) 2016-2019 - Brad Parker
|
||||
*
|
||||
* RetroArch is free software: you can redistribute it and/or modify it under the terms
|
||||
* of the GNU General Public License as published by the Free Software Found-
|
||||
|
@ -1,5 +1,6 @@
|
||||
/* RetroArch - A frontend for libretro.
|
||||
* Copyright (C) 2011-2017 - Daniel De Matteis
|
||||
* Copyright (C) 2016-2019 - Brad Parker
|
||||
*
|
||||
* RetroArch is free software: you can redistribute it and/or modify it under the terms
|
||||
* of the GNU General Public License as published by the Free Software Found-
|
||||
|
647
libretro-common/cdrom/cdrom.c
Normal file
647
libretro-common/cdrom/cdrom.c
Normal file
@ -0,0 +1,647 @@
|
||||
/* Copyright (C) 2010-2019 The RetroArch team
|
||||
*
|
||||
* ---------------------------------------------------------------------------------------
|
||||
* The following license statement only applies to this file (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.
|
||||
*/
|
||||
|
||||
#ifdef HAVE_CONFIG_H
|
||||
#include "config.h"
|
||||
#endif
|
||||
|
||||
#include <cdrom/cdrom.h>
|
||||
#include <libretro.h>
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include <compat/strl.h>
|
||||
#include <retro_math.h>
|
||||
#include <streams/file_stream.h>
|
||||
#include <retro_endianness.h>
|
||||
#include <retro_miscellaneous.h>
|
||||
#include <vfs/vfs_implementation.h>
|
||||
|
||||
#include <math.h>
|
||||
#include <unistd.h>
|
||||
|
||||
#ifdef __linux__
|
||||
#include <stropts.h>
|
||||
#include <scsi/sg.h>
|
||||
#endif
|
||||
|
||||
#ifdef _WIN32
|
||||
#include <winioctl.h>
|
||||
#include <ntddscsi.h>
|
||||
#endif
|
||||
|
||||
#define CDROM_CUE_TRACK_BYTES 86
|
||||
#define CDROM_MAX_SENSE_BYTES 16
|
||||
#define CDROM_MAX_RETRIES 10
|
||||
|
||||
typedef enum
|
||||
{
|
||||
DIRECTION_NONE,
|
||||
DIRECTION_IN,
|
||||
DIRECTION_OUT
|
||||
} CDROM_CMD_Direction;
|
||||
|
||||
void lba_to_msf(unsigned lba, unsigned char *min, unsigned char *sec, unsigned char *frame)
|
||||
{
|
||||
if (!min || !sec || !frame)
|
||||
return;
|
||||
|
||||
*frame = lba % 75;
|
||||
lba /= 75;
|
||||
*sec = lba % 60;
|
||||
lba /= 60;
|
||||
*min = lba;
|
||||
}
|
||||
|
||||
unsigned msf_to_lba(unsigned char min, unsigned char sec, unsigned char frame)
|
||||
{
|
||||
return (min * 60 + sec) * 75 + frame;
|
||||
}
|
||||
|
||||
void increment_msf(unsigned char *min, unsigned char *sec, unsigned char *frame)
|
||||
{
|
||||
if (!min || !sec || !frame)
|
||||
return;
|
||||
|
||||
*min = (*frame == 74) ? (*sec < 59 ? *min : *min + 1) : *min;
|
||||
*sec = (*frame == 74) ? (*sec < 59 ? (*sec + 1) : 0) : *sec;
|
||||
*frame = (*frame < 74) ? (*frame + 1) : 0;
|
||||
}
|
||||
|
||||
#ifdef _WIN32
|
||||
static int cdrom_send_command_win32(HANDLE fh, CDROM_CMD_Direction dir, void *buf, size_t len, unsigned char *cmd, size_t cmd_len, unsigned char *sense, size_t sense_len)
|
||||
{
|
||||
DWORD ioctl_bytes;
|
||||
BOOL ioctl_rv;
|
||||
struct sptd_with_sense
|
||||
{
|
||||
SCSI_PASS_THROUGH_DIRECT s;
|
||||
UCHAR sense[128];
|
||||
} sptd;
|
||||
|
||||
memset(&sptd, 0, sizeof(sptd));
|
||||
|
||||
sptd.s.Length = sizeof(sptd.s);
|
||||
sptd.s.CdbLength = cmd_len;
|
||||
|
||||
switch (dir)
|
||||
{
|
||||
case DIRECTION_IN:
|
||||
sptd.s.DataIn = SCSI_IOCTL_DATA_IN;
|
||||
break;
|
||||
case DIRECTION_OUT:
|
||||
sptd.s.DataIn = SCSI_IOCTL_DATA_OUT;
|
||||
break;
|
||||
case DIRECTION_NONE:
|
||||
default:
|
||||
sptd.s.DataIn = SCSI_IOCTL_DATA_UNSPECIFIED;
|
||||
break;
|
||||
}
|
||||
|
||||
sptd.s.TimeOutValue = 30;
|
||||
sptd.s.DataBuffer = buf;
|
||||
sptd.s.DataTransferLength = len;
|
||||
sptd.s.SenseInfoLength = sizeof(sptd.sense);
|
||||
sptd.s.SenseInfoOffset = offsetof(struct sptd_with_sense, sense);
|
||||
|
||||
memcpy(sptd.s.Cdb, cmd, cmd_len);
|
||||
|
||||
ioctl_rv = DeviceIoControl(fh, IOCTL_SCSI_PASS_THROUGH_DIRECT, &sptd,
|
||||
sizeof(sptd), &sptd, sizeof(sptd), &ioctl_bytes, NULL);
|
||||
|
||||
if (!ioctl_rv)
|
||||
return 1;
|
||||
|
||||
return 0;
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifdef __linux__
|
||||
static int cdrom_send_command_linux(int fd, CDROM_CMD_Direction dir, void *buf, size_t len, unsigned char *cmd, size_t cmd_len, unsigned char *sense, size_t sense_len)
|
||||
{
|
||||
sg_io_hdr_t sgio = {0};
|
||||
int rv;
|
||||
|
||||
switch (dir)
|
||||
{
|
||||
case DIRECTION_IN:
|
||||
sgio.dxfer_direction = SG_DXFER_FROM_DEV;
|
||||
break;
|
||||
case DIRECTION_OUT:
|
||||
sgio.dxfer_direction = SG_DXFER_TO_DEV;
|
||||
break;
|
||||
case DIRECTION_NONE:
|
||||
default:
|
||||
sgio.dxfer_direction = SG_DXFER_NONE;
|
||||
break;
|
||||
}
|
||||
|
||||
sgio.interface_id = 'S';
|
||||
sgio.cmd_len = cmd_len;
|
||||
sgio.cmdp = cmd;
|
||||
sgio.dxferp = buf;
|
||||
sgio.dxfer_len = len;
|
||||
sgio.sbp = sense;
|
||||
sgio.mx_sb_len = sense_len;
|
||||
sgio.timeout = 30000;
|
||||
|
||||
rv = ioctl(fd, SG_IO, &sgio);
|
||||
|
||||
if (rv == -1 || sgio.info & SG_INFO_CHECK)
|
||||
return 1;
|
||||
|
||||
return 0;
|
||||
}
|
||||
#endif
|
||||
|
||||
static int cdrom_send_command(libretro_vfs_implementation_file *stream, CDROM_CMD_Direction dir, void *buf, size_t len, unsigned char *cmd, size_t cmd_len, size_t skip)
|
||||
{
|
||||
unsigned char *xfer_buf;
|
||||
unsigned char sense[CDROM_MAX_SENSE_BYTES] = {0};
|
||||
unsigned char retries_left = CDROM_MAX_RETRIES;
|
||||
int rv = 0;
|
||||
|
||||
if (!cmd || cmd_len == 0)
|
||||
return 1;
|
||||
|
||||
xfer_buf = (unsigned char*)calloc(1, len + skip);
|
||||
|
||||
if (!xfer_buf)
|
||||
return 1;
|
||||
|
||||
#ifdef CDROM_DEBUG
|
||||
{
|
||||
unsigned i;
|
||||
|
||||
printf("CDROM Send Command: ");
|
||||
|
||||
for (i = 0; i < cmd_len / sizeof(*cmd); i++)
|
||||
{
|
||||
printf("%02X ", cmd[i]);
|
||||
}
|
||||
|
||||
printf("\n");
|
||||
fflush(stdout);
|
||||
}
|
||||
#endif
|
||||
|
||||
retry:
|
||||
#ifdef __linux__
|
||||
if (!cdrom_send_command_linux(fileno(stream->fp), dir, xfer_buf, len + skip, cmd, cmd_len, sense, sizeof(sense)))
|
||||
#else
|
||||
#ifdef _WIN32
|
||||
if (!cdrom_send_command_win32(stream->fh, dir, xfer_buf, len + skip, cmd, cmd_len, sense, sizeof(sense)))
|
||||
#endif
|
||||
#endif
|
||||
{
|
||||
rv = 0;
|
||||
|
||||
if (buf)
|
||||
memcpy(buf, xfer_buf + skip, len);
|
||||
}
|
||||
else
|
||||
{
|
||||
unsigned i;
|
||||
const char *sense_key_text = NULL;
|
||||
|
||||
(void)sense_key_text;
|
||||
(void)i;
|
||||
|
||||
switch (sense[2] & 0xF)
|
||||
{
|
||||
case 0:
|
||||
case 2:
|
||||
case 3:
|
||||
case 4:
|
||||
case 6:
|
||||
if (retries_left)
|
||||
{
|
||||
#ifdef CDROM_DEBUG
|
||||
printf("CDROM Read Retry...\n");
|
||||
fflush(stdout);
|
||||
#endif
|
||||
retries_left--;
|
||||
usleep(1000 * 1000);
|
||||
goto retry;
|
||||
}
|
||||
else
|
||||
{
|
||||
rv = 1;
|
||||
#ifdef CDROM_DEBUG
|
||||
printf("CDROM Read Retries failed, giving up.\n");
|
||||
fflush(stdout);
|
||||
#endif
|
||||
}
|
||||
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
#ifdef CDROM_DEBUG
|
||||
printf("CHECK CONDITION\n");
|
||||
|
||||
for (i = 0; i < CDROM_MAX_SENSE_BYTES; i++)
|
||||
{
|
||||
printf("%02X ", sense[i]);
|
||||
}
|
||||
|
||||
printf("\n");
|
||||
|
||||
if (sense[0] == 0x70)
|
||||
printf("CURRENT ERROR:\n");
|
||||
if (sense[0] == 0x71)
|
||||
printf("DEFERRED ERROR:\n");
|
||||
|
||||
switch (sense[2] & 0xF)
|
||||
{
|
||||
case 0:
|
||||
sense_key_text = "NO SENSE";
|
||||
break;
|
||||
case 1:
|
||||
sense_key_text = "RECOVERED ERROR";
|
||||
break;
|
||||
case 2:
|
||||
sense_key_text = "NOT READY";
|
||||
break;
|
||||
case 3:
|
||||
sense_key_text = "MEDIUM ERROR";
|
||||
break;
|
||||
case 4:
|
||||
sense_key_text = "HARDWARE ERROR";
|
||||
break;
|
||||
case 5:
|
||||
sense_key_text = "ILLEGAL REQUEST";
|
||||
break;
|
||||
case 6:
|
||||
sense_key_text = "UNIT ATTENTION";
|
||||
break;
|
||||
case 7:
|
||||
sense_key_text = "DATA PROTECT";
|
||||
break;
|
||||
case 8:
|
||||
sense_key_text = "BLANK CHECK";
|
||||
break;
|
||||
case 9:
|
||||
sense_key_text = "VENDOR SPECIFIC";
|
||||
break;
|
||||
case 10:
|
||||
sense_key_text = "COPY ABORTED";
|
||||
break;
|
||||
case 11:
|
||||
sense_key_text = "ABORTED COMMAND";
|
||||
break;
|
||||
case 13:
|
||||
sense_key_text = "VOLUME OVERFLOW";
|
||||
break;
|
||||
case 14:
|
||||
sense_key_text = "MISCOMPARE";
|
||||
break;
|
||||
}
|
||||
|
||||
printf("Sense Key: %02X (%s)\n", sense[2] & 0xF, sense_key_text);
|
||||
printf("ASC: %02X\n", sense[12]);
|
||||
printf("ASCQ: %02X\n", sense[13]);
|
||||
|
||||
fflush(stdout);
|
||||
|
||||
rv = 1;
|
||||
#endif
|
||||
}
|
||||
|
||||
if (xfer_buf)
|
||||
free(xfer_buf);
|
||||
|
||||
return rv;
|
||||
}
|
||||
|
||||
int cdrom_read_subq(libretro_vfs_implementation_file *stream, unsigned char *buf, size_t len)
|
||||
{
|
||||
/* MMC Command: READ TOC/PMA/ATIP */
|
||||
unsigned char cdb[] = {0x43, 0x2, 0x2, 0, 0, 0, 0x1, 0x9, 0x30, 0};
|
||||
#ifdef CDROM_DEBUG
|
||||
unsigned short data_len = 0;
|
||||
unsigned char first_session = 0;
|
||||
unsigned char last_session = 0;
|
||||
int i;
|
||||
#endif
|
||||
int rv;
|
||||
|
||||
if (!buf)
|
||||
return 1;
|
||||
|
||||
rv = cdrom_send_command(stream, DIRECTION_IN, buf, len, cdb, sizeof(cdb), 0);
|
||||
|
||||
if (rv)
|
||||
return 1;
|
||||
|
||||
#ifdef CDROM_DEBUG
|
||||
data_len = buf[0] << 8 | buf[1];
|
||||
first_session = buf[2];
|
||||
last_session = buf[3];
|
||||
|
||||
printf("Data Length: %d\n", data_len);
|
||||
printf("First Session: %d\n", first_session);
|
||||
printf("Last Session: %d\n", last_session);
|
||||
|
||||
for (i = 0; i < (data_len - 2) / 11; i++)
|
||||
{
|
||||
unsigned char session_num = buf[4 + (i * 11) + 0];
|
||||
unsigned char adr = (buf[4 + (i * 11) + 1] >> 4) & 0xF;
|
||||
/*unsigned char control = buf[4 + (i * 11) + 1] & 0xF;*/
|
||||
unsigned char tno = buf[4 + (i * 11) + 2];
|
||||
unsigned char point = buf[4 + (i * 11) + 3];
|
||||
unsigned char pmin = buf[4 + (i * 11) + 8];
|
||||
unsigned char psec = buf[4 + (i * 11) + 9];
|
||||
unsigned char pframe = buf[4 + (i * 11) + 10];
|
||||
|
||||
/*printf("i %d control %d adr %d tno %d point %d: ", i, control, adr, tno, point);*/
|
||||
/* why is control always 0? */
|
||||
|
||||
if (/*(control == 4 || control == 6) && */adr == 1 && tno == 0 && point >= 1 && point <= 99)
|
||||
{
|
||||
printf("- Session#: %d TNO %d POINT %d ", session_num, tno, point);
|
||||
printf("Track start time: (MSF %02u:%02u:%02u) ", pmin, psec, pframe);
|
||||
}
|
||||
else if (/*(control == 4 || control == 6) && */adr == 1 && tno == 0 && point == 0xA0)
|
||||
{
|
||||
printf("- Session#: %d TNO %d POINT %d ", session_num, tno, point);
|
||||
printf("First Track Number: %d ", pmin);
|
||||
printf("Disc Type: %d ", psec);
|
||||
}
|
||||
else if (/*(control == 4 || control == 6) && */adr == 1 && tno == 0 && point == 0xA1)
|
||||
{
|
||||
printf("- Session#: %d TNO %d POINT %d ", session_num, tno, point);
|
||||
printf("Last Track Number: %d ", pmin);
|
||||
}
|
||||
else if (/*(control == 4 || control == 6) && */adr == 1 && tno == 0 && point == 0xA2)
|
||||
{
|
||||
printf("- Session#: %d TNO %d POINT %d ", session_num, tno, point);
|
||||
printf("Lead-out runtime: (MSF %02u:%02u:%02u) ", pmin, psec, pframe);
|
||||
}
|
||||
|
||||
printf("\n");
|
||||
}
|
||||
|
||||
fflush(stdout);
|
||||
#endif
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int cdrom_read_track_info(libretro_vfs_implementation_file *stream, unsigned char track, cdrom_toc_t *toc)
|
||||
{
|
||||
/* MMC Command: READ TRACK INFORMATION */
|
||||
unsigned char cdb[] = {0x52, 0x1, 0, 0, 0, track, 0, 0x1, 0x80, 0};
|
||||
unsigned char buf[384] = {0};
|
||||
unsigned lba = 0;
|
||||
unsigned track_size = 0;
|
||||
int rv = cdrom_send_command(stream, DIRECTION_IN, buf, sizeof(buf), cdb, sizeof(cdb), 0);
|
||||
|
||||
if (rv)
|
||||
return 1;
|
||||
|
||||
memcpy(&lba, buf + 8, 4);
|
||||
memcpy(&track_size, buf + 24, 4);
|
||||
|
||||
lba = swap_if_little32(lba);
|
||||
track_size = swap_if_little32(track_size);
|
||||
|
||||
/* lba_start may be earlier than the MSF start times seen in read_subq */
|
||||
toc->track[track - 1].lba_start = lba;
|
||||
toc->track[track - 1].track_size = track_size;
|
||||
|
||||
#ifdef CDROM_DEBUG
|
||||
printf("Track %d Info: ", track);
|
||||
printf("Copy: %d ", (buf[5] & 0x10) > 0);
|
||||
printf("Data Mode: %d ", buf[6] & 0xF);
|
||||
printf("LBA Start: %d ", lba);
|
||||
printf("Track Size: %d\n", track_size);
|
||||
fflush(stdout);
|
||||
#endif
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int cdrom_set_read_speed(libretro_vfs_implementation_file *stream, unsigned speed)
|
||||
{
|
||||
unsigned new_speed = swap_if_big32(speed);
|
||||
/* MMC Command: SET CD SPEED */
|
||||
unsigned char cmd[] = {0xBB, 0, (new_speed >> 24) & 0xFF, (new_speed >> 16) & 0xFF, (new_speed >> 8) & 0xFF, new_speed & 0xFF, 0, 0, 0, 0, 0, 0 };
|
||||
|
||||
return cdrom_send_command(stream, DIRECTION_NONE, NULL, 0, cmd, sizeof(cmd), 0);
|
||||
}
|
||||
|
||||
int cdrom_write_cue(libretro_vfs_implementation_file *stream, char **out_buf, size_t *out_len, char cdrom_drive, unsigned char *num_tracks, cdrom_toc_t *toc)
|
||||
{
|
||||
unsigned char buf[2352] = {0};
|
||||
unsigned short data_len = 0;
|
||||
size_t len = 0;
|
||||
size_t pos = 0;
|
||||
int rv = 0;
|
||||
int i;
|
||||
|
||||
if (!out_buf || !out_len || !num_tracks || !toc)
|
||||
{
|
||||
#ifdef CDROM_DEBUG
|
||||
printf("Invalid buffer/length pointer for CDROM cue sheet\n");
|
||||
fflush(stdout);
|
||||
#endif
|
||||
return 1;
|
||||
}
|
||||
|
||||
cdrom_set_read_speed(stream, 0xFFFFFFFF);
|
||||
|
||||
rv = cdrom_read_subq(stream, buf, sizeof(buf));
|
||||
|
||||
if (rv)
|
||||
return rv;
|
||||
|
||||
data_len = buf[0] << 8 | buf[1];
|
||||
|
||||
for (i = 0; i < (data_len - 2) / 11; i++)
|
||||
{
|
||||
unsigned char adr = (buf[4 + (i * 11) + 1] >> 4) & 0xF;
|
||||
unsigned char tno = buf[4 + (i * 11) + 2];
|
||||
unsigned char point = buf[4 + (i * 11) + 3];
|
||||
unsigned char pmin = buf[4 + (i * 11) + 8];
|
||||
|
||||
if (/*(control == 4 || control == 6) && */adr == 1 && tno == 0 && point == 0xA1)
|
||||
{
|
||||
*num_tracks = pmin;
|
||||
#ifdef CDROM_DEBUG
|
||||
printf("Number of CDROM tracks: %d\n", *num_tracks);
|
||||
fflush(stdout);
|
||||
#endif
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (!*num_tracks || *num_tracks > 99)
|
||||
{
|
||||
#ifdef CDROM_DEBUG
|
||||
printf("Invalid number of CDROM tracks: %d\n", *num_tracks);
|
||||
fflush(stdout);
|
||||
#endif
|
||||
return 1;
|
||||
}
|
||||
|
||||
len = CDROM_CUE_TRACK_BYTES * (*num_tracks);
|
||||
toc->num_tracks = *num_tracks;
|
||||
*out_buf = (char*)calloc(1, len);
|
||||
*out_len = len;
|
||||
|
||||
for (i = 0; i < (data_len - 2) / 11; i++)
|
||||
{
|
||||
/*unsigned char session_num = buf[4 + (i * 11) + 0];*/
|
||||
unsigned char adr = (buf[4 + (i * 11) + 1] >> 4) & 0xF;
|
||||
unsigned char control = buf[4 + (i * 11) + 1] & 0xF;
|
||||
unsigned char tno = buf[4 + (i * 11) + 2];
|
||||
unsigned char point = buf[4 + (i * 11) + 3];
|
||||
unsigned char pmin = buf[4 + (i * 11) + 8];
|
||||
unsigned char psec = buf[4 + (i * 11) + 9];
|
||||
unsigned char pframe = buf[4 + (i * 11) + 10];
|
||||
unsigned lba = msf_to_lba(pmin, psec, pframe);
|
||||
|
||||
/*printf("i %d control %d adr %d tno %d point %d: ", i, control, adr, tno, point);*/
|
||||
/* why is control always 0? */
|
||||
|
||||
if (/*(control == 4 || control == 6) && */adr == 1 && tno == 0 && point >= 1 && point <= 99)
|
||||
{
|
||||
unsigned char mode = 1;
|
||||
bool audio = false;
|
||||
const char *track_type = "MODE1/2352";
|
||||
|
||||
mode = adr;
|
||||
audio = (!(control & 0x4) && !(control & 0x5));
|
||||
|
||||
#ifdef CDROM_DEBUG
|
||||
printf("Track %02d CONTROL %01X ADR %01X MODE %d AUDIO? %d\n", point, control, adr, mode, audio);
|
||||
fflush(stdout);
|
||||
#endif
|
||||
|
||||
toc->track[point - 1].track_num = point;
|
||||
toc->track[point - 1].min = pmin;
|
||||
toc->track[point - 1].sec = psec;
|
||||
toc->track[point - 1].frame = pframe;
|
||||
toc->track[point - 1].lba = lba;
|
||||
toc->track[point - 1].mode = mode;
|
||||
toc->track[point - 1].audio = audio;
|
||||
|
||||
if (audio)
|
||||
track_type = "AUDIO";
|
||||
else if (mode == 1)
|
||||
track_type = "MODE1/2352";
|
||||
else if (mode == 2)
|
||||
track_type = "MODE2/2352";
|
||||
|
||||
cdrom_read_track_info(stream, point, toc);
|
||||
|
||||
#ifdef _WIN32
|
||||
pos += snprintf(*out_buf + pos, len - pos, "FILE \"cdrom://%c://drive-track%02d.bin\" BINARY\n", cdrom_drive, point);
|
||||
#else
|
||||
pos += snprintf(*out_buf + pos, len - pos, "FILE \"cdrom://drive%c-track%02d.bin\" BINARY\n", cdrom_drive, point);
|
||||
#endif
|
||||
pos += snprintf(*out_buf + pos, len - pos, " TRACK %02d %s\n", point, track_type);
|
||||
pos += snprintf(*out_buf + pos, len - pos, " INDEX 01 00:00:00\n");
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* needs 32 bytes for full vendor, product and version */
|
||||
int cdrom_get_inquiry(libretro_vfs_implementation_file *stream, char *model, int len)
|
||||
{
|
||||
/* MMC Command: INQUIRY */
|
||||
unsigned char cdb[] = {0x12, 0, 0, 0, 0xff, 0};
|
||||
unsigned char buf[256] = {0};
|
||||
int rv = cdrom_send_command(stream, DIRECTION_IN, buf, sizeof(buf), cdb, sizeof(cdb), 0);
|
||||
|
||||
if (rv)
|
||||
return 1;
|
||||
|
||||
if (model && len >= 32)
|
||||
{
|
||||
memset(model, 0, len);
|
||||
|
||||
/* vendor */
|
||||
memcpy(model, buf + 8, 8);
|
||||
|
||||
model[8] = ' ';
|
||||
|
||||
/* product */
|
||||
memcpy(model + 9, buf + 16, 16);
|
||||
|
||||
model[25] = ' ';
|
||||
|
||||
/* version */
|
||||
memcpy(model + 26, buf + 32, 4);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int cdrom_read(libretro_vfs_implementation_file *stream, unsigned char min, unsigned char sec, unsigned char frame, void *s, size_t len, size_t skip)
|
||||
{
|
||||
/* MMC Command: READ CD MSF */
|
||||
unsigned char cdb[] = {0xB9, 0, 0, min, sec, frame, 0, 0, 0, 0xF8, 0, 0};
|
||||
int rv;
|
||||
|
||||
if (len + skip <= 2352)
|
||||
{
|
||||
unsigned char next_min = (frame == 74) ? (sec < 59 ? min : min + 1) : min;
|
||||
unsigned char next_sec = (frame == 74) ? (sec < 59 ? (sec + 1) : 0) : sec;
|
||||
unsigned char next_frame = (frame < 74) ? (frame + 1) : 0;
|
||||
|
||||
cdb[6] = next_min;
|
||||
cdb[7] = next_sec;
|
||||
cdb[8] = next_frame;
|
||||
|
||||
#ifdef CDROM_DEBUG
|
||||
printf("single-frame read: from %d %d %d to %d %d %d skip %" PRId64 "\n", cdb[3], cdb[4], cdb[5], cdb[6], cdb[7], cdb[8], skip);
|
||||
fflush(stdout);
|
||||
#endif
|
||||
}
|
||||
else
|
||||
{
|
||||
unsigned frames = msf_to_lba(min, sec, frame) + round((len + skip) / 2352.0);
|
||||
|
||||
lba_to_msf(frames, &cdb[6], &cdb[7], &cdb[8]);
|
||||
|
||||
#ifdef CDROM_DEBUG
|
||||
printf("multi-frame read: from %d %d %d to %d %d %d skip %" PRId64 "\n", cdb[3], cdb[4], cdb[5], cdb[6], cdb[7], cdb[8], skip);
|
||||
fflush(stdout);
|
||||
#endif
|
||||
}
|
||||
|
||||
rv = cdrom_send_command(stream, DIRECTION_IN, s, len, cdb, sizeof(cdb), skip);
|
||||
|
||||
#ifdef CDROM_DEBUG
|
||||
printf("read status code %d\n", rv);
|
||||
fflush(stdout);
|
||||
#endif
|
||||
|
||||
if (rv)
|
||||
return 1;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
84
libretro-common/include/cdrom/cdrom.h
Normal file
84
libretro-common/include/cdrom/cdrom.h
Normal file
@ -0,0 +1,84 @@
|
||||
/* Copyright (C) 2010-2019 The RetroArch team
|
||||
*
|
||||
* ---------------------------------------------------------------------------------------
|
||||
* The following license statement only applies to this file (cdrom.h).
|
||||
* ---------------------------------------------------------------------------------------
|
||||
*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
#ifndef __LIBRETRO_SDK_CDROM_H
|
||||
#define __LIBRETRO_SDK_CDROM_H
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdint.h>
|
||||
#include <stddef.h>
|
||||
#include <sys/types.h>
|
||||
|
||||
#include <libretro.h>
|
||||
#include <retro_common_api.h>
|
||||
#include <retro_inline.h>
|
||||
|
||||
#include <boolean.h>
|
||||
|
||||
#ifdef VFS_FRONTEND
|
||||
typedef struct retro_vfs_file_handle libretro_vfs_implementation_file;
|
||||
#else
|
||||
typedef struct libretro_vfs_implementation_file libretro_vfs_implementation_file;
|
||||
#endif
|
||||
|
||||
RETRO_BEGIN_DECLS
|
||||
|
||||
typedef struct
|
||||
{
|
||||
unsigned lba_start; /* start of pregap */
|
||||
unsigned lba; /* start of data */
|
||||
unsigned track_size;
|
||||
unsigned char track_num;
|
||||
unsigned char min; /* start of data */
|
||||
unsigned char sec;
|
||||
unsigned char frame;
|
||||
unsigned char mode;
|
||||
bool audio;
|
||||
} cdrom_track_t;
|
||||
|
||||
typedef struct
|
||||
{
|
||||
char drive;
|
||||
unsigned char num_tracks;
|
||||
cdrom_track_t track[99];
|
||||
} cdrom_toc_t;
|
||||
|
||||
void lba_to_msf(unsigned lba, unsigned char *min, unsigned char *sec, unsigned char *frame);
|
||||
|
||||
unsigned msf_to_lba(unsigned char min, unsigned char sec, unsigned char frame);
|
||||
|
||||
void increment_msf(unsigned char *min, unsigned char *sec, unsigned char *frame);
|
||||
|
||||
int cdrom_read_subq(libretro_vfs_implementation_file *stream, unsigned char *buf, size_t len);
|
||||
|
||||
int cdrom_write_cue(libretro_vfs_implementation_file *stream, char **out_buf, size_t *out_len, char cdrom_drive, unsigned char *num_tracks, cdrom_toc_t *toc);
|
||||
|
||||
/* needs 32 bytes for full vendor, product and version */
|
||||
int cdrom_get_inquiry(libretro_vfs_implementation_file *stream, char *model, int len);
|
||||
|
||||
int cdrom_read(libretro_vfs_implementation_file *stream, unsigned char min, unsigned char sec, unsigned char frame, void *s, size_t len, size_t skip);
|
||||
|
||||
int cdrom_set_read_speed(libretro_vfs_implementation_file *stream, unsigned speed);
|
||||
|
||||
RETRO_END_DECLS
|
||||
|
||||
#endif
|
@ -36,6 +36,7 @@
|
||||
#include <boolean.h>
|
||||
|
||||
#include <stdarg.h>
|
||||
#include <vfs/vfs_implementation.h>
|
||||
|
||||
#define FILESTREAM_REQUIRED_VFS_VERSION 2
|
||||
|
||||
@ -106,6 +107,8 @@ bool filestream_exists(const char *path);
|
||||
|
||||
char *filestream_getline(RFILE *stream);
|
||||
|
||||
const libretro_vfs_implementation_file* filestream_get_vfs_handle(RFILE *stream);
|
||||
|
||||
RETRO_END_DECLS
|
||||
|
||||
#endif
|
||||
|
@ -23,9 +23,48 @@
|
||||
#ifndef __LIBRETRO_SDK_VFS_IMPLEMENTATION_H
|
||||
#define __LIBRETRO_SDK_VFS_IMPLEMENTATION_H
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdint.h>
|
||||
#include <libretro.h>
|
||||
|
||||
#ifdef HAVE_CDROM
|
||||
#include <vfs/vfs_implementation_cdrom.h>
|
||||
#endif
|
||||
|
||||
#ifdef _WIN32
|
||||
typedef void* HANDLE;
|
||||
#endif
|
||||
|
||||
enum vfs_scheme
|
||||
{
|
||||
VFS_SCHEME_NONE = 0,
|
||||
VFS_SCHEME_CDROM
|
||||
};
|
||||
|
||||
#ifdef VFS_FRONTEND
|
||||
struct retro_vfs_file_handle
|
||||
#else
|
||||
struct libretro_vfs_implementation_file
|
||||
#endif
|
||||
{
|
||||
int fd;
|
||||
unsigned hints;
|
||||
int64_t size;
|
||||
char *buf;
|
||||
FILE *fp;
|
||||
#ifdef _WIN32
|
||||
HANDLE fh;
|
||||
#endif
|
||||
char* orig_path;
|
||||
uint64_t mappos;
|
||||
uint64_t mapsize;
|
||||
uint8_t *mapped;
|
||||
enum vfs_scheme scheme;
|
||||
#ifdef HAVE_CDROM
|
||||
vfs_cdrom_t cdrom;
|
||||
#endif
|
||||
};
|
||||
|
||||
/* Replace the following symbol with something appropriate
|
||||
* to signify the file is being compiled for a front end instead of a core.
|
||||
* This allows the same code to act as reference implementation
|
||||
|
72
libretro-common/include/vfs/vfs_implementation_cdrom.h
Normal file
72
libretro-common/include/vfs/vfs_implementation_cdrom.h
Normal file
@ -0,0 +1,72 @@
|
||||
/* Copyright (C) 2010-2019 The RetroArch team
|
||||
*
|
||||
* ---------------------------------------------------------------------------------------
|
||||
* The following license statement only applies to this file (vfs_implementation_cdrom.h).
|
||||
* ---------------------------------------------------------------------------------------
|
||||
*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
#ifndef __LIBRETRO_SDK_VFS_IMPLEMENTATION_CDROM_H
|
||||
#define __LIBRETRO_SDK_VFS_IMPLEMENTATION_CDROM_H
|
||||
|
||||
#include <cdrom/cdrom.h>
|
||||
|
||||
RETRO_BEGIN_DECLS
|
||||
|
||||
typedef struct RFILE RFILE;
|
||||
|
||||
typedef struct
|
||||
{
|
||||
char *cue_buf;
|
||||
size_t cue_len;
|
||||
int64_t byte_pos;
|
||||
char drive;
|
||||
unsigned char cur_min;
|
||||
unsigned char cur_sec;
|
||||
unsigned char cur_frame;
|
||||
unsigned char cur_track;
|
||||
unsigned cur_lba;
|
||||
} vfs_cdrom_t;
|
||||
|
||||
#ifdef VFS_FRONTEND
|
||||
struct retro_vfs_file_handle;
|
||||
#else
|
||||
struct libretro_vfs_implementation_file;
|
||||
#endif
|
||||
|
||||
int64_t retro_vfs_file_seek_cdrom(libretro_vfs_implementation_file *stream, int64_t offset, int whence);
|
||||
|
||||
void retro_vfs_file_open_cdrom(
|
||||
libretro_vfs_implementation_file *stream,
|
||||
const char *path, unsigned mode, unsigned hints);
|
||||
|
||||
int retro_vfs_file_close_cdrom(libretro_vfs_implementation_file *stream);
|
||||
|
||||
int64_t retro_vfs_file_tell_cdrom(libretro_vfs_implementation_file *stream);
|
||||
|
||||
int64_t retro_vfs_file_read_cdrom(libretro_vfs_implementation_file *stream,
|
||||
void *s, uint64_t len);
|
||||
|
||||
int retro_vfs_file_error_cdrom(libretro_vfs_implementation_file *stream);
|
||||
|
||||
const cdrom_toc_t* retro_vfs_file_get_cdrom_toc(void);
|
||||
|
||||
const vfs_cdrom_t* retro_vfs_file_get_cdrom_position(const libretro_vfs_implementation_file *stream);
|
||||
|
||||
RETRO_END_DECLS
|
||||
|
||||
#endif
|
@ -609,3 +609,8 @@ char *filestream_getline(RFILE *stream)
|
||||
newline[idx] = '\0';
|
||||
return newline;
|
||||
}
|
||||
|
||||
const libretro_vfs_implementation_file* filestream_get_vfs_handle(RFILE *stream)
|
||||
{
|
||||
return (const libretro_vfs_implementation_file*)stream->hfile;
|
||||
}
|
||||
|
@ -190,26 +190,11 @@
|
||||
#include <compat/fopen_utf8.h>
|
||||
#include <file/file_path.h>
|
||||
|
||||
#define RFILE_HINT_UNBUFFERED (1 << 8)
|
||||
#ifdef HAVE_CDROM
|
||||
#include <vfs/vfs_implementation_cdrom.h>
|
||||
#endif
|
||||
|
||||
#ifdef VFS_FRONTEND
|
||||
struct retro_vfs_file_handle
|
||||
#else
|
||||
struct libretro_vfs_implementation_file
|
||||
#endif
|
||||
{
|
||||
int fd;
|
||||
unsigned hints;
|
||||
int64_t size;
|
||||
char *buf;
|
||||
FILE *fp;
|
||||
char* orig_path;
|
||||
#if defined(HAVE_MMAP)
|
||||
uint64_t mappos;
|
||||
uint64_t mapsize;
|
||||
uint8_t *mapped;
|
||||
#endif
|
||||
};
|
||||
#define RFILE_HINT_UNBUFFERED (1 << 8)
|
||||
|
||||
int64_t retro_vfs_file_seek_internal(libretro_vfs_implementation_file *stream, int64_t offset, int whence)
|
||||
{
|
||||
@ -235,7 +220,12 @@ int64_t retro_vfs_file_seek_internal(libretro_vfs_implementation_file *stream, i
|
||||
return -1;
|
||||
return 0;
|
||||
#else
|
||||
return fseeko(stream->fp, (off_t)offset, whence);
|
||||
#ifdef HAVE_CDROM
|
||||
if (stream->scheme == VFS_SCHEME_CDROM)
|
||||
return retro_vfs_file_seek_cdrom(stream, offset, whence);
|
||||
else
|
||||
#endif
|
||||
return fseeko(stream->fp, (off_t)offset, whence);
|
||||
#endif
|
||||
}
|
||||
#ifdef HAVE_MMAP
|
||||
@ -296,6 +286,7 @@ libretro_vfs_implementation_file *retro_vfs_file_open_impl(
|
||||
{
|
||||
int flags = 0;
|
||||
const char *mode_str = NULL;
|
||||
int path_len = (int)strlen(path);
|
||||
libretro_vfs_implementation_file *stream = (libretro_vfs_implementation_file*)
|
||||
calloc(1, sizeof(*stream));
|
||||
|
||||
@ -303,7 +294,6 @@ libretro_vfs_implementation_file *retro_vfs_file_open_impl(
|
||||
const char *dumb_prefix = "vfsonly://";
|
||||
size_t dumb_prefix_siz = strlen(dumb_prefix);
|
||||
int dumb_prefix_len = (int)dumb_prefix_siz;
|
||||
int path_len = (int)strlen(path);
|
||||
|
||||
if (path_len >= dumb_prefix_len)
|
||||
{
|
||||
@ -312,6 +302,23 @@ libretro_vfs_implementation_file *retro_vfs_file_open_impl(
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifdef HAVE_CDROM
|
||||
{
|
||||
const char *cdrom_prefix = "cdrom://";
|
||||
size_t cdrom_prefix_siz = strlen(cdrom_prefix);
|
||||
int cdrom_prefix_len = (int)cdrom_prefix_siz;
|
||||
|
||||
if (path_len > cdrom_prefix_len)
|
||||
{
|
||||
if (!memcmp(path, cdrom_prefix, cdrom_prefix_len))
|
||||
{
|
||||
path += cdrom_prefix_siz;
|
||||
stream->scheme = VFS_SCHEME_CDROM;
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
if (!stream)
|
||||
return NULL;
|
||||
|
||||
@ -398,11 +405,29 @@ libretro_vfs_implementation_file *retro_vfs_file_open_impl(
|
||||
}
|
||||
stream->fd = fd;
|
||||
#else
|
||||
FILE *fp = (FILE*)fopen_utf8(path, mode_str);
|
||||
FILE *fp;
|
||||
#ifdef HAVE_CDROM
|
||||
if (stream->scheme == VFS_SCHEME_CDROM)
|
||||
{
|
||||
retro_vfs_file_open_cdrom(stream, path, mode, hints);
|
||||
#ifdef _WIN32
|
||||
if (!stream->fh)
|
||||
goto error;
|
||||
#else
|
||||
if (!stream->fp)
|
||||
goto error;
|
||||
#endif
|
||||
}
|
||||
else
|
||||
#endif
|
||||
{
|
||||
fp = (FILE*)fopen_utf8(path, mode_str);
|
||||
|
||||
if (!fp)
|
||||
goto error;
|
||||
if (!fp)
|
||||
goto error;
|
||||
|
||||
stream->fp = fp;
|
||||
}
|
||||
/* Regarding setvbuf:
|
||||
*
|
||||
* https://www.freebsd.org/cgi/man.cgi?query=setvbuf&apropos=0&sektion=0&manpath=FreeBSD+11.1-RELEASE&arch=default&format=html
|
||||
@ -413,10 +438,10 @@ libretro_vfs_implementation_file *retro_vfs_file_open_impl(
|
||||
* Since C89 does not support specifying a null buffer with a non-zero size, we create and track our own buffer for it.
|
||||
*/
|
||||
/* TODO: this is only useful for a few platforms, find which and add ifdef */
|
||||
stream->fp = fp;
|
||||
#if !defined(PS2) && !defined(PSP)
|
||||
stream->buf = (char*)calloc(1, 0x4000);
|
||||
setvbuf(stream->fp, stream->buf, _IOFBF, 0x4000);
|
||||
if (stream->fp)
|
||||
setvbuf(stream->fp, stream->buf, _IOFBF, 0x4000);
|
||||
#endif
|
||||
#endif
|
||||
}
|
||||
@ -465,12 +490,26 @@ libretro_vfs_implementation_file *retro_vfs_file_open_impl(
|
||||
stream->size = orbisLseek(stream->fd, 0, SEEK_END);
|
||||
orbisLseek(stream->fd, 0, SEEK_SET);
|
||||
#else
|
||||
retro_vfs_file_seek_internal(stream, 0, SEEK_SET);
|
||||
retro_vfs_file_seek_internal(stream, 0, SEEK_END);
|
||||
#ifdef HAVE_CDROM
|
||||
if (stream->scheme == VFS_SCHEME_CDROM)
|
||||
{
|
||||
retro_vfs_file_seek_cdrom(stream, 0, SEEK_SET);
|
||||
retro_vfs_file_seek_cdrom(stream, 0, SEEK_END);
|
||||
|
||||
stream->size = retro_vfs_file_tell_impl(stream);
|
||||
stream->size = retro_vfs_file_tell_impl(stream);
|
||||
|
||||
retro_vfs_file_seek_internal(stream, 0, SEEK_SET);
|
||||
retro_vfs_file_seek_cdrom(stream, 0, SEEK_SET);
|
||||
}
|
||||
else
|
||||
#endif
|
||||
{
|
||||
retro_vfs_file_seek_internal(stream, 0, SEEK_SET);
|
||||
retro_vfs_file_seek_internal(stream, 0, SEEK_END);
|
||||
|
||||
stream->size = retro_vfs_file_tell_impl(stream);
|
||||
|
||||
retro_vfs_file_seek_internal(stream, 0, SEEK_SET);
|
||||
}
|
||||
#endif
|
||||
return stream;
|
||||
|
||||
@ -484,10 +523,20 @@ int retro_vfs_file_close_impl(libretro_vfs_implementation_file *stream)
|
||||
if (!stream)
|
||||
return -1;
|
||||
|
||||
#ifdef HAVE_CDROM
|
||||
if (stream->scheme == VFS_SCHEME_CDROM)
|
||||
{
|
||||
retro_vfs_file_close_cdrom(stream);
|
||||
goto end;
|
||||
}
|
||||
#endif
|
||||
|
||||
if ((stream->hints & RFILE_HINT_UNBUFFERED) == 0)
|
||||
{
|
||||
if (stream->fp)
|
||||
{
|
||||
fclose(stream->fp);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
@ -506,10 +555,17 @@ int retro_vfs_file_close_impl(libretro_vfs_implementation_file *stream)
|
||||
close(stream->fd);
|
||||
#endif
|
||||
}
|
||||
#ifdef HAVE_CDROM
|
||||
end:
|
||||
if (stream->cdrom.cue_buf)
|
||||
free(stream->cdrom.cue_buf);
|
||||
#endif
|
||||
if (stream->buf)
|
||||
free(stream->buf);
|
||||
|
||||
if (stream->orig_path)
|
||||
free(stream->orig_path);
|
||||
|
||||
free(stream);
|
||||
|
||||
return 0;
|
||||
@ -520,9 +576,12 @@ int retro_vfs_file_error_impl(libretro_vfs_implementation_file *stream)
|
||||
#ifdef ORBIS
|
||||
/* TODO/FIXME - implement this? */
|
||||
return 0;
|
||||
#else
|
||||
return ferror(stream->fp);
|
||||
#endif
|
||||
#ifdef HAVE_CDROM
|
||||
if (stream->scheme == VFS_SCHEME_CDROM)
|
||||
return retro_vfs_file_error_cdrom(stream);
|
||||
#endif
|
||||
return ferror(stream->fp);
|
||||
}
|
||||
|
||||
int64_t retro_vfs_file_size_impl(libretro_vfs_implementation_file *stream)
|
||||
@ -555,6 +614,10 @@ int64_t retro_vfs_file_tell_impl(libretro_vfs_implementation_file *stream)
|
||||
|
||||
if ((stream->hints & RFILE_HINT_UNBUFFERED) == 0)
|
||||
{
|
||||
#ifdef HAVE_CDROM
|
||||
if (stream->scheme == VFS_SCHEME_CDROM)
|
||||
return retro_vfs_file_tell_cdrom(stream);
|
||||
#endif
|
||||
#ifdef ORBIS
|
||||
int64_t ret = orbisLseek(stream->fd, 0, SEEK_CUR);
|
||||
if (ret < 0)
|
||||
@ -565,7 +628,7 @@ int64_t retro_vfs_file_tell_impl(libretro_vfs_implementation_file *stream)
|
||||
#ifdef ATLEAST_VC2005
|
||||
return _ftelli64(stream->fp);
|
||||
#else
|
||||
return ftell(stream->fp);
|
||||
return ftell(stream->fp);
|
||||
#endif
|
||||
#endif
|
||||
}
|
||||
@ -614,7 +677,12 @@ int64_t retro_vfs_file_read_impl(libretro_vfs_implementation_file *stream,
|
||||
return -1;
|
||||
return 0;
|
||||
#else
|
||||
return fread(s, 1, (size_t)len, stream->fp);
|
||||
#ifdef HAVE_CDROM
|
||||
if (stream->scheme == VFS_SCHEME_CDROM)
|
||||
return retro_vfs_file_read_cdrom(stream, s, len);
|
||||
else
|
||||
#endif
|
||||
return fread(s, 1, (size_t)len, stream->fp);
|
||||
#endif
|
||||
}
|
||||
#ifdef HAVE_MMAP
|
||||
|
429
libretro-common/vfs/vfs_implementation_cdrom.c
Normal file
429
libretro-common/vfs/vfs_implementation_cdrom.c
Normal file
@ -0,0 +1,429 @@
|
||||
/* 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.
|
||||
*/
|
||||
|
||||
#include <vfs/vfs_implementation.h>
|
||||
#include <file/file_path.h>
|
||||
#include <compat/fopen_utf8.h>
|
||||
#include <string/stdstring.h>
|
||||
#include <cdrom/cdrom.h>
|
||||
|
||||
#ifdef _WIN32
|
||||
#include <windows.h>
|
||||
#endif
|
||||
|
||||
static cdrom_toc_t vfs_cdrom_toc = {0};
|
||||
|
||||
const cdrom_toc_t* retro_vfs_file_get_cdrom_toc(void)
|
||||
{
|
||||
return &vfs_cdrom_toc;
|
||||
}
|
||||
|
||||
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:
|
||||
stream->cdrom.byte_pos = offset;
|
||||
break;
|
||||
case SEEK_CUR:
|
||||
stream->cdrom.byte_pos += offset;
|
||||
break;
|
||||
case SEEK_END:
|
||||
stream->cdrom.byte_pos = (stream->cdrom.cue_len - 1) + offset;
|
||||
break;
|
||||
}
|
||||
|
||||
#ifdef CDROM_DEBUG
|
||||
printf("CDROM Seek: Path %s Offset %" PRIu64 " is now at %" PRIu64 "\n", stream->orig_path, offset, stream->cdrom.byte_pos);
|
||||
fflush(stdout);
|
||||
#endif
|
||||
}
|
||||
else if (string_is_equal_noncase(ext, "bin"))
|
||||
{
|
||||
int lba = (offset / 2352);
|
||||
unsigned char min = 0;
|
||||
unsigned char sec = 0;
|
||||
unsigned char frame = 0;
|
||||
const char *seek_type = "SEEK_SET";
|
||||
|
||||
(void)seek_type;
|
||||
|
||||
switch (whence)
|
||||
{
|
||||
case SEEK_CUR:
|
||||
{
|
||||
unsigned new_lba;
|
||||
|
||||
stream->cdrom.byte_pos += offset;
|
||||
new_lba = vfs_cdrom_toc.track[stream->cdrom.cur_track - 1].lba + (stream->cdrom.byte_pos / 2352);
|
||||
seek_type = "SEEK_CUR";
|
||||
|
||||
lba_to_msf(new_lba, &min, &sec, &frame);
|
||||
|
||||
break;
|
||||
}
|
||||
case SEEK_END:
|
||||
{
|
||||
ssize_t end_lba = (vfs_cdrom_toc.track[vfs_cdrom_toc.num_tracks - 1].lba_start + vfs_cdrom_toc.track[vfs_cdrom_toc.num_tracks - 1].track_size) - 1;
|
||||
|
||||
lba_to_msf(end_lba + lba, &min, &sec, &frame);
|
||||
|
||||
stream->cdrom.byte_pos = end_lba * 2352;
|
||||
seek_type = "SEEK_END";
|
||||
|
||||
break;
|
||||
}
|
||||
case SEEK_SET:
|
||||
default:
|
||||
{
|
||||
seek_type = "SEEK_SET";
|
||||
stream->cdrom.byte_pos = offset;
|
||||
lba_to_msf(vfs_cdrom_toc.track[stream->cdrom.cur_track - 1].lba + (stream->cdrom.byte_pos / 2352), &min, &sec, &frame);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
stream->cdrom.cur_min = min;
|
||||
stream->cdrom.cur_sec = sec;
|
||||
stream->cdrom.cur_frame = frame;
|
||||
stream->cdrom.cur_lba = msf_to_lba(min, sec, frame);
|
||||
|
||||
#ifdef CDROM_DEBUG
|
||||
printf("CDROM Seek %s: Path %s Offset %" PRIu64 " is now at %" PRIu64 " (MSF %02d:%02d:%02d) (LBA %u)...\n", seek_type, stream->orig_path, offset, stream->cdrom.byte_pos, stream->cdrom.cur_min, stream->cdrom.cur_sec, stream->cdrom.cur_frame, stream->cdrom.cur_lba);
|
||||
fflush(stdout);
|
||||
#endif
|
||||
}
|
||||
else
|
||||
return -1;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
void retro_vfs_file_open_cdrom(
|
||||
libretro_vfs_implementation_file *stream,
|
||||
const char *path, unsigned mode, unsigned hints)
|
||||
{
|
||||
#ifdef __linux__
|
||||
char model[32] = {0};
|
||||
char cdrom_path[] = "/dev/sg1";
|
||||
size_t path_len = strlen(path);
|
||||
const char *ext = path_get_extension(path);
|
||||
|
||||
stream->cdrom.cur_track = 1;
|
||||
|
||||
if (!string_is_equal_noncase(ext, "cue") && !string_is_equal_noncase(ext, "bin"))
|
||||
return;
|
||||
|
||||
if (path_len >= strlen("drive1-track01.bin"))
|
||||
{
|
||||
if (!memcmp(path, "drive", strlen("drive")))
|
||||
{
|
||||
if (!memcmp(path + 6, "-track", strlen("-track")))
|
||||
{
|
||||
if (sscanf(path + 12, "%02u", (unsigned*)&stream->cdrom.cur_track))
|
||||
{
|
||||
#ifdef CDROM_DEBUG
|
||||
printf("CDROM: Opening track %d\n", stream->cdrom.cur_track);
|
||||
fflush(stdout);
|
||||
#endif
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (path_len >= strlen("drive1.cue"))
|
||||
{
|
||||
if (!memcmp(path, "drive", strlen("drive")))
|
||||
{
|
||||
if (path[5] >= '0' && path[5] <= '9')
|
||||
{
|
||||
cdrom_path[7] = path[5];
|
||||
stream->cdrom.drive = path[5];
|
||||
vfs_cdrom_toc.drive = stream->cdrom.drive;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#ifdef CDROM_DEBUG
|
||||
printf("CDROM Open: Path %s URI %s\n", cdrom_path, path);
|
||||
fflush(stdout);
|
||||
#endif
|
||||
stream->fp = (FILE*)fopen_utf8(cdrom_path, "r+b");
|
||||
|
||||
if (stream->fp)
|
||||
{
|
||||
if (!cdrom_get_inquiry(stream, model, sizeof(model)))
|
||||
{
|
||||
#ifdef CDROM_DEBUG
|
||||
printf("CDROM Model: %s\n", model);
|
||||
fflush(stdout);
|
||||
#endif
|
||||
}
|
||||
}
|
||||
else
|
||||
return;
|
||||
|
||||
if (string_is_equal_noncase(ext, "cue"))
|
||||
{
|
||||
if (stream->cdrom.cue_buf)
|
||||
{
|
||||
free(stream->cdrom.cue_buf);
|
||||
stream->cdrom.cue_buf = NULL;
|
||||
}
|
||||
|
||||
cdrom_write_cue(stream, &stream->cdrom.cue_buf, &stream->cdrom.cue_len, stream->cdrom.drive, &vfs_cdrom_toc.num_tracks, &vfs_cdrom_toc);
|
||||
|
||||
#ifdef CDROM_DEBUG
|
||||
if (string_is_empty(stream->cdrom.cue_buf))
|
||||
{
|
||||
printf("Error writing cue sheet.\n");
|
||||
fflush(stdout);
|
||||
}
|
||||
else
|
||||
{
|
||||
printf("CDROM CUE Sheet:\n%s\n", stream->cdrom.cue_buf);
|
||||
fflush(stdout);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
#endif
|
||||
#ifdef _WIN32
|
||||
char model[32] = {0};
|
||||
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;
|
||||
|
||||
if (path_len >= strlen("d:/drive-track01.bin"))
|
||||
{
|
||||
if (!memcmp(path + 1, ":/drive-track", strlen(":/drive-track")))
|
||||
{
|
||||
if (sscanf(path + 14, "%02u", (unsigned*)&stream->cdrom.cur_track))
|
||||
{
|
||||
#ifdef CDROM_DEBUG
|
||||
printf("CDROM: Opening track %d\n", stream->cdrom.cur_track);
|
||||
fflush(stdout);
|
||||
#endif
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (path_len >= strlen("d:/drive.cue"))
|
||||
{
|
||||
if (!memcmp(path + 1, ":/drive", strlen(":/drive")))
|
||||
{
|
||||
if ((path[0] >= 'A' && path[0] <= 'Z') || (path[0] >= 'a' && path[0] <= 'z'))
|
||||
{
|
||||
cdrom_path[4] = path[0];
|
||||
stream->cdrom.drive = path[0];
|
||||
vfs_cdrom_toc.drive = stream->cdrom.drive;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#ifdef CDROM_DEBUG
|
||||
printf("CDROM Open: Path %s URI %s\n", cdrom_path, path);
|
||||
fflush(stdout);
|
||||
#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;
|
||||
else
|
||||
{
|
||||
if (!cdrom_get_inquiry(stream, model, sizeof(model)))
|
||||
{
|
||||
#ifdef CDROM_DEBUG
|
||||
printf("CDROM Model: %s\n", model);
|
||||
fflush(stdout);
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
if (string_is_equal_noncase(ext, "cue"))
|
||||
{
|
||||
if (stream->cdrom.cue_buf)
|
||||
{
|
||||
free(stream->cdrom.cue_buf);
|
||||
stream->cdrom.cue_buf = NULL;
|
||||
}
|
||||
|
||||
cdrom_write_cue(stream, &stream->cdrom.cue_buf, &stream->cdrom.cue_len, stream->cdrom.drive, &vfs_cdrom_toc.num_tracks, &vfs_cdrom_toc);
|
||||
|
||||
#ifdef CDROM_DEBUG
|
||||
if (string_is_empty(stream->cdrom.cue_buf))
|
||||
{
|
||||
printf("Error writing cue sheet.\n");
|
||||
fflush(stdout);
|
||||
}
|
||||
else
|
||||
{
|
||||
printf("CDROM CUE Sheet:\n%s\n", stream->cdrom.cue_buf);
|
||||
fflush(stdout);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
#endif
|
||||
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;
|
||||
stream->cdrom.cur_lba = msf_to_lba(stream->cdrom.cur_min, stream->cdrom.cur_sec, stream->cdrom.cur_frame);
|
||||
}
|
||||
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;
|
||||
stream->cdrom.cur_lba = msf_to_lba(stream->cdrom.cur_min, stream->cdrom.cur_sec, stream->cdrom.cur_frame);
|
||||
}
|
||||
}
|
||||
|
||||
int retro_vfs_file_close_cdrom(libretro_vfs_implementation_file *stream)
|
||||
{
|
||||
#ifdef CDROM_DEBUG
|
||||
printf("CDROM Close: Path %s\n", stream->orig_path);
|
||||
fflush(stdout);
|
||||
#endif
|
||||
|
||||
#ifdef _WIN32
|
||||
if (!stream->fh || !CloseHandle(stream->fh))
|
||||
return -1;
|
||||
#else
|
||||
if (!stream->fp || fclose(stream->fp))
|
||||
return -1;
|
||||
#endif
|
||||
|
||||
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
|
||||
printf("CDROM (cue) Tell: Path %s Position %" PRIu64 "\n", stream->orig_path, stream->cdrom.byte_pos);
|
||||
fflush(stdout);
|
||||
#endif
|
||||
return stream->cdrom.byte_pos;
|
||||
}
|
||||
else if (string_is_equal_noncase(ext, "bin"))
|
||||
{
|
||||
#ifdef CDROM_DEBUG
|
||||
printf("CDROM (bin) Tell: Path %s Position %" PRId64 "\n", stream->orig_path, stream->cdrom.byte_pos);
|
||||
fflush(stdout);
|
||||
#endif
|
||||
return stream->cdrom.byte_pos;
|
||||
}
|
||||
|
||||
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"))
|
||||
{
|
||||
if (len < stream->cdrom.cue_len - stream->cdrom.byte_pos)
|
||||
{
|
||||
#ifdef CDROM_DEBUG
|
||||
printf("CDROM Read: Reading %" PRIu64 " bytes from cuesheet starting at %" PRIu64 "...\n", len, stream->cdrom.byte_pos);
|
||||
fflush(stdout);
|
||||
#endif
|
||||
memcpy(s, stream->cdrom.cue_buf + stream->cdrom.byte_pos, len);
|
||||
stream->cdrom.byte_pos += len;
|
||||
|
||||
return len;
|
||||
}
|
||||
else
|
||||
{
|
||||
#ifdef CDROM_DEBUG
|
||||
printf("CDROM Read: Reading %" PRIu64 " bytes from cuesheet starting at %" PRIu64 " failed.\n", len, stream->cdrom.byte_pos);
|
||||
fflush(stdout);
|
||||
#endif
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
else if (string_is_equal_noncase(ext, "bin"))
|
||||
{
|
||||
size_t skip = stream->cdrom.byte_pos % 2352;
|
||||
unsigned char min = 0;
|
||||
unsigned char sec = 0;
|
||||
unsigned char frame = 0;
|
||||
|
||||
lba_to_msf(stream->cdrom.cur_lba, &min, &sec, &frame);
|
||||
|
||||
#ifdef CDROM_DEBUG
|
||||
printf("CDROM Read: Reading %" PRIu64 " bytes from %s starting at byte offset %" PRIu64 " (MSF %02d:%02d:%02d) (LBA %u) skip %" PRIu64 "...\n", len, stream->orig_path, stream->cdrom.byte_pos, min, sec, frame, stream->cdrom.cur_lba, skip);
|
||||
fflush(stdout);
|
||||
#endif
|
||||
|
||||
rv = cdrom_read(stream, min, sec, frame, s, (size_t)len, skip);
|
||||
|
||||
if (rv)
|
||||
{
|
||||
#ifdef CDROM_DEBUG
|
||||
printf("Failed to read %" PRIu64 " bytes from CD.\n", len);
|
||||
fflush(stdout);
|
||||
#endif
|
||||
return 0;
|
||||
}
|
||||
|
||||
stream->cdrom.byte_pos += len;
|
||||
stream->cdrom.cur_lba = vfs_cdrom_toc.track[stream->cdrom.cur_track - 1].lba + (stream->cdrom.byte_pos / 2352);
|
||||
lba_to_msf(stream->cdrom.cur_lba, &stream->cdrom.cur_min, &stream->cdrom.cur_sec, &stream->cdrom.cur_frame);
|
||||
|
||||
#ifdef CDROM_DEBUG
|
||||
printf("CDROM read %" PRIu64 " bytes, position is now: %" PRIu64 " (MSF %02d:%02d:%02d) (LBA %u)\n", len, stream->cdrom.byte_pos, stream->cdrom.cur_min, stream->cdrom.cur_sec, stream->cdrom.cur_frame, msf_to_lba(stream->cdrom.cur_min, stream->cdrom.cur_sec, stream->cdrom.cur_frame));
|
||||
fflush(stdout);
|
||||
#endif
|
||||
|
||||
return len;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int retro_vfs_file_error_cdrom(libretro_vfs_implementation_file *stream)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
const vfs_cdrom_t* retro_vfs_file_get_cdrom_position(const libretro_vfs_implementation_file *stream)
|
||||
{
|
||||
return &stream->cdrom;
|
||||
}
|
1
paths.c
1
paths.c
@ -1,6 +1,7 @@
|
||||
/* RetroArch - A frontend for libretro.
|
||||
* Copyright (C) 2011-2019 - Daniel De Matteis
|
||||
* Copyright (C) 2017-2019 - Andrés Suárez
|
||||
* Copyright (C) 2016-2019 - Brad Parker
|
||||
*
|
||||
* RetroArch is free software: you can redistribute it and/or modify it under the terms
|
||||
* of the GNU General Public License as published by the Free Software Found-
|
||||
|
1
paths.h
1
paths.h
@ -1,5 +1,6 @@
|
||||
/* RetroArch - A frontend for libretro.
|
||||
* Copyright (C) 2011-2019 - Daniel De Matteis
|
||||
* Copyright (C) 2016-2019 - Brad Parker
|
||||
*
|
||||
* RetroArch is free software: you can redistribute it and/or modify it under the terms
|
||||
* of the GNU General Public License as published by the Free Software Found-
|
||||
|
@ -1,6 +1,7 @@
|
||||
/* RetroArch - A frontend for libretro.
|
||||
* Copyright (C) 2010-2014 - Hans-Kristian Arntzen
|
||||
* Copyright (C) 2011-2017 - Daniel De Matteis
|
||||
* Copyright (C) 2016-2019 - Brad Parker
|
||||
*
|
||||
* RetroArch is free software: you can redistribute it and/or modify it under the terms
|
||||
* of the GNU General Public License as published by the Free Software Found-
|
||||
|
@ -1,5 +1,6 @@
|
||||
/* RetroArch - A frontend for libretro.
|
||||
* Copyright (C) 2011-2017 - Daniel De Matteis
|
||||
* Copyright (C) 2016-2019 - Brad Parker
|
||||
*
|
||||
* RetroArch is free software: you can redistribute it and/or modify it under the terms
|
||||
* of the GNU General Public License as published by the Free Software Found-
|
||||
|
Loading…
x
Reference in New Issue
Block a user