Merge commit 'dec0d4ec4153bf9fc2b78ae6c2df45b6ea8dde7a' as 'external/sdl/SDL'

This commit is contained in:
2023-07-25 22:27:55 +02:00
1663 changed files with 627495 additions and 0 deletions

View File

@ -0,0 +1,61 @@
/*
Simple DirectMedia Layer
Copyright (C) 1997-2023 Sam Lantinga <slouken@libsdl.org>
This software is provided 'as-is', without any express or implied
warranty. In no event will the authors be held liable for any damages
arising from the use of this software.
Permission is granted to anyone to use this software for any purpose,
including commercial applications, and to alter it and redistribute it
freely, subject to the following restrictions:
1. The origin of this software must not be misrepresented; you must not
claim that you wrote the original software. If you use this software
in a product, an acknowledgment in the product documentation would be
appreciated but is not required.
2. Altered source versions must be plainly marked as such, and must not be
misrepresented as being the original software.
3. This notice may not be removed or altered from any source distribution.
*/
#include "SDL_internal.h"
#ifdef SDL_FILESYSTEM_ANDROID
/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
/* System dependent filesystem routines */
#include <unistd.h>
char *SDL_GetBasePath(void)
{
/* The current working directory is / on Android */
SDL_Unsupported();
return NULL;
}
char *SDL_GetPrefPath(const char *org, const char *app)
{
const char *path = SDL_AndroidGetInternalStoragePath();
if (path) {
size_t pathlen = SDL_strlen(path) + 2;
char *fullpath = (char *)SDL_malloc(pathlen);
if (fullpath == NULL) {
SDL_OutOfMemory();
return NULL;
}
SDL_snprintf(fullpath, pathlen, "%s/", path);
return fullpath;
}
return NULL;
}
char *SDL_GetPath(SDL_Folder folder)
{
/* TODO: see https://developer.android.com/reference/android/os/Environment#lfields
and https://stackoverflow.com/questions/39332085/get-path-to-pictures-directory */
SDL_Unsupported();
return NULL;
}
#endif /* SDL_FILESYSTEM_ANDROID */

View File

@ -0,0 +1,242 @@
/*
Simple DirectMedia Layer
Copyright (C) 1997-2023 Sam Lantinga <slouken@libsdl.org>
This software is provided 'as-is', without any express or implied
warranty. In no event will the authors be held liable for any damages
arising from the use of this software.
Permission is granted to anyone to use this software for any purpose,
including commercial applications, and to alter it and redistribute it
freely, subject to the following restrictions:
1. The origin of this software must not be misrepresented; you must not
claim that you wrote the original software. If you use this software
in a product, an acknowledgment in the product documentation would be
appreciated but is not required.
2. Altered source versions must be plainly marked as such, and must not be
misrepresented as being the original software.
3. This notice may not be removed or altered from any source distribution.
*/
#include "SDL_internal.h"
#ifdef SDL_FILESYSTEM_COCOA
/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
/* System dependent filesystem routines */
#include <Foundation/Foundation.h>
#include <sys/stat.h>
#include <sys/types.h>
char *SDL_GetBasePath(void)
{
@autoreleasepool {
NSBundle *bundle = [NSBundle mainBundle];
const char *baseType = [[[bundle infoDictionary] objectForKey:@"SDL_FILESYSTEM_BASE_DIR_TYPE"] UTF8String];
const char *base = NULL;
char *retval = NULL;
if (baseType == NULL) {
baseType = "resource";
}
if (SDL_strcasecmp(baseType, "bundle") == 0) {
base = [[bundle bundlePath] fileSystemRepresentation];
} else if (SDL_strcasecmp(baseType, "parent") == 0) {
base = [[[bundle bundlePath] stringByDeletingLastPathComponent] fileSystemRepresentation];
} else {
/* this returns the exedir for non-bundled and the resourceDir for bundled apps */
base = [[bundle resourcePath] fileSystemRepresentation];
}
if (base) {
const size_t len = SDL_strlen(base) + 2;
retval = (char *)SDL_malloc(len);
if (retval == NULL) {
SDL_OutOfMemory();
} else {
SDL_snprintf(retval, len, "%s/", base);
}
}
return retval;
}
}
char *SDL_GetPrefPath(const char *org, const char *app)
{
@autoreleasepool {
char *retval = NULL;
NSArray *array;
if (!app) {
SDL_InvalidParamError("app");
return NULL;
}
if (!org) {
org = "";
}
#if !TARGET_OS_TV
array = NSSearchPathForDirectoriesInDomains(NSApplicationSupportDirectory, NSUserDomainMask, YES);
#else
/* tvOS does not have persistent local storage!
* The only place on-device where we can store data is
* a cache directory that the OS can empty at any time.
*
* It's therefore very likely that save data will be erased
* between sessions. If you want your app's save data to
* actually stick around, you'll need to use iCloud storage.
*/
{
static SDL_bool shown = SDL_FALSE;
if (!shown) {
shown = SDL_TRUE;
SDL_LogCritical(SDL_LOG_CATEGORY_SYSTEM, "tvOS does not have persistent local storage! Use iCloud storage if you want your data to persist between sessions.\n");
}
}
array = NSSearchPathForDirectoriesInDomains(NSCachesDirectory, NSUserDomainMask, YES);
#endif /* !TARGET_OS_TV */
if ([array count] > 0) { /* we only want the first item in the list. */
NSString *str = [array objectAtIndex:0];
const char *base = [str fileSystemRepresentation];
if (base) {
const size_t len = SDL_strlen(base) + SDL_strlen(org) + SDL_strlen(app) + 4;
retval = (char *)SDL_malloc(len);
if (retval == NULL) {
SDL_OutOfMemory();
} else {
char *ptr;
if (*org) {
SDL_snprintf(retval, len, "%s/%s/%s/", base, org, app);
} else {
SDL_snprintf(retval, len, "%s/%s/", base, app);
}
for (ptr = retval + 1; *ptr; ptr++) {
if (*ptr == '/') {
*ptr = '\0';
mkdir(retval, 0700);
*ptr = '/';
}
}
mkdir(retval, 0700);
}
}
}
return retval;
}
}
char *SDL_GetPath(SDL_Folder folder)
{
@autoreleasepool {
#if TARGET_OS_TV
SDL_SetError("tvOS does not have persistent storage");
return NULL;
#else
char *retval = NULL;
const char* base;
NSArray *array;
NSSearchPathDirectory dir;
NSString *str;
char *ptr;
switch (folder) {
case SDL_FOLDER_HOME:
base = SDL_getenv("HOME");
if (!base) {
SDL_SetError("No $HOME environment variable available");
}
retval = SDL_strdup(base);
if (!retval) {
SDL_OutOfMemory();
}
return retval;
case SDL_FOLDER_DESKTOP:
dir = NSDesktopDirectory;
break;
case SDL_FOLDER_DOCUMENTS:
dir = NSDocumentDirectory;
break;
case SDL_FOLDER_DOWNLOADS:
dir = NSDownloadsDirectory;
break;
case SDL_FOLDER_MUSIC:
dir = NSMusicDirectory;
break;
case SDL_FOLDER_PICTURES:
dir = NSPicturesDirectory;
break;
case SDL_FOLDER_PUBLICSHARE:
dir = NSSharedPublicDirectory;
break;
case SDL_FOLDER_SAVEDGAMES:
SDL_SetError("Saved games folder not supported on Cocoa");
return NULL;
case SDL_FOLDER_SCREENSHOTS:
SDL_SetError("Screenshots folder not supported on Cocoa");
return NULL;
case SDL_FOLDER_TEMPLATES:
SDL_SetError("Templates folder not supported on Cocoa");
return NULL;
case SDL_FOLDER_VIDEOS:
dir = NSMoviesDirectory;
break;
default:
SDL_SetError("Invalid SDL_Folder: %d", (int) folder);
return NULL;
};
array = NSSearchPathForDirectoriesInDomains(dir, NSUserDomainMask, YES);
if ([array count] <= 0) {
SDL_SetError("Directory not found");
return NULL;
}
str = [array objectAtIndex:0];
base = [str fileSystemRepresentation];
if (!base) {
SDL_SetError("Couldn't get folder path");
return NULL;
}
retval = SDL_strdup(base);
if (retval == NULL) {
SDL_OutOfMemory();
return NULL;
}
for (ptr = retval + 1; *ptr; ptr++) {
if (*ptr == '/') {
*ptr = '\0';
mkdir(retval, 0700);
*ptr = '/';
}
}
mkdir(retval, 0700);
return retval;
#endif /* TARGET_OS_TV */
}
}
#endif /* SDL_FILESYSTEM_COCOA */

