2 #include <snes/snes.hpp>
9 #include <boost/iostreams/categories.hpp>
10 #include <boost/iostreams/copy.hpp>
11 #include <boost/iostreams/stream.hpp>
12 #include <boost/iostreams/stream_buffer.hpp>
13 #include <boost/iostreams/filter/symmetric.hpp>
14 #include <boost/iostreams/filter/zlib.hpp>
15 #include <boost/iostreams/filtering_stream.hpp>
16 #include <boost/iostreams/device/back_inserter.hpp>
18 #include "command.hpp"
19 #include "fieldsplit.hpp"
22 #include "memorymanip.hpp"
28 typedef uint8_t uint8
;
29 typedef uint16_t uint16
;
30 typedef uint32_t uint32
;
32 typedef int16_t int16
;
33 typedef int32_t int32
;
34 #include <nall/platform.hpp>
35 #include <nall/endian.hpp>
36 #include <nall/varint.hpp>
37 #include <nall/bit.hpp>
38 #include <nall/serializer.hpp>
39 #include <nall/property.hpp>
41 #include <ui-libsnes/libsnes.hpp>
43 //Some anti-typo defs.
44 #define SNES_TYPE "snes"
45 #define SNES_PAL "snes_pal"
46 #define SNES_NTSC "snes_ntsc"
48 #define BSXSLOTTED "bsxslotted"
49 #define SUFAMITURBO "sufamiturbo"
50 #define SGB_TYPE "SGB"
51 #define SGB_PAL "sgb_pal"
52 #define SGB_NTSC "sgb_ntsc"
54 void strip_CR(std::string
& x
);
56 std::string
gtype::tostring(rom_type rtype
, rom_region region
) throw(std::bad_alloc
, std::runtime_error
)
61 case REGION_AUTO
: return "snes";
62 case REGION_NTSC
: return "snes_ntsc";
63 case REGION_PAL
: return "snes_pal";
67 case REGION_AUTO
: return "sgb";
68 case REGION_NTSC
: return "sgb_ntsc";
69 case REGION_PAL
: return "sgb_pal";
71 case ROMTYPE_BSX
: return "bsx";
72 case ROMTYPE_BSXSLOTTED
: return "bsxslotted";
73 case ROMTYPE_SUFAMITURBO
: return "sufamiturbo";
74 default: throw std::runtime_error("tostring: ROMTYPE_NONE");
78 std::string
gtype::tostring(gametype_t gametype
) throw(std::bad_alloc
, std::runtime_error
)
81 case GT_SNES_NTSC
: return "snes_ntsc";
82 case GT_SNES_PAL
: return "snes_pal";
83 case GT_SGB_NTSC
: return "sgb_ntsc";
84 case GT_SGB_PAL
: return "sgb_pal";
85 case GT_BSX
: return "bsx";
86 case GT_BSX_SLOTTED
: return "bsxslotted";
87 case GT_SUFAMITURBO
: return "sufamiturbo";
88 default: throw std::runtime_error("tostring: GT_INVALID");
92 gametype_t
gtype::togametype(rom_type rtype
, rom_region region
) throw(std::bad_alloc
, std::runtime_error
)
97 case REGION_AUTO
: return GT_SGB_NTSC
;
98 case REGION_NTSC
: return GT_SNES_NTSC
;
99 case REGION_PAL
: return GT_SNES_PAL
;
103 case REGION_AUTO
: return GT_SGB_NTSC
;
104 case REGION_NTSC
: return GT_SGB_NTSC
;
105 case REGION_PAL
: return GT_SGB_PAL
;
107 case ROMTYPE_BSX
: return GT_BSX
;
108 case ROMTYPE_BSXSLOTTED
: return GT_BSX_SLOTTED
;
109 case ROMTYPE_SUFAMITURBO
: return GT_SUFAMITURBO
;
110 default: throw std::runtime_error("togametype: ROMTYPE_NONE");
114 gametype_t
gtype::togametype(const std::string
& gametype
) throw(std::bad_alloc
, std::runtime_error
)
116 if(gametype
== "snes_ntsc")
118 if(gametype
== "snes_pal")
120 if(gametype
== "sgb_ntsc")
122 if(gametype
== "sgb_pal")
124 if(gametype
== "bsx")
126 if(gametype
== "bsxslotted")
127 return GT_BSX_SLOTTED
;
128 if(gametype
== "sufamiturbo")
129 return GT_SUFAMITURBO
;
130 throw std::runtime_error("Unknown game type '" + gametype
+ "'");
133 rom_type
gtype::toromtype(const std::string
& gametype
) throw(std::bad_alloc
, std::runtime_error
)
135 if(gametype
== "snes_ntsc")
137 if(gametype
== "snes_pal")
139 if(gametype
== "snes")
141 if(gametype
== "sgb_ntsc")
143 if(gametype
== "sgb_pal")
145 if(gametype
== "sgb")
147 if(gametype
== "bsx")
149 if(gametype
== "bsxslotted")
150 return ROMTYPE_BSXSLOTTED
;
151 if(gametype
== "sufamiturbo")
152 return ROMTYPE_SUFAMITURBO
;
153 throw std::runtime_error("Unknown game type '" + gametype
+ "'");
156 rom_type
gtype::toromtype(gametype_t gametype
) throw()
159 case GT_SNES_NTSC
: return ROMTYPE_SNES
;
160 case GT_SNES_PAL
: return ROMTYPE_SNES
;
161 case GT_SGB_NTSC
: return ROMTYPE_SGB
;
162 case GT_SGB_PAL
: return ROMTYPE_SGB
;
163 case GT_BSX
: return ROMTYPE_BSX
;
164 case GT_BSX_SLOTTED
: return ROMTYPE_BSXSLOTTED
;
165 case GT_SUFAMITURBO
: return ROMTYPE_SUFAMITURBO
;
166 case GT_INVALID
: throw std::runtime_error("toromtype: GT_INVALID");
170 rom_region
gtype::toromregion(const std::string
& gametype
) throw(std::bad_alloc
, std::runtime_error
)
172 if(gametype
== "snes_ntsc")
174 if(gametype
== "snes_pal")
176 if(gametype
== "snes")
178 if(gametype
== "sgb_ntsc")
180 if(gametype
== "sgb_pal")
182 if(gametype
== "sgb")
184 if(gametype
== "bsx")
186 if(gametype
== "bsxslotted")
188 if(gametype
== "sufamiturbo")
190 throw std::runtime_error("Unknown game type '" + gametype
+ "'");
193 rom_region
gtype::toromregion(gametype_t gametype
) throw()
196 case GT_SNES_NTSC
: return REGION_NTSC
;
197 case GT_SNES_PAL
: return REGION_PAL
;
198 case GT_SGB_NTSC
: return REGION_NTSC
;
199 case GT_SGB_PAL
: return REGION_PAL
;
200 case GT_BSX
: return REGION_NTSC
;
201 case GT_BSX_SLOTTED
: return REGION_NTSC
;
202 case GT_SUFAMITURBO
: return REGION_NTSC
;
203 case GT_INVALID
: throw std::runtime_error("toromregion: GT_INVALID");
210 bool option_set(const std::vector
<std::string
>& cmdline
, const std::string
& option
)
212 for(auto i
= cmdline
.begin(); i
!= cmdline
.end(); i
++)
218 const char* romtypes_to_recognize
[] = {
219 "rom", "bsx", "bsxslotted", "dmg", "slot-a", "slot-b",
220 "rom-xml", "bsx-xml", "bsxslotted-xml", "dmg-xml", "slot-a-xml", "slot-b-xml"
223 enum rom_type current_rom_type
= ROMTYPE_NONE
;
224 enum rom_region current_region
= REGION_NTSC
;
226 uint64_t readval(const std::vector
<char>& patch
, size_t offset
, size_t vsize
) throw(std::runtime_error
)
228 if(offset
>= patch
.size() || offset
+ vsize
> patch
.size())
229 throw std::runtime_error("IPS file corrupt");
231 for(size_t i
= 0; i
< vsize
; i
++)
232 val
= (val
<< 8) | static_cast<uint8_t>(patch
[offset
+ i
]);
236 std::string
findoption(const std::vector
<std::string
>& cmdline
, const std::string
& option
)
239 for(auto i
= cmdline
.begin(); i
!= cmdline
.end(); ++i
) {
240 std::string arg
= *i
;
241 if(arg
.length() < 3 + option
.length())
243 if(arg
[0] != '-' || arg
[1] != '-' || arg
.substr(2, option
.length()) != option
||
244 arg
[2 + option
.length()] != '=')
247 value
= arg
.substr(3 + option
.length());
249 std::cerr
<< "WARNING: Ignored duplicate option for '" << option
<< "'." << std::endl
;
251 throw std::runtime_error("Empty value for '" + option
+ "' is not allowed");
258 loaded_slot::loaded_slot() throw(std::bad_alloc
)
263 loaded_slot::loaded_slot(const std::string
& filename
, const std::string
& base
, bool xml_flag
) throw(std::bad_alloc
,
272 data
= read_file_relative(filename
, base
);
273 sha256
= sha256::hash(data
);
275 size_t osize
= data
.size();
276 data
.resize(osize
+ 1);
281 void loaded_slot::patch(const std::vector
<char>& patch
, int32_t offset
) throw(std::bad_alloc
, std::runtime_error
)
283 bool warned_extend
= false;
284 bool warned_negative
= false;
287 data
.resize(data
.size() - 1);
288 if(readval(patch
, poffset
, 5) != 0x5041544348)
289 throw std::runtime_error("Bad IPS file magic");
292 uint64_t addr
= readval(patch
, poffset
, 3);
295 uint64_t len
= readval(patch
, poffset
+ 3, 2);
302 roffset
= poffset
+ 5;
305 //RLE block. Read real size first.
306 len
= readval(patch
, poffset
+ 5, 2);
308 roffset
= poffset
+ 7;
311 for(uint64_t i
= 0; i
< len
; i
++) {
312 int64_t baddr
= addr
+ i
+ offset
;
315 std::cerr
<< "WARNING: IPS patch tries to modify negative offset. "
316 << "Bad patch or offset?" << std::endl
;
317 warned_negative
= true;
319 } else if(baddr
>= static_cast<int64_t>(data
.size())) {
321 std::cerr
<< "WARNING: IPS patch tries to extend the ROM. "
322 << "Bad patch or offset? " << std::endl
;
323 warned_extend
= true;
324 size_t oldsize
= data
.size();
325 data
.resize(baddr
+ 1);
326 for(size_t j
= oldsize
; j
<= static_cast<uint64_t>(baddr
); j
++)
329 size_t srcoff
= roffset
+ readstride
* i
;
330 if(srcoff
>= patch
.size())
331 throw std::runtime_error("Corrupt IPS patch");
332 data
[baddr
] = static_cast<uint8_t>(patch
[srcoff
]);
336 //Mark the slot as valid and update hash.
338 sha256
= sha256::hash(data
);
340 size_t osize
= data
.size();
341 data
.resize(osize
+ 1);
346 rom_files::rom_files() throw()
348 rtype
= ROMTYPE_NONE
;
349 region
= REGION_AUTO
;
353 rom_files::rom_files(const std::vector
<std::string
>& cmdline
, window
* win
) throw(std::bad_alloc
, std::runtime_error
)
355 rom
= rom_xml
= slota
= slota_xml
= slotb
= slotb_xml
= "";
356 std::string arr
[sizeof(romtypes_to_recognize
) / sizeof(romtypes_to_recognize
[0])];
357 unsigned long flags
= 0;
358 for(size_t i
= 0; i
< sizeof(romtypes_to_recognize
) / sizeof(romtypes_to_recognize
[0]); i
++) {
359 arr
[i
] = findoption(cmdline
, romtypes_to_recognize
[i
]);
363 rtype
= recognize_platform(flags
);
364 for(size_t i
= 0; i
< sizeof(romtypes_to_recognize
) / sizeof(romtypes_to_recognize
[0]); i
++) {
366 switch(recognize_commandline_rom(rtype
, romtypes_to_recognize
[i
])) {
367 case 0: rom
= arr
[i
]; break;
368 case 1: rom_xml
= arr
[i
]; break;
369 case 2: slota
= arr
[i
]; break;
370 case 3: slota_xml
= arr
[i
]; break;
371 case 4: slotb
= arr
[i
]; break;
372 case 5: slotb_xml
= arr
[i
]; break;
375 region
= (rtype
== ROMTYPE_SGB
|| rtype
== ROMTYPE_SNES
) ? REGION_AUTO
: REGION_NTSC
;
376 if(option_set(cmdline
, "--ntsc"))
377 region
= REGION_NTSC
;
378 else if(option_set(cmdline
, "--pal"))
384 void rom_files::resolve_relative() throw(std::bad_alloc
, std::runtime_error
)
386 rom
= resolve_file_relative(rom
, base_file
);
387 rom_xml
= resolve_file_relative(rom_xml
, base_file
);
388 slota
= resolve_file_relative(slota
, base_file
);
389 slota_xml
= resolve_file_relative(slota_xml
, base_file
);
390 slotb
= resolve_file_relative(slotb
, base_file
);
391 slotb_xml
= resolve_file_relative(slotb_xml
, base_file
);
396 std::pair
<enum rom_type
, enum rom_region
> get_current_rom_info() throw()
398 return std::make_pair(current_rom_type
, current_region
);
401 loaded_rom::loaded_rom() throw()
403 rtype
= ROMTYPE_NONE
;
404 region
= orig_region
= REGION_AUTO
;
407 loaded_rom::loaded_rom(const rom_files
& files
, window
* win
) throw(std::bad_alloc
, std::runtime_error
)
409 std::string _slota
= files
.slota
;
410 std::string _slota_xml
= files
.slota_xml
;
411 std::string _slotb
= files
.slotb
;
412 std::string _slotb_xml
= files
.slotb_xml
;
413 if(files
.rtype
== ROMTYPE_NONE
) {
414 rtype
= ROMTYPE_NONE
;
415 region
= orig_region
= files
.region
;
418 if((_slota
!= "" || _slota_xml
!= "") && files
.rtype
== ROMTYPE_SNES
) {
419 out(win
) << "WARNING: SNES takes only 1 ROM image" << std::endl
;
423 if((_slotb
!= "" || _slotb_xml
!= "") && files
.rtype
!= ROMTYPE_SUFAMITURBO
) {
424 out(win
) << "WARNING: Only Sufami Turbo takes 3 ROM images" << std::endl
;
428 if(files
.rom_xml
!= "" && files
.rom
== "")
429 out(win
) << "WARNING: " << name_subrom(files
.rtype
, 0) << " specified without corresponding "
430 << name_subrom(files
.rtype
, 1) << std::endl
;
431 if(_slota_xml
!= "" && _slota
== "")
432 out(win
) << "WARNING: " << name_subrom(files
.rtype
, 2) << " specified without corresponding "
433 << name_subrom(files
.rtype
, 3) << std::endl
;
434 if(_slotb_xml
!= "" && _slotb
== "")
435 out(win
) << "WARNING: " << name_subrom(files
.rtype
, 4) << " specified without corresponding "
436 << name_subrom(files
.rtype
, 5) << std::endl
;
439 rom
= loaded_slot(files
.rom
, files
.base_file
);
440 rom_xml
= loaded_slot(files
.rom_xml
, files
.base_file
, true);
441 slota
= loaded_slot(_slota
, files
.base_file
);
442 slota_xml
= loaded_slot(_slota_xml
, files
.base_file
, true);
443 slotb
= loaded_slot(_slotb
, files
.base_file
);
444 slotb_xml
= loaded_slot(_slotb_xml
, files
.base_file
, true);
445 orig_region
= region
= files
.region
;
448 void loaded_rom::load() throw(std::bad_alloc
, std::runtime_error
)
450 current_rom_type
= ROMTYPE_NONE
;
451 if(region
== REGION_AUTO
&& orig_region
!= REGION_AUTO
)
452 region
= orig_region
;
453 if(region
!= orig_region
&& orig_region
!= REGION_AUTO
)
454 throw std::runtime_error("Trying to force incompatible region");
455 if(rtype
== ROMTYPE_NONE
)
456 throw std::runtime_error("Can't insert cartridge of type NONE!");
459 config
.region
= System::Region::Autodetect
;
462 config
.region
= System::Region::NTSC
;
465 config
.region
= System::Region::PAL
;
468 throw std::runtime_error("Trying to force unknown region");
472 if(!snes_load_cartridge_normal(rom_xml
, rom
, rom
))
473 throw std::runtime_error("Can't load cartridge ROM");
476 if(region
== REGION_PAL
)
477 throw std::runtime_error("BSX can't be PAL");
478 if(!snes_load_cartridge_bsx(rom_xml
, rom
, rom
, slota_xml
, slota
, slota
))
479 throw std::runtime_error("Can't load cartridge ROM");
481 case ROMTYPE_BSXSLOTTED
:
482 if(region
== REGION_PAL
)
483 throw std::runtime_error("Slotted BSX can't be PAL");
484 if(!snes_load_cartridge_bsx_slotted(rom_xml
, rom
, rom
, slota_xml
, slota
, slota
))
485 throw std::runtime_error("Can't load cartridge ROM");
488 if(!snes_load_cartridge_super_game_boy(rom_xml
, rom
, rom
, slota_xml
, slota
, slota
))
489 throw std::runtime_error("Can't load cartridge ROM");
491 case ROMTYPE_SUFAMITURBO
:
492 if(region
== REGION_PAL
)
493 throw std::runtime_error("Sufami Turbo can't be PAL");
494 if(!snes_load_cartridge_sufami_turbo(rom_xml
, rom
, rom
, slota_xml
, slota
, slota
, slotb_xml
, slotb
,
496 throw std::runtime_error("Can't load cartridge ROM");
499 throw std::runtime_error("Unknown cartridge type");
501 if(region
== REGION_AUTO
)
502 region
= snes_get_region() ? REGION_PAL
: REGION_NTSC
;
504 current_rom_type
= rtype
;
505 current_region
= region
;
506 refresh_cart_mappings();
509 void loaded_rom::do_patch(const std::vector
<std::string
>& cmdline
, window
* win
) throw(std::bad_alloc
,
513 for(auto i
= cmdline
.begin(); i
!= cmdline
.end(); i
++) {
514 std::string opt
= *i
;
515 if(opt
.length() >= 13 && opt
.substr(0, 13) == "--ips-offset=") {
517 offset
= parse_value
<int32_t>(opt
.substr(13));
518 } catch(std::exception
& e
) {
519 throw std::runtime_error("Invalid IPS offset option '" + opt
+ "': " + e
.what());
523 if(opt
.length() < 6 || opt
.substr(0, 6) != "--ips-")
525 size_t split
= opt
.find_first_of("=");
526 if(split
> opt
.length())
527 throw std::runtime_error("Invalid IPS patch argument '" + opt
+ "'");
528 std::string kind
= opt
.substr(6, split
- 6);
529 std::string filename
= opt
.substr(split
+ 1);
530 out(win
) << "Patching " << kind
<< " using '" << filename
<< "'" << std::endl
;
531 std::vector
<char> ips
;
533 ips
= read_file_relative(filename
, "");
534 } catch(std::bad_alloc
& e
) {
536 } catch(std::exception
& e
) {
537 throw std::runtime_error("Can't read IPS '" + filename
+ "': " + e
.what());
540 switch(recognize_commandline_rom(rtype
, kind
)) {
541 case 0: rom
.patch(ips
, offset
); break;
542 case 1: rom_xml
.patch(ips
, offset
); break;
543 case 2: slota
.patch(ips
, offset
); break;
544 case 3: slota_xml
.patch(ips
, offset
); break;
545 case 4: slotb
.patch(ips
, offset
); break;
546 case 5: slotb_xml
.patch(ips
, offset
); break;
548 throw std::runtime_error("Invalid subROM '" + kind
+ "' to patch");
550 } catch(std::bad_alloc
& e
) {
552 } catch(std::exception
& e
) {
553 throw std::runtime_error("Can't Patch with IPS '" + filename
+ "': " + e
.what());
560 std::string
sram_name(const nall::string
& _id
, Cartridge::Slot slotname
)
562 std::string
id(_id
, _id
.length());
563 if(slotname
== Cartridge::Slot::SufamiTurboA
)
564 return "slota." + id
.substr(1);
565 if(slotname
== Cartridge::Slot::SufamiTurboB
)
566 return "slotb." + id
.substr(1);
571 std::map
<std::string
, std::vector
<char>> save_sram() throw(std::bad_alloc
)
573 std::map
<std::string
, std::vector
<char>> out
;
574 for(unsigned i
= 0; i
< cartridge
.nvram
.size(); i
++) {
575 Cartridge::NonVolatileRAM
& r
= cartridge
.nvram
[i
];
576 std::string savename
= sram_name(r
.id
, r
.slot
);
579 memcpy(&x
[0], r
.data
, r
.size
);
585 void load_sram(std::map
<std::string
, std::vector
<char>>& sram
, window
* win
) throw(std::bad_alloc
)
587 std::set
<std::string
> used
;
590 for(unsigned i
= 0; i
< cartridge
.nvram
.size(); i
++) {
591 Cartridge::NonVolatileRAM
& r
= cartridge
.nvram
[i
];
592 std::string savename
= sram_name(r
.id
, r
.slot
);
593 if(sram
.count(savename
)) {
594 std::vector
<char>& x
= sram
[savename
];
595 if(r
.size
!= x
.size())
596 out(win
) << "WARNING: SRAM '" << savename
<< "': Loaded " << x
.size() << " bytes, "
597 << " but the SRAM is " << r
.size
<< "." << std::endl
;
598 memcpy(r
.data
, &x
[0], (r
.size
< x
.size()) ? r
.size
: x
.size());
599 used
.insert(savename
);
601 out(win
) << "WARNING: SRAM '" << savename
<< ": No data." << std::endl
;
603 for(auto i
= sram
.begin(); i
!= sram
.end(); ++i
)
604 if(!used
.count(i
->first
))
605 out(win
) << "WARNING: SRAM '" << i
->first
<< ": Not found on cartridge." << std::endl
;
608 std::map
<std::string
, std::vector
<char>> load_sram_commandline(const std::vector
<std::string
>& cmdline
)
609 throw(std::bad_alloc
, std::runtime_error
)
611 std::map
<std::string
, std::vector
<char>> ret
;
612 for(auto i
= cmdline
.begin(); i
!= cmdline
.end(); i
++) {
613 std::string opt
= *i
;
614 if(opt
.length() >= 11 && opt
.substr(0, 11) == "--continue=") {
615 size_t split
= opt
.find_first_of("=");
616 if(split
> opt
.length() - 1)
617 throw std::runtime_error("Bad SRAM option '" + opt
+ "'");
618 std::string file
= opt
.substr(split
+ 1);
620 for(auto j
= r
.begin(); j
!= r
.end(); j
++) {
621 std::string fname
= *j
;
622 if(fname
.length() < 6 || fname
.substr(0, 5) != "sram.")
624 std::istream
& x
= r
[fname
];
626 std::vector
<char> out
;
627 boost::iostreams::back_insert_device
<std::vector
<char>> rd(out
);
628 boost::iostreams::copy(x
, rd
);
630 ret
[fname
.substr(5, split
- 5)] = out
;
638 if(opt
.length() < 8 || opt
.substr(0, 7) != "--sram-")
640 size_t split
= opt
.find_first_of("=");
641 if(split
> opt
.length() - 1)
642 throw std::runtime_error("Bad SRAM option '" + opt
+ "'");
643 std::string kind
= opt
.substr(7, split
- 7);
644 std::string file
= opt
.substr(split
+ 1);
646 throw std::runtime_error("Bad SRAM option '" + opt
+ "'");
648 ret
[kind
] = read_file_relative(file
, "");
649 } catch(std::bad_alloc
& e
) {
651 } catch(std::runtime_error
& e
) {
652 throw std::runtime_error("Can't load SRAM '" + kind
+ "': " + e
.what());
658 void emulate_frame() throw()
663 void reset_snes() throw()
665 SNES::system
.reset();
668 std::vector
<char> save_core_state() throw(std::bad_alloc
)
670 SNES::system
.runtosave();
671 std::vector
<char> ret
;
672 serializer s
= SNES::system
.serialize();
673 ret
.resize(s
.size());
674 memcpy(&ret
[0], s
.data(), s
.size());
675 size_t offset
= ret
.size();
676 unsigned char tmp
[32];
677 sha256::hash(tmp
, ret
);
678 ret
.resize(offset
+ 32);
679 memcpy(&ret
[offset
], tmp
, 32);
683 void load_core_state(const std::vector
<char>& buf
) throw(std::runtime_error
)
686 throw std::runtime_error("Savestate corrupt");
687 unsigned char tmp
[32];
688 sha256::hash(tmp
, reinterpret_cast<const uint8_t*>(&buf
[0]), buf
.size() - 32);
689 if(memcmp(tmp
, &buf
[buf
.size() - 32], 32))
690 throw std::runtime_error("Savestate corrupt");
691 serializer
s(reinterpret_cast<const uint8_t*>(&buf
[0]), buf
.size() - 32);
692 if(!SNES::system
.unserialize(s
))
693 throw std::runtime_error("SNES core rejected savestate");
704 std::list
<index_entry
> rom_index
;
706 void replace_index(std::list
<index_entry
> new_index
, const std::string
& source
)
708 std::list
<index_entry
> tmp_index
;
709 for(auto i
= rom_index
.begin(); i
!= rom_index
.end(); i
++) {
710 if(i
->from
!= source
)
711 tmp_index
.push_back(*i
);
713 for(auto i
= new_index
.begin(); i
!= new_index
.end(); i
++) {
714 tmp_index
.push_back(*i
);
716 rom_index
= new_index
;
720 void load_index_file(const std::string
& filename
) throw(std::bad_alloc
, std::runtime_error
)
722 std::istream
& s
= open_file_relative(filename
, "");
725 std::list
<index_entry
> partial_index
;
727 while(std::getline(s
, line
)) {
731 tokensplitter
t(line
);
732 e
.hash
= static_cast<std::string
>(t
);
733 e
.relpath
= t
.tail();
735 if(e
.hash
.length() != 64 || e
.relpath
== "")
736 throw std::runtime_error("Bad index file");
737 partial_index
.push_back(e
);
739 replace_index(partial_index
, filename
);
747 std::string
lookup_file_by_sha256(const std::string
& hash
) throw(std::bad_alloc
, std::runtime_error
)
751 for(auto i
= rom_index
.begin(); i
!= rom_index
.end(); i
++) {
755 std::istream
& o
= open_file_relative(i
->relpath
, i
->from
);
757 return resolve_file_relative(i
->relpath
, i
->from
);
762 throw std::runtime_error("No file with hash '" + hash
+ "' found in known indices");
765 std::string
name_subrom(enum rom_type major
, unsigned romnumber
) throw(std::bad_alloc
)
769 else if(romnumber
== 1)
771 else if(major
== ROMTYPE_BSX
&& romnumber
== 2)
773 else if(major
== ROMTYPE_BSX
&& romnumber
== 3)
775 else if(major
== ROMTYPE_BSXSLOTTED
&& romnumber
== 2)
777 else if(major
== ROMTYPE_BSXSLOTTED
&& romnumber
== 3)
779 else if(major
== ROMTYPE_SGB
&& romnumber
== 2)
781 else if(major
== ROMTYPE_SGB
&& romnumber
== 3)
783 else if(major
== ROMTYPE_SUFAMITURBO
&& romnumber
== 2)
785 else if(major
== ROMTYPE_SUFAMITURBO
&& romnumber
== 3)
787 else if(major
== ROMTYPE_SUFAMITURBO
&& romnumber
== 4)
789 else if(major
== ROMTYPE_SUFAMITURBO
&& romnumber
== 5)
791 else if(romnumber
% 2)
792 return "UNKNOWN XML";
794 return "UNKNOWN ROM";
798 int recognize_commandline_rom(enum rom_type major
, const std::string
& romname
) throw(std::bad_alloc
)
800 if(romname
== romtypes_to_recognize
[0])
802 else if(romname
== romtypes_to_recognize
[6])
804 else if(major
== ROMTYPE_BSX
&& romname
== romtypes_to_recognize
[1])
806 else if(major
== ROMTYPE_BSX
&& romname
== romtypes_to_recognize
[7])
808 else if(major
== ROMTYPE_BSX
&& romname
== romtypes_to_recognize
[2])
810 else if(major
== ROMTYPE_BSX
&& romname
== romtypes_to_recognize
[8])
812 else if(major
== ROMTYPE_SGB
&& romname
== romtypes_to_recognize
[3])
814 else if(major
== ROMTYPE_SGB
&& romname
== romtypes_to_recognize
[9])
816 else if(major
== ROMTYPE_SUFAMITURBO
&& romname
== romtypes_to_recognize
[4])
818 else if(major
== ROMTYPE_SUFAMITURBO
&& romname
== romtypes_to_recognize
[10])
820 else if(major
== ROMTYPE_SUFAMITURBO
&& romname
== romtypes_to_recognize
[5])
822 else if(major
== ROMTYPE_SUFAMITURBO
&& romname
== romtypes_to_recognize
[11])
828 rom_type
recognize_platform(unsigned long flags
) throw(std::bad_alloc
, std::runtime_error
)
830 if((flags
& 07700) >> 6 & ~(flags
& 077))
831 throw std::runtime_error("SubROM XML specified without corresponding subROM");
833 throw std::runtime_error("No SNES main cartridge ROM specified");
834 if((flags
& 077) == 1)
836 if((flags
& 077) == 3)
838 if((flags
& 077) == 5)
839 return ROMTYPE_BSXSLOTTED
;
840 if((flags
& 077) == 9)
842 if((flags
& 060) != 0 && (flags
& 017) == 1)
843 return ROMTYPE_SUFAMITURBO
;
844 throw std::runtime_error("Not valid combination of rom/bsx/bsxslotted/dmg/slot-a/slot-b");