From b4e7cd1b51aa08b9f832d46c1f98527810075c76 Mon Sep 17 00:00:00 2001 From: kub Date: Wed, 9 Feb 2022 18:42:04 +0000 Subject: [PATCH] libretro, update libretro-common --- Makefile | 3 + Makefile.libretro | 16 - .../compat/compat_posix_string.c | 2 +- .../compat/compat_strcasestr.c | 58 ++ .../libretro-common/compat/compat_strl.c | 2 +- .../libretro-common/compat/fopen_utf8.c | 13 +- .../libretro-common/encodings/encoding_utf.c | 124 +++-- .../libretro-common/include/boolean.h | 2 +- .../include/compat/apple_compat.h | 2 +- .../libretro-common/include/compat/fnmatch.h | 2 +- .../include/compat/fopen_utf8.h | 2 +- .../libretro-common/include/compat/getopt.h | 2 +- .../include/compat/intrinsics.h | 42 +- .../libretro-common/include/compat/msvc.h | 13 +- .../include/compat/posix_string.h | 6 +- .../include/compat/strcasestr.h | 6 +- .../libretro-common/include/compat/strl.h | 2 +- .../libretro-common/include/encodings/utf.h | 4 +- .../libretro-common/include/file/file_path.h | 47 +- .../libretro-common/include/libretro.h | 7 + .../libretro/libretro-common/include/memmap.h | 4 +- .../libretro-common/include/retro_common.h | 2 +- .../include/retro_common_api.h | 2 +- .../libretro-common/include/retro_dirent.h | 3 +- .../include/retro_endianness.h | 521 ++++++++++++++---- .../include/retro_environment.h | 2 +- .../libretro-common/include/retro_inline.h | 2 +- .../include/retro_miscellaneous.h | 53 +- .../include/streams/file_stream.h | 4 +- .../include/streams/file_stream_transforms.h | 2 +- .../include/string/stdstring.h | 170 +++++- .../libretro-common/include/vfs/vfs.h | 28 +- .../include/vfs/vfs_implementation.h | 8 +- .../libretro/libretro-common/memmap/memmap.c | 163 ++++++ .../libretro-common/streams/file_stream.c | 230 +++++--- .../streams/file_stream_transforms.c | 46 +- .../libretro-common/string/stdstring.c | 380 ++++++++++--- .../libretro-common/vfs/vfs_implementation.c | 448 ++++++++------- platform/libretro/libretro.c | 26 - 39 files changed, 1739 insertions(+), 710 deletions(-) create mode 100644 platform/libretro/libretro-common/compat/compat_strcasestr.c create mode 100644 platform/libretro/libretro-common/memmap/memmap.c diff --git a/Makefile b/Makefile index 94446a95..ce1938e4 100644 --- a/Makefile +++ b/Makefile @@ -196,10 +196,13 @@ endif ifeq "$(PLATFORM)" "libretro" OBJS += platform/libretro/libretro.o ifeq "$(USE_LIBRETRO_VFS)" "1" +OBJS += platform/libretro/libretro-common/compat/compat_strcasestr.o OBJS += platform/libretro/libretro-common/compat/compat_posix_string.o OBJS += platform/libretro/libretro-common/compat/compat_strl.o OBJS += platform/libretro/libretro-common/compat/fopen_utf8.o +OBJS += platform/libretro/libretro-common/memmap/memmap.o OBJS += platform/libretro/libretro-common/encodings/encoding_utf.o +OBJS += platform/libretro/libretro-common/string/stdstring.o OBJS += platform/libretro/libretro-common/streams/file_stream.o OBJS += platform/libretro/libretro-common/streams/file_stream_transforms.o OBJS += platform/libretro/libretro-common/vfs/vfs_implementation.o diff --git a/Makefile.libretro b/Makefile.libretro index 3c7c67a2..cf9ac1d1 100644 --- a/Makefile.libretro +++ b/Makefile.libretro @@ -160,7 +160,6 @@ else ifeq ($(platform), ps3) AR = $(CELL_SDK)/host-win32/ppu/bin/ppu-lv2-ar.exe CFLAGS += -DBLARGG_BIG_ENDIAN=1 -D__ppc__ -DFAMEC_NO_GOTOS STATIC_LINKING = 1 - NO_MMAP = 1 # PS3 has memory mapped in a way not suitable for DRC use_sh2drc = 0 use_svpdrc = 0 @@ -173,7 +172,6 @@ else ifeq ($(platform), sncps3) AR = $(CELL_SDK)/host-win32/sn/bin/ps3snarl.exe CFLAGS += -DBLARGG_BIG_ENDIAN=1 -D__ppc__ -DFAMEC_NO_GOTOS STATIC_LINKING = 1 - NO_MMAP = 1 # PS3 has memory mapped in a way not suitable for DRC use_sh2drc = 0 use_svpdrc = 0 @@ -185,7 +183,6 @@ else ifeq ($(platform), psl1ght) AR = $(PS3DEV)/ppu/bin/ppu-ar$(EXE_EXT) CFLAGS += -DBLARGG_BIG_ENDIAN=1 -D__ppc__ -DFAMEC_NO_GOTOS STATIC_LINKING = 1 - NO_MMAP = 1 # PS3 has memory mapped in a way not suitable for DRC use_sh2drc = 0 use_svpdrc = 0 @@ -199,7 +196,6 @@ else ifeq ($(platform), psp1) CFLAGS += -G0 -ftracer CFLAGS += -DPSP STATIC_LINKING = 1 - NO_MMAP = 1 # PS2 else ifeq ($(platform), ps2) @@ -211,7 +207,6 @@ else ifeq ($(platform), ps2) CFLAGS += -I$(PS2DEV)/gsKit/include -I$(PS2SDK)/ee/include -I$(PS2SDK)/common/include CFLAGS += -DHAVE_NO_LANGEXTRA STATIC_LINKING = 1 - NO_MMAP = 1 # CTR (3DS) else ifeq ($(platform), ctr) @@ -224,7 +219,6 @@ else ifeq ($(platform), ctr) CFLAGS += -Wall -mword-relocations CFLAGS += -fomit-frame-pointer -ffast-math STATIC_LINKING = 1 - NO_MMAP = 1 OBJS += platform/libretro/3ds/3ds_utils.o platform/libretro/3ds/utils.o @@ -249,7 +243,6 @@ else ifeq ($(platform), vita) CFLAGS += -mword-relocations -fno-unwind-tables CFLAGS += -fno-optimize-sibling-calls STATIC_LINKING = 1 - NO_MMAP = 1 # Xbox 360 else ifeq ($(platform), xenon) @@ -265,7 +258,6 @@ else ifeq ($(platform), ngc) AR = $(DEVKITPPC)/bin/powerpc-eabi-ar$(EXE_EXT) CFLAGS += -DGEKKO -DHW_DOL -mrvl -mcpu=750 -meabi -mhard-float -D__ppc__ -DMSB_FIRST STATIC_LINKING = 1 - NO_MMAP = 1 # Nintendo Wii else ifeq ($(platform), wii) @@ -274,7 +266,6 @@ else ifeq ($(platform), wii) AR = $(DEVKITPPC)/bin/powerpc-eabi-ar$(EXE_EXT) CFLAGS += -DGEKKO -DHW_RVL -mrvl -mcpu=750 -meabi -mhard-float -D__ppc__ -DMSB_FIRST STATIC_LINKING = 1 - NO_MMAP = 1 # Nintendo Wii U else ifeq ($(platform), wiiu) @@ -284,14 +275,12 @@ else ifeq ($(platform), wiiu) AR = $(DEVKITPPC)/bin/powerpc-eabi-ar$(EXE_EXT) CFLAGS += -DGEKKO -DWIIU -DHW_RVL -DHW_WUP -mwup -mcpu=750 -meabi -mhard-float -D__ppc__ -DMSB_FIRST STATIC_LINKING = 1 - NO_MMAP = 1 # Nintendo Switch (libtransistor) else ifeq ($(platform), switch) TARGET := $(TARGET_NAME)_libretro_$(platform).a include $(LIBTRANSISTOR_HOME)/libtransistor.mk STATIC_LINKING=1 - NO_MMAP = 1 # Nintendo Switch (libnx) else ifeq ($(platform), libnx) @@ -548,14 +537,9 @@ endif CFLAGS += -DNO_ZLIB -D__LIBRETRO__ ifeq ($(USE_LIBRETRO_VFS),1) - NO_MMAP = 1 CFLAGS += -DUSE_LIBRETRO_VFS endif -ifeq ($(NO_MMAP),1) - CFLAGS += -DNO_MMAP -endif - ifeq ($(NO_ARM_ASM),1) use_cyclone = 0 use_fame = 1 diff --git a/platform/libretro/libretro-common/compat/compat_posix_string.c b/platform/libretro/libretro-common/compat/compat_posix_string.c index 33a30e57..6a2f07ee 100644 --- a/platform/libretro/libretro-common/compat/compat_posix_string.c +++ b/platform/libretro/libretro-common/compat/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_posix_string.c). diff --git a/platform/libretro/libretro-common/compat/compat_strcasestr.c b/platform/libretro/libretro-common/compat/compat_strcasestr.c new file mode 100644 index 00000000..4129dab2 --- /dev/null +++ b/platform/libretro/libretro-common/compat/compat_strcasestr.c @@ -0,0 +1,58 @@ +/* Copyright (C) 2010-2020 The RetroArch team + * + * --------------------------------------------------------------------------------------- + * The following license statement only applies to this file (compat_strcasestr.c). + * --------------------------------------------------------------------------------------- + * + * Permission is hereby granted, free of charge, + * to any person obtaining a copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation the rights to + * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, + * and to permit persons to whom the Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, + * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. + * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, + * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + */ + +#include + +#include + +/* Pretty much strncasecmp. */ +static int casencmp(const char *a, const char *b, size_t n) +{ + size_t i; + + for (i = 0; i < n; i++) + { + int a_lower = tolower(a[i]); + int b_lower = tolower(b[i]); + if (a_lower != b_lower) + return a_lower - b_lower; + } + + return 0; +} + +char *strcasestr_retro__(const char *haystack, const char *needle) +{ + size_t i, search_off; + size_t hay_len = strlen(haystack); + size_t needle_len = strlen(needle); + + if (needle_len > hay_len) + return NULL; + + search_off = hay_len - needle_len; + for (i = 0; i <= search_off; i++) + if (!casencmp(haystack + i, needle, needle_len)) + return (char*)haystack + i; + + return NULL; +} diff --git a/platform/libretro/libretro-common/compat/compat_strl.c b/platform/libretro/libretro-common/compat/compat_strl.c index 94cb39b6..31723107 100644 --- a/platform/libretro/libretro-common/compat/compat_strl.c +++ b/platform/libretro/libretro-common/compat/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 (compat_strl.c). diff --git a/platform/libretro/libretro-common/compat/fopen_utf8.c b/platform/libretro/libretro-common/compat/fopen_utf8.c index 893afb83..85abb59e 100644 --- a/platform/libretro/libretro-common/compat/fopen_utf8.c +++ b/platform/libretro/libretro-common/compat/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 (fopen_utf8.c). @@ -49,9 +49,14 @@ void *fopen_utf8(const char * filename, const char * mode) #else wchar_t * filename_w = utf8_to_utf16_string_alloc(filename); wchar_t * mode_w = utf8_to_utf16_string_alloc(mode); - FILE* ret = _wfopen(filename_w, mode_w); - free(filename_w); - free(mode_w); + FILE* ret = NULL; + + if (filename_w && mode_w) + ret = _wfopen(filename_w, mode_w); + if (filename_w) + free(filename_w); + if (mode_w) + free(mode_w); return ret; #endif } diff --git a/platform/libretro/libretro-common/encodings/encoding_utf.c b/platform/libretro/libretro-common/encodings/encoding_utf.c index b6ad2f96..2760824d 100644 --- a/platform/libretro/libretro-common/encodings/encoding_utf.c +++ b/platform/libretro/libretro-common/encodings/encoding_utf.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_utf.c). @@ -37,6 +37,8 @@ #include #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) + 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) { - path_buf_wide = (wchar_t*) - calloc(path_buf_wide_len + sizeof(wchar_t), sizeof(wchar_t)); + MultiByteToWideChar(cp_in, 0, + str, -1, path_buf_wide, path_buf_wide_len); - if (path_buf_wide) + if (*path_buf_wide) { - MultiByteToWideChar(cp_in, 0, - str, -1, path_buf_wide, path_buf_wide_len); + int path_buf_len = WideCharToMultiByte(cp_out, 0, + path_buf_wide, -1, NULL, 0, NULL, NULL); - if (*path_buf_wide) + if (path_buf_len) { - path_buf_len = WideCharToMultiByte(cp_out, 0, - path_buf_wide, -1, NULL, 0, NULL, NULL); + char *path_buf = (char*) + calloc(path_buf_len + sizeof(char), sizeof(char)); - if (path_buf_len) + if (path_buf) { - path_buf = (char*) - calloc(path_buf_len + sizeof(char), sizeof(char)); + WideCharToMultiByte(cp_out, 0, + path_buf_wide, -1, path_buf, + path_buf_len, NULL, NULL); - if (path_buf) - { - WideCharToMultiByte(cp_out, 0, - path_buf_wide, -1, path_buf, - path_buf_len, NULL, NULL); - - free(path_buf_wide); + free(path_buf_wide); - if (*path_buf) - return path_buf; + if (*path_buf) + return path_buf; - free(path_buf); - return NULL; - } - } - else - { - free(path_buf_wide); - return strdup(str); + free(path_buf); + return NULL; } } + else + { + free(path_buf_wide); + return strdup(str); + } } - } - else - return strdup(str); - if (path_buf_wide) 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; diff --git a/platform/libretro/libretro-common/include/boolean.h b/platform/libretro/libretro-common/include/boolean.h index f06ac5a7..9d0d7c12 100644 --- a/platform/libretro/libretro-common/include/boolean.h +++ b/platform/libretro/libretro-common/include/boolean.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 (boolean.h). diff --git a/platform/libretro/libretro-common/include/compat/apple_compat.h b/platform/libretro/libretro-common/include/compat/apple_compat.h index 819b39ec..bf98a591 100644 --- a/platform/libretro/libretro-common/include/compat/apple_compat.h +++ b/platform/libretro/libretro-common/include/compat/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 (apple_compat.h). diff --git a/platform/libretro/libretro-common/include/compat/fnmatch.h b/platform/libretro/libretro-common/include/compat/fnmatch.h index cede1ca6..97878784 100644 --- a/platform/libretro/libretro-common/include/compat/fnmatch.h +++ b/platform/libretro/libretro-common/include/compat/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 (fnmatch.h). diff --git a/platform/libretro/libretro-common/include/compat/fopen_utf8.h b/platform/libretro/libretro-common/include/compat/fopen_utf8.h index f59822a5..97d4404e 100644 --- a/platform/libretro/libretro-common/include/compat/fopen_utf8.h +++ b/platform/libretro/libretro-common/include/compat/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 (fopen_utf8.h). diff --git a/platform/libretro/libretro-common/include/compat/getopt.h b/platform/libretro/libretro-common/include/compat/getopt.h index 2e606a68..48603f0d 100644 --- a/platform/libretro/libretro-common/include/compat/getopt.h +++ b/platform/libretro/libretro-common/include/compat/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 (getopt.h). diff --git a/platform/libretro/libretro-common/include/compat/intrinsics.h b/platform/libretro/libretro-common/include/compat/intrinsics.h index cb1f540d..ac490274 100644 --- a/platform/libretro/libretro-common/include/compat/intrinsics.h +++ b/platform/libretro/libretro-common/include/compat/intrinsics.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; @@ -63,20 +63,34 @@ static INLINE int compat_ctz(unsigned x) return __builtin_ctz(x); #elif _MSC_VER >= 1400 && !defined(_XBOX) && !defined(__WINRT__) unsigned long r = 0; - _BitScanReverse((unsigned long*)&r, x); + _BitScanForward((unsigned long*)&r, x); return (int)r; #else -/* Only checks at nibble granularity, - * because that's what we need. */ - if (x & 0x000f) - return 0; - if (x & 0x00f0) - return 4; - if (x & 0x0f00) - return 8; - if (x & 0xf000) - return 12; - return 16; + int count = 0; + if (!(x & 0xffff)) + { + x >>= 16; + count |= 16; + } + if (!(x & 0xff)) + { + x >>= 8; + count |= 8; + } + if (!(x & 0xf)) + { + x >>= 4; + count |= 4; + } + if (!(x & 0x3)) + { + x >>= 2; + count |= 2; + } + if (!(x & 0x1)) + count |= 1; + + return count; #endif } diff --git a/platform/libretro/libretro-common/include/compat/msvc.h b/platform/libretro/libretro-common/include/compat/msvc.h index 1c242630..a4c93a59 100644 --- a/platform/libretro/libretro-common/include/compat/msvc.h +++ b/platform/libretro/libretro-common/include/compat/msvc.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 (msvc.h). @@ -29,22 +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 + #include #include + #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 - #include - #include #ifndef vsnprintf #define vsnprintf c99_vsnprintf_retro__ #endif diff --git a/platform/libretro/libretro-common/include/compat/posix_string.h b/platform/libretro/libretro-common/include/compat/posix_string.h index f4380c3a..47964b2a 100644 --- a/platform/libretro/libretro-common/include/compat/posix_string.h +++ b/platform/libretro/libretro-common/include/compat/posix_string.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 (posix_string.h). @@ -29,10 +29,6 @@ #include #endif -#if defined(PS2) -#include -#endif - RETRO_BEGIN_DECLS #ifdef _WIN32 diff --git a/platform/libretro/libretro-common/include/compat/strcasestr.h b/platform/libretro/libretro-common/include/compat/strcasestr.h index c26de9e0..227e253e 100644 --- a/platform/libretro/libretro-common/include/compat/strcasestr.h +++ b/platform/libretro/libretro-common/include/compat/strcasestr.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 (strcasestr.h). @@ -25,10 +25,6 @@ #include -#if defined(PS2) -#include -#endif - #if defined(RARCH_INTERNAL) && defined(HAVE_CONFIG_H) #include "../../../config.h" #endif diff --git a/platform/libretro/libretro-common/include/compat/strl.h b/platform/libretro/libretro-common/include/compat/strl.h index c70f1195..5e7a892f 100644 --- a/platform/libretro/libretro-common/include/compat/strl.h +++ b/platform/libretro/libretro-common/include/compat/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 (strl.h). diff --git a/platform/libretro/libretro-common/include/encodings/utf.h b/platform/libretro/libretro-common/include/encodings/utf.h index b513f28a..bea4e145 100644 --- a/platform/libretro/libretro-common/include/encodings/utf.h +++ b/platform/libretro/libretro-common/include/encodings/utf.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, diff --git a/platform/libretro/libretro-common/include/file/file_path.h b/platform/libretro/libretro-common/include/file/file_path.h index 8d365a9c..452763fe 100644 --- a/platform/libretro/libretro-common/include/file/file_path.h +++ b/platform/libretro/libretro-common/include/file/file_path.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 (file_path.h). @@ -125,6 +125,7 @@ char *path_remove_extension(char *path); * Returns: basename from path. **/ const char *path_basename(const char *path); +const char *path_basename_nocompression(const char *path); /** * path_basedir: @@ -178,7 +179,7 @@ char *path_resolve_realpath(char *buf, size_t size, bool resolve_symlinks); * * E.g. path /a/b/e/f.cgp with base /a/b/c/d/ turns into ../../e/f.cgp **/ -void path_relative_to(char *out, const char *path, const char *base, size_t size); +size_t path_relative_to(char *out, const char *path, const char *base, size_t size); /** * path_is_absolute: @@ -226,7 +227,7 @@ void fill_pathname(char *out_path, const char *in_path, * E.g.: * out_filename = "RetroArch-{month}{day}-{Hours}{Minutes}.{@ext}" **/ -void fill_dated_filename(char *out_filename, +size_t fill_dated_filename(char *out_filename, const char *ext, size_t size); /** @@ -259,7 +260,7 @@ void fill_str_dated_filename(char *out_filename, * present in 'in_path', it will be ignored. * */ -void fill_pathname_noext(char *out_path, const char *in_path, +size_t fill_pathname_noext(char *out_path, const char *in_path, const char *replace, size_t size); /** @@ -289,7 +290,7 @@ char *find_last_slash(const char *str); * E.g..: in_dir = "/tmp/some_dir", in_basename = "/some_content/foo.c", * replace = ".asm" => in_dir = "/tmp/some_dir/foo.c.asm" **/ -void fill_pathname_dir(char *in_dir, const char *in_basename, +size_t fill_pathname_dir(char *in_dir, const char *in_basename, const char *replace, size_t size); /** @@ -300,12 +301,12 @@ void fill_pathname_dir(char *in_dir, const char *in_basename, * * Copies basename of @in_path into @out_path. **/ -void fill_pathname_base(char *out_path, const char *in_path, size_t size); +size_t fill_pathname_base(char *out_path, const char *in_path, size_t size); void fill_pathname_base_noext(char *out_dir, const char *in_path, size_t size); -void fill_pathname_base_ext(char *out, +size_t fill_pathname_base_ext(char *out, const char *in_path, const char *ext, size_t size); @@ -376,20 +377,20 @@ void fill_pathname_resolve_relative(char *out_path, const char *in_refpath, * Makes sure not to get two consecutive slashes * between directory and path. **/ -void fill_pathname_join(char *out_path, const char *dir, +size_t fill_pathname_join(char *out_path, const char *dir, const char *path, size_t size); -void fill_pathname_join_special_ext(char *out_path, +size_t fill_pathname_join_special_ext(char *out_path, const char *dir, const char *path, const char *last, const char *ext, size_t size); -void fill_pathname_join_concat_noext(char *out_path, +size_t fill_pathname_join_concat_noext(char *out_path, const char *dir, const char *path, const char *concat, size_t size); -void fill_pathname_join_concat(char *out_path, +size_t fill_pathname_join_concat(char *out_path, const char *dir, const char *path, const char *concat, size_t size); @@ -408,10 +409,10 @@ void fill_pathname_join_noext(char *out_path, * Joins a directory (@dir) and path (@path) together * using the given delimiter (@delim). **/ -void fill_pathname_join_delim(char *out_path, const char *dir, +size_t fill_pathname_join_delim(char *out_path, const char *dir, const char *path, const char delim, size_t size); -void fill_pathname_join_delim_concat(char *out_path, const char *dir, +size_t fill_pathname_join_delim_concat(char *out_path, const char *dir, const char *path, const char delim, const char *concat, size_t size); @@ -430,7 +431,7 @@ void fill_pathname_join_delim_concat(char *out_path, const char *dir, * E.g.: "/path/to/game.img" -> game.img * "/path/to/myarchive.7z#folder/to/game.img" -> game.img */ -void fill_short_pathname_representation(char* out_rep, +size_t fill_short_pathname_representation(char* out_rep, const char *in_path, size_t size); void fill_short_pathname_representation_noext(char* out_rep, @@ -442,6 +443,12 @@ void fill_pathname_expand_special(char *out_path, void fill_pathname_abbreviate_special(char *out_path, const char *in_path, size_t size); +void fill_pathname_abbreviated_or_relative(char *out_path, const char *in_refpath, const char *in_path, size_t size); + +void pathname_conform_slashes_to_os(char *path); + +void pathname_make_slashes_portable(char *path); + /** * path_basedir: * @path : path @@ -460,9 +467,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 +480,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 /** diff --git a/platform/libretro/libretro-common/include/libretro.h b/platform/libretro/libretro-common/include/libretro.h index 2f174837..2887e5e8 100644 --- a/platform/libretro/libretro-common/include/libretro.h +++ b/platform/libretro/libretro-common/include/libretro.h @@ -283,6 +283,9 @@ enum retro_language RETRO_LANGUAGE_HEBREW = 21, RETRO_LANGUAGE_ASTURIAN = 22, RETRO_LANGUAGE_FINNISH = 23, + RETRO_LANGUAGE_INDONESIAN = 24, + RETRO_LANGUAGE_SWEDISH = 25, + RETRO_LANGUAGE_UKRAINIAN = 26, RETRO_LANGUAGE_LAST, /* Ensure sizeof(enum) == sizeof(int) */ @@ -3461,6 +3464,10 @@ struct retro_core_option_definition const char *default_value; }; +#ifdef __PS3__ +#undef local +#endif + struct retro_core_options_intl { /* Pointer to an array of retro_core_option_definition structs diff --git a/platform/libretro/libretro-common/include/memmap.h b/platform/libretro/libretro-common/include/memmap.h index 277f9cb3..88978777 100644 --- a/platform/libretro/libretro-common/include/memmap.h +++ b/platform/libretro/libretro-common/include/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 (memmap.h). @@ -26,7 +26,7 @@ #include #include -#if defined(__CELLOS_LV2__) || defined(PSP) || defined(PS2) || defined(GEKKO) || defined(VITA) || defined(_XBOX) || defined(_3DS) || defined(WIIU) || defined(SWITCH) || defined(HAVE_LIBNX) +#if defined(PSP) || defined(PS2) || defined(GEKKO) || defined(VITA) || defined(_XBOX) || defined(_3DS) || defined(WIIU) || defined(SWITCH) || defined(HAVE_LIBNX) || defined(__PS3__) || defined(__PSL1GHT__) /* No mman available */ #elif defined(_WIN32) && !defined(_XBOX) #include diff --git a/platform/libretro/libretro-common/include/retro_common.h b/platform/libretro/libretro-common/include/retro_common.h index 9a1fd5fd..a715a28c 100644 --- a/platform/libretro/libretro-common/include/retro_common.h +++ b/platform/libretro/libretro-common/include/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.h). diff --git a/platform/libretro/libretro-common/include/retro_common_api.h b/platform/libretro/libretro-common/include/retro_common_api.h index d784842e..0f68b7d9 100644 --- a/platform/libretro/libretro-common/include/retro_common_api.h +++ b/platform/libretro/libretro-common/include/retro_common_api.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). diff --git a/platform/libretro/libretro-common/include/retro_dirent.h b/platform/libretro/libretro-common/include/retro_dirent.h index 8a2591bd..3b041679 100644 --- a/platform/libretro/libretro-common/include/retro_dirent.h +++ b/platform/libretro/libretro-common/include/retro_dirent.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). @@ -25,7 +25,6 @@ #include #include -#include #include diff --git a/platform/libretro/libretro-common/include/retro_endianness.h b/platform/libretro/libretro-common/include/retro_endianness.h index e721ec9d..aefffef8 100644 --- a/platform/libretro/libretro-common/include/retro_endianness.h +++ b/platform/libretro/libretro-common/include/retro_endianness.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,97 @@ #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 + +#ifdef _MSC_VER +/* MSVC pre-defines macros depending on target arch */ +#if defined (_M_IX86) || defined (_M_AMD64) || defined (_M_ARM) || defined (_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 +130,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 +142,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 +158,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 +174,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 +190,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 +206,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 +222,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 +254,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 diff --git a/platform/libretro/libretro-common/include/retro_environment.h b/platform/libretro/libretro-common/include/retro_environment.h index 4a68046b..1389eb5c 100644 --- a/platform/libretro/libretro-common/include/retro_environment.h +++ b/platform/libretro/libretro-common/include/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_environment.h). diff --git a/platform/libretro/libretro-common/include/retro_inline.h b/platform/libretro/libretro-common/include/retro_inline.h index e4a21f6c..b27d6dd6 100644 --- a/platform/libretro/libretro-common/include/retro_inline.h +++ b/platform/libretro/libretro-common/include/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_inline.h). diff --git a/platform/libretro/libretro-common/include/retro_miscellaneous.h b/platform/libretro/libretro-common/include/retro_miscellaneous.h index 3893416e..bd71c916 100644 --- a/platform/libretro/libretro-common/include/retro_miscellaneous.h +++ b/platform/libretro/libretro-common/include/retro_miscellaneous.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,17 +30,17 @@ #include #include -#if defined(_WIN32) && !defined(_XBOX) +#if defined(_WIN32) + +#if defined(_XBOX) +#include +#else #ifndef WIN32_LEAN_AND_MEAN #define WIN32_LEAN_AND_MEAN #endif #include -#elif defined(_WIN32) && defined(_XBOX) -#include #endif -#if defined(__CELLOS_LV2__) -#include #endif #include @@ -75,15 +75,17 @@ static INLINE bool bits_any_set(uint32_t* ptr, uint32_t count) } #ifndef PATH_MAX_LENGTH -#if defined(__CELLOS_LV2__) -#define PATH_MAX_LENGTH CELL_FS_MAX_FS_PATH_LENGTH -#elif defined(_XBOX1) || defined(_3DS) || defined(PSP) || defined(PS2) || defined(GEKKO)|| defined(WIIU) || defined(ORBIS) +#if defined(_XBOX1) || defined(_3DS) || defined(PSP) || defined(PS2) || defined(GEKKO)|| defined(WIIU) || defined(ORBIS) || defined(__PSL1GHT__) || defined(__PS3__) #define PATH_MAX_LENGTH 512 #else #define PATH_MAX_LENGTH 4096 #endif #endif +#ifndef NAME_MAX_LENGTH +#define NAME_MAX_LENGTH 256 +#endif + #ifndef MAX #define MAX(a, b) ((a) > (b) ? (a) : (b)) #endif @@ -106,8 +108,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 +118,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)) @@ -136,6 +138,16 @@ static INLINE bool bits_any_set(uint32_t* ptr, uint32_t count) #define BIT256_GET_PTR(a, bit) BIT256_GET(*a, bit) #define BIT256_CLEAR_ALL_PTR(a) BIT256_CLEAR_ALL(*a) +#define BIT512_SET(a, bit) BIT256_SET(a, bit) +#define BIT512_CLEAR(a, bit) BIT256_CLEAR(a, bit) +#define BIT512_GET(a, bit) BIT256_GET(a, bit) +#define BIT512_CLEAR_ALL(a) BIT256_CLEAR_ALL(a) + +#define BIT512_SET_PTR(a, bit) BIT512_SET(*a, bit) +#define BIT512_CLEAR_PTR(a, bit) BIT512_CLEAR(*a, bit) +#define BIT512_GET_PTR(a, bit) BIT512_GET(*a, bit) +#define BIT512_CLEAR_ALL_PTR(a) BIT512_CLEAR_ALL(*a) + #define BITS_COPY16_PTR(a,bits) \ { \ BIT128_CLEAR_ALL_PTR(a); \ @@ -148,6 +160,13 @@ static INLINE bool bits_any_set(uint32_t* ptr, uint32_t count) BITS_GET_ELEM_PTR(a, 0) = (bits); \ } +#define BITS_COPY64_PTR(a,bits) \ +{ \ + BIT128_CLEAR_ALL_PTR(a); \ + BITS_GET_ELEM_PTR(a, 0) = (bits); \ + BITS_GET_ELEM_PTR(a, 1) = (bits >> 32); \ +} + /* Helper macros and struct to keep track of many booleans. */ /* This struct has 256 bits. */ typedef struct @@ -155,6 +174,12 @@ typedef struct uint32_t data[8]; } retro_bits_t; +/* This struct has 512 bits. */ +typedef struct +{ + uint32_t data[16]; +} retro_bits_512_t; + #ifdef _WIN32 # ifdef _WIN64 # define PRI_SIZET PRIu64 @@ -165,7 +190,7 @@ typedef struct # define PRI_SIZET "u" # endif # endif -#elif PS2 +#elif defined(PS2) # define PRI_SIZET "u" #else # if (SIZE_MAX == 0xFFFF) diff --git a/platform/libretro/libretro-common/include/streams/file_stream.h b/platform/libretro/libretro-common/include/streams/file_stream.h index 0cfadad8..5276f87a 100644 --- a/platform/libretro/libretro-common/include/streams/file_stream.h +++ b/platform/libretro/libretro-common/include/streams/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.h). @@ -81,6 +81,8 @@ char* filestream_gets(RFILE *stream, char *s, size_t len); int filestream_getc(RFILE *stream); +int filestream_vscanf(RFILE *stream, const char* format, va_list *args); + int filestream_scanf(RFILE *stream, const char* format, ...); int filestream_eof(RFILE *stream); diff --git a/platform/libretro/libretro-common/include/streams/file_stream_transforms.h b/platform/libretro/libretro-common/include/streams/file_stream_transforms.h index 9cf15c59..327e2184 100644 --- a/platform/libretro/libretro-common/include/streams/file_stream_transforms.h +++ b/platform/libretro/libretro-common/include/streams/file_stream_transforms.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). diff --git a/platform/libretro/libretro-common/include/string/stdstring.h b/platform/libretro/libretro-common/include/string/stdstring.h index d57256a7..2dc00e33 100644 --- a/platform/libretro/libretro-common/include/string/stdstring.h +++ b/platform/libretro/libretro-common/include/string/stdstring.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[(unsigned char)(c)] & 0x20)) +#define TOUPPER(c) ((c) & ~(lr_char_props[(unsigned char)(c)] & 0x20)) + +/* C standard says \f \v are space, but this one disagrees */ +#define ISSPACE(c) (lr_char_props[(unsigned char)(c)] & 0x80) + +#define ISDIGIT(c) (lr_char_props[(unsigned char)(c)] & 0x40) +#define ISALPHA(c) (lr_char_props[(unsigned char)(c)] & 0x20) +#define ISLOWER(c) (lr_char_props[(unsigned char)(c)] & 0x04) +#define ISUPPER(c) (lr_char_props[(unsigned char)(c)] & 0x02) +#define ISALNUM(c) (lr_char_props[(unsigned char)(c)] & 0x60) +#define ISUALPHA(c) (lr_char_props[(unsigned char)(c)] & 0x28) +#define ISUALNUM(c) (lr_char_props[(unsigned char)(c)] & 0x68) +#define IS_XDIGIT(c) (lr_char_props[(unsigned char)(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,22 +130,23 @@ 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) +static INLINE bool string_starts_with_case_insensitive(const char *str, + const char *prefix) { int result = 0; - const unsigned char *p1 = (const unsigned char*)a; - const unsigned char *p2 = (const unsigned char*)b; + const unsigned char *p1 = (const unsigned char*)str; + const unsigned char *p2 = (const unsigned char*)prefix; - if (!a || !b) + if (!str || !prefix) return false; if (p1 == p2) - return false; + return true; - while ((result = tolower (*p1) - tolower (*p2++)) == 0) - if (*p1++ == '\0') + while ((result = tolower (*p1++) - tolower (*p2)) == 0) + if (*p2++ == '\0') break; - return (result == 0); + return (result == 0 || *p2 == '\0'); } char *string_to_upper(char *s); @@ -107,9 +167,61 @@ char *string_trim_whitespace_right(char *const s); /* Remove leading and trailing whitespaces */ char *string_trim_whitespace(char *const s); -/* max_lines == 0 means no limit */ -char *word_wrap(char *buffer, const char *string, - int line_width, bool unicode, unsigned max_lines); +/* + * Wraps string specified by 'src' to destination buffer + * specified by 'dst' and 'dst_size'. + * This function assumes that all glyphs in the string + * have an on-screen pixel width similar to that of + * regular Latin characters - i.e. it will not wrap + * correctly any text containing so-called 'wide' Unicode + * characters (e.g. CJK languages, emojis, etc.). + * + * @param dst pointer to destination buffer. + * @param dst_size size of destination buffer. + * @param src pointer to input string. + * @param line_width max number of characters per line. + * @param wideglyph_width not used, but is necessary to keep + * compatibility with word_wrap_wideglyph(). + * @param max_lines max lines of destination string. + * 0 means no limit. + */ +void word_wrap(char *dst, size_t dst_size, const char *src, + int line_width, int wideglyph_width, unsigned max_lines); + +/* + * Wraps string specified by 'src' to destination buffer + * specified by 'dst' and 'dst_size'. + * This function assumes that all glyphs in the string + * are: + * - EITHER 'non-wide' Unicode glyphs, with an on-screen + * pixel width similar to that of regular Latin characters + * - OR 'wide' Unicode glyphs (e.g. CJK languages, emojis, etc.) + * with an on-screen pixel width defined by 'wideglyph_width' + * Note that wrapping may occur in inappropriate locations + * if 'src' string contains 'wide' Unicode characters whose + * on-screen pixel width deviates greatly from the set + * 'wideglyph_width' value. + * + * @param dst pointer to destination buffer. + * @param dst_size size of destination buffer. + * @param src pointer to input string. + * @param line_width max number of characters per line. + * @param wideglyph_width effective width of 'wide' Unicode glyphs. + * the value here is normalised relative to the + * typical on-screen pixel width of a regular + * Latin character: + * - a regular Latin character is defined to + * have an effective width of 100 + * - wideglyph_width = 100 * (wide_character_pixel_width / latin_character_pixel_width) + * - e.g. if 'wide' Unicode characters in 'src' + * have an on-screen pixel width twice that of + * regular Latin characters, wideglyph_width + * would be 200 + * @param max_lines max lines of destination string. + * 0 means no limit. + */ +void word_wrap_wideglyph(char *dst, size_t dst_size, const char *src, + int line_width, int wideglyph_width, unsigned max_lines); /* Splits string into tokens seperated by 'delim' * > Returned token string must be free()'d @@ -121,7 +233,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 +258,30 @@ 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]; + +/* Get the total number of occurrences of a character in the given string. */ +int string_count_occurrences_single_character(char *str, char t); + +/* Replaces all spaces with the given character. */ +void string_replace_whitespace_with_single_character(char *str, char t); + +/* Replaces multiple spaces with a single space in a string. */ +void string_replace_multi_space_with_single_space(char *str); + +/* Remove all spaces from the given string. */ +void string_remove_all_whitespace(char* str_trimmed, const char* str_untrimmed); + +/* Retrieve the last occurance of the given character in a string. */ +int string_index_last_occurance(char str[], char t); + +/* Find the position of a substring in a string. */ +int string_find_index_substring_string(const char* str1, const char* str2); + RETRO_END_DECLS #endif diff --git a/platform/libretro/libretro-common/include/vfs/vfs.h b/platform/libretro/libretro-common/include/vfs/vfs.h index b876f438..bd61c69a 100644 --- a/platform/libretro/libretro-common/include/vfs/vfs.h +++ b/platform/libretro/libretro-common/include/vfs/vfs.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.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 @@ -62,29 +62,29 @@ enum vfs_scheme VFS_SCHEME_CDROM }; -#ifndef __WINRT__ +#if !(defined(__WINRT__) && defined(__cplusplus_winrt)) #ifdef VFS_FRONTEND struct retro_vfs_file_handle #else 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 diff --git a/platform/libretro/libretro-common/include/vfs/vfs_implementation.h b/platform/libretro/libretro-common/include/vfs/vfs_implementation.h index c981cf72..b88d2f3d 100644 --- a/platform/libretro/libretro-common/include/vfs/vfs_implementation.h +++ b/platform/libretro/libretro-common/include/vfs/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.h). @@ -71,6 +71,12 @@ bool retro_vfs_dirent_is_dir_impl(libretro_vfs_implementation_dir *dirstream); int retro_vfs_closedir_impl(libretro_vfs_implementation_dir *dirstream); +#ifdef __WINRT__ + +void uwp_set_acl(const wchar_t* path, const wchar_t* AccessString); + +#endif + RETRO_END_DECLS #endif diff --git a/platform/libretro/libretro-common/memmap/memmap.c b/platform/libretro/libretro-common/memmap/memmap.c new file mode 100644 index 00000000..e84e0875 --- /dev/null +++ b/platform/libretro/libretro-common/memmap/memmap.c @@ -0,0 +1,163 @@ +/* Copyright (C) 2010-2020 The RetroArch team + * + * --------------------------------------------------------------------------------------- + * The following license statement only applies to this file (memmap.c). + * --------------------------------------------------------------------------------------- + * + * Permission is hereby granted, free of charge, + * to any person obtaining a copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation the rights to + * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, + * and to permit persons to whom the Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, + * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. + * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, + * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + */ + +#include +#include + +#ifndef PROT_READ +#define PROT_READ 0x1 /* Page can be read */ +#endif + +#ifndef PROT_WRITE +#define PROT_WRITE 0x2 /* Page can be written. */ +#endif + +#ifndef PROT_READWRITE +#define PROT_READWRITE 0x3 /* Page can be written to and read from. */ +#endif + +#ifndef PROT_EXEC +#define PROT_EXEC 0x4 /* Page can be executed. */ +#endif + +#ifndef PROT_NONE +#define PROT_NONE 0x0 /* Page can not be accessed. */ +#endif + +#ifndef MAP_FAILED +#define MAP_FAILED ((void *) -1) +#endif + +#ifdef _WIN32 +void* mmap(void *addr, size_t len, int prot, int flags, + int fildes, size_t offset) +{ + void *map = (void*)NULL; + HANDLE handle = INVALID_HANDLE_VALUE; + + switch (prot) + { + case PROT_READ: + default: + handle = CreateFileMapping((HANDLE) + _get_osfhandle(fildes), 0, PAGE_READONLY, 0, + len, 0); + if (!handle) + break; + map = (void*)MapViewOfFile(handle, FILE_MAP_READ, 0, 0, len); + CloseHandle(handle); + break; + case PROT_WRITE: + handle = CreateFileMapping((HANDLE) + _get_osfhandle(fildes),0,PAGE_READWRITE,0, + len, 0); + if (!handle) + break; + map = (void*)MapViewOfFile(handle, FILE_MAP_WRITE, 0, 0, len); + CloseHandle(handle); + break; + case PROT_READWRITE: + handle = CreateFileMapping((HANDLE) + _get_osfhandle(fildes),0,PAGE_READWRITE,0, + len, 0); + if (!handle) + break; + map = (void*)MapViewOfFile(handle, FILE_MAP_ALL_ACCESS, 0, 0, len); + CloseHandle(handle); + break; + } + + if (map == (void*)NULL) + return((void*)MAP_FAILED); + return((void*) ((int8_t*)map + offset)); +} + +int munmap(void *addr, size_t length) +{ + if (!UnmapViewOfFile(addr)) + return -1; + return 0; +} + +int mprotect(void *addr, size_t len, int prot) +{ + /* Incomplete, just assumes PAGE_EXECUTE_READWRITE right now + * instead of correctly handling prot */ + prot = 0; + if (prot & (PROT_READ | PROT_WRITE | PROT_EXEC)) + prot = PAGE_EXECUTE_READWRITE; + return VirtualProtect(addr, len, prot, 0); +} + +#elif !defined(HAVE_MMAN) +void* mmap(void *addr, size_t len, int prot, int flags, + int fildes, size_t offset) +{ + return malloc(len); +} + +int munmap(void *addr, size_t len) +{ + free(addr); + return 0; +} + +int mprotect(void *addr, size_t len, int prot) +{ + /* stub - not really needed at this point + * since this codepath has no dynarecs. */ + return 0; +} + +#endif + +#if defined(__MACH__) && defined(__arm__) +#include +#endif + +int memsync(void *start, void *end) +{ + size_t len = (char*)end - (char*)start; +#if defined(__MACH__) && defined(__arm__) + sys_dcache_flush(start ,len); + sys_icache_invalidate(start, len); + return 0; +#elif defined(__arm__) && !defined(__QNX__) + (void)len; + __clear_cache(start, end); + return 0; +#elif defined(HAVE_MMAN) + return msync(start, len, MS_SYNC | MS_INVALIDATE +#ifdef __QNX__ + MS_CACHE_ONLY +#endif + ); +#else + (void)len; + return 0; +#endif +} + +int memprotect(void *addr, size_t len) +{ + return mprotect(addr, len, PROT_READ | PROT_WRITE | PROT_EXEC); +} diff --git a/platform/libretro/libretro-common/streams/file_stream.c b/platform/libretro/libretro-common/streams/file_stream.c index e3e45907..2ac5dbb8 100644 --- a/platform/libretro/libretro-common/streams/file_stream.c +++ b/platform/libretro/libretro-common/streams/file_stream.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 +#endif + +#include #include #define VFS_FRONTEND #include -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,22 +216,19 @@ 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; } -int filestream_scanf(RFILE *stream, const char* format, ...) +int filestream_vscanf(RFILE *stream, const char* format, va_list *args) { char buf[4096]; char subfmt[64]; - va_list args; - + va_list args_copy; 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) @@ -226,14 +236,22 @@ int filestream_scanf(RFILE *stream, const char* format, ...) buf[maxlen] = '\0'; - va_start(args, format); + /* Have to copy the input va_list here + * > Calling va_arg() on 'args' directly would + * cause the va_list to have an indeterminate value + * in the function calling filestream_vscanf(), + * leading to unexpected behaviour */ +#ifdef __va_copy + __va_copy(args_copy, *args); +#else + va_copy(args_copy, *args); +#endif while (*format) { if (*format == '%') { int sublen; - char* subfmtiter = subfmt; bool asterisk = false; @@ -243,19 +261,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 +287,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_copy, 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 @@ -299,24 +336,38 @@ int filestream_scanf(RFILE *stream, const char* format, ...) } } - va_end(args); - filestream_seek(stream, startpos+(bufiter-buf), RETRO_VFS_SEEK_POSITION_START); + va_end(args_copy); + filestream_seek(stream, startpos+(bufiter-buf), + RETRO_VFS_SEEK_POSITION_START); return ret; } +int filestream_scanf(RFILE *stream, const char* format, ...) +{ + int result; + va_list vl; + va_start(vl, format); + result = filestream_vscanf(stream, format, &vl); + va_end(vl); + return result; +} + int64_t filestream_seek(RFILE *stream, int64_t offset, int seek_position) { int64_t 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 +381,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 +399,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 +424,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 +438,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 +446,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 +454,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 +482,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 +523,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); @@ -481,10 +540,11 @@ int filestream_close(RFILE *stream) * @path : path to file. * @buf : buffer to allocate and read the contents of the * file into. Needs to be freed manually. + * @len : optional output integer containing bytes read. * * Read the contents of a file into @buf. * - * Returns: number of items read, -1 on error. + * Returns: non zero on success. */ int64_t filestream_read_file(const char *path, void **buf, int64_t *len) { @@ -497,8 +557,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 +575,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 +594,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 +624,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; diff --git a/platform/libretro/libretro-common/streams/file_stream_transforms.c b/platform/libretro/libretro-common/streams/file_stream_transforms.c index 0a0cd540..e94a3112 100644 --- a/platform/libretro/libretro-common/streams/file_stream_transforms.c +++ b/platform/libretro/libretro-common/streams/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 (file_stream_transforms.c). @@ -69,17 +69,27 @@ RFILE* rfopen(const char *path, const char *mode) int rfclose(RFILE* stream) { + if (!stream) + return EOF; + return filestream_close(stream); } int64_t rftell(RFILE* stream) { + if (!stream) + return -1; + return filestream_tell(stream); } int64_t rfseek(RFILE* stream, int64_t offset, int origin) { int seek_position = -1; + + if (!stream) + return -1; + switch (origin) { case SEEK_SET: @@ -99,39 +109,61 @@ int64_t rfseek(RFILE* stream, int64_t offset, int origin) int64_t rfread(void* buffer, size_t elem_size, size_t elem_count, RFILE* stream) { + if (!stream || (elem_size == 0) || (elem_count == 0)) + return 0; + return (filestream_read(stream, buffer, elem_size * elem_count) / elem_size); } char *rfgets(char *buffer, int maxCount, RFILE* stream) { + if (!stream) + return NULL; + return filestream_gets(stream, buffer, maxCount); } int rfgetc(RFILE* stream) { + if (!stream) + return EOF; + return filestream_getc(stream); } int64_t rfwrite(void const* buffer, size_t elem_size, size_t elem_count, RFILE* stream) { - return filestream_write(stream, buffer, elem_size * elem_count); + if (!stream || (elem_size == 0) || (elem_count == 0)) + return 0; + + return (filestream_write(stream, buffer, elem_size * elem_count) / elem_size); } int rfputc(int character, RFILE * stream) { - return filestream_putc(stream, character); + if (!stream) + return EOF; + + return filestream_putc(stream, character); } int64_t rfflush(RFILE * stream) { - return filestream_flush(stream); + if (!stream) + return EOF; + + return filestream_flush(stream); } int rfprintf(RFILE * stream, const char * format, ...) { int result; va_list vl; + + if (!stream) + return -1; + va_start(vl, format); result = filestream_vprintf(stream, format, vl); va_end(vl); @@ -152,8 +184,12 @@ int rfscanf(RFILE * stream, const char * format, ...) { int result; va_list vl; + + if (!stream) + return 0; + va_start(vl, format); - result = filestream_scanf(stream, format, vl); + result = filestream_vscanf(stream, format, &vl); va_end(vl); return result; } diff --git a/platform/libretro/libretro-common/string/stdstring.c b/platform/libretro/libretro-common/string/stdstring.c index e2afef14..45446ca7 100644 --- a/platform/libretro/libretro-common/string/stdstring.c +++ b/platform/libretro/libretro-common/string/stdstring.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). @@ -22,10 +22,43 @@ #include #include +#include #include #include +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 +140,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 +161,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; @@ -154,88 +187,207 @@ char *string_trim_whitespace(char *const s) return s; } -char *word_wrap(char* buffer, const char *string, int line_width, bool unicode, unsigned max_lines) +void word_wrap(char *dst, size_t dst_size, const char *src, int line_width, int wideglyph_width, unsigned max_lines) { - unsigned i = 0; - unsigned len = (unsigned)strlen(string); - unsigned lines = 1; + char *lastspace = NULL; + unsigned counter = 0; + unsigned lines = 1; + size_t src_len = strlen(src); + const char *src_end = src + src_len; + + /* Prevent buffer overflow */ + if (dst_size < src_len + 1) + return; - while (i < len) + /* Early return if src string length is less + * than line width */ + if (src_len < line_width) { - unsigned counter; - int pos = (int)(&buffer[i] - buffer); + strcpy(dst, src); + return; + } - /* copy string until the end of the line is reached */ - for (counter = 1; counter <= (unsigned)line_width; counter++) - { - const char *character; - unsigned char_len; - unsigned j = i; + while (*src != '\0') + { + unsigned char_len; + + char_len = (unsigned)(utf8skip(src, 1) - src); + counter++; - /* check if end of string reached */ - if (i == len) + if (*src == ' ') + lastspace = dst; /* Remember the location of the whitespace */ + else if (*src == '\n') + { + /* If newlines embedded in the input, + * reset the index */ + lines++; + counter = 0; + + /* Early return if remaining src string + * length is less than line width */ + if (src_end - src <= line_width) { - buffer[i] = 0; - return buffer; + strcpy(dst, src); + return; } + } - character = utf8skip(&string[i], 1); - char_len = (unsigned)(character - &string[i]); + while (char_len--) + *dst++ = *src++; - if (!unicode) - counter += char_len - 1; + if (counter >= (unsigned)line_width) + { + counter = 0; - do - { - buffer[i] = string[i]; - char_len--; - i++; - } while(char_len); - - /* check for newlines embedded in the original input - * and reset the index */ - if (buffer[j] == '\n') + if (lastspace && (max_lines == 0 || lines < max_lines)) { + /* Replace nearest (previous) whitespace + * with newline character */ + *lastspace = '\n'; lines++; - counter = 1; + + src -= dst - lastspace - 1; + dst = lastspace + 1; + lastspace = NULL; + + /* Early return if remaining src string + * length is less than line width */ + if (src_end - src < line_width) + { + strcpy(dst, src); + return; + } } } + } + + *dst = '\0'; +} - /* check for whitespace */ - if (string[i] == ' ') +void word_wrap_wideglyph(char *dst, size_t dst_size, const char *src, int line_width, int wideglyph_width, unsigned max_lines) +{ + char *lastspace = NULL; + char *lastwideglyph = NULL; + const char *src_end = src + strlen(src); + unsigned lines = 1; + /* 'line_width' means max numbers of characters per line, + * but this metric is only meaningful when dealing with + * 'regular' glyphs that have an on-screen pixel width + * similar to that of regular Latin characters. + * When handing so-called 'wide' Unicode glyphs, it is + * necessary to consider the actual on-screen pixel width + * of each character. + * In order to do this, we create a distinction between + * regular Latin 'non-wide' glyphs and 'wide' glyphs, and + * normalise all values relative to the on-screen pixel + * width of regular Latin characters: + * - Regular 'non-wide' glyphs have a normalised width of 100 + * - 'line_width' is therefore normalised to 100 * (width_in_characters) + * - 'wide' glyphs have a normalised width of + * 100 * (wide_character_pixel_width / latin_character_pixel_width) + * - When a character is detected, the position in the current + * line is incremented by the regular normalised width of 100 + * - If that character is then determined to be a 'wide' + * glyph, the position in the current line is further incremented + * by the difference between the normalised 'wide' and 'non-wide' + * width values */ + unsigned counter_normalized = 0; + int line_width_normalized = line_width * 100; + int additional_counter_normalized = wideglyph_width - 100; + + /* Early return if src string length is less + * than line width */ + if (src_end - src < line_width) + { + strlcpy(dst, src, dst_size); + return; + } + + while (*src != '\0') + { + unsigned char_len; + + char_len = (unsigned)(utf8skip(src, 1) - src); + counter_normalized += 100; + + /* Prevent buffer overflow */ + if (char_len >= dst_size) + break; + + if (*src == ' ') + lastspace = dst; /* Remember the location of the whitespace */ + else if (*src == '\n') { - if ((max_lines == 0 || lines < max_lines)) + /* If newlines embedded in the input, + * reset the index */ + lines++; + counter_normalized = 0; + + /* Early return if remaining src string + * length is less than line width */ + if (src_end - src <= line_width) { - buffer[i] = '\n'; - i++; - lines++; + strlcpy(dst, src, dst_size); + return; } } - else + else if (char_len >= 3) { - int k; + /* Remember the location of the first byte + * whose length as UTF-8 >= 3*/ + lastwideglyph = dst; + counter_normalized += additional_counter_normalized; + } - /* check for nearest whitespace back in string */ - for (k = i; k > 0; k--) - { - if (string[k] != ' ' || (max_lines != 0 && lines >= max_lines)) - continue; + dst_size -= char_len; + while (char_len--) + *dst++ = *src++; - buffer[k] = '\n'; - /* set string index back to character after this one */ - i = k + 1; + if (counter_normalized >= (unsigned)line_width_normalized) + { + counter_normalized = 0; + + if (max_lines != 0 && lines >= max_lines) + continue; + else if (lastwideglyph && (!lastspace || lastwideglyph > lastspace)) + { + /* Insert newline character */ + *lastwideglyph = '\n'; lines++; - break; + src -= dst - lastwideglyph; + dst = lastwideglyph + 1; + lastwideglyph = NULL; + + /* Early return if remaining src string + * length is less than line width */ + if (src_end - src <= line_width) + { + strlcpy(dst, src, dst_size); + return; + } + } + else if (lastspace) + { + /* Replace nearest (previous) whitespace + * with newline character */ + *lastspace = '\n'; + lines++; + src -= dst - lastspace - 1; + dst = lastspace + 1; + lastspace = NULL; + + /* Early return if remaining src string + * length is less than line width */ + if (src_end - src < line_width) + { + strlcpy(dst, src, dst_size); + return; + } } - - if (&buffer[i] - buffer == pos) - return buffer; } } - buffer[i] = 0; - - return buffer; + *dst = '\0'; } /* Splits string into tokens seperated by 'delim' @@ -248,7 +400,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 +480,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 +495,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,9 +528,105 @@ 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; } return (unsigned)strtoul(hex_str, NULL, 16); } + +/** + * Get the total number of occurrences of a character in the given string. + */ +int string_count_occurrences_single_character(char *str, char t) +{ + int ctr = 0; + int i; + + for (i = 0; str[i] != '\0'; ++i) { + if (t == str[i]) + ++ctr; + } + + return ctr; +} + +/** + * Replaces all spaces with the given character. + */ +void string_replace_whitespace_with_single_character(char *str, char t) +{ + + while (*str) { + if (isspace(*str)) + *str = t; + str++; + } +} + +/** + * Replaces multiple spaces with a single space in a string. + */ +void string_replace_multi_space_with_single_space(char *str) +{ + char *dest = str; + + while (*str != '\0') + { + while (*str == ' ' && *(str + 1) == ' ') + str++; + + *dest++ = *str++; + } + + *dest = '\0'; +} + +/** + * Remove all spaces from the given string. + */ +void string_remove_all_whitespace(char* str_trimmed, const char* str_untrimmed) +{ + while (*str_untrimmed != '\0') + { + if(!isspace(*str_untrimmed)) + { + *str_trimmed = *str_untrimmed; + str_trimmed++; + } + str_untrimmed++; + } + *str_trimmed = '\0'; +} + +/** + * Retrieve the last occurance of the given character in a string. + */ +int string_index_last_occurance(char *str, char t) +{ + const char * ret = strrchr(str, t); + if (ret) + return ret-str; + + return -1; +} + +/** + * Find the position of a substring in a string. + */ +int string_find_index_substring_string(const char* str1, const char* str2) +{ + int index; + + if (str1[0] != '\0') + { + const char *pfound = strstr(str1, str2); + if (pfound != NULL) + { + index = (pfound - str1); + return index; + } + } + + return -1; +} diff --git a/platform/libretro/libretro-common/vfs/vfs_implementation.c b/platform/libretro/libretro-common/vfs/vfs_implementation.c index 71529482..afd4f0f6 100644 --- a/platform/libretro/libretro-common/vfs/vfs_implementation.c +++ b/platform/libretro/libretro-common/vfs/vfs_implementation.c @@ -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 # endif -# if defined(PS2) -# include -# include -# endif # include # include # if !defined(VITA) @@ -66,18 +62,12 @@ # include # include # endif +# if defined(WIIU) +# include +# endif #endif -#ifdef __CELLOS_LV2__ -#include -#define O_RDONLY CELL_FS_O_RDONLY -#define O_WRONLY CELL_FS_O_WRONLY -#define O_CREAT CELL_FS_O_CREAT -#define O_TRUNC CELL_FS_O_TRUNC -#define O_RDWR CELL_FS_O_RDWR -#else #include -#endif /* TODO: Some things are duplicated but I'm really afraid of breaking other platforms by touching this */ #if defined(VITA) @@ -93,16 +83,13 @@ # if defined(PSP) # include # endif -# if defined(PS2) -# include -# endif # include # include # include # include #endif -#if (defined(__CELLOS_LV2__) && !defined(__PSL1GHT__)) || defined(__QNX__) || defined(PSP) || defined(PS2) +#if defined(__QNX__) || defined(PSP) #include /* stat() is defined here */ #endif @@ -146,20 +133,18 @@ #include #endif -#if defined(PS2) -#include -#include +#if defined(__PS3__) || defined(__PSL1GHT__) +#include +#if defined(__PSL1GHT__) +#include #endif - -#if defined(__CELLOS_LV2__) -#include #endif #if defined(VITA) #define FIO_S_ISDIR SCE_S_ISDIR #endif -#if (defined(__CELLOS_LV2__) && !defined(__PSL1GHT__)) || defined(__QNX__) || defined(PSP) +#if defined(__QNX__) || defined(PSP) #include /* stat() is defined here */ #endif @@ -173,14 +158,16 @@ #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 #include #include +#if defined(HAVE_MMAP) #include +#endif #include #include #include @@ -189,9 +176,17 @@ #include #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 +197,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 +207,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 +250,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,49 +269,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; - libretro_vfs_implementation_file *stream = (libretro_vfs_implementation_file*) - calloc(1, sizeof(*stream)); #if defined(VFS_FRONTEND) || defined(HAVE_CDROM) int path_len = (int)strlen(path); #endif - #ifdef VFS_FRONTEND const char *dumb_prefix = "vfsonly://"; - size_t dumb_prefix_siz = strlen(dumb_prefix); + size_t dumb_prefix_siz = STRLEN_CONST("vfsonly://"); int dumb_prefix_len = (int)dumb_prefix_siz; +#endif +#ifdef HAVE_CDROM + const char *cdrom_prefix = "cdrom://"; + size_t cdrom_prefix_siz = STRLEN_CONST("cdrom://"); + int cdrom_prefix_len = (int)cdrom_prefix_siz; +#endif + int flags = 0; + const char *mode_str = NULL; + libretro_vfs_implementation_file *stream = + (libretro_vfs_implementation_file*) + malloc(sizeof(*stream)); + if (!stream) + return NULL; + + 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; - } + 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) { - 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)) { - if (!memcmp(path, cdrom_prefix, cdrom_prefix_len)) - { - path += cdrom_prefix_siz; - stream->scheme = VFS_SCHEME_CDROM; - } + path += cdrom_prefix_siz; + stream->scheme = VFS_SCHEME_CDROM; } } #endif - if (!stream) - return NULL; - - (void)flags; - - stream->hints = hints; stream->orig_path = strdup(path); #ifdef HAVE_MMAP @@ -350,9 +360,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; @@ -364,9 +372,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; @@ -380,9 +386,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; @@ -403,7 +407,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 @@ -432,13 +436,30 @@ 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(WIIU) + if (stream->scheme != VFS_SCHEME_CDROM) + { + const int bufsize = 128*1024; + stream->buf = (char*)memalign(0x40, bufsize); + if (stream->fp) + setvbuf(stream->fp, stream->buf, _IOFBF, bufsize); + } if (stream->scheme != VFS_SCHEME_CDROM) { stream->buf = (char*)calloc(1, 0x4000); @@ -537,9 +558,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 { @@ -604,7 +623,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 @@ -630,9 +649,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 @@ -641,7 +662,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) @@ -865,12 +887,12 @@ const char *retro_vfs_file_get_path_impl( int retro_vfs_stat_impl(const char *path, int32_t *size) { -#if defined(VITA) || defined(PSP) - /* Vita / PSP */ - SceIoStat buf; - int stat_ret; bool is_dir = false; bool is_character_special = false; +#if defined(VITA) + /* Vita / PSP */ + SceIoStat buf; + int dir_ret; char *tmp = NULL; size_t len = 0; @@ -882,97 +904,47 @@ 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; + is_character_special = S_ISCHR(buf.st_mode); +#elif defined(__PSL1GHT__) || defined(__PS3__) + /* Lowlevel Lv2 */ + sysFSStat buf; 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__) - /* CellOS Lv2 */ - bool is_dir; - bool is_character_special = false; - CellFsStat buf; - - if (!path || !*path) - return 0; - if (cellFsStat(path, &buf) < 0) + if (sysFsStat(path, &buf) < 0) return 0; if (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); + *size = (int32_t)buf.st_size; + 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 @@ -983,8 +955,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); @@ -992,8 +964,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); @@ -1009,11 +981,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) @@ -1026,9 +1028,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) @@ -1043,27 +1044,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) +#elif defined(VITA) 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 @@ -1089,16 +1110,13 @@ struct libretro_vfs_implementation_dir HANDLE directory; bool next; char path[PATH_MAX_LENGTH]; -#elif defined(VITA) || defined(PSP) +#elif defined(VITA) SceUID directory; SceIoDirent entry; -#elif defined(PS2) +#elif defined(__PSL1GHT__) || defined(__PS3__) + int error; int directory; - iox_dirent_t entry; -#elif defined(__CELLOS_LV2__) - CellFsErrno error; - int directory; - CellFsDirent entry; + sysFSDirent entry; #elif defined(ORBIS) int directory; struct dirent entry; @@ -1112,10 +1130,10 @@ 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(ORBIS) return (rdir->directory < 0); -#elif defined(__CELLOS_LV2__) - return (rdir->error != CELL_FS_SUCCEEDED); +#elif defined(__PSL1GHT__) || defined(__PS3__) + return (rdir->error != FS_SUCCEEDED); #else return !(rdir->directory); #endif @@ -1174,15 +1192,13 @@ libretro_vfs_implementation_dir *retro_vfs_opendir_impl( free(path_wide); #endif -#elif defined(VITA) || defined(PSP) +#elif defined(VITA) 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__) - rdir->error = cellFsOpendir(name, &rdir->directory); +#elif defined(__PSL1GHT__) || defined(__PS3__) + rdir->error = sysFsOpendir(name, &rdir->directory); #elif defined(ORBIS) rdir->directory = orbisDopen(name); #else @@ -1216,16 +1232,11 @@ bool retro_vfs_readdir_impl(libretro_vfs_implementation_dir *rdir) rdir->next = true; return (rdir->directory != INVALID_HANDLE_VALUE); -#elif defined(VITA) || defined(PSP) +#elif defined(VITA) 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(__PSL1GHT__) || defined(__PS3__) uint64_t nread; - rdir->error = cellFsReaddir(rdir->directory, &rdir->entry, &nread); + rdir->error = sysFsReaddir(rdir->directory, &rdir->entry, &nread); return (nread != 0); #elif defined(ORBIS) return (orbisDread(rdir->directory, &rdir->entry) > 0); @@ -1238,29 +1249,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(ORBIS) || defined(__PSL1GHT__) || defined(__PS3__) return rdir->entry.d_name; -#elif defined(PS2) - return rdir->entry.name; #else if (!rdir || !rdir->entry) return NULL; @@ -1273,21 +1272,14 @@ bool retro_vfs_dirent_is_dir_impl(libretro_vfs_implementation_dir *rdir) #if defined(_WIN32) 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; -#if defined(PSP) - return (entry->d_stat.st_attr & FIO_SO_IFDIR) == FIO_SO_IFDIR; #elif defined(VITA) + const SceIoDirent *entry = (const SceIoDirent*)&rdir->entry; 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; - return (entry->d_type == CELL_FS_TYPE_DIRECTORY); +#elif defined(__PSL1GHT__) || defined(__PS3__) + sysFSDirent *entry = (sysFSDirent*)&rdir->entry; + return (entry->d_type == FS_TYPE_DIR); #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,12 +1312,10 @@ int retro_vfs_closedir_impl(libretro_vfs_implementation_dir *rdir) #if defined(_WIN32) if (rdir->directory != INVALID_HANDLE_VALUE) FindClose(rdir->directory); -#elif defined(VITA) || defined(PSP) +#elif defined(VITA) sceIoDclose(rdir->directory); -#elif defined(PS2) - ps2fileXioDclose(rdir->directory); -#elif defined(__CELLOS_LV2__) - rdir->error = cellFsClosedir(rdir->directory); +#elif defined(__PSL1GHT__) || defined(__PS3__) + rdir->error = sysFsClosedir(rdir->directory); #elif defined(ORBIS) orbisDclose(rdir->directory); #else diff --git a/platform/libretro/libretro.c b/platform/libretro/libretro.c index f03d4d68..2399a3c8 100644 --- a/platform/libretro/libretro.c +++ b/platform/libretro/libretro.c @@ -15,13 +15,11 @@ #include #include #ifndef _WIN32 -#ifndef NO_MMAP #ifdef __SWITCH__ #include "switch/mman.h" #else #include #endif -#endif #else #include #include @@ -340,30 +338,6 @@ static void munmap(void *addr, size_t length) UnmapViewOfFile(addr); /* ruh-ro, we leaked handle from CreateFileMapping() ... */ } -#elif defined(NO_MMAP) -#define PROT_EXEC 0x04 -#define MAP_FAILED 0 -#define PROT_READ 0 -#define PROT_WRITE 0 -#define MAP_PRIVATE 0 -#define MAP_ANONYMOUS 0 - -void* mmap(void *desired_addr, size_t len, int mmap_prot, int mmap_flags, int fildes, size_t off) -{ - return calloc(1, len); -} - -void munmap(void *base_addr, size_t len) -{ - free(base_addr); -} - -int mprotect(void *addr, size_t len, int prot) -{ - /* stub - not really needed at this point since this codepath has no dynarecs */ - return 0; -} - #endif #ifndef MAP_ANONYMOUS -- 2.39.2