physfs
physfs copied to clipboard
Add libretro support
This introduces libretro.h virtual file system support for PhysFS, allowing to use PhysFS directly from a libretro core through RETRO_ENVIRONMENT_GET_VFS_INTERFACE.
I've put together a physfs_test_libretro core to test out the functionality. It was originally written for the chailove core.
A few considerations...
- In both Playdate, and libretro now,
PHYSFS_init()requires you to pass in some user data pertaining to the environment as anargv0argument. As you mentioned in the comments, it seems like a cheat. Would it make sense to introduce a function likePHYSFS_setPlatformData(void*)or something? - I didn't include the CMakeLists.txt update, as this does depend on some of libretro-common, and libretro-common doesn't use CMake at all. Would be nice to include CMake support, but I'm unsure how to best accomplish it. For reference, it depends on the following from libretro-common...
include/libretro.h rthreads/rthreads.c - Haven't tested this with UTF-8 paths yet
- Unsure of the pref directory strategy so far
It was originally written for the chailove core.
Before we go any further: is this code able to be contributed under a zlib license? ChaiLove uses the MIT license.
Good call. As the original author of ChaiLove, I'm okay to re-license this code to zlib. I got the :+1: from phcoder too.
In both Playdate, and libretro now
(AND android...this is a big mess, and I'll probably change this in PhysicsFS 4 to not take a const char *, but this API has been otherwise-stable for like...23 years now, so I'm hesitant to change it. :) Hack it in for now.)
May I suggest something like the following to make it buildable in C90 mode and avoid errors if ELOOP isn't available:
diff --git a/src/physfs_platform_libretro.c b/src/physfs_platform_libretro.c
index 58694ba..dcc0c87 100644
--- a/src/physfs_platform_libretro.c
+++ b/src/physfs_platform_libretro.c
@@ -306,9 +306,10 @@ void *__PHYSFS_platformOpenAppend(const char *filename)
PHYSFS_sint64 __PHYSFS_platformRead(void *opaque, void *buffer,
PHYSFS_uint64 len)
{
+ PHYSFS_sint64 retval;
BAIL_IF(physfs_platform_libretro_vfs == NULL || physfs_platform_libretro_vfs->read == NULL, PHYSFS_ERR_NOT_INITIALIZED, -1);
BAIL_IF(opaque == NULL || buffer == NULL, PHYSFS_ERR_INVALID_ARGUMENT, -1);
- PHYSFS_sint64 retval = (PHYSFS_sint64) physfs_platform_libretro_vfs->read((struct retro_vfs_file_handle *) opaque, buffer, (uint64_t) len);
+ retval = (PHYSFS_sint64) physfs_platform_libretro_vfs->read((struct retro_vfs_file_handle *) opaque, buffer, (uint64_t) len);
BAIL_IF(retval == -1, PHYSFS_ERR_IO, -1);
return retval;
} /* __PHYSFS_platformRead */
@@ -317,9 +318,10 @@ PHYSFS_sint64 __PHYSFS_platformRead(void *opaque, void *buffer,
PHYSFS_sint64 __PHYSFS_platformWrite(void *opaque, const void *buffer,
PHYSFS_uint64 len)
{
+ PHYSFS_sint64 retval;
BAIL_IF(physfs_platform_libretro_vfs == NULL || physfs_platform_libretro_vfs->write == NULL, PHYSFS_ERR_NOT_INITIALIZED, -1);
BAIL_IF(opaque == NULL || buffer == NULL, PHYSFS_ERR_INVALID_ARGUMENT, -1);
- PHYSFS_sint64 retval = (PHYSFS_sint64) physfs_platform_libretro_vfs->write((struct retro_vfs_file_handle *) opaque, buffer, (uint64_t)len);
+ retval = (PHYSFS_sint64) physfs_platform_libretro_vfs->write((struct retro_vfs_file_handle *) opaque, buffer, (uint64_t)len);
BAIL_IF(retval == -1, PHYSFS_ERR_IO, -1);
return retval;
} /* __PHYSFS_platformWrite */
@@ -386,7 +388,9 @@ static PHYSFS_ErrorCode errcodeFromErrnoError(const int err)
case WSAEDQUOT: return PHYSFS_ERR_NO_SPACE;
#endif
case EIO: return PHYSFS_ERR_IO;
+#if defined(ELOOP)
case ELOOP: return PHYSFS_ERR_SYMLINK_LOOP;
+#endif
case EMLINK: return PHYSFS_ERR_NO_SPACE;
case ENAMETOOLONG: return PHYSFS_ERR_BAD_FILENAME;
case ENOENT: return PHYSFS_ERR_NOT_FOUND;
Did another test of this with https://github.com/robloach/physfs_test_libretro ... Looking pretty good. If there's anything else you can think of adding, feel free to let me know.
YOLO
I might make changes later, but it's silly that this has been in an unmerged PR for this long.
Thanks for the merge. Been using this in a core that's built across a few different platforms. Works well. I am finding a strange bug on emscripten with the environment callback not being saved from physfsInit. I believe it's something to do with threading so trying to fix that.
Feel free to change anything in there 🙌