initial cdrom support

This commit is contained in:
Brad Parker 2019-07-25 21:48:23 -04:00
parent ef3ecc7612
commit 2d050ee501
46 changed files with 7122 additions and 309 deletions

View File

@ -14,15 +14,15 @@ unixcygpath = /$(subst :,,$(call unixpath,$1))
ifeq ($(platform),)
platform = unix
ifeq ($(shell uname -a),)
ifeq ($(shell uname -s),)
platform = win
else ifneq ($(findstring Darwin,$(shell uname -a)),)
else ifneq ($(findstring Darwin,$(shell uname -s)),)
platform = osx
arch = intel
ifeq ($(shell uname -p),powerpc)
arch = ppc
endif
else ifneq ($(findstring MINGW,$(shell uname -a)),)
else ifneq ($(findstring MINGW,$(shell uname -s)),)
platform = win
endif
else ifneq (,$(findstring armv,$(platform)))
@ -46,6 +46,7 @@ NEED_CRC32 = 1
WANT_NEW_API = 1
CORE_DEFINE := -DWANT_PCE_EMU -DWANT_STEREO_SOUND
HAVE_CHD = 1
HAVE_CDROM = 0
prefix := /usr
libdir := $(prefix)/lib
@ -75,6 +76,10 @@ ifneq (,$(findstring unix,$(platform)))
LDFLAGS += -lrt
endif
ifneq ($(findstring Linux,$(shell uname -s)),)
HAVE_CDROM = 1
endif
# Raspberry Pi
ifneq (,$(findstring rpi,$(platform)))
FLAGS += -fomit-frame-pointer -ffast-math
@ -356,6 +361,8 @@ else ifneq (,$(findstring windows_msvc2017,$(platform)))
VCCompilerToolsBinDir := $(VcCompilerToolsDir)\bin\HostX86
endif
HAVE_CDROM = 1
PATH := $(shell IFS=$$'\n'; cygpath "$(VCCompilerToolsBinDir)/$(TargetArchMoniker)"):$(PATH)
PATH := $(PATH):$(shell IFS=$$'\n'; cygpath "$(VsInstallRoot)/Common7/IDE")
INCLUDE := $(shell IFS=$$'\n'; cygpath -w "$(VcCompilerToolsDir)/include")
@ -387,6 +394,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.1A" -v "InstallationFolder" | grep -o '[A-Z]:\\.*')Include
HAVE_CDROM = 1
INCFLAGS_PLATFORM = -I"$(WindowsSdkDirInc)"
export INCLUDE := $(INCLUDE)
@ -412,6 +420,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.1A" -v "InstallationFolder" | grep -o '[A-Z]:\\.*')Include
HAVE_CDROM = 1
INCFLAGS_PLATFORM = -I"$(WindowsSdkDirInc)"
export INCLUDE := $(INCLUDE)
@ -434,6 +443,8 @@ BIN := $(shell IFS=$$'\n'; cygpath "$(VS80COMNTOOLS)../../VC/bin")
WindowsSdkDir := $(INETSDK)
HAVE_CDROM = 1
export INCLUDE := $(INCLUDE);$(INETSDK)/Include;libretro-common/include/compat/msvc
export LIB := $(LIB);$(WindowsSdkDir);$(INETSDK)/Lib
TARGET := $(TARGET_NAME)_libretro.dll
@ -464,6 +475,7 @@ else ifeq ($(platform), windows_msvc2003_x86)
CC = cl.exe
CXX = cl.exe
HAVE_CDROM = 1
PATH := $(shell IFS=$$'\n'; cygpath "$(VS71COMNTOOLS)../../Vc7/bin"):$(PATH)
PATH := $(PATH):$(shell IFS=$$'\n'; cygpath "$(VS71COMNTOOLS)../IDE")
INCLUDE := $(shell IFS=$$'\n'; cygpath "$(VS71COMNTOOLS)../../Vc7/include")
@ -487,6 +499,7 @@ else
CXX = g++
SHARED := -shared -Wl,--no-undefined -Wl,--version-script=link.T
LDFLAGS += -static-libgcc -static-libstdc++ -lwinmm
HAVE_CDROM = 1
WINDOWS_VERSION=1
endif
@ -549,6 +562,13 @@ ifeq ($(WANT_NEW_API), 1)
FLAGS += -DWANT_NEW_API
endif
ifeq ($(HAVE_CDROM), 1)
FLAGS += -DHAVE_CDROM
ifeq ($(CDROM_DEBUG), 1)
FLAGS += -DCDROM_DEBUG
endif
endif
CXXFLAGS += $(FLAGS)
CFLAGS += $(FLAGS)

