Update libretro-common

This commit is contained in:
twinaphex 2020-06-30 00:23:58 +02:00
parent 9839a46682
commit 4b1b114507
70 changed files with 1759 additions and 1034 deletions

View File

@ -1,4 +1,4 @@
/* Copyright (C) 2010-2019 The RetroArch team /* Copyright (C) 2010-2020 The RetroArch team
* *
* --------------------------------------------------------------------------------------- * ---------------------------------------------------------------------------------------
* The following license statement only applies to this file (cdrom.c). * The following license statement only applies to this file (cdrom.c).
@ -96,6 +96,7 @@ void increment_msf(unsigned char *min, unsigned char *sec, unsigned char *frame)
*frame = (*frame < 74) ? (*frame + 1) : 0; *frame = (*frame < 74) ? (*frame + 1) : 0;
} }
#ifdef CDROM_DEBUG
static void cdrom_print_sense_data(const unsigned char *sense, size_t len) static void cdrom_print_sense_data(const unsigned char *sense, size_t len)
{ {
unsigned i; unsigned i;
@ -175,7 +176,7 @@ static void cdrom_print_sense_data(const unsigned char *sense, size_t len)
break; break;
} }
printf("[CDROM] Sense Key: %02X (%s)\n", key, sense_key_text); printf("[CDROM] Sense Key: %02X (%s)\n", key, sense_key_text ? sense_key_text : "null");
printf("[CDROM] ASC: %02X\n", asc); printf("[CDROM] ASC: %02X\n", asc);
printf("[CDROM] ASCQ: %02X\n", ascq); printf("[CDROM] ASCQ: %02X\n", ascq);
@ -252,6 +253,7 @@ static void cdrom_print_sense_data(const unsigned char *sense, size_t len)
fflush(stdout); fflush(stdout);
} }
#endif
#if defined(_WIN32) && !defined(_XBOX) #if defined(_WIN32) && !defined(_XBOX)
static int cdrom_send_command_win32(const libretro_vfs_implementation_file *stream, CDROM_CMD_Direction dir, void *buf, size_t len, unsigned char *cmd, size_t cmd_len, unsigned char *sense, size_t sense_len) static int cdrom_send_command_win32(const libretro_vfs_implementation_file *stream, CDROM_CMD_Direction dir, void *buf, size_t len, unsigned char *cmd, size_t cmd_len, unsigned char *sense, size_t sense_len)
@ -519,7 +521,9 @@ retry:
} }
else else
{ {
#ifdef CDROM_DEBUG
cdrom_print_sense_data(sense, sizeof(sense)); cdrom_print_sense_data(sense, sizeof(sense));
#endif
/* INQUIRY/TEST/SENSE should never fail, don't retry. */ /* INQUIRY/TEST/SENSE should never fail, don't retry. */
/* READ ATIP seems to fail outright on some drives with pressed discs, skip retries. */ /* READ ATIP seems to fail outright on some drives with pressed discs, skip retries. */
@ -672,7 +676,9 @@ int cdrom_get_sense(libretro_vfs_implementation_file *stream, unsigned char *sen
if (rv) if (rv)
return 1; return 1;
#ifdef CDROM_DEBUG
cdrom_print_sense_data(buf, sizeof(buf)); cdrom_print_sense_data(buf, sizeof(buf));
#endif
return 0; return 0;
} }
@ -931,23 +937,23 @@ int cdrom_read_subq(libretro_vfs_implementation_file *stream, unsigned char *buf
if (/*(control == 4 || control == 6) && */adr == 1 && tno == 0 && point >= 1 && point <= 99) if (/*(control == 4 || control == 6) && */adr == 1 && tno == 0 && point >= 1 && point <= 99)
{ {
printf("[CDROM] - Session#: %d TNO %d POINT %d ", session_num, tno, point); printf("[CDROM] - Session#: %d TNO %d POINT %d ", session_num, tno, point);
printf("[CDROM] Track start time: (MSF %02u:%02u:%02u) ", (unsigned)pmin, (unsigned)psec, (unsigned)pframe); printf("Track start time: (aMSF %02u:%02u:%02u) ", (unsigned)pmin, (unsigned)psec, (unsigned)pframe);
} }
else if (/*(control == 4 || control == 6) && */adr == 1 && tno == 0 && point == 0xA0) else if (/*(control == 4 || control == 6) && */adr == 1 && tno == 0 && point == 0xA0)
{ {
printf("[CDROM] - Session#: %d TNO %d POINT %d ", session_num, tno, point); printf("[CDROM] - Session#: %d TNO %d POINT %d ", session_num, tno, point);
printf("[CDROM] First Track Number: %d ", pmin); printf("First Track Number: %d ", pmin);
printf("[CDROM] Disc Type: %d ", psec); printf("Disc Type: %d ", psec);
} }
else if (/*(control == 4 || control == 6) && */adr == 1 && tno == 0 && point == 0xA1) else if (/*(control == 4 || control == 6) && */adr == 1 && tno == 0 && point == 0xA1)
{ {
printf("[CDROM] - Session#: %d TNO %d POINT %d ", session_num, tno, point); printf("[CDROM] - Session#: %d TNO %d POINT %d ", session_num, tno, point);
printf("[CDROM] Last Track Number: %d ", pmin); printf("Last Track Number: %d ", pmin);
} }
else if (/*(control == 4 || control == 6) && */adr == 1 && tno == 0 && point == 0xA2) else if (/*(control == 4 || control == 6) && */adr == 1 && tno == 0 && point == 0xA2)
{ {
printf("[CDROM] - Session#: %d TNO %d POINT %d ", session_num, tno, point); printf("[CDROM] - Session#: %d TNO %d POINT %d ", session_num, tno, point);
printf("[CDROM] Lead-out runtime: (MSF %02u:%02u:%02u) ", (unsigned)pmin, (unsigned)psec, (unsigned)pframe); printf("Lead-out start time: (aMSF %02u:%02u:%02u) ", (unsigned)pmin, (unsigned)psec, (unsigned)pframe);
} }
printf("\n"); printf("\n");
@ -992,10 +998,10 @@ static int cdrom_read_track_info(libretro_vfs_implementation_file *stream, unsig
#ifdef CDROM_DEBUG #ifdef CDROM_DEBUG
printf("[CDROM] Track %d Info: ", track); printf("[CDROM] Track %d Info: ", track);
printf("[CDROM] Copy: %d ", (buf[5] & 0x10) > 0); printf("Copy: %d ", (buf[5] & 0x10) > 0);
printf("[CDROM] Data Mode: %d ", toc->track[track - 1].mode); printf("Data Mode: %d ", toc->track[track - 1].mode);
printf("[CDROM] LBA Start: %d (%d) ", lba, toc->track[track - 1].lba); printf("LBA Start: %d (%d) ", lba, toc->track[track - 1].lba);
printf("[CDROM] Track Size: %d\n", track_size); printf("Track Size: %d\n", track_size);
fflush(stdout); fflush(stdout);
#endif #endif
@ -1005,7 +1011,7 @@ static int cdrom_read_track_info(libretro_vfs_implementation_file *stream, unsig
int cdrom_set_read_speed(libretro_vfs_implementation_file *stream, unsigned speed) int cdrom_set_read_speed(libretro_vfs_implementation_file *stream, unsigned speed)
{ {
/* MMC Command: SET CD SPEED */ /* MMC Command: SET CD SPEED */
unsigned char cmd[] = {0xBB, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }; unsigned char cmd[] = {0xBB, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0};
cmd[2] = (speed >> 24) & 0xFF; cmd[2] = (speed >> 24) & 0xFF;
cmd[3] = (speed >> 16) & 0xFF; cmd[3] = (speed >> 16) & 0xFF;
@ -1329,24 +1335,35 @@ struct string_list* cdrom_get_available_drives(void)
#if defined(__linux__) && !defined(ANDROID) #if defined(__linux__) && !defined(ANDROID)
struct string_list *dir_list = dir_list_new("/dev", NULL, false, false, false, false); struct string_list *dir_list = dir_list_new("/dev", NULL, false, false, false, false);
int i; int i;
bool found = false;
if (!dir_list) if (!dir_list)
return list; return list;
for (i = 0; i < (int)dir_list->size; i++) for (i = 0; i < (int)dir_list->size; i++)
{ {
if (strstr(dir_list->elems[i].data, "/dev/sg")) if (string_starts_with_size(dir_list->elems[i].data, "/dev/sg",
STRLEN_CONST("/dev/sg")))
{ {
char drive_model[32] = {0};
char drive_string[33] = {0};
union string_list_elem_attr attr = {0};
int dev_index = 0;
RFILE *file = filestream_open(dir_list->elems[i].data, RETRO_VFS_FILE_ACCESS_READ, 0);
libretro_vfs_implementation_file *stream; libretro_vfs_implementation_file *stream;
bool is_cdrom = false; char drive_model[32] = {0};
char drive_string[33] = {0};
union string_list_elem_attr attr = {0};
int dev_index = 0;
RFILE *file = filestream_open(
dir_list->elems[i].data, RETRO_VFS_FILE_ACCESS_READ, 0);
bool is_cdrom = false;
found = true;
if (!file) if (!file)
{
#ifdef CDROM_DEBUG
printf("[CDROM] Could not open %s, please check permissions.\n", dir_list->elems[i].data);
fflush(stdout);
#endif
continue; continue;
}
stream = filestream_get_vfs_handle(file); stream = filestream_get_vfs_handle(file);
cdrom_get_inquiry(stream, drive_model, sizeof(drive_model), &is_cdrom); cdrom_get_inquiry(stream, drive_model, sizeof(drive_model), &is_cdrom);
@ -1355,10 +1372,11 @@ struct string_list* cdrom_get_available_drives(void)
if (!is_cdrom) if (!is_cdrom)
continue; continue;
sscanf(dir_list->elems[i].data + strlen("/dev/sg"), "%d", &dev_index); sscanf(dir_list->elems[i].data + STRLEN_CONST("/dev/sg"),
"%d", &dev_index);
dev_index = '0' + dev_index; dev_index = '0' + dev_index;
attr.i = dev_index; attr.i = dev_index;
if (!string_is_empty(drive_model)) if (!string_is_empty(drive_model))
strlcat(drive_string, drive_model, sizeof(drive_string)); strlcat(drive_string, drive_model, sizeof(drive_string));
@ -1369,6 +1387,56 @@ struct string_list* cdrom_get_available_drives(void)
} }
} }
if (!found)
{
char *buf = NULL;
int64_t len = 0;
if (filestream_read_file("/proc/modules", (void**)&buf, &len))
{
#ifdef CDROM_DEBUG
bool found = false;
#endif
struct string_list *mods = string_split(buf, "\n");
if (mods)
{
for (i = 0; i < mods->size; i++)
{
if (strcasestr(mods->elems[i].data, "sg "))
{
#ifdef CDROM_DEBUG
found = true;
#endif
break;
}
}
string_list_free(mods);
}
#ifdef CDROM_DEBUG
if (found)
{
printf("[CDROM] No sg devices found but kernel module is loaded.\n");
fflush(stdout);
}
else
{
printf("[CDROM] No sg devices found and sg kernel module is not loaded.\n");
fflush(stdout);
}
#endif
}
#ifdef CDROM_DEBUG
else
{
printf("[CDROM] No sg devices found, could not check if sg kernel module is loaded.\n");
fflush(stdout);
}
#endif
}
string_list_free(dir_list); string_list_free(dir_list);
#endif #endif
#if defined(_WIN32) && !defined(_XBOX) #if defined(_WIN32) && !defined(_XBOX)
@ -1444,9 +1512,7 @@ bool cdrom_is_media_inserted(libretro_vfs_implementation_file *stream)
bool cdrom_drive_has_media(const char drive) bool cdrom_drive_has_media(const char drive)
{ {
RFILE *file; RFILE *file;
char cdrom_path_bin[256]; char cdrom_path_bin[256] = {0};
cdrom_path_bin[0] = '\0';
cdrom_device_fillpath(cdrom_path_bin, sizeof(cdrom_path_bin), drive, 1, false); cdrom_device_fillpath(cdrom_path_bin, sizeof(cdrom_path_bin), drive, 1, false);
@ -1640,8 +1706,11 @@ void cdrom_device_fillpath(char *path, size_t len, char drive, unsigned char tra
#ifdef __linux__ #ifdef __linux__
pos = strlcpy(path, "cdrom://drive", len); pos = strlcpy(path, "cdrom://drive", len);
if (len > pos) if (len > pos + 1)
{
path[pos++] = drive; path[pos++] = drive;
path[pos] = '\0';
}
pos = strlcat(path, ".cue", len); pos = strlcat(path, ".cue", len);
#endif #endif
@ -1652,8 +1721,11 @@ void cdrom_device_fillpath(char *path, size_t len, char drive, unsigned char tra
#ifdef _WIN32 #ifdef _WIN32
pos = strlcpy(path, "cdrom://", len); pos = strlcpy(path, "cdrom://", len);
if (len > pos) if (len > pos + 1)
{
path[pos++] = drive; path[pos++] = drive;
path[pos] = '\0';
}
pos += snprintf(path + pos, len - pos, ":/drive-track%02d.bin", track); pos += snprintf(path + pos, len - pos, ":/drive-track%02d.bin", track);
#else #else

View File

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

View File

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

View File

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

View File

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

View File

@ -1,4 +1,4 @@
/* Copyright (C) 2010-2018 The RetroArch team /* Copyright (C) 2010-2020 The RetroArch team
* *
* --------------------------------------------------------------------------------------- * ---------------------------------------------------------------------------------------
* The following license statement only applies to this file (fopen_utf8.c). * The following license statement only applies to this file (fopen_utf8.c).
@ -36,9 +36,7 @@
void *fopen_utf8(const char * filename, const char * mode) void *fopen_utf8(const char * filename, const char * mode)
{ {
#if defined(_XBOX) #if defined(LEGACY_WIN32)
return fopen(filename, mode);
#elif defined(LEGACY_WIN32)
FILE *ret = NULL; FILE *ret = NULL;
char * filename_local = utf8_to_local_string_alloc(filename); char * filename_local = utf8_to_local_string_alloc(filename);

View File

@ -1,4 +1,4 @@
/* Copyright (C) 2010-2018 The RetroArch team /* Copyright (C) 2010-2020 The RetroArch team
* *
* --------------------------------------------------------------------------------------- * ---------------------------------------------------------------------------------------
* The following license statement only applies to this file (encoding_utf.c). * The following license statement only applies to this file (encoding_utf.c).
@ -37,6 +37,8 @@
#include <xtl.h> #include <xtl.h>
#endif #endif
#define UTF8_WALKBYTE(string) (*((*(string))++))
static unsigned leading_ones(uint8_t c) static unsigned leading_ones(uint8_t c)
{ {
unsigned ones = 0; unsigned ones = 0;
@ -89,13 +91,14 @@ size_t utf8_conv_utf32(uint32_t *out, size_t out_chars,
bool utf16_conv_utf8(uint8_t *out, size_t *out_chars, bool utf16_conv_utf8(uint8_t *out, size_t *out_chars,
const uint16_t *in, size_t in_size) const uint16_t *in, size_t in_size)
{ {
static uint8_t kUtf8Limits[5] = { 0xC0, 0xE0, 0xF0, 0xF8, 0xFC }; size_t out_pos = 0;
size_t out_pos = 0; size_t in_pos = 0;
size_t in_pos = 0; static const
uint8_t utf8_limits[5] = { 0xC0, 0xE0, 0xF0, 0xF8, 0xFC };
for (;;) for (;;)
{ {
unsigned numAdds; unsigned num_adds;
uint32_t value; uint32_t value;
if (in_pos == in_size) if (in_pos == in_size)
@ -124,21 +127,21 @@ bool utf16_conv_utf8(uint8_t *out, size_t *out_chars,
value = (((value - 0xD800) << 10) | (c2 - 0xDC00)) + 0x10000; value = (((value - 0xD800) << 10) | (c2 - 0xDC00)) + 0x10000;
} }
for (numAdds = 1; numAdds < 5; numAdds++) for (num_adds = 1; num_adds < 5; num_adds++)
if (value < (((uint32_t)1) << (numAdds * 5 + 6))) if (value < (((uint32_t)1) << (num_adds * 5 + 6)))
break; break;
if (out) if (out)
out[out_pos] = (char)(kUtf8Limits[numAdds - 1] out[out_pos] = (char)(utf8_limits[num_adds - 1]
+ (value >> (6 * numAdds))); + (value >> (6 * num_adds)));
out_pos++; out_pos++;
do do
{ {
numAdds--; num_adds--;
if (out) if (out)
out[out_pos] = (char)(0x80 out[out_pos] = (char)(0x80
+ ((value >> (6 * numAdds)) & 0x3F)); + ((value >> (6 * num_adds)) & 0x3F));
out_pos++; out_pos++;
}while (numAdds != 0); }while (num_adds != 0);
} }
*out_chars = out_pos; *out_chars = out_pos;
@ -166,13 +169,15 @@ size_t utf8cpy(char *d, size_t d_len, const char *s, size_t chars)
while (*sb && chars-- > 0) while (*sb && chars-- > 0)
{ {
sb++; sb++;
while ((*sb & 0xC0) == 0x80) sb++; while ((*sb & 0xC0) == 0x80)
sb++;
} }
if ((size_t)(sb - sb_org) > d_len-1 /* NUL */) if ((size_t)(sb - sb_org) > d_len-1 /* NUL */)
{ {
sb = sb_org + d_len-1; sb = sb_org + d_len-1;
while ((*sb & 0xC0) == 0x80) sb--; while ((*sb & 0xC0) == 0x80)
sb--;
} }
memcpy(d, sb_org, sb-sb_org); memcpy(d, sb_org, sb-sb_org);
@ -184,14 +189,18 @@ size_t utf8cpy(char *d, size_t d_len, const char *s, size_t chars)
const char *utf8skip(const char *str, size_t chars) const char *utf8skip(const char *str, size_t chars)
{ {
const uint8_t *strb = (const uint8_t*)str; const uint8_t *strb = (const uint8_t*)str;
if (!chars) if (!chars)
return str; return str;
do do
{ {
strb++; strb++;
while ((*strb & 0xC0)==0x80) strb++; while ((*strb & 0xC0)==0x80)
strb++;
chars--; chars--;
} while(chars); }while (chars);
return (const char*)strb; return (const char*)strb;
} }
@ -211,24 +220,22 @@ size_t utf8len(const char *string)
return ret; return ret;
} }
#define utf8_walkbyte(string) (*((*(string))++))
/* Does not validate the input, returns garbage if it's not UTF-8. */ /* Does not validate the input, returns garbage if it's not UTF-8. */
uint32_t utf8_walk(const char **string) uint32_t utf8_walk(const char **string)
{ {
uint8_t first = utf8_walkbyte(string); uint8_t first = UTF8_WALKBYTE(string);
uint32_t ret = 0; uint32_t ret = 0;
if (first < 128) if (first < 128)
return first; return first;
ret = (ret << 6) | (utf8_walkbyte(string) & 0x3F); ret = (ret << 6) | (UTF8_WALKBYTE(string) & 0x3F);
if (first >= 0xE0) if (first >= 0xE0)
{ {
ret = (ret << 6) | (utf8_walkbyte(string) & 0x3F); ret = (ret << 6) | (UTF8_WALKBYTE(string) & 0x3F);
if (first >= 0xF0) if (first >= 0xF0)
{ {
ret = (ret << 6) | (utf8_walkbyte(string) & 0x3F); ret = (ret << 6) | (UTF8_WALKBYTE(string) & 0x3F);
return ret | (first & 7) << 18; return ret | (first & 7) << 18;
} }
return ret | (first & 15) << 12; return ret | (first & 15) << 12;
@ -379,13 +386,13 @@ char* local_to_utf8_string_alloc(const char *str)
wchar_t* utf8_to_utf16_string_alloc(const char *str) wchar_t* utf8_to_utf16_string_alloc(const char *str)
{ {
#ifdef _WIN32 #ifdef _WIN32
int len = 0; int len = 0;
int out_len = 0; int out_len = 0;
#else #else
size_t len = 0; size_t len = 0;
size_t out_len = 0; size_t out_len = 0;
#endif #endif
wchar_t *buf = NULL; wchar_t *buf = NULL;
if (!str || !*str) if (!str || !*str)
return NULL; return NULL;

View File

@ -1,4 +1,4 @@
/* Copyright (C) 2010-2019 The RetroArch team /* Copyright (C) 2010-2020 The RetroArch team
* *
* --------------------------------------------------------------------------------------- * ---------------------------------------------------------------------------------------
* The following license statement only applies to this file (file_path.c). * The following license statement only applies to this file (file_path.c).
@ -32,8 +32,7 @@
#include <file/file_path.h> #include <file/file_path.h>
#include <retro_assert.h> #include <retro_assert.h>
#include <string/stdstring.h> #include <string/stdstring.h>
#define VFS_FRONTEND #include <time/rtime.h>
#include <vfs/vfs_implementation.h>
/* TODO: There are probably some unnecessary things on this huge include list now but I'm too afraid to touch it */ /* TODO: There are probably some unnecessary things on this huge include list now but I'm too afraid to touch it */
#ifdef __APPLE__ #ifdef __APPLE__
@ -46,7 +45,6 @@
#include <compat/strl.h> #include <compat/strl.h>
#include <compat/posix_string.h> #include <compat/posix_string.h>
#endif #endif
#include <compat/strcasestr.h>
#include <retro_miscellaneous.h> #include <retro_miscellaneous.h>
#include <encodings/utf.h> #include <encodings/utf.h>
@ -82,12 +80,7 @@
#include <pspkernel.h> #include <pspkernel.h>
#endif #endif
#if defined(PS2) #if defined(__CELLOS_LV2__) && !defined(__PSL1GHT__)
#include <fileXio_rpc.h>
#include <fileXio.h>
#endif
#if defined(__CELLOS_LV2__)
#include <cell/cell_fs.h> #include <cell/cell_fs.h>
#endif #endif
@ -95,7 +88,7 @@
#define FIO_S_ISDIR SCE_S_ISDIR #define FIO_S_ISDIR SCE_S_ISDIR
#endif #endif
#if (defined(__CELLOS_LV2__) && !defined(__PSL1GHT__)) || defined(__QNX__) || defined(PSP) || defined(PS2) #if (defined(__CELLOS_LV2__) && !defined(__PSL1GHT__)) || defined(__QNX__) || defined(PSP)
#include <unistd.h> /* stat() is defined here */ #include <unistd.h> /* stat() is defined here */
#endif #endif
@ -114,137 +107,6 @@
#endif #endif
static retro_vfs_stat_t path_stat_cb = NULL;
static retro_vfs_mkdir_t path_mkdir_cb = NULL;
void path_vfs_init(const struct retro_vfs_interface_info* vfs_info)
{
const struct retro_vfs_interface*
vfs_iface = vfs_info->iface;
path_stat_cb = NULL;
path_mkdir_cb = NULL;
if (vfs_info->required_interface_version < PATH_REQUIRED_VFS_VERSION || !vfs_iface)
return;
path_stat_cb = vfs_iface->stat;
path_mkdir_cb = vfs_iface->mkdir;
}
#define path_stat_internal(path, size) ((path_stat_cb != NULL) ? path_stat_cb((path), (size)) : retro_vfs_stat_impl((path), (size)))
#define path_mkdir_norecurse(dir) ((path_mkdir_cb != NULL) ? path_mkdir_cb((dir)) : retro_vfs_mkdir_impl((dir)))
int path_stat(const char *path)
{
return path_stat_internal(path, NULL);
}
/**
* path_is_directory:
* @path : path
*
* Checks if path is a directory.
*
* Returns: true (1) if path is a directory, otherwise false (0).
*/
bool path_is_directory(const char *path)
{
return (path_stat_internal(path, NULL) & RETRO_VFS_STAT_IS_DIRECTORY) != 0;
}
bool path_is_character_special(const char *path)
{
return (path_stat_internal(path, NULL) & RETRO_VFS_STAT_IS_CHARACTER_SPECIAL) != 0;
}
bool path_is_valid(const char *path)
{
return (path_stat_internal(path, NULL) & RETRO_VFS_STAT_IS_VALID) != 0;
}
int32_t path_get_size(const char *path)
{
int32_t filesize = 0;
if (path_stat_internal(path, &filesize) != 0)
return filesize;
return -1;
}
/**
* path_mkdir:
* @dir : directory
*
* Create directory on filesystem.
*
* Returns: true (1) if directory could be created, otherwise false (0).
**/
bool path_mkdir(const char *dir)
{
bool sret = false;
bool norecurse = false;
char *basedir = NULL;
if (!(dir && *dir))
return false;
/* Use heap. Real chance of stack
* overflow if we recurse too hard. */
basedir = strdup(dir);
if (!basedir)
return false;
path_parent_dir(basedir);
if (!*basedir || !strcmp(basedir, dir))
{
free(basedir);
return false;
}
#if defined(GEKKO)
{
size_t len = strlen(basedir);
/* path_parent_dir() keeps the trailing slash.
* On Wii, mkdir() fails if the path has a
* trailing slash...
* We must therefore remove it. */
if (len > 0)
if (basedir[len - 1] == '/')
basedir[len - 1] = '\0';
}
#endif
if (path_is_directory(basedir))
norecurse = true;
else
{
sret = path_mkdir(basedir);
if (sret)
norecurse = true;
}
free(basedir);
if (norecurse)
{
int ret = path_mkdir_norecurse(dir);
/* Don't treat this as an error. */
if (ret == -2 && path_is_directory(dir))
return true;
return (ret == 0);
}
return sret;
}
/** /**
* path_get_archive_delim: * path_get_archive_delim:
* @path : path * @path : path
@ -257,26 +119,48 @@ bool path_mkdir(const char *dir)
*/ */
const char *path_get_archive_delim(const char *path) const char *path_get_archive_delim(const char *path)
{ {
const char *last = find_last_slash(path); const char *last_slash = find_last_slash(path);
const char *delim = NULL; const char *delim = NULL;
char buf[5];
if (!last) buf[0] = '\0';
if (!last_slash)
return NULL; return NULL;
/* Test if it's .zip */ /* Find delimiter position */
delim = strcasestr(last, ".zip#"); delim = strrchr(last_slash, '#');
if (!delim) /* If it's not a .zip, test if it's .apk */ if (!delim)
delim = strcasestr(last, ".apk#"); return NULL;
if (delim) /* Check whether this is a known archive type
return delim + 4; * > Note: The code duplication here is
* deliberate, to maximise performance */
if (delim - last_slash > 4)
{
strlcpy(buf, delim - 4, sizeof(buf));
buf[4] = '\0';
/* If it's not a .zip or .apk file, test if it's .7z */ string_to_lower(buf);
delim = strcasestr(last, ".7z#");
if (delim) /* Check if this is a '.zip', '.apk' or '.7z' file */
return delim + 3; if (string_is_equal(buf, ".zip") ||
string_is_equal(buf, ".apk") ||
string_is_equal(buf + 1, ".7z"))
return delim;
}
else if (delim - last_slash > 3)
{
strlcpy(buf, delim - 3, sizeof(buf));
buf[3] = '\0';
string_to_lower(buf);
/* Check if this is a '.7z' file */
if (string_is_equal(buf, ".7z"))
return delim;
}
return NULL; return NULL;
} }
@ -335,9 +219,12 @@ bool path_is_compressed_file(const char* path)
{ {
const char *ext = path_get_extension(path); const char *ext = path_get_extension(path);
if ( strcasestr(ext, "zip") if (string_is_empty(ext))
|| strcasestr(ext, "apk") return false;
|| strcasestr(ext, "7z"))
if (string_is_equal_noncase(ext, "zip") ||
string_is_equal_noncase(ext, "apk") ||
string_is_equal_noncase(ext, "7z"))
return true; return true;
return false; return false;
@ -393,11 +280,11 @@ void fill_pathname(char *out_path, const char *in_path,
* present in 'in_path', it will be ignored. * present in 'in_path', it will be ignored.
* *
*/ */
void fill_pathname_noext(char *out_path, const char *in_path, size_t fill_pathname_noext(char *out_path, const char *in_path,
const char *replace, size_t size) const char *replace, size_t size)
{ {
strlcpy(out_path, in_path, size); strlcpy(out_path, in_path, size);
strlcat(out_path, replace, size); return strlcat(out_path, replace, size);
} }
char *find_last_slash(const char *str) char *find_last_slash(const char *str)
@ -427,7 +314,7 @@ void fill_pathname_slash(char *path, size_t size)
if (!last_slash) if (!last_slash)
{ {
strlcat(path, path_default_slash(), size); strlcat(path, PATH_DEFAULT_SLASH(), size);
return; return;
} }
@ -435,12 +322,8 @@ void fill_pathname_slash(char *path, size_t size)
/* Try to preserve slash type. */ /* Try to preserve slash type. */
if (last_slash != (path + path_len - 1)) if (last_slash != (path + path_len - 1))
{ {
char join_str[2]; path[path_len] = last_slash[0];
path[path_len+1] = '\0';
join_str[0] = '\0';
strlcpy(join_str, last_slash, sizeof(join_str));
strlcat(path, join_str, size);
} }
} }
@ -461,7 +344,7 @@ void fill_pathname_slash(char *path, size_t size)
* E.g..: in_dir = "/tmp/some_dir", in_basename = "/some_content/foo.c", * E.g..: in_dir = "/tmp/some_dir", in_basename = "/some_content/foo.c",
* replace = ".asm" => in_dir = "/tmp/some_dir/foo.c.asm" * replace = ".asm" => in_dir = "/tmp/some_dir/foo.c.asm"
**/ **/
void fill_pathname_dir(char *in_dir, const char *in_basename, size_t fill_pathname_dir(char *in_dir, const char *in_basename,
const char *replace, size_t size) const char *replace, size_t size)
{ {
const char *base = NULL; const char *base = NULL;
@ -469,7 +352,7 @@ void fill_pathname_dir(char *in_dir, const char *in_basename,
fill_pathname_slash(in_dir, size); fill_pathname_slash(in_dir, size);
base = path_basename(in_basename); base = path_basename(in_basename);
strlcat(in_dir, base, size); strlcat(in_dir, base, size);
strlcat(in_dir, replace, size); return strlcat(in_dir, replace, size);
} }
/** /**
@ -480,14 +363,14 @@ void fill_pathname_dir(char *in_dir, const char *in_basename,
* *
* Copies basename of @in_path into @out_path. * Copies basename of @in_path into @out_path.
**/ **/
void fill_pathname_base(char *out, const char *in_path, size_t size) size_t fill_pathname_base(char *out, const char *in_path, size_t size)
{ {
const char *ptr = path_basename(in_path); const char *ptr = path_basename(in_path);
if (!ptr) if (!ptr)
ptr = in_path; ptr = in_path;
strlcpy(out, ptr, size); return strlcpy(out, ptr, size);
} }
void fill_pathname_base_noext(char *out, void fill_pathname_base_noext(char *out,
@ -497,12 +380,12 @@ void fill_pathname_base_noext(char *out,
path_remove_extension(out); path_remove_extension(out);
} }
void fill_pathname_base_ext(char *out, size_t fill_pathname_base_ext(char *out,
const char *in_path, const char *ext, const char *in_path, const char *ext,
size_t size) size_t size)
{ {
fill_pathname_base_noext(out, in_path, size); fill_pathname_base_noext(out, in_path, size);
strlcat(out, ext, size); return strlcat(out, ext, size);
} }
/** /**
@ -597,15 +480,17 @@ void fill_pathname_parent_dir(char *out_dir,
* E.g.: * E.g.:
* out_filename = "RetroArch-{month}{day}-{Hours}{Minutes}.{@ext}" * out_filename = "RetroArch-{month}{day}-{Hours}{Minutes}.{@ext}"
**/ **/
void fill_dated_filename(char *out_filename, size_t fill_dated_filename(char *out_filename,
const char *ext, size_t size) const char *ext, size_t size)
{ {
time_t cur_time = time(NULL); time_t cur_time = time(NULL);
const struct tm* tm_ = localtime(&cur_time); struct tm tm_;
rtime_localtime(&cur_time, &tm_);
strftime(out_filename, size, strftime(out_filename, size,
"RetroArch-%m%d-%H%M%S", tm_); "RetroArch-%m%d-%H%M%S", &tm_);
strlcat(out_filename, ext, size); return strlcat(out_filename, ext, size);
} }
/** /**
@ -625,19 +510,21 @@ void fill_str_dated_filename(char *out_filename,
const char *in_str, const char *ext, size_t size) const char *in_str, const char *ext, size_t size)
{ {
char format[256]; char format[256];
time_t cur_time = time(NULL); struct tm tm_;
const struct tm* tm_ = localtime(&cur_time); time_t cur_time = time(NULL);
format[0] = '\0'; format[0] = '\0';
rtime_localtime(&cur_time, &tm_);
if (string_is_empty(ext)) if (string_is_empty(ext))
{ {
strftime(format, sizeof(format), "-%y%m%d-%H%M%S", tm_); strftime(format, sizeof(format), "-%y%m%d-%H%M%S", &tm_);
fill_pathname_noext(out_filename, in_str, format, size); fill_pathname_noext(out_filename, in_str, format, size);
} }
else else
{ {
strftime(format, sizeof(format), "-%y%m%d-%H%M%S.", tm_); strftime(format, sizeof(format), "-%y%m%d-%H%M%S.", &tm_);
fill_pathname_join_concat_noext(out_filename, fill_pathname_join_concat_noext(out_filename,
in_str, format, ext, in_str, format, ext,
@ -655,6 +542,7 @@ void fill_str_dated_filename(char *out_filename,
void path_basedir(char *path) void path_basedir(char *path)
{ {
char *last = NULL; char *last = NULL;
if (strlen(path) < 2) if (strlen(path) < 2)
return; return;
@ -663,7 +551,7 @@ void path_basedir(char *path)
if (last) if (last)
last[1] = '\0'; last[1] = '\0';
else else
snprintf(path, 3, ".%s", path_default_slash()); snprintf(path, 3, "." PATH_DEFAULT_SLASH());
} }
/** /**
@ -683,7 +571,7 @@ void path_parent_dir(char *path)
len = strlen(path); len = strlen(path);
if (len && path_char_is_slash(path[len - 1])) if (len && PATH_CHAR_IS_SLASH(path[len - 1]))
{ {
bool path_was_absolute = path_is_absolute(path); bool path_was_absolute = path_is_absolute(path);
@ -738,53 +626,157 @@ const char *path_basename(const char *path)
**/ **/
bool path_is_absolute(const char *path) bool path_is_absolute(const char *path)
{ {
if (string_is_empty(path))
return false;
if (path[0] == '/') if (path[0] == '/')
return true; return true;
#ifdef _WIN32
/* Many roads lead to Rome ... */ #if defined(_WIN32)
if (( strstr(path, "\\\\") == path) /* Many roads lead to Rome...
|| strstr(path, ":/") * Note: Drive letter can only be 1 character long */
|| strstr(path, ":\\") if (string_starts_with_size(path, "\\\\", STRLEN_CONST("\\\\")) ||
|| strstr(path, ":\\\\")) string_starts_with_size(path + 1, ":/", STRLEN_CONST(":/")) ||
return true; string_starts_with_size(path + 1, ":\\", STRLEN_CONST(":\\")))
#elif defined(__wiiu__)
if (strstr(path, ":/"))
return true; return true;
#elif defined(__wiiu__) || defined(VITA)
{
const char *seperator = strchr(path, ':');
if (seperator && (seperator[1] == '/'))
return true;
}
#endif #endif
return false; return false;
} }
/** /**
* path_resolve_realpath: * path_resolve_realpath:
* @buf : buffer for path * @buf : input and output buffer for path
* @size : size of buffer * @size : size of buffer
* @resolve_symlinks : whether to resolve symlinks or not
* *
* Turns relative paths into absolute paths and * Resolves use of ".", "..", multiple slashes etc in absolute paths.
* resolves use of "." and ".." in absolute paths. *
* If relative, rebases on current working dir. * Relative paths are rebased on the current working dir.
*
* Returns: @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,
* e.g. on Android it is "/"
* Use of fill_pathname_resolve_relative() should be prefered
**/ **/
void path_resolve_realpath(char *buf, size_t size) char *path_resolve_realpath(char *buf, size_t size, bool resolve_symlinks)
{ {
#if !defined(RARCH_CONSOLE) && defined(RARCH_INTERNAL) #if !defined(RARCH_CONSOLE) && defined(RARCH_INTERNAL)
char tmp[PATH_MAX_LENGTH]; char tmp[PATH_MAX_LENGTH];
tmp[0] = '\0';
strlcpy(tmp, buf, sizeof(tmp));
#ifdef _WIN32 #ifdef _WIN32
strlcpy(tmp, buf, sizeof(tmp));
if (!_fullpath(buf, tmp, size)) if (!_fullpath(buf, tmp, size))
{
strlcpy(buf, tmp, size); strlcpy(buf, tmp, size);
return NULL;
}
return buf;
#else #else
size_t t;
char *p;
const char *next;
const char *buf_end;
/* NOTE: realpath() expects at least PATH_MAX_LENGTH bytes in buf. if (resolve_symlinks)
* Technically, PATH_MAX_LENGTH needn't be defined, but we rely on it anyways. {
* POSIX 2008 can automatically allocate for you, strlcpy(tmp, buf, sizeof(tmp));
* but don't rely on that. */
if (!realpath(tmp, buf)) /* NOTE: realpath() expects at least PATH_MAX_LENGTH bytes in buf.
strlcpy(buf, tmp, size); * Technically, PATH_MAX_LENGTH needn't be defined, but we rely on it anyways.
* POSIX 2008 can automatically allocate for you,
* but don't rely on that. */
if (!realpath(tmp, buf))
{
strlcpy(buf, tmp, size);
return NULL;
}
return buf;
}
t = 0; /* length of output */
buf_end = buf + strlen(buf);
if (!path_is_absolute(buf))
{
size_t len;
/* rebase on working directory */
if (!getcwd(tmp, PATH_MAX_LENGTH-1))
return NULL;
len = strlen(tmp);
t += len;
if (tmp[len-1] != '/')
tmp[t++] = '/';
if (string_is_empty(buf))
goto end;
p = buf;
}
else
{
/* UNIX paths can start with multiple '/', copy those */
for (p = buf; *p == '/'; p++)
tmp[t++] = '/';
}
/* p points to just after a slash while 'next' points to the next slash
* if there are no slashes, they point relative to where one would be */
do
{
next = strchr(p, '/');
if (!next)
next = buf_end;
if ((next - p == 2 && p[0] == '.' && p[1] == '.'))
{
p += 3;
/* fail for illegal /.., //.. etc */
if (t == 1 || tmp[t-2] == '/')
return NULL;
/* delete previous segment in tmp by adjusting size t
* tmp[t-1] == '/', find '/' before that */
t = t-2;
while (tmp[t] != '/')
t--;
t++;
}
else if (next - p == 1 && p[0] == '.')
p += 2;
else if (next - p == 0)
p += 1;
else
{
/* fail when truncating */
if (t + next-p+1 > PATH_MAX_LENGTH-1)
return NULL;
while (p <= next)
tmp[t++] = *p++;
}
}
while (next < buf_end);
end:
tmp[t] = '\0';
strlcpy(buf, tmp, size);
return buf;
#endif #endif
#endif #endif
return NULL;
} }
/** /**
@ -801,10 +793,10 @@ void path_resolve_realpath(char *buf, size_t size)
* *
* E.g. path /a/b/e/f.cg with base /a/b/c/d/ turns into ../../e/f.cg * E.g. path /a/b/e/f.cg with base /a/b/c/d/ turns into ../../e/f.cg
**/ **/
void path_relative_to(char *out, size_t path_relative_to(char *out,
const char *path, const char *base, size_t size) const char *path, const char *base, size_t size)
{ {
unsigned i; size_t i, j;
const char *trimmed_path, *trimmed_base; const char *trimmed_path, *trimmed_base;
#ifdef _WIN32 #ifdef _WIN32
@ -812,24 +804,24 @@ void path_relative_to(char *out,
if (strlen(path) >= 2 && strlen(base) >= 2 if (strlen(path) >= 2 && strlen(base) >= 2
&& path[1] == ':' && base[1] == ':' && path[1] == ':' && base[1] == ':'
&& path[0] != base[0]) && path[0] != base[0])
{ return strlcpy(out, path, size);
out[0] = '\0';
strlcat(out, path, size);
}
#endif #endif
/* Trim common beginning */ /* Trim common beginning */
for (i = 0; path[i] && base[i] && path[i] == base[i]; ) for (i = 0, j = 0; path[i] && base[i] && path[i] == base[i]; i++)
i++; if (path[i] == PATH_DEFAULT_SLASH_C())
trimmed_path = path+i; j = i + 1;
trimmed_path = path+j;
trimmed_base = base+i; trimmed_base = base+i;
/* Each segment of base turns into ".." */ /* Each segment of base turns into ".." */
out[0] = '\0'; out[0] = '\0';
for (i = 0; trimmed_base[i]; i++) for (i = 0; trimmed_base[i]; i++)
if (trimmed_base[i] == '/' || trimmed_base[i] == '\\') if (trimmed_base[i] == PATH_DEFAULT_SLASH_C())
strlcat(out, "../", size); /* Use '/' as universal separator */ strlcat(out, ".." PATH_DEFAULT_SLASH(), size);
strlcat(out, trimmed_path, size);
return strlcat(out, trimmed_path, size);
} }
/** /**
@ -855,7 +847,7 @@ void fill_pathname_resolve_relative(char *out_path,
fill_pathname_basedir(out_path, in_refpath, size); fill_pathname_basedir(out_path, in_refpath, size);
strlcat(out_path, in_path, size); strlcat(out_path, in_path, size);
path_resolve_realpath(out_path, size); path_resolve_realpath(out_path, size, false);
} }
/** /**
@ -869,7 +861,7 @@ void fill_pathname_resolve_relative(char *out_path,
* Makes sure not to get two consecutive slashes * Makes sure not to get two consecutive slashes
* between directory and path. * between directory and path.
**/ **/
void fill_pathname_join(char *out_path, size_t fill_pathname_join(char *out_path,
const char *dir, const char *path, size_t size) const char *dir, const char *path, size_t size)
{ {
if (out_path != dir) if (out_path != dir)
@ -878,10 +870,10 @@ void fill_pathname_join(char *out_path,
if (*out_path) if (*out_path)
fill_pathname_slash(out_path, size); fill_pathname_slash(out_path, size);
strlcat(out_path, path, size); return strlcat(out_path, path, size);
} }
void fill_pathname_join_special_ext(char *out_path, size_t fill_pathname_join_special_ext(char *out_path,
const char *dir, const char *path, const char *dir, const char *path,
const char *last, const char *ext, const char *last, const char *ext,
size_t size) size_t size)
@ -891,25 +883,25 @@ void fill_pathname_join_special_ext(char *out_path,
fill_pathname_slash(out_path, size); fill_pathname_slash(out_path, size);
strlcat(out_path, last, size); strlcat(out_path, last, size);
strlcat(out_path, ext, size); return strlcat(out_path, ext, size);
} }
void fill_pathname_join_concat_noext(char *out_path, size_t fill_pathname_join_concat_noext(char *out_path,
const char *dir, const char *path, const char *dir, const char *path,
const char *concat, const char *concat,
size_t size) size_t size)
{ {
fill_pathname_noext(out_path, dir, path, size); fill_pathname_noext(out_path, dir, path, size);
strlcat(out_path, concat, size); return strlcat(out_path, concat, size);
} }
void fill_pathname_join_concat(char *out_path, size_t fill_pathname_join_concat(char *out_path,
const char *dir, const char *path, const char *dir, const char *path,
const char *concat, const char *concat,
size_t size) size_t size)
{ {
fill_pathname_join(out_path, dir, path, size); fill_pathname_join(out_path, dir, path, size);
strlcat(out_path, concat, size); return strlcat(out_path, concat, size);
} }
void fill_pathname_join_noext(char *out_path, void fill_pathname_join_noext(char *out_path,
@ -930,7 +922,7 @@ void fill_pathname_join_noext(char *out_path,
* Joins a directory (@dir) and path (@path) together * Joins a directory (@dir) and path (@path) together
* using the given delimiter (@delim). * using the given delimiter (@delim).
**/ **/
void fill_pathname_join_delim(char *out_path, const char *dir, size_t fill_pathname_join_delim(char *out_path, const char *dir,
const char *path, const char delim, size_t size) const char *path, const char delim, size_t size)
{ {
size_t copied; size_t copied;
@ -944,15 +936,16 @@ void fill_pathname_join_delim(char *out_path, const char *dir,
out_path[copied+1] = '\0'; out_path[copied+1] = '\0';
if (path) if (path)
strlcat(out_path, path, size); copied = strlcat(out_path, path, size);
return copied;
} }
void fill_pathname_join_delim_concat(char *out_path, const char *dir, size_t fill_pathname_join_delim_concat(char *out_path, const char *dir,
const char *path, const char delim, const char *concat, const char *path, const char delim, const char *concat,
size_t size) size_t size)
{ {
fill_pathname_join_delim(out_path, dir, path, delim, size); fill_pathname_join_delim(out_path, dir, path, delim, size);
strlcat(out_path, concat, size); return strlcat(out_path, concat, size);
} }
/** /**
@ -970,7 +963,7 @@ void fill_pathname_join_delim_concat(char *out_path, const char *dir,
* E.g.: "/path/to/game.img" -> game.img * E.g.: "/path/to/game.img" -> game.img
* "/path/to/myarchive.7z#folder/to/game.img" -> game.img * "/path/to/myarchive.7z#folder/to/game.img" -> game.img
*/ */
void fill_short_pathname_representation(char* out_rep, size_t fill_short_pathname_representation(char* out_rep,
const char *in_path, size_t size) const char *in_path, size_t size)
{ {
char path_short[PATH_MAX_LENGTH]; char path_short[PATH_MAX_LENGTH];
@ -980,7 +973,7 @@ void fill_short_pathname_representation(char* out_rep,
fill_pathname(path_short, path_basename(in_path), "", fill_pathname(path_short, path_basename(in_path), "",
sizeof(path_short)); sizeof(path_short));
strlcpy(out_rep, path_short, size); return strlcpy(out_rep, path_short, size);
} }
void fill_short_pathname_representation_noext(char* out_rep, void fill_short_pathname_representation_noext(char* out_rep,
@ -1011,9 +1004,9 @@ void fill_pathname_expand_special(char *out_path,
out_path += src_size; out_path += src_size;
size -= src_size; size -= src_size;
if (!path_char_is_slash(out_path[-1])) if (!PATH_CHAR_IS_SLASH(out_path[-1]))
{ {
src_size = strlcpy(out_path, path_default_slash(), size); src_size = strlcpy(out_path, PATH_DEFAULT_SLASH(), size);
retro_assert(src_size < size); retro_assert(src_size < size);
out_path += src_size; out_path += src_size;
@ -1042,9 +1035,9 @@ void fill_pathname_expand_special(char *out_path,
out_path += src_size; out_path += src_size;
size -= src_size; size -= src_size;
if (!path_char_is_slash(out_path[-1])) if (!PATH_CHAR_IS_SLASH(out_path[-1]))
{ {
src_size = strlcpy(out_path, path_default_slash(), size); src_size = strlcpy(out_path, PATH_DEFAULT_SLASH(), size);
retro_assert(src_size < size); retro_assert(src_size < size);
out_path += src_size; out_path += src_size;
@ -1068,10 +1061,11 @@ void fill_pathname_abbreviate_special(char *out_path,
unsigned i; unsigned i;
const char *candidates[3]; const char *candidates[3];
const char *notations[3]; const char *notations[3];
char *application_dir = (char*)malloc(PATH_MAX_LENGTH * sizeof(char)); char application_dir[PATH_MAX_LENGTH];
char *home_dir = (char*)malloc(PATH_MAX_LENGTH * sizeof(char)); char home_dir[PATH_MAX_LENGTH];
application_dir[0] = '\0'; application_dir[0] = '\0';
home_dir[0] = '\0';
/* application_dir could be zero-string. Safeguard against this. /* application_dir could be zero-string. Safeguard against this.
* *
@ -1088,15 +1082,13 @@ void fill_pathname_abbreviate_special(char *out_path,
notations [1] = "~"; notations [1] = "~";
notations [2] = NULL; notations [2] = NULL;
fill_pathname_application_dir(application_dir, fill_pathname_application_dir(application_dir, sizeof(application_dir));
PATH_MAX_LENGTH * sizeof(char)); fill_pathname_home_dir(home_dir, sizeof(home_dir));
fill_pathname_home_dir(home_dir,
PATH_MAX_LENGTH * sizeof(char));
for (i = 0; candidates[i]; i++) for (i = 0; candidates[i]; i++)
{ {
if (!string_is_empty(candidates[i]) && if (!string_is_empty(candidates[i]) &&
strstr(in_path, candidates[i]) == in_path) string_starts_with(in_path, candidates[i]))
{ {
size_t src_size = strlcpy(out_path, notations[i], size); size_t src_size = strlcpy(out_path, notations[i], size);
@ -1106,10 +1098,10 @@ void fill_pathname_abbreviate_special(char *out_path,
size -= src_size; size -= src_size;
in_path += strlen(candidates[i]); in_path += strlen(candidates[i]);
if (!path_char_is_slash(*in_path)) if (!PATH_CHAR_IS_SLASH(*in_path))
{ {
retro_assert(strlcpy(out_path, retro_assert(strlcpy(out_path,
path_default_slash(), size) < size); PATH_DEFAULT_SLASH(), size) < size);
out_path++; out_path++;
size--; size--;
} }
@ -1118,8 +1110,6 @@ void fill_pathname_abbreviate_special(char *out_path,
} }
} }
free(application_dir);
free(home_dir);
#endif #endif
retro_assert(strlcpy(out_path, in_path, size) < size); retro_assert(strlcpy(out_path, in_path, size) < size);
@ -1150,7 +1140,7 @@ void path_basedir_wrapper(char *path)
if (last) if (last)
last[1] = '\0'; last[1] = '\0';
else else
snprintf(path, 3, ".%s", path_default_slash()); snprintf(path, 3, "." PATH_DEFAULT_SLASH());
} }
#if !defined(RARCH_CONSOLE) && defined(RARCH_INTERNAL) #if !defined(RARCH_CONSOLE) && defined(RARCH_INTERNAL)
@ -1197,10 +1187,27 @@ void fill_pathname_application_path(char *s, size_t len)
CFURLRef bundle_url = CFBundleCopyBundleURL(bundle); CFURLRef bundle_url = CFBundleCopyBundleURL(bundle);
CFStringRef bundle_path = CFURLCopyPath(bundle_url); CFStringRef bundle_path = CFURLCopyPath(bundle_url);
CFStringGetCString(bundle_path, s, len, kCFStringEncodingUTF8); CFStringGetCString(bundle_path, s, len, kCFStringEncodingUTF8);
#ifdef HAVE_COCOATOUCH
{
/* This needs to be done so that the path becomes
* /private/var/... and this
* is used consistently throughout for the iOS bundle path */
char resolved_bundle_dir_buf[PATH_MAX_LENGTH] = {0};
if (realpath(s, resolved_bundle_dir_buf))
{
strlcpy(s, resolved_bundle_dir_buf, len - 1);
strlcat(s, "/", len);
}
}
#endif
CFRelease(bundle_path); CFRelease(bundle_path);
CFRelease(bundle_url); CFRelease(bundle_url);
#ifndef HAVE_COCOATOUCH
/* Not sure what this does but it breaks
* stuff for iOS, so skipping */
retro_assert(strlcat(s, "nobin", len) < len); retro_assert(strlcat(s, "nobin", len) < len);
#endif
return; return;
} }
#elif defined(__HAIKU__) #elif defined(__HAIKU__)
@ -1273,17 +1280,17 @@ void fill_pathname_home_dir(char *s, size_t len)
bool is_path_accessible_using_standard_io(const char *path) bool is_path_accessible_using_standard_io(const char *path)
{ {
bool result = true;
#ifdef __WINRT__ #ifdef __WINRT__
bool result;
size_t path_sizeof = PATH_MAX_LENGTH * sizeof(char); size_t path_sizeof = PATH_MAX_LENGTH * sizeof(char);
char *relative_path_abbrev = (char*)malloc(path_sizeof); char *relative_path_abbrev = (char*)malloc(path_sizeof);
fill_pathname_abbreviate_special(relative_path_abbrev, path, path_sizeof); fill_pathname_abbreviate_special(relative_path_abbrev, path, path_sizeof);
result = strlen(relative_path_abbrev) >= 2 && (relative_path_abbrev[0] == ':' || relative_path_abbrev[0] == '~') && path_char_is_slash(relative_path_abbrev[1]); result = (strlen(relative_path_abbrev) >= 2 )
&& (relative_path_abbrev[0] == ':' || relative_path_abbrev[0] == '~')
&& PATH_CHAR_IS_SLASH(relative_path_abbrev[1]);
free(relative_path_abbrev); free(relative_path_abbrev);
return result;
#else
return true;
#endif #endif
return result;
} }

View File

@ -1,4 +1,4 @@
/* Copyright (C) 2010-2019 The RetroArch team /* Copyright (C) 2010-2020 The RetroArch team
* *
* --------------------------------------------------------------------------------------- * ---------------------------------------------------------------------------------------
* The following license statement only applies to this file (retro_dirent.c). * The following license statement only applies to this file (retro_dirent.c).
@ -61,7 +61,7 @@ void dirent_vfs_init(const struct retro_vfs_interface_info* vfs_info)
struct RDIR *retro_opendir_include_hidden(const char *name, bool include_hidden) struct RDIR *retro_opendir_include_hidden(const char *name, bool include_hidden)
{ {
if (dirent_opendir_cb != NULL) if (dirent_opendir_cb)
return (struct RDIR *)dirent_opendir_cb(name, include_hidden); return (struct RDIR *)dirent_opendir_cb(name, include_hidden);
return (struct RDIR *)retro_vfs_opendir_impl(name, include_hidden); return (struct RDIR *)retro_vfs_opendir_impl(name, include_hidden);
} }
@ -79,14 +79,14 @@ bool retro_dirent_error(struct RDIR *rdir)
int retro_readdir(struct RDIR *rdir) int retro_readdir(struct RDIR *rdir)
{ {
if (dirent_readdir_cb != NULL) if (dirent_readdir_cb)
return dirent_readdir_cb((struct retro_vfs_dir_handle *)rdir); return dirent_readdir_cb((struct retro_vfs_dir_handle *)rdir);
return retro_vfs_readdir_impl((struct retro_vfs_dir_handle *)rdir); return retro_vfs_readdir_impl((struct retro_vfs_dir_handle *)rdir);
} }
const char *retro_dirent_get_name(struct RDIR *rdir) const char *retro_dirent_get_name(struct RDIR *rdir)
{ {
if (dirent_dirent_get_name_cb != NULL) if (dirent_dirent_get_name_cb)
return dirent_dirent_get_name_cb((struct retro_vfs_dir_handle *)rdir); return dirent_dirent_get_name_cb((struct retro_vfs_dir_handle *)rdir);
return retro_vfs_dirent_get_name_impl((struct retro_vfs_dir_handle *)rdir); return retro_vfs_dirent_get_name_impl((struct retro_vfs_dir_handle *)rdir);
} }
@ -104,14 +104,14 @@ const char *retro_dirent_get_name(struct RDIR *rdir)
*/ */
bool retro_dirent_is_dir(struct RDIR *rdir, const char *unused) bool retro_dirent_is_dir(struct RDIR *rdir, const char *unused)
{ {
if (dirent_dirent_is_dir_cb != NULL) if (dirent_dirent_is_dir_cb)
return dirent_dirent_is_dir_cb((struct retro_vfs_dir_handle *)rdir); return dirent_dirent_is_dir_cb((struct retro_vfs_dir_handle *)rdir);
return retro_vfs_dirent_is_dir_impl((struct retro_vfs_dir_handle *)rdir); return retro_vfs_dirent_is_dir_impl((struct retro_vfs_dir_handle *)rdir);
} }
void retro_closedir(struct RDIR *rdir) void retro_closedir(struct RDIR *rdir)
{ {
if (dirent_closedir_cb != NULL) if (dirent_closedir_cb)
dirent_closedir_cb((struct retro_vfs_dir_handle *)rdir); dirent_closedir_cb((struct retro_vfs_dir_handle *)rdir);
else else
retro_vfs_closedir_impl((struct retro_vfs_dir_handle *)rdir); retro_vfs_closedir_impl((struct retro_vfs_dir_handle *)rdir);

View File

@ -2,9 +2,7 @@
""" """
License statement applies to this file (glgen.py) only. License statement applies to this file (glgen.py) only.
"""
"""
Permission is hereby granted, free of charge, Permission is hereby granted, free of charge,
to any person obtaining a copy of this software and associated documentation files (the "Software"), to any person obtaining a copy of this software and associated documentation files (the "Software"),
to deal in the Software without restriction, including without limitation the rights to to deal in the Software without restriction, including without limitation the rights to

View File

@ -1,4 +1,4 @@
/* Copyright (C) 2010-2018 The RetroArch team /* Copyright (C) 2010-2020 The RetroArch team
* *
* --------------------------------------------------------------------------------------- * ---------------------------------------------------------------------------------------
* The following license statement only applies to this libretro SDK code part (glsym). * The following license statement only applies to this libretro SDK code part (glsym).

View File

@ -1,4 +1,4 @@
/* Copyright (C) 2010-2018 The RetroArch team /* Copyright (C) 2010-2020 The RetroArch team
* *
* --------------------------------------------------------------------------------------- * ---------------------------------------------------------------------------------------
* The following license statement only applies to this libretro SDK code part (glsym). * The following license statement only applies to this libretro SDK code part (glsym).

View File

@ -2,9 +2,7 @@
""" """
License statement applies to this file (glgen.py) only. License statement applies to this file (glgen.py) only.
"""
"""
Permission is hereby granted, free of charge, Permission is hereby granted, free of charge,
to any person obtaining a copy of this software and associated documentation files (the "Software"), to any person obtaining a copy of this software and associated documentation files (the "Software"),
to deal in the Software without restriction, including without limitation the rights to to deal in the Software without restriction, including without limitation the rights to

View File

@ -1,4 +1,4 @@
/* Copyright (C) 2010-2018 The RetroArch team /* Copyright (C) 2010-2020 The RetroArch team
* *
* --------------------------------------------------------------------------------------- * ---------------------------------------------------------------------------------------
* The following license statement only applies to this file (rhash.c). * The following license statement only applies to this file (rhash.c).
@ -307,7 +307,22 @@ uint32_t crc32_calculate(const uint8_t *data, size_t length)
/* Define the circular shift macro */ /* Define the circular shift macro */
#define SHA1CircularShift(bits,word) ((((word) << (bits)) & 0xFFFFFFFF) | ((word) >> (32-(bits)))) #define SHA1CircularShift(bits,word) ((((word) << (bits)) & 0xFFFFFFFF) | ((word) >> (32-(bits))))
static void SHA1Reset(SHA1Context *context) struct sha1_context
{
unsigned Message_Digest[5]; /* Message Digest (output) */
unsigned Length_Low; /* Message length in bits */
unsigned Length_High; /* Message length in bits */
unsigned char Message_Block[64]; /* 512-bit message blocks */
int Message_Block_Index; /* Index into message block array */
int Computed; /* Is the digest computed? */
int Corrupted; /* Is the message digest corruped? */
};
static void SHA1Reset(struct sha1_context *context)
{ {
if (!context) if (!context)
return; return;
@ -326,7 +341,7 @@ static void SHA1Reset(SHA1Context *context)
context->Corrupted = 0; context->Corrupted = 0;
} }
static void SHA1ProcessMessageBlock(SHA1Context *context) static void SHA1ProcessMessageBlock(struct sha1_context *context)
{ {
const unsigned K[] = /* Constants defined in SHA-1 */ const unsigned K[] = /* Constants defined in SHA-1 */
{ {
@ -418,7 +433,7 @@ static void SHA1ProcessMessageBlock(SHA1Context *context)
context->Message_Block_Index = 0; context->Message_Block_Index = 0;
} }
static void SHA1PadMessage(SHA1Context *context) static void SHA1PadMessage(struct sha1_context *context)
{ {
if (!context) if (!context)
return; return;
@ -433,13 +448,13 @@ static void SHA1PadMessage(SHA1Context *context)
if (context->Message_Block_Index > 55) if (context->Message_Block_Index > 55)
{ {
while(context->Message_Block_Index < 64) while (context->Message_Block_Index < 64)
context->Message_Block[context->Message_Block_Index++] = 0; context->Message_Block[context->Message_Block_Index++] = 0;
SHA1ProcessMessageBlock(context); SHA1ProcessMessageBlock(context);
} }
while(context->Message_Block_Index < 56) while (context->Message_Block_Index < 56)
context->Message_Block[context->Message_Block_Index++] = 0; context->Message_Block[context->Message_Block_Index++] = 0;
/* Store the message length as the last 8 octets */ /* Store the message length as the last 8 octets */
@ -455,7 +470,7 @@ static void SHA1PadMessage(SHA1Context *context)
SHA1ProcessMessageBlock(context); SHA1ProcessMessageBlock(context);
} }
static int SHA1Result(SHA1Context *context) static int SHA1Result(struct sha1_context *context)
{ {
if (context->Corrupted) if (context->Corrupted)
return 0; return 0;
@ -469,7 +484,7 @@ static int SHA1Result(SHA1Context *context)
return 1; return 1;
} }
static void SHA1Input(SHA1Context *context, static void SHA1Input(struct sha1_context *context,
const unsigned char *message_array, const unsigned char *message_array,
unsigned length) unsigned length)
{ {
@ -482,7 +497,7 @@ static void SHA1Input(SHA1Context *context,
return; return;
} }
while(length-- && !context->Corrupted) while (length-- && !context->Corrupted)
{ {
context->Message_Block[context->Message_Block_Index++] = context->Message_Block[context->Message_Block_Index++] =
(*message_array & 0xFF); (*message_array & 0xFF);
@ -508,7 +523,7 @@ static void SHA1Input(SHA1Context *context,
int sha1_calculate(const char *path, char *result) int sha1_calculate(const char *path, char *result)
{ {
SHA1Context sha; struct sha1_context sha;
unsigned char buff[4096]; unsigned char buff[4096];
int rv = 1; int rv = 1;
RFILE *fd = filestream_open(path, RFILE *fd = filestream_open(path,
@ -529,7 +544,7 @@ int sha1_calculate(const char *path, char *result)
goto error; goto error;
SHA1Input(&sha, buff, rv); SHA1Input(&sha, buff, rv);
}while(rv); } while (rv);
if (!SHA1Result(&sha)) if (!SHA1Result(&sha))
goto error; goto error;

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@ -1,4 +1,4 @@
/* Copyright (C) 2010-2018 The RetroArch team /* Copyright (C) 2010-2020 The RetroArch team
* *
* --------------------------------------------------------------------------------------- * ---------------------------------------------------------------------------------------
* The following license statement only applies to this file (intrinsics.h). * The following license statement only applies to this file (intrinsics.h).
@ -41,7 +41,7 @@ RETRO_BEGIN_DECLS
/* Count Leading Zero, unsigned 16bit input value */ /* Count Leading Zero, unsigned 16bit input value */
static INLINE unsigned compat_clz_u16(uint16_t val) static INLINE unsigned compat_clz_u16(uint16_t val)
{ {
#if defined(__GNUC__) && !defined(PS2) #if defined(__GNUC__)
return __builtin_clz(val << 16 | 0x8000); return __builtin_clz(val << 16 | 0x8000);
#else #else
unsigned ret = 0; unsigned ret = 0;

View File

@ -1,4 +1,4 @@
/* Copyright (C) 2010-2018 The RetroArch team /* Copyright (C) 2010-2020 The RetroArch team
* *
* --------------------------------------------------------------------------------------- * ---------------------------------------------------------------------------------------
* The following license statement only applies to this file (msvc.h). * The following license statement only applies to this file (msvc.h).
@ -31,6 +31,7 @@ extern "C" {
/* Pre-MSVC 2015 compilers don't implement snprintf in a cross-platform manner. */ /* Pre-MSVC 2015 compilers don't implement snprintf in a cross-platform manner. */
#if _MSC_VER < 1900 #if _MSC_VER < 1900
#include <stdio.h>
#include <stdlib.h> #include <stdlib.h>
#ifndef snprintf #ifndef snprintf
#define snprintf c99_snprintf_retro__ #define snprintf c99_snprintf_retro__
@ -41,6 +42,7 @@ extern "C" {
/* Pre-MSVC 2008 compilers don't implement vsnprintf in a cross-platform manner? Not sure about this one. */ /* Pre-MSVC 2008 compilers don't implement vsnprintf in a cross-platform manner? Not sure about this one. */
#if _MSC_VER < 1500 #if _MSC_VER < 1500
#include <stdio.h>
#include <stdarg.h> #include <stdarg.h>
#include <stdlib.h> #include <stdlib.h>
#ifndef vsnprintf #ifndef vsnprintf

View File

@ -1,4 +1,4 @@
/* Copyright (C) 2010-2018 The RetroArch team /* Copyright (C) 2010-2020 The RetroArch team
* *
* --------------------------------------------------------------------------------------- * ---------------------------------------------------------------------------------------
* The following license statement only applies to this file (posix_string.h). * The following license statement only applies to this file (posix_string.h).
@ -29,10 +29,6 @@
#include <compat/msvc.h> #include <compat/msvc.h>
#endif #endif
#if defined(PS2)
#include <compat_ctype.h>
#endif
RETRO_BEGIN_DECLS RETRO_BEGIN_DECLS
#ifdef _WIN32 #ifdef _WIN32

View File

@ -1,4 +1,4 @@
/* Copyright (C) 2010-2018 The RetroArch team /* Copyright (C) 2010-2020 The RetroArch team
* *
* --------------------------------------------------------------------------------------- * ---------------------------------------------------------------------------------------
* The following license statement only applies to this file (strcasestr.h). * The following license statement only applies to this file (strcasestr.h).
@ -25,10 +25,6 @@
#include <string.h> #include <string.h>
#if defined(PS2)
#include <compat_ctype.h>
#endif
#if defined(RARCH_INTERNAL) && defined(HAVE_CONFIG_H) #if defined(RARCH_INTERNAL) && defined(HAVE_CONFIG_H)
#include "../../../config.h" #include "../../../config.h"
#endif #endif

View File

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

View File

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

View File

@ -1,4 +1,4 @@
/* Copyright (C) 2010-2019 The RetroArch team /* Copyright (C) 2010-2020 The RetroArch team
* *
* --------------------------------------------------------------------------------------- * ---------------------------------------------------------------------------------------
* The following license statement only applies to this file (file_path.h). * The following license statement only applies to this file (file_path.h).
@ -147,14 +147,22 @@ void path_parent_dir(char *path);
/** /**
* path_resolve_realpath: * path_resolve_realpath:
* @buf : buffer for path * @buf : input and output buffer for path
* @size : size of buffer * @size : size of buffer
* @resolve_symlinks : whether to resolve symlinks or not
* *
* Turns relative paths into absolute paths and * Resolves use of ".", "..", multiple slashes etc in absolute paths.
* resolves use of "." and ".." in absolute paths. *
* If relative, rebases on current working dir. * Relative paths are rebased on the current working dir.
*
* Returns: @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,
* e.g. on Android it is "/"
* Use of fill_pathname_resolve_relative() should be prefered
**/ **/
void path_resolve_realpath(char *buf, size_t size); char *path_resolve_realpath(char *buf, size_t size, bool resolve_symlinks);
/** /**
* path_relative_to: * path_relative_to:
@ -170,7 +178,7 @@ void path_resolve_realpath(char *buf, size_t size);
* *
* E.g. path /a/b/e/f.cgp with base /a/b/c/d/ turns into ../../e/f.cgp * E.g. path /a/b/e/f.cgp with base /a/b/c/d/ turns into ../../e/f.cgp
**/ **/
void 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: * path_is_absolute:
@ -218,7 +226,7 @@ void fill_pathname(char *out_path, const char *in_path,
* E.g.: * E.g.:
* out_filename = "RetroArch-{month}{day}-{Hours}{Minutes}.{@ext}" * out_filename = "RetroArch-{month}{day}-{Hours}{Minutes}.{@ext}"
**/ **/
void fill_dated_filename(char *out_filename, size_t fill_dated_filename(char *out_filename,
const char *ext, size_t size); const char *ext, size_t size);
/** /**
@ -251,7 +259,7 @@ void fill_str_dated_filename(char *out_filename,
* present in 'in_path', it will be ignored. * present in 'in_path', it will be ignored.
* *
*/ */
void fill_pathname_noext(char *out_path, const char *in_path, size_t fill_pathname_noext(char *out_path, const char *in_path,
const char *replace, size_t size); const char *replace, size_t size);
/** /**
@ -281,7 +289,7 @@ char *find_last_slash(const char *str);
* E.g..: in_dir = "/tmp/some_dir", in_basename = "/some_content/foo.c", * E.g..: in_dir = "/tmp/some_dir", in_basename = "/some_content/foo.c",
* replace = ".asm" => in_dir = "/tmp/some_dir/foo.c.asm" * replace = ".asm" => in_dir = "/tmp/some_dir/foo.c.asm"
**/ **/
void fill_pathname_dir(char *in_dir, const char *in_basename, size_t fill_pathname_dir(char *in_dir, const char *in_basename,
const char *replace, size_t size); const char *replace, size_t size);
/** /**
@ -292,12 +300,12 @@ void fill_pathname_dir(char *in_dir, const char *in_basename,
* *
* Copies basename of @in_path into @out_path. * Copies basename of @in_path into @out_path.
**/ **/
void fill_pathname_base(char *out_path, const char *in_path, size_t size); size_t fill_pathname_base(char *out_path, const char *in_path, size_t size);
void fill_pathname_base_noext(char *out_dir, void fill_pathname_base_noext(char *out_dir,
const char *in_path, size_t size); const char *in_path, size_t size);
void fill_pathname_base_ext(char *out, size_t fill_pathname_base_ext(char *out,
const char *in_path, const char *ext, const char *in_path, const char *ext,
size_t size); size_t size);
@ -368,20 +376,20 @@ void fill_pathname_resolve_relative(char *out_path, const char *in_refpath,
* Makes sure not to get two consecutive slashes * Makes sure not to get two consecutive slashes
* between directory and path. * between directory and path.
**/ **/
void fill_pathname_join(char *out_path, const char *dir, size_t fill_pathname_join(char *out_path, const char *dir,
const char *path, size_t size); const char *path, size_t size);
void fill_pathname_join_special_ext(char *out_path, size_t fill_pathname_join_special_ext(char *out_path,
const char *dir, const char *path, const char *dir, const char *path,
const char *last, const char *ext, const char *last, const char *ext,
size_t size); size_t size);
void fill_pathname_join_concat_noext(char *out_path, size_t fill_pathname_join_concat_noext(char *out_path,
const char *dir, const char *path, const char *dir, const char *path,
const char *concat, const char *concat,
size_t size); size_t size);
void fill_pathname_join_concat(char *out_path, size_t fill_pathname_join_concat(char *out_path,
const char *dir, const char *path, const char *dir, const char *path,
const char *concat, const char *concat,
size_t size); size_t size);
@ -400,10 +408,10 @@ void fill_pathname_join_noext(char *out_path,
* Joins a directory (@dir) and path (@path) together * Joins a directory (@dir) and path (@path) together
* using the given delimiter (@delim). * using the given delimiter (@delim).
**/ **/
void fill_pathname_join_delim(char *out_path, const char *dir, size_t fill_pathname_join_delim(char *out_path, const char *dir,
const char *path, const char delim, size_t size); const char *path, const char delim, size_t size);
void fill_pathname_join_delim_concat(char *out_path, const char *dir, size_t fill_pathname_join_delim_concat(char *out_path, const char *dir,
const char *path, const char delim, const char *concat, const char *path, const char delim, const char *concat,
size_t size); size_t size);
@ -422,7 +430,7 @@ void fill_pathname_join_delim_concat(char *out_path, const char *dir,
* E.g.: "/path/to/game.img" -> game.img * E.g.: "/path/to/game.img" -> game.img
* "/path/to/myarchive.7z#folder/to/game.img" -> game.img * "/path/to/myarchive.7z#folder/to/game.img" -> game.img
*/ */
void fill_short_pathname_representation(char* out_rep, size_t fill_short_pathname_representation(char* out_rep,
const char *in_path, size_t size); const char *in_path, size_t size);
void fill_short_pathname_representation_noext(char* out_rep, void fill_short_pathname_representation_noext(char* out_rep,
@ -452,9 +460,9 @@ void path_basedir_wrapper(char *path);
* Returns: true (1) if character is a slash, otherwise false (0). * Returns: true (1) if character is a slash, otherwise false (0).
*/ */
#ifdef _WIN32 #ifdef _WIN32
#define path_char_is_slash(c) (((c) == '/') || ((c) == '\\')) #define PATH_CHAR_IS_SLASH(c) (((c) == '/') || ((c) == '\\'))
#else #else
#define path_char_is_slash(c) ((c) == '/') #define PATH_CHAR_IS_SLASH(c) ((c) == '/')
#endif #endif
/** /**
@ -465,11 +473,11 @@ void path_basedir_wrapper(char *path);
* Returns: default slash separator. * Returns: default slash separator.
*/ */
#ifdef _WIN32 #ifdef _WIN32
#define path_default_slash() "\\" #define PATH_DEFAULT_SLASH() "\\"
#define path_default_slash_c() '\\' #define PATH_DEFAULT_SLASH_C() '\\'
#else #else
#define path_default_slash() "/" #define PATH_DEFAULT_SLASH() "/"
#define path_default_slash_c() '/' #define PATH_DEFAULT_SLASH_C() '/'
#endif #endif
/** /**

View File

@ -32,8 +32,8 @@
RETRO_BEGIN_DECLS RETRO_BEGIN_DECLS
#ifdef HAVE_OPENGLES2 #ifdef HAVE_OPENGLES2
typedef GLfloat GLdouble; typedef double GLdouble;
typedef GLclampf GLclampd; typedef double GLclampd;
#endif #endif
#if defined(HAVE_OPENGLES2) #if defined(HAVE_OPENGLES2)

View File

@ -25,6 +25,10 @@
#include <glsm/glsm.h> #include <glsm/glsm.h>
#ifdef HAVE_GLSYM_PRIVATE
#include "glsym_private.h"
#endif
#include <retro_common_api.h> #include <retro_common_api.h>
RETRO_BEGIN_DECLS RETRO_BEGIN_DECLS
@ -150,7 +154,7 @@ RETRO_BEGIN_DECLS
#define glUniformBlockBinding rglUniformBlockBinding #define glUniformBlockBinding rglUniformBlockBinding
#define glGetUniformBlockIndex rglGetUniformBlockIndex #define glGetUniformBlockIndex rglGetUniformBlockIndex
#define glGetActiveUniformBlockiv rglGetActiveUniformBlockiv #define glGetActiveUniformBlockiv rglGetActiveUniformBlockiv
#define glBindBufferBase rglBindBufferBase #define glBindBufferBase rglBindBufferBase
#define glGetUniformIndices rglGetUniformIndices #define glGetUniformIndices rglGetUniformIndices
#define glGetActiveUniformsiv rglGetActiveUniformsiv #define glGetActiveUniformsiv rglGetActiveUniformsiv
#define glGetError rglGetError #define glGetError rglGetError

View File

@ -1,4 +1,4 @@
/* Copyright (C) 2010-2018 The RetroArch team /* Copyright (C) 2010-2020 The RetroArch team
* *
* --------------------------------------------------------------------------------------- * ---------------------------------------------------------------------------------------
* The following license statement only applies to this libretro SDK code part (glsym). * The following license statement only applies to this libretro SDK code part (glsym).

View File

@ -1,4 +1,4 @@
/* Copyright (C) 2010-2018 The RetroArch team /* Copyright (C) 2010-2020 The RetroArch team
* *
* --------------------------------------------------------------------------------------- * ---------------------------------------------------------------------------------------
* The following license statement only applies to this libretro SDK code part (glsym). * The following license statement only applies to this libretro SDK code part (glsym).

View File

@ -1,4 +1,4 @@
/* Copyright (C) 2010-2018 The RetroArch team /* Copyright (C) 2010-2020 The RetroArch team
* *
* --------------------------------------------------------------------------------------- * ---------------------------------------------------------------------------------------
* The following license statement only applies to this libretro SDK code part (glsym). * The following license statement only applies to this libretro SDK code part (glsym).

View File

@ -1,4 +1,4 @@
/* Copyright (C) 2010-2018 The RetroArch team /* Copyright (C) 2010-2020 The RetroArch team
* *
* --------------------------------------------------------------------------------------- * ---------------------------------------------------------------------------------------
* The following license statement only applies to this libretro SDK code part (glsym). * The following license statement only applies to this libretro SDK code part (glsym).
@ -28,55 +28,7 @@
#include <EGL/eglext.h> #include <EGL/eglext.h>
#endif #endif
#if defined(IOS) #include "rglgen_private_headers.h"
#if defined(HAVE_OPENGLES3)
#include <OpenGLES/ES3/gl.h>
#include <OpenGLES/ES3/glext.h>
#else
#include <OpenGLES/ES2/gl.h>
#include <OpenGLES/ES2/glext.h>
#endif
#elif defined(__APPLE__)
#include <compat/apple_compat.h>
#if MAC_OS_X_VERSION_10_7
#include <OpenGL/gl3.h>
#include <OpenGL/gl3ext.h>
#else
#include <OpenGL/gl.h>
#include <OpenGL/glext.h>
#endif
#elif defined(HAVE_PSGL)
#include <PSGL/psgl.h>
#include <GLES/glext.h>
#elif defined(HAVE_OPENGL_MODERN)
#include <GL3/gl3.h>
#include <GL3/gl3ext.h>
#elif defined(HAVE_OPENGLES3)
#include <GLES3/gl3.h>
#define __gl2_h_
#include <GLES2/gl2ext.h>
#elif defined(HAVE_OPENGLES2)
#include <GLES2/gl2.h>
#include <GLES2/gl2ext.h>
#elif defined(HAVE_OPENGLES1)
#include <GLES/gl.h>
#include <GLES/glext.h>
#else
#if defined(_WIN32) && !defined(_XBOX)
#define WIN32_LEAN_AND_MEAN
#include <windows.h>
#endif
#ifndef HAVE_LIBNX
#include <GL/gl.h>
#include <GL/glext.h>
#else
/* We need to avoid including <GL/gl.h> on this platform */
#include "switch/nx_gl.h"
#include <GL/glext.h>
#endif /* SWITCH */
#endif
#ifndef GL_MAP_WRITE_BIT #ifndef GL_MAP_WRITE_BIT
#define GL_MAP_WRITE_BIT 0x0002 #define GL_MAP_WRITE_BIT 0x0002

View File

@ -279,6 +279,9 @@ enum retro_language
RETRO_LANGUAGE_GREEK = 17, RETRO_LANGUAGE_GREEK = 17,
RETRO_LANGUAGE_TURKISH = 18, RETRO_LANGUAGE_TURKISH = 18,
RETRO_LANGUAGE_SLOVAK = 19, RETRO_LANGUAGE_SLOVAK = 19,
RETRO_LANGUAGE_PERSIAN = 20,
RETRO_LANGUAGE_HEBREW = 21,
RETRO_LANGUAGE_ASTURIAN = 22,
RETRO_LANGUAGE_LAST, RETRO_LANGUAGE_LAST,
/* Ensure sizeof(enum) == sizeof(int) */ /* Ensure sizeof(enum) == sizeof(int) */

View File

@ -1,4 +1,4 @@
/* Copyright (C) 2010-2018 The RetroArch team /* Copyright (C) 2010-2020 The RetroArch team
* *
* --------------------------------------------------------------------------------------------- * ---------------------------------------------------------------------------------------------
* The following license statement only applies to this libretro API header (libretro_vulkan.h) * The following license statement only applies to this libretro API header (libretro_vulkan.h)

View File

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

View File

@ -1,4 +1,4 @@
/* Copyright (C) 2010-2018 The RetroArch team /* Copyright (C) 2010-2020 The RetroArch team
* *
* --------------------------------------------------------------------------------------- * ---------------------------------------------------------------------------------------
* The following license statement only applies to this file (string_list.h). * The following license statement only applies to this file (string_list.h).
@ -41,6 +41,7 @@ union string_list_elem_attr
struct string_list_elem struct string_list_elem
{ {
char *data; char *data;
void *userdata;
union string_list_elem_attr attr; union string_list_elem_attr attr;
}; };
@ -87,6 +88,19 @@ bool string_list_find_elem_prefix(const struct string_list *list,
*/ */
struct string_list *string_split(const char *str, const char *delim); struct string_list *string_split(const char *str, const char *delim);
/**
* string_separate:
* @str : string to turn into a string list
* @delim : delimiter character to use for separating the string.
*
* Creates a new string list based on string @str, delimited by @delim.
* Includes empty strings - i.e. two adjacent delimiters will resolve
* to a string list element of "".
*
* Returns: new string list if successful, otherwise NULL.
*/
struct string_list *string_separate(char *str, const char *delim);
/** /**
* string_list_new: * string_list_new:
* *

View File

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

View File

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

View File

@ -1,4 +1,4 @@
/* Copyright (C) 2010-2018 The RetroArch team /* Copyright (C) 2010-2020 The RetroArch team
* *
* --------------------------------------------------------------------------------------- * ---------------------------------------------------------------------------------------
* The following license statement only applies to this file (memmap.h). * The following license statement only applies to this file (memmap.h).
@ -26,7 +26,7 @@
#include <stdio.h> #include <stdio.h>
#include <stdint.h> #include <stdint.h>
#if defined(__CELLOS_LV2__) || defined(PSP) || defined(PS2) || defined(GEKKO) || defined(VITA) || defined(_XBOX) || defined(_3DS) || defined(WIIU) || defined(SWITCH) #if defined(__CELLOS_LV2__) || defined(PSP) || defined(PS2) || defined(GEKKO) || defined(VITA) || defined(_XBOX) || defined(_3DS) || defined(WIIU) || defined(SWITCH) || defined(HAVE_LIBNX)
/* No mman available */ /* No mman available */
#elif defined(_WIN32) && !defined(_XBOX) #elif defined(_WIN32) && !defined(_XBOX)
#include <windows.h> #include <windows.h>

View File

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

View File

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

View File

@ -1,4 +1,4 @@
/* Copyright (C) 2010-2018 The RetroArch team /* Copyright (C) 2010-2020 The RetroArch team
* *
* --------------------------------------------------------------------------------------- * ---------------------------------------------------------------------------------------
* The following license statement only applies to this file (retro_common_api.h). * The following license statement only applies to this file (retro_common_api.h).
@ -89,7 +89,9 @@ typedef int ssize_t;
/* C++11 says this one isn't needed, but apparently (some versions of) mingw require it anyways */ /* C++11 says this one isn't needed, but apparently (some versions of) mingw require it anyways */
/* https://stackoverflow.com/questions/8132399/how-to-printf-uint64-t-fails-with-spurious-trailing-in-format */ /* https://stackoverflow.com/questions/8132399/how-to-printf-uint64-t-fails-with-spurious-trailing-in-format */
/* https://github.com/libretro/RetroArch/issues/6009 */ /* https://github.com/libretro/RetroArch/issues/6009 */
#define __STDC_FORMAT_MACROS #ifndef __STDC_FORMAT_MACROS
#define __STDC_FORMAT_MACROS 1
#endif
#include <inttypes.h> #include <inttypes.h>
#endif #endif
#ifndef PRId64 #ifndef PRId64

View File

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

View File

@ -1,4 +1,4 @@
/* Copyright (C) 2010-2018 The RetroArch team /* Copyright (C) 2010-2020 The RetroArch team
* *
* --------------------------------------------------------------------------------------- * ---------------------------------------------------------------------------------------
* The following license statement only applies to this file (retro_endianness.h). * The following license statement only applies to this file (retro_endianness.h).
@ -31,40 +31,100 @@
#define SWAP16 _byteswap_ushort #define SWAP16 _byteswap_ushort
#define SWAP32 _byteswap_ulong #define SWAP32 _byteswap_ulong
#else #else
#define SWAP16(x) ((uint16_t)( \ static INLINE uint16_t SWAP16(uint16_t x)
(((uint16_t)(x) & 0x00ff) << 8) | \ {
(((uint16_t)(x) & 0xff00) >> 8) \ return ((x & 0x00ff) << 8) |
)) ((x & 0xff00) >> 8);
#define SWAP32(x) ((uint32_t)( \ }
(((uint32_t)(x) & 0x000000ff) << 24) | \
(((uint32_t)(x) & 0x0000ff00) << 8) | \ static INLINE uint32_t SWAP32(uint32_t x)
(((uint32_t)(x) & 0x00ff0000) >> 8) | \ {
(((uint32_t)(x) & 0xff000000) >> 24) \ return ((x & 0x000000ff) << 24) |
)) ((x & 0x0000ff00) << 8) |
((x & 0x00ff0000) >> 8) |
((x & 0xff000000) >> 24);
}
#endif #endif
#if defined(_MSC_VER) && _MSC_VER <= 1200 #if defined(_MSC_VER) && _MSC_VER <= 1200
#define SWAP64(val) \ static INLINE uint64_t SWAP64(uint64_t val)
((((uint64_t)(val) & 0x00000000000000ff) << 56) \ {
| (((uint64_t)(val) & 0x000000000000ff00) << 40) \ return
| (((uint64_t)(val) & 0x0000000000ff0000) << 24) \ ((val & 0x00000000000000ff) << 56)
| (((uint64_t)(val) & 0x00000000ff000000) << 8) \ | ((val & 0x000000000000ff00) << 40)
| (((uint64_t)(val) & 0x000000ff00000000) >> 8) \ | ((val & 0x0000000000ff0000) << 24)
| (((uint64_t)(val) & 0x0000ff0000000000) >> 24) \ | ((val & 0x00000000ff000000) << 8)
| (((uint64_t)(val) & 0x00ff000000000000) >> 40) \ | ((val & 0x000000ff00000000) >> 8)
| (((uint64_t)(val) & 0xff00000000000000) >> 56)) | ((val & 0x0000ff0000000000) >> 24)
| ((val & 0x00ff000000000000) >> 40)
| ((val & 0xff00000000000000) >> 56);
}
#else #else
#define SWAP64(val) \ static INLINE uint64_t SWAP64(uint64_t val)
((((uint64_t)(val) & 0x00000000000000ffULL) << 56) \ {
| (((uint64_t)(val) & 0x000000000000ff00ULL) << 40) \ return ((val & 0x00000000000000ffULL) << 56)
| (((uint64_t)(val) & 0x0000000000ff0000ULL) << 24) \ | ((val & 0x000000000000ff00ULL) << 40)
| (((uint64_t)(val) & 0x00000000ff000000ULL) << 8) \ | ((val & 0x0000000000ff0000ULL) << 24)
| (((uint64_t)(val) & 0x000000ff00000000ULL) >> 8) \ | ((val & 0x00000000ff000000ULL) << 8)
| (((uint64_t)(val) & 0x0000ff0000000000ULL) >> 24) \ | ((val & 0x000000ff00000000ULL) >> 8)
| (((uint64_t)(val) & 0x00ff000000000000ULL) >> 40) \ | ((val & 0x0000ff0000000000ULL) >> 24)
| (((uint64_t)(val) & 0xff00000000000000ULL) >> 56)) | ((val & 0x00ff000000000000ULL) >> 40)
| ((val & 0xff00000000000000ULL) >> 56);
}
#endif #endif
#if defined (LSB_FIRST) || defined (MSB_FIRST)
# warning Defining MSB_FIRST and LSB_FIRST in compile options is deprecated
# undef LSB_FIRST
# undef MSB_FIRST
#endif
#if defined(_MSC_VER) && !defined(_XBOX)
#include <winsock2.h>
#endif
#ifdef _MSC_VER
#if _M_IX86 || _M_AMD64 || _M_ARM || _M_ARM64
#define LSB_FIRST 1
#elif _M_PPC
#define MSB_FIRST 1
#else
/* MSVC can run on _M_ALPHA and _M_IA64 too, but they're both bi-endian; need to find what mode MSVC runs them at */
#error "unknown platform, can't determine endianness"
#endif
#else
#if __BYTE_ORDER__ == __ORDER_BIG_ENDIAN__
#define MSB_FIRST 1
#elif __BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__
#define LSB_FIRST 1
#else
#error "Invalid endianness macros"
#endif
#endif
#if defined(MSB_FIRST) && defined(LSB_FIRST)
# error "Bug in LSB_FIRST/MSB_FIRST definition"
#endif
#if !defined(MSB_FIRST) && !defined(LSB_FIRST)
# error "Bug in LSB_FIRST/MSB_FIRST definition"
#endif
#ifdef MSB_FIRST
# define RETRO_IS_BIG_ENDIAN 1
# define RETRO_IS_LITTLE_ENDIAN 0
/* For compatibility */
# define WORDS_BIGENDIAN 1
#else
# define RETRO_IS_BIG_ENDIAN 0
# define RETRO_IS_LITTLE_ENDIAN 1
/* For compatibility */
# undef WORDS_BIGENDIAN
#endif
/** /**
* is_little_endian: * is_little_endian:
* *
@ -73,23 +133,7 @@
* Returns: greater than 0 if little-endian, * Returns: greater than 0 if little-endian,
* otherwise big-endian. * otherwise big-endian.
**/ **/
#if defined(MSB_FIRST) #define is_little_endian() RETRO_IS_LITTLE_ENDIAN
#define is_little_endian() (0)
#elif defined(__x86_64) || defined(__i386) || defined(_M_IX86) || defined(_M_X64)
#define is_little_endian() (1)
#else
static INLINE uint8_t is_little_endian(void)
{
union
{
uint16_t x;
uint8_t y[2];
} u;
u.x = 1;
return u.y[0];
}
#endif
/** /**
* swap_if_big64: * swap_if_big64:
@ -101,17 +145,10 @@ static INLINE uint8_t is_little_endian(void)
* otherwise returns same value. * otherwise returns same value.
**/ **/
#if defined(MSB_FIRST) #if RETRO_IS_BIG_ENDIAN
#define swap_if_big64(val) (SWAP64(val)) #define swap_if_big64(val) (SWAP64(val))
#elif defined(__x86_64) || defined(__i386) || defined(_M_IX86) || defined(_M_X64) #elif RETRO_IS_LITTLE_ENDIAN
#define swap_if_big64(val) (val) #define swap_if_big64(val) (val)
#else
static INLINE uint64_t swap_if_big64(uint64_t val)
{
if (is_little_endian())
return val;
return SWAP64(val);
}
#endif #endif
/** /**
@ -124,17 +161,10 @@ static INLINE uint64_t swap_if_big64(uint64_t val)
* otherwise returns same value. * otherwise returns same value.
**/ **/
#if defined(MSB_FIRST) #if RETRO_IS_BIG_ENDIAN
#define swap_if_big32(val) (SWAP32(val)) #define swap_if_big32(val) (SWAP32(val))
#elif defined(__x86_64) || defined(__i386) || defined(_M_IX86) || defined(_M_X64) #elif RETRO_IS_LITTLE_ENDIAN
#define swap_if_big32(val) (val) #define swap_if_big32(val) (val)
#else
static INLINE uint32_t swap_if_big32(uint32_t val)
{
if (is_little_endian())
return val;
return SWAP32(val);
}
#endif #endif
/** /**
@ -147,17 +177,10 @@ static INLINE uint32_t swap_if_big32(uint32_t val)
* otherwise returns same value. * otherwise returns same value.
**/ **/
#if defined(MSB_FIRST) #if RETRO_IS_BIG_ENDIAN
#define swap_if_little64(val) (val) #define swap_if_little64(val) (val)
#elif defined(__x86_64) || defined(__i386) || defined(_M_IX86) || defined(_M_X64) #elif RETRO_IS_LITTLE_ENDIAN
#define swap_if_little64(val) (SWAP64(val)) #define swap_if_little64(val) (SWAP64(val))
#else
static INLINE uint64_t swap_if_little64(uint64_t val)
{
if (is_little_endian())
return SWAP64(val);
return val;
}
#endif #endif
/** /**
@ -170,17 +193,10 @@ static INLINE uint64_t swap_if_little64(uint64_t val)
* otherwise returns same value. * otherwise returns same value.
**/ **/
#if defined(MSB_FIRST) #if RETRO_IS_BIG_ENDIAN
#define swap_if_little32(val) (val) #define swap_if_little32(val) (val)
#elif defined(__x86_64) || defined(__i386) || defined(_M_IX86) || defined(_M_X64) #elif RETRO_IS_LITTLE_ENDIAN
#define swap_if_little32(val) (SWAP32(val)) #define swap_if_little32(val) (SWAP32(val))
#else
static INLINE uint32_t swap_if_little32(uint32_t val)
{
if (is_little_endian())
return SWAP32(val);
return val;
}
#endif #endif
/** /**
@ -193,17 +209,10 @@ static INLINE uint32_t swap_if_little32(uint32_t val)
* otherwise returns same value. * otherwise returns same value.
**/ **/
#if defined(MSB_FIRST) #if RETRO_IS_BIG_ENDIAN
#define swap_if_big16(val) (SWAP16(val)) #define swap_if_big16(val) (SWAP16(val))
#elif defined(__x86_64) || defined(__i386) || defined(_M_IX86) || defined(_M_X64) #elif RETRO_IS_LITTLE_ENDIAN
#define swap_if_big16(val) (val) #define swap_if_big16(val) (val)
#else
static INLINE uint16_t swap_if_big16(uint16_t val)
{
if (is_little_endian())
return val;
return SWAP16(val);
}
#endif #endif
/** /**
@ -216,17 +225,10 @@ static INLINE uint16_t swap_if_big16(uint16_t val)
* otherwise returns same value. * otherwise returns same value.
**/ **/
#if defined(MSB_FIRST) #if RETRO_IS_BIG_ENDIAN
#define swap_if_little16(val) (val) #define swap_if_little16(val) (val)
#elif defined(__x86_64) || defined(__i386) || defined(_M_IX86) || defined(_M_X64) #elif RETRO_IS_LITTLE_ENDIAN
#define swap_if_little16(val) (SWAP16(val)) #define swap_if_little16(val) (SWAP16(val))
#else
static INLINE uint16_t swap_if_little16(uint16_t val)
{
if (is_little_endian())
return SWAP16(val);
return val;
}
#endif #endif
/** /**
@ -255,4 +257,326 @@ static INLINE uint32_t load32be(const uint32_t *addr)
return swap_if_little32(*addr); return swap_if_little32(*addr);
} }
/**
* retro_cpu_to_le16:
* @val : unsigned 16-bit value
*
* Convert unsigned 16-bit value from system to little-endian.
*
* Returns: Little-endian representation of val.
**/
#define retro_cpu_to_le16(val) swap_if_big16(val)
/**
* retro_cpu_to_le32:
* @val : unsigned 32-bit value
*
* Convert unsigned 32-bit value from system to little-endian.
*
* Returns: Little-endian representation of val.
**/
#define retro_cpu_to_le32(val) swap_if_big32(val)
/**
* retro_cpu_to_le64:
* @val : unsigned 64-bit value
*
* Convert unsigned 64-bit value from system to little-endian.
*
* Returns: Little-endian representation of val.
**/
#define retro_cpu_to_le64(val) swap_if_big64(val)
/**
* retro_le_to_cpu16:
* @val : unsigned 16-bit value
*
* Convert unsigned 16-bit value from little-endian to native.
*
* Returns: Native representation of little-endian val.
**/
#define retro_le_to_cpu16(val) swap_if_big16(val)
/**
* retro_le_to_cpu32:
* @val : unsigned 32-bit value
*
* Convert unsigned 32-bit value from little-endian to native.
*
* Returns: Native representation of little-endian val.
**/
#define retro_le_to_cpu32(val) swap_if_big32(val)
/**
* retro_le_to_cpu16:
* @val : unsigned 64-bit value
*
* Convert unsigned 64-bit value from little-endian to native.
*
* Returns: Native representation of little-endian val.
**/
#define retro_le_to_cpu64(val) swap_if_big64(val)
/**
* retro_cpu_to_be16:
* @val : unsigned 16-bit value
*
* Convert unsigned 16-bit value from system to big-endian.
*
* Returns: Big-endian representation of val.
**/
#define retro_cpu_to_be16(val) swap_if_little16(val)
/**
* retro_cpu_to_be32:
* @val : unsigned 32-bit value
*
* Convert unsigned 32-bit value from system to big-endian.
*
* Returns: Big-endian representation of val.
**/
#define retro_cpu_to_be32(val) swap_if_little32(val)
/**
* retro_cpu_to_be64:
* @val : unsigned 64-bit value
*
* Convert unsigned 64-bit value from system to big-endian.
*
* Returns: Big-endian representation of val.
**/
#define retro_cpu_to_be64(val) swap_if_little64(val)
/**
* retro_be_to_cpu16:
* @val : unsigned 16-bit value
*
* Convert unsigned 16-bit value from big-endian to native.
*
* Returns: Native representation of big-endian val.
**/
#define retro_be_to_cpu16(val) swap_if_little16(val)
/**
* retro_be_to_cpu32:
* @val : unsigned 32-bit value
*
* Convert unsigned 32-bit value from big-endian to native.
*
* Returns: Native representation of big-endian val.
**/
#define retro_be_to_cpu32(val) swap_if_little32(val)
/**
* retro_be_to_cpu64:
* @val : unsigned 64-bit value
*
* Convert unsigned 64-bit value from big-endian to native.
*
* Returns: Native representation of big-endian val.
**/
#define retro_be_to_cpu64(val) swap_if_little64(val)
#ifdef __GNUC__
/* This attribute means that the same memory may be referred through
pointers to different size of the object (aliasing). E.g. that u8 *
and u32 * may actually be pointing to the same object. */
#define MAY_ALIAS __attribute__((__may_alias__))
#else
#define MAY_ALIAS
#endif
#pragma pack(push, 1)
struct retro_unaligned_uint16_s
{
uint16_t val;
} MAY_ALIAS;
struct retro_unaligned_uint32_s
{
uint32_t val;
} MAY_ALIAS;
struct retro_unaligned_uint64_s
{
uint64_t val;
} MAY_ALIAS;
#pragma pack(pop)
typedef struct retro_unaligned_uint16_s retro_unaligned_uint16_t;
typedef struct retro_unaligned_uint32_s retro_unaligned_uint32_t;
typedef struct retro_unaligned_uint64_s retro_unaligned_uint64_t;
/* L-value references to unaligned pointers. */
#define retro_unaligned16(p) (((retro_unaligned_uint16_t *)p)->val)
#define retro_unaligned32(p) (((retro_unaligned_uint32_t *)p)->val)
#define retro_unaligned64(p) (((retro_unaligned_uint64_t *)p)->val)
/**
* retro_get_unaligned_16be:
* @addr : pointer to unsigned 16-bit value
*
* Convert unsigned unaligned 16-bit value from big-endian to native.
*
* Returns: Native representation of big-endian val.
**/
static INLINE uint16_t retro_get_unaligned_16be(void *addr) {
return retro_be_to_cpu16(retro_unaligned16(addr));
}
/**
* retro_get_unaligned_32be:
* @addr : pointer to unsigned 32-bit value
*
* Convert unsigned unaligned 32-bit value from big-endian to native.
*
* Returns: Native representation of big-endian val.
**/
static INLINE uint32_t retro_get_unaligned_32be(void *addr) {
return retro_be_to_cpu32(retro_unaligned32(addr));
}
/**
* retro_get_unaligned_64be:
* @addr : pointer to unsigned 64-bit value
*
* Convert unsigned unaligned 64-bit value from big-endian to native.
*
* Returns: Native representation of big-endian val.
**/
static INLINE uint64_t retro_get_unaligned_64be(void *addr) {
return retro_be_to_cpu64(retro_unaligned64(addr));
}
/**
* retro_get_unaligned_16le:
* @addr : pointer to unsigned 16-bit value
*
* Convert unsigned unaligned 16-bit value from little-endian to native.
*
* Returns: Native representation of little-endian val.
**/
static INLINE uint16_t retro_get_unaligned_16le(void *addr) {
return retro_le_to_cpu16(retro_unaligned16(addr));
}
/**
* retro_get_unaligned_32le:
* @addr : pointer to unsigned 32-bit value
*
* Convert unsigned unaligned 32-bit value from little-endian to native.
*
* Returns: Native representation of little-endian val.
**/
static INLINE uint32_t retro_get_unaligned_32le(void *addr) {
return retro_le_to_cpu32(retro_unaligned32(addr));
}
/**
* retro_get_unaligned_64le:
* @addr : pointer to unsigned 64-bit value
*
* Convert unsigned unaligned 64-bit value from little-endian to native.
*
* Returns: Native representation of little-endian val.
**/
static INLINE uint64_t retro_get_unaligned_64le(void *addr) {
return retro_le_to_cpu64(retro_unaligned64(addr));
}
/**
* retro_set_unaligned_16le:
* @addr : pointer to unsigned 16-bit value
* @val : value to store
*
* Convert native value to unsigned unaligned 16-bit little-endian value
*
**/
static INLINE void retro_set_unaligned_16le(void *addr, uint16_t v) {
retro_unaligned16(addr) = retro_cpu_to_le16(v);
}
/**
* retro_set_unaligned_32le:
* @addr : pointer to unsigned 32-bit value
* @val : value to store
*
* Convert native value to unsigned unaligned 32-bit little-endian value
*
**/
static INLINE void retro_set_unaligned_32le(void *addr, uint32_t v) {
retro_unaligned32(addr) = retro_cpu_to_le32(v);
}
/**
* retro_set_unaligned_32le:
* @addr : pointer to unsigned 32-bit value
* @val : value to store
*
* Convert native value to unsigned unaligned 32-bit little-endian value
*
**/
static INLINE void retro_set_unaligned_64le(void *addr, uint64_t v) {
retro_unaligned64(addr) = retro_cpu_to_le64(v);
}
/**
* retro_set_unaligned_16be:
* @addr : pointer to unsigned 16-bit value
* @val : value to store
*
* Convert native value to unsigned unaligned 16-bit big-endian value
*
**/
static INLINE void retro_set_unaligned_16be(void *addr, uint16_t v) {
retro_unaligned16(addr) = retro_cpu_to_be16(v);
}
/**
* retro_set_unaligned_32be:
* @addr : pointer to unsigned 32-bit value
* @val : value to store
*
* Convert native value to unsigned unaligned 32-bit big-endian value
*
**/
static INLINE void retro_set_unaligned_32be(void *addr, uint32_t v) {
retro_unaligned32(addr) = retro_cpu_to_be32(v);
}
/**
* retro_set_unaligned_32be:
* @addr : pointer to unsigned 32-bit value
* @val : value to store
*
* Convert native value to unsigned unaligned 32-bit big-endian value
*
**/
static INLINE void retro_set_unaligned_64be(void *addr, uint64_t v) {
retro_unaligned64(addr) = retro_cpu_to_be64(v);
}
#endif #endif

View File

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

View File

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

View File

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

View File

@ -1,4 +1,4 @@
/* Copyright (C) 2010-2018 The RetroArch team /* Copyright (C) 2010-2020 The RetroArch team
* *
* --------------------------------------------------------------------------------------- * ---------------------------------------------------------------------------------------
* The following license statement only applies to this file (retro_miscellaneous.h). * The following license statement only applies to this file (retro_miscellaneous.h).
@ -39,7 +39,7 @@
#include <Xtl.h> #include <Xtl.h>
#endif #endif
#if defined(__CELLOS_LV2__) #if defined(__CELLOS_LV2__) && !defined(__PSL1GHT__)
#include <sys/fs_external.h> #include <sys/fs_external.h>
#endif #endif
@ -75,7 +75,7 @@ static INLINE bool bits_any_set(uint32_t* ptr, uint32_t count)
} }
#ifndef PATH_MAX_LENGTH #ifndef PATH_MAX_LENGTH
#if defined(__CELLOS_LV2__) #if defined(__CELLOS_LV2__) && !defined(__PSL1GHT__)
#define PATH_MAX_LENGTH CELL_FS_MAX_FS_PATH_LENGTH #define PATH_MAX_LENGTH CELL_FS_MAX_FS_PATH_LENGTH
#elif defined(_XBOX1) || defined(_3DS) || defined(PSP) || defined(PS2) || defined(GEKKO)|| defined(WIIU) || defined(ORBIS) #elif defined(_XBOX1) || defined(_3DS) || defined(PSP) || defined(PS2) || defined(GEKKO)|| defined(WIIU) || defined(ORBIS)
#define PATH_MAX_LENGTH 512 #define PATH_MAX_LENGTH 512
@ -106,8 +106,8 @@ static INLINE bool bits_any_set(uint32_t* ptr, uint32_t count)
#define BIT16_GET(a, bit) (((a) >> ((bit) & 15)) & 1) #define BIT16_GET(a, bit) (((a) >> ((bit) & 15)) & 1)
#define BIT16_CLEAR_ALL(a) ((a) = 0) #define BIT16_CLEAR_ALL(a) ((a) = 0)
#define BIT32_SET(a, bit) ((a) |= (1 << ((bit) & 31))) #define BIT32_SET(a, bit) ((a) |= (UINT32_C(1) << ((bit) & 31)))
#define BIT32_CLEAR(a, bit) ((a) &= ~(1 << ((bit) & 31))) #define BIT32_CLEAR(a, bit) ((a) &= ~(UINT32_C(1) << ((bit) & 31)))
#define BIT32_GET(a, bit) (((a) >> ((bit) & 31)) & 1) #define BIT32_GET(a, bit) (((a) >> ((bit) & 31)) & 1)
#define BIT32_CLEAR_ALL(a) ((a) = 0) #define BIT32_CLEAR_ALL(a) ((a) = 0)
@ -116,8 +116,8 @@ static INLINE bool bits_any_set(uint32_t* ptr, uint32_t count)
#define BIT64_GET(a, bit) (((a) >> ((bit) & 63)) & 1) #define BIT64_GET(a, bit) (((a) >> ((bit) & 63)) & 1)
#define BIT64_CLEAR_ALL(a) ((a) = 0) #define BIT64_CLEAR_ALL(a) ((a) = 0)
#define BIT128_SET(a, bit) ((a).data[(bit) >> 5] |= (1 << ((bit) & 31))) #define BIT128_SET(a, bit) ((a).data[(bit) >> 5] |= (UINT32_C(1) << ((bit) & 31)))
#define BIT128_CLEAR(a, bit) ((a).data[(bit) >> 5] &= ~(1 << ((bit) & 31))) #define BIT128_CLEAR(a, bit) ((a).data[(bit) >> 5] &= ~(UINT32_C(1) << ((bit) & 31)))
#define BIT128_GET(a, bit) (((a).data[(bit) >> 5] >> ((bit) & 31)) & 1) #define BIT128_GET(a, bit) (((a).data[(bit) >> 5] >> ((bit) & 31)) & 1)
#define BIT128_CLEAR_ALL(a) memset(&(a), 0, sizeof(a)) #define BIT128_CLEAR_ALL(a) memset(&(a), 0, sizeof(a))

View File

@ -1,4 +1,4 @@
/* Copyright (C) 2010-2018 The RetroArch team /* Copyright (C) 2010-2020 The RetroArch team
* *
* --------------------------------------------------------------------------------------- * ---------------------------------------------------------------------------------------
* The following license statement only applies to this file (retro_timers.h). * The following license statement only applies to this file (retro_timers.h).
@ -37,8 +37,6 @@
#include <pspthreadman.h> #include <pspthreadman.h>
#elif defined(VITA) #elif defined(VITA)
#include <psp2/kernel/threadmgr.h> #include <psp2/kernel/threadmgr.h>
#elif defined(PS2)
#include <SDL/SDL_timer.h>
#elif defined(_3DS) #elif defined(_3DS)
#include <3ds.h> #include <3ds.h>
#else #else
@ -68,7 +66,7 @@ extern int nanosleep(const struct timespec *rqtp, struct timespec *rmtp);
static int nanosleepDOS(const struct timespec *rqtp, struct timespec *rmtp) static int nanosleepDOS(const struct timespec *rqtp, struct timespec *rmtp)
{ {
usleep(1000000 * rqtp->tv_sec + rqtp->tv_nsec / 1000); usleep(1000000L * rqtp->tv_sec + rqtp->tv_nsec / 1000);
if (rmtp) if (rmtp)
rmtp->tv_sec = rmtp->tv_nsec=0; rmtp->tv_sec = rmtp->tv_nsec=0;
@ -91,8 +89,6 @@ static INLINE void retro_sleep(unsigned msec)
sys_timer_usleep(1000 * msec); sys_timer_usleep(1000 * msec);
#elif defined(PSP) || defined(VITA) #elif defined(PSP) || defined(VITA)
sceKernelDelayThread(1000 * msec); sceKernelDelayThread(1000 * msec);
#elif defined(PS2)
SDL_Delay(msec);
#elif defined(_3DS) #elif defined(_3DS)
svcSleepThread(1000000 * (s64)msec); svcSleepThread(1000000 * (s64)msec);
#elif defined(__WINRT__) || defined(WINAPI_FAMILY) && WINAPI_FAMILY == WINAPI_FAMILY_PHONE_APP #elif defined(__WINRT__) || defined(WINAPI_FAMILY) && WINAPI_FAMILY == WINAPI_FAMILY_PHONE_APP

View File

@ -1,4 +1,4 @@
/* Copyright (C) 2010-2018 The RetroArch team /* Copyright (C) 2010-2020 The RetroArch team
* *
* --------------------------------------------------------------------------------------- * ---------------------------------------------------------------------------------------
* The following license statement only applies to this file (rhash.h). * The following license statement only applies to this file (rhash.h).
@ -20,31 +20,8 @@
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*/ */
/* #ifndef __LIBRETRO_SDK_HASH_H
* sha1.h #define __LIBRETRO_SDK_HASH_H
*
* Copyright (C) 1998, 2009
* Paul E. Jones <paulej@packetizer.com>
* All Rights Reserved
*
*****************************************************************************
* $Id: sha1.h 12 2009-06-22 19:34:25Z paulej $
*****************************************************************************
*
* Description:
* This class implements the Secure Hashing Standard as defined
* in FIPS PUB 180-1 published April 17, 1995.
*
* Many of the variable names in the SHA1Context, especially the
* single character names, were used because those were the names
* used in the publication.
*
* Please read the file sha1.c for more information.
*
*/
#ifndef __RARCH_HASH_H
#define __RARCH_HASH_H
#include <stdint.h> #include <stdint.h>
#include <stddef.h> #include <stddef.h>
@ -70,20 +47,6 @@ RETRO_BEGIN_DECLS
**/ **/
void sha256_hash(char *out, const uint8_t *in, size_t size); void sha256_hash(char *out, const uint8_t *in, size_t size);
typedef struct SHA1Context
{
unsigned Message_Digest[5]; /* Message Digest (output) */
unsigned Length_Low; /* Message length in bits */
unsigned Length_High; /* Message length in bits */
unsigned char Message_Block[64]; /* 512-bit message blocks */
int Message_Block_Index; /* Index into message block array */
int Computed; /* Is the digest computed? */
int Corrupted; /* Is the message digest corruped? */
} SHA1Context;
int sha1_calculate(const char *path, char *result); int sha1_calculate(const char *path, char *result);
uint32_t djb2_calculate(const char *str); uint32_t djb2_calculate(const char *str);

View File

@ -1,4 +1,4 @@
/* Copyright (C) 2010-2018 The RetroArch team /* Copyright (C) 2010-2020 The RetroArch team
* *
* --------------------------------------------------------------------------------------- * ---------------------------------------------------------------------------------------
* The following license statement only applies to this file (rthreads.h). * The following license statement only applies to this file (rthreads.h).
@ -131,6 +131,15 @@ void slock_free(slock_t *lock);
**/ **/
void slock_lock(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: * slock_unlock:
* @lock : pointer to mutex object * @lock : pointer to mutex object
@ -236,11 +245,25 @@ void *sthread_tls_get(sthread_tls_t *tls);
/** /**
* @brief Binds thread specific data to a key * @brief Binds thread specific data to a key
* @param tls * @param tls
* @return whether the operation suceeded or not * @return Whether the operation suceeded or not
*/ */
bool sthread_tls_set(sthread_tls_t *tls, const void *data); bool sthread_tls_set(sthread_tls_t *tls, const void *data);
#endif #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 RETRO_END_DECLS
#endif #endif

View File

@ -1,4 +1,4 @@
/* Copyright (C) 2010-2018 The RetroArch team /* Copyright (C) 2010-2020 The RetroArch team
* *
* --------------------------------------------------------------------------------------- * ---------------------------------------------------------------------------------------
* The following license statement only applies to this file (file_stream.h). * The following license statement only applies to this file (file_stream.h).
@ -61,7 +61,7 @@ int64_t filestream_truncate(RFILE *stream, int64_t length);
* Opens a file for reading or writing, depending on the requested mode. * Opens a file for reading or writing, depending on the requested mode.
* Returns a pointer to an RFILE if opened successfully, otherwise NULL. * Returns a pointer to an RFILE if opened successfully, otherwise NULL.
**/ **/
RFILE *filestream_open(const char *path, unsigned mode, unsigned hints); RFILE* filestream_open(const char *path, unsigned mode, unsigned hints);
int64_t filestream_seek(RFILE *stream, int64_t offset, int seek_position); int64_t filestream_seek(RFILE *stream, int64_t offset, int seek_position);
@ -77,7 +77,7 @@ int filestream_close(RFILE *stream);
int64_t filestream_read_file(const char *path, void **buf, int64_t *len); int64_t filestream_read_file(const char *path, void **buf, int64_t *len);
char *filestream_gets(RFILE *stream, char *s, size_t len); char* filestream_gets(RFILE *stream, char *s, size_t len);
int filestream_getc(RFILE *stream); int filestream_getc(RFILE *stream);
@ -101,11 +101,12 @@ int filestream_delete(const char *path);
int filestream_rename(const char *old_path, const char *new_path); int filestream_rename(const char *old_path, const char *new_path);
const char *filestream_get_path(RFILE *stream); const char* filestream_get_path(RFILE *stream);
bool filestream_exists(const char *path); bool filestream_exists(const char *path);
char *filestream_getline(RFILE *stream); /* Returned pointer must be freed by the caller. */
char* filestream_getline(RFILE *stream);
libretro_vfs_implementation_file* filestream_get_vfs_handle(RFILE *stream); libretro_vfs_implementation_file* filestream_get_vfs_handle(RFILE *stream);

View File

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

View File

@ -1,4 +1,4 @@
/* Copyright (C) 2010-2019 The RetroArch team /* Copyright (C) 2010-2020 The RetroArch team
* *
* --------------------------------------------------------------------------------------- * ---------------------------------------------------------------------------------------
* The following license statement only applies to this file (stdstring.h). * The following license statement only applies to this file (stdstring.h).
@ -45,31 +45,40 @@ static INLINE bool string_is_equal(const char *a, const char *b)
return (a && b) ? !strcmp(a, b) : false; return (a && b) ? !strcmp(a, b) : false;
} }
static INLINE bool string_starts_with_size(const char *str, const char *prefix,
size_t size)
{
return (str && prefix) ? !strncmp(prefix, str, size) : false;
}
static INLINE bool string_starts_with(const char *str, const char *prefix)
{
return (str && prefix) ? !strncmp(prefix, str, strlen(prefix)) : false;
}
static INLINE bool string_ends_with_size(const char *str, const char *suffix,
size_t str_len, size_t suffix_len)
{
return (str_len < suffix_len) ? false :
!memcmp(suffix, str + (str_len - suffix_len), suffix_len);
}
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));
}
#define STRLEN_CONST(x) ((sizeof((x))-1)) #define STRLEN_CONST(x) ((sizeof((x))-1))
#define string_is_not_equal(a, b) !string_is_equal((a), (b)) #define string_is_not_equal(a, b) !string_is_equal((a), (b))
#define string_add_pair_open(s, size) strlcat((s), " (", (size))
#define string_add_pair_close(s, size) strlcat((s), ")", (size))
#define string_add_bracket_open(s, size) strlcat((s), "{", (size))
#define string_add_bracket_close(s, size) strlcat((s), "}", (size))
#define string_add_single_quote(s, size) strlcat((s), "'", (size))
#define string_add_quote(s, size) strlcat((s), "\"", (size))
#define string_add_colon(s, size) strlcat((s), ":", (size))
#define string_add_glob_open(s, size) strlcat((s), "glob('*", (size))
#define string_add_glob_close(s, size) strlcat((s), "*')", (size))
#define string_is_not_equal_fast(a, b, size) (memcmp(a, b, size) != 0) #define string_is_not_equal_fast(a, b, size) (memcmp(a, b, size) != 0)
#define string_is_equal_fast(a, b, size) (memcmp(a, b, size) == 0) #define string_is_equal_fast(a, b, size) (memcmp(a, b, size) == 0)
static INLINE void string_add_between_pairs(char *s, const char *str,
size_t size)
{
string_add_pair_open(s, size);
strlcat(s, str, size);
string_add_pair_close(s, size);
}
static INLINE bool string_is_equal_case_insensitive(const char *a, static INLINE bool string_is_equal_case_insensitive(const char *a,
const char *b) const char *b)
{ {
@ -129,6 +138,45 @@ char *string_trim_whitespace(char *const s);
char *word_wrap(char *buffer, const char *string, char *word_wrap(char *buffer, const char *string,
int line_width, bool unicode, unsigned max_lines); int line_width, bool unicode, unsigned max_lines);
/* 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
* last found token
* > Tokens *include* empty strings
* Usage example:
* char *str = "1,2,3,4,5,6,7,,,10,";
* char **str_ptr = &str;
* char *token = NULL;
* while ((token = string_tokenize(str_ptr, ",")))
* {
* printf("%s\n", token);
* free(token);
* token = NULL;
* }
*/
char* string_tokenize(char **str, const char *delim);
/* 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' */
void string_replace_all_chars(char *str, char find, char replace);
/* Converts string to unsigned integer.
* Returns 0 if string is invalid */
unsigned string_to_unsigned(const char *str);
/* Converts hexadecimal string to unsigned integer.
* Handles optional leading '0x'.
* Returns 0 if string is invalid */
unsigned string_hex_to_unsigned(const char *str);
char *string_init(const char *src);
void string_set(char **string, const char *src);
RETRO_END_DECLS RETRO_END_DECLS
#endif #endif

View File

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

View File

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

View File

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

View File

@ -1,4 +1,4 @@
/* Copyright (C) 2010-2018 The RetroArch team /* Copyright (C) 2010-2020 The RetroArch team
* *
* --------------------------------------------------------------------------------------- * ---------------------------------------------------------------------------------------
* The following license statement only applies to this file (dir_list.c). * The following license statement only applies to this file (dir_list.c).
@ -116,10 +116,21 @@ static int dir_list_read(const char *dir,
char file_path[PATH_MAX_LENGTH]; char file_path[PATH_MAX_LENGTH];
const char *name = retro_dirent_get_name(entry); const char *name = retro_dirent_get_name(entry);
if (!include_hidden && *name == '.') if (name[0] == '.')
continue; {
if (!strcmp(name, ".") || !strcmp(name, "..")) /* Do not include hidden files and directories */
continue; if (!include_hidden)
continue;
/* char-wise comparisons to avoid string comparison */
/* Do not include current dir */
if (name[1] == '\0')
continue;
/* Do not include parent dir */
if (name[1] == '.' && name[2] == '\0')
continue;
}
file_path[0] = '\0'; file_path[0] = '\0';
fill_pathname_join(file_path, dir, name, sizeof(file_path)); fill_pathname_join(file_path, dir, name, sizeof(file_path));

View File

@ -1,4 +1,4 @@
/* Copyright (C) 2010-2018 The RetroArch team /* Copyright (C) 2010-2020 The RetroArch team
* *
* --------------------------------------------------------------------------------------- * ---------------------------------------------------------------------------------------
* The following license statement only applies to this file (string_list.c). * The following license statement only applies to this file (string_list.c).
@ -47,7 +47,10 @@ void string_list_free(struct string_list *list)
{ {
if (list->elems[i].data) if (list->elems[i].data)
free(list->elems[i].data); free(list->elems[i].data);
list->elems[i].data = NULL; if (list->elems[i].userdata)
free(list->elems[i].userdata);
list->elems[i].data = NULL;
list->elems[i].userdata = NULL;
} }
free(list->elems); free(list->elems);
@ -92,11 +95,15 @@ static bool string_list_capacity(struct string_list *list, size_t cap)
struct string_list *string_list_new(void) struct string_list *string_list_new(void)
{ {
struct string_list *list = (struct string_list*) struct string_list *list = (struct string_list*)
calloc(1, sizeof(*list)); malloc(sizeof(*list));
if (!list) if (!list)
return NULL; return NULL;
list->elems = NULL;
list->size = 0;
list->cap = 0;
if (!string_list_capacity(list, 32)) if (!string_list_capacity(list, 32))
{ {
string_list_free(list); string_list_free(list);
@ -256,6 +263,59 @@ error:
return NULL; return NULL;
} }
/**
* string_separate:
* @str : string to turn into a string list
* @delim : delimiter character to use for separating the string.
*
* Creates a new string list based on string @str, delimited by @delim.
* Includes empty strings - i.e. two adjacent delimiters will resolve
* to a string list element of "".
*
* Returns: new string list if successful, otherwise NULL.
*/
struct string_list *string_separate(char *str, const char *delim)
{
char *token = NULL;
char **str_ptr = NULL;
struct string_list *list = NULL;
/* Sanity check */
if (!str || string_is_empty(delim))
goto error;
str_ptr = &str;
list = string_list_new();
if (!list)
goto error;
token = string_tokenize(str_ptr, delim);
while (token)
{
union string_list_elem_attr attr;
attr.i = 0;
if (!string_list_append(list, token, attr))
goto error;
free(token);
token = NULL;
token = string_tokenize(str_ptr, delim);
}
return list;
error:
if (token)
free(token);
if (list)
string_list_free(list);
return NULL;
}
/** /**
* string_list_find_elem: * string_list_find_elem:
* @list : pointer to string list * @list : pointer to string list
@ -320,19 +380,22 @@ struct string_list *string_list_clone(
const struct string_list *src) const struct string_list *src)
{ {
unsigned i; unsigned i;
struct string_list_elem *elems = NULL; struct string_list_elem
struct string_list *dest = (struct string_list*) *elems = NULL;
calloc(1, sizeof(struct string_list)); struct string_list
*dest = (struct string_list*)
malloc(sizeof(struct string_list));
if (!dest) if (!dest)
return NULL; return NULL;
dest->size = src->size; dest->elems = NULL;
dest->cap = src->cap; dest->size = src->size;
dest->cap = src->cap;
if (dest->cap < dest->size) if (dest->cap < dest->size)
dest->cap = dest->size; dest->cap = dest->size;
elems = (struct string_list_elem*) elems = (struct string_list_elem*)
calloc(dest->cap, sizeof(struct string_list_elem)); calloc(dest->cap, sizeof(struct string_list_elem));
if (!elems) if (!elems)

View File

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

View File

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

View File

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

View File

@ -1,4 +1,4 @@
/* Copyright (C) 2010-2018 The RetroArch team /* Copyright (C) 2010-2020 The RetroArch team
* *
* --------------------------------------------------------------------------------------- * ---------------------------------------------------------------------------------------
* The following license statement only applies to this file (rthreads.c). * The following license statement only applies to this file (rthreads.c).
@ -191,12 +191,12 @@ sthread_t *sthread_create_with_priority(void (*thread_func)(void*), void *userda
#endif #endif
bool thread_created = false; bool thread_created = false;
struct thread_data *data = NULL; struct thread_data *data = NULL;
sthread_t *thread = (sthread_t*)calloc(1, sizeof(*thread)); sthread_t *thread = (sthread_t*)malloc(sizeof(*thread));
if (!thread) if (!thread)
return NULL; return NULL;
data = (struct thread_data*)calloc(1, sizeof(*data)); data = (struct thread_data*)malloc(sizeof(*data));
if (!data) if (!data)
goto error; goto error;
@ -204,14 +204,17 @@ sthread_t *sthread_create_with_priority(void (*thread_func)(void*), void *userda
data->userdata = userdata; data->userdata = userdata;
#ifdef USE_WIN32_THREADS #ifdef USE_WIN32_THREADS
thread->thread = CreateThread(NULL, 0, thread_wrap, data, 0, &thread->id); thread->id = 0;
thread->thread = CreateThread(NULL, 0, thread_wrap,
data, 0, &thread->id);
thread_created = !!thread->thread; thread_created = !!thread->thread;
#else #else
thread->id = 0;
#ifdef HAVE_THREAD_ATTR #ifdef HAVE_THREAD_ATTR
pthread_attr_init(&thread_attr); pthread_attr_init(&thread_attr);
if ( (thread_priority >= 1) && (thread_priority <= 100) ) if ((thread_priority >= 1) && (thread_priority <= 100))
{ {
struct sched_param sp; struct sched_param sp;
memset(&sp, 0, sizeof(struct sched_param)); memset(&sp, 0, sizeof(struct sched_param));
@ -268,7 +271,9 @@ int sthread_detach(sthread_t *thread)
free(thread); free(thread);
return 0; return 0;
#else #else
return pthread_detach(thread->id); int ret = pthread_detach(thread->id);
free(thread);
return ret;
#endif #endif
} }
@ -330,11 +335,12 @@ slock_t *slock_new(void)
if (!lock) if (!lock)
return NULL; return NULL;
#ifdef USE_WIN32_THREADS #ifdef USE_WIN32_THREADS
InitializeCriticalSection(&lock->lock); InitializeCriticalSection(&lock->lock);
mutex_created = true; mutex_created = true;
#else #else
mutex_created = (pthread_mutex_init(&lock->lock, NULL) == 0); mutex_created = (pthread_mutex_init(&lock->lock, NULL) == 0);
#endif #endif
if (!mutex_created) if (!mutex_created)
@ -385,6 +391,24 @@ void slock_lock(slock_t *lock)
#endif #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)
{
if (!lock)
return false;
#ifdef USE_WIN32_THREADS
return TryEnterCriticalSection(&lock->lock);
#else
return pthread_mutex_trylock(&lock->lock)==0;
#endif
}
/** /**
* slock_unlock: * slock_unlock:
* @lock : pointer to mutex object * @lock : pointer to mutex object
@ -419,7 +443,6 @@ scond_t *scond_new(void)
return NULL; return NULL;
#ifdef USE_WIN32_THREADS #ifdef USE_WIN32_THREADS
/* This is very complex because recreating condition variable semantics /* This is very complex because recreating condition variable semantics
* with Win32 parts is not easy. * with Win32 parts is not easy.
* *
@ -445,9 +468,10 @@ scond_t *scond_new(void)
* *
* Note: We might could simplify this using vista+ condition variables, * Note: We might could simplify this using vista+ condition variables,
* but we wanted an XP compatible solution. */ * but we wanted an XP compatible solution. */
cond->event = CreateEvent(NULL, FALSE, FALSE, NULL); cond->event = CreateEvent(NULL, FALSE, FALSE, NULL);
if (!cond->event) goto error; if (!cond->event)
cond->hot_potato = CreateEvent(NULL, FALSE, FALSE, NULL); goto error;
cond->hot_potato = CreateEvent(NULL, FALSE, FALSE, NULL);
if (!cond->hot_potato) if (!cond->hot_potato)
{ {
CloseHandle(cond->event); CloseHandle(cond->event);
@ -455,9 +479,6 @@ scond_t *scond_new(void)
} }
InitializeCriticalSection(&cond->cs); InitializeCriticalSection(&cond->cs);
cond->waiters = cond->wakens = 0;
cond->head = NULL;
#else #else
if (pthread_cond_init(&cond->cond, NULL) != 0) if (pthread_cond_init(&cond->cond, NULL) != 0)
goto error; goto error;
@ -851,7 +872,7 @@ bool scond_wait_timeout(scond_t *cond, slock_t *lock, int64_t timeout_us)
now.tv_sec = s; now.tv_sec = s;
now.tv_nsec = n; now.tv_nsec = n;
#elif defined(PS2) #elif defined(PS2)
int tickms = clock(); int tickms = ps2_clock();
now.tv_sec = tickms/1000; now.tv_sec = tickms/1000;
now.tv_nsec = tickms * 1000; now.tv_nsec = tickms * 1000;
#elif defined(__mips__) || defined(VITA) || defined(_3DS) #elif defined(__mips__) || defined(VITA) || defined(_3DS)
@ -921,3 +942,19 @@ bool sthread_tls_set(sthread_tls_t *tls, const void *data)
#endif #endif
} }
#endif #endif
uintptr_t sthread_get_thread_id(sthread_t *thread)
{
if (!thread)
return 0;
return (uintptr_t)thread->id;
}
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-2018 The RetroArch team /* Copyright (C) 2010-2020 The RetroArch team
* *
* --------------------------------------------------------------------------------------- * ---------------------------------------------------------------------------------------
* The following license statement only applies to this file (xenon_sdl_threads.c). * The following license statement only applies to this file (xenon_sdl_threads.c).

View File

@ -1,4 +1,4 @@
/* Copyright (C) 2010-2018 The RetroArch team /* Copyright (C) 2010-2020 The RetroArch team
* *
* --------------------------------------------------------------------------------------- * ---------------------------------------------------------------------------------------
* The following license statement only applies to this file (file_stream.c). * The following license statement only applies to this file (file_stream.c).
@ -111,7 +111,11 @@ bool filestream_exists(const char *path)
if (!dummy) if (!dummy)
return false; return false;
filestream_close(dummy); if (filestream_close(dummy) != 0)
if (dummy)
free(dummy);
dummy = NULL;
return true; return true;
} }
@ -119,7 +123,7 @@ int64_t filestream_get_size(RFILE *stream)
{ {
int64_t output; int64_t output;
if (filestream_size_cb != NULL) if (filestream_size_cb)
output = filestream_size_cb(stream->hfile); output = filestream_size_cb(stream->hfile);
else else
output = retro_vfs_file_size_impl((libretro_vfs_implementation_file*)stream->hfile); output = retro_vfs_file_size_impl((libretro_vfs_implementation_file*)stream->hfile);
@ -134,7 +138,7 @@ int64_t filestream_truncate(RFILE *stream, int64_t length)
{ {
int64_t output; int64_t output;
if (filestream_truncate_cb != NULL) if (filestream_truncate_cb)
output = filestream_truncate_cb(stream->hfile, length); output = filestream_truncate_cb(stream->hfile, length);
else else
output = retro_vfs_file_truncate_impl((libretro_vfs_implementation_file*)stream->hfile, length); output = retro_vfs_file_truncate_impl((libretro_vfs_implementation_file*)stream->hfile, length);
@ -154,12 +158,12 @@ int64_t filestream_truncate(RFILE *stream, int64_t length)
* Opens a file for reading or writing, depending on the requested mode. * Opens a file for reading or writing, depending on the requested mode.
* Returns a pointer to an RFILE if opened successfully, otherwise NULL. * Returns a pointer to an RFILE if opened successfully, otherwise NULL.
**/ **/
RFILE *filestream_open(const char *path, unsigned mode, unsigned hints) RFILE* filestream_open(const char *path, unsigned mode, unsigned hints)
{ {
struct retro_vfs_file_handle *fp = NULL; struct retro_vfs_file_handle *fp = NULL;
RFILE* output = NULL; RFILE* output = NULL;
if (filestream_open_cb != NULL) if (filestream_open_cb)
fp = (struct retro_vfs_file_handle*) fp = (struct retro_vfs_file_handle*)
filestream_open_cb(path, mode, hints); filestream_open_cb(path, mode, hints);
else else
@ -176,7 +180,7 @@ RFILE *filestream_open(const char *path, unsigned mode, unsigned hints)
return output; return output;
} }
char *filestream_gets(RFILE *stream, char *s, size_t len) char* filestream_gets(RFILE *stream, char *s, size_t len)
{ {
int c = 0; int c = 0;
char *p = s; char *p = s;
@ -203,9 +207,7 @@ char *filestream_gets(RFILE *stream, char *s, size_t len)
int filestream_getc(RFILE *stream) int filestream_getc(RFILE *stream)
{ {
char c = 0; char c = 0;
if (!stream) if (stream && filestream_read(stream, &c, 1) == 1)
return EOF;
if (filestream_read(stream, &c, 1) == 1)
return (int)(unsigned char)c; return (int)(unsigned char)c;
return EOF; return EOF;
} }
@ -215,7 +217,6 @@ int filestream_scanf(RFILE *stream, const char* format, ...)
char buf[4096]; char buf[4096];
char subfmt[64]; char subfmt[64];
va_list args; va_list args;
const char * bufiter = buf; const char * bufiter = buf;
int64_t startpos = filestream_tell(stream); int64_t startpos = filestream_tell(stream);
int ret = 0; int ret = 0;
@ -233,7 +234,6 @@ int filestream_scanf(RFILE *stream, const char* format, ...)
if (*format == '%') if (*format == '%')
{ {
int sublen; int sublen;
char* subfmtiter = subfmt; char* subfmtiter = subfmt;
bool asterisk = false; bool asterisk = false;
@ -243,19 +243,25 @@ int filestream_scanf(RFILE *stream, const char* format, ...)
if (*format == '*') if (*format == '*')
{ {
asterisk = true; asterisk = true;
*subfmtiter++ = *format++; *subfmtiter++ = *format++;
} }
while (isdigit(*format)) *subfmtiter++ = *format++; /* width */ while (isdigit(*format))
*subfmtiter++ = *format++; /* width */
/* length */ /* length */
if (*format == 'h' || *format == 'l') if (*format == 'h' || *format == 'l')
{ {
if (format[1] == format[0]) *subfmtiter++ = *format++; if (format[1] == format[0])
*subfmtiter++ = *format++; *subfmtiter++ = *format++;
*subfmtiter++ = *format++;
} }
else if (*format == 'j' || *format == 'z' || *format == 't' || *format == 'L') else if (
*format == 'j' ||
*format == 'z' ||
*format == 't' ||
*format == 'L')
{ {
*subfmtiter++ = *format++; *subfmtiter++ = *format++;
} }
@ -263,23 +269,31 @@ int filestream_scanf(RFILE *stream, const char* format, ...)
/* specifier - always a single character (except ]) */ /* specifier - always a single character (except ]) */
if (*format == '[') if (*format == '[')
{ {
while (*format != ']') *subfmtiter++ = *format++; while (*format != ']')
*subfmtiter++ = *format++; *subfmtiter++ = *format++;
*subfmtiter++ = *format++;
} }
else *subfmtiter++ = *format++; else
*subfmtiter++ = *format++;
*subfmtiter++ = '%'; *subfmtiter++ = '%';
*subfmtiter++ = 'n'; *subfmtiter++ = 'n';
*subfmtiter++ = '\0'; *subfmtiter++ = '\0';
if (sizeof(void*) != sizeof(long*)) abort(); /* all pointers must have the same size */ if (sizeof(void*) != sizeof(long*)) abort(); /* all pointers must have the same size */
if (asterisk) if (asterisk)
{ {
if (sscanf(bufiter, subfmt, &sublen) != 0) break; int v = sscanf(bufiter, subfmt, &sublen);
if (v == EOF)
return EOF;
if (v != 0) break;
} }
else else
{ {
if (sscanf(bufiter, subfmt, va_arg(args, void*), &sublen) != 1) break; int v = sscanf(bufiter, subfmt, va_arg(args, void*), &sublen);
if (v == EOF)
return EOF;
if (v != 1) break;
} }
ret++; ret++;
@ -309,7 +323,7 @@ int64_t filestream_seek(RFILE *stream, int64_t offset, int seek_position)
{ {
int64_t output; int64_t output;
if (filestream_seek_cb != NULL) if (filestream_seek_cb)
output = filestream_seek_cb(stream->hfile, offset, seek_position); output = filestream_seek_cb(stream->hfile, offset, seek_position);
else else
output = retro_vfs_file_seek_impl((libretro_vfs_implementation_file*)stream->hfile, offset, seek_position); output = retro_vfs_file_seek_impl((libretro_vfs_implementation_file*)stream->hfile, offset, seek_position);
@ -330,7 +344,7 @@ int64_t filestream_tell(RFILE *stream)
{ {
int64_t output; int64_t output;
if (filestream_size_cb != NULL) if (filestream_size_cb)
output = filestream_tell_cb(stream->hfile); output = filestream_tell_cb(stream->hfile);
else else
output = retro_vfs_file_tell_impl((libretro_vfs_implementation_file*)stream->hfile); output = retro_vfs_file_tell_impl((libretro_vfs_implementation_file*)stream->hfile);
@ -354,7 +368,7 @@ int64_t filestream_read(RFILE *stream, void *s, int64_t len)
{ {
int64_t output; int64_t output;
if (filestream_read_cb != NULL) if (filestream_read_cb)
output = filestream_read_cb(stream->hfile, s, len); output = filestream_read_cb(stream->hfile, s, len);
else else
output = retro_vfs_file_read_impl( output = retro_vfs_file_read_impl(
@ -372,7 +386,7 @@ int filestream_flush(RFILE *stream)
{ {
int output; int output;
if (filestream_flush_cb != NULL) if (filestream_flush_cb)
output = filestream_flush_cb(stream->hfile); output = filestream_flush_cb(stream->hfile);
else else
output = retro_vfs_file_flush_impl((libretro_vfs_implementation_file*)stream->hfile); output = retro_vfs_file_flush_impl((libretro_vfs_implementation_file*)stream->hfile);
@ -385,7 +399,7 @@ int filestream_flush(RFILE *stream)
int filestream_delete(const char *path) int filestream_delete(const char *path)
{ {
if (filestream_remove_cb != NULL) if (filestream_remove_cb)
return filestream_remove_cb(path); return filestream_remove_cb(path);
return retro_vfs_file_remove_impl(path); return retro_vfs_file_remove_impl(path);
@ -393,15 +407,15 @@ int filestream_delete(const char *path)
int filestream_rename(const char *old_path, const char *new_path) int filestream_rename(const char *old_path, const char *new_path)
{ {
if (filestream_rename_cb != NULL) if (filestream_rename_cb)
return filestream_rename_cb(old_path, new_path); return filestream_rename_cb(old_path, new_path);
return retro_vfs_file_rename_impl(old_path, new_path); return retro_vfs_file_rename_impl(old_path, new_path);
} }
const char *filestream_get_path(RFILE *stream) const char* filestream_get_path(RFILE *stream)
{ {
if (filestream_get_path_cb != NULL) if (filestream_get_path_cb)
return filestream_get_path_cb(stream->hfile); return filestream_get_path_cb(stream->hfile);
return retro_vfs_file_get_path_impl((libretro_vfs_implementation_file*)stream->hfile); return retro_vfs_file_get_path_impl((libretro_vfs_implementation_file*)stream->hfile);
@ -411,7 +425,7 @@ int64_t filestream_write(RFILE *stream, const void *s, int64_t len)
{ {
int64_t output; int64_t output;
if (filestream_write_cb != NULL) if (filestream_write_cb)
output = filestream_write_cb(stream->hfile, s, len); output = filestream_write_cb(stream->hfile, s, len);
else else
output = retro_vfs_file_write_impl((libretro_vfs_implementation_file*)stream->hfile, s, len); output = retro_vfs_file_write_impl((libretro_vfs_implementation_file*)stream->hfile, s, len);
@ -433,7 +447,8 @@ int filestream_putc(RFILE *stream, int c)
int filestream_vprintf(RFILE *stream, const char* format, va_list args) int filestream_vprintf(RFILE *stream, const char* format, va_list args)
{ {
static char buffer[8 * 1024]; static char buffer[8 * 1024];
int64_t num_chars = vsprintf(buffer, format, args); int64_t num_chars = vsnprintf(buffer, sizeof(buffer),
format, args);
if (num_chars < 0) if (num_chars < 0)
return -1; return -1;
@ -465,7 +480,7 @@ int filestream_close(RFILE *stream)
int output; int output;
struct retro_vfs_file_handle* fp = stream->hfile; struct retro_vfs_file_handle* fp = stream->hfile;
if (filestream_close_cb != NULL) if (filestream_close_cb)
output = filestream_close_cb(fp); output = filestream_close_cb(fp);
else else
output = retro_vfs_file_close_impl((libretro_vfs_implementation_file*)fp); output = retro_vfs_file_close_impl((libretro_vfs_implementation_file*)fp);
@ -497,8 +512,8 @@ int64_t filestream_read_file(const char *path, void **buf, int64_t *len)
if (!file) if (!file)
{ {
fprintf(stderr, "Failed to open %s: %s\n", path, strerror(errno)); *buf = NULL;
goto error; return 0;
} }
content_buf_size = filestream_get_size(file); content_buf_size = filestream_get_size(file);
@ -515,12 +530,11 @@ int64_t filestream_read_file(const char *path, void **buf, int64_t *len)
ret = filestream_read(file, content_buf, (int64_t)content_buf_size); ret = filestream_read(file, content_buf, (int64_t)content_buf_size);
if (ret < 0) if (ret < 0)
{
fprintf(stderr, "Failed to read %s: %s\n", path, strerror(errno));
goto error; goto error;
}
filestream_close(file); if (filestream_close(file) != 0)
if (file)
free(file);
*buf = content_buf; *buf = content_buf;
@ -535,7 +549,8 @@ int64_t filestream_read_file(const char *path, void **buf, int64_t *len)
error: error:
if (file) if (file)
filestream_close(file); if (filestream_close(file) != 0)
free(file);
if (content_buf) if (content_buf)
free(content_buf); free(content_buf);
if (len) if (len)
@ -564,7 +579,9 @@ bool filestream_write_file(const char *path, const void *data, int64_t size)
return false; return false;
ret = filestream_write(file, data, size); ret = filestream_write(file, data, size);
filestream_close(file); if (filestream_close(file) != 0)
if (file)
free(file);
if (ret != size) if (ret != size)
return false; return false;
@ -572,13 +589,14 @@ bool filestream_write_file(const char *path, const void *data, int64_t size)
return true; return true;
} }
char *filestream_getline(RFILE *stream) /* Returned pointer must be freed by the caller. */
char* filestream_getline(RFILE *stream)
{ {
char* newline_tmp = NULL; char *newline_tmp = NULL;
size_t cur_size = 8; size_t cur_size = 8;
size_t idx = 0; size_t idx = 0;
int in = 0; int in = 0;
char* newline = (char*)malloc(9); char *newline = (char*)malloc(9);
if (!stream || !newline) if (!stream || !newline)
{ {

View File

@ -1,4 +1,4 @@
/* Copyright (C) 2010-2018 The RetroArch team /* Copyright (C) 2010-2020 The RetroArch team
* *
* --------------------------------------------------------------------------------------- * ---------------------------------------------------------------------------------------
* The following license statement only applies to this file (file_stream_transforms.c). * The following license statement only applies to this file (file_stream_transforms.c).
@ -99,7 +99,7 @@ int64_t rfseek(RFILE* stream, int64_t offset, int origin)
int64_t rfread(void* buffer, int64_t rfread(void* buffer,
size_t elem_size, size_t elem_count, RFILE* stream) size_t elem_size, size_t elem_count, RFILE* stream)
{ {
return filestream_read(stream, buffer, elem_size * elem_count); return (filestream_read(stream, buffer, elem_size * elem_count) / elem_size);
} }
char *rfgets(char *buffer, int maxCount, RFILE* stream) char *rfgets(char *buffer, int maxCount, RFILE* stream)

View File

@ -1,4 +1,4 @@
/* Copyright (C) 2010-2018 The RetroArch team /* Copyright (C) 2010-2020 The RetroArch team
* *
* --------------------------------------------------------------------------------------- * ---------------------------------------------------------------------------------------
* The following license statement only applies to this file (stdstring.c). * The following license statement only applies to this file (stdstring.c).
@ -26,6 +26,18 @@
#include <string/stdstring.h> #include <string/stdstring.h>
#include <encodings/utf.h> #include <encodings/utf.h>
char *string_init(const char *src)
{
return src ? strdup(src) : NULL;
}
void string_set(char **string, const char *src)
{
free(*string);
*string = src ? strdup(src) : NULL;
}
char *string_to_upper(char *s) char *string_to_upper(char *s)
{ {
char *cs = (char *)s; char *cs = (char *)s;
@ -107,18 +119,18 @@ char *string_replace_substring(const char *in,
/* Remove leading whitespaces */ /* Remove leading whitespaces */
char *string_trim_whitespace_left(char *const s) char *string_trim_whitespace_left(char *const s)
{ {
if(s && *s) if (s && *s)
{ {
size_t len = strlen(s); size_t len = strlen(s);
char *current = s; char *current = s;
while(*current && isspace((unsigned char)*current)) while (*current && isspace((unsigned char)*current))
{ {
++current; ++current;
--len; --len;
} }
if(s != current) if (s != current)
memmove(s, current, len + 1); memmove(s, current, len + 1);
} }
@ -128,12 +140,12 @@ char *string_trim_whitespace_left(char *const s)
/* Remove trailing whitespaces */ /* Remove trailing whitespaces */
char *string_trim_whitespace_right(char *const s) char *string_trim_whitespace_right(char *const s)
{ {
if(s && *s) if (s && *s)
{ {
size_t len = strlen(s); size_t len = strlen(s);
char *current = s + len - 1; char *current = s + len - 1;
while(current != s && isspace((unsigned char)*current)) while (current != s && isspace((unsigned char)*current))
{ {
--current; --current;
--len; --len;
@ -190,7 +202,7 @@ char *word_wrap(char* buffer, const char *string, int line_width, bool unicode,
buffer[i] = string[i]; buffer[i] = string[i];
char_len--; char_len--;
i++; i++;
} while(char_len); } while (char_len);
/* check for newlines embedded in the original input /* check for newlines embedded in the original input
* and reset the index */ * and reset the index */
@ -237,3 +249,148 @@ char *word_wrap(char* buffer, const char *string, int line_width, bool unicode,
return buffer; return buffer;
} }
/* 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
* last found token
* > Tokens *include* empty strings
* Usage example:
* char *str = "1,2,3,4,5,6,7,,,10,";
* char **str_ptr = &str;
* char *token = NULL;
* while ((token = string_tokenize(str_ptr, ",")))
* {
* printf("%s\n", token);
* 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# */
char *str_ptr = NULL;
char *delim_ptr = NULL;
char *token = NULL;
size_t token_len = 0;
/* Sanity checks */
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)
return NULL;
/* Search for delimiter */
delim_ptr = strstr(str_ptr, delim);
if (delim_ptr)
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)
return NULL;
/* Copy token */
strlcpy(token, str_ptr, (token_len + 1) * sizeof(char));
token[token_len] = '\0';
/* Update input string pointer */
*str = delim_ptr ? delim_ptr + strlen(delim) : NULL;
return token;
}
/* 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;
while (*read_ptr != '\0')
{
*write_ptr = *read_ptr++;
write_ptr += (*write_ptr != c) ? 1 : 0;
}
*write_ptr = '\0';
}
/* 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 */
unsigned string_to_unsigned(const char *str)
{
const char *ptr = NULL;
if (string_is_empty(str))
return 0;
for (ptr = str; *ptr != '\0'; ptr++)
{
if (!isdigit(*ptr))
return 0;
}
return (unsigned)strtoul(str, NULL, 10);
}
/* Converts hexadecimal string to unsigned integer.
* Handles optional leading '0x'.
* Returns 0 if string is invalid */
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')))
hex_str = str + 2;
if (string_is_empty(hex_str))
return 0;
/* Check for valid characters */
for (ptr = hex_str; *ptr != '\0'; ptr++)
{
if (!isxdigit(*ptr))
return 0;
}
return (unsigned)strtoul(hex_str, NULL, 16);
}

View File

@ -1,4 +1,4 @@
/* Copyright (C) 2010-2019 The RetroArch team /* Copyright (C) 2010-2020 The RetroArch team
* *
* --------------------------------------------------------------------------------------- * ---------------------------------------------------------------------------------------
* The following license statement only applies to this file (vfs_implementation.c). * The following license statement only applies to this file (vfs_implementation.c).
@ -51,10 +51,6 @@
# if defined(PSP) # if defined(PSP)
# include <pspiofilemgr.h> # include <pspiofilemgr.h>
# endif # endif
# if defined(PS2)
# include <fileXio_rpc.h>
# include <fileXio_cdvd.h>
# endif
# include <sys/types.h> # include <sys/types.h>
# include <sys/stat.h> # include <sys/stat.h>
# if !defined(VITA) # if !defined(VITA)
@ -68,7 +64,7 @@
# endif # endif
#endif #endif
#ifdef __CELLOS_LV2__ #if defined (__CELLOS_LV2__) && !defined(__PSL1GHT__)
#include <cell/cell_fs.h> #include <cell/cell_fs.h>
#define O_RDONLY CELL_FS_O_RDONLY #define O_RDONLY CELL_FS_O_RDONLY
#define O_WRONLY CELL_FS_O_WRONLY #define O_WRONLY CELL_FS_O_WRONLY
@ -93,16 +89,13 @@
# if defined(PSP) # if defined(PSP)
# include <pspiofilemgr.h> # include <pspiofilemgr.h>
# endif # endif
# if defined(PS2)
# include <fileXio_rpc.h>
# endif
# include <sys/types.h> # include <sys/types.h>
# include <sys/stat.h> # include <sys/stat.h>
# include <dirent.h> # include <dirent.h>
# include <unistd.h> # include <unistd.h>
#endif #endif
#if (defined(__CELLOS_LV2__) && !defined(__PSL1GHT__)) || defined(__QNX__) || defined(PSP) || defined(PS2) #if (defined(__CELLOS_LV2__) && !defined(__PSL1GHT__)) || defined(__QNX__) || defined(PSP)
#include <unistd.h> /* stat() is defined here */ #include <unistd.h> /* stat() is defined here */
#endif #endif
@ -146,12 +139,7 @@
#include <pspkernel.h> #include <pspkernel.h>
#endif #endif
#if defined(PS2) #if defined(__CELLOS_LV2__) && !defined(__PSL1GHT__)
#include <fileXio_rpc.h>
#include <fileXio.h>
#endif
#if defined(__CELLOS_LV2__)
#include <cell/cell_fs.h> #include <cell/cell_fs.h>
#endif #endif
@ -172,7 +160,7 @@
#endif #endif
#if defined(_WIN32) && !defined(_XBOX) #if defined(_WIN32)
#if !defined(_MSC_VER) || (defined(_MSC_VER) && _MSC_VER >= 1400) #if !defined(_MSC_VER) || (defined(_MSC_VER) && _MSC_VER >= 1400)
#define ATLEAST_VC2005 #define ATLEAST_VC2005
#endif #endif
@ -189,9 +177,17 @@
#include <vfs/vfs_implementation_cdrom.h> #include <vfs/vfs_implementation_cdrom.h>
#endif #endif
#if (defined(_POSIX_C_SOURCE) && (_POSIX_C_SOURCE - 0) >= 200112) || (defined(__POSIX_VISIBLE) && __POSIX_VISIBLE >= 200112) || (defined(_POSIX_VERSION) && _POSIX_VERSION >= 200112) || __USE_LARGEFILE
#ifndef HAVE_64BIT_OFFSETS
#define HAVE_64BIT_OFFSETS
#endif
#endif
#define RFILE_HINT_UNBUFFERED (1 << 8) #define RFILE_HINT_UNBUFFERED (1 << 8)
int64_t retro_vfs_file_seek_internal(libretro_vfs_implementation_file *stream, int64_t offset, int whence) int64_t retro_vfs_file_seek_internal(
libretro_vfs_implementation_file *stream,
int64_t offset, int whence)
{ {
if (!stream) if (!stream)
return -1; return -1;
@ -202,19 +198,9 @@ int64_t retro_vfs_file_seek_internal(libretro_vfs_implementation_file *stream, i
if (stream->scheme == VFS_SCHEME_CDROM) if (stream->scheme == VFS_SCHEME_CDROM)
return retro_vfs_file_seek_cdrom(stream, offset, whence); return retro_vfs_file_seek_cdrom(stream, offset, whence);
#endif #endif
/* VC2005 and up have a special 64-bit fseek */
#ifdef ATLEAST_VC2005 #ifdef ATLEAST_VC2005
/* VC2005 and up have a special 64-bit fseek */
return _fseeki64(stream->fp, offset, whence); return _fseeki64(stream->fp, offset, whence);
#elif defined(__CELLOS_LV2__) || defined(_MSC_VER) && _MSC_VER <= 1310
return fseek(stream->fp, (long)offset, whence);
#elif defined(PS2)
{
int64_t ret = fileXioLseek(fileno(stream->fp), (off_t)offset, whence);
/* fileXioLseek could return positive numbers */
if (ret > 0)
return 0;
return ret;
}
#elif defined(ORBIS) #elif defined(ORBIS)
{ {
int ret = orbisLseek(stream->fd, offset, whence); int ret = orbisLseek(stream->fd, offset, whence);
@ -222,8 +208,10 @@ int64_t retro_vfs_file_seek_internal(libretro_vfs_implementation_file *stream, i
return -1; return -1;
return 0; return 0;
} }
#else #elif defined(HAVE_64BIT_OFFSETS)
return fseeko(stream->fp, (off_t)offset, whence); return fseeko(stream->fp, (off_t)offset, whence);
#else
return fseek(stream->fp, (long)offset, whence);
#endif #endif
} }
#ifdef HAVE_MMAP #ifdef HAVE_MMAP
@ -282,47 +270,72 @@ int64_t retro_vfs_file_seek_internal(libretro_vfs_implementation_file *stream, i
libretro_vfs_implementation_file *retro_vfs_file_open_impl( libretro_vfs_implementation_file *retro_vfs_file_open_impl(
const char *path, unsigned mode, unsigned hints) const char *path, unsigned mode, unsigned hints)
{ {
int flags = 0; #if defined(VFS_FRONTEND) || defined(HAVE_CDROM)
const char *mode_str = NULL;
int path_len = (int)strlen(path); int path_len = (int)strlen(path);
libretro_vfs_implementation_file *stream = (libretro_vfs_implementation_file*) #endif
calloc(1, sizeof(*stream));
#ifdef VFS_FRONTEND #ifdef VFS_FRONTEND
const char *dumb_prefix = "vfsonly://"; const char *dumb_prefix = "vfsonly://";
size_t dumb_prefix_siz = strlen(dumb_prefix); size_t dumb_prefix_siz = STRLEN_CONST("vfsonly://");
int dumb_prefix_len = (int)dumb_prefix_siz; int dumb_prefix_len = (int)dumb_prefix_siz;
if (path_len >= dumb_prefix_len)
{
if (!memcmp(path, dumb_prefix, dumb_prefix_len))
path += dumb_prefix_siz;
}
#endif #endif
#ifdef HAVE_CDROM #ifdef HAVE_CDROM
{ const char *cdrom_prefix = "cdrom://";
const char *cdrom_prefix = "cdrom://"; size_t cdrom_prefix_siz = STRLEN_CONST("cdrom://");
size_t cdrom_prefix_siz = strlen(cdrom_prefix); int cdrom_prefix_len = (int)cdrom_prefix_siz;
int cdrom_prefix_len = (int)cdrom_prefix_siz;
if (path_len > cdrom_prefix_len)
{
if (!memcmp(path, cdrom_prefix, cdrom_prefix_len))
{
path += cdrom_prefix_siz;
stream->scheme = VFS_SCHEME_CDROM;
}
}
}
#endif #endif
int flags = 0;
const char *mode_str = NULL;
libretro_vfs_implementation_file *stream =
(libretro_vfs_implementation_file*)
malloc(sizeof(*stream));
if (!stream) if (!stream)
return NULL; return NULL;
(void)flags; stream->fd = 0;
stream->hints = hints;
stream->size = 0;
stream->buf = NULL;
stream->fp = NULL;
#ifdef _WIN32
stream->fh = 0;
#endif
stream->orig_path = NULL;
stream->mappos = 0;
stream->mapsize = 0;
stream->mapped = NULL;
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;
#endif
#ifdef HAVE_CDROM
stream->cdrom.cue_buf = NULL;
stream->cdrom.cue_len = 0;
stream->cdrom.byte_pos = 0;
stream->cdrom.drive = 0;
stream->cdrom.cur_min = 0;
stream->cdrom.cur_sec = 0;
stream->cdrom.cur_frame = 0;
stream->cdrom.cur_track = 0;
stream->cdrom.cur_lba = 0;
stream->cdrom.last_frame_lba = 0;
stream->cdrom.last_frame[0] = '\0';
stream->cdrom.last_frame_valid = false;
if (path_len > cdrom_prefix_len)
{
if (!memcmp(path, cdrom_prefix, cdrom_prefix_len))
{
path += cdrom_prefix_siz;
stream->scheme = VFS_SCHEME_CDROM;
}
}
#endif
stream->hints = hints;
stream->orig_path = strdup(path); stream->orig_path = strdup(path);
#ifdef HAVE_MMAP #ifdef HAVE_MMAP
@ -348,9 +361,7 @@ libretro_vfs_implementation_file *retro_vfs_file_open_impl(
flags = O_WRONLY | O_CREAT | O_TRUNC; flags = O_WRONLY | O_CREAT | O_TRUNC;
#if !defined(ORBIS) #if !defined(ORBIS)
#if defined(PS2) #if !defined(_WIN32)
flags |= FIO_S_IRUSR | FIO_S_IWUSR;
#elif !defined(_WIN32)
flags |= S_IRUSR | S_IWUSR; flags |= S_IRUSR | S_IWUSR;
#else #else
flags |= O_BINARY; flags |= O_BINARY;
@ -362,9 +373,7 @@ libretro_vfs_implementation_file *retro_vfs_file_open_impl(
mode_str = "w+b"; mode_str = "w+b";
flags = O_RDWR | O_CREAT | O_TRUNC; flags = O_RDWR | O_CREAT | O_TRUNC;
#if !defined(ORBIS) #if !defined(ORBIS)
#if defined(PS2) #if !defined(_WIN32)
flags |= FIO_S_IRUSR | FIO_S_IWUSR;
#elif !defined(_WIN32)
flags |= S_IRUSR | S_IWUSR; flags |= S_IRUSR | S_IWUSR;
#else #else
flags |= O_BINARY; flags |= O_BINARY;
@ -378,9 +387,7 @@ libretro_vfs_implementation_file *retro_vfs_file_open_impl(
flags = O_RDWR; flags = O_RDWR;
#if !defined(ORBIS) #if !defined(ORBIS)
#if defined(PS2) #if !defined(_WIN32)
flags |= FIO_S_IRUSR | FIO_S_IWUSR;
#elif !defined(_WIN32)
flags |= S_IRUSR | S_IWUSR; flags |= S_IRUSR | S_IWUSR;
#else #else
flags |= O_BINARY; flags |= O_BINARY;
@ -401,7 +408,7 @@ libretro_vfs_implementation_file *retro_vfs_file_open_impl(
stream->fd = -1; stream->fd = -1;
goto error; goto error;
} }
stream->fd = fd; stream->fd = fd;
#else #else
FILE *fp; FILE *fp;
#ifdef HAVE_CDROM #ifdef HAVE_CDROM
@ -430,13 +437,16 @@ libretro_vfs_implementation_file *retro_vfs_file_open_impl(
* *
* https://www.freebsd.org/cgi/man.cgi?query=setvbuf&apropos=0&sektion=0&manpath=FreeBSD+11.1-RELEASE&arch=default&format=html * https://www.freebsd.org/cgi/man.cgi?query=setvbuf&apropos=0&sektion=0&manpath=FreeBSD+11.1-RELEASE&arch=default&format=html
* *
* If the size argument is not zero but buf is NULL, a buffer of the given size will be allocated immediately, and * 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. * released on close. This is an extension to ANSI C.
* *
* Since C89 does not support specifying a null buffer with a non-zero size, we create and track our own buffer for it. * Since C89 does not support specifying a NULL buffer
* with a non-zero size, we create and track our own buffer for it.
*/ */
/* TODO: this is only useful for a few platforms, find which and add ifdef */ /* TODO: this is only useful for a few platforms,
#if !defined(PS2) && !defined(PSP) * find which and add ifdef */
#if !defined(PSP)
if (stream->scheme != VFS_SCHEME_CDROM) if (stream->scheme != VFS_SCHEME_CDROM)
{ {
stream->buf = (char*)calloc(1, 0x4000); stream->buf = (char*)calloc(1, 0x4000);
@ -535,9 +545,7 @@ int retro_vfs_file_close_impl(libretro_vfs_implementation_file *stream)
if ((stream->hints & RFILE_HINT_UNBUFFERED) == 0) if ((stream->hints & RFILE_HINT_UNBUFFERED) == 0)
{ {
if (stream->fp) if (stream->fp)
{
fclose(stream->fp); fclose(stream->fp);
}
} }
else else
{ {
@ -628,9 +636,11 @@ int64_t retro_vfs_file_tell_impl(libretro_vfs_implementation_file *stream)
return ret; return ret;
} }
#else #else
/* VC2005 and up have a special 64-bit ftell */
#ifdef ATLEAST_VC2005 #ifdef ATLEAST_VC2005
/* VC2005 and up have a special 64-bit ftell */
return _ftelli64(stream->fp); return _ftelli64(stream->fp);
#elif defined(HAVE_64BIT_OFFSETS)
return ftello(stream->fp);
#else #else
return ftell(stream->fp); return ftell(stream->fp);
#endif #endif
@ -639,7 +649,8 @@ int64_t retro_vfs_file_tell_impl(libretro_vfs_implementation_file *stream)
#ifdef HAVE_MMAP #ifdef HAVE_MMAP
/* Need to check stream->mapped because this function /* Need to check stream->mapped because this function
* is called in filestream_open() */ * is called in filestream_open() */
if (stream->mapped && stream->hints & RETRO_VFS_FILE_ACCESS_HINT_FREQUENT_ACCESS) if (stream->mapped && stream->hints &
RETRO_VFS_FILE_ACCESS_HINT_FREQUENT_ACCESS)
return stream->mappos; return stream->mappos;
#endif #endif
if (lseek(stream->fd, 0, SEEK_CUR) < 0) if (lseek(stream->fd, 0, SEEK_CUR) < 0)
@ -863,12 +874,12 @@ const char *retro_vfs_file_get_path_impl(
int retro_vfs_stat_impl(const char *path, int32_t *size) 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) #if defined(VITA) || defined(PSP)
/* Vita / PSP */ /* Vita / PSP */
SceIoStat buf; SceIoStat buf;
int stat_ret; int dir_ret;
bool is_dir = false;
bool is_character_special = false;
char *tmp = NULL; char *tmp = NULL;
size_t len = 0; size_t len = 0;
@ -880,75 +891,32 @@ int retro_vfs_stat_impl(const char *path, int32_t *size)
if (tmp[len-1] == '/') if (tmp[len-1] == '/')
tmp[len-1] = '\0'; tmp[len-1] = '\0';
stat_ret = sceIoGetstat(tmp, &buf); dir_ret = sceIoGetstat(tmp, &buf);
free(tmp); free(tmp);
if (stat_ret < 0) if (dir_ret < 0)
return 0; return 0;
if (size) if (size)
*size = (int32_t)buf.st_size; *size = (int32_t)buf.st_size;
is_dir = FIO_S_ISDIR(buf.st_mode);
return RETRO_VFS_STAT_IS_VALID | (is_dir ? RETRO_VFS_STAT_IS_DIRECTORY : 0) | (is_character_special ? RETRO_VFS_STAT_IS_CHARACTER_SPECIAL : 0);
is_dir = FIO_S_ISDIR(buf.st_mode);
#elif defined(ORBIS) #elif defined(ORBIS)
/* Orbis */ /* Orbis */
bool is_dir, is_character_special; int dir_ret = 0;
int dir_ret;
if (!path || !*path) if (!path || !*path)
return 0; return 0;
if (size) if (size)
*size = (int32_t)buf.st_size; *size = (int32_t)buf.st_size;
dir_ret = orbisDopen(path); dir_ret = orbisDopen(path);
is_dir = dir_ret > 0; is_dir = dir_ret > 0;
orbisDclose(dir_ret); orbisDclose(dir_ret);
is_character_special = S_ISCHR(buf.st_mode); is_character_special = S_ISCHR(buf.st_mode);
#elif defined(__CELLOS_LV2__) && !defined(__PSL1GHT__)
return RETRO_VFS_STAT_IS_VALID | (is_dir ? RETRO_VFS_STAT_IS_DIRECTORY : 0) | (is_character_special ? RETRO_VFS_STAT_IS_CHARACTER_SPECIAL : 0);
#elif defined(PS2)
/* PS2 */
iox_stat_t buf;
bool is_dir;
bool is_character_special = false;
char *tmp = NULL;
size_t len = 0;
if (!path || !*path)
return 0;
tmp = strdup(path);
len = strlen(tmp);
if (tmp[len-1] == '/')
tmp[len-1] = '\0';
fileXioGetStat(tmp, &buf);
free(tmp);
if (size)
*size = (int32_t)buf.size;
if (!buf.mode)
{
/* if fileXioGetStat fails */
int dir_ret = fileXioDopen(path);
is_dir = dir_ret > 0;
fileXioDclose(dir_ret);
}
else
is_dir = FIO_S_ISDIR(buf.mode);
return RETRO_VFS_STAT_IS_VALID | (is_dir ? RETRO_VFS_STAT_IS_DIRECTORY : 0) | (is_character_special ? RETRO_VFS_STAT_IS_CHARACTER_SPECIAL : 0);
#elif defined(__CELLOS_LV2__)
/* CellOS Lv2 */ /* CellOS Lv2 */
bool is_dir;
bool is_character_special = false;
CellFsStat buf; CellFsStat buf;
if (!path || !*path) if (!path || !*path)
@ -957,18 +925,14 @@ int retro_vfs_stat_impl(const char *path, int32_t *size)
return 0; return 0;
if (size) if (size)
*size = (int32_t)buf.st_size; *size = (int32_t)buf.st_size;
is_dir = ((buf.st_mode & S_IFMT) == S_IFDIR); is_dir = ((buf.st_mode & S_IFMT) == S_IFDIR);
return RETRO_VFS_STAT_IS_VALID | (is_dir ? RETRO_VFS_STAT_IS_DIRECTORY : 0) | (is_character_special ? RETRO_VFS_STAT_IS_CHARACTER_SPECIAL : 0);
#elif defined(_WIN32) #elif defined(_WIN32)
/* Windows */ /* Windows */
bool is_dir;
DWORD file_info; DWORD file_info;
struct _stat buf; struct _stat buf;
bool is_character_special = false;
#if defined(LEGACY_WIN32) #if defined(LEGACY_WIN32)
char *path_local = NULL; char *path_local = NULL;
#else #else
@ -979,8 +943,8 @@ int retro_vfs_stat_impl(const char *path, int32_t *size)
return 0; return 0;
#if defined(LEGACY_WIN32) #if defined(LEGACY_WIN32)
path_local = utf8_to_local_string_alloc(path); path_local = utf8_to_local_string_alloc(path);
file_info = GetFileAttributes(path_local); file_info = GetFileAttributes(path_local);
if (!string_is_empty(path_local)) if (!string_is_empty(path_local))
_stat(path_local, &buf); _stat(path_local, &buf);
@ -988,8 +952,8 @@ int retro_vfs_stat_impl(const char *path, int32_t *size)
if (path_local) if (path_local)
free(path_local); free(path_local);
#else #else
path_wide = utf8_to_utf16_string_alloc(path); path_wide = utf8_to_utf16_string_alloc(path);
file_info = GetFileAttributesW(path_wide); file_info = GetFileAttributesW(path_wide);
_wstat(path_wide, &buf); _wstat(path_wide, &buf);
@ -1004,12 +968,8 @@ int retro_vfs_stat_impl(const char *path, int32_t *size)
*size = (int32_t)buf.st_size; *size = (int32_t)buf.st_size;
is_dir = (file_info & FILE_ATTRIBUTE_DIRECTORY); is_dir = (file_info & FILE_ATTRIBUTE_DIRECTORY);
return RETRO_VFS_STAT_IS_VALID | (is_dir ? RETRO_VFS_STAT_IS_DIRECTORY : 0) | (is_character_special ? RETRO_VFS_STAT_IS_CHARACTER_SPECIAL : 0);
#else #else
/* Every other platform */ /* Every other platform */
bool is_dir, is_character_special;
struct stat buf; struct stat buf;
if (!path || !*path) if (!path || !*path)
@ -1022,9 +982,8 @@ int retro_vfs_stat_impl(const char *path, int32_t *size)
is_dir = S_ISDIR(buf.st_mode); is_dir = S_ISDIR(buf.st_mode);
is_character_special = S_ISCHR(buf.st_mode); is_character_special = S_ISCHR(buf.st_mode);
return RETRO_VFS_STAT_IS_VALID | (is_dir ? RETRO_VFS_STAT_IS_DIRECTORY : 0) | (is_character_special ? RETRO_VFS_STAT_IS_CHARACTER_SPECIAL : 0);
#endif #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);
} }
#if defined(VITA) #if defined(VITA)
@ -1039,23 +998,21 @@ int retro_vfs_mkdir_impl(const char *dir)
{ {
#if defined(_WIN32) #if defined(_WIN32)
#ifdef LEGACY_WIN32 #ifdef LEGACY_WIN32
int ret = _mkdir(dir); int ret = _mkdir(dir);
#else #else
wchar_t *dirW = utf8_to_utf16_string_alloc(dir); wchar_t *dir_w = utf8_to_utf16_string_alloc(dir);
int ret = -1; int ret = -1;
if (dirW) if (dir_w)
{ {
ret = _wmkdir(dirW); ret = _wmkdir(dir_w);
free(dirW); free(dir_w);
} }
#endif #endif
#elif defined(IOS) #elif defined(IOS)
int ret = mkdir(dir, 0755); int ret = mkdir(dir, 0755);
#elif defined(VITA) || defined(PSP) #elif defined(VITA) || defined(PSP)
int ret = sceIoMkdir(dir, 0777); int ret = sceIoMkdir(dir, 0777);
#elif defined(PS2)
int ret = fileXioMkdir(dir, 0777);
#elif defined(ORBIS) #elif defined(ORBIS)
int ret = orbisMkdir(dir, 0755); int ret = orbisMkdir(dir, 0755);
#elif defined(__QNX__) #elif defined(__QNX__)
@ -1088,10 +1045,7 @@ struct libretro_vfs_implementation_dir
#elif defined(VITA) || defined(PSP) #elif defined(VITA) || defined(PSP)
SceUID directory; SceUID directory;
SceIoDirent entry; SceIoDirent entry;
#elif defined(PS2) #elif defined(__CELLOS_LV2__) && !defined(__PSL1GHT__)
int directory;
iox_dirent_t entry;
#elif defined(__CELLOS_LV2__)
CellFsErrno error; CellFsErrno error;
int directory; int directory;
CellFsDirent entry; CellFsDirent entry;
@ -1108,20 +1062,22 @@ static bool dirent_check_error(libretro_vfs_implementation_dir *rdir)
{ {
#if defined(_WIN32) #if defined(_WIN32)
return (rdir->directory == INVALID_HANDLE_VALUE); return (rdir->directory == INVALID_HANDLE_VALUE);
#elif defined(VITA) || defined(PSP) || defined(PS2) || defined(ORBIS) #elif defined(VITA) || defined(PSP) || defined(ORBIS)
return (rdir->directory < 0); return (rdir->directory < 0);
#elif defined(__CELLOS_LV2__) #elif defined(__CELLOS_LV2__) && !defined(__PSL1GHT__)
return (rdir->error != CELL_FS_SUCCEEDED); return (rdir->error != CELL_FS_SUCCEEDED);
#else #else
return !(rdir->directory); return !(rdir->directory);
#endif #endif
} }
libretro_vfs_implementation_dir *retro_vfs_opendir_impl(const char *name, bool include_hidden) libretro_vfs_implementation_dir *retro_vfs_opendir_impl(
const char *name, bool include_hidden)
{ {
#if defined(_WIN32) #if defined(_WIN32)
unsigned path_len; unsigned path_len;
char path_buf[1024]; char path_buf[1024];
size_t copied = 0;
#if defined(LEGACY_WIN32) #if defined(LEGACY_WIN32)
char *path_local = NULL; char *path_local = NULL;
#else #else
@ -1145,21 +1101,24 @@ libretro_vfs_implementation_dir *retro_vfs_opendir_impl(const char *name, bool i
path_buf[0] = '\0'; path_buf[0] = '\0';
path_len = strlen(name); path_len = strlen(name);
copied = strlcpy(path_buf, name, sizeof(path_buf));
/* Non-NT platforms don't like extra slashes in the path */ /* Non-NT platforms don't like extra slashes in the path */
if (name[path_len - 1] == '\\') if (name[path_len - 1] != '\\')
snprintf(path_buf, sizeof(path_buf), "%s*", name); path_buf[copied++] = '\\';
else
snprintf(path_buf, sizeof(path_buf), "%s\\*", name); path_buf[copied] = '*';
path_buf[copied+1] = '\0';
#if defined(LEGACY_WIN32) #if defined(LEGACY_WIN32)
path_local = utf8_to_local_string_alloc(path_buf); path_local = utf8_to_local_string_alloc(path_buf);
rdir->directory = FindFirstFile(path_local, &rdir->entry); rdir->directory = FindFirstFile(path_local, &rdir->entry);
if (path_local) if (path_local)
free(path_local); free(path_local);
#else #else
path_wide = utf8_to_utf16_string_alloc(path_buf); path_wide = utf8_to_utf16_string_alloc(path_buf);
rdir->directory = FindFirstFileW(path_wide, &rdir->entry); rdir->directory = FindFirstFileW(path_wide, &rdir->entry);
if (path_wide) if (path_wide)
free(path_wide); free(path_wide);
@ -1167,12 +1126,10 @@ libretro_vfs_implementation_dir *retro_vfs_opendir_impl(const char *name, bool i
#elif defined(VITA) || defined(PSP) #elif defined(VITA) || defined(PSP)
rdir->directory = sceIoDopen(name); rdir->directory = sceIoDopen(name);
#elif defined(PS2)
rdir->directory = ps2fileXioDopen(name);
#elif defined(_3DS) #elif defined(_3DS)
rdir->directory = !string_is_empty(name) ? opendir(name) : NULL; rdir->directory = !string_is_empty(name) ? opendir(name) : NULL;
rdir->entry = NULL; rdir->entry = NULL;
#elif defined(__CELLOS_LV2__) #elif defined(__CELLOS_LV2__) && !defined(__PSL1GHT__)
rdir->error = cellFsOpendir(name, &rdir->directory); rdir->error = cellFsOpendir(name, &rdir->directory);
#elif defined(ORBIS) #elif defined(ORBIS)
rdir->directory = orbisDopen(name); rdir->directory = orbisDopen(name);
@ -1209,12 +1166,7 @@ bool retro_vfs_readdir_impl(libretro_vfs_implementation_dir *rdir)
return (rdir->directory != INVALID_HANDLE_VALUE); return (rdir->directory != INVALID_HANDLE_VALUE);
#elif defined(VITA) || defined(PSP) #elif defined(VITA) || defined(PSP)
return (sceIoDread(rdir->directory, &rdir->entry) > 0); return (sceIoDread(rdir->directory, &rdir->entry) > 0);
#elif defined(PS2) #elif defined(__CELLOS_LV2__) && !defined(__PSL1GHT__)
iox_dirent_t record;
int ret = ps2fileXioDread(rdir->directory, &record);
rdir->entry = record;
return ( ret > 0);
#elif defined(__CELLOS_LV2__)
uint64_t nread; uint64_t nread;
rdir->error = cellFsReaddir(rdir->directory, &rdir->entry, &nread); rdir->error = cellFsReaddir(rdir->directory, &rdir->entry, &nread);
return (nread != 0); return (nread != 0);
@ -1229,27 +1181,20 @@ const char *retro_vfs_dirent_get_name_impl(libretro_vfs_implementation_dir *rdir
{ {
#if defined(_WIN32) #if defined(_WIN32)
#if defined(LEGACY_WIN32) #if defined(LEGACY_WIN32)
char *name_local = local_to_utf8_string_alloc(rdir->entry.cFileName); char *name = local_to_utf8_string_alloc(rdir->entry.cFileName);
memset(rdir->entry.cFileName, 0, sizeof(rdir->entry.cFileName));
strlcpy(rdir->entry.cFileName, name_local, sizeof(rdir->entry.cFileName));
if (name_local)
free(name_local);
#else #else
char *name = utf16_to_utf8_string_alloc(rdir->entry.cFileName); char *name = utf16_to_utf8_string_alloc(rdir->entry.cFileName);
#endif
memset(rdir->entry.cFileName, 0, sizeof(rdir->entry.cFileName)); memset(rdir->entry.cFileName, 0, sizeof(rdir->entry.cFileName));
strlcpy((char*)rdir->entry.cFileName, name, sizeof(rdir->entry.cFileName)); strlcpy((char*)rdir->entry.cFileName, name, sizeof(rdir->entry.cFileName));
if (name) if (name)
free(name); free(name);
#endif
return (char*)rdir->entry.cFileName; return (char*)rdir->entry.cFileName;
#elif defined(VITA) || defined(PSP) || defined(__CELLOS_LV2__) || defined(ORBIS) #elif defined(VITA) || defined(PSP) || defined(__CELLOS_LV2__) && !defined(__PSL1GHT__) || defined(ORBIS)
return rdir->entry.d_name; return rdir->entry.d_name;
#elif defined(PS2)
return rdir->entry.name;
#else #else
if (!rdir || !rdir->entry)
return NULL;
return rdir->entry->d_name; return rdir->entry->d_name;
#endif #endif
} }
@ -1260,20 +1205,17 @@ bool retro_vfs_dirent_is_dir_impl(libretro_vfs_implementation_dir *rdir)
const WIN32_FIND_DATA *entry = (const WIN32_FIND_DATA*)&rdir->entry; const WIN32_FIND_DATA *entry = (const WIN32_FIND_DATA*)&rdir->entry;
return entry->dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY; return entry->dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY;
#elif defined(PSP) || defined(VITA) #elif defined(PSP) || defined(VITA)
const SceIoDirent *entry = (const SceIoDirent*)&rdir->entry; const SceIoDirent *entry = (const SceIoDirent*)&rdir->entry;
#if defined(PSP) #if defined(PSP)
return (entry->d_stat.st_attr & FIO_SO_IFDIR) == FIO_SO_IFDIR; return (entry->d_stat.st_attr & FIO_SO_IFDIR) == FIO_SO_IFDIR;
#elif defined(VITA) #elif defined(VITA)
return SCE_S_ISDIR(entry->d_stat.st_mode); return SCE_S_ISDIR(entry->d_stat.st_mode);
#endif #endif
#elif defined(PS2) #elif defined(__CELLOS_LV2__) && !defined(__PSL1GHT__)
const iox_dirent_t *entry = (const iox_dirent_t*)&rdir->entry; CellFsDirent *entry = (CellFsDirent*)&rdir->entry;
return FIO_S_ISDIR(entry->stat.mode);
#elif defined(__CELLOS_LV2__)
CellFsDirent *entry = (CellFsDirent*)&rdir->entry;
return (entry->d_type == CELL_FS_TYPE_DIRECTORY); return (entry->d_type == CELL_FS_TYPE_DIRECTORY);
#elif defined(ORBIS) #elif defined(ORBIS)
const struct dirent *entry = &rdir->entry; const struct dirent *entry = &rdir->entry;
if (entry->d_type == DT_DIR) if (entry->d_type == DT_DIR)
return true; return true;
if (!(entry->d_type == DT_UNKNOWN || entry->d_type == DT_LNK)) if (!(entry->d_type == DT_UNKNOWN || entry->d_type == DT_LNK))
@ -1308,9 +1250,7 @@ int retro_vfs_closedir_impl(libretro_vfs_implementation_dir *rdir)
FindClose(rdir->directory); FindClose(rdir->directory);
#elif defined(VITA) || defined(PSP) #elif defined(VITA) || defined(PSP)
sceIoDclose(rdir->directory); sceIoDclose(rdir->directory);
#elif defined(PS2) #elif defined(__CELLOS_LV2__) && !defined(__PSL1GHT__)
ps2fileXioDclose(rdir->directory);
#elif defined(__CELLOS_LV2__)
rdir->error = cellFsClosedir(rdir->directory); rdir->error = cellFsClosedir(rdir->directory);
#elif defined(ORBIS) #elif defined(ORBIS)
orbisDclose(rdir->directory); orbisDclose(rdir->directory);

View File

@ -1,4 +1,4 @@
/* Copyright (C) 2010-2019 The RetroArch team /* Copyright (C) 2010-2020 The RetroArch team
* *
* --------------------------------------------------------------------------------------- * ---------------------------------------------------------------------------------------
* The following license statement only applies to this file (vfs_implementation_cdrom.c). * The following license statement only applies to this file (vfs_implementation_cdrom.c).
@ -30,6 +30,7 @@
#include <windows.h> #include <windows.h>
#endif #endif
/* TODO/FIXME - static global variable */
static cdrom_toc_t vfs_cdrom_toc = {0}; static cdrom_toc_t vfs_cdrom_toc = {0};
const cdrom_toc_t* retro_vfs_file_get_cdrom_toc(void) const cdrom_toc_t* retro_vfs_file_get_cdrom_toc(void)
@ -37,7 +38,9 @@ const cdrom_toc_t* retro_vfs_file_get_cdrom_toc(void)
return &vfs_cdrom_toc; return &vfs_cdrom_toc;
} }
int64_t retro_vfs_file_seek_cdrom(libretro_vfs_implementation_file *stream, int64_t offset, int whence) int64_t retro_vfs_file_seek_cdrom(
libretro_vfs_implementation_file *stream,
int64_t offset, int whence)
{ {
const char *ext = path_get_extension(stream->orig_path); const char *ext = path_get_extension(stream->orig_path);
@ -52,68 +55,84 @@ int64_t retro_vfs_file_seek_cdrom(libretro_vfs_implementation_file *stream, int6
stream->cdrom.byte_pos += offset; stream->cdrom.byte_pos += offset;
break; break;
case SEEK_END: case SEEK_END:
stream->cdrom.byte_pos = (stream->cdrom.cue_len - 1) + offset; stream->cdrom.byte_pos = (stream->cdrom.cue_len - 1) + offset;
break; break;
} }
#ifdef CDROM_DEBUG #ifdef CDROM_DEBUG
printf("[CDROM] Seek: Path %s Offset %" PRIu64 " is now at %" PRIu64 "\n", stream->orig_path, offset, stream->cdrom.byte_pos); printf("[CDROM] Seek: Path %s Offset %" PRIu64 " is now at %" PRIu64 "\n",
stream->orig_path,
offset,
stream->cdrom.byte_pos);
fflush(stdout); fflush(stdout);
#endif #endif
} }
else if (string_is_equal_noncase(ext, "bin")) else if (string_is_equal_noncase(ext, "bin"))
{ {
int lba = (offset / 2352); int lba = (offset / 2352);
unsigned char min = 0; unsigned char min = 0;
unsigned char sec = 0; unsigned char sec = 0;
unsigned char frame = 0; unsigned char frame = 0;
#ifdef CDROM_DEBUG
const char *seek_type = "SEEK_SET"; const char *seek_type = "SEEK_SET";
#endif
(void)seek_type;
switch (whence) switch (whence)
{ {
case SEEK_CUR: case SEEK_CUR:
{ {
unsigned new_lba; unsigned new_lba;
#ifdef CDROM_DEBUG
stream->cdrom.byte_pos += offset; seek_type = "SEEK_CUR";
new_lba = vfs_cdrom_toc.track[stream->cdrom.cur_track - 1].lba + (stream->cdrom.byte_pos / 2352); #endif
seek_type = "SEEK_CUR"; stream->cdrom.byte_pos += offset;
new_lba = vfs_cdrom_toc.track[stream->cdrom.cur_track - 1].lba + (stream->cdrom.byte_pos / 2352);
cdrom_lba_to_msf(new_lba, &min, &sec, &frame);
cdrom_lba_to_msf(new_lba, &min, &sec, &frame);
}
break; break;
}
case SEEK_END: case SEEK_END:
{ {
ssize_t pregap_lba_len = (vfs_cdrom_toc.track[stream->cdrom.cur_track - 1].audio ? 0 : (vfs_cdrom_toc.track[stream->cdrom.cur_track - 1].lba - vfs_cdrom_toc.track[stream->cdrom.cur_track - 1].lba_start)); ssize_t pregap_lba_len = (vfs_cdrom_toc.track[stream->cdrom.cur_track - 1].audio
ssize_t lba_len = vfs_cdrom_toc.track[stream->cdrom.cur_track - 1].track_size - pregap_lba_len; ? 0
: (vfs_cdrom_toc.track[stream->cdrom.cur_track - 1].lba - vfs_cdrom_toc.track[stream->cdrom.cur_track - 1].lba_start));
cdrom_lba_to_msf(lba_len + lba, &min, &sec, &frame); ssize_t lba_len = vfs_cdrom_toc.track[stream->cdrom.cur_track - 1].track_size - pregap_lba_len;
#ifdef CDROM_DEBUG
stream->cdrom.byte_pos = lba_len * 2352; seek_type = "SEEK_END";
seek_type = "SEEK_END"; #endif
cdrom_lba_to_msf(lba_len + lba, &min, &sec, &frame);
stream->cdrom.byte_pos = lba_len * 2352;
}
break; break;
}
case SEEK_SET: case SEEK_SET:
default: default:
{ {
seek_type = "SEEK_SET"; #ifdef CDROM_DEBUG
stream->cdrom.byte_pos = offset; seek_type = "SEEK_SET";
cdrom_lba_to_msf(vfs_cdrom_toc.track[stream->cdrom.cur_track - 1].lba + (stream->cdrom.byte_pos / 2352), &min, &sec, &frame); #endif
stream->cdrom.byte_pos = offset;
cdrom_lba_to_msf(vfs_cdrom_toc.track[stream->cdrom.cur_track - 1].lba + (stream->cdrom.byte_pos / 2352), &min, &sec, &frame);
}
break; break;
}
} }
stream->cdrom.cur_min = min; stream->cdrom.cur_min = min;
stream->cdrom.cur_sec = sec; stream->cdrom.cur_sec = sec;
stream->cdrom.cur_frame = frame; stream->cdrom.cur_frame = frame;
stream->cdrom.cur_lba = cdrom_msf_to_lba(min, sec, frame); stream->cdrom.cur_lba = cdrom_msf_to_lba(min, sec, frame);
#ifdef CDROM_DEBUG #ifdef CDROM_DEBUG
printf("[CDROM] Seek %s: Path %s Offset %" PRIu64 " is now at %" PRIu64 " (MSF %02u:%02u:%02u) (LBA %u)...\n", seek_type, stream->orig_path, offset, stream->cdrom.byte_pos, (unsigned)stream->cdrom.cur_min, (unsigned)stream->cdrom.cur_sec, (unsigned)stream->cdrom.cur_frame, stream->cdrom.cur_lba); printf(
"[CDROM] Seek %s: Path %s Offset %" PRIu64 " is now at %" PRIu64 " (MSF %02u:%02u:%02u) (LBA %u)...\n",
seek_type,
stream->orig_path,
offset,
stream->cdrom.byte_pos,
(unsigned)stream->cdrom.cur_min,
(unsigned)stream->cdrom.cur_sec,
(unsigned)stream->cdrom.cur_frame,
stream->cdrom.cur_lba);
fflush(stdout); fflush(stdout);
#endif #endif
} }
@ -128,20 +147,21 @@ void retro_vfs_file_open_cdrom(
const char *path, unsigned mode, unsigned hints) const char *path, unsigned mode, unsigned hints)
{ {
#if defined(__linux__) && !defined(ANDROID) #if defined(__linux__) && !defined(ANDROID)
char cdrom_path[] = "/dev/sg1"; char cdrom_path[] = "/dev/sg1";
size_t path_len = strlen(path); size_t path_len = strlen(path);
const char *ext = path_get_extension(path); const char *ext = path_get_extension(path);
stream->cdrom.cur_track = 1; stream->cdrom.cur_track = 1;
if (!string_is_equal_noncase(ext, "cue") && !string_is_equal_noncase(ext, "bin")) if ( !string_is_equal_noncase(ext, "cue")
&& !string_is_equal_noncase(ext, "bin"))
return; return;
if (path_len >= strlen("drive1-track01.bin")) if (path_len >= STRLEN_CONST("drive1-track01.bin"))
{ {
if (!memcmp(path, "drive", strlen("drive"))) if (!memcmp(path, "drive", STRLEN_CONST("drive")))
{ {
if (!memcmp(path + 6, "-track", strlen("-track"))) if (!memcmp(path + 6, "-track", STRLEN_CONST("-track")))
{ {
if (sscanf(path + 12, "%02u", (unsigned*)&stream->cdrom.cur_track)) if (sscanf(path + 12, "%02u", (unsigned*)&stream->cdrom.cur_track))
{ {
@ -154,13 +174,13 @@ void retro_vfs_file_open_cdrom(
} }
} }
if (path_len >= strlen("drive1.cue")) if (path_len >= STRLEN_CONST("drive1.cue"))
{ {
if (!memcmp(path, "drive", strlen("drive"))) if (!memcmp(path, "drive", STRLEN_CONST("drive")))
{ {
if (path[5] >= '0' && path[5] <= '9') if (path[5] >= '0' && path[5] <= '9')
{ {
cdrom_path[7] = path[5]; cdrom_path[7] = path[5];
stream->cdrom.drive = path[5]; stream->cdrom.drive = path[5];
vfs_cdrom_toc.drive = stream->cdrom.drive; vfs_cdrom_toc.drive = stream->cdrom.drive;
} }
@ -184,7 +204,12 @@ void retro_vfs_file_open_cdrom(
stream->cdrom.cue_buf = NULL; stream->cdrom.cue_buf = NULL;
} }
cdrom_write_cue(stream, &stream->cdrom.cue_buf, &stream->cdrom.cue_len, stream->cdrom.drive, &vfs_cdrom_toc.num_tracks, &vfs_cdrom_toc); cdrom_write_cue(stream,
&stream->cdrom.cue_buf,
&stream->cdrom.cue_len,
stream->cdrom.drive,
&vfs_cdrom_toc.num_tracks,
&vfs_cdrom_toc);
cdrom_get_timeouts(stream, &vfs_cdrom_toc.timeouts); cdrom_get_timeouts(stream, &vfs_cdrom_toc.timeouts);
#ifdef CDROM_DEBUG #ifdef CDROM_DEBUG
@ -203,15 +228,16 @@ void retro_vfs_file_open_cdrom(
#endif #endif
#if defined(_WIN32) && !defined(_XBOX) #if defined(_WIN32) && !defined(_XBOX)
char cdrom_path[] = "\\\\.\\D:"; char cdrom_path[] = "\\\\.\\D:";
size_t path_len = strlen(path); size_t path_len = strlen(path);
const char *ext = path_get_extension(path); const char *ext = path_get_extension(path);
if (!string_is_equal_noncase(ext, "cue") && !string_is_equal_noncase(ext, "bin")) if ( !string_is_equal_noncase(ext, "cue")
&& !string_is_equal_noncase(ext, "bin"))
return; return;
if (path_len >= strlen("d:/drive-track01.bin")) if (path_len >= STRLEN_CONST("d:/drive-track01.bin"))
{ {
if (!memcmp(path + 1, ":/drive-track", strlen(":/drive-track"))) if (!memcmp(path + 1, ":/drive-track", STRLEN_CONST(":/drive-track")))
{ {
if (sscanf(path + 14, "%02u", (unsigned*)&stream->cdrom.cur_track)) if (sscanf(path + 14, "%02u", (unsigned*)&stream->cdrom.cur_track))
{ {
@ -223,13 +249,13 @@ void retro_vfs_file_open_cdrom(
} }
} }
if (path_len >= strlen("d:/drive.cue")) if (path_len >= STRLEN_CONST("d:/drive.cue"))
{ {
if (!memcmp(path + 1, ":/drive", strlen(":/drive"))) if (!memcmp(path + 1, ":/drive", STRLEN_CONST(":/drive")))
{ {
if ((path[0] >= 'A' && path[0] <= 'Z') || (path[0] >= 'a' && path[0] <= 'z')) if ((path[0] >= 'A' && path[0] <= 'Z') || (path[0] >= 'a' && path[0] <= 'z'))
{ {
cdrom_path[4] = path[0]; cdrom_path[4] = path[0];
stream->cdrom.drive = path[0]; stream->cdrom.drive = path[0];
vfs_cdrom_toc.drive = stream->cdrom.drive; vfs_cdrom_toc.drive = stream->cdrom.drive;
} }
@ -240,7 +266,13 @@ void retro_vfs_file_open_cdrom(
printf("[CDROM] Open: Path %s URI %s\n", cdrom_path, path); printf("[CDROM] Open: Path %s URI %s\n", cdrom_path, path);
fflush(stdout); fflush(stdout);
#endif #endif
stream->fh = CreateFile(cdrom_path, GENERIC_READ | GENERIC_WRITE, FILE_SHARE_READ | FILE_SHARE_WRITE, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL); stream->fh = CreateFile(cdrom_path,
GENERIC_READ | GENERIC_WRITE,
FILE_SHARE_READ | FILE_SHARE_WRITE,
NULL,
OPEN_EXISTING,
FILE_ATTRIBUTE_NORMAL,
NULL);
if (stream->fh == INVALID_HANDLE_VALUE) if (stream->fh == INVALID_HANDLE_VALUE)
return; return;
@ -253,8 +285,14 @@ void retro_vfs_file_open_cdrom(
stream->cdrom.cue_buf = NULL; stream->cdrom.cue_buf = NULL;
} }
cdrom_write_cue(stream, &stream->cdrom.cue_buf, &stream->cdrom.cue_len, stream->cdrom.drive, &vfs_cdrom_toc.num_tracks, &vfs_cdrom_toc); cdrom_write_cue(stream,
cdrom_get_timeouts(stream, &vfs_cdrom_toc.timeouts); &stream->cdrom.cue_buf,
&stream->cdrom.cue_len,
stream->cdrom.drive,
&vfs_cdrom_toc.num_tracks,
&vfs_cdrom_toc);
cdrom_get_timeouts(stream,
&vfs_cdrom_toc.timeouts);
#ifdef CDROM_DEBUG #ifdef CDROM_DEBUG
if (string_is_empty(stream->cdrom.cue_buf)) if (string_is_empty(stream->cdrom.cue_buf))
@ -272,17 +310,17 @@ void retro_vfs_file_open_cdrom(
#endif #endif
if (vfs_cdrom_toc.num_tracks > 1 && stream->cdrom.cur_track) if (vfs_cdrom_toc.num_tracks > 1 && stream->cdrom.cur_track)
{ {
stream->cdrom.cur_min = vfs_cdrom_toc.track[stream->cdrom.cur_track - 1].min; stream->cdrom.cur_min = vfs_cdrom_toc.track[stream->cdrom.cur_track - 1].min;
stream->cdrom.cur_sec = vfs_cdrom_toc.track[stream->cdrom.cur_track - 1].sec; stream->cdrom.cur_sec = vfs_cdrom_toc.track[stream->cdrom.cur_track - 1].sec;
stream->cdrom.cur_frame = vfs_cdrom_toc.track[stream->cdrom.cur_track - 1].frame; stream->cdrom.cur_frame = vfs_cdrom_toc.track[stream->cdrom.cur_track - 1].frame;
stream->cdrom.cur_lba = cdrom_msf_to_lba(stream->cdrom.cur_min, stream->cdrom.cur_sec, stream->cdrom.cur_frame); stream->cdrom.cur_lba = cdrom_msf_to_lba(stream->cdrom.cur_min, stream->cdrom.cur_sec, stream->cdrom.cur_frame);
} }
else else
{ {
stream->cdrom.cur_min = vfs_cdrom_toc.track[0].min; stream->cdrom.cur_min = vfs_cdrom_toc.track[0].min;
stream->cdrom.cur_sec = vfs_cdrom_toc.track[0].sec; stream->cdrom.cur_sec = vfs_cdrom_toc.track[0].sec;
stream->cdrom.cur_frame = vfs_cdrom_toc.track[0].frame; stream->cdrom.cur_frame = vfs_cdrom_toc.track[0].frame;
stream->cdrom.cur_lba = cdrom_msf_to_lba(stream->cdrom.cur_min, stream->cdrom.cur_sec, stream->cdrom.cur_frame); stream->cdrom.cur_lba = cdrom_msf_to_lba(stream->cdrom.cur_min, stream->cdrom.cur_sec, stream->cdrom.cur_frame);
} }
} }
@ -340,52 +378,69 @@ int64_t retro_vfs_file_read_cdrom(libretro_vfs_implementation_file *stream,
if (string_is_equal_noncase(ext, "cue")) if (string_is_equal_noncase(ext, "cue"))
{ {
if (len < stream->cdrom.cue_len - stream->cdrom.byte_pos) if ((int64_t)len >= (int64_t)stream->cdrom.cue_len
{ - stream->cdrom.byte_pos)
len = stream->cdrom.cue_len - stream->cdrom.byte_pos - 1;
#ifdef CDROM_DEBUG #ifdef CDROM_DEBUG
printf("[CDROM] Read: Reading %" PRIu64 " bytes from cuesheet starting at %" PRIu64 "...\n", len, stream->cdrom.byte_pos); printf(
fflush(stdout); "[CDROM] Read: Reading %" PRIu64 " bytes from cuesheet starting at %" PRIu64 "...\n",
len,
stream->cdrom.byte_pos);
fflush(stdout);
#endif #endif
memcpy(s, stream->cdrom.cue_buf + stream->cdrom.byte_pos, len); memcpy(s, stream->cdrom.cue_buf + stream->cdrom.byte_pos, len);
stream->cdrom.byte_pos += len; stream->cdrom.byte_pos += len;
return len; return len;
}
else
{
#ifdef CDROM_DEBUG
printf("[CDROM] Read: Reading %" PRIu64 " bytes from cuesheet starting at %" PRIu64 " failed.\n", len, stream->cdrom.byte_pos);
fflush(stdout);
#endif
return 0;
}
} }
else if (string_is_equal_noncase(ext, "bin")) else if (string_is_equal_noncase(ext, "bin"))
{ {
size_t skip = stream->cdrom.byte_pos % 2352; unsigned char min = 0;
unsigned char min = 0; unsigned char sec = 0;
unsigned char sec = 0; unsigned char frame = 0;
unsigned char frame = 0; unsigned char rmin = 0;
unsigned char rmin = 0; unsigned char rsec = 0;
unsigned char rsec = 0;
unsigned char rframe = 0; unsigned char rframe = 0;
size_t skip = stream->cdrom.byte_pos % 2352;
if (stream->cdrom.byte_pos >= vfs_cdrom_toc.track[stream->cdrom.cur_track - 1].track_bytes) if (stream->cdrom.byte_pos >=
vfs_cdrom_toc.track[stream->cdrom.cur_track - 1].track_bytes)
return 0; return 0;
if (stream->cdrom.byte_pos + len > vfs_cdrom_toc.track[stream->cdrom.cur_track - 1].track_bytes) if (stream->cdrom.byte_pos + len >
len -= (stream->cdrom.byte_pos + len) - vfs_cdrom_toc.track[stream->cdrom.cur_track - 1].track_bytes; vfs_cdrom_toc.track[stream->cdrom.cur_track - 1].track_bytes)
len -= (stream->cdrom.byte_pos + len)
- vfs_cdrom_toc.track[stream->cdrom.cur_track - 1].track_bytes;
cdrom_lba_to_msf(stream->cdrom.cur_lba, &min, &sec, &frame); cdrom_lba_to_msf(stream->cdrom.cur_lba, &min, &sec, &frame);
cdrom_lba_to_msf(stream->cdrom.cur_lba - vfs_cdrom_toc.track[stream->cdrom.cur_track - 1].lba, &rmin, &rsec, &rframe); cdrom_lba_to_msf(stream->cdrom.cur_lba
- vfs_cdrom_toc.track[stream->cdrom.cur_track - 1].lba,
&rmin, &rsec, &rframe);
#ifdef CDROM_DEBUG #ifdef CDROM_DEBUG
printf("[CDROM] Read: Reading %" PRIu64 " bytes from %s starting at byte offset %" PRIu64 " (rMSF %02u:%02u:%02u aMSF %02u:%02u:%02u) (LBA %u) skip %" PRIu64 "...\n", len, stream->orig_path, stream->cdrom.byte_pos, (unsigned)rmin, (unsigned)rsec, (unsigned)rframe, (unsigned)min, (unsigned)sec, (unsigned)frame, stream->cdrom.cur_lba, skip); printf(
"[CDROM] Read: Reading %" PRIu64 " bytes from %s starting at byte offset %" PRIu64 " (rMSF %02u:%02u:%02u aMSF %02u:%02u:%02u) (LBA %u) skip %" PRIu64 "...\n",
len,
stream->orig_path,
stream->cdrom.byte_pos,
(unsigned)rmin,
(unsigned)rsec,
(unsigned)rframe,
(unsigned)min,
(unsigned)sec,
(unsigned)frame,
stream->cdrom.cur_lba,
skip);
fflush(stdout); fflush(stdout);
#endif #endif
rv = cdrom_read(stream, &vfs_cdrom_toc.timeouts, min, sec, frame, s, (size_t)len, skip); #if 1
/*rv = cdrom_read_lba(stream, stream->cdrom.cur_lba, s, (size_t)len, skip);*/ rv = cdrom_read(stream, &vfs_cdrom_toc.timeouts, min, sec,
frame, s, (size_t)len, skip);
#else
rv = cdrom_read_lba(stream, stream->cdrom.cur_lba, s,
(size_t)len, skip);
#endif
if (rv) if (rv)
{ {
@ -397,12 +452,28 @@ int64_t retro_vfs_file_read_cdrom(libretro_vfs_implementation_file *stream,
} }
stream->cdrom.byte_pos += len; stream->cdrom.byte_pos += len;
stream->cdrom.cur_lba = vfs_cdrom_toc.track[stream->cdrom.cur_track - 1].lba + (stream->cdrom.byte_pos / 2352); stream->cdrom.cur_lba =
vfs_cdrom_toc.track[stream->cdrom.cur_track - 1].lba
+ (stream->cdrom.byte_pos / 2352);
cdrom_lba_to_msf(stream->cdrom.cur_lba, &stream->cdrom.cur_min, &stream->cdrom.cur_sec, &stream->cdrom.cur_frame); cdrom_lba_to_msf(stream->cdrom.cur_lba,
&stream->cdrom.cur_min,
&stream->cdrom.cur_sec,
&stream->cdrom.cur_frame);
#ifdef CDROM_DEBUG #ifdef CDROM_DEBUG
printf("[CDROM] read %" PRIu64 " bytes, position is now: %" PRIu64 " (MSF %02u:%02u:%02u) (LBA %u)\n", len, stream->cdrom.byte_pos, (unsigned)stream->cdrom.cur_min, (unsigned)stream->cdrom.cur_sec, (unsigned)stream->cdrom.cur_frame, cdrom_msf_to_lba(stream->cdrom.cur_min, stream->cdrom.cur_sec, stream->cdrom.cur_frame)); printf(
"[CDROM] read %" PRIu64 " bytes, position is now: %" PRIu64 " (MSF %02u:%02u:%02u) (LBA %u)\n",
len,
stream->cdrom.byte_pos,
(unsigned)stream->cdrom.cur_min,
(unsigned)stream->cdrom.cur_sec,
(unsigned)stream->cdrom.cur_frame,
cdrom_msf_to_lba(
stream->cdrom.cur_min,
stream->cdrom.cur_sec,
stream->cdrom.cur_frame)
);
fflush(stdout); fflush(stdout);
#endif #endif
@ -417,7 +488,8 @@ int retro_vfs_file_error_cdrom(libretro_vfs_implementation_file *stream)
return 0; return 0;
} }
const vfs_cdrom_t* retro_vfs_file_get_cdrom_position(const libretro_vfs_implementation_file *stream) const vfs_cdrom_t* retro_vfs_file_get_cdrom_position(
const libretro_vfs_implementation_file *stream)
{ {
return &stream->cdrom; return &stream->cdrom;
} }