Replace direct file access with VFS routines + clean-ups

This commit is contained in:
jdgleaver 2021-10-04 13:42:38 +01:00
parent bb13e166bd
commit 422ea3bb84
29 changed files with 1611 additions and 647 deletions

View File

@ -1,12 +1,22 @@
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)))
INCFLAGS += -I$(LIBRETRO_COMM_DIR)/include/compat/msvc
endif
SOURCES_C := $(CORE_DIR)/../libretro/blipper.c
SOURCES_CXX := $(CORE_DIR)/bootloader.cpp \
SOURCES_C := \
$(CORE_DIR)/../libretro/gambatte_log.c \
$(CORE_DIR)/../libretro/blipper.c
SOURCES_CXX := \
$(CORE_DIR)/bootloader.cpp \
$(CORE_DIR)/cpu.cpp \
$(CORE_DIR)/gambatte.cpp \
$(CORE_DIR)/initstate.cpp \
@ -38,21 +48,23 @@ SOURCES_CXX := $(CORE_DIR)/bootloader.cpp \
$(CORE_DIR)/../libretro/libretro.cpp
ifeq ($(HAVE_NETWORK),1)
SOURCES_CXX += $(CORE_DIR)/../libretro/net_serial.cpp
SOURCES_CXX += \
$(CORE_DIR)/../libretro/net_serial.cpp
endif
ifeq ($(STATIC_LINKING),1)
else
SOURCES_C += $(LIBRETRO_COMM_DIR)/streams/file_stream.c \
$(LIBRETRO_COMM_DIR)/vfs/vfs_implementation.c \
$(LIBRETRO_COMM_DIR)/compat/fopen_utf8.c \
$(LIBRETRO_COMM_DIR)/compat/compat_strl.c \
$(LIBRETRO_COMM_DIR)/compat/compat_snprintf.c \
ifneq ($(STATIC_LINKING), 1)
SOURCES_C += \
$(LIBRETRO_COMM_DIR)/compat/compat_posix_string.c \
$(LIBRETRO_COMM_DIR)/compat/compat_snprintf.c \
$(LIBRETRO_COMM_DIR)/compat/compat_strcasestr.c \
$(LIBRETRO_COMM_DIR)/compat/compat_strl.c \
$(LIBRETRO_COMM_DIR)/compat/fopen_utf8.c \
$(LIBRETRO_COMM_DIR)/encodings/encoding_utf.c \
$(LIBRETRO_COMM_DIR)/file/file_path.c \
$(LIBRETRO_COMM_DIR)/time/rtime.c \
$(LIBRETRO_COMM_DIR)/file/file_path_io.c \
$(LIBRETRO_COMM_DIR)/streams/file_stream.c \
$(LIBRETRO_COMM_DIR)/streams/file_stream_transforms.c \
$(LIBRETRO_COMM_DIR)/string/stdstring.c \
$(LIBRETRO_COMM_DIR)/encodings/encoding_utf.c
$(LIBRETRO_COMM_DIR)/time/rtime.c \
$(LIBRETRO_COMM_DIR)/vfs/vfs_implementation.c
endif

View File

@ -33,12 +33,12 @@
#if _MSC_VER < 1300
#define _vscprintf c89_vscprintf_retro__
static int c89_vscprintf_retro__(const char *format, va_list pargs)
static int c89_vscprintf_retro__(const char *fmt, va_list pargs)
{
int retval;
va_list argcopy;
va_copy(argcopy, pargs);
retval = vsnprintf(NULL, 0, format, argcopy);
retval = vsnprintf(NULL, 0, fmt, argcopy);
va_end(argcopy);
return retval;
}
@ -46,38 +46,36 @@ static int c89_vscprintf_retro__(const char *format, va_list pargs)
/* http://stackoverflow.com/questions/2915672/snprintf-and-visual-studio-2010 */
int c99_vsnprintf_retro__(char *outBuf, size_t size, const char *format, va_list ap)
int c99_vsnprintf_retro__(char *s, size_t len, const char *fmt, va_list ap)
{
int count = -1;
if (size != 0)
if (len != 0)
{
#if (_MSC_VER <= 1310)
count = _vsnprintf(outBuf, size - 1, format, ap);
count = _vsnprintf(s, len - 1, fmt, ap);
#else
count = _vsnprintf_s(outBuf, size, size - 1, format, ap);
count = _vsnprintf_s(s, len, len - 1, fmt, ap);
#endif
}
if (count == -1)
count = _vscprintf(format, ap);
count = _vscprintf(fmt, ap);
if (count == size)
{
/* there was no room for a NULL, so truncate the last character */
outBuf[size - 1] = '\0';
}
if (count == len && len)
s[len - 1] = '\0';
return count;
}
int c99_snprintf_retro__(char *outBuf, size_t size, const char *format, ...)
int c99_snprintf_retro__(char *s, size_t len, const char *fmt, ...)
{
int count;
va_list ap;
va_start(ap, format);
count = c99_vsnprintf_retro__(outBuf, size, format, ap);
va_start(ap, fmt);
count = c99_vsnprintf_retro__(s, len, fmt, ap);
va_end(ap);
return count;

View File

@ -49,8 +49,13 @@ void *fopen_utf8(const char * filename, const char * mode)
#else
wchar_t * filename_w = utf8_to_utf16_string_alloc(filename);
wchar_t * mode_w = utf8_to_utf16_string_alloc(mode);
FILE* ret = _wfopen(filename_w, mode_w);
FILE* ret = NULL;
if (filename_w && mode_w)
ret = _wfopen(filename_w, mode_w);
if (filename_w)
free(filename_w);
if (mode_w)
free(mode_w);
return ret;
#endif

View File

@ -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,
enum CodePage cp_in, enum CodePage cp_out)
{
char *path_buf = NULL;
wchar_t *path_buf_wide = NULL;
int path_buf_len = 0;
int path_buf_wide_len = MultiByteToWideChar(cp_in, 0, str, -1, NULL, 0);
/* Windows 95 will return 0 from these functions with
@ -299,8 +297,9 @@ static char *mb_to_mb_string_alloc(const char *str,
* MultiByteToWideChar also supports CP_UTF7 and CP_UTF8.
*/
if (path_buf_wide_len)
{
if (!path_buf_wide_len)
return strdup(str);
path_buf_wide = (wchar_t*)
calloc(path_buf_wide_len + sizeof(wchar_t), sizeof(wchar_t));
@ -311,12 +310,12 @@ static char *mb_to_mb_string_alloc(const char *str,
if (*path_buf_wide)
{
path_buf_len = WideCharToMultiByte(cp_out, 0,
int path_buf_len = WideCharToMultiByte(cp_out, 0,
path_buf_wide, -1, NULL, 0, NULL, NULL);
if (path_buf_len)
{
path_buf = (char*)
char *path_buf = (char*)
calloc(path_buf_len + sizeof(char), sizeof(char));
if (path_buf)
@ -340,13 +339,9 @@ static char *mb_to_mb_string_alloc(const char *str,
return strdup(str);
}
}
}
}
else
return strdup(str);
if (path_buf_wide)
free(path_buf_wide);
}
return NULL;
}

View File

@ -48,43 +48,9 @@
#include <retro_miscellaneous.h>
#include <encodings/utf.h>
#if defined(_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>
#ifdef _WIN32
#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
#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 */
#endif
@ -121,15 +87,23 @@ const char *path_get_archive_delim(const char *path)
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)
return NULL;
last_slash = path;
/* Find delimiter position */
delim = strrchr(last_slash, '#');
if (!delim)
return NULL;
/* Find delimiter position
* > Since filenames may contain '#' characters,
* must loop until we find the first '#' that
* is directly *after* a compression extension */
delim = strchr(last_slash, '#');
while (delim)
{
/* Check whether this is a known archive type
* > Note: The code duplication here is
* deliberate, to maximise performance */
@ -158,6 +132,10 @@ const char *path_get_archive_delim(const char *path)
return delim;
}
delim++;
delim = strchr(delim, '#');
}
return NULL;
}
@ -214,15 +192,11 @@ char *path_remove_extension(char *path)
bool path_is_compressed_file(const char* path)
{
const char *ext = path_get_extension(path);
if (string_is_empty(ext))
return false;
if (string_is_equal_noncase(ext, "zip") ||
if (!string_is_empty(ext))
if ( string_is_equal_noncase(ext, "zip") ||
string_is_equal_noncase(ext, "apk") ||
string_is_equal_noncase(ext, "7z"))
return true;
return false;
}
@ -547,7 +521,7 @@ void path_basedir(char *path)
if (last)
last[1] = '\0';
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;
}
/* 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 : path
@ -666,16 +650,31 @@ bool path_is_absolute(const char *path)
char *path_resolve_realpath(char *buf, size_t size, bool resolve_symlinks)
{
#if !defined(RARCH_CONSOLE) && defined(RARCH_INTERNAL)
char tmp[PATH_MAX_LENGTH];
#ifdef _WIN32
strlcpy(tmp, buf, sizeof(tmp));
if (!_fullpath(buf, tmp, size))
char *ret = NULL;
wchar_t abs_path[PATH_MAX_LENGTH];
wchar_t *rel_path = utf8_to_utf16_string_alloc(buf);
if (rel_path)
{
if (_wfullpath(abs_path, rel_path, PATH_MAX_LENGTH))
{
char *tmp = utf16_to_utf8_string_alloc(abs_path);
if (tmp)
{
strlcpy(buf, tmp, size);
return NULL;
free(tmp);
ret = buf;
}
return buf;
}
free(rel_path);
}
return ret;
#else
char tmp[PATH_MAX_LENGTH];
size_t t;
char *p;
const char *next;
@ -1096,8 +1095,7 @@ void fill_pathname_abbreviate_special(char *out_path,
if (!PATH_CHAR_IS_SLASH(*in_path))
{
retro_assert(strlcpy(out_path,
PATH_DEFAULT_SLASH(), size) < size);
strcpy_literal(out_path, PATH_DEFAULT_SLASH());
out_path++;
size--;
}
@ -1111,6 +1109,99 @@ void fill_pathname_abbreviate_special(char *out_path,
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 : path
@ -1136,7 +1227,7 @@ void path_basedir_wrapper(char *path)
if (last)
last[1] = '\0';
else
snprintf(path, 3, "." PATH_DEFAULT_SLASH());
strlcpy(path, "." PATH_DEFAULT_SLASH(), 3);
}
#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)
{
#ifdef __WINRT__
strlcpy(s, uwp_dir_data, len);
const char *home = uwp_dir_data;
#else
const char *home = getenv("HOME");
#endif
if (home)
strlcpy(s, home, len);
else
*s = 0;
#endif
}
#endif
bool is_path_accessible_using_standard_io(const char *path)
{
bool result = true;
#ifdef __WINRT__
size_t path_sizeof = PATH_MAX_LENGTH * sizeof(char);
char *relative_path_abbrev = (char*)malloc(path_sizeof);
fill_pathname_abbreviate_special(relative_path_abbrev, path, path_sizeof);
result = (strlen(relative_path_abbrev) >= 2 )
&& (relative_path_abbrev[0] == ':' || relative_path_abbrev[0] == '~')
char relative_path_abbrev[PATH_MAX_LENGTH];
fill_pathname_abbreviate_special(relative_path_abbrev,
path, sizeof(relative_path_abbrev));
return (strlen(relative_path_abbrev) >= 2 )
&& ( relative_path_abbrev[0] == ':'
|| relative_path_abbrev[0] == '~')
&& PATH_CHAR_IS_SLASH(relative_path_abbrev[1]);
free(relative_path_abbrev);
#else
return true;
#endif
return result;
}

View 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;
}

View File

@ -29,22 +29,17 @@
extern "C" {
#endif
/* Pre-MSVC 2015 compilers don't implement snprintf in a cross-platform manner. */
/* Pre-MSVC 2015 compilers don't implement snprintf, vsnprintf in a cross-platform manner. */
#if _MSC_VER < 1900
#include <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 <stdarg.h>
#include <stdlib.h>
#ifndef snprintf
#define snprintf c99_snprintf_retro__
#endif
int c99_snprintf_retro__(char *outBuf, size_t size, const char *format, ...);
#ifndef vsnprintf
#define vsnprintf c99_vsnprintf_retro__
#endif

