diff --git a/CMakeLists.txt b/CMakeLists.txt index b3d5b1c..b151291 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -88,6 +88,7 @@ set(PHYSFS_SRCS src/physfs_platform_dos.c src/physfs_platform_emscripten.c src/physfs_platform_posix.c + src/physfs_platform_sdl3.c src/physfs_platform_unix.c src/physfs_platform_windows.c src/physfs_platform_ogc.c @@ -193,6 +194,11 @@ if(NOT PHYSFS_ARCHIVE_POD) add_definitions(-DPHYSFS_SUPPORTS_POD=0) endif() +option(PHYSFS_PLATFORM_SDL3 "Enable building for the SDL3 file system" FALSE) +if(PHYSFS_PLATFORM_SDL3) + add_definitions(-DPHYSFS_PLATFORM_SDL3=1) +endif() + if(EMSCRIPTEN) set(PHYSFS_EMSCRIPTEN_STORAGE_PATH "" CACHE STRING "Specify a path for prefdir on Emscripten") if(NOT PHYSFS_EMSCRIPTEN_STORAGE_PATH STREQUAL "") diff --git a/src/physfs_platform_sdl3.c b/src/physfs_platform_sdl3.c new file mode 100644 index 0000000..193c26b --- /dev/null +++ b/src/physfs_platform_sdl3.c @@ -0,0 +1,251 @@ +/* + * SDL3 support routines for PhysicsFS. + * + * Please see the file LICENSE.txt in the source's root directory. + * + * This file written by Rob Loach (@RobLoach). + */ + +#define __PHYSICSFS_INTERNAL__ +#include "physfs_internal.h" + +#ifdef PHYSFS_PLATFORM_SDL3 + +#include + +/** + * Context for enumeration. + * + * @see __PHYSFS_platformEnumerate() + */ +typedef struct platformEnumerateContext +{ + PHYSFS_EnumerateCallback callback; + const char *origdir; + void *callbackdata; + PHYSFS_EnumerateCallbackResult result; +} platformEnumerateContext; + +int __PHYSFS_platformInit(const char *argv0) +{ + (void)argv0; + return 1; /* always succeed. */ +} /* __PHYSFS_platformInit */ + +void __PHYSFS_platformDeinit(void) +{ + /* no-op */ +} /* __PHYSFS_platformDeinit */ + +void *__PHYSFS_platformGetThreadID(void) +{ + return (void *)(size_t)SDL_GetCurrentThreadID(); +} /* __PHYSFS_platformGetThreadID */ + +void *__PHYSFS_platformCreateMutex(void) +{ + return (void *)SDL_CreateMutex(); +} /* __PHYSFS_platformCreateMutex */ + +void __PHYSFS_platformDestroyMutex(void *mutex) +{ + SDL_DestroyMutex((SDL_Mutex *)mutex); +} /* __PHYSFS_platformDestroyMutex */ + +int __PHYSFS_platformGrabMutex(void *mutex) +{ + SDL_LockMutex((SDL_Mutex *)mutex); + return 1; +} /* __PHYSFS_platformGrabMutex */ + +void __PHYSFS_platformReleaseMutex(void *mutex) +{ + SDL_UnlockMutex((SDL_Mutex *)mutex); +} /* __PHYSFS_platformReleaseMutex */ + +/** + * Not supported by SDL3. + */ +void __PHYSFS_platformDetectAvailableCDs(PHYSFS_StringCallback cb, void *data) +{ + (void)cb; + (void)data; +} /* __PHYSFS_platformDetectAvailableCDs */ + +char *__PHYSFS_platformCalcBaseDir(const char *argv0) +{ + const char *base = SDL_GetBasePath(); + (void)argv0; + BAIL_IF(base == NULL, PHYSFS_ERR_OS_ERROR, NULL); + return __PHYSFS_strdup(base); +} /* __PHYSFS_platformCalcBaseDir */ + +char *__PHYSFS_platformCalcUserDir(void) +{ + const char *home = SDL_GetUserFolder(SDL_FOLDER_HOME); + BAIL_IF(home == NULL, PHYSFS_ERR_OS_ERROR, NULL); + return __PHYSFS_strdup(home); +} /* __PHYSFS_platformCalcUserDir */ + +char *__PHYSFS_platformCalcPrefDir(const char *org, const char *app) +{ + char *out = SDL_GetPrefPath(org, app); + BAIL_IF(out == NULL, PHYSFS_ERR_OS_ERROR, NULL); + /* Unlike SDL_GetBasePath() or SDL_GetUserFolder(), SDL_GetPrefPath() allocates the string for us. */ + return out; +} /* __PHYSFS_platformCalcPrefDir */ + +static SDL_EnumerationResult SDLCALL platformEnumerateCallback(void *userdata, + const char *dirname, + const char *fname) +{ + platformEnumerateContext *ctx = (platformEnumerateContext *)userdata; + (void)dirname; + + ctx->result = ctx->callback(ctx->callbackdata, ctx->origdir, fname); + + switch (ctx->result) { + case PHYSFS_ENUM_OK: return SDL_ENUM_CONTINUE; + case PHYSFS_ENUM_STOP: return SDL_ENUM_SUCCESS; + case PHYSFS_ENUM_ERROR: return SDL_ENUM_FAILURE; + } + return SDL_ENUM_FAILURE; +} /* platformEnumerateCallback */ + +PHYSFS_EnumerateCallbackResult __PHYSFS_platformEnumerate(const char *dirname, + PHYSFS_EnumerateCallback callback, + const char *origdir, + void *callbackdata) +{ + platformEnumerateContext ctx; + ctx.callback = callback; + ctx.origdir = origdir; + ctx.callbackdata = callbackdata; + ctx.result = PHYSFS_ENUM_OK; + + BAIL_IF(!SDL_EnumerateDirectory(dirname, platformEnumerateCallback, &ctx), + /* Determine the correct PhysFS error to report. */ + ctx.result == PHYSFS_ENUM_ERROR ? PHYSFS_ERR_APP_CALLBACK : PHYSFS_ERR_OS_ERROR, + PHYSFS_ENUM_ERROR); + + return ctx.result; +} /* __PHYSFS_platformEnumerate */ + +int __PHYSFS_platformMkDir(const char *path) +{ + BAIL_IF(!SDL_CreateDirectory(path), PHYSFS_ERR_OS_ERROR, 0); + return 1; +} /* __PHYSFS_platformMkDir */ + +int __PHYSFS_platformDelete(const char *path) +{ + BAIL_IF(!SDL_RemovePath(path), PHYSFS_ERR_OS_ERROR, 0); + return 1; +} /* __PHYSFS_platformDelete */ + +int __PHYSFS_platformStat(const char *fn, PHYSFS_Stat *stat, const int follow) +{ + SDL_PathInfo info; + (void)follow; + + BAIL_IF(!SDL_GetPathInfo(fn, &info), PHYSFS_ERR_NOT_FOUND, 0); + + switch (info.type) { + case SDL_PATHTYPE_FILE: + stat->filetype = PHYSFS_FILETYPE_REGULAR; + stat->filesize = (PHYSFS_sint64)info.size; + break; + case SDL_PATHTYPE_DIRECTORY: + stat->filetype = PHYSFS_FILETYPE_DIRECTORY; + stat->filesize = 0; + break; + case SDL_PATHTYPE_OTHER: + stat->filetype = PHYSFS_FILETYPE_OTHER; + stat->filesize = -1; + break; + case SDL_PATHTYPE_NONE: + default: + BAIL(PHYSFS_ERR_NOT_FOUND, 0); + } + + stat->accesstime = (PHYSFS_sint64)(info.access_time / SDL_NS_PER_SECOND); + stat->createtime = (PHYSFS_sint64)(info.create_time / SDL_NS_PER_SECOND); + stat->modtime = (PHYSFS_sint64)(info.modify_time / SDL_NS_PER_SECOND); + stat->readonly = 0; + return 1; +} /* __PHYSFS_platformStat */ + +static void *doOpen(const char *filename, const char* mode) +{ + SDL_IOStream *io = SDL_IOFromFile(filename, mode); + BAIL_IF(io == NULL, PHYSFS_ERR_OS_ERROR, NULL); + return io; +} /* doOpen */ + +void *__PHYSFS_platformOpenRead(const char *filename) +{ + return doOpen(filename, "rb"); +} /* __PHYSFS_platformOpenRead */ + +void *__PHYSFS_platformOpenWrite(const char *filename) +{ + return doOpen(filename, "wb"); +} /* __PHYSFS_platformOpenWrite */ + +void *__PHYSFS_platformOpenAppend(const char *filename) +{ + return doOpen(filename, "ab"); +} /* __PHYSFS_platformOpenAppend */ + +PHYSFS_sint64 __PHYSFS_platformRead(void *opaque, void *buf, PHYSFS_uint64 len) +{ + SDL_IOStream *io = (SDL_IOStream *)opaque; + size_t size = (size_t)len; + size_t rc = SDL_ReadIO(io, buf, size); + BAIL_IF(rc < size && SDL_GetIOStatus(io) == SDL_IO_STATUS_ERROR, PHYSFS_ERR_IO, -1); + return (PHYSFS_sint64)rc; +} /* __PHYSFS_platformRead */ + +PHYSFS_sint64 __PHYSFS_platformWrite(void *opaque, const void *buf, PHYSFS_uint64 len) +{ + SDL_IOStream *io = (SDL_IOStream *)opaque; + size_t size = (size_t)len; + size_t rc = SDL_WriteIO(io, buf, size); + BAIL_IF(rc < size && SDL_GetIOStatus(io) == SDL_IO_STATUS_ERROR, PHYSFS_ERR_IO, -1); + return (PHYSFS_sint64)rc; +} /* __PHYSFS_platformWrite */ + +int __PHYSFS_platformSeek(void *opaque, PHYSFS_uint64 pos) +{ + BAIL_IF(SDL_SeekIO((SDL_IOStream *)opaque, (Sint64)pos, SDL_IO_SEEK_SET) < 0, PHYSFS_ERR_IO, 0); + return 1; +} /* __PHYSFS_platformSeek */ + +PHYSFS_sint64 __PHYSFS_platformTell(void *opaque) +{ + Sint64 pos = SDL_TellIO((SDL_IOStream *)opaque); + BAIL_IF(pos < 0, PHYSFS_ERR_IO, -1); + return (PHYSFS_sint64)pos; +} /* __PHYSFS_platformTell */ + +PHYSFS_sint64 __PHYSFS_platformFileLength(void *opaque) +{ + Sint64 size = SDL_GetIOSize((SDL_IOStream *)opaque); + BAIL_IF(size < 0, PHYSFS_ERR_IO, -1); + return (PHYSFS_sint64)size; +} /* __PHYSFS_platformFileLength */ + +int __PHYSFS_platformFlush(void *opaque) +{ + BAIL_IF(!SDL_FlushIO((SDL_IOStream *)opaque), PHYSFS_ERR_IO, 0); + return 1; +} /* __PHYSFS_platformFlush */ + +void __PHYSFS_platformClose(void *opaque) +{ + if (!SDL_CloseIO((SDL_IOStream *)opaque)) { + SDL_ClearError(); + } +} /* __PHYSFS_platformClose */ + +#endif diff --git a/src/physfs_platforms.h b/src/physfs_platforms.h index bd9efb2..ea0cfea 100644 --- a/src/physfs_platforms.h +++ b/src/physfs_platforms.h @@ -12,7 +12,9 @@ * PHYSFS_PLATFORM_UNIX on that system. */ -#if defined(TARGET_EXTENSION) && (defined(TARGET_PLAYDATE) || defined(TARGET_SIMULATOR)) +#if defined(PHYSFS_PLATFORM_SDL3) +#define PHYSFS_NO_CDROM_SUPPORT 1 +#elif defined(TARGET_EXTENSION) && (defined(TARGET_PLAYDATE) || defined(TARGET_SIMULATOR)) # define PHYSFS_PLATFORM_PLAYDATE 1 # define PHYSFS_NO_CRUNTIME_MALLOC 1 #elif (defined __EMSCRIPTEN__)