mirror of
https://github.com/libretro/gambatte-libretro.git
synced 2024-11-27 01:40:23 +00:00
Replace direct file access with VFS routines + clean-ups
This commit is contained in:
parent
bb13e166bd
commit
422ea3bb84
106
Makefile.common
106
Makefile.common
@ -1,58 +1,70 @@
|
|||||||
LIBRETRO_COMM_DIR := $(CORE_DIR)/../libretro-common
|
LIBRETRO_COMM_DIR := $(CORE_DIR)/../libretro-common
|
||||||
INCFLAGS := -I$(CORE_DIR) -I$(CORE_DIR)/../include -I$(CORE_DIR)/../../common -I$(CORE_DIR)/../../common/resample -I$(CORE_DIR)/../libretro -I$(LIBRETRO_COMM_DIR)/include
|
INCFLAGS := \
|
||||||
|
-I$(CORE_DIR) \
|
||||||
|
-I$(CORE_DIR)/../include \
|
||||||
|
-I$(CORE_DIR)/../../common \
|
||||||
|
-I$(CORE_DIR)/../../common/resample \
|
||||||
|
-I$(CORE_DIR)/../libretro \
|
||||||
|
-I$(LIBRETRO_COMM_DIR)/include
|
||||||
|
|
||||||
ifneq (,$(findstring msvc2003,$(platform)))
|
ifneq (,$(findstring msvc2003,$(platform)))
|
||||||
INCFLAGS += -I$(LIBRETRO_COMM_DIR)/include/compat/msvc
|
INCFLAGS += -I$(LIBRETRO_COMM_DIR)/include/compat/msvc
|
||||||
endif
|
endif
|
||||||
|
|
||||||
SOURCES_C := $(CORE_DIR)/../libretro/blipper.c
|
SOURCES_C := \
|
||||||
SOURCES_CXX := $(CORE_DIR)/bootloader.cpp \
|
$(CORE_DIR)/../libretro/gambatte_log.c \
|
||||||
$(CORE_DIR)/cpu.cpp \
|
$(CORE_DIR)/../libretro/blipper.c
|
||||||
$(CORE_DIR)/gambatte.cpp \
|
|
||||||
$(CORE_DIR)/initstate.cpp \
|
SOURCES_CXX := \
|
||||||
$(CORE_DIR)/interrupter.cpp \
|
$(CORE_DIR)/bootloader.cpp \
|
||||||
$(CORE_DIR)/interruptrequester.cpp \
|
$(CORE_DIR)/cpu.cpp \
|
||||||
$(CORE_DIR)/gambatte-memory.cpp \
|
$(CORE_DIR)/gambatte.cpp \
|
||||||
$(CORE_DIR)/sound.cpp \
|
$(CORE_DIR)/initstate.cpp \
|
||||||
$(CORE_DIR)/statesaver.cpp \
|
$(CORE_DIR)/interrupter.cpp \
|
||||||
$(CORE_DIR)/tima.cpp \
|
$(CORE_DIR)/interruptrequester.cpp \
|
||||||
$(CORE_DIR)/video.cpp \
|
$(CORE_DIR)/gambatte-memory.cpp \
|
||||||
$(CORE_DIR)/video_libretro.cpp \
|
$(CORE_DIR)/sound.cpp \
|
||||||
$(CORE_DIR)/mem/cartridge.cpp \
|
$(CORE_DIR)/statesaver.cpp \
|
||||||
$(CORE_DIR)/mem/cartridge_libretro.cpp \
|
$(CORE_DIR)/tima.cpp \
|
||||||
$(CORE_DIR)/mem/huc3.cpp \
|
$(CORE_DIR)/video.cpp \
|
||||||
$(CORE_DIR)/mem/memptrs.cpp \
|
$(CORE_DIR)/video_libretro.cpp \
|
||||||
$(CORE_DIR)/mem/rtc.cpp \
|
$(CORE_DIR)/mem/cartridge.cpp \
|
||||||
$(CORE_DIR)/sound/channel1.cpp \
|
$(CORE_DIR)/mem/cartridge_libretro.cpp \
|
||||||
$(CORE_DIR)/sound/channel2.cpp \
|
$(CORE_DIR)/mem/huc3.cpp \
|
||||||
$(CORE_DIR)/sound/channel3.cpp \
|
$(CORE_DIR)/mem/memptrs.cpp \
|
||||||
$(CORE_DIR)/sound/channel4.cpp \
|
$(CORE_DIR)/mem/rtc.cpp \
|
||||||
$(CORE_DIR)/sound/duty_unit.cpp \
|
$(CORE_DIR)/sound/channel1.cpp \
|
||||||
$(CORE_DIR)/sound/envelope_unit.cpp \
|
$(CORE_DIR)/sound/channel2.cpp \
|
||||||
$(CORE_DIR)/sound/length_counter.cpp \
|
$(CORE_DIR)/sound/channel3.cpp \
|
||||||
$(CORE_DIR)/video/ly_counter.cpp \
|
$(CORE_DIR)/sound/channel4.cpp \
|
||||||
$(CORE_DIR)/video/lyc_irq.cpp \
|
$(CORE_DIR)/sound/duty_unit.cpp \
|
||||||
$(CORE_DIR)/video/next_m0_time.cpp \
|
$(CORE_DIR)/sound/envelope_unit.cpp \
|
||||||
$(CORE_DIR)/video/ppu.cpp \
|
$(CORE_DIR)/sound/length_counter.cpp \
|
||||||
$(CORE_DIR)/video/sprite_mapper.cpp \
|
$(CORE_DIR)/video/ly_counter.cpp \
|
||||||
$(CORE_DIR)/../libretro/libretro.cpp
|
$(CORE_DIR)/video/lyc_irq.cpp \
|
||||||
|
$(CORE_DIR)/video/next_m0_time.cpp \
|
||||||
|
$(CORE_DIR)/video/ppu.cpp \
|
||||||
|
$(CORE_DIR)/video/sprite_mapper.cpp \
|
||||||
|
$(CORE_DIR)/../libretro/libretro.cpp
|
||||||
|
|
||||||
ifeq ($(HAVE_NETWORK),1)
|
ifeq ($(HAVE_NETWORK),1)
|
||||||
SOURCES_CXX += $(CORE_DIR)/../libretro/net_serial.cpp
|
SOURCES_CXX += \
|
||||||
|
$(CORE_DIR)/../libretro/net_serial.cpp
|
||||||
endif
|
endif
|
||||||
|
|
||||||
ifeq ($(STATIC_LINKING),1)
|
ifneq ($(STATIC_LINKING), 1)
|
||||||
else
|
SOURCES_C += \
|
||||||
SOURCES_C += $(LIBRETRO_COMM_DIR)/streams/file_stream.c \
|
$(LIBRETRO_COMM_DIR)/compat/compat_posix_string.c \
|
||||||
$(LIBRETRO_COMM_DIR)/vfs/vfs_implementation.c \
|
$(LIBRETRO_COMM_DIR)/compat/compat_snprintf.c \
|
||||||
$(LIBRETRO_COMM_DIR)/compat/fopen_utf8.c \
|
$(LIBRETRO_COMM_DIR)/compat/compat_strcasestr.c \
|
||||||
$(LIBRETRO_COMM_DIR)/compat/compat_strl.c \
|
$(LIBRETRO_COMM_DIR)/compat/compat_strl.c \
|
||||||
$(LIBRETRO_COMM_DIR)/compat/compat_snprintf.c \
|
$(LIBRETRO_COMM_DIR)/compat/fopen_utf8.c \
|
||||||
$(LIBRETRO_COMM_DIR)/compat/compat_posix_string.c \
|
$(LIBRETRO_COMM_DIR)/encodings/encoding_utf.c \
|
||||||
$(LIBRETRO_COMM_DIR)/compat/compat_strcasestr.c \
|
$(LIBRETRO_COMM_DIR)/file/file_path.c \
|
||||||
$(LIBRETRO_COMM_DIR)/file/file_path.c \
|
$(LIBRETRO_COMM_DIR)/file/file_path_io.c \
|
||||||
$(LIBRETRO_COMM_DIR)/time/rtime.c \
|
$(LIBRETRO_COMM_DIR)/streams/file_stream.c \
|
||||||
$(LIBRETRO_COMM_DIR)/string/stdstring.c \
|
$(LIBRETRO_COMM_DIR)/streams/file_stream_transforms.c \
|
||||||
$(LIBRETRO_COMM_DIR)/encodings/encoding_utf.c
|
$(LIBRETRO_COMM_DIR)/string/stdstring.c \
|
||||||
|
$(LIBRETRO_COMM_DIR)/time/rtime.c \
|
||||||
|
$(LIBRETRO_COMM_DIR)/vfs/vfs_implementation.c
|
||||||
endif
|
endif
|
||||||
|
|
||||||
|
@ -33,12 +33,12 @@
|
|||||||
#if _MSC_VER < 1300
|
#if _MSC_VER < 1300
|
||||||
#define _vscprintf c89_vscprintf_retro__
|
#define _vscprintf c89_vscprintf_retro__
|
||||||
|
|
||||||
static int c89_vscprintf_retro__(const char *format, va_list pargs)
|
static int c89_vscprintf_retro__(const char *fmt, va_list pargs)
|
||||||
{
|
{
|
||||||
int retval;
|
int retval;
|
||||||
va_list argcopy;
|
va_list argcopy;
|
||||||
va_copy(argcopy, pargs);
|
va_copy(argcopy, pargs);
|
||||||
retval = vsnprintf(NULL, 0, format, argcopy);
|
retval = vsnprintf(NULL, 0, fmt, argcopy);
|
||||||
va_end(argcopy);
|
va_end(argcopy);
|
||||||
return retval;
|
return retval;
|
||||||
}
|
}
|
||||||
@ -46,38 +46,36 @@ static int c89_vscprintf_retro__(const char *format, va_list pargs)
|
|||||||
|
|
||||||
/* http://stackoverflow.com/questions/2915672/snprintf-and-visual-studio-2010 */
|
/* http://stackoverflow.com/questions/2915672/snprintf-and-visual-studio-2010 */
|
||||||
|
|
||||||
int c99_vsnprintf_retro__(char *outBuf, size_t size, const char *format, va_list ap)
|
int c99_vsnprintf_retro__(char *s, size_t len, const char *fmt, va_list ap)
|
||||||
{
|
{
|
||||||
int count = -1;
|
int count = -1;
|
||||||
|
|
||||||
if (size != 0)
|
if (len != 0)
|
||||||
{
|
{
|
||||||
#if (_MSC_VER <= 1310)
|
#if (_MSC_VER <= 1310)
|
||||||
count = _vsnprintf(outBuf, size - 1, format, ap);
|
count = _vsnprintf(s, len - 1, fmt, ap);
|
||||||
#else
|
#else
|
||||||
count = _vsnprintf_s(outBuf, size, size - 1, format, ap);
|
count = _vsnprintf_s(s, len, len - 1, fmt, ap);
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
if (count == -1)
|
if (count == -1)
|
||||||
count = _vscprintf(format, ap);
|
count = _vscprintf(fmt, ap);
|
||||||
|
|
||||||
if (count == size)
|
/* there was no room for a NULL, so truncate the last character */
|
||||||
{
|
if (count == len && len)
|
||||||
/* there was no room for a NULL, so truncate the last character */
|
s[len - 1] = '\0';
|
||||||
outBuf[size - 1] = '\0';
|
|
||||||
}
|
|
||||||
|
|
||||||
return count;
|
return count;
|
||||||
}
|
}
|
||||||
|
|
||||||
int c99_snprintf_retro__(char *outBuf, size_t size, const char *format, ...)
|
int c99_snprintf_retro__(char *s, size_t len, const char *fmt, ...)
|
||||||
{
|
{
|
||||||
int count;
|
int count;
|
||||||
va_list ap;
|
va_list ap;
|
||||||
|
|
||||||
va_start(ap, format);
|
va_start(ap, fmt);
|
||||||
count = c99_vsnprintf_retro__(outBuf, size, format, ap);
|
count = c99_vsnprintf_retro__(s, len, fmt, ap);
|
||||||
va_end(ap);
|
va_end(ap);
|
||||||
|
|
||||||
return count;
|
return count;
|
||||||
|
@ -49,9 +49,14 @@ void *fopen_utf8(const char * filename, const char * mode)
|
|||||||
#else
|
#else
|
||||||
wchar_t * filename_w = utf8_to_utf16_string_alloc(filename);
|
wchar_t * filename_w = utf8_to_utf16_string_alloc(filename);
|
||||||
wchar_t * mode_w = utf8_to_utf16_string_alloc(mode);
|
wchar_t * mode_w = utf8_to_utf16_string_alloc(mode);
|
||||||
FILE* ret = _wfopen(filename_w, mode_w);
|
FILE* ret = NULL;
|
||||||
free(filename_w);
|
|
||||||
free(mode_w);
|
if (filename_w && mode_w)
|
||||||
|
ret = _wfopen(filename_w, mode_w);
|
||||||
|
if (filename_w)
|
||||||
|
free(filename_w);
|
||||||
|
if (mode_w)
|
||||||
|
free(mode_w);
|
||||||
return ret;
|
return ret;
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
@ -284,9 +284,7 @@ bool utf16_to_char_string(const uint16_t *in, char *s, size_t len)
|
|||||||
static char *mb_to_mb_string_alloc(const char *str,
|
static char *mb_to_mb_string_alloc(const char *str,
|
||||||
enum CodePage cp_in, enum CodePage cp_out)
|
enum CodePage cp_in, enum CodePage cp_out)
|
||||||
{
|
{
|
||||||
char *path_buf = NULL;
|
|
||||||
wchar_t *path_buf_wide = NULL;
|
wchar_t *path_buf_wide = NULL;
|
||||||
int path_buf_len = 0;
|
|
||||||
int path_buf_wide_len = MultiByteToWideChar(cp_in, 0, str, -1, NULL, 0);
|
int path_buf_wide_len = MultiByteToWideChar(cp_in, 0, str, -1, NULL, 0);
|
||||||
|
|
||||||
/* Windows 95 will return 0 from these functions with
|
/* Windows 95 will return 0 from these functions with
|
||||||
@ -299,54 +297,51 @@ static char *mb_to_mb_string_alloc(const char *str,
|
|||||||
* MultiByteToWideChar also supports CP_UTF7 and CP_UTF8.
|
* MultiByteToWideChar also supports CP_UTF7 and CP_UTF8.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
if (path_buf_wide_len)
|
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);
|
return strdup(str);
|
||||||
|
|
||||||
|
path_buf_wide = (wchar_t*)
|
||||||
|
calloc(path_buf_wide_len + sizeof(wchar_t), sizeof(wchar_t));
|
||||||
|
|
||||||
if (path_buf_wide)
|
if (path_buf_wide)
|
||||||
|
{
|
||||||
|
MultiByteToWideChar(cp_in, 0,
|
||||||
|
str, -1, path_buf_wide, path_buf_wide_len);
|
||||||
|
|
||||||
|
if (*path_buf_wide)
|
||||||
|
{
|
||||||
|
int path_buf_len = WideCharToMultiByte(cp_out, 0,
|
||||||
|
path_buf_wide, -1, NULL, 0, NULL, NULL);
|
||||||
|
|
||||||
|
if (path_buf_len)
|
||||||
|
{
|
||||||
|
char *path_buf = (char*)
|
||||||
|
calloc(path_buf_len + sizeof(char), sizeof(char));
|
||||||
|
|
||||||
|
if (path_buf)
|
||||||
|
{
|
||||||
|
WideCharToMultiByte(cp_out, 0,
|
||||||
|
path_buf_wide, -1, path_buf,
|
||||||
|
path_buf_len, NULL, NULL);
|
||||||
|
|
||||||
|
free(path_buf_wide);
|
||||||
|
|
||||||
|
if (*path_buf)
|
||||||
|
return path_buf;
|
||||||
|
|
||||||
|
free(path_buf);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
free(path_buf_wide);
|
||||||
|
return strdup(str);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
free(path_buf_wide);
|
free(path_buf_wide);
|
||||||
|
}
|
||||||
|
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
@ -48,43 +48,9 @@
|
|||||||
#include <retro_miscellaneous.h>
|
#include <retro_miscellaneous.h>
|
||||||
#include <encodings/utf.h>
|
#include <encodings/utf.h>
|
||||||
|
|
||||||
#if defined(_WIN32)
|
#ifdef _WIN32
|
||||||
#ifdef _MSC_VER
|
|
||||||
#define setmode _setmode
|
|
||||||
#endif
|
|
||||||
#include <sys/stat.h>
|
|
||||||
#ifdef _XBOX
|
|
||||||
#include <xtl.h>
|
|
||||||
#define INVALID_FILE_ATTRIBUTES -1
|
|
||||||
#else
|
|
||||||
#include <io.h>
|
|
||||||
#include <fcntl.h>
|
|
||||||
#include <direct.h>
|
#include <direct.h>
|
||||||
#include <windows.h>
|
|
||||||
#if defined(_MSC_VER) && _MSC_VER <= 1200
|
|
||||||
#define INVALID_FILE_ATTRIBUTES ((DWORD)-1)
|
|
||||||
#endif
|
|
||||||
#endif
|
|
||||||
#elif defined(VITA)
|
|
||||||
#define SCE_ERROR_ERRNO_EEXIST 0x80010011
|
|
||||||
#include <psp2/io/fcntl.h>
|
|
||||||
#include <psp2/io/dirent.h>
|
|
||||||
#include <psp2/io/stat.h>
|
|
||||||
#else
|
#else
|
||||||
#include <sys/types.h>
|
|
||||||
#include <sys/stat.h>
|
|
||||||
#include <unistd.h>
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#if defined(PSP)
|
|
||||||
#include <pspkernel.h>
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#if defined(VITA)
|
|
||||||
#define FIO_S_ISDIR SCE_S_ISDIR
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#if defined(__QNX__) || defined(PSP)
|
|
||||||
#include <unistd.h> /* stat() is defined here */
|
#include <unistd.h> /* stat() is defined here */
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
@ -121,41 +87,53 @@ const char *path_get_archive_delim(const char *path)
|
|||||||
|
|
||||||
buf[0] = '\0';
|
buf[0] = '\0';
|
||||||
|
|
||||||
|
/* We search for delimiters after the last slash
|
||||||
|
* in the file path to avoid capturing delimiter
|
||||||
|
* characters in any parent directory names.
|
||||||
|
* If there are no slashes in the file name, then
|
||||||
|
* the path is just the file basename - in this
|
||||||
|
* case we search the path in its entirety */
|
||||||
if (!last_slash)
|
if (!last_slash)
|
||||||
return NULL;
|
last_slash = path;
|
||||||
|
|
||||||
/* Find delimiter position */
|
/* Find delimiter position
|
||||||
delim = strrchr(last_slash, '#');
|
* > Since filenames may contain '#' characters,
|
||||||
|
* must loop until we find the first '#' that
|
||||||
|
* is directly *after* a compression extension */
|
||||||
|
delim = strchr(last_slash, '#');
|
||||||
|
|
||||||
if (!delim)
|
while (delim)
|
||||||
return NULL;
|
|
||||||
|
|
||||||
/* Check whether this is a known archive type
|
|
||||||
* > Note: The code duplication here is
|
|
||||||
* deliberate, to maximise performance */
|
|
||||||
if (delim - last_slash > 4)
|
|
||||||
{
|
{
|
||||||
strlcpy(buf, delim - 4, sizeof(buf));
|
/* Check whether this is a known archive type
|
||||||
buf[4] = '\0';
|
* > Note: The code duplication here is
|
||||||
|
* deliberate, to maximise performance */
|
||||||
|
if (delim - last_slash > 4)
|
||||||
|
{
|
||||||
|
strlcpy(buf, delim - 4, sizeof(buf));
|
||||||
|
buf[4] = '\0';
|
||||||
|
|
||||||
string_to_lower(buf);
|
string_to_lower(buf);
|
||||||
|
|
||||||
/* Check if this is a '.zip', '.apk' or '.7z' file */
|
/* Check if this is a '.zip', '.apk' or '.7z' file */
|
||||||
if (string_is_equal(buf, ".zip") ||
|
if (string_is_equal(buf, ".zip") ||
|
||||||
string_is_equal(buf, ".apk") ||
|
string_is_equal(buf, ".apk") ||
|
||||||
string_is_equal(buf + 1, ".7z"))
|
string_is_equal(buf + 1, ".7z"))
|
||||||
return delim;
|
return delim;
|
||||||
}
|
}
|
||||||
else if (delim - last_slash > 3)
|
else if (delim - last_slash > 3)
|
||||||
{
|
{
|
||||||
strlcpy(buf, delim - 3, sizeof(buf));
|
strlcpy(buf, delim - 3, sizeof(buf));
|
||||||
buf[3] = '\0';
|
buf[3] = '\0';
|
||||||
|
|
||||||
string_to_lower(buf);
|
string_to_lower(buf);
|
||||||
|
|
||||||
/* Check if this is a '.7z' file */
|
/* Check if this is a '.7z' file */
|
||||||
if (string_is_equal(buf, ".7z"))
|
if (string_is_equal(buf, ".7z"))
|
||||||
return delim;
|
return delim;
|
||||||
|
}
|
||||||
|
|
||||||
|
delim++;
|
||||||
|
delim = strchr(delim, '#');
|
||||||
}
|
}
|
||||||
|
|
||||||
return NULL;
|
return NULL;
|
||||||
@ -214,15 +192,11 @@ char *path_remove_extension(char *path)
|
|||||||
bool path_is_compressed_file(const char* path)
|
bool path_is_compressed_file(const char* path)
|
||||||
{
|
{
|
||||||
const char *ext = path_get_extension(path);
|
const char *ext = path_get_extension(path);
|
||||||
|
if (!string_is_empty(ext))
|
||||||
if (string_is_empty(ext))
|
if ( string_is_equal_noncase(ext, "zip") ||
|
||||||
return false;
|
string_is_equal_noncase(ext, "apk") ||
|
||||||
|
string_is_equal_noncase(ext, "7z"))
|
||||||
if (string_is_equal_noncase(ext, "zip") ||
|
return true;
|
||||||
string_is_equal_noncase(ext, "apk") ||
|
|
||||||
string_is_equal_noncase(ext, "7z"))
|
|
||||||
return true;
|
|
||||||
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -547,7 +521,7 @@ void path_basedir(char *path)
|
|||||||
if (last)
|
if (last)
|
||||||
last[1] = '\0';
|
last[1] = '\0';
|
||||||
else
|
else
|
||||||
snprintf(path, 3, "." PATH_DEFAULT_SLASH());
|
strlcpy(path, "." PATH_DEFAULT_SLASH(), 3);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -612,6 +586,16 @@ const char *path_basename(const char *path)
|
|||||||
return path;
|
return path;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Specialized version */
|
||||||
|
const char *path_basename_nocompression(const char *path)
|
||||||
|
{
|
||||||
|
/* We cut at the last slash */
|
||||||
|
const char *last = find_last_slash(path);
|
||||||
|
if (last)
|
||||||
|
return last + 1;
|
||||||
|
return path;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* path_is_absolute:
|
* path_is_absolute:
|
||||||
* @path : path
|
* @path : path
|
||||||
@ -666,16 +650,31 @@ bool path_is_absolute(const char *path)
|
|||||||
char *path_resolve_realpath(char *buf, size_t size, bool resolve_symlinks)
|
char *path_resolve_realpath(char *buf, size_t size, bool resolve_symlinks)
|
||||||
{
|
{
|
||||||
#if !defined(RARCH_CONSOLE) && defined(RARCH_INTERNAL)
|
#if !defined(RARCH_CONSOLE) && defined(RARCH_INTERNAL)
|
||||||
char tmp[PATH_MAX_LENGTH];
|
|
||||||
#ifdef _WIN32
|
#ifdef _WIN32
|
||||||
strlcpy(tmp, buf, sizeof(tmp));
|
char *ret = NULL;
|
||||||
if (!_fullpath(buf, tmp, size))
|
wchar_t abs_path[PATH_MAX_LENGTH];
|
||||||
|
wchar_t *rel_path = utf8_to_utf16_string_alloc(buf);
|
||||||
|
|
||||||
|
if (rel_path)
|
||||||
{
|
{
|
||||||
strlcpy(buf, tmp, size);
|
if (_wfullpath(abs_path, rel_path, PATH_MAX_LENGTH))
|
||||||
return NULL;
|
{
|
||||||
|
char *tmp = utf16_to_utf8_string_alloc(abs_path);
|
||||||
|
|
||||||
|
if (tmp)
|
||||||
|
{
|
||||||
|
strlcpy(buf, tmp, size);
|
||||||
|
free(tmp);
|
||||||
|
ret = buf;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
free(rel_path);
|
||||||
}
|
}
|
||||||
return buf;
|
|
||||||
|
return ret;
|
||||||
#else
|
#else
|
||||||
|
char tmp[PATH_MAX_LENGTH];
|
||||||
size_t t;
|
size_t t;
|
||||||
char *p;
|
char *p;
|
||||||
const char *next;
|
const char *next;
|
||||||
@ -1006,7 +1005,7 @@ void fill_pathname_expand_special(char *out_path,
|
|||||||
retro_assert(src_size < size);
|
retro_assert(src_size < size);
|
||||||
|
|
||||||
out_path += src_size;
|
out_path += src_size;
|
||||||
size -= src_size;
|
size -= src_size;
|
||||||
}
|
}
|
||||||
|
|
||||||
in_path += 2;
|
in_path += 2;
|
||||||
@ -1096,8 +1095,7 @@ void fill_pathname_abbreviate_special(char *out_path,
|
|||||||
|
|
||||||
if (!PATH_CHAR_IS_SLASH(*in_path))
|
if (!PATH_CHAR_IS_SLASH(*in_path))
|
||||||
{
|
{
|
||||||
retro_assert(strlcpy(out_path,
|
strcpy_literal(out_path, PATH_DEFAULT_SLASH());
|
||||||
PATH_DEFAULT_SLASH(), size) < size);
|
|
||||||
out_path++;
|
out_path++;
|
||||||
size--;
|
size--;
|
||||||
}
|
}
|
||||||
@ -1111,6 +1109,99 @@ void fill_pathname_abbreviate_special(char *out_path,
|
|||||||
retro_assert(strlcpy(out_path, in_path, size) < size);
|
retro_assert(strlcpy(out_path, in_path, size) < size);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Changes the slashes to the correct kind for the os
|
||||||
|
* So forward slash on linux and backslash on Windows */
|
||||||
|
void pathname_conform_slashes_to_os(char *path)
|
||||||
|
{
|
||||||
|
/* Conform slashes to os standard so we get proper matching */
|
||||||
|
char* p;
|
||||||
|
for (p = path; *p; p++)
|
||||||
|
if (*p == '/' || *p == '\\')
|
||||||
|
*p = PATH_DEFAULT_SLASH_C();
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Change all shashes to forward so they are more portable between windows and linux */
|
||||||
|
void pathname_make_slashes_portable(char *path)
|
||||||
|
{
|
||||||
|
/* Conform slashes to os standard so we get proper matching */
|
||||||
|
char* p;
|
||||||
|
for (p = path; *p; p++)
|
||||||
|
if (*p == '/' || *p == '\\')
|
||||||
|
*p = '/';
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Get the number of slashes in a path, returns an integer */
|
||||||
|
int get_pathname_num_slashes(const char *in_path)
|
||||||
|
{
|
||||||
|
int num_slashes = 0;
|
||||||
|
int i = 0;
|
||||||
|
|
||||||
|
for (i = 0; i < PATH_MAX_LENGTH; i++)
|
||||||
|
{
|
||||||
|
if (PATH_CHAR_IS_SLASH(in_path[i]))
|
||||||
|
num_slashes++;
|
||||||
|
if (in_path[i] == '\0')
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
return num_slashes;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Fills the supplied path with either the abbreviated path or the relative path, which ever
|
||||||
|
* one is has less depth / number of slashes
|
||||||
|
* If lengths of abbreviated and relative paths are the same the relative path will be used
|
||||||
|
* in_path can be an absolute, relative or abbreviated path */
|
||||||
|
void fill_pathname_abbreviated_or_relative(char *out_path, const char *in_refpath, const char *in_path, size_t size)
|
||||||
|
{
|
||||||
|
char in_path_conformed[PATH_MAX_LENGTH];
|
||||||
|
char in_refpath_conformed[PATH_MAX_LENGTH];
|
||||||
|
char expanded_path[PATH_MAX_LENGTH];
|
||||||
|
char absolute_path[PATH_MAX_LENGTH];
|
||||||
|
char relative_path[PATH_MAX_LENGTH];
|
||||||
|
char abbreviated_path[PATH_MAX_LENGTH];
|
||||||
|
|
||||||
|
in_path_conformed[0] = '\0';
|
||||||
|
in_refpath_conformed[0] = '\0';
|
||||||
|
expanded_path[0] = '\0';
|
||||||
|
absolute_path[0] = '\0';
|
||||||
|
relative_path[0] = '\0';
|
||||||
|
abbreviated_path[0] = '\0';
|
||||||
|
|
||||||
|
strcpy_literal(in_path_conformed, in_path);
|
||||||
|
strcpy_literal(in_refpath_conformed, in_refpath);
|
||||||
|
|
||||||
|
pathname_conform_slashes_to_os(in_path_conformed);
|
||||||
|
pathname_conform_slashes_to_os(in_refpath_conformed);
|
||||||
|
|
||||||
|
/* Expand paths which start with :\ to an absolute path */
|
||||||
|
fill_pathname_expand_special(expanded_path,
|
||||||
|
in_path_conformed, sizeof(expanded_path));
|
||||||
|
|
||||||
|
/* Get the absolute path if it is not already */
|
||||||
|
if (path_is_absolute(expanded_path))
|
||||||
|
strlcpy(absolute_path, expanded_path, PATH_MAX_LENGTH);
|
||||||
|
else
|
||||||
|
fill_pathname_resolve_relative(absolute_path,
|
||||||
|
in_refpath_conformed, in_path_conformed, PATH_MAX_LENGTH);
|
||||||
|
|
||||||
|
pathname_conform_slashes_to_os(absolute_path);
|
||||||
|
|
||||||
|
/* Get the relative path and see how many directories long it is */
|
||||||
|
path_relative_to(relative_path, absolute_path,
|
||||||
|
in_refpath_conformed, sizeof(relative_path));
|
||||||
|
|
||||||
|
/* Get the abbreviated path and see how many directories long it is */
|
||||||
|
fill_pathname_abbreviate_special(abbreviated_path,
|
||||||
|
absolute_path, sizeof(abbreviated_path));
|
||||||
|
|
||||||
|
/* Use the shortest path, preferring the relative path*/
|
||||||
|
if ( get_pathname_num_slashes(relative_path) <=
|
||||||
|
get_pathname_num_slashes(abbreviated_path))
|
||||||
|
retro_assert(strlcpy(out_path, relative_path, size) < size);
|
||||||
|
else
|
||||||
|
retro_assert(strlcpy(out_path, abbreviated_path, size) < size);
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* path_basedir:
|
* path_basedir:
|
||||||
* @path : path
|
* @path : path
|
||||||
@ -1136,7 +1227,7 @@ void path_basedir_wrapper(char *path)
|
|||||||
if (last)
|
if (last)
|
||||||
last[1] = '\0';
|
last[1] = '\0';
|
||||||
else
|
else
|
||||||
snprintf(path, 3, "." PATH_DEFAULT_SLASH());
|
strlcpy(path, "." PATH_DEFAULT_SLASH(), 3);
|
||||||
}
|
}
|
||||||
|
|
||||||
#if !defined(RARCH_CONSOLE) && defined(RARCH_INTERNAL)
|
#if !defined(RARCH_CONSOLE) && defined(RARCH_INTERNAL)
|
||||||
@ -1263,30 +1354,28 @@ void fill_pathname_application_dir(char *s, size_t len)
|
|||||||
void fill_pathname_home_dir(char *s, size_t len)
|
void fill_pathname_home_dir(char *s, size_t len)
|
||||||
{
|
{
|
||||||
#ifdef __WINRT__
|
#ifdef __WINRT__
|
||||||
strlcpy(s, uwp_dir_data, len);
|
const char *home = uwp_dir_data;
|
||||||
#else
|
#else
|
||||||
const char *home = getenv("HOME");
|
const char *home = getenv("HOME");
|
||||||
|
#endif
|
||||||
if (home)
|
if (home)
|
||||||
strlcpy(s, home, len);
|
strlcpy(s, home, len);
|
||||||
else
|
else
|
||||||
*s = 0;
|
*s = 0;
|
||||||
#endif
|
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
bool is_path_accessible_using_standard_io(const char *path)
|
bool is_path_accessible_using_standard_io(const char *path)
|
||||||
{
|
{
|
||||||
bool result = true;
|
|
||||||
#ifdef __WINRT__
|
#ifdef __WINRT__
|
||||||
size_t path_sizeof = PATH_MAX_LENGTH * sizeof(char);
|
char relative_path_abbrev[PATH_MAX_LENGTH];
|
||||||
char *relative_path_abbrev = (char*)malloc(path_sizeof);
|
fill_pathname_abbreviate_special(relative_path_abbrev,
|
||||||
fill_pathname_abbreviate_special(relative_path_abbrev, path, path_sizeof);
|
path, sizeof(relative_path_abbrev));
|
||||||
|
return (strlen(relative_path_abbrev) >= 2 )
|
||||||
result = (strlen(relative_path_abbrev) >= 2 )
|
&& ( relative_path_abbrev[0] == ':'
|
||||||
&& (relative_path_abbrev[0] == ':' || relative_path_abbrev[0] == '~')
|
|| relative_path_abbrev[0] == '~')
|
||||||
&& PATH_CHAR_IS_SLASH(relative_path_abbrev[1]);
|
&& PATH_CHAR_IS_SLASH(relative_path_abbrev[1]);
|
||||||
|
#else
|
||||||
free(relative_path_abbrev);
|
return true;
|
||||||
#endif
|
#endif
|
||||||
return result;
|
|
||||||
}
|
}
|
||||||
|
151
libgambatte/libretro-common/file/file_path_io.c
Normal file
151
libgambatte/libretro-common/file/file_path_io.c
Normal file
@ -0,0 +1,151 @@
|
|||||||
|
/* Copyright (C) 2010-2020 The RetroArch team
|
||||||
|
*
|
||||||
|
* ---------------------------------------------------------------------------------------
|
||||||
|
* The following license statement only applies to this file (file_path_io.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 <time.h>
|
||||||
|
#include <errno.h>
|
||||||
|
|
||||||
|
#include <sys/stat.h>
|
||||||
|
|
||||||
|
#include <boolean.h>
|
||||||
|
#include <file/file_path.h>
|
||||||
|
#include <retro_assert.h>
|
||||||
|
#include <compat/strl.h>
|
||||||
|
#include <compat/posix_string.h>
|
||||||
|
#include <retro_miscellaneous.h>
|
||||||
|
#include <string/stdstring.h>
|
||||||
|
#define VFS_FRONTEND
|
||||||
|
#include <vfs/vfs_implementation.h>
|
||||||
|
|
||||||
|
#ifdef _WIN32
|
||||||
|
#include <direct.h>
|
||||||
|
#else
|
||||||
|
#include <unistd.h> /* stat() is defined here */
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/* TODO/FIXME - globals */
|
||||||
|
static retro_vfs_stat_t path_stat_cb = retro_vfs_stat_impl;
|
||||||
|
static retro_vfs_mkdir_t path_mkdir_cb = retro_vfs_mkdir_impl;
|
||||||
|
|
||||||
|
void path_vfs_init(const struct retro_vfs_interface_info* vfs_info)
|
||||||
|
{
|
||||||
|
const struct retro_vfs_interface*
|
||||||
|
vfs_iface = vfs_info->iface;
|
||||||
|
|
||||||
|
path_stat_cb = retro_vfs_stat_impl;
|
||||||
|
path_mkdir_cb = retro_vfs_mkdir_impl;
|
||||||
|
|
||||||
|
if (vfs_info->required_interface_version < PATH_REQUIRED_VFS_VERSION || !vfs_iface)
|
||||||
|
return;
|
||||||
|
|
||||||
|
path_stat_cb = vfs_iface->stat;
|
||||||
|
path_mkdir_cb = vfs_iface->mkdir;
|
||||||
|
}
|
||||||
|
|
||||||
|
int path_stat(const char *path)
|
||||||
|
{
|
||||||
|
return path_stat_cb(path, NULL);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* path_is_directory:
|
||||||
|
* @path : path
|
||||||
|
*
|
||||||
|
* Checks if path is a directory.
|
||||||
|
*
|
||||||
|
* Returns: true (1) if path is a directory, otherwise false (0).
|
||||||
|
*/
|
||||||
|
bool path_is_directory(const char *path)
|
||||||
|
{
|
||||||
|
return (path_stat_cb(path, NULL) & RETRO_VFS_STAT_IS_DIRECTORY) != 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool path_is_character_special(const char *path)
|
||||||
|
{
|
||||||
|
return (path_stat_cb(path, NULL) & RETRO_VFS_STAT_IS_CHARACTER_SPECIAL) != 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool path_is_valid(const char *path)
|
||||||
|
{
|
||||||
|
return (path_stat_cb(path, NULL) & RETRO_VFS_STAT_IS_VALID) != 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
int32_t path_get_size(const char *path)
|
||||||
|
{
|
||||||
|
int32_t filesize = 0;
|
||||||
|
if (path_stat_cb(path, &filesize) != 0)
|
||||||
|
return filesize;
|
||||||
|
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* path_mkdir:
|
||||||
|
* @dir : directory
|
||||||
|
*
|
||||||
|
* Create directory on filesystem.
|
||||||
|
*
|
||||||
|
* Returns: true (1) if directory could be created, otherwise false (0).
|
||||||
|
**/
|
||||||
|
bool path_mkdir(const char *dir)
|
||||||
|
{
|
||||||
|
bool norecurse = false;
|
||||||
|
char *basedir = NULL;
|
||||||
|
|
||||||
|
if (!(dir && *dir))
|
||||||
|
return false;
|
||||||
|
|
||||||
|
/* Use heap. Real chance of stack
|
||||||
|
* overflow if we recurse too hard. */
|
||||||
|
basedir = strdup(dir);
|
||||||
|
|
||||||
|
if (!basedir)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
path_parent_dir(basedir);
|
||||||
|
|
||||||
|
if (!*basedir || !strcmp(basedir, dir))
|
||||||
|
{
|
||||||
|
free(basedir);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if ( path_is_directory(basedir)
|
||||||
|
|| path_mkdir(basedir))
|
||||||
|
norecurse = true;
|
||||||
|
|
||||||
|
free(basedir);
|
||||||
|
|
||||||
|
if (norecurse)
|
||||||
|
{
|
||||||
|
int ret = path_mkdir_cb(dir);
|
||||||
|
|
||||||
|
/* Don't treat this as an error. */
|
||||||
|
if (ret == -2 && path_is_directory(dir))
|
||||||
|
return true;
|
||||||
|
else if (ret == 0)
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
@ -29,22 +29,17 @@
|
|||||||
extern "C" {
|
extern "C" {
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
/* Pre-MSVC 2015 compilers don't implement snprintf in a cross-platform manner. */
|
/* Pre-MSVC 2015 compilers don't implement snprintf, vsnprintf in a cross-platform manner. */
|
||||||
#if _MSC_VER < 1900
|
#if _MSC_VER < 1900
|
||||||
#include <stdio.h>
|
|
||||||
#include <stdlib.h>
|
|
||||||
#ifndef snprintf
|
|
||||||
#define snprintf c99_snprintf_retro__
|
|
||||||
#endif
|
|
||||||
|
|
||||||
int c99_snprintf_retro__(char *outBuf, size_t size, const char *format, ...);
|
|
||||||
#endif
|
|
||||||
|
|
||||||
/* Pre-MSVC 2008 compilers don't implement vsnprintf in a cross-platform manner? Not sure about this one. */
|
|
||||||
#if _MSC_VER < 1500
|
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
#include <stdarg.h>
|
#include <stdarg.h>
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
|
|
||||||
|
#ifndef snprintf
|
||||||
|
#define snprintf c99_snprintf_retro__
|
||||||
|
#endif
|
||||||
|
int c99_snprintf_retro__(char *outBuf, size_t size, const char *format, ...);
|
||||||
|
|
||||||
#ifndef vsnprintf
|
#ifndef vsnprintf
|
||||||
#define vsnprintf c99_vsnprintf_retro__
|
#define vsnprintf c99_vsnprintf_retro__
|
||||||
#endif
|
#endif
|
||||||
|
@ -35,7 +35,7 @@ RETRO_BEGIN_DECLS
|
|||||||
enum CodePage
|
enum CodePage
|
||||||
{
|
{
|
||||||
CODEPAGE_LOCAL = 0, /* CP_ACP */
|
CODEPAGE_LOCAL = 0, /* CP_ACP */
|
||||||
CODEPAGE_UTF8 = 65001 /* CP_UTF8 */
|
CODEPAGE_UTF8 = 65001 /* CP_UTF8 */
|
||||||
};
|
};
|
||||||
|
|
||||||
size_t utf8_conv_utf32(uint32_t *out, size_t out_chars,
|
size_t utf8_conv_utf32(uint32_t *out, size_t out_chars,
|
||||||
|
@ -125,6 +125,7 @@ char *path_remove_extension(char *path);
|
|||||||
* Returns: basename from path.
|
* Returns: basename from path.
|
||||||
**/
|
**/
|
||||||
const char *path_basename(const char *path);
|
const char *path_basename(const char *path);
|
||||||
|
const char *path_basename_nocompression(const char *path);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* path_basedir:
|
* path_basedir:
|
||||||
@ -442,6 +443,12 @@ void fill_pathname_expand_special(char *out_path,
|
|||||||
void fill_pathname_abbreviate_special(char *out_path,
|
void fill_pathname_abbreviate_special(char *out_path,
|
||||||
const char *in_path, size_t size);
|
const char *in_path, size_t size);
|
||||||
|
|
||||||
|
void fill_pathname_abbreviated_or_relative(char *out_path, const char *in_refpath, const char *in_path, size_t size);
|
||||||
|
|
||||||
|
void pathname_conform_slashes_to_os(char *path);
|
||||||
|
|
||||||
|
void pathname_make_slashes_portable(char *path);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* path_basedir:
|
* path_basedir:
|
||||||
* @path : path
|
* @path : path
|
||||||
|
@ -1,52 +0,0 @@
|
|||||||
/* Copyright (C) 2010-2020 The RetroArch team
|
|
||||||
*
|
|
||||||
* ---------------------------------------------------------------------------------------
|
|
||||||
* The following license statement only applies to this file (memmap.h).
|
|
||||||
* ---------------------------------------------------------------------------------------
|
|
||||||
*
|
|
||||||
* Permission is hereby granted, free of charge,
|
|
||||||
* to any person obtaining a copy of this software and associated documentation files (the "Software"),
|
|
||||||
* to deal in the Software without restriction, including without limitation the rights to
|
|
||||||
* use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software,
|
|
||||||
* and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
|
|
||||||
*
|
|
||||||
* The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
|
|
||||||
*
|
|
||||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
|
|
||||||
* INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
||||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
|
|
||||||
* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
|
|
||||||
* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
||||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
|
||||||
*/
|
|
||||||
|
|
||||||
#ifndef _LIBRETRO_MEMMAP_H
|
|
||||||
#define _LIBRETRO_MEMMAP_H
|
|
||||||
|
|
||||||
#include <stdio.h>
|
|
||||||
#include <stdint.h>
|
|
||||||
|
|
||||||
#if defined(PSP) || defined(PS2) || defined(GEKKO) || defined(VITA) || defined(_XBOX) || defined(_3DS) || defined(WIIU) || defined(SWITCH) || defined(HAVE_LIBNX)
|
|
||||||
/* No mman available */
|
|
||||||
#elif defined(_WIN32) && !defined(_XBOX)
|
|
||||||
#include <windows.h>
|
|
||||||
#include <errno.h>
|
|
||||||
#include <io.h>
|
|
||||||
#else
|
|
||||||
#define HAVE_MMAN
|
|
||||||
#include <sys/mman.h>
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#if !defined(HAVE_MMAN) || defined(_WIN32)
|
|
||||||
void* mmap(void *addr, size_t len, int mmap_prot, int mmap_flags, int fildes, size_t off);
|
|
||||||
|
|
||||||
int munmap(void *addr, size_t len);
|
|
||||||
|
|
||||||
int mprotect(void *addr, size_t len, int prot);
|
|
||||||
#endif
|
|
||||||
|
|
||||||
int memsync(void *start, void *end);
|
|
||||||
|
|
||||||
int memprotect(void *addr, size_t len);
|
|
||||||
|
|
||||||
#endif
|
|
@ -27,9 +27,7 @@
|
|||||||
|
|
||||||
#ifdef RARCH_INTERNAL
|
#ifdef RARCH_INTERNAL
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
#define retro_assert(cond) do { \
|
#define retro_assert(cond) ((void)( (cond) || (printf("Assertion failed at %s:%d.\n", __FILE__, __LINE__), abort(), 0) ))
|
||||||
if (!(cond)) { printf("Assertion failed at %s:%d.\n", __FILE__, __LINE__); abort(); } \
|
|
||||||
} while(0)
|
|
||||||
#else
|
#else
|
||||||
#define retro_assert(cond) assert(cond)
|
#define retro_assert(cond) assert(cond)
|
||||||
#endif
|
#endif
|
||||||
|
@ -30,13 +30,17 @@
|
|||||||
#include <boolean.h>
|
#include <boolean.h>
|
||||||
#include <retro_inline.h>
|
#include <retro_inline.h>
|
||||||
|
|
||||||
#if defined(_WIN32) && !defined(_XBOX)
|
#if defined(_WIN32)
|
||||||
|
|
||||||
|
#if defined(_XBOX)
|
||||||
|
#include <Xtl.h>
|
||||||
|
#else
|
||||||
#ifndef WIN32_LEAN_AND_MEAN
|
#ifndef WIN32_LEAN_AND_MEAN
|
||||||
#define WIN32_LEAN_AND_MEAN
|
#define WIN32_LEAN_AND_MEAN
|
||||||
#endif
|
#endif
|
||||||
#include <windows.h>
|
#include <windows.h>
|
||||||
#elif defined(_WIN32) && defined(_XBOX)
|
#endif
|
||||||
#include <Xtl.h>
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#include <limits.h>
|
#include <limits.h>
|
||||||
@ -71,7 +75,7 @@ static INLINE bool bits_any_set(uint32_t* ptr, uint32_t count)
|
|||||||
}
|
}
|
||||||
|
|
||||||
#ifndef PATH_MAX_LENGTH
|
#ifndef PATH_MAX_LENGTH
|
||||||
#if defined(_XBOX1) || defined(_3DS) || defined(PSP) || defined(PS2) || defined(GEKKO)|| defined(WIIU) || defined(ORBIS)
|
#if defined(_XBOX1) || defined(_3DS) || defined(PSP) || defined(PS2) || defined(GEKKO)|| defined(WIIU) || defined(ORBIS) || defined(__PSL1GHT__) || defined(__PS3__)
|
||||||
#define PATH_MAX_LENGTH 512
|
#define PATH_MAX_LENGTH 512
|
||||||
#else
|
#else
|
||||||
#define PATH_MAX_LENGTH 4096
|
#define PATH_MAX_LENGTH 4096
|
||||||
@ -130,6 +134,16 @@ static INLINE bool bits_any_set(uint32_t* ptr, uint32_t count)
|
|||||||
#define BIT256_GET_PTR(a, bit) BIT256_GET(*a, bit)
|
#define BIT256_GET_PTR(a, bit) BIT256_GET(*a, bit)
|
||||||
#define BIT256_CLEAR_ALL_PTR(a) BIT256_CLEAR_ALL(*a)
|
#define BIT256_CLEAR_ALL_PTR(a) BIT256_CLEAR_ALL(*a)
|
||||||
|
|
||||||
|
#define BIT512_SET(a, bit) BIT256_SET(a, bit)
|
||||||
|
#define BIT512_CLEAR(a, bit) BIT256_CLEAR(a, bit)
|
||||||
|
#define BIT512_GET(a, bit) BIT256_GET(a, bit)
|
||||||
|
#define BIT512_CLEAR_ALL(a) BIT256_CLEAR_ALL(a)
|
||||||
|
|
||||||
|
#define BIT512_SET_PTR(a, bit) BIT512_SET(*a, bit)
|
||||||
|
#define BIT512_CLEAR_PTR(a, bit) BIT512_CLEAR(*a, bit)
|
||||||
|
#define BIT512_GET_PTR(a, bit) BIT512_GET(*a, bit)
|
||||||
|
#define BIT512_CLEAR_ALL_PTR(a) BIT512_CLEAR_ALL(*a)
|
||||||
|
|
||||||
#define BITS_COPY16_PTR(a,bits) \
|
#define BITS_COPY16_PTR(a,bits) \
|
||||||
{ \
|
{ \
|
||||||
BIT128_CLEAR_ALL_PTR(a); \
|
BIT128_CLEAR_ALL_PTR(a); \
|
||||||
@ -142,6 +156,13 @@ static INLINE bool bits_any_set(uint32_t* ptr, uint32_t count)
|
|||||||
BITS_GET_ELEM_PTR(a, 0) = (bits); \
|
BITS_GET_ELEM_PTR(a, 0) = (bits); \
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#define BITS_COPY64_PTR(a,bits) \
|
||||||
|
{ \
|
||||||
|
BIT128_CLEAR_ALL_PTR(a); \
|
||||||
|
BITS_GET_ELEM_PTR(a, 0) = (bits); \
|
||||||
|
BITS_GET_ELEM_PTR(a, 1) = (bits >> 32); \
|
||||||
|
}
|
||||||
|
|
||||||
/* Helper macros and struct to keep track of many booleans. */
|
/* Helper macros and struct to keep track of many booleans. */
|
||||||
/* This struct has 256 bits. */
|
/* This struct has 256 bits. */
|
||||||
typedef struct
|
typedef struct
|
||||||
@ -149,6 +170,12 @@ typedef struct
|
|||||||
uint32_t data[8];
|
uint32_t data[8];
|
||||||
} retro_bits_t;
|
} retro_bits_t;
|
||||||
|
|
||||||
|
/* This struct has 512 bits. */
|
||||||
|
typedef struct
|
||||||
|
{
|
||||||
|
uint32_t data[16];
|
||||||
|
} retro_bits_512_t;
|
||||||
|
|
||||||
#ifdef _WIN32
|
#ifdef _WIN32
|
||||||
# ifdef _WIN64
|
# ifdef _WIN64
|
||||||
# define PRI_SIZET PRIu64
|
# define PRI_SIZET PRIu64
|
||||||
@ -159,7 +186,7 @@ typedef struct
|
|||||||
# define PRI_SIZET "u"
|
# define PRI_SIZET "u"
|
||||||
# endif
|
# endif
|
||||||
# endif
|
# endif
|
||||||
#elif PS2
|
#elif defined(PS2)
|
||||||
# define PRI_SIZET "u"
|
# define PRI_SIZET "u"
|
||||||
#else
|
#else
|
||||||
# if (SIZE_MAX == 0xFFFF)
|
# if (SIZE_MAX == 0xFFFF)
|
||||||
|
@ -81,6 +81,8 @@ char* filestream_gets(RFILE *stream, char *s, size_t len);
|
|||||||
|
|
||||||
int filestream_getc(RFILE *stream);
|
int filestream_getc(RFILE *stream);
|
||||||
|
|
||||||
|
int filestream_vscanf(RFILE *stream, const char* format, va_list *args);
|
||||||
|
|
||||||
int filestream_scanf(RFILE *stream, const char* format, ...);
|
int filestream_scanf(RFILE *stream, const char* format, ...);
|
||||||
|
|
||||||
int filestream_eof(RFILE *stream);
|
int filestream_eof(RFILE *stream);
|
||||||
|
@ -0,0 +1,101 @@
|
|||||||
|
/* Copyright (C) 2010-2020 The RetroArch team
|
||||||
|
*
|
||||||
|
* ---------------------------------------------------------------------------------------
|
||||||
|
* The following license statement only applies to this file (file_stream_transforms.h).
|
||||||
|
* ---------------------------------------------------------------------------------------
|
||||||
|
*
|
||||||
|
* Permission is hereby granted, free of charge,
|
||||||
|
* to any person obtaining a copy of this software and associated documentation files (the "Software"),
|
||||||
|
* to deal in the Software without restriction, including without limitation the rights to
|
||||||
|
* use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software,
|
||||||
|
* and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
|
||||||
|
*
|
||||||
|
* The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
|
||||||
|
*
|
||||||
|
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
|
||||||
|
* INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
|
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
|
||||||
|
* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
|
||||||
|
* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||||
|
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef __LIBRETRO_SDK_FILE_STREAM_TRANSFORMS_H
|
||||||
|
#define __LIBRETRO_SDK_FILE_STREAM_TRANSFORMS_H
|
||||||
|
|
||||||
|
#include <stdint.h>
|
||||||
|
#include <string.h>
|
||||||
|
#include <retro_common_api.h>
|
||||||
|
#include <streams/file_stream.h>
|
||||||
|
|
||||||
|
RETRO_BEGIN_DECLS
|
||||||
|
|
||||||
|
#ifndef SKIP_STDIO_REDEFINES
|
||||||
|
|
||||||
|
#define FILE RFILE
|
||||||
|
|
||||||
|
#undef fopen
|
||||||
|
#undef fclose
|
||||||
|
#undef ftell
|
||||||
|
#undef fseek
|
||||||
|
#undef fread
|
||||||
|
#undef fgets
|
||||||
|
#undef fgetc
|
||||||
|
#undef fwrite
|
||||||
|
#undef fputc
|
||||||
|
#undef fflush
|
||||||
|
#undef fprintf
|
||||||
|
#undef ferror
|
||||||
|
#undef feof
|
||||||
|
#undef fscanf
|
||||||
|
|
||||||
|
#define fopen rfopen
|
||||||
|
#define fclose rfclose
|
||||||
|
#define ftell rftell
|
||||||
|
#define fseek rfseek
|
||||||
|
#define fread rfread
|
||||||
|
#define fgets rfgets
|
||||||
|
#define fgetc rfgetc
|
||||||
|
#define fwrite rfwrite
|
||||||
|
#define fputc rfputc
|
||||||
|
#define fflush rfflush
|
||||||
|
#define fprintf rfprintf
|
||||||
|
#define ferror rferror
|
||||||
|
#define feof rfeof
|
||||||
|
#define fscanf rfscanf
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
||||||
|
RFILE* rfopen(const char *path, const char *mode);
|
||||||
|
|
||||||
|
int rfclose(RFILE* stream);
|
||||||
|
|
||||||
|
int64_t rftell(RFILE* stream);
|
||||||
|
|
||||||
|
int64_t rfseek(RFILE* stream, int64_t offset, int origin);
|
||||||
|
|
||||||
|
int64_t rfread(void* buffer,
|
||||||
|
size_t elem_size, size_t elem_count, RFILE* stream);
|
||||||
|
|
||||||
|
char *rfgets(char *buffer, int maxCount, RFILE* stream);
|
||||||
|
|
||||||
|
int rfgetc(RFILE* stream);
|
||||||
|
|
||||||
|
int64_t rfwrite(void const* buffer,
|
||||||
|
size_t elem_size, size_t elem_count, RFILE* stream);
|
||||||
|
|
||||||
|
int rfputc(int character, RFILE * stream);
|
||||||
|
|
||||||
|
int64_t rfflush(RFILE * stream);
|
||||||
|
|
||||||
|
int rfprintf(RFILE * stream, const char * format, ...);
|
||||||
|
|
||||||
|
int rferror(RFILE* stream);
|
||||||
|
|
||||||
|
int rfeof(RFILE* stream);
|
||||||
|
|
||||||
|
int rfscanf(RFILE * stream, const char * format, ...);
|
||||||
|
|
||||||
|
RETRO_END_DECLS
|
||||||
|
|
||||||
|
#endif
|
@ -35,6 +35,33 @@
|
|||||||
|
|
||||||
RETRO_BEGIN_DECLS
|
RETRO_BEGIN_DECLS
|
||||||
|
|
||||||
|
#define STRLEN_CONST(x) ((sizeof((x))-1))
|
||||||
|
|
||||||
|
#define strcpy_literal(a, b) strcpy(a, b)
|
||||||
|
|
||||||
|
#define string_is_not_equal(a, b) !string_is_equal((a), (b))
|
||||||
|
|
||||||
|
#define string_is_not_equal_fast(a, b, size) (memcmp(a, b, size) != 0)
|
||||||
|
#define string_is_equal_fast(a, b, size) (memcmp(a, b, size) == 0)
|
||||||
|
|
||||||
|
#define TOLOWER(c) ((c) | (lr_char_props[(unsigned char)(c)] & 0x20))
|
||||||
|
#define TOUPPER(c) ((c) & ~(lr_char_props[(unsigned char)(c)] & 0x20))
|
||||||
|
|
||||||
|
/* C standard says \f \v are space, but this one disagrees */
|
||||||
|
#define ISSPACE(c) (lr_char_props[(unsigned char)(c)] & 0x80)
|
||||||
|
|
||||||
|
#define ISDIGIT(c) (lr_char_props[(unsigned char)(c)] & 0x40)
|
||||||
|
#define ISALPHA(c) (lr_char_props[(unsigned char)(c)] & 0x20)
|
||||||
|
#define ISLOWER(c) (lr_char_props[(unsigned char)(c)] & 0x04)
|
||||||
|
#define ISUPPER(c) (lr_char_props[(unsigned char)(c)] & 0x02)
|
||||||
|
#define ISALNUM(c) (lr_char_props[(unsigned char)(c)] & 0x60)
|
||||||
|
#define ISUALPHA(c) (lr_char_props[(unsigned char)(c)] & 0x28)
|
||||||
|
#define ISUALNUM(c) (lr_char_props[(unsigned char)(c)] & 0x68)
|
||||||
|
#define IS_XDIGIT(c) (lr_char_props[(unsigned char)(c)] & 0x01)
|
||||||
|
|
||||||
|
/* Deprecated alias, all callers should use string_is_equal_case_insensitive instead */
|
||||||
|
#define string_is_equal_noncase string_is_equal_case_insensitive
|
||||||
|
|
||||||
static INLINE bool string_is_empty(const char *data)
|
static INLINE bool string_is_empty(const char *data)
|
||||||
{
|
{
|
||||||
return !data || (*data == '\0');
|
return !data || (*data == '\0');
|
||||||
@ -70,15 +97,20 @@ static INLINE bool string_ends_with(const char *str, const char *suffix)
|
|||||||
return string_ends_with_size(str, suffix, strlen(str), strlen(suffix));
|
return string_ends_with_size(str, suffix, strlen(str), strlen(suffix));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Returns the length of 'str' (c.f. strlen()), but only
|
||||||
|
* checks the first 'size' characters
|
||||||
|
* - If 'str' is NULL, returns 0
|
||||||
|
* - If 'str' is not NULL and no '\0' character is found
|
||||||
|
* in the first 'size' characters, returns 'size' */
|
||||||
|
static INLINE size_t strlen_size(const char *str, size_t size)
|
||||||
|
{
|
||||||
|
size_t i = 0;
|
||||||
|
if (str)
|
||||||
|
while (i < size && str[i]) i++;
|
||||||
|
return i;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
#define STRLEN_CONST(x) ((sizeof((x))-1))
|
|
||||||
|
|
||||||
#define string_is_not_equal(a, b) !string_is_equal((a), (b))
|
|
||||||
|
|
||||||
#define string_is_not_equal_fast(a, b, size) (memcmp(a, b, size) != 0)
|
|
||||||
#define string_is_equal_fast(a, b, size) (memcmp(a, b, size) == 0)
|
|
||||||
|
|
||||||
static INLINE bool string_is_equal_case_insensitive(const char *a,
|
static INLINE bool string_is_equal_case_insensitive(const char *a,
|
||||||
const char *b)
|
const char *b)
|
||||||
{
|
{
|
||||||
@ -98,24 +130,6 @@ static INLINE bool string_is_equal_case_insensitive(const char *a,
|
|||||||
return (result == 0);
|
return (result == 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
static INLINE bool string_is_equal_noncase(const char *a, const char *b)
|
|
||||||
{
|
|
||||||
int result = 0;
|
|
||||||
const unsigned char *p1 = (const unsigned char*)a;
|
|
||||||
const unsigned char *p2 = (const unsigned char*)b;
|
|
||||||
|
|
||||||
if (!a || !b)
|
|
||||||
return false;
|
|
||||||
if (p1 == p2)
|
|
||||||
return false;
|
|
||||||
|
|
||||||
while ((result = tolower (*p1) - tolower (*p2++)) == 0)
|
|
||||||
if (*p1++ == '\0')
|
|
||||||
break;
|
|
||||||
|
|
||||||
return (result == 0);
|
|
||||||
}
|
|
||||||
|
|
||||||
char *string_to_upper(char *s);
|
char *string_to_upper(char *s);
|
||||||
|
|
||||||
char *string_to_lower(char *s);
|
char *string_to_lower(char *s);
|
||||||
@ -134,9 +148,61 @@ char *string_trim_whitespace_right(char *const s);
|
|||||||
/* Remove leading and trailing whitespaces */
|
/* Remove leading and trailing whitespaces */
|
||||||
char *string_trim_whitespace(char *const s);
|
char *string_trim_whitespace(char *const s);
|
||||||
|
|
||||||
/* max_lines == 0 means no limit */
|
/*
|
||||||
char *word_wrap(char *buffer, const char *string,
|
* Wraps string specified by 'src' to destination buffer
|
||||||
int line_width, bool unicode, unsigned max_lines);
|
* specified by 'dst' and 'dst_size'.
|
||||||
|
* This function assumes that all glyphs in the string
|
||||||
|
* have an on-screen pixel width similar to that of
|
||||||
|
* regular Latin characters - i.e. it will not wrap
|
||||||
|
* correctly any text containing so-called 'wide' Unicode
|
||||||
|
* characters (e.g. CJK languages, emojis, etc.).
|
||||||
|
*
|
||||||
|
* @param dst pointer to destination buffer.
|
||||||
|
* @param dst_size size of destination buffer.
|
||||||
|
* @param src pointer to input string.
|
||||||
|
* @param line_width max number of characters per line.
|
||||||
|
* @param wideglyph_width not used, but is necessary to keep
|
||||||
|
* compatibility with word_wrap_wideglyph().
|
||||||
|
* @param max_lines max lines of destination string.
|
||||||
|
* 0 means no limit.
|
||||||
|
*/
|
||||||
|
void word_wrap(char *dst, size_t dst_size, const char *src,
|
||||||
|
int line_width, int wideglyph_width, unsigned max_lines);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Wraps string specified by 'src' to destination buffer
|
||||||
|
* specified by 'dst' and 'dst_size'.
|
||||||
|
* This function assumes that all glyphs in the string
|
||||||
|
* are:
|
||||||
|
* - EITHER 'non-wide' Unicode glyphs, with an on-screen
|
||||||
|
* pixel width similar to that of regular Latin characters
|
||||||
|
* - OR 'wide' Unicode glyphs (e.g. CJK languages, emojis, etc.)
|
||||||
|
* with an on-screen pixel width defined by 'wideglyph_width'
|
||||||
|
* Note that wrapping may occur in inappropriate locations
|
||||||
|
* if 'src' string contains 'wide' Unicode characters whose
|
||||||
|
* on-screen pixel width deviates greatly from the set
|
||||||
|
* 'wideglyph_width' value.
|
||||||
|
*
|
||||||
|
* @param dst pointer to destination buffer.
|
||||||
|
* @param dst_size size of destination buffer.
|
||||||
|
* @param src pointer to input string.
|
||||||
|
* @param line_width max number of characters per line.
|
||||||
|
* @param wideglyph_width effective width of 'wide' Unicode glyphs.
|
||||||
|
* the value here is normalised relative to the
|
||||||
|
* typical on-screen pixel width of a regular
|
||||||
|
* Latin character:
|
||||||
|
* - a regular Latin character is defined to
|
||||||
|
* have an effective width of 100
|
||||||
|
* - wideglyph_width = 100 * (wide_character_pixel_width / latin_character_pixel_width)
|
||||||
|
* - e.g. if 'wide' Unicode characters in 'src'
|
||||||
|
* have an on-screen pixel width twice that of
|
||||||
|
* regular Latin characters, wideglyph_width
|
||||||
|
* would be 200
|
||||||
|
* @param max_lines max lines of destination string.
|
||||||
|
* 0 means no limit.
|
||||||
|
*/
|
||||||
|
void word_wrap_wideglyph(char *dst, size_t dst_size, const char *src,
|
||||||
|
int line_width, int wideglyph_width, unsigned max_lines);
|
||||||
|
|
||||||
/* Splits string into tokens seperated by 'delim'
|
/* Splits string into tokens seperated by 'delim'
|
||||||
* > Returned token string must be free()'d
|
* > Returned token string must be free()'d
|
||||||
@ -177,6 +243,8 @@ char *string_init(const char *src);
|
|||||||
|
|
||||||
void string_set(char **string, const char *src);
|
void string_set(char **string, const char *src);
|
||||||
|
|
||||||
|
extern const unsigned char lr_char_props[256];
|
||||||
|
|
||||||
RETRO_END_DECLS
|
RETRO_END_DECLS
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
@ -41,17 +41,17 @@ typedef void* HANDLE;
|
|||||||
#ifdef HAVE_CDROM
|
#ifdef HAVE_CDROM
|
||||||
typedef struct
|
typedef struct
|
||||||
{
|
{
|
||||||
|
int64_t byte_pos;
|
||||||
char *cue_buf;
|
char *cue_buf;
|
||||||
size_t cue_len;
|
size_t cue_len;
|
||||||
int64_t byte_pos;
|
unsigned cur_lba;
|
||||||
char drive;
|
unsigned last_frame_lba;
|
||||||
unsigned char cur_min;
|
unsigned char cur_min;
|
||||||
unsigned char cur_sec;
|
unsigned char cur_sec;
|
||||||
unsigned char cur_frame;
|
unsigned char cur_frame;
|
||||||
unsigned char cur_track;
|
unsigned char cur_track;
|
||||||
unsigned cur_lba;
|
|
||||||
unsigned last_frame_lba;
|
|
||||||
unsigned char last_frame[2352];
|
unsigned char last_frame[2352];
|
||||||
|
char drive;
|
||||||
bool last_frame_valid;
|
bool last_frame_valid;
|
||||||
} vfs_cdrom_t;
|
} vfs_cdrom_t;
|
||||||
#endif
|
#endif
|
||||||
@ -69,22 +69,22 @@ struct retro_vfs_file_handle
|
|||||||
struct libretro_vfs_implementation_file
|
struct libretro_vfs_implementation_file
|
||||||
#endif
|
#endif
|
||||||
{
|
{
|
||||||
int fd;
|
#ifdef HAVE_CDROM
|
||||||
unsigned hints;
|
vfs_cdrom_t cdrom; /* int64_t alignment */
|
||||||
|
#endif
|
||||||
int64_t size;
|
int64_t size;
|
||||||
char *buf;
|
uint64_t mappos;
|
||||||
|
uint64_t mapsize;
|
||||||
FILE *fp;
|
FILE *fp;
|
||||||
#ifdef _WIN32
|
#ifdef _WIN32
|
||||||
HANDLE fh;
|
HANDLE fh;
|
||||||
#endif
|
#endif
|
||||||
|
char *buf;
|
||||||
char* orig_path;
|
char* orig_path;
|
||||||
uint64_t mappos;
|
|
||||||
uint64_t mapsize;
|
|
||||||
uint8_t *mapped;
|
uint8_t *mapped;
|
||||||
|
int fd;
|
||||||
|
unsigned hints;
|
||||||
enum vfs_scheme scheme;
|
enum vfs_scheme scheme;
|
||||||
#ifdef HAVE_CDROM
|
|
||||||
vfs_cdrom_t cdrom;
|
|
||||||
#endif
|
|
||||||
};
|
};
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
@ -35,11 +35,19 @@
|
|||||||
#include <compat/msvc.h>
|
#include <compat/msvc.h>
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
#include <string/stdstring.h>
|
||||||
#include <streams/file_stream.h>
|
#include <streams/file_stream.h>
|
||||||
#define VFS_FRONTEND
|
#define VFS_FRONTEND
|
||||||
#include <vfs/vfs_implementation.h>
|
#include <vfs/vfs_implementation.h>
|
||||||
|
|
||||||
static const int64_t vfs_error_return_value = -1;
|
#define VFS_ERROR_RETURN_VALUE -1
|
||||||
|
|
||||||
|
struct RFILE
|
||||||
|
{
|
||||||
|
struct retro_vfs_file_handle *hfile;
|
||||||
|
bool error_flag;
|
||||||
|
bool eof_flag;
|
||||||
|
};
|
||||||
|
|
||||||
static retro_vfs_get_path_t filestream_get_path_cb = NULL;
|
static retro_vfs_get_path_t filestream_get_path_cb = NULL;
|
||||||
static retro_vfs_open_t filestream_open_cb = NULL;
|
static retro_vfs_open_t filestream_open_cb = NULL;
|
||||||
@ -54,18 +62,12 @@ static retro_vfs_flush_t filestream_flush_cb = NULL;
|
|||||||
static retro_vfs_remove_t filestream_remove_cb = NULL;
|
static retro_vfs_remove_t filestream_remove_cb = NULL;
|
||||||
static retro_vfs_rename_t filestream_rename_cb = NULL;
|
static retro_vfs_rename_t filestream_rename_cb = NULL;
|
||||||
|
|
||||||
struct RFILE
|
|
||||||
{
|
|
||||||
struct retro_vfs_file_handle *hfile;
|
|
||||||
bool error_flag;
|
|
||||||
bool eof_flag;
|
|
||||||
};
|
|
||||||
|
|
||||||
/* VFS Initialization */
|
/* VFS Initialization */
|
||||||
|
|
||||||
void filestream_vfs_init(const struct retro_vfs_interface_info* vfs_info)
|
void filestream_vfs_init(const struct retro_vfs_interface_info* vfs_info)
|
||||||
{
|
{
|
||||||
const struct retro_vfs_interface* vfs_iface;
|
const struct retro_vfs_interface *
|
||||||
|
vfs_iface = vfs_info->iface;
|
||||||
|
|
||||||
filestream_get_path_cb = NULL;
|
filestream_get_path_cb = NULL;
|
||||||
filestream_open_cb = NULL;
|
filestream_open_cb = NULL;
|
||||||
@ -80,9 +82,9 @@ void filestream_vfs_init(const struct retro_vfs_interface_info* vfs_info)
|
|||||||
filestream_remove_cb = NULL;
|
filestream_remove_cb = NULL;
|
||||||
filestream_rename_cb = NULL;
|
filestream_rename_cb = NULL;
|
||||||
|
|
||||||
vfs_iface = vfs_info->iface;
|
if (
|
||||||
|
(vfs_info->required_interface_version <
|
||||||
if (vfs_info->required_interface_version < FILESTREAM_REQUIRED_VFS_VERSION
|
FILESTREAM_REQUIRED_VFS_VERSION)
|
||||||
|| !vfs_iface)
|
|| !vfs_iface)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
@ -103,12 +105,13 @@ void filestream_vfs_init(const struct retro_vfs_interface_info* vfs_info)
|
|||||||
/* Callback wrappers */
|
/* Callback wrappers */
|
||||||
bool filestream_exists(const char *path)
|
bool filestream_exists(const char *path)
|
||||||
{
|
{
|
||||||
RFILE *dummy = NULL;
|
RFILE *dummy = NULL;
|
||||||
|
|
||||||
if (!path || !*path)
|
if (!path || !*path)
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
dummy = filestream_open(path,
|
dummy = filestream_open(
|
||||||
|
path,
|
||||||
RETRO_VFS_FILE_ACCESS_READ,
|
RETRO_VFS_FILE_ACCESS_READ,
|
||||||
RETRO_VFS_FILE_ACCESS_HINT_NONE);
|
RETRO_VFS_FILE_ACCESS_HINT_NONE);
|
||||||
|
|
||||||
@ -130,9 +133,10 @@ int64_t filestream_get_size(RFILE *stream)
|
|||||||
if (filestream_size_cb)
|
if (filestream_size_cb)
|
||||||
output = filestream_size_cb(stream->hfile);
|
output = filestream_size_cb(stream->hfile);
|
||||||
else
|
else
|
||||||
output = retro_vfs_file_size_impl((libretro_vfs_implementation_file*)stream->hfile);
|
output = retro_vfs_file_size_impl(
|
||||||
|
(libretro_vfs_implementation_file*)stream->hfile);
|
||||||
|
|
||||||
if (output == vfs_error_return_value)
|
if (output == VFS_ERROR_RETURN_VALUE)
|
||||||
stream->error_flag = true;
|
stream->error_flag = true;
|
||||||
|
|
||||||
return output;
|
return output;
|
||||||
@ -145,9 +149,10 @@ int64_t filestream_truncate(RFILE *stream, int64_t length)
|
|||||||
if (filestream_truncate_cb)
|
if (filestream_truncate_cb)
|
||||||
output = filestream_truncate_cb(stream->hfile, length);
|
output = filestream_truncate_cb(stream->hfile, length);
|
||||||
else
|
else
|
||||||
output = retro_vfs_file_truncate_impl((libretro_vfs_implementation_file*)stream->hfile, length);
|
output = retro_vfs_file_truncate_impl(
|
||||||
|
(libretro_vfs_implementation_file*)stream->hfile, length);
|
||||||
|
|
||||||
if (output == vfs_error_return_value)
|
if (output == VFS_ERROR_RETURN_VALUE)
|
||||||
stream->error_flag = true;
|
stream->error_flag = true;
|
||||||
|
|
||||||
return output;
|
return output;
|
||||||
@ -216,14 +221,14 @@ int filestream_getc(RFILE *stream)
|
|||||||
return EOF;
|
return EOF;
|
||||||
}
|
}
|
||||||
|
|
||||||
int filestream_scanf(RFILE *stream, const char* format, ...)
|
int filestream_vscanf(RFILE *stream, const char* format, va_list *args)
|
||||||
{
|
{
|
||||||
char buf[4096];
|
char buf[4096];
|
||||||
char subfmt[64];
|
char subfmt[64];
|
||||||
va_list args;
|
va_list args_copy;
|
||||||
const char * bufiter = buf;
|
const char * bufiter = buf;
|
||||||
int64_t startpos = filestream_tell(stream);
|
|
||||||
int ret = 0;
|
int ret = 0;
|
||||||
|
int64_t startpos = filestream_tell(stream);
|
||||||
int64_t maxlen = filestream_read(stream, buf, sizeof(buf)-1);
|
int64_t maxlen = filestream_read(stream, buf, sizeof(buf)-1);
|
||||||
|
|
||||||
if (maxlen <= 0)
|
if (maxlen <= 0)
|
||||||
@ -231,7 +236,12 @@ int filestream_scanf(RFILE *stream, const char* format, ...)
|
|||||||
|
|
||||||
buf[maxlen] = '\0';
|
buf[maxlen] = '\0';
|
||||||
|
|
||||||
va_start(args, format);
|
/* Have to copy the input va_list here
|
||||||
|
* > Calling va_arg() on 'args' directly would
|
||||||
|
* cause the va_list to have an indeterminate value
|
||||||
|
* in the function calling filestream_vscanf(),
|
||||||
|
* leading to unexpected behaviour */
|
||||||
|
va_copy(args_copy, *args);
|
||||||
|
|
||||||
while (*format)
|
while (*format)
|
||||||
{
|
{
|
||||||
@ -251,7 +261,7 @@ int filestream_scanf(RFILE *stream, const char* format, ...)
|
|||||||
*subfmtiter++ = *format++;
|
*subfmtiter++ = *format++;
|
||||||
}
|
}
|
||||||
|
|
||||||
while (isdigit(*format))
|
while (ISDIGIT((unsigned char)*format))
|
||||||
*subfmtiter++ = *format++; /* width */
|
*subfmtiter++ = *format++; /* width */
|
||||||
|
|
||||||
/* length */
|
/* length */
|
||||||
@ -284,28 +294,33 @@ int filestream_scanf(RFILE *stream, const char* format, ...)
|
|||||||
*subfmtiter++ = 'n';
|
*subfmtiter++ = 'n';
|
||||||
*subfmtiter++ = '\0';
|
*subfmtiter++ = '\0';
|
||||||
|
|
||||||
if (sizeof(void*) != sizeof(long*)) abort(); /* all pointers must have the same size */
|
if (sizeof(void*) != sizeof(long*))
|
||||||
|
abort(); /* all pointers must have the same size */
|
||||||
|
|
||||||
if (asterisk)
|
if (asterisk)
|
||||||
{
|
{
|
||||||
int v = sscanf(bufiter, subfmt, &sublen);
|
int v = sscanf(bufiter, subfmt, &sublen);
|
||||||
if (v == EOF)
|
if (v == EOF)
|
||||||
return EOF;
|
return EOF;
|
||||||
if (v != 0) break;
|
if (v != 0)
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
int v = sscanf(bufiter, subfmt, va_arg(args, void*), &sublen);
|
int v = sscanf(bufiter, subfmt, va_arg(args_copy, void*), &sublen);
|
||||||
if (v == EOF)
|
if (v == EOF)
|
||||||
return EOF;
|
return EOF;
|
||||||
if (v != 1) break;
|
if (v != 1)
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
ret++;
|
ret++;
|
||||||
bufiter += sublen;
|
bufiter += sublen;
|
||||||
}
|
}
|
||||||
else if (isspace(*format))
|
else if (isspace((unsigned char)*format))
|
||||||
{
|
{
|
||||||
while (isspace(*bufiter)) bufiter++;
|
while (isspace((unsigned char)*bufiter))
|
||||||
|
bufiter++;
|
||||||
format++;
|
format++;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
@ -317,12 +332,23 @@ int filestream_scanf(RFILE *stream, const char* format, ...)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
va_end(args);
|
va_end(args_copy);
|
||||||
filestream_seek(stream, startpos+(bufiter-buf), RETRO_VFS_SEEK_POSITION_START);
|
filestream_seek(stream, startpos+(bufiter-buf),
|
||||||
|
RETRO_VFS_SEEK_POSITION_START);
|
||||||
|
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
int filestream_scanf(RFILE *stream, const char* format, ...)
|
||||||
|
{
|
||||||
|
int result;
|
||||||
|
va_list vl;
|
||||||
|
va_start(vl, format);
|
||||||
|
result = filestream_vscanf(stream, format, &vl);
|
||||||
|
va_end(vl);
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
int64_t filestream_seek(RFILE *stream, int64_t offset, int seek_position)
|
int64_t filestream_seek(RFILE *stream, int64_t offset, int seek_position)
|
||||||
{
|
{
|
||||||
int64_t output;
|
int64_t output;
|
||||||
@ -330,11 +356,14 @@ int64_t filestream_seek(RFILE *stream, int64_t offset, int seek_position)
|
|||||||
if (filestream_seek_cb)
|
if (filestream_seek_cb)
|
||||||
output = filestream_seek_cb(stream->hfile, offset, seek_position);
|
output = filestream_seek_cb(stream->hfile, offset, seek_position);
|
||||||
else
|
else
|
||||||
output = retro_vfs_file_seek_impl((libretro_vfs_implementation_file*)stream->hfile, offset, seek_position);
|
output = retro_vfs_file_seek_impl(
|
||||||
|
(libretro_vfs_implementation_file*)stream->hfile,
|
||||||
|
offset, seek_position);
|
||||||
|
|
||||||
if (output == vfs_error_return_value)
|
if (output == VFS_ERROR_RETURN_VALUE)
|
||||||
stream->error_flag = true;
|
stream->error_flag = true;
|
||||||
stream->eof_flag = false;
|
|
||||||
|
stream->eof_flag = false;
|
||||||
|
|
||||||
return output;
|
return output;
|
||||||
}
|
}
|
||||||
@ -351,9 +380,10 @@ int64_t filestream_tell(RFILE *stream)
|
|||||||
if (filestream_size_cb)
|
if (filestream_size_cb)
|
||||||
output = filestream_tell_cb(stream->hfile);
|
output = filestream_tell_cb(stream->hfile);
|
||||||
else
|
else
|
||||||
output = retro_vfs_file_tell_impl((libretro_vfs_implementation_file*)stream->hfile);
|
output = retro_vfs_file_tell_impl(
|
||||||
|
(libretro_vfs_implementation_file*)stream->hfile);
|
||||||
|
|
||||||
if (output == vfs_error_return_value)
|
if (output == VFS_ERROR_RETURN_VALUE)
|
||||||
stream->error_flag = true;
|
stream->error_flag = true;
|
||||||
|
|
||||||
return output;
|
return output;
|
||||||
@ -365,7 +395,7 @@ void filestream_rewind(RFILE *stream)
|
|||||||
return;
|
return;
|
||||||
filestream_seek(stream, 0L, RETRO_VFS_SEEK_POSITION_START);
|
filestream_seek(stream, 0L, RETRO_VFS_SEEK_POSITION_START);
|
||||||
stream->error_flag = false;
|
stream->error_flag = false;
|
||||||
stream->eof_flag = false;
|
stream->eof_flag = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
int64_t filestream_read(RFILE *stream, void *s, int64_t len)
|
int64_t filestream_read(RFILE *stream, void *s, int64_t len)
|
||||||
@ -378,10 +408,10 @@ int64_t filestream_read(RFILE *stream, void *s, int64_t len)
|
|||||||
output = retro_vfs_file_read_impl(
|
output = retro_vfs_file_read_impl(
|
||||||
(libretro_vfs_implementation_file*)stream->hfile, s, len);
|
(libretro_vfs_implementation_file*)stream->hfile, s, len);
|
||||||
|
|
||||||
if (output == vfs_error_return_value)
|
if (output == VFS_ERROR_RETURN_VALUE)
|
||||||
stream->error_flag = true;
|
stream->error_flag = true;
|
||||||
if (output < len)
|
if (output < len)
|
||||||
stream->eof_flag = true;
|
stream->eof_flag = true;
|
||||||
|
|
||||||
return output;
|
return output;
|
||||||
}
|
}
|
||||||
@ -393,9 +423,10 @@ int filestream_flush(RFILE *stream)
|
|||||||
if (filestream_flush_cb)
|
if (filestream_flush_cb)
|
||||||
output = filestream_flush_cb(stream->hfile);
|
output = filestream_flush_cb(stream->hfile);
|
||||||
else
|
else
|
||||||
output = retro_vfs_file_flush_impl((libretro_vfs_implementation_file*)stream->hfile);
|
output = retro_vfs_file_flush_impl(
|
||||||
|
(libretro_vfs_implementation_file*)stream->hfile);
|
||||||
|
|
||||||
if (output == vfs_error_return_value)
|
if (output == VFS_ERROR_RETURN_VALUE)
|
||||||
stream->error_flag = true;
|
stream->error_flag = true;
|
||||||
|
|
||||||
return output;
|
return output;
|
||||||
@ -422,7 +453,8 @@ const char* filestream_get_path(RFILE *stream)
|
|||||||
if (filestream_get_path_cb)
|
if (filestream_get_path_cb)
|
||||||
return filestream_get_path_cb(stream->hfile);
|
return filestream_get_path_cb(stream->hfile);
|
||||||
|
|
||||||
return retro_vfs_file_get_path_impl((libretro_vfs_implementation_file*)stream->hfile);
|
return retro_vfs_file_get_path_impl(
|
||||||
|
(libretro_vfs_implementation_file*)stream->hfile);
|
||||||
}
|
}
|
||||||
|
|
||||||
int64_t filestream_write(RFILE *stream, const void *s, int64_t len)
|
int64_t filestream_write(RFILE *stream, const void *s, int64_t len)
|
||||||
@ -432,9 +464,10 @@ int64_t filestream_write(RFILE *stream, const void *s, int64_t len)
|
|||||||
if (filestream_write_cb)
|
if (filestream_write_cb)
|
||||||
output = filestream_write_cb(stream->hfile, s, len);
|
output = filestream_write_cb(stream->hfile, s, len);
|
||||||
else
|
else
|
||||||
output = retro_vfs_file_write_impl((libretro_vfs_implementation_file*)stream->hfile, s, len);
|
output = retro_vfs_file_write_impl(
|
||||||
|
(libretro_vfs_implementation_file*)stream->hfile, s, len);
|
||||||
|
|
||||||
if (output == vfs_error_return_value)
|
if (output == VFS_ERROR_RETURN_VALUE)
|
||||||
stream->error_flag = true;
|
stream->error_flag = true;
|
||||||
|
|
||||||
return output;
|
return output;
|
||||||
@ -445,7 +478,9 @@ int filestream_putc(RFILE *stream, int c)
|
|||||||
char c_char = (char)c;
|
char c_char = (char)c;
|
||||||
if (!stream)
|
if (!stream)
|
||||||
return EOF;
|
return EOF;
|
||||||
return filestream_write(stream, &c_char, 1)==1 ? (int)(unsigned char)c : EOF;
|
return filestream_write(stream, &c_char, 1) == 1
|
||||||
|
? (int)(unsigned char)c
|
||||||
|
: EOF;
|
||||||
}
|
}
|
||||||
|
|
||||||
int filestream_vprintf(RFILE *stream, const char* format, va_list args)
|
int filestream_vprintf(RFILE *stream, const char* format, va_list args)
|
||||||
@ -487,7 +522,8 @@ int filestream_close(RFILE *stream)
|
|||||||
if (filestream_close_cb)
|
if (filestream_close_cb)
|
||||||
output = filestream_close_cb(fp);
|
output = filestream_close_cb(fp);
|
||||||
else
|
else
|
||||||
output = retro_vfs_file_close_impl((libretro_vfs_implementation_file*)fp);
|
output = retro_vfs_file_close_impl(
|
||||||
|
(libretro_vfs_implementation_file*)fp);
|
||||||
|
|
||||||
if (output == 0)
|
if (output == 0)
|
||||||
free(stream);
|
free(stream);
|
||||||
@ -500,10 +536,11 @@ int filestream_close(RFILE *stream)
|
|||||||
* @path : path to file.
|
* @path : path to file.
|
||||||
* @buf : buffer to allocate and read the contents of the
|
* @buf : buffer to allocate and read the contents of the
|
||||||
* file into. Needs to be freed manually.
|
* file into. Needs to be freed manually.
|
||||||
|
* @len : optional output integer containing bytes read.
|
||||||
*
|
*
|
||||||
* Read the contents of a file into @buf.
|
* Read the contents of a file into @buf.
|
||||||
*
|
*
|
||||||
* Returns: number of items read, -1 on error.
|
* Returns: non zero on success.
|
||||||
*/
|
*/
|
||||||
int64_t filestream_read_file(const char *path, void **buf, int64_t *len)
|
int64_t filestream_read_file(const char *path, void **buf, int64_t *len)
|
||||||
{
|
{
|
||||||
|
159
libgambatte/libretro-common/streams/file_stream_transforms.c
Normal file
159
libgambatte/libretro-common/streams/file_stream_transforms.c
Normal file
@ -0,0 +1,159 @@
|
|||||||
|
/* Copyright (C) 2010-2020 The RetroArch team
|
||||||
|
*
|
||||||
|
* ---------------------------------------------------------------------------------------
|
||||||
|
* The following license statement only applies to this file (file_stream_transforms.c).
|
||||||
|
* ---------------------------------------------------------------------------------------
|
||||||
|
*
|
||||||
|
* Permission is hereby granted, free of charge,
|
||||||
|
* to any person obtaining a copy of this software and associated documentation files (the "Software"),
|
||||||
|
* to deal in the Software without restriction, including without limitation the rights to
|
||||||
|
* use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software,
|
||||||
|
* and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
|
||||||
|
*
|
||||||
|
* The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
|
||||||
|
*
|
||||||
|
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
|
||||||
|
* INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
|
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
|
||||||
|
* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
|
||||||
|
* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||||
|
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <string.h>
|
||||||
|
#include <stdarg.h>
|
||||||
|
|
||||||
|
#include <libretro.h>
|
||||||
|
#include <streams/file_stream.h>
|
||||||
|
|
||||||
|
RFILE* rfopen(const char *path, const char *mode)
|
||||||
|
{
|
||||||
|
RFILE *output = NULL;
|
||||||
|
unsigned int retro_mode = RETRO_VFS_FILE_ACCESS_READ;
|
||||||
|
bool position_to_end = false;
|
||||||
|
|
||||||
|
if (strstr(mode, "r"))
|
||||||
|
{
|
||||||
|
retro_mode = RETRO_VFS_FILE_ACCESS_READ;
|
||||||
|
if (strstr(mode, "+"))
|
||||||
|
{
|
||||||
|
retro_mode = RETRO_VFS_FILE_ACCESS_READ_WRITE |
|
||||||
|
RETRO_VFS_FILE_ACCESS_UPDATE_EXISTING;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if (strstr(mode, "w"))
|
||||||
|
{
|
||||||
|
retro_mode = RETRO_VFS_FILE_ACCESS_WRITE;
|
||||||
|
if (strstr(mode, "+"))
|
||||||
|
retro_mode = RETRO_VFS_FILE_ACCESS_READ_WRITE;
|
||||||
|
}
|
||||||
|
else if (strstr(mode, "a"))
|
||||||
|
{
|
||||||
|
retro_mode = RETRO_VFS_FILE_ACCESS_WRITE |
|
||||||
|
RETRO_VFS_FILE_ACCESS_UPDATE_EXISTING;
|
||||||
|
position_to_end = true;
|
||||||
|
if (strstr(mode, "+"))
|
||||||
|
{
|
||||||
|
retro_mode = RETRO_VFS_FILE_ACCESS_READ_WRITE |
|
||||||
|
RETRO_VFS_FILE_ACCESS_UPDATE_EXISTING;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
output = filestream_open(path, retro_mode,
|
||||||
|
RETRO_VFS_FILE_ACCESS_HINT_NONE);
|
||||||
|
if (output && position_to_end)
|
||||||
|
filestream_seek(output, 0, RETRO_VFS_SEEK_POSITION_END);
|
||||||
|
|
||||||
|
return output;
|
||||||
|
}
|
||||||
|
|
||||||
|
int rfclose(RFILE* stream)
|
||||||
|
{
|
||||||
|
return filestream_close(stream);
|
||||||
|
}
|
||||||
|
|
||||||
|
int64_t rftell(RFILE* stream)
|
||||||
|
{
|
||||||
|
return filestream_tell(stream);
|
||||||
|
}
|
||||||
|
|
||||||
|
int64_t rfseek(RFILE* stream, int64_t offset, int origin)
|
||||||
|
{
|
||||||
|
int seek_position = -1;
|
||||||
|
switch (origin)
|
||||||
|
{
|
||||||
|
case SEEK_SET:
|
||||||
|
seek_position = RETRO_VFS_SEEK_POSITION_START;
|
||||||
|
break;
|
||||||
|
case SEEK_CUR:
|
||||||
|
seek_position = RETRO_VFS_SEEK_POSITION_CURRENT;
|
||||||
|
break;
|
||||||
|
case SEEK_END:
|
||||||
|
seek_position = RETRO_VFS_SEEK_POSITION_END;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
return filestream_seek(stream, offset, seek_position);
|
||||||
|
}
|
||||||
|
|
||||||
|
int64_t rfread(void* buffer,
|
||||||
|
size_t elem_size, size_t elem_count, RFILE* stream)
|
||||||
|
{
|
||||||
|
return (filestream_read(stream, buffer, elem_size * elem_count) / elem_size);
|
||||||
|
}
|
||||||
|
|
||||||
|
char *rfgets(char *buffer, int maxCount, RFILE* stream)
|
||||||
|
{
|
||||||
|
return filestream_gets(stream, buffer, maxCount);
|
||||||
|
}
|
||||||
|
|
||||||
|
int rfgetc(RFILE* stream)
|
||||||
|
{
|
||||||
|
return filestream_getc(stream);
|
||||||
|
}
|
||||||
|
|
||||||
|
int64_t rfwrite(void const* buffer,
|
||||||
|
size_t elem_size, size_t elem_count, RFILE* stream)
|
||||||
|
{
|
||||||
|
return filestream_write(stream, buffer, elem_size * elem_count);
|
||||||
|
}
|
||||||
|
|
||||||
|
int rfputc(int character, RFILE * stream)
|
||||||
|
{
|
||||||
|
return filestream_putc(stream, character);
|
||||||
|
}
|
||||||
|
|
||||||
|
int64_t rfflush(RFILE * stream)
|
||||||
|
{
|
||||||
|
return filestream_flush(stream);
|
||||||
|
}
|
||||||
|
|
||||||
|
int rfprintf(RFILE * stream, const char * format, ...)
|
||||||
|
{
|
||||||
|
int result;
|
||||||
|
va_list vl;
|
||||||
|
va_start(vl, format);
|
||||||
|
result = filestream_vprintf(stream, format, vl);
|
||||||
|
va_end(vl);
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
int rferror(RFILE* stream)
|
||||||
|
{
|
||||||
|
return filestream_error(stream);
|
||||||
|
}
|
||||||
|
|
||||||
|
int rfeof(RFILE* stream)
|
||||||
|
{
|
||||||
|
return filestream_eof(stream);
|
||||||
|
}
|
||||||
|
|
||||||
|
int rfscanf(RFILE * stream, const char * format, ...)
|
||||||
|
{
|
||||||
|
int result;
|
||||||
|
va_list vl;
|
||||||
|
va_start(vl, format);
|
||||||
|
result = filestream_vscanf(stream, format, &vl);
|
||||||
|
va_end(vl);
|
||||||
|
return result;
|
||||||
|
}
|
@ -22,10 +22,31 @@
|
|||||||
|
|
||||||
#include <stdint.h>
|
#include <stdint.h>
|
||||||
#include <ctype.h>
|
#include <ctype.h>
|
||||||
|
#include <string.h>
|
||||||
|
|
||||||
#include <string/stdstring.h>
|
#include <string/stdstring.h>
|
||||||
#include <encodings/utf.h>
|
#include <encodings/utf.h>
|
||||||
|
|
||||||
|
const uint8_t lr_char_props[256] = {
|
||||||
|
/*x0 x1 x2 x3 x4 x5 x6 x7 x8 x9 xA xB xC xD xE xF */
|
||||||
|
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x80,0x80,0x00,0x00,0x80,0x00,0x00, /* 0x */
|
||||||
|
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, /* 1x */
|
||||||
|
0x80,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, /* 2x !"#$%&'()*+,-./ */
|
||||||
|
0x41,0x41,0x41,0x41,0x41,0x41,0x41,0x41,0x41,0x41,0x00,0x00,0x00,0x00,0x00,0x00, /* 3x 0123456789:;<=>? */
|
||||||
|
0x00,0x23,0x23,0x23,0x23,0x23,0x23,0x22,0x22,0x22,0x22,0x22,0x22,0x22,0x22,0x22, /* 4x @ABCDEFGHIJKLMNO */
|
||||||
|
0x22,0x22,0x22,0x22,0x22,0x22,0x22,0x22,0x22,0x22,0x22,0x00,0x00,0x00,0x00,0x08, /* 5x PQRSTUVWXYZ[\]^_ */
|
||||||
|
0x00,0x25,0x25,0x25,0x25,0x25,0x25,0x24,0x24,0x24,0x24,0x24,0x24,0x24,0x24,0x24, /* 6x `abcdefghijklmno */
|
||||||
|
0x24,0x24,0x24,0x24,0x24,0x24,0x24,0x24,0x24,0x24,0x24,0x00,0x00,0x00,0x00,0x00, /* 7x pqrstuvwxyz{|}~ */
|
||||||
|
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, /* 8x */
|
||||||
|
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, /* 9x */
|
||||||
|
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, /* Ax */
|
||||||
|
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, /* Bx */
|
||||||
|
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, /* Cx */
|
||||||
|
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, /* Dx */
|
||||||
|
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, /* Ex */
|
||||||
|
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, /* Fx */
|
||||||
|
};
|
||||||
|
|
||||||
char *string_init(const char *src)
|
char *string_init(const char *src)
|
||||||
{
|
{
|
||||||
return src ? strdup(src) : NULL;
|
return src ? strdup(src) : NULL;
|
||||||
@ -34,7 +55,7 @@ char *string_init(const char *src)
|
|||||||
void string_set(char **string, const char *src)
|
void string_set(char **string, const char *src)
|
||||||
{
|
{
|
||||||
free(*string);
|
free(*string);
|
||||||
*string = src ? strdup(src) : NULL;
|
*string = string_init(src);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@ -124,7 +145,7 @@ char *string_trim_whitespace_left(char *const s)
|
|||||||
size_t len = strlen(s);
|
size_t len = strlen(s);
|
||||||
char *current = s;
|
char *current = s;
|
||||||
|
|
||||||
while (*current && isspace((unsigned char)*current))
|
while (*current && ISSPACE((unsigned char)*current))
|
||||||
{
|
{
|
||||||
++current;
|
++current;
|
||||||
--len;
|
--len;
|
||||||
@ -145,13 +166,13 @@ char *string_trim_whitespace_right(char *const s)
|
|||||||
size_t len = strlen(s);
|
size_t len = strlen(s);
|
||||||
char *current = s + len - 1;
|
char *current = s + len - 1;
|
||||||
|
|
||||||
while (current != s && isspace((unsigned char)*current))
|
while (current != s && ISSPACE((unsigned char)*current))
|
||||||
{
|
{
|
||||||
--current;
|
--current;
|
||||||
--len;
|
--len;
|
||||||
}
|
}
|
||||||
|
|
||||||
current[isspace((unsigned char)*current) ? 0 : 1] = '\0';
|
current[ISSPACE((unsigned char)*current) ? 0 : 1] = '\0';
|
||||||
}
|
}
|
||||||
|
|
||||||
return s;
|
return s;
|
||||||
@ -166,88 +187,207 @@ char *string_trim_whitespace(char *const s)
|
|||||||
return s;
|
return s;
|
||||||
}
|
}
|
||||||
|
|
||||||
char *word_wrap(char* buffer, const char *string, int line_width, bool unicode, unsigned max_lines)
|
void word_wrap(char *dst, size_t dst_size, const char *src, int line_width, int wideglyph_width, unsigned max_lines)
|
||||||
{
|
{
|
||||||
unsigned i = 0;
|
char *lastspace = NULL;
|
||||||
unsigned len = (unsigned)strlen(string);
|
unsigned counter = 0;
|
||||||
unsigned lines = 1;
|
unsigned lines = 1;
|
||||||
|
size_t src_len = strlen(src);
|
||||||
|
const char *src_end = src + src_len;
|
||||||
|
|
||||||
while (i < len)
|
/* Prevent buffer overflow */
|
||||||
|
if (dst_size < src_len + 1)
|
||||||
|
return;
|
||||||
|
|
||||||
|
/* Early return if src string length is less
|
||||||
|
* than line width */
|
||||||
|
if (src_len < line_width)
|
||||||
{
|
{
|
||||||
unsigned counter;
|
strcpy(dst, src);
|
||||||
int pos = (int)(&buffer[i] - buffer);
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
/* copy string until the end of the line is reached */
|
while (*src != '\0')
|
||||||
for (counter = 1; counter <= (unsigned)line_width; counter++)
|
{
|
||||||
|
unsigned char_len;
|
||||||
|
|
||||||
|
char_len = (unsigned)(utf8skip(src, 1) - src);
|
||||||
|
counter++;
|
||||||
|
|
||||||
|
if (*src == ' ')
|
||||||
|
lastspace = dst; /* Remember the location of the whitespace */
|
||||||
|
else if (*src == '\n')
|
||||||
{
|
{
|
||||||
const char *character;
|
/* If newlines embedded in the input,
|
||||||
unsigned char_len;
|
* reset the index */
|
||||||
unsigned j = i;
|
lines++;
|
||||||
|
counter = 0;
|
||||||
|
|
||||||
/* check if end of string reached */
|
/* Early return if remaining src string
|
||||||
if (i == len)
|
* length is less than line width */
|
||||||
|
if (src_end - src <= line_width)
|
||||||
{
|
{
|
||||||
buffer[i] = 0;
|
strcpy(dst, src);
|
||||||
return buffer;
|
return;
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
character = utf8skip(&string[i], 1);
|
while (char_len--)
|
||||||
char_len = (unsigned)(character - &string[i]);
|
*dst++ = *src++;
|
||||||
|
|
||||||
if (!unicode)
|
if (counter >= (unsigned)line_width)
|
||||||
counter += char_len - 1;
|
|
||||||
|
|
||||||
do
|
|
||||||
{
|
|
||||||
buffer[i] = string[i];
|
|
||||||
char_len--;
|
|
||||||
i++;
|
|
||||||
} while (char_len);
|
|
||||||
|
|
||||||
/* check for newlines embedded in the original input
|
|
||||||
* and reset the index */
|
|
||||||
if (buffer[j] == '\n')
|
|
||||||
{
|
|
||||||
lines++;
|
|
||||||
counter = 1;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/* check for whitespace */
|
|
||||||
if (string[i] == ' ')
|
|
||||||
{
|
{
|
||||||
if ((max_lines == 0 || lines < max_lines))
|
counter = 0;
|
||||||
|
|
||||||
|
if (lastspace && (max_lines == 0 || lines < max_lines))
|
||||||
{
|
{
|
||||||
buffer[i] = '\n';
|
/* Replace nearest (previous) whitespace
|
||||||
i++;
|
* with newline character */
|
||||||
|
*lastspace = '\n';
|
||||||
lines++;
|
lines++;
|
||||||
|
|
||||||
|
src -= dst - lastspace - 1;
|
||||||
|
dst = lastspace + 1;
|
||||||
|
lastspace = NULL;
|
||||||
|
|
||||||
|
/* Early return if remaining src string
|
||||||
|
* length is less than line width */
|
||||||
|
if (src_end - src < line_width)
|
||||||
|
{
|
||||||
|
strcpy(dst, src);
|
||||||
|
return;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else
|
|
||||||
{
|
|
||||||
int k;
|
|
||||||
|
|
||||||
/* check for nearest whitespace back in string */
|
|
||||||
for (k = i; k > 0; k--)
|
|
||||||
{
|
|
||||||
if (string[k] != ' ' || (max_lines != 0 && lines >= max_lines))
|
|
||||||
continue;
|
|
||||||
|
|
||||||
buffer[k] = '\n';
|
|
||||||
/* set string index back to character after this one */
|
|
||||||
i = k + 1;
|
|
||||||
lines++;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (&buffer[i] - buffer == pos)
|
|
||||||
return buffer;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
buffer[i] = 0;
|
*dst = '\0';
|
||||||
|
}
|
||||||
|
|
||||||
return buffer;
|
void word_wrap_wideglyph(char *dst, size_t dst_size, const char *src, int line_width, int wideglyph_width, unsigned max_lines)
|
||||||
|
{
|
||||||
|
char *lastspace = NULL;
|
||||||
|
char *lastwideglyph = NULL;
|
||||||
|
const char *src_end = src + strlen(src);
|
||||||
|
unsigned lines = 1;
|
||||||
|
/* 'line_width' means max numbers of characters per line,
|
||||||
|
* but this metric is only meaningful when dealing with
|
||||||
|
* 'regular' glyphs that have an on-screen pixel width
|
||||||
|
* similar to that of regular Latin characters.
|
||||||
|
* When handing so-called 'wide' Unicode glyphs, it is
|
||||||
|
* necessary to consider the actual on-screen pixel width
|
||||||
|
* of each character.
|
||||||
|
* In order to do this, we create a distinction between
|
||||||
|
* regular Latin 'non-wide' glyphs and 'wide' glyphs, and
|
||||||
|
* normalise all values relative to the on-screen pixel
|
||||||
|
* width of regular Latin characters:
|
||||||
|
* - Regular 'non-wide' glyphs have a normalised width of 100
|
||||||
|
* - 'line_width' is therefore normalised to 100 * (width_in_characters)
|
||||||
|
* - 'wide' glyphs have a normalised width of
|
||||||
|
* 100 * (wide_character_pixel_width / latin_character_pixel_width)
|
||||||
|
* - When a character is detected, the position in the current
|
||||||
|
* line is incremented by the regular normalised width of 100
|
||||||
|
* - If that character is then determined to be a 'wide'
|
||||||
|
* glyph, the position in the current line is further incremented
|
||||||
|
* by the difference between the normalised 'wide' and 'non-wide'
|
||||||
|
* width values */
|
||||||
|
unsigned counter_normalized = 0;
|
||||||
|
int line_width_normalized = line_width * 100;
|
||||||
|
int additional_counter_normalized = wideglyph_width - 100;
|
||||||
|
|
||||||
|
/* Early return if src string length is less
|
||||||
|
* than line width */
|
||||||
|
if (src_end - src < line_width)
|
||||||
|
{
|
||||||
|
strlcpy(dst, src, dst_size);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
while (*src != '\0')
|
||||||
|
{
|
||||||
|
unsigned char_len;
|
||||||
|
|
||||||
|
char_len = (unsigned)(utf8skip(src, 1) - src);
|
||||||
|
counter_normalized += 100;
|
||||||
|
|
||||||
|
/* Prevent buffer overflow */
|
||||||
|
if (char_len >= dst_size)
|
||||||
|
break;
|
||||||
|
|
||||||
|
if (*src == ' ')
|
||||||
|
lastspace = dst; /* Remember the location of the whitespace */
|
||||||
|
else if (*src == '\n')
|
||||||
|
{
|
||||||
|
/* If newlines embedded in the input,
|
||||||
|
* reset the index */
|
||||||
|
lines++;
|
||||||
|
counter_normalized = 0;
|
||||||
|
|
||||||
|
/* Early return if remaining src string
|
||||||
|
* length is less than line width */
|
||||||
|
if (src_end - src <= line_width)
|
||||||
|
{
|
||||||
|
strlcpy(dst, src, dst_size);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if (char_len >= 3)
|
||||||
|
{
|
||||||
|
/* Remember the location of the first byte
|
||||||
|
* whose length as UTF-8 >= 3*/
|
||||||
|
lastwideglyph = dst;
|
||||||
|
counter_normalized += additional_counter_normalized;
|
||||||
|
}
|
||||||
|
|
||||||
|
dst_size -= char_len;
|
||||||
|
while (char_len--)
|
||||||
|
*dst++ = *src++;
|
||||||
|
|
||||||
|
if (counter_normalized >= (unsigned)line_width_normalized)
|
||||||
|
{
|
||||||
|
counter_normalized = 0;
|
||||||
|
|
||||||
|
if (max_lines != 0 && lines >= max_lines)
|
||||||
|
continue;
|
||||||
|
else if (lastwideglyph && (!lastspace || lastwideglyph > lastspace))
|
||||||
|
{
|
||||||
|
/* Insert newline character */
|
||||||
|
*lastwideglyph = '\n';
|
||||||
|
lines++;
|
||||||
|
src -= dst - lastwideglyph;
|
||||||
|
dst = lastwideglyph + 1;
|
||||||
|
lastwideglyph = NULL;
|
||||||
|
|
||||||
|
/* Early return if remaining src string
|
||||||
|
* length is less than line width */
|
||||||
|
if (src_end - src <= line_width)
|
||||||
|
{
|
||||||
|
strlcpy(dst, src, dst_size);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if (lastspace)
|
||||||
|
{
|
||||||
|
/* Replace nearest (previous) whitespace
|
||||||
|
* with newline character */
|
||||||
|
*lastspace = '\n';
|
||||||
|
lines++;
|
||||||
|
src -= dst - lastspace - 1;
|
||||||
|
dst = lastspace + 1;
|
||||||
|
lastspace = NULL;
|
||||||
|
|
||||||
|
/* Early return if remaining src string
|
||||||
|
* length is less than line width */
|
||||||
|
if (src_end - src < line_width)
|
||||||
|
{
|
||||||
|
strlcpy(dst, src, dst_size);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
*dst = '\0';
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Splits string into tokens seperated by 'delim'
|
/* Splits string into tokens seperated by 'delim'
|
||||||
@ -355,7 +495,7 @@ unsigned string_to_unsigned(const char *str)
|
|||||||
|
|
||||||
for (ptr = str; *ptr != '\0'; ptr++)
|
for (ptr = str; *ptr != '\0'; ptr++)
|
||||||
{
|
{
|
||||||
if (!isdigit(*ptr))
|
if (!ISDIGIT((unsigned char)*ptr))
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -388,7 +528,7 @@ unsigned string_hex_to_unsigned(const char *str)
|
|||||||
/* Check for valid characters */
|
/* Check for valid characters */
|
||||||
for (ptr = hex_str; *ptr != '\0'; ptr++)
|
for (ptr = hex_str; *ptr != '\0'; ptr++)
|
||||||
{
|
{
|
||||||
if (!isxdigit(*ptr))
|
if (!isxdigit((unsigned char)*ptr))
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -30,6 +30,7 @@
|
|||||||
#include <time/rtime.h>
|
#include <time/rtime.h>
|
||||||
|
|
||||||
#ifdef HAVE_THREADS
|
#ifdef HAVE_THREADS
|
||||||
|
/* TODO/FIXME - global */
|
||||||
slock_t *rtime_localtime_lock = NULL;
|
slock_t *rtime_localtime_lock = NULL;
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
@ -62,6 +62,9 @@
|
|||||||
# include <sys/dirent.h>
|
# include <sys/dirent.h>
|
||||||
# include <orbisFile.h>
|
# include <orbisFile.h>
|
||||||
# endif
|
# endif
|
||||||
|
# if defined(WIIU)
|
||||||
|
# include <malloc.h>
|
||||||
|
# endif
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#include <fcntl.h>
|
#include <fcntl.h>
|
||||||
@ -130,6 +133,13 @@
|
|||||||
#include <pspkernel.h>
|
#include <pspkernel.h>
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
#if defined(__PS3__) || defined(__PSL1GHT__)
|
||||||
|
#include <defines/ps3_defines.h>
|
||||||
|
#if defined(__PSL1GHT__)
|
||||||
|
#include <lv2/sysfs.h>
|
||||||
|
#endif
|
||||||
|
#endif
|
||||||
|
|
||||||
#if defined(VITA)
|
#if defined(VITA)
|
||||||
#define FIO_S_ISDIR SCE_S_ISDIR
|
#define FIO_S_ISDIR SCE_S_ISDIR
|
||||||
#endif
|
#endif
|
||||||
@ -148,14 +158,16 @@
|
|||||||
#endif
|
#endif
|
||||||
|
|
||||||
#if defined(_WIN32)
|
#if defined(_WIN32)
|
||||||
#if !defined(_MSC_VER) || (defined(_MSC_VER) && _MSC_VER >= 1400)
|
#if defined(_MSC_VER) && _MSC_VER >= 1400
|
||||||
#define ATLEAST_VC2005
|
#define ATLEAST_VC2005
|
||||||
#endif
|
#endif
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#include <vfs/vfs_implementation.h>
|
#include <vfs/vfs_implementation.h>
|
||||||
#include <libretro.h>
|
#include <libretro.h>
|
||||||
|
#if defined(HAVE_MMAP)
|
||||||
#include <memmap.h>
|
#include <memmap.h>
|
||||||
|
#endif
|
||||||
#include <encodings/utf.h>
|
#include <encodings/utf.h>
|
||||||
#include <compat/fopen_utf8.h>
|
#include <compat/fopen_utf8.h>
|
||||||
#include <file/file_path.h>
|
#include <file/file_path.h>
|
||||||
@ -164,7 +176,7 @@
|
|||||||
#include <vfs/vfs_implementation_cdrom.h>
|
#include <vfs/vfs_implementation_cdrom.h>
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#if (defined(_POSIX_C_SOURCE) && (_POSIX_C_SOURCE - 0) >= 200112) || (defined(__POSIX_VISIBLE) && __POSIX_VISIBLE >= 200112) || (defined(_POSIX_VERSION) && _POSIX_VERSION >= 200112) || __USE_LARGEFILE
|
#if (defined(_POSIX_C_SOURCE) && (_POSIX_C_SOURCE - 0) >= 200112) || (defined(__POSIX_VISIBLE) && __POSIX_VISIBLE >= 200112) || (defined(_POSIX_VERSION) && _POSIX_VERSION >= 200112) || __USE_LARGEFILE || (defined(_FILE_OFFSET_BITS) && _FILE_OFFSET_BITS == 64)
|
||||||
#ifndef HAVE_64BIT_OFFSETS
|
#ifndef HAVE_64BIT_OFFSETS
|
||||||
#define HAVE_64BIT_OFFSETS
|
#define HAVE_64BIT_OFFSETS
|
||||||
#endif
|
#endif
|
||||||
@ -238,7 +250,7 @@ int64_t retro_vfs_file_seek_internal(
|
|||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
if (lseek(stream->fd, offset, whence) < 0)
|
if (lseek(stream->fd, (off_t)offset, whence) < 0)
|
||||||
return -1;
|
return -1;
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
@ -433,7 +445,22 @@ libretro_vfs_implementation_file *retro_vfs_file_open_impl(
|
|||||||
*/
|
*/
|
||||||
/* TODO: this is only useful for a few platforms,
|
/* TODO: this is only useful for a few platforms,
|
||||||
* find which and add ifdef */
|
* find which and add ifdef */
|
||||||
#if !defined(PSP)
|
#if defined(_3DS)
|
||||||
|
if (stream->scheme != VFS_SCHEME_CDROM)
|
||||||
|
{
|
||||||
|
stream->buf = (char*)calloc(1, 0x10000);
|
||||||
|
if (stream->fp)
|
||||||
|
setvbuf(stream->fp, stream->buf, _IOFBF, 0x10000);
|
||||||
|
}
|
||||||
|
#elif defined(WIIU)
|
||||||
|
if (stream->scheme != VFS_SCHEME_CDROM)
|
||||||
|
{
|
||||||
|
const int bufsize = 128*1024;
|
||||||
|
stream->buf = (char*)memalign(0x40, bufsize);
|
||||||
|
if (stream->fp)
|
||||||
|
setvbuf(stream->fp, stream->buf, _IOFBF, bufsize);
|
||||||
|
}
|
||||||
|
#elif !defined(PSP)
|
||||||
if (stream->scheme != VFS_SCHEME_CDROM)
|
if (stream->scheme != VFS_SCHEME_CDROM)
|
||||||
{
|
{
|
||||||
stream->buf = (char*)calloc(1, 0x4000);
|
stream->buf = (char*)calloc(1, 0x4000);
|
||||||
@ -597,7 +624,7 @@ int64_t retro_vfs_file_truncate_impl(libretro_vfs_implementation_file *stream, i
|
|||||||
if (_chsize(_fileno(stream->fp), length) != 0)
|
if (_chsize(_fileno(stream->fp), length) != 0)
|
||||||
return -1;
|
return -1;
|
||||||
#elif !defined(VITA) && !defined(PSP) && !defined(PS2) && !defined(ORBIS) && (!defined(SWITCH) || defined(HAVE_LIBNX))
|
#elif !defined(VITA) && !defined(PSP) && !defined(PS2) && !defined(ORBIS) && (!defined(SWITCH) || defined(HAVE_LIBNX))
|
||||||
if (ftruncate(fileno(stream->fp), length) != 0)
|
if (ftruncate(fileno(stream->fp), (off_t)length) != 0)
|
||||||
return -1;
|
return -1;
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
@ -902,6 +929,19 @@ int retro_vfs_stat_impl(const char *path, int32_t *size)
|
|||||||
orbisDclose(dir_ret);
|
orbisDclose(dir_ret);
|
||||||
|
|
||||||
is_character_special = S_ISCHR(buf.st_mode);
|
is_character_special = S_ISCHR(buf.st_mode);
|
||||||
|
#elif defined(__PSL1GHT__) || defined(__PS3__)
|
||||||
|
/* Lowlevel Lv2 */
|
||||||
|
sysFSStat buf;
|
||||||
|
|
||||||
|
if (!path || !*path)
|
||||||
|
return 0;
|
||||||
|
if (sysFsStat(path, &buf) < 0)
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
if (size)
|
||||||
|
*size = (int32_t)buf.st_size;
|
||||||
|
|
||||||
|
is_dir = ((buf.st_mode & S_IFMT) == S_IFDIR);
|
||||||
#elif defined(_WIN32)
|
#elif defined(_WIN32)
|
||||||
/* Windows */
|
/* Windows */
|
||||||
DWORD file_info;
|
DWORD file_info;
|
||||||
@ -941,6 +981,40 @@ int retro_vfs_stat_impl(const char *path, int32_t *size)
|
|||||||
*size = (int32_t)buf.st_size;
|
*size = (int32_t)buf.st_size;
|
||||||
|
|
||||||
is_dir = (file_info & FILE_ATTRIBUTE_DIRECTORY);
|
is_dir = (file_info & FILE_ATTRIBUTE_DIRECTORY);
|
||||||
|
|
||||||
|
#elif defined(GEKKO)
|
||||||
|
/* On GEKKO platforms, paths cannot have
|
||||||
|
* trailing slashes - we must therefore
|
||||||
|
* remove them */
|
||||||
|
char *path_buf = NULL;
|
||||||
|
int stat_ret = -1;
|
||||||
|
struct stat stat_buf;
|
||||||
|
size_t len;
|
||||||
|
|
||||||
|
if (string_is_empty(path))
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
path_buf = strdup(path);
|
||||||
|
if (!path_buf)
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
len = strlen(path_buf);
|
||||||
|
if (len > 0)
|
||||||
|
if (path_buf[len - 1] == '/')
|
||||||
|
path_buf[len - 1] = '\0';
|
||||||
|
|
||||||
|
stat_ret = stat(path_buf, &stat_buf);
|
||||||
|
free(path_buf);
|
||||||
|
|
||||||
|
if (stat_ret < 0)
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
if (size)
|
||||||
|
*size = (int32_t)stat_buf.st_size;
|
||||||
|
|
||||||
|
is_dir = S_ISDIR(stat_buf.st_mode);
|
||||||
|
is_character_special = S_ISCHR(stat_buf.st_mode);
|
||||||
|
|
||||||
#else
|
#else
|
||||||
/* Every other platform */
|
/* Every other platform */
|
||||||
struct stat buf;
|
struct stat buf;
|
||||||
@ -990,6 +1064,28 @@ int retro_vfs_mkdir_impl(const char *dir)
|
|||||||
int ret = orbisMkdir(dir, 0755);
|
int ret = orbisMkdir(dir, 0755);
|
||||||
#elif defined(__QNX__)
|
#elif defined(__QNX__)
|
||||||
int ret = mkdir(dir, 0777);
|
int ret = mkdir(dir, 0777);
|
||||||
|
#elif defined(GEKKO)
|
||||||
|
/* On GEKKO platforms, mkdir() fails if
|
||||||
|
* the path has a trailing slash. We must
|
||||||
|
* therefore remove it. */
|
||||||
|
int ret = -1;
|
||||||
|
if (!string_is_empty(dir))
|
||||||
|
{
|
||||||
|
char *dir_buf = strdup(dir);
|
||||||
|
|
||||||
|
if (dir_buf)
|
||||||
|
{
|
||||||
|
size_t len = strlen(dir_buf);
|
||||||
|
|
||||||
|
if (len > 0)
|
||||||
|
if (dir_buf[len - 1] == '/')
|
||||||
|
dir_buf[len - 1] = '\0';
|
||||||
|
|
||||||
|
ret = mkdir(dir_buf, 0750);
|
||||||
|
|
||||||
|
free(dir_buf);
|
||||||
|
}
|
||||||
|
}
|
||||||
#else
|
#else
|
||||||
int ret = mkdir(dir, 0750);
|
int ret = mkdir(dir, 0750);
|
||||||
#endif
|
#endif
|
||||||
@ -1018,6 +1114,10 @@ struct libretro_vfs_implementation_dir
|
|||||||
#elif defined(VITA) || defined(PSP)
|
#elif defined(VITA) || defined(PSP)
|
||||||
SceUID directory;
|
SceUID directory;
|
||||||
SceIoDirent entry;
|
SceIoDirent entry;
|
||||||
|
#elif defined(__PSL1GHT__) || defined(__PS3__)
|
||||||
|
int error;
|
||||||
|
int directory;
|
||||||
|
sysFSDirent entry;
|
||||||
#elif defined(ORBIS)
|
#elif defined(ORBIS)
|
||||||
int directory;
|
int directory;
|
||||||
struct dirent entry;
|
struct dirent entry;
|
||||||
@ -1033,6 +1133,8 @@ static bool dirent_check_error(libretro_vfs_implementation_dir *rdir)
|
|||||||
return (rdir->directory == INVALID_HANDLE_VALUE);
|
return (rdir->directory == INVALID_HANDLE_VALUE);
|
||||||
#elif defined(VITA) || defined(PSP) || defined(ORBIS)
|
#elif defined(VITA) || defined(PSP) || defined(ORBIS)
|
||||||
return (rdir->directory < 0);
|
return (rdir->directory < 0);
|
||||||
|
#elif defined(__PSL1GHT__) || defined(__PS3__)
|
||||||
|
return (rdir->error != FS_SUCCEEDED);
|
||||||
#else
|
#else
|
||||||
return !(rdir->directory);
|
return !(rdir->directory);
|
||||||
#endif
|
#endif
|
||||||
@ -1096,6 +1198,8 @@ libretro_vfs_implementation_dir *retro_vfs_opendir_impl(
|
|||||||
#elif defined(_3DS)
|
#elif defined(_3DS)
|
||||||
rdir->directory = !string_is_empty(name) ? opendir(name) : NULL;
|
rdir->directory = !string_is_empty(name) ? opendir(name) : NULL;
|
||||||
rdir->entry = NULL;
|
rdir->entry = NULL;
|
||||||
|
#elif defined(__PSL1GHT__) || defined(__PS3__)
|
||||||
|
rdir->error = sysFsOpendir(name, &rdir->directory);
|
||||||
#elif defined(ORBIS)
|
#elif defined(ORBIS)
|
||||||
rdir->directory = orbisDopen(name);
|
rdir->directory = orbisDopen(name);
|
||||||
#else
|
#else
|
||||||
@ -1131,6 +1235,10 @@ bool retro_vfs_readdir_impl(libretro_vfs_implementation_dir *rdir)
|
|||||||
return (rdir->directory != INVALID_HANDLE_VALUE);
|
return (rdir->directory != INVALID_HANDLE_VALUE);
|
||||||
#elif defined(VITA) || defined(PSP)
|
#elif defined(VITA) || defined(PSP)
|
||||||
return (sceIoDread(rdir->directory, &rdir->entry) > 0);
|
return (sceIoDread(rdir->directory, &rdir->entry) > 0);
|
||||||
|
#elif defined(__PSL1GHT__) || defined(__PS3__)
|
||||||
|
uint64_t nread;
|
||||||
|
rdir->error = sysFsReaddir(rdir->directory, &rdir->entry, &nread);
|
||||||
|
return (nread != 0);
|
||||||
#elif defined(ORBIS)
|
#elif defined(ORBIS)
|
||||||
return (orbisDread(rdir->directory, &rdir->entry) > 0);
|
return (orbisDread(rdir->directory, &rdir->entry) > 0);
|
||||||
#else
|
#else
|
||||||
@ -1151,7 +1259,7 @@ const char *retro_vfs_dirent_get_name_impl(libretro_vfs_implementation_dir *rdir
|
|||||||
if (name)
|
if (name)
|
||||||
free(name);
|
free(name);
|
||||||
return (char*)rdir->entry.cFileName;
|
return (char*)rdir->entry.cFileName;
|
||||||
#elif defined(VITA) || defined(PSP) || defined(ORBIS)
|
#elif defined(VITA) || defined(PSP) || defined(ORBIS) || defined(__PSL1GHT__) || defined(__PS3__)
|
||||||
return rdir->entry.d_name;
|
return rdir->entry.d_name;
|
||||||
#else
|
#else
|
||||||
if (!rdir || !rdir->entry)
|
if (!rdir || !rdir->entry)
|
||||||
@ -1172,6 +1280,9 @@ bool retro_vfs_dirent_is_dir_impl(libretro_vfs_implementation_dir *rdir)
|
|||||||
#elif defined(VITA)
|
#elif defined(VITA)
|
||||||
return SCE_S_ISDIR(entry->d_stat.st_mode);
|
return SCE_S_ISDIR(entry->d_stat.st_mode);
|
||||||
#endif
|
#endif
|
||||||
|
#elif defined(__PSL1GHT__) || defined(__PS3__)
|
||||||
|
sysFSDirent *entry = (sysFSDirent*)&rdir->entry;
|
||||||
|
return (entry->d_type == FS_TYPE_DIR);
|
||||||
#elif defined(ORBIS)
|
#elif defined(ORBIS)
|
||||||
const struct dirent *entry = &rdir->entry;
|
const struct dirent *entry = &rdir->entry;
|
||||||
if (entry->d_type == DT_DIR)
|
if (entry->d_type == DT_DIR)
|
||||||
@ -1208,6 +1319,8 @@ int retro_vfs_closedir_impl(libretro_vfs_implementation_dir *rdir)
|
|||||||
FindClose(rdir->directory);
|
FindClose(rdir->directory);
|
||||||
#elif defined(VITA) || defined(PSP)
|
#elif defined(VITA) || defined(PSP)
|
||||||
sceIoDclose(rdir->directory);
|
sceIoDclose(rdir->directory);
|
||||||
|
#elif defined(__PSL1GHT__) || defined(__PS3__)
|
||||||
|
rdir->error = sysFsClosedir(rdir->directory);
|
||||||
#elif defined(ORBIS)
|
#elif defined(ORBIS)
|
||||||
orbisDclose(rdir->directory);
|
orbisDclose(rdir->directory);
|
||||||
#else
|
#else
|
||||||
|
@ -25,6 +25,7 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
#include "blipper.h"
|
#include "blipper.h"
|
||||||
|
#include "gambatte_log.h"
|
||||||
|
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
@ -71,7 +72,9 @@ void blipper_free(blipper_t *blip)
|
|||||||
if (blip)
|
if (blip)
|
||||||
{
|
{
|
||||||
#if BLIPPER_LOG_PERFORMANCE
|
#if BLIPPER_LOG_PERFORMANCE
|
||||||
fprintf(stderr, "[blipper]: Processed %lu samples, using %.6f seconds blipping and %.6f seconds integrating.\n", blip->total_samples, blip->total_time, blip->integrator_time);
|
gambatte_log(RETRO_LOG_INFO,
|
||||||
|
"<blipper> Processed %lu samples, using %.6f seconds blipping and %.6f seconds integrating.\n",
|
||||||
|
blip->total_samples, blip->total_time, blip->integrator_time);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
if (blip->owns_filter)
|
if (blip->owns_filter)
|
||||||
@ -312,13 +315,13 @@ blipper_t *blipper_new(unsigned taps, double cutoff, double beta,
|
|||||||
/* Sanity check. Not strictly required to be supported in C. */
|
/* Sanity check. Not strictly required to be supported in C. */
|
||||||
if ((-3 >> 2) != -1)
|
if ((-3 >> 2) != -1)
|
||||||
{
|
{
|
||||||
fprintf(stderr, "Integer right shift not supported.\n");
|
gambatte_log(RETRO_LOG_ERROR, "<blipper> Integer right shift not supported.\n");
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
if ((decimation & (decimation - 1)) != 0)
|
if ((decimation & (decimation - 1)) != 0)
|
||||||
{
|
{
|
||||||
fprintf(stderr, "[blipper]: Decimation factor must be POT.\n");
|
gambatte_log(RETRO_LOG_ERROR, "<blipper> Decimation factor must be POT.\n");
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
32
libgambatte/libretro/gambatte_log.c
Normal file
32
libgambatte/libretro/gambatte_log.c
Normal file
@ -0,0 +1,32 @@
|
|||||||
|
#include <stdio.h>
|
||||||
|
#include <stdarg.h>
|
||||||
|
#include <string/stdstring.h>
|
||||||
|
#include "gambatte_log.h"
|
||||||
|
|
||||||
|
static retro_log_printf_t gambatte_log_cb = NULL;
|
||||||
|
|
||||||
|
void gambatte_log_set_cb(retro_log_printf_t log_cb)
|
||||||
|
{
|
||||||
|
gambatte_log_cb = log_cb;
|
||||||
|
}
|
||||||
|
|
||||||
|
void gambatte_log(enum retro_log_level level, const char *format, ...)
|
||||||
|
{
|
||||||
|
char msg[512];
|
||||||
|
va_list ap;
|
||||||
|
|
||||||
|
msg[0] = '\0';
|
||||||
|
|
||||||
|
if (string_is_empty(format))
|
||||||
|
return;
|
||||||
|
|
||||||
|
va_start(ap, format);
|
||||||
|
vsprintf(msg, format, ap);
|
||||||
|
va_end(ap);
|
||||||
|
|
||||||
|
if (gambatte_log_cb)
|
||||||
|
gambatte_log_cb(level, "[Gambatte] %s", msg);
|
||||||
|
else
|
||||||
|
fprintf((level == RETRO_LOG_ERROR) ? stderr : stdout,
|
||||||
|
"[Gambatte] %s", msg);
|
||||||
|
}
|
17
libgambatte/libretro/gambatte_log.h
Normal file
17
libgambatte/libretro/gambatte_log.h
Normal file
@ -0,0 +1,17 @@
|
|||||||
|
#ifndef _GAMBATTE_LOG_H
|
||||||
|
#define _GAMBATTE_LOG_H
|
||||||
|
|
||||||
|
#include <libretro.h>
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
extern "C" {
|
||||||
|
#endif
|
||||||
|
|
||||||
|
void gambatte_log_set_cb(retro_log_printf_t log_cb);
|
||||||
|
void gambatte_log(enum retro_log_level level, const char *format, ...);
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#endif
|
@ -2,6 +2,7 @@
|
|||||||
|
|
||||||
#include <libretro.h>
|
#include <libretro.h>
|
||||||
#include <libretro_core_options.h>
|
#include <libretro_core_options.h>
|
||||||
|
#include "gambatte_log.h"
|
||||||
#include "blipper.h"
|
#include "blipper.h"
|
||||||
#include "gambatte.h"
|
#include "gambatte.h"
|
||||||
#include "gbcpalettes.h"
|
#include "gbcpalettes.h"
|
||||||
@ -15,6 +16,16 @@
|
|||||||
#undef __STRICT_ANSI__
|
#undef __STRICT_ANSI__
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
#ifndef PATH_MAX_LENGTH
|
||||||
|
#if defined(_XBOX1) || defined(_3DS) || defined(PSP) || defined(PS2) || defined(GEKKO)|| defined(WIIU) || defined(ORBIS) || defined(__PSL1GHT__) || defined(__PS3__)
|
||||||
|
#define PATH_MAX_LENGTH 512
|
||||||
|
#else
|
||||||
|
#define PATH_MAX_LENGTH 4096
|
||||||
|
#endif
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#include <string/stdstring.h>
|
||||||
|
#include <file/file_path.h>
|
||||||
#include <streams/file_stream.h>
|
#include <streams/file_stream.h>
|
||||||
|
|
||||||
#include <cassert>
|
#include <cassert>
|
||||||
@ -32,7 +43,6 @@ extern "C" void* linearMemAlign(size_t size, size_t alignment);
|
|||||||
extern "C" void linearFree(void* mem);
|
extern "C" void linearFree(void* mem);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
retro_log_printf_t log_cb;
|
|
||||||
static retro_video_refresh_t video_cb;
|
static retro_video_refresh_t video_cb;
|
||||||
static retro_input_poll_t input_poll_cb;
|
static retro_input_poll_t input_poll_cb;
|
||||||
static retro_input_state_t input_state_cb;
|
static retro_input_state_t input_state_cb;
|
||||||
@ -709,7 +719,7 @@ static bool update_option_visibility(void)
|
|||||||
#endif
|
#endif
|
||||||
|
|
||||||
/* Fast forward override */
|
/* Fast forward override */
|
||||||
void set_fastforward_override(bool fastforward)
|
static void set_fastforward_override(bool fastforward)
|
||||||
{
|
{
|
||||||
struct retro_fastforwarding_override ff_override;
|
struct retro_fastforwarding_override ff_override;
|
||||||
|
|
||||||
@ -733,75 +743,90 @@ void set_fastforward_override(bool fastforward)
|
|||||||
environ_cb(RETRO_ENVIRONMENT_SET_FASTFORWARDING_OVERRIDE, &ff_override);
|
environ_cb(RETRO_ENVIRONMENT_SET_FASTFORWARDING_OVERRIDE, &ff_override);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool file_present_in_system(std::string fname)
|
static bool file_present_in_system(const char *fname)
|
||||||
{
|
{
|
||||||
const char *systemdirtmp = NULL;
|
const char *system_dir = NULL;
|
||||||
bool worked = environ_cb(RETRO_ENVIRONMENT_GET_SYSTEM_DIRECTORY, &systemdirtmp);
|
char full_path[PATH_MAX_LENGTH];
|
||||||
if (!worked)
|
|
||||||
|
full_path[0] = '\0';
|
||||||
|
|
||||||
|
if (string_is_empty(fname))
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
std::string fullpath = systemdirtmp;
|
/* Get system directory */
|
||||||
fullpath += "/";
|
if (!environ_cb(RETRO_ENVIRONMENT_GET_SYSTEM_DIRECTORY, &system_dir) ||
|
||||||
fullpath += fname;
|
!system_dir)
|
||||||
|
|
||||||
RFILE *fp = filestream_open(fullpath.c_str(), RETRO_VFS_FILE_ACCESS_READ,
|
|
||||||
RETRO_VFS_FILE_ACCESS_HINT_NONE);
|
|
||||||
|
|
||||||
if (fp)
|
|
||||||
{
|
{
|
||||||
filestream_close(fp);
|
gambatte_log(RETRO_LOG_WARN,
|
||||||
return true;
|
"No system directory defined, unable to look for '%s'.\n", fname);
|
||||||
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
return false;
|
fill_pathname_join(full_path, system_dir,
|
||||||
|
fname, sizeof(full_path));
|
||||||
|
|
||||||
|
return path_is_valid(full_path);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool get_bootloader_from_file(void* userdata, bool isgbc, uint8_t* data, uint32_t buf_size)
|
static bool get_bootloader_from_file(void* userdata, bool isgbc, uint8_t* data, uint32_t buf_size)
|
||||||
{
|
{
|
||||||
std::string path;
|
const char *system_dir = NULL;
|
||||||
unsigned int size;
|
const char *bios_name = NULL;
|
||||||
RFILE *fp = NULL;
|
RFILE *bios_file = NULL;
|
||||||
int64_t n = 0;
|
int64_t bios_size = 0;
|
||||||
bool worked = false;
|
int64_t bytes_read = 0;
|
||||||
const char *systemdirtmp = NULL;
|
char bios_path[PATH_MAX_LENGTH];
|
||||||
|
|
||||||
|
bios_path[0] = '\0';
|
||||||
|
|
||||||
if (!use_official_bootloader)
|
if (!use_official_bootloader)
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
// get path
|
/* Get system directory */
|
||||||
worked = environ_cb(RETRO_ENVIRONMENT_GET_SYSTEM_DIRECTORY, &systemdirtmp);
|
if (!environ_cb(RETRO_ENVIRONMENT_GET_SYSTEM_DIRECTORY, &system_dir) ||
|
||||||
if (!worked)
|
!system_dir)
|
||||||
|
{
|
||||||
|
gambatte_log(RETRO_LOG_WARN,
|
||||||
|
"No system directory defined, unable to look for bootloader.\n");
|
||||||
return false;
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
path = systemdirtmp;
|
/* Get BIOS type */
|
||||||
path += "/"; //retroarch/libretro does not add a slash at the end of directory names
|
|
||||||
|
|
||||||
if (isgbc)
|
if (isgbc)
|
||||||
{
|
{
|
||||||
path += "gbc_bios.bin";
|
bios_name = "gbc_bios.bin";
|
||||||
size = 0x900;
|
bios_size = 0x900;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
path += "gb_bios.bin";
|
bios_name = "gb_bios.bin";
|
||||||
size = 0x100;
|
bios_size = 0x100;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (size > buf_size)
|
if (bios_size > buf_size)
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
// open file
|
/* Get BIOS path */
|
||||||
fp = filestream_open(path.c_str(), RETRO_VFS_FILE_ACCESS_READ,
|
fill_pathname_join(bios_path, system_dir,
|
||||||
|
bios_name, sizeof(bios_path));
|
||||||
|
|
||||||
|
/* Read BIOS file */
|
||||||
|
bios_file = filestream_open(bios_path,
|
||||||
|
RETRO_VFS_FILE_ACCESS_READ,
|
||||||
RETRO_VFS_FILE_ACCESS_HINT_NONE);
|
RETRO_VFS_FILE_ACCESS_HINT_NONE);
|
||||||
|
|
||||||
if (!fp)
|
if (!bios_file)
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
n = filestream_read(fp, data, size);
|
bytes_read = filestream_read(bios_file,
|
||||||
filestream_close(fp);
|
data, bios_size);
|
||||||
|
filestream_close(bios_file);
|
||||||
|
|
||||||
if (n != size)
|
if (bytes_read != bios_size)
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
|
gambatte_log(RETRO_LOG_INFO, "Read bootloader: %s\n", bios_path);
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -962,16 +987,14 @@ static void check_system_specs(void)
|
|||||||
environ_cb(RETRO_ENVIRONMENT_SET_PERFORMANCE_LEVEL, &level);
|
environ_cb(RETRO_ENVIRONMENT_SET_PERFORMANCE_LEVEL, &level);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void log_null(enum retro_log_level level, const char *fmt, ...) {}
|
|
||||||
|
|
||||||
void retro_init(void)
|
void retro_init(void)
|
||||||
{
|
{
|
||||||
struct retro_log_callback log;
|
struct retro_log_callback log;
|
||||||
|
|
||||||
if (environ_cb(RETRO_ENVIRONMENT_GET_LOG_INTERFACE, &log))
|
if (environ_cb(RETRO_ENVIRONMENT_GET_LOG_INTERFACE, &log))
|
||||||
log_cb = log.log;
|
gambatte_log_set_cb(log.log);
|
||||||
else
|
else
|
||||||
log_cb = log_null;
|
gambatte_log_set_cb(NULL);
|
||||||
|
|
||||||
// Using uint_least32_t in an audio interface expecting you to cast to short*? :( Weird stuff.
|
// Using uint_least32_t in an audio interface expecting you to cast to short*? :( Weird stuff.
|
||||||
assert(sizeof(gambatte::uint_least32_t) == sizeof(uint32_t));
|
assert(sizeof(gambatte::uint_least32_t) == sizeof(uint32_t));
|
||||||
@ -1209,28 +1232,6 @@ void retro_cheat_set(unsigned index, bool enabled, const char *code)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
static std::string basename(std::string filename)
|
|
||||||
{
|
|
||||||
// Remove directory if present.
|
|
||||||
// Do this before extension removal incase directory has a period character.
|
|
||||||
const size_t last_slash_idx = filename.find_last_of("\\/");
|
|
||||||
if (std::string::npos != last_slash_idx)
|
|
||||||
filename.erase(0, last_slash_idx + 1);
|
|
||||||
|
|
||||||
// Remove extension if present.
|
|
||||||
const size_t period_idx = filename.rfind('.');
|
|
||||||
if (std::string::npos != period_idx)
|
|
||||||
filename.erase(period_idx);
|
|
||||||
|
|
||||||
return filename;
|
|
||||||
}
|
|
||||||
|
|
||||||
static bool startswith(const std::string s1, const std::string prefix)
|
|
||||||
{
|
|
||||||
return s1.compare(0, prefix.length(), prefix) == 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
enum gb_colorization_enable_type
|
enum gb_colorization_enable_type
|
||||||
{
|
{
|
||||||
GB_COLORIZATION_DISABLED = 0,
|
GB_COLORIZATION_DISABLED = 0,
|
||||||
@ -1248,110 +1249,174 @@ static char internal_game_name[17];
|
|||||||
|
|
||||||
static void load_custom_palette(void)
|
static void load_custom_palette(void)
|
||||||
{
|
{
|
||||||
unsigned rgb32 = 0;
|
const char *system_dir = NULL;
|
||||||
|
const char *rom_file = NULL;
|
||||||
|
char *rom_name = NULL;
|
||||||
|
RFILE *palette_file = NULL;
|
||||||
|
unsigned line_index = 0;
|
||||||
|
bool path_valid = false;
|
||||||
|
unsigned rgb32 = 0;
|
||||||
|
char palette_path[PATH_MAX_LENGTH];
|
||||||
|
|
||||||
const char *system_directory_c = NULL;
|
palette_path[0] = '\0';
|
||||||
environ_cb(RETRO_ENVIRONMENT_GET_SYSTEM_DIRECTORY, &system_directory_c);
|
|
||||||
if (!system_directory_c)
|
/* Get system directory */
|
||||||
|
if (!environ_cb(RETRO_ENVIRONMENT_GET_SYSTEM_DIRECTORY, &system_dir) ||
|
||||||
|
!system_dir)
|
||||||
{
|
{
|
||||||
log_cb(RETRO_LOG_WARN, "[Gambatte]: no system directory defined, unable to look for custom palettes.\n");
|
gambatte_log(RETRO_LOG_WARN,
|
||||||
|
"No system directory defined, unable to look for custom palettes.\n");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
std::string system_directory(system_directory_c);
|
/* Look for palette named after ROM file */
|
||||||
std::string custom_palette_path = system_directory + "/palettes/" + basename(rom_path) + ".pal";
|
rom_file = path_basename(rom_path.c_str());
|
||||||
std::ifstream palette_file(custom_palette_path.c_str()); // try to open the palette file in read-only mode
|
if (!string_is_empty(rom_file))
|
||||||
|
|
||||||
if (!palette_file.is_open())
|
|
||||||
{
|
{
|
||||||
// try again with the internal game name from the ROM header
|
size_t len = (strlen(rom_file) + 1) * sizeof(char);
|
||||||
custom_palette_path = system_directory + "/palettes/" + std::string(internal_game_name) + ".pal";
|
rom_name = (char*)malloc(len);
|
||||||
palette_file.open(custom_palette_path.c_str());
|
strlcpy(rom_name, rom_file, len);
|
||||||
|
path_remove_extension(rom_name);
|
||||||
|
if (!string_is_empty(rom_name))
|
||||||
|
{
|
||||||
|
fill_pathname_join_special_ext(palette_path,
|
||||||
|
system_dir, "palettes", rom_name, ".pal",
|
||||||
|
sizeof(palette_path));
|
||||||
|
path_valid = path_is_valid(palette_path);
|
||||||
|
}
|
||||||
|
free(rom_name);
|
||||||
|
rom_name = NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!palette_file.is_open())// && !findGbcTitlePal(internal_game_name))
|
if (!path_valid)
|
||||||
{
|
{
|
||||||
// try again with default.pal
|
/* Look for palette named after the internal game
|
||||||
//- removed last line if colorization is enabled
|
* name in the ROM header */
|
||||||
custom_palette_path = system_directory + "/palettes/" + "default.pal";
|
fill_pathname_join_special_ext(palette_path,
|
||||||
palette_file.open(custom_palette_path.c_str());
|
system_dir, "palettes", internal_game_name, ".pal",
|
||||||
|
sizeof(palette_path));
|
||||||
|
path_valid = path_is_valid(palette_path);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!palette_file.is_open())
|
if (!path_valid)
|
||||||
return; // unable to find any custom palette file
|
|
||||||
|
|
||||||
#if 0
|
|
||||||
fprintf(RETRO_LOG_INFO, "[Gambatte]: using custom palette %s.\n", custom_palette_path.c_str());
|
|
||||||
#endif
|
|
||||||
unsigned line_count = 0;
|
|
||||||
for (std::string line; getline(palette_file, line); ) // iterate over file lines
|
|
||||||
{
|
{
|
||||||
line_count++;
|
/* Look for default custom palette file (default.pal) */
|
||||||
|
fill_pathname_join_special_ext(palette_path,
|
||||||
|
system_dir, "palettes", "default", ".pal",
|
||||||
|
sizeof(palette_path));
|
||||||
|
path_valid = path_is_valid(palette_path);
|
||||||
|
}
|
||||||
|
|
||||||
if (line[0]=='[') // skip ini sections
|
if (!path_valid)
|
||||||
continue;
|
return; /* Unable to find any custom palette file */
|
||||||
|
|
||||||
if (line[0]==';') // skip ini comments
|
palette_file = filestream_open(palette_path,
|
||||||
continue;
|
RETRO_VFS_FILE_ACCESS_READ,
|
||||||
|
RETRO_VFS_FILE_ACCESS_HINT_NONE);
|
||||||
|
|
||||||
if (line[0]=='\n') // skip empty lines
|
if (!palette_file)
|
||||||
continue;
|
{
|
||||||
|
gambatte_log(RETRO_LOG_WARN,
|
||||||
|
"Failed to open custom palette: %s\n", palette_path);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
if (line.find("=") == std::string::npos)
|
gambatte_log(RETRO_LOG_INFO, "Using custom palette: %s\n", palette_path);
|
||||||
|
|
||||||
|
/* Iterate over palette file lines */
|
||||||
|
while (!filestream_eof(palette_file))
|
||||||
|
{
|
||||||
|
char *line = filestream_getline(palette_file);
|
||||||
|
const char *value_str = NULL;
|
||||||
|
|
||||||
|
if (!line)
|
||||||
|
break;
|
||||||
|
|
||||||
|
if (string_is_empty(line) || /* Skip empty lines */
|
||||||
|
(*line == '[') || /* Skip ini sections */
|
||||||
|
(*line == ';')) /* Skip ini comments */
|
||||||
|
goto palette_line_end;
|
||||||
|
|
||||||
|
/* Supposed to be a typo here... */
|
||||||
|
if (string_starts_with(line, "slectedScheme="))
|
||||||
|
goto palette_line_end;
|
||||||
|
|
||||||
|
/* Get substring after first '=' character */
|
||||||
|
value_str = strchr(line, '=');
|
||||||
|
if (!value_str ||
|
||||||
|
string_is_empty(++value_str))
|
||||||
{
|
{
|
||||||
log_cb(RETRO_LOG_WARN, "[Gambatte]: error in %s, line %d (color left as default).\n", custom_palette_path.c_str(), line_count);
|
gambatte_log(RETRO_LOG_WARN,
|
||||||
continue; // current line does not contain a palette color definition, so go to next line
|
"Error in %s, line %u (color left as default)\n",
|
||||||
|
palette_path, line_index);
|
||||||
|
goto palette_line_end;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Supposed to be a typo here.
|
/* Extract colour value */
|
||||||
if (startswith(line, "slectedScheme="))
|
rgb32 = string_to_unsigned(value_str);
|
||||||
continue;
|
if (rgb32 == 0)
|
||||||
|
|
||||||
std::string line_value = line.substr(line.find("=") + 1); // extract the color value string
|
|
||||||
std::stringstream ss(line_value); // convert the color value to int
|
|
||||||
ss >> rgb32;
|
|
||||||
if (!ss)
|
|
||||||
{
|
{
|
||||||
log_cb(RETRO_LOG_WARN, "[Gambatte]: unable to read palette color in %s, line %d (color left as default).\n",
|
/* string_to_unsigned() will return 0 if
|
||||||
custom_palette_path.c_str(), line_count);
|
* string is invalid, so perform a manual
|
||||||
continue;
|
* validity check... */
|
||||||
|
for (; *value_str != '\0'; value_str++)
|
||||||
|
{
|
||||||
|
if (*value_str != '0')
|
||||||
|
{
|
||||||
|
gambatte_log(RETRO_LOG_WARN,
|
||||||
|
"Unable to read palette color in %s, line %u (color left as default)\n",
|
||||||
|
palette_path, line_index);
|
||||||
|
goto palette_line_end;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#ifdef VIDEO_RGB565
|
#ifdef VIDEO_RGB565
|
||||||
rgb32=(rgb32&0x0000F8)>>3 |//blue
|
rgb32 = (rgb32 & 0x0000F8) >> 3 | /* blue */
|
||||||
(rgb32&0x00FC00)>>5 |//green
|
(rgb32 & 0x00FC00) >> 5 | /* green */
|
||||||
(rgb32&0xF80000)>>8;//red
|
(rgb32 & 0xF80000) >> 8; /* red */
|
||||||
#elif defined(VIDEO_ABGR1555)
|
#elif defined(VIDEO_ABGR1555)
|
||||||
rgb32=(rgb32&0x0000F8)<<7 |//blue
|
rgb32 = (rgb32 & 0x0000F8) << 7 | /* blue */
|
||||||
(rgb32&0xF800)>>6 |//green
|
(rgb32 & 0xF800) >> 6 | /* green */
|
||||||
(rgb32&0xF80000)>>19;//red
|
(rgb32 & 0xF80000) >> 19; /* red */
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
if (startswith(line, "Background0="))
|
if ( string_starts_with(line, "Background0="))
|
||||||
gb.setDmgPaletteColor(0, 0, rgb32);
|
gb.setDmgPaletteColor(0, 0, rgb32);
|
||||||
else if (startswith(line, "Background1="))
|
else if (string_starts_with(line, "Background1="))
|
||||||
gb.setDmgPaletteColor(0, 1, rgb32);
|
gb.setDmgPaletteColor(0, 1, rgb32);
|
||||||
else if (startswith(line, "Background2="))
|
else if (string_starts_with(line, "Background2="))
|
||||||
gb.setDmgPaletteColor(0, 2, rgb32);
|
gb.setDmgPaletteColor(0, 2, rgb32);
|
||||||
else if (startswith(line, "Background3="))
|
else if (string_starts_with(line, "Background3="))
|
||||||
gb.setDmgPaletteColor(0, 3, rgb32);
|
gb.setDmgPaletteColor(0, 3, rgb32);
|
||||||
else if (startswith(line, "Sprite%2010="))
|
else if (string_starts_with(line, "Sprite%2010="))
|
||||||
gb.setDmgPaletteColor(1, 0, rgb32);
|
gb.setDmgPaletteColor(1, 0, rgb32);
|
||||||
else if (startswith(line, "Sprite%2011="))
|
else if (string_starts_with(line, "Sprite%2011="))
|
||||||
gb.setDmgPaletteColor(1, 1, rgb32);
|
gb.setDmgPaletteColor(1, 1, rgb32);
|
||||||
else if (startswith(line, "Sprite%2012="))
|
else if (string_starts_with(line, "Sprite%2012="))
|
||||||
gb.setDmgPaletteColor(1, 2, rgb32);
|
gb.setDmgPaletteColor(1, 2, rgb32);
|
||||||
else if (startswith(line, "Sprite%2013="))
|
else if (string_starts_with(line, "Sprite%2013="))
|
||||||
gb.setDmgPaletteColor(1, 3, rgb32);
|
gb.setDmgPaletteColor(1, 3, rgb32);
|
||||||
else if (startswith(line, "Sprite%2020="))
|
else if (string_starts_with(line, "Sprite%2020="))
|
||||||
gb.setDmgPaletteColor(2, 0, rgb32);
|
gb.setDmgPaletteColor(2, 0, rgb32);
|
||||||
else if (startswith(line, "Sprite%2021="))
|
else if (string_starts_with(line, "Sprite%2021="))
|
||||||
gb.setDmgPaletteColor(2, 1, rgb32);
|
gb.setDmgPaletteColor(2, 1, rgb32);
|
||||||
else if (startswith(line, "Sprite%2022="))
|
else if (string_starts_with(line, "Sprite%2022="))
|
||||||
gb.setDmgPaletteColor(2, 2, rgb32);
|
gb.setDmgPaletteColor(2, 2, rgb32);
|
||||||
else if (startswith(line, "Sprite%2023="))
|
else if (string_starts_with(line, "Sprite%2023="))
|
||||||
gb.setDmgPaletteColor(2, 3, rgb32);
|
gb.setDmgPaletteColor(2, 3, rgb32);
|
||||||
else log_cb(RETRO_LOG_WARN, "[Gambatte]: error in %s, line %d (color left as default).\n", custom_palette_path.c_str(), line_count);
|
else
|
||||||
} // endfor
|
gambatte_log(RETRO_LOG_WARN,
|
||||||
|
"Error in %s, line %u (color left as default)\n",
|
||||||
|
palette_path, line_index);
|
||||||
|
|
||||||
|
palette_line_end:
|
||||||
|
line_index++;
|
||||||
|
free(line);
|
||||||
|
line = NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
filestream_close(palette_file);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void find_internal_palette(const unsigned short **palette, bool *is_gbc)
|
static void find_internal_palette(const unsigned short **palette, bool *is_gbc)
|
||||||
@ -1733,14 +1798,14 @@ bool retro_load_game(const struct retro_game_info *info)
|
|||||||
environ_cb(RETRO_ENVIRONMENT_GET_CAN_DUPE, &can_dupe);
|
environ_cb(RETRO_ENVIRONMENT_GET_CAN_DUPE, &can_dupe);
|
||||||
if (!can_dupe)
|
if (!can_dupe)
|
||||||
{
|
{
|
||||||
log_cb(RETRO_LOG_ERROR, "[Gambatte]: Cannot dupe frames!\n");
|
gambatte_log(RETRO_LOG_ERROR, "Cannot dupe frames!\n");
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (environ_cb(RETRO_ENVIRONMENT_GET_RUMBLE_INTERFACE, &rumble))
|
if (environ_cb(RETRO_ENVIRONMENT_GET_RUMBLE_INTERFACE, &rumble))
|
||||||
log_cb(RETRO_LOG_INFO, "Rumble environment supported.\n");
|
gambatte_log(RETRO_LOG_INFO, "Rumble environment supported.\n");
|
||||||
else
|
else
|
||||||
log_cb(RETRO_LOG_INFO, "Rumble environment not supported.\n");
|
gambatte_log(RETRO_LOG_INFO, "Rumble environment not supported.\n");
|
||||||
|
|
||||||
struct retro_input_descriptor desc[] = {
|
struct retro_input_descriptor desc[] = {
|
||||||
{ 0, RETRO_DEVICE_JOYPAD, 0, RETRO_DEVICE_ID_JOYPAD_LEFT, "D-Pad Left" },
|
{ 0, RETRO_DEVICE_JOYPAD, 0, RETRO_DEVICE_ID_JOYPAD_LEFT, "D-Pad Left" },
|
||||||
@ -1780,14 +1845,14 @@ bool retro_load_game(const struct retro_game_info *info)
|
|||||||
enum retro_pixel_format fmt = RETRO_PIXEL_FORMAT_RGB565;
|
enum retro_pixel_format fmt = RETRO_PIXEL_FORMAT_RGB565;
|
||||||
if (!environ_cb(RETRO_ENVIRONMENT_SET_PIXEL_FORMAT, &fmt))
|
if (!environ_cb(RETRO_ENVIRONMENT_SET_PIXEL_FORMAT, &fmt))
|
||||||
{
|
{
|
||||||
log_cb(RETRO_LOG_ERROR, "[Gambatte]: RGB565 is not supported.\n");
|
gambatte_log(RETRO_LOG_ERROR, "RGB565 is not supported.\n");
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
#else
|
#else
|
||||||
enum retro_pixel_format fmt = RETRO_PIXEL_FORMAT_XRGB8888;
|
enum retro_pixel_format fmt = RETRO_PIXEL_FORMAT_XRGB8888;
|
||||||
if (!environ_cb(RETRO_ENVIRONMENT_SET_PIXEL_FORMAT, &fmt))
|
if (!environ_cb(RETRO_ENVIRONMENT_SET_PIXEL_FORMAT, &fmt))
|
||||||
{
|
{
|
||||||
log_cb(RETRO_LOG_ERROR, "[Gambatte]: XRGB8888 is not supported.\n");
|
gambatte_log(RETRO_LOG_ERROR, "XRGB8888 is not supported.\n");
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
@ -1829,7 +1894,7 @@ bool retro_load_game(const struct retro_game_info *info)
|
|||||||
strncpy(internal_game_name, (const char*)info->data + 0x134, sizeof(internal_game_name) - 1);
|
strncpy(internal_game_name, (const char*)info->data + 0x134, sizeof(internal_game_name) - 1);
|
||||||
internal_game_name[sizeof(internal_game_name)-1]='\0';
|
internal_game_name[sizeof(internal_game_name)-1]='\0';
|
||||||
|
|
||||||
log_cb(RETRO_LOG_INFO, "[Gambatte]: Got internal game name: %s.\n", internal_game_name);
|
gambatte_log(RETRO_LOG_INFO, "Got internal game name: %s.\n", internal_game_name);
|
||||||
|
|
||||||
check_variables();
|
check_variables();
|
||||||
|
|
||||||
|
@ -1,5 +1,6 @@
|
|||||||
#include "net_serial.h"
|
#include "net_serial.h"
|
||||||
#include "libretro.h"
|
#include "libretro.h"
|
||||||
|
#include "gambatte_log.h"
|
||||||
#include <iostream>
|
#include <iostream>
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
@ -17,9 +18,9 @@
|
|||||||
#include <netdb.h>
|
#include <netdb.h>
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
extern retro_log_printf_t log_cb;
|
|
||||||
//FILE* fpout;
|
//FILE* fpout;
|
||||||
//FILE* fpin;
|
//FILE* fpin;
|
||||||
|
|
||||||
NetSerial::NetSerial()
|
NetSerial::NetSerial()
|
||||||
: is_stopped_(true)
|
: is_stopped_(true)
|
||||||
, is_server_(false)
|
, is_server_(false)
|
||||||
@ -44,7 +45,7 @@ bool NetSerial::start(bool is_server, int port, const std::string& hostname)
|
|||||||
{
|
{
|
||||||
stop();
|
stop();
|
||||||
|
|
||||||
log_cb(RETRO_LOG_INFO, "Starting GameLink nework %s on %s:%d\n",
|
gambatte_log(RETRO_LOG_INFO, "Starting GameLink network %s on %s:%d\n",
|
||||||
is_server ? "server" : "client", hostname.c_str(), port);
|
is_server ? "server" : "client", hostname.c_str(), port);
|
||||||
is_server_ = is_server;
|
is_server_ = is_server;
|
||||||
port_ = port;
|
port_ = port;
|
||||||
@ -56,7 +57,7 @@ bool NetSerial::start(bool is_server, int port, const std::string& hostname)
|
|||||||
void NetSerial::stop()
|
void NetSerial::stop()
|
||||||
{
|
{
|
||||||
if (!is_stopped_) {
|
if (!is_stopped_) {
|
||||||
log_cb(RETRO_LOG_INFO, "Stoping GameLink nework\n");
|
gambatte_log(RETRO_LOG_INFO, "Stopping GameLink network\n");
|
||||||
is_stopped_ = true;
|
is_stopped_ = true;
|
||||||
if (sockfd_ >= 0) {
|
if (sockfd_ >= 0) {
|
||||||
close(sockfd_);
|
close(sockfd_);
|
||||||
@ -109,23 +110,23 @@ bool NetSerial::startServerSocket()
|
|||||||
|
|
||||||
int fd = socket(AF_INET, SOCK_STREAM, 0);
|
int fd = socket(AF_INET, SOCK_STREAM, 0);
|
||||||
if (fd < 0) {
|
if (fd < 0) {
|
||||||
log_cb(RETRO_LOG_ERROR, "Error opening socket: %s\n", strerror(errno));
|
gambatte_log(RETRO_LOG_ERROR, "Error opening socket: %s\n", strerror(errno));
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (bind(fd, (struct sockaddr *)&server_addr, sizeof(server_addr)) < 0) {
|
if (bind(fd, (struct sockaddr *)&server_addr, sizeof(server_addr)) < 0) {
|
||||||
log_cb(RETRO_LOG_ERROR, "Error on binding: %s\n", strerror(errno));
|
gambatte_log(RETRO_LOG_ERROR, "Error on binding: %s\n", strerror(errno));
|
||||||
close(fd);
|
close(fd);
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (listen(fd, 1) < 0) {
|
if (listen(fd, 1) < 0) {
|
||||||
log_cb(RETRO_LOG_ERROR, "Error listening: %s\n", strerror(errno));
|
gambatte_log(RETRO_LOG_ERROR, "Error listening: %s\n", strerror(errno));
|
||||||
close(fd);
|
close(fd);
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
server_fd_ = fd;
|
server_fd_ = fd;
|
||||||
log_cb(RETRO_LOG_INFO, "GameLink network server started!\n");
|
gambatte_log(RETRO_LOG_INFO, "GameLink network server started!\n");
|
||||||
}
|
}
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
@ -154,10 +155,10 @@ bool NetSerial::acceptClient()
|
|||||||
socklen_t client_len = sizeof(client_addr);
|
socklen_t client_len = sizeof(client_addr);
|
||||||
sockfd_ = accept(server_fd_, (struct sockaddr*)&client_addr, &client_len);
|
sockfd_ = accept(server_fd_, (struct sockaddr*)&client_addr, &client_len);
|
||||||
if (sockfd_ < 0) {
|
if (sockfd_ < 0) {
|
||||||
log_cb(RETRO_LOG_ERROR, "Error on accept: %s\n", strerror(errno));
|
gambatte_log(RETRO_LOG_ERROR, "Error on accept: %s\n", strerror(errno));
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
log_cb(RETRO_LOG_INFO, "GameLink network server connected to client!\n");
|
gambatte_log(RETRO_LOG_INFO, "GameLink network server connected to client!\n");
|
||||||
}
|
}
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
@ -173,25 +174,25 @@ bool NetSerial::startClientSocket()
|
|||||||
|
|
||||||
int fd = socket(AF_INET, SOCK_STREAM, 0);
|
int fd = socket(AF_INET, SOCK_STREAM, 0);
|
||||||
if (fd < 0) {
|
if (fd < 0) {
|
||||||
log_cb(RETRO_LOG_ERROR, "Error opening socket: %s\n", strerror(errno));
|
gambatte_log(RETRO_LOG_ERROR, "Error opening socket: %s\n", strerror(errno));
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
struct hostent* server_hostname = gethostbyname(hostname_.c_str());
|
struct hostent* server_hostname = gethostbyname(hostname_.c_str());
|
||||||
if (server_hostname == NULL) {
|
if (server_hostname == NULL) {
|
||||||
log_cb(RETRO_LOG_ERROR, "Error, no such host: %s\n", hostname_.c_str());
|
gambatte_log(RETRO_LOG_ERROR, "Error, no such host: %s\n", hostname_.c_str());
|
||||||
close(fd);
|
close(fd);
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
memmove((char*)&server_addr.sin_addr.s_addr, (char*)server_hostname->h_addr, server_hostname->h_length);
|
memmove((char*)&server_addr.sin_addr.s_addr, (char*)server_hostname->h_addr, server_hostname->h_length);
|
||||||
if (connect(fd, (struct sockaddr*)&server_addr, sizeof(server_addr)) < 0) {
|
if (connect(fd, (struct sockaddr*)&server_addr, sizeof(server_addr)) < 0) {
|
||||||
log_cb(RETRO_LOG_ERROR, "Error connecting to server: %s\n", strerror(errno));
|
gambatte_log(RETRO_LOG_ERROR, "Error connecting to server: %s\n", strerror(errno));
|
||||||
close(fd);
|
close(fd);
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
sockfd_ = fd;
|
sockfd_ = fd;
|
||||||
log_cb(RETRO_LOG_INFO, "GameLink network client connected to server!\n");
|
gambatte_log(RETRO_LOG_INFO, "GameLink network client connected to server!\n");
|
||||||
}
|
}
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
@ -220,7 +221,7 @@ unsigned char NetSerial::send(unsigned char data, bool fastCgb)
|
|||||||
if (write(sockfd_, buffer, 2) <= 0)
|
if (write(sockfd_, buffer, 2) <= 0)
|
||||||
#endif
|
#endif
|
||||||
{
|
{
|
||||||
log_cb(RETRO_LOG_ERROR, "Error writing to socket: %s\n", strerror(errno));
|
gambatte_log(RETRO_LOG_ERROR, "Error writing to socket: %s\n", strerror(errno));
|
||||||
close(sockfd_);
|
close(sockfd_);
|
||||||
sockfd_ = -1;
|
sockfd_ = -1;
|
||||||
return 0xFF;
|
return 0xFF;
|
||||||
@ -233,7 +234,7 @@ unsigned char NetSerial::send(unsigned char data, bool fastCgb)
|
|||||||
if (read(sockfd_, buffer, 2) <= 0)
|
if (read(sockfd_, buffer, 2) <= 0)
|
||||||
#endif
|
#endif
|
||||||
{
|
{
|
||||||
log_cb(RETRO_LOG_ERROR, "Error reading from socket: %s\n", strerror(errno));
|
gambatte_log(RETRO_LOG_ERROR, "Error reading from socket: %s\n", strerror(errno));
|
||||||
close(sockfd_);
|
close(sockfd_);
|
||||||
sockfd_ = -1;
|
sockfd_ = -1;
|
||||||
return 0xFF;
|
return 0xFF;
|
||||||
@ -271,7 +272,7 @@ bool NetSerial::check(unsigned char out, unsigned char& in, bool& fastCgb)
|
|||||||
if (ioctl(sockfd_, FIONREAD, &bytes_avail) < 0)
|
if (ioctl(sockfd_, FIONREAD, &bytes_avail) < 0)
|
||||||
#endif
|
#endif
|
||||||
{
|
{
|
||||||
log_cb(RETRO_LOG_ERROR, "IOCTL Failed: %s\n", strerror(errno));
|
gambatte_log(RETRO_LOG_ERROR, "IOCTL Failed: %s\n", strerror(errno));
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -286,7 +287,7 @@ bool NetSerial::check(unsigned char out, unsigned char& in, bool& fastCgb)
|
|||||||
if (read(sockfd_, buffer, 2) <= 0)
|
if (read(sockfd_, buffer, 2) <= 0)
|
||||||
#endif
|
#endif
|
||||||
{
|
{
|
||||||
log_cb(RETRO_LOG_ERROR, "Error reading from socket: %s\n", strerror(errno));
|
gambatte_log(RETRO_LOG_ERROR, "Error reading from socket: %s\n", strerror(errno));
|
||||||
close(sockfd_);
|
close(sockfd_);
|
||||||
sockfd_ = -1;
|
sockfd_ = -1;
|
||||||
return false;
|
return false;
|
||||||
@ -306,7 +307,7 @@ bool NetSerial::check(unsigned char out, unsigned char& in, bool& fastCgb)
|
|||||||
if (write(sockfd_, buffer, 2) <= 0)
|
if (write(sockfd_, buffer, 2) <= 0)
|
||||||
#endif
|
#endif
|
||||||
{
|
{
|
||||||
log_cb(RETRO_LOG_ERROR, "Error writing to socket: %s\n", strerror(errno));
|
gambatte_log(RETRO_LOG_ERROR, "Error writing to socket: %s\n", strerror(errno));
|
||||||
close(sockfd_);
|
close(sockfd_);
|
||||||
sockfd_ = -1;
|
sockfd_ = -1;
|
||||||
return false;
|
return false;
|
||||||
|
@ -23,6 +23,7 @@
|
|||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
#include <algorithm>
|
#include <algorithm>
|
||||||
|
#include "gambatte_log.h"
|
||||||
|
|
||||||
extern void cartridge_set_rumble(unsigned active);
|
extern void cartridge_set_rumble(unsigned active);
|
||||||
|
|
||||||
@ -383,16 +384,16 @@ namespace gambatte
|
|||||||
switch (p >> 13 & 3) {
|
switch (p >> 13 & 3) {
|
||||||
case 0:
|
case 0:
|
||||||
ramflag_ = data;
|
ramflag_ = data;
|
||||||
//printf("[HuC3] set ramflag to %02X\n", data);
|
//gambatte_log(RETRO_LOG_DEBUG, "<HuC3> set ramflag to %02X\n", data);
|
||||||
setRambank();
|
setRambank();
|
||||||
break;
|
break;
|
||||||
case 1:
|
case 1:
|
||||||
//printf("[HuC3] set rombank to %02X\n", data);
|
//gambatte_log(RETRO_LOG_DEBUG, "<HuC3> set rombank to %02X\n", data);
|
||||||
rombank_ = data;
|
rombank_ = data;
|
||||||
setRombank();
|
setRombank();
|
||||||
break;
|
break;
|
||||||
case 2:
|
case 2:
|
||||||
//printf("[HuC3] set rambank to %02X\n", data);
|
//gambatte_log(RETRO_LOG_DEBUG, "<HuC3> set rambank to %02X\n", data);
|
||||||
rambank_ = data;
|
rambank_ = data;
|
||||||
setRambank();
|
setRambank();
|
||||||
break;
|
break;
|
||||||
@ -552,38 +553,38 @@ namespace gambatte
|
|||||||
|
|
||||||
switch (header[0x0147])
|
switch (header[0x0147])
|
||||||
{
|
{
|
||||||
case 0x00: printf("Plain ROM loaded.\n"); type = PLAIN; break;
|
case 0x00: gambatte_log(RETRO_LOG_INFO, "Plain ROM loaded.\n"); type = PLAIN; break;
|
||||||
case 0x01: printf("MBC1 ROM loaded.\n"); type = MBC1; break;
|
case 0x01: gambatte_log(RETRO_LOG_INFO, "MBC1 ROM loaded.\n"); type = MBC1; break;
|
||||||
case 0x02: printf("MBC1 ROM+RAM loaded.\n"); type = MBC1; break;
|
case 0x02: gambatte_log(RETRO_LOG_INFO, "MBC1 ROM+RAM loaded.\n"); type = MBC1; break;
|
||||||
case 0x03: printf("MBC1 ROM+RAM+BATTERY loaded.\n"); type = MBC1; break;
|
case 0x03: gambatte_log(RETRO_LOG_INFO, "MBC1 ROM+RAM+BATTERY loaded.\n"); type = MBC1; break;
|
||||||
case 0x05: printf("MBC2 ROM loaded.\n"); type = MBC2; break;
|
case 0x05: gambatte_log(RETRO_LOG_INFO, "MBC2 ROM loaded.\n"); type = MBC2; break;
|
||||||
case 0x06: printf("MBC2 ROM+BATTERY loaded.\n"); type = MBC2; break;
|
case 0x06: gambatte_log(RETRO_LOG_INFO, "MBC2 ROM+BATTERY loaded.\n"); type = MBC2; break;
|
||||||
case 0x08: printf("Plain ROM with additional RAM loaded.\n"); type = MBC2; break;
|
case 0x08: gambatte_log(RETRO_LOG_INFO, "Plain ROM with additional RAM loaded.\n"); type = MBC2; break;
|
||||||
case 0x09: printf("Plain ROM with additional RAM and Battery loaded.\n"); type = MBC2;break;
|
case 0x09: gambatte_log(RETRO_LOG_INFO, "Plain ROM with additional RAM and Battery loaded.\n"); type = MBC2;break;
|
||||||
case 0x0B: printf("MM01 ROM not supported.\n"); return -1;
|
case 0x0B: gambatte_log(RETRO_LOG_INFO, "MM01 ROM not supported.\n"); return -1;
|
||||||
case 0x0C: printf("MM01 ROM not supported.\n"); return -1;
|
case 0x0C: gambatte_log(RETRO_LOG_INFO, "MM01 ROM not supported.\n"); return -1;
|
||||||
case 0x0D: printf("MM01 ROM not supported.\n"); return -1;
|
case 0x0D: gambatte_log(RETRO_LOG_INFO, "MM01 ROM not supported.\n"); return -1;
|
||||||
case 0x0F: printf("MBC3 ROM+TIMER+BATTERY loaded.\n"); type = MBC3; break;
|
case 0x0F: gambatte_log(RETRO_LOG_INFO, "MBC3 ROM+TIMER+BATTERY loaded.\n"); type = MBC3; break;
|
||||||
case 0x10: printf("MBC3 ROM+TIMER+RAM+BATTERY loaded.\n"); type = MBC3; break;
|
case 0x10: gambatte_log(RETRO_LOG_INFO, "MBC3 ROM+TIMER+RAM+BATTERY loaded.\n"); type = MBC3; break;
|
||||||
case 0x11: printf("MBC3 ROM loaded.\n"); type = MBC3; break;
|
case 0x11: gambatte_log(RETRO_LOG_INFO, "MBC3 ROM loaded.\n"); type = MBC3; break;
|
||||||
case 0x12: printf("MBC3 ROM+RAM loaded.\n"); type = MBC3; break;
|
case 0x12: gambatte_log(RETRO_LOG_INFO, "MBC3 ROM+RAM loaded.\n"); type = MBC3; break;
|
||||||
case 0x13: printf("MBC3 ROM+RAM+BATTERY loaded.\n"); type = MBC3; break;
|
case 0x13: gambatte_log(RETRO_LOG_INFO, "MBC3 ROM+RAM+BATTERY loaded.\n"); type = MBC3; break;
|
||||||
case 0x15: printf("MBC4 ROM not supported.\n"); return -1;
|
case 0x15: gambatte_log(RETRO_LOG_INFO, "MBC4 ROM not supported.\n"); return -1;
|
||||||
case 0x16: printf("MBC4 ROM not supported.\n"); return -1;
|
case 0x16: gambatte_log(RETRO_LOG_INFO, "MBC4 ROM not supported.\n"); return -1;
|
||||||
case 0x17: printf("MBC4 ROM not supported.\n"); return -1;
|
case 0x17: gambatte_log(RETRO_LOG_INFO, "MBC4 ROM not supported.\n"); return -1;
|
||||||
case 0x19: printf("MBC5 ROM loaded.\n"); type = MBC5; break;
|
case 0x19: gambatte_log(RETRO_LOG_INFO, "MBC5 ROM loaded.\n"); type = MBC5; break;
|
||||||
case 0x1A: printf("MBC5 ROM+RAM loaded.\n"); type = MBC5; break;
|
case 0x1A: gambatte_log(RETRO_LOG_INFO, "MBC5 ROM+RAM loaded.\n"); type = MBC5; break;
|
||||||
case 0x1B: printf("MBC5 ROM+RAM+BATTERY loaded.\n"); type = MBC5; break;
|
case 0x1B: gambatte_log(RETRO_LOG_INFO, "MBC5 ROM+RAM+BATTERY loaded.\n"); type = MBC5; break;
|
||||||
case 0x1C: printf("MBC5+RUMBLE ROM loaded.\n"); type = MBC5; rumble = true; break;
|
case 0x1C: gambatte_log(RETRO_LOG_INFO, "MBC5+RUMBLE ROM loaded.\n"); type = MBC5; rumble = true; break;
|
||||||
case 0x1D: printf("MBC5+RUMBLE+RAM ROM loaded.\n"); type = MBC5; rumble = true; break;
|
case 0x1D: gambatte_log(RETRO_LOG_INFO, "MBC5+RUMBLE+RAM ROM loaded.\n"); type = MBC5; rumble = true; break;
|
||||||
case 0x1E: printf("MBC5+RUMBLE+RAM+BATTERY ROM loaded.\n"); type = MBC5; rumble = true; break;
|
case 0x1E: gambatte_log(RETRO_LOG_INFO, "MBC5+RUMBLE+RAM+BATTERY ROM loaded.\n"); type = MBC5; rumble = true; break;
|
||||||
case 0x20: printf("MBC6 ROM not supported.\n"); return -1;
|
case 0x20: gambatte_log(RETRO_LOG_INFO, "MBC6 ROM not supported.\n"); return -1;
|
||||||
case 0x22: printf("MBC7 ROM not supported.\n"); return -1;
|
case 0x22: gambatte_log(RETRO_LOG_INFO, "MBC7 ROM not supported.\n"); return -1;
|
||||||
case 0xFC: printf("Pocket Camera ROM not supported.\n"); return -1;
|
case 0xFC: gambatte_log(RETRO_LOG_INFO, "Pocket Camera ROM not supported.\n"); return -1;
|
||||||
case 0xFD: printf("Bandai TAMA5 ROM not supported.\n"); return -1;
|
case 0xFD: gambatte_log(RETRO_LOG_INFO, "Bandai TAMA5 ROM not supported.\n"); return -1;
|
||||||
case 0xFE: printf("HuC3 ROM+RAM+BATTERY loaded.\n"); type = HUC3; break;
|
case 0xFE: gambatte_log(RETRO_LOG_INFO, "HuC3 ROM+RAM+BATTERY loaded.\n"); type = HUC3; break;
|
||||||
case 0xFF: printf("HuC1 ROM+BATTERY loaded.\n"); type = HUC1; break;
|
case 0xFF: gambatte_log(RETRO_LOG_INFO, "HuC1 ROM+BATTERY loaded.\n"); type = HUC1; break;
|
||||||
default: printf("Wrong data-format, corrupt or unsupported ROM.\n"); return -1;
|
default: gambatte_log(RETRO_LOG_INFO, "Wrong data-format, corrupt or unsupported ROM.\n"); return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
switch (header[0x0149])
|
switch (header[0x0149])
|
||||||
@ -619,10 +620,10 @@ namespace gambatte
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
printf("rambanks: %u\n", rambanks);
|
gambatte_log(RETRO_LOG_INFO, "rambanks: %u\n", rambanks);
|
||||||
|
|
||||||
rombanks = pow2ceil(romsize / 0x4000);
|
rombanks = pow2ceil(romsize / 0x4000);
|
||||||
printf("rombanks: %u\n", static_cast<unsigned>(romsize / 0x4000));
|
gambatte_log(RETRO_LOG_INFO, "rombanks: %u\n", static_cast<unsigned>(romsize / 0x4000));
|
||||||
|
|
||||||
ggUndoList_.clear();
|
ggUndoList_.clear();
|
||||||
mbc.reset();
|
mbc.reset();
|
||||||
|
@ -5,8 +5,6 @@
|
|||||||
|
|
||||||
#include <libretro.h>
|
#include <libretro.h>
|
||||||
|
|
||||||
extern retro_log_printf_t log_cb;
|
|
||||||
|
|
||||||
namespace gambatte
|
namespace gambatte
|
||||||
{
|
{
|
||||||
static bool hasBattery(unsigned char headerByte0x147)
|
static bool hasBattery(unsigned char headerByte0x147)
|
||||||
|
@ -19,6 +19,7 @@
|
|||||||
#include "huc3.h"
|
#include "huc3.h"
|
||||||
#include "../savestate.h"
|
#include "../savestate.h"
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
|
#include "gambatte_log.h"
|
||||||
|
|
||||||
namespace gambatte {
|
namespace gambatte {
|
||||||
|
|
||||||
@ -113,7 +114,7 @@ unsigned char HuC3Chip::read(unsigned p, unsigned long const cc) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
if(ramflag_ < 0x0B || ramflag_ > 0x0D) {
|
if(ramflag_ < 0x0B || ramflag_ > 0x0D) {
|
||||||
printf("[HuC3] error, hit huc3 read with ramflag=%02X\n", ramflag_);
|
gambatte_log(RETRO_LOG_ERROR, "<HuC3> error, hit huc3 read with ramflag=%02X\n", ramflag_);
|
||||||
return 0xFF;
|
return 0xFF;
|
||||||
}
|
}
|
||||||
if(ramflag_ == 0x0D) return 1;
|
if(ramflag_ == 0x0D) return 1;
|
||||||
|
Loading…
Reference in New Issue
Block a user