View File

@ -0,0 +1,46 @@
/*
Simple DirectMedia Layer
Copyright (C) 1997-2023 Sam Lantinga <slouken@libsdl.org>
This software is provided 'as-is', without any express or implied
warranty. In no event will the authors be held liable for any damages
arising from the use of this software.
Permission is granted to anyone to use this software for any purpose,
including commercial applications, and to alter it and redistribute it
freely, subject to the following restrictions:
1. The origin of this software must not be misrepresented; you must not
claim that you wrote the original software. If you use this software
in a product, an acknowledgment in the product documentation would be
appreciated but is not required.
2. Altered source versions must be plainly marked as such, and must not be
misrepresented as being the original software.
3. This notice may not be removed or altered from any source distribution.
*/
#include "SDL_internal.h"
#if defined(SDL_FILESYSTEM_DUMMY) || defined(SDL_FILESYSTEM_DISABLED)
/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
/* System dependent filesystem routines */
char *SDL_GetBasePath(void)
{
SDL_Unsupported();
return NULL;
}
char *SDL_GetPrefPath(const char *org, const char *app)
{
SDL_Unsupported();
return NULL;
}
char *SDL_GetPath(SDL_Folder folder)
{
SDL_Unsupported();
return NULL;
}
#endif /* SDL_FILESYSTEM_DUMMY || SDL_FILESYSTEM_DISABLED */

View File

@ -0,0 +1,111 @@
/*
Simple DirectMedia Layer
Copyright (C) 1997-2023 Sam Lantinga <slouken@libsdl.org>
This software is provided 'as-is', without any express or implied
warranty. In no event will the authors be held liable for any damages
arising from the use of this software.
Permission is granted to anyone to use this software for any purpose,
including commercial applications, and to alter it and redistribute it
freely, subject to the following restrictions:
1. The origin of this software must not be misrepresented; you must not
claim that you wrote the original software. If you use this software
in a product, an acknowledgment in the product documentation would be
appreciated but is not required.
2. Altered source versions must be plainly marked as such, and must not be
misrepresented as being the original software.
3. This notice may not be removed or altered from any source distribution.
*/
#include "SDL_internal.h"
#ifdef SDL_FILESYSTEM_EMSCRIPTEN
/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
/* System dependent filesystem routines */
#include <errno.h>
#include <sys/stat.h>
#include <emscripten/emscripten.h>
char *SDL_GetBasePath(void)
{
char *retval = "/";
return SDL_strdup(retval);
}
char *SDL_GetPrefPath(const char *org, const char *app)
{
const char *append = "/libsdl/";
char *retval;
char *ptr = NULL;
size_t len = 0;
if (app == NULL) {
SDL_InvalidParamError("app");
return NULL;
}
if (org == NULL) {
org = "";
}
len = SDL_strlen(append) + SDL_strlen(org) + SDL_strlen(app) + 3;
retval = (char *)SDL_malloc(len);
if (retval == NULL) {
SDL_OutOfMemory();
return NULL;
}
if (*org) {
SDL_snprintf(retval, len, "%s%s/%s/", append, org, app);
} else {
SDL_snprintf(retval, len, "%s%s/", append, app);
}
for (ptr = retval + 1; *ptr; ptr++) {
if (*ptr == '/') {
*ptr = '\0';
if (mkdir(retval, 0700) != 0 && errno != EEXIST) {
goto error;
}
*ptr = '/';
}
}
if (mkdir(retval, 0700) != 0 && errno != EEXIST) {
error:
SDL_SetError("Couldn't create directory '%s': '%s'", retval, strerror(errno));
SDL_free(retval);
return NULL;
}
return retval;
}
char *SDL_GetPath(SDL_Folder folder)
{
const char *home = NULL;
char *retval;
if (folder != SDL_FOLDER_HOME) {
SDL_SetError("Emscripten only supports the home folder");
return NULL;
}
home = SDL_getenv("HOME");
if (!home) {
SDL_SetError("No $HOME environment variable available");
return NULL;
}
retval = SDL_strdup(home);
if (!retval) {
SDL_OutOfMemory();
}
return retval;
}
#endif /* SDL_FILESYSTEM_EMSCRIPTEN */

View File

@ -0,0 +1,149 @@
/*
Simple DirectMedia Layer
Copyright (C) 1997-2023 Sam Lantinga <slouken@libsdl.org>
This software is provided 'as-is', without any express or implied
warranty. In no event will the authors be held liable for any damages
arising from the use of this software.
Permission is granted to anyone to use this software for any purpose,
including commercial applications, and to alter it and redistribute it
freely, subject to the following restrictions:
1. The origin of this software must not be misrepresented; you must not
claim that you wrote the original software. If you use this software
in a product, an acknowledgment in the product documentation would be
appreciated but is not required.
2. Altered source versions must be plainly marked as such, and must not be
misrepresented as being the original software.
3. This notice may not be removed or altered from any source distribution.
*/
#include "SDL_internal.h"
#ifdef SDL_FILESYSTEM_HAIKU
/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
/* System dependent filesystem routines */
#include <kernel/image.h>
#include <storage/Directory.h>
#include <storage/Entry.h>
#include <storage/FindDirectory.h>
#include <storage/Path.h>
char *SDL_GetBasePath(void)
{
char name[MAXPATHLEN];
if (find_path(B_APP_IMAGE_SYMBOL, B_FIND_PATH_IMAGE_PATH, NULL, name, sizeof(name)) != B_OK) {
return NULL;
}
BEntry entry(name, true);
BPath path;
status_t rc = entry.GetPath(&path); /* (path) now has binary's path. */
SDL_assert(rc == B_OK);
rc = path.GetParent(&path); /* chop filename, keep directory. */
SDL_assert(rc == B_OK);
const char *str = path.Path();
SDL_assert(str != NULL);
const size_t len = SDL_strlen(str);
char *retval = (char *) SDL_malloc(len + 2);
if (retval == NULL) {
SDL_OutOfMemory();
return NULL;
}
SDL_memcpy(retval, str, len);
retval[len] = '/';
retval[len+1] = '\0';
return retval;
}
char *SDL_GetPrefPath(const char *org, const char *app)
{
// !!! FIXME: is there a better way to do this?
const char *home = SDL_getenv("HOME");
const char *append = "/config/settings/";
size_t len = SDL_strlen(home);
if (app == NULL) {
SDL_InvalidParamError("app");
return NULL;
}
if (org == NULL) {
org = "";
}
if (!len || (home[len - 1] == '/')) {
++append; // home empty or ends with separator, skip the one from append
}
len += SDL_strlen(append) + SDL_strlen(org) + SDL_strlen(app) + 3;
char *retval = (char *) SDL_malloc(len);
if (retval == NULL) {
SDL_OutOfMemory();
} else {
if (*org) {
SDL_snprintf(retval, len, "%s%s%s/%s/", home, append, org, app);
} else {
SDL_snprintf(retval, len, "%s%s%s/", home, append, app);
}
create_directory(retval, 0700); // Haiku api: creates missing dirs
}
return retval;
}
char *SDL_GetPath(SDL_Folder folder)
{
const char *home = NULL;
char *retval;
home = SDL_getenv("HOME");
if (!home) {
SDL_SetError("No $HOME environment variable available");
return NULL;
}
switch (folder) {
case SDL_FOLDER_HOME:
retval = SDL_strdup(home);
if (!retval) {
SDL_OutOfMemory();
}
return retval;
/* TODO: Is Haiku's desktop folder always ~/Desktop/ ? */
case SDL_FOLDER_DESKTOP:
retval = (char *) SDL_malloc(SDL_strlen(home) + 10);
if (!retval) {
SDL_OutOfMemory();
}
SDL_strlcpy(retval, home, SDL_strlen(home) + 10);
SDL_strlcat(retval, "/Desktop/", SDL_strlen(home) + 10);
return retval;
case SDL_FOLDER_DOCUMENTS:
case SDL_FOLDER_DOWNLOADS:
case SDL_FOLDER_MUSIC:
case SDL_FOLDER_PICTURES:
case SDL_FOLDER_PUBLICSHARE:
case SDL_FOLDER_SAVEDGAMES:
case SDL_FOLDER_SCREENSHOTS:
case SDL_FOLDER_TEMPLATES:
case SDL_FOLDER_VIDEOS:
default:
SDL_SetError("Only HOME and DESKTOP available on Haiku");
return NULL;
}
}
#endif /* SDL_FILESYSTEM_HAIKU */

