JSON-based controller descriptions
[lsnes.git] / src / core / rom.cpp
blob47e6c518d87e84a917af97f12e9de3e9769f4dcf
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/pixfmt-rgb16.hpp"
17 #include "library/controller-data.hpp"
18 #include "library/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>
37 #include <boost/filesystem.hpp>
39 #ifdef USE_LIBGCRYPT_SHA256
40 #include <gcrypt.h>
41 #endif
43 #ifdef BOOST_FILESYSTEM3
44 namespace boost_fs = boost::filesystem3;
45 #else
46 namespace boost_fs = boost::filesystem;
47 #endif
49 namespace
51 const char* null_chars = "F";
52 uint16_t null_cover_fbmem[512 * 448];
54 setting_var<setting_var_model_bool<setting_yes_no>> savestate_no_check(lsnes_vset, "dont-check-savestate",
55 "Movie‣Loading‣Don't check savestates", false);
57 //Framebuffer.
58 struct framebuffer_info null_fbinfo = {
59 &_pixel_format_bgr16, //Format.
60 (char*)null_cover_fbmem, //Memory.
61 512, 448, 1024, //Physical size.
62 512, 448, 1024, //Logical size.
63 0, 0 //Offset.
66 port_index_triple sync_triple = {true, 0, 0, 0 };
68 struct interface_device_reg null_registers[] = {
69 {NULL, NULL, NULL}
72 struct _core_null : public core_core, public core_type, public core_region, public core_sysregion
74 _core_null() : core_core({}, {}), core_type({{
75 .iname = "null",
76 .hname = "(null)",
77 .id = 9999,
78 .sysname = "System",
79 .bios = NULL,
80 .regions = {this},
81 .images = {},
82 .settings = {},
83 .core = this,
84 }}), core_region({{"null", "(null)", 0, 0, false, {1, 60}, {0}}}),
85 core_sysregion("null", *this, *this) {}
86 std::string c_core_identifier() { return "null core"; }
87 bool c_set_region(core_region& reg) { return true; }
88 std::pair<unsigned, unsigned> c_video_rate() { return std::make_pair(60, 1); }
89 double c_get_PAR() { return 1.0; }
90 std::pair<unsigned, unsigned> c_audio_rate() { return std::make_pair(48000, 1); }
91 std::map<std::string, std::vector<char>> c_save_sram() throw (std::bad_alloc) {
92 std::map<std::string, std::vector<char>> x;
93 return x;
95 void c_load_sram(std::map<std::string, std::vector<char>>& sram) throw (std::bad_alloc) {}
96 void c_serialize(std::vector<char>& out) { out.clear(); }
97 void c_unserialize(const char* in, size_t insize) {}
98 core_region& c_get_region() { return *this; }
99 void c_power() {}
100 void c_unload_cartridge() {}
101 std::pair<uint32_t, uint32_t> c_get_scale_factors(uint32_t width, uint32_t height) {
102 return std::make_pair(1, 1);
104 void c_install_handler() {}
105 void c_uninstall_handler() {}
106 void c_emulate() {}
107 void c_runtosave() {}
108 bool c_get_pflag() { return false; }
109 void c_set_pflag(bool pflag) {}
110 framebuffer_raw& c_draw_cover() {
111 static framebuffer_raw x(null_fbinfo);
112 for(size_t i = 0; i < sizeof(null_cover_fbmem)/sizeof(null_cover_fbmem[0]); i++)
113 null_cover_fbmem[i] = 0x0000;
114 std::string message = "NO ROM LOADED";
115 cover_render_string(null_cover_fbmem, 204, 220, message, 0xFFFF, 0x0000, 512, 448, 1024, 2);
116 return x;
118 std::string c_get_core_shortname() { return "null"; }
119 void c_pre_emulate_frame(controller_frame& cf) {}
120 void c_execute_action(unsigned id, const std::vector<interface_action_paramval>& p) {}
121 const interface_device_reg* c_get_registers() { return null_registers; }
122 int t_load_rom(core_romimage* img, std::map<std::string, std::string>& settings,
123 uint64_t secs, uint64_t subsecs)
125 return 0;
127 controller_set t_controllerconfig(std::map<std::string, std::string>& settings)
129 controller_set x;
130 x.ports.push_back(&get_default_system_port_type());
131 return x;
133 std::pair<uint64_t, uint64_t> c_get_bus_map() { return std::make_pair(0ULL, 0ULL); }
134 std::list<core_vma_info> c_vma_list() { return std::list<core_vma_info>(); }
135 std::set<std::string> c_srams() { return std::set<std::string>(); }
136 unsigned c_action_flags(unsigned id) { return 0; }
137 int c_reset_action(bool hard) { return -1; }
138 bool c_isnull() { return true; }
139 } core_null;
141 core_type* current_rom_type = &core_null;
142 core_region* current_region = &core_null;
144 core_type* find_core_by_extension(const std::string& ext, const std::string& tmpprefer)
146 std::string key = "ext:" + ext;
147 std::list<core_type*> possible = core_type::get_core_types();
148 core_type* fallback = NULL;
149 core_type* preferred = preferred_core.count(key) ? preferred_core[key] : NULL;
150 //Tmpprefer overrides normal preferred core.
151 if(tmpprefer != "")
152 for(auto i : possible)
153 if(i->get_iname() == tmpprefer)
154 preferred = i;
155 for(auto i : possible)
156 if(i->is_known_extension(ext)) {
157 fallback = i;
158 if(!preferred && i->get_core_shortname() == preferred_core_default)
159 return i;
160 if(i == preferred)
161 return i;
163 return fallback;
166 core_type* find_core_by_name(const std::string& name, const std::string& tmpprefer)
168 std::string key = "type:" + name;
169 std::list<core_type*> possible = core_type::get_core_types();
170 core_type* fallback = NULL;
171 core_type* preferred = preferred_core.count(key) ? preferred_core[key] : NULL;
172 //Tmpprefer overrides normal preferred core.
173 if(tmpprefer != "")
174 for(auto i : possible)
175 if(i->get_iname() == tmpprefer)
176 preferred = i;
177 for(auto i : possible)
178 if(i->get_iname() == name) {
179 fallback = i;
180 if(!preferred && i->get_core_shortname() == preferred_core_default)
181 return i;
182 if(i == preferred)
183 return i;
185 return fallback;
188 struct loaded_image::info get_xml_info()
190 loaded_image::info i;
191 i.type = loaded_image::info::IT_MARKUP;
192 i.headersize = 0;
193 return i;
196 struct loaded_image::info xlate_info(core_romimage_info ri)
198 loaded_image::info i;
199 if(ri.pass_mode == 0) i.type = loaded_image::info::IT_MEMORY;
200 if(ri.pass_mode == 1) i.type = loaded_image::info::IT_FILE;
201 i.headersize = ri.headersize;
202 return i;
205 void record_files(loaded_rom& rom)
207 for(unsigned i = 0; i < ROM_SLOT_COUNT; i++) {
208 try {
209 record_filehash(rom.romimg[i].filename, rom.romimg[i].stripped,
210 rom.romimg[i].sha_256.read());
211 } catch(...) {}
212 try {
213 record_filehash(rom.romxml[i].filename, rom.romxml[i].stripped,
214 rom.romxml[i].sha_256.read());
215 } catch(...) {}
220 sha256_hasher lsnes_image_hasher;
222 std::pair<core_type*, core_region*> get_current_rom_info() throw()
224 return std::make_pair(current_rom_type, current_region);
227 loaded_rom::loaded_rom() throw()
229 rtype = &core_null;
230 region = orig_region = &core_null;
233 loaded_rom::loaded_rom(const std::string& file, core_type& ctype) throw(std::bad_alloc, std::runtime_error)
235 rtype = &ctype;
236 region = orig_region = &rtype->get_preferred_region();
237 unsigned romidx = 0;
238 std::string bios;
239 unsigned pmand = 0, tmand = 0;
240 for(unsigned i = 0; i < ctype.get_image_count(); i++)
241 tmand |= ctype.get_image_info(i).mandatory;
242 if((bios = ctype.get_biosname()) != "") {
243 //This thing has a BIOS.
244 romidx = 1;
245 std::string basename = lsnes_vset["firmwarepath"].str() + "/" + bios;
246 romimg[0] = loaded_image(lsnes_image_hasher, basename, "", xlate_info(ctype.get_image_info(0)));
247 if(file_exists_zip(basename + ".xml"))
248 romxml[0] = loaded_image(lsnes_image_hasher, basename + ".xml", "", get_xml_info());
249 pmand |= ctype.get_image_info(0).mandatory;
251 romimg[romidx] = loaded_image(lsnes_image_hasher, file, "", xlate_info(ctype.get_image_info(romidx)));
252 if(file_exists_zip(file + ".xml"))
253 romxml[romidx] = loaded_image(lsnes_image_hasher, file + ".xml", "", get_xml_info());
254 pmand |= ctype.get_image_info(romidx).mandatory;
255 msu1_base = resolve_file_relative(file, "");
256 record_files(*this);
257 if(pmand != tmand)
258 throw std::runtime_error("Required ROM images missing");
259 return;
262 loaded_rom::loaded_rom(const std::string& file, const std::string& tmpprefer) throw(std::bad_alloc,
263 std::runtime_error)
265 std::istream& spec = open_file_relative(file, "");
266 std::string s;
267 std::getline(spec, s);
268 istrip_CR(s);
269 if(!spec || s != "[GAMEPACK FILE]") {
270 //This is a Raw ROM image.
271 regex_results tmp;
272 std::string ext = regex(".*\\.([^.]*)?", file, "Can't read file extension")[1];
273 core_type* coretype = find_core_by_extension(ext, tmpprefer);
274 if(!coretype)
275 (stringfmt() << "Extension '" << ext << "' unknown").throwex();
276 rtype = coretype;
277 region = orig_region = &rtype->get_preferred_region();
278 unsigned romidx = 0;
279 std::string bios;
280 unsigned pmand = 0, tmand = 0;
281 for(unsigned i = 0; i < rtype->get_image_count(); i++)
282 tmand |= rtype->get_image_info(i).mandatory;
283 if((bios = coretype->get_biosname()) != "") {
284 //This thing has a BIOS.
285 romidx = 1;
286 std::string basename = lsnes_vset["firmwarepath"].str() + "/" + bios;
287 romimg[0] = loaded_image(lsnes_image_hasher, basename, "",
288 xlate_info(coretype->get_image_info(0)));
289 if(file_exists_zip(basename + ".xml"))
290 romxml[0] = loaded_image(lsnes_image_hasher, basename + ".xml", "", get_xml_info());
291 pmand |= rtype->get_image_info(0).mandatory;
293 romimg[romidx] = loaded_image(lsnes_image_hasher, file, "",
294 xlate_info(coretype->get_image_info(romidx)));
295 if(file_exists_zip(file + ".xml"))
296 romxml[romidx] = loaded_image(lsnes_image_hasher, file + ".xml", "", get_xml_info());
297 pmand |= rtype->get_image_info(romidx).mandatory;
298 msu1_base = resolve_file_relative(file, "");
299 record_files(*this);
300 if(pmand != tmand)
301 throw std::runtime_error("Required ROM images missing");
302 return;
304 load_filename = file;
305 std::vector<std::string> lines;
306 while(std::getline(spec, s))
307 lines.push_back(strip_CR(s));
308 std::string platname = "";
309 std::string platreg = "";
310 for(auto i : lines) {
311 regex_results tmp;
312 if(tmp = regex("type[ \t]+(.+)", i))
313 platname = tmp[1];
314 if(tmp = regex("region[ \t]+(.+)", i))
315 platreg = tmp[1];
318 //Detect type.
319 rtype = find_core_by_name(platname, tmpprefer);
320 if(!rtype)
321 (stringfmt() << "Not a valid system type '" << platname << "'").throwex();
323 //Detect region.
324 bool goodreg = false;
325 orig_region = &rtype->get_preferred_region();
326 for(auto i: rtype->get_regions())
327 if(i->get_iname() == platreg) {
328 orig_region = i;
329 goodreg = true;
331 if(!goodreg && platreg != "")
332 (stringfmt() << "Not a valid system region '" << platreg << "'").throwex();
333 region = orig_region;
335 //ROM files.
336 std::string cromimg[ROM_SLOT_COUNT];
337 std::string cromxml[ROM_SLOT_COUNT];
338 for(auto i : lines) {
339 regex_results tmp;
340 if(!(tmp = regex("(rom|xml)[ \t]+([^ \t]+)[ \t]+(.*)", i)))
341 continue;
342 size_t idxs = rtype->get_image_count();
343 size_t idx = idxs;
344 for(size_t i = 0; i < idxs; i++)
345 if(rtype->get_image_info(i).iname == tmp[2])
346 idx = i;
347 if(idx == idxs)
348 (stringfmt() << "Not a valid ROM name '" << tmp[2] << "'").throwex();
349 if(tmp[1] == "rom")
350 cromimg[idx] = tmp[3];
351 else
352 cromxml[idx] = tmp[3];
355 //Check ROMs.
356 unsigned mask1 = 0, mask2 = 0;
357 for(size_t i = 0; i < rtype->get_image_count(); i++) {
358 auto ii = rtype->get_image_info(i);
359 mask1 |= ii.mandatory;
360 if(cromimg[i] != "")
361 mask2 |= ii.mandatory;
362 if(cromimg[i] == "" && cromxml[i] != "") {
363 messages << "WARNING: Slot " << ii.iname << ": XML without ROM." << std::endl;
364 cromxml[i] = "";
367 if(mask1 != mask2)
368 throw std::runtime_error("Required ROM missing");
370 //Load ROMs.
371 for(size_t i = 0; i < rtype->get_image_count(); i++) {
372 romimg[i] = loaded_image(lsnes_image_hasher, cromimg[i], file, xlate_info(rtype->get_image_info(i)));
373 romxml[i] = loaded_image(lsnes_image_hasher, cromxml[i], file, get_xml_info());
375 record_files(*this); //Have to do this before patching.
377 //Patch ROMs.
378 for(auto i : lines) {
379 regex_results tmp;
380 if(!(tmp = regex("patch([+-][0-9]+)?[ \t]+([^ \t]+)[ \t]+(.*)", i)))
381 continue;
382 size_t idxs = rtype->get_image_count();
383 size_t idx = idxs;
384 for(size_t i = 0; i < idxs; i++)
385 if(rtype->get_image_info(i).iname == tmp[2])
386 idx = i;
387 if(idx == idxs)
388 (stringfmt() << "Not a valid ROM name '" << tmp[2] << "'").throwex();
389 int32_t offset = 0;
390 if(tmp[1] != "")
391 offset = parse_value<int32_t>(tmp[1]);
392 romimg[idx].patch(read_file_relative(tmp[3], file), offset);
395 //MSU-1 base.
396 if(cromimg[1] != "")
397 msu1_base = resolve_file_relative(cromimg[1], file);
398 else
399 msu1_base = resolve_file_relative(cromimg[0], file);
402 namespace
404 bool filter_by_core(core_type& ctype, const std::string& core)
406 return (core == "" || ctype.get_core_identifier() == core);
409 bool filter_by_type(core_type& ctype, const std::string& type)
411 return (type == "" || ctype.get_iname() == type);
414 bool filter_by_region(core_type& ctype, const std::string& region)
416 if(region == "")
417 return true;
418 for(auto i : ctype.get_regions())
419 if(i->get_iname() == region)
420 return true;
421 return false;
424 bool filter_by_extension(core_type& ctype, const std::string& file)
426 regex_results tmp = regex(".*\\.([^.]*)", file);
427 if(!tmp)
428 return false;
429 std::string ext = tmp[1];
430 return ctype.is_known_extension(ext);
433 bool filter_by_fileset(core_type& ctype, const std::string file[ROM_SLOT_COUNT])
435 uint32_t m = 0, t = 0;
436 for(unsigned i = 0; i < ROM_SLOT_COUNT; i++) {
437 if(i >= ctype.get_image_count() && file[i] != "")
438 return false;
439 auto s = ctype.get_image_info(i);
440 if(file[i] != "")
441 m |= s.mandatory;
442 t |= s.mandatory;
444 return (m == t);
447 core_region* detect_region(core_type* t, const std::string& region)
449 core_region* r = NULL;
450 for(auto i: t->get_regions())
451 if(i->get_iname() == region)
452 r = i;
453 if(!r && region != "")
454 (stringfmt() << "Not a valid system region '" << region << "'").throwex();
455 if(!r) r = &t->get_preferred_region(); //Default region.
456 return r;
460 loaded_rom::loaded_rom(const std::string& file, const std::string& core, const std::string& type,
461 const std::string& _region)
463 core_type* t = NULL;
464 core_region* r = NULL;
465 bool fullspec = (core != "" && type != "");
466 for(auto i : core_type::get_core_types()) {
467 if(!filter_by_core(*i, core))
468 continue;
469 if(!filter_by_type(*i, type))
470 continue;
471 if(!fullspec && !filter_by_region(*i, _region))
472 continue;
473 if(!fullspec && !filter_by_extension(*i, file))
474 continue;
475 t = i;
477 if(!t) throw std::runtime_error("No matching core found");
478 r = detect_region(t, _region);
479 unsigned pmand = 0, tmand = 0;
480 for(unsigned i = 0; i < t->get_image_count(); i++)
481 tmand |= t->get_image_info(i).mandatory;
482 std::string bios = t->get_biosname();
483 unsigned romidx = (bios != "") ? 1 : 0;
484 if(bios != "") {
485 std::string basename = lsnes_vset["firmwarepath"].str() + "/" + bios;
486 romimg[0] = loaded_image(lsnes_image_hasher, basename, "", xlate_info(t->get_image_info(0)));
487 if(file_exists_zip(basename + ".xml"))
488 romxml[0] = loaded_image(lsnes_image_hasher, basename + ".xml", "", get_xml_info());
489 pmand |= t->get_image_info(0).mandatory;
491 romimg[romidx] = loaded_image(lsnes_image_hasher, file, "", xlate_info(t->get_image_info(romidx)));
492 if(file_exists_zip(file + ".xml"))
493 romxml[romidx] = loaded_image(lsnes_image_hasher, file + ".xml", "", get_xml_info());
494 pmand |= t->get_image_info(romidx).mandatory;
495 msu1_base = resolve_file_relative(file, "");
496 record_files(*this);
497 if(pmand != tmand)
498 throw std::runtime_error("Required ROM images missing");
499 rtype = t;
500 orig_region = region = r;
503 loaded_rom::loaded_rom(const std::string file[ROM_SLOT_COUNT], const std::string& core, const std::string& type,
504 const std::string& _region)
506 core_type* t = NULL;
507 core_region* r = NULL;
508 bool fullspec = (core != "" && type != "");
509 for(auto i : core_type::get_core_types()) {
510 if(!filter_by_core(*i, core)) {
511 continue;
513 if(!filter_by_type(*i, type)) {
514 continue;
516 if(!fullspec && !filter_by_region(*i, _region)) {
517 continue;
519 if(!fullspec && !filter_by_fileset(*i, file)) {
520 continue;
522 t = i;
524 if(!t) throw std::runtime_error("No matching core found");
525 r = detect_region(t, _region);
526 std::string bios = t->get_biosname();
527 unsigned romidx = (bios != "") ? 1 : 0;
528 unsigned pmand = 0, tmand = 0;
529 for(unsigned i = 0; i < 27; i++) {
530 if(i >= t->get_image_count())
531 continue;
532 if(file[i] != "")
533 pmand |= t->get_image_info(i).mandatory;
534 tmand |= t->get_image_info(i).mandatory;
535 romimg[i] = loaded_image(lsnes_image_hasher, file[i], "", xlate_info(t->get_image_info(i)));
536 if(file_exists_zip(file[i] + ".xml"))
537 romxml[i] = loaded_image(lsnes_image_hasher, file[i] + ".xml", "", get_xml_info());
539 msu1_base = resolve_file_relative(file[romidx], "");
540 record_files(*this);
541 if(pmand != tmand)
542 throw std::runtime_error("Required ROM images missing");
543 rtype = t;
544 orig_region = region = r;
547 void loaded_rom::load(std::map<std::string, std::string>& settings, uint64_t rtc_sec, uint64_t rtc_subsec)
548 throw(std::bad_alloc, std::runtime_error)
550 core_type* old_type = current_rom_type;
551 core_core* old_core = current_rom_type->get_core();
552 current_rom_type = &core_null;
553 if(!orig_region && rtype != &core_null)
554 orig_region = &rtype->get_preferred_region();
555 if(!region)
556 region = orig_region;
557 if(rtype && !orig_region->compatible_with(*region))
558 throw std::runtime_error("Trying to force incompatible region");
559 if(rtype && !rtype->set_region(*region))
560 throw std::runtime_error("Trying to force unknown region");
562 core_romimage images[ROM_SLOT_COUNT];
563 for(size_t i = 0; i < ROM_SLOT_COUNT; i++) {
564 images[i].markup = (const char*)romxml[i];
565 images[i].data = (const unsigned char*)romimg[i];
566 images[i].size = (size_t)romimg[i];
568 if(!rtype->load(images, settings, rtc_sec, rtc_subsec))
569 throw std::runtime_error("Can't load cartridge ROM");
571 region = &rtype->get_region();
572 rtype->power();
573 auto nominal_fps = rtype->get_video_rate();
574 auto nominal_hz = rtype->get_audio_rate();
575 set_nominal_framerate(1.0 * nominal_fps.first / nominal_fps.second);
576 information_dispatch::do_sound_rate(nominal_hz.first, nominal_hz.second);
577 current_rom_type = rtype;
578 current_region = region;
579 //If core changes, unload the cartridge.
580 if(old_core != current_rom_type->get_core())
581 try { old_core->unload_cartridge(); } catch(...) {}
582 refresh_cart_mappings();
583 notify_core_changed(old_type != current_rom_type);
586 std::map<std::string, std::vector<char>> load_sram_commandline(const std::vector<std::string>& cmdline)
587 throw(std::bad_alloc, std::runtime_error)
589 std::map<std::string, std::vector<char>> ret;
590 regex_results opt;
591 for(auto i : cmdline) {
592 if(opt = regex("--continue=(.+)", i)) {
593 zip_reader r(opt[1]);
594 for(auto j : r) {
595 auto sramname = regex("sram\\.(.*)", j);
596 if(!sramname)
597 continue;
598 std::istream& x = r[j];
599 try {
600 std::vector<char> out;
601 boost::iostreams::back_insert_device<std::vector<char>> rd(out);
602 boost::iostreams::copy(x, rd);
603 delete &x;
604 ret[sramname[1]] = out;
605 } catch(...) {
606 delete &x;
607 throw;
610 continue;
611 } else if(opt = regex("--sram-([^=]+)=(.+)", i)) {
612 try {
613 ret[opt[1]] = read_file_relative(opt[2], "");
614 } catch(std::bad_alloc& e) {
615 throw;
616 } catch(std::runtime_error& e) {
617 throw std::runtime_error("Can't load SRAM '" + opt[1] + "': " + e.what());
621 return ret;
624 std::vector<char> loaded_rom::save_core_state(bool nochecksum) throw(std::bad_alloc)
626 std::vector<char> ret;
627 rtype->serialize(ret);
628 if(nochecksum)
629 return ret;
630 size_t offset = ret.size();
631 unsigned char tmp[32];
632 #ifdef USE_LIBGCRYPT_SHA256
633 gcry_md_hash_buffer(GCRY_MD_SHA256, tmp, &ret[0], offset);
634 #else
635 sha256::hash(tmp, ret);
636 #endif
637 ret.resize(offset + 32);
638 memcpy(&ret[offset], tmp, 32);
639 return ret;
642 void loaded_rom::load_core_state(const std::vector<char>& buf, bool nochecksum) throw(std::runtime_error)
644 if(nochecksum) {
645 rtype->unserialize(&buf[0], buf.size());
646 return;
649 if(buf.size() < 32)
650 throw std::runtime_error("Savestate corrupt");
651 if(!savestate_no_check) {
652 unsigned char tmp[32];
653 #ifdef USE_LIBGCRYPT_SHA256
654 gcry_md_hash_buffer(GCRY_MD_SHA256, tmp, &buf[0], buf.size() - 32);
655 #else
656 sha256::hash(tmp, reinterpret_cast<const uint8_t*>(&buf[0]), buf.size() - 32);
657 #endif
658 if(memcmp(tmp, &buf[buf.size() - 32], 32))
659 throw std::runtime_error("Savestate corrupt");
661 rtype->unserialize(&buf[0], buf.size() - 32);
664 void set_hasher_callback(std::function<void(uint64_t, uint64_t)> cb)
666 lsnes_image_hasher.set_callback(cb);
669 std::map<std::string, core_type*> preferred_core;
670 std::string preferred_core_default;