#include "libphysfs-serve.h" #include #include #include #include #include #include static void ignore_ret(bool b, ...) {}; #define ignore_ret(x) ignore_ret(true, x); struct io_wrapper { SDL_RWops *ops; const char *path; }; static SDL_RWops* get_ops(struct io_wrapper *w) { return w->ops; } static const char* get_path(struct io_wrapper *w) { return w->path; } static PHYSFS_sint64 SDLRWIoRead(struct PHYSFS_Io *io, void *buf, PHYSFS_uint64 len) { return SDL_RWread(get_ops(io->opaque), buf, 1, len); } static int SDLRWIoSeek(struct PHYSFS_Io *io, PHYSFS_uint64 offset) { return (SDL_RWseek(get_ops(io->opaque), offset, RW_SEEK_SET) != -1); } static PHYSFS_sint64 SDLRWIoTell(struct PHYSFS_Io *io) { return SDL_RWseek(get_ops(io->opaque), 0, RW_SEEK_CUR); } static PHYSFS_sint64 SDLRWIoLength(struct PHYSFS_Io *io) { return SDL_RWsize(get_ops(io->opaque)); } static PHYSFS_Io* SDLRWIo_new(const char *path); static struct PHYSFS_Io* SDLRWIoDuplicate(struct PHYSFS_Io *io) { PHYSFS_Io *dup = SDLRWIo_new(get_path(io->opaque)); if (dup) SDLRWIoSeek(dup, io->tell(io)); return dup; } static void SDLRWIoDestroy(struct PHYSFS_Io *io) { SDL_RWclose(get_ops(io->opaque)); free(io->opaque); free(io); } static void* copy_dynamic(const void *ptr, const size_t size) { void *cpy = malloc(size); memcpy(cpy, ptr, size); return cpy; } #define copy_static(x) copy_dynamic(&x, sizeof(x)) static PHYSFS_Io* SDLRWIo_new(const char *path) { struct io_wrapper wrapper = { .ops = SDL_RWFromFile(path, "r"), .path = path, }; if (!wrapper.ops) return NULL; struct PHYSFS_Io io = { .version = 0, .opaque = copy_static(wrapper), .read = SDLRWIoRead, .write = NULL, .seek = SDLRWIoSeek, .tell = SDLRWIoTell, .length = SDLRWIoLength, .duplicate = SDLRWIoDuplicate, .flush = NULL, .destroy = SDLRWIoDestroy }; if (!io.opaque) { SDL_RWclose(wrapper.ops); return NULL; } return copy_static(io); } static bool mount(const char *path, const char *root, bool append) { if (PHYSFS_mount(path, root, append)) return true; PHYSFS_Io *io = SDLRWIo_new(path); if (!PHYSFS_mountIo(io, path, root, append)) { io->destroy(io); return false; } return true; } static const char* content_type(struct physfs_serve *serve, const char *path) { if (physfs_ends_with(path, ".rpgmvp")) return "image/png"; else if (physfs_ends_with(path, ".rpgmvo")) return "audio/ogg"; else if (physfs_ends_with(path, ".rpgmvm")) return "audio/mp4"; return physfs_default_content_type(serve, path); } static bool replace_ext(char buf[], const size_t bufsz, const char *old, const char *new) { if (!physfs_ends_with(buf, old)) return false; size_t len = strlen(buf); assert(len >= strlen(old)); len -= strlen(old); assert(bufsz >= len); snprintf(buf + len, bufsz - len, "%s", new); return true; } static bool path_rewrite(struct physfs_serve *serve, char buf[], const size_t bufsz, struct PHYSFS_Stat *st) { if (physfs_default_path_rewrite(serve, buf, bufsz, st)) return true; if (st->filetype != -1) return false; if (replace_ext(buf, bufsz, ".rpgmvm", ".rpgmvo")) return PHYSFS_stat(buf, st); else if (replace_ext(buf, bufsz, ".rpgmvo", ".rpgmvm")) return PHYSFS_stat(buf, st); else if (replace_ext(buf, bufsz, ".webm", ".mp4")) return PHYSFS_stat(buf, st); else if (replace_ext(buf, bufsz, ".mp4", ".webm")) return PHYSFS_stat(buf, st); else if (replace_ext(buf, bufsz, ".png", ".rpgmvp")) return PHYSFS_stat(buf, st); else if (replace_ext(buf, bufsz, ".ogg", ".rpgmvo")) return PHYSFS_stat(buf, st); else if (replace_ext(buf, bufsz, ".mp4", ".rpgmvm")) return PHYSFS_stat(buf, st); return false; } #define SERVE_INIT .content_type = content_type, .path_rewrite = path_rewrite #define PHYSFS_mount mount #define main physfs_serve_main #include "physfs-serve.c" #undef main #undef PHYSFS_mount #undef SERVE_INIT #include #include int main(int argc, char *argv[]) { SDL_Init(0); int ret = physfs_serve_main(argc, argv); SDL_Quit(); return ret; }