Просмотр исходного кода

extras: added physfssdl3.

This is like physfsrwops, but for SDL3's SDL_IOStream and SDL_Storage.

Fixes #77.

(cherry picked from commit f4dfeb9b0abf53b23527ab63524f3695a3ff2716)
Ryan C. Gordon 1 год назад
Родитель
Сommit
b577af883d
4 измененных файлов с 408 добавлено и 0 удалено
  1. 2 0
      extras/physfsrwops.c
  2. 2 0
      extras/physfsrwops.h
  3. 298 0
      extras/physfssdl3.c
  4. 106 0
      extras/physfssdl3.h

+ 2 - 0
extras/physfsrwops.c

@@ -21,6 +21,8 @@
  *  This file was written by Ryan C. Gordon. (icculus@icculus.org).
  *  This file was written by Ryan C. Gordon. (icculus@icculus.org).
  */
  */
 
 
+/* This works with SDL1 and SDL2. For SDL3, use physfssdl3.c */
+
 #include <stdio.h>  /* used for SEEK_SET, SEEK_CUR, SEEK_END ... */
 #include <stdio.h>  /* used for SEEK_SET, SEEK_CUR, SEEK_END ... */
 #include "physfsrwops.h"
 #include "physfsrwops.h"
 
 

+ 2 - 0
extras/physfsrwops.h

@@ -21,6 +21,8 @@
  *  This file was written by Ryan C. Gordon. (icculus@icculus.org).
  *  This file was written by Ryan C. Gordon. (icculus@icculus.org).
  */
  */
 
 
+/* This works with SDL1 and SDL2. For SDL3, use physfssdl3.h */
+
 #ifndef _INCLUDE_PHYSFSRWOPS_H_
 #ifndef _INCLUDE_PHYSFSRWOPS_H_
 #define _INCLUDE_PHYSFSRWOPS_H_
 #define _INCLUDE_PHYSFSRWOPS_H_
 
 

+ 298 - 0
extras/physfssdl3.c

