#include "libphysfs-serve.h" #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 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 (physfs_ends_with(buf, ".rpgmvm")) { buf[strlen(buf) - 1] = 'o'; if (st->filetype == -1 && PHYSFS_stat(buf, st)) return false; } else if (physfs_ends_with(buf, ".rpgmvo")) { buf[strlen(buf) - 1] = 'm'; if (st->filetype == -1 && PHYSFS_stat(buf, st)) return false; } else if (physfs_ends_with(buf, ".webm")) { buf[strlen(buf) - 1] = 0; buf[strlen(buf) - 2] = '4'; buf[strlen(buf) - 3] = 'p'; buf[strlen(buf) - 4] = 'm'; if (st->filetype == -1 && PHYSFS_stat(buf, st)) return false; } else if (physfs_ends_with(buf, ".mp4")) { buf[strlen(buf) + 2] = 0; buf[strlen(buf) + 1] = 'm'; buf[strlen(buf)] = 'b'; buf[strlen(buf) - 1] = 'e'; buf[strlen(buf) - 2] = 'w'; if (st->filetype == -1 && PHYSFS_stat(buf, st)) return false; } 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; }