If loading ROM with multiple candidates, prompt before adding to recentrom
[lsnes.git] / src / core / rom.cpp
blob9e3b0ab38fa8984afcca1d5d53e6b753bb33d2a7
1 #include "lsnes.hpp"
3 #include "core/command.hpp"
4 #include "core/dispatch.hpp"
5 #include "core/framerate.hpp"
6 #include "core/mainloop.hpp"
7 #include "core/memorymanip.hpp"
8 #include "core/misc.hpp"
9 #include "core/rom.hpp"
10 #include "core/romguess.hpp"
11 #include "core/settings.hpp"
12 #include "core/window.hpp"
13 #include "interface/cover.hpp"
14 #include "interface/romtype.hpp"
15 #include "interface/callbacks.hpp"
16 #include "library/framebuffer-pixfmt-rgb16.hpp"
17 #include "library/controller-data.hpp"
18 #include "library/fileimage-patch.hpp"
19 #include "library/sha256.hpp"
20 #include "library/string.hpp"
21 #include "library/zip.hpp"
23 #include <stdexcept>
25 #include <sstream>
26 #include <iomanip>
27 #include <cstdint>
28 #include <set>
29 #include <boost/iostreams/categories.hpp>
30 #include <boost/iostreams/copy.hpp>
31 #include <boost/iostreams/stream.hpp>
32 #include <boost/iostreams/stream_buffer.hpp>
33 #include <boost/iostreams/filter/symmetric.hpp>
34 #include <boost/iostreams/filter/zlib.hpp>
35 #include <boost/iostreams/filtering_stream.hpp>
36 #include <boost/iostreams/device/back_inserter.hpp>
38 #ifdef USE_LIBGCRYPT_SHA256
39 #include <gcrypt.h>
40 #endif
42 namespace
44 uint16_t null_cover_fbmem[512 * 448];
46 settingvar::variable<settingvar::model_bool<settingvar::yes_no>> savestate_no_check(lsnes_vset,
47 "dont-check-savestate", "Movie‣Loading‣Don't check savestates", false);
49 //Framebuffer.
50 struct framebuffer::info null_fbinfo = {
51 &framebuffer::pixfmt_bgr16, //Format.
52 (char*)null_cover_fbmem, //Memory.
53 512, 448, 1024, //Physical size.
54 512, 448, 1024, //Logical size.
55 0, 0 //Offset.
58 struct interface_device_reg null_registers[] = {
59 {NULL, NULL, NULL}
62 struct _core_null : public core_core, public core_type, public core_region, public core_sysregion
64 _core_null() : core_core({}, {}), core_type({{
65 .iname = "null",
66 .hname = "(null)",
67 .id = 9999,
68 .sysname = "System",
69 .bios = NULL,
70 .regions = {this},
71 .images = {},
72 .settings = {},
73 .core = this,
74 }}), core_region({{"null", "(null)", 0, 0, false, {1, 60}, {0}}}),
75 core_sysregion("null", *this, *this) { hide(); }
76 std::string c_core_identifier() { return "null core"; }
77 bool c_set_region(core_region& reg) { return true; }
78 std::pair<unsigned, unsigned> c_video_rate() { return std::make_pair(60, 1); }
79 double c_get_PAR() { return 1.0; }
80 std::pair<unsigned, unsigned> c_audio_rate() { return std::make_pair(48000, 1); }
81 std::map<std::string, std::vector<char>> c_save_sram() throw (std::bad_alloc) {
82 std::map<std::string, std::vector<char>> x;
83 return x;
85 void c_load_sram(std::map<std::string, std::vector<char>>& sram) throw (std::bad_alloc) {}
86 void c_serialize(std::vector<char>& out) { out.clear(); }
87 void c_unserialize(const char* in, size_t insize) {}
88 core_region& c_get_region() { return *this; }
89 void c_power() {}
90 void c_unload_cartridge() {}
91 std::pair<uint32_t, uint32_t> c_get_scale_factors(uint32_t width, uint32_t height) {
92 return std::make_pair(1, 1);
94 void c_install_handler() {}
95 void c_uninstall_handler() {}
96 void c_emulate() {}
97 void c_runtosave() {}
98 bool c_get_pflag() { return false; }
99 void c_set_pflag(bool pflag) {}
100 framebuffer::raw& c_draw_cover() {
101 static framebuffer::raw x(null_fbinfo);
102 for(size_t i = 0; i < sizeof(null_cover_fbmem)/sizeof(null_cover_fbmem[0]); i++)
103 null_cover_fbmem[i] = 0x0000;
104 std::string message = "NO ROM LOADED";
105 cover_render_string(null_cover_fbmem, 204, 220, message, 0xFFFF, 0x0000, 512, 448, 1024, 2);
106 return x;
108 std::string c_get_core_shortname() { return "null"; }
109 void c_pre_emulate_frame(controller_frame& cf) {}
110 void c_execute_action(unsigned id, const std::vector<interface_action_paramval>& p) {}
111 const interface_device_reg* c_get_registers() { return null_registers; }
112 int t_load_rom(core_romimage* img, std::map<std::string, std::string>& settings,
113 uint64_t secs, uint64_t subsecs)
115 return 0;
117 controller_set t_controllerconfig(std::map<std::string, std::string>& settings)
119 controller_set x;
120 x.ports.push_back(&get_default_system_port_type());
121 return x;
123 std::pair<uint64_t, uint64_t> c_get_bus_map() { return std::make_pair(0ULL, 0ULL); }
124 std::list<core_vma_info> c_vma_list() { return std::list<core_vma_info>(); }
125 std::set<std::string> c_srams() { return std::set<std::string>(); }
126 unsigned c_action_flags(unsigned id) { return 0; }
127 int c_reset_action(bool hard) { return -1; }
128 bool c_isnull() { return true; }
129 void c_set_debug_flags(uint64_t addr, unsigned int sflags, unsigned int cflags) {}
130 void c_set_cheat(uint64_t addr, uint64_t value, bool set) {}
131 void c_debug_reset() {}
132 std::vector<std::string> c_get_trace_cpus()
134 return std::vector<std::string>();
136 } core_null;
138 core_type* current_rom_type = &core_null;
139 core_region* current_region = &core_null;
141 core_type* prompt_core_fallback(const std::vector<core_type*>& choices)
143 if(choices.size() == 0)
144 return NULL;
145 if(choices.size() == 1)
146 return choices[0];
147 rom_request req;
148 req.cores = choices;
149 req.core_guessed = false;
150 req.selected = 0;
151 //Tell that all ROMs have been correctly guessed, leaving only core select.
152 for(unsigned i = 0; i < ROM_SLOT_COUNT; i++) {
153 req.has_slot[i] = false;
154 req.guessed[i] = false;
156 req.canceled = false;
157 graphics_driver_request_rom(req);
158 if(req.canceled)
159 throw std::runtime_error("Canceled ROM loading");
160 if(req.selected < choices.size())
161 return choices[req.selected];
162 return choices[0];
165 core_type* find_core_by_extension(const std::string& ext, const std::string& tmpprefer)
167 std::string key = "ext:" + ext;
168 std::list<core_type*> possible = core_type::get_core_types();
169 core_type* preferred = preferred_core.count(key) ? preferred_core[key] : NULL;
170 std::vector<core_type*> fallbacks;
171 //Tmpprefer overrides normal preferred core.
172 if(tmpprefer != "")
173 for(auto i : possible)
174 if(i->get_core_identifier() == tmpprefer)
175 return i;
176 for(auto i : possible)
177 if(i->is_known_extension(ext)) {
178 fallbacks.push_back(i);
179 if(i == preferred)
180 return i;
182 core_type* fallback = prompt_core_fallback(fallbacks);
183 if(!fallback) throw std::runtime_error("No core available to load the ROM");
184 return fallback;
187 core_type* find_core_by_name(const std::string& name, const std::string& tmpprefer)
189 std::string key = "type:" + name;
190 std::list<core_type*> possible = core_type::get_core_types();
191 std::vector<core_type*> fallbacks;
192 core_type* preferred = preferred_core.count(key) ? preferred_core[key] : NULL;
193 //Tmpprefer overrides normal preferred core.
194 if(tmpprefer != "")
195 for(auto i : possible)
196 if(i->get_iname() == tmpprefer)
197 return i;
198 for(auto i : possible)
199 if(i->get_iname() == name) {
200 fallbacks.push_back(i);
201 if(i == preferred)
202 return i;
204 core_type* fallback = prompt_core_fallback(fallbacks);
205 if(!fallback) throw std::runtime_error("No core available to load the ROM");
206 return fallback;
209 struct fileimage::image::info get_xml_info()
211 fileimage::image::info i;
212 i.type = fileimage::image::info::IT_MARKUP;
213 i.headersize = 0;
214 return i;
217 struct fileimage::image::info xlate_info(core_romimage_info ri)
219 fileimage::image::info i;
220 if(ri.pass_mode == 0) i.type = fileimage::image::info::IT_MEMORY;
221 if(ri.pass_mode == 1) i.type = fileimage::image::info::IT_FILE;
222 i.headersize = ri.headersize;
223 return i;
226 void record_files(loaded_rom& rom)
228 for(unsigned i = 0; i < ROM_SLOT_COUNT; i++) {
229 try {
230 record_filehash(rom.romimg[i].filename, rom.romimg[i].stripped,
231 rom.romimg[i].sha_256.read());
232 } catch(...) {}
233 try {
234 record_filehash(rom.romxml[i].filename, rom.romxml[i].stripped,
235 rom.romxml[i].sha_256.read());
236 } catch(...) {}
241 fileimage::hash lsnes_image_hasher;
243 std::pair<core_type*, core_region*> get_current_rom_info() throw()
245 return std::make_pair(current_rom_type, current_region);
248 loaded_rom::loaded_rom() throw()
250 rtype = &core_null;
251 region = orig_region = &core_null;
254 loaded_rom::loaded_rom(const std::string& file, core_type& ctype) throw(std::bad_alloc, std::runtime_error)
256 rtype = &ctype;
257 region = orig_region = &rtype->get_preferred_region();
258 unsigned romidx = 0;
259 std::string bios;
260 unsigned pmand = 0, tmand = 0;
261 for(unsigned i = 0; i < ctype.get_image_count(); i++)
262 tmand |= ctype.get_image_info(i).mandatory;
263 if((bios = ctype.get_biosname()) != "") {
264 //This thing has a BIOS.
265 romidx = 1;
266 std::string basename = lsnes_vset["firmwarepath"].str() + "/" + bios;
267 romimg[0] = fileimage::image(lsnes_image_hasher, basename, "", xlate_info(ctype.get_image_info(0)));
268 if(zip::file_exists(basename + ".xml"))
269 romxml[0] = fileimage::image(lsnes_image_hasher, basename + ".xml", "", get_xml_info());
270 pmand |= ctype.get_image_info(0).mandatory;
272 romimg[romidx] = fileimage::image(lsnes_image_hasher, file, "", xlate_info(ctype.get_image_info(romidx)));
273 if(zip::file_exists(file + ".xml"))
274 romxml[romidx] = fileimage::image(lsnes_image_hasher, file + ".xml", "", get_xml_info());
275 pmand |= ctype.get_image_info(romidx).mandatory;
276 msu1_base = zip::resolverel(file, "");
277 record_files(*this);
278 if(pmand != tmand)
279 throw std::runtime_error("Required ROM images missing");
280 return;
283 loaded_rom::loaded_rom(const std::string& file, const std::string& tmpprefer) throw(std::bad_alloc,
284 std::runtime_error)
286 std::istream& spec = zip::openrel(file, "");
287 std::string s;
288 std::getline(spec, s);
289 istrip_CR(s);
290 if(!spec || s != "[GAMEPACK FILE]") {
291 //This is a Raw ROM image.
292 regex_results tmp;
293 std::string ext = regex(".*\\.([^.]*)?", file, "Can't read file extension")[1];
294 core_type* coretype = find_core_by_extension(ext, tmpprefer);
295 if(!coretype)
296 (stringfmt() << "Extension '" << ext << "' unknown").throwex();
297 rtype = coretype;
298 region = orig_region = &rtype->get_preferred_region();
299 unsigned romidx = 0;
300 std::string bios;
301 unsigned pmand = 0, tmand = 0;
302 for(unsigned i = 0; i < rtype->get_image_count(); i++)
303 tmand |= rtype->get_image_info(i).mandatory;
304 if((bios = coretype->get_biosname()) != "") {
305 //This thing has a BIOS.
306 romidx = 1;
307 std::string basename = lsnes_vset["firmwarepath"].str() + "/" + bios;
308 romimg[0] = fileimage::image(lsnes_image_hasher, basename, "",
309 xlate_info(coretype->get_image_info(0)));
310 if(zip::file_exists(basename + ".xml"))
311 romxml[0] = fileimage::image(lsnes_image_hasher, basename + ".xml", "",
312 get_xml_info());
313 pmand |= rtype->get_image_info(0).mandatory;
315 romimg[romidx] = fileimage::image(lsnes_image_hasher, file, "",
316 xlate_info(coretype->get_image_info(romidx)));
317 if(zip::file_exists(file + ".xml"))
318 romxml[romidx] = fileimage::image(lsnes_image_hasher, file + ".xml", "", get_xml_info());
319 pmand |= rtype->get_image_info(romidx).mandatory;
320 msu1_base = zip::resolverel(file, "");
321 record_files(*this);
322 if(pmand != tmand)
323 throw std::runtime_error("Required ROM images missing");
324 return;
326 load_filename = file;
327 std::vector<std::string> lines;
328 while(std::getline(spec, s))
329 lines.push_back(strip_CR(s));
330 std::string platname = "";
331 std::string platreg = "";
332 for(auto i : lines) {
333 regex_results tmp;
334 if(tmp = regex("type[ \t]+(.+)", i))
335 platname = tmp[1];
336 if(tmp = regex("region[ \t]+(.+)", i))
337 platreg = tmp[1];
340 //Detect type.
341 rtype = find_core_by_name(platname, tmpprefer);
342 if(!rtype)
343 (stringfmt() << "Not a valid system type '" << platname << "'").throwex();
345 //Detect region.
346 bool goodreg = false;
347 orig_region = &rtype->get_preferred_region();
348 for(auto i: rtype->get_regions())
349 if(i->get_iname() == platreg) {
350 orig_region = i;
351 goodreg = true;
353 if(!goodreg && platreg != "")
354 (stringfmt() << "Not a valid system region '" << platreg << "'").throwex();
355 region = orig_region;
357 //ROM files.
358 std::string cromimg[ROM_SLOT_COUNT];
359 std::string cromxml[ROM_SLOT_COUNT];
360 for(auto i : lines) {
361 regex_results tmp;
362 if(!(tmp = regex("(rom|xml)[ \t]+([^ \t]+)[ \t]+(.*)", i)))
363 continue;
364 size_t idxs = rtype->get_image_count();
365 size_t idx = idxs;
366 for(size_t i = 0; i < idxs; i++)
367 if(rtype->get_image_info(i).iname == tmp[2])
368 idx = i;
369 if(idx == idxs)
370 (stringfmt() << "Not a valid ROM name '" << tmp[2] << "'").throwex();
371 if(tmp[1] == "rom")
372 cromimg[idx] = tmp[3];
373 else
374 cromxml[idx] = tmp[3];
377 //Check ROMs.
378 unsigned mask1 = 0, mask2 = 0;
379 for(size_t i = 0; i < rtype->get_image_count(); i++) {
380 auto ii = rtype->get_image_info(i);
381 mask1 |= ii.mandatory;
382 if(cromimg[i] != "")
383 mask2 |= ii.mandatory;
384 if(cromimg[i] == "" && cromxml[i] != "") {
385 messages << "WARNING: Slot " << ii.iname << ": XML without ROM." << std::endl;
386 cromxml[i] = "";
389 if(mask1 != mask2)
390 throw std::runtime_error("Required ROM missing");
392 //Load ROMs.
393 for(size_t i = 0; i < rtype->get_image_count(); i++) {
394 romimg[i] = fileimage::image(lsnes_image_hasher, cromimg[i], file,
395 xlate_info(rtype->get_image_info(i)));
396 romxml[i] = fileimage::image(lsnes_image_hasher, cromxml[i], file, get_xml_info());
398 record_files(*this); //Have to do this before patching.
400 //Patch ROMs.
401 for(auto i : lines) {
402 regex_results tmp;
403 if(!(tmp = regex("patch([+-][0-9]+)?[ \t]+([^ \t]+)[ \t]+(.*)", i)))
404 continue;
405 size_t idxs = rtype->get_image_count();
406 size_t idx = idxs;
407 for(size_t i = 0; i < idxs; i++)
408 if(rtype->get_image_info(i).iname == tmp[2])
409 idx = i;
410 if(idx == idxs)
411 (stringfmt() << "Not a valid ROM name '" << tmp[2] << "'").throwex();
412 int32_t offset = 0;
413 if(tmp[1] != "")
414 offset = parse_value<int32_t>(tmp[1]);
415 romimg[idx].patch(zip::readrel(tmp[3], file), offset);
418 //MSU-1 base.
419 if(cromimg[1] != "")
420 msu1_base = zip::resolverel(cromimg[1], file);
421 else
422 msu1_base = zip::resolverel(cromimg[0], file);
425 namespace
427 bool filter_by_core(core_type& ctype, const std::string& core)
429 return (core == "" || ctype.get_core_identifier() == core);
432 bool filter_by_type(core_type& ctype, const std::string& type)
434 return (type == "" || ctype.get_iname() == type);
437 bool filter_by_region(core_type& ctype, const std::string& region)
439 if(region == "")
440 return true;
441 for(auto i : ctype.get_regions())
442 if(i->get_iname() == region)
443 return true;
444 return false;
447 bool filter_by_extension(core_type& ctype, const std::string& file)
449 regex_results tmp = regex(".*\\.([^.]*)", file);
450 if(!tmp)
451 return false;
452 std::string ext = tmp[1];
453 return ctype.is_known_extension(ext);
456 bool filter_by_fileset(core_type& ctype, const std::string file[ROM_SLOT_COUNT])
458 uint32_t m = 0, t = 0;
459 for(unsigned i = 0; i < ROM_SLOT_COUNT; i++) {
460 if(i >= ctype.get_image_count() && file[i] != "")
461 return false;
462 auto s = ctype.get_image_info(i);
463 if(file[i] != "")
464 m |= s.mandatory;
465 t |= s.mandatory;
467 return (m == t);
470 core_region* detect_region(core_type* t, const std::string& region)
472 core_region* r = NULL;
473 for(auto i: t->get_regions())
474 if(i->get_iname() == region)
475 r = i;
476 if(!r && region != "")
477 (stringfmt() << "Not a valid system region '" << region << "'").throwex();
478 if(!r) r = &t->get_preferred_region(); //Default region.
479 return r;
483 loaded_rom::loaded_rom(const std::string& file, const std::string& core, const std::string& type,
484 const std::string& _region)
486 core_type* t = NULL;
487 core_region* r = NULL;
488 bool fullspec = (core != "" && type != "");
489 for(auto i : core_type::get_core_types()) {
490 if(!filter_by_core(*i, core))
491 continue;
492 if(!filter_by_type(*i, type))
493 continue;
494 if(!fullspec && !filter_by_region(*i, _region))
495 continue;
496 if(!fullspec && !filter_by_extension(*i, file))
497 continue;
498 t = i;
500 if(!t) throw std::runtime_error("No matching core found");
501 r = detect_region(t, _region);
502 unsigned pmand = 0, tmand = 0;
503 for(unsigned i = 0; i < t->get_image_count(); i++)
504 tmand |= t->get_image_info(i).mandatory;
505 std::string bios = t->get_biosname();
506 unsigned romidx = (bios != "") ? 1 : 0;
507 if(bios != "") {
508 std::string basename = lsnes_vset["firmwarepath"].str() + "/" + bios;
509 romimg[0] = fileimage::image(lsnes_image_hasher, basename, "", xlate_info(t->get_image_info(0)));
510 if(zip::file_exists(basename + ".xml"))
511 romxml[0] = fileimage::image(lsnes_image_hasher, basename + ".xml", "", get_xml_info());
512 pmand |= t->get_image_info(0).mandatory;
514 romimg[romidx] = fileimage::image(lsnes_image_hasher, file, "", xlate_info(t->get_image_info(romidx)));
515 if(zip::file_exists(file + ".xml"))
516 romxml[romidx] = fileimage::image(lsnes_image_hasher, file + ".xml", "", get_xml_info());
517 pmand |= t->get_image_info(romidx).mandatory;
518 msu1_base = zip::resolverel(file, "");
519 record_files(*this);
520 if(pmand != tmand)
521 throw std::runtime_error("Required ROM images missing");
522 rtype = t;
523 orig_region = region = r;
526 loaded_rom::loaded_rom(const std::string file[ROM_SLOT_COUNT], const std::string& core, const std::string& type,
527 const std::string& _region)
529 core_type* t = NULL;
530 core_region* r = NULL;
531 bool fullspec = (core != "" && type != "");
532 for(auto i : core_type::get_core_types()) {
533 if(!filter_by_core(*i, core)) {
534 continue;
536 if(!filter_by_type(*i, type)) {
537 continue;
539 if(!fullspec && !filter_by_region(*i, _region)) {
540 continue;
542 if(!fullspec && !filter_by_fileset(*i, file)) {
543 continue;
545 t = i;
547 if(!t) throw std::runtime_error("No matching core found");
548 r = detect_region(t, _region);
549 std::string bios = t->get_biosname();
550 unsigned romidx = (bios != "") ? 1 : 0;
551 unsigned pmand = 0, tmand = 0;
552 for(unsigned i = 0; i < 27; i++) {
553 if(i >= t->get_image_count())
554 continue;
555 if(file[i] != "")
556 pmand |= t->get_image_info(i).mandatory;
557 tmand |= t->get_image_info(i).mandatory;
558 romimg[i] = fileimage::image(lsnes_image_hasher, file[i], "", xlate_info(t->get_image_info(i)));
559 if(zip::file_exists(file[i] + ".xml"))
560 romxml[i] = fileimage::image(lsnes_image_hasher, file[i] + ".xml", "", get_xml_info());
562 msu1_base = zip::resolverel(file[romidx], "");
563 record_files(*this);
564 if(pmand != tmand)
565 throw std::runtime_error("Required ROM images missing");
566 rtype = t;
567 orig_region = region = r;
570 void loaded_rom::load(std::map<std::string, std::string>& settings, uint64_t rtc_sec, uint64_t rtc_subsec)
571 throw(std::bad_alloc, std::runtime_error)
573 core_type* old_type = current_rom_type;
574 core_core* old_core = current_rom_type->get_core();
575 current_rom_type = &core_null;
576 if(!orig_region && rtype != &core_null)
577 orig_region = &rtype->get_preferred_region();
578 if(!region)
579 region = orig_region;
580 if(rtype && !orig_region->compatible_with(*region))
581 throw std::runtime_error("Trying to force incompatible region");
582 if(rtype && !rtype->set_region(*region))
583 throw std::runtime_error("Trying to force unknown region");
585 core_romimage images[ROM_SLOT_COUNT];
586 for(size_t i = 0; i < ROM_SLOT_COUNT; i++) {
587 images[i].markup = (const char*)romxml[i];
588 images[i].data = (const unsigned char*)romimg[i];
589 images[i].size = (size_t)romimg[i];
591 if(!rtype->load(images, settings, rtc_sec, rtc_subsec))
592 throw std::runtime_error("Can't load cartridge ROM");
594 region = &rtype->get_region();
595 rtype->power();
596 auto nominal_fps = rtype->get_video_rate();
597 auto nominal_hz = rtype->get_audio_rate();
598 set_nominal_framerate(1.0 * nominal_fps.first / nominal_fps.second);
599 information_dispatch::do_sound_rate(nominal_hz.first, nominal_hz.second);
600 current_rom_type = rtype;
601 current_region = region;
602 //If core changes, unload the cartridge.
603 if(old_core != current_rom_type->get_core())
604 try {
605 old_core->debug_reset();
606 old_core->unload_cartridge();
607 } catch(...) {}
608 refresh_cart_mappings();
609 notify_core_changed(old_type != current_rom_type);
612 std::map<std::string, std::vector<char>> load_sram_commandline(const std::vector<std::string>& cmdline)
613 throw(std::bad_alloc, std::runtime_error)
615 std::map<std::string, std::vector<char>> ret;
616 regex_results opt;
617 for(auto i : cmdline) {
618 if(opt = regex("--continue=(.+)", i)) {
619 zip::reader r(opt[1]);
620 for(auto j : r) {
621 auto sramname = regex("sram\\.(.*)", j);
622 if(!sramname)
623 continue;
624 std::istream& x = r[j];
625 try {
626 std::vector<char> out;
627 boost::iostreams::back_insert_device<std::vector<char>> rd(out);
628 boost::iostreams::copy(x, rd);
629 delete &x;
630 ret[sramname[1]] = out;
631 } catch(...) {
632 delete &x;
633 throw;
636 continue;
637 } else if(opt = regex("--sram-([^=]+)=(.+)", i)) {
638 try {
639 ret[opt[1]] = zip::readrel(opt[2], "");
640 } catch(std::bad_alloc& e) {
641 throw;
642 } catch(std::runtime_error& e) {
643 throw std::runtime_error("Can't load SRAM '" + opt[1] + "': " + e.what());
647 return ret;
650 std::vector<char> loaded_rom::save_core_state(bool nochecksum) throw(std::bad_alloc, std::runtime_error)
652 std::vector<char> ret;
653 rtype->serialize(ret);
654 if(nochecksum)
655 return ret;
656 size_t offset = ret.size();
657 unsigned char tmp[32];
658 #ifdef USE_LIBGCRYPT_SHA256
659 gcry_md_hash_buffer(GCRY_MD_SHA256, tmp, &ret[0], offset);
660 #else
661 sha256::hash(tmp, ret);
662 #endif
663 ret.resize(offset + 32);
664 memcpy(&ret[offset], tmp, 32);
665 return ret;
668 void loaded_rom::load_core_state(const std::vector<char>& buf, bool nochecksum) throw(std::runtime_error)
670 if(nochecksum) {
671 rtype->unserialize(&buf[0], buf.size());
672 return;
675 if(buf.size() < 32)
676 throw std::runtime_error("Savestate corrupt");
677 if(!savestate_no_check) {
678 unsigned char tmp[32];
679 #ifdef USE_LIBGCRYPT_SHA256
680 gcry_md_hash_buffer(GCRY_MD_SHA256, tmp, &buf[0], buf.size() - 32);
681 #else
682 sha256::hash(tmp, reinterpret_cast<const uint8_t*>(&buf[0]), buf.size() - 32);
683 #endif
684 if(memcmp(tmp, &buf[buf.size() - 32], 32))
685 throw std::runtime_error("Savestate corrupt");
687 rtype->unserialize(&buf[0], buf.size() - 32);
690 bool loaded_rom::is_gamepak(const std::string& filename) throw(std::bad_alloc, std::runtime_error)
692 std::istream* spec = NULL;
693 try {
694 spec = &zip::openrel(filename, "");
695 std::string line;
696 std::getline(*spec, line);
697 istrip_CR(line);
698 bool ret = (line == "[GAMEPACK FILE]");
699 delete spec;
700 return ret;
701 } catch(...) {
702 delete spec;
703 return false;
707 void set_hasher_callback(std::function<void(uint64_t, uint64_t)> cb)
709 lsnes_image_hasher.set_callback(cb);
712 std::map<std::string, core_type*> preferred_core;