mirror of
https://github.com/libretro/beetle-pce-fast-libretro.git
synced 2024-11-22 23:39:50 +00:00
Update libretro-common
This commit is contained in:
parent
b2c50422b4
commit
df79493f3c
@ -217,7 +217,8 @@ ifneq ($(STATIC_LINKING), 1)
|
||||
$(LIBRETRO_COMM_DIR)/encodings/encoding_utf.c \
|
||||
$(LIBRETRO_COMM_DIR)/encodings/encoding_crc32.c \
|
||||
$(LIBRETRO_COMM_DIR)/memmap/memalign.c \
|
||||
$(LIBRETRO_COMM_DIR)/string/stdstring.c
|
||||
$(LIBRETRO_COMM_DIR)/string/stdstring.c \
|
||||
$(LIBRETRO_COMM_DIR)/time/rtime.c
|
||||
|
||||
ifneq (,$(findstring uwp,$(PlatformSuffix)))
|
||||
SOURCES_CXX += $(LIBRETRO_COMM_DIR)/vfs/vfs_implementation_uwp.cpp
|
||||
|
@ -1,4 +1,4 @@
|
||||
/* Copyright (C) 2010-2019 The RetroArch team
|
||||
/* Copyright (C) 2010-2020 The RetroArch team
|
||||
*
|
||||
* ---------------------------------------------------------------------------------------
|
||||
* The following license statement only applies to this file (cdrom.c).
|
||||
@ -29,6 +29,7 @@
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include <compat/strl.h>
|
||||
#include <compat/strcasestr.h>
|
||||
#include <retro_math.h>
|
||||
#include <retro_timers.h>
|
||||
#include <streams/file_stream.h>
|
||||
@ -96,6 +97,7 @@ void increment_msf(unsigned char *min, unsigned char *sec, unsigned char *frame)
|
||||
*frame = (*frame < 74) ? (*frame + 1) : 0;
|
||||
}
|
||||
|
||||
#ifdef CDROM_DEBUG
|
||||
static void cdrom_print_sense_data(const unsigned char *sense, size_t len)
|
||||
{
|
||||
unsigned i;
|
||||
@ -252,6 +254,7 @@ static void cdrom_print_sense_data(const unsigned char *sense, size_t len)
|
||||
|
||||
fflush(stdout);
|
||||
}
|
||||
#endif
|
||||
|
||||
#if defined(_WIN32) && !defined(_XBOX)
|
||||
static int cdrom_send_command_win32(const libretro_vfs_implementation_file *stream, CDROM_CMD_Direction dir, void *buf, size_t len, unsigned char *cmd, size_t cmd_len, unsigned char *sense, size_t sense_len)
|
||||
@ -519,7 +522,9 @@ retry:
|
||||
}
|
||||
else
|
||||
{
|
||||
#ifdef CDROM_DEBUG
|
||||
cdrom_print_sense_data(sense, sizeof(sense));
|
||||
#endif
|
||||
|
||||
/* INQUIRY/TEST/SENSE should never fail, don't retry. */
|
||||
/* READ ATIP seems to fail outright on some drives with pressed discs, skip retries. */
|
||||
@ -672,7 +677,9 @@ int cdrom_get_sense(libretro_vfs_implementation_file *stream, unsigned char *sen
|
||||
if (rv)
|
||||
return 1;
|
||||
|
||||
#ifdef CDROM_DEBUG
|
||||
cdrom_print_sense_data(buf, sizeof(buf));
|
||||
#endif
|
||||
|
||||
return 0;
|
||||
}
|
||||
@ -1336,22 +1343,26 @@ struct string_list* cdrom_get_available_drives(void)
|
||||
|
||||
for (i = 0; i < (int)dir_list->size; i++)
|
||||
{
|
||||
if (strstr(dir_list->elems[i].data, "/dev/sg"))
|
||||
if (string_starts_with_size(dir_list->elems[i].data, "/dev/sg",
|
||||
STRLEN_CONST("/dev/sg")))
|
||||
{
|
||||
char drive_model[32] = {0};
|
||||
char drive_string[33] = {0};
|
||||
union string_list_elem_attr attr = {0};
|
||||
int dev_index = 0;
|
||||
RFILE *file = filestream_open(dir_list->elems[i].data, RETRO_VFS_FILE_ACCESS_READ, 0);
|
||||
libretro_vfs_implementation_file *stream;
|
||||
bool is_cdrom = false;
|
||||
char drive_model[32] = {0};
|
||||
char drive_string[33] = {0};
|
||||
union string_list_elem_attr attr = {0};
|
||||
int dev_index = 0;
|
||||
RFILE *file = filestream_open(
|
||||
dir_list->elems[i].data, RETRO_VFS_FILE_ACCESS_READ, 0);
|
||||
bool is_cdrom = false;
|
||||
|
||||
found = true;
|
||||
|
||||
if (!file)
|
||||
{
|
||||
#ifdef CDROM_DEBUG
|
||||
printf("[CDROM] Could not open %s, please check permissions.\n", dir_list->elems[i].data);
|
||||
fflush(stdout);
|
||||
#endif
|
||||
continue;
|
||||
}
|
||||
|
||||
@ -1362,10 +1373,11 @@ struct string_list* cdrom_get_available_drives(void)
|
||||
if (!is_cdrom)
|
||||
continue;
|
||||
|
||||
sscanf(dir_list->elems[i].data + strlen("/dev/sg"), "%d", &dev_index);
|
||||
sscanf(dir_list->elems[i].data + STRLEN_CONST("/dev/sg"),
|
||||
"%d", &dev_index);
|
||||
|
||||
dev_index = '0' + dev_index;
|
||||
attr.i = dev_index;
|
||||
attr.i = dev_index;
|
||||
|
||||
if (!string_is_empty(drive_model))
|
||||
strlcat(drive_string, drive_model, sizeof(drive_string));
|
||||
@ -1378,29 +1390,34 @@ struct string_list* cdrom_get_available_drives(void)
|
||||
|
||||
if (!found)
|
||||
{
|
||||
char *buf = NULL;
|
||||
char *buf = NULL;
|
||||
int64_t len = 0;
|
||||
|
||||
if (filestream_read_file("/proc/modules", (void**)&buf, &len))
|
||||
{
|
||||
struct string_list *mods = string_split(buf, "\n");
|
||||
bool found = false;
|
||||
#ifdef CDROM_DEBUG
|
||||
bool found = false;
|
||||
#endif
|
||||
struct string_list mods = {0};
|
||||
|
||||
if (mods)
|
||||
string_list_initialize(&mods);
|
||||
|
||||
if (string_split_noalloc(&mods, buf, "\n"))
|
||||
{
|
||||
|
||||
for (i = 0; i < mods->size; i++)
|
||||
for (i = 0; i < mods.size; i++)
|
||||
{
|
||||
if (strcasestr(mods->elems[i].data, "sg "))
|
||||
if (strcasestr(mods.elems[i].data, "sg "))
|
||||
{
|
||||
#ifdef CDROM_DEBUG
|
||||
found = true;
|
||||
#endif
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
string_list_free(mods);
|
||||
}
|
||||
string_list_deinitialize(&mods);
|
||||
|
||||
#ifdef CDROM_DEBUG
|
||||
if (found)
|
||||
{
|
||||
printf("[CDROM] No sg devices found but kernel module is loaded.\n");
|
||||
@ -1411,12 +1428,15 @@ struct string_list* cdrom_get_available_drives(void)
|
||||
printf("[CDROM] No sg devices found and sg kernel module is not loaded.\n");
|
||||
fflush(stdout);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
#ifdef CDROM_DEBUG
|
||||
else
|
||||
{
|
||||
printf("[CDROM] No sg devices found, could not check if sg kernel module is loaded.\n");
|
||||
fflush(stdout);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
string_list_free(dir_list);
|
||||
|
@ -1,4 +1,4 @@
|
||||
/* Copyright (C) 2010-2018 The RetroArch team
|
||||
/* Copyright (C) 2010-2020 The RetroArch team
|
||||
*
|
||||
* ---------------------------------------------------------------------------------------
|
||||
* The following license statement only applies to this file (compat_posix_string.c).
|
||||
|
@ -1,4 +1,4 @@
|
||||
/* Copyright (C) 2010-2018 The RetroArch team
|
||||
/* Copyright (C) 2010-2020 The RetroArch team
|
||||
*
|
||||
* ---------------------------------------------------------------------------------------
|
||||
* The following license statement only applies to this file (compat_snprintf.c).
|
||||
@ -33,12 +33,12 @@
|
||||
#if _MSC_VER < 1300
|
||||
#define _vscprintf c89_vscprintf_retro__
|
||||
|
||||
static int c89_vscprintf_retro__(const char *format, va_list pargs)
|
||||
static int c89_vscprintf_retro__(const char *fmt, va_list pargs)
|
||||
{
|
||||
int retval;
|
||||
va_list argcopy;
|
||||
va_copy(argcopy, pargs);
|
||||
retval = vsnprintf(NULL, 0, format, argcopy);
|
||||
retval = vsnprintf(NULL, 0, fmt, argcopy);
|
||||
va_end(argcopy);
|
||||
return retval;
|
||||
}
|
||||
@ -46,38 +46,36 @@ static int c89_vscprintf_retro__(const char *format, va_list pargs)
|
||||
|
||||
/* http://stackoverflow.com/questions/2915672/snprintf-and-visual-studio-2010 */
|
||||
|
||||
int c99_vsnprintf_retro__(char *outBuf, size_t size, const char *format, va_list ap)
|
||||
int c99_vsnprintf_retro__(char *s, size_t len, const char *fmt, va_list ap)
|
||||
{
|
||||
int count = -1;
|
||||
|
||||
if (size != 0)
|
||||
if (len != 0)
|
||||
{
|
||||
#if (_MSC_VER <= 1310)
|
||||
count = _vsnprintf(outBuf, size - 1, format, ap);
|
||||
count = _vsnprintf(s, len - 1, fmt, ap);
|
||||
#else
|
||||
count = _vsnprintf_s(outBuf, size, size - 1, format, ap);
|
||||
count = _vsnprintf_s(s, len, len - 1, fmt, ap);
|
||||
#endif
|
||||
}
|
||||
|
||||
if (count == -1)
|
||||
count = _vscprintf(format, ap);
|
||||
count = _vscprintf(fmt, ap);
|
||||
|
||||
if (count == size)
|
||||
{
|
||||
/* there was no room for a NULL, so truncate the last character */
|
||||
outBuf[size - 1] = '\0';
|
||||
}
|
||||
/* there was no room for a NULL, so truncate the last character */
|
||||
if (count == len && len)
|
||||
s[len - 1] = '\0';
|
||||
|
||||
return count;
|
||||
}
|
||||
|
||||
int c99_snprintf_retro__(char *outBuf, size_t size, const char *format, ...)
|
||||
int c99_snprintf_retro__(char *s, size_t len, const char *fmt, ...)
|
||||
{
|
||||
int count;
|
||||
va_list ap;
|
||||
|
||||
va_start(ap, format);
|
||||
count = c99_vsnprintf_retro__(outBuf, size, format, ap);
|
||||
va_start(ap, fmt);
|
||||
count = c99_vsnprintf_retro__(s, len, fmt, ap);
|
||||
va_end(ap);
|
||||
|
||||
return count;
|
||||
|
@ -1,4 +1,4 @@
|
||||
/* Copyright (C) 2010-2018 The RetroArch team
|
||||
/* Copyright (C) 2010-2020 The RetroArch team
|
||||
*
|
||||
* ---------------------------------------------------------------------------------------
|
||||
* The following license statement only applies to this file (compat_strcasestr.c).
|
||||
|
@ -1,4 +1,4 @@
|
||||
/* Copyright (C) 2010-2018 The RetroArch team
|
||||
/* Copyright (C) 2010-2020 The RetroArch team
|
||||
*
|
||||
* ---------------------------------------------------------------------------------------
|
||||
* The following license statement only applies to this file (compat_strl.c).
|
||||
|
@ -1,4 +1,4 @@
|
||||
/* Copyright (C) 2010-2018 The RetroArch team
|
||||
/* Copyright (C) 2010-2020 The RetroArch team
|
||||
*
|
||||
* ---------------------------------------------------------------------------------------
|
||||
* The following license statement only applies to this file (fopen_utf8.c).
|
||||
|
@ -1,4 +1,4 @@
|
||||
/* Copyright (C) 2010-2018 The RetroArch team
|
||||
/* Copyright (C) 2010-2020 The RetroArch team
|
||||
*
|
||||
* ---------------------------------------------------------------------------------------
|
||||
* The following license statement only applies to this file (encoding_crc32.c).
|
||||
@ -117,7 +117,7 @@ uint32_t file_crc32(uint32_t crc, const char *path)
|
||||
if (!buf)
|
||||
goto error;
|
||||
|
||||
for(i = 0; i < CRC32_MAX_MB; i++)
|
||||
for (i = 0; i < CRC32_MAX_MB; i++)
|
||||
{
|
||||
int64_t nread = filestream_read(file, buf, CRC32_BUFFER_SIZE);
|
||||
if (nread < 0)
|
||||
|
@ -1,4 +1,4 @@
|
||||
/* Copyright (C) 2010-2018 The RetroArch team
|
||||
/* Copyright (C) 2010-2020 The RetroArch team
|
||||
*
|
||||
* ---------------------------------------------------------------------------------------
|
||||
* The following license statement only applies to this file (encoding_utf.c).
|
||||
@ -37,6 +37,8 @@
|
||||
#include <xtl.h>
|
||||
#endif
|
||||
|
||||
#define UTF8_WALKBYTE(string) (*((*(string))++))
|
||||
|
||||
static unsigned leading_ones(uint8_t c)
|
||||
{
|
||||
unsigned ones = 0;
|
||||
@ -89,13 +91,14 @@ size_t utf8_conv_utf32(uint32_t *out, size_t out_chars,
|
||||
bool utf16_conv_utf8(uint8_t *out, size_t *out_chars,
|
||||
const uint16_t *in, size_t in_size)
|
||||
{
|
||||
static uint8_t kUtf8Limits[5] = { 0xC0, 0xE0, 0xF0, 0xF8, 0xFC };
|
||||
size_t out_pos = 0;
|
||||
size_t in_pos = 0;
|
||||
size_t out_pos = 0;
|
||||
size_t in_pos = 0;
|
||||
static const
|
||||
uint8_t utf8_limits[5] = { 0xC0, 0xE0, 0xF0, 0xF8, 0xFC };
|
||||
|
||||
for (;;)
|
||||
{
|
||||
unsigned numAdds;
|
||||
unsigned num_adds;
|
||||
uint32_t value;
|
||||
|
||||
if (in_pos == in_size)
|
||||
@ -124,21 +127,21 @@ bool utf16_conv_utf8(uint8_t *out, size_t *out_chars,
|
||||
value = (((value - 0xD800) << 10) | (c2 - 0xDC00)) + 0x10000;
|
||||
}
|
||||
|
||||
for (numAdds = 1; numAdds < 5; numAdds++)
|
||||
if (value < (((uint32_t)1) << (numAdds * 5 + 6)))
|
||||
for (num_adds = 1; num_adds < 5; num_adds++)
|
||||
if (value < (((uint32_t)1) << (num_adds * 5 + 6)))
|
||||
break;
|
||||
if (out)
|
||||
out[out_pos] = (char)(kUtf8Limits[numAdds - 1]
|
||||
+ (value >> (6 * numAdds)));
|
||||
out[out_pos] = (char)(utf8_limits[num_adds - 1]
|
||||
+ (value >> (6 * num_adds)));
|
||||
out_pos++;
|
||||
do
|
||||
{
|
||||
numAdds--;
|
||||
num_adds--;
|
||||
if (out)
|
||||
out[out_pos] = (char)(0x80
|
||||
+ ((value >> (6 * numAdds)) & 0x3F));
|
||||
+ ((value >> (6 * num_adds)) & 0x3F));
|
||||
out_pos++;
|
||||
}while (numAdds != 0);
|
||||
}while (num_adds != 0);
|
||||
}
|
||||
|
||||
*out_chars = out_pos;
|
||||
@ -166,13 +169,15 @@ size_t utf8cpy(char *d, size_t d_len, const char *s, size_t chars)
|
||||
while (*sb && chars-- > 0)
|
||||
{
|
||||
sb++;
|
||||
while ((*sb & 0xC0) == 0x80) sb++;
|
||||
while ((*sb & 0xC0) == 0x80)
|
||||
sb++;
|
||||
}
|
||||
|
||||
if ((size_t)(sb - sb_org) > d_len-1 /* NUL */)
|
||||
{
|
||||
sb = sb_org + d_len-1;
|
||||
while ((*sb & 0xC0) == 0x80) sb--;
|
||||
while ((*sb & 0xC0) == 0x80)
|
||||
sb--;
|
||||
}
|
||||
|
||||
memcpy(d, sb_org, sb-sb_org);
|
||||
@ -184,14 +189,18 @@ size_t utf8cpy(char *d, size_t d_len, const char *s, size_t chars)
|
||||
const char *utf8skip(const char *str, size_t chars)
|
||||
{
|
||||
const uint8_t *strb = (const uint8_t*)str;
|
||||
|
||||
if (!chars)
|
||||
return str;
|
||||
|
||||
do
|
||||
{
|
||||
strb++;
|
||||
while ((*strb & 0xC0)==0x80) strb++;
|
||||
while ((*strb & 0xC0)==0x80)
|
||||
strb++;
|
||||
chars--;
|
||||
} while(chars);
|
||||
}while (chars);
|
||||
|
||||
return (const char*)strb;
|
||||
}
|
||||
|
||||
@ -211,24 +220,22 @@ size_t utf8len(const char *string)
|
||||
return ret;
|
||||
}
|
||||
|
||||
#define utf8_walkbyte(string) (*((*(string))++))
|
||||
|
||||
/* Does not validate the input, returns garbage if it's not UTF-8. */
|
||||
uint32_t utf8_walk(const char **string)
|
||||
{
|
||||
uint8_t first = utf8_walkbyte(string);
|
||||
uint8_t first = UTF8_WALKBYTE(string);
|
||||
uint32_t ret = 0;
|
||||
|
||||
if (first < 128)
|
||||
return first;
|
||||
|
||||
ret = (ret << 6) | (utf8_walkbyte(string) & 0x3F);
|
||||
ret = (ret << 6) | (UTF8_WALKBYTE(string) & 0x3F);
|
||||
if (first >= 0xE0)
|
||||
{
|
||||
ret = (ret << 6) | (utf8_walkbyte(string) & 0x3F);
|
||||
ret = (ret << 6) | (UTF8_WALKBYTE(string) & 0x3F);
|
||||
if (first >= 0xF0)
|
||||
{
|
||||
ret = (ret << 6) | (utf8_walkbyte(string) & 0x3F);
|
||||
ret = (ret << 6) | (UTF8_WALKBYTE(string) & 0x3F);
|
||||
return ret | (first & 7) << 18;
|
||||
}
|
||||
return ret | (first & 15) << 12;
|
||||
@ -277,9 +284,7 @@ bool utf16_to_char_string(const uint16_t *in, char *s, size_t len)
|
||||
static char *mb_to_mb_string_alloc(const char *str,
|
||||
enum CodePage cp_in, enum CodePage cp_out)
|
||||
{
|
||||
char *path_buf = NULL;
|
||||
wchar_t *path_buf_wide = NULL;
|
||||
int path_buf_len = 0;
|
||||
int path_buf_wide_len = MultiByteToWideChar(cp_in, 0, str, -1, NULL, 0);
|
||||
|
||||
/* Windows 95 will return 0 from these functions with
|
||||
@ -292,54 +297,51 @@ static char *mb_to_mb_string_alloc(const char *str,
|
||||
* MultiByteToWideChar also supports CP_UTF7 and CP_UTF8.
|
||||
*/
|
||||
|
||||
if (path_buf_wide_len)
|
||||
{
|
||||
path_buf_wide = (wchar_t*)
|
||||
calloc(path_buf_wide_len + sizeof(wchar_t), sizeof(wchar_t));
|
||||
|
||||
if (path_buf_wide)
|
||||
{
|
||||
MultiByteToWideChar(cp_in, 0,
|
||||
str, -1, path_buf_wide, path_buf_wide_len);
|
||||
|
||||
if (*path_buf_wide)
|
||||
{
|
||||
path_buf_len = WideCharToMultiByte(cp_out, 0,
|
||||
path_buf_wide, -1, NULL, 0, NULL, NULL);
|
||||
|
||||
if (path_buf_len)
|
||||
{
|
||||
path_buf = (char*)
|
||||
calloc(path_buf_len + sizeof(char), sizeof(char));
|
||||
|
||||
if (path_buf)
|
||||
{
|
||||
WideCharToMultiByte(cp_out, 0,
|
||||
path_buf_wide, -1, path_buf,
|
||||
path_buf_len, NULL, NULL);
|
||||
|
||||
free(path_buf_wide);
|
||||
|
||||
if (*path_buf)
|
||||
return path_buf;
|
||||
|
||||
free(path_buf);
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
free(path_buf_wide);
|
||||
return strdup(str);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
if (!path_buf_wide_len)
|
||||
return strdup(str);
|
||||
|
||||
path_buf_wide = (wchar_t*)
|
||||
calloc(path_buf_wide_len + sizeof(wchar_t), sizeof(wchar_t));
|
||||
|
||||
if (path_buf_wide)
|
||||
{
|
||||
MultiByteToWideChar(cp_in, 0,
|
||||
str, -1, path_buf_wide, path_buf_wide_len);
|
||||
|
||||
if (*path_buf_wide)
|
||||
{
|
||||
int path_buf_len = WideCharToMultiByte(cp_out, 0,
|
||||
path_buf_wide, -1, NULL, 0, NULL, NULL);
|
||||
|
||||
if (path_buf_len)
|
||||
{
|
||||
char *path_buf = (char*)
|
||||
calloc(path_buf_len + sizeof(char), sizeof(char));
|
||||
|
||||
if (path_buf)
|
||||
{
|
||||
WideCharToMultiByte(cp_out, 0,
|
||||
path_buf_wide, -1, path_buf,
|
||||
path_buf_len, NULL, NULL);
|
||||
|
||||
free(path_buf_wide);
|
||||
|
||||
if (*path_buf)
|
||||
return path_buf;
|
||||
|
||||
free(path_buf);
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
free(path_buf_wide);
|
||||
return strdup(str);
|
||||
}
|
||||
}
|
||||
|
||||
free(path_buf_wide);
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
@ -379,13 +381,13 @@ char* local_to_utf8_string_alloc(const char *str)
|
||||
wchar_t* utf8_to_utf16_string_alloc(const char *str)
|
||||
{
|
||||
#ifdef _WIN32
|
||||
int len = 0;
|
||||
int out_len = 0;
|
||||
int len = 0;
|
||||
int out_len = 0;
|
||||
#else
|
||||
size_t len = 0;
|
||||
size_t len = 0;
|
||||
size_t out_len = 0;
|
||||
#endif
|
||||
wchar_t *buf = NULL;
|
||||
wchar_t *buf = NULL;
|
||||
|
||||
if (!str || !*str)
|
||||
return NULL;
|
||||
|
@ -1,4 +1,4 @@
|
||||
/* Copyright (C) 2010-2019 The RetroArch team
|
||||
/* Copyright (C) 2010-2020 The RetroArch team
|
||||
*
|
||||
* ---------------------------------------------------------------------------------------
|
||||
* The following license statement only applies to this file (file_path.c).
|
||||
@ -32,8 +32,7 @@
|
||||
#include <file/file_path.h>
|
||||
#include <retro_assert.h>
|
||||
#include <string/stdstring.h>
|
||||
#define VFS_FRONTEND
|
||||
#include <vfs/vfs_implementation.h>
|
||||
#include <time/rtime.h>
|
||||
|
||||
/* TODO: There are probably some unnecessary things on this huge include list now but I'm too afraid to touch it */
|
||||
#ifdef __APPLE__
|
||||
@ -46,7 +45,6 @@
|
||||
#include <compat/strl.h>
|
||||
#include <compat/posix_string.h>
|
||||
#endif
|
||||
#include <compat/strcasestr.h>
|
||||
#include <retro_miscellaneous.h>
|
||||
#include <encodings/utf.h>
|
||||
|
||||
@ -82,12 +80,7 @@
|
||||
#include <pspkernel.h>
|
||||
#endif
|
||||
|
||||
#if defined(PS2)
|
||||
#include <fileXio_rpc.h>
|
||||
#include <fileXio.h>
|
||||
#endif
|
||||
|
||||
#if defined(__CELLOS_LV2__)
|
||||
#if defined(__CELLOS_LV2__) && !defined(__PSL1GHT__)
|
||||
#include <cell/cell_fs.h>
|
||||
#endif
|
||||
|
||||
@ -95,7 +88,7 @@
|
||||
#define FIO_S_ISDIR SCE_S_ISDIR
|
||||
#endif
|
||||
|
||||
#if (defined(__CELLOS_LV2__) && !defined(__PSL1GHT__)) || defined(__QNX__) || defined(PSP) || defined(PS2)
|
||||
#if (defined(__CELLOS_LV2__) && !defined(__PSL1GHT__)) || defined(__QNX__) || defined(PSP)
|
||||
#include <unistd.h> /* stat() is defined here */
|
||||
#endif
|
||||
|
||||
@ -114,133 +107,6 @@
|
||||
|
||||
#endif
|
||||
|
||||
static retro_vfs_stat_t path_stat_cb = retro_vfs_stat_impl;
|
||||
static retro_vfs_mkdir_t path_mkdir_cb = retro_vfs_mkdir_impl;
|
||||
|
||||
void path_vfs_init(const struct retro_vfs_interface_info* vfs_info)
|
||||
{
|
||||
const struct retro_vfs_interface*
|
||||
vfs_iface = vfs_info->iface;
|
||||
|
||||
path_stat_cb = retro_vfs_stat_impl;
|
||||
path_mkdir_cb = retro_vfs_mkdir_impl;
|
||||
|
||||
if (vfs_info->required_interface_version < PATH_REQUIRED_VFS_VERSION || !vfs_iface)
|
||||
return;
|
||||
|
||||
path_stat_cb = vfs_iface->stat;
|
||||
path_mkdir_cb = vfs_iface->mkdir;
|
||||
}
|
||||
|
||||
int path_stat(const char *path)
|
||||
{
|
||||
return path_stat_cb(path, NULL);
|
||||
}
|
||||
|
||||
/**
|
||||
* path_is_directory:
|
||||
* @path : path
|
||||
*
|
||||
* Checks if path is a directory.
|
||||
*
|
||||
* Returns: true (1) if path is a directory, otherwise false (0).
|
||||
*/
|
||||
bool path_is_directory(const char *path)
|
||||
{
|
||||
return (path_stat_cb(path, NULL) & RETRO_VFS_STAT_IS_DIRECTORY) != 0;
|
||||
}
|
||||
|
||||
bool path_is_character_special(const char *path)
|
||||
{
|
||||
return (path_stat_cb(path, NULL) & RETRO_VFS_STAT_IS_CHARACTER_SPECIAL) != 0;
|
||||
}
|
||||
|
||||
bool path_is_valid(const char *path)
|
||||
{
|
||||
return (path_stat_cb(path, NULL) & RETRO_VFS_STAT_IS_VALID) != 0;
|
||||
}
|
||||
|
||||
int32_t path_get_size(const char *path)
|
||||
{
|
||||
int32_t filesize = 0;
|
||||
if (path_stat_cb(path, &filesize) != 0)
|
||||
return filesize;
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
/**
|
||||
* path_mkdir:
|
||||
* @dir : directory
|
||||
*
|
||||
* Create directory on filesystem.
|
||||
*
|
||||
* Returns: true (1) if directory could be created, otherwise false (0).
|
||||
**/
|
||||
bool path_mkdir(const char *dir)
|
||||
{
|
||||
bool sret = false;
|
||||
bool norecurse = false;
|
||||
char *basedir = NULL;
|
||||
|
||||
if (!(dir && *dir))
|
||||
return false;
|
||||
|
||||
/* Use heap. Real chance of stack
|
||||
* overflow if we recurse too hard. */
|
||||
basedir = strdup(dir);
|
||||
|
||||
if (!basedir)
|
||||
return false;
|
||||
|
||||
path_parent_dir(basedir);
|
||||
|
||||
if (!*basedir || !strcmp(basedir, dir))
|
||||
{
|
||||
free(basedir);
|
||||
return false;
|
||||
}
|
||||
|
||||
#if defined(GEKKO)
|
||||
{
|
||||
size_t len = strlen(basedir);
|
||||
|
||||
/* path_parent_dir() keeps the trailing slash.
|
||||
* On Wii, mkdir() fails if the path has a
|
||||
* trailing slash...
|
||||
* We must therefore remove it. */
|
||||
if (len > 0)
|
||||
if (basedir[len - 1] == '/')
|
||||
basedir[len - 1] = '\0';
|
||||
}
|
||||
#endif
|
||||
|
||||
if (path_is_directory(basedir))
|
||||
norecurse = true;
|
||||
else
|
||||
{
|
||||
sret = path_mkdir(basedir);
|
||||
|
||||
if (sret)
|
||||
norecurse = true;
|
||||
}
|
||||
|
||||
free(basedir);
|
||||
|
||||
if (norecurse)
|
||||
{
|
||||
int ret = path_mkdir_cb(dir);
|
||||
|
||||
/* Don't treat this as an error. */
|
||||
if (ret == -2 && path_is_directory(dir))
|
||||
return true;
|
||||
|
||||
return (ret == 0);
|
||||
}
|
||||
|
||||
return sret;
|
||||
}
|
||||
|
||||
/**
|
||||
* path_get_archive_delim:
|
||||
* @path : path
|
||||
@ -253,26 +119,48 @@ bool path_mkdir(const char *dir)
|
||||
*/
|
||||
const char *path_get_archive_delim(const char *path)
|
||||
{
|
||||
const char *last = find_last_slash(path);
|
||||
const char *delim = NULL;
|
||||
const char *last_slash = find_last_slash(path);
|
||||
const char *delim = NULL;
|
||||
char buf[5];
|
||||
|
||||
if (!last)
|
||||
buf[0] = '\0';
|
||||
|
||||
if (!last_slash)
|
||||
return NULL;
|
||||
|
||||
/* Test if it's .zip */
|
||||
delim = strcasestr(last, ".zip#");
|
||||
/* Find delimiter position */
|
||||
delim = strrchr(last_slash, '#');
|
||||
|
||||
if (!delim) /* If it's not a .zip, test if it's .apk */
|
||||
delim = strcasestr(last, ".apk#");
|
||||
if (!delim)
|
||||
return NULL;
|
||||
|
||||
if (delim)
|
||||
return delim + 4;
|
||||
/* Check whether this is a known archive type
|
||||
* > Note: The code duplication here is
|
||||
* deliberate, to maximise performance */
|
||||
if (delim - last_slash > 4)
|
||||
{
|
||||
strlcpy(buf, delim - 4, sizeof(buf));
|
||||
buf[4] = '\0';
|
||||
|
||||
/* If it's not a .zip or .apk file, test if it's .7z */
|
||||
delim = strcasestr(last, ".7z#");
|
||||
string_to_lower(buf);
|
||||
|
||||
if (delim)
|
||||
return delim + 3;
|
||||
/* Check if this is a '.zip', '.apk' or '.7z' file */
|
||||
if (string_is_equal(buf, ".zip") ||
|
||||
string_is_equal(buf, ".apk") ||
|
||||
string_is_equal(buf + 1, ".7z"))
|
||||
return delim;
|
||||
}
|
||||
else if (delim - last_slash > 3)
|
||||
{
|
||||
strlcpy(buf, delim - 3, sizeof(buf));
|
||||
buf[3] = '\0';
|
||||
|
||||
string_to_lower(buf);
|
||||
|
||||
/* Check if this is a '.7z' file */
|
||||
if (string_is_equal(buf, ".7z"))
|
||||
return delim;
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
@ -331,9 +219,12 @@ bool path_is_compressed_file(const char* path)
|
||||
{
|
||||
const char *ext = path_get_extension(path);
|
||||
|
||||
if ( strcasestr(ext, "zip")
|
||||
|| strcasestr(ext, "apk")
|
||||
|| strcasestr(ext, "7z"))
|
||||
if (string_is_empty(ext))
|
||||
return false;
|
||||
|
||||
if (string_is_equal_noncase(ext, "zip") ||
|
||||
string_is_equal_noncase(ext, "apk") ||
|
||||
string_is_equal_noncase(ext, "7z"))
|
||||
return true;
|
||||
|
||||
return false;
|
||||
@ -423,7 +314,7 @@ void fill_pathname_slash(char *path, size_t size)
|
||||
|
||||
if (!last_slash)
|
||||
{
|
||||
strlcat(path, path_default_slash(), size);
|
||||
strlcat(path, PATH_DEFAULT_SLASH(), size);
|
||||
return;
|
||||
}
|
||||
|
||||
@ -592,11 +483,13 @@ void fill_pathname_parent_dir(char *out_dir,
|
||||
size_t fill_dated_filename(char *out_filename,
|
||||
const char *ext, size_t size)
|
||||
{
|
||||
time_t cur_time = time(NULL);
|
||||
const struct tm* tm_ = localtime(&cur_time);
|
||||
time_t cur_time = time(NULL);
|
||||
struct tm tm_;
|
||||
|
||||
rtime_localtime(&cur_time, &tm_);
|
||||
|
||||
strftime(out_filename, size,
|
||||
"RetroArch-%m%d-%H%M%S", tm_);
|
||||
"RetroArch-%m%d-%H%M%S", &tm_);
|
||||
return strlcat(out_filename, ext, size);
|
||||
}
|
||||
|
||||
@ -617,19 +510,21 @@ void fill_str_dated_filename(char *out_filename,
|
||||
const char *in_str, const char *ext, size_t size)
|
||||
{
|
||||
char format[256];
|
||||
time_t cur_time = time(NULL);
|
||||
const struct tm* tm_ = localtime(&cur_time);
|
||||
struct tm tm_;
|
||||
time_t cur_time = time(NULL);
|
||||
|
||||
format[0] = '\0';
|
||||
format[0] = '\0';
|
||||
|
||||
rtime_localtime(&cur_time, &tm_);
|
||||
|
||||
if (string_is_empty(ext))
|
||||
{
|
||||
strftime(format, sizeof(format), "-%y%m%d-%H%M%S", tm_);
|
||||
strftime(format, sizeof(format), "-%y%m%d-%H%M%S", &tm_);
|
||||
fill_pathname_noext(out_filename, in_str, format, size);
|
||||
}
|
||||
else
|
||||
{
|
||||
strftime(format, sizeof(format), "-%y%m%d-%H%M%S.", tm_);
|
||||
strftime(format, sizeof(format), "-%y%m%d-%H%M%S.", &tm_);
|
||||
|
||||
fill_pathname_join_concat_noext(out_filename,
|
||||
in_str, format, ext,
|
||||
@ -656,7 +551,7 @@ void path_basedir(char *path)
|
||||
if (last)
|
||||
last[1] = '\0';
|
||||
else
|
||||
snprintf(path, 3, ".%s", path_default_slash());
|
||||
snprintf(path, 3, "." PATH_DEFAULT_SLASH());
|
||||
}
|
||||
|
||||
/**
|
||||
@ -676,7 +571,7 @@ void path_parent_dir(char *path)
|
||||
|
||||
len = strlen(path);
|
||||
|
||||
if (len && path_char_is_slash(path[len - 1]))
|
||||
if (len && PATH_CHAR_IS_SLASH(path[len - 1]))
|
||||
{
|
||||
bool path_was_absolute = path_is_absolute(path);
|
||||
|
||||
@ -731,19 +626,27 @@ const char *path_basename(const char *path)
|
||||
**/
|
||||
bool path_is_absolute(const char *path)
|
||||
{
|
||||
if (string_is_empty(path))
|
||||
return false;
|
||||
|
||||
if (path[0] == '/')
|
||||
return true;
|
||||
#ifdef _WIN32
|
||||
/* Many roads lead to Rome ... */
|
||||
if (( strstr(path, "\\\\") == path)
|
||||
|| strstr(path, ":/")
|
||||
|| strstr(path, ":\\")
|
||||
|| strstr(path, ":\\\\"))
|
||||
return true;
|
||||
#elif defined(__wiiu__)
|
||||
if (strstr(path, ":/"))
|
||||
|
||||
#if defined(_WIN32)
|
||||
/* Many roads lead to Rome...
|
||||
* Note: Drive letter can only be 1 character long */
|
||||
if (string_starts_with_size(path, "\\\\", STRLEN_CONST("\\\\")) ||
|
||||
string_starts_with_size(path + 1, ":/", STRLEN_CONST(":/")) ||
|
||||
string_starts_with_size(path + 1, ":\\", STRLEN_CONST(":\\")))
|
||||
return true;
|
||||
#elif defined(__wiiu__) || defined(VITA)
|
||||
{
|
||||
const char *seperator = strchr(path, ':');
|
||||
if (seperator && (seperator[1] == '/'))
|
||||
return true;
|
||||
}
|
||||
#endif
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
@ -893,7 +796,7 @@ end:
|
||||
size_t path_relative_to(char *out,
|
||||
const char *path, const char *base, size_t size)
|
||||
{
|
||||
size_t i;
|
||||
size_t i, j;
|
||||
const char *trimmed_path, *trimmed_base;
|
||||
|
||||
#ifdef _WIN32
|
||||
@ -905,16 +808,18 @@ size_t path_relative_to(char *out,
|
||||
#endif
|
||||
|
||||
/* Trim common beginning */
|
||||
for (i = 0; path[i] && base[i] && path[i] == base[i]; )
|
||||
i++;
|
||||
trimmed_path = path+i;
|
||||
for (i = 0, j = 0; path[i] && base[i] && path[i] == base[i]; i++)
|
||||
if (path[i] == PATH_DEFAULT_SLASH_C())
|
||||
j = i + 1;
|
||||
|
||||
trimmed_path = path+j;
|
||||
trimmed_base = base+i;
|
||||
|
||||
/* Each segment of base turns into ".." */
|
||||
out[0] = '\0';
|
||||
for (i = 0; trimmed_base[i]; i++)
|
||||
if (trimmed_base[i] == path_default_slash_c())
|
||||
strlcat(out, ".." path_default_slash(), size);
|
||||
if (trimmed_base[i] == PATH_DEFAULT_SLASH_C())
|
||||
strlcat(out, ".." PATH_DEFAULT_SLASH(), size);
|
||||
|
||||
return strlcat(out, trimmed_path, size);
|
||||
}
|
||||
@ -1099,13 +1004,13 @@ void fill_pathname_expand_special(char *out_path,
|
||||
out_path += src_size;
|
||||
size -= src_size;
|
||||
|
||||
if (!path_char_is_slash(out_path[-1]))
|
||||
if (!PATH_CHAR_IS_SLASH(out_path[-1]))
|
||||
{
|
||||
src_size = strlcpy(out_path, path_default_slash(), size);
|
||||
src_size = strlcpy(out_path, PATH_DEFAULT_SLASH(), size);
|
||||
retro_assert(src_size < size);
|
||||
|
||||
out_path += src_size;
|
||||
size -= src_size;
|
||||
size -= src_size;
|
||||
}
|
||||
|
||||
in_path += 2;
|
||||
@ -1130,9 +1035,9 @@ void fill_pathname_expand_special(char *out_path,
|
||||
out_path += src_size;
|
||||
size -= src_size;
|
||||
|
||||
if (!path_char_is_slash(out_path[-1]))
|
||||
if (!PATH_CHAR_IS_SLASH(out_path[-1]))
|
||||
{
|
||||
src_size = strlcpy(out_path, path_default_slash(), size);
|
||||
src_size = strlcpy(out_path, PATH_DEFAULT_SLASH(), size);
|
||||
retro_assert(src_size < size);
|
||||
|
||||
out_path += src_size;
|
||||
@ -1156,10 +1061,11 @@ void fill_pathname_abbreviate_special(char *out_path,
|
||||
unsigned i;
|
||||
const char *candidates[3];
|
||||
const char *notations[3];
|
||||
char *application_dir = (char*)malloc(PATH_MAX_LENGTH * sizeof(char));
|
||||
char *home_dir = (char*)malloc(PATH_MAX_LENGTH * sizeof(char));
|
||||
char application_dir[PATH_MAX_LENGTH];
|
||||
char home_dir[PATH_MAX_LENGTH];
|
||||
|
||||
application_dir[0] = '\0';
|
||||
home_dir[0] = '\0';
|
||||
|
||||
/* application_dir could be zero-string. Safeguard against this.
|
||||
*
|
||||
@ -1176,15 +1082,13 @@ void fill_pathname_abbreviate_special(char *out_path,
|
||||
notations [1] = "~";
|
||||
notations [2] = NULL;
|
||||
|
||||
fill_pathname_application_dir(application_dir,
|
||||
PATH_MAX_LENGTH * sizeof(char));
|
||||
fill_pathname_home_dir(home_dir,
|
||||
PATH_MAX_LENGTH * sizeof(char));
|
||||
fill_pathname_application_dir(application_dir, sizeof(application_dir));
|
||||
fill_pathname_home_dir(home_dir, sizeof(home_dir));
|
||||
|
||||
for (i = 0; candidates[i]; i++)
|
||||
{
|
||||
if (!string_is_empty(candidates[i]) &&
|
||||
strstr(in_path, candidates[i]) == in_path)
|
||||
string_starts_with(in_path, candidates[i]))
|
||||
{
|
||||
size_t src_size = strlcpy(out_path, notations[i], size);
|
||||
|
||||
@ -1194,10 +1098,9 @@ void fill_pathname_abbreviate_special(char *out_path,
|
||||
size -= src_size;
|
||||
in_path += strlen(candidates[i]);
|
||||
|
||||
if (!path_char_is_slash(*in_path))
|
||||
if (!PATH_CHAR_IS_SLASH(*in_path))
|
||||
{
|
||||
retro_assert(strlcpy(out_path,
|
||||
path_default_slash(), size) < size);
|
||||
strcpy_literal(out_path, PATH_DEFAULT_SLASH());
|
||||
out_path++;
|
||||
size--;
|
||||
}
|
||||
@ -1206,8 +1109,6 @@ void fill_pathname_abbreviate_special(char *out_path,
|
||||
}
|
||||
}
|
||||
|
||||
free(application_dir);
|
||||
free(home_dir);
|
||||
#endif
|
||||
|
||||
retro_assert(strlcpy(out_path, in_path, size) < size);
|
||||
@ -1238,7 +1139,7 @@ void path_basedir_wrapper(char *path)
|
||||
if (last)
|
||||
last[1] = '\0';
|
||||
else
|
||||
snprintf(path, 3, ".%s", path_default_slash());
|
||||
snprintf(path, 3, "." PATH_DEFAULT_SLASH());
|
||||
}
|
||||
|
||||
#if !defined(RARCH_CONSOLE) && defined(RARCH_INTERNAL)
|
||||
@ -1365,29 +1266,27 @@ void fill_pathname_application_dir(char *s, size_t len)
|
||||
void fill_pathname_home_dir(char *s, size_t len)
|
||||
{
|
||||
#ifdef __WINRT__
|
||||
strlcpy(s, uwp_dir_data, len);
|
||||
const char *home = uwp_dir_data;
|
||||
#else
|
||||
const char *home = getenv("HOME");
|
||||
#endif
|
||||
if (home)
|
||||
strlcpy(s, home, len);
|
||||
else
|
||||
*s = 0;
|
||||
#endif
|
||||
}
|
||||
#endif
|
||||
|
||||
bool is_path_accessible_using_standard_io(const char *path)
|
||||
{
|
||||
#ifdef __WINRT__
|
||||
bool result;
|
||||
size_t path_sizeof = PATH_MAX_LENGTH * sizeof(char);
|
||||
char *relative_path_abbrev = (char*)malloc(path_sizeof);
|
||||
fill_pathname_abbreviate_special(relative_path_abbrev, path, path_sizeof);
|
||||
|
||||
result = strlen(relative_path_abbrev) >= 2 && (relative_path_abbrev[0] == ':' || relative_path_abbrev[0] == '~') && path_char_is_slash(relative_path_abbrev[1]);
|
||||
|
||||
free(relative_path_abbrev);
|
||||
return result;
|
||||
char relative_path_abbrev[PATH_MAX_LENGTH];
|
||||
fill_pathname_abbreviate_special(relative_path_abbrev,
|
||||
path, sizeof(relative_path_abbrev));
|
||||
return (strlen(relative_path_abbrev) >= 2 )
|
||||
&& ( relative_path_abbrev[0] == ':'
|
||||
|| relative_path_abbrev[0] == '~')
|
||||
&& PATH_CHAR_IS_SLASH(relative_path_abbrev[1]);
|
||||
#else
|
||||
return true;
|
||||
#endif
|
||||
|
@ -1,4 +1,4 @@
|
||||
/* Copyright (C) 2010-2019 The RetroArch team
|
||||
/* Copyright (C) 2010-2020 The RetroArch team
|
||||
*
|
||||
* ---------------------------------------------------------------------------------------
|
||||
* The following license statement only applies to this file (retro_dirent.c).
|
||||
@ -31,37 +31,41 @@
|
||||
#define VFS_FRONTEND
|
||||
#include <vfs/vfs_implementation.h>
|
||||
|
||||
static retro_vfs_opendir_t dirent_opendir_cb = NULL;
|
||||
static retro_vfs_readdir_t dirent_readdir_cb = NULL;
|
||||
/* TODO/FIXME - static globals */
|
||||
static retro_vfs_opendir_t dirent_opendir_cb = NULL;
|
||||
static retro_vfs_readdir_t dirent_readdir_cb = NULL;
|
||||
static retro_vfs_dirent_get_name_t dirent_dirent_get_name_cb = NULL;
|
||||
static retro_vfs_dirent_is_dir_t dirent_dirent_is_dir_cb = NULL;
|
||||
static retro_vfs_closedir_t dirent_closedir_cb = NULL;
|
||||
static retro_vfs_dirent_is_dir_t dirent_dirent_is_dir_cb = NULL;
|
||||
static retro_vfs_closedir_t dirent_closedir_cb = NULL;
|
||||
|
||||
void dirent_vfs_init(const struct retro_vfs_interface_info* vfs_info)
|
||||
{
|
||||
const struct retro_vfs_interface* vfs_iface;
|
||||
|
||||
dirent_opendir_cb = NULL;
|
||||
dirent_readdir_cb = NULL;
|
||||
dirent_opendir_cb = NULL;
|
||||
dirent_readdir_cb = NULL;
|
||||
dirent_dirent_get_name_cb = NULL;
|
||||
dirent_dirent_is_dir_cb = NULL;
|
||||
dirent_closedir_cb = NULL;
|
||||
dirent_dirent_is_dir_cb = NULL;
|
||||
dirent_closedir_cb = NULL;
|
||||
|
||||
vfs_iface = vfs_info->iface;
|
||||
vfs_iface = vfs_info->iface;
|
||||
|
||||
if (vfs_info->required_interface_version < DIRENT_REQUIRED_VFS_VERSION || !vfs_iface)
|
||||
if (
|
||||
vfs_info->required_interface_version < DIRENT_REQUIRED_VFS_VERSION ||
|
||||
!vfs_iface)
|
||||
return;
|
||||
|
||||
dirent_opendir_cb = vfs_iface->opendir;
|
||||
dirent_readdir_cb = vfs_iface->readdir;
|
||||
dirent_opendir_cb = vfs_iface->opendir;
|
||||
dirent_readdir_cb = vfs_iface->readdir;
|
||||
dirent_dirent_get_name_cb = vfs_iface->dirent_get_name;
|
||||
dirent_dirent_is_dir_cb = vfs_iface->dirent_is_dir;
|
||||
dirent_closedir_cb = vfs_iface->closedir;
|
||||
dirent_dirent_is_dir_cb = vfs_iface->dirent_is_dir;
|
||||
dirent_closedir_cb = vfs_iface->closedir;
|
||||
}
|
||||
|
||||
struct RDIR *retro_opendir_include_hidden(const char *name, bool include_hidden)
|
||||
struct RDIR *retro_opendir_include_hidden(
|
||||
const char *name, bool include_hidden)
|
||||
{
|
||||
if (dirent_opendir_cb != NULL)
|
||||
if (dirent_opendir_cb)
|
||||
return (struct RDIR *)dirent_opendir_cb(name, include_hidden);
|
||||
return (struct RDIR *)retro_vfs_opendir_impl(name, include_hidden);
|
||||
}
|
||||
@ -79,14 +83,14 @@ bool retro_dirent_error(struct RDIR *rdir)
|
||||
|
||||
int retro_readdir(struct RDIR *rdir)
|
||||
{
|
||||
if (dirent_readdir_cb != NULL)
|
||||
if (dirent_readdir_cb)
|
||||
return dirent_readdir_cb((struct retro_vfs_dir_handle *)rdir);
|
||||
return retro_vfs_readdir_impl((struct retro_vfs_dir_handle *)rdir);
|
||||
}
|
||||
|
||||
const char *retro_dirent_get_name(struct RDIR *rdir)
|
||||
{
|
||||
if (dirent_dirent_get_name_cb != NULL)
|
||||
if (dirent_dirent_get_name_cb)
|
||||
return dirent_dirent_get_name_cb((struct retro_vfs_dir_handle *)rdir);
|
||||
return retro_vfs_dirent_get_name_impl((struct retro_vfs_dir_handle *)rdir);
|
||||
}
|
||||
@ -104,14 +108,14 @@ const char *retro_dirent_get_name(struct RDIR *rdir)
|
||||
*/
|
||||
bool retro_dirent_is_dir(struct RDIR *rdir, const char *unused)
|
||||
{
|
||||
if (dirent_dirent_is_dir_cb != NULL)
|
||||
if (dirent_dirent_is_dir_cb)
|
||||
return dirent_dirent_is_dir_cb((struct retro_vfs_dir_handle *)rdir);
|
||||
return retro_vfs_dirent_is_dir_impl((struct retro_vfs_dir_handle *)rdir);
|
||||
}
|
||||
|
||||
void retro_closedir(struct RDIR *rdir)
|
||||
{
|
||||
if (dirent_closedir_cb != NULL)
|
||||
if (dirent_closedir_cb)
|
||||
dirent_closedir_cb((struct retro_vfs_dir_handle *)rdir);
|
||||
else
|
||||
retro_vfs_closedir_impl((struct retro_vfs_dir_handle *)rdir);
|
||||
|
@ -1,4 +1,4 @@
|
||||
/* Copyright (C) 2010-2018 The RetroArch team
|
||||
/* Copyright (C) 2010-2020 The RetroArch team
|
||||
*
|
||||
* ---------------------------------------------------------------------------------------
|
||||
* The following license statement only applies to this file (boolean.h).
|
||||
|
@ -1,4 +1,4 @@
|
||||
/* Copyright (C) 2010-2019 The RetroArch team
|
||||
/* Copyright (C) 2010-2020 The RetroArch team
|
||||
*
|
||||
* ---------------------------------------------------------------------------------------
|
||||
* The following license statement only applies to this file (cdrom.h).
|
||||
@ -62,10 +62,10 @@ typedef struct
|
||||
|
||||
typedef struct
|
||||
{
|
||||
char drive;
|
||||
cdrom_track_t track[99]; /* unsigned alignment */
|
||||
cdrom_group_timeouts_t timeouts; /* unsigned short alignment */
|
||||
unsigned char num_tracks;
|
||||
cdrom_group_timeouts_t timeouts;
|
||||
cdrom_track_t track[99];
|
||||
char drive;
|
||||
} cdrom_toc_t;
|
||||
|
||||
void cdrom_lba_to_msf(unsigned lba, unsigned char *min, unsigned char *sec, unsigned char *frame);
|
||||
|
@ -1,4 +1,4 @@
|
||||
/* Copyright (C) 2010-2018 The RetroArch team
|
||||
/* Copyright (C) 2010-2020 The RetroArch team
|
||||
*
|
||||
* ---------------------------------------------------------------------------------------
|
||||
* The following license statement only applies to this file (apple_compat.h).
|
||||
|
@ -1,4 +1,4 @@
|
||||
/* Copyright (C) 2010-2018 The RetroArch team
|
||||
/* Copyright (C) 2010-2020 The RetroArch team
|
||||
*
|
||||
* ---------------------------------------------------------------------------------------
|
||||
* The following license statement only applies to this file (fnmatch.h).
|
||||
|
@ -1,4 +1,4 @@
|
||||
/* Copyright (C) 2010-2018 The RetroArch team
|
||||
/* Copyright (C) 2010-2020 The RetroArch team
|
||||
*
|
||||
* ---------------------------------------------------------------------------------------
|
||||
* The following license statement only applies to this file (fopen_utf8.h).
|
||||
|
@ -1,4 +1,4 @@
|
||||
/* Copyright (C) 2010-2018 The RetroArch team
|
||||
/* Copyright (C) 2010-2020 The RetroArch team
|
||||
*
|
||||
* ---------------------------------------------------------------------------------------
|
||||
* The following license statement only applies to this file (getopt.h).
|
||||
|
@ -1,4 +1,4 @@
|
||||
/* Copyright (C) 2010-2018 The RetroArch team
|
||||
/* Copyright (C) 2010-2020 The RetroArch team
|
||||
*
|
||||
* ---------------------------------------------------------------------------------------
|
||||
* The following license statement only applies to this file (intrinsics.h).
|
||||
@ -41,7 +41,7 @@ RETRO_BEGIN_DECLS
|
||||
/* Count Leading Zero, unsigned 16bit input value */
|
||||
static INLINE unsigned compat_clz_u16(uint16_t val)
|
||||
{
|
||||
#if defined(__GNUC__) && !defined(PS2)
|
||||
#if defined(__GNUC__)
|
||||
return __builtin_clz(val << 16 | 0x8000);
|
||||
#else
|
||||
unsigned ret = 0;
|
||||
|
@ -1,4 +1,4 @@
|
||||
/* Copyright (C) 2010-2018 The RetroArch team
|
||||
/* Copyright (C) 2010-2020 The RetroArch team
|
||||
*
|
||||
* ---------------------------------------------------------------------------------------
|
||||
* The following license statement only applies to this file (msvc.h).
|
||||
@ -29,20 +29,17 @@
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/* Pre-MSVC 2015 compilers don't implement snprintf in a cross-platform manner. */
|
||||
/* Pre-MSVC 2015 compilers don't implement snprintf, vsnprintf in a cross-platform manner. */
|
||||
#if _MSC_VER < 1900
|
||||
#include <stdio.h>
|
||||
#include <stdarg.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
#ifndef snprintf
|
||||
#define snprintf c99_snprintf_retro__
|
||||
#endif
|
||||
|
||||
int c99_snprintf_retro__(char *outBuf, size_t size, const char *format, ...);
|
||||
#endif
|
||||
|
||||
/* Pre-MSVC 2008 compilers don't implement vsnprintf in a cross-platform manner? Not sure about this one. */
|
||||
#if _MSC_VER < 1500
|
||||
#include <stdarg.h>
|
||||
#include <stdlib.h>
|
||||
#ifndef vsnprintf
|
||||
#define vsnprintf c99_vsnprintf_retro__
|
||||
#endif
|
||||
|
@ -1,4 +1,4 @@
|
||||
/* Copyright (C) 2010-2018 The RetroArch team
|
||||
/* Copyright (C) 2010-2020 The RetroArch team
|
||||
*
|
||||
* ---------------------------------------------------------------------------------------
|
||||
* The following license statement only applies to this file (posix_string.h).
|
||||
@ -29,10 +29,6 @@
|
||||
#include <compat/msvc.h>
|
||||
#endif
|
||||
|
||||
#if defined(PS2)
|
||||
#include <compat_ctype.h>
|
||||
#endif
|
||||
|
||||
RETRO_BEGIN_DECLS
|
||||
|
||||
#ifdef _WIN32
|
||||
|
@ -1,4 +1,4 @@
|
||||
/* Copyright (C) 2010-2018 The RetroArch team
|
||||
/* Copyright (C) 2010-2020 The RetroArch team
|
||||
*
|
||||
* ---------------------------------------------------------------------------------------
|
||||
* The following license statement only applies to this file (strcasestr.h).
|
||||
@ -25,10 +25,6 @@
|
||||
|
||||
#include <string.h>
|
||||
|
||||
#if defined(PS2)
|
||||
#include <compat_ctype.h>
|
||||
#endif
|
||||
|
||||
#if defined(RARCH_INTERNAL) && defined(HAVE_CONFIG_H)
|
||||
#include "../../../config.h"
|
||||
#endif
|
||||
|
@ -1,4 +1,4 @@
|
||||
/* Copyright (C) 2010-2018 The RetroArch team
|
||||
/* Copyright (C) 2010-2020 The RetroArch team
|
||||
*
|
||||
* ---------------------------------------------------------------------------------------
|
||||
* The following license statement only applies to this file (strl.h).
|
||||
|
@ -1,4 +1,4 @@
|
||||
/* Copyright (C) 2010-2018 The RetroArch team
|
||||
/* Copyright (C) 2010-2020 The RetroArch team
|
||||
*
|
||||
* ---------------------------------------------------------------------------------------
|
||||
* The following license statement only applies to this file (crc32.h).
|
||||
|
@ -1,4 +1,4 @@
|
||||
/* Copyright (C) 2010-2018 The RetroArch team
|
||||
/* Copyright (C) 2010-2020 The RetroArch team
|
||||
*
|
||||
* ---------------------------------------------------------------------------------------
|
||||
* The following license statement only applies to this file (utf.h).
|
||||
@ -35,7 +35,7 @@ RETRO_BEGIN_DECLS
|
||||
enum CodePage
|
||||
{
|
||||
CODEPAGE_LOCAL = 0, /* CP_ACP */
|
||||
CODEPAGE_UTF8 = 65001 /* CP_UTF8 */
|
||||
CODEPAGE_UTF8 = 65001 /* CP_UTF8 */
|
||||
};
|
||||
|
||||
size_t utf8_conv_utf32(uint32_t *out, size_t out_chars,
|
||||
|
@ -1,4 +1,4 @@
|
||||
/* Copyright (C) 2010-2019 The RetroArch team
|
||||
/* Copyright (C) 2010-2020 The RetroArch team
|
||||
*
|
||||
* ---------------------------------------------------------------------------------------
|
||||
* The following license statement only applies to this file (file_path.h).
|
||||
@ -460,9 +460,9 @@ void path_basedir_wrapper(char *path);
|
||||
* Returns: true (1) if character is a slash, otherwise false (0).
|
||||
*/
|
||||
#ifdef _WIN32
|
||||
#define path_char_is_slash(c) (((c) == '/') || ((c) == '\\'))
|
||||
#define PATH_CHAR_IS_SLASH(c) (((c) == '/') || ((c) == '\\'))
|
||||
#else
|
||||
#define path_char_is_slash(c) ((c) == '/')
|
||||
#define PATH_CHAR_IS_SLASH(c) ((c) == '/')
|
||||
#endif
|
||||
|
||||
/**
|
||||
@ -473,11 +473,11 @@ void path_basedir_wrapper(char *path);
|
||||
* Returns: default slash separator.
|
||||
*/
|
||||
#ifdef _WIN32
|
||||
#define path_default_slash() "\\"
|
||||
#define path_default_slash_c() '\\'
|
||||
#define PATH_DEFAULT_SLASH() "\\"
|
||||
#define PATH_DEFAULT_SLASH_C() '\\'
|
||||
#else
|
||||
#define path_default_slash() "/"
|
||||
#define path_default_slash_c() '/'
|
||||
#define PATH_DEFAULT_SLASH() "/"
|
||||
#define PATH_DEFAULT_SLASH_C() '/'
|
||||
#endif
|
||||
|
||||
/**
|
||||
|
@ -1,4 +1,4 @@
|
||||
/* Copyright (C) 2010-2018 The RetroArch team
|
||||
/* Copyright (C) 2010-2020 The RetroArch team
|
||||
*
|
||||
* ---------------------------------------------------------------------------------------
|
||||
* The following license statement only applies to this libretro API header (libretro.h).
|
||||
@ -278,6 +278,10 @@ enum retro_language
|
||||
RETRO_LANGUAGE_ARABIC = 16,
|
||||
RETRO_LANGUAGE_GREEK = 17,
|
||||
RETRO_LANGUAGE_TURKISH = 18,
|
||||
RETRO_LANGUAGE_SLOVAK = 19,
|
||||
RETRO_LANGUAGE_PERSIAN = 20,
|
||||
RETRO_LANGUAGE_HEBREW = 21,
|
||||
RETRO_LANGUAGE_ASTURIAN = 22,
|
||||
RETRO_LANGUAGE_LAST,
|
||||
|
||||
/* Ensure sizeof(enum) == sizeof(int) */
|
||||
@ -1087,10 +1091,10 @@ enum retro_mod
|
||||
|
||||
#define RETRO_ENVIRONMENT_GET_TARGET_REFRESH_RATE (50 | RETRO_ENVIRONMENT_EXPERIMENTAL)
|
||||
/* float * --
|
||||
* Float value that lets us know what target refresh rate
|
||||
* Float value that lets us know what target refresh rate
|
||||
* is curently in use by the frontend.
|
||||
*
|
||||
* The core can use the returned value to set an ideal
|
||||
* The core can use the returned value to set an ideal
|
||||
* refresh rate/framerate.
|
||||
*/
|
||||
|
||||
@ -1098,7 +1102,7 @@ enum retro_mod
|
||||
/* bool * --
|
||||
* Boolean value that indicates whether or not the frontend supports
|
||||
* input bitmasks being returned by retro_input_state_t. The advantage
|
||||
* of this is that retro_input_state_t has to be only called once to
|
||||
* of this is that retro_input_state_t has to be only called once to
|
||||
* grab all button states instead of multiple times.
|
||||
*
|
||||
* If it returns true, you can pass RETRO_DEVICE_ID_JOYPAD_MASK as 'id'
|
||||
@ -1117,7 +1121,7 @@ enum retro_mod
|
||||
* This may be still be done regardless of the core options
|
||||
* interface version.
|
||||
*
|
||||
* If version is 1 however, core options may instead be set by
|
||||
* If version is >= 1 however, core options may instead be set by
|
||||
* passing an array of retro_core_option_definition structs to
|
||||
* RETRO_ENVIRONMENT_SET_CORE_OPTIONS, or a 2D array of
|
||||
* retro_core_option_definition structs to RETRO_ENVIRONMENT_SET_CORE_OPTIONS_INTL.
|
||||
@ -1132,8 +1136,8 @@ enum retro_mod
|
||||
* GET_VARIABLE.
|
||||
* This allows the frontend to present these variables to
|
||||
* a user dynamically.
|
||||
* This should only be called if RETRO_ENVIRONMENT_GET_ENHANCED_CORE_OPTIONS
|
||||
* returns an API version of 1.
|
||||
* This should only be called if RETRO_ENVIRONMENT_GET_CORE_OPTIONS_VERSION
|
||||
* returns an API version of >= 1.
|
||||
* This should be called instead of RETRO_ENVIRONMENT_SET_VARIABLES.
|
||||
* This should be called the first time as early as
|
||||
* possible (ideally in retro_set_environment).
|
||||
@ -1169,8 +1173,6 @@ enum retro_mod
|
||||
* i.e. it should be feasible to cycle through options
|
||||
* without a keyboard.
|
||||
*
|
||||
* First entry should be treated as a default.
|
||||
*
|
||||
* Example entry:
|
||||
* {
|
||||
* "foo_option",
|
||||
@ -1196,8 +1198,8 @@ enum retro_mod
|
||||
* GET_VARIABLE.
|
||||
* This allows the frontend to present these variables to
|
||||
* a user dynamically.
|
||||
* This should only be called if RETRO_ENVIRONMENT_GET_ENHANCED_CORE_OPTIONS
|
||||
* returns an API version of 1.
|
||||
* This should only be called if RETRO_ENVIRONMENT_GET_CORE_OPTIONS_VERSION
|
||||
* returns an API version of >= 1.
|
||||
* This should be called instead of RETRO_ENVIRONMENT_SET_VARIABLES.
|
||||
* This should be called the first time as early as
|
||||
* possible (ideally in retro_set_environment).
|
||||
@ -1257,7 +1259,82 @@ enum retro_mod
|
||||
*
|
||||
* 'data' points to an unsigned variable
|
||||
*/
|
||||
|
||||
|
||||
#define RETRO_ENVIRONMENT_GET_DISK_CONTROL_INTERFACE_VERSION 57
|
||||
/* unsigned * --
|
||||
* Unsigned value is the API version number of the disk control
|
||||
* interface supported by the frontend. If callback return false,
|
||||
* API version is assumed to be 0.
|
||||
*
|
||||
* In legacy code, the disk control interface is defined by passing
|
||||
* a struct of type retro_disk_control_callback to
|
||||
* RETRO_ENVIRONMENT_SET_DISK_CONTROL_INTERFACE.
|
||||
* This may be still be done regardless of the disk control
|
||||
* interface version.
|
||||
*
|
||||
* If version is >= 1 however, the disk control interface may
|
||||
* instead be defined by passing a struct of type
|
||||
* retro_disk_control_ext_callback to
|
||||
* RETRO_ENVIRONMENT_SET_DISK_CONTROL_EXT_INTERFACE.
|
||||
* This allows the core to provide additional information about
|
||||
* disk images to the frontend and/or enables extra
|
||||
* disk control functionality by the frontend.
|
||||
*/
|
||||
|
||||
#define RETRO_ENVIRONMENT_SET_DISK_CONTROL_EXT_INTERFACE 58
|
||||
/* const struct retro_disk_control_ext_callback * --
|
||||
* Sets an interface which frontend can use to eject and insert
|
||||
* disk images, and also obtain information about individual
|
||||
* disk image files registered by the core.
|
||||
* This is used for games which consist of multiple images and
|
||||
* must be manually swapped out by the user (e.g. PSX, floppy disk
|
||||
* based systems).
|
||||
*/
|
||||
|
||||
#define RETRO_ENVIRONMENT_GET_MESSAGE_INTERFACE_VERSION 59
|
||||
/* unsigned * --
|
||||
* Unsigned value is the API version number of the message
|
||||
* interface supported by the frontend. If callback returns
|
||||
* false, API version is assumed to be 0.
|
||||
*
|
||||
* In legacy code, messages may be displayed in an
|
||||
* implementation-specific manner by passing a struct
|
||||
* of type retro_message to RETRO_ENVIRONMENT_SET_MESSAGE.
|
||||
* This may be still be done regardless of the message
|
||||
* interface version.
|
||||
*
|
||||
* If version is >= 1 however, messages may instead be
|
||||
* displayed by passing a struct of type retro_message_ext
|
||||
* to RETRO_ENVIRONMENT_SET_MESSAGE_EXT. This allows the
|
||||
* core to specify message logging level, priority and
|
||||
* destination (OSD, logging interface or both).
|
||||
*/
|
||||
|
||||
#define RETRO_ENVIRONMENT_SET_MESSAGE_EXT 60
|
||||
/* const struct retro_message_ext * --
|
||||
* Sets a message to be displayed in an implementation-specific
|
||||
* manner for a certain amount of 'frames'. Additionally allows
|
||||
* the core to specify message logging level, priority and
|
||||
* destination (OSD, logging interface or both).
|
||||
* Should not be used for trivial messages, which should simply be
|
||||
* logged via RETRO_ENVIRONMENT_GET_LOG_INTERFACE (or as a
|
||||
* fallback, stderr).
|
||||
*/
|
||||
|
||||
#define RETRO_ENVIRONMENT_GET_INPUT_MAX_USERS 61
|
||||
/* unsigned * --
|
||||
* Unsigned value is the number of active input devices
|
||||
* provided by the frontend. This may change between
|
||||
* frames, but will remain constant for the duration
|
||||
* of each frame.
|
||||
* If callback returns true, a core need not poll any
|
||||
* input device with an index greater than or equal to
|
||||
* the number of active devices.
|
||||
* If callback returns false, the number of active input
|
||||
* devices is unknown. In this case, all input devices
|
||||
* should be considered active.
|
||||
*/
|
||||
|
||||
/* VFS functionality */
|
||||
|
||||
/* File paths:
|
||||
@ -2307,7 +2384,8 @@ struct retro_keyboard_callback
|
||||
retro_keyboard_event_t callback;
|
||||
};
|
||||
|
||||
/* Callbacks for RETRO_ENVIRONMENT_SET_DISK_CONTROL_INTERFACE.
|
||||
/* Callbacks for RETRO_ENVIRONMENT_SET_DISK_CONTROL_INTERFACE &
|
||||
* RETRO_ENVIRONMENT_SET_DISK_CONTROL_EXT_INTERFACE.
|
||||
* Should be set for implementations which can swap out multiple disk
|
||||
* images in runtime.
|
||||
*
|
||||
@ -2365,6 +2443,53 @@ typedef bool (RETRO_CALLCONV *retro_replace_image_index_t)(unsigned index,
|
||||
* with replace_image_index. */
|
||||
typedef bool (RETRO_CALLCONV *retro_add_image_index_t)(void);
|
||||
|
||||
/* Sets initial image to insert in drive when calling
|
||||
* core_load_game().
|
||||
* Since we cannot pass the initial index when loading
|
||||
* content (this would require a major API change), this
|
||||
* is set by the frontend *before* calling the core's
|
||||
* retro_load_game()/retro_load_game_special() implementation.
|
||||
* A core should therefore cache the index/path values and handle
|
||||
* them inside retro_load_game()/retro_load_game_special().
|
||||
* - If 'index' is invalid (index >= get_num_images()), the
|
||||
* core should ignore the set value and instead use 0
|
||||
* - 'path' is used purely for error checking - i.e. when
|
||||
* content is loaded, the core should verify that the
|
||||
* disk specified by 'index' has the specified file path.
|
||||
* This is to guard against auto selecting the wrong image
|
||||
* if (for example) the user should modify an existing M3U
|
||||
* playlist. We have to let the core handle this because
|
||||
* set_initial_image() must be called before loading content,
|
||||
* i.e. the frontend cannot access image paths in advance
|
||||
* and thus cannot perform the error check itself.
|
||||
* If set path and content path do not match, the core should
|
||||
* ignore the set 'index' value and instead use 0
|
||||
* Returns 'false' if index or 'path' are invalid, or core
|
||||
* does not support this functionality
|
||||
*/
|
||||
typedef bool (RETRO_CALLCONV *retro_set_initial_image_t)(unsigned index, const char *path);
|
||||
|
||||
/* Fetches the path of the specified disk image file.
|
||||
* Returns 'false' if index is invalid (index >= get_num_images())
|
||||
* or path is otherwise unavailable.
|
||||
*/
|
||||
typedef bool (RETRO_CALLCONV *retro_get_image_path_t)(unsigned index, char *path, size_t len);
|
||||
|
||||
/* Fetches a core-provided 'label' for the specified disk
|
||||
* image file. In the simplest case this may be a file name
|
||||
* (without extension), but for cores with more complex
|
||||
* content requirements information may be provided to
|
||||
* facilitate user disk swapping - for example, a core
|
||||
* running floppy-disk-based content may uniquely label
|
||||
* save disks, data disks, level disks, etc. with names
|
||||
* corresponding to in-game disk change prompts (so the
|
||||
* frontend can provide better user guidance than a 'dumb'
|
||||
* disk index value).
|
||||
* Returns 'false' if index is invalid (index >= get_num_images())
|
||||
* or label is otherwise unavailable.
|
||||
*/
|
||||
typedef bool (RETRO_CALLCONV *retro_get_image_label_t)(unsigned index, char *label, size_t len);
|
||||
|
||||
struct retro_disk_control_callback
|
||||
{
|
||||
retro_set_eject_state_t set_eject_state;
|
||||
@ -2378,6 +2503,27 @@ struct retro_disk_control_callback
|
||||
retro_add_image_index_t add_image_index;
|
||||
};
|
||||
|
||||
struct retro_disk_control_ext_callback
|
||||
{
|
||||
retro_set_eject_state_t set_eject_state;
|
||||
retro_get_eject_state_t get_eject_state;
|
||||
|
||||
retro_get_image_index_t get_image_index;
|
||||
retro_set_image_index_t set_image_index;
|
||||
retro_get_num_images_t get_num_images;
|
||||
|
||||
retro_replace_image_index_t replace_image_index;
|
||||
retro_add_image_index_t add_image_index;
|
||||
|
||||
/* NOTE: Frontend will only attempt to record/restore
|
||||
* last used disk index if both set_initial_image()
|
||||
* and get_image_path() are implemented */
|
||||
retro_set_initial_image_t set_initial_image; /* Optional - may be NULL */
|
||||
|
||||
retro_get_image_path_t get_image_path; /* Optional - may be NULL */
|
||||
retro_get_image_label_t get_image_label; /* Optional - may be NULL */
|
||||
};
|
||||
|
||||
enum retro_pixel_format
|
||||
{
|
||||
/* 0RGB1555, native endian.
|
||||
@ -2408,6 +2554,104 @@ struct retro_message
|
||||
unsigned frames; /* Duration in frames of message. */
|
||||
};
|
||||
|
||||
enum retro_message_target
|
||||
{
|
||||
RETRO_MESSAGE_TARGET_ALL = 0,
|
||||
RETRO_MESSAGE_TARGET_OSD,
|
||||
RETRO_MESSAGE_TARGET_LOG
|
||||
};
|
||||
|
||||
enum retro_message_type
|
||||
{
|
||||
RETRO_MESSAGE_TYPE_NOTIFICATION = 0,
|
||||
RETRO_MESSAGE_TYPE_NOTIFICATION_ALT,
|
||||
RETRO_MESSAGE_TYPE_STATUS,
|
||||
RETRO_MESSAGE_TYPE_PROGRESS
|
||||
};
|
||||
|
||||
struct retro_message_ext
|
||||
{
|
||||
/* Message string to be displayed/logged */
|
||||
const char *msg;
|
||||
/* Duration (in ms) of message when targeting the OSD */
|
||||
unsigned duration;
|
||||
/* Message priority when targeting the OSD
|
||||
* > When multiple concurrent messages are sent to
|
||||
* the frontend and the frontend does not have the
|
||||
* capacity to display them all, messages with the
|
||||
* *highest* priority value should be shown
|
||||
* > There is no upper limit to a message priority
|
||||
* value (within the bounds of the unsigned data type)
|
||||
* > In the reference frontend (RetroArch), the same
|
||||
* priority values are used for frontend-generated
|
||||
* notifications, which are typically assigned values
|
||||
* between 0 and 3 depending upon importance */
|
||||
unsigned priority;
|
||||
/* Message logging level (info, warn, error, etc.) */
|
||||
enum retro_log_level level;
|
||||
/* Message destination: OSD, logging interface or both */
|
||||
enum retro_message_target target;
|
||||
/* Message 'type' when targeting the OSD
|
||||
* > RETRO_MESSAGE_TYPE_NOTIFICATION: Specifies that a
|
||||
* message should be handled in identical fashion to
|
||||
* a standard frontend-generated notification
|
||||
* > RETRO_MESSAGE_TYPE_NOTIFICATION_ALT: Specifies that
|
||||
* message is a notification that requires user attention
|
||||
* or action, but that it should be displayed in a manner
|
||||
* that differs from standard frontend-generated notifications.
|
||||
* This would typically correspond to messages that should be
|
||||
* displayed immediately (independently from any internal
|
||||
* frontend message queue), and/or which should be visually
|
||||
* distinguishable from frontend-generated notifications.
|
||||
* For example, a core may wish to inform the user of
|
||||
* information related to a disk-change event. It is
|
||||
* expected that the frontend itself may provide a
|
||||
* notification in this case; if the core sends a
|
||||
* message of type RETRO_MESSAGE_TYPE_NOTIFICATION, an
|
||||
* uncomfortable 'double-notification' may occur. A message
|
||||
* of RETRO_MESSAGE_TYPE_NOTIFICATION_ALT should therefore
|
||||
* be presented such that visual conflict with regular
|
||||
* notifications does not occur
|
||||
* > RETRO_MESSAGE_TYPE_STATUS: Indicates that message
|
||||
* is not a standard notification. This typically
|
||||
* corresponds to 'status' indicators, such as a core's
|
||||
* internal FPS, which are intended to be displayed
|
||||
* either permanently while a core is running, or in
|
||||
* a manner that does not suggest user attention or action
|
||||
* is required. 'Status' type messages should therefore be
|
||||
* displayed in a different on-screen location and in a manner
|
||||
* easily distinguishable from both standard frontend-generated
|
||||
* notifications and messages of type RETRO_MESSAGE_TYPE_NOTIFICATION_ALT
|
||||
* > RETRO_MESSAGE_TYPE_PROGRESS: Indicates that message reports
|
||||
* the progress of an internal core task. For example, in cases
|
||||
* where a core itself handles the loading of content from a file,
|
||||
* this may correspond to the percentage of the file that has been
|
||||
* read. Alternatively, an audio/video playback core may use a
|
||||
* message of type RETRO_MESSAGE_TYPE_PROGRESS to display the current
|
||||
* playback position as a percentage of the runtime. 'Progress' type
|
||||
* messages should therefore be displayed as a literal progress bar,
|
||||
* where:
|
||||
* - 'retro_message_ext.msg' is the progress bar title/label
|
||||
* - 'retro_message_ext.progress' determines the length of
|
||||
* the progress bar
|
||||
* NOTE: Message type is a *hint*, and may be ignored
|
||||
* by the frontend. If a frontend lacks support for
|
||||
* displaying messages via alternate means than standard
|
||||
* frontend-generated notifications, it will treat *all*
|
||||
* messages as having the type RETRO_MESSAGE_TYPE_NOTIFICATION */
|
||||
enum retro_message_type type;
|
||||
/* Task progress when targeting the OSD and message is
|
||||
* of type RETRO_MESSAGE_TYPE_PROGRESS
|
||||
* > -1: Unmetered/indeterminate
|
||||
* > 0-100: Current progress percentage
|
||||
* NOTE: Since message type is a hint, a frontend may ignore
|
||||
* progress values. Where relevant, a core should therefore
|
||||
* include progress percentage within the message string,
|
||||
* such that the message intent remains clear when displayed
|
||||
* as a standard frontend-generated notification */
|
||||
int8_t progress;
|
||||
};
|
||||
|
||||
/* Describes how the libretro implementation maps a libretro input bind
|
||||
* to its internal input system through a human readable string.
|
||||
* This string can be used to better let a user configure input. */
|
||||
@ -2428,7 +2672,7 @@ struct retro_input_descriptor
|
||||
struct retro_system_info
|
||||
{
|
||||
/* All pointers are owned by libretro implementation, and pointers must
|
||||
* remain valid until retro_deinit() is called. */
|
||||
* remain valid until it is unloaded. */
|
||||
|
||||
const char *library_name; /* Descriptive name of library. Should not
|
||||
* contain any version numbers, etc. */
|
||||
@ -2522,8 +2766,20 @@ struct retro_core_option_display
|
||||
};
|
||||
|
||||
/* Maximum number of values permitted for a core option
|
||||
* NOTE: This may be increased on a core-by-core basis
|
||||
* if required (doing so has no effect on the frontend) */
|
||||
* > Note: We have to set a maximum value due the limitations
|
||||
* of the C language - i.e. it is not possible to create an
|
||||
* array of structs each containing a variable sized array,
|
||||
* so the retro_core_option_definition values array must
|
||||
* have a fixed size. The size limit of 128 is a balancing
|
||||
* act - it needs to be large enough to support all 'sane'
|
||||
* core options, but setting it too large may impact low memory
|
||||
* platforms. In practise, if a core option has more than
|
||||
* 128 values then the implementation is likely flawed.
|
||||
* To quote the above API reference:
|
||||
* "The number of possible options should be very limited
|
||||
* i.e. it should be feasible to cycle through options
|
||||
* without a keyboard."
|
||||
*/
|
||||
#define RETRO_NUM_CORE_OPTION_VALUES_MAX 128
|
||||
|
||||
struct retro_core_option_value
|
||||
|
@ -1,4 +1,4 @@
|
||||
/* Copyright (C) 2010-2018 The RetroArch team
|
||||
/* Copyright (C) 2010-2020 The RetroArch team
|
||||
*
|
||||
* ---------------------------------------------------------------------------------------
|
||||
* The following license statement only applies to this file (dir_list.h).
|
||||
@ -24,6 +24,7 @@
|
||||
#define __LIBRETRO_SDK_DIR_LIST_H
|
||||
|
||||
#include <retro_common_api.h>
|
||||
#include <boolean.h>
|
||||
|
||||
#include <lists/string_list.h>
|
||||
|
||||
@ -63,6 +64,15 @@ bool dir_list_append(struct string_list *list, const char *dir, const char *ext,
|
||||
struct string_list *dir_list_new(const char *dir, const char *ext,
|
||||
bool include_dirs, bool include_hidden, bool include_compressed, bool recursive);
|
||||
|
||||
/* Warning: 'list' must zero initialised before
|
||||
* calling this function, otherwise memory leaks/
|
||||
* undefined behaviour will occur */
|
||||
bool dir_list_initialize(struct string_list *list,
|
||||
const char *dir,
|
||||
const char *ext, bool include_dirs,
|
||||
bool include_hidden, bool include_compressed,
|
||||
bool recursive);
|
||||
|
||||
/**
|
||||
* dir_list_sort:
|
||||
* @list : pointer to the directory listing.
|
||||
@ -82,6 +92,8 @@ void dir_list_sort(struct string_list *list, bool dir_first);
|
||||
**/
|
||||
void dir_list_free(struct string_list *list);
|
||||
|
||||
bool dir_list_deinitialize(struct string_list *list);
|
||||
|
||||
RETRO_END_DECLS
|
||||
|
||||
#endif
|
||||
|
@ -1,4 +1,4 @@
|
||||
/* Copyright (C) 2010-2018 The RetroArch team
|
||||
/* Copyright (C) 2010-2020 The RetroArch team
|
||||
*
|
||||
* ---------------------------------------------------------------------------------------
|
||||
* The following license statement only applies to this file (string_list.h).
|
||||
@ -88,6 +88,9 @@ bool string_list_find_elem_prefix(const struct string_list *list,
|
||||
*/
|
||||
struct string_list *string_split(const char *str, const char *delim);
|
||||
|
||||
bool string_split_noalloc(struct string_list *list,
|
||||
const char *str, const char *delim);
|
||||
|
||||
/**
|
||||
* string_separate:
|
||||
* @str : string to turn into a string list
|
||||
@ -101,6 +104,13 @@ struct string_list *string_split(const char *str, const char *delim);
|
||||
*/
|
||||
struct string_list *string_separate(char *str, const char *delim);
|
||||
|
||||
bool string_separate_noalloc(struct string_list *list,
|
||||
char *str, const char *delim);
|
||||
|
||||
bool string_list_deinitialize(struct string_list *list);
|
||||
|
||||
bool string_list_initialize(struct string_list *list);
|
||||
|
||||
/**
|
||||
* string_list_new:
|
||||
*
|
||||
|
@ -1,4 +1,4 @@
|
||||
/* Copyright (C) 2010-2018 The RetroArch team
|
||||
/* Copyright (C) 2010-2020 The RetroArch team
|
||||
*
|
||||
* ---------------------------------------------------------------------------------------
|
||||
* The following license statement only applies to this file (memalign.h).
|
||||
|
@ -1,4 +1,4 @@
|
||||
/* Copyright (C) 2010-2018 The RetroArch team
|
||||
/* Copyright (C) 2010-2020 The RetroArch team
|
||||
*
|
||||
* ---------------------------------------------------------------------------------------
|
||||
* The following license statement only applies to this file (memmap.h).
|
||||
|
@ -1,4 +1,4 @@
|
||||
/* Copyright (C) 2010-2018 The RetroArch team
|
||||
/* Copyright (C) 2010-2020 The RetroArch team
|
||||
*
|
||||
* ---------------------------------------------------------------------------------------
|
||||
* The following license statement only applies to this file (retro_assert.h).
|
||||
|
@ -1,4 +1,4 @@
|
||||
/* Copyright (C) 2010-2018 The RetroArch team
|
||||
/* Copyright (C) 2010-2020 The RetroArch team
|
||||
*
|
||||
* ---------------------------------------------------------------------------------------
|
||||
* The following license statement only applies to this file (retro_common.h).
|
||||
|
@ -1,4 +1,4 @@
|
||||
/* Copyright (C) 2010-2018 The RetroArch team
|
||||
/* Copyright (C) 2010-2020 The RetroArch team
|
||||
*
|
||||
* ---------------------------------------------------------------------------------------
|
||||
* The following license statement only applies to this file (retro_common_api.h).
|
||||
|
@ -1,4 +1,4 @@
|
||||
/* Copyright (C) 2010-2019 The RetroArch team
|
||||
/* Copyright (C) 2010-2020 The RetroArch team
|
||||
*
|
||||
* ---------------------------------------------------------------------------------------
|
||||
* The following license statement only applies to this file (retro_dirent.h).
|
||||
|
@ -1,4 +1,4 @@
|
||||
/* Copyright (C) 2010-2018 The RetroArch team
|
||||
/* Copyright (C) 2010-2020 The RetroArch team
|
||||
*
|
||||
* ---------------------------------------------------------------------------------------
|
||||
* The following license statement only applies to this file (retro_endianness.h).
|
||||
@ -31,40 +31,100 @@
|
||||
#define SWAP16 _byteswap_ushort
|
||||
#define SWAP32 _byteswap_ulong
|
||||
#else
|
||||
#define SWAP16(x) ((uint16_t)( \
|
||||
(((uint16_t)(x) & 0x00ff) << 8) | \
|
||||
(((uint16_t)(x) & 0xff00) >> 8) \
|
||||
))
|
||||
#define SWAP32(x) ((uint32_t)( \
|
||||
(((uint32_t)(x) & 0x000000ff) << 24) | \
|
||||
(((uint32_t)(x) & 0x0000ff00) << 8) | \
|
||||
(((uint32_t)(x) & 0x00ff0000) >> 8) | \
|
||||
(((uint32_t)(x) & 0xff000000) >> 24) \
|
||||
))
|
||||
static INLINE uint16_t SWAP16(uint16_t x)
|
||||
{
|
||||
return ((x & 0x00ff) << 8) |
|
||||
((x & 0xff00) >> 8);
|
||||
}
|
||||
|
||||
static INLINE uint32_t SWAP32(uint32_t x)
|
||||
{
|
||||
return ((x & 0x000000ff) << 24) |
|
||||
((x & 0x0000ff00) << 8) |
|
||||
((x & 0x00ff0000) >> 8) |
|
||||
((x & 0xff000000) >> 24);
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
#if defined(_MSC_VER) && _MSC_VER <= 1200
|
||||
#define SWAP64(val) \
|
||||
((((uint64_t)(val) & 0x00000000000000ff) << 56) \
|
||||
| (((uint64_t)(val) & 0x000000000000ff00) << 40) \
|
||||
| (((uint64_t)(val) & 0x0000000000ff0000) << 24) \
|
||||
| (((uint64_t)(val) & 0x00000000ff000000) << 8) \
|
||||
| (((uint64_t)(val) & 0x000000ff00000000) >> 8) \
|
||||
| (((uint64_t)(val) & 0x0000ff0000000000) >> 24) \
|
||||
| (((uint64_t)(val) & 0x00ff000000000000) >> 40) \
|
||||
| (((uint64_t)(val) & 0xff00000000000000) >> 56))
|
||||
static INLINE uint64_t SWAP64(uint64_t val)
|
||||
{
|
||||
return
|
||||
((val & 0x00000000000000ff) << 56)
|
||||
| ((val & 0x000000000000ff00) << 40)
|
||||
| ((val & 0x0000000000ff0000) << 24)
|
||||
| ((val & 0x00000000ff000000) << 8)
|
||||
| ((val & 0x000000ff00000000) >> 8)
|
||||
| ((val & 0x0000ff0000000000) >> 24)
|
||||
| ((val & 0x00ff000000000000) >> 40)
|
||||
| ((val & 0xff00000000000000) >> 56);
|
||||
}
|
||||
#else
|
||||
#define SWAP64(val) \
|
||||
((((uint64_t)(val) & 0x00000000000000ffULL) << 56) \
|
||||
| (((uint64_t)(val) & 0x000000000000ff00ULL) << 40) \
|
||||
| (((uint64_t)(val) & 0x0000000000ff0000ULL) << 24) \
|
||||
| (((uint64_t)(val) & 0x00000000ff000000ULL) << 8) \
|
||||
| (((uint64_t)(val) & 0x000000ff00000000ULL) >> 8) \
|
||||
| (((uint64_t)(val) & 0x0000ff0000000000ULL) >> 24) \
|
||||
| (((uint64_t)(val) & 0x00ff000000000000ULL) >> 40) \
|
||||
| (((uint64_t)(val) & 0xff00000000000000ULL) >> 56))
|
||||
static INLINE uint64_t SWAP64(uint64_t val)
|
||||
{
|
||||
return ((val & 0x00000000000000ffULL) << 56)
|
||||
| ((val & 0x000000000000ff00ULL) << 40)
|
||||
| ((val & 0x0000000000ff0000ULL) << 24)
|
||||
| ((val & 0x00000000ff000000ULL) << 8)
|
||||
| ((val & 0x000000ff00000000ULL) >> 8)
|
||||
| ((val & 0x0000ff0000000000ULL) >> 24)
|
||||
| ((val & 0x00ff000000000000ULL) >> 40)
|
||||
| ((val & 0xff00000000000000ULL) >> 56);
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
#if defined (LSB_FIRST) || defined (MSB_FIRST)
|
||||
# warning Defining MSB_FIRST and LSB_FIRST in compile options is deprecated
|
||||
# undef LSB_FIRST
|
||||
# undef MSB_FIRST
|
||||
#endif
|
||||
|
||||
#if defined(_MSC_VER) && !defined(_XBOX)
|
||||
#include <winsock2.h>
|
||||
#endif
|
||||
|
||||
#ifdef _MSC_VER
|
||||
#if _M_IX86 || _M_AMD64 || _M_ARM || _M_ARM64
|
||||
#define LSB_FIRST 1
|
||||
#elif _M_PPC
|
||||
#define MSB_FIRST 1
|
||||
#else
|
||||
/* MSVC can run on _M_ALPHA and _M_IA64 too, but they're both bi-endian; need to find what mode MSVC runs them at */
|
||||
#error "unknown platform, can't determine endianness"
|
||||
#endif
|
||||
#else
|
||||
#if __BYTE_ORDER__ == __ORDER_BIG_ENDIAN__
|
||||
#define MSB_FIRST 1
|
||||
#elif __BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__
|
||||
#define LSB_FIRST 1
|
||||
#else
|
||||
#error "Invalid endianness macros"
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#if defined(MSB_FIRST) && defined(LSB_FIRST)
|
||||
# error "Bug in LSB_FIRST/MSB_FIRST definition"
|
||||
#endif
|
||||
|
||||
#if !defined(MSB_FIRST) && !defined(LSB_FIRST)
|
||||
# error "Bug in LSB_FIRST/MSB_FIRST definition"
|
||||
#endif
|
||||
|
||||
#ifdef MSB_FIRST
|
||||
# define RETRO_IS_BIG_ENDIAN 1
|
||||
# define RETRO_IS_LITTLE_ENDIAN 0
|
||||
/* For compatibility */
|
||||
# define WORDS_BIGENDIAN 1
|
||||
#else
|
||||
# define RETRO_IS_BIG_ENDIAN 0
|
||||
# define RETRO_IS_LITTLE_ENDIAN 1
|
||||
/* For compatibility */
|
||||
# undef WORDS_BIGENDIAN
|
||||
#endif
|
||||
|
||||
|
||||
/**
|
||||
* is_little_endian:
|
||||
*
|
||||
@ -73,23 +133,7 @@
|
||||
* Returns: greater than 0 if little-endian,
|
||||
* otherwise big-endian.
|
||||
**/
|
||||
#if defined(MSB_FIRST)
|
||||
#define is_little_endian() (0)
|
||||
#elif defined(__x86_64) || defined(__i386) || defined(_M_IX86) || defined(_M_X64)
|
||||
#define is_little_endian() (1)
|
||||
#else
|
||||
static INLINE uint8_t is_little_endian(void)
|
||||
{
|
||||
union
|
||||
{
|
||||
uint16_t x;
|
||||
uint8_t y[2];
|
||||
} u;
|
||||
|
||||
u.x = 1;
|
||||
return u.y[0];
|
||||
}
|
||||
#endif
|
||||
#define is_little_endian() RETRO_IS_LITTLE_ENDIAN
|
||||
|
||||
/**
|
||||
* swap_if_big64:
|
||||
@ -101,17 +145,10 @@ static INLINE uint8_t is_little_endian(void)
|
||||
* otherwise returns same value.
|
||||
**/
|
||||
|
||||
#if defined(MSB_FIRST)
|
||||
#if RETRO_IS_BIG_ENDIAN
|
||||
#define swap_if_big64(val) (SWAP64(val))
|
||||
#elif defined(__x86_64) || defined(__i386) || defined(_M_IX86) || defined(_M_X64)
|
||||
#elif RETRO_IS_LITTLE_ENDIAN
|
||||
#define swap_if_big64(val) (val)
|
||||
#else
|
||||
static INLINE uint64_t swap_if_big64(uint64_t val)
|
||||
{
|
||||
if (is_little_endian())
|
||||
return val;
|
||||
return SWAP64(val);
|
||||
}
|
||||
#endif
|
||||
|
||||
/**
|
||||
@ -124,17 +161,10 @@ static INLINE uint64_t swap_if_big64(uint64_t val)
|
||||
* otherwise returns same value.
|
||||
**/
|
||||
|
||||
#if defined(MSB_FIRST)
|
||||
#if RETRO_IS_BIG_ENDIAN
|
||||
#define swap_if_big32(val) (SWAP32(val))
|
||||
#elif defined(__x86_64) || defined(__i386) || defined(_M_IX86) || defined(_M_X64)
|
||||
#elif RETRO_IS_LITTLE_ENDIAN
|
||||
#define swap_if_big32(val) (val)
|
||||
#else
|
||||
static INLINE uint32_t swap_if_big32(uint32_t val)
|
||||
{
|
||||
if (is_little_endian())
|
||||
return val;
|
||||
return SWAP32(val);
|
||||
}
|
||||
#endif
|
||||
|
||||
/**
|
||||
@ -147,17 +177,10 @@ static INLINE uint32_t swap_if_big32(uint32_t val)
|
||||
* otherwise returns same value.
|
||||
**/
|
||||
|
||||
#if defined(MSB_FIRST)
|
||||
#if RETRO_IS_BIG_ENDIAN
|
||||
#define swap_if_little64(val) (val)
|
||||
#elif defined(__x86_64) || defined(__i386) || defined(_M_IX86) || defined(_M_X64)
|
||||
#elif RETRO_IS_LITTLE_ENDIAN
|
||||
#define swap_if_little64(val) (SWAP64(val))
|
||||
#else
|
||||
static INLINE uint64_t swap_if_little64(uint64_t val)
|
||||
{
|
||||
if (is_little_endian())
|
||||
return SWAP64(val);
|
||||
return val;
|
||||
}
|
||||
#endif
|
||||
|
||||
/**
|
||||
@ -170,17 +193,10 @@ static INLINE uint64_t swap_if_little64(uint64_t val)
|
||||
* otherwise returns same value.
|
||||
**/
|
||||
|
||||
#if defined(MSB_FIRST)
|
||||
#if RETRO_IS_BIG_ENDIAN
|
||||
#define swap_if_little32(val) (val)
|
||||
#elif defined(__x86_64) || defined(__i386) || defined(_M_IX86) || defined(_M_X64)
|
||||
#elif RETRO_IS_LITTLE_ENDIAN
|
||||
#define swap_if_little32(val) (SWAP32(val))
|
||||
#else
|
||||
static INLINE uint32_t swap_if_little32(uint32_t val)
|
||||
{
|
||||
if (is_little_endian())
|
||||
return SWAP32(val);
|
||||
return val;
|
||||
}
|
||||
#endif
|
||||
|
||||
/**
|
||||
@ -193,17 +209,10 @@ static INLINE uint32_t swap_if_little32(uint32_t val)
|
||||
* otherwise returns same value.
|
||||
**/
|
||||
|
||||
#if defined(MSB_FIRST)
|
||||
#if RETRO_IS_BIG_ENDIAN
|
||||
#define swap_if_big16(val) (SWAP16(val))
|
||||
#elif defined(__x86_64) || defined(__i386) || defined(_M_IX86) || defined(_M_X64)
|
||||
#elif RETRO_IS_LITTLE_ENDIAN
|
||||
#define swap_if_big16(val) (val)
|
||||
#else
|
||||
static INLINE uint16_t swap_if_big16(uint16_t val)
|
||||
{
|
||||
if (is_little_endian())
|
||||
return val;
|
||||
return SWAP16(val);
|
||||
}
|
||||
#endif
|
||||
|
||||
/**
|
||||
@ -216,17 +225,10 @@ static INLINE uint16_t swap_if_big16(uint16_t val)
|
||||
* otherwise returns same value.
|
||||
**/
|
||||
|
||||
#if defined(MSB_FIRST)
|
||||
#if RETRO_IS_BIG_ENDIAN
|
||||
#define swap_if_little16(val) (val)
|
||||
#elif defined(__x86_64) || defined(__i386) || defined(_M_IX86) || defined(_M_X64)
|
||||
#elif RETRO_IS_LITTLE_ENDIAN
|
||||
#define swap_if_little16(val) (SWAP16(val))
|
||||
#else
|
||||
static INLINE uint16_t swap_if_little16(uint16_t val)
|
||||
{
|
||||
if (is_little_endian())
|
||||
return SWAP16(val);
|
||||
return val;
|
||||
}
|
||||
#endif
|
||||
|
||||
/**
|
||||
@ -255,4 +257,326 @@ static INLINE uint32_t load32be(const uint32_t *addr)
|
||||
return swap_if_little32(*addr);
|
||||
}
|
||||
|
||||
/**
|
||||
* retro_cpu_to_le16:
|
||||
* @val : unsigned 16-bit value
|
||||
*
|
||||
* Convert unsigned 16-bit value from system to little-endian.
|
||||
*
|
||||
* Returns: Little-endian representation of val.
|
||||
**/
|
||||
|
||||
#define retro_cpu_to_le16(val) swap_if_big16(val)
|
||||
|
||||
/**
|
||||
* retro_cpu_to_le32:
|
||||
* @val : unsigned 32-bit value
|
||||
*
|
||||
* Convert unsigned 32-bit value from system to little-endian.
|
||||
*
|
||||
* Returns: Little-endian representation of val.
|
||||
**/
|
||||
|
||||
#define retro_cpu_to_le32(val) swap_if_big32(val)
|
||||
|
||||
/**
|
||||
* retro_cpu_to_le64:
|
||||
* @val : unsigned 64-bit value
|
||||
*
|
||||
* Convert unsigned 64-bit value from system to little-endian.
|
||||
*
|
||||
* Returns: Little-endian representation of val.
|
||||
**/
|
||||
|
||||
#define retro_cpu_to_le64(val) swap_if_big64(val)
|
||||
|
||||
/**
|
||||
* retro_le_to_cpu16:
|
||||
* @val : unsigned 16-bit value
|
||||
*
|
||||
* Convert unsigned 16-bit value from little-endian to native.
|
||||
*
|
||||
* Returns: Native representation of little-endian val.
|
||||
**/
|
||||
|
||||
#define retro_le_to_cpu16(val) swap_if_big16(val)
|
||||
|
||||
/**
|
||||
* retro_le_to_cpu32:
|
||||
* @val : unsigned 32-bit value
|
||||
*
|
||||
* Convert unsigned 32-bit value from little-endian to native.
|
||||
*
|
||||
* Returns: Native representation of little-endian val.
|
||||
**/
|
||||
|
||||
#define retro_le_to_cpu32(val) swap_if_big32(val)
|
||||
|
||||
/**
|
||||
* retro_le_to_cpu16:
|
||||
* @val : unsigned 64-bit value
|
||||
*
|
||||
* Convert unsigned 64-bit value from little-endian to native.
|
||||
*
|
||||
* Returns: Native representation of little-endian val.
|
||||
**/
|
||||
|
||||
#define retro_le_to_cpu64(val) swap_if_big64(val)
|
||||
|
||||
/**
|
||||
* retro_cpu_to_be16:
|
||||
* @val : unsigned 16-bit value
|
||||
*
|
||||
* Convert unsigned 16-bit value from system to big-endian.
|
||||
*
|
||||
* Returns: Big-endian representation of val.
|
||||
**/
|
||||
|
||||
#define retro_cpu_to_be16(val) swap_if_little16(val)
|
||||
|
||||
/**
|
||||
* retro_cpu_to_be32:
|
||||
* @val : unsigned 32-bit value
|
||||
*
|
||||
* Convert unsigned 32-bit value from system to big-endian.
|
||||
*
|
||||
* Returns: Big-endian representation of val.
|
||||
**/
|
||||
|
||||
#define retro_cpu_to_be32(val) swap_if_little32(val)
|
||||
|
||||
/**
|
||||
* retro_cpu_to_be64:
|
||||
* @val : unsigned 64-bit value
|
||||
*
|
||||
* Convert unsigned 64-bit value from system to big-endian.
|
||||
*
|
||||
* Returns: Big-endian representation of val.
|
||||
**/
|
||||
|
||||
#define retro_cpu_to_be64(val) swap_if_little64(val)
|
||||
|
||||
/**
|
||||
* retro_be_to_cpu16:
|
||||
* @val : unsigned 16-bit value
|
||||
*
|
||||
* Convert unsigned 16-bit value from big-endian to native.
|
||||
*
|
||||
* Returns: Native representation of big-endian val.
|
||||
**/
|
||||
|
||||
#define retro_be_to_cpu16(val) swap_if_little16(val)
|
||||
|
||||
/**
|
||||
* retro_be_to_cpu32:
|
||||
* @val : unsigned 32-bit value
|
||||
*
|
||||
* Convert unsigned 32-bit value from big-endian to native.
|
||||
*
|
||||
* Returns: Native representation of big-endian val.
|
||||
**/
|
||||
|
||||
#define retro_be_to_cpu32(val) swap_if_little32(val)
|
||||
|
||||
/**
|
||||
* retro_be_to_cpu64:
|
||||
* @val : unsigned 64-bit value
|
||||
*
|
||||
* Convert unsigned 64-bit value from big-endian to native.
|
||||
*
|
||||
* Returns: Native representation of big-endian val.
|
||||
**/
|
||||
|
||||
#define retro_be_to_cpu64(val) swap_if_little64(val)
|
||||
|
||||
#ifdef __GNUC__
|
||||
/* This attribute means that the same memory may be referred through
|
||||
pointers to different size of the object (aliasing). E.g. that u8 *
|
||||
and u32 * may actually be pointing to the same object. */
|
||||
#define MAY_ALIAS __attribute__((__may_alias__))
|
||||
#else
|
||||
#define MAY_ALIAS
|
||||
#endif
|
||||
|
||||
#pragma pack(push, 1)
|
||||
struct retro_unaligned_uint16_s
|
||||
{
|
||||
uint16_t val;
|
||||
} MAY_ALIAS;
|
||||
struct retro_unaligned_uint32_s
|
||||
{
|
||||
uint32_t val;
|
||||
} MAY_ALIAS;
|
||||
struct retro_unaligned_uint64_s
|
||||
{
|
||||
uint64_t val;
|
||||
} MAY_ALIAS;
|
||||
#pragma pack(pop)
|
||||
|
||||
typedef struct retro_unaligned_uint16_s retro_unaligned_uint16_t;
|
||||
typedef struct retro_unaligned_uint32_s retro_unaligned_uint32_t;
|
||||
typedef struct retro_unaligned_uint64_s retro_unaligned_uint64_t;
|
||||
|
||||
/* L-value references to unaligned pointers. */
|
||||
#define retro_unaligned16(p) (((retro_unaligned_uint16_t *)p)->val)
|
||||
#define retro_unaligned32(p) (((retro_unaligned_uint32_t *)p)->val)
|
||||
#define retro_unaligned64(p) (((retro_unaligned_uint64_t *)p)->val)
|
||||
|
||||
/**
|
||||
* retro_get_unaligned_16be:
|
||||
* @addr : pointer to unsigned 16-bit value
|
||||
*
|
||||
* Convert unsigned unaligned 16-bit value from big-endian to native.
|
||||
*
|
||||
* Returns: Native representation of big-endian val.
|
||||
**/
|
||||
|
||||
static INLINE uint16_t retro_get_unaligned_16be(void *addr) {
|
||||
return retro_be_to_cpu16(retro_unaligned16(addr));
|
||||
}
|
||||
|
||||
/**
|
||||
* retro_get_unaligned_32be:
|
||||
* @addr : pointer to unsigned 32-bit value
|
||||
*
|
||||
* Convert unsigned unaligned 32-bit value from big-endian to native.
|
||||
*
|
||||
* Returns: Native representation of big-endian val.
|
||||
**/
|
||||
|
||||
static INLINE uint32_t retro_get_unaligned_32be(void *addr) {
|
||||
return retro_be_to_cpu32(retro_unaligned32(addr));
|
||||
}
|
||||
|
||||
/**
|
||||
* retro_get_unaligned_64be:
|
||||
* @addr : pointer to unsigned 64-bit value
|
||||
*
|
||||
* Convert unsigned unaligned 64-bit value from big-endian to native.
|
||||
*
|
||||
* Returns: Native representation of big-endian val.
|
||||
**/
|
||||
|
||||
static INLINE uint64_t retro_get_unaligned_64be(void *addr) {
|
||||
return retro_be_to_cpu64(retro_unaligned64(addr));
|
||||
}
|
||||
|
||||
/**
|
||||
* retro_get_unaligned_16le:
|
||||
* @addr : pointer to unsigned 16-bit value
|
||||
*
|
||||
* Convert unsigned unaligned 16-bit value from little-endian to native.
|
||||
*
|
||||
* Returns: Native representation of little-endian val.
|
||||
**/
|
||||
|
||||
static INLINE uint16_t retro_get_unaligned_16le(void *addr) {
|
||||
return retro_le_to_cpu16(retro_unaligned16(addr));
|
||||
}
|
||||
|
||||
/**
|
||||
* retro_get_unaligned_32le:
|
||||
* @addr : pointer to unsigned 32-bit value
|
||||
*
|
||||
* Convert unsigned unaligned 32-bit value from little-endian to native.
|
||||
*
|
||||
* Returns: Native representation of little-endian val.
|
||||
**/
|
||||
|
||||
static INLINE uint32_t retro_get_unaligned_32le(void *addr) {
|
||||
return retro_le_to_cpu32(retro_unaligned32(addr));
|
||||
}
|
||||
|
||||
/**
|
||||
* retro_get_unaligned_64le:
|
||||
* @addr : pointer to unsigned 64-bit value
|
||||
*
|
||||
* Convert unsigned unaligned 64-bit value from little-endian to native.
|
||||
*
|
||||
* Returns: Native representation of little-endian val.
|
||||
**/
|
||||
|
||||
static INLINE uint64_t retro_get_unaligned_64le(void *addr) {
|
||||
return retro_le_to_cpu64(retro_unaligned64(addr));
|
||||
}
|
||||
|
||||
/**
|
||||
* retro_set_unaligned_16le:
|
||||
* @addr : pointer to unsigned 16-bit value
|
||||
* @val : value to store
|
||||
*
|
||||
* Convert native value to unsigned unaligned 16-bit little-endian value
|
||||
*
|
||||
**/
|
||||
|
||||
static INLINE void retro_set_unaligned_16le(void *addr, uint16_t v) {
|
||||
retro_unaligned16(addr) = retro_cpu_to_le16(v);
|
||||
}
|
||||
|
||||
/**
|
||||
* retro_set_unaligned_32le:
|
||||
* @addr : pointer to unsigned 32-bit value
|
||||
* @val : value to store
|
||||
*
|
||||
* Convert native value to unsigned unaligned 32-bit little-endian value
|
||||
*
|
||||
**/
|
||||
|
||||
static INLINE void retro_set_unaligned_32le(void *addr, uint32_t v) {
|
||||
retro_unaligned32(addr) = retro_cpu_to_le32(v);
|
||||
}
|
||||
|
||||
/**
|
||||
* retro_set_unaligned_32le:
|
||||
* @addr : pointer to unsigned 32-bit value
|
||||
* @val : value to store
|
||||
*
|
||||
* Convert native value to unsigned unaligned 32-bit little-endian value
|
||||
*
|
||||
**/
|
||||
|
||||
static INLINE void retro_set_unaligned_64le(void *addr, uint64_t v) {
|
||||
retro_unaligned64(addr) = retro_cpu_to_le64(v);
|
||||
}
|
||||
|
||||
/**
|
||||
* retro_set_unaligned_16be:
|
||||
* @addr : pointer to unsigned 16-bit value
|
||||
* @val : value to store
|
||||
*
|
||||
* Convert native value to unsigned unaligned 16-bit big-endian value
|
||||
*
|
||||
**/
|
||||
|
||||
static INLINE void retro_set_unaligned_16be(void *addr, uint16_t v) {
|
||||
retro_unaligned16(addr) = retro_cpu_to_be16(v);
|
||||
}
|
||||
|
||||
/**
|
||||
* retro_set_unaligned_32be:
|
||||
* @addr : pointer to unsigned 32-bit value
|
||||
* @val : value to store
|
||||
*
|
||||
* Convert native value to unsigned unaligned 32-bit big-endian value
|
||||
*
|
||||
**/
|
||||
|
||||
static INLINE void retro_set_unaligned_32be(void *addr, uint32_t v) {
|
||||
retro_unaligned32(addr) = retro_cpu_to_be32(v);
|
||||
}
|
||||
|
||||
/**
|
||||
* retro_set_unaligned_32be:
|
||||
* @addr : pointer to unsigned 32-bit value
|
||||
* @val : value to store
|
||||
*
|
||||
* Convert native value to unsigned unaligned 32-bit big-endian value
|
||||
*
|
||||
**/
|
||||
|
||||
static INLINE void retro_set_unaligned_64be(void *addr, uint64_t v) {
|
||||
retro_unaligned64(addr) = retro_cpu_to_be64(v);
|
||||
}
|
||||
|
||||
|
||||
#endif
|
||||
|
@ -1,4 +1,4 @@
|
||||
/* Copyright (C) 2010-2018 The RetroArch team
|
||||
/* Copyright (C) 2010-2020 The RetroArch team
|
||||
*
|
||||
* ---------------------------------------------------------------------------------------
|
||||
* The following license statement only applies to this file (retro_environment.h).
|
||||
|
@ -1,4 +1,4 @@
|
||||
/* Copyright (C) 2010-2018 The RetroArch team
|
||||
/* Copyright (C) 2010-2020 The RetroArch team
|
||||
*
|
||||
* ---------------------------------------------------------------------------------------
|
||||
* The following license statement only applies to this file (retro_inline.h).
|
||||
|
@ -1,4 +1,4 @@
|
||||
/* Copyright (C) 2010-2018 The RetroArch team
|
||||
/* Copyright (C) 2010-2020 The RetroArch team
|
||||
*
|
||||
* ---------------------------------------------------------------------------------------
|
||||
* The following license statement only applies to this file (retro_math.h).
|
||||
|
@ -1,4 +1,4 @@
|
||||
/* Copyright (C) 2010-2018 The RetroArch team
|
||||
/* Copyright (C) 2010-2020 The RetroArch team
|
||||
*
|
||||
* ---------------------------------------------------------------------------------------
|
||||
* The following license statement only applies to this file (retro_miscellaneous.h).
|
||||
@ -30,16 +30,20 @@
|
||||
#include <boolean.h>
|
||||
#include <retro_inline.h>
|
||||
|
||||
#if defined(_WIN32) && !defined(_XBOX)
|
||||
#if defined(_WIN32)
|
||||
|
||||
#if defined(_XBOX)
|
||||
#include <Xtl.h>
|
||||
#else
|
||||
#ifndef WIN32_LEAN_AND_MEAN
|
||||
#define WIN32_LEAN_AND_MEAN
|
||||
#endif
|
||||
#include <windows.h>
|
||||
#elif defined(_WIN32) && defined(_XBOX)
|
||||
#include <Xtl.h>
|
||||
#endif
|
||||
|
||||
#if defined(__CELLOS_LV2__)
|
||||
#endif
|
||||
|
||||
#if defined(__CELLOS_LV2__) && !defined(__PSL1GHT__)
|
||||
#include <sys/fs_external.h>
|
||||
#endif
|
||||
|
||||
@ -75,7 +79,7 @@ static INLINE bool bits_any_set(uint32_t* ptr, uint32_t count)
|
||||
}
|
||||
|
||||
#ifndef PATH_MAX_LENGTH
|
||||
#if defined(__CELLOS_LV2__)
|
||||
#if defined(__CELLOS_LV2__) && !defined(__PSL1GHT__)
|
||||
#define PATH_MAX_LENGTH CELL_FS_MAX_FS_PATH_LENGTH
|
||||
#elif defined(_XBOX1) || defined(_3DS) || defined(PSP) || defined(PS2) || defined(GEKKO)|| defined(WIIU) || defined(ORBIS)
|
||||
#define PATH_MAX_LENGTH 512
|
||||
@ -106,8 +110,8 @@ static INLINE bool bits_any_set(uint32_t* ptr, uint32_t count)
|
||||
#define BIT16_GET(a, bit) (((a) >> ((bit) & 15)) & 1)
|
||||
#define BIT16_CLEAR_ALL(a) ((a) = 0)
|
||||
|
||||
#define BIT32_SET(a, bit) ((a) |= (1 << ((bit) & 31)))
|
||||
#define BIT32_CLEAR(a, bit) ((a) &= ~(1 << ((bit) & 31)))
|
||||
#define BIT32_SET(a, bit) ((a) |= (UINT32_C(1) << ((bit) & 31)))
|
||||
#define BIT32_CLEAR(a, bit) ((a) &= ~(UINT32_C(1) << ((bit) & 31)))
|
||||
#define BIT32_GET(a, bit) (((a) >> ((bit) & 31)) & 1)
|
||||
#define BIT32_CLEAR_ALL(a) ((a) = 0)
|
||||
|
||||
@ -116,8 +120,8 @@ static INLINE bool bits_any_set(uint32_t* ptr, uint32_t count)
|
||||
#define BIT64_GET(a, bit) (((a) >> ((bit) & 63)) & 1)
|
||||
#define BIT64_CLEAR_ALL(a) ((a) = 0)
|
||||
|
||||
#define BIT128_SET(a, bit) ((a).data[(bit) >> 5] |= (1 << ((bit) & 31)))
|
||||
#define BIT128_CLEAR(a, bit) ((a).data[(bit) >> 5] &= ~(1 << ((bit) & 31)))
|
||||
#define BIT128_SET(a, bit) ((a).data[(bit) >> 5] |= (UINT32_C(1) << ((bit) & 31)))
|
||||
#define BIT128_CLEAR(a, bit) ((a).data[(bit) >> 5] &= ~(UINT32_C(1) << ((bit) & 31)))
|
||||
#define BIT128_GET(a, bit) (((a).data[(bit) >> 5] >> ((bit) & 31)) & 1)
|
||||
#define BIT128_CLEAR_ALL(a) memset(&(a), 0, sizeof(a))
|
||||
|
||||
@ -165,7 +169,7 @@ typedef struct
|
||||
# define PRI_SIZET "u"
|
||||
# endif
|
||||
# endif
|
||||
#elif PS2
|
||||
#elif defined(PS2)
|
||||
# define PRI_SIZET "u"
|
||||
#else
|
||||
# if (SIZE_MAX == 0xFFFF)
|
||||
|
@ -1,4 +1,4 @@
|
||||
/* Copyright (C) 2010-2018 The RetroArch team
|
||||
/* Copyright (C) 2010-2020 The RetroArch team
|
||||
*
|
||||
* ---------------------------------------------------------------------------------------
|
||||
* The following license statement only applies to this file (retro_timers.h).
|
||||
@ -37,8 +37,6 @@
|
||||
#include <pspthreadman.h>
|
||||
#elif defined(VITA)
|
||||
#include <psp2/kernel/threadmgr.h>
|
||||
#elif defined(PS2)
|
||||
#include <SDL/SDL_timer.h>
|
||||
#elif defined(_3DS)
|
||||
#include <3ds.h>
|
||||
#else
|
||||
@ -68,7 +66,7 @@ extern int nanosleep(const struct timespec *rqtp, struct timespec *rmtp);
|
||||
|
||||
static int nanosleepDOS(const struct timespec *rqtp, struct timespec *rmtp)
|
||||
{
|
||||
usleep(1000000 * rqtp->tv_sec + rqtp->tv_nsec / 1000);
|
||||
usleep(1000000L * rqtp->tv_sec + rqtp->tv_nsec / 1000);
|
||||
|
||||
if (rmtp)
|
||||
rmtp->tv_sec = rmtp->tv_nsec=0;
|
||||
@ -85,32 +83,30 @@ static int nanosleepDOS(const struct timespec *rqtp, struct timespec *rmtp)
|
||||
*
|
||||
* Sleeps for a specified amount of milliseconds (@msec).
|
||||
**/
|
||||
#if defined(__CELLOS_LV2__) && !defined(__PSL1GHT__)
|
||||
#define retro_sleep(msec) (sys_timer_usleep(1000 * (msec)))
|
||||
#elif defined(PSP) || defined(VITA)
|
||||
#define retro_sleep(msec) (sceKernelDelayThread(1000 * (msec)))
|
||||
#elif defined(_3DS)
|
||||
#define retro_sleep(msec) (svcSleepThread(1000000 * (s64)(msec)))
|
||||
#elif defined(__WINRT__) || defined(WINAPI_FAMILY) && WINAPI_FAMILY == WINAPI_FAMILY_PHONE_APP
|
||||
#define retro_sleep(msec) (SleepEx((msec), FALSE))
|
||||
#elif defined(_WIN32)
|
||||
#define retro_sleep(msec) (Sleep((msec)))
|
||||
#elif defined(XENON)
|
||||
#define retro_sleep(msec) (udelay(1000 * (msec)))
|
||||
#elif defined(GEKKO) || defined(__PSL1GHT__) || defined(__QNX__)
|
||||
#define retro_sleep(msec) (usleep(1000 * (msec)))
|
||||
#elif defined(WIIU)
|
||||
#define retro_sleep(msec) (OSSleepTicks(ms_to_ticks((msec))))
|
||||
#else
|
||||
static INLINE void retro_sleep(unsigned msec)
|
||||
{
|
||||
#if defined(__CELLOS_LV2__) && !defined(__PSL1GHT__)
|
||||
sys_timer_usleep(1000 * msec);
|
||||
#elif defined(PSP) || defined(VITA)
|
||||
sceKernelDelayThread(1000 * msec);
|
||||
#elif defined(PS2)
|
||||
SDL_Delay(msec);
|
||||
#elif defined(_3DS)
|
||||
svcSleepThread(1000000 * (s64)msec);
|
||||
#elif defined(__WINRT__) || defined(WINAPI_FAMILY) && WINAPI_FAMILY == WINAPI_FAMILY_PHONE_APP
|
||||
SleepEx(msec, FALSE);
|
||||
#elif defined(_WIN32)
|
||||
Sleep(msec);
|
||||
#elif defined(XENON)
|
||||
udelay(1000 * msec);
|
||||
#elif defined(GEKKO) || defined(__PSL1GHT__) || defined(__QNX__)
|
||||
usleep(1000 * msec);
|
||||
#elif defined(WIIU)
|
||||
OSSleepTicks(ms_to_ticks(msec));
|
||||
#else
|
||||
struct timespec tv = {0};
|
||||
tv.tv_sec = msec / 1000;
|
||||
tv.tv_nsec = (msec % 1000) * 1000000;
|
||||
tv.tv_sec = msec / 1000;
|
||||
tv.tv_nsec = (msec % 1000) * 1000000;
|
||||
nanosleep(&tv, NULL);
|
||||
#endif
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif
|
||||
|
@ -1,4 +1,4 @@
|
||||
/* Copyright (C) 2010-2018 The RetroArch team
|
||||
/* Copyright (C) 2010-2020 The RetroArch team
|
||||
*
|
||||
* ---------------------------------------------------------------------------------------
|
||||
* The following license statement only applies to this file (file_stream.h).
|
||||
|
@ -1,4 +1,4 @@
|
||||
/* Copyright (C) 2010-2018 The RetroArch team
|
||||
/* Copyright (C) 2010-2020 The RetroArch team
|
||||
*
|
||||
* ---------------------------------------------------------------------------------------
|
||||
* The following license statement only applies to this file (file_stream_transforms.h).
|
||||
|
@ -1,4 +1,4 @@
|
||||
/* Copyright (C) 2010-2019 The RetroArch team
|
||||
/* Copyright (C) 2010-2020 The RetroArch team
|
||||
*
|
||||
* ---------------------------------------------------------------------------------------
|
||||
* The following license statement only applies to this file (stdstring.h).
|
||||
@ -35,6 +35,33 @@
|
||||
|
||||
RETRO_BEGIN_DECLS
|
||||
|
||||
#define STRLEN_CONST(x) ((sizeof((x))-1))
|
||||
|
||||
#define strcpy_literal(a, b) strcpy(a, b)
|
||||
|
||||
#define string_is_not_equal(a, b) !string_is_equal((a), (b))
|
||||
|
||||
#define string_is_not_equal_fast(a, b, size) (memcmp(a, b, size) != 0)
|
||||
#define string_is_equal_fast(a, b, size) (memcmp(a, b, size) == 0)
|
||||
|
||||
#define TOLOWER(c) (c | (lr_char_props[c] & 0x20))
|
||||
#define TOUPPER(c) (c & ~(lr_char_props[c] & 0x20))
|
||||
|
||||
/* C standard says \f \v are space, but this one disagrees */
|
||||
#define ISSPACE(c) (lr_char_props[c] & 0x80)
|
||||
|
||||
#define ISDIGIT(c) (lr_char_props[c] & 0x40)
|
||||
#define ISALPHA(c) (lr_char_props[c] & 0x20)
|
||||
#define ISLOWER(c) (lr_char_props[c] & 0x04)
|
||||
#define ISUPPER(c) (lr_char_props[c] & 0x02)
|
||||
#define ISALNUM(c) (lr_char_props[c] & 0x60)
|
||||
#define ISUALPHA(c) (lr_char_props[c] & 0x28)
|
||||
#define ISUALNUM(c) (lr_char_props[c] & 0x68)
|
||||
#define IS_XDIGIT(c) (lr_char_props[c] & 0x01)
|
||||
|
||||
/* Deprecated alias, all callers should use string_is_equal_case_insensitive instead */
|
||||
#define string_is_equal_noncase string_is_equal_case_insensitive
|
||||
|
||||
static INLINE bool string_is_empty(const char *data)
|
||||
{
|
||||
return !data || (*data == '\0');
|
||||
@ -45,12 +72,44 @@ static INLINE bool string_is_equal(const char *a, const char *b)
|
||||
return (a && b) ? !strcmp(a, b) : false;
|
||||
}
|
||||
|
||||
#define STRLEN_CONST(x) ((sizeof((x))-1))
|
||||
static INLINE bool string_starts_with_size(const char *str, const char *prefix,
|
||||
size_t size)
|
||||
{
|
||||
return (str && prefix) ? !strncmp(prefix, str, size) : false;
|
||||
}
|
||||
|
||||
#define string_is_not_equal(a, b) !string_is_equal((a), (b))
|
||||
static INLINE bool string_starts_with(const char *str, const char *prefix)
|
||||
{
|
||||
return (str && prefix) ? !strncmp(prefix, str, strlen(prefix)) : false;
|
||||
}
|
||||
|
||||
static INLINE bool string_ends_with_size(const char *str, const char *suffix,
|
||||
size_t str_len, size_t suffix_len)
|
||||
{
|
||||
return (str_len < suffix_len) ? false :
|
||||
!memcmp(suffix, str + (str_len - suffix_len), suffix_len);
|
||||
}
|
||||
|
||||
static INLINE bool string_ends_with(const char *str, const char *suffix)
|
||||
{
|
||||
if (!str || !suffix)
|
||||
return false;
|
||||
return string_ends_with_size(str, suffix, strlen(str), strlen(suffix));
|
||||
}
|
||||
|
||||
/* Returns the length of 'str' (c.f. strlen()), but only
|
||||
* checks the first 'size' characters
|
||||
* - If 'str' is NULL, returns 0
|
||||
* - If 'str' is not NULL and no '\0' character is found
|
||||
* in the first 'size' characters, returns 'size' */
|
||||
static INLINE size_t strlen_size(const char *str, size_t size)
|
||||
{
|
||||
size_t i = 0;
|
||||
if (str)
|
||||
while (i < size && str[i]) i++;
|
||||
return i;
|
||||
}
|
||||
|
||||
#define string_is_not_equal_fast(a, b, size) (memcmp(a, b, size) != 0)
|
||||
#define string_is_equal_fast(a, b, size) (memcmp(a, b, size) == 0)
|
||||
|
||||
static INLINE bool string_is_equal_case_insensitive(const char *a,
|
||||
const char *b)
|
||||
@ -71,24 +130,6 @@ static INLINE bool string_is_equal_case_insensitive(const char *a,
|
||||
return (result == 0);
|
||||
}
|
||||
|
||||
static INLINE bool string_is_equal_noncase(const char *a, const char *b)
|
||||
{
|
||||
int result = 0;
|
||||
const unsigned char *p1 = (const unsigned char*)a;
|
||||
const unsigned char *p2 = (const unsigned char*)b;
|
||||
|
||||
if (!a || !b)
|
||||
return false;
|
||||
if (p1 == p2)
|
||||
return false;
|
||||
|
||||
while ((result = tolower (*p1) - tolower (*p2++)) == 0)
|
||||
if (*p1++ == '\0')
|
||||
break;
|
||||
|
||||
return (result == 0);
|
||||
}
|
||||
|
||||
char *string_to_upper(char *s);
|
||||
|
||||
char *string_to_lower(char *s);
|
||||
@ -121,7 +162,7 @@ char *word_wrap(char *buffer, const char *string,
|
||||
* char *str = "1,2,3,4,5,6,7,,,10,";
|
||||
* char **str_ptr = &str;
|
||||
* char *token = NULL;
|
||||
* while((token = string_tokenize(str_ptr, ",")))
|
||||
* while ((token = string_tokenize(str_ptr, ",")))
|
||||
* {
|
||||
* printf("%s\n", token);
|
||||
* free(token);
|
||||
@ -146,6 +187,12 @@ unsigned string_to_unsigned(const char *str);
|
||||
* Returns 0 if string is invalid */
|
||||
unsigned string_hex_to_unsigned(const char *str);
|
||||
|
||||
char *string_init(const char *src);
|
||||
|
||||
void string_set(char **string, const char *src);
|
||||
|
||||
extern const unsigned char lr_char_props[256];
|
||||
|
||||
RETRO_END_DECLS
|
||||
|
||||
#endif
|
||||
|
48
libretro-common/include/time/rtime.h
Normal file
48
libretro-common/include/time/rtime.h
Normal file
@ -0,0 +1,48 @@
|
||||
/* Copyright (C) 2010-2020 The RetroArch team
|
||||
*
|
||||
* ---------------------------------------------------------------------------------------
|
||||
* The following license statement only applies to this file (rtime.h).
|
||||
* ---------------------------------------------------------------------------------------
|
||||
*
|
||||
* Permission is hereby granted, free of charge,
|
||||
* to any person obtaining a copy of this software and associated documentation files (the "Software"),
|
||||
* to deal in the Software without restriction, including without limitation the rights to
|
||||
* use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software,
|
||||
* and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
|
||||
* INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
|
||||
* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
|
||||
* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
*/
|
||||
|
||||
#ifndef __LIBRETRO_SDK_RTIME_H__
|
||||
#define __LIBRETRO_SDK_RTIME_H__
|
||||
|
||||
#include <retro_common_api.h>
|
||||
|
||||
#include <stdint.h>
|
||||
#include <stddef.h>
|
||||
#include <time.h>
|
||||
|
||||
RETRO_BEGIN_DECLS
|
||||
|
||||
/* TODO/FIXME: Move all generic time handling functions
|
||||
* to this file */
|
||||
|
||||
/* Must be called before using rtime_localtime() */
|
||||
void rtime_init(void);
|
||||
|
||||
/* Must be called upon program termination */
|
||||
void rtime_deinit(void);
|
||||
|
||||
/* Thread-safe wrapper for localtime() */
|
||||
struct tm *rtime_localtime(const time_t *timep, struct tm *result);
|
||||
|
||||
RETRO_END_DECLS
|
||||
|
||||
#endif
|
@ -1,4 +1,4 @@
|
||||
/* Copyright (C) 2010-2019 The RetroArch team
|
||||
/* Copyright (C) 2010-2020 The RetroArch team
|
||||
*
|
||||
* ---------------------------------------------------------------------------------------
|
||||
* The following license statement only applies to this file (vfs_implementation.h).
|
||||
@ -41,17 +41,17 @@ typedef void* HANDLE;
|
||||
#ifdef HAVE_CDROM
|
||||
typedef struct
|
||||
{
|
||||
int64_t byte_pos;
|
||||
char *cue_buf;
|
||||
size_t cue_len;
|
||||
int64_t byte_pos;
|
||||
char drive;
|
||||
unsigned cur_lba;
|
||||
unsigned last_frame_lba;
|
||||
unsigned char cur_min;
|
||||
unsigned char cur_sec;
|
||||
unsigned char cur_frame;
|
||||
unsigned char cur_track;
|
||||
unsigned cur_lba;
|
||||
unsigned last_frame_lba;
|
||||
unsigned char last_frame[2352];
|
||||
char drive;
|
||||
bool last_frame_valid;
|
||||
} vfs_cdrom_t;
|
||||
#endif
|
||||
@ -69,22 +69,22 @@ struct retro_vfs_file_handle
|
||||
struct libretro_vfs_implementation_file
|
||||
#endif
|
||||
{
|
||||
int fd;
|
||||
unsigned hints;
|
||||
#ifdef HAVE_CDROM
|
||||
vfs_cdrom_t cdrom; /* int64_t alignment */
|
||||
#endif
|
||||
int64_t size;
|
||||
char *buf;
|
||||
uint64_t mappos;
|
||||
uint64_t mapsize;
|
||||
FILE *fp;
|
||||
#ifdef _WIN32
|
||||
HANDLE fh;
|
||||
#endif
|
||||
char *buf;
|
||||
char* orig_path;
|
||||
uint64_t mappos;
|
||||
uint64_t mapsize;
|
||||
uint8_t *mapped;
|
||||
int fd;
|
||||
unsigned hints;
|
||||
enum vfs_scheme scheme;
|
||||
#ifdef HAVE_CDROM
|
||||
vfs_cdrom_t cdrom;
|
||||
#endif
|
||||
};
|
||||
#endif
|
||||
|
||||
|
@ -1,4 +1,4 @@
|
||||
/* Copyright (C) 2010-2019 The RetroArch team
|
||||
/* Copyright (C) 2010-2020 The RetroArch team
|
||||
*
|
||||
* ---------------------------------------------------------------------------------------
|
||||
* The following license statement only applies to this file (vfs_implementation.h).
|
||||
|
@ -1,4 +1,4 @@
|
||||
/* Copyright (C) 2010-2019 The RetroArch team
|
||||
/* Copyright (C) 2010-2020 The RetroArch team
|
||||
*
|
||||
* ---------------------------------------------------------------------------------------
|
||||
* The following license statement only applies to this file (vfs_implementation_cdrom.h).
|
||||
|
@ -1,4 +1,4 @@
|
||||
/* Copyright (C) 2010-2018 The RetroArch team
|
||||
/* Copyright (C) 2010-2020 The RetroArch team
|
||||
*
|
||||
* ---------------------------------------------------------------------------------------
|
||||
* The following license statement only applies to this file (dir_list.c).
|
||||
@ -86,6 +86,13 @@ void dir_list_free(struct string_list *list)
|
||||
string_list_free(list);
|
||||
}
|
||||
|
||||
bool dir_list_deinitialize(struct string_list *list)
|
||||
{
|
||||
if (!list)
|
||||
return false;
|
||||
return string_list_deinitialize(list);
|
||||
}
|
||||
|
||||
/**
|
||||
* dir_list_read:
|
||||
* @dir : directory path.
|
||||
@ -116,10 +123,21 @@ static int dir_list_read(const char *dir,
|
||||
char file_path[PATH_MAX_LENGTH];
|
||||
const char *name = retro_dirent_get_name(entry);
|
||||
|
||||
if (!include_hidden && *name == '.')
|
||||
continue;
|
||||
if (!strcmp(name, ".") || !strcmp(name, ".."))
|
||||
continue;
|
||||
if (name[0] == '.')
|
||||
{
|
||||
/* Do not include hidden files and directories */
|
||||
if (!include_hidden)
|
||||
continue;
|
||||
|
||||
/* char-wise comparisons to avoid string comparison */
|
||||
|
||||
/* Do not include current dir */
|
||||
if (name[1] == '\0')
|
||||
continue;
|
||||
/* Do not include parent dir */
|
||||
if (name[1] == '.' && name[2] == '\0')
|
||||
continue;
|
||||
}
|
||||
|
||||
file_path[0] = '\0';
|
||||
fill_pathname_join(file_path, dir, name, sizeof(file_path));
|
||||
@ -196,12 +214,19 @@ bool dir_list_append(struct string_list *list,
|
||||
bool include_hidden, bool include_compressed,
|
||||
bool recursive)
|
||||
{
|
||||
struct string_list *ext_list = ext ? string_split(ext, "|") : NULL;
|
||||
bool ret = dir_list_read(dir, list, ext_list,
|
||||
bool ret = false;
|
||||
struct string_list ext_list = {0};
|
||||
struct string_list *ext_list_ptr = NULL;
|
||||
|
||||
if (ext)
|
||||
{
|
||||
string_list_initialize(&ext_list);
|
||||
string_split_noalloc(&ext_list, ext, "|");
|
||||
ext_list_ptr = &ext_list;
|
||||
}
|
||||
ret = dir_list_read(dir, list, ext_list_ptr,
|
||||
include_dirs, include_hidden, include_compressed, recursive) != -1;
|
||||
|
||||
string_list_free(ext_list);
|
||||
|
||||
string_list_deinitialize(&ext_list);
|
||||
return ret;
|
||||
}
|
||||
|
||||
@ -224,9 +249,9 @@ struct string_list *dir_list_new(const char *dir,
|
||||
bool include_hidden, bool include_compressed,
|
||||
bool recursive)
|
||||
{
|
||||
struct string_list *list = NULL;
|
||||
struct string_list *list = string_list_new();
|
||||
|
||||
if (!(list = string_list_new()))
|
||||
if (!list)
|
||||
return NULL;
|
||||
|
||||
if (!dir_list_append(list, dir, ext, include_dirs,
|
||||
@ -238,3 +263,18 @@ struct string_list *dir_list_new(const char *dir,
|
||||
|
||||
return list;
|
||||
}
|
||||
|
||||
/* Warning: 'list' must zero initialised before
|
||||
* calling this function, otherwise memory leaks/
|
||||
* undefined behaviour will occur */
|
||||
bool dir_list_initialize(struct string_list *list,
|
||||
const char *dir,
|
||||
const char *ext, bool include_dirs,
|
||||
bool include_hidden, bool include_compressed,
|
||||
bool recursive)
|
||||
{
|
||||
if (!list || !string_list_initialize(list))
|
||||
return false;
|
||||
return dir_list_append(list, dir, ext, include_dirs,
|
||||
include_hidden, include_compressed, recursive);
|
||||
}
|
||||
|
@ -1,4 +1,4 @@
|
||||
/* Copyright (C) 2010-2018 The RetroArch team
|
||||
/* Copyright (C) 2010-2020 The RetroArch team
|
||||
*
|
||||
* ---------------------------------------------------------------------------------------
|
||||
* The following license statement only applies to this file (string_list.c).
|
||||
@ -29,20 +29,14 @@
|
||||
#include <compat/posix_string.h>
|
||||
#include <string/stdstring.h>
|
||||
|
||||
/**
|
||||
* string_list_free
|
||||
* @list : pointer to string list object
|
||||
*
|
||||
* Frees a string list.
|
||||
*/
|
||||
void string_list_free(struct string_list *list)
|
||||
static bool string_list_deinitialize_internal(struct string_list *list)
|
||||
{
|
||||
size_t i;
|
||||
if (!list)
|
||||
return;
|
||||
return false;
|
||||
|
||||
if (list->elems)
|
||||
{
|
||||
unsigned i;
|
||||
for (i = 0; i < list->size; i++)
|
||||
{
|
||||
if (list->elems[i].data)
|
||||
@ -57,7 +51,8 @@ void string_list_free(struct string_list *list)
|
||||
}
|
||||
|
||||
list->elems = NULL;
|
||||
free(list);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
@ -85,6 +80,34 @@ static bool string_list_capacity(struct string_list *list, size_t cap)
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* string_list_free
|
||||
* @list : pointer to string list object
|
||||
*
|
||||
* Frees a string list.
|
||||
*/
|
||||
void string_list_free(struct string_list *list)
|
||||
{
|
||||
if (!list)
|
||||
return;
|
||||
|
||||
string_list_deinitialize_internal(list);
|
||||
|
||||
free(list);
|
||||
}
|
||||
|
||||
bool string_list_deinitialize(struct string_list *list)
|
||||
{
|
||||
if (!list)
|
||||
return false;
|
||||
if (!string_list_deinitialize_internal(list))
|
||||
return false;
|
||||
list->elems = NULL;
|
||||
list->size = 0;
|
||||
list->cap = 0;
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* string_list_new:
|
||||
*
|
||||
@ -94,21 +117,45 @@ static bool string_list_capacity(struct string_list *list, size_t cap)
|
||||
*/
|
||||
struct string_list *string_list_new(void)
|
||||
{
|
||||
struct string_list_elem *
|
||||
elems = NULL;
|
||||
struct string_list *list = (struct string_list*)
|
||||
calloc(1, sizeof(*list));
|
||||
|
||||
malloc(sizeof(*list));
|
||||
if (!list)
|
||||
return NULL;
|
||||
|
||||
if (!string_list_capacity(list, 32))
|
||||
if (!(elems = (struct string_list_elem*)
|
||||
calloc(32, sizeof(*elems))))
|
||||
{
|
||||
string_list_free(list);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
list->elems = elems;
|
||||
list->size = 0;
|
||||
list->cap = 32;
|
||||
|
||||
return list;
|
||||
}
|
||||
|
||||
bool string_list_initialize(struct string_list *list)
|
||||
{
|
||||
struct string_list_elem *
|
||||
elems = NULL;
|
||||
if (!list)
|
||||
return false;
|
||||
if (!(elems = (struct string_list_elem*)
|
||||
calloc(32, sizeof(*elems))))
|
||||
{
|
||||
string_list_deinitialize(list);
|
||||
return false;
|
||||
}
|
||||
list->elems = elems;
|
||||
list->size = 0;
|
||||
list->cap = 32;
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* string_list_append:
|
||||
* @list : pointer to string list
|
||||
@ -124,8 +171,15 @@ bool string_list_append(struct string_list *list, const char *elem,
|
||||
{
|
||||
char *data_dup = NULL;
|
||||
|
||||
/* Note: If 'list' is incorrectly initialised
|
||||
* (i.e. if struct is zero initialised and
|
||||
* string_list_initialize() is not called on
|
||||
* it) capacity will be zero. This will cause
|
||||
* a segfault. Handle this case by forcing the new
|
||||
* capacity to a fixed size of 32 */
|
||||
if (list->size >= list->cap &&
|
||||
!string_list_capacity(list, list->cap * 2))
|
||||
!string_list_capacity(list,
|
||||
(list->cap > 0) ? (list->cap * 2) : 32))
|
||||
return false;
|
||||
|
||||
data_dup = strdup(elem);
|
||||
@ -201,7 +255,18 @@ void string_list_set(struct string_list *list,
|
||||
void string_list_join_concat(char *buffer, size_t size,
|
||||
const struct string_list *list, const char *delim)
|
||||
{
|
||||
size_t i, len = strlen(buffer);
|
||||
size_t i;
|
||||
size_t len = strlen_size(buffer, size);
|
||||
|
||||
/* If buffer is already 'full', nothing
|
||||
* further can be added
|
||||
* > This condition will also be triggered
|
||||
* if buffer is not NUL-terminated,
|
||||
* in which case any attempt to increment
|
||||
* buffer or decrement size would lead to
|
||||
* undefined behaviour */
|
||||
if (len >= size)
|
||||
return;
|
||||
|
||||
buffer += len;
|
||||
size -= len;
|
||||
@ -231,7 +296,7 @@ struct string_list *string_split(const char *str, const char *delim)
|
||||
struct string_list *list = string_list_new();
|
||||
|
||||
if (!list)
|
||||
goto error;
|
||||
return NULL;
|
||||
|
||||
copy = strdup(str);
|
||||
if (!copy)
|
||||
@ -259,6 +324,40 @@ error:
|
||||
return NULL;
|
||||
}
|
||||
|
||||
bool string_split_noalloc(struct string_list *list,
|
||||
const char *str, const char *delim)
|
||||
{
|
||||
char *save = NULL;
|
||||
char *copy = NULL;
|
||||
const char *tmp = NULL;
|
||||
|
||||
if (!list)
|
||||
return false;
|
||||
|
||||
copy = strdup(str);
|
||||
if (!copy)
|
||||
return false;
|
||||
|
||||
tmp = strtok_r(copy, delim, &save);
|
||||
while (tmp)
|
||||
{
|
||||
union string_list_elem_attr attr;
|
||||
|
||||
attr.i = 0;
|
||||
|
||||
if (!string_list_append(list, tmp, attr))
|
||||
{
|
||||
free(copy);
|
||||
return false;
|
||||
}
|
||||
|
||||
tmp = strtok_r(NULL, delim, &save);
|
||||
}
|
||||
|
||||
free(copy);
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* string_separate:
|
||||
* @str : string to turn into a string list
|
||||
@ -312,6 +411,39 @@ error:
|
||||
return NULL;
|
||||
}
|
||||
|
||||
bool string_separate_noalloc(
|
||||
struct string_list *list,
|
||||
char *str, const char *delim)
|
||||
{
|
||||
char *token = NULL;
|
||||
char **str_ptr = NULL;
|
||||
|
||||
/* Sanity check */
|
||||
if (!str || string_is_empty(delim) || !list)
|
||||
return false;
|
||||
|
||||
str_ptr = &str;
|
||||
token = string_tokenize(str_ptr, delim);
|
||||
|
||||
while (token)
|
||||
{
|
||||
union string_list_elem_attr attr;
|
||||
|
||||
attr.i = 0;
|
||||
|
||||
if (!string_list_append(list, token, attr))
|
||||
{
|
||||
free(token);
|
||||
return false;
|
||||
}
|
||||
|
||||
free(token);
|
||||
token = string_tokenize(str_ptr, delim);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* string_list_find_elem:
|
||||
* @list : pointer to string list
|
||||
@ -376,19 +508,22 @@ struct string_list *string_list_clone(
|
||||
const struct string_list *src)
|
||||
{
|
||||
unsigned i;
|
||||
struct string_list_elem *elems = NULL;
|
||||
struct string_list *dest = (struct string_list*)
|
||||
calloc(1, sizeof(struct string_list));
|
||||
struct string_list_elem
|
||||
*elems = NULL;
|
||||
struct string_list
|
||||
*dest = (struct string_list*)
|
||||
malloc(sizeof(struct string_list));
|
||||
|
||||
if (!dest)
|
||||
return NULL;
|
||||
|
||||
dest->size = src->size;
|
||||
dest->cap = src->cap;
|
||||
dest->elems = NULL;
|
||||
dest->size = src->size;
|
||||
dest->cap = src->cap;
|
||||
if (dest->cap < dest->size)
|
||||
dest->cap = dest->size;
|
||||
dest->cap = dest->size;
|
||||
|
||||
elems = (struct string_list_elem*)
|
||||
elems = (struct string_list_elem*)
|
||||
calloc(dest->cap, sizeof(struct string_list_elem));
|
||||
|
||||
if (!elems)
|
||||
|
@ -1,4 +1,4 @@
|
||||
/* Copyright (C) 2010-2018 The RetroArch team
|
||||
/* Copyright (C) 2010-2020 The RetroArch team
|
||||
*
|
||||
* ---------------------------------------------------------------------------------------
|
||||
* The following license statement only applies to this file (memalign.c).
|
||||
|
@ -1,4 +1,4 @@
|
||||
/* Copyright (C) 2010-2018 The RetroArch team
|
||||
/* Copyright (C) 2010-2020 The RetroArch team
|
||||
*
|
||||
* ---------------------------------------------------------------------------------------
|
||||
* The following license statement only applies to this file (file_stream.c).
|
||||
@ -31,11 +31,23 @@
|
||||
#include "config.h"
|
||||
#endif
|
||||
|
||||
#ifdef _MSC_VER
|
||||
#include <compat/msvc.h>
|
||||
#endif
|
||||
|
||||
#include <string/stdstring.h>
|
||||
#include <streams/file_stream.h>
|
||||
#define VFS_FRONTEND
|
||||
#include <vfs/vfs_implementation.h>
|
||||
|
||||
static const int64_t vfs_error_return_value = -1;
|
||||
#define VFS_ERROR_RETURN_VALUE -1
|
||||
|
||||
struct RFILE
|
||||
{
|
||||
struct retro_vfs_file_handle *hfile;
|
||||
bool error_flag;
|
||||
bool eof_flag;
|
||||
};
|
||||
|
||||
static retro_vfs_get_path_t filestream_get_path_cb = NULL;
|
||||
static retro_vfs_open_t filestream_open_cb = NULL;
|
||||
@ -50,18 +62,12 @@ static retro_vfs_flush_t filestream_flush_cb = NULL;
|
||||
static retro_vfs_remove_t filestream_remove_cb = NULL;
|
||||
static retro_vfs_rename_t filestream_rename_cb = NULL;
|
||||
|
||||
struct RFILE
|
||||
{
|
||||
struct retro_vfs_file_handle *hfile;
|
||||
bool error_flag;
|
||||
bool eof_flag;
|
||||
};
|
||||
|
||||
/* VFS Initialization */
|
||||
|
||||
void filestream_vfs_init(const struct retro_vfs_interface_info* vfs_info)
|
||||
{
|
||||
const struct retro_vfs_interface* vfs_iface;
|
||||
const struct retro_vfs_interface *
|
||||
vfs_iface = vfs_info->iface;
|
||||
|
||||
filestream_get_path_cb = NULL;
|
||||
filestream_open_cb = NULL;
|
||||
@ -76,9 +82,9 @@ void filestream_vfs_init(const struct retro_vfs_interface_info* vfs_info)
|
||||
filestream_remove_cb = NULL;
|
||||
filestream_rename_cb = NULL;
|
||||
|
||||
vfs_iface = vfs_info->iface;
|
||||
|
||||
if (vfs_info->required_interface_version < FILESTREAM_REQUIRED_VFS_VERSION
|
||||
if (
|
||||
(vfs_info->required_interface_version <
|
||||
FILESTREAM_REQUIRED_VFS_VERSION)
|
||||
|| !vfs_iface)
|
||||
return;
|
||||
|
||||
@ -99,19 +105,24 @@ void filestream_vfs_init(const struct retro_vfs_interface_info* vfs_info)
|
||||
/* Callback wrappers */
|
||||
bool filestream_exists(const char *path)
|
||||
{
|
||||
RFILE *dummy = NULL;
|
||||
RFILE *dummy = NULL;
|
||||
|
||||
if (!path || !*path)
|
||||
return false;
|
||||
|
||||
dummy = filestream_open(path,
|
||||
dummy = filestream_open(
|
||||
path,
|
||||
RETRO_VFS_FILE_ACCESS_READ,
|
||||
RETRO_VFS_FILE_ACCESS_HINT_NONE);
|
||||
|
||||
if (!dummy)
|
||||
return false;
|
||||
|
||||
filestream_close(dummy);
|
||||
if (filestream_close(dummy) != 0)
|
||||
if (dummy)
|
||||
free(dummy);
|
||||
|
||||
dummy = NULL;
|
||||
return true;
|
||||
}
|
||||
|
||||
@ -119,12 +130,13 @@ int64_t filestream_get_size(RFILE *stream)
|
||||
{
|
||||
int64_t output;
|
||||
|
||||
if (filestream_size_cb != NULL)
|
||||
if (filestream_size_cb)
|
||||
output = filestream_size_cb(stream->hfile);
|
||||
else
|
||||
output = retro_vfs_file_size_impl((libretro_vfs_implementation_file*)stream->hfile);
|
||||
output = retro_vfs_file_size_impl(
|
||||
(libretro_vfs_implementation_file*)stream->hfile);
|
||||
|
||||
if (output == vfs_error_return_value)
|
||||
if (output == VFS_ERROR_RETURN_VALUE)
|
||||
stream->error_flag = true;
|
||||
|
||||
return output;
|
||||
@ -134,12 +146,13 @@ int64_t filestream_truncate(RFILE *stream, int64_t length)
|
||||
{
|
||||
int64_t output;
|
||||
|
||||
if (filestream_truncate_cb != NULL)
|
||||
if (filestream_truncate_cb)
|
||||
output = filestream_truncate_cb(stream->hfile, length);
|
||||
else
|
||||
output = retro_vfs_file_truncate_impl((libretro_vfs_implementation_file*)stream->hfile, length);
|
||||
output = retro_vfs_file_truncate_impl(
|
||||
(libretro_vfs_implementation_file*)stream->hfile, length);
|
||||
|
||||
if (output == vfs_error_return_value)
|
||||
if (output == VFS_ERROR_RETURN_VALUE)
|
||||
stream->error_flag = true;
|
||||
|
||||
return output;
|
||||
@ -159,7 +172,7 @@ RFILE* filestream_open(const char *path, unsigned mode, unsigned hints)
|
||||
struct retro_vfs_file_handle *fp = NULL;
|
||||
RFILE* output = NULL;
|
||||
|
||||
if (filestream_open_cb != NULL)
|
||||
if (filestream_open_cb)
|
||||
fp = (struct retro_vfs_file_handle*)
|
||||
filestream_open_cb(path, mode, hints);
|
||||
else
|
||||
@ -203,9 +216,7 @@ char* filestream_gets(RFILE *stream, char *s, size_t len)
|
||||
int filestream_getc(RFILE *stream)
|
||||
{
|
||||
char c = 0;
|
||||
if (!stream)
|
||||
return EOF;
|
||||
if (filestream_read(stream, &c, 1) == 1)
|
||||
if (stream && filestream_read(stream, &c, 1) == 1)
|
||||
return (int)(unsigned char)c;
|
||||
return EOF;
|
||||
}
|
||||
@ -215,10 +226,9 @@ int filestream_scanf(RFILE *stream, const char* format, ...)
|
||||
char buf[4096];
|
||||
char subfmt[64];
|
||||
va_list args;
|
||||
|
||||
const char * bufiter = buf;
|
||||
int64_t startpos = filestream_tell(stream);
|
||||
int ret = 0;
|
||||
int64_t startpos = filestream_tell(stream);
|
||||
int64_t maxlen = filestream_read(stream, buf, sizeof(buf)-1);
|
||||
|
||||
if (maxlen <= 0)
|
||||
@ -233,7 +243,6 @@ int filestream_scanf(RFILE *stream, const char* format, ...)
|
||||
if (*format == '%')
|
||||
{
|
||||
int sublen;
|
||||
|
||||
char* subfmtiter = subfmt;
|
||||
bool asterisk = false;
|
||||
|
||||
@ -243,19 +252,25 @@ int filestream_scanf(RFILE *stream, const char* format, ...)
|
||||
|
||||
if (*format == '*')
|
||||
{
|
||||
asterisk = true;
|
||||
asterisk = true;
|
||||
*subfmtiter++ = *format++;
|
||||
}
|
||||
|
||||
while (isdigit(*format)) *subfmtiter++ = *format++; /* width */
|
||||
while (ISDIGIT((unsigned char)*format))
|
||||
*subfmtiter++ = *format++; /* width */
|
||||
|
||||
/* length */
|
||||
if (*format == 'h' || *format == 'l')
|
||||
{
|
||||
if (format[1] == format[0]) *subfmtiter++ = *format++;
|
||||
*subfmtiter++ = *format++;
|
||||
if (format[1] == format[0])
|
||||
*subfmtiter++ = *format++;
|
||||
*subfmtiter++ = *format++;
|
||||
}
|
||||
else if (*format == 'j' || *format == 'z' || *format == 't' || *format == 'L')
|
||||
else if (
|
||||
*format == 'j' ||
|
||||
*format == 'z' ||
|
||||
*format == 't' ||
|
||||
*format == 'L')
|
||||
{
|
||||
*subfmtiter++ = *format++;
|
||||
}
|
||||
@ -263,31 +278,44 @@ int filestream_scanf(RFILE *stream, const char* format, ...)
|
||||
/* specifier - always a single character (except ]) */
|
||||
if (*format == '[')
|
||||
{
|
||||
while (*format != ']') *subfmtiter++ = *format++;
|
||||
*subfmtiter++ = *format++;
|
||||
while (*format != ']')
|
||||
*subfmtiter++ = *format++;
|
||||
*subfmtiter++ = *format++;
|
||||
}
|
||||
else *subfmtiter++ = *format++;
|
||||
else
|
||||
*subfmtiter++ = *format++;
|
||||
|
||||
*subfmtiter++ = '%';
|
||||
*subfmtiter++ = 'n';
|
||||
*subfmtiter++ = '\0';
|
||||
*subfmtiter++ = '%';
|
||||
*subfmtiter++ = 'n';
|
||||
*subfmtiter++ = '\0';
|
||||
|
||||
if (sizeof(void*) != sizeof(long*))
|
||||
abort(); /* all pointers must have the same size */
|
||||
|
||||
if (sizeof(void*) != sizeof(long*)) abort(); /* all pointers must have the same size */
|
||||
if (asterisk)
|
||||
{
|
||||
if (sscanf(bufiter, subfmt, &sublen) != 0) break;
|
||||
int v = sscanf(bufiter, subfmt, &sublen);
|
||||
if (v == EOF)
|
||||
return EOF;
|
||||
if (v != 0)
|
||||
break;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (sscanf(bufiter, subfmt, va_arg(args, void*), &sublen) != 1) break;
|
||||
int v = sscanf(bufiter, subfmt, va_arg(args, void*), &sublen);
|
||||
if (v == EOF)
|
||||
return EOF;
|
||||
if (v != 1)
|
||||
break;
|
||||
}
|
||||
|
||||
ret++;
|
||||
bufiter += sublen;
|
||||
}
|
||||
else if (isspace(*format))
|
||||
else if (isspace((unsigned char)*format))
|
||||
{
|
||||
while (isspace(*bufiter)) bufiter++;
|
||||
while (isspace((unsigned char)*bufiter))
|
||||
bufiter++;
|
||||
format++;
|
||||
}
|
||||
else
|
||||
@ -300,7 +328,8 @@ int filestream_scanf(RFILE *stream, const char* format, ...)
|
||||
}
|
||||
|
||||
va_end(args);
|
||||
filestream_seek(stream, startpos+(bufiter-buf), RETRO_VFS_SEEK_POSITION_START);
|
||||
filestream_seek(stream, startpos+(bufiter-buf),
|
||||
RETRO_VFS_SEEK_POSITION_START);
|
||||
|
||||
return ret;
|
||||
}
|
||||
@ -309,14 +338,17 @@ int64_t filestream_seek(RFILE *stream, int64_t offset, int seek_position)
|
||||
{
|
||||
int64_t output;
|
||||
|
||||
if (filestream_seek_cb != NULL)
|
||||
if (filestream_seek_cb)
|
||||
output = filestream_seek_cb(stream->hfile, offset, seek_position);
|
||||
else
|
||||
output = retro_vfs_file_seek_impl((libretro_vfs_implementation_file*)stream->hfile, offset, seek_position);
|
||||
output = retro_vfs_file_seek_impl(
|
||||
(libretro_vfs_implementation_file*)stream->hfile,
|
||||
offset, seek_position);
|
||||
|
||||
if (output == vfs_error_return_value)
|
||||
if (output == VFS_ERROR_RETURN_VALUE)
|
||||
stream->error_flag = true;
|
||||
stream->eof_flag = false;
|
||||
|
||||
stream->eof_flag = false;
|
||||
|
||||
return output;
|
||||
}
|
||||
@ -330,12 +362,13 @@ int64_t filestream_tell(RFILE *stream)
|
||||
{
|
||||
int64_t output;
|
||||
|
||||
if (filestream_size_cb != NULL)
|
||||
if (filestream_size_cb)
|
||||
output = filestream_tell_cb(stream->hfile);
|
||||
else
|
||||
output = retro_vfs_file_tell_impl((libretro_vfs_implementation_file*)stream->hfile);
|
||||
output = retro_vfs_file_tell_impl(
|
||||
(libretro_vfs_implementation_file*)stream->hfile);
|
||||
|
||||
if (output == vfs_error_return_value)
|
||||
if (output == VFS_ERROR_RETURN_VALUE)
|
||||
stream->error_flag = true;
|
||||
|
||||
return output;
|
||||
@ -347,23 +380,23 @@ void filestream_rewind(RFILE *stream)
|
||||
return;
|
||||
filestream_seek(stream, 0L, RETRO_VFS_SEEK_POSITION_START);
|
||||
stream->error_flag = false;
|
||||
stream->eof_flag = false;
|
||||
stream->eof_flag = false;
|
||||
}
|
||||
|
||||
int64_t filestream_read(RFILE *stream, void *s, int64_t len)
|
||||
{
|
||||
int64_t output;
|
||||
|
||||
if (filestream_read_cb != NULL)
|
||||
if (filestream_read_cb)
|
||||
output = filestream_read_cb(stream->hfile, s, len);
|
||||
else
|
||||
output = retro_vfs_file_read_impl(
|
||||
(libretro_vfs_implementation_file*)stream->hfile, s, len);
|
||||
|
||||
if (output == vfs_error_return_value)
|
||||
if (output == VFS_ERROR_RETURN_VALUE)
|
||||
stream->error_flag = true;
|
||||
if (output < len)
|
||||
stream->eof_flag = true;
|
||||
stream->eof_flag = true;
|
||||
|
||||
return output;
|
||||
}
|
||||
@ -372,12 +405,13 @@ int filestream_flush(RFILE *stream)
|
||||
{
|
||||
int output;
|
||||
|
||||
if (filestream_flush_cb != NULL)
|
||||
if (filestream_flush_cb)
|
||||
output = filestream_flush_cb(stream->hfile);
|
||||
else
|
||||
output = retro_vfs_file_flush_impl((libretro_vfs_implementation_file*)stream->hfile);
|
||||
output = retro_vfs_file_flush_impl(
|
||||
(libretro_vfs_implementation_file*)stream->hfile);
|
||||
|
||||
if (output == vfs_error_return_value)
|
||||
if (output == VFS_ERROR_RETURN_VALUE)
|
||||
stream->error_flag = true;
|
||||
|
||||
return output;
|
||||
@ -385,7 +419,7 @@ int filestream_flush(RFILE *stream)
|
||||
|
||||
int filestream_delete(const char *path)
|
||||
{
|
||||
if (filestream_remove_cb != NULL)
|
||||
if (filestream_remove_cb)
|
||||
return filestream_remove_cb(path);
|
||||
|
||||
return retro_vfs_file_remove_impl(path);
|
||||
@ -393,7 +427,7 @@ int filestream_delete(const char *path)
|
||||
|
||||
int filestream_rename(const char *old_path, const char *new_path)
|
||||
{
|
||||
if (filestream_rename_cb != NULL)
|
||||
if (filestream_rename_cb)
|
||||
return filestream_rename_cb(old_path, new_path);
|
||||
|
||||
return retro_vfs_file_rename_impl(old_path, new_path);
|
||||
@ -401,22 +435,24 @@ int filestream_rename(const char *old_path, const char *new_path)
|
||||
|
||||
const char* filestream_get_path(RFILE *stream)
|
||||
{
|
||||
if (filestream_get_path_cb != NULL)
|
||||
if (filestream_get_path_cb)
|
||||
return filestream_get_path_cb(stream->hfile);
|
||||
|
||||
return retro_vfs_file_get_path_impl((libretro_vfs_implementation_file*)stream->hfile);
|
||||
return retro_vfs_file_get_path_impl(
|
||||
(libretro_vfs_implementation_file*)stream->hfile);
|
||||
}
|
||||
|
||||
int64_t filestream_write(RFILE *stream, const void *s, int64_t len)
|
||||
{
|
||||
int64_t output;
|
||||
|
||||
if (filestream_write_cb != NULL)
|
||||
if (filestream_write_cb)
|
||||
output = filestream_write_cb(stream->hfile, s, len);
|
||||
else
|
||||
output = retro_vfs_file_write_impl((libretro_vfs_implementation_file*)stream->hfile, s, len);
|
||||
output = retro_vfs_file_write_impl(
|
||||
(libretro_vfs_implementation_file*)stream->hfile, s, len);
|
||||
|
||||
if (output == vfs_error_return_value)
|
||||
if (output == VFS_ERROR_RETURN_VALUE)
|
||||
stream->error_flag = true;
|
||||
|
||||
return output;
|
||||
@ -427,13 +463,16 @@ int filestream_putc(RFILE *stream, int c)
|
||||
char c_char = (char)c;
|
||||
if (!stream)
|
||||
return EOF;
|
||||
return filestream_write(stream, &c_char, 1)==1 ? (int)(unsigned char)c : EOF;
|
||||
return filestream_write(stream, &c_char, 1) == 1
|
||||
? (int)(unsigned char)c
|
||||
: EOF;
|
||||
}
|
||||
|
||||
int filestream_vprintf(RFILE *stream, const char* format, va_list args)
|
||||
{
|
||||
static char buffer[8 * 1024];
|
||||
int64_t num_chars = vsprintf(buffer, format, args);
|
||||
int64_t num_chars = vsnprintf(buffer, sizeof(buffer),
|
||||
format, args);
|
||||
|
||||
if (num_chars < 0)
|
||||
return -1;
|
||||
@ -465,10 +504,11 @@ int filestream_close(RFILE *stream)
|
||||
int output;
|
||||
struct retro_vfs_file_handle* fp = stream->hfile;
|
||||
|
||||
if (filestream_close_cb != NULL)
|
||||
if (filestream_close_cb)
|
||||
output = filestream_close_cb(fp);
|
||||
else
|
||||
output = retro_vfs_file_close_impl((libretro_vfs_implementation_file*)fp);
|
||||
output = retro_vfs_file_close_impl(
|
||||
(libretro_vfs_implementation_file*)fp);
|
||||
|
||||
if (output == 0)
|
||||
free(stream);
|
||||
@ -497,8 +537,8 @@ int64_t filestream_read_file(const char *path, void **buf, int64_t *len)
|
||||
|
||||
if (!file)
|
||||
{
|
||||
fprintf(stderr, "Failed to open %s: %s\n", path, strerror(errno));
|
||||
goto error;
|
||||
*buf = NULL;
|
||||
return 0;
|
||||
}
|
||||
|
||||
content_buf_size = filestream_get_size(file);
|
||||
@ -515,12 +555,11 @@ int64_t filestream_read_file(const char *path, void **buf, int64_t *len)
|
||||
|
||||
ret = filestream_read(file, content_buf, (int64_t)content_buf_size);
|
||||
if (ret < 0)
|
||||
{
|
||||
fprintf(stderr, "Failed to read %s: %s\n", path, strerror(errno));
|
||||
goto error;
|
||||
}
|
||||
|
||||
filestream_close(file);
|
||||
if (filestream_close(file) != 0)
|
||||
if (file)
|
||||
free(file);
|
||||
|
||||
*buf = content_buf;
|
||||
|
||||
@ -535,7 +574,8 @@ int64_t filestream_read_file(const char *path, void **buf, int64_t *len)
|
||||
|
||||
error:
|
||||
if (file)
|
||||
filestream_close(file);
|
||||
if (filestream_close(file) != 0)
|
||||
free(file);
|
||||
if (content_buf)
|
||||
free(content_buf);
|
||||
if (len)
|
||||
@ -564,7 +604,9 @@ bool filestream_write_file(const char *path, const void *data, int64_t size)
|
||||
return false;
|
||||
|
||||
ret = filestream_write(file, data, size);
|
||||
filestream_close(file);
|
||||
if (filestream_close(file) != 0)
|
||||
if (file)
|
||||
free(file);
|
||||
|
||||
if (ret != size)
|
||||
return false;
|
||||
|
@ -1,4 +1,4 @@
|
||||
/* Copyright (C) 2010-2018 The RetroArch team
|
||||
/* Copyright (C) 2010-2020 The RetroArch team
|
||||
*
|
||||
* ---------------------------------------------------------------------------------------
|
||||
* The following license statement only applies to this file (file_stream_transforms.c).
|
||||
|
@ -1,4 +1,4 @@
|
||||
/* Copyright (C) 2010-2018 The RetroArch team
|
||||
/* Copyright (C) 2010-2020 The RetroArch team
|
||||
*
|
||||
* ---------------------------------------------------------------------------------------
|
||||
* The following license statement only applies to this file (stdstring.c).
|
||||
@ -26,6 +26,38 @@
|
||||
#include <string/stdstring.h>
|
||||
#include <encodings/utf.h>
|
||||
|
||||
const uint8_t lr_char_props[256] = {
|
||||
/*x0 x1 x2 x3 x4 x5 x6 x7 x8 x9 xA xB xC xD xE xF */
|
||||
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x80,0x80,0x00,0x00,0x80,0x00,0x00, /* 0x */
|
||||
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, /* 1x */
|
||||
0x80,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, /* 2x !"#$%&'()*+,-./ */
|
||||
0x41,0x41,0x41,0x41,0x41,0x41,0x41,0x41,0x41,0x41,0x00,0x00,0x00,0x00,0x00,0x00, /* 3x 0123456789:;<=>? */
|
||||
0x00,0x23,0x23,0x23,0x23,0x23,0x23,0x22,0x22,0x22,0x22,0x22,0x22,0x22,0x22,0x22, /* 4x @ABCDEFGHIJKLMNO */
|
||||
0x22,0x22,0x22,0x22,0x22,0x22,0x22,0x22,0x22,0x22,0x22,0x00,0x00,0x00,0x00,0x08, /* 5x PQRSTUVWXYZ[\]^_ */
|
||||
0x00,0x25,0x25,0x25,0x25,0x25,0x25,0x24,0x24,0x24,0x24,0x24,0x24,0x24,0x24,0x24, /* 6x `abcdefghijklmno */
|
||||
0x24,0x24,0x24,0x24,0x24,0x24,0x24,0x24,0x24,0x24,0x24,0x00,0x00,0x00,0x00,0x00, /* 7x pqrstuvwxyz{|}~ */
|
||||
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, /* 8x */
|
||||
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, /* 9x */
|
||||
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, /* Ax */
|
||||
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, /* Bx */
|
||||
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, /* Cx */
|
||||
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, /* Dx */
|
||||
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, /* Ex */
|
||||
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, /* Fx */
|
||||
};
|
||||
|
||||
char *string_init(const char *src)
|
||||
{
|
||||
return src ? strdup(src) : NULL;
|
||||
}
|
||||
|
||||
void string_set(char **string, const char *src)
|
||||
{
|
||||
free(*string);
|
||||
*string = string_init(src);
|
||||
}
|
||||
|
||||
|
||||
char *string_to_upper(char *s)
|
||||
{
|
||||
char *cs = (char *)s;
|
||||
@ -107,18 +139,18 @@ char *string_replace_substring(const char *in,
|
||||
/* Remove leading whitespaces */
|
||||
char *string_trim_whitespace_left(char *const s)
|
||||
{
|
||||
if(s && *s)
|
||||
if (s && *s)
|
||||
{
|
||||
size_t len = strlen(s);
|
||||
char *current = s;
|
||||
|
||||
while(*current && isspace((unsigned char)*current))
|
||||
while (*current && ISSPACE((unsigned char)*current))
|
||||
{
|
||||
++current;
|
||||
--len;
|
||||
}
|
||||
|
||||
if(s != current)
|
||||
if (s != current)
|
||||
memmove(s, current, len + 1);
|
||||
}
|
||||
|
||||
@ -128,18 +160,18 @@ char *string_trim_whitespace_left(char *const s)
|
||||
/* Remove trailing whitespaces */
|
||||
char *string_trim_whitespace_right(char *const s)
|
||||
{
|
||||
if(s && *s)
|
||||
if (s && *s)
|
||||
{
|
||||
size_t len = strlen(s);
|
||||
char *current = s + len - 1;
|
||||
|
||||
while(current != s && isspace((unsigned char)*current))
|
||||
while (current != s && ISSPACE((unsigned char)*current))
|
||||
{
|
||||
--current;
|
||||
--len;
|
||||
}
|
||||
|
||||
current[isspace((unsigned char)*current) ? 0 : 1] = '\0';
|
||||
current[ISSPACE((unsigned char)*current) ? 0 : 1] = '\0';
|
||||
}
|
||||
|
||||
return s;
|
||||
@ -190,7 +222,7 @@ char *word_wrap(char* buffer, const char *string, int line_width, bool unicode,
|
||||
buffer[i] = string[i];
|
||||
char_len--;
|
||||
i++;
|
||||
} while(char_len);
|
||||
} while (char_len);
|
||||
|
||||
/* check for newlines embedded in the original input
|
||||
* and reset the index */
|
||||
@ -248,7 +280,7 @@ char *word_wrap(char* buffer, const char *string, int line_width, bool unicode,
|
||||
* char *str = "1,2,3,4,5,6,7,,,10,";
|
||||
* char **str_ptr = &str;
|
||||
* char *token = NULL;
|
||||
* while((token = string_tokenize(str_ptr, ",")))
|
||||
* while ((token = string_tokenize(str_ptr, ",")))
|
||||
* {
|
||||
* printf("%s\n", token);
|
||||
* free(token);
|
||||
@ -328,7 +360,7 @@ void string_replace_all_chars(char *str, char find, char replace)
|
||||
if (string_is_empty(str))
|
||||
return;
|
||||
|
||||
while((str_ptr = strchr(str_ptr, find)) != NULL)
|
||||
while ((str_ptr = strchr(str_ptr, find)))
|
||||
*str_ptr++ = replace;
|
||||
}
|
||||
|
||||
@ -343,7 +375,7 @@ unsigned string_to_unsigned(const char *str)
|
||||
|
||||
for (ptr = str; *ptr != '\0'; ptr++)
|
||||
{
|
||||
if (!isdigit(*ptr))
|
||||
if (!ISDIGIT((unsigned char)*ptr))
|
||||
return 0;
|
||||
}
|
||||
|
||||
@ -376,7 +408,7 @@ unsigned string_hex_to_unsigned(const char *str)
|
||||
/* Check for valid characters */
|
||||
for (ptr = hex_str; *ptr != '\0'; ptr++)
|
||||
{
|
||||
if (!isxdigit(*ptr))
|
||||
if (!isxdigit((unsigned char)*ptr))
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
81
libretro-common/time/rtime.c
Normal file
81
libretro-common/time/rtime.c
Normal file
@ -0,0 +1,81 @@
|
||||
/* Copyright (C) 2010-2020 The RetroArch team
|
||||
*
|
||||
* ---------------------------------------------------------------------------------------
|
||||
* The following license statement only applies to this file (rtime.c).
|
||||
* ---------------------------------------------------------------------------------------
|
||||
*
|
||||
* Permission is hereby granted, free of charge,
|
||||
* to any person obtaining a copy of this software and associated documentation files (the "Software"),
|
||||
* to deal in the Software without restriction, including without limitation the rights to
|
||||
* use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software,
|
||||
* and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
|
||||
* INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
|
||||
* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
|
||||
* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
*/
|
||||
|
||||
#ifdef HAVE_THREADS
|
||||
#include <rthreads/rthreads.h>
|
||||
#include <retro_assert.h>
|
||||
#include <stdlib.h>
|
||||
#endif
|
||||
|
||||
#include <string.h>
|
||||
#include <time/rtime.h>
|
||||
|
||||
#ifdef HAVE_THREADS
|
||||
/* TODO/FIXME - global */
|
||||
slock_t *rtime_localtime_lock = NULL;
|
||||
#endif
|
||||
|
||||
/* Must be called before using rtime_localtime() */
|
||||
void rtime_init(void)
|
||||
{
|
||||
rtime_deinit();
|
||||
#ifdef HAVE_THREADS
|
||||
if (!rtime_localtime_lock)
|
||||
rtime_localtime_lock = slock_new();
|
||||
|
||||
retro_assert(rtime_localtime_lock);
|
||||
#endif
|
||||
}
|
||||
|
||||
/* Must be called upon program termination */
|
||||
void rtime_deinit(void)
|
||||
{
|
||||
#ifdef HAVE_THREADS
|
||||
if (rtime_localtime_lock)
|
||||
{
|
||||
slock_free(rtime_localtime_lock);
|
||||
rtime_localtime_lock = NULL;
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
/* Thread-safe wrapper for localtime() */
|
||||
struct tm *rtime_localtime(const time_t *timep, struct tm *result)
|
||||
{
|
||||
struct tm *time_info = NULL;
|
||||
|
||||
/* Lock mutex */
|
||||
#ifdef HAVE_THREADS
|
||||
slock_lock(rtime_localtime_lock);
|
||||
#endif
|
||||
|
||||
time_info = localtime(timep);
|
||||
if (time_info)
|
||||
memcpy(result, time_info, sizeof(struct tm));
|
||||
|
||||
/* Unlock mutex */
|
||||
#ifdef HAVE_THREADS
|
||||
slock_unlock(rtime_localtime_lock);
|
||||
#endif
|
||||
|
||||
return result;
|
||||
}
|
@ -1,4 +1,4 @@
|
||||
/* Copyright (C) 2010-2019 The RetroArch team
|
||||
/* Copyright (C) 2010-2020 The RetroArch team
|
||||
*
|
||||
* ---------------------------------------------------------------------------------------
|
||||
* The following license statement only applies to this file (vfs_implementation.c).
|
||||
@ -51,10 +51,6 @@
|
||||
# if defined(PSP)
|
||||
# include <pspiofilemgr.h>
|
||||
# endif
|
||||
# if defined(PS2)
|
||||
# include <fileXio_rpc.h>
|
||||
# include <fileXio_cdvd.h>
|
||||
# endif
|
||||
# include <sys/types.h>
|
||||
# include <sys/stat.h>
|
||||
# if !defined(VITA)
|
||||
@ -68,7 +64,7 @@
|
||||
# endif
|
||||
#endif
|
||||
|
||||
#ifdef __CELLOS_LV2__
|
||||
#if defined (__CELLOS_LV2__) && !defined(__PSL1GHT__)
|
||||
#include <cell/cell_fs.h>
|
||||
#define O_RDONLY CELL_FS_O_RDONLY
|
||||
#define O_WRONLY CELL_FS_O_WRONLY
|
||||
@ -93,16 +89,13 @@
|
||||
# if defined(PSP)
|
||||
# include <pspiofilemgr.h>
|
||||
# endif
|
||||
# if defined(PS2)
|
||||
# include <fileXio_rpc.h>
|
||||
# endif
|
||||
# include <sys/types.h>
|
||||
# include <sys/stat.h>
|
||||
# include <dirent.h>
|
||||
# include <unistd.h>
|
||||
#endif
|
||||
|
||||
#if (defined(__CELLOS_LV2__) && !defined(__PSL1GHT__)) || defined(__QNX__) || defined(PSP) || defined(PS2)
|
||||
#if (defined(__CELLOS_LV2__) && !defined(__PSL1GHT__)) || defined(__QNX__) || defined(PSP)
|
||||
#include <unistd.h> /* stat() is defined here */
|
||||
#endif
|
||||
|
||||
@ -146,12 +139,7 @@
|
||||
#include <pspkernel.h>
|
||||
#endif
|
||||
|
||||
#if defined(PS2)
|
||||
#include <fileXio_rpc.h>
|
||||
#include <fileXio.h>
|
||||
#endif
|
||||
|
||||
#if defined(__CELLOS_LV2__)
|
||||
#if defined(__CELLOS_LV2__) && !defined(__PSL1GHT__)
|
||||
#include <cell/cell_fs.h>
|
||||
#endif
|
||||
|
||||
@ -173,7 +161,7 @@
|
||||
#endif
|
||||
|
||||
#if defined(_WIN32)
|
||||
#if !defined(_MSC_VER) || (defined(_MSC_VER) && _MSC_VER >= 1400)
|
||||
#if defined(_MSC_VER) && _MSC_VER >= 1400
|
||||
#define ATLEAST_VC2005
|
||||
#endif
|
||||
#endif
|
||||
@ -189,9 +177,17 @@
|
||||
#include <vfs/vfs_implementation_cdrom.h>
|
||||
#endif
|
||||
|
||||
#if (defined(_POSIX_C_SOURCE) && (_POSIX_C_SOURCE - 0) >= 200112) || (defined(__POSIX_VISIBLE) && __POSIX_VISIBLE >= 200112) || (defined(_POSIX_VERSION) && _POSIX_VERSION >= 200112) || __USE_LARGEFILE || (defined(_FILE_OFFSET_BITS) && _FILE_OFFSET_BITS == 64)
|
||||
#ifndef HAVE_64BIT_OFFSETS
|
||||
#define HAVE_64BIT_OFFSETS
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#define RFILE_HINT_UNBUFFERED (1 << 8)
|
||||
|
||||
int64_t retro_vfs_file_seek_internal(libretro_vfs_implementation_file *stream, int64_t offset, int whence)
|
||||
int64_t retro_vfs_file_seek_internal(
|
||||
libretro_vfs_implementation_file *stream,
|
||||
int64_t offset, int whence)
|
||||
{
|
||||
if (!stream)
|
||||
return -1;
|
||||
@ -202,19 +198,9 @@ int64_t retro_vfs_file_seek_internal(libretro_vfs_implementation_file *stream, i
|
||||
if (stream->scheme == VFS_SCHEME_CDROM)
|
||||
return retro_vfs_file_seek_cdrom(stream, offset, whence);
|
||||
#endif
|
||||
/* VC2005 and up have a special 64-bit fseek */
|
||||
#ifdef ATLEAST_VC2005
|
||||
/* VC2005 and up have a special 64-bit fseek */
|
||||
return _fseeki64(stream->fp, offset, whence);
|
||||
#elif defined(__CELLOS_LV2__) || defined(_MSC_VER) && _MSC_VER <= 1310
|
||||
return fseek(stream->fp, (long)offset, whence);
|
||||
#elif defined(PS2)
|
||||
{
|
||||
int64_t ret = fileXioLseek(fileno(stream->fp), (off_t)offset, whence);
|
||||
/* fileXioLseek could return positive numbers */
|
||||
if (ret > 0)
|
||||
return 0;
|
||||
return ret;
|
||||
}
|
||||
#elif defined(ORBIS)
|
||||
{
|
||||
int ret = orbisLseek(stream->fd, offset, whence);
|
||||
@ -222,8 +208,10 @@ int64_t retro_vfs_file_seek_internal(libretro_vfs_implementation_file *stream, i
|
||||
return -1;
|
||||
return 0;
|
||||
}
|
||||
#else
|
||||
#elif defined(HAVE_64BIT_OFFSETS)
|
||||
return fseeko(stream->fp, (off_t)offset, whence);
|
||||
#else
|
||||
return fseek(stream->fp, (long)offset, whence);
|
||||
#endif
|
||||
}
|
||||
#ifdef HAVE_MMAP
|
||||
@ -263,7 +251,7 @@ int64_t retro_vfs_file_seek_internal(libretro_vfs_implementation_file *stream, i
|
||||
}
|
||||
#endif
|
||||
|
||||
if (lseek(stream->fd, offset, whence) < 0)
|
||||
if (lseek(stream->fd, (off_t)offset, whence) < 0)
|
||||
return -1;
|
||||
|
||||
return 0;
|
||||
@ -282,47 +270,72 @@ int64_t retro_vfs_file_seek_internal(libretro_vfs_implementation_file *stream, i
|
||||
libretro_vfs_implementation_file *retro_vfs_file_open_impl(
|
||||
const char *path, unsigned mode, unsigned hints)
|
||||
{
|
||||
int flags = 0;
|
||||
const char *mode_str = NULL;
|
||||
#if defined(VFS_FRONTEND) || defined(HAVE_CDROM)
|
||||
int path_len = (int)strlen(path);
|
||||
libretro_vfs_implementation_file *stream = (libretro_vfs_implementation_file*)
|
||||
calloc(1, sizeof(*stream));
|
||||
|
||||
#endif
|
||||
#ifdef VFS_FRONTEND
|
||||
const char *dumb_prefix = "vfsonly://";
|
||||
size_t dumb_prefix_siz = strlen(dumb_prefix);
|
||||
size_t dumb_prefix_siz = STRLEN_CONST("vfsonly://");
|
||||
int dumb_prefix_len = (int)dumb_prefix_siz;
|
||||
|
||||
if (path_len >= dumb_prefix_len)
|
||||
{
|
||||
if (!memcmp(path, dumb_prefix, dumb_prefix_len))
|
||||
path += dumb_prefix_siz;
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifdef HAVE_CDROM
|
||||
{
|
||||
const char *cdrom_prefix = "cdrom://";
|
||||
size_t cdrom_prefix_siz = strlen(cdrom_prefix);
|
||||
int cdrom_prefix_len = (int)cdrom_prefix_siz;
|
||||
|
||||
if (path_len > cdrom_prefix_len)
|
||||
{
|
||||
if (!memcmp(path, cdrom_prefix, cdrom_prefix_len))
|
||||
{
|
||||
path += cdrom_prefix_siz;
|
||||
stream->scheme = VFS_SCHEME_CDROM;
|
||||
}
|
||||
}
|
||||
}
|
||||
const char *cdrom_prefix = "cdrom://";
|
||||
size_t cdrom_prefix_siz = STRLEN_CONST("cdrom://");
|
||||
int cdrom_prefix_len = (int)cdrom_prefix_siz;
|
||||
#endif
|
||||
int flags = 0;
|
||||
const char *mode_str = NULL;
|
||||
libretro_vfs_implementation_file *stream =
|
||||
(libretro_vfs_implementation_file*)
|
||||
malloc(sizeof(*stream));
|
||||
|
||||
if (!stream)
|
||||
return NULL;
|
||||
|
||||
(void)flags;
|
||||
stream->fd = 0;
|
||||
stream->hints = hints;
|
||||
stream->size = 0;
|
||||
stream->buf = NULL;
|
||||
stream->fp = NULL;
|
||||
#ifdef _WIN32
|
||||
stream->fh = 0;
|
||||
#endif
|
||||
stream->orig_path = NULL;
|
||||
stream->mappos = 0;
|
||||
stream->mapsize = 0;
|
||||
stream->mapped = NULL;
|
||||
stream->scheme = VFS_SCHEME_NONE;
|
||||
|
||||
#ifdef VFS_FRONTEND
|
||||
if (path_len >= dumb_prefix_len)
|
||||
if (!memcmp(path, dumb_prefix, dumb_prefix_len))
|
||||
path += dumb_prefix_siz;
|
||||
#endif
|
||||
|
||||
#ifdef HAVE_CDROM
|
||||
stream->cdrom.cue_buf = NULL;
|
||||
stream->cdrom.cue_len = 0;
|
||||
stream->cdrom.byte_pos = 0;
|
||||
stream->cdrom.drive = 0;
|
||||
stream->cdrom.cur_min = 0;
|
||||
stream->cdrom.cur_sec = 0;
|
||||
stream->cdrom.cur_frame = 0;
|
||||
stream->cdrom.cur_track = 0;
|
||||
stream->cdrom.cur_lba = 0;
|
||||
stream->cdrom.last_frame_lba = 0;
|
||||
stream->cdrom.last_frame[0] = '\0';
|
||||
stream->cdrom.last_frame_valid = false;
|
||||
|
||||
if (path_len > cdrom_prefix_len)
|
||||
{
|
||||
if (!memcmp(path, cdrom_prefix, cdrom_prefix_len))
|
||||
{
|
||||
path += cdrom_prefix_siz;
|
||||
stream->scheme = VFS_SCHEME_CDROM;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
stream->hints = hints;
|
||||
stream->orig_path = strdup(path);
|
||||
|
||||
#ifdef HAVE_MMAP
|
||||
@ -348,9 +361,7 @@ libretro_vfs_implementation_file *retro_vfs_file_open_impl(
|
||||
|
||||
flags = O_WRONLY | O_CREAT | O_TRUNC;
|
||||
#if !defined(ORBIS)
|
||||
#if defined(PS2)
|
||||
flags |= FIO_S_IRUSR | FIO_S_IWUSR;
|
||||
#elif !defined(_WIN32)
|
||||
#if !defined(_WIN32)
|
||||
flags |= S_IRUSR | S_IWUSR;
|
||||
#else
|
||||
flags |= O_BINARY;
|
||||
@ -362,9 +373,7 @@ libretro_vfs_implementation_file *retro_vfs_file_open_impl(
|
||||
mode_str = "w+b";
|
||||
flags = O_RDWR | O_CREAT | O_TRUNC;
|
||||
#if !defined(ORBIS)
|
||||
#if defined(PS2)
|
||||
flags |= FIO_S_IRUSR | FIO_S_IWUSR;
|
||||
#elif !defined(_WIN32)
|
||||
#if !defined(_WIN32)
|
||||
flags |= S_IRUSR | S_IWUSR;
|
||||
#else
|
||||
flags |= O_BINARY;
|
||||
@ -378,9 +387,7 @@ libretro_vfs_implementation_file *retro_vfs_file_open_impl(
|
||||
|
||||
flags = O_RDWR;
|
||||
#if !defined(ORBIS)
|
||||
#if defined(PS2)
|
||||
flags |= FIO_S_IRUSR | FIO_S_IWUSR;
|
||||
#elif !defined(_WIN32)
|
||||
#if !defined(_WIN32)
|
||||
flags |= S_IRUSR | S_IWUSR;
|
||||
#else
|
||||
flags |= O_BINARY;
|
||||
@ -401,7 +408,7 @@ libretro_vfs_implementation_file *retro_vfs_file_open_impl(
|
||||
stream->fd = -1;
|
||||
goto error;
|
||||
}
|
||||
stream->fd = fd;
|
||||
stream->fd = fd;
|
||||
#else
|
||||
FILE *fp;
|
||||
#ifdef HAVE_CDROM
|
||||
@ -430,13 +437,23 @@ libretro_vfs_implementation_file *retro_vfs_file_open_impl(
|
||||
*
|
||||
* https://www.freebsd.org/cgi/man.cgi?query=setvbuf&apropos=0&sektion=0&manpath=FreeBSD+11.1-RELEASE&arch=default&format=html
|
||||
*
|
||||
* If the size argument is not zero but buf is NULL, a buffer of the given size will be allocated immediately, and
|
||||
* If the size argument is not zero but buf is NULL,
|
||||
* a buffer of the given size will be allocated immediately, and
|
||||
* released on close. This is an extension to ANSI C.
|
||||
*
|
||||
* Since C89 does not support specifying a null buffer with a non-zero size, we create and track our own buffer for it.
|
||||
* Since C89 does not support specifying a NULL buffer
|
||||
* with a non-zero size, we create and track our own buffer for it.
|
||||
*/
|
||||
/* TODO: this is only useful for a few platforms, find which and add ifdef */
|
||||
#if !defined(PS2) && !defined(PSP)
|
||||
/* TODO: this is only useful for a few platforms,
|
||||
* find which and add ifdef */
|
||||
#if defined(_3DS)
|
||||
if (stream->scheme != VFS_SCHEME_CDROM)
|
||||
{
|
||||
stream->buf = (char*)calloc(1, 0x10000);
|
||||
if (stream->fp)
|
||||
setvbuf(stream->fp, stream->buf, _IOFBF, 0x10000);
|
||||
}
|
||||
#elif !defined(PSP)
|
||||
if (stream->scheme != VFS_SCHEME_CDROM)
|
||||
{
|
||||
stream->buf = (char*)calloc(1, 0x4000);
|
||||
@ -535,9 +552,7 @@ int retro_vfs_file_close_impl(libretro_vfs_implementation_file *stream)
|
||||
if ((stream->hints & RFILE_HINT_UNBUFFERED) == 0)
|
||||
{
|
||||
if (stream->fp)
|
||||
{
|
||||
fclose(stream->fp);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
@ -602,7 +617,7 @@ int64_t retro_vfs_file_truncate_impl(libretro_vfs_implementation_file *stream, i
|
||||
if (_chsize(_fileno(stream->fp), length) != 0)
|
||||
return -1;
|
||||
#elif !defined(VITA) && !defined(PSP) && !defined(PS2) && !defined(ORBIS) && (!defined(SWITCH) || defined(HAVE_LIBNX))
|
||||
if (ftruncate(fileno(stream->fp), length) != 0)
|
||||
if (ftruncate(fileno(stream->fp), (off_t)length) != 0)
|
||||
return -1;
|
||||
#endif
|
||||
|
||||
@ -628,9 +643,11 @@ int64_t retro_vfs_file_tell_impl(libretro_vfs_implementation_file *stream)
|
||||
return ret;
|
||||
}
|
||||
#else
|
||||
/* VC2005 and up have a special 64-bit ftell */
|
||||
#ifdef ATLEAST_VC2005
|
||||
/* VC2005 and up have a special 64-bit ftell */
|
||||
return _ftelli64(stream->fp);
|
||||
#elif defined(HAVE_64BIT_OFFSETS)
|
||||
return ftello(stream->fp);
|
||||
#else
|
||||
return ftell(stream->fp);
|
||||
#endif
|
||||
@ -639,7 +656,8 @@ int64_t retro_vfs_file_tell_impl(libretro_vfs_implementation_file *stream)
|
||||
#ifdef HAVE_MMAP
|
||||
/* Need to check stream->mapped because this function
|
||||
* is called in filestream_open() */
|
||||
if (stream->mapped && stream->hints & RETRO_VFS_FILE_ACCESS_HINT_FREQUENT_ACCESS)
|
||||
if (stream->mapped && stream->hints &
|
||||
RETRO_VFS_FILE_ACCESS_HINT_FREQUENT_ACCESS)
|
||||
return stream->mappos;
|
||||
#endif
|
||||
if (lseek(stream->fd, 0, SEEK_CUR) < 0)
|
||||
@ -863,12 +881,12 @@ const char *retro_vfs_file_get_path_impl(
|
||||
|
||||
int retro_vfs_stat_impl(const char *path, int32_t *size)
|
||||
{
|
||||
bool is_dir = false;
|
||||
bool is_character_special = false;
|
||||
#if defined(VITA) || defined(PSP)
|
||||
/* Vita / PSP */
|
||||
SceIoStat buf;
|
||||
int stat_ret;
|
||||
bool is_dir = false;
|
||||
bool is_character_special = false;
|
||||
int dir_ret;
|
||||
char *tmp = NULL;
|
||||
size_t len = 0;
|
||||
|
||||
@ -880,77 +898,32 @@ int retro_vfs_stat_impl(const char *path, int32_t *size)
|
||||
if (tmp[len-1] == '/')
|
||||
tmp[len-1] = '\0';
|
||||
|
||||
stat_ret = sceIoGetstat(tmp, &buf);
|
||||
dir_ret = sceIoGetstat(tmp, &buf);
|
||||
free(tmp);
|
||||
if (stat_ret < 0)
|
||||
if (dir_ret < 0)
|
||||
return 0;
|
||||
|
||||
if (size)
|
||||
*size = (int32_t)buf.st_size;
|
||||
|
||||
is_dir = FIO_S_ISDIR(buf.st_mode);
|
||||
|
||||
return RETRO_VFS_STAT_IS_VALID | (is_dir ? RETRO_VFS_STAT_IS_DIRECTORY : 0) | (is_character_special ? RETRO_VFS_STAT_IS_CHARACTER_SPECIAL : 0);
|
||||
*size = (int32_t)buf.st_size;
|
||||
|
||||
is_dir = FIO_S_ISDIR(buf.st_mode);
|
||||
#elif defined(ORBIS)
|
||||
/* Orbis */
|
||||
bool is_dir, is_character_special;
|
||||
int dir_ret;
|
||||
int dir_ret = 0;
|
||||
|
||||
if (!path || !*path)
|
||||
return 0;
|
||||
|
||||
if (size)
|
||||
*size = (int32_t)buf.st_size;
|
||||
*size = (int32_t)buf.st_size;
|
||||
|
||||
dir_ret = orbisDopen(path);
|
||||
is_dir = dir_ret > 0;
|
||||
dir_ret = orbisDopen(path);
|
||||
is_dir = dir_ret > 0;
|
||||
orbisDclose(dir_ret);
|
||||
|
||||
is_character_special = S_ISCHR(buf.st_mode);
|
||||
|
||||
return RETRO_VFS_STAT_IS_VALID | (is_dir ? RETRO_VFS_STAT_IS_DIRECTORY : 0) | (is_character_special ? RETRO_VFS_STAT_IS_CHARACTER_SPECIAL : 0);
|
||||
|
||||
#elif defined(PS2)
|
||||
/* PS2 */
|
||||
iox_stat_t buf;
|
||||
bool is_dir;
|
||||
bool is_character_special = false;
|
||||
char *tmp = NULL;
|
||||
size_t len = 0;
|
||||
|
||||
if (!path || !*path)
|
||||
return 0;
|
||||
|
||||
tmp = strdup(path);
|
||||
len = strlen(tmp);
|
||||
if (tmp[len-1] == '/')
|
||||
tmp[len-1] = '\0';
|
||||
|
||||
fileXioGetStat(tmp, &buf);
|
||||
free(tmp);
|
||||
|
||||
if (size)
|
||||
*size = (int32_t)buf.size;
|
||||
|
||||
if (!buf.mode)
|
||||
{
|
||||
/* if fileXioGetStat fails */
|
||||
int dir_ret = fileXioDopen(path);
|
||||
is_dir = dir_ret > 0;
|
||||
if (is_dir) {
|
||||
fileXioDclose(dir_ret);
|
||||
}
|
||||
}
|
||||
else
|
||||
is_dir = FIO_S_ISDIR(buf.mode);
|
||||
|
||||
return RETRO_VFS_STAT_IS_VALID | (is_dir ? RETRO_VFS_STAT_IS_DIRECTORY : 0) | (is_character_special ? RETRO_VFS_STAT_IS_CHARACTER_SPECIAL : 0);
|
||||
|
||||
#elif defined(__CELLOS_LV2__)
|
||||
is_character_special = S_ISCHR(buf.st_mode);
|
||||
#elif defined(__CELLOS_LV2__) && !defined(__PSL1GHT__)
|
||||
/* CellOS Lv2 */
|
||||
bool is_dir;
|
||||
bool is_character_special = false;
|
||||
CellFsStat buf;
|
||||
|
||||
if (!path || !*path)
|
||||
@ -959,18 +932,14 @@ int retro_vfs_stat_impl(const char *path, int32_t *size)
|
||||
return 0;
|
||||
|
||||
if (size)
|
||||
*size = (int32_t)buf.st_size;
|
||||
*size = (int32_t)buf.st_size;
|
||||
|
||||
is_dir = ((buf.st_mode & S_IFMT) == S_IFDIR);
|
||||
|
||||
return RETRO_VFS_STAT_IS_VALID | (is_dir ? RETRO_VFS_STAT_IS_DIRECTORY : 0) | (is_character_special ? RETRO_VFS_STAT_IS_CHARACTER_SPECIAL : 0);
|
||||
is_dir = ((buf.st_mode & S_IFMT) == S_IFDIR);
|
||||
|
||||
#elif defined(_WIN32)
|
||||
/* Windows */
|
||||
bool is_dir;
|
||||
DWORD file_info;
|
||||
struct _stat buf;
|
||||
bool is_character_special = false;
|
||||
#if defined(LEGACY_WIN32)
|
||||
char *path_local = NULL;
|
||||
#else
|
||||
@ -981,8 +950,8 @@ int retro_vfs_stat_impl(const char *path, int32_t *size)
|
||||
return 0;
|
||||
|
||||
#if defined(LEGACY_WIN32)
|
||||
path_local = utf8_to_local_string_alloc(path);
|
||||
file_info = GetFileAttributes(path_local);
|
||||
path_local = utf8_to_local_string_alloc(path);
|
||||
file_info = GetFileAttributes(path_local);
|
||||
|
||||
if (!string_is_empty(path_local))
|
||||
_stat(path_local, &buf);
|
||||
@ -990,8 +959,8 @@ int retro_vfs_stat_impl(const char *path, int32_t *size)
|
||||
if (path_local)
|
||||
free(path_local);
|
||||
#else
|
||||
path_wide = utf8_to_utf16_string_alloc(path);
|
||||
file_info = GetFileAttributesW(path_wide);
|
||||
path_wide = utf8_to_utf16_string_alloc(path);
|
||||
file_info = GetFileAttributesW(path_wide);
|
||||
|
||||
_wstat(path_wide, &buf);
|
||||
|
||||
@ -1007,11 +976,41 @@ int retro_vfs_stat_impl(const char *path, int32_t *size)
|
||||
|
||||
is_dir = (file_info & FILE_ATTRIBUTE_DIRECTORY);
|
||||
|
||||
return RETRO_VFS_STAT_IS_VALID | (is_dir ? RETRO_VFS_STAT_IS_DIRECTORY : 0) | (is_character_special ? RETRO_VFS_STAT_IS_CHARACTER_SPECIAL : 0);
|
||||
#elif defined(GEKKO)
|
||||
/* On GEKKO platforms, paths cannot have
|
||||
* trailing slashes - we must therefore
|
||||
* remove them */
|
||||
char *path_buf = NULL;
|
||||
int stat_ret = -1;
|
||||
struct stat stat_buf;
|
||||
size_t len;
|
||||
|
||||
if (string_is_empty(path))
|
||||
return 0;
|
||||
|
||||
path_buf = strdup(path);
|
||||
if (!path_buf)
|
||||
return 0;
|
||||
|
||||
len = strlen(path_buf);
|
||||
if (len > 0)
|
||||
if (path_buf[len - 1] == '/')
|
||||
path_buf[len - 1] = '\0';
|
||||
|
||||
stat_ret = stat(path_buf, &stat_buf);
|
||||
free(path_buf);
|
||||
|
||||
if (stat_ret < 0)
|
||||
return 0;
|
||||
|
||||
if (size)
|
||||
*size = (int32_t)stat_buf.st_size;
|
||||
|
||||
is_dir = S_ISDIR(stat_buf.st_mode);
|
||||
is_character_special = S_ISCHR(stat_buf.st_mode);
|
||||
|
||||
#else
|
||||
/* Every other platform */
|
||||
bool is_dir, is_character_special;
|
||||
struct stat buf;
|
||||
|
||||
if (!path || !*path)
|
||||
@ -1024,9 +1023,8 @@ int retro_vfs_stat_impl(const char *path, int32_t *size)
|
||||
|
||||
is_dir = S_ISDIR(buf.st_mode);
|
||||
is_character_special = S_ISCHR(buf.st_mode);
|
||||
|
||||
return RETRO_VFS_STAT_IS_VALID | (is_dir ? RETRO_VFS_STAT_IS_DIRECTORY : 0) | (is_character_special ? RETRO_VFS_STAT_IS_CHARACTER_SPECIAL : 0);
|
||||
#endif
|
||||
return RETRO_VFS_STAT_IS_VALID | (is_dir ? RETRO_VFS_STAT_IS_DIRECTORY : 0) | (is_character_special ? RETRO_VFS_STAT_IS_CHARACTER_SPECIAL : 0);
|
||||
}
|
||||
|
||||
#if defined(VITA)
|
||||
@ -1041,27 +1039,47 @@ int retro_vfs_mkdir_impl(const char *dir)
|
||||
{
|
||||
#if defined(_WIN32)
|
||||
#ifdef LEGACY_WIN32
|
||||
int ret = _mkdir(dir);
|
||||
int ret = _mkdir(dir);
|
||||
#else
|
||||
wchar_t *dirW = utf8_to_utf16_string_alloc(dir);
|
||||
int ret = -1;
|
||||
wchar_t *dir_w = utf8_to_utf16_string_alloc(dir);
|
||||
int ret = -1;
|
||||
|
||||
if (dirW)
|
||||
if (dir_w)
|
||||
{
|
||||
ret = _wmkdir(dirW);
|
||||
free(dirW);
|
||||
ret = _wmkdir(dir_w);
|
||||
free(dir_w);
|
||||
}
|
||||
#endif
|
||||
#elif defined(IOS)
|
||||
int ret = mkdir(dir, 0755);
|
||||
#elif defined(VITA) || defined(PSP)
|
||||
int ret = sceIoMkdir(dir, 0777);
|
||||
#elif defined(PS2)
|
||||
int ret = fileXioMkdir(dir, 0777);
|
||||
#elif defined(ORBIS)
|
||||
int ret = orbisMkdir(dir, 0755);
|
||||
#elif defined(__QNX__)
|
||||
int ret = mkdir(dir, 0777);
|
||||
#elif defined(GEKKO)
|
||||
/* On GEKKO platforms, mkdir() fails if
|
||||
* the path has a trailing slash. We must
|
||||
* therefore remove it. */
|
||||
int ret = -1;
|
||||
if (!string_is_empty(dir))
|
||||
{
|
||||
char *dir_buf = strdup(dir);
|
||||
|
||||
if (dir_buf)
|
||||
{
|
||||
size_t len = strlen(dir_buf);
|
||||
|
||||
if (len > 0)
|
||||
if (dir_buf[len - 1] == '/')
|
||||
dir_buf[len - 1] = '\0';
|
||||
|
||||
ret = mkdir(dir_buf, 0750);
|
||||
|
||||
free(dir_buf);
|
||||
}
|
||||
}
|
||||
#else
|
||||
int ret = mkdir(dir, 0750);
|
||||
#endif
|
||||
@ -1090,10 +1108,7 @@ struct libretro_vfs_implementation_dir
|
||||
#elif defined(VITA) || defined(PSP)
|
||||
SceUID directory;
|
||||
SceIoDirent entry;
|
||||
#elif defined(PS2)
|
||||
int directory;
|
||||
iox_dirent_t entry;
|
||||
#elif defined(__CELLOS_LV2__)
|
||||
#elif defined(__CELLOS_LV2__) && !defined(__PSL1GHT__)
|
||||
CellFsErrno error;
|
||||
int directory;
|
||||
CellFsDirent entry;
|
||||
@ -1110,9 +1125,9 @@ static bool dirent_check_error(libretro_vfs_implementation_dir *rdir)
|
||||
{
|
||||
#if defined(_WIN32)
|
||||
return (rdir->directory == INVALID_HANDLE_VALUE);
|
||||
#elif defined(VITA) || defined(PSP) || defined(PS2) || defined(ORBIS)
|
||||
#elif defined(VITA) || defined(PSP) || defined(ORBIS)
|
||||
return (rdir->directory < 0);
|
||||
#elif defined(__CELLOS_LV2__)
|
||||
#elif defined(__CELLOS_LV2__) && !defined(__PSL1GHT__)
|
||||
return (rdir->error != CELL_FS_SUCCEEDED);
|
||||
#else
|
||||
return !(rdir->directory);
|
||||
@ -1174,12 +1189,10 @@ libretro_vfs_implementation_dir *retro_vfs_opendir_impl(
|
||||
|
||||
#elif defined(VITA) || defined(PSP)
|
||||
rdir->directory = sceIoDopen(name);
|
||||
#elif defined(PS2)
|
||||
rdir->directory = ps2fileXioDopen(name);
|
||||
#elif defined(_3DS)
|
||||
rdir->directory = !string_is_empty(name) ? opendir(name) : NULL;
|
||||
rdir->entry = NULL;
|
||||
#elif defined(__CELLOS_LV2__)
|
||||
#elif defined(__CELLOS_LV2__) && !defined(__PSL1GHT__)
|
||||
rdir->error = cellFsOpendir(name, &rdir->directory);
|
||||
#elif defined(ORBIS)
|
||||
rdir->directory = orbisDopen(name);
|
||||
@ -1216,12 +1229,7 @@ bool retro_vfs_readdir_impl(libretro_vfs_implementation_dir *rdir)
|
||||
return (rdir->directory != INVALID_HANDLE_VALUE);
|
||||
#elif defined(VITA) || defined(PSP)
|
||||
return (sceIoDread(rdir->directory, &rdir->entry) > 0);
|
||||
#elif defined(PS2)
|
||||
iox_dirent_t record;
|
||||
int ret = ps2fileXioDread(rdir->directory, &record);
|
||||
rdir->entry = record;
|
||||
return ( ret > 0);
|
||||
#elif defined(__CELLOS_LV2__)
|
||||
#elif defined(__CELLOS_LV2__) && !defined(__PSL1GHT__)
|
||||
uint64_t nread;
|
||||
rdir->error = cellFsReaddir(rdir->directory, &rdir->entry, &nread);
|
||||
return (nread != 0);
|
||||
@ -1236,29 +1244,17 @@ const char *retro_vfs_dirent_get_name_impl(libretro_vfs_implementation_dir *rdir
|
||||
{
|
||||
#if defined(_WIN32)
|
||||
#if defined(LEGACY_WIN32)
|
||||
{
|
||||
char *name_local = local_to_utf8_string_alloc(rdir->entry.cFileName);
|
||||
memset(rdir->entry.cFileName, 0, sizeof(rdir->entry.cFileName));
|
||||
strlcpy(rdir->entry.cFileName, name_local, sizeof(rdir->entry.cFileName));
|
||||
|
||||
if (name_local)
|
||||
free(name_local);
|
||||
}
|
||||
char *name = local_to_utf8_string_alloc(rdir->entry.cFileName);
|
||||
#else
|
||||
{
|
||||
char *name = utf16_to_utf8_string_alloc(rdir->entry.cFileName);
|
||||
memset(rdir->entry.cFileName, 0, sizeof(rdir->entry.cFileName));
|
||||
strlcpy((char*)rdir->entry.cFileName, name, sizeof(rdir->entry.cFileName));
|
||||
|
||||
if (name)
|
||||
free(name);
|
||||
}
|
||||
char *name = utf16_to_utf8_string_alloc(rdir->entry.cFileName);
|
||||
#endif
|
||||
memset(rdir->entry.cFileName, 0, sizeof(rdir->entry.cFileName));
|
||||
strlcpy((char*)rdir->entry.cFileName, name, sizeof(rdir->entry.cFileName));
|
||||
if (name)
|
||||
free(name);
|
||||
return (char*)rdir->entry.cFileName;
|
||||
#elif defined(VITA) || defined(PSP) || defined(__CELLOS_LV2__) || defined(ORBIS)
|
||||
#elif defined(VITA) || defined(PSP) || defined(__CELLOS_LV2__) && !defined(__PSL1GHT__) || defined(ORBIS)
|
||||
return rdir->entry.d_name;
|
||||
#elif defined(PS2)
|
||||
return rdir->entry.name;
|
||||
#else
|
||||
if (!rdir || !rdir->entry)
|
||||
return NULL;
|
||||
@ -1272,20 +1268,17 @@ bool retro_vfs_dirent_is_dir_impl(libretro_vfs_implementation_dir *rdir)
|
||||
const WIN32_FIND_DATA *entry = (const WIN32_FIND_DATA*)&rdir->entry;
|
||||
return entry->dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY;
|
||||
#elif defined(PSP) || defined(VITA)
|
||||
const SceIoDirent *entry = (const SceIoDirent*)&rdir->entry;
|
||||
const SceIoDirent *entry = (const SceIoDirent*)&rdir->entry;
|
||||
#if defined(PSP)
|
||||
return (entry->d_stat.st_attr & FIO_SO_IFDIR) == FIO_SO_IFDIR;
|
||||
#elif defined(VITA)
|
||||
return SCE_S_ISDIR(entry->d_stat.st_mode);
|
||||
#endif
|
||||
#elif defined(PS2)
|
||||
const iox_dirent_t *entry = (const iox_dirent_t*)&rdir->entry;
|
||||
return FIO_S_ISDIR(entry->stat.mode);
|
||||
#elif defined(__CELLOS_LV2__)
|
||||
CellFsDirent *entry = (CellFsDirent*)&rdir->entry;
|
||||
#elif defined(__CELLOS_LV2__) && !defined(__PSL1GHT__)
|
||||
CellFsDirent *entry = (CellFsDirent*)&rdir->entry;
|
||||
return (entry->d_type == CELL_FS_TYPE_DIRECTORY);
|
||||
#elif defined(ORBIS)
|
||||
const struct dirent *entry = &rdir->entry;
|
||||
const struct dirent *entry = &rdir->entry;
|
||||
if (entry->d_type == DT_DIR)
|
||||
return true;
|
||||
if (!(entry->d_type == DT_UNKNOWN || entry->d_type == DT_LNK))
|
||||
@ -1320,9 +1313,7 @@ int retro_vfs_closedir_impl(libretro_vfs_implementation_dir *rdir)
|
||||
FindClose(rdir->directory);
|
||||
#elif defined(VITA) || defined(PSP)
|
||||
sceIoDclose(rdir->directory);
|
||||
#elif defined(PS2)
|
||||
ps2fileXioDclose(rdir->directory);
|
||||
#elif defined(__CELLOS_LV2__)
|
||||
#elif defined(__CELLOS_LV2__) && !defined(__PSL1GHT__)
|
||||
rdir->error = cellFsClosedir(rdir->directory);
|
||||
#elif defined(ORBIS)
|
||||
orbisDclose(rdir->directory);
|
||||
|
@ -1,4 +1,4 @@
|
||||
/* Copyright (C) 2010-2019 The RetroArch team
|
||||
/* Copyright (C) 2010-2020 The RetroArch team
|
||||
*
|
||||
* ---------------------------------------------------------------------------------------
|
||||
* The following license statement only applies to this file (vfs_implementation_cdrom.c).
|
||||
@ -30,6 +30,7 @@
|
||||
#include <windows.h>
|
||||
#endif
|
||||
|
||||
/* TODO/FIXME - static global variable */
|
||||
static cdrom_toc_t vfs_cdrom_toc = {0};
|
||||
|
||||
const cdrom_toc_t* retro_vfs_file_get_cdrom_toc(void)
|
||||
@ -37,7 +38,9 @@ const cdrom_toc_t* retro_vfs_file_get_cdrom_toc(void)
|
||||
return &vfs_cdrom_toc;
|
||||
}
|
||||
|
||||
int64_t retro_vfs_file_seek_cdrom(libretro_vfs_implementation_file *stream, int64_t offset, int whence)
|
||||
int64_t retro_vfs_file_seek_cdrom(
|
||||
libretro_vfs_implementation_file *stream,
|
||||
int64_t offset, int whence)
|
||||
{
|
||||
const char *ext = path_get_extension(stream->orig_path);
|
||||
|
||||
@ -52,68 +55,84 @@ int64_t retro_vfs_file_seek_cdrom(libretro_vfs_implementation_file *stream, int6
|
||||
stream->cdrom.byte_pos += offset;
|
||||
break;
|
||||
case SEEK_END:
|
||||
stream->cdrom.byte_pos = (stream->cdrom.cue_len - 1) + offset;
|
||||
stream->cdrom.byte_pos = (stream->cdrom.cue_len - 1) + offset;
|
||||
break;
|
||||
}
|
||||
|
||||
#ifdef CDROM_DEBUG
|
||||
printf("[CDROM] Seek: Path %s Offset %" PRIu64 " is now at %" PRIu64 "\n", stream->orig_path, offset, stream->cdrom.byte_pos);
|
||||
printf("[CDROM] Seek: Path %s Offset %" PRIu64 " is now at %" PRIu64 "\n",
|
||||
stream->orig_path,
|
||||
offset,
|
||||
stream->cdrom.byte_pos);
|
||||
fflush(stdout);
|
||||
#endif
|
||||
}
|
||||
else if (string_is_equal_noncase(ext, "bin"))
|
||||
{
|
||||
int lba = (offset / 2352);
|
||||
unsigned char min = 0;
|
||||
unsigned char sec = 0;
|
||||
unsigned char frame = 0;
|
||||
int lba = (offset / 2352);
|
||||
unsigned char min = 0;
|
||||
unsigned char sec = 0;
|
||||
unsigned char frame = 0;
|
||||
#ifdef CDROM_DEBUG
|
||||
const char *seek_type = "SEEK_SET";
|
||||
|
||||
(void)seek_type;
|
||||
#endif
|
||||
|
||||
switch (whence)
|
||||
{
|
||||
case SEEK_CUR:
|
||||
{
|
||||
unsigned new_lba;
|
||||
|
||||
stream->cdrom.byte_pos += offset;
|
||||
new_lba = vfs_cdrom_toc.track[stream->cdrom.cur_track - 1].lba + (stream->cdrom.byte_pos / 2352);
|
||||
seek_type = "SEEK_CUR";
|
||||
|
||||
cdrom_lba_to_msf(new_lba, &min, &sec, &frame);
|
||||
{
|
||||
unsigned new_lba;
|
||||
#ifdef CDROM_DEBUG
|
||||
seek_type = "SEEK_CUR";
|
||||
#endif
|
||||
stream->cdrom.byte_pos += offset;
|
||||
new_lba = vfs_cdrom_toc.track[stream->cdrom.cur_track - 1].lba + (stream->cdrom.byte_pos / 2352);
|
||||
|
||||
cdrom_lba_to_msf(new_lba, &min, &sec, &frame);
|
||||
}
|
||||
break;
|
||||
}
|
||||
case SEEK_END:
|
||||
{
|
||||
ssize_t pregap_lba_len = (vfs_cdrom_toc.track[stream->cdrom.cur_track - 1].audio ? 0 : (vfs_cdrom_toc.track[stream->cdrom.cur_track - 1].lba - vfs_cdrom_toc.track[stream->cdrom.cur_track - 1].lba_start));
|
||||
ssize_t lba_len = vfs_cdrom_toc.track[stream->cdrom.cur_track - 1].track_size - pregap_lba_len;
|
||||
|
||||
cdrom_lba_to_msf(lba_len + lba, &min, &sec, &frame);
|
||||
|
||||
stream->cdrom.byte_pos = lba_len * 2352;
|
||||
seek_type = "SEEK_END";
|
||||
{
|
||||
ssize_t pregap_lba_len = (vfs_cdrom_toc.track[stream->cdrom.cur_track - 1].audio
|
||||
? 0
|
||||
: (vfs_cdrom_toc.track[stream->cdrom.cur_track - 1].lba - vfs_cdrom_toc.track[stream->cdrom.cur_track - 1].lba_start));
|
||||
ssize_t lba_len = vfs_cdrom_toc.track[stream->cdrom.cur_track - 1].track_size - pregap_lba_len;
|
||||
#ifdef CDROM_DEBUG
|
||||
seek_type = "SEEK_END";
|
||||
#endif
|
||||
|
||||
cdrom_lba_to_msf(lba_len + lba, &min, &sec, &frame);
|
||||
stream->cdrom.byte_pos = lba_len * 2352;
|
||||
}
|
||||
break;
|
||||
}
|
||||
case SEEK_SET:
|
||||
default:
|
||||
{
|
||||
seek_type = "SEEK_SET";
|
||||
stream->cdrom.byte_pos = offset;
|
||||
cdrom_lba_to_msf(vfs_cdrom_toc.track[stream->cdrom.cur_track - 1].lba + (stream->cdrom.byte_pos / 2352), &min, &sec, &frame);
|
||||
{
|
||||
#ifdef CDROM_DEBUG
|
||||
seek_type = "SEEK_SET";
|
||||
#endif
|
||||
stream->cdrom.byte_pos = offset;
|
||||
cdrom_lba_to_msf(vfs_cdrom_toc.track[stream->cdrom.cur_track - 1].lba + (stream->cdrom.byte_pos / 2352), &min, &sec, &frame);
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
stream->cdrom.cur_min = min;
|
||||
stream->cdrom.cur_sec = sec;
|
||||
stream->cdrom.cur_min = min;
|
||||
stream->cdrom.cur_sec = sec;
|
||||
stream->cdrom.cur_frame = frame;
|
||||
stream->cdrom.cur_lba = cdrom_msf_to_lba(min, sec, frame);
|
||||
stream->cdrom.cur_lba = cdrom_msf_to_lba(min, sec, frame);
|
||||
|
||||
#ifdef CDROM_DEBUG
|
||||
printf("[CDROM] Seek %s: Path %s Offset %" PRIu64 " is now at %" PRIu64 " (MSF %02u:%02u:%02u) (LBA %u)...\n", seek_type, stream->orig_path, offset, stream->cdrom.byte_pos, (unsigned)stream->cdrom.cur_min, (unsigned)stream->cdrom.cur_sec, (unsigned)stream->cdrom.cur_frame, stream->cdrom.cur_lba);
|
||||
printf(
|
||||
"[CDROM] Seek %s: Path %s Offset %" PRIu64 " is now at %" PRIu64 " (MSF %02u:%02u:%02u) (LBA %u)...\n",
|
||||
seek_type,
|
||||
stream->orig_path,
|
||||
offset,
|
||||
stream->cdrom.byte_pos,
|
||||
(unsigned)stream->cdrom.cur_min,
|
||||
(unsigned)stream->cdrom.cur_sec,
|
||||
(unsigned)stream->cdrom.cur_frame,
|
||||
stream->cdrom.cur_lba);
|
||||
fflush(stdout);
|
||||
#endif
|
||||
}
|
||||
@ -128,20 +147,21 @@ void retro_vfs_file_open_cdrom(
|
||||
const char *path, unsigned mode, unsigned hints)
|
||||
{
|
||||
#if defined(__linux__) && !defined(ANDROID)
|
||||
char cdrom_path[] = "/dev/sg1";
|
||||
size_t path_len = strlen(path);
|
||||
const char *ext = path_get_extension(path);
|
||||
char cdrom_path[] = "/dev/sg1";
|
||||
size_t path_len = strlen(path);
|
||||
const char *ext = path_get_extension(path);
|
||||
|
||||
stream->cdrom.cur_track = 1;
|
||||
|
||||
if (!string_is_equal_noncase(ext, "cue") && !string_is_equal_noncase(ext, "bin"))
|
||||
if ( !string_is_equal_noncase(ext, "cue")
|
||||
&& !string_is_equal_noncase(ext, "bin"))
|
||||
return;
|
||||
|
||||
if (path_len >= strlen("drive1-track01.bin"))
|
||||
if (path_len >= STRLEN_CONST("drive1-track01.bin"))
|
||||
{
|
||||
if (!memcmp(path, "drive", strlen("drive")))
|
||||
if (!memcmp(path, "drive", STRLEN_CONST("drive")))
|
||||
{
|
||||
if (!memcmp(path + 6, "-track", strlen("-track")))
|
||||
if (!memcmp(path + 6, "-track", STRLEN_CONST("-track")))
|
||||
{
|
||||
if (sscanf(path + 12, "%02u", (unsigned*)&stream->cdrom.cur_track))
|
||||
{
|
||||
@ -154,13 +174,13 @@ void retro_vfs_file_open_cdrom(
|
||||
}
|
||||
}
|
||||
|
||||
if (path_len >= strlen("drive1.cue"))
|
||||
if (path_len >= STRLEN_CONST("drive1.cue"))
|
||||
{
|
||||
if (!memcmp(path, "drive", strlen("drive")))
|
||||
if (!memcmp(path, "drive", STRLEN_CONST("drive")))
|
||||
{
|
||||
if (path[5] >= '0' && path[5] <= '9')
|
||||
{
|
||||
cdrom_path[7] = path[5];
|
||||
cdrom_path[7] = path[5];
|
||||
stream->cdrom.drive = path[5];
|
||||
vfs_cdrom_toc.drive = stream->cdrom.drive;
|
||||
}
|
||||
@ -184,7 +204,12 @@ void retro_vfs_file_open_cdrom(
|
||||
stream->cdrom.cue_buf = NULL;
|
||||
}
|
||||
|
||||
cdrom_write_cue(stream, &stream->cdrom.cue_buf, &stream->cdrom.cue_len, stream->cdrom.drive, &vfs_cdrom_toc.num_tracks, &vfs_cdrom_toc);
|
||||
cdrom_write_cue(stream,
|
||||
&stream->cdrom.cue_buf,
|
||||
&stream->cdrom.cue_len,
|
||||
stream->cdrom.drive,
|
||||
&vfs_cdrom_toc.num_tracks,
|
||||
&vfs_cdrom_toc);
|
||||
cdrom_get_timeouts(stream, &vfs_cdrom_toc.timeouts);
|
||||
|
||||
#ifdef CDROM_DEBUG
|
||||
@ -203,15 +228,16 @@ void retro_vfs_file_open_cdrom(
|
||||
#endif
|
||||
#if defined(_WIN32) && !defined(_XBOX)
|
||||
char cdrom_path[] = "\\\\.\\D:";
|
||||
size_t path_len = strlen(path);
|
||||
const char *ext = path_get_extension(path);
|
||||
size_t path_len = strlen(path);
|
||||
const char *ext = path_get_extension(path);
|
||||
|
||||
if (!string_is_equal_noncase(ext, "cue") && !string_is_equal_noncase(ext, "bin"))
|
||||
if ( !string_is_equal_noncase(ext, "cue")
|
||||
&& !string_is_equal_noncase(ext, "bin"))
|
||||
return;
|
||||
|
||||
if (path_len >= strlen("d:/drive-track01.bin"))
|
||||
if (path_len >= STRLEN_CONST("d:/drive-track01.bin"))
|
||||
{
|
||||
if (!memcmp(path + 1, ":/drive-track", strlen(":/drive-track")))
|
||||
if (!memcmp(path + 1, ":/drive-track", STRLEN_CONST(":/drive-track")))
|
||||
{
|
||||
if (sscanf(path + 14, "%02u", (unsigned*)&stream->cdrom.cur_track))
|
||||
{
|
||||
@ -223,13 +249,13 @@ void retro_vfs_file_open_cdrom(
|
||||
}
|
||||
}
|
||||
|
||||
if (path_len >= strlen("d:/drive.cue"))
|
||||
if (path_len >= STRLEN_CONST("d:/drive.cue"))
|
||||
{
|
||||
if (!memcmp(path + 1, ":/drive", strlen(":/drive")))
|
||||
if (!memcmp(path + 1, ":/drive", STRLEN_CONST(":/drive")))
|
||||
{
|
||||
if ((path[0] >= 'A' && path[0] <= 'Z') || (path[0] >= 'a' && path[0] <= 'z'))
|
||||
{
|
||||
cdrom_path[4] = path[0];
|
||||
cdrom_path[4] = path[0];
|
||||
stream->cdrom.drive = path[0];
|
||||
vfs_cdrom_toc.drive = stream->cdrom.drive;
|
||||
}
|
||||
@ -240,7 +266,13 @@ void retro_vfs_file_open_cdrom(
|
||||
printf("[CDROM] Open: Path %s URI %s\n", cdrom_path, path);
|
||||
fflush(stdout);
|
||||
#endif
|
||||
stream->fh = CreateFile(cdrom_path, GENERIC_READ | GENERIC_WRITE, FILE_SHARE_READ | FILE_SHARE_WRITE, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
|
||||
stream->fh = CreateFile(cdrom_path,
|
||||
GENERIC_READ | GENERIC_WRITE,
|
||||
FILE_SHARE_READ | FILE_SHARE_WRITE,
|
||||
NULL,
|
||||
OPEN_EXISTING,
|
||||
FILE_ATTRIBUTE_NORMAL,
|
||||
NULL);
|
||||
|
||||
if (stream->fh == INVALID_HANDLE_VALUE)
|
||||
return;
|
||||
@ -253,8 +285,14 @@ void retro_vfs_file_open_cdrom(
|
||||
stream->cdrom.cue_buf = NULL;
|
||||
}
|
||||
|
||||
cdrom_write_cue(stream, &stream->cdrom.cue_buf, &stream->cdrom.cue_len, stream->cdrom.drive, &vfs_cdrom_toc.num_tracks, &vfs_cdrom_toc);
|
||||
cdrom_get_timeouts(stream, &vfs_cdrom_toc.timeouts);
|
||||
cdrom_write_cue(stream,
|
||||
&stream->cdrom.cue_buf,
|
||||
&stream->cdrom.cue_len,
|
||||
stream->cdrom.drive,
|
||||
&vfs_cdrom_toc.num_tracks,
|
||||
&vfs_cdrom_toc);
|
||||
cdrom_get_timeouts(stream,
|
||||
&vfs_cdrom_toc.timeouts);
|
||||
|
||||
#ifdef CDROM_DEBUG
|
||||
if (string_is_empty(stream->cdrom.cue_buf))
|
||||
@ -272,17 +310,17 @@ void retro_vfs_file_open_cdrom(
|
||||
#endif
|
||||
if (vfs_cdrom_toc.num_tracks > 1 && stream->cdrom.cur_track)
|
||||
{
|
||||
stream->cdrom.cur_min = vfs_cdrom_toc.track[stream->cdrom.cur_track - 1].min;
|
||||
stream->cdrom.cur_sec = vfs_cdrom_toc.track[stream->cdrom.cur_track - 1].sec;
|
||||
stream->cdrom.cur_min = vfs_cdrom_toc.track[stream->cdrom.cur_track - 1].min;
|
||||
stream->cdrom.cur_sec = vfs_cdrom_toc.track[stream->cdrom.cur_track - 1].sec;
|
||||
stream->cdrom.cur_frame = vfs_cdrom_toc.track[stream->cdrom.cur_track - 1].frame;
|
||||
stream->cdrom.cur_lba = cdrom_msf_to_lba(stream->cdrom.cur_min, stream->cdrom.cur_sec, stream->cdrom.cur_frame);
|
||||
stream->cdrom.cur_lba = cdrom_msf_to_lba(stream->cdrom.cur_min, stream->cdrom.cur_sec, stream->cdrom.cur_frame);
|
||||
}
|
||||
else
|
||||
{
|
||||
stream->cdrom.cur_min = vfs_cdrom_toc.track[0].min;
|
||||
stream->cdrom.cur_sec = vfs_cdrom_toc.track[0].sec;
|
||||
stream->cdrom.cur_min = vfs_cdrom_toc.track[0].min;
|
||||
stream->cdrom.cur_sec = vfs_cdrom_toc.track[0].sec;
|
||||
stream->cdrom.cur_frame = vfs_cdrom_toc.track[0].frame;
|
||||
stream->cdrom.cur_lba = cdrom_msf_to_lba(stream->cdrom.cur_min, stream->cdrom.cur_sec, stream->cdrom.cur_frame);
|
||||
stream->cdrom.cur_lba = cdrom_msf_to_lba(stream->cdrom.cur_min, stream->cdrom.cur_sec, stream->cdrom.cur_frame);
|
||||
}
|
||||
}
|
||||
|
||||
@ -340,52 +378,69 @@ int64_t retro_vfs_file_read_cdrom(libretro_vfs_implementation_file *stream,
|
||||
|
||||
if (string_is_equal_noncase(ext, "cue"))
|
||||
{
|
||||
if ((int64_t)len < (int64_t)stream->cdrom.cue_len - stream->cdrom.byte_pos)
|
||||
{
|
||||
if ((int64_t)len >= (int64_t)stream->cdrom.cue_len
|
||||
- stream->cdrom.byte_pos)
|
||||
len = stream->cdrom.cue_len - stream->cdrom.byte_pos - 1;
|
||||
#ifdef CDROM_DEBUG
|
||||
printf("[CDROM] Read: Reading %" PRIu64 " bytes from cuesheet starting at %" PRIu64 "...\n", len, stream->cdrom.byte_pos);
|
||||
fflush(stdout);
|
||||
printf(
|
||||
"[CDROM] Read: Reading %" PRIu64 " bytes from cuesheet starting at %" PRIu64 "...\n",
|
||||
len,
|
||||
stream->cdrom.byte_pos);
|
||||
fflush(stdout);
|
||||
#endif
|
||||
memcpy(s, stream->cdrom.cue_buf + stream->cdrom.byte_pos, len);
|
||||
stream->cdrom.byte_pos += len;
|
||||
memcpy(s, stream->cdrom.cue_buf + stream->cdrom.byte_pos, len);
|
||||
stream->cdrom.byte_pos += len;
|
||||
|
||||
return len;
|
||||
}
|
||||
else
|
||||
{
|
||||
#ifdef CDROM_DEBUG
|
||||
printf("[CDROM] Read: Reading %" PRIu64 " bytes from cuesheet starting at %" PRIu64 " failed.\n", len, stream->cdrom.byte_pos);
|
||||
fflush(stdout);
|
||||
#endif
|
||||
return 0;
|
||||
}
|
||||
return len;
|
||||
}
|
||||
else if (string_is_equal_noncase(ext, "bin"))
|
||||
{
|
||||
size_t skip = stream->cdrom.byte_pos % 2352;
|
||||
unsigned char min = 0;
|
||||
unsigned char sec = 0;
|
||||
unsigned char frame = 0;
|
||||
unsigned char rmin = 0;
|
||||
unsigned char rsec = 0;
|
||||
unsigned char min = 0;
|
||||
unsigned char sec = 0;
|
||||
unsigned char frame = 0;
|
||||
unsigned char rmin = 0;
|
||||
unsigned char rsec = 0;
|
||||
unsigned char rframe = 0;
|
||||
size_t skip = stream->cdrom.byte_pos % 2352;
|
||||
|
||||
if (stream->cdrom.byte_pos >= vfs_cdrom_toc.track[stream->cdrom.cur_track - 1].track_bytes)
|
||||
if (stream->cdrom.byte_pos >=
|
||||
vfs_cdrom_toc.track[stream->cdrom.cur_track - 1].track_bytes)
|
||||
return 0;
|
||||
|
||||
if (stream->cdrom.byte_pos + len > vfs_cdrom_toc.track[stream->cdrom.cur_track - 1].track_bytes)
|
||||
len -= (stream->cdrom.byte_pos + len) - vfs_cdrom_toc.track[stream->cdrom.cur_track - 1].track_bytes;
|
||||
if (stream->cdrom.byte_pos + len >
|
||||
vfs_cdrom_toc.track[stream->cdrom.cur_track - 1].track_bytes)
|
||||
len -= (stream->cdrom.byte_pos + len)
|
||||
- vfs_cdrom_toc.track[stream->cdrom.cur_track - 1].track_bytes;
|
||||
|
||||
cdrom_lba_to_msf(stream->cdrom.cur_lba, &min, &sec, &frame);
|
||||
cdrom_lba_to_msf(stream->cdrom.cur_lba - vfs_cdrom_toc.track[stream->cdrom.cur_track - 1].lba, &rmin, &rsec, &rframe);
|
||||
cdrom_lba_to_msf(stream->cdrom.cur_lba
|
||||
- vfs_cdrom_toc.track[stream->cdrom.cur_track - 1].lba,
|
||||
&rmin, &rsec, &rframe);
|
||||
|
||||
#ifdef CDROM_DEBUG
|
||||
printf("[CDROM] Read: Reading %" PRIu64 " bytes from %s starting at byte offset %" PRIu64 " (rMSF %02u:%02u:%02u aMSF %02u:%02u:%02u) (LBA %u) skip %" PRIu64 "...\n", len, stream->orig_path, stream->cdrom.byte_pos, (unsigned)rmin, (unsigned)rsec, (unsigned)rframe, (unsigned)min, (unsigned)sec, (unsigned)frame, stream->cdrom.cur_lba, skip);
|
||||
printf(
|
||||
"[CDROM] Read: Reading %" PRIu64 " bytes from %s starting at byte offset %" PRIu64 " (rMSF %02u:%02u:%02u aMSF %02u:%02u:%02u) (LBA %u) skip %" PRIu64 "...\n",
|
||||
len,
|
||||
stream->orig_path,
|
||||
stream->cdrom.byte_pos,
|
||||
(unsigned)rmin,
|
||||
(unsigned)rsec,
|
||||
(unsigned)rframe,
|
||||
(unsigned)min,
|
||||
(unsigned)sec,
|
||||
(unsigned)frame,
|
||||
stream->cdrom.cur_lba,
|
||||
skip);
|
||||
fflush(stdout);
|
||||
#endif
|
||||
|
||||
rv = cdrom_read(stream, &vfs_cdrom_toc.timeouts, min, sec, frame, s, (size_t)len, skip);
|
||||
/*rv = cdrom_read_lba(stream, stream->cdrom.cur_lba, s, (size_t)len, skip);*/
|
||||
#if 1
|
||||
rv = cdrom_read(stream, &vfs_cdrom_toc.timeouts, min, sec,
|
||||
frame, s, (size_t)len, skip);
|
||||
#else
|
||||
rv = cdrom_read_lba(stream, stream->cdrom.cur_lba, s,
|
||||
(size_t)len, skip);
|
||||
#endif
|
||||
|
||||
if (rv)
|
||||
{
|
||||
@ -397,12 +452,28 @@ int64_t retro_vfs_file_read_cdrom(libretro_vfs_implementation_file *stream,
|
||||
}
|
||||
|
||||
stream->cdrom.byte_pos += len;
|
||||
stream->cdrom.cur_lba = vfs_cdrom_toc.track[stream->cdrom.cur_track - 1].lba + (stream->cdrom.byte_pos / 2352);
|
||||
stream->cdrom.cur_lba =
|
||||
vfs_cdrom_toc.track[stream->cdrom.cur_track - 1].lba
|
||||
+ (stream->cdrom.byte_pos / 2352);
|
||||
|
||||
cdrom_lba_to_msf(stream->cdrom.cur_lba, &stream->cdrom.cur_min, &stream->cdrom.cur_sec, &stream->cdrom.cur_frame);
|
||||
cdrom_lba_to_msf(stream->cdrom.cur_lba,
|
||||
&stream->cdrom.cur_min,
|
||||
&stream->cdrom.cur_sec,
|
||||
&stream->cdrom.cur_frame);
|
||||
|
||||
#ifdef CDROM_DEBUG
|
||||
printf("[CDROM] read %" PRIu64 " bytes, position is now: %" PRIu64 " (MSF %02u:%02u:%02u) (LBA %u)\n", len, stream->cdrom.byte_pos, (unsigned)stream->cdrom.cur_min, (unsigned)stream->cdrom.cur_sec, (unsigned)stream->cdrom.cur_frame, cdrom_msf_to_lba(stream->cdrom.cur_min, stream->cdrom.cur_sec, stream->cdrom.cur_frame));
|
||||
printf(
|
||||
"[CDROM] read %" PRIu64 " bytes, position is now: %" PRIu64 " (MSF %02u:%02u:%02u) (LBA %u)\n",
|
||||
len,
|
||||
stream->cdrom.byte_pos,
|
||||
(unsigned)stream->cdrom.cur_min,
|
||||
(unsigned)stream->cdrom.cur_sec,
|
||||
(unsigned)stream->cdrom.cur_frame,
|
||||
cdrom_msf_to_lba(
|
||||
stream->cdrom.cur_min,
|
||||
stream->cdrom.cur_sec,
|
||||
stream->cdrom.cur_frame)
|
||||
);
|
||||
fflush(stdout);
|
||||
#endif
|
||||
|
||||
@ -417,7 +488,8 @@ int retro_vfs_file_error_cdrom(libretro_vfs_implementation_file *stream)
|
||||
return 0;
|
||||
}
|
||||
|
||||
const vfs_cdrom_t* retro_vfs_file_get_cdrom_position(const libretro_vfs_implementation_file *stream)
|
||||
const vfs_cdrom_t* retro_vfs_file_get_cdrom_position(
|
||||
const libretro_vfs_implementation_file *stream)
|
||||
{
|
||||
return &stream->cdrom;
|
||||
}
|
||||
|
@ -1,4 +1,4 @@
|
||||
/* Copyright (C) 2018-2019 The RetroArch team
|
||||
/* Copyright (C) 2018-2020 The RetroArch team
|
||||
*
|
||||
* ---------------------------------------------------------------------------------------
|
||||
* The following license statement only applies to this file (vfs_implementation_uwp.cpp).
|
||||
@ -51,20 +51,21 @@ using namespace Windows::Storage::FileProperties;
|
||||
#include <retro_miscellaneous.h>
|
||||
#include <file/file_path.h>
|
||||
#include <retro_assert.h>
|
||||
#include <verbosity.h>
|
||||
#include <string/stdstring.h>
|
||||
#include <retro_environment.h>
|
||||
#include <uwp/uwp_func.h>
|
||||
#include <uwp/uwp_async.h>
|
||||
|
||||
namespace
|
||||
{
|
||||
void windowsize_path(wchar_t* path)
|
||||
{
|
||||
/* UWP deals with paths containing / instead of \ way worse than normal Windows */
|
||||
/* and RetroArch may sometimes mix them (e.g. on archive extraction) */
|
||||
/* UWP deals with paths containing / instead of
|
||||
* \ way worse than normal Windows */
|
||||
/* and RetroArch may sometimes mix them
|
||||
* (e.g. on archive extraction) */
|
||||
if (!path)
|
||||
return;
|
||||
|
||||
while (*path)
|
||||
{
|
||||
if (*path == '/')
|
||||
@ -141,15 +142,21 @@ namespace
|
||||
/* Look for a matching directory we can use */
|
||||
for each (StorageFolder^ folder in accessible_directories)
|
||||
{
|
||||
std::wstring file_path;
|
||||
std::wstring folder_path = folder->Path->Data();
|
||||
size_t folder_path_size = folder_path.size();
|
||||
/* Could be C:\ or C:\Users\somebody - remove the trailing slash to unify them */
|
||||
if (folder_path[folder_path.size() - 1] == '\\')
|
||||
folder_path.erase(folder_path.size() - 1);
|
||||
std::wstring file_path = path->Data();
|
||||
if (folder_path[folder_path_size - 1] == '\\')
|
||||
folder_path.erase(folder_path_size - 1);
|
||||
|
||||
file_path = path->Data();
|
||||
|
||||
if (file_path.find(folder_path) == 0)
|
||||
{
|
||||
/* Found a match */
|
||||
file_path = file_path.length() > folder_path.length() ? file_path.substr(folder_path.length() + 1) : L"";
|
||||
file_path = file_path.length() > folder_path.length()
|
||||
? file_path.substr(folder_path.length() + 1)
|
||||
: L"";
|
||||
return concurrency::create_task(GetItemInFolderFromPathAsync<T>(folder, ref new Platform::String(file_path.data())));
|
||||
}
|
||||
}
|
||||
@ -228,7 +235,8 @@ public:
|
||||
{
|
||||
}
|
||||
|
||||
HRESULT __stdcall RuntimeClassInitialize(byte *buffer, uint32_t capacity, uint32_t length)
|
||||
HRESULT __stdcall RuntimeClassInitialize(
|
||||
byte *buffer, uint32_t capacity, uint32_t length)
|
||||
{
|
||||
m_buffer = buffer;
|
||||
m_capacity = capacity;
|
||||
@ -294,37 +302,39 @@ struct libretro_vfs_implementation_file
|
||||
size_t buffer_fill;
|
||||
};
|
||||
|
||||
libretro_vfs_implementation_file *retro_vfs_file_open_impl(const char *path, unsigned mode, unsigned hints)
|
||||
libretro_vfs_implementation_file *retro_vfs_file_open_impl(
|
||||
const char *path, unsigned mode, unsigned hints)
|
||||
{
|
||||
char dirpath[PATH_MAX_LENGTH];
|
||||
char filename[PATH_MAX_LENGTH];
|
||||
wchar_t *dirpath_wide;
|
||||
wchar_t *filename_wide;
|
||||
Platform::String^ filename_str;
|
||||
Platform::String^ dirpath_str;
|
||||
if (!path || !*path)
|
||||
return NULL;
|
||||
|
||||
/* Something tried to access files from current directory.
|
||||
* This is not allowed on UWP. */
|
||||
if (!path_is_absolute(path))
|
||||
{
|
||||
RARCH_WARN("Something tried to access files from current directory ('%s'). This is not allowed on UWP.\n", path);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (path_char_is_slash(path[strlen(path) - 1]))
|
||||
{
|
||||
RARCH_WARN("Trying to open a directory as file?! ('%s')\n", path);
|
||||
/* Trying to open a directory as file?! */
|
||||
if (PATH_CHAR_IS_SLASH(path[strlen(path) - 1]))
|
||||
return NULL;
|
||||
}
|
||||
|
||||
char* dirpath = (char*)malloc(PATH_MAX_LENGTH * sizeof(char));
|
||||
fill_pathname_basedir(dirpath, path, PATH_MAX_LENGTH);
|
||||
wchar_t *dirpath_wide = utf8_to_utf16_string_alloc(dirpath);
|
||||
dirpath[0] = filename[0] = '\0';
|
||||
|
||||
fill_pathname_basedir(dirpath, path, sizeof(dirpath));
|
||||
dirpath_wide = utf8_to_utf16_string_alloc(dirpath);
|
||||
windowsize_path(dirpath_wide);
|
||||
Platform::String^ dirpath_str = ref new Platform::String(dirpath_wide);
|
||||
dirpath_str = ref new Platform::String(dirpath_wide);
|
||||
free(dirpath_wide);
|
||||
free(dirpath);
|
||||
|
||||
char* filename = (char*)malloc(PATH_MAX_LENGTH * sizeof(char));
|
||||
fill_pathname_base(filename, path, PATH_MAX_LENGTH);
|
||||
wchar_t *filename_wide = utf8_to_utf16_string_alloc(filename);
|
||||
Platform::String^ filename_str = ref new Platform::String(filename_wide);
|
||||
fill_pathname_base(filename, path, sizeof(filename));
|
||||
filename_wide = utf8_to_utf16_string_alloc(filename);
|
||||
filename_str = ref new Platform::String(filename_wide);
|
||||
free(filename_wide);
|
||||
free(filename);
|
||||
|
||||
retro_assert(!dirpath_str->IsEmpty() && !filename_str->IsEmpty());
|
||||
|
||||
@ -336,7 +346,7 @@ libretro_vfs_implementation_file *retro_vfs_file_open_impl(const char *path, uns
|
||||
return dir->CreateFileAsync(filename_str, (mode & RETRO_VFS_FILE_ACCESS_UPDATE_EXISTING) != 0 ?
|
||||
CreationCollisionOption::OpenIfExists : CreationCollisionOption::ReplaceExisting);
|
||||
}).then([&](StorageFile^ file) {
|
||||
FileAccessMode accessMode = mode == RETRO_VFS_FILE_ACCESS_READ ?
|
||||
FileAccessMode accessMode = (mode == RETRO_VFS_FILE_ACCESS_READ) ?
|
||||
FileAccessMode::Read : FileAccessMode::ReadWrite;
|
||||
return file->OpenAsync(accessMode);
|
||||
}).then([&](IRandomAccessStream^ fpstream) {
|
||||
@ -344,13 +354,14 @@ libretro_vfs_implementation_file *retro_vfs_file_open_impl(const char *path, uns
|
||||
if (!stream)
|
||||
return (libretro_vfs_implementation_file*)NULL;
|
||||
|
||||
stream->orig_path = strdup(path);
|
||||
stream->fp = fpstream;
|
||||
stream->orig_path = strdup(path);
|
||||
stream->fp = fpstream;
|
||||
stream->fp->Seek(0);
|
||||
// Preallocate a small buffer for manually buffered IO, makes short read faster
|
||||
int buf_size = 8 * 1024;
|
||||
stream->buffer = (char*)malloc(buf_size);
|
||||
stream->bufferp = CreateNativeBuffer(stream->buffer, buf_size, 0);
|
||||
/* Preallocate a small buffer for manually buffered I/O,
|
||||
* makes short read faster */
|
||||
int buf_size = 8 * 1024;
|
||||
stream->buffer = (char*)malloc(buf_size);
|
||||
stream->bufferp = CreateNativeBuffer(stream->buffer, buf_size, 0);
|
||||
stream->buffer_left = 0;
|
||||
stream->buffer_fill = 0;
|
||||
stream->buffer_size = buf_size;
|
||||
@ -399,116 +410,131 @@ int64_t retro_vfs_file_tell_impl(libretro_vfs_implementation_file *stream)
|
||||
return stream->fp->Position - stream->buffer_left;
|
||||
}
|
||||
|
||||
int64_t retro_vfs_file_seek_impl(libretro_vfs_implementation_file *stream, int64_t offset, int seek_position)
|
||||
int64_t retro_vfs_file_seek_impl(
|
||||
libretro_vfs_implementation_file *stream,
|
||||
int64_t offset, int seek_position)
|
||||
{
|
||||
if (!stream || !stream->fp)
|
||||
return -1;
|
||||
if (!stream || !stream->fp)
|
||||
return -1;
|
||||
|
||||
switch (seek_position)
|
||||
{
|
||||
case RETRO_VFS_SEEK_POSITION_START:
|
||||
stream->fp->Seek(offset);
|
||||
break;
|
||||
switch (seek_position)
|
||||
{
|
||||
case RETRO_VFS_SEEK_POSITION_START:
|
||||
stream->fp->Seek(offset);
|
||||
break;
|
||||
|
||||
case RETRO_VFS_SEEK_POSITION_CURRENT:
|
||||
stream->fp->Seek(retro_vfs_file_tell_impl(stream) + offset);
|
||||
break;
|
||||
case RETRO_VFS_SEEK_POSITION_CURRENT:
|
||||
stream->fp->Seek(retro_vfs_file_tell_impl(stream) + offset);
|
||||
break;
|
||||
|
||||
case RETRO_VFS_SEEK_POSITION_END:
|
||||
stream->fp->Seek(stream->fp->Size - offset);
|
||||
break;
|
||||
}
|
||||
case RETRO_VFS_SEEK_POSITION_END:
|
||||
stream->fp->Seek(stream->fp->Size - offset);
|
||||
break;
|
||||
}
|
||||
|
||||
// For simplicity always flush the buffer on seek
|
||||
stream->buffer_left = 0;
|
||||
// For simplicity always flush the buffer on seek
|
||||
stream->buffer_left = 0;
|
||||
|
||||
return 0;
|
||||
return 0;
|
||||
}
|
||||
|
||||
int64_t retro_vfs_file_read_impl(libretro_vfs_implementation_file *stream, void *s, uint64_t len)
|
||||
int64_t retro_vfs_file_read_impl(
|
||||
libretro_vfs_implementation_file *stream, void *s, uint64_t len)
|
||||
{
|
||||
int64_t ret;
|
||||
int64_t bytes_read = 0;
|
||||
IBuffer^ buffer;
|
||||
|
||||
if (!stream || !stream->fp || !s)
|
||||
return -1;
|
||||
|
||||
int64_t bytes_read = 0;
|
||||
if (len <= stream->buffer_size)
|
||||
{
|
||||
/* Small read, use manually buffered I/O */
|
||||
if (stream->buffer_left < len)
|
||||
{
|
||||
/* Exhaust the buffer */
|
||||
memcpy(s,
|
||||
&stream->buffer[stream->buffer_fill - stream->buffer_left],
|
||||
stream->buffer_left);
|
||||
len -= stream->buffer_left;
|
||||
bytes_read += stream->buffer_left;
|
||||
stream->buffer_left = 0;
|
||||
|
||||
if (len <= stream->buffer_size) {
|
||||
// Small read, use manually buffered IO
|
||||
if (stream->buffer_left < len) {
|
||||
// Exhaust the buffer
|
||||
memcpy(s, &stream->buffer[stream->buffer_fill - stream->buffer_left], stream->buffer_left);
|
||||
len -= stream->buffer_left;
|
||||
bytes_read += stream->buffer_left;
|
||||
stream->buffer_left = 0;
|
||||
/* Fill buffer */
|
||||
stream->buffer_left = RunAsyncAndCatchErrors<int64_t>([&]() {
|
||||
return concurrency::create_task(stream->fp->ReadAsync(stream->bufferp, stream->bufferp->Capacity, InputStreamOptions::None)).then([&](IBuffer^ buf) {
|
||||
retro_assert(stream->bufferp == buf);
|
||||
return (int64_t)stream->bufferp->Length;
|
||||
});
|
||||
}, -1);
|
||||
stream->buffer_fill = stream->buffer_left;
|
||||
|
||||
// Fill buffer
|
||||
stream->buffer_left = RunAsyncAndCatchErrors<int64_t>([&]() {
|
||||
return concurrency::create_task(stream->fp->ReadAsync(stream->bufferp, stream->bufferp->Capacity, InputStreamOptions::None)).then([&](IBuffer^ buf) {
|
||||
retro_assert(stream->bufferp == buf);
|
||||
return (int64_t)stream->bufferp->Length;
|
||||
});
|
||||
}, -1);
|
||||
stream->buffer_fill = stream->buffer_left;
|
||||
if (stream->buffer_left == -1)
|
||||
{
|
||||
stream->buffer_left = 0;
|
||||
stream->buffer_fill = 0;
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (stream->buffer_left == -1) {
|
||||
stream->buffer_left = 0;
|
||||
stream->buffer_fill = 0;
|
||||
return -1;
|
||||
}
|
||||
if (stream->buffer_left < len)
|
||||
{
|
||||
/* EOF */
|
||||
memcpy(&((char*)s)[bytes_read],
|
||||
stream->buffer, stream->buffer_left);
|
||||
bytes_read += stream->buffer_left;
|
||||
stream->buffer_left = 0;
|
||||
return bytes_read;
|
||||
}
|
||||
|
||||
if (stream->buffer_left < len) {
|
||||
// EOF
|
||||
memcpy(&((char*)s)[bytes_read], stream->buffer, stream->buffer_left);
|
||||
bytes_read += stream->buffer_left;
|
||||
stream->buffer_left = 0;
|
||||
return bytes_read;
|
||||
}
|
||||
memcpy(&((char*)s)[bytes_read], stream->buffer, len);
|
||||
bytes_read += len;
|
||||
stream->buffer_left -= len;
|
||||
return bytes_read;
|
||||
}
|
||||
|
||||
memcpy(&((char*)s)[bytes_read], stream->buffer, len);
|
||||
bytes_read += len;
|
||||
stream->buffer_left -= len;
|
||||
return bytes_read;
|
||||
}
|
||||
/* Internal buffer already contains requested amount */
|
||||
memcpy(s,
|
||||
&stream->buffer[stream->buffer_fill - stream->buffer_left],
|
||||
len);
|
||||
stream->buffer_left -= len;
|
||||
return len;
|
||||
}
|
||||
|
||||
// Internal buffer already contains requested amount
|
||||
memcpy(s, &stream->buffer[stream->buffer_fill - stream->buffer_left], len);
|
||||
stream->buffer_left -= len;
|
||||
return len;
|
||||
}
|
||||
|
||||
// Big read exceeding buffer size, exhaust small buffer and read rest in one go
|
||||
/* Big read exceeding buffer size,
|
||||
* exhaust small buffer and read rest in one go */
|
||||
memcpy(s, &stream->buffer[stream->buffer_fill - stream->buffer_left], stream->buffer_left);
|
||||
len -= stream->buffer_left;
|
||||
bytes_read += stream->buffer_left;
|
||||
stream->buffer_left = 0;
|
||||
len -= stream->buffer_left;
|
||||
bytes_read += stream->buffer_left;
|
||||
stream->buffer_left = 0;
|
||||
|
||||
IBuffer^ buffer = CreateNativeBuffer(&((char*)s)[bytes_read], len, 0);
|
||||
|
||||
int64_t ret = RunAsyncAndCatchErrors<int64_t>([&]() {
|
||||
buffer = CreateNativeBuffer(&((char*)s)[bytes_read], len, 0);
|
||||
ret = RunAsyncAndCatchErrors<int64_t>([&]() {
|
||||
return concurrency::create_task(stream->fp->ReadAsync(buffer, buffer->Capacity - bytes_read, InputStreamOptions::None)).then([&](IBuffer^ buf) {
|
||||
retro_assert(buf == buffer);
|
||||
return (int64_t)buffer->Length;
|
||||
});
|
||||
}, -1);
|
||||
|
||||
if (ret == -1) {
|
||||
if (ret == -1)
|
||||
return -1;
|
||||
}
|
||||
return bytes_read + ret;
|
||||
}
|
||||
|
||||
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)
|
||||
{
|
||||
if (!stream || !stream->fp || !s)
|
||||
return -1;
|
||||
IBuffer^ buffer;
|
||||
if (!stream || !stream->fp || !s)
|
||||
return -1;
|
||||
|
||||
// const_cast to remove const modifier is undefined behaviour, but the buffer is only read, should be safe
|
||||
IBuffer^ buffer = CreateNativeBuffer(const_cast<void*>(s), len, len);
|
||||
return RunAsyncAndCatchErrors<int64_t>([&]() {
|
||||
return concurrency::create_task(stream->fp->WriteAsync(buffer)).then([&](unsigned int written) {
|
||||
return (int64_t)written;
|
||||
});
|
||||
}, -1);
|
||||
/* const_cast to remove const modifier is undefined behaviour, but the buffer is only read, should be safe */
|
||||
buffer = CreateNativeBuffer(const_cast<void*>(s), len, len);
|
||||
return RunAsyncAndCatchErrors<int64_t>([&]() {
|
||||
return concurrency::create_task(stream->fp->WriteAsync(buffer)).then([&](unsigned int written) {
|
||||
return (int64_t)written;
|
||||
});
|
||||
}, -1);
|
||||
}
|
||||
|
||||
int retro_vfs_file_flush_impl(libretro_vfs_implementation_file *stream)
|
||||
@ -527,12 +553,15 @@ int retro_vfs_file_flush_impl(libretro_vfs_implementation_file *stream)
|
||||
|
||||
int retro_vfs_file_remove_impl(const char *path)
|
||||
{
|
||||
wchar_t *path_wide;
|
||||
Platform::String^ path_str;
|
||||
|
||||
if (!path || !*path)
|
||||
return -1;
|
||||
|
||||
wchar_t *path_wide = utf8_to_utf16_string_alloc(path);
|
||||
path_wide = utf8_to_utf16_string_alloc(path);
|
||||
windowsize_path(path_wide);
|
||||
Platform::String^ path_str = ref new Platform::String(path_wide);
|
||||
path_str = ref new Platform::String(path_wide);
|
||||
free(path_wide);
|
||||
|
||||
return RunAsyncAndCatchErrors<int>([&]() {
|
||||
@ -547,27 +576,34 @@ int retro_vfs_file_remove_impl(const char *path)
|
||||
/* TODO: this may not work if trying to move a directory */
|
||||
int retro_vfs_file_rename_impl(const char *old_path, const char *new_path)
|
||||
{
|
||||
if (!old_path || !*old_path || !new_path || !*new_path)
|
||||
char new_file_name[PATH_MAX_LENGTH];
|
||||
char new_dir_path[PATH_MAX_LENGTH];
|
||||
wchar_t *new_file_name_wide;
|
||||
wchar_t *old_path_wide, *new_dir_path_wide;
|
||||
Platform::String^ old_path_str;
|
||||
Platform::String^ new_dir_path_str;
|
||||
Platform::String^ new_file_name_str;
|
||||
|
||||
if (!old_path || !*old_path || !new_path || !*new_path)
|
||||
return -1;
|
||||
|
||||
wchar_t* old_path_wide = utf8_to_utf16_string_alloc(old_path);
|
||||
Platform::String^ old_path_str = ref new Platform::String(old_path_wide);
|
||||
new_file_name[0] = '\0';
|
||||
new_dir_path [0] = '\0';
|
||||
|
||||
old_path_wide = utf8_to_utf16_string_alloc(old_path);
|
||||
old_path_str = ref new Platform::String(old_path_wide);
|
||||
free(old_path_wide);
|
||||
|
||||
char* new_dir_path = (char*)malloc(PATH_MAX_LENGTH * sizeof(char));
|
||||
fill_pathname_basedir(new_dir_path, new_path, PATH_MAX_LENGTH);
|
||||
wchar_t *new_dir_path_wide = utf8_to_utf16_string_alloc(new_dir_path);
|
||||
fill_pathname_basedir(new_dir_path, new_path, sizeof(new_dir_path));
|
||||
new_dir_path_wide = utf8_to_utf16_string_alloc(new_dir_path);
|
||||
windowsize_path(new_dir_path_wide);
|
||||
Platform::String^ new_dir_path_str = ref new Platform::String(new_dir_path_wide);
|
||||
new_dir_path_str = ref new Platform::String(new_dir_path_wide);
|
||||
free(new_dir_path_wide);
|
||||
free(new_dir_path);
|
||||
|
||||
char* new_file_name = (char*)malloc(PATH_MAX_LENGTH * sizeof(char));
|
||||
fill_pathname_base(new_file_name, new_path, PATH_MAX_LENGTH);
|
||||
wchar_t *new_file_name_wide = utf8_to_utf16_string_alloc(new_file_name);
|
||||
Platform::String^ new_file_name_str = ref new Platform::String(new_file_name_wide);
|
||||
fill_pathname_base(new_file_name, new_path, sizeof(new_file_name));
|
||||
new_file_name_wide = utf8_to_utf16_string_alloc(new_file_name);
|
||||
new_file_name_str = ref new Platform::String(new_file_name_wide);
|
||||
free(new_file_name_wide);
|
||||
free(new_file_name);
|
||||
|
||||
retro_assert(!old_path_str->IsEmpty() && !new_dir_path_str->IsEmpty() && !new_file_name_str->IsEmpty());
|
||||
|
||||
@ -599,15 +635,19 @@ const char *retro_vfs_file_get_path_impl(libretro_vfs_implementation_file *strea
|
||||
|
||||
int retro_vfs_stat_impl(const char *path, int32_t *size)
|
||||
{
|
||||
wchar_t *path_wide;
|
||||
Platform::String^ path_str;
|
||||
IStorageItem^ item;
|
||||
|
||||
if (!path || !*path)
|
||||
return 0;
|
||||
|
||||
wchar_t *path_wide = utf8_to_utf16_string_alloc(path);
|
||||
path_wide = utf8_to_utf16_string_alloc(path);
|
||||
windowsize_path(path_wide);
|
||||
Platform::String^ path_str = ref new Platform::String(path_wide);
|
||||
path_str = ref new Platform::String(path_wide);
|
||||
free(path_wide);
|
||||
|
||||
IStorageItem^ item = LocateStorageFileOrFolder(path_str);
|
||||
item = LocateStorageFileOrFolder(path_str);
|
||||
if (!item)
|
||||
return 0;
|
||||
|
||||
@ -622,36 +662,44 @@ int retro_vfs_stat_impl(const char *path, int32_t *size)
|
||||
|
||||
int retro_vfs_mkdir_impl(const char *dir)
|
||||
{
|
||||
Platform::String^ parent_path_str;
|
||||
Platform::String^ dir_name_str;
|
||||
wchar_t *dir_name_wide, *parent_path_wide;
|
||||
char *dir_local, *tmp, *dir_name;
|
||||
char parent_path[PATH_MAX_LENGTH];
|
||||
char dir_name[PATH_MAX_LENGTH];
|
||||
if (!dir || !*dir)
|
||||
return -1;
|
||||
|
||||
char* dir_local = strdup(dir);
|
||||
/* If the path ends with a slash, we have to remove it for basename to work */
|
||||
char* tmp = dir_local + strlen(dir_local) - 1;
|
||||
if (path_char_is_slash(*tmp))
|
||||
*tmp = 0;
|
||||
dir_name[0] = '\0';
|
||||
|
||||
char* dir_name = (char*)malloc(PATH_MAX_LENGTH * sizeof(char));
|
||||
fill_pathname_base(dir_name, dir_local, PATH_MAX_LENGTH);
|
||||
wchar_t *dir_name_wide = utf8_to_utf16_string_alloc(dir_name);
|
||||
Platform::String^ dir_name_str = ref new Platform::String(dir_name_wide);
|
||||
/* If the path ends with a slash, we have to remove
|
||||
* it for basename to work */
|
||||
dir_local = strdup(dir);
|
||||
tmp = dir_local + strlen(dir_local) - 1;
|
||||
|
||||
if (PATH_CHAR_IS_SLASH(*tmp))
|
||||
*tmp = 0;
|
||||
|
||||
fill_pathname_base(dir_name, dir_local, sizeof(dir_name));
|
||||
dir_name_wide = utf8_to_utf16_string_alloc(dir_name);
|
||||
dir_name_str = ref new Platform::String(dir_name_wide);
|
||||
free(dir_name_wide);
|
||||
free(dir_name);
|
||||
|
||||
char* parent_path = (char*)malloc(PATH_MAX_LENGTH * sizeof(char));
|
||||
fill_pathname_parent_dir(parent_path, dir_local, PATH_MAX_LENGTH);
|
||||
wchar_t *parent_path_wide = utf8_to_utf16_string_alloc(parent_path);
|
||||
fill_pathname_parent_dir(parent_path, dir_local, sizeof(parent_path));
|
||||
parent_path_wide = utf8_to_utf16_string_alloc(parent_path);
|
||||
windowsize_path(parent_path_wide);
|
||||
Platform::String^ parent_path_str = ref new Platform::String(parent_path_wide);
|
||||
parent_path_str = ref new Platform::String(parent_path_wide);
|
||||
free(parent_path_wide);
|
||||
free(parent_path);
|
||||
|
||||
retro_assert(!dir_name_str->IsEmpty() && !parent_path_str->IsEmpty());
|
||||
retro_assert(!dir_name_str->IsEmpty()
|
||||
&& !parent_path_str->IsEmpty());
|
||||
|
||||
free(dir_local);
|
||||
|
||||
return RunAsyncAndCatchErrors<int>([&]() {
|
||||
return concurrency::create_task(LocateStorageItem<StorageFolder>(parent_path_str)).then([&](StorageFolder^ parent) {
|
||||
return concurrency::create_task(LocateStorageItem<StorageFolder>(
|
||||
parent_path_str)).then([&](StorageFolder^ parent) {
|
||||
return parent->CreateFolderAsync(dir_name_str);
|
||||
}).then([&](concurrency::task<StorageFolder^> new_dir) {
|
||||
try
|
||||
@ -682,6 +730,8 @@ struct libretro_vfs_implementation_dir
|
||||
|
||||
libretro_vfs_implementation_dir *retro_vfs_opendir_impl(const char *name, bool include_hidden)
|
||||
{
|
||||
wchar_t *name_wide;
|
||||
Platform::String^ name_str;
|
||||
libretro_vfs_implementation_dir *rdir;
|
||||
|
||||
if (!name || !*name)
|
||||
@ -691,9 +741,9 @@ libretro_vfs_implementation_dir *retro_vfs_opendir_impl(const char *name, bool i
|
||||
if (!rdir)
|
||||
return NULL;
|
||||
|
||||
wchar_t *name_wide = utf8_to_utf16_string_alloc(name);
|
||||
name_wide = utf8_to_utf16_string_alloc(name);
|
||||
windowsize_path(name_wide);
|
||||
Platform::String^ name_str = ref new Platform::String(name_wide);
|
||||
name_str = ref new Platform::String(name_wide);
|
||||
free(name_wide);
|
||||
|
||||
rdir->directory = RunAsyncAndCatchErrors<IVectorView<IStorageItem^>^>([&]() {
|
||||
@ -716,17 +766,16 @@ bool retro_vfs_readdir_impl(libretro_vfs_implementation_dir *rdir)
|
||||
rdir->entry = rdir->directory->First();
|
||||
return rdir->entry->HasCurrent;
|
||||
}
|
||||
else
|
||||
{
|
||||
return rdir->entry->MoveNext();
|
||||
}
|
||||
return rdir->entry->MoveNext();
|
||||
}
|
||||
|
||||
const char *retro_vfs_dirent_get_name_impl(libretro_vfs_implementation_dir *rdir)
|
||||
const char *retro_vfs_dirent_get_name_impl(
|
||||
libretro_vfs_implementation_dir *rdir)
|
||||
{
|
||||
if (rdir->entry_name)
|
||||
free(rdir->entry_name);
|
||||
rdir->entry_name = utf16_to_utf8_string_alloc(rdir->entry->Current->Name->Data());
|
||||
rdir->entry_name = utf16_to_utf8_string_alloc(
|
||||
rdir->entry->Current->Name->Data());
|
||||
return rdir->entry_name;
|
||||
}
|
||||
|
||||
@ -742,7 +791,7 @@ int retro_vfs_closedir_impl(libretro_vfs_implementation_dir *rdir)
|
||||
|
||||
if (rdir->entry_name)
|
||||
free(rdir->entry_name);
|
||||
rdir->entry = nullptr;
|
||||
rdir->entry = nullptr;
|
||||
rdir->directory = nullptr;
|
||||
|
||||
free(rdir);
|
||||
@ -751,18 +800,20 @@ int retro_vfs_closedir_impl(libretro_vfs_implementation_dir *rdir)
|
||||
|
||||
bool uwp_drive_exists(const char *path)
|
||||
{
|
||||
if (!path || !*path)
|
||||
return 0;
|
||||
wchar_t *path_wide;
|
||||
Platform::String^ path_str;
|
||||
if (!path || !*path)
|
||||
return 0;
|
||||
|
||||
wchar_t *path_wide = utf8_to_utf16_string_alloc(path);
|
||||
Platform::String^ path_str = ref new Platform::String(path_wide);
|
||||
free(path_wide);
|
||||
path_wide = utf8_to_utf16_string_alloc(path);
|
||||
path_str = ref new Platform::String(path_wide);
|
||||
free(path_wide);
|
||||
|
||||
return RunAsyncAndCatchErrors<bool>([&]() {
|
||||
return concurrency::create_task(StorageFolder::GetFolderFromPathAsync(path_str)).then([](StorageFolder^ properties) {
|
||||
return true;
|
||||
});
|
||||
}, false);
|
||||
return RunAsyncAndCatchErrors<bool>([&]() {
|
||||
return concurrency::create_task(StorageFolder::GetFolderFromPathAsync(path_str)).then([](StorageFolder^ properties) {
|
||||
return true;
|
||||
});
|
||||
}, false);
|
||||
}
|
||||
|
||||
char* uwp_trigger_picker(void)
|
||||
|
Loading…
Reference in New Issue
Block a user