2 #include <snes/snes.hpp>
3 #include <ui-libsnes/libsnes.hpp>
5 #include "core/command.hpp"
6 #include "core/dispatch.hpp"
7 #include "core/framerate.hpp"
8 #include "core/memorymanip.hpp"
9 #include "core/misc.hpp"
10 #include "core/patchrom.hpp"
11 #include "core/rom.hpp"
12 #include "core/window.hpp"
13 #include "library/zip.hpp"
20 #include <boost/iostreams/categories.hpp>
21 #include <boost/iostreams/copy.hpp>
22 #include <boost/iostreams/stream.hpp>
23 #include <boost/iostreams/stream_buffer.hpp>
24 #include <boost/iostreams/filter/symmetric.hpp>
25 #include <boost/iostreams/filter/zlib.hpp>
26 #include <boost/iostreams/filtering_stream.hpp>
27 #include <boost/iostreams/device/back_inserter.hpp>
29 //Some anti-typo defs.
30 #define SNES_TYPE "snes"
31 #define SNES_PAL "snes_pal"
32 #define SNES_NTSC "snes_ntsc"
34 #define BSXSLOTTED "bsxslotted"
35 #define SUFAMITURBO "sufamiturbo"
36 #define SGB_TYPE "SGB"
37 #define SGB_PAL "sgb_pal"
38 #define SGB_NTSC "sgb_ntsc"
40 std::string
gtype::tostring(rom_type rtype
, rom_region region
) throw(std::bad_alloc
, std::runtime_error
)
45 case REGION_AUTO
: return "snes";
46 case REGION_NTSC
: return "snes_ntsc";
47 case REGION_PAL
: return "snes_pal";
51 case REGION_AUTO
: return "sgb";
52 case REGION_NTSC
: return "sgb_ntsc";
53 case REGION_PAL
: return "sgb_pal";
55 case ROMTYPE_BSX
: return "bsx";
56 case ROMTYPE_BSXSLOTTED
: return "bsxslotted";
57 case ROMTYPE_SUFAMITURBO
: return "sufamiturbo";
58 default: throw std::runtime_error("tostring: ROMTYPE_NONE");
62 std::string
gtype::tostring(gametype_t gametype
) throw(std::bad_alloc
, std::runtime_error
)
65 case GT_SNES_NTSC
: return "snes_ntsc";
66 case GT_SNES_PAL
: return "snes_pal";
67 case GT_SGB_NTSC
: return "sgb_ntsc";
68 case GT_SGB_PAL
: return "sgb_pal";
69 case GT_BSX
: return "bsx";
70 case GT_BSX_SLOTTED
: return "bsxslotted";
71 case GT_SUFAMITURBO
: return "sufamiturbo";
72 default: throw std::runtime_error("tostring: GT_INVALID");
76 gametype_t
gtype::togametype(rom_type rtype
, rom_region region
) throw(std::bad_alloc
, std::runtime_error
)
81 case REGION_AUTO
: return GT_SGB_NTSC
;
82 case REGION_NTSC
: return GT_SNES_NTSC
;
83 case REGION_PAL
: return GT_SNES_PAL
;
87 case REGION_AUTO
: return GT_SGB_NTSC
;
88 case REGION_NTSC
: return GT_SGB_NTSC
;
89 case REGION_PAL
: return GT_SGB_PAL
;
91 case ROMTYPE_BSX
: return GT_BSX
;
92 case ROMTYPE_BSXSLOTTED
: return GT_BSX_SLOTTED
;
93 case ROMTYPE_SUFAMITURBO
: return GT_SUFAMITURBO
;
94 default: throw std::runtime_error("togametype: ROMTYPE_NONE");
98 gametype_t
gtype::togametype(const std::string
& gametype
) throw(std::bad_alloc
, std::runtime_error
)
100 if(gametype
== "snes_ntsc")
102 if(gametype
== "snes_pal")
104 if(gametype
== "sgb_ntsc")
106 if(gametype
== "sgb_pal")
108 if(gametype
== "bsx")
110 if(gametype
== "bsxslotted")
111 return GT_BSX_SLOTTED
;
112 if(gametype
== "sufamiturbo")
113 return GT_SUFAMITURBO
;
114 throw std::runtime_error("Unknown game type '" + gametype
+ "'");
117 rom_type
gtype::toromtype(const std::string
& gametype
) throw(std::bad_alloc
, std::runtime_error
)
119 if(gametype
== "snes_ntsc")
121 if(gametype
== "snes_pal")
123 if(gametype
== "snes")
125 if(gametype
== "sgb_ntsc")
127 if(gametype
== "sgb_pal")
129 if(gametype
== "sgb")
131 if(gametype
== "bsx")
133 if(gametype
== "bsxslotted")
134 return ROMTYPE_BSXSLOTTED
;
135 if(gametype
== "sufamiturbo")
136 return ROMTYPE_SUFAMITURBO
;
137 throw std::runtime_error("Unknown game type '" + gametype
+ "'");
140 rom_type
gtype::toromtype(gametype_t gametype
) throw()
143 case GT_SNES_NTSC
: return ROMTYPE_SNES
;
144 case GT_SNES_PAL
: return ROMTYPE_SNES
;
145 case GT_SGB_NTSC
: return ROMTYPE_SGB
;
146 case GT_SGB_PAL
: return ROMTYPE_SGB
;
147 case GT_BSX
: return ROMTYPE_BSX
;
148 case GT_BSX_SLOTTED
: return ROMTYPE_BSXSLOTTED
;
149 case GT_SUFAMITURBO
: return ROMTYPE_SUFAMITURBO
;
150 case GT_INVALID
: throw std::runtime_error("toromtype: GT_INVALID");
154 rom_region
gtype::toromregion(const std::string
& gametype
) throw(std::bad_alloc
, std::runtime_error
)
156 if(gametype
== "snes_ntsc")
158 if(gametype
== "snes_pal")
160 if(gametype
== "snes")
162 if(gametype
== "sgb_ntsc")
164 if(gametype
== "sgb_pal")
166 if(gametype
== "sgb")
168 if(gametype
== "bsx")
170 if(gametype
== "bsxslotted")
172 if(gametype
== "sufamiturbo")
174 throw std::runtime_error("Unknown game type '" + gametype
+ "'");
177 rom_region
gtype::toromregion(gametype_t gametype
) throw()
180 case GT_SNES_NTSC
: return REGION_NTSC
;
181 case GT_SNES_PAL
: return REGION_PAL
;
182 case GT_SGB_NTSC
: return REGION_NTSC
;
183 case GT_SGB_PAL
: return REGION_PAL
;
184 case GT_BSX
: return REGION_NTSC
;
185 case GT_BSX_SLOTTED
: return REGION_NTSC
;
186 case GT_SUFAMITURBO
: return REGION_NTSC
;
187 case GT_INVALID
: throw std::runtime_error("toromregion: GT_INVALID");
194 bool option_set(const std::vector
<std::string
>& cmdline
, const std::string
& option
)
196 for(auto i
: cmdline
)
202 const char* romtypes_to_recognize
[] = {
203 "rom", "bsx", "bsxslotted", "dmg", "slot-a", "slot-b",
204 "rom-xml", "bsx-xml", "bsxslotted-xml", "dmg-xml", "slot-a-xml", "slot-b-xml"
207 enum rom_type current_rom_type
= ROMTYPE_NONE
;
208 enum rom_region current_region
= REGION_NTSC
;
210 std::string
findoption(const std::vector
<std::string
>& cmdline
, const std::string
& option
)
213 for(auto i
: cmdline
) {
215 if(arg
.length() < 3 + option
.length())
217 if(arg
[0] != '-' || arg
[1] != '-' || arg
.substr(2, option
.length()) != option
||
218 arg
[2 + option
.length()] != '=')
221 value
= arg
.substr(3 + option
.length());
223 std::cerr
<< "WARNING: Ignored duplicate option for '" << option
<< "'." << std::endl
;
225 throw std::runtime_error("Empty value for '" + option
+ "' is not allowed");
232 loaded_slot::loaded_slot() throw(std::bad_alloc
)
237 loaded_slot::loaded_slot(const std::string
& filename
, const std::string
& base
, bool xml_flag
)
238 throw(std::bad_alloc
, std::runtime_error
)
240 bool headered
= false;
247 data
= read_file_relative(filename
, base
);
248 if(!xml
&& data
.size() % 1024 == 512)
251 if(headered
&& !xml
) {
252 if(data
.size() >= 512) {
253 memmove(&data
[0], &data
[512], data
.size() - 512);
254 data
.resize(data
.size() - 512);
259 sha256
= sha256::hash(data
);
261 size_t osize
= data
.size();
262 data
.resize(osize
+ 1);
267 void loaded_slot::patch(const std::vector
<char>& patch
, int32_t offset
) throw(std::bad_alloc
, std::runtime_error
)
270 std::vector
<char> data2
= data
;
273 data2
.resize(data2
.size() - 1);
274 data2
= do_patch_file(data2
, patch
, offset
);
275 //Mark the slot as valid and update hash.
277 std::string new_sha256
= sha256::hash(data2
);
279 size_t osize
= data2
.size();
280 data2
.resize(osize
+ 1);
290 rom_files::rom_files() throw()
292 rtype
= ROMTYPE_NONE
;
293 region
= REGION_AUTO
;
297 rom_files::rom_files(const std::vector
<std::string
>& cmdline
) throw(std::bad_alloc
, std::runtime_error
)
299 rom
= rom_xml
= slota
= slota_xml
= slotb
= slotb_xml
= "";
300 std::string arr
[sizeof(romtypes_to_recognize
) / sizeof(romtypes_to_recognize
[0])];
301 unsigned long flags
= 0;
302 for(size_t i
= 0; i
< sizeof(romtypes_to_recognize
) / sizeof(romtypes_to_recognize
[0]); i
++) {
303 arr
[i
] = findoption(cmdline
, romtypes_to_recognize
[i
]);
307 rtype
= recognize_platform(flags
);
308 for(size_t i
= 0; i
< sizeof(romtypes_to_recognize
) / sizeof(romtypes_to_recognize
[0]); i
++) {
310 switch(recognize_commandline_rom(rtype
, romtypes_to_recognize
[i
])) {
311 case 0: rom
= arr
[i
]; break;
312 case 1: rom_xml
= arr
[i
]; break;
313 case 2: slota
= arr
[i
]; break;
314 case 3: slota_xml
= arr
[i
]; break;
315 case 4: slotb
= arr
[i
]; break;
316 case 5: slotb_xml
= arr
[i
]; break;
319 region
= (rtype
== ROMTYPE_SGB
|| rtype
== ROMTYPE_SNES
) ? REGION_AUTO
: REGION_NTSC
;
320 if(option_set(cmdline
, "--ntsc"))
321 region
= REGION_NTSC
;
322 else if(option_set(cmdline
, "--pal"))
328 void rom_files::resolve_relative() throw(std::bad_alloc
, std::runtime_error
)
330 rom
= resolve_file_relative(rom
, base_file
);
331 rom_xml
= resolve_file_relative(rom_xml
, base_file
);
332 slota
= resolve_file_relative(slota
, base_file
);
333 slota_xml
= resolve_file_relative(slota_xml
, base_file
);
334 slotb
= resolve_file_relative(slotb
, base_file
);
335 slotb_xml
= resolve_file_relative(slotb_xml
, base_file
);
340 std::pair
<enum rom_type
, enum rom_region
> get_current_rom_info() throw()
342 return std::make_pair(current_rom_type
, current_region
);
345 loaded_rom::loaded_rom() throw()
347 rtype
= ROMTYPE_NONE
;
348 region
= orig_region
= REGION_AUTO
;
351 loaded_rom::loaded_rom(const rom_files
& files
) throw(std::bad_alloc
, std::runtime_error
)
353 std::string _slota
= files
.slota
;
354 std::string _slota_xml
= files
.slota_xml
;
355 std::string _slotb
= files
.slotb
;
356 std::string _slotb_xml
= files
.slotb_xml
;
357 if(files
.rtype
== ROMTYPE_NONE
) {
358 rtype
= ROMTYPE_NONE
;
359 region
= orig_region
= files
.region
;
362 if((_slota
!= "" || _slota_xml
!= "") && files
.rtype
== ROMTYPE_SNES
) {
363 messages
<< "WARNING: SNES takes only 1 ROM image" << std::endl
;
367 if((_slotb
!= "" || _slotb_xml
!= "") && files
.rtype
!= ROMTYPE_SUFAMITURBO
) {
368 messages
<< "WARNING: Only Sufami Turbo takes 3 ROM images" << std::endl
;
372 if(files
.rom_xml
!= "" && files
.rom
== "")
373 messages
<< "WARNING: " << name_subrom(files
.rtype
, 0) << " specified without corresponding "
374 << name_subrom(files
.rtype
, 1) << std::endl
;
375 if(_slota_xml
!= "" && _slota
== "")
376 messages
<< "WARNING: " << name_subrom(files
.rtype
, 2) << " specified without corresponding "
377 << name_subrom(files
.rtype
, 3) << std::endl
;
378 if(_slotb_xml
!= "" && _slotb
== "")
379 messages
<< "WARNING: " << name_subrom(files
.rtype
, 4) << " specified without corresponding "
380 << name_subrom(files
.rtype
, 5) << std::endl
;
383 rom
= loaded_slot(files
.rom
, files
.base_file
, false);
384 rom_xml
= loaded_slot(files
.rom_xml
, files
.base_file
, true);
385 slota
= loaded_slot(_slota
, files
.base_file
, false);
386 slota_xml
= loaded_slot(_slota_xml
, files
.base_file
, true);
387 slotb
= loaded_slot(_slotb
, files
.base_file
, false);
388 slotb_xml
= loaded_slot(_slotb_xml
, files
.base_file
, true);
389 orig_region
= region
= files
.region
;
392 void loaded_rom::load() throw(std::bad_alloc
, std::runtime_error
)
394 current_rom_type
= ROMTYPE_NONE
;
395 if(region
== REGION_AUTO
&& orig_region
!= REGION_AUTO
)
396 region
= orig_region
;
397 if(region
!= orig_region
&& orig_region
!= REGION_AUTO
)
398 throw std::runtime_error("Trying to force incompatible region");
399 if(rtype
== ROMTYPE_NONE
)
400 throw std::runtime_error("Can't insert cartridge of type NONE!");
403 SNES::config
.region
= SNES::System::Region::Autodetect
;
406 SNES::config
.region
= SNES::System::Region::NTSC
;
409 SNES::config
.region
= SNES::System::Region::PAL
;
412 throw std::runtime_error("Trying to force unknown region");
416 if(!snes_load_cartridge_normal(rom_xml
, rom
, rom
))
417 throw std::runtime_error("Can't load cartridge ROM");
420 if(region
== REGION_PAL
)
421 throw std::runtime_error("BSX can't be PAL");
422 if(!snes_load_cartridge_bsx(rom_xml
, rom
, rom
, slota_xml
, slota
, slota
))
423 throw std::runtime_error("Can't load cartridge ROM");
425 case ROMTYPE_BSXSLOTTED
:
426 if(region
== REGION_PAL
)
427 throw std::runtime_error("Slotted BSX can't be PAL");
428 if(!snes_load_cartridge_bsx_slotted(rom_xml
, rom
, rom
, slota_xml
, slota
, slota
))
429 throw std::runtime_error("Can't load cartridge ROM");
432 if(!snes_load_cartridge_super_game_boy(rom_xml
, rom
, rom
, slota_xml
, slota
, slota
))
433 throw std::runtime_error("Can't load cartridge ROM");
435 case ROMTYPE_SUFAMITURBO
:
436 if(region
== REGION_PAL
)
437 throw std::runtime_error("Sufami Turbo can't be PAL");
438 if(!snes_load_cartridge_sufami_turbo(rom_xml
, rom
, rom
, slota_xml
, slota
, slota
, slotb_xml
, slotb
,
440 throw std::runtime_error("Can't load cartridge ROM");
443 throw std::runtime_error("Unknown cartridge type");
445 if(region
== REGION_AUTO
)
446 region
= snes_get_region() ? REGION_PAL
: REGION_NTSC
;
448 if(region
== REGION_PAL
)
449 set_nominal_framerate(SNES::system
.cpu_frequency() / DURATION_PAL_FRAME
);
451 set_nominal_framerate(SNES::system
.cpu_frequency() / DURATION_NTSC_FRAME
);
452 information_dispatch::do_sound_rate(SNES::system
.apu_frequency(), 768);
453 current_rom_type
= rtype
;
454 current_region
= region
;
455 refresh_cart_mappings();
458 void loaded_rom::do_patch(const std::vector
<std::string
>& cmdline
) throw(std::bad_alloc
,
462 for(auto i
: cmdline
) {
464 if(opt
.length() >= 13 && opt
.substr(0, 13) == "--ips-offset=") {
466 offset
= parse_value
<int32_t>(opt
.substr(13));
467 } catch(std::exception
& e
) {
468 throw std::runtime_error("Invalid IPS offset option '" + opt
+ "': " + e
.what());
472 if(opt
.length() < 6 || opt
.substr(0, 6) != "--ips-")
474 size_t split
= opt
.find_first_of("=");
475 if(split
> opt
.length())
476 throw std::runtime_error("Invalid IPS patch argument '" + opt
+ "'");
477 std::string kind
= opt
.substr(6, split
- 6);
478 std::string filename
= opt
.substr(split
+ 1);
479 messages
<< "Patching " << kind
<< " using '" << filename
<< "'" << std::endl
;
480 std::vector
<char> ips
;
482 ips
= read_file_relative(filename
, "");
483 } catch(std::bad_alloc
& e
) {
485 } catch(std::exception
& e
) {
486 throw std::runtime_error("Can't read IPS '" + filename
+ "': " + e
.what());
489 switch(recognize_commandline_rom(rtype
, kind
)) {
490 case 0: rom
.patch(ips
, offset
); break;
491 case 1: rom_xml
.patch(ips
, offset
); break;
492 case 2: slota
.patch(ips
, offset
); break;
493 case 3: slota_xml
.patch(ips
, offset
); break;
494 case 4: slotb
.patch(ips
, offset
); break;
495 case 5: slotb_xml
.patch(ips
, offset
); break;
497 throw std::runtime_error("Invalid subROM '" + kind
+ "' to patch");
499 } catch(std::bad_alloc
& e
) {
501 } catch(std::exception
& e
) {
502 throw std::runtime_error("Can't Patch with IPS '" + filename
+ "': " + e
.what());
509 std::string
sram_name(const nall::string
& _id
, SNES::Cartridge::Slot slotname
)
511 std::string
id(_id
, _id
.length());
512 if(slotname
== SNES::Cartridge::Slot::SufamiTurboA
)
513 return "slota." + id
.substr(1);
514 if(slotname
== SNES::Cartridge::Slot::SufamiTurboB
)
515 return "slotb." + id
.substr(1);
520 std::map
<std::string
, std::vector
<char>> save_sram() throw(std::bad_alloc
)
522 std::map
<std::string
, std::vector
<char>> out
;
523 for(unsigned i
= 0; i
< SNES::cartridge
.nvram
.size(); i
++) {
524 SNES::Cartridge::NonVolatileRAM
& r
= SNES::cartridge
.nvram
[i
];
525 std::string savename
= sram_name(r
.id
, r
.slot
);
528 memcpy(&x
[0], r
.data
, r
.size
);
534 void load_sram(std::map
<std::string
, std::vector
<char>>& sram
) throw(std::bad_alloc
)
536 std::set
<std::string
> used
;
539 for(unsigned i
= 0; i
< SNES::cartridge
.nvram
.size(); i
++) {
540 SNES::Cartridge::NonVolatileRAM
& r
= SNES::cartridge
.nvram
[i
];
541 std::string savename
= sram_name(r
.id
, r
.slot
);
542 if(sram
.count(savename
)) {
543 std::vector
<char>& x
= sram
[savename
];
544 if(r
.size
!= x
.size())
545 messages
<< "WARNING: SRAM '" << savename
<< "': Loaded " << x
.size()
546 << " bytes, but the SRAM is " << r
.size
<< "." << std::endl
;
547 memcpy(r
.data
, &x
[0], (r
.size
< x
.size()) ? r
.size
: x
.size());
548 used
.insert(savename
);
550 messages
<< "WARNING: SRAM '" << savename
<< ": No data." << std::endl
;
553 if(!used
.count(i
.first
))
554 messages
<< "WARNING: SRAM '" << i
.first
<< ": Not found on cartridge." << std::endl
;
557 std::map
<std::string
, std::vector
<char>> load_sram_commandline(const std::vector
<std::string
>& cmdline
)
558 throw(std::bad_alloc
, std::runtime_error
)
560 std::map
<std::string
, std::vector
<char>> ret
;
561 for(auto i
: cmdline
) {
563 if(opt
.length() >= 11 && opt
.substr(0, 11) == "--continue=") {
564 size_t split
= opt
.find_first_of("=");
565 if(split
> opt
.length() - 1)
566 throw std::runtime_error("Bad SRAM option '" + opt
+ "'");
567 std::string file
= opt
.substr(split
+ 1);
570 std::string fname
= j
;
571 if(fname
.length() < 6 || fname
.substr(0, 5) != "sram.")
573 std::istream
& x
= r
[fname
];
575 std::vector
<char> out
;
576 boost::iostreams::back_insert_device
<std::vector
<char>> rd(out
);
577 boost::iostreams::copy(x
, rd
);
579 ret
[fname
.substr(5, split
- 5)] = out
;
587 if(opt
.length() < 8 || opt
.substr(0, 7) != "--sram-")
589 size_t split
= opt
.find_first_of("=");
590 if(split
> opt
.length() - 1)
591 throw std::runtime_error("Bad SRAM option '" + opt
+ "'");
592 std::string kind
= opt
.substr(7, split
- 7);
593 std::string file
= opt
.substr(split
+ 1);
595 throw std::runtime_error("Bad SRAM option '" + opt
+ "'");
597 ret
[kind
] = read_file_relative(file
, "");
598 } catch(std::bad_alloc
& e
) {
600 } catch(std::runtime_error
& e
) {
601 throw std::runtime_error("Can't load SRAM '" + kind
+ "': " + e
.what());
607 std::vector
<char> save_core_state() throw(std::bad_alloc
)
609 std::vector
<char> ret
;
610 serializer s
= SNES::system
.serialize();
611 ret
.resize(s
.size());
612 memcpy(&ret
[0], s
.data(), s
.size());
613 size_t offset
= ret
.size();
614 unsigned char tmp
[32];
615 sha256::hash(tmp
, ret
);
616 ret
.resize(offset
+ 32);
617 memcpy(&ret
[offset
], tmp
, 32);
621 void load_core_state(const std::vector
<char>& buf
) throw(std::runtime_error
)
624 throw std::runtime_error("Savestate corrupt");
625 unsigned char tmp
[32];
626 sha256::hash(tmp
, reinterpret_cast<const uint8_t*>(&buf
[0]), buf
.size() - 32);
627 if(memcmp(tmp
, &buf
[buf
.size() - 32], 32))
628 throw std::runtime_error("Savestate corrupt");
629 serializer
s(reinterpret_cast<const uint8_t*>(&buf
[0]), buf
.size() - 32);
630 if(!SNES::system
.unserialize(s
))
631 throw std::runtime_error("SNES core rejected savestate");
634 std::string
name_subrom(enum rom_type major
, unsigned romnumber
) throw(std::bad_alloc
)
638 else if(romnumber
== 1)
640 else if(major
== ROMTYPE_BSX
&& romnumber
== 2)
642 else if(major
== ROMTYPE_BSX
&& romnumber
== 3)
644 else if(major
== ROMTYPE_BSXSLOTTED
&& romnumber
== 2)
646 else if(major
== ROMTYPE_BSXSLOTTED
&& romnumber
== 3)
648 else if(major
== ROMTYPE_SGB
&& romnumber
== 2)
650 else if(major
== ROMTYPE_SGB
&& romnumber
== 3)
652 else if(major
== ROMTYPE_SUFAMITURBO
&& romnumber
== 2)
654 else if(major
== ROMTYPE_SUFAMITURBO
&& romnumber
== 3)
656 else if(major
== ROMTYPE_SUFAMITURBO
&& romnumber
== 4)
658 else if(major
== ROMTYPE_SUFAMITURBO
&& romnumber
== 5)
660 else if(romnumber
% 2)
661 return "UNKNOWN XML";
663 return "UNKNOWN ROM";
667 int recognize_commandline_rom(enum rom_type major
, const std::string
& romname
) throw(std::bad_alloc
)
669 if(romname
== romtypes_to_recognize
[0])
671 else if(romname
== romtypes_to_recognize
[6])
673 else if(major
== ROMTYPE_BSX
&& romname
== romtypes_to_recognize
[1])
675 else if(major
== ROMTYPE_BSX
&& romname
== romtypes_to_recognize
[7])
677 else if(major
== ROMTYPE_BSX
&& romname
== romtypes_to_recognize
[2])
679 else if(major
== ROMTYPE_BSX
&& romname
== romtypes_to_recognize
[8])
681 else if(major
== ROMTYPE_SGB
&& romname
== romtypes_to_recognize
[3])
683 else if(major
== ROMTYPE_SGB
&& romname
== romtypes_to_recognize
[9])
685 else if(major
== ROMTYPE_SUFAMITURBO
&& romname
== romtypes_to_recognize
[4])
687 else if(major
== ROMTYPE_SUFAMITURBO
&& romname
== romtypes_to_recognize
[10])
689 else if(major
== ROMTYPE_SUFAMITURBO
&& romname
== romtypes_to_recognize
[5])
691 else if(major
== ROMTYPE_SUFAMITURBO
&& romname
== romtypes_to_recognize
[11])
697 rom_type
recognize_platform(unsigned long flags
) throw(std::bad_alloc
, std::runtime_error
)
699 if((flags
& 07700) >> 6 & ~(flags
& 077))
700 throw std::runtime_error("SubROM XML specified without corresponding subROM");
702 throw std::runtime_error("No SNES main cartridge ROM specified");
703 if((flags
& 077) == 1)
705 if((flags
& 077) == 3)
707 if((flags
& 077) == 5)
708 return ROMTYPE_BSXSLOTTED
;
709 if((flags
& 077) == 9)
711 if((flags
& 060) != 0 && (flags
& 017) == 1)
712 return ROMTYPE_SUFAMITURBO
;
713 throw std::runtime_error("Not valid combination of rom/bsx/bsxslotted/dmg/slot-a/slot-b");