Namespace library port-controller stuff
[lsnes.git] / src / core / rom.cpp
blobb1563705970633853b06d5f78dfacf30ad72db56
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/rom.hpp"
10 #include "core/settings.hpp"
11 #include "core/window.hpp"
12 #include "interface/callbacks.hpp"
13 #include "interface/cover.hpp"
14 #include "interface/romtype.hpp"
15 #include "library/portctrl-data.hpp"
16 #include "library/fileimage-patch.hpp"
17 #include "library/framebuffer-pixfmt-rgb16.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 uint16_t null_cover_fbmem[512 * 448];
44 settingvar::supervariable<settingvar::model_bool<settingvar::yes_no>> savestate_no_check(lsnes_setgrp,
45 "dont-check-savestate", "Movie‣Loading‣Don't check savestates", false);
47 //Framebuffer.
48 struct framebuffer::info null_fbinfo = {
49 &framebuffer::pixfmt_bgr16, //Format.
50 (char*)null_cover_fbmem, //Memory.
51 512, 448, 1024, //Physical size.
52 512, 448, 1024, //Logical size.
53 0, 0 //Offset.
56 struct interface_device_reg null_registers[] = {
57 {NULL, NULL, NULL}
60 struct _core_null : public core_core, public core_type, public core_region, public core_sysregion
62 _core_null() : core_core({}, {}), core_type({{
63 .iname = "null",
64 .hname = "(null)",
65 .id = 9999,
66 .sysname = "System",
67 .bios = NULL,
68 .regions = {this},
69 .images = {},
70 .settings = {},
71 .core = this,
72 }}), core_region({{"null", "(null)", 0, 0, false, {1, 60}, {0}}}),
73 core_sysregion("null", *this, *this) { hide(); }
74 std::string c_core_identifier() { return "null core"; }
75 bool c_set_region(core_region& reg) { return true; }
76 std::pair<unsigned, unsigned> c_video_rate() { return std::make_pair(60, 1); }
77 double c_get_PAR() { return 1.0; }
78 std::pair<unsigned, unsigned> c_audio_rate() { return std::make_pair(48000, 1); }
79 std::map<std::string, std::vector<char>> c_save_sram() throw (std::bad_alloc) {
80 std::map<std::string, std::vector<char>> x;
81 return x;
83 void c_load_sram(std::map<std::string, std::vector<char>>& sram) throw (std::bad_alloc) {}
84 void c_serialize(std::vector<char>& out) { out.clear(); }
85 void c_unserialize(const char* in, size_t insize) {}
86 core_region& c_get_region() { return *this; }
87 void c_power() {}
88 void c_unload_cartridge() {}
89 std::pair<uint32_t, uint32_t> c_get_scale_factors(uint32_t width, uint32_t height) {
90 return std::make_pair(1, 1);
92 void c_install_handler() {}
93 void c_uninstall_handler() {}
94 void c_emulate() {}
95 void c_runtosave() {}
96 bool c_get_pflag() { return false; }
97 void c_set_pflag(bool pflag) {}
98 framebuffer::raw& c_draw_cover() {
99 static framebuffer::raw x(null_fbinfo);
100 for(size_t i = 0; i < sizeof(null_cover_fbmem)/sizeof(null_cover_fbmem[0]); i++)
101 null_cover_fbmem[i] = 0x0000;
102 std::string message = "NO ROM LOADED";
103 cover_render_string(null_cover_fbmem, 204, 220, message, 0xFFFF, 0x0000, 512, 448, 1024, 2);
104 return x;
106 std::string c_get_core_shortname() { return "null"; }
107 void c_pre_emulate_frame(portctrl::frame& cf) {}
108 void c_execute_action(unsigned id, const std::vector<interface_action_paramval>& p) {}
109 const interface_device_reg* c_get_registers() { return null_registers; }
110 int t_load_rom(core_romimage* img, std::map<std::string, std::string>& settings,
111 uint64_t secs, uint64_t subsecs)
113 return 0;
115 controller_set t_controllerconfig(std::map<std::string, std::string>& settings)
117 controller_set x;
118 x.ports.push_back(&portctrl::get_default_system_port_type());
119 return x;
121 std::pair<uint64_t, uint64_t> c_get_bus_map() { return std::make_pair(0ULL, 0ULL); }
122 std::list<core_vma_info> c_vma_list() { return std::list<core_vma_info>(); }
123 std::set<std::string> c_srams() { return std::set<std::string>(); }
124 unsigned c_action_flags(unsigned id) { return 0; }
125 int c_reset_action(bool hard) { return -1; }
126 bool c_isnull() { return true; }
127 void c_set_debug_flags(uint64_t addr, unsigned int sflags, unsigned int cflags) {}
128 void c_set_cheat(uint64_t addr, uint64_t value, bool set) {}
129 void c_debug_reset() {}
130 std::vector<std::string> c_get_trace_cpus()
132 return std::vector<std::string>();
134 } core_null;
136 core_type* current_rom_type = &core_null;
137 core_region* current_region = &core_null;
139 core_type* prompt_core_fallback(const std::vector<core_type*>& choices)
141 if(choices.size() == 0)
142 return NULL;
143 if(choices.size() == 1)
144 return choices[0];
145 rom_request req;
146 req.cores = choices;
147 req.core_guessed = false;
148 req.selected = 0;
149 //Tell that all ROMs have been correctly guessed, leaving only core select.
150 for(unsigned i = 0; i < ROM_SLOT_COUNT; i++) {
151 req.has_slot[i] = false;
152 req.guessed[i] = false;
154 req.canceled = false;
155 graphics_driver_request_rom(req);
156 if(req.canceled)
157 throw std::runtime_error("Canceled ROM loading");
158 if(req.selected < choices.size())
159 return choices[req.selected];
160 return choices[0];
163 core_type* find_core_by_extension(const std::string& ext, const std::string& tmpprefer)
165 std::string key = "ext:" + ext;
166 std::list<core_type*> possible = core_type::get_core_types();
167 core_type* preferred = preferred_core.count(key) ? preferred_core[key] : NULL;
168 std::vector<core_type*> fallbacks;
169 //Tmpprefer overrides normal preferred core.
170 if(tmpprefer != "")
171 for(auto i : possible)
172 if(i->get_core_identifier() == tmpprefer)
173 return i;
174 for(auto i : possible)
175 if(i->is_known_extension(ext)) {
176 fallbacks.push_back(i);
177 if(i == preferred)
178 return i;
180 core_type* fallback = prompt_core_fallback(fallbacks);
181 if(!fallback) throw std::runtime_error("No core available to load the ROM");
182 return fallback;
185 core_type* find_core_by_name(const std::string& name, const std::string& tmpprefer)
187 std::string key = "type:" + name;
188 std::list<core_type*> possible = core_type::get_core_types();
189 std::vector<core_type*> fallbacks;
190 core_type* preferred = preferred_core.count(key) ? preferred_core[key] : NULL;
191 //Tmpprefer overrides normal preferred core.
192 if(tmpprefer != "")
193 for(auto i : possible)
194 if(i->get_iname() == tmpprefer)
195 return i;
196 for(auto i : possible)
197 if(i->get_iname() == name) {
198 fallbacks.push_back(i);
199 if(i == preferred)
200 return i;
202 core_type* fallback = prompt_core_fallback(fallbacks);
203 if(!fallback) throw std::runtime_error("No core available to load the ROM");
204 return fallback;
207 struct fileimage::image::info get_xml_info()
209 fileimage::image::info i;
210 i.type = fileimage::image::info::IT_MARKUP;
211 i.headersize = 0;
212 return i;
215 struct fileimage::image::info xlate_info(core_romimage_info ri)
217 fileimage::image::info i;
218 if(ri.pass_mode == 0) i.type = fileimage::image::info::IT_MEMORY;
219 if(ri.pass_mode == 1) i.type = fileimage::image::info::IT_FILE;
220 i.headersize = ri.headersize;
221 return i;
224 void record_files(loaded_rom& rom)
226 for(unsigned i = 0; i < ROM_SLOT_COUNT; i++) {
227 try {
228 record_filehash(rom.romimg[i].filename, rom.romimg[i].stripped,
229 rom.romimg[i].sha_256.read());
230 } catch(...) {}
231 try {
232 record_filehash(rom.romxml[i].filename, rom.romxml[i].stripped,
233 rom.romxml[i].sha_256.read());
234 } catch(...) {}
239 fileimage::hash lsnes_image_hasher;
241 std::pair<core_type*, core_region*> get_current_rom_info() throw()
243 return std::make_pair(current_rom_type, current_region);
246 loaded_rom::loaded_rom() throw()
248 rtype = &core_null;
249 region = orig_region = &core_null;
252 loaded_rom::loaded_rom(const std::string& file, core_type& ctype) throw(std::bad_alloc, std::runtime_error)
254 rtype = &ctype;
255 region = orig_region = &rtype->get_preferred_region();
256 unsigned romidx = 0;
257 std::string bios;
258 unsigned pmand = 0, tmand = 0;
259 for(unsigned i = 0; i < ctype.get_image_count(); i++)
260 tmand |= ctype.get_image_info(i).mandatory;
261 if((bios = ctype.get_biosname()) != "") {
262 //This thing has a BIOS.
263 romidx = 1;
264 std::string basename = CORE().setcache->get("firmwarepath") + "/" + bios;
265 romimg[0] = fileimage::image(lsnes_image_hasher, basename, "", xlate_info(ctype.get_image_info(0)));
266 if(zip::file_exists(basename + ".xml"))
267 romxml[0] = fileimage::image(lsnes_image_hasher, basename + ".xml", "", get_xml_info());
268 pmand |= ctype.get_image_info(0).mandatory;
270 romimg[romidx] = fileimage::image(lsnes_image_hasher, file, "", xlate_info(ctype.get_image_info(romidx)));
271 if(zip::file_exists(file + ".xml"))
272 romxml[romidx] = fileimage::image(lsnes_image_hasher, file + ".xml", "", get_xml_info());
273 pmand |= ctype.get_image_info(romidx).mandatory;
274 msu1_base = zip::resolverel(file, "");
275 record_files(*this);
276 if(pmand != tmand)
277 throw std::runtime_error("Required ROM images missing");
278 return;
281 loaded_rom::loaded_rom(const std::string& file, const std::string& tmpprefer) throw(std::bad_alloc,
282 std::runtime_error)
284 std::istream& spec = zip::openrel(file, "");
285 std::string s;
286 std::getline(spec, s);
287 istrip_CR(s);
288 if(!spec || s != "[GAMEPACK FILE]") {
289 //This is a Raw ROM image.
290 regex_results tmp;
291 std::string ext = regex(".*\\.([^.]*)?", file, "Can't read file extension")[1];
292 core_type* coretype = find_core_by_extension(ext, tmpprefer);
293 if(!coretype)
294 (stringfmt() << "Extension '" << ext << "' unknown").throwex();
295 rtype = coretype;
296 region = orig_region = &rtype->get_preferred_region();
297 unsigned romidx = 0;
298 std::string bios;
299 unsigned pmand = 0, tmand = 0;
300 for(unsigned i = 0; i < rtype->get_image_count(); i++)
301 tmand |= rtype->get_image_info(i).mandatory;
302 if((bios = coretype->get_biosname()) != "") {
303 //This thing has a BIOS.
304 romidx = 1;
305 std::string basename = CORE().setcache->get("firmwarepath") + "/" + bios;
306 romimg[0] = fileimage::image(lsnes_image_hasher, basename, "",
307 xlate_info(coretype->get_image_info(0)));
308 if(zip::file_exists(basename + ".xml"))
309 romxml[0] = fileimage::image(lsnes_image_hasher, basename + ".xml", "",
310 get_xml_info());
311 pmand |= rtype->get_image_info(0).mandatory;
313 romimg[romidx] = fileimage::image(lsnes_image_hasher, file, "",
314 xlate_info(coretype->get_image_info(romidx)));
315 if(zip::file_exists(file + ".xml"))
316 romxml[romidx] = fileimage::image(lsnes_image_hasher, file + ".xml", "", get_xml_info());
317 pmand |= rtype->get_image_info(romidx).mandatory;
318 msu1_base = zip::resolverel(file, "");
319 record_files(*this);
320 if(pmand != tmand)
321 throw std::runtime_error("Required ROM images missing");
322 return;
324 load_filename = file;
325 std::vector<std::string> lines;
326 while(std::getline(spec, s))
327 lines.push_back(strip_CR(s));
328 std::string platname = "";
329 std::string platreg = "";
330 for(auto i : lines) {
331 regex_results tmp;
332 if(tmp = regex("type[ \t]+(.+)", i))
333 platname = tmp[1];
334 if(tmp = regex("region[ \t]+(.+)", i))
335 platreg = tmp[1];
338 //Detect type.
339 rtype = find_core_by_name(platname, tmpprefer);
340 if(!rtype)
341 (stringfmt() << "Not a valid system type '" << platname << "'").throwex();
343 //Detect region.
344 bool goodreg = false;
345 orig_region = &rtype->get_preferred_region();
346 for(auto i: rtype->get_regions())
347 if(i->get_iname() == platreg) {
348 orig_region = i;
349 goodreg = true;
351 if(!goodreg && platreg != "")
352 (stringfmt() << "Not a valid system region '" << platreg << "'").throwex();
353 region = orig_region;
355 //ROM files.
356 std::string cromimg[ROM_SLOT_COUNT];
357 std::string cromxml[ROM_SLOT_COUNT];
358 for(auto i : lines) {
359 regex_results tmp;
360 if(!(tmp = regex("(rom|xml)[ \t]+([^ \t]+)[ \t]+(.*)", i)))
361 continue;
362 size_t idxs = rtype->get_image_count();
363 size_t idx = idxs;
364 for(size_t i = 0; i < idxs; i++)
365 if(rtype->get_image_info(i).iname == tmp[2])
366 idx = i;
367 if(idx == idxs)
368 (stringfmt() << "Not a valid ROM name '" << tmp[2] << "'").throwex();
369 if(tmp[1] == "rom")
370 cromimg[idx] = tmp[3];
371 else
372 cromxml[idx] = tmp[3];
375 //Check ROMs.
376 unsigned mask1 = 0, mask2 = 0;
377 for(size_t i = 0; i < rtype->get_image_count(); i++) {
378 auto ii = rtype->get_image_info(i);
379 mask1 |= ii.mandatory;
380 if(cromimg[i] != "")
381 mask2 |= ii.mandatory;
382 if(cromimg[i] == "" && cromxml[i] != "") {
383 messages << "WARNING: Slot " << ii.iname << ": XML without ROM." << std::endl;
384 cromxml[i] = "";
387 if(mask1 != mask2)
388 throw std::runtime_error("Required ROM missing");
390 //Load ROMs.
391 for(size_t i = 0; i < rtype->get_image_count(); i++) {
392 romimg[i] = fileimage::image(lsnes_image_hasher, cromimg[i], file,
393 xlate_info(rtype->get_image_info(i)));
394 romxml[i] = fileimage::image(lsnes_image_hasher, cromxml[i], file, get_xml_info());
396 record_files(*this); //Have to do this before patching.
398 //Patch ROMs.
399 for(auto i : lines) {
400 regex_results tmp;
401 if(!(tmp = regex("patch([+-][0-9]+)?[ \t]+([^ \t]+)[ \t]+(.*)", i)))
402 continue;
403 size_t idxs = rtype->get_image_count();
404 size_t idx = idxs;
405 for(size_t i = 0; i < idxs; i++)
406 if(rtype->get_image_info(i).iname == tmp[2])
407 idx = i;
408 if(idx == idxs)
409 (stringfmt() << "Not a valid ROM name '" << tmp[2] << "'").throwex();
410 int32_t offset = 0;
411 if(tmp[1] != "")
412 offset = parse_value<int32_t>(tmp[1]);
413 romimg[idx].patch(zip::readrel(tmp[3], file), offset);
416 //MSU-1 base.
417 if(cromimg[1] != "")
418 msu1_base = zip::resolverel(cromimg[1], file);
419 else
420 msu1_base = zip::resolverel(cromimg[0], file);
423 namespace
425 bool filter_by_core(core_type& ctype, const std::string& core)
427 return (core == "" || ctype.get_core_identifier() == core);
430 bool filter_by_type(core_type& ctype, const std::string& type)
432 return (type == "" || ctype.get_iname() == type);
435 bool filter_by_region(core_type& ctype, const std::string& region)
437 if(region == "")
438 return true;
439 for(auto i : ctype.get_regions())
440 if(i->get_iname() == region)
441 return true;
442 return false;
445 bool filter_by_extension(core_type& ctype, const std::string& file)
447 regex_results tmp = regex(".*\\.([^.]*)", file);
448 if(!tmp)
449 return false;
450 std::string ext = tmp[1];
451 return ctype.is_known_extension(ext);
454 bool filter_by_fileset(core_type& ctype, const std::string file[ROM_SLOT_COUNT])
456 uint32_t m = 0, t = 0;
457 for(unsigned i = 0; i < ROM_SLOT_COUNT; i++) {
458 if(i >= ctype.get_image_count() && file[i] != "")
459 return false;
460 auto s = ctype.get_image_info(i);
461 if(file[i] != "")
462 m |= s.mandatory;
463 t |= s.mandatory;
465 return (m == t);
468 core_region* detect_region(core_type* t, const std::string& region)
470 core_region* r = NULL;
471 for(auto i: t->get_regions())
472 if(i->get_iname() == region)
473 r = i;
474 if(!r && region != "")
475 (stringfmt() << "Not a valid system region '" << region << "'").throwex();
476 if(!r) r = &t->get_preferred_region(); //Default region.
477 return r;
481 loaded_rom::loaded_rom(const std::string& file, const std::string& core, const std::string& type,
482 const std::string& _region)
484 core_type* t = NULL;
485 core_region* r = NULL;
486 bool fullspec = (core != "" && type != "");
487 for(auto i : core_type::get_core_types()) {
488 if(!filter_by_core(*i, core))
489 continue;
490 if(!filter_by_type(*i, type))
491 continue;
492 if(!fullspec && !filter_by_region(*i, _region))
493 continue;
494 if(!fullspec && !filter_by_extension(*i, file))
495 continue;
496 t = i;
498 if(!t) throw std::runtime_error("No matching core found");
499 r = detect_region(t, _region);
500 unsigned pmand = 0, tmand = 0;
501 for(unsigned i = 0; i < t->get_image_count(); i++)
502 tmand |= t->get_image_info(i).mandatory;
503 std::string bios = t->get_biosname();
504 unsigned romidx = (bios != "") ? 1 : 0;
505 if(bios != "") {
506 std::string basename = CORE().setcache->get("firmwarepath") + "/" + bios;
507 romimg[0] = fileimage::image(lsnes_image_hasher, basename, "", xlate_info(t->get_image_info(0)));
508 if(zip::file_exists(basename + ".xml"))
509 romxml[0] = fileimage::image(lsnes_image_hasher, basename + ".xml", "", get_xml_info());
510 pmand |= t->get_image_info(0).mandatory;
512 romimg[romidx] = fileimage::image(lsnes_image_hasher, file, "", xlate_info(t->get_image_info(romidx)));
513 if(zip::file_exists(file + ".xml"))
514 romxml[romidx] = fileimage::image(lsnes_image_hasher, file + ".xml", "", get_xml_info());
515 pmand |= t->get_image_info(romidx).mandatory;
516 msu1_base = zip::resolverel(file, "");
517 record_files(*this);
518 if(pmand != tmand)
519 throw std::runtime_error("Required ROM images missing");
520 rtype = t;
521 orig_region = region = r;
524 loaded_rom::loaded_rom(const std::string file[ROM_SLOT_COUNT], const std::string& core, const std::string& type,
525 const std::string& _region)
527 core_type* t = NULL;
528 core_region* r = NULL;
529 bool fullspec = (core != "" && type != "");
530 for(auto i : core_type::get_core_types()) {
531 if(!filter_by_core(*i, core)) {
532 continue;
534 if(!filter_by_type(*i, type)) {
535 continue;
537 if(!fullspec && !filter_by_region(*i, _region)) {
538 continue;
540 if(!fullspec && !filter_by_fileset(*i, file)) {
541 continue;
543 t = i;
545 if(!t) throw std::runtime_error("No matching core found");
546 r = detect_region(t, _region);
547 std::string bios = t->get_biosname();
548 unsigned romidx = (bios != "") ? 1 : 0;
549 unsigned pmand = 0, tmand = 0;
550 for(unsigned i = 0; i < 27; i++) {
551 if(i >= t->get_image_count())
552 continue;
553 if(file[i] != "")
554 pmand |= t->get_image_info(i).mandatory;
555 tmand |= t->get_image_info(i).mandatory;
556 romimg[i] = fileimage::image(lsnes_image_hasher, file[i], "", xlate_info(t->get_image_info(i)));
557 if(zip::file_exists(file[i] + ".xml"))
558 romxml[i] = fileimage::image(lsnes_image_hasher, file[i] + ".xml", "", get_xml_info());
560 msu1_base = zip::resolverel(file[romidx], "");
561 record_files(*this);
562 if(pmand != tmand)
563 throw std::runtime_error("Required ROM images missing");
564 rtype = t;
565 orig_region = region = r;
568 void loaded_rom::load(std::map<std::string, std::string>& settings, uint64_t rtc_sec, uint64_t rtc_subsec)
569 throw(std::bad_alloc, std::runtime_error)
571 auto& core = CORE();
572 core_type* old_type = current_rom_type;
573 core_core* old_core = current_rom_type->get_core();
574 current_rom_type = &core_null;
575 if(!orig_region && rtype != &core_null)
576 orig_region = &rtype->get_preferred_region();
577 if(!region)
578 region = orig_region;
579 if(rtype && !orig_region->compatible_with(*region))
580 throw std::runtime_error("Trying to force incompatible region");
581 if(rtype && !rtype->set_region(*region))
582 throw std::runtime_error("Trying to force unknown region");
584 core_romimage images[ROM_SLOT_COUNT];
585 for(size_t i = 0; i < ROM_SLOT_COUNT; i++) {
586 images[i].markup = (const char*)romxml[i];
587 images[i].data = (const unsigned char*)romimg[i];
588 images[i].size = (size_t)romimg[i];
590 if(!rtype->load(images, settings, rtc_sec, rtc_subsec))
591 throw std::runtime_error("Can't load cartridge ROM");
593 region = &rtype->get_region();
594 rtype->power();
595 auto nominal_fps = rtype->get_video_rate();
596 auto nominal_hz = rtype->get_audio_rate();
597 core.framerate->set_nominal_framerate(1.0 * nominal_fps.first / nominal_fps.second);
598 core.mdumper->on_rate_change(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 (*core.cmapper)();
609 core.dispatch->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(*CORE().settings)) {
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;