@@ -0,0 +1,298 @@
+/*
+ * This code provides a glue layer between PhysicsFS and Simple Directmedia
+ *  Layer 3's (SDL3) SDL_IOStream and SDL_Storage i/o abstractions.
+ *
+ * License: this code is public domain. I make no warranty that it is useful,
+ *  correct, harmless, or environmentally safe.
+ *
+ * This particular file may be used however you like, including copying it
+ *  verbatim into a closed-source project, exploiting it commercially, and
+ *  removing any trace of my name from the source (although I hope you won't
+ *  do that). I welcome enhancements and corrections to this file, but I do
+ *  not require you to send me patches if you make changes. This code has
+ *  NO WARRANTY.
+ *
+ * Unless otherwise stated, the rest of PhysicsFS falls under the zlib license.
+ *  Please see LICENSE.txt in the root of the source tree.
+ *
+ * SDL3 is zlib-licensed, like PhysicsFS. You can get SDL at
+ *  https://www.libsdl.org/
+ *
+ *  This file was written by Ryan C. Gordon. (icculus@icculus.org).
+ */
+
+/* This works with SDL3. For SDL1 and SDL2, use physfsrwops.h */
+
+#include "physfssdl3.h"
+
+/* SDL_IOStream -> PhysicsFS bridge ... */
+
+static Sint64 SDLCALL physfsiostream_size(void *userdata)
+{
+    return (Sint64) PHYSFS_fileLength((PHYSFS_File *) userdata);
+}
+
+static Sint64 SDLCALL physfsiostream_seek(void *userdata, Sint64 offset, int whence)
+{
+    PHYSFS_File *handle = (PHYSFS_File *) userdata;
+    PHYSFS_sint64 pos = 0;
+
+    if (whence == SDL_IO_SEEK_SET) {
+        pos = (PHYSFS_sint64) offset;
+    } else if (whence == SDL_IO_SEEK_CUR) {
+        const PHYSFS_sint64 current = PHYSFS_tell(handle);
+        if (current == -1) {
+            return SDL_SetError("Can't find position in file: %s", PHYSFS_getErrorByCode(PHYSFS_getLastErrorCode()));
+        }
+
+        if (offset == 0) {  /* this is a "tell" call. We're done. */
+            return (Sint64) current;
+        }
+
+        pos = current + ((PHYSFS_sint64) offset);
+    } else if (whence == SDL_IO_SEEK_END) {
+        const PHYSFS_sint64 len = PHYSFS_fileLength(handle);
+        if (len == -1) {
+            return SDL_SetError("Can't find end of file: %s", PHYSFS_getErrorByCode(PHYSFS_getLastErrorCode()));
+        }
+
+        pos = len + ((PHYSFS_sint64) offset);
+    } else {
+        return SDL_SetError("Invalid 'whence' parameter.");
+    }
+
+    if ( pos < 0 ) {
+        return SDL_SetError("Attempt to seek past start of file.");
+    }
+    
+    if (!PHYSFS_seek(handle, (PHYSFS_uint64) pos)) {
+        return SDL_SetError("PhysicsFS error: %s", PHYSFS_getErrorByCode(PHYSFS_getLastErrorCode()));
+    }
+
+    return (Sint64) pos;
+}
+
+static size_t SDLCALL physfsiostream_read(void *userdata, void *ptr, size_t size, SDL_IOStatus *status)
+{
+    PHYSFS_File *handle = (PHYSFS_File *) userdata;
+    const PHYSFS_uint64 readlen = (PHYSFS_uint64) size;
+    const PHYSFS_sint64 rc = PHYSFS_readBytes(handle, ptr, readlen);
+    if (rc != ((PHYSFS_sint64) readlen)) {
+        if (!PHYSFS_eof(handle)) {  /* not EOF? Must be an error. */
+            /* Setting an SDL error makes SDL take care of `status` for you. */
+            SDL_SetError("PhysicsFS error: %s", PHYSFS_getErrorByCode(PHYSFS_getLastErrorCode()));
+            return 0;
+        }
+    }
+    return (size_t) rc;
+}
+
+static size_t SDLCALL physfsiostream_write(void *userdata, const void *ptr, size_t size, SDL_IOStatus *status)
+{
+    PHYSFS_File *handle = (PHYSFS_File *) userdata;
+    const PHYSFS_uint64 writelen = (PHYSFS_uint64) size;
+    const PHYSFS_sint64 rc = PHYSFS_writeBytes(handle, ptr, writelen);
+    if (rc != ((PHYSFS_sint64) writelen)) {
+        /* Setting an SDL error makes SDL take care of `status` for you. */
+        SDL_SetError("PhysicsFS error: %s", PHYSFS_getErrorByCode(PHYSFS_getLastErrorCode()));
+    }
+    return (size_t) rc;
+}
+
+static int SDLCALL physfsiostream_close(void *userdata)
+{
+    if (!PHYSFS_close((PHYSFS_File *) userdata)) {
+        return SDL_SetError("PhysicsFS error: %s", PHYSFS_getErrorByCode(PHYSFS_getLastErrorCode()));
+    }
+    return 0;
+}
+
+static SDL_IOStream *create_iostream(PHYSFS_File *handle)
+{
+    SDL_IOStream *retval = NULL;
+    if (handle == NULL) {
+        SDL_SetError("PhysicsFS error: %s", PHYSFS_getErrorByCode(PHYSFS_getLastErrorCode()));
+    } else {
+        SDL_IOStreamInterface iface;
+        iface.size  = physfsiostream_size;
+        iface.seek  = physfsiostream_seek;
+        iface.read  = physfsiostream_read;
+        iface.write = physfsiostream_write;
+        iface.close = physfsiostream_close;
+        retval = SDL_OpenIO(&iface, handle);
+    }
+
+    return retval;
+}
+
+SDL_IOStream *PHYSFSSDL3_makeIOStream(PHYSFS_File *handle)
+{
+    SDL_IOStream *retval = NULL;
+    if (handle == NULL) {
+        SDL_SetError("NULL pointer passed to PHYSFSSDL3_makeRWops().");
+    } else {
+        retval = create_iostream(handle);
+    }
+    return retval;
+}
+
+SDL_IOStream *PHYSFSSDL3_openRead(const char *fname)
+{
+    return create_iostream(PHYSFS_openRead(fname));
+}
+
+SDL_IOStream *PHYSFSSDL3_openWrite(const char *fname)
+{
+    return create_iostream(PHYSFS_openWrite(fname));
+}
+
+SDL_IOStream *PHYSFSSDL3_openAppend(const char *fname)
+{
+    return create_iostream(PHYSFS_openAppend(fname));
+}
+
+
+/* SDL_Storage -> PhysicsFS bridge ... */
+
+static int SDLCALL physfssdl3storage_close(void *userdata)
+{
+    return 0;  /* this doesn't do anything, we didn't allocate anything specific to this object. */
+}
+
+static SDL_bool SDLCALL physfssdl3storage_ready(void *userdata)
+{
+    return SDL_TRUE;
+}
+
+/* this is a really obnoxious symbol name... */
+typedef struct physfssdl3storage_enumerate_callback_data
+{
+    SDL_EnumerateDirectoryCallback sdlcallback;
+    void *sdluserdata;
+} physfssdl3storage_enumerate_callback_data;
+
+static PHYSFS_EnumerateCallbackResult physfssdl3storage_enumerate_callback(void *userdata, const char *origdir, const char *fname)
+{
+    const physfssdl3storage_enumerate_callback_data *data = (physfssdl3storage_enumerate_callback_data *) userdata;
+    const int rc = data->sdlcallback(data->sdluserdata, origdir, fname);
+    if (rc < 0) {
+        return PHYSFS_ENUM_ERROR;
+    } else if (rc == 0) {
+        return PHYSFS_ENUM_STOP;
+    }
+    return PHYSFS_ENUM_OK;
+}
+
+static int SDLCALL physfssdl3storage_enumerate(void *userdata, const char *path, SDL_EnumerateDirectoryCallback callback, void *callback_userdata)
+{
+    physfssdl3storage_enumerate_callback_data data;
+    data.sdlcallback = callback;
+    data.sdluserdata = callback_userdata;
+    return PHYSFS_enumerate(path, physfssdl3storage_enumerate_callback, &data) ? 0 : -1;
+}
+
+static int SDLCALL physfssdl3storage_info(void *userdata, const char *path, SDL_PathInfo *info)
+{
+    PHYSFS_Stat statbuf;
+    if (!PHYSFS_stat(path, &statbuf)) {
+        return SDL_SetError("%s", PHYSFS_getErrorByCode(PHYSFS_getLastErrorCode()));
+    }
+
+    if (info) {
+        switch (statbuf.filetype) {
+            case PHYSFS_FILETYPE_REGULAR: info->type = SDL_PATHTYPE_FILE; break;
+            case PHYSFS_FILETYPE_DIRECTORY: info->type = SDL_PATHTYPE_DIRECTORY; break;
+            default: info->type = SDL_PATHTYPE_OTHER; break;
+        }
+
+        info->size = (Uint64) statbuf.filesize;
+        info->create_time = (SDL_Time) ((statbuf.createtime < 0) ? 0 : SDL_SECONDS_TO_NS(statbuf.createtime));
+        info->modify_time = (SDL_Time) ((statbuf.modtime < 0) ? 0 : SDL_SECONDS_TO_NS(statbuf.modtime));
+        info->access_time = (SDL_Time) ((statbuf.accesstime < 0) ? 0 : SDL_SECONDS_TO_NS(statbuf.accesstime));
+    }
+
+    return 0;
+}
+
+static int SDLCALL physfssdl3storage_read_file(void *userdata, const char *path, void *destination, Uint64 length)
+{
+    PHYSFS_file *f = PHYSFS_openRead(path);
+    PHYSFS_sint64 br;
+
+    if (!f) {
+        return SDL_SetError("%s", PHYSFS_getErrorByCode(PHYSFS_getLastErrorCode()));
+    }
+
+    br = PHYSFS_readBytes(f, destination, length);
+    PHYSFS_close(f);
+
+    if (br != (Sint64) length) {
+        return SDL_SetError("%s", PHYSFS_getErrorByCode(PHYSFS_getLastErrorCode()));
+    }
+    return 0;
+}
+
+
+static int SDLCALL physfssdl3storage_write_file(void *userdata, const char *path, const void *source, Uint64 length)
+{
+    PHYSFS_file *f = PHYSFS_openWrite(path);
+    PHYSFS_sint64 bw;
+
+    if (!f) {
+        return SDL_SetError("%s", PHYSFS_getErrorByCode(PHYSFS_getLastErrorCode()));
+    }
+
+    bw = PHYSFS_writeBytes(f, source, length);
+    PHYSFS_close(f);
+
+    if (bw != (Sint64) length) {
+        return SDL_SetError("%s", PHYSFS_getErrorByCode(PHYSFS_getLastErrorCode()));
+    }
+    return 0;
+}
+
+static int SDLCALL physfssdl3storage_mkdir(void *userdata, const char *path)
+{
+    if (!PHYSFS_mkdir(path)) {
+        return SDL_SetError("%s", PHYSFS_getErrorByCode(PHYSFS_getLastErrorCode()));
+    }
+    return 0;
+
+}
+
+static int SDLCALL physfssdl3storage_remove(void *userdata, const char *path)
+{
+    if (!PHYSFS_delete(path)) {
+        return SDL_SetError("%s", PHYSFS_getErrorByCode(PHYSFS_getLastErrorCode()));
+    }
+    return 0;
+}
+
+static int SDLCALL physfssdl3storage_rename(void *userdata, const char *oldpath, const char *newpath)
+{
+    return SDL_Unsupported();  /* no rename operation in PhysicsFS. */
+}
+
+static Uint64 SDLCALL physfssdl3storage_space_remaining(void *userdata)
+{
+    return SDL_MAX_UINT64;  /* we don't track this in PhysicsFS. */
+}
+
+SDL_Storage *PHYSFSSDL3_makeStorage(void)
+{
+    SDL_StorageInterface iface;
+    iface.close = physfssdl3storage_close;
+    iface.ready = physfssdl3storage_ready;
+    iface.enumerate = physfssdl3storage_enumerate;
+    iface.info = physfssdl3storage_info;
+    iface.read_file = physfssdl3storage_read_file;
+    iface.write_file = physfssdl3storage_write_file;
+    iface.mkdir = physfssdl3storage_mkdir;
+    iface.remove = physfssdl3storage_remove;
+    iface.rename = physfssdl3storage_rename;
+    iface.space_remaining = physfssdl3storage_space_remaining;
+    return SDL_OpenStorage(&iface, NULL);
+}
+
+/* end of physfssdl3.c ... */
+

