From 4fb94aaf1031ee9c7f412faedbd6776ce1888cba Mon Sep 17 00:00:00 2001 From: Jonas Kulla Date: Fri, 2 Jan 2015 14:50:14 +0100 Subject: [PATCH] FileSystem: Add fallback to wrapped SDL_RWops if normal mounting fails Makes it easy to mount archives on Android residing in "assets/". --- src/filesystem.cpp | 110 ++++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 109 insertions(+), 1 deletion(-) diff --git a/src/filesystem.cpp b/src/filesystem.cpp index 2b1e6ee..0e4a06c 100644 --- a/src/filesystem.cpp +++ b/src/filesystem.cpp @@ -42,6 +42,105 @@ #include #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(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(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(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) { return static_cast(ops->hidden.unknown.data1); @@ -368,7 +467,16 @@ FileSystem::~FileSystem() 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__