View File

@ -20,6 +20,12 @@ ifneq (,$(findstring msvc2003,$(platform)))
INCFLAGS += -I$(LIBRETRO_COMM_DIR)/include/compat/msvc
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)
SOURCES_CXX += \
$(CORE_DIR)/libretro.cpp \
@ -209,6 +215,10 @@ ifneq ($(STATIC_LINKING), 1)
SOURCES_C += \
$(LIBRETRO_COMM_DIR)/streams/file_stream.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_snprintf.c \
$(LIBRETRO_COMM_DIR)/compat/compat_posix_string.c \
@ -217,5 +227,6 @@ SOURCES_C += \
$(LIBRETRO_COMM_DIR)/encodings/encoding_utf.c \
$(LIBRETRO_COMM_DIR)/encodings/encoding_crc32.c \
$(LIBRETRO_COMM_DIR)/vfs/vfs_implementation.c \
$(LIBRETRO_COMM_DIR)/memmap/memalign.c \
$(LIBRETRO_COMM_DIR)/string/stdstring.c
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 */
#ifdef _MSC_VER
#include <retro_common.h>
#if _MSC_VER >= 1800
#include <stdio.h> /* added for _vsnprintf_s and _vscprintf on VS2015 and VS2017 */
#endif
#include <stdio.h>
#include <stdarg.h>
#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;
if (size != 0)
{
#if (_MSC_VER <= 1310)
count = _vsnprintf(outBuf, size - 1, format, ap);
count = _vsnprintf(outBuf, size - 1, format, ap);
#else
count = _vsnprintf_s(outBuf, size, size - 1, format, ap);
count = _vsnprintf_s(outBuf, size, size - 1, format, ap);
#endif
}
if (count == -1)
count = _vscprintf(format, ap);

View File

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

View File

