Merge pull request #150 from Aftnet/master

Updated vfs.h to match current libretro common
This commit is contained in:
LibretroAdmin 2024-06-28 17:50:49 -05:00 committed by GitHub
commit 2c726f25da
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
32 changed files with 3346 additions and 1601 deletions

View File

@ -60,10 +60,3 @@ size_t strlcat(char *dest, const char *source, size_t size)
return len + strlcpy(dest, source, size);
}
#endif
char *strldup(const char *s, size_t n)
{
char *dst = (char*)malloc(sizeof(char) * (n + 1));
strlcpy(dst, s, n);
return dst;
}

View File

@ -37,27 +37,28 @@
void *fopen_utf8(const char * filename, const char * mode)
{
#if defined(LEGACY_WIN32)
FILE *ret = NULL;
char * filename_local = utf8_to_local_string_alloc(filename);
if (!filename_local)
return NULL;
ret = fopen(filename_local, mode);
if (filename_local)
{
FILE *ret = fopen(filename_local, mode);
free(filename_local);
return ret;
return ret;
}
#else
wchar_t * filename_w = utf8_to_utf16_string_alloc(filename);
wchar_t * mode_w = utf8_to_utf16_string_alloc(mode);
FILE* ret = NULL;
if (filename_w && mode_w)
ret = _wfopen(filename_w, mode_w);
wchar_t * filename_w = utf8_to_utf16_string_alloc(filename);
if (filename_w)
{
FILE *ret = NULL;
wchar_t *mode_w = utf8_to_utf16_string_alloc(mode);
if (mode_w)
{
ret = _wfopen(filename_w, mode_w);
free(mode_w);
}
free(filename_w);
if (mode_w)
free(mode_w);
return ret;
return ret;
}
#endif
return NULL;
}
#endif

View File