View File

@ -0,0 +1,89 @@
/*
Simple DirectMedia Layer
Copyright (C) 1997-2023 Sam Lantinga <slouken@libsdl.org>
This software is provided 'as-is', without any express or implied
warranty. In no event will the authors be held liable for any damages
arising from the use of this software.
Permission is granted to anyone to use this software for any purpose,
including commercial applications, and to alter it and redistribute it
freely, subject to the following restrictions:
1. The origin of this software must not be misrepresented; you must not
claim that you wrote the original software. If you use this software
in a product, an acknowledgment in the product documentation would be
appreciated but is not required.
2. Altered source versions must be plainly marked as such, and must not be
misrepresented as being the original software.
3. This notice may not be removed or altered from any source distribution.
*/
#include "SDL_internal.h"
#ifdef SDL_FILESYSTEM_N3DS
/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
/* System dependent filesystem routines */
#include <3ds.h>
#include <dirent.h>
#include <errno.h>
static char *MakePrefPath(const char *app);
static int CreatePrefPathDir(const char *pref);
char *SDL_GetBasePath(void)
{
char *base_path = SDL_strdup("romfs:/");
return base_path;
}
char *SDL_GetPrefPath(const char *org, const char *app)
{
char *pref_path = NULL;
if (app == NULL) {
SDL_InvalidParamError("app");
return NULL;
}
pref_path = MakePrefPath(app);
if (pref_path == NULL) {
return NULL;
}
if (CreatePrefPathDir(pref_path) < 0) {
SDL_free(pref_path);
return NULL;
}
return pref_path;
}
/* TODO */
char *SDL_GetPath(SDL_Folder folder)
{
SDL_Unsupported();
return NULL;
}
static char *MakePrefPath(const char *app)
{
char *pref_path;
if (SDL_asprintf(&pref_path, "sdmc:/3ds/%s/", app) < 0) {
SDL_OutOfMemory();
return NULL;
}
return pref_path;
}
static int CreatePrefPathDir(const char *pref)
{
int result = mkdir(pref, 0666);
if (result == -1 && errno != EEXIST) {
return SDL_SetError("Failed to create '%s' (%s)", pref, strerror(errno));
}
return 0;
}
#endif /* SDL_FILESYSTEM_N3DS */

View File

@ -0,0 +1,112 @@
/*
Simple DirectMedia Layer
Copyright (C) 1997-2023 Sam Lantinga <slouken@libsdl.org>
This software is provided 'as-is', without any express or implied
warranty. In no event will the authors be held liable for any damages
arising from the use of this software.
Permission is granted to anyone to use this software for any purpose,
including commercial applications, and to alter it and redistribute it
freely, subject to the following restrictions:
1. The origin of this software must not be misrepresented; you must not
claim that you wrote the original software. If you use this software
in a product, an acknowledgment in the product documentation would be
appreciated but is not required.
2. Altered source versions must be plainly marked as such, and must not be
misrepresented as being the original software.
3. This notice may not be removed or altered from any source distribution.
*/
#include "SDL_internal.h"
#include <sys/stat.h>
#include <unistd.h>
#ifdef SDL_FILESYSTEM_PS2
/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
/* System dependent filesystem routines */
char *SDL_GetBasePath(void)
{
char *retval;
size_t len;
char cwd[FILENAME_MAX];
getcwd(cwd, sizeof(cwd));
len = SDL_strlen(cwd) + 1;
retval = (char *)SDL_malloc(len);
if (retval) {
SDL_memcpy(retval, cwd, len);
}
return retval;
}
/* Do a recursive mkdir of parents folders */
static void recursive_mkdir(const char *dir)
{
char tmp[FILENAME_MAX];
char *base = SDL_GetBasePath();
char *p = NULL;
size_t len;
SDL_snprintf(tmp, sizeof(tmp), "%s", dir);
len = SDL_strlen(tmp);
if (tmp[len - 1] == '/') {
tmp[len - 1] = 0;
}
for (p = tmp + 1; *p; p++) {
if (*p == '/') {
*p = 0;
// Just creating subfolders from current path
if (SDL_strstr(tmp, base) != NULL) {
mkdir(tmp, S_IRWXU);
}
*p = '/';
}
}
SDL_free(base);
mkdir(tmp, S_IRWXU);
}
char *SDL_GetPrefPath(const char *org, const char *app)
{
char *retval = NULL;
size_t len;
char *base = SDL_GetBasePath();
if (app == NULL) {
SDL_InvalidParamError("app");
return NULL;
}
if (org == NULL) {
org = "";
}
len = SDL_strlen(base) + SDL_strlen(org) + SDL_strlen(app) + 4;
retval = (char *)SDL_malloc(len);
if (*org) {
SDL_snprintf(retval, len, "%s%s/%s/", base, org, app);
} else {
SDL_snprintf(retval, len, "%s%s/", base, app);
}
SDL_free(base);
recursive_mkdir(retval);
return retval;
}
/* TODO */
char *SDL_GetPath(SDL_Folder folder)
{
SDL_Unsupported();
return NULL;
}
#endif /* SDL_FILESYSTEM_PS2 */

View File

@ -0,0 +1,79 @@
/*
Simple DirectMedia Layer
Copyright (C) 1997-2023 Sam Lantinga <slouken@libsdl.org>
This software is provided 'as-is', without any express or implied
warranty. In no event will the authors be held liable for any damages
arising from the use of this software.
Permission is granted to anyone to use this software for any purpose,
including commercial applications, and to alter it and redistribute it
freely, subject to the following restrictions:
1. The origin of this software must not be misrepresented; you must not
claim that you wrote the original software. If you use this software
in a product, an acknowledgment in the product documentation would be
appreciated but is not required.
2. Altered source versions must be plainly marked as such, and must not be
misrepresented as being the original software.
3. This notice may not be removed or altered from any source distribution.
*/
#include "SDL_internal.h"
#include <sys/stat.h>
#include <unistd.h>
#ifdef SDL_FILESYSTEM_PSP
/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
/* System dependent filesystem routines */
char *SDL_GetBasePath(void)
{
char *retval = NULL;
size_t len;
char cwd[FILENAME_MAX];
getcwd(cwd, sizeof(cwd));
len = SDL_strlen(cwd) + 2;
retval = (char *)SDL_malloc(len);
SDL_snprintf(retval, len, "%s/", cwd);
return retval;
}
char *SDL_GetPrefPath(const char *org, const char *app)
{
char *retval = NULL;
size_t len;
char *base = SDL_GetBasePath();
if (app == NULL) {
SDL_InvalidParamError("app");
return NULL;
}
if (org == NULL) {
org = "";
}
len = SDL_strlen(base) + SDL_strlen(org) + SDL_strlen(app) + 4;
retval = (char *)SDL_malloc(len);
if (*org) {
SDL_snprintf(retval, len, "%s%s/%s/", base, org, app);
} else {
SDL_snprintf(retval, len, "%s%s/", base, app);
}
SDL_free(base);
mkdir(retval, 0755);
return retval;
}
/* TODO */
char *SDL_GetPath(SDL_Folder folder)
{
SDL_Unsupported();
return NULL;
}
#endif /* SDL_FILESYSTEM_PSP */

View File