@ -23,6 +23,8 @@
#include <stdint.h>
#include <stddef.h>
#include <encodings/crc32.h>
#include <streams/file_stream.h>
#include <stdlib.h>
static const uint32_t crc32_table[256] = {
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;
}
#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;
}
static uint8_t utf8_walkbyte(const char **string)
{
return *((*string)++);
}
#define utf8_walkbyte(string) (*((*(string))++))
/* Does not validate the input, returns garbage if it's not UTF-8. */
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);
if (first >= 0xE0)
{
ret = (ret << 6) | (utf8_walkbyte(string) & 0x3F);
if (first >= 0xF0)
ret = (ret << 6) | (utf8_walkbyte(string) & 0x3F);
if (first >= 0xF0)
return ret | (first & 7) << 18;
if (first >= 0xE0)
if (first >= 0xF0)
{
ret = (ret << 6) | (utf8_walkbyte(string) & 0x3F);
return ret | (first & 7) << 18;
}
return ret | (first & 15) << 12;
}
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;
}
#if defined(_WIN32) && !defined(_XBOX) && !defined(UNICODE)
/* 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)
{
char *path_buf = NULL;
wchar_t *path_buf_wide = NULL;
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)
return NULL;
(void)path_buf;
(void)path_buf_wide;
(void)path_buf_len;
(void)path_buf_wide_len;
#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.
/* 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)
{
@ -355,20 +342,37 @@ static char* mb_to_mb_string_alloc(const char *str,
free(path_buf_wide);
return NULL;
#endif
#endif
}
#endif
/* Returned pointer MUST be freed by the caller if non-NULL. */
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. */
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. */
@ -447,52 +451,44 @@ wchar_t* utf8_to_utf16_string_alloc(const char *str)
char* utf16_to_utf8_string_alloc(const wchar_t *str)
{
#ifdef _WIN32
int len = 0;
int out_len = 0;
int len = 0;
#else
size_t len = 0;
size_t out_len = 0;
size_t len = 0;
#endif
char *buf = NULL;
char *buf = NULL;
if (!str || !*str)
return NULL;
#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));
if (!buf)
return NULL;
out_len = WideCharToMultiByte(CP_UTF8, 0, str, -1, buf, len, NULL, NULL);
}
else
{
/* fallback to ANSI codepage instead */
len = WideCharToMultiByte(CP_ACP, 0, str, -1, NULL, 0, NULL, NULL);
if (len)
if (WideCharToMultiByte(code_page,
0, str, -1, buf, len, NULL, NULL) < 0)
{
buf = (char*)calloc(len, sizeof(char));
if (!buf)
return NULL;
out_len = WideCharToMultiByte(CP_ACP, 0, str, -1, buf, len, NULL, NULL);
free(buf);
return NULL;
}
}
if (out_len < 0)
{
free(buf);
return NULL;
}
#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;
if (len)
@ -502,13 +498,11 @@ char* utf16_to_utf8_string_alloc(const wchar_t *str)
if (!buf)
return NULL;
out_len = wcstombs(buf, str, len);
}
if (out_len == (size_t)-1)
{
free(buf);
return NULL;
if (wcstombs(buf, str, len) == (size_t)-1)
{
free(buf);
return NULL;
}
}
#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 */
#endif

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@ -31,6 +31,7 @@
RETRO_BEGIN_DECLS
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

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

@ -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 <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 */
#elif defined(_WIN32) && !defined(_XBOX)
#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>
#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...
*/
/* _LIBRETRO_COMMON_RETRO_COMMON_API_H */
#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
#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

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
#if defined(__CELLOS_LV2__)
#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
#else
#define PATH_MAX_LENGTH 4096
@ -159,14 +159,24 @@ typedef struct
# ifdef _WIN64
# define PRI_SIZET PRIu64
# else
#if _MSC_VER == 1800
# define PRI_SIZET PRIu32
#else
# define PRI_SIZET "u"
#endif
# if _MSC_VER == 1800
# define PRI_SIZET PRIu32
# else
# define PRI_SIZET "u"
# endif
# endif
#elif PS2
# define PRI_SIZET "u"
#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

View File

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

View File

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

View File

