Move NULL core code to its own file
[lsnes.git] / src / core / rom.cpp
blob27a61aa6001d96b622666b5f2c27afa3279b0f65
1 #include "lsnes.hpp"
3 #include "core/advdumper.hpp"
4 #include "core/dispatch.hpp"
5 #include "core/framerate.hpp"
6 #include "core/instance.hpp"
7 #include "core/memorymanip.hpp"
8 #include "core/messages.hpp"
9 #include "core/nullcore.hpp"
10 #include "core/rom.hpp"
11 #include "core/settings.hpp"
12 #include "core/window.hpp"
13 #include "interface/callbacks.hpp"
14 #include "interface/cover.hpp"
15 #include "interface/romtype.hpp"
16 #include "library/portctrl-data.hpp"
17 #include "library/fileimage-patch.hpp"
18 #include "library/sha256.hpp"
19 #include "library/string.hpp"
20 #include "library/zip.hpp"
22 #include <stdexcept>
23 #include <sstream>
24 #include <iomanip>
25 #include <cstdint>
26 #include <set>
27 #include <boost/iostreams/categories.hpp>
28 #include <boost/iostreams/copy.hpp>
29 #include <boost/iostreams/stream.hpp>
30 #include <boost/iostreams/stream_buffer.hpp>
31 #include <boost/iostreams/filter/symmetric.hpp>
32 #include <boost/iostreams/filter/zlib.hpp>
33 #include <boost/iostreams/filtering_stream.hpp>
34 #include <boost/iostreams/device/back_inserter.hpp>
36 #ifdef USE_LIBGCRYPT_SHA256
37 #include <gcrypt.h>
38 #endif
40 namespace
42 settingvar::supervariable<settingvar::model_bool<settingvar::yes_no>> savestate_no_check(lsnes_setgrp,
43 "dont-check-savestate", "Movie‣Loading‣Don't check savestates", false);
45 core_type* current_rom_type = &get_null_type();
46 core_region* current_region = &get_null_region();
48 core_type* prompt_core_fallback(const std::vector<core_type*>& choices)
50 if(choices.size() == 0)
51 return NULL;
52 if(choices.size() == 1)
53 return choices[0];
54 rom_request req;
55 req.cores = choices;
56 req.core_guessed = false;
57 req.selected = 0;
58 //Tell that all ROMs have been correctly guessed, leaving only core select.
59 for(unsigned i = 0; i < ROM_SLOT_COUNT; i++) {
60 req.has_slot[i] = false;
61 req.guessed[i] = false;
63 req.canceled = false;
64 graphics_driver_request_rom(req);
65 if(req.canceled)
66 throw std::runtime_error("Canceled ROM loading");
67 if(req.selected < choices.size())
68 return choices[req.selected];
69 return choices[0];
72 core_type* find_core_by_extension(const std::string& ext, const std::string& tmpprefer)
74 std::string key = "ext:" + ext;
75 std::list<core_type*> possible = core_type::get_core_types();
76 core_type* preferred = preferred_core.count(key) ? preferred_core[key] : NULL;
77 std::vector<core_type*> fallbacks;
78 //Tmpprefer overrides normal preferred core.
79 if(tmpprefer != "")
80 for(auto i : possible)
81 if(i->get_core_identifier() == tmpprefer)
82 return i;
83 for(auto i : possible)
84 if(i->is_known_extension(ext)) {
85 fallbacks.push_back(i);
86 if(i == preferred)
87 return i;
89 core_type* fallback = prompt_core_fallback(fallbacks);
90 if(!fallback) throw std::runtime_error("No core available to load the ROM");
91 return fallback;
94 core_type* find_core_by_name(const std::string& name, const std::string& tmpprefer)
96 std::string key = "type:" + name;
97 std::list<core_type*> possible = core_type::get_core_types();
98 std::vector<core_type*> fallbacks;
99 core_type* preferred = preferred_core.count(key) ? preferred_core[key] : NULL;
100 //Tmpprefer overrides normal preferred core.
101 if(tmpprefer != "")
102 for(auto i : possible)
103 if(i->get_iname() == tmpprefer)
104 return i;
105 for(auto i : possible)
106 if(i->get_iname() == name) {
107 fallbacks.push_back(i);
108 if(i == preferred)
109 return i;
111 core_type* fallback = prompt_core_fallback(fallbacks);
112 if(!fallback) throw std::runtime_error("No core available to load the ROM");
113 return fallback;
116 struct fileimage::image::info get_xml_info()
118 fileimage::image::info i;
119 i.type = fileimage::image::info::IT_MARKUP;
120 i.headersize = 0;
121 return i;
124 struct fileimage::image::info xlate_info(core_romimage_info ri)
126 fileimage::image::info i;
127 if(ri.pass_mode == 0) i.type = fileimage::image::info::IT_MEMORY;
128 if(ri.pass_mode == 1) i.type = fileimage::image::info::IT_FILE;
129 i.headersize = ri.headersize;
130 return i;
133 void record_files(loaded_rom& rom)
135 for(unsigned i = 0; i < ROM_SLOT_COUNT; i++) {
136 try {
137 auto& j = rom.get_rom(i);
138 record_filehash(j.filename, j.stripped, j.sha_256.read());
139 } catch(...) {}
140 try {
141 auto& j = rom.get_markup(i);
142 record_filehash(j.filename, j.stripped, j.sha_256.read());
143 } catch(...) {}
148 fileimage::hash lsnes_image_hasher;
149 fileimage::image loaded_rom::null_img;
151 std::pair<core_type*, core_region*> get_current_rom_info() throw()
153 return std::make_pair(current_rom_type, current_region);
156 loaded_rom::loaded_rom() throw()
158 rtype = &get_null_type();
159 region = orig_region = &get_null_region();
162 loaded_rom::loaded_rom(const std::string& file, core_type& ctype) throw(std::bad_alloc, std::runtime_error)
164 rtype = &ctype;
165 region = orig_region = &rtype->get_preferred_region();
166 unsigned romidx = 0;
167 std::string bios;
168 unsigned pmand = 0, tmand = 0;
169 for(unsigned i = 0; i < ctype.get_image_count(); i++)
170 tmand |= ctype.get_image_info(i).mandatory;
171 if((bios = ctype.get_biosname()) != "") {
172 //This thing has a BIOS.
173 romidx = 1;
174 std::string basename = CORE().setcache->get("firmwarepath") + "/" + bios;
175 romimg[0] = fileimage::image(lsnes_image_hasher, basename, "", xlate_info(ctype.get_image_info(0)));
176 if(zip::file_exists(basename + ".xml"))
177 romxml[0] = fileimage::image(lsnes_image_hasher, basename + ".xml", "", get_xml_info());
178 pmand |= ctype.get_image_info(0).mandatory;
180 romimg[romidx] = fileimage::image(lsnes_image_hasher, file, "", xlate_info(ctype.get_image_info(romidx)));
181 if(zip::file_exists(file + ".xml"))
182 romxml[romidx] = fileimage::image(lsnes_image_hasher, file + ".xml", "", get_xml_info());
183 pmand |= ctype.get_image_info(romidx).mandatory;
184 msu1_base = zip::resolverel(file, "");
185 record_files(*this);
186 if(pmand != tmand)
187 throw std::runtime_error("Required ROM images missing");
188 return;
191 loaded_rom::loaded_rom(const std::string& file, const std::string& tmpprefer) throw(std::bad_alloc,
192 std::runtime_error)
194 std::istream& spec = zip::openrel(file, "");
195 std::string s;
196 std::getline(spec, s);
197 istrip_CR(s);
198 if(!spec || s != "[GAMEPACK FILE]") {
199 //This is a Raw ROM image.
200 regex_results tmp;
201 std::string ext = regex(".*\\.([^.]*)?", file, "Can't read file extension")[1];
202 core_type* coretype = find_core_by_extension(ext, tmpprefer);
203 if(!coretype)
204 (stringfmt() << "Extension '" << ext << "' unknown").throwex();
205 rtype = coretype;
206 region = orig_region = &rtype->get_preferred_region();
207 unsigned romidx = 0;
208 std::string bios;
209 unsigned pmand = 0, tmand = 0;
210 for(unsigned i = 0; i < rtype->get_image_count(); i++)
211 tmand |= rtype->get_image_info(i).mandatory;
212 if((bios = coretype->get_biosname()) != "") {
213 //This thing has a BIOS.
214 romidx = 1;
215 std::string basename = CORE().setcache->get("firmwarepath") + "/" + bios;
216 romimg[0] = fileimage::image(lsnes_image_hasher, basename, "",
217 xlate_info(coretype->get_image_info(0)));
218 if(zip::file_exists(basename + ".xml"))
219 romxml[0] = fileimage::image(lsnes_image_hasher, basename + ".xml", "",
220 get_xml_info());
221 pmand |= rtype->get_image_info(0).mandatory;
223 romimg[romidx] = fileimage::image(lsnes_image_hasher, file, "",
224 xlate_info(coretype->get_image_info(romidx)));
225 if(zip::file_exists(file + ".xml"))
226 romxml[romidx] = fileimage::image(lsnes_image_hasher, file + ".xml", "", get_xml_info());
227 pmand |= rtype->get_image_info(romidx).mandatory;
228 msu1_base = zip::resolverel(file, "");
229 record_files(*this);
230 if(pmand != tmand)
231 throw std::runtime_error("Required ROM images missing");
232 return;
234 load_bundle(file, spec, tmpprefer);
237 void loaded_rom::load_bundle(const std::string& file, std::istream& spec, const std::string& tmpprefer) throw(std::bad_alloc,
238 std::runtime_error)
240 std::string s;
241 load_filename = file;
242 std::vector<std::string> lines;
243 while(std::getline(spec, s))
244 lines.push_back(strip_CR(s));
245 std::string platname = "";
246 std::string platreg = "";
247 for(auto i : lines) {
248 regex_results tmp;
249 if(tmp = regex("type[ \t]+(.+)", i))
250 platname = tmp[1];
251 if(tmp = regex("region[ \t]+(.+)", i))
252 platreg = tmp[1];
255 //Detect type.
256 rtype = find_core_by_name(platname, tmpprefer);
257 if(!rtype)
258 (stringfmt() << "Not a valid system type '" << platname << "'").throwex();
260 //Detect region.
261 bool goodreg = false;
262 orig_region = &rtype->get_preferred_region();
263 for(auto i: rtype->get_regions())
264 if(i->get_iname() == platreg) {
265 orig_region = i;
266 goodreg = true;
268 if(!goodreg && platreg != "")
269 (stringfmt() << "Not a valid system region '" << platreg << "'").throwex();
270 region = orig_region;
272 //ROM files.
273 std::string cromimg[ROM_SLOT_COUNT];
274 std::string cromxml[ROM_SLOT_COUNT];
275 for(auto i : lines) {
276 regex_results tmp;
277 if(!(tmp = regex("(rom|xml)[ \t]+([^ \t]+)[ \t]+(.*)", i)))
278 continue;
279 size_t idxs = rtype->get_image_count();
280 size_t idx = idxs;
281 for(size_t i = 0; i < idxs; i++)
282 if(rtype->get_image_info(i).iname == tmp[2])
283 idx = i;
284 if(idx == idxs)
285 (stringfmt() << "Not a valid ROM name '" << tmp[2] << "'").throwex();
286 if(tmp[1] == "rom")
287 cromimg[idx] = tmp[3];
288 else
289 cromxml[idx] = tmp[3];
292 //Check ROMs.
293 unsigned mask1 = 0, mask2 = 0;
294 for(size_t i = 0; i < rtype->get_image_count(); i++) {
295 auto ii = rtype->get_image_info(i);
296 mask1 |= ii.mandatory;
297 if(cromimg[i] != "")
298 mask2 |= ii.mandatory;
299 if(cromimg[i] == "" && cromxml[i] != "") {
300 messages << "WARNING: Slot " << ii.iname << ": XML without ROM." << std::endl;
301 cromxml[i] = "";
304 if(mask1 != mask2)
305 throw std::runtime_error("Required ROM missing");
307 //Load ROMs.
308 for(size_t i = 0; i < rtype->get_image_count(); i++) {
309 romimg[i] = fileimage::image(lsnes_image_hasher, cromimg[i], file,
310 xlate_info(rtype->get_image_info(i)));
311 romxml[i] = fileimage::image(lsnes_image_hasher, cromxml[i], file, get_xml_info());
313 record_files(*this); //Have to do this before patching.
315 //Patch ROMs.
316 for(auto i : lines) {
317 regex_results tmp;
318 if(!(tmp = regex("patch([+-][0-9]+)?[ \t]+([^ \t]+)[ \t]+(.*)", i)))
319 continue;
320 size_t idxs = rtype->get_image_count();
321 size_t idx = idxs;
322 for(size_t i = 0; i < idxs; i++)
323 if(rtype->get_image_info(i).iname == tmp[2])
324 idx = i;
325 if(idx == idxs)
326 (stringfmt() << "Not a valid ROM name '" << tmp[2] << "'").throwex();
327 int32_t offset = 0;
328 if(tmp[1] != "")
329 offset = parse_value<int32_t>(tmp[1]);
330 romimg[idx].patch(zip::readrel(tmp[3], file), offset);
333 //MSU-1 base.
334 if(cromimg[1] != "")
335 msu1_base = zip::resolverel(cromimg[1], file);
336 else
337 msu1_base = zip::resolverel(cromimg[0], file);
340 namespace
342 bool filter_by_core(core_type& ctype, const std::string& core)
344 return (core == "" || ctype.get_core_identifier() == core);
347 bool filter_by_type(core_type& ctype, const std::string& type)
349 return (type == "" || ctype.get_iname() == type);
352 bool filter_by_region(core_type& ctype, const std::string& region)
354 if(region == "")
355 return true;
356 for(auto i : ctype.get_regions())
357 if(i->get_iname() == region)
358 return true;
359 return false;
362 bool filter_by_extension(core_type& ctype, const std::string& file)
364 regex_results tmp = regex(".*\\.([^.]*)", file);
365 if(!tmp)
366 return false;
367 std::string ext = tmp[1];
368 return ctype.is_known_extension(ext);
371 bool filter_by_fileset(core_type& ctype, const std::string file[ROM_SLOT_COUNT])
373 uint32_t m = 0, t = 0;
374 for(unsigned i = 0; i < ROM_SLOT_COUNT; i++) {
375 if(i >= ctype.get_image_count() && file[i] != "")
376 return false;
377 auto s = ctype.get_image_info(i);
378 if(file[i] != "")
379 m |= s.mandatory;
380 t |= s.mandatory;
382 return (m == t);
385 core_region* detect_region(core_type* t, const std::string& region)
387 core_region* r = NULL;
388 for(auto i: t->get_regions())
389 if(i->get_iname() == region)
390 r = i;
391 if(!r && region != "")
392 (stringfmt() << "Not a valid system region '" << region << "'").throwex();
393 if(!r) r = &t->get_preferred_region(); //Default region.
394 return r;
398 loaded_rom::loaded_rom(const std::string& file, const std::string& core, const std::string& type,
399 const std::string& _region)
401 core_type* t = NULL;
402 core_region* r = NULL;
403 bool fullspec = (core != "" && type != "");
404 for(auto i : core_type::get_core_types()) {
405 if(!filter_by_core(*i, core))
406 continue;
407 if(!filter_by_type(*i, type))
408 continue;
409 if(!fullspec && !filter_by_region(*i, _region))
410 continue;
411 if(!fullspec && !filter_by_extension(*i, file))
412 continue;
413 t = i;
415 if(!t) throw std::runtime_error("No matching core found");
416 r = detect_region(t, _region);
417 unsigned pmand = 0, tmand = 0;
418 for(unsigned i = 0; i < t->get_image_count(); i++)
419 tmand |= t->get_image_info(i).mandatory;
420 std::string bios = t->get_biosname();
421 unsigned romidx = (bios != "") ? 1 : 0;
422 if(bios != "") {
423 std::string basename = CORE().setcache->get("firmwarepath") + "/" + bios;
424 romimg[0] = fileimage::image(lsnes_image_hasher, basename, "", xlate_info(t->get_image_info(0)));
425 if(zip::file_exists(basename + ".xml"))
426 romxml[0] = fileimage::image(lsnes_image_hasher, basename + ".xml", "", get_xml_info());
427 pmand |= t->get_image_info(0).mandatory;
429 romimg[romidx] = fileimage::image(lsnes_image_hasher, file, "", xlate_info(t->get_image_info(romidx)));
430 if(zip::file_exists(file + ".xml"))
431 romxml[romidx] = fileimage::image(lsnes_image_hasher, file + ".xml", "", get_xml_info());
432 pmand |= t->get_image_info(romidx).mandatory;
433 msu1_base = zip::resolverel(file, "");
434 record_files(*this);
435 if(pmand != tmand)
436 throw std::runtime_error("Required ROM images missing");
437 rtype = t;
438 orig_region = region = r;
441 loaded_rom::loaded_rom(const std::string file[ROM_SLOT_COUNT], const std::string& core, const std::string& type,
442 const std::string& _region)
444 core_type* t = NULL;
445 core_region* r = NULL;
446 bool fullspec = (core != "" && type != "");
447 for(auto i : core_type::get_core_types()) {
448 if(!filter_by_core(*i, core)) {
449 continue;
451 if(!filter_by_type(*i, type)) {
452 continue;
454 if(!fullspec && !filter_by_region(*i, _region)) {
455 continue;
457 if(!fullspec && !filter_by_fileset(*i, file)) {
458 continue;
460 t = i;
462 if(!t) throw std::runtime_error("No matching core found");
463 r = detect_region(t, _region);
464 std::string bios = t->get_biosname();
465 unsigned romidx = (bios != "") ? 1 : 0;
466 unsigned pmand = 0, tmand = 0;
467 for(unsigned i = 0; i < 27; i++) {
468 if(i >= t->get_image_count())
469 continue;
470 if(file[i] != "")
471 pmand |= t->get_image_info(i).mandatory;
472 tmand |= t->get_image_info(i).mandatory;
473 romimg[i] = fileimage::image(lsnes_image_hasher, file[i], "", xlate_info(t->get_image_info(i)));
474 if(zip::file_exists(file[i] + ".xml"))
475 romxml[i] = fileimage::image(lsnes_image_hasher, file[i] + ".xml", "", get_xml_info());
477 msu1_base = zip::resolverel(file[romidx], "");
478 record_files(*this);
479 if(pmand != tmand)
480 throw std::runtime_error("Required ROM images missing");
481 rtype = t;
482 orig_region = region = r;
485 void loaded_rom::load(std::map<std::string, std::string>& settings, uint64_t rtc_sec, uint64_t rtc_subsec)
486 throw(std::bad_alloc, std::runtime_error)
488 auto& core = CORE();
489 core_type* old_type = current_rom_type;
490 core_core* old_core = current_rom_type->get_core();
491 current_rom_type = &get_null_type();
492 if(!orig_region && rtype != &get_null_type())
493 orig_region = &rtype->get_preferred_region();
494 if(!region)
495 region = orig_region;
496 if(rtype && !orig_region->compatible_with(*region))
497 throw std::runtime_error("Trying to force incompatible region");
498 if(rtype && !rtype->set_region(*region))
499 throw std::runtime_error("Trying to force unknown region");
501 core_romimage images[ROM_SLOT_COUNT];
502 for(size_t i = 0; i < ROM_SLOT_COUNT; i++) {
503 images[i].markup = (const char*)romxml[i];
504 images[i].data = (const unsigned char*)romimg[i];
505 images[i].size = (size_t)romimg[i];
507 if(!rtype->load(images, settings, rtc_sec, rtc_subsec))
508 throw std::runtime_error("Can't load cartridge ROM");
510 region = &rtype->get_region();
511 rtype->power();
512 auto nominal_fps = rtype->get_video_rate();
513 auto nominal_hz = rtype->get_audio_rate();
514 core.framerate->set_nominal_framerate(1.0 * nominal_fps.first / nominal_fps.second);
515 core.mdumper->on_rate_change(nominal_hz.first, nominal_hz.second);
517 current_rom_type = rtype;
518 current_region = region;
519 //If core changes, unload the cartridge.
520 if(old_core != current_rom_type->get_core())
521 try {
522 old_core->debug_reset();
523 old_core->unload_cartridge();
524 } catch(...) {}
525 (*core.cmapper)();
526 core.dispatch->core_changed(old_type != current_rom_type);
529 std::map<std::string, std::vector<char>> load_sram_commandline(const std::vector<std::string>& cmdline)
530 throw(std::bad_alloc, std::runtime_error)
532 std::map<std::string, std::vector<char>> ret;
533 regex_results opt;
534 for(auto i : cmdline) {
535 if(opt = regex("--continue=(.+)", i)) {
536 zip::reader r(opt[1]);
537 for(auto j : r) {
538 auto sramname = regex("sram\\.(.*)", j);
539 if(!sramname)
540 continue;
541 std::istream& x = r[j];
542 try {
543 std::vector<char> out;
544 boost::iostreams::back_insert_device<std::vector<char>> rd(out);
545 boost::iostreams::copy(x, rd);
546 delete &x;
547 ret[sramname[1]] = out;
548 } catch(...) {
549 delete &x;
550 throw;
553 continue;
554 } else if(opt = regex("--sram-([^=]+)=(.+)", i)) {
555 try {
556 ret[opt[1]] = zip::readrel(opt[2], "");
557 } catch(std::bad_alloc& e) {
558 throw;
559 } catch(std::runtime_error& e) {
560 throw std::runtime_error("Can't load SRAM '" + opt[1] + "': " + e.what());
564 return ret;
567 std::vector<char> loaded_rom::save_core_state(bool nochecksum) throw(std::bad_alloc, std::runtime_error)
569 std::vector<char> ret;
570 rtype->serialize(ret);
571 if(nochecksum)
572 return ret;
573 size_t offset = ret.size();
574 unsigned char tmp[32];
575 #ifdef USE_LIBGCRYPT_SHA256
576 gcry_md_hash_buffer(GCRY_MD_SHA256, tmp, &ret[0], offset);
577 #else
578 sha256::hash(tmp, ret);
579 #endif
580 ret.resize(offset + 32);
581 memcpy(&ret[offset], tmp, 32);
582 return ret;
585 void loaded_rom::load_core_state(const std::vector<char>& buf, bool nochecksum) throw(std::runtime_error)
587 if(nochecksum) {
588 rtype->unserialize(&buf[0], buf.size());
589 return;
592 if(buf.size() < 32)
593 throw std::runtime_error("Savestate corrupt");
594 if(!savestate_no_check(*CORE().settings)) {
595 unsigned char tmp[32];
596 #ifdef USE_LIBGCRYPT_SHA256
597 gcry_md_hash_buffer(GCRY_MD_SHA256, tmp, &buf[0], buf.size() - 32);
598 #else
599 sha256::hash(tmp, reinterpret_cast<const uint8_t*>(&buf[0]), buf.size() - 32);
600 #endif
601 if(memcmp(tmp, &buf[buf.size() - 32], 32))
602 throw std::runtime_error("Savestate corrupt");
604 rtype->unserialize(&buf[0], buf.size() - 32);
607 bool loaded_rom::is_gamepak(const std::string& filename) throw(std::bad_alloc, std::runtime_error)
609 std::istream* spec = NULL;
610 try {
611 spec = &zip::openrel(filename, "");
612 std::string line;
613 std::getline(*spec, line);
614 istrip_CR(line);
615 bool ret = (line == "[GAMEPACK FILE]");
616 delete spec;
617 return ret;
618 } catch(...) {
619 delete spec;
620 return false;
624 void set_hasher_callback(std::function<void(uint64_t, uint64_t)> cb)
626 lsnes_image_hasher.set_callback(cb);
629 std::map<std::string, core_type*> preferred_core;