@ -0,0 +1,209 @@
/*
Simple DirectMedia Layer
Copyright (C) 1997-2023 Sam Lantinga <slouken@libsdl.org>
This software is provided 'as-is', without any express or implied
warranty. In no event will the authors be held liable for any damages
arising from the use of this software.
Permission is granted to anyone to use this software for any purpose,
including commercial applications, and to alter it and redistribute it
freely, subject to the following restrictions:
1. The origin of this software must not be misrepresented; you must not
claim that you wrote the original software. If you use this software
in a product, an acknowledgment in the product documentation would be
appreciated but is not required.
2. Altered source versions must be plainly marked as such, and must not be
misrepresented as being the original software.
3. This notice may not be removed or altered from any source distribution.
*/
#include "SDL_internal.h"
#ifdef SDL_FILESYSTEM_RISCOS
/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
/* System dependent filesystem routines */
#include <kernel.h>
#include <swis.h>
#include <unixlib/local.h>
/* Wrapper around __unixify_std that uses SDL's memory allocators */
static char *SDL_unixify_std(const char *ro_path, char *buffer, size_t buf_len, int filetype)
{
const char *const in_buf = buffer; /* = NULL if we allocate the buffer. */
if (buffer == NULL) {
/* This matches the logic in __unixify, with an additional byte for the
* extra path separator.
*/
buf_len = SDL_strlen(ro_path) + 14 + 1;
buffer = SDL_malloc(buf_len);
if (buffer == NULL) {
SDL_OutOfMemory();
return NULL;
}
}
if (!__unixify_std(ro_path, buffer, buf_len, filetype)) {
if (in_buf == NULL) {
SDL_free(buffer);
}
SDL_SetError("Could not convert '%s' to a Unix-style path", ro_path);
return NULL;
}
/* HACK: It's necessary to add an extra path separator here since SDL's API
* requires it, however paths with trailing separators aren't normally valid
* on RISC OS.
*/
if (__get_riscosify_control() & __RISCOSIFY_NO_PROCESS)
SDL_strlcat(buffer, ".", buf_len);
else
SDL_strlcat(buffer, "/", buf_len);
return buffer;
}
static char *canonicalisePath(const char *path, const char *pathVar)
{
_kernel_oserror *error;
_kernel_swi_regs regs;
char *buf;
regs.r[0] = 37;
regs.r[1] = (int)path;
regs.r[2] = 0;
regs.r[3] = (int)pathVar;
regs.r[4] = 0;
regs.r[5] = 0;
error = _kernel_swi(OS_FSControl, &regs, &regs);
if (error) {
SDL_SetError("Couldn't canonicalise path: %s", error->errmess);
return NULL;
}
regs.r[5] = 1 - regs.r[5];
buf = SDL_malloc(regs.r[5]);
if (buf == NULL) {
SDL_OutOfMemory();
return NULL;
}
regs.r[2] = (int)buf;
error = _kernel_swi(OS_FSControl, &regs, &regs);
if (error) {
SDL_SetError("Couldn't canonicalise path: %s", error->errmess);
SDL_free(buf);
return NULL;
}
return buf;
}
static _kernel_oserror *createDirectoryRecursive(char *path)
{
char *ptr = NULL;
_kernel_oserror *error;
_kernel_swi_regs regs;
regs.r[0] = 8;
regs.r[1] = (int)path;
regs.r[2] = 0;
for (ptr = path + 1; *ptr; ptr++) {
if (*ptr == '.') {
*ptr = '\0';
error = _kernel_swi(OS_File, &regs, &regs);
*ptr = '.';
if (error != NULL) {
return error;
}
}
}
return _kernel_swi(OS_File, &regs, &regs);
}
char *SDL_GetBasePath(void)
{
_kernel_swi_regs regs;
_kernel_oserror *error;
char *canon, *ptr, *retval;
error = _kernel_swi(OS_GetEnv, &regs, &regs);
if (error) {
return NULL;
}
canon = canonicalisePath((const char *)regs.r[0], "Run$Path");
if (canon == NULL) {
return NULL;
}
/* chop off filename. */
ptr = SDL_strrchr(canon, '.');
if (ptr != NULL) {
*ptr = '\0';
}
retval = SDL_unixify_std(canon, NULL, 0, __RISCOSIFY_FILETYPE_NOTSPECIFIED);
SDL_free(canon);
return retval;
}
char *SDL_GetPrefPath(const char *org, const char *app)
{
char *canon, *dir, *retval;
size_t len;
_kernel_oserror *error;
if (app == NULL) {
SDL_InvalidParamError("app");
return NULL;
}
if (org == NULL) {
org = "";
}
canon = canonicalisePath("<Choices$Write>", "Run$Path");
if (canon == NULL) {
return NULL;
}
len = SDL_strlen(canon) + SDL_strlen(org) + SDL_strlen(app) + 4;
dir = (char *)SDL_malloc(len);
if (dir == NULL) {
SDL_OutOfMemory();
SDL_free(canon);
return NULL;
}
if (*org) {
SDL_snprintf(dir, len, "%s.%s.%s", canon, org, app);
} else {
SDL_snprintf(dir, len, "%s.%s", canon, app);
}
SDL_free(canon);
error = createDirectoryRecursive(dir);
if (error != NULL) {
SDL_SetError("Couldn't create directory: %s", error->errmess);
SDL_free(dir);
return NULL;
}
retval = SDL_unixify_std(dir, NULL, 0, __RISCOSIFY_FILETYPE_NOTSPECIFIED);
SDL_free(dir);
return retval;
}
/* TODO */
char *SDL_GetPath(SDL_Folder folder)
{
SDL_Unsupported();
return NULL;
}
#endif /* SDL_FILESYSTEM_RISCOS */

View File

