mirror of
https://github.com/libretro/gambatte-libretro.git
synced 2024-11-23 07:49:48 +00:00
This reverts commit 9481e11d50
.
This commit is contained in:
parent
fe131fb544
commit
5d47507d3e
@ -60,3 +60,10 @@ 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,28 +37,27 @@
|
|||||||
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);
|
||||||
return ret;
|
if (mode_w)
|
||||||
}
|
free(mode_w);
|
||||||
|
return ret;
|
||||||
#endif
|
#endif
|
||||||
return NULL;
|
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
@ -51,12 +51,9 @@ static unsigned leading_ones(uint8_t c)
|
|||||||
return ones;
|
return ones;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/* Simple implementation. Assumes the sequence is
|
||||||
* utf8_conv_utf32:
|
* properly synchronized and terminated. */
|
||||||
*
|
|
||||||
* 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)
|
||||||
{
|
{
|
||||||
@ -82,7 +79,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++;
|
||||||
@ -91,11 +88,6 @@ 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)
|
||||||
{
|
{
|
||||||
@ -156,20 +148,16 @@ 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. Does not copy half a character.
|
* Always NULL terminates.
|
||||||
* @s is assumed valid UTF-8.
|
* Does not copy half a character.
|
||||||
* Use only if @chars is considerably less than @d_len.
|
|
||||||
*
|
*
|
||||||
* @return Number of bytes.
|
* Returns number of bytes. 's' is assumed valid UTF-8.
|
||||||
**/
|
* 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;
|
||||||
@ -198,11 +186,6 @@ 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;
|
||||||
@ -221,11 +204,6 @@ 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;
|
||||||
@ -242,15 +220,7 @@ 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);
|
||||||
@ -278,23 +248,24 @@ 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;
|
||||||
if ((*utf_data = (uint8_t*)malloc(*dest_len)) != 0)
|
*utf_data = (uint8_t*)malloc(*dest_len);
|
||||||
return utf16_conv_utf8(*utf_data, dest_len, in, len);
|
if (*utf_data == 0)
|
||||||
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)
|
||||||
{
|
{
|
||||||
@ -303,17 +274,13 @@ 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)
|
||||||
{
|
{
|
||||||
@ -333,8 +300,10 @@ 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);
|
||||||
|
|
||||||
if ((path_buf_wide = (wchar_t*)
|
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);
|
||||||
@ -378,49 +347,45 @@ 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
|
||||||
return strdup(str); /* Assume string needs no modification if not on Windows */
|
/* 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. */
|
||||||
* local_to_utf8_string_alloc:
|
char* local_to_utf8_string_alloc(const char *str)
|
||||||
*
|
|
||||||
* @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
|
||||||
return strdup(str); /* Assume string needs no modification if not on Windows */
|
/* 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;
|
||||||
|
|
||||||
@ -428,55 +393,63 @@ wchar_t* utf8_to_utf16_string_alloc(const char *str)
|
|||||||
return NULL;
|
return NULL;
|
||||||
|
|
||||||
#ifdef _WIN32
|
#ifdef _WIN32
|
||||||
if ((len = MultiByteToWideChar(CP_UTF8, 0, str, -1, NULL, 0)))
|
len = MultiByteToWideChar(CP_UTF8, 0, str, -1, NULL, 0);
|
||||||
|
|
||||||
|
if (len)
|
||||||
{
|
{
|
||||||
if (!(buf = (wchar_t*)calloc(len, sizeof(wchar_t))))
|
buf = (wchar_t*)calloc(len, sizeof(wchar_t));
|
||||||
|
|
||||||
|
if (!buf)
|
||||||
return NULL;
|
return NULL;
|
||||||
|
|
||||||
if ((MultiByteToWideChar(CP_UTF8, 0, str, -1, buf, len)) < 0)
|
out_len = MultiByteToWideChar(CP_UTF8, 0, str, -1, buf, len);
|
||||||
{
|
|
||||||
free(buf);
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
/* Fallback to ANSI codepage instead */
|
/* fallback to ANSI codepage instead */
|
||||||
if ((len = MultiByteToWideChar(CP_ACP, 0, str, -1, NULL, 0)))
|
len = MultiByteToWideChar(CP_ACP, 0, str, -1, NULL, 0);
|
||||||
|
|
||||||
|
if (len)
|
||||||
{
|
{
|
||||||
if (!(buf = (wchar_t*)calloc(len, sizeof(wchar_t))))
|
buf = (wchar_t*)calloc(len, sizeof(wchar_t));
|
||||||
|
|
||||||
|
if (!buf)
|
||||||
return NULL;
|
return NULL;
|
||||||
|
|
||||||
if ((MultiByteToWideChar(CP_ACP, 0, str, -1, buf, len)) < 0)
|
out_len = MultiByteToWideChar(CP_ACP, 0, str, -1, buf, len);
|
||||||
{
|
|
||||||
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. */
|
||||||
if ((len = mbstowcs(NULL, str, 0) + 1))
|
len = mbstowcs(NULL, str, 0) + 1;
|
||||||
|
|
||||||
|
if (len)
|
||||||
{
|
{
|
||||||
if (!(buf = (wchar_t*)calloc(len, sizeof(wchar_t))))
|
buf = (wchar_t*)calloc(len, sizeof(wchar_t));
|
||||||
|
|
||||||
|
if (!buf)
|
||||||
return NULL;
|
return NULL;
|
||||||
|
|
||||||
if ((mbstowcs(buf, str, len)) == (size_t)-1)
|
out_len = mbstowcs(buf, str, len);
|
||||||
{
|
}
|
||||||
free(buf);
|
|
||||||
return NULL;
|
if (out_len == (size_t)-1)
|
||||||
}
|
{
|
||||||
|
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
|
||||||
@ -492,17 +465,20 @@ 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 = WideCharToMultiByte(code_page,
|
if (!len)
|
||||||
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);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!(buf = (char*)calloc(len, sizeof(char))))
|
buf = (char*)calloc(len, sizeof(char));
|
||||||
|
|
||||||
|
if (!buf)
|
||||||
return NULL;
|
return NULL;
|
||||||
|
|
||||||
if (WideCharToMultiByte(code_page,
|
if (WideCharToMultiByte(code_page,
|
||||||
@ -515,9 +491,13 @@ 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. */
|
||||||
if ((len = wcstombs(NULL, str, 0) + 1))
|
len = wcstombs(NULL, str, 0) + 1;
|
||||||
|
|
||||||
|
if (len)
|
||||||
{
|
{
|
||||||
if (!(buf = (char*)calloc(len, sizeof(char))))
|
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)
|
||||||
|
File diff suppressed because it is too large
Load Diff
@ -24,11 +24,13 @@
|
|||||||
#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>
|
||||||
@ -72,7 +74,7 @@ int path_stat(const char *path)
|
|||||||
*
|
*
|
||||||
* Checks if path is a directory.
|
* Checks if path is a directory.
|
||||||
*
|
*
|
||||||
* @return true if path is a directory, otherwise false.
|
* Returns: true (1) if path is a directory, otherwise false (0).
|
||||||
*/
|
*/
|
||||||
bool path_is_directory(const char *path)
|
bool path_is_directory(const char *path)
|
||||||
{
|
{
|
||||||
@ -103,10 +105,8 @@ int32_t path_get_size(const char *path)
|
|||||||
* @dir : directory
|
* @dir : directory
|
||||||
*
|
*
|
||||||
* Create directory on filesystem.
|
* Create directory on filesystem.
|
||||||
*
|
|
||||||
* Recursive function.
|
|
||||||
*
|
*
|
||||||
* @return true if directory could be created, otherwise false.
|
* Returns: true (1) if directory could be created, otherwise false (0).
|
||||||
**/
|
**/
|
||||||
bool path_mkdir(const char *dir)
|
bool path_mkdir(const char *dir)
|
||||||
{
|
{
|
||||||
@ -118,10 +118,12 @@ 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. */
|
||||||
if (!(basedir = strdup(dir)))
|
basedir = strdup(dir);
|
||||||
return false;
|
|
||||||
|
|
||||||
path_parent_dir(basedir, strlen(basedir));
|
if (!basedir)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
path_parent_dir(basedir);
|
||||||
|
|
||||||
if (!*basedir || !strcmp(basedir, dir))
|
if (!*basedir || !strcmp(basedir, dir))
|
||||||
{
|
{
|
||||||
|
@ -229,6 +229,18 @@ RHMAP__UNUSED static void* rhmap__grow(void* old_ptr, size_t elem_size, size_t r
|
|||||||
return new_vals;
|
return new_vals;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
RHMAP__UNUSED static char* rhmap__strdup(const char * str)
|
||||||
|
{
|
||||||
|
size_t full_len = strlen(str) + 1;
|
||||||
|
char *dup_str = (char *)malloc(full_len);
|
||||||
|
|
||||||
|
if (!dup_str)
|
||||||
|
return NULL;
|
||||||
|
|
||||||
|
memcpy(dup_str, str, full_len);
|
||||||
|
return dup_str;
|
||||||
|
}
|
||||||
|
|
||||||
RHMAP__UNUSED static ptrdiff_t rhmap__idx(struct rhmap__hdr* hdr, uint32_t key, const char * str, int add, size_t del)
|
RHMAP__UNUSED static ptrdiff_t rhmap__idx(struct rhmap__hdr* hdr, uint32_t key, const char * str, int add, size_t del)
|
||||||
{
|
{
|
||||||
uint32_t i;
|
uint32_t i;
|
||||||
@ -261,7 +273,7 @@ RHMAP__UNUSED static ptrdiff_t rhmap__idx(struct rhmap__hdr* hdr, uint32_t key,
|
|||||||
}
|
}
|
||||||
if (!hdr->keys[i])
|
if (!hdr->keys[i])
|
||||||
{
|
{
|
||||||
if (add) { hdr->len++; hdr->keys[i] = key; if (str) hdr->key_strs[i] = strdup(str); return (ptrdiff_t)i; }
|
if (add) { hdr->len++; hdr->keys[i] = key; if (str) hdr->key_strs[i] = rhmap__strdup(str); return (ptrdiff_t)i; }
|
||||||
return (ptrdiff_t)-1;
|
return (ptrdiff_t)-1;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -38,99 +38,29 @@ 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
|
||||||
|
|
||||||
|
@ -51,28 +51,6 @@ 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
|
||||||
@ -103,12 +81,12 @@ bool path_is_compressed_file(const char *path);
|
|||||||
* path_get_archive_delim:
|
* path_get_archive_delim:
|
||||||
* @path : path
|
* @path : path
|
||||||
*
|
*
|
||||||
* Find delimiter of an archive file. Only the first '#'
|
* Gets delimiter of an archive file. Only the first '#'
|
||||||
* after a compression extension is considered.
|
* after a compression extension is considered.
|
||||||
*
|
*
|
||||||
* @return pointer to the delimiter in the path if it contains
|
* Returns: pointer to the delimiter in the path if it contains
|
||||||
* a path inside a compressed file, otherwise NULL.
|
* a compressed file, otherwise NULL.
|
||||||
**/
|
*/
|
||||||
const char *path_get_archive_delim(const char *path);
|
const char *path_get_archive_delim(const char *path);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -118,28 +96,10 @@ 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.
|
||||||
*
|
*
|
||||||
* Hidden non-leaf function cost:
|
* Returns: extension part from the path.
|
||||||
* - 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
|
||||||
@ -148,10 +108,7 @@ char *path_get_extension_mutable(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.
|
||||||
*
|
*
|
||||||
* Hidden non-leaf function cost:
|
* Returns:
|
||||||
* - 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.
|
||||||
@ -165,26 +122,9 @@ char *path_remove_extension(char *path);
|
|||||||
*
|
*
|
||||||
* Get basename from @path.
|
* Get basename from @path.
|
||||||
*
|
*
|
||||||
* Hidden non-leaf function cost:
|
* Returns: basename from path.
|
||||||
* - 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);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -199,13 +139,12 @@ 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, size_t len);
|
void path_parent_dir(char *path);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* path_resolve_realpath:
|
* path_resolve_realpath:
|
||||||
@ -217,7 +156,7 @@ void path_parent_dir(char *path, size_t len);
|
|||||||
*
|
*
|
||||||
* Relative paths are rebased on the current working dir.
|
* Relative paths are rebased on the current working dir.
|
||||||
*
|
*
|
||||||
* @return @buf if successful, NULL otherwise.
|
* Returns: @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,
|
||||||
@ -239,11 +178,8 @@ 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 path_relative_to(char *out, const char *path, const char *base, size_t size);
|
||||||
size_t size);
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* path_is_absolute:
|
* path_is_absolute:
|
||||||
@ -251,7 +187,7 @@ size_t path_relative_to(char *out, const char *path, const char *base,
|
|||||||
*
|
*
|
||||||
* Checks if @path is an absolute path or a relative path.
|
* Checks if @path is an absolute path or a relative path.
|
||||||
*
|
*
|
||||||
* @return true if path is absolute, false if path is relative.
|
* Returns: true if path is absolute, false if path is relative.
|
||||||
**/
|
**/
|
||||||
bool path_is_absolute(const char *path);
|
bool path_is_absolute(const char *path);
|
||||||
|
|
||||||
@ -275,15 +211,8 @@ 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
|
|
||||||
*/
|
*/
|
||||||
size_t fill_pathname(char *out_path, const char *in_path,
|
void fill_pathname(char *out_path, const char *in_path,
|
||||||
const char *replace, size_t size);
|
const char *replace, size_t size);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -297,12 +226,6 @@ size_t 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);
|
||||||
@ -319,33 +242,34 @@ 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 2x
|
|
||||||
* - Calls string_is_empty()
|
|
||||||
* - Calls strftime
|
|
||||||
* - Calls strlcat
|
|
||||||
*
|
|
||||||
* @return Length of the string copied into @out_path
|
|
||||||
**/
|
**/
|
||||||
size_t fill_str_dated_filename(char *out_filename,
|
void 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);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* find_last_slash:
|
* fill_pathname_noext:
|
||||||
* @str : path
|
* @out_path : output path
|
||||||
* @size : size of path
|
* @in_path : input path
|
||||||
|
* @replace : what to replace
|
||||||
|
* @size : buffer size of output path
|
||||||
*
|
*
|
||||||
* Find last slash in path. Tries to find
|
* Appends a filename extension 'replace' to 'in_path', and outputs
|
||||||
* a backslash on Windows too which takes precedence
|
* result in 'out_path'.
|
||||||
* over regular slash.
|
*
|
||||||
|
* 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);
|
||||||
|
|
||||||
* Hidden non-leaf function cost:
|
/**
|
||||||
* - calls strrchr
|
* find_last_slash:
|
||||||
|
* @str : input path
|
||||||
*
|
*
|
||||||
* @return pointer to last slash/backslash found in @str.
|
* Gets a pointer to the last slash in the input path.
|
||||||
|
*
|
||||||
|
* Returns: a pointer to the last slash in the input path.
|
||||||
**/
|
**/
|
||||||
char *find_last_slash(const char *str);
|
char *find_last_slash(const char *str);
|
||||||
|
|
||||||
@ -365,11 +289,6 @@ 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 strlcpy 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);
|
||||||
@ -381,15 +300,16 @@ 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
|
||||||
@ -399,13 +319,12 @@ size_t fill_pathname_base(char *out_path, const char *in_path, size_t size);
|
|||||||
* 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
|
||||||
@ -414,13 +333,7 @@ void fill_pathname_basedir(char *out_path, const char *in_path, size_t size);
|
|||||||
*
|
*
|
||||||
* 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);
|
||||||
@ -434,11 +347,6 @@ 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);
|
||||||
@ -466,51 +374,30 @@ 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 at least once
|
|
||||||
* - calls fill_pathname_slash()
|
|
||||||
*
|
|
||||||
* 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 2x
|
|
||||||
* - calls find_last_slash()
|
|
||||||
*
|
|
||||||
* @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
|
||||||
@ -521,57 +408,45 @@ size_t fill_pathname_join_special_ext(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_expand_special(char *out_path,
|
size_t fill_pathname_join_delim_concat(char *out_path, const char *dir,
|
||||||
const char *in_path, size_t size);
|
const char *path, const char delim, const char *concat,
|
||||||
|
size_t size);
|
||||||
size_t fill_pathname_abbreviate_special(char *out_path,
|
|
||||||
const char *in_path, size_t size);
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* fill_pathname_abbreviated_or_relative:
|
* fill_short_pathname_representation:
|
||||||
|
* @out_rep : output representation
|
||||||
|
* @in_path : input path
|
||||||
|
* @size : size of output representation
|
||||||
*
|
*
|
||||||
* Fills the supplied path with either the abbreviated path or
|
* Generates a short representation of path. It should only
|
||||||
* the relative path, which ever one has less depth / number of slashes
|
* be used for displaying the result; the output representation is not
|
||||||
*
|
* binding in any meaningful way (for a normal path, this is the same as basename)
|
||||||
* If lengths of abbreviated and relative paths are the same,
|
* In case of more complex URLs, this should cut everything except for
|
||||||
* the relative path will be used
|
* the main image file.
|
||||||
* @in_path can be an absolute, relative or abbreviated path
|
|
||||||
*
|
*
|
||||||
* @return Length of the string copied into @out_path
|
* E.g.: "/path/to/game.img" -> game.img
|
||||||
**/
|
* "/path/to/myarchive.7z#folder/to/game.img" -> game.img
|
||||||
size_t fill_pathname_abbreviated_or_relative(char *out_path,
|
*/
|
||||||
const char *in_refpath, const char *in_path, size_t size);
|
size_t fill_short_pathname_representation(char* out_rep,
|
||||||
|
const char *in_path, size_t size);
|
||||||
|
|
||||||
|
void fill_short_pathname_representation_noext(char* out_rep,
|
||||||
|
const char *in_path, size_t size);
|
||||||
|
|
||||||
|
void fill_pathname_expand_special(char *out_path,
|
||||||
|
const char *in_path, size_t size);
|
||||||
|
|
||||||
|
void fill_pathname_abbreviate_special(char *out_path,
|
||||||
|
const char *in_path, size_t size);
|
||||||
|
|
||||||
|
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);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -589,8 +464,8 @@ void path_basedir_wrapper(char *path);
|
|||||||
*
|
*
|
||||||
* Checks if character (@c) is a slash.
|
* Checks if character (@c) is a slash.
|
||||||
*
|
*
|
||||||
* @return true if character is a slash, otherwise false.
|
* Returns: true (1) if character is a slash, otherwise false (0).
|
||||||
**/
|
*/
|
||||||
#ifdef _WIN32
|
#ifdef _WIN32
|
||||||
#define PATH_CHAR_IS_SLASH(c) (((c) == '/') || ((c) == '\\'))
|
#define PATH_CHAR_IS_SLASH(c) (((c) == '/') || ((c) == '\\'))
|
||||||
#else
|
#else
|
||||||
@ -602,8 +477,8 @@ void path_basedir_wrapper(char *path);
|
|||||||
*
|
*
|
||||||
* Gets the default slash separator.
|
* Gets the default slash separator.
|
||||||
*
|
*
|
||||||
* @return default slash separator.
|
* Returns: 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() '\\'
|
||||||
@ -619,13 +494,8 @@ 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
|
|
||||||
**/
|
**/
|
||||||
size_t fill_pathname_slash(char *path, size_t size);
|
void fill_pathname_slash(char *path, size_t size);
|
||||||
|
|
||||||
#if !defined(RARCH_CONSOLE) && defined(RARCH_INTERNAL)
|
#if !defined(RARCH_CONSOLE) && defined(RARCH_INTERNAL)
|
||||||
void fill_pathname_application_path(char *buf, size_t size);
|
void fill_pathname_application_path(char *buf, size_t size);
|
||||||
@ -639,16 +509,7 @@ void fill_pathname_home_dir(char *buf, size_t size);
|
|||||||
*
|
*
|
||||||
* Create directory on filesystem.
|
* Create directory on filesystem.
|
||||||
*
|
*
|
||||||
* Recursive function.
|
* Returns: true (1) if directory could be created, otherwise false (0).
|
||||||
*
|
|
||||||
* 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);
|
||||||
|
|
||||||
@ -658,15 +519,10 @@ bool path_mkdir(const char *dir);
|
|||||||
*
|
*
|
||||||
* Checks if path is a directory.
|
* Checks if path is a directory.
|
||||||
*
|
*
|
||||||
* @return true if path is a directory, otherwise false.
|
* Returns: true (1) if path is a directory, otherwise false (0).
|
||||||
*/
|
*/
|
||||||
bool path_is_directory(const char *path);
|
bool path_is_directory(const char *path);
|
||||||
|
|
||||||
/* Time format strings with AM-PM designation require special
|
|
||||||
* handling due to platform dependence */
|
|
||||||
void strftime_am_pm(char *s, size_t len, const char* format,
|
|
||||||
const void* timeptr);
|
|
||||||
|
|
||||||
bool path_is_character_special(const char *path);
|
bool path_is_character_special(const char *path);
|
||||||
|
|
||||||
int path_stat(const char *path);
|
int path_stat(const char *path);
|
||||||
|
@ -291,7 +291,6 @@ enum retro_language
|
|||||||
RETRO_LANGUAGE_CATALAN = 29,
|
RETRO_LANGUAGE_CATALAN = 29,
|
||||||
RETRO_LANGUAGE_BRITISH_ENGLISH = 30,
|
RETRO_LANGUAGE_BRITISH_ENGLISH = 30,
|
||||||
RETRO_LANGUAGE_HUNGARIAN = 31,
|
RETRO_LANGUAGE_HUNGARIAN = 31,
|
||||||
RETRO_LANGUAGE_BELARUSIAN = 32,
|
|
||||||
RETRO_LANGUAGE_LAST,
|
RETRO_LANGUAGE_LAST,
|
||||||
|
|
||||||
/* Ensure sizeof(enum) == sizeof(int) */
|
/* Ensure sizeof(enum) == sizeof(int) */
|
||||||
@ -929,6 +928,8 @@ enum retro_mod
|
|||||||
* anything else.
|
* anything else.
|
||||||
* It is recommended to expose all relevant pointers through
|
* It is recommended to expose all relevant pointers through
|
||||||
* retro_get_memory_* as well.
|
* retro_get_memory_* as well.
|
||||||
|
*
|
||||||
|
* Can be called from retro_init and retro_load_game.
|
||||||
*/
|
*/
|
||||||
#define RETRO_ENVIRONMENT_SET_GEOMETRY 37
|
#define RETRO_ENVIRONMENT_SET_GEOMETRY 37
|
||||||
/* const struct retro_game_geometry * --
|
/* const struct retro_game_geometry * --
|
||||||
@ -1766,90 +1767,6 @@ 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.
|
|
||||||
*/
|
|
||||||
|
|
||||||
#define RETRO_ENVIRONMENT_GET_JIT_CAPABLE 74
|
|
||||||
/* bool * --
|
|
||||||
* Result is set to true if the frontend has already verified JIT can be
|
|
||||||
* used, mainly for use iOS/tvOS. On other platforms the result is true.
|
|
||||||
*/
|
|
||||||
|
|
||||||
#define RETRO_ENVIRONMENT_GET_MICROPHONE_INTERFACE (75 | RETRO_ENVIRONMENT_EXPERIMENTAL)
|
|
||||||
/* struct retro_microphone_interface * --
|
|
||||||
* Returns an interface that can be used to receive input from the microphone driver.
|
|
||||||
*
|
|
||||||
* Returns true if microphone support is available,
|
|
||||||
* even if no microphones are plugged in.
|
|
||||||
* Returns false if mic support is disabled or unavailable.
|
|
||||||
*
|
|
||||||
* This callback can be invoked at any time,
|
|
||||||
* even before the microphone driver is ready.
|
|
||||||
*/
|
|
||||||
|
|
||||||
#define RETRO_ENVIRONMENT_SET_NETPACKET_INTERFACE 76
|
|
||||||
/* const struct retro_netpacket_callback * --
|
|
||||||
* When set, a core gains control over network packets sent and
|
|
||||||
* received during a multiplayer session. This can be used to
|
|
||||||
* emulate multiplayer games that were originally played on two
|
|
||||||
* or more separate consoles or computers connected together.
|
|
||||||
*
|
|
||||||
* The frontend will take care of connecting players together,
|
|
||||||
* and the core only needs to send the actual data as needed for
|
|
||||||
* the emulation, while handshake and connection management happen
|
|
||||||
* in the background.
|
|
||||||
*
|
|
||||||
* When two or more players are connected and this interface has
|
|
||||||
* been set, time manipulation features (such as pausing, slow motion,
|
|
||||||
* fast forward, rewinding, save state loading, etc.) are disabled to
|
|
||||||
* avoid interrupting communication.
|
|
||||||
*
|
|
||||||
* Should be set in either retro_init or retro_load_game, but not both.
|
|
||||||
*
|
|
||||||
* When not set, a frontend may use state serialization-based
|
|
||||||
* multiplayer, where a deterministic core supporting multiple
|
|
||||||
* input devices does not need to take any action on its own.
|
|
||||||
*/
|
|
||||||
|
|
||||||
#define RETRO_ENVIRONMENT_GET_DEVICE_POWER (77 | RETRO_ENVIRONMENT_EXPERIMENTAL)
|
|
||||||
/* struct retro_device_power * --
|
|
||||||
* Returns the device's current power state as reported by the frontend.
|
|
||||||
* This is useful for emulating the battery level in handheld consoles,
|
|
||||||
* or for reducing power consumption when on battery power.
|
|
||||||
*
|
|
||||||
* The return value indicates whether the frontend can provide this information,
|
|
||||||
* even if the parameter is NULL.
|
|
||||||
*
|
|
||||||
* If the frontend does not support this functionality,
|
|
||||||
* then the provided argument will remain unchanged.
|
|
||||||
*
|
|
||||||
* Note that this environment call describes the power state for the entire device,
|
|
||||||
* not for individual peripherals like controllers.
|
|
||||||
*/
|
|
||||||
|
|
||||||
/* VFS functionality */
|
/* VFS functionality */
|
||||||
|
|
||||||
/* File paths:
|
/* File paths:
|
||||||
@ -2024,13 +1941,13 @@ struct retro_vfs_interface_info
|
|||||||
|
|
||||||
enum retro_hw_render_interface_type
|
enum retro_hw_render_interface_type
|
||||||
{
|
{
|
||||||
RETRO_HW_RENDER_INTERFACE_VULKAN = 0,
|
RETRO_HW_RENDER_INTERFACE_VULKAN = 0,
|
||||||
RETRO_HW_RENDER_INTERFACE_D3D9 = 1,
|
RETRO_HW_RENDER_INTERFACE_D3D9 = 1,
|
||||||
RETRO_HW_RENDER_INTERFACE_D3D10 = 2,
|
RETRO_HW_RENDER_INTERFACE_D3D10 = 2,
|
||||||
RETRO_HW_RENDER_INTERFACE_D3D11 = 3,
|
RETRO_HW_RENDER_INTERFACE_D3D11 = 3,
|
||||||
RETRO_HW_RENDER_INTERFACE_D3D12 = 4,
|
RETRO_HW_RENDER_INTERFACE_D3D12 = 4,
|
||||||
RETRO_HW_RENDER_INTERFACE_GSKIT_PS2 = 5,
|
RETRO_HW_RENDER_INTERFACE_GSKIT_PS2 = 5,
|
||||||
RETRO_HW_RENDER_INTERFACE_DUMMY = INT_MAX
|
RETRO_HW_RENDER_INTERFACE_DUMMY = INT_MAX
|
||||||
};
|
};
|
||||||
|
|
||||||
/* Base struct. All retro_hw_render_interface_* types
|
/* Base struct. All retro_hw_render_interface_* types
|
||||||
@ -2806,17 +2723,9 @@ enum retro_hw_context_type
|
|||||||
/* Vulkan, see RETRO_ENVIRONMENT_GET_HW_RENDER_INTERFACE. */
|
/* Vulkan, see RETRO_ENVIRONMENT_GET_HW_RENDER_INTERFACE. */
|
||||||
RETRO_HW_CONTEXT_VULKAN = 6,
|
RETRO_HW_CONTEXT_VULKAN = 6,
|
||||||
|
|
||||||
/* Direct3D11, see RETRO_ENVIRONMENT_GET_HW_RENDER_INTERFACE */
|
/* Direct3D, set version_major to select the type of interface
|
||||||
RETRO_HW_CONTEXT_D3D11 = 7,
|
* returned by RETRO_ENVIRONMENT_GET_HW_RENDER_INTERFACE */
|
||||||
|
RETRO_HW_CONTEXT_DIRECT3D = 7,
|
||||||
/* Direct3D10, see RETRO_ENVIRONMENT_GET_HW_RENDER_INTERFACE */
|
|
||||||
RETRO_HW_CONTEXT_D3D10 = 8,
|
|
||||||
|
|
||||||
/* Direct3D12, see RETRO_ENVIRONMENT_GET_HW_RENDER_INTERFACE */
|
|
||||||
RETRO_HW_CONTEXT_D3D12 = 9,
|
|
||||||
|
|
||||||
/* Direct3D9, see RETRO_ENVIRONMENT_GET_HW_RENDER_INTERFACE */
|
|
||||||
RETRO_HW_CONTEXT_D3D9 = 10,
|
|
||||||
|
|
||||||
RETRO_HW_CONTEXT_DUMMY = INT_MAX
|
RETRO_HW_CONTEXT_DUMMY = INT_MAX
|
||||||
};
|
};
|
||||||
@ -3071,100 +2980,6 @@ struct retro_disk_control_ext_callback
|
|||||||
retro_get_image_label_t get_image_label; /* Optional - may be NULL */
|
retro_get_image_label_t get_image_label; /* Optional - may be NULL */
|
||||||
};
|
};
|
||||||
|
|
||||||
/* Definitions for RETRO_ENVIRONMENT_SET_NETPACKET_INTERFACE.
|
|
||||||
* A core can set it if sending and receiving custom network packets
|
|
||||||
* during a multiplayer session is desired.
|
|
||||||
*/
|
|
||||||
|
|
||||||
/* Netpacket flags for retro_netpacket_send_t */
|
|
||||||
#define RETRO_NETPACKET_UNRELIABLE 0 /* Packet to be sent unreliable, depending on network quality it might not arrive. */
|
|
||||||
#define RETRO_NETPACKET_RELIABLE (1 << 0) /* Reliable packets are guaranteed to arrive at the target in the order they were send. */
|
|
||||||
#define RETRO_NETPACKET_UNSEQUENCED (1 << 1) /* Packet will not be sequenced with other packets and may arrive out of order. Cannot be set on reliable packets. */
|
|
||||||
|
|
||||||
/* Used by the core to send a packet to one or more connected players.
|
|
||||||
* A single packet sent via this interface can contain up to 64 KB of data.
|
|
||||||
*
|
|
||||||
* The broadcast flag can be set to true to send to multiple connected clients.
|
|
||||||
* In a broadcast, the client_id argument indicates 1 client NOT to send the
|
|
||||||
* packet to (pass 0xFFFF to send to everyone). Otherwise, the client_id
|
|
||||||
* argument indicates a single client to send the packet to.
|
|
||||||
*
|
|
||||||
* A frontend must support sending reliable packets (RETRO_NETPACKET_RELIABLE).
|
|
||||||
* Unreliable packets might not be supported by the frontend, but the flags can
|
|
||||||
* still be specified. Reliable transmission will be used instead.
|
|
||||||
*
|
|
||||||
* If this function is called passing NULL for buf, it will instead flush all
|
|
||||||
* previously buffered outgoing packets and instantly read any incoming packets.
|
|
||||||
* During such a call, retro_netpacket_receive_t and retro_netpacket_stop_t can
|
|
||||||
* be called. The core can perform this in a loop to do a blocking read, i.e.,
|
|
||||||
* wait for incoming data, but needs to handle stop getting called and also
|
|
||||||
* give up after a short while to avoid freezing on a connection problem.
|
|
||||||
*
|
|
||||||
* This function is not guaranteed to be thread-safe and must be called during
|
|
||||||
* retro_run or any of the netpacket callbacks passed with this interface.
|
|
||||||
*/
|
|
||||||
typedef void (RETRO_CALLCONV *retro_netpacket_send_t)(int flags, const void* buf, size_t len, uint16_t client_id, bool broadcast);
|
|
||||||
|
|
||||||
/* Called by the frontend to signify that a multiplayer session has started.
|
|
||||||
* If client_id is 0 the local player is the host of the session and at this
|
|
||||||
* point no other player has connected yet.
|
|
||||||
*
|
|
||||||
* If client_id is > 0 the local player is a client connected to a host and
|
|
||||||
* at this point is already fully connected to the host.
|
|
||||||
*
|
|
||||||
* The core must store the retro_netpacket_send_t function pointer provided
|
|
||||||
* here and use it whenever it wants to send a packet. This function pointer
|
|
||||||
* remains valid until the frontend calls retro_netpacket_stop_t.
|
|
||||||
*/
|
|
||||||
typedef void (RETRO_CALLCONV *retro_netpacket_start_t)(uint16_t client_id, retro_netpacket_send_t send_fn);
|
|
||||||
|
|
||||||
/* Called by the frontend when a new packet arrives which has been sent from
|
|
||||||
* another player with retro_netpacket_send_t. The client_id argument indicates
|
|
||||||
* who has sent the packet.
|
|
||||||
*/
|
|
||||||
typedef void (RETRO_CALLCONV *retro_netpacket_receive_t)(const void* buf, size_t len, uint16_t client_id);
|
|
||||||
|
|
||||||
/* Called by the frontend when the multiplayer session has ended.
|
|
||||||
* Once this gets called the retro_netpacket_send_t function pointer passed
|
|
||||||
* to retro_netpacket_start_t will not be valid anymore.
|
|
||||||
*/
|
|
||||||
typedef void (RETRO_CALLCONV *retro_netpacket_stop_t)(void);
|
|
||||||
|
|
||||||
/* Called by the frontend every frame (between calls to retro_run while
|
|
||||||
* updating the state of the multiplayer session.
|
|
||||||
* This is a good place for the core to call retro_netpacket_send_t from.
|
|
||||||
*/
|
|
||||||
typedef void (RETRO_CALLCONV *retro_netpacket_poll_t)(void);
|
|
||||||
|
|
||||||
/* Called by the frontend when a new player connects to the hosted session.
|
|
||||||
* This is only called on the host side, not for clients connected to the host.
|
|
||||||
* If this function returns false, the newly connected player gets dropped.
|
|
||||||
* This can be used for example to limit the number of players.
|
|
||||||
*/
|
|
||||||
typedef bool (RETRO_CALLCONV *retro_netpacket_connected_t)(uint16_t client_id);
|
|
||||||
|
|
||||||
/* Called by the frontend when a player leaves or disconnects from the hosted session.
|
|
||||||
* This is only called on the host side, not for clients connected to the host.
|
|
||||||
*/
|
|
||||||
typedef void (RETRO_CALLCONV *retro_netpacket_disconnected_t)(uint16_t client_id);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* A callback interface for giving a core the ability to send and receive custom
|
|
||||||
* network packets during a multiplayer session between two or more instances
|
|
||||||
* of a libretro frontend.
|
|
||||||
*
|
|
||||||
* @see RETRO_ENVIRONMENT_SET_NETPACKET_INTERFACE
|
|
||||||
*/
|
|
||||||
struct retro_netpacket_callback
|
|
||||||
{
|
|
||||||
retro_netpacket_start_t start;
|
|
||||||
retro_netpacket_receive_t receive;
|
|
||||||
retro_netpacket_stop_t stop; /* Optional - may be NULL */
|
|
||||||
retro_netpacket_poll_t poll; /* Optional - may be NULL */
|
|
||||||
retro_netpacket_connected_t connected; /* Optional - may be NULL */
|
|
||||||
retro_netpacket_disconnected_t disconnected; /* Optional - may be NULL */
|
|
||||||
};
|
|
||||||
|
|
||||||
enum retro_pixel_format
|
enum retro_pixel_format
|
||||||
{
|
{
|
||||||
/* 0RGB1555, native endian.
|
/* 0RGB1555, native endian.
|
||||||
@ -3967,289 +3782,6 @@ struct retro_throttle_state
|
|||||||
float rate;
|
float rate;
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
|
||||||
* Opaque handle to a microphone that's been opened for use.
|
|
||||||
* The underlying object is accessed or created with \c retro_microphone_interface_t.
|
|
||||||
*/
|
|
||||||
typedef struct retro_microphone retro_microphone_t;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Parameters for configuring a microphone.
|
|
||||||
* Some of these might not be honored,
|
|
||||||
* depending on the available hardware and driver configuration.
|
|
||||||
*/
|
|
||||||
typedef struct retro_microphone_params
|
|
||||||
{
|
|
||||||
/**
|
|
||||||
* The desired sample rate of the microphone's input, in Hz.
|
|
||||||
* The microphone's input will be resampled,
|
|
||||||
* so cores can ask for whichever frequency they need.
|
|
||||||
*
|
|
||||||
* If zero, some reasonable default will be provided by the frontend
|
|
||||||
* (usually from its config file).
|
|
||||||
*
|
|
||||||
* @see retro_get_mic_rate_t
|
|
||||||
*/
|
|
||||||
unsigned rate;
|
|
||||||
} retro_microphone_params_t;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @copydoc retro_microphone_interface::open_mic
|
|
||||||
*/
|
|
||||||
typedef retro_microphone_t *(RETRO_CALLCONV *retro_open_mic_t)(const retro_microphone_params_t *params);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @copydoc retro_microphone_interface::close_mic
|
|
||||||
*/
|
|
||||||
typedef void (RETRO_CALLCONV *retro_close_mic_t)(retro_microphone_t *microphone);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @copydoc retro_microphone_interface::get_params
|
|
||||||
*/
|
|
||||||
typedef bool (RETRO_CALLCONV *retro_get_mic_params_t)(const retro_microphone_t *microphone, retro_microphone_params_t *params);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @copydoc retro_microphone_interface::set_mic_state
|
|
||||||
*/
|
|
||||||
typedef bool (RETRO_CALLCONV *retro_set_mic_state_t)(retro_microphone_t *microphone, bool state);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @copydoc retro_microphone_interface::get_mic_state
|
|
||||||
*/
|
|
||||||
typedef bool (RETRO_CALLCONV *retro_get_mic_state_t)(const retro_microphone_t *microphone);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @copydoc retro_microphone_interface::read_mic
|
|
||||||
*/
|
|
||||||
typedef int (RETRO_CALLCONV *retro_read_mic_t)(retro_microphone_t *microphone, int16_t* samples, size_t num_samples);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* The current version of the microphone interface.
|
|
||||||
* Will be incremented whenever \c retro_microphone_interface or \c retro_microphone_params_t
|
|
||||||
* receive new fields.
|
|
||||||
*
|
|
||||||
* Frontends using cores built against older mic interface versions
|
|
||||||
* should not access fields introduced in newer versions.
|
|
||||||
*/
|
|
||||||
#define RETRO_MICROPHONE_INTERFACE_VERSION 1
|
|
||||||
|
|
||||||
/**
|
|
||||||
* An interface for querying the microphone and accessing data read from it.
|
|
||||||
*
|
|
||||||
* @see RETRO_ENVIRONMENT_GET_MICROPHONE_INTERFACE
|
|
||||||
*/
|
|
||||||
struct retro_microphone_interface
|
|
||||||
{
|
|
||||||
/**
|
|
||||||
* The version of this microphone interface.
|
|
||||||
* Set by the core to request a particular version,
|
|
||||||
* and set by the frontend to indicate the returned version.
|
|
||||||
* 0 indicates that the interface is invalid or uninitialized.
|
|
||||||
*/
|
|
||||||
unsigned interface_version;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Initializes a new microphone.
|
|
||||||
* Assuming that microphone support is enabled and provided by the frontend,
|
|
||||||
* cores may call this function whenever necessary.
|
|
||||||
* A microphone could be opened throughout a core's lifetime,
|
|
||||||
* or it could wait until a microphone is plugged in to the emulated device.
|
|
||||||
*
|
|
||||||
* The returned handle will be valid until it's freed,
|
|
||||||
* even if the audio driver is reinitialized.
|
|
||||||
*
|
|
||||||
* This function is not guaranteed to be thread-safe.
|
|
||||||
*
|
|
||||||
* @param args[in] Parameters used to create the microphone.
|
|
||||||
* May be \c NULL, in which case the default value of each parameter will be used.
|
|
||||||
*
|
|
||||||
* @returns Pointer to the newly-opened microphone,
|
|
||||||
* or \c NULL if one couldn't be opened.
|
|
||||||
* This likely means that no microphone is plugged in and recognized,
|
|
||||||
* or the maximum number of supported microphones has been reached.
|
|
||||||
*
|
|
||||||
* @note Microphones are \em inactive by default;
|
|
||||||
* to begin capturing audio, call \c set_mic_state.
|
|
||||||
* @see retro_microphone_params_t
|
|
||||||
*/
|
|
||||||
retro_open_mic_t open_mic;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Closes a microphone that was initialized with \c open_mic.
|
|
||||||
* Calling this function will stop all microphone activity
|
|
||||||
* and free up the resources that it allocated.
|
|
||||||
* Afterwards, the handle is invalid and must not be used.
|
|
||||||
*
|
|
||||||
* A frontend may close opened microphones when unloading content,
|
|
||||||
* but this behavior is not guaranteed.
|
|
||||||
* Cores should close their microphones when exiting, just to be safe.
|
|
||||||
*
|
|
||||||
* @param microphone Pointer to the microphone that was allocated by \c open_mic.
|
|
||||||
* If \c NULL, this function does nothing.
|
|
||||||
*
|
|
||||||
* @note The handle might be reused if another microphone is opened later.
|
|
||||||
*/
|
|
||||||
retro_close_mic_t close_mic;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Returns the configured parameters of this microphone.
|
|
||||||
* These may differ from what was requested depending on
|
|
||||||
* the driver and device configuration.
|
|
||||||
*
|
|
||||||
* Cores should check these values before they start fetching samples.
|
|
||||||
*
|
|
||||||
* Will not change after the mic was opened.
|
|
||||||
*
|
|
||||||
* @param microphone[in] Opaque handle to the microphone
|
|
||||||
* whose parameters will be retrieved.
|
|
||||||
* @param params[out] The parameters object that the
|
|
||||||
* microphone's parameters will be copied to.
|
|
||||||
*
|
|
||||||
* @return \c true if the parameters were retrieved,
|
|
||||||
* \c false if there was an error.
|
|
||||||
*/
|
|
||||||
retro_get_mic_params_t get_params;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Enables or disables the given microphone.
|
|
||||||
* Microphones are disabled by default
|
|
||||||
* and must be explicitly enabled before they can be used.
|
|
||||||
* Disabled microphones will not process incoming audio samples,
|
|
||||||
* and will therefore have minimal impact on overall performance.
|
|
||||||
* Cores may enable microphones throughout their lifetime,
|
|
||||||
* or only for periods where they're needed.
|
|
||||||
*
|
|
||||||
* Cores that accept microphone input should be able to operate without it;
|
|
||||||
* we suggest substituting silence in this case.
|
|
||||||
*
|
|
||||||
* @param microphone Opaque handle to the microphone
|
|
||||||
* whose state will be adjusted.
|
|
||||||
* This will have been provided by \c open_mic.
|
|
||||||
* @param state \c true if the microphone should receive audio input,
|
|
||||||
* \c false if it should be idle.
|
|
||||||
* @returns \c true if the microphone's state was successfully set,
|
|
||||||
* \c false if \c microphone is invalid
|
|
||||||
* or if there was an error.
|
|
||||||
*/
|
|
||||||
retro_set_mic_state_t set_mic_state;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Queries the active state of a microphone at the given index.
|
|
||||||
* Will return whether the microphone is enabled,
|
|
||||||
* even if the driver is paused.
|
|
||||||
*
|
|
||||||
* @param microphone Opaque handle to the microphone
|
|
||||||
* whose state will be queried.
|
|
||||||
* @return \c true if the provided \c microphone is valid and active,
|
|
||||||
* \c false if not or if there was an error.
|
|
||||||
*/
|
|
||||||
retro_get_mic_state_t get_mic_state;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Retrieves the input processed by the microphone since the last call.
|
|
||||||
* \em Must be called every frame unless \c microphone is disabled,
|
|
||||||
* similar to how \c retro_audio_sample_batch_t works.
|
|
||||||
*
|
|
||||||
* @param[in] microphone Opaque handle to the microphone
|
|
||||||
* whose recent input will be retrieved.
|
|
||||||
* @param[out] samples The buffer that will be used to store the microphone's data.
|
|
||||||
* Microphone input is in mono (i.e. one number per sample).
|
|
||||||
* Should be large enough to accommodate the expected number of samples per frame;
|
|
||||||
* for example, a 44.1kHz sample rate at 60 FPS would require space for 735 samples.
|
|
||||||
* @param[in] num_samples The size of the data buffer in samples (\em not bytes).
|
|
||||||
* Microphone input is in mono, so a "frame" and a "sample" are equivalent in length here.
|
|
||||||
*
|
|
||||||
* @return The number of samples that were copied into \c samples.
|
|
||||||
* If \c microphone is pending driver initialization,
|
|
||||||
* this function will copy silence of the requested length into \c samples.
|
|
||||||
*
|
|
||||||
* Will return -1 if the microphone is disabled,
|
|
||||||
* the audio driver is paused,
|
|
||||||
* or there was an error.
|
|
||||||
*/
|
|
||||||
retro_read_mic_t read_mic;
|
|
||||||
};
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Describes how a device is being powered.
|
|
||||||
* @see RETRO_ENVIRONMENT_GET_DEVICE_POWER
|
|
||||||
*/
|
|
||||||
enum retro_power_state
|
|
||||||
{
|
|
||||||
/**
|
|
||||||
* Indicates that the frontend cannot report its power state at this time,
|
|
||||||
* most likely due to a lack of support.
|
|
||||||
*
|
|
||||||
* \c RETRO_ENVIRONMENT_GET_DEVICE_POWER will not return this value;
|
|
||||||
* instead, the environment callback will return \c false.
|
|
||||||
*/
|
|
||||||
RETRO_POWERSTATE_UNKNOWN = 0,
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Indicates that the device is running on its battery.
|
|
||||||
* Usually applies to portable devices such as handhelds, laptops, and smartphones.
|
|
||||||
*/
|
|
||||||
RETRO_POWERSTATE_DISCHARGING,
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Indicates that the device's battery is currently charging.
|
|
||||||
*/
|
|
||||||
RETRO_POWERSTATE_CHARGING,
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Indicates that the device is connected to a power source
|
|
||||||
* and that its battery has finished charging.
|
|
||||||
*/
|
|
||||||
RETRO_POWERSTATE_CHARGED,
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Indicates that the device is connected to a power source
|
|
||||||
* and that it does not have a battery.
|
|
||||||
* This usually suggests a desktop computer or a non-portable game console.
|
|
||||||
*/
|
|
||||||
RETRO_POWERSTATE_PLUGGED_IN
|
|
||||||
};
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Indicates that an estimate is not available for the battery level or time remaining,
|
|
||||||
* even if the actual power state is known.
|
|
||||||
*/
|
|
||||||
#define RETRO_POWERSTATE_NO_ESTIMATE (-1)
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Describes the power state of the device running the frontend.
|
|
||||||
* @see RETRO_ENVIRONMENT_GET_DEVICE_POWER
|
|
||||||
*/
|
|
||||||
struct retro_device_power
|
|
||||||
{
|
|
||||||
/**
|
|
||||||
* The current state of the frontend's power usage.
|
|
||||||
*/
|
|
||||||
enum retro_power_state state;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* A rough estimate of the amount of time remaining (in seconds)
|
|
||||||
* before the device powers off.
|
|
||||||
* This value depends on a variety of factors,
|
|
||||||
* so it is not guaranteed to be accurate.
|
|
||||||
*
|
|
||||||
* Will be set to \c RETRO_POWERSTATE_NO_ESTIMATE if \c state does not equal \c RETRO_POWERSTATE_DISCHARGING.
|
|
||||||
* May still be set to \c RETRO_POWERSTATE_NO_ESTIMATE if the frontend is unable to provide an estimate.
|
|
||||||
*/
|
|
||||||
int seconds;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* The approximate percentage of battery charge,
|
|
||||||
* ranging from 0 to 100 (inclusive).
|
|
||||||
* The device may power off before this reaches 0.
|
|
||||||
*
|
|
||||||
* The user might have configured their device
|
|
||||||
* to stop charging before the battery is full,
|
|
||||||
* so do not assume that this will be 100 in the \c RETRO_POWERSTATE_CHARGED state.
|
|
||||||
*/
|
|
||||||
int8_t percent;
|
|
||||||
};
|
|
||||||
|
|
||||||
/* Callbacks */
|
/* Callbacks */
|
||||||
|
|
||||||
/* Environment callback. Gives implementations a way of performing
|
/* Environment callback. Gives implementations a way of performing
|
||||||
|
@ -101,26 +101,6 @@ typedef int ssize_t;
|
|||||||
#define STRING_REP_UINT64 "%" PRIu64
|
#define STRING_REP_UINT64 "%" PRIu64
|
||||||
#define STRING_REP_USIZE "%" PRIuPTR
|
#define STRING_REP_USIZE "%" PRIuPTR
|
||||||
|
|
||||||
/* Wrap a declaration in RETRO_DEPRECATED() to produce a compiler warning when
|
|
||||||
it's used. This is intended for developer machines, so it won't work on ancient
|
|
||||||
or obscure compilers */
|
|
||||||
#if defined(_MSC_VER)
|
|
||||||
#if _MSC_VER >= 1400 /* Visual C 2005 or later */
|
|
||||||
#define RETRO_DEPRECATED(decl) __declspec(deprecated) decl
|
|
||||||
#endif
|
|
||||||
#elif defined(__GNUC__)
|
|
||||||
#if __GNUC__ >= 3 /* GCC 3 or later */
|
|
||||||
#define RETRO_DEPRECATED(decl) decl __attribute__((deprecated))
|
|
||||||
#endif
|
|
||||||
#elif defined(__clang__)
|
|
||||||
#if __clang_major__ >= 3 /* clang 3 or later */
|
|
||||||
#define RETRO_DEPRECATED(decl) decl __attribute__((deprecated))
|
|
||||||
#endif
|
|
||||||
#endif
|
|
||||||
#ifndef RETRO_DEPRECATED /* Unsupported compilers */
|
|
||||||
#define RETRO_DEPRECATED(decl) decl
|
|
||||||
#endif
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
I would like to see retro_inline.h moved in here; possibly boolean too.
|
I would like to see retro_inline.h moved in here; possibly boolean too.
|
||||||
|
|
||||||
|
@ -49,10 +49,6 @@
|
|||||||
#include <compat/msvc.h>
|
#include <compat/msvc.h>
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#ifdef IOS
|
|
||||||
#include <sys/param.h>
|
|
||||||
#endif
|
|
||||||
|
|
||||||
static INLINE void bits_or_bits(uint32_t *a, uint32_t *b, uint32_t count)
|
static INLINE void bits_or_bits(uint32_t *a, uint32_t *b, uint32_t count)
|
||||||
{
|
{
|
||||||
uint32_t i;
|
uint32_t i;
|
||||||
@ -78,29 +74,14 @@ 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(__PSL1GHT__) || defined(__PS3__)
|
#if defined(_XBOX1) || defined(_3DS) || defined(PSP) || defined(PS2) || defined(GEKKO)|| defined(WIIU) || defined(ORBIS) || 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
|
||||||
|
@ -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.
|
||||||
* @return A pointer to an RFILE if opened successfully, otherwise NULL.
|
* Returns 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,17 +75,6 @@ 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);
|
||||||
@ -98,16 +87,6 @@ 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);
|
||||||
@ -128,11 +107,7 @@ 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);
|
||||||
|
@ -48,7 +48,7 @@ RETRO_BEGIN_DECLS
|
|||||||
#define TOUPPER(c) ((c) & ~(lr_char_props[(unsigned char)(c)] & 0x20))
|
#define TOUPPER(c) ((c) & ~(lr_char_props[(unsigned char)(c)] & 0x20))
|
||||||
|
|
||||||
/* C standard says \f \v are space, but this one disagrees */
|
/* C standard says \f \v are space, but this one disagrees */
|
||||||
#define ISSPACE(c) (lr_char_props[(unsigned char)(c)] & 0x80)
|
#define ISSPACE(c) (lr_char_props[(unsigned char)(c)] & 0x80)
|
||||||
|
|
||||||
#define ISDIGIT(c) (lr_char_props[(unsigned char)(c)] & 0x40)
|
#define ISDIGIT(c) (lr_char_props[(unsigned char)(c)] & 0x40)
|
||||||
#define ISALPHA(c) (lr_char_props[(unsigned char)(c)] & 0x20)
|
#define ISALPHA(c) (lr_char_props[(unsigned char)(c)] & 0x20)
|
||||||
@ -92,20 +92,16 @@ 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)
|
||||||
{
|
{
|
||||||
return str && suffix && string_ends_with_size(str, suffix, strlen(str), strlen(suffix));
|
if (!str || !suffix)
|
||||||
|
return false;
|
||||||
|
return string_ends_with_size(str, suffix, strlen(str), strlen(suffix));
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/* Returns the length of 'str' (c.f. strlen()), but only
|
||||||
* 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;
|
||||||
@ -134,68 +130,25 @@ 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,
|
char *string_replace_substring(const char *in, const char *pattern,
|
||||||
const char *pattern, size_t pattern_len,
|
const char *by);
|
||||||
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
|
||||||
@ -203,57 +156,58 @@ 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.).
|
||||||
**/
|
*
|
||||||
size_t word_wrap(char *dst, size_t dst_size, const char *src, size_t src_len,
|
* @param dst pointer to destination buffer.
|
||||||
|
* @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);
|
||||||
|
|
||||||
/**
|
/*
|
||||||
* word_wrap_wideglyph:
|
* Wraps string specified by 'src' to destination buffer
|
||||||
* @dst : pointer to destination buffer.
|
* specified by 'dst' and 'dst_size'.
|
||||||
* @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.
|
||||||
**/
|
|
||||||
size_t 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);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* string_tokenize:
|
|
||||||
*
|
*
|
||||||
* Splits string into tokens seperated by @delim
|
* @param dst pointer to destination buffer.
|
||||||
|
* @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 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
|
||||||
|
* @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'
|
||||||
* > 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:
|
||||||
@ -266,120 +220,29 @@ size_t word_wrap_wideglyph(
|
|||||||
* 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'
|
||||||
* string_replace_all_chars:
|
* with character 'replace' */
|
||||||
* @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.
|
||||||
* string_to_unsigned:
|
* Returns 0 if string is invalid */
|
||||||
* @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
|
||||||
|
@ -71,12 +71,6 @@ 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
|
||||||
|
@ -25,6 +25,7 @@
|
|||||||
#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"
|
||||||
@ -45,6 +46,7 @@ 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;
|
||||||
@ -107,14 +109,18 @@ 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)
|
||||||
free(dummy);
|
if (dummy)
|
||||||
|
free(dummy);
|
||||||
|
|
||||||
dummy = NULL;
|
dummy = NULL;
|
||||||
return true;
|
return true;
|
||||||
@ -159,7 +165,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.
|
||||||
* @return A pointer to an RFILE if opened successfully, otherwise NULL.
|
* Returns 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)
|
||||||
{
|
{
|
||||||
@ -178,6 +184,7 @@ 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;
|
||||||
}
|
}
|
||||||
@ -219,7 +226,7 @@ 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 = filestream_tell(stream);
|
||||||
int64_t maxlen = filestream_read(stream, buf, sizeof(buf)-1);
|
int64_t maxlen = filestream_read(stream, buf, sizeof(buf)-1);
|
||||||
@ -234,11 +241,7 @@ 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)
|
||||||
{
|
{
|
||||||
@ -330,7 +333,7 @@ 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),
|
filestream_seek(stream, startpos+(bufiter-buf),
|
||||||
RETRO_VFS_SEEK_POSITION_START);
|
RETRO_VFS_SEEK_POSITION_START);
|
||||||
|
|
||||||
return ret;
|
return ret;
|
||||||
@ -360,12 +363,14 @@ 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 filestream_tell(stream) == filestream_get_size(stream) ? EOF : 0;
|
return stream->eof_flag;
|
||||||
}
|
}
|
||||||
|
|
||||||
int64_t filestream_tell(RFILE *stream)
|
int64_t filestream_tell(RFILE *stream)
|
||||||
@ -390,6 +395,7 @@ 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)
|
||||||
@ -404,6 +410,8 @@ 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;
|
||||||
}
|
}
|
||||||
@ -501,7 +509,9 @@ int filestream_printf(RFILE *stream, const char* format, ...)
|
|||||||
|
|
||||||
int filestream_error(RFILE *stream)
|
int filestream_error(RFILE *stream)
|
||||||
{
|
{
|
||||||
return (stream && stream->error_flag);
|
if (stream && stream->error_flag)
|
||||||
|
return 1;
|
||||||
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
int filestream_close(RFILE *stream)
|
int filestream_close(RFILE *stream)
|
||||||
@ -530,7 +540,7 @@ int filestream_close(RFILE *stream)
|
|||||||
*
|
*
|
||||||
* Read the contents of a file into @buf.
|
* Read the contents of a file into @buf.
|
||||||
*
|
*
|
||||||
* @return Non-zero on success.
|
* Returns: 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,20 +557,25 @@ int64_t filestream_read_file(const char *path, void **buf, int64_t *len)
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
if ((content_buf_size = filestream_get_size(file)) < 0)
|
content_buf_size = filestream_get_size(file);
|
||||||
|
|
||||||
|
if (content_buf_size < 0)
|
||||||
goto error;
|
goto error;
|
||||||
|
|
||||||
if (!(content_buf = malloc((size_t)(content_buf_size + 1))))
|
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;
|
||||||
|
|
||||||
if ((ret = filestream_read(file, content_buf, (int64_t)content_buf_size)) <
|
ret = filestream_read(file, content_buf, (int64_t)content_buf_size);
|
||||||
0)
|
if (ret < 0)
|
||||||
goto error;
|
goto error;
|
||||||
|
|
||||||
if (filestream_close(file) != 0)
|
if (filestream_close(file) != 0)
|
||||||
free(file);
|
if (file)
|
||||||
|
free(file);
|
||||||
|
|
||||||
*buf = content_buf;
|
*buf = content_buf;
|
||||||
|
|
||||||
@ -574,8 +589,9 @@ int64_t filestream_read_file(const char *path, void **buf, int64_t *len)
|
|||||||
return 1;
|
return 1;
|
||||||
|
|
||||||
error:
|
error:
|
||||||
if (filestream_close(file) != 0)
|
if (file)
|
||||||
free(file);
|
if (filestream_close(file) != 0)
|
||||||
|
free(file);
|
||||||
if (content_buf)
|
if (content_buf)
|
||||||
free(content_buf);
|
free(content_buf);
|
||||||
if (len)
|
if (len)
|
||||||
@ -592,8 +608,8 @@ error:
|
|||||||
*
|
*
|
||||||
* Writes data to a file.
|
* Writes data to a file.
|
||||||
*
|
*
|
||||||
* @return true on success, otherwise false.
|
* Returns: true (1) on success, false (0) otherwise.
|
||||||
**/
|
*/
|
||||||
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;
|
||||||
@ -602,18 +618,20 @@ 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)
|
||||||
free(file);
|
if (file)
|
||||||
return (ret == size);
|
free(file);
|
||||||
|
|
||||||
|
if (ret != size)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/* Returned pointer must be freed by the caller. */
|
||||||
* filestream_getline:
|
char* filestream_getline(RFILE *stream)
|
||||||
*
|
|
||||||
* 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;
|
||||||
@ -628,15 +646,16 @@ 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 = (char*)realloc(newline, cur_size + 1)))
|
if (!newline_tmp)
|
||||||
{
|
{
|
||||||
free(newline);
|
free(newline);
|
||||||
return NULL;
|
return NULL;
|
||||||
|
@ -69,27 +69,17 @@ 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:
|
||||||
@ -109,61 +99,39 @@ 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)
|
||||||
{
|
{
|
||||||
if (!stream || (elem_size == 0) || (elem_count == 0))
|
return filestream_write(stream, buffer, elem_size * elem_count);
|
||||||
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)
|
||||||
{
|
{
|
||||||
if (!stream)
|
return filestream_putc(stream, character);
|
||||||
return EOF;
|
|
||||||
|
|
||||||
return filestream_putc(stream, character);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
int64_t rfflush(RFILE * stream)
|
int64_t rfflush(RFILE * stream)
|
||||||
{
|
{
|
||||||
if (!stream)
|
return filestream_flush(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);
|
||||||
@ -184,10 +152,6 @@ 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,7 +24,6 @@
|
|||||||
#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>
|
||||||
|
|
||||||
@ -90,11 +89,9 @@ char *string_ucwords(char *s)
|
|||||||
}
|
}
|
||||||
|
|
||||||
char *string_replace_substring(const char *in,
|
char *string_replace_substring(const char *in,
|
||||||
const char *pattern, size_t pattern_len,
|
const char *pattern, const char *replacement)
|
||||||
const char *replacement, size_t replacement_len)
|
|
||||||
{
|
{
|
||||||
size_t outlen;
|
size_t numhits, pattern_len, replacement_len, 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;
|
||||||
@ -105,6 +102,9 @@ 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,8 +114,9 @@ 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 = (char *)malloc(outlen+1)))
|
if (!out)
|
||||||
return NULL;
|
return NULL;
|
||||||
|
|
||||||
outat = out;
|
outat = out;
|
||||||
@ -128,7 +129,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);
|
||||||
@ -136,11 +137,7 @@ 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)
|
||||||
@ -161,11 +158,7 @@ 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)
|
||||||
@ -185,11 +178,7 @@ 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 */
|
||||||
@ -198,62 +187,49 @@ 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.).
|
|
||||||
**/
|
|
||||||
size_t 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 *last_space = 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 */
|
||||||
if (dst_size < src_len + 1)
|
if (dst_size < src_len + 1)
|
||||||
return 0;
|
return;
|
||||||
|
|
||||||
/* 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 < (size_t)line_width)
|
if (src_len < line_width)
|
||||||
return strlcpy(dst, src, dst_size);
|
{
|
||||||
|
strcpy(dst, src);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
while (*src != '\0')
|
while (*src != '\0')
|
||||||
{
|
{
|
||||||
unsigned char_len = (unsigned)(utf8skip(src, 1) - src);
|
unsigned char_len;
|
||||||
|
|
||||||
|
char_len = (unsigned)(utf8skip(src, 1) - src);
|
||||||
counter++;
|
counter++;
|
||||||
|
|
||||||
if (*src == ' ')
|
if (*src == ' ')
|
||||||
last_space = 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,
|
||||||
* reset the index */
|
* reset the index */
|
||||||
lines++;
|
lines++;
|
||||||
counter = 0;
|
counter = 0;
|
||||||
|
|
||||||
/* Early return if remaining src string
|
/* Early return if remaining src string
|
||||||
* length is less than line width */
|
* length is less than line width */
|
||||||
if (src_end - src <= line_width)
|
if (src_end - src <= line_width)
|
||||||
return strlcpy(dst, src, dst_size);
|
{
|
||||||
|
strcpy(dst, src);
|
||||||
|
return;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
while (char_len--)
|
while (char_len--)
|
||||||
@ -263,69 +239,36 @@ size_t word_wrap(
|
|||||||
{
|
{
|
||||||
counter = 0;
|
counter = 0;
|
||||||
|
|
||||||
if (last_space && (max_lines == 0 || lines < max_lines))
|
if (lastspace && (max_lines == 0 || lines < max_lines))
|
||||||
{
|
{
|
||||||
/* Replace nearest (previous) whitespace
|
/* Replace nearest (previous) whitespace
|
||||||
* with newline character */
|
* with newline character */
|
||||||
*last_space = '\n';
|
*lastspace = '\n';
|
||||||
lines++;
|
lines++;
|
||||||
|
|
||||||
src -= dst - last_space - 1;
|
src -= dst - lastspace - 1;
|
||||||
dst = last_space + 1;
|
dst = lastspace + 1;
|
||||||
last_space = 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 */
|
||||||
if (src_end - src < line_width)
|
if (src_end - src < line_width)
|
||||||
return strlcpy(dst, src, dst_size);
|
{
|
||||||
|
strcpy(dst, src);
|
||||||
|
return;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
*dst = '\0';
|
*dst = '\0';
|
||||||
return 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.
|
|
||||||
**/
|
|
||||||
size_t 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 + src_len;
|
const char *src_end = src + strlen(src);
|
||||||
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
|
||||||
@ -351,15 +294,20 @@ size_t word_wrap_wideglyph(char *dst, size_t dst_size,
|
|||||||
unsigned counter_normalized = 0;
|
unsigned counter_normalized = 0;
|
||||||
int line_width_normalized = line_width * 100;
|
int line_width_normalized = line_width * 100;
|
||||||
int additional_counter_normalized = wideglyph_width - 100;
|
int additional_counter_normalized = wideglyph_width - 100;
|
||||||
|
|
||||||
/* Early return if src string length is less
|
/* Early return if src string length is less
|
||||||
* than line width */
|
* than line width */
|
||||||
if (src_end - src < line_width)
|
if (src_end - src < line_width)
|
||||||
return strlcpy(dst, src, dst_size);
|
{
|
||||||
|
strlcpy(dst, src, dst_size);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
while (*src != '\0')
|
while (*src != '\0')
|
||||||
{
|
{
|
||||||
unsigned char_len = (unsigned)(utf8skip(src, 1) - src);
|
unsigned char_len;
|
||||||
|
|
||||||
|
char_len = (unsigned)(utf8skip(src, 1) - src);
|
||||||
counter_normalized += 100;
|
counter_normalized += 100;
|
||||||
|
|
||||||
/* Prevent buffer overflow */
|
/* Prevent buffer overflow */
|
||||||
@ -367,7 +315,7 @@ size_t word_wrap_wideglyph(char *dst, size_t dst_size,
|
|||||||
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,
|
||||||
@ -378,13 +326,16 @@ size_t word_wrap_wideglyph(char *dst, size_t dst_size,
|
|||||||
/* Early return if remaining src string
|
/* Early return if remaining src string
|
||||||
* length is less than line width */
|
* length is less than line width */
|
||||||
if (src_end - src <= line_width)
|
if (src_end - src <= line_width)
|
||||||
return strlcpy(dst, src, dst_size);
|
{
|
||||||
|
strlcpy(dst, src, dst_size);
|
||||||
|
return;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
else if (char_len >= 3)
|
else if (char_len >= 3)
|
||||||
{
|
{
|
||||||
/* 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;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -403,14 +354,17 @@ size_t word_wrap_wideglyph(char *dst, size_t dst_size,
|
|||||||
/* 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 */
|
||||||
if (src_end - src <= line_width)
|
if (src_end - src <= line_width)
|
||||||
return strlcpy(dst, src, dst_size);
|
{
|
||||||
|
strlcpy(dst, src, dst_size);
|
||||||
|
return;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
else if (lastspace)
|
else if (lastspace)
|
||||||
{
|
{
|
||||||
@ -418,29 +372,28 @@ size_t word_wrap_wideglyph(char *dst, size_t dst_size,
|
|||||||
* 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 */
|
||||||
if (src_end - src < line_width)
|
if (src_end - src < line_width)
|
||||||
return strlcpy(dst, src, dst_size);
|
{
|
||||||
|
strlcpy(dst, src, dst_size);
|
||||||
|
return;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
*dst = '\0';
|
*dst = '\0';
|
||||||
return 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:
|
||||||
@ -453,7 +406,7 @@ size_t word_wrap_wideglyph(char *dst, size_t dst_size,
|
|||||||
* 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# */
|
||||||
@ -466,20 +419,25 @@ 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 = *str))
|
if (!str_ptr)
|
||||||
return NULL;
|
return NULL;
|
||||||
|
|
||||||
/* Search for delimiter */
|
/* Search for delimiter */
|
||||||
if ((delim_ptr = strstr(str_ptr, delim)))
|
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 */
|
||||||
if (!(token = (char *)malloc((token_len + 1) * sizeof(char))))
|
token = (char *)malloc((token_len + 1) * sizeof(char));
|
||||||
|
|
||||||
|
if (!token)
|
||||||
return NULL;
|
return NULL;
|
||||||
|
|
||||||
/* Copy token */
|
/* Copy token */
|
||||||
@ -492,53 +450,42 @@ 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 = str;
|
char *read_ptr = NULL;
|
||||||
char *write_ptr = str;
|
char *write_ptr = NULL;
|
||||||
|
|
||||||
|
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++;
|
||||||
if (*write_ptr != c)
|
write_ptr += (*write_ptr != c) ? 1 : 0;
|
||||||
write_ptr++;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
*write_ptr = '\0';
|
*write_ptr = '\0';
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/* Replaces every instance of character 'find' in 'str'
|
||||||
* string_replace_all_chars:
|
* with character 'replace' */
|
||||||
* @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.
|
||||||
* string_to_unsigned:
|
* Returns 0 if string is invalid */
|
||||||
* @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;
|
||||||
@ -555,33 +502,27 @@ 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 */
|
||||||
if (str[0] != '\0' && str[1] != '\0')
|
len = strlen(str);
|
||||||
{
|
|
||||||
if ( (str[0] == '0') &&
|
if (len >= 2)
|
||||||
((str[1] == 'x') ||
|
if ((str[0] == '0') &&
|
||||||
(str[1] == 'X')))
|
((str[1] == 'x') || (str[1] == 'X')))
|
||||||
{
|
|
||||||
hex_str = str + 2;
|
hex_str = str + 2;
|
||||||
if (string_is_empty(hex_str))
|
|
||||||
return 0;
|
if (string_is_empty(hex_str))
|
||||||
}
|
|
||||||
}
|
|
||||||
else
|
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
/* Check for valid characters */
|
/* Check for valid characters */
|
||||||
@ -593,117 +534,3 @@ 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,6 +22,7 @@
|
|||||||
|
|
||||||
#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
|
||||||
|
|
||||||
@ -40,6 +41,8 @@ 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> /* string_is_empty */
|
#include <string/stdstring.h>
|
||||||
|
|
||||||
#ifdef HAVE_CONFIG_H
|
#ifdef HAVE_CONFIG_H
|
||||||
#include "config.h"
|
#include "config.h"
|
||||||
@ -57,6 +57,11 @@
|
|||||||
# 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
|
||||||
@ -69,6 +74,11 @@
|
|||||||
# 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>
|
||||||
@ -114,66 +124,19 @@
|
|||||||
#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__)
|
||||||
#define FS_SUCCEEDED 0
|
#include <defines/ps3_defines.h>
|
||||||
#define FS_TYPE_DIR 1
|
#if defined(__PSL1GHT__)
|
||||||
#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
|
||||||
|
|
||||||
@ -237,6 +200,13 @@ 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
|
||||||
@ -299,9 +269,22 @@ 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 =
|
||||||
(libretro_vfs_implementation_file*)
|
(libretro_vfs_implementation_file*)
|
||||||
malloc(sizeof(*stream));
|
malloc(sizeof(*stream));
|
||||||
|
|
||||||
@ -323,18 +306,9 @@ 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
|
if (path_len >= dumb_prefix_len)
|
||||||
&& path[0] == 'v'
|
if (!memcmp(path, dumb_prefix, dumb_prefix_len))
|
||||||
&& path[1] == 'f'
|
path += dumb_prefix_siz;
|
||||||
&& 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
|
||||||
@ -351,19 +325,13 @@ 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
|
if (path_len > cdrom_prefix_len)
|
||||||
&& path[0] == 'c'
|
|
||||||
&& path[1] == 'd'
|
|
||||||
&& path[2] == 'r'
|
|
||||||
&& path[3] == 'o'
|
|
||||||
&& path[4] == 'm'
|
|
||||||
&& path[5] == ':'
|
|
||||||
&& path[6] == '/'
|
|
||||||
&& path[7] == '/'
|
|
||||||
&& path[8] != '\0')
|
|
||||||
{
|
{
|
||||||
path += sizeof("cdrom://")-1;
|
if (!memcmp(path, cdrom_prefix, cdrom_prefix_len))
|
||||||
stream->scheme = VFS_SCHEME_CDROM;
|
{
|
||||||
|
path += cdrom_prefix_siz;
|
||||||
|
stream->scheme = VFS_SCHEME_CDROM;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
@ -391,20 +359,24 @@ 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;
|
||||||
|
|
||||||
@ -413,10 +385,12 @@ 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;
|
||||||
|
|
||||||
@ -426,6 +400,15 @@ 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)
|
||||||
@ -442,24 +425,25 @@ libretro_vfs_implementation_file *retro_vfs_file_open_impl(
|
|||||||
else
|
else
|
||||||
#endif
|
#endif
|
||||||
{
|
{
|
||||||
if (!(fp = (FILE*)fopen_utf8(path, mode_str)))
|
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
|
||||||
*
|
*
|
||||||
* If the size argument is not zero but buf is NULL,
|
* If the size argument is not zero but buf is NULL,
|
||||||
* a buffer of the given size will be allocated immediately, and
|
* a buffer of the given size will be allocated immediately, and
|
||||||
* released on close. This is an extension to ANSI C.
|
* released on close. This is an extension to ANSI C.
|
||||||
*
|
*
|
||||||
* Since C89 does not support specifying a NULL buffer
|
* Since C89 does not support specifying a NULL buffer
|
||||||
* with a non-zero size, we create and track our own buffer for it.
|
* with a non-zero size, we create and track our own buffer for it.
|
||||||
*/
|
*/
|
||||||
/* TODO: this is only useful for a few platforms,
|
/* TODO: this is only useful for a few platforms,
|
||||||
* find which and add ifdef */
|
* find which and add ifdef */
|
||||||
#if defined(_3DS)
|
#if defined(_3DS)
|
||||||
if (stream->scheme != VFS_SCHEME_CDROM)
|
if (stream->scheme != VFS_SCHEME_CDROM)
|
||||||
@ -471,14 +455,19 @@ 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
|
||||||
@ -514,12 +503,18 @@ 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);
|
||||||
|
|
||||||
if ((stream->mapped = (uint8_t*)mmap((void*)0,
|
stream->mapped = (uint8_t*)mmap((void*)0,
|
||||||
stream->mapsize, PROT_READ, MAP_SHARED, stream->fd, 0)) == MAP_FAILED)
|
stream->mapsize, PROT_READ, MAP_SHARED, stream->fd, 0);
|
||||||
|
|
||||||
|
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)
|
||||||
{
|
{
|
||||||
@ -540,6 +535,7 @@ 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:
|
||||||
@ -574,7 +570,14 @@ 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)
|
||||||
@ -597,7 +600,12 @@ 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)
|
||||||
@ -609,20 +617,18 @@ 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 (stream && _chsize(_fileno(stream->fp), length) == 0)
|
if (_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 (stream && ftruncate(fileno(stream->fp), (off_t)length) == 0)
|
if (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)
|
||||||
@ -636,6 +642,14 @@ 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);
|
||||||
@ -643,12 +657,13 @@ 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
|
||||||
/* Need to check stream->mapped because this function
|
/* Need to check stream->mapped because this function
|
||||||
* is called in filestream_open() */
|
* is called in filestream_open() */
|
||||||
if (stream->mapped && stream->hints &
|
if (stream->mapped && stream->hints &
|
||||||
RETRO_VFS_FILE_ACCESS_HINT_FREQUENT_ACCESS)
|
RETRO_VFS_FILE_ACCESS_HINT_FREQUENT_ACCESS)
|
||||||
return stream->mappos;
|
return stream->mappos;
|
||||||
#endif
|
#endif
|
||||||
@ -661,7 +676,21 @@ 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)
|
||||||
{
|
{
|
||||||
return retro_vfs_file_seek_internal(stream, offset, seek_position);
|
int whence = -1;
|
||||||
|
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,
|
||||||
@ -676,7 +705,13 @@ 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)
|
||||||
@ -699,80 +734,83 @@ 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;
|
|
||||||
ssize_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)
|
||||||
{
|
{
|
||||||
pos = retro_vfs_file_tell_impl(stream);
|
#ifdef ORBIS
|
||||||
result = fwrite(s, 1, (size_t)len, stream->fp);
|
if (orbisWrite(stream->fd, s, (size_t)len) < 0)
|
||||||
|
return -1;
|
||||||
if (result != -1 && pos + result > stream->size)
|
return 0;
|
||||||
stream->size = pos + result;
|
#else
|
||||||
|
return fwrite(s, 1, (size_t)len, stream->fp);
|
||||||
return result;
|
#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)
|
||||||
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 && fflush(stream->fp) == 0)
|
if (!stream)
|
||||||
return 0;
|
return -1;
|
||||||
return -1;
|
#ifdef ORBIS
|
||||||
|
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)
|
||||||
{
|
{
|
||||||
if (path && *path)
|
|
||||||
{
|
|
||||||
int ret = -1;
|
|
||||||
#if defined(_WIN32) && !defined(_XBOX)
|
#if defined(_WIN32) && !defined(_XBOX)
|
||||||
/* Win32 (no Xbox) */
|
/* Win32 (no Xbox) */
|
||||||
|
|
||||||
#if defined(_WIN32_WINNT) && _WIN32_WINNT < 0x0500
|
#if defined(_WIN32_WINNT) && _WIN32_WINNT < 0x0500
|
||||||
char *path_local = NULL;
|
char *path_local = NULL;
|
||||||
if ((path_local = utf8_to_local_string_alloc(path)))
|
|
||||||
{
|
|
||||||
/* We need to check if path is a directory */
|
|
||||||
if ((retro_vfs_stat_impl(path, NULL) & RETRO_VFS_STAT_IS_DIRECTORY) != 0)
|
|
||||||
ret = _rmdir(path_local);
|
|
||||||
else
|
|
||||||
ret = remove(path_local);
|
|
||||||
free(path_local);
|
|
||||||
}
|
|
||||||
#else
|
#else
|
||||||
wchar_t *path_wide = NULL;
|
wchar_t *path_wide = NULL;
|
||||||
if ((path_wide = utf8_to_utf16_string_alloc(path)))
|
|
||||||
{
|
|
||||||
/* We need to check if path is a directory */
|
|
||||||
if ((retro_vfs_stat_impl(path, NULL) & RETRO_VFS_STAT_IS_DIRECTORY) != 0)
|
|
||||||
ret = _wrmdir(path_wide);
|
|
||||||
else
|
|
||||||
ret = _wremove(path_wide);
|
|
||||||
free(path_wide);
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
#else
|
|
||||||
ret = remove(path);
|
|
||||||
#endif
|
#endif
|
||||||
|
if (!path || !*path)
|
||||||
|
return -1;
|
||||||
|
#if defined(_WIN32_WINNT) && _WIN32_WINNT < 0x0500
|
||||||
|
path_local = utf8_to_local_string_alloc(path);
|
||||||
|
|
||||||
|
if (path_local)
|
||||||
|
{
|
||||||
|
int ret = remove(path_local);
|
||||||
|
free(path_local);
|
||||||
|
|
||||||
if (ret == 0)
|
if (ret == 0)
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
#else
|
||||||
|
path_wide = utf8_to_utf16_string_alloc(path);
|
||||||
|
|
||||||
|
if (path_wide)
|
||||||
|
{
|
||||||
|
int ret = _wremove(path_wide);
|
||||||
|
free(path_wide);
|
||||||
|
|
||||||
|
if (ret == 0)
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
return -1;
|
return -1;
|
||||||
|
#elif defined(ORBIS)
|
||||||
|
/* Orbis
|
||||||
|
* TODO/FIXME - stub for now */
|
||||||
|
return 0;
|
||||||
|
#else
|
||||||
|
if (remove(path) == 0)
|
||||||
|
return 0;
|
||||||
|
return -1;
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
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)
|
||||||
@ -824,6 +862,13 @@ 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)
|
||||||
@ -843,123 +888,154 @@ const char *retro_vfs_file_get_path_impl(
|
|||||||
|
|
||||||
int retro_vfs_stat_impl(const char *path, int32_t *size)
|
int retro_vfs_stat_impl(const char *path, int32_t *size)
|
||||||
{
|
{
|
||||||
int ret = RETRO_VFS_STAT_IS_VALID;
|
bool is_dir = false;
|
||||||
|
bool is_character_special = false;
|
||||||
|
#if defined(VITA) || defined(PSP)
|
||||||
|
/* Vita / PSP */
|
||||||
|
SceIoStat buf;
|
||||||
|
int dir_ret;
|
||||||
|
char *tmp = NULL;
|
||||||
|
size_t len = 0;
|
||||||
|
|
||||||
if (!path || !*path)
|
if (!path || !*path)
|
||||||
return 0;
|
return 0;
|
||||||
{
|
|
||||||
#if defined(VITA)
|
|
||||||
/* Vita / PSP */
|
|
||||||
SceIoStat stat_buf;
|
|
||||||
int dir_ret;
|
|
||||||
char *tmp = strdup(path);
|
|
||||||
size_t len = strlen(tmp);
|
|
||||||
if (tmp[len-1] == '/')
|
|
||||||
tmp[len-1] = '\0';
|
|
||||||
|
|
||||||
dir_ret = sceIoGetstat(tmp, &stat_buf);
|
tmp = strdup(path);
|
||||||
free(tmp);
|
len = strlen(tmp);
|
||||||
if (dir_ret < 0)
|
if (tmp[len-1] == '/')
|
||||||
return 0;
|
tmp[len-1] = '\0';
|
||||||
|
|
||||||
if (size)
|
dir_ret = sceIoGetstat(tmp, &buf);
|
||||||
*size = (int32_t)stat_buf.st_size;
|
free(tmp);
|
||||||
|
if (dir_ret < 0)
|
||||||
|
return 0;
|
||||||
|
|
||||||
if (FIO_S_ISDIR(stat_buf.st_mode))
|
if (size)
|
||||||
ret |= RETRO_VFS_STAT_IS_DIRECTORY;
|
*size = (int32_t)buf.st_size;
|
||||||
|
|
||||||
|
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 stat_buf;
|
sysFSStat buf;
|
||||||
|
|
||||||
if (sysFsStat(path, &stat_buf) < 0)
|
if (!path || !*path)
|
||||||
return 0;
|
return 0;
|
||||||
|
if (sysFsStat(path, &buf) < 0)
|
||||||
|
return 0;
|
||||||
|
|
||||||
if (size)
|
if (size)
|
||||||
*size = (int32_t)stat_buf.st_size;
|
*size = (int32_t)buf.st_size;
|
||||||
|
|
||||||
if ((stat_buf.st_mode & S_IFMT) == S_IFDIR)
|
is_dir = ((buf.st_mode & S_IFMT) == S_IFDIR);
|
||||||
ret |= RETRO_VFS_STAT_IS_DIRECTORY;
|
|
||||||
#elif defined(_WIN32)
|
#elif defined(_WIN32)
|
||||||
/* Windows */
|
/* Windows */
|
||||||
struct _stat stat_buf;
|
DWORD file_info;
|
||||||
|
struct _stat buf;
|
||||||
#if defined(LEGACY_WIN32)
|
#if defined(LEGACY_WIN32)
|
||||||
char *path_local = utf8_to_local_string_alloc(path);
|
char *path_local = NULL;
|
||||||
DWORD file_info = GetFileAttributes(path_local);
|
|
||||||
|
|
||||||
if (!string_is_empty(path_local))
|
|
||||||
_stat(path_local, &stat_buf);
|
|
||||||
|
|
||||||
if (path_local)
|
|
||||||
free(path_local);
|
|
||||||
#else
|
#else
|
||||||
wchar_t *path_wide = utf8_to_utf16_string_alloc(path);
|
wchar_t *path_wide = NULL;
|
||||||
DWORD file_info = GetFileAttributesW(path_wide);
|
|
||||||
|
|
||||||
_wstat(path_wide, &stat_buf);
|
|
||||||
|
|
||||||
if (path_wide)
|
|
||||||
free(path_wide);
|
|
||||||
#endif
|
#endif
|
||||||
if (file_info == INVALID_FILE_ATTRIBUTES)
|
|
||||||
return 0;
|
|
||||||
|
|
||||||
if (size)
|
if (!path || !*path)
|
||||||
*size = (int32_t)stat_buf.st_size;
|
return 0;
|
||||||
|
|
||||||
|
#if defined(LEGACY_WIN32)
|
||||||
|
path_local = utf8_to_local_string_alloc(path);
|
||||||
|
file_info = GetFileAttributes(path_local);
|
||||||
|
|
||||||
|
if (!string_is_empty(path_local))
|
||||||
|
_stat(path_local, &buf);
|
||||||
|
|
||||||
|
if (path_local)
|
||||||
|
free(path_local);
|
||||||
|
#else
|
||||||
|
path_wide = utf8_to_utf16_string_alloc(path);
|
||||||
|
file_info = GetFileAttributesW(path_wide);
|
||||||
|
|
||||||
|
_wstat(path_wide, &buf);
|
||||||
|
|
||||||
|
if (path_wide)
|
||||||
|
free(path_wide);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
if (file_info == INVALID_FILE_ATTRIBUTES)
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
if (size)
|
||||||
|
*size = (int32_t)buf.st_size;
|
||||||
|
|
||||||
|
is_dir = (file_info & FILE_ATTRIBUTE_DIRECTORY);
|
||||||
|
|
||||||
if (file_info & FILE_ATTRIBUTE_DIRECTORY)
|
|
||||||
ret |= RETRO_VFS_STAT_IS_DIRECTORY;
|
|
||||||
#elif defined(GEKKO)
|
#elif defined(GEKKO)
|
||||||
/* On GEKKO platforms, paths cannot have
|
/* On GEKKO platforms, paths cannot have
|
||||||
* trailing slashes - we must therefore
|
* trailing slashes - we must therefore
|
||||||
* remove them */
|
* remove them */
|
||||||
size_t len;
|
char *path_buf = NULL;
|
||||||
char *path_buf = NULL;
|
int stat_ret = -1;
|
||||||
struct stat stat_buf;
|
struct stat stat_buf;
|
||||||
|
size_t len;
|
||||||
|
|
||||||
if (!(path_buf = strdup(path)))
|
if (string_is_empty(path))
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
if ((len = strlen(path_buf)) > 0)
|
path_buf = strdup(path);
|
||||||
if (path_buf[len - 1] == '/')
|
if (!path_buf)
|
||||||
path_buf[len - 1] = '\0';
|
return 0;
|
||||||
|
|
||||||
if (stat(path_buf, &stat_buf) < 0)
|
len = strlen(path_buf);
|
||||||
{
|
if (len > 0)
|
||||||
free(path_buf);
|
if (path_buf[len - 1] == '/')
|
||||||
return 0;
|
path_buf[len - 1] = '\0';
|
||||||
}
|
|
||||||
|
|
||||||
free(path_buf);
|
stat_ret = stat(path_buf, &stat_buf);
|
||||||
|
free(path_buf);
|
||||||
if (size)
|
|
||||||
*size = (int32_t)stat_buf.st_size;
|
if (stat_ret < 0)
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
if (size)
|
||||||
|
*size = (int32_t)stat_buf.st_size;
|
||||||
|
|
||||||
|
is_dir = S_ISDIR(stat_buf.st_mode);
|
||||||
|
is_character_special = S_ISCHR(stat_buf.st_mode);
|
||||||
|
|
||||||
if (S_ISDIR(stat_buf.st_mode))
|
|
||||||
ret |= RETRO_VFS_STAT_IS_DIRECTORY;
|
|
||||||
if (S_ISCHR(stat_buf.st_mode))
|
|
||||||
ret |= RETRO_VFS_STAT_IS_CHARACTER_SPECIAL;
|
|
||||||
#else
|
#else
|
||||||
/* Every other platform */
|
/* Every other platform */
|
||||||
struct stat stat_buf;
|
struct stat buf;
|
||||||
|
|
||||||
if (stat(path, &stat_buf) < 0)
|
if (!path || !*path)
|
||||||
return 0;
|
return 0;
|
||||||
|
if (stat(path, &buf) < 0)
|
||||||
|
return 0;
|
||||||
|
|
||||||
if (size)
|
if (size)
|
||||||
*size = (int32_t)stat_buf.st_size;
|
*size = (int32_t)buf.st_size;
|
||||||
|
|
||||||
if (S_ISDIR(stat_buf.st_mode))
|
is_dir = S_ISDIR(buf.st_mode);
|
||||||
ret |= RETRO_VFS_STAT_IS_DIRECTORY;
|
is_character_special = S_ISCHR(buf.st_mode);
|
||||||
if (S_ISCHR(stat_buf.st_mode))
|
|
||||||
ret |= RETRO_VFS_STAT_IS_CHARACTER_SPECIAL;
|
|
||||||
#endif
|
#endif
|
||||||
}
|
return RETRO_VFS_STAT_IS_VALID | (is_dir ? RETRO_VFS_STAT_IS_DIRECTORY : 0) | (is_character_special ? RETRO_VFS_STAT_IS_CHARACTER_SPECIAL : 0);
|
||||||
return ret;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#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)
|
#elif defined(PSP) || defined(PS2) || defined(_3DS) || defined(WIIU) || defined(SWITCH) || defined(ORBIS)
|
||||||
#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)
|
||||||
@ -982,11 +1058,13 @@ 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)
|
#elif defined(VITA) || defined(PSP)
|
||||||
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) || defined(WIIU)
|
#elif defined(GEKKO)
|
||||||
/* 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. */
|
||||||
@ -1033,13 +1111,16 @@ 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)
|
#elif defined(VITA) || defined(PSP)
|
||||||
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;
|
||||||
@ -1050,7 +1131,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(ORBIS)
|
#elif defined(VITA) || defined(PSP) || 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);
|
||||||
@ -1063,6 +1144,7 @@ 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)
|
||||||
@ -1073,25 +1155,28 @@ 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*/
|
||||||
if (!(rdir = (libretro_vfs_implementation_dir*)
|
rdir = (libretro_vfs_implementation_dir*)calloc(1, sizeof(*rdir));
|
||||||
calloc(1, sizeof(*rdir))))
|
if (!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 (path_buf[copied - 1] != '\\')
|
if (name[path_len - 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)
|
||||||
@ -1108,13 +1193,15 @@ libretro_vfs_implementation_dir *retro_vfs_opendir_impl(
|
|||||||
free(path_wide);
|
free(path_wide);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#elif defined(VITA)
|
#elif defined(VITA) || defined(PSP)
|
||||||
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;
|
||||||
@ -1146,12 +1233,14 @@ 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)
|
#elif defined(VITA) || defined(PSP)
|
||||||
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
|
||||||
@ -1170,7 +1259,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(__PSL1GHT__) || defined(__PS3__)
|
#elif defined(VITA) || defined(PSP) || defined(ORBIS) || defined(__PSL1GHT__) || defined(__PS3__)
|
||||||
return rdir->entry.d_name;
|
return rdir->entry.d_name;
|
||||||
#else
|
#else
|
||||||
if (!rdir || !rdir->entry)
|
if (!rdir || !rdir->entry)
|
||||||
@ -1184,12 +1273,22 @@ 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(VITA)
|
#elif defined(PSP) || defined(VITA)
|
||||||
const SceIoDirent *entry = (const SceIoDirent*)&rdir->entry;
|
const SceIoDirent *entry = (const SceIoDirent*)&rdir->entry;
|
||||||
|
#if defined(PSP)
|
||||||
|
return (entry->d_stat.st_attr & FIO_SO_IFDIR) == FIO_SO_IFDIR;
|
||||||
|
#elif defined(VITA)
|
||||||
return SCE_S_ISDIR(entry->d_stat.st_mode);
|
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];
|
||||||
@ -1202,7 +1301,8 @@ 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 ... */
|
||||||
fill_pathname_join_special(path, rdir->orig_path, retro_vfs_dirent_get_name_impl(rdir), sizeof(path));
|
path[0] = '\0';
|
||||||
|
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);
|
||||||
@ -1217,10 +1317,12 @@ 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)
|
#elif defined(VITA) || defined(PSP)
|
||||||
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);
|
||||||
|
Loading…
Reference in New Issue
Block a user