add SDL2 audio backend
[rofl0r-gnuboy.git] / loader.c
blobcc1921b386dce1b950f3e42a991a78370822c65b
1 #undef _POSIX_C_SOURCE
2 #define _POSIX_C_SOURCE 200809L
3 #undef _GNU_SOURCE
4 #define _GNU_SOURCE
5 #include <string.h>
7 #include <stdio.h>
8 #include <stdlib.h>
9 #include <ctype.h>
10 #include <time.h>
12 #include "defs.h"
13 #include "regs.h"
14 #include "mem.h"
15 #include "hw.h"
16 #include "rtc.h"
17 #include "rc.h"
18 #include "lcd.h"
19 #include "inflate.h"
20 #define XZ_USE_CRC64
21 #include "xz/xz.h"
22 #include "save.h"
23 #include "sound.h"
24 #include "sys.h"
26 static int mbc_table[256] =
28 0, 1, 1, 1, 0, 2, 2, 0, 0, 0, 0, 0, 0, 0, 0, 3,
29 3, 3, 3, 3, 0, 0, 0, 0, 0, 5, 5, 5, MBC_RUMBLE, MBC_RUMBLE, MBC_RUMBLE, 0,
30 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
31 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
33 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
34 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
35 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
36 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
38 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
39 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
40 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
41 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
43 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
44 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
45 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
46 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, MBC_HUC3, MBC_HUC1
49 static int rtc_table[256] =
51 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1,
52 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
56 static int batt_table[256] =
58 0, 0, 0, 1, 0, 0, 1, 0, 0, 1, 0, 0, 0, 1, 0, 0,
59 1, 0, 1, 1, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1, 0,
63 static int romsize_table[256] =
65 2, 4, 8, 16, 32, 64, 128, 256, 512,
66 0, 0, 0, 0, 0, 0, 0, 0,
67 0, 0, 0, 0, 0, 0, 0, 0,
68 0, 0, 0, 0, 0, 0, 0, 0,
69 0, 0, 0, 0, 0, 0, 0, 0,
70 0, 0, 0, 0, 0, 0, 0, 0,
71 0, 0, 0, 0, 0, 0, 0, 0,
72 0, 0, 0, 0, 0, 0, 0, 0,
73 0, 0, 0, 0, 0, 0, 0, 0,
74 0, 0, 0, 0, 0, 0, 0, 0,
75 0, 0, 128, 128, 128
76 /* 0, 0, 72, 80, 96 -- actual values but bad to use these! */
79 static int ramsize_table[256] =
81 1, 1, 1, 4, 16,
82 4 /* FIXME - what value should this be?! */
86 static char *romfile;
87 static char *sramfile;
88 static char *rtcfile;
89 static char *saveprefix;
91 static char *savename;
92 static char *savedir;
94 static int saveslot;
96 static int forcebatt, nobatt;
97 static int forcedmg, gbamode;
99 static int memfill = -1, memrand = -1;
102 static void initmem(void *mem, int size)
104 char *p = mem;
105 if (memrand >= 0)
107 srand(memrand ? memrand : time(0));
108 while(size--) *(p++) = rand();
110 else if (memfill >= 0)
111 memset(p, memfill, size);
114 static byte *loadfile(FILE *f, int *len)
116 int c, l = 0, p = 0;
117 byte *d = 0, buf[512];
119 for(;;)
121 c = fread(buf, 1, sizeof buf, f);
122 if (c <= 0) break;
123 l += c;
124 d = realloc(d, l);
125 if (!d) return 0;
126 memcpy(d+p, buf, c);
127 p += c;
129 *len = l;
130 return d;
133 static byte *inf_buf;
134 static int inf_pos, inf_len;
136 static void inflate_callback(byte b)
138 if (inf_pos >= inf_len)
140 inf_len += 512;
141 inf_buf = realloc(inf_buf, inf_len);
142 if (!inf_buf) die("out of memory inflating file @ %d bytes\n", inf_pos);
144 inf_buf[inf_pos++] = b;
147 static byte *gunzip(byte *data, int *len) {
148 long pos = 0;
149 inf_buf = 0;
150 inf_pos = inf_len = 0;
151 if (unzip(data, &pos, inflate_callback) < 0)
152 return data;
153 *len = inf_pos;
154 return inf_buf;
157 static void write_dec(byte *data, int len) {
158 int i;
159 for(i=0; i < len; i++)
160 inflate_callback(data[i]);
163 static int unxz(byte *data, int len) {
164 struct xz_buf b;
165 struct xz_dec *s;
166 enum xz_ret ret;
167 unsigned char out[4096];
170 * Support up to 64 MiB dictionary. The actually needed memory
171 * is allocated once the headers have been parsed.
173 s = xz_dec_init(XZ_DYNALLOC, 1 << 26);
174 if(!s) goto err;
176 b.in = data;
177 b.in_pos = 0;
178 b.in_size = len;
179 b.out = out;
180 b.out_pos = 0;
181 b.out_size = sizeof(out);
183 while (1) {
184 ret = xz_dec_run(s, &b);
185 if(b.out_pos == sizeof(out)) {
186 write_dec(out, sizeof(out));
187 b.out_pos = 0;
190 if(ret == XZ_OK) continue;
192 write_dec(out, b.out_pos);
194 if(ret == XZ_STREAM_END) {
195 xz_dec_end(s);
196 return 0;
198 goto err;
201 err:
202 xz_dec_end(s);
203 return -1;
206 static byte *do_unxz(byte *data, int *len) {
207 xz_crc32_init();
208 xz_crc64_init();
209 inf_buf = 0;
210 inf_pos = inf_len = 0;
211 if (unxz(data, *len) < 0)
212 return data;
213 *len = inf_pos;
214 return inf_buf;
217 static byte *decompress(byte *data, int *len)
219 if (data[0] == 0x1f && data[1] == 0x8b)
220 return gunzip(data, len);
221 if(data[0] == 0xFD && !memcmp(data+1, "7zXZ", 4))
222 return do_unxz(data, len);
223 return data;
227 int rom_load()
229 FILE *f;
230 byte c, *data, *header;
231 int len = 0, rlen;
233 if (strcmp(romfile, "-")) f = fopen(romfile, "rb");
234 else f = stdin;
235 if (!f) die("cannot open rom file: %s\n", romfile);
237 data = loadfile(f, &len);
238 header = data = decompress(data, &len);
240 memcpy(rom.name, header+0x0134, 16);
241 if (rom.name[14] & 0x80) rom.name[14] = 0;
242 if (rom.name[15] & 0x80) rom.name[15] = 0;
243 rom.name[16] = 0;
245 c = header[0x0147];
246 mbc.type = mbc_table[c];
247 mbc.batt = (batt_table[c] && !nobatt) || forcebatt;
248 rtc.batt = rtc_table[c];
249 mbc.romsize = romsize_table[header[0x0148]];
250 mbc.ramsize = ramsize_table[header[0x0149]];
252 if (!mbc.romsize) die("unknown ROM size %02X\n", header[0x0148]);
253 if (!mbc.ramsize) die("unknown SRAM size %02X\n", header[0x0149]);
255 rlen = 16384 * mbc.romsize;
256 rom.bank = realloc(data, rlen);
257 if (rlen > len) memset(rom.bank[0]+len, 0xff, rlen - len);
259 ram.sbank = malloc(8192 * mbc.ramsize);
261 initmem(ram.sbank, 8192 * mbc.ramsize);
262 initmem(ram.ibank, 4096 * 8);
264 mbc.rombank = 1;
265 mbc.rambank = 0;
267 c = header[0x0143];
268 hw.cgb = ((c == 0x80) || (c == 0xc0)) && !forcedmg;
269 hw.gba = (hw.cgb && gbamode);
271 if (strcmp(romfile, "-")) fclose(f);
273 return 0;
276 int sram_load()
278 FILE *f;
280 if (!mbc.batt || !sramfile || !*sramfile) return -1;
282 /* Consider sram loaded at this point, even if file doesn't exist */
283 ram.loaded = 1;
285 f = fopen(sramfile, "rb");
286 if (!f) return -1;
287 fread(ram.sbank, 8192, mbc.ramsize, f);
288 fclose(f);
290 return 0;
294 int sram_save()
296 FILE *f;
298 /* If we crash before we ever loaded sram, DO NOT SAVE! */
299 if (!mbc.batt || !sramfile || !ram.loaded || !mbc.ramsize)
300 return -1;
302 f = fopen(sramfile, "wb");
303 if (!f) return -1;
304 fwrite(ram.sbank, 8192, mbc.ramsize, f);
305 fclose(f);
307 return 0;
311 void state_save(int n)
313 FILE *f;
314 char *name;
316 if (n < 0) n = saveslot;
317 if (n < 0) n = 0;
318 name = malloc(strlen(saveprefix) + 5);
319 sprintf(name, "%s.%03d", saveprefix, n);
321 if ((f = fopen(name, "wb")))
323 savestate(f);
324 fclose(f);
326 free(name);
330 void state_load(int n)
332 FILE *f;
333 char *name;
335 if (n < 0) n = saveslot;
336 if (n < 0) n = 0;
337 name = malloc(strlen(saveprefix) + 5);
338 sprintf(name, "%s.%03d", saveprefix, n);
340 if ((f = fopen(name, "rb")))
342 loadstate(f);
343 fclose(f);
344 vram_dirty();
345 pal_dirty();
346 sound_dirty();
347 mem_updatemap();
349 free(name);
352 void rtc_save()
354 FILE *f;
355 if (!rtc.batt) return;
356 if (!(f = fopen(rtcfile, "wb"))) return;
357 rtc_save_internal(f);
358 fclose(f);
361 void rtc_load()
363 FILE *f;
364 if (!rtc.batt) return;
365 if (!(f = fopen(rtcfile, "r"))) return;
366 rtc_load_internal(f);
367 fclose(f);
371 void loader_unload()
373 sram_save();
374 if (romfile) free(romfile);
375 if (sramfile) free(sramfile);
376 if (saveprefix) free(saveprefix);
377 if (rom.bank) free(rom.bank);
378 if (ram.sbank) free(ram.sbank);
379 romfile = sramfile = saveprefix = 0;
380 rom.bank = 0;
381 ram.sbank = 0;
382 mbc.type = mbc.romsize = mbc.ramsize = mbc.batt = 0;
385 static char *base(char *s)
387 char *p;
388 p = strrchr(s, '/');
389 if (p) return p+1;
390 return s;
393 static char *ldup(char *s)
395 int i;
396 char *n, *p;
397 p = n = malloc(strlen(s));
398 for (i = 0; s[i]; i++) if (isalnum(s[i])) *(p++) = tolower(s[i]);
399 *p = 0;
400 return n;
403 static void cleanup()
405 sram_save();
406 rtc_save();
407 /* IDEA - if error, write emergency savestate..? */
410 void loader_init(char *s)
412 char *name, *p;
414 sys_checkdir(savedir, 1); /* needs to be writable */
416 romfile = s;
417 rom_load();
418 vid_settitle(rom.name);
419 if (savename && *savename)
421 if (savename[0] == '-' && savename[1] == 0)
422 name = ldup(rom.name);
423 else name = strdup(savename);
425 else if (romfile && *base(romfile) && strcmp(romfile, "-"))
427 name = strdup(base(romfile));
428 p = strchr(name, '.');
429 if (p) *p = 0;
431 else name = ldup(rom.name);
433 saveprefix = malloc(strlen(savedir) + strlen(name) + 2);
434 sprintf(saveprefix, "%s/%s", savedir, name);
436 sramfile = malloc(strlen(saveprefix) + 5);
437 strcpy(sramfile, saveprefix);
438 strcat(sramfile, ".sav");
440 rtcfile = malloc(strlen(saveprefix) + 5);
441 strcpy(rtcfile, saveprefix);
442 strcat(rtcfile, ".rtc");
444 sram_load();
445 rtc_load();
447 atexit(cleanup);
450 rcvar_t loader_exports[] =
452 RCV_STRING("savedir", &savedir),
453 RCV_STRING("savename", &savename),
454 RCV_INT("saveslot", &saveslot),
455 RCV_BOOL("forcebatt", &forcebatt),
456 RCV_BOOL("nobatt", &nobatt),
457 RCV_BOOL("forcedmg", &forcedmg),
458 RCV_BOOL("gbamode", &gbamode),
459 RCV_INT("memfill", &memfill),
460 RCV_INT("memrand", &memrand),
461 RCV_END