@ -0,0 +1,613 @@
/*
Simple DirectMedia Layer
Copyright (C) 1997-2023 Sam Lantinga <slouken@libsdl.org>
This software is provided 'as-is', without any express or implied
warranty. In no event will the authors be held liable for any damages
arising from the use of this software.
Permission is granted to anyone to use this software for any purpose,
including commercial applications, and to alter it and redistribute it
freely, subject to the following restrictions:
1. The origin of this software must not be misrepresented; you must not
claim that you wrote the original software. If you use this software
in a product, an acknowledgment in the product documentation would be
appreciated but is not required.
2. Altered source versions must be plainly marked as such, and must not be
misrepresented as being the original software.
3. This notice may not be removed or altered from any source distribution.
*/
#include "SDL_internal.h"
#ifdef SDL_FILESYSTEM_UNIX
/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
/* System dependent filesystem routines */
#include <sys/stat.h>
#include <sys/types.h>
#include <dirent.h>
#include <errno.h>
#include <fcntl.h>
#include <limits.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#if defined(__FREEBSD__) || defined(__OPENBSD__)
#include <sys/sysctl.h>
#endif
static char *readSymLink(const char *path)
{
char *retval = NULL;
ssize_t len = 64;
ssize_t rc = -1;
while (1) {
char *ptr = (char *)SDL_realloc(retval, (size_t)len);
if (ptr == NULL) {
SDL_OutOfMemory();
break;
}
retval = ptr;
rc = readlink(path, retval, len);
if (rc == -1) {
break; /* not a symlink, i/o error, etc. */
} else if (rc < len) {
retval[rc] = '\0'; /* readlink doesn't null-terminate. */
return retval; /* we're good to go. */
}
len *= 2; /* grow buffer, try again. */
}
SDL_free(retval);
return NULL;
}
#ifdef __OPENBSD__
static char *search_path_for_binary(const char *bin)
{
char *envr = SDL_getenv("PATH");
size_t alloc_size;
char *exe = NULL;
char *start = envr;
char *ptr;
if (envr == NULL) {
SDL_SetError("No $PATH set");
return NULL;
}
envr = SDL_strdup(envr);
if (envr == NULL) {
SDL_OutOfMemory();
return NULL;
}
SDL_assert(bin != NULL);
alloc_size = SDL_strlen(bin) + SDL_strlen(envr) + 2;
exe = (char *)SDL_malloc(alloc_size);
do {
ptr = SDL_strchr(start, ':'); /* find next $PATH separator. */
if (ptr != start) {
if (ptr) {
*ptr = '\0';
}
/* build full binary path... */
SDL_snprintf(exe, alloc_size, "%s%s%s", start, (ptr && (ptr[-1] == '/')) ? "" : "/", bin);
if (access(exe, X_OK) == 0) { /* Exists as executable? We're done. */
SDL_free(envr);
return exe;
}
}
start = ptr + 1; /* start points to beginning of next element. */
} while (ptr != NULL);
SDL_free(envr);
SDL_free(exe);
SDL_SetError("Process not found in $PATH");
return NULL; /* doesn't exist in path. */
}
#endif
char *SDL_GetBasePath(void)
{
char *retval = NULL;
#ifdef __FREEBSD__
char fullpath[PATH_MAX];
size_t buflen = sizeof(fullpath);
const int mib[] = { CTL_KERN, KERN_PROC, KERN_PROC_PATHNAME, -1 };
if (sysctl(mib, SDL_arraysize(mib), fullpath, &buflen, NULL, 0) != -1) {
retval = SDL_strdup(fullpath);
if (retval == NULL) {
SDL_OutOfMemory();
return NULL;
}
}
#endif
#ifdef __OPENBSD__
/* Please note that this will fail if the process was launched with a relative path and $PWD + the cwd have changed, or argv is altered. So don't do that. Or add a new sysctl to OpenBSD. */
char **cmdline;
size_t len;
const int mib[] = { CTL_KERN, KERN_PROC_ARGS, getpid(), KERN_PROC_ARGV };
if (sysctl(mib, 4, NULL, &len, NULL, 0) != -1) {
char *exe, *pwddst;
char *realpathbuf = (char *)SDL_malloc(PATH_MAX + 1);
if (realpathbuf == NULL) {
SDL_OutOfMemory();
return NULL;
}
cmdline = SDL_malloc(len);
if (cmdline == NULL) {
SDL_free(realpathbuf);
SDL_OutOfMemory();
return NULL;
}
sysctl(mib, 4, cmdline, &len, NULL, 0);
exe = cmdline[0];
pwddst = NULL;
if (SDL_strchr(exe, '/') == NULL) { /* not a relative or absolute path, check $PATH for it */
exe = search_path_for_binary(cmdline[0]);
} else {
if (exe && *exe == '.') {
const char *pwd = SDL_getenv("PWD");
if (pwd && *pwd) {
SDL_asprintf(&pwddst, "%s/%s", pwd, exe);
}
}
}
if (exe) {
if (pwddst == NULL) {
if (realpath(exe, realpathbuf) != NULL) {
retval = realpathbuf;
}
} else {
if (realpath(pwddst, realpathbuf) != NULL) {
retval = realpathbuf;
}
SDL_free(pwddst);
}
if (exe != cmdline[0]) {
SDL_free(exe);
}
}
if (retval == NULL) {
SDL_free(realpathbuf);
}
SDL_free(cmdline);
}
#endif
/* is a Linux-style /proc filesystem available? */
if (retval == NULL && (access("/proc", F_OK) == 0)) {
/* !!! FIXME: after 2.0.6 ships, let's delete this code and just
use the /proc/%llu version. There's no reason to have
two copies of this plus all the #ifdefs. --ryan. */
#ifdef __FREEBSD__
retval = readSymLink("/proc/curproc/file");
#elif defined(__NETBSD__)
retval = readSymLink("/proc/curproc/exe");
#elif defined(__SOLARIS__)
retval = readSymLink("/proc/self/path/a.out");
#else
retval = readSymLink("/proc/self/exe"); /* linux. */
if (retval == NULL) {
/* older kernels don't have /proc/self ... try PID version... */
char path[64];
const int rc = SDL_snprintf(path, sizeof(path),
"/proc/%llu/exe",
(unsigned long long)getpid());
if ((rc > 0) && (rc < sizeof(path))) {
retval = readSymLink(path);
}
}
#endif
}
#ifdef __SOLARIS__ /* try this as a fallback if /proc didn't pan out */
if (!retval) {
const char *path = getexecname();
if ((path != NULL) && (path[0] == '/')) { /* must be absolute path... */
retval = SDL_strdup(path);
if (retval == NULL) {
SDL_OutOfMemory();
return NULL;
}
}
}
#endif
/* If we had access to argv[0] here, we could check it for a path,
or troll through $PATH looking for it, too. */
if (retval != NULL) { /* chop off filename. */
char *ptr = SDL_strrchr(retval, '/');
if (ptr != NULL) {
*(ptr + 1) = '\0';
} else { /* shouldn't happen, but just in case... */
SDL_free(retval);
retval = NULL;
}
}
if (retval != NULL) {
/* try to shrink buffer... */
char *ptr = (char *)SDL_realloc(retval, SDL_strlen(retval) + 1);
if (ptr != NULL) {
retval = ptr; /* oh well if it failed. */
}
}
return retval;
}
char *SDL_GetPrefPath(const char *org, const char *app)
{
/*
* We use XDG's base directory spec, even if you're not on Linux.
* This isn't strictly correct, but the results are relatively sane
* in any case.
*
* http://standards.freedesktop.org/basedir-spec/basedir-spec-latest.html
*/
const char *envr = SDL_getenv("XDG_DATA_HOME");
const char *append;
char *retval = NULL;
char *ptr = NULL;
size_t len = 0;
if (app == NULL) {
SDL_InvalidParamError("app");
return NULL;
}
if (org == NULL) {
org = "";
}
if (envr == NULL) {
/* You end up with "$HOME/.local/share/Game Name 2" */
envr = SDL_getenv("HOME");
if (envr == NULL) {
/* we could take heroic measures with /etc/passwd, but oh well. */
SDL_SetError("neither XDG_DATA_HOME nor HOME environment is set");
return NULL;
}
append = "/.local/share/";
} else {
append = "/";
}
len = SDL_strlen(envr);
if (envr[len - 1] == '/') {
append += 1;
}
len += SDL_strlen(append) + SDL_strlen(org) + SDL_strlen(app) + 3;
retval = (char *)SDL_malloc(len);
if (retval == NULL) {
SDL_OutOfMemory();
return NULL;
}
if (*org) {
(void)SDL_snprintf(retval, len, "%s%s%s/%s/", envr, append, org, app);
} else {
(void)SDL_snprintf(retval, len, "%s%s%s/", envr, append, app);
}
for (ptr = retval + 1; *ptr; ptr++) {
if (*ptr == '/') {
*ptr = '\0';
if (mkdir(retval, 0700) != 0 && errno != EEXIST) {
goto error;
}
*ptr = '/';
}
}
if (mkdir(retval, 0700) != 0 && errno != EEXIST) {
error:
SDL_SetError("Couldn't create directory '%s': '%s'", retval, strerror(errno));
SDL_free(retval);
return NULL;
}
return retval;
}
/*
The two functions below (prefixed with `xdg_`) have been copied from:
https://gitlab.freedesktop.org/xdg/xdg-user-dirs/-/blob/master/xdg-user-dir-lookup.c
and have been adapted to work with SDL. They are licensed under the following
terms:
Copyright (c) 2007 Red Hat, Inc.
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.
*/
static char *xdg_user_dir_lookup_with_fallback (const char *type, const char *fallback)
{
FILE *file;
char *home_dir, *config_home, *config_file;
char buffer[512];
char *user_dir;
char *p, *d;
int len;
int relative;
size_t l;
home_dir = SDL_getenv ("HOME");
if (home_dir == NULL)
goto error;
config_home = SDL_getenv ("XDG_CONFIG_HOME");
if (config_home == NULL || config_home[0] == 0)
{
l = SDL_strlen (home_dir) + SDL_strlen ("/.config/user-dirs.dirs") + 1;
config_file = (char*) SDL_malloc (l);
if (config_file == NULL)
goto error;
SDL_strlcpy (config_file, home_dir, l);
SDL_strlcat (config_file, "/.config/user-dirs.dirs", l);
}
else
{
l = SDL_strlen (config_home) + SDL_strlen ("/user-dirs.dirs") + 1;
config_file = (char*) SDL_malloc (l);
if (config_file == NULL)
goto error;
SDL_strlcpy (config_file, config_home, l);
SDL_strlcat (config_file, "/user-dirs.dirs", l);
}
file = fopen (config_file, "r");
SDL_free (config_file);
if (file == NULL)
goto error;
user_dir = NULL;
while (fgets (buffer, sizeof (buffer), file))
{
/* Remove newline at end */
len = SDL_strlen (buffer);
if (len > 0 && buffer[len-1] == '\n')
buffer[len-1] = 0;
p = buffer;
while (*p == ' ' || *p == '\t')
p++;
if (SDL_strncmp (p, "XDG_", 4) != 0)
continue;
p += 4;
if (SDL_strncmp (p, type, SDL_strlen (type)) != 0)
continue;
p += SDL_strlen (type);
if (SDL_strncmp (p, "_DIR", 4) != 0)
continue;
p += 4;
while (*p == ' ' || *p == '\t')
p++;
if (*p != '=')
continue;
p++;
while (*p == ' ' || *p == '\t')
p++;
if (*p != '"')
continue;
p++;
relative = 0;
if (SDL_strncmp (p, "$HOME/", 6) == 0)
{
p += 6;
relative = 1;
}
else if (*p != '/')
continue;
SDL_free (user_dir);
if (relative)
{
l = SDL_strlen (home_dir) + 1 + SDL_strlen (p) + 1;
user_dir = (char*) SDL_malloc (l);
if (user_dir == NULL)
goto error2;
SDL_strlcpy (user_dir, home_dir, l);
SDL_strlcat (user_dir, "/", l);
}
else
{
user_dir = (char*) SDL_malloc (SDL_strlen (p) + 1);
if (user_dir == NULL)
goto error2;
*user_dir = 0;
}
d = user_dir + SDL_strlen (user_dir);
while (*p && *p != '"')
{
if ((*p == '\\') && (*(p+1) != 0))
p++;
*d++ = *p++;
}
*d = 0;
}
error2:
fclose (file);
if (user_dir)
return user_dir;
error:
if (fallback)
return SDL_strdup (fallback);
return NULL;
}
static char *xdg_user_dir_lookup (const char *type)
{
char *dir, *home_dir, *user_dir;
dir = xdg_user_dir_lookup_with_fallback(type, NULL);
if (dir != NULL)
return dir;
home_dir = SDL_getenv("HOME");
if (home_dir == NULL)
return NULL;
/* Special case desktop for historical compatibility */
if (SDL_strcmp(type, "DESKTOP") == 0)
{
user_dir = (char*) SDL_malloc(SDL_strlen(home_dir) +
SDL_strlen("/Desktop") + 1);
if (user_dir == NULL)
return NULL;
strcpy(user_dir, home_dir);
strcat(user_dir, "/Desktop");
return user_dir;
}
return NULL;
}
char *SDL_GetPath(SDL_Folder folder)
{
const char *param = NULL;
char *retval;
/* According to `man xdg-user-dir`, the possible values are:
DESKTOP
DOWNLOAD
TEMPLATES
PUBLICSHARE
DOCUMENTS
MUSIC
PICTURES
VIDEOS
*/
switch(folder) {
case SDL_FOLDER_HOME:
param = SDL_getenv("HOME");
if (!param) {
SDL_SetError("No $HOME environment variable available");
return NULL;
}
retval = SDL_strdup(param);
if (!retval) {
SDL_OutOfMemory();
}
return retval;
case SDL_FOLDER_DESKTOP:
param = "DESKTOP";
break;
case SDL_FOLDER_DOCUMENTS:
param = "DOCUMENTS";
break;
case SDL_FOLDER_DOWNLOADS:
param = "DOWNLOAD";
break;
case SDL_FOLDER_MUSIC:
param = "MUSIC";
break;
case SDL_FOLDER_PICTURES:
param = "PICTURES";
break;
case SDL_FOLDER_PUBLICSHARE:
param = "PUBLICSHARE";
break;
case SDL_FOLDER_SAVEDGAMES:
SDL_SetError("Saved Games folder unavailable on XDG");
return NULL;
case SDL_FOLDER_SCREENSHOTS:
SDL_SetError("Screenshots folder unavailable on XDG");
return NULL;
case SDL_FOLDER_TEMPLATES:
param = "TEMPLATES";
break;
case SDL_FOLDER_VIDEOS:
param = "VIDEOS";
break;
default:
SDL_SetError("Invalid SDL_Folder: %d", (int) folder);
return NULL;
}
/* param *should* to be set to something at this point, but just in case */
if (!param) {
SDL_SetError("No corresponding XDG user directory");
return NULL;
}
retval = xdg_user_dir_lookup(param);
if (!retval) {
SDL_SetError("XDG directory not available");
return NULL;
}
return retval;
}
#endif /* SDL_FILESYSTEM_UNIX */