@ -51,9 +51,12 @@ static unsigned leading_ones(uint8_t c)
return ones;
}
/* Simple implementation. Assumes the sequence is
* properly synchronized and terminated. */
/**
* utf8_conv_utf32:
*
* Simple implementation. Assumes the sequence is
* properly synchronized and terminated.
**/
size_t utf8_conv_utf32(uint32_t *out, size_t out_chars,
const char *in, size_t in_size)
{
@ -79,7 +82,7 @@ size_t utf8_conv_utf32(uint32_t *out, size_t out_chars,
for (i = 0; i < extra; i++, in++, shift -= 6)
c |= (*in & 0x3f) << shift;
*out++ = c;
*out++ = c;
in_size -= 1 + extra;
out_chars--;
ret++;
@ -88,6 +91,11 @@ size_t utf8_conv_utf32(uint32_t *out, size_t out_chars,
return ret;
}
/**
* utf16_conv_utf8:
*
* Leaf function.
**/
bool utf16_conv_utf8(uint8_t *out, size_t *out_chars,
const uint16_t *in, size_t in_size)
{
@ -148,16 +156,20 @@ bool utf16_conv_utf8(uint8_t *out, size_t *out_chars,
return false;
}
/* Acts mostly like strlcpy.
/**
* utf8cpy:
*
* Acts mostly like strlcpy.
*
* Copies the given number of UTF-8 characters,
* but at most d_len bytes.
* but at most @d_len bytes.
*
* Always NULL terminates.
* Does not copy half a character.
* Always NULL terminates. Does not copy half a character.
* @s is assumed valid UTF-8.
* Use only if @chars is considerably less than @d_len.
*
* Returns number of bytes. 's' is assumed valid UTF-8.
* Use only if 'chars' is considerably less than 'd_len'. */
* @return Number of bytes.
**/
size_t utf8cpy(char *d, size_t d_len, const char *s, size_t chars)
{
const uint8_t *sb = (const uint8_t*)s;
@ -186,6 +198,11 @@ size_t utf8cpy(char *d, size_t d_len, const char *s, size_t chars)
return sb-sb_org;
}
/**
* utf8skip:
*
* Leaf function
**/
const char *utf8skip(const char *str, size_t chars)
{
const uint8_t *strb = (const uint8_t*)str;
@ -204,6 +221,11 @@ const char *utf8skip(const char *str, size_t chars)
return (const char*)strb;
}
/**
* utf8len:
*
* Leaf function.
**/
size_t utf8len(const char *string)
{
size_t ret = 0;
@ -220,7 +242,15 @@ size_t utf8len(const char *string)
return ret;
}
/* Does not validate the input, returns garbage if it's not UTF-8. */
/**
* utf8_walk:
*
* Does not validate the input.
*
* Leaf function.
*
* @return Returns garbage if it's not UTF-8.
**/
uint32_t utf8_walk(const char **string)
{
uint8_t first = UTF8_WALKBYTE(string);
@ -248,24 +278,23 @@ static bool utf16_to_char(uint8_t **utf_data,
size_t *dest_len, const uint16_t *in)
{
unsigned len = 0;
while (in[len] != '\0')
len++;
utf16_conv_utf8(NULL, dest_len, in, len);
*dest_len += 1;
*utf_data = (uint8_t*)malloc(*dest_len);
if (*utf_data == 0)
return false;
return utf16_conv_utf8(*utf_data, dest_len, in, len);
if ((*utf_data = (uint8_t*)malloc(*dest_len)) != 0)
return utf16_conv_utf8(*utf_data, dest_len, in, len);
return false;
}
/**
* utf16_to_char_string:
**/
bool utf16_to_char_string(const uint16_t *in, char *s, size_t len)
{
size_t dest_len = 0;
uint8_t *utf16_data = NULL;
bool ret = utf16_to_char(&utf16_data, &dest_len, in);
size_t dest_len = 0;
uint8_t *utf16_data = NULL;
bool ret = utf16_to_char(&utf16_data, &dest_len, in);
if (ret)
{
@ -274,13 +303,17 @@ bool utf16_to_char_string(const uint16_t *in, char *s, size_t len)
}
free(utf16_data);
utf16_data = NULL;
utf16_data = NULL;
return ret;
}
#if defined(_WIN32) && !defined(_XBOX) && !defined(UNICODE)
/* Returned pointer MUST be freed by the caller if non-NULL. */
/**
* mb_to_mb_string_alloc:
*
* @return Returned pointer MUST be freed by the caller if non-NULL.
**/
static char *mb_to_mb_string_alloc(const char *str,
enum CodePage cp_in, enum CodePage cp_out)
{
@ -300,10 +333,8 @@ static char *mb_to_mb_string_alloc(const char *str,
if (!path_buf_wide_len)
return strdup(str);
path_buf_wide = (wchar_t*)
calloc(path_buf_wide_len + sizeof(wchar_t), sizeof(wchar_t));
if (path_buf_wide)
if ((path_buf_wide = (wchar_t*)
calloc(path_buf_wide_len + sizeof(wchar_t), sizeof(wchar_t))))
{
MultiByteToWideChar(cp_in, 0,
str, -1, path_buf_wide, path_buf_wide_len);
@ -347,45 +378,49 @@ static char *mb_to_mb_string_alloc(const char *str,
}
#endif
/* Returned pointer MUST be freed by the caller if non-NULL. */
/**
* utf8_to_local_string_alloc:
*
* @return Returned pointer MUST be freed by the caller if non-NULL.
**/
char* utf8_to_local_string_alloc(const char *str)
{
if (str && *str)
{
#if defined(_WIN32) && !defined(_XBOX) && !defined(UNICODE)
return mb_to_mb_string_alloc(str, CODEPAGE_UTF8, CODEPAGE_LOCAL);
#else
/* assume string needs no modification if not on Windows */
return strdup(str);
return strdup(str); /* Assume string needs no modification if not on Windows */
#endif
}
return NULL;
}
/* Returned pointer MUST be freed by the caller if non-NULL. */
char* local_to_utf8_string_alloc(const char *str)
/**
* local_to_utf8_string_alloc:
*
* @return Returned pointer MUST be freed by the caller if non-NULL.
**/
char *local_to_utf8_string_alloc(const char *str)
{
if (str && *str)
{
if (str && *str)
#if defined(_WIN32) && !defined(_XBOX) && !defined(UNICODE)
return mb_to_mb_string_alloc(str, CODEPAGE_LOCAL, CODEPAGE_UTF8);
return mb_to_mb_string_alloc(str, CODEPAGE_LOCAL, CODEPAGE_UTF8);
#else
/* assume string needs no modification if not on Windows */
return strdup(str);
return strdup(str); /* Assume string needs no modification if not on Windows */
#endif
}
return NULL;
return NULL;
}
/* Returned pointer MUST be freed by the caller if non-NULL. */
/**
* utf8_to_utf16_string_alloc:
*
* @return Returned pointer MUST be freed by the caller if non-NULL.
**/
wchar_t* utf8_to_utf16_string_alloc(const char *str)
{
#ifdef _WIN32
int len = 0;
int out_len = 0;
#else
size_t len = 0;
size_t out_len = 0;
#endif
wchar_t *buf = NULL;
@ -393,63 +428,55 @@ wchar_t* utf8_to_utf16_string_alloc(const char *str)
return NULL;
#ifdef _WIN32
len = MultiByteToWideChar(CP_UTF8, 0, str, -1, NULL, 0);
if (len)
if ((len = MultiByteToWideChar(CP_UTF8, 0, str, -1, NULL, 0)))
{
buf = (wchar_t*)calloc(len, sizeof(wchar_t));
if (!buf)
if (!(buf = (wchar_t*)calloc(len, sizeof(wchar_t))))
return NULL;
out_len = MultiByteToWideChar(CP_UTF8, 0, str, -1, buf, len);
if ((MultiByteToWideChar(CP_UTF8, 0, str, -1, buf, len)) < 0)
{
free(buf);
return NULL;
}
}
else
{
/* fallback to ANSI codepage instead */
len = MultiByteToWideChar(CP_ACP, 0, str, -1, NULL, 0);
if (len)
/* Fallback to ANSI codepage instead */
if ((len = MultiByteToWideChar(CP_ACP, 0, str, -1, NULL, 0)))
{
buf = (wchar_t*)calloc(len, sizeof(wchar_t));
if (!buf)
if (!(buf = (wchar_t*)calloc(len, sizeof(wchar_t))))
return NULL;
out_len = MultiByteToWideChar(CP_ACP, 0, str, -1, buf, len);
if ((MultiByteToWideChar(CP_ACP, 0, str, -1, buf, len)) < 0)
{
free(buf);
return NULL;
}
}
}
if (out_len < 0)
{
free(buf);
return NULL;
}
#else
/* NOTE: For now, assume non-Windows platforms' locale is already UTF-8. */
len = mbstowcs(NULL, str, 0) + 1;
if (len)
if ((len = mbstowcs(NULL, str, 0) + 1))
{
buf = (wchar_t*)calloc(len, sizeof(wchar_t));
if (!buf)
if (!(buf = (wchar_t*)calloc(len, sizeof(wchar_t))))
return NULL;
out_len = mbstowcs(buf, str, len);
}
if (out_len == (size_t)-1)
{
free(buf);
return NULL;
if ((mbstowcs(buf, str, len)) == (size_t)-1)
{
free(buf);
return NULL;
}
}
#endif
return buf;
}
/* Returned pointer MUST be freed by the caller if non-NULL. */
/**
* utf16_to_utf8_string_alloc:
*
* @return Returned pointer MUST be freed by the caller if non-NULL.
**/
char* utf16_to_utf8_string_alloc(const wchar_t *str)
{
#ifdef _WIN32
@ -465,20 +492,17 @@ char* utf16_to_utf8_string_alloc(const wchar_t *str)
#ifdef _WIN32
{
UINT code_page = CP_UTF8;
len = WideCharToMultiByte(code_page,
0, str, -1, NULL, 0, NULL, NULL);
/* fallback to ANSI codepage instead */
if (!len)
if (!(len = WideCharToMultiByte(code_page,
0, str, -1, NULL, 0, NULL, NULL)))
{
code_page = CP_ACP;
len = WideCharToMultiByte(code_page,
0, str, -1, NULL, 0, NULL, NULL);
}
buf = (char*)calloc(len, sizeof(char));
if (!buf)
if (!(buf = (char*)calloc(len, sizeof(char))))
return NULL;
if (WideCharToMultiByte(code_page,
@ -491,13 +515,9 @@ char* utf16_to_utf8_string_alloc(const wchar_t *str)
#else
/* NOTE: For now, assume non-Windows platforms'
* locale is already UTF-8. */
len = wcstombs(NULL, str, 0) + 1;
if (len)
if ((len = wcstombs(NULL, str, 0) + 1))
{
buf = (char*)calloc(len, sizeof(char));
if (!buf)
if (!(buf = (char*)calloc(len, sizeof(char))))
return NULL;
if (wcstombs(buf, str, len) == (size_t)-1)

File diff suppressed because it is too large Load Diff

View File

@ -24,13 +24,11 @@
#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>
@ -74,7 +72,7 @@ int path_stat(const char *path)
*
* Checks if path is a directory.
*
* Returns: true (1) if path is a directory, otherwise false (0).
* @return true if path is a directory, otherwise false.
*/
bool path_is_directory(const char *path)
{
@ -105,8 +103,10 @@ int32_t path_get_size(const char *path)
* @dir : directory
*
* Create directory on filesystem.
*
* Recursive function.
*
* Returns: true (1) if directory could be created, otherwise false (0).
* @return true if directory could be created, otherwise false.
**/
bool path_mkdir(const char *dir)
{
@ -118,12 +118,10 @@ bool path_mkdir(const char *dir)
/* Use heap. Real chance of stack
* overflow if we recurse too hard. */
basedir = strdup(dir);
if (!(basedir = strdup(dir)))
return false;
if (!basedir)
return false;
path_parent_dir(basedir);
path_parent_dir(basedir, strlen(basedir));
if (!*basedir || !strcmp(basedir, dir))
{

View File

@ -1,4 +1,4 @@
/* Copyright (C) 2010-2016 The RetroArch team
/* Copyright (C) 2010-2020 The RetroArch team
*
* ---------------------------------------------------------------------------------------
* The following license statement only applies to this file (apple_compat.h).
@ -20,6 +20,9 @@
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*/
#ifndef __APPLE_COMPAT_H
#define __APPLE_COMPAT_H
#ifdef __APPLE__
#include <AvailabilityMacros.h>
#endif
@ -32,6 +35,32 @@ typedef unsigned NSUInteger;
typedef float CGFloat;
#endif
#ifndef __has_feature
/* Compatibility with non-Clang compilers. */
#define __has_feature(x) 0
#endif
#ifndef CF_RETURNS_RETAINED
#if __has_feature(attribute_cf_returns_retained)
#define CF_RETURNS_RETAINED __attribute__((cf_returns_retained))
#else
#define CF_RETURNS_RETAINED
#endif
#endif
#ifndef NS_INLINE
#define NS_INLINE inline
#endif
NS_INLINE CF_RETURNS_RETAINED CFTypeRef CFBridgingRetainCompat(id X)
{
#if __has_feature(objc_arc)
return (__bridge_retained CFTypeRef)X;
#else
return X;
#endif
}
#endif
#ifdef IOS
@ -43,7 +72,13 @@ typedef float CGFloat;
#import <UIKit/UIKit.h>
#import <GLKit/GLKit.h>
#import <Foundation/Foundation.h>
#endif
#else
#ifdef __OBJC__
#include <objc/objc-runtime.h>
#endif
#endif
#endif

View File

@ -1,7 +1,7 @@
/* Copyright (C) 2010-2016 The RetroArch team
/* Copyright (C) 2010-2020 The RetroArch team
*
* ---------------------------------------------------------------------------------------
* The following license statement only applies to this file (compat_fnmatch.h).
* The following license statement only applies to this file (fnmatch.h).
* ---------------------------------------------------------------------------------------
*
* Permission is hereby granted, free of charge,

View File

@ -1,7 +1,7 @@
/* Copyright (C) 2010-2016 The RetroArch team
/* Copyright (C) 2010-2020 The RetroArch team
*
* ---------------------------------------------------------------------------------------
* The following license statement only applies to this file (compat_getopt.h).
* The following license statement only applies to this file (getopt.h).
* ---------------------------------------------------------------------------------------
*
* Permission is hereby granted, free of charge,
@ -28,13 +28,13 @@
#endif
/* Custom implementation of the GNU getopt_long for portability.
* Not designed to be fully compatible, but compatible with
* Not designed to be fully compatible, but compatible with
* the features RetroArch uses. */
#ifdef HAVE_GETOPT_LONG
#include <getopt.h>
#else
/* Avoid possible naming collisions during link since we
/* Avoid possible naming collisions during link since we
* prefer to use the actual name. */
#define getopt_long(argc, argv, optstring, longopts, longindex) __getopt_long_retro(argc, argv, optstring, longopts, longindex)
@ -51,7 +51,7 @@ struct option
};
/* argv[] is declared with char * const argv[] in GNU,
* but this makes no sense, as non-POSIX getopt_long
* but this makes no sense, as non-POSIX getopt_long
* mutates argv (non-opts are moved to the end). */
int getopt_long(int argc, char *argv[],
const char *optstring, const struct option *longopts, int *longindex);
@ -72,4 +72,3 @@ RETRO_END_DECLS
/* pragma once */
#endif

View File

@ -1,4 +1,4 @@
/* Copyright (C) 2010-2016 The RetroArch team
/* Copyright (C) 2010-2020 The RetroArch team
*
* ---------------------------------------------------------------------------------------
* The following license statement only applies to this file (intrinsics.h).
@ -30,16 +30,18 @@
#include <retro_common_api.h>
#include <retro_inline.h>
#ifdef _MSC_VER
#if defined(_MSC_VER) && !defined(_XBOX)
#if (_MSC_VER > 1310)
#include <intrin.h>
#endif
#endif
RETRO_BEGIN_DECLS
/* Count Leading Zero, unsigned 16bit input value */
static INLINE unsigned compat_clz_u16(uint16_t val)
{
#ifdef __GNUC__
#if defined(__GNUC__)
return __builtin_clz(val << 16 | 0x8000);
#else
unsigned ret = 0;
@ -55,34 +57,42 @@ static INLINE unsigned compat_clz_u16(uint16_t val)
}
/* Count Trailing Zero */
static INLINE int compat_ctz(unsigned x)
{
#if defined(__GNUC__) && !defined(RARCH_CONSOLE)
static INLINE int compat_ctz(unsigned x)
{
return __builtin_ctz(x);
}
#elif _MSC_VER >= 1400
static INLINE int compat_ctz(unsigned x)
{
#elif _MSC_VER >= 1400 && !defined(_XBOX) && !defined(__WINRT__)
unsigned long r = 0;
_BitScanReverse((unsigned long*)&r, x);
_BitScanForward((unsigned long*)&r, x);
return (int)r;
}
#else
/* Only checks at nibble granularity,
* because that's what we need. */
static INLINE int compat_ctz(unsigned x)
{
if (x & 0x000f)
return 0;
if (x & 0x00f0)
return 4;
if (x & 0x0f00)
return 8;
if (x & 0xf000)
return 12;
return 16;
}
int count = 0;
if (!(x & 0xffff))
{
x >>= 16;
count |= 16;
}
if (!(x & 0xff))
{
x >>= 8;
count |= 8;
}
if (!(x & 0xf))
{
x >>= 4;
count |= 4;
}
if (!(x & 0x3))
{
x >>= 2;
count |= 2;
}
if (!(x & 0x1))
count |= 1;
return count;
#endif
}
RETRO_END_DECLS

View File

@ -4,7 +4,7 @@
#ifdef WANT_ZLIB
#ifdef RARCH_INTERNAL
#include "../../../deps/zlib/zconf.h.in"
#include "zconf.h.in"
#endif
/* zlib.h -- interface of the 'zlib' general purpose compression library
@ -31,7 +31,6 @@
Jean-loup Gailly Mark Adler
jloup@gzip.org madler@alumni.caltech.edu
The data format used by the zlib library is described by RFCs (Request for
Comments) 1950 to 1952 in the files http://tools.ietf.org/html/rfc1950
(zlib format), rfc1951 (deflate format) and rfc1952 (gzip format).
@ -40,6 +39,7 @@
#ifndef ZLIB_H
#define ZLIB_H
#include <stdint.h>
#include "zconf.h"
#ifdef __cplusplus
@ -86,8 +86,8 @@ extern "C" {
even in case of corrupted input.
*/
typedef voidpf (*alloc_func) OF((voidpf opaque, uInt items, uInt size));
typedef void (*free_func) OF((voidpf opaque, voidpf address));
typedef voidpf (*alloc_func) (voidpf opaque, uInt items, uInt size);
typedef void (*free_func) (voidpf opaque, voidpf address);
struct internal_state;
@ -219,10 +219,9 @@ typedef gz_header FAR *gz_headerp;
#define zlib_version zlibVersion()
/* for compatibility with versions < 1.0.2 */
/* basic functions */
ZEXTERN const char * ZEXPORT zlibVersion OF((void));
const char * zlibVersion (void);
/* The application can compare zlibVersion and ZLIB_VERSION for consistency.
If the first character differs, the library code actually used is not
compatible with the zlib.h header file used by the application. This check
@ -230,7 +229,7 @@ ZEXTERN const char * ZEXPORT zlibVersion OF((void));
*/
/*
ZEXTERN int ZEXPORT deflateInit OF((z_streamp strm, int level));
int deflateInit (z_streamp strm, int level);
Initializes the internal stream state for compression. The fields
zalloc, zfree and opaque must be initialized before by the caller. If
@ -251,8 +250,7 @@ ZEXTERN int ZEXPORT deflateInit OF((z_streamp strm, int level));
this will be done by deflate().
*/
ZEXTERN int ZEXPORT deflate OF((z_streamp strm, int flush));
int deflate (z_streamp strm, int flush);
/*
deflate compresses as much data as possible, and stops when the input
buffer becomes empty or the output buffer becomes full. It may introduce
@ -358,8 +356,7 @@ ZEXTERN int ZEXPORT deflate OF((z_streamp strm, int flush));
space to continue compressing.
*/
ZEXTERN int ZEXPORT deflateEnd OF((z_streamp strm));
int deflateEnd (z_streamp strm);
/*
All dynamically allocated data structures for this stream are freed.
This function discards any unprocessed input and does not flush any pending
@ -372,9 +369,8 @@ ZEXTERN int ZEXPORT deflateEnd OF((z_streamp strm));
deallocated).
*/
/*
ZEXTERN int ZEXPORT inflateInit OF((z_streamp strm));
int inflateInit (z_streamp strm);
Initializes the internal stream state for decompression. The fields
next_in, avail_in, zalloc, zfree and opaque must be initialized before by
@ -397,8 +393,7 @@ ZEXTERN int ZEXPORT inflateInit OF((z_streamp strm));
until inflate() is called.
*/
ZEXTERN int ZEXPORT inflate OF((z_streamp strm, int flush));
int inflate (z_streamp strm, int flush);
/*
inflate decompresses as much data as possible, and stops when the input
buffer becomes empty or the output buffer becomes full. It may introduce
@ -513,8 +508,7 @@ ZEXTERN int ZEXPORT inflate OF((z_streamp strm, int flush));
recovery of the data is desired.
*/
ZEXTERN int ZEXPORT inflateEnd OF((z_streamp strm));
int inflateEnd (z_streamp strm);
/*
All dynamically allocated data structures for this stream are freed.
This function discards any unprocessed input and does not flush any pending
@ -525,7 +519,6 @@ ZEXTERN int ZEXPORT inflateEnd OF((z_streamp strm));
static string (which must not be deallocated).
*/
/* Advanced functions */
/*
@ -533,12 +526,12 @@ ZEXTERN int ZEXPORT inflateEnd OF((z_streamp strm));
*/
/*
ZEXTERN int ZEXPORT deflateInit2 OF((z_streamp strm,
int deflateInit2 (z_streamp strm,
int level,
int method,
int windowBits,
int memLevel,
int strategy));
int strategy);
This is another version of deflateInit with more compression options. The
fields next_in, zalloc, zfree and opaque must be initialized before by the
@ -593,9 +586,9 @@ ZEXTERN int ZEXPORT deflateInit2 OF((z_streamp strm,
compression: this will be done by deflate().
*/
ZEXTERN int ZEXPORT deflateSetDictionary OF((z_streamp strm,
int deflateSetDictionary (z_streamp strm,
const Bytef *dictionary,
uInt dictLength));
uInt dictLength);
/*
Initializes the compression dictionary from the given byte sequence
without producing any compressed output. When using the zlib format, this
@ -637,8 +630,8 @@ ZEXTERN int ZEXPORT deflateSetDictionary OF((z_streamp strm,
not perform any compression: this will be done by deflate().
*/
ZEXTERN int ZEXPORT deflateCopy OF((z_streamp dest,
z_streamp source));
int deflateCopy (z_streamp dest,
z_streamp source);
/*
Sets the destination stream as a complete copy of the source stream.
@ -655,7 +648,7 @@ ZEXTERN int ZEXPORT deflateCopy OF((z_streamp dest,
destination.
*/
ZEXTERN int ZEXPORT deflateReset OF((z_streamp strm));
int deflateReset (z_streamp strm);
/*
This function is equivalent to deflateEnd followed by deflateInit,
but does not free and reallocate all the internal compression state. The
@ -666,9 +659,9 @@ ZEXTERN int ZEXPORT deflateReset OF((z_streamp strm));
stream state was inconsistent (such as zalloc or state being Z_NULL).
*/
ZEXTERN int ZEXPORT deflateParams OF((z_streamp strm,
int deflateParams (z_streamp strm,
int level,
int strategy));
int strategy);
/*
Dynamically update the compression level and compression strategy. The
interpretation of level and strategy is as in deflateInit2. This can be
@ -687,11 +680,11 @@ ZEXTERN int ZEXPORT deflateParams OF((z_streamp strm,
strm->avail_out was zero.
*/
ZEXTERN int ZEXPORT deflateTune OF((z_streamp strm,
int deflateTune (z_streamp strm,
int good_length,
int max_lazy,
int nice_length,
int max_chain));
int max_chain);
/*
Fine tune deflate's internal compression parameters. This should only be
used by someone who understands the algorithm used by zlib's deflate for
@ -704,8 +697,8 @@ ZEXTERN int ZEXPORT deflateTune OF((z_streamp strm,
returns Z_OK on success, or Z_STREAM_ERROR for an invalid deflate stream.
*/
ZEXTERN uLong ZEXPORT deflateBound OF((z_streamp strm,
uLong sourceLen));
uLong deflateBound (z_streamp strm,
uLong sourceLen);
/*
deflateBound() returns an upper bound on the compressed size after
deflation of sourceLen bytes. It must be called after deflateInit() or
@ -719,9 +712,9 @@ ZEXTERN uLong ZEXPORT deflateBound OF((z_streamp strm,
than Z_FINISH or Z_NO_FLUSH are used.
*/
ZEXTERN int ZEXPORT deflatePending OF((z_streamp strm,
int deflatePending (z_streamp strm,
unsigned *pending,
int *bits));
int *bits);
/*
deflatePending() returns the number of bytes and bits of output that have
been generated, but not yet provided in the available output. The bytes not
@ -734,9 +727,9 @@ ZEXTERN int ZEXPORT deflatePending OF((z_streamp strm,
stream state was inconsistent.
*/
ZEXTERN int ZEXPORT deflatePrime OF((z_streamp strm,
int deflatePrime (z_streamp strm,
int bits,
int value));
int value);
/*
deflatePrime() inserts bits in the deflate output stream. The intent
is that this function is used to start off the deflate output with the bits
@ -751,8 +744,8 @@ ZEXTERN int ZEXPORT deflatePrime OF((z_streamp strm,
source stream state was inconsistent.
*/
ZEXTERN int ZEXPORT deflateSetHeader OF((z_streamp strm,
gz_headerp head));
int deflateSetHeader (z_streamp strm,
gz_headerp head);
/*
deflateSetHeader() provides gzip header information for when a gzip
stream is requested by deflateInit2(). deflateSetHeader() may be called
@ -776,8 +769,8 @@ ZEXTERN int ZEXPORT deflateSetHeader OF((z_streamp strm,
*/
/*
ZEXTERN int ZEXPORT inflateInit2 OF((z_streamp strm,
int windowBits));
int inflateInit2 (z_streamp strm,
int windowBits);
This is another version of inflateInit with an extra parameter. The
fields next_in, avail_in, zalloc, zfree and opaque must be initialized
@ -825,9 +818,9 @@ ZEXTERN int ZEXPORT inflateInit2 OF((z_streamp strm,
deferred until inflate() is called.
*/
ZEXTERN int ZEXPORT inflateSetDictionary OF((z_streamp strm,
int inflateSetDictionary (z_streamp strm,
const Bytef *dictionary,
uInt dictLength));
uInt dictLength);
/*
Initializes the decompression dictionary from the given uncompressed byte
sequence. This function must be called immediately after a call of inflate,
@ -848,9 +841,9 @@ ZEXTERN int ZEXPORT inflateSetDictionary OF((z_streamp strm,
inflate().
*/
ZEXTERN int ZEXPORT inflateGetDictionary OF((z_streamp strm,
int inflateGetDictionary (z_streamp strm,
Bytef *dictionary,
uInt *dictLength));
uInt *dictLength);
/*
Returns the sliding dictionary being maintained by inflate. dictLength is
set to the number of bytes in the dictionary, and that many bytes are copied
@ -863,7 +856,7 @@ ZEXTERN int ZEXPORT inflateGetDictionary OF((z_streamp strm,
stream state is inconsistent.
*/
ZEXTERN int ZEXPORT inflateSync OF((z_streamp strm));
int inflateSync (z_streamp strm);
/*
Skips invalid compressed data until a possible full flush point (see above
for the description of deflate with Z_FULL_FLUSH) can be found, or until all
@ -882,8 +875,8 @@ ZEXTERN int ZEXPORT inflateSync OF((z_streamp strm));
input each time, until success or end of the input data.
*/
ZEXTERN int ZEXPORT inflateCopy OF((z_streamp dest,
z_streamp source));
int inflateCopy (z_streamp dest,
z_streamp source);
/*
Sets the destination stream as a complete copy of the source stream.
@ -898,7 +891,7 @@ ZEXTERN int ZEXPORT inflateCopy OF((z_streamp dest,
destination.
*/
ZEXTERN int ZEXPORT inflateReset OF((z_streamp strm));
int inflateReset (z_streamp strm);
/*
This function is equivalent to inflateEnd followed by inflateInit,
but does not free and reallocate all the internal decompression state. The
@ -908,8 +901,8 @@ ZEXTERN int ZEXPORT inflateReset OF((z_streamp strm));
stream state was inconsistent (such as zalloc or state being Z_NULL).
*/
ZEXTERN int ZEXPORT inflateReset2 OF((z_streamp strm,
int windowBits));
int inflateReset2 (z_streamp strm,
int windowBits);
/*
This function is the same as inflateReset, but it also permits changing
the wrap and window size requests. The windowBits parameter is interpreted
@ -920,9 +913,9 @@ ZEXTERN int ZEXPORT inflateReset2 OF((z_streamp strm,
the windowBits parameter is invalid.
*/
ZEXTERN int ZEXPORT inflatePrime OF((z_streamp strm,
int inflatePrime (z_streamp strm,
int bits,
int value));
int value);
/*
This function inserts bits in the inflate input stream. The intent is
that this function is used to start inflating at a bit position in the
@ -941,7 +934,7 @@ ZEXTERN int ZEXPORT inflatePrime OF((z_streamp strm,
stream state was inconsistent.
*/
ZEXTERN long ZEXPORT inflateMark OF((z_streamp strm));
long inflateMark (z_streamp strm);
/*
This function returns two values, one in the lower 16 bits of the return
value, and the other in the remaining upper bits, obtained by shifting the
@ -969,8 +962,8 @@ ZEXTERN long ZEXPORT inflateMark OF((z_streamp strm));
source stream state was inconsistent.
*/
ZEXTERN int ZEXPORT inflateGetHeader OF((z_streamp strm,
gz_headerp head));
int inflateGetHeader (z_streamp strm,
gz_headerp head);
/*
inflateGetHeader() requests that gzip header information be stored in the
provided gz_header structure. inflateGetHeader() may be called after
@ -1010,8 +1003,8 @@ ZEXTERN int ZEXPORT inflateGetHeader OF((z_streamp strm,
*/
/*
ZEXTERN int ZEXPORT inflateBackInit OF((z_streamp strm, int windowBits,
unsigned char FAR *window));
int inflateBackInit (z_streamp strm, int windowBits,
unsigned char FAR *window);
Initialize the internal stream state for decompression using inflateBack()
calls. The fields zalloc, zfree and opaque in strm must be initialized
@ -1031,13 +1024,13 @@ ZEXTERN int ZEXPORT inflateBackInit OF((z_streamp strm, int windowBits,
the version of the header file.
*/
typedef unsigned (*in_func) OF((void FAR *,
z_const unsigned char FAR * FAR *));
typedef int (*out_func) OF((void FAR *, unsigned char FAR *, unsigned));
typedef unsigned (*in_func) (void FAR *,
z_const unsigned char FAR * FAR *);
typedef int (*out_func) (void FAR *, unsigned char FAR *, unsigned);
ZEXTERN int ZEXPORT inflateBack OF((z_streamp strm,
int inflateBack (z_streamp strm,
in_func in, void FAR *in_desc,
out_func out, void FAR *out_desc));
out_func out, void FAR *out_desc);
/*
inflateBack() does a raw inflate with a single call using a call-back
interface for input and output. This is potentially more efficient than
@ -1105,7 +1098,7 @@ ZEXTERN int ZEXPORT inflateBack OF((z_streamp strm,
cannot return Z_OK.
*/
ZEXTERN int ZEXPORT inflateBackEnd OF((z_streamp strm));
int inflateBackEnd (z_streamp strm);
/*
All memory allocated by inflateBackInit() is freed.
@ -1113,7 +1106,7 @@ ZEXTERN int ZEXPORT inflateBackEnd OF((z_streamp strm));
state was inconsistent.
*/
ZEXTERN uLong ZEXPORT zlibCompileFlags OF((void));
uLong zlibCompileFlags (void);
/* Return flags indicating compile-time options.
Type sizes, two bits each, 00 = 16 bits, 01 = 32, 10 = 64, 11 = other:
@ -1166,8 +1159,8 @@ ZEXTERN uLong ZEXPORT zlibCompileFlags OF((void));
you need special options.
*/
ZEXTERN int ZEXPORT compress OF((Bytef *dest, uLongf *destLen,
const Bytef *source, uLong sourceLen));
int compress (Bytef *dest, uLongf *destLen,
const Bytef *source, uLong sourceLen);
/*
Compresses the source buffer into the destination buffer. sourceLen is
the byte length of the source buffer. Upon entry, destLen is the total size
@ -1180,9 +1173,9 @@ ZEXTERN int ZEXPORT compress OF((Bytef *dest, uLongf *destLen,
buffer.
*/
ZEXTERN int ZEXPORT compress2 OF((Bytef *dest, uLongf *destLen,
int compress2 (Bytef *dest, uLongf *destLen,
const Bytef *source, uLong sourceLen,
int level));
int level);
/*
Compresses the source buffer into the destination buffer. The level
parameter has the same meaning as in deflateInit. sourceLen is the byte
@ -1196,15 +1189,15 @@ ZEXTERN int ZEXPORT compress2 OF((Bytef *dest, uLongf *destLen,
Z_STREAM_ERROR if the level parameter is invalid.
*/
ZEXTERN uLong ZEXPORT compressBound OF((uLong sourceLen));
uLong compressBound (uLong sourceLen);
/*
compressBound() returns an upper bound on the compressed size after
compress() or compress2() on sourceLen bytes. It would be used before a
compress() or compress2() call to allocate the destination buffer.
*/
ZEXTERN int ZEXPORT uncompress OF((Bytef *dest, uLongf *destLen,
const Bytef *source, uLong sourceLen));
int uncompress (Bytef *dest, uLongf *destLen,
const Bytef *source, uLongf sourceLen);
/*
Decompresses the source buffer into the destination buffer. sourceLen is
the byte length of the source buffer. Upon entry, destLen is the total size
@ -1233,7 +1226,7 @@ ZEXTERN int ZEXPORT uncompress OF((Bytef *dest, uLongf *destLen,
typedef struct gzFile_s *gzFile; /* semi-opaque gzip file descriptor */
/*
ZEXTERN gzFile ZEXPORT gzopen OF((const char *path, const char *mode));
gzFile gzopen (const char *path, const char *mode);
Opens a gzip (.gz) file for reading or writing. The mode parameter is as
in fopen ("rb" or "wb") but can also include a compression level ("wb9") or
@ -1270,7 +1263,7 @@ ZEXTERN gzFile ZEXPORT gzopen OF((const char *path, const char *mode));
file could not be opened.
*/
ZEXTERN gzFile ZEXPORT gzdopen OF((int fd, const char *mode));
gzFile gzdopen (int fd, const char *mode);
/*
gzdopen associates a gzFile with the file descriptor fd. File descriptors
are obtained from calls like open, dup, creat, pipe or fileno (if the file
@ -1293,7 +1286,7 @@ ZEXTERN gzFile ZEXPORT gzdopen OF((int fd, const char *mode));
will not detect if fd is invalid (unless fd is -1).
*/
ZEXTERN int ZEXPORT gzbuffer OF((gzFile file, unsigned size));
int gzbuffer (gzFile file, unsigned size);
/*
Set the internal buffer size used by this library's functions. The
default buffer size is 8192 bytes. This function must be called after
@ -1310,7 +1303,7 @@ ZEXTERN int ZEXPORT gzbuffer OF((gzFile file, unsigned size));
too late.
*/
ZEXTERN int ZEXPORT gzsetparams OF((gzFile file, int level, int strategy));
int gzsetparams (gzFile file, int level, int strategy);
/*
Dynamically update the compression level or strategy. See the description
of deflateInit2 for the meaning of these parameters.
@ -1319,7 +1312,7 @@ ZEXTERN int ZEXPORT gzsetparams OF((gzFile file, int level, int strategy));
opened for writing.
*/
ZEXTERN int ZEXPORT gzread OF((gzFile file, voidp buf, unsigned len));
int gzread (gzFile file, voidp buf, unsigned len);
/*
Reads the given number of uncompressed bytes from the compressed file. If
the input file is not in gzip format, gzread copies the given number of
@ -1347,15 +1340,15 @@ ZEXTERN int ZEXPORT gzread OF((gzFile file, voidp buf, unsigned len));
len for end of file, or -1 for error.
*/
ZEXTERN int ZEXPORT gzwrite OF((gzFile file,
voidpc buf, unsigned len));
int gzwrite (gzFile file,
voidpc buf, unsigned len);
/*
Writes the given number of uncompressed bytes into the compressed file.
gzwrite returns the number of uncompressed bytes written or 0 in case of
error.
*/
ZEXTERN int ZEXPORTVA gzprintf Z_ARG((gzFile file, const char *format, ...));
int gzprintf Z_ARG((gzFile file, const char *format, ...));
/*
Converts, formats, and writes the arguments to the compressed file under
control of the format string, as in fprintf. gzprintf returns the number of
@ -1370,7 +1363,7 @@ ZEXTERN int ZEXPORTVA gzprintf Z_ARG((gzFile file, const char *format, ...));
zlibCompileFlags().
*/
ZEXTERN int ZEXPORT gzputs OF((gzFile file, const char *s));
int gzputs (gzFile file, const char *s);
/*
Writes the given null-terminated string to the compressed file, excluding
the terminating null character.
@ -1378,7 +1371,7 @@ ZEXTERN int ZEXPORT gzputs OF((gzFile file, const char *s));
gzputs returns the number of characters written, or -1 in case of error.
*/
ZEXTERN char * ZEXPORT gzgets OF((gzFile file, char *buf, int len));
char * gzgets (gzFile file, char *buf, int len);
/*
Reads bytes from the compressed file until len-1 characters are read, or a
newline character is read and transferred to buf, or an end-of-file
@ -1391,13 +1384,13 @@ ZEXTERN char * ZEXPORT gzgets OF((gzFile file, char *buf, int len));
buf are indeterminate.
*/
ZEXTERN int ZEXPORT gzputc OF((gzFile file, int c));
int gzputc (gzFile file, int c);
/*
Writes c, converted to an unsigned char, into the compressed file. gzputc
returns the value that was written, or -1 in case of error.
*/
ZEXTERN int ZEXPORT gzgetc OF((gzFile file));
int gzgetc (gzFile file);
/*
Reads one byte from the compressed file. gzgetc returns this byte or -1
in case of end of file or error. This is implemented as a macro for speed.
@ -1406,7 +1399,7 @@ ZEXTERN int ZEXPORT gzgetc OF((gzFile file));
points to has been clobbered or not.
*/
ZEXTERN int ZEXPORT gzungetc OF((int c, gzFile file));
int gzungetc (int c, gzFile file);
/*
Push one character back onto the stream to be read as the first character
on the next read. At least one character of push-back is allowed.
@ -1418,7 +1411,7 @@ ZEXTERN int ZEXPORT gzungetc OF((int c, gzFile file));
gzseek() or gzrewind().
*/
ZEXTERN int ZEXPORT gzflush OF((gzFile file, int flush));
int gzflush (gzFile file, int flush);
/*
Flushes all pending output into the compressed file. The parameter flush
is as in the deflate() function. The return value is the zlib error number
@ -1434,8 +1427,8 @@ ZEXTERN int ZEXPORT gzflush OF((gzFile file, int flush));
*/
/*
ZEXTERN z_off_t ZEXPORT gzseek OF((gzFile file,
z_off_t offset, int whence));
z_off_t gzseek (gzFile file,
z_off_t offset, int whence);
Sets the starting position for the next gzread or gzwrite on the given
compressed file. The offset represents a number of bytes in the
@ -1453,7 +1446,7 @@ ZEXTERN z_off_t ZEXPORT gzseek OF((gzFile file,
would be before the current position.
*/
ZEXTERN int ZEXPORT gzrewind OF((gzFile file));
int gzrewind (gzFile file);
/*
Rewinds the given file. This function is supported only for reading.
@ -1461,7 +1454,7 @@ ZEXTERN int ZEXPORT gzrewind OF((gzFile file));
*/
/*
ZEXTERN z_off_t ZEXPORT gztell OF((gzFile file));
z_off_t gztell (gzFile file);
Returns the starting position for the next gzread or gzwrite on the given
compressed file. This position represents a number of bytes in the
@ -1472,7 +1465,7 @@ ZEXTERN z_off_t ZEXPORT gztell OF((gzFile file));
*/
/*
ZEXTERN z_off_t ZEXPORT gzoffset OF((gzFile file));
z_off_t gzoffset (gzFile file);
Returns the current offset in the file being read or written. This offset
includes the count of bytes that precede the gzip stream, for example when
@ -1481,7 +1474,7 @@ ZEXTERN z_off_t ZEXPORT gzoffset OF((gzFile file));
for a progress indicator. On error, gzoffset() returns -1.
*/
ZEXTERN int ZEXPORT gzeof OF((gzFile file));
int gzeof (gzFile file);
/*
Returns true (1) if the end-of-file indicator has been set while reading,
false (0) otherwise. Note that the end-of-file indicator is set only if the
@ -1496,7 +1489,7 @@ ZEXTERN int ZEXPORT gzeof OF((gzFile file));
has grown since the previous end of file was detected.
*/
ZEXTERN int ZEXPORT gzdirect OF((gzFile file));
int gzdirect (gzFile file);
/*
Returns true (1) if file is being copied directly while reading, or false
(0) if file is a gzip stream being decompressed.
@ -1517,7 +1510,7 @@ ZEXTERN int ZEXPORT gzdirect OF((gzFile file));
gzip file reading and decompression, which may not be desired.)
*/
ZEXTERN int ZEXPORT gzclose OF((gzFile file));
int gzclose (gzFile file);
/*
Flushes all pending output if necessary, closes the compressed file and
deallocates the (de)compression state. Note that once file is closed, you
@ -1530,8 +1523,8 @@ ZEXTERN int ZEXPORT gzclose OF((gzFile file));
last read ended in the middle of a gzip stream, or Z_OK on success.
*/
ZEXTERN int ZEXPORT gzclose_r OF((gzFile file));
ZEXTERN int ZEXPORT gzclose_w OF((gzFile file));
int gzclose_r (gzFile file);
int gzclose_w (gzFile file);
/*
Same as gzclose(), but gzclose_r() is only for use when reading, and
gzclose_w() is only for use when writing or appending. The advantage to
@ -1542,7 +1535,7 @@ ZEXTERN int ZEXPORT gzclose_w OF((gzFile file));
zlib library.
*/
ZEXTERN const char * ZEXPORT gzerror OF((gzFile file, int *errnum));
const char * gzerror (gzFile file, int *errnum);
/*
Returns the error message for the last error which occurred on the given
compressed file. errnum is set to zlib error number. If an error occurred
@ -1558,7 +1551,7 @@ ZEXTERN const char * ZEXPORT gzerror OF((gzFile file, int *errnum));
functions above that do not distinguish those cases in their return values.
*/
ZEXTERN void ZEXPORT gzclearerr OF((gzFile file));
void gzclearerr (gzFile file);
/*
Clears the error and end-of-file flags for file. This is analogous to the
clearerr() function in stdio. This is useful for continuing to read a gzip
@ -1575,7 +1568,7 @@ ZEXTERN void ZEXPORT gzclearerr OF((gzFile file));
library.
*/
ZEXTERN uLong ZEXPORT adler32 OF((uLong adler, const Bytef *buf, uInt len));
uint32_t adler32 (uint32_t adler, const uint8_t *buf, size_t len);
/*
Update a running Adler-32 checksum with the bytes buf[0..len-1] and
return the updated checksum. If buf is Z_NULL, this function returns the
@ -1595,8 +1588,8 @@ ZEXTERN uLong ZEXPORT adler32 OF((uLong adler, const Bytef *buf, uInt len));
*/
/*
ZEXTERN uLong ZEXPORT adler32_combine OF((uLong adler1, uLong adler2,
z_off_t len2));
uLong adler32_combine (uLong adler1, uLong adler2,
z_off_t len2);
Combine two Adler-32 checksums into one. For two sequences of bytes, seq1
and seq2 with lengths len1 and len2, Adler-32 checksums were calculated for
@ -1606,7 +1599,7 @@ ZEXTERN uLong ZEXPORT adler32_combine OF((uLong adler1, uLong adler2,
negative, the result has no meaning or utility.
*/
ZEXTERN uLong ZEXPORT crc32 OF((uLong crc, const Bytef *buf, uInt len));
uLong crc32 (uLong crc, const Bytef *buf, uInt len);
/*
Update a running CRC-32 with the bytes buf[0..len-1] and return the
updated CRC-32. If buf is Z_NULL, this function returns the required
@ -1624,7 +1617,7 @@ ZEXTERN uLong ZEXPORT crc32 OF((uLong crc, const Bytef *buf, uInt len));
*/
/*
ZEXTERN uLong ZEXPORT crc32_combine OF((uLong crc1, uLong crc2, z_off_t len2));
uLong crc32_combine (uLong crc1, uLong crc2, z_off_t len2);
Combine two CRC-32 check values into one. For two sequences of bytes,
seq1 and seq2 with lengths len1 and len2, CRC-32 check values were
@ -1633,26 +1626,25 @@ ZEXTERN uLong ZEXPORT crc32_combine OF((uLong crc1, uLong crc2, z_off_t len2));
len2.
*/
/* various hacks, don't look :) */
/* deflateInit and inflateInit are macros to allow checking the zlib version
* and the compiler's view of z_stream:
*/
ZEXTERN int ZEXPORT deflateInit_ OF((z_streamp strm, int level,
const char *version, int stream_size));
ZEXTERN int ZEXPORT inflateInit_ OF((z_streamp strm,
const char *version, int stream_size));
ZEXTERN int ZEXPORT deflateInit2_ OF((z_streamp strm, int level, int method,
int deflateInit_ (z_streamp strm, int level,
const char *version, int stream_size);
int inflateInit_ (z_streamp strm,
const char *version, int stream_size);
int deflateInit2_ (z_streamp strm, int level, int method,
int windowBits, int memLevel,
int strategy, const char *version,
int stream_size));
ZEXTERN int ZEXPORT inflateInit2_ OF((z_streamp strm, int windowBits,
const char *version, int stream_size));
ZEXTERN int ZEXPORT inflateBackInit_ OF((z_streamp strm, int windowBits,
int stream_size);
int inflateInit2_ (z_streamp strm, int windowBits,
const char *version, int stream_size);
int inflateBackInit_ (z_streamp strm, int windowBits,
unsigned char FAR *window,
const char *version,
int stream_size));
int stream_size);
#define deflateInit(strm, level) \
deflateInit_((strm), (level), ZLIB_VERSION, (int)sizeof(z_stream))
#define inflateInit(strm) \
@ -1676,7 +1668,7 @@ ZEXTERN int ZEXPORT inflateBackInit_ OF((z_streamp strm, int windowBits,
* behavior could change in the future, perhaps even capriciously. They can
* only be used by the gzgetc() macro. You have been warned.
*/
ZEXTERN int ZEXPORT gzgetc_ OF((gzFile file)); /* backward compatibility */
int gzgetc_ (gzFile file); /* backward compatibility */
#ifdef Z_PREFIX_SET
# undef z_gzgetc
# define z_gzgetc(g) \
@ -1693,12 +1685,12 @@ ZEXTERN int ZEXPORT gzgetc_ OF((gzFile file)); /* backward compatibility */
* without large file support, _LFS64_LARGEFILE must also be true
*/
#ifdef Z_LARGE64
ZEXTERN gzFile ZEXPORT gzopen64 OF((const char *, const char *));
ZEXTERN z_off64_t ZEXPORT gzseek64 OF((gzFile, z_off64_t, int));
ZEXTERN z_off64_t ZEXPORT gztell64 OF((gzFile));
ZEXTERN z_off64_t ZEXPORT gzoffset64 OF((gzFile));
ZEXTERN uLong ZEXPORT adler32_combine64 OF((uLong, uLong, z_off64_t));
ZEXTERN uLong ZEXPORT crc32_combine64 OF((uLong, uLong, z_off64_t));
gzFile gzopen64 (const char *, const char *);
z_off64_t gzseek64 (gzFile, z_off64_t, int);
z_off64_t gztell64 (gzFile);
z_off64_t gzoffset64 (gzFile);
uLong adler32_combine64 (uLong, uLong, z_off64_t);
uLong crc32_combine64 (uLong, uLong, z_off64_t);
#endif
#if !defined(ZLIB_INTERNAL) && defined(Z_WANT64)
@ -1718,26 +1710,26 @@ ZEXTERN int ZEXPORT gzgetc_ OF((gzFile file)); /* backward compatibility */
# define crc32_combine crc32_combine64
# endif
# ifndef Z_LARGE64
ZEXTERN gzFile ZEXPORT gzopen64 OF((const char *, const char *));
ZEXTERN z_off_t ZEXPORT gzseek64 OF((gzFile, z_off_t, int));
ZEXTERN z_off_t ZEXPORT gztell64 OF((gzFile));
ZEXTERN z_off_t ZEXPORT gzoffset64 OF((gzFile));
ZEXTERN uLong ZEXPORT adler32_combine64 OF((uLong, uLong, z_off_t));
ZEXTERN uLong ZEXPORT crc32_combine64 OF((uLong, uLong, z_off_t));
gzFile gzopen64 (const char *, const char *);
z_off_t gzseek64 (gzFile, z_off_t, int);
z_off_t gztell64 (gzFile);
z_off_t gzoffset64 (gzFile);
uLong adler32_combine64 (uLong, uLong, z_off_t);
uLong crc32_combine64 (uLong, uLong, z_off_t);
# endif
#else
ZEXTERN gzFile ZEXPORT gzopen OF((const char *, const char *));
ZEXTERN z_off_t ZEXPORT gzseek OF((gzFile, z_off_t, int));
ZEXTERN z_off_t ZEXPORT gztell OF((gzFile));
ZEXTERN z_off_t ZEXPORT gzoffset OF((gzFile));
ZEXTERN uLong ZEXPORT adler32_combine OF((uLong, uLong, z_off_t));
ZEXTERN uLong ZEXPORT crc32_combine OF((uLong, uLong, z_off_t));
gzFile gzopen (const char *, const char *);
z_off_t gzseek (gzFile, z_off_t, int);
z_off_t gztell (gzFile);
z_off_t gzoffset (gzFile);
uLong adler32_combine (uLong, uLong, z_off_t);
uLong crc32_combine (uLong, uLong, z_off_t);
#endif
#else /* Z_SOLO */
ZEXTERN uLong ZEXPORT adler32_combine OF((uLong, uLong, z_off_t));
ZEXTERN uLong ZEXPORT crc32_combine OF((uLong, uLong, z_off_t));
uLong adler32_combine (uLong, uLong, z_off_t);
uLong crc32_combine (uLong, uLong, z_off_t);
#endif /* !Z_SOLO */
@ -1747,19 +1739,21 @@ ZEXTERN int ZEXPORT gzgetc_ OF((gzFile file)); /* backward compatibility */
#endif
/* undocumented functions */
ZEXTERN const char * ZEXPORT zError OF((int));
ZEXTERN int ZEXPORT inflateSyncPoint OF((z_streamp));
ZEXTERN const z_crc_t FAR * ZEXPORT get_crc_table OF((void));
ZEXTERN int ZEXPORT inflateUndermine OF((z_streamp, int));
ZEXTERN int ZEXPORT inflateResetKeep OF((z_streamp));
ZEXTERN int ZEXPORT deflateResetKeep OF((z_streamp));
const char * zError (int);
int inflateSyncPoint (z_streamp);
const uint32_t * get_crc_table(void);
int inflateUndermine (z_streamp, int);
int inflateValidate (z_streamp, int);
int inflateResetKeep (z_streamp);
int deflateResetKeep (z_streamp);
#if defined(_WIN32) && !defined(Z_SOLO)
ZEXTERN gzFile ZEXPORT gzopen_w OF((const wchar_t *path,
const char *mode));
gzFile gzopen_w (const wchar_t *path,
const char *mode);
#endif
#if defined(STDC) || defined(Z_HAVE_STDARG_H)
# ifndef Z_SOLO
ZEXTERN int ZEXPORTVA gzvprintf Z_ARG((gzFile file,
int gzvprintf Z_ARG((gzFile file,
const char *format,
va_list va));
# endif

View File

@ -109,6 +109,8 @@ extern char z_errmsg[10][21]; /* indexed by 2-zlib_error */
#if defined(VAXC) || defined(VMS)
# define OS_CODE 0x02
# define F_OPEN(name, mode) \
fopen((name), (mode), "mbc=60", "ctx=stm", "rfm=fix", "mrs=512")
#endif
#if defined(ATARI) || defined(atarist)
@ -174,14 +176,18 @@ extern char z_errmsg[10][21]; /* indexed by 2-zlib_error */
/* provide prototypes for these when building zlib without LFS */
#if !defined(_WIN32) && \
(!defined(_LARGEFILE64_SOURCE) || _LFS64_LARGEFILE-0 == 0)
ZEXTERN uLong ZEXPORT adler32_combine64 OF((uLong, uLong, z_off_t));
ZEXTERN uLong ZEXPORT crc32_combine64 OF((uLong, uLong, z_off_t));
uLong adler32_combine64 (uLong, uLong, z_off_t);
uLong crc32_combine64 (uLong, uLong, z_off_t);
#endif
/* common defaults */
#ifndef OS_CODE
# define OS_CODE 0x03 /* assume Unix */
#endif
#ifndef F_OPEN
# define F_OPEN(name, mode) fopen((name), (mode))
#endif
/* functions */
@ -210,35 +216,23 @@ extern char z_errmsg[10][21]; /* indexed by 2-zlib_error */
# define zmemzero(dest, len) memset(dest, 0, len)
# endif
#else
void ZLIB_INTERNAL zmemcpy OF((Bytef* dest, const Bytef* source, uInt len));
int ZLIB_INTERNAL zmemcmp OF((const Bytef* s1, const Bytef* s2, uInt len));
void ZLIB_INTERNAL zmemzero OF((Bytef* dest, uInt len));
void ZLIB_INTERNAL zmemcpy (Bytef* dest, const Bytef* source, uInt len);
int ZLIB_INTERNAL zmemcmp (const Bytef* s1, const Bytef* s2, uInt len);
void ZLIB_INTERNAL zmemzero (Bytef* dest, uInt len);
#endif
/* Diagnostic functions */
#ifdef DEBUG
# include <stdio.h>
extern int ZLIB_INTERNAL z_verbose;
extern void ZLIB_INTERNAL z_error OF((char *m));
# define Assert(cond,msg) {if(!(cond)) z_error(msg);}
# define Trace(x) {if (z_verbose>=0) fprintf x ;}
# define Tracev(x) {if (z_verbose>0) fprintf x ;}
# define Tracevv(x) {if (z_verbose>1) fprintf x ;}
# define Tracec(c,x) {if (z_verbose>0 && (c)) fprintf x ;}
# define Tracecv(c,x) {if (z_verbose>1 && (c)) fprintf x ;}
#else
# define Assert(cond,msg)
# define Trace(x)
# define Tracev(x)
# define Tracevv(x)
# define Tracec(c,x)
# define Tracecv(c,x)
#endif
#ifndef Z_SOLO
voidpf ZLIB_INTERNAL zcalloc OF((voidpf opaque, unsigned items,
unsigned size));
void ZLIB_INTERNAL zcfree OF((voidpf opaque, voidpf ptr));
voidpf ZLIB_INTERNAL zcalloc (voidpf opaque, unsigned items,
unsigned size);
void ZLIB_INTERNAL zcfree (voidpf opaque, voidpf ptr);
#endif
#define ZALLOC(strm, items, size) \

View File

@ -38,29 +38,99 @@ enum CodePage
CODEPAGE_UTF8 = 65001 /* CP_UTF8 */
};
/**
* utf8_conv_utf32:
*
* Simple implementation. Assumes the sequence is
* properly synchronized and terminated.
**/
size_t utf8_conv_utf32(uint32_t *out, size_t out_chars,
const char *in, size_t in_size);
/**
* utf16_conv_utf8:
*
* Leaf function.
**/
bool utf16_conv_utf8(uint8_t *out, size_t *out_chars,
const uint16_t *in, size_t in_size);
/**
* utf8len:
*
* Leaf function.
**/
size_t utf8len(const char *string);
/**
* utf8cpy:
*
* Acts mostly like strlcpy.
*
* Copies the given number of UTF-8 characters,
* but at most @d_len bytes.
*
* Always NULL terminates. Does not copy half a character.
* @s is assumed valid UTF-8.
* Use only if @chars is considerably less than @d_len.
*
* Hidden non-leaf function cost:
* - Calls memcpy
*
* @return Number of bytes.
**/
size_t utf8cpy(char *d, size_t d_len, const char *s, size_t chars);
/**
* utf8skip:
*
* Leaf function
**/
const char *utf8skip(const char *str, size_t chars);
/**
* utf8_walk:
*
* Does not validate the input.
*
* Leaf function.
*
* @return Returns garbage if it's not UTF-8.
**/
uint32_t utf8_walk(const char **string);
/**
* utf16_to_char_string:
**/
bool utf16_to_char_string(const uint16_t *in, char *s, size_t len);
char* utf8_to_local_string_alloc(const char *str);
/**
* utf8_to_local_string_alloc:
*
* @return Returned pointer MUST be freed by the caller if non-NULL.
**/
char *utf8_to_local_string_alloc(const char *str);
char* local_to_utf8_string_alloc(const char *str);
/**
* local_to_utf8_string_alloc:
*
* @return Returned pointer MUST be freed by the caller if non-NULL.
**/
char *local_to_utf8_string_alloc(const char *str);
wchar_t* utf8_to_utf16_string_alloc(const char *str);
/**
* utf8_to_utf16_string_alloc:
*
* @return Returned pointer MUST be freed by the caller if non-NULL.
**/
wchar_t *utf8_to_utf16_string_alloc(const char *str);
char* utf16_to_utf8_string_alloc(const wchar_t *str);
/**
* utf16_to_utf8_string_alloc:
*
* @return Returned pointer MUST be freed by the caller if non-NULL.
**/
char *utf16_to_utf8_string_alloc(const wchar_t *str);
RETRO_END_DECLS

View File

@ -51,6 +51,28 @@ enum
RARCH_FILE_UNSUPPORTED
};
struct path_linked_list
{
char *path;
struct path_linked_list *next;
};
/**
* Create a new linked list with one item in it
* The path on this item will be set to NULL
**/
struct path_linked_list* path_linked_list_new(void);
/* Free the entire linked list */
void path_linked_list_free(struct path_linked_list *in_path_linked_list);
/**
* Add a node to the linked list with this path
* If the first node's path if it's not yet set,
* set this instead
**/
void path_linked_list_add_path(struct path_linked_list *in_path_linked_list, char *path);
/**
* path_is_compressed_file:
* @path : path
@ -81,12 +103,12 @@ bool path_is_compressed_file(const char *path);
* path_get_archive_delim:
* @path : path
*
* Gets delimiter of an archive file. Only the first '#'
* Find delimiter of an archive file. Only the first '#'
* after a compression extension is considered.
*
* Returns: pointer to the delimiter in the path if it contains
* a compressed file, otherwise NULL.
*/
* @return pointer to the delimiter in the path if it contains
* a path inside a compressed file, otherwise NULL.
**/
const char *path_get_archive_delim(const char *path);
/**
@ -96,10 +118,28 @@ const char *path_get_archive_delim(const char *path);
* Gets extension of file. Only '.'s
* after the last slash are considered.
*
* Returns: extension part from the path.
*/
* Hidden non-leaf function cost:
* - calls string_is_empty()
* - calls strrchr
*
* @return extension part from the path.
**/
const char *path_get_extension(const char *path);
/**
* path_get_extension_mutable:
* @path : path
*
* Specialized version of path_get_extension(). Return
* value is mutable.
*
* Gets extension of file. Only '.'s
* after the last slash are considered.
*
* @return extension part from the path.
**/
char *path_get_extension_mutable(const char *path);
/**
* path_remove_extension:
* @path : path
@ -108,7 +148,10 @@ const char *path_get_extension(const char *path);
* text after and including the last '.'.
* Only '.'s after the last slash are considered.
*
* Returns:
* Hidden non-leaf function cost:
* - calls strrchr
*
* @return
* 1) If path has an extension, returns path with the
* extension removed.
* 2) If there is no extension, returns NULL.
@ -122,9 +165,26 @@ char *path_remove_extension(char *path);
*
* Get basename from @path.
*
* Returns: basename from path.
* Hidden non-leaf function cost:
* - Calls path_get_archive_delim()
* - can call find_last_slash() once if it returns NULL
*
* @return basename from path.
**/
const char *path_basename(const char *path);
/**
* path_basename_nocompression:
* @path : path
*
* Specialized version of path_basename().
* Get basename from @path.
*
* Hidden non-leaf function cost:
* - Calls find_last_slash()
*
* @return basename from path.
**/
const char *path_basename_nocompression(const char *path);
/**
@ -139,12 +199,13 @@ void path_basedir(char *path);
/**
* path_parent_dir:
* @path : path
* @len : length of @path
*
* Extracts parent directory by mutating path.
* Assumes that path is a directory. Keeps trailing '/'.
* If the path was already at the root directory, returns empty string
**/
void path_parent_dir(char *path);
void path_parent_dir(char *path, size_t len);
/**
* path_resolve_realpath:
@ -156,7 +217,7 @@ void path_parent_dir(char *path);
*
* Relative paths are rebased on the current working dir.
*
* Returns: @buf if successful, NULL otherwise.
* @return @buf if successful, NULL otherwise.
* Note: Not implemented on consoles
* Note: Symlinks are only resolved on Unix-likes
* Note: The current working dir might not be what you expect,
@ -178,8 +239,11 @@ char *path_resolve_realpath(char *buf, size_t size, bool resolve_symlinks);
* Both @path and @base are assumed to be absolute paths without "." or "..".
*
* E.g. path /a/b/e/f.cgp with base /a/b/c/d/ turns into ../../e/f.cgp
*
* @return Length of the string copied into @out
**/
size_t path_relative_to(char *out, const char *path, const char *base, size_t size);
size_t path_relative_to(char *out, const char *path, const char *base,
size_t size);
/**
* path_is_absolute:
@ -187,7 +251,7 @@ size_t path_relative_to(char *out, const char *path, const char *base, size_t si
*
* Checks if @path is an absolute path or a relative path.
*
* Returns: true if path is absolute, false if path is relative.
* @return true if path is absolute, false if path is relative.
**/
bool path_is_absolute(const char *path);
@ -211,8 +275,15 @@ bool path_is_absolute(const char *path);
* out_path = "/foo/bar/baz/boo.asm"
* E.g.: in_path = "/foo/bar/baz/boo.c", replace = "" =>
* out_path = "/foo/bar/baz/boo"
*
* Hidden non-leaf function cost:
* - calls strlcpy 2x
* - calls strrchr
* - calls strlcat
*
* @return Length of the string copied into @out
*/
void fill_pathname(char *out_path, const char *in_path,
size_t fill_pathname(char *out_path, const char *in_path,
const char *replace, size_t size);
/**
@ -226,6 +297,12 @@ void fill_pathname(char *out_path, const char *in_path,
*
* E.g.:
* out_filename = "RetroArch-{month}{day}-{Hours}{Minutes}.{@ext}"
*
* Hidden non-leaf function cost:
* - Calls rtime_localtime()
* - Calls strftime
* - Calls strlcat
*
**/
size_t fill_dated_filename(char *out_filename,
const char *ext, size_t size);
@ -242,34 +319,33 @@ size_t fill_dated_filename(char *out_filename,
*
* E.g.:
* out_filename = "RetroArch-{year}{month}{day}-{Hour}{Minute}{Second}.{@ext}"
*
* Hidden non-leaf function cost:
* - Calls time
* - Calls rtime_localtime()
* - Calls strlcpy 2x
* - Calls string_is_empty()
* - Calls strftime
* - Calls strlcat
*
* @return Length of the string copied into @out_path
**/
void fill_str_dated_filename(char *out_filename,
size_t fill_str_dated_filename(char *out_filename,
const char *in_str, const char *ext, size_t size);
/**
* fill_pathname_noext:
* @out_path : output path
* @in_path : input path
* @replace : what to replace
* @size : buffer size of output path
*
* Appends a filename extension 'replace' to 'in_path', and outputs
* result in 'out_path'.
*
* Assumes in_path has no extension. If an extension is still
* present in 'in_path', it will be ignored.
*
*/
size_t fill_pathname_noext(char *out_path, const char *in_path,
const char *replace, size_t size);
/**
* find_last_slash:
* @str : input path
* @str : path
* @size : size of path
*
* Gets a pointer to the last slash in the input path.
* Find last slash in path. Tries to find
* a backslash on Windows too which takes precedence
* over regular slash.
* Hidden non-leaf function cost:
* - calls strrchr
*
* Returns: a pointer to the last slash in the input path.
* @return pointer to last slash/backslash found in @str.
**/
char *find_last_slash(const char *str);
@ -289,6 +365,11 @@ char *find_last_slash(const char *str);
*
* E.g..: in_dir = "/tmp/some_dir", in_basename = "/some_content/foo.c",
* replace = ".asm" => in_dir = "/tmp/some_dir/foo.c.asm"
*
* Hidden non-leaf function cost:
* - Calls fill_pathname_slash()
* - Calls path_basename()
* - Calls strlcpy 2x
**/
size_t fill_pathname_dir(char *in_dir, const char *in_basename,
const char *replace, size_t size);
@ -300,16 +381,15 @@ size_t fill_pathname_dir(char *in_dir, const char *in_basename,
* @size : size of output path
*
* Copies basename of @in_path into @out_path.
*
* Hidden non-leaf function cost:
* - Calls path_basename()
* - Calls strlcpy
*
* @return length of the string copied into @out
**/
size_t fill_pathname_base(char *out_path, const char *in_path, size_t size);
void fill_pathname_base_noext(char *out_dir,
const char *in_path, size_t size);
size_t fill_pathname_base_ext(char *out,
const char *in_path, const char *ext,
size_t size);
/**
* fill_pathname_basedir:
* @out_dir : output directory
@ -319,12 +399,13 @@ size_t fill_pathname_base_ext(char *out,
* Copies base directory of @in_path into @out_path.
* If in_path is a path without any slashes (relative current directory),
* @out_path will get path "./".
*
* Hidden non-leaf function cost:
* - Calls strlcpy
* - Calls path_basedir()
**/
void fill_pathname_basedir(char *out_path, const char *in_path, size_t size);
void fill_pathname_basedir_noext(char *out_dir,
const char *in_path, size_t size);
/**
* fill_pathname_parent_dir_name:
* @out_dir : output directory
@ -333,7 +414,13 @@ void fill_pathname_basedir_noext(char *out_dir,
*
* Copies only the parent directory name of @in_dir into @out_dir.
* The two buffers must not overlap. Removes trailing '/'.
* Returns true on success, false if a slash was not found in the path.
*
* Hidden non-leaf function cost:
* - Calls strdup
* - Calls find_last_slash() x times
* - Can call strlcpy
*
* @return true on success, false if a slash was not found in the path.
**/
bool fill_pathname_parent_dir_name(char *out_dir,
const char *in_dir, size_t size);
@ -347,6 +434,11 @@ bool fill_pathname_parent_dir_name(char *out_dir,
* Copies parent directory of @in_dir into @out_dir.
* Assumes @in_dir is a directory. Keeps trailing '/'.
* If the path was already at the root directory, @out_dir will be an empty string.
*
* Hidden non-leaf function cost:
* - Can call strlcpy if (@out_dir != @in_dir)
* - Calls strlen if (@out_dir == @in_dir)
* - Calls path_parent_dir()
**/
void fill_pathname_parent_dir(char *out_dir,
const char *in_dir, size_t size);
@ -374,30 +466,51 @@ void fill_pathname_resolve_relative(char *out_path, const char *in_refpath,
* @size : size of output path
*
* Joins a directory (@dir) and path (@path) together.
* Makes sure not to get two consecutive slashes
* Makes sure not to get two consecutive slashes
* between directory and path.
*
* Hidden non-leaf function cost:
* - calls strlcpy at least once
* - calls fill_pathname_slash()
*
* Deprecated. Use fill_pathname_join_special() instead
* if you can ensure @dir != @out_path
*
* @return Length of the string copied into @out_path
**/
size_t fill_pathname_join(char *out_path, const char *dir,
const char *path, size_t size);
/**
* fill_pathname_join_special:
* @out_path : output path
* @dir : directory. Cannot be identical to @out_path
* @path : path
* @size : size of output path
*
*
* Specialized version of fill_pathname_join.
* Unlike fill_pathname_join(),
* @dir and @out_path CANNOT be identical.
*
* Joins a directory (@dir) and path (@path) together.
* Makes sure not to get two consecutive slashes
* between directory and path.
*
* Hidden non-leaf function cost:
* - calls strlcpy 2x
* - calls find_last_slash()
*
* @return Length of the string copied into @out_path
**/
size_t fill_pathname_join_special(char *out_path,
const char *dir, const char *path, size_t size);
size_t fill_pathname_join_special_ext(char *out_path,
const char *dir, const char *path,
const char *last, const char *ext,
size_t size);
size_t fill_pathname_join_concat_noext(char *out_path,
const char *dir, const char *path,
const char *concat,
size_t size);
size_t fill_pathname_join_concat(char *out_path,
const char *dir, const char *path,
const char *concat,
size_t size);
void fill_pathname_join_noext(char *out_path,
const char *dir, const char *path, size_t size);
/**
* fill_pathname_join_delim:
* @out_path : output path
@ -408,45 +521,57 @@ void fill_pathname_join_noext(char *out_path,
*
* Joins a directory (@dir) and path (@path) together
* using the given delimiter (@delim).
*
* Hidden non-leaf function cost:
* - can call strlen
* - can call strlcpy
* - can call strlcat
**/
size_t fill_pathname_join_delim(char *out_path, const char *dir,
const char *path, const char delim, size_t size);
size_t fill_pathname_join_delim_concat(char *out_path, const char *dir,
const char *path, const char delim, const char *concat,
size_t size);
size_t fill_pathname_expand_special(char *out_path,
const char *in_path, size_t size);
size_t fill_pathname_abbreviate_special(char *out_path,
const char *in_path, size_t size);
/**
* fill_short_pathname_representation:
* @out_rep : output representation
* @in_path : input path
* @size : size of output representation
* fill_pathname_abbreviated_or_relative:
*
* Generates a short representation of path. It should only
* be used for displaying the result; the output representation is not
* binding in any meaningful way (for a normal path, this is the same as basename)
* In case of more complex URLs, this should cut everything except for
* the main image file.
* Fills the supplied path with either the abbreviated path or
* the relative path, which ever one 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
*
* E.g.: "/path/to/game.img" -> game.img
* "/path/to/myarchive.7z#folder/to/game.img" -> game.img
*/
size_t fill_short_pathname_representation(char* out_rep,
const char *in_path, size_t size);
void fill_short_pathname_representation_noext(char* out_rep,
const char *in_path, size_t size);
void fill_pathname_expand_special(char *out_path,
const char *in_path, size_t size);
void fill_pathname_abbreviate_special(char *out_path,
const char *in_path, size_t size);
void fill_pathname_abbreviated_or_relative(char *out_path, const char *in_refpath, const char *in_path, size_t size);
* @return Length of the string copied into @out_path
**/
size_t fill_pathname_abbreviated_or_relative(char *out_path,
const char *in_refpath, const char *in_path, size_t size);
/**
* pathname_conform_slashes_to_os:
*
* @path : path
*
* Leaf function.
*
* 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);
/**
* pathname_make_slashes_portable:
* @path : path
*
* Leaf function.
*
* Change all slashes to forward so they are more
* portable between Windows and Linux
**/
void pathname_make_slashes_portable(char *path);
/**
@ -464,8 +589,8 @@ void path_basedir_wrapper(char *path);
*
* Checks if character (@c) is a slash.
*
* Returns: true (1) if character is a slash, otherwise false (0).
*/
* @return true if character is a slash, otherwise false.
**/
#ifdef _WIN32
#define PATH_CHAR_IS_SLASH(c) (((c) == '/') || ((c) == '\\'))
#else
@ -477,8 +602,8 @@ void path_basedir_wrapper(char *path);
*
* Gets the default slash separator.
*
* Returns: default slash separator.
*/
* @return default slash separator.
**/
#ifdef _WIN32
#define PATH_DEFAULT_SLASH() "\\"
#define PATH_DEFAULT_SLASH_C() '\\'
@ -494,8 +619,13 @@ void path_basedir_wrapper(char *path);
*
* Assumes path is a directory. Appends a slash
* if not already there.
* Hidden non-leaf function cost:
* - calls find_last_slash()
* - can call strlcat once if it returns false
* - calls strlen
**/
void fill_pathname_slash(char *path, size_t size);
size_t fill_pathname_slash(char *path, size_t size);
#if !defined(RARCH_CONSOLE) && defined(RARCH_INTERNAL)
void fill_pathname_application_path(char *buf, size_t size);
@ -509,7 +639,16 @@ void fill_pathname_home_dir(char *buf, size_t size);
*
* Create directory on filesystem.
*
* Returns: true (1) if directory could be created, otherwise false (0).
* Recursive function.
*
* Hidden non-leaf function cost:
* - Calls strdup
* - Calls path_parent_dir()
* - Calls strcmp
* - Calls path_is_directory()
* - Calls path_mkdir()
*
* @return true if directory could be created, otherwise false.
**/
bool path_mkdir(const char *dir);
@ -519,10 +658,15 @@ bool path_mkdir(const char *dir);
*
* Checks if path is a directory.
*
* Returns: true (1) if path is a directory, otherwise false (0).
* @return true if path is a directory, otherwise false.
*/
bool path_is_directory(const char *path);
/* Time format strings with AM-PM designation require special
* handling due to platform dependence */
void strftime_am_pm(char *s, size_t len, const char* format,
const void* timeptr);
bool path_is_character_special(const char *path);
int path_stat(const char *path);

View File

@ -69,7 +69,7 @@ extern "C" {
# endif
# endif
# else
# if defined(__GNUC__) && __GNUC__ >= 4 && !defined(__PS3__)
# if defined(__GNUC__) && __GNUC__ >= 4
# define RETRO_API RETRO_CALLCONV __attribute__((__visibility__("default")))
# else
# define RETRO_API RETRO_CALLCONV
@ -283,6 +283,15 @@ enum retro_language
RETRO_LANGUAGE_HEBREW = 21,
RETRO_LANGUAGE_ASTURIAN = 22,
RETRO_LANGUAGE_FINNISH = 23,
RETRO_LANGUAGE_INDONESIAN = 24,
RETRO_LANGUAGE_SWEDISH = 25,
RETRO_LANGUAGE_UKRAINIAN = 26,
RETRO_LANGUAGE_CZECH = 27,
RETRO_LANGUAGE_CATALAN_VALENCIA = 28,
RETRO_LANGUAGE_CATALAN = 29,
RETRO_LANGUAGE_BRITISH_ENGLISH = 30,
RETRO_LANGUAGE_HUNGARIAN = 31,
RETRO_LANGUAGE_BELARUSIAN = 32,
RETRO_LANGUAGE_LAST,
/* Ensure sizeof(enum) == sizeof(int) */
@ -920,8 +929,6 @@ enum retro_mod
* anything else.
* It is recommended to expose all relevant pointers through
* retro_get_memory_* as well.
*
* Can be called from retro_init and retro_load_game.
*/
#define RETRO_ENVIRONMENT_SET_GEOMETRY 37
/* const struct retro_game_geometry * --
@ -1722,6 +1729,127 @@ enum retro_mod
* Must be called in retro_set_environment().
*/
#define RETRO_ENVIRONMENT_SET_VARIABLE 70
/* const struct retro_variable * --
* Allows an implementation to notify the frontend
* that a core option value has changed.
*
* retro_variable::key and retro_variable::value
* must match strings that have been set previously
* via one of the following:
*
* - RETRO_ENVIRONMENT_SET_VARIABLES
* - RETRO_ENVIRONMENT_SET_CORE_OPTIONS
* - RETRO_ENVIRONMENT_SET_CORE_OPTIONS_INTL
* - RETRO_ENVIRONMENT_SET_CORE_OPTIONS_V2
* - RETRO_ENVIRONMENT_SET_CORE_OPTIONS_V2_INTL
*
* After changing a core option value via this
* callback, RETRO_ENVIRONMENT_GET_VARIABLE_UPDATE
* will return true.
*
* If data is NULL, no changes will be registered
* and the callback will return true; an
* implementation may therefore pass NULL in order
* to test whether the callback is supported.
*/
#define RETRO_ENVIRONMENT_GET_THROTTLE_STATE (71 | RETRO_ENVIRONMENT_EXPERIMENTAL)
/* struct retro_throttle_state * --
* Allows an implementation to get details on the actual rate
* the frontend is attempting to call retro_run().
*/
#define RETRO_ENVIRONMENT_GET_SAVESTATE_CONTEXT (72 | RETRO_ENVIRONMENT_EXPERIMENTAL)
/* int * --
* Tells the core about the context the frontend is asking for savestate.
* (see enum retro_savestate_context)
*/
#define RETRO_ENVIRONMENT_GET_HW_RENDER_CONTEXT_NEGOTIATION_INTERFACE_SUPPORT (73 | RETRO_ENVIRONMENT_EXPERIMENTAL)
/* struct retro_hw_render_context_negotiation_interface * --
* Before calling SET_HW_RNEDER_CONTEXT_NEGOTIATION_INTERFACE, a core can query
* which version of the interface is supported.
*
* Frontend looks at interface_type and returns the maximum supported
* context negotiation interface version.
* If the interface_type is not supported or recognized by the frontend, a version of 0
* must be returned in interface_version and true is returned by frontend.
*
* If this environment call returns true with interface_version greater than 0,
* a core can always use a negotiation interface version larger than what the frontend returns, but only
* earlier versions of the interface will be used by the frontend.
* A frontend must not reject a negotiation interface version that is larger than
* what the frontend supports. Instead, the frontend will use the older entry points that it recognizes.
* If this is incompatible with a particular core's requirements, it can error out early.
*
* Backwards compatibility note:
* This environment call was introduced after Vulkan v1 context negotiation.
* If this environment call is not supported by frontend - i.e. the environment call returns false -
* only Vulkan v1 context negotiation is supported (if Vulkan HW rendering is supported at all).
* If a core uses Vulkan negotiation interface with version > 1, negotiation may fail unexpectedly.
* All future updates to the context negotiation interface implies that frontend must support
* this environment call to query support.
*/
#define RETRO_ENVIRONMENT_GET_JIT_CAPABLE 74
/* bool * --
* Result is set to true if the frontend has already verified JIT can be
* used, mainly for use iOS/tvOS. On other platforms the result is true.
*/
#define RETRO_ENVIRONMENT_GET_MICROPHONE_INTERFACE (75 | RETRO_ENVIRONMENT_EXPERIMENTAL)
/* struct retro_microphone_interface * --
* Returns an interface that can be used to receive input from the microphone driver.
*
* Returns true if microphone support is available,
* even if no microphones are plugged in.
* Returns false if mic support is disabled or unavailable.
*
* This callback can be invoked at any time,
* even before the microphone driver is ready.
*/
#define RETRO_ENVIRONMENT_SET_NETPACKET_INTERFACE 76
/* const struct retro_netpacket_callback * --
* When set, a core gains control over network packets sent and
* received during a multiplayer session. This can be used to
* emulate multiplayer games that were originally played on two
* or more separate consoles or computers connected together.
*
* The frontend will take care of connecting players together,
* and the core only needs to send the actual data as needed for
* the emulation, while handshake and connection management happen
* in the background.
*
* When two or more players are connected and this interface has
* been set, time manipulation features (such as pausing, slow motion,
* fast forward, rewinding, save state loading, etc.) are disabled to
* avoid interrupting communication.
*
* Should be set in either retro_init or retro_load_game, but not both.
*
* When not set, a frontend may use state serialization-based
* multiplayer, where a deterministic core supporting multiple
* input devices does not need to take any action on its own.
*/
#define RETRO_ENVIRONMENT_GET_DEVICE_POWER (77 | RETRO_ENVIRONMENT_EXPERIMENTAL)
/* struct retro_device_power * --
* Returns the device's current power state as reported by the frontend.
* This is useful for emulating the battery level in handheld consoles,
* or for reducing power consumption when on battery power.
*
* The return value indicates whether the frontend can provide this information,
* even if the parameter is NULL.
*
* If the frontend does not support this functionality,
* then the provided argument will remain unchanged.
*
* Note that this environment call describes the power state for the entire device,
* not for individual peripherals like controllers.
*/
/* VFS functionality */
/* File paths:
@ -1896,13 +2024,13 @@ struct retro_vfs_interface_info
enum retro_hw_render_interface_type
{
RETRO_HW_RENDER_INTERFACE_VULKAN = 0,
RETRO_HW_RENDER_INTERFACE_D3D9 = 1,
RETRO_HW_RENDER_INTERFACE_D3D10 = 2,
RETRO_HW_RENDER_INTERFACE_D3D11 = 3,
RETRO_HW_RENDER_INTERFACE_D3D12 = 4,
RETRO_HW_RENDER_INTERFACE_VULKAN = 0,
RETRO_HW_RENDER_INTERFACE_D3D9 = 1,
RETRO_HW_RENDER_INTERFACE_D3D10 = 2,
RETRO_HW_RENDER_INTERFACE_D3D11 = 3,
RETRO_HW_RENDER_INTERFACE_D3D12 = 4,
RETRO_HW_RENDER_INTERFACE_GSKIT_PS2 = 5,
RETRO_HW_RENDER_INTERFACE_DUMMY = INT_MAX
RETRO_HW_RENDER_INTERFACE_DUMMY = INT_MAX
};
/* Base struct. All retro_hw_render_interface_* types
@ -2678,9 +2806,17 @@ enum retro_hw_context_type
/* Vulkan, see RETRO_ENVIRONMENT_GET_HW_RENDER_INTERFACE. */
RETRO_HW_CONTEXT_VULKAN = 6,
/* Direct3D, set version_major to select the type of interface
* returned by RETRO_ENVIRONMENT_GET_HW_RENDER_INTERFACE */
RETRO_HW_CONTEXT_DIRECT3D = 7,
/* Direct3D11, see RETRO_ENVIRONMENT_GET_HW_RENDER_INTERFACE */
RETRO_HW_CONTEXT_D3D11 = 7,
/* Direct3D10, see RETRO_ENVIRONMENT_GET_HW_RENDER_INTERFACE */
RETRO_HW_CONTEXT_D3D10 = 8,
/* Direct3D12, see RETRO_ENVIRONMENT_GET_HW_RENDER_INTERFACE */
RETRO_HW_CONTEXT_D3D12 = 9,
/* Direct3D9, see RETRO_ENVIRONMENT_GET_HW_RENDER_INTERFACE */
RETRO_HW_CONTEXT_D3D9 = 10,
RETRO_HW_CONTEXT_DUMMY = INT_MAX
};
@ -2935,6 +3071,100 @@ struct retro_disk_control_ext_callback
retro_get_image_label_t get_image_label; /* Optional - may be NULL */
};
/* Definitions for RETRO_ENVIRONMENT_SET_NETPACKET_INTERFACE.
* A core can set it if sending and receiving custom network packets
* during a multiplayer session is desired.
*/
/* Netpacket flags for retro_netpacket_send_t */
#define RETRO_NETPACKET_UNRELIABLE 0 /* Packet to be sent unreliable, depending on network quality it might not arrive. */
#define RETRO_NETPACKET_RELIABLE (1 << 0) /* Reliable packets are guaranteed to arrive at the target in the order they were send. */
#define RETRO_NETPACKET_UNSEQUENCED (1 << 1) /* Packet will not be sequenced with other packets and may arrive out of order. Cannot be set on reliable packets. */
/* Used by the core to send a packet to one or more connected players.
* A single packet sent via this interface can contain up to 64 KB of data.
*
* The broadcast flag can be set to true to send to multiple connected clients.
* In a broadcast, the client_id argument indicates 1 client NOT to send the
* packet to (pass 0xFFFF to send to everyone). Otherwise, the client_id
* argument indicates a single client to send the packet to.
*
* A frontend must support sending reliable packets (RETRO_NETPACKET_RELIABLE).
* Unreliable packets might not be supported by the frontend, but the flags can
* still be specified. Reliable transmission will be used instead.
*
* If this function is called passing NULL for buf, it will instead flush all
* previously buffered outgoing packets and instantly read any incoming packets.
* During such a call, retro_netpacket_receive_t and retro_netpacket_stop_t can
* be called. The core can perform this in a loop to do a blocking read, i.e.,
* wait for incoming data, but needs to handle stop getting called and also
* give up after a short while to avoid freezing on a connection problem.
*
* This function is not guaranteed to be thread-safe and must be called during
* retro_run or any of the netpacket callbacks passed with this interface.
*/
typedef void (RETRO_CALLCONV *retro_netpacket_send_t)(int flags, const void* buf, size_t len, uint16_t client_id, bool broadcast);
/* Called by the frontend to signify that a multiplayer session has started.
* If client_id is 0 the local player is the host of the session and at this
* point no other player has connected yet.
*
* If client_id is > 0 the local player is a client connected to a host and
* at this point is already fully connected to the host.
*
* The core must store the retro_netpacket_send_t function pointer provided
* here and use it whenever it wants to send a packet. This function pointer
* remains valid until the frontend calls retro_netpacket_stop_t.
*/
typedef void (RETRO_CALLCONV *retro_netpacket_start_t)(uint16_t client_id, retro_netpacket_send_t send_fn);
/* Called by the frontend when a new packet arrives which has been sent from
* another player with retro_netpacket_send_t. The client_id argument indicates
* who has sent the packet.
*/
typedef void (RETRO_CALLCONV *retro_netpacket_receive_t)(const void* buf, size_t len, uint16_t client_id);
/* Called by the frontend when the multiplayer session has ended.
* Once this gets called the retro_netpacket_send_t function pointer passed
* to retro_netpacket_start_t will not be valid anymore.
*/
typedef void (RETRO_CALLCONV *retro_netpacket_stop_t)(void);
/* Called by the frontend every frame (between calls to retro_run while
* updating the state of the multiplayer session.
* This is a good place for the core to call retro_netpacket_send_t from.
*/
typedef void (RETRO_CALLCONV *retro_netpacket_poll_t)(void);
/* Called by the frontend when a new player connects to the hosted session.
* This is only called on the host side, not for clients connected to the host.
* If this function returns false, the newly connected player gets dropped.
* This can be used for example to limit the number of players.
*/
typedef bool (RETRO_CALLCONV *retro_netpacket_connected_t)(uint16_t client_id);
/* Called by the frontend when a player leaves or disconnects from the hosted session.
* This is only called on the host side, not for clients connected to the host.
*/
typedef void (RETRO_CALLCONV *retro_netpacket_disconnected_t)(uint16_t client_id);
/**
* A callback interface for giving a core the ability to send and receive custom
* network packets during a multiplayer session between two or more instances
* of a libretro frontend.
*
* @see RETRO_ENVIRONMENT_SET_NETPACKET_INTERFACE
*/
struct retro_netpacket_callback
{
retro_netpacket_start_t start;
retro_netpacket_receive_t receive;
retro_netpacket_stop_t stop; /* Optional - may be NULL */
retro_netpacket_poll_t poll; /* Optional - may be NULL */
retro_netpacket_connected_t connected; /* Optional - may be NULL */
retro_netpacket_disconnected_t disconnected; /* Optional - may be NULL */
};
enum retro_pixel_format
{
/* 0RGB1555, native endian.
@ -2959,6 +3189,35 @@ enum retro_pixel_format
RETRO_PIXEL_FORMAT_UNKNOWN = INT_MAX
};
enum retro_savestate_context
{
/* Standard savestate written to disk. */
RETRO_SAVESTATE_CONTEXT_NORMAL = 0,
/* Savestate where you are guaranteed that the same instance will load the save state.
* You can store internal pointers to code or data.
* It's still a full serialization and deserialization, and could be loaded or saved at any time.
* It won't be written to disk or sent over the network.
*/
RETRO_SAVESTATE_CONTEXT_RUNAHEAD_SAME_INSTANCE = 1,
/* Savestate where you are guaranteed that the same emulator binary will load that savestate.
* You can skip anything that would slow down saving or loading state but you can not store internal pointers.
* It won't be written to disk or sent over the network.
* Example: "Second Instance" runahead
*/
RETRO_SAVESTATE_CONTEXT_RUNAHEAD_SAME_BINARY = 2,
/* Savestate used within a rollback netplay feature.
* You should skip anything that would unnecessarily increase bandwidth usage.
* It won't be written to disk but it will be sent over the network.
*/
RETRO_SAVESTATE_CONTEXT_ROLLBACK_NETPLAY = 3,
/* Ensure sizeof() == sizeof(int). */
RETRO_SAVESTATE_CONTEXT_UNKNOWN = INT_MAX
};
struct retro_message
{
const char *msg; /* Message to be displayed. */
@ -3430,6 +3689,10 @@ struct retro_core_option_definition
const char *default_value;
};
#ifdef __PS3__
#undef local
#endif
struct retro_core_options_intl
{
/* Pointer to an array of retro_core_option_definition structs
@ -3667,6 +3930,326 @@ struct retro_fastforwarding_override
bool inhibit_toggle;
};
/* During normal operation. Rate will be equal to the core's internal FPS. */
#define RETRO_THROTTLE_NONE 0
/* While paused or stepping single frames. Rate will be 0. */
#define RETRO_THROTTLE_FRAME_STEPPING 1
/* During fast forwarding.
* Rate will be 0 if not specifically limited to a maximum speed. */
#define RETRO_THROTTLE_FAST_FORWARD 2
/* During slow motion. Rate will be less than the core's internal FPS. */
#define RETRO_THROTTLE_SLOW_MOTION 3
/* While rewinding recorded save states. Rate can vary depending on the rewind
* speed or be 0 if the frontend is not aiming for a specific rate. */
#define RETRO_THROTTLE_REWINDING 4
/* While vsync is active in the video driver and the target refresh rate is
* lower than the core's internal FPS. Rate is the target refresh rate. */
#define RETRO_THROTTLE_VSYNC 5
/* When the frontend does not throttle in any way. Rate will be 0.
* An example could be if no vsync or audio output is active. */
#define RETRO_THROTTLE_UNBLOCKED 6
struct retro_throttle_state
{
/* The current throttling mode. Should be one of the values above. */
unsigned mode;
/* How many times per second the frontend aims to call retro_run.
* Depending on the mode, it can be 0 if there is no known fixed rate.
* This won't be accurate if the total processing time of the core and
* the frontend is longer than what is available for one frame. */
float rate;
};
/**
* Opaque handle to a microphone that's been opened for use.
* The underlying object is accessed or created with \c retro_microphone_interface_t.
*/
typedef struct retro_microphone retro_microphone_t;
/**
* Parameters for configuring a microphone.
* Some of these might not be honored,
* depending on the available hardware and driver configuration.
*/
typedef struct retro_microphone_params
{
/**
* The desired sample rate of the microphone's input, in Hz.
* The microphone's input will be resampled,
* so cores can ask for whichever frequency they need.
*
* If zero, some reasonable default will be provided by the frontend
* (usually from its config file).
*
* @see retro_get_mic_rate_t
*/
unsigned rate;
} retro_microphone_params_t;
/**
* @copydoc retro_microphone_interface::open_mic
*/
typedef retro_microphone_t *(RETRO_CALLCONV *retro_open_mic_t)(const retro_microphone_params_t *params);
/**
* @copydoc retro_microphone_interface::close_mic
*/
typedef void (RETRO_CALLCONV *retro_close_mic_t)(retro_microphone_t *microphone);
/**
* @copydoc retro_microphone_interface::get_params
*/
typedef bool (RETRO_CALLCONV *retro_get_mic_params_t)(const retro_microphone_t *microphone, retro_microphone_params_t *params);
/**
* @copydoc retro_microphone_interface::set_mic_state
*/
typedef bool (RETRO_CALLCONV *retro_set_mic_state_t)(retro_microphone_t *microphone, bool state);
/**
* @copydoc retro_microphone_interface::get_mic_state
*/
typedef bool (RETRO_CALLCONV *retro_get_mic_state_t)(const retro_microphone_t *microphone);
/**
* @copydoc retro_microphone_interface::read_mic
*/
typedef int (RETRO_CALLCONV *retro_read_mic_t)(retro_microphone_t *microphone, int16_t* samples, size_t num_samples);
/**
* The current version of the microphone interface.
* Will be incremented whenever \c retro_microphone_interface or \c retro_microphone_params_t
* receive new fields.
*
* Frontends using cores built against older mic interface versions
* should not access fields introduced in newer versions.
*/
#define RETRO_MICROPHONE_INTERFACE_VERSION 1
/**
* An interface for querying the microphone and accessing data read from it.
*
* @see RETRO_ENVIRONMENT_GET_MICROPHONE_INTERFACE
*/
struct retro_microphone_interface
{
/**
* The version of this microphone interface.
* Set by the core to request a particular version,
* and set by the frontend to indicate the returned version.
* 0 indicates that the interface is invalid or uninitialized.
*/
unsigned interface_version;
/**
* Initializes a new microphone.
* Assuming that microphone support is enabled and provided by the frontend,
* cores may call this function whenever necessary.
* A microphone could be opened throughout a core's lifetime,
* or it could wait until a microphone is plugged in to the emulated device.
*
* The returned handle will be valid until it's freed,
* even if the audio driver is reinitialized.
*
* This function is not guaranteed to be thread-safe.
*
* @param args[in] Parameters used to create the microphone.
* May be \c NULL, in which case the default value of each parameter will be used.
*
* @returns Pointer to the newly-opened microphone,
* or \c NULL if one couldn't be opened.
* This likely means that no microphone is plugged in and recognized,
* or the maximum number of supported microphones has been reached.
*
* @note Microphones are \em inactive by default;
* to begin capturing audio, call \c set_mic_state.
* @see retro_microphone_params_t
*/
retro_open_mic_t open_mic;
/**
* Closes a microphone that was initialized with \c open_mic.
* Calling this function will stop all microphone activity
* and free up the resources that it allocated.
* Afterwards, the handle is invalid and must not be used.
*
* A frontend may close opened microphones when unloading content,
* but this behavior is not guaranteed.
* Cores should close their microphones when exiting, just to be safe.
*
* @param microphone Pointer to the microphone that was allocated by \c open_mic.
* If \c NULL, this function does nothing.
*
* @note The handle might be reused if another microphone is opened later.
*/
retro_close_mic_t close_mic;
/**
* Returns the configured parameters of this microphone.
* These may differ from what was requested depending on
* the driver and device configuration.
*
* Cores should check these values before they start fetching samples.
*
* Will not change after the mic was opened.
*
* @param microphone[in] Opaque handle to the microphone
* whose parameters will be retrieved.
* @param params[out] The parameters object that the
* microphone's parameters will be copied to.
*
* @return \c true if the parameters were retrieved,
* \c false if there was an error.
*/
retro_get_mic_params_t get_params;
/**
* Enables or disables the given microphone.
* Microphones are disabled by default
* and must be explicitly enabled before they can be used.
* Disabled microphones will not process incoming audio samples,
* and will therefore have minimal impact on overall performance.
* Cores may enable microphones throughout their lifetime,
* or only for periods where they're needed.
*
* Cores that accept microphone input should be able to operate without it;
* we suggest substituting silence in this case.
*
* @param microphone Opaque handle to the microphone
* whose state will be adjusted.
* This will have been provided by \c open_mic.
* @param state \c true if the microphone should receive audio input,
* \c false if it should be idle.
* @returns \c true if the microphone's state was successfully set,
* \c false if \c microphone is invalid
* or if there was an error.
*/
retro_set_mic_state_t set_mic_state;
/**
* Queries the active state of a microphone at the given index.
* Will return whether the microphone is enabled,
* even if the driver is paused.
*
* @param microphone Opaque handle to the microphone
* whose state will be queried.
* @return \c true if the provided \c microphone is valid and active,
* \c false if not or if there was an error.
*/
retro_get_mic_state_t get_mic_state;
/**
* Retrieves the input processed by the microphone since the last call.
* \em Must be called every frame unless \c microphone is disabled,
* similar to how \c retro_audio_sample_batch_t works.
*
* @param[in] microphone Opaque handle to the microphone
* whose recent input will be retrieved.
* @param[out] samples The buffer that will be used to store the microphone's data.
* Microphone input is in mono (i.e. one number per sample).
* Should be large enough to accommodate the expected number of samples per frame;
* for example, a 44.1kHz sample rate at 60 FPS would require space for 735 samples.
* @param[in] num_samples The size of the data buffer in samples (\em not bytes).
* Microphone input is in mono, so a "frame" and a "sample" are equivalent in length here.
*
* @return The number of samples that were copied into \c samples.
* If \c microphone is pending driver initialization,
* this function will copy silence of the requested length into \c samples.
*
* Will return -1 if the microphone is disabled,
* the audio driver is paused,
* or there was an error.
*/
retro_read_mic_t read_mic;
};
/**
* Describes how a device is being powered.
* @see RETRO_ENVIRONMENT_GET_DEVICE_POWER
*/
enum retro_power_state
{
/**
* Indicates that the frontend cannot report its power state at this time,
* most likely due to a lack of support.
*
* \c RETRO_ENVIRONMENT_GET_DEVICE_POWER will not return this value;
* instead, the environment callback will return \c false.
*/
RETRO_POWERSTATE_UNKNOWN = 0,
/**
* Indicates that the device is running on its battery.
* Usually applies to portable devices such as handhelds, laptops, and smartphones.
*/
RETRO_POWERSTATE_DISCHARGING,
/**
* Indicates that the device's battery is currently charging.
*/
RETRO_POWERSTATE_CHARGING,
/**
* Indicates that the device is connected to a power source
* and that its battery has finished charging.
*/
RETRO_POWERSTATE_CHARGED,
/**
* Indicates that the device is connected to a power source
* and that it does not have a battery.
* This usually suggests a desktop computer or a non-portable game console.
*/
RETRO_POWERSTATE_PLUGGED_IN
};
/**
* Indicates that an estimate is not available for the battery level or time remaining,
* even if the actual power state is known.
*/
#define RETRO_POWERSTATE_NO_ESTIMATE (-1)
/**
* Describes the power state of the device running the frontend.
* @see RETRO_ENVIRONMENT_GET_DEVICE_POWER
*/
struct retro_device_power
{
/**
* The current state of the frontend's power usage.
*/
enum retro_power_state state;
/**
* A rough estimate of the amount of time remaining (in seconds)
* before the device powers off.
* This value depends on a variety of factors,
* so it is not guaranteed to be accurate.
*
* Will be set to \c RETRO_POWERSTATE_NO_ESTIMATE if \c state does not equal \c RETRO_POWERSTATE_DISCHARGING.
* May still be set to \c RETRO_POWERSTATE_NO_ESTIMATE if the frontend is unable to provide an estimate.
*/
int seconds;
/**
* The approximate percentage of battery charge,
* ranging from 0 to 100 (inclusive).
* The device may power off before this reaches 0.
*
* The user might have configured their device
* to stop charging before the battery is full,
* so do not assume that this will be 100 in the \c RETRO_POWERSTATE_CHARGED state.
*/
int8_t percent;
};
/* Callbacks */
/* Environment callback. Gives implementations a way of performing

View File

@ -1,4 +1,4 @@
/* Copyright (C) 2010-2016 The RetroArch team
/* Copyright (C) 2010-2020 The RetroArch team
*
* ---------------------------------------------------------------------------------------
* The following license statement only applies to this file (memalign.h).

View File

@ -1,4 +1,4 @@
/* Copyright (C) 2010-2016 The RetroArch team
/* Copyright (C) 2010-2020 The RetroArch team
*
* ---------------------------------------------------------------------------------------
* The following license statement only applies to this file (retro_common.h).
@ -26,7 +26,7 @@
/*
This file is designed to normalize the libretro-common compiling environment.
It is not to be used in public API headers, as they should be designed as leanly as possible.
Nonetheless.. in the meantime, if you do something like use ssize_t, which is not fully portable,
Nonetheless.. in the meantime, if you do something like use ssize_t, which is not fully portable,
in a public API, you may need this.
*/
@ -34,4 +34,3 @@ in a public API, you may need this.
#include <compat/msvc.h>
#endif

View File

@ -101,6 +101,26 @@ typedef int ssize_t;
#define STRING_REP_UINT64 "%" PRIu64
#define STRING_REP_USIZE "%" PRIuPTR
/* Wrap a declaration in RETRO_DEPRECATED() to produce a compiler warning when
it's used. This is intended for developer machines, so it won't work on ancient
or obscure compilers */
#if defined(_MSC_VER)
#if _MSC_VER >= 1400 /* Visual C 2005 or later */
#define RETRO_DEPRECATED(decl) __declspec(deprecated) decl
#endif
#elif defined(__GNUC__)
#if __GNUC__ >= 3 /* GCC 3 or later */
#define RETRO_DEPRECATED(decl) decl __attribute__((deprecated))
#endif
#elif defined(__clang__)
#if __clang_major__ >= 3 /* clang 3 or later */
#define RETRO_DEPRECATED(decl) decl __attribute__((deprecated))
#endif
#endif
#ifndef RETRO_DEPRECATED /* Unsupported compilers */
#define RETRO_DEPRECATED(decl) decl
#endif
/*
I would like to see retro_inline.h moved in here; possibly boolean too.

View File

@ -49,6 +49,10 @@
#include <compat/msvc.h>
#endif
#ifdef IOS
#include <sys/param.h>
#endif
static INLINE void bits_or_bits(uint32_t *a, uint32_t *b, uint32_t count)
{
uint32_t i;
@ -74,14 +78,29 @@ static INLINE bool bits_any_set(uint32_t* ptr, uint32_t count)
return false;
}
static INLINE bool bits_any_different(uint32_t *a, uint32_t *b, uint32_t count)
{
uint32_t i;
for (i = 0; i < count; i++)
{
if (a[i] != b[i])
return true;
}
return false;
}
#ifndef PATH_MAX_LENGTH
#if defined(_XBOX1) || defined(_3DS) || defined(PSP) || defined(PS2) || defined(GEKKO)|| defined(WIIU) || defined(ORBIS) || defined(__PS3__)
#if defined(_XBOX1) || defined(_3DS) || defined(PSP) || defined(PS2) || defined(GEKKO)|| defined(WIIU) || defined(__PSL1GHT__) || defined(__PS3__)
#define PATH_MAX_LENGTH 512
#else
#define PATH_MAX_LENGTH 4096
#endif
#endif
#ifndef NAME_MAX_LENGTH
#define NAME_MAX_LENGTH 256
#endif
#ifndef MAX
#define MAX(a, b) ((a) > (b) ? (a) : (b))
#endif

View File

@ -1,4 +1,4 @@
/* Copyright (C) 2010-2015 The RetroArch team
/* Copyright (C) 2010-2020 The RetroArch team
*
* ---------------------------------------------------------------------------------------
* The following license statement only applies to this file (rthreads.h).
@ -36,6 +36,10 @@ typedef struct sthread sthread_t;
typedef struct slock slock_t;
typedef struct scond scond_t;
#ifdef HAVE_THREAD_STORAGE
typedef unsigned sthread_tls_t;
#endif
/**
* sthread_create:
* @start_routine : thread entry callback function
@ -48,13 +52,30 @@ typedef struct scond scond_t;
*/
sthread_t *sthread_create(void (*thread_func)(void*), void *userdata);
/**
* sthread_create_with_priority:
* @start_routine : thread entry callback function
* @userdata : pointer to userdata that will be made
* available in thread entry callback function
* @thread_priority : thread priority hint value from [1-100]
*
* Create a new thread. It is possible for the caller to give a hint
* for the thread's priority from [1-100]. Any passed in @thread_priority
* values that are outside of this range will cause sthread_create() to
* create a new thread using the operating system's default thread
* priority.
*
* Returns: pointer to new thread if successful, otherwise NULL.
*/
sthread_t *sthread_create_with_priority(void (*thread_func)(void*), void *userdata, int thread_priority);
/**
* sthread_detach:
* @thread : pointer to thread object
* @thread : pointer to thread object
*
* Detach a thread. When a detached thread terminates, its
* resource sare automatically released back to the system
* without the need for another thread to join with the
* without the need for another thread to join with the
* terminated thread.
*
* Returns: 0 on success, otherwise it returns a non-zero error number.
@ -63,26 +84,21 @@ int sthread_detach(sthread_t *thread);
/**
* sthread_join:
* @thread : pointer to thread object
* @thread : pointer to thread object
*
* Join with a terminated thread. Waits for the thread specified by
* @thread to terminate. If that thread has already terminated, then
* it will return immediately. The thread specified by @thread must
* be joinable.
*
*
* Returns: 0 on success, otherwise it returns a non-zero error number.
*/
void sthread_join(sthread_t *thread);
/**
* sthread_isself:
* @thread : pointer to thread object
* @thread : pointer to thread object
*
* Join with a terminated thread. Waits for the thread specified by
* @thread to terminate. If that thread has already terminated, then
* it will return immediately. The thread specified by @thread must
* be joinable.
*
* Returns: true (1) if calling thread is the specified thread
*/
bool sthread_isself(sthread_t *thread);
@ -99,7 +115,7 @@ slock_t *slock_new(void);
/**
* slock_free:
* @lock : pointer to mutex object
* @lock : pointer to mutex object
*
* Frees a mutex.
**/
@ -107,7 +123,7 @@ void slock_free(slock_t *lock);
/**
* slock_lock:
* @lock : pointer to mutex object
* @lock : pointer to mutex object
*
* Locks a mutex. If a mutex is already locked by
* another thread, the calling thread shall block until
@ -115,9 +131,18 @@ void slock_free(slock_t *lock);
**/
void slock_lock(slock_t *lock);
/**
* slock_try_lock:
* @lock : pointer to mutex object
*
* Attempts to lock a mutex. If a mutex is already locked by
* another thread, return false. If the lock is acquired, return true.
**/
bool slock_try_lock(slock_t *lock);
/**
* slock_unlock:
* @lock : pointer to mutex object
* @lock : pointer to mutex object
*
* Unlocks a mutex.
**/
@ -136,7 +161,7 @@ scond_t *scond_new(void);
/**
* scond_free:
* @cond : pointer to condition variable object
* @cond : pointer to condition variable object
*
* Frees a condition variable.
**/
@ -144,17 +169,17 @@ void scond_free(scond_t *cond);
/**
* scond_wait:
* @cond : pointer to condition variable object
* @lock : pointer to mutex object
* @cond : pointer to condition variable object
* @lock : pointer to mutex object
*
* Block on a condition variable (i.e. wait on a condition).
* Block on a condition variable (i.e. wait on a condition).
**/
void scond_wait(scond_t *cond, slock_t *lock);
/**
* scond_wait_timeout:
* @cond : pointer to condition variable object
* @lock : pointer to mutex object
* @cond : pointer to condition variable object
* @lock : pointer to mutex object
* @timeout_us : timeout (in microseconds)
*
* Try to block on a condition variable (i.e. wait on a condition) until
@ -167,22 +192,78 @@ bool scond_wait_timeout(scond_t *cond, slock_t *lock, int64_t timeout_us);
/**
* scond_broadcast:
* @cond : pointer to condition variable object
* @cond : pointer to condition variable object
*
* Broadcast a condition. Unblocks all threads currently blocked
* on the specified condition variable @cond.
* on the specified condition variable @cond.
**/
int scond_broadcast(scond_t *cond);
/**
* scond_signal:
* @cond : pointer to condition variable object
* @cond : pointer to condition variable object
*
* Signal a condition. Unblocks at least one of the threads currently blocked
* on the specified condition variable @cond.
* on the specified condition variable @cond.
**/
void scond_signal(scond_t *cond);
#ifdef HAVE_THREAD_STORAGE
/**
* @brief Creates a thread local storage key
*
* This function shall create thread-specific data key visible to all threads in
* the process. The same key can be used by multiple threads to store
* thread-local data.
*
* When the key is created NULL shall be associated with it in all active
* threads. Whenever a new thread is spawned the all defined keys will be
* associated with NULL on that thread.
*
* @param tls
* @return whether the operation suceeded or not
*/
bool sthread_tls_create(sthread_tls_t *tls);
/**
* @brief Deletes a thread local storage
* @param tls
* @return whether the operation suceeded or not
*/
bool sthread_tls_delete(sthread_tls_t *tls);
/**
* @brief Retrieves thread specific data associated with a key
*
* There is no way to tell whether this function failed.
*
* @param tls
* @return
*/
void *sthread_tls_get(sthread_tls_t *tls);
/**
* @brief Binds thread specific data to a key
* @param tls
* @return Whether the operation suceeded or not
*/
bool sthread_tls_set(sthread_tls_t *tls, const void *data);
#endif
/*
* @brief Get thread ID of specified thread
* @param thread
* @return The ID of the specified thread
*/
uintptr_t sthread_get_thread_id(sthread_t *thread);
/*
* @brief Get thread ID of the current thread
* @param
* @return The ID of the current thread
*/
uintptr_t sthread_get_current_thread_id(void);
RETRO_END_DECLS
#endif

View File

@ -59,7 +59,7 @@ int64_t filestream_truncate(RFILE *stream, int64_t length);
* @bufsize : optional buffer size (-1 or 0 to use default)
*
* Opens a file for reading or writing, depending on the requested mode.
* Returns a pointer to an RFILE if opened successfully, otherwise NULL.
* @return A pointer to an RFILE if opened successfully, otherwise NULL.
**/
RFILE* filestream_open(const char *path, unsigned mode, unsigned hints);
@ -75,16 +75,39 @@ void filestream_rewind(RFILE *stream);
int filestream_close(RFILE *stream);
/**
* filestream_read_file:
* @path : path to file.
* @buf : buffer to allocate and read the contents of the
* file into. Needs to be freed manually.
* @len : optional output integer containing bytes read.
*
* Read the contents of a file into @buf.
*
* @return Non-zero on success.
*/
int64_t filestream_read_file(const char *path, void **buf, int64_t *len);
char* filestream_gets(RFILE *stream, char *s, size_t len);
int filestream_getc(RFILE *stream);
int filestream_vscanf(RFILE *stream, const char* format, va_list *args);
int filestream_scanf(RFILE *stream, const char* format, ...);
int filestream_eof(RFILE *stream);
/**
* filestream_write_file:
* @path : path to file.
* @data : contents to write to the file.
* @size : size of the contents.
*
* Writes data to a file.
*
* @return true on success, otherwise false.
**/
bool filestream_write_file(const char *path, const void *data, int64_t size);
int filestream_putc(RFILE *stream, int c);
@ -105,7 +128,11 @@ const char* filestream_get_path(RFILE *stream);
bool filestream_exists(const char *path);
/* Returned pointer must be freed by the caller. */
/**
* filestream_getline:
*
* Returned pointer must be freed by the caller.
**/
char* filestream_getline(RFILE *stream);
libretro_vfs_implementation_file* filestream_get_vfs_handle(RFILE *stream);

View File

@ -48,7 +48,7 @@ RETRO_BEGIN_DECLS
#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 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)
@ -92,16 +92,20 @@ static INLINE bool string_ends_with_size(const char *str, const char *suffix,
static INLINE bool string_ends_with(const char *str, const char *suffix)
{
if (!str || !suffix)
return false;
return string_ends_with_size(str, suffix, strlen(str), strlen(suffix));
return str && suffix && string_ends_with_size(str, suffix, strlen(str), strlen(suffix));
}
/* Returns the length of 'str' (c.f. strlen()), but only
/**
* strlen_size:
*
* Leaf function.
*
* @return 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' */
* in the first 'size' characters, returns 'size'
**/
static INLINE size_t strlen_size(const char *str, size_t size)
{
size_t i = 0;
@ -130,25 +134,68 @@ static INLINE bool string_is_equal_case_insensitive(const char *a,
return (result == 0);
}
static INLINE bool string_starts_with_case_insensitive(const char *str,
const char *prefix)
{
int result = 0;
const unsigned char *p1 = (const unsigned char*)str;
const unsigned char *p2 = (const unsigned char*)prefix;
if (!str || !prefix)
return false;
if (p1 == p2)
return true;
while ((result = tolower (*p1++) - tolower (*p2)) == 0)
if (*p2++ == '\0')
break;
return (result == 0 || *p2 == '\0');
}
char *string_to_upper(char *s);
char *string_to_lower(char *s);
char *string_ucwords(char *s);
char *string_replace_substring(const char *in, const char *pattern,
const char *by);
char *string_replace_substring(const char *in,
const char *pattern, size_t pattern_len,
const char *replacement, size_t replacement_len);
/* Remove leading whitespaces */
/**
* string_trim_whitespace_left:
*
* Remove leading whitespaces
**/
char *string_trim_whitespace_left(char *const s);
/* Remove trailing whitespaces */
/**
* string_trim_whitespace_right:
*
* Remove trailing whitespaces
**/
char *string_trim_whitespace_right(char *const s);
/* Remove leading and trailing whitespaces */
/**
* string_trim_whitespace:
*
* Remove leading and trailing whitespaces
**/
char *string_trim_whitespace(char *const s);
/*
/**
* word_wrap:
* @dst : pointer to destination buffer.
* @dst_size : size of destination buffer.
* @src : pointer to input string.
* @src_len : length of @src
* @line_width : max number of characters per line.
* @wideglyph_width : not used, but is necessary to keep
* compatibility with word_wrap_wideglyph().
* @max_lines : max lines of destination string.
* 0 means no limit.
*
* Wraps string specified by 'src' to destination buffer
* specified by 'dst' and 'dst_size'.
* This function assumes that all glyphs in the string
@ -156,58 +203,57 @@ char *string_trim_whitespace(char *const s);
* 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,
**/
size_t word_wrap(char *dst, size_t dst_size, const char *src, size_t src_len,
int line_width, int wideglyph_width, unsigned max_lines);
/*
* Wraps string specified by 'src' to destination buffer
* specified by 'dst' and 'dst_size'.
/**
* word_wrap_wideglyph:
* @dst : pointer to destination buffer.
* @dst_size : size of destination buffer.
* @src : pointer to input string.
* @src_len : length of @src
* @line_width : max number of characters per line.
* @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
* @max_lines : max lines of destination string.
* 0 means no limit.
*
* 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'
* 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
* 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);
* @wideglyph_width value.
**/
size_t word_wrap_wideglyph(
char *dst, size_t dst_size,
const char *src, size_t src_len,
int line_width, int wideglyph_width,
unsigned max_lines);
/* Splits string into tokens seperated by 'delim'
/**
* string_tokenize:
*
* Splits string into tokens seperated by @delim
* > Returned token string must be free()'d
* > Returns NULL if token is not found
* > After each call, 'str' is set to the position after the
* > After each call, @str is set to the position after the
* last found token
* > Tokens *include* empty strings
* Usage example:
@ -220,29 +266,120 @@ void word_wrap_wideglyph(char *dst, size_t dst_size, const char *src,
* free(token);
* token = NULL;
* }
*/
**/
char* string_tokenize(char **str, const char *delim);
/* Removes every instance of character 'c' from 'str' */
/**
* string_remove_all_chars:
* @str : input string (must be non-NULL, otherwise UB)
*
* Leaf function.
*
* Removes every instance of character @c from @str
**/
void string_remove_all_chars(char *str, char c);
/* Replaces every instance of character 'find' in 'str'
* with character 'replace' */
/**
* string_replace_all_chars:
* @str : input string (must be non-NULL, otherwise UB)
* @find : character to find
* @replace : character to replace @find with
*
* Hidden non-leaf function cost:
* - Calls strchr (in a loop)
*
* Replaces every instance of character @find in @str
* with character @replace
**/
void string_replace_all_chars(char *str, char find, char replace);
/* Converts string to unsigned integer.
* Returns 0 if string is invalid */
/**
* string_to_unsigned:
* @str : input string
*
* Converts string to unsigned integer.
*
* @return 0 if string is invalid, otherwise > 0
**/
unsigned string_to_unsigned(const char *str);
/* Converts hexadecimal string to unsigned integer.
/**
* string_hex_to_unsigned:
* @str : input string (must be non-NULL, otherwise UB)
*
* Converts hexadecimal string to unsigned integer.
* Handles optional leading '0x'.
* Returns 0 if string is invalid */
*
* @return 0 if string is invalid, otherwise > 0
**/
unsigned string_hex_to_unsigned(const char *str);
char *string_init(const char *src);
void string_set(char **string, const char *src);
/**
* string_count_occurrences_single_character:
*
* Leaf function.
*
* Get the total number of occurrences of character @c in @str.
*
* @return Total number of occurrences of character @c
*/
int string_count_occurrences_single_character(const char *str, char c);
/**
* string_replace_whitespace_with_single_character:
*
* Leaf function.
*
* Replaces all spaces with given character @c.
**/
void string_replace_whitespace_with_single_character(char *str, char c);
/**
* string_replace_multi_space_with_single_space:
*
* Leaf function.
*
* Replaces multiple spaces with a single space in a string.
**/
void string_replace_multi_space_with_single_space(char *str);
/**
* string_remove_all_whitespace:
*
* Leaf function.
*
* Remove all spaces from the given string.
**/
void string_remove_all_whitespace(char *str_trimmed, const char *str);
/* Retrieve the last occurance of the given character in a string. */
int string_index_last_occurance(const char *str, char c);
/**
* string_find_index_substring_string:
* @str : input string (must be non-NULL, otherwise UB)
* @substr : substring to find in @str
*
* Hidden non-leaf function cost:
* - Calls strstr
*
* Find the position of substring @substr in string @str.
**/
int string_find_index_substring_string(const char *str, const char *substr);
/**
* string_copy_only_ascii:
*
* Leaf function.
*
* Strips non-ASCII characters from a string.
**/
void string_copy_only_ascii(char *str_stripped, const char *str);
extern const unsigned char lr_char_props[256];
RETRO_END_DECLS

View File

@ -62,7 +62,7 @@ enum vfs_scheme
VFS_SCHEME_CDROM
};
#ifndef __WINRT__
#if !(defined(__WINRT__) && defined(__cplusplus_winrt))
#ifdef VFS_FRONTEND
struct retro_vfs_file_handle
#else

View File

@ -71,6 +71,12 @@ bool retro_vfs_dirent_is_dir_impl(libretro_vfs_implementation_dir *dirstream);
int retro_vfs_closedir_impl(libretro_vfs_implementation_dir *dirstream);
#ifdef __WINRT__
void uwp_set_acl(const wchar_t* path, const wchar_t* AccessString);
#endif
RETRO_END_DECLS
#endif

View File

@ -1,4 +1,4 @@
/* Copyright (C) 2010-2016 The RetroArch team
/* Copyright (C) 2010-2020 The RetroArch team
*
* ---------------------------------------------------------------------------------------
* The following license statement only applies to this file (gx_pthread.h).
@ -84,10 +84,13 @@
typedef OSThread pthread_t;
typedef mutex_t pthread_mutex_t;
typedef OSCond pthread_cond_t;
#if defined(GX_PTHREAD_LEGACY)
typedef void* pthread_mutexattr_t;
typedef int pthread_attr_t;
typedef OSCond pthread_cond_t;
typedef OSCond pthread_condattr_t;
#endif
static INLINE int pthread_create(pthread_t *thread,
const pthread_attr_t *attr, void *(*start_routine)(void*), void *arg)
@ -180,6 +183,4 @@ static INLINE int pthread_cond_destroy(pthread_cond_t *cond)
return LWP_CondDestroy(*cond);
}
extern int pthread_equal(pthread_t t1, pthread_t t2);
#endif

View File

@ -1,4 +1,4 @@
/* Copyright (C) 2010-2016 The RetroArch team
/* Copyright (C) 2010-2020 The RetroArch team
*
* ---------------------------------------------------------------------------------------
* The following license statement only applies to this file (psp_pthread.h).
@ -26,6 +26,7 @@
#ifdef VITA
#include <psp2/kernel/threadmgr.h>
#include <sys/time.h>
#else
#include <pspkernel.h>
#include <pspthreadman.h>
@ -61,7 +62,6 @@ typedef struct
sthreadEntry start_routine;
} sthread_args_struct;
static int psp_thread_wrap(SceSize args, void *argp)
{
sthread_args_struct* sthread_args = (sthread_args_struct*)argp;
@ -72,7 +72,7 @@ static int psp_thread_wrap(SceSize args, void *argp)
static INLINE int pthread_create(pthread_t *thread,
const pthread_attr_t *attr, void *(*start_routine)(void*), void *arg)
{
sprintf(name_buffer, "0x%08X", (uint32_t) thread);
snprintf(name_buffer, sizeof(name_buffer), "0x%08X", (unsigned int) thread);
#ifdef VITA
*thread = sceKernelCreateThread(name_buffer, psp_thread_wrap,
@ -92,11 +92,11 @@ static INLINE int pthread_create(pthread_t *thread,
static INLINE int pthread_mutex_init(pthread_mutex_t *mutex,
const pthread_mutexattr_t *attr)
{
sprintf(name_buffer, "0x%08X", (uint32_t) mutex);
snprintf(name_buffer, sizeof(name_buffer), "0x%08X", (unsigned int) mutex);
#ifdef VITA
*mutex = sceKernelCreateMutex(name_buffer, 0, 0, 0);
if(*mutex<0)
if (*mutex<0)
return *mutex;
return 0;
#else
@ -117,7 +117,6 @@ static INLINE int pthread_mutex_lock(pthread_mutex_t *mutex)
{
#ifdef VITA
int ret = sceKernelLockMutex(*mutex, 1, 0);
//sceClibPrintf("pthread_mutex_lock: %x\n",ret);
return ret;
#else
@ -130,7 +129,6 @@ static INLINE int pthread_mutex_unlock(pthread_mutex_t *mutex)
{
#ifdef VITA
int ret = sceKernelUnlockMutex(*mutex, 1);
//sceClibPrintf("pthread_mutex_unlock: %x\n",ret);
return ret;
#else
/* FIXME: stub */
@ -138,18 +136,15 @@ static INLINE int pthread_mutex_unlock(pthread_mutex_t *mutex)
#endif
}
static INLINE int pthread_join(pthread_t thread, void **retval)
{
#ifdef VITA
int res = sceKernelWaitThreadEnd(thread, 0, 0);
if (res < 0) {
return res;
}
return sceKernelDeleteThread(thread);
int res = sceKernelWaitThreadEnd(thread, 0, 0);
if (res < 0)
return res;
return sceKernelDeleteThread(thread);
#else
SceUInt timeout = (SceUInt)-1;
SceUInt timeout = (SceUInt)-1;
sceKernelWaitThreadEnd(thread, &timeout);
exit_status = sceKernelGetThreadExitStatus(thread);
sceKernelDeleteThread(thread);
@ -171,20 +166,18 @@ static INLINE int pthread_cond_wait(pthread_cond_t *cond,
pthread_mutex_t *mutex)
{
#ifdef VITA
int ret = pthread_mutex_lock(&cond->mutex);
if (ret < 0) {
return ret;
}
++cond->waiting;
pthread_mutex_unlock(mutex);
pthread_mutex_unlock(&cond->mutex);
int ret = pthread_mutex_lock(&cond->mutex);
if (ret < 0)
return ret;
++cond->waiting;
pthread_mutex_unlock(mutex);
pthread_mutex_unlock(&cond->mutex);
ret = sceKernelWaitSema(cond->sema, 1, 0);
if (ret < 0) {
sceClibPrintf("Premature wakeup: %08X", ret);
}
pthread_mutex_lock(mutex);
return ret;
ret = sceKernelWaitSema(cond->sema, 1, 0);
if (ret < 0)
sceClibPrintf("Premature wakeup: %08X", ret);
pthread_mutex_lock(mutex);
return ret;
#else
/* FIXME: stub */
sceKernelDelayThread(10000);
@ -196,26 +189,24 @@ static INLINE int pthread_cond_timedwait(pthread_cond_t *cond,
pthread_mutex_t *mutex, const struct timespec *abstime)
{
#ifdef VITA
int ret = pthread_mutex_lock(&cond->mutex);
if (ret < 0) {
return ret;
}
++cond->waiting;
pthread_mutex_unlock(mutex);
pthread_mutex_unlock(&cond->mutex);
SceUInt timeout = 0;
timeout = abstime->tv_sec;
timeout += abstime->tv_nsec / 1.0e6;
ret = sceKernelWaitSema(cond->sema, 1, &timeout);
if (ret < 0) {
sceClibPrintf("Premature wakeup: %08X", ret);
}
pthread_mutex_lock(mutex);
return ret;
int ret = pthread_mutex_lock(&cond->mutex);
if (ret < 0)
return ret;
++cond->waiting;
pthread_mutex_unlock(mutex);
pthread_mutex_unlock(&cond->mutex);
SceUInt timeout = 0;
timeout = abstime->tv_sec;
timeout += abstime->tv_nsec / 1.0e6;
ret = sceKernelWaitSema(cond->sema, 1, &timeout);
if (ret < 0)
sceClibPrintf("Premature wakeup: %08X", ret);
pthread_mutex_lock(mutex);
return ret;
#else
/* FIXME: stub */
return 1;
@ -226,27 +217,25 @@ static INLINE int pthread_cond_init(pthread_cond_t *cond,
const pthread_condattr_t *attr)
{
#ifdef VITA
pthread_mutex_init(&cond->mutex,NULL);
sceClibPrintf("pthread_cond_init: mutex %x\n",cond->mutex);
if(cond->mutex<0){
return cond->mutex;
}
sprintf(name_buffer, "0x%08X", (uint32_t) cond);
//cond->sema = sceKernelCreateCond(name_buffer, 0, cond->mutex, 0);
cond->sema = sceKernelCreateSema(name_buffer, 0, 0, 1, 0);
sceClibPrintf("pthread_cond_init: sema %x\n",cond->sema);
if(cond->sema<0){
pthread_mutex_destroy(&cond->mutex);
return cond->sema;
}
cond->waiting = 0;
return 0;
pthread_mutex_init(&cond->mutex,NULL);
if (cond->mutex<0)
return cond->mutex;
snprintf(name_buffer, sizeof(name_buffer), "0x%08X", (unsigned int) cond);
cond->sema = sceKernelCreateSema(name_buffer, 0, 0, 1, 0);
if (cond->sema < 0)
{
pthread_mutex_destroy(&cond->mutex);
return cond->sema;
}
cond->waiting = 0;
return 0;
#else
/* FIXME: stub */
return 1;
@ -257,10 +246,10 @@ static INLINE int pthread_cond_signal(pthread_cond_t *cond)
{
#ifdef VITA
pthread_mutex_lock(&cond->mutex);
if (cond->waiting) {
if (cond->waiting)
{
--cond->waiting;
int ret = sceKernelSignalSema(cond->sema, 1);
sceClibPrintf("pthread_cond_signal: %x\n",ret);
sceKernelSignalSema(cond->sema, 1);
}
pthread_mutex_unlock(&cond->mutex);
return 0;
@ -280,7 +269,7 @@ static INLINE int pthread_cond_destroy(pthread_cond_t *cond)
{
#ifdef VITA
int ret = sceKernelDeleteSema(cond->sema);
if(ret < 0)
if (ret < 0)
return ret;
return sceKernelDeleteMutex(cond->mutex);
@ -290,7 +279,6 @@ static INLINE int pthread_cond_destroy(pthread_cond_t *cond)
#endif
}
static INLINE int pthread_detach(pthread_t thread)
{
return 0;

View File

@ -1,4 +1,4 @@
/* Copyright (C) 2010-2016 The RetroArch team
/* Copyright (C) 2010-2020 The RetroArch team
*
* ---------------------------------------------------------------------------------------
* The following license statement only applies to this file (rthreads.c).
@ -21,10 +21,13 @@
*/
#ifdef __unix__
#ifndef __sun__
#define _POSIX_C_SOURCE 199309
#endif
#endif
#include <stdlib.h>
#include <string.h>
#include <boolean.h>
#include <rthreads/rthreads.h>
@ -37,21 +40,23 @@
#include <xtl.h>
#else
#define WIN32_LEAN_AND_MEAN
#ifndef _WIN32_WINNT
#define _WIN32_WINNT 0x0500 /*_WIN32_WINNT_WIN2K */
#endif
#include <windows.h>
#include <mmsystem.h>
#endif
#elif defined(GEKKO)
#include <ogc/lwp_watchdog.h>
#include "gx_pthread.h"
#elif defined(PSP) || defined(VITA)
#include "psp_pthread.h"
#elif defined(__PS3__)
#include <pthread.h>
#include <sys/sys_time.h>
#elif defined(_3DS)
#include "ctr_pthread.h"
#else
#include <pthread.h>
#include <time.h>
#endif
#if defined(VITA)
#if defined(VITA) || defined(BSD) || defined(ORBIS) || defined(__mips__) || defined(_3DS)
#include <sys/time.h>
#endif
@ -70,6 +75,7 @@ struct sthread
{
#ifdef USE_WIN32_THREADS
HANDLE thread;
DWORD id;
#else
pthread_t id;
#endif
@ -78,16 +84,49 @@ struct sthread
struct slock
{
#ifdef USE_WIN32_THREADS
HANDLE lock;
CRITICAL_SECTION lock;
#else
pthread_mutex_t lock;
#endif
};
#ifdef USE_WIN32_THREADS
/* The syntax we'll use is mind-bending unless we use a struct. Plus, we might want to store more info later */
/* This will be used as a linked list immplementing a queue of waiting threads */
struct queue_entry
{
struct queue_entry *next;
};
#endif
struct scond
{
#ifdef USE_WIN32_THREADS
/* With this implementation of scond, we don't have any way of waking
* (or even identifying) specific threads
* But we need to wake them in the order indicated by the queue.
* This potato token will get get passed around every waiter.
* The bearer can test whether he's next, and hold onto the potato if he is.
* When he's done he can then put it back into play to progress
* the queue further */
HANDLE hot_potato;
/* The primary signalled event. Hot potatoes are passed until this is set. */
HANDLE event;
/* the head of the queue; NULL if queue is empty */
struct queue_entry *head;
/* equivalent to the queue length */
int waiters;
/* how many waiters in the queue have been conceptually wakened by signals
* (even if we haven't managed to actually wake them yet) */
int wakens;
/* used to control access to this scond, in case the user fails */
CRITICAL_SECTION cs;
#else
pthread_cond_t cond;
#endif
@ -119,46 +158,107 @@ static void *thread_wrap(void *data_)
*/
sthread_t *sthread_create(void (*thread_func)(void*), void *userdata)
{
return sthread_create_with_priority(thread_func, userdata, 0);
}
/* TODO/FIXME - this needs to be implemented for Switch/3DS */
#if !defined(SWITCH) && !defined(USE_WIN32_THREADS) && !defined(_3DS) && !defined(GEKKO) && !defined(__HAIKU__) && !defined(EMSCRIPTEN)
#define HAVE_THREAD_ATTR
#endif
/**
* sthread_create_with_priority:
* @start_routine : thread entry callback function
* @userdata : pointer to userdata that will be made
* available in thread entry callback function
* @thread_priority : thread priority hint value from [1-100]
*
* Create a new thread. It is possible for the caller to give a hint
* for the thread's priority from [1-100]. Any passed in @thread_priority
* values that are outside of this range will cause sthread_create() to
* create a new thread using the operating system's default thread
* priority.
*
* Returns: pointer to new thread if successful, otherwise NULL.
*/
sthread_t *sthread_create_with_priority(void (*thread_func)(void*), void *userdata, int thread_priority)
{
#ifdef HAVE_THREAD_ATTR
pthread_attr_t thread_attr;
bool thread_attr_needed = false;
#endif
bool thread_created = false;
struct thread_data *data = NULL;
sthread_t *thread = (sthread_t*)calloc(1, sizeof(*thread));
sthread_t *thread = (sthread_t*)malloc(sizeof(*thread));
if (!thread)
return NULL;
data = (struct thread_data*)calloc(1, sizeof(*data));
if (!data)
goto error;
if (!(data = (struct thread_data*)malloc(sizeof(*data))))
{
free(thread);
return NULL;
}
data->func = thread_func;
data->userdata = userdata;
data->func = thread_func;
data->userdata = userdata;
thread->id = 0;
#ifdef USE_WIN32_THREADS
thread->thread = CreateThread(NULL, 0, thread_wrap, data, 0, NULL);
thread_created = !!thread->thread;
thread->thread = CreateThread(NULL, 0, thread_wrap,
data, 0, &thread->id);
thread_created = !!thread->thread;
#else
thread_created = pthread_create(&thread->id, NULL, thread_wrap, data) == 0;
#ifdef HAVE_THREAD_ATTR
pthread_attr_init(&thread_attr);
if ((thread_priority >= 1) && (thread_priority <= 100))
{
struct sched_param sp;
memset(&sp, 0, sizeof(struct sched_param));
sp.sched_priority = thread_priority;
pthread_attr_setschedpolicy(&thread_attr, SCHED_RR);
pthread_attr_setschedparam(&thread_attr, &sp);
thread_attr_needed = true;
}
#if defined(VITA)
pthread_attr_setstacksize(&thread_attr , 0x10000 );
thread_attr_needed = true;
#elif defined(__APPLE__)
/* Default stack size on Apple is 512Kb;
* for PS2 disc scanning and other reasons, we'd like 2MB. */
pthread_attr_setstacksize(&thread_attr , 0x200000 );
thread_attr_needed = true;
#endif
if (!thread_created)
goto error;
if (thread_attr_needed)
thread_created = pthread_create(&thread->id, &thread_attr, thread_wrap, data) == 0;
else
thread_created = pthread_create(&thread->id, NULL, thread_wrap, data) == 0;
return thread;
pthread_attr_destroy(&thread_attr);
#else
thread_created = pthread_create(&thread->id, NULL, thread_wrap, data) == 0;
#endif
error:
if (data)
free(data);
#endif
if (thread_created)
return thread;
free(data);
free(thread);
return NULL;
}
/**
* sthread_detach:
* @thread : pointer to thread object
* @thread : pointer to thread object
*
* Detach a thread. When a detached thread terminates, its
* resource sare automatically released back to the system
* without the need for another thread to join with the
* resources are automatically released back to the system
* without the need for another thread to join with the
* terminated thread.
*
* Returns: 0 on success, otherwise it returns a non-zero error number.
@ -170,23 +270,27 @@ int sthread_detach(sthread_t *thread)
free(thread);
return 0;
#else
return pthread_detach(thread->id);
int ret = pthread_detach(thread->id);
free(thread);
return ret;
#endif
}
/**
* sthread_join:
* @thread : pointer to thread object
* @thread : pointer to thread object
*
* Join with a terminated thread. Waits for the thread specified by
* @thread to terminate. If that thread has already terminated, then
* it will return immediately. The thread specified by @thread must
* be joinable.
*
*
* Returns: 0 on success, otherwise it returns a non-zero error number.
*/
void sthread_join(sthread_t *thread)
{
if (!thread)
return;
#ifdef USE_WIN32_THREADS
WaitForSingleObject(thread->thread, INFINITE);
CloseHandle(thread->thread);
@ -196,25 +300,22 @@ void sthread_join(sthread_t *thread)
free(thread);
}
#if !defined(GEKKO)
/**
* sthread_isself:
* @thread : pointer to thread object
* @thread : pointer to thread object
*
* Join with a terminated thread. Waits for the thread specified by
* @thread to terminate. If that thread has already terminated, then
* it will return immediately. The thread specified by @thread must
* be joinable.
*
* Returns: true (1) if calling thread is the specified thread
*/
bool sthread_isself(sthread_t *thread)
{
#ifdef USE_WIN32_THREADS
return GetCurrentThread() == thread->thread;
return thread ? GetCurrentThreadId() == thread->id : false;
#else
return pthread_equal(pthread_self(),thread->id);
return thread ? pthread_equal(pthread_self(), thread->id) : false;
#endif
}
#endif
/**
* slock_new:
@ -229,26 +330,21 @@ slock_t *slock_new(void)
slock_t *lock = (slock_t*)calloc(1, sizeof(*lock));
if (!lock)
return NULL;
#ifdef USE_WIN32_THREADS
lock->lock = CreateMutex(NULL, FALSE, NULL);
if (!lock->lock)
goto error;
InitializeCriticalSection(&lock->lock);
#else
if ((pthread_mutex_init(&lock->lock, NULL) < 0))
goto error;
if (pthread_mutex_init(&lock->lock, NULL) != 0)
{
free(lock);
return NULL;
}
#endif
return lock;
error:
slock_free(lock);
return NULL;
}
/**
* slock_free:
* @lock : pointer to mutex object
* @lock : pointer to mutex object
*
* Frees a mutex.
**/
@ -258,7 +354,7 @@ void slock_free(slock_t *lock)
return;
#ifdef USE_WIN32_THREADS
CloseHandle(lock->lock);
DeleteCriticalSection(&lock->lock);
#else
pthread_mutex_destroy(&lock->lock);
#endif
@ -267,7 +363,7 @@ void slock_free(slock_t *lock)
/**
* slock_lock:
* @lock : pointer to mutex object
* @lock : pointer to mutex object
*
* Locks a mutex. If a mutex is already locked by
* another thread, the calling thread shall block until
@ -275,23 +371,43 @@ void slock_free(slock_t *lock)
**/
void slock_lock(slock_t *lock)
{
if (!lock)
return;
#ifdef USE_WIN32_THREADS
WaitForSingleObject(lock->lock, INFINITE);
EnterCriticalSection(&lock->lock);
#else
pthread_mutex_lock(&lock->lock);
#endif
}
/**
* slock_try_lock:
* @lock : pointer to mutex object
*
* Attempts to lock a mutex. If a mutex is already locked by
* another thread, return false. If the lock is acquired, return true.
**/
bool slock_try_lock(slock_t *lock)
{
#ifdef USE_WIN32_THREADS
return lock && TryEnterCriticalSection(&lock->lock);
#else
return lock && (pthread_mutex_trylock(&lock->lock) == 0);
#endif
}
/**
* slock_unlock:
* @lock : pointer to mutex object
* @lock : pointer to mutex object
*
* Unlocks a mutex.
**/
void slock_unlock(slock_t *lock)
{
if (!lock)
return;
#ifdef USE_WIN32_THREADS
ReleaseMutex(lock->lock);
LeaveCriticalSection(&lock->lock);
#else
pthread_mutex_unlock(&lock->lock);
#endif
@ -308,21 +424,50 @@ void slock_unlock(slock_t *lock)
**/
scond_t *scond_new(void)
{
bool event_created = false;
scond_t *cond = (scond_t*)calloc(1, sizeof(*cond));
if (!cond)
return NULL;
#ifdef USE_WIN32_THREADS
cond->event = CreateEvent(NULL, FALSE, FALSE, NULL);
event_created = !!cond->event;
#else
event_created = (pthread_cond_init(&cond->cond, NULL) == 0);
#endif
if (!event_created)
/* This is very complex because recreating condition variable semantics
* with Win32 parts is not easy.
*
* The main problem is that a condition variable can't be used to
* "pre-wake" a thread (it will get wakened only after it's waited).
*
* Whereas a win32 event can pre-wake a thread (the event will be set
* in advance, so a 'waiter' won't even have to wait on it).
*
* Keep in mind a condition variable can apparently pre-wake a thread,
* insofar as spurious wakeups are always possible,
* but nobody will be expecting this and it does not need to be simulated.
*
* Moreover, we won't be doing this, because it counts as a spurious wakeup
* -- someone else with a genuine claim must get wakened, in any case.
*
* Therefore we choose to wake only one of the correct waiting threads.
* So at the very least, we need to do something clever. But there's
* bigger problems.
* We don't even have a straightforward way in win32 to satisfy
* pthread_cond_wait's atomicity requirement. The bulk of this
* algorithm is solving that.
*
* Note: We might could simplify this using vista+ condition variables,
* but we wanted an XP compatible solution. */
if (!(cond->event = CreateEvent(NULL, FALSE, FALSE, NULL)))
goto error;
if (!(cond->hot_potato = CreateEvent(NULL, FALSE, FALSE, NULL)))
{
CloseHandle(cond->event);
goto error;
}
InitializeCriticalSection(&cond->cs);
#else
if (pthread_cond_init(&cond->cond, NULL) != 0)
goto error;
#endif
return cond;
@ -333,7 +478,7 @@ error:
/**
* scond_free:
* @cond : pointer to condition variable object
* @cond : pointer to condition variable object
*
* Frees a condition variable.
**/
@ -344,26 +489,231 @@ void scond_free(scond_t *cond)
#ifdef USE_WIN32_THREADS
CloseHandle(cond->event);
CloseHandle(cond->hot_potato);
DeleteCriticalSection(&cond->cs);
#else
pthread_cond_destroy(&cond->cond);
#endif
free(cond);
}
#ifdef USE_WIN32_THREADS
static bool _scond_wait_win32(scond_t *cond, slock_t *lock, DWORD dwMilliseconds)
{
struct queue_entry myentry;
struct queue_entry **ptr;
#if _WIN32_WINNT >= 0x0500 || defined(_XBOX)
static LARGE_INTEGER performanceCounterFrequency;
LARGE_INTEGER tsBegin;
static bool first_init = true;
#else
static bool beginPeriod = false;
DWORD tsBegin;
#endif
DWORD waitResult;
DWORD dwFinalTimeout = dwMilliseconds; /* Careful! in case we begin in the head,
we don't do the hot potato stuff,
so this timeout needs presetting. */
/* Reminder: `lock` is held before this is called. */
/* however, someone else may have called scond_signal without the lock. soo... */
EnterCriticalSection(&cond->cs);
/* since this library is meant for realtime game software
* I have no problem setting this to 1 and forgetting about it. */
#if _WIN32_WINNT >= 0x0500 || defined(_XBOX)
if (first_init)
{
performanceCounterFrequency.QuadPart = 0;
first_init = false;
}
if (performanceCounterFrequency.QuadPart == 0)
QueryPerformanceFrequency(&performanceCounterFrequency);
#else
if (!beginPeriod)
{
beginPeriod = true;
timeBeginPeriod(1);
}
#endif
/* Now we can take a good timestamp for use in faking the timeout ourselves. */
/* But don't bother unless we need to (to save a little time) */
if (dwMilliseconds != INFINITE)
#if _WIN32_WINNT >= 0x0500 || defined(_XBOX)
QueryPerformanceCounter(&tsBegin);
#else
tsBegin = timeGetTime();
#endif
/* add ourselves to a queue of waiting threads */
ptr = &cond->head;
/* walk to the end of the linked list */
while (*ptr)
ptr = &((*ptr)->next);
*ptr = &myentry;
myentry.next = NULL;
cond->waiters++;
/* now the conceptual lock release and condition block are supposed to be atomic.
* we can't do that in Windows, but we can simulate the effects by using
* the queue, by the following analysis:
* What happens if they aren't atomic?
*
* 1. a signaller can rush in and signal, expecting a waiter to get it;
* but the waiter wouldn't, because he isn't blocked yet.
* Solution: Win32 events make this easy. The event will sit there enabled
*
* 2. a signaller can rush in and signal, and then turn right around and wait.
* Solution: the signaller will get queued behind the waiter, who's
* enqueued before he releases the mutex. */
/* It's my turn if I'm the head of the queue.
* Check to see if it's my turn. */
while (cond->head != &myentry)
{
/* It isn't my turn: */
DWORD timeout = INFINITE;
/* As long as someone is even going to be able to wake up
* when they receive the potato, keep it going round. */
if (cond->wakens > 0)
SetEvent(cond->hot_potato);
/* Assess the remaining timeout time */
if (dwMilliseconds != INFINITE)
{
#if _WIN32_WINNT >= 0x0500 || defined(_XBOX)
LARGE_INTEGER now;
LONGLONG elapsed;
QueryPerformanceCounter(&now);
elapsed = now.QuadPart - tsBegin.QuadPart;
elapsed *= 1000;
elapsed /= performanceCounterFrequency.QuadPart;
#else
DWORD now = timeGetTime();
DWORD elapsed = now - tsBegin;
#endif
/* Try one last time with a zero timeout (keeps the code simpler) */
if (elapsed > dwMilliseconds)
elapsed = dwMilliseconds;
timeout = dwMilliseconds - elapsed;
}
/* Let someone else go */
LeaveCriticalSection(&lock->lock);
LeaveCriticalSection(&cond->cs);
/* Wait a while to catch the hot potato..
* someone else should get a chance to go */
/* After all, it isn't my turn (and it must be someone else's) */
Sleep(0);
waitResult = WaitForSingleObject(cond->hot_potato, timeout);
/* I should come out of here with the main lock taken */
EnterCriticalSection(&lock->lock);
EnterCriticalSection(&cond->cs);
if (waitResult == WAIT_TIMEOUT)
{
/* Out of time! Now, let's think about this. I do have the potato now--
* maybe it's my turn, and I have the event?
* If that's the case, I could proceed right now without aborting
* due to timeout.
*
* However.. I DID wait a real long time. The caller was willing
* to wait that long.
*
* I choose to give him one last chance with a zero timeout
* in the next step
*/
if (cond->head == &myentry)
{
dwFinalTimeout = 0;
break;
}
else
{
/* It's not our turn and we're out of time. Give up.
* Remove ourself from the queue and bail. */
struct queue_entry *curr = cond->head;
while (curr->next != &myentry)
curr = curr->next;
curr->next = myentry.next;
cond->waiters--;
LeaveCriticalSection(&cond->cs);
return false;
}
}
}
/* It's my turn now -- and I hold the potato */
/* I still have the main lock, in any case */
/* I need to release it so that someone can set the event */
LeaveCriticalSection(&lock->lock);
LeaveCriticalSection(&cond->cs);
/* Wait for someone to actually signal this condition */
/* We're the only waiter waiting on the event right now -- everyone else
* is waiting on something different */
waitResult = WaitForSingleObject(cond->event, dwFinalTimeout);
/* Take the main lock so we can do work. Nobody else waits on this lock
* for very long, so even though it's GO TIME we won't have to wait long */
EnterCriticalSection(&lock->lock);
EnterCriticalSection(&cond->cs);
/* Remove ourselves from the queue */
cond->head = myentry.next;
cond->waiters--;
if (waitResult == WAIT_TIMEOUT)
{
/* Oops! ran out of time in the final wait. Just bail. */
LeaveCriticalSection(&cond->cs);
return false;
}
/* If any other wakenings are pending, go ahead and set it up */
/* There may actually be no waiters. That's OK. The first waiter will come in,
* find it's his turn, and immediately get the signaled event */
cond->wakens--;
if (cond->wakens > 0)
{
SetEvent(cond->event);
/* Progress the queue: Put the hot potato back into play. It'll be
* tossed around until next in line gets it */
SetEvent(cond->hot_potato);
}
LeaveCriticalSection(&cond->cs);
return true;
}
#endif
/**
* scond_wait:
* @cond : pointer to condition variable object
* @lock : pointer to mutex object
* @cond : pointer to condition variable object
* @lock : pointer to mutex object
*
* Block on a condition variable (i.e. wait on a condition).
* Block on a condition variable (i.e. wait on a condition).
**/
void scond_wait(scond_t *cond, slock_t *lock)
{
#ifdef USE_WIN32_THREADS
WaitForSingleObject(cond->event, 0);
SignalObjectAndWait(lock->lock, cond->event, INFINITE, FALSE);
slock_lock(lock);
_scond_wait_win32(cond, lock, INFINITE);
#else
pthread_cond_wait(&cond->cond, &lock->lock);
#endif
@ -371,17 +721,25 @@ void scond_wait(scond_t *cond, slock_t *lock)
/**
* scond_broadcast:
* @cond : pointer to condition variable object
* @cond : pointer to condition variable object
*
* Broadcast a condition. Unblocks all threads currently blocked
* on the specified condition variable @cond.
* on the specified condition variable @cond.
**/
int scond_broadcast(scond_t *cond)
{
#ifdef USE_WIN32_THREADS
/* FIXME _- check how this function should differ
* from scond_signal implementation. */
SetEvent(cond->event);
/* Remember, we currently have mutex */
if (cond->waiters != 0)
{
/* Awaken everything which is currently queued up */
if (cond->wakens == 0)
SetEvent(cond->event);
cond->wakens = cond->waiters;
/* Since there is now at least one pending waken, the potato must be in play */
SetEvent(cond->hot_potato);
}
return 0;
#else
return pthread_cond_broadcast(&cond->cond);
@ -390,15 +748,45 @@ int scond_broadcast(scond_t *cond)
/**
* scond_signal:
* @cond : pointer to condition variable object
* @cond : pointer to condition variable object
*
* Signal a condition. Unblocks at least one of the threads currently blocked
* on the specified condition variable @cond.
* on the specified condition variable @cond.
**/
void scond_signal(scond_t *cond)
{
#ifdef USE_WIN32_THREADS
SetEvent(cond->event);
/* Unfortunately, pthread_cond_signal does not require that the
* lock be held in advance */
/* To avoid stomping on the condvar from other threads, we need
* to control access to it with this */
EnterCriticalSection(&cond->cs);
/* remember: we currently have mutex */
if (cond->waiters == 0)
{
LeaveCriticalSection(&cond->cs);
return;
}
/* wake up the next thing in the queue */
if (cond->wakens == 0)
SetEvent(cond->event);
cond->wakens++;
/* The data structure is done being modified.. I think we can leave the CS now.
* This would prevent some other thread from receiving the hot potato and then
* immediately stalling for the critical section.
* But remember, we were trying to replicate a semantic where this entire
* scond_signal call was controlled (by the user) by a lock.
* So in case there's trouble with this, we can move it after SetEvent() */
LeaveCriticalSection(&cond->cs);
/* Since there is now at least one pending waken, the potato must be in play */
SetEvent(cond->hot_potato);
#else
pthread_cond_signal(&cond->cond);
#endif
@ -406,8 +794,8 @@ void scond_signal(scond_t *cond)
/**
* scond_wait_timeout:
* @cond : pointer to condition variable object
* @lock : pointer to mutex object
* @cond : pointer to condition variable object
* @lock : pointer to mutex object
* @timeout_us : timeout (in microseconds)
*
* Try to block on a condition variable (i.e. wait on a condition) until
@ -419,56 +807,129 @@ void scond_signal(scond_t *cond)
bool scond_wait_timeout(scond_t *cond, slock_t *lock, int64_t timeout_us)
{
#ifdef USE_WIN32_THREADS
DWORD ret;
WaitForSingleObject(cond->event, 0);
ret = SignalObjectAndWait(lock->lock, cond->event,
(DWORD)(timeout_us) / 1000, FALSE);
slock_lock(lock);
return ret == WAIT_OBJECT_0;
/* How to convert a microsecond (us) timeout to millisecond (ms)?
*
* Someone asking for a 0 timeout clearly wants immediate timeout.
* Someone asking for a 1 timeout clearly wants an actual timeout
* of the minimum length */
/* The implementation of a 0 timeout here with pthreads is sketchy.
* It isn't clear what happens if pthread_cond_timedwait is called with NOW.
* Moreover, it is possible that this thread gets pre-empted after the
* clock_gettime but before the pthread_cond_timedwait.
* In order to help smoke out problems caused by this strange usage,
* let's treat a 0 timeout as always timing out.
*/
if (timeout_us == 0)
return false;
else if (timeout_us < 1000)
return _scond_wait_win32(cond, lock, 1);
/* Someone asking for 1000 or 1001 timeout shouldn't
* accidentally get 2ms. */
return _scond_wait_win32(cond, lock, timeout_us / 1000);
#else
int ret;
int64_t seconds, remainder;
struct timespec now = {0};
struct timespec now;
#ifdef __MACH__
/* OSX doesn't have clock_gettime. */
clock_serv_t cclock;
mach_timespec_t mts;
host_get_clock_service(mach_host_self(), CALENDAR_CLOCK, &cclock);
clock_get_time(cclock, &mts);
mach_port_deallocate(mach_task_self(), cclock);
now.tv_sec = mts.tv_sec;
now.tv_nsec = mts.tv_nsec;
#elif defined(__PS3__)
#elif !defined(__PSL1GHT__) && defined(__PS3__)
sys_time_sec_t s;
sys_time_nsec_t n;
sys_time_get_current_time(&s, &n);
now.tv_sec = s;
now.tv_nsec = n;
#elif defined(__mips__) || defined(VITA)
now.tv_sec = s;
now.tv_nsec = n;
#elif defined(PS2)
int tickms = ps2_clock();
now.tv_sec = tickms / 1000;
now.tv_nsec = tickms * 1000;
#elif !defined(DINGUX_BETA) && (defined(__mips__) || defined(VITA) || defined(_3DS))
struct timeval tm;
gettimeofday(&tm, NULL);
now.tv_sec = tm.tv_sec;
now.tv_nsec = tm.tv_usec * 1000;
now.tv_sec = tm.tv_sec;
now.tv_nsec = tm.tv_usec * 1000;
#elif defined(RETRO_WIN32_USE_PTHREADS)
_ftime64_s(&now);
#elif !defined(GEKKO)
/* timeout on libogc is duration, not end time. */
#elif defined(GEKKO)
/* Avoid gettimeofday due to it being reported to be broken */
const uint64_t tickms = gettime() / TB_TIMER_CLOCK;
now.tv_sec = tickms / 1000;
now.tv_nsec = tickms * 1000;
#else
clock_gettime(CLOCK_REALTIME, &now);
#endif
seconds = timeout_us / INT64_C(1000000);
remainder = timeout_us % INT64_C(1000000);
seconds = timeout_us / INT64_C(1000000);
remainder = timeout_us % INT64_C(1000000);
now.tv_sec += seconds;
now.tv_nsec += remainder * INT64_C(1000);
now.tv_sec += seconds;
now.tv_nsec += remainder * INT64_C(1000);
ret = pthread_cond_timedwait(&cond->cond, &lock->lock, &now);
return (ret == 0);
if (now.tv_nsec > 1000000000)
{
now.tv_nsec -= 1000000000;
now.tv_sec += 1;
}
return (pthread_cond_timedwait(&cond->cond, &lock->lock, &now) == 0);
#endif
}
#ifdef HAVE_THREAD_STORAGE
bool sthread_tls_create(sthread_tls_t *tls)
{
#ifdef USE_WIN32_THREADS
return (*tls = TlsAlloc()) != TLS_OUT_OF_INDEXES;
#else
return pthread_key_create((pthread_key_t*)tls, NULL) == 0;
#endif
}
bool sthread_tls_delete(sthread_tls_t *tls)
{
#ifdef USE_WIN32_THREADS
return TlsFree(*tls) != 0;
#else
return pthread_key_delete(*tls) == 0;
#endif
}
void *sthread_tls_get(sthread_tls_t *tls)
{
#ifdef USE_WIN32_THREADS
return TlsGetValue(*tls);
#else
return pthread_getspecific(*tls);
#endif
}
bool sthread_tls_set(sthread_tls_t *tls, const void *data)
{
#ifdef USE_WIN32_THREADS
return TlsSetValue(*tls, (void*)data) != 0;
#else
return pthread_setspecific(*tls, data) == 0;
#endif
}
#endif
uintptr_t sthread_get_thread_id(sthread_t *thread)
{
if (thread)
return (uintptr_t)thread->id;
return 0;
}
uintptr_t sthread_get_current_thread_id(void)
{
#ifdef USE_WIN32_THREADS
return (uintptr_t)GetCurrentThreadId();
#else
return (uintptr_t)pthread_self();
#endif
}

View File

@ -1,4 +1,4 @@
/* Copyright (C) 2010-2016 The RetroArch team
/* Copyright (C) 2010-2020 The RetroArch team
*
* ---------------------------------------------------------------------------------------
* The following license statement only applies to this file (xenon_sdl_threads.c).
@ -20,7 +20,7 @@
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*/
// libSDLxenon doesn't implement this yet :[. Implement it very stupidly for now. ;)
/* libSDLxenon doesn't implement this yet :[. Implement it very stupidly for now. ;) */
#include "SDL_thread.h"
#include "SDL_mutex.h"
@ -56,4 +56,3 @@ int SDL_CondSignal(SDL_cond *cond)
*(volatile bool*)cond = false;
return 0;
}

View File

@ -25,7 +25,6 @@
#include <string.h>
#include <stdarg.h>
#include <ctype.h>
#include <errno.h>
#ifdef HAVE_CONFIG_H
#include "config.h"
@ -46,7 +45,6 @@ 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;
@ -109,18 +107,14 @@ bool filestream_exists(const char *path)
if (!path || !*path)
return false;
dummy = filestream_open(
if (!(dummy = filestream_open(
path,
RETRO_VFS_FILE_ACCESS_READ,
RETRO_VFS_FILE_ACCESS_HINT_NONE);
if (!dummy)
RETRO_VFS_FILE_ACCESS_HINT_NONE)))
return false;
if (filestream_close(dummy) != 0)
if (dummy)
free(dummy);
free(dummy);
dummy = NULL;
return true;
@ -165,7 +159,7 @@ int64_t filestream_truncate(RFILE *stream, int64_t length)
* @hints :
*
* Opens a file for reading or writing, depending on the requested mode.
* Returns a pointer to an RFILE if opened successfully, otherwise NULL.
* @return A pointer to an RFILE if opened successfully, otherwise NULL.
**/
RFILE* filestream_open(const char *path, unsigned mode, unsigned hints)
{
@ -184,7 +178,6 @@ RFILE* filestream_open(const char *path, unsigned mode, unsigned hints)
output = (RFILE*)malloc(sizeof(RFILE));
output->error_flag = false;
output->eof_flag = false;
output->hfile = fp;
return output;
}
@ -221,12 +214,12 @@ int filestream_getc(RFILE *stream)
return EOF;
}
int filestream_scanf(RFILE *stream, const char* format, ...)
int filestream_vscanf(RFILE *stream, const char* format, va_list *args)
{
char buf[4096];
char subfmt[64];
va_list args;
const char * bufiter = buf;
va_list args_copy;
const char *bufiter = buf;
int ret = 0;
int64_t startpos = filestream_tell(stream);
int64_t maxlen = filestream_read(stream, buf, sizeof(buf)-1);
@ -236,7 +229,16 @@ int filestream_scanf(RFILE *stream, const char* format, ...)
buf[maxlen] = '\0';
va_start(args, format);
/* Have to copy the input va_list here
* > Calling va_arg() on 'args' directly would
* cause the va_list to have an indeterminate value
* in the function calling filestream_vscanf(),
* leading to unexpected behaviour */
#ifdef __va_copy
__va_copy(args_copy, *args);
#else
va_copy(args_copy, *args);
#endif
while (*format)
{
@ -302,7 +304,7 @@ int filestream_scanf(RFILE *stream, const char* format, ...)
}
else
{
int v = sscanf(bufiter, subfmt, va_arg(args, void*), &sublen);
int v = sscanf(bufiter, subfmt, va_arg(args_copy, void*), &sublen);
if (v == EOF)
return EOF;
if (v != 1)
@ -327,13 +329,23 @@ int filestream_scanf(RFILE *stream, const char* format, ...)
}
}
va_end(args);
filestream_seek(stream, startpos+(bufiter-buf),
va_end(args_copy);
filestream_seek(stream, startpos + (bufiter - buf),
RETRO_VFS_SEEK_POSITION_START);
return ret;
}
int filestream_scanf(RFILE *stream, const char* format, ...)
{
int result;
va_list vl;
va_start(vl, format);
result = filestream_vscanf(stream, format, &vl);
va_end(vl);
return result;
}
int64_t filestream_seek(RFILE *stream, int64_t offset, int seek_position)
{
int64_t output;
@ -348,14 +360,12 @@ int64_t filestream_seek(RFILE *stream, int64_t offset, int seek_position)
if (output == VFS_ERROR_RETURN_VALUE)
stream->error_flag = true;
stream->eof_flag = false;
return output;
}
int filestream_eof(RFILE *stream)
{
return stream->eof_flag;
return filestream_tell(stream) == filestream_get_size(stream) ? EOF : 0;
}
int64_t filestream_tell(RFILE *stream)
@ -380,7 +390,6 @@ void filestream_rewind(RFILE *stream)
return;
filestream_seek(stream, 0L, RETRO_VFS_SEEK_POSITION_START);
stream->error_flag = false;
stream->eof_flag = false;
}
int64_t filestream_read(RFILE *stream, void *s, int64_t len)
@ -395,8 +404,6 @@ int64_t filestream_read(RFILE *stream, void *s, int64_t len)
if (output == VFS_ERROR_RETURN_VALUE)
stream->error_flag = true;
if (output < len)
stream->eof_flag = true;
return output;
}
@ -494,9 +501,7 @@ int filestream_printf(RFILE *stream, const char* format, ...)
int filestream_error(RFILE *stream)
{
if (stream && stream->error_flag)
return 1;
return 0;
return (stream && stream->error_flag);
}
int filestream_close(RFILE *stream)
@ -525,7 +530,7 @@ int filestream_close(RFILE *stream)
*
* Read the contents of a file into @buf.
*
* Returns: non zero on success.
* @return Non-zero on success.
*/
int64_t filestream_read_file(const char *path, void **buf, int64_t *len)
{
@ -542,25 +547,20 @@ int64_t filestream_read_file(const char *path, void **buf, int64_t *len)
return 0;
}
content_buf_size = filestream_get_size(file);
if (content_buf_size < 0)
if ((content_buf_size = filestream_get_size(file)) < 0)
goto error;
content_buf = malloc((size_t)(content_buf_size + 1));
if (!content_buf)
if (!(content_buf = malloc((size_t)(content_buf_size + 1))))
goto error;
if ((int64_t)(uint64_t)(content_buf_size + 1) != (content_buf_size + 1))
goto error;
ret = filestream_read(file, content_buf, (int64_t)content_buf_size);
if (ret < 0)
if ((ret = filestream_read(file, content_buf, (int64_t)content_buf_size)) <
0)
goto error;
if (filestream_close(file) != 0)
if (file)
free(file);
free(file);
*buf = content_buf;
@ -574,9 +574,8 @@ int64_t filestream_read_file(const char *path, void **buf, int64_t *len)
return 1;
error:
if (file)
if (filestream_close(file) != 0)
free(file);
if (filestream_close(file) != 0)
free(file);
if (content_buf)
free(content_buf);
if (len)
@ -593,8 +592,8 @@ error:
*
* Writes data to a file.
*
* Returns: true (1) on success, false (0) otherwise.
*/
* @return true on success, otherwise false.
**/
bool filestream_write_file(const char *path, const void *data, int64_t size)
{
int64_t ret = 0;
@ -603,20 +602,18 @@ bool filestream_write_file(const char *path, const void *data, int64_t size)
RETRO_VFS_FILE_ACCESS_HINT_NONE);
if (!file)
return false;
ret = filestream_write(file, data, size);
if (filestream_close(file) != 0)
if (file)
free(file);
if (ret != size)
return false;
return true;
free(file);
return (ret == size);
}
/* Returned pointer must be freed by the caller. */
char* filestream_getline(RFILE *stream)
/**
* filestream_getline:
*
* Returned pointer must be freed by the caller.
**/
char *filestream_getline(RFILE *stream)
{
char *newline_tmp = NULL;
size_t cur_size = 8;
@ -631,16 +628,15 @@ char* filestream_getline(RFILE *stream)
return NULL;
}
in = filestream_getc(stream);
in = filestream_getc(stream);
while (in != EOF && in != '\n')
{
if (idx == cur_size)
{
cur_size *= 2;
newline_tmp = (char*)realloc(newline, cur_size + 1);
if (!newline_tmp)
if (!(newline_tmp = (char*)realloc(newline, cur_size + 1)))
{
free(newline);
return NULL;

View File

@ -69,17 +69,27 @@ RFILE* rfopen(const char *path, const char *mode)
int rfclose(RFILE* stream)
{
if (!stream)
return EOF;
return filestream_close(stream);
}
int64_t rftell(RFILE* stream)
{
if (!stream)
return -1;
return filestream_tell(stream);
}
int64_t rfseek(RFILE* stream, int64_t offset, int origin)
{
int seek_position = -1;
if (!stream)
return -1;
switch (origin)
{
case SEEK_SET:
@ -99,39 +109,61 @@ 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)
{
if (!stream || (elem_size == 0) || (elem_count == 0))
return 0;
return (filestream_read(stream, buffer, elem_size * elem_count) / elem_size);
}
char *rfgets(char *buffer, int maxCount, RFILE* stream)
{
if (!stream)
return NULL;
return filestream_gets(stream, buffer, maxCount);
}
int rfgetc(RFILE* stream)
{
if (!stream)
return EOF;
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);
if (!stream || (elem_size == 0) || (elem_count == 0))
return 0;
return (filestream_write(stream, buffer, elem_size * elem_count) / elem_size);
}
int rfputc(int character, RFILE * stream)
{
return filestream_putc(stream, character);
if (!stream)
return EOF;
return filestream_putc(stream, character);
}
int64_t rfflush(RFILE * stream)
{
return filestream_flush(stream);
if (!stream)
return EOF;
return filestream_flush(stream);
}
int rfprintf(RFILE * stream, const char * format, ...)
{
int result;
va_list vl;
if (!stream)
return -1;
va_start(vl, format);
result = filestream_vprintf(stream, format, vl);
va_end(vl);
@ -152,8 +184,12 @@ int rfscanf(RFILE * stream, const char * format, ...)
{
int result;
va_list vl;
if (!stream)
return 0;
va_start(vl, format);
result = filestream_scanf(stream, format, vl);
result = filestream_vscanf(stream, format, &vl);
va_end(vl);
return result;
}

View File

@ -24,6 +24,7 @@
#include <ctype.h>
#include <string.h>
#include <compat/strl.h>
#include <string/stdstring.h>
#include <encodings/utf.h>
@ -89,9 +90,11 @@ char *string_ucwords(char *s)
}
char *string_replace_substring(const char *in,
const char *pattern, const char *replacement)
const char *pattern, size_t pattern_len,
const char *replacement, size_t replacement_len)
{
size_t numhits, pattern_len, replacement_len, outlen;
size_t outlen;
size_t numhits = 0;
const char *inat = NULL;
const char *inprev = NULL;
char *out = NULL;
@ -102,9 +105,6 @@ char *string_replace_substring(const char *in,
if (!pattern || !replacement)
return strdup(in);
pattern_len = strlen(pattern);
replacement_len = strlen(replacement);
numhits = 0;
inat = in;
while ((inat = strstr(inat, pattern)))
@ -114,9 +114,8 @@ char *string_replace_substring(const char *in,
}
outlen = strlen(in) - pattern_len*numhits + replacement_len*numhits;
out = (char *)malloc(outlen+1);
if (!out)
if (!(out = (char *)malloc(outlen+1)))
return NULL;
outat = out;
@ -129,7 +128,7 @@ char *string_replace_substring(const char *in,
outat += inat-inprev;
memcpy(outat, replacement, replacement_len);
outat += replacement_len;
inat += pattern_len;
inat += pattern_len;
inprev = inat;
}
strcpy(outat, inprev);
@ -137,7 +136,11 @@ char *string_replace_substring(const char *in,
return out;
}
/* Remove leading whitespaces */
/**
* string_trim_whitespace_left:
*
* Remove leading whitespaces
**/
char *string_trim_whitespace_left(char *const s)
{
if (s && *s)
@ -158,7 +161,11 @@ char *string_trim_whitespace_left(char *const s)
return s;
}
/* Remove trailing whitespaces */
/**
* string_trim_whitespace_right:
*
* Remove trailing whitespaces
**/
char *string_trim_whitespace_right(char *const s)
{
if (s && *s)
@ -178,7 +185,11 @@ char *string_trim_whitespace_right(char *const s)
return s;
}
/* Remove leading and trailing whitespaces */
/**
* string_trim_whitespace:
*
* Remove leading and trailing whitespaces
**/
char *string_trim_whitespace(char *const s)
{
string_trim_whitespace_right(s); /* order matters */
@ -187,49 +198,62 @@ char *string_trim_whitespace(char *const s)
return s;
}
void word_wrap(char *dst, size_t dst_size, const char *src, int line_width, int wideglyph_width, unsigned max_lines)
/**
* word_wrap:
* @dst : pointer to destination buffer.
* @dst_size : size of destination buffer.
* @src : pointer to input string.
* @line_width : max number of characters per line.
* @wideglyph_width : not used, but is necessary to keep
* compatibility with word_wrap_wideglyph().
* @max_lines : max lines of destination string.
* 0 means no limit.
*
* Wraps string specified by 'src' to destination buffer
* specified by 'dst' and 'dst_size'.
* This function assumes that all glyphs in the string
* have an on-screen pixel width similar to that of
* regular Latin characters - i.e. it will not wrap
* correctly any text containing so-called 'wide' Unicode
* characters (e.g. CJK languages, emojis, etc.).
**/
size_t word_wrap(
char *dst, size_t dst_size,
const char *src, size_t src_len,
int line_width, int wideglyph_width, unsigned max_lines)
{
char *lastspace = NULL;
char *last_space = NULL;
unsigned counter = 0;
unsigned lines = 1;
size_t src_len = strlen(src);
const char *src_end = src + src_len;
/* Prevent buffer overflow */
if (dst_size < src_len + 1)
return;
return 0;
/* Early return if src string length is less
* than line width */
if (src_len < line_width)
{
strcpy(dst, src);
return;
}
if (src_len < (size_t)line_width)
return strlcpy(dst, src, dst_size);
while (*src != '\0')
{
unsigned char_len;
char_len = (unsigned)(utf8skip(src, 1) - src);
unsigned char_len = (unsigned)(utf8skip(src, 1) - src);
counter++;
if (*src == ' ')
lastspace = dst; /* Remember the location of the whitespace */
last_space = dst; /* Remember the location of the whitespace */
else if (*src == '\n')
{
/* If newlines embedded in the input,
* reset the index */
lines++;
counter = 0;
counter = 0;
/* Early return if remaining src string
* length is less than line width */
if (src_end - src <= line_width)
{
strcpy(dst, src);
return;
}
return strlcpy(dst, src, dst_size);
}
while (char_len--)
@ -239,36 +263,69 @@ void word_wrap(char *dst, size_t dst_size, const char *src, int line_width, int
{
counter = 0;
if (lastspace && (max_lines == 0 || lines < max_lines))
if (last_space && (max_lines == 0 || lines < max_lines))
{
/* Replace nearest (previous) whitespace
* with newline character */
*lastspace = '\n';
*last_space = '\n';
lines++;
src -= dst - lastspace - 1;
dst = lastspace + 1;
lastspace = NULL;
src -= dst - last_space - 1;
dst = last_space + 1;
last_space = NULL;
/* Early return if remaining src string
* length is less than line width */
if (src_end - src < line_width)
{
strcpy(dst, src);
return;
}
return strlcpy(dst, src, dst_size);
}
}
}
*dst = '\0';
return 0;
}
void word_wrap_wideglyph(char *dst, size_t dst_size, const char *src, int line_width, int wideglyph_width, unsigned max_lines)
/**
* word_wrap_wideglyph:
* @dst : pointer to destination buffer.
* @dst_size : size of destination buffer.
* @src : pointer to input string.
* @line_width : max number of characters per line.
* @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
* @max_lines : max lines of destination string.
* 0 means no limit.
*
* 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.
**/
size_t word_wrap_wideglyph(char *dst, size_t dst_size,
const char *src, size_t src_len, int line_width,
int wideglyph_width, unsigned max_lines)
{
char *lastspace = NULL;
char *lastwideglyph = NULL;
const char *src_end = src + strlen(src);
const char *src_end = src + src_len;
unsigned lines = 1;
/* 'line_width' means max numbers of characters per line,
* but this metric is only meaningful when dealing with
@ -294,20 +351,15 @@ void word_wrap_wideglyph(char *dst, size_t dst_size, const char *src, int line_w
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;
}
return strlcpy(dst, src, dst_size);
while (*src != '\0')
{
unsigned char_len;
char_len = (unsigned)(utf8skip(src, 1) - src);
unsigned char_len = (unsigned)(utf8skip(src, 1) - src);
counter_normalized += 100;
/* Prevent buffer overflow */
@ -315,7 +367,7 @@ void word_wrap_wideglyph(char *dst, size_t dst_size, const char *src, int line_w
break;
if (*src == ' ')
lastspace = dst; /* Remember the location of the whitespace */
lastspace = dst; /* Remember the location of the whitespace */
else if (*src == '\n')
{
/* If newlines embedded in the input,
@ -326,16 +378,13 @@ void word_wrap_wideglyph(char *dst, size_t dst_size, const char *src, int line_w
/* Early return if remaining src string
* length is less than line width */
if (src_end - src <= line_width)
{
strlcpy(dst, src, dst_size);
return;
}
return strlcpy(dst, src, dst_size);
}
else if (char_len >= 3)
{
/* Remember the location of the first byte
* whose length as UTF-8 >= 3*/
lastwideglyph = dst;
lastwideglyph = dst;
counter_normalized += additional_counter_normalized;
}
@ -354,17 +403,14 @@ void word_wrap_wideglyph(char *dst, size_t dst_size, const char *src, int line_w
/* Insert newline character */
*lastwideglyph = '\n';
lines++;
src -= dst - lastwideglyph;
dst = lastwideglyph + 1;
lastwideglyph = NULL;
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;
}
return strlcpy(dst, src, dst_size);
}
else if (lastspace)
{
@ -372,28 +418,29 @@ void word_wrap_wideglyph(char *dst, size_t dst_size, const char *src, int line_w
* with newline character */
*lastspace = '\n';
lines++;
src -= dst - lastspace - 1;
dst = lastspace + 1;
lastspace = NULL;
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;
}
return strlcpy(dst, src, dst_size);
}
}
}
*dst = '\0';
return 0;
}
/* Splits string into tokens seperated by 'delim'
/**
* string_tokenize:
*
* Splits string into tokens seperated by @delim
* > Returned token string must be free()'d
* > Returns NULL if token is not found
* > After each call, 'str' is set to the position after the
* > After each call, @str is set to the position after the
* last found token
* > Tokens *include* empty strings
* Usage example:
@ -406,7 +453,7 @@ void word_wrap_wideglyph(char *dst, size_t dst_size, const char *src, int line_w
* free(token);
* token = NULL;
* }
*/
**/
char* string_tokenize(char **str, const char *delim)
{
/* Taken from https://codereview.stackexchange.com/questions/216956/strtok-function-thread-safe-supports-empty-tokens-doesnt-change-string# */
@ -419,25 +466,20 @@ char* string_tokenize(char **str, const char *delim)
if (!str || string_is_empty(delim))
return NULL;
str_ptr = *str;
/* Note: we don't check string_is_empty() here,
* empty strings are valid */
if (!str_ptr)
if (!(str_ptr = *str))
return NULL;
/* Search for delimiter */
delim_ptr = strstr(str_ptr, delim);
if (delim_ptr)
if ((delim_ptr = strstr(str_ptr, delim)))
token_len = delim_ptr - str_ptr;
else
token_len = strlen(str_ptr);
/* Allocate token string */
token = (char *)malloc((token_len + 1) * sizeof(char));
if (!token)
if (!(token = (char *)malloc((token_len + 1) * sizeof(char))))
return NULL;
/* Copy token */
@ -450,42 +492,53 @@ char* string_tokenize(char **str, const char *delim)
return token;
}
/* Removes every instance of character 'c' from 'str' */
/**
* string_remove_all_chars:
* @str : input string (must be non-NULL, otherwise UB)
*
* Leaf function.
*
* Removes every instance of character @c from @str
**/
void string_remove_all_chars(char *str, char c)
{
char *read_ptr = NULL;
char *write_ptr = NULL;
if (string_is_empty(str))
return;
read_ptr = str;
write_ptr = str;
char *read_ptr = str;
char *write_ptr = str;
while (*read_ptr != '\0')
{
*write_ptr = *read_ptr++;
write_ptr += (*write_ptr != c) ? 1 : 0;
if (*write_ptr != c)
write_ptr++;
}
*write_ptr = '\0';
}
/* Replaces every instance of character 'find' in 'str'
* with character 'replace' */
/**
* string_replace_all_chars:
* @str : input string (must be non-NULL, otherwise UB)
* @find : character to find
* @replace : character to replace @find with
*
* Replaces every instance of character @find in @str
* with character @replace
**/
void string_replace_all_chars(char *str, char find, char replace)
{
char *str_ptr = str;
if (string_is_empty(str))
return;
while ((str_ptr = strchr(str_ptr, find)))
*str_ptr++ = replace;
}
/* Converts string to unsigned integer.
* Returns 0 if string is invalid */
/**
* string_to_unsigned:
* @str : input string
*
* Converts string to unsigned integer.
*
* @return 0 if string is invalid, otherwise > 0
**/
unsigned string_to_unsigned(const char *str)
{
const char *ptr = NULL;
@ -502,27 +555,33 @@ unsigned string_to_unsigned(const char *str)
return (unsigned)strtoul(str, NULL, 10);
}
/* Converts hexadecimal string to unsigned integer.
/**
* string_hex_to_unsigned:
* @str : input string (must be non-NULL, otherwise UB)
*
* Converts hexadecimal string to unsigned integer.
* Handles optional leading '0x'.
* Returns 0 if string is invalid */
*
* @return 0 if string is invalid, otherwise > 0
**/
unsigned string_hex_to_unsigned(const char *str)
{
const char *hex_str = str;
const char *ptr = NULL;
size_t len;
if (string_is_empty(str))
return 0;
/* Remove leading '0x', if required */
len = strlen(str);
if (len >= 2)
if ((str[0] == '0') &&
((str[1] == 'x') || (str[1] == 'X')))
if (str[0] != '\0' && str[1] != '\0')
{
if ( (str[0] == '0') &&
((str[1] == 'x') ||
(str[1] == 'X')))
{
hex_str = str + 2;
if (string_is_empty(hex_str))
if (string_is_empty(hex_str))
return 0;
}
}
else
return 0;
/* Check for valid characters */
@ -534,3 +593,117 @@ unsigned string_hex_to_unsigned(const char *str)
return (unsigned)strtoul(hex_str, NULL, 16);
}
/**
* string_count_occurrences_single_character:
*
* Leaf function.
*
* Get the total number of occurrences of character @c in @str.
*
* @return Total number of occurrences of character @c
*/
int string_count_occurrences_single_character(const char *str, char c)
{
int count = 0;
for (; *str; str++)
if (*str == c)
count++;
return count;
}
/**
* string_replace_whitespace_with_single_character:
*
* Leaf function.
*
* Replaces all spaces with given character @c.
**/
void string_replace_whitespace_with_single_character(char *str, char c)
{
for (; *str; str++)
if (ISSPACE(*str))
*str = c;
}
/**
* string_replace_multi_space_with_single_space:
*
* Leaf function.
*
* Replaces multiple spaces with a single space in a string.
**/
void string_replace_multi_space_with_single_space(char *str)
{
char *str_trimmed = str;
bool prev_is_space = false;
bool curr_is_space = false;
for (; *str; str++)
{
curr_is_space = ISSPACE(*str);
if (prev_is_space && curr_is_space)
continue;
*str_trimmed++ = *str;
prev_is_space = curr_is_space;
}
*str_trimmed = '\0';
}
/**
* string_remove_all_whitespace:
*
* Leaf function.
*
* Remove all spaces from the given string.
**/
void string_remove_all_whitespace(char *str_trimmed, const char *str)
{
for (; *str; str++)
if (!ISSPACE(*str))
*str_trimmed++ = *str;
*str_trimmed = '\0';
}
/**
* Retrieve the last occurance of the given character in a string.
*/
int string_index_last_occurance(const char *str, char c)
{
const char *pos = strrchr(str, c);
if (pos)
return (int)(pos - str);
return -1;
}
/**
* string_find_index_substring_string:
* @str : input string (must be non-NULL, otherwise UB)
* @substr : substring to find in @str
*
* Find the position of substring @substr in string @str.
**/
int string_find_index_substring_string(const char *str, const char *substr)
{
const char *pos = strstr(str, substr);
if (pos)
return (int)(pos - str);
return -1;
}
/**
* string_copy_only_ascii:
*
* Leaf function.
*
* Strips non-ASCII characters from a string.
**/
void string_copy_only_ascii(char *str_stripped, const char *str)
{
for (; *str; str++)
if (*str > 0x1F && *str < 0x7F)
*str_stripped++ = *str;
*str_stripped = '\0';
}

View File

@ -22,7 +22,6 @@
#ifdef HAVE_THREADS
#include <rthreads/rthreads.h>
#include <retro_assert.h>
#include <stdlib.h>
#endif
@ -41,8 +40,6 @@ void rtime_init(void)
#ifdef HAVE_THREADS
if (!rtime_localtime_lock)
rtime_localtime_lock = slock_new();
retro_assert(rtime_localtime_lock);
#endif
}

View File

@ -26,7 +26,7 @@
#include <errno.h>
#include <sys/types.h>
#include <string/stdstring.h>
#include <string/stdstring.h> /* string_is_empty */
#ifdef HAVE_CONFIG_H
#include "config.h"
@ -57,11 +57,6 @@
# include <dirent.h>
# endif
# include <unistd.h>
# if defined(ORBIS)
# include <sys/fcntl.h>
# include <sys/dirent.h>
# include <orbisFile.h>
# endif
# if defined(WIIU)
# include <malloc.h>
# endif
@ -74,11 +69,6 @@
# include <psp2/io/fcntl.h>
# include <psp2/io/dirent.h>
# include <psp2/io/stat.h>
#elif defined(ORBIS)
# include <orbisFile.h>
# include <ps4link.h>
# include <sys/dirent.h>
# include <sys/fcntl.h>
#elif !defined(_WIN32)
# if defined(PSP)
# include <pspiofilemgr.h>
@ -124,19 +114,66 @@
#include <unistd.h>
#endif
#if defined(ORBIS)
#include <orbisFile.h>
#include <sys/fcntl.h>
#include <sys/dirent.h>
#endif
#if defined(PSP)
#include <pspkernel.h>
#endif
#if defined(__PS3__) || defined(__PSL1GHT__)
#include <defines/ps3_defines.h>
#if defined(__PSL1GHT__)
#define FS_SUCCEEDED 0
#define FS_TYPE_DIR 1
#ifdef __PSL1GHT__
#include <lv2/sysfs.h>
#ifndef O_RDONLY
#define O_RDONLY SYS_O_RDONLY
#endif
#ifndef O_WRONLY
#define O_WRONLY SYS_O_WRONLY
#endif
#ifndef O_CREAT
#define O_CREAT SYS_O_CREAT
#endif
#ifndef O_TRUNC
#define O_TRUNC SYS_O_TRUNC
#endif
#ifndef O_RDWR
#define O_RDWR SYS_O_RDWR
#endif
#else
#include <cell/cell_fs.h>
#ifndef O_RDONLY
#define O_RDONLY CELL_FS_O_RDONLY
#endif
#ifndef O_WRONLY
#define O_WRONLY CELL_FS_O_WRONLY
#endif
#ifndef O_CREAT
#define O_CREAT CELL_FS_O_CREAT
#endif
#ifndef O_TRUNC
#define O_TRUNC CELL_FS_O_TRUNC
#endif
#ifndef O_RDWR
#define O_RDWR CELL_FS_O_RDWR
#endif
#ifndef sysFsStat
#define sysFsStat cellFsStat
#endif
#ifndef sysFSDirent
#define sysFSDirent CellFsDirent
#endif
#ifndef sysFsOpendir
#define sysFsOpendir cellFsOpendir
#endif
#ifndef sysFsReaddir
#define sysFsReaddir cellFsReaddir
#endif
#ifndef sysFSDirent
#define sysFSDirent CellFsDirent
#endif
#ifndef sysFsClosedir
#define sysFsClosedir cellFsClosedir
#endif
#endif
#endif
@ -200,13 +237,6 @@ int64_t retro_vfs_file_seek_internal(
#ifdef ATLEAST_VC2005
/* VC2005 and up have a special 64-bit fseek */
return _fseeki64(stream->fp, offset, whence);
#elif defined(ORBIS)
{
int ret = orbisLseek(stream->fd, offset, whence);
if (ret < 0)
return -1;
return 0;
}
#elif defined(HAVE_64BIT_OFFSETS)
return fseeko(stream->fp, (off_t)offset, whence);
#else
@ -269,22 +299,9 @@ int64_t retro_vfs_file_seek_internal(
libretro_vfs_implementation_file *retro_vfs_file_open_impl(
const char *path, unsigned mode, unsigned hints)
{
#if defined(VFS_FRONTEND) || defined(HAVE_CDROM)
int path_len = (int)strlen(path);
#endif
#ifdef VFS_FRONTEND
const char *dumb_prefix = "vfsonly://";
size_t dumb_prefix_siz = STRLEN_CONST("vfsonly://");
int dumb_prefix_len = (int)dumb_prefix_siz;
#endif
#ifdef HAVE_CDROM
const char *cdrom_prefix = "cdrom://";
size_t cdrom_prefix_siz = STRLEN_CONST("cdrom://");
int cdrom_prefix_len = (int)cdrom_prefix_siz;
#endif
int flags = 0;
const char *mode_str = NULL;
libretro_vfs_implementation_file *stream =
libretro_vfs_implementation_file *stream =
(libretro_vfs_implementation_file*)
malloc(sizeof(*stream));
@ -306,9 +323,18 @@ libretro_vfs_implementation_file *retro_vfs_file_open_impl(
stream->scheme = VFS_SCHEME_NONE;
#ifdef VFS_FRONTEND
if (path_len >= dumb_prefix_len)
if (!memcmp(path, dumb_prefix, dumb_prefix_len))
path += dumb_prefix_siz;
if ( path
&& path[0] == 'v'
&& path[1] == 'f'
&& path[2] == 's'
&& path[3] == 'o'
&& path[4] == 'n'
&& path[5] == 'l'
&& path[6] == 'y'
&& path[7] == ':'
&& path[8] == '/'
&& path[9] == '/')
path += sizeof("vfsonly://")-1;
#endif
#ifdef HAVE_CDROM
@ -325,13 +351,19 @@ libretro_vfs_implementation_file *retro_vfs_file_open_impl(
stream->cdrom.last_frame[0] = '\0';
stream->cdrom.last_frame_valid = false;
if (path_len > cdrom_prefix_len)
if ( path
&& path[0] == 'c'
&& path[1] == 'd'
&& path[2] == 'r'
&& path[3] == 'o'
&& path[4] == 'm'
&& path[5] == ':'
&& path[6] == '/'
&& path[7] == '/'
&& path[8] != '\0')
{
if (!memcmp(path, cdrom_prefix, cdrom_prefix_len))
{
path += cdrom_prefix_siz;
stream->scheme = VFS_SCHEME_CDROM;
}
path += sizeof("cdrom://")-1;
stream->scheme = VFS_SCHEME_CDROM;
}
#endif
@ -359,24 +391,20 @@ libretro_vfs_implementation_file *retro_vfs_file_open_impl(
mode_str = "wb";
flags = O_WRONLY | O_CREAT | O_TRUNC;
#if !defined(ORBIS)
#if !defined(_WIN32)
flags |= S_IRUSR | S_IWUSR;
#else
flags |= O_BINARY;
#endif
#endif
break;
case RETRO_VFS_FILE_ACCESS_READ_WRITE:
mode_str = "w+b";
flags = O_RDWR | O_CREAT | O_TRUNC;
#if !defined(ORBIS)
#if !defined(_WIN32)
flags |= S_IRUSR | S_IWUSR;
#else
flags |= O_BINARY;
#endif
#endif
break;
@ -385,12 +413,10 @@ libretro_vfs_implementation_file *retro_vfs_file_open_impl(
mode_str = "r+b";
flags = O_RDWR;
#if !defined(ORBIS)
#if !defined(_WIN32)
flags |= S_IRUSR | S_IWUSR;
#else
flags |= O_BINARY;
#endif
#endif
break;
@ -400,15 +426,6 @@ libretro_vfs_implementation_file *retro_vfs_file_open_impl(
if ((stream->hints & RFILE_HINT_UNBUFFERED) == 0)
{
#ifdef ORBIS
int fd = orbisOpen(path, flags, 0644);
if (fd < 0)
{
stream->fd = -1;
goto error;
}
stream->fd = fd;
#else
FILE *fp;
#ifdef HAVE_CDROM
if (stream->scheme == VFS_SCHEME_CDROM)
@ -425,25 +442,24 @@ libretro_vfs_implementation_file *retro_vfs_file_open_impl(
else
#endif
{
fp = (FILE*)fopen_utf8(path, mode_str);
if (!fp)
if (!(fp = (FILE*)fopen_utf8(path, mode_str)))
goto error;
stream->fp = fp;
}
/* Regarding setvbuf:
*
* https://www.freebsd.org/cgi/man.cgi?query=setvbuf&apropos=0&sektion=0&manpath=FreeBSD+11.1-RELEASE&arch=default&format=html
*
* If the size argument is not zero but buf is NULL,
* If the size argument is not zero but buf is NULL,
* a buffer of the given size will be allocated immediately, and
* released on close. This is an extension to ANSI C.
*
* Since C89 does not support specifying a NULL buffer
* Since C89 does not support specifying a NULL buffer
* with a non-zero size, we create and track our own buffer for it.
*/
/* TODO: this is only useful for a few platforms,
/* TODO: this is only useful for a few platforms,
* find which and add ifdef */
#if defined(_3DS)
if (stream->scheme != VFS_SCHEME_CDROM)
@ -455,19 +471,14 @@ libretro_vfs_implementation_file *retro_vfs_file_open_impl(
#elif defined(WIIU)
if (stream->scheme != VFS_SCHEME_CDROM)
{
const int bufsize = 128*1024;
const int bufsize = 128 * 1024;
stream->buf = (char*)memalign(0x40, bufsize);
if (stream->fp)
setvbuf(stream->fp, stream->buf, _IOFBF, bufsize);
}
#elif !defined(PSP)
if (stream->scheme != VFS_SCHEME_CDROM)
{
stream->buf = (char*)calloc(1, 0x4000);
if (stream->fp)
setvbuf(stream->fp, stream->buf, _IOFBF, 0x4000);
}
#endif
#endif
}
else
@ -503,18 +514,12 @@ libretro_vfs_implementation_file *retro_vfs_file_open_impl(
retro_vfs_file_seek_internal(stream, 0, SEEK_SET);
stream->mapped = (uint8_t*)mmap((void*)0,
stream->mapsize, PROT_READ, MAP_SHARED, stream->fd, 0);
if (stream->mapped == MAP_FAILED)
if ((stream->mapped = (uint8_t*)mmap((void*)0,
stream->mapsize, PROT_READ, MAP_SHARED, stream->fd, 0)) == MAP_FAILED)
stream->hints &= ~RETRO_VFS_FILE_ACCESS_HINT_FREQUENT_ACCESS;
}
#endif
}
#ifdef ORBIS
stream->size = orbisLseek(stream->fd, 0, SEEK_END);
orbisLseek(stream->fd, 0, SEEK_SET);
#else
#ifdef HAVE_CDROM
if (stream->scheme == VFS_SCHEME_CDROM)
{
@ -535,7 +540,6 @@ libretro_vfs_implementation_file *retro_vfs_file_open_impl(
retro_vfs_file_seek_internal(stream, 0, SEEK_SET);
}
#endif
return stream;
error:
@ -570,14 +574,7 @@ int retro_vfs_file_close_impl(libretro_vfs_implementation_file *stream)
}
if (stream->fd > 0)
{
#ifdef ORBIS
orbisClose(stream->fd);
stream->fd = -1;
#else
close(stream->fd);
#endif
}
#ifdef HAVE_CDROM
end:
if (stream->cdrom.cue_buf)
@ -600,12 +597,7 @@ int retro_vfs_file_error_impl(libretro_vfs_implementation_file *stream)
if (stream->scheme == VFS_SCHEME_CDROM)
return retro_vfs_file_error_cdrom(stream);
#endif
#ifdef ORBIS
/* TODO/FIXME - implement this? */
return 0;
#else
return ferror(stream->fp);
#endif
}
int64_t retro_vfs_file_size_impl(libretro_vfs_implementation_file *stream)
@ -617,18 +609,20 @@ int64_t retro_vfs_file_size_impl(libretro_vfs_implementation_file *stream)
int64_t retro_vfs_file_truncate_impl(libretro_vfs_implementation_file *stream, int64_t length)
{
if (!stream)
return -1;
#ifdef _WIN32
if (_chsize(_fileno(stream->fp), length) != 0)
return -1;
if (stream && _chsize(_fileno(stream->fp), length) == 0)
{
stream->size = length;
return 0;
}
#elif !defined(VITA) && !defined(PSP) && !defined(PS2) && !defined(ORBIS) && (!defined(SWITCH) || defined(HAVE_LIBNX))
if (ftruncate(fileno(stream->fp), (off_t)length) != 0)
return -1;
if (stream && ftruncate(fileno(stream->fp), (off_t)length) == 0)
{
stream->size = length;
return 0;
}
#endif
return 0;
return -1;
}
int64_t retro_vfs_file_tell_impl(libretro_vfs_implementation_file *stream)
@ -642,14 +636,6 @@ int64_t retro_vfs_file_tell_impl(libretro_vfs_implementation_file *stream)
if (stream->scheme == VFS_SCHEME_CDROM)
return retro_vfs_file_tell_cdrom(stream);
#endif
#ifdef ORBIS
{
int64_t ret = orbisLseek(stream->fd, 0, SEEK_CUR);
if (ret < 0)
return -1;
return ret;
}
#else
#ifdef ATLEAST_VC2005
/* VC2005 and up have a special 64-bit ftell */
return _ftelli64(stream->fp);
@ -657,13 +643,12 @@ int64_t retro_vfs_file_tell_impl(libretro_vfs_implementation_file *stream)
return ftello(stream->fp);
#else
return ftell(stream->fp);
#endif
#endif
}
#ifdef HAVE_MMAP
/* Need to check stream->mapped because this function
* is called in filestream_open() */
if (stream->mapped && stream->hints &
if (stream->mapped && stream->hints &
RETRO_VFS_FILE_ACCESS_HINT_FREQUENT_ACCESS)
return stream->mappos;
#endif
@ -676,21 +661,7 @@ int64_t retro_vfs_file_tell_impl(libretro_vfs_implementation_file *stream)
int64_t retro_vfs_file_seek_impl(libretro_vfs_implementation_file *stream,
int64_t offset, int seek_position)
{
int whence = -1;
switch (seek_position)
{
case RETRO_VFS_SEEK_POSITION_START:
whence = SEEK_SET;
break;
case RETRO_VFS_SEEK_POSITION_CURRENT:
whence = SEEK_CUR;
break;
case RETRO_VFS_SEEK_POSITION_END:
whence = SEEK_END;
break;
}
return retro_vfs_file_seek_internal(stream, offset, whence);
return retro_vfs_file_seek_internal(stream, offset, seek_position);
}
int64_t retro_vfs_file_read_impl(libretro_vfs_implementation_file *stream,
@ -705,13 +676,7 @@ int64_t retro_vfs_file_read_impl(libretro_vfs_implementation_file *stream,
if (stream->scheme == VFS_SCHEME_CDROM)
return retro_vfs_file_read_cdrom(stream, s, len);
#endif
#ifdef ORBIS
if (orbisRead(stream->fd, s, (size_t)len) < 0)
return -1;
return 0;
#else
return fread(s, 1, (size_t)len, stream->fp);
#endif
}
#ifdef HAVE_MMAP
if (stream->hints & RETRO_VFS_FILE_ACCESS_HINT_FREQUENT_ACCESS)
@ -734,83 +699,80 @@ int64_t retro_vfs_file_read_impl(libretro_vfs_implementation_file *stream,
int64_t retro_vfs_file_write_impl(libretro_vfs_implementation_file *stream, const void *s, uint64_t len)
{
int64_t pos = 0;
ssize_t result = -1;
if (!stream)
return -1;
if ((stream->hints & RFILE_HINT_UNBUFFERED) == 0)
{
#ifdef ORBIS
if (orbisWrite(stream->fd, s, (size_t)len) < 0)
return -1;
return 0;
#else
return fwrite(s, 1, (size_t)len, stream->fp);
#endif
}
pos = retro_vfs_file_tell_impl(stream);
result = fwrite(s, 1, (size_t)len, stream->fp);
if (result != -1 && pos + result > stream->size)
stream->size = pos + result;
return result;
}
#ifdef HAVE_MMAP
if (stream->hints & RETRO_VFS_FILE_ACCESS_HINT_FREQUENT_ACCESS)
return -1;
#endif
return write(stream->fd, s, (size_t)len);
pos = retro_vfs_file_tell_impl(stream);
result = write(stream->fd, s, (size_t)len);
if (result != -1 && pos + result > stream->size)
stream->size = pos + result;
return result;
}
int retro_vfs_file_flush_impl(libretro_vfs_implementation_file *stream)
{
if (!stream)
return -1;
#ifdef ORBIS
return 0;
#else
return fflush(stream->fp) == 0 ? 0 : -1;
#endif
if (stream && fflush(stream->fp) == 0)
return 0;
return -1;
}
int retro_vfs_file_remove_impl(const char *path)
{
if (path && *path)
{
int ret = -1;
#if defined(_WIN32) && !defined(_XBOX)
/* Win32 (no Xbox) */
/* Win32 (no Xbox) */
#if defined(_WIN32_WINNT) && _WIN32_WINNT < 0x0500
char *path_local = NULL;
char *path_local = NULL;
if ((path_local = utf8_to_local_string_alloc(path)))
{
/* We need to check if path is a directory */
if ((retro_vfs_stat_impl(path, NULL) & RETRO_VFS_STAT_IS_DIRECTORY) != 0)
ret = _rmdir(path_local);
else
ret = remove(path_local);
free(path_local);
}
#else
wchar_t *path_wide = NULL;
wchar_t *path_wide = NULL;
if ((path_wide = utf8_to_utf16_string_alloc(path)))
{
/* We need to check if path is a directory */
if ((retro_vfs_stat_impl(path, NULL) & RETRO_VFS_STAT_IS_DIRECTORY) != 0)
ret = _wrmdir(path_wide);
else
ret = _wremove(path_wide);
free(path_wide);
}
#endif
#else
ret = remove(path);
#endif
if (!path || !*path)
return -1;
#if defined(_WIN32_WINNT) && _WIN32_WINNT < 0x0500
path_local = utf8_to_local_string_alloc(path);
if (path_local)
{
int ret = remove(path_local);
free(path_local);
if (ret == 0)
return 0;
}
#else
path_wide = utf8_to_utf16_string_alloc(path);
if (path_wide)
{
int ret = _wremove(path_wide);
free(path_wide);
if (ret == 0)
return 0;
}
#endif
return -1;
#elif defined(ORBIS)
/* Orbis
* TODO/FIXME - stub for now */
return 0;
#else
if (remove(path) == 0)
return 0;
return -1;
#endif
}
int retro_vfs_file_rename_impl(const char *old_path, const char *new_path)
@ -862,13 +824,6 @@ int retro_vfs_file_rename_impl(const char *old_path, const char *new_path)
#endif
return ret;
#elif defined(ORBIS)
/* Orbis */
/* TODO/FIXME - Stub for now */
if (!old_path || !*old_path || !new_path || !*new_path)
return -1;
return 0;
#else
/* Every other platform */
if (!old_path || !*old_path || !new_path || !*new_path)
@ -888,154 +843,123 @@ const char *retro_vfs_file_get_path_impl(
int retro_vfs_stat_impl(const char *path, int32_t *size)
{
bool is_dir = false;
bool is_character_special = false;
#if defined(VITA) || defined(PSP)
/* Vita / PSP */
SceIoStat buf;
int dir_ret;
char *tmp = NULL;
size_t len = 0;
int ret = RETRO_VFS_STAT_IS_VALID;
if (!path || !*path)
return 0;
{
#if defined(VITA)
/* Vita / PSP */
SceIoStat stat_buf;
int dir_ret;
char *tmp = strdup(path);
size_t len = strlen(tmp);
if (tmp[len-1] == '/')
tmp[len-1] = '\0';
tmp = strdup(path);
len = strlen(tmp);
if (tmp[len-1] == '/')
tmp[len-1] = '\0';
dir_ret = sceIoGetstat(tmp, &stat_buf);
free(tmp);
if (dir_ret < 0)
return 0;
dir_ret = sceIoGetstat(tmp, &buf);
free(tmp);
if (dir_ret < 0)
return 0;
if (size)
*size = (int32_t)stat_buf.st_size;
if (size)
*size = (int32_t)buf.st_size;
is_dir = FIO_S_ISDIR(buf.st_mode);
#elif defined(ORBIS)
/* Orbis */
int dir_ret = 0;
if (!path || !*path)
return 0;
if (size)
*size = (int32_t)buf.st_size;
dir_ret = orbisDopen(path);
is_dir = dir_ret > 0;
orbisDclose(dir_ret);
is_character_special = S_ISCHR(buf.st_mode);
if (FIO_S_ISDIR(stat_buf.st_mode))
ret |= RETRO_VFS_STAT_IS_DIRECTORY;
#elif defined(__PSL1GHT__) || defined(__PS3__)
/* Lowlevel Lv2 */
sysFSStat buf;
/* Lowlevel Lv2 */
sysFSStat stat_buf;
if (!path || !*path)
return 0;
if (sysFsStat(path, &buf) < 0)
return 0;
if (sysFsStat(path, &stat_buf) < 0)
return 0;
if (size)
*size = (int32_t)buf.st_size;
if (size)
*size = (int32_t)stat_buf.st_size;
is_dir = ((buf.st_mode & S_IFMT) == S_IFDIR);
if ((stat_buf.st_mode & S_IFMT) == S_IFDIR)
ret |= RETRO_VFS_STAT_IS_DIRECTORY;
#elif defined(_WIN32)
/* Windows */
DWORD file_info;
struct _stat buf;
/* Windows */
struct _stat stat_buf;
#if defined(LEGACY_WIN32)
char *path_local = NULL;
char *path_local = utf8_to_local_string_alloc(path);
DWORD file_info = GetFileAttributes(path_local);
if (!string_is_empty(path_local))
_stat(path_local, &stat_buf);
if (path_local)
free(path_local);
#else
wchar_t *path_wide = NULL;
wchar_t *path_wide = utf8_to_utf16_string_alloc(path);
DWORD file_info = GetFileAttributesW(path_wide);
_wstat(path_wide, &stat_buf);
if (path_wide)
free(path_wide);
#endif
if (file_info == INVALID_FILE_ATTRIBUTES)
return 0;
if (!path || !*path)
return 0;
#if defined(LEGACY_WIN32)
path_local = utf8_to_local_string_alloc(path);
file_info = GetFileAttributes(path_local);
if (!string_is_empty(path_local))
_stat(path_local, &buf);
if (path_local)
free(path_local);
#else
path_wide = utf8_to_utf16_string_alloc(path);
file_info = GetFileAttributesW(path_wide);
_wstat(path_wide, &buf);
if (path_wide)
free(path_wide);
#endif
if (file_info == INVALID_FILE_ATTRIBUTES)
return 0;
if (size)
*size = (int32_t)buf.st_size;
is_dir = (file_info & FILE_ATTRIBUTE_DIRECTORY);
if (size)
*size = (int32_t)stat_buf.st_size;
if (file_info & FILE_ATTRIBUTE_DIRECTORY)
ret |= RETRO_VFS_STAT_IS_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;
/* On GEKKO platforms, paths cannot have
* trailing slashes - we must therefore
* remove them */
size_t len;
char *path_buf = NULL;
struct stat stat_buf;
if (string_is_empty(path))
return 0;
if (!(path_buf = strdup(path)))
return 0;
path_buf = strdup(path);
if (!path_buf)
return 0;
if ((len = strlen(path_buf)) > 0)
if (path_buf[len - 1] == '/')
path_buf[len - 1] = '\0';
len = strlen(path_buf);
if (len > 0)
if (path_buf[len - 1] == '/')
path_buf[len - 1] = '\0';
if (stat(path_buf, &stat_buf) < 0)
{
free(path_buf);
return 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);
free(path_buf);
if (size)
*size = (int32_t)stat_buf.st_size;
if (S_ISDIR(stat_buf.st_mode))
ret |= RETRO_VFS_STAT_IS_DIRECTORY;
if (S_ISCHR(stat_buf.st_mode))
ret |= RETRO_VFS_STAT_IS_CHARACTER_SPECIAL;
#else
/* Every other platform */
struct stat buf;
/* Every other platform */
struct stat stat_buf;
if (!path || !*path)
return 0;
if (stat(path, &buf) < 0)
return 0;
if (stat(path, &stat_buf) < 0)
return 0;
if (size)
*size = (int32_t)buf.st_size;
if (size)
*size = (int32_t)stat_buf.st_size;
is_dir = S_ISDIR(buf.st_mode);
is_character_special = S_ISCHR(buf.st_mode);
if (S_ISDIR(stat_buf.st_mode))
ret |= RETRO_VFS_STAT_IS_DIRECTORY;
if (S_ISCHR(stat_buf.st_mode))
ret |= RETRO_VFS_STAT_IS_CHARACTER_SPECIAL;
#endif
return RETRO_VFS_STAT_IS_VALID | (is_dir ? RETRO_VFS_STAT_IS_DIRECTORY : 0) | (is_character_special ? RETRO_VFS_STAT_IS_CHARACTER_SPECIAL : 0);
}
return ret;
}
#if defined(VITA)
#define path_mkdir_error(ret) (((ret) == SCE_ERROR_ERRNO_EEXIST))
#elif defined(PSP) || defined(PS2) || defined(_3DS) || defined(WIIU) || defined(SWITCH) || defined(ORBIS)
#elif defined(PSP) || defined(PS2) || defined(_3DS) || defined(WIIU) || defined(SWITCH)
#define path_mkdir_error(ret) ((ret) == -1)
#else
#define path_mkdir_error(ret) ((ret) < 0 && errno == EEXIST)
@ -1058,13 +982,11 @@ int retro_vfs_mkdir_impl(const char *dir)
#endif
#elif defined(IOS)
int ret = mkdir(dir, 0755);
#elif defined(VITA) || defined(PSP)
#elif defined(VITA)
int ret = sceIoMkdir(dir, 0777);
#elif defined(ORBIS)
int ret = orbisMkdir(dir, 0755);
#elif defined(__QNX__)
int ret = mkdir(dir, 0777);
#elif defined(GEKKO)
#elif defined(GEKKO) || defined(WIIU)
/* On GEKKO platforms, mkdir() fails if
* the path has a trailing slash. We must
* therefore remove it. */
@ -1111,16 +1033,13 @@ struct libretro_vfs_implementation_dir
HANDLE directory;
bool next;
char path[PATH_MAX_LENGTH];
#elif defined(VITA) || defined(PSP)
#elif defined(VITA)
SceUID directory;
SceIoDirent entry;
#elif defined(__PSL1GHT__) || defined(__PS3__)
int error;
int directory;
sysFSDirent entry;
#elif defined(ORBIS)
int directory;
struct dirent entry;
#else
DIR *directory;
const struct dirent *entry;
@ -1131,7 +1050,7 @@ static bool dirent_check_error(libretro_vfs_implementation_dir *rdir)
{
#if defined(_WIN32)
return (rdir->directory == INVALID_HANDLE_VALUE);
#elif defined(VITA) || defined(PSP) || defined(ORBIS)
#elif defined(VITA) || defined(ORBIS)
return (rdir->directory < 0);
#elif defined(__PSL1GHT__) || defined(__PS3__)
return (rdir->error != FS_SUCCEEDED);
@ -1144,7 +1063,6 @@ libretro_vfs_implementation_dir *retro_vfs_opendir_impl(
const char *name, bool include_hidden)
{
#if defined(_WIN32)
unsigned path_len;
char path_buf[1024];
size_t copied = 0;
#if defined(LEGACY_WIN32)
@ -1155,28 +1073,25 @@ libretro_vfs_implementation_dir *retro_vfs_opendir_impl(
#endif
libretro_vfs_implementation_dir *rdir;
/*Reject null or empty string paths*/
/* Reject NULL or empty string paths*/
if (!name || (*name == 0))
return NULL;
/*Allocate RDIR struct. Tidied later with retro_closedir*/
rdir = (libretro_vfs_implementation_dir*)calloc(1, sizeof(*rdir));
if (!rdir)
if (!(rdir = (libretro_vfs_implementation_dir*)
calloc(1, sizeof(*rdir))))
return NULL;
rdir->orig_path = strdup(name);
#if defined(_WIN32)
path_buf[0] = '\0';
path_len = strlen(name);
copied = strlcpy(path_buf, name, sizeof(path_buf));
/* Non-NT platforms don't like extra slashes in the path */
if (name[path_len - 1] != '\\')
path_buf[copied++] = '\\';
if (path_buf[copied - 1] != '\\')
path_buf [copied++] = '\\';
path_buf[copied] = '*';
path_buf[copied ] = '*';
path_buf[copied+1] = '\0';
#if defined(LEGACY_WIN32)
@ -1193,15 +1108,13 @@ libretro_vfs_implementation_dir *retro_vfs_opendir_impl(
free(path_wide);
#endif
#elif defined(VITA) || defined(PSP)
#elif defined(VITA)
rdir->directory = sceIoDopen(name);
#elif defined(_3DS)
rdir->directory = !string_is_empty(name) ? opendir(name) : NULL;
rdir->entry = NULL;
#elif defined(__PSL1GHT__) || defined(__PS3__)
rdir->error = sysFsOpendir(name, &rdir->directory);
#elif defined(ORBIS)
rdir->directory = orbisDopen(name);
#else
rdir->directory = opendir(name);
rdir->entry = NULL;
@ -1233,14 +1146,12 @@ bool retro_vfs_readdir_impl(libretro_vfs_implementation_dir *rdir)
rdir->next = true;
return (rdir->directory != INVALID_HANDLE_VALUE);
#elif defined(VITA) || defined(PSP)
#elif defined(VITA)
return (sceIoDread(rdir->directory, &rdir->entry) > 0);
#elif defined(__PSL1GHT__) || defined(__PS3__)
uint64_t nread;
rdir->error = sysFsReaddir(rdir->directory, &rdir->entry, &nread);
return (nread != 0);
#elif defined(ORBIS)
return (orbisDread(rdir->directory, &rdir->entry) > 0);
#else
return ((rdir->entry = readdir(rdir->directory)) != NULL);
#endif
@ -1259,7 +1170,7 @@ const char *retro_vfs_dirent_get_name_impl(libretro_vfs_implementation_dir *rdir
if (name)
free(name);
return (char*)rdir->entry.cFileName;
#elif defined(VITA) || defined(PSP) || defined(ORBIS) || defined(__PSL1GHT__) || defined(__PS3__)
#elif defined(VITA) || defined(__PSL1GHT__) || defined(__PS3__)
return rdir->entry.d_name;
#else
if (!rdir || !rdir->entry)
@ -1273,22 +1184,12 @@ bool retro_vfs_dirent_is_dir_impl(libretro_vfs_implementation_dir *rdir)
#if defined(_WIN32)
const WIN32_FIND_DATA *entry = (const WIN32_FIND_DATA*)&rdir->entry;
return entry->dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY;
#elif defined(PSP) || defined(VITA)
const SceIoDirent *entry = (const SceIoDirent*)&rdir->entry;
#if defined(PSP)
return (entry->d_stat.st_attr & FIO_SO_IFDIR) == FIO_SO_IFDIR;
#elif defined(VITA)
const SceIoDirent *entry = (const SceIoDirent*)&rdir->entry;
return SCE_S_ISDIR(entry->d_stat.st_mode);
#endif
#elif defined(__PSL1GHT__) || defined(__PS3__)
sysFSDirent *entry = (sysFSDirent*)&rdir->entry;
return (entry->d_type == FS_TYPE_DIR);
#elif defined(ORBIS)
const struct dirent *entry = &rdir->entry;
if (entry->d_type == DT_DIR)
return true;
if (!(entry->d_type == DT_UNKNOWN || entry->d_type == DT_LNK))
return false;
#else
struct stat buf;
char path[PATH_MAX_LENGTH];
@ -1301,8 +1202,7 @@ bool retro_vfs_dirent_is_dir_impl(libretro_vfs_implementation_dir *rdir)
return false;
#endif
/* dirent struct doesn't have d_type, do it the slow way ... */
path[0] = '\0';
fill_pathname_join(path, rdir->orig_path, retro_vfs_dirent_get_name_impl(rdir), sizeof(path));
fill_pathname_join_special(path, rdir->orig_path, retro_vfs_dirent_get_name_impl(rdir), sizeof(path));
if (stat(path, &buf) < 0)
return false;
return S_ISDIR(buf.st_mode);
@ -1317,12 +1217,10 @@ int retro_vfs_closedir_impl(libretro_vfs_implementation_dir *rdir)
#if defined(_WIN32)
if (rdir->directory != INVALID_HANDLE_VALUE)
FindClose(rdir->directory);
#elif defined(VITA) || defined(PSP)
#elif defined(VITA)
sceIoDclose(rdir->directory);
#elif defined(__PSL1GHT__) || defined(__PS3__)
rdir->error = sysFsClosedir(rdir->directory);
#elif defined(ORBIS)
orbisDclose(rdir->directory);
#else
if (rdir->directory)
closedir(rdir->directory);