removed one warning for windoze build
[awish.git] / src / resfile.c
blob4acc685128e4eafb8596f65d4af6b67090406e6c
1 #ifdef _WIN32
2 # include <windows.h>
3 #endif
4 #include <stdio.h>
5 #include <stdlib.h>
6 #include <string.h>
7 #include <unistd.h>
8 #include <sys/types.h>
10 #include "libdernc.h"
12 #include "resfile.h"
15 #ifndef DATA_DIR
16 # define DATA_DIR "/usr/local/share/awish"
17 #endif
20 extern int goobers;
21 extern int datfirst;
24 static const char *getMyDir (void) {
25 static char myDir[8192];
26 static int inited = 0;
28 if (!inited) {
29 #ifndef _WIN32
30 pid_t pid = getpid();
31 char buf[128];
33 sprintf(buf, "/proc/%u/exe", (unsigned int)pid);
34 if (readlink(buf, myDir, sizeof(myDir)-1) < 0) {
35 strcpy(myDir, ".");
36 } else {
37 char *p = (char *)strrchr(myDir, '/');
39 if (!p) strcpy(myDir, "."); else *p = '\0';
41 strcat(myDir, "/data");
42 #else
43 char *p;
45 memset(myDir, 0, sizeof(myDir));
46 GetModuleFileName(GetModuleHandle(NULL), myDir, sizeof(myDir)-1);
47 for (p = myDir; *p; ++p) if (*p == '/') *p = '\\';
48 p = strrchr(myDir, '\\');
49 if (!p) strcpy(myDir, "."); else *p = '\0';
50 strcat(myDir, "\\data");
51 #endif
52 inited = 1;
54 return myDir;
58 #ifndef _WIN32
59 static const char *getHomeDir (void) {
60 static char homeDir[8192];
61 static int inited = 0;
63 if (!inited) {
64 #ifndef _WIN32
65 const char *h = getenv("HOME");
67 strcpy(homeDir, (h && h[0]) ? h : ".");
68 strcat(homeDir, "/.local/awish/data");
69 #else
70 // fuck windoze
71 strcpy(homeDir, ".");
72 #endif
73 inited = 1;
75 return homeDir;
77 #endif
80 int initResFile (ResFile *resfile, const char *fname) {
81 uint8_t fcnt;
82 uint8_t sign[3];
83 FILE *fl = fopen(fname, "rb");
84 int rr = -1, sz;
86 if (!fl) return -1;
87 if (!resfile) goto quit;
88 memset(resfile, 0, sizeof(resfile));
90 if (fread(sign, 3, 1, fl) != 1) goto quit;
91 if (memcmp(sign, "RES", 3) != 0) goto quit;
92 if (fread(&fcnt, 1, 1, fl) != 1) goto quit;
93 if (fcnt != 93) goto quit;
95 resfile->fl = fl;
96 resfile->count = fcnt;
98 if ((resfile->offsets = malloc(4*resfile->count)) == NULL) goto quit;
99 if ((resfile->sizes = malloc(4*resfile->count)) == NULL) goto quit;
101 if (fread(resfile->offsets, 4*resfile->count, 1, fl) != 1) goto quit;
102 #if SDL_BYTEORDER == SDL_BIG_ENDIAN
103 for (int f = 0; f < resfile->count; ++f) resfile->offsets[f] = SDL_SwapLE32(resfile->offsets[f]);
104 #endif
105 if (fseek(fl, 0, SEEK_END) != 0) goto quit;
106 sz = ftell(fl);
107 for (int f = 0; f < resfile->count-1; ++f) resfile->sizes[f] = resfile->offsets[f+1]-resfile->offsets[f];
108 resfile->sizes[resfile->count-1] = sz-resfile->offsets[resfile->count-1];
110 fl = NULL;
111 rr = 0;
112 quit:
113 if (fl != NULL) {
114 fclose(fl);
115 if (resfile->sizes) free(resfile->sizes);
116 if (resfile->offsets) free(resfile->offsets);
117 memset(resfile, 0, sizeof(resfile));
119 return rr;
123 void deinitResFile (ResFile *resfile) {
124 if (resfile) {
125 if (resfile->fl) fclose(resfile->fl);
126 if (resfile->sizes) free(resfile->sizes);
127 if (resfile->offsets) free(resfile->offsets);
128 memset(resfile, 0, sizeof(resfile));
133 typedef int (*UnpackCB) (unsigned char *dest, const unsigned char *data, int size);
136 static int unpackFNTFont (unsigned char *dest, const unsigned char *data, int size) {
137 Uint8 fc, lc;
138 int pos;
140 memset(dest, 0, 256*8);
141 if (size < 6) goto quit;
142 if (memcmp(data, "FNT0", 4) != 0) goto quit;
143 fc = data[4];
144 lc = data[5];
145 if (fc > lc) goto quit;
146 pos = 6;
147 for (int f = fc; f <= lc; ++f) {
148 if (pos+8 > size) goto quit;
149 memcpy(dest+f*8, data+pos, 8);
150 pos += 8;
152 return 0;
153 quit:
154 memset(dest, 0, 256*8);
155 return -1;
159 static int unpackBINFont (unsigned char *dest, const unsigned char *data, int size) {
160 memset(dest, 0, 256*8);
161 if (size < 90*8) return -1;
162 memcpy(dest+33*8, data, 90*8);
163 return 0;
167 static int unpackVPI (unsigned char *dest, const unsigned char *data, int size) {
168 if (size >= 320*200) {
169 memcpy(dest, data, 320*200);
170 } else {
171 int pos = 0; // in packed
172 int opos = 0; // in unpacked
173 int cpos = 0; // meaningless here (position of colormap)
175 while (opos < 320*200 && pos+2 <= size) {
176 int csz = ((uint32_t)(data[pos]))+256*((uint32_t)(data[pos+1])); // picture chunk size
178 cpos = (pos += 2); // colormap
179 pos += 512; // skip colormap
180 while (opos < 320*200 && pos < size && csz > 0) {
181 int idx = data[pos++];
183 dest[opos++] = data[cpos+idx*2+0];
184 dest[opos++] = data[cpos+idx*2+1];
185 --csz;
189 return 0;
193 uint8_t *tryDiskFile (const char *fname, int *rsz) {
194 FILE *fl = fopen(fname, "rb");
195 uint8_t *res = NULL;
196 long size;
198 if (rsz) *rsz = 0;
199 if (fl == NULL) return NULL;
200 if (goobers) fprintf(stderr, "trying disk resource: '%s'\n", fname);
201 if (fseek(fl, 0, SEEK_END) != 0) goto quit;
202 size = ftell(fl);
203 rewind(fl);
204 if (size < 0) goto quit;
206 res = calloc(1, size+16);
207 if (res == NULL) goto quit;
208 if (fread(res, size, 1, fl) != 1) goto quit;
210 if (size >= 18 && memcmp(res, "RNC\x01", 4) == 0) {
211 // unpack RNC file
212 int ulen, uplen;
213 uint8_t *udata;
215 ulen = rnc_ulen(res);
216 if (ulen < 1) goto quit;
217 udata = malloc(ulen+16);
218 if (udata == NULL) goto quit;
219 uplen = rnc_unpack(res, udata, NULL);
220 free(res);
221 res = udata;
222 if (goobers) fprintf(stderr, "RNC: %d -> %d (%d)\n", (int)size, ulen, uplen);
223 if (uplen != ulen) goto quit;
224 size = ulen;
226 fclose(fl);
227 fl = NULL;
229 quit:
230 if (fl != NULL) {
231 fclose(fl);
232 if (res != NULL) { free(res); res = NULL; }
233 } else {
234 if (res != NULL && rsz) *rsz = size;
236 return res;
240 static uint8_t *tryDiskFileEx (const char *fname, int *rsz, UnpackCB unp, int destsize) {
241 uint8_t *res, *up;
242 int sz;
244 if ((res = tryDiskFile(fname, &sz)) == NULL) return NULL;
246 if (!unp) {
247 if (destsize >= 0 && sz < destsize) { free(res); return NULL; }
248 } else {
250 if (destsize < 0) { free(res); return NULL; }
251 if ((up = calloc(1, destsize+16)) == NULL) { free(res); return NULL; }
252 if (unp(up, res, sz) != 0) { free(up); free(res); return NULL; }
253 free(res);
254 res = up;
255 sz = destsize;
257 if (rsz) *rsz = sz;
258 return res;
262 #define TRY_FILE(upk,usz,fmt,srcdir,...) do { \
263 sprintf(fname, (fmt), (srcdir), __VA_ARGS__); \
264 if ((res = tryDiskFileEx(fname, rsz, (upk), (usz))) != NULL) return res; \
265 } while (0)
268 #ifndef _WIN32
270 #define TRY_FILES(upk,usz,fmt,...) do { \
271 TRY_FILE((upk), (usz), "%s/" fmt, getHomeDir(), __VA_ARGS__); \
272 TRY_FILE((upk), (usz), "%s/" fmt, getMyDir(), __VA_ARGS__); \
273 TRY_FILE((upk), (usz), "%s/" fmt, DATA_DIR, __VA_ARGS__); \
274 } while (0)
276 #else
278 #define TRY_FILES(upk,usz,fmt,...) do { \
279 TRY_FILE((upk), (usz), "%s/" fmt, getMyDir(), __VA_ARGS__); \
280 } while (0)
282 #endif
285 static uint8_t *tryLocalCodeFile (int *rsz) {
286 static char fname[512];
287 char *t;
289 strcpy(fname, getMyDir());
290 t = strrchr(fname, '/');
291 if (t) *t = 0;
292 strcat(fname, "/awish.vmd");
293 return tryDiskFileEx(fname, rsz, NULL, 8);
297 static uint8_t *loadDiskFile (int idx, int *rsz) {
298 static char fname[512];
299 uint8_t *res;
301 if (rsz) *rsz = 0;
302 if (idx < 0) return NULL;
304 if (idx >= 0 && idx <= 6) {
305 TRY_FILES(unpackVPI, 64000, "pics/back%02d.vpi", idx+1);
306 return NULL;
309 if (idx == 7) {
310 TRY_FILES(unpackVPI, 64000, "pics/title.vpi%s", "");
311 return NULL;
314 if (idx == 8) {
315 TRY_FILES(unpackVPI, 64000, "pics/interback.vpi%s", "");
316 return NULL;
319 if (idx >= 9 && idx <= 82) {
320 TRY_FILES(NULL, 3700, "maps/level%02d.lvl", idx-8);
321 return NULL;
324 if (idx == 83) {
325 TRY_FILES(NULL, 768, "pics/palette.vga%s", "");
326 return NULL;
329 if (idx == 84) {
330 TRY_FILES(NULL, 50568, "sprites/professor.spr%s", "");
331 return NULL;
334 if (idx == 85) {
335 TRY_FILES(NULL, 3468, "sprites/fgtiles.spr%s", "");
336 return NULL;
339 if (idx == 86) {
340 TRY_FILES(NULL, 2652, "sprites/bgtiles.spr%s", "");
341 return NULL;
344 if (idx == 87) {
345 TRY_FILES(NULL, 588, "sprites/maptiles.spr%s", "");
346 return NULL;
349 if (idx == 88) {
350 TRY_FILES(NULL, 19796, "sprites/items.spr%s", "");
351 return NULL;
354 if (idx == 89) {
355 TRY_FILES(NULL, 620, "sprites/mapitems.spr%s", "");
356 return NULL;
359 if (idx == 90) {
360 TRY_FILES(NULL, 44940, "sprites/professorim.spr%s", "");
361 return NULL;
364 if (idx == 91) {
365 TRY_FILES(NULL, 9441, "sprites/himenu.spr%s", "");
366 return NULL;
369 if (idx == 92) {
370 TRY_FILES(unpackFNTFont, 256*8, "fonts/namco.fnt%s", "");
371 TRY_FILES(unpackFNTFont, 256*8, "fonts/font.fnt%s", "");
372 TRY_FILES(unpackBINFont, 256*8, "fonts/font.bin%s", "");
373 return NULL;
376 if (idx == 666) {
377 if (goobers) {
378 if ((res = tryLocalCodeFile(rsz)) != NULL) return res;
381 TRY_FILES(NULL, 8, "code/awish.vmd%s", "");
383 if (!goobers) {
384 if ((res = tryLocalCodeFile(rsz)) != NULL) return res;
386 return NULL;
388 return NULL;
392 static uint8_t *tryResFile (ResFile *resfile, int idx, int *rsz, UnpackCB unp, int destsize) {
393 uint8_t *res = NULL, *up;
394 int size;
396 if (rsz) *rsz = 0;
397 if (!resfile || !resfile->fl || idx < 0 || idx >= resfile->count) return NULL;
399 if (goobers) fprintf(stderr, "trying RES resource: %d\n", idx);
400 //fprintf(stderr, "idx=%d; ofs=%u; size=%u\n", idx, resfile->offsets[idx], resfile->sizes[idx]);
401 size = resfile->sizes[idx];
402 if (fseek(resfile->fl, resfile->offsets[idx], SEEK_SET) != 0) return NULL;
403 if ((res = (uint8_t *)calloc(1, size+16)) == NULL) return NULL;
404 if (size > 0) {
405 if (fread(res, size, 1, resfile->fl) != 1) { free(res); return NULL; }
408 if (size >= 18 && memcmp(res, "RNC\x01", 4) == 0) {
409 // unpack RNC file
410 int ulen, uplen;
411 uint8_t *udata;
413 ulen = rnc_ulen(res);
414 if (ulen < 1) { free(res); return NULL; }
415 udata = malloc(ulen+16);
416 if (udata == NULL) { free(res); return NULL; }
417 uplen = rnc_unpack(res, udata, NULL);
418 free(res);
419 res = udata;
420 if (uplen != ulen) { free(res); return NULL; }
421 size = ulen;
424 if (!unp) {
425 if (destsize >= 0 && size < destsize) { free(res); return NULL; }
426 } else {
427 if (destsize < 0) { free(res); return NULL; }
428 if ((up = calloc(1, destsize+16)) == NULL) { free(res); return NULL; }
429 if (unp(up, res, size) != 0) { free(up); free(res); return NULL; }
430 free(res);
431 res = up;
432 size = destsize;
435 if (rsz) *rsz = size;
436 return res;
440 uint8_t *loadResFile (ResFile *resfile, int idx, int *rsz) {
441 uint8_t *res = NULL;
443 if (!datfirst) res = loadDiskFile(idx, rsz);
445 if (res != NULL || resfile == NULL) return res;
447 if (idx >= 0 && idx <= 8) {
448 return tryResFile(resfile, idx, rsz, (resfile->sizes[idx] < 320*200) ? unpackVPI : NULL, 320*200);
451 if (idx >= 9 && idx <= 82) {
452 return tryResFile(resfile, idx, rsz, NULL, 3700);
455 if (idx == 83) {
456 return tryResFile(resfile, idx, rsz, NULL, 768);
459 if (idx == 84) {
460 return tryResFile(resfile, idx, rsz, NULL, 50568);
463 if (idx == 85) {
464 return tryResFile(resfile, idx, rsz, NULL, 3468);
467 if (idx == 86) {
468 return tryResFile(resfile, idx, rsz, NULL, 2652);
471 if (idx == 87) {
472 return tryResFile(resfile, idx, rsz, NULL, 588);
475 if (idx == 88) {
476 return tryResFile(resfile, idx, rsz, NULL, 19796);
479 if (idx == 89) {
480 return tryResFile(resfile, idx, rsz, NULL, 620);
483 if (idx == 90) {
484 return tryResFile(resfile, idx, rsz, NULL, 44940);
487 if (idx == 91) {
488 return tryResFile(resfile, idx, rsz, NULL, 9441);
491 if (idx == 92) {
492 return tryResFile(resfile, idx, rsz, unpackBINFont, 256*8);
495 if (datfirst) res = loadDiskFile(idx, rsz);
497 return res;