Merge pull request #119 from bparker06/cdrom_fast

initial cdrom support (master branch)
This commit is contained in:
Twinaphex 2019-07-26 04:22:37 +02:00 committed by GitHub
commit 49001078e8
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
48 changed files with 7642 additions and 523 deletions

View File

@ -14,15 +14,15 @@ unixcygpath = /$(subst :,,$(call unixpath,$1))
ifeq ($(platform),) ifeq ($(platform),)
platform = unix platform = unix
ifeq ($(shell uname -a),) ifeq ($(shell uname -s),)
platform = win platform = win
else ifneq ($(findstring Darwin,$(shell uname -a)),) else ifneq ($(findstring Darwin,$(shell uname -s)),)
platform = osx platform = osx
arch = intel arch = intel
ifeq ($(shell uname -p),powerpc) ifeq ($(shell uname -p),powerpc)
arch = ppc arch = ppc
endif endif
else ifneq ($(findstring MINGW,$(shell uname -a)),) else ifneq ($(findstring MINGW,$(shell uname -s)),)
platform = win platform = win
endif endif
else ifneq (,$(findstring armv,$(platform))) else ifneq (,$(findstring armv,$(platform)))
@ -46,6 +46,7 @@ NEED_CRC32 = 1
WANT_NEW_API = 1 WANT_NEW_API = 1
CORE_DEFINE := -DWANT_PCE_FAST_EMU -DWANT_STEREO_SOUND CORE_DEFINE := -DWANT_PCE_FAST_EMU -DWANT_STEREO_SOUND
HAVE_CHD = 1 HAVE_CHD = 1
HAVE_CDROM = 0
prefix := /usr prefix := /usr
libdir := $(prefix)/lib libdir := $(prefix)/lib
@ -76,6 +77,10 @@ ifneq (,$(findstring unix,$(platform)))
LDFLAGS += -lrt LDFLAGS += -lrt
endif endif
ifneq ($(findstring Linux,$(shell uname -s)),)
HAVE_CDROM = 1
endif
# Raspberry Pi # Raspberry Pi
ifneq (,$(findstring rpi,$(platform))) ifneq (,$(findstring rpi,$(platform)))
FLAGS += -fomit-frame-pointer -ffast-math FLAGS += -fomit-frame-pointer -ffast-math
@ -357,6 +362,8 @@ else ifneq (,$(findstring windows_msvc2017,$(platform)))
VCCompilerToolsBinDir := $(VcCompilerToolsDir)\bin\HostX86 VCCompilerToolsBinDir := $(VcCompilerToolsDir)\bin\HostX86
endif endif
HAVE_CDROM = 1
PATH := $(shell IFS=$$'\n'; cygpath "$(VCCompilerToolsBinDir)/$(TargetArchMoniker)"):$(PATH) PATH := $(shell IFS=$$'\n'; cygpath "$(VCCompilerToolsBinDir)/$(TargetArchMoniker)"):$(PATH)
PATH := $(PATH):$(shell IFS=$$'\n'; cygpath "$(VsInstallRoot)/Common7/IDE") PATH := $(PATH):$(shell IFS=$$'\n'; cygpath "$(VsInstallRoot)/Common7/IDE")
INCLUDE := $(shell IFS=$$'\n'; cygpath -w "$(VcCompilerToolsDir)/include") INCLUDE := $(shell IFS=$$'\n'; cygpath -w "$(VcCompilerToolsDir)/include")
@ -388,6 +395,7 @@ WindowsSdkDir ?= $(shell reg query "HKLM\SOFTWARE\Microsoft\Microsoft SDKs\Windo
WindowsSdkDirInc := $(shell reg query "HKLM\SOFTWARE\Microsoft\Microsoft SDKs\Windows\v7.0A" -v "InstallationFolder" | grep -o '[A-Z]:\\.*')Include WindowsSdkDirInc := $(shell reg query "HKLM\SOFTWARE\Microsoft\Microsoft SDKs\Windows\v7.0A" -v "InstallationFolder" | grep -o '[A-Z]:\\.*')Include
WindowsSdkDirInc ?= $(shell reg query "HKLM\SOFTWARE\Microsoft\Microsoft SDKs\Windows\v7.1A" -v "InstallationFolder" | grep -o '[A-Z]:\\.*')Include WindowsSdkDirInc ?= $(shell reg query "HKLM\SOFTWARE\Microsoft\Microsoft SDKs\Windows\v7.1A" -v "InstallationFolder" | grep -o '[A-Z]:\\.*')Include
HAVE_CDROM = 1
INCFLAGS_PLATFORM = -I"$(WindowsSdkDirInc)" INCFLAGS_PLATFORM = -I"$(WindowsSdkDirInc)"
export INCLUDE := $(INCLUDE) export INCLUDE := $(INCLUDE)
@ -413,6 +421,7 @@ WindowsSdkDir ?= $(shell reg query "HKLM\SOFTWARE\Microsoft\Microsoft SDKs\Windo
WindowsSdkDirInc := $(shell reg query "HKLM\SOFTWARE\Microsoft\Microsoft SDKs\Windows\v7.0A" -v "InstallationFolder" | grep -o '[A-Z]:\\.*')Include WindowsSdkDirInc := $(shell reg query "HKLM\SOFTWARE\Microsoft\Microsoft SDKs\Windows\v7.0A" -v "InstallationFolder" | grep -o '[A-Z]:\\.*')Include
WindowsSdkDirInc ?= $(shell reg query "HKLM\SOFTWARE\Microsoft\Microsoft SDKs\Windows\v7.1A" -v "InstallationFolder" | grep -o '[A-Z]:\\.*')Include WindowsSdkDirInc ?= $(shell reg query "HKLM\SOFTWARE\Microsoft\Microsoft SDKs\Windows\v7.1A" -v "InstallationFolder" | grep -o '[A-Z]:\\.*')Include
HAVE_CDROM = 1
INCFLAGS_PLATFORM = -I"$(WindowsSdkDirInc)" INCFLAGS_PLATFORM = -I"$(WindowsSdkDirInc)"
export INCLUDE := $(INCLUDE) export INCLUDE := $(INCLUDE)
@ -435,6 +444,8 @@ BIN := $(shell IFS=$$'\n'; cygpath "$(VS80COMNTOOLS)../../VC/bin")
WindowsSdkDir := $(INETSDK) WindowsSdkDir := $(INETSDK)
HAVE_CDROM = 1
export INCLUDE := $(INCLUDE);$(INETSDK)/Include;libretro-common/include/compat/msvc export INCLUDE := $(INCLUDE);$(INETSDK)/Include;libretro-common/include/compat/msvc
export LIB := $(LIB);$(WindowsSdkDir);$(INETSDK)/Lib export LIB := $(LIB);$(WindowsSdkDir);$(INETSDK)/Lib
TARGET := $(TARGET_NAME)_libretro.dll TARGET := $(TARGET_NAME)_libretro.dll
@ -465,6 +476,7 @@ else ifeq ($(platform), windows_msvc2003_x86)
CC = cl.exe CC = cl.exe
CXX = cl.exe CXX = cl.exe
HAVE_CDROM = 1
PATH := $(shell IFS=$$'\n'; cygpath "$(VS71COMNTOOLS)../../Vc7/bin"):$(PATH) PATH := $(shell IFS=$$'\n'; cygpath "$(VS71COMNTOOLS)../../Vc7/bin"):$(PATH)
PATH := $(PATH):$(shell IFS=$$'\n'; cygpath "$(VS71COMNTOOLS)../IDE") PATH := $(PATH):$(shell IFS=$$'\n'; cygpath "$(VS71COMNTOOLS)../IDE")
INCLUDE := $(shell IFS=$$'\n'; cygpath "$(VS71COMNTOOLS)../../Vc7/include") INCLUDE := $(shell IFS=$$'\n'; cygpath "$(VS71COMNTOOLS)../../Vc7/include")
@ -488,6 +500,7 @@ else
CXX = g++ CXX = g++
SHARED := -shared -Wl,--no-undefined -Wl,--version-script=link.T SHARED := -shared -Wl,--no-undefined -Wl,--version-script=link.T
LDFLAGS += -static-libgcc -static-libstdc++ -lwinmm LDFLAGS += -static-libgcc -static-libstdc++ -lwinmm
HAVE_CDROM = 1
WINDOWS_VERSION=1 WINDOWS_VERSION=1
endif endif
@ -550,6 +563,13 @@ ifeq ($(WANT_NEW_API), 1)
FLAGS += -DWANT_NEW_API FLAGS += -DWANT_NEW_API
endif endif
ifeq ($(HAVE_CDROM), 1)
FLAGS += -DHAVE_CDROM
ifeq ($(CDROM_DEBUG), 1)
FLAGS += -DCDROM_DEBUG
endif
endif
CXXFLAGS += $(FLAGS) CXXFLAGS += $(FLAGS)
CFLAGS += $(FLAGS) CFLAGS += $(FLAGS)

View File

@ -20,6 +20,12 @@ ifneq (,$(findstring msvc2003,$(platform)))
INCFLAGS += -I$(LIBRETRO_COMM_DIR)/include/compat/msvc INCFLAGS += -I$(LIBRETRO_COMM_DIR)/include/compat/msvc
endif endif
ifeq ($(HAVE_CDROM), 1)
SOURCES_C += \
$(LIBRETRO_COMM_DIR)/cdrom/cdrom.c \
$(LIBRETRO_COMM_DIR)/vfs/vfs_implementation_cdrom.c
endif
ifneq ($(HAVE_GRIFFIN),1) ifneq ($(HAVE_GRIFFIN),1)
SOURCES_CXX += \ SOURCES_CXX += \
$(CORE_EMU_DIR)/huc6280.cpp \ $(CORE_EMU_DIR)/huc6280.cpp \
@ -196,6 +202,10 @@ endif
ifneq ($(STATIC_LINKING), 1) ifneq ($(STATIC_LINKING), 1)
SOURCES_C += $(LIBRETRO_COMM_DIR)/streams/file_stream.c \ SOURCES_C += $(LIBRETRO_COMM_DIR)/streams/file_stream.c \
$(LIBRETRO_COMM_DIR)/streams/file_stream_transforms.c \ $(LIBRETRO_COMM_DIR)/streams/file_stream_transforms.c \
$(LIBRETRO_COMM_DIR)/file/file_path.c \
$(LIBRETRO_COMM_DIR)/file/retro_dirent.c \
$(LIBRETRO_COMM_DIR)/lists/string_list.c \
$(LIBRETRO_COMM_DIR)/lists/dir_list.c \
$(LIBRETRO_COMM_DIR)/compat/compat_strl.c \ $(LIBRETRO_COMM_DIR)/compat/compat_strl.c \
$(LIBRETRO_COMM_DIR)/compat/compat_snprintf.c \ $(LIBRETRO_COMM_DIR)/compat/compat_snprintf.c \
$(LIBRETRO_COMM_DIR)/compat/compat_posix_string.c \ $(LIBRETRO_COMM_DIR)/compat/compat_posix_string.c \
@ -204,5 +214,6 @@ SOURCES_C += $(LIBRETRO_COMM_DIR)/streams/file_stream.c \
$(LIBRETRO_COMM_DIR)/encodings/encoding_utf.c \ $(LIBRETRO_COMM_DIR)/encodings/encoding_utf.c \
$(LIBRETRO_COMM_DIR)/encodings/encoding_crc32.c \ $(LIBRETRO_COMM_DIR)/encodings/encoding_crc32.c \
$(LIBRETRO_COMM_DIR)/vfs/vfs_implementation.c \ $(LIBRETRO_COMM_DIR)/vfs/vfs_implementation.c \
$(LIBRETRO_COMM_DIR)/memmap/memalign.c \
$(LIBRETRO_COMM_DIR)/string/stdstring.c $(LIBRETRO_COMM_DIR)/string/stdstring.c
endif endif

File diff suppressed because it is too large Load Diff

View File

@ -23,10 +23,7 @@
/* THIS FILE HAS NOT BEEN VALIDATED ON PLATFORMS BESIDES MSVC */ /* THIS FILE HAS NOT BEEN VALIDATED ON PLATFORMS BESIDES MSVC */
#ifdef _MSC_VER #ifdef _MSC_VER
#include <retro_common.h> #include <stdio.h>
#if _MSC_VER >= 1800
#include <stdio.h> /* added for _vsnprintf_s and _vscprintf on VS2015 and VS2017 */
#endif
#include <stdarg.h> #include <stdarg.h>
#if _MSC_VER < 1800 #if _MSC_VER < 1800
@ -54,11 +51,14 @@ int c99_vsnprintf_retro__(char *outBuf, size_t size, const char *format, va_list
int count = -1; int count = -1;
if (size != 0) if (size != 0)
{
#if (_MSC_VER <= 1310) #if (_MSC_VER <= 1310)
count = _vsnprintf(outBuf, size - 1, format, ap); count = _vsnprintf(outBuf, size - 1, format, ap);
#else #else
count = _vsnprintf_s(outBuf, size, size - 1, format, ap); count = _vsnprintf_s(outBuf, size, size - 1, format, ap);
#endif #endif
}
if (count == -1) if (count == -1)
count = _vscprintf(format, ap); count = _vscprintf(format, ap);

View File

@ -36,9 +36,7 @@
void *fopen_utf8(const char * filename, const char * mode) void *fopen_utf8(const char * filename, const char * mode)
{ {
#if defined(_XBOX) #if defined(LEGACY_WIN32)
return fopen(filename, mode);
#elif defined(LEGACY_WIN32)
FILE *ret = NULL; FILE *ret = NULL;
char * filename_local = utf8_to_local_string_alloc(filename); char * filename_local = utf8_to_local_string_alloc(filename);

View File

@ -23,6 +23,8 @@
#include <stdint.h> #include <stdint.h>
#include <stddef.h> #include <stddef.h>
#include <encodings/crc32.h> #include <encodings/crc32.h>
#include <streams/file_stream.h>
#include <stdlib.h>
static const uint32_t crc32_table[256] = { static const uint32_t crc32_table[256] = {
0x00000000L, 0x77073096L, 0xee0e612cL, 0x990951baL, 0x076dc419L, 0x00000000L, 0x77073096L, 0xee0e612cL, 0x990951baL, 0x076dc419L,
@ -88,3 +90,51 @@ uint32_t encoding_crc32(uint32_t crc, const uint8_t *buf, size_t len)
return crc ^ 0xffffffff; return crc ^ 0xffffffff;
} }
#define CRC32_BUFFER_SIZE 1048576
#define CRC32_MAX_MB 64
/**
* Calculate a CRC32 from the first part of the given file.
* "first part" being the first (CRC32_BUFFER_SIZE * CRC32_MAX_MB)
* bytes.
*
* Returns: the crc32, or 0 if there was an error.
*/
uint32_t file_crc32(uint32_t crc, const char *path)
{
unsigned i;
RFILE *file = NULL;
unsigned char *buf = NULL;
if (!path)
return 0;
file = filestream_open(path, RETRO_VFS_FILE_ACCESS_READ, 0);
if (!file)
goto error;
buf = (unsigned char*)malloc(CRC32_BUFFER_SIZE);
if (!buf)
goto error;
for(i = 0; i < CRC32_MAX_MB; i++)
{
int64_t nread = filestream_read(file, buf, CRC32_BUFFER_SIZE);
if (nread < 0)
goto error;
crc = encoding_crc32(crc, buf, (size_t)nread);
if (filestream_eof(file))
break;
}
free(buf);
filestream_close(file);
return crc;
error:
if (buf)
free(buf);
if (file)
filestream_close(file);
return 0;
}

View File

@ -211,10 +211,7 @@ size_t utf8len(const char *string)
return ret; return ret;
} }
static uint8_t utf8_walkbyte(const char **string) #define utf8_walkbyte(string) (*((*(string))++))
{
return *((*string)++);
}
/* Does not validate the input, returns garbage if it's not UTF-8. */ /* Does not validate the input, returns garbage if it's not UTF-8. */
uint32_t utf8_walk(const char **string) uint32_t utf8_walk(const char **string)
@ -227,14 +224,16 @@ uint32_t utf8_walk(const char **string)
ret = (ret << 6) | (utf8_walkbyte(string) & 0x3F); ret = (ret << 6) | (utf8_walkbyte(string) & 0x3F);
if (first >= 0xE0) if (first >= 0xE0)
{
ret = (ret << 6) | (utf8_walkbyte(string) & 0x3F); ret = (ret << 6) | (utf8_walkbyte(string) & 0x3F);
if (first >= 0xF0) if (first >= 0xF0)
ret = (ret << 6) | (utf8_walkbyte(string) & 0x3F); {
ret = (ret << 6) | (utf8_walkbyte(string) & 0x3F);
if (first >= 0xF0) return ret | (first & 7) << 18;
return ret | (first & 7) << 18; }
if (first >= 0xE0)
return ret | (first & 15) << 12; return ret | (first & 15) << 12;
}
return ret | (first & 31) << 6; return ret | (first & 31) << 6;
} }
@ -273,37 +272,25 @@ bool utf16_to_char_string(const uint16_t *in, char *s, size_t len)
return ret; return ret;
} }
#if defined(_WIN32) && !defined(_XBOX) && !defined(UNICODE)
/* Returned pointer MUST be freed by the caller if non-NULL. */ /* Returned pointer MUST be freed by the caller if non-NULL. */
static char* mb_to_mb_string_alloc(const char *str, static char *mb_to_mb_string_alloc(const char *str,
enum CodePage cp_in, enum CodePage cp_out) enum CodePage cp_in, enum CodePage cp_out)
{ {
char *path_buf = NULL; char *path_buf = NULL;
wchar_t *path_buf_wide = NULL; wchar_t *path_buf_wide = NULL;
int path_buf_len = 0; int path_buf_len = 0;
int path_buf_wide_len = 0; int path_buf_wide_len = MultiByteToWideChar(cp_in, 0, str, -1, NULL, 0);
if (!str || !*str) /* Windows 95 will return 0 from these functions with
return NULL; * a UTF8 codepage set without MSLU.
*
(void)path_buf; * From an unknown MSDN version (others omit this info):
(void)path_buf_wide; * - CP_UTF8 Windows 98/Me, Windows NT 4.0 and later:
(void)path_buf_len; * Translate using UTF-8. When this is set, dwFlags must be zero.
(void)path_buf_wide_len; * - Windows 95: Under the Microsoft Layer for Unicode,
* MultiByteToWideChar also supports CP_UTF7 and CP_UTF8.
#if !defined(_WIN32) || defined(_XBOX)
/* assume string needs no modification if not on Windows */
return strdup(str);
#else
#ifdef UNICODE
/* TODO/FIXME: Not implemented. */
return strdup(str);
#else
/* Windows 95 will return 0 from these functions with a UTF8 codepage set without MSLU. From an unknown MSDN version (others omit this info):
* - CP_UTF8 Windows 98/Me, Windows NT 4.0 and later: Translate using UTF-8. When this is set, dwFlags must be zero.
* - Windows 95: Under the Microsoft Layer for Unicode, MultiByteToWideChar also supports CP_UTF7 and CP_UTF8.
*/ */
path_buf_wide_len = MultiByteToWideChar(cp_in, 0, str, -1, NULL, 0);
if (path_buf_wide_len) if (path_buf_wide_len)
{ {
@ -355,20 +342,37 @@ static char* mb_to_mb_string_alloc(const char *str,
free(path_buf_wide); free(path_buf_wide);
return NULL; return NULL;
#endif
#endif
} }
#endif
/* Returned pointer MUST be freed by the caller if non-NULL. */ /* Returned pointer MUST be freed by the caller if non-NULL. */
char* utf8_to_local_string_alloc(const char *str) char* utf8_to_local_string_alloc(const char *str)
{ {
return mb_to_mb_string_alloc(str, CODEPAGE_UTF8, CODEPAGE_LOCAL); if (str && *str)
{
#if defined(_WIN32) && !defined(_XBOX) && !defined(UNICODE)
return mb_to_mb_string_alloc(str, CODEPAGE_UTF8, CODEPAGE_LOCAL);
#else
/* assume string needs no modification if not on Windows */
return strdup(str);
#endif
}
return NULL;
} }
/* Returned pointer MUST be freed by the caller if non-NULL. */ /* Returned pointer MUST be freed by the caller if non-NULL. */
char* local_to_utf8_string_alloc(const char *str) char* local_to_utf8_string_alloc(const char *str)
{ {
return mb_to_mb_string_alloc(str, CODEPAGE_LOCAL, CODEPAGE_UTF8); if (str && *str)
{
#if defined(_WIN32) && !defined(_XBOX) && !defined(UNICODE)
return mb_to_mb_string_alloc(str, CODEPAGE_LOCAL, CODEPAGE_UTF8);
#else
/* assume string needs no modification if not on Windows */
return strdup(str);
#endif
}
return NULL;
} }
/* Returned pointer MUST be freed by the caller if non-NULL. */ /* Returned pointer MUST be freed by the caller if non-NULL. */
@ -447,52 +451,44 @@ wchar_t* utf8_to_utf16_string_alloc(const char *str)
char* utf16_to_utf8_string_alloc(const wchar_t *str) char* utf16_to_utf8_string_alloc(const wchar_t *str)
{ {
#ifdef _WIN32 #ifdef _WIN32
int len = 0; int len = 0;
int out_len = 0;
#else #else
size_t len = 0; size_t len = 0;
size_t out_len = 0;
#endif #endif
char *buf = NULL; char *buf = NULL;
if (!str || !*str) if (!str || !*str)
return NULL; return NULL;
#ifdef _WIN32 #ifdef _WIN32
len = WideCharToMultiByte(CP_UTF8, 0, str, -1, NULL, 0, NULL, NULL);
if (len)
{ {
UINT code_page = CP_UTF8;
len = WideCharToMultiByte(code_page,
0, str, -1, NULL, 0, NULL, NULL);
/* fallback to ANSI codepage instead */
if (!len)
{
code_page = CP_ACP;
len = WideCharToMultiByte(code_page,
0, str, -1, NULL, 0, NULL, NULL);
}
buf = (char*)calloc(len, sizeof(char)); buf = (char*)calloc(len, sizeof(char));
if (!buf) if (!buf)
return NULL; return NULL;
out_len = WideCharToMultiByte(CP_UTF8, 0, str, -1, buf, len, NULL, NULL); if (WideCharToMultiByte(code_page,
} 0, str, -1, buf, len, NULL, NULL) < 0)
else
{
/* fallback to ANSI codepage instead */
len = WideCharToMultiByte(CP_ACP, 0, str, -1, NULL, 0, NULL, NULL);
if (len)
{ {
buf = (char*)calloc(len, sizeof(char)); free(buf);
return NULL;
if (!buf)
return NULL;
out_len = WideCharToMultiByte(CP_ACP, 0, str, -1, buf, len, NULL, NULL);
} }
} }
if (out_len < 0)
{
free(buf);
return NULL;
}
#else #else
/* NOTE: For now, assume non-Windows platforms' locale is already UTF-8. */ /* NOTE: For now, assume non-Windows platforms'
* locale is already UTF-8. */
len = wcstombs(NULL, str, 0) + 1; len = wcstombs(NULL, str, 0) + 1;
if (len) if (len)
@ -502,13 +498,11 @@ char* utf16_to_utf8_string_alloc(const wchar_t *str)
if (!buf) if (!buf)
return NULL; return NULL;
out_len = wcstombs(buf, str, len); if (wcstombs(buf, str, len) == (size_t)-1)
} {
free(buf);
if (out_len == (size_t)-1) return NULL;
{ }
free(buf);
return NULL;
} }
#endif #endif

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,118 @@
/* Copyright (C) 2010-2019 The RetroArch team
*
* ---------------------------------------------------------------------------------------
* The following license statement only applies to this file (retro_dirent.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 <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <retro_common.h>
#include <boolean.h>
#include <retro_dirent.h>
#define VFS_FRONTEND
#include <vfs/vfs_implementation.h>
static retro_vfs_opendir_t dirent_opendir_cb = NULL;
static retro_vfs_readdir_t dirent_readdir_cb = NULL;
static retro_vfs_dirent_get_name_t dirent_dirent_get_name_cb = NULL;
static retro_vfs_dirent_is_dir_t dirent_dirent_is_dir_cb = NULL;
static retro_vfs_closedir_t dirent_closedir_cb = NULL;
void dirent_vfs_init(const struct retro_vfs_interface_info* vfs_info)
{
const struct retro_vfs_interface* vfs_iface;
dirent_opendir_cb = NULL;
dirent_readdir_cb = NULL;
dirent_dirent_get_name_cb = NULL;
dirent_dirent_is_dir_cb = NULL;
dirent_closedir_cb = NULL;
vfs_iface = vfs_info->iface;
if (vfs_info->required_interface_version < DIRENT_REQUIRED_VFS_VERSION || !vfs_iface)
return;
dirent_opendir_cb = vfs_iface->opendir;
dirent_readdir_cb = vfs_iface->readdir;
dirent_dirent_get_name_cb = vfs_iface->dirent_get_name;
dirent_dirent_is_dir_cb = vfs_iface->dirent_is_dir;
dirent_closedir_cb = vfs_iface->closedir;
}
struct RDIR *retro_opendir_include_hidden(const char *name, bool include_hidden)
{
if (dirent_opendir_cb != NULL)
return (struct RDIR *)dirent_opendir_cb(name, include_hidden);
return (struct RDIR *)retro_vfs_opendir_impl(name, include_hidden);
}
struct RDIR *retro_opendir(const char *name)
{
return retro_opendir_include_hidden(name, false);
}
bool retro_dirent_error(struct RDIR *rdir)
{
/* Left for compatibility */
return false;
}
int retro_readdir(struct RDIR *rdir)
{
if (dirent_readdir_cb != NULL)
return dirent_readdir_cb((struct retro_vfs_dir_handle *)rdir);
return retro_vfs_readdir_impl((struct retro_vfs_dir_handle *)rdir);
}
const char *retro_dirent_get_name(struct RDIR *rdir)
{
if (dirent_dirent_get_name_cb != NULL)
return dirent_dirent_get_name_cb((struct retro_vfs_dir_handle *)rdir);
return retro_vfs_dirent_get_name_impl((struct retro_vfs_dir_handle *)rdir);
}
/**
*
* retro_dirent_is_dir:
* @rdir : pointer to the directory entry.
* @unused : deprecated, included for compatibility reasons, pass NULL
*
* Is the directory listing entry a directory?
*
* Returns: true if directory listing entry is
* a directory, false if not.
*/
bool retro_dirent_is_dir(struct RDIR *rdir, const char *unused)
{
if (dirent_dirent_is_dir_cb != NULL)
return dirent_dirent_is_dir_cb((struct retro_vfs_dir_handle *)rdir);
return retro_vfs_dirent_is_dir_impl((struct retro_vfs_dir_handle *)rdir);
}
void retro_closedir(struct RDIR *rdir)
{
if (dirent_closedir_cb != NULL)
dirent_closedir_cb((struct retro_vfs_dir_handle *)rdir);
else
retro_vfs_closedir_impl((struct retro_vfs_dir_handle *)rdir);
}

View File

@ -0,0 +1,125 @@
/* 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 <vfs/vfs.h>
#include <libretro.h>
#include <retro_common_api.h>
#include <retro_inline.h>
#include <boolean.h>
struct string_list;
RETRO_BEGIN_DECLS
typedef struct
{
unsigned short g1_timeout;
unsigned short g2_timeout;
unsigned short g3_timeout;
} cdrom_group_timeouts_t;
typedef struct
{
unsigned lba_start; /* start of pregap */
unsigned lba; /* start of data */
unsigned track_size; /* in LBAs */
unsigned track_bytes;
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_group_timeouts_t timeouts;
cdrom_track_t track[99];
} cdrom_toc_t;
void cdrom_lba_to_msf(unsigned lba, unsigned char *min, unsigned char *sec, unsigned char *frame);
unsigned cdrom_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, bool *is_cdrom);
int cdrom_read(libretro_vfs_implementation_file *stream, cdrom_group_timeouts_t *timeouts, 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);
int cdrom_stop(libretro_vfs_implementation_file *stream);
int cdrom_unlock(libretro_vfs_implementation_file *stream);
int cdrom_open_tray(libretro_vfs_implementation_file *stream);
int cdrom_close_tray(libretro_vfs_implementation_file *stream);
/* must be freed by the caller */
struct string_list* cdrom_get_available_drives(void);
bool cdrom_is_media_inserted(libretro_vfs_implementation_file *stream);
bool cdrom_drive_has_media(const char drive);
void cdrom_get_current_config_core(libretro_vfs_implementation_file *stream);
void cdrom_get_current_config_profiles(libretro_vfs_implementation_file *stream);
void cdrom_get_current_config_cdread(libretro_vfs_implementation_file *stream);
void cdrom_get_current_config_multiread(libretro_vfs_implementation_file *stream);
void cdrom_get_current_config_random_readable(libretro_vfs_implementation_file *stream);
int cdrom_get_sense(libretro_vfs_implementation_file *stream, unsigned char *sense, size_t len);
bool cdrom_set_read_cache(libretro_vfs_implementation_file *stream, bool enabled);
bool cdrom_get_timeouts(libretro_vfs_implementation_file *stream, cdrom_group_timeouts_t *timeouts);
bool cdrom_has_atip(libretro_vfs_implementation_file *stream);
void cdrom_device_fillpath(char *path, size_t len, char drive, unsigned char track, bool is_cue);
RETRO_END_DECLS
#endif

