2 #define _POSIX_C_SOURCE 200809L
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,
76 /* 0, 0, 72, 80, 96 -- actual values but bad to use these! */
79 static int ramsize_table
[256] =
82 4 /* FIXME - what value should this be?! */
87 static char *sramfile
;
89 static char *saveprefix
;
91 static char *savename
;
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
)
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
)
117 byte
*d
= 0, buf
[512];
121 c
= fread(buf
, 1, sizeof buf
, f
);
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
)
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
) {
150 inf_pos
= inf_len
= 0;
151 if (unzip(data
, &pos
, inflate_callback
) < 0)
157 static void write_dec(byte
*data
, int len
) {
159 for(i
=0; i
< len
; i
++)
160 inflate_callback(data
[i
]);
163 static int unxz(byte
*data
, int len
) {
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);
181 b
.out_size
= sizeof(out
);
184 ret
= xz_dec_run(s
, &b
);
185 if(b
.out_pos
== sizeof(out
)) {
186 write_dec(out
, sizeof(out
));
190 if(ret
== XZ_OK
) continue;
192 write_dec(out
, b
.out_pos
);
194 if(ret
== XZ_STREAM_END
) {
206 static byte
*do_unxz(byte
*data
, int *len
) {
210 inf_pos
= inf_len
= 0;
211 if (unxz(data
, *len
) < 0)
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
);
230 byte c
, *data
, *header
;
233 if (strcmp(romfile
, "-")) f
= fopen(romfile
, "rb");
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;
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);
268 hw
.cgb
= ((c
== 0x80) || (c
== 0xc0)) && !forcedmg
;
269 hw
.gba
= (hw
.cgb
&& gbamode
);
271 if (strcmp(romfile
, "-")) fclose(f
);
280 if (!mbc
.batt
|| !sramfile
|| !*sramfile
) return -1;
282 /* Consider sram loaded at this point, even if file doesn't exist */
285 f
= fopen(sramfile
, "rb");
287 fread(ram
.sbank
, 8192, mbc
.ramsize
, f
);
298 /* If we crash before we ever loaded sram, DO NOT SAVE! */
299 if (!mbc
.batt
|| !sramfile
|| !ram
.loaded
|| !mbc
.ramsize
)
302 f
= fopen(sramfile
, "wb");
304 fwrite(ram
.sbank
, 8192, mbc
.ramsize
, f
);
311 void state_save(int n
)
316 if (n
< 0) n
= saveslot
;
318 name
= malloc(strlen(saveprefix
) + 5);
319 sprintf(name
, "%s.%03d", saveprefix
, n
);
321 if ((f
= fopen(name
, "wb")))
330 void state_load(int n
)
335 if (n
< 0) n
= saveslot
;
337 name
= malloc(strlen(saveprefix
) + 5);
338 sprintf(name
, "%s.%03d", saveprefix
, n
);
340 if ((f
= fopen(name
, "rb")))
355 if (!rtc
.batt
) return;
356 if (!(f
= fopen(rtcfile
, "wb"))) return;
357 rtc_save_internal(f
);
364 if (!rtc
.batt
) return;
365 if (!(f
= fopen(rtcfile
, "r"))) return;
366 rtc_load_internal(f
);
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;
382 mbc
.type
= mbc
.romsize
= mbc
.ramsize
= mbc
.batt
= 0;
385 static char *base(char *s
)
393 static char *ldup(char *s
)
397 p
= n
= malloc(strlen(s
));
398 for (i
= 0; s
[i
]; i
++) if (isalnum(s
[i
])) *(p
++) = tolower(s
[i
]);
403 static void cleanup()
407 /* IDEA - if error, write emergency savestate..? */
410 void loader_init(char *s
)
414 sys_checkdir(savedir
, 1); /* needs to be writable */
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
, '.');
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");
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
),