View File

@ -125,6 +125,7 @@ char *path_remove_extension(char *path);
* Returns: basename from path.
**/
const char *path_basename(const char *path);
const char *path_basename_nocompression(const char *path);
/**
* path_basedir:
@ -442,6 +443,12 @@ void fill_pathname_expand_special(char *out_path,
void fill_pathname_abbreviate_special(char *out_path,
const char *in_path, size_t size);
void fill_pathname_abbreviated_or_relative(char *out_path, const char *in_refpath, const char *in_path, size_t size);
void pathname_conform_slashes_to_os(char *path);
void pathname_make_slashes_portable(char *path);
/**
* path_basedir:
* @path : path

View File

@ -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

View File

@ -27,9 +27,7 @@
#ifdef RARCH_INTERNAL
#include <stdio.h>
#define retro_assert(cond) do { \
if (!(cond)) { printf("Assertion failed at %s:%d.\n", __FILE__, __LINE__); abort(); } \
} while(0)
#define retro_assert(cond) ((void)( (cond) || (printf("Assertion failed at %s:%d.\n", __FILE__, __LINE__), abort(), 0) ))
#else
#define retro_assert(cond) assert(cond)
#endif

View File

@ -30,13 +30,17 @@
#include <boolean.h>
#include <retro_inline.h>
#if defined(_WIN32) && !defined(_XBOX)
#if defined(_WIN32)
#if defined(_XBOX)
#include <Xtl.h>
#else
#ifndef WIN32_LEAN_AND_MEAN
#define WIN32_LEAN_AND_MEAN
#endif
#include <windows.h>
#elif defined(_WIN32) && defined(_XBOX)
#include <Xtl.h>
#endif
#endif
#include <limits.h>
@ -71,7 +75,7 @@ static INLINE bool bits_any_set(uint32_t* ptr, uint32_t count)
}
#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
#else
#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_CLEAR_ALL_PTR(a) BIT256_CLEAR_ALL(*a)
#define BIT512_SET(a, bit) BIT256_SET(a, bit)
#define BIT512_CLEAR(a, bit) BIT256_CLEAR(a, bit)
#define BIT512_GET(a, bit) BIT256_GET(a, bit)
#define BIT512_CLEAR_ALL(a) BIT256_CLEAR_ALL(a)
#define BIT512_SET_PTR(a, bit) BIT512_SET(*a, bit)
#define BIT512_CLEAR_PTR(a, bit) BIT512_CLEAR(*a, bit)
#define BIT512_GET_PTR(a, bit) BIT512_GET(*a, bit)
#define BIT512_CLEAR_ALL_PTR(a) BIT512_CLEAR_ALL(*a)
#define BITS_COPY16_PTR(a,bits) \
{ \
BIT128_CLEAR_ALL_PTR(a); \
@ -142,6 +156,13 @@ static INLINE bool bits_any_set(uint32_t* ptr, uint32_t count)
BITS_GET_ELEM_PTR(a, 0) = (bits); \
}
#define BITS_COPY64_PTR(a,bits) \
{ \
BIT128_CLEAR_ALL_PTR(a); \
BITS_GET_ELEM_PTR(a, 0) = (bits); \
BITS_GET_ELEM_PTR(a, 1) = (bits >> 32); \
}
/* Helper macros and struct to keep track of many booleans. */
/* This struct has 256 bits. */
typedef struct
@ -149,6 +170,12 @@ typedef struct
uint32_t data[8];
} retro_bits_t;
/* This struct has 512 bits. */
typedef struct
{
uint32_t data[16];
} retro_bits_512_t;
#ifdef _WIN32
# ifdef _WIN64
# define PRI_SIZET PRIu64
@ -159,7 +186,7 @@ typedef struct
# define PRI_SIZET "u"
# endif
# endif
#elif PS2
#elif defined(PS2)
# define PRI_SIZET "u"
#else
# if (SIZE_MAX == 0xFFFF)

View File

@ -81,6 +81,8 @@ char* filestream_gets(RFILE *stream, char *s, size_t len);
int filestream_getc(RFILE *stream);
int filestream_vscanf(RFILE *stream, const char* format, va_list *args);
int filestream_scanf(RFILE *stream, const char* format, ...);
int filestream_eof(RFILE *stream);

View File

@ -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

View File