@ -30,6 +30,8 @@
RETRO_BEGIN_DECLS
#ifndef SKIP_STDIO_REDEFINES
#define FILE RFILE
#undef fopen
@ -41,9 +43,11 @@ RETRO_BEGIN_DECLS
#undef fgetc
#undef fwrite
#undef fputc
#undef fflush
#undef fprintf
#undef ferror
#undef feof
#undef fscanf
#define fopen rfopen
#define fclose rfclose
@ -54,9 +58,13 @@ RETRO_BEGIN_DECLS
#define fgetc rfgetc
#define fwrite rfwrite
#define fputc rfputc
#define fflush rfflush
#define fprintf rfprintf
#define ferror rferror
#define feof rfeof
#define fscanf rfscanf
#endif
RFILE* rfopen(const char *path, const char *mode);
@ -78,12 +86,16 @@ int64_t rfwrite(void const* buffer,
int rfputc(int character, RFILE * stream);
int64_t rfflush(RFILE * stream);
int rfprintf(RFILE * stream, const char * format, ...);
int rferror(RFILE* stream);
int rfeof(RFILE* stream);
int rfscanf(RFILE * stream, const char * format, ...);
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 (stdstring.h).
@ -37,35 +37,30 @@ RETRO_BEGIN_DECLS
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)
{
if (!a || !b)
return false;
while(*a && (*a == *b))
{
a++;
b++;
}
return (*(const unsigned char*)a - *(const unsigned char*)b) == 0;
return (a && b) ? !strcmp(a, b) : false;
}
static INLINE bool string_is_not_equal(const char *a, const char *b)
{
return !string_is_equal(a, b);
}
#define STRLEN_CONST(x) ((sizeof((x))-1))
#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_is_not_equal(a, b) !string_is_equal((a), (b))
#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_single_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_glob_open(s, size) strlcat((s), "glob('*", (size))
#define string_add_glob_close(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_colon(s, size) strlcat((s), ":", (size))
#define string_add_glob_open(s, size) strlcat((s), "glob('*", (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,
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);
}
#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,
const char *b)
{
@ -119,7 +111,7 @@ char *string_to_upper(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,
const char *by);
@ -133,7 +125,9 @@ char *string_trim_whitespace_right(char *const s);
/* Remove leading and trailing whitespaces */
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

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).
@ -23,20 +23,13 @@
#ifndef __LIBRETRO_SDK_VFS_IMPLEMENTATION_H
#define __LIBRETRO_SDK_VFS_IMPLEMENTATION_H
#include <stdio.h>
#include <stdint.h>
#include <libretro.h>
#include <retro_environment.h>
#include <vfs/vfs.h>
/* 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
RETRO_BEGIN_DECLS
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_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_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);
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

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_close_t filestream_close_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_seek_t filestream_seek_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_tell_cb = NULL;
filestream_size_cb = NULL;
filestream_truncate_cb = NULL;
filestream_seek_cb = NULL;
filestream_read_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_close_cb = vfs_iface->close;
filestream_size_cb = vfs_iface->size;
filestream_truncate_cb = vfs_iface->truncate;
filestream_tell_cb = vfs_iface->tell;
filestream_seek_cb = vfs_iface->seek;
filestream_read_cb = vfs_iface->read;
@ -127,6 +130,21 @@ int64_t filestream_get_size(RFILE *stream)
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:
* @path : path to file
@ -186,9 +204,9 @@ int filestream_getc(RFILE *stream)
{
char c = 0;
if (!stream)
return 0;
if(filestream_read(stream, &c, 1) == 1)
return (int)c;
return EOF;
if (filestream_read(stream, &c, 1) == 1)
return (int)(unsigned char)c;
return EOF;
}
@ -197,37 +215,40 @@ int filestream_scanf(RFILE *stream, const char* format, ...)
char buf[4096];
char subfmt[64];
va_list args;
const char * bufiter = buf;
int64_t startpos = filestream_tell(stream);
int ret = 0;
int64_t maxlen = filestream_read(stream, buf, sizeof(buf)-1);
if (maxlen <= 0)
return EOF;
buf[maxlen] = '\0';
va_start(args, format);
while (*format)
{
if (*format == '%')
{
int sublen;
char* subfmtiter = subfmt;
bool asterisk = false;
*subfmtiter++ = *format++; /* '%' */
/* %[*][width][length]specifier */
if (*format == '*')
{
asterisk = true;
*subfmtiter++ = *format++;
}
while (isdigit(*format)) *subfmtiter++ = *format++; /* width */
/* length */
if (*format == 'h' || *format == 'l')
{
@ -238,7 +259,7 @@ int filestream_scanf(RFILE *stream, const char* format, ...)
{
*subfmtiter++ = *format++;
}
/* specifier - always a single character (except ]) */
if (*format == '[')
{
@ -246,11 +267,11 @@ int filestream_scanf(RFILE *stream, const char* format, ...)
*subfmtiter++ = *format++;
}
else *subfmtiter++ = *format++;
*subfmtiter++ = '%';
*subfmtiter++ = 'n';
*subfmtiter++ = '\0';
if (sizeof(void*) != sizeof(long*)) abort(); /* all pointers must have the same size */
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;
}
ret++;
bufiter += sublen;
}
@ -277,10 +298,10 @@ int filestream_scanf(RFILE *stream, const char* format, ...)
format++;
}
}
va_end(args);
filestream_seek(stream, startpos+(bufiter-buf), RETRO_VFS_SEEK_POSITION_START);
return ret;
}
@ -305,7 +326,6 @@ int filestream_eof(RFILE *stream)
return stream->eof_flag;
}
int64_t filestream_tell(RFILE *stream)
{
int64_t output;
@ -407,7 +427,7 @@ int filestream_putc(RFILE *stream, int c)
char c_char = (char)c;
if (!stream)
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)
@ -592,3 +612,8 @@ char *filestream_getline(RFILE *stream)
newline[idx] = '\0';
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;
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;
}
}
@ -49,12 +49,12 @@ RFILE* rfopen(const char *path, const char *mode)
}
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;
position_to_end = true;
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;
}
}
@ -99,7 +99,7 @@ int64_t rfseek(RFILE* stream, int64_t offset, int origin)
int64_t rfread(void* buffer,
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)
@ -109,7 +109,7 @@ char *rfgets(char *buffer, int maxCount, RFILE* stream)
int rfgetc(RFILE* stream)
{
return filestream_getc(stream);
return filestream_getc(stream);
}
int64_t rfwrite(void const* buffer,
@ -123,14 +123,19 @@ int rfputc(int character, RFILE * stream)
return filestream_putc(stream, character);
}
int64_t rfflush(RFILE * stream)
{
return filestream_flush(stream);
}
int rfprintf(RFILE * stream, const char * format, ...)
{
int result;
va_list vl;
va_start(vl, format);
result = filestream_vprintf(stream, format, vl);
va_end(vl);
return result;
va_list vl;
va_start(vl, format);
result = filestream_vprintf(stream, format, vl);
va_end(vl);
return result;
}
int rferror(RFILE* stream)
@ -142,3 +147,13 @@ int rfeof(RFILE* 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;
out = (char *)malloc(outlen+1);
if (!out)
return NULL;
outat = out;
inat = in;
inprev = in;
@ -105,18 +109,17 @@ char *string_trim_whitespace_left(char *const s)
{
if(s && *s)
{
size_t len = strlen(s);
char *cur = s;
size_t len = strlen(s);
char *current = s;
while(*cur && isspace((unsigned char)*cur))
while(*current && isspace((unsigned char)*current))
{
++cur;
++current;
--len;
}
if(s != cur)
memmove(s, cur, len + 1);
if(s != current)
memmove(s, current, len + 1);
}
return s;
@ -127,16 +130,16 @@ char *string_trim_whitespace_right(char *const s)
{
if(s && *s)
{
size_t len = strlen(s);
char *cur = s + len - 1;
size_t len = strlen(s);
char *current = s + len - 1;
while(cur != s && isspace((unsigned char)*cur))
while(current != s && isspace((unsigned char)*current))
{
--cur;
--current;
--len;
}
cur[isspace((unsigned char)*cur) ? 0 : 1] = '\0';
current[isspace((unsigned char)*current) ? 0 : 1] = '\0';
}
return s;
@ -151,14 +154,16 @@ char *string_trim_whitespace(char *const 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 len = (unsigned)strlen(string);
unsigned i = 0;
unsigned len = (unsigned)strlen(string);
unsigned lines = 1;
while (i < len)
{
unsigned counter;
int pos = (int)(&buffer[i] - buffer);
/* copy string until the end of the line is reached */
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
* and reset the index */
if (buffer[j] == '\n')
{
lines++;
counter = 1;
}
}
/* check for whitespace */
if (string[i] == ' ')
{
buffer[i] = '\n';
i++;
if ((max_lines == 0 || lines < max_lines))
{
buffer[i] = '\n';
i++;
lines++;
}
}
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 */
for (k = i; k > 0; k--)
{
if (string[k] != ' ')
if (string[k] != ' ' || (max_lines != 0 && lines >= max_lines))
continue;
buffer[k] = '\n';
/* set string index back to character after this one */
i = k + 1;
lines++;
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;
}