View File

@ -72,4 +72,3 @@ RETRO_END_DECLS
/* pragma once */ /* pragma once */
#endif #endif

View File

@ -41,7 +41,7 @@ RETRO_BEGIN_DECLS
/* Count Leading Zero, unsigned 16bit input value */ /* Count Leading Zero, unsigned 16bit input value */
static INLINE unsigned compat_clz_u16(uint16_t val) static INLINE unsigned compat_clz_u16(uint16_t val)
{ {
#ifdef __GNUC__ #if defined(__GNUC__) && !defined(PS2)
return __builtin_clz(val << 16 | 0x8000); return __builtin_clz(val << 16 | 0x8000);
#else #else
unsigned ret = 0; unsigned ret = 0;
@ -61,7 +61,7 @@ static INLINE int compat_ctz(unsigned x)
{ {
#if defined(__GNUC__) && !defined(RARCH_CONSOLE) #if defined(__GNUC__) && !defined(RARCH_CONSOLE)
return __builtin_ctz(x); return __builtin_ctz(x);
#elif _MSC_VER >= 1400 && !defined(_XBOX) #elif _MSC_VER >= 1400 && !defined(_XBOX) && !defined(__WINRT__)
unsigned long r = 0; unsigned long r = 0;
_BitScanReverse((unsigned long*)&r, x); _BitScanReverse((unsigned long*)&r, x);
return (int)r; return (int)r;

View File

@ -39,8 +39,8 @@ extern "C" {
int c99_snprintf_retro__(char *outBuf, size_t size, const char *format, ...); int c99_snprintf_retro__(char *outBuf, size_t size, const char *format, ...);
#endif #endif
/* Pre-MSVC 2010 compilers don't implement vsnprintf in a cross-platform manner? Not sure about this one. */ /* Pre-MSVC 2008 compilers don't implement vsnprintf in a cross-platform manner? Not sure about this one. */
#if _MSC_VER < 1600 #if _MSC_VER < 1500
#include <stdarg.h> #include <stdarg.h>
#include <stdlib.h> #include <stdlib.h>
#ifndef vsnprintf #ifndef vsnprintf
@ -56,6 +56,8 @@ extern "C" {
#undef UNICODE /* Do not bother with UNICODE at this time. */ #undef UNICODE /* Do not bother with UNICODE at this time. */
#include <direct.h> #include <direct.h>
#include <stddef.h> #include <stddef.h>
#define _USE_MATH_DEFINES
#include <math.h> #include <math.h>
/* Python headers defines ssize_t and sets HAVE_SSIZE_T. /* Python headers defines ssize_t and sets HAVE_SSIZE_T.
@ -125,4 +127,3 @@ typedef int ssize_t;
#endif #endif
#endif #endif

View File

@ -67,7 +67,6 @@ extern "C" {
# endif # endif
#endif #endif
/* 7.18.1 Integer types. */ /* 7.18.1 Integer types. */
/* 7.18.1.1 Exact-width integer types. */ /* 7.18.1.1 Exact-width integer types. */
@ -94,7 +93,6 @@ extern "C" {
typedef signed __int64 int64_t; typedef signed __int64 int64_t;
typedef unsigned __int64 uint64_t; typedef unsigned __int64 uint64_t;
/* 7.18.1.2 Minimum-width integer types. */ /* 7.18.1.2 Minimum-width integer types. */
typedef int8_t int_least8_t; typedef int8_t int_least8_t;
typedef int16_t int_least16_t; typedef int16_t int_least16_t;
@ -255,4 +253,3 @@ typedef uint64_t uintmax_t;
#endif #endif
#endif #endif

View File

@ -29,6 +29,10 @@
#include <compat/msvc.h> #include <compat/msvc.h>
#endif #endif
#if defined(PS2)
#include <compat_ctype.h>
#endif
RETRO_BEGIN_DECLS RETRO_BEGIN_DECLS
#ifdef _WIN32 #ifdef _WIN32
@ -55,7 +59,6 @@ int isblank(int c);
#endif #endif
RETRO_END_DECLS RETRO_END_DECLS
#endif #endif

View File

@ -25,6 +25,10 @@
#include <string.h> #include <string.h>
#if defined(PS2)
#include <compat_ctype.h>
#endif
#if defined(RARCH_INTERNAL) && defined(HAVE_CONFIG_H) #if defined(RARCH_INTERNAL) && defined(HAVE_CONFIG_H)
#include "../../../config.h" #include "../../../config.h"
#endif #endif
@ -46,4 +50,3 @@ RETRO_END_DECLS
#endif #endif
#endif #endif

View File

@ -57,4 +57,3 @@ char *strldup(const char *s, size_t n);
RETRO_END_DECLS RETRO_END_DECLS
#endif #endif

View File

@ -31,6 +31,7 @@
RETRO_BEGIN_DECLS RETRO_BEGIN_DECLS
uint32_t encoding_crc32(uint32_t crc, const uint8_t *buf, size_t len); uint32_t encoding_crc32(uint32_t crc, const uint8_t *buf, size_t len);
uint32_t file_crc32(uint32_t crc, const char *path);
RETRO_END_DECLS RETRO_END_DECLS

View File

@ -0,0 +1,531 @@
/* Copyright (C) 2010-2019 The RetroArch team
*
* ---------------------------------------------------------------------------------------
* The following license statement only applies to this file (file_path.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_FILE_PATH_H
#define __LIBRETRO_SDK_FILE_PATH_H
#include <stdio.h>
#include <stdint.h>
#include <stddef.h>
#include <sys/types.h>
#include <libretro.h>
#include <retro_common_api.h>
#include <boolean.h>
RETRO_BEGIN_DECLS
#define PATH_REQUIRED_VFS_VERSION 3
void path_vfs_init(const struct retro_vfs_interface_info* vfs_info);
/* Order in this enum is equivalent to negative sort order in filelist
* (i.e. DIRECTORY is on top of PLAIN_FILE) */
enum
{
RARCH_FILETYPE_UNSET,
RARCH_PLAIN_FILE,
RARCH_COMPRESSED_FILE_IN_ARCHIVE,
RARCH_COMPRESSED_ARCHIVE,
RARCH_DIRECTORY,
RARCH_FILE_UNSUPPORTED
};
/**
* path_is_compressed_file:
* @path : path
*
* Checks if path is a compressed file.
*
* Returns: true (1) if path is a compressed file, otherwise false (0).
**/
bool path_is_compressed_file(const char *path);
/**
* path_contains_compressed_file:
* @path : path
*
* Checks if path contains a compressed file.
*
* Currently we only check for hash symbol (#) inside the pathname.
* If path is ever expanded to a general URI, we should check for that here.
*
* Example: Somewhere in the path there might be a compressed file
* E.g.: /path/to/file.7z#mygame.img
*
* Returns: true (1) if path contains compressed file, otherwise false (0).
**/
#define path_contains_compressed_file(path) (path_get_archive_delim((path)) != NULL)
/**
* path_get_archive_delim:
* @path : path
*
* Gets delimiter of an archive file. Only the first '#'
* after a compression extension is considered.
*
* Returns: pointer to the delimiter in the path if it contains
* a compressed file, otherwise NULL.
*/
const char *path_get_archive_delim(const char *path);
/**
* path_get_extension:
* @path : path
*
* Gets extension of file. Only '.'s
* after the last slash are considered.
*
* Returns: extension part from the path.
*/
const char *path_get_extension(const char *path);
/**
* path_remove_extension:
* @path : path
*
* Mutates path by removing its extension. Removes all
* text after and including the last '.'.
* Only '.'s after the last slash are considered.
*
* Returns:
* 1) If path has an extension, returns path with the
* extension removed.
* 2) If there is no extension, returns NULL.
* 3) If path is empty or NULL, returns NULL
*/
char *path_remove_extension(char *path);
/**
* path_basename:
* @path : path
*
* Get basename from @path.
*
* Returns: basename from path.
**/
const char *path_basename(const char *path);
/**
* path_basedir:
* @path : path
*
* Extracts base directory by mutating path.
* Keeps trailing '/'.
**/
void path_basedir(char *path);
/**
* path_parent_dir:
* @path : path
*
* Extracts parent directory by mutating path.
* Assumes that path is a directory. Keeps trailing '/'.
* If the path was already at the root directory, returns empty string
**/
void path_parent_dir(char *path);
/**
* path_resolve_realpath:
* @buf : input and output buffer for path
* @size : size of buffer
* @resolve_symlinks : whether to resolve symlinks or not
*
* Resolves use of ".", "..", multiple slashes etc in absolute paths.
*
* Relative paths are rebased on the current working dir.
*
* Returns: @buf if successful, NULL otherwise.
* Note: Not implemented on consoles
* Note: Symlinks are only resolved on Unix-likes
* Note: The current working dir might not be what you expect,
* e.g. on Android it is "/"
* Use of fill_pathname_resolve_relative() should be prefered
**/
char *path_resolve_realpath(char *buf, size_t size, bool resolve_symlinks);
/**
* path_relative_to:
* @out : buffer to write the relative path to
* @path : path to be expressed relatively
* @base : relative to this
* @size : size of output buffer
*
* Turns @path into a path relative to @base and writes it to @out.
*
* @base is assumed to be a base directory, i.e. a path ending with '/' or '\'.
* Both @path and @base are assumed to be absolute paths without "." or "..".
*
* E.g. path /a/b/e/f.cgp with base /a/b/c/d/ turns into ../../e/f.cgp
**/
void path_relative_to(char *out, const char *path, const char *base, size_t size);
/**
* path_is_absolute:
* @path : path
*
* Checks if @path is an absolute path or a relative path.
*
* Returns: true if path is absolute, false if path is relative.
**/
bool path_is_absolute(const char *path);
/**
* fill_pathname:
* @out_path : output path
* @in_path : input path
* @replace : what to replace
* @size : buffer size of output path
*
* FIXME: Verify
*
* Replaces filename extension with 'replace' and outputs result to out_path.
* The extension here is considered to be the string from the last '.'
* to the end.
*
* Only '.'s after the last slash are considered as extensions.
* If no '.' is present, in_path and replace will simply be concatenated.
* 'size' is buffer size of 'out_path'.
* E.g.: in_path = "/foo/bar/baz/boo.c", replace = ".asm" =>
* out_path = "/foo/bar/baz/boo.asm"
* E.g.: in_path = "/foo/bar/baz/boo.c", replace = "" =>
* out_path = "/foo/bar/baz/boo"
*/
void fill_pathname(char *out_path, const char *in_path,
const char *replace, size_t size);
/**
* fill_dated_filename:
* @out_filename : output filename
* @ext : extension of output filename
* @size : buffer size of output filename
*
* Creates a 'dated' filename prefixed by 'RetroArch', and
* concatenates extension (@ext) to it.
*
* E.g.:
* out_filename = "RetroArch-{month}{day}-{Hours}{Minutes}.{@ext}"
**/
void fill_dated_filename(char *out_filename,
const char *ext, size_t size);
/**
* fill_str_dated_filename:
* @out_filename : output filename
* @in_str : input string
* @ext : extension of output filename
* @size : buffer size of output filename
*
* Creates a 'dated' filename prefixed by the string @in_str, and
* concatenates extension (@ext) to it.
*
* E.g.:
* out_filename = "RetroArch-{year}{month}{day}-{Hour}{Minute}{Second}.{@ext}"
**/
void fill_str_dated_filename(char *out_filename,
const char *in_str, const char *ext, size_t size);
/**
* fill_pathname_noext:
* @out_path : output path
* @in_path : input path
* @replace : what to replace
* @size : buffer size of output path
*
* Appends a filename extension 'replace' to 'in_path', and outputs
* result in 'out_path'.
*
* Assumes in_path has no extension. If an extension is still
* present in 'in_path', it will be ignored.
*
*/
void fill_pathname_noext(char *out_path, const char *in_path,
const char *replace, size_t size);
/**
* find_last_slash:
* @str : input path
*
* Gets a pointer to the last slash in the input path.
*
* Returns: a pointer to the last slash in the input path.
**/
char *find_last_slash(const char *str);
/**
* fill_pathname_dir:
* @in_dir : input directory path
* @in_basename : input basename to be appended to @in_dir
* @replace : replacement to be appended to @in_basename
* @size : size of buffer
*
* Appends basename of 'in_basename', to 'in_dir', along with 'replace'.
* Basename of in_basename is the string after the last '/' or '\\',
* i.e the filename without directories.
*
* If in_basename has no '/' or '\\', the whole 'in_basename' will be used.
* 'size' is buffer size of 'in_dir'.
*
* E.g..: in_dir = "/tmp/some_dir", in_basename = "/some_content/foo.c",
* replace = ".asm" => in_dir = "/tmp/some_dir/foo.c.asm"
**/
void fill_pathname_dir(char *in_dir, const char *in_basename,
const char *replace, size_t size);
/**
* fill_pathname_base:
* @out : output path
* @in_path : input path
* @size : size of output path
*
* Copies basename of @in_path into @out_path.
**/
void fill_pathname_base(char *out_path, const char *in_path, size_t size);
void fill_pathname_base_noext(char *out_dir,
const char *in_path, size_t size);
void fill_pathname_base_ext(char *out,
const char *in_path, const char *ext,
size_t size);
/**
* fill_pathname_basedir:
* @out_dir : output directory
* @in_path : input path
* @size : size of output directory
*
* Copies base directory of @in_path into @out_path.
* If in_path is a path without any slashes (relative current directory),
* @out_path will get path "./".
**/
void fill_pathname_basedir(char *out_path, const char *in_path, size_t size);
void fill_pathname_basedir_noext(char *out_dir,
const char *in_path, size_t size);
/**
* fill_pathname_parent_dir_name:
* @out_dir : output directory
* @in_dir : input directory
* @size : size of output directory
*
* Copies only the parent directory name of @in_dir into @out_dir.
* The two buffers must not overlap. Removes trailing '/'.
* Returns true on success, false if a slash was not found in the path.
**/
bool fill_pathname_parent_dir_name(char *out_dir,
const char *in_dir, size_t size);
/**
* fill_pathname_parent_dir:
* @out_dir : output directory
* @in_dir : input directory
* @size : size of output directory
*
* Copies parent directory of @in_dir into @out_dir.
* Assumes @in_dir is a directory. Keeps trailing '/'.
* If the path was already at the root directory, @out_dir will be an empty string.
**/
void fill_pathname_parent_dir(char *out_dir,
const char *in_dir, size_t size);
/**
* fill_pathname_resolve_relative:
* @out_path : output path
* @in_refpath : input reference path
* @in_path : input path
* @size : size of @out_path
*
* Joins basedir of @in_refpath together with @in_path.
* If @in_path is an absolute path, out_path = in_path.
* E.g.: in_refpath = "/foo/bar/baz.a", in_path = "foobar.cg",
* out_path = "/foo/bar/foobar.cg".
**/
void fill_pathname_resolve_relative(char *out_path, const char *in_refpath,
const char *in_path, size_t size);
/**
* fill_pathname_join:
* @out_path : output path
* @dir : directory
* @path : path
* @size : size of output path
*
* Joins a directory (@dir) and path (@path) together.
* Makes sure not to get two consecutive slashes
* between directory and path.
**/
void fill_pathname_join(char *out_path, const char *dir,
const char *path, size_t size);
void fill_pathname_join_special_ext(char *out_path,
const char *dir, const char *path,
const char *last, const char *ext,
size_t size);
void fill_pathname_join_concat_noext(char *out_path,
const char *dir, const char *path,
const char *concat,
size_t size);
void fill_pathname_join_concat(char *out_path,
const char *dir, const char *path,
const char *concat,
size_t size);
void fill_pathname_join_noext(char *out_path,
const char *dir, const char *path, size_t size);
/**
* fill_pathname_join_delim:
* @out_path : output path
* @dir : directory
* @path : path
* @delim : delimiter
* @size : size of output path
*
* Joins a directory (@dir) and path (@path) together
* using the given delimiter (@delim).
**/
void fill_pathname_join_delim(char *out_path, const char *dir,
const char *path, const char delim, size_t size);
void fill_pathname_join_delim_concat(char *out_path, const char *dir,
const char *path, const char delim, const char *concat,
size_t size);
/**
* fill_short_pathname_representation:
* @out_rep : output representation
* @in_path : input path
* @size : size of output representation
*
* Generates a short representation of path. It should only
* be used for displaying the result; the output representation is not
* binding in any meaningful way (for a normal path, this is the same as basename)
* In case of more complex URLs, this should cut everything except for
* the main image file.
*
* E.g.: "/path/to/game.img" -> game.img
* "/path/to/myarchive.7z#folder/to/game.img" -> game.img
*/
void fill_short_pathname_representation(char* out_rep,
const char *in_path, size_t size);
void fill_short_pathname_representation_noext(char* out_rep,
const char *in_path, size_t size);
void fill_pathname_expand_special(char *out_path,
const char *in_path, size_t size);
void fill_pathname_abbreviate_special(char *out_path,
const char *in_path, size_t size);
/**
* path_basedir:
* @path : path
*
* Extracts base directory by mutating path.
* Keeps trailing '/'.
**/
void path_basedir_wrapper(char *path);
/**
* path_char_is_slash:
* @c : character
*
* Checks if character (@c) is a slash.
*
* Returns: true (1) if character is a slash, otherwise false (0).
*/
#ifdef _WIN32
#define path_char_is_slash(c) (((c) == '/') || ((c) == '\\'))
#else
#define path_char_is_slash(c) ((c) == '/')
#endif
/**
* path_default_slash and path_default_slash_c:
*
* Gets the default slash separator.
*
* Returns: default slash separator.
*/
#ifdef _WIN32
#define path_default_slash() "\\"
#define path_default_slash_c() '\\'
#else
#define path_default_slash() "/"
#define path_default_slash_c() '/'
#endif
/**
* fill_pathname_slash:
* @path : path
* @size : size of path
*
* Assumes path is a directory. Appends a slash
* if not already there.
**/
void fill_pathname_slash(char *path, size_t size);
#if !defined(RARCH_CONSOLE) && defined(RARCH_INTERNAL)
void fill_pathname_application_path(char *buf, size_t size);
void fill_pathname_application_dir(char *buf, size_t size);
void fill_pathname_home_dir(char *buf, size_t size);
#endif
/**
* path_mkdir:
* @dir : directory
*
* Create directory on filesystem.
*
* Returns: true (1) if directory could be created, otherwise false (0).
**/
bool path_mkdir(const char *dir);
/**
* path_is_directory:
* @path : path
*
* Checks if path is a directory.
*
* Returns: true (1) if path is a directory, otherwise false (0).
*/
bool path_is_directory(const char *path);
bool path_is_character_special(const char *path);
int path_stat(const char *path);
bool path_is_valid(const char *path);
int32_t path_get_size(const char *path);
bool is_path_accessible_using_standard_io(const char *path);
RETRO_END_DECLS
#endif

View File

@ -128,7 +128,8 @@ extern "C" {
/* LIGHTGUN device is similar to Guncon-2 for PlayStation 2. /* LIGHTGUN device is similar to Guncon-2 for PlayStation 2.
* It reports X/Y coordinates in screen space (similar to the pointer) * It reports X/Y coordinates in screen space (similar to the pointer)
* in the range [-0x8000, 0x7fff] in both axes, with zero being center. * in the range [-0x8000, 0x7fff] in both axes, with zero being center and
* -0x8000 being out of bounds.
* As well as reporting on/off screen state. It features a trigger, * As well as reporting on/off screen state. It features a trigger,
* start/select buttons, auxiliary action buttons and a * start/select buttons, auxiliary action buttons and a
* directional pad. A forced off-screen shot can be requested for * directional pad. A forced off-screen shot can be requested for
@ -139,7 +140,8 @@ extern "C" {
/* The ANALOG device is an extension to JOYPAD (RetroPad). /* The ANALOG device is an extension to JOYPAD (RetroPad).
* Similar to DualShock2 it adds two analog sticks and all buttons can * Similar to DualShock2 it adds two analog sticks and all buttons can
* be analog. This is treated as a separate device type as it returns * be analog. This is treated as a separate device type as it returns
* axis values in the full analog range of [-0x8000, 0x7fff]. * axis values in the full analog range of [-0x7fff, 0x7fff],
* although some devices may return -0x8000.
* Positive X axis is right. Positive Y axis is down. * Positive X axis is right. Positive Y axis is down.
* Buttons are returned in the range [0, 0x7fff]. * Buttons are returned in the range [0, 0x7fff].
* Only use ANALOG type when polling for analog values. * Only use ANALOG type when polling for analog values.
@ -200,6 +202,8 @@ extern "C" {
#define RETRO_DEVICE_ID_JOYPAD_L3 14 #define RETRO_DEVICE_ID_JOYPAD_L3 14
#define RETRO_DEVICE_ID_JOYPAD_R3 15 #define RETRO_DEVICE_ID_JOYPAD_R3 15
#define RETRO_DEVICE_ID_JOYPAD_MASK 256
/* Index / Id values for ANALOG device. */ /* Index / Id values for ANALOG device. */
#define RETRO_DEVICE_INDEX_ANALOG_LEFT 0 #define RETRO_DEVICE_INDEX_ANALOG_LEFT 0
#define RETRO_DEVICE_INDEX_ANALOG_RIGHT 1 #define RETRO_DEVICE_INDEX_ANALOG_RIGHT 1
@ -246,6 +250,7 @@ extern "C" {
#define RETRO_DEVICE_ID_POINTER_X 0 #define RETRO_DEVICE_ID_POINTER_X 0
#define RETRO_DEVICE_ID_POINTER_Y 1 #define RETRO_DEVICE_ID_POINTER_Y 1
#define RETRO_DEVICE_ID_POINTER_PRESSED 2 #define RETRO_DEVICE_ID_POINTER_PRESSED 2
#define RETRO_DEVICE_ID_POINTER_COUNT 3
/* Returned from retro_get_region(). */ /* Returned from retro_get_region(). */
#define RETRO_REGION_NTSC 0 #define RETRO_REGION_NTSC 0
@ -271,6 +276,8 @@ enum retro_language
RETRO_LANGUAGE_POLISH = 14, RETRO_LANGUAGE_POLISH = 14,
RETRO_LANGUAGE_VIETNAMESE = 15, RETRO_LANGUAGE_VIETNAMESE = 15,
RETRO_LANGUAGE_ARABIC = 16, RETRO_LANGUAGE_ARABIC = 16,
RETRO_LANGUAGE_GREEK = 17,
RETRO_LANGUAGE_TURKISH = 18,
RETRO_LANGUAGE_LAST, RETRO_LANGUAGE_LAST,
/* Ensure sizeof(enum) == sizeof(int) */ /* Ensure sizeof(enum) == sizeof(int) */
@ -450,6 +457,7 @@ enum retro_key
RETROK_POWER = 320, RETROK_POWER = 320,
RETROK_EURO = 321, RETROK_EURO = 321,
RETROK_UNDO = 322, RETROK_UNDO = 322,
RETROK_OEM_102 = 323,
RETROK_LAST, RETROK_LAST,
@ -481,11 +489,13 @@ enum retro_mod
/* Environment commands. */ /* Environment commands. */
#define RETRO_ENVIRONMENT_SET_ROTATION 1 /* const unsigned * -- #define RETRO_ENVIRONMENT_SET_ROTATION 1 /* const unsigned * --
* Sets screen rotation of graphics. * Sets screen rotation of graphics.
* Is only implemented if rotation can be accelerated by hardware.
* Valid values are 0, 1, 2, 3, which rotates screen by 0, 90, 180, * Valid values are 0, 1, 2, 3, which rotates screen by 0, 90, 180,
* 270 degrees counter-clockwise respectively. * 270 degrees counter-clockwise respectively.
*/ */
#define RETRO_ENVIRONMENT_GET_OVERSCAN 2 /* bool * -- #define RETRO_ENVIRONMENT_GET_OVERSCAN 2 /* bool * --
* NOTE: As of 2019 this callback is considered deprecated in favor of
* using core options to manage overscan in a more nuanced, core-specific way.
*
* Boolean value whether or not the implementation should use overscan, * Boolean value whether or not the implementation should use overscan,
* or crop away overscan. * or crop away overscan.
*/ */
@ -604,7 +614,7 @@ enum retro_mod
* Afterward it may be called again for the core to communicate * Afterward it may be called again for the core to communicate
* updated options to the frontend, but the number of core * updated options to the frontend, but the number of core
* options must not change from the number in the initial call. * options must not change from the number in the initial call.
* *
* 'data' points to an array of retro_variable structs * 'data' points to an array of retro_variable structs
* terminated by a { NULL, NULL } element. * terminated by a { NULL, NULL } element.
* retro_variable::key should be namespaced to not collide * retro_variable::key should be namespaced to not collide
@ -657,6 +667,15 @@ enum retro_mod
/* Environment 20 was an obsolete version of SET_AUDIO_CALLBACK. /* Environment 20 was an obsolete version of SET_AUDIO_CALLBACK.
* It was not used by any known core at the time, * It was not used by any known core at the time,
* and was removed from the API. */ * and was removed from the API. */
#define RETRO_ENVIRONMENT_SET_FRAME_TIME_CALLBACK 21
/* const struct retro_frame_time_callback * --
* Lets the core know how much time has passed since last
* invocation of retro_run().
* The frontend can tamper with the timing to fake fast-forward,
* slow-motion, frame stepping, etc.
* In this case the delta time will use the reference value
* in frame_time_callback..
*/
#define RETRO_ENVIRONMENT_SET_AUDIO_CALLBACK 22 #define RETRO_ENVIRONMENT_SET_AUDIO_CALLBACK 22
/* const struct retro_audio_callback * -- /* const struct retro_audio_callback * --
* Sets an interface which is used to notify a libretro core about audio * Sets an interface which is used to notify a libretro core about audio
@ -683,15 +702,6 @@ enum retro_mod
* A libretro core using SET_AUDIO_CALLBACK should also make use of * A libretro core using SET_AUDIO_CALLBACK should also make use of
* SET_FRAME_TIME_CALLBACK. * SET_FRAME_TIME_CALLBACK.
*/ */
#define RETRO_ENVIRONMENT_SET_FRAME_TIME_CALLBACK 21
/* const struct retro_frame_time_callback * --
* Lets the core know how much time has passed since last
* invocation of retro_run().
* The frontend can tamper with the timing to fake fast-forward,
* slow-motion, frame stepping, etc.
* In this case the delta time will use the reference value
* in frame_time_callback..
*/
#define RETRO_ENVIRONMENT_GET_RUMBLE_INTERFACE 23 #define RETRO_ENVIRONMENT_GET_RUMBLE_INTERFACE 23
/* struct retro_rumble_interface * -- /* struct retro_rumble_interface * --
* Gets an interface which is used by a libretro core to set * Gets an interface which is used by a libretro core to set
@ -871,12 +881,12 @@ enum retro_mod
* types already defined in the libretro API. * types already defined in the libretro API.
* *
* The core must pass an array of const struct retro_controller_info which * The core must pass an array of const struct retro_controller_info which
* is terminated with a blanked out struct. Each element of the * is terminated with a blanked out struct. Each element of the
* retro_controller_info struct corresponds to the ascending port index * retro_controller_info struct corresponds to the ascending port index
* that is passed to retro_set_controller_port_device() when that function * that is passed to retro_set_controller_port_device() when that function
* is called to indicate to the core that the frontend has changed the * is called to indicate to the core that the frontend has changed the
* active device subclass. SEE ALSO: retro_set_controller_port_device() * active device subclass. SEE ALSO: retro_set_controller_port_device()
* *
* The ascending input port indexes provided by the core in the struct * The ascending input port indexes provided by the core in the struct
* are generally presented by frontends as ascending User # or Player #, * are generally presented by frontends as ascending User # or Player #,
* such as Player 1, Player 2, Player 3, etc. Which device subclasses are * such as Player 1, Player 2, Player 3, etc. Which device subclasses are
@ -888,7 +898,7 @@ enum retro_mod
* User or Player, beginning with the generic Libretro device that the * User or Player, beginning with the generic Libretro device that the
* subclasses are derived from. The second inner element of each entry is the * subclasses are derived from. The second inner element of each entry is the
* total number of subclasses that are listed in the retro_controller_description. * total number of subclasses that are listed in the retro_controller_description.
* *
* NOTE: Even if special device types are set in the libretro core, * NOTE: Even if special device types are set in the libretro core,
* libretro should only poll input based on the base input device types. * libretro should only poll input based on the base input device types.
*/ */
@ -968,7 +978,37 @@ enum retro_mod
* A frontend must make sure that the pointer obtained from this function is * A frontend must make sure that the pointer obtained from this function is
* writeable (and readable). * writeable (and readable).
*/ */
#define RETRO_ENVIRONMENT_GET_HW_RENDER_INTERFACE (41 | RETRO_ENVIRONMENT_EXPERIMENTAL)
/* const struct retro_hw_render_interface ** --
* Returns an API specific rendering interface for accessing API specific data.
* Not all HW rendering APIs support or need this.
* The contents of the returned pointer is specific to the rendering API
* being used. See the various headers like libretro_vulkan.h, etc.
*
* GET_HW_RENDER_INTERFACE cannot be called before context_reset has been called.
* Similarly, after context_destroyed callback returns,
* the contents of the HW_RENDER_INTERFACE are invalidated.
*/
#define RETRO_ENVIRONMENT_SET_SUPPORT_ACHIEVEMENTS (42 | RETRO_ENVIRONMENT_EXPERIMENTAL)
/* const bool * --
* If true, the libretro implementation supports achievements
* either via memory descriptors set with RETRO_ENVIRONMENT_SET_MEMORY_MAPS
* or via retro_get_memory_data/retro_get_memory_size.
*
* This must be called before the first call to retro_run.
*/
#define RETRO_ENVIRONMENT_SET_HW_RENDER_CONTEXT_NEGOTIATION_INTERFACE (43 | RETRO_ENVIRONMENT_EXPERIMENTAL)
/* const struct retro_hw_render_context_negotiation_interface * --
* Sets an interface which lets the libretro core negotiate with frontend how a context is created.
* The semantics of this interface depends on which API is used in SET_HW_RENDER earlier.
* This interface will be used when the frontend is trying to create a HW rendering context,
* so it will be used after SET_HW_RENDER, but before the context_reset callback.
*/
#define RETRO_ENVIRONMENT_SET_SERIALIZATION_QUIRKS 44
/* uint64_t * --
* Sets quirk flags associated with serialization. The frontend will zero any flags it doesn't
* recognize or support. Should be set in either retro_init or retro_load_game, but not both.
*/
#define RETRO_ENVIRONMENT_SET_HW_SHARED_CONTEXT (44 | RETRO_ENVIRONMENT_EXPERIMENTAL) #define RETRO_ENVIRONMENT_SET_HW_SHARED_CONTEXT (44 | RETRO_ENVIRONMENT_EXPERIMENTAL)
/* N/A (null) * -- /* N/A (null) * --
* The frontend will try to use a 'shared' hardware context (mostly applicable * The frontend will try to use a 'shared' hardware context (mostly applicable
@ -980,160 +1020,19 @@ enum retro_mod
* This will do nothing on its own until SET_HW_RENDER env callbacks are * This will do nothing on its own until SET_HW_RENDER env callbacks are
* being used. * being used.
*/ */
#define RETRO_ENVIRONMENT_GET_VFS_INTERFACE (45 | RETRO_ENVIRONMENT_EXPERIMENTAL) #define RETRO_ENVIRONMENT_GET_VFS_INTERFACE (45 | RETRO_ENVIRONMENT_EXPERIMENTAL)
/* struct retro_vfs_interface_info * -- /* struct retro_vfs_interface_info * --
* Gets access to the VFS interface. * Gets access to the VFS interface.
* VFS presence needs to be queried prior to load_game or any * VFS presence needs to be queried prior to load_game or any
* get_system/save/other_directory being called to let front end know * get_system/save/other_directory being called to let front end know
* core supports VFS before it starts handing out paths. * core supports VFS before it starts handing out paths.
* It is recomended to do so in retro_set_environment */ * It is recomended to do so in retro_set_environment
*/
/* VFS functionality */
/* File paths:
* File paths passed as parameters when using this api shall be well formed unix-style,
* using "/" (unquoted forward slash) as directory separator regardless of the platform's native separator.
* Paths shall also include at least one forward slash ("game.bin" is an invalid path, use "./game.bin" instead).
* Other than the directory separator, cores shall not make assumptions about path format:
* "C:/path/game.bin", "http://example.com/game.bin", "#game/game.bin", "./game.bin" (without quotes) are all valid paths.
* Cores may replace the basename or remove path components from the end, and/or add new components;
* however, cores shall not append "./", "../" or multiple consecutive forward slashes ("//") to paths they request to front end.
* The frontend is encouraged to make such paths work as well as it can, but is allowed to give up if the core alters paths too much.
* Frontends are encouraged, but not required, to support native file system paths (modulo replacing the directory separator, if applicable).
* Cores are allowed to try using them, but must remain functional if the front rejects such requests.
* Cores are encouraged to use the libretro-common filestream functions for file I/O,
* as they seamlessly integrate with VFS, deal with directory separator replacement as appropriate
* and provide platform-specific fallbacks in cases where front ends do not support VFS. */
/* Opaque file handle
* Introduced in VFS API v1 */
struct retro_vfs_file_handle;
/* File open flags
* Introduced in VFS API v1 */
#define RETRO_VFS_FILE_ACCESS_READ (1 << 0) /* Read only mode */
#define RETRO_VFS_FILE_ACCESS_WRITE (1 << 1) /* Write only mode, discard contents and overwrites existing file unless RETRO_VFS_FILE_ACCESS_UPDATE is also specified */
#define RETRO_VFS_FILE_ACCESS_READ_WRITE (RETRO_VFS_FILE_ACCESS_READ | RETRO_VFS_FILE_ACCESS_WRITE) /* Read-write mode, discard contents and overwrites existing file unless RETRO_VFS_FILE_ACCESS_UPDATE is also specified*/
#define RETRO_VFS_FILE_ACCESS_UPDATE_EXISTING (1 << 2) /* Prevents discarding content of existing files opened for writing */
/* These are only hints. The frontend may choose to ignore them. Other than RAM/CPU/etc use,
and how they react to unlikely external interference (for example someone else writing to that file,
or the file's server going down), behavior will not change. */
#define RETRO_VFS_FILE_ACCESS_HINT_NONE (0)
/* Indicate that the file will be accessed many times. The frontend should aggressively cache everything. */
#define RETRO_VFS_FILE_ACCESS_HINT_FREQUENT_ACCESS (1 << 0)
/* Seek positions */
#define RETRO_VFS_SEEK_POSITION_START 0
#define RETRO_VFS_SEEK_POSITION_CURRENT 1
#define RETRO_VFS_SEEK_POSITION_END 2
/* Get path from opaque handle. Returns the exact same path passed to file_open when getting the handle
* Introduced in VFS API v1 */
typedef const char *(RETRO_CALLCONV *retro_vfs_get_path_t)(struct retro_vfs_file_handle *stream);
/* Open a file for reading or writing. If path points to a directory, this will
* fail. Returns the opaque file handle, or NULL for error.
* Introduced in VFS API v1 */
typedef struct retro_vfs_file_handle *(RETRO_CALLCONV *retro_vfs_open_t)(const char *path, unsigned mode, unsigned hints);
/* Close the file and release its resources. Must be called if open_file returns non-NULL. Returns 0 on succes, -1 on failure.
* Whether the call succeeds ot not, the handle passed as parameter becomes invalid and should no longer be used.
* Introduced in VFS API v1 */
typedef int (RETRO_CALLCONV *retro_vfs_close_t)(struct retro_vfs_file_handle *stream);
/* Return the size of the file in bytes, or -1 for error.
* Introduced in VFS API v1 */
typedef int64_t (RETRO_CALLCONV *retro_vfs_size_t)(struct retro_vfs_file_handle *stream);
/* Get the current read / write position for the file. Returns - 1 for error.
* Introduced in VFS API v1 */
typedef int64_t (RETRO_CALLCONV *retro_vfs_tell_t)(struct retro_vfs_file_handle *stream);
/* Set the current read/write position for the file. Returns the new position, -1 for error.
* Introduced in VFS API v1 */
typedef int64_t (RETRO_CALLCONV *retro_vfs_seek_t)(struct retro_vfs_file_handle *stream, int64_t offset, int seek_position);
/* Read data from a file. Returns the number of bytes read, or -1 for error.
* Introduced in VFS API v1 */
typedef int64_t (RETRO_CALLCONV *retro_vfs_read_t)(struct retro_vfs_file_handle *stream, void *s, uint64_t len);
/* Write data to a file. Returns the number of bytes written, or -1 for error.
* Introduced in VFS API v1 */
typedef int64_t (RETRO_CALLCONV *retro_vfs_write_t)(struct retro_vfs_file_handle *stream, const void *s, uint64_t len);
/* Flush pending writes to file, if using buffered IO. Returns 0 on sucess, or -1 on failure.
* Introduced in VFS API v1 */
typedef int (RETRO_CALLCONV *retro_vfs_flush_t)(struct retro_vfs_file_handle *stream);
/* Delete the specified file. Returns 0 on success, -1 on failure
* Introduced in VFS API v1 */
typedef int (RETRO_CALLCONV *retro_vfs_remove_t)(const char *path);
/* Rename the specified file. Returns 0 on success, -1 on failure
* Introduced in VFS API v1 */
typedef int (RETRO_CALLCONV *retro_vfs_rename_t)(const char *old_path, const char *new_path);
struct retro_vfs_interface
{
retro_vfs_get_path_t get_path;
retro_vfs_open_t open;
retro_vfs_close_t close;
retro_vfs_size_t size;
retro_vfs_tell_t tell;
retro_vfs_seek_t seek;
retro_vfs_read_t read;
retro_vfs_write_t write;
retro_vfs_flush_t flush;
retro_vfs_remove_t remove;
retro_vfs_rename_t rename;
};
struct retro_vfs_interface_info
{
/* Set by core: should this be higher than the version the front end supports,
* front end will return false in the RETRO_ENVIRONMENT_GET_VFS_INTERFACE call
* Introduced in VFS API v1 */
uint32_t required_interface_version;
/* Frontend writes interface pointer here. The frontend also sets the actual
* version, must be at least required_interface_version.
* Introduced in VFS API v1 */
struct retro_vfs_interface *iface;
};
enum retro_hw_render_interface_type
{
RETRO_HW_RENDER_INTERFACE_VULKAN = 0,
RETRO_HW_RENDER_INTERFACE_D3D9 = 1,
RETRO_HW_RENDER_INTERFACE_D3D10 = 2,
RETRO_HW_RENDER_INTERFACE_D3D11 = 3,
RETRO_HW_RENDER_INTERFACE_D3D12 = 4,
RETRO_HW_RENDER_INTERFACE_DUMMY = INT_MAX
};
/* Base struct. All retro_hw_render_interface_* types
* contain at least these fields. */
struct retro_hw_render_interface
{
enum retro_hw_render_interface_type interface_type;
unsigned interface_version;
};
#define RETRO_ENVIRONMENT_GET_LED_INTERFACE (46 | RETRO_ENVIRONMENT_EXPERIMENTAL) #define RETRO_ENVIRONMENT_GET_LED_INTERFACE (46 | RETRO_ENVIRONMENT_EXPERIMENTAL)
/* struct retro_led_interface * -- /* struct retro_led_interface * --
* Gets an interface which is used by a libretro core to set * Gets an interface which is used by a libretro core to set
* state of LEDs. * state of LEDs.
*/ */
typedef void (RETRO_CALLCONV *retro_set_led_state_t)(int led, int state);
struct retro_led_interface
{
retro_set_led_state_t set_led_state;
};
#define RETRO_ENVIRONMENT_GET_AUDIO_VIDEO_ENABLE (47 | RETRO_ENVIRONMENT_EXPERIMENTAL) #define RETRO_ENVIRONMENT_GET_AUDIO_VIDEO_ENABLE (47 | RETRO_ENVIRONMENT_EXPERIMENTAL)
/* int * -- /* int * --
* Tells the core if the frontend wants audio or video. * Tells the core if the frontend wants audio or video.
@ -1175,12 +1074,377 @@ struct retro_led_interface
* never need an accurate audio state in the future. * never need an accurate audio state in the future.
* * State will never be saved when using Hard Disable Audio. * * State will never be saved when using Hard Disable Audio.
*/ */
#define RETRO_ENVIRONMENT_GET_MIDI_INTERFACE (48 | RETRO_ENVIRONMENT_EXPERIMENTAL) #define RETRO_ENVIRONMENT_GET_MIDI_INTERFACE (48 | RETRO_ENVIRONMENT_EXPERIMENTAL)
/* struct retro_midi_interface ** -- /* struct retro_midi_interface ** --
* Returns a MIDI interface that can be used for raw data I/O. * Returns a MIDI interface that can be used for raw data I/O.
*/ */
#define RETRO_ENVIRONMENT_GET_FASTFORWARDING (49 | RETRO_ENVIRONMENT_EXPERIMENTAL)
/* bool * --
* Boolean value that indicates whether or not the frontend is in
* fastforwarding mode.
*/
#define RETRO_ENVIRONMENT_GET_TARGET_REFRESH_RATE (50 | RETRO_ENVIRONMENT_EXPERIMENTAL)
/* float * --
* Float value that lets us know what target refresh rate
* is curently in use by the frontend.
*
* The core can use the returned value to set an ideal
* refresh rate/framerate.
*/
#define RETRO_ENVIRONMENT_GET_INPUT_BITMASKS (51 | RETRO_ENVIRONMENT_EXPERIMENTAL)
/* bool * --
* Boolean value that indicates whether or not the frontend supports
* input bitmasks being returned by retro_input_state_t. The advantage
* of this is that retro_input_state_t has to be only called once to
* grab all button states instead of multiple times.
*
* If it returns true, you can pass RETRO_DEVICE_ID_JOYPAD_MASK as 'id'
* to retro_input_state_t (make sure 'device' is set to RETRO_DEVICE_JOYPAD).
* It will return a bitmask of all the digital buttons.
*/
#define RETRO_ENVIRONMENT_GET_CORE_OPTIONS_VERSION 52
/* unsigned * --
* Unsigned value is the API version number of the core options
* interface supported by the frontend. If callback return false,
* API version is assumed to be 0.
*
* In legacy code, core options are set by passing an array of
* retro_variable structs to RETRO_ENVIRONMENT_SET_VARIABLES.
* This may be still be done regardless of the core options
* interface version.
*
* If version is 1 however, core options may instead be set by
* passing an array of retro_core_option_definition structs to
* RETRO_ENVIRONMENT_SET_CORE_OPTIONS, or a 2D array of
* retro_core_option_definition structs to RETRO_ENVIRONMENT_SET_CORE_OPTIONS_INTL.
* This allows the core to additionally set option sublabel information
* and/or provide localisation support.
*/
#define RETRO_ENVIRONMENT_SET_CORE_OPTIONS 53
/* const struct retro_core_option_definition ** --
* Allows an implementation to signal the environment
* which variables it might want to check for later using
* GET_VARIABLE.
* This allows the frontend to present these variables to
* a user dynamically.
* This should only be called if RETRO_ENVIRONMENT_GET_ENHANCED_CORE_OPTIONS
* returns an API version of 1.
* This should be called instead of RETRO_ENVIRONMENT_SET_VARIABLES.
* This should be called the first time as early as
* possible (ideally in retro_set_environment).
* Afterwards it may be called again for the core to communicate
* updated options to the frontend, but the number of core
* options must not change from the number in the initial call.
*
* 'data' points to an array of retro_core_option_definition structs
* terminated by a { NULL, NULL, NULL, {{0}}, NULL } element.
* retro_core_option_definition::key should be namespaced to not collide
* with other implementations' keys. e.g. A core called
* 'foo' should use keys named as 'foo_option'.
* retro_core_option_definition::desc should contain a human readable
* description of the key.
* retro_core_option_definition::info should contain any additional human
* readable information text that a typical user may need to
* understand the functionality of the option.
* retro_core_option_definition::values is an array of retro_core_option_value
* structs terminated by a { NULL, NULL } element.
* > retro_core_option_definition::values[index].value is an expected option
* value.
* > retro_core_option_definition::values[index].label is a human readable
* label used when displaying the value on screen. If NULL,
* the value itself is used.
* retro_core_option_definition::default_value is the default core option
* setting. It must match one of the expected option values in the
* retro_core_option_definition::values array. If it does not, or the
* default value is NULL, the first entry in the
* retro_core_option_definition::values array is treated as the default.
*
* The number of possible options should be very limited,
* and must be less than RETRO_NUM_CORE_OPTION_VALUES_MAX.
* i.e. it should be feasible to cycle through options
* without a keyboard.
*
* First entry should be treated as a default.
*
* Example entry:
* {
* "foo_option",
* "Speed hack coprocessor X",
* "Provides increased performance at the expense of reduced accuracy",
* {
* { "false", NULL },
* { "true", NULL },
* { "unstable", "Turbo (Unstable)" },
* { NULL, NULL },
* },
* "false"
* }
*
* Only strings are operated on. The possible values will
* generally be displayed and stored as-is by the frontend.
*/
#define RETRO_ENVIRONMENT_SET_CORE_OPTIONS_INTL 54
/* const struct retro_core_options_intl * --
* Allows an implementation to signal the environment
* which variables it might want to check for later using
* GET_VARIABLE.
* This allows the frontend to present these variables to
* a user dynamically.
* This should only be called if RETRO_ENVIRONMENT_GET_ENHANCED_CORE_OPTIONS
* returns an API version of 1.
* This should be called instead of RETRO_ENVIRONMENT_SET_VARIABLES.
* This should be called the first time as early as
* possible (ideally in retro_set_environment).
* Afterwards it may be called again for the core to communicate
* updated options to the frontend, but the number of core
* options must not change from the number in the initial call.
*
* This is fundamentally the same as RETRO_ENVIRONMENT_SET_CORE_OPTIONS,
* with the addition of localisation support. The description of the
* RETRO_ENVIRONMENT_SET_CORE_OPTIONS callback should be consulted
* for further details.
*
* 'data' points to a retro_core_options_intl struct.
*
* retro_core_options_intl::us is a pointer to an array of
* retro_core_option_definition structs defining the US English
* core options implementation. It must point to a valid array.
*
* retro_core_options_intl::local is a pointer to an array of
* retro_core_option_definition structs defining core options for
* the current frontend language. It may be NULL (in which case
* retro_core_options_intl::us is used by the frontend). Any items
* missing from this array will be read from retro_core_options_intl::us
* instead.
*
* NOTE: Default core option values are always taken from the
* retro_core_options_intl::us array. Any default values in
* retro_core_options_intl::local array will be ignored.
*/
#define RETRO_ENVIRONMENT_SET_CORE_OPTIONS_DISPLAY 55
/* struct retro_core_option_display * --
*
* Allows an implementation to signal the environment to show
* or hide a variable when displaying core options. This is
* considered a *suggestion*. The frontend is free to ignore
* this callback, and its implementation not considered mandatory.
*
* 'data' points to a retro_core_option_display struct
*
* retro_core_option_display::key is a variable identifier
* which has already been set by SET_VARIABLES/SET_CORE_OPTIONS.
*
* retro_core_option_display::visible is a boolean, specifying
* whether variable should be displayed
*
* Note that all core option variables will be set visible by
* default when calling SET_VARIABLES/SET_CORE_OPTIONS.
*/
/* VFS functionality */
/* File paths:
* File paths passed as parameters when using this API shall be well formed UNIX-style,
* using "/" (unquoted forward slash) as directory separator regardless of the platform's native separator.
* Paths shall also include at least one forward slash ("game.bin" is an invalid path, use "./game.bin" instead).
* Other than the directory separator, cores shall not make assumptions about path format:
* "C:/path/game.bin", "http://example.com/game.bin", "#game/game.bin", "./game.bin" (without quotes) are all valid paths.
* Cores may replace the basename or remove path components from the end, and/or add new components;
* however, cores shall not append "./", "../" or multiple consecutive forward slashes ("//") to paths they request to front end.
* The frontend is encouraged to make such paths work as well as it can, but is allowed to give up if the core alters paths too much.
* Frontends are encouraged, but not required, to support native file system paths (modulo replacing the directory separator, if applicable).
* Cores are allowed to try using them, but must remain functional if the front rejects such requests.
* Cores are encouraged to use the libretro-common filestream functions for file I/O,
* as they seamlessly integrate with VFS, deal with directory separator replacement as appropriate
* and provide platform-specific fallbacks in cases where front ends do not support VFS. */
/* Opaque file handle
* Introduced in VFS API v1 */
struct retro_vfs_file_handle;
/* Opaque directory handle
* Introduced in VFS API v3 */
struct retro_vfs_dir_handle;
/* File open flags
* Introduced in VFS API v1 */
#define RETRO_VFS_FILE_ACCESS_READ (1 << 0) /* Read only mode */
#define RETRO_VFS_FILE_ACCESS_WRITE (1 << 1) /* Write only mode, discard contents and overwrites existing file unless RETRO_VFS_FILE_ACCESS_UPDATE is also specified */
#define RETRO_VFS_FILE_ACCESS_READ_WRITE (RETRO_VFS_FILE_ACCESS_READ | RETRO_VFS_FILE_ACCESS_WRITE) /* Read-write mode, discard contents and overwrites existing file unless RETRO_VFS_FILE_ACCESS_UPDATE is also specified*/
#define RETRO_VFS_FILE_ACCESS_UPDATE_EXISTING (1 << 2) /* Prevents discarding content of existing files opened for writing */
/* These are only hints. The frontend may choose to ignore them. Other than RAM/CPU/etc use,
and how they react to unlikely external interference (for example someone else writing to that file,
or the file's server going down), behavior will not change. */
#define RETRO_VFS_FILE_ACCESS_HINT_NONE (0)
/* Indicate that the file will be accessed many times. The frontend should aggressively cache everything. */
#define RETRO_VFS_FILE_ACCESS_HINT_FREQUENT_ACCESS (1 << 0)
/* Seek positions */
#define RETRO_VFS_SEEK_POSITION_START 0
#define RETRO_VFS_SEEK_POSITION_CURRENT 1
#define RETRO_VFS_SEEK_POSITION_END 2
/* stat() result flags
* Introduced in VFS API v3 */
#define RETRO_VFS_STAT_IS_VALID (1 << 0)
#define RETRO_VFS_STAT_IS_DIRECTORY (1 << 1)
#define RETRO_VFS_STAT_IS_CHARACTER_SPECIAL (1 << 2)
/* Get path from opaque handle. Returns the exact same path passed to file_open when getting the handle
* Introduced in VFS API v1 */
typedef const char *(RETRO_CALLCONV *retro_vfs_get_path_t)(struct retro_vfs_file_handle *stream);
/* Open a file for reading or writing. If path points to a directory, this will
* fail. Returns the opaque file handle, or NULL for error.
* Introduced in VFS API v1 */
typedef struct retro_vfs_file_handle *(RETRO_CALLCONV *retro_vfs_open_t)(const char *path, unsigned mode, unsigned hints);
/* Close the file and release its resources. Must be called if open_file returns non-NULL. Returns 0 on success, -1 on failure.
* Whether the call succeeds ot not, the handle passed as parameter becomes invalid and should no longer be used.
* Introduced in VFS API v1 */
typedef int (RETRO_CALLCONV *retro_vfs_close_t)(struct retro_vfs_file_handle *stream);
/* Return the size of the file in bytes, or -1 for error.
* Introduced in VFS API v1 */
typedef int64_t (RETRO_CALLCONV *retro_vfs_size_t)(struct retro_vfs_file_handle *stream);
/* Truncate file to specified size. Returns 0 on success or -1 on error
* Introduced in VFS API v2 */
typedef int64_t (RETRO_CALLCONV *retro_vfs_truncate_t)(struct retro_vfs_file_handle *stream, int64_t length);
/* Get the current read / write position for the file. Returns -1 for error.
* Introduced in VFS API v1 */
typedef int64_t (RETRO_CALLCONV *retro_vfs_tell_t)(struct retro_vfs_file_handle *stream);
/* Set the current read/write position for the file. Returns the new position, -1 for error.
* Introduced in VFS API v1 */
typedef int64_t (RETRO_CALLCONV *retro_vfs_seek_t)(struct retro_vfs_file_handle *stream, int64_t offset, int seek_position);
/* Read data from a file. Returns the number of bytes read, or -1 for error.
* Introduced in VFS API v1 */
typedef int64_t (RETRO_CALLCONV *retro_vfs_read_t)(struct retro_vfs_file_handle *stream, void *s, uint64_t len);
/* Write data to a file. Returns the number of bytes written, or -1 for error.
* Introduced in VFS API v1 */
typedef int64_t (RETRO_CALLCONV *retro_vfs_write_t)(struct retro_vfs_file_handle *stream, const void *s, uint64_t len);
/* Flush pending writes to file, if using buffered IO. Returns 0 on sucess, or -1 on failure.
* Introduced in VFS API v1 */
typedef int (RETRO_CALLCONV *retro_vfs_flush_t)(struct retro_vfs_file_handle *stream);
/* Delete the specified file. Returns 0 on success, -1 on failure
* Introduced in VFS API v1 */
typedef int (RETRO_CALLCONV *retro_vfs_remove_t)(const char *path);
/* Rename the specified file. Returns 0 on success, -1 on failure
* Introduced in VFS API v1 */
typedef int (RETRO_CALLCONV *retro_vfs_rename_t)(const char *old_path, const char *new_path);
/* Stat the specified file. Retruns a bitmask of RETRO_VFS_STAT_* flags, none are set if path was not valid.
* Additionally stores file size in given variable, unless NULL is given.
* Introduced in VFS API v3 */
typedef int (RETRO_CALLCONV *retro_vfs_stat_t)(const char *path, int32_t *size);
/* Create the specified directory. Returns 0 on success, -1 on unknown failure, -2 if already exists.
* Introduced in VFS API v3 */
typedef int (RETRO_CALLCONV *retro_vfs_mkdir_t)(const char *dir);
/* Open the specified directory for listing. Returns the opaque dir handle, or NULL for error.
* Support for the include_hidden argument may vary depending on the platform.
* Introduced in VFS API v3 */
typedef struct retro_vfs_dir_handle *(RETRO_CALLCONV *retro_vfs_opendir_t)(const char *dir, bool include_hidden);
/* Read the directory entry at the current position, and move the read pointer to the next position.
* Returns true on success, false if already on the last entry.
* Introduced in VFS API v3 */
typedef bool (RETRO_CALLCONV *retro_vfs_readdir_t)(struct retro_vfs_dir_handle *dirstream);
/* Get the name of the last entry read. Returns a string on success, or NULL for error.
* The returned string pointer is valid until the next call to readdir or closedir.
* Introduced in VFS API v3 */
typedef const char *(RETRO_CALLCONV *retro_vfs_dirent_get_name_t)(struct retro_vfs_dir_handle *dirstream);
/* Check if the last entry read was a directory. Returns true if it was, false otherwise (or on error).
* Introduced in VFS API v3 */
typedef bool (RETRO_CALLCONV *retro_vfs_dirent_is_dir_t)(struct retro_vfs_dir_handle *dirstream);
/* Close the directory and release its resources. Must be called if opendir returns non-NULL. Returns 0 on success, -1 on failure.
* Whether the call succeeds ot not, the handle passed as parameter becomes invalid and should no longer be used.
* Introduced in VFS API v3 */
typedef int (RETRO_CALLCONV *retro_vfs_closedir_t)(struct retro_vfs_dir_handle *dirstream);
struct retro_vfs_interface
{
/* VFS API v1 */
retro_vfs_get_path_t get_path;
retro_vfs_open_t open;
retro_vfs_close_t close;
retro_vfs_size_t size;
retro_vfs_tell_t tell;
retro_vfs_seek_t seek;
retro_vfs_read_t read;
retro_vfs_write_t write;
retro_vfs_flush_t flush;
retro_vfs_remove_t remove;
retro_vfs_rename_t rename;
/* VFS API v2 */
retro_vfs_truncate_t truncate;
/* VFS API v3 */
retro_vfs_stat_t stat;
retro_vfs_mkdir_t mkdir;
retro_vfs_opendir_t opendir;
retro_vfs_readdir_t readdir;
retro_vfs_dirent_get_name_t dirent_get_name;
retro_vfs_dirent_is_dir_t dirent_is_dir;
retro_vfs_closedir_t closedir;
};
struct retro_vfs_interface_info
{
/* Set by core: should this be higher than the version the front end supports,
* front end will return false in the RETRO_ENVIRONMENT_GET_VFS_INTERFACE call
* Introduced in VFS API v1 */
uint32_t required_interface_version;
/* Frontend writes interface pointer here. The frontend also sets the actual
* version, must be at least required_interface_version.
* Introduced in VFS API v1 */
struct retro_vfs_interface *iface;
};
enum retro_hw_render_interface_type
{
RETRO_HW_RENDER_INTERFACE_VULKAN = 0,
RETRO_HW_RENDER_INTERFACE_D3D9 = 1,
RETRO_HW_RENDER_INTERFACE_D3D10 = 2,
RETRO_HW_RENDER_INTERFACE_D3D11 = 3,
RETRO_HW_RENDER_INTERFACE_D3D12 = 4,
RETRO_HW_RENDER_INTERFACE_GSKIT_PS2 = 5,
RETRO_HW_RENDER_INTERFACE_DUMMY = INT_MAX
};
/* Base struct. All retro_hw_render_interface_* types
* contain at least these fields. */
struct retro_hw_render_interface
{
enum retro_hw_render_interface_type interface_type;
unsigned interface_version;
};
typedef void (RETRO_CALLCONV *retro_set_led_state_t)(int led, int state);
struct retro_led_interface
{
retro_set_led_state_t set_led_state;
};
/* Retrieves the current state of the MIDI input. /* Retrieves the current state of the MIDI input.
* Returns true if it's enabled, false otherwise. */ * Returns true if it's enabled, false otherwise. */
typedef bool (RETRO_CALLCONV *retro_midi_input_enabled_t)(void); typedef bool (RETRO_CALLCONV *retro_midi_input_enabled_t)(void);
@ -1211,27 +1475,6 @@ struct retro_midi_interface
retro_midi_flush_t flush; retro_midi_flush_t flush;
}; };
#define RETRO_ENVIRONMENT_GET_HW_RENDER_INTERFACE (41 | RETRO_ENVIRONMENT_EXPERIMENTAL)
/* const struct retro_hw_render_interface ** --
* Returns an API specific rendering interface for accessing API specific data.
* Not all HW rendering APIs support or need this.
* The contents of the returned pointer is specific to the rendering API
* being used. See the various headers like libretro_vulkan.h, etc.
*
* GET_HW_RENDER_INTERFACE cannot be called before context_reset has been called.
* Similarly, after context_destroyed callback returns,
* the contents of the HW_RENDER_INTERFACE are invalidated.
*/
#define RETRO_ENVIRONMENT_SET_SUPPORT_ACHIEVEMENTS (42 | RETRO_ENVIRONMENT_EXPERIMENTAL)
/* const bool * --
* If true, the libretro implementation supports achievements
* either via memory descriptors set with RETRO_ENVIRONMENT_SET_MEMORY_MAPS
* or via retro_get_memory_data/retro_get_memory_size.
*
* This must be called before the first call to retro_run.
*/
enum retro_hw_render_context_negotiation_interface_type enum retro_hw_render_context_negotiation_interface_type
{ {
RETRO_HW_RENDER_CONTEXT_NEGOTIATION_INTERFACE_VULKAN = 0, RETRO_HW_RENDER_CONTEXT_NEGOTIATION_INTERFACE_VULKAN = 0,
@ -1245,13 +1488,6 @@ struct retro_hw_render_context_negotiation_interface
enum retro_hw_render_context_negotiation_interface_type interface_type; enum retro_hw_render_context_negotiation_interface_type interface_type;
unsigned interface_version; unsigned interface_version;
}; };
#define RETRO_ENVIRONMENT_SET_HW_RENDER_CONTEXT_NEGOTIATION_INTERFACE (43 | RETRO_ENVIRONMENT_EXPERIMENTAL)
/* const struct retro_hw_render_context_negotiation_interface * --
* Sets an interface which lets the libretro core negotiate with frontend how a context is created.
* The semantics of this interface depends on which API is used in SET_HW_RENDER earlier.
* This interface will be used when the frontend is trying to create a HW rendering context,
* so it will be used after SET_HW_RENDER, but before the context_reset callback.
*/
/* Serialized state is incomplete in some way. Set if serialization is /* Serialized state is incomplete in some way. Set if serialization is
* usable in typical end-user cases but should not be relied upon to * usable in typical end-user cases but should not be relied upon to
@ -1277,20 +1513,17 @@ struct retro_hw_render_context_negotiation_interface
* dependence */ * dependence */
#define RETRO_SERIALIZATION_QUIRK_PLATFORM_DEPENDENT (1 << 6) #define RETRO_SERIALIZATION_QUIRK_PLATFORM_DEPENDENT (1 << 6)
#define RETRO_ENVIRONMENT_SET_SERIALIZATION_QUIRKS 44 #define RETRO_MEMDESC_CONST (1 << 0) /* The frontend will never change this memory area once retro_load_game has returned. */
/* uint64_t * -- #define RETRO_MEMDESC_BIGENDIAN (1 << 1) /* The memory area contains big endian data. Default is little endian. */
* Sets quirk flags associated with serialization. The frontend will zero any flags it doesn't #define RETRO_MEMDESC_SYSTEM_RAM (1 << 2) /* The memory area is system RAM. This is main RAM of the gaming system. */
* recognize or support. Should be set in either retro_init or retro_load_game, but not both. #define RETRO_MEMDESC_SAVE_RAM (1 << 3) /* The memory area is save RAM. This RAM is usually found on a game cartridge, backed up by a battery. */
*/ #define RETRO_MEMDESC_VIDEO_RAM (1 << 4) /* The memory area is video RAM (VRAM) */
#define RETRO_MEMDESC_ALIGN_2 (1 << 16) /* All memory access in this area is aligned to their own size, or 2, whichever is smaller. */
#define RETRO_MEMDESC_CONST (1 << 0) /* The frontend will never change this memory area once retro_load_game has returned. */ #define RETRO_MEMDESC_ALIGN_4 (2 << 16)
#define RETRO_MEMDESC_BIGENDIAN (1 << 1) /* The memory area contains big endian data. Default is little endian. */ #define RETRO_MEMDESC_ALIGN_8 (3 << 16)
#define RETRO_MEMDESC_ALIGN_2 (1 << 16) /* All memory access in this area is aligned to their own size, or 2, whichever is smaller. */ #define RETRO_MEMDESC_MINSIZE_2 (1 << 24) /* All memory in this region is accessed at least 2 bytes at the time. */
#define RETRO_MEMDESC_ALIGN_4 (2 << 16) #define RETRO_MEMDESC_MINSIZE_4 (2 << 24)
#define RETRO_MEMDESC_ALIGN_8 (3 << 16) #define RETRO_MEMDESC_MINSIZE_8 (3 << 24)
#define RETRO_MEMDESC_MINSIZE_2 (1 << 24) /* All memory in this region is accessed at least 2 bytes at the time. */
#define RETRO_MEMDESC_MINSIZE_4 (2 << 24)
#define RETRO_MEMDESC_MINSIZE_8 (3 << 24)
struct retro_memory_descriptor struct retro_memory_descriptor
{ {
uint64_t flags; uint64_t flags;
@ -2190,17 +2423,26 @@ struct retro_system_info
* Typically used for a GUI to filter * Typically used for a GUI to filter
* out extensions. */ * out extensions. */
/* If true, retro_load_game() is guaranteed to provide a valid pathname /* Libretro cores that need to have direct access to their content
* in retro_game_info::path. * files, including cores which use the path of the content files to
* ::data and ::size are both invalid. * determine the paths of other files, should set need_fullpath to true.
* *
* If false, ::data and ::size are guaranteed to be valid, but ::path * Cores should strive for setting need_fullpath to false,
* might not be valid. * as it allows the frontend to perform patching, etc.
* *
* This is typically set to true for libretro implementations that must * If need_fullpath is true and retro_load_game() is called:
* load from file. * - retro_game_info::path is guaranteed to have a valid path
* Implementations should strive for setting this to false, as it allows * - retro_game_info::data and retro_game_info::size are invalid
* the frontend to perform patching, etc. */ *
* If need_fullpath is false and retro_load_game() is called:
* - retro_game_info::path may be NULL
* - retro_game_info::data and retro_game_info::size are guaranteed
* to be valid
*
* See also:
* - RETRO_ENVIRONMENT_GET_SYSTEM_DIRECTORY
* - RETRO_ENVIRONMENT_GET_SAVE_DIRECTORY
*/
bool need_fullpath; bool need_fullpath;
/* If true, the frontend is not allowed to extract any archives before /* If true, the frontend is not allowed to extract any archives before
@ -2251,6 +2493,64 @@ struct retro_variable
const char *value; const char *value;
}; };
struct retro_core_option_display
{
/* Variable to configure in RETRO_ENVIRONMENT_SET_CORE_OPTIONS_DISPLAY */
const char *key;
/* Specifies whether variable should be displayed
* when presenting core options to the user */
bool visible;
};
/* Maximum number of values permitted for a core option
* NOTE: This may be increased on a core-by-core basis
* if required (doing so has no effect on the frontend) */
#define RETRO_NUM_CORE_OPTION_VALUES_MAX 128
struct retro_core_option_value
{
/* Expected option value */
const char *value;
/* Human-readable value label. If NULL, value itself
* will be displayed by the frontend */
const char *label;
};
struct retro_core_option_definition
{
/* Variable to query in RETRO_ENVIRONMENT_GET_VARIABLE. */
const char *key;
/* Human-readable core option description (used as menu label) */
const char *desc;
/* Human-readable core option information (used as menu sublabel) */
const char *info;
/* Array of retro_core_option_value structs, terminated by NULL */
struct retro_core_option_value values[RETRO_NUM_CORE_OPTION_VALUES_MAX];
/* Default core option value. Must match one of the values
* in the retro_core_option_value array, otherwise will be
* ignored */
const char *default_value;
};
struct retro_core_options_intl
{
/* Pointer to an array of retro_core_option_definition structs
* - US English implementation
* - Must point to a valid array */
struct retro_core_option_definition *us;
/* Pointer to an array of retro_core_option_definition structs
* - Implementation for current frontend language
* - May be NULL */
struct retro_core_option_definition *local;
};
struct retro_game_info struct retro_game_info
{ {
const char *path; /* Path to game, UTF-8 encoded. const char *path; /* Path to game, UTF-8 encoded.
@ -2423,7 +2723,7 @@ RETRO_API bool retro_unserialize(const void *data, size_t size);
RETRO_API void retro_cheat_reset(void); RETRO_API void retro_cheat_reset(void);
RETRO_API void retro_cheat_set(unsigned index, bool enabled, const char *code); RETRO_API void retro_cheat_set(unsigned index, bool enabled, const char *code);
/* Loads a game. /* Loads a game.
* Return true to indicate successful loading and false to indicate load failure. * Return true to indicate successful loading and false to indicate load failure.
*/ */
RETRO_API bool retro_load_game(const struct retro_game_info *game); RETRO_API bool retro_load_game(const struct retro_game_info *game);

View File

@ -0,0 +1,87 @@
/* Copyright (C) 2010-2018 The RetroArch team
*
* ---------------------------------------------------------------------------------------
* The following license statement only applies to this file (dir_list.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_DIR_LIST_H
#define __LIBRETRO_SDK_DIR_LIST_H
#include <retro_common_api.h>
#include <lists/string_list.h>
RETRO_BEGIN_DECLS
/**
* dir_list_append:
* @list : existing list to append to.
* @dir : directory path.
* @ext : allowed extensions of file directory entries to include.
* @include_dirs : include directories as part of the finished directory listing?
* @include_hidden : include hidden files and directories as part of the finished directory listing?
* @include_compressed : Only include files which match ext. Do not try to match compressed files, etc.
* @recursive : list directory contents recursively
*
* Create a directory listing, appending to an existing list
*
* Returns: true success, false in case of error.
**/
bool dir_list_append(struct string_list *list, const char *dir, const char *ext,
bool include_dirs, bool include_hidden, bool include_compressed, bool recursive);
/**
* dir_list_new:
* @dir : directory path.
* @ext : allowed extensions of file directory entries to include.
* @include_dirs : include directories as part of the finished directory listing?
* @include_hidden : include hidden files and directories as part of the finished directory listing?
* @include_compressed : include compressed files, even when not part of ext.
* @recursive : list directory contents recursively
*
* Create a directory listing.
*
* Returns: pointer to a directory listing of type 'struct string_list *' on success,
* NULL in case of error. Has to be freed manually.
**/
struct string_list *dir_list_new(const char *dir, const char *ext,
bool include_dirs, bool include_hidden, bool include_compressed, bool recursive);
/**
* dir_list_sort:
* @list : pointer to the directory listing.
* @dir_first : move the directories in the listing to the top?
*
* Sorts a directory listing.
*
**/
void dir_list_sort(struct string_list *list, bool dir_first);
/**
* dir_list_free:
* @list : pointer to the directory listing
*
* Frees a directory listing.
*
**/
void dir_list_free(struct string_list *list);
RETRO_END_DECLS
#endif

View File

@ -0,0 +1,162 @@
/* Copyright (C) 2010-2018 The RetroArch team
*
* ---------------------------------------------------------------------------------------
* The following license statement only applies to this file (string_list.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_STRING_LIST_H
#define __LIBRETRO_SDK_STRING_LIST_H
#include <retro_common_api.h>
#include <boolean.h>
#include <stdlib.h>
#include <stddef.h>
RETRO_BEGIN_DECLS
union string_list_elem_attr
{
bool b;
int i;
void *p;
};
struct string_list_elem
{
char *data;
union string_list_elem_attr attr;
};
struct string_list
{
struct string_list_elem *elems;
size_t size;
size_t cap;
};
/**
* string_list_find_elem:
* @list : pointer to string list
* @elem : element to find inside the string list.
*
* Searches for an element (@elem) inside the string list.
*
* Returns: true (1) if element could be found, otherwise false (0).
*/
int string_list_find_elem(const struct string_list *list, const char *elem);
/**
* string_list_find_elem_prefix:
* @list : pointer to string list
* @prefix : prefix to append to @elem
* @elem : element to find inside the string list.
*
* Searches for an element (@elem) inside the string list. Will
* also search for the same element prefixed by @prefix.
*
* Returns: true (1) if element could be found, otherwise false (0).
*/
bool string_list_find_elem_prefix(const struct string_list *list,
const char *prefix, const char *elem);
/**
* string_split:
* @str : string to turn into a string list
* @delim : delimiter character to use for splitting the string.
*
* Creates a new string list based on string @str, delimited by @delim.
*
* Returns: new string list if successful, otherwise NULL.
*/
struct string_list *string_split(const char *str, const char *delim);
/**
* string_list_new:
*
* Creates a new string list. Has to be freed manually.
*
* Returns: new string list if successful, otherwise NULL.
*/
struct string_list *string_list_new(void);
/**
* string_list_append:
* @list : pointer to string list
* @elem : element to add to the string list
* @attr : attributes of new element.
*
* Appends a new element to the string list.
*
* Returns: true (1) if successful, otherwise false (0).
**/
bool string_list_append(struct string_list *list, const char *elem,
union string_list_elem_attr attr);
/**
* string_list_append_n:
* @list : pointer to string list
* @elem : element to add to the string list
* @length : read at most this many bytes from elem
* @attr : attributes of new element.
*
* Appends a new element to the string list.
*
* Returns: true (1) if successful, otherwise false (0).
**/
bool string_list_append_n(struct string_list *list, const char *elem,
unsigned length, union string_list_elem_attr attr);
/**
* string_list_free
* @list : pointer to string list object
*
* Frees a string list.
*/
void string_list_free(struct string_list *list);
/**
* string_list_join_concat:
* @buffer : buffer that @list will be joined to.
* @size : length of @buffer.
* @list : pointer to string list.
* @delim : delimiter character for @list.
*
* A string list will be joined/concatenated as a
* string to @buffer, delimited by @delim.
*/
void string_list_join_concat(char *buffer, size_t size,
const struct string_list *list, const char *sep);
/**
* string_list_set:
* @list : pointer to string list
* @idx : index of element in string list
* @str : value for the element.
*
* Set value of element inside string list.
**/
void string_list_set(struct string_list *list, unsigned idx,
const char *str);
struct string_list *string_list_clone(const struct string_list *src);
RETRO_END_DECLS
#endif

View File

@ -0,0 +1,40 @@
/* Copyright (C) 2010-2018 The RetroArch team
*
* ---------------------------------------------------------------------------------------
* The following license statement only applies to this file (memalign.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_MEMALIGN_H
#define _LIBRETRO_MEMALIGN_H
#include <stddef.h>
#include <retro_common_api.h>
RETRO_BEGIN_DECLS
void *memalign_alloc(size_t boundary, size_t size);
void *memalign_alloc_aligned(size_t size);
void memalign_free(void *ptr);
RETRO_END_DECLS
#endif

View File

@ -26,7 +26,7 @@
#include <stdio.h> #include <stdio.h>
#include <stdint.h> #include <stdint.h>
#if defined(__CELLOS_LV2__) || defined(PSP) || defined(GEKKO) || defined(VITA) || defined(_XBOX) || defined(_3DS) || defined(WIIU) || defined(SWITCH) #if defined(__CELLOS_LV2__) || defined(PSP) || defined(PS2) || defined(GEKKO) || defined(VITA) || defined(_XBOX) || defined(_3DS) || defined(WIIU) || defined(SWITCH)
/* No mman available */ /* No mman available */
#elif defined(_WIN32) && !defined(_XBOX) #elif defined(_WIN32) && !defined(_XBOX)
#include <windows.h> #include <windows.h>

View File

@ -0,0 +1,37 @@
/* Copyright (C) 2010-2018 The RetroArch team
*
* ---------------------------------------------------------------------------------------
* The following license statement only applies to this file (retro_assert.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 __RETRO_ASSERT_H
#define __RETRO_ASSERT_H
#include <assert.h>
#ifdef RARCH_INTERNAL
#include <stdio.h>
#define retro_assert(cond) do { \
if (!(cond)) { printf("Assertion failed at %s:%d.\n", __FILE__, __LINE__); abort(); } \
} while(0)
#else
#define retro_assert(cond) assert(cond)
#endif
#endif

View File

@ -34,4 +34,3 @@ in a public API, you may need this.
#include <compat/msvc.h> #include <compat/msvc.h>
#endif #endif

View File

@ -113,6 +113,5 @@ Of course, another school of thought is that you should do as little damage as p
in as few places as possible... in as few places as possible...
*/ */
/* _LIBRETRO_COMMON_RETRO_COMMON_API_H */ /* _LIBRETRO_COMMON_RETRO_COMMON_API_H */
#endif #endif

View File

@ -0,0 +1,78 @@
/* Copyright (C) 2010-2019 The RetroArch team
*
* ---------------------------------------------------------------------------------------
* The following license statement only applies to this file (retro_dirent.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 __RETRO_DIRENT_H
#define __RETRO_DIRENT_H
#include <libretro.h>
#include <retro_common_api.h>
#include <retro_miscellaneous.h>
#include <boolean.h>
RETRO_BEGIN_DECLS
#define DIRENT_REQUIRED_VFS_VERSION 3
void dirent_vfs_init(const struct retro_vfs_interface_info* vfs_info);
typedef struct RDIR RDIR;
/**
*
* retro_opendir:
* @name : path to the directory to open.
*
* Opens a directory for reading. Tidy up with retro_closedir.
*
* Returns: RDIR pointer on success, NULL if name is not a
* valid directory, null itself or the empty string.
*/
struct RDIR *retro_opendir(const char *name);
struct RDIR *retro_opendir_include_hidden(const char *name, bool include_hidden);
int retro_readdir(struct RDIR *rdir);
/* Deprecated, returns false, left for compatibility */
bool retro_dirent_error(struct RDIR *rdir);
const char *retro_dirent_get_name(struct RDIR *rdir);
/**
*
* retro_dirent_is_dir:
* @rdir : pointer to the directory entry.
* @unused : deprecated, included for compatibility reasons, pass NULL
*
* Is the directory listing entry a directory?
*
* Returns: true if directory listing entry is
* a directory, false if not.
*/
bool retro_dirent_is_dir(struct RDIR *rdir, const char *unused);
void retro_closedir(struct RDIR *rdir);
RETRO_END_DECLS
#endif

View File

@ -0,0 +1,258 @@
/* Copyright (C) 2010-2018 The RetroArch team
*
* ---------------------------------------------------------------------------------------
* The following license statement only applies to this file (retro_endianness.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_ENDIANNESS_H
#define __LIBRETRO_SDK_ENDIANNESS_H
#include <retro_inline.h>
#include <stdint.h>
#include <stdlib.h>
#if defined(_MSC_VER) && _MSC_VER > 1200
#define SWAP16 _byteswap_ushort
#define SWAP32 _byteswap_ulong
#else
#define SWAP16(x) ((uint16_t)( \
(((uint16_t)(x) & 0x00ff) << 8) | \
(((uint16_t)(x) & 0xff00) >> 8) \
))
#define SWAP32(x) ((uint32_t)( \
(((uint32_t)(x) & 0x000000ff) << 24) | \
(((uint32_t)(x) & 0x0000ff00) << 8) | \
(((uint32_t)(x) & 0x00ff0000) >> 8) | \
(((uint32_t)(x) & 0xff000000) >> 24) \
))
#endif
#if defined(_MSC_VER) && _MSC_VER <= 1200
#define SWAP64(val) \
((((uint64_t)(val) & 0x00000000000000ff) << 56) \
| (((uint64_t)(val) & 0x000000000000ff00) << 40) \
| (((uint64_t)(val) & 0x0000000000ff0000) << 24) \
| (((uint64_t)(val) & 0x00000000ff000000) << 8) \
| (((uint64_t)(val) & 0x000000ff00000000) >> 8) \
| (((uint64_t)(val) & 0x0000ff0000000000) >> 24) \
| (((uint64_t)(val) & 0x00ff000000000000) >> 40) \
| (((uint64_t)(val) & 0xff00000000000000) >> 56))
#else
#define SWAP64(val) \
((((uint64_t)(val) & 0x00000000000000ffULL) << 56) \
| (((uint64_t)(val) & 0x000000000000ff00ULL) << 40) \
| (((uint64_t)(val) & 0x0000000000ff0000ULL) << 24) \
| (((uint64_t)(val) & 0x00000000ff000000ULL) << 8) \
| (((uint64_t)(val) & 0x000000ff00000000ULL) >> 8) \
| (((uint64_t)(val) & 0x0000ff0000000000ULL) >> 24) \
| (((uint64_t)(val) & 0x00ff000000000000ULL) >> 40) \
| (((uint64_t)(val) & 0xff00000000000000ULL) >> 56))
#endif
/**
* is_little_endian:
*
* Checks if the system is little endian or big-endian.
*
* Returns: greater than 0 if little-endian,
* otherwise big-endian.
**/
#if defined(MSB_FIRST)
#define is_little_endian() (0)
#elif defined(__x86_64) || defined(__i386) || defined(_M_IX86) || defined(_M_X64)
#define is_little_endian() (1)
#else
static INLINE uint8_t is_little_endian(void)
{
union
{
uint16_t x;
uint8_t y[2];
} u;
u.x = 1;
return u.y[0];
}
#endif
/**
* swap_if_big64:
* @val : unsigned 64-bit value
*
* Byteswap unsigned 64-bit value if system is big-endian.
*
* Returns: Byteswapped value in case system is big-endian,
* otherwise returns same value.
**/
#if defined(MSB_FIRST)
#define swap_if_big64(val) (SWAP64(val))
#elif defined(__x86_64) || defined(__i386) || defined(_M_IX86) || defined(_M_X64)
#define swap_if_big64(val) (val)
#else
static INLINE uint64_t swap_if_big64(uint64_t val)
{
if (is_little_endian())
return val;
return SWAP64(val);
}
#endif
/**
* swap_if_big32:
* @val : unsigned 32-bit value
*
* Byteswap unsigned 32-bit value if system is big-endian.
*
* Returns: Byteswapped value in case system is big-endian,
* otherwise returns same value.
**/
#if defined(MSB_FIRST)
#define swap_if_big32(val) (SWAP32(val))
#elif defined(__x86_64) || defined(__i386) || defined(_M_IX86) || defined(_M_X64)
#define swap_if_big32(val) (val)
#else
static INLINE uint32_t swap_if_big32(uint32_t val)
{
if (is_little_endian())
return val;
return SWAP32(val);
}
#endif
/**
* swap_if_little64:
* @val : unsigned 64-bit value
*
* Byteswap unsigned 64-bit value if system is little-endian.
*
* Returns: Byteswapped value in case system is little-endian,
* otherwise returns same value.
**/
#if defined(MSB_FIRST)
#define swap_if_little64(val) (val)
#elif defined(__x86_64) || defined(__i386) || defined(_M_IX86) || defined(_M_X64)
#define swap_if_little64(val) (SWAP64(val))
#else
static INLINE uint64_t swap_if_little64(uint64_t val)
{
if (is_little_endian())
return SWAP64(val);
return val;
}
#endif
/**
* swap_if_little32:
* @val : unsigned 32-bit value
*
* Byteswap unsigned 32-bit value if system is little-endian.
*
* Returns: Byteswapped value in case system is little-endian,
* otherwise returns same value.
**/
#if defined(MSB_FIRST)
#define swap_if_little32(val) (val)
#elif defined(__x86_64) || defined(__i386) || defined(_M_IX86) || defined(_M_X64)
#define swap_if_little32(val) (SWAP32(val))
#else
static INLINE uint32_t swap_if_little32(uint32_t val)
{
if (is_little_endian())
return SWAP32(val);
return val;
}
#endif
/**
* swap_if_big16:
* @val : unsigned 16-bit value
*
* Byteswap unsigned 16-bit value if system is big-endian.
*
* Returns: Byteswapped value in case system is big-endian,
* otherwise returns same value.
**/
#if defined(MSB_FIRST)
#define swap_if_big16(val) (SWAP16(val))
#elif defined(__x86_64) || defined(__i386) || defined(_M_IX86) || defined(_M_X64)
#define swap_if_big16(val) (val)
#else
static INLINE uint16_t swap_if_big16(uint16_t val)
{
if (is_little_endian())
return val;
return SWAP16(val);
}
#endif
/**
* swap_if_little16:
* @val : unsigned 16-bit value
*
* Byteswap unsigned 16-bit value if system is little-endian.
*
* Returns: Byteswapped value in case system is little-endian,
* otherwise returns same value.
**/
#if defined(MSB_FIRST)
#define swap_if_little16(val) (val)
#elif defined(__x86_64) || defined(__i386) || defined(_M_IX86) || defined(_M_X64)
#define swap_if_little16(val) (SWAP16(val))
#else
static INLINE uint16_t swap_if_little16(uint16_t val)
{
if (is_little_endian())
return SWAP16(val);
return val;
}
#endif
/**
* store32be:
* @addr : pointer to unsigned 32-bit buffer
* @data : unsigned 32-bit value to write
*
* Write data to address. Endian-safe. Byteswaps the data
* first if necessary before storing it.
**/
static INLINE void store32be(uint32_t *addr, uint32_t data)
{
*addr = swap_if_little32(data);
}
/**
* load32be:
* @addr : pointer to unsigned 32-bit buffer
*
* Load value from address. Endian-safe.
*
* Returns: value from address, byte-swapped if necessary.
**/
static INLINE uint32_t load32be(const uint32_t *addr)
{
return swap_if_little32(*addr);
}
#endif

View File

@ -101,6 +101,14 @@ printf("This is C++, version %d.\n", __cplusplus);
#define __WINRT__ 1 #define __WINRT__ 1
#endif #endif
/* MSVC obviously has to have some non-standard constants... */
#if _M_IX86_FP == 1
#define __SSE__ 1
#elif _M_IX86_FP == 2 || (defined(_M_AMD64) || defined(_M_X64))
#define __SSE__ 1
#define __SSE2__ 1
#endif #endif
#endif #endif
#endif

View File

@ -0,0 +1,94 @@
/* Copyright (C) 2010-2018 The RetroArch team
*
* ---------------------------------------------------------------------------------------
* The following license statement only applies to this file (retro_math.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_COMMON_MATH_H
#define _LIBRETRO_COMMON_MATH_H
#include <stdint.h>
#if defined(_WIN32) && !defined(_XBOX)
#define WIN32_LEAN_AND_MEAN
#include <windows.h>
#elif defined(_WIN32) && defined(_XBOX)
#include <Xtl.h>
#endif
#include <limits.h>
#ifdef _MSC_VER
#include <compat/msvc.h>
#endif
#include <retro_inline.h>
#ifndef M_PI
#if !defined(USE_MATH_DEFINES)
#define M_PI 3.14159265358979323846264338327
#endif
#endif
#ifndef MAX
#define MAX(a, b) ((a) > (b) ? (a) : (b))
#endif
#ifndef MIN
#define MIN(a, b) ((a) < (b) ? (a) : (b))
#endif
/**
* next_pow2:
* @v : initial value
*
* Get next power of 2 value based on initial value.
*
* Returns: next power of 2 value (derived from @v).
**/
static INLINE uint32_t next_pow2(uint32_t v)
{
v--;
v |= v >> 1;
v |= v >> 2;
v |= v >> 4;
v |= v >> 8;
v |= v >> 16;
v++;
return v;
}
/**
* prev_pow2:
* @v : initial value
*
* Get previous power of 2 value based on initial value.
*
* Returns: previous power of 2 value (derived from @v).
**/
static INLINE uint32_t prev_pow2(uint32_t v)
{
v |= v >> 1;
v |= v >> 2;
v |= v >> 4;
v |= v >> 8;
v |= v >> 16;
return v - (v >> 1);
}
#endif

View File

@ -77,7 +77,7 @@ static INLINE bool bits_any_set(uint32_t* ptr, uint32_t count)
#ifndef PATH_MAX_LENGTH #ifndef PATH_MAX_LENGTH
#if defined(__CELLOS_LV2__) #if defined(__CELLOS_LV2__)
#define PATH_MAX_LENGTH CELL_FS_MAX_FS_PATH_LENGTH #define PATH_MAX_LENGTH CELL_FS_MAX_FS_PATH_LENGTH
#elif defined(_XBOX1) || defined(_3DS) || defined(PSP) || defined(GEKKO)|| defined(WIIU) #elif defined(_XBOX1) || defined(_3DS) || defined(PSP) || defined(PS2) || defined(GEKKO)|| defined(WIIU) || defined(ORBIS)
#define PATH_MAX_LENGTH 512 #define PATH_MAX_LENGTH 512
#else #else
#define PATH_MAX_LENGTH 4096 #define PATH_MAX_LENGTH 4096
@ -159,14 +159,24 @@ typedef struct
# ifdef _WIN64 # ifdef _WIN64
# define PRI_SIZET PRIu64 # define PRI_SIZET PRIu64
# else # else
#if _MSC_VER == 1800 # if _MSC_VER == 1800
# define PRI_SIZET PRIu32 # define PRI_SIZET PRIu32
#else # else
# define PRI_SIZET "u" # define PRI_SIZET "u"
#endif # endif
# endif # endif
#elif PS2
# define PRI_SIZET "u"
#else #else
# define PRI_SIZET "zu" # if (SIZE_MAX == 0xFFFF)
# define PRI_SIZET "hu"
# elif (SIZE_MAX == 0xFFFFFFFF)
# define PRI_SIZET "u"
# elif (SIZE_MAX == 0xFFFFFFFFFFFFFFFF)
# define PRI_SIZET "lu"
# else
# error PRI_SIZET: unknown SIZE_MAX
# endif
#endif #endif
#endif #endif

View File

@ -37,6 +37,8 @@
#include <pspthreadman.h> #include <pspthreadman.h>
#elif defined(VITA) #elif defined(VITA)
#include <psp2/kernel/threadmgr.h> #include <psp2/kernel/threadmgr.h>
#elif defined(PS2)
#include <SDL/SDL_timer.h>
#elif defined(_3DS) #elif defined(_3DS)
#include <3ds.h> #include <3ds.h>
#else #else
@ -89,10 +91,12 @@ static INLINE void retro_sleep(unsigned msec)
sys_timer_usleep(1000 * msec); sys_timer_usleep(1000 * msec);
#elif defined(PSP) || defined(VITA) #elif defined(PSP) || defined(VITA)
sceKernelDelayThread(1000 * msec); sceKernelDelayThread(1000 * msec);
#elif defined(PS2)
SDL_Delay(msec);
#elif defined(_3DS) #elif defined(_3DS)
svcSleepThread(1000000 * (s64)msec); svcSleepThread(1000000 * (s64)msec);
#elif defined(__WINRT__) #elif defined(__WINRT__) || defined(WINAPI_FAMILY) && WINAPI_FAMILY == WINAPI_FAMILY_PHONE_APP
/* TODO/FIXME */ SleepEx(msec, FALSE);
#elif defined(_WIN32) #elif defined(_WIN32)
Sleep(msec); Sleep(msec);
#elif defined(XENON) #elif defined(XENON)

View File

@ -36,19 +36,22 @@
#include <boolean.h> #include <boolean.h>
#include <stdarg.h> #include <stdarg.h>
#include <vfs/vfs_implementation.h>
#define FILESTREAM_REQUIRED_VFS_VERSION 1 #define FILESTREAM_REQUIRED_VFS_VERSION 2
RETRO_BEGIN_DECLS RETRO_BEGIN_DECLS
typedef struct RFILE RFILE; typedef struct RFILE RFILE;
#define FILESTREAM_REQUIRED_VFS_VERSION 1 #define FILESTREAM_REQUIRED_VFS_VERSION 2
void filestream_vfs_init(const struct retro_vfs_interface_info* vfs_info); void filestream_vfs_init(const struct retro_vfs_interface_info* vfs_info);
int64_t filestream_get_size(RFILE *stream); int64_t filestream_get_size(RFILE *stream);
int64_t filestream_truncate(RFILE *stream, int64_t length);
/** /**
* filestream_open: * filestream_open:
* @path : path to file * @path : path to file
@ -104,6 +107,8 @@ bool filestream_exists(const char *path);
char *filestream_getline(RFILE *stream); char *filestream_getline(RFILE *stream);
libretro_vfs_implementation_file* filestream_get_vfs_handle(RFILE *stream);
RETRO_END_DECLS RETRO_END_DECLS
#endif #endif

View File

@ -30,6 +30,8 @@
RETRO_BEGIN_DECLS RETRO_BEGIN_DECLS
#ifndef SKIP_STDIO_REDEFINES
#define FILE RFILE #define FILE RFILE
#undef fopen #undef fopen
@ -41,9 +43,11 @@ RETRO_BEGIN_DECLS
#undef fgetc #undef fgetc
#undef fwrite #undef fwrite
#undef fputc #undef fputc
#undef fflush
#undef fprintf #undef fprintf
#undef ferror #undef ferror
#undef feof #undef feof
#undef fscanf
#define fopen rfopen #define fopen rfopen
#define fclose rfclose #define fclose rfclose
@ -54,9 +58,13 @@ RETRO_BEGIN_DECLS
#define fgetc rfgetc #define fgetc rfgetc
#define fwrite rfwrite #define fwrite rfwrite
#define fputc rfputc #define fputc rfputc
#define fflush rfflush
#define fprintf rfprintf #define fprintf rfprintf
#define ferror rferror #define ferror rferror
#define feof rfeof #define feof rfeof
#define fscanf rfscanf
#endif
RFILE* rfopen(const char *path, const char *mode); RFILE* rfopen(const char *path, const char *mode);
@ -78,12 +86,16 @@ int64_t rfwrite(void const* buffer,
int rfputc(int character, RFILE * stream); int rfputc(int character, RFILE * stream);
int64_t rfflush(RFILE * stream);
int rfprintf(RFILE * stream, const char * format, ...); int rfprintf(RFILE * stream, const char * format, ...);
int rferror(RFILE* stream); int rferror(RFILE* stream);
int rfeof(RFILE* stream); int rfeof(RFILE* stream);
int rfscanf(RFILE * stream, const char * format, ...);
RETRO_END_DECLS RETRO_END_DECLS
#endif #endif

View File

@ -1,4 +1,4 @@
/* Copyright (C) 2010-2018 The RetroArch team /* Copyright (C) 2010-2019 The RetroArch team
* *
* --------------------------------------------------------------------------------------- * ---------------------------------------------------------------------------------------
* The following license statement only applies to this file (stdstring.h). * The following license statement only applies to this file (stdstring.h).
@ -37,35 +37,30 @@ RETRO_BEGIN_DECLS
static INLINE bool string_is_empty(const char *data) static INLINE bool string_is_empty(const char *data)
{ {
return (data == NULL) || (*data == '\0'); return !data || (*data == '\0');
} }
static INLINE bool string_is_equal(const char *a, const char *b) static INLINE bool string_is_equal(const char *a, const char *b)
{ {
if (!a || !b) return (a && b) ? !strcmp(a, b) : false;
return false;
while(*a && (*a == *b))
{
a++;
b++;
}
return (*(const unsigned char*)a - *(const unsigned char*)b) == 0;
} }
static INLINE bool string_is_not_equal(const char *a, const char *b) #define STRLEN_CONST(x) ((sizeof((x))-1))
{
return !string_is_equal(a, b);
}
#define string_add_pair_open(s, size) strlcat((s), " (", (size)) #define string_is_not_equal(a, b) !string_is_equal((a), (b))
#define string_add_pair_close(s, size) strlcat((s), ")", (size))
#define string_add_bracket_open(s, size) strlcat((s), "{", (size)) #define string_add_pair_open(s, size) strlcat((s), " (", (size))
#define string_add_pair_close(s, size) strlcat((s), ")", (size))
#define string_add_bracket_open(s, size) strlcat((s), "{", (size))
#define string_add_bracket_close(s, size) strlcat((s), "}", (size)) #define string_add_bracket_close(s, size) strlcat((s), "}", (size))
#define string_add_single_quote(s, size) strlcat((s), "'", (size)) #define string_add_single_quote(s, size) strlcat((s), "'", (size))
#define string_add_quote(s, size) strlcat((s), "\"", (size)) #define string_add_quote(s, size) strlcat((s), "\"", (size))
#define string_add_colon(s, size) strlcat((s), ":", (size)) #define string_add_colon(s, size) strlcat((s), ":", (size))
#define string_add_glob_open(s, size) strlcat((s), "glob('*", (size)) #define string_add_glob_open(s, size) strlcat((s), "glob('*", (size))
#define string_add_glob_close(s, size) strlcat((s), "*')", (size)) #define string_add_glob_close(s, size) strlcat((s), "*')", (size))
#define string_is_not_equal_fast(a, b, size) (memcmp(a, b, size) != 0)
#define string_is_equal_fast(a, b, size) (memcmp(a, b, size) == 0)
static INLINE void string_add_between_pairs(char *s, const char *str, static INLINE void string_add_between_pairs(char *s, const char *str,
size_t size) size_t size)
@ -75,9 +70,6 @@ static INLINE void string_add_between_pairs(char *s, const char *str,
string_add_pair_close(s, size); string_add_pair_close(s, size);
} }
#define string_is_not_equal_fast(a, b, size) (memcmp(a, b, size) != 0)
#define string_is_equal_fast(a, b, size) (memcmp(a, b, size) == 0)
static INLINE bool string_is_equal_case_insensitive(const char *a, static INLINE bool string_is_equal_case_insensitive(const char *a,
const char *b) const char *b)
{ {
@ -119,7 +111,7 @@ char *string_to_upper(char *s);
char *string_to_lower(char *s); char *string_to_lower(char *s);
char *string_ucwords(char* s); char *string_ucwords(char *s);
char *string_replace_substring(const char *in, const char *pattern, char *string_replace_substring(const char *in, const char *pattern,
const char *by); const char *by);
@ -133,7 +125,9 @@ char *string_trim_whitespace_right(char *const s);
/* Remove leading and trailing whitespaces */ /* Remove leading and trailing whitespaces */
char *string_trim_whitespace(char *const s); char *string_trim_whitespace(char *const s);
char *word_wrap(char* buffer, const char *string, int line_width, bool unicode); /* max_lines == 0 means no limit */
char *word_wrap(char *buffer, const char *string,
int line_width, bool unicode, unsigned max_lines);
RETRO_END_DECLS RETRO_END_DECLS

View File

@ -0,0 +1,111 @@
/* Copyright (C) 2010-2019 The RetroArch team
*
* ---------------------------------------------------------------------------------------
* The following license statement only applies to this file (vfs_implementation.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_H
#define __LIBRETRO_SDK_VFS_H
#include <retro_common_api.h>
#include <boolean.h>
#ifdef RARCH_INTERNAL
#ifndef VFS_FRONTEND
#define VFS_FRONTEND
#endif
#endif
RETRO_BEGIN_DECLS
#ifdef _WIN32
typedef void* HANDLE;
#endif
#ifdef HAVE_CDROM
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;
unsigned last_frame_lba;
unsigned char last_frame[2352];
bool last_frame_valid;
} vfs_cdrom_t;
#endif
enum vfs_scheme
{
VFS_SCHEME_NONE = 0,
VFS_SCHEME_CDROM
};
#ifndef __WINRT__
#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
};
#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
* for VFS and as fallbacks for when the front end does not provide VFS functionality.
*/
#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
#ifdef VFS_FRONTEND
typedef struct retro_vfs_dir_handle libretro_vfs_implementation_dir;
#else
typedef struct libretro_vfs_implementation_dir libretro_vfs_implementation_dir;
#endif
RETRO_END_DECLS
#endif

View File

@ -1,4 +1,4 @@
/* Copyright (C) 2010-2018 The RetroArch team /* Copyright (C) 2010-2019 The RetroArch team
* *
* --------------------------------------------------------------------------------------- * ---------------------------------------------------------------------------------------
* The following license statement only applies to this file (vfs_implementation.h). * The following license statement only applies to this file (vfs_implementation.h).
@ -23,20 +23,13 @@
#ifndef __LIBRETRO_SDK_VFS_IMPLEMENTATION_H #ifndef __LIBRETRO_SDK_VFS_IMPLEMENTATION_H
#define __LIBRETRO_SDK_VFS_IMPLEMENTATION_H #define __LIBRETRO_SDK_VFS_IMPLEMENTATION_H
#include <stdio.h>
#include <stdint.h> #include <stdint.h>
#include <libretro.h> #include <libretro.h>
#include <retro_environment.h>
#include <vfs/vfs.h>
/* Replace the following symbol with something appropriate RETRO_BEGIN_DECLS
* 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
* for VFS and as fallbacks for when the front end does not provide VFS functionality.
*/
#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
libretro_vfs_implementation_file *retro_vfs_file_open_impl(const char *path, unsigned mode, unsigned hints); libretro_vfs_implementation_file *retro_vfs_file_open_impl(const char *path, unsigned mode, unsigned hints);
@ -46,6 +39,8 @@ int retro_vfs_file_error_impl(libretro_vfs_implementation_file *stream);
int64_t retro_vfs_file_size_impl(libretro_vfs_implementation_file *stream); int64_t retro_vfs_file_size_impl(libretro_vfs_implementation_file *stream);
int64_t retro_vfs_file_truncate_impl(libretro_vfs_implementation_file *stream, int64_t length);
int64_t retro_vfs_file_tell_impl(libretro_vfs_implementation_file *stream); int64_t retro_vfs_file_tell_impl(libretro_vfs_implementation_file *stream);
int64_t retro_vfs_file_seek_impl(libretro_vfs_implementation_file *stream, int64_t offset, int seek_position); int64_t retro_vfs_file_seek_impl(libretro_vfs_implementation_file *stream, int64_t offset, int seek_position);
@ -62,4 +57,20 @@ int retro_vfs_file_rename_impl(const char *old_path, const char *new_path);
const char *retro_vfs_file_get_path_impl(libretro_vfs_implementation_file *stream); const char *retro_vfs_file_get_path_impl(libretro_vfs_implementation_file *stream);
int retro_vfs_stat_impl(const char *path, int32_t *size);
int retro_vfs_mkdir_impl(const char *dir);
libretro_vfs_implementation_dir *retro_vfs_opendir_impl(const char *dir, bool include_hidden);
bool retro_vfs_readdir_impl(libretro_vfs_implementation_dir *dirstream);
const char *retro_vfs_dirent_get_name_impl(libretro_vfs_implementation_dir *dirstream);
bool retro_vfs_dirent_is_dir_impl(libretro_vfs_implementation_dir *dirstream);
int retro_vfs_closedir_impl(libretro_vfs_implementation_dir *dirstream);
RETRO_END_DECLS
#endif #endif

View File

@ -0,0 +1,52 @@
/* 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 <vfs/vfs.h>
#include <cdrom/cdrom.h>
RETRO_BEGIN_DECLS
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

View File

@ -0,0 +1,240 @@
/* Copyright (C) 2010-2018 The RetroArch team
*
* ---------------------------------------------------------------------------------------
* The following license statement only applies to this file (dir_list.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 <stdlib.h>
#if defined(_WIN32) && defined(_XBOX)
#include <xtl.h>
#elif defined(_WIN32)
#include <windows.h>
#endif
#include <lists/dir_list.h>
#include <lists/string_list.h>
#include <file/file_path.h>
#include <compat/strl.h>
#include <retro_dirent.h>
#include <string/stdstring.h>
#include <retro_miscellaneous.h>
static int qstrcmp_plain(const void *a_, const void *b_)
{
const struct string_list_elem *a = (const struct string_list_elem*)a_;
const struct string_list_elem *b = (const struct string_list_elem*)b_;
return strcasecmp(a->data, b->data);
}
static int qstrcmp_dir(const void *a_, const void *b_)
{
const struct string_list_elem *a = (const struct string_list_elem*)a_;
const struct string_list_elem *b = (const struct string_list_elem*)b_;
int a_type = a->attr.i;
int b_type = b->attr.i;
/* Sort directories before files. */
if (a_type != b_type)
return b_type - a_type;
return strcasecmp(a->data, b->data);
}
/**
* dir_list_sort:
* @list : pointer to the directory listing.
* @dir_first : move the directories in the listing to the top?
*
* Sorts a directory listing.
*
**/
void dir_list_sort(struct string_list *list, bool dir_first)
{
if (list)
qsort(list->elems, list->size, sizeof(struct string_list_elem),
dir_first ? qstrcmp_dir : qstrcmp_plain);
}
/**
* dir_list_free:
* @list : pointer to the directory listing
*
* Frees a directory listing.
*
**/
void dir_list_free(struct string_list *list)
{
string_list_free(list);
}
/**
* dir_list_read:
* @dir : directory path.
* @list : the string list to add files to
* @ext_list : the string list of extensions to include
* @include_dirs : include directories as part of the finished directory listing?
* @include_hidden : include hidden files and directories as part of the finished directory listing?
* @include_compressed : Only include files which match ext. Do not try to match compressed files, etc.
* @recursive : list directory contents recursively
*
* Add files within a directory to an existing string list
*
* Returns: -1 on error, 0 on success.
**/
static int dir_list_read(const char *dir,
struct string_list *list, struct string_list *ext_list,
bool include_dirs, bool include_hidden,
bool include_compressed, bool recursive)
{
struct RDIR *entry = retro_opendir_include_hidden(dir, include_hidden);
if (!entry || retro_dirent_error(entry))
goto error;
while (retro_readdir(entry))
{
union string_list_elem_attr attr;
char file_path[PATH_MAX_LENGTH];
const char *name = retro_dirent_get_name(entry);
if (!include_hidden && *name == '.')
continue;
if (!strcmp(name, ".") || !strcmp(name, ".."))
continue;
file_path[0] = '\0';
fill_pathname_join(file_path, dir, name, sizeof(file_path));
if (retro_dirent_is_dir(entry, NULL))
{
if (recursive)
dir_list_read(file_path, list, ext_list, include_dirs,
include_hidden, include_compressed, recursive);
if (!include_dirs)
continue;
attr.i = RARCH_DIRECTORY;
}
else
{
const char *file_ext = path_get_extension(name);
attr.i = RARCH_FILETYPE_UNSET;
/*
* If the file format is explicitly supported by the libretro-core, we
* need to immediately load it and not designate it as a compressed file.
*
* Example: .zip could be supported as a image by the core and as a
* compressed_file. In that case, we have to interpret it as a image.
*
* */
if (string_list_find_elem_prefix(ext_list, ".", file_ext))
attr.i = RARCH_PLAIN_FILE;
else
{
bool is_compressed_file;
if ((is_compressed_file = path_is_compressed_file(file_path)))
attr.i = RARCH_COMPRESSED_ARCHIVE;
if (ext_list &&
(!is_compressed_file || !include_compressed))
continue;
}
}
if (!string_list_append(list, file_path, attr))
goto error;
}
retro_closedir(entry);
return 0;
error:
if (entry)
retro_closedir(entry);
return -1;
}
/**
* dir_list_append:
* @list : existing list to append to.
* @dir : directory path.
* @ext : allowed extensions of file directory entries to include.
* @include_dirs : include directories as part of the finished directory listing?
* @include_hidden : include hidden files and directories as part of the finished directory listing?
* @include_compressed : Only include files which match ext. Do not try to match compressed files, etc.
* @recursive : list directory contents recursively
*
* Create a directory listing, appending to an existing list
*
* Returns: true success, false in case of error.
**/
bool dir_list_append(struct string_list *list,
const char *dir,
const char *ext, bool include_dirs,
bool include_hidden, bool include_compressed,
bool recursive)
{
struct string_list *ext_list = ext ? string_split(ext, "|") : NULL;
bool ret = dir_list_read(dir, list, ext_list,
include_dirs, include_hidden, include_compressed, recursive) != -1;
string_list_free(ext_list);
return ret;
}
/**
* dir_list_new:
* @dir : directory path.
* @ext : allowed extensions of file directory entries to include.
* @include_dirs : include directories as part of the finished directory listing?
* @include_hidden : include hidden files and directories as part of the finished directory listing?
* @include_compressed : Only include files which match ext. Do not try to match compressed files, etc.
* @recursive : list directory contents recursively
*
* Create a directory listing.
*
* Returns: pointer to a directory listing of type 'struct string_list *' on success,
* NULL in case of error. Has to be freed manually.
**/
struct string_list *dir_list_new(const char *dir,
const char *ext, bool include_dirs,
bool include_hidden, bool include_compressed,
bool recursive)
{
struct string_list *list = NULL;
if (!(list = string_list_new()))
return NULL;
if (!dir_list_append(list, dir, ext, include_dirs,
include_hidden, include_compressed, recursive))
{
string_list_free(list);
return NULL;
}
return list;
}

View File

@ -0,0 +1,363 @@
/* Copyright (C) 2010-2018 The RetroArch team
*
* ---------------------------------------------------------------------------------------
* The following license statement only applies to this file (string_list.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 <stdio.h>
#include <stdint.h>
#include <string.h>
#include <lists/string_list.h>
#include <compat/strl.h>
#include <compat/posix_string.h>
#include <string/stdstring.h>
/**
* string_list_free
* @list : pointer to string list object
*
* Frees a string list.
*/
void string_list_free(struct string_list *list)
{
size_t i;
if (!list)
return;
if (list->elems)
{
for (i = 0; i < list->size; i++)
{
if (list->elems[i].data)
free(list->elems[i].data);
list->elems[i].data = NULL;
}
free(list->elems);
}
list->elems = NULL;
free(list);
}
/**
* string_list_capacity:
* @list : pointer to string list
* @cap : new capacity for string list.
*
* Change maximum capacity of string list's size.
*
* Returns: true (1) if successful, otherwise false (0).
**/
static bool string_list_capacity(struct string_list *list, size_t cap)
{
struct string_list_elem *new_data = (struct string_list_elem*)
realloc(list->elems, cap * sizeof(*new_data));
if (!new_data)
return false;
if (cap > list->cap)
memset(&new_data[list->cap], 0, sizeof(*new_data) * (cap - list->cap));
list->elems = new_data;
list->cap = cap;
return true;
}
/**
* string_list_new:
*
* Creates a new string list. Has to be freed manually.
*
* Returns: new string list if successful, otherwise NULL.
*/
struct string_list *string_list_new(void)
{
struct string_list *list = (struct string_list*)
calloc(1, sizeof(*list));
if (!list)
return NULL;
if (!string_list_capacity(list, 32))
{
string_list_free(list);
return NULL;
}
return list;
}
/**
* string_list_append:
* @list : pointer to string list
* @elem : element to add to the string list
* @attr : attributes of new element.
*
* Appends a new element to the string list.
*
* Returns: true (1) if successful, otherwise false (0).
**/
bool string_list_append(struct string_list *list, const char *elem,
union string_list_elem_attr attr)
{
char *data_dup = NULL;
if (list->size >= list->cap &&
!string_list_capacity(list, list->cap * 2))
return false;
data_dup = strdup(elem);
if (!data_dup)
return false;
list->elems[list->size].data = data_dup;
list->elems[list->size].attr = attr;
list->size++;
return true;
}
/**
* string_list_append_n:
* @list : pointer to string list
* @elem : element to add to the string list
* @length : read at most this many bytes from elem
* @attr : attributes of new element.
*
* Appends a new element to the string list.
*
* Returns: true (1) if successful, otherwise false (0).
**/
bool string_list_append_n(struct string_list *list, const char *elem,
unsigned length, union string_list_elem_attr attr)
{
char *data_dup = NULL;
if (list->size >= list->cap &&
!string_list_capacity(list, list->cap * 2))
return false;
data_dup = (char*)malloc(length + 1);
if (!data_dup)
return false;
strlcpy(data_dup, elem, length + 1);
list->elems[list->size].data = data_dup;
list->elems[list->size].attr = attr;
list->size++;
return true;
}
/**
* string_list_set:
* @list : pointer to string list
* @idx : index of element in string list
* @str : value for the element.
*
* Set value of element inside string list.
**/
void string_list_set(struct string_list *list,
unsigned idx, const char *str)
{
free(list->elems[idx].data);
list->elems[idx].data = strdup(str);
}
/**
* string_list_join_concat:
* @buffer : buffer that @list will be joined to.
* @size : length of @buffer.
* @list : pointer to string list.
* @delim : delimiter character for @list.
*
* A string list will be joined/concatenated as a
* string to @buffer, delimited by @delim.
*/
void string_list_join_concat(char *buffer, size_t size,
const struct string_list *list, const char *delim)
{
size_t i, len = strlen(buffer);
buffer += len;
size -= len;
for (i = 0; i < list->size; i++)
{
strlcat(buffer, list->elems[i].data, size);
if ((i + 1) < list->size)
strlcat(buffer, delim, size);
}
}
/**
* string_split:
* @str : string to turn into a string list
* @delim : delimiter character to use for splitting the string.
*
* Creates a new string list based on string @str, delimited by @delim.
*
* Returns: new string list if successful, otherwise NULL.
*/
struct string_list *string_split(const char *str, const char *delim)
{
char *save = NULL;
char *copy = NULL;
const char *tmp = NULL;
struct string_list *list = string_list_new();
if (!list)
goto error;
copy = strdup(str);
if (!copy)
goto error;
tmp = strtok_r(copy, delim, &save);
while (tmp)
{
union string_list_elem_attr attr;
attr.i = 0;
if (!string_list_append(list, tmp, attr))
goto error;
tmp = strtok_r(NULL, delim, &save);
}
free(copy);
return list;
error:
string_list_free(list);
free(copy);
return NULL;
}
/**
* string_list_find_elem:
* @list : pointer to string list
* @elem : element to find inside the string list.
*
* Searches for an element (@elem) inside the string list.
*
* Returns: true (1) if element could be found, otherwise false (0).
*/
int string_list_find_elem(const struct string_list *list, const char *elem)
{
size_t i;
if (!list)
return false;
for (i = 0; i < list->size; i++)
{
if (string_is_equal_noncase(list->elems[i].data, elem))
return (int)(i + 1);
}
return false;
}
/**
* string_list_find_elem_prefix:
* @list : pointer to string list
* @prefix : prefix to append to @elem
* @elem : element to find inside the string list.
*
* Searches for an element (@elem) inside the string list. Will
* also search for the same element prefixed by @prefix.
*
* Returns: true (1) if element could be found, otherwise false (0).
*/
bool string_list_find_elem_prefix(const struct string_list *list,
const char *prefix, const char *elem)
{
size_t i;
char prefixed[255];
if (!list)
return false;
prefixed[0] = '\0';
strlcpy(prefixed, prefix, sizeof(prefixed));
strlcat(prefixed, elem, sizeof(prefixed));
for (i = 0; i < list->size; i++)
{
if (string_is_equal_noncase(list->elems[i].data, elem) ||
string_is_equal_noncase(list->elems[i].data, prefixed))
return true;
}
return false;
}
struct string_list *string_list_clone(
const struct string_list *src)
{
unsigned i;
struct string_list_elem *elems = NULL;
struct string_list *dest = (struct string_list*)
calloc(1, sizeof(struct string_list));
if (!dest)
return NULL;
dest->size = src->size;
dest->cap = src->cap;
if (dest->cap < dest->size)
dest->cap = dest->size;
elems = (struct string_list_elem*)
calloc(dest->cap, sizeof(struct string_list_elem));
if (!elems)
{
free(dest);
return NULL;
}
dest->elems = elems;
for (i = 0; i < src->size; i++)
{
const char *_src = src->elems[i].data;
size_t len = _src ? strlen(_src) : 0;
dest->elems[i].data = NULL;
dest->elems[i].attr = src->elems[i].attr;
if (len != 0)
{
char *result = (char*)malloc(len + 1);
strcpy(result, _src);
dest->elems[i].data = result;
}
}
return dest;
}

View File

@ -0,0 +1,63 @@
/* Copyright (C) 2010-2018 The RetroArch team
*
* ---------------------------------------------------------------------------------------
* The following license statement only applies to this file (memalign.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 <stdint.h>
#include <stdlib.h>
#include <memalign.h>
void *memalign_alloc(size_t boundary, size_t size)
{
void **place = NULL;
uintptr_t addr = 0;
void *ptr = (void*)malloc(boundary + size + sizeof(uintptr_t));
if (!ptr)
return NULL;
addr = ((uintptr_t)ptr + sizeof(uintptr_t) + boundary)
& ~(boundary - 1);
place = (void**)addr;
place[-1] = ptr;
return (void*)addr;
}
void memalign_free(void *ptr)
{
void **p = NULL;
if (!ptr)
return;
p = (void**)ptr;
free(p[-1]);
}
void *memalign_alloc_aligned(size_t size)
{
#if defined(__x86_64__) || defined(__LP64) || defined(__IA64__) || defined(_M_X64) || defined(_M_X64) || defined(_WIN64)
return memalign_alloc(64, size);
#elif defined(__i386__) || defined(__i486__) || defined(__i686__) || defined(GEKKO) || defined(_M_IX86)
return memalign_alloc(32, size);
#else
return memalign_alloc(32, size);
#endif
}

View File

@ -41,6 +41,7 @@ static retro_vfs_get_path_t filestream_get_path_cb = NULL;
static retro_vfs_open_t filestream_open_cb = NULL; static retro_vfs_open_t filestream_open_cb = NULL;
static retro_vfs_close_t filestream_close_cb = NULL; static retro_vfs_close_t filestream_close_cb = NULL;
static retro_vfs_size_t filestream_size_cb = NULL; static retro_vfs_size_t filestream_size_cb = NULL;
static retro_vfs_truncate_t filestream_truncate_cb = NULL;
static retro_vfs_tell_t filestream_tell_cb = NULL; static retro_vfs_tell_t filestream_tell_cb = NULL;
static retro_vfs_seek_t filestream_seek_cb = NULL; static retro_vfs_seek_t filestream_seek_cb = NULL;
static retro_vfs_read_t filestream_read_cb = NULL; static retro_vfs_read_t filestream_read_cb = NULL;
@ -67,6 +68,7 @@ void filestream_vfs_init(const struct retro_vfs_interface_info* vfs_info)
filestream_close_cb = NULL; filestream_close_cb = NULL;
filestream_tell_cb = NULL; filestream_tell_cb = NULL;
filestream_size_cb = NULL; filestream_size_cb = NULL;
filestream_truncate_cb = NULL;
filestream_seek_cb = NULL; filestream_seek_cb = NULL;
filestream_read_cb = NULL; filestream_read_cb = NULL;
filestream_write_cb = NULL; filestream_write_cb = NULL;
@ -84,6 +86,7 @@ void filestream_vfs_init(const struct retro_vfs_interface_info* vfs_info)
filestream_open_cb = vfs_iface->open; filestream_open_cb = vfs_iface->open;
filestream_close_cb = vfs_iface->close; filestream_close_cb = vfs_iface->close;
filestream_size_cb = vfs_iface->size; filestream_size_cb = vfs_iface->size;
filestream_truncate_cb = vfs_iface->truncate;
filestream_tell_cb = vfs_iface->tell; filestream_tell_cb = vfs_iface->tell;
filestream_seek_cb = vfs_iface->seek; filestream_seek_cb = vfs_iface->seek;
filestream_read_cb = vfs_iface->read; filestream_read_cb = vfs_iface->read;
@ -127,6 +130,21 @@ int64_t filestream_get_size(RFILE *stream)
return output; return output;
} }
int64_t filestream_truncate(RFILE *stream, int64_t length)
{
int64_t output;
if (filestream_truncate_cb != NULL)
output = filestream_truncate_cb(stream->hfile, length);
else
output = retro_vfs_file_truncate_impl((libretro_vfs_implementation_file*)stream->hfile, length);
if (output == vfs_error_return_value)
stream->error_flag = true;
return output;
}
/** /**
* filestream_open: * filestream_open:
* @path : path to file * @path : path to file
@ -186,9 +204,9 @@ int filestream_getc(RFILE *stream)
{ {
char c = 0; char c = 0;
if (!stream) if (!stream)
return 0; return EOF;
if(filestream_read(stream, &c, 1) == 1) if (filestream_read(stream, &c, 1) == 1)
return (int)c; return (int)(unsigned char)c;
return EOF; return EOF;
} }
@ -197,37 +215,40 @@ int filestream_scanf(RFILE *stream, const char* format, ...)
char buf[4096]; char buf[4096];
char subfmt[64]; char subfmt[64];
va_list args; va_list args;
const char * bufiter = buf; const char * bufiter = buf;
int64_t startpos = filestream_tell(stream); int64_t startpos = filestream_tell(stream);
int ret = 0; int ret = 0;
int64_t maxlen = filestream_read(stream, buf, sizeof(buf)-1); int64_t maxlen = filestream_read(stream, buf, sizeof(buf)-1);
if (maxlen <= 0)
return EOF;
buf[maxlen] = '\0'; buf[maxlen] = '\0';
va_start(args, format); va_start(args, format);
while (*format) while (*format)
{ {
if (*format == '%') if (*format == '%')
{ {
int sublen; int sublen;
char* subfmtiter = subfmt; char* subfmtiter = subfmt;
bool asterisk = false; bool asterisk = false;
*subfmtiter++ = *format++; /* '%' */ *subfmtiter++ = *format++; /* '%' */
/* %[*][width][length]specifier */ /* %[*][width][length]specifier */
if (*format == '*') if (*format == '*')
{ {
asterisk = true; asterisk = true;
*subfmtiter++ = *format++; *subfmtiter++ = *format++;
} }
while (isdigit(*format)) *subfmtiter++ = *format++; /* width */ while (isdigit(*format)) *subfmtiter++ = *format++; /* width */
/* length */ /* length */
if (*format == 'h' || *format == 'l') if (*format == 'h' || *format == 'l')
{ {
@ -238,7 +259,7 @@ int filestream_scanf(RFILE *stream, const char* format, ...)
{ {
*subfmtiter++ = *format++; *subfmtiter++ = *format++;
} }
/* specifier - always a single character (except ]) */ /* specifier - always a single character (except ]) */
if (*format == '[') if (*format == '[')
{ {
@ -246,11 +267,11 @@ int filestream_scanf(RFILE *stream, const char* format, ...)
*subfmtiter++ = *format++; *subfmtiter++ = *format++;
} }
else *subfmtiter++ = *format++; else *subfmtiter++ = *format++;
*subfmtiter++ = '%'; *subfmtiter++ = '%';
*subfmtiter++ = 'n'; *subfmtiter++ = 'n';
*subfmtiter++ = '\0'; *subfmtiter++ = '\0';
if (sizeof(void*) != sizeof(long*)) abort(); /* all pointers must have the same size */ if (sizeof(void*) != sizeof(long*)) abort(); /* all pointers must have the same size */
if (asterisk) if (asterisk)
{ {
@ -260,7 +281,7 @@ int filestream_scanf(RFILE *stream, const char* format, ...)
{ {
if (sscanf(bufiter, subfmt, va_arg(args, void*), &sublen) != 1) break; if (sscanf(bufiter, subfmt, va_arg(args, void*), &sublen) != 1) break;
} }
ret++; ret++;
bufiter += sublen; bufiter += sublen;
} }
@ -277,10 +298,10 @@ int filestream_scanf(RFILE *stream, const char* format, ...)
format++; format++;
} }
} }
va_end(args); va_end(args);
filestream_seek(stream, startpos+(bufiter-buf), RETRO_VFS_SEEK_POSITION_START); filestream_seek(stream, startpos+(bufiter-buf), RETRO_VFS_SEEK_POSITION_START);
return ret; return ret;
} }
@ -305,7 +326,6 @@ int filestream_eof(RFILE *stream)
return stream->eof_flag; return stream->eof_flag;
} }
int64_t filestream_tell(RFILE *stream) int64_t filestream_tell(RFILE *stream)
{ {
int64_t output; int64_t output;
@ -407,7 +427,7 @@ int filestream_putc(RFILE *stream, int c)
char c_char = (char)c; char c_char = (char)c;
if (!stream) if (!stream)
return EOF; return EOF;
return filestream_write(stream, &c_char, 1)==1 ? c : EOF; return filestream_write(stream, &c_char, 1)==1 ? (int)(unsigned char)c : EOF;
} }
int filestream_vprintf(RFILE *stream, const char* format, va_list args) int filestream_vprintf(RFILE *stream, const char* format, va_list args)
@ -592,3 +612,8 @@ char *filestream_getline(RFILE *stream)
newline[idx] = '\0'; newline[idx] = '\0';
return newline; return newline;
} }
libretro_vfs_implementation_file* filestream_get_vfs_handle(RFILE *stream)
{
return (libretro_vfs_implementation_file*)stream->hfile;
}

View File

@ -37,7 +37,7 @@ RFILE* rfopen(const char *path, const char *mode)
retro_mode = RETRO_VFS_FILE_ACCESS_READ; retro_mode = RETRO_VFS_FILE_ACCESS_READ;
if (strstr(mode, "+")) if (strstr(mode, "+"))
{ {
retro_mode = RETRO_VFS_FILE_ACCESS_READ_WRITE | retro_mode = RETRO_VFS_FILE_ACCESS_READ_WRITE |
RETRO_VFS_FILE_ACCESS_UPDATE_EXISTING; RETRO_VFS_FILE_ACCESS_UPDATE_EXISTING;
} }
} }
@ -49,12 +49,12 @@ RFILE* rfopen(const char *path, const char *mode)
} }
else if (strstr(mode, "a")) else if (strstr(mode, "a"))
{ {
retro_mode = RETRO_VFS_FILE_ACCESS_WRITE | retro_mode = RETRO_VFS_FILE_ACCESS_WRITE |
RETRO_VFS_FILE_ACCESS_UPDATE_EXISTING; RETRO_VFS_FILE_ACCESS_UPDATE_EXISTING;
position_to_end = true; position_to_end = true;
if (strstr(mode, "+")) if (strstr(mode, "+"))
{ {
retro_mode = RETRO_VFS_FILE_ACCESS_READ_WRITE | retro_mode = RETRO_VFS_FILE_ACCESS_READ_WRITE |
RETRO_VFS_FILE_ACCESS_UPDATE_EXISTING; RETRO_VFS_FILE_ACCESS_UPDATE_EXISTING;
} }
} }
@ -99,7 +99,7 @@ int64_t rfseek(RFILE* stream, int64_t offset, int origin)
int64_t rfread(void* buffer, int64_t rfread(void* buffer,
size_t elem_size, size_t elem_count, RFILE* stream) size_t elem_size, size_t elem_count, RFILE* stream)
{ {
return filestream_read(stream, buffer, elem_size * elem_count); return (filestream_read(stream, buffer, elem_size * elem_count) / elem_size);
} }
char *rfgets(char *buffer, int maxCount, RFILE* stream) char *rfgets(char *buffer, int maxCount, RFILE* stream)
@ -109,7 +109,7 @@ char *rfgets(char *buffer, int maxCount, RFILE* stream)
int rfgetc(RFILE* stream) int rfgetc(RFILE* stream)
{ {
return filestream_getc(stream); return filestream_getc(stream);
} }
int64_t rfwrite(void const* buffer, int64_t rfwrite(void const* buffer,
@ -123,14 +123,19 @@ int rfputc(int character, RFILE * stream)
return filestream_putc(stream, character); return filestream_putc(stream, character);
} }
int64_t rfflush(RFILE * stream)
{
return filestream_flush(stream);
}
int rfprintf(RFILE * stream, const char * format, ...) int rfprintf(RFILE * stream, const char * format, ...)
{ {
int result; int result;
va_list vl; va_list vl;
va_start(vl, format); va_start(vl, format);
result = filestream_vprintf(stream, format, vl); result = filestream_vprintf(stream, format, vl);
va_end(vl); va_end(vl);
return result; return result;
} }
int rferror(RFILE* stream) int rferror(RFILE* stream)
@ -142,3 +147,13 @@ int rfeof(RFILE* stream)
{ {
return filestream_eof(stream); return filestream_eof(stream);
} }
int rfscanf(RFILE * stream, const char * format, ...)
{
int result;
va_list vl;
va_start(vl, format);
result = filestream_scanf(stream, format, vl);
va_end(vl);
return result;
}