@ -35,6 +35,33 @@
RETRO_BEGIN_DECLS
#define STRLEN_CONST(x) ((sizeof((x))-1))
#define strcpy_literal(a, b) strcpy(a, b)
#define string_is_not_equal(a, b) !string_is_equal((a), (b))
#define string_is_not_equal_fast(a, b, size) (memcmp(a, b, size) != 0)
#define string_is_equal_fast(a, b, size) (memcmp(a, b, size) == 0)
#define TOLOWER(c) ((c) | (lr_char_props[(unsigned char)(c)] & 0x20))
#define TOUPPER(c) ((c) & ~(lr_char_props[(unsigned char)(c)] & 0x20))
/* C standard says \f \v are space, but this one disagrees */
#define ISSPACE(c) (lr_char_props[(unsigned char)(c)] & 0x80)
#define ISDIGIT(c) (lr_char_props[(unsigned char)(c)] & 0x40)
#define ISALPHA(c) (lr_char_props[(unsigned char)(c)] & 0x20)
#define ISLOWER(c) (lr_char_props[(unsigned char)(c)] & 0x04)
#define ISUPPER(c) (lr_char_props[(unsigned char)(c)] & 0x02)
#define ISALNUM(c) (lr_char_props[(unsigned char)(c)] & 0x60)
#define ISUALPHA(c) (lr_char_props[(unsigned char)(c)] & 0x28)
#define ISUALNUM(c) (lr_char_props[(unsigned char)(c)] & 0x68)
#define IS_XDIGIT(c) (lr_char_props[(unsigned char)(c)] & 0x01)
/* Deprecated alias, all callers should use string_is_equal_case_insensitive instead */
#define string_is_equal_noncase string_is_equal_case_insensitive
static INLINE bool string_is_empty(const char *data)
{
return !data || (*data == '\0');
@ -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));
}
/* 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,
const char *b)
{
@ -98,24 +130,6 @@ static INLINE bool string_is_equal_case_insensitive(const char *a,
return (result == 0);
}
static INLINE bool string_is_equal_noncase(const char *a, const char *b)
{
int result = 0;
const unsigned char *p1 = (const unsigned char*)a;
const unsigned char *p2 = (const unsigned char*)b;
if (!a || !b)
return false;
if (p1 == p2)
return false;
while ((result = tolower (*p1) - tolower (*p2++)) == 0)
if (*p1++ == '\0')
break;
return (result == 0);
}
char *string_to_upper(char *s);
char *string_to_lower(char *s);
@ -134,9 +148,61 @@ char *string_trim_whitespace_right(char *const s);
/* Remove leading and trailing whitespaces */
char *string_trim_whitespace(char *const s);
/* max_lines == 0 means no limit */
char *word_wrap(char *buffer, const char *string,
int line_width, bool unicode, unsigned max_lines);
/*
* Wraps string specified by 'src' to destination buffer
* specified by 'dst' and 'dst_size'.
* This function assumes that all glyphs in the string
* have an on-screen pixel width similar to that of
* regular Latin characters - i.e. it will not wrap
* correctly any text containing so-called 'wide' Unicode
* characters (e.g. CJK languages, emojis, etc.).
*
* @param dst pointer to destination buffer.
* @param dst_size size of destination buffer.
* @param src pointer to input string.
* @param line_width max number of characters per line.
* @param wideglyph_width not used, but is necessary to keep
* compatibility with word_wrap_wideglyph().
* @param max_lines max lines of destination string.
* 0 means no limit.
*/
void word_wrap(char *dst, size_t dst_size, const char *src,
int line_width, int wideglyph_width, unsigned max_lines);
/*
* Wraps string specified by 'src' to destination buffer
* specified by 'dst' and 'dst_size'.
* This function assumes that all glyphs in the string
* are:
* - EITHER 'non-wide' Unicode glyphs, with an on-screen
* pixel width similar to that of regular Latin characters
* - OR 'wide' Unicode glyphs (e.g. CJK languages, emojis, etc.)
* with an on-screen pixel width defined by 'wideglyph_width'
* Note that wrapping may occur in inappropriate locations
* if 'src' string contains 'wide' Unicode characters whose
* on-screen pixel width deviates greatly from the set
* 'wideglyph_width' value.
*
* @param dst pointer to destination buffer.
* @param dst_size size of destination buffer.
* @param src pointer to input string.
* @param line_width max number of characters per line.
* @param wideglyph_width effective width of 'wide' Unicode glyphs.
* the value here is normalised relative to the
* typical on-screen pixel width of a regular
* Latin character:
* - a regular Latin character is defined to
* have an effective width of 100
* - wideglyph_width = 100 * (wide_character_pixel_width / latin_character_pixel_width)
* - e.g. if 'wide' Unicode characters in 'src'
* have an on-screen pixel width twice that of
* regular Latin characters, wideglyph_width
* would be 200
* @param max_lines max lines of destination string.
* 0 means no limit.
*/
void word_wrap_wideglyph(char *dst, size_t dst_size, const char *src,
int line_width, int wideglyph_width, unsigned max_lines);
/* Splits string into tokens seperated by 'delim'
* > Returned token string must be free()'d
@ -177,6 +243,8 @@ char *string_init(const char *src);
void string_set(char **string, const char *src);
extern const unsigned char lr_char_props[256];
RETRO_END_DECLS
#endif

View File

@ -41,17 +41,17 @@ typedef void* HANDLE;
#ifdef HAVE_CDROM
typedef struct
{
int64_t byte_pos;
char *cue_buf;
size_t cue_len;
int64_t byte_pos;
char drive;
unsigned cur_lba;
unsigned last_frame_lba;
unsigned char cur_min;
unsigned char cur_sec;
unsigned char cur_frame;
unsigned char cur_track;
unsigned cur_lba;
unsigned last_frame_lba;
unsigned char last_frame[2352];
char drive;
bool last_frame_valid;
} vfs_cdrom_t;
#endif
@ -69,22 +69,22 @@ struct retro_vfs_file_handle
struct libretro_vfs_implementation_file
#endif
{
int fd;
unsigned hints;
#ifdef HAVE_CDROM
vfs_cdrom_t cdrom; /* int64_t alignment */
#endif
int64_t size;
char *buf;
uint64_t mappos;
uint64_t mapsize;
FILE *fp;
#ifdef _WIN32
HANDLE fh;
#endif
char *buf;
char* orig_path;
uint64_t mappos;
uint64_t mapsize;
uint8_t *mapped;
int fd;
unsigned hints;
enum vfs_scheme scheme;
#ifdef HAVE_CDROM
vfs_cdrom_t cdrom;
#endif
};
#endif

View File

