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>
19 #include "command.hpp"
20 #include "fieldsplit.hpp"
23 #include "memorymanip.hpp"
29 typedef uint8_t uint8
;
30 typedef uint16_t uint16
;
31 typedef uint32_t uint32
;
33 typedef int16_t int16
;
34 typedef int32_t int32
;
35 #include <nall/platform.hpp>
36 #include <nall/endian.hpp>
37 #include <nall/varint.hpp>
38 #include <nall/bit.hpp>
39 #include <nall/serializer.hpp>
40 #include <nall/property.hpp>
42 #include <ui-libsnes/libsnes.hpp>
44 //Some anti-typo defs.
45 #define SNES_TYPE "snes"
46 #define SNES_PAL "snes_pal"
47 #define SNES_NTSC "snes_ntsc"
49 #define BSXSLOTTED "bsxslotted"
50 #define SUFAMITURBO "sufamiturbo"
51 #define SGB_TYPE "SGB"
52 #define SGB_PAL "sgb_pal"
53 #define SGB_NTSC "sgb_ntsc"
55 void strip_CR(std::string
& x
);
57 std::string
gtype::tostring(rom_type rtype
, rom_region region
) throw(std::bad_alloc
, std::runtime_error
)
62 case REGION_AUTO
: return "snes";
63 case REGION_NTSC
: return "snes_ntsc";
64 case REGION_PAL
: return "snes_pal";
68 case REGION_AUTO
: return "sgb";
69 case REGION_NTSC
: return "sgb_ntsc";
70 case REGION_PAL
: return "sgb_pal";
72 case ROMTYPE_BSX
: return "bsx";
73 case ROMTYPE_BSXSLOTTED
: return "bsxslotted";
74 case ROMTYPE_SUFAMITURBO
: return "sufamiturbo";
75 default: throw std::runtime_error("tostring: ROMTYPE_NONE");
79 std::string
gtype::tostring(gametype_t gametype
) throw(std::bad_alloc
, std::runtime_error
)
82 case GT_SNES_NTSC
: return "snes_ntsc";
83 case GT_SNES_PAL
: return "snes_pal";
84 case GT_SGB_NTSC
: return "sgb_ntsc";
85 case GT_SGB_PAL
: return "sgb_pal";
86 case GT_BSX
: return "bsx";
87 case GT_BSX_SLOTTED
: return "bsxslotted";
88 case GT_SUFAMITURBO
: return "sufamiturbo";
89 default: throw std::runtime_error("tostring: GT_INVALID");
93 gametype_t
gtype::togametype(rom_type rtype
, rom_region region
) throw(std::bad_alloc
, std::runtime_error
)
98 case REGION_AUTO
: return GT_SGB_NTSC
;
99 case REGION_NTSC
: return GT_SNES_NTSC
;
100 case REGION_PAL
: return GT_SNES_PAL
;
104 case REGION_AUTO
: return GT_SGB_NTSC
;
105 case REGION_NTSC
: return GT_SGB_NTSC
;
106 case REGION_PAL
: return GT_SGB_PAL
;
108 case ROMTYPE_BSX
: return GT_BSX
;
109 case ROMTYPE_BSXSLOTTED
: return GT_BSX_SLOTTED
;
110 case ROMTYPE_SUFAMITURBO
: return GT_SUFAMITURBO
;
111 default: throw std::runtime_error("togametype: ROMTYPE_NONE");
115 gametype_t
gtype::togametype(const std::string
& gametype
) throw(std::bad_alloc
, std::runtime_error
)
117 if(gametype
== "snes_ntsc")
119 if(gametype
== "snes_pal")
121 if(gametype
== "sgb_ntsc")
123 if(gametype
== "sgb_pal")
125 if(gametype
== "bsx")
127 if(gametype
== "bsxslotted")
128 return GT_BSX_SLOTTED
;
129 if(gametype
== "sufamiturbo")
130 return GT_SUFAMITURBO
;
131 throw std::runtime_error("Unknown game type '" + gametype
+ "'");
134 rom_type
gtype::toromtype(const std::string
& gametype
) throw(std::bad_alloc
, std::runtime_error
)
136 if(gametype
== "snes_ntsc")
138 if(gametype
== "snes_pal")
140 if(gametype
== "snes")
142 if(gametype
== "sgb_ntsc")
144 if(gametype
== "sgb_pal")
146 if(gametype
== "sgb")
148 if(gametype
== "bsx")
150 if(gametype
== "bsxslotted")
151 return ROMTYPE_BSXSLOTTED
;
152 if(gametype
== "sufamiturbo")
153 return ROMTYPE_SUFAMITURBO
;
154 throw std::runtime_error("Unknown game type '" + gametype
+ "'");
157 rom_type
gtype::toromtype(gametype_t gametype
) throw()
160 case GT_SNES_NTSC
: return ROMTYPE_SNES
;
161 case GT_SNES_PAL
: return ROMTYPE_SNES
;
162 case GT_SGB_NTSC
: return ROMTYPE_SGB
;
163 case GT_SGB_PAL
: return ROMTYPE_SGB
;
164 case GT_BSX
: return ROMTYPE_BSX
;
165 case GT_BSX_SLOTTED
: return ROMTYPE_BSXSLOTTED
;
166 case GT_SUFAMITURBO
: return ROMTYPE_SUFAMITURBO
;
167 case GT_INVALID
: throw std::runtime_error("toromtype: GT_INVALID");
171 rom_region
gtype::toromregion(const std::string
& gametype
) throw(std::bad_alloc
, std::runtime_error
)
173 if(gametype
== "snes_ntsc")
175 if(gametype
== "snes_pal")
177 if(gametype
== "snes")
179 if(gametype
== "sgb_ntsc")
181 if(gametype
== "sgb_pal")
183 if(gametype
== "sgb")
185 if(gametype
== "bsx")
187 if(gametype
== "bsxslotted")
189 if(gametype
== "sufamiturbo")
191 throw std::runtime_error("Unknown game type '" + gametype
+ "'");
194 rom_region
gtype::toromregion(gametype_t gametype
) throw()
197 case GT_SNES_NTSC
: return REGION_NTSC
;
198 case GT_SNES_PAL
: return REGION_PAL
;
199 case GT_SGB_NTSC
: return REGION_NTSC
;
200 case GT_SGB_PAL
: return REGION_PAL
;
201 case GT_BSX
: return REGION_NTSC
;
202 case GT_BSX_SLOTTED
: return REGION_NTSC
;
203 case GT_SUFAMITURBO
: return REGION_NTSC
;
204 case GT_INVALID
: throw std::runtime_error("toromregion: GT_INVALID");
211 bool option_set(const std::vector
<std::string
>& cmdline
, const std::string
& option
)
213 for(auto i
= cmdline
.begin(); i
!= cmdline
.end(); i
++)
219 const char* romtypes_to_recognize
[] = {
220 "rom", "bsx", "bsxslotted", "dmg", "slot-a", "slot-b",
221 "rom-xml", "bsx-xml", "bsxslotted-xml", "dmg-xml", "slot-a-xml", "slot-b-xml"
224 enum rom_type current_rom_type
= ROMTYPE_NONE
;
225 enum rom_region current_region
= REGION_NTSC
;
227 uint64_t readval(const std::vector
<char>& patch
, size_t offset
, size_t vsize
) throw(std::runtime_error
)
229 if(offset
>= patch
.size() || offset
+ vsize
> patch
.size())
230 throw std::runtime_error("IPS file corrupt");
232 for(size_t i
= 0; i
< vsize
; i
++)
233 val
= (val
<< 8) | static_cast<uint8_t>(patch
[offset
+ i
]);
237 std::string
findoption(const std::vector
<std::string
>& cmdline
, const std::string
& option
)
240 for(auto i
= cmdline
.begin(); i
!= cmdline
.end(); ++i
) {
241 std::string arg
= *i
;
242 if(arg
.length() < 3 + option
.length())
244 if(arg
[0] != '-' || arg
[1] != '-' || arg
.substr(2, option
.length()) != option
||
245 arg
[2 + option
.length()] != '=')
248 value
= arg
.substr(3 + option
.length());
250 std::cerr
<< "WARNING: Ignored duplicate option for '" << option
<< "'." << std::endl
;
252 throw std::runtime_error("Empty value for '" + option
+ "' is not allowed");
259 loaded_slot::loaded_slot() throw(std::bad_alloc
)
264 loaded_slot::loaded_slot(const std::string
& filename
, const std::string
& base
, bool xml_flag
) throw(std::bad_alloc
,
273 data
= read_file_relative(filename
, base
);
274 sha256
= sha256::hash(data
);
276 size_t osize
= data
.size();
277 data
.resize(osize
+ 1);
282 void loaded_slot::patch(const std::vector
<char>& patch
, int32_t offset
) throw(std::bad_alloc
, std::runtime_error
)
284 bool warned_extend
= false;
285 bool warned_negative
= false;
288 data
.resize(data
.size() - 1);
289 if(readval(patch
, poffset
, 5) != 0x5041544348)
290 throw std::runtime_error("Bad IPS file magic");
293 uint64_t addr
= readval(patch
, poffset
, 3);
296 uint64_t len
= readval(patch
, poffset
+ 3, 2);
303 roffset
= poffset
+ 5;
306 //RLE block. Read real size first.
307 len
= readval(patch
, poffset
+ 5, 2);
309 roffset
= poffset
+ 7;
312 for(uint64_t i
= 0; i
< len
; i
++) {
313 int64_t baddr
= addr
+ i
+ offset
;
316 std::cerr
<< "WARNING: IPS patch tries to modify negative offset. "
317 << "Bad patch or offset?" << std::endl
;
318 warned_negative
= true;
320 } else if(baddr
>= static_cast<int64_t>(data
.size())) {
322 std::cerr
<< "WARNING: IPS patch tries to extend the ROM. "
323 << "Bad patch or offset? " << std::endl
;
324 warned_extend
= true;
325 size_t oldsize
= data
.size();
326 data
.resize(baddr
+ 1);
327 for(size_t j
= oldsize
; j
<= static_cast<uint64_t>(baddr
); j
++)
330 size_t srcoff
= roffset
+ readstride
* i
;
331 if(srcoff
>= patch
.size())
332 throw std::runtime_error("Corrupt IPS patch");
333 data
[baddr
] = static_cast<uint8_t>(patch
[srcoff
]);
337 //Mark the slot as valid and update hash.
339 sha256
= sha256::hash(data
);
341 size_t osize
= data
.size();
342 data
.resize(osize
+ 1);
347 rom_files::rom_files() throw()
349 rtype
= ROMTYPE_NONE
;
350 region
= REGION_AUTO
;
354 rom_files::rom_files(const std::vector
<std::string
>& cmdline
) throw(std::bad_alloc
, std::runtime_error
)
356 rom
= rom_xml
= slota
= slota_xml
= slotb
= slotb_xml
= "";
357 std::string arr
[sizeof(romtypes_to_recognize
) / sizeof(romtypes_to_recognize
[0])];
358 unsigned long flags
= 0;
359 for(size_t i
= 0; i
< sizeof(romtypes_to_recognize
) / sizeof(romtypes_to_recognize
[0]); i
++) {
360 arr
[i
] = findoption(cmdline
, romtypes_to_recognize
[i
]);
364 rtype
= recognize_platform(flags
);
365 for(size_t i
= 0; i
< sizeof(romtypes_to_recognize
) / sizeof(romtypes_to_recognize
[0]); i
++) {
367 switch(recognize_commandline_rom(rtype
, romtypes_to_recognize
[i
])) {
368 case 0: rom
= arr
[i
]; break;
369 case 1: rom_xml
= arr
[i
]; break;
370 case 2: slota
= arr
[i
]; break;
371 case 3: slota_xml
= arr
[i
]; break;
372 case 4: slotb
= arr
[i
]; break;
373 case 5: slotb_xml
= arr
[i
]; break;
376 region
= (rtype
== ROMTYPE_SGB
|| rtype
== ROMTYPE_SNES
) ? REGION_AUTO
: REGION_NTSC
;
377 if(option_set(cmdline
, "--ntsc"))
378 region
= REGION_NTSC
;
379 else if(option_set(cmdline
, "--pal"))
385 void rom_files::resolve_relative() throw(std::bad_alloc
, std::runtime_error
)
387 rom
= resolve_file_relative(rom
, base_file
);
388 rom_xml
= resolve_file_relative(rom_xml
, base_file
);
389 slota
= resolve_file_relative(slota
, base_file
);
390 slota_xml
= resolve_file_relative(slota_xml
, base_file
);
391 slotb
= resolve_file_relative(slotb
, base_file
);
392 slotb_xml
= resolve_file_relative(slotb_xml
, base_file
);
397 std::pair
<enum rom_type
, enum rom_region
> get_current_rom_info() throw()
399 return std::make_pair(current_rom_type
, current_region
);
402 loaded_rom::loaded_rom() throw()
404 rtype
= ROMTYPE_NONE
;
405 region
= orig_region
= REGION_AUTO
;
408 loaded_rom::loaded_rom(const rom_files
& files
) throw(std::bad_alloc
, std::runtime_error
)
410 std::string _slota
= files
.slota
;
411 std::string _slota_xml
= files
.slota_xml
;
412 std::string _slotb
= files
.slotb
;
413 std::string _slotb_xml
= files
.slotb_xml
;
414 if(files
.rtype
== ROMTYPE_NONE
) {
415 rtype
= ROMTYPE_NONE
;
416 region
= orig_region
= files
.region
;
419 if((_slota
!= "" || _slota_xml
!= "") && files
.rtype
== ROMTYPE_SNES
) {
420 window::out() << "WARNING: SNES takes only 1 ROM image" << std::endl
;
424 if((_slotb
!= "" || _slotb_xml
!= "") && files
.rtype
!= ROMTYPE_SUFAMITURBO
) {
425 window::out() << "WARNING: Only Sufami Turbo takes 3 ROM images" << std::endl
;
429 if(files
.rom_xml
!= "" && files
.rom
== "")
430 window::out() << "WARNING: " << name_subrom(files
.rtype
, 0) << " specified without corresponding "
431 << name_subrom(files
.rtype
, 1) << std::endl
;
432 if(_slota_xml
!= "" && _slota
== "")
433 window::out() << "WARNING: " << name_subrom(files
.rtype
, 2) << " specified without corresponding "
434 << name_subrom(files
.rtype
, 3) << std::endl
;
435 if(_slotb_xml
!= "" && _slotb
== "")
436 window::out() << "WARNING: " << name_subrom(files
.rtype
, 4) << " specified without corresponding "
437 << name_subrom(files
.rtype
, 5) << std::endl
;
440 rom
= loaded_slot(files
.rom
, files
.base_file
);
441 rom_xml
= loaded_slot(files
.rom_xml
, files
.base_file
, true);
442 slota
= loaded_slot(_slota
, files
.base_file
);
443 slota_xml
= loaded_slot(_slota_xml
, files
.base_file
, true);
444 slotb
= loaded_slot(_slotb
, files
.base_file
);
445 slotb_xml
= loaded_slot(_slotb_xml
, files
.base_file
, true);
446 orig_region
= region
= files
.region
;
449 void loaded_rom::load() throw(std::bad_alloc
, std::runtime_error
)
451 current_rom_type
= ROMTYPE_NONE
;
452 if(region
== REGION_AUTO
&& orig_region
!= REGION_AUTO
)
453 region
= orig_region
;
454 if(region
!= orig_region
&& orig_region
!= REGION_AUTO
)
455 throw std::runtime_error("Trying to force incompatible region");
456 if(rtype
== ROMTYPE_NONE
)
457 throw std::runtime_error("Can't insert cartridge of type NONE!");
460 config
.region
= System::Region::Autodetect
;
463 config
.region
= System::Region::NTSC
;
466 config
.region
= System::Region::PAL
;
469 throw std::runtime_error("Trying to force unknown region");
473 if(!snes_load_cartridge_normal(rom_xml
, rom
, rom
))
474 throw std::runtime_error("Can't load cartridge ROM");
477 if(region
== REGION_PAL
)
478 throw std::runtime_error("BSX can't be PAL");
479 if(!snes_load_cartridge_bsx(rom_xml
, rom
, rom
, slota_xml
, slota
, slota
))
480 throw std::runtime_error("Can't load cartridge ROM");
482 case ROMTYPE_BSXSLOTTED
:
483 if(region
== REGION_PAL
)
484 throw std::runtime_error("Slotted BSX can't be PAL");
485 if(!snes_load_cartridge_bsx_slotted(rom_xml
, rom
, rom
, slota_xml
, slota
, slota
))
486 throw std::runtime_error("Can't load cartridge ROM");
489 if(!snes_load_cartridge_super_game_boy(rom_xml
, rom
, rom
, slota_xml
, slota
, slota
))
490 throw std::runtime_error("Can't load cartridge ROM");
492 case ROMTYPE_SUFAMITURBO
:
493 if(region
== REGION_PAL
)
494 throw std::runtime_error("Sufami Turbo can't be PAL");
495 if(!snes_load_cartridge_sufami_turbo(rom_xml
, rom
, rom
, slota_xml
, slota
, slota
, slotb_xml
, slotb
,
497 throw std::runtime_error("Can't load cartridge ROM");
500 throw std::runtime_error("Unknown cartridge type");
502 if(region
== REGION_AUTO
)
503 region
= snes_get_region() ? REGION_PAL
: REGION_NTSC
;
505 current_rom_type
= rtype
;
506 current_region
= region
;
507 refresh_cart_mappings();
510 void loaded_rom::do_patch(const std::vector
<std::string
>& cmdline
) throw(std::bad_alloc
,
514 for(auto i
= cmdline
.begin(); i
!= cmdline
.end(); i
++) {
515 std::string opt
= *i
;
516 if(opt
.length() >= 13 && opt
.substr(0, 13) == "--ips-offset=") {
518 offset
= parse_value
<int32_t>(opt
.substr(13));
519 } catch(std::exception
& e
) {
520 throw std::runtime_error("Invalid IPS offset option '" + opt
+ "': " + e
.what());
524 if(opt
.length() < 6 || opt
.substr(0, 6) != "--ips-")
526 size_t split
= opt
.find_first_of("=");
527 if(split
> opt
.length())
528 throw std::runtime_error("Invalid IPS patch argument '" + opt
+ "'");
529 std::string kind
= opt
.substr(6, split
- 6);
530 std::string filename
= opt
.substr(split
+ 1);
531 window::out() << "Patching " << kind
<< " using '" << filename
<< "'" << std::endl
;
532 std::vector
<char> ips
;
534 ips
= read_file_relative(filename
, "");
535 } catch(std::bad_alloc
& e
) {
537 } catch(std::exception
& e
) {
538 throw std::runtime_error("Can't read IPS '" + filename
+ "': " + e
.what());
541 switch(recognize_commandline_rom(rtype
, kind
)) {
542 case 0: rom
.patch(ips
, offset
); break;
543 case 1: rom_xml
.patch(ips
, offset
); break;
544 case 2: slota
.patch(ips
, offset
); break;
545 case 3: slota_xml
.patch(ips
, offset
); break;
546 case 4: slotb
.patch(ips
, offset
); break;
547 case 5: slotb_xml
.patch(ips
, offset
); break;
549 throw std::runtime_error("Invalid subROM '" + kind
+ "' to patch");
551 } catch(std::bad_alloc
& e
) {
553 } catch(std::exception
& e
) {
554 throw std::runtime_error("Can't Patch with IPS '" + filename
+ "': " + e
.what());
561 std::string
sram_name(const nall::string
& _id
, Cartridge::Slot slotname
)
563 std::string
id(_id
, _id
.length());
564 if(slotname
== Cartridge::Slot::SufamiTurboA
)
565 return "slota." + id
.substr(1);
566 if(slotname
== Cartridge::Slot::SufamiTurboB
)
567 return "slotb." + id
.substr(1);
572 std::map
<std::string
, std::vector
<char>> save_sram() throw(std::bad_alloc
)
574 std::map
<std::string
, std::vector
<char>> out
;
575 for(unsigned i
= 0; i
< cartridge
.nvram
.size(); i
++) {
576 Cartridge::NonVolatileRAM
& r
= cartridge
.nvram
[i
];
577 std::string savename
= sram_name(r
.id
, r
.slot
);
580 memcpy(&x
[0], r
.data
, r
.size
);
586 void load_sram(std::map
<std::string
, std::vector
<char>>& sram
) throw(std::bad_alloc
)
588 std::set
<std::string
> used
;
591 for(unsigned i
= 0; i
< cartridge
.nvram
.size(); i
++) {
592 Cartridge::NonVolatileRAM
& r
= cartridge
.nvram
[i
];
593 std::string savename
= sram_name(r
.id
, r
.slot
);
594 if(sram
.count(savename
)) {
595 std::vector
<char>& x
= sram
[savename
];
596 if(r
.size
!= x
.size())
597 window::out() << "WARNING: SRAM '" << savename
<< "': Loaded " << x
.size()
598 << " bytes, but the SRAM is " << r
.size
<< "." << std::endl
;
599 memcpy(r
.data
, &x
[0], (r
.size
< x
.size()) ? r
.size
: x
.size());
600 used
.insert(savename
);
602 window::out() << "WARNING: SRAM '" << savename
<< ": No data." << std::endl
;
604 for(auto i
= sram
.begin(); i
!= sram
.end(); ++i
)
605 if(!used
.count(i
->first
))
606 window::out() << "WARNING: SRAM '" << i
->first
<< ": Not found on cartridge." << std::endl
;
609 std::map
<std::string
, std::vector
<char>> load_sram_commandline(const std::vector
<std::string
>& cmdline
)
610 throw(std::bad_alloc
, std::runtime_error
)
612 std::map
<std::string
, std::vector
<char>> ret
;
613 for(auto i
= cmdline
.begin(); i
!= cmdline
.end(); i
++) {
614 std::string opt
= *i
;
615 if(opt
.length() >= 11 && opt
.substr(0, 11) == "--continue=") {
616 size_t split
= opt
.find_first_of("=");
617 if(split
> opt
.length() - 1)
618 throw std::runtime_error("Bad SRAM option '" + opt
+ "'");
619 std::string file
= opt
.substr(split
+ 1);
621 for(auto j
= r
.begin(); j
!= r
.end(); j
++) {
622 std::string fname
= *j
;
623 if(fname
.length() < 6 || fname
.substr(0, 5) != "sram.")
625 std::istream
& x
= r
[fname
];
627 std::vector
<char> out
;
628 boost::iostreams::back_insert_device
<std::vector
<char>> rd(out
);
629 boost::iostreams::copy(x
, rd
);
631 ret
[fname
.substr(5, split
- 5)] = out
;
639 if(opt
.length() < 8 || opt
.substr(0, 7) != "--sram-")
641 size_t split
= opt
.find_first_of("=");
642 if(split
> opt
.length() - 1)
643 throw std::runtime_error("Bad SRAM option '" + opt
+ "'");
644 std::string kind
= opt
.substr(7, split
- 7);
645 std::string file
= opt
.substr(split
+ 1);
647 throw std::runtime_error("Bad SRAM option '" + opt
+ "'");
649 ret
[kind
] = read_file_relative(file
, "");
650 } catch(std::bad_alloc
& e
) {
652 } catch(std::runtime_error
& e
) {
653 throw std::runtime_error("Can't load SRAM '" + kind
+ "': " + e
.what());
659 std::vector
<char> save_core_state() throw(std::bad_alloc
)
661 SNES::system
.runtosave();
662 std::vector
<char> ret
;
663 serializer s
= SNES::system
.serialize();
664 ret
.resize(s
.size());
665 memcpy(&ret
[0], s
.data(), s
.size());
666 size_t offset
= ret
.size();
667 unsigned char tmp
[32];
668 sha256::hash(tmp
, ret
);
669 ret
.resize(offset
+ 32);
670 memcpy(&ret
[offset
], tmp
, 32);
674 void load_core_state(const std::vector
<char>& buf
) throw(std::runtime_error
)
677 throw std::runtime_error("Savestate corrupt");
678 unsigned char tmp
[32];
679 sha256::hash(tmp
, reinterpret_cast<const uint8_t*>(&buf
[0]), buf
.size() - 32);
680 if(memcmp(tmp
, &buf
[buf
.size() - 32], 32))
681 throw std::runtime_error("Savestate corrupt");
682 serializer
s(reinterpret_cast<const uint8_t*>(&buf
[0]), buf
.size() - 32);
683 if(!SNES::system
.unserialize(s
))
684 throw std::runtime_error("SNES core rejected savestate");
695 std::list
<index_entry
> rom_index
;
697 void replace_index(std::list
<index_entry
> new_index
, const std::string
& source
)
699 std::list
<index_entry
> tmp_index
;
700 for(auto i
= rom_index
.begin(); i
!= rom_index
.end(); i
++) {
701 if(i
->from
!= source
)
702 tmp_index
.push_back(*i
);
704 for(auto i
= new_index
.begin(); i
!= new_index
.end(); i
++) {
705 tmp_index
.push_back(*i
);
707 rom_index
= new_index
;
711 void load_index_file(const std::string
& filename
) throw(std::bad_alloc
, std::runtime_error
)
713 std::istream
& s
= open_file_relative(filename
, "");
716 std::list
<index_entry
> partial_index
;
718 while(std::getline(s
, line
)) {
722 tokensplitter
t(line
);
723 e
.hash
= static_cast<std::string
>(t
);
724 e
.relpath
= t
.tail();
726 if(e
.hash
.length() != 64 || e
.relpath
== "")
727 throw std::runtime_error("Bad index file");
728 partial_index
.push_back(e
);
730 replace_index(partial_index
, filename
);
738 std::string
lookup_file_by_sha256(const std::string
& hash
) throw(std::bad_alloc
, std::runtime_error
)
742 for(auto i
= rom_index
.begin(); i
!= rom_index
.end(); i
++) {
746 std::istream
& o
= open_file_relative(i
->relpath
, i
->from
);
748 return resolve_file_relative(i
->relpath
, i
->from
);
753 throw std::runtime_error("No file with hash '" + hash
+ "' found in known indices");
756 std::string
name_subrom(enum rom_type major
, unsigned romnumber
) throw(std::bad_alloc
)
760 else if(romnumber
== 1)
762 else if(major
== ROMTYPE_BSX
&& romnumber
== 2)
764 else if(major
== ROMTYPE_BSX
&& romnumber
== 3)
766 else if(major
== ROMTYPE_BSXSLOTTED
&& romnumber
== 2)
768 else if(major
== ROMTYPE_BSXSLOTTED
&& romnumber
== 3)
770 else if(major
== ROMTYPE_SGB
&& romnumber
== 2)
772 else if(major
== ROMTYPE_SGB
&& romnumber
== 3)
774 else if(major
== ROMTYPE_SUFAMITURBO
&& romnumber
== 2)
776 else if(major
== ROMTYPE_SUFAMITURBO
&& romnumber
== 3)
778 else if(major
== ROMTYPE_SUFAMITURBO
&& romnumber
== 4)
780 else if(major
== ROMTYPE_SUFAMITURBO
&& romnumber
== 5)
782 else if(romnumber
% 2)
783 return "UNKNOWN XML";
785 return "UNKNOWN ROM";
789 int recognize_commandline_rom(enum rom_type major
, const std::string
& romname
) throw(std::bad_alloc
)
791 if(romname
== romtypes_to_recognize
[0])
793 else if(romname
== romtypes_to_recognize
[6])
795 else if(major
== ROMTYPE_BSX
&& romname
== romtypes_to_recognize
[1])
797 else if(major
== ROMTYPE_BSX
&& romname
== romtypes_to_recognize
[7])
799 else if(major
== ROMTYPE_BSX
&& romname
== romtypes_to_recognize
[2])
801 else if(major
== ROMTYPE_BSX
&& romname
== romtypes_to_recognize
[8])
803 else if(major
== ROMTYPE_SGB
&& romname
== romtypes_to_recognize
[3])
805 else if(major
== ROMTYPE_SGB
&& romname
== romtypes_to_recognize
[9])
807 else if(major
== ROMTYPE_SUFAMITURBO
&& romname
== romtypes_to_recognize
[4])
809 else if(major
== ROMTYPE_SUFAMITURBO
&& romname
== romtypes_to_recognize
[10])
811 else if(major
== ROMTYPE_SUFAMITURBO
&& romname
== romtypes_to_recognize
[5])
813 else if(major
== ROMTYPE_SUFAMITURBO
&& romname
== romtypes_to_recognize
[11])
819 rom_type
recognize_platform(unsigned long flags
) throw(std::bad_alloc
, std::runtime_error
)
821 if((flags
& 07700) >> 6 & ~(flags
& 077))
822 throw std::runtime_error("SubROM XML specified without corresponding subROM");
824 throw std::runtime_error("No SNES main cartridge ROM specified");
825 if((flags
& 077) == 1)
827 if((flags
& 077) == 3)
829 if((flags
& 077) == 5)
830 return ROMTYPE_BSXSLOTTED
;
831 if((flags
& 077) == 9)
833 if((flags
& 060) != 0 && (flags
& 017) == 1)
834 return ROMTYPE_SUFAMITURBO
;
835 throw std::runtime_error("Not valid combination of rom/bsx/bsxslotted/dmg/slot-a/slot-b");