diff --git a/Makefile b/Makefile index f39cfcbe..ee25f7c2 100644 --- a/Makefile +++ b/Makefile @@ -125,6 +125,12 @@ PLATFORM_MP3 = 1 endif ifeq "$(PLATFORM)" "libretro" OBJS += platform/libretro/libretro.o +OBJS += platform/libretro/libretro-common/compat/compat_strl.o +OBJS += platform/libretro/libretro-common/compat/fopen_utf8.o +OBJS += platform/libretro/libretro-common/encodings/encoding_utf.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 endif ifeq "$(USE_FRONTEND)" "1" diff --git a/Makefile.libretro b/Makefile.libretro index f2ebbc32..559e707e 100644 --- a/Makefile.libretro +++ b/Makefile.libretro @@ -30,6 +30,9 @@ AS ?= as CC_AS ?= $(CC) CFLAGS ?= +#libretro includes +CFLAGS += -I platform/libretro/libretro-common/include -I platform/libretro/libretro-common/include/compat + STATIC_LINKING:= 0 TARGET_NAME := picodrive LIBM := -lm diff --git a/platform/libretro/libretro-common/compat/compat_strl.c b/platform/libretro/libretro-common/compat/compat_strl.c new file mode 100644 index 00000000..94cb39b6 --- /dev/null +++ b/platform/libretro/libretro-common/compat/compat_strl.c @@ -0,0 +1,69 @@ +/* Copyright (C) 2010-2018 The RetroArch team + * + * --------------------------------------------------------------------------------------- + * The following license statement only applies to this file (compat_strl.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 + +#include + +/* Implementation of strlcpy()/strlcat() based on OpenBSD. */ + +#ifndef __MACH__ + +size_t strlcpy(char *dest, const char *source, size_t size) +{ + size_t src_size = 0; + size_t n = size; + + if (n) + while (--n && (*dest++ = *source++)) src_size++; + + if (!n) + { + if (size) *dest = '\0'; + while (*source++) src_size++; + } + + return src_size; +} + +size_t strlcat(char *dest, const char *source, size_t size) +{ + size_t len = strlen(dest); + + dest += len; + + if (len > size) + size = 0; + else + size -= len; + + return len + strlcpy(dest, source, size); +} +#endif + +char *strldup(const char *s, size_t n) +{ + char *dst = (char*)malloc(sizeof(char) * (n + 1)); + strlcpy(dst, s, n); + return dst; +} diff --git a/platform/libretro/libretro-common/compat/fopen_utf8.c b/platform/libretro/libretro-common/compat/fopen_utf8.c new file mode 100644 index 00000000..52b481e7 --- /dev/null +++ b/platform/libretro/libretro-common/compat/fopen_utf8.c @@ -0,0 +1,60 @@ +/* Copyright (C) 2010-2018 The RetroArch team + * + * --------------------------------------------------------------------------------------- + * The following license statement only applies to this file (fopen_utf8.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 +#include +#include + +#if defined(_WIN32_WINNT) && _WIN32_WINNT < 0x0500 || defined(_XBOX) +#ifndef LEGACY_WIN32 +#define LEGACY_WIN32 +#endif +#endif + +#ifdef _WIN32 +#undef fopen + +void *fopen_utf8(const char * filename, const char * mode) +{ +#if defined(_XBOX) + return fopen(filename, mode); +#elif defined(LEGACY_WIN32) + FILE *ret = NULL; + char * filename_local = utf8_to_local_string_alloc(filename); + + if (!filename_local) + return NULL; + ret = fopen(filename_local, mode); + if (filename_local) + free(filename_local); + return ret; +#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); + return ret; +#endif +} +#endif diff --git a/platform/libretro/libretro-common/encodings/encoding_utf.c b/platform/libretro/libretro-common/encodings/encoding_utf.c new file mode 100644 index 00000000..f7c533f1 --- /dev/null +++ b/platform/libretro/libretro-common/encodings/encoding_utf.c @@ -0,0 +1,516 @@ +/* Copyright (C) 2010-2018 The RetroArch team + * + * --------------------------------------------------------------------------------------- + * The following license statement only applies to this file (encoding_utf.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 +#include +#include + +#include +#include +#include + +#include + +#if defined(_WIN32) && !defined(_XBOX) +#include +#elif defined(_XBOX) +#include +#endif + +static unsigned leading_ones(uint8_t c) +{ + unsigned ones = 0; + while (c & 0x80) + { + ones++; + c <<= 1; + } + + return ones; +} + +/* Simple implementation. Assumes the sequence is + * properly synchronized and terminated. */ + +size_t utf8_conv_utf32(uint32_t *out, size_t out_chars, + const char *in, size_t in_size) +{ + unsigned i; + size_t ret = 0; + while (in_size && out_chars) + { + unsigned extra, shift; + uint32_t c; + uint8_t first = *in++; + unsigned ones = leading_ones(first); + + if (ones > 6 || ones == 1) /* Invalid or desync. */ + break; + + extra = ones ? ones - 1 : ones; + if (1 + extra > in_size) /* Overflow. */ + break; + + shift = (extra - 1) * 6; + c = (first & ((1 << (7 - ones)) - 1)) << (6 * extra); + + for (i = 0; i < extra; i++, in++, shift -= 6) + c |= (*in & 0x3f) << shift; + + *out++ = c; + in_size -= 1 + extra; + out_chars--; + ret++; + } + + return ret; +} + +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; + + for (;;) + { + unsigned numAdds; + uint32_t value; + + if (in_pos == in_size) + { + *out_chars = out_pos; + return true; + } + value = in[in_pos++]; + if (value < 0x80) + { + if (out) + out[out_pos] = (char)value; + out_pos++; + continue; + } + + if (value >= 0xD800 && value < 0xE000) + { + uint32_t c2; + + if (value >= 0xDC00 || in_pos == in_size) + break; + c2 = in[in_pos++]; + if (c2 < 0xDC00 || c2 >= 0xE000) + break; + value = (((value - 0xD800) << 10) | (c2 - 0xDC00)) + 0x10000; + } + + for (numAdds = 1; numAdds < 5; numAdds++) + if (value < (((uint32_t)1) << (numAdds * 5 + 6))) + break; + if (out) + out[out_pos] = (char)(kUtf8Limits[numAdds - 1] + + (value >> (6 * numAdds))); + out_pos++; + do + { + numAdds--; + if (out) + out[out_pos] = (char)(0x80 + + ((value >> (6 * numAdds)) & 0x3F)); + out_pos++; + }while (numAdds != 0); + } + + *out_chars = out_pos; + return false; +} + +/* Acts mostly like strlcpy. + * + * Copies the given number of UTF-8 characters, + * but at most d_len bytes. + * + * Always NULL terminates. + * Does not copy half a character. + * + * Returns number of bytes. 's' is assumed valid UTF-8. + * Use only if 'chars' is considerably less than 'd_len'. */ +size_t utf8cpy(char *d, size_t d_len, const char *s, size_t chars) +{ + const uint8_t *sb = (const uint8_t*)s; + const uint8_t *sb_org = sb; + + if (!s) + return 0; + + while (*sb && chars-- > 0) + { + 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--; + } + + memcpy(d, sb_org, sb-sb_org); + d[sb-sb_org] = '\0'; + + return sb-sb_org; +} + +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++; + chars--; + } while(chars); + return (const char*)strb; +} + +size_t utf8len(const char *string) +{ + size_t ret = 0; + + if (!string) + return 0; + + while (*string) + { + if ((*string & 0xC0) != 0x80) + ret++; + string++; + } + return ret; +} + +static uint8_t utf8_walkbyte(const char **string) +{ + return *((*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); + uint32_t ret = 0; + + if (first < 128) + return first; + + ret = (ret << 6) | (utf8_walkbyte(string) & 0x3F); + if (first >= 0xE0) + ret = (ret << 6) | (utf8_walkbyte(string) & 0x3F); + if (first >= 0xF0) + ret = (ret << 6) | (utf8_walkbyte(string) & 0x3F); + + if (first >= 0xF0) + return ret | (first & 7) << 18; + if (first >= 0xE0) + return ret | (first & 15) << 12; + return ret | (first & 31) << 6; +} + +static bool utf16_to_char(uint8_t **utf_data, + size_t *dest_len, const uint16_t *in) +{ + unsigned len = 0; + + while (in[len] != '\0') + len++; + + utf16_conv_utf8(NULL, dest_len, in, len); + *dest_len += 1; + *utf_data = (uint8_t*)malloc(*dest_len); + if (*utf_data == 0) + return false; + + return utf16_conv_utf8(*utf_data, dest_len, in, len); +} + +bool utf16_to_char_string(const uint16_t *in, char *s, size_t len) +{ + size_t dest_len = 0; + uint8_t *utf16_data = NULL; + bool ret = utf16_to_char(&utf16_data, &dest_len, in); + + if (ret) + { + utf16_data[dest_len] = 0; + strlcpy(s, (const char*)utf16_data, len); + } + + free(utf16_data); + utf16_data = NULL; + + return ret; +} + +/* Returned pointer MUST be freed by the caller if non-NULL. */ +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 = 0; + + if (!str || !*str) + return NULL; + + (void)path_buf; + (void)path_buf_wide; + (void)path_buf_len; + (void)path_buf_wide_len; + +#if !defined(_WIN32) || defined(_XBOX) + /* assume string needs no modification if not on Windows */ + return strdup(str); +#else +#ifdef UNICODE + /* TODO/FIXME: Not implemented. */ + return strdup(str); +#else + + /* Windows 95 will return 0 from these functions with a UTF8 codepage set without MSLU. From an unknown MSDN version (others omit this info): + * - CP_UTF8 Windows 98/Me, Windows NT 4.0 and later: Translate using UTF-8. When this is set, dwFlags must be zero. + * - Windows 95: Under the Microsoft Layer for Unicode, MultiByteToWideChar also supports CP_UTF7 and CP_UTF8. + */ + path_buf_wide_len = MultiByteToWideChar(cp_in, 0, str, -1, NULL, 0); + + if (path_buf_wide_len) + { + path_buf_wide = (wchar_t*) + calloc(path_buf_wide_len + sizeof(wchar_t), sizeof(wchar_t)); + + if (path_buf_wide) + { + MultiByteToWideChar(cp_in, 0, + str, -1, path_buf_wide, path_buf_wide_len); + + if (*path_buf_wide) + { + path_buf_len = WideCharToMultiByte(cp_out, 0, + path_buf_wide, -1, NULL, 0, NULL, NULL); + + if (path_buf_len) + { + path_buf = (char*) + calloc(path_buf_len + sizeof(char), sizeof(char)); + + if (path_buf) + { + WideCharToMultiByte(cp_out, 0, + path_buf_wide, -1, path_buf, + path_buf_len, NULL, NULL); + + free(path_buf_wide); + + if (*path_buf) + return path_buf; + + free(path_buf); + return NULL; + } + } + else + { + free(path_buf_wide); + return strdup(str); + } + } + } + } + else + return strdup(str); + + if (path_buf_wide) + free(path_buf_wide); + + return NULL; +#endif +#endif +} + +/* Returned pointer MUST be freed by the caller if non-NULL. */ +char* utf8_to_local_string_alloc(const char *str) +{ + return mb_to_mb_string_alloc(str, CODEPAGE_UTF8, CODEPAGE_LOCAL); +} + +/* Returned pointer MUST be freed by the caller if non-NULL. */ +char* local_to_utf8_string_alloc(const char *str) +{ + return mb_to_mb_string_alloc(str, CODEPAGE_LOCAL, CODEPAGE_UTF8); +} + +/* Returned pointer MUST be freed by the caller if non-NULL. */ +wchar_t* utf8_to_utf16_string_alloc(const char *str) +{ +#ifdef _WIN32 + int len = 0; + int out_len = 0; +#else + size_t len = 0; + size_t out_len = 0; +#endif + wchar_t *buf = NULL; + + if (!str || !*str) + return NULL; + +#ifdef _WIN32 + len = MultiByteToWideChar(CP_UTF8, 0, str, -1, NULL, 0); + + if (len) + { + buf = (wchar_t*)calloc(len, sizeof(wchar_t)); + + if (!buf) + return NULL; + + out_len = MultiByteToWideChar(CP_UTF8, 0, str, -1, buf, len); + } + else + { + /* fallback to ANSI codepage instead */ + len = MultiByteToWideChar(CP_ACP, 0, str, -1, NULL, 0); + + if (len) + { + buf = (wchar_t*)calloc(len, sizeof(wchar_t)); + + if (!buf) + return NULL; + + out_len = MultiByteToWideChar(CP_ACP, 0, str, -1, buf, len); + } + } + + if (out_len < 0) + { + free(buf); + return NULL; + } +#else + /* NOTE: For now, assume non-Windows platforms' locale is already UTF-8. */ + len = mbstowcs(NULL, str, 0) + 1; + + if (len) + { + buf = (wchar_t*)calloc(len, sizeof(wchar_t)); + + if (!buf) + return NULL; + + out_len = mbstowcs(buf, str, len); + } + + if (out_len == (size_t)-1) + { + free(buf); + return NULL; + } +#endif + + return buf; +} + +/* Returned pointer MUST be freed by the caller if non-NULL. */ +char* utf16_to_utf8_string_alloc(const wchar_t *str) +{ +#ifdef _WIN32 + int len = 0; + int out_len = 0; +#else + size_t len = 0; + size_t out_len = 0; +#endif + char *buf = NULL; + + if (!str || !*str) + return NULL; + +#ifdef _WIN32 + len = WideCharToMultiByte(CP_UTF8, 0, str, -1, NULL, 0, NULL, NULL); + + if (len) + { + buf = (char*)calloc(len, sizeof(char)); + + if (!buf) + return NULL; + + out_len = WideCharToMultiByte(CP_UTF8, 0, str, -1, buf, len, NULL, NULL); + } + else + { + /* fallback to ANSI codepage instead */ + len = WideCharToMultiByte(CP_ACP, 0, str, -1, NULL, 0, NULL, NULL); + + if (len) + { + buf = (char*)calloc(len, sizeof(char)); + + if (!buf) + return NULL; + + out_len = WideCharToMultiByte(CP_ACP, 0, str, -1, buf, len, NULL, NULL); + } + } + + if (out_len < 0) + { + free(buf); + return NULL; + } +#else + /* NOTE: For now, assume non-Windows platforms' locale is already UTF-8. */ + len = wcstombs(NULL, str, 0) + 1; + + if (len) + { + buf = (char*)calloc(len, sizeof(char)); + + if (!buf) + return NULL; + + out_len = wcstombs(buf, str, len); + } + + if (out_len == (size_t)-1) + { + free(buf); + return NULL; + } +#endif + + return buf; +} diff --git a/platform/libretro/libretro-common/include/boolean.h b/platform/libretro/libretro-common/include/boolean.h new file mode 100644 index 00000000..f06ac5a7 --- /dev/null +++ b/platform/libretro/libretro-common/include/boolean.h @@ -0,0 +1,39 @@ +/* Copyright (C) 2010-2018 The RetroArch team + * + * --------------------------------------------------------------------------------------- + * The following license statement only applies to this file (boolean.h). + * --------------------------------------------------------------------------------------- + * + * Permission is hereby granted, free of charge, + * to any person obtaining a copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation the rights to + * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, + * and to permit persons to whom the Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, + * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. + * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, + * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + */ + +#ifndef __LIBRETRO_SDK_BOOLEAN_H +#define __LIBRETRO_SDK_BOOLEAN_H + +#ifndef __cplusplus + +#if defined(_MSC_VER) && _MSC_VER < 1800 && !defined(SN_TARGET_PS3) +/* Hack applied for MSVC when compiling in C89 mode as it isn't C99 compliant. */ +#define bool unsigned char +#define true 1 +#define false 0 +#else +#include +#endif + +#endif + +#endif diff --git a/platform/libretro/libretro-common/include/compat/apple_compat.h b/platform/libretro/libretro-common/include/compat/apple_compat.h new file mode 100644 index 00000000..819b39ec --- /dev/null +++ b/platform/libretro/libretro-common/include/compat/apple_compat.h @@ -0,0 +1,84 @@ +/* Copyright (C) 2010-2018 The RetroArch team + * + * --------------------------------------------------------------------------------------- + * The following license statement only applies to this file (apple_compat.h). + * --------------------------------------------------------------------------------------- + * + * Permission is hereby granted, free of charge, + * to any person obtaining a copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation the rights to + * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, + * and to permit persons to whom the Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, + * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. + * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, + * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + */ + +#ifndef __APPLE_COMPAT_H +#define __APPLE_COMPAT_H + +#ifdef __APPLE__ +#include +#endif + +#ifdef __OBJC__ + +#if (MAC_OS_X_VERSION_MAX_ALLOWED <= MAC_OS_X_VERSION_10_4) +typedef int NSInteger; +typedef unsigned NSUInteger; +typedef float CGFloat; +#endif + +#ifndef __has_feature +/* Compatibility with non-Clang compilers. */ +#define __has_feature(x) 0 +#endif + +#ifndef CF_RETURNS_RETAINED +#if __has_feature(attribute_cf_returns_retained) +#define CF_RETURNS_RETAINED __attribute__((cf_returns_retained)) +#else +#define CF_RETURNS_RETAINED +#endif +#endif + +#ifndef NS_INLINE +#define NS_INLINE inline +#endif + +NS_INLINE CF_RETURNS_RETAINED CFTypeRef CFBridgingRetainCompat(id X) +{ +#if __has_feature(objc_arc) + return (__bridge_retained CFTypeRef)X; +#else + return X; +#endif +} + +#endif + +#ifdef IOS +#ifndef __IPHONE_5_0 +#warning "This project uses features only available in iOS SDK 5.0 and later." +#endif + +#ifdef __OBJC__ +#import +#import +#import +#endif + +#else + +#ifdef __OBJC__ +#include +#endif +#endif + +#endif diff --git a/platform/libretro/libretro-common/include/compat/fnmatch.h b/platform/libretro/libretro-common/include/compat/fnmatch.h new file mode 100644 index 00000000..cede1ca6 --- /dev/null +++ b/platform/libretro/libretro-common/include/compat/fnmatch.h @@ -0,0 +1,30 @@ +/* Copyright (C) 2010-2018 The RetroArch team + * + * --------------------------------------------------------------------------------------- + * The following license statement only applies to this file (fnmatch.h). + * --------------------------------------------------------------------------------------- + * + * Permission is hereby granted, free of charge, + * to any person obtaining a copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation the rights to + * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, + * and to permit persons to whom the Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, + * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. + * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, + * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + */ + +#ifndef __LIBRETRO_SDK_COMPAT_FNMATCH_H__ +#define __LIBRETRO_SDK_COMPAT_FNMATCH_H__ + +#define FNM_NOMATCH 1 + +int rl_fnmatch(const char *pattern, const char *string, int flags); + +#endif diff --git a/platform/libretro/libretro-common/include/compat/fopen_utf8.h b/platform/libretro/libretro-common/include/compat/fopen_utf8.h new file mode 100644 index 00000000..f59822a5 --- /dev/null +++ b/platform/libretro/libretro-common/include/compat/fopen_utf8.h @@ -0,0 +1,34 @@ +/* Copyright (C) 2010-2018 The RetroArch team + * + * --------------------------------------------------------------------------------------- + * The following license statement only applies to this file (fopen_utf8.h). + * --------------------------------------------------------------------------------------- + * + * Permission is hereby granted, free of charge, + * to any person obtaining a copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation the rights to + * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, + * and to permit persons to whom the Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, + * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. + * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, + * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + */ + +#ifndef __LIBRETRO_SDK_COMPAT_FOPEN_UTF8_H +#define __LIBRETRO_SDK_COMPAT_FOPEN_UTF8_H + +#ifdef _WIN32 +/* Defined to error rather than fopen_utf8, to make it clear to everyone reading the code that not worrying about utf16 is fine */ +/* TODO: enable */ +/* #define fopen (use fopen_utf8 instead) */ +void *fopen_utf8(const char * filename, const char * mode); +#else +#define fopen_utf8 fopen +#endif +#endif diff --git a/platform/libretro/libretro-common/include/compat/getopt.h b/platform/libretro/libretro-common/include/compat/getopt.h new file mode 100644 index 00000000..74287b64 --- /dev/null +++ b/platform/libretro/libretro-common/include/compat/getopt.h @@ -0,0 +1,75 @@ +/* Copyright (C) 2010-2018 The RetroArch team + * + * --------------------------------------------------------------------------------------- + * The following license statement only applies to this file (getopt.h). + * --------------------------------------------------------------------------------------- + * + * Permission is hereby granted, free of charge, + * to any person obtaining a copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation the rights to + * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, + * and to permit persons to whom the Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, + * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. + * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, + * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + */ + +#ifndef __LIBRETRO_SDK_COMPAT_GETOPT_H +#define __LIBRETRO_SDK_COMPAT_GETOPT_H + +#if defined(RARCH_INTERNAL) && defined(HAVE_CONFIG_H) +#include "../../../config.h" +#endif + +/* Custom implementation of the GNU getopt_long for portability. + * Not designed to be fully compatible, but compatible with + * the features RetroArch uses. */ + +#ifdef HAVE_GETOPT_LONG +#include +#else +/* Avoid possible naming collisions during link since we + * prefer to use the actual name. */ +#define getopt_long(argc, argv, optstring, longopts, longindex) __getopt_long_retro(argc, argv, optstring, longopts, longindex) + +#include + +RETRO_BEGIN_DECLS + +struct option +{ + const char *name; + int has_arg; + int *flag; + int val; +}; + +/* argv[] is declared with char * const argv[] in GNU, + * but this makes no sense, as non-POSIX getopt_long + * mutates argv (non-opts are moved to the end). */ +int getopt_long(int argc, char *argv[], + const char *optstring, const struct option *longopts, int *longindex); +extern char *optarg; +extern int optind, opterr, optopt; + +RETRO_END_DECLS + +/* If these are variously #defined, then we have bigger problems */ +#ifndef no_argument + #define no_argument 0 + #define required_argument 1 + #define optional_argument 2 +#endif + +/* HAVE_GETOPT_LONG */ +#endif + +/* pragma once */ +#endif + diff --git a/platform/libretro/libretro-common/include/compat/ifaddrs.h b/platform/libretro/libretro-common/include/compat/ifaddrs.h new file mode 100644 index 00000000..2dc68487 --- /dev/null +++ b/platform/libretro/libretro-common/include/compat/ifaddrs.h @@ -0,0 +1,53 @@ +/* + * Copyright (c) 1995, 1999 + * Berkeley Software Design, Inc. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * THIS SOFTWARE IS PROVIDED BY Berkeley Software Design, Inc. ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL Berkeley Software Design, Inc. BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * BSDI ifaddrs.h,v 2.5 2000/02/23 14:51:59 dab Exp + */ + +#ifndef _IFADDRS_H_ +#define _IFADDRS_H_ + +struct ifaddrs +{ + struct ifaddrs *ifa_next; + char *ifa_name; + unsigned int ifa_flags; + struct sockaddr *ifa_addr; + struct sockaddr *ifa_netmask; + struct sockaddr *ifa_dstaddr; + void *ifa_data; +}; + +/* + * This may have been defined in . Note that if is + * to be included it must be included before this header file. + */ +#ifndef ifa_broadaddr +#define ifa_broadaddr ifa_dstaddr /* broadcast address interface */ +#endif + +#include + +extern int getifaddrs(struct ifaddrs **ifap); +extern void freeifaddrs(struct ifaddrs *ifa); + +#endif diff --git a/platform/libretro/libretro-common/include/compat/intrinsics.h b/platform/libretro/libretro-common/include/compat/intrinsics.h new file mode 100644 index 00000000..3fc7d929 --- /dev/null +++ b/platform/libretro/libretro-common/include/compat/intrinsics.h @@ -0,0 +1,85 @@ +/* Copyright (C) 2010-2018 The RetroArch team + * + * --------------------------------------------------------------------------------------- + * The following license statement only applies to this file (intrinsics.h). + * --------------------------------------------------------------------------------------- + * + * Permission is hereby granted, free of charge, + * to any person obtaining a copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation the rights to + * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, + * and to permit persons to whom the Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, + * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. + * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, + * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + */ + +#ifndef __LIBRETRO_SDK_COMPAT_INTRINSICS_H +#define __LIBRETRO_SDK_COMPAT_INTRINSICS_H + +#include +#include +#include + +#include +#include + +#if defined(_MSC_VER) && !defined(_XBOX) +#if (_MSC_VER > 1310) +#include +#endif +#endif + +RETRO_BEGIN_DECLS + +/* Count Leading Zero, unsigned 16bit input value */ +static INLINE unsigned compat_clz_u16(uint16_t val) +{ +#ifdef __GNUC__ + return __builtin_clz(val << 16 | 0x8000); +#else + unsigned ret = 0; + + while(!(val & 0x8000) && ret < 16) + { + val <<= 1; + ret++; + } + + return ret; +#endif +} + +/* Count Trailing Zero */ +static INLINE int compat_ctz(unsigned x) +{ +#if defined(__GNUC__) && !defined(RARCH_CONSOLE) + return __builtin_ctz(x); +#elif _MSC_VER >= 1400 && !defined(_XBOX) + unsigned long r = 0; + _BitScanReverse((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; +#endif +} + +RETRO_END_DECLS + +#endif diff --git a/platform/libretro/libretro-common/include/compat/msvc.h b/platform/libretro/libretro-common/include/compat/msvc.h new file mode 100644 index 00000000..822c9733 --- /dev/null +++ b/platform/libretro/libretro-common/include/compat/msvc.h @@ -0,0 +1,128 @@ +/* Copyright (C) 2010-2018 The RetroArch team + * + * --------------------------------------------------------------------------------------- + * The following license statement only applies to this file (msvc.h). + * --------------------------------------------------------------------------------------- + * + * Permission is hereby granted, free of charge, + * to any person obtaining a copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation the rights to + * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, + * and to permit persons to whom the Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, + * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. + * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, + * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + */ + +#ifndef __LIBRETRO_SDK_COMPAT_MSVC_H +#define __LIBRETRO_SDK_COMPAT_MSVC_H + +#ifdef _MSC_VER + +#ifdef __cplusplus +extern "C" { +#endif + +/* Pre-MSVC 2015 compilers don't implement snprintf in a cross-platform manner. */ +#if _MSC_VER < 1900 + #include + #ifndef snprintf + #define snprintf c99_snprintf_retro__ + #endif + + int c99_snprintf_retro__(char *outBuf, size_t size, const char *format, ...); +#endif + +/* Pre-MSVC 2010 compilers don't implement vsnprintf in a cross-platform manner? Not sure about this one. */ +#if _MSC_VER < 1600 + #include + #include + #ifndef vsnprintf + #define vsnprintf c99_vsnprintf_retro__ + #endif + int c99_vsnprintf_retro__(char *outBuf, size_t size, const char *format, va_list ap); +#endif + +#ifdef __cplusplus +} +#endif + +#undef UNICODE /* Do not bother with UNICODE at this time. */ +#include +#include +#include + +/* Python headers defines ssize_t and sets HAVE_SSIZE_T. + * Cannot duplicate these efforts. + */ +#ifndef HAVE_SSIZE_T +#if defined(_WIN64) +typedef __int64 ssize_t; +#elif defined(_WIN32) +typedef int ssize_t; +#endif +#endif + +#define mkdir(dirname, unused) _mkdir(dirname) +#define strtoull _strtoui64 +#undef strcasecmp +#define strcasecmp _stricmp +#undef strncasecmp +#define strncasecmp _strnicmp + +/* Disable some of the annoying warnings. */ +#pragma warning(disable : 4800) +#pragma warning(disable : 4805) +#pragma warning(disable : 4244) +#pragma warning(disable : 4305) +#pragma warning(disable : 4146) +#pragma warning(disable : 4267) +#pragma warning(disable : 4723) +#pragma warning(disable : 4996) + +/* roundf and va_copy is available since MSVC 2013 */ +#if _MSC_VER < 1800 +#define roundf(in) (in >= 0.0f ? floorf(in + 0.5f) : ceilf(in - 0.5f)) +#define va_copy(x, y) ((x) = (y)) +#endif + +#if _MSC_VER <= 1310 + #ifndef __cplusplus + /* VC6 math.h doesn't define some functions when in C mode. + * Trying to define a prototype gives "undefined reference". + * But providing an implementation then gives "function already has body". + * So the equivalent of the implementations from math.h are used as + * defines here instead, and it seems to work. + */ + #define cosf(x) ((float)cos((double)x)) + #define powf(x, y) ((float)pow((double)x, (double)y)) + #define sinf(x) ((float)sin((double)x)) + #define ceilf(x) ((float)ceil((double)x)) + #define floorf(x) ((float)floor((double)x)) + #define sqrtf(x) ((float)sqrt((double)x)) + #define fabsf(x) ((float)fabs((double)(x))) + #endif + + #ifndef _strtoui64 + #define _strtoui64(x, y, z) (_atoi64(x)) + #endif + +#endif + +#ifndef PATH_MAX +#define PATH_MAX _MAX_PATH +#endif + +#ifndef SIZE_MAX +#define SIZE_MAX _UI32_MAX +#endif + +#endif +#endif + diff --git a/platform/libretro/libretro-common/include/compat/msvc/stdint.h b/platform/libretro/libretro-common/include/compat/msvc/stdint.h new file mode 100644 index 00000000..c791176c --- /dev/null +++ b/platform/libretro/libretro-common/include/compat/msvc/stdint.h @@ -0,0 +1,258 @@ +/* ISO C9x compliant stdint.h for Microsoft Visual Studio + * Based on ISO/IEC 9899:TC2 Committee draft (May 6, 2005) WG14/N1124 + * + * Copyright (c) 2006-2008 Alexander Chemeris + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * 3. The name of the author may be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO + * EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; + * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, + * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR + * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF + * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef __RARCH_STDINT_H +#define __RARCH_STDINT_H + +#if _MSC_VER && (_MSC_VER < 1600) +/* Pre-MSVC 2010 needs an implementation of stdint.h. */ + +#if _MSC_VER > 1000 +#pragma once +#endif + +#include + +/* For Visual Studio 6 in C++ mode and for many Visual Studio versions when + * compiling for ARM we should wrap include with 'extern "C++" {}' + * or compiler give many errors like this: + * + * error C2733: second C linkage of overloaded function 'wmemchr' not allowed + */ +#ifdef __cplusplus +#if _MSC_VER <= 1200 +extern "C++" { +#else +extern "C" { +#endif +#endif +# include +#ifdef __cplusplus +} +#endif + +/* Define _W64 macros to mark types changing their size, like intptr_t. */ +#ifndef _W64 +# if !defined(__midl) && (defined(_X86_) || defined(_M_IX86)) && _MSC_VER >= 1300 +# define _W64 __w64 +# else +# define _W64 +# endif +#endif + + +/* 7.18.1 Integer types. */ + +/* 7.18.1.1 Exact-width integer types. */ + +/* Visual Studio 6 and Embedded Visual C++ 4 doesn't + * realize that, e.g. char has the same size as __int8 + * so we give up on __intX for them. + */ +#if (_MSC_VER < 1300) + typedef signed char int8_t; + typedef signed short int16_t; + typedef signed int int32_t; + typedef unsigned char uint8_t; + typedef unsigned short uint16_t; + typedef unsigned int uint32_t; +#else + typedef signed __int8 int8_t; + typedef signed __int16 int16_t; + typedef signed __int32 int32_t; + typedef unsigned __int8 uint8_t; + typedef unsigned __int16 uint16_t; + typedef unsigned __int32 uint32_t; +#endif +typedef signed __int64 int64_t; +typedef unsigned __int64 uint64_t; + + +/* 7.18.1.2 Minimum-width integer types. */ +typedef int8_t int_least8_t; +typedef int16_t int_least16_t; +typedef int32_t int_least32_t; +typedef int64_t int_least64_t; +typedef uint8_t uint_least8_t; +typedef uint16_t uint_least16_t; +typedef uint32_t uint_least32_t; +typedef uint64_t uint_least64_t; + +/* 7.18.1.3 Fastest minimum-width integer types. */ +typedef int8_t int_fast8_t; +typedef int16_t int_fast16_t; +typedef int32_t int_fast32_t; +typedef int64_t int_fast64_t; +typedef uint8_t uint_fast8_t; +typedef uint16_t uint_fast16_t; +typedef uint32_t uint_fast32_t; +typedef uint64_t uint_fast64_t; + +/* 7.18.1.4 Integer types capable of holding object pointers. */ +#ifdef _WIN64 /* [ */ + typedef signed __int64 intptr_t; + typedef unsigned __int64 uintptr_t; +#else /* _WIN64 ][ */ + typedef _W64 signed int intptr_t; + typedef _W64 unsigned int uintptr_t; +#endif /* _WIN64 ] */ + +/* 7.18.1.5 Greatest-width integer types. */ +typedef int64_t intmax_t; +typedef uint64_t uintmax_t; + +/* 7.18.2 Limits of specified-width integer types. */ + +#if !defined(__cplusplus) || defined(__STDC_LIMIT_MACROS) +/* [ See footnote 220 at page 257 and footnote 221 at page 259. */ + +/* 7.18.2.1 Limits of exact-width integer types. */ +#define INT8_MIN ((int8_t)_I8_MIN) +#define INT8_MAX _I8_MAX +#define INT16_MIN ((int16_t)_I16_MIN) +#define INT16_MAX _I16_MAX +#define INT32_MIN ((int32_t)_I32_MIN) +#define INT32_MAX _I32_MAX +#define INT64_MIN ((int64_t)_I64_MIN) +#define INT64_MAX _I64_MAX +#define UINT8_MAX _UI8_MAX +#define UINT16_MAX _UI16_MAX +#define UINT32_MAX _UI32_MAX +#define UINT64_MAX _UI64_MAX + +/* 7.18.2.2 Limits of minimum-width integer types. */ +#define INT_LEAST8_MIN INT8_MIN +#define INT_LEAST8_MAX INT8_MAX +#define INT_LEAST16_MIN INT16_MIN +#define INT_LEAST16_MAX INT16_MAX +#define INT_LEAST32_MIN INT32_MIN +#define INT_LEAST32_MAX INT32_MAX +#define INT_LEAST64_MIN INT64_MIN +#define INT_LEAST64_MAX INT64_MAX +#define UINT_LEAST8_MAX UINT8_MAX +#define UINT_LEAST16_MAX UINT16_MAX +#define UINT_LEAST32_MAX UINT32_MAX +#define UINT_LEAST64_MAX UINT64_MAX + +/* 7.18.2.3 Limits of fastest minimum-width integer types. */ +#define INT_FAST8_MIN INT8_MIN +#define INT_FAST8_MAX INT8_MAX +#define INT_FAST16_MIN INT16_MIN +#define INT_FAST16_MAX INT16_MAX +#define INT_FAST32_MIN INT32_MIN +#define INT_FAST32_MAX INT32_MAX +#define INT_FAST64_MIN INT64_MIN +#define INT_FAST64_MAX INT64_MAX +#define UINT_FAST8_MAX UINT8_MAX +#define UINT_FAST16_MAX UINT16_MAX +#define UINT_FAST32_MAX UINT32_MAX +#define UINT_FAST64_MAX UINT64_MAX + +/* 7.18.2.4 Limits of integer types capable of holding object pointers. */ +#ifdef _WIN64 /* [ */ +# define INTPTR_MIN INT64_MIN +# define INTPTR_MAX INT64_MAX +# define UINTPTR_MAX UINT64_MAX +#else /* _WIN64 ][ */ +# define INTPTR_MIN INT32_MIN +# define INTPTR_MAX INT32_MAX +# define UINTPTR_MAX UINT32_MAX +#endif /* _WIN64 ] */ + +/* 7.18.2.5 Limits of greatest-width integer types */ +#define INTMAX_MIN INT64_MIN +#define INTMAX_MAX INT64_MAX +#define UINTMAX_MAX UINT64_MAX + +/* 7.18.3 Limits of other integer types */ + +#ifdef _WIN64 /* [ */ +# define PTRDIFF_MIN _I64_MIN +# define PTRDIFF_MAX _I64_MAX +#else /* _WIN64 ][ */ +# define PTRDIFF_MIN _I32_MIN +# define PTRDIFF_MAX _I32_MAX +#endif /* _WIN64 ] */ + +#define SIG_ATOMIC_MIN INT_MIN +#define SIG_ATOMIC_MAX INT_MAX + +#ifndef SIZE_MAX /* [ */ +# ifdef _WIN64 /* [ */ +# define SIZE_MAX _UI64_MAX +# else /* _WIN64 ][ */ +# define SIZE_MAX _UI32_MAX +# endif /* _WIN64 ] */ +#endif /* SIZE_MAX ] */ + +/* WCHAR_MIN and WCHAR_MAX are also defined in */ +#ifndef WCHAR_MIN /* [ */ +# define WCHAR_MIN 0 +#endif /* WCHAR_MIN ] */ +#ifndef WCHAR_MAX // [ +# define WCHAR_MAX _UI16_MAX +#endif /* WCHAR_MAX ] */ + +#define WINT_MIN 0 +#define WINT_MAX _UI16_MAX + +#endif /* __STDC_LIMIT_MACROS ] */ + +/* 7.18.4 Limits of other integer types */ + +#if !defined(__cplusplus) || defined(__STDC_CONSTANT_MACROS) +/* [ See footnote 224 at page 260 */ + +/* 7.18.4.1 Macros for minimum-width integer constants */ + +#define INT8_C(val) val##i8 +#define INT16_C(val) val##i16 +#define INT32_C(val) val##i32 +#define INT64_C(val) val##i64 + +#define UINT8_C(val) val##ui8 +#define UINT16_C(val) val##ui16 +#define UINT32_C(val) val##ui32 +#define UINT64_C(val) val##ui64 + +/* 7.18.4.2 Macros for greatest-width integer constants */ +#define INTMAX_C INT64_C +#define UINTMAX_C UINT64_C + +#endif +/* __STDC_CONSTANT_MACROS ] */ + +#else +/* Sanity for everything else. */ +#include +#endif + +#endif + diff --git a/platform/libretro/libretro-common/include/compat/posix_string.h b/platform/libretro/libretro-common/include/compat/posix_string.h new file mode 100644 index 00000000..9f56322a --- /dev/null +++ b/platform/libretro/libretro-common/include/compat/posix_string.h @@ -0,0 +1,61 @@ +/* Copyright (C) 2010-2018 The RetroArch team + * + * --------------------------------------------------------------------------------------- + * The following license statement only applies to this file (posix_string.h). + * --------------------------------------------------------------------------------------- + * + * Permission is hereby granted, free of charge, + * to any person obtaining a copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation the rights to + * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, + * and to permit persons to whom the Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, + * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. + * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, + * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + */ + +#ifndef __LIBRETRO_SDK_COMPAT_POSIX_STRING_H +#define __LIBRETRO_SDK_COMPAT_POSIX_STRING_H + +#include + +#ifdef _MSC_VER +#include +#endif + +RETRO_BEGIN_DECLS + +#ifdef _WIN32 +#undef strtok_r +#define strtok_r(str, delim, saveptr) retro_strtok_r__(str, delim, saveptr) + +char *strtok_r(char *str, const char *delim, char **saveptr); +#endif + +#ifdef _MSC_VER +#undef strcasecmp +#undef strdup +#define strcasecmp(a, b) retro_strcasecmp__(a, b) +#define strdup(orig) retro_strdup__(orig) +int strcasecmp(const char *a, const char *b); +char *strdup(const char *orig); + +/* isblank is available since MSVC 2013 */ +#if _MSC_VER < 1800 +#undef isblank +#define isblank(c) retro_isblank__(c) +int isblank(int c); +#endif + +#endif + + +RETRO_END_DECLS + +#endif diff --git a/platform/libretro/libretro-common/include/compat/strcasestr.h b/platform/libretro/libretro-common/include/compat/strcasestr.h new file mode 100644 index 00000000..f849593b --- /dev/null +++ b/platform/libretro/libretro-common/include/compat/strcasestr.h @@ -0,0 +1,49 @@ +/* Copyright (C) 2010-2018 The RetroArch team + * + * --------------------------------------------------------------------------------------- + * The following license statement only applies to this file (strcasestr.h). + * --------------------------------------------------------------------------------------- + * + * Permission is hereby granted, free of charge, + * to any person obtaining a copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation the rights to + * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, + * and to permit persons to whom the Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, + * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. + * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, + * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + */ + +#ifndef __LIBRETRO_SDK_COMPAT_STRCASESTR_H +#define __LIBRETRO_SDK_COMPAT_STRCASESTR_H + +#include + +#if defined(RARCH_INTERNAL) && defined(HAVE_CONFIG_H) +#include "../../../config.h" +#endif + +#ifndef HAVE_STRCASESTR + +#include + +RETRO_BEGIN_DECLS + +/* Avoid possible naming collisions during link + * since we prefer to use the actual name. */ +#define strcasestr(haystack, needle) strcasestr_retro__(haystack, needle) + +char *strcasestr(const char *haystack, const char *needle); + +RETRO_END_DECLS + +#endif + +#endif + diff --git a/platform/libretro/libretro-common/include/compat/strl.h b/platform/libretro/libretro-common/include/compat/strl.h new file mode 100644 index 00000000..290498d9 --- /dev/null +++ b/platform/libretro/libretro-common/include/compat/strl.h @@ -0,0 +1,60 @@ +/* Copyright (C) 2010-2018 The RetroArch team + * + * --------------------------------------------------------------------------------------- + * The following license statement only applies to this file (strl.h). + * --------------------------------------------------------------------------------------- + * + * Permission is hereby granted, free of charge, + * to any person obtaining a copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation the rights to + * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, + * and to permit persons to whom the Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, + * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. + * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, + * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + */ + +#ifndef __LIBRETRO_SDK_COMPAT_STRL_H +#define __LIBRETRO_SDK_COMPAT_STRL_H + +#include +#include + +#if defined(RARCH_INTERNAL) && defined(HAVE_CONFIG_H) +#include "../../../config.h" +#endif + +#include + +RETRO_BEGIN_DECLS + +#ifdef __MACH__ +#ifndef HAVE_STRL +#define HAVE_STRL +#endif +#endif + +#ifndef HAVE_STRL +/* Avoid possible naming collisions during link since + * we prefer to use the actual name. */ +#define strlcpy(dst, src, size) strlcpy_retro__(dst, src, size) + +#define strlcat(dst, src, size) strlcat_retro__(dst, src, size) + +size_t strlcpy(char *dest, const char *source, size_t size); +size_t strlcat(char *dest, const char *source, size_t size); + +#endif + +char *strldup(const char *s, size_t n); + +RETRO_END_DECLS + +#endif + diff --git a/platform/libretro/libretro-common/include/encodings/utf.h b/platform/libretro/libretro-common/include/encodings/utf.h new file mode 100644 index 00000000..b513f28a --- /dev/null +++ b/platform/libretro/libretro-common/include/encodings/utf.h @@ -0,0 +1,67 @@ +/* Copyright (C) 2010-2018 The RetroArch team + * + * --------------------------------------------------------------------------------------- + * The following license statement only applies to this file (utf.h). + * --------------------------------------------------------------------------------------- + * + * Permission is hereby granted, free of charge, + * to any person obtaining a copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation the rights to + * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, + * and to permit persons to whom the Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, + * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. + * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, + * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + */ + +#ifndef _LIBRETRO_ENCODINGS_UTF_H +#define _LIBRETRO_ENCODINGS_UTF_H + +#include +#include + +#include + +#include + +RETRO_BEGIN_DECLS + +enum CodePage +{ + CODEPAGE_LOCAL = 0, /* CP_ACP */ + CODEPAGE_UTF8 = 65001 /* CP_UTF8 */ +}; + +size_t utf8_conv_utf32(uint32_t *out, size_t out_chars, + const char *in, size_t in_size); + +bool utf16_conv_utf8(uint8_t *out, size_t *out_chars, + const uint16_t *in, size_t in_size); + +size_t utf8len(const char *string); + +size_t utf8cpy(char *d, size_t d_len, const char *s, size_t chars); + +const char *utf8skip(const char *str, size_t chars); + +uint32_t utf8_walk(const char **string); + +bool utf16_to_char_string(const uint16_t *in, char *s, size_t len); + +char* utf8_to_local_string_alloc(const char *str); + +char* local_to_utf8_string_alloc(const char *str); + +wchar_t* utf8_to_utf16_string_alloc(const char *str); + +char* utf16_to_utf8_string_alloc(const wchar_t *str); + +RETRO_END_DECLS + +#endif diff --git a/platform/libretro/libretro.h b/platform/libretro/libretro-common/include/libretro.h similarity index 100% rename from platform/libretro/libretro.h rename to platform/libretro/libretro-common/include/libretro.h diff --git a/platform/libretro/libretro-common/include/memmap.h b/platform/libretro/libretro-common/include/memmap.h new file mode 100644 index 00000000..2bedd5c9 --- /dev/null +++ b/platform/libretro/libretro-common/include/memmap.h @@ -0,0 +1,52 @@ +/* Copyright (C) 2010-2018 The RetroArch team + * + * --------------------------------------------------------------------------------------- + * The following license statement only applies to this file (memmap.h). + * --------------------------------------------------------------------------------------- + * + * Permission is hereby granted, free of charge, + * to any person obtaining a copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation the rights to + * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, + * and to permit persons to whom the Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, + * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. + * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, + * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + */ + +#ifndef _LIBRETRO_MEMMAP_H +#define _LIBRETRO_MEMMAP_H + +#include +#include + +#if defined(__CELLOS_LV2__) || defined(PSP) || defined(GEKKO) || defined(VITA) || defined(_XBOX) || defined(_3DS) || defined(WIIU) || defined(SWITCH) +/* No mman available */ +#elif defined(_WIN32) && !defined(_XBOX) +#include +#include +#include +#else +#define HAVE_MMAN +#include +#endif + +#if !defined(HAVE_MMAN) || defined(_WIN32) +void* mmap(void *addr, size_t len, int mmap_prot, int mmap_flags, int fildes, size_t off); + +int munmap(void *addr, size_t len); + +int mprotect(void *addr, size_t len, int prot); +#endif + +int memsync(void *start, void *end); + +int memprotect(void *addr, size_t len); + +#endif diff --git a/platform/libretro/libretro-common/include/retro_common.h b/platform/libretro/libretro-common/include/retro_common.h new file mode 100644 index 00000000..e4804fae --- /dev/null +++ b/platform/libretro/libretro-common/include/retro_common.h @@ -0,0 +1,37 @@ +/* Copyright (C) 2010-2018 The RetroArch team + * + * --------------------------------------------------------------------------------------- + * The following license statement only applies to this file (retro_common.h). + * --------------------------------------------------------------------------------------- + * + * Permission is hereby granted, free of charge, + * to any person obtaining a copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation the rights to + * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, + * and to permit persons to whom the Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, + * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. + * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, + * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + */ + +#ifndef _LIBRETRO_COMMON_RETRO_COMMON_H +#define _LIBRETRO_COMMON_RETRO_COMMON_H + +/* +This file is designed to normalize the libretro-common compiling environment. +It is not to be used in public API headers, as they should be designed as leanly as possible. +Nonetheless.. in the meantime, if you do something like use ssize_t, which is not fully portable, +in a public API, you may need this. +*/ + +/* conditional compilation is handled inside here */ +#include + +#endif + diff --git a/platform/libretro/libretro-common/include/retro_common_api.h b/platform/libretro/libretro-common/include/retro_common_api.h new file mode 100644 index 00000000..c3b3f492 --- /dev/null +++ b/platform/libretro/libretro-common/include/retro_common_api.h @@ -0,0 +1,118 @@ +/* Copyright (C) 2010-2018 The RetroArch team + * + * --------------------------------------------------------------------------------------- + * The following license statement only applies to this file (retro_common_api.h). + * --------------------------------------------------------------------------------------- + * + * Permission is hereby granted, free of charge, + * to any person obtaining a copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation the rights to + * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, + * and to permit persons to whom the Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, + * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. + * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, + * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + */ + +#ifndef _LIBRETRO_COMMON_RETRO_COMMON_API_H +#define _LIBRETRO_COMMON_RETRO_COMMON_API_H + +/* +This file is designed to normalize the libretro-common compiling environment +for public API headers. This should be leaner than a normal compiling environment, +since it gets #included into other project's sources. +*/ + +/* ------------------------------------ */ + +/* +Ordinarily we want to put #ifdef __cplusplus extern "C" in C library +headers to enable them to get used by c++ sources. +However, we want to support building this library as C++ as well, so a +special technique is called for. +*/ + +#define RETRO_BEGIN_DECLS +#define RETRO_END_DECLS + +#ifdef __cplusplus + +#ifdef CXX_BUILD +/* build wants everything to be built as c++, so no extern "C" */ +#else +#undef RETRO_BEGIN_DECLS +#undef RETRO_END_DECLS +#define RETRO_BEGIN_DECLS extern "C" { +#define RETRO_END_DECLS } +#endif + +#else + +/* header is included by a C source file, so no extern "C" */ + +#endif + +/* +IMO, this non-standard ssize_t should not be used. +However, it's a good example of how to handle something like this. +*/ +#ifdef _MSC_VER +#ifndef HAVE_SSIZE_T +#define HAVE_SSIZE_T +#if defined(_WIN64) +typedef __int64 ssize_t; +#elif defined(_WIN32) +typedef int ssize_t; +#endif +#endif +#elif defined(__MACH__) +#include +#endif + +#ifdef _MSC_VER +#if _MSC_VER >= 1800 +#include +#else +#ifndef PRId64 +#define PRId64 "I64d" +#define PRIu64 "I64u" +#define PRIuPTR "Iu" +#endif +#endif +#else +/* C++11 says this one isn't needed, but apparently (some versions of) mingw require it anyways */ +/* https://stackoverflow.com/questions/8132399/how-to-printf-uint64-t-fails-with-spurious-trailing-in-format */ +/* https://github.com/libretro/RetroArch/issues/6009 */ +#define __STDC_FORMAT_MACROS +#include +#endif +#ifndef PRId64 +#error "inttypes.h is being screwy" +#endif +#define STRING_REP_INT64 "%" PRId64 +#define STRING_REP_UINT64 "%" PRIu64 +#define STRING_REP_USIZE "%" PRIuPTR + +/* +I would like to see retro_inline.h moved in here; possibly boolean too. + +rationale: these are used in public APIs, and it is easier to find problems +and write code that works the first time portably when theyre included uniformly +than to do the analysis from scratch each time you think you need it, for each feature. + +Moreover it helps force you to make hard decisions: if you EVER bring in boolean.h, +then you should pay the price everywhere, so you can see how much grief it will cause. + +Of course, another school of thought is that you should do as little damage as possible +in as few places as possible... +*/ + + +/* _LIBRETRO_COMMON_RETRO_COMMON_API_H */ +#endif diff --git a/platform/libretro/libretro-common/include/retro_dirent.h b/platform/libretro/libretro-common/include/retro_dirent.h new file mode 100644 index 00000000..c3450732 --- /dev/null +++ b/platform/libretro/libretro-common/include/retro_dirent.h @@ -0,0 +1,71 @@ +/* Copyright (C) 2010-2018 The RetroArch team + * + * --------------------------------------------------------------------------------------- + * The following license statement only applies to this file (retro_dirent.h). + * --------------------------------------------------------------------------------------- + * + * Permission is hereby granted, free of charge, + * to any person obtaining a copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation the rights to + * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, + * and to permit persons to whom the Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, + * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. + * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, + * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + */ + +#ifndef __RETRO_DIRENT_H +#define __RETRO_DIRENT_H + +#include +#include + +#include + +RETRO_BEGIN_DECLS + +typedef struct RDIR RDIR; + +/** + * + * retro_opendir: + * @name : path to the directory to open. + * + * Opens a directory for reading. Tidy up with retro_closedir. + * + * Returns: RDIR pointer on success, NULL if name is not a + * valid directory, null itself or the empty string. + */ +struct RDIR *retro_opendir(const char *name); + +int retro_readdir(struct RDIR *rdir); + +bool retro_dirent_error(struct RDIR *rdir); + +void retro_dirent_include_hidden(struct RDIR *rdir, bool include_hidden); + +const char *retro_dirent_get_name(struct RDIR *rdir); + +/** + * + * retro_dirent_is_dir: + * @rdir : pointer to the directory entry. + * + * Is the directory listing entry a directory? + * + * Returns: true if directory listing entry is + * a directory, false if not. + */ +bool retro_dirent_is_dir(struct RDIR *rdir, const char *path); + +void retro_closedir(struct RDIR *rdir); + +RETRO_END_DECLS + +#endif diff --git a/platform/libretro/libretro-common/include/retro_endianness.h b/platform/libretro/libretro-common/include/retro_endianness.h new file mode 100644 index 00000000..e721ec9d --- /dev/null +++ b/platform/libretro/libretro-common/include/retro_endianness.h @@ -0,0 +1,258 @@ +/* Copyright (C) 2010-2018 The RetroArch team + * + * --------------------------------------------------------------------------------------- + * The following license statement only applies to this file (retro_endianness.h). + * --------------------------------------------------------------------------------------- + * + * Permission is hereby granted, free of charge, + * to any person obtaining a copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation the rights to + * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, + * and to permit persons to whom the Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, + * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. + * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, + * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + */ + +#ifndef __LIBRETRO_SDK_ENDIANNESS_H +#define __LIBRETRO_SDK_ENDIANNESS_H + +#include +#include +#include + +#if defined(_MSC_VER) && _MSC_VER > 1200 +#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) \ + )) +#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)) +#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)) +#endif + +/** + * is_little_endian: + * + * Checks if the system is little endian or big-endian. + * + * 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 + +/** + * swap_if_big64: + * @val : unsigned 64-bit value + * + * Byteswap unsigned 64-bit value if system is big-endian. + * + * Returns: Byteswapped value in case system is big-endian, + * otherwise returns same value. + **/ + +#if defined(MSB_FIRST) +#define swap_if_big64(val) (SWAP64(val)) +#elif defined(__x86_64) || defined(__i386) || defined(_M_IX86) || defined(_M_X64) +#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 + +/** + * swap_if_big32: + * @val : unsigned 32-bit value + * + * Byteswap unsigned 32-bit value if system is big-endian. + * + * Returns: Byteswapped value in case system is big-endian, + * otherwise returns same value. + **/ + +#if defined(MSB_FIRST) +#define swap_if_big32(val) (SWAP32(val)) +#elif defined(__x86_64) || defined(__i386) || defined(_M_IX86) || defined(_M_X64) +#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 + +/** + * swap_if_little64: + * @val : unsigned 64-bit value + * + * Byteswap unsigned 64-bit value if system is little-endian. + * + * Returns: Byteswapped value in case system is little-endian, + * otherwise returns same value. + **/ + +#if defined(MSB_FIRST) +#define swap_if_little64(val) (val) +#elif defined(__x86_64) || defined(__i386) || defined(_M_IX86) || defined(_M_X64) +#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 + +/** + * swap_if_little32: + * @val : unsigned 32-bit value + * + * Byteswap unsigned 32-bit value if system is little-endian. + * + * Returns: Byteswapped value in case system is little-endian, + * otherwise returns same value. + **/ + +#if defined(MSB_FIRST) +#define swap_if_little32(val) (val) +#elif defined(__x86_64) || defined(__i386) || defined(_M_IX86) || defined(_M_X64) +#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 + +/** + * swap_if_big16: + * @val : unsigned 16-bit value + * + * Byteswap unsigned 16-bit value if system is big-endian. + * + * Returns: Byteswapped value in case system is big-endian, + * otherwise returns same value. + **/ + +#if defined(MSB_FIRST) +#define swap_if_big16(val) (SWAP16(val)) +#elif defined(__x86_64) || defined(__i386) || defined(_M_IX86) || defined(_M_X64) +#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 + +/** + * swap_if_little16: + * @val : unsigned 16-bit value + * + * Byteswap unsigned 16-bit value if system is little-endian. + * + * Returns: Byteswapped value in case system is little-endian, + * otherwise returns same value. + **/ + +#if defined(MSB_FIRST) +#define swap_if_little16(val) (val) +#elif defined(__x86_64) || defined(__i386) || defined(_M_IX86) || defined(_M_X64) +#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 + +/** + * store32be: + * @addr : pointer to unsigned 32-bit buffer + * @data : unsigned 32-bit value to write + * + * Write data to address. Endian-safe. Byteswaps the data + * first if necessary before storing it. + **/ +static INLINE void store32be(uint32_t *addr, uint32_t data) +{ + *addr = swap_if_little32(data); +} + +/** + * load32be: + * @addr : pointer to unsigned 32-bit buffer + * + * Load value from address. Endian-safe. + * + * Returns: value from address, byte-swapped if necessary. + **/ +static INLINE uint32_t load32be(const uint32_t *addr) +{ + return swap_if_little32(*addr); +} + +#endif diff --git a/platform/libretro/libretro-common/include/retro_environment.h b/platform/libretro/libretro-common/include/retro_environment.h new file mode 100644 index 00000000..1a18cd6f --- /dev/null +++ b/platform/libretro/libretro-common/include/retro_environment.h @@ -0,0 +1,78 @@ +/* Copyright (C) 2010-2018 The RetroArch team + * + * --------------------------------------------------------------------------------------- + * The following license statement only applies to this file (retro_environment.h). + * --------------------------------------------------------------------------------------- + * + * Permission is hereby granted, free of charge, + * to any person obtaining a copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation the rights to + * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, + * and to permit persons to whom the Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, + * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. + * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, + * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + */ + +#ifndef __LIBRETRO_SDK_ENVIRONMENT_H +#define __LIBRETRO_SDK_ENVIRONMENT_H + +/* +This file is designed to create a normalized environment for compiling +libretro-common's private implementations, or any other sources which might +enjoy use of it's environment (RetroArch for instance). +This should be an elaborately crafted environment so that sources don't +need to be full of platform-specific workarounds. +*/ + +#if defined (__cplusplus) +#if 0 +printf("This is C++, version %d.\n", __cplusplus); +#endif +/* The expected values would be + * 199711L, for ISO/IEC 14882:1998 or 14882:2003 + */ + +#elif defined(__STDC__) +/* This is standard C. */ + +#if (__STDC__ == 1) +/* The implementation is ISO-conforming. */ +#define __STDC_ISO__ +#else +/* The implementation is not ISO-conforming. */ +#endif + +#if defined(__STDC_VERSION__) +#if (__STDC_VERSION__ >= 201112L) +/* This is C11. */ +#define __STDC_C11__ +#elif (__STDC_VERSION__ >= 199901L) +/* This is C99. */ +#define __STDC_C99__ +#elif (__STDC_VERSION__ >= 199409L) +/* This is C89 with amendment 1. */ +#define __STDC_C89__ +#define __STDC_C89_AMENDMENT_1__ +#else +/* This is C89 without amendment 1. */ +#define __STDC_C89__ +#endif +#else /* !defined(__STDC_VERSION__) */ +/* This is C89. __STDC_VERSION__ is not defined. */ +#define __STDC_C89__ +#endif + +#else /* !defined(__STDC__) */ +/* This is not standard C. __STDC__ is not defined. */ +#endif + + + +#endif diff --git a/platform/libretro/libretro-common/include/retro_inline.h b/platform/libretro/libretro-common/include/retro_inline.h new file mode 100644 index 00000000..e4a21f6c --- /dev/null +++ b/platform/libretro/libretro-common/include/retro_inline.h @@ -0,0 +1,39 @@ +/* Copyright (C) 2010-2018 The RetroArch team + * + * --------------------------------------------------------------------------------------- + * The following license statement only applies to this file (retro_inline.h). + * --------------------------------------------------------------------------------------- + * + * Permission is hereby granted, free of charge, + * to any person obtaining a copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation the rights to + * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, + * and to permit persons to whom the Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, + * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. + * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, + * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + */ + +#ifndef __LIBRETRO_SDK_INLINE_H +#define __LIBRETRO_SDK_INLINE_H + +#ifndef INLINE + +#if defined(_WIN32) || defined(__INTEL_COMPILER) +#define INLINE __inline +#elif defined(__STDC_VERSION__) && __STDC_VERSION__>=199901L +#define INLINE inline +#elif defined(__GNUC__) +#define INLINE __inline__ +#else +#define INLINE +#endif + +#endif +#endif diff --git a/platform/libretro/libretro-common/include/retro_miscellaneous.h b/platform/libretro/libretro-common/include/retro_miscellaneous.h new file mode 100644 index 00000000..afcb885c --- /dev/null +++ b/platform/libretro/libretro-common/include/retro_miscellaneous.h @@ -0,0 +1,158 @@ +/* Copyright (C) 2010-2018 The RetroArch team + * + * --------------------------------------------------------------------------------------- + * The following license statement only applies to this file (retro_miscellaneous.h). + * --------------------------------------------------------------------------------------- + * + * Permission is hereby granted, free of charge, + * to any person obtaining a copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation the rights to + * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, + * and to permit persons to whom the Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, + * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. + * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, + * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + */ + +#ifndef __RARCH_MISCELLANEOUS_H +#define __RARCH_MISCELLANEOUS_H + +#define RARCH_MAX_SUBSYSTEMS 10 +#define RARCH_MAX_SUBSYSTEM_ROMS 10 + +#include +#include +#include + +#if defined(_WIN32) && !defined(_XBOX) +#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 + +#ifdef _MSC_VER +#include +#endif + +static INLINE void bits_or_bits(uint32_t *a, uint32_t *b, uint32_t count) +{ + uint32_t i; + for (i = 0; i < count;i++) + a[i] |= b[i]; +} + +static INLINE void bits_clear_bits(uint32_t *a, uint32_t *b, uint32_t count) +{ + uint32_t i; + for (i = 0; i < count;i++) + a[i] &= ~b[i]; +} + +static INLINE bool bits_any_set(uint32_t* ptr, uint32_t count) +{ + uint32_t i; + for (i = 0; i < count; i++) + { + if (ptr[i] != 0) + return true; + } + return false; +} + +#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(GEKKO)|| defined(WIIU) +#define PATH_MAX_LENGTH 512 +#else +#define PATH_MAX_LENGTH 4096 +#endif +#endif + +#ifndef MAX +#define MAX(a, b) ((a) > (b) ? (a) : (b)) +#endif + +#ifndef MIN +#define MIN(a, b) ((a) < (b) ? (a) : (b)) +#endif + +#define ARRAY_SIZE(a) (sizeof(a) / sizeof((a)[0])) + +#define BITS_GET_ELEM(a, i) ((a).data[i]) +#define BITS_GET_ELEM_PTR(a, i) ((a)->data[i]) + +#define BIT_SET(a, bit) ((a)[(bit) >> 3] |= (1 << ((bit) & 7))) +#define BIT_CLEAR(a, bit) ((a)[(bit) >> 3] &= ~(1 << ((bit) & 7))) +#define BIT_GET(a, bit) (((a)[(bit) >> 3] >> ((bit) & 7)) & 1) + +#define BIT16_SET(a, bit) ((a) |= (1 << ((bit) & 15))) +#define BIT16_CLEAR(a, bit) ((a) &= ~(1 << ((bit) & 15))) +#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_GET(a, bit) (((a) >> ((bit) & 31)) & 1) +#define BIT32_CLEAR_ALL(a) ((a) = 0) + +#define BIT64_SET(a, bit) ((a) |= (UINT64_C(1) << ((bit) & 63))) +#define BIT64_CLEAR(a, bit) ((a) &= ~(UINT64_C(1) << ((bit) & 63))) +#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_GET(a, bit) (((a).data[(bit) >> 5] >> ((bit) & 31)) & 1) +#define BIT128_CLEAR_ALL(a) memset(&(a), 0, sizeof(a)) + +#define BIT128_SET_PTR(a, bit) BIT128_SET(*a, bit) +#define BIT128_CLEAR_PTR(a, bit) BIT128_CLEAR(*a, bit) +#define BIT128_GET_PTR(a, bit) BIT128_GET(*a, bit) +#define BIT128_CLEAR_ALL_PTR(a) BIT128_CLEAR_ALL(*a) + +#define BIT256_SET(a, bit) BIT128_SET(a, bit) +#define BIT256_CLEAR(a, bit) BIT128_CLEAR(a, bit) +#define BIT256_GET(a, bit) BIT128_GET(a, bit) +#define BIT256_CLEAR_ALL(a) BIT128_CLEAR_ALL(a) + +#define BIT256_SET_PTR(a, bit) BIT256_SET(*a, bit) +#define BIT256_CLEAR_PTR(a, bit) BIT256_CLEAR(*a, bit) +#define BIT256_GET_PTR(a, bit) BIT256_GET(*a, bit) +#define BIT256_CLEAR_ALL_PTR(a) BIT256_CLEAR_ALL(*a) + +#define BITS_COPY16_PTR(a,bits) \ +{ \ + BIT128_CLEAR_ALL_PTR(a); \ + BITS_GET_ELEM_PTR(a, 0) = (bits) & 0xffff; \ +} + +#define BITS_COPY32_PTR(a,bits) \ +{ \ + BIT128_CLEAR_ALL_PTR(a); \ + BITS_GET_ELEM_PTR(a, 0) = (bits); \ +} + +/* Helper macros and struct to keep track of many booleans. */ +/* This struct has 256 bits. */ +typedef struct +{ + uint32_t data[8]; +} retro_bits_t; + +#endif diff --git a/platform/libretro/libretro-common/include/streams/file_stream.h b/platform/libretro/libretro-common/include/streams/file_stream.h new file mode 100644 index 00000000..546fd126 --- /dev/null +++ b/platform/libretro/libretro-common/include/streams/file_stream.h @@ -0,0 +1,107 @@ +/* Copyright (C) 2010-2018 The RetroArch team + * + * --------------------------------------------------------------------------------------- + * The following license statement only applies to this file (file_stream.h). + * --------------------------------------------------------------------------------------- + * + * Permission is hereby granted, free of charge, + * to any person obtaining a copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation the rights to + * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, + * and to permit persons to whom the Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, + * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. + * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, + * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + */ + +#ifndef __LIBRETRO_SDK_FILE_STREAM_H +#define __LIBRETRO_SDK_FILE_STREAM_H + +#include +#include +#include +#include + +#include + +#include +#include +#include +#include + +#include + +#define FILESTREAM_REQUIRED_VFS_VERSION 1 + +RETRO_BEGIN_DECLS + +typedef struct RFILE RFILE; + +#define FILESTREAM_REQUIRED_VFS_VERSION 1 + +void filestream_vfs_init(const struct retro_vfs_interface_info* vfs_info); + +int64_t filestream_get_size(RFILE *stream); + +/** + * filestream_open: + * @path : path to file + * @mode : file mode to use when opening (read/write) + * @bufsize : optional buffer size (-1 or 0 to use default) + * + * Opens a file for reading or writing, depending on the requested mode. + * Returns a pointer to an RFILE if opened successfully, otherwise NULL. + **/ +RFILE *filestream_open(const char *path, unsigned mode, unsigned hints); + +int64_t filestream_seek(RFILE *stream, int64_t offset, int seek_position); + +int64_t filestream_read(RFILE *stream, void *data, int64_t len); + +int64_t filestream_write(RFILE *stream, const void *data, int64_t len); + +int64_t filestream_tell(RFILE *stream); + +void filestream_rewind(RFILE *stream); + +int filestream_close(RFILE *stream); + +int64_t filestream_read_file(const char *path, void **buf, int64_t *len); + +char *filestream_gets(RFILE *stream, char *s, size_t len); + +int filestream_getc(RFILE *stream); + +int filestream_eof(RFILE *stream); + +bool filestream_write_file(const char *path, const void *data, int64_t size); + +int filestream_putc(RFILE *stream, int c); + +int filestream_vprintf(RFILE *stream, const char* format, va_list args); + +int filestream_printf(RFILE *stream, const char* format, ...); + +int filestream_error(RFILE *stream); + +int filestream_flush(RFILE *stream); + +int filestream_delete(const char *path); + +int filestream_rename(const char *old_path, const char *new_path); + +const char *filestream_get_path(RFILE *stream); + +bool filestream_exists(const char *path); + +char *filestream_getline(RFILE *stream); + +RETRO_END_DECLS + +#endif diff --git a/platform/libretro/libretro-common/include/streams/file_stream_transforms.h b/platform/libretro/libretro-common/include/streams/file_stream_transforms.h new file mode 100644 index 00000000..c1690fa6 --- /dev/null +++ b/platform/libretro/libretro-common/include/streams/file_stream_transforms.h @@ -0,0 +1,89 @@ +/* Copyright (C) 2010-2018 The RetroArch team +* +* --------------------------------------------------------------------------------------- +* The following license statement only applies to this file (file_stream_transforms.h). +* --------------------------------------------------------------------------------------- +* +* Permission is hereby granted, free of charge, +* to any person obtaining a copy of this software and associated documentation files (the "Software"), +* to deal in the Software without restriction, including without limitation the rights to +* use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, +* and to permit persons to whom the Software is furnished to do so, subject to the following conditions: +* +* The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. +* +* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, +* INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. +* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, +* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +*/ + +#ifndef __LIBRETRO_SDK_FILE_STREAM_TRANSFORMS_H +#define __LIBRETRO_SDK_FILE_STREAM_TRANSFORMS_H + +#include +#include +#include +#include + +RETRO_BEGIN_DECLS + +#define FILE RFILE + +#undef fopen +#undef fclose +#undef ftell +#undef fseek +#undef fread +#undef fgets +#undef fgetc +#undef fwrite +#undef fputc +#undef fprintf +#undef ferror +#undef feof + +#define fopen rfopen +#define fclose rfclose +#define ftell rftell +#define fseek rfseek +#define fread rfread +#define fgets rfgets +#define fgetc rfgetc +#define fwrite rfwrite +#define fputc rfputc +#define fprintf rfprintf +#define ferror rferror +#define feof rfeof + +RFILE* rfopen(const char *path, const char *mode); + +int rfclose(RFILE* stream); + +int64_t rftell(RFILE* stream); + +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); + +char *rfgets(char *buffer, int maxCount, RFILE* stream); + +int rfgetc(RFILE* stream); + +int64_t rfwrite(void const* buffer, + size_t elem_size, size_t elem_count, RFILE* stream); + +int rfputc(int character, RFILE * stream); + +int rfprintf(RFILE * stream, const char * format, ...); + +int rferror(RFILE* stream); + +int rfeof(RFILE* stream); + +RETRO_END_DECLS + +#endif diff --git a/platform/libretro/libretro-common/include/string/stdstring.h b/platform/libretro/libretro-common/include/string/stdstring.h new file mode 100644 index 00000000..eb2954b8 --- /dev/null +++ b/platform/libretro/libretro-common/include/string/stdstring.h @@ -0,0 +1,137 @@ +/* Copyright (C) 2010-2018 The RetroArch team + * + * --------------------------------------------------------------------------------------- + * The following license statement only applies to this file (stdstring.h). + * --------------------------------------------------------------------------------------- + * + * Permission is hereby granted, free of charge, + * to any person obtaining a copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation the rights to + * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, + * and to permit persons to whom the Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, + * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. + * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, + * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + */ + +#ifndef __LIBRETRO_SDK_STDSTRING_H +#define __LIBRETRO_SDK_STDSTRING_H + +#include +#include +#include +#include +#include + +#include +#include +#include + +RETRO_BEGIN_DECLS + +static INLINE bool string_is_empty(const char *data) +{ + return (data == NULL) || (*data == '\0'); +} + +static INLINE bool string_is_equal(const char *a, const char *b) +{ + if (!a || !b) + return false; + while(*a && (*a == *b)) + a++, b++; + return (*(const unsigned char*)a - *(const unsigned char*)b) == 0; +} + +static INLINE bool string_is_not_equal(const char *a, const char *b) +{ + return !string_is_equal(a, b); +} + +#define string_add_pair_open(s, size) strlcat((s), " (", (size)) +#define string_add_pair_close(s, size) strlcat((s), ")", (size)) +#define string_add_bracket_open(s, size) strlcat((s), "{", (size)) +#define string_add_bracket_close(s, size) strlcat((s), "}", (size)) +#define string_add_single_quote(s, size) strlcat((s), "'", (size)) +#define string_add_quote(s, size) strlcat((s), "\"", (size)) +#define string_add_colon(s, size) strlcat((s), ":", (size)) +#define string_add_glob_open(s, size) strlcat((s), "glob('*", (size)) +#define string_add_glob_close(s, size) strlcat((s), "*')", (size)) + +static INLINE void string_add_between_pairs(char *s, const char *str, + size_t size) +{ + string_add_pair_open(s, size); + strlcat(s, str, size); + string_add_pair_close(s, size); +} + +#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) +{ + int result = 0; + const unsigned char *p1 = (const unsigned char*)a; + const unsigned char *p2 = (const unsigned char*)b; + + if (!a || !b) + return false; + if (p1 == p2) + return true; + + while ((result = tolower (*p1) - tolower (*p2++)) == 0) + if (*p1++ == '\0') + break; + + return (result == 0); +} + +static INLINE bool string_is_equal_noncase(const char *a, const char *b) +{ + int result = 0; + const unsigned char *p1 = (const unsigned char*)a; + const unsigned char *p2 = (const unsigned char*)b; + + if (!a || !b) + return false; + if (p1 == p2) + return false; + + while ((result = tolower (*p1) - tolower (*p2++)) == 0) + if (*p1++ == '\0') + break; + + return (result == 0); +} + +char *string_to_upper(char *s); + +char *string_to_lower(char *s); + +char *string_ucwords(char* s); + +char *string_replace_substring(const char *in, const char *pattern, + const char *by); + +/* Remove leading whitespaces */ +char *string_trim_whitespace_left(char *const s); + +/* Remove trailing whitespaces */ +char *string_trim_whitespace_right(char *const s); + +/* Remove leading and trailing whitespaces */ +char *string_trim_whitespace(char *const s); + +char *word_wrap(char* buffer, const char *string, int line_width, bool unicode); + +RETRO_END_DECLS + +#endif diff --git a/platform/libretro/libretro-common/include/vfs/vfs_implementation.h b/platform/libretro/libretro-common/include/vfs/vfs_implementation.h new file mode 100644 index 00000000..047b1703 --- /dev/null +++ b/platform/libretro/libretro-common/include/vfs/vfs_implementation.h @@ -0,0 +1,65 @@ +/* Copyright (C) 2010-2018 The RetroArch team +* +* --------------------------------------------------------------------------------------- +* The following license statement only applies to this file (vfs_implementation.h). +* --------------------------------------------------------------------------------------- +* +* Permission is hereby granted, free of charge, +* to any person obtaining a copy of this software and associated documentation files (the "Software"), +* to deal in the Software without restriction, including without limitation the rights to +* use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, +* and to permit persons to whom the Software is furnished to do so, subject to the following conditions: +* +* The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. +* +* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, +* INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. +* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, +* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +*/ + +#ifndef __LIBRETRO_SDK_VFS_IMPLEMENTATION_H +#define __LIBRETRO_SDK_VFS_IMPLEMENTATION_H + +#include +#include + +/* Replace the following symbol with something appropriate + * to signify the file is being compiled for a front end instead of a core. + * This allows the same code to act as reference implementation + * for VFS and as fallbacks for when the front end does not provide VFS functionality. + */ + +#ifdef VFS_FRONTEND +typedef struct retro_vfs_file_handle libretro_vfs_implementation_file; +#else +typedef struct libretro_vfs_implementation_file libretro_vfs_implementation_file; +#endif + +libretro_vfs_implementation_file *retro_vfs_file_open_impl(const char *path, unsigned mode, unsigned hints); + +int retro_vfs_file_close_impl(libretro_vfs_implementation_file *stream); + +int retro_vfs_file_error_impl(libretro_vfs_implementation_file *stream); + +int64_t retro_vfs_file_size_impl(libretro_vfs_implementation_file *stream); + +int64_t retro_vfs_file_tell_impl(libretro_vfs_implementation_file *stream); + +int64_t retro_vfs_file_seek_impl(libretro_vfs_implementation_file *stream, int64_t offset, int seek_position); + +int64_t retro_vfs_file_read_impl(libretro_vfs_implementation_file *stream, void *s, uint64_t len); + +int64_t retro_vfs_file_write_impl(libretro_vfs_implementation_file *stream, const void *s, uint64_t len); + +int retro_vfs_file_flush_impl(libretro_vfs_implementation_file *stream); + +int retro_vfs_file_remove_impl(const char *path); + +int retro_vfs_file_rename_impl(const char *old_path, const char *new_path); + +const char *retro_vfs_file_get_path_impl(libretro_vfs_implementation_file *stream); + +#endif diff --git a/platform/libretro/libretro-common/streams/file_stream.c b/platform/libretro/libretro-common/streams/file_stream.c new file mode 100644 index 00000000..5ccdbcfa --- /dev/null +++ b/platform/libretro/libretro-common/streams/file_stream.c @@ -0,0 +1,501 @@ +/* Copyright (C) 2010-2018 The RetroArch team + * + * --------------------------------------------------------------------------------------- + * The following license statement only applies to this file (file_stream.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 +#include +#include +#include + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include +#define VFS_FRONTEND +#include + +static const int64_t vfs_error_return_value = -1; + +static retro_vfs_get_path_t filestream_get_path_cb = NULL; +static retro_vfs_open_t filestream_open_cb = NULL; +static retro_vfs_close_t filestream_close_cb = NULL; +static retro_vfs_size_t filestream_size_cb = NULL; +static retro_vfs_tell_t filestream_tell_cb = NULL; +static retro_vfs_seek_t filestream_seek_cb = NULL; +static retro_vfs_read_t filestream_read_cb = NULL; +static retro_vfs_write_t filestream_write_cb = NULL; +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; + + filestream_get_path_cb = NULL; + filestream_open_cb = NULL; + filestream_close_cb = NULL; + filestream_tell_cb = NULL; + filestream_size_cb = NULL; + filestream_seek_cb = NULL; + filestream_read_cb = NULL; + filestream_write_cb = NULL; + filestream_flush_cb = NULL; + filestream_remove_cb = NULL; + filestream_rename_cb = NULL; + + vfs_iface = vfs_info->iface; + + if (vfs_info->required_interface_version < FILESTREAM_REQUIRED_VFS_VERSION + || !vfs_iface) + return; + + filestream_get_path_cb = vfs_iface->get_path; + filestream_open_cb = vfs_iface->open; + filestream_close_cb = vfs_iface->close; + filestream_size_cb = vfs_iface->size; + filestream_tell_cb = vfs_iface->tell; + filestream_seek_cb = vfs_iface->seek; + filestream_read_cb = vfs_iface->read; + filestream_write_cb = vfs_iface->write; + filestream_flush_cb = vfs_iface->flush; + filestream_remove_cb = vfs_iface->remove; + filestream_rename_cb = vfs_iface->rename; +} + +/* Callback wrappers */ +bool filestream_exists(const char *path) +{ + RFILE *dummy = NULL; + + if (!path || !*path) + return false; + + dummy = filestream_open(path, + RETRO_VFS_FILE_ACCESS_READ, + RETRO_VFS_FILE_ACCESS_HINT_NONE); + + if (!dummy) + return false; + + filestream_close(dummy); + return true; +} + +int64_t filestream_get_size(RFILE *stream) +{ + int64_t output; + + if (filestream_size_cb != NULL) + output = filestream_size_cb(stream->hfile); + else + output = retro_vfs_file_size_impl((libretro_vfs_implementation_file*)stream->hfile); + + if (output == vfs_error_return_value) + stream->error_flag = true; + + return output; +} + +/** + * filestream_open: + * @path : path to file + * @mode : file mode to use when opening (read/write) + * @hints : + * + * Opens a file for reading or writing, depending on the requested mode. + * Returns a pointer to an RFILE if opened successfully, otherwise NULL. + **/ +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) + fp = (struct retro_vfs_file_handle*) + filestream_open_cb(path, mode, hints); + else + fp = (struct retro_vfs_file_handle*) + retro_vfs_file_open_impl(path, mode, hints); + + if (!fp) + return NULL; + + output = (RFILE*)malloc(sizeof(RFILE)); + output->error_flag = false; + output->eof_flag = false; + output->hfile = fp; + return output; +} + +char *filestream_gets(RFILE *stream, char *s, size_t len) +{ + int c = 0; + char *p = s; + if (!stream) + return NULL; + + /* get max bytes or up to a newline */ + + for (len--; len > 0; len--) + { + if ((c = filestream_getc(stream)) == EOF) + break; + *p++ = c; + if (c == '\n') + break; + } + *p = 0; + + if (p == s && c == EOF) + return NULL; + return (s); +} + +int filestream_getc(RFILE *stream) +{ + char c = 0; + if (!stream) + return 0; + if(filestream_read(stream, &c, 1) == 1) + return (int)c; + return EOF; +} + +int64_t filestream_seek(RFILE *stream, int64_t offset, int seek_position) +{ + int64_t output; + + if (filestream_seek_cb != NULL) + 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); + + if (output == vfs_error_return_value) + stream->error_flag = true; + stream->eof_flag = false; + + return output; +} + +int filestream_eof(RFILE *stream) +{ + return stream->eof_flag; +} + + +int64_t filestream_tell(RFILE *stream) +{ + int64_t output; + + if (filestream_size_cb != NULL) + output = filestream_tell_cb(stream->hfile); + else + output = retro_vfs_file_tell_impl((libretro_vfs_implementation_file*)stream->hfile); + + if (output == vfs_error_return_value) + stream->error_flag = true; + + return output; +} + +void filestream_rewind(RFILE *stream) +{ + if (!stream) + return; + filestream_seek(stream, 0L, RETRO_VFS_SEEK_POSITION_START); + stream->error_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) + 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) + stream->error_flag = true; + if (output < len) + stream->eof_flag = true; + + return output; +} + +int filestream_flush(RFILE *stream) +{ + int output; + + if (filestream_flush_cb != NULL) + output = filestream_flush_cb(stream->hfile); + else + output = retro_vfs_file_flush_impl((libretro_vfs_implementation_file*)stream->hfile); + + if (output == vfs_error_return_value) + stream->error_flag = true; + + return output; +} + +int filestream_delete(const char *path) +{ + if (filestream_remove_cb != NULL) + return filestream_remove_cb(path); + + return retro_vfs_file_remove_impl(path); +} + +int filestream_rename(const char *old_path, const char *new_path) +{ + if (filestream_rename_cb != NULL) + return filestream_rename_cb(old_path, new_path); + + return retro_vfs_file_rename_impl(old_path, new_path); +} + +const char *filestream_get_path(RFILE *stream) +{ + if (filestream_get_path_cb != NULL) + return filestream_get_path_cb(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) + output = filestream_write_cb(stream->hfile, s, len); + else + output = retro_vfs_file_write_impl((libretro_vfs_implementation_file*)stream->hfile, s, len); + + if (output == vfs_error_return_value) + stream->error_flag = true; + + return output; +} + +int filestream_putc(RFILE *stream, int c) +{ + char c_char = (char)c; + if (!stream) + return EOF; + return filestream_write(stream, &c_char, 1)==1 ? 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); + + if (num_chars < 0) + return -1; + else if (num_chars == 0) + return 0; + + return (int)filestream_write(stream, buffer, num_chars); +} + +int filestream_printf(RFILE *stream, const char* format, ...) +{ + va_list vl; + int result; + va_start(vl, format); + result = filestream_vprintf(stream, format, vl); + va_end(vl); + return result; +} + +int filestream_error(RFILE *stream) +{ + if (stream && stream->error_flag) + return 1; + return 0; +} + +int filestream_close(RFILE *stream) +{ + int output; + struct retro_vfs_file_handle* fp = stream->hfile; + + if (filestream_close_cb != NULL) + output = filestream_close_cb(fp); + else + output = retro_vfs_file_close_impl((libretro_vfs_implementation_file*)fp); + + if (output == 0) + free(stream); + + return output; +} + +/** + * filestream_read_file: + * @path : path to file. + * @buf : buffer to allocate and read the contents of the + * file into. Needs to be freed manually. + * + * Read the contents of a file into @buf. + * + * Returns: number of items read, -1 on error. + */ +int64_t filestream_read_file(const char *path, void **buf, int64_t *len) +{ + int64_t ret = 0; + int64_t content_buf_size = 0; + void *content_buf = NULL; + RFILE *file = filestream_open(path, + RETRO_VFS_FILE_ACCESS_READ, + RETRO_VFS_FILE_ACCESS_HINT_NONE); + + if (!file) + { + fprintf(stderr, "Failed to open %s: %s\n", path, strerror(errno)); + goto error; + } + + content_buf_size = filestream_get_size(file); + + if (content_buf_size < 0) + goto error; + + content_buf = malloc((size_t)(content_buf_size + 1)); + + if (!content_buf) + goto error; + if ((int64_t)(uint64_t)(content_buf_size + 1) != (content_buf_size + 1)) + goto error; + + 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); + + *buf = content_buf; + + /* Allow for easy reading of strings to be safe. + * Will only work with sane character formatting (Unix). */ + ((char*)content_buf)[ret] = '\0'; + + if (len) + *len = ret; + + return 1; + +error: + if (file) + filestream_close(file); + if (content_buf) + free(content_buf); + if (len) + *len = -1; + *buf = NULL; + return 0; +} + +/** + * filestream_write_file: + * @path : path to file. + * @data : contents to write to the file. + * @size : size of the contents. + * + * Writes data to a file. + * + * Returns: true (1) on success, false (0) otherwise. + */ +bool filestream_write_file(const char *path, const void *data, int64_t size) +{ + int64_t ret = 0; + RFILE *file = filestream_open(path, + RETRO_VFS_FILE_ACCESS_WRITE, + RETRO_VFS_FILE_ACCESS_HINT_NONE); + if (!file) + return false; + + ret = filestream_write(file, data, size); + filestream_close(file); + + if (ret != size) + return false; + + return true; +} + +char *filestream_getline(RFILE *stream) +{ + char* newline_tmp = NULL; + size_t cur_size = 8; + size_t idx = 0; + int in = 0; + char* newline = (char*)malloc(9); + + if (!stream || !newline) + { + if (newline) + free(newline); + return NULL; + } + + in = filestream_getc(stream); + + while (in != EOF && in != '\n') + { + if (idx == cur_size) + { + cur_size *= 2; + newline_tmp = (char*)realloc(newline, cur_size + 1); + + if (!newline_tmp) + { + free(newline); + return NULL; + } + + newline = newline_tmp; + } + + newline[idx++] = in; + in = filestream_getc(stream); + } + + newline[idx] = '\0'; + return newline; +} diff --git a/platform/libretro/libretro-common/streams/file_stream_transforms.c b/platform/libretro/libretro-common/streams/file_stream_transforms.c new file mode 100644 index 00000000..efeb7edd --- /dev/null +++ b/platform/libretro/libretro-common/streams/file_stream_transforms.c @@ -0,0 +1,144 @@ +/* Copyright (C) 2010-2018 The RetroArch team +* +* --------------------------------------------------------------------------------------- +* The following license statement only applies to this file (file_stream_transforms.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 + +#include +#include + +RFILE* rfopen(const char *path, const char *mode) +{ + RFILE *output = NULL; + unsigned int retro_mode = RETRO_VFS_FILE_ACCESS_READ; + bool position_to_end = false; + + if (strstr(mode, "r")) + { + retro_mode = RETRO_VFS_FILE_ACCESS_READ; + if (strstr(mode, "+")) + { + retro_mode = RETRO_VFS_FILE_ACCESS_READ_WRITE | + RETRO_VFS_FILE_ACCESS_UPDATE_EXISTING; + } + } + else if (strstr(mode, "w")) + { + retro_mode = RETRO_VFS_FILE_ACCESS_WRITE; + if (strstr(mode, "+")) + retro_mode = RETRO_VFS_FILE_ACCESS_READ_WRITE; + } + else if (strstr(mode, "a")) + { + retro_mode = RETRO_VFS_FILE_ACCESS_WRITE | + RETRO_VFS_FILE_ACCESS_UPDATE_EXISTING; + position_to_end = true; + if (strstr(mode, "+")) + { + retro_mode = RETRO_VFS_FILE_ACCESS_READ_WRITE | + RETRO_VFS_FILE_ACCESS_UPDATE_EXISTING; + } + } + + output = filestream_open(path, retro_mode, + RETRO_VFS_FILE_ACCESS_HINT_NONE); + if (output && position_to_end) + filestream_seek(output, 0, RETRO_VFS_SEEK_POSITION_END); + + return output; +} + +int rfclose(RFILE* stream) +{ + return filestream_close(stream); +} + +int64_t rftell(RFILE* stream) +{ + return filestream_tell(stream); +} + +int64_t rfseek(RFILE* stream, int64_t offset, int origin) +{ + int seek_position = -1; + switch (origin) + { + case SEEK_SET: + seek_position = RETRO_VFS_SEEK_POSITION_START; + break; + case SEEK_CUR: + seek_position = RETRO_VFS_SEEK_POSITION_CURRENT; + break; + case SEEK_END: + seek_position = RETRO_VFS_SEEK_POSITION_END; + break; + } + + return filestream_seek(stream, offset, seek_position); +} + +int64_t rfread(void* buffer, + size_t elem_size, size_t elem_count, RFILE* stream) +{ + return filestream_read(stream, buffer, elem_size * elem_count); +} + +char *rfgets(char *buffer, int maxCount, RFILE* stream) +{ + return filestream_gets(stream, buffer, maxCount); +} + +int rfgetc(RFILE* stream) +{ + 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); +} + +int rfputc(int character, RFILE * stream) +{ + return filestream_putc(stream, character); +} + +int rfprintf(RFILE * stream, const char * format, ...) +{ + int result; + va_list vl; + va_start(vl, format); + result = filestream_vprintf(stream, format, vl); + va_end(vl); + return result; +} + +int rferror(RFILE* stream) +{ + return filestream_error(stream); +} + +int rfeof(RFILE* stream) +{ + return filestream_eof(stream); +} diff --git a/platform/libretro/libretro-common/string/stdstring.c b/platform/libretro/libretro-common/string/stdstring.c new file mode 100644 index 00000000..6e1555db --- /dev/null +++ b/platform/libretro/libretro-common/string/stdstring.c @@ -0,0 +1,217 @@ +/* Copyright (C) 2010-2018 The RetroArch team + * + * --------------------------------------------------------------------------------------- + * The following license statement only applies to this file (stdstring.c). + * --------------------------------------------------------------------------------------- + * + * Permission is hereby granted, free of charge, + * to any person obtaining a copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation the rights to + * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, + * and to permit persons to whom the Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, + * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. + * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, + * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + */ + +#include +#include + +#include +#include + +char *string_to_upper(char *s) +{ + char *cs = (char *)s; + for ( ; *cs != '\0'; cs++) + *cs = toupper((unsigned char)*cs); + return s; +} + +char *string_to_lower(char *s) +{ + char *cs = (char *)s; + for ( ; *cs != '\0'; cs++) + *cs = tolower((unsigned char)*cs); + return s; +} + +char *string_ucwords(char *s) +{ + char *cs = (char *)s; + for ( ; *cs != '\0'; cs++) + { + if (*cs == ' ') + *(cs+1) = toupper((unsigned char)*(cs+1)); + } + + s[0] = toupper((unsigned char)s[0]); + return s; +} + +char *string_replace_substring(const char *in, + const char *pattern, const char *replacement) +{ + size_t numhits, pattern_len, replacement_len, outlen; + const char *inat = NULL; + const char *inprev = NULL; + char *out = NULL; + char *outat = NULL; + + /* if either pattern or replacement is NULL, + * duplicate in and let caller handle it. */ + if (!pattern || !replacement) + return strdup(in); + + pattern_len = strlen(pattern); + replacement_len = strlen(replacement); + numhits = 0; + inat = in; + + while ((inat = strstr(inat, pattern))) + { + inat += pattern_len; + numhits++; + } + + outlen = strlen(in) - pattern_len*numhits + replacement_len*numhits; + out = (char *)malloc(outlen+1); + outat = out; + inat = in; + inprev = in; + + while ((inat = strstr(inat, pattern))) + { + memcpy(outat, inprev, inat-inprev); + outat += inat-inprev; + memcpy(outat, replacement, replacement_len); + outat += replacement_len; + inat += pattern_len; + inprev = inat; + } + strcpy(outat, inprev); + + return out; +} + +/* Remove leading whitespaces */ +char *string_trim_whitespace_left(char *const s) +{ + if(s && *s) + { + size_t len = strlen(s); + char *cur = s; + + while(*cur && isspace((unsigned char)*cur)) + ++cur, --len; + + if(s != cur) + memmove(s, cur, len + 1); + + } + + return s; +} + +/* Remove trailing whitespaces */ +char *string_trim_whitespace_right(char *const s) +{ + if(s && *s) + { + size_t len = strlen(s); + char *cur = s + len - 1; + + while(cur != s && isspace((unsigned char)*cur)) + --cur, --len; + + cur[isspace((unsigned char)*cur) ? 0 : 1] = '\0'; + } + + return s; +} + +/* Remove leading and trailing whitespaces */ +char *string_trim_whitespace(char *const s) +{ + string_trim_whitespace_right(s); /* order matters */ + string_trim_whitespace_left(s); + + return s; +} + +char *word_wrap(char* buffer, const char *string, int line_width, bool unicode) +{ + unsigned i = 0; + unsigned len = (unsigned)strlen(string); + + while (i < len) + { + unsigned counter; + + /* copy string until the end of the line is reached */ + for (counter = 1; counter <= (unsigned)line_width; counter++) + { + const char *character; + unsigned char_len; + unsigned j = i; + + /* check if end of string reached */ + if (i == len) + { + buffer[i] = 0; + return buffer; + } + + character = utf8skip(&string[i], 1); + char_len = (unsigned)(character - &string[i]); + + if (!unicode) + counter += char_len - 1; + + do + { + buffer[i] = string[i]; + char_len--; + i++; + } while(char_len); + + /* check for newlines embedded in the original input + * and reset the index */ + if (buffer[j] == '\n') + counter = 1; + } + + /* check for whitespace */ + if (string[i] == ' ') + { + buffer[i] = '\n'; + i++; + } + else + { + int k; + + /* check for nearest whitespace back in string */ + for (k = i; k > 0; k--) + { + if (string[k] != ' ') + continue; + + buffer[k] = '\n'; + /* set string index back to character after this one */ + i = k + 1; + break; + } + } + } + + buffer[i] = 0; + + return buffer; +} diff --git a/platform/libretro/libretro-common/vfs/vfs_implementation.c b/platform/libretro/libretro-common/vfs/vfs_implementation.c new file mode 100644 index 00000000..ff8100f7 --- /dev/null +++ b/platform/libretro/libretro-common/vfs/vfs_implementation.c @@ -0,0 +1,591 @@ +/* Copyright (C) 2010-2018 The RetroArch team +* +* --------------------------------------------------------------------------------------- +* The following license statement only applies to this file (vfs_implementation.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 +#include +#include +#include + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#if defined(_WIN32) +# ifdef _MSC_VER +# define setmode _setmode +# endif +# ifdef _XBOX +# include +# define INVALID_FILE_ATTRIBUTES -1 +# else +# include +# include +# include +# include +# endif +#else +# if defined(PSP) +# include +# endif +# include +# include +# if !defined(VITA) +# include +# endif +# include +#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 + +/* Assume W-functions do not work below Win2K and Xbox platforms */ +#if defined(_WIN32_WINNT) && _WIN32_WINNT < 0x0500 || defined(_XBOX) + +#ifndef LEGACY_WIN32 +#define LEGACY_WIN32 +#endif + +#endif + +#if defined(_WIN32) && !defined(_XBOX) +#if !defined(_MSC_VER) || (defined(_MSC_VER) && _MSC_VER >= 1400) +#define ATLEAST_VC2005 +#endif +#endif + +#ifdef RARCH_INTERNAL +#ifndef VFS_FRONTEND +#define VFS_FRONTEND +#endif +#endif + +#include +#include +#include +#include +#include + +#define RFILE_HINT_UNBUFFERED (1 << 8) + +#ifdef VFS_FRONTEND +struct retro_vfs_file_handle +#else +struct libretro_vfs_implementation_file +#endif +{ + int fd; + unsigned hints; + int64_t size; + char *buf; + FILE *fp; + char* orig_path; +#if defined(HAVE_MMAP) + uint64_t mappos; + uint64_t mapsize; + uint8_t *mapped; +#endif +}; + +int64_t retro_vfs_file_seek_internal(libretro_vfs_implementation_file *stream, int64_t offset, int whence) +{ + if (!stream) + goto error; + + if ((stream->hints & RFILE_HINT_UNBUFFERED) == 0) +/* VC2005 and up have a special 64-bit fseek */ +#ifdef ATLEAST_VC2005 + return _fseeki64(stream->fp, offset, whence); +#elif defined(__CELLOS_LV2__) || defined(_MSC_VER) && _MSC_VER <= 1310 + return fseek(stream->fp, (long)offset, whence); +#else + return fseeko(stream->fp, (off_t)offset, whence); +#endif + +#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) + { + /* fseek() returns error on under/overflow but + * allows cursor > EOF for + read-only file descriptors. */ + switch (whence) + { + case SEEK_SET: + if (offset < 0) + goto error; + + stream->mappos = offset; + break; + + case SEEK_CUR: + if ((offset < 0 && stream->mappos + offset > stream->mappos) || + (offset > 0 && stream->mappos + offset < stream->mappos)) + goto error; + + stream->mappos += offset; + break; + + case SEEK_END: + if (stream->mapsize + offset < stream->mapsize) + goto error; + + stream->mappos = stream->mapsize + offset; + break; + } + return stream->mappos; + } +#endif + + if (lseek(stream->fd, offset, whence) < 0) + goto error; + + return 0; + +error: + return -1; +} + +/** + * retro_vfs_file_open_impl: + * @path : path to file + * @mode : file mode to use when opening (read/write) + * @hints : + * + * Opens a file for reading or writing, depending on the requested mode. + * Returns a pointer to an RFILE if opened successfully, otherwise NULL. + **/ + +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)); + +#ifdef VFS_FRONTEND + const char *dumb_prefix = "vfsonly://"; + + if (!memcmp(path, dumb_prefix, strlen(dumb_prefix))) + path += strlen(dumb_prefix); +#endif + + if (!stream) + return NULL; + + (void)flags; + + stream->hints = hints; + stream->orig_path = strdup(path); + +#ifdef HAVE_MMAP + if (stream->hints & RETRO_VFS_FILE_ACCESS_HINT_FREQUENT_ACCESS && mode == RETRO_VFS_FILE_ACCESS_READ) + stream->hints |= RFILE_HINT_UNBUFFERED; + else +#endif + stream->hints &= ~RETRO_VFS_FILE_ACCESS_HINT_FREQUENT_ACCESS; + + switch (mode) + { + case RETRO_VFS_FILE_ACCESS_READ: + mode_str = "rb"; + + flags = O_RDONLY; +#ifdef _WIN32 + flags |= O_BINARY; +#endif + break; + + case RETRO_VFS_FILE_ACCESS_WRITE: + mode_str = "wb"; + + flags = O_WRONLY | O_CREAT | O_TRUNC; +#ifndef _WIN32 + flags |= S_IRUSR | S_IWUSR; +#else + flags |= O_BINARY; +#endif + break; + + case RETRO_VFS_FILE_ACCESS_READ_WRITE: + mode_str = "w+b"; + + flags = O_RDWR | O_CREAT | O_TRUNC; +#ifndef _WIN32 + flags |= S_IRUSR | S_IWUSR; +#else + flags |= O_BINARY; +#endif + break; + + case RETRO_VFS_FILE_ACCESS_WRITE | RETRO_VFS_FILE_ACCESS_UPDATE_EXISTING: + case RETRO_VFS_FILE_ACCESS_READ_WRITE | RETRO_VFS_FILE_ACCESS_UPDATE_EXISTING: + mode_str = "r+b"; + + flags = O_RDWR; +#ifndef _WIN32 + flags |= S_IRUSR | S_IWUSR; +#else + flags |= O_BINARY; +#endif + break; + + default: + goto error; + } + + if ((stream->hints & RFILE_HINT_UNBUFFERED) == 0) + { + FILE *fp = (FILE*)fopen_utf8(path, mode_str); + + if (!fp) + goto error; + + /* Regarding setvbuf: + * + * 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 + * 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. + */ + /* TODO: this is only useful for a few platforms, find which and add ifdef */ + stream->fp = fp; + stream->buf = (char*)calloc(1, 0x4000); + setvbuf(stream->fp, stream->buf, _IOFBF, 0x4000); + } + else + { +#if defined(_WIN32) && !defined(_XBOX) +#if defined(LEGACY_WIN32) + char *path_local = utf8_to_local_string_alloc(path); + stream->fd = open(path_local, flags, 0); + if (path_local) + free(path_local); +#else + wchar_t * path_wide = utf8_to_utf16_string_alloc(path); + stream->fd = _wopen(path_wide, flags, 0); + if (path_wide) + free(path_wide); +#endif +#else + stream->fd = open(path, flags, 0); +#endif + + if (stream->fd == -1) + goto error; + +#ifdef HAVE_MMAP + if (stream->hints & RETRO_VFS_FILE_ACCESS_HINT_FREQUENT_ACCESS) + { + stream->mappos = 0; + stream->mapped = NULL; + stream->mapsize = retro_vfs_file_seek_internal(stream, 0, SEEK_END); + + if (stream->mapsize == (uint64_t)-1) + goto error; + + retro_vfs_file_seek_internal(stream, 0, SEEK_SET); + + stream->mapped = (uint8_t*)mmap((void*)0, + stream->mapsize, PROT_READ, MAP_SHARED, stream->fd, 0); + + if (stream->mapped == MAP_FAILED) + stream->hints &= ~RETRO_VFS_FILE_ACCESS_HINT_FREQUENT_ACCESS; + } +#endif + } + + retro_vfs_file_seek_internal(stream, 0, SEEK_SET); + retro_vfs_file_seek_internal(stream, 0, SEEK_END); + + stream->size = retro_vfs_file_tell_impl(stream); + + retro_vfs_file_seek_internal(stream, 0, SEEK_SET); + + return stream; + +error: + retro_vfs_file_close_impl(stream); + return NULL; +} + +int retro_vfs_file_close_impl(libretro_vfs_implementation_file *stream) +{ + if (!stream) + return -1; + + if ((stream->hints & RFILE_HINT_UNBUFFERED) == 0) + { + if (stream->fp) + fclose(stream->fp); + } + else + { +#ifdef HAVE_MMAP + if (stream->hints & RETRO_VFS_FILE_ACCESS_HINT_FREQUENT_ACCESS) + munmap(stream->mapped, stream->mapsize); +#endif + } + + if (stream->fd > 0) + close(stream->fd); + if (stream->buf) + free(stream->buf); + if (stream->orig_path) + free(stream->orig_path); + free(stream); + + return 0; +} + +int retro_vfs_file_error_impl(libretro_vfs_implementation_file *stream) +{ + return ferror(stream->fp); +} + +int64_t retro_vfs_file_size_impl(libretro_vfs_implementation_file *stream) +{ + if (!stream) + return 0; + return stream->size; +} + +int64_t retro_vfs_file_tell_impl(libretro_vfs_implementation_file *stream) +{ + if (!stream) + return -1; + + if ((stream->hints & RFILE_HINT_UNBUFFERED) == 0) +/* VC2005 and up have a special 64-bit ftell */ +#ifdef ATLEAST_VC2005 + return _ftelli64(stream->fp); +#else + return ftell(stream->fp); +#endif + +#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) + return stream->mappos; +#endif + if (lseek(stream->fd, 0, SEEK_CUR) < 0) + return -1; + + return 0; +} + +int64_t retro_vfs_file_seek_impl(libretro_vfs_implementation_file *stream, int64_t offset, int seek_position) +{ + int whence = -1; + switch (seek_position) + { + case RETRO_VFS_SEEK_POSITION_START: + whence = SEEK_SET; + break; + case RETRO_VFS_SEEK_POSITION_CURRENT: + whence = SEEK_CUR; + break; + case RETRO_VFS_SEEK_POSITION_END: + whence = SEEK_END; + break; + } + + return retro_vfs_file_seek_internal(stream, offset, whence); +} + +int64_t retro_vfs_file_read_impl(libretro_vfs_implementation_file *stream, void *s, uint64_t len) +{ + if (!stream || !s) + goto error; + + if ((stream->hints & RFILE_HINT_UNBUFFERED) == 0) + return fread(s, 1, (size_t)len, stream->fp); + +#ifdef HAVE_MMAP + if (stream->hints & RETRO_VFS_FILE_ACCESS_HINT_FREQUENT_ACCESS) + { + if (stream->mappos > stream->mapsize) + goto error; + + if (stream->mappos + len > stream->mapsize) + len = stream->mapsize - stream->mappos; + + memcpy(s, &stream->mapped[stream->mappos], len); + stream->mappos += len; + + return len; + } +#endif + + return read(stream->fd, s, (size_t)len); + +error: + return -1; +} + +int64_t retro_vfs_file_write_impl(libretro_vfs_implementation_file *stream, const void *s, uint64_t len) +{ + if (!stream) + goto error; + + if ((stream->hints & RFILE_HINT_UNBUFFERED) == 0) + return fwrite(s, 1, (size_t)len, stream->fp); + +#ifdef HAVE_MMAP + if (stream->hints & RETRO_VFS_FILE_ACCESS_HINT_FREQUENT_ACCESS) + goto error; +#endif + return write(stream->fd, s, (size_t)len); + +error: + return -1; +} + +int retro_vfs_file_flush_impl(libretro_vfs_implementation_file *stream) +{ + if (!stream) + return -1; + return fflush(stream->fp)==0 ? 0 : -1; +} + +int retro_vfs_file_remove_impl(const char *path) +{ + char *path_local = NULL; + wchar_t *path_wide = NULL; + + if (!path || !*path) + return -1; + + (void)path_local; + (void)path_wide; + +#if defined(_WIN32) && !defined(_XBOX) +#if defined(_WIN32_WINNT) && _WIN32_WINNT < 0x0500 + path_local = utf8_to_local_string_alloc(path); + + if (path_local) + { + int ret = remove(path_local); + free(path_local); + + if (ret == 0) + return 0; + } +#else + path_wide = utf8_to_utf16_string_alloc(path); + + if (path_wide) + { + int ret = _wremove(path_wide); + free(path_wide); + + if (ret == 0) + return 0; + } +#endif +#else + if (remove(path) == 0) + return 0; +#endif + return -1; +} + +int retro_vfs_file_rename_impl(const char *old_path, const char *new_path) +{ + char *old_path_local = NULL; + char *new_path_local = NULL; + wchar_t *old_path_wide = NULL; + wchar_t *new_path_wide = NULL; + + if (!old_path || !*old_path || !new_path || !*new_path) + return -1; + + (void)old_path_local; + (void)new_path_local; + (void)old_path_wide; + (void)new_path_wide; + +#if defined(_WIN32) && !defined(_XBOX) +#if defined(_WIN32_WINNT) && _WIN32_WINNT < 0x0500 + old_path_local = utf8_to_local_string_alloc(old_path); + new_path_local = utf8_to_local_string_alloc(new_path); + + if (old_path_local) + { + if (new_path_local) + { + int ret = rename(old_path_local, new_path_local); + free(old_path_local); + free(new_path_local); + return ret==0 ? 0 : -1; + } + + free(old_path_local); + } + + if (new_path_local) + free(new_path_local); +#else + old_path_wide = utf8_to_utf16_string_alloc(old_path); + new_path_wide = utf8_to_utf16_string_alloc(new_path); + + if (old_path_wide) + { + if (new_path_wide) + { + int ret = _wrename(old_path_wide, new_path_wide); + free(old_path_wide); + free(new_path_wide); + return ret==0 ? 0 : -1; + } + + free(old_path_wide); + } + + if (new_path_wide) + free(new_path_wide); +#endif + return -1; +#else + return rename(old_path, new_path)==0 ? 0 : -1; +#endif +} + +const char *retro_vfs_file_get_path_impl(libretro_vfs_implementation_file *stream) +{ + /* should never happen, do something noisy so caller can be fixed */ + if (!stream) + abort(); + return stream->orig_path; +}