@ -35,11 +35,19 @@
#include <compat/msvc.h>
#endif
#include <string/stdstring.h>
#include <streams/file_stream.h>
#define VFS_FRONTEND
#include <vfs/vfs_implementation.h>
static const int64_t vfs_error_return_value = -1;
#define VFS_ERROR_RETURN_VALUE -1
struct RFILE
{
struct retro_vfs_file_handle *hfile;
bool error_flag;
bool eof_flag;
};
static retro_vfs_get_path_t filestream_get_path_cb = NULL;
static retro_vfs_open_t filestream_open_cb = NULL;
@ -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_rename_t filestream_rename_cb = NULL;
struct RFILE
{
struct retro_vfs_file_handle *hfile;
bool error_flag;
bool eof_flag;
};
/* VFS Initialization */
void filestream_vfs_init(const struct retro_vfs_interface_info* vfs_info)
{
const struct retro_vfs_interface* vfs_iface;
const struct retro_vfs_interface *
vfs_iface = vfs_info->iface;
filestream_get_path_cb = NULL;
filestream_open_cb = NULL;
@ -80,9 +82,9 @@ void filestream_vfs_init(const struct retro_vfs_interface_info* vfs_info)
filestream_remove_cb = NULL;
filestream_rename_cb = NULL;
vfs_iface = vfs_info->iface;
if (vfs_info->required_interface_version < FILESTREAM_REQUIRED_VFS_VERSION
if (
(vfs_info->required_interface_version <
FILESTREAM_REQUIRED_VFS_VERSION)
|| !vfs_iface)
return;
@ -108,7 +110,8 @@ bool filestream_exists(const char *path)
if (!path || !*path)
return false;
dummy = filestream_open(path,
dummy = filestream_open(
path,
RETRO_VFS_FILE_ACCESS_READ,
RETRO_VFS_FILE_ACCESS_HINT_NONE);
@ -130,9 +133,10 @@ int64_t filestream_get_size(RFILE *stream)
if (filestream_size_cb)
output = filestream_size_cb(stream->hfile);
else
output = retro_vfs_file_size_impl((libretro_vfs_implementation_file*)stream->hfile);
output = retro_vfs_file_size_impl(
(libretro_vfs_implementation_file*)stream->hfile);
if (output == vfs_error_return_value)
if (output == VFS_ERROR_RETURN_VALUE)
stream->error_flag = true;
return output;
@ -145,9 +149,10 @@ int64_t filestream_truncate(RFILE *stream, int64_t length)
if (filestream_truncate_cb)
output = filestream_truncate_cb(stream->hfile, length);
else
output = retro_vfs_file_truncate_impl((libretro_vfs_implementation_file*)stream->hfile, length);
output = retro_vfs_file_truncate_impl(
(libretro_vfs_implementation_file*)stream->hfile, length);
if (output == vfs_error_return_value)
if (output == VFS_ERROR_RETURN_VALUE)
stream->error_flag = true;
return output;
@ -216,14 +221,14 @@ int filestream_getc(RFILE *stream)
return EOF;
}
int filestream_scanf(RFILE *stream, const char* format, ...)
int filestream_vscanf(RFILE *stream, const char* format, va_list *args)
{
char buf[4096];
char subfmt[64];
va_list args;
va_list args_copy;
const char * bufiter = buf;
int64_t startpos = filestream_tell(stream);
int ret = 0;
int64_t startpos = filestream_tell(stream);
int64_t maxlen = filestream_read(stream, buf, sizeof(buf)-1);
if (maxlen <= 0)
@ -231,7 +236,12 @@ int filestream_scanf(RFILE *stream, const char* format, ...)
buf[maxlen] = '\0';
va_start(args, format);
/* Have to copy the input va_list here
* > Calling va_arg() on 'args' directly would
* cause the va_list to have an indeterminate value
* in the function calling filestream_vscanf(),
* leading to unexpected behaviour */
va_copy(args_copy, *args);
while (*format)
{
@ -251,7 +261,7 @@ int filestream_scanf(RFILE *stream, const char* format, ...)
*subfmtiter++ = *format++;
}
while (isdigit(*format))
while (ISDIGIT((unsigned char)*format))
*subfmtiter++ = *format++; /* width */
/* length */
@ -284,28 +294,33 @@ int filestream_scanf(RFILE *stream, const char* format, ...)
*subfmtiter++ = 'n';
*subfmtiter++ = '\0';
if (sizeof(void*) != sizeof(long*)) abort(); /* all pointers must have the same size */
if (sizeof(void*) != sizeof(long*))
abort(); /* all pointers must have the same size */
if (asterisk)
{
int v = sscanf(bufiter, subfmt, &sublen);
if (v == EOF)
return EOF;
if (v != 0) break;
if (v != 0)
break;
}
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)
return EOF;
if (v != 1) break;
if (v != 1)
break;
}
ret++;
bufiter += sublen;
}
else if (isspace(*format))
else if (isspace((unsigned char)*format))
{
while (isspace(*bufiter)) bufiter++;
while (isspace((unsigned char)*bufiter))
bufiter++;
format++;
}
else
@ -317,12 +332,23 @@ int filestream_scanf(RFILE *stream, const char* format, ...)
}
}
va_end(args);
filestream_seek(stream, startpos+(bufiter-buf), RETRO_VFS_SEEK_POSITION_START);
va_end(args_copy);
filestream_seek(stream, startpos+(bufiter-buf),
RETRO_VFS_SEEK_POSITION_START);
return ret;
}
int filestream_scanf(RFILE *stream, const char* format, ...)
{
int result;
va_list vl;
va_start(vl, format);
result = filestream_vscanf(stream, format, &vl);
va_end(vl);
return result;
}
int64_t filestream_seek(RFILE *stream, int64_t offset, int seek_position)
{
int64_t output;
@ -330,10 +356,13 @@ int64_t filestream_seek(RFILE *stream, int64_t offset, int seek_position)
if (filestream_seek_cb)
output = filestream_seek_cb(stream->hfile, offset, seek_position);
else
output = retro_vfs_file_seek_impl((libretro_vfs_implementation_file*)stream->hfile, offset, seek_position);
output = retro_vfs_file_seek_impl(
(libretro_vfs_implementation_file*)stream->hfile,
offset, seek_position);
if (output == vfs_error_return_value)
if (output == VFS_ERROR_RETURN_VALUE)
stream->error_flag = true;
stream->eof_flag = false;
return output;
@ -351,9 +380,10 @@ int64_t filestream_tell(RFILE *stream)
if (filestream_size_cb)
output = filestream_tell_cb(stream->hfile);
else
output = retro_vfs_file_tell_impl((libretro_vfs_implementation_file*)stream->hfile);
output = retro_vfs_file_tell_impl(
(libretro_vfs_implementation_file*)stream->hfile);
if (output == vfs_error_return_value)
if (output == VFS_ERROR_RETURN_VALUE)
stream->error_flag = true;
return output;
@ -378,7 +408,7 @@ int64_t filestream_read(RFILE *stream, void *s, int64_t len)
output = retro_vfs_file_read_impl(
(libretro_vfs_implementation_file*)stream->hfile, s, len);
if (output == vfs_error_return_value)
if (output == VFS_ERROR_RETURN_VALUE)
stream->error_flag = true;
if (output < len)
stream->eof_flag = true;
@ -393,9 +423,10 @@ int filestream_flush(RFILE *stream)
if (filestream_flush_cb)
output = filestream_flush_cb(stream->hfile);
else
output = retro_vfs_file_flush_impl((libretro_vfs_implementation_file*)stream->hfile);
output = retro_vfs_file_flush_impl(
(libretro_vfs_implementation_file*)stream->hfile);
if (output == vfs_error_return_value)
if (output == VFS_ERROR_RETURN_VALUE)
stream->error_flag = true;
return output;
@ -422,7 +453,8 @@ const char* filestream_get_path(RFILE *stream)
if (filestream_get_path_cb)
return filestream_get_path_cb(stream->hfile);
return retro_vfs_file_get_path_impl((libretro_vfs_implementation_file*)stream->hfile);
return retro_vfs_file_get_path_impl(
(libretro_vfs_implementation_file*)stream->hfile);
}
int64_t filestream_write(RFILE *stream, const void *s, int64_t len)
@ -432,9 +464,10 @@ int64_t filestream_write(RFILE *stream, const void *s, int64_t len)
if (filestream_write_cb)
output = filestream_write_cb(stream->hfile, s, len);
else
output = retro_vfs_file_write_impl((libretro_vfs_implementation_file*)stream->hfile, s, len);
output = retro_vfs_file_write_impl(
(libretro_vfs_implementation_file*)stream->hfile, s, len);
if (output == vfs_error_return_value)
if (output == VFS_ERROR_RETURN_VALUE)
stream->error_flag = true;
return output;
@ -445,7 +478,9 @@ int filestream_putc(RFILE *stream, int c)
char c_char = (char)c;
if (!stream)
return EOF;
return filestream_write(stream, &c_char, 1)==1 ? (int)(unsigned char)c : EOF;
return filestream_write(stream, &c_char, 1) == 1
? (int)(unsigned char)c
: EOF;
}
int filestream_vprintf(RFILE *stream, const char* format, va_list args)
@ -487,7 +522,8 @@ int filestream_close(RFILE *stream)
if (filestream_close_cb)
output = filestream_close_cb(fp);
else
output = retro_vfs_file_close_impl((libretro_vfs_implementation_file*)fp);
output = retro_vfs_file_close_impl(
(libretro_vfs_implementation_file*)fp);
if (output == 0)
free(stream);
@ -500,10 +536,11 @@ int filestream_close(RFILE *stream)
* @path : path to file.
* @buf : buffer to allocate and read the contents of the
* file into. Needs to be freed manually.
* @len : optional output integer containing bytes read.
*
* Read the contents of a file into @buf.
*
* Returns: number of items read, -1 on error.
* Returns: non zero on success.
*/
int64_t filestream_read_file(const char *path, void **buf, int64_t *len)
{

View 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;
}

View File

