mirror of
https://github.com/libretro/gambatte-libretro.git
synced 2024-11-23 07:49:48 +00:00
Updates
This commit is contained in:
parent
bcfd2df6d9
commit
cce80279b6
@ -42,6 +42,10 @@ endif
|
||||
|
||||
ifeq ($(STATIC_LINKING),1)
|
||||
else
|
||||
SOURCES_C += $(LIBRETRO_COMM_DIR)/streams/file_stream.c
|
||||
SOURCES_C += $(LIBRETRO_COMM_DIR)/streams/file_stream.c \
|
||||
$(LIBRETRO_COMM_DIR)/vfs/vfs_implementation.c \
|
||||
$(LIBRETRO_COMM_DIR)/compat/fopen_utf8.c \
|
||||
$(LIBRETRO_COMM_DIR)/compat/compat_strl.c \
|
||||
$(LIBRETRO_COMM_DIR)/encodings/encoding_utf.c
|
||||
endif
|
||||
|
||||
|
69
libgambatte/libretro-common/compat/compat_strl.c
Normal file
69
libgambatte/libretro-common/compat/compat_strl.c
Normal file
@ -0,0 +1,69 @@
|
||||
/* Copyright (C) 2010-2017 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 <stdlib.h>
|
||||
#include <ctype.h>
|
||||
|
||||
#include <compat/strl.h>
|
||||
|
||||
/* 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;
|
||||
}
|
32
libgambatte/libretro-common/compat/fopen_utf8.c
Normal file
32
libgambatte/libretro-common/compat/fopen_utf8.c
Normal file
@ -0,0 +1,32 @@
|
||||
#include <compat/fopen_utf8.h>
|
||||
#include <encodings/utf.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
#if defined(_WIN32_WINNT) && _WIN32_WINNT < 0x0500 || defined(_XBOX)
|
||||
#ifndef LEGACY_WIN32
|
||||
#define LEGACY_WIN32
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#ifdef _WIN32
|
||||
#undef fopen
|
||||
|
||||
FILE* fopen_utf8(const char * filename, const char * mode)
|
||||
{
|
||||
#if defined(_XBOX)
|
||||
return fopen(filename, mode);
|
||||
#elif defined(LEGACY_WIN32)
|
||||
char * filename_local = utf8_to_local_string_alloc(filename);
|
||||
FILE* ret = fopen(filename_local, mode);
|
||||
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
|
514
libgambatte/libretro-common/encodings/encoding_utf.c
Normal file
514
libgambatte/libretro-common/encodings/encoding_utf.c
Normal file
@ -0,0 +1,514 @@
|
||||
/* Copyright (C) 2010-2017 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 <stdint.h>
|
||||
#include <stdlib.h>
|
||||
#include <stddef.h>
|
||||
#include <string.h>
|
||||
|
||||
#include <boolean.h>
|
||||
#include <compat/strl.h>
|
||||
#include <retro_inline.h>
|
||||
|
||||
#include <encodings/utf.h>
|
||||
|
||||
#if defined(_WIN32) && !defined(_XBOX)
|
||||
#include <windows.h>
|
||||
#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;
|
||||
}
|
14
libgambatte/libretro-common/include/compat/fopen_utf8.h
Normal file
14
libgambatte/libretro-common/include/compat/fopen_utf8.h
Normal file
@ -0,0 +1,14 @@
|
||||
#ifndef __FOPEN_UTF8_H
|
||||
#define __FOPEN_UTF8_H
|
||||
|
||||
#include <stdio.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) */
|
||||
FILE* fopen_utf8(const char * filename, const char * mode);
|
||||
#else
|
||||
#define fopen_utf8 fopen
|
||||
#endif
|
||||
#endif
|
60
libgambatte/libretro-common/include/compat/strl.h
Normal file
60
libgambatte/libretro-common/include/compat/strl.h
Normal file
@ -0,0 +1,60 @@
|
||||
/* Copyright (C) 2010-2017 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 <string.h>
|
||||
#include <stddef.h>
|
||||
|
||||
#ifdef HAVE_CONFIG_H
|
||||
#include "../../../config.h"
|
||||
#endif
|
||||
|
||||
#include <retro_common_api.h>
|
||||
|
||||
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
|
||||
|
67
libgambatte/libretro-common/include/encodings/utf.h
Normal file
67
libgambatte/libretro-common/include/encodings/utf.h
Normal file
@ -0,0 +1,67 @@
|
||||
/* Copyright (C) 2010-2017 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 <stdint.h>
|
||||
#include <stddef.h>
|
||||
|
||||
#include <boolean.h>
|
||||
|
||||
#include <retro_common_api.h>
|
||||
|
||||
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
|
@ -1,4 +1,4 @@
|
||||
/* Copyright (C) 2010-2016 The RetroArch team
|
||||
/* Copyright (C) 2010-2017 The RetroArch team
|
||||
*
|
||||
* ---------------------------------------------------------------------------------------
|
||||
* The following license statement only applies to this libretro API header (libretro.h).
|
||||
@ -126,16 +126,23 @@ extern "C" {
|
||||
*/
|
||||
#define RETRO_DEVICE_KEYBOARD 3
|
||||
|
||||
/* Lightgun X/Y coordinates are reported relatively to last poll,
|
||||
* similar to mouse. */
|
||||
/* LIGHTGUN device is similar to Guncon-2 for PlayStation 2.
|
||||
* It reports X/Y coordinates in screen space (similar to the pointer)
|
||||
* in the range [-0x8000, 0x7fff] in both axes, with zero being center.
|
||||
* As well as reporting on/off screen state. It features a trigger,
|
||||
* start/select buttons, auxiliary action buttons and a
|
||||
* directional pad. A forced off-screen shot can be requested for
|
||||
* auto-reloading function in some games.
|
||||
*/
|
||||
#define RETRO_DEVICE_LIGHTGUN 4
|
||||
|
||||
/* The ANALOG device is an extension to JOYPAD (RetroPad).
|
||||
* Similar to DualShock it adds two analog sticks.
|
||||
* This is treated as a separate device type as it returns values in the
|
||||
* full analog range of [-0x8000, 0x7fff]. Positive X axis is right.
|
||||
* Positive Y axis is down.
|
||||
* Only use ANALOG type when polling for analog values of the axes.
|
||||
* Similar to DualShock2 it adds two analog sticks and all buttons can
|
||||
* be analog. This is treated as a separate device type as it returns
|
||||
* axis values in the full analog range of [-0x8000, 0x7fff].
|
||||
* Positive X axis is right. Positive Y axis is down.
|
||||
* Buttons are returned in the range [0, 0x7fff].
|
||||
* Only use ANALOG type when polling for analog values.
|
||||
*/
|
||||
#define RETRO_DEVICE_ANALOG 5
|
||||
|
||||
@ -174,7 +181,8 @@ extern "C" {
|
||||
/* Buttons for the RetroPad (JOYPAD).
|
||||
* The placement of these is equivalent to placements on the
|
||||
* Super Nintendo controller.
|
||||
* L2/R2/L3/R3 buttons correspond to the PS1 DualShock. */
|
||||
* L2/R2/L3/R3 buttons correspond to the PS1 DualShock.
|
||||
* Also used as id values for RETRO_DEVICE_INDEX_ANALOG_BUTTON */
|
||||
#define RETRO_DEVICE_ID_JOYPAD_B 0
|
||||
#define RETRO_DEVICE_ID_JOYPAD_Y 1
|
||||
#define RETRO_DEVICE_ID_JOYPAD_SELECT 2
|
||||
@ -195,6 +203,7 @@ extern "C" {
|
||||
/* Index / Id values for ANALOG device. */
|
||||
#define RETRO_DEVICE_INDEX_ANALOG_LEFT 0
|
||||
#define RETRO_DEVICE_INDEX_ANALOG_RIGHT 1
|
||||
#define RETRO_DEVICE_INDEX_ANALOG_BUTTON 2
|
||||
#define RETRO_DEVICE_ID_ANALOG_X 0
|
||||
#define RETRO_DEVICE_ID_ANALOG_Y 1
|
||||
|
||||
@ -208,15 +217,30 @@ extern "C" {
|
||||
#define RETRO_DEVICE_ID_MOUSE_MIDDLE 6
|
||||
#define RETRO_DEVICE_ID_MOUSE_HORIZ_WHEELUP 7
|
||||
#define RETRO_DEVICE_ID_MOUSE_HORIZ_WHEELDOWN 8
|
||||
#define RETRO_DEVICE_ID_MOUSE_BUTTON_4 9
|
||||
#define RETRO_DEVICE_ID_MOUSE_BUTTON_5 10
|
||||
|
||||
/* Id values for LIGHTGUN types. */
|
||||
#define RETRO_DEVICE_ID_LIGHTGUN_X 0
|
||||
#define RETRO_DEVICE_ID_LIGHTGUN_Y 1
|
||||
/* Id values for LIGHTGUN. */
|
||||
#define RETRO_DEVICE_ID_LIGHTGUN_SCREEN_X 13 /*Absolute Position*/
|
||||
#define RETRO_DEVICE_ID_LIGHTGUN_SCREEN_Y 14 /*Absolute*/
|
||||
#define RETRO_DEVICE_ID_LIGHTGUN_IS_OFFSCREEN 15 /*Status Check*/
|
||||
#define RETRO_DEVICE_ID_LIGHTGUN_TRIGGER 2
|
||||
#define RETRO_DEVICE_ID_LIGHTGUN_CURSOR 3
|
||||
#define RETRO_DEVICE_ID_LIGHTGUN_TURBO 4
|
||||
#define RETRO_DEVICE_ID_LIGHTGUN_PAUSE 5
|
||||
#define RETRO_DEVICE_ID_LIGHTGUN_RELOAD 16 /*Forced off-screen shot*/
|
||||
#define RETRO_DEVICE_ID_LIGHTGUN_AUX_A 3
|
||||
#define RETRO_DEVICE_ID_LIGHTGUN_AUX_B 4
|
||||
#define RETRO_DEVICE_ID_LIGHTGUN_START 6
|
||||
#define RETRO_DEVICE_ID_LIGHTGUN_SELECT 7
|
||||
#define RETRO_DEVICE_ID_LIGHTGUN_AUX_C 8
|
||||
#define RETRO_DEVICE_ID_LIGHTGUN_DPAD_UP 9
|
||||
#define RETRO_DEVICE_ID_LIGHTGUN_DPAD_DOWN 10
|
||||
#define RETRO_DEVICE_ID_LIGHTGUN_DPAD_LEFT 11
|
||||
#define RETRO_DEVICE_ID_LIGHTGUN_DPAD_RIGHT 12
|
||||
/* deprecated */
|
||||
#define RETRO_DEVICE_ID_LIGHTGUN_X 0 /*Relative Position*/
|
||||
#define RETRO_DEVICE_ID_LIGHTGUN_Y 1 /*Relative*/
|
||||
#define RETRO_DEVICE_ID_LIGHTGUN_CURSOR 3 /*Use Aux:A*/
|
||||
#define RETRO_DEVICE_ID_LIGHTGUN_TURBO 4 /*Use Aux:B*/
|
||||
#define RETRO_DEVICE_ID_LIGHTGUN_PAUSE 5 /*Use Start*/
|
||||
|
||||
/* Id values for POINTER. */
|
||||
#define RETRO_DEVICE_ID_POINTER_X 0
|
||||
@ -237,13 +261,15 @@ enum retro_language
|
||||
RETRO_LANGUAGE_GERMAN = 4,
|
||||
RETRO_LANGUAGE_ITALIAN = 5,
|
||||
RETRO_LANGUAGE_DUTCH = 6,
|
||||
RETRO_LANGUAGE_PORTUGUESE = 7,
|
||||
RETRO_LANGUAGE_RUSSIAN = 8,
|
||||
RETRO_LANGUAGE_KOREAN = 9,
|
||||
RETRO_LANGUAGE_CHINESE_TRADITIONAL = 10,
|
||||
RETRO_LANGUAGE_CHINESE_SIMPLIFIED = 11,
|
||||
RETRO_LANGUAGE_ESPERANTO = 12,
|
||||
RETRO_LANGUAGE_POLISH = 13,
|
||||
RETRO_LANGUAGE_PORTUGUESE_BRAZIL = 7,
|
||||
RETRO_LANGUAGE_PORTUGUESE_PORTUGAL = 8,
|
||||
RETRO_LANGUAGE_RUSSIAN = 9,
|
||||
RETRO_LANGUAGE_KOREAN = 10,
|
||||
RETRO_LANGUAGE_CHINESE_TRADITIONAL = 11,
|
||||
RETRO_LANGUAGE_CHINESE_SIMPLIFIED = 12,
|
||||
RETRO_LANGUAGE_ESPERANTO = 13,
|
||||
RETRO_LANGUAGE_POLISH = 14,
|
||||
RETRO_LANGUAGE_VIETNAMESE = 15,
|
||||
RETRO_LANGUAGE_LAST,
|
||||
|
||||
/* Ensure sizeof(enum) == sizeof(int) */
|
||||
@ -712,7 +738,7 @@ enum retro_mod
|
||||
/* struct retro_log_callback * --
|
||||
* Gets an interface for logging. This is useful for
|
||||
* logging in a cross-platform way
|
||||
* as certain platforms cannot use use stderr for logging.
|
||||
* as certain platforms cannot use stderr for logging.
|
||||
* It also allows the frontend to
|
||||
* show logging information in a more suitable way.
|
||||
* If this interface is not used, libretro cores should
|
||||
@ -921,6 +947,118 @@ enum retro_mod
|
||||
* writeable (and readable).
|
||||
*/
|
||||
|
||||
#define RETRO_ENVIRONMENT_SET_HW_SHARED_CONTEXT (44 | RETRO_ENVIRONMENT_EXPERIMENTAL)
|
||||
/* N/A (null) * --
|
||||
* The frontend will try to use a 'shared' hardware context (mostly applicable
|
||||
* to OpenGL) when a hardware context is being set up.
|
||||
*
|
||||
* Returns true if the frontend supports shared hardware contexts and false
|
||||
* if the frontend does not support shared hardware contexts.
|
||||
*
|
||||
* This will do nothing on its own until SET_HW_RENDER env callbacks are
|
||||
* being used.
|
||||
*/
|
||||
|
||||
#define RETRO_ENVIRONMENT_GET_VFS_INTERFACE (45 | RETRO_ENVIRONMENT_EXPERIMENTAL)
|
||||
/* struct retro_vfs_interface_info * --
|
||||
* Gets access to the VFS interface.
|
||||
* VFS presence needs to be queried prior to load_game or any
|
||||
* get_system/save/other_directory being called to let front end know
|
||||
* core supports VFS before it starts handing out paths.
|
||||
* It is recomended to do so in retro_set_environment */
|
||||
|
||||
/* Opaque file handle
|
||||
* Introduced in VFS API v1 */
|
||||
struct retro_vfs_file_handle;
|
||||
|
||||
/* File open flags
|
||||
* Introduced in VFS API v1 */
|
||||
#define RETRO_VFS_FILE_ACCESS_READ (1 << 0) /* Read only mode */
|
||||
#define RETRO_VFS_FILE_ACCESS_WRITE (1 << 1) /* Write only mode, discard contents and overwrites existing file unless RETRO_VFS_FILE_ACCESS_UPDATE is also specified */
|
||||
#define RETRO_VFS_FILE_ACCESS_READ_WRITE (RETRO_VFS_FILE_ACCESS_READ | RETRO_VFS_FILE_ACCESS_WRITE) /* Read-write mode, discard contents and overwrites existing file unless RETRO_VFS_FILE_ACCESS_UPDATE is also specified*/
|
||||
#define RETRO_VFS_FILE_ACCESS_UPDATE_EXISTING (1 << 2) /* Prevents discarding content of existing files opened for writing */
|
||||
|
||||
/* These are only hints. The frontend may choose to ignore them. Other than RAM/CPU/etc use,
|
||||
and how they react to unlikely external interference (for example someone else writing to that file,
|
||||
or the file's server going down), behavior will not change. */
|
||||
#define RETRO_VFS_FILE_ACCESS_HINT_NONE (0)
|
||||
/* Indicate that the file will be accessed many times. The frontend should aggressively cache everything. */
|
||||
#define RETRO_VFS_FILE_ACCESS_HINT_FREQUENT_ACCESS (1 << 0)
|
||||
|
||||
/* Get path from opaque handle. Returns the exact same path passed to file_open when getting the handle
|
||||
* Introduced in VFS API v1 */
|
||||
typedef const char *(RETRO_CALLCONV *retro_vfs_get_path_t)(struct retro_vfs_file_handle *stream);
|
||||
|
||||
/* Open a file for reading or writing. If path points to a directory, this will
|
||||
* fail. Returns the opaque file handle, or NULL for error.
|
||||
* Introduced in VFS API v1 */
|
||||
typedef struct retro_vfs_file_handle *(RETRO_CALLCONV *retro_vfs_open_t)(const char *path, unsigned mode, unsigned hints);
|
||||
|
||||
/* Close the file and release its resources. Must be called if open_file returns non-NULL. Returns 0 on succes, -1 on failure.
|
||||
* Whether the call succeeds ot not, the handle passed as parameter becomes invalid and should no longer be used.
|
||||
* Introduced in VFS API v1 */
|
||||
typedef int (RETRO_CALLCONV *retro_vfs_close_t)(struct retro_vfs_file_handle *stream);
|
||||
|
||||
/* Return the size of the file in bytes, or -1 for error.
|
||||
* Introduced in VFS API v1 */
|
||||
typedef int64_t (RETRO_CALLCONV *retro_vfs_size_t)(struct retro_vfs_file_handle *stream);
|
||||
|
||||
/* Get the current read / write position for the file. Returns - 1 for error.
|
||||
* Introduced in VFS API v1 */
|
||||
typedef int64_t (RETRO_CALLCONV *retro_vfs_tell_t)(struct retro_vfs_file_handle *stream);
|
||||
|
||||
/* Set the current read/write position for the file. Returns the new position, -1 for error.
|
||||
* Introduced in VFS API v1 */
|
||||
typedef int64_t (RETRO_CALLCONV *retro_vfs_seek_t)(struct retro_vfs_file_handle *stream, int64_t offset, int whence);
|
||||
|
||||
/* Read data from a file. Returns the number of bytes read, or -1 for error.
|
||||
* Introduced in VFS API v1 */
|
||||
typedef int64_t (RETRO_CALLCONV *retro_vfs_read_t)(struct retro_vfs_file_handle *stream, void *s, uint64_t len);
|
||||
|
||||
/* Write data to a file. Returns the number of bytes written, or -1 for error.
|
||||
* Introduced in VFS API v1 */
|
||||
typedef int64_t (RETRO_CALLCONV *retro_vfs_write_t)(struct retro_vfs_file_handle *stream, const void *s, uint64_t len);
|
||||
|
||||
/* Flush pending writes to file, if using buffered IO. Returns 0 on sucess, or -1 on failure.
|
||||
* Introduced in VFS API v1 */
|
||||
typedef int (RETRO_CALLCONV *retro_vfs_flush_t)(struct retro_vfs_file_handle *stream);
|
||||
|
||||
/* Delete the specified file. Returns 0 on success, -1 on failure
|
||||
* Introduced in VFS API v1 */
|
||||
typedef int (RETRO_CALLCONV *retro_vfs_remove_t)(const char *path);
|
||||
|
||||
/* Rename the specified file. Returns 0 on success, -1 on failure
|
||||
* Introduced in VFS API v1 */
|
||||
typedef int (RETRO_CALLCONV *retro_vfs_rename_t)(const char *old_path, const char *new_path);
|
||||
|
||||
struct retro_vfs_interface
|
||||
{
|
||||
retro_vfs_get_path_t get_path;
|
||||
retro_vfs_open_t open;
|
||||
retro_vfs_close_t close;
|
||||
retro_vfs_size_t size;
|
||||
retro_vfs_tell_t tell;
|
||||
retro_vfs_seek_t seek;
|
||||
retro_vfs_read_t read;
|
||||
retro_vfs_write_t write;
|
||||
retro_vfs_flush_t flush;
|
||||
retro_vfs_remove_t remove;
|
||||
retro_vfs_rename_t rename;
|
||||
};
|
||||
|
||||
struct retro_vfs_interface_info
|
||||
{
|
||||
/* Set by core: should this be higher than the version the front end supports,
|
||||
* front end will return false in the RETRO_ENVIRONMENT_GET_VFS_INTERFACE call
|
||||
* Introduced in VFS API v1 */
|
||||
uint32_t required_interface_version;
|
||||
|
||||
/* Frontend writes interface pointer here. The frontend also sets the actual
|
||||
* version, must be at least required_interface_version.
|
||||
* Introduced in VFS API v1 */
|
||||
struct retro_vfs_interface *iface;
|
||||
};
|
||||
|
||||
enum retro_hw_render_interface_type
|
||||
{
|
||||
RETRO_HW_RENDER_INTERFACE_VULKAN = 0,
|
||||
@ -955,6 +1093,57 @@ struct retro_hw_render_interface
|
||||
* This must be called before the first call to retro_run.
|
||||
*/
|
||||
|
||||
enum retro_hw_render_context_negotiation_interface_type
|
||||
{
|
||||
RETRO_HW_RENDER_CONTEXT_NEGOTIATION_INTERFACE_VULKAN = 0,
|
||||
RETRO_HW_RENDER_CONTEXT_NEGOTIATION_INTERFACE_DUMMY = INT_MAX
|
||||
};
|
||||
|
||||
/* Base struct. All retro_hw_render_context_negotiation_interface_* types
|
||||
* contain at least these fields. */
|
||||
struct retro_hw_render_context_negotiation_interface
|
||||
{
|
||||
enum retro_hw_render_context_negotiation_interface_type interface_type;
|
||||
unsigned interface_version;
|
||||
};
|
||||
#define RETRO_ENVIRONMENT_SET_HW_RENDER_CONTEXT_NEGOTIATION_INTERFACE (43 | RETRO_ENVIRONMENT_EXPERIMENTAL)
|
||||
/* const struct retro_hw_render_context_negotiation_interface * --
|
||||
* Sets an interface which lets the libretro core negotiate with frontend how a context is created.
|
||||
* The semantics of this interface depends on which API is used in SET_HW_RENDER earlier.
|
||||
* This interface will be used when the frontend is trying to create a HW rendering context,
|
||||
* so it will be used after SET_HW_RENDER, but before the context_reset callback.
|
||||
*/
|
||||
|
||||
/* Serialized state is incomplete in some way. Set if serialization is
|
||||
* usable in typical end-user cases but should not be relied upon to
|
||||
* implement frame-sensitive frontend features such as netplay or
|
||||
* rerecording. */
|
||||
#define RETRO_SERIALIZATION_QUIRK_INCOMPLETE (1 << 0)
|
||||
/* The core must spend some time initializing before serialization is
|
||||
* supported. retro_serialize() will initially fail; retro_unserialize()
|
||||
* and retro_serialize_size() may or may not work correctly either. */
|
||||
#define RETRO_SERIALIZATION_QUIRK_MUST_INITIALIZE (1 << 1)
|
||||
/* Serialization size may change within a session. */
|
||||
#define RETRO_SERIALIZATION_QUIRK_CORE_VARIABLE_SIZE (1 << 2)
|
||||
/* Set by the frontend to acknowledge that it supports variable-sized
|
||||
* states. */
|
||||
#define RETRO_SERIALIZATION_QUIRK_FRONT_VARIABLE_SIZE (1 << 3)
|
||||
/* Serialized state can only be loaded during the same session. */
|
||||
#define RETRO_SERIALIZATION_QUIRK_SINGLE_SESSION (1 << 4)
|
||||
/* Serialized state cannot be loaded on an architecture with a different
|
||||
* endianness from the one it was saved on. */
|
||||
#define RETRO_SERIALIZATION_QUIRK_ENDIAN_DEPENDENT (1 << 5)
|
||||
/* Serialized state cannot be loaded on a different platform from the one it
|
||||
* was saved on for reasons other than endianness, such as word size
|
||||
* dependence */
|
||||
#define RETRO_SERIALIZATION_QUIRK_PLATFORM_DEPENDENT (1 << 6)
|
||||
|
||||
#define RETRO_ENVIRONMENT_SET_SERIALIZATION_QUIRKS 44
|
||||
/* uint64_t * --
|
||||
* Sets quirk flags associated with serialization. The frontend will zero any flags it doesn't
|
||||
* recognize or support. Should be set in either retro_init or retro_load_game, but not both.
|
||||
*/
|
||||
|
||||
#define RETRO_MEMDESC_CONST (1 << 0) /* The frontend will never change this memory area once retro_load_game has returned. */
|
||||
#define RETRO_MEMDESC_BIGENDIAN (1 << 1) /* The memory area contains big endian data. Default is little endian. */
|
||||
#define RETRO_MEMDESC_ALIGN_2 (1 << 16) /* All memory access in this area is aligned to their own size, or 2, whichever is smaller. */
|
||||
@ -1010,9 +1199,9 @@ struct retro_memory_descriptor
|
||||
|
||||
/* To go from emulated address to physical address, the following
|
||||
* order applies:
|
||||
* Subtract 'start', pick off 'disconnect', apply 'len', add 'offset'.
|
||||
*
|
||||
* The address space name must consist of only a-zA-Z0-9_-,
|
||||
* Subtract 'start', pick off 'disconnect', apply 'len', add 'offset'. */
|
||||
|
||||
/* The address space name must consist of only a-zA-Z0-9_-,
|
||||
* should be as short as feasible (maximum length is 8 plus the NUL),
|
||||
* and may not be any other address space plus one or more 0-9A-F
|
||||
* at the end.
|
||||
@ -1038,6 +1227,37 @@ struct retro_memory_descriptor
|
||||
* The length can't be used for that purpose; the frontend may want
|
||||
* to append arbitrary data to an address, without a separator. */
|
||||
const char *addrspace;
|
||||
|
||||
/* TODO: When finalizing this one, add a description field, which should be
|
||||
* "WRAM" or something roughly equally long. */
|
||||
|
||||
/* TODO: When finalizing this one, replace 'select' with 'limit', which tells
|
||||
* which bits can vary and still refer to the same address (limit = ~select).
|
||||
* TODO: limit? range? vary? something else? */
|
||||
|
||||
/* TODO: When finalizing this one, if 'len' is above what 'select' (or
|
||||
* 'limit') allows, it's bankswitched. Bankswitched data must have both 'len'
|
||||
* and 'select' != 0, and the mappings don't tell how the system switches the
|
||||
* banks. */
|
||||
|
||||
/* TODO: When finalizing this one, fix the 'len' bit removal order.
|
||||
* For len=0x1800, pointer 0x1C00 should go to 0x1400, not 0x0C00.
|
||||
* Algorithm: Take bits highest to lowest, but if it goes above len, clear
|
||||
* the most recent addition and continue on the next bit.
|
||||
* TODO: Can the above be optimized? Is "remove the lowest bit set in both
|
||||
* pointer and 'len'" equivalent? */
|
||||
|
||||
/* TODO: Some emulators (MAME?) emulate big endian systems by only accessing
|
||||
* the emulated memory in 32-bit chunks, native endian. But that's nothing
|
||||
* compared to Darek Mihocka <http://www.emulators.com/docs/nx07_vm101.htm>
|
||||
* (section Emulation 103 - Nearly Free Byte Reversal) - he flips the ENTIRE
|
||||
* RAM backwards! I'll want to represent both of those, via some flags.
|
||||
*
|
||||
* I suspect MAME either didn't think of that idea, or don't want the #ifdef.
|
||||
* Not sure which, nor do I really care. */
|
||||
|
||||
/* TODO: Some of those flags are unused and/or don't really make sense. Clean
|
||||
* them up. */
|
||||
};
|
||||
|
||||
/* The frontend may use the largest value of 'start'+'select' in a
|
||||
@ -1167,7 +1387,7 @@ struct retro_subsystem_info
|
||||
unsigned id;
|
||||
};
|
||||
|
||||
typedef void (*retro_proc_address_t)(void);
|
||||
typedef void (RETRO_CALLCONV *retro_proc_address_t)(void);
|
||||
|
||||
/* libretro API extension functions:
|
||||
* (None here so far).
|
||||
@ -1183,7 +1403,7 @@ typedef void (*retro_proc_address_t)(void);
|
||||
* e.g. if void retro_foo(void); exists, the symbol must be called "retro_foo".
|
||||
* The returned function pointer must be cast to the corresponding type.
|
||||
*/
|
||||
typedef retro_proc_address_t (*retro_get_proc_address_t)(const char *sym);
|
||||
typedef retro_proc_address_t (RETRO_CALLCONV *retro_get_proc_address_t)(const char *sym);
|
||||
|
||||
struct retro_get_proc_address_interface
|
||||
{
|
||||
@ -1201,7 +1421,7 @@ enum retro_log_level
|
||||
};
|
||||
|
||||
/* Logging function. Takes log level argument as well. */
|
||||
typedef void (*retro_log_printf_t)(enum retro_log_level level,
|
||||
typedef void (RETRO_CALLCONV *retro_log_printf_t)(enum retro_log_level level,
|
||||
const char *fmt, ...);
|
||||
|
||||
struct retro_log_callback
|
||||
@ -1232,6 +1452,8 @@ struct retro_log_callback
|
||||
#define RETRO_SIMD_VFPV4 (1 << 17)
|
||||
#define RETRO_SIMD_POPCNT (1 << 18)
|
||||
#define RETRO_SIMD_MOVBE (1 << 19)
|
||||
#define RETRO_SIMD_CMOV (1 << 20)
|
||||
#define RETRO_SIMD_ASIMD (1 << 21)
|
||||
|
||||
typedef uint64_t retro_perf_tick_t;
|
||||
typedef int64_t retro_time_t;
|
||||
@ -1249,34 +1471,34 @@ struct retro_perf_counter
|
||||
/* Returns current time in microseconds.
|
||||
* Tries to use the most accurate timer available.
|
||||
*/
|
||||
typedef retro_time_t (*retro_perf_get_time_usec_t)(void);
|
||||
typedef retro_time_t (RETRO_CALLCONV *retro_perf_get_time_usec_t)(void);
|
||||
|
||||
/* A simple counter. Usually nanoseconds, but can also be CPU cycles.
|
||||
* Can be used directly if desired (when creating a more sophisticated
|
||||
* performance counter system).
|
||||
* */
|
||||
typedef retro_perf_tick_t (*retro_perf_get_counter_t)(void);
|
||||
typedef retro_perf_tick_t (RETRO_CALLCONV *retro_perf_get_counter_t)(void);
|
||||
|
||||
/* Returns a bit-mask of detected CPU features (RETRO_SIMD_*). */
|
||||
typedef uint64_t (*retro_get_cpu_features_t)(void);
|
||||
typedef uint64_t (RETRO_CALLCONV *retro_get_cpu_features_t)(void);
|
||||
|
||||
/* Asks frontend to log and/or display the state of performance counters.
|
||||
* Performance counters can always be poked into manually as well.
|
||||
*/
|
||||
typedef void (*retro_perf_log_t)(void);
|
||||
typedef void (RETRO_CALLCONV *retro_perf_log_t)(void);
|
||||
|
||||
/* Register a performance counter.
|
||||
* ident field must be set with a discrete value and other values in
|
||||
* retro_perf_counter must be 0.
|
||||
* Registering can be called multiple times. To avoid calling to
|
||||
* frontend redundantly, you can check registered field first. */
|
||||
typedef void (*retro_perf_register_t)(struct retro_perf_counter *counter);
|
||||
typedef void (RETRO_CALLCONV *retro_perf_register_t)(struct retro_perf_counter *counter);
|
||||
|
||||
/* Starts a registered counter. */
|
||||
typedef void (*retro_perf_start_t)(struct retro_perf_counter *counter);
|
||||
typedef void (RETRO_CALLCONV *retro_perf_start_t)(struct retro_perf_counter *counter);
|
||||
|
||||
/* Stops a registered counter. */
|
||||
typedef void (*retro_perf_stop_t)(struct retro_perf_counter *counter);
|
||||
typedef void (RETRO_CALLCONV *retro_perf_stop_t)(struct retro_perf_counter *counter);
|
||||
|
||||
/* For convenience it can be useful to wrap register, start and stop in macros.
|
||||
* E.g.:
|
||||
@ -1339,10 +1561,10 @@ enum retro_sensor_action
|
||||
#define RETRO_SENSOR_ACCELEROMETER_Y 1
|
||||
#define RETRO_SENSOR_ACCELEROMETER_Z 2
|
||||
|
||||
typedef bool (*retro_set_sensor_state_t)(unsigned port,
|
||||
typedef bool (RETRO_CALLCONV *retro_set_sensor_state_t)(unsigned port,
|
||||
enum retro_sensor_action action, unsigned rate);
|
||||
|
||||
typedef float (*retro_sensor_get_input_t)(unsigned port, unsigned id);
|
||||
typedef float (RETRO_CALLCONV *retro_sensor_get_input_t)(unsigned port, unsigned id);
|
||||
|
||||
struct retro_sensor_interface
|
||||
{
|
||||
@ -1359,22 +1581,22 @@ enum retro_camera_buffer
|
||||
};
|
||||
|
||||
/* Starts the camera driver. Can only be called in retro_run(). */
|
||||
typedef bool (*retro_camera_start_t)(void);
|
||||
typedef bool (RETRO_CALLCONV *retro_camera_start_t)(void);
|
||||
|
||||
/* Stops the camera driver. Can only be called in retro_run(). */
|
||||
typedef void (*retro_camera_stop_t)(void);
|
||||
typedef void (RETRO_CALLCONV *retro_camera_stop_t)(void);
|
||||
|
||||
/* Callback which signals when the camera driver is initialized
|
||||
* and/or deinitialized.
|
||||
* retro_camera_start_t can be called in initialized callback.
|
||||
*/
|
||||
typedef void (*retro_camera_lifetime_status_t)(void);
|
||||
typedef void (RETRO_CALLCONV *retro_camera_lifetime_status_t)(void);
|
||||
|
||||
/* A callback for raw framebuffer data. buffer points to an XRGB8888 buffer.
|
||||
* Width, height and pitch are similar to retro_video_refresh_t.
|
||||
* First pixel is top-left origin.
|
||||
*/
|
||||
typedef void (*retro_camera_frame_raw_framebuffer_t)(const uint32_t *buffer,
|
||||
typedef void (RETRO_CALLCONV *retro_camera_frame_raw_framebuffer_t)(const uint32_t *buffer,
|
||||
unsigned width, unsigned height, size_t pitch);
|
||||
|
||||
/* A callback for when OpenGL textures are used.
|
||||
@ -1395,7 +1617,7 @@ typedef void (*retro_camera_frame_raw_framebuffer_t)(const uint32_t *buffer,
|
||||
* GL-specific typedefs are avoided here to avoid relying on gl.h in
|
||||
* the API definition.
|
||||
*/
|
||||
typedef void (*retro_camera_frame_opengl_texture_t)(unsigned texture_id,
|
||||
typedef void (RETRO_CALLCONV *retro_camera_frame_opengl_texture_t)(unsigned texture_id,
|
||||
unsigned texture_target, const float *affine);
|
||||
|
||||
struct retro_camera_callback
|
||||
@ -1441,28 +1663,28 @@ struct retro_camera_callback
|
||||
* interval_ms is the interval expressed in milliseconds.
|
||||
* interval_distance is the distance interval expressed in meters.
|
||||
*/
|
||||
typedef void (*retro_location_set_interval_t)(unsigned interval_ms,
|
||||
typedef void (RETRO_CALLCONV *retro_location_set_interval_t)(unsigned interval_ms,
|
||||
unsigned interval_distance);
|
||||
|
||||
/* Start location services. The device will start listening for changes to the
|
||||
* current location at regular intervals (which are defined with
|
||||
* retro_location_set_interval_t). */
|
||||
typedef bool (*retro_location_start_t)(void);
|
||||
typedef bool (RETRO_CALLCONV *retro_location_start_t)(void);
|
||||
|
||||
/* Stop location services. The device will stop listening for changes
|
||||
* to the current location. */
|
||||
typedef void (*retro_location_stop_t)(void);
|
||||
typedef void (RETRO_CALLCONV *retro_location_stop_t)(void);
|
||||
|
||||
/* Get the position of the current location. Will set parameters to
|
||||
* 0 if no new location update has happened since the last time. */
|
||||
typedef bool (*retro_location_get_position_t)(double *lat, double *lon,
|
||||
typedef bool (RETRO_CALLCONV *retro_location_get_position_t)(double *lat, double *lon,
|
||||
double *horiz_accuracy, double *vert_accuracy);
|
||||
|
||||
/* Callback which signals when the location driver is initialized
|
||||
* and/or deinitialized.
|
||||
* retro_location_start_t can be called in initialized callback.
|
||||
*/
|
||||
typedef void (*retro_location_lifetime_status_t)(void);
|
||||
typedef void (RETRO_CALLCONV *retro_location_lifetime_status_t)(void);
|
||||
|
||||
struct retro_location_callback
|
||||
{
|
||||
@ -1490,7 +1712,7 @@ enum retro_rumble_effect
|
||||
*
|
||||
* Returns true if rumble state request was honored.
|
||||
* Calling this before first retro_run() is likely to return false. */
|
||||
typedef bool (*retro_set_rumble_state_t)(unsigned port,
|
||||
typedef bool (RETRO_CALLCONV *retro_set_rumble_state_t)(unsigned port,
|
||||
enum retro_rumble_effect effect, uint16_t strength);
|
||||
|
||||
struct retro_rumble_interface
|
||||
@ -1499,7 +1721,7 @@ struct retro_rumble_interface
|
||||
};
|
||||
|
||||
/* Notifies libretro that audio data should be written. */
|
||||
typedef void (*retro_audio_callback_t)(void);
|
||||
typedef void (RETRO_CALLCONV *retro_audio_callback_t)(void);
|
||||
|
||||
/* True: Audio driver in frontend is active, and callback is
|
||||
* expected to be called regularily.
|
||||
@ -1508,7 +1730,7 @@ typedef void (*retro_audio_callback_t)(void);
|
||||
* called with true.
|
||||
* Initial state is false (inactive).
|
||||
*/
|
||||
typedef void (*retro_audio_set_state_callback_t)(bool enabled);
|
||||
typedef void (RETRO_CALLCONV *retro_audio_set_state_callback_t)(bool enabled);
|
||||
|
||||
struct retro_audio_callback
|
||||
{
|
||||
@ -1525,7 +1747,7 @@ struct retro_audio_callback
|
||||
*
|
||||
* In those scenarios the reference frame time value will be used. */
|
||||
typedef int64_t retro_usec_t;
|
||||
typedef void (*retro_frame_time_callback_t)(retro_usec_t usec);
|
||||
typedef void (RETRO_CALLCONV *retro_frame_time_callback_t)(retro_usec_t usec);
|
||||
struct retro_frame_time_callback
|
||||
{
|
||||
retro_frame_time_callback_t callback;
|
||||
@ -1549,15 +1771,15 @@ struct retro_frame_time_callback
|
||||
* Also called first time video driver is initialized,
|
||||
* allowing libretro core to initialize resources.
|
||||
*/
|
||||
typedef void (*retro_hw_context_reset_t)(void);
|
||||
typedef void (RETRO_CALLCONV *retro_hw_context_reset_t)(void);
|
||||
|
||||
/* Gets current framebuffer which is to be rendered to.
|
||||
* Could change every frame potentially.
|
||||
*/
|
||||
typedef uintptr_t (*retro_hw_get_current_framebuffer_t)(void);
|
||||
typedef uintptr_t (RETRO_CALLCONV *retro_hw_get_current_framebuffer_t)(void);
|
||||
|
||||
/* Get a symbol from HW context. */
|
||||
typedef retro_proc_address_t (*retro_hw_get_proc_address_t)(const char *sym);
|
||||
typedef retro_proc_address_t (RETRO_CALLCONV *retro_hw_get_proc_address_t)(const char *sym);
|
||||
|
||||
enum retro_hw_context_type
|
||||
{
|
||||
@ -1605,7 +1827,8 @@ struct retro_hw_render_callback
|
||||
* be providing preallocated framebuffers. */
|
||||
retro_hw_get_current_framebuffer_t get_current_framebuffer;
|
||||
|
||||
/* Set by frontend. */
|
||||
/* Set by frontend.
|
||||
* Can return all relevant functions, including glClear on Windows. */
|
||||
retro_hw_get_proc_address_t get_proc_address;
|
||||
|
||||
/* Set if render buffers should have depth component attached.
|
||||
@ -1682,7 +1905,7 @@ struct retro_hw_render_callback
|
||||
* Similarily if only a keycode event is generated with no corresponding
|
||||
* character, character should be 0.
|
||||
*/
|
||||
typedef void (*retro_keyboard_event_t)(bool down, unsigned keycode,
|
||||
typedef void (RETRO_CALLCONV *retro_keyboard_event_t)(bool down, unsigned keycode,
|
||||
uint32_t character, uint16_t key_modifiers);
|
||||
|
||||
struct retro_keyboard_callback
|
||||
@ -1706,24 +1929,24 @@ struct retro_keyboard_callback
|
||||
/* If ejected is true, "ejects" the virtual disk tray.
|
||||
* When ejected, the disk image index can be set.
|
||||
*/
|
||||
typedef bool (*retro_set_eject_state_t)(bool ejected);
|
||||
typedef bool (RETRO_CALLCONV *retro_set_eject_state_t)(bool ejected);
|
||||
|
||||
/* Gets current eject state. The initial state is 'not ejected'. */
|
||||
typedef bool (*retro_get_eject_state_t)(void);
|
||||
typedef bool (RETRO_CALLCONV *retro_get_eject_state_t)(void);
|
||||
|
||||
/* Gets current disk index. First disk is index 0.
|
||||
* If return value is >= get_num_images(), no disk is currently inserted.
|
||||
*/
|
||||
typedef unsigned (*retro_get_image_index_t)(void);
|
||||
typedef unsigned (RETRO_CALLCONV *retro_get_image_index_t)(void);
|
||||
|
||||
/* Sets image index. Can only be called when disk is ejected.
|
||||
* The implementation supports setting "no disk" by using an
|
||||
* index >= get_num_images().
|
||||
*/
|
||||
typedef bool (*retro_set_image_index_t)(unsigned index);
|
||||
typedef bool (RETRO_CALLCONV *retro_set_image_index_t)(unsigned index);
|
||||
|
||||
/* Gets total number of images which are available to use. */
|
||||
typedef unsigned (*retro_get_num_images_t)(void);
|
||||
typedef unsigned (RETRO_CALLCONV *retro_get_num_images_t)(void);
|
||||
|
||||
struct retro_game_info;
|
||||
|
||||
@ -1739,14 +1962,14 @@ struct retro_game_info;
|
||||
* returned 4 before.
|
||||
* Index 1 will be removed, and the new index is 3.
|
||||
*/
|
||||
typedef bool (*retro_replace_image_index_t)(unsigned index,
|
||||
typedef bool (RETRO_CALLCONV *retro_replace_image_index_t)(unsigned index,
|
||||
const struct retro_game_info *info);
|
||||
|
||||
/* Adds a new valid index (get_num_images()) to the internal disk list.
|
||||
* This will increment subsequent return values from get_num_images() by 1.
|
||||
* This image index cannot be used until a disk image has been set
|
||||
* with replace_image_index. */
|
||||
typedef bool (*retro_add_image_index_t)(void);
|
||||
typedef bool (RETRO_CALLCONV *retro_add_image_index_t)(void);
|
||||
|
||||
struct retro_disk_control_callback
|
||||
{
|
||||
@ -1888,10 +2111,12 @@ struct retro_variable
|
||||
struct retro_game_info
|
||||
{
|
||||
const char *path; /* Path to game, UTF-8 encoded.
|
||||
* Usually used as a reference.
|
||||
* May be NULL if rom was loaded from stdin
|
||||
* or similar.
|
||||
* retro_system_info::need_fullpath guaranteed
|
||||
* Sometimes used as a reference for building other paths.
|
||||
* May be NULL if game was loaded from stdin or similar,
|
||||
* but in this case some cores will be unable to load `data`.
|
||||
* So, it is preferable to fabricate something here instead
|
||||
* of passing NULL, which will help more cores to succeed.
|
||||
* retro_system_info::need_fullpath requires
|
||||
* that this path is valid. */
|
||||
const void *data; /* Memory buffer of loaded game. Will be NULL
|
||||
* if need_fullpath was set. */
|
||||
@ -1933,7 +2158,7 @@ struct retro_framebuffer
|
||||
|
||||
/* Environment callback. Gives implementations a way of performing
|
||||
* uncommon tasks. Extensible. */
|
||||
typedef bool (*retro_environment_t)(unsigned cmd, void *data);
|
||||
typedef bool (RETRO_CALLCONV *retro_environment_t)(unsigned cmd, void *data);
|
||||
|
||||
/* Render a frame. Pixel format is 15-bit 0RGB1555 native endian
|
||||
* unless changed (see RETRO_ENVIRONMENT_SET_PIXEL_FORMAT).
|
||||
@ -1946,14 +2171,14 @@ typedef bool (*retro_environment_t)(unsigned cmd, void *data);
|
||||
* Certain graphic APIs, such as OpenGL ES, do not like textures
|
||||
* that are not packed in memory.
|
||||
*/
|
||||
typedef void (*retro_video_refresh_t)(const void *data, unsigned width,
|
||||
typedef void (RETRO_CALLCONV *retro_video_refresh_t)(const void *data, unsigned width,
|
||||
unsigned height, size_t pitch);
|
||||
|
||||
/* Renders a single audio frame. Should only be used if implementation
|
||||
* generates a single sample at a time.
|
||||
* Format is signed 16-bit native endian.
|
||||
*/
|
||||
typedef void (*retro_audio_sample_t)(int16_t left, int16_t right);
|
||||
typedef void (RETRO_CALLCONV *retro_audio_sample_t)(int16_t left, int16_t right);
|
||||
|
||||
/* Renders multiple audio frames in one go.
|
||||
*
|
||||
@ -1961,11 +2186,11 @@ typedef void (*retro_audio_sample_t)(int16_t left, int16_t right);
|
||||
* I.e. int16_t buf[4] = { l, r, l, r }; would be 2 frames.
|
||||
* Only one of the audio callbacks must ever be used.
|
||||
*/
|
||||
typedef size_t (*retro_audio_sample_batch_t)(const int16_t *data,
|
||||
typedef size_t (RETRO_CALLCONV *retro_audio_sample_batch_t)(const int16_t *data,
|
||||
size_t frames);
|
||||
|
||||
/* Polls input. */
|
||||
typedef void (*retro_input_poll_t)(void);
|
||||
typedef void (RETRO_CALLCONV *retro_input_poll_t)(void);
|
||||
|
||||
/* Queries for input for player 'port'. device will be masked with
|
||||
* RETRO_DEVICE_MASK.
|
||||
@ -1974,7 +2199,7 @@ typedef void (*retro_input_poll_t)(void);
|
||||
* have been set with retro_set_controller_port_device()
|
||||
* will still use the higher level RETRO_DEVICE_JOYPAD to request input.
|
||||
*/
|
||||
typedef int16_t (*retro_input_state_t)(unsigned port, unsigned device,
|
||||
typedef int16_t (RETRO_CALLCONV *retro_input_state_t)(unsigned port, unsigned device,
|
||||
unsigned index, unsigned id);
|
||||
|
||||
/* Sets callbacks. retro_set_environment() is guaranteed to be called
|
@ -23,37 +23,48 @@
|
||||
#ifndef __LIBRETRO_SDK_FILE_STREAM_H
|
||||
#define __LIBRETRO_SDK_FILE_STREAM_H
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdint.h>
|
||||
#include <stdlib.h>
|
||||
#include <stddef.h>
|
||||
|
||||
#include <sys/types.h>
|
||||
|
||||
#include <libretro.h>
|
||||
#include <retro_common_api.h>
|
||||
#include <retro_inline.h>
|
||||
#include <boolean.h>
|
||||
|
||||
#include <stdarg.h>
|
||||
|
||||
#define FILESTREAM_REQUIRED_VFS_VERSION 1
|
||||
|
||||
RETRO_BEGIN_DECLS
|
||||
|
||||
typedef struct RFILE RFILE;
|
||||
|
||||
enum
|
||||
{
|
||||
RFILE_MODE_READ = 0,
|
||||
RFILE_MODE_READ_TEXT,
|
||||
RFILE_MODE_WRITE,
|
||||
RFILE_MODE_READ_WRITE,
|
||||
#define FILESTREAM_REQUIRED_VFS_VERSION 1
|
||||
|
||||
/* There is no garantee these requests will be attended. */
|
||||
RFILE_HINT_UNBUFFERED = 1<<8,
|
||||
RFILE_HINT_MMAP = 1<<9 /* requires RFILE_MODE_READ */
|
||||
};
|
||||
void filestream_vfs_init(const struct retro_vfs_interface_info* vfs_info);
|
||||
|
||||
RFILE *filestream_open(const char *path, unsigned mode, ssize_t len);
|
||||
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);
|
||||
|
||||
ssize_t filestream_seek(RFILE *stream, ssize_t offset, int whence);
|
||||
|
||||
ssize_t filestream_read(RFILE *stream, void *data, size_t len);
|
||||
ssize_t filestream_read(RFILE *stream, void *data, int64_t len);
|
||||
|
||||
ssize_t filestream_write(RFILE *stream, const void *data, size_t len);
|
||||
ssize_t filestream_write(RFILE *stream, const void *data, int64_t len);
|
||||
|
||||
ssize_t filestream_tell(RFILE *stream);
|
||||
|
||||
@ -65,8 +76,6 @@ int filestream_read_file(const char *path, void **buf, ssize_t *len);
|
||||
|
||||
char *filestream_gets(RFILE *stream, char *s, size_t len);
|
||||
|
||||
char *filestream_getline(RFILE *stream);
|
||||
|
||||
int filestream_getc(RFILE *stream);
|
||||
|
||||
int filestream_eof(RFILE *stream);
|
||||
@ -75,7 +84,23 @@ bool filestream_write_file(const char *path, const void *data, ssize_t size);
|
||||
|
||||
int filestream_putc(RFILE *stream, int c);
|
||||
|
||||
int filestream_get_fd(RFILE *stream);
|
||||
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
|
||||
|
||||
|
65
libgambatte/libretro-common/include/vfs/vfs_implementation.h
Normal file
65
libgambatte/libretro-common/include/vfs/vfs_implementation.h
Normal file
@ -0,0 +1,65 @@
|
||||
/* Copyright (C) 2010-2017 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 <stdint.h>
|
||||
#include <libretro.h>
|
||||
|
||||
/* 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 whence);
|
||||
|
||||
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
|
@ -23,546 +23,342 @@
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <stdarg.h>
|
||||
#include <errno.h>
|
||||
|
||||
#if defined(_WIN32)
|
||||
# ifdef _MSC_VER
|
||||
# define setmode _setmode
|
||||
# endif
|
||||
# ifdef _XBOX
|
||||
# include <xtl.h>
|
||||
# define INVALID_FILE_ATTRIBUTES -1
|
||||
# else
|
||||
# include <io.h>
|
||||
# include <fcntl.h>
|
||||
# include <direct.h>
|
||||
# include <windows.h>
|
||||
# endif
|
||||
#else
|
||||
# if defined(PSP)
|
||||
# include <pspiofilemgr.h>
|
||||
# endif
|
||||
# include <sys/types.h>
|
||||
# include <sys/stat.h>
|
||||
# if !defined(VITA)
|
||||
# include <dirent.h>
|
||||
# endif
|
||||
# include <unistd.h>
|
||||
#endif
|
||||
|
||||
#ifdef __CELLOS_LV2__
|
||||
#include <cell/cell_fs.h>
|
||||
#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 <fcntl.h>
|
||||
#ifdef HAVE_CONFIG_H
|
||||
#include "config.h"
|
||||
#endif
|
||||
|
||||
#include <streams/file_stream.h>
|
||||
#include <memmap.h>
|
||||
#include <retro_miscellaneous.h>
|
||||
#include <vfs/vfs_implementation.h>
|
||||
|
||||
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
|
||||
{
|
||||
unsigned hints;
|
||||
char *ext;
|
||||
long long int size;
|
||||
#if defined(PSP)
|
||||
SceUID fd;
|
||||
#else
|
||||
|
||||
#define HAVE_BUFFERED_IO 1
|
||||
|
||||
#define MODE_STR_READ "r"
|
||||
#define MODE_STR_READ_UNBUF "rb"
|
||||
#define MODE_STR_WRITE_UNBUF "wb"
|
||||
#define MODE_STR_WRITE_PLUS "w+"
|
||||
|
||||
#if defined(HAVE_BUFFERED_IO)
|
||||
FILE *fp;
|
||||
#endif
|
||||
#if defined(HAVE_MMAP)
|
||||
uint8_t *mapped;
|
||||
uint64_t mappos;
|
||||
uint64_t mapsize;
|
||||
#endif
|
||||
int fd;
|
||||
#endif
|
||||
struct retro_vfs_file_handle *hfile;
|
||||
bool error_flag;
|
||||
};
|
||||
|
||||
int filestream_get_fd(RFILE *stream)
|
||||
{
|
||||
if (!stream)
|
||||
return -1;
|
||||
#if defined(HAVE_BUFFERED_IO)
|
||||
if ((stream->hints & RFILE_HINT_UNBUFFERED) == 0)
|
||||
return fileno(stream->fp);
|
||||
#endif
|
||||
return stream->fd;
|
||||
}
|
||||
/* VFS Initialization */
|
||||
|
||||
const char *filestream_get_ext(RFILE *stream)
|
||||
void filestream_vfs_init(const struct retro_vfs_interface_info* vfs_info)
|
||||
{
|
||||
if (!stream)
|
||||
return NULL;
|
||||
return stream->ext;
|
||||
}
|
||||
const struct retro_vfs_interface* vfs_iface;
|
||||
|
||||
long long int filestream_get_size(RFILE *stream)
|
||||
{
|
||||
if (!stream)
|
||||
return 0;
|
||||
return stream->size;
|
||||
}
|
||||
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;
|
||||
|
||||
void filestream_set_size(RFILE *stream)
|
||||
{
|
||||
if (!stream)
|
||||
vfs_iface = vfs_info->iface;
|
||||
|
||||
if (vfs_info->required_interface_version < FILESTREAM_REQUIRED_VFS_VERSION
|
||||
|| !vfs_iface)
|
||||
return;
|
||||
|
||||
filestream_seek(stream, 0, SEEK_SET);
|
||||
filestream_seek(stream, 0, SEEK_END);
|
||||
|
||||
stream->size = filestream_tell(stream);
|
||||
|
||||
filestream_seek(stream, 0, SEEK_SET);
|
||||
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;
|
||||
}
|
||||
|
||||
RFILE *filestream_open(const char *path, unsigned mode, ssize_t len)
|
||||
/* Callback wrappers */
|
||||
bool filestream_exists(const char *path)
|
||||
{
|
||||
int flags = 0;
|
||||
int mode_int = 0;
|
||||
#if defined(HAVE_BUFFERED_IO)
|
||||
const char *mode_str = NULL;
|
||||
#endif
|
||||
RFILE *stream = (RFILE*)calloc(1, sizeof(*stream));
|
||||
RFILE *dummy = NULL;
|
||||
|
||||
if (!stream)
|
||||
return NULL;
|
||||
if (!path || !*path)
|
||||
return false;
|
||||
|
||||
(void)mode_int;
|
||||
(void)flags;
|
||||
dummy = filestream_open(path,
|
||||
RETRO_VFS_FILE_ACCESS_READ,
|
||||
RETRO_VFS_FILE_ACCESS_HINT_NONE);
|
||||
|
||||
stream->hints = mode;
|
||||
if (!dummy)
|
||||
return false;
|
||||
|
||||
#ifdef HAVE_MMAP
|
||||
if (stream->hints & RFILE_HINT_MMAP && (stream->hints & 0xff) == RFILE_MODE_READ)
|
||||
stream->hints |= RFILE_HINT_UNBUFFERED;
|
||||
else
|
||||
#endif
|
||||
stream->hints &= ~RFILE_HINT_MMAP;
|
||||
|
||||
switch (mode & 0xff)
|
||||
{
|
||||
case RFILE_MODE_READ_TEXT:
|
||||
#if defined(PSP)
|
||||
mode_int = 0666;
|
||||
flags = PSP_O_RDONLY;
|
||||
#else
|
||||
#if defined(HAVE_BUFFERED_IO)
|
||||
if ((stream->hints & RFILE_HINT_UNBUFFERED) == 0)
|
||||
mode_str = MODE_STR_READ;
|
||||
#endif
|
||||
/* No "else" here */
|
||||
flags = O_RDONLY;
|
||||
#endif
|
||||
break;
|
||||
case RFILE_MODE_READ:
|
||||
#if defined(PSP)
|
||||
mode_int = 0666;
|
||||
flags = PSP_O_RDONLY;
|
||||
#else
|
||||
#if defined(HAVE_BUFFERED_IO)
|
||||
if ((stream->hints & RFILE_HINT_UNBUFFERED) == 0)
|
||||
mode_str = MODE_STR_READ_UNBUF;
|
||||
#endif
|
||||
/* No "else" here */
|
||||
flags = O_RDONLY;
|
||||
#endif
|
||||
break;
|
||||
case RFILE_MODE_WRITE:
|
||||
#if defined(PSP)
|
||||
mode_int = 0666;
|
||||
flags = PSP_O_CREAT | PSP_O_WRONLY | PSP_O_TRUNC;
|
||||
#else
|
||||
#if defined(HAVE_BUFFERED_IO)
|
||||
if ((stream->hints & RFILE_HINT_UNBUFFERED) == 0)
|
||||
mode_str = MODE_STR_WRITE_UNBUF;
|
||||
#endif
|
||||
else
|
||||
{
|
||||
flags = O_WRONLY | O_CREAT | O_TRUNC;
|
||||
#ifndef _WIN32
|
||||
flags |= S_IRUSR | S_IWUSR;
|
||||
#endif
|
||||
}
|
||||
#endif
|
||||
break;
|
||||
case RFILE_MODE_READ_WRITE:
|
||||
#if defined(PSP)
|
||||
mode_int = 0666;
|
||||
flags = PSP_O_RDWR;
|
||||
#else
|
||||
#if defined(HAVE_BUFFERED_IO)
|
||||
if ((stream->hints & RFILE_HINT_UNBUFFERED) == 0)
|
||||
mode_str = MODE_STR_WRITE_PLUS;
|
||||
#endif
|
||||
else
|
||||
{
|
||||
flags = O_RDWR;
|
||||
#ifdef _WIN32
|
||||
flags |= O_BINARY;
|
||||
#endif
|
||||
}
|
||||
#endif
|
||||
break;
|
||||
}
|
||||
|
||||
#if defined(PSP)
|
||||
stream->fd = sceIoOpen(path, flags, mode_int);
|
||||
#else
|
||||
#if defined(HAVE_BUFFERED_IO)
|
||||
if ((stream->hints & RFILE_HINT_UNBUFFERED) == 0 && mode_str)
|
||||
{
|
||||
stream->fp = fopen(path, mode_str);
|
||||
if (!stream->fp)
|
||||
goto error;
|
||||
}
|
||||
else
|
||||
#endif
|
||||
{
|
||||
/* FIXME: HAVE_BUFFERED_IO is always 1, but if it is ever changed, open() needs to be changed to _wopen() for WIndows. */
|
||||
stream->fd = open(path, flags, mode_int);
|
||||
if (stream->fd == -1)
|
||||
goto error;
|
||||
#ifdef HAVE_MMAP
|
||||
if (stream->hints & RFILE_HINT_MMAP)
|
||||
{
|
||||
stream->mappos = 0;
|
||||
stream->mapped = NULL;
|
||||
stream->mapsize = filestream_seek(stream, 0, SEEK_END);
|
||||
|
||||
if (stream->mapsize == (uint64_t)-1)
|
||||
goto error;
|
||||
|
||||
filestream_rewind(stream);
|
||||
|
||||
stream->mapped = (uint8_t*)mmap((void*)0,
|
||||
stream->mapsize, PROT_READ, MAP_SHARED, stream->fd, 0);
|
||||
|
||||
if (stream->mapped == MAP_FAILED)
|
||||
stream->hints &= ~RFILE_HINT_MMAP;
|
||||
}
|
||||
#endif
|
||||
}
|
||||
#endif
|
||||
|
||||
#if defined(PSP)
|
||||
if (stream->fd == -1)
|
||||
goto error;
|
||||
#endif
|
||||
|
||||
{
|
||||
const char *ld = (const char*)strrchr(path, '.');
|
||||
stream->ext = strdup(ld ? ld + 1 : "");
|
||||
}
|
||||
|
||||
filestream_set_size(stream);
|
||||
|
||||
return stream;
|
||||
|
||||
error:
|
||||
filestream_close(stream);
|
||||
return NULL;
|
||||
filestream_close(dummy);
|
||||
return true;
|
||||
}
|
||||
|
||||
char *filestream_getline(RFILE *stream)
|
||||
int64_t filestream_get_size(RFILE *stream)
|
||||
{
|
||||
char* newline = (char*)malloc(9);
|
||||
char* newline_tmp = NULL;
|
||||
size_t cur_size = 8;
|
||||
size_t idx = 0;
|
||||
int in = filestream_getc(stream);
|
||||
int64_t output;
|
||||
|
||||
if (!newline)
|
||||
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;
|
||||
|
||||
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;
|
||||
output = (RFILE*)malloc(sizeof(RFILE));
|
||||
output->error_flag = false;
|
||||
output->hfile = fp;
|
||||
return output;
|
||||
}
|
||||
|
||||
char *filestream_gets(RFILE *stream, char *s, size_t len)
|
||||
{
|
||||
int c = 0;
|
||||
char *p = NULL;
|
||||
if (!stream)
|
||||
return NULL;
|
||||
#if defined(HAVE_BUFFERED_IO)
|
||||
return fgets(s, (int)len, stream->fp);
|
||||
#elif defined(PSP)
|
||||
if(filestream_read(stream,s,len)==len)
|
||||
return s;
|
||||
|
||||
/* get max bytes or up to a newline */
|
||||
|
||||
for (p = s, 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;
|
||||
#else
|
||||
return gets(s);
|
||||
#endif
|
||||
return (p);
|
||||
}
|
||||
|
||||
int filestream_getc(RFILE *stream)
|
||||
{
|
||||
char c = 0;
|
||||
(void)c;
|
||||
if (!stream)
|
||||
return 0;
|
||||
#if defined(HAVE_BUFFERED_IO)
|
||||
return fgetc(stream->fp);
|
||||
#elif defined(PSP)
|
||||
if(filestream_read(stream, &c, 1) == 1)
|
||||
return (int)c;
|
||||
return EOF;
|
||||
#else
|
||||
return getc(stream->fd);
|
||||
#endif
|
||||
}
|
||||
|
||||
ssize_t filestream_seek(RFILE *stream, ssize_t offset, int whence)
|
||||
{
|
||||
if (!stream)
|
||||
goto error;
|
||||
int64_t output;
|
||||
|
||||
#if defined(PSP)
|
||||
if (sceIoLseek(stream->fd, (SceOff)offset, whence) == -1)
|
||||
goto error;
|
||||
#else
|
||||
if (filestream_seek_cb != NULL)
|
||||
output = filestream_seek_cb(stream->hfile, offset, whence);
|
||||
else
|
||||
output = retro_vfs_file_seek_impl((libretro_vfs_implementation_file*)stream->hfile, offset, whence);
|
||||
|
||||
#if defined(HAVE_BUFFERED_IO)
|
||||
if ((stream->hints & RFILE_HINT_UNBUFFERED) == 0)
|
||||
return fseek(stream->fp, (long)offset, whence);
|
||||
#endif
|
||||
if (output == vfs_error_return_value)
|
||||
stream->error_flag = true;
|
||||
|
||||
#ifdef HAVE_MMAP
|
||||
/* Need to check stream->mapped because this function is
|
||||
* called in filestream_open() */
|
||||
if (stream->mapped && stream->hints & RFILE_HINT_MMAP)
|
||||
{
|
||||
/* 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;
|
||||
|
||||
#endif
|
||||
|
||||
return 0;
|
||||
|
||||
error:
|
||||
return -1;
|
||||
return output;
|
||||
}
|
||||
|
||||
int filestream_eof(RFILE *stream)
|
||||
{
|
||||
size_t current_position = filestream_tell(stream);
|
||||
size_t end_position = filestream_seek(stream, 0, SEEK_END);
|
||||
|
||||
filestream_seek(stream, current_position, SEEK_SET);
|
||||
int64_t current_position = filestream_tell(stream);
|
||||
int64_t end_position = filestream_get_size(stream);
|
||||
|
||||
if (current_position >= end_position)
|
||||
return 1;
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
ssize_t filestream_tell(RFILE *stream)
|
||||
{
|
||||
if (!stream)
|
||||
goto error;
|
||||
#if defined(PSP)
|
||||
if (sceIoLseek(stream->fd, 0, SEEK_CUR) < 0)
|
||||
goto error;
|
||||
#else
|
||||
#if defined(HAVE_BUFFERED_IO)
|
||||
if ((stream->hints & RFILE_HINT_UNBUFFERED) == 0)
|
||||
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 & RFILE_HINT_MMAP)
|
||||
return stream->mappos;
|
||||
#endif
|
||||
if (lseek(stream->fd, 0, SEEK_CUR) < 0)
|
||||
goto error;
|
||||
#endif
|
||||
ssize_t output;
|
||||
|
||||
return 0;
|
||||
if (filestream_size_cb != NULL)
|
||||
output = filestream_tell_cb(stream->hfile);
|
||||
else
|
||||
output = retro_vfs_file_tell_impl((libretro_vfs_implementation_file*)stream->hfile);
|
||||
|
||||
error:
|
||||
return -1;
|
||||
if (output == vfs_error_return_value)
|
||||
stream->error_flag = true;
|
||||
|
||||
return output;
|
||||
}
|
||||
|
||||
void filestream_rewind(RFILE *stream)
|
||||
{
|
||||
if (!stream)
|
||||
return;
|
||||
filestream_seek(stream, 0L, SEEK_SET);
|
||||
stream->error_flag = false;
|
||||
}
|
||||
|
||||
ssize_t filestream_read(RFILE *stream, void *s, size_t len)
|
||||
ssize_t filestream_read(RFILE *stream, void *s, int64_t len)
|
||||
{
|
||||
if (!stream || !s)
|
||||
goto error;
|
||||
#if defined(PSP)
|
||||
return sceIoRead(stream->fd, s, len);
|
||||
#else
|
||||
#if defined(HAVE_BUFFERED_IO)
|
||||
if ((stream->hints & RFILE_HINT_UNBUFFERED) == 0)
|
||||
return fread(s, 1, len, stream->fp);
|
||||
#endif
|
||||
#ifdef HAVE_MMAP
|
||||
if (stream->hints & RFILE_HINT_MMAP)
|
||||
{
|
||||
if (stream->mappos > stream->mapsize)
|
||||
goto error;
|
||||
int64_t output;
|
||||
|
||||
if (stream->mappos + len > stream->mapsize)
|
||||
len = stream->mapsize - stream->mappos;
|
||||
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);
|
||||
|
||||
memcpy(s, &stream->mapped[stream->mappos], len);
|
||||
stream->mappos += len;
|
||||
if (output == vfs_error_return_value)
|
||||
stream->error_flag = true;
|
||||
|
||||
return len;
|
||||
}
|
||||
#endif
|
||||
return read(stream->fd, s, len);
|
||||
#endif
|
||||
|
||||
error:
|
||||
return -1;
|
||||
return output;
|
||||
}
|
||||
|
||||
int filestream_flush(RFILE *stream)
|
||||
{
|
||||
#if defined(HAVE_BUFFERED_IO)
|
||||
return fflush(stream->fp);
|
||||
#else
|
||||
return 0;
|
||||
#endif
|
||||
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;
|
||||
}
|
||||
|
||||
ssize_t filestream_write(RFILE *stream, const void *s, size_t len)
|
||||
int filestream_delete(const char *path)
|
||||
{
|
||||
if (!stream)
|
||||
goto error;
|
||||
#if defined(PSP)
|
||||
return sceIoWrite(stream->fd, s, len);
|
||||
#else
|
||||
#if defined(HAVE_BUFFERED_IO)
|
||||
if ((stream->hints & RFILE_HINT_UNBUFFERED) == 0)
|
||||
return fwrite(s, 1, len, stream->fp);
|
||||
#endif
|
||||
#ifdef HAVE_MMAP
|
||||
if (stream->hints & RFILE_HINT_MMAP)
|
||||
goto error;
|
||||
#endif
|
||||
return write(stream->fd, s, len);
|
||||
#endif
|
||||
if (filestream_remove_cb != NULL)
|
||||
return filestream_remove_cb(path);
|
||||
|
||||
error:
|
||||
return -1;
|
||||
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);
|
||||
}
|
||||
|
||||
ssize_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);
|
||||
}
|
||||
|
||||
#if defined(HAVE_BUFFERED_IO)
|
||||
return fputc(c, stream->fp);
|
||||
#else
|
||||
/* unimplemented */
|
||||
return EOF;
|
||||
#endif
|
||||
int filestream_vprintf(RFILE *stream, const char* format, va_list args)
|
||||
{
|
||||
static char buffer[8 * 1024];
|
||||
int num_chars = vsprintf(buffer, format, args);
|
||||
|
||||
if (num_chars < 0)
|
||||
return -1;
|
||||
else if (num_chars == 0)
|
||||
return 0;
|
||||
|
||||
return 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)
|
||||
{
|
||||
if (!stream)
|
||||
goto error;
|
||||
int output;
|
||||
struct retro_vfs_file_handle* fp = stream->hfile;
|
||||
|
||||
if (stream->ext)
|
||||
free(stream->ext);
|
||||
|
||||
#if defined(PSP)
|
||||
if (stream->fd > 0)
|
||||
sceIoClose(stream->fd);
|
||||
#else
|
||||
#if defined(HAVE_BUFFERED_IO)
|
||||
if ((stream->hints & RFILE_HINT_UNBUFFERED) == 0)
|
||||
{
|
||||
if (stream->fp)
|
||||
fclose(stream->fp);
|
||||
}
|
||||
if (filestream_close_cb != NULL)
|
||||
output = filestream_close_cb(fp);
|
||||
else
|
||||
#endif
|
||||
#ifdef HAVE_MMAP
|
||||
if (stream->hints & RFILE_HINT_MMAP)
|
||||
munmap(stream->mapped, stream->mapsize);
|
||||
#endif
|
||||
output = retro_vfs_file_close_impl((libretro_vfs_implementation_file*)fp);
|
||||
|
||||
if (stream->fd > 0)
|
||||
close(stream->fd);
|
||||
#endif
|
||||
if (output == 0)
|
||||
free(stream);
|
||||
|
||||
return 0;
|
||||
|
||||
error:
|
||||
return -1;
|
||||
return output;
|
||||
}
|
||||
|
||||
/**
|
||||
@ -578,9 +374,11 @@ error:
|
||||
int filestream_read_file(const char *path, void **buf, ssize_t *len)
|
||||
{
|
||||
ssize_t ret = 0;
|
||||
ssize_t content_buf_size = 0;
|
||||
int64_t content_buf_size = 0;
|
||||
void *content_buf = NULL;
|
||||
RFILE *file = filestream_open(path, RFILE_MODE_READ, -1);
|
||||
RFILE *file = filestream_open(path,
|
||||
RETRO_VFS_FILE_ACCESS_READ,
|
||||
RETRO_VFS_FILE_ACCESS_HINT_NONE);
|
||||
|
||||
if (!file)
|
||||
{
|
||||
@ -588,21 +386,19 @@ int filestream_read_file(const char *path, void **buf, ssize_t *len)
|
||||
goto error;
|
||||
}
|
||||
|
||||
if (filestream_seek(file, 0, SEEK_END) != 0)
|
||||
goto error;
|
||||
content_buf_size = filestream_get_size(file);
|
||||
|
||||
content_buf_size = filestream_tell(file);
|
||||
if (content_buf_size < 0)
|
||||
goto error;
|
||||
|
||||
filestream_rewind(file);
|
||||
|
||||
content_buf = malloc(content_buf_size + 1);
|
||||
content_buf = malloc((size_t)(content_buf_size + 1));
|
||||
|
||||
if (!content_buf)
|
||||
goto error;
|
||||
if ((size_t)(content_buf_size + 1) != (content_buf_size + 1))
|
||||
goto error;
|
||||
|
||||
ret = filestream_read(file, content_buf, content_buf_size);
|
||||
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));
|
||||
@ -646,7 +442,9 @@ error:
|
||||
bool filestream_write_file(const char *path, const void *data, ssize_t size)
|
||||
{
|
||||
ssize_t ret = 0;
|
||||
RFILE *file = filestream_open(path, RFILE_MODE_WRITE, -1);
|
||||
RFILE *file = filestream_open(path,
|
||||
RETRO_VFS_FILE_ACCESS_WRITE,
|
||||
RETRO_VFS_FILE_ACCESS_HINT_NONE);
|
||||
if (!file)
|
||||
return false;
|
||||
|
||||
@ -658,3 +456,38 @@ bool filestream_write_file(const char *path, const void *data, ssize_t size)
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
char *filestream_getline(RFILE *stream)
|
||||
{
|
||||
char* newline = (char*)malloc(9);
|
||||
char* newline_tmp = NULL;
|
||||
size_t cur_size = 8;
|
||||
size_t idx = 0;
|
||||
int in = filestream_getc(stream);
|
||||
|
||||
if (!newline)
|
||||
return NULL;
|
||||
|
||||
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;
|
||||
}
|
||||
|
546
libgambatte/libretro-common/vfs/vfs_implementation.c
Normal file
546
libgambatte/libretro-common/vfs/vfs_implementation.c
Normal file
@ -0,0 +1,546 @@
|
||||
/* Copyright (C) 2010-2017 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 <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <errno.h>
|
||||
|
||||
#ifdef HAVE_CONFIG_H
|
||||
#include "config.h"
|
||||
#endif
|
||||
|
||||
#if defined(_WIN32)
|
||||
# ifdef _MSC_VER
|
||||
# define setmode _setmode
|
||||
# endif
|
||||
# ifdef _XBOX
|
||||
# include <xtl.h>
|
||||
# define INVALID_FILE_ATTRIBUTES -1
|
||||
# else
|
||||
# include <io.h>
|
||||
# include <fcntl.h>
|
||||
# include <direct.h>
|
||||
# include <windows.h>
|
||||
# endif
|
||||
#else
|
||||
# if defined(PSP)
|
||||
# include <pspiofilemgr.h>
|
||||
# endif
|
||||
# include <sys/types.h>
|
||||
# include <sys/stat.h>
|
||||
# if !defined(VITA)
|
||||
# include <dirent.h>
|
||||
# endif
|
||||
# include <unistd.h>
|
||||
#endif
|
||||
|
||||
#ifdef __CELLOS_LV2__
|
||||
#include <cell/cell_fs.h>
|
||||
#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 <fcntl.h>
|
||||
#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
|
||||
|
||||
#define MODE_STR_READ "r"
|
||||
#define MODE_STR_READ_UNBUF "rb"
|
||||
#define MODE_STR_WRITE_UNBUF "wb"
|
||||
#define MODE_STR_WRITE_PLUS "w+"
|
||||
|
||||
#ifdef RARCH_INTERNAL
|
||||
#ifndef VFS_FRONTEND
|
||||
#define VFS_FRONTEND
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#include <vfs/vfs_implementation.h>
|
||||
#include <libretro.h>
|
||||
#include <memmap.h>
|
||||
#include <encodings/utf.h>
|
||||
#include <compat/fopen_utf8.h>
|
||||
|
||||
#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)
|
||||
return fseek(stream->fp, (long)offset, whence);
|
||||
|
||||
#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, (off_t)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:
|
||||
if ((stream->hints & RFILE_HINT_UNBUFFERED) == 0)
|
||||
mode_str = MODE_STR_READ_UNBUF;
|
||||
/* No "else" here */
|
||||
flags = O_RDONLY;
|
||||
break;
|
||||
case RETRO_VFS_FILE_ACCESS_WRITE:
|
||||
if ((stream->hints & RFILE_HINT_UNBUFFERED) == 0)
|
||||
mode_str = MODE_STR_WRITE_UNBUF;
|
||||
else
|
||||
{
|
||||
flags = O_WRONLY | O_CREAT | O_TRUNC;
|
||||
#ifndef _WIN32
|
||||
flags |= S_IRUSR | S_IWUSR;
|
||||
#endif
|
||||
}
|
||||
break;
|
||||
case RETRO_VFS_FILE_ACCESS_READ_WRITE:
|
||||
if ((stream->hints & RFILE_HINT_UNBUFFERED) == 0)
|
||||
mode_str = MODE_STR_WRITE_PLUS;
|
||||
else
|
||||
{
|
||||
flags = O_RDWR;
|
||||
#ifdef _WIN32
|
||||
flags |= O_BINARY;
|
||||
#endif
|
||||
}
|
||||
break;
|
||||
/* TODO/FIXME - implement */
|
||||
case RETRO_VFS_FILE_ACCESS_UPDATE_EXISTING:
|
||||
break;
|
||||
}
|
||||
|
||||
if ((stream->hints & RFILE_HINT_UNBUFFERED) == 0 && mode_str)
|
||||
{
|
||||
stream->fp = fopen_utf8(path, mode_str);
|
||||
|
||||
if (!stream->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->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)
|
||||
return ftell(stream->fp);
|
||||
|
||||
#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 whence)
|
||||
{
|
||||
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);
|
||||
}
|
||||
|
||||
int retro_vfs_file_remove_impl(const char *path)
|
||||
{
|
||||
char *path_local = NULL;
|
||||
wchar_t *path_wide = NULL;
|
||||
|
||||
if (!path || !*path)
|
||||
return false;
|
||||
|
||||
(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 true;
|
||||
}
|
||||
#else
|
||||
path_wide = utf8_to_utf16_string_alloc(path);
|
||||
|
||||
if (path_wide)
|
||||
{
|
||||
int ret = _wremove(path_wide);
|
||||
free(path_wide);
|
||||
|
||||
if (ret == 0)
|
||||
return true;
|
||||
}
|
||||
#endif
|
||||
#else
|
||||
if (remove(path) == 0)
|
||||
return true;
|
||||
#endif
|
||||
return false;
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
free(old_path_wide);
|
||||
}
|
||||
|
||||
if (new_path_wide)
|
||||
free(new_path_wide);
|
||||
#endif
|
||||
return -1;
|
||||
#else
|
||||
return rename(old_path, new_path);
|
||||
#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;
|
||||
}
|
@ -1,6 +1,6 @@
|
||||
#include <stdlib.h>
|
||||
|
||||
#include "libretro.h"
|
||||
#include <libretro.h>
|
||||
#include "blipper.h"
|
||||
#include "gambatte.h"
|
||||
#include "gbcpalettes.h"
|
||||
@ -68,7 +68,8 @@ bool file_present_in_system(std::string fname)
|
||||
fullpath += "/";
|
||||
fullpath += fname;
|
||||
|
||||
RFILE *fp = filestream_open(fullpath.c_str(), RFILE_MODE_READ, 0);
|
||||
RFILE *fp = filestream_open(fullpath.c_str(), RETRO_VFS_FILE_ACCESS_READ,
|
||||
RETRO_VFS_FILE_ACCESS_HINT_NONE);
|
||||
|
||||
if (fp)
|
||||
{
|
||||
@ -111,7 +112,8 @@ bool get_bootloader_from_file(void* userdata, bool isgbc, uint8_t* data, uint32_
|
||||
|
||||
// open file
|
||||
int n = 0;
|
||||
RFILE *fp = filestream_open(path.c_str(), RFILE_MODE_READ, 0);
|
||||
RFILE *fp = filestream_open(path.c_str(), RETRO_VFS_FILE_ACCESS_READ,
|
||||
RETRO_VFS_FILE_ACCESS_HINT_NONE);
|
||||
|
||||
if (fp)
|
||||
{
|
||||
|
@ -3,7 +3,8 @@
|
||||
#include <cstring>
|
||||
#include <fstream>
|
||||
|
||||
#include "../../libretro/libretro.h"
|
||||
#include <libretro.h>
|
||||
|
||||
extern retro_log_printf_t log_cb;
|
||||
|
||||
namespace gambatte
|
||||
|
Loading…
Reference in New Issue
Block a user