mirror of
https://github.com/libretro/RACE.git
synced 2024-11-23 08:59:49 +00:00
Replace direct direct file access with VFS routines
This commit is contained in:
parent
e0c56aa78e
commit
fc05721710
@ -38,6 +38,21 @@ else
|
|||||||
$(CORE_DIR)/cz80_support.c
|
$(CORE_DIR)/cz80_support.c
|
||||||
endif
|
endif
|
||||||
|
|
||||||
|
ifneq ($(STATIC_LINKING), 1)
|
||||||
|
SOURCES_C += \
|
||||||
|
$(LIBRETRO_COMM_DIR)/compat/compat_posix_string.c \
|
||||||
|
$(LIBRETRO_COMM_DIR)/compat/compat_strcasestr.c \
|
||||||
|
$(LIBRETRO_COMM_DIR)/compat/compat_strl.c \
|
||||||
|
$(LIBRETRO_COMM_DIR)/compat/fopen_utf8.c \
|
||||||
|
$(LIBRETRO_COMM_DIR)/encodings/encoding_utf.c \
|
||||||
|
$(LIBRETRO_COMM_DIR)/file/file_path.c \
|
||||||
|
$(LIBRETRO_COMM_DIR)/file/file_path_io.c \
|
||||||
|
$(LIBRETRO_COMM_DIR)/streams/file_stream.c \
|
||||||
|
$(LIBRETRO_COMM_DIR)/streams/file_stream_transforms.c \
|
||||||
|
$(LIBRETRO_COMM_DIR)/string/stdstring.c \
|
||||||
|
$(LIBRETRO_COMM_DIR)/time/rtime.c \
|
||||||
|
$(LIBRETRO_COMM_DIR)/vfs/vfs_implementation.c
|
||||||
|
endif
|
||||||
|
|
||||||
FLAGS += -D__LIBRETRO__ -D_MAX_PATH=2048 -DHOST_FPS=60
|
FLAGS += -D__LIBRETRO__ -D_MAX_PATH=2048 -DHOST_FPS=60
|
||||||
ifeq (,$(findstring msvc,$(platform)))
|
ifeq (,$(findstring msvc,$(platform)))
|
||||||
|
59
flash.c
59
flash.c
@ -15,6 +15,7 @@
|
|||||||
|
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
|
#include <streams/file_stream.h>
|
||||||
#ifdef _WIN32
|
#ifdef _WIN32
|
||||||
#include <direct.h>
|
#include <direct.h>
|
||||||
#else
|
#else
|
||||||
@ -228,20 +229,21 @@ void writeSaveGameFile(void)
|
|||||||
{
|
{
|
||||||
/* find the dirty blocks and write them to the .NGF file */
|
/* find the dirty blocks and write them to the .NGF file */
|
||||||
int totalBlocks = bootBlockStartNum+4;
|
int totalBlocks = bootBlockStartNum+4;
|
||||||
|
RFILE *ngfFile = NULL;
|
||||||
int i;
|
int i;
|
||||||
FILE *ngfFile;
|
|
||||||
|
|
||||||
int bytes;
|
int64_t bytes;
|
||||||
struct NGFheaderStruct NGFheader;
|
struct NGFheaderStruct NGFheader;
|
||||||
struct blockStruct block;
|
struct blockStruct block;
|
||||||
|
|
||||||
setupNGFfilename();
|
setupNGFfilename();
|
||||||
|
|
||||||
ngfFile = fopen(ngfFilename, "wb");
|
ngfFile = filestream_open(ngfFilename,
|
||||||
|
RETRO_VFS_FILE_ACCESS_WRITE,
|
||||||
|
RETRO_VFS_FILE_ACCESS_HINT_NONE);
|
||||||
if(!ngfFile)
|
if(!ngfFile)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
|
|
||||||
NGFheader.version = 0x53;
|
NGFheader.version = 0x53;
|
||||||
NGFheader.numBlocks = 0;
|
NGFheader.numBlocks = 0;
|
||||||
NGFheader.fileLen = sizeof(struct NGFheaderStruct);
|
NGFheader.fileLen = sizeof(struct NGFheaderStruct);
|
||||||
@ -269,34 +271,32 @@ void writeSaveGameFile(void)
|
|||||||
|
|
||||||
NGFheader.fileLen += NGFheader.numBlocks * sizeof(struct blockStruct);
|
NGFheader.fileLen += NGFheader.numBlocks * sizeof(struct blockStruct);
|
||||||
|
|
||||||
bytes = fwrite(&NGFheader, 1, sizeof(struct NGFheaderStruct), ngfFile);
|
bytes = filestream_write(ngfFile, &NGFheader, sizeof(struct NGFheaderStruct));
|
||||||
if(bytes != sizeof(struct NGFheaderStruct))
|
if(bytes != sizeof(struct NGFheaderStruct))
|
||||||
{
|
{
|
||||||
fclose(ngfFile);
|
filestream_close(ngfFile);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
for(i=0;i<totalBlocks;i++)
|
for(i=0;i<totalBlocks;i++)
|
||||||
{
|
{
|
||||||
if(blocksDirty[0][i])
|
if(blocksDirty[0][i])
|
||||||
{
|
{
|
||||||
|
|
||||||
block.NGPCaddr = blockNumToAddr(0, i)+0x200000;
|
block.NGPCaddr = blockNumToAddr(0, i)+0x200000;
|
||||||
block.len = blockSize(i);
|
block.len = blockSize(i);
|
||||||
|
|
||||||
|
bytes = filestream_write(ngfFile, &block, sizeof(struct blockStruct));
|
||||||
bytes = fwrite(&block, 1, sizeof(struct blockStruct), ngfFile);
|
|
||||||
if(bytes != sizeof(struct blockStruct))
|
if(bytes != sizeof(struct blockStruct))
|
||||||
{
|
{
|
||||||
fclose(ngfFile);
|
filestream_close(ngfFile);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
bytes = fwrite(&mainrom[blockNumToAddr(0, i)], 1, blockSize(i), ngfFile);
|
bytes = filestream_write(ngfFile,
|
||||||
|
&mainrom[blockNumToAddr(0, i)], blockSize(i));
|
||||||
if(bytes != blockSize(i))
|
if(bytes != blockSize(i))
|
||||||
{
|
{
|
||||||
fclose(ngfFile);
|
filestream_close(ngfFile);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -311,24 +311,25 @@ void writeSaveGameFile(void)
|
|||||||
block.NGPCaddr = blockNumToAddr(1, i)+0x600000;
|
block.NGPCaddr = blockNumToAddr(1, i)+0x600000;
|
||||||
block.len = blockSize(i);
|
block.len = blockSize(i);
|
||||||
|
|
||||||
bytes = fwrite(&block, 1, sizeof(struct blockStruct), ngfFile);
|
bytes = filestream_write(ngfFile, &block, sizeof(struct blockStruct));
|
||||||
if(bytes != sizeof(struct blockStruct))
|
if(bytes != sizeof(struct blockStruct))
|
||||||
{
|
{
|
||||||
fclose(ngfFile);
|
filestream_close(ngfFile);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
bytes = fwrite(&mainrom[blockNumToAddr(1, i)], 1, blockSize(i), ngfFile);
|
bytes = filestream_write(ngfFile,
|
||||||
|
&mainrom[blockNumToAddr(1, i)], blockSize(i));
|
||||||
if(bytes != blockSize(i))
|
if(bytes != blockSize(i))
|
||||||
{
|
{
|
||||||
fclose(ngfFile);
|
filestream_close(ngfFile);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fclose(ngfFile);
|
filestream_close(ngfFile);
|
||||||
/* char msg[50];
|
/* char msg[50];
|
||||||
sprintf(msg, "Saved File %s", ngfFilename);
|
sprintf(msg, "Saved File %s", ngfFilename);
|
||||||
printTTF(msg, 0, 100, yellow, 1, actualScreen, 1);*/
|
printTTF(msg, 0, 100, yellow, 1, actualScreen, 1);*/
|
||||||
@ -345,8 +346,9 @@ void writeSaveGameFile(void)
|
|||||||
void loadSaveGameFile(void)
|
void loadSaveGameFile(void)
|
||||||
{
|
{
|
||||||
/* find the NGF file and read it in */
|
/* find the NGF file and read it in */
|
||||||
FILE *ngfFile;
|
RFILE *ngfFile = NULL;
|
||||||
int bytes, i;
|
int64_t bytes;
|
||||||
|
int i;
|
||||||
unsigned char *blocks;
|
unsigned char *blocks;
|
||||||
void *blockMem;
|
void *blockMem;
|
||||||
struct NGFheaderStruct NGFheader;
|
struct NGFheaderStruct NGFheader;
|
||||||
@ -354,19 +356,19 @@ void loadSaveGameFile(void)
|
|||||||
|
|
||||||
setupNGFfilename();
|
setupNGFfilename();
|
||||||
|
|
||||||
ngfFile = fopen(ngfFilename, "rb");
|
ngfFile = filestream_open(ngfFilename,
|
||||||
|
RETRO_VFS_FILE_ACCESS_READ,
|
||||||
|
RETRO_VFS_FILE_ACCESS_HINT_NONE);
|
||||||
if(!ngfFile)
|
if(!ngfFile)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
bytes = fread(&NGFheader, 1, sizeof(struct NGFheaderStruct), ngfFile);
|
bytes = filestream_read(ngfFile, &NGFheader, sizeof(struct NGFheaderStruct));
|
||||||
|
|
||||||
if(bytes != sizeof(struct NGFheaderStruct))
|
if(bytes != sizeof(struct NGFheaderStruct))
|
||||||
{
|
{
|
||||||
fclose(ngfFile);
|
filestream_close(ngfFile);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
unsigned short version; // always 0x53?
|
unsigned short version; // always 0x53?
|
||||||
unsigned short numBlocks; // how many blocks are in the file
|
unsigned short numBlocks; // how many blocks are in the file
|
||||||
@ -375,7 +377,7 @@ void loadSaveGameFile(void)
|
|||||||
|
|
||||||
if(NGFheader.version != 0x53)
|
if(NGFheader.version != 0x53)
|
||||||
{
|
{
|
||||||
fclose(ngfFile);
|
filestream_close(ngfFile);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -387,8 +389,9 @@ void loadSaveGameFile(void)
|
|||||||
|
|
||||||
blocks = (unsigned char *)blockMem;
|
blocks = (unsigned char *)blockMem;
|
||||||
|
|
||||||
bytes = fread(blocks, 1, NGFheader.fileLen - sizeof(struct NGFheaderStruct), ngfFile);
|
bytes = filestream_read(ngfFile, blocks,
|
||||||
fclose(ngfFile);
|
NGFheader.fileLen - sizeof(struct NGFheaderStruct));
|
||||||
|
filestream_close(ngfFile);
|
||||||
|
|
||||||
if(bytes != (NGFheader.fileLen - sizeof(struct NGFheaderStruct)))
|
if(bytes != (NGFheader.fileLen - sizeof(struct NGFheaderStruct)))
|
||||||
{
|
{
|
||||||
|
104
libretro-common/compat/compat_posix_string.c
Normal file
104
libretro-common/compat/compat_posix_string.c
Normal file
@ -0,0 +1,104 @@
|
|||||||
|
/* Copyright (C) 2010-2020 The RetroArch team
|
||||||
|
*
|
||||||
|
* ---------------------------------------------------------------------------------------
|
||||||
|
* The following license statement only applies to this file (compat_posix_string.c).
|
||||||
|
* ---------------------------------------------------------------------------------------
|
||||||
|
*
|
||||||
|
* Permission is hereby granted, free of charge,
|
||||||
|
* to any person obtaining a copy of this software and associated documentation files (the "Software"),
|
||||||
|
* to deal in the Software without restriction, including without limitation the rights to
|
||||||
|
* use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software,
|
||||||
|
* and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
|
||||||
|
*
|
||||||
|
* The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
|
||||||
|
*
|
||||||
|
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
|
||||||
|
* INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
|
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
|
||||||
|
* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
|
||||||
|
* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||||
|
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <ctype.h>
|
||||||
|
|
||||||
|
#include <compat/posix_string.h>
|
||||||
|
|
||||||
|
#ifdef _WIN32
|
||||||
|
|
||||||
|
#undef strcasecmp
|
||||||
|
#undef strdup
|
||||||
|
#undef isblank
|
||||||
|
#undef strtok_r
|
||||||
|
#include <ctype.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <stddef.h>
|
||||||
|
#include <compat/strl.h>
|
||||||
|
|
||||||
|
#include <string.h>
|
||||||
|
|
||||||
|
int retro_strcasecmp__(const char *a, const char *b)
|
||||||
|
{
|
||||||
|
while (*a && *b)
|
||||||
|
{
|
||||||
|
int a_ = tolower(*a);
|
||||||
|
int b_ = tolower(*b);
|
||||||
|
|
||||||
|
if (a_ != b_)
|
||||||
|
return a_ - b_;
|
||||||
|
|
||||||
|
a++;
|
||||||
|
b++;
|
||||||
|
}
|
||||||
|
|
||||||
|
return tolower(*a) - tolower(*b);
|
||||||
|
}
|
||||||
|
|
||||||
|
char *retro_strdup__(const char *orig)
|
||||||
|
{
|
||||||
|
size_t len = strlen(orig) + 1;
|
||||||
|
char *ret = (char*)malloc(len);
|
||||||
|
if (!ret)
|
||||||
|
return NULL;
|
||||||
|
|
||||||
|
strlcpy(ret, orig, len);
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
int retro_isblank__(int c)
|
||||||
|
{
|
||||||
|
return (c == ' ') || (c == '\t');
|
||||||
|
}
|
||||||
|
|
||||||
|
char *retro_strtok_r__(char *str, const char *delim, char **saveptr)
|
||||||
|
{
|
||||||
|
char *first = NULL;
|
||||||
|
if (!saveptr || !delim)
|
||||||
|
return NULL;
|
||||||
|
|
||||||
|
if (str)
|
||||||
|
*saveptr = str;
|
||||||
|
|
||||||
|
do
|
||||||
|
{
|
||||||
|
char *ptr = NULL;
|
||||||
|
first = *saveptr;
|
||||||
|
while (*first && strchr(delim, *first))
|
||||||
|
*first++ = '\0';
|
||||||
|
|
||||||
|
if (*first == '\0')
|
||||||
|
return NULL;
|
||||||
|
|
||||||
|
ptr = first + 1;
|
||||||
|
|
||||||
|
while (*ptr && !strchr(delim, *ptr))
|
||||||
|
ptr++;
|
||||||
|
|
||||||
|
*saveptr = ptr + (*ptr ? 1 : 0);
|
||||||
|
*ptr = '\0';
|
||||||
|
} while (strlen(first) == 0);
|
||||||
|
|
||||||
|
return first;
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif
|
58
libretro-common/compat/compat_strcasestr.c
Normal file
58
libretro-common/compat/compat_strcasestr.c
Normal file
@ -0,0 +1,58 @@
|
|||||||
|
/* Copyright (C) 2010-2020 The RetroArch team
|
||||||
|
*
|
||||||
|
* ---------------------------------------------------------------------------------------
|
||||||
|
* The following license statement only applies to this file (compat_strcasestr.c).
|
||||||
|
* ---------------------------------------------------------------------------------------
|
||||||
|
*
|
||||||
|
* Permission is hereby granted, free of charge,
|
||||||
|
* to any person obtaining a copy of this software and associated documentation files (the "Software"),
|
||||||
|
* to deal in the Software without restriction, including without limitation the rights to
|
||||||
|
* use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software,
|
||||||
|
* and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
|
||||||
|
*
|
||||||
|
* The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
|
||||||
|
*
|
||||||
|
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
|
||||||
|
* INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
|
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
|
||||||
|
* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
|
||||||
|
* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||||
|
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <ctype.h>
|
||||||
|
|
||||||
|
#include <compat/strcasestr.h>
|
||||||
|
|
||||||
|
/* Pretty much strncasecmp. */
|
||||||
|
static int casencmp(const char *a, const char *b, size_t n)
|
||||||
|
{
|
||||||
|
size_t i;
|
||||||
|
|
||||||
|
for (i = 0; i < n; i++)
|
||||||
|
{
|
||||||
|
int a_lower = tolower(a[i]);
|
||||||
|
int b_lower = tolower(b[i]);
|
||||||
|
if (a_lower != b_lower)
|
||||||
|
return a_lower - b_lower;
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
char *strcasestr_retro__(const char *haystack, const char *needle)
|
||||||
|
{
|
||||||
|
size_t i, search_off;
|
||||||
|
size_t hay_len = strlen(haystack);
|
||||||
|
size_t needle_len = strlen(needle);
|
||||||
|
|
||||||
|
if (needle_len > hay_len)
|
||||||
|
return NULL;
|
||||||
|
|
||||||
|
search_off = hay_len - needle_len;
|
||||||
|
for (i = 0; i <= search_off; i++)
|
||||||
|
if (!casencmp(haystack + i, needle, needle_len))
|
||||||
|
return (char*)haystack + i;
|
||||||
|
|
||||||
|
return NULL;
|
||||||
|
}
|
69
libretro-common/compat/compat_strl.c
Normal file
69
libretro-common/compat/compat_strl.c
Normal file
@ -0,0 +1,69 @@
|
|||||||
|
/* Copyright (C) 2010-2020 The RetroArch team
|
||||||
|
*
|
||||||
|
* ---------------------------------------------------------------------------------------
|
||||||
|
* The following license statement only applies to this file (compat_strl.c).
|
||||||
|
* ---------------------------------------------------------------------------------------
|
||||||
|
*
|
||||||
|
* Permission is hereby granted, free of charge,
|
||||||
|
* to any person obtaining a copy of this software and associated documentation files (the "Software"),
|
||||||
|
* to deal in the Software without restriction, including without limitation the rights to
|
||||||
|
* use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software,
|
||||||
|
* and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
|
||||||
|
*
|
||||||
|
* The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
|
||||||
|
*
|
||||||
|
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
|
||||||
|
* INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
|
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
|
||||||
|
* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
|
||||||
|
* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||||
|
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <ctype.h>
|
||||||
|
|
||||||
|
#include <compat/strl.h>
|
||||||
|
|
||||||
|
/* Implementation of strlcpy()/strlcat() based on OpenBSD. */
|
||||||
|
|
||||||
|
#ifndef __MACH__
|
||||||
|
|
||||||
|
size_t strlcpy(char *dest, const char *source, size_t size)
|
||||||
|
{
|
||||||
|
size_t src_size = 0;
|
||||||
|
size_t n = size;
|
||||||
|
|
||||||
|
if (n)
|
||||||
|
while (--n && (*dest++ = *source++)) src_size++;
|
||||||
|
|
||||||
|
if (!n)
|
||||||
|
{
|
||||||
|
if (size) *dest = '\0';
|
||||||
|
while (*source++) src_size++;
|
||||||
|
}
|
||||||
|
|
||||||
|
return src_size;
|
||||||
|
}
|
||||||
|
|
||||||
|
size_t strlcat(char *dest, const char *source, size_t size)
|
||||||
|
{
|
||||||
|
size_t len = strlen(dest);
|
||||||
|
|
||||||
|
dest += len;
|
||||||
|
|
||||||
|
if (len > size)
|
||||||
|
size = 0;
|
||||||
|
else
|
||||||
|
size -= len;
|
||||||
|
|
||||||
|
return len + strlcpy(dest, source, size);
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
char *strldup(const char *s, size_t n)
|
||||||
|
{
|
||||||
|
char *dst = (char*)malloc(sizeof(char) * (n + 1));
|
||||||
|
strlcpy(dst, s, n);
|
||||||
|
return dst;
|
||||||
|
}
|
63
libretro-common/compat/fopen_utf8.c
Normal file
63
libretro-common/compat/fopen_utf8.c
Normal file
@ -0,0 +1,63 @@
|
|||||||
|
/* Copyright (C) 2010-2020 The RetroArch team
|
||||||
|
*
|
||||||
|
* ---------------------------------------------------------------------------------------
|
||||||
|
* The following license statement only applies to this file (fopen_utf8.c).
|
||||||
|
* ---------------------------------------------------------------------------------------
|
||||||
|
*
|
||||||
|
* Permission is hereby granted, free of charge,
|
||||||
|
* to any person obtaining a copy of this software and associated documentation files (the "Software"),
|
||||||
|
* to deal in the Software without restriction, including without limitation the rights to
|
||||||
|
* use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software,
|
||||||
|
* and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
|
||||||
|
*
|
||||||
|
* The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
|
||||||
|
*
|
||||||
|
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
|
||||||
|
* INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
|
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
|
||||||
|
* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
|
||||||
|
* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||||
|
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <compat/fopen_utf8.h>
|
||||||
|
#include <encodings/utf.h>
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
|
||||||
|
#if defined(_WIN32_WINNT) && _WIN32_WINNT < 0x0500 || defined(_XBOX)
|
||||||
|
#ifndef LEGACY_WIN32
|
||||||
|
#define LEGACY_WIN32
|
||||||
|
#endif
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifdef _WIN32
|
||||||
|
#undef fopen
|
||||||
|
|
||||||
|
void *fopen_utf8(const char * filename, const char * mode)
|
||||||
|
{
|
||||||
|
#if defined(LEGACY_WIN32)
|
||||||
|
FILE *ret = NULL;
|
||||||
|
char * filename_local = utf8_to_local_string_alloc(filename);
|
||||||
|
|
||||||
|
if (!filename_local)
|
||||||
|
return NULL;
|
||||||
|
ret = fopen(filename_local, mode);
|
||||||
|
if (filename_local)
|
||||||
|
free(filename_local);
|
||||||
|
return ret;
|
||||||
|
#else
|
||||||
|
wchar_t * filename_w = utf8_to_utf16_string_alloc(filename);
|
||||||
|
wchar_t * mode_w = utf8_to_utf16_string_alloc(mode);
|
||||||
|
FILE* ret = NULL;
|
||||||
|
|
||||||
|
if (filename_w && mode_w)
|
||||||
|
ret = _wfopen(filename_w, mode_w);
|
||||||
|
if (filename_w)
|
||||||
|
free(filename_w);
|
||||||
|
if (mode_w)
|
||||||
|
free(mode_w);
|
||||||
|
return ret;
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
#endif
|
512
libretro-common/encodings/encoding_utf.c
Normal file
512
libretro-common/encodings/encoding_utf.c
Normal file
@ -0,0 +1,512 @@
|
|||||||
|
/* Copyright (C) 2010-2020 The RetroArch team
|
||||||
|
*
|
||||||
|
* ---------------------------------------------------------------------------------------
|
||||||
|
* The following license statement only applies to this file (encoding_utf.c).
|
||||||
|
* ---------------------------------------------------------------------------------------
|
||||||
|
*
|
||||||
|
* Permission is hereby granted, free of charge,
|
||||||
|
* to any person obtaining a copy of this software and associated documentation files (the "Software"),
|
||||||
|
* to deal in the Software without restriction, including without limitation the rights to
|
||||||
|
* use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software,
|
||||||
|
* and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
|
||||||
|
*
|
||||||
|
* The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
|
||||||
|
*
|
||||||
|
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
|
||||||
|
* INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
|
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
|
||||||
|
* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
|
||||||
|
* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||||
|
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <stdint.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <stddef.h>
|
||||||
|
#include <string.h>
|
||||||
|
|
||||||
|
#include <boolean.h>
|
||||||
|
#include <compat/strl.h>
|
||||||
|
#include <retro_inline.h>
|
||||||
|
|
||||||
|
#include <encodings/utf.h>
|
||||||
|
|
||||||
|
#if defined(_WIN32) && !defined(_XBOX)
|
||||||
|
#include <windows.h>
|
||||||
|
#elif defined(_XBOX)
|
||||||
|
#include <xtl.h>
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#define UTF8_WALKBYTE(string) (*((*(string))++))
|
||||||
|
|
||||||
|
static unsigned leading_ones(uint8_t c)
|
||||||
|
{
|
||||||
|
unsigned ones = 0;
|
||||||
|
while (c & 0x80)
|
||||||
|
{
|
||||||
|
ones++;
|
||||||
|
c <<= 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
return ones;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Simple implementation. Assumes the sequence is
|
||||||
|
* properly synchronized and terminated. */
|
||||||
|
|
||||||
|
size_t utf8_conv_utf32(uint32_t *out, size_t out_chars,
|
||||||
|
const char *in, size_t in_size)
|
||||||
|
{
|
||||||
|
unsigned i;
|
||||||
|
size_t ret = 0;
|
||||||
|
while (in_size && out_chars)
|
||||||
|
{
|
||||||
|
unsigned extra, shift;
|
||||||
|
uint32_t c;
|
||||||
|
uint8_t first = *in++;
|
||||||
|
unsigned ones = leading_ones(first);
|
||||||
|
|
||||||
|
if (ones > 6 || ones == 1) /* Invalid or desync. */
|
||||||
|
break;
|
||||||
|
|
||||||
|
extra = ones ? ones - 1 : ones;
|
||||||
|
if (1 + extra > in_size) /* Overflow. */
|
||||||
|
break;
|
||||||
|
|
||||||
|
shift = (extra - 1) * 6;
|
||||||
|
c = (first & ((1 << (7 - ones)) - 1)) << (6 * extra);
|
||||||
|
|
||||||
|
for (i = 0; i < extra; i++, in++, shift -= 6)
|
||||||
|
c |= (*in & 0x3f) << shift;
|
||||||
|
|
||||||
|
*out++ = c;
|
||||||
|
in_size -= 1 + extra;
|
||||||
|
out_chars--;
|
||||||
|
ret++;
|
||||||
|
}
|
||||||
|
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool utf16_conv_utf8(uint8_t *out, size_t *out_chars,
|
||||||
|
const uint16_t *in, size_t in_size)
|
||||||
|
{
|
||||||
|
size_t out_pos = 0;
|
||||||
|
size_t in_pos = 0;
|
||||||
|
static const
|
||||||
|
uint8_t utf8_limits[5] = { 0xC0, 0xE0, 0xF0, 0xF8, 0xFC };
|
||||||
|
|
||||||
|
for (;;)
|
||||||
|
{
|
||||||
|
unsigned num_adds;
|
||||||
|
uint32_t value;
|
||||||
|
|
||||||
|
if (in_pos == in_size)
|
||||||
|
{
|
||||||
|
*out_chars = out_pos;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
value = in[in_pos++];
|
||||||
|
if (value < 0x80)
|
||||||
|
{
|
||||||
|
if (out)
|
||||||
|
out[out_pos] = (char)value;
|
||||||
|
out_pos++;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (value >= 0xD800 && value < 0xE000)
|
||||||
|
{
|
||||||
|
uint32_t c2;
|
||||||
|
|
||||||
|
if (value >= 0xDC00 || in_pos == in_size)
|
||||||
|
break;
|
||||||
|
c2 = in[in_pos++];
|
||||||
|
if (c2 < 0xDC00 || c2 >= 0xE000)
|
||||||
|
break;
|
||||||
|
value = (((value - 0xD800) << 10) | (c2 - 0xDC00)) + 0x10000;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (num_adds = 1; num_adds < 5; num_adds++)
|
||||||
|
if (value < (((uint32_t)1) << (num_adds * 5 + 6)))
|
||||||
|
break;
|
||||||
|
if (out)
|
||||||
|
out[out_pos] = (char)(utf8_limits[num_adds - 1]
|
||||||
|
+ (value >> (6 * num_adds)));
|
||||||
|
out_pos++;
|
||||||
|
do
|
||||||
|
{
|
||||||
|
num_adds--;
|
||||||
|
if (out)
|
||||||
|
out[out_pos] = (char)(0x80
|
||||||
|
+ ((value >> (6 * num_adds)) & 0x3F));
|
||||||
|
out_pos++;
|
||||||
|
}while (num_adds != 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
*out_chars = out_pos;
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Acts mostly like strlcpy.
|
||||||
|
*
|
||||||
|
* Copies the given number of UTF-8 characters,
|
||||||
|
* but at most d_len bytes.
|
||||||
|
*
|
||||||
|
* Always NULL terminates.
|
||||||
|
* Does not copy half a character.
|
||||||
|
*
|
||||||
|
* Returns number of bytes. 's' is assumed valid UTF-8.
|
||||||
|
* Use only if 'chars' is considerably less than 'd_len'. */
|
||||||
|
size_t utf8cpy(char *d, size_t d_len, const char *s, size_t chars)
|
||||||
|
{
|
||||||
|
const uint8_t *sb = (const uint8_t*)s;
|
||||||
|
const uint8_t *sb_org = sb;
|
||||||
|
|
||||||
|
if (!s)
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
while (*sb && chars-- > 0)
|
||||||
|
{
|
||||||
|
sb++;
|
||||||
|
while ((*sb & 0xC0) == 0x80)
|
||||||
|
sb++;
|
||||||
|
}
|
||||||
|
|
||||||
|
if ((size_t)(sb - sb_org) > d_len-1 /* NUL */)
|
||||||
|
{
|
||||||
|
sb = sb_org + d_len-1;
|
||||||
|
while ((*sb & 0xC0) == 0x80)
|
||||||
|
sb--;
|
||||||
|
}
|
||||||
|
|
||||||
|
memcpy(d, sb_org, sb-sb_org);
|
||||||
|
d[sb-sb_org] = '\0';
|
||||||
|
|
||||||
|
return sb-sb_org;
|
||||||
|
}
|
||||||
|
|
||||||
|
const char *utf8skip(const char *str, size_t chars)
|
||||||
|
{
|
||||||
|
const uint8_t *strb = (const uint8_t*)str;
|
||||||
|
|
||||||
|
if (!chars)
|
||||||
|
return str;
|
||||||
|
|
||||||
|
do
|
||||||
|
{
|
||||||
|
strb++;
|
||||||
|
while ((*strb & 0xC0)==0x80)
|
||||||
|
strb++;
|
||||||
|
chars--;
|
||||||
|
}while (chars);
|
||||||
|
|
||||||
|
return (const char*)strb;
|
||||||
|
}
|
||||||
|
|
||||||
|
size_t utf8len(const char *string)
|
||||||
|
{
|
||||||
|
size_t ret = 0;
|
||||||
|
|
||||||
|
if (!string)
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
while (*string)
|
||||||
|
{
|
||||||
|
if ((*string & 0xC0) != 0x80)
|
||||||
|
ret++;
|
||||||
|
string++;
|
||||||
|
}
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Does not validate the input, returns garbage if it's not UTF-8. */
|
||||||
|
uint32_t utf8_walk(const char **string)
|
||||||
|
{
|
||||||
|
uint8_t first = UTF8_WALKBYTE(string);
|
||||||
|
uint32_t ret = 0;
|
||||||
|
|
||||||
|
if (first < 128)
|
||||||
|
return first;
|
||||||
|
|
||||||
|
ret = (ret << 6) | (UTF8_WALKBYTE(string) & 0x3F);
|
||||||
|
if (first >= 0xE0)
|
||||||
|
{
|
||||||
|
ret = (ret << 6) | (UTF8_WALKBYTE(string) & 0x3F);
|
||||||
|
if (first >= 0xF0)
|
||||||
|
{
|
||||||
|
ret = (ret << 6) | (UTF8_WALKBYTE(string) & 0x3F);
|
||||||
|
return ret | (first & 7) << 18;
|
||||||
|
}
|
||||||
|
return ret | (first & 15) << 12;
|
||||||
|
}
|
||||||
|
|
||||||
|
return ret | (first & 31) << 6;
|
||||||
|
}
|
||||||
|
|
||||||
|
static bool utf16_to_char(uint8_t **utf_data,
|
||||||
|
size_t *dest_len, const uint16_t *in)
|
||||||
|
{
|
||||||
|
unsigned len = 0;
|
||||||
|
|
||||||
|
while (in[len] != '\0')
|
||||||
|
len++;
|
||||||
|
|
||||||
|
utf16_conv_utf8(NULL, dest_len, in, len);
|
||||||
|
*dest_len += 1;
|
||||||
|
*utf_data = (uint8_t*)malloc(*dest_len);
|
||||||
|
if (*utf_data == 0)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
return utf16_conv_utf8(*utf_data, dest_len, in, len);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool utf16_to_char_string(const uint16_t *in, char *s, size_t len)
|
||||||
|
{
|
||||||
|
size_t dest_len = 0;
|
||||||
|
uint8_t *utf16_data = NULL;
|
||||||
|
bool ret = utf16_to_char(&utf16_data, &dest_len, in);
|
||||||
|
|
||||||
|
if (ret)
|
||||||
|
{
|
||||||
|
utf16_data[dest_len] = 0;
|
||||||
|
strlcpy(s, (const char*)utf16_data, len);
|
||||||
|
}
|
||||||
|
|
||||||
|
free(utf16_data);
|
||||||
|
utf16_data = NULL;
|
||||||
|
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
#if defined(_WIN32) && !defined(_XBOX) && !defined(UNICODE)
|
||||||
|
/* Returned pointer MUST be freed by the caller if non-NULL. */
|
||||||
|
static char *mb_to_mb_string_alloc(const char *str,
|
||||||
|
enum CodePage cp_in, enum CodePage cp_out)
|
||||||
|
{
|
||||||
|
wchar_t *path_buf_wide = NULL;
|
||||||
|
int path_buf_wide_len = MultiByteToWideChar(cp_in, 0, str, -1, NULL, 0);
|
||||||
|
|
||||||
|
/* Windows 95 will return 0 from these functions with
|
||||||
|
* a UTF8 codepage set without MSLU.
|
||||||
|
*
|
||||||
|
* From an unknown MSDN version (others omit this info):
|
||||||
|
* - CP_UTF8 Windows 98/Me, Windows NT 4.0 and later:
|
||||||
|
* Translate using UTF-8. When this is set, dwFlags must be zero.
|
||||||
|
* - Windows 95: Under the Microsoft Layer for Unicode,
|
||||||
|
* MultiByteToWideChar also supports CP_UTF7 and CP_UTF8.
|
||||||
|
*/
|
||||||
|
|
||||||
|
if (!path_buf_wide_len)
|
||||||
|
return strdup(str);
|
||||||
|
|
||||||
|
path_buf_wide = (wchar_t*)
|
||||||
|
calloc(path_buf_wide_len + sizeof(wchar_t), sizeof(wchar_t));
|
||||||
|
|
||||||
|
if (path_buf_wide)
|
||||||
|
{
|
||||||
|
MultiByteToWideChar(cp_in, 0,
|
||||||
|
str, -1, path_buf_wide, path_buf_wide_len);
|
||||||
|
|
||||||
|
if (*path_buf_wide)
|
||||||
|
{
|
||||||
|
int path_buf_len = WideCharToMultiByte(cp_out, 0,
|
||||||
|
path_buf_wide, -1, NULL, 0, NULL, NULL);
|
||||||
|
|
||||||
|
if (path_buf_len)
|
||||||
|
{
|
||||||
|
char *path_buf = (char*)
|
||||||
|
calloc(path_buf_len + sizeof(char), sizeof(char));
|
||||||
|
|
||||||
|
if (path_buf)
|
||||||
|
{
|
||||||
|
WideCharToMultiByte(cp_out, 0,
|
||||||
|
path_buf_wide, -1, path_buf,
|
||||||
|
path_buf_len, NULL, NULL);
|
||||||
|
|
||||||
|
free(path_buf_wide);
|
||||||
|
|
||||||
|
if (*path_buf)
|
||||||
|
return path_buf;
|
||||||
|
|
||||||
|
free(path_buf);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
free(path_buf_wide);
|
||||||
|
return strdup(str);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
free(path_buf_wide);
|
||||||
|
}
|
||||||
|
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/* Returned pointer MUST be freed by the caller if non-NULL. */
|
||||||
|
char* utf8_to_local_string_alloc(const char *str)
|
||||||
|
{
|
||||||
|
if (str && *str)
|
||||||
|
{
|
||||||
|
#if defined(_WIN32) && !defined(_XBOX) && !defined(UNICODE)
|
||||||
|
return mb_to_mb_string_alloc(str, CODEPAGE_UTF8, CODEPAGE_LOCAL);
|
||||||
|
#else
|
||||||
|
/* assume string needs no modification if not on Windows */
|
||||||
|
return strdup(str);
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Returned pointer MUST be freed by the caller if non-NULL. */
|
||||||
|
char* local_to_utf8_string_alloc(const char *str)
|
||||||
|
{
|
||||||
|
if (str && *str)
|
||||||
|
{
|
||||||
|
#if defined(_WIN32) && !defined(_XBOX) && !defined(UNICODE)
|
||||||
|
return mb_to_mb_string_alloc(str, CODEPAGE_LOCAL, CODEPAGE_UTF8);
|
||||||
|
#else
|
||||||
|
/* assume string needs no modification if not on Windows */
|
||||||
|
return strdup(str);
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Returned pointer MUST be freed by the caller if non-NULL. */
|
||||||
|
wchar_t* utf8_to_utf16_string_alloc(const char *str)
|
||||||
|
{
|
||||||
|
#ifdef _WIN32
|
||||||
|
int len = 0;
|
||||||
|
int out_len = 0;
|
||||||
|
#else
|
||||||
|
size_t len = 0;
|
||||||
|
size_t out_len = 0;
|
||||||
|
#endif
|
||||||
|
wchar_t *buf = NULL;
|
||||||
|
|
||||||
|
if (!str || !*str)
|
||||||
|
return NULL;
|
||||||
|
|
||||||
|
#ifdef _WIN32
|
||||||
|
len = MultiByteToWideChar(CP_UTF8, 0, str, -1, NULL, 0);
|
||||||
|
|
||||||
|
if (len)
|
||||||
|
{
|
||||||
|
buf = (wchar_t*)calloc(len, sizeof(wchar_t));
|
||||||
|
|
||||||
|
if (!buf)
|
||||||
|
return NULL;
|
||||||
|
|
||||||
|
out_len = MultiByteToWideChar(CP_UTF8, 0, str, -1, buf, len);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
/* fallback to ANSI codepage instead */
|
||||||
|
len = MultiByteToWideChar(CP_ACP, 0, str, -1, NULL, 0);
|
||||||
|
|
||||||
|
if (len)
|
||||||
|
{
|
||||||
|
buf = (wchar_t*)calloc(len, sizeof(wchar_t));
|
||||||
|
|
||||||
|
if (!buf)
|
||||||
|
return NULL;
|
||||||
|
|
||||||
|
out_len = MultiByteToWideChar(CP_ACP, 0, str, -1, buf, len);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (out_len < 0)
|
||||||
|
{
|
||||||
|
free(buf);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
#else
|
||||||
|
/* NOTE: For now, assume non-Windows platforms' locale is already UTF-8. */
|
||||||
|
len = mbstowcs(NULL, str, 0) + 1;
|
||||||
|
|
||||||
|
if (len)
|
||||||
|
{
|
||||||
|
buf = (wchar_t*)calloc(len, sizeof(wchar_t));
|
||||||
|
|
||||||
|
if (!buf)
|
||||||
|
return NULL;
|
||||||
|
|
||||||
|
out_len = mbstowcs(buf, str, len);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (out_len == (size_t)-1)
|
||||||
|
{
|
||||||
|
free(buf);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
return buf;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Returned pointer MUST be freed by the caller if non-NULL. */
|
||||||
|
char* utf16_to_utf8_string_alloc(const wchar_t *str)
|
||||||
|
{
|
||||||
|
#ifdef _WIN32
|
||||||
|
int len = 0;
|
||||||
|
#else
|
||||||
|
size_t len = 0;
|
||||||
|
#endif
|
||||||
|
char *buf = NULL;
|
||||||
|
|
||||||
|
if (!str || !*str)
|
||||||
|
return NULL;
|
||||||
|
|
||||||
|
#ifdef _WIN32
|
||||||
|
{
|
||||||
|
UINT code_page = CP_UTF8;
|
||||||
|
len = WideCharToMultiByte(code_page,
|
||||||
|
0, str, -1, NULL, 0, NULL, NULL);
|
||||||
|
|
||||||
|
/* fallback to ANSI codepage instead */
|
||||||
|
if (!len)
|
||||||
|
{
|
||||||
|
code_page = CP_ACP;
|
||||||
|
len = WideCharToMultiByte(code_page,
|
||||||
|
0, str, -1, NULL, 0, NULL, NULL);
|
||||||
|
}
|
||||||
|
|
||||||
|
buf = (char*)calloc(len, sizeof(char));
|
||||||
|
|
||||||
|
if (!buf)
|
||||||
|
return NULL;
|
||||||
|
|
||||||
|
if (WideCharToMultiByte(code_page,
|
||||||
|
0, str, -1, buf, len, NULL, NULL) < 0)
|
||||||
|
{
|
||||||
|
free(buf);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#else
|
||||||
|
/* NOTE: For now, assume non-Windows platforms'
|
||||||
|
* locale is already UTF-8. */
|
||||||
|
len = wcstombs(NULL, str, 0) + 1;
|
||||||
|
|
||||||
|
if (len)
|
||||||
|
{
|
||||||
|
buf = (char*)calloc(len, sizeof(char));
|
||||||
|
|
||||||
|
if (!buf)
|
||||||
|
return NULL;
|
||||||
|
|
||||||
|
if (wcstombs(buf, str, len) == (size_t)-1)
|
||||||
|
{
|
||||||
|
free(buf);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
return buf;
|
||||||
|
}
|
1381
libretro-common/file/file_path.c
Normal file
1381
libretro-common/file/file_path.c
Normal file
File diff suppressed because it is too large
Load Diff
151
libretro-common/file/file_path_io.c
Normal file
151
libretro-common/file/file_path_io.c
Normal file
@ -0,0 +1,151 @@
|
|||||||
|
/* Copyright (C) 2010-2020 The RetroArch team
|
||||||
|
*
|
||||||
|
* ---------------------------------------------------------------------------------------
|
||||||
|
* The following license statement only applies to this file (file_path_io.c).
|
||||||
|
* ---------------------------------------------------------------------------------------
|
||||||
|
*
|
||||||
|
* Permission is hereby granted, free of charge,
|
||||||
|
* to any person obtaining a copy of this software and associated documentation files (the "Software"),
|
||||||
|
* to deal in the Software without restriction, including without limitation the rights to
|
||||||
|
* use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software,
|
||||||
|
* and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
|
||||||
|
*
|
||||||
|
* The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
|
||||||
|
*
|
||||||
|
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
|
||||||
|
* INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
|
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
|
||||||
|
* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
|
||||||
|
* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||||
|
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <string.h>
|
||||||
|
#include <time.h>
|
||||||
|
#include <errno.h>
|
||||||
|
|
||||||
|
#include <sys/stat.h>
|
||||||
|
|
||||||
|
#include <boolean.h>
|
||||||
|
#include <file/file_path.h>
|
||||||
|
#include <retro_assert.h>
|
||||||
|
#include <compat/strl.h>
|
||||||
|
#include <compat/posix_string.h>
|
||||||
|
#include <retro_miscellaneous.h>
|
||||||
|
#include <string/stdstring.h>
|
||||||
|
#define VFS_FRONTEND
|
||||||
|
#include <vfs/vfs_implementation.h>
|
||||||
|
|
||||||
|
#ifdef _WIN32
|
||||||
|
#include <direct.h>
|
||||||
|
#else
|
||||||
|
#include <unistd.h> /* stat() is defined here */
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/* TODO/FIXME - globals */
|
||||||
|
static retro_vfs_stat_t path_stat_cb = retro_vfs_stat_impl;
|
||||||
|
static retro_vfs_mkdir_t path_mkdir_cb = retro_vfs_mkdir_impl;
|
||||||
|
|
||||||
|
void path_vfs_init(const struct retro_vfs_interface_info* vfs_info)
|
||||||
|
{
|
||||||
|
const struct retro_vfs_interface*
|
||||||
|
vfs_iface = vfs_info->iface;
|
||||||
|
|
||||||
|
path_stat_cb = retro_vfs_stat_impl;
|
||||||
|
path_mkdir_cb = retro_vfs_mkdir_impl;
|
||||||
|
|
||||||
|
if (vfs_info->required_interface_version < PATH_REQUIRED_VFS_VERSION || !vfs_iface)
|
||||||
|
return;
|
||||||
|
|
||||||
|
path_stat_cb = vfs_iface->stat;
|
||||||
|
path_mkdir_cb = vfs_iface->mkdir;
|
||||||
|
}
|
||||||
|
|
||||||
|
int path_stat(const char *path)
|
||||||
|
{
|
||||||
|
return path_stat_cb(path, NULL);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* path_is_directory:
|
||||||
|
* @path : path
|
||||||
|
*
|
||||||
|
* Checks if path is a directory.
|
||||||
|
*
|
||||||
|
* Returns: true (1) if path is a directory, otherwise false (0).
|
||||||
|
*/
|
||||||
|
bool path_is_directory(const char *path)
|
||||||
|
{
|
||||||
|
return (path_stat_cb(path, NULL) & RETRO_VFS_STAT_IS_DIRECTORY) != 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool path_is_character_special(const char *path)
|
||||||
|
{
|
||||||
|
return (path_stat_cb(path, NULL) & RETRO_VFS_STAT_IS_CHARACTER_SPECIAL) != 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool path_is_valid(const char *path)
|
||||||
|
{
|
||||||
|
return (path_stat_cb(path, NULL) & RETRO_VFS_STAT_IS_VALID) != 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
int32_t path_get_size(const char *path)
|
||||||
|
{
|
||||||
|
int32_t filesize = 0;
|
||||||
|
if (path_stat_cb(path, &filesize) != 0)
|
||||||
|
return filesize;
|
||||||
|
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* path_mkdir:
|
||||||
|
* @dir : directory
|
||||||
|
*
|
||||||
|
* Create directory on filesystem.
|
||||||
|
*
|
||||||
|
* Returns: true (1) if directory could be created, otherwise false (0).
|
||||||
|
**/
|
||||||
|
bool path_mkdir(const char *dir)
|
||||||
|
{
|
||||||
|
bool norecurse = false;
|
||||||
|
char *basedir = NULL;
|
||||||
|
|
||||||
|
if (!(dir && *dir))
|
||||||
|
return false;
|
||||||
|
|
||||||
|
/* Use heap. Real chance of stack
|
||||||
|
* overflow if we recurse too hard. */
|
||||||
|
basedir = strdup(dir);
|
||||||
|
|
||||||
|
if (!basedir)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
path_parent_dir(basedir);
|
||||||
|
|
||||||
|
if (!*basedir || !strcmp(basedir, dir))
|
||||||
|
{
|
||||||
|
free(basedir);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if ( path_is_directory(basedir)
|
||||||
|
|| path_mkdir(basedir))
|
||||||
|
norecurse = true;
|
||||||
|
|
||||||
|
free(basedir);
|
||||||
|
|
||||||
|
if (norecurse)
|
||||||
|
{
|
||||||
|
int ret = path_mkdir_cb(dir);
|
||||||
|
|
||||||
|
/* Don't treat this as an error. */
|
||||||
|
if (ret == -2 && path_is_directory(dir))
|
||||||
|
return true;
|
||||||
|
else if (ret == 0)
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
39
libretro-common/include/boolean.h
Normal file
39
libretro-common/include/boolean.h
Normal file
@ -0,0 +1,39 @@
|
|||||||
|
/* Copyright (C) 2010-2020 The RetroArch team
|
||||||
|
*
|
||||||
|
* ---------------------------------------------------------------------------------------
|
||||||
|
* The following license statement only applies to this file (boolean.h).
|
||||||
|
* ---------------------------------------------------------------------------------------
|
||||||
|
*
|
||||||
|
* Permission is hereby granted, free of charge,
|
||||||
|
* to any person obtaining a copy of this software and associated documentation files (the "Software"),
|
||||||
|
* to deal in the Software without restriction, including without limitation the rights to
|
||||||
|
* use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software,
|
||||||
|
* and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
|
||||||
|
*
|
||||||
|
* The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
|
||||||
|
*
|
||||||
|
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
|
||||||
|
* INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
|
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
|
||||||
|
* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
|
||||||
|
* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||||
|
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef __LIBRETRO_SDK_BOOLEAN_H
|
||||||
|
#define __LIBRETRO_SDK_BOOLEAN_H
|
||||||
|
|
||||||
|
#ifndef __cplusplus
|
||||||
|
|
||||||
|
#if defined(_MSC_VER) && _MSC_VER < 1800 && !defined(SN_TARGET_PS3)
|
||||||
|
/* Hack applied for MSVC when compiling in C89 mode as it isn't C99 compliant. */
|
||||||
|
#define bool unsigned char
|
||||||
|
#define true 1
|
||||||
|
#define false 0
|
||||||
|
#else
|
||||||
|
#include <stdbool.h>
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#endif
|
34
libretro-common/include/compat/fopen_utf8.h
Normal file
34
libretro-common/include/compat/fopen_utf8.h
Normal file
@ -0,0 +1,34 @@
|
|||||||
|
/* Copyright (C) 2010-2020 The RetroArch team
|
||||||
|
*
|
||||||
|
* ---------------------------------------------------------------------------------------
|
||||||
|
* The following license statement only applies to this file (fopen_utf8.h).
|
||||||
|
* ---------------------------------------------------------------------------------------
|
||||||
|
*
|
||||||
|
* Permission is hereby granted, free of charge,
|
||||||
|
* to any person obtaining a copy of this software and associated documentation files (the "Software"),
|
||||||
|
* to deal in the Software without restriction, including without limitation the rights to
|
||||||
|
* use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software,
|
||||||
|
* and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
|
||||||
|
*
|
||||||
|
* The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
|
||||||
|
*
|
||||||
|
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
|
||||||
|
* INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
|
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
|
||||||
|
* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
|
||||||
|
* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||||
|
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef __LIBRETRO_SDK_COMPAT_FOPEN_UTF8_H
|
||||||
|
#define __LIBRETRO_SDK_COMPAT_FOPEN_UTF8_H
|
||||||
|
|
||||||
|
#ifdef _WIN32
|
||||||
|
/* Defined to error rather than fopen_utf8, to make it clear to everyone reading the code that not worrying about utf16 is fine */
|
||||||
|
/* TODO: enable */
|
||||||
|
/* #define fopen (use fopen_utf8 instead) */
|
||||||
|
void *fopen_utf8(const char * filename, const char * mode);
|
||||||
|
#else
|
||||||
|
#define fopen_utf8 fopen
|
||||||
|
#endif
|
||||||
|
#endif
|
@ -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 (msvc.h).
|
* The following license statement only applies to this file (msvc.h).
|
||||||
@ -29,20 +29,17 @@
|
|||||||
extern "C" {
|
extern "C" {
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
/* Pre-MSVC 2015 compilers don't implement snprintf in a cross-platform manner. */
|
/* Pre-MSVC 2015 compilers don't implement snprintf, vsnprintf in a cross-platform manner. */
|
||||||
#if _MSC_VER < 1900
|
#if _MSC_VER < 1900
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <stdarg.h>
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
|
|
||||||
#ifndef snprintf
|
#ifndef snprintf
|
||||||
#define snprintf c99_snprintf_retro__
|
#define snprintf c99_snprintf_retro__
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
int c99_snprintf_retro__(char *outBuf, size_t size, const char *format, ...);
|
int c99_snprintf_retro__(char *outBuf, size_t size, const char *format, ...);
|
||||||
#endif
|
|
||||||
|
|
||||||
/* Pre-MSVC 2010 compilers don't implement vsnprintf in a cross-platform manner? Not sure about this one. */
|
|
||||||
#if _MSC_VER < 1600
|
|
||||||
#include <stdarg.h>
|
|
||||||
#include <stdlib.h>
|
|
||||||
#ifndef vsnprintf
|
#ifndef vsnprintf
|
||||||
#define vsnprintf c99_vsnprintf_retro__
|
#define vsnprintf c99_vsnprintf_retro__
|
||||||
#endif
|
#endif
|
||||||
@ -56,6 +53,8 @@ extern "C" {
|
|||||||
#undef UNICODE /* Do not bother with UNICODE at this time. */
|
#undef UNICODE /* Do not bother with UNICODE at this time. */
|
||||||
#include <direct.h>
|
#include <direct.h>
|
||||||
#include <stddef.h>
|
#include <stddef.h>
|
||||||
|
|
||||||
|
#define _USE_MATH_DEFINES
|
||||||
#include <math.h>
|
#include <math.h>
|
||||||
|
|
||||||
/* Python headers defines ssize_t and sets HAVE_SSIZE_T.
|
/* Python headers defines ssize_t and sets HAVE_SSIZE_T.
|
||||||
@ -86,9 +85,33 @@ typedef int ssize_t;
|
|||||||
#pragma warning(disable : 4723)
|
#pragma warning(disable : 4723)
|
||||||
#pragma warning(disable : 4996)
|
#pragma warning(disable : 4996)
|
||||||
|
|
||||||
/* roundf is available since MSVC 2013 */
|
/* roundf and va_copy is available since MSVC 2013 */
|
||||||
#if _MSC_VER < 1800
|
#if _MSC_VER < 1800
|
||||||
#define roundf(in) (in >= 0.0f ? floorf(in + 0.5f) : ceilf(in - 0.5f))
|
#define roundf(in) (in >= 0.0f ? floorf(in + 0.5f) : ceilf(in - 0.5f))
|
||||||
|
#define va_copy(x, y) ((x) = (y))
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if _MSC_VER <= 1310
|
||||||
|
#ifndef __cplusplus
|
||||||
|
/* VC6 math.h doesn't define some functions when in C mode.
|
||||||
|
* Trying to define a prototype gives "undefined reference".
|
||||||
|
* But providing an implementation then gives "function already has body".
|
||||||
|
* So the equivalent of the implementations from math.h are used as
|
||||||
|
* defines here instead, and it seems to work.
|
||||||
|
*/
|
||||||
|
#define cosf(x) ((float)cos((double)x))
|
||||||
|
#define powf(x, y) ((float)pow((double)x, (double)y))
|
||||||
|
#define sinf(x) ((float)sin((double)x))
|
||||||
|
#define ceilf(x) ((float)ceil((double)x))
|
||||||
|
#define floorf(x) ((float)floor((double)x))
|
||||||
|
#define sqrtf(x) ((float)sqrt((double)x))
|
||||||
|
#define fabsf(x) ((float)fabs((double)(x)))
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifndef _strtoui64
|
||||||
|
#define _strtoui64(x, y, z) (_atoi64(x))
|
||||||
|
#endif
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#ifndef PATH_MAX
|
#ifndef PATH_MAX
|
||||||
|
@ -47,8 +47,12 @@
|
|||||||
* error C2733: second C linkage of overloaded function 'wmemchr' not allowed
|
* error C2733: second C linkage of overloaded function 'wmemchr' not allowed
|
||||||
*/
|
*/
|
||||||
#ifdef __cplusplus
|
#ifdef __cplusplus
|
||||||
|
#if _MSC_VER <= 1200
|
||||||
|
extern "C++" {
|
||||||
|
#else
|
||||||
extern "C" {
|
extern "C" {
|
||||||
#endif
|
#endif
|
||||||
|
#endif
|
||||||
# include <wchar.h>
|
# include <wchar.h>
|
||||||
#ifdef __cplusplus
|
#ifdef __cplusplus
|
||||||
}
|
}
|
||||||
@ -63,7 +67,6 @@ extern "C" {
|
|||||||
# endif
|
# endif
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
|
||||||
/* 7.18.1 Integer types. */
|
/* 7.18.1 Integer types. */
|
||||||
|
|
||||||
/* 7.18.1.1 Exact-width integer types. */
|
/* 7.18.1.1 Exact-width integer types. */
|
||||||
@ -90,7 +93,6 @@ extern "C" {
|
|||||||
typedef signed __int64 int64_t;
|
typedef signed __int64 int64_t;
|
||||||
typedef unsigned __int64 uint64_t;
|
typedef unsigned __int64 uint64_t;
|
||||||
|
|
||||||
|
|
||||||
/* 7.18.1.2 Minimum-width integer types. */
|
/* 7.18.1.2 Minimum-width integer types. */
|
||||||
typedef int8_t int_least8_t;
|
typedef int8_t int_least8_t;
|
||||||
typedef int16_t int_least16_t;
|
typedef int16_t int_least16_t;
|
||||||
|
60
libretro-common/include/compat/posix_string.h
Normal file
60
libretro-common/include/compat/posix_string.h
Normal file
@ -0,0 +1,60 @@
|
|||||||
|
/* Copyright (C) 2010-2020 The RetroArch team
|
||||||
|
*
|
||||||
|
* ---------------------------------------------------------------------------------------
|
||||||
|
* The following license statement only applies to this file (posix_string.h).
|
||||||
|
* ---------------------------------------------------------------------------------------
|
||||||
|
*
|
||||||
|
* Permission is hereby granted, free of charge,
|
||||||
|
* to any person obtaining a copy of this software and associated documentation files (the "Software"),
|
||||||
|
* to deal in the Software without restriction, including without limitation the rights to
|
||||||
|
* use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software,
|
||||||
|
* and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
|
||||||
|
*
|
||||||
|
* The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
|
||||||
|
*
|
||||||
|
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
|
||||||
|
* INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
|
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
|
||||||
|
* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
|
||||||
|
* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||||
|
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef __LIBRETRO_SDK_COMPAT_POSIX_STRING_H
|
||||||
|
#define __LIBRETRO_SDK_COMPAT_POSIX_STRING_H
|
||||||
|
|
||||||
|
#include <retro_common_api.h>
|
||||||
|
|
||||||
|
#ifdef _MSC_VER
|
||||||
|
#include <compat/msvc.h>
|
||||||
|
#endif
|
||||||
|
|
||||||
|
RETRO_BEGIN_DECLS
|
||||||
|
|
||||||
|
#ifdef _WIN32
|
||||||
|
#undef strtok_r
|
||||||
|
#define strtok_r(str, delim, saveptr) retro_strtok_r__(str, delim, saveptr)
|
||||||
|
|
||||||
|
char *strtok_r(char *str, const char *delim, char **saveptr);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifdef _MSC_VER
|
||||||
|
#undef strcasecmp
|
||||||
|
#undef strdup
|
||||||
|
#define strcasecmp(a, b) retro_strcasecmp__(a, b)
|
||||||
|
#define strdup(orig) retro_strdup__(orig)
|
||||||
|
int strcasecmp(const char *a, const char *b);
|
||||||
|
char *strdup(const char *orig);
|
||||||
|
|
||||||
|
/* isblank is available since MSVC 2013 */
|
||||||
|
#if _MSC_VER < 1800
|
||||||
|
#undef isblank
|
||||||
|
#define isblank(c) retro_isblank__(c)
|
||||||
|
int isblank(int c);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
||||||
|
RETRO_END_DECLS
|
||||||
|
|
||||||
|
#endif
|
48
libretro-common/include/compat/strcasestr.h
Normal file
48
libretro-common/include/compat/strcasestr.h
Normal file
@ -0,0 +1,48 @@
|
|||||||
|
/* Copyright (C) 2010-2020 The RetroArch team
|
||||||
|
*
|
||||||
|
* ---------------------------------------------------------------------------------------
|
||||||
|
* The following license statement only applies to this file (strcasestr.h).
|
||||||
|
* ---------------------------------------------------------------------------------------
|
||||||
|
*
|
||||||
|
* Permission is hereby granted, free of charge,
|
||||||
|
* to any person obtaining a copy of this software and associated documentation files (the "Software"),
|
||||||
|
* to deal in the Software without restriction, including without limitation the rights to
|
||||||
|
* use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software,
|
||||||
|
* and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
|
||||||
|
*
|
||||||
|
* The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
|
||||||
|
*
|
||||||
|
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
|
||||||
|
* INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
|
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
|
||||||
|
* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
|
||||||
|
* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||||
|
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef __LIBRETRO_SDK_COMPAT_STRCASESTR_H
|
||||||
|
#define __LIBRETRO_SDK_COMPAT_STRCASESTR_H
|
||||||
|
|
||||||
|
#include <string.h>
|
||||||
|
|
||||||
|
#if defined(RARCH_INTERNAL) && defined(HAVE_CONFIG_H)
|
||||||
|
#include "../../../config.h"
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifndef HAVE_STRCASESTR
|
||||||
|
|
||||||
|
#include <retro_common_api.h>
|
||||||
|
|
||||||
|
RETRO_BEGIN_DECLS
|
||||||
|
|
||||||
|
/* Avoid possible naming collisions during link
|
||||||
|
* since we prefer to use the actual name. */
|
||||||
|
#define strcasestr(haystack, needle) strcasestr_retro__(haystack, needle)
|
||||||
|
|
||||||
|
char *strcasestr(const char *haystack, const char *needle);
|
||||||
|
|
||||||
|
RETRO_END_DECLS
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#endif
|
59
libretro-common/include/compat/strl.h
Normal file
59
libretro-common/include/compat/strl.h
Normal file
@ -0,0 +1,59 @@
|
|||||||
|
/* Copyright (C) 2010-2020 The RetroArch team
|
||||||
|
*
|
||||||
|
* ---------------------------------------------------------------------------------------
|
||||||
|
* The following license statement only applies to this file (strl.h).
|
||||||
|
* ---------------------------------------------------------------------------------------
|
||||||
|
*
|
||||||
|
* Permission is hereby granted, free of charge,
|
||||||
|
* to any person obtaining a copy of this software and associated documentation files (the "Software"),
|
||||||
|
* to deal in the Software without restriction, including without limitation the rights to
|
||||||
|
* use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software,
|
||||||
|
* and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
|
||||||
|
*
|
||||||
|
* The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
|
||||||
|
*
|
||||||
|
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
|
||||||
|
* INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
|
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
|
||||||
|
* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
|
||||||
|
* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||||
|
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef __LIBRETRO_SDK_COMPAT_STRL_H
|
||||||
|
#define __LIBRETRO_SDK_COMPAT_STRL_H
|
||||||
|
|
||||||
|
#include <string.h>
|
||||||
|
#include <stddef.h>
|
||||||
|
|
||||||
|
#if defined(RARCH_INTERNAL) && defined(HAVE_CONFIG_H)
|
||||||
|
#include "../../../config.h"
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#include <retro_common_api.h>
|
||||||
|
|
||||||
|
RETRO_BEGIN_DECLS
|
||||||
|
|
||||||
|
#ifdef __MACH__
|
||||||
|
#ifndef HAVE_STRL
|
||||||
|
#define HAVE_STRL
|
||||||
|
#endif
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifndef HAVE_STRL
|
||||||
|
/* Avoid possible naming collisions during link since
|
||||||
|
* we prefer to use the actual name. */
|
||||||
|
#define strlcpy(dst, src, size) strlcpy_retro__(dst, src, size)
|
||||||
|
|
||||||
|
#define strlcat(dst, src, size) strlcat_retro__(dst, src, size)
|
||||||
|
|
||||||
|
size_t strlcpy(char *dest, const char *source, size_t size);
|
||||||
|
size_t strlcat(char *dest, const char *source, size_t size);
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
||||||
|
char *strldup(const char *s, size_t n);
|
||||||
|
|
||||||
|
RETRO_END_DECLS
|
||||||
|
|
||||||
|
#endif
|
67
libretro-common/include/encodings/utf.h
Normal file
67
libretro-common/include/encodings/utf.h
Normal file
@ -0,0 +1,67 @@
|
|||||||
|
/* Copyright (C) 2010-2020 The RetroArch team
|
||||||
|
*
|
||||||
|
* ---------------------------------------------------------------------------------------
|
||||||
|
* The following license statement only applies to this file (utf.h).
|
||||||
|
* ---------------------------------------------------------------------------------------
|
||||||
|
*
|
||||||
|
* Permission is hereby granted, free of charge,
|
||||||
|
* to any person obtaining a copy of this software and associated documentation files (the "Software"),
|
||||||
|
* to deal in the Software without restriction, including without limitation the rights to
|
||||||
|
* use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software,
|
||||||
|
* and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
|
||||||
|
*
|
||||||
|
* The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
|
||||||
|
*
|
||||||
|
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
|
||||||
|
* INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
|
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
|
||||||
|
* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
|
||||||
|
* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||||
|
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef _LIBRETRO_ENCODINGS_UTF_H
|
||||||
|
#define _LIBRETRO_ENCODINGS_UTF_H
|
||||||
|
|
||||||
|
#include <stdint.h>
|
||||||
|
#include <stddef.h>
|
||||||
|
|
||||||
|
#include <boolean.h>
|
||||||
|
|
||||||
|
#include <retro_common_api.h>
|
||||||
|
|
||||||
|
RETRO_BEGIN_DECLS
|
||||||
|
|
||||||
|
enum CodePage
|
||||||
|
{
|
||||||
|
CODEPAGE_LOCAL = 0, /* CP_ACP */
|
||||||
|
CODEPAGE_UTF8 = 65001 /* CP_UTF8 */
|
||||||
|
};
|
||||||
|
|
||||||
|
size_t utf8_conv_utf32(uint32_t *out, size_t out_chars,
|
||||||
|
const char *in, size_t in_size);
|
||||||
|
|
||||||
|
bool utf16_conv_utf8(uint8_t *out, size_t *out_chars,
|
||||||
|
const uint16_t *in, size_t in_size);
|
||||||
|
|
||||||
|
size_t utf8len(const char *string);
|
||||||
|
|
||||||
|
size_t utf8cpy(char *d, size_t d_len, const char *s, size_t chars);
|
||||||
|
|
||||||
|
const char *utf8skip(const char *str, size_t chars);
|
||||||
|
|
||||||
|
uint32_t utf8_walk(const char **string);
|
||||||
|
|
||||||
|
bool utf16_to_char_string(const uint16_t *in, char *s, size_t len);
|
||||||
|
|
||||||
|
char* utf8_to_local_string_alloc(const char *str);
|
||||||
|
|
||||||
|
char* local_to_utf8_string_alloc(const char *str);
|
||||||
|
|
||||||
|
wchar_t* utf8_to_utf16_string_alloc(const char *str);
|
||||||
|
|
||||||
|
char* utf16_to_utf8_string_alloc(const wchar_t *str);
|
||||||
|
|
||||||
|
RETRO_END_DECLS
|
||||||
|
|
||||||
|
#endif
|
538
libretro-common/include/file/file_path.h
Normal file
538
libretro-common/include/file/file_path.h
Normal file
@ -0,0 +1,538 @@
|
|||||||
|
/* Copyright (C) 2010-2020 The RetroArch team
|
||||||
|
*
|
||||||
|
* ---------------------------------------------------------------------------------------
|
||||||
|
* The following license statement only applies to this file (file_path.h).
|
||||||
|
* ---------------------------------------------------------------------------------------
|
||||||
|
*
|
||||||
|
* Permission is hereby granted, free of charge,
|
||||||
|
* to any person obtaining a copy of this software and associated documentation files (the "Software"),
|
||||||
|
* to deal in the Software without restriction, including without limitation the rights to
|
||||||
|
* use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software,
|
||||||
|
* and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
|
||||||
|
*
|
||||||
|
* The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
|
||||||
|
*
|
||||||
|
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
|
||||||
|
* INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
|
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
|
||||||
|
* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
|
||||||
|
* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||||
|
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef __LIBRETRO_SDK_FILE_PATH_H
|
||||||
|
#define __LIBRETRO_SDK_FILE_PATH_H
|
||||||
|
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <stdint.h>
|
||||||
|
#include <stddef.h>
|
||||||
|
#include <sys/types.h>
|
||||||
|
|
||||||
|
#include <libretro.h>
|
||||||
|
#include <retro_common_api.h>
|
||||||
|
|
||||||
|
#include <boolean.h>
|
||||||
|
|
||||||
|
RETRO_BEGIN_DECLS
|
||||||
|
|
||||||
|
#define PATH_REQUIRED_VFS_VERSION 3
|
||||||
|
|
||||||
|
void path_vfs_init(const struct retro_vfs_interface_info* vfs_info);
|
||||||
|
|
||||||
|
/* Order in this enum is equivalent to negative sort order in filelist
|
||||||
|
* (i.e. DIRECTORY is on top of PLAIN_FILE) */
|
||||||
|
enum
|
||||||
|
{
|
||||||
|
RARCH_FILETYPE_UNSET,
|
||||||
|
RARCH_PLAIN_FILE,
|
||||||
|
RARCH_COMPRESSED_FILE_IN_ARCHIVE,
|
||||||
|
RARCH_COMPRESSED_ARCHIVE,
|
||||||
|
RARCH_DIRECTORY,
|
||||||
|
RARCH_FILE_UNSUPPORTED
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* path_is_compressed_file:
|
||||||
|
* @path : path
|
||||||
|
*
|
||||||
|
* Checks if path is a compressed file.
|
||||||
|
*
|
||||||
|
* Returns: true (1) if path is a compressed file, otherwise false (0).
|
||||||
|
**/
|
||||||
|
bool path_is_compressed_file(const char *path);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* path_contains_compressed_file:
|
||||||
|
* @path : path
|
||||||
|
*
|
||||||
|
* Checks if path contains a compressed file.
|
||||||
|
*
|
||||||
|
* Currently we only check for hash symbol (#) inside the pathname.
|
||||||
|
* If path is ever expanded to a general URI, we should check for that here.
|
||||||
|
*
|
||||||
|
* Example: Somewhere in the path there might be a compressed file
|
||||||
|
* E.g.: /path/to/file.7z#mygame.img
|
||||||
|
*
|
||||||
|
* Returns: true (1) if path contains compressed file, otherwise false (0).
|
||||||
|
**/
|
||||||
|
#define path_contains_compressed_file(path) (path_get_archive_delim((path)) != NULL)
|
||||||
|
|
||||||
|
/**
|
||||||
|
* path_get_archive_delim:
|
||||||
|
* @path : path
|
||||||
|
*
|
||||||
|
* Gets delimiter of an archive file. Only the first '#'
|
||||||
|
* after a compression extension is considered.
|
||||||
|
*
|
||||||
|
* Returns: pointer to the delimiter in the path if it contains
|
||||||
|
* a compressed file, otherwise NULL.
|
||||||
|
*/
|
||||||
|
const char *path_get_archive_delim(const char *path);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* path_get_extension:
|
||||||
|
* @path : path
|
||||||
|
*
|
||||||
|
* Gets extension of file. Only '.'s
|
||||||
|
* after the last slash are considered.
|
||||||
|
*
|
||||||
|
* Returns: extension part from the path.
|
||||||
|
*/
|
||||||
|
const char *path_get_extension(const char *path);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* path_remove_extension:
|
||||||
|
* @path : path
|
||||||
|
*
|
||||||
|
* Mutates path by removing its extension. Removes all
|
||||||
|
* text after and including the last '.'.
|
||||||
|
* Only '.'s after the last slash are considered.
|
||||||
|
*
|
||||||
|
* Returns:
|
||||||
|
* 1) If path has an extension, returns path with the
|
||||||
|
* extension removed.
|
||||||
|
* 2) If there is no extension, returns NULL.
|
||||||
|
* 3) If path is empty or NULL, returns NULL
|
||||||
|
*/
|
||||||
|
char *path_remove_extension(char *path);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* path_basename:
|
||||||
|
* @path : path
|
||||||
|
*
|
||||||
|
* Get basename from @path.
|
||||||
|
*
|
||||||
|
* Returns: basename from path.
|
||||||
|
**/
|
||||||
|
const char *path_basename(const char *path);
|
||||||
|
const char *path_basename_nocompression(const char *path);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* path_basedir:
|
||||||
|
* @path : path
|
||||||
|
*
|
||||||
|
* Extracts base directory by mutating path.
|
||||||
|
* Keeps trailing '/'.
|
||||||
|
**/
|
||||||
|
void path_basedir(char *path);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* path_parent_dir:
|
||||||
|
* @path : path
|
||||||
|
*
|
||||||
|
* Extracts parent directory by mutating path.
|
||||||
|
* Assumes that path is a directory. Keeps trailing '/'.
|
||||||
|
* If the path was already at the root directory, returns empty string
|
||||||
|
**/
|
||||||
|
void path_parent_dir(char *path);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* path_resolve_realpath:
|
||||||
|
* @buf : input and output buffer for path
|
||||||
|
* @size : size of buffer
|
||||||
|
* @resolve_symlinks : whether to resolve symlinks or not
|
||||||
|
*
|
||||||
|
* Resolves use of ".", "..", multiple slashes etc in absolute paths.
|
||||||
|
*
|
||||||
|
* 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
|
||||||
|
**/
|
||||||
|
char *path_resolve_realpath(char *buf, size_t size, bool resolve_symlinks);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* path_relative_to:
|
||||||
|
* @out : buffer to write the relative path to
|
||||||
|
* @path : path to be expressed relatively
|
||||||
|
* @base : relative to this
|
||||||
|
* @size : size of output buffer
|
||||||
|
*
|
||||||
|
* Turns @path into a path relative to @base and writes it to @out.
|
||||||
|
*
|
||||||
|
* @base is assumed to be a base directory, i.e. a path ending with '/' or '\'.
|
||||||
|
* Both @path and @base are assumed to be absolute paths without "." or "..".
|
||||||
|
*
|
||||||
|
* E.g. path /a/b/e/f.cgp with base /a/b/c/d/ turns into ../../e/f.cgp
|
||||||
|
**/
|
||||||
|
size_t path_relative_to(char *out, const char *path, const char *base, size_t size);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* path_is_absolute:
|
||||||
|
* @path : path
|
||||||
|
*
|
||||||
|
* Checks if @path is an absolute path or a relative path.
|
||||||
|
*
|
||||||
|
* Returns: true if path is absolute, false if path is relative.
|
||||||
|
**/
|
||||||
|
bool path_is_absolute(const char *path);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* fill_pathname:
|
||||||
|
* @out_path : output path
|
||||||
|
* @in_path : input path
|
||||||
|
* @replace : what to replace
|
||||||
|
* @size : buffer size of output path
|
||||||
|
*
|
||||||
|
* FIXME: Verify
|
||||||
|
*
|
||||||
|
* Replaces filename extension with 'replace' and outputs result to out_path.
|
||||||
|
* The extension here is considered to be the string from the last '.'
|
||||||
|
* to the end.
|
||||||
|
*
|
||||||
|
* Only '.'s after the last slash are considered as extensions.
|
||||||
|
* If no '.' is present, in_path and replace will simply be concatenated.
|
||||||
|
* 'size' is buffer size of 'out_path'.
|
||||||
|
* E.g.: in_path = "/foo/bar/baz/boo.c", replace = ".asm" =>
|
||||||
|
* out_path = "/foo/bar/baz/boo.asm"
|
||||||
|
* E.g.: in_path = "/foo/bar/baz/boo.c", replace = "" =>
|
||||||
|
* out_path = "/foo/bar/baz/boo"
|
||||||
|
*/
|
||||||
|
void fill_pathname(char *out_path, const char *in_path,
|
||||||
|
const char *replace, size_t size);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* fill_dated_filename:
|
||||||
|
* @out_filename : output filename
|
||||||
|
* @ext : extension of output filename
|
||||||
|
* @size : buffer size of output filename
|
||||||
|
*
|
||||||
|
* Creates a 'dated' filename prefixed by 'RetroArch', and
|
||||||
|
* concatenates extension (@ext) to it.
|
||||||
|
*
|
||||||
|
* E.g.:
|
||||||
|
* out_filename = "RetroArch-{month}{day}-{Hours}{Minutes}.{@ext}"
|
||||||
|
**/
|
||||||
|
size_t fill_dated_filename(char *out_filename,
|
||||||
|
const char *ext, size_t size);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* fill_str_dated_filename:
|
||||||
|
* @out_filename : output filename
|
||||||
|
* @in_str : input string
|
||||||
|
* @ext : extension of output filename
|
||||||
|
* @size : buffer size of output filename
|
||||||
|
*
|
||||||
|
* Creates a 'dated' filename prefixed by the string @in_str, and
|
||||||
|
* concatenates extension (@ext) to it.
|
||||||
|
*
|
||||||
|
* E.g.:
|
||||||
|
* out_filename = "RetroArch-{year}{month}{day}-{Hour}{Minute}{Second}.{@ext}"
|
||||||
|
**/
|
||||||
|
void fill_str_dated_filename(char *out_filename,
|
||||||
|
const char *in_str, const char *ext, size_t size);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* fill_pathname_noext:
|
||||||
|
* @out_path : output path
|
||||||
|
* @in_path : input path
|
||||||
|
* @replace : what to replace
|
||||||
|
* @size : buffer size of output path
|
||||||
|
*
|
||||||
|
* Appends a filename extension 'replace' to 'in_path', and outputs
|
||||||
|
* result in 'out_path'.
|
||||||
|
*
|
||||||
|
* Assumes in_path has no extension. If an extension is still
|
||||||
|
* present in 'in_path', it will be ignored.
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
size_t fill_pathname_noext(char *out_path, const char *in_path,
|
||||||
|
const char *replace, size_t size);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* find_last_slash:
|
||||||
|
* @str : input path
|
||||||
|
*
|
||||||
|
* Gets a pointer to the last slash in the input path.
|
||||||
|
*
|
||||||
|
* Returns: a pointer to the last slash in the input path.
|
||||||
|
**/
|
||||||
|
char *find_last_slash(const char *str);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* fill_pathname_dir:
|
||||||
|
* @in_dir : input directory path
|
||||||
|
* @in_basename : input basename to be appended to @in_dir
|
||||||
|
* @replace : replacement to be appended to @in_basename
|
||||||
|
* @size : size of buffer
|
||||||
|
*
|
||||||
|
* Appends basename of 'in_basename', to 'in_dir', along with 'replace'.
|
||||||
|
* Basename of in_basename is the string after the last '/' or '\\',
|
||||||
|
* i.e the filename without directories.
|
||||||
|
*
|
||||||
|
* If in_basename has no '/' or '\\', the whole 'in_basename' will be used.
|
||||||
|
* 'size' is buffer size of 'in_dir'.
|
||||||
|
*
|
||||||
|
* E.g..: in_dir = "/tmp/some_dir", in_basename = "/some_content/foo.c",
|
||||||
|
* replace = ".asm" => in_dir = "/tmp/some_dir/foo.c.asm"
|
||||||
|
**/
|
||||||
|
size_t fill_pathname_dir(char *in_dir, const char *in_basename,
|
||||||
|
const char *replace, size_t size);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* fill_pathname_base:
|
||||||
|
* @out : output path
|
||||||
|
* @in_path : input path
|
||||||
|
* @size : size of output path
|
||||||
|
*
|
||||||
|
* Copies basename of @in_path into @out_path.
|
||||||
|
**/
|
||||||
|
size_t fill_pathname_base(char *out_path, const char *in_path, size_t size);
|
||||||
|
|
||||||
|
void fill_pathname_base_noext(char *out_dir,
|
||||||
|
const char *in_path, size_t size);
|
||||||
|
|
||||||
|
size_t fill_pathname_base_ext(char *out,
|
||||||
|
const char *in_path, const char *ext,
|
||||||
|
size_t size);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* fill_pathname_basedir:
|
||||||
|
* @out_dir : output directory
|
||||||
|
* @in_path : input path
|
||||||
|
* @size : size of output directory
|
||||||
|
*
|
||||||
|
* Copies base directory of @in_path into @out_path.
|
||||||
|
* If in_path is a path without any slashes (relative current directory),
|
||||||
|
* @out_path will get path "./".
|
||||||
|
**/
|
||||||
|
void fill_pathname_basedir(char *out_path, const char *in_path, size_t size);
|
||||||
|
|
||||||
|
void fill_pathname_basedir_noext(char *out_dir,
|
||||||
|
const char *in_path, size_t size);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* fill_pathname_parent_dir_name:
|
||||||
|
* @out_dir : output directory
|
||||||
|
* @in_dir : input directory
|
||||||
|
* @size : size of output directory
|
||||||
|
*
|
||||||
|
* Copies only the parent directory name of @in_dir into @out_dir.
|
||||||
|
* The two buffers must not overlap. Removes trailing '/'.
|
||||||
|
* Returns true on success, false if a slash was not found in the path.
|
||||||
|
**/
|
||||||
|
bool fill_pathname_parent_dir_name(char *out_dir,
|
||||||
|
const char *in_dir, size_t size);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* fill_pathname_parent_dir:
|
||||||
|
* @out_dir : output directory
|
||||||
|
* @in_dir : input directory
|
||||||
|
* @size : size of output directory
|
||||||
|
*
|
||||||
|
* Copies parent directory of @in_dir into @out_dir.
|
||||||
|
* Assumes @in_dir is a directory. Keeps trailing '/'.
|
||||||
|
* If the path was already at the root directory, @out_dir will be an empty string.
|
||||||
|
**/
|
||||||
|
void fill_pathname_parent_dir(char *out_dir,
|
||||||
|
const char *in_dir, size_t size);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* fill_pathname_resolve_relative:
|
||||||
|
* @out_path : output path
|
||||||
|
* @in_refpath : input reference path
|
||||||
|
* @in_path : input path
|
||||||
|
* @size : size of @out_path
|
||||||
|
*
|
||||||
|
* Joins basedir of @in_refpath together with @in_path.
|
||||||
|
* If @in_path is an absolute path, out_path = in_path.
|
||||||
|
* E.g.: in_refpath = "/foo/bar/baz.a", in_path = "foobar.cg",
|
||||||
|
* out_path = "/foo/bar/foobar.cg".
|
||||||
|
**/
|
||||||
|
void fill_pathname_resolve_relative(char *out_path, const char *in_refpath,
|
||||||
|
const char *in_path, size_t size);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* fill_pathname_join:
|
||||||
|
* @out_path : output path
|
||||||
|
* @dir : directory
|
||||||
|
* @path : path
|
||||||
|
* @size : size of output path
|
||||||
|
*
|
||||||
|
* Joins a directory (@dir) and path (@path) together.
|
||||||
|
* Makes sure not to get two consecutive slashes
|
||||||
|
* between directory and path.
|
||||||
|
**/
|
||||||
|
size_t fill_pathname_join(char *out_path, const char *dir,
|
||||||
|
const char *path, size_t size);
|
||||||
|
|
||||||
|
size_t fill_pathname_join_special_ext(char *out_path,
|
||||||
|
const char *dir, const char *path,
|
||||||
|
const char *last, const char *ext,
|
||||||
|
size_t size);
|
||||||
|
|
||||||
|
size_t fill_pathname_join_concat_noext(char *out_path,
|
||||||
|
const char *dir, const char *path,
|
||||||
|
const char *concat,
|
||||||
|
size_t size);
|
||||||
|
|
||||||
|
size_t fill_pathname_join_concat(char *out_path,
|
||||||
|
const char *dir, const char *path,
|
||||||
|
const char *concat,
|
||||||
|
size_t size);
|
||||||
|
|
||||||
|
void fill_pathname_join_noext(char *out_path,
|
||||||
|
const char *dir, const char *path, size_t size);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* fill_pathname_join_delim:
|
||||||
|
* @out_path : output path
|
||||||
|
* @dir : directory
|
||||||
|
* @path : path
|
||||||
|
* @delim : delimiter
|
||||||
|
* @size : size of output path
|
||||||
|
*
|
||||||
|
* Joins a directory (@dir) and path (@path) together
|
||||||
|
* using the given delimiter (@delim).
|
||||||
|
**/
|
||||||
|
size_t fill_pathname_join_delim(char *out_path, const char *dir,
|
||||||
|
const char *path, const char delim, size_t size);
|
||||||
|
|
||||||
|
size_t fill_pathname_join_delim_concat(char *out_path, const char *dir,
|
||||||
|
const char *path, const char delim, const char *concat,
|
||||||
|
size_t size);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* fill_short_pathname_representation:
|
||||||
|
* @out_rep : output representation
|
||||||
|
* @in_path : input path
|
||||||
|
* @size : size of output representation
|
||||||
|
*
|
||||||
|
* Generates a short representation of path. It should only
|
||||||
|
* be used for displaying the result; the output representation is not
|
||||||
|
* binding in any meaningful way (for a normal path, this is the same as basename)
|
||||||
|
* In case of more complex URLs, this should cut everything except for
|
||||||
|
* the main image file.
|
||||||
|
*
|
||||||
|
* E.g.: "/path/to/game.img" -> game.img
|
||||||
|
* "/path/to/myarchive.7z#folder/to/game.img" -> game.img
|
||||||
|
*/
|
||||||
|
size_t fill_short_pathname_representation(char* out_rep,
|
||||||
|
const char *in_path, size_t size);
|
||||||
|
|
||||||
|
void fill_short_pathname_representation_noext(char* out_rep,
|
||||||
|
const char *in_path, size_t size);
|
||||||
|
|
||||||
|
void fill_pathname_expand_special(char *out_path,
|
||||||
|
const char *in_path, size_t size);
|
||||||
|
|
||||||
|
void fill_pathname_abbreviate_special(char *out_path,
|
||||||
|
const char *in_path, size_t size);
|
||||||
|
|
||||||
|
void fill_pathname_abbreviated_or_relative(char *out_path, const char *in_refpath, const char *in_path, size_t size);
|
||||||
|
|
||||||
|
void pathname_conform_slashes_to_os(char *path);
|
||||||
|
|
||||||
|
void pathname_make_slashes_portable(char *path);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* path_basedir:
|
||||||
|
* @path : path
|
||||||
|
*
|
||||||
|
* Extracts base directory by mutating path.
|
||||||
|
* Keeps trailing '/'.
|
||||||
|
**/
|
||||||
|
void path_basedir_wrapper(char *path);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* path_char_is_slash:
|
||||||
|
* @c : character
|
||||||
|
*
|
||||||
|
* Checks if character (@c) is a slash.
|
||||||
|
*
|
||||||
|
* Returns: true (1) if character is a slash, otherwise false (0).
|
||||||
|
*/
|
||||||
|
#ifdef _WIN32
|
||||||
|
#define PATH_CHAR_IS_SLASH(c) (((c) == '/') || ((c) == '\\'))
|
||||||
|
#else
|
||||||
|
#define PATH_CHAR_IS_SLASH(c) ((c) == '/')
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/**
|
||||||
|
* path_default_slash and path_default_slash_c:
|
||||||
|
*
|
||||||
|
* Gets the default slash separator.
|
||||||
|
*
|
||||||
|
* Returns: default slash separator.
|
||||||
|
*/
|
||||||
|
#ifdef _WIN32
|
||||||
|
#define PATH_DEFAULT_SLASH() "\\"
|
||||||
|
#define PATH_DEFAULT_SLASH_C() '\\'
|
||||||
|
#else
|
||||||
|
#define PATH_DEFAULT_SLASH() "/"
|
||||||
|
#define PATH_DEFAULT_SLASH_C() '/'
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/**
|
||||||
|
* fill_pathname_slash:
|
||||||
|
* @path : path
|
||||||
|
* @size : size of path
|
||||||
|
*
|
||||||
|
* Assumes path is a directory. Appends a slash
|
||||||
|
* if not already there.
|
||||||
|
**/
|
||||||
|
void fill_pathname_slash(char *path, size_t size);
|
||||||
|
|
||||||
|
#if !defined(RARCH_CONSOLE) && defined(RARCH_INTERNAL)
|
||||||
|
void fill_pathname_application_path(char *buf, size_t size);
|
||||||
|
void fill_pathname_application_dir(char *buf, size_t size);
|
||||||
|
void fill_pathname_home_dir(char *buf, size_t size);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 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);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 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);
|
||||||
|
|
||||||
|
bool path_is_character_special(const char *path);
|
||||||
|
|
||||||
|
int path_stat(const char *path);
|
||||||
|
|
||||||
|
bool path_is_valid(const char *path);
|
||||||
|
|
||||||
|
int32_t path_get_size(const char *path);
|
||||||
|
|
||||||
|
bool is_path_accessible_using_standard_io(const char *path);
|
||||||
|
|
||||||
|
RETRO_END_DECLS
|
||||||
|
|
||||||
|
#endif
|
3822
libretro-common/include/libretro.h
Normal file
3822
libretro-common/include/libretro.h
Normal file
File diff suppressed because it is too large
Load Diff
35
libretro-common/include/retro_assert.h
Normal file
35
libretro-common/include/retro_assert.h
Normal file
@ -0,0 +1,35 @@
|
|||||||
|
/* Copyright (C) 2010-2020 The RetroArch team
|
||||||
|
*
|
||||||
|
* ---------------------------------------------------------------------------------------
|
||||||
|
* The following license statement only applies to this file (retro_assert.h).
|
||||||
|
* ---------------------------------------------------------------------------------------
|
||||||
|
*
|
||||||
|
* Permission is hereby granted, free of charge,
|
||||||
|
* to any person obtaining a copy of this software and associated documentation files (the "Software"),
|
||||||
|
* to deal in the Software without restriction, including without limitation the rights to
|
||||||
|
* use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software,
|
||||||
|
* and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
|
||||||
|
*
|
||||||
|
* The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
|
||||||
|
*
|
||||||
|
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
|
||||||
|
* INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
|
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
|
||||||
|
* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
|
||||||
|
* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||||
|
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef __RETRO_ASSERT_H
|
||||||
|
#define __RETRO_ASSERT_H
|
||||||
|
|
||||||
|
#include <assert.h>
|
||||||
|
|
||||||
|
#ifdef RARCH_INTERNAL
|
||||||
|
#include <stdio.h>
|
||||||
|
#define retro_assert(cond) ((void)( (cond) || (printf("Assertion failed at %s:%d.\n", __FILE__, __LINE__), abort(), 0) ))
|
||||||
|
#else
|
||||||
|
#define retro_assert(cond) assert(cond)
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#endif
|
119
libretro-common/include/retro_common_api.h
Normal file
119
libretro-common/include/retro_common_api.h
Normal file
@ -0,0 +1,119 @@
|
|||||||
|
/* Copyright (C) 2010-2020 The RetroArch team
|
||||||
|
*
|
||||||
|
* ---------------------------------------------------------------------------------------
|
||||||
|
* The following license statement only applies to this file (retro_common_api.h).
|
||||||
|
* ---------------------------------------------------------------------------------------
|
||||||
|
*
|
||||||
|
* Permission is hereby granted, free of charge,
|
||||||
|
* to any person obtaining a copy of this software and associated documentation files (the "Software"),
|
||||||
|
* to deal in the Software without restriction, including without limitation the rights to
|
||||||
|
* use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software,
|
||||||
|
* and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
|
||||||
|
*
|
||||||
|
* The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
|
||||||
|
*
|
||||||
|
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
|
||||||
|
* INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
|
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
|
||||||
|
* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
|
||||||
|
* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||||
|
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef _LIBRETRO_COMMON_RETRO_COMMON_API_H
|
||||||
|
#define _LIBRETRO_COMMON_RETRO_COMMON_API_H
|
||||||
|
|
||||||
|
/*
|
||||||
|
This file is designed to normalize the libretro-common compiling environment
|
||||||
|
for public API headers. This should be leaner than a normal compiling environment,
|
||||||
|
since it gets #included into other project's sources.
|
||||||
|
*/
|
||||||
|
|
||||||
|
/* ------------------------------------ */
|
||||||
|
|
||||||
|
/*
|
||||||
|
Ordinarily we want to put #ifdef __cplusplus extern "C" in C library
|
||||||
|
headers to enable them to get used by c++ sources.
|
||||||
|
However, we want to support building this library as C++ as well, so a
|
||||||
|
special technique is called for.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#define RETRO_BEGIN_DECLS
|
||||||
|
#define RETRO_END_DECLS
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
|
||||||
|
#ifdef CXX_BUILD
|
||||||
|
/* build wants everything to be built as c++, so no extern "C" */
|
||||||
|
#else
|
||||||
|
#undef RETRO_BEGIN_DECLS
|
||||||
|
#undef RETRO_END_DECLS
|
||||||
|
#define RETRO_BEGIN_DECLS extern "C" {
|
||||||
|
#define RETRO_END_DECLS }
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#else
|
||||||
|
|
||||||
|
/* header is included by a C source file, so no extern "C" */
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/*
|
||||||
|
IMO, this non-standard ssize_t should not be used.
|
||||||
|
However, it's a good example of how to handle something like this.
|
||||||
|
*/
|
||||||
|
#ifdef _MSC_VER
|
||||||
|
#ifndef HAVE_SSIZE_T
|
||||||
|
#define HAVE_SSIZE_T
|
||||||
|
#if defined(_WIN64)
|
||||||
|
typedef __int64 ssize_t;
|
||||||
|
#elif defined(_WIN32)
|
||||||
|
typedef int ssize_t;
|
||||||
|
#endif
|
||||||
|
#endif
|
||||||
|
#elif defined(__MACH__)
|
||||||
|
#include <sys/types.h>
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifdef _MSC_VER
|
||||||
|
#if _MSC_VER >= 1800
|
||||||
|
#include <inttypes.h>
|
||||||
|
#else
|
||||||
|
#ifndef PRId64
|
||||||
|
#define PRId64 "I64d"
|
||||||
|
#define PRIu64 "I64u"
|
||||||
|
#define PRIuPTR "Iu"
|
||||||
|
#endif
|
||||||
|
#endif
|
||||||
|
#else
|
||||||
|
/* 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://github.com/libretro/RetroArch/issues/6009 */
|
||||||
|
#ifndef __STDC_FORMAT_MACROS
|
||||||
|
#define __STDC_FORMAT_MACROS 1
|
||||||
|
#endif
|
||||||
|
#include <inttypes.h>
|
||||||
|
#endif
|
||||||
|
#ifndef PRId64
|
||||||
|
#error "inttypes.h is being screwy"
|
||||||
|
#endif
|
||||||
|
#define STRING_REP_INT64 "%" PRId64
|
||||||
|
#define STRING_REP_UINT64 "%" PRIu64
|
||||||
|
#define STRING_REP_USIZE "%" PRIuPTR
|
||||||
|
|
||||||
|
/*
|
||||||
|
I would like to see retro_inline.h moved in here; possibly boolean too.
|
||||||
|
|
||||||
|
rationale: these are used in public APIs, and it is easier to find problems
|
||||||
|
and write code that works the first time portably when theyre included uniformly
|
||||||
|
than to do the analysis from scratch each time you think you need it, for each feature.
|
||||||
|
|
||||||
|
Moreover it helps force you to make hard decisions: if you EVER bring in boolean.h,
|
||||||
|
then you should pay the price everywhere, so you can see how much grief it will cause.
|
||||||
|
|
||||||
|
Of course, another school of thought is that you should do as little damage as possible
|
||||||
|
in as few places as possible...
|
||||||
|
*/
|
||||||
|
|
||||||
|
/* _LIBRETRO_COMMON_RETRO_COMMON_API_H */
|
||||||
|
#endif
|
114
libretro-common/include/retro_environment.h
Normal file
114
libretro-common/include/retro_environment.h
Normal file
@ -0,0 +1,114 @@
|
|||||||
|
/* Copyright (C) 2010-2020 The RetroArch team
|
||||||
|
*
|
||||||
|
* ---------------------------------------------------------------------------------------
|
||||||
|
* The following license statement only applies to this file (retro_environment.h).
|
||||||
|
* ---------------------------------------------------------------------------------------
|
||||||
|
*
|
||||||
|
* Permission is hereby granted, free of charge,
|
||||||
|
* to any person obtaining a copy of this software and associated documentation files (the "Software"),
|
||||||
|
* to deal in the Software without restriction, including without limitation the rights to
|
||||||
|
* use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software,
|
||||||
|
* and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
|
||||||
|
*
|
||||||
|
* The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
|
||||||
|
*
|
||||||
|
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
|
||||||
|
* INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
|
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
|
||||||
|
* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
|
||||||
|
* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||||
|
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef __LIBRETRO_SDK_ENVIRONMENT_H
|
||||||
|
#define __LIBRETRO_SDK_ENVIRONMENT_H
|
||||||
|
|
||||||
|
/*
|
||||||
|
This file is designed to create a normalized environment for compiling
|
||||||
|
libretro-common's private implementations, or any other sources which might
|
||||||
|
enjoy use of it's environment (RetroArch for instance).
|
||||||
|
This should be an elaborately crafted environment so that sources don't
|
||||||
|
need to be full of platform-specific workarounds.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#if defined (__cplusplus)
|
||||||
|
#if 0
|
||||||
|
printf("This is C++, version %d.\n", __cplusplus);
|
||||||
|
#endif
|
||||||
|
/* The expected values would be
|
||||||
|
* 199711L, for ISO/IEC 14882:1998 or 14882:2003
|
||||||
|
*/
|
||||||
|
|
||||||
|
#elif defined(__STDC__)
|
||||||
|
/* This is standard C. */
|
||||||
|
|
||||||
|
#if (__STDC__ == 1)
|
||||||
|
/* The implementation is ISO-conforming. */
|
||||||
|
#define __STDC_ISO__
|
||||||
|
#else
|
||||||
|
/* The implementation is not ISO-conforming. */
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if defined(__STDC_VERSION__)
|
||||||
|
#if (__STDC_VERSION__ >= 201112L)
|
||||||
|
/* This is C11. */
|
||||||
|
#define __STDC_C11__
|
||||||
|
#elif (__STDC_VERSION__ >= 199901L)
|
||||||
|
/* This is C99. */
|
||||||
|
#define __STDC_C99__
|
||||||
|
#elif (__STDC_VERSION__ >= 199409L)
|
||||||
|
/* This is C89 with amendment 1. */
|
||||||
|
#define __STDC_C89__
|
||||||
|
#define __STDC_C89_AMENDMENT_1__
|
||||||
|
#else
|
||||||
|
/* This is C89 without amendment 1. */
|
||||||
|
#define __STDC_C89__
|
||||||
|
#endif
|
||||||
|
#else /* !defined(__STDC_VERSION__) */
|
||||||
|
/* This is C89. __STDC_VERSION__ is not defined. */
|
||||||
|
#define __STDC_C89__
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#else /* !defined(__STDC__) */
|
||||||
|
/* This is not standard C. __STDC__ is not defined. */
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if defined(WIN32) || defined(_WIN32) || defined(__CYGWIN__) || defined(__MINGW32__)
|
||||||
|
/* Try to find out if we're compiling for WinRT or non-WinRT */
|
||||||
|
#if defined(_MSC_VER) && defined(__has_include)
|
||||||
|
#if __has_include(<winapifamily.h>)
|
||||||
|
#define HAVE_WINAPIFAMILY_H 1
|
||||||
|
#else
|
||||||
|
#define HAVE_WINAPIFAMILY_H 0
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/* If _USING_V110_SDK71_ is defined it means we are using the Windows XP toolset. */
|
||||||
|
#elif defined(_MSC_VER) && (_MSC_VER >= 1700 && !_USING_V110_SDK71_) /* _MSC_VER == 1700 for Visual Studio 2012 */
|
||||||
|
#define HAVE_WINAPIFAMILY_H 1
|
||||||
|
#else
|
||||||
|
#define HAVE_WINAPIFAMILY_H 0
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if HAVE_WINAPIFAMILY_H
|
||||||
|
#include <winapifamily.h>
|
||||||
|
#define WINAPI_FAMILY_WINRT (!WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_DESKTOP) && WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_APP))
|
||||||
|
#else
|
||||||
|
#define WINAPI_FAMILY_WINRT 0
|
||||||
|
#endif /* HAVE_WINAPIFAMILY_H */
|
||||||
|
|
||||||
|
#if WINAPI_FAMILY_WINRT
|
||||||
|
#undef __WINRT__
|
||||||
|
#define __WINRT__ 1
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/* MSVC obviously has to have some non-standard constants... */
|
||||||
|
#if _M_IX86_FP == 1
|
||||||
|
#define __SSE__ 1
|
||||||
|
#elif _M_IX86_FP == 2 || (defined(_M_AMD64) || defined(_M_X64))
|
||||||
|
#define __SSE__ 1
|
||||||
|
#define __SSE2__ 1
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#endif
|
@ -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).
|
||||||
|
203
libretro-common/include/retro_miscellaneous.h
Normal file
203
libretro-common/include/retro_miscellaneous.h
Normal file
@ -0,0 +1,203 @@
|
|||||||
|
/* Copyright (C) 2010-2020 The RetroArch team
|
||||||
|
*
|
||||||
|
* ---------------------------------------------------------------------------------------
|
||||||
|
* The following license statement only applies to this file (retro_miscellaneous.h).
|
||||||
|
* ---------------------------------------------------------------------------------------
|
||||||
|
*
|
||||||
|
* Permission is hereby granted, free of charge,
|
||||||
|
* to any person obtaining a copy of this software and associated documentation files (the "Software"),
|
||||||
|
* to deal in the Software without restriction, including without limitation the rights to
|
||||||
|
* use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software,
|
||||||
|
* and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
|
||||||
|
*
|
||||||
|
* The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
|
||||||
|
*
|
||||||
|
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
|
||||||
|
* INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
|
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
|
||||||
|
* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
|
||||||
|
* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||||
|
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef __RARCH_MISCELLANEOUS_H
|
||||||
|
#define __RARCH_MISCELLANEOUS_H
|
||||||
|
|
||||||
|
#define RARCH_MAX_SUBSYSTEMS 10
|
||||||
|
#define RARCH_MAX_SUBSYSTEM_ROMS 10
|
||||||
|
|
||||||
|
#include <stdint.h>
|
||||||
|
#include <boolean.h>
|
||||||
|
#include <retro_inline.h>
|
||||||
|
|
||||||
|
#if defined(_WIN32)
|
||||||
|
|
||||||
|
#if defined(_XBOX)
|
||||||
|
#include <Xtl.h>
|
||||||
|
#else
|
||||||
|
#ifndef WIN32_LEAN_AND_MEAN
|
||||||
|
#define WIN32_LEAN_AND_MEAN
|
||||||
|
#endif
|
||||||
|
#include <windows.h>
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#include <limits.h>
|
||||||
|
|
||||||
|
#ifdef _MSC_VER
|
||||||
|
#include <compat/msvc.h>
|
||||||
|
#endif
|
||||||
|
|
||||||
|
static INLINE void bits_or_bits(uint32_t *a, uint32_t *b, uint32_t count)
|
||||||
|
{
|
||||||
|
uint32_t i;
|
||||||
|
for (i = 0; i < count;i++)
|
||||||
|
a[i] |= b[i];
|
||||||
|
}
|
||||||
|
|
||||||
|
static INLINE void bits_clear_bits(uint32_t *a, uint32_t *b, uint32_t count)
|
||||||
|
{
|
||||||
|
uint32_t i;
|
||||||
|
for (i = 0; i < count;i++)
|
||||||
|
a[i] &= ~b[i];
|
||||||
|
}
|
||||||
|
|
||||||
|
static INLINE bool bits_any_set(uint32_t* ptr, uint32_t count)
|
||||||
|
{
|
||||||
|
uint32_t i;
|
||||||
|
for (i = 0; i < count; i++)
|
||||||
|
{
|
||||||
|
if (ptr[i] != 0)
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
#ifndef PATH_MAX_LENGTH
|
||||||
|
#if defined(_XBOX1) || defined(_3DS) || defined(PSP) || defined(PS2) || defined(GEKKO)|| defined(WIIU) || defined(ORBIS) || defined(__PSL1GHT__) || defined(__PS3__)
|
||||||
|
#define PATH_MAX_LENGTH 512
|
||||||
|
#else
|
||||||
|
#define PATH_MAX_LENGTH 4096
|
||||||
|
#endif
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifndef MAX
|
||||||
|
#define MAX(a, b) ((a) > (b) ? (a) : (b))
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifndef MIN
|
||||||
|
#define MIN(a, b) ((a) < (b) ? (a) : (b))
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#define ARRAY_SIZE(a) (sizeof(a) / sizeof((a)[0]))
|
||||||
|
|
||||||
|
#define BITS_GET_ELEM(a, i) ((a).data[i])
|
||||||
|
#define BITS_GET_ELEM_PTR(a, i) ((a)->data[i])
|
||||||
|
|
||||||
|
#define BIT_SET(a, bit) ((a)[(bit) >> 3] |= (1 << ((bit) & 7)))
|
||||||
|
#define BIT_CLEAR(a, bit) ((a)[(bit) >> 3] &= ~(1 << ((bit) & 7)))
|
||||||
|
#define BIT_GET(a, bit) (((a)[(bit) >> 3] >> ((bit) & 7)) & 1)
|
||||||
|
|
||||||
|
#define BIT16_SET(a, bit) ((a) |= (1 << ((bit) & 15)))
|
||||||
|
#define BIT16_CLEAR(a, bit) ((a) &= ~(1 << ((bit) & 15)))
|
||||||
|
#define BIT16_GET(a, bit) (((a) >> ((bit) & 15)) & 1)
|
||||||
|
#define BIT16_CLEAR_ALL(a) ((a) = 0)
|
||||||
|
|
||||||
|
#define BIT32_SET(a, bit) ((a) |= (UINT32_C(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_CLEAR_ALL(a) ((a) = 0)
|
||||||
|
|
||||||
|
#define BIT64_SET(a, bit) ((a) |= (UINT64_C(1) << ((bit) & 63)))
|
||||||
|
#define BIT64_CLEAR(a, bit) ((a) &= ~(UINT64_C(1) << ((bit) & 63)))
|
||||||
|
#define BIT64_GET(a, bit) (((a) >> ((bit) & 63)) & 1)
|
||||||
|
#define BIT64_CLEAR_ALL(a) ((a) = 0)
|
||||||
|
|
||||||
|
#define BIT128_SET(a, bit) ((a).data[(bit) >> 5] |= (UINT32_C(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_CLEAR_ALL(a) memset(&(a), 0, sizeof(a))
|
||||||
|
|
||||||
|
#define BIT128_SET_PTR(a, bit) BIT128_SET(*a, bit)
|
||||||
|
#define BIT128_CLEAR_PTR(a, bit) BIT128_CLEAR(*a, bit)
|
||||||
|
#define BIT128_GET_PTR(a, bit) BIT128_GET(*a, bit)
|
||||||
|
#define BIT128_CLEAR_ALL_PTR(a) BIT128_CLEAR_ALL(*a)
|
||||||
|
|
||||||
|
#define BIT256_SET(a, bit) BIT128_SET(a, bit)
|
||||||
|
#define BIT256_CLEAR(a, bit) BIT128_CLEAR(a, bit)
|
||||||
|
#define BIT256_GET(a, bit) BIT128_GET(a, bit)
|
||||||
|
#define BIT256_CLEAR_ALL(a) BIT128_CLEAR_ALL(a)
|
||||||
|
|
||||||
|
#define BIT256_SET_PTR(a, bit) BIT256_SET(*a, bit)
|
||||||
|
#define BIT256_CLEAR_PTR(a, bit) BIT256_CLEAR(*a, bit)
|
||||||
|
#define BIT256_GET_PTR(a, bit) BIT256_GET(*a, bit)
|
||||||
|
#define BIT256_CLEAR_ALL_PTR(a) BIT256_CLEAR_ALL(*a)
|
||||||
|
|
||||||
|
#define BIT512_SET(a, bit) BIT256_SET(a, bit)
|
||||||
|
#define BIT512_CLEAR(a, bit) BIT256_CLEAR(a, bit)
|
||||||
|
#define BIT512_GET(a, bit) BIT256_GET(a, bit)
|
||||||
|
#define BIT512_CLEAR_ALL(a) BIT256_CLEAR_ALL(a)
|
||||||
|
|
||||||
|
#define BIT512_SET_PTR(a, bit) BIT512_SET(*a, bit)
|
||||||
|
#define BIT512_CLEAR_PTR(a, bit) BIT512_CLEAR(*a, bit)
|
||||||
|
#define BIT512_GET_PTR(a, bit) BIT512_GET(*a, bit)
|
||||||
|
#define BIT512_CLEAR_ALL_PTR(a) BIT512_CLEAR_ALL(*a)
|
||||||
|
|
||||||
|
#define BITS_COPY16_PTR(a,bits) \
|
||||||
|
{ \
|
||||||
|
BIT128_CLEAR_ALL_PTR(a); \
|
||||||
|
BITS_GET_ELEM_PTR(a, 0) = (bits) & 0xffff; \
|
||||||
|
}
|
||||||
|
|
||||||
|
#define BITS_COPY32_PTR(a,bits) \
|
||||||
|
{ \
|
||||||
|
BIT128_CLEAR_ALL_PTR(a); \
|
||||||
|
BITS_GET_ELEM_PTR(a, 0) = (bits); \
|
||||||
|
}
|
||||||
|
|
||||||
|
#define BITS_COPY64_PTR(a,bits) \
|
||||||
|
{ \
|
||||||
|
BIT128_CLEAR_ALL_PTR(a); \
|
||||||
|
BITS_GET_ELEM_PTR(a, 0) = (bits); \
|
||||||
|
BITS_GET_ELEM_PTR(a, 1) = (bits >> 32); \
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Helper macros and struct to keep track of many booleans. */
|
||||||
|
/* This struct has 256 bits. */
|
||||||
|
typedef struct
|
||||||
|
{
|
||||||
|
uint32_t data[8];
|
||||||
|
} retro_bits_t;
|
||||||
|
|
||||||
|
/* This struct has 512 bits. */
|
||||||
|
typedef struct
|
||||||
|
{
|
||||||
|
uint32_t data[16];
|
||||||
|
} retro_bits_512_t;
|
||||||
|
|
||||||
|
#ifdef _WIN32
|
||||||
|
# ifdef _WIN64
|
||||||
|
# define PRI_SIZET PRIu64
|
||||||
|
# else
|
||||||
|
# if _MSC_VER == 1800
|
||||||
|
# define PRI_SIZET PRIu32
|
||||||
|
# else
|
||||||
|
# define PRI_SIZET "u"
|
||||||
|
# endif
|
||||||
|
# endif
|
||||||
|
#elif defined(PS2)
|
||||||
|
# define PRI_SIZET "u"
|
||||||
|
#else
|
||||||
|
# if (SIZE_MAX == 0xFFFF)
|
||||||
|
# define PRI_SIZET "hu"
|
||||||
|
# elif (SIZE_MAX == 0xFFFFFFFF)
|
||||||
|
# define PRI_SIZET "u"
|
||||||
|
# elif (SIZE_MAX == 0xFFFFFFFFFFFFFFFF)
|
||||||
|
# define PRI_SIZET "lu"
|
||||||
|
# else
|
||||||
|
# error PRI_SIZET: unknown SIZE_MAX
|
||||||
|
# endif
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#endif
|
115
libretro-common/include/streams/file_stream.h
Normal file
115
libretro-common/include/streams/file_stream.h
Normal file
@ -0,0 +1,115 @@
|
|||||||
|
/* Copyright (C) 2010-2020 The RetroArch team
|
||||||
|
*
|
||||||
|
* ---------------------------------------------------------------------------------------
|
||||||
|
* The following license statement only applies to this file (file_stream.h).
|
||||||
|
* ---------------------------------------------------------------------------------------
|
||||||
|
*
|
||||||
|
* Permission is hereby granted, free of charge,
|
||||||
|
* to any person obtaining a copy of this software and associated documentation files (the "Software"),
|
||||||
|
* to deal in the Software without restriction, including without limitation the rights to
|
||||||
|
* use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software,
|
||||||
|
* and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
|
||||||
|
*
|
||||||
|
* The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
|
||||||
|
*
|
||||||
|
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
|
||||||
|
* INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
|
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
|
||||||
|
* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
|
||||||
|
* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||||
|
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef __LIBRETRO_SDK_FILE_STREAM_H
|
||||||
|
#define __LIBRETRO_SDK_FILE_STREAM_H
|
||||||
|
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <stdint.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <stddef.h>
|
||||||
|
|
||||||
|
#include <sys/types.h>
|
||||||
|
|
||||||
|
#include <libretro.h>
|
||||||
|
#include <retro_common_api.h>
|
||||||
|
#include <retro_inline.h>
|
||||||
|
#include <boolean.h>
|
||||||
|
|
||||||
|
#include <stdarg.h>
|
||||||
|
#include <vfs/vfs_implementation.h>
|
||||||
|
|
||||||
|
#define FILESTREAM_REQUIRED_VFS_VERSION 2
|
||||||
|
|
||||||
|
RETRO_BEGIN_DECLS
|
||||||
|
|
||||||
|
typedef struct RFILE RFILE;
|
||||||
|
|
||||||
|
#define FILESTREAM_REQUIRED_VFS_VERSION 2
|
||||||
|
|
||||||
|
void filestream_vfs_init(const struct retro_vfs_interface_info* vfs_info);
|
||||||
|
|
||||||
|
int64_t filestream_get_size(RFILE *stream);
|
||||||
|
|
||||||
|
int64_t filestream_truncate(RFILE *stream, int64_t length);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* filestream_open:
|
||||||
|
* @path : path to file
|
||||||
|
* @mode : file mode to use when opening (read/write)
|
||||||
|
* @bufsize : optional buffer size (-1 or 0 to use default)
|
||||||
|
*
|
||||||
|
* Opens a file for reading or writing, depending on the requested mode.
|
||||||
|
* Returns a pointer to an RFILE if opened successfully, otherwise NULL.
|
||||||
|
**/
|
||||||
|
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_read(RFILE *stream, void *data, int64_t len);
|
||||||
|
|
||||||
|
int64_t filestream_write(RFILE *stream, const void *data, int64_t len);
|
||||||
|
|
||||||
|
int64_t filestream_tell(RFILE *stream);
|
||||||
|
|
||||||
|
void filestream_rewind(RFILE *stream);
|
||||||
|
|
||||||
|
int filestream_close(RFILE *stream);
|
||||||
|
|
||||||
|
int64_t filestream_read_file(const char *path, void **buf, int64_t *len);
|
||||||
|
|
||||||
|
char* filestream_gets(RFILE *stream, char *s, size_t len);
|
||||||
|
|
||||||
|
int filestream_getc(RFILE *stream);
|
||||||
|
|
||||||
|
int filestream_scanf(RFILE *stream, const char* format, ...);
|
||||||
|
|
||||||
|
int filestream_eof(RFILE *stream);
|
||||||
|
|
||||||
|
bool filestream_write_file(const char *path, const void *data, int64_t size);
|
||||||
|
|
||||||
|
int filestream_putc(RFILE *stream, int c);
|
||||||
|
|
||||||
|
int filestream_vprintf(RFILE *stream, const char* format, va_list args);
|
||||||
|
|
||||||
|
int filestream_printf(RFILE *stream, const char* format, ...);
|
||||||
|
|
||||||
|
int filestream_error(RFILE *stream);
|
||||||
|
|
||||||
|
int filestream_flush(RFILE *stream);
|
||||||
|
|
||||||
|
int filestream_delete(const char *path);
|
||||||
|
|
||||||
|
int filestream_rename(const char *old_path, const char *new_path);
|
||||||
|
|
||||||
|
const char* filestream_get_path(RFILE *stream);
|
||||||
|
|
||||||
|
bool filestream_exists(const char *path);
|
||||||
|
|
||||||
|
/* Returned pointer must be freed by the caller. */
|
||||||
|
char* filestream_getline(RFILE *stream);
|
||||||
|
|
||||||
|
libretro_vfs_implementation_file* filestream_get_vfs_handle(RFILE *stream);
|
||||||
|
|
||||||
|
RETRO_END_DECLS
|
||||||
|
|
||||||
|
#endif
|
250
libretro-common/include/string/stdstring.h
Normal file
250
libretro-common/include/string/stdstring.h
Normal file
@ -0,0 +1,250 @@
|
|||||||
|
/* Copyright (C) 2010-2020 The RetroArch team
|
||||||
|
*
|
||||||
|
* ---------------------------------------------------------------------------------------
|
||||||
|
* The following license statement only applies to this file (stdstring.h).
|
||||||
|
* ---------------------------------------------------------------------------------------
|
||||||
|
*
|
||||||
|
* Permission is hereby granted, free of charge,
|
||||||
|
* to any person obtaining a copy of this software and associated documentation files (the "Software"),
|
||||||
|
* to deal in the Software without restriction, including without limitation the rights to
|
||||||
|
* use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software,
|
||||||
|
* and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
|
||||||
|
*
|
||||||
|
* The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
|
||||||
|
*
|
||||||
|
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
|
||||||
|
* INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
|
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
|
||||||
|
* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
|
||||||
|
* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||||
|
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef __LIBRETRO_SDK_STDSTRING_H
|
||||||
|
#define __LIBRETRO_SDK_STDSTRING_H
|
||||||
|
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <stddef.h>
|
||||||
|
#include <ctype.h>
|
||||||
|
#include <string.h>
|
||||||
|
#include <boolean.h>
|
||||||
|
|
||||||
|
#include <retro_common_api.h>
|
||||||
|
#include <retro_inline.h>
|
||||||
|
#include <compat/strl.h>
|
||||||
|
|
||||||
|
RETRO_BEGIN_DECLS
|
||||||
|
|
||||||
|
#define STRLEN_CONST(x) ((sizeof((x))-1))
|
||||||
|
|
||||||
|
#define strcpy_literal(a, b) strcpy(a, b)
|
||||||
|
|
||||||
|
#define string_is_not_equal(a, b) !string_is_equal((a), (b))
|
||||||
|
|
||||||
|
#define string_is_not_equal_fast(a, b, size) (memcmp(a, b, size) != 0)
|
||||||
|
#define string_is_equal_fast(a, b, size) (memcmp(a, b, size) == 0)
|
||||||
|
|
||||||
|
#define TOLOWER(c) ((c) | (lr_char_props[(unsigned char)(c)] & 0x20))
|
||||||
|
#define TOUPPER(c) ((c) & ~(lr_char_props[(unsigned char)(c)] & 0x20))
|
||||||
|
|
||||||
|
/* C standard says \f \v are space, but this one disagrees */
|
||||||
|
#define ISSPACE(c) (lr_char_props[(unsigned char)(c)] & 0x80)
|
||||||
|
|
||||||
|
#define ISDIGIT(c) (lr_char_props[(unsigned char)(c)] & 0x40)
|
||||||
|
#define ISALPHA(c) (lr_char_props[(unsigned char)(c)] & 0x20)
|
||||||
|
#define ISLOWER(c) (lr_char_props[(unsigned char)(c)] & 0x04)
|
||||||
|
#define ISUPPER(c) (lr_char_props[(unsigned char)(c)] & 0x02)
|
||||||
|
#define ISALNUM(c) (lr_char_props[(unsigned char)(c)] & 0x60)
|
||||||
|
#define ISUALPHA(c) (lr_char_props[(unsigned char)(c)] & 0x28)
|
||||||
|
#define ISUALNUM(c) (lr_char_props[(unsigned char)(c)] & 0x68)
|
||||||
|
#define IS_XDIGIT(c) (lr_char_props[(unsigned char)(c)] & 0x01)
|
||||||
|
|
||||||
|
/* Deprecated alias, all callers should use string_is_equal_case_insensitive instead */
|
||||||
|
#define string_is_equal_noncase string_is_equal_case_insensitive
|
||||||
|
|
||||||
|
static INLINE bool string_is_empty(const char *data)
|
||||||
|
{
|
||||||
|
return !data || (*data == '\0');
|
||||||
|
}
|
||||||
|
|
||||||
|
static INLINE bool string_is_equal(const char *a, const char *b)
|
||||||
|
{
|
||||||
|
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));
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Returns the length of 'str' (c.f. strlen()), but only
|
||||||
|
* checks the first 'size' characters
|
||||||
|
* - If 'str' is NULL, returns 0
|
||||||
|
* - If 'str' is not NULL and no '\0' character is found
|
||||||
|
* in the first 'size' characters, returns 'size' */
|
||||||
|
static INLINE size_t strlen_size(const char *str, size_t size)
|
||||||
|
{
|
||||||
|
size_t i = 0;
|
||||||
|
if (str)
|
||||||
|
while (i < size && str[i]) i++;
|
||||||
|
return i;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static INLINE bool string_is_equal_case_insensitive(const char *a,
|
||||||
|
const char *b)
|
||||||
|
{
|
||||||
|
int result = 0;
|
||||||
|
const unsigned char *p1 = (const unsigned char*)a;
|
||||||
|
const unsigned char *p2 = (const unsigned char*)b;
|
||||||
|
|
||||||
|
if (!a || !b)
|
||||||
|
return false;
|
||||||
|
if (p1 == p2)
|
||||||
|
return true;
|
||||||
|
|
||||||
|
while ((result = tolower (*p1) - tolower (*p2++)) == 0)
|
||||||
|
if (*p1++ == '\0')
|
||||||
|
break;
|
||||||
|
|
||||||
|
return (result == 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
char *string_to_upper(char *s);
|
||||||
|
|
||||||
|
char *string_to_lower(char *s);
|
||||||
|
|
||||||
|
char *string_ucwords(char *s);
|
||||||
|
|
||||||
|
char *string_replace_substring(const char *in, const char *pattern,
|
||||||
|
const char *by);
|
||||||
|
|
||||||
|
/* Remove leading whitespaces */
|
||||||
|
char *string_trim_whitespace_left(char *const s);
|
||||||
|
|
||||||
|
/* Remove trailing whitespaces */
|
||||||
|
char *string_trim_whitespace_right(char *const s);
|
||||||
|
|
||||||
|
/* Remove leading and trailing whitespaces */
|
||||||
|
char *string_trim_whitespace(char *const s);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Wraps string specified by 'src' to destination buffer
|
||||||
|
* specified by 'dst' and 'dst_size'.
|
||||||
|
* This function assumes that all glyphs in the string
|
||||||
|
* have an on-screen pixel width similar to that of
|
||||||
|
* regular Latin characters - i.e. it will not wrap
|
||||||
|
* correctly any text containing so-called 'wide' Unicode
|
||||||
|
* characters (e.g. CJK languages, emojis, etc.).
|
||||||
|
*
|
||||||
|
* @param dst pointer to destination buffer.
|
||||||
|
* @param dst_size size of destination buffer.
|
||||||
|
* @param src pointer to input string.
|
||||||
|
* @param line_width max number of characters per line.
|
||||||
|
* @param wideglyph_width not used, but is necessary to keep
|
||||||
|
* compatibility with word_wrap_wideglyph().
|
||||||
|
* @param max_lines max lines of destination string.
|
||||||
|
* 0 means no limit.
|
||||||
|
*/
|
||||||
|
void word_wrap(char *dst, size_t dst_size, const char *src,
|
||||||
|
int line_width, int wideglyph_width, unsigned max_lines);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Wraps string specified by 'src' to destination buffer
|
||||||
|
* specified by 'dst' and 'dst_size'.
|
||||||
|
* This function assumes that all glyphs in the string
|
||||||
|
* are:
|
||||||
|
* - EITHER 'non-wide' Unicode glyphs, with an on-screen
|
||||||
|
* pixel width similar to that of regular Latin characters
|
||||||
|
* - OR 'wide' Unicode glyphs (e.g. CJK languages, emojis, etc.)
|
||||||
|
* with an on-screen pixel width defined by 'wideglyph_width'
|
||||||
|
* Note that wrapping may occur in inappropriate locations
|
||||||
|
* if 'src' string contains 'wide' Unicode characters whose
|
||||||
|
* on-screen pixel width deviates greatly from the set
|
||||||
|
* 'wideglyph_width' value.
|
||||||
|
*
|
||||||
|
* @param dst pointer to destination buffer.
|
||||||
|
* @param dst_size size of destination buffer.
|
||||||
|
* @param src pointer to input string.
|
||||||
|
* @param line_width max number of characters per line.
|
||||||
|
* @param wideglyph_width effective width of 'wide' Unicode glyphs.
|
||||||
|
* the value here is normalised relative to the
|
||||||
|
* typical on-screen pixel width of a regular
|
||||||
|
* Latin character:
|
||||||
|
* - a regular Latin character is defined to
|
||||||
|
* have an effective width of 100
|
||||||
|
* - wideglyph_width = 100 * (wide_character_pixel_width / latin_character_pixel_width)
|
||||||
|
* - e.g. if 'wide' Unicode characters in 'src'
|
||||||
|
* have an on-screen pixel width twice that of
|
||||||
|
* regular Latin characters, wideglyph_width
|
||||||
|
* would be 200
|
||||||
|
* @param max_lines max lines of destination string.
|
||||||
|
* 0 means no limit.
|
||||||
|
*/
|
||||||
|
void word_wrap_wideglyph(char *dst, size_t dst_size, const char *src,
|
||||||
|
int line_width, int wideglyph_width, unsigned max_lines);
|
||||||
|
|
||||||
|
/* Splits string into tokens seperated by 'delim'
|
||||||
|
* > Returned token string must be free()'d
|
||||||
|
* > 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);
|
||||||
|
|
||||||
|
extern const unsigned char lr_char_props[256];
|
||||||
|
|
||||||
|
RETRO_END_DECLS
|
||||||
|
|
||||||
|
#endif
|
48
libretro-common/include/time/rtime.h
Normal file
48
libretro-common/include/time/rtime.h
Normal file
@ -0,0 +1,48 @@
|
|||||||
|
/* Copyright (C) 2010-2020 The RetroArch team
|
||||||
|
*
|
||||||
|
* ---------------------------------------------------------------------------------------
|
||||||
|
* The following license statement only applies to this file (rtime.h).
|
||||||
|
* ---------------------------------------------------------------------------------------
|
||||||
|
*
|
||||||
|
* Permission is hereby granted, free of charge,
|
||||||
|
* to any person obtaining a copy of this software and associated documentation files (the "Software"),
|
||||||
|
* to deal in the Software without restriction, including without limitation the rights to
|
||||||
|
* use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software,
|
||||||
|
* and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
|
||||||
|
*
|
||||||
|
* The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
|
||||||
|
*
|
||||||
|
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
|
||||||
|
* INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
|
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
|
||||||
|
* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
|
||||||
|
* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||||
|
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef __LIBRETRO_SDK_RTIME_H__
|
||||||
|
#define __LIBRETRO_SDK_RTIME_H__
|
||||||
|
|
||||||
|
#include <retro_common_api.h>
|
||||||
|
|
||||||
|
#include <stdint.h>
|
||||||
|
#include <stddef.h>
|
||||||
|
#include <time.h>
|
||||||
|
|
||||||
|
RETRO_BEGIN_DECLS
|
||||||
|
|
||||||
|
/* TODO/FIXME: Move all generic time handling functions
|
||||||
|
* to this file */
|
||||||
|
|
||||||
|
/* Must be called before using rtime_localtime() */
|
||||||
|
void rtime_init(void);
|
||||||
|
|
||||||
|
/* Must be called upon program termination */
|
||||||
|
void rtime_deinit(void);
|
||||||
|
|
||||||
|
/* Thread-safe wrapper for localtime() */
|
||||||
|
struct tm *rtime_localtime(const time_t *timep, struct tm *result);
|
||||||
|
|
||||||
|
RETRO_END_DECLS
|
||||||
|
|
||||||
|
#endif
|
111
libretro-common/include/vfs/vfs.h
Normal file
111
libretro-common/include/vfs/vfs.h
Normal file
@ -0,0 +1,111 @@
|
|||||||
|
/* Copyright (C) 2010-2020 The RetroArch team
|
||||||
|
*
|
||||||
|
* ---------------------------------------------------------------------------------------
|
||||||
|
* The following license statement only applies to this file (vfs_implementation.h).
|
||||||
|
* ---------------------------------------------------------------------------------------
|
||||||
|
*
|
||||||
|
* Permission is hereby granted, free of charge,
|
||||||
|
* to any person obtaining a copy of this software and associated documentation files (the "Software"),
|
||||||
|
* to deal in the Software without restriction, including without limitation the rights to
|
||||||
|
* use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software,
|
||||||
|
* and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
|
||||||
|
*
|
||||||
|
* The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
|
||||||
|
*
|
||||||
|
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
|
||||||
|
* INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
|
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
|
||||||
|
* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
|
||||||
|
* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||||
|
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef __LIBRETRO_SDK_VFS_H
|
||||||
|
#define __LIBRETRO_SDK_VFS_H
|
||||||
|
|
||||||
|
#include <retro_common_api.h>
|
||||||
|
#include <boolean.h>
|
||||||
|
|
||||||
|
#ifdef RARCH_INTERNAL
|
||||||
|
#ifndef VFS_FRONTEND
|
||||||
|
#define VFS_FRONTEND
|
||||||
|
#endif
|
||||||
|
#endif
|
||||||
|
|
||||||
|
RETRO_BEGIN_DECLS
|
||||||
|
|
||||||
|
#ifdef _WIN32
|
||||||
|
typedef void* HANDLE;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifdef HAVE_CDROM
|
||||||
|
typedef struct
|
||||||
|
{
|
||||||
|
int64_t byte_pos;
|
||||||
|
char *cue_buf;
|
||||||
|
size_t cue_len;
|
||||||
|
unsigned cur_lba;
|
||||||
|
unsigned last_frame_lba;
|
||||||
|
unsigned char cur_min;
|
||||||
|
unsigned char cur_sec;
|
||||||
|
unsigned char cur_frame;
|
||||||
|
unsigned char cur_track;
|
||||||
|
unsigned char last_frame[2352];
|
||||||
|
char drive;
|
||||||
|
bool last_frame_valid;
|
||||||
|
} vfs_cdrom_t;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
enum vfs_scheme
|
||||||
|
{
|
||||||
|
VFS_SCHEME_NONE = 0,
|
||||||
|
VFS_SCHEME_CDROM
|
||||||
|
};
|
||||||
|
|
||||||
|
#ifndef __WINRT__
|
||||||
|
#ifdef VFS_FRONTEND
|
||||||
|
struct retro_vfs_file_handle
|
||||||
|
#else
|
||||||
|
struct libretro_vfs_implementation_file
|
||||||
|
#endif
|
||||||
|
{
|
||||||
|
#ifdef HAVE_CDROM
|
||||||
|
vfs_cdrom_t cdrom; /* int64_t alignment */
|
||||||
|
#endif
|
||||||
|
int64_t size;
|
||||||
|
uint64_t mappos;
|
||||||
|
uint64_t mapsize;
|
||||||
|
FILE *fp;
|
||||||
|
#ifdef _WIN32
|
||||||
|
HANDLE fh;
|
||||||
|
#endif
|
||||||
|
char *buf;
|
||||||
|
char* orig_path;
|
||||||
|
uint8_t *mapped;
|
||||||
|
int fd;
|
||||||
|
unsigned hints;
|
||||||
|
enum vfs_scheme scheme;
|
||||||
|
};
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/* Replace the following symbol with something appropriate
|
||||||
|
* to signify the file is being compiled for a front end instead of a core.
|
||||||
|
* This allows the same code to act as reference implementation
|
||||||
|
* for VFS and as fallbacks for when the front end does not provide VFS functionality.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifdef VFS_FRONTEND
|
||||||
|
typedef struct retro_vfs_file_handle libretro_vfs_implementation_file;
|
||||||
|
#else
|
||||||
|
typedef struct libretro_vfs_implementation_file libretro_vfs_implementation_file;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifdef VFS_FRONTEND
|
||||||
|
typedef struct retro_vfs_dir_handle libretro_vfs_implementation_dir;
|
||||||
|
#else
|
||||||
|
typedef struct libretro_vfs_implementation_dir libretro_vfs_implementation_dir;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
RETRO_END_DECLS
|
||||||
|
|
||||||
|
#endif
|
76
libretro-common/include/vfs/vfs_implementation.h
Normal file
76
libretro-common/include/vfs/vfs_implementation.h
Normal file
@ -0,0 +1,76 @@
|
|||||||
|
/* Copyright (C) 2010-2020 The RetroArch team
|
||||||
|
*
|
||||||
|
* ---------------------------------------------------------------------------------------
|
||||||
|
* The following license statement only applies to this file (vfs_implementation.h).
|
||||||
|
* ---------------------------------------------------------------------------------------
|
||||||
|
*
|
||||||
|
* Permission is hereby granted, free of charge,
|
||||||
|
* to any person obtaining a copy of this software and associated documentation files (the "Software"),
|
||||||
|
* to deal in the Software without restriction, including without limitation the rights to
|
||||||
|
* use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software,
|
||||||
|
* and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
|
||||||
|
*
|
||||||
|
* The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
|
||||||
|
*
|
||||||
|
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
|
||||||
|
* INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
|
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
|
||||||
|
* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
|
||||||
|
* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||||
|
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef __LIBRETRO_SDK_VFS_IMPLEMENTATION_H
|
||||||
|
#define __LIBRETRO_SDK_VFS_IMPLEMENTATION_H
|
||||||
|
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <stdint.h>
|
||||||
|
#include <libretro.h>
|
||||||
|
#include <retro_environment.h>
|
||||||
|
#include <vfs/vfs.h>
|
||||||
|
|
||||||
|
RETRO_BEGIN_DECLS
|
||||||
|
|
||||||
|
libretro_vfs_implementation_file *retro_vfs_file_open_impl(const char *path, unsigned mode, unsigned hints);
|
||||||
|
|
||||||
|
int retro_vfs_file_close_impl(libretro_vfs_implementation_file *stream);
|
||||||
|
|
||||||
|
int retro_vfs_file_error_impl(libretro_vfs_implementation_file *stream);
|
||||||
|
|
||||||
|
int64_t retro_vfs_file_size_impl(libretro_vfs_implementation_file *stream);
|
||||||
|
|
||||||
|
int64_t retro_vfs_file_truncate_impl(libretro_vfs_implementation_file *stream, int64_t length);
|
||||||
|
|
||||||
|
int64_t retro_vfs_file_tell_impl(libretro_vfs_implementation_file *stream);
|
||||||
|
|
||||||
|
int64_t retro_vfs_file_seek_impl(libretro_vfs_implementation_file *stream, int64_t offset, int seek_position);
|
||||||
|
|
||||||
|
int64_t retro_vfs_file_read_impl(libretro_vfs_implementation_file *stream, void *s, uint64_t len);
|
||||||
|
|
||||||
|
int64_t retro_vfs_file_write_impl(libretro_vfs_implementation_file *stream, const void *s, uint64_t len);
|
||||||
|
|
||||||
|
int retro_vfs_file_flush_impl(libretro_vfs_implementation_file *stream);
|
||||||
|
|
||||||
|
int retro_vfs_file_remove_impl(const char *path);
|
||||||
|
|
||||||
|
int retro_vfs_file_rename_impl(const char *old_path, const char *new_path);
|
||||||
|
|
||||||
|
const char *retro_vfs_file_get_path_impl(libretro_vfs_implementation_file *stream);
|
||||||
|
|
||||||
|
int retro_vfs_stat_impl(const char *path, int32_t *size);
|
||||||
|
|
||||||
|
int retro_vfs_mkdir_impl(const char *dir);
|
||||||
|
|
||||||
|
libretro_vfs_implementation_dir *retro_vfs_opendir_impl(const char *dir, bool include_hidden);
|
||||||
|
|
||||||
|
bool retro_vfs_readdir_impl(libretro_vfs_implementation_dir *dirstream);
|
||||||
|
|
||||||
|
const char *retro_vfs_dirent_get_name_impl(libretro_vfs_implementation_dir *dirstream);
|
||||||
|
|
||||||
|
bool retro_vfs_dirent_is_dir_impl(libretro_vfs_implementation_dir *dirstream);
|
||||||
|
|
||||||
|
int retro_vfs_closedir_impl(libretro_vfs_implementation_dir *dirstream);
|
||||||
|
|
||||||
|
RETRO_END_DECLS
|
||||||
|
|
||||||
|
#endif
|
663
libretro-common/streams/file_stream.c
Normal file
663
libretro-common/streams/file_stream.c
Normal file
@ -0,0 +1,663 @@
|
|||||||
|
/* Copyright (C) 2010-2020 The RetroArch team
|
||||||
|
*
|
||||||
|
* ---------------------------------------------------------------------------------------
|
||||||
|
* The following license statement only applies to this file (file_stream.c).
|
||||||
|
* ---------------------------------------------------------------------------------------
|
||||||
|
*
|
||||||
|
* Permission is hereby granted, free of charge,
|
||||||
|
* to any person obtaining a copy of this software and associated documentation files (the "Software"),
|
||||||
|
* to deal in the Software without restriction, including without limitation the rights to
|
||||||
|
* use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software,
|
||||||
|
* and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
|
||||||
|
*
|
||||||
|
* The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
|
||||||
|
*
|
||||||
|
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
|
||||||
|
* INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
|
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
|
||||||
|
* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
|
||||||
|
* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||||
|
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <string.h>
|
||||||
|
#include <stdarg.h>
|
||||||
|
#include <ctype.h>
|
||||||
|
#include <errno.h>
|
||||||
|
|
||||||
|
#ifdef HAVE_CONFIG_H
|
||||||
|
#include "config.h"
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifdef _MSC_VER
|
||||||
|
#include <compat/msvc.h>
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#include <string/stdstring.h>
|
||||||
|
#include <streams/file_stream.h>
|
||||||
|
#define VFS_FRONTEND
|
||||||
|
#include <vfs/vfs_implementation.h>
|
||||||
|
|
||||||
|
#define VFS_ERROR_RETURN_VALUE -1
|
||||||
|
|
||||||
|
struct RFILE
|
||||||
|
{
|
||||||
|
struct retro_vfs_file_handle *hfile;
|
||||||
|
bool error_flag;
|
||||||
|
bool eof_flag;
|
||||||
|
};
|
||||||
|
|
||||||
|
static retro_vfs_get_path_t filestream_get_path_cb = NULL;
|
||||||
|
static retro_vfs_open_t filestream_open_cb = NULL;
|
||||||
|
static retro_vfs_close_t filestream_close_cb = NULL;
|
||||||
|
static retro_vfs_size_t filestream_size_cb = NULL;
|
||||||
|
static retro_vfs_truncate_t filestream_truncate_cb = NULL;
|
||||||
|
static retro_vfs_tell_t filestream_tell_cb = NULL;
|
||||||
|
static retro_vfs_seek_t filestream_seek_cb = NULL;
|
||||||
|
static retro_vfs_read_t filestream_read_cb = NULL;
|
||||||
|
static retro_vfs_write_t filestream_write_cb = NULL;
|
||||||
|
static retro_vfs_flush_t filestream_flush_cb = NULL;
|
||||||
|
static retro_vfs_remove_t filestream_remove_cb = NULL;
|
||||||
|
static retro_vfs_rename_t filestream_rename_cb = NULL;
|
||||||
|
|
||||||
|
/* VFS Initialization */
|
||||||
|
|
||||||
|
void filestream_vfs_init(const struct retro_vfs_interface_info* vfs_info)
|
||||||
|
{
|
||||||
|
const struct retro_vfs_interface *
|
||||||
|
vfs_iface = vfs_info->iface;
|
||||||
|
|
||||||
|
filestream_get_path_cb = NULL;
|
||||||
|
filestream_open_cb = NULL;
|
||||||
|
filestream_close_cb = NULL;
|
||||||
|
filestream_tell_cb = NULL;
|
||||||
|
filestream_size_cb = NULL;
|
||||||
|
filestream_truncate_cb = NULL;
|
||||||
|
filestream_seek_cb = NULL;
|
||||||
|
filestream_read_cb = NULL;
|
||||||
|
filestream_write_cb = NULL;
|
||||||
|
filestream_flush_cb = NULL;
|
||||||
|
filestream_remove_cb = NULL;
|
||||||
|
filestream_rename_cb = NULL;
|
||||||
|
|
||||||
|
if (
|
||||||
|
(vfs_info->required_interface_version <
|
||||||
|
FILESTREAM_REQUIRED_VFS_VERSION)
|
||||||
|
|| !vfs_iface)
|
||||||
|
return;
|
||||||
|
|
||||||
|
filestream_get_path_cb = vfs_iface->get_path;
|
||||||
|
filestream_open_cb = vfs_iface->open;
|
||||||
|
filestream_close_cb = vfs_iface->close;
|
||||||
|
filestream_size_cb = vfs_iface->size;
|
||||||
|
filestream_truncate_cb = vfs_iface->truncate;
|
||||||
|
filestream_tell_cb = vfs_iface->tell;
|
||||||
|
filestream_seek_cb = vfs_iface->seek;
|
||||||
|
filestream_read_cb = vfs_iface->read;
|
||||||
|
filestream_write_cb = vfs_iface->write;
|
||||||
|
filestream_flush_cb = vfs_iface->flush;
|
||||||
|
filestream_remove_cb = vfs_iface->remove;
|
||||||
|
filestream_rename_cb = vfs_iface->rename;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Callback wrappers */
|
||||||
|
bool filestream_exists(const char *path)
|
||||||
|
{
|
||||||
|
RFILE *dummy = NULL;
|
||||||
|
|
||||||
|
if (!path || !*path)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
dummy = filestream_open(
|
||||||
|
path,
|
||||||
|
RETRO_VFS_FILE_ACCESS_READ,
|
||||||
|
RETRO_VFS_FILE_ACCESS_HINT_NONE);
|
||||||
|
|
||||||
|
if (!dummy)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
if (filestream_close(dummy) != 0)
|
||||||
|
if (dummy)
|
||||||
|
free(dummy);
|
||||||
|
|
||||||
|
dummy = NULL;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
int64_t filestream_get_size(RFILE *stream)
|
||||||
|
{
|
||||||
|
int64_t output;
|
||||||
|
|
||||||
|
if (filestream_size_cb)
|
||||||
|
output = filestream_size_cb(stream->hfile);
|
||||||
|
else
|
||||||
|
output = retro_vfs_file_size_impl(
|
||||||
|
(libretro_vfs_implementation_file*)stream->hfile);
|
||||||
|
|
||||||
|
if (output == VFS_ERROR_RETURN_VALUE)
|
||||||
|
stream->error_flag = true;
|
||||||
|
|
||||||
|
return output;
|
||||||
|
}
|
||||||
|
|
||||||
|
int64_t filestream_truncate(RFILE *stream, int64_t length)
|
||||||
|
{
|
||||||
|
int64_t output;
|
||||||
|
|
||||||
|
if (filestream_truncate_cb)
|
||||||
|
output = filestream_truncate_cb(stream->hfile, length);
|
||||||
|
else
|
||||||
|
output = retro_vfs_file_truncate_impl(
|
||||||
|
(libretro_vfs_implementation_file*)stream->hfile, length);
|
||||||
|
|
||||||
|
if (output == VFS_ERROR_RETURN_VALUE)
|
||||||
|
stream->error_flag = true;
|
||||||
|
|
||||||
|
return output;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* filestream_open:
|
||||||
|
* @path : path to file
|
||||||
|
* @mode : file mode to use when opening (read/write)
|
||||||
|
* @hints :
|
||||||
|
*
|
||||||
|
* Opens a file for reading or writing, depending on the requested mode.
|
||||||
|
* Returns a pointer to an RFILE if opened successfully, otherwise NULL.
|
||||||
|
**/
|
||||||
|
RFILE* filestream_open(const char *path, unsigned mode, unsigned hints)
|
||||||
|
{
|
||||||
|
struct retro_vfs_file_handle *fp = NULL;
|
||||||
|
RFILE* output = NULL;
|
||||||
|
|
||||||
|
if (filestream_open_cb)
|
||||||
|
fp = (struct retro_vfs_file_handle*)
|
||||||
|
filestream_open_cb(path, mode, hints);
|
||||||
|
else
|
||||||
|
fp = (struct retro_vfs_file_handle*)
|
||||||
|
retro_vfs_file_open_impl(path, mode, hints);
|
||||||
|
|
||||||
|
if (!fp)
|
||||||
|
return NULL;
|
||||||
|
|
||||||
|
output = (RFILE*)malloc(sizeof(RFILE));
|
||||||
|
output->error_flag = false;
|
||||||
|
output->eof_flag = false;
|
||||||
|
output->hfile = fp;
|
||||||
|
return output;
|
||||||
|
}
|
||||||
|
|
||||||
|
char* filestream_gets(RFILE *stream, char *s, size_t len)
|
||||||
|
{
|
||||||
|
int c = 0;
|
||||||
|
char *p = s;
|
||||||
|
if (!stream)
|
||||||
|
return NULL;
|
||||||
|
|
||||||
|
/* get max bytes or up to a newline */
|
||||||
|
|
||||||
|
for (len--; len > 0; len--)
|
||||||
|
{
|
||||||
|
if ((c = filestream_getc(stream)) == EOF)
|
||||||
|
break;
|
||||||
|
*p++ = c;
|
||||||
|
if (c == '\n')
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
*p = 0;
|
||||||
|
|
||||||
|
if (p == s && c == EOF)
|
||||||
|
return NULL;
|
||||||
|
return (s);
|
||||||
|
}
|
||||||
|
|
||||||
|
int filestream_getc(RFILE *stream)
|
||||||
|
{
|
||||||
|
char c = 0;
|
||||||
|
if (stream && filestream_read(stream, &c, 1) == 1)
|
||||||
|
return (int)(unsigned char)c;
|
||||||
|
return EOF;
|
||||||
|
}
|
||||||
|
|
||||||
|
int filestream_scanf(RFILE *stream, const char* format, ...)
|
||||||
|
{
|
||||||
|
char buf[4096];
|
||||||
|
char subfmt[64];
|
||||||
|
va_list args;
|
||||||
|
const char * bufiter = buf;
|
||||||
|
int ret = 0;
|
||||||
|
int64_t startpos = filestream_tell(stream);
|
||||||
|
int64_t maxlen = filestream_read(stream, buf, sizeof(buf)-1);
|
||||||
|
|
||||||
|
if (maxlen <= 0)
|
||||||
|
return EOF;
|
||||||
|
|
||||||
|
buf[maxlen] = '\0';
|
||||||
|
|
||||||
|
va_start(args, format);
|
||||||
|
|
||||||
|
while (*format)
|
||||||
|
{
|
||||||
|
if (*format == '%')
|
||||||
|
{
|
||||||
|
int sublen;
|
||||||
|
char* subfmtiter = subfmt;
|
||||||
|
bool asterisk = false;
|
||||||
|
|
||||||
|
*subfmtiter++ = *format++; /* '%' */
|
||||||
|
|
||||||
|
/* %[*][width][length]specifier */
|
||||||
|
|
||||||
|
if (*format == '*')
|
||||||
|
{
|
||||||
|
asterisk = true;
|
||||||
|
*subfmtiter++ = *format++;
|
||||||
|
}
|
||||||
|
|
||||||
|
while (ISDIGIT((unsigned char)*format))
|
||||||
|
*subfmtiter++ = *format++; /* width */
|
||||||
|
|
||||||
|
/* length */
|
||||||
|
if (*format == 'h' || *format == 'l')
|
||||||
|
{
|
||||||
|
if (format[1] == format[0])
|
||||||
|
*subfmtiter++ = *format++;
|
||||||
|
*subfmtiter++ = *format++;
|
||||||
|
}
|
||||||
|
else if (
|
||||||
|
*format == 'j' ||
|
||||||
|
*format == 'z' ||
|
||||||
|
*format == 't' ||
|
||||||
|
*format == 'L')
|
||||||
|
{
|
||||||
|
*subfmtiter++ = *format++;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* specifier - always a single character (except ]) */
|
||||||
|
if (*format == '[')
|
||||||
|
{
|
||||||
|
while (*format != ']')
|
||||||
|
*subfmtiter++ = *format++;
|
||||||
|
*subfmtiter++ = *format++;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
*subfmtiter++ = *format++;
|
||||||
|
|
||||||
|
*subfmtiter++ = '%';
|
||||||
|
*subfmtiter++ = 'n';
|
||||||
|
*subfmtiter++ = '\0';
|
||||||
|
|
||||||
|
if (sizeof(void*) != sizeof(long*))
|
||||||
|
abort(); /* all pointers must have the same size */
|
||||||
|
|
||||||
|
if (asterisk)
|
||||||
|
{
|
||||||
|
int v = sscanf(bufiter, subfmt, &sublen);
|
||||||
|
if (v == EOF)
|
||||||
|
return EOF;
|
||||||
|
if (v != 0)
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
int v = sscanf(bufiter, subfmt, va_arg(args, void*), &sublen);
|
||||||
|
if (v == EOF)
|
||||||
|
return EOF;
|
||||||
|
if (v != 1)
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
ret++;
|
||||||
|
bufiter += sublen;
|
||||||
|
}
|
||||||
|
else if (isspace((unsigned char)*format))
|
||||||
|
{
|
||||||
|
while (isspace((unsigned char)*bufiter))
|
||||||
|
bufiter++;
|
||||||
|
format++;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
if (*bufiter != *format)
|
||||||
|
break;
|
||||||
|
bufiter++;
|
||||||
|
format++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
va_end(args);
|
||||||
|
filestream_seek(stream, startpos+(bufiter-buf),
|
||||||
|
RETRO_VFS_SEEK_POSITION_START);
|
||||||
|
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
int64_t filestream_seek(RFILE *stream, int64_t offset, int seek_position)
|
||||||
|
{
|
||||||
|
int64_t output;
|
||||||
|
|
||||||
|
if (filestream_seek_cb)
|
||||||
|
output = filestream_seek_cb(stream->hfile, offset, seek_position);
|
||||||
|
else
|
||||||
|
output = retro_vfs_file_seek_impl(
|
||||||
|
(libretro_vfs_implementation_file*)stream->hfile,
|
||||||
|
offset, seek_position);
|
||||||
|
|
||||||
|
if (output == VFS_ERROR_RETURN_VALUE)
|
||||||
|
stream->error_flag = true;
|
||||||
|
|
||||||
|
stream->eof_flag = false;
|
||||||
|
|
||||||
|
return output;
|
||||||
|
}
|
||||||
|
|
||||||
|
int filestream_eof(RFILE *stream)
|
||||||
|
{
|
||||||
|
return stream->eof_flag;
|
||||||
|
}
|
||||||
|
|
||||||
|
int64_t filestream_tell(RFILE *stream)
|
||||||
|
{
|
||||||
|
int64_t output;
|
||||||
|
|
||||||
|
if (filestream_size_cb)
|
||||||
|
output = filestream_tell_cb(stream->hfile);
|
||||||
|
else
|
||||||
|
output = retro_vfs_file_tell_impl(
|
||||||
|
(libretro_vfs_implementation_file*)stream->hfile);
|
||||||
|
|
||||||
|
if (output == VFS_ERROR_RETURN_VALUE)
|
||||||
|
stream->error_flag = true;
|
||||||
|
|
||||||
|
return output;
|
||||||
|
}
|
||||||
|
|
||||||
|
void filestream_rewind(RFILE *stream)
|
||||||
|
{
|
||||||
|
if (!stream)
|
||||||
|
return;
|
||||||
|
filestream_seek(stream, 0L, RETRO_VFS_SEEK_POSITION_START);
|
||||||
|
stream->error_flag = false;
|
||||||
|
stream->eof_flag = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
int64_t filestream_read(RFILE *stream, void *s, int64_t len)
|
||||||
|
{
|
||||||
|
int64_t output;
|
||||||
|
|
||||||
|
if (filestream_read_cb)
|
||||||
|
output = filestream_read_cb(stream->hfile, s, len);
|
||||||
|
else
|
||||||
|
output = retro_vfs_file_read_impl(
|
||||||
|
(libretro_vfs_implementation_file*)stream->hfile, s, len);
|
||||||
|
|
||||||
|
if (output == VFS_ERROR_RETURN_VALUE)
|
||||||
|
stream->error_flag = true;
|
||||||
|
if (output < len)
|
||||||
|
stream->eof_flag = true;
|
||||||
|
|
||||||
|
return output;
|
||||||
|
}
|
||||||
|
|
||||||
|
int filestream_flush(RFILE *stream)
|
||||||
|
{
|
||||||
|
int output;
|
||||||
|
|
||||||
|
if (filestream_flush_cb)
|
||||||
|
output = filestream_flush_cb(stream->hfile);
|
||||||
|
else
|
||||||
|
output = retro_vfs_file_flush_impl(
|
||||||
|
(libretro_vfs_implementation_file*)stream->hfile);
|
||||||
|
|
||||||
|
if (output == VFS_ERROR_RETURN_VALUE)
|
||||||
|
stream->error_flag = true;
|
||||||
|
|
||||||
|
return output;
|
||||||
|
}
|
||||||
|
|
||||||
|
int filestream_delete(const char *path)
|
||||||
|
{
|
||||||
|
if (filestream_remove_cb)
|
||||||
|
return filestream_remove_cb(path);
|
||||||
|
|
||||||
|
return retro_vfs_file_remove_impl(path);
|
||||||
|
}
|
||||||
|
|
||||||
|
int filestream_rename(const char *old_path, const char *new_path)
|
||||||
|
{
|
||||||
|
if (filestream_rename_cb)
|
||||||
|
return filestream_rename_cb(old_path, new_path);
|
||||||
|
|
||||||
|
return retro_vfs_file_rename_impl(old_path, new_path);
|
||||||
|
}
|
||||||
|
|
||||||
|
const char* filestream_get_path(RFILE *stream)
|
||||||
|
{
|
||||||
|
if (filestream_get_path_cb)
|
||||||
|
return filestream_get_path_cb(stream->hfile);
|
||||||
|
|
||||||
|
return retro_vfs_file_get_path_impl(
|
||||||
|
(libretro_vfs_implementation_file*)stream->hfile);
|
||||||
|
}
|
||||||
|
|
||||||
|
int64_t filestream_write(RFILE *stream, const void *s, int64_t len)
|
||||||
|
{
|
||||||
|
int64_t output;
|
||||||
|
|
||||||
|
if (filestream_write_cb)
|
||||||
|
output = filestream_write_cb(stream->hfile, s, len);
|
||||||
|
else
|
||||||
|
output = retro_vfs_file_write_impl(
|
||||||
|
(libretro_vfs_implementation_file*)stream->hfile, s, len);
|
||||||
|
|
||||||
|
if (output == VFS_ERROR_RETURN_VALUE)
|
||||||
|
stream->error_flag = true;
|
||||||
|
|
||||||
|
return output;
|
||||||
|
}
|
||||||
|
|
||||||
|
int filestream_putc(RFILE *stream, int c)
|
||||||
|
{
|
||||||
|
char c_char = (char)c;
|
||||||
|
if (!stream)
|
||||||
|
return EOF;
|
||||||
|
return filestream_write(stream, &c_char, 1) == 1
|
||||||
|
? (int)(unsigned char)c
|
||||||
|
: EOF;
|
||||||
|
}
|
||||||
|
|
||||||
|
int filestream_vprintf(RFILE *stream, const char* format, va_list args)
|
||||||
|
{
|
||||||
|
static char buffer[8 * 1024];
|
||||||
|
int64_t num_chars = vsnprintf(buffer, sizeof(buffer),
|
||||||
|
format, args);
|
||||||
|
|
||||||
|
if (num_chars < 0)
|
||||||
|
return -1;
|
||||||
|
else if (num_chars == 0)
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
return (int)filestream_write(stream, buffer, num_chars);
|
||||||
|
}
|
||||||
|
|
||||||
|
int filestream_printf(RFILE *stream, const char* format, ...)
|
||||||
|
{
|
||||||
|
va_list vl;
|
||||||
|
int result;
|
||||||
|
va_start(vl, format);
|
||||||
|
result = filestream_vprintf(stream, format, vl);
|
||||||
|
va_end(vl);
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
int filestream_error(RFILE *stream)
|
||||||
|
{
|
||||||
|
if (stream && stream->error_flag)
|
||||||
|
return 1;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
int filestream_close(RFILE *stream)
|
||||||
|
{
|
||||||
|
int output;
|
||||||
|
struct retro_vfs_file_handle* fp = stream->hfile;
|
||||||
|
|
||||||
|
if (filestream_close_cb)
|
||||||
|
output = filestream_close_cb(fp);
|
||||||
|
else
|
||||||
|
output = retro_vfs_file_close_impl(
|
||||||
|
(libretro_vfs_implementation_file*)fp);
|
||||||
|
|
||||||
|
if (output == 0)
|
||||||
|
free(stream);
|
||||||
|
|
||||||
|
return output;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* filestream_read_file:
|
||||||
|
* @path : path to file.
|
||||||
|
* @buf : buffer to allocate and read the contents of the
|
||||||
|
* file into. Needs to be freed manually.
|
||||||
|
* @len : optional output integer containing bytes read.
|
||||||
|
*
|
||||||
|
* Read the contents of a file into @buf.
|
||||||
|
*
|
||||||
|
* Returns: non zero on success.
|
||||||
|
*/
|
||||||
|
int64_t filestream_read_file(const char *path, void **buf, int64_t *len)
|
||||||
|
{
|
||||||
|
int64_t ret = 0;
|
||||||
|
int64_t content_buf_size = 0;
|
||||||
|
void *content_buf = NULL;
|
||||||
|
RFILE *file = filestream_open(path,
|
||||||
|
RETRO_VFS_FILE_ACCESS_READ,
|
||||||
|
RETRO_VFS_FILE_ACCESS_HINT_NONE);
|
||||||
|
|
||||||
|
if (!file)
|
||||||
|
{
|
||||||
|
*buf = NULL;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
content_buf_size = filestream_get_size(file);
|
||||||
|
|
||||||
|
if (content_buf_size < 0)
|
||||||
|
goto error;
|
||||||
|
|
||||||
|
content_buf = malloc((size_t)(content_buf_size + 1));
|
||||||
|
|
||||||
|
if (!content_buf)
|
||||||
|
goto error;
|
||||||
|
if ((int64_t)(uint64_t)(content_buf_size + 1) != (content_buf_size + 1))
|
||||||
|
goto error;
|
||||||
|
|
||||||
|
ret = filestream_read(file, content_buf, (int64_t)content_buf_size);
|
||||||
|
if (ret < 0)
|
||||||
|
goto error;
|
||||||
|
|
||||||
|
if (filestream_close(file) != 0)
|
||||||
|
if (file)
|
||||||
|
free(file);
|
||||||
|
|
||||||
|
*buf = content_buf;
|
||||||
|
|
||||||
|
/* Allow for easy reading of strings to be safe.
|
||||||
|
* Will only work with sane character formatting (Unix). */
|
||||||
|
((char*)content_buf)[ret] = '\0';
|
||||||
|
|
||||||
|
if (len)
|
||||||
|
*len = ret;
|
||||||
|
|
||||||
|
return 1;
|
||||||
|
|
||||||
|
error:
|
||||||
|
if (file)
|
||||||
|
if (filestream_close(file) != 0)
|
||||||
|
free(file);
|
||||||
|
if (content_buf)
|
||||||
|
free(content_buf);
|
||||||
|
if (len)
|
||||||
|
*len = -1;
|
||||||
|
*buf = NULL;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* filestream_write_file:
|
||||||
|
* @path : path to file.
|
||||||
|
* @data : contents to write to the file.
|
||||||
|
* @size : size of the contents.
|
||||||
|
*
|
||||||
|
* Writes data to a file.
|
||||||
|
*
|
||||||
|
* Returns: true (1) on success, false (0) otherwise.
|
||||||
|
*/
|
||||||
|
bool filestream_write_file(const char *path, const void *data, int64_t size)
|
||||||
|
{
|
||||||
|
int64_t ret = 0;
|
||||||
|
RFILE *file = filestream_open(path,
|
||||||
|
RETRO_VFS_FILE_ACCESS_WRITE,
|
||||||
|
RETRO_VFS_FILE_ACCESS_HINT_NONE);
|
||||||
|
if (!file)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
ret = filestream_write(file, data, size);
|
||||||
|
if (filestream_close(file) != 0)
|
||||||
|
if (file)
|
||||||
|
free(file);
|
||||||
|
|
||||||
|
if (ret != size)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Returned pointer must be freed by the caller. */
|
||||||
|
char* filestream_getline(RFILE *stream)
|
||||||
|
{
|
||||||
|
char *newline_tmp = NULL;
|
||||||
|
size_t cur_size = 8;
|
||||||
|
size_t idx = 0;
|
||||||
|
int in = 0;
|
||||||
|
char *newline = (char*)malloc(9);
|
||||||
|
|
||||||
|
if (!stream || !newline)
|
||||||
|
{
|
||||||
|
if (newline)
|
||||||
|
free(newline);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
in = filestream_getc(stream);
|
||||||
|
|
||||||
|
while (in != EOF && in != '\n')
|
||||||
|
{
|
||||||
|
if (idx == cur_size)
|
||||||
|
{
|
||||||
|
cur_size *= 2;
|
||||||
|
newline_tmp = (char*)realloc(newline, cur_size + 1);
|
||||||
|
|
||||||
|
if (!newline_tmp)
|
||||||
|
{
|
||||||
|
free(newline);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
newline = newline_tmp;
|
||||||
|
}
|
||||||
|
|
||||||
|
newline[idx++] = in;
|
||||||
|
in = filestream_getc(stream);
|
||||||
|
}
|
||||||
|
|
||||||
|
newline[idx] = '\0';
|
||||||
|
return newline;
|
||||||
|
}
|
||||||
|
|
||||||
|
libretro_vfs_implementation_file* filestream_get_vfs_handle(RFILE *stream)
|
||||||
|
{
|
||||||
|
return (libretro_vfs_implementation_file*)stream->hfile;
|
||||||
|
}
|
159
libretro-common/streams/file_stream_transforms.c
Normal file
159
libretro-common/streams/file_stream_transforms.c
Normal file
@ -0,0 +1,159 @@
|
|||||||
|
/* Copyright (C) 2010-2020 The RetroArch team
|
||||||
|
*
|
||||||
|
* ---------------------------------------------------------------------------------------
|
||||||
|
* The following license statement only applies to this file (file_stream_transforms.c).
|
||||||
|
* ---------------------------------------------------------------------------------------
|
||||||
|
*
|
||||||
|
* Permission is hereby granted, free of charge,
|
||||||
|
* to any person obtaining a copy of this software and associated documentation files (the "Software"),
|
||||||
|
* to deal in the Software without restriction, including without limitation the rights to
|
||||||
|
* use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software,
|
||||||
|
* and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
|
||||||
|
*
|
||||||
|
* The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
|
||||||
|
*
|
||||||
|
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
|
||||||
|
* INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
|
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
|
||||||
|
* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
|
||||||
|
* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||||
|
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <string.h>
|
||||||
|
#include <stdarg.h>
|
||||||
|
|
||||||
|
#include <libretro.h>
|
||||||
|
#include <streams/file_stream.h>
|
||||||
|
|
||||||
|
RFILE* rfopen(const char *path, const char *mode)
|
||||||
|
{
|
||||||
|
RFILE *output = NULL;
|
||||||
|
unsigned int retro_mode = RETRO_VFS_FILE_ACCESS_READ;
|
||||||
|
bool position_to_end = false;
|
||||||
|
|
||||||
|
if (strstr(mode, "r"))
|
||||||
|
{
|
||||||
|
retro_mode = RETRO_VFS_FILE_ACCESS_READ;
|
||||||
|
if (strstr(mode, "+"))
|
||||||
|
{
|
||||||
|
retro_mode = RETRO_VFS_FILE_ACCESS_READ_WRITE |
|
||||||
|
RETRO_VFS_FILE_ACCESS_UPDATE_EXISTING;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if (strstr(mode, "w"))
|
||||||
|
{
|
||||||
|
retro_mode = RETRO_VFS_FILE_ACCESS_WRITE;
|
||||||
|
if (strstr(mode, "+"))
|
||||||
|
retro_mode = RETRO_VFS_FILE_ACCESS_READ_WRITE;
|
||||||
|
}
|
||||||
|
else if (strstr(mode, "a"))
|
||||||
|
{
|
||||||
|
retro_mode = RETRO_VFS_FILE_ACCESS_WRITE |
|
||||||
|
RETRO_VFS_FILE_ACCESS_UPDATE_EXISTING;
|
||||||
|
position_to_end = true;
|
||||||
|
if (strstr(mode, "+"))
|
||||||
|
{
|
||||||
|
retro_mode = RETRO_VFS_FILE_ACCESS_READ_WRITE |
|
||||||
|
RETRO_VFS_FILE_ACCESS_UPDATE_EXISTING;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
output = filestream_open(path, retro_mode,
|
||||||
|
RETRO_VFS_FILE_ACCESS_HINT_NONE);
|
||||||
|
if (output && position_to_end)
|
||||||
|
filestream_seek(output, 0, RETRO_VFS_SEEK_POSITION_END);
|
||||||
|
|
||||||
|
return output;
|
||||||
|
}
|
||||||
|
|
||||||
|
int rfclose(RFILE* stream)
|
||||||
|
{
|
||||||
|
return filestream_close(stream);
|
||||||
|
}
|
||||||
|
|
||||||
|
int64_t rftell(RFILE* stream)
|
||||||
|
{
|
||||||
|
return filestream_tell(stream);
|
||||||
|
}
|
||||||
|
|
||||||
|
int64_t rfseek(RFILE* stream, int64_t offset, int origin)
|
||||||
|
{
|
||||||
|
int seek_position = -1;
|
||||||
|
switch (origin)
|
||||||
|
{
|
||||||
|
case SEEK_SET:
|
||||||
|
seek_position = RETRO_VFS_SEEK_POSITION_START;
|
||||||
|
break;
|
||||||
|
case SEEK_CUR:
|
||||||
|
seek_position = RETRO_VFS_SEEK_POSITION_CURRENT;
|
||||||
|
break;
|
||||||
|
case SEEK_END:
|
||||||
|
seek_position = RETRO_VFS_SEEK_POSITION_END;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
return filestream_seek(stream, offset, seek_position);
|
||||||
|
}
|
||||||
|
|
||||||
|
int64_t rfread(void* buffer,
|
||||||
|
size_t elem_size, size_t elem_count, RFILE* stream)
|
||||||
|
{
|
||||||
|
return (filestream_read(stream, buffer, elem_size * elem_count) / elem_size);
|
||||||
|
}
|
||||||
|
|
||||||
|
char *rfgets(char *buffer, int maxCount, RFILE* stream)
|
||||||
|
{
|
||||||
|
return filestream_gets(stream, buffer, maxCount);
|
||||||
|
}
|
||||||
|
|
||||||
|
int rfgetc(RFILE* stream)
|
||||||
|
{
|
||||||
|
return filestream_getc(stream);
|
||||||
|
}
|
||||||
|
|
||||||
|
int64_t rfwrite(void const* buffer,
|
||||||
|
size_t elem_size, size_t elem_count, RFILE* stream)
|
||||||
|
{
|
||||||
|
return filestream_write(stream, buffer, elem_size * elem_count);
|
||||||
|
}
|
||||||
|
|
||||||
|
int rfputc(int character, RFILE * stream)
|
||||||
|
{
|
||||||
|
return filestream_putc(stream, character);
|
||||||
|
}
|
||||||
|
|
||||||
|
int64_t rfflush(RFILE * stream)
|
||||||
|
{
|
||||||
|
return filestream_flush(stream);
|
||||||
|
}
|
||||||
|
|
||||||
|
int rfprintf(RFILE * stream, const char * format, ...)
|
||||||
|
{
|
||||||
|
int result;
|
||||||
|
va_list vl;
|
||||||
|
va_start(vl, format);
|
||||||
|
result = filestream_vprintf(stream, format, vl);
|
||||||
|
va_end(vl);
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
int rferror(RFILE* stream)
|
||||||
|
{
|
||||||
|
return filestream_error(stream);
|
||||||
|
}
|
||||||
|
|
||||||
|
int rfeof(RFILE* stream)
|
||||||
|
{
|
||||||
|
return filestream_eof(stream);
|
||||||
|
}
|
||||||
|
|
||||||
|
int rfscanf(RFILE * stream, const char * format, ...)
|
||||||
|
{
|
||||||
|
int result;
|
||||||
|
va_list vl;
|
||||||
|
va_start(vl, format);
|
||||||
|
result = filestream_scanf(stream, format, vl);
|
||||||
|
va_end(vl);
|
||||||
|
return result;
|
||||||
|
}
|
536
libretro-common/string/stdstring.c
Normal file
536
libretro-common/string/stdstring.c
Normal file
@ -0,0 +1,536 @@
|
|||||||
|
/* Copyright (C) 2010-2020 The RetroArch team
|
||||||
|
*
|
||||||
|
* ---------------------------------------------------------------------------------------
|
||||||
|
* The following license statement only applies to this file (stdstring.c).
|
||||||
|
* ---------------------------------------------------------------------------------------
|
||||||
|
*
|
||||||
|
* Permission is hereby granted, free of charge,
|
||||||
|
* to any person obtaining a copy of this software and associated documentation files (the "Software"),
|
||||||
|
* to deal in the Software without restriction, including without limitation the rights to
|
||||||
|
* use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software,
|
||||||
|
* and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
|
||||||
|
*
|
||||||
|
* The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
|
||||||
|
*
|
||||||
|
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
|
||||||
|
* INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
|
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
|
||||||
|
* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
|
||||||
|
* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||||
|
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <stdint.h>
|
||||||
|
#include <ctype.h>
|
||||||
|
#include <string.h>
|
||||||
|
|
||||||
|
#include <string/stdstring.h>
|
||||||
|
#include <encodings/utf.h>
|
||||||
|
|
||||||
|
const uint8_t lr_char_props[256] = {
|
||||||
|
/*x0 x1 x2 x3 x4 x5 x6 x7 x8 x9 xA xB xC xD xE xF */
|
||||||
|
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x80,0x80,0x00,0x00,0x80,0x00,0x00, /* 0x */
|
||||||
|
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, /* 1x */
|
||||||
|
0x80,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, /* 2x !"#$%&'()*+,-./ */
|
||||||
|
0x41,0x41,0x41,0x41,0x41,0x41,0x41,0x41,0x41,0x41,0x00,0x00,0x00,0x00,0x00,0x00, /* 3x 0123456789:;<=>? */
|
||||||
|
0x00,0x23,0x23,0x23,0x23,0x23,0x23,0x22,0x22,0x22,0x22,0x22,0x22,0x22,0x22,0x22, /* 4x @ABCDEFGHIJKLMNO */
|
||||||
|
0x22,0x22,0x22,0x22,0x22,0x22,0x22,0x22,0x22,0x22,0x22,0x00,0x00,0x00,0x00,0x08, /* 5x PQRSTUVWXYZ[\]^_ */
|
||||||
|
0x00,0x25,0x25,0x25,0x25,0x25,0x25,0x24,0x24,0x24,0x24,0x24,0x24,0x24,0x24,0x24, /* 6x `abcdefghijklmno */
|
||||||
|
0x24,0x24,0x24,0x24,0x24,0x24,0x24,0x24,0x24,0x24,0x24,0x00,0x00,0x00,0x00,0x00, /* 7x pqrstuvwxyz{|}~ */
|
||||||
|
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, /* 8x */
|
||||||
|
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, /* 9x */
|
||||||
|
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, /* Ax */
|
||||||
|
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, /* Bx */
|
||||||
|
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, /* Cx */
|
||||||
|
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, /* Dx */
|
||||||
|
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, /* Ex */
|
||||||
|
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, /* Fx */
|
||||||
|
};
|
||||||
|
|
||||||
|
char *string_init(const char *src)
|
||||||
|
{
|
||||||
|
return src ? strdup(src) : NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
void string_set(char **string, const char *src)
|
||||||
|
{
|
||||||
|
free(*string);
|
||||||
|
*string = string_init(src);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
char *string_to_upper(char *s)
|
||||||
|
{
|
||||||
|
char *cs = (char *)s;
|
||||||
|
for ( ; *cs != '\0'; cs++)
|
||||||
|
*cs = toupper((unsigned char)*cs);
|
||||||
|
return s;
|
||||||
|
}
|
||||||
|
|
||||||
|
char *string_to_lower(char *s)
|
||||||
|
{
|
||||||
|
char *cs = (char *)s;
|
||||||
|
for ( ; *cs != '\0'; cs++)
|
||||||
|
*cs = tolower((unsigned char)*cs);
|
||||||
|
return s;
|
||||||
|
}
|
||||||
|
|
||||||
|
char *string_ucwords(char *s)
|
||||||
|
{
|
||||||
|
char *cs = (char *)s;
|
||||||
|
for ( ; *cs != '\0'; cs++)
|
||||||
|
{
|
||||||
|
if (*cs == ' ')
|
||||||
|
*(cs+1) = toupper((unsigned char)*(cs+1));
|
||||||
|
}
|
||||||
|
|
||||||
|
s[0] = toupper((unsigned char)s[0]);
|
||||||
|
return s;
|
||||||
|
}
|
||||||
|
|
||||||
|
char *string_replace_substring(const char *in,
|
||||||
|
const char *pattern, const char *replacement)
|
||||||
|
{
|
||||||
|
size_t numhits, pattern_len, replacement_len, outlen;
|
||||||
|
const char *inat = NULL;
|
||||||
|
const char *inprev = NULL;
|
||||||
|
char *out = NULL;
|
||||||
|
char *outat = NULL;
|
||||||
|
|
||||||
|
/* if either pattern or replacement is NULL,
|
||||||
|
* duplicate in and let caller handle it. */
|
||||||
|
if (!pattern || !replacement)
|
||||||
|
return strdup(in);
|
||||||
|
|
||||||
|
pattern_len = strlen(pattern);
|
||||||
|
replacement_len = strlen(replacement);
|
||||||
|
numhits = 0;
|
||||||
|
inat = in;
|
||||||
|
|
||||||
|
while ((inat = strstr(inat, pattern)))
|
||||||
|
{
|
||||||
|
inat += pattern_len;
|
||||||
|
numhits++;
|
||||||
|
}
|
||||||
|
|
||||||
|
outlen = strlen(in) - pattern_len*numhits + replacement_len*numhits;
|
||||||
|
out = (char *)malloc(outlen+1);
|
||||||
|
|
||||||
|
if (!out)
|
||||||
|
return NULL;
|
||||||
|
|
||||||
|
outat = out;
|
||||||
|
inat = in;
|
||||||
|
inprev = in;
|
||||||
|
|
||||||
|
while ((inat = strstr(inat, pattern)))
|
||||||
|
{
|
||||||
|
memcpy(outat, inprev, inat-inprev);
|
||||||
|
outat += inat-inprev;
|
||||||
|
memcpy(outat, replacement, replacement_len);
|
||||||
|
outat += replacement_len;
|
||||||
|
inat += pattern_len;
|
||||||
|
inprev = inat;
|
||||||
|
}
|
||||||
|
strcpy(outat, inprev);
|
||||||
|
|
||||||
|
return out;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Remove leading whitespaces */
|
||||||
|
char *string_trim_whitespace_left(char *const s)
|
||||||
|
{
|
||||||
|
if (s && *s)
|
||||||
|
{
|
||||||
|
size_t len = strlen(s);
|
||||||
|
char *current = s;
|
||||||
|
|
||||||
|
while (*current && ISSPACE((unsigned char)*current))
|
||||||
|
{
|
||||||
|
++current;
|
||||||
|
--len;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (s != current)
|
||||||
|
memmove(s, current, len + 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
return s;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Remove trailing whitespaces */
|
||||||
|
char *string_trim_whitespace_right(char *const s)
|
||||||
|
{
|
||||||
|
if (s && *s)
|
||||||
|
{
|
||||||
|
size_t len = strlen(s);
|
||||||
|
char *current = s + len - 1;
|
||||||
|
|
||||||
|
while (current != s && ISSPACE((unsigned char)*current))
|
||||||
|
{
|
||||||
|
--current;
|
||||||
|
--len;
|
||||||
|
}
|
||||||
|
|
||||||
|
current[ISSPACE((unsigned char)*current) ? 0 : 1] = '\0';
|
||||||
|
}
|
||||||
|
|
||||||
|
return s;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Remove leading and trailing whitespaces */
|
||||||
|
char *string_trim_whitespace(char *const s)
|
||||||
|
{
|
||||||
|
string_trim_whitespace_right(s); /* order matters */
|
||||||
|
string_trim_whitespace_left(s);
|
||||||
|
|
||||||
|
return s;
|
||||||
|
}
|
||||||
|
|
||||||
|
void word_wrap(char *dst, size_t dst_size, const char *src, int line_width, int wideglyph_width, unsigned max_lines)
|
||||||
|
{
|
||||||
|
char *lastspace = NULL;
|
||||||
|
unsigned counter = 0;
|
||||||
|
unsigned lines = 1;
|
||||||
|
size_t src_len = strlen(src);
|
||||||
|
const char *src_end = src + src_len;
|
||||||
|
|
||||||
|
/* Prevent buffer overflow */
|
||||||
|
if (dst_size < src_len + 1)
|
||||||
|
return;
|
||||||
|
|
||||||
|
/* Early return if src string length is less
|
||||||
|
* than line width */
|
||||||
|
if (src_len < line_width)
|
||||||
|
{
|
||||||
|
strcpy(dst, src);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
while (*src != '\0')
|
||||||
|
{
|
||||||
|
unsigned char_len;
|
||||||
|
|
||||||
|
char_len = (unsigned)(utf8skip(src, 1) - src);
|
||||||
|
counter++;
|
||||||
|
|
||||||
|
if (*src == ' ')
|
||||||
|
lastspace = dst; /* Remember the location of the whitespace */
|
||||||
|
else if (*src == '\n')
|
||||||
|
{
|
||||||
|
/* If newlines embedded in the input,
|
||||||
|
* reset the index */
|
||||||
|
lines++;
|
||||||
|
counter = 0;
|
||||||
|
|
||||||
|
/* Early return if remaining src string
|
||||||
|
* length is less than line width */
|
||||||
|
if (src_end - src <= line_width)
|
||||||
|
{
|
||||||
|
strcpy(dst, src);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
while (char_len--)
|
||||||
|
*dst++ = *src++;
|
||||||
|
|
||||||
|
if (counter >= (unsigned)line_width)
|
||||||
|
{
|
||||||
|
counter = 0;
|
||||||
|
|
||||||
|
if (lastspace && (max_lines == 0 || lines < max_lines))
|
||||||
|
{
|
||||||
|
/* Replace nearest (previous) whitespace
|
||||||
|
* with newline character */
|
||||||
|
*lastspace = '\n';
|
||||||
|
lines++;
|
||||||
|
|
||||||
|
src -= dst - lastspace - 1;
|
||||||
|
dst = lastspace + 1;
|
||||||
|
lastspace = NULL;
|
||||||
|
|
||||||
|
/* Early return if remaining src string
|
||||||
|
* length is less than line width */
|
||||||
|
if (src_end - src < line_width)
|
||||||
|
{
|
||||||
|
strcpy(dst, src);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
*dst = '\0';
|
||||||
|
}
|
||||||
|
|
||||||
|
void word_wrap_wideglyph(char *dst, size_t dst_size, const char *src, int line_width, int wideglyph_width, unsigned max_lines)
|
||||||
|
{
|
||||||
|
char *lastspace = NULL;
|
||||||
|
char *lastwideglyph = NULL;
|
||||||
|
const char *src_end = src + strlen(src);
|
||||||
|
unsigned lines = 1;
|
||||||
|
/* 'line_width' means max numbers of characters per line,
|
||||||
|
* but this metric is only meaningful when dealing with
|
||||||
|
* 'regular' glyphs that have an on-screen pixel width
|
||||||
|
* similar to that of regular Latin characters.
|
||||||
|
* When handing so-called 'wide' Unicode glyphs, it is
|
||||||
|
* necessary to consider the actual on-screen pixel width
|
||||||
|
* of each character.
|
||||||
|
* In order to do this, we create a distinction between
|
||||||
|
* regular Latin 'non-wide' glyphs and 'wide' glyphs, and
|
||||||
|
* normalise all values relative to the on-screen pixel
|
||||||
|
* width of regular Latin characters:
|
||||||
|
* - Regular 'non-wide' glyphs have a normalised width of 100
|
||||||
|
* - 'line_width' is therefore normalised to 100 * (width_in_characters)
|
||||||
|
* - 'wide' glyphs have a normalised width of
|
||||||
|
* 100 * (wide_character_pixel_width / latin_character_pixel_width)
|
||||||
|
* - When a character is detected, the position in the current
|
||||||
|
* line is incremented by the regular normalised width of 100
|
||||||
|
* - If that character is then determined to be a 'wide'
|
||||||
|
* glyph, the position in the current line is further incremented
|
||||||
|
* by the difference between the normalised 'wide' and 'non-wide'
|
||||||
|
* width values */
|
||||||
|
unsigned counter_normalized = 0;
|
||||||
|
int line_width_normalized = line_width * 100;
|
||||||
|
int additional_counter_normalized = wideglyph_width - 100;
|
||||||
|
|
||||||
|
/* Early return if src string length is less
|
||||||
|
* than line width */
|
||||||
|
if (src_end - src < line_width)
|
||||||
|
{
|
||||||
|
strlcpy(dst, src, dst_size);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
while (*src != '\0')
|
||||||
|
{
|
||||||
|
unsigned char_len;
|
||||||
|
|
||||||
|
char_len = (unsigned)(utf8skip(src, 1) - src);
|
||||||
|
counter_normalized += 100;
|
||||||
|
|
||||||
|
/* Prevent buffer overflow */
|
||||||
|
if (char_len >= dst_size)
|
||||||
|
break;
|
||||||
|
|
||||||
|
if (*src == ' ')
|
||||||
|
lastspace = dst; /* Remember the location of the whitespace */
|
||||||
|
else if (*src == '\n')
|
||||||
|
{
|
||||||
|
/* If newlines embedded in the input,
|
||||||
|
* reset the index */
|
||||||
|
lines++;
|
||||||
|
counter_normalized = 0;
|
||||||
|
|
||||||
|
/* Early return if remaining src string
|
||||||
|
* length is less than line width */
|
||||||
|
if (src_end - src <= line_width)
|
||||||
|
{
|
||||||
|
strlcpy(dst, src, dst_size);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if (char_len >= 3)
|
||||||
|
{
|
||||||
|
/* Remember the location of the first byte
|
||||||
|
* whose length as UTF-8 >= 3*/
|
||||||
|
lastwideglyph = dst;
|
||||||
|
counter_normalized += additional_counter_normalized;
|
||||||
|
}
|
||||||
|
|
||||||
|
dst_size -= char_len;
|
||||||
|
while (char_len--)
|
||||||
|
*dst++ = *src++;
|
||||||
|
|
||||||
|
if (counter_normalized >= (unsigned)line_width_normalized)
|
||||||
|
{
|
||||||
|
counter_normalized = 0;
|
||||||
|
|
||||||
|
if (max_lines != 0 && lines >= max_lines)
|
||||||
|
continue;
|
||||||
|
else if (lastwideglyph && (!lastspace || lastwideglyph > lastspace))
|
||||||
|
{
|
||||||
|
/* Insert newline character */
|
||||||
|
*lastwideglyph = '\n';
|
||||||
|
lines++;
|
||||||
|
src -= dst - lastwideglyph;
|
||||||
|
dst = lastwideglyph + 1;
|
||||||
|
lastwideglyph = NULL;
|
||||||
|
|
||||||
|
/* Early return if remaining src string
|
||||||
|
* length is less than line width */
|
||||||
|
if (src_end - src <= line_width)
|
||||||
|
{
|
||||||
|
strlcpy(dst, src, dst_size);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if (lastspace)
|
||||||
|
{
|
||||||
|
/* Replace nearest (previous) whitespace
|
||||||
|
* with newline character */
|
||||||
|
*lastspace = '\n';
|
||||||
|
lines++;
|
||||||
|
src -= dst - lastspace - 1;
|
||||||
|
dst = lastspace + 1;
|
||||||
|
lastspace = NULL;
|
||||||
|
|
||||||
|
/* Early return if remaining src string
|
||||||
|
* length is less than line width */
|
||||||
|
if (src_end - src < line_width)
|
||||||
|
{
|
||||||
|
strlcpy(dst, src, dst_size);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
*dst = '\0';
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Splits string into tokens seperated by 'delim'
|
||||||
|
* > 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((unsigned char)*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((unsigned char)*ptr))
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
return (unsigned)strtoul(hex_str, NULL, 16);
|
||||||
|
}
|
81
libretro-common/time/rtime.c
Normal file
81
libretro-common/time/rtime.c
Normal file
@ -0,0 +1,81 @@
|
|||||||
|
/* Copyright (C) 2010-2020 The RetroArch team
|
||||||
|
*
|
||||||
|
* ---------------------------------------------------------------------------------------
|
||||||
|
* The following license statement only applies to this file (rtime.c).
|
||||||
|
* ---------------------------------------------------------------------------------------
|
||||||
|
*
|
||||||
|
* Permission is hereby granted, free of charge,
|
||||||
|
* to any person obtaining a copy of this software and associated documentation files (the "Software"),
|
||||||
|
* to deal in the Software without restriction, including without limitation the rights to
|
||||||
|
* use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software,
|
||||||
|
* and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
|
||||||
|
*
|
||||||
|
* The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
|
||||||
|
*
|
||||||
|
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
|
||||||
|
* INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
|
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
|
||||||
|
* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
|
||||||
|
* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||||
|
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifdef HAVE_THREADS
|
||||||
|
#include <rthreads/rthreads.h>
|
||||||
|
#include <retro_assert.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#include <string.h>
|
||||||
|
#include <time/rtime.h>
|
||||||
|
|
||||||
|
#ifdef HAVE_THREADS
|
||||||
|
/* TODO/FIXME - global */
|
||||||
|
slock_t *rtime_localtime_lock = NULL;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/* Must be called before using rtime_localtime() */
|
||||||
|
void rtime_init(void)
|
||||||
|
{
|
||||||
|
rtime_deinit();
|
||||||
|
#ifdef HAVE_THREADS
|
||||||
|
if (!rtime_localtime_lock)
|
||||||
|
rtime_localtime_lock = slock_new();
|
||||||
|
|
||||||
|
retro_assert(rtime_localtime_lock);
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Must be called upon program termination */
|
||||||
|
void rtime_deinit(void)
|
||||||
|
{
|
||||||
|
#ifdef HAVE_THREADS
|
||||||
|
if (rtime_localtime_lock)
|
||||||
|
{
|
||||||
|
slock_free(rtime_localtime_lock);
|
||||||
|
rtime_localtime_lock = NULL;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Thread-safe wrapper for localtime() */
|
||||||
|
struct tm *rtime_localtime(const time_t *timep, struct tm *result)
|
||||||
|
{
|
||||||
|
struct tm *time_info = NULL;
|
||||||
|
|
||||||
|
/* Lock mutex */
|
||||||
|
#ifdef HAVE_THREADS
|
||||||
|
slock_lock(rtime_localtime_lock);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
time_info = localtime(timep);
|
||||||
|
if (time_info)
|
||||||
|
memcpy(result, time_info, sizeof(struct tm));
|
||||||
|
|
||||||
|
/* Unlock mutex */
|
||||||
|
#ifdef HAVE_THREADS
|
||||||
|
slock_unlock(rtime_localtime_lock);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
1335
libretro-common/vfs/vfs_implementation.c
Normal file
1335
libretro-common/vfs/vfs_implementation.c
Normal file
File diff suppressed because it is too large
Load Diff
@ -3,6 +3,7 @@
|
|||||||
#include "log.h"
|
#include "log.h"
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
|
#include <streams/file_stream.h>
|
||||||
|
|
||||||
#include "../types.h"
|
#include "../types.h"
|
||||||
#include "../state.h"
|
#include "../state.h"
|
||||||
@ -241,6 +242,7 @@ void retro_deinit(void)
|
|||||||
|
|
||||||
void retro_set_environment(retro_environment_t cb)
|
void retro_set_environment(retro_environment_t cb)
|
||||||
{
|
{
|
||||||
|
struct retro_vfs_interface_info vfs_iface_info;
|
||||||
static const struct retro_system_content_info_override content_overrides[] = {
|
static const struct retro_system_content_info_override content_overrides[] = {
|
||||||
{
|
{
|
||||||
RACE_EXTENSIONS, /* extensions */
|
RACE_EXTENSIONS, /* extensions */
|
||||||
@ -256,6 +258,11 @@ void retro_set_environment(retro_environment_t cb)
|
|||||||
|
|
||||||
environ_cb = cb;
|
environ_cb = cb;
|
||||||
|
|
||||||
|
vfs_iface_info.required_interface_version = 1;
|
||||||
|
vfs_iface_info.iface = NULL;
|
||||||
|
if (environ_cb(RETRO_ENVIRONMENT_GET_VFS_INTERFACE, &vfs_iface_info))
|
||||||
|
filestream_vfs_init(&vfs_iface_info);
|
||||||
|
|
||||||
libretro_set_core_options(environ_cb);
|
libretro_set_core_options(environ_cb);
|
||||||
environ_cb(RETRO_ENVIRONMENT_SET_CONTENT_INFO_OVERRIDE,
|
environ_cb(RETRO_ENVIRONMENT_SET_CONTENT_INFO_OVERRIDE,
|
||||||
(void*)content_overrides);
|
(void*)content_overrides);
|
||||||
|
22
main.c
22
main.c
@ -15,7 +15,7 @@
|
|||||||
#include "main.h"
|
#include "main.h"
|
||||||
|
|
||||||
#include <libretro.h>
|
#include <libretro.h>
|
||||||
|
#include <streams/file_stream.h>
|
||||||
|
|
||||||
#include "flash.h"
|
#include "flash.h"
|
||||||
#include "race-memory.h"
|
#include "race-memory.h"
|
||||||
@ -229,20 +229,30 @@ int handleInputFile(const char *romName,
|
|||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
FILE *romFile = NULL;
|
RFILE *romFile = NULL;
|
||||||
|
int64_t size = 0;
|
||||||
|
|
||||||
//get ROM from binary ROM file
|
//get ROM from binary ROM file
|
||||||
romFile = fopen(romName, "rb");
|
romFile = filestream_open(romName,
|
||||||
|
RETRO_VFS_FILE_ACCESS_READ,
|
||||||
|
RETRO_VFS_FILE_ACCESS_HINT_NONE);
|
||||||
if(!romFile)
|
if(!romFile)
|
||||||
{
|
{
|
||||||
log_cb(RETRO_LOG_ERROR, "Couldn't open %s file\n", romName);
|
log_cb(RETRO_LOG_ERROR, "Couldn't open %s file\n", romName);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
m_emuInfo.romSize = fread(mainrom, 1, MAINROM_SIZE_MAX, romFile);
|
size = filestream_read(romFile, mainrom, MAINROM_SIZE_MAX);
|
||||||
strcpy(m_emuInfo.RomFileName, romName);
|
filestream_close(romFile);
|
||||||
|
|
||||||
fclose(romFile);
|
if (size <= 0)
|
||||||
|
{
|
||||||
|
log_cb(RETRO_LOG_ERROR, "Couldn't read %s file\n", romName);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
m_emuInfo.romSize = (int)size;
|
||||||
|
strcpy(m_emuInfo.RomFileName, romName);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!initRom())
|
if (!initRom())
|
||||||
|
@ -15,6 +15,10 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
|
#if 0
|
||||||
|
#include <streams/file_stream.h>
|
||||||
|
#endif
|
||||||
|
|
||||||
#include "race-memory.h"
|
#include "race-memory.h"
|
||||||
#include "types.h"
|
#include "types.h"
|
||||||
#include "input.h" /* for Gameboy Input */
|
#include "input.h" /* for Gameboy Input */
|
||||||
@ -339,17 +343,30 @@ const unsigned int ngpVectors[0x21] = {
|
|||||||
/* return 0 on fail */
|
/* return 0 on fail */
|
||||||
static unsigned char loadBIOS(void)
|
static unsigned char loadBIOS(void)
|
||||||
{
|
{
|
||||||
int bytesRead;
|
#if 0
|
||||||
FILE *biosFile = fopen("NPBIOS.BIN", "rb");
|
int64_t bytesRead;
|
||||||
|
RFILE *biosFile = filestream_open("NPBIOS.BIN",
|
||||||
|
RETRO_VFS_FILE_ACCESS_READ,
|
||||||
|
RETRO_VFS_FILE_ACCESS_HINT_NONE);
|
||||||
|
|
||||||
if(!biosFile)
|
if(!biosFile)
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
bytesRead = fread(cpurom, 1, 0x10000, biosFile);
|
bytesRead = filestream_read(biosFile, cpurom, 0x10000);
|
||||||
fclose(biosFile);
|
filestream_close(biosFile);
|
||||||
|
|
||||||
if(bytesRead != 0x10000)
|
if(bytesRead != 0x10000)
|
||||||
return 0;
|
return 0;
|
||||||
return 1;
|
return 1;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/* Using a real bios file causes nothing but issues.
|
||||||
|
* The relevant code path has not been thoroughly tested,
|
||||||
|
* and there are known errors - e.g. the Test Mode button
|
||||||
|
* does not work correctly in Card Fighters' Clash.
|
||||||
|
* We therefore force-disable the loading of real bios
|
||||||
|
* files */
|
||||||
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
void mem_init(void)
|
void mem_init(void)
|
||||||
@ -443,11 +460,21 @@ void mem_init(void)
|
|||||||
//koyote.bin handling
|
//koyote.bin handling
|
||||||
memcpy(mainram,koyote_bin,KOYOTE_BIN_SIZE/*12*1024*/);
|
memcpy(mainram,koyote_bin,KOYOTE_BIN_SIZE/*12*1024*/);
|
||||||
|
|
||||||
/* FILE *fp=fopen("koyote.bin","rb");
|
/* What is this code, and why is it disabled?
|
||||||
|
* koyote.bin is supposed to be a memory dump from the
|
||||||
|
* console immediately after a boot (i.e. bios has executed
|
||||||
|
* all of its routines and the ROM has just loaded, giving
|
||||||
|
* us a fresh RAM post-bios). But it seems we already have
|
||||||
|
* this data in koyote_bin. So why were we reading from
|
||||||
|
* file here? And if this is legacy code (replaced by
|
||||||
|
* koyote_bin), why not outright delete it? */
|
||||||
|
#if 0
|
||||||
|
RFILE *fp = filestream_open("koyote.bin", RETRO_VFS_FILE_ACCESS_READ,
|
||||||
|
RETRO_VFS_FILE_ACCESS_HINT_NONE)
|
||||||
if (fp!=NULL)
|
if (fp!=NULL)
|
||||||
{
|
{
|
||||||
fread(mainram,1,12*1024,fp);
|
filestream_read(fp, mainram, KOYOTE_BIN_SIZE/*12*1024*/);
|
||||||
fclose(fp);
|
filestream_close(fp);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
@ -455,8 +482,8 @@ void mem_init(void)
|
|||||||
for(i=0; i<18; i++) {
|
for(i=0; i<18; i++) {
|
||||||
*((unsigned int *)(&mainram[0x2FB8+4*i])) = (unsigned int)0x00FFF800;
|
*((unsigned int *)(&mainram[0x2FB8+4*i])) = (unsigned int)0x00FFF800;
|
||||||
}
|
}
|
||||||
}*/
|
}
|
||||||
|
#endif
|
||||||
// setup the additional CPU ram
|
// setup the additional CPU ram
|
||||||
// interrupt priorities, timer settings, transfer settings, etc
|
// interrupt priorities, timer settings, transfer settings, etc
|
||||||
for(i=0; i<sizeof(ngpcpuram); i++)
|
for(i=0; i<sizeof(ngpcpuram); i++)
|
||||||
|
12
tlcs900h.c
12
tlcs900h.c
@ -383,7 +383,17 @@ static INLINE void tlcsMemWriteL(unsigned int addr, unsigned int data)
|
|||||||
{
|
{
|
||||||
tlcsFastMemWriteL(addr, data);
|
tlcsFastMemWriteL(addr, data);
|
||||||
}
|
}
|
||||||
else
|
// tlcsFastMemWriteB() writes to
|
||||||
|
// mainram[((addr&0xFFFFFF)-0x00004000)]
|
||||||
|
// > If (addr + 3) is greater than mainram
|
||||||
|
// size ((64+32+128)*1024) then buffer
|
||||||
|
// will overflow and core will likely
|
||||||
|
// segfault
|
||||||
|
// > This should in theory never happen,
|
||||||
|
// but it occurs randomly in some games.
|
||||||
|
// Until the root cause is identified,
|
||||||
|
// just place a guard here...
|
||||||
|
else if (addr < 0x0003C000 - 3)
|
||||||
{
|
{
|
||||||
tlcsMemWriteB(addr, (unsigned char)(data & 0xFF));
|
tlcsMemWriteB(addr, (unsigned char)(data & 0xFF));
|
||||||
tlcsFastMemWriteB(addr+1, (unsigned char)((data>>8) & 0xFF));
|
tlcsFastMemWriteB(addr+1, (unsigned char)((data>>8) & 0xFF));
|
||||||
|
Loading…
Reference in New Issue
Block a user