2 * This program is free software: you can redistribute it and/or modify
3 * it under the terms of the GNU General Public License as published by
4 * the Free Software Foundation, either version 3 of the License, or
5 * (at your option) any later version.
7 * This program is distributed in the hope that it will be useful,
8 * but WITHOUT ANY WARRANTY; without even the implied warranty of
9 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
10 * GNU General Public License for more details.
12 * You should have received a copy of the GNU General Public License
13 * along with this program. If not, see <http://www.gnu.org/licenses/>.
22 #include <sys/types.h>
24 #include "librnc/librnc.h"
30 # define DATA_DIR "/usr/local/share/awish"
38 static const char *getMyDir (void) {
39 static char myDir
[8192];
40 static int inited
= 0;
47 sprintf(buf
, "/proc/%u/exe", (unsigned int)pid
);
48 if (readlink(buf
, myDir
, sizeof(myDir
)-1) < 0) {
51 char *p
= (char *)strrchr(myDir
, '/');
53 if (!p
) strcpy(myDir
, "."); else *p
= '\0';
55 strcat(myDir
, "/data");
59 memset(myDir
, 0, sizeof(myDir
));
60 GetModuleFileName(GetModuleHandle(NULL
), myDir
, sizeof(myDir
)-1);
61 for (p
= myDir
; *p
; ++p
) if (*p
== '/') *p
= '\\';
62 p
= strrchr(myDir
, '\\');
63 if (!p
) strcpy(myDir
, "."); else *p
= '\0';
64 strcat(myDir
, "\\data");
65 for (p
= myDir
; *p
; ++p
) if (*p
== '\\') *p
= '/';
74 static const char *getHomeDir (void) {
75 static char homeDir
[8192];
76 static int inited
= 0;
80 const char *h
= getenv("HOME");
82 strcpy(homeDir
, (h
&& h
[0]) ? h
: ".");
83 strcat(homeDir
, "/.local/awish/data");
87 for (char *p
= myDir
; *p
; ++p
) if (*p
== '\\') *p
= '/';
96 static int tryInitResFile (ResFile
*resfile
, const char *fname
) {
100 FILE *fl
= fopen(fname
, "rb");
104 if (!resfile
) goto quit
;
105 memset(resfile
, 0, sizeof(resfile
));
107 if (fread(sign
, 3, 1, fl
) != 1) goto quit
;
108 if (memcmp(sign
, "RES", 3) != 0) goto quit
;
109 if (fread(&fcnt
, 1, 1, fl
) != 1) goto quit
;
110 if (fcnt
< 93) goto quit
;
113 resfile
->count
= fcnt
;
115 if ((resfile
->offsets
= malloc(4*resfile
->count
)) == NULL
) goto quit
;
116 if ((resfile
->sizes
= malloc(4*resfile
->count
)) == NULL
) goto quit
;
118 if (fread(resfile
->offsets
, 4*resfile
->count
, 1, fl
) != 1) goto quit
;
119 #if SDL_BYTEORDER == SDL_BIG_ENDIAN
120 for (int f
= 0; f
< resfile
->count
; ++f
) resfile
->offsets
[f
] = SDL_SwapLE32(resfile
->offsets
[f
]);
122 if (fseek(fl
, 0, SEEK_END
) != 0) goto quit
;
124 for (int f
= 0; f
< resfile
->count
-1; ++f
) resfile
->sizes
[f
] = resfile
->offsets
[f
+1]-resfile
->offsets
[f
];
125 resfile
->sizes
[resfile
->count
-1] = sz
-resfile
->offsets
[resfile
->count
-1];
132 if (resfile
->sizes
) free(resfile
->sizes
);
133 if (resfile
->offsets
) free(resfile
->offsets
);
134 memset(resfile
, 0, sizeof(resfile
));
140 int initResFile (ResFile
*resfile
, const char *rfname
) {
141 static char fname
[8192];
145 sprintf(fname
, "%s/%s", getHomeDir(), rfname
);
146 res
= tryInitResFile(resfile
, fname
);
149 sprintf(fname
, "%s/%s", getMyDir(), rfname
);
150 res
= tryInitResFile(resfile
, fname
);
154 sprintf(fname
, "%s/%s", DATA_DIR
, rfname
);
155 res
= tryInitResFile(resfile
, fname
);
161 strcpy(fname
, getMyDir());
162 t
= strrchr(fname
, '/');
164 strcat(fname
, rfname
);
165 res
= tryInitResFile(resfile
, fname
);
169 if (res
== 0) fprintf(stderr
, "using resource file '%s'\n", fname
);
170 else fprintf(stderr
, "can't find resource file '%s'\n", rfname
);
176 void deinitResFile (ResFile
*resfile
) {
178 if (resfile
->fl
) fclose(resfile
->fl
);
179 if (resfile
->sizes
) free(resfile
->sizes
);
180 if (resfile
->offsets
) free(resfile
->offsets
);
181 memset(resfile
, 0, sizeof(resfile
));
186 typedef int (*UnpackCB
) (unsigned char *dest
, const unsigned char *data
, int size
);
189 static int unpackFNTFont (unsigned char *dest
, const unsigned char *data
, int size
) {
193 memset(dest
, 0, 256*8);
194 if (size
< 6) goto quit
;
195 if (memcmp(data
, "FNT0", 4) != 0) goto quit
;
198 if (fc
> lc
) goto quit
;
200 for (int f
= fc
; f
<= lc
; ++f
) {
201 if (pos
+8 > size
) goto quit
;
202 memcpy(dest
+f
*8, data
+pos
, 8);
207 memset(dest
, 0, 256*8);
212 static int unpackBINFont (unsigned char *dest
, const unsigned char *data
, int size
) {
213 memset(dest
, 0, 256*8);
214 if (size
< 90*8) return -1;
215 memcpy(dest
+33*8, data
, 90*8);
220 static int unpackVPI (unsigned char *dest
, const unsigned char *data
, int size
) {
221 if (size
>= 320*200) {
222 memcpy(dest
, data
, 320*200);
224 int pos
= 0; // in packed
225 int opos
= 0; // in unpacked
226 int cpos
= 0; // meaningless here (position of colormap)
228 while (opos
< 320*200 && pos
+2 <= size
) {
229 int csz
= ((uint32_t)(data
[pos
]))+256*((uint32_t)(data
[pos
+1])); // picture chunk size
231 cpos
= (pos
+= 2); // colormap
232 pos
+= 512; // skip colormap
233 while (opos
< 320*200 && pos
< size
&& csz
> 0) {
234 int idx
= data
[pos
++];
236 dest
[opos
++] = data
[cpos
+idx
*2+0];
237 dest
[opos
++] = data
[cpos
+idx
*2+1];
246 uint8_t *tryDiskFile (const char *fname
, int *rsz
) {
247 FILE *fl
= fopen(fname
, "rb");
252 if (fl
== NULL
) return NULL
;
253 if (goobers
) fprintf(stderr
, "trying disk resource: '%s'\n", fname
);
254 if (fseek(fl
, 0, SEEK_END
) != 0) goto quit
;
257 if (size
< 0) goto quit
;
259 res
= calloc(1, size
+16);
260 if (res
== NULL
) goto quit
;
261 if (fread(res
, size
, 1, fl
) != 1) goto quit
;
263 if (size
>= 18 && rnc_sign(res
)) {
268 ulen
= rnc_ulen(res
);
269 if (ulen
< 1) goto quit
;
270 udata
= malloc(ulen
+16);
271 if (udata
== NULL
) goto quit
;
272 uplen
= rnc_unpack(res
, udata
, NULL
);
275 //if (goobers) fprintf(stderr, "RNC: %d -> %d (%d)\n", (int)size, ulen, uplen);
276 if (uplen
!= ulen
) goto quit
;
285 if (res
!= NULL
) { free(res
); res
= NULL
; }
287 if (res
!= NULL
&& rsz
) *rsz
= size
;
293 static uint8_t *tryDiskFileEx (const char *fname
, int *rsz
, UnpackCB unp
, int destsize
) {
297 if ((res
= tryDiskFile(fname
, &sz
)) == NULL
) return NULL
;
300 if (destsize
>= 0 && sz
< destsize
) { free(res
); return NULL
; }
303 if (destsize
< 0) { free(res
); return NULL
; }
304 if ((up
= calloc(1, destsize
+16)) == NULL
) { free(res
); return NULL
; }
305 if (unp(up
, res
, sz
) != 0) { free(up
); free(res
); return NULL
; }
315 #define TRY_FILE(upk,usz,fmt,srcdir,...) do { \
316 sprintf(fname, (fmt), (srcdir), __VA_ARGS__); \
317 if ((res = tryDiskFileEx(fname, rsz, (upk), (usz))) != NULL) return res; \
323 #define TRY_FILES(upk,usz,fmt,...) do { \
324 TRY_FILE((upk), (usz), "%s/" fmt, getHomeDir(), __VA_ARGS__); \
325 TRY_FILE((upk), (usz), "%s/" fmt, getMyDir(), __VA_ARGS__); \
326 TRY_FILE((upk), (usz), "%s/" fmt, DATA_DIR, __VA_ARGS__); \
331 #define TRY_FILES(upk,usz,fmt,...) do { \
332 TRY_FILE((upk), (usz), "%s/" fmt, getMyDir(), __VA_ARGS__); \
338 static uint8_t *tryLocalCodeFile (int *rsz
) {
339 static char fname
[512];
342 strcpy(fname
, getMyDir());
343 t
= strrchr(fname
, '/');
345 strcat(fname
, "/awish.vmd");
346 return tryDiskFileEx(fname
, rsz
, NULL
, 8);
350 static uint8_t *loadDiskFile (int idx
, int *rsz
) {
351 static char fname
[512];
355 if (idx
< 0) return NULL
;
357 if (idx
>= 0 && idx
<= 6) {
358 TRY_FILES(unpackVPI
, 64000, "pics/back%02d.vpi", idx
+1);
363 TRY_FILES(unpackVPI
, 64000, "pics/title.vpi%s", "");
368 TRY_FILES(unpackVPI
, 64000, "pics/interback.vpi%s", "");
372 if (idx
>= 9 && idx
<= 82) {
373 TRY_FILES(NULL
, 3700, "maps/level%02d.lvl", idx
-8);
378 TRY_FILES(NULL
, 768, "pics/palette.vga%s", "");
383 TRY_FILES(NULL
, 50568, "sprites/professor.spr%s", "");
388 TRY_FILES(NULL
, 3468, "sprites/fgtiles.spr%s", "");
393 TRY_FILES(NULL
, 2652, "sprites/bgtiles.spr%s", "");
398 TRY_FILES(NULL
, 588, "sprites/maptiles.spr%s", "");
403 TRY_FILES(NULL
, 19796, "sprites/items.spr%s", "");
408 TRY_FILES(NULL
, 620, "sprites/mapitems.spr%s", "");
413 TRY_FILES(NULL
, 44940, "sprites/professorim.spr%s", "");
418 TRY_FILES(NULL
, 9441, "sprites/himenu.spr%s", "");
423 TRY_FILES(unpackFNTFont
, 256*8, "fonts/namco.fnt%s", "");
424 TRY_FILES(unpackFNTFont
, 256*8, "fonts/font.fnt%s", "");
425 TRY_FILES(unpackBINFont
, 256*8, "fonts/font.bin%s", "");
429 if (idx
== 666 || idx
== 93) {
431 if ((res
= tryLocalCodeFile(rsz
)) != NULL
) return res
;
434 TRY_FILES(NULL
, 8, "code/awish.vmd%s", "");
437 if ((res
= tryLocalCodeFile(rsz
)) != NULL
) return res
;
445 static uint8_t *tryResFile (ResFile
*resfile
, int idx
, int *rsz
, UnpackCB unp
, int destsize
) {
446 uint8_t *res
= NULL
, *up
;
450 if (!resfile
|| !resfile
->fl
|| idx
< 0 || idx
>= resfile
->count
) return NULL
;
452 if (goobers
) fprintf(stderr
, "trying RES resource: %d\n", idx
);
453 //fprintf(stderr, "idx=%d; ofs=%u; size=%u\n", idx, resfile->offsets[idx], resfile->sizes[idx]);
454 size
= resfile
->sizes
[idx
];
455 if (fseek(resfile
->fl
, resfile
->offsets
[idx
], SEEK_SET
) != 0) return NULL
;
456 if ((res
= (uint8_t *)calloc(1, size
+16)) == NULL
) return NULL
;
458 if (fread(res
, size
, 1, resfile
->fl
) != 1) { free(res
); return NULL
; }
461 if (size
>= 18 && rnc_sign(res
)) {
466 ulen
= rnc_ulen(res
);
467 if (ulen
< 1) { free(res
); return NULL
; }
468 udata
= malloc(ulen
+16);
469 if (udata
== NULL
) { free(res
); return NULL
; }
470 uplen
= rnc_unpack(res
, udata
, NULL
);
473 if (uplen
!= ulen
) { free(res
); return NULL
; }
478 if (destsize
>= 0 && size
< destsize
) { free(res
); return NULL
; }
480 if (destsize
< 0) { free(res
); return NULL
; }
481 if ((up
= calloc(1, destsize
+16)) == NULL
) { free(res
); return NULL
; }
482 if (unp(up
, res
, size
) != 0) { free(up
); free(res
); return NULL
; }
488 if (rsz
) *rsz
= size
;
493 uint8_t *loadResFile (ResFile
*resfile
, int idx
, int *rsz
) {
496 if (!datfirst
) res
= loadDiskFile(idx
, rsz
);
498 if (res
!= NULL
|| resfile
== NULL
) return res
;
500 if (idx
>= 0 && idx
< resfile
->count
) {
503 if (resfile
->sizes
[idx
] < 320*200) {
504 res
= tryResFile(resfile
, idx
, rsz
, unpackVPI
, 320*200);
506 res
= tryResFile(resfile
, idx
, rsz
, NULL
, 320*200);
510 res
= tryResFile(resfile
, idx
, rsz
, NULL
, 3700);
513 res
= tryResFile(resfile
, idx
, rsz
, NULL
, 768);
516 res
= tryResFile(resfile
, idx
, rsz
, NULL
, 50568);
519 res
= tryResFile(resfile
, idx
, rsz
, NULL
, 3468);
522 res
= tryResFile(resfile
, idx
, rsz
, NULL
, 2652);
525 res
= tryResFile(resfile
, idx
, rsz
, NULL
, 588);
528 res
= tryResFile(resfile
, idx
, rsz
, NULL
, 19796);
531 res
= tryResFile(resfile
, idx
, rsz
, NULL
, 620);
534 res
= tryResFile(resfile
, idx
, rsz
, NULL
, 44940);
537 res
= tryResFile(resfile
, idx
, rsz
, NULL
, 9441);
540 res
= tryResFile(resfile
, idx
, rsz
, unpackBINFont
, 256*8);
543 res
= tryResFile(resfile
, idx
, rsz
, NULL
, -1);
548 if (!res
&& datfirst
) res
= loadDiskFile(idx
, rsz
);