Update libretro-common

This commit is contained in:
negativeExponent 2020-10-14 11:59:45 +08:00
parent 48b6b73923
commit a5ff21568e
32 changed files with 1465 additions and 685 deletions

View File

@ -99,7 +99,9 @@ SOURCES_C += \
$(LIBRETRO_COMM_DIR)/compat/compat_strcasestr.c \
$(LIBRETRO_COMM_DIR)/encodings/encoding_utf.c \
$(LIBRETRO_COMM_DIR)/file/file_path.c \
$(LIBRETRO_COMM_DIR)/vfs/vfs_implementation.c
$(LIBRETRO_COMM_DIR)/vfs/vfs_implementation.c \
$(LIBRETRO_COMM_DIR)/time/rtime.c \
$(LIBRETRO_COMM_DIR)/string/stdstring.c
endif
SOURCES_C += \

View File

@ -1,4 +1,4 @@
/* Copyright (C) 2010-2018 The RetroArch team
/* Copyright (C) 2010-2020 The RetroArch team
*
* ---------------------------------------------------------------------------------------
* The following license statement only applies to this file (compat_posix_string.c).

View File

@ -1,4 +1,4 @@
/* Copyright (C) 2010-2018 The RetroArch team
/* Copyright (C) 2010-2020 The RetroArch team
*
* ---------------------------------------------------------------------------------------
* The following license statement only applies to this file (compat_snprintf.c).
@ -33,12 +33,12 @@
#if _MSC_VER < 1300
#define _vscprintf c89_vscprintf_retro__
static int c89_vscprintf_retro__(const char *format, va_list pargs)
static int c89_vscprintf_retro__(const char *fmt, va_list pargs)
{
int retval;
va_list argcopy;
va_copy(argcopy, pargs);
retval = vsnprintf(NULL, 0, format, argcopy);
retval = vsnprintf(NULL, 0, fmt, argcopy);
va_end(argcopy);
return retval;
}
@ -46,38 +46,36 @@ static int c89_vscprintf_retro__(const char *format, va_list pargs)
/* http://stackoverflow.com/questions/2915672/snprintf-and-visual-studio-2010 */
int c99_vsnprintf_retro__(char *outBuf, size_t size, const char *format, va_list ap)
int c99_vsnprintf_retro__(char *s, size_t len, const char *fmt, va_list ap)
{
int count = -1;
if (size != 0)
if (len != 0)
{
#if (_MSC_VER <= 1310)
count = _vsnprintf(outBuf, size - 1, format, ap);
count = _vsnprintf(s, len - 1, fmt, ap);
#else
count = _vsnprintf_s(outBuf, size, size - 1, format, ap);
count = _vsnprintf_s(s, len, len - 1, fmt, ap);
#endif
}
if (count == -1)
count = _vscprintf(format, ap);
count = _vscprintf(fmt, ap);
if (count == size)
{
/* there was no room for a NULL, so truncate the last character */
outBuf[size - 1] = '\0';
}
/* there was no room for a NULL, so truncate the last character */
if (count == len && len)
s[len - 1] = '\0';
return count;
}
int c99_snprintf_retro__(char *outBuf, size_t size, const char *format, ...)
int c99_snprintf_retro__(char *s, size_t len, const char *fmt, ...)
{
int count;
va_list ap;
va_start(ap, format);
count = c99_vsnprintf_retro__(outBuf, size, format, ap);
va_start(ap, fmt);
count = c99_vsnprintf_retro__(s, len, fmt, ap);
va_end(ap);
return count;

View File

@ -1,4 +1,4 @@
/* Copyright (C) 2010-2018 The RetroArch team
/* Copyright (C) 2010-2020 The RetroArch team
*
* ---------------------------------------------------------------------------------------
* The following license statement only applies to this file (compat_strcasestr.c).

View File

@ -1,4 +1,4 @@
/* Copyright (C) 2010-2018 The RetroArch team
/* Copyright (C) 2010-2020 The RetroArch team
*
* ---------------------------------------------------------------------------------------
* The following license statement only applies to this file (compat_strl.c).

View File

@ -1,4 +1,4 @@
/* Copyright (C) 2010-2018 The RetroArch team
/* Copyright (C) 2010-2020 The RetroArch team
*
* ---------------------------------------------------------------------------------------
* The following license statement only applies to this file (fopen_utf8.c).

View File

@ -1,4 +1,4 @@
/* Copyright (C) 2010-2018 The RetroArch team
/* Copyright (C) 2010-2020 The RetroArch team
*
* ---------------------------------------------------------------------------------------
* The following license statement only applies to this file (encoding_utf.c).
@ -37,6 +37,8 @@
#include <xtl.h>
#endif
#define UTF8_WALKBYTE(string) (*((*(string))++))
static unsigned leading_ones(uint8_t c)
{
unsigned ones = 0;
@ -89,13 +91,14 @@ size_t utf8_conv_utf32(uint32_t *out, size_t out_chars,
bool utf16_conv_utf8(uint8_t *out, size_t *out_chars,
const uint16_t *in, size_t in_size)
{
static uint8_t kUtf8Limits[5] = { 0xC0, 0xE0, 0xF0, 0xF8, 0xFC };
size_t out_pos = 0;
size_t in_pos = 0;
size_t out_pos = 0;
size_t in_pos = 0;
static const
uint8_t utf8_limits[5] = { 0xC0, 0xE0, 0xF0, 0xF8, 0xFC };
for (;;)
{
unsigned numAdds;
unsigned num_adds;
uint32_t value;
if (in_pos == in_size)
@ -124,21 +127,21 @@ bool utf16_conv_utf8(uint8_t *out, size_t *out_chars,
value = (((value - 0xD800) << 10) | (c2 - 0xDC00)) + 0x10000;
}
for (numAdds = 1; numAdds < 5; numAdds++)
if (value < (((uint32_t)1) << (numAdds * 5 + 6)))
for (num_adds = 1; num_adds < 5; num_adds++)
if (value < (((uint32_t)1) << (num_adds * 5 + 6)))
break;
if (out)
out[out_pos] = (char)(kUtf8Limits[numAdds - 1]
+ (value >> (6 * numAdds)));
out[out_pos] = (char)(utf8_limits[num_adds - 1]
+ (value >> (6 * num_adds)));
out_pos++;
do
{
numAdds--;
num_adds--;
if (out)
out[out_pos] = (char)(0x80
+ ((value >> (6 * numAdds)) & 0x3F));
+ ((value >> (6 * num_adds)) & 0x3F));
out_pos++;
}while (numAdds != 0);
}while (num_adds != 0);
}
*out_chars = out_pos;
@ -166,13 +169,15 @@ size_t utf8cpy(char *d, size_t d_len, const char *s, size_t chars)
while (*sb && chars-- > 0)
{
sb++;
while ((*sb & 0xC0) == 0x80) sb++;
while ((*sb & 0xC0) == 0x80)
sb++;
}
if ((size_t)(sb - sb_org) > d_len-1 /* NUL */)
{
sb = sb_org + d_len-1;
while ((*sb & 0xC0) == 0x80) sb--;
while ((*sb & 0xC0) == 0x80)
sb--;
}
memcpy(d, sb_org, sb-sb_org);
@ -184,14 +189,18 @@ size_t utf8cpy(char *d, size_t d_len, const char *s, size_t chars)
const char *utf8skip(const char *str, size_t chars)
{
const uint8_t *strb = (const uint8_t*)str;
if (!chars)
return str;
do
{
strb++;
while ((*strb & 0xC0)==0x80) strb++;
while ((*strb & 0xC0)==0x80)
strb++;
chars--;
} while(chars);
}while (chars);
return (const char*)strb;
}
@ -211,24 +220,22 @@ size_t utf8len(const char *string)
return ret;
}
#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)
{
uint8_t first = utf8_walkbyte(string);
uint8_t first = UTF8_WALKBYTE(string);
uint32_t ret = 0;
if (first < 128)
return first;
ret = (ret << 6) | (utf8_walkbyte(string) & 0x3F);
ret = (ret << 6) | (UTF8_WALKBYTE(string) & 0x3F);
if (first >= 0xE0)
{
ret = (ret << 6) | (utf8_walkbyte(string) & 0x3F);
ret = (ret << 6) | (UTF8_WALKBYTE(string) & 0x3F);
if (first >= 0xF0)
{
ret = (ret << 6) | (utf8_walkbyte(string) & 0x3F);
ret = (ret << 6) | (UTF8_WALKBYTE(string) & 0x3F);
return ret | (first & 7) << 18;
}
return ret | (first & 15) << 12;
@ -277,9 +284,7 @@ bool utf16_to_char_string(const uint16_t *in, char *s, size_t len)
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 = MultiByteToWideChar(cp_in, 0, str, -1, NULL, 0);
/* Windows 95 will return 0 from these functions with
@ -292,54 +297,51 @@ static char *mb_to_mb_string_alloc(const char *str,
* MultiByteToWideChar also supports CP_UTF7 and CP_UTF8.
*/
if (path_buf_wide_len)
{
path_buf_wide = (wchar_t*)
calloc(path_buf_wide_len + sizeof(wchar_t), sizeof(wchar_t));
if (path_buf_wide)
{
MultiByteToWideChar(cp_in, 0,
str, -1, path_buf_wide, path_buf_wide_len);
if (*path_buf_wide)
{
path_buf_len = WideCharToMultiByte(cp_out, 0,
path_buf_wide, -1, NULL, 0, NULL, NULL);
if (path_buf_len)
{
path_buf = (char*)
calloc(path_buf_len + sizeof(char), sizeof(char));
if (path_buf)
{
WideCharToMultiByte(cp_out, 0,
path_buf_wide, -1, path_buf,
path_buf_len, NULL, NULL);
free(path_buf_wide);
if (*path_buf)
return path_buf;
free(path_buf);
return NULL;
}
}
else
{
free(path_buf_wide);
return strdup(str);
}
}
}
}
else
if (!path_buf_wide_len)
return strdup(str);
path_buf_wide = (wchar_t*)
calloc(path_buf_wide_len + sizeof(wchar_t), sizeof(wchar_t));
if (path_buf_wide)
{
MultiByteToWideChar(cp_in, 0,
str, -1, path_buf_wide, path_buf_wide_len);
if (*path_buf_wide)
{
int path_buf_len = WideCharToMultiByte(cp_out, 0,
path_buf_wide, -1, NULL, 0, NULL, NULL);
if (path_buf_len)
{
char *path_buf = (char*)
calloc(path_buf_len + sizeof(char), sizeof(char));
if (path_buf)
{
WideCharToMultiByte(cp_out, 0,
path_buf_wide, -1, path_buf,
path_buf_len, NULL, NULL);
free(path_buf_wide);
if (*path_buf)
return path_buf;
free(path_buf);
return NULL;
}
}
else
{
free(path_buf_wide);
return strdup(str);
}
}
free(path_buf_wide);
}
return NULL;
}
@ -379,13 +381,13 @@ char* local_to_utf8_string_alloc(const char *str)
wchar_t* utf8_to_utf16_string_alloc(const char *str)
{
#ifdef _WIN32
int len = 0;
int out_len = 0;
int len = 0;
int out_len = 0;
#else
size_t len = 0;
size_t len = 0;
size_t out_len = 0;
#endif
wchar_t *buf = NULL;
wchar_t *buf = NULL;
if (!str || !*str)
return NULL;

View File

@ -1,4 +1,4 @@
/* Copyright (C) 2010-2019 The RetroArch team
/* Copyright (C) 2010-2020 The RetroArch team
*
* ---------------------------------------------------------------------------------------
* The following license statement only applies to this file (file_path.c).
@ -32,8 +32,7 @@
#include <file/file_path.h>
#include <retro_assert.h>
#include <string/stdstring.h>
#define VFS_FRONTEND
#include <vfs/vfs_implementation.h>
#include <time/rtime.h>
/* TODO: There are probably some unnecessary things on this huge include list now but I'm too afraid to touch it */
#ifdef __APPLE__
@ -46,7 +45,6 @@
#include <compat/strl.h>
#include <compat/posix_string.h>
#endif
#include <compat/strcasestr.h>
#include <retro_miscellaneous.h>
#include <encodings/utf.h>
@ -82,12 +80,7 @@
#include <pspkernel.h>
#endif
#if defined(PS2)
#include <fileXio_rpc.h>
#include <fileXio.h>
#endif
#if defined(__CELLOS_LV2__)
#if defined(__CELLOS_LV2__) && !defined(__PSL1GHT__)
#include <cell/cell_fs.h>
#endif
@ -95,7 +88,7 @@
#define FIO_S_ISDIR SCE_S_ISDIR
#endif
#if (defined(__CELLOS_LV2__) && !defined(__PSL1GHT__)) || defined(__QNX__) || defined(PSP) || defined(PS2)
#if (defined(__CELLOS_LV2__) && !defined(__PSL1GHT__)) || defined(__QNX__) || defined(PSP)
#include <unistd.h> /* stat() is defined here */
#endif
@ -114,133 +107,6 @@
#endif
static retro_vfs_stat_t path_stat_cb = retro_vfs_stat_impl;
static retro_vfs_mkdir_t path_mkdir_cb = retro_vfs_mkdir_impl;
void path_vfs_init(const struct retro_vfs_interface_info* vfs_info)
{
const struct retro_vfs_interface*
vfs_iface = vfs_info->iface;
path_stat_cb = retro_vfs_stat_impl;
path_mkdir_cb = retro_vfs_mkdir_impl;
if (vfs_info->required_interface_version < PATH_REQUIRED_VFS_VERSION || !vfs_iface)
return;
path_stat_cb = vfs_iface->stat;
path_mkdir_cb = vfs_iface->mkdir;
}
int path_stat(const char *path)
{
return path_stat_cb(path, NULL);
}
/**
* 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)
{
return (path_stat_cb(path, NULL) & RETRO_VFS_STAT_IS_DIRECTORY) != 0;
}
bool path_is_character_special(const char *path)
{
return (path_stat_cb(path, NULL) & RETRO_VFS_STAT_IS_CHARACTER_SPECIAL) != 0;
}
bool path_is_valid(const char *path)
{
return (path_stat_cb(path, NULL) & RETRO_VFS_STAT_IS_VALID) != 0;
}
int32_t path_get_size(const char *path)
{
int32_t filesize = 0;
if (path_stat_cb(path, &filesize) != 0)
return filesize;
return -1;
}
/**
* 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)
{
bool sret = false;
bool norecurse = false;
char *basedir = NULL;
if (!(dir && *dir))
return false;
/* Use heap. Real chance of stack
* overflow if we recurse too hard. */
basedir = strdup(dir);
if (!basedir)
return false;
path_parent_dir(basedir);
if (!*basedir || !strcmp(basedir, dir))
{
free(basedir);
return false;
}
#if defined(GEKKO)
{
size_t len = strlen(basedir);
/* path_parent_dir() keeps the trailing slash.
* On Wii, mkdir() fails if the path has a
* trailing slash...
* We must therefore remove it. */
if (len > 0)
if (basedir[len - 1] == '/')
basedir[len - 1] = '\0';
}
#endif
if (path_is_directory(basedir))
norecurse = true;
else
{
sret = path_mkdir(basedir);
if (sret)
norecurse = true;
}
free(basedir);
if (norecurse)
{
int ret = path_mkdir_cb(dir);
/* Don't treat this as an error. */
if (ret == -2 && path_is_directory(dir))
return true;
return (ret == 0);
}
return sret;
}
/**
* path_get_archive_delim:
* @path : path
@ -253,26 +119,48 @@ bool path_mkdir(const char *dir)
*/
const char *path_get_archive_delim(const char *path)
{
const char *last = find_last_slash(path);
const char *delim = NULL;
const char *last_slash = find_last_slash(path);
const char *delim = NULL;
char buf[5];
if (!last)
buf[0] = '\0';
if (!last_slash)
return NULL;
/* Test if it's .zip */
delim = strcasestr(last, ".zip#");
/* Find delimiter position */
delim = strrchr(last_slash, '#');
if (!delim) /* If it's not a .zip, test if it's .apk */
delim = strcasestr(last, ".apk#");
if (!delim)
return NULL;
if (delim)
return delim + 4;
/* Check whether this is a known archive type
* > Note: The code duplication here is
* deliberate, to maximise performance */
if (delim - last_slash > 4)
{
strlcpy(buf, delim - 4, sizeof(buf));
buf[4] = '\0';
/* If it's not a .zip or .apk file, test if it's .7z */
delim = strcasestr(last, ".7z#");
string_to_lower(buf);
if (delim)
return delim + 3;
/* Check if this is a '.zip', '.apk' or '.7z' file */
if (string_is_equal(buf, ".zip") ||
string_is_equal(buf, ".apk") ||
string_is_equal(buf + 1, ".7z"))
return delim;
}
else if (delim - last_slash > 3)
{
strlcpy(buf, delim - 3, sizeof(buf));
buf[3] = '\0';
string_to_lower(buf);
/* Check if this is a '.7z' file */
if (string_is_equal(buf, ".7z"))
return delim;
}
return NULL;
}
@ -331,9 +219,12 @@ bool path_is_compressed_file(const char* path)
{
const char *ext = path_get_extension(path);
if ( strcasestr(ext, "zip")
|| strcasestr(ext, "apk")
|| strcasestr(ext, "7z"))
if (string_is_empty(ext))
return false;
if (string_is_equal_noncase(ext, "zip") ||
string_is_equal_noncase(ext, "apk") ||
string_is_equal_noncase(ext, "7z"))
return true;
return false;
@ -423,7 +314,7 @@ void fill_pathname_slash(char *path, size_t size)
if (!last_slash)
{
strlcat(path, path_default_slash(), size);
strlcat(path, PATH_DEFAULT_SLASH(), size);
return;
}
@ -592,11 +483,13 @@ void fill_pathname_parent_dir(char *out_dir,
size_t fill_dated_filename(char *out_filename,
const char *ext, size_t size)
{
time_t cur_time = time(NULL);
const struct tm* tm_ = localtime(&cur_time);
time_t cur_time = time(NULL);
struct tm tm_;
rtime_localtime(&cur_time, &tm_);
strftime(out_filename, size,
"RetroArch-%m%d-%H%M%S", tm_);
"RetroArch-%m%d-%H%M%S", &tm_);
return strlcat(out_filename, ext, size);
}
@ -617,19 +510,21 @@ void fill_str_dated_filename(char *out_filename,
const char *in_str, const char *ext, size_t size)
{
char format[256];
time_t cur_time = time(NULL);
const struct tm* tm_ = localtime(&cur_time);
struct tm tm_;
time_t cur_time = time(NULL);
format[0] = '\0';
format[0] = '\0';
rtime_localtime(&cur_time, &tm_);
if (string_is_empty(ext))
{
strftime(format, sizeof(format), "-%y%m%d-%H%M%S", tm_);
strftime(format, sizeof(format), "-%y%m%d-%H%M%S", &tm_);
fill_pathname_noext(out_filename, in_str, format, size);
}
else
{
strftime(format, sizeof(format), "-%y%m%d-%H%M%S.", tm_);
strftime(format, sizeof(format), "-%y%m%d-%H%M%S.", &tm_);
fill_pathname_join_concat_noext(out_filename,
in_str, format, ext,
@ -656,7 +551,7 @@ void path_basedir(char *path)
if (last)
last[1] = '\0';
else
snprintf(path, 3, ".%s", path_default_slash());
snprintf(path, 3, "." PATH_DEFAULT_SLASH());
}
/**
@ -676,7 +571,7 @@ void path_parent_dir(char *path)
len = strlen(path);
if (len && path_char_is_slash(path[len - 1]))
if (len && PATH_CHAR_IS_SLASH(path[len - 1]))
{
bool path_was_absolute = path_is_absolute(path);
@ -731,19 +626,27 @@ const char *path_basename(const char *path)
**/
bool path_is_absolute(const char *path)
{
if (string_is_empty(path))
return false;
if (path[0] == '/')
return true;
#ifdef _WIN32
/* Many roads lead to Rome ... */
if (( strstr(path, "\\\\") == path)
|| strstr(path, ":/")
|| strstr(path, ":\\")
|| strstr(path, ":\\\\"))
return true;
#elif defined(__wiiu__)
if (strstr(path, ":/"))
#if defined(_WIN32)
/* Many roads lead to Rome...
* Note: Drive letter can only be 1 character long */
if (string_starts_with_size(path, "\\\\", STRLEN_CONST("\\\\")) ||
string_starts_with_size(path + 1, ":/", STRLEN_CONST(":/")) ||
string_starts_with_size(path + 1, ":\\", STRLEN_CONST(":\\")))
return true;
#elif defined(__wiiu__) || defined(VITA)
{
const char *seperator = strchr(path, ':');
if (seperator && (seperator[1] == '/'))
return true;
}
#endif
return false;
}
@ -893,7 +796,7 @@ end:
size_t path_relative_to(char *out,
const char *path, const char *base, size_t size)
{
size_t i;
size_t i, j;
const char *trimmed_path, *trimmed_base;
#ifdef _WIN32
@ -905,16 +808,18 @@ size_t path_relative_to(char *out,
#endif
/* Trim common beginning */
for (i = 0; path[i] && base[i] && path[i] == base[i]; )
i++;
trimmed_path = path+i;
for (i = 0, j = 0; path[i] && base[i] && path[i] == base[i]; i++)
if (path[i] == PATH_DEFAULT_SLASH_C())
j = i + 1;
trimmed_path = path+j;
trimmed_base = base+i;
/* Each segment of base turns into ".." */
out[0] = '\0';
for (i = 0; trimmed_base[i]; i++)
if (trimmed_base[i] == path_default_slash_c())
strlcat(out, ".." path_default_slash(), size);
if (trimmed_base[i] == PATH_DEFAULT_SLASH_C())
strlcat(out, ".." PATH_DEFAULT_SLASH(), size);
return strlcat(out, trimmed_path, size);
}
@ -1099,13 +1004,13 @@ void fill_pathname_expand_special(char *out_path,
out_path += src_size;
size -= src_size;
if (!path_char_is_slash(out_path[-1]))
if (!PATH_CHAR_IS_SLASH(out_path[-1]))
{
src_size = strlcpy(out_path, path_default_slash(), size);
src_size = strlcpy(out_path, PATH_DEFAULT_SLASH(), size);
retro_assert(src_size < size);
out_path += src_size;
size -= src_size;
size -= src_size;
}
in_path += 2;
@ -1130,9 +1035,9 @@ void fill_pathname_expand_special(char *out_path,
out_path += src_size;
size -= src_size;
if (!path_char_is_slash(out_path[-1]))
if (!PATH_CHAR_IS_SLASH(out_path[-1]))
{
src_size = strlcpy(out_path, path_default_slash(), size);
src_size = strlcpy(out_path, PATH_DEFAULT_SLASH(), size);
retro_assert(src_size < size);
out_path += src_size;
@ -1156,10 +1061,11 @@ void fill_pathname_abbreviate_special(char *out_path,
unsigned i;
const char *candidates[3];
const char *notations[3];
char *application_dir = (char*)malloc(PATH_MAX_LENGTH * sizeof(char));
char *home_dir = (char*)malloc(PATH_MAX_LENGTH * sizeof(char));
char application_dir[PATH_MAX_LENGTH];
char home_dir[PATH_MAX_LENGTH];
application_dir[0] = '\0';
home_dir[0] = '\0';
/* application_dir could be zero-string. Safeguard against this.
*
@ -1176,15 +1082,13 @@ void fill_pathname_abbreviate_special(char *out_path,
notations [1] = "~";
notations [2] = NULL;
fill_pathname_application_dir(application_dir,
PATH_MAX_LENGTH * sizeof(char));
fill_pathname_home_dir(home_dir,
PATH_MAX_LENGTH * sizeof(char));
fill_pathname_application_dir(application_dir, sizeof(application_dir));
fill_pathname_home_dir(home_dir, sizeof(home_dir));
for (i = 0; candidates[i]; i++)
{
if (!string_is_empty(candidates[i]) &&
strstr(in_path, candidates[i]) == in_path)
string_starts_with(in_path, candidates[i]))
{
size_t src_size = strlcpy(out_path, notations[i], size);
@ -1194,10 +1098,9 @@ void fill_pathname_abbreviate_special(char *out_path,
size -= src_size;
in_path += strlen(candidates[i]);
if (!path_char_is_slash(*in_path))
if (!PATH_CHAR_IS_SLASH(*in_path))
{
retro_assert(strlcpy(out_path,
path_default_slash(), size) < size);
strcpy_literal(out_path, PATH_DEFAULT_SLASH());
out_path++;
size--;
}
@ -1206,8 +1109,6 @@ void fill_pathname_abbreviate_special(char *out_path,
}
}
free(application_dir);
free(home_dir);
#endif
retro_assert(strlcpy(out_path, in_path, size) < size);
@ -1238,7 +1139,7 @@ void path_basedir_wrapper(char *path)
if (last)
last[1] = '\0';
else
snprintf(path, 3, ".%s", path_default_slash());
snprintf(path, 3, "." PATH_DEFAULT_SLASH());
}
#if !defined(RARCH_CONSOLE) && defined(RARCH_INTERNAL)
@ -1365,29 +1266,27 @@ void fill_pathname_application_dir(char *s, size_t len)
void fill_pathname_home_dir(char *s, size_t len)
{
#ifdef __WINRT__
strlcpy(s, uwp_dir_data, len);
const char *home = uwp_dir_data;
#else
const char *home = getenv("HOME");
#endif
if (home)
strlcpy(s, home, len);
else
*s = 0;
#endif
}
#endif
bool is_path_accessible_using_standard_io(const char *path)
{
#ifdef __WINRT__
bool result;
size_t path_sizeof = PATH_MAX_LENGTH * sizeof(char);
char *relative_path_abbrev = (char*)malloc(path_sizeof);
fill_pathname_abbreviate_special(relative_path_abbrev, path, path_sizeof);
result = strlen(relative_path_abbrev) >= 2 && (relative_path_abbrev[0] == ':' || relative_path_abbrev[0] == '~') && path_char_is_slash(relative_path_abbrev[1]);
free(relative_path_abbrev);
return result;
char relative_path_abbrev[PATH_MAX_LENGTH];
fill_pathname_abbreviate_special(relative_path_abbrev,
path, sizeof(relative_path_abbrev));
return (strlen(relative_path_abbrev) >= 2 )
&& ( relative_path_abbrev[0] == ':'
|| relative_path_abbrev[0] == '~')
&& PATH_CHAR_IS_SLASH(relative_path_abbrev[1]);
#else
return true;
#endif

View File

@ -1,4 +1,4 @@
/* Copyright (C) 2010-2018 The RetroArch team
/* Copyright (C) 2010-2020 The RetroArch team
*
* ---------------------------------------------------------------------------------------
* The following license statement only applies to this file (fopen_utf8.h).

View File

@ -1,4 +1,4 @@
/* Copyright (C) 2010-2018 The RetroArch team
/* Copyright (C) 2010-2020 The RetroArch team
*
* ---------------------------------------------------------------------------------------
* The following license statement only applies to this file (msvc.h).
@ -29,20 +29,17 @@
extern "C" {
#endif
/* Pre-MSVC 2015 compilers don't implement snprintf in a cross-platform manner. */
/* Pre-MSVC 2015 compilers don't implement snprintf, vsnprintf in a cross-platform manner. */
#if _MSC_VER < 1900
#include <stdio.h>
#include <stdarg.h>
#include <stdlib.h>
#ifndef snprintf
#define snprintf c99_snprintf_retro__
#endif
int c99_snprintf_retro__(char *outBuf, size_t size, const char *format, ...);
#endif
/* 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
#define vsnprintf c99_vsnprintf_retro__
#endif

View File

@ -1,4 +1,4 @@
/* Copyright (C) 2010-2018 The RetroArch team
/* Copyright (C) 2010-2020 The RetroArch team
*
* ---------------------------------------------------------------------------------------
* The following license statement only applies to this file (posix_string.h).
@ -29,10 +29,6 @@
#include <compat/msvc.h>
#endif
#if defined(PS2)
#include <compat_ctype.h>
#endif
RETRO_BEGIN_DECLS
#ifdef _WIN32

View File

@ -1,4 +1,4 @@
/* Copyright (C) 2010-2018 The RetroArch team
/* Copyright (C) 2010-2020 The RetroArch team
*
* ---------------------------------------------------------------------------------------
* The following license statement only applies to this file (strcasestr.h).
@ -25,10 +25,6 @@
#include <string.h>
#if defined(PS2)
#include <compat_ctype.h>
#endif
#if defined(RARCH_INTERNAL) && defined(HAVE_CONFIG_H)
#include "../../../config.h"
#endif

View File

@ -1,4 +1,4 @@
/* Copyright (C) 2010-2018 The RetroArch team
/* Copyright (C) 2010-2020 The RetroArch team
*
* ---------------------------------------------------------------------------------------
* The following license statement only applies to this file (strl.h).

View File

@ -1,4 +1,4 @@
/* Copyright (C) 2010-2018 The RetroArch team
/* Copyright (C) 2010-2020 The RetroArch team
*
* ---------------------------------------------------------------------------------------
* The following license statement only applies to this file (utf.h).
@ -35,7 +35,7 @@ RETRO_BEGIN_DECLS
enum CodePage
{
CODEPAGE_LOCAL = 0, /* CP_ACP */
CODEPAGE_UTF8 = 65001 /* CP_UTF8 */
CODEPAGE_UTF8 = 65001 /* CP_UTF8 */
};
size_t utf8_conv_utf32(uint32_t *out, size_t out_chars,

View File

@ -1,4 +1,4 @@
/* Copyright (C) 2010-2019 The RetroArch team
/* Copyright (C) 2010-2020 The RetroArch team
*
* ---------------------------------------------------------------------------------------
* The following license statement only applies to this file (file_path.h).
@ -460,9 +460,9 @@ void path_basedir_wrapper(char *path);
* Returns: true (1) if character is a slash, otherwise false (0).
*/
#ifdef _WIN32
#define path_char_is_slash(c) (((c) == '/') || ((c) == '\\'))
#define PATH_CHAR_IS_SLASH(c) (((c) == '/') || ((c) == '\\'))
#else
#define path_char_is_slash(c) ((c) == '/')
#define PATH_CHAR_IS_SLASH(c) ((c) == '/')
#endif
/**
@ -473,11 +473,11 @@ void path_basedir_wrapper(char *path);
* Returns: default slash separator.
*/
#ifdef _WIN32
#define path_default_slash() "\\"
#define path_default_slash_c() '\\'
#define PATH_DEFAULT_SLASH() "\\"
#define PATH_DEFAULT_SLASH_C() '\\'
#else
#define path_default_slash() "/"
#define path_default_slash_c() '/'
#define PATH_DEFAULT_SLASH() "/"
#define PATH_DEFAULT_SLASH_C() '/'
#endif
/**

View File

@ -1,4 +1,4 @@
/* Copyright (C) 2010-2018 The RetroArch team
/* Copyright (C) 2010-2020 The RetroArch team
*
* ---------------------------------------------------------------------------------------
* The following license statement only applies to this libretro API header (libretro.h).
@ -278,6 +278,10 @@ enum retro_language
RETRO_LANGUAGE_ARABIC = 16,
RETRO_LANGUAGE_GREEK = 17,
RETRO_LANGUAGE_TURKISH = 18,
RETRO_LANGUAGE_SLOVAK = 19,
RETRO_LANGUAGE_PERSIAN = 20,
RETRO_LANGUAGE_HEBREW = 21,
RETRO_LANGUAGE_ASTURIAN = 22,
RETRO_LANGUAGE_LAST,
/* Ensure sizeof(enum) == sizeof(int) */
@ -1087,10 +1091,10 @@ enum retro_mod
#define RETRO_ENVIRONMENT_GET_TARGET_REFRESH_RATE (50 | RETRO_ENVIRONMENT_EXPERIMENTAL)
/* float * --
* Float value that lets us know what target refresh rate
* Float value that lets us know what target refresh rate
* is curently in use by the frontend.
*
* The core can use the returned value to set an ideal
* The core can use the returned value to set an ideal
* refresh rate/framerate.
*/
@ -1098,7 +1102,7 @@ enum retro_mod
/* bool * --
* Boolean value that indicates whether or not the frontend supports
* input bitmasks being returned by retro_input_state_t. The advantage
* of this is that retro_input_state_t has to be only called once to
* of this is that retro_input_state_t has to be only called once to
* grab all button states instead of multiple times.
*
* If it returns true, you can pass RETRO_DEVICE_ID_JOYPAD_MASK as 'id'
@ -1117,7 +1121,7 @@ enum retro_mod
* This may be still be done regardless of the core options
* interface version.
*
* If version is 1 however, core options may instead be set by
* If version is >= 1 however, core options may instead be set by
* passing an array of retro_core_option_definition structs to
* RETRO_ENVIRONMENT_SET_CORE_OPTIONS, or a 2D array of
* retro_core_option_definition structs to RETRO_ENVIRONMENT_SET_CORE_OPTIONS_INTL.
@ -1132,8 +1136,8 @@ enum retro_mod
* GET_VARIABLE.
* This allows the frontend to present these variables to
* a user dynamically.
* This should only be called if RETRO_ENVIRONMENT_GET_ENHANCED_CORE_OPTIONS
* returns an API version of 1.
* This should only be called if RETRO_ENVIRONMENT_GET_CORE_OPTIONS_VERSION
* returns an API version of >= 1.
* This should be called instead of RETRO_ENVIRONMENT_SET_VARIABLES.
* This should be called the first time as early as
* possible (ideally in retro_set_environment).
@ -1169,8 +1173,6 @@ enum retro_mod
* i.e. it should be feasible to cycle through options
* without a keyboard.
*
* First entry should be treated as a default.
*
* Example entry:
* {
* "foo_option",
@ -1196,8 +1198,8 @@ enum retro_mod
* GET_VARIABLE.
* This allows the frontend to present these variables to
* a user dynamically.
* This should only be called if RETRO_ENVIRONMENT_GET_ENHANCED_CORE_OPTIONS
* returns an API version of 1.
* This should only be called if RETRO_ENVIRONMENT_GET_CORE_OPTIONS_VERSION
* returns an API version of >= 1.
* This should be called instead of RETRO_ENVIRONMENT_SET_VARIABLES.
* This should be called the first time as early as
* possible (ideally in retro_set_environment).
@ -1257,7 +1259,82 @@ enum retro_mod
*
* 'data' points to an unsigned variable
*/
#define RETRO_ENVIRONMENT_GET_DISK_CONTROL_INTERFACE_VERSION 57
/* unsigned * --
* Unsigned value is the API version number of the disk control
* interface supported by the frontend. If callback return false,
* API version is assumed to be 0.
*
* In legacy code, the disk control interface is defined by passing
* a struct of type retro_disk_control_callback to
* RETRO_ENVIRONMENT_SET_DISK_CONTROL_INTERFACE.
* This may be still be done regardless of the disk control
* interface version.
*
* If version is >= 1 however, the disk control interface may
* instead be defined by passing a struct of type
* retro_disk_control_ext_callback to
* RETRO_ENVIRONMENT_SET_DISK_CONTROL_EXT_INTERFACE.
* This allows the core to provide additional information about
* disk images to the frontend and/or enables extra
* disk control functionality by the frontend.
*/
#define RETRO_ENVIRONMENT_SET_DISK_CONTROL_EXT_INTERFACE 58
/* const struct retro_disk_control_ext_callback * --
* Sets an interface which frontend can use to eject and insert
* disk images, and also obtain information about individual
* disk image files registered by the core.
* This is used for games which consist of multiple images and
* must be manually swapped out by the user (e.g. PSX, floppy disk
* based systems).
*/
#define RETRO_ENVIRONMENT_GET_MESSAGE_INTERFACE_VERSION 59
/* unsigned * --
* Unsigned value is the API version number of the message
* interface supported by the frontend. If callback returns
* false, API version is assumed to be 0.
*
* In legacy code, messages may be displayed in an
* implementation-specific manner by passing a struct
* of type retro_message to RETRO_ENVIRONMENT_SET_MESSAGE.
* This may be still be done regardless of the message
* interface version.
*
* If version is >= 1 however, messages may instead be
* displayed by passing a struct of type retro_message_ext
* to RETRO_ENVIRONMENT_SET_MESSAGE_EXT. This allows the
* core to specify message logging level, priority and
* destination (OSD, logging interface or both).
*/
#define RETRO_ENVIRONMENT_SET_MESSAGE_EXT 60
/* const struct retro_message_ext * --
* Sets a message to be displayed in an implementation-specific
* manner for a certain amount of 'frames'. Additionally allows
* the core to specify message logging level, priority and
* destination (OSD, logging interface or both).
* Should not be used for trivial messages, which should simply be
* logged via RETRO_ENVIRONMENT_GET_LOG_INTERFACE (or as a
* fallback, stderr).
*/
#define RETRO_ENVIRONMENT_GET_INPUT_MAX_USERS 61
/* unsigned * --
* Unsigned value is the number of active input devices
* provided by the frontend. This may change between
* frames, but will remain constant for the duration
* of each frame.
* If callback returns true, a core need not poll any
* input device with an index greater than or equal to
* the number of active devices.
* If callback returns false, the number of active input
* devices is unknown. In this case, all input devices
* should be considered active.
*/
/* VFS functionality */
/* File paths:
@ -2307,7 +2384,8 @@ struct retro_keyboard_callback
retro_keyboard_event_t callback;
};
/* Callbacks for RETRO_ENVIRONMENT_SET_DISK_CONTROL_INTERFACE.
/* Callbacks for RETRO_ENVIRONMENT_SET_DISK_CONTROL_INTERFACE &
* RETRO_ENVIRONMENT_SET_DISK_CONTROL_EXT_INTERFACE.
* Should be set for implementations which can swap out multiple disk
* images in runtime.
*
@ -2365,6 +2443,53 @@ typedef bool (RETRO_CALLCONV *retro_replace_image_index_t)(unsigned index,
* with replace_image_index. */
typedef bool (RETRO_CALLCONV *retro_add_image_index_t)(void);
/* Sets initial image to insert in drive when calling
* core_load_game().
* Since we cannot pass the initial index when loading
* content (this would require a major API change), this
* is set by the frontend *before* calling the core's
* retro_load_game()/retro_load_game_special() implementation.
* A core should therefore cache the index/path values and handle
* them inside retro_load_game()/retro_load_game_special().
* - If 'index' is invalid (index >= get_num_images()), the
* core should ignore the set value and instead use 0
* - 'path' is used purely for error checking - i.e. when
* content is loaded, the core should verify that the
* disk specified by 'index' has the specified file path.
* This is to guard against auto selecting the wrong image
* if (for example) the user should modify an existing M3U
* playlist. We have to let the core handle this because
* set_initial_image() must be called before loading content,
* i.e. the frontend cannot access image paths in advance
* and thus cannot perform the error check itself.
* If set path and content path do not match, the core should
* ignore the set 'index' value and instead use 0
* Returns 'false' if index or 'path' are invalid, or core
* does not support this functionality
*/
typedef bool (RETRO_CALLCONV *retro_set_initial_image_t)(unsigned index, const char *path);
/* Fetches the path of the specified disk image file.
* Returns 'false' if index is invalid (index >= get_num_images())
* or path is otherwise unavailable.
*/
typedef bool (RETRO_CALLCONV *retro_get_image_path_t)(unsigned index, char *path, size_t len);
/* Fetches a core-provided 'label' for the specified disk
* image file. In the simplest case this may be a file name
* (without extension), but for cores with more complex
* content requirements information may be provided to
* facilitate user disk swapping - for example, a core
* running floppy-disk-based content may uniquely label
* save disks, data disks, level disks, etc. with names
* corresponding to in-game disk change prompts (so the
* frontend can provide better user guidance than a 'dumb'
* disk index value).
* Returns 'false' if index is invalid (index >= get_num_images())
* or label is otherwise unavailable.
*/
typedef bool (RETRO_CALLCONV *retro_get_image_label_t)(unsigned index, char *label, size_t len);
struct retro_disk_control_callback
{
retro_set_eject_state_t set_eject_state;
@ -2378,6 +2503,27 @@ struct retro_disk_control_callback
retro_add_image_index_t add_image_index;
};
struct retro_disk_control_ext_callback
{
retro_set_eject_state_t set_eject_state;
retro_get_eject_state_t get_eject_state;
retro_get_image_index_t get_image_index;
retro_set_image_index_t set_image_index;
retro_get_num_images_t get_num_images;
retro_replace_image_index_t replace_image_index;
retro_add_image_index_t add_image_index;
/* NOTE: Frontend will only attempt to record/restore
* last used disk index if both set_initial_image()
* and get_image_path() are implemented */
retro_set_initial_image_t set_initial_image; /* Optional - may be NULL */
retro_get_image_path_t get_image_path; /* Optional - may be NULL */
retro_get_image_label_t get_image_label; /* Optional - may be NULL */
};
enum retro_pixel_format
{
/* 0RGB1555, native endian.
@ -2408,6 +2554,104 @@ struct retro_message
unsigned frames; /* Duration in frames of message. */
};
enum retro_message_target
{
RETRO_MESSAGE_TARGET_ALL = 0,
RETRO_MESSAGE_TARGET_OSD,
RETRO_MESSAGE_TARGET_LOG
};
enum retro_message_type
{
RETRO_MESSAGE_TYPE_NOTIFICATION = 0,
RETRO_MESSAGE_TYPE_NOTIFICATION_ALT,
RETRO_MESSAGE_TYPE_STATUS,
RETRO_MESSAGE_TYPE_PROGRESS
};
struct retro_message_ext
{
/* Message string to be displayed/logged */
const char *msg;
/* Duration (in ms) of message when targeting the OSD */
unsigned duration;
/* Message priority when targeting the OSD
* > When multiple concurrent messages are sent to
* the frontend and the frontend does not have the
* capacity to display them all, messages with the
* *highest* priority value should be shown
* > There is no upper limit to a message priority
* value (within the bounds of the unsigned data type)
* > In the reference frontend (RetroArch), the same
* priority values are used for frontend-generated
* notifications, which are typically assigned values
* between 0 and 3 depending upon importance */
unsigned priority;
/* Message logging level (info, warn, error, etc.) */
enum retro_log_level level;
/* Message destination: OSD, logging interface or both */
enum retro_message_target target;
/* Message 'type' when targeting the OSD
* > RETRO_MESSAGE_TYPE_NOTIFICATION: Specifies that a
* message should be handled in identical fashion to
* a standard frontend-generated notification
* > RETRO_MESSAGE_TYPE_NOTIFICATION_ALT: Specifies that
* message is a notification that requires user attention
* or action, but that it should be displayed in a manner
* that differs from standard frontend-generated notifications.
* This would typically correspond to messages that should be
* displayed immediately (independently from any internal
* frontend message queue), and/or which should be visually
* distinguishable from frontend-generated notifications.
* For example, a core may wish to inform the user of
* information related to a disk-change event. It is
* expected that the frontend itself may provide a
* notification in this case; if the core sends a
* message of type RETRO_MESSAGE_TYPE_NOTIFICATION, an
* uncomfortable 'double-notification' may occur. A message
* of RETRO_MESSAGE_TYPE_NOTIFICATION_ALT should therefore
* be presented such that visual conflict with regular
* notifications does not occur
* > RETRO_MESSAGE_TYPE_STATUS: Indicates that message
* is not a standard notification. This typically
* corresponds to 'status' indicators, such as a core's
* internal FPS, which are intended to be displayed
* either permanently while a core is running, or in
* a manner that does not suggest user attention or action
* is required. 'Status' type messages should therefore be
* displayed in a different on-screen location and in a manner
* easily distinguishable from both standard frontend-generated
* notifications and messages of type RETRO_MESSAGE_TYPE_NOTIFICATION_ALT
* > RETRO_MESSAGE_TYPE_PROGRESS: Indicates that message reports
* the progress of an internal core task. For example, in cases
* where a core itself handles the loading of content from a file,
* this may correspond to the percentage of the file that has been
* read. Alternatively, an audio/video playback core may use a
* message of type RETRO_MESSAGE_TYPE_PROGRESS to display the current
* playback position as a percentage of the runtime. 'Progress' type
* messages should therefore be displayed as a literal progress bar,
* where:
* - 'retro_message_ext.msg' is the progress bar title/label
* - 'retro_message_ext.progress' determines the length of
* the progress bar
* NOTE: Message type is a *hint*, and may be ignored
* by the frontend. If a frontend lacks support for
* displaying messages via alternate means than standard
* frontend-generated notifications, it will treat *all*
* messages as having the type RETRO_MESSAGE_TYPE_NOTIFICATION */
enum retro_message_type type;
/* Task progress when targeting the OSD and message is
* of type RETRO_MESSAGE_TYPE_PROGRESS
* > -1: Unmetered/indeterminate
* > 0-100: Current progress percentage
* NOTE: Since message type is a hint, a frontend may ignore
* progress values. Where relevant, a core should therefore
* include progress percentage within the message string,
* such that the message intent remains clear when displayed
* as a standard frontend-generated notification */
int8_t progress;
};
/* Describes how the libretro implementation maps a libretro input bind
* to its internal input system through a human readable string.
* This string can be used to better let a user configure input. */
@ -2428,7 +2672,7 @@ struct retro_input_descriptor
struct retro_system_info
{
/* All pointers are owned by libretro implementation, and pointers must
* remain valid until retro_deinit() is called. */
* remain valid until it is unloaded. */
const char *library_name; /* Descriptive name of library. Should not
* contain any version numbers, etc. */
@ -2522,8 +2766,20 @@ struct retro_core_option_display
};
/* Maximum number of values permitted for a core option
* NOTE: This may be increased on a core-by-core basis
* if required (doing so has no effect on the frontend) */
* > Note: We have to set a maximum value due the limitations
* of the C language - i.e. it is not possible to create an
* array of structs each containing a variable sized array,
* so the retro_core_option_definition values array must
* have a fixed size. The size limit of 128 is a balancing
* act - it needs to be large enough to support all 'sane'
* core options, but setting it too large may impact low memory
* platforms. In practise, if a core option has more than
* 128 values then the implementation is likely flawed.
* To quote the above API reference:
* "The number of possible options should be very limited
* i.e. it should be feasible to cycle through options
* without a keyboard."
*/
#define RETRO_NUM_CORE_OPTION_VALUES_MAX 128
struct retro_core_option_value

View File

@ -1,4 +1,4 @@
/* Copyright (C) 2010-2018 The RetroArch team
/* Copyright (C) 2010-2020 The RetroArch team
*
* ---------------------------------------------------------------------------------------
* The following license statement only applies to this file (memmap.h).

View File

@ -1,4 +1,4 @@
/* Copyright (C) 2010-2018 The RetroArch team
/* Copyright (C) 2010-2020 The RetroArch team
*
* ---------------------------------------------------------------------------------------
* The following license statement only applies to this file (retro_assert.h).

View File

@ -1,4 +1,4 @@
/* Copyright (C) 2010-2018 The RetroArch team
/* Copyright (C) 2010-2020 The RetroArch team
*
* ---------------------------------------------------------------------------------------
* The following license statement only applies to this file (retro_common.h).

View File

@ -1,4 +1,4 @@
/* Copyright (C) 2010-2018 The RetroArch team
/* Copyright (C) 2010-2020 The RetroArch team
*
* ---------------------------------------------------------------------------------------
* The following license statement only applies to this file (retro_common_api.h).

View File

@ -1,4 +1,4 @@
/* Copyright (C) 2010-2018 The RetroArch team
/* Copyright (C) 2010-2020 The RetroArch team
*
* ---------------------------------------------------------------------------------------
* The following license statement only applies to this file (retro_environment.h).

View File

@ -1,4 +1,4 @@
/* Copyright (C) 2010-2018 The RetroArch team
/* Copyright (C) 2010-2020 The RetroArch team
*
* ---------------------------------------------------------------------------------------
* The following license statement only applies to this file (retro_inline.h).

View File

@ -1,4 +1,4 @@
/* Copyright (C) 2010-2018 The RetroArch team
/* Copyright (C) 2010-2020 The RetroArch team
*
* ---------------------------------------------------------------------------------------
* The following license statement only applies to this file (retro_miscellaneous.h).
@ -30,16 +30,20 @@
#include <boolean.h>
#include <retro_inline.h>
#if defined(_WIN32) && !defined(_XBOX)
#if defined(_WIN32)
#if defined(_XBOX)
#include <Xtl.h>
#else
#ifndef WIN32_LEAN_AND_MEAN
#define WIN32_LEAN_AND_MEAN
#endif
#include <windows.h>
#elif defined(_WIN32) && defined(_XBOX)
#include <Xtl.h>
#endif
#if defined(__CELLOS_LV2__)
#endif
#if defined(__CELLOS_LV2__) && !defined(__PSL1GHT__)
#include <sys/fs_external.h>
#endif
@ -75,7 +79,7 @@ static INLINE bool bits_any_set(uint32_t* ptr, uint32_t count)
}
#ifndef PATH_MAX_LENGTH
#if defined(__CELLOS_LV2__)
#if defined(__CELLOS_LV2__) && !defined(__PSL1GHT__)
#define PATH_MAX_LENGTH CELL_FS_MAX_FS_PATH_LENGTH
#elif defined(_XBOX1) || defined(_3DS) || defined(PSP) || defined(PS2) || defined(GEKKO)|| defined(WIIU) || defined(ORBIS)
#define PATH_MAX_LENGTH 512
@ -106,8 +110,8 @@ static INLINE bool bits_any_set(uint32_t* ptr, uint32_t count)
#define BIT16_GET(a, bit) (((a) >> ((bit) & 15)) & 1)
#define BIT16_CLEAR_ALL(a) ((a) = 0)
#define BIT32_SET(a, bit) ((a) |= (1 << ((bit) & 31)))
#define BIT32_CLEAR(a, bit) ((a) &= ~(1 << ((bit) & 31)))
#define BIT32_SET(a, bit) ((a) |= (UINT32_C(1) << ((bit) & 31)))
#define BIT32_CLEAR(a, bit) ((a) &= ~(UINT32_C(1) << ((bit) & 31)))
#define BIT32_GET(a, bit) (((a) >> ((bit) & 31)) & 1)
#define BIT32_CLEAR_ALL(a) ((a) = 0)
@ -116,8 +120,8 @@ static INLINE bool bits_any_set(uint32_t* ptr, uint32_t count)
#define BIT64_GET(a, bit) (((a) >> ((bit) & 63)) & 1)
#define BIT64_CLEAR_ALL(a) ((a) = 0)
#define BIT128_SET(a, bit) ((a).data[(bit) >> 5] |= (1 << ((bit) & 31)))
#define BIT128_CLEAR(a, bit) ((a).data[(bit) >> 5] &= ~(1 << ((bit) & 31)))
#define BIT128_SET(a, bit) ((a).data[(bit) >> 5] |= (UINT32_C(1) << ((bit) & 31)))
#define BIT128_CLEAR(a, bit) ((a).data[(bit) >> 5] &= ~(UINT32_C(1) << ((bit) & 31)))
#define BIT128_GET(a, bit) (((a).data[(bit) >> 5] >> ((bit) & 31)) & 1)
#define BIT128_CLEAR_ALL(a) memset(&(a), 0, sizeof(a))
@ -165,7 +169,7 @@ typedef struct
# define PRI_SIZET "u"
# endif
# endif
#elif PS2
#elif defined(PS2)
# define PRI_SIZET "u"
#else
# if (SIZE_MAX == 0xFFFF)

View File

@ -1,4 +1,4 @@
/* Copyright (C) 2010-2018 The RetroArch team
/* Copyright (C) 2010-2020 The RetroArch team
*
* ---------------------------------------------------------------------------------------
* The following license statement only applies to this file (file_stream.h).

View File

@ -1,4 +1,4 @@
/* Copyright (C) 2010-2019 The RetroArch team
/* Copyright (C) 2010-2020 The RetroArch team
*
* ---------------------------------------------------------------------------------------
* The following license statement only applies to this file (stdstring.h).
@ -35,6 +35,33 @@
RETRO_BEGIN_DECLS
#define STRLEN_CONST(x) ((sizeof((x))-1))
#define strcpy_literal(a, b) strcpy(a, b)
#define string_is_not_equal(a, b) !string_is_equal((a), (b))
#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)
#define TOLOWER(c) (c | (lr_char_props[c] & 0x20))
#define TOUPPER(c) (c & ~(lr_char_props[c] & 0x20))
/* C standard says \f \v are space, but this one disagrees */
#define ISSPACE(c) (lr_char_props[c] & 0x80)
#define ISDIGIT(c) (lr_char_props[c] & 0x40)
#define ISALPHA(c) (lr_char_props[c] & 0x20)
#define ISLOWER(c) (lr_char_props[c] & 0x04)
#define ISUPPER(c) (lr_char_props[c] & 0x02)
#define ISALNUM(c) (lr_char_props[c] & 0x60)
#define ISUALPHA(c) (lr_char_props[c] & 0x28)
#define ISUALNUM(c) (lr_char_props[c] & 0x68)
#define IS_XDIGIT(c) (lr_char_props[c] & 0x01)
/* Deprecated alias, all callers should use string_is_equal_case_insensitive instead */
#define string_is_equal_noncase string_is_equal_case_insensitive
static INLINE bool string_is_empty(const char *data)
{
return !data || (*data == '\0');
@ -45,12 +72,44 @@ static INLINE bool string_is_equal(const char *a, const char *b)
return (a && b) ? !strcmp(a, b) : false;
}
#define STRLEN_CONST(x) ((sizeof((x))-1))
static INLINE bool string_starts_with_size(const char *str, const char *prefix,
size_t size)
{
return (str && prefix) ? !strncmp(prefix, str, size) : false;
}
#define string_is_not_equal(a, b) !string_is_equal((a), (b))
static INLINE bool string_starts_with(const char *str, const char *prefix)
{
return (str && prefix) ? !strncmp(prefix, str, strlen(prefix)) : false;
}
static INLINE bool string_ends_with_size(const char *str, const char *suffix,
size_t str_len, size_t suffix_len)
{
return (str_len < suffix_len) ? false :
!memcmp(suffix, str + (str_len - suffix_len), suffix_len);
}
static INLINE bool string_ends_with(const char *str, const char *suffix)
{
if (!str || !suffix)
return false;
return string_ends_with_size(str, suffix, strlen(str), strlen(suffix));
}
/* Returns the length of 'str' (c.f. strlen()), but only
* checks the first 'size' characters
* - If 'str' is NULL, returns 0
* - If 'str' is not NULL and no '\0' character is found
* in the first 'size' characters, returns 'size' */
static INLINE size_t strlen_size(const char *str, size_t size)
{
size_t i = 0;
if (str)
while (i < size && str[i]) i++;
return i;
}
#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)
@ -71,24 +130,6 @@ static INLINE bool string_is_equal_case_insensitive(const char *a,
return (result == 0);
}
static INLINE bool string_is_equal_noncase(const char *a, const char *b)
{
int result = 0;
const unsigned char *p1 = (const unsigned char*)a;
const unsigned char *p2 = (const unsigned char*)b;
if (!a || !b)
return false;
if (p1 == p2)
return false;
while ((result = tolower (*p1) - tolower (*p2++)) == 0)
if (*p1++ == '\0')
break;
return (result == 0);
}
char *string_to_upper(char *s);
char *string_to_lower(char *s);
@ -121,7 +162,7 @@ char *word_wrap(char *buffer, const char *string,
* char *str = "1,2,3,4,5,6,7,,,10,";
* char **str_ptr = &str;
* char *token = NULL;
* while((token = string_tokenize(str_ptr, ",")))
* while ((token = string_tokenize(str_ptr, ",")))
* {
* printf("%s\n", token);
* free(token);
@ -141,6 +182,17 @@ void string_replace_all_chars(char *str, char find, char replace);
* Returns 0 if string is invalid */
unsigned string_to_unsigned(const char *str);
/* Converts hexadecimal string to unsigned integer.
* Handles optional leading '0x'.
* Returns 0 if string is invalid */
unsigned string_hex_to_unsigned(const char *str);
char *string_init(const char *src);
void string_set(char **string, const char *src);
extern const unsigned char lr_char_props[256];
RETRO_END_DECLS
#endif

View File

@ -0,0 +1,48 @@
/* Copyright (C) 2010-2020 The RetroArch team
*
* ---------------------------------------------------------------------------------------
* The following license statement only applies to this file (rtime.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_RTIME_H__
#define __LIBRETRO_SDK_RTIME_H__
#include <retro_common_api.h>
#include <stdint.h>
#include <stddef.h>
#include <time.h>
RETRO_BEGIN_DECLS
/* TODO/FIXME: Move all generic time handling functions
* to this file */
/* Must be called before using rtime_localtime() */
void rtime_init(void);
/* Must be called upon program termination */
void rtime_deinit(void);
/* Thread-safe wrapper for localtime() */
struct tm *rtime_localtime(const time_t *timep, struct tm *result);
RETRO_END_DECLS
#endif

View File

@ -1,4 +1,4 @@
/* Copyright (C) 2010-2019 The RetroArch team
/* Copyright (C) 2010-2020 The RetroArch team
*
* ---------------------------------------------------------------------------------------
* The following license statement only applies to this file (vfs_implementation.h).
@ -41,17 +41,17 @@ typedef void* HANDLE;
#ifdef HAVE_CDROM
typedef struct
{
int64_t byte_pos;
char *cue_buf;
size_t cue_len;
int64_t byte_pos;
char drive;
unsigned cur_lba;
unsigned last_frame_lba;
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];
char drive;
bool last_frame_valid;
} vfs_cdrom_t;
#endif
@ -69,22 +69,22 @@ struct retro_vfs_file_handle
struct libretro_vfs_implementation_file
#endif
{
int fd;
unsigned hints;
#ifdef HAVE_CDROM
vfs_cdrom_t cdrom; /* int64_t alignment */
#endif
int64_t size;
char *buf;
uint64_t mappos;
uint64_t mapsize;
FILE *fp;
#ifdef _WIN32
HANDLE fh;
#endif
char *buf;
char* orig_path;
uint64_t mappos;
uint64_t mapsize;
uint8_t *mapped;
int fd;
unsigned hints;
enum vfs_scheme scheme;
#ifdef HAVE_CDROM
vfs_cdrom_t cdrom;
#endif
};
#endif

View File

@ -1,4 +1,4 @@
/* Copyright (C) 2010-2019 The RetroArch team
/* Copyright (C) 2010-2020 The RetroArch team
*
* ---------------------------------------------------------------------------------------
* The following license statement only applies to this file (vfs_implementation.h).

View File

@ -1,4 +1,4 @@
/* Copyright (C) 2010-2018 The RetroArch team
/* Copyright (C) 2010-2020 The RetroArch team
*
* ---------------------------------------------------------------------------------------
* The following license statement only applies to this file (file_stream.c).
@ -31,11 +31,23 @@
#include "config.h"
#endif
#ifdef _MSC_VER
#include <compat/msvc.h>
#endif
#include <string/stdstring.h>
#include <streams/file_stream.h>
#define VFS_FRONTEND
#include <vfs/vfs_implementation.h>
static const int64_t vfs_error_return_value = -1;
#define VFS_ERROR_RETURN_VALUE -1
struct RFILE
{
struct retro_vfs_file_handle *hfile;
bool error_flag;
bool eof_flag;
};
static retro_vfs_get_path_t filestream_get_path_cb = NULL;
static retro_vfs_open_t filestream_open_cb = NULL;
@ -50,18 +62,12 @@ static retro_vfs_flush_t filestream_flush_cb = NULL;
static retro_vfs_remove_t filestream_remove_cb = NULL;
static retro_vfs_rename_t filestream_rename_cb = NULL;
struct RFILE
{
struct retro_vfs_file_handle *hfile;
bool error_flag;
bool eof_flag;
};
/* VFS Initialization */
void filestream_vfs_init(const struct retro_vfs_interface_info* vfs_info)
{
const struct retro_vfs_interface* vfs_iface;
const struct retro_vfs_interface *
vfs_iface = vfs_info->iface;
filestream_get_path_cb = NULL;
filestream_open_cb = NULL;
@ -76,9 +82,9 @@ void filestream_vfs_init(const struct retro_vfs_interface_info* vfs_info)
filestream_remove_cb = NULL;
filestream_rename_cb = NULL;
vfs_iface = vfs_info->iface;
if (vfs_info->required_interface_version < FILESTREAM_REQUIRED_VFS_VERSION
if (
(vfs_info->required_interface_version <
FILESTREAM_REQUIRED_VFS_VERSION)
|| !vfs_iface)
return;
@ -99,19 +105,24 @@ void filestream_vfs_init(const struct retro_vfs_interface_info* vfs_info)
/* Callback wrappers */
bool filestream_exists(const char *path)
{
RFILE *dummy = NULL;
RFILE *dummy = NULL;
if (!path || !*path)
return false;
dummy = filestream_open(path,
dummy = filestream_open(
path,
RETRO_VFS_FILE_ACCESS_READ,
RETRO_VFS_FILE_ACCESS_HINT_NONE);
if (!dummy)
return false;
filestream_close(dummy);
if (filestream_close(dummy) != 0)
if (dummy)
free(dummy);
dummy = NULL;
return true;
}
@ -119,12 +130,13 @@ int64_t filestream_get_size(RFILE *stream)
{
int64_t output;
if (filestream_size_cb != NULL)
if (filestream_size_cb)
output = filestream_size_cb(stream->hfile);
else
output = retro_vfs_file_size_impl((libretro_vfs_implementation_file*)stream->hfile);
output = retro_vfs_file_size_impl(
(libretro_vfs_implementation_file*)stream->hfile);
if (output == vfs_error_return_value)
if (output == VFS_ERROR_RETURN_VALUE)
stream->error_flag = true;
return output;
@ -134,12 +146,13 @@ int64_t filestream_truncate(RFILE *stream, int64_t length)
{
int64_t output;
if (filestream_truncate_cb != NULL)
if (filestream_truncate_cb)
output = filestream_truncate_cb(stream->hfile, length);
else
output = retro_vfs_file_truncate_impl((libretro_vfs_implementation_file*)stream->hfile, length);
output = retro_vfs_file_truncate_impl(
(libretro_vfs_implementation_file*)stream->hfile, length);
if (output == vfs_error_return_value)
if (output == VFS_ERROR_RETURN_VALUE)
stream->error_flag = true;
return output;
@ -159,7 +172,7 @@ RFILE* filestream_open(const char *path, unsigned mode, unsigned hints)
struct retro_vfs_file_handle *fp = NULL;
RFILE* output = NULL;
if (filestream_open_cb != NULL)
if (filestream_open_cb)
fp = (struct retro_vfs_file_handle*)
filestream_open_cb(path, mode, hints);
else
@ -203,9 +216,7 @@ char* filestream_gets(RFILE *stream, char *s, size_t len)
int filestream_getc(RFILE *stream)
{
char c = 0;
if (!stream)
return EOF;
if (filestream_read(stream, &c, 1) == 1)
if (stream && filestream_read(stream, &c, 1) == 1)
return (int)(unsigned char)c;
return EOF;
}
@ -215,10 +226,9 @@ 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 startpos = filestream_tell(stream);
int64_t maxlen = filestream_read(stream, buf, sizeof(buf)-1);
if (maxlen <= 0)
@ -233,7 +243,6 @@ int filestream_scanf(RFILE *stream, const char* format, ...)
if (*format == '%')
{
int sublen;
char* subfmtiter = subfmt;
bool asterisk = false;
@ -243,19 +252,25 @@ int filestream_scanf(RFILE *stream, const char* format, ...)
if (*format == '*')
{
asterisk = true;
asterisk = true;
*subfmtiter++ = *format++;
}
while (isdigit(*format)) *subfmtiter++ = *format++; /* width */
while (ISDIGIT((unsigned char)*format))
*subfmtiter++ = *format++; /* width */
/* length */
if (*format == 'h' || *format == 'l')
{
if (format[1] == format[0]) *subfmtiter++ = *format++;
*subfmtiter++ = *format++;
if (format[1] == format[0])
*subfmtiter++ = *format++;
*subfmtiter++ = *format++;
}
else if (*format == 'j' || *format == 'z' || *format == 't' || *format == 'L')
else if (
*format == 'j' ||
*format == 'z' ||
*format == 't' ||
*format == 'L')
{
*subfmtiter++ = *format++;
}
@ -263,31 +278,44 @@ int filestream_scanf(RFILE *stream, const char* format, ...)
/* specifier - always a single character (except ]) */
if (*format == '[')
{
while (*format != ']') *subfmtiter++ = *format++;
*subfmtiter++ = *format++;
while (*format != ']')
*subfmtiter++ = *format++;
*subfmtiter++ = *format++;
}
else *subfmtiter++ = *format++;
else
*subfmtiter++ = *format++;
*subfmtiter++ = '%';
*subfmtiter++ = 'n';
*subfmtiter++ = '\0';
*subfmtiter++ = '%';
*subfmtiter++ = 'n';
*subfmtiter++ = '\0';
if (sizeof(void*) != sizeof(long*))
abort(); /* all pointers must have the same size */
if (sizeof(void*) != sizeof(long*)) abort(); /* all pointers must have the same size */
if (asterisk)
{
if (sscanf(bufiter, subfmt, &sublen) != 0) break;
int v = sscanf(bufiter, subfmt, &sublen);
if (v == EOF)
return EOF;
if (v != 0)
break;
}
else
{
if (sscanf(bufiter, subfmt, va_arg(args, void*), &sublen) != 1) break;
int v = sscanf(bufiter, subfmt, va_arg(args, void*), &sublen);
if (v == EOF)
return EOF;
if (v != 1)
break;
}
ret++;
bufiter += sublen;
}
else if (isspace(*format))
else if (isspace((unsigned char)*format))
{
while (isspace(*bufiter)) bufiter++;
while (isspace((unsigned char)*bufiter))
bufiter++;
format++;
}
else
@ -300,7 +328,8 @@ int filestream_scanf(RFILE *stream, const char* format, ...)
}
va_end(args);
filestream_seek(stream, startpos+(bufiter-buf), RETRO_VFS_SEEK_POSITION_START);
filestream_seek(stream, startpos+(bufiter-buf),
RETRO_VFS_SEEK_POSITION_START);
return ret;
}
@ -309,14 +338,17 @@ int64_t filestream_seek(RFILE *stream, int64_t offset, int seek_position)
{
int64_t output;
if (filestream_seek_cb != NULL)
if (filestream_seek_cb)
output = filestream_seek_cb(stream->hfile, offset, seek_position);
else
output = retro_vfs_file_seek_impl((libretro_vfs_implementation_file*)stream->hfile, offset, seek_position);
output = retro_vfs_file_seek_impl(
(libretro_vfs_implementation_file*)stream->hfile,
offset, seek_position);
if (output == vfs_error_return_value)
if (output == VFS_ERROR_RETURN_VALUE)
stream->error_flag = true;
stream->eof_flag = false;
stream->eof_flag = false;
return output;
}
@ -330,12 +362,13 @@ int64_t filestream_tell(RFILE *stream)
{
int64_t output;
if (filestream_size_cb != NULL)
if (filestream_size_cb)
output = filestream_tell_cb(stream->hfile);
else
output = retro_vfs_file_tell_impl((libretro_vfs_implementation_file*)stream->hfile);
output = retro_vfs_file_tell_impl(
(libretro_vfs_implementation_file*)stream->hfile);
if (output == vfs_error_return_value)
if (output == VFS_ERROR_RETURN_VALUE)
stream->error_flag = true;
return output;
@ -347,23 +380,23 @@ void filestream_rewind(RFILE *stream)
return;
filestream_seek(stream, 0L, RETRO_VFS_SEEK_POSITION_START);
stream->error_flag = false;
stream->eof_flag = false;
stream->eof_flag = false;
}
int64_t filestream_read(RFILE *stream, void *s, int64_t len)
{
int64_t output;
if (filestream_read_cb != NULL)
if (filestream_read_cb)
output = filestream_read_cb(stream->hfile, s, len);
else
output = retro_vfs_file_read_impl(
(libretro_vfs_implementation_file*)stream->hfile, s, len);
if (output == vfs_error_return_value)
if (output == VFS_ERROR_RETURN_VALUE)
stream->error_flag = true;
if (output < len)
stream->eof_flag = true;
stream->eof_flag = true;
return output;
}
@ -372,12 +405,13 @@ int filestream_flush(RFILE *stream)
{
int output;
if (filestream_flush_cb != NULL)
if (filestream_flush_cb)
output = filestream_flush_cb(stream->hfile);
else
output = retro_vfs_file_flush_impl((libretro_vfs_implementation_file*)stream->hfile);
output = retro_vfs_file_flush_impl(
(libretro_vfs_implementation_file*)stream->hfile);
if (output == vfs_error_return_value)
if (output == VFS_ERROR_RETURN_VALUE)
stream->error_flag = true;
return output;
@ -385,7 +419,7 @@ int filestream_flush(RFILE *stream)
int filestream_delete(const char *path)
{
if (filestream_remove_cb != NULL)
if (filestream_remove_cb)
return filestream_remove_cb(path);
return retro_vfs_file_remove_impl(path);
@ -393,7 +427,7 @@ int filestream_delete(const char *path)
int filestream_rename(const char *old_path, const char *new_path)
{
if (filestream_rename_cb != NULL)
if (filestream_rename_cb)
return filestream_rename_cb(old_path, new_path);
return retro_vfs_file_rename_impl(old_path, new_path);
@ -401,22 +435,24 @@ int filestream_rename(const char *old_path, const char *new_path)
const char* filestream_get_path(RFILE *stream)
{
if (filestream_get_path_cb != NULL)
if (filestream_get_path_cb)
return filestream_get_path_cb(stream->hfile);
return retro_vfs_file_get_path_impl((libretro_vfs_implementation_file*)stream->hfile);
return retro_vfs_file_get_path_impl(
(libretro_vfs_implementation_file*)stream->hfile);
}
int64_t filestream_write(RFILE *stream, const void *s, int64_t len)
{
int64_t output;
if (filestream_write_cb != NULL)
if (filestream_write_cb)
output = filestream_write_cb(stream->hfile, s, len);
else
output = retro_vfs_file_write_impl((libretro_vfs_implementation_file*)stream->hfile, s, len);
output = retro_vfs_file_write_impl(
(libretro_vfs_implementation_file*)stream->hfile, s, len);
if (output == vfs_error_return_value)
if (output == VFS_ERROR_RETURN_VALUE)
stream->error_flag = true;
return output;
@ -427,13 +463,16 @@ int filestream_putc(RFILE *stream, int c)
char c_char = (char)c;
if (!stream)
return EOF;
return filestream_write(stream, &c_char, 1)==1 ? (int)(unsigned char)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)
{
static char buffer[8 * 1024];
int64_t num_chars = vsprintf(buffer, format, args);
int64_t num_chars = vsnprintf(buffer, sizeof(buffer),
format, args);
if (num_chars < 0)
return -1;
@ -465,10 +504,11 @@ int filestream_close(RFILE *stream)
int output;
struct retro_vfs_file_handle* fp = stream->hfile;
if (filestream_close_cb != NULL)
if (filestream_close_cb)
output = filestream_close_cb(fp);
else
output = retro_vfs_file_close_impl((libretro_vfs_implementation_file*)fp);
output = retro_vfs_file_close_impl(
(libretro_vfs_implementation_file*)fp);
if (output == 0)
free(stream);
@ -497,8 +537,8 @@ int64_t filestream_read_file(const char *path, void **buf, int64_t *len)
if (!file)
{
fprintf(stderr, "Failed to open %s: %s\n", path, strerror(errno));
goto error;
*buf = NULL;
return 0;
}
content_buf_size = filestream_get_size(file);
@ -515,12 +555,11 @@ int64_t filestream_read_file(const char *path, void **buf, int64_t *len)
ret = filestream_read(file, content_buf, (int64_t)content_buf_size);
if (ret < 0)
{
fprintf(stderr, "Failed to read %s: %s\n", path, strerror(errno));
goto error;
}
filestream_close(file);
if (filestream_close(file) != 0)
if (file)
free(file);
*buf = content_buf;
@ -535,7 +574,8 @@ int64_t filestream_read_file(const char *path, void **buf, int64_t *len)
error:
if (file)
filestream_close(file);
if (filestream_close(file) != 0)
free(file);
if (content_buf)
free(content_buf);
if (len)
@ -564,7 +604,9 @@ bool filestream_write_file(const char *path, const void *data, int64_t size)
return false;
ret = filestream_write(file, data, size);
filestream_close(file);
if (filestream_close(file) != 0)
if (file)
free(file);
if (ret != size)
return false;

View File

@ -0,0 +1,416 @@
/* Copyright (C) 2010-2020 The RetroArch team
*
* ---------------------------------------------------------------------------------------
* The following license statement only applies to this file (stdstring.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 <ctype.h>
#include <string/stdstring.h>
#include <encodings/utf.h>
const uint8_t lr_char_props[256] = {
/*x0 x1 x2 x3 x4 x5 x6 x7 x8 x9 xA xB xC xD xE xF */
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x80,0x80,0x00,0x00,0x80,0x00,0x00, /* 0x */
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, /* 1x */
0x80,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, /* 2x !"#$%&'()*+,-./ */
0x41,0x41,0x41,0x41,0x41,0x41,0x41,0x41,0x41,0x41,0x00,0x00,0x00,0x00,0x00,0x00, /* 3x 0123456789:;<=>? */
0x00,0x23,0x23,0x23,0x23,0x23,0x23,0x22,0x22,0x22,0x22,0x22,0x22,0x22,0x22,0x22, /* 4x @ABCDEFGHIJKLMNO */
0x22,0x22,0x22,0x22,0x22,0x22,0x22,0x22,0x22,0x22,0x22,0x00,0x00,0x00,0x00,0x08, /* 5x PQRSTUVWXYZ[\]^_ */
0x00,0x25,0x25,0x25,0x25,0x25,0x25,0x24,0x24,0x24,0x24,0x24,0x24,0x24,0x24,0x24, /* 6x `abcdefghijklmno */
0x24,0x24,0x24,0x24,0x24,0x24,0x24,0x24,0x24,0x24,0x24,0x00,0x00,0x00,0x00,0x00, /* 7x pqrstuvwxyz{|}~ */
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, /* 8x */
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, /* 9x */
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, /* Ax */
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, /* Bx */
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, /* Cx */
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, /* Dx */
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, /* Ex */
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, /* Fx */
};
char *string_init(const char *src)
{
return src ? strdup(src) : NULL;
}
void string_set(char **string, const char *src)
{
free(*string);
*string = string_init(src);
}
char *string_to_upper(char *s)
{
char *cs = (char *)s;
for ( ; *cs != '\0'; cs++)
*cs = toupper((unsigned char)*cs);
return s;
}
char *string_to_lower(char *s)
{
char *cs = (char *)s;
for ( ; *cs != '\0'; cs++)
*cs = tolower((unsigned char)*cs);
return s;
}
char *string_ucwords(char *s)
{
char *cs = (char *)s;
for ( ; *cs != '\0'; cs++)
{
if (*cs == ' ')
*(cs+1) = toupper((unsigned char)*(cs+1));
}
s[0] = toupper((unsigned char)s[0]);
return s;
}
char *string_replace_substring(const char *in,
const char *pattern, const char *replacement)
{
size_t numhits, pattern_len, replacement_len, outlen;
const char *inat = NULL;
const char *inprev = NULL;
char *out = NULL;
char *outat = NULL;
/* if either pattern or replacement is NULL,
* duplicate in and let caller handle it. */
if (!pattern || !replacement)
return strdup(in);
pattern_len = strlen(pattern);
replacement_len = strlen(replacement);
numhits = 0;
inat = in;
while ((inat = strstr(inat, pattern)))
{
inat += pattern_len;
numhits++;
}
outlen = strlen(in) - pattern_len*numhits + replacement_len*numhits;
out = (char *)malloc(outlen+1);
if (!out)
return NULL;
outat = out;
inat = in;
inprev = in;
while ((inat = strstr(inat, pattern)))
{
memcpy(outat, inprev, inat-inprev);
outat += inat-inprev;
memcpy(outat, replacement, replacement_len);
outat += replacement_len;
inat += pattern_len;
inprev = inat;
}
strcpy(outat, inprev);
return out;
}
/* Remove leading whitespaces */
char *string_trim_whitespace_left(char *const s)
{
if (s && *s)
{
size_t len = strlen(s);
char *current = s;
while (*current && ISSPACE((unsigned char)*current))
{
++current;
--len;
}
if (s != current)
memmove(s, current, len + 1);
}
return s;
}
/* Remove trailing whitespaces */
char *string_trim_whitespace_right(char *const s)
{
if (s && *s)
{
size_t len = strlen(s);
char *current = s + len - 1;
while (current != s && ISSPACE((unsigned char)*current))
{
--current;
--len;
}
current[ISSPACE((unsigned char)*current) ? 0 : 1] = '\0';
}
return s;
}
/* Remove leading and trailing whitespaces */
char *string_trim_whitespace(char *const s)
{
string_trim_whitespace_right(s); /* order matters */
string_trim_whitespace_left(s);
return s;
}
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 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++)
{
const char *character;
unsigned char_len;
unsigned j = i;
/* check if end of string reached */
if (i == len)
{
buffer[i] = 0;
return buffer;
}
character = utf8skip(&string[i], 1);
char_len = (unsigned)(character - &string[i]);
if (!unicode)
counter += char_len - 1;
do
{
buffer[i] = string[i];
char_len--;
i++;
} while (char_len);
/* 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] == ' ')
{
if ((max_lines == 0 || lines < max_lines))
{
buffer[i] = '\n';
i++;
lines++;
}
}
else
{
int k;
/* check for nearest whitespace back in string */
for (k = i; k > 0; 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;
}
}
buffer[i] = 0;
return buffer;
}
/* Splits string into tokens seperated by 'delim'
* > Returned token string must be free()'d
* > Returns NULL if token is not found
* > After each call, 'str' is set to the position after the
* last found token
* > Tokens *include* empty strings
* Usage example:
* char *str = "1,2,3,4,5,6,7,,,10,";
* char **str_ptr = &str;
* char *token = NULL;
* while ((token = string_tokenize(str_ptr, ",")))
* {
* printf("%s\n", token);
* free(token);
* token = NULL;
* }
*/
char* string_tokenize(char **str, const char *delim)
{
/* Taken from https://codereview.stackexchange.com/questions/216956/strtok-function-thread-safe-supports-empty-tokens-doesnt-change-string# */
char *str_ptr = NULL;
char *delim_ptr = NULL;
char *token = NULL;
size_t token_len = 0;
/* Sanity checks */
if (!str || string_is_empty(delim))
return NULL;
str_ptr = *str;
/* Note: we don't check string_is_empty() here,
* empty strings are valid */
if (!str_ptr)
return NULL;
/* Search for delimiter */
delim_ptr = strstr(str_ptr, delim);
if (delim_ptr)
token_len = delim_ptr - str_ptr;
else
token_len = strlen(str_ptr);
/* Allocate token string */
token = (char *)malloc((token_len + 1) * sizeof(char));
if (!token)
return NULL;
/* Copy token */
strlcpy(token, str_ptr, (token_len + 1) * sizeof(char));
token[token_len] = '\0';
/* Update input string pointer */
*str = delim_ptr ? delim_ptr + strlen(delim) : NULL;
return token;
}
/* Removes every instance of character 'c' from 'str' */
void string_remove_all_chars(char *str, char c)
{
char *read_ptr = NULL;
char *write_ptr = NULL;
if (string_is_empty(str))
return;
read_ptr = str;
write_ptr = str;
while (*read_ptr != '\0')
{
*write_ptr = *read_ptr++;
write_ptr += (*write_ptr != c) ? 1 : 0;
}
*write_ptr = '\0';
}
/* Replaces every instance of character 'find' in 'str'
* with character 'replace' */
void string_replace_all_chars(char *str, char find, char replace)
{
char *str_ptr = str;
if (string_is_empty(str))
return;
while ((str_ptr = strchr(str_ptr, find)))
*str_ptr++ = replace;
}
/* Converts string to unsigned integer.
* Returns 0 if string is invalid */
unsigned string_to_unsigned(const char *str)
{
const char *ptr = NULL;
if (string_is_empty(str))
return 0;
for (ptr = str; *ptr != '\0'; ptr++)
{
if (!ISDIGIT((unsigned char)*ptr))
return 0;
}
return (unsigned)strtoul(str, NULL, 10);
}
/* Converts hexadecimal string to unsigned integer.
* Handles optional leading '0x'.
* Returns 0 if string is invalid */
unsigned string_hex_to_unsigned(const char *str)
{
const char *hex_str = str;
const char *ptr = NULL;
size_t len;
if (string_is_empty(str))
return 0;
/* Remove leading '0x', if required */
len = strlen(str);
if (len >= 2)
if ((str[0] == '0') &&
((str[1] == 'x') || (str[1] == 'X')))
hex_str = str + 2;
if (string_is_empty(hex_str))
return 0;
/* Check for valid characters */
for (ptr = hex_str; *ptr != '\0'; ptr++)
{
if (!isxdigit((unsigned char)*ptr))
return 0;
}
return (unsigned)strtoul(hex_str, NULL, 16);
}

View File

@ -0,0 +1,81 @@
/* Copyright (C) 2010-2020 The RetroArch team
*
* ---------------------------------------------------------------------------------------
* The following license statement only applies to this file (rtime.c).
* ---------------------------------------------------------------------------------------
*
* Permission is hereby granted, free of charge,
* to any person obtaining a copy of this software and associated documentation files (the "Software"),
* to deal in the Software without restriction, including without limitation the rights to
* use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software,
* and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
* INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*/
#ifdef HAVE_THREADS
#include <rthreads/rthreads.h>
#include <retro_assert.h>
#include <stdlib.h>
#endif
#include <string.h>
#include <time/rtime.h>
#ifdef HAVE_THREADS
/* TODO/FIXME - global */
slock_t *rtime_localtime_lock = NULL;
#endif
/* Must be called before using rtime_localtime() */
void rtime_init(void)
{
rtime_deinit();
#ifdef HAVE_THREADS
if (!rtime_localtime_lock)
rtime_localtime_lock = slock_new();
retro_assert(rtime_localtime_lock);
#endif
}
/* Must be called upon program termination */
void rtime_deinit(void)
{
#ifdef HAVE_THREADS
if (rtime_localtime_lock)
{
slock_free(rtime_localtime_lock);
rtime_localtime_lock = NULL;
}
#endif
}
/* Thread-safe wrapper for localtime() */
struct tm *rtime_localtime(const time_t *timep, struct tm *result)
{
struct tm *time_info = NULL;
/* Lock mutex */
#ifdef HAVE_THREADS
slock_lock(rtime_localtime_lock);
#endif
time_info = localtime(timep);
if (time_info)
memcpy(result, time_info, sizeof(struct tm));
/* Unlock mutex */
#ifdef HAVE_THREADS
slock_unlock(rtime_localtime_lock);
#endif
return result;
}

View File

@ -1,4 +1,4 @@
/* Copyright (C) 2010-2019 The RetroArch team
/* Copyright (C) 2010-2020 The RetroArch team
*
* ---------------------------------------------------------------------------------------
* The following license statement only applies to this file (vfs_implementation.c).
@ -51,10 +51,6 @@
# if defined(PSP)
# include <pspiofilemgr.h>
# endif
# if defined(PS2)
# include <fileXio_rpc.h>
# include <fileXio_cdvd.h>
# endif
# include <sys/types.h>
# include <sys/stat.h>
# if !defined(VITA)
@ -68,7 +64,7 @@
# endif
#endif
#ifdef __CELLOS_LV2__
#if defined (__CELLOS_LV2__) && !defined(__PSL1GHT__)
#include <cell/cell_fs.h>
#define O_RDONLY CELL_FS_O_RDONLY
#define O_WRONLY CELL_FS_O_WRONLY
@ -93,16 +89,13 @@
# if defined(PSP)
# include <pspiofilemgr.h>
# endif
# if defined(PS2)
# include <fileXio_rpc.h>
# endif
# include <sys/types.h>
# include <sys/stat.h>
# include <dirent.h>
# include <unistd.h>
#endif
#if (defined(__CELLOS_LV2__) && !defined(__PSL1GHT__)) || defined(__QNX__) || defined(PSP) || defined(PS2)
#if (defined(__CELLOS_LV2__) && !defined(__PSL1GHT__)) || defined(__QNX__) || defined(PSP)
#include <unistd.h> /* stat() is defined here */
#endif
@ -146,12 +139,7 @@
#include <pspkernel.h>
#endif
#if defined(PS2)
#include <fileXio_rpc.h>
#include <fileXio.h>
#endif
#if defined(__CELLOS_LV2__)
#if defined(__CELLOS_LV2__) && !defined(__PSL1GHT__)
#include <cell/cell_fs.h>
#endif
@ -173,7 +161,7 @@
#endif
#if defined(_WIN32)
#if !defined(_MSC_VER) || (defined(_MSC_VER) && _MSC_VER >= 1400)
#if defined(_MSC_VER) && _MSC_VER >= 1400
#define ATLEAST_VC2005
#endif
#endif
@ -189,9 +177,17 @@
#include <vfs/vfs_implementation_cdrom.h>
#endif
#if (defined(_POSIX_C_SOURCE) && (_POSIX_C_SOURCE - 0) >= 200112) || (defined(__POSIX_VISIBLE) && __POSIX_VISIBLE >= 200112) || (defined(_POSIX_VERSION) && _POSIX_VERSION >= 200112) || __USE_LARGEFILE || (defined(_FILE_OFFSET_BITS) && _FILE_OFFSET_BITS == 64)
#ifndef HAVE_64BIT_OFFSETS
#define HAVE_64BIT_OFFSETS
#endif
#endif
#define RFILE_HINT_UNBUFFERED (1 << 8)
int64_t retro_vfs_file_seek_internal(libretro_vfs_implementation_file *stream, int64_t offset, int whence)
int64_t retro_vfs_file_seek_internal(
libretro_vfs_implementation_file *stream,
int64_t offset, int whence)
{
if (!stream)
return -1;
@ -202,19 +198,9 @@ int64_t retro_vfs_file_seek_internal(libretro_vfs_implementation_file *stream, i
if (stream->scheme == VFS_SCHEME_CDROM)
return retro_vfs_file_seek_cdrom(stream, offset, whence);
#endif
/* VC2005 and up have a special 64-bit fseek */
#ifdef ATLEAST_VC2005
/* VC2005 and up have a special 64-bit fseek */
return _fseeki64(stream->fp, offset, whence);
#elif defined(__CELLOS_LV2__) || defined(_MSC_VER) && _MSC_VER <= 1310
return fseek(stream->fp, (long)offset, whence);
#elif defined(PS2)
{
int64_t ret = fileXioLseek(fileno(stream->fp), (off_t)offset, whence);
/* fileXioLseek could return positive numbers */
if (ret > 0)
return 0;
return ret;
}
#elif defined(ORBIS)
{
int ret = orbisLseek(stream->fd, offset, whence);
@ -222,8 +208,10 @@ int64_t retro_vfs_file_seek_internal(libretro_vfs_implementation_file *stream, i
return -1;
return 0;
}
#else
#elif defined(HAVE_64BIT_OFFSETS)
return fseeko(stream->fp, (off_t)offset, whence);
#else
return fseek(stream->fp, (long)offset, whence);
#endif
}
#ifdef HAVE_MMAP
@ -263,7 +251,7 @@ int64_t retro_vfs_file_seek_internal(libretro_vfs_implementation_file *stream, i
}
#endif
if (lseek(stream->fd, offset, whence) < 0)
if (lseek(stream->fd, (off_t)offset, whence) < 0)
return -1;
return 0;
@ -282,47 +270,72 @@ int64_t retro_vfs_file_seek_internal(libretro_vfs_implementation_file *stream, i
libretro_vfs_implementation_file *retro_vfs_file_open_impl(
const char *path, unsigned mode, unsigned hints)
{
int flags = 0;
const char *mode_str = NULL;
#if defined(VFS_FRONTEND) || defined(HAVE_CDROM)
int path_len = (int)strlen(path);
libretro_vfs_implementation_file *stream = (libretro_vfs_implementation_file*)
calloc(1, sizeof(*stream));
#endif
#ifdef VFS_FRONTEND
const char *dumb_prefix = "vfsonly://";
size_t dumb_prefix_siz = strlen(dumb_prefix);
size_t dumb_prefix_siz = STRLEN_CONST("vfsonly://");
int dumb_prefix_len = (int)dumb_prefix_siz;
if (path_len >= dumb_prefix_len)
{
if (!memcmp(path, dumb_prefix, dumb_prefix_len))
path += dumb_prefix_siz;
}
#endif
#ifdef HAVE_CDROM
{
const char *cdrom_prefix = "cdrom://";
size_t cdrom_prefix_siz = strlen(cdrom_prefix);
int cdrom_prefix_len = (int)cdrom_prefix_siz;
if (path_len > cdrom_prefix_len)
{
if (!memcmp(path, cdrom_prefix, cdrom_prefix_len))
{
path += cdrom_prefix_siz;
stream->scheme = VFS_SCHEME_CDROM;
}
}
}
const char *cdrom_prefix = "cdrom://";
size_t cdrom_prefix_siz = STRLEN_CONST("cdrom://");
int cdrom_prefix_len = (int)cdrom_prefix_siz;
#endif
int flags = 0;
const char *mode_str = NULL;
libretro_vfs_implementation_file *stream =
(libretro_vfs_implementation_file*)
malloc(sizeof(*stream));
if (!stream)
return NULL;
(void)flags;
stream->fd = 0;
stream->hints = hints;
stream->size = 0;
stream->buf = NULL;
stream->fp = NULL;
#ifdef _WIN32
stream->fh = 0;
#endif
stream->orig_path = NULL;
stream->mappos = 0;
stream->mapsize = 0;
stream->mapped = NULL;
stream->scheme = VFS_SCHEME_NONE;
#ifdef VFS_FRONTEND
if (path_len >= dumb_prefix_len)
if (!memcmp(path, dumb_prefix, dumb_prefix_len))
path += dumb_prefix_siz;
#endif
#ifdef HAVE_CDROM
stream->cdrom.cue_buf = NULL;
stream->cdrom.cue_len = 0;
stream->cdrom.byte_pos = 0;
stream->cdrom.drive = 0;
stream->cdrom.cur_min = 0;
stream->cdrom.cur_sec = 0;
stream->cdrom.cur_frame = 0;
stream->cdrom.cur_track = 0;
stream->cdrom.cur_lba = 0;
stream->cdrom.last_frame_lba = 0;
stream->cdrom.last_frame[0] = '\0';
stream->cdrom.last_frame_valid = false;
if (path_len > cdrom_prefix_len)
{
if (!memcmp(path, cdrom_prefix, cdrom_prefix_len))
{
path += cdrom_prefix_siz;
stream->scheme = VFS_SCHEME_CDROM;
}
}
#endif
stream->hints = hints;
stream->orig_path = strdup(path);
#ifdef HAVE_MMAP
@ -348,9 +361,7 @@ libretro_vfs_implementation_file *retro_vfs_file_open_impl(
flags = O_WRONLY | O_CREAT | O_TRUNC;
#if !defined(ORBIS)
#if defined(PS2)
flags |= FIO_S_IRUSR | FIO_S_IWUSR;
#elif !defined(_WIN32)
#if !defined(_WIN32)
flags |= S_IRUSR | S_IWUSR;
#else
flags |= O_BINARY;
@ -362,9 +373,7 @@ libretro_vfs_implementation_file *retro_vfs_file_open_impl(
mode_str = "w+b";
flags = O_RDWR | O_CREAT | O_TRUNC;
#if !defined(ORBIS)
#if defined(PS2)
flags |= FIO_S_IRUSR | FIO_S_IWUSR;
#elif !defined(_WIN32)
#if !defined(_WIN32)
flags |= S_IRUSR | S_IWUSR;
#else
flags |= O_BINARY;
@ -378,9 +387,7 @@ libretro_vfs_implementation_file *retro_vfs_file_open_impl(
flags = O_RDWR;
#if !defined(ORBIS)
#if defined(PS2)
flags |= FIO_S_IRUSR | FIO_S_IWUSR;
#elif !defined(_WIN32)
#if !defined(_WIN32)
flags |= S_IRUSR | S_IWUSR;
#else
flags |= O_BINARY;
@ -401,7 +408,7 @@ libretro_vfs_implementation_file *retro_vfs_file_open_impl(
stream->fd = -1;
goto error;
}
stream->fd = fd;
stream->fd = fd;
#else
FILE *fp;
#ifdef HAVE_CDROM
@ -430,13 +437,23 @@ libretro_vfs_implementation_file *retro_vfs_file_open_impl(
*
* https://www.freebsd.org/cgi/man.cgi?query=setvbuf&apropos=0&sektion=0&manpath=FreeBSD+11.1-RELEASE&arch=default&format=html
*
* If the size argument is not zero but buf is NULL, a buffer of the given size will be allocated immediately, and
* If the size argument is not zero but buf is NULL,
* a buffer of the given size will be allocated immediately, and
* released on close. This is an extension to ANSI C.
*
* Since C89 does not support specifying a null buffer with a non-zero size, we create and track our own buffer for it.
* Since C89 does not support specifying a NULL buffer
* with a non-zero size, we create and track our own buffer for it.
*/
/* TODO: this is only useful for a few platforms, find which and add ifdef */
#if !defined(PS2) && !defined(PSP)
/* TODO: this is only useful for a few platforms,
* find which and add ifdef */
#if defined(_3DS)
if (stream->scheme != VFS_SCHEME_CDROM)
{
stream->buf = (char*)calloc(1, 0x10000);
if (stream->fp)
setvbuf(stream->fp, stream->buf, _IOFBF, 0x10000);
}
#elif !defined(PSP)
if (stream->scheme != VFS_SCHEME_CDROM)
{
stream->buf = (char*)calloc(1, 0x4000);
@ -535,9 +552,7 @@ int retro_vfs_file_close_impl(libretro_vfs_implementation_file *stream)
if ((stream->hints & RFILE_HINT_UNBUFFERED) == 0)
{
if (stream->fp)
{
fclose(stream->fp);
}
}
else
{
@ -602,7 +617,7 @@ int64_t retro_vfs_file_truncate_impl(libretro_vfs_implementation_file *stream, i
if (_chsize(_fileno(stream->fp), length) != 0)
return -1;
#elif !defined(VITA) && !defined(PSP) && !defined(PS2) && !defined(ORBIS) && (!defined(SWITCH) || defined(HAVE_LIBNX))
if (ftruncate(fileno(stream->fp), length) != 0)
if (ftruncate(fileno(stream->fp), (off_t)length) != 0)
return -1;
#endif
@ -628,9 +643,11 @@ int64_t retro_vfs_file_tell_impl(libretro_vfs_implementation_file *stream)
return ret;
}
#else
/* VC2005 and up have a special 64-bit ftell */
#ifdef ATLEAST_VC2005
/* VC2005 and up have a special 64-bit ftell */
return _ftelli64(stream->fp);
#elif defined(HAVE_64BIT_OFFSETS)
return ftello(stream->fp);
#else
return ftell(stream->fp);
#endif
@ -639,7 +656,8 @@ int64_t retro_vfs_file_tell_impl(libretro_vfs_implementation_file *stream)
#ifdef HAVE_MMAP
/* Need to check stream->mapped because this function
* is called in filestream_open() */
if (stream->mapped && stream->hints & RETRO_VFS_FILE_ACCESS_HINT_FREQUENT_ACCESS)
if (stream->mapped && stream->hints &
RETRO_VFS_FILE_ACCESS_HINT_FREQUENT_ACCESS)
return stream->mappos;
#endif
if (lseek(stream->fd, 0, SEEK_CUR) < 0)
@ -863,12 +881,12 @@ const char *retro_vfs_file_get_path_impl(
int retro_vfs_stat_impl(const char *path, int32_t *size)
{
bool is_dir = false;
bool is_character_special = false;
#if defined(VITA) || defined(PSP)
/* Vita / PSP */
SceIoStat buf;
int stat_ret;
bool is_dir = false;
bool is_character_special = false;
int dir_ret;
char *tmp = NULL;
size_t len = 0;
@ -880,77 +898,32 @@ int retro_vfs_stat_impl(const char *path, int32_t *size)
if (tmp[len-1] == '/')
tmp[len-1] = '\0';
stat_ret = sceIoGetstat(tmp, &buf);
dir_ret = sceIoGetstat(tmp, &buf);
free(tmp);
if (stat_ret < 0)
if (dir_ret < 0)
return 0;
if (size)
*size = (int32_t)buf.st_size;
is_dir = FIO_S_ISDIR(buf.st_mode);
return RETRO_VFS_STAT_IS_VALID | (is_dir ? RETRO_VFS_STAT_IS_DIRECTORY : 0) | (is_character_special ? RETRO_VFS_STAT_IS_CHARACTER_SPECIAL : 0);
*size = (int32_t)buf.st_size;
is_dir = FIO_S_ISDIR(buf.st_mode);
#elif defined(ORBIS)
/* Orbis */
bool is_dir, is_character_special;
int dir_ret;
int dir_ret = 0;
if (!path || !*path)
return 0;
if (size)
*size = (int32_t)buf.st_size;
*size = (int32_t)buf.st_size;
dir_ret = orbisDopen(path);
is_dir = dir_ret > 0;
dir_ret = orbisDopen(path);
is_dir = dir_ret > 0;
orbisDclose(dir_ret);
is_character_special = S_ISCHR(buf.st_mode);
return RETRO_VFS_STAT_IS_VALID | (is_dir ? RETRO_VFS_STAT_IS_DIRECTORY : 0) | (is_character_special ? RETRO_VFS_STAT_IS_CHARACTER_SPECIAL : 0);
#elif defined(PS2)
/* PS2 */
iox_stat_t buf;
bool is_dir;
bool is_character_special = false;
char *tmp = NULL;
size_t len = 0;
if (!path || !*path)
return 0;
tmp = strdup(path);
len = strlen(tmp);
if (tmp[len-1] == '/')
tmp[len-1] = '\0';
fileXioGetStat(tmp, &buf);
free(tmp);
if (size)
*size = (int32_t)buf.size;
if (!buf.mode)
{
/* if fileXioGetStat fails */
int dir_ret = fileXioDopen(path);
is_dir = dir_ret > 0;
if (is_dir) {
fileXioDclose(dir_ret);
}
}
else
is_dir = FIO_S_ISDIR(buf.mode);
return RETRO_VFS_STAT_IS_VALID | (is_dir ? RETRO_VFS_STAT_IS_DIRECTORY : 0) | (is_character_special ? RETRO_VFS_STAT_IS_CHARACTER_SPECIAL : 0);
#elif defined(__CELLOS_LV2__)
is_character_special = S_ISCHR(buf.st_mode);
#elif defined(__CELLOS_LV2__) && !defined(__PSL1GHT__)
/* CellOS Lv2 */
bool is_dir;
bool is_character_special = false;
CellFsStat buf;
if (!path || !*path)
@ -959,18 +932,14 @@ int retro_vfs_stat_impl(const char *path, int32_t *size)
return 0;
if (size)
*size = (int32_t)buf.st_size;
*size = (int32_t)buf.st_size;
is_dir = ((buf.st_mode & S_IFMT) == S_IFDIR);
return RETRO_VFS_STAT_IS_VALID | (is_dir ? RETRO_VFS_STAT_IS_DIRECTORY : 0) | (is_character_special ? RETRO_VFS_STAT_IS_CHARACTER_SPECIAL : 0);
is_dir = ((buf.st_mode & S_IFMT) == S_IFDIR);
#elif defined(_WIN32)
/* Windows */
bool is_dir;
DWORD file_info;
struct _stat buf;
bool is_character_special = false;
#if defined(LEGACY_WIN32)
char *path_local = NULL;
#else
@ -981,8 +950,8 @@ int retro_vfs_stat_impl(const char *path, int32_t *size)
return 0;
#if defined(LEGACY_WIN32)
path_local = utf8_to_local_string_alloc(path);
file_info = GetFileAttributes(path_local);
path_local = utf8_to_local_string_alloc(path);
file_info = GetFileAttributes(path_local);
if (!string_is_empty(path_local))
_stat(path_local, &buf);
@ -990,8 +959,8 @@ int retro_vfs_stat_impl(const char *path, int32_t *size)
if (path_local)
free(path_local);
#else
path_wide = utf8_to_utf16_string_alloc(path);
file_info = GetFileAttributesW(path_wide);
path_wide = utf8_to_utf16_string_alloc(path);
file_info = GetFileAttributesW(path_wide);
_wstat(path_wide, &buf);
@ -1007,11 +976,41 @@ int retro_vfs_stat_impl(const char *path, int32_t *size)
is_dir = (file_info & FILE_ATTRIBUTE_DIRECTORY);
return RETRO_VFS_STAT_IS_VALID | (is_dir ? RETRO_VFS_STAT_IS_DIRECTORY : 0) | (is_character_special ? RETRO_VFS_STAT_IS_CHARACTER_SPECIAL : 0);
#elif defined(GEKKO)
/* On GEKKO platforms, paths cannot have
* trailing slashes - we must therefore
* remove them */
char *path_buf = NULL;
int stat_ret = -1;
struct stat stat_buf;
size_t len;
if (string_is_empty(path))
return 0;
path_buf = strdup(path);
if (!path_buf)
return 0;
len = strlen(path_buf);
if (len > 0)
if (path_buf[len - 1] == '/')
path_buf[len - 1] = '\0';
stat_ret = stat(path_buf, &stat_buf);
free(path_buf);
if (stat_ret < 0)
return 0;
if (size)
*size = (int32_t)stat_buf.st_size;
is_dir = S_ISDIR(stat_buf.st_mode);
is_character_special = S_ISCHR(stat_buf.st_mode);
#else
/* Every other platform */
bool is_dir, is_character_special;
struct stat buf;
if (!path || !*path)
@ -1024,9 +1023,8 @@ int retro_vfs_stat_impl(const char *path, int32_t *size)
is_dir = S_ISDIR(buf.st_mode);
is_character_special = S_ISCHR(buf.st_mode);
return RETRO_VFS_STAT_IS_VALID | (is_dir ? RETRO_VFS_STAT_IS_DIRECTORY : 0) | (is_character_special ? RETRO_VFS_STAT_IS_CHARACTER_SPECIAL : 0);
#endif
return RETRO_VFS_STAT_IS_VALID | (is_dir ? RETRO_VFS_STAT_IS_DIRECTORY : 0) | (is_character_special ? RETRO_VFS_STAT_IS_CHARACTER_SPECIAL : 0);
}
#if defined(VITA)
@ -1041,27 +1039,47 @@ int retro_vfs_mkdir_impl(const char *dir)
{
#if defined(_WIN32)
#ifdef LEGACY_WIN32
int ret = _mkdir(dir);
int ret = _mkdir(dir);
#else
wchar_t *dirW = utf8_to_utf16_string_alloc(dir);
int ret = -1;
wchar_t *dir_w = utf8_to_utf16_string_alloc(dir);
int ret = -1;
if (dirW)
if (dir_w)
{
ret = _wmkdir(dirW);
free(dirW);
ret = _wmkdir(dir_w);
free(dir_w);
}
#endif
#elif defined(IOS)
int ret = mkdir(dir, 0755);
#elif defined(VITA) || defined(PSP)
int ret = sceIoMkdir(dir, 0777);
#elif defined(PS2)
int ret = fileXioMkdir(dir, 0777);
#elif defined(ORBIS)
int ret = orbisMkdir(dir, 0755);
#elif defined(__QNX__)
int ret = mkdir(dir, 0777);
#elif defined(GEKKO)
/* On GEKKO platforms, mkdir() fails if
* the path has a trailing slash. We must
* therefore remove it. */
int ret = -1;
if (!string_is_empty(dir))
{
char *dir_buf = strdup(dir);
if (dir_buf)
{
size_t len = strlen(dir_buf);
if (len > 0)
if (dir_buf[len - 1] == '/')
dir_buf[len - 1] = '\0';
ret = mkdir(dir_buf, 0750);
free(dir_buf);
}
}
#else
int ret = mkdir(dir, 0750);
#endif
@ -1090,10 +1108,7 @@ struct libretro_vfs_implementation_dir
#elif defined(VITA) || defined(PSP)
SceUID directory;
SceIoDirent entry;
#elif defined(PS2)
int directory;
iox_dirent_t entry;
#elif defined(__CELLOS_LV2__)
#elif defined(__CELLOS_LV2__) && !defined(__PSL1GHT__)
CellFsErrno error;
int directory;
CellFsDirent entry;
@ -1110,9 +1125,9 @@ static bool dirent_check_error(libretro_vfs_implementation_dir *rdir)
{
#if defined(_WIN32)
return (rdir->directory == INVALID_HANDLE_VALUE);
#elif defined(VITA) || defined(PSP) || defined(PS2) || defined(ORBIS)
#elif defined(VITA) || defined(PSP) || defined(ORBIS)
return (rdir->directory < 0);
#elif defined(__CELLOS_LV2__)
#elif defined(__CELLOS_LV2__) && !defined(__PSL1GHT__)
return (rdir->error != CELL_FS_SUCCEEDED);
#else
return !(rdir->directory);
@ -1174,12 +1189,10 @@ libretro_vfs_implementation_dir *retro_vfs_opendir_impl(
#elif defined(VITA) || defined(PSP)
rdir->directory = sceIoDopen(name);
#elif defined(PS2)
rdir->directory = ps2fileXioDopen(name);
#elif defined(_3DS)
rdir->directory = !string_is_empty(name) ? opendir(name) : NULL;
rdir->entry = NULL;
#elif defined(__CELLOS_LV2__)
#elif defined(__CELLOS_LV2__) && !defined(__PSL1GHT__)
rdir->error = cellFsOpendir(name, &rdir->directory);
#elif defined(ORBIS)
rdir->directory = orbisDopen(name);
@ -1216,12 +1229,7 @@ bool retro_vfs_readdir_impl(libretro_vfs_implementation_dir *rdir)
return (rdir->directory != INVALID_HANDLE_VALUE);
#elif defined(VITA) || defined(PSP)
return (sceIoDread(rdir->directory, &rdir->entry) > 0);
#elif defined(PS2)
iox_dirent_t record;
int ret = ps2fileXioDread(rdir->directory, &record);
rdir->entry = record;
return ( ret > 0);
#elif defined(__CELLOS_LV2__)
#elif defined(__CELLOS_LV2__) && !defined(__PSL1GHT__)
uint64_t nread;
rdir->error = cellFsReaddir(rdir->directory, &rdir->entry, &nread);
return (nread != 0);
@ -1236,29 +1244,17 @@ const char *retro_vfs_dirent_get_name_impl(libretro_vfs_implementation_dir *rdir
{
#if defined(_WIN32)
#if defined(LEGACY_WIN32)
{
char *name_local = local_to_utf8_string_alloc(rdir->entry.cFileName);
memset(rdir->entry.cFileName, 0, sizeof(rdir->entry.cFileName));
strlcpy(rdir->entry.cFileName, name_local, sizeof(rdir->entry.cFileName));
if (name_local)
free(name_local);
}
char *name = local_to_utf8_string_alloc(rdir->entry.cFileName);
#else
{
char *name = utf16_to_utf8_string_alloc(rdir->entry.cFileName);
memset(rdir->entry.cFileName, 0, sizeof(rdir->entry.cFileName));
strlcpy((char*)rdir->entry.cFileName, name, sizeof(rdir->entry.cFileName));
if (name)
free(name);
}
char *name = utf16_to_utf8_string_alloc(rdir->entry.cFileName);
#endif
memset(rdir->entry.cFileName, 0, sizeof(rdir->entry.cFileName));
strlcpy((char*)rdir->entry.cFileName, name, sizeof(rdir->entry.cFileName));
if (name)
free(name);
return (char*)rdir->entry.cFileName;
#elif defined(VITA) || defined(PSP) || defined(__CELLOS_LV2__) || defined(ORBIS)
#elif defined(VITA) || defined(PSP) || defined(__CELLOS_LV2__) && !defined(__PSL1GHT__) || defined(ORBIS)
return rdir->entry.d_name;
#elif defined(PS2)
return rdir->entry.name;
#else
if (!rdir || !rdir->entry)
return NULL;
@ -1272,20 +1268,17 @@ bool retro_vfs_dirent_is_dir_impl(libretro_vfs_implementation_dir *rdir)
const WIN32_FIND_DATA *entry = (const WIN32_FIND_DATA*)&rdir->entry;
return entry->dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY;
#elif defined(PSP) || defined(VITA)
const SceIoDirent *entry = (const SceIoDirent*)&rdir->entry;
const SceIoDirent *entry = (const SceIoDirent*)&rdir->entry;
#if defined(PSP)
return (entry->d_stat.st_attr & FIO_SO_IFDIR) == FIO_SO_IFDIR;
#elif defined(VITA)
return SCE_S_ISDIR(entry->d_stat.st_mode);
#endif
#elif defined(PS2)
const iox_dirent_t *entry = (const iox_dirent_t*)&rdir->entry;
return FIO_S_ISDIR(entry->stat.mode);
#elif defined(__CELLOS_LV2__)
CellFsDirent *entry = (CellFsDirent*)&rdir->entry;
#elif defined(__CELLOS_LV2__) && !defined(__PSL1GHT__)
CellFsDirent *entry = (CellFsDirent*)&rdir->entry;
return (entry->d_type == CELL_FS_TYPE_DIRECTORY);
#elif defined(ORBIS)
const struct dirent *entry = &rdir->entry;
const struct dirent *entry = &rdir->entry;
if (entry->d_type == DT_DIR)
return true;
if (!(entry->d_type == DT_UNKNOWN || entry->d_type == DT_LNK))
@ -1320,9 +1313,7 @@ int retro_vfs_closedir_impl(libretro_vfs_implementation_dir *rdir)
FindClose(rdir->directory);
#elif defined(VITA) || defined(PSP)
sceIoDclose(rdir->directory);
#elif defined(PS2)
ps2fileXioDclose(rdir->directory);
#elif defined(__CELLOS_LV2__)
#elif defined(__CELLOS_LV2__) && !defined(__PSL1GHT__)
rdir->error = cellFsClosedir(rdir->directory);
#elif defined(ORBIS)
orbisDclose(rdir->directory);