View File

@ -82,6 +82,10 @@ char *string_replace_substring(const char *in,
outlen = strlen(in) - pattern_len*numhits + replacement_len*numhits; outlen = strlen(in) - pattern_len*numhits + replacement_len*numhits;
out = (char *)malloc(outlen+1); out = (char *)malloc(outlen+1);
if (!out)
return NULL;
outat = out; outat = out;
inat = in; inat = in;
inprev = in; inprev = in;
@ -105,18 +109,17 @@ char *string_trim_whitespace_left(char *const s)
{ {
if(s && *s) if(s && *s)
{ {
size_t len = strlen(s); size_t len = strlen(s);
char *cur = s; char *current = s;
while(*cur && isspace((unsigned char)*cur)) while(*current && isspace((unsigned char)*current))
{ {
++cur; ++current;
--len; --len;
} }
if(s != cur) if(s != current)
memmove(s, cur, len + 1); memmove(s, current, len + 1);
} }
return s; return s;
@ -127,16 +130,16 @@ char *string_trim_whitespace_right(char *const s)
{ {
if(s && *s) if(s && *s)
{ {
size_t len = strlen(s); size_t len = strlen(s);
char *cur = s + len - 1; char *current = s + len - 1;
while(cur != s && isspace((unsigned char)*cur)) while(current != s && isspace((unsigned char)*current))
{ {
--cur; --current;
--len; --len;
} }
cur[isspace((unsigned char)*cur) ? 0 : 1] = '\0'; current[isspace((unsigned char)*current) ? 0 : 1] = '\0';
} }
return s; return s;
@ -151,14 +154,16 @@ char *string_trim_whitespace(char *const s)
return s; return s;
} }
char *word_wrap(char* buffer, const char *string, int line_width, bool unicode) char *word_wrap(char* buffer, const char *string, int line_width, bool unicode, unsigned max_lines)
{ {
unsigned i = 0; unsigned i = 0;
unsigned len = (unsigned)strlen(string); unsigned len = (unsigned)strlen(string);
unsigned lines = 1;
while (i < len) while (i < len)
{ {
unsigned counter; unsigned counter;
int pos = (int)(&buffer[i] - buffer);
/* copy string until the end of the line is reached */ /* copy string until the end of the line is reached */
for (counter = 1; counter <= (unsigned)line_width; counter++) for (counter = 1; counter <= (unsigned)line_width; counter++)
@ -190,14 +195,21 @@ char *word_wrap(char* buffer, const char *string, int line_width, bool unicode)
/* check for newlines embedded in the original input /* check for newlines embedded in the original input
* and reset the index */ * and reset the index */
if (buffer[j] == '\n') if (buffer[j] == '\n')
{
lines++;
counter = 1; counter = 1;
}
} }
/* check for whitespace */ /* check for whitespace */
if (string[i] == ' ') if (string[i] == ' ')
{ {
buffer[i] = '\n'; if ((max_lines == 0 || lines < max_lines))
i++; {
buffer[i] = '\n';
i++;
lines++;
}
} }
else else
{ {
@ -206,14 +218,18 @@ char *word_wrap(char* buffer, const char *string, int line_width, bool unicode)
/* check for nearest whitespace back in string */ /* check for nearest whitespace back in string */
for (k = i; k > 0; k--) for (k = i; k > 0; k--)
{ {
if (string[k] != ' ') if (string[k] != ' ' || (max_lines != 0 && lines >= max_lines))
continue; continue;
buffer[k] = '\n'; buffer[k] = '\n';
/* set string index back to character after this one */ /* set string index back to character after this one */
i = k + 1; i = k + 1;
lines++;
break; break;
} }
if (&buffer[i] - buffer == pos)
return buffer;
} }
} }

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,423 @@
/* 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>
#if defined(_WIN32) && !defined(_XBOX)
#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";
cdrom_lba_to_msf(new_lba, &min, &sec, &frame);
break;
}
case SEEK_END:
{
ssize_t pregap_lba_len = (vfs_cdrom_toc.track[stream->cdrom.cur_track - 1].audio ? 0 : (vfs_cdrom_toc.track[stream->cdrom.cur_track - 1].lba - vfs_cdrom_toc.track[stream->cdrom.cur_track - 1].lba_start));
ssize_t lba_len = vfs_cdrom_toc.track[stream->cdrom.cur_track - 1].track_size - pregap_lba_len;
cdrom_lba_to_msf(lba_len + lba, &min, &sec, &frame);
stream->cdrom.byte_pos = lba_len * 2352;
seek_type = "SEEK_END";
break;
}
case SEEK_SET:
default:
{
seek_type = "SEEK_SET";
stream->cdrom.byte_pos = offset;
cdrom_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 = cdrom_msf_to_lba(min, sec, frame);
#ifdef CDROM_DEBUG
printf("[CDROM] Seek %s: Path %s Offset %" PRIu64 " is now at %" PRIu64 " (MSF %02u:%02u:%02u) (LBA %u)...\n", seek_type, stream->orig_path, offset, stream->cdrom.byte_pos, (unsigned)stream->cdrom.cur_min, (unsigned)stream->cdrom.cur_sec, (unsigned)stream->cdrom.cur_frame, stream->cdrom.cur_lba);
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)
{
#if defined(__linux__) && !defined(ANDROID)
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)
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);
cdrom_get_timeouts(stream, &vfs_cdrom_toc.timeouts);
#ifdef CDROM_DEBUG
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
}
#endif
#if defined(_WIN32) && !defined(_XBOX)
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;
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);
cdrom_get_timeouts(stream, &vfs_cdrom_toc.timeouts);
#ifdef CDROM_DEBUG
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
}
#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 = cdrom_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 = cdrom_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
#if defined(_WIN32) && !defined(_XBOX)
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)
{
const char *ext = NULL;
if (!stream)
return -1;
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 ((int64_t)len < (int64_t)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;
unsigned char rmin = 0;
unsigned char rsec = 0;
unsigned char rframe = 0;
if (stream->cdrom.byte_pos >= vfs_cdrom_toc.track[stream->cdrom.cur_track - 1].track_bytes)
return 0;
if (stream->cdrom.byte_pos + len > vfs_cdrom_toc.track[stream->cdrom.cur_track - 1].track_bytes)
len -= (stream->cdrom.byte_pos + len) - vfs_cdrom_toc.track[stream->cdrom.cur_track - 1].track_bytes;
cdrom_lba_to_msf(stream->cdrom.cur_lba, &min, &sec, &frame);
cdrom_lba_to_msf(stream->cdrom.cur_lba - vfs_cdrom_toc.track[stream->cdrom.cur_track - 1].lba, &rmin, &rsec, &rframe);
#ifdef CDROM_DEBUG
printf("[CDROM] Read: Reading %" PRIu64 " bytes from %s starting at byte offset %" PRIu64 " (rMSF %02u:%02u:%02u aMSF %02u:%02u:%02u) (LBA %u) skip %" PRIu64 "...\n", len, stream->orig_path, stream->cdrom.byte_pos, (unsigned)rmin, (unsigned)rsec, (unsigned)rframe, (unsigned)min, (unsigned)sec, (unsigned)frame, stream->cdrom.cur_lba, skip);
fflush(stdout);
#endif
rv = cdrom_read(stream, &vfs_cdrom_toc.timeouts, min, sec, frame, s, (size_t)len, skip);
/*rv = cdrom_read_lba(stream, stream->cdrom.cur_lba, s, (size_t)len, skip);*/
if (rv)
{
#ifdef CDROM_DEBUG
printf("[CDROM] 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);
cdrom_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 %02u:%02u:%02u) (LBA %u)\n", len, stream->cdrom.byte_pos, (unsigned)stream->cdrom.cur_min, (unsigned)stream->cdrom.cur_sec, (unsigned)stream->cdrom.cur_frame, cdrom_msf_to_lba(stream->cdrom.cur_min, stream->cdrom.cur_sec, stream->cdrom.cur_frame));
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;
}

View File

@ -670,7 +670,13 @@ bool CDAccess_Image::ImageOpen(const std::string& path, bool image_memcache)
active_track = -1; active_track = -1;
} }
std::string efn = MDFN_EvalFIP(base_dir, args[0]); std::string efn;
if(args[0].find("cdrom://") == std::string::npos)
efn = MDFN_EvalFIP(base_dir, args[0]);
else
efn = args[0];
TmpTrack.fp = new FileStream(efn.c_str(), MODE_READ); TmpTrack.fp = new FileStream(efn.c_str(), MODE_READ);
TmpTrack.FirstFileInstance = 1; TmpTrack.FirstFileInstance = 1;