FileSystem: Add fallback to wrapped SDL_RWops if normal mounting fails
Makes it easy to mount archives on Android residing in "assets/".
This commit is contained in:
parent
3411435138
commit
4fb94aaf10
|
@ -42,6 +42,105 @@
|
||||||
#include <iconv.h>
|
#include <iconv.h>
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
struct SDLRWIoContext
|
||||||
|
{
|
||||||
|
SDL_RWops *ops;
|
||||||
|
std::string filename;
|
||||||
|
|
||||||
|
SDLRWIoContext(const char *filename)
|
||||||
|
: ops(SDL_RWFromFile(filename, "r")),
|
||||||
|
filename(filename)
|
||||||
|
{
|
||||||
|
if (!ops)
|
||||||
|
throw Exception(Exception::SDLError,
|
||||||
|
"Failed to open file: %s", SDL_GetError());
|
||||||
|
}
|
||||||
|
|
||||||
|
~SDLRWIoContext()
|
||||||
|
{
|
||||||
|
SDL_RWclose(ops);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
static PHYSFS_Io *createSDLRWIo(const char *filename);
|
||||||
|
|
||||||
|
static SDL_RWops *getSDLRWops(PHYSFS_Io *io)
|
||||||
|
{
|
||||||
|
return static_cast<SDLRWIoContext*>(io->opaque)->ops;
|
||||||
|
}
|
||||||
|
|
||||||
|
static PHYSFS_sint64 SDLRWIoRead(struct PHYSFS_Io *io, void *buf, PHYSFS_uint64 len)
|
||||||
|
{
|
||||||
|
return SDL_RWread(getSDLRWops(io), buf, 1, len);
|
||||||
|
}
|
||||||
|
|
||||||
|
static int SDLRWIoSeek(struct PHYSFS_Io *io, PHYSFS_uint64 offset)
|
||||||
|
{
|
||||||
|
return (SDL_RWseek(getSDLRWops(io), offset, RW_SEEK_SET) != -1);
|
||||||
|
}
|
||||||
|
|
||||||
|
static PHYSFS_sint64 SDLRWIoTell(struct PHYSFS_Io *io)
|
||||||
|
{
|
||||||
|
return SDL_RWseek(getSDLRWops(io), 0, RW_SEEK_CUR);
|
||||||
|
}
|
||||||
|
|
||||||
|
static PHYSFS_sint64 SDLRWIoLength(struct PHYSFS_Io *io)
|
||||||
|
{
|
||||||
|
return SDL_RWsize(getSDLRWops(io));
|
||||||
|
}
|
||||||
|
|
||||||
|
static struct PHYSFS_Io *SDLRWIoDuplicate(struct PHYSFS_Io *io)
|
||||||
|
{
|
||||||
|
SDLRWIoContext *ctx = static_cast<SDLRWIoContext*>(io->opaque);
|
||||||
|
int64_t offset = io->tell(io);
|
||||||
|
PHYSFS_Io *dup = createSDLRWIo(ctx->filename.c_str());
|
||||||
|
|
||||||
|
if (dup)
|
||||||
|
SDLRWIoSeek(dup, offset);
|
||||||
|
|
||||||
|
return dup;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void SDLRWIoDestroy(struct PHYSFS_Io *io)
|
||||||
|
{
|
||||||
|
delete static_cast<SDLRWIoContext*>(io->opaque);
|
||||||
|
delete io;
|
||||||
|
}
|
||||||
|
|
||||||
|
static PHYSFS_Io SDLRWIoTemplate =
|
||||||
|
{
|
||||||
|
0, 0, /* version, opaque */
|
||||||
|
SDLRWIoRead,
|
||||||
|
0, /* write */
|
||||||
|
SDLRWIoSeek,
|
||||||
|
SDLRWIoTell,
|
||||||
|
SDLRWIoLength,
|
||||||
|
SDLRWIoDuplicate,
|
||||||
|
0, /* flush */
|
||||||
|
SDLRWIoDestroy
|
||||||
|
};
|
||||||
|
|
||||||
|
static PHYSFS_Io *createSDLRWIo(const char *filename)
|
||||||
|
{
|
||||||
|
SDLRWIoContext *ctx;
|
||||||
|
|
||||||
|
try
|
||||||
|
{
|
||||||
|
ctx = new SDLRWIoContext(filename);
|
||||||
|
}
|
||||||
|
catch (const Exception &e)
|
||||||
|
{
|
||||||
|
Debug() << "Failed mounting" << filename;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
PHYSFS_Io *io = new PHYSFS_Io;
|
||||||
|
*io = SDLRWIoTemplate;
|
||||||
|
io->opaque = ctx;
|
||||||
|
|
||||||
|
return io;
|
||||||
|
}
|
||||||
|
|
||||||
static inline PHYSFS_File *sdlPHYS(SDL_RWops *ops)
|
static inline PHYSFS_File *sdlPHYS(SDL_RWops *ops)
|
||||||
{
|
{
|
||||||
return static_cast<PHYSFS_File*>(ops->hidden.unknown.data1);
|
return static_cast<PHYSFS_File*>(ops->hidden.unknown.data1);
|
||||||
|
@ -368,7 +467,16 @@ FileSystem::~FileSystem()
|
||||||
|
|
||||||
void FileSystem::addPath(const char *path)
|
void FileSystem::addPath(const char *path)
|
||||||
{
|
{
|
||||||
PHYSFS_mount(path, 0, 1);
|
/* Try the normal mount first */
|
||||||
|
if (!PHYSFS_mount(path, 0, 1))
|
||||||
|
{
|
||||||
|
/* If it didn't work, try mounting via a wrapped
|
||||||
|
* SDL_RWops */
|
||||||
|
PHYSFS_Io *io = createSDLRWIo(path);
|
||||||
|
|
||||||
|
if (io)
|
||||||
|
PHYSFS_mountIo(io, path, 0, 1);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#ifdef __APPLE__
|
#ifdef __APPLE__
|
||||||
|
|
Loading…
Reference in New Issue