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");
73 static const char *getHomeDir (void) {
74 static char homeDir
[8192];
75 static int inited
= 0;
79 const char *h
= getenv("HOME");
81 strcpy(homeDir
, (h
&& h
[0]) ? h
: ".");
82 strcat(homeDir
, "/.local/awish/data");
94 int initResFile (ResFile
*resfile
, const char *fname
) {
97 FILE *fl
= fopen(fname
, "rb");
101 if (!resfile
) goto quit
;
102 memset(resfile
, 0, sizeof(resfile
));
104 if (fread(sign
, 3, 1, fl
) != 1) goto quit
;
105 if (memcmp(sign
, "RES", 3) != 0) goto quit
;
106 if (fread(&fcnt
, 1, 1, fl
) != 1) goto quit
;
107 if (fcnt
!= 93) goto quit
;
110 resfile
->count
= fcnt
;
112 if ((resfile
->offsets
= malloc(4*resfile
->count
)) == NULL
) goto quit
;
113 if ((resfile
->sizes
= malloc(4*resfile
->count
)) == NULL
) goto quit
;
115 if (fread(resfile
->offsets
, 4*resfile
->count
, 1, fl
) != 1) goto quit
;
116 #if SDL_BYTEORDER == SDL_BIG_ENDIAN
117 for (int f
= 0; f
< resfile
->count
; ++f
) resfile
->offsets
[f
] = SDL_SwapLE32(resfile
->offsets
[f
]);
119 if (fseek(fl
, 0, SEEK_END
) != 0) goto quit
;
121 for (int f
= 0; f
< resfile
->count
-1; ++f
) resfile
->sizes
[f
] = resfile
->offsets
[f
+1]-resfile
->offsets
[f
];
122 resfile
->sizes
[resfile
->count
-1] = sz
-resfile
->offsets
[resfile
->count
-1];
129 if (resfile
->sizes
) free(resfile
->sizes
);
130 if (resfile
->offsets
) free(resfile
->offsets
);
131 memset(resfile
, 0, sizeof(resfile
));
137 void deinitResFile (ResFile
*resfile
) {
139 if (resfile
->fl
) fclose(resfile
->fl
);
140 if (resfile
->sizes
) free(resfile
->sizes
);
141 if (resfile
->offsets
) free(resfile
->offsets
);
142 memset(resfile
, 0, sizeof(resfile
));
147 typedef int (*UnpackCB
) (unsigned char *dest
, const unsigned char *data
, int size
);
150 static int unpackFNTFont (unsigned char *dest
, const unsigned char *data
, int size
) {
154 memset(dest
, 0, 256*8);
155 if (size
< 6) goto quit
;
156 if (memcmp(data
, "FNT0", 4) != 0) goto quit
;
159 if (fc
> lc
) goto quit
;
161 for (int f
= fc
; f
<= lc
; ++f
) {
162 if (pos
+8 > size
) goto quit
;
163 memcpy(dest
+f
*8, data
+pos
, 8);
168 memset(dest
, 0, 256*8);
173 static int unpackBINFont (unsigned char *dest
, const unsigned char *data
, int size
) {
174 memset(dest
, 0, 256*8);
175 if (size
< 90*8) return -1;
176 memcpy(dest
+33*8, data
, 90*8);
181 static int unpackVPI (unsigned char *dest
, const unsigned char *data
, int size
) {
182 if (size
>= 320*200) {
183 memcpy(dest
, data
, 320*200);
185 int pos
= 0; // in packed
186 int opos
= 0; // in unpacked
187 int cpos
= 0; // meaningless here (position of colormap)
189 while (opos
< 320*200 && pos
+2 <= size
) {
190 int csz
= ((uint32_t)(data
[pos
]))+256*((uint32_t)(data
[pos
+1])); // picture chunk size
192 cpos
= (pos
+= 2); // colormap
193 pos
+= 512; // skip colormap
194 while (opos
< 320*200 && pos
< size
&& csz
> 0) {
195 int idx
= data
[pos
++];
197 dest
[opos
++] = data
[cpos
+idx
*2+0];
198 dest
[opos
++] = data
[cpos
+idx
*2+1];
207 uint8_t *tryDiskFile (const char *fname
, int *rsz
) {
208 FILE *fl
= fopen(fname
, "rb");
213 if (fl
== NULL
) return NULL
;
214 if (goobers
) fprintf(stderr
, "trying disk resource: '%s'\n", fname
);
215 if (fseek(fl
, 0, SEEK_END
) != 0) goto quit
;
218 if (size
< 0) goto quit
;
220 res
= calloc(1, size
+16);
221 if (res
== NULL
) goto quit
;
222 if (fread(res
, size
, 1, fl
) != 1) goto quit
;
224 if (size
>= 18 && rnc_sign(res
)) {
229 ulen
= rnc_ulen(res
);
230 if (ulen
< 1) goto quit
;
231 udata
= malloc(ulen
+16);
232 if (udata
== NULL
) goto quit
;
233 uplen
= rnc_unpack(res
, udata
, NULL
);
236 if (goobers
) fprintf(stderr
, "RNC: %d -> %d (%d)\n", (int)size
, ulen
, uplen
);
237 if (uplen
!= ulen
) goto quit
;
246 if (res
!= NULL
) { free(res
); res
= NULL
; }
248 if (res
!= NULL
&& rsz
) *rsz
= size
;
254 static uint8_t *tryDiskFileEx (const char *fname
, int *rsz
, UnpackCB unp
, int destsize
) {
258 if ((res
= tryDiskFile(fname
, &sz
)) == NULL
) return NULL
;
261 if (destsize
>= 0 && sz
< destsize
) { free(res
); return NULL
; }
264 if (destsize
< 0) { free(res
); return NULL
; }
265 if ((up
= calloc(1, destsize
+16)) == NULL
) { free(res
); return NULL
; }
266 if (unp(up
, res
, sz
) != 0) { free(up
); free(res
); return NULL
; }
276 #define TRY_FILE(upk,usz,fmt,srcdir,...) do { \
277 sprintf(fname, (fmt), (srcdir), __VA_ARGS__); \
278 if ((res = tryDiskFileEx(fname, rsz, (upk), (usz))) != NULL) return res; \
284 #define TRY_FILES(upk,usz,fmt,...) do { \
285 TRY_FILE((upk), (usz), "%s/" fmt, getHomeDir(), __VA_ARGS__); \
286 TRY_FILE((upk), (usz), "%s/" fmt, getMyDir(), __VA_ARGS__); \
287 TRY_FILE((upk), (usz), "%s/" fmt, DATA_DIR, __VA_ARGS__); \
292 #define TRY_FILES(upk,usz,fmt,...) do { \
293 TRY_FILE((upk), (usz), "%s/" fmt, getMyDir(), __VA_ARGS__); \
299 static uint8_t *tryLocalCodeFile (int *rsz
) {
300 static char fname
[512];
303 strcpy(fname
, getMyDir());
304 t
= strrchr(fname
, '/');
306 strcat(fname
, "/awish.vmd");
307 return tryDiskFileEx(fname
, rsz
, NULL
, 8);
311 static uint8_t *loadDiskFile (int idx
, int *rsz
) {
312 static char fname
[512];
316 if (idx
< 0) return NULL
;
318 if (idx
>= 0 && idx
<= 6) {
319 TRY_FILES(unpackVPI
, 64000, "pics/back%02d.vpi", idx
+1);
324 TRY_FILES(unpackVPI
, 64000, "pics/title.vpi%s", "");
329 TRY_FILES(unpackVPI
, 64000, "pics/interback.vpi%s", "");
333 if (idx
>= 9 && idx
<= 82) {
334 TRY_FILES(NULL
, 3700, "maps/level%02d.lvl", idx
-8);
339 TRY_FILES(NULL
, 768, "pics/palette.vga%s", "");
344 TRY_FILES(NULL
, 50568, "sprites/professor.spr%s", "");
349 TRY_FILES(NULL
, 3468, "sprites/fgtiles.spr%s", "");
354 TRY_FILES(NULL
, 2652, "sprites/bgtiles.spr%s", "");
359 TRY_FILES(NULL
, 588, "sprites/maptiles.spr%s", "");
364 TRY_FILES(NULL
, 19796, "sprites/items.spr%s", "");
369 TRY_FILES(NULL
, 620, "sprites/mapitems.spr%s", "");
374 TRY_FILES(NULL
, 44940, "sprites/professorim.spr%s", "");
379 TRY_FILES(NULL
, 9441, "sprites/himenu.spr%s", "");
384 TRY_FILES(unpackFNTFont
, 256*8, "fonts/namco.fnt%s", "");
385 TRY_FILES(unpackFNTFont
, 256*8, "fonts/font.fnt%s", "");
386 TRY_FILES(unpackBINFont
, 256*8, "fonts/font.bin%s", "");
390 if (idx
== 666 || idx
== 93) {
392 if ((res
= tryLocalCodeFile(rsz
)) != NULL
) return res
;
395 TRY_FILES(NULL
, 8, "code/awish.vmd%s", "");
398 if ((res
= tryLocalCodeFile(rsz
)) != NULL
) return res
;
406 static uint8_t *tryResFile (ResFile
*resfile
, int idx
, int *rsz
, UnpackCB unp
, int destsize
) {
407 uint8_t *res
= NULL
, *up
;
411 if (!resfile
|| !resfile
->fl
|| idx
< 0 || idx
>= resfile
->count
) return NULL
;
413 if (goobers
) fprintf(stderr
, "trying RES resource: %d\n", idx
);
414 //fprintf(stderr, "idx=%d; ofs=%u; size=%u\n", idx, resfile->offsets[idx], resfile->sizes[idx]);
415 size
= resfile
->sizes
[idx
];
416 if (fseek(resfile
->fl
, resfile
->offsets
[idx
], SEEK_SET
) != 0) return NULL
;
417 if ((res
= (uint8_t *)calloc(1, size
+16)) == NULL
) return NULL
;
419 if (fread(res
, size
, 1, resfile
->fl
) != 1) { free(res
); return NULL
; }
422 if (size
>= 18 && rnc_sign(res
)) {
427 ulen
= rnc_ulen(res
);
428 if (ulen
< 1) { free(res
); return NULL
; }
429 udata
= malloc(ulen
+16);
430 if (udata
== NULL
) { free(res
); return NULL
; }
431 uplen
= rnc_unpack(res
, udata
, NULL
);
434 if (uplen
!= ulen
) { free(res
); return NULL
; }
439 if (destsize
>= 0 && size
< destsize
) { free(res
); return NULL
; }
441 if (destsize
< 0) { free(res
); return NULL
; }
442 if ((up
= calloc(1, destsize
+16)) == NULL
) { free(res
); return NULL
; }
443 if (unp(up
, res
, size
) != 0) { free(up
); free(res
); return NULL
; }
449 if (rsz
) *rsz
= size
;
454 uint8_t *loadResFile (ResFile
*resfile
, int idx
, int *rsz
) {
457 if (!datfirst
) res
= loadDiskFile(idx
, rsz
);
459 if (res
!= NULL
|| resfile
== NULL
) return res
;
461 if (idx
>= 0 && idx
<= 8) {
462 return tryResFile(resfile
, idx
, rsz
, (resfile
->sizes
[idx
] < 320*200) ? unpackVPI
: NULL
, 320*200);
465 if (idx
>= 9 && idx
<= 82) {
466 return tryResFile(resfile
, idx
, rsz
, NULL
, 3700);
470 return tryResFile(resfile
, idx
, rsz
, NULL
, 768);
474 return tryResFile(resfile
, idx
, rsz
, NULL
, 50568);
478 return tryResFile(resfile
, idx
, rsz
, NULL
, 3468);
482 return tryResFile(resfile
, idx
, rsz
, NULL
, 2652);
486 return tryResFile(resfile
, idx
, rsz
, NULL
, 588);
490 return tryResFile(resfile
, idx
, rsz
, NULL
, 19796);
494 return tryResFile(resfile
, idx
, rsz
, NULL
, 620);
498 return tryResFile(resfile
, idx
, rsz
, NULL
, 44940);
502 return tryResFile(resfile
, idx
, rsz
, NULL
, 9441);
506 return tryResFile(resfile
, idx
, rsz
, unpackBINFont
, 256*8);
509 if (datfirst
) res
= loadDiskFile(idx
, rsz
);