+ 106 - 0
extras/physfssdl3.h

@@ -0,0 +1,106 @@
+/*
+ * This code provides a glue layer between PhysicsFS and Simple Directmedia
+ *  Layer 3's (SDL3) SDL_IOStream and SDL_Storage i/o abstractions.
+ *
+ * License: this code is public domain. I make no warranty that it is useful,
+ *  correct, harmless, or environmentally safe.
+ *
+ * This particular file may be used however you like, including copying it
+ *  verbatim into a closed-source project, exploiting it commercially, and
+ *  removing any trace of my name from the source (although I hope you won't
+ *  do that). I welcome enhancements and corrections to this file, but I do
+ *  not require you to send me patches if you make changes. This code has
+ *  NO WARRANTY.
+ *
+ * Unless otherwise stated, the rest of PhysicsFS falls under the zlib license.
+ *  Please see LICENSE.txt in the root of the source tree.
+ *
+ * SDL3 is zlib-licensed, like PhysicsFS. You can get SDL at
+ *  https://www.libsdl.org/
+ *
+ *  This file was written by Ryan C. Gordon. (icculus@icculus.org).
+ */
+
+/* This works with SDL3. For SDL1 and SDL2, use physfsrwops.h */
+
+#ifndef _INCLUDE_PHYSFSSDL3_H_
+#define _INCLUDE_PHYSFSSDL3_H_
+
+#include "physfs.h"
+#include <SDL3/SDL.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/* You can either just get SDL_IOStreams directly from a PhysicsFS path,
+   or make an SDL_Storage that bridges to the PhysicsFS VFS. */
+
+
+/**
+ * Open a platform-independent filename for reading, and make it accessible
+ *  via an SDL_IOStream. The file will be closed in PhysicsFS when the
+ *  RWops is closed. PhysicsFS should be configured to your liking before
+ *  opening files through this method.
+ *
+ *   @param filename File to open in platform-independent notation.
+ *  @return A valid SDL_IOStream on success, NULL on error. Specifics
+ *           of the error can be gleaned from SDL_GetError().
+ */
+PHYSFS_DECL SDL_IOStream *PHYSFSSDL3_openRead(const char *fname);
+
+/**
+ * Open a platform-independent filename for writing, and make it accessible
+ *  via an SDL_IOStream. The file will be closed in PhysicsFS when the
+ *  RWops is closed. PhysicsFS should be configured to your liking before
+ *  opening files through this method.
+ *
+ *   @param filename File to open in platform-independent notation.
+ *  @return A valid SDL_IOStream on success, NULL on error. Specifics
+ *           of the error can be gleaned from SDL_GetError().
+ */
+PHYSFS_DECL SDL_IOStream *PHYSFSSDL3_openWrite(const char *fname);
+
+/**
+ * Open a platform-independent filename for appending, and make it accessible
+ *  via an SDL_IOStream. The file will be closed in PhysicsFS when the
+ *  RWops is closed. PhysicsFS should be configured to your liking before
+ *  opening files through this method.
+ *
+ *   @param filename File to open in platform-independent notation.
+ *  @return A valid SDL_IOStream on success, NULL on error. Specifics
+ *           of the error can be gleaned from SDL_GetError().
+ */
+PHYSFS_DECL SDL_IOStream *PHYSFSSDL3_openAppend(const char *fname);
+
+/**
+ * Make a SDL_IOStream from an existing PhysicsFS file handle. You should
+ *  dispose of any references to the handle after successful creation of
+ *  the RWops. The actual PhysicsFS handle will be destroyed when the
+ *  RWops is closed.
+ *
+ *   @param handle a valid PhysicsFS file handle.
+ *  @return A valid SDL_IOStream on success, NULL on error. Specifics
+ *           of the error can be gleaned from SDL_GetError().
+ */
+PHYSFS_DECL SDL_IOStream *PHYSFSSDL3_makeIOStream(PHYSFS_File *handle);
+
+/**
+ * Expose the PhysicsFS VFS through an SDL_Storage interface.
+ * This just makes the global interpolated file tree available
+ * through SDL3's interface. You can still manipulate it outside
+ * of SDL_Storage by calling PhysicsFS APIs directly.
+ *
+ *  @return A valid SDL_Storage on success, NULL on error. Specifics
+ *           of the error can be gleaned from SDL_GetError().
+ */
+PHYSFS_DECL SDL_Storage *PHYSFSSDL3_makeStorage(void);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* include-once blocker */
+
+/* end of physfssdl3.h ... */
+