View File

@ -0,0 +1,93 @@
/*
Simple DirectMedia Layer
Copyright (C) 1997-2023 Sam Lantinga <slouken@libsdl.org>
This software is provided 'as-is', without any express or implied
warranty. In no event will the authors be held liable for any damages
arising from the use of this software.
Permission is granted to anyone to use this software for any purpose,
including commercial applications, and to alter it and redistribute it
freely, subject to the following restrictions:
1. The origin of this software must not be misrepresented; you must not
claim that you wrote the original software. If you use this software
in a product, an acknowledgment in the product documentation would be
appreciated but is not required.
2. Altered source versions must be plainly marked as such, and must not be
misrepresented as being the original software.
3. This notice may not be removed or altered from any source distribution.
*/
#include "SDL_internal.h"
#ifdef SDL_FILESYSTEM_VITA
/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
/* System dependent filesystem routines */
#include <errno.h>
#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>
#include <psp2/io/stat.h>
#include <sys/types.h>
#include <limits.h>
#include <fcntl.h>
char *SDL_GetBasePath(void)
{
const char *basepath = "app0:/";
char *retval = SDL_strdup(basepath);
return retval;
}
char *SDL_GetPrefPath(const char *org, const char *app)
{
const char *envr = "ux0:/data/";
char *retval = NULL;
char *ptr = NULL;
size_t len = 0;
if (app == NULL) {
SDL_InvalidParamError("app");
return NULL;
}
if (org == NULL) {
org = "";
}
len = SDL_strlen(envr);
len += SDL_strlen(org) + SDL_strlen(app) + 3;
retval = (char *)SDL_malloc(len);
if (retval == NULL) {
SDL_OutOfMemory();
return NULL;
}
if (*org) {
SDL_snprintf(retval, len, "%s%s/%s/", envr, org, app);
} else {
SDL_snprintf(retval, len, "%s%s/", envr, app);
}
for (ptr = retval + 1; *ptr; ptr++) {
if (*ptr == '/') {
*ptr = '\0';
sceIoMkdir(retval, 0777);
*ptr = '/';
}
}
sceIoMkdir(retval, 0777);
return retval;
}
/* TODO */
char *SDL_GetPath(SDL_Folder folder)
{
SDL_Unsupported();
return NULL;
}
#endif /* SDL_FILESYSTEM_VITA */

View File