@ -22,10 +22,31 @@
#include <stdint.h>
#include <ctype.h>
#include <string.h>
#include <string/stdstring.h>
#include <encodings/utf.h>
const uint8_t lr_char_props[256] = {
/*x0 x1 x2 x3 x4 x5 x6 x7 x8 x9 xA xB xC xD xE xF */
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x80,0x80,0x00,0x00,0x80,0x00,0x00, /* 0x */
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, /* 1x */
0x80,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, /* 2x !"#$%&'()*+,-./ */
0x41,0x41,0x41,0x41,0x41,0x41,0x41,0x41,0x41,0x41,0x00,0x00,0x00,0x00,0x00,0x00, /* 3x 0123456789:;<=>? */
0x00,0x23,0x23,0x23,0x23,0x23,0x23,0x22,0x22,0x22,0x22,0x22,0x22,0x22,0x22,0x22, /* 4x @ABCDEFGHIJKLMNO */
0x22,0x22,0x22,0x22,0x22,0x22,0x22,0x22,0x22,0x22,0x22,0x00,0x00,0x00,0x00,0x08, /* 5x PQRSTUVWXYZ[\]^_ */
0x00,0x25,0x25,0x25,0x25,0x25,0x25,0x24,0x24,0x24,0x24,0x24,0x24,0x24,0x24,0x24, /* 6x `abcdefghijklmno */
0x24,0x24,0x24,0x24,0x24,0x24,0x24,0x24,0x24,0x24,0x24,0x00,0x00,0x00,0x00,0x00, /* 7x pqrstuvwxyz{|}~ */
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, /* 8x */
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, /* 9x */
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, /* Ax */
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, /* Bx */
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, /* Cx */
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, /* Dx */
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, /* Ex */
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, /* Fx */
};
char *string_init(const char *src)
{
return src ? strdup(src) : NULL;
@ -34,7 +55,7 @@ char *string_init(const char *src)
void string_set(char **string, const char *src)
{
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);
char *current = s;
while (*current && isspace((unsigned char)*current))
while (*current && ISSPACE((unsigned char)*current))
{
++current;
--len;
@ -145,13 +166,13 @@ char *string_trim_whitespace_right(char *const s)
size_t len = strlen(s);
char *current = s + len - 1;
while (current != s && isspace((unsigned char)*current))
while (current != s && ISSPACE((unsigned char)*current))
{
--current;
--len;
}
current[isspace((unsigned char)*current) ? 0 : 1] = '\0';
current[ISSPACE((unsigned char)*current) ? 0 : 1] = '\0';
}
return s;
@ -166,88 +187,207 @@ char *string_trim_whitespace(char *const s)
return s;
}
char *word_wrap(char* buffer, const char *string, int line_width, bool unicode, unsigned max_lines)
void word_wrap(char *dst, size_t dst_size, const char *src, int line_width, int wideglyph_width, unsigned max_lines)
{
unsigned i = 0;
unsigned len = (unsigned)strlen(string);
char *lastspace = NULL;
unsigned counter = 0;
unsigned lines = 1;
size_t src_len = strlen(src);
const char *src_end = src + src_len;
while (i < len)
{
unsigned counter;
int pos = (int)(&buffer[i] - buffer);
/* Prevent buffer overflow */
if (dst_size < src_len + 1)
return;
/* copy string until the end of the line is reached */
for (counter = 1; counter <= (unsigned)line_width; counter++)
/* Early return if src string length is less
* than line width */
if (src_len < line_width)
{
strcpy(dst, src);
return;
}
while (*src != '\0')
{
const char *character;
unsigned char_len;
unsigned j = i;
/* check if end of string reached */
if (i == len)
{
buffer[i] = 0;
return buffer;
}
character = utf8skip(&string[i], 1);
char_len = (unsigned)(character - &string[i]);
if (!unicode)
counter += char_len - 1;
do
{
buffer[i] = string[i];
char_len--;
i++;
} while (char_len);
/* check for newlines embedded in the original input
* and reset the index */
if (buffer[j] == '\n')
char_len = (unsigned)(utf8skip(src, 1) - src);
counter++;
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 = 1;
counter = 0;
/* Early return if remaining src string
* length is less than line width */
if (src_end - src <= line_width)
{
strcpy(dst, src);
return;
}
}
/* check for whitespace */
if (string[i] == ' ')
while (char_len--)
*dst++ = *src++;
if (counter >= (unsigned)line_width)
{
if ((max_lines == 0 || lines < max_lines))
counter = 0;
if (lastspace && (max_lines == 0 || lines < max_lines))
{
buffer[i] = '\n';
i++;
/* 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)
{
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;
*dst = '\0';
}
buffer[k] = '\n';
/* set string index back to character after this one */
i = k + 1;
lines++;
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;
}
if (&buffer[i] - buffer == pos)
return buffer;
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;
}
}
}
}
buffer[i] = 0;
return buffer;
*dst = '\0';
}
/* Splits string into tokens seperated by 'delim'
@ -355,7 +495,7 @@ unsigned string_to_unsigned(const char *str)
for (ptr = str; *ptr != '\0'; ptr++)
{
if (!isdigit(*ptr))
if (!ISDIGIT((unsigned char)*ptr))
return 0;
}
@ -388,7 +528,7 @@ unsigned string_hex_to_unsigned(const char *str)
/* Check for valid characters */
for (ptr = hex_str; *ptr != '\0'; ptr++)
{
if (!isxdigit(*ptr))
if (!isxdigit((unsigned char)*ptr))
return 0;
}

View File

@ -30,6 +30,7 @@
#include <time/rtime.h>
#ifdef HAVE_THREADS
/* TODO/FIXME - global */
slock_t *rtime_localtime_lock = NULL;
#endif

View File

