summaryrefslogtreecommitdiff
path: root/jni/physfs-serve-sdl-wrap.c
blob: 92b2290130b57d12c33104090399679e6de3e2e1 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
#include "libphysfs-serve.h"
#include <physfs.h>
#include <SDL_rwops.h>
#include <unistd.h>
#include <string.h>
#include <stdio.h>
#include <assert.h>

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 != -1return 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 <SDL.h>
#include <unistd.h>

int
main(int argc, char *argv[]) {
   SDL_Init(0);
   int ret = physfs_serve_main(argc, argv);
   SDL_Quit();
   return ret;
}