-
-
Notifications
You must be signed in to change notification settings - Fork 98
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
This is like physfsrwops, but for SDL3's SDL_IOStream and SDL_Storage. Fixes #77. (cherry picked from commit f4dfeb9)
- Loading branch information
Showing
4 changed files
with
408 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -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 ... */ | ||
|
Oops, something went wrong.