@ -62,6 +62,9 @@
# include <sys/dirent.h>
# include <orbisFile.h>
# endif
# if defined(WIIU)
# include <malloc.h>
# endif
#endif
#include <fcntl.h>
@ -130,6 +133,13 @@
#include <pspkernel.h>
#endif
#if defined(__PS3__) || defined(__PSL1GHT__)
#include <defines/ps3_defines.h>
#if defined(__PSL1GHT__)
#include <lv2/sysfs.h>
#endif
#endif
#if defined(VITA)
#define FIO_S_ISDIR SCE_S_ISDIR
#endif
@ -148,14 +158,16 @@
#endif
#if defined(_WIN32)
#if !defined(_MSC_VER) || (defined(_MSC_VER) && _MSC_VER >= 1400)
#if defined(_MSC_VER) && _MSC_VER >= 1400
#define ATLEAST_VC2005
#endif
#endif
#include <vfs/vfs_implementation.h>
#include <libretro.h>
#if defined(HAVE_MMAP)
#include <memmap.h>
#endif
#include <encodings/utf.h>
#include <compat/fopen_utf8.h>
#include <file/file_path.h>
@ -164,7 +176,7 @@
#include <vfs/vfs_implementation_cdrom.h>
#endif
#if (defined(_POSIX_C_SOURCE) && (_POSIX_C_SOURCE - 0) >= 200112) || (defined(__POSIX_VISIBLE) && __POSIX_VISIBLE >= 200112) || (defined(_POSIX_VERSION) && _POSIX_VERSION >= 200112) || __USE_LARGEFILE
#if (defined(_POSIX_C_SOURCE) && (_POSIX_C_SOURCE - 0) >= 200112) || (defined(__POSIX_VISIBLE) && __POSIX_VISIBLE >= 200112) || (defined(_POSIX_VERSION) && _POSIX_VERSION >= 200112) || __USE_LARGEFILE || (defined(_FILE_OFFSET_BITS) && _FILE_OFFSET_BITS == 64)
#ifndef HAVE_64BIT_OFFSETS
#define HAVE_64BIT_OFFSETS
#endif
@ -238,7 +250,7 @@ int64_t retro_vfs_file_seek_internal(
}
#endif
if (lseek(stream->fd, offset, whence) < 0)
if (lseek(stream->fd, (off_t)offset, whence) < 0)
return -1;
return 0;
@ -433,7 +445,22 @@ libretro_vfs_implementation_file *retro_vfs_file_open_impl(
*/
/* TODO: this is only useful for a few platforms,
* 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)
{
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)
return -1;
#elif !defined(VITA) && !defined(PSP) && !defined(PS2) && !defined(ORBIS) && (!defined(SWITCH) || defined(HAVE_LIBNX))
if (ftruncate(fileno(stream->fp), length) != 0)
if (ftruncate(fileno(stream->fp), (off_t)length) != 0)
return -1;
#endif
@ -902,6 +929,19 @@ int retro_vfs_stat_impl(const char *path, int32_t *size)
orbisDclose(dir_ret);
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)
/* Windows */
DWORD file_info;
@ -941,6 +981,40 @@ int retro_vfs_stat_impl(const char *path, int32_t *size)
*size = (int32_t)buf.st_size;
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
/* Every other platform */
struct stat buf;
@ -990,6 +1064,28 @@ int retro_vfs_mkdir_impl(const char *dir)
int ret = orbisMkdir(dir, 0755);
#elif defined(__QNX__)
int ret = mkdir(dir, 0777);
#elif defined(GEKKO)
/* On GEKKO platforms, mkdir() fails if
* the path has a trailing slash. We must
* therefore remove it. */
int ret = -1;
if (!string_is_empty(dir))
{
char *dir_buf = strdup(dir);
if (dir_buf)
{
size_t len = strlen(dir_buf);
if (len > 0)
if (dir_buf[len - 1] == '/')
dir_buf[len - 1] = '\0';
ret = mkdir(dir_buf, 0750);
free(dir_buf);
}
}
#else
int ret = mkdir(dir, 0750);
#endif
@ -1018,6 +1114,10 @@ struct libretro_vfs_implementation_dir
#elif defined(VITA) || defined(PSP)
SceUID directory;
SceIoDirent entry;
#elif defined(__PSL1GHT__) || defined(__PS3__)
int error;
int directory;
sysFSDirent entry;
#elif defined(ORBIS)
int directory;
struct dirent entry;
@ -1033,6 +1133,8 @@ static bool dirent_check_error(libretro_vfs_implementation_dir *rdir)
return (rdir->directory == INVALID_HANDLE_VALUE);
#elif defined(VITA) || defined(PSP) || defined(ORBIS)
return (rdir->directory < 0);
#elif defined(__PSL1GHT__) || defined(__PS3__)
return (rdir->error != FS_SUCCEEDED);
#else
return !(rdir->directory);
#endif
@ -1096,6 +1198,8 @@ libretro_vfs_implementation_dir *retro_vfs_opendir_impl(
#elif defined(_3DS)
rdir->directory = !string_is_empty(name) ? opendir(name) : NULL;
rdir->entry = NULL;
#elif defined(__PSL1GHT__) || defined(__PS3__)
rdir->error = sysFsOpendir(name, &rdir->directory);
#elif defined(ORBIS)
rdir->directory = orbisDopen(name);
#else
@ -1131,6 +1235,10 @@ bool retro_vfs_readdir_impl(libretro_vfs_implementation_dir *rdir)
return (rdir->directory != INVALID_HANDLE_VALUE);
#elif defined(VITA) || defined(PSP)
return (sceIoDread(rdir->directory, &rdir->entry) > 0);
#elif defined(__PSL1GHT__) || defined(__PS3__)
uint64_t nread;
rdir->error = sysFsReaddir(rdir->directory, &rdir->entry, &nread);
return (nread != 0);
#elif defined(ORBIS)
return (orbisDread(rdir->directory, &rdir->entry) > 0);
#else
@ -1151,7 +1259,7 @@ const char *retro_vfs_dirent_get_name_impl(libretro_vfs_implementation_dir *rdir
if (name)
free(name);
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;
#else
if (!rdir || !rdir->entry)
@ -1172,6 +1280,9 @@ bool retro_vfs_dirent_is_dir_impl(libretro_vfs_implementation_dir *rdir)
#elif defined(VITA)
return SCE_S_ISDIR(entry->d_stat.st_mode);
#endif
#elif defined(__PSL1GHT__) || defined(__PS3__)
sysFSDirent *entry = (sysFSDirent*)&rdir->entry;
return (entry->d_type == FS_TYPE_DIR);
#elif defined(ORBIS)
const struct dirent *entry = &rdir->entry;
if (entry->d_type == DT_DIR)
@ -1208,6 +1319,8 @@ int retro_vfs_closedir_impl(libretro_vfs_implementation_dir *rdir)
FindClose(rdir->directory);
#elif defined(VITA) || defined(PSP)
sceIoDclose(rdir->directory);
#elif defined(__PSL1GHT__) || defined(__PS3__)
rdir->error = sysFsClosedir(rdir->directory);
#elif defined(ORBIS)
orbisDclose(rdir->directory);
#else

View File

@ -25,6 +25,7 @@
*/
#include "blipper.h"
#include "gambatte_log.h"
#include <stdlib.h>
#include <stdio.h>
@ -71,7 +72,9 @@ void blipper_free(blipper_t *blip)
if (blip)
{
#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
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. */
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;
}
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;
}

View 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);
}

View 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

View File

