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 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)/../libretro/blipper.c
SOURCES_CXX := \
$(CORE_DIR)/bootloader.cpp \
$(CORE_DIR)/cpu.cpp \ $(CORE_DIR)/cpu.cpp \
$(CORE_DIR)/gambatte.cpp \ $(CORE_DIR)/gambatte.cpp \
$(CORE_DIR)/initstate.cpp \ $(CORE_DIR)/initstate.cpp \
@ -38,21 +48,23 @@ SOURCES_CXX := $(CORE_DIR)/bootloader.cpp \
$(CORE_DIR)/../libretro/libretro.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)/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 \
$(LIBRETRO_COMM_DIR)/compat/compat_posix_string.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_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)/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)/string/stdstring.c \
$(LIBRETRO_COMM_DIR)/encodings/encoding_utf.c $(LIBRETRO_COMM_DIR)/time/rtime.c \
$(LIBRETRO_COMM_DIR)/vfs/vfs_implementation.c
endif endif

View File

@ -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 */ /* 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; 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;

View File

@ -49,8 +49,13 @@ 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;
if (filename_w && mode_w)
ret = _wfopen(filename_w, mode_w);
if (filename_w)
free(filename_w); free(filename_w);
if (mode_w)
free(mode_w); free(mode_w);
return ret; return ret;
#endif #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, 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,8 +297,9 @@ 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)
{ return strdup(str);
path_buf_wide = (wchar_t*) path_buf_wide = (wchar_t*)
calloc(path_buf_wide_len + sizeof(wchar_t), sizeof(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) 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); path_buf_wide, -1, NULL, 0, NULL, NULL);
if (path_buf_len) if (path_buf_len)
{ {
path_buf = (char*) char *path_buf = (char*)
calloc(path_buf_len + sizeof(char), sizeof(char)); calloc(path_buf_len + sizeof(char), sizeof(char));
if (path_buf) if (path_buf)
@ -340,13 +339,9 @@ static char *mb_to_mb_string_alloc(const char *str,
return strdup(str); return strdup(str);
} }
} }
}
}
else
return strdup(str);
if (path_buf_wide)
free(path_buf_wide); free(path_buf_wide);
}
return NULL; return NULL;
} }

View File

@ -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,15 +87,23 @@ 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
if (!delim) * is directly *after* a compression extension */
return NULL; delim = strchr(last_slash, '#');
while (delim)
{
/* Check whether this is a known archive type /* Check whether this is a known archive type
* > Note: The code duplication here is * > Note: The code duplication here is
* deliberate, to maximise performance */ * deliberate, to maximise performance */
@ -158,6 +132,10 @@ const char *path_get_archive_delim(const char *path)
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;
if (string_is_equal_noncase(ext, "zip") ||
string_is_equal_noncase(ext, "apk") || string_is_equal_noncase(ext, "apk") ||
string_is_equal_noncase(ext, "7z")) string_is_equal_noncase(ext, "7z"))
return true; 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)
{
if (_wfullpath(abs_path, rel_path, PATH_MAX_LENGTH))
{
char *tmp = utf16_to_utf8_string_alloc(abs_path);
if (tmp)
{ {
strlcpy(buf, tmp, size); strlcpy(buf, tmp, size);
return NULL; free(tmp);
ret = buf;
} }
return buf; }
free(rel_path);
}
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;
@ -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;
} }

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" { 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

View File

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

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

View File

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

View File

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

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

View File

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

View File

@ -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;
@ -108,7 +110,8 @@ bool filestream_exists(const char *path)
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,10 +356,13 @@ 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;
@ -378,7 +408,7 @@ 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;
@ -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)
{ {

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 <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)
unsigned counter; return;
int pos = (int)(&buffer[i] - buffer);
/* copy string until the end of the line is reached */ /* Early return if src string length is less
for (counter = 1; counter <= (unsigned)line_width; counter++) * than line width */
if (src_len < line_width)
{
strcpy(dst, src);
return;
}
while (*src != '\0')
{ {
const char *character;
unsigned char_len; unsigned char_len;
unsigned j = i;
/* check if end of string reached */ char_len = (unsigned)(utf8skip(src, 1) - src);
if (i == len) counter++;
{
buffer[i] = 0; if (*src == ' ')
return buffer; lastspace = dst; /* Remember the location of the whitespace */
} else if (*src == '\n')
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')
{ {
/* If newlines embedded in the input,
* reset the index */
lines++; 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 */ while (char_len--)
if (string[i] == ' ') *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'; /* 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 */ *dst = '\0';
for (k = i; k > 0; k--) }
{
if (string[k] != ' ' || (max_lines != 0 && lines >= max_lines))
continue;
buffer[k] = '\n'; void word_wrap_wideglyph(char *dst, size_t dst_size, const char *src, int line_width, int wideglyph_width, unsigned max_lines)
/* set string index back to character after this one */ {
i = k + 1; char *lastspace = NULL;
lines++; 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; 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) dst_size -= char_len;
return buffer; 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; *dst = '\0';
return buffer;
} }
/* 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;
} }

View File

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

View File

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

View File

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

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.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)
{ {
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; 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,
if (line[0]=='[') // skip ini sections system_dir, "palettes", "default", ".pal",
continue; sizeof(palette_path));
path_valid = path_is_valid(palette_path);
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
} }
// Supposed to be a typo here. if (!path_valid)
if (startswith(line, "slectedScheme=")) return; /* Unable to find any custom palette file */
continue;
std::string line_value = line.substr(line.find("=") + 1); // extract the color value string palette_file = filestream_open(palette_path,
std::stringstream ss(line_value); // convert the color value to int RETRO_VFS_FILE_ACCESS_READ,
ss >> rgb32; RETRO_VFS_FILE_ACCESS_HINT_NONE);
if (!ss)
if (!palette_file)
{ {
log_cb(RETRO_LOG_WARN, "[Gambatte]: unable to read palette color in %s, line %d (color left as default).\n", gambatte_log(RETRO_LOG_WARN,
custom_palette_path.c_str(), line_count); "Failed to open custom palette: %s\n", palette_path);
continue; 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 #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();

View File

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

View File

@ -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();

View File

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

View File

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