mirror of
https://github.com/libretro/libretro-prboom.git
synced 2024-11-23 07:59:39 +00:00
iUpdate libretro-common
This commit is contained in:
parent
ddaa6e34d2
commit
0827aba637
@ -24,6 +24,7 @@ SOURCES_C := $(LIBRETRO_DIR)/libretro.c \
|
|||||||
$(LIBRETRO_COMM_DIR)/compat/compat_strl.c \
|
$(LIBRETRO_COMM_DIR)/compat/compat_strl.c \
|
||||||
$(LIBRETRO_COMM_DIR)/compat/compat_posix_string.c \
|
$(LIBRETRO_COMM_DIR)/compat/compat_posix_string.c \
|
||||||
$(LIBRETRO_COMM_DIR)/compat/fopen_utf8.c \
|
$(LIBRETRO_COMM_DIR)/compat/fopen_utf8.c \
|
||||||
|
$(LIBRETRO_COMM_DIR)/features/features_cpu.c \
|
||||||
$(LIBRETRO_COMM_DIR)/streams/file_stream.c \
|
$(LIBRETRO_COMM_DIR)/streams/file_stream.c \
|
||||||
$(LIBRETRO_COMM_DIR)/streams/file_stream_transforms.c \
|
$(LIBRETRO_COMM_DIR)/streams/file_stream_transforms.c \
|
||||||
$(LIBRETRO_COMM_DIR)/string/stdstring.c \
|
$(LIBRETRO_COMM_DIR)/string/stdstring.c \
|
||||||
|
@ -60,10 +60,3 @@ size_t strlcat(char *dest, const char *source, size_t size)
|
|||||||
return len + strlcpy(dest, source, size);
|
return len + strlcpy(dest, source, size);
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
char *strldup(const char *s, size_t n)
|
|
||||||
{
|
|
||||||
char *dst = (char*)malloc(sizeof(char) * (n + 1));
|
|
||||||
strlcpy(dst, s, n);
|
|
||||||
return dst;
|
|
||||||
}
|
|
||||||
|
@ -37,27 +37,28 @@
|
|||||||
void *fopen_utf8(const char * filename, const char * mode)
|
void *fopen_utf8(const char * filename, const char * mode)
|
||||||
{
|
{
|
||||||
#if defined(LEGACY_WIN32)
|
#if defined(LEGACY_WIN32)
|
||||||
FILE *ret = NULL;
|
|
||||||
char * filename_local = utf8_to_local_string_alloc(filename);
|
char * filename_local = utf8_to_local_string_alloc(filename);
|
||||||
|
|
||||||
if (!filename_local)
|
|
||||||
return NULL;
|
|
||||||
ret = fopen(filename_local, mode);
|
|
||||||
if (filename_local)
|
if (filename_local)
|
||||||
|
{
|
||||||
|
FILE *ret = fopen(filename_local, mode);
|
||||||
free(filename_local);
|
free(filename_local);
|
||||||
return ret;
|
return ret;
|
||||||
|
}
|
||||||
#else
|
#else
|
||||||
wchar_t * filename_w = utf8_to_utf16_string_alloc(filename);
|
wchar_t * filename_w = utf8_to_utf16_string_alloc(filename);
|
||||||
wchar_t * mode_w = utf8_to_utf16_string_alloc(mode);
|
|
||||||
FILE* ret = NULL;
|
|
||||||
|
|
||||||
if (filename_w && mode_w)
|
|
||||||
ret = _wfopen(filename_w, mode_w);
|
|
||||||
if (filename_w)
|
if (filename_w)
|
||||||
|
{
|
||||||
|
FILE *ret = NULL;
|
||||||
|
wchar_t *mode_w = utf8_to_utf16_string_alloc(mode);
|
||||||
|
if (mode_w)
|
||||||
|
{
|
||||||
|
ret = _wfopen(filename_w, mode_w);
|
||||||
|
free(mode_w);
|
||||||
|
}
|
||||||
free(filename_w);
|
free(filename_w);
|
||||||
if (mode_w)
|
return ret;
|
||||||
free(mode_w);
|
}
|
||||||
return ret;
|
|
||||||
#endif
|
#endif
|
||||||
|
return NULL;
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
@ -51,9 +51,12 @@ static unsigned leading_ones(uint8_t c)
|
|||||||
return ones;
|
return ones;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Simple implementation. Assumes the sequence is
|
/**
|
||||||
* properly synchronized and terminated. */
|
* utf8_conv_utf32:
|
||||||
|
*
|
||||||
|
* Simple implementation. Assumes the sequence is
|
||||||
|
* properly synchronized and terminated.
|
||||||
|
**/
|
||||||
size_t utf8_conv_utf32(uint32_t *out, size_t out_chars,
|
size_t utf8_conv_utf32(uint32_t *out, size_t out_chars,
|
||||||
const char *in, size_t in_size)
|
const char *in, size_t in_size)
|
||||||
{
|
{
|
||||||
@ -79,7 +82,7 @@ size_t utf8_conv_utf32(uint32_t *out, size_t out_chars,
|
|||||||
for (i = 0; i < extra; i++, in++, shift -= 6)
|
for (i = 0; i < extra; i++, in++, shift -= 6)
|
||||||
c |= (*in & 0x3f) << shift;
|
c |= (*in & 0x3f) << shift;
|
||||||
|
|
||||||
*out++ = c;
|
*out++ = c;
|
||||||
in_size -= 1 + extra;
|
in_size -= 1 + extra;
|
||||||
out_chars--;
|
out_chars--;
|
||||||
ret++;
|
ret++;
|
||||||
@ -88,6 +91,11 @@ size_t utf8_conv_utf32(uint32_t *out, size_t out_chars,
|
|||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* utf16_conv_utf8:
|
||||||
|
*
|
||||||
|
* Leaf function.
|
||||||
|
**/
|
||||||
bool utf16_conv_utf8(uint8_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)
|
const uint16_t *in, size_t in_size)
|
||||||
{
|
{
|
||||||
@ -148,16 +156,20 @@ bool utf16_conv_utf8(uint8_t *out, size_t *out_chars,
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Acts mostly like strlcpy.
|
/**
|
||||||
|
* utf8cpy:
|
||||||
|
*
|
||||||
|
* Acts mostly like strlcpy.
|
||||||
*
|
*
|
||||||
* Copies the given number of UTF-8 characters,
|
* Copies the given number of UTF-8 characters,
|
||||||
* but at most d_len bytes.
|
* but at most @d_len bytes.
|
||||||
*
|
*
|
||||||
* Always NULL terminates.
|
* Always NULL terminates. Does not copy half a character.
|
||||||
* Does not copy half a character.
|
* @s is assumed valid UTF-8.
|
||||||
|
* Use only if @chars is considerably less than @d_len.
|
||||||
*
|
*
|
||||||
* Returns number of bytes. 's' is assumed valid UTF-8.
|
* @return Number of bytes.
|
||||||
* Use only if 'chars' is considerably less than 'd_len'. */
|
**/
|
||||||
size_t utf8cpy(char *d, size_t d_len, const char *s, size_t chars)
|
size_t utf8cpy(char *d, size_t d_len, const char *s, size_t chars)
|
||||||
{
|
{
|
||||||
const uint8_t *sb = (const uint8_t*)s;
|
const uint8_t *sb = (const uint8_t*)s;
|
||||||
@ -186,6 +198,11 @@ size_t utf8cpy(char *d, size_t d_len, const char *s, size_t chars)
|
|||||||
return sb-sb_org;
|
return sb-sb_org;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* utf8skip:
|
||||||
|
*
|
||||||
|
* Leaf function
|
||||||
|
**/
|
||||||
const char *utf8skip(const char *str, size_t chars)
|
const char *utf8skip(const char *str, size_t chars)
|
||||||
{
|
{
|
||||||
const uint8_t *strb = (const uint8_t*)str;
|
const uint8_t *strb = (const uint8_t*)str;
|
||||||
@ -204,6 +221,11 @@ const char *utf8skip(const char *str, size_t chars)
|
|||||||
return (const char*)strb;
|
return (const char*)strb;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* utf8len:
|
||||||
|
*
|
||||||
|
* Leaf function.
|
||||||
|
**/
|
||||||
size_t utf8len(const char *string)
|
size_t utf8len(const char *string)
|
||||||
{
|
{
|
||||||
size_t ret = 0;
|
size_t ret = 0;
|
||||||
@ -220,7 +242,15 @@ size_t utf8len(const char *string)
|
|||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Does not validate the input, returns garbage if it's not UTF-8. */
|
/**
|
||||||
|
* utf8_walk:
|
||||||
|
*
|
||||||
|
* Does not validate the input.
|
||||||
|
*
|
||||||
|
* Leaf function.
|
||||||
|
*
|
||||||
|
* @return Returns garbage if it's not UTF-8.
|
||||||
|
**/
|
||||||
uint32_t utf8_walk(const char **string)
|
uint32_t utf8_walk(const char **string)
|
||||||
{
|
{
|
||||||
uint8_t first = UTF8_WALKBYTE(string);
|
uint8_t first = UTF8_WALKBYTE(string);
|
||||||
@ -248,24 +278,23 @@ static bool utf16_to_char(uint8_t **utf_data,
|
|||||||
size_t *dest_len, const uint16_t *in)
|
size_t *dest_len, const uint16_t *in)
|
||||||
{
|
{
|
||||||
unsigned len = 0;
|
unsigned len = 0;
|
||||||
|
|
||||||
while (in[len] != '\0')
|
while (in[len] != '\0')
|
||||||
len++;
|
len++;
|
||||||
|
|
||||||
utf16_conv_utf8(NULL, dest_len, in, len);
|
utf16_conv_utf8(NULL, dest_len, in, len);
|
||||||
*dest_len += 1;
|
*dest_len += 1;
|
||||||
*utf_data = (uint8_t*)malloc(*dest_len);
|
if ((*utf_data = (uint8_t*)malloc(*dest_len)) != 0)
|
||||||
if (*utf_data == 0)
|
return utf16_conv_utf8(*utf_data, dest_len, in, len);
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
return utf16_conv_utf8(*utf_data, dest_len, in, len);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* utf16_to_char_string:
|
||||||
|
**/
|
||||||
bool utf16_to_char_string(const uint16_t *in, char *s, size_t len)
|
bool utf16_to_char_string(const uint16_t *in, char *s, size_t len)
|
||||||
{
|
{
|
||||||
size_t dest_len = 0;
|
size_t dest_len = 0;
|
||||||
uint8_t *utf16_data = NULL;
|
uint8_t *utf16_data = NULL;
|
||||||
bool ret = utf16_to_char(&utf16_data, &dest_len, in);
|
bool ret = utf16_to_char(&utf16_data, &dest_len, in);
|
||||||
|
|
||||||
if (ret)
|
if (ret)
|
||||||
{
|
{
|
||||||
@ -274,13 +303,17 @@ bool utf16_to_char_string(const uint16_t *in, char *s, size_t len)
|
|||||||
}
|
}
|
||||||
|
|
||||||
free(utf16_data);
|
free(utf16_data);
|
||||||
utf16_data = NULL;
|
utf16_data = NULL;
|
||||||
|
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
#if defined(_WIN32) && !defined(_XBOX) && !defined(UNICODE)
|
#if defined(_WIN32) && !defined(_XBOX) && !defined(UNICODE)
|
||||||
/* Returned pointer MUST be freed by the caller if non-NULL. */
|
/**
|
||||||
|
* mb_to_mb_string_alloc:
|
||||||
|
*
|
||||||
|
* @return Returned pointer MUST be freed by the caller if non-NULL.
|
||||||
|
**/
|
||||||
static char *mb_to_mb_string_alloc(const char *str,
|
static char *mb_to_mb_string_alloc(const char *str,
|
||||||
enum CodePage cp_in, enum CodePage cp_out)
|
enum CodePage cp_in, enum CodePage cp_out)
|
||||||
{
|
{
|
||||||
@ -300,10 +333,8 @@ static char *mb_to_mb_string_alloc(const char *str,
|
|||||||
if (!path_buf_wide_len)
|
if (!path_buf_wide_len)
|
||||||
return strdup(str);
|
return strdup(str);
|
||||||
|
|
||||||
path_buf_wide = (wchar_t*)
|
if ((path_buf_wide = (wchar_t*)
|
||||||
calloc(path_buf_wide_len + sizeof(wchar_t), sizeof(wchar_t));
|
calloc(path_buf_wide_len + sizeof(wchar_t), sizeof(wchar_t))))
|
||||||
|
|
||||||
if (path_buf_wide)
|
|
||||||
{
|
{
|
||||||
MultiByteToWideChar(cp_in, 0,
|
MultiByteToWideChar(cp_in, 0,
|
||||||
str, -1, path_buf_wide, path_buf_wide_len);
|
str, -1, path_buf_wide, path_buf_wide_len);
|
||||||
@ -347,45 +378,49 @@ static char *mb_to_mb_string_alloc(const char *str,
|
|||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
/* Returned pointer MUST be freed by the caller if non-NULL. */
|
/**
|
||||||
|
* utf8_to_local_string_alloc:
|
||||||
|
*
|
||||||
|
* @return Returned pointer MUST be freed by the caller if non-NULL.
|
||||||
|
**/
|
||||||
char* utf8_to_local_string_alloc(const char *str)
|
char* utf8_to_local_string_alloc(const char *str)
|
||||||
{
|
{
|
||||||
if (str && *str)
|
if (str && *str)
|
||||||
{
|
|
||||||
#if defined(_WIN32) && !defined(_XBOX) && !defined(UNICODE)
|
#if defined(_WIN32) && !defined(_XBOX) && !defined(UNICODE)
|
||||||
return mb_to_mb_string_alloc(str, CODEPAGE_UTF8, CODEPAGE_LOCAL);
|
return mb_to_mb_string_alloc(str, CODEPAGE_UTF8, CODEPAGE_LOCAL);
|
||||||
#else
|
#else
|
||||||
/* assume string needs no modification if not on Windows */
|
return strdup(str); /* Assume string needs no modification if not on Windows */
|
||||||
return strdup(str);
|
|
||||||
#endif
|
#endif
|
||||||
}
|
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Returned pointer MUST be freed by the caller if non-NULL. */
|
/**
|
||||||
char* local_to_utf8_string_alloc(const char *str)
|
* local_to_utf8_string_alloc:
|
||||||
|
*
|
||||||
|
* @return Returned pointer MUST be freed by the caller if non-NULL.
|
||||||
|
**/
|
||||||
|
char *local_to_utf8_string_alloc(const char *str)
|
||||||
{
|
{
|
||||||
if (str && *str)
|
if (str && *str)
|
||||||
{
|
|
||||||
#if defined(_WIN32) && !defined(_XBOX) && !defined(UNICODE)
|
#if defined(_WIN32) && !defined(_XBOX) && !defined(UNICODE)
|
||||||
return mb_to_mb_string_alloc(str, CODEPAGE_LOCAL, CODEPAGE_UTF8);
|
return mb_to_mb_string_alloc(str, CODEPAGE_LOCAL, CODEPAGE_UTF8);
|
||||||
#else
|
#else
|
||||||
/* assume string needs no modification if not on Windows */
|
return strdup(str); /* Assume string needs no modification if not on Windows */
|
||||||
return strdup(str);
|
|
||||||
#endif
|
#endif
|
||||||
}
|
return NULL;
|
||||||
return NULL;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Returned pointer MUST be freed by the caller if non-NULL. */
|
/**
|
||||||
|
* utf8_to_utf16_string_alloc:
|
||||||
|
*
|
||||||
|
* @return Returned pointer MUST be freed by the caller if non-NULL.
|
||||||
|
**/
|
||||||
wchar_t* utf8_to_utf16_string_alloc(const char *str)
|
wchar_t* utf8_to_utf16_string_alloc(const char *str)
|
||||||
{
|
{
|
||||||
#ifdef _WIN32
|
#ifdef _WIN32
|
||||||
int len = 0;
|
int len = 0;
|
||||||
int out_len = 0;
|
|
||||||
#else
|
#else
|
||||||
size_t len = 0;
|
size_t len = 0;
|
||||||
size_t out_len = 0;
|
|
||||||
#endif
|
#endif
|
||||||
wchar_t *buf = NULL;
|
wchar_t *buf = NULL;
|
||||||
|
|
||||||
@ -393,63 +428,55 @@ wchar_t* utf8_to_utf16_string_alloc(const char *str)
|
|||||||
return NULL;
|
return NULL;
|
||||||
|
|
||||||
#ifdef _WIN32
|
#ifdef _WIN32
|
||||||
len = MultiByteToWideChar(CP_UTF8, 0, str, -1, NULL, 0);
|
if ((len = MultiByteToWideChar(CP_UTF8, 0, str, -1, NULL, 0)))
|
||||||
|
|
||||||
if (len)
|
|
||||||
{
|
{
|
||||||
buf = (wchar_t*)calloc(len, sizeof(wchar_t));
|
if (!(buf = (wchar_t*)calloc(len, sizeof(wchar_t))))
|
||||||
|
|
||||||
if (!buf)
|
|
||||||
return NULL;
|
return NULL;
|
||||||
|
|
||||||
out_len = MultiByteToWideChar(CP_UTF8, 0, str, -1, buf, len);
|
if ((MultiByteToWideChar(CP_UTF8, 0, str, -1, buf, len)) < 0)
|
||||||
|
{
|
||||||
|
free(buf);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
/* fallback to ANSI codepage instead */
|
/* Fallback to ANSI codepage instead */
|
||||||
len = MultiByteToWideChar(CP_ACP, 0, str, -1, NULL, 0);
|
if ((len = MultiByteToWideChar(CP_ACP, 0, str, -1, NULL, 0)))
|
||||||
|
|
||||||
if (len)
|
|
||||||
{
|
{
|
||||||
buf = (wchar_t*)calloc(len, sizeof(wchar_t));
|
if (!(buf = (wchar_t*)calloc(len, sizeof(wchar_t))))
|
||||||
|
|
||||||
if (!buf)
|
|
||||||
return NULL;
|
return NULL;
|
||||||
|
|
||||||
out_len = MultiByteToWideChar(CP_ACP, 0, str, -1, buf, len);
|
if ((MultiByteToWideChar(CP_ACP, 0, str, -1, buf, len)) < 0)
|
||||||
|
{
|
||||||
|
free(buf);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (out_len < 0)
|
|
||||||
{
|
|
||||||
free(buf);
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
#else
|
#else
|
||||||
/* NOTE: For now, assume non-Windows platforms' locale is already UTF-8. */
|
/* NOTE: For now, assume non-Windows platforms' locale is already UTF-8. */
|
||||||
len = mbstowcs(NULL, str, 0) + 1;
|
if ((len = mbstowcs(NULL, str, 0) + 1))
|
||||||
|
|
||||||
if (len)
|
|
||||||
{
|
{
|
||||||
buf = (wchar_t*)calloc(len, sizeof(wchar_t));
|
if (!(buf = (wchar_t*)calloc(len, sizeof(wchar_t))))
|
||||||
|
|
||||||
if (!buf)
|
|
||||||
return NULL;
|
return NULL;
|
||||||
|
|
||||||
out_len = mbstowcs(buf, str, len);
|
if ((mbstowcs(buf, str, len)) == (size_t)-1)
|
||||||
}
|
{
|
||||||
|
free(buf);
|
||||||
if (out_len == (size_t)-1)
|
return NULL;
|
||||||
{
|
}
|
||||||
free(buf);
|
|
||||||
return NULL;
|
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
return buf;
|
return buf;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Returned pointer MUST be freed by the caller if non-NULL. */
|
/**
|
||||||
|
* utf16_to_utf8_string_alloc:
|
||||||
|
*
|
||||||
|
* @return Returned pointer MUST be freed by the caller if non-NULL.
|
||||||
|
**/
|
||||||
char* utf16_to_utf8_string_alloc(const wchar_t *str)
|
char* utf16_to_utf8_string_alloc(const wchar_t *str)
|
||||||
{
|
{
|
||||||
#ifdef _WIN32
|
#ifdef _WIN32
|
||||||
@ -465,20 +492,17 @@ char* utf16_to_utf8_string_alloc(const wchar_t *str)
|
|||||||
#ifdef _WIN32
|
#ifdef _WIN32
|
||||||
{
|
{
|
||||||
UINT code_page = CP_UTF8;
|
UINT code_page = CP_UTF8;
|
||||||
len = WideCharToMultiByte(code_page,
|
|
||||||
0, str, -1, NULL, 0, NULL, NULL);
|
|
||||||
|
|
||||||
/* fallback to ANSI codepage instead */
|
/* fallback to ANSI codepage instead */
|
||||||
if (!len)
|
if (!(len = WideCharToMultiByte(code_page,
|
||||||
|
0, str, -1, NULL, 0, NULL, NULL)))
|
||||||
{
|
{
|
||||||
code_page = CP_ACP;
|
code_page = CP_ACP;
|
||||||
len = WideCharToMultiByte(code_page,
|
len = WideCharToMultiByte(code_page,
|
||||||
0, str, -1, NULL, 0, NULL, NULL);
|
0, str, -1, NULL, 0, NULL, NULL);
|
||||||
}
|
}
|
||||||
|
|
||||||
buf = (char*)calloc(len, sizeof(char));
|
if (!(buf = (char*)calloc(len, sizeof(char))))
|
||||||
|
|
||||||
if (!buf)
|
|
||||||
return NULL;
|
return NULL;
|
||||||
|
|
||||||
if (WideCharToMultiByte(code_page,
|
if (WideCharToMultiByte(code_page,
|
||||||
@ -491,13 +515,9 @@ char* utf16_to_utf8_string_alloc(const wchar_t *str)
|
|||||||
#else
|
#else
|
||||||
/* NOTE: For now, assume non-Windows platforms'
|
/* NOTE: For now, assume non-Windows platforms'
|
||||||
* locale is already UTF-8. */
|
* locale is already UTF-8. */
|
||||||
len = wcstombs(NULL, str, 0) + 1;
|
if ((len = wcstombs(NULL, str, 0) + 1))
|
||||||
|
|
||||||
if (len)
|
|
||||||
{
|
{
|
||||||
buf = (char*)calloc(len, sizeof(char));
|
if (!(buf = (char*)calloc(len, sizeof(char))))
|
||||||
|
|
||||||
if (!buf)
|
|
||||||
return NULL;
|
return NULL;
|
||||||
|
|
||||||
if (wcstombs(buf, str, len) == (size_t)-1)
|
if (wcstombs(buf, str, len) == (size_t)-1)
|
||||||
|
919
libretro/libretro-common/features/features_cpu.c
Normal file
919
libretro/libretro-common/features/features_cpu.c
Normal file
@ -0,0 +1,919 @@
|
|||||||
|
/* Copyright (C) 2010-2020 The RetroArch team
|
||||||
|
*
|
||||||
|
* ---------------------------------------------------------------------------------------
|
||||||
|
* The following license statement only applies to this file (features_cpu.c).
|
||||||
|
* ---------------------------------------------------------------------------------------
|
||||||
|
*
|
||||||
|
* Permission is hereby granted, free of charge,
|
||||||
|
* to any person obtaining a copy of this software and associated documentation files (the "Software"),
|
||||||
|
* to deal in the Software without restriction, including without limitation the rights to
|
||||||
|
* use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software,
|
||||||
|
* and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
|
||||||
|
*
|
||||||
|
* The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
|
||||||
|
*
|
||||||
|
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
|
||||||
|
* INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
|
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
|
||||||
|
* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
|
||||||
|
* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||||
|
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
|
||||||
|
#if defined(_WIN32)
|
||||||
|
#include <direct.h>
|
||||||
|
#else
|
||||||
|
#include <unistd.h>
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#include <compat/strl.h>
|
||||||
|
#include <streams/file_stream.h>
|
||||||
|
#include <libretro.h>
|
||||||
|
#include <features/features_cpu.h>
|
||||||
|
#include <retro_timers.h>
|
||||||
|
|
||||||
|
#if defined(_WIN32) && !defined(_XBOX)
|
||||||
|
#include <windows.h>
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifdef __PSL1GHT__
|
||||||
|
#include <lv2/systime.h>
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if defined(_XBOX360)
|
||||||
|
#include <PPCIntrinsics.h>
|
||||||
|
#elif !defined(__MACH__) && (defined(__POWERPC__) || defined(__powerpc__) || defined(__ppc__) || defined(__PPC64__) || defined(__powerpc64__))
|
||||||
|
#ifndef _PPU_INTRINSICS_H
|
||||||
|
#include <ppu_intrinsics.h>
|
||||||
|
#endif
|
||||||
|
#elif defined(_POSIX_MONOTONIC_CLOCK) || defined(ANDROID) || defined(__QNX__) || defined(DJGPP)
|
||||||
|
/* POSIX_MONOTONIC_CLOCK is not being defined in Android headers despite support being present. */
|
||||||
|
#include <time.h>
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if defined(__QNX__) && !defined(CLOCK_MONOTONIC)
|
||||||
|
#define CLOCK_MONOTONIC 2
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if defined(PSP)
|
||||||
|
#include <pspkernel.h>
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if defined(PSP) || defined(__PSL1GHT__)
|
||||||
|
#include <sys/time.h>
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if defined(PSP)
|
||||||
|
#include <psprtc.h>
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if defined(VITA)
|
||||||
|
#include <psp2/kernel/processmgr.h>
|
||||||
|
#include <psp2/rtc.h>
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if defined(ORBIS)
|
||||||
|
#include <orbis/libkernel.h>
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if defined(PS2)
|
||||||
|
#include <ps2sdkapi.h>
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if !defined(__PSL1GHT__) && defined(__PS3__)
|
||||||
|
#include <sys/sys_time.h>
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifdef GEKKO
|
||||||
|
#include <ogc/lwp_watchdog.h>
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifdef WIIU
|
||||||
|
#include <wiiu/os/time.h>
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if defined(HAVE_LIBNX)
|
||||||
|
#include <switch.h>
|
||||||
|
#elif defined(SWITCH)
|
||||||
|
#include <libtransistor/types.h>
|
||||||
|
#include <libtransistor/svc.h>
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if defined(_3DS)
|
||||||
|
#include <3ds/svc.h>
|
||||||
|
#include <3ds/os.h>
|
||||||
|
#include <3ds/services/cfgu.h>
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/* iOS/OSX specific. Lacks clock_gettime(), so implement it. */
|
||||||
|
#ifdef __MACH__
|
||||||
|
#include <sys/time.h>
|
||||||
|
|
||||||
|
#ifndef CLOCK_MONOTONIC
|
||||||
|
#define CLOCK_MONOTONIC 0
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifndef CLOCK_REALTIME
|
||||||
|
#define CLOCK_REALTIME 0
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/**
|
||||||
|
* TODO/FIXME: clock_gettime function is part of iOS 10 now
|
||||||
|
**/
|
||||||
|
static int ra_clock_gettime(int clk_ik, struct timespec *t)
|
||||||
|
{
|
||||||
|
struct timeval now;
|
||||||
|
int rv = gettimeofday(&now, NULL);
|
||||||
|
if (rv)
|
||||||
|
return rv;
|
||||||
|
t->tv_sec = now.tv_sec;
|
||||||
|
t->tv_nsec = now.tv_usec * 1000;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if defined(__MACH__) && __IPHONE_OS_VERSION_MIN_REQUIRED < 100000
|
||||||
|
#else
|
||||||
|
#define ra_clock_gettime clock_gettime
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifdef EMSCRIPTEN
|
||||||
|
#include <emscripten.h>
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if defined(BSD) || defined(__APPLE__)
|
||||||
|
#include <sys/sysctl.h>
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#include <string.h>
|
||||||
|
|
||||||
|
/**
|
||||||
|
* cpu_features_get_perf_counter:
|
||||||
|
*
|
||||||
|
* Gets performance counter.
|
||||||
|
*
|
||||||
|
* @return Performance counter.
|
||||||
|
**/
|
||||||
|
retro_perf_tick_t cpu_features_get_perf_counter(void)
|
||||||
|
{
|
||||||
|
retro_perf_tick_t time_ticks = 0;
|
||||||
|
#if defined(_WIN32)
|
||||||
|
long tv_sec, tv_usec;
|
||||||
|
#if defined(_MSC_VER) && _MSC_VER <= 1200
|
||||||
|
static const unsigned __int64 epoch = 11644473600000000;
|
||||||
|
#else
|
||||||
|
static const unsigned __int64 epoch = 11644473600000000ULL;
|
||||||
|
#endif
|
||||||
|
FILETIME file_time;
|
||||||
|
SYSTEMTIME system_time;
|
||||||
|
ULARGE_INTEGER ularge;
|
||||||
|
|
||||||
|
GetSystemTime(&system_time);
|
||||||
|
SystemTimeToFileTime(&system_time, &file_time);
|
||||||
|
ularge.LowPart = file_time.dwLowDateTime;
|
||||||
|
ularge.HighPart = file_time.dwHighDateTime;
|
||||||
|
|
||||||
|
tv_sec = (long)((ularge.QuadPart - epoch) / 10000000L);
|
||||||
|
tv_usec = (long)(system_time.wMilliseconds * 1000);
|
||||||
|
time_ticks = (1000000 * tv_sec + tv_usec);
|
||||||
|
#elif defined(GEKKO)
|
||||||
|
time_ticks = gettime();
|
||||||
|
#elif !defined(__MACH__) && (defined(_XBOX360) || defined(__powerpc__) || defined(__ppc__) || defined(__POWERPC__) || defined(__PSL1GHT__) || defined(__PPC64__) || defined(__powerpc64__))
|
||||||
|
time_ticks = __mftb();
|
||||||
|
#elif (defined(_POSIX_MONOTONIC_CLOCK) && _POSIX_MONOTONIC_CLOCK > 0) || defined(__QNX__) || defined(ANDROID)
|
||||||
|
struct timespec tv;
|
||||||
|
if (ra_clock_gettime(CLOCK_MONOTONIC, &tv) == 0)
|
||||||
|
time_ticks = (retro_perf_tick_t)tv.tv_sec * 1000000000 +
|
||||||
|
(retro_perf_tick_t)tv.tv_nsec;
|
||||||
|
|
||||||
|
#elif defined(__GNUC__) && defined(__i386__) || defined(__i486__) || defined(__i686__) || defined(_M_X64) || defined(_M_AMD64)
|
||||||
|
__asm__ volatile ("rdtsc" : "=A" (time_ticks));
|
||||||
|
#elif defined(__GNUC__) && defined(__x86_64__) || defined(_M_IX86)
|
||||||
|
unsigned a, d;
|
||||||
|
__asm__ volatile ("rdtsc" : "=a" (a), "=d" (d));
|
||||||
|
time_ticks = (retro_perf_tick_t)a | ((retro_perf_tick_t)d << 32);
|
||||||
|
#elif defined(__ARM_ARCH_6__)
|
||||||
|
__asm__ volatile( "mrc p15, 0, %0, c9, c13, 0" : "=r"(time_ticks) );
|
||||||
|
#elif defined(__aarch64__)
|
||||||
|
__asm__ volatile( "mrs %0, cntvct_el0" : "=r"(time_ticks) );
|
||||||
|
#elif defined(PSP) || defined(VITA)
|
||||||
|
time_ticks = sceKernelGetSystemTimeWide();
|
||||||
|
#elif defined(ORBIS)
|
||||||
|
sceRtcGetCurrentTick((SceRtcTick*)&time_ticks);
|
||||||
|
#elif defined(PS2)
|
||||||
|
time_ticks = ps2_clock();
|
||||||
|
#elif defined(_3DS)
|
||||||
|
time_ticks = svcGetSystemTick();
|
||||||
|
#elif defined(WIIU)
|
||||||
|
time_ticks = OSGetSystemTime();
|
||||||
|
#elif defined(HAVE_LIBNX)
|
||||||
|
time_ticks = armGetSystemTick();
|
||||||
|
#elif defined(EMSCRIPTEN)
|
||||||
|
time_ticks = emscripten_get_now() * 1000;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
return time_ticks;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* cpu_features_get_time_usec:
|
||||||
|
*
|
||||||
|
* Gets time in microseconds.
|
||||||
|
*
|
||||||
|
* @return Time in microseconds.
|
||||||
|
**/
|
||||||
|
retro_time_t cpu_features_get_time_usec(void)
|
||||||
|
{
|
||||||
|
#if defined(_WIN32)
|
||||||
|
static LARGE_INTEGER freq;
|
||||||
|
LARGE_INTEGER count;
|
||||||
|
|
||||||
|
/* Frequency is guaranteed to not change. */
|
||||||
|
if (!freq.QuadPart && !QueryPerformanceFrequency(&freq))
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
if (!QueryPerformanceCounter(&count))
|
||||||
|
return 0;
|
||||||
|
return (count.QuadPart / freq.QuadPart * 1000000) + (count.QuadPart % freq.QuadPart * 1000000 / freq.QuadPart);
|
||||||
|
#elif defined(__PSL1GHT__)
|
||||||
|
return sysGetSystemTime();
|
||||||
|
#elif !defined(__PSL1GHT__) && defined(__PS3__)
|
||||||
|
return sys_time_get_system_time();
|
||||||
|
#elif defined(GEKKO)
|
||||||
|
return ticks_to_microsecs(gettime());
|
||||||
|
#elif defined(WIIU)
|
||||||
|
return ticks_to_us(OSGetSystemTime());
|
||||||
|
#elif defined(SWITCH) || defined(HAVE_LIBNX)
|
||||||
|
return (svcGetSystemTick() * 10) / 192;
|
||||||
|
#elif defined(_3DS)
|
||||||
|
return osGetTime() * 1000;
|
||||||
|
#elif defined(_POSIX_MONOTONIC_CLOCK) || defined(__QNX__) || defined(ANDROID) || defined(__MACH__)
|
||||||
|
struct timespec tv;
|
||||||
|
if (ra_clock_gettime(CLOCK_MONOTONIC, &tv) < 0)
|
||||||
|
return 0;
|
||||||
|
return tv.tv_sec * INT64_C(1000000) + (tv.tv_nsec + 500) / 1000;
|
||||||
|
#elif defined(EMSCRIPTEN)
|
||||||
|
return emscripten_get_now() * 1000;
|
||||||
|
#elif defined(PS2)
|
||||||
|
return ps2_clock() / PS2_CLOCKS_PER_MSEC * 1000;
|
||||||
|
#elif defined(VITA) || defined(PSP)
|
||||||
|
return sceKernelGetSystemTimeWide();
|
||||||
|
#elif defined(DJGPP)
|
||||||
|
return uclock() * 1000000LL / UCLOCKS_PER_SEC;
|
||||||
|
#elif defined(ORBIS)
|
||||||
|
return sceKernelGetProcessTime();
|
||||||
|
#else
|
||||||
|
#error "Your platform does not have a timer function implemented in cpu_features_get_time_usec(). Cannot continue."
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
#if defined(__x86_64__) || defined(__i386__) || defined(__i486__) || defined(__i686__) || (defined(_M_X64) && _MSC_VER > 1310) || (defined(_M_IX86) && _MSC_VER > 1310)
|
||||||
|
#define CPU_X86
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if defined(_MSC_VER) && !defined(_XBOX)
|
||||||
|
#if (_MSC_VER > 1310)
|
||||||
|
#include <intrin.h>
|
||||||
|
#endif
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if defined(CPU_X86) && !defined(__MACH__)
|
||||||
|
void x86_cpuid(int func, int flags[4])
|
||||||
|
{
|
||||||
|
/* On Android, we compile RetroArch with PIC, and we
|
||||||
|
* are not allowed to clobber the ebx register. */
|
||||||
|
#ifdef __x86_64__
|
||||||
|
#define REG_b "rbx"
|
||||||
|
#define REG_S "rsi"
|
||||||
|
#else
|
||||||
|
#define REG_b "ebx"
|
||||||
|
#define REG_S "esi"
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if defined(__GNUC__)
|
||||||
|
__asm__ volatile (
|
||||||
|
"mov %%" REG_b ", %%" REG_S "\n"
|
||||||
|
"cpuid\n"
|
||||||
|
"xchg %%" REG_b ", %%" REG_S "\n"
|
||||||
|
: "=a"(flags[0]), "=S"(flags[1]), "=c"(flags[2]), "=d"(flags[3])
|
||||||
|
: "a"(func));
|
||||||
|
#elif defined(_MSC_VER)
|
||||||
|
__cpuid(flags, func);
|
||||||
|
#else
|
||||||
|
#ifndef NDEBUG
|
||||||
|
printf("Unknown compiler. Cannot check CPUID with inline assembly.\n");
|
||||||
|
#endif
|
||||||
|
memset(flags, 0, 4 * sizeof(int));
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Only runs on i686 and above. Needs to be conditionally run. */
|
||||||
|
static uint64_t xgetbv_x86(uint32_t idx)
|
||||||
|
{
|
||||||
|
#if defined(__GNUC__)
|
||||||
|
uint32_t eax, edx;
|
||||||
|
__asm__ volatile (
|
||||||
|
/* Older GCC versions (Apple's GCC for example) do
|
||||||
|
* not understand xgetbv instruction.
|
||||||
|
* Stamp out the machine code directly.
|
||||||
|
*/
|
||||||
|
".byte 0x0f, 0x01, 0xd0\n"
|
||||||
|
: "=a"(eax), "=d"(edx) : "c"(idx));
|
||||||
|
return ((uint64_t)edx << 32) | eax;
|
||||||
|
#elif _MSC_FULL_VER >= 160040219
|
||||||
|
/* Intrinsic only works on 2010 SP1 and above. */
|
||||||
|
return _xgetbv(idx);
|
||||||
|
#else
|
||||||
|
#ifndef NDEBUG
|
||||||
|
printf("Unknown compiler. Cannot check xgetbv bits.\n");
|
||||||
|
#endif
|
||||||
|
return 0;
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if defined(__ARM_NEON__)
|
||||||
|
#if defined(__arm__)
|
||||||
|
static void arm_enable_runfast_mode(void)
|
||||||
|
{
|
||||||
|
/* RunFast mode. Enables flush-to-zero and some
|
||||||
|
* floating point optimizations. */
|
||||||
|
static const unsigned x = 0x04086060;
|
||||||
|
static const unsigned y = 0x03000000;
|
||||||
|
int r;
|
||||||
|
__asm__ volatile(
|
||||||
|
"fmrx %0, fpscr \n\t" /* r0 = FPSCR */
|
||||||
|
"and %0, %0, %1 \n\t" /* r0 = r0 & 0x04086060 */
|
||||||
|
"orr %0, %0, %2 \n\t" /* r0 = r0 | 0x03000000 */
|
||||||
|
"fmxr fpscr, %0 \n\t" /* FPSCR = r0 */
|
||||||
|
: "=r"(r)
|
||||||
|
: "r"(x), "r"(y)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if defined(__linux__) && !defined(CPU_X86)
|
||||||
|
static unsigned char check_arm_cpu_feature(const char* feature)
|
||||||
|
{
|
||||||
|
char line[1024];
|
||||||
|
unsigned char status = 0;
|
||||||
|
RFILE *fp = filestream_open("/proc/cpuinfo",
|
||||||
|
RETRO_VFS_FILE_ACCESS_READ,
|
||||||
|
RETRO_VFS_FILE_ACCESS_HINT_NONE);
|
||||||
|
|
||||||
|
if (!fp)
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
while (filestream_gets(fp, line, sizeof(line)))
|
||||||
|
{
|
||||||
|
if (strncmp(line, "Features\t: ", 11))
|
||||||
|
continue;
|
||||||
|
|
||||||
|
if (strstr(line + 11, feature))
|
||||||
|
status = 1;
|
||||||
|
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
filestream_close(fp);
|
||||||
|
|
||||||
|
return status;
|
||||||
|
}
|
||||||
|
|
||||||
|
#if !defined(_SC_NPROCESSORS_ONLN)
|
||||||
|
/**
|
||||||
|
* parse_decimal:
|
||||||
|
*
|
||||||
|
* Parse an decimal integer starting from 'input', but not going further
|
||||||
|
* than 'limit'. Return the value into '*result'.
|
||||||
|
*
|
||||||
|
* NOTE: Does not skip over leading spaces, or deal with sign characters.
|
||||||
|
* NOTE: Ignores overflows.
|
||||||
|
*
|
||||||
|
* The function returns NULL in case of error (bad format), or the new
|
||||||
|
* position after the decimal number in case of success (which will always
|
||||||
|
* be <= 'limit').
|
||||||
|
*
|
||||||
|
* Leaf function.
|
||||||
|
**/
|
||||||
|
static const char *parse_decimal(const char* input,
|
||||||
|
const char* limit, int* result)
|
||||||
|
{
|
||||||
|
const char* p = input;
|
||||||
|
int val = 0;
|
||||||
|
|
||||||
|
while (p < limit)
|
||||||
|
{
|
||||||
|
int d = (*p - '0');
|
||||||
|
if ((unsigned)d >= 10U)
|
||||||
|
break;
|
||||||
|
val = val*10 + d;
|
||||||
|
p++;
|
||||||
|
}
|
||||||
|
if (p == input)
|
||||||
|
return NULL;
|
||||||
|
|
||||||
|
*result = val;
|
||||||
|
return p;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* cpulist_parse:
|
||||||
|
* Parse a textual list of cpus and store the result inside a CpuList object.
|
||||||
|
* Input format is the following:
|
||||||
|
* - comma-separated list of items (no spaces)
|
||||||
|
* - each item is either a single decimal number (cpu index), or a range made
|
||||||
|
* of two numbers separated by a single dash (-). Ranges are inclusive.
|
||||||
|
*
|
||||||
|
* Examples: 0
|
||||||
|
* 2,4-127,128-143
|
||||||
|
* 0-1
|
||||||
|
**/
|
||||||
|
static void cpulist_parse(CpuList* list, char **buf, ssize_t length)
|
||||||
|
{
|
||||||
|
const char* p = (const char*)buf;
|
||||||
|
const char* end = p + length;
|
||||||
|
|
||||||
|
/* NOTE: the input line coming from sysfs typically contains a
|
||||||
|
* trailing newline, so take care of it in the code below
|
||||||
|
*/
|
||||||
|
while (p < end && *p != '\n')
|
||||||
|
{
|
||||||
|
int val, start_value, end_value;
|
||||||
|
/* Find the end of current item, and put it into 'q' */
|
||||||
|
const char *q = (const char*)memchr(p, ',', end-p);
|
||||||
|
|
||||||
|
if (!q)
|
||||||
|
q = end;
|
||||||
|
|
||||||
|
/* Get first value */
|
||||||
|
if (!(p = parse_decimal(p, q, &start_value)))
|
||||||
|
return;
|
||||||
|
|
||||||
|
end_value = start_value;
|
||||||
|
|
||||||
|
/* If we're not at the end of the item, expect a dash and
|
||||||
|
* and integer; extract end value.
|
||||||
|
*/
|
||||||
|
if (p < q && *p == '-')
|
||||||
|
{
|
||||||
|
if (!(p = parse_decimal(p+1, q, &end_value)))
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Set bits CPU list bits */
|
||||||
|
for (val = start_value; val <= end_value; val++)
|
||||||
|
{
|
||||||
|
if ((unsigned)val < 32)
|
||||||
|
list->mask |= (uint32_t)(UINT32_C(1) << val);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Jump to next item */
|
||||||
|
p = q;
|
||||||
|
if (p < end)
|
||||||
|
p++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* cpulist_read_from:
|
||||||
|
*
|
||||||
|
* Read a CPU list from one sysfs file
|
||||||
|
**/
|
||||||
|
static void cpulist_read_from(CpuList* list, const char* filename)
|
||||||
|
{
|
||||||
|
ssize_t length;
|
||||||
|
char *buf = NULL;
|
||||||
|
|
||||||
|
list->mask = 0;
|
||||||
|
|
||||||
|
if (filestream_read_file(filename, (void**)&buf, &length) != 1)
|
||||||
|
return;
|
||||||
|
|
||||||
|
cpulist_parse(list, &buf, length);
|
||||||
|
if (buf)
|
||||||
|
free(buf);
|
||||||
|
buf = NULL;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/**
|
||||||
|
* cpu_features_get_core_amount:
|
||||||
|
*
|
||||||
|
* Gets the amount of available CPU cores.
|
||||||
|
*
|
||||||
|
* @return Amount of CPU cores available.
|
||||||
|
**/
|
||||||
|
unsigned cpu_features_get_core_amount(void)
|
||||||
|
{
|
||||||
|
#if defined(_WIN32) && !defined(_XBOX)
|
||||||
|
/* Win32 */
|
||||||
|
SYSTEM_INFO sysinfo;
|
||||||
|
#if defined(__WINRT__) || defined(WINAPI_FAMILY) && WINAPI_FAMILY == WINAPI_FAMILY_PHONE_APP
|
||||||
|
GetNativeSystemInfo(&sysinfo);
|
||||||
|
#else
|
||||||
|
GetSystemInfo(&sysinfo);
|
||||||
|
#endif
|
||||||
|
return sysinfo.dwNumberOfProcessors;
|
||||||
|
#elif defined(GEKKO)
|
||||||
|
return 1;
|
||||||
|
#elif defined(PSP) || defined(PS2)
|
||||||
|
return 1;
|
||||||
|
#elif defined(__PSL1GHT__) || !defined(__PSL1GHT__) && defined(__PS3__)
|
||||||
|
return 1; /* Only one PPU, SPUs don't really count */
|
||||||
|
#elif defined(VITA)
|
||||||
|
return 4;
|
||||||
|
#elif defined(HAVE_LIBNX) || defined(SWITCH)
|
||||||
|
return 4;
|
||||||
|
#elif defined(_3DS)
|
||||||
|
u8 device_model = 0xFF;
|
||||||
|
CFGU_GetSystemModel(&device_model);/*(0 = O3DS, 1 = O3DSXL, 2 = N3DS, 3 = 2DS, 4 = N3DSXL, 5 = N2DSXL)*/
|
||||||
|
switch (device_model)
|
||||||
|
{
|
||||||
|
case 0:
|
||||||
|
case 1:
|
||||||
|
case 3:
|
||||||
|
/*Old 3/2DS*/
|
||||||
|
return 2;
|
||||||
|
|
||||||
|
case 2:
|
||||||
|
case 4:
|
||||||
|
case 5:
|
||||||
|
/*New 3/2DS*/
|
||||||
|
return 4;
|
||||||
|
|
||||||
|
default:
|
||||||
|
/*Unknown Device Or Check Failed*/
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
return 1;
|
||||||
|
#elif defined(WIIU)
|
||||||
|
return 3;
|
||||||
|
#elif defined(_SC_NPROCESSORS_ONLN)
|
||||||
|
/* Linux, most UNIX-likes. */
|
||||||
|
long ret = sysconf(_SC_NPROCESSORS_ONLN);
|
||||||
|
if (ret <= 0)
|
||||||
|
return (unsigned)1;
|
||||||
|
return (unsigned)ret;
|
||||||
|
#elif defined(BSD) || defined(__APPLE__)
|
||||||
|
/* BSD */
|
||||||
|
/* Copypasta from stackoverflow, dunno if it works. */
|
||||||
|
int num_cpu = 0;
|
||||||
|
int mib[4];
|
||||||
|
size_t len = sizeof(num_cpu);
|
||||||
|
|
||||||
|
mib[0] = CTL_HW;
|
||||||
|
mib[1] = HW_AVAILCPU;
|
||||||
|
sysctl(mib, 2, &num_cpu, &len, NULL, 0);
|
||||||
|
if (num_cpu < 1)
|
||||||
|
{
|
||||||
|
mib[1] = HW_NCPU;
|
||||||
|
sysctl(mib, 2, &num_cpu, &len, NULL, 0);
|
||||||
|
if (num_cpu < 1)
|
||||||
|
num_cpu = 1;
|
||||||
|
}
|
||||||
|
return num_cpu;
|
||||||
|
#elif defined(__linux__)
|
||||||
|
CpuList cpus_present[1];
|
||||||
|
CpuList cpus_possible[1];
|
||||||
|
int amount = 0;
|
||||||
|
|
||||||
|
cpulist_read_from(cpus_present, "/sys/devices/system/cpu/present");
|
||||||
|
cpulist_read_from(cpus_possible, "/sys/devices/system/cpu/possible");
|
||||||
|
|
||||||
|
/* Compute the intersection of both sets to get the actual number of
|
||||||
|
* CPU cores that can be used on this device by the kernel.
|
||||||
|
*/
|
||||||
|
cpus_present->mask &= cpus_possible->mask;
|
||||||
|
amount = __builtin_popcount(cpus_present->mask);
|
||||||
|
|
||||||
|
if (amount == 0)
|
||||||
|
return 1;
|
||||||
|
return amount;
|
||||||
|
#elif defined(_XBOX360)
|
||||||
|
return 3;
|
||||||
|
#else
|
||||||
|
/* No idea, assume single core. */
|
||||||
|
return 1;
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
/* According to http://en.wikipedia.org/wiki/CPUID */
|
||||||
|
#define VENDOR_INTEL_b 0x756e6547
|
||||||
|
#define VENDOR_INTEL_c 0x6c65746e
|
||||||
|
#define VENDOR_INTEL_d 0x49656e69
|
||||||
|
|
||||||
|
/**
|
||||||
|
* cpu_features_get:
|
||||||
|
*
|
||||||
|
* Gets CPU features..
|
||||||
|
*
|
||||||
|
* @return Bitmask of all CPU features available.
|
||||||
|
**/
|
||||||
|
uint64_t cpu_features_get(void)
|
||||||
|
{
|
||||||
|
uint64_t cpu = 0;
|
||||||
|
#if defined(CPU_X86) && !defined(__MACH__)
|
||||||
|
int vendor_is_intel = 0;
|
||||||
|
const int avx_flags = (1 << 27) | (1 << 28);
|
||||||
|
#endif
|
||||||
|
#if defined(__MACH__)
|
||||||
|
size_t len = sizeof(size_t);
|
||||||
|
|
||||||
|
if (sysctlbyname("hw.optional.floatingpoint", NULL, &len, NULL, 0) == 0)
|
||||||
|
cpu |= RETRO_SIMD_CMOV;
|
||||||
|
|
||||||
|
#if defined(CPU_X86)
|
||||||
|
len = sizeof(size_t);
|
||||||
|
if (sysctlbyname("hw.optional.mmx", NULL, &len, NULL, 0) == 0)
|
||||||
|
cpu |= RETRO_SIMD_MMX | RETRO_SIMD_MMXEXT;
|
||||||
|
|
||||||
|
len = sizeof(size_t);
|
||||||
|
if (sysctlbyname("hw.optional.sse", NULL, &len, NULL, 0) == 0)
|
||||||
|
cpu |= RETRO_SIMD_SSE;
|
||||||
|
|
||||||
|
len = sizeof(size_t);
|
||||||
|
if (sysctlbyname("hw.optional.sse2", NULL, &len, NULL, 0) == 0)
|
||||||
|
cpu |= RETRO_SIMD_SSE2;
|
||||||
|
|
||||||
|
len = sizeof(size_t);
|
||||||
|
if (sysctlbyname("hw.optional.sse3", NULL, &len, NULL, 0) == 0)
|
||||||
|
cpu |= RETRO_SIMD_SSE3;
|
||||||
|
|
||||||
|
len = sizeof(size_t);
|
||||||
|
if (sysctlbyname("hw.optional.supplementalsse3", NULL, &len, NULL, 0) == 0)
|
||||||
|
cpu |= RETRO_SIMD_SSSE3;
|
||||||
|
|
||||||
|
len = sizeof(size_t);
|
||||||
|
if (sysctlbyname("hw.optional.sse4_1", NULL, &len, NULL, 0) == 0)
|
||||||
|
cpu |= RETRO_SIMD_SSE4;
|
||||||
|
|
||||||
|
len = sizeof(size_t);
|
||||||
|
if (sysctlbyname("hw.optional.sse4_2", NULL, &len, NULL, 0) == 0)
|
||||||
|
cpu |= RETRO_SIMD_SSE42;
|
||||||
|
|
||||||
|
len = sizeof(size_t);
|
||||||
|
if (sysctlbyname("hw.optional.aes", NULL, &len, NULL, 0) == 0)
|
||||||
|
cpu |= RETRO_SIMD_AES;
|
||||||
|
|
||||||
|
len = sizeof(size_t);
|
||||||
|
if (sysctlbyname("hw.optional.avx1_0", NULL, &len, NULL, 0) == 0)
|
||||||
|
cpu |= RETRO_SIMD_AVX;
|
||||||
|
|
||||||
|
len = sizeof(size_t);
|
||||||
|
if (sysctlbyname("hw.optional.avx2_0", NULL, &len, NULL, 0) == 0)
|
||||||
|
cpu |= RETRO_SIMD_AVX2;
|
||||||
|
|
||||||
|
len = sizeof(size_t);
|
||||||
|
if (sysctlbyname("hw.optional.altivec", NULL, &len, NULL, 0) == 0)
|
||||||
|
cpu |= RETRO_SIMD_VMX;
|
||||||
|
|
||||||
|
#else
|
||||||
|
len = sizeof(size_t);
|
||||||
|
if (sysctlbyname("hw.optional.neon", NULL, &len, NULL, 0) == 0)
|
||||||
|
cpu |= RETRO_SIMD_NEON;
|
||||||
|
|
||||||
|
len = sizeof(size_t);
|
||||||
|
if (sysctlbyname("hw.optional.neon_fp16", NULL, &len, NULL, 0) == 0)
|
||||||
|
cpu |= RETRO_SIMD_VFPV3;
|
||||||
|
|
||||||
|
len = sizeof(size_t);
|
||||||
|
if (sysctlbyname("hw.optional.neon_hpfp", NULL, &len, NULL, 0) == 0)
|
||||||
|
cpu |= RETRO_SIMD_VFPV4;
|
||||||
|
#endif
|
||||||
|
#elif defined(_XBOX1)
|
||||||
|
cpu |= RETRO_SIMD_MMX | RETRO_SIMD_SSE | RETRO_SIMD_MMXEXT;
|
||||||
|
#elif defined(CPU_X86)
|
||||||
|
unsigned max_flag = 0;
|
||||||
|
int flags[4];
|
||||||
|
int vendor_shuffle[3];
|
||||||
|
char vendor[13];
|
||||||
|
uint64_t cpu_flags = 0;
|
||||||
|
x86_cpuid(0, flags);
|
||||||
|
vendor_shuffle[0] = flags[1];
|
||||||
|
vendor_shuffle[1] = flags[3];
|
||||||
|
vendor_shuffle[2] = flags[2];
|
||||||
|
|
||||||
|
vendor[0] = '\0';
|
||||||
|
memcpy(vendor, vendor_shuffle, sizeof(vendor_shuffle));
|
||||||
|
|
||||||
|
/* printf("[CPUID]: Vendor: %s\n", vendor); */
|
||||||
|
|
||||||
|
vendor_is_intel = (
|
||||||
|
flags[1] == VENDOR_INTEL_b &&
|
||||||
|
flags[2] == VENDOR_INTEL_c &&
|
||||||
|
flags[3] == VENDOR_INTEL_d);
|
||||||
|
|
||||||
|
max_flag = flags[0];
|
||||||
|
if (max_flag < 1) /* Does CPUID not support func = 1? (unlikely ...) */
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
x86_cpuid(1, flags);
|
||||||
|
|
||||||
|
if (flags[3] & (1 << 15))
|
||||||
|
cpu |= RETRO_SIMD_CMOV;
|
||||||
|
|
||||||
|
if (flags[3] & (1 << 23))
|
||||||
|
cpu |= RETRO_SIMD_MMX;
|
||||||
|
|
||||||
|
/* SSE also implies MMXEXT (according to FFmpeg source). */
|
||||||
|
if (flags[3] & (1 << 25))
|
||||||
|
cpu |= RETRO_SIMD_SSE | RETRO_SIMD_MMXEXT;
|
||||||
|
|
||||||
|
if (flags[3] & (1 << 26))
|
||||||
|
cpu |= RETRO_SIMD_SSE2;
|
||||||
|
|
||||||
|
if (flags[2] & (1 << 0))
|
||||||
|
cpu |= RETRO_SIMD_SSE3;
|
||||||
|
|
||||||
|
if (flags[2] & (1 << 9))
|
||||||
|
cpu |= RETRO_SIMD_SSSE3;
|
||||||
|
|
||||||
|
if (flags[2] & (1 << 19))
|
||||||
|
cpu |= RETRO_SIMD_SSE4;
|
||||||
|
|
||||||
|
if (flags[2] & (1 << 20))
|
||||||
|
cpu |= RETRO_SIMD_SSE42;
|
||||||
|
|
||||||
|
if ((flags[2] & (1 << 23)))
|
||||||
|
cpu |= RETRO_SIMD_POPCNT;
|
||||||
|
|
||||||
|
if (vendor_is_intel && (flags[2] & (1 << 22)))
|
||||||
|
cpu |= RETRO_SIMD_MOVBE;
|
||||||
|
|
||||||
|
if (flags[2] & (1 << 25))
|
||||||
|
cpu |= RETRO_SIMD_AES;
|
||||||
|
|
||||||
|
/* Must only perform xgetbv check if we have
|
||||||
|
* AVX CPU support (guaranteed to have at least i686). */
|
||||||
|
if (((flags[2] & avx_flags) == avx_flags)
|
||||||
|
&& ((xgetbv_x86(0) & 0x6) == 0x6))
|
||||||
|
cpu |= RETRO_SIMD_AVX;
|
||||||
|
|
||||||
|
if (max_flag >= 7)
|
||||||
|
{
|
||||||
|
x86_cpuid(7, flags);
|
||||||
|
if (flags[1] & (1 << 5))
|
||||||
|
cpu |= RETRO_SIMD_AVX2;
|
||||||
|
}
|
||||||
|
|
||||||
|
x86_cpuid(0x80000000, flags);
|
||||||
|
max_flag = flags[0];
|
||||||
|
if (max_flag >= 0x80000001u)
|
||||||
|
{
|
||||||
|
x86_cpuid(0x80000001, flags);
|
||||||
|
if (flags[3] & (1 << 23))
|
||||||
|
cpu |= RETRO_SIMD_MMX;
|
||||||
|
if (flags[3] & (1 << 22))
|
||||||
|
cpu |= RETRO_SIMD_MMXEXT;
|
||||||
|
}
|
||||||
|
#elif defined(__linux__)
|
||||||
|
if (check_arm_cpu_feature("neon"))
|
||||||
|
{
|
||||||
|
cpu |= RETRO_SIMD_NEON;
|
||||||
|
#if defined(__ARM_NEON__) && defined(__arm__)
|
||||||
|
arm_enable_runfast_mode();
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
if (check_arm_cpu_feature("vfpv3"))
|
||||||
|
cpu |= RETRO_SIMD_VFPV3;
|
||||||
|
|
||||||
|
if (check_arm_cpu_feature("vfpv4"))
|
||||||
|
cpu |= RETRO_SIMD_VFPV4;
|
||||||
|
|
||||||
|
if (check_arm_cpu_feature("asimd"))
|
||||||
|
{
|
||||||
|
cpu |= RETRO_SIMD_ASIMD;
|
||||||
|
#ifdef __ARM_NEON__
|
||||||
|
cpu |= RETRO_SIMD_NEON;
|
||||||
|
#if defined(__arm__)
|
||||||
|
arm_enable_runfast_mode();
|
||||||
|
#endif
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
#if 0
|
||||||
|
check_arm_cpu_feature("swp");
|
||||||
|
check_arm_cpu_feature("half");
|
||||||
|
check_arm_cpu_feature("thumb");
|
||||||
|
check_arm_cpu_feature("fastmult");
|
||||||
|
check_arm_cpu_feature("vfp");
|
||||||
|
check_arm_cpu_feature("edsp");
|
||||||
|
check_arm_cpu_feature("thumbee");
|
||||||
|
check_arm_cpu_feature("tls");
|
||||||
|
check_arm_cpu_feature("idiva");
|
||||||
|
check_arm_cpu_feature("idivt");
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#elif defined(__ARM_NEON__)
|
||||||
|
cpu |= RETRO_SIMD_NEON;
|
||||||
|
#if defined(__arm__)
|
||||||
|
arm_enable_runfast_mode();
|
||||||
|
#endif
|
||||||
|
#elif defined(__ALTIVEC__)
|
||||||
|
cpu |= RETRO_SIMD_VMX;
|
||||||
|
#elif defined(XBOX360)
|
||||||
|
cpu |= RETRO_SIMD_VMX128;
|
||||||
|
#elif defined(PSP) || defined(PS2)
|
||||||
|
cpu |= RETRO_SIMD_VFPU;
|
||||||
|
#elif defined(GEKKO)
|
||||||
|
cpu |= RETRO_SIMD_PS;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
return cpu;
|
||||||
|
}
|
||||||
|
|
||||||
|
void cpu_features_get_model_name(char *name, int len)
|
||||||
|
{
|
||||||
|
#if defined(CPU_X86) && !defined(__MACH__)
|
||||||
|
union {
|
||||||
|
int i[4];
|
||||||
|
unsigned char s[16];
|
||||||
|
} flags;
|
||||||
|
int i, j;
|
||||||
|
size_t pos = 0;
|
||||||
|
bool start = false;
|
||||||
|
|
||||||
|
if (!name)
|
||||||
|
return;
|
||||||
|
|
||||||
|
x86_cpuid(0x80000000, flags.i);
|
||||||
|
|
||||||
|
if (flags.i[0] < 0x80000004)
|
||||||
|
return;
|
||||||
|
|
||||||
|
for (i = 0; i < 3; i++)
|
||||||
|
{
|
||||||
|
memset(flags.i, 0, sizeof(flags.i));
|
||||||
|
x86_cpuid(0x80000002 + i, flags.i);
|
||||||
|
|
||||||
|
for (j = 0; j < sizeof(flags.s); j++)
|
||||||
|
{
|
||||||
|
if (!start && flags.s[j] == ' ')
|
||||||
|
continue;
|
||||||
|
else
|
||||||
|
start = true;
|
||||||
|
|
||||||
|
if (pos == len - 1)
|
||||||
|
{
|
||||||
|
/* truncate if we ran out of room */
|
||||||
|
name[pos] = '\0';
|
||||||
|
goto end;
|
||||||
|
}
|
||||||
|
|
||||||
|
name[pos++] = flags.s[j];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
end:
|
||||||
|
/* terminate our string */
|
||||||
|
if (pos < (size_t)len)
|
||||||
|
name[pos] = '\0';
|
||||||
|
#elif defined(__MACH__)
|
||||||
|
if (!name)
|
||||||
|
return;
|
||||||
|
{
|
||||||
|
size_t len_size = len;
|
||||||
|
sysctlbyname("machdep.cpu.brand_string", name, &len_size, NULL, 0);
|
||||||
|
}
|
||||||
|
#elif defined(__linux__)
|
||||||
|
if (!name)
|
||||||
|
return;
|
||||||
|
{
|
||||||
|
char *model_name, line[128];
|
||||||
|
RFILE *fp = filestream_open("/proc/cpuinfo",
|
||||||
|
RETRO_VFS_FILE_ACCESS_READ,
|
||||||
|
RETRO_VFS_FILE_ACCESS_HINT_NONE);
|
||||||
|
|
||||||
|
if (!fp)
|
||||||
|
return;
|
||||||
|
|
||||||
|
while (filestream_gets(fp, line, sizeof(line)))
|
||||||
|
{
|
||||||
|
if (strncmp(line, "model name", 10))
|
||||||
|
continue;
|
||||||
|
|
||||||
|
if ((model_name = strstr(line + 10, ": ")))
|
||||||
|
{
|
||||||
|
model_name += 2;
|
||||||
|
strncpy(name, model_name, len);
|
||||||
|
name[len - 1] = '\0';
|
||||||
|
}
|
||||||
|
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
filestream_close(fp);
|
||||||
|
}
|
||||||
|
#else
|
||||||
|
if (!name)
|
||||||
|
return;
|
||||||
|
return;
|
||||||
|
#endif
|
||||||
|
}
|
File diff suppressed because it is too large
Load Diff
@ -24,13 +24,11 @@
|
|||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
#include <time.h>
|
#include <time.h>
|
||||||
#include <errno.h>
|
|
||||||
|
|
||||||
#include <sys/stat.h>
|
#include <sys/stat.h>
|
||||||
|
|
||||||
#include <boolean.h>
|
#include <boolean.h>
|
||||||
#include <file/file_path.h>
|
#include <file/file_path.h>
|
||||||
#include <retro_assert.h>
|
|
||||||
#include <compat/strl.h>
|
#include <compat/strl.h>
|
||||||
#include <compat/posix_string.h>
|
#include <compat/posix_string.h>
|
||||||
#include <retro_miscellaneous.h>
|
#include <retro_miscellaneous.h>
|
||||||
@ -74,7 +72,7 @@ int path_stat(const char *path)
|
|||||||
*
|
*
|
||||||
* Checks if path is a directory.
|
* Checks if path is a directory.
|
||||||
*
|
*
|
||||||
* Returns: true (1) if path is a directory, otherwise false (0).
|
* @return true if path is a directory, otherwise false.
|
||||||
*/
|
*/
|
||||||
bool path_is_directory(const char *path)
|
bool path_is_directory(const char *path)
|
||||||
{
|
{
|
||||||
@ -105,8 +103,10 @@ int32_t path_get_size(const char *path)
|
|||||||
* @dir : directory
|
* @dir : directory
|
||||||
*
|
*
|
||||||
* Create directory on filesystem.
|
* Create directory on filesystem.
|
||||||
|
*
|
||||||
|
* Recursive function.
|
||||||
*
|
*
|
||||||
* Returns: true (1) if directory could be created, otherwise false (0).
|
* @return true if directory could be created, otherwise false.
|
||||||
**/
|
**/
|
||||||
bool path_mkdir(const char *dir)
|
bool path_mkdir(const char *dir)
|
||||||
{
|
{
|
||||||
@ -118,12 +118,10 @@ bool path_mkdir(const char *dir)
|
|||||||
|
|
||||||
/* Use heap. Real chance of stack
|
/* Use heap. Real chance of stack
|
||||||
* overflow if we recurse too hard. */
|
* overflow if we recurse too hard. */
|
||||||
basedir = strdup(dir);
|
if (!(basedir = strdup(dir)))
|
||||||
|
return false;
|
||||||
|
|
||||||
if (!basedir)
|
path_parent_dir(basedir, strlen(basedir));
|
||||||
return false;
|
|
||||||
|
|
||||||
path_parent_dir(basedir);
|
|
||||||
|
|
||||||
if (!*basedir || !strcmp(basedir, dir))
|
if (!*basedir || !strcmp(basedir, dir))
|
||||||
{
|
{
|
||||||
|
@ -165,6 +165,7 @@ extern int audioAddData(uint32_t portNum, float *data,
|
|||||||
#define ioPadGetData cellPadGetData
|
#define ioPadGetData cellPadGetData
|
||||||
#define ioPadInit cellPadInit
|
#define ioPadInit cellPadInit
|
||||||
#define ioPadEnd cellPadEnd
|
#define ioPadEnd cellPadEnd
|
||||||
|
#define ioPadSetPortSetting cellPadSetPortSetting
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
/*============================================================
|
/*============================================================
|
||||||
@ -198,6 +199,13 @@ extern int audioAddData(uint32_t portNum, float *data,
|
|||||||
|
|
||||||
#else
|
#else
|
||||||
#include <cell/mouse.h>
|
#include <cell/mouse.h>
|
||||||
|
#define mouseInfo CellMouseInfo
|
||||||
|
#define mouseData CellMouseData
|
||||||
|
|
||||||
|
#define ioMouseInit cellMouseInit
|
||||||
|
#define ioMouseGetData cellMouseGetData
|
||||||
|
#define ioMouseEnd cellMouseEnd
|
||||||
|
#define ioMouseGetInfo cellMouseGetInfo
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
@ -683,25 +691,56 @@ extern int audioAddData(uint32_t portNum, float *data,
|
|||||||
#define FS_TYPE_DIR 1
|
#define FS_TYPE_DIR 1
|
||||||
#ifdef __PSL1GHT__
|
#ifdef __PSL1GHT__
|
||||||
#include <lv2/sysfs.h>
|
#include <lv2/sysfs.h>
|
||||||
|
#ifndef O_RDONLY
|
||||||
#define O_RDONLY SYS_O_RDONLY
|
#define O_RDONLY SYS_O_RDONLY
|
||||||
|
#endif
|
||||||
|
#ifndef O_WRONLY
|
||||||
#define O_WRONLY SYS_O_WRONLY
|
#define O_WRONLY SYS_O_WRONLY
|
||||||
|
#endif
|
||||||
|
#ifndef O_CREAT
|
||||||
#define O_CREAT SYS_O_CREAT
|
#define O_CREAT SYS_O_CREAT
|
||||||
|
#endif
|
||||||
|
#ifndef O_TRUNC
|
||||||
#define O_TRUNC SYS_O_TRUNC
|
#define O_TRUNC SYS_O_TRUNC
|
||||||
|
#endif
|
||||||
|
#ifndef O_RDWR
|
||||||
#define O_RDWR SYS_O_RDWR
|
#define O_RDWR SYS_O_RDWR
|
||||||
|
#endif
|
||||||
#else
|
#else
|
||||||
#include <cell/cell_fs.h>
|
#include <cell/cell_fs.h>
|
||||||
|
#ifndef O_RDONLY
|
||||||
#define O_RDONLY CELL_FS_O_RDONLY
|
#define O_RDONLY CELL_FS_O_RDONLY
|
||||||
|
#endif
|
||||||
|
#ifndef O_WRONLY
|
||||||
#define O_WRONLY CELL_FS_O_WRONLY
|
#define O_WRONLY CELL_FS_O_WRONLY
|
||||||
|
#endif
|
||||||
|
#ifndef O_CREAT
|
||||||
#define O_CREAT CELL_FS_O_CREAT
|
#define O_CREAT CELL_FS_O_CREAT
|
||||||
|
#endif
|
||||||
|
#ifndef O_TRUNC
|
||||||
#define O_TRUNC CELL_FS_O_TRUNC
|
#define O_TRUNC CELL_FS_O_TRUNC
|
||||||
|
#endif
|
||||||
|
#ifndef O_RDWR
|
||||||
#define O_RDWR CELL_FS_O_RDWR
|
#define O_RDWR CELL_FS_O_RDWR
|
||||||
|
#endif
|
||||||
|
#ifndef sysFsStat
|
||||||
#define sysFsStat cellFsStat
|
#define sysFsStat cellFsStat
|
||||||
#define sysFSStat CellFsStat
|
#endif
|
||||||
|
#ifndef sysFSDirent
|
||||||
#define sysFSDirent CellFsDirent
|
#define sysFSDirent CellFsDirent
|
||||||
|
#endif
|
||||||
|
#ifndef sysFsOpendir
|
||||||
#define sysFsOpendir cellFsOpendir
|
#define sysFsOpendir cellFsOpendir
|
||||||
|
#endif
|
||||||
|
#ifndef sysFsReaddir
|
||||||
#define sysFsReaddir cellFsReaddir
|
#define sysFsReaddir cellFsReaddir
|
||||||
|
#endif
|
||||||
|
#ifndef sysFSDirent
|
||||||
#define sysFSDirent CellFsDirent
|
#define sysFSDirent CellFsDirent
|
||||||
|
#endif
|
||||||
|
#ifndef sysFsClosedir
|
||||||
#define sysFsClosedir cellFsClosedir
|
#define sysFsClosedir cellFsClosedir
|
||||||
#endif
|
#endif
|
||||||
|
#endif
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
@ -38,29 +38,99 @@ enum CodePage
|
|||||||
CODEPAGE_UTF8 = 65001 /* CP_UTF8 */
|
CODEPAGE_UTF8 = 65001 /* CP_UTF8 */
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* utf8_conv_utf32:
|
||||||
|
*
|
||||||
|
* Simple implementation. Assumes the sequence is
|
||||||
|
* properly synchronized and terminated.
|
||||||
|
**/
|
||||||
size_t utf8_conv_utf32(uint32_t *out, size_t out_chars,
|
size_t utf8_conv_utf32(uint32_t *out, size_t out_chars,
|
||||||
const char *in, size_t in_size);
|
const char *in, size_t in_size);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* utf16_conv_utf8:
|
||||||
|
*
|
||||||
|
* Leaf function.
|
||||||
|
**/
|
||||||
bool utf16_conv_utf8(uint8_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);
|
const uint16_t *in, size_t in_size);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* utf8len:
|
||||||
|
*
|
||||||
|
* Leaf function.
|
||||||
|
**/
|
||||||
size_t utf8len(const char *string);
|
size_t utf8len(const char *string);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* utf8cpy:
|
||||||
|
*
|
||||||
|
* Acts mostly like strlcpy.
|
||||||
|
*
|
||||||
|
* Copies the given number of UTF-8 characters,
|
||||||
|
* but at most @d_len bytes.
|
||||||
|
*
|
||||||
|
* Always NULL terminates. Does not copy half a character.
|
||||||
|
* @s is assumed valid UTF-8.
|
||||||
|
* Use only if @chars is considerably less than @d_len.
|
||||||
|
*
|
||||||
|
* Hidden non-leaf function cost:
|
||||||
|
* - Calls memcpy
|
||||||
|
*
|
||||||
|
* @return Number of bytes.
|
||||||
|
**/
|
||||||
size_t utf8cpy(char *d, size_t d_len, const char *s, size_t chars);
|
size_t utf8cpy(char *d, size_t d_len, const char *s, size_t chars);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* utf8skip:
|
||||||
|
*
|
||||||
|
* Leaf function
|
||||||
|
**/
|
||||||
const char *utf8skip(const char *str, size_t chars);
|
const char *utf8skip(const char *str, size_t chars);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* utf8_walk:
|
||||||
|
*
|
||||||
|
* Does not validate the input.
|
||||||
|
*
|
||||||
|
* Leaf function.
|
||||||
|
*
|
||||||
|
* @return Returns garbage if it's not UTF-8.
|
||||||
|
**/
|
||||||
uint32_t utf8_walk(const char **string);
|
uint32_t utf8_walk(const char **string);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* utf16_to_char_string:
|
||||||
|
**/
|
||||||
bool utf16_to_char_string(const uint16_t *in, char *s, size_t len);
|
bool utf16_to_char_string(const uint16_t *in, char *s, size_t len);
|
||||||
|
|
||||||
char* utf8_to_local_string_alloc(const char *str);
|
/**
|
||||||
|
* utf8_to_local_string_alloc:
|
||||||
|
*
|
||||||
|
* @return Returned pointer MUST be freed by the caller if non-NULL.
|
||||||
|
**/
|
||||||
|
char *utf8_to_local_string_alloc(const char *str);
|
||||||
|
|
||||||
char* local_to_utf8_string_alloc(const char *str);
|
/**
|
||||||
|
* local_to_utf8_string_alloc:
|
||||||
|
*
|
||||||
|
* @return Returned pointer MUST be freed by the caller if non-NULL.
|
||||||
|
**/
|
||||||
|
char *local_to_utf8_string_alloc(const char *str);
|
||||||
|
|
||||||
wchar_t* utf8_to_utf16_string_alloc(const char *str);
|
/**
|
||||||
|
* utf8_to_utf16_string_alloc:
|
||||||
|
*
|
||||||
|
* @return Returned pointer MUST be freed by the caller if non-NULL.
|
||||||
|
**/
|
||||||
|
wchar_t *utf8_to_utf16_string_alloc(const char *str);
|
||||||
|
|
||||||
char* utf16_to_utf8_string_alloc(const wchar_t *str);
|
/**
|
||||||
|
* utf16_to_utf8_string_alloc:
|
||||||
|
*
|
||||||
|
* @return Returned pointer MUST be freed by the caller if non-NULL.
|
||||||
|
**/
|
||||||
|
char *utf16_to_utf8_string_alloc(const wchar_t *str);
|
||||||
|
|
||||||
RETRO_END_DECLS
|
RETRO_END_DECLS
|
||||||
|
|
||||||
|
75
libretro/libretro-common/include/features/features_cpu.h
Normal file
75
libretro/libretro-common/include/features/features_cpu.h
Normal file
@ -0,0 +1,75 @@
|
|||||||
|
/* Copyright (C) 2010-2020 The RetroArch team
|
||||||
|
*
|
||||||
|
* ---------------------------------------------------------------------------------------
|
||||||
|
* The following license statement only applies to this file (features_cpu.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_CPU_INFO_H
|
||||||
|
#define _LIBRETRO_SDK_CPU_INFO_H
|
||||||
|
|
||||||
|
#include <retro_common_api.h>
|
||||||
|
|
||||||
|
#include <stdint.h>
|
||||||
|
|
||||||
|
#include <libretro.h>
|
||||||
|
|
||||||
|
RETRO_BEGIN_DECLS
|
||||||
|
|
||||||
|
/**
|
||||||
|
* cpu_features_get_perf_counter:
|
||||||
|
*
|
||||||
|
* Gets performance counter.
|
||||||
|
*
|
||||||
|
* @return Performance counter.
|
||||||
|
**/
|
||||||
|
retro_perf_tick_t cpu_features_get_perf_counter(void);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* cpu_features_get_time_usec:
|
||||||
|
*
|
||||||
|
* Gets time in microseconds, from an undefined epoch.
|
||||||
|
* The epoch may change between computers or across reboots.
|
||||||
|
*
|
||||||
|
* @return Time in microseconds
|
||||||
|
**/
|
||||||
|
retro_time_t cpu_features_get_time_usec(void);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* cpu_features_get:
|
||||||
|
*
|
||||||
|
* Gets CPU features.
|
||||||
|
*
|
||||||
|
* @return Bitmask of all CPU features available.
|
||||||
|
**/
|
||||||
|
uint64_t cpu_features_get(void);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* cpu_features_get_core_amount:
|
||||||
|
*
|
||||||
|
* Gets the amount of available CPU cores.
|
||||||
|
*
|
||||||
|
* @return Amount of CPU cores available.
|
||||||
|
**/
|
||||||
|
unsigned cpu_features_get_core_amount(void);
|
||||||
|
|
||||||
|
void cpu_features_get_model_name(char *name, int len);
|
||||||
|
|
||||||
|
RETRO_END_DECLS
|
||||||
|
|
||||||
|
#endif
|
@ -51,6 +51,28 @@ enum
|
|||||||
RARCH_FILE_UNSUPPORTED
|
RARCH_FILE_UNSUPPORTED
|
||||||
};
|
};
|
||||||
|
|
||||||
|
struct path_linked_list
|
||||||
|
{
|
||||||
|
char *path;
|
||||||
|
struct path_linked_list *next;
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Create a new linked list with one item in it
|
||||||
|
* The path on this item will be set to NULL
|
||||||
|
**/
|
||||||
|
struct path_linked_list* path_linked_list_new(void);
|
||||||
|
|
||||||
|
/* Free the entire linked list */
|
||||||
|
void path_linked_list_free(struct path_linked_list *in_path_linked_list);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Add a node to the linked list with this path
|
||||||
|
* If the first node's path if it's not yet set,
|
||||||
|
* set this instead
|
||||||
|
**/
|
||||||
|
void path_linked_list_add_path(struct path_linked_list *in_path_linked_list, char *path);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* path_is_compressed_file:
|
* path_is_compressed_file:
|
||||||
* @path : path
|
* @path : path
|
||||||
@ -81,12 +103,12 @@ bool path_is_compressed_file(const char *path);
|
|||||||
* path_get_archive_delim:
|
* path_get_archive_delim:
|
||||||
* @path : path
|
* @path : path
|
||||||
*
|
*
|
||||||
* Gets delimiter of an archive file. Only the first '#'
|
* Find delimiter of an archive file. Only the first '#'
|
||||||
* after a compression extension is considered.
|
* after a compression extension is considered.
|
||||||
*
|
*
|
||||||
* Returns: pointer to the delimiter in the path if it contains
|
* @return pointer to the delimiter in the path if it contains
|
||||||
* a compressed file, otherwise NULL.
|
* a path inside a compressed file, otherwise NULL.
|
||||||
*/
|
**/
|
||||||
const char *path_get_archive_delim(const char *path);
|
const char *path_get_archive_delim(const char *path);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -96,10 +118,28 @@ const char *path_get_archive_delim(const char *path);
|
|||||||
* Gets extension of file. Only '.'s
|
* Gets extension of file. Only '.'s
|
||||||
* after the last slash are considered.
|
* after the last slash are considered.
|
||||||
*
|
*
|
||||||
* Returns: extension part from the path.
|
* Hidden non-leaf function cost:
|
||||||
*/
|
* - calls string_is_empty()
|
||||||
|
* - calls strrchr
|
||||||
|
*
|
||||||
|
* @return extension part from the path.
|
||||||
|
**/
|
||||||
const char *path_get_extension(const char *path);
|
const char *path_get_extension(const char *path);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* path_get_extension_mutable:
|
||||||
|
* @path : path
|
||||||
|
*
|
||||||
|
* Specialized version of path_get_extension(). Return
|
||||||
|
* value is mutable.
|
||||||
|
*
|
||||||
|
* Gets extension of file. Only '.'s
|
||||||
|
* after the last slash are considered.
|
||||||
|
*
|
||||||
|
* @return extension part from the path.
|
||||||
|
**/
|
||||||
|
char *path_get_extension_mutable(const char *path);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* path_remove_extension:
|
* path_remove_extension:
|
||||||
* @path : path
|
* @path : path
|
||||||
@ -108,7 +148,10 @@ const char *path_get_extension(const char *path);
|
|||||||
* text after and including the last '.'.
|
* text after and including the last '.'.
|
||||||
* Only '.'s after the last slash are considered.
|
* Only '.'s after the last slash are considered.
|
||||||
*
|
*
|
||||||
* Returns:
|
* Hidden non-leaf function cost:
|
||||||
|
* - calls strrchr
|
||||||
|
*
|
||||||
|
* @return
|
||||||
* 1) If path has an extension, returns path with the
|
* 1) If path has an extension, returns path with the
|
||||||
* extension removed.
|
* extension removed.
|
||||||
* 2) If there is no extension, returns NULL.
|
* 2) If there is no extension, returns NULL.
|
||||||
@ -122,9 +165,26 @@ char *path_remove_extension(char *path);
|
|||||||
*
|
*
|
||||||
* Get basename from @path.
|
* Get basename from @path.
|
||||||
*
|
*
|
||||||
* Returns: basename from path.
|
* Hidden non-leaf function cost:
|
||||||
|
* - Calls path_get_archive_delim()
|
||||||
|
* - can call find_last_slash() once if it returns NULL
|
||||||
|
*
|
||||||
|
* @return basename from path.
|
||||||
**/
|
**/
|
||||||
const char *path_basename(const char *path);
|
const char *path_basename(const char *path);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* path_basename_nocompression:
|
||||||
|
* @path : path
|
||||||
|
*
|
||||||
|
* Specialized version of path_basename().
|
||||||
|
* Get basename from @path.
|
||||||
|
*
|
||||||
|
* Hidden non-leaf function cost:
|
||||||
|
* - Calls find_last_slash()
|
||||||
|
*
|
||||||
|
* @return basename from path.
|
||||||
|
**/
|
||||||
const char *path_basename_nocompression(const char *path);
|
const char *path_basename_nocompression(const char *path);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -139,12 +199,13 @@ void path_basedir(char *path);
|
|||||||
/**
|
/**
|
||||||
* path_parent_dir:
|
* path_parent_dir:
|
||||||
* @path : path
|
* @path : path
|
||||||
|
* @len : length of @path
|
||||||
*
|
*
|
||||||
* Extracts parent directory by mutating path.
|
* Extracts parent directory by mutating path.
|
||||||
* Assumes that path is a directory. Keeps trailing '/'.
|
* Assumes that path is a directory. Keeps trailing '/'.
|
||||||
* If the path was already at the root directory, returns empty string
|
* If the path was already at the root directory, returns empty string
|
||||||
**/
|
**/
|
||||||
void path_parent_dir(char *path);
|
void path_parent_dir(char *path, size_t len);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* path_resolve_realpath:
|
* path_resolve_realpath:
|
||||||
@ -156,7 +217,7 @@ void path_parent_dir(char *path);
|
|||||||
*
|
*
|
||||||
* Relative paths are rebased on the current working dir.
|
* Relative paths are rebased on the current working dir.
|
||||||
*
|
*
|
||||||
* Returns: @buf if successful, NULL otherwise.
|
* @return @buf if successful, NULL otherwise.
|
||||||
* Note: Not implemented on consoles
|
* Note: Not implemented on consoles
|
||||||
* Note: Symlinks are only resolved on Unix-likes
|
* Note: Symlinks are only resolved on Unix-likes
|
||||||
* Note: The current working dir might not be what you expect,
|
* Note: The current working dir might not be what you expect,
|
||||||
@ -178,8 +239,11 @@ char *path_resolve_realpath(char *buf, size_t size, bool resolve_symlinks);
|
|||||||
* Both @path and @base are assumed to be absolute paths without "." or "..".
|
* Both @path and @base are assumed to be absolute paths without "." or "..".
|
||||||
*
|
*
|
||||||
* E.g. path /a/b/e/f.cgp with base /a/b/c/d/ turns into ../../e/f.cgp
|
* E.g. path /a/b/e/f.cgp with base /a/b/c/d/ turns into ../../e/f.cgp
|
||||||
|
*
|
||||||
|
* @return Length of the string copied into @out
|
||||||
**/
|
**/
|
||||||
size_t path_relative_to(char *out, const char *path, const char *base, size_t size);
|
size_t path_relative_to(char *out, const char *path, const char *base,
|
||||||
|
size_t size);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* path_is_absolute:
|
* path_is_absolute:
|
||||||
@ -187,7 +251,7 @@ size_t path_relative_to(char *out, const char *path, const char *base, size_t si
|
|||||||
*
|
*
|
||||||
* Checks if @path is an absolute path or a relative path.
|
* Checks if @path is an absolute path or a relative path.
|
||||||
*
|
*
|
||||||
* Returns: true if path is absolute, false if path is relative.
|
* @return true if path is absolute, false if path is relative.
|
||||||
**/
|
**/
|
||||||
bool path_is_absolute(const char *path);
|
bool path_is_absolute(const char *path);
|
||||||
|
|
||||||
@ -211,8 +275,15 @@ bool path_is_absolute(const char *path);
|
|||||||
* out_path = "/foo/bar/baz/boo.asm"
|
* out_path = "/foo/bar/baz/boo.asm"
|
||||||
* E.g.: in_path = "/foo/bar/baz/boo.c", replace = "" =>
|
* E.g.: in_path = "/foo/bar/baz/boo.c", replace = "" =>
|
||||||
* out_path = "/foo/bar/baz/boo"
|
* out_path = "/foo/bar/baz/boo"
|
||||||
|
*
|
||||||
|
* Hidden non-leaf function cost:
|
||||||
|
* - calls strlcpy 2x
|
||||||
|
* - calls strrchr
|
||||||
|
* - calls strlcat
|
||||||
|
*
|
||||||
|
* @return Length of the string copied into @out
|
||||||
*/
|
*/
|
||||||
void fill_pathname(char *out_path, const char *in_path,
|
size_t fill_pathname(char *out_path, const char *in_path,
|
||||||
const char *replace, size_t size);
|
const char *replace, size_t size);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -226,6 +297,12 @@ void fill_pathname(char *out_path, const char *in_path,
|
|||||||
*
|
*
|
||||||
* E.g.:
|
* E.g.:
|
||||||
* out_filename = "RetroArch-{month}{day}-{Hours}{Minutes}.{@ext}"
|
* out_filename = "RetroArch-{month}{day}-{Hours}{Minutes}.{@ext}"
|
||||||
|
*
|
||||||
|
* Hidden non-leaf function cost:
|
||||||
|
* - Calls rtime_localtime()
|
||||||
|
* - Calls strftime
|
||||||
|
* - Calls strlcat
|
||||||
|
*
|
||||||
**/
|
**/
|
||||||
size_t fill_dated_filename(char *out_filename,
|
size_t fill_dated_filename(char *out_filename,
|
||||||
const char *ext, size_t size);
|
const char *ext, size_t size);
|
||||||
@ -242,34 +319,33 @@ size_t fill_dated_filename(char *out_filename,
|
|||||||
*
|
*
|
||||||
* E.g.:
|
* E.g.:
|
||||||
* out_filename = "RetroArch-{year}{month}{day}-{Hour}{Minute}{Second}.{@ext}"
|
* out_filename = "RetroArch-{year}{month}{day}-{Hour}{Minute}{Second}.{@ext}"
|
||||||
|
*
|
||||||
|
* Hidden non-leaf function cost:
|
||||||
|
* - Calls time
|
||||||
|
* - Calls rtime_localtime()
|
||||||
|
* - Calls strlcpy
|
||||||
|
* - Calls string_is_empty()
|
||||||
|
* - Calls strftime
|
||||||
|
* - Calls strlcat at least 2x
|
||||||
|
*
|
||||||
|
* @return Length of the string copied into @out_path
|
||||||
**/
|
**/
|
||||||
void fill_str_dated_filename(char *out_filename,
|
size_t fill_str_dated_filename(char *out_filename,
|
||||||
const char *in_str, const char *ext, size_t size);
|
const char *in_str, const char *ext, size_t size);
|
||||||
|
|
||||||
/**
|
|
||||||
* fill_pathname_noext:
|
|
||||||
* @out_path : output path
|
|
||||||
* @in_path : input path
|
|
||||||
* @replace : what to replace
|
|
||||||
* @size : buffer size of output path
|
|
||||||
*
|
|
||||||
* Appends a filename extension 'replace' to 'in_path', and outputs
|
|
||||||
* result in 'out_path'.
|
|
||||||
*
|
|
||||||
* Assumes in_path has no extension. If an extension is still
|
|
||||||
* present in 'in_path', it will be ignored.
|
|
||||||
*
|
|
||||||
*/
|
|
||||||
size_t fill_pathname_noext(char *out_path, const char *in_path,
|
|
||||||
const char *replace, size_t size);
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* find_last_slash:
|
* find_last_slash:
|
||||||
* @str : input path
|
* @str : path
|
||||||
|
* @size : size of path
|
||||||
*
|
*
|
||||||
* Gets a pointer to the last slash in the input path.
|
* Find last slash in path. Tries to find
|
||||||
|
* a backslash on Windows too which takes precedence
|
||||||
|
* over regular slash.
|
||||||
|
|
||||||
|
* Hidden non-leaf function cost:
|
||||||
|
* - calls strrchr
|
||||||
*
|
*
|
||||||
* Returns: a pointer to the last slash in the input path.
|
* @return pointer to last slash/backslash found in @str.
|
||||||
**/
|
**/
|
||||||
char *find_last_slash(const char *str);
|
char *find_last_slash(const char *str);
|
||||||
|
|
||||||
@ -289,6 +365,11 @@ char *find_last_slash(const char *str);
|
|||||||
*
|
*
|
||||||
* E.g..: in_dir = "/tmp/some_dir", in_basename = "/some_content/foo.c",
|
* E.g..: in_dir = "/tmp/some_dir", in_basename = "/some_content/foo.c",
|
||||||
* replace = ".asm" => in_dir = "/tmp/some_dir/foo.c.asm"
|
* replace = ".asm" => in_dir = "/tmp/some_dir/foo.c.asm"
|
||||||
|
*
|
||||||
|
* Hidden non-leaf function cost:
|
||||||
|
* - Calls fill_pathname_slash()
|
||||||
|
* - Calls path_basename()
|
||||||
|
* - Calls strlcat 2x
|
||||||
**/
|
**/
|
||||||
size_t fill_pathname_dir(char *in_dir, const char *in_basename,
|
size_t fill_pathname_dir(char *in_dir, const char *in_basename,
|
||||||
const char *replace, size_t size);
|
const char *replace, size_t size);
|
||||||
@ -300,16 +381,15 @@ size_t fill_pathname_dir(char *in_dir, const char *in_basename,
|
|||||||
* @size : size of output path
|
* @size : size of output path
|
||||||
*
|
*
|
||||||
* Copies basename of @in_path into @out_path.
|
* Copies basename of @in_path into @out_path.
|
||||||
|
*
|
||||||
|
* Hidden non-leaf function cost:
|
||||||
|
* - Calls path_basename()
|
||||||
|
* - Calls strlcpy
|
||||||
|
*
|
||||||
|
* @return length of the string copied into @out
|
||||||
**/
|
**/
|
||||||
size_t fill_pathname_base(char *out_path, const char *in_path, size_t size);
|
size_t fill_pathname_base(char *out_path, const char *in_path, size_t size);
|
||||||
|
|
||||||
void fill_pathname_base_noext(char *out_dir,
|
|
||||||
const char *in_path, size_t size);
|
|
||||||
|
|
||||||
size_t fill_pathname_base_ext(char *out,
|
|
||||||
const char *in_path, const char *ext,
|
|
||||||
size_t size);
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* fill_pathname_basedir:
|
* fill_pathname_basedir:
|
||||||
* @out_dir : output directory
|
* @out_dir : output directory
|
||||||
@ -319,12 +399,13 @@ size_t fill_pathname_base_ext(char *out,
|
|||||||
* Copies base directory of @in_path into @out_path.
|
* Copies base directory of @in_path into @out_path.
|
||||||
* If in_path is a path without any slashes (relative current directory),
|
* If in_path is a path without any slashes (relative current directory),
|
||||||
* @out_path will get path "./".
|
* @out_path will get path "./".
|
||||||
|
*
|
||||||
|
* Hidden non-leaf function cost:
|
||||||
|
* - Calls strlcpy
|
||||||
|
* - Calls path_basedir()
|
||||||
**/
|
**/
|
||||||
void fill_pathname_basedir(char *out_path, const char *in_path, size_t size);
|
void fill_pathname_basedir(char *out_path, const char *in_path, size_t size);
|
||||||
|
|
||||||
void fill_pathname_basedir_noext(char *out_dir,
|
|
||||||
const char *in_path, size_t size);
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* fill_pathname_parent_dir_name:
|
* fill_pathname_parent_dir_name:
|
||||||
* @out_dir : output directory
|
* @out_dir : output directory
|
||||||
@ -333,7 +414,13 @@ void fill_pathname_basedir_noext(char *out_dir,
|
|||||||
*
|
*
|
||||||
* Copies only the parent directory name of @in_dir into @out_dir.
|
* Copies only the parent directory name of @in_dir into @out_dir.
|
||||||
* The two buffers must not overlap. Removes trailing '/'.
|
* The two buffers must not overlap. Removes trailing '/'.
|
||||||
* Returns true on success, false if a slash was not found in the path.
|
*
|
||||||
|
* Hidden non-leaf function cost:
|
||||||
|
* - Calls strdup
|
||||||
|
* - Calls find_last_slash() x times
|
||||||
|
* - Can call strlcpy
|
||||||
|
*
|
||||||
|
* @return true on success, false if a slash was not found in the path.
|
||||||
**/
|
**/
|
||||||
bool fill_pathname_parent_dir_name(char *out_dir,
|
bool fill_pathname_parent_dir_name(char *out_dir,
|
||||||
const char *in_dir, size_t size);
|
const char *in_dir, size_t size);
|
||||||
@ -347,6 +434,11 @@ bool fill_pathname_parent_dir_name(char *out_dir,
|
|||||||
* Copies parent directory of @in_dir into @out_dir.
|
* Copies parent directory of @in_dir into @out_dir.
|
||||||
* Assumes @in_dir is a directory. Keeps trailing '/'.
|
* Assumes @in_dir is a directory. Keeps trailing '/'.
|
||||||
* If the path was already at the root directory, @out_dir will be an empty string.
|
* If the path was already at the root directory, @out_dir will be an empty string.
|
||||||
|
*
|
||||||
|
* Hidden non-leaf function cost:
|
||||||
|
* - Can call strlcpy if (@out_dir != @in_dir)
|
||||||
|
* - Calls strlen if (@out_dir == @in_dir)
|
||||||
|
* - Calls path_parent_dir()
|
||||||
**/
|
**/
|
||||||
void fill_pathname_parent_dir(char *out_dir,
|
void fill_pathname_parent_dir(char *out_dir,
|
||||||
const char *in_dir, size_t size);
|
const char *in_dir, size_t size);
|
||||||
@ -374,30 +466,53 @@ void fill_pathname_resolve_relative(char *out_path, const char *in_refpath,
|
|||||||
* @size : size of output path
|
* @size : size of output path
|
||||||
*
|
*
|
||||||
* Joins a directory (@dir) and path (@path) together.
|
* Joins a directory (@dir) and path (@path) together.
|
||||||
* Makes sure not to get two consecutive slashes
|
* Makes sure not to get two consecutive slashes
|
||||||
* between directory and path.
|
* between directory and path.
|
||||||
|
*
|
||||||
|
* Hidden non-leaf function cost:
|
||||||
|
* - calls strlcpy
|
||||||
|
* - calls fill_pathname_slash()
|
||||||
|
* - calls strlcat
|
||||||
|
*
|
||||||
|
* Deprecated. Use fill_pathname_join_special() instead
|
||||||
|
* if you can ensure @dir != @out_path
|
||||||
|
*
|
||||||
|
* @return Length of the string copied into @out_path
|
||||||
**/
|
**/
|
||||||
size_t fill_pathname_join(char *out_path, const char *dir,
|
size_t fill_pathname_join(char *out_path, const char *dir,
|
||||||
const char *path, size_t size);
|
const char *path, size_t size);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* fill_pathname_join_special:
|
||||||
|
* @out_path : output path
|
||||||
|
* @dir : directory. Cannot be identical to @out_path
|
||||||
|
* @path : path
|
||||||
|
* @size : size of output path
|
||||||
|
*
|
||||||
|
*
|
||||||
|
* Specialized version of fill_pathname_join.
|
||||||
|
* Unlike fill_pathname_join(),
|
||||||
|
* @dir and @out_path CANNOT be identical.
|
||||||
|
*
|
||||||
|
* Joins a directory (@dir) and path (@path) together.
|
||||||
|
* Makes sure not to get two consecutive slashes
|
||||||
|
* between directory and path.
|
||||||
|
*
|
||||||
|
* Hidden non-leaf function cost:
|
||||||
|
* - calls strlcpy
|
||||||
|
* - calls find_last_slash()
|
||||||
|
* - calls strlcat
|
||||||
|
*
|
||||||
|
* @return Length of the string copied into @out_path
|
||||||
|
**/
|
||||||
|
size_t fill_pathname_join_special(char *out_path,
|
||||||
|
const char *dir, const char *path, size_t size);
|
||||||
|
|
||||||
size_t fill_pathname_join_special_ext(char *out_path,
|
size_t fill_pathname_join_special_ext(char *out_path,
|
||||||
const char *dir, const char *path,
|
const char *dir, const char *path,
|
||||||
const char *last, const char *ext,
|
const char *last, const char *ext,
|
||||||
size_t size);
|
size_t size);
|
||||||
|
|
||||||
size_t fill_pathname_join_concat_noext(char *out_path,
|
|
||||||
const char *dir, const char *path,
|
|
||||||
const char *concat,
|
|
||||||
size_t size);
|
|
||||||
|
|
||||||
size_t fill_pathname_join_concat(char *out_path,
|
|
||||||
const char *dir, const char *path,
|
|
||||||
const char *concat,
|
|
||||||
size_t size);
|
|
||||||
|
|
||||||
void fill_pathname_join_noext(char *out_path,
|
|
||||||
const char *dir, const char *path, size_t size);
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* fill_pathname_join_delim:
|
* fill_pathname_join_delim:
|
||||||
* @out_path : output path
|
* @out_path : output path
|
||||||
@ -408,45 +523,57 @@ void fill_pathname_join_noext(char *out_path,
|
|||||||
*
|
*
|
||||||
* Joins a directory (@dir) and path (@path) together
|
* Joins a directory (@dir) and path (@path) together
|
||||||
* using the given delimiter (@delim).
|
* using the given delimiter (@delim).
|
||||||
|
*
|
||||||
|
* Hidden non-leaf function cost:
|
||||||
|
* - can call strlen
|
||||||
|
* - can call strlcpy
|
||||||
|
* - can call strlcat
|
||||||
**/
|
**/
|
||||||
size_t fill_pathname_join_delim(char *out_path, const char *dir,
|
size_t fill_pathname_join_delim(char *out_path, const char *dir,
|
||||||
const char *path, const char delim, size_t size);
|
const char *path, const char delim, size_t size);
|
||||||
|
|
||||||
size_t fill_pathname_join_delim_concat(char *out_path, const char *dir,
|
size_t fill_pathname_expand_special(char *out_path,
|
||||||
const char *path, const char delim, const char *concat,
|
const char *in_path, size_t size);
|
||||||
size_t size);
|
|
||||||
|
size_t fill_pathname_abbreviate_special(char *out_path,
|
||||||
|
const char *in_path, size_t size);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* fill_short_pathname_representation:
|
* fill_pathname_abbreviated_or_relative:
|
||||||
* @out_rep : output representation
|
|
||||||
* @in_path : input path
|
|
||||||
* @size : size of output representation
|
|
||||||
*
|
*
|
||||||
* Generates a short representation of path. It should only
|
* Fills the supplied path with either the abbreviated path or
|
||||||
* be used for displaying the result; the output representation is not
|
* the relative path, which ever one has less depth / number of slashes
|
||||||
* binding in any meaningful way (for a normal path, this is the same as basename)
|
*
|
||||||
* In case of more complex URLs, this should cut everything except for
|
* If lengths of abbreviated and relative paths are the same,
|
||||||
* the main image file.
|
* the relative path will be used
|
||||||
|
* @in_path can be an absolute, relative or abbreviated path
|
||||||
*
|
*
|
||||||
* E.g.: "/path/to/game.img" -> game.img
|
* @return Length of the string copied into @out_path
|
||||||
* "/path/to/myarchive.7z#folder/to/game.img" -> game.img
|
**/
|
||||||
*/
|
size_t fill_pathname_abbreviated_or_relative(char *out_path,
|
||||||
size_t fill_short_pathname_representation(char* out_rep,
|
const char *in_refpath, const char *in_path, size_t size);
|
||||||
const char *in_path, size_t size);
|
|
||||||
|
|
||||||
void fill_short_pathname_representation_noext(char* out_rep,
|
|
||||||
const char *in_path, size_t size);
|
|
||||||
|
|
||||||
void fill_pathname_expand_special(char *out_path,
|
|
||||||
const char *in_path, size_t size);
|
|
||||||
|
|
||||||
void fill_pathname_abbreviate_special(char *out_path,
|
|
||||||
const char *in_path, size_t size);
|
|
||||||
|
|
||||||
void fill_pathname_abbreviated_or_relative(char *out_path, const char *in_refpath, const char *in_path, size_t size);
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* pathname_conform_slashes_to_os:
|
||||||
|
*
|
||||||
|
* @path : path
|
||||||
|
*
|
||||||
|
* Leaf function.
|
||||||
|
*
|
||||||
|
* Changes the slashes to the correct kind for the os
|
||||||
|
* So forward slash on linux and backslash on Windows
|
||||||
|
**/
|
||||||
void pathname_conform_slashes_to_os(char *path);
|
void pathname_conform_slashes_to_os(char *path);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* pathname_make_slashes_portable:
|
||||||
|
* @path : path
|
||||||
|
*
|
||||||
|
* Leaf function.
|
||||||
|
*
|
||||||
|
* Change all slashes to forward so they are more
|
||||||
|
* portable between Windows and Linux
|
||||||
|
**/
|
||||||
void pathname_make_slashes_portable(char *path);
|
void pathname_make_slashes_portable(char *path);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -464,8 +591,8 @@ void path_basedir_wrapper(char *path);
|
|||||||
*
|
*
|
||||||
* Checks if character (@c) is a slash.
|
* Checks if character (@c) is a slash.
|
||||||
*
|
*
|
||||||
* Returns: true (1) if character is a slash, otherwise false (0).
|
* @return true if character is a slash, otherwise false.
|
||||||
*/
|
**/
|
||||||
#ifdef _WIN32
|
#ifdef _WIN32
|
||||||
#define PATH_CHAR_IS_SLASH(c) (((c) == '/') || ((c) == '\\'))
|
#define PATH_CHAR_IS_SLASH(c) (((c) == '/') || ((c) == '\\'))
|
||||||
#else
|
#else
|
||||||
@ -477,8 +604,8 @@ void path_basedir_wrapper(char *path);
|
|||||||
*
|
*
|
||||||
* Gets the default slash separator.
|
* Gets the default slash separator.
|
||||||
*
|
*
|
||||||
* Returns: default slash separator.
|
* @return default slash separator.
|
||||||
*/
|
**/
|
||||||
#ifdef _WIN32
|
#ifdef _WIN32
|
||||||
#define PATH_DEFAULT_SLASH() "\\"
|
#define PATH_DEFAULT_SLASH() "\\"
|
||||||
#define PATH_DEFAULT_SLASH_C() '\\'
|
#define PATH_DEFAULT_SLASH_C() '\\'
|
||||||
@ -494,6 +621,11 @@ void path_basedir_wrapper(char *path);
|
|||||||
*
|
*
|
||||||
* Assumes path is a directory. Appends a slash
|
* Assumes path is a directory. Appends a slash
|
||||||
* if not already there.
|
* if not already there.
|
||||||
|
|
||||||
|
* Hidden non-leaf function cost:
|
||||||
|
* - calls find_last_slash()
|
||||||
|
* - can call strlcat once if it returns false
|
||||||
|
* - calls strlen
|
||||||
**/
|
**/
|
||||||
void fill_pathname_slash(char *path, size_t size);
|
void fill_pathname_slash(char *path, size_t size);
|
||||||
|
|
||||||
@ -509,7 +641,16 @@ void fill_pathname_home_dir(char *buf, size_t size);
|
|||||||
*
|
*
|
||||||
* Create directory on filesystem.
|
* Create directory on filesystem.
|
||||||
*
|
*
|
||||||
* Returns: true (1) if directory could be created, otherwise false (0).
|
* Recursive function.
|
||||||
|
*
|
||||||
|
* Hidden non-leaf function cost:
|
||||||
|
* - Calls strdup
|
||||||
|
* - Calls path_parent_dir()
|
||||||
|
* - Calls strcmp
|
||||||
|
* - Calls path_is_directory()
|
||||||
|
* - Calls path_mkdir()
|
||||||
|
*
|
||||||
|
* @return true if directory could be created, otherwise false.
|
||||||
**/
|
**/
|
||||||
bool path_mkdir(const char *dir);
|
bool path_mkdir(const char *dir);
|
||||||
|
|
||||||
@ -519,7 +660,7 @@ bool path_mkdir(const char *dir);
|
|||||||
*
|
*
|
||||||
* Checks if path is a directory.
|
* Checks if path is a directory.
|
||||||
*
|
*
|
||||||
* Returns: true (1) if path is a directory, otherwise false (0).
|
* @return true if path is a directory, otherwise false.
|
||||||
*/
|
*/
|
||||||
bool path_is_directory(const char *path);
|
bool path_is_directory(const char *path);
|
||||||
|
|
||||||
|
@ -1767,6 +1767,33 @@ enum retro_mod
|
|||||||
* (see enum retro_savestate_context)
|
* (see enum retro_savestate_context)
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
#define RETRO_ENVIRONMENT_GET_HW_RENDER_CONTEXT_NEGOTIATION_INTERFACE_SUPPORT (73 | RETRO_ENVIRONMENT_EXPERIMENTAL)
|
||||||
|
/* struct retro_hw_render_context_negotiation_interface * --
|
||||||
|
* Before calling SET_HW_RNEDER_CONTEXT_NEGOTIATION_INTERFACE, a core can query
|
||||||
|
* which version of the interface is supported.
|
||||||
|
*
|
||||||
|
* Frontend looks at interface_type and returns the maximum supported
|
||||||
|
* context negotiation interface version.
|
||||||
|
* If the interface_type is not supported or recognized by the frontend, a version of 0
|
||||||
|
* must be returned in interface_version and true is returned by frontend.
|
||||||
|
*
|
||||||
|
* If this environment call returns true with interface_version greater than 0,
|
||||||
|
* a core can always use a negotiation interface version larger than what the frontend returns, but only
|
||||||
|
* earlier versions of the interface will be used by the frontend.
|
||||||
|
* A frontend must not reject a negotiation interface version that is larger than
|
||||||
|
* what the frontend supports. Instead, the frontend will use the older entry points that it recognizes.
|
||||||
|
* If this is incompatible with a particular core's requirements, it can error out early.
|
||||||
|
*
|
||||||
|
* Backwards compatibility note:
|
||||||
|
* This environment call was introduced after Vulkan v1 context negotiation.
|
||||||
|
* If this environment call is not supported by frontend - i.e. the environment call returns false -
|
||||||
|
* only Vulkan v1 context negotiation is supported (if Vulkan HW rendering is supported at all).
|
||||||
|
* If a core uses Vulkan negotiation interface with version > 1, negotiation may fail unexpectedly.
|
||||||
|
* All future updates to the context negotiation interface implies that frontend must support
|
||||||
|
* this environment call to query support.
|
||||||
|
*/
|
||||||
|
|
||||||
|
|
||||||
/* VFS functionality */
|
/* VFS functionality */
|
||||||
|
|
||||||
/* File paths:
|
/* File paths:
|
||||||
|
@ -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).
|
* The following license statement only applies to this file (retro_common.h).
|
||||||
@ -34,4 +34,3 @@ in a public API, you may need this.
|
|||||||
#include <compat/msvc.h>
|
#include <compat/msvc.h>
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
@ -82,11 +82,8 @@ static INLINE uint64_t SWAP64(uint64_t val)
|
|||||||
#endif
|
#endif
|
||||||
|
|
||||||
#ifdef _MSC_VER
|
#ifdef _MSC_VER
|
||||||
#include <winsock2.h>
|
/* MSVC pre-defines macros depending on target arch */
|
||||||
#endif
|
#if defined (_M_IX86) || defined (_M_AMD64) || defined (_M_ARM) || defined (_M_ARM64)
|
||||||
|
|
||||||
#ifdef _MSC_VER
|
|
||||||
#if _M_IX86 || _M_AMD64 || _M_ARM || _M_ARM64
|
|
||||||
#define LSB_FIRST 1
|
#define LSB_FIRST 1
|
||||||
#elif _M_PPC
|
#elif _M_PPC
|
||||||
#define MSB_FIRST 1
|
#define MSB_FIRST 1
|
||||||
@ -263,7 +260,7 @@ static INLINE uint32_t load32be(const uint32_t *addr)
|
|||||||
*
|
*
|
||||||
* Convert unsigned 16-bit value from system to little-endian.
|
* Convert unsigned 16-bit value from system to little-endian.
|
||||||
*
|
*
|
||||||
* Returns: Little-endian represantation of val.
|
* Returns: Little-endian representation of val.
|
||||||
**/
|
**/
|
||||||
|
|
||||||
#define retro_cpu_to_le16(val) swap_if_big16(val)
|
#define retro_cpu_to_le16(val) swap_if_big16(val)
|
||||||
@ -274,7 +271,7 @@ static INLINE uint32_t load32be(const uint32_t *addr)
|
|||||||
*
|
*
|
||||||
* Convert unsigned 32-bit value from system to little-endian.
|
* Convert unsigned 32-bit value from system to little-endian.
|
||||||
*
|
*
|
||||||
* Returns: Little-endian represantation of val.
|
* Returns: Little-endian representation of val.
|
||||||
**/
|
**/
|
||||||
|
|
||||||
#define retro_cpu_to_le32(val) swap_if_big32(val)
|
#define retro_cpu_to_le32(val) swap_if_big32(val)
|
||||||
@ -285,7 +282,7 @@ static INLINE uint32_t load32be(const uint32_t *addr)
|
|||||||
*
|
*
|
||||||
* Convert unsigned 64-bit value from system to little-endian.
|
* Convert unsigned 64-bit value from system to little-endian.
|
||||||
*
|
*
|
||||||
* Returns: Little-endian represantation of val.
|
* Returns: Little-endian representation of val.
|
||||||
**/
|
**/
|
||||||
|
|
||||||
#define retro_cpu_to_le64(val) swap_if_big64(val)
|
#define retro_cpu_to_le64(val) swap_if_big64(val)
|
||||||
@ -296,7 +293,7 @@ static INLINE uint32_t load32be(const uint32_t *addr)
|
|||||||
*
|
*
|
||||||
* Convert unsigned 16-bit value from little-endian to native.
|
* Convert unsigned 16-bit value from little-endian to native.
|
||||||
*
|
*
|
||||||
* Returns: Native represantation of little-endian val.
|
* Returns: Native representation of little-endian val.
|
||||||
**/
|
**/
|
||||||
|
|
||||||
#define retro_le_to_cpu16(val) swap_if_big16(val)
|
#define retro_le_to_cpu16(val) swap_if_big16(val)
|
||||||
@ -307,7 +304,7 @@ static INLINE uint32_t load32be(const uint32_t *addr)
|
|||||||
*
|
*
|
||||||
* Convert unsigned 32-bit value from little-endian to native.
|
* Convert unsigned 32-bit value from little-endian to native.
|
||||||
*
|
*
|
||||||
* Returns: Native represantation of little-endian val.
|
* Returns: Native representation of little-endian val.
|
||||||
**/
|
**/
|
||||||
|
|
||||||
#define retro_le_to_cpu32(val) swap_if_big32(val)
|
#define retro_le_to_cpu32(val) swap_if_big32(val)
|
||||||
@ -318,7 +315,7 @@ static INLINE uint32_t load32be(const uint32_t *addr)
|
|||||||
*
|
*
|
||||||
* Convert unsigned 64-bit value from little-endian to native.
|
* Convert unsigned 64-bit value from little-endian to native.
|
||||||
*
|
*
|
||||||
* Returns: Native represantation of little-endian val.
|
* Returns: Native representation of little-endian val.
|
||||||
**/
|
**/
|
||||||
|
|
||||||
#define retro_le_to_cpu64(val) swap_if_big64(val)
|
#define retro_le_to_cpu64(val) swap_if_big64(val)
|
||||||
@ -329,7 +326,7 @@ static INLINE uint32_t load32be(const uint32_t *addr)
|
|||||||
*
|
*
|
||||||
* Convert unsigned 16-bit value from system to big-endian.
|
* Convert unsigned 16-bit value from system to big-endian.
|
||||||
*
|
*
|
||||||
* Returns: Big-endian represantation of val.
|
* Returns: Big-endian representation of val.
|
||||||
**/
|
**/
|
||||||
|
|
||||||
#define retro_cpu_to_be16(val) swap_if_little16(val)
|
#define retro_cpu_to_be16(val) swap_if_little16(val)
|
||||||
@ -340,7 +337,7 @@ static INLINE uint32_t load32be(const uint32_t *addr)
|
|||||||
*
|
*
|
||||||
* Convert unsigned 32-bit value from system to big-endian.
|
* Convert unsigned 32-bit value from system to big-endian.
|
||||||
*
|
*
|
||||||
* Returns: Big-endian represantation of val.
|
* Returns: Big-endian representation of val.
|
||||||
**/
|
**/
|
||||||
|
|
||||||
#define retro_cpu_to_be32(val) swap_if_little32(val)
|
#define retro_cpu_to_be32(val) swap_if_little32(val)
|
||||||
@ -351,7 +348,7 @@ static INLINE uint32_t load32be(const uint32_t *addr)
|
|||||||
*
|
*
|
||||||
* Convert unsigned 64-bit value from system to big-endian.
|
* Convert unsigned 64-bit value from system to big-endian.
|
||||||
*
|
*
|
||||||
* Returns: Big-endian represantation of val.
|
* Returns: Big-endian representation of val.
|
||||||
**/
|
**/
|
||||||
|
|
||||||
#define retro_cpu_to_be64(val) swap_if_little64(val)
|
#define retro_cpu_to_be64(val) swap_if_little64(val)
|
||||||
@ -362,7 +359,7 @@ static INLINE uint32_t load32be(const uint32_t *addr)
|
|||||||
*
|
*
|
||||||
* Convert unsigned 16-bit value from big-endian to native.
|
* Convert unsigned 16-bit value from big-endian to native.
|
||||||
*
|
*
|
||||||
* Returns: Native represantation of big-endian val.
|
* Returns: Native representation of big-endian val.
|
||||||
**/
|
**/
|
||||||
|
|
||||||
#define retro_be_to_cpu16(val) swap_if_little16(val)
|
#define retro_be_to_cpu16(val) swap_if_little16(val)
|
||||||
@ -373,7 +370,7 @@ static INLINE uint32_t load32be(const uint32_t *addr)
|
|||||||
*
|
*
|
||||||
* Convert unsigned 32-bit value from big-endian to native.
|
* Convert unsigned 32-bit value from big-endian to native.
|
||||||
*
|
*
|
||||||
* Returns: Native represantation of big-endian val.
|
* Returns: Native representation of big-endian val.
|
||||||
**/
|
**/
|
||||||
|
|
||||||
#define retro_be_to_cpu32(val) swap_if_little32(val)
|
#define retro_be_to_cpu32(val) swap_if_little32(val)
|
||||||
@ -384,7 +381,7 @@ static INLINE uint32_t load32be(const uint32_t *addr)
|
|||||||
*
|
*
|
||||||
* Convert unsigned 64-bit value from big-endian to native.
|
* Convert unsigned 64-bit value from big-endian to native.
|
||||||
*
|
*
|
||||||
* Returns: Native represantation of big-endian val.
|
* Returns: Native representation of big-endian val.
|
||||||
**/
|
**/
|
||||||
|
|
||||||
#define retro_be_to_cpu64(val) swap_if_little64(val)
|
#define retro_be_to_cpu64(val) swap_if_little64(val)
|
||||||
@ -428,7 +425,7 @@ typedef struct retro_unaligned_uint64_s retro_unaligned_uint64_t;
|
|||||||
*
|
*
|
||||||
* Convert unsigned unaligned 16-bit value from big-endian to native.
|
* Convert unsigned unaligned 16-bit value from big-endian to native.
|
||||||
*
|
*
|
||||||
* Returns: Native represantation of big-endian val.
|
* Returns: Native representation of big-endian val.
|
||||||
**/
|
**/
|
||||||
|
|
||||||
static INLINE uint16_t retro_get_unaligned_16be(void *addr) {
|
static INLINE uint16_t retro_get_unaligned_16be(void *addr) {
|
||||||
@ -441,7 +438,7 @@ static INLINE uint16_t retro_get_unaligned_16be(void *addr) {
|
|||||||
*
|
*
|
||||||
* Convert unsigned unaligned 32-bit value from big-endian to native.
|
* Convert unsigned unaligned 32-bit value from big-endian to native.
|
||||||
*
|
*
|
||||||
* Returns: Native represantation of big-endian val.
|
* Returns: Native representation of big-endian val.
|
||||||
**/
|
**/
|
||||||
|
|
||||||
static INLINE uint32_t retro_get_unaligned_32be(void *addr) {
|
static INLINE uint32_t retro_get_unaligned_32be(void *addr) {
|
||||||
@ -454,7 +451,7 @@ static INLINE uint32_t retro_get_unaligned_32be(void *addr) {
|
|||||||
*
|
*
|
||||||
* Convert unsigned unaligned 64-bit value from big-endian to native.
|
* Convert unsigned unaligned 64-bit value from big-endian to native.
|
||||||
*
|
*
|
||||||
* Returns: Native represantation of big-endian val.
|
* Returns: Native representation of big-endian val.
|
||||||
**/
|
**/
|
||||||
|
|
||||||
static INLINE uint64_t retro_get_unaligned_64be(void *addr) {
|
static INLINE uint64_t retro_get_unaligned_64be(void *addr) {
|
||||||
@ -467,7 +464,7 @@ static INLINE uint64_t retro_get_unaligned_64be(void *addr) {
|
|||||||
*
|
*
|
||||||
* Convert unsigned unaligned 16-bit value from little-endian to native.
|
* Convert unsigned unaligned 16-bit value from little-endian to native.
|
||||||
*
|
*
|
||||||
* Returns: Native represantation of little-endian val.
|
* Returns: Native representation of little-endian val.
|
||||||
**/
|
**/
|
||||||
|
|
||||||
static INLINE uint16_t retro_get_unaligned_16le(void *addr) {
|
static INLINE uint16_t retro_get_unaligned_16le(void *addr) {
|
||||||
@ -480,7 +477,7 @@ static INLINE uint16_t retro_get_unaligned_16le(void *addr) {
|
|||||||
*
|
*
|
||||||
* Convert unsigned unaligned 32-bit value from little-endian to native.
|
* Convert unsigned unaligned 32-bit value from little-endian to native.
|
||||||
*
|
*
|
||||||
* Returns: Native represantation of little-endian val.
|
* Returns: Native representation of little-endian val.
|
||||||
**/
|
**/
|
||||||
|
|
||||||
static INLINE uint32_t retro_get_unaligned_32le(void *addr) {
|
static INLINE uint32_t retro_get_unaligned_32le(void *addr) {
|
||||||
@ -493,7 +490,7 @@ static INLINE uint32_t retro_get_unaligned_32le(void *addr) {
|
|||||||
*
|
*
|
||||||
* Convert unsigned unaligned 64-bit value from little-endian to native.
|
* Convert unsigned unaligned 64-bit value from little-endian to native.
|
||||||
*
|
*
|
||||||
* Returns: Native represantation of little-endian val.
|
* Returns: Native representation of little-endian val.
|
||||||
**/
|
**/
|
||||||
|
|
||||||
static INLINE uint64_t retro_get_unaligned_64le(void *addr) {
|
static INLINE uint64_t retro_get_unaligned_64le(void *addr) {
|
||||||
|
@ -74,14 +74,29 @@ static INLINE bool bits_any_set(uint32_t* ptr, uint32_t count)
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static INLINE bool bits_any_different(uint32_t *a, uint32_t *b, uint32_t count)
|
||||||
|
{
|
||||||
|
uint32_t i;
|
||||||
|
for (i = 0; i < count; i++)
|
||||||
|
{
|
||||||
|
if (a[i] != b[i])
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
#ifndef PATH_MAX_LENGTH
|
#ifndef PATH_MAX_LENGTH
|
||||||
#if defined(_XBOX1) || defined(_3DS) || defined(PSP) || defined(PS2) || defined(GEKKO)|| defined(WIIU) || defined(ORBIS) || defined(__PSL1GHT__) || defined(__PS3__)
|
#if defined(_XBOX1) || defined(_3DS) || defined(PSP) || defined(PS2) || defined(GEKKO)|| defined(WIIU) || defined(__PSL1GHT__) || defined(__PS3__)
|
||||||
#define PATH_MAX_LENGTH 512
|
#define PATH_MAX_LENGTH 512
|
||||||
#else
|
#else
|
||||||
#define PATH_MAX_LENGTH 4096
|
#define PATH_MAX_LENGTH 4096
|
||||||
#endif
|
#endif
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
#ifndef NAME_MAX_LENGTH
|
||||||
|
#define NAME_MAX_LENGTH 256
|
||||||
|
#endif
|
||||||
|
|
||||||
#ifndef MAX
|
#ifndef MAX
|
||||||
#define MAX(a, b) ((a) > (b) ? (a) : (b))
|
#define MAX(a, b) ((a) > (b) ? (a) : (b))
|
||||||
#endif
|
#endif
|
||||||
|
112
libretro/libretro-common/include/retro_timers.h
Normal file
112
libretro/libretro-common/include/retro_timers.h
Normal file
@ -0,0 +1,112 @@
|
|||||||
|
/* Copyright (C) 2010-2020 The RetroArch team
|
||||||
|
*
|
||||||
|
* ---------------------------------------------------------------------------------------
|
||||||
|
* The following license statement only applies to this file (retro_timers.h).
|
||||||
|
* ---------------------------------------------------------------------------------------
|
||||||
|
*
|
||||||
|
* Permission is hereby granted, free of charge,
|
||||||
|
* to any person obtaining a copy of this software and associated documentation files (the "Software"),
|
||||||
|
* to deal in the Software without restriction, including without limitation the rights to
|
||||||
|
* use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software,
|
||||||
|
* and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
|
||||||
|
*
|
||||||
|
* The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
|
||||||
|
*
|
||||||
|
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
|
||||||
|
* INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
|
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
|
||||||
|
* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
|
||||||
|
* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||||
|
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef __LIBRETRO_COMMON_TIMERS_H
|
||||||
|
#define __LIBRETRO_COMMON_TIMERS_H
|
||||||
|
|
||||||
|
#include <stdint.h>
|
||||||
|
|
||||||
|
#if defined(XENON)
|
||||||
|
#include <time/time.h>
|
||||||
|
#elif !defined(__PSL1GHT__) && defined(__PS3__)
|
||||||
|
#include <sys/timer.h>
|
||||||
|
#elif defined(GEKKO) || defined(__PSL1GHT__) || defined(__QNX__)
|
||||||
|
#include <unistd.h>
|
||||||
|
#elif defined(WIIU)
|
||||||
|
#include <wiiu/os/thread.h>
|
||||||
|
#elif defined(PSP)
|
||||||
|
#include <pspthreadman.h>
|
||||||
|
#elif defined(VITA)
|
||||||
|
#include <psp2/kernel/threadmgr.h>
|
||||||
|
#elif defined(_3DS)
|
||||||
|
#include <3ds.h>
|
||||||
|
#else
|
||||||
|
#include <time.h>
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if defined(_WIN32) && !defined(_XBOX)
|
||||||
|
#define WIN32_LEAN_AND_MEAN
|
||||||
|
#include <windows.h>
|
||||||
|
#elif defined(_WIN32) && defined(_XBOX)
|
||||||
|
#include <Xtl.h>
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#include <limits.h>
|
||||||
|
|
||||||
|
#ifdef _MSC_VER
|
||||||
|
#include <compat/msvc.h>
|
||||||
|
#endif
|
||||||
|
#include <retro_inline.h>
|
||||||
|
|
||||||
|
#ifdef DJGPP
|
||||||
|
#define timespec timeval
|
||||||
|
#define tv_nsec tv_usec
|
||||||
|
#include <unistd.h>
|
||||||
|
|
||||||
|
extern int nanosleep(const struct timespec *rqtp, struct timespec *rmtp);
|
||||||
|
|
||||||
|
static int nanosleepDOS(const struct timespec *rqtp, struct timespec *rmtp)
|
||||||
|
{
|
||||||
|
usleep(1000000L * rqtp->tv_sec + rqtp->tv_nsec / 1000);
|
||||||
|
|
||||||
|
if (rmtp)
|
||||||
|
rmtp->tv_sec = rmtp->tv_nsec=0;
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
#define nanosleep nanosleepDOS
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/**
|
||||||
|
* retro_sleep:
|
||||||
|
* @msec : amount in milliseconds to sleep
|
||||||
|
*
|
||||||
|
* Sleeps for a specified amount of milliseconds (@msec).
|
||||||
|
**/
|
||||||
|
#if defined(VITA)
|
||||||
|
#define retro_sleep(msec) (sceKernelDelayThread(1000 * (msec)))
|
||||||
|
#elif defined(_3DS)
|
||||||
|
#define retro_sleep(msec) (svcSleepThread(1000000 * (s64)(msec)))
|
||||||
|
#elif defined(__WINRT__) || defined(WINAPI_FAMILY) && WINAPI_FAMILY == WINAPI_FAMILY_PHONE_APP
|
||||||
|
#define retro_sleep(msec) (SleepEx((msec), FALSE))
|
||||||
|
#elif defined(_WIN32)
|
||||||
|
#define retro_sleep(msec) (Sleep((msec)))
|
||||||
|
#elif defined(XENON)
|
||||||
|
#define retro_sleep(msec) (udelay(1000 * (msec)))
|
||||||
|
#elif !defined(__PSL1GHT__) && defined(__PS3__)
|
||||||
|
#define retro_sleep(msec) (sys_timer_usleep(1000 * (msec)))
|
||||||
|
#elif defined(GEKKO) || defined(__PSL1GHT__) || defined(__QNX__)
|
||||||
|
#define retro_sleep(msec) (usleep(1000 * (msec)))
|
||||||
|
#elif defined(WIIU)
|
||||||
|
#define retro_sleep(msec) (OSSleepTicks(ms_to_ticks((msec))))
|
||||||
|
#else
|
||||||
|
#define retro_sleep(msec) \
|
||||||
|
{ \
|
||||||
|
struct timespec tv; \
|
||||||
|
tv.tv_sec = msec / 1000; \
|
||||||
|
tv.tv_nsec = (msec % 1000) * 1000000; \
|
||||||
|
nanosleep(&tv, NULL); \
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#endif
|
@ -59,7 +59,7 @@ int64_t filestream_truncate(RFILE *stream, int64_t length);
|
|||||||
* @bufsize : optional buffer size (-1 or 0 to use default)
|
* @bufsize : optional buffer size (-1 or 0 to use default)
|
||||||
*
|
*
|
||||||
* Opens a file for reading or writing, depending on the requested mode.
|
* Opens a file for reading or writing, depending on the requested mode.
|
||||||
* Returns a pointer to an RFILE if opened successfully, otherwise NULL.
|
* @return A pointer to an RFILE if opened successfully, otherwise NULL.
|
||||||
**/
|
**/
|
||||||
RFILE* filestream_open(const char *path, unsigned mode, unsigned hints);
|
RFILE* filestream_open(const char *path, unsigned mode, unsigned hints);
|
||||||
|
|
||||||
@ -75,6 +75,17 @@ void filestream_rewind(RFILE *stream);
|
|||||||
|
|
||||||
int filestream_close(RFILE *stream);
|
int filestream_close(RFILE *stream);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* filestream_read_file:
|
||||||
|
* @path : path to file.
|
||||||
|
* @buf : buffer to allocate and read the contents of the
|
||||||
|
* file into. Needs to be freed manually.
|
||||||
|
* @len : optional output integer containing bytes read.
|
||||||
|
*
|
||||||
|
* Read the contents of a file into @buf.
|
||||||
|
*
|
||||||
|
* @return Non-zero on success.
|
||||||
|
*/
|
||||||
int64_t filestream_read_file(const char *path, void **buf, int64_t *len);
|
int64_t filestream_read_file(const char *path, void **buf, int64_t *len);
|
||||||
|
|
||||||
char* filestream_gets(RFILE *stream, char *s, size_t len);
|
char* filestream_gets(RFILE *stream, char *s, size_t len);
|
||||||
@ -83,8 +94,20 @@ int filestream_getc(RFILE *stream);
|
|||||||
|
|
||||||
int filestream_vscanf(RFILE *stream, const char* format, va_list *args);
|
int filestream_vscanf(RFILE *stream, const char* format, va_list *args);
|
||||||
|
|
||||||
|
int filestream_scanf(RFILE *stream, const char* format, ...);
|
||||||
|
|
||||||
int filestream_eof(RFILE *stream);
|
int filestream_eof(RFILE *stream);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* filestream_write_file:
|
||||||
|
* @path : path to file.
|
||||||
|
* @data : contents to write to the file.
|
||||||
|
* @size : size of the contents.
|
||||||
|
*
|
||||||
|
* Writes data to a file.
|
||||||
|
*
|
||||||
|
* @return true on success, otherwise false.
|
||||||
|
**/
|
||||||
bool filestream_write_file(const char *path, const void *data, int64_t size);
|
bool filestream_write_file(const char *path, const void *data, int64_t size);
|
||||||
|
|
||||||
int filestream_putc(RFILE *stream, int c);
|
int filestream_putc(RFILE *stream, int c);
|
||||||
@ -105,7 +128,11 @@ const char* filestream_get_path(RFILE *stream);
|
|||||||
|
|
||||||
bool filestream_exists(const char *path);
|
bool filestream_exists(const char *path);
|
||||||
|
|
||||||
/* Returned pointer must be freed by the caller. */
|
/**
|
||||||
|
* filestream_getline:
|
||||||
|
*
|
||||||
|
* Returned pointer must be freed by the caller.
|
||||||
|
**/
|
||||||
char* filestream_getline(RFILE *stream);
|
char* filestream_getline(RFILE *stream);
|
||||||
|
|
||||||
libretro_vfs_implementation_file* filestream_get_vfs_handle(RFILE *stream);
|
libretro_vfs_implementation_file* filestream_get_vfs_handle(RFILE *stream);
|
||||||
|
@ -92,16 +92,20 @@ static INLINE bool string_ends_with_size(const char *str, const char *suffix,
|
|||||||
|
|
||||||
static INLINE bool string_ends_with(const char *str, const char *suffix)
|
static INLINE bool string_ends_with(const char *str, const char *suffix)
|
||||||
{
|
{
|
||||||
if (!str || !suffix)
|
return str && suffix && string_ends_with_size(str, suffix, strlen(str), strlen(suffix));
|
||||||
return false;
|
|
||||||
return string_ends_with_size(str, suffix, strlen(str), strlen(suffix));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Returns the length of 'str' (c.f. strlen()), but only
|
/**
|
||||||
|
* strlen_size:
|
||||||
|
*
|
||||||
|
* Leaf function.
|
||||||
|
*
|
||||||
|
* @return the length of 'str' (c.f. strlen()), but only
|
||||||
* checks the first 'size' characters
|
* checks the first 'size' characters
|
||||||
* - If 'str' is NULL, returns 0
|
* - If 'str' is NULL, returns 0
|
||||||
* - If 'str' is not NULL and no '\0' character is found
|
* - If 'str' is not NULL and no '\0' character is found
|
||||||
* in the first 'size' characters, returns 'size' */
|
* in the first 'size' characters, returns 'size'
|
||||||
|
**/
|
||||||
static INLINE size_t strlen_size(const char *str, size_t size)
|
static INLINE size_t strlen_size(const char *str, size_t size)
|
||||||
{
|
{
|
||||||
size_t i = 0;
|
size_t i = 0;
|
||||||
@ -130,25 +134,68 @@ static INLINE bool string_is_equal_case_insensitive(const char *a,
|
|||||||
return (result == 0);
|
return (result == 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static INLINE bool string_starts_with_case_insensitive(const char *str,
|
||||||
|
const char *prefix)
|
||||||
|
{
|
||||||
|
int result = 0;
|
||||||
|
const unsigned char *p1 = (const unsigned char*)str;
|
||||||
|
const unsigned char *p2 = (const unsigned char*)prefix;
|
||||||
|
|
||||||
|
if (!str || !prefix)
|
||||||
|
return false;
|
||||||
|
if (p1 == p2)
|
||||||
|
return true;
|
||||||
|
|
||||||
|
while ((result = tolower (*p1++) - tolower (*p2)) == 0)
|
||||||
|
if (*p2++ == '\0')
|
||||||
|
break;
|
||||||
|
|
||||||
|
return (result == 0 || *p2 == '\0');
|
||||||
|
}
|
||||||
|
|
||||||
char *string_to_upper(char *s);
|
char *string_to_upper(char *s);
|
||||||
|
|
||||||
char *string_to_lower(char *s);
|
char *string_to_lower(char *s);
|
||||||
|
|
||||||
char *string_ucwords(char *s);
|
char *string_ucwords(char *s);
|
||||||
|
|
||||||
char *string_replace_substring(const char *in, const char *pattern,
|
char *string_replace_substring(const char *in,
|
||||||
const char *by);
|
const char *pattern, size_t pattern_len,
|
||||||
|
const char *replacement, size_t replacement_len);
|
||||||
|
|
||||||
/* Remove leading whitespaces */
|
/**
|
||||||
|
* string_trim_whitespace_left:
|
||||||
|
*
|
||||||
|
* Remove leading whitespaces
|
||||||
|
**/
|
||||||
char *string_trim_whitespace_left(char *const s);
|
char *string_trim_whitespace_left(char *const s);
|
||||||
|
|
||||||
/* Remove trailing whitespaces */
|
/**
|
||||||
|
* string_trim_whitespace_right:
|
||||||
|
*
|
||||||
|
* Remove trailing whitespaces
|
||||||
|
**/
|
||||||
char *string_trim_whitespace_right(char *const s);
|
char *string_trim_whitespace_right(char *const s);
|
||||||
|
|
||||||
/* Remove leading and trailing whitespaces */
|
/**
|
||||||
|
* string_trim_whitespace:
|
||||||
|
*
|
||||||
|
* Remove leading and trailing whitespaces
|
||||||
|
**/
|
||||||
char *string_trim_whitespace(char *const s);
|
char *string_trim_whitespace(char *const s);
|
||||||
|
|
||||||
/*
|
/**
|
||||||
|
* word_wrap:
|
||||||
|
* @dst : pointer to destination buffer.
|
||||||
|
* @dst_size : size of destination buffer.
|
||||||
|
* @src : pointer to input string.
|
||||||
|
* @src_len : length of @src
|
||||||
|
* @line_width : max number of characters per line.
|
||||||
|
* @wideglyph_width : not used, but is necessary to keep
|
||||||
|
* compatibility with word_wrap_wideglyph().
|
||||||
|
* @max_lines : max lines of destination string.
|
||||||
|
* 0 means no limit.
|
||||||
|
*
|
||||||
* Wraps string specified by 'src' to destination buffer
|
* Wraps string specified by 'src' to destination buffer
|
||||||
* specified by 'dst' and 'dst_size'.
|
* specified by 'dst' and 'dst_size'.
|
||||||
* This function assumes that all glyphs in the string
|
* This function assumes that all glyphs in the string
|
||||||
@ -156,58 +203,57 @@ char *string_trim_whitespace(char *const s);
|
|||||||
* regular Latin characters - i.e. it will not wrap
|
* regular Latin characters - i.e. it will not wrap
|
||||||
* correctly any text containing so-called 'wide' Unicode
|
* correctly any text containing so-called 'wide' Unicode
|
||||||
* characters (e.g. CJK languages, emojis, etc.).
|
* characters (e.g. CJK languages, emojis, etc.).
|
||||||
*
|
**/
|
||||||
* @param dst pointer to destination buffer.
|
void word_wrap(char *dst, size_t dst_size, const char *src, size_t src_len,
|
||||||
* @param dst_size size of destination buffer.
|
|
||||||
* @param src pointer to input string.
|
|
||||||
* @param line_width max number of characters per line.
|
|
||||||
* @param wideglyph_width not used, but is necessary to keep
|
|
||||||
* compatibility with word_wrap_wideglyph().
|
|
||||||
* @param max_lines max lines of destination string.
|
|
||||||
* 0 means no limit.
|
|
||||||
*/
|
|
||||||
void word_wrap(char *dst, size_t dst_size, const char *src,
|
|
||||||
int line_width, int wideglyph_width, unsigned max_lines);
|
int line_width, int wideglyph_width, unsigned max_lines);
|
||||||
|
|
||||||
/*
|
/**
|
||||||
* Wraps string specified by 'src' to destination buffer
|
* word_wrap_wideglyph:
|
||||||
* specified by 'dst' and 'dst_size'.
|
* @dst : pointer to destination buffer.
|
||||||
|
* @dst_size : size of destination buffer.
|
||||||
|
* @src : pointer to input string.
|
||||||
|
* @src_len : length of @src
|
||||||
|
* @line_width : max number of characters per line.
|
||||||
|
* @wideglyph_width : effective width of 'wide' Unicode glyphs.
|
||||||
|
* the value here is normalised relative to the
|
||||||
|
* typical on-screen pixel width of a regular
|
||||||
|
* Latin character:
|
||||||
|
* - a regular Latin character is defined to
|
||||||
|
* have an effective width of 100
|
||||||
|
* - wideglyph_width = 100 * (wide_character_pixel_width / latin_character_pixel_width)
|
||||||
|
* - e.g. if 'wide' Unicode characters in 'src'
|
||||||
|
* have an on-screen pixel width twice that of
|
||||||
|
* regular Latin characters, wideglyph_width
|
||||||
|
* would be 200
|
||||||
|
* @max_lines : max lines of destination string.
|
||||||
|
* 0 means no limit.
|
||||||
|
*
|
||||||
|
* Wraps string specified by @src to destination buffer
|
||||||
|
* specified by @dst and @dst_size.
|
||||||
* This function assumes that all glyphs in the string
|
* This function assumes that all glyphs in the string
|
||||||
* are:
|
* are:
|
||||||
* - EITHER 'non-wide' Unicode glyphs, with an on-screen
|
* - EITHER 'non-wide' Unicode glyphs, with an on-screen
|
||||||
* pixel width similar to that of regular Latin characters
|
* pixel width similar to that of regular Latin characters
|
||||||
* - OR 'wide' Unicode glyphs (e.g. CJK languages, emojis, etc.)
|
* - OR 'wide' Unicode glyphs (e.g. CJK languages, emojis, etc.)
|
||||||
* with an on-screen pixel width defined by 'wideglyph_width'
|
* with an on-screen pixel width defined by @wideglyph_width
|
||||||
* Note that wrapping may occur in inappropriate locations
|
* Note that wrapping may occur in inappropriate locations
|
||||||
* if 'src' string contains 'wide' Unicode characters whose
|
* if @src string contains 'wide' Unicode characters whose
|
||||||
* on-screen pixel width deviates greatly from the set
|
* on-screen pixel width deviates greatly from the set
|
||||||
* 'wideglyph_width' value.
|
* @wideglyph_width value.
|
||||||
*
|
**/
|
||||||
* @param dst pointer to destination buffer.
|
void word_wrap_wideglyph(
|
||||||
* @param dst_size size of destination buffer.
|
char *dst, size_t dst_size,
|
||||||
* @param src pointer to input string.
|
const char *src, size_t src_len,
|
||||||
* @param line_width max number of characters per line.
|
int line_width, int wideglyph_width,
|
||||||
* @param wideglyph_width effective width of 'wide' Unicode glyphs.
|
unsigned max_lines);
|
||||||
* the value here is normalised relative to the
|
|
||||||
* typical on-screen pixel width of a regular
|
|
||||||
* Latin character:
|
|
||||||
* - a regular Latin character is defined to
|
|
||||||
* have an effective width of 100
|
|
||||||
* - wideglyph_width = 100 * (wide_character_pixel_width / latin_character_pixel_width)
|
|
||||||
* - e.g. if 'wide' Unicode characters in 'src'
|
|
||||||
* have an on-screen pixel width twice that of
|
|
||||||
* regular Latin characters, wideglyph_width
|
|
||||||
* would be 200
|
|
||||||
* @param max_lines max lines of destination string.
|
|
||||||
* 0 means no limit.
|
|
||||||
*/
|
|
||||||
void word_wrap_wideglyph(char *dst, size_t dst_size, const char *src,
|
|
||||||
int line_width, int wideglyph_width, unsigned max_lines);
|
|
||||||
|
|
||||||
/* Splits string into tokens seperated by 'delim'
|
/**
|
||||||
|
* string_tokenize:
|
||||||
|
*
|
||||||
|
* Splits string into tokens seperated by @delim
|
||||||
* > Returned token string must be free()'d
|
* > Returned token string must be free()'d
|
||||||
* > Returns NULL if token is not found
|
* > Returns NULL if token is not found
|
||||||
* > After each call, 'str' is set to the position after the
|
* > After each call, @str is set to the position after the
|
||||||
* last found token
|
* last found token
|
||||||
* > Tokens *include* empty strings
|
* > Tokens *include* empty strings
|
||||||
* Usage example:
|
* Usage example:
|
||||||
@ -220,29 +266,120 @@ void word_wrap_wideglyph(char *dst, size_t dst_size, const char *src,
|
|||||||
* free(token);
|
* free(token);
|
||||||
* token = NULL;
|
* token = NULL;
|
||||||
* }
|
* }
|
||||||
*/
|
**/
|
||||||
char* string_tokenize(char **str, const char *delim);
|
char* string_tokenize(char **str, const char *delim);
|
||||||
|
|
||||||
/* Removes every instance of character 'c' from 'str' */
|
/**
|
||||||
|
* string_remove_all_chars:
|
||||||
|
* @str : input string (must be non-NULL, otherwise UB)
|
||||||
|
*
|
||||||
|
* Leaf function.
|
||||||
|
*
|
||||||
|
* Removes every instance of character @c from @str
|
||||||
|
**/
|
||||||
void string_remove_all_chars(char *str, char c);
|
void string_remove_all_chars(char *str, char c);
|
||||||
|
|
||||||
/* Replaces every instance of character 'find' in 'str'
|
/**
|
||||||
* with character 'replace' */
|
* string_replace_all_chars:
|
||||||
|
* @str : input string (must be non-NULL, otherwise UB)
|
||||||
|
* @find : character to find
|
||||||
|
* @replace : character to replace @find with
|
||||||
|
*
|
||||||
|
* Hidden non-leaf function cost:
|
||||||
|
* - Calls strchr (in a loop)
|
||||||
|
*
|
||||||
|
* Replaces every instance of character @find in @str
|
||||||
|
* with character @replace
|
||||||
|
**/
|
||||||
void string_replace_all_chars(char *str, char find, char replace);
|
void string_replace_all_chars(char *str, char find, char replace);
|
||||||
|
|
||||||
/* Converts string to unsigned integer.
|
/**
|
||||||
* Returns 0 if string is invalid */
|
* string_to_unsigned:
|
||||||
|
* @str : input string
|
||||||
|
*
|
||||||
|
* Converts string to unsigned integer.
|
||||||
|
*
|
||||||
|
* @return 0 if string is invalid, otherwise > 0
|
||||||
|
**/
|
||||||
unsigned string_to_unsigned(const char *str);
|
unsigned string_to_unsigned(const char *str);
|
||||||
|
|
||||||
/* Converts hexadecimal string to unsigned integer.
|
/**
|
||||||
|
* string_hex_to_unsigned:
|
||||||
|
* @str : input string (must be non-NULL, otherwise UB)
|
||||||
|
*
|
||||||
|
* Converts hexadecimal string to unsigned integer.
|
||||||
* Handles optional leading '0x'.
|
* Handles optional leading '0x'.
|
||||||
* Returns 0 if string is invalid */
|
*
|
||||||
|
* @return 0 if string is invalid, otherwise > 0
|
||||||
|
**/
|
||||||
unsigned string_hex_to_unsigned(const char *str);
|
unsigned string_hex_to_unsigned(const char *str);
|
||||||
|
|
||||||
char *string_init(const char *src);
|
char *string_init(const char *src);
|
||||||
|
|
||||||
void string_set(char **string, const char *src);
|
void string_set(char **string, const char *src);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* string_count_occurrences_single_character:
|
||||||
|
*
|
||||||
|
* Leaf function.
|
||||||
|
*
|
||||||
|
* Get the total number of occurrences of character @c in @str.
|
||||||
|
*
|
||||||
|
* @return Total number of occurrences of character @c
|
||||||
|
*/
|
||||||
|
int string_count_occurrences_single_character(const char *str, char c);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* string_replace_whitespace_with_single_character:
|
||||||
|
*
|
||||||
|
* Leaf function.
|
||||||
|
*
|
||||||
|
* Replaces all spaces with given character @c.
|
||||||
|
**/
|
||||||
|
void string_replace_whitespace_with_single_character(char *str, char c);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* string_replace_multi_space_with_single_space:
|
||||||
|
*
|
||||||
|
* Leaf function.
|
||||||
|
*
|
||||||
|
* Replaces multiple spaces with a single space in a string.
|
||||||
|
**/
|
||||||
|
void string_replace_multi_space_with_single_space(char *str);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* string_remove_all_whitespace:
|
||||||
|
*
|
||||||
|
* Leaf function.
|
||||||
|
*
|
||||||
|
* Remove all spaces from the given string.
|
||||||
|
**/
|
||||||
|
void string_remove_all_whitespace(char *str_trimmed, const char *str);
|
||||||
|
|
||||||
|
/* Retrieve the last occurance of the given character in a string. */
|
||||||
|
int string_index_last_occurance(const char *str, char c);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* string_find_index_substring_string:
|
||||||
|
* @str : input string (must be non-NULL, otherwise UB)
|
||||||
|
* @substr : substring to find in @str
|
||||||
|
*
|
||||||
|
* Hidden non-leaf function cost:
|
||||||
|
* - Calls strstr
|
||||||
|
*
|
||||||
|
* Find the position of substring @substr in string @str.
|
||||||
|
**/
|
||||||
|
int string_find_index_substring_string(const char *str, const char *substr);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* string_copy_only_ascii:
|
||||||
|
*
|
||||||
|
* Leaf function.
|
||||||
|
*
|
||||||
|
* Strips non-ASCII characters from a string.
|
||||||
|
**/
|
||||||
|
void string_copy_only_ascii(char *str_stripped, const char *str);
|
||||||
|
|
||||||
extern const unsigned char lr_char_props[256];
|
extern const unsigned char lr_char_props[256];
|
||||||
|
|
||||||
RETRO_END_DECLS
|
RETRO_END_DECLS
|
||||||
|
@ -62,7 +62,7 @@ enum vfs_scheme
|
|||||||
VFS_SCHEME_CDROM
|
VFS_SCHEME_CDROM
|
||||||
};
|
};
|
||||||
|
|
||||||
#ifndef __WINRT__
|
#if !(defined(__WINRT__) && defined(__cplusplus_winrt))
|
||||||
#ifdef VFS_FRONTEND
|
#ifdef VFS_FRONTEND
|
||||||
struct retro_vfs_file_handle
|
struct retro_vfs_file_handle
|
||||||
#else
|
#else
|
||||||
|
@ -71,6 +71,12 @@ bool retro_vfs_dirent_is_dir_impl(libretro_vfs_implementation_dir *dirstream);
|
|||||||
|
|
||||||
int retro_vfs_closedir_impl(libretro_vfs_implementation_dir *dirstream);
|
int retro_vfs_closedir_impl(libretro_vfs_implementation_dir *dirstream);
|
||||||
|
|
||||||
|
#ifdef __WINRT__
|
||||||
|
|
||||||
|
void uwp_set_acl(const wchar_t* path, const wchar_t* AccessString);
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
||||||
RETRO_END_DECLS
|
RETRO_END_DECLS
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
@ -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.c).
|
* The following license statement only applies to this file (memmap.c).
|
||||||
@ -21,6 +21,7 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
#include <stdint.h>
|
#include <stdint.h>
|
||||||
|
#include <stdlib.h>
|
||||||
#include <memmap.h>
|
#include <memmap.h>
|
||||||
|
|
||||||
#ifndef PROT_READ
|
#ifndef PROT_READ
|
||||||
|
@ -25,7 +25,6 @@
|
|||||||
#include <string.h>
|
#include <string.h>
|
||||||
#include <stdarg.h>
|
#include <stdarg.h>
|
||||||
#include <ctype.h>
|
#include <ctype.h>
|
||||||
#include <errno.h>
|
|
||||||
|
|
||||||
#ifdef HAVE_CONFIG_H
|
#ifdef HAVE_CONFIG_H
|
||||||
#include "config.h"
|
#include "config.h"
|
||||||
@ -46,7 +45,6 @@ struct RFILE
|
|||||||
{
|
{
|
||||||
struct retro_vfs_file_handle *hfile;
|
struct retro_vfs_file_handle *hfile;
|
||||||
bool error_flag;
|
bool error_flag;
|
||||||
bool eof_flag;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
static retro_vfs_get_path_t filestream_get_path_cb = NULL;
|
static retro_vfs_get_path_t filestream_get_path_cb = NULL;
|
||||||
@ -109,18 +107,14 @@ bool filestream_exists(const char *path)
|
|||||||
|
|
||||||
if (!path || !*path)
|
if (!path || !*path)
|
||||||
return false;
|
return false;
|
||||||
|
if (!(dummy = filestream_open(
|
||||||
dummy = filestream_open(
|
|
||||||
path,
|
path,
|
||||||
RETRO_VFS_FILE_ACCESS_READ,
|
RETRO_VFS_FILE_ACCESS_READ,
|
||||||
RETRO_VFS_FILE_ACCESS_HINT_NONE);
|
RETRO_VFS_FILE_ACCESS_HINT_NONE)))
|
||||||
|
|
||||||
if (!dummy)
|
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
if (filestream_close(dummy) != 0)
|
if (filestream_close(dummy) != 0)
|
||||||
if (dummy)
|
free(dummy);
|
||||||
free(dummy);
|
|
||||||
|
|
||||||
dummy = NULL;
|
dummy = NULL;
|
||||||
return true;
|
return true;
|
||||||
@ -165,7 +159,7 @@ int64_t filestream_truncate(RFILE *stream, int64_t length)
|
|||||||
* @hints :
|
* @hints :
|
||||||
*
|
*
|
||||||
* Opens a file for reading or writing, depending on the requested mode.
|
* Opens a file for reading or writing, depending on the requested mode.
|
||||||
* Returns a pointer to an RFILE if opened successfully, otherwise NULL.
|
* @return A pointer to an RFILE if opened successfully, otherwise NULL.
|
||||||
**/
|
**/
|
||||||
RFILE* filestream_open(const char *path, unsigned mode, unsigned hints)
|
RFILE* filestream_open(const char *path, unsigned mode, unsigned hints)
|
||||||
{
|
{
|
||||||
@ -184,7 +178,6 @@ RFILE* filestream_open(const char *path, unsigned mode, unsigned hints)
|
|||||||
|
|
||||||
output = (RFILE*)malloc(sizeof(RFILE));
|
output = (RFILE*)malloc(sizeof(RFILE));
|
||||||
output->error_flag = false;
|
output->error_flag = false;
|
||||||
output->eof_flag = false;
|
|
||||||
output->hfile = fp;
|
output->hfile = fp;
|
||||||
return output;
|
return output;
|
||||||
}
|
}
|
||||||
@ -226,9 +219,9 @@ int filestream_vscanf(RFILE *stream, const char* format, va_list *args)
|
|||||||
char buf[4096];
|
char buf[4096];
|
||||||
char subfmt[64];
|
char subfmt[64];
|
||||||
va_list args_copy;
|
va_list args_copy;
|
||||||
const char * bufiter = buf;
|
const char *bufiter = buf;
|
||||||
int ret = 0;
|
int ret = 0;
|
||||||
int64_t startpos = filestream_tell(stream);
|
int64_t startpos = 0;
|
||||||
int64_t maxlen = filestream_read(stream, buf, sizeof(buf)-1);
|
int64_t maxlen = filestream_read(stream, buf, sizeof(buf)-1);
|
||||||
|
|
||||||
if (maxlen <= 0)
|
if (maxlen <= 0)
|
||||||
@ -241,7 +234,11 @@ int filestream_vscanf(RFILE *stream, const char* format, va_list *args)
|
|||||||
* cause the va_list to have an indeterminate value
|
* cause the va_list to have an indeterminate value
|
||||||
* in the function calling filestream_vscanf(),
|
* in the function calling filestream_vscanf(),
|
||||||
* leading to unexpected behaviour */
|
* leading to unexpected behaviour */
|
||||||
|
#ifdef __va_copy
|
||||||
|
__va_copy(args_copy, *args);
|
||||||
|
#else
|
||||||
va_copy(args_copy, *args);
|
va_copy(args_copy, *args);
|
||||||
|
#endif
|
||||||
|
|
||||||
while (*format)
|
while (*format)
|
||||||
{
|
{
|
||||||
@ -333,12 +330,23 @@ int filestream_vscanf(RFILE *stream, const char* format, va_list *args)
|
|||||||
}
|
}
|
||||||
|
|
||||||
va_end(args_copy);
|
va_end(args_copy);
|
||||||
filestream_seek(stream, startpos+(bufiter-buf),
|
startpos = filestream_tell(stream);
|
||||||
|
filestream_seek(stream, startpos + (bufiter - buf),
|
||||||
RETRO_VFS_SEEK_POSITION_START);
|
RETRO_VFS_SEEK_POSITION_START);
|
||||||
|
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
int filestream_scanf(RFILE *stream, const char* format, ...)
|
||||||
|
{
|
||||||
|
int result;
|
||||||
|
va_list vl;
|
||||||
|
va_start(vl, format);
|
||||||
|
result = filestream_vscanf(stream, format, &vl);
|
||||||
|
va_end(vl);
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
int64_t filestream_seek(RFILE *stream, int64_t offset, int seek_position)
|
int64_t filestream_seek(RFILE *stream, int64_t offset, int seek_position)
|
||||||
{
|
{
|
||||||
int64_t output;
|
int64_t output;
|
||||||
@ -353,14 +361,12 @@ int64_t filestream_seek(RFILE *stream, int64_t offset, int seek_position)
|
|||||||
if (output == VFS_ERROR_RETURN_VALUE)
|
if (output == VFS_ERROR_RETURN_VALUE)
|
||||||
stream->error_flag = true;
|
stream->error_flag = true;
|
||||||
|
|
||||||
stream->eof_flag = false;
|
|
||||||
|
|
||||||
return output;
|
return output;
|
||||||
}
|
}
|
||||||
|
|
||||||
int filestream_eof(RFILE *stream)
|
int filestream_eof(RFILE *stream)
|
||||||
{
|
{
|
||||||
return stream->eof_flag;
|
return filestream_tell(stream) == filestream_get_size(stream) ? EOF : 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
int64_t filestream_tell(RFILE *stream)
|
int64_t filestream_tell(RFILE *stream)
|
||||||
@ -385,7 +391,6 @@ void filestream_rewind(RFILE *stream)
|
|||||||
return;
|
return;
|
||||||
filestream_seek(stream, 0L, RETRO_VFS_SEEK_POSITION_START);
|
filestream_seek(stream, 0L, RETRO_VFS_SEEK_POSITION_START);
|
||||||
stream->error_flag = false;
|
stream->error_flag = false;
|
||||||
stream->eof_flag = false;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
int64_t filestream_read(RFILE *stream, void *s, int64_t len)
|
int64_t filestream_read(RFILE *stream, void *s, int64_t len)
|
||||||
@ -400,8 +405,6 @@ int64_t filestream_read(RFILE *stream, void *s, int64_t len)
|
|||||||
|
|
||||||
if (output == VFS_ERROR_RETURN_VALUE)
|
if (output == VFS_ERROR_RETURN_VALUE)
|
||||||
stream->error_flag = true;
|
stream->error_flag = true;
|
||||||
if (output < len)
|
|
||||||
stream->eof_flag = true;
|
|
||||||
|
|
||||||
return output;
|
return output;
|
||||||
}
|
}
|
||||||
@ -499,9 +502,7 @@ int filestream_printf(RFILE *stream, const char* format, ...)
|
|||||||
|
|
||||||
int filestream_error(RFILE *stream)
|
int filestream_error(RFILE *stream)
|
||||||
{
|
{
|
||||||
if (stream && stream->error_flag)
|
return (stream && stream->error_flag);
|
||||||
return 1;
|
|
||||||
return 0;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
int filestream_close(RFILE *stream)
|
int filestream_close(RFILE *stream)
|
||||||
@ -530,7 +531,7 @@ int filestream_close(RFILE *stream)
|
|||||||
*
|
*
|
||||||
* Read the contents of a file into @buf.
|
* Read the contents of a file into @buf.
|
||||||
*
|
*
|
||||||
* Returns: non zero on success.
|
* @return Non-zero on success.
|
||||||
*/
|
*/
|
||||||
int64_t filestream_read_file(const char *path, void **buf, int64_t *len)
|
int64_t filestream_read_file(const char *path, void **buf, int64_t *len)
|
||||||
{
|
{
|
||||||
@ -547,25 +548,20 @@ int64_t filestream_read_file(const char *path, void **buf, int64_t *len)
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
content_buf_size = filestream_get_size(file);
|
if ((content_buf_size = filestream_get_size(file)) < 0)
|
||||||
|
|
||||||
if (content_buf_size < 0)
|
|
||||||
goto error;
|
goto error;
|
||||||
|
|
||||||
content_buf = malloc((size_t)(content_buf_size + 1));
|
if (!(content_buf = malloc((size_t)(content_buf_size + 1))))
|
||||||
|
|
||||||
if (!content_buf)
|
|
||||||
goto error;
|
goto error;
|
||||||
if ((int64_t)(uint64_t)(content_buf_size + 1) != (content_buf_size + 1))
|
if ((int64_t)(uint64_t)(content_buf_size + 1) != (content_buf_size + 1))
|
||||||
goto error;
|
goto error;
|
||||||
|
|
||||||
ret = filestream_read(file, content_buf, (int64_t)content_buf_size);
|
if ((ret = filestream_read(file, content_buf, (int64_t)content_buf_size)) <
|
||||||
if (ret < 0)
|
0)
|
||||||
goto error;
|
goto error;
|
||||||
|
|
||||||
if (filestream_close(file) != 0)
|
if (filestream_close(file) != 0)
|
||||||
if (file)
|
free(file);
|
||||||
free(file);
|
|
||||||
|
|
||||||
*buf = content_buf;
|
*buf = content_buf;
|
||||||
|
|
||||||
@ -579,9 +575,8 @@ int64_t filestream_read_file(const char *path, void **buf, int64_t *len)
|
|||||||
return 1;
|
return 1;
|
||||||
|
|
||||||
error:
|
error:
|
||||||
if (file)
|
if (filestream_close(file) != 0)
|
||||||
if (filestream_close(file) != 0)
|
free(file);
|
||||||
free(file);
|
|
||||||
if (content_buf)
|
if (content_buf)
|
||||||
free(content_buf);
|
free(content_buf);
|
||||||
if (len)
|
if (len)
|
||||||
@ -598,8 +593,8 @@ error:
|
|||||||
*
|
*
|
||||||
* Writes data to a file.
|
* Writes data to a file.
|
||||||
*
|
*
|
||||||
* Returns: true (1) on success, false (0) otherwise.
|
* @return true on success, otherwise false.
|
||||||
*/
|
**/
|
||||||
bool filestream_write_file(const char *path, const void *data, int64_t size)
|
bool filestream_write_file(const char *path, const void *data, int64_t size)
|
||||||
{
|
{
|
||||||
int64_t ret = 0;
|
int64_t ret = 0;
|
||||||
@ -608,20 +603,18 @@ bool filestream_write_file(const char *path, const void *data, int64_t size)
|
|||||||
RETRO_VFS_FILE_ACCESS_HINT_NONE);
|
RETRO_VFS_FILE_ACCESS_HINT_NONE);
|
||||||
if (!file)
|
if (!file)
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
ret = filestream_write(file, data, size);
|
ret = filestream_write(file, data, size);
|
||||||
if (filestream_close(file) != 0)
|
if (filestream_close(file) != 0)
|
||||||
if (file)
|
free(file);
|
||||||
free(file);
|
return (ret == size);
|
||||||
|
|
||||||
if (ret != size)
|
|
||||||
return false;
|
|
||||||
|
|
||||||
return true;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Returned pointer must be freed by the caller. */
|
/**
|
||||||
char* filestream_getline(RFILE *stream)
|
* filestream_getline:
|
||||||
|
*
|
||||||
|
* Returned pointer must be freed by the caller.
|
||||||
|
**/
|
||||||
|
char *filestream_getline(RFILE *stream)
|
||||||
{
|
{
|
||||||
char *newline_tmp = NULL;
|
char *newline_tmp = NULL;
|
||||||
size_t cur_size = 8;
|
size_t cur_size = 8;
|
||||||
@ -636,16 +629,15 @@ char* filestream_getline(RFILE *stream)
|
|||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
in = filestream_getc(stream);
|
in = filestream_getc(stream);
|
||||||
|
|
||||||
while (in != EOF && in != '\n')
|
while (in != EOF && in != '\n')
|
||||||
{
|
{
|
||||||
if (idx == cur_size)
|
if (idx == cur_size)
|
||||||
{
|
{
|
||||||
cur_size *= 2;
|
cur_size *= 2;
|
||||||
newline_tmp = (char*)realloc(newline, cur_size + 1);
|
|
||||||
|
|
||||||
if (!newline_tmp)
|
if (!(newline_tmp = (char*)realloc(newline, cur_size + 1)))
|
||||||
{
|
{
|
||||||
free(newline);
|
free(newline);
|
||||||
return NULL;
|
return NULL;
|
||||||
|
@ -69,17 +69,27 @@ RFILE* rfopen(const char *path, const char *mode)
|
|||||||
|
|
||||||
int rfclose(RFILE* stream)
|
int rfclose(RFILE* stream)
|
||||||
{
|
{
|
||||||
|
if (!stream)
|
||||||
|
return EOF;
|
||||||
|
|
||||||
return filestream_close(stream);
|
return filestream_close(stream);
|
||||||
}
|
}
|
||||||
|
|
||||||
int64_t rftell(RFILE* stream)
|
int64_t rftell(RFILE* stream)
|
||||||
{
|
{
|
||||||
|
if (!stream)
|
||||||
|
return -1;
|
||||||
|
|
||||||
return filestream_tell(stream);
|
return filestream_tell(stream);
|
||||||
}
|
}
|
||||||
|
|
||||||
int64_t rfseek(RFILE* stream, int64_t offset, int origin)
|
int64_t rfseek(RFILE* stream, int64_t offset, int origin)
|
||||||
{
|
{
|
||||||
int seek_position = -1;
|
int seek_position = -1;
|
||||||
|
|
||||||
|
if (!stream)
|
||||||
|
return -1;
|
||||||
|
|
||||||
switch (origin)
|
switch (origin)
|
||||||
{
|
{
|
||||||
case SEEK_SET:
|
case SEEK_SET:
|
||||||
@ -99,39 +109,61 @@ int64_t rfseek(RFILE* stream, int64_t offset, int origin)
|
|||||||
int64_t rfread(void* buffer,
|
int64_t rfread(void* buffer,
|
||||||
size_t elem_size, size_t elem_count, RFILE* stream)
|
size_t elem_size, size_t elem_count, RFILE* stream)
|
||||||
{
|
{
|
||||||
|
if (!stream || (elem_size == 0) || (elem_count == 0))
|
||||||
|
return 0;
|
||||||
|
|
||||||
return (filestream_read(stream, buffer, elem_size * elem_count) / elem_size);
|
return (filestream_read(stream, buffer, elem_size * elem_count) / elem_size);
|
||||||
}
|
}
|
||||||
|
|
||||||
char *rfgets(char *buffer, int maxCount, RFILE* stream)
|
char *rfgets(char *buffer, int maxCount, RFILE* stream)
|
||||||
{
|
{
|
||||||
|
if (!stream)
|
||||||
|
return NULL;
|
||||||
|
|
||||||
return filestream_gets(stream, buffer, maxCount);
|
return filestream_gets(stream, buffer, maxCount);
|
||||||
}
|
}
|
||||||
|
|
||||||
int rfgetc(RFILE* stream)
|
int rfgetc(RFILE* stream)
|
||||||
{
|
{
|
||||||
|
if (!stream)
|
||||||
|
return EOF;
|
||||||
|
|
||||||
return filestream_getc(stream);
|
return filestream_getc(stream);
|
||||||
}
|
}
|
||||||
|
|
||||||
int64_t rfwrite(void const* buffer,
|
int64_t rfwrite(void const* buffer,
|
||||||
size_t elem_size, size_t elem_count, RFILE* stream)
|
size_t elem_size, size_t elem_count, RFILE* stream)
|
||||||
{
|
{
|
||||||
return filestream_write(stream, buffer, elem_size * elem_count);
|
if (!stream || (elem_size == 0) || (elem_count == 0))
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
return (filestream_write(stream, buffer, elem_size * elem_count) / elem_size);
|
||||||
}
|
}
|
||||||
|
|
||||||
int rfputc(int character, RFILE * stream)
|
int rfputc(int character, RFILE * stream)
|
||||||
{
|
{
|
||||||
return filestream_putc(stream, character);
|
if (!stream)
|
||||||
|
return EOF;
|
||||||
|
|
||||||
|
return filestream_putc(stream, character);
|
||||||
}
|
}
|
||||||
|
|
||||||
int64_t rfflush(RFILE * stream)
|
int64_t rfflush(RFILE * stream)
|
||||||
{
|
{
|
||||||
return filestream_flush(stream);
|
if (!stream)
|
||||||
|
return EOF;
|
||||||
|
|
||||||
|
return filestream_flush(stream);
|
||||||
}
|
}
|
||||||
|
|
||||||
int rfprintf(RFILE * stream, const char * format, ...)
|
int rfprintf(RFILE * stream, const char * format, ...)
|
||||||
{
|
{
|
||||||
int result;
|
int result;
|
||||||
va_list vl;
|
va_list vl;
|
||||||
|
|
||||||
|
if (!stream)
|
||||||
|
return -1;
|
||||||
|
|
||||||
va_start(vl, format);
|
va_start(vl, format);
|
||||||
result = filestream_vprintf(stream, format, vl);
|
result = filestream_vprintf(stream, format, vl);
|
||||||
va_end(vl);
|
va_end(vl);
|
||||||
@ -152,6 +184,10 @@ int rfscanf(RFILE * stream, const char * format, ...)
|
|||||||
{
|
{
|
||||||
int result;
|
int result;
|
||||||
va_list vl;
|
va_list vl;
|
||||||
|
|
||||||
|
if (!stream)
|
||||||
|
return 0;
|
||||||
|
|
||||||
va_start(vl, format);
|
va_start(vl, format);
|
||||||
result = filestream_vscanf(stream, format, &vl);
|
result = filestream_vscanf(stream, format, &vl);
|
||||||
va_end(vl);
|
va_end(vl);
|
||||||
|
@ -24,6 +24,7 @@
|
|||||||
#include <ctype.h>
|
#include <ctype.h>
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
|
|
||||||
|
#include <compat/strl.h>
|
||||||
#include <string/stdstring.h>
|
#include <string/stdstring.h>
|
||||||
#include <encodings/utf.h>
|
#include <encodings/utf.h>
|
||||||
|
|
||||||
@ -89,9 +90,11 @@ char *string_ucwords(char *s)
|
|||||||
}
|
}
|
||||||
|
|
||||||
char *string_replace_substring(const char *in,
|
char *string_replace_substring(const char *in,
|
||||||
const char *pattern, const char *replacement)
|
const char *pattern, size_t pattern_len,
|
||||||
|
const char *replacement, size_t replacement_len)
|
||||||
{
|
{
|
||||||
size_t numhits, pattern_len, replacement_len, outlen;
|
size_t outlen;
|
||||||
|
size_t numhits = 0;
|
||||||
const char *inat = NULL;
|
const char *inat = NULL;
|
||||||
const char *inprev = NULL;
|
const char *inprev = NULL;
|
||||||
char *out = NULL;
|
char *out = NULL;
|
||||||
@ -102,9 +105,6 @@ char *string_replace_substring(const char *in,
|
|||||||
if (!pattern || !replacement)
|
if (!pattern || !replacement)
|
||||||
return strdup(in);
|
return strdup(in);
|
||||||
|
|
||||||
pattern_len = strlen(pattern);
|
|
||||||
replacement_len = strlen(replacement);
|
|
||||||
numhits = 0;
|
|
||||||
inat = in;
|
inat = in;
|
||||||
|
|
||||||
while ((inat = strstr(inat, pattern)))
|
while ((inat = strstr(inat, pattern)))
|
||||||
@ -114,9 +114,8 @@ char *string_replace_substring(const char *in,
|
|||||||
}
|
}
|
||||||
|
|
||||||
outlen = strlen(in) - pattern_len*numhits + replacement_len*numhits;
|
outlen = strlen(in) - pattern_len*numhits + replacement_len*numhits;
|
||||||
out = (char *)malloc(outlen+1);
|
|
||||||
|
|
||||||
if (!out)
|
if (!(out = (char *)malloc(outlen+1)))
|
||||||
return NULL;
|
return NULL;
|
||||||
|
|
||||||
outat = out;
|
outat = out;
|
||||||
@ -129,7 +128,7 @@ char *string_replace_substring(const char *in,
|
|||||||
outat += inat-inprev;
|
outat += inat-inprev;
|
||||||
memcpy(outat, replacement, replacement_len);
|
memcpy(outat, replacement, replacement_len);
|
||||||
outat += replacement_len;
|
outat += replacement_len;
|
||||||
inat += pattern_len;
|
inat += pattern_len;
|
||||||
inprev = inat;
|
inprev = inat;
|
||||||
}
|
}
|
||||||
strcpy(outat, inprev);
|
strcpy(outat, inprev);
|
||||||
@ -137,7 +136,11 @@ char *string_replace_substring(const char *in,
|
|||||||
return out;
|
return out;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Remove leading whitespaces */
|
/**
|
||||||
|
* string_trim_whitespace_left:
|
||||||
|
*
|
||||||
|
* Remove leading whitespaces
|
||||||
|
**/
|
||||||
char *string_trim_whitespace_left(char *const s)
|
char *string_trim_whitespace_left(char *const s)
|
||||||
{
|
{
|
||||||
if (s && *s)
|
if (s && *s)
|
||||||
@ -158,7 +161,11 @@ char *string_trim_whitespace_left(char *const s)
|
|||||||
return s;
|
return s;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Remove trailing whitespaces */
|
/**
|
||||||
|
* string_trim_whitespace_right:
|
||||||
|
*
|
||||||
|
* Remove trailing whitespaces
|
||||||
|
**/
|
||||||
char *string_trim_whitespace_right(char *const s)
|
char *string_trim_whitespace_right(char *const s)
|
||||||
{
|
{
|
||||||
if (s && *s)
|
if (s && *s)
|
||||||
@ -178,7 +185,11 @@ char *string_trim_whitespace_right(char *const s)
|
|||||||
return s;
|
return s;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Remove leading and trailing whitespaces */
|
/**
|
||||||
|
* string_trim_whitespace:
|
||||||
|
*
|
||||||
|
* Remove leading and trailing whitespaces
|
||||||
|
**/
|
||||||
char *string_trim_whitespace(char *const s)
|
char *string_trim_whitespace(char *const s)
|
||||||
{
|
{
|
||||||
string_trim_whitespace_right(s); /* order matters */
|
string_trim_whitespace_right(s); /* order matters */
|
||||||
@ -187,12 +198,33 @@ char *string_trim_whitespace(char *const s)
|
|||||||
return s;
|
return s;
|
||||||
}
|
}
|
||||||
|
|
||||||
void word_wrap(char *dst, size_t dst_size, const char *src, int line_width, int wideglyph_width, unsigned max_lines)
|
/**
|
||||||
|
* word_wrap:
|
||||||
|
* @dst : pointer to destination buffer.
|
||||||
|
* @dst_size : size of destination buffer.
|
||||||
|
* @src : pointer to input string.
|
||||||
|
* @line_width : max number of characters per line.
|
||||||
|
* @wideglyph_width : not used, but is necessary to keep
|
||||||
|
* compatibility with word_wrap_wideglyph().
|
||||||
|
* @max_lines : max lines of destination string.
|
||||||
|
* 0 means no limit.
|
||||||
|
*
|
||||||
|
* Wraps string specified by 'src' to destination buffer
|
||||||
|
* specified by 'dst' and 'dst_size'.
|
||||||
|
* This function assumes that all glyphs in the string
|
||||||
|
* have an on-screen pixel width similar to that of
|
||||||
|
* regular Latin characters - i.e. it will not wrap
|
||||||
|
* correctly any text containing so-called 'wide' Unicode
|
||||||
|
* characters (e.g. CJK languages, emojis, etc.).
|
||||||
|
**/
|
||||||
|
void word_wrap(
|
||||||
|
char *dst, size_t dst_size,
|
||||||
|
const char *src, size_t src_len,
|
||||||
|
int line_width, int wideglyph_width, unsigned max_lines)
|
||||||
{
|
{
|
||||||
char *lastspace = NULL;
|
char *lastspace = NULL;
|
||||||
unsigned counter = 0;
|
unsigned counter = 0;
|
||||||
unsigned lines = 1;
|
unsigned lines = 1;
|
||||||
size_t src_len = strlen(src);
|
|
||||||
const char *src_end = src + src_len;
|
const char *src_end = src + src_len;
|
||||||
|
|
||||||
/* Prevent buffer overflow */
|
/* Prevent buffer overflow */
|
||||||
@ -201,17 +233,15 @@ void word_wrap(char *dst, size_t dst_size, const char *src, int line_width, int
|
|||||||
|
|
||||||
/* Early return if src string length is less
|
/* Early return if src string length is less
|
||||||
* than line width */
|
* than line width */
|
||||||
if (src_len < line_width)
|
if (src_len < (size_t)line_width)
|
||||||
{
|
{
|
||||||
strcpy(dst, src);
|
strlcpy(dst, src, dst_size);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
while (*src != '\0')
|
while (*src != '\0')
|
||||||
{
|
{
|
||||||
unsigned char_len;
|
unsigned char_len = (unsigned)(utf8skip(src, 1) - src);
|
||||||
|
|
||||||
char_len = (unsigned)(utf8skip(src, 1) - src);
|
|
||||||
counter++;
|
counter++;
|
||||||
|
|
||||||
if (*src == ' ')
|
if (*src == ' ')
|
||||||
@ -227,7 +257,7 @@ void word_wrap(char *dst, size_t dst_size, const char *src, int line_width, int
|
|||||||
* length is less than line width */
|
* length is less than line width */
|
||||||
if (src_end - src <= line_width)
|
if (src_end - src <= line_width)
|
||||||
{
|
{
|
||||||
strcpy(dst, src);
|
strlcpy(dst, src, dst_size);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -254,7 +284,7 @@ void word_wrap(char *dst, size_t dst_size, const char *src, int line_width, int
|
|||||||
* length is less than line width */
|
* length is less than line width */
|
||||||
if (src_end - src < line_width)
|
if (src_end - src < line_width)
|
||||||
{
|
{
|
||||||
strcpy(dst, src);
|
strlcpy(dst, src, dst_size);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -264,11 +294,46 @@ void word_wrap(char *dst, size_t dst_size, const char *src, int line_width, int
|
|||||||
*dst = '\0';
|
*dst = '\0';
|
||||||
}
|
}
|
||||||
|
|
||||||
void word_wrap_wideglyph(char *dst, size_t dst_size, const char *src, int line_width, int wideglyph_width, unsigned max_lines)
|
/**
|
||||||
|
* word_wrap_wideglyph:
|
||||||
|
* @dst : pointer to destination buffer.
|
||||||
|
* @dst_size : size of destination buffer.
|
||||||
|
* @src : pointer to input string.
|
||||||
|
* @line_width : max number of characters per line.
|
||||||
|
* @wideglyph_width : effective width of 'wide' Unicode glyphs.
|
||||||
|
* the value here is normalised relative to the
|
||||||
|
* typical on-screen pixel width of a regular
|
||||||
|
* Latin character:
|
||||||
|
* - a regular Latin character is defined to
|
||||||
|
* have an effective width of 100
|
||||||
|
* - wideglyph_width = 100 * (wide_character_pixel_width / latin_character_pixel_width)
|
||||||
|
* - e.g. if 'wide' Unicode characters in 'src'
|
||||||
|
* have an on-screen pixel width twice that of
|
||||||
|
* regular Latin characters, wideglyph_width
|
||||||
|
* would be 200
|
||||||
|
* @max_lines : max lines of destination string.
|
||||||
|
* 0 means no limit.
|
||||||
|
*
|
||||||
|
* Wraps string specified by @src to destination buffer
|
||||||
|
* specified by @dst and @dst_size.
|
||||||
|
* This function assumes that all glyphs in the string
|
||||||
|
* are:
|
||||||
|
* - EITHER 'non-wide' Unicode glyphs, with an on-screen
|
||||||
|
* pixel width similar to that of regular Latin characters
|
||||||
|
* - OR 'wide' Unicode glyphs (e.g. CJK languages, emojis, etc.)
|
||||||
|
* with an on-screen pixel width defined by @wideglyph_width
|
||||||
|
* Note that wrapping may occur in inappropriate locations
|
||||||
|
* if @src string contains 'wide' Unicode characters whose
|
||||||
|
* on-screen pixel width deviates greatly from the set
|
||||||
|
* @wideglyph_width value.
|
||||||
|
**/
|
||||||
|
void word_wrap_wideglyph(char *dst, size_t dst_size,
|
||||||
|
const char *src, size_t src_len, int line_width,
|
||||||
|
int wideglyph_width, unsigned max_lines)
|
||||||
{
|
{
|
||||||
char *lastspace = NULL;
|
char *lastspace = NULL;
|
||||||
char *lastwideglyph = NULL;
|
char *lastwideglyph = NULL;
|
||||||
const char *src_end = src + strlen(src);
|
const char *src_end = src + src_len;
|
||||||
unsigned lines = 1;
|
unsigned lines = 1;
|
||||||
/* 'line_width' means max numbers of characters per line,
|
/* 'line_width' means max numbers of characters per line,
|
||||||
* but this metric is only meaningful when dealing with
|
* but this metric is only meaningful when dealing with
|
||||||
@ -305,9 +370,7 @@ void word_wrap_wideglyph(char *dst, size_t dst_size, const char *src, int line_w
|
|||||||
|
|
||||||
while (*src != '\0')
|
while (*src != '\0')
|
||||||
{
|
{
|
||||||
unsigned char_len;
|
unsigned char_len = (unsigned)(utf8skip(src, 1) - src);
|
||||||
|
|
||||||
char_len = (unsigned)(utf8skip(src, 1) - src);
|
|
||||||
counter_normalized += 100;
|
counter_normalized += 100;
|
||||||
|
|
||||||
/* Prevent buffer overflow */
|
/* Prevent buffer overflow */
|
||||||
@ -315,7 +378,7 @@ void word_wrap_wideglyph(char *dst, size_t dst_size, const char *src, int line_w
|
|||||||
break;
|
break;
|
||||||
|
|
||||||
if (*src == ' ')
|
if (*src == ' ')
|
||||||
lastspace = dst; /* Remember the location of the whitespace */
|
lastspace = dst; /* Remember the location of the whitespace */
|
||||||
else if (*src == '\n')
|
else if (*src == '\n')
|
||||||
{
|
{
|
||||||
/* If newlines embedded in the input,
|
/* If newlines embedded in the input,
|
||||||
@ -335,7 +398,7 @@ void word_wrap_wideglyph(char *dst, size_t dst_size, const char *src, int line_w
|
|||||||
{
|
{
|
||||||
/* Remember the location of the first byte
|
/* Remember the location of the first byte
|
||||||
* whose length as UTF-8 >= 3*/
|
* whose length as UTF-8 >= 3*/
|
||||||
lastwideglyph = dst;
|
lastwideglyph = dst;
|
||||||
counter_normalized += additional_counter_normalized;
|
counter_normalized += additional_counter_normalized;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -354,9 +417,9 @@ void word_wrap_wideglyph(char *dst, size_t dst_size, const char *src, int line_w
|
|||||||
/* Insert newline character */
|
/* Insert newline character */
|
||||||
*lastwideglyph = '\n';
|
*lastwideglyph = '\n';
|
||||||
lines++;
|
lines++;
|
||||||
src -= dst - lastwideglyph;
|
src -= dst - lastwideglyph;
|
||||||
dst = lastwideglyph + 1;
|
dst = lastwideglyph + 1;
|
||||||
lastwideglyph = NULL;
|
lastwideglyph = NULL;
|
||||||
|
|
||||||
/* Early return if remaining src string
|
/* Early return if remaining src string
|
||||||
* length is less than line width */
|
* length is less than line width */
|
||||||
@ -372,9 +435,9 @@ void word_wrap_wideglyph(char *dst, size_t dst_size, const char *src, int line_w
|
|||||||
* with newline character */
|
* with newline character */
|
||||||
*lastspace = '\n';
|
*lastspace = '\n';
|
||||||
lines++;
|
lines++;
|
||||||
src -= dst - lastspace - 1;
|
src -= dst - lastspace - 1;
|
||||||
dst = lastspace + 1;
|
dst = lastspace + 1;
|
||||||
lastspace = NULL;
|
lastspace = NULL;
|
||||||
|
|
||||||
/* Early return if remaining src string
|
/* Early return if remaining src string
|
||||||
* length is less than line width */
|
* length is less than line width */
|
||||||
@ -390,10 +453,13 @@ void word_wrap_wideglyph(char *dst, size_t dst_size, const char *src, int line_w
|
|||||||
*dst = '\0';
|
*dst = '\0';
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Splits string into tokens seperated by 'delim'
|
/**
|
||||||
|
* string_tokenize:
|
||||||
|
*
|
||||||
|
* Splits string into tokens seperated by @delim
|
||||||
* > Returned token string must be free()'d
|
* > Returned token string must be free()'d
|
||||||
* > Returns NULL if token is not found
|
* > Returns NULL if token is not found
|
||||||
* > After each call, 'str' is set to the position after the
|
* > After each call, @str is set to the position after the
|
||||||
* last found token
|
* last found token
|
||||||
* > Tokens *include* empty strings
|
* > Tokens *include* empty strings
|
||||||
* Usage example:
|
* Usage example:
|
||||||
@ -406,7 +472,7 @@ void word_wrap_wideglyph(char *dst, size_t dst_size, const char *src, int line_w
|
|||||||
* free(token);
|
* free(token);
|
||||||
* token = NULL;
|
* token = NULL;
|
||||||
* }
|
* }
|
||||||
*/
|
**/
|
||||||
char* string_tokenize(char **str, const char *delim)
|
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# */
|
/* Taken from https://codereview.stackexchange.com/questions/216956/strtok-function-thread-safe-supports-empty-tokens-doesnt-change-string# */
|
||||||
@ -419,25 +485,20 @@ char* string_tokenize(char **str, const char *delim)
|
|||||||
if (!str || string_is_empty(delim))
|
if (!str || string_is_empty(delim))
|
||||||
return NULL;
|
return NULL;
|
||||||
|
|
||||||
str_ptr = *str;
|
|
||||||
|
|
||||||
/* Note: we don't check string_is_empty() here,
|
/* Note: we don't check string_is_empty() here,
|
||||||
* empty strings are valid */
|
* empty strings are valid */
|
||||||
if (!str_ptr)
|
if (!(str_ptr = *str))
|
||||||
return NULL;
|
return NULL;
|
||||||
|
|
||||||
/* Search for delimiter */
|
/* Search for delimiter */
|
||||||
delim_ptr = strstr(str_ptr, delim);
|
if ((delim_ptr = strstr(str_ptr, delim)))
|
||||||
|
|
||||||
if (delim_ptr)
|
|
||||||
token_len = delim_ptr - str_ptr;
|
token_len = delim_ptr - str_ptr;
|
||||||
else
|
else
|
||||||
token_len = strlen(str_ptr);
|
token_len = strlen(str_ptr);
|
||||||
|
|
||||||
/* Allocate token string */
|
/* Allocate token string */
|
||||||
token = (char *)malloc((token_len + 1) * sizeof(char));
|
if (!(token = (char *)malloc((token_len + 1) * sizeof(char))))
|
||||||
|
|
||||||
if (!token)
|
|
||||||
return NULL;
|
return NULL;
|
||||||
|
|
||||||
/* Copy token */
|
/* Copy token */
|
||||||
@ -450,42 +511,53 @@ char* string_tokenize(char **str, const char *delim)
|
|||||||
return token;
|
return token;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Removes every instance of character 'c' from 'str' */
|
/**
|
||||||
|
* string_remove_all_chars:
|
||||||
|
* @str : input string (must be non-NULL, otherwise UB)
|
||||||
|
*
|
||||||
|
* Leaf function.
|
||||||
|
*
|
||||||
|
* Removes every instance of character @c from @str
|
||||||
|
**/
|
||||||
void string_remove_all_chars(char *str, char c)
|
void string_remove_all_chars(char *str, char c)
|
||||||
{
|
{
|
||||||
char *read_ptr = NULL;
|
char *read_ptr = str;
|
||||||
char *write_ptr = NULL;
|
char *write_ptr = str;
|
||||||
|
|
||||||
if (string_is_empty(str))
|
|
||||||
return;
|
|
||||||
|
|
||||||
read_ptr = str;
|
|
||||||
write_ptr = str;
|
|
||||||
|
|
||||||
while (*read_ptr != '\0')
|
while (*read_ptr != '\0')
|
||||||
{
|
{
|
||||||
*write_ptr = *read_ptr++;
|
*write_ptr = *read_ptr++;
|
||||||
write_ptr += (*write_ptr != c) ? 1 : 0;
|
if (*write_ptr != c)
|
||||||
|
write_ptr++;
|
||||||
}
|
}
|
||||||
|
|
||||||
*write_ptr = '\0';
|
*write_ptr = '\0';
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Replaces every instance of character 'find' in 'str'
|
/**
|
||||||
* with character 'replace' */
|
* string_replace_all_chars:
|
||||||
|
* @str : input string (must be non-NULL, otherwise UB)
|
||||||
|
* @find : character to find
|
||||||
|
* @replace : character to replace @find with
|
||||||
|
*
|
||||||
|
* Replaces every instance of character @find in @str
|
||||||
|
* with character @replace
|
||||||
|
**/
|
||||||
void string_replace_all_chars(char *str, char find, char replace)
|
void string_replace_all_chars(char *str, char find, char replace)
|
||||||
{
|
{
|
||||||
char *str_ptr = str;
|
char *str_ptr = str;
|
||||||
|
|
||||||
if (string_is_empty(str))
|
|
||||||
return;
|
|
||||||
|
|
||||||
while ((str_ptr = strchr(str_ptr, find)))
|
while ((str_ptr = strchr(str_ptr, find)))
|
||||||
*str_ptr++ = replace;
|
*str_ptr++ = replace;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Converts string to unsigned integer.
|
/**
|
||||||
* Returns 0 if string is invalid */
|
* string_to_unsigned:
|
||||||
|
* @str : input string
|
||||||
|
*
|
||||||
|
* Converts string to unsigned integer.
|
||||||
|
*
|
||||||
|
* @return 0 if string is invalid, otherwise > 0
|
||||||
|
**/
|
||||||
unsigned string_to_unsigned(const char *str)
|
unsigned string_to_unsigned(const char *str)
|
||||||
{
|
{
|
||||||
const char *ptr = NULL;
|
const char *ptr = NULL;
|
||||||
@ -502,27 +574,33 @@ unsigned string_to_unsigned(const char *str)
|
|||||||
return (unsigned)strtoul(str, NULL, 10);
|
return (unsigned)strtoul(str, NULL, 10);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Converts hexadecimal string to unsigned integer.
|
/**
|
||||||
|
* string_hex_to_unsigned:
|
||||||
|
* @str : input string (must be non-NULL, otherwise UB)
|
||||||
|
*
|
||||||
|
* Converts hexadecimal string to unsigned integer.
|
||||||
* Handles optional leading '0x'.
|
* Handles optional leading '0x'.
|
||||||
* Returns 0 if string is invalid */
|
*
|
||||||
|
* @return 0 if string is invalid, otherwise > 0
|
||||||
|
**/
|
||||||
unsigned string_hex_to_unsigned(const char *str)
|
unsigned string_hex_to_unsigned(const char *str)
|
||||||
{
|
{
|
||||||
const char *hex_str = str;
|
const char *hex_str = str;
|
||||||
const char *ptr = NULL;
|
const char *ptr = NULL;
|
||||||
size_t len;
|
|
||||||
|
|
||||||
if (string_is_empty(str))
|
|
||||||
return 0;
|
|
||||||
|
|
||||||
/* Remove leading '0x', if required */
|
/* Remove leading '0x', if required */
|
||||||
len = strlen(str);
|
if (str[0] != '\0' && str[1] != '\0')
|
||||||
|
{
|
||||||
if (len >= 2)
|
if ( (str[0] == '0') &&
|
||||||
if ((str[0] == '0') &&
|
((str[1] == 'x') ||
|
||||||
((str[1] == 'x') || (str[1] == 'X')))
|
(str[1] == 'X')))
|
||||||
|
{
|
||||||
hex_str = str + 2;
|
hex_str = str + 2;
|
||||||
|
if (string_is_empty(hex_str))
|
||||||
if (string_is_empty(hex_str))
|
return 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
/* Check for valid characters */
|
/* Check for valid characters */
|
||||||
@ -534,3 +612,117 @@ unsigned string_hex_to_unsigned(const char *str)
|
|||||||
|
|
||||||
return (unsigned)strtoul(hex_str, NULL, 16);
|
return (unsigned)strtoul(hex_str, NULL, 16);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* string_count_occurrences_single_character:
|
||||||
|
*
|
||||||
|
* Leaf function.
|
||||||
|
*
|
||||||
|
* Get the total number of occurrences of character @c in @str.
|
||||||
|
*
|
||||||
|
* @return Total number of occurrences of character @c
|
||||||
|
*/
|
||||||
|
int string_count_occurrences_single_character(const char *str, char c)
|
||||||
|
{
|
||||||
|
int count = 0;
|
||||||
|
|
||||||
|
for (; *str; str++)
|
||||||
|
if (*str == c)
|
||||||
|
count++;
|
||||||
|
|
||||||
|
return count;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* string_replace_whitespace_with_single_character:
|
||||||
|
*
|
||||||
|
* Leaf function.
|
||||||
|
*
|
||||||
|
* Replaces all spaces with given character @c.
|
||||||
|
**/
|
||||||
|
void string_replace_whitespace_with_single_character(char *str, char c)
|
||||||
|
{
|
||||||
|
for (; *str; str++)
|
||||||
|
if (ISSPACE(*str))
|
||||||
|
*str = c;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* string_replace_multi_space_with_single_space:
|
||||||
|
*
|
||||||
|
* Leaf function.
|
||||||
|
*
|
||||||
|
* Replaces multiple spaces with a single space in a string.
|
||||||
|
**/
|
||||||
|
void string_replace_multi_space_with_single_space(char *str)
|
||||||
|
{
|
||||||
|
char *str_trimmed = str;
|
||||||
|
bool prev_is_space = false;
|
||||||
|
bool curr_is_space = false;
|
||||||
|
|
||||||
|
for (; *str; str++)
|
||||||
|
{
|
||||||
|
curr_is_space = ISSPACE(*str);
|
||||||
|
if (prev_is_space && curr_is_space)
|
||||||
|
continue;
|
||||||
|
*str_trimmed++ = *str;
|
||||||
|
prev_is_space = curr_is_space;
|
||||||
|
}
|
||||||
|
*str_trimmed = '\0';
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* string_remove_all_whitespace:
|
||||||
|
*
|
||||||
|
* Leaf function.
|
||||||
|
*
|
||||||
|
* Remove all spaces from the given string.
|
||||||
|
**/
|
||||||
|
void string_remove_all_whitespace(char *str_trimmed, const char *str)
|
||||||
|
{
|
||||||
|
for (; *str; str++)
|
||||||
|
if (!ISSPACE(*str))
|
||||||
|
*str_trimmed++ = *str;
|
||||||
|
*str_trimmed = '\0';
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Retrieve the last occurance of the given character in a string.
|
||||||
|
*/
|
||||||
|
int string_index_last_occurance(const char *str, char c)
|
||||||
|
{
|
||||||
|
const char *pos = strrchr(str, c);
|
||||||
|
if (pos)
|
||||||
|
return (int)(pos - str);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* string_find_index_substring_string:
|
||||||
|
* @str : input string (must be non-NULL, otherwise UB)
|
||||||
|
* @substr : substring to find in @str
|
||||||
|
*
|
||||||
|
* Find the position of substring @substr in string @str.
|
||||||
|
**/
|
||||||
|
int string_find_index_substring_string(const char *str, const char *substr)
|
||||||
|
{
|
||||||
|
const char *pos = strstr(str, substr);
|
||||||
|
if (pos)
|
||||||
|
return (int)(pos - str);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* string_copy_only_ascii:
|
||||||
|
*
|
||||||
|
* Leaf function.
|
||||||
|
*
|
||||||
|
* Strips non-ASCII characters from a string.
|
||||||
|
**/
|
||||||
|
void string_copy_only_ascii(char *str_stripped, const char *str)
|
||||||
|
{
|
||||||
|
for (; *str; str++)
|
||||||
|
if (*str > 0x1F && *str < 0x7F)
|
||||||
|
*str_stripped++ = *str;
|
||||||
|
*str_stripped = '\0';
|
||||||
|
}
|
||||||
|
@ -22,7 +22,6 @@
|
|||||||
|
|
||||||
#ifdef HAVE_THREADS
|
#ifdef HAVE_THREADS
|
||||||
#include <rthreads/rthreads.h>
|
#include <rthreads/rthreads.h>
|
||||||
#include <retro_assert.h>
|
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
@ -41,8 +40,6 @@ void rtime_init(void)
|
|||||||
#ifdef HAVE_THREADS
|
#ifdef HAVE_THREADS
|
||||||
if (!rtime_localtime_lock)
|
if (!rtime_localtime_lock)
|
||||||
rtime_localtime_lock = slock_new();
|
rtime_localtime_lock = slock_new();
|
||||||
|
|
||||||
retro_assert(rtime_localtime_lock);
|
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -26,7 +26,7 @@
|
|||||||
#include <errno.h>
|
#include <errno.h>
|
||||||
#include <sys/types.h>
|
#include <sys/types.h>
|
||||||
|
|
||||||
#include <string/stdstring.h>
|
#include <string/stdstring.h> /* string_is_empty */
|
||||||
|
|
||||||
#ifdef HAVE_CONFIG_H
|
#ifdef HAVE_CONFIG_H
|
||||||
#include "config.h"
|
#include "config.h"
|
||||||
@ -57,11 +57,6 @@
|
|||||||
# include <dirent.h>
|
# include <dirent.h>
|
||||||
# endif
|
# endif
|
||||||
# include <unistd.h>
|
# include <unistd.h>
|
||||||
# if defined(ORBIS)
|
|
||||||
# include <sys/fcntl.h>
|
|
||||||
# include <sys/dirent.h>
|
|
||||||
# include <orbisFile.h>
|
|
||||||
# endif
|
|
||||||
# if defined(WIIU)
|
# if defined(WIIU)
|
||||||
# include <malloc.h>
|
# include <malloc.h>
|
||||||
# endif
|
# endif
|
||||||
@ -74,11 +69,6 @@
|
|||||||
# include <psp2/io/fcntl.h>
|
# include <psp2/io/fcntl.h>
|
||||||
# include <psp2/io/dirent.h>
|
# include <psp2/io/dirent.h>
|
||||||
# include <psp2/io/stat.h>
|
# include <psp2/io/stat.h>
|
||||||
#elif defined(ORBIS)
|
|
||||||
# include <orbisFile.h>
|
|
||||||
# include <ps4link.h>
|
|
||||||
# include <sys/dirent.h>
|
|
||||||
# include <sys/fcntl.h>
|
|
||||||
#elif !defined(_WIN32)
|
#elif !defined(_WIN32)
|
||||||
# if defined(PSP)
|
# if defined(PSP)
|
||||||
# include <pspiofilemgr.h>
|
# include <pspiofilemgr.h>
|
||||||
@ -124,19 +114,66 @@
|
|||||||
#include <unistd.h>
|
#include <unistd.h>
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#if defined(ORBIS)
|
|
||||||
#include <orbisFile.h>
|
|
||||||
#include <sys/fcntl.h>
|
|
||||||
#include <sys/dirent.h>
|
|
||||||
#endif
|
|
||||||
#if defined(PSP)
|
#if defined(PSP)
|
||||||
#include <pspkernel.h>
|
#include <pspkernel.h>
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#if defined(__PS3__) || defined(__PSL1GHT__)
|
#if defined(__PS3__) || defined(__PSL1GHT__)
|
||||||
#include <defines/ps3_defines.h>
|
#define FS_SUCCEEDED 0
|
||||||
#if defined(__PSL1GHT__)
|
#define FS_TYPE_DIR 1
|
||||||
|
#ifdef __PSL1GHT__
|
||||||
#include <lv2/sysfs.h>
|
#include <lv2/sysfs.h>
|
||||||
|
#ifndef O_RDONLY
|
||||||
|
#define O_RDONLY SYS_O_RDONLY
|
||||||
|
#endif
|
||||||
|
#ifndef O_WRONLY
|
||||||
|
#define O_WRONLY SYS_O_WRONLY
|
||||||
|
#endif
|
||||||
|
#ifndef O_CREAT
|
||||||
|
#define O_CREAT SYS_O_CREAT
|
||||||
|
#endif
|
||||||
|
#ifndef O_TRUNC
|
||||||
|
#define O_TRUNC SYS_O_TRUNC
|
||||||
|
#endif
|
||||||
|
#ifndef O_RDWR
|
||||||
|
#define O_RDWR SYS_O_RDWR
|
||||||
|
#endif
|
||||||
|
#else
|
||||||
|
#include <cell/cell_fs.h>
|
||||||
|
#ifndef O_RDONLY
|
||||||
|
#define O_RDONLY CELL_FS_O_RDONLY
|
||||||
|
#endif
|
||||||
|
#ifndef O_WRONLY
|
||||||
|
#define O_WRONLY CELL_FS_O_WRONLY
|
||||||
|
#endif
|
||||||
|
#ifndef O_CREAT
|
||||||
|
#define O_CREAT CELL_FS_O_CREAT
|
||||||
|
#endif
|
||||||
|
#ifndef O_TRUNC
|
||||||
|
#define O_TRUNC CELL_FS_O_TRUNC
|
||||||
|
#endif
|
||||||
|
#ifndef O_RDWR
|
||||||
|
#define O_RDWR CELL_FS_O_RDWR
|
||||||
|
#endif
|
||||||
|
#ifndef sysFsStat
|
||||||
|
#define sysFsStat cellFsStat
|
||||||
|
#endif
|
||||||
|
#ifndef sysFSDirent
|
||||||
|
#define sysFSDirent CellFsDirent
|
||||||
|
#endif
|
||||||
|
#ifndef sysFsOpendir
|
||||||
|
#define sysFsOpendir cellFsOpendir
|
||||||
|
#endif
|
||||||
|
#ifndef sysFsReaddir
|
||||||
|
#define sysFsReaddir cellFsReaddir
|
||||||
|
#endif
|
||||||
|
#ifndef sysFSDirent
|
||||||
|
#define sysFSDirent CellFsDirent
|
||||||
|
#endif
|
||||||
|
#ifndef sysFsClosedir
|
||||||
|
#define sysFsClosedir cellFsClosedir
|
||||||
|
#endif
|
||||||
#endif
|
#endif
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
@ -200,13 +237,6 @@ int64_t retro_vfs_file_seek_internal(
|
|||||||
#ifdef ATLEAST_VC2005
|
#ifdef ATLEAST_VC2005
|
||||||
/* VC2005 and up have a special 64-bit fseek */
|
/* VC2005 and up have a special 64-bit fseek */
|
||||||
return _fseeki64(stream->fp, offset, whence);
|
return _fseeki64(stream->fp, offset, whence);
|
||||||
#elif defined(ORBIS)
|
|
||||||
{
|
|
||||||
int ret = orbisLseek(stream->fd, offset, whence);
|
|
||||||
if (ret < 0)
|
|
||||||
return -1;
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
#elif defined(HAVE_64BIT_OFFSETS)
|
#elif defined(HAVE_64BIT_OFFSETS)
|
||||||
return fseeko(stream->fp, (off_t)offset, whence);
|
return fseeko(stream->fp, (off_t)offset, whence);
|
||||||
#else
|
#else
|
||||||
@ -269,19 +299,6 @@ int64_t retro_vfs_file_seek_internal(
|
|||||||
libretro_vfs_implementation_file *retro_vfs_file_open_impl(
|
libretro_vfs_implementation_file *retro_vfs_file_open_impl(
|
||||||
const char *path, unsigned mode, unsigned hints)
|
const char *path, unsigned mode, unsigned hints)
|
||||||
{
|
{
|
||||||
#if defined(VFS_FRONTEND) || defined(HAVE_CDROM)
|
|
||||||
int path_len = (int)strlen(path);
|
|
||||||
#endif
|
|
||||||
#ifdef VFS_FRONTEND
|
|
||||||
const char *dumb_prefix = "vfsonly://";
|
|
||||||
size_t dumb_prefix_siz = STRLEN_CONST("vfsonly://");
|
|
||||||
int dumb_prefix_len = (int)dumb_prefix_siz;
|
|
||||||
#endif
|
|
||||||
#ifdef HAVE_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;
|
int flags = 0;
|
||||||
const char *mode_str = NULL;
|
const char *mode_str = NULL;
|
||||||
libretro_vfs_implementation_file *stream =
|
libretro_vfs_implementation_file *stream =
|
||||||
@ -306,9 +323,18 @@ libretro_vfs_implementation_file *retro_vfs_file_open_impl(
|
|||||||
stream->scheme = VFS_SCHEME_NONE;
|
stream->scheme = VFS_SCHEME_NONE;
|
||||||
|
|
||||||
#ifdef VFS_FRONTEND
|
#ifdef VFS_FRONTEND
|
||||||
if (path_len >= dumb_prefix_len)
|
if ( path
|
||||||
if (!memcmp(path, dumb_prefix, dumb_prefix_len))
|
&& path[0] == 'v'
|
||||||
path += dumb_prefix_siz;
|
&& path[1] == 'f'
|
||||||
|
&& path[2] == 's'
|
||||||
|
&& path[3] == 'o'
|
||||||
|
&& path[4] == 'n'
|
||||||
|
&& path[5] == 'l'
|
||||||
|
&& path[6] == 'y'
|
||||||
|
&& path[7] == ':'
|
||||||
|
&& path[8] == '/'
|
||||||
|
&& path[9] == '/')
|
||||||
|
path += sizeof("vfsonly://")-1;
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#ifdef HAVE_CDROM
|
#ifdef HAVE_CDROM
|
||||||
@ -325,13 +351,19 @@ libretro_vfs_implementation_file *retro_vfs_file_open_impl(
|
|||||||
stream->cdrom.last_frame[0] = '\0';
|
stream->cdrom.last_frame[0] = '\0';
|
||||||
stream->cdrom.last_frame_valid = false;
|
stream->cdrom.last_frame_valid = false;
|
||||||
|
|
||||||
if (path_len > cdrom_prefix_len)
|
if ( path
|
||||||
|
&& path[0] == 'c'
|
||||||
|
&& path[1] == 'd'
|
||||||
|
&& path[2] == 'r'
|
||||||
|
&& path[3] == 'o'
|
||||||
|
&& path[4] == 'm'
|
||||||
|
&& path[5] == ':'
|
||||||
|
&& path[6] == '/'
|
||||||
|
&& path[7] == '/'
|
||||||
|
&& path[8] != '\0')
|
||||||
{
|
{
|
||||||
if (!memcmp(path, cdrom_prefix, cdrom_prefix_len))
|
path += sizeof("cdrom://")-1;
|
||||||
{
|
stream->scheme = VFS_SCHEME_CDROM;
|
||||||
path += cdrom_prefix_siz;
|
|
||||||
stream->scheme = VFS_SCHEME_CDROM;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
@ -359,24 +391,20 @@ libretro_vfs_implementation_file *retro_vfs_file_open_impl(
|
|||||||
mode_str = "wb";
|
mode_str = "wb";
|
||||||
|
|
||||||
flags = O_WRONLY | O_CREAT | O_TRUNC;
|
flags = O_WRONLY | O_CREAT | O_TRUNC;
|
||||||
#if !defined(ORBIS)
|
|
||||||
#if !defined(_WIN32)
|
#if !defined(_WIN32)
|
||||||
flags |= S_IRUSR | S_IWUSR;
|
flags |= S_IRUSR | S_IWUSR;
|
||||||
#else
|
#else
|
||||||
flags |= O_BINARY;
|
flags |= O_BINARY;
|
||||||
#endif
|
|
||||||
#endif
|
#endif
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case RETRO_VFS_FILE_ACCESS_READ_WRITE:
|
case RETRO_VFS_FILE_ACCESS_READ_WRITE:
|
||||||
mode_str = "w+b";
|
mode_str = "w+b";
|
||||||
flags = O_RDWR | O_CREAT | O_TRUNC;
|
flags = O_RDWR | O_CREAT | O_TRUNC;
|
||||||
#if !defined(ORBIS)
|
|
||||||
#if !defined(_WIN32)
|
#if !defined(_WIN32)
|
||||||
flags |= S_IRUSR | S_IWUSR;
|
flags |= S_IRUSR | S_IWUSR;
|
||||||
#else
|
#else
|
||||||
flags |= O_BINARY;
|
flags |= O_BINARY;
|
||||||
#endif
|
|
||||||
#endif
|
#endif
|
||||||
break;
|
break;
|
||||||
|
|
||||||
@ -385,12 +413,10 @@ libretro_vfs_implementation_file *retro_vfs_file_open_impl(
|
|||||||
mode_str = "r+b";
|
mode_str = "r+b";
|
||||||
|
|
||||||
flags = O_RDWR;
|
flags = O_RDWR;
|
||||||
#if !defined(ORBIS)
|
|
||||||
#if !defined(_WIN32)
|
#if !defined(_WIN32)
|
||||||
flags |= S_IRUSR | S_IWUSR;
|
flags |= S_IRUSR | S_IWUSR;
|
||||||
#else
|
#else
|
||||||
flags |= O_BINARY;
|
flags |= O_BINARY;
|
||||||
#endif
|
|
||||||
#endif
|
#endif
|
||||||
break;
|
break;
|
||||||
|
|
||||||
@ -400,15 +426,6 @@ libretro_vfs_implementation_file *retro_vfs_file_open_impl(
|
|||||||
|
|
||||||
if ((stream->hints & RFILE_HINT_UNBUFFERED) == 0)
|
if ((stream->hints & RFILE_HINT_UNBUFFERED) == 0)
|
||||||
{
|
{
|
||||||
#ifdef ORBIS
|
|
||||||
int fd = orbisOpen(path, flags, 0644);
|
|
||||||
if (fd < 0)
|
|
||||||
{
|
|
||||||
stream->fd = -1;
|
|
||||||
goto error;
|
|
||||||
}
|
|
||||||
stream->fd = fd;
|
|
||||||
#else
|
|
||||||
FILE *fp;
|
FILE *fp;
|
||||||
#ifdef HAVE_CDROM
|
#ifdef HAVE_CDROM
|
||||||
if (stream->scheme == VFS_SCHEME_CDROM)
|
if (stream->scheme == VFS_SCHEME_CDROM)
|
||||||
@ -425,13 +442,12 @@ libretro_vfs_implementation_file *retro_vfs_file_open_impl(
|
|||||||
else
|
else
|
||||||
#endif
|
#endif
|
||||||
{
|
{
|
||||||
fp = (FILE*)fopen_utf8(path, mode_str);
|
if (!(fp = (FILE*)fopen_utf8(path, mode_str)))
|
||||||
|
|
||||||
if (!fp)
|
|
||||||
goto error;
|
goto error;
|
||||||
|
|
||||||
stream->fp = fp;
|
stream->fp = fp;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Regarding setvbuf:
|
/* Regarding setvbuf:
|
||||||
*
|
*
|
||||||
* https://www.freebsd.org/cgi/man.cgi?query=setvbuf&apropos=0&sektion=0&manpath=FreeBSD+11.1-RELEASE&arch=default&format=html
|
* https://www.freebsd.org/cgi/man.cgi?query=setvbuf&apropos=0&sektion=0&manpath=FreeBSD+11.1-RELEASE&arch=default&format=html
|
||||||
@ -455,19 +471,14 @@ libretro_vfs_implementation_file *retro_vfs_file_open_impl(
|
|||||||
#elif defined(WIIU)
|
#elif defined(WIIU)
|
||||||
if (stream->scheme != VFS_SCHEME_CDROM)
|
if (stream->scheme != VFS_SCHEME_CDROM)
|
||||||
{
|
{
|
||||||
const int bufsize = 128*1024;
|
const int bufsize = 128 * 1024;
|
||||||
stream->buf = (char*)memalign(0x40, bufsize);
|
stream->buf = (char*)memalign(0x40, bufsize);
|
||||||
if (stream->fp)
|
if (stream->fp)
|
||||||
setvbuf(stream->fp, stream->buf, _IOFBF, bufsize);
|
setvbuf(stream->fp, stream->buf, _IOFBF, bufsize);
|
||||||
}
|
|
||||||
#elif !defined(PSP)
|
|
||||||
if (stream->scheme != VFS_SCHEME_CDROM)
|
|
||||||
{
|
|
||||||
stream->buf = (char*)calloc(1, 0x4000);
|
stream->buf = (char*)calloc(1, 0x4000);
|
||||||
if (stream->fp)
|
if (stream->fp)
|
||||||
setvbuf(stream->fp, stream->buf, _IOFBF, 0x4000);
|
setvbuf(stream->fp, stream->buf, _IOFBF, 0x4000);
|
||||||
}
|
}
|
||||||
#endif
|
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
@ -503,18 +514,12 @@ libretro_vfs_implementation_file *retro_vfs_file_open_impl(
|
|||||||
|
|
||||||
retro_vfs_file_seek_internal(stream, 0, SEEK_SET);
|
retro_vfs_file_seek_internal(stream, 0, SEEK_SET);
|
||||||
|
|
||||||
stream->mapped = (uint8_t*)mmap((void*)0,
|
if ((stream->mapped = (uint8_t*)mmap((void*)0,
|
||||||
stream->mapsize, PROT_READ, MAP_SHARED, stream->fd, 0);
|
stream->mapsize, PROT_READ, MAP_SHARED, stream->fd, 0)) == MAP_FAILED)
|
||||||
|
|
||||||
if (stream->mapped == MAP_FAILED)
|
|
||||||
stream->hints &= ~RETRO_VFS_FILE_ACCESS_HINT_FREQUENT_ACCESS;
|
stream->hints &= ~RETRO_VFS_FILE_ACCESS_HINT_FREQUENT_ACCESS;
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
#ifdef ORBIS
|
|
||||||
stream->size = orbisLseek(stream->fd, 0, SEEK_END);
|
|
||||||
orbisLseek(stream->fd, 0, SEEK_SET);
|
|
||||||
#else
|
|
||||||
#ifdef HAVE_CDROM
|
#ifdef HAVE_CDROM
|
||||||
if (stream->scheme == VFS_SCHEME_CDROM)
|
if (stream->scheme == VFS_SCHEME_CDROM)
|
||||||
{
|
{
|
||||||
@ -535,7 +540,6 @@ libretro_vfs_implementation_file *retro_vfs_file_open_impl(
|
|||||||
|
|
||||||
retro_vfs_file_seek_internal(stream, 0, SEEK_SET);
|
retro_vfs_file_seek_internal(stream, 0, SEEK_SET);
|
||||||
}
|
}
|
||||||
#endif
|
|
||||||
return stream;
|
return stream;
|
||||||
|
|
||||||
error:
|
error:
|
||||||
@ -570,14 +574,7 @@ int retro_vfs_file_close_impl(libretro_vfs_implementation_file *stream)
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (stream->fd > 0)
|
if (stream->fd > 0)
|
||||||
{
|
|
||||||
#ifdef ORBIS
|
|
||||||
orbisClose(stream->fd);
|
|
||||||
stream->fd = -1;
|
|
||||||
#else
|
|
||||||
close(stream->fd);
|
close(stream->fd);
|
||||||
#endif
|
|
||||||
}
|
|
||||||
#ifdef HAVE_CDROM
|
#ifdef HAVE_CDROM
|
||||||
end:
|
end:
|
||||||
if (stream->cdrom.cue_buf)
|
if (stream->cdrom.cue_buf)
|
||||||
@ -600,12 +597,7 @@ int retro_vfs_file_error_impl(libretro_vfs_implementation_file *stream)
|
|||||||
if (stream->scheme == VFS_SCHEME_CDROM)
|
if (stream->scheme == VFS_SCHEME_CDROM)
|
||||||
return retro_vfs_file_error_cdrom(stream);
|
return retro_vfs_file_error_cdrom(stream);
|
||||||
#endif
|
#endif
|
||||||
#ifdef ORBIS
|
|
||||||
/* TODO/FIXME - implement this? */
|
|
||||||
return 0;
|
|
||||||
#else
|
|
||||||
return ferror(stream->fp);
|
return ferror(stream->fp);
|
||||||
#endif
|
|
||||||
}
|
}
|
||||||
|
|
||||||
int64_t retro_vfs_file_size_impl(libretro_vfs_implementation_file *stream)
|
int64_t retro_vfs_file_size_impl(libretro_vfs_implementation_file *stream)
|
||||||
@ -617,18 +609,20 @@ int64_t retro_vfs_file_size_impl(libretro_vfs_implementation_file *stream)
|
|||||||
|
|
||||||
int64_t retro_vfs_file_truncate_impl(libretro_vfs_implementation_file *stream, int64_t length)
|
int64_t retro_vfs_file_truncate_impl(libretro_vfs_implementation_file *stream, int64_t length)
|
||||||
{
|
{
|
||||||
if (!stream)
|
|
||||||
return -1;
|
|
||||||
|
|
||||||
#ifdef _WIN32
|
#ifdef _WIN32
|
||||||
if (_chsize(_fileno(stream->fp), length) != 0)
|
if (stream && _chsize(_fileno(stream->fp), length) == 0)
|
||||||
return -1;
|
{
|
||||||
|
stream->size = length;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
#elif !defined(VITA) && !defined(PSP) && !defined(PS2) && !defined(ORBIS) && (!defined(SWITCH) || defined(HAVE_LIBNX))
|
#elif !defined(VITA) && !defined(PSP) && !defined(PS2) && !defined(ORBIS) && (!defined(SWITCH) || defined(HAVE_LIBNX))
|
||||||
if (ftruncate(fileno(stream->fp), (off_t)length) != 0)
|
if (stream && ftruncate(fileno(stream->fp), (off_t)length) == 0)
|
||||||
return -1;
|
{
|
||||||
|
stream->size = length;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
#endif
|
#endif
|
||||||
|
return -1;
|
||||||
return 0;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
int64_t retro_vfs_file_tell_impl(libretro_vfs_implementation_file *stream)
|
int64_t retro_vfs_file_tell_impl(libretro_vfs_implementation_file *stream)
|
||||||
@ -642,14 +636,6 @@ int64_t retro_vfs_file_tell_impl(libretro_vfs_implementation_file *stream)
|
|||||||
if (stream->scheme == VFS_SCHEME_CDROM)
|
if (stream->scheme == VFS_SCHEME_CDROM)
|
||||||
return retro_vfs_file_tell_cdrom(stream);
|
return retro_vfs_file_tell_cdrom(stream);
|
||||||
#endif
|
#endif
|
||||||
#ifdef ORBIS
|
|
||||||
{
|
|
||||||
int64_t ret = orbisLseek(stream->fd, 0, SEEK_CUR);
|
|
||||||
if (ret < 0)
|
|
||||||
return -1;
|
|
||||||
return ret;
|
|
||||||
}
|
|
||||||
#else
|
|
||||||
#ifdef ATLEAST_VC2005
|
#ifdef ATLEAST_VC2005
|
||||||
/* VC2005 and up have a special 64-bit ftell */
|
/* VC2005 and up have a special 64-bit ftell */
|
||||||
return _ftelli64(stream->fp);
|
return _ftelli64(stream->fp);
|
||||||
@ -657,7 +643,6 @@ int64_t retro_vfs_file_tell_impl(libretro_vfs_implementation_file *stream)
|
|||||||
return ftello(stream->fp);
|
return ftello(stream->fp);
|
||||||
#else
|
#else
|
||||||
return ftell(stream->fp);
|
return ftell(stream->fp);
|
||||||
#endif
|
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
#ifdef HAVE_MMAP
|
#ifdef HAVE_MMAP
|
||||||
@ -676,21 +661,7 @@ int64_t retro_vfs_file_tell_impl(libretro_vfs_implementation_file *stream)
|
|||||||
int64_t retro_vfs_file_seek_impl(libretro_vfs_implementation_file *stream,
|
int64_t retro_vfs_file_seek_impl(libretro_vfs_implementation_file *stream,
|
||||||
int64_t offset, int seek_position)
|
int64_t offset, int seek_position)
|
||||||
{
|
{
|
||||||
int whence = -1;
|
return retro_vfs_file_seek_internal(stream, offset, seek_position);
|
||||||
switch (seek_position)
|
|
||||||
{
|
|
||||||
case RETRO_VFS_SEEK_POSITION_START:
|
|
||||||
whence = SEEK_SET;
|
|
||||||
break;
|
|
||||||
case RETRO_VFS_SEEK_POSITION_CURRENT:
|
|
||||||
whence = SEEK_CUR;
|
|
||||||
break;
|
|
||||||
case RETRO_VFS_SEEK_POSITION_END:
|
|
||||||
whence = SEEK_END;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
return retro_vfs_file_seek_internal(stream, offset, whence);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
int64_t retro_vfs_file_read_impl(libretro_vfs_implementation_file *stream,
|
int64_t retro_vfs_file_read_impl(libretro_vfs_implementation_file *stream,
|
||||||
@ -705,13 +676,7 @@ int64_t retro_vfs_file_read_impl(libretro_vfs_implementation_file *stream,
|
|||||||
if (stream->scheme == VFS_SCHEME_CDROM)
|
if (stream->scheme == VFS_SCHEME_CDROM)
|
||||||
return retro_vfs_file_read_cdrom(stream, s, len);
|
return retro_vfs_file_read_cdrom(stream, s, len);
|
||||||
#endif
|
#endif
|
||||||
#ifdef ORBIS
|
|
||||||
if (orbisRead(stream->fd, s, (size_t)len) < 0)
|
|
||||||
return -1;
|
|
||||||
return 0;
|
|
||||||
#else
|
|
||||||
return fread(s, 1, (size_t)len, stream->fp);
|
return fread(s, 1, (size_t)len, stream->fp);
|
||||||
#endif
|
|
||||||
}
|
}
|
||||||
#ifdef HAVE_MMAP
|
#ifdef HAVE_MMAP
|
||||||
if (stream->hints & RETRO_VFS_FILE_ACCESS_HINT_FREQUENT_ACCESS)
|
if (stream->hints & RETRO_VFS_FILE_ACCESS_HINT_FREQUENT_ACCESS)
|
||||||
@ -734,36 +699,41 @@ int64_t retro_vfs_file_read_impl(libretro_vfs_implementation_file *stream,
|
|||||||
|
|
||||||
int64_t retro_vfs_file_write_impl(libretro_vfs_implementation_file *stream, const void *s, uint64_t len)
|
int64_t retro_vfs_file_write_impl(libretro_vfs_implementation_file *stream, const void *s, uint64_t len)
|
||||||
{
|
{
|
||||||
|
int64_t pos = 0;
|
||||||
|
size_t result = -1;
|
||||||
|
|
||||||
if (!stream)
|
if (!stream)
|
||||||
return -1;
|
return -1;
|
||||||
|
|
||||||
if ((stream->hints & RFILE_HINT_UNBUFFERED) == 0)
|
if ((stream->hints & RFILE_HINT_UNBUFFERED) == 0)
|
||||||
{
|
{
|
||||||
#ifdef ORBIS
|
pos = retro_vfs_file_tell_impl(stream);
|
||||||
if (orbisWrite(stream->fd, s, (size_t)len) < 0)
|
result = fwrite(s, 1, (size_t)len, stream->fp);
|
||||||
return -1;
|
|
||||||
return 0;
|
|
||||||
#else
|
|
||||||
return fwrite(s, 1, (size_t)len, stream->fp);
|
|
||||||
#endif
|
|
||||||
}
|
|
||||||
|
|
||||||
|
if (result != -1 && pos + result > stream->size)
|
||||||
|
stream->size = pos + result;
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
#ifdef HAVE_MMAP
|
#ifdef HAVE_MMAP
|
||||||
if (stream->hints & RETRO_VFS_FILE_ACCESS_HINT_FREQUENT_ACCESS)
|
if (stream->hints & RETRO_VFS_FILE_ACCESS_HINT_FREQUENT_ACCESS)
|
||||||
return -1;
|
return -1;
|
||||||
#endif
|
#endif
|
||||||
return write(stream->fd, s, (size_t)len);
|
|
||||||
|
pos = retro_vfs_file_tell_impl(stream);
|
||||||
|
result = write(stream->fd, s, (size_t)len);
|
||||||
|
|
||||||
|
if (result != -1 && pos + result > stream->size)
|
||||||
|
stream->size = pos + result;
|
||||||
|
|
||||||
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
int retro_vfs_file_flush_impl(libretro_vfs_implementation_file *stream)
|
int retro_vfs_file_flush_impl(libretro_vfs_implementation_file *stream)
|
||||||
{
|
{
|
||||||
if (!stream)
|
if (stream && fflush(stream->fp) == 0)
|
||||||
return -1;
|
return 0;
|
||||||
#ifdef ORBIS
|
return -1;
|
||||||
return 0;
|
|
||||||
#else
|
|
||||||
return fflush(stream->fp) == 0 ? 0 : -1;
|
|
||||||
#endif
|
|
||||||
}
|
}
|
||||||
|
|
||||||
int retro_vfs_file_remove_impl(const char *path)
|
int retro_vfs_file_remove_impl(const char *path)
|
||||||
@ -779,9 +749,7 @@ int retro_vfs_file_remove_impl(const char *path)
|
|||||||
if (!path || !*path)
|
if (!path || !*path)
|
||||||
return -1;
|
return -1;
|
||||||
#if defined(_WIN32_WINNT) && _WIN32_WINNT < 0x0500
|
#if defined(_WIN32_WINNT) && _WIN32_WINNT < 0x0500
|
||||||
path_local = utf8_to_local_string_alloc(path);
|
if ((path_local = utf8_to_local_string_alloc(path)))
|
||||||
|
|
||||||
if (path_local)
|
|
||||||
{
|
{
|
||||||
int ret = remove(path_local);
|
int ret = remove(path_local);
|
||||||
free(path_local);
|
free(path_local);
|
||||||
@ -790,9 +758,7 @@ int retro_vfs_file_remove_impl(const char *path)
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
#else
|
#else
|
||||||
path_wide = utf8_to_utf16_string_alloc(path);
|
if ((path_wide = utf8_to_utf16_string_alloc(path)))
|
||||||
|
|
||||||
if (path_wide)
|
|
||||||
{
|
{
|
||||||
int ret = _wremove(path_wide);
|
int ret = _wremove(path_wide);
|
||||||
free(path_wide);
|
free(path_wide);
|
||||||
@ -801,16 +767,11 @@ int retro_vfs_file_remove_impl(const char *path)
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
return -1;
|
|
||||||
#elif defined(ORBIS)
|
|
||||||
/* Orbis
|
|
||||||
* TODO/FIXME - stub for now */
|
|
||||||
return 0;
|
|
||||||
#else
|
#else
|
||||||
if (remove(path) == 0)
|
if (remove(path) == 0)
|
||||||
return 0;
|
return 0;
|
||||||
return -1;
|
|
||||||
#endif
|
#endif
|
||||||
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
int retro_vfs_file_rename_impl(const char *old_path, const char *new_path)
|
int retro_vfs_file_rename_impl(const char *old_path, const char *new_path)
|
||||||
@ -862,13 +823,6 @@ int retro_vfs_file_rename_impl(const char *old_path, const char *new_path)
|
|||||||
#endif
|
#endif
|
||||||
return ret;
|
return ret;
|
||||||
|
|
||||||
#elif defined(ORBIS)
|
|
||||||
/* Orbis */
|
|
||||||
/* TODO/FIXME - Stub for now */
|
|
||||||
if (!old_path || !*old_path || !new_path || !*new_path)
|
|
||||||
return -1;
|
|
||||||
return 0;
|
|
||||||
|
|
||||||
#else
|
#else
|
||||||
/* Every other platform */
|
/* Every other platform */
|
||||||
if (!old_path || !*old_path || !new_path || !*new_path)
|
if (!old_path || !*old_path || !new_path || !*new_path)
|
||||||
@ -890,7 +844,7 @@ int retro_vfs_stat_impl(const char *path, int32_t *size)
|
|||||||
{
|
{
|
||||||
bool is_dir = false;
|
bool is_dir = false;
|
||||||
bool is_character_special = false;
|
bool is_character_special = false;
|
||||||
#if defined(VITA) || defined(PSP)
|
#if defined(VITA)
|
||||||
/* Vita / PSP */
|
/* Vita / PSP */
|
||||||
SceIoStat buf;
|
SceIoStat buf;
|
||||||
int dir_ret;
|
int dir_ret;
|
||||||
@ -903,7 +857,7 @@ int retro_vfs_stat_impl(const char *path, int32_t *size)
|
|||||||
tmp = strdup(path);
|
tmp = strdup(path);
|
||||||
len = strlen(tmp);
|
len = strlen(tmp);
|
||||||
if (tmp[len-1] == '/')
|
if (tmp[len-1] == '/')
|
||||||
tmp[len-1] = '\0';
|
tmp[len-1] = '\0';
|
||||||
|
|
||||||
dir_ret = sceIoGetstat(tmp, &buf);
|
dir_ret = sceIoGetstat(tmp, &buf);
|
||||||
free(tmp);
|
free(tmp);
|
||||||
@ -914,21 +868,6 @@ int retro_vfs_stat_impl(const char *path, int32_t *size)
|
|||||||
*size = (int32_t)buf.st_size;
|
*size = (int32_t)buf.st_size;
|
||||||
|
|
||||||
is_dir = FIO_S_ISDIR(buf.st_mode);
|
is_dir = FIO_S_ISDIR(buf.st_mode);
|
||||||
#elif defined(ORBIS)
|
|
||||||
/* Orbis */
|
|
||||||
int dir_ret = 0;
|
|
||||||
|
|
||||||
if (!path || !*path)
|
|
||||||
return 0;
|
|
||||||
|
|
||||||
if (size)
|
|
||||||
*size = (int32_t)buf.st_size;
|
|
||||||
|
|
||||||
dir_ret = orbisDopen(path);
|
|
||||||
is_dir = dir_ret > 0;
|
|
||||||
orbisDclose(dir_ret);
|
|
||||||
|
|
||||||
is_character_special = S_ISCHR(buf.st_mode);
|
|
||||||
#elif defined(__PSL1GHT__) || defined(__PS3__)
|
#elif defined(__PSL1GHT__) || defined(__PS3__)
|
||||||
/* Lowlevel Lv2 */
|
/* Lowlevel Lv2 */
|
||||||
sysFSStat buf;
|
sysFSStat buf;
|
||||||
@ -994,12 +933,10 @@ int retro_vfs_stat_impl(const char *path, int32_t *size)
|
|||||||
if (string_is_empty(path))
|
if (string_is_empty(path))
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
path_buf = strdup(path);
|
if (!(path_buf = strdup(path)))
|
||||||
if (!path_buf)
|
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
len = strlen(path_buf);
|
if ((len = strlen(path_buf)) > 0)
|
||||||
if (len > 0)
|
|
||||||
if (path_buf[len - 1] == '/')
|
if (path_buf[len - 1] == '/')
|
||||||
path_buf[len - 1] = '\0';
|
path_buf[len - 1] = '\0';
|
||||||
|
|
||||||
@ -1035,7 +972,7 @@ int retro_vfs_stat_impl(const char *path, int32_t *size)
|
|||||||
|
|
||||||
#if defined(VITA)
|
#if defined(VITA)
|
||||||
#define path_mkdir_error(ret) (((ret) == SCE_ERROR_ERRNO_EEXIST))
|
#define path_mkdir_error(ret) (((ret) == SCE_ERROR_ERRNO_EEXIST))
|
||||||
#elif defined(PSP) || defined(PS2) || defined(_3DS) || defined(WIIU) || defined(SWITCH) || defined(ORBIS)
|
#elif defined(PSP) || defined(PS2) || defined(_3DS) || defined(WIIU) || defined(SWITCH)
|
||||||
#define path_mkdir_error(ret) ((ret) == -1)
|
#define path_mkdir_error(ret) ((ret) == -1)
|
||||||
#else
|
#else
|
||||||
#define path_mkdir_error(ret) ((ret) < 0 && errno == EEXIST)
|
#define path_mkdir_error(ret) ((ret) < 0 && errno == EEXIST)
|
||||||
@ -1058,13 +995,11 @@ int retro_vfs_mkdir_impl(const char *dir)
|
|||||||
#endif
|
#endif
|
||||||
#elif defined(IOS)
|
#elif defined(IOS)
|
||||||
int ret = mkdir(dir, 0755);
|
int ret = mkdir(dir, 0755);
|
||||||
#elif defined(VITA) || defined(PSP)
|
#elif defined(VITA)
|
||||||
int ret = sceIoMkdir(dir, 0777);
|
int ret = sceIoMkdir(dir, 0777);
|
||||||
#elif defined(ORBIS)
|
|
||||||
int ret = orbisMkdir(dir, 0755);
|
|
||||||
#elif defined(__QNX__)
|
#elif defined(__QNX__)
|
||||||
int ret = mkdir(dir, 0777);
|
int ret = mkdir(dir, 0777);
|
||||||
#elif defined(GEKKO)
|
#elif defined(GEKKO) || defined(WIIU)
|
||||||
/* On GEKKO platforms, mkdir() fails if
|
/* On GEKKO platforms, mkdir() fails if
|
||||||
* the path has a trailing slash. We must
|
* the path has a trailing slash. We must
|
||||||
* therefore remove it. */
|
* therefore remove it. */
|
||||||
@ -1111,16 +1046,13 @@ struct libretro_vfs_implementation_dir
|
|||||||
HANDLE directory;
|
HANDLE directory;
|
||||||
bool next;
|
bool next;
|
||||||
char path[PATH_MAX_LENGTH];
|
char path[PATH_MAX_LENGTH];
|
||||||
#elif defined(VITA) || defined(PSP)
|
#elif defined(VITA)
|
||||||
SceUID directory;
|
SceUID directory;
|
||||||
SceIoDirent entry;
|
SceIoDirent entry;
|
||||||
#elif defined(__PSL1GHT__) || defined(__PS3__)
|
#elif defined(__PSL1GHT__) || defined(__PS3__)
|
||||||
int error;
|
int error;
|
||||||
int directory;
|
int directory;
|
||||||
sysFSDirent entry;
|
sysFSDirent entry;
|
||||||
#elif defined(ORBIS)
|
|
||||||
int directory;
|
|
||||||
struct dirent entry;
|
|
||||||
#else
|
#else
|
||||||
DIR *directory;
|
DIR *directory;
|
||||||
const struct dirent *entry;
|
const struct dirent *entry;
|
||||||
@ -1131,7 +1063,7 @@ static bool dirent_check_error(libretro_vfs_implementation_dir *rdir)
|
|||||||
{
|
{
|
||||||
#if defined(_WIN32)
|
#if defined(_WIN32)
|
||||||
return (rdir->directory == INVALID_HANDLE_VALUE);
|
return (rdir->directory == INVALID_HANDLE_VALUE);
|
||||||
#elif defined(VITA) || defined(PSP) || defined(ORBIS)
|
#elif defined(VITA) || defined(ORBIS)
|
||||||
return (rdir->directory < 0);
|
return (rdir->directory < 0);
|
||||||
#elif defined(__PSL1GHT__) || defined(__PS3__)
|
#elif defined(__PSL1GHT__) || defined(__PS3__)
|
||||||
return (rdir->error != FS_SUCCEEDED);
|
return (rdir->error != FS_SUCCEEDED);
|
||||||
@ -1144,7 +1076,6 @@ libretro_vfs_implementation_dir *retro_vfs_opendir_impl(
|
|||||||
const char *name, bool include_hidden)
|
const char *name, bool include_hidden)
|
||||||
{
|
{
|
||||||
#if defined(_WIN32)
|
#if defined(_WIN32)
|
||||||
unsigned path_len;
|
|
||||||
char path_buf[1024];
|
char path_buf[1024];
|
||||||
size_t copied = 0;
|
size_t copied = 0;
|
||||||
#if defined(LEGACY_WIN32)
|
#if defined(LEGACY_WIN32)
|
||||||
@ -1155,28 +1086,25 @@ libretro_vfs_implementation_dir *retro_vfs_opendir_impl(
|
|||||||
#endif
|
#endif
|
||||||
libretro_vfs_implementation_dir *rdir;
|
libretro_vfs_implementation_dir *rdir;
|
||||||
|
|
||||||
/*Reject null or empty string paths*/
|
/* Reject NULL or empty string paths*/
|
||||||
if (!name || (*name == 0))
|
if (!name || (*name == 0))
|
||||||
return NULL;
|
return NULL;
|
||||||
|
|
||||||
/*Allocate RDIR struct. Tidied later with retro_closedir*/
|
/*Allocate RDIR struct. Tidied later with retro_closedir*/
|
||||||
rdir = (libretro_vfs_implementation_dir*)calloc(1, sizeof(*rdir));
|
if (!(rdir = (libretro_vfs_implementation_dir*)
|
||||||
if (!rdir)
|
calloc(1, sizeof(*rdir))))
|
||||||
return NULL;
|
return NULL;
|
||||||
|
|
||||||
rdir->orig_path = strdup(name);
|
rdir->orig_path = strdup(name);
|
||||||
|
|
||||||
#if defined(_WIN32)
|
#if defined(_WIN32)
|
||||||
path_buf[0] = '\0';
|
|
||||||
path_len = strlen(name);
|
|
||||||
|
|
||||||
copied = strlcpy(path_buf, name, sizeof(path_buf));
|
copied = strlcpy(path_buf, name, sizeof(path_buf));
|
||||||
|
|
||||||
/* Non-NT platforms don't like extra slashes in the path */
|
/* Non-NT platforms don't like extra slashes in the path */
|
||||||
if (name[path_len - 1] != '\\')
|
if (path_buf[copied - 1] != '\\')
|
||||||
path_buf[copied++] = '\\';
|
path_buf [copied++] = '\\';
|
||||||
|
|
||||||
path_buf[copied] = '*';
|
path_buf[copied ] = '*';
|
||||||
path_buf[copied+1] = '\0';
|
path_buf[copied+1] = '\0';
|
||||||
|
|
||||||
#if defined(LEGACY_WIN32)
|
#if defined(LEGACY_WIN32)
|
||||||
@ -1193,15 +1121,13 @@ libretro_vfs_implementation_dir *retro_vfs_opendir_impl(
|
|||||||
free(path_wide);
|
free(path_wide);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#elif defined(VITA) || defined(PSP)
|
#elif defined(VITA)
|
||||||
rdir->directory = sceIoDopen(name);
|
rdir->directory = sceIoDopen(name);
|
||||||
#elif defined(_3DS)
|
#elif defined(_3DS)
|
||||||
rdir->directory = !string_is_empty(name) ? opendir(name) : NULL;
|
rdir->directory = !string_is_empty(name) ? opendir(name) : NULL;
|
||||||
rdir->entry = NULL;
|
rdir->entry = NULL;
|
||||||
#elif defined(__PSL1GHT__) || defined(__PS3__)
|
#elif defined(__PSL1GHT__) || defined(__PS3__)
|
||||||
rdir->error = sysFsOpendir(name, &rdir->directory);
|
rdir->error = sysFsOpendir(name, &rdir->directory);
|
||||||
#elif defined(ORBIS)
|
|
||||||
rdir->directory = orbisDopen(name);
|
|
||||||
#else
|
#else
|
||||||
rdir->directory = opendir(name);
|
rdir->directory = opendir(name);
|
||||||
rdir->entry = NULL;
|
rdir->entry = NULL;
|
||||||
@ -1233,14 +1159,12 @@ bool retro_vfs_readdir_impl(libretro_vfs_implementation_dir *rdir)
|
|||||||
|
|
||||||
rdir->next = true;
|
rdir->next = true;
|
||||||
return (rdir->directory != INVALID_HANDLE_VALUE);
|
return (rdir->directory != INVALID_HANDLE_VALUE);
|
||||||
#elif defined(VITA) || defined(PSP)
|
#elif defined(VITA)
|
||||||
return (sceIoDread(rdir->directory, &rdir->entry) > 0);
|
return (sceIoDread(rdir->directory, &rdir->entry) > 0);
|
||||||
#elif defined(__PSL1GHT__) || defined(__PS3__)
|
#elif defined(__PSL1GHT__) || defined(__PS3__)
|
||||||
uint64_t nread;
|
uint64_t nread;
|
||||||
rdir->error = sysFsReaddir(rdir->directory, &rdir->entry, &nread);
|
rdir->error = sysFsReaddir(rdir->directory, &rdir->entry, &nread);
|
||||||
return (nread != 0);
|
return (nread != 0);
|
||||||
#elif defined(ORBIS)
|
|
||||||
return (orbisDread(rdir->directory, &rdir->entry) > 0);
|
|
||||||
#else
|
#else
|
||||||
return ((rdir->entry = readdir(rdir->directory)) != NULL);
|
return ((rdir->entry = readdir(rdir->directory)) != NULL);
|
||||||
#endif
|
#endif
|
||||||
@ -1259,7 +1183,7 @@ const char *retro_vfs_dirent_get_name_impl(libretro_vfs_implementation_dir *rdir
|
|||||||
if (name)
|
if (name)
|
||||||
free(name);
|
free(name);
|
||||||
return (char*)rdir->entry.cFileName;
|
return (char*)rdir->entry.cFileName;
|
||||||
#elif defined(VITA) || defined(PSP) || defined(ORBIS) || defined(__PSL1GHT__) || defined(__PS3__)
|
#elif defined(VITA) || defined(__PSL1GHT__) || defined(__PS3__)
|
||||||
return rdir->entry.d_name;
|
return rdir->entry.d_name;
|
||||||
#else
|
#else
|
||||||
if (!rdir || !rdir->entry)
|
if (!rdir || !rdir->entry)
|
||||||
@ -1273,22 +1197,12 @@ bool retro_vfs_dirent_is_dir_impl(libretro_vfs_implementation_dir *rdir)
|
|||||||
#if defined(_WIN32)
|
#if defined(_WIN32)
|
||||||
const WIN32_FIND_DATA *entry = (const WIN32_FIND_DATA*)&rdir->entry;
|
const WIN32_FIND_DATA *entry = (const WIN32_FIND_DATA*)&rdir->entry;
|
||||||
return entry->dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY;
|
return entry->dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY;
|
||||||
#elif defined(PSP) || defined(VITA)
|
|
||||||
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)
|
#elif defined(VITA)
|
||||||
|
const SceIoDirent *entry = (const SceIoDirent*)&rdir->entry;
|
||||||
return SCE_S_ISDIR(entry->d_stat.st_mode);
|
return SCE_S_ISDIR(entry->d_stat.st_mode);
|
||||||
#endif
|
|
||||||
#elif defined(__PSL1GHT__) || defined(__PS3__)
|
#elif defined(__PSL1GHT__) || defined(__PS3__)
|
||||||
sysFSDirent *entry = (sysFSDirent*)&rdir->entry;
|
sysFSDirent *entry = (sysFSDirent*)&rdir->entry;
|
||||||
return (entry->d_type == FS_TYPE_DIR);
|
return (entry->d_type == FS_TYPE_DIR);
|
||||||
#elif defined(ORBIS)
|
|
||||||
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))
|
|
||||||
return false;
|
|
||||||
#else
|
#else
|
||||||
struct stat buf;
|
struct stat buf;
|
||||||
char path[PATH_MAX_LENGTH];
|
char path[PATH_MAX_LENGTH];
|
||||||
@ -1301,8 +1215,7 @@ bool retro_vfs_dirent_is_dir_impl(libretro_vfs_implementation_dir *rdir)
|
|||||||
return false;
|
return false;
|
||||||
#endif
|
#endif
|
||||||
/* dirent struct doesn't have d_type, do it the slow way ... */
|
/* dirent struct doesn't have d_type, do it the slow way ... */
|
||||||
path[0] = '\0';
|
fill_pathname_join_special(path, rdir->orig_path, retro_vfs_dirent_get_name_impl(rdir), sizeof(path));
|
||||||
fill_pathname_join(path, rdir->orig_path, retro_vfs_dirent_get_name_impl(rdir), sizeof(path));
|
|
||||||
if (stat(path, &buf) < 0)
|
if (stat(path, &buf) < 0)
|
||||||
return false;
|
return false;
|
||||||
return S_ISDIR(buf.st_mode);
|
return S_ISDIR(buf.st_mode);
|
||||||
@ -1317,12 +1230,10 @@ int retro_vfs_closedir_impl(libretro_vfs_implementation_dir *rdir)
|
|||||||
#if defined(_WIN32)
|
#if defined(_WIN32)
|
||||||
if (rdir->directory != INVALID_HANDLE_VALUE)
|
if (rdir->directory != INVALID_HANDLE_VALUE)
|
||||||
FindClose(rdir->directory);
|
FindClose(rdir->directory);
|
||||||
#elif defined(VITA) || defined(PSP)
|
#elif defined(VITA)
|
||||||
sceIoDclose(rdir->directory);
|
sceIoDclose(rdir->directory);
|
||||||
#elif defined(__PSL1GHT__) || defined(__PS3__)
|
#elif defined(__PSL1GHT__) || defined(__PS3__)
|
||||||
rdir->error = sysFsClosedir(rdir->directory);
|
rdir->error = sysFsClosedir(rdir->directory);
|
||||||
#elif defined(ORBIS)
|
|
||||||
orbisDclose(rdir->directory);
|
|
||||||
#else
|
#else
|
||||||
if (rdir->directory)
|
if (rdir->directory)
|
||||||
closedir(rdir->directory);
|
closedir(rdir->directory);
|
||||||
|
File diff suppressed because it is too large
Load Diff
Loading…
Reference in New Issue
Block a user