physfs icon indicating copy to clipboard operation
physfs copied to clipboard

Add libretro support

Open RobLoach opened this issue 1 year ago • 5 comments

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...

  1. In both Playdate, and libretro now, PHYSFS_init() requires you to pass in some user data pertaining to the environment as an argv0 argument. As you mentioned in the comments, it seems like a cheat. Would it make sense to introduce a function like PHYSFS_setPlatformData(void*) or something?
  2. 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
    
  3. Haven't tested this with UTF-8 paths yet
  4. Unsure of the pref directory strategy so far

RobLoach avatar May 17 '24 03:05 RobLoach

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.

icculus avatar May 17 '24 14:05 icculus

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.

RobLoach avatar May 17 '24 15:05 RobLoach

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.)

icculus avatar May 17 '24 22:05 icculus

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;

sezero avatar May 18 '24 18:05 sezero

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.

RobLoach avatar May 25 '24 21:05 RobLoach

YOLO

icculus avatar Feb 09 '25 03:02 icculus

I might make changes later, but it's silly that this has been in an unmerged PR for this long.

icculus avatar Feb 09 '25 03:02 icculus

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 🙌

Screenshot_20250209-085456

RobLoach avatar Feb 09 '25 13:02 RobLoach