@ -0,0 +1,354 @@
/*
Simple DirectMedia Layer
Copyright (C) 1997-2023 Sam Lantinga <slouken@libsdl.org>
This software is provided 'as-is', without any express or implied
warranty. In no event will the authors be held liable for any damages
arising from the use of this software.
Permission is granted to anyone to use this software for any purpose,
including commercial applications, and to alter it and redistribute it
freely, subject to the following restrictions:
1. The origin of this software must not be misrepresented; you must not
claim that you wrote the original software. If you use this software
in a product, an acknowledgment in the product documentation would be
appreciated but is not required.
2. Altered source versions must be plainly marked as such, and must not be
misrepresented as being the original software.
3. This notice may not be removed or altered from any source distribution.
*/
#include "SDL_internal.h"
#ifdef SDL_FILESYSTEM_WINDOWS
/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
/* System dependent filesystem routines */
#include "../../core/windows/SDL_windows.h"
#include <shlobj.h>
#include <initguid.h>
/* These aren't all defined in older SDKs, so define them here */
DEFINE_GUID(SDL_FOLDERID_Profile, 0x5E6C858F, 0x0E22, 0x4760, 0x9A, 0xFE, 0xEA, 0x33, 0x17, 0xB6, 0x71, 0x73);
DEFINE_GUID(SDL_FOLDERID_Desktop, 0xB4BFCC3A, 0xDB2C, 0x424C, 0xB0, 0x29, 0x7F, 0xE9, 0x9A, 0x87, 0xC6, 0x41);
DEFINE_GUID(SDL_FOLDERID_Documents, 0xFDD39AD0, 0x238F, 0x46AF, 0xAD, 0xB4, 0x6C, 0x85, 0x48, 0x03, 0x69, 0xC7);
DEFINE_GUID(SDL_FOLDERID_Downloads, 0x374de290, 0x123f, 0x4565, 0x91, 0x64, 0x39, 0xc4, 0x92, 0x5e, 0x46, 0x7b);
DEFINE_GUID(SDL_FOLDERID_Music, 0x4BD8D571, 0x6D19, 0x48D3, 0xBE, 0x97, 0x42, 0x22, 0x20, 0x08, 0x0E, 0x43);
DEFINE_GUID(SDL_FOLDERID_Pictures, 0x33E28130, 0x4E1E, 0x4676, 0x83, 0x5A, 0x98, 0x39, 0x5C, 0x3B, 0xC3, 0xBB);
DEFINE_GUID(SDL_FOLDERID_SavedGames, 0x4c5c32ff, 0xbb9d, 0x43b0, 0xb5, 0xb4, 0x2d, 0x72, 0xe5, 0x4e, 0xaa, 0xa4);
DEFINE_GUID(SDL_FOLDERID_Screenshots, 0xb7bede81, 0xdf94, 0x4682, 0xa7, 0xd8, 0x57, 0xa5, 0x26, 0x20, 0xb8, 0x6f);
DEFINE_GUID(SDL_FOLDERID_Templates, 0xA63293E8, 0x664E, 0x48DB, 0xA0, 0x79, 0xDF, 0x75, 0x9E, 0x05, 0x09, 0xF7);
DEFINE_GUID(SDL_FOLDERID_Videos, 0x18989B1D, 0x99B5, 0x455B, 0x84, 0x1C, 0xAB, 0x7C, 0x74, 0xE4, 0xDD, 0xFC);
char *SDL_GetBasePath(void)
{
DWORD buflen = 128;
WCHAR *path = NULL;
char *retval = NULL;
DWORD len = 0;
int i;
while (SDL_TRUE) {
void *ptr = SDL_realloc(path, buflen * sizeof(WCHAR));
if (ptr == NULL) {
SDL_free(path);
SDL_OutOfMemory();
return NULL;
}
path = (WCHAR *)ptr;
len = GetModuleFileNameW(NULL, path, buflen);
/* if it truncated, then len >= buflen - 1 */
/* if there was enough room (or failure), len < buflen - 1 */
if (len < buflen - 1) {
break;
}
/* buffer too small? Try again. */
buflen *= 2;
}
if (len == 0) {
SDL_free(path);
WIN_SetError("Couldn't locate our .exe");
return NULL;
}
for (i = len - 1; i > 0; i--) {
if (path[i] == '\\') {
break;
}
}
SDL_assert(i > 0); /* Should have been an absolute path. */
path[i + 1] = '\0'; /* chop off filename. */
retval = WIN_StringToUTF8W(path);
SDL_free(path);
return retval;
}
char *SDL_GetPrefPath(const char *org, const char *app)
{
/*
* Vista and later has a new API for this, but SHGetFolderPath works there,
* and apparently just wraps the new API. This is the new way to do it:
*
* SHGetKnownFolderPath(SDL_FOLDERID_RoamingAppData, KF_FLAG_CREATE,
* NULL, &wszPath);
*/
WCHAR path[MAX_PATH];
char *retval = NULL;
WCHAR *worg = NULL;
WCHAR *wapp = NULL;
size_t new_wpath_len = 0;
BOOL api_result = FALSE;
if (app == NULL) {
SDL_InvalidParamError("app");
return NULL;
}
if (org == NULL) {
org = "";
}
if (!SUCCEEDED(SHGetFolderPathW(NULL, CSIDL_APPDATA | CSIDL_FLAG_CREATE, NULL, 0, path))) {
WIN_SetError("Couldn't locate our prefpath");
return NULL;
}
worg = WIN_UTF8ToStringW(org);
if (worg == NULL) {
SDL_OutOfMemory();
return NULL;
}
wapp = WIN_UTF8ToStringW(app);
if (wapp == NULL) {
SDL_free(worg);
SDL_OutOfMemory();
return NULL;
}
new_wpath_len = SDL_wcslen(worg) + SDL_wcslen(wapp) + SDL_wcslen(path) + 3;
if ((new_wpath_len + 1) > MAX_PATH) {
SDL_free(worg);
SDL_free(wapp);
WIN_SetError("Path too long.");
return NULL;
}
if (*worg) {
SDL_wcslcat(path, L"\\", SDL_arraysize(path));
SDL_wcslcat(path, worg, SDL_arraysize(path));
}
SDL_free(worg);
api_result = CreateDirectoryW(path, NULL);
if (api_result == FALSE) {
if (GetLastError() != ERROR_ALREADY_EXISTS) {
SDL_free(wapp);
WIN_SetError("Couldn't create a prefpath.");
return NULL;
}
}
SDL_wcslcat(path, L"\\", SDL_arraysize(path));
SDL_wcslcat(path, wapp, SDL_arraysize(path));
SDL_free(wapp);
api_result = CreateDirectoryW(path, NULL);
if (api_result == FALSE) {
if (GetLastError() != ERROR_ALREADY_EXISTS) {
WIN_SetError("Couldn't create a prefpath.");
return NULL;
}
}
SDL_wcslcat(path, L"\\", SDL_arraysize(path));
retval = WIN_StringToUTF8W(path);
return retval;
}
char *SDL_GetPath(SDL_Folder folder)
{
typedef HRESULT (WINAPI *pfnSHGetKnownFolderPath)(REFGUID /* REFKNOWNFOLDERID */, DWORD, HANDLE, PWSTR*);
HMODULE lib = LoadLibrary(L"Shell32.dll");
pfnSHGetKnownFolderPath pSHGetKnownFolderPath = NULL;
char *retval = NULL;
if (lib) {
pSHGetKnownFolderPath = (pfnSHGetKnownFolderPath)GetProcAddress(lib, "SHGetKnownFolderPath");
}
if (pSHGetKnownFolderPath) {
GUID type; /* KNOWNFOLDERID */
HRESULT result;
wchar_t *path;
switch (folder) {
case SDL_FOLDER_HOME:
type = SDL_FOLDERID_Profile;
break;
case SDL_FOLDER_DESKTOP:
type = SDL_FOLDERID_Desktop;
break;
case SDL_FOLDER_DOCUMENTS:
type = SDL_FOLDERID_Documents;
break;
case SDL_FOLDER_DOWNLOADS:
type = SDL_FOLDERID_Downloads;
break;
case SDL_FOLDER_MUSIC:
type = SDL_FOLDERID_Music;
break;
case SDL_FOLDER_PICTURES:
type = SDL_FOLDERID_Pictures;
break;
case SDL_FOLDER_PUBLICSHARE:
SDL_SetError("Public share unavailable on Windows");
goto done;
case SDL_FOLDER_SAVEDGAMES:
type = SDL_FOLDERID_SavedGames;
break;
case SDL_FOLDER_SCREENSHOTS:
type = SDL_FOLDERID_Screenshots;
break;
case SDL_FOLDER_TEMPLATES:
type = SDL_FOLDERID_Templates;
break;
case SDL_FOLDER_VIDEOS:
type = SDL_FOLDERID_Videos;
break;
default:
SDL_SetError("Invalid SDL_Folder: %d", (int)folder);
goto done;
};
result = pSHGetKnownFolderPath(&type, 0x00008000 /* KF_FLAG_CREATE */, NULL, &path);
if (SUCCEEDED(result)) {
retval = WIN_StringToUTF8W(path);
} else {
WIN_SetErrorFromHRESULT("Couldn't get folder", result);
}
} else {
int type;
HRESULT result;
wchar_t path[MAX_PATH];
switch (folder) {
case SDL_FOLDER_HOME:
type = CSIDL_PROFILE;
break;
case SDL_FOLDER_DESKTOP:
type = CSIDL_DESKTOP;
break;
case SDL_FOLDER_DOCUMENTS:
type = CSIDL_MYDOCUMENTS;
break;
case SDL_FOLDER_DOWNLOADS:
SDL_SetError("Downloads folder unavailable before Vista");
goto done;
case SDL_FOLDER_MUSIC:
type = CSIDL_MYMUSIC;
break;
case SDL_FOLDER_PICTURES:
type = CSIDL_MYPICTURES;
break;
case SDL_FOLDER_PUBLICSHARE:
SDL_SetError("Public share unavailable on Windows");
goto done;
case SDL_FOLDER_SAVEDGAMES:
SDL_SetError("Saved games unavailable before Vista");
goto done;
case SDL_FOLDER_SCREENSHOTS:
SDL_SetError("Screenshots folder unavailable before Vista");
goto done;
case SDL_FOLDER_TEMPLATES:
type = CSIDL_TEMPLATES;
break;
case SDL_FOLDER_VIDEOS:
type = CSIDL_MYVIDEO;
break;
default:
SDL_SetError("Unsupported SDL_Folder on Windows before Vista: %d", (int)folder);
goto done;
};
/* Create the OS-specific folder if it doesn't already exist */
type |= CSIDL_FLAG_CREATE;
#if 0
/* Apparently the oldest, but not supported in modern Windows */
HRESULT result = SHGetSpecialFolderPath(NULL, path, type, TRUE);
#endif
/* Windows 2000/XP and later, deprecated as of Windows 10 (still
available), available in Wine (tested 6.0.3) */
result = SHGetFolderPathW(NULL, type, NULL, SHGFP_TYPE_CURRENT, path);
/* use `== TRUE` for SHGetSpecialFolderPath */
if (SUCCEEDED(result)) {
retval = WIN_StringToUTF8W(path);
} else {
WIN_SetErrorFromHRESULT("Couldn't get folder", result);
}
}
done:
if (lib) {
FreeLibrary(lib);
}
return retval;
}
#endif /* SDL_FILESYSTEM_WINDOWS */
#ifdef SDL_FILESYSTEM_XBOX
char *SDL_GetBasePath(void)
{
SDL_Unsupported();
return NULL;
}
char *SDL_GetPrefPath(const char *org, const char *app)
{
SDL_Unsupported();
return NULL;
}
char *SDL_GetPath(SDL_Folder folder)
{
SDL_Unsupported();
return NULL;
}
#endif /* SDL_FILESYSTEM_XBOX */