@ -2,6 +2,7 @@
#include <libretro.h>
#include <libretro_core_options.h>
#include "gambatte_log.h"
#include "blipper.h"
#include "gambatte.h"
#include "gbcpalettes.h"
@ -15,6 +16,16 @@
#undef __STRICT_ANSI__
#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 <cassert>
@ -32,7 +43,6 @@ extern "C" void* linearMemAlign(size_t size, size_t alignment);
extern "C" void linearFree(void* mem);
#endif
retro_log_printf_t log_cb;
static retro_video_refresh_t video_cb;
static retro_input_poll_t input_poll_cb;
static retro_input_state_t input_state_cb;
@ -709,7 +719,7 @@ static bool update_option_visibility(void)
#endif
/* Fast forward override */
void set_fastforward_override(bool fastforward)
static void set_fastforward_override(bool fastforward)
{
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);
}
bool file_present_in_system(std::string fname)
static bool file_present_in_system(const char *fname)
{
const char *systemdirtmp = NULL;
bool worked = environ_cb(RETRO_ENVIRONMENT_GET_SYSTEM_DIRECTORY, &systemdirtmp);
if (!worked)
const char *system_dir = NULL;
char full_path[PATH_MAX_LENGTH];
full_path[0] = '\0';
if (string_is_empty(fname))
return false;
std::string fullpath = systemdirtmp;
fullpath += "/";
fullpath += fname;
RFILE *fp = filestream_open(fullpath.c_str(), RETRO_VFS_FILE_ACCESS_READ,
RETRO_VFS_FILE_ACCESS_HINT_NONE);
if (fp)
/* Get system directory */
if (!environ_cb(RETRO_ENVIRONMENT_GET_SYSTEM_DIRECTORY, &system_dir) ||
!system_dir)
{
filestream_close(fp);
return true;
gambatte_log(RETRO_LOG_WARN,
"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;
unsigned int size;
RFILE *fp = NULL;
int64_t n = 0;
bool worked = false;
const char *systemdirtmp = NULL;
const char *system_dir = NULL;
const char *bios_name = NULL;
RFILE *bios_file = NULL;
int64_t bios_size = 0;
int64_t bytes_read = 0;
char bios_path[PATH_MAX_LENGTH];
bios_path[0] = '\0';
if (!use_official_bootloader)
return false;
// get path
worked = environ_cb(RETRO_ENVIRONMENT_GET_SYSTEM_DIRECTORY, &systemdirtmp);
if (!worked)
/* Get system directory */
if (!environ_cb(RETRO_ENVIRONMENT_GET_SYSTEM_DIRECTORY, &system_dir) ||
!system_dir)
{
gambatte_log(RETRO_LOG_WARN,
"No system directory defined, unable to look for bootloader.\n");
return false;
}
path = systemdirtmp;
path += "/"; //retroarch/libretro does not add a slash at the end of directory names
/* Get BIOS type */
if (isgbc)
{
path += "gbc_bios.bin";
size = 0x900;
bios_name = "gbc_bios.bin";
bios_size = 0x900;
}
else
{
path += "gb_bios.bin";
size = 0x100;
bios_name = "gb_bios.bin";
bios_size = 0x100;
}
if (size > buf_size)
if (bios_size > buf_size)
return false;
// open file
fp = filestream_open(path.c_str(), RETRO_VFS_FILE_ACCESS_READ,
/* Get BIOS path */
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);
if (!fp)
if (!bios_file)
return false;
n = filestream_read(fp, data, size);
filestream_close(fp);
bytes_read = filestream_read(bios_file,
data, bios_size);
filestream_close(bios_file);
if (n != size)
if (bytes_read != bios_size)
return false;
gambatte_log(RETRO_LOG_INFO, "Read bootloader: %s\n", bios_path);
return true;
}
@ -962,16 +987,14 @@ static void check_system_specs(void)
environ_cb(RETRO_ENVIRONMENT_SET_PERFORMANCE_LEVEL, &level);
}
static void log_null(enum retro_log_level level, const char *fmt, ...) {}
void retro_init(void)
{
struct retro_log_callback log;
if (environ_cb(RETRO_ENVIRONMENT_GET_LOG_INTERFACE, &log))
log_cb = log.log;
gambatte_log_set_cb(log.log);
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.
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
{
GB_COLORIZATION_DISABLED = 0,
@ -1248,110 +1249,174 @@ static char internal_game_name[17];
static void load_custom_palette(void)
{
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;
environ_cb(RETRO_ENVIRONMENT_GET_SYSTEM_DIRECTORY, &system_directory_c);
if (!system_directory_c)
palette_path[0] = '\0';
/* 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;
}
std::string system_directory(system_directory_c);
std::string custom_palette_path = system_directory + "/palettes/" + basename(rom_path) + ".pal";
std::ifstream palette_file(custom_palette_path.c_str()); // try to open the palette file in read-only mode
if (!palette_file.is_open())
/* Look for palette named after ROM file */
rom_file = path_basename(rom_path.c_str());
if (!string_is_empty(rom_file))
{
// try again with the internal game name from the ROM header
custom_palette_path = system_directory + "/palettes/" + std::string(internal_game_name) + ".pal";
palette_file.open(custom_palette_path.c_str());
size_t len = (strlen(rom_file) + 1) * sizeof(char);
rom_name = (char*)malloc(len);
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
//- removed last line if colorization is enabled
custom_palette_path = system_directory + "/palettes/" + "default.pal";
palette_file.open(custom_palette_path.c_str());
/* Look for palette named after the internal game
* name in the ROM header */
fill_pathname_join_special_ext(palette_path,
system_dir, "palettes", internal_game_name, ".pal",
sizeof(palette_path));
path_valid = path_is_valid(palette_path);
}
if (!palette_file.is_open())
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
if (!path_valid)
{
line_count++;
if (line[0]=='[') // skip ini sections
continue;
if (line[0]==';') // skip ini comments
continue;
if (line[0]=='\n') // skip empty lines
continue;
if (line.find("=") == std::string::npos)
{
log_cb(RETRO_LOG_WARN, "[Gambatte]: error in %s, line %d (color left as default).\n", custom_palette_path.c_str(), line_count);
continue; // current line does not contain a palette color definition, so go to next line
/* 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);
}
// Supposed to be a typo here.
if (startswith(line, "slectedScheme="))
continue;
if (!path_valid)
return; /* Unable to find any custom palette file */
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)
palette_file = filestream_open(palette_path,
RETRO_VFS_FILE_ACCESS_READ,
RETRO_VFS_FILE_ACCESS_HINT_NONE);
if (!palette_file)
{
log_cb(RETRO_LOG_WARN, "[Gambatte]: unable to read palette color in %s, line %d (color left as default).\n",
custom_palette_path.c_str(), line_count);
continue;
gambatte_log(RETRO_LOG_WARN,
"Failed to open custom palette: %s\n", palette_path);
return;
}
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))
{
gambatte_log(RETRO_LOG_WARN,
"Error in %s, line %u (color left as default)\n",
palette_path, line_index);
goto palette_line_end;
}
/* Extract colour value */
rgb32 = string_to_unsigned(value_str);
if (rgb32 == 0)
{
/* string_to_unsigned() will return 0 if
* string is invalid, so perform a manual
* 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
rgb32=(rgb32&0x0000F8)>>3 |//blue
(rgb32&0x00FC00)>>5 |//green
(rgb32&0xF80000)>>8;//red
rgb32 = (rgb32 & 0x0000F8) >> 3 | /* blue */
(rgb32 & 0x00FC00) >> 5 | /* green */
(rgb32 & 0xF80000) >> 8; /* red */
#elif defined(VIDEO_ABGR1555)
rgb32=(rgb32&0x0000F8)<<7 |//blue
(rgb32&0xF800)>>6 |//green
(rgb32&0xF80000)>>19;//red
rgb32 = (rgb32 & 0x0000F8) << 7 | /* blue */
(rgb32 & 0xF800) >> 6 | /* green */
(rgb32 & 0xF80000) >> 19; /* red */
#endif
if (startswith(line, "Background0="))
if ( string_starts_with(line, "Background0="))
gb.setDmgPaletteColor(0, 0, rgb32);
else if (startswith(line, "Background1="))
else if (string_starts_with(line, "Background1="))
gb.setDmgPaletteColor(0, 1, rgb32);
else if (startswith(line, "Background2="))
else if (string_starts_with(line, "Background2="))
gb.setDmgPaletteColor(0, 2, rgb32);
else if (startswith(line, "Background3="))
else if (string_starts_with(line, "Background3="))
gb.setDmgPaletteColor(0, 3, rgb32);
else if (startswith(line, "Sprite%2010="))
else if (string_starts_with(line, "Sprite%2010="))
gb.setDmgPaletteColor(1, 0, rgb32);
else if (startswith(line, "Sprite%2011="))
else if (string_starts_with(line, "Sprite%2011="))
gb.setDmgPaletteColor(1, 1, rgb32);
else if (startswith(line, "Sprite%2012="))
else if (string_starts_with(line, "Sprite%2012="))
gb.setDmgPaletteColor(1, 2, rgb32);
else if (startswith(line, "Sprite%2013="))
else if (string_starts_with(line, "Sprite%2013="))
gb.setDmgPaletteColor(1, 3, rgb32);
else if (startswith(line, "Sprite%2020="))
else if (string_starts_with(line, "Sprite%2020="))
gb.setDmgPaletteColor(2, 0, rgb32);
else if (startswith(line, "Sprite%2021="))
else if (string_starts_with(line, "Sprite%2021="))
gb.setDmgPaletteColor(2, 1, rgb32);
else if (startswith(line, "Sprite%2022="))
else if (string_starts_with(line, "Sprite%2022="))
gb.setDmgPaletteColor(2, 2, rgb32);
else if (startswith(line, "Sprite%2023="))
else if (string_starts_with(line, "Sprite%2023="))
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);
} // endfor
else
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)
@ -1733,14 +1798,14 @@ bool retro_load_game(const struct retro_game_info *info)
environ_cb(RETRO_ENVIRONMENT_GET_CAN_DUPE, &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;
}
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
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[] = {
{ 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;
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;
}
#else
enum retro_pixel_format fmt = RETRO_PIXEL_FORMAT_XRGB8888;
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;
}
#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);
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();

View File

@ -1,5 +1,6 @@
#include "net_serial.h"
#include "libretro.h"
#include "gambatte_log.h"
#include <iostream>
#include <stdio.h>
#include <stdlib.h>
@ -17,9 +18,9 @@
#include <netdb.h>
#endif
extern retro_log_printf_t log_cb;
//FILE* fpout;
//FILE* fpin;
NetSerial::NetSerial()
: is_stopped_(true)
, is_server_(false)
@ -44,7 +45,7 @@ bool NetSerial::start(bool is_server, int port, const std::string& hostname)
{
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_ = is_server;
port_ = port;
@ -56,7 +57,7 @@ bool NetSerial::start(bool is_server, int port, const std::string& hostname)
void NetSerial::stop()
{
if (!is_stopped_) {
log_cb(RETRO_LOG_INFO, "Stoping GameLink nework\n");
gambatte_log(RETRO_LOG_INFO, "Stopping GameLink network\n");
is_stopped_ = true;
if (sockfd_ >= 0) {
close(sockfd_);
@ -109,23 +110,23 @@ bool NetSerial::startServerSocket()
int fd = socket(AF_INET, SOCK_STREAM, 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;
}
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);
return false;
}
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);
return false;
}
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;
@ -154,10 +155,10 @@ bool NetSerial::acceptClient()
socklen_t client_len = sizeof(client_addr);
sockfd_ = accept(server_fd_, (struct sockaddr*)&client_addr, &client_len);
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;
}
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;
}
@ -173,25 +174,25 @@ bool NetSerial::startClientSocket()
int fd = socket(AF_INET, SOCK_STREAM, 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;
}
struct hostent* server_hostname = gethostbyname(hostname_.c_str());
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);
return false;
}
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) {
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);
return false;
}
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;
}
@ -220,7 +221,7 @@ unsigned char NetSerial::send(unsigned char data, bool fastCgb)
if (write(sockfd_, buffer, 2) <= 0)
#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_);
sockfd_ = -1;
return 0xFF;
@ -233,7 +234,7 @@ unsigned char NetSerial::send(unsigned char data, bool fastCgb)
if (read(sockfd_, buffer, 2) <= 0)
#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_);
sockfd_ = -1;
return 0xFF;
@ -271,7 +272,7 @@ bool NetSerial::check(unsigned char out, unsigned char& in, bool& fastCgb)
if (ioctl(sockfd_, FIONREAD, &bytes_avail) < 0)
#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;
}
@ -286,7 +287,7 @@ bool NetSerial::check(unsigned char out, unsigned char& in, bool& fastCgb)
if (read(sockfd_, buffer, 2) <= 0)
#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_);
sockfd_ = -1;
return false;
@ -306,7 +307,7 @@ bool NetSerial::check(unsigned char out, unsigned char& in, bool& fastCgb)
if (write(sockfd_, buffer, 2) <= 0)
#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_);
sockfd_ = -1;
return false;

