remove umbrella sprite on level start
[awish.git] / src / resfile.c
blob66b07f8508fadedf0e319c5624972b627e4a251d
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 static const char *getHomeDir (void) {
59 static char homeDir[8192];
60 static int inited = 0;
62 if (!inited) {
63 #ifndef _WIN32
64 const char *h = getenv("HOME");
66 strcpy(homeDir, (h && h[0]) ? h : ".");
67 strcat(homeDir, "/.local/awish/data");
68 #else
69 // fuck windoze
70 strcpy(homeDir, ".");
71 #endif
72 inited = 1;
74 return homeDir;
78 int initResFile (ResFile *resfile, const char *fname) {
79 uint8_t fcnt;
80 uint8_t sign[3];
81 FILE *fl = fopen(fname, "rb");
82 int rr = -1, sz;
84 if (!fl) return -1;
85 if (!resfile) goto quit;
86 memset(resfile, 0, sizeof(resfile));
88 if (fread(sign, 3, 1, fl) != 1) goto quit;
89 if (memcmp(sign, "RES", 3) != 0) goto quit;
90 if (fread(&fcnt, 1, 1, fl) != 1) goto quit;
91 if (fcnt != 93) goto quit;
93 resfile->fl = fl;
94 resfile->count = fcnt;
96 if ((resfile->offsets = malloc(4*resfile->count)) == NULL) goto quit;
97 if ((resfile->sizes = malloc(4*resfile->count)) == NULL) goto quit;
99 if (fread(resfile->offsets, 4*resfile->count, 1, fl) != 1) goto quit;
100 #if SDL_BYTEORDER == SDL_BIG_ENDIAN
101 for (int f = 0; f < resfile->count; ++f) resfile->offsets[f] = SDL_SwapLE32(resfile->offsets[f]);
102 #endif
103 if (fseek(fl, 0, SEEK_END) != 0) goto quit;
104 sz = ftell(fl);
105 for (int f = 0; f < resfile->count-1; ++f) resfile->sizes[f] = resfile->offsets[f+1]-resfile->offsets[f];
106 resfile->sizes[resfile->count-1] = sz-resfile->offsets[resfile->count-1];
108 fl = NULL;
109 rr = 0;
110 quit:
111 if (fl != NULL) {
112 fclose(fl);
113 if (resfile->sizes) free(resfile->sizes);
114 if (resfile->offsets) free(resfile->offsets);
115 memset(resfile, 0, sizeof(resfile));
117 return rr;
121 void deinitResFile (ResFile *resfile) {
122 if (resfile) {
123 if (resfile->fl) fclose(resfile->fl);
124 if (resfile->sizes) free(resfile->sizes);
125 if (resfile->offsets) free(resfile->offsets);
126 memset(resfile, 0, sizeof(resfile));
131 typedef int (*UnpackCB) (unsigned char *dest, const unsigned char *data, int size);
134 static int unpackFNTFont (unsigned char *dest, const unsigned char *data, int size) {
135 Uint8 fc, lc;
136 int pos;
138 memset(dest, 0, 256*8);
139 if (size < 6) goto quit;
140 if (memcmp(data, "FNT0", 4) != 0) goto quit;
141 fc = data[4];
142 lc = data[5];
143 if (fc > lc) goto quit;
144 pos = 6;
145 for (int f = fc; f <= lc; ++f) {
146 if (pos+8 > size) goto quit;
147 memcpy(dest+f*8, data+pos, 8);
148 pos += 8;
150 return 0;
151 quit:
152 memset(dest, 0, 256*8);
153 return -1;
157 static int unpackBINFont (unsigned char *dest, const unsigned char *data, int size) {
158 memset(dest, 0, 256*8);
159 if (size < 90*8) return -1;
160 memcpy(dest+33*8, data, 90*8);
161 return 0;
165 static int unpackVPI (unsigned char *dest, const unsigned char *data, int size) {
166 if (size >= 320*200) {
167 memcpy(dest, data, 320*200);
168 } else {
169 int pos = 0; // in packed
170 int opos = 0; // in unpacked
171 int cpos = 0; // meaningless here (position of colormap)
173 while (opos < 320*200 && pos+2 <= size) {
174 int csz = ((uint32_t)(data[pos]))+256*((uint32_t)(data[pos+1])); // picture chunk size
176 cpos = (pos += 2); // colormap
177 pos += 512; // skip colormap
178 while (opos < 320*200 && pos < size && csz > 0) {
179 int idx = data[pos++];
181 dest[opos++] = data[cpos+idx*2+0];
182 dest[opos++] = data[cpos+idx*2+1];
183 --csz;
187 return 0;
191 uint8_t *tryDiskFile (const char *fname, int *rsz) {
192 FILE *fl = fopen(fname, "rb");
193 uint8_t *res = NULL;
194 long size;
196 if (rsz) *rsz = 0;
197 if (fl == NULL) return NULL;
198 if (goobers) fprintf(stderr, "trying disk resource: '%s'\n", fname);
199 if (fseek(fl, 0, SEEK_END) != 0) goto quit;
200 size = ftell(fl);
201 rewind(fl);
202 if (size < 0) goto quit;
204 res = calloc(1, size+16);
205 if (res == NULL) goto quit;
206 if (fread(res, size, 1, fl) != 1) goto quit;
208 if (size >= 18 && memcmp(res, "RNC\x01", 4) == 0) {
209 // unpack RNC file
210 int ulen, uplen;
211 uint8_t *udata;
213 ulen = rnc_ulen(res);
214 if (ulen < 1) goto quit;
215 udata = malloc(ulen+16);
216 if (udata == NULL) goto quit;
217 uplen = rnc_unpack(res, udata, NULL);
218 free(res);
219 res = udata;
220 if (goobers) fprintf(stderr, "RNC: %d -> %d (%d)\n", (int)size, ulen, uplen);
221 if (uplen != ulen) goto quit;
222 size = ulen;
224 fclose(fl);
225 fl = NULL;
227 quit:
228 if (fl != NULL) {
229 fclose(fl);
230 if (res != NULL) { free(res); res = NULL; }
231 } else {
232 if (res != NULL && rsz) *rsz = size;
234 return res;
238 static uint8_t *tryDiskFileEx (const char *fname, int *rsz, UnpackCB unp, int destsize) {
239 uint8_t *res, *up;
240 int sz;
242 if ((res = tryDiskFile(fname, &sz)) == NULL) return NULL;
244 if (!unp) {
245 if (destsize >= 0 && sz < destsize) { free(res); return NULL; }
246 } else {
248 if (destsize < 0) { free(res); return NULL; }
249 if ((up = calloc(1, destsize+16)) == NULL) { free(res); return NULL; }
250 if (unp(up, res, sz) != 0) { free(up); free(res); return NULL; }
251 free(res);
252 res = up;
253 sz = destsize;
255 if (rsz) *rsz = sz;
256 return res;
260 #define TRY_FILE(upk,usz,fmt,srcdir,...) do { \
261 sprintf(fname, (fmt), (srcdir), __VA_ARGS__); \
262 if ((res = tryDiskFileEx(fname, rsz, (upk), (usz))) != NULL) return res; \
263 } while (0)
266 #ifndef _WIN32
268 #define TRY_FILES(upk,usz,fmt,...) do { \
269 TRY_FILE((upk), (usz), "%s/" fmt, getHomeDir(), __VA_ARGS__); \
270 TRY_FILE((upk), (usz), "%s/" fmt, getMyDir(), __VA_ARGS__); \
271 TRY_FILE((upk), (usz), "%s/" fmt, DATA_DIR, __VA_ARGS__); \
272 } while (0)
274 #else
276 #define TRY_FILES(upk,usz,fmt,...) do { \
277 TRY_FILE((upk), (usz), "%s/" fmt, getMyDir(), __VA_ARGS__); \
278 } while (0)
280 #endif
283 static uint8_t *tryLocalCodeFile (int *rsz) {
284 static char fname[512];
285 char *t;
287 strcpy(fname, getMyDir());
288 t = strrchr(fname, '/');
289 if (t) *t = 0;
290 strcat(fname, "/awish.vmd");
291 return tryDiskFileEx(fname, rsz, NULL, 8);
295 static uint8_t *loadDiskFile (int idx, int *rsz) {
296 static char fname[512];
297 uint8_t *res;
299 if (rsz) *rsz = 0;
300 if (idx < 0) return NULL;
302 if (idx >= 0 && idx <= 6) {
303 TRY_FILES(unpackVPI, 64000, "pics/back%02d.vpi", idx+1);
304 return NULL;
307 if (idx == 7) {
308 TRY_FILES(unpackVPI, 64000, "pics/title.vpi%s", "");
309 return NULL;
312 if (idx == 8) {
313 TRY_FILES(unpackVPI, 64000, "pics/interback.vpi%s", "");
314 return NULL;
317 if (idx >= 9 && idx <= 82) {
318 TRY_FILES(NULL, 3700, "maps/level%02d.lvl", idx-8);
319 return NULL;
322 if (idx == 83) {
323 TRY_FILES(NULL, 768, "pics/palette.vga%s", "");
324 return NULL;
327 if (idx == 84) {
328 TRY_FILES(NULL, 50568, "sprites/professor.spr%s", "");
329 return NULL;
332 if (idx == 85) {
333 TRY_FILES(NULL, 3468, "sprites/fgtiles.spr%s", "");
334 return NULL;
337 if (idx == 86) {
338 TRY_FILES(NULL, 2652, "sprites/bgtiles.spr%s", "");
339 return NULL;
342 if (idx == 87) {
343 TRY_FILES(NULL, 588, "sprites/maptiles.spr%s", "");
344 return NULL;
347 if (idx == 88) {
348 TRY_FILES(NULL, 19796, "sprites/items.spr%s", "");
349 return NULL;
352 if (idx == 89) {
353 TRY_FILES(NULL, 620, "sprites/mapitems.spr%s", "");
354 return NULL;
357 if (idx == 90) {
358 TRY_FILES(NULL, 44940, "sprites/professorim.spr%s", "");
359 return NULL;
362 if (idx == 91) {
363 TRY_FILES(NULL, 9441, "sprites/himenu.spr%s", "");
364 return NULL;
367 if (idx == 92) {
368 TRY_FILES(unpackFNTFont, 256*8, "fonts/namco.fnt%s", "");
369 TRY_FILES(unpackFNTFont, 256*8, "fonts/font.fnt%s", "");
370 TRY_FILES(unpackBINFont, 256*8, "fonts/font.bin%s", "");
371 return NULL;
374 if (idx == 666) {
375 if (goobers) {
376 if ((res = tryLocalCodeFile(rsz)) != NULL) return res;
379 TRY_FILES(NULL, 8, "code/awish.vmd%s", "");
381 if (!goobers) {
382 if ((res = tryLocalCodeFile(rsz)) != NULL) return res;
384 return NULL;
386 return NULL;
390 static uint8_t *tryResFile (ResFile *resfile, int idx, int *rsz, UnpackCB unp, int destsize) {
391 uint8_t *res = NULL, *up;
392 int size;
394 if (rsz) *rsz = 0;
395 if (!resfile || !resfile->fl || idx < 0 || idx >= resfile->count) return NULL;
397 if (goobers) fprintf(stderr, "trying RES resource: %d\n", idx);
398 //fprintf(stderr, "idx=%d; ofs=%u; size=%u\n", idx, resfile->offsets[idx], resfile->sizes[idx]);
399 size = resfile->sizes[idx];
400 if (fseek(resfile->fl, resfile->offsets[idx], SEEK_SET) != 0) return NULL;
401 if ((res = (uint8_t *)calloc(1, size+16)) == NULL) return NULL;
402 if (size > 0) {
403 if (fread(res, size, 1, resfile->fl) != 1) { free(res); return NULL; }
406 if (size >= 18 && memcmp(res, "RNC\x01", 4) == 0) {
407 // unpack RNC file
408 int ulen, uplen;
409 uint8_t *udata;
411 ulen = rnc_ulen(res);
412 if (ulen < 1) { free(res); return NULL; }
413 udata = malloc(ulen+16);
414 if (udata == NULL) { free(res); return NULL; }
415 uplen = rnc_unpack(res, udata, NULL);
416 free(res);
417 res = udata;
418 if (uplen != ulen) { free(res); return NULL; }
419 size = ulen;
422 if (!unp) {
423 if (destsize >= 0 && size < destsize) { free(res); return NULL; }
424 } else {
425 if (destsize < 0) { free(res); return NULL; }
426 if ((up = calloc(1, destsize+16)) == NULL) { free(res); return NULL; }
427 if (unp(up, res, size) != 0) { free(up); free(res); return NULL; }
428 free(res);
429 res = up;
430 size = destsize;
433 if (rsz) *rsz = size;
434 return res;
438 uint8_t *loadResFile (ResFile *resfile, int idx, int *rsz) {
439 uint8_t *res = NULL;
441 if (!datfirst) res = loadDiskFile(idx, rsz);
443 if (res != NULL || resfile == NULL) return res;
445 if (idx >= 0 && idx <= 8) {
446 return tryResFile(resfile, idx, rsz, (resfile->sizes[idx] < 320*200) ? unpackVPI : NULL, 320*200);
449 if (idx >= 9 && idx <= 82) {
450 return tryResFile(resfile, idx, rsz, NULL, 3700);
453 if (idx == 83) {
454 return tryResFile(resfile, idx, rsz, NULL, 768);
457 if (idx == 84) {
458 return tryResFile(resfile, idx, rsz, NULL, 50568);
461 if (idx == 85) {
462 return tryResFile(resfile, idx, rsz, NULL, 3468);
465 if (idx == 86) {
466 return tryResFile(resfile, idx, rsz, NULL, 2652);
469 if (idx == 87) {
470 return tryResFile(resfile, idx, rsz, NULL, 588);
473 if (idx == 88) {
474 return tryResFile(resfile, idx, rsz, NULL, 19796);
477 if (idx == 89) {
478 return tryResFile(resfile, idx, rsz, NULL, 620);
481 if (idx == 90) {
482 return tryResFile(resfile, idx, rsz, NULL, 44940);
485 if (idx == 91) {
486 return tryResFile(resfile, idx, rsz, NULL, 9441);
489 if (idx == 92) {
490 return tryResFile(resfile, idx, rsz, unpackBINFont, 256*8);
493 if (datfirst) res = loadDiskFile(idx, rsz);
495 return res;