View File

@ -0,0 +1,242 @@
/*
Simple DirectMedia Layer
Copyright (C) 1997-2023 Sam Lantinga <slouken@libsdl.org>
This software is provided 'as-is', without any express or implied
warranty. In no event will the authors be held liable for any damages
arising from the use of this software.
Permission is granted to anyone to use this software for any purpose,
including commercial applications, and to alter it and redistribute it
freely, subject to the following restrictions:
1. The origin of this software must not be misrepresented; you must not
claim that you wrote the original software. If you use this software
in a product, an acknowledgment in the product documentation would be
appreciated but is not required.
2. Altered source versions must be plainly marked as such, and must not be
misrepresented as being the original software.
3. This notice may not be removed or altered from any source distribution.
*/
#include "SDL_internal.h"
/* TODO, WinRT: remove the need to compile this with C++/CX (/ZW) extensions, and if possible, without C++ at all
*/
#ifdef __WINRT__
extern "C" {
#include "../../core/windows/SDL_windows.h"
}
#include <string>
#include <unordered_map>
using namespace std;
using namespace Windows::Storage;
extern "C" const wchar_t *
SDL_WinRTGetFSPathUNICODE(SDL_WinRT_Path pathType)
{
switch (pathType) {
case SDL_WINRT_PATH_INSTALLED_LOCATION:
{
static wstring path;
if (path.empty()) {
#if defined(NTDDI_WIN10_19H1) && (NTDDI_VERSION >= NTDDI_WIN10_19H1) && (WINAPI_FAMILY == WINAPI_FAMILY_PC_APP) /* Only PC supports mods */
/* Windows 1903 supports mods, via the EffectiveLocation API */
if (Windows::Foundation::Metadata::ApiInformation::IsApiContractPresent("Windows.Foundation.UniversalApiContract", 8, 0)) {
path = Windows::ApplicationModel::Package::Current->EffectiveLocation->Path->Data();
} else {
path = Windows::ApplicationModel::Package::Current->InstalledLocation->Path->Data();
}
#else
path = Windows::ApplicationModel::Package::Current->InstalledLocation->Path->Data();
#endif
}
return path.c_str();
}
case SDL_WINRT_PATH_LOCAL_FOLDER:
{
static wstring path;
if (path.empty()) {
path = ApplicationData::Current->LocalFolder->Path->Data();
}
return path.c_str();
}
#if !SDL_WINAPI_FAMILY_PHONE || NTDDI_VERSION > NTDDI_WIN8
case SDL_WINRT_PATH_ROAMING_FOLDER:
{
static wstring path;
if (path.empty()) {
path = ApplicationData::Current->RoamingFolder->Path->Data();
}
return path.c_str();
}
case SDL_WINRT_PATH_TEMP_FOLDER:
{
static wstring path;
if (path.empty()) {
path = ApplicationData::Current->TemporaryFolder->Path->Data();
}
return path.c_str();
}
#endif
default:
break;
}
SDL_Unsupported();
return NULL;
}
extern "C" const char *
SDL_WinRTGetFSPathUTF8(SDL_WinRT_Path pathType)
{
typedef unordered_map<SDL_WinRT_Path, string> UTF8PathMap;
static UTF8PathMap utf8Paths;
UTF8PathMap::iterator searchResult = utf8Paths.find(pathType);
if (searchResult != utf8Paths.end()) {
return searchResult->second.c_str();
}
const wchar_t *ucs2Path = SDL_WinRTGetFSPathUNICODE(pathType);
if (ucs2Path == NULL) {
return NULL;
}
char *utf8Path = WIN_StringToUTF8(ucs2Path);
utf8Paths[pathType] = utf8Path;
SDL_free(utf8Path);
return utf8Paths[pathType].c_str();
}
extern "C" char *
SDL_GetBasePath(void)
{
const char *srcPath = SDL_WinRTGetFSPathUTF8(SDL_WINRT_PATH_INSTALLED_LOCATION);
size_t destPathLen;
char *destPath = NULL;
if (srcPath == NULL) {
SDL_SetError("Couldn't locate our basepath: %s", SDL_GetError());
return NULL;
}
destPathLen = SDL_strlen(srcPath) + 2;
destPath = (char *)SDL_malloc(destPathLen);
if (destPath == NULL) {
SDL_OutOfMemory();
return NULL;
}
SDL_snprintf(destPath, destPathLen, "%s\\", srcPath);
return destPath;
}
extern "C" char *
SDL_GetPrefPath(const char *org, const char *app)
{
/* WinRT note: The 'SHGetFolderPath' API that is used in Windows 7 and
* earlier is not available on WinRT or Windows Phone. WinRT provides
* a similar API, but SHGetFolderPath can't be called, at least not
* without violating Microsoft's app-store requirements.
*/
const WCHAR *srcPath = NULL;
WCHAR path[MAX_PATH];
char *retval = NULL;
WCHAR *worg = NULL;
WCHAR *wapp = NULL;
size_t new_wpath_len = 0;
BOOL api_result = FALSE;
if (app == NULL) {
SDL_InvalidParamError("app");
return NULL;
}
if (org == NULL) {
org = "";
}
srcPath = SDL_WinRTGetFSPathUNICODE(SDL_WINRT_PATH_LOCAL_FOLDER);
if (srcPath == NULL) {
SDL_SetError("Unable to find a source path");
return NULL;
}
if (SDL_wcslen(srcPath) >= MAX_PATH) {
SDL_SetError("Path too long.");
return NULL;
}
SDL_wcslcpy(path, srcPath, SDL_arraysize(path));
worg = WIN_UTF8ToString(org);
if (worg == NULL) {
SDL_OutOfMemory();
return NULL;
}
wapp = WIN_UTF8ToString(app);
if (wapp == NULL) {
SDL_free(worg);
SDL_OutOfMemory();
return NULL;
}
new_wpath_len = SDL_wcslen(worg) + SDL_wcslen(wapp) + SDL_wcslen(path) + 3;
if ((new_wpath_len + 1) > MAX_PATH) {
SDL_free(worg);
SDL_free(wapp);
SDL_SetError("Path too long.");
return NULL;
}
if (*worg) {
SDL_wcslcat(path, L"\\", new_wpath_len + 1);
SDL_wcslcat(path, worg, new_wpath_len + 1);
SDL_free(worg);
}
api_result = CreateDirectoryW(path, NULL);
if (api_result == FALSE) {
if (GetLastError() != ERROR_ALREADY_EXISTS) {
SDL_free(wapp);
WIN_SetError("Couldn't create a prefpath.");
return NULL;
}
}
SDL_wcslcat(path, L"\\", new_wpath_len + 1);
SDL_wcslcat(path, wapp, new_wpath_len + 1);
SDL_free(wapp);
api_result = CreateDirectoryW(path, NULL);
if (api_result == FALSE) {
if (GetLastError() != ERROR_ALREADY_EXISTS) {
WIN_SetError("Couldn't create a prefpath.");
return NULL;
}
}
SDL_wcslcat(path, L"\\", new_wpath_len + 1);
retval = WIN_StringToUTF8(path);
return retval;
}
/* TODO */
char *SDL_GetPath(SDL_Folder folder)
{
SDL_Unsupported();
return NULL;
}
#endif /* __WINRT__ */