View File

@ -23,6 +23,7 @@
#include <stdio.h>
#include <string.h>
#include <algorithm>
#include "gambatte_log.h"
extern void cartridge_set_rumble(unsigned active);
@ -383,16 +384,16 @@ namespace gambatte
switch (p >> 13 & 3) {
case 0:
ramflag_ = data;
//printf("[HuC3] set ramflag to %02X\n", data);
//gambatte_log(RETRO_LOG_DEBUG, "<HuC3> set ramflag to %02X\n", data);
setRambank();
break;
case 1:
//printf("[HuC3] set rombank to %02X\n", data);
//gambatte_log(RETRO_LOG_DEBUG, "<HuC3> set rombank to %02X\n", data);
rombank_ = data;
setRombank();
break;
case 2:
//printf("[HuC3] set rambank to %02X\n", data);
//gambatte_log(RETRO_LOG_DEBUG, "<HuC3> set rambank to %02X\n", data);
rambank_ = data;
setRambank();
break;
@ -552,38 +553,38 @@ namespace gambatte
switch (header[0x0147])
{
case 0x00: printf("Plain ROM loaded.\n"); type = PLAIN; break;
case 0x01: printf("MBC1 ROM loaded.\n"); type = MBC1; break;
case 0x02: printf("MBC1 ROM+RAM loaded.\n"); type = MBC1; break;
case 0x03: printf("MBC1 ROM+RAM+BATTERY loaded.\n"); type = MBC1; break;
case 0x05: printf("MBC2 ROM loaded.\n"); type = MBC2; break;
case 0x06: printf("MBC2 ROM+BATTERY loaded.\n"); type = MBC2; break;
case 0x08: printf("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 0x0B: printf("MM01 ROM not supported.\n"); return -1;
case 0x0C: printf("MM01 ROM not supported.\n"); return -1;
case 0x0D: printf("MM01 ROM not supported.\n"); return -1;
case 0x0F: printf("MBC3 ROM+TIMER+BATTERY loaded.\n"); type = MBC3; break;
case 0x10: printf("MBC3 ROM+TIMER+RAM+BATTERY loaded.\n"); type = MBC3; break;
case 0x11: printf("MBC3 ROM loaded.\n"); type = MBC3; break;
case 0x12: printf("MBC3 ROM+RAM loaded.\n"); type = MBC3; break;
case 0x13: printf("MBC3 ROM+RAM+BATTERY loaded.\n"); type = MBC3; break;
case 0x15: printf("MBC4 ROM not supported.\n"); return -1;
case 0x16: printf("MBC4 ROM not supported.\n"); return -1;
case 0x17: printf("MBC4 ROM not supported.\n"); return -1;
case 0x19: printf("MBC5 ROM loaded.\n"); type = MBC5; break;
case 0x1A: printf("MBC5 ROM+RAM loaded.\n"); type = MBC5; break;
case 0x1B: printf("MBC5 ROM+RAM+BATTERY loaded.\n"); type = MBC5; break;
case 0x1C: printf("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 0x1E: printf("MBC5+RUMBLE+RAM+BATTERY ROM loaded.\n"); type = MBC5; rumble = true; break;
case 0x20: printf("MBC6 ROM not supported.\n"); return -1;
case 0x22: printf("MBC7 ROM not supported.\n"); return -1;
case 0xFC: printf("Pocket Camera ROM not supported.\n"); return -1;
case 0xFD: printf("Bandai TAMA5 ROM not supported.\n"); return -1;
case 0xFE: printf("HuC3 ROM+RAM+BATTERY loaded.\n"); type = HUC3; break;
case 0xFF: printf("HuC1 ROM+BATTERY loaded.\n"); type = HUC1; break;
default: printf("Wrong data-format, corrupt or unsupported ROM.\n"); return -1;
case 0x00: gambatte_log(RETRO_LOG_INFO, "Plain ROM loaded.\n"); type = PLAIN; break;
case 0x01: gambatte_log(RETRO_LOG_INFO, "MBC1 ROM loaded.\n"); type = MBC1; break;
case 0x02: gambatte_log(RETRO_LOG_INFO, "MBC1 ROM+RAM loaded.\n"); type = MBC1; break;
case 0x03: gambatte_log(RETRO_LOG_INFO, "MBC1 ROM+RAM+BATTERY loaded.\n"); type = MBC1; break;
case 0x05: gambatte_log(RETRO_LOG_INFO, "MBC2 ROM loaded.\n"); type = MBC2; break;
case 0x06: gambatte_log(RETRO_LOG_INFO, "MBC2 ROM+BATTERY loaded.\n"); type = MBC2; break;
case 0x08: gambatte_log(RETRO_LOG_INFO, "Plain ROM with additional RAM 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: gambatte_log(RETRO_LOG_INFO, "MM01 ROM not supported.\n"); return -1;
case 0x0C: gambatte_log(RETRO_LOG_INFO, "MM01 ROM not supported.\n"); return -1;
case 0x0D: gambatte_log(RETRO_LOG_INFO, "MM01 ROM not supported.\n"); return -1;
case 0x0F: gambatte_log(RETRO_LOG_INFO, "MBC3 ROM+TIMER+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: gambatte_log(RETRO_LOG_INFO, "MBC3 ROM loaded.\n"); type = MBC3; break;
case 0x12: gambatte_log(RETRO_LOG_INFO, "MBC3 ROM+RAM loaded.\n"); type = MBC3; break;
case 0x13: gambatte_log(RETRO_LOG_INFO, "MBC3 ROM+RAM+BATTERY loaded.\n"); type = MBC3; break;
case 0x15: gambatte_log(RETRO_LOG_INFO, "MBC4 ROM not supported.\n"); return -1;
case 0x16: gambatte_log(RETRO_LOG_INFO, "MBC4 ROM not supported.\n"); return -1;
case 0x17: gambatte_log(RETRO_LOG_INFO, "MBC4 ROM not supported.\n"); return -1;
case 0x19: gambatte_log(RETRO_LOG_INFO, "MBC5 ROM loaded.\n"); type = MBC5; break;
case 0x1A: gambatte_log(RETRO_LOG_INFO, "MBC5 ROM+RAM loaded.\n"); type = MBC5; break;
case 0x1B: gambatte_log(RETRO_LOG_INFO, "MBC5 ROM+RAM+BATTERY loaded.\n"); type = MBC5; break;
case 0x1C: gambatte_log(RETRO_LOG_INFO, "MBC5+RUMBLE 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: gambatte_log(RETRO_LOG_INFO, "MBC5+RUMBLE+RAM+BATTERY ROM loaded.\n"); type = MBC5; rumble = true; break;
case 0x20: gambatte_log(RETRO_LOG_INFO, "MBC6 ROM not supported.\n"); return -1;
case 0x22: gambatte_log(RETRO_LOG_INFO, "MBC7 ROM not supported.\n"); return -1;
case 0xFC: gambatte_log(RETRO_LOG_INFO, "Pocket Camera ROM not supported.\n"); return -1;
case 0xFD: gambatte_log(RETRO_LOG_INFO, "Bandai TAMA5 ROM not supported.\n"); return -1;
case 0xFE: gambatte_log(RETRO_LOG_INFO, "HuC3 ROM+RAM+BATTERY loaded.\n"); type = HUC3; break;
case 0xFF: gambatte_log(RETRO_LOG_INFO, "HuC1 ROM+BATTERY loaded.\n"); type = HUC1; break;
default: gambatte_log(RETRO_LOG_INFO, "Wrong data-format, corrupt or unsupported ROM.\n"); return -1;
}
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);
printf("rombanks: %u\n", static_cast<unsigned>(romsize / 0x4000));
gambatte_log(RETRO_LOG_INFO, "rombanks: %u\n", static_cast<unsigned>(romsize / 0x4000));
ggUndoList_.clear();
mbc.reset();

View File

@ -5,8 +5,6 @@
#include <libretro.h>
extern retro_log_printf_t log_cb;
namespace gambatte
{
static bool hasBattery(unsigned char headerByte0x147)

View File

@ -19,6 +19,7 @@
#include "huc3.h"
#include "../savestate.h"
#include <stdio.h>
#include "gambatte_log.h"
namespace gambatte {
@ -113,7 +114,7 @@ unsigned char HuC3Chip::read(unsigned p, unsigned long const cc) {
}
}
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;
}
if(ramflag_ == 0x0D) return 1;