Merge branch 'rr1-maint' into rr1-gambatte
This commit is contained in:
commit
89ed1d5a2c
21 changed files with 826 additions and 1075 deletions
|
@ -193,6 +193,7 @@ public:
|
|||
* \param value The value to search for
|
||||
*/
|
||||
void byte_value(uint8_t value) throw();
|
||||
void byte_difference(uint8_t value) throw();
|
||||
/**
|
||||
* \brief Search for bytes that are signed less
|
||||
*/
|
||||
|
@ -241,12 +242,17 @@ public:
|
|||
* \brief Search for bytes that are unsigned greater
|
||||
*/
|
||||
void byte_ugt() throw();
|
||||
void byte_seqlt() throw();
|
||||
void byte_seqle() throw();
|
||||
void byte_seqge() throw();
|
||||
void byte_seqgt() throw();
|
||||
|
||||
/**
|
||||
* \brief Search for word with specified value
|
||||
* \param value The value to search for
|
||||
*/
|
||||
void word_value(uint16_t value) throw();
|
||||
void word_difference(uint16_t value) throw();
|
||||
/**
|
||||
* \brief Search for words that are signed less
|
||||
*/
|
||||
|
@ -295,12 +301,17 @@ public:
|
|||
* \brief Search for words that are unsigned greater
|
||||
*/
|
||||
void word_ugt() throw();
|
||||
void word_seqlt() throw();
|
||||
void word_seqle() throw();
|
||||
void word_seqge() throw();
|
||||
void word_seqgt() throw();
|
||||
|
||||
/**
|
||||
* \brief Search for dword with specified value
|
||||
* \param value The value to search for
|
||||
*/
|
||||
void dword_value(uint32_t value) throw();
|
||||
void dword_difference(uint32_t value) throw();
|
||||
/**
|
||||
* \brief Search for dwords that are signed less
|
||||
*/
|
||||
|
@ -349,12 +360,17 @@ public:
|
|||
* \brief Search for dwords that are unsigned greater
|
||||
*/
|
||||
void dword_ugt() throw();
|
||||
void dword_seqlt() throw();
|
||||
void dword_seqle() throw();
|
||||
void dword_seqge() throw();
|
||||
void dword_seqgt() throw();
|
||||
|
||||
/**
|
||||
* \brief Search for qword with specified value
|
||||
* \param value The value to search for
|
||||
*/
|
||||
void qword_value(uint64_t value) throw();
|
||||
void qword_difference(uint64_t value) throw();
|
||||
/**
|
||||
* \brief Search for qwords that are signed less
|
||||
*/
|
||||
|
@ -403,6 +419,15 @@ public:
|
|||
* \brief Search for qwords that are unsigned greater
|
||||
*/
|
||||
void qword_ugt() throw();
|
||||
void qword_seqlt() throw();
|
||||
void qword_seqle() throw();
|
||||
void qword_seqge() throw();
|
||||
void qword_seqgt() throw();
|
||||
|
||||
/**
|
||||
* \brief DQ a range of addresses (inclusive on both ends!).
|
||||
*/
|
||||
void dq_range(uint64_t first, uint64_t last);
|
||||
|
||||
/**
|
||||
* \brief Search for all bytes (update values)
|
||||
|
|
|
@ -156,6 +156,10 @@ struct moviefile
|
|||
* Start paused flag.
|
||||
*/
|
||||
bool start_paused;
|
||||
/**
|
||||
* Lazy project create flag.
|
||||
*/
|
||||
bool lazy_project_create;
|
||||
/**
|
||||
* Get number of frames in movie.
|
||||
*
|
||||
|
|
|
@ -8,57 +8,6 @@
|
|||
#include "core/misc.hpp"
|
||||
#include "core/romtype.hpp"
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* This structure gives all files associated with given ROM image.
|
||||
*/
|
||||
struct rom_files
|
||||
{
|
||||
/**
|
||||
* Construct defaults
|
||||
*/
|
||||
rom_files() throw();
|
||||
|
||||
/**
|
||||
* Reads the filenames out of command line arguments given.
|
||||
*
|
||||
* parameter cmdline: The commmand line
|
||||
* throws std::bad_alloc: Not enough memory
|
||||
* throws std::runtime_error: Failed to load ROM filenames.
|
||||
*/
|
||||
rom_files(const std::vector<std::string>& cmdline) throw(std::bad_alloc, std::runtime_error);
|
||||
|
||||
/**
|
||||
* Resolve relative references.
|
||||
*
|
||||
* throws std::bad_alloc: Not enough memory
|
||||
* throws std::runtime_error: Bad path.
|
||||
*/
|
||||
void resolve_relative() throw(std::bad_alloc, std::runtime_error);
|
||||
|
||||
/**
|
||||
* The file to look other ROM files relative to. May be blank.
|
||||
*/
|
||||
std::string base_file;
|
||||
/**
|
||||
* Major ROM type.
|
||||
*/
|
||||
core_type* rtype;
|
||||
/**
|
||||
* Game region (the region ROM is to be loaded as)
|
||||
*/
|
||||
core_region* region;
|
||||
/**
|
||||
* Relative filename of main ROM file.
|
||||
*/
|
||||
std::string romimg[27];
|
||||
/**
|
||||
* Relative filename of main ROM XML file.
|
||||
*/
|
||||
std::string romxml[27];
|
||||
};
|
||||
|
||||
/**
|
||||
* Some loaded data or indication of no data.
|
||||
*/
|
||||
|
@ -76,12 +25,13 @@ struct loaded_slot
|
|||
*
|
||||
* parameter filename: The filename to read. If "", empty slot is constructed.
|
||||
* parameter base: Base filename to interpret the filename against. If "", no base filename is used.
|
||||
* parameter imginfo: Image information.
|
||||
* parameter xml_flag: If set, always keep trailing NUL.
|
||||
* throws std::bad_alloc: Not enough memory.
|
||||
* throws std::runtime_error: Can't load the data.
|
||||
*/
|
||||
loaded_slot(const std::string& filename, const std::string& base, bool xml_flag = false)
|
||||
throw(std::bad_alloc, std::runtime_error);
|
||||
loaded_slot(const std::string& filename, const std::string& base, const struct core_romimage_info& imginfo,
|
||||
bool xml_flag = false) throw(std::bad_alloc, std::runtime_error);
|
||||
|
||||
/**
|
||||
* This method patches this slot using specified IPS patch.
|
||||
|
@ -149,13 +99,13 @@ struct loaded_rom
|
|||
*/
|
||||
loaded_rom() throw();
|
||||
/**
|
||||
* Takes in collection of ROM filenames and loads them into memory.
|
||||
* Take in ROM filename (or a bundle) and load it to memory.
|
||||
*
|
||||
* parameter files: The files to load
|
||||
* parameter file: The file to load
|
||||
* throws std::bad_alloc: Not enough memory.
|
||||
* throws std::runtime_error: Loading ROM files failed.
|
||||
* throws std::runtime_error: Loading ROM file failed.
|
||||
*/
|
||||
loaded_rom(const rom_files& files) throw(std::bad_alloc, std::runtime_error);
|
||||
loaded_rom(const std::string& file) throw(std::bad_alloc, std::runtime_error);
|
||||
/**
|
||||
* ROM type
|
||||
*/
|
||||
|
@ -181,14 +131,9 @@ struct loaded_rom
|
|||
*/
|
||||
std::string msu1_base;
|
||||
/**
|
||||
* Patch the ROM.
|
||||
*
|
||||
* parameter cmdline: The command line.
|
||||
* throws std::bad_alloc: Not enough memory.
|
||||
* throws std::runtime_error: Failed to patch the ROM.
|
||||
* Load filename.
|
||||
*/
|
||||
void do_patch(const std::vector<std::string>& cmdline) throw(std::bad_alloc, std::runtime_error);
|
||||
|
||||
std::string load_filename;
|
||||
/**
|
||||
* Switches the active cartridge to this cartridge. The compatiblity between selected region and original region
|
||||
* is checked. Region is updated after cartridge has been loaded.
|
||||
|
@ -199,16 +144,6 @@ struct loaded_rom
|
|||
void load(uint64_t rtc_sec, uint64_t rtc_subsec) throw(std::bad_alloc, std::runtime_error);
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Name a sub-ROM.
|
||||
*
|
||||
* parameter major: The major type.
|
||||
* parameter romnumber: ROM number to name (as returned by recognize_commandline_rom).
|
||||
* throws std::bad_alloc: Not enough memory
|
||||
*/
|
||||
std::string name_subrom(core_type& major, unsigned romnumber) throw(std::bad_alloc);
|
||||
|
||||
/**
|
||||
* Get major type and region of loaded ROM.
|
||||
*
|
||||
|
@ -259,23 +194,4 @@ std::vector<char> save_core_state(bool nochecksum = false) throw(std::bad_alloc)
|
|||
*/
|
||||
void load_core_state(const std::vector<char>& buf, bool nochecksum = false) throw(std::runtime_error);
|
||||
|
||||
/**
|
||||
* Read index of ROMs and add ROMs found to content-searchable storage.
|
||||
*
|
||||
* parameter filename: The filename of index file.
|
||||
* throws std::bad_alloc: Not enough memory.
|
||||
* throws std::runtime_error: Loading index failed.
|
||||
*/
|
||||
void load_index_file(const std::string& filename) throw(std::bad_alloc, std::runtime_error);
|
||||
|
||||
/**
|
||||
* Search all indices, looking for file with specified SHA-256 (specifying hash of "" results "").
|
||||
*
|
||||
* parameter hash: The hash of file.
|
||||
* returns: Absolute filename.
|
||||
* throws std::bad_alloc: Not enough memory.
|
||||
* throws std::runtime_error: Not found.
|
||||
*/
|
||||
std::string lookup_file_by_sha256(const std::string& hash) throw(std::bad_alloc, std::runtime_error);
|
||||
|
||||
#endif
|
||||
|
|
|
@ -57,7 +57,7 @@ struct core_type
|
|||
{
|
||||
public:
|
||||
core_type(const std::string& iname, const std::string& hname, unsigned id, int (*_load)(core_romimage* images,
|
||||
uint64_t rtc_sec, uint64_t rtc_subsec));
|
||||
uint64_t rtc_sec, uint64_t rtc_subsec), const std::string& extensions);
|
||||
static std::list<core_type*> get_core_types();
|
||||
void add_region(core_region& reg);
|
||||
void add_romimage(core_romimage_info& info, unsigned index);
|
||||
|
@ -66,6 +66,8 @@ public:
|
|||
core_sysregion& combine_region(core_region& reg);
|
||||
const std::string& get_iname();
|
||||
const std::string& get_hname();
|
||||
const std::list<std::string>& get_extensions();
|
||||
bool is_known_extension(const std::string& ext);
|
||||
unsigned get_id();
|
||||
unsigned get_image_count();
|
||||
core_romimage_info get_image_info(unsigned index);
|
||||
|
@ -77,6 +79,7 @@ private:
|
|||
unsigned id;
|
||||
std::string iname;
|
||||
std::string hname;
|
||||
std::list<std::string> extensions;
|
||||
std::list<core_region*> regions;
|
||||
std::vector<core_romimage_info*> imageinfo;
|
||||
};
|
||||
|
|
|
@ -64,9 +64,10 @@ public:
|
|||
* Read the saved set of load IDs for specified project and switch to that project.
|
||||
*
|
||||
* parameter project: The name of project.
|
||||
* parameter lazy: If true, just switch to project, don't read the IDs.
|
||||
* throws std::bad_alloc: Not enough memory
|
||||
*/
|
||||
static void read_base(const std::string& project) throw(std::bad_alloc);
|
||||
static void read_base(const std::string& project, bool lazy) throw(std::bad_alloc);
|
||||
/**
|
||||
* Switch to no project, closing the load IDs.
|
||||
*/
|
||||
|
|
|
@ -32,6 +32,7 @@ void initialize_wx_keyboard();
|
|||
void signal_program_exit();
|
||||
void signal_resize_needed();
|
||||
void _runuifun_async(void (*fn)(void*), void* arg);
|
||||
void show_projectwindow(wxWindow* modwin);
|
||||
|
||||
//Editor dialogs.
|
||||
void wxeditor_authors_display(wxWindow* parent);
|
||||
|
|
|
@ -45,7 +45,7 @@ namespace
|
|||
}
|
||||
|
||||
|
||||
core_type* internal_rom;
|
||||
core_type* internal_rom = NULL;
|
||||
extern core_type type_dmg;
|
||||
extern core_type type_gbc;
|
||||
extern core_type type_gbc_gba;
|
||||
|
@ -55,6 +55,20 @@ namespace
|
|||
unsigned frame_overflow = 0;
|
||||
std::vector<unsigned char> romdata;
|
||||
uint32_t primary_framebuffer[160*144];
|
||||
uint32_t norom_framebuffer[160*144];
|
||||
uint32_t accumulator_l = 0;
|
||||
uint32_t accumulator_r = 0;
|
||||
unsigned accumulator_s = 0;
|
||||
|
||||
void init_norom_framebuffer()
|
||||
{
|
||||
static bool done = false;
|
||||
if(done)
|
||||
return;
|
||||
done = true;
|
||||
for(size_t i = 0; i < 160 * 144; i++)
|
||||
norom_framebuffer[i] = 0xFF8080;
|
||||
}
|
||||
|
||||
time_t walltime_fn()
|
||||
{
|
||||
|
@ -79,7 +93,8 @@ namespace
|
|||
};
|
||||
} getinput;
|
||||
|
||||
int load_rom_common(core_romimage* img, unsigned flags, uint64_t rtc_sec, uint64_t rtc_subsec)
|
||||
int load_rom_common(core_romimage* img, unsigned flags, uint64_t rtc_sec, uint64_t rtc_subsec,
|
||||
core_type* inttype)
|
||||
{
|
||||
const char* markup = img[0].markup;
|
||||
int flags2 = 0;
|
||||
|
@ -106,32 +121,33 @@ namespace
|
|||
rtc_fixed = false;
|
||||
romdata.resize(size);
|
||||
memcpy(&romdata[0], data, size);
|
||||
internal_rom = inttype;
|
||||
}
|
||||
|
||||
int load_rom_dmg(core_romimage* img, uint64_t rtc_sec, uint64_t rtc_subsec)
|
||||
{
|
||||
return load_rom_common(img, gambatte::GB::FORCE_DMG, rtc_sec, rtc_subsec);
|
||||
return load_rom_common(img, gambatte::GB::FORCE_DMG, rtc_sec, rtc_subsec, &type_dmg);
|
||||
}
|
||||
|
||||
int load_rom_gbc(core_romimage* img, uint64_t rtc_sec, uint64_t rtc_subsec)
|
||||
{
|
||||
return load_rom_common(img, 0, rtc_sec, rtc_subsec);
|
||||
return load_rom_common(img, 0, rtc_sec, rtc_subsec, &type_gbc);
|
||||
}
|
||||
|
||||
int load_rom_gbc_gba(core_romimage* img, uint64_t rtc_sec, uint64_t rtc_subsec)
|
||||
{
|
||||
return load_rom_common(img, gambatte::GB::GBA_CGB, rtc_sec, rtc_subsec);
|
||||
return load_rom_common(img, gambatte::GB::GBA_CGB, rtc_sec, rtc_subsec, &type_gbc_gba);
|
||||
}
|
||||
|
||||
uint64_t magic[4] = {35112, 2097152, 16742706, 626688};
|
||||
|
||||
core_region region_world("world", "World", 0, 0, false, magic, regions_compatible);
|
||||
core_romimage_info image_rom_dmg("gbrom", "Cartridge ROM", 1, header_fn);
|
||||
core_romimage_info image_rom_gbc("gbcrom", "Cartridge ROM", 1, header_fn);
|
||||
core_romimage_info image_rom_gbca("gbcarom", "Cartridge ROM", 1, header_fn);
|
||||
core_type type_dmg("dmg", "Game Boy", 1, load_rom_dmg);
|
||||
core_type type_gbc("gbc", "Game Boy Color", 0, load_rom_gbc);
|
||||
core_type type_gbc_gba("gbc_gba", "Game Boy Color (GBA)", 2, load_rom_gbc_gba);
|
||||
core_romimage_info image_rom_dmg("rom", "Cartridge ROM", 1, header_fn);
|
||||
core_romimage_info image_rom_gbc("rom", "Cartridge ROM", 1, header_fn);
|
||||
core_romimage_info image_rom_gbca("rom", "Cartridge ROM", 1, header_fn);
|
||||
core_type type_dmg("dmg", "Game Boy", 1, load_rom_dmg, "gb;dmg");
|
||||
core_type type_gbc("gbc", "Game Boy Color", 0, load_rom_gbc, "gbc;cgb");
|
||||
core_type type_gbc_gba("gbc_gba", "Game Boy Color (GBA)", 2, load_rom_gbc_gba, "");
|
||||
core_type_region_bind bind_A(type_dmg, region_world);
|
||||
core_type_region_bind bind_B(type_gbc, region_world);
|
||||
core_type_region_bind bind_C(type_gbc_gba, region_world);
|
||||
|
@ -263,6 +279,8 @@ void core_runtosave()
|
|||
|
||||
void core_reset()
|
||||
{
|
||||
if(!internal_rom)
|
||||
return;
|
||||
instance->reset();
|
||||
}
|
||||
|
||||
|
@ -293,11 +311,49 @@ void core_uninstall_handler()
|
|||
{
|
||||
}
|
||||
|
||||
void core_emulate_frame_nocore()
|
||||
{
|
||||
init_norom_framebuffer();
|
||||
while(true) {
|
||||
unsigned samples_emitted = SAMPLES_PER_FRAME - frame_overflow;
|
||||
for(unsigned i = 0; i < samples_emitted; i++) {
|
||||
accumulator_l += 32768;
|
||||
accumulator_r += 32768;
|
||||
accumulator_s++;
|
||||
if((accumulator_s & 63) == 0) {
|
||||
uint16_t l2 = accumulator_l >> 6;
|
||||
uint16_t r2 = accumulator_r >> 6;
|
||||
platform::audio_sample(l2, r2);
|
||||
information_dispatch::do_sample(l2 - 32768, r2 - 32768);
|
||||
accumulator_l = accumulator_r = 0;
|
||||
accumulator_s = 0;
|
||||
}
|
||||
}
|
||||
ecore_callbacks->timer_tick(samples_emitted, 2097152);
|
||||
frame_overflow = 0;
|
||||
break;
|
||||
}
|
||||
framebuffer_info inf;
|
||||
inf.type = &_pixel_format_rgb32;
|
||||
inf.mem = const_cast<char*>(reinterpret_cast<const char*>(norom_framebuffer));
|
||||
inf.physwidth = 160;
|
||||
inf.physheight = 144;
|
||||
inf.physstride = 640;
|
||||
inf.width = 160;
|
||||
inf.height = 144;
|
||||
inf.stride = 640;
|
||||
inf.offset_x = 0;
|
||||
inf.offset_y = 0;
|
||||
|
||||
framebuffer_raw ls(inf);
|
||||
ecore_callbacks->output_frame(ls, 262144, 4389);
|
||||
}
|
||||
void core_emulate_frame()
|
||||
{
|
||||
static uint32_t accumulator_l = 0;
|
||||
static uint32_t accumulator_r = 0;
|
||||
static unsigned accumulator_s = 0;
|
||||
if(!internal_rom) {
|
||||
core_emulate_frame_nocore();
|
||||
return;
|
||||
}
|
||||
uint32_t samplebuffer[SAMPLES_PER_FRAME + 2064];
|
||||
while(true) {
|
||||
unsigned samples_emitted = SAMPLES_PER_FRAME - frame_overflow;
|
||||
|
@ -343,6 +399,8 @@ void core_emulate_frame()
|
|||
std::list<vma_info> get_vma_list()
|
||||
{
|
||||
std::list<vma_info> vmas;
|
||||
if(!internal_rom)
|
||||
return vmas;
|
||||
vma_info sram;
|
||||
vma_info wram;
|
||||
vma_info vram;
|
||||
|
@ -405,6 +463,8 @@ std::list<vma_info> get_vma_list()
|
|||
std::set<std::string> get_sram_set()
|
||||
{
|
||||
std::set<std::string> s;
|
||||
if(!internal_rom)
|
||||
return s;
|
||||
auto g = instance->getSaveRam();
|
||||
if(g.second)
|
||||
s.insert("main");
|
||||
|
@ -415,6 +475,8 @@ std::set<std::string> get_sram_set()
|
|||
std::map<std::string, std::vector<char>> save_sram() throw(std::bad_alloc)
|
||||
{
|
||||
std::map<std::string, std::vector<char>> s;
|
||||
if(!internal_rom)
|
||||
return s;
|
||||
auto g = instance->getSaveRam();
|
||||
s["main"].resize(g.second);
|
||||
memcpy(&s["main"][0], g.first, g.second);
|
||||
|
@ -427,7 +489,7 @@ std::map<std::string, std::vector<char>> save_sram() throw(std::bad_alloc)
|
|||
|
||||
void load_sram(std::map<std::string, std::vector<char>>& sram) throw(std::bad_alloc)
|
||||
{
|
||||
if(!sram.count("main"))
|
||||
if(!internal_rom)
|
||||
return;
|
||||
std::vector<char>& x = sram["main"];
|
||||
std::vector<char>& x2 = sram["rtc"];
|
||||
|
@ -445,17 +507,23 @@ void load_sram(std::map<std::string, std::vector<char>>& sram) throw(std::bad_al
|
|||
std::vector<char> cmp_save;
|
||||
|
||||
function_ptr_command<> cmp_save1("set-cmp-save", "", "\n", []() throw(std::bad_alloc, std::runtime_error) {
|
||||
if(!internal_rom)
|
||||
return;
|
||||
instance->saveState(cmp_save);
|
||||
});
|
||||
|
||||
function_ptr_command<> cmp_save2("do-cmp-save", "", "\n", []() throw(std::bad_alloc, std::runtime_error) {
|
||||
std::vector<char> x;
|
||||
if(!internal_rom)
|
||||
return;
|
||||
instance->saveState(x, cmp_save);
|
||||
});
|
||||
|
||||
|
||||
void core_serialize(std::vector<char>& out)
|
||||
{
|
||||
if(!internal_rom)
|
||||
throw std::runtime_error("Can't save without ROM");
|
||||
instance->saveState(out);
|
||||
size_t osize = out.size();
|
||||
out.resize(osize + 4 * sizeof(primary_framebuffer) / sizeof(primary_framebuffer[0]));
|
||||
|
@ -467,6 +535,8 @@ void core_serialize(std::vector<char>& out)
|
|||
|
||||
void core_unserialize(const char* in, size_t insize)
|
||||
{
|
||||
if(!internal_rom)
|
||||
throw std::runtime_error("Can't load without ROM");
|
||||
size_t foffset = insize - 2 - 4 * sizeof(primary_framebuffer) / sizeof(primary_framebuffer[0]);
|
||||
std::vector<char> tmp;
|
||||
tmp.resize(foffset);
|
||||
|
|
|
@ -192,18 +192,19 @@ namespace
|
|||
{
|
||||
std::string filenam = filename;
|
||||
if(filenam == "")
|
||||
filenam = our_rom->msu1_base;
|
||||
filenam = our_rom->load_filename;
|
||||
if(filenam == "") {
|
||||
messages << "No ROM loaded" << std::endl;
|
||||
return false;
|
||||
}
|
||||
try {
|
||||
loaded_slot newrom(filenam, "");
|
||||
if(our_rom->romimg[1].sha256 != "")
|
||||
our_rom->romimg[1] = newrom;
|
||||
else
|
||||
our_rom->romimg[0] = newrom;
|
||||
our_rom->msu1_base = filenam;
|
||||
if(our_rom->romimg[1].sha256 != "")
|
||||
our_movie.romimg_sha256[1] = newrom.sha256;
|
||||
else
|
||||
our_movie.romimg_sha256[0] = newrom.sha256;
|
||||
messages << "Loading ROM " << filenam << std::endl;
|
||||
loaded_rom newrom(filenam);
|
||||
*our_rom = newrom;
|
||||
for(size_t i = 0; i < sizeof(our_rom->romimg)/sizeof(our_rom->romimg[0]); i++) {
|
||||
our_movie.romimg_sha256[i] = our_rom->romimg[i].sha256;
|
||||
our_movie.romxml_sha256[i] = our_rom->romxml[i].sha256;
|
||||
}
|
||||
} catch(std::exception& e) {
|
||||
messages << "Can't reload ROM: " << e.what() << std::endl;
|
||||
return false;
|
||||
|
@ -497,6 +498,12 @@ namespace
|
|||
mark_pending_load(args, LOAD_STATE_CURRENT);
|
||||
});
|
||||
|
||||
function_ptr_command<arg_filename> load_smart_c("load-smart", "Load savestate (heuristic mode)",
|
||||
"Syntax: load <file>\nLoads SNES state from <file> in heuristic mode\n",
|
||||
[](arg_filename args) throw(std::bad_alloc, std::runtime_error) {
|
||||
mark_pending_load(args, LOAD_STATE_DEFAULT);
|
||||
});
|
||||
|
||||
function_ptr_command<arg_filename> load_state_c("load-state", "Load savestate (R/W)",
|
||||
"Syntax: load-state <file>\nLoads SNES state from <file> in Read/Write mode\n",
|
||||
[](arg_filename args) throw(std::bad_alloc, std::runtime_error) {
|
||||
|
|
|
@ -359,6 +359,44 @@ struct search_value
|
|||
T val;
|
||||
};
|
||||
|
||||
/**
|
||||
* \brief Native-value search function for specific difference
|
||||
*/
|
||||
template<typename T>
|
||||
struct search_difference
|
||||
{
|
||||
/**
|
||||
* \brief The underlying numeric type
|
||||
*/
|
||||
typedef T value_type;
|
||||
|
||||
/**
|
||||
* \brief Create new search object
|
||||
*
|
||||
* \param v The value to search for.
|
||||
*/
|
||||
search_difference(T v) throw()
|
||||
{
|
||||
val = v;
|
||||
}
|
||||
|
||||
/**
|
||||
* \brief Condition function.
|
||||
* \param oldv The old value
|
||||
* \param newv The new value
|
||||
* \return True if new value satisfies condition, false otherwise.
|
||||
*/
|
||||
bool operator()(T oldv, T newv) const throw()
|
||||
{
|
||||
return ((newv - oldv) == val);
|
||||
}
|
||||
|
||||
/**
|
||||
* \brief The value to look for
|
||||
*/
|
||||
T val;
|
||||
};
|
||||
|
||||
/**
|
||||
* \brief Native-value search function for less-than function.
|
||||
*/
|
||||
|
@ -497,6 +535,107 @@ struct search_gt
|
|||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* \brief Native-value search function for sequence less-than function.
|
||||
*/
|
||||
template<typename T>
|
||||
struct search_seqlt
|
||||
{
|
||||
/**
|
||||
* \brief The underlying numeric type
|
||||
*/
|
||||
typedef T value_type;
|
||||
|
||||
/**
|
||||
* \brief Condition function.
|
||||
* \param oldv The old value
|
||||
* \param newv The new value
|
||||
* \return True if new value satisfies condition, false otherwise.
|
||||
*/
|
||||
bool operator()(T oldv, T newv) const throw()
|
||||
{
|
||||
T mask = (T)1 << (sizeof(T) * 8 - 1);
|
||||
T diff = newv - oldv;
|
||||
return ((diff & mask) != 0);
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* \brief Native-value search function for sequence less-or-equal function.
|
||||
*/
|
||||
template<typename T>
|
||||
struct search_seqle
|
||||
{
|
||||
/**
|
||||
* \brief The underlying numeric type
|
||||
*/
|
||||
typedef T value_type;
|
||||
|
||||
/**
|
||||
* \brief Condition function.
|
||||
* \param oldv The old value
|
||||
* \param newv The new value
|
||||
* \return True if new value satisfies condition, false otherwise.
|
||||
*/
|
||||
bool operator()(T oldv, T newv) const throw()
|
||||
{
|
||||
T mask = (T)1 << (sizeof(T) * 8 - 1);
|
||||
T diff = newv - oldv;
|
||||
return ((diff & mask) != 0) || (diff == 0);
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* \brief Native-value search function for sequence greater-or-equal function.
|
||||
*/
|
||||
template<typename T>
|
||||
struct search_seqge
|
||||
{
|
||||
/**
|
||||
* \brief The underlying numeric type
|
||||
*/
|
||||
typedef T value_type;
|
||||
|
||||
/**
|
||||
* \brief Condition function.
|
||||
* \param oldv The old value
|
||||
* \param newv The new value
|
||||
* \return True if new value satisfies condition, false otherwise.
|
||||
*/
|
||||
bool operator()(T oldv, T newv) const throw()
|
||||
{
|
||||
T mask = (T)1 << (sizeof(T) * 8 - 1);
|
||||
T diff = newv - oldv;
|
||||
return ((diff & mask) == 0);
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* \brief Native-value search function for sequence greater-than function.
|
||||
*/
|
||||
template<typename T>
|
||||
struct search_seqgt
|
||||
{
|
||||
/**
|
||||
* \brief The underlying numeric type
|
||||
*/
|
||||
typedef T value_type;
|
||||
|
||||
/**
|
||||
* \brief Condition function.
|
||||
* \param oldv The old value
|
||||
* \param newv The new value
|
||||
* \return True if new value satisfies condition, false otherwise.
|
||||
*/
|
||||
bool operator()(T oldv, T newv) const throw()
|
||||
{
|
||||
T mask = (T)1 << (sizeof(T) * 8 - 1);
|
||||
T diff = newv - oldv;
|
||||
return ((diff & mask) == 0) && (diff != 0);
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* \brief Helper class to decode arguments to search functions
|
||||
*
|
||||
|
@ -552,6 +691,35 @@ struct search_value_helper
|
|||
const T& val;
|
||||
};
|
||||
|
||||
void memorysearch::dq_range(uint64_t first, uint64_t last)
|
||||
{
|
||||
struct translated_address t = translate_address_linear_ram(0);
|
||||
uint64_t switch_at = t.memory_size;
|
||||
uint64_t base = 0;
|
||||
uint64_t size = previous_content.size();
|
||||
for(uint64_t i = 0; i < size; i++) {
|
||||
if(still_in[i / 64] == 0) {
|
||||
i = (i + 64) >> 6 << 6;
|
||||
i--;
|
||||
continue;
|
||||
}
|
||||
//t.memory_size == 0 can happen if cart changes.
|
||||
while(i >= switch_at && t.memory_size > 0) {
|
||||
t = translate_address_linear_ram(switch_at);
|
||||
base = switch_at;
|
||||
switch_at += t.memory_size;
|
||||
}
|
||||
uint64_t addr = t.raw_addr + (i - base);
|
||||
if(t.memory_size == 0 || (addr >= first && addr <= last)) {
|
||||
if((still_in[i / 64] >> (i % 64)) & 1) {
|
||||
still_in[i / 64] &= ~(1ULL << (i % 64));
|
||||
candidates--;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
template<class T> void memorysearch::search(const T& obj) throw()
|
||||
{
|
||||
search_value_helper<T> helper(obj);
|
||||
|
@ -593,6 +761,7 @@ template<class T> void memorysearch::search(const T& obj) throw()
|
|||
}
|
||||
|
||||
void memorysearch::byte_value(uint8_t value) throw() { search(search_value<uint8_t>(value)); }
|
||||
void memorysearch::byte_difference(uint8_t value) throw() { search(search_difference<uint8_t>(value)); }
|
||||
void memorysearch::byte_slt() throw() { search(search_lt<int8_t>()); }
|
||||
void memorysearch::byte_sle() throw() { search(search_le<int8_t>()); }
|
||||
void memorysearch::byte_seq() throw() { search(search_eq<int8_t>()); }
|
||||
|
@ -605,8 +774,13 @@ void memorysearch::byte_ueq() throw() { search(search_eq<uint8_t>()); }
|
|||
void memorysearch::byte_une() throw() { search(search_ne<uint8_t>()); }
|
||||
void memorysearch::byte_uge() throw() { search(search_ge<uint8_t>()); }
|
||||
void memorysearch::byte_ugt() throw() { search(search_gt<uint8_t>()); }
|
||||
void memorysearch::byte_seqlt() throw() { search(search_seqlt<uint8_t>()); }
|
||||
void memorysearch::byte_seqle() throw() { search(search_seqle<uint8_t>()); }
|
||||
void memorysearch::byte_seqge() throw() { search(search_seqge<uint8_t>()); }
|
||||
void memorysearch::byte_seqgt() throw() { search(search_seqgt<uint8_t>()); }
|
||||
|
||||
void memorysearch::word_value(uint16_t value) throw() { search(search_value<uint16_t>(value)); }
|
||||
void memorysearch::word_difference(uint16_t value) throw() { search(search_difference<uint16_t>(value)); }
|
||||
void memorysearch::word_slt() throw() { search(search_lt<int16_t>()); }
|
||||
void memorysearch::word_sle() throw() { search(search_le<int16_t>()); }
|
||||
void memorysearch::word_seq() throw() { search(search_eq<int16_t>()); }
|
||||
|
@ -619,8 +793,13 @@ void memorysearch::word_ueq() throw() { search(search_eq<uint16_t>()); }
|
|||
void memorysearch::word_une() throw() { search(search_ne<uint16_t>()); }
|
||||
void memorysearch::word_uge() throw() { search(search_ge<uint16_t>()); }
|
||||
void memorysearch::word_ugt() throw() { search(search_gt<uint16_t>()); }
|
||||
void memorysearch::word_seqlt() throw() { search(search_seqlt<uint16_t>()); }
|
||||
void memorysearch::word_seqle() throw() { search(search_seqle<uint16_t>()); }
|
||||
void memorysearch::word_seqge() throw() { search(search_seqge<uint16_t>()); }
|
||||
void memorysearch::word_seqgt() throw() { search(search_seqgt<uint16_t>()); }
|
||||
|
||||
void memorysearch::dword_value(uint32_t value) throw() { search(search_value<uint32_t>(value)); }
|
||||
void memorysearch::dword_difference(uint32_t value) throw() { search(search_difference<uint32_t>(value)); }
|
||||
void memorysearch::dword_slt() throw() { search(search_lt<int32_t>()); }
|
||||
void memorysearch::dword_sle() throw() { search(search_le<int32_t>()); }
|
||||
void memorysearch::dword_seq() throw() { search(search_eq<int32_t>()); }
|
||||
|
@ -633,8 +812,13 @@ void memorysearch::dword_ueq() throw() { search(search_eq<uint32_t>()); }
|
|||
void memorysearch::dword_une() throw() { search(search_ne<uint32_t>()); }
|
||||
void memorysearch::dword_uge() throw() { search(search_ge<uint32_t>()); }
|
||||
void memorysearch::dword_ugt() throw() { search(search_gt<uint32_t>()); }
|
||||
void memorysearch::dword_seqlt() throw() { search(search_seqlt<uint32_t>()); }
|
||||
void memorysearch::dword_seqle() throw() { search(search_seqle<uint32_t>()); }
|
||||
void memorysearch::dword_seqge() throw() { search(search_seqge<uint32_t>()); }
|
||||
void memorysearch::dword_seqgt() throw() { search(search_seqgt<uint32_t>()); }
|
||||
|
||||
void memorysearch::qword_value(uint64_t value) throw() { search(search_value<uint64_t>(value)); }
|
||||
void memorysearch::qword_difference(uint64_t value) throw() { search(search_difference<uint64_t>(value)); }
|
||||
void memorysearch::qword_slt() throw() { search(search_lt<int64_t>()); }
|
||||
void memorysearch::qword_sle() throw() { search(search_le<int64_t>()); }
|
||||
void memorysearch::qword_seq() throw() { search(search_eq<int64_t>()); }
|
||||
|
@ -647,6 +831,10 @@ void memorysearch::qword_ueq() throw() { search(search_eq<uint64_t>()); }
|
|||
void memorysearch::qword_une() throw() { search(search_ne<uint64_t>()); }
|
||||
void memorysearch::qword_uge() throw() { search(search_ge<uint64_t>()); }
|
||||
void memorysearch::qword_ugt() throw() { search(search_gt<uint64_t>()); }
|
||||
void memorysearch::qword_seqlt() throw() { search(search_seqlt<uint64_t>()); }
|
||||
void memorysearch::qword_seqle() throw() { search(search_seqle<uint64_t>()); }
|
||||
void memorysearch::qword_seqge() throw() { search(search_seqge<uint64_t>()); }
|
||||
void memorysearch::qword_seqgt() throw() { search(search_seqgt<uint64_t>()); }
|
||||
|
||||
void memorysearch::update() throw() { search(search_update()); }
|
||||
|
||||
|
@ -865,10 +1053,22 @@ namespace
|
|||
isrch->byte_uge();
|
||||
else if(firstword == "ubgt" && !has_value)
|
||||
isrch->byte_ugt();
|
||||
else if(firstword == "bseqlt" && !has_value)
|
||||
isrch->byte_seqlt();
|
||||
else if(firstword == "bseqle" && !has_value)
|
||||
isrch->byte_seqle();
|
||||
else if(firstword == "bseqge" && !has_value)
|
||||
isrch->byte_seqge();
|
||||
else if(firstword == "bseqgt" && !has_value)
|
||||
isrch->byte_seqgt();
|
||||
else if(firstword == "b" && has_value) {
|
||||
if(static_cast<int64_t>(value) < -128 || value > 255)
|
||||
throw std::runtime_error("Value to compare out of range");
|
||||
isrch->byte_value(value & 0xFF);
|
||||
} else if(firstword == "bdiff" && has_value) {
|
||||
if(static_cast<int64_t>(value) < -128 || value > 255)
|
||||
throw std::runtime_error("Value to compare out of range");
|
||||
isrch->byte_difference(value & 0xFF);
|
||||
} else if(firstword == "swlt" && !has_value)
|
||||
isrch->word_slt();
|
||||
else if(firstword == "swle" && !has_value)
|
||||
|
@ -893,10 +1093,22 @@ namespace
|
|||
isrch->word_uge();
|
||||
else if(firstword == "uwgt" && !has_value)
|
||||
isrch->word_ugt();
|
||||
else if(firstword == "wseqlt" && !has_value)
|
||||
isrch->word_seqlt();
|
||||
else if(firstword == "wseqle" && !has_value)
|
||||
isrch->word_seqle();
|
||||
else if(firstword == "wseqge" && !has_value)
|
||||
isrch->word_seqge();
|
||||
else if(firstword == "wseqgt" && !has_value)
|
||||
isrch->word_seqgt();
|
||||
else if(firstword == "w" && has_value) {
|
||||
if(static_cast<int64_t>(value) < -32768 || value > 65535)
|
||||
throw std::runtime_error("Value to compare out of range");
|
||||
isrch->word_value(value & 0xFFFF);
|
||||
} else if(firstword == "wdiff" && has_value) {
|
||||
if(static_cast<int64_t>(value) < -32768 || value > 65535)
|
||||
throw std::runtime_error("Value to compare out of range");
|
||||
isrch->word_difference(value & 0xFFFF);
|
||||
} else if(firstword == "sdlt" && !has_value)
|
||||
isrch->dword_slt();
|
||||
else if(firstword == "sdle" && !has_value)
|
||||
|
@ -921,10 +1133,22 @@ namespace
|
|||
isrch->dword_uge();
|
||||
else if(firstword == "udgt" && !has_value)
|
||||
isrch->dword_ugt();
|
||||
else if(firstword == "dseqlt" && !has_value)
|
||||
isrch->dword_seqlt();
|
||||
else if(firstword == "dseqle" && !has_value)
|
||||
isrch->dword_seqle();
|
||||
else if(firstword == "dseqge" && !has_value)
|
||||
isrch->dword_seqge();
|
||||
else if(firstword == "dseqgt" && !has_value)
|
||||
isrch->dword_seqgt();
|
||||
else if(firstword == "d" && has_value) {
|
||||
if(static_cast<int64_t>(value) < -2147483648LL || value > 4294967295ULL)
|
||||
throw std::runtime_error("Value to compare out of range");
|
||||
isrch->dword_value(value & 0xFFFFFFFFULL);
|
||||
} else if(firstword == "ddiff" && has_value) {
|
||||
if(static_cast<int64_t>(value) < -2147483648LL || value > 4294967295ULL)
|
||||
throw std::runtime_error("Value to compare out of range");
|
||||
isrch->dword_difference(value & 0xFFFFFFFFULL);
|
||||
} else if(firstword == "sqlt" && !has_value)
|
||||
isrch->qword_slt();
|
||||
else if(firstword == "sqle" && !has_value)
|
||||
|
@ -949,9 +1173,26 @@ namespace
|
|||
isrch->qword_uge();
|
||||
else if(firstword == "uqgt" && !has_value)
|
||||
isrch->qword_ugt();
|
||||
else if(firstword == "qseqlt" && !has_value)
|
||||
isrch->qword_seqlt();
|
||||
else if(firstword == "qseqle" && !has_value)
|
||||
isrch->qword_seqle();
|
||||
else if(firstword == "qseqge" && !has_value)
|
||||
isrch->qword_seqge();
|
||||
else if(firstword == "qseqgt" && !has_value)
|
||||
isrch->qword_seqgt();
|
||||
else if(firstword == "q" && has_value)
|
||||
isrch->qword_value(value);
|
||||
else if(firstword == "update" && !has_value)
|
||||
else if(firstword == "qdiff" && has_value)
|
||||
isrch->qword_difference(value);
|
||||
else if(firstword == "disqualify" && has_value)
|
||||
isrch->dq_range(value, value);
|
||||
else if(firstword == "disqualify_vma" && has_value) {
|
||||
auto r = translate_address(value);
|
||||
if(r.memory_size != 0)
|
||||
isrch->dq_range(r.raw_addr - r.rel_addr, r.raw_addr - r.rel_addr +
|
||||
r.memory_size - 1);
|
||||
} else if(firstword == "update" && !has_value)
|
||||
isrch->update();
|
||||
else if(firstword == "reset" && !has_value)
|
||||
isrch->reset();
|
||||
|
@ -972,7 +1213,10 @@ namespace
|
|||
std::string get_long_help() throw(std::bad_alloc)
|
||||
{
|
||||
return "Syntax: " + _command + " {s,u}{b,w,d,q}{lt,le,eq,ne,ge,gt}\n"
|
||||
"Syntax: " + _command + " {b,w,d,q}seq{lt,le,ge,gt}\n"
|
||||
"Syntax: " + _command + " {b,w,d,q} <value>\n"
|
||||
"Syntax: " + _command + " {b,w,d,q}diff <value>\n"
|
||||
"Syntax: " + _command + " disqualify{,_vma} <address>\n"
|
||||
"Syntax: " + _command + " update\n"
|
||||
"Syntax: " + _command + " reset\n"
|
||||
"Syntax: " + _command + " count\n"
|
||||
|
|
|
@ -6,6 +6,7 @@
|
|||
#include "core/threaddebug.hpp"
|
||||
#include "core/window.hpp"
|
||||
#include "library/sha256.hpp"
|
||||
#include "library/string.hpp"
|
||||
|
||||
#include <sstream>
|
||||
#include <iostream>
|
||||
|
@ -97,27 +98,17 @@ void set_random_seed() throw(std::bad_alloc)
|
|||
struct loaded_rom load_rom_from_commandline(std::vector<std::string> cmdline) throw(std::bad_alloc,
|
||||
std::runtime_error)
|
||||
{
|
||||
struct rom_files f;
|
||||
try {
|
||||
f = rom_files(cmdline);
|
||||
f.resolve_relative();
|
||||
} catch(std::bad_alloc& e) {
|
||||
OOM_panic();
|
||||
} catch(std::exception& e) {
|
||||
throw std::runtime_error(std::string("Can't resolve ROM files: ") + e.what());
|
||||
}
|
||||
messages << "ROM type: " << f.rtype->get_hname() << " (" << f.region->get_hname() << ")" << std::endl;
|
||||
for(size_t i = 0; i < sizeof(f.romimg)/sizeof(f.romimg[0]); i++) {
|
||||
if(f.romimg[i] != "") messages << name_subrom(*f.rtype, 2 * i + 0) << " file: '" << f.romimg[i]
|
||||
<< "'" << std::endl;
|
||||
if(f.romxml[i] != "") messages << name_subrom(*f.rtype, 2 * i + 1) << " file: '" << f.romxml[i]
|
||||
<< "'" << std::endl;
|
||||
std::string f;
|
||||
regex_results optp;
|
||||
for(auto i : cmdline) {
|
||||
if(!(optp = regex("--rom=(.+)", i)))
|
||||
continue;
|
||||
f = optp[1];
|
||||
}
|
||||
|
||||
struct loaded_rom r;
|
||||
try {
|
||||
r = loaded_rom(f);
|
||||
r.do_patch(cmdline);
|
||||
} catch(std::bad_alloc& e) {
|
||||
OOM_panic();
|
||||
} catch(std::exception& e) {
|
||||
|
@ -126,10 +117,15 @@ struct loaded_rom load_rom_from_commandline(std::vector<std::string> cmdline) th
|
|||
|
||||
std::string not_present = "N/A";
|
||||
for(size_t i = 0; i < sizeof(r.romimg)/sizeof(r.romimg[0]); i++) {
|
||||
if(r.romimg[i].valid) messages << name_subrom(*f.rtype, 2 * i + 0) << " hash: "
|
||||
<< r.romimg[i].sha256 << std::endl;
|
||||
if(r.romxml[i].valid) messages << name_subrom(*f.rtype, 2 * i + 1) << " hash: "
|
||||
<< r.romxml[i].sha256 << std::endl;
|
||||
std::string romname = "UNKNOWN ROM";
|
||||
std::string xmlname = "UNKNOWN XML";
|
||||
if(i < r.rtype->get_image_count()) {
|
||||
romname = (r.rtype->get_image_info(i).hname == "ROM") ? std::string("ROM") :
|
||||
(r.rtype->get_image_info(i).hname + " ROM");
|
||||
xmlname = r.rtype->get_image_info(i).hname + " XML";
|
||||
}
|
||||
if(r.romimg[i].valid) messages << romname << " hash: " << r.romimg[i].sha256 << std::endl;
|
||||
if(r.romxml[i].valid) messages << xmlname << " hash: " << r.romxml[i].sha256 << std::endl;
|
||||
}
|
||||
return r;
|
||||
}
|
||||
|
|
|
@ -14,6 +14,16 @@
|
|||
|
||||
namespace
|
||||
{
|
||||
uint64_t find_next_sync(controller_frame_vector& movie, uint64_t after)
|
||||
{
|
||||
if(after >= movie.size())
|
||||
return after;
|
||||
do {
|
||||
after++;
|
||||
} while(after < movie.size() && !movie[after].sync());
|
||||
return after;
|
||||
}
|
||||
|
||||
bool movies_compatible(controller_frame_vector& old_movie, controller_frame_vector& new_movie,
|
||||
uint64_t frame, const uint32_t* polls, const std::string& old_projectid,
|
||||
const std::string& new_projectid)
|
||||
|
@ -44,10 +54,12 @@ namespace
|
|||
frames_read--;
|
||||
//Current frame. We need to compare each control up to poll counter.
|
||||
uint64_t readable_old_subframes = 0, readable_new_subframes = 0;
|
||||
if(frames_read < old_movie.size())
|
||||
readable_old_subframes = old_movie.size() - frames_read;
|
||||
if(frames_read < new_movie.size())
|
||||
readable_new_subframes = new_movie.size() - frames_read;
|
||||
uint64_t oldlen = find_next_sync(old_movie, frames_read);
|
||||
uint64_t newlen = find_next_sync(new_movie, frames_read);
|
||||
if(frames_read < oldlen)
|
||||
readable_old_subframes = oldlen - frames_read;
|
||||
if(frames_read < newlen)
|
||||
readable_new_subframes = newlen - frames_read;
|
||||
//Compare reset flags of current frame.
|
||||
bool old_reset = false;
|
||||
bool new_reset = false;
|
||||
|
|
|
@ -48,6 +48,7 @@ movie& get_movie()
|
|||
namespace
|
||||
{
|
||||
numeric_setting savecompression("savecompression", 0, 9, 7);
|
||||
boolean_setting readonly_load_preserves("preserve_on_readonly_load", true);
|
||||
|
||||
path_setting slotpath_setting("slotpath");
|
||||
|
||||
|
@ -212,6 +213,10 @@ std::pair<std::string, std::string> split_author(const std::string& author) thro
|
|||
void do_save_state(const std::string& filename) throw(std::bad_alloc,
|
||||
std::runtime_error)
|
||||
{
|
||||
if(!our_movie.gametype) {
|
||||
messages << "Can't save movie without a ROM" << std::endl;
|
||||
return;
|
||||
}
|
||||
std::string filename2 = translate_name_mprefix(filename, true);
|
||||
lua_callback_pre_save(filename2, true);
|
||||
try {
|
||||
|
@ -245,6 +250,10 @@ void do_save_state(const std::string& filename) throw(std::bad_alloc,
|
|||
//Save movie.
|
||||
void do_save_movie(const std::string& filename) throw(std::bad_alloc, std::runtime_error)
|
||||
{
|
||||
if(!our_movie.gametype) {
|
||||
messages << "Can't save movie without a ROM" << std::endl;
|
||||
return;
|
||||
}
|
||||
std::string filename2 = translate_name_mprefix(filename, true);
|
||||
lua_callback_pre_save(filename2, false);
|
||||
try {
|
||||
|
@ -270,15 +279,27 @@ extern time_t random_seed_value;
|
|||
|
||||
void do_load_beginning(bool reload) throw(std::bad_alloc, std::runtime_error)
|
||||
{
|
||||
if(!our_movie.gametype && !reload) {
|
||||
messages << "Can't load movie without a ROM" << std::endl;
|
||||
return;
|
||||
}
|
||||
set_preload_settings();
|
||||
|
||||
//Negative return.
|
||||
if(!reload) {
|
||||
//Force unlazy rrdata.
|
||||
rrdata::read_base(our_movie.projectid, false);
|
||||
rrdata::add_internal();
|
||||
}
|
||||
try {
|
||||
bool ro = movb.get_movie().readonly_mode();
|
||||
movb.get_movie().reset_state();
|
||||
random_seed_value = our_movie.movie_rtc_second;
|
||||
our_rom->load(our_movie.movie_rtc_second, our_movie.movie_rtc_subsecond);
|
||||
if(our_rom->rtype)
|
||||
our_movie.gametype = &our_rom->rtype->combine_region(*our_rom->region);
|
||||
else
|
||||
our_movie.gametype = NULL;
|
||||
if(reload)
|
||||
movb.get_movie().readonly_mode(ro);
|
||||
|
||||
|
@ -312,12 +333,12 @@ void do_load_state(struct moviefile& _movie, int lmode)
|
|||
if(_movie.force_corrupt)
|
||||
throw std::runtime_error("Movie file invalid");
|
||||
bool will_load_state = _movie.is_savestate && lmode != LOAD_STATE_MOVIE;
|
||||
if(&(_movie.gametype->get_type()) != our_rom->rtype)
|
||||
if(our_rom->rtype && &(_movie.gametype->get_type()) != our_rom->rtype)
|
||||
throw std::runtime_error("ROM types of movie and loaded ROM don't match");
|
||||
if(!our_rom->orig_region->compatible_with(_movie.gametype->get_region()))
|
||||
if(our_rom->orig_region && !our_rom->orig_region->compatible_with(_movie.gametype->get_region()))
|
||||
throw std::runtime_error("NTSC/PAL select of movie and loaded ROM don't match");
|
||||
|
||||
if(_movie.coreversion != bsnes_core_version) {
|
||||
if(our_rom->rtype && _movie.coreversion != bsnes_core_version) {
|
||||
if(will_load_state) {
|
||||
std::ostringstream x;
|
||||
x << "ERROR: Emulator core version mismatch!" << std::endl
|
||||
|
@ -341,6 +362,9 @@ void do_load_state(struct moviefile& _movie, int lmode)
|
|||
|
||||
set_preload_settings();
|
||||
|
||||
if(lmode == LOAD_STATE_CURRENT && movb.get_movie().readonly_mode() && readonly_load_preserves)
|
||||
lmode = LOAD_STATE_PRESERVE;
|
||||
|
||||
movie newmovie;
|
||||
if(lmode == LOAD_STATE_PRESERVE)
|
||||
newmovie = movb.get_movie();
|
||||
|
@ -352,11 +376,11 @@ void do_load_state(struct moviefile& _movie, int lmode)
|
|||
(lmode == LOAD_STATE_PRESERVE) ? &_movie.input : NULL, _movie.projectid);
|
||||
|
||||
//Negative return.
|
||||
rrdata::read_base(_movie.projectid);
|
||||
rrdata::read_base(_movie.projectid, _movie.lazy_project_create);
|
||||
rrdata::read(_movie.c_rrdata);
|
||||
rrdata::add_internal();
|
||||
try {
|
||||
our_rom->region = &(_movie.gametype->get_region());
|
||||
our_rom->region = _movie.gametype ? &(_movie.gametype->get_region()) : NULL;
|
||||
random_seed_value = _movie.movie_rtc_second;
|
||||
our_rom->load(_movie.movie_rtc_second, _movie.movie_rtc_subsecond);
|
||||
|
||||
|
@ -406,11 +430,13 @@ void do_load_state(struct moviefile& _movie, int lmode)
|
|||
//Activate RW mode if needed.
|
||||
if(lmode == LOAD_STATE_RW)
|
||||
movb.get_movie().readonly_mode(false);
|
||||
if(lmode == LOAD_STATE_DEFAULT && movb.get_movie().get_frame_count() <= movb.get_movie().get_current_frame())
|
||||
if(lmode == LOAD_STATE_DEFAULT && !current_mode &&
|
||||
movb.get_movie().get_frame_count() <= movb.get_movie().get_current_frame())
|
||||
movb.get_movie().readonly_mode(false);
|
||||
if(lmode == LOAD_STATE_CURRENT && !current_mode)
|
||||
movb.get_movie().readonly_mode(false);
|
||||
information_dispatch::do_mode_change(movb.get_movie().readonly_mode());
|
||||
if(our_rom->rtype)
|
||||
messages << "ROM Type " << our_rom->rtype->get_hname() << " region " << our_rom->region->get_hname()
|
||||
<< std::endl;
|
||||
uint64_t mlength = _movie.get_movie_length();
|
||||
|
@ -469,6 +495,8 @@ bool do_load_state(const std::string& filename, int lmode)
|
|||
|
||||
void mainloop_restore_state(const std::vector<char>& state, uint64_t secs, uint64_t ssecs)
|
||||
{
|
||||
//Force unlazy rrdata.
|
||||
rrdata::read_base(our_movie.projectid, false);
|
||||
rrdata::add_internal();
|
||||
our_movie.rtc_second = secs;
|
||||
our_movie.rtc_subsecond = ssecs;
|
||||
|
|
|
@ -292,7 +292,6 @@ porttype_info& parse_controller_type(const std::string& type, unsigned port) thr
|
|||
}
|
||||
}
|
||||
|
||||
|
||||
moviefile::moviefile() throw(std::bad_alloc)
|
||||
{
|
||||
force_corrupt = false;
|
||||
|
@ -306,6 +305,7 @@ moviefile::moviefile() throw(std::bad_alloc)
|
|||
movie_rtc_second = rtc_second = DEFAULT_RTC_SECOND;
|
||||
movie_rtc_subsecond = rtc_subsecond = DEFAULT_RTC_SUBSECOND;
|
||||
start_paused = false;
|
||||
lazy_project_create = true;
|
||||
}
|
||||
|
||||
moviefile::moviefile(const std::string& movie) throw(std::bad_alloc, std::runtime_error)
|
||||
|
@ -313,6 +313,7 @@ moviefile::moviefile(const std::string& movie) throw(std::bad_alloc, std::runtim
|
|||
start_paused = false;
|
||||
force_corrupt = false;
|
||||
is_savestate = false;
|
||||
lazy_project_create = false;
|
||||
std::string tmp;
|
||||
zip_reader r(movie);
|
||||
read_linefile(r, "systemid", tmp);
|
||||
|
@ -453,6 +454,9 @@ namespace
|
|||
uint64_t moviefile::get_movie_length() throw()
|
||||
{
|
||||
uint64_t frames = get_frame_count();
|
||||
if(!gametype) {
|
||||
return 100000000ULL * frames / 6;
|
||||
}
|
||||
uint64_t _magic[4];
|
||||
gametype->fill_framerate_magic(_magic);
|
||||
uint64_t t = _magic[BLOCK_SECONDS] * 1000000000ULL * (frames / _magic[BLOCK_FRAMES]);
|
||||
|
|
392
src/core/rom.cpp
392
src/core/rom.cpp
|
@ -28,109 +28,37 @@
|
|||
#include <boost/iostreams/filtering_stream.hpp>
|
||||
#include <boost/iostreams/device/back_inserter.hpp>
|
||||
|
||||
//Some anti-typo defs.
|
||||
#define SNES_TYPE "snes"
|
||||
#define SNES_PAL "snes_pal"
|
||||
#define SNES_NTSC "snes_ntsc"
|
||||
#define BSX "bsx"
|
||||
#define BSXSLOTTED "bsxslotted"
|
||||
#define SUFAMITURBO "sufamiturbo"
|
||||
#define SGB_TYPE "SGB"
|
||||
#define SGB_PAL "sgb_pal"
|
||||
#define SGB_NTSC "sgb_ntsc"
|
||||
|
||||
/**
|
||||
* Recognize the slot this ROM goes to.
|
||||
*
|
||||
* parameter major: The major type.
|
||||
* parameter romname: Name of the ROM type.
|
||||
* returns: Even if this is main rom, odd if XML. 0/1 for main slot, 2/3 for slot A, 4/5 for slot B. -1 if not valid
|
||||
* rom type.
|
||||
* throws std::bad_alloc: Not enough memory
|
||||
*/
|
||||
int recognize_commandline_rom(core_type& major, const std::string& romname) throw(std::bad_alloc);
|
||||
|
||||
/**
|
||||
* Recognize major type from flags.
|
||||
*
|
||||
* parameter flags: Flags telling what ROM parameters are present.
|
||||
* returns: The recognzed major type.
|
||||
* throws std::bad_alloc: Not enough memory
|
||||
* throws std::runtime_error: Illegal flags.
|
||||
*/
|
||||
core_type& recognize_platform(const std::set<std::string>& present) throw(std::bad_alloc, std::runtime_error);
|
||||
|
||||
|
||||
namespace
|
||||
{
|
||||
bool option_set(const std::vector<std::string>& cmdline, const std::string& option)
|
||||
{
|
||||
for(auto i : cmdline)
|
||||
if(i == option)
|
||||
return true;
|
||||
return false;
|
||||
}
|
||||
|
||||
core_type* current_rom_type = NULL;
|
||||
core_region* current_region = NULL;
|
||||
|
||||
std::string findoption(const std::vector<std::string>& cmdline, const std::string& option)
|
||||
{
|
||||
std::string value;
|
||||
regex_results optp;
|
||||
for(auto i : cmdline) {
|
||||
if(!(optp = regex("--([^=]+)=(.*)", i)) || optp[1] != option)
|
||||
continue;
|
||||
if(value == "")
|
||||
value = optp[2];
|
||||
else
|
||||
std::cerr << "WARNING: Ignored duplicate option for '" << option << "'." << std::endl;
|
||||
if(value == "")
|
||||
throw std::runtime_error("Empty value for '" + option + "' is not allowed");
|
||||
}
|
||||
return value;
|
||||
}
|
||||
|
||||
std::set<std::string> find_present_roms(const std::vector<std::string>& cmdline)
|
||||
{
|
||||
std::set<std::string> p;
|
||||
std::list<core_type*> types = core_type::get_core_types();
|
||||
for(auto i : types) {
|
||||
for(unsigned j = 0; j < i->get_image_count(); j++) {
|
||||
std::string iname = i->get_image_info(j).iname;
|
||||
if(findoption(cmdline, iname) != "")
|
||||
p.insert(iname);
|
||||
if(findoption(cmdline, iname + "-xml") != "")
|
||||
p.insert(iname + "-xml");
|
||||
}
|
||||
}
|
||||
return p;
|
||||
}
|
||||
}
|
||||
|
||||
loaded_slot::loaded_slot() throw(std::bad_alloc)
|
||||
{
|
||||
valid = false;
|
||||
xml = false;
|
||||
sha256 = "";
|
||||
}
|
||||
|
||||
loaded_slot::loaded_slot(const std::string& filename, const std::string& base, bool xml_flag)
|
||||
throw(std::bad_alloc, std::runtime_error)
|
||||
loaded_slot::loaded_slot(const std::string& filename, const std::string& base,
|
||||
const struct core_romimage_info& imginfo, bool xml_flag) throw(std::bad_alloc, std::runtime_error)
|
||||
{
|
||||
bool headered = false;
|
||||
unsigned headered = 0;
|
||||
xml = xml_flag;
|
||||
if(filename == "") {
|
||||
valid = false;
|
||||
sha256 = "";
|
||||
return;
|
||||
}
|
||||
valid = true;
|
||||
data = read_file_relative(filename, base);
|
||||
if(!xml && data.size() % 1024 == 512)
|
||||
//Assume headered.
|
||||
headered = true;
|
||||
if(!xml)
|
||||
headered = imginfo.headersize(data.size());
|
||||
if(headered && !xml) {
|
||||
if(data.size() >= 512) {
|
||||
memmove(&data[0], &data[512], data.size() - 512);
|
||||
data.resize(data.size() - 512);
|
||||
if(data.size() >= headered) {
|
||||
memmove(&data[0], &data[headered], data.size() - headered);
|
||||
data.resize(data.size() - headered);
|
||||
} else {
|
||||
data.resize(0);
|
||||
}
|
||||
|
@ -166,55 +94,6 @@ void loaded_slot::patch(const std::vector<char>& patch, int32_t offset) throw(st
|
|||
}
|
||||
}
|
||||
|
||||
rom_files::rom_files() throw()
|
||||
{
|
||||
rtype = NULL;
|
||||
region = NULL;
|
||||
}
|
||||
|
||||
rom_files::rom_files(const std::vector<std::string>& cmdline) throw(std::bad_alloc, std::runtime_error)
|
||||
{
|
||||
for(size_t i = 0; i < sizeof(romimg) / sizeof(romimg[0]); i++) {
|
||||
romimg[i] = "";
|
||||
romxml[i] = "";
|
||||
}
|
||||
|
||||
auto opts = find_present_roms(cmdline);
|
||||
rtype = &recognize_platform(opts);
|
||||
for(auto i : opts) {
|
||||
std::string o = findoption(cmdline, i);
|
||||
if(o != "") {
|
||||
int j = recognize_commandline_rom(*rtype, i);
|
||||
if(j >= 0 && j & 1)
|
||||
romxml[j / 2] = o;
|
||||
else if(j >= 0)
|
||||
romimg[j / 2] = o;
|
||||
}
|
||||
}
|
||||
region = &rtype->get_preferred_region();
|
||||
std::string _region = findoption(cmdline, "region");
|
||||
if(_region != "") {
|
||||
bool isset = false;
|
||||
for(auto i : rtype->get_regions()) {
|
||||
if(i->get_iname() == _region) {
|
||||
region = i;
|
||||
isset = true;
|
||||
}
|
||||
}
|
||||
if(!isset)
|
||||
throw std::runtime_error("Unknown region for system type");
|
||||
}
|
||||
base_file = "";
|
||||
}
|
||||
|
||||
void rom_files::resolve_relative() throw(std::bad_alloc, std::runtime_error)
|
||||
{
|
||||
for(size_t i = 0; i < sizeof(romimg)/sizeof(romimg[0]); i++) {
|
||||
romimg[i] = resolve_file_relative(romimg[i], base_file);
|
||||
romxml[i] = resolve_file_relative(romxml[i], base_file);
|
||||
}
|
||||
base_file = "";
|
||||
}
|
||||
|
||||
|
||||
std::pair<core_type*, core_region*> get_current_rom_info() throw()
|
||||
|
@ -228,56 +107,139 @@ loaded_rom::loaded_rom() throw()
|
|||
region = orig_region = NULL;
|
||||
}
|
||||
|
||||
loaded_rom::loaded_rom(const rom_files& files) throw(std::bad_alloc, std::runtime_error)
|
||||
loaded_rom::loaded_rom(const std::string& file) throw(std::bad_alloc, std::runtime_error)
|
||||
{
|
||||
std::string cromimg[sizeof(files.romimg)/sizeof(files.romimg[0])];
|
||||
std::string cromxml[sizeof(files.romimg)/sizeof(files.romimg[0])];
|
||||
for(size_t i = 0; i < sizeof(files.romimg)/sizeof(files.romimg[0]); i++) {
|
||||
cromimg[i] = files.romimg[i];
|
||||
cromxml[i] = files.romxml[i];
|
||||
std::list<core_type*> possible = core_type::get_core_types();
|
||||
std::istream& spec = open_file_relative(file, "");
|
||||
std::string s;
|
||||
std::getline(spec, s);
|
||||
load_filename = file;
|
||||
if(!spec || s != "[GAMEPACK FILE]") {
|
||||
//This is a Raw ROM image.
|
||||
regex_results tmp;
|
||||
std::string ext = regex(".*\\.([^.]*)?", file, "Unknown ROM file type")[1];
|
||||
core_type* coretype = NULL;
|
||||
for(auto i : possible) {
|
||||
if(i->is_known_extension(ext))
|
||||
coretype = i;
|
||||
}
|
||||
if(!files.rtype) {
|
||||
rtype = NULL;
|
||||
region = orig_region = files.region;
|
||||
if(!coretype)
|
||||
throw std::runtime_error("Unknown ROM file type");
|
||||
rtype = coretype;
|
||||
region = orig_region = &rtype->get_preferred_region();
|
||||
romimg[0] = loaded_slot(file, "", coretype->get_image_info(0), false);
|
||||
msu1_base = resolve_file_relative(file, "");
|
||||
return;
|
||||
}
|
||||
for(size_t i = 0; i < sizeof(files.romimg)/sizeof(files.romimg[0]); i++) {
|
||||
if((cromimg[i] != "" || cromxml[i] != "") && i > rtype->get_image_count()) {
|
||||
messages << "Warning: ROM slot #" << (i + 1) << " is not used for this console" << std::endl;
|
||||
cromimg[i] = "";
|
||||
cromxml[i] = "";
|
||||
}
|
||||
if(cromimg[i] == "" && cromxml[i] != "") {
|
||||
messages << "WARNING: " << name_subrom(*files.rtype, 2 * i + 1) << " specified without "
|
||||
<< "corresponding " << name_subrom(*files.rtype, 2 * i + 0) << std::endl;
|
||||
cromxml[i] = "";
|
||||
}
|
||||
std::vector<std::string> lines;
|
||||
while(std::getline(spec, s))
|
||||
lines.push_back(s);
|
||||
std::string platname = "";
|
||||
std::string platreg = "";
|
||||
for(auto i : lines) {
|
||||
regex_results tmp;
|
||||
if(tmp = regex("type[ \t]+(.+)", i))
|
||||
platname = tmp[1];
|
||||
if(tmp = regex("region[ \t]+(.+)", i))
|
||||
platreg = tmp[1];
|
||||
}
|
||||
|
||||
rtype = files.rtype;
|
||||
for(size_t i = 0; i < sizeof(romimg) / sizeof(romimg[0]); i++) {
|
||||
romimg[i] = loaded_slot(cromimg[i], files.base_file, false);
|
||||
romxml[i] = loaded_slot(cromxml[i], files.base_file, true);
|
||||
//Detect type.
|
||||
rtype = NULL;
|
||||
for(auto i : possible)
|
||||
if(i->get_iname() == platname)
|
||||
rtype = i;
|
||||
if(!rtype)
|
||||
(stringfmt() << "Not a valid system type '" << platname << "'").throwex();
|
||||
|
||||
//Detect region.
|
||||
bool goodreg = false;
|
||||
orig_region = &rtype->get_preferred_region();
|
||||
for(auto i: rtype->get_regions())
|
||||
if(i->get_iname() == platreg) {
|
||||
orig_region = i;
|
||||
goodreg = true;
|
||||
}
|
||||
orig_region = region = files.region;
|
||||
if(cromimg[1] != "")
|
||||
msu1_base = resolve_file_relative(cromimg[1], files.base_file);
|
||||
if(!goodreg && platreg != "")
|
||||
(stringfmt() << "Not a valid system region '" << platreg << "'").throwex();
|
||||
region = orig_region;
|
||||
|
||||
//ROM files.
|
||||
std::string cromimg[sizeof(romimg)/sizeof(romimg[0])];
|
||||
std::string cromxml[sizeof(romimg)/sizeof(romimg[0])];
|
||||
for(auto i : lines) {
|
||||
regex_results tmp;
|
||||
if(!(tmp = regex("(rom|xml)[ \t]+([^ \t]+)[ \t]+(.*)", i)))
|
||||
continue;
|
||||
size_t idxs = rtype->get_image_count();
|
||||
size_t idx = idxs;
|
||||
for(size_t i = 0; i < idxs; i++)
|
||||
if(rtype->get_image_info(i).iname == tmp[2])
|
||||
idx = i;
|
||||
if(idx == idxs)
|
||||
(stringfmt() << "Not a valid ROM name '" << tmp[2] << "'").throwex();
|
||||
if(tmp[1] == "rom")
|
||||
cromimg[idx] = tmp[3];
|
||||
else
|
||||
msu1_base = resolve_file_relative(cromimg[0], files.base_file);
|
||||
cromxml[idx] = tmp[3];
|
||||
}
|
||||
|
||||
//Check ROMs.
|
||||
unsigned mask1 = 0, mask2 = 0;
|
||||
for(size_t i = 0; i < rtype->get_image_count(); i++) {
|
||||
auto ii = rtype->get_image_info(i);
|
||||
mask1 |= ii.mandatory;
|
||||
if(cromimg[i] != "")
|
||||
mask2 |= ii.mandatory;
|
||||
if(cromimg[i] == "" && cromxml[i] != "") {
|
||||
messages << "WARNING: Slot " << ii.iname << ": XML without ROM." << std::endl;
|
||||
cromxml[i] = "";
|
||||
}
|
||||
}
|
||||
if(mask1 != mask2)
|
||||
throw std::runtime_error("Required ROM missing");
|
||||
|
||||
//Load ROMs.
|
||||
for(size_t i = 0; i < rtype->get_image_count(); i++) {
|
||||
romimg[i] = loaded_slot(cromimg[i], file, rtype->get_image_info(i), false);
|
||||
romxml[i] = loaded_slot(cromxml[i], file, rtype->get_image_info(i), true);
|
||||
}
|
||||
|
||||
//Patch ROMs.
|
||||
for(auto i : lines) {
|
||||
regex_results tmp;
|
||||
if(!(tmp = regex("patch[ \t]+([^ \t]+)[ \t]+(.*)([ \t]+[+-][0-9]+)?", i)))
|
||||
continue;
|
||||
size_t idxs = rtype->get_image_count();
|
||||
size_t idx = idxs;
|
||||
for(size_t i = 0; i < idxs; i++)
|
||||
if(rtype->get_image_info(i).iname == tmp[1])
|
||||
idx = i;
|
||||
if(idx == idxs)
|
||||
(stringfmt() << "Not a valid ROM name '" << tmp[1] << "'").throwex();
|
||||
int32_t offset = 0;
|
||||
if(tmp[3] != "")
|
||||
offset = parse_value<int32_t>(tmp[3]);
|
||||
romimg[idx].patch(read_file_relative(tmp[2], ""), offset);
|
||||
}
|
||||
|
||||
//MSU-1 base.
|
||||
if(cromimg[1] != "")
|
||||
msu1_base = resolve_file_relative(cromimg[1], file);
|
||||
else
|
||||
msu1_base = resolve_file_relative(cromimg[0], file);
|
||||
}
|
||||
|
||||
void loaded_rom::load(uint64_t rtc_sec, uint64_t rtc_subsec) throw(std::bad_alloc, std::runtime_error)
|
||||
{
|
||||
if(!rtype)
|
||||
throw std::runtime_error("Can't insert cartridge of type NONE!");
|
||||
current_rom_type = NULL;
|
||||
if(!orig_region)
|
||||
if(!orig_region && rtype)
|
||||
orig_region = &rtype->get_preferred_region();
|
||||
if(!region)
|
||||
region = orig_region;
|
||||
if(!orig_region->compatible_with(*region))
|
||||
if(rtype && !orig_region->compatible_with(*region))
|
||||
throw std::runtime_error("Trying to force incompatible region");
|
||||
if(!core_set_region(*region))
|
||||
if(rtype && !core_set_region(*region))
|
||||
throw std::runtime_error("Trying to force unknown region");
|
||||
|
||||
core_romimage images[sizeof(romimg)/sizeof(romimg[0])];
|
||||
|
@ -286,8 +248,11 @@ void loaded_rom::load(uint64_t rtc_sec, uint64_t rtc_subsec) throw(std::bad_allo
|
|||
images[i].data = (const unsigned char*)romimg[i];
|
||||
images[i].size = (size_t)romimg[i];
|
||||
}
|
||||
if(rtype) {
|
||||
if(!rtype->load(images, rtc_sec, rtc_subsec))
|
||||
throw std::runtime_error("Can't load cartridge ROM");
|
||||
} else
|
||||
core_unload_cartridge();
|
||||
|
||||
region = &core_get_region();
|
||||
core_power();
|
||||
|
@ -301,46 +266,6 @@ void loaded_rom::load(uint64_t rtc_sec, uint64_t rtc_subsec) throw(std::bad_allo
|
|||
refresh_cart_mappings();
|
||||
}
|
||||
|
||||
void loaded_rom::do_patch(const std::vector<std::string>& cmdline) throw(std::bad_alloc,
|
||||
std::runtime_error)
|
||||
{
|
||||
int32_t offset = 0;
|
||||
regex_results opt;
|
||||
for(auto i : cmdline) {
|
||||
if(opt = regex("--ips-offset=(.*)", i)) {
|
||||
try {
|
||||
offset = parse_value<int32_t>(opt[1]);
|
||||
} catch(std::exception& e) {
|
||||
throw std::runtime_error("Invalid IPS offset option '" + i + "': " + e.what());
|
||||
}
|
||||
continue;
|
||||
} else if(opt = regex("--ips-([^=]*)=(.+)", i)) {
|
||||
messages << "Patching " << opt[1] << " using '" << opt[2] << "'" << std::endl;
|
||||
std::vector<char> ips;
|
||||
try {
|
||||
ips = read_file_relative(opt[2], "");
|
||||
} catch(std::bad_alloc& e) {
|
||||
OOM_panic();
|
||||
} catch(std::exception& e) {
|
||||
throw std::runtime_error("Can't read IPS '" + opt[2] + "': " + e.what());
|
||||
}
|
||||
try {
|
||||
int r_id = recognize_commandline_rom(*rtype, opt[1]);
|
||||
if(r_id < 0 || r_id > 2 * sizeof(romimg) / sizeof(romimg[0]))
|
||||
throw std::runtime_error("Invalid subROM '" + opt[1] + "' to patch");
|
||||
if(r_id & 1)
|
||||
romxml[r_id / 2].patch(ips, offset);
|
||||
else
|
||||
romimg[r_id / 2].patch(ips, offset);
|
||||
} catch(std::bad_alloc& e) {
|
||||
OOM_panic();
|
||||
} catch(std::exception& e) {
|
||||
throw std::runtime_error("Can't Patch with IPS '" + opt[2] + "': " + e.what());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
std::map<std::string, std::vector<char>> load_sram_commandline(const std::vector<std::string>& cmdline)
|
||||
throw(std::bad_alloc, std::runtime_error)
|
||||
{
|
||||
|
@ -408,60 +333,3 @@ void load_core_state(const std::vector<char>& buf, bool nochecksum) throw(std::r
|
|||
throw std::runtime_error("Savestate corrupt");
|
||||
core_unserialize(&buf[0], buf.size() - 32);;
|
||||
}
|
||||
|
||||
std::string name_subrom(core_type& major, unsigned romnumber) throw(std::bad_alloc)
|
||||
{
|
||||
std::string name = "UNKNOWN";
|
||||
if(romnumber < 2 * major.get_image_count())
|
||||
name = major.get_image_info(romnumber / 2).hname;
|
||||
if(romnumber % 2)
|
||||
return name + " XML";
|
||||
else if(name != "ROM")
|
||||
return name + " ROM";
|
||||
else
|
||||
return "ROM";
|
||||
}
|
||||
|
||||
|
||||
int recognize_commandline_rom(core_type& major, const std::string& romname) throw(std::bad_alloc)
|
||||
{
|
||||
for(unsigned i = 0; i < major.get_image_count(); i++) {
|
||||
std::string iname = major.get_image_info(i).iname;
|
||||
if(romname == iname)
|
||||
return 2 * i + 0;
|
||||
if(romname == iname + "-xml")
|
||||
return 2 * i + 1;
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
core_type& recognize_platform(const std::set<std::string>& present) throw(std::bad_alloc, std::runtime_error)
|
||||
{
|
||||
std::list<core_type*> possible = core_type::get_core_types();
|
||||
unsigned total = 0;
|
||||
for(auto i : present) {
|
||||
regex_results r;
|
||||
std::string base = i;
|
||||
if(r = regex("(.*)-xml", base)) {
|
||||
if(!present.count(r[1]))
|
||||
throw std::runtime_error("SubROM XML specified without corresponding subROM");
|
||||
} else
|
||||
total++;
|
||||
}
|
||||
for(auto i : possible) {
|
||||
unsigned pmask = 0;
|
||||
unsigned rmask = 0;
|
||||
unsigned found = 0;
|
||||
for(unsigned j = 0; j < i->get_image_count(); j++) {
|
||||
std::string iname = i->get_image_info(j).iname;
|
||||
if(present.count(iname)) {
|
||||
pmask |= i->get_image_info(j).mandatory;
|
||||
found++;
|
||||
}
|
||||
rmask |= i->get_image_info(j).mandatory;
|
||||
}
|
||||
if(pmask == rmask && found == total)
|
||||
return *i;
|
||||
}
|
||||
throw std::runtime_error("Invalid combination of subROMs");
|
||||
}
|
||||
|
|
|
@ -1,6 +1,10 @@
|
|||
#include "core/romtype.hpp"
|
||||
#include "library/minmax.hpp"
|
||||
#include "library/string.hpp"
|
||||
#include <map>
|
||||
#include <string>
|
||||
#include <algorithm>
|
||||
#include <cctype>
|
||||
#include <stdexcept>
|
||||
#include <list>
|
||||
|
||||
|
@ -263,13 +267,32 @@ core_sysregion& core_type::combine_region(core_region& reg)
|
|||
}
|
||||
|
||||
core_type::core_type(const std::string& _iname, const std::string& _hname, unsigned _id,
|
||||
int (*_load)(core_romimage* images, uint64_t rtc_sec, uint64_t rtc_subsec))
|
||||
int (*_load)(core_romimage* images, uint64_t rtc_sec, uint64_t rtc_subsec), const std::string& _extensions)
|
||||
: iname(_iname), hname(_hname), loadimg(_load), id(_id)
|
||||
{
|
||||
types()[iname] = this;
|
||||
std::string ext;
|
||||
std::string ext2 = _extensions;
|
||||
while(extract_token(ext2, ext, ";") >= 0)
|
||||
extensions.push_back(ext);
|
||||
process_registrations();
|
||||
}
|
||||
|
||||
const std::list<std::string>& core_type::get_extensions()
|
||||
{
|
||||
return extensions;
|
||||
}
|
||||
|
||||
bool core_type::is_known_extension(const std::string& ext)
|
||||
{
|
||||
std::string _ext = ext;
|
||||
std::transform(_ext.begin(), _ext.end(), _ext.begin(), ::tolower);
|
||||
for(auto i : extensions)
|
||||
if(i == _ext)
|
||||
return true;
|
||||
return false;
|
||||
}
|
||||
|
||||
core_type_region_bind::core_type_region_bind(core_type& type, core_region& region)
|
||||
{
|
||||
reglist1().push_back(std::make_pair(&type, ®ion));
|
||||
|
|
|
@ -76,6 +76,7 @@ namespace
|
|||
std::ofstream ohandle;
|
||||
bool handle_open;
|
||||
std::string current_project;
|
||||
bool lazy_mode;
|
||||
//% is intentionally missing.
|
||||
const char* allowed_filename_chars = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789"
|
||||
"^&'@{}[],$?!-#().+~_";
|
||||
|
@ -94,17 +95,29 @@ namespace
|
|||
}
|
||||
}
|
||||
|
||||
void rrdata::read_base(const std::string& project) throw(std::bad_alloc)
|
||||
void rrdata::read_base(const std::string& project, bool lazy) throw(std::bad_alloc)
|
||||
{
|
||||
if(project == current_project)
|
||||
if(project == current_project && (!lazy_mode || lazy))
|
||||
return;
|
||||
if(lazy) {
|
||||
std::set<rrdata::instance> new_rrset;
|
||||
rrset = new_rrset;
|
||||
current_project = project;
|
||||
lazy_mode = true;
|
||||
if(handle_open)
|
||||
ohandle.close();
|
||||
handle_open = false;
|
||||
return;
|
||||
}
|
||||
std::set<rrdata::instance> new_rrset;
|
||||
if(project == current_project)
|
||||
new_rrset = rrset;
|
||||
std::string filename = get_config_path() + "/" + safe_filename(project) + ".rr";
|
||||
if(handle_open) {
|
||||
ohandle.close();
|
||||
handle_open = false;
|
||||
}
|
||||
ihandle.open(filename.c_str(), std::ios_base::in);
|
||||
ihandle.open(filename.c_str(), std::ios_base::in | std::ios_base::binary);
|
||||
while(ihandle) {
|
||||
unsigned char bytes[RRDATA_BYTES];
|
||||
ihandle.read(reinterpret_cast<char*>(bytes), RRDATA_BYTES);
|
||||
|
@ -113,11 +126,19 @@ void rrdata::read_base(const std::string& project) throw(std::bad_alloc)
|
|||
new_rrset.insert(k);
|
||||
}
|
||||
ihandle.close();
|
||||
ohandle.open(filename.c_str(), std::ios_base::out | std::ios_base::app);
|
||||
ohandle.open(filename.c_str(), std::ios_base::out | std::ios_base::app | std::ios_base::binary);
|
||||
if(ohandle)
|
||||
handle_open = true;
|
||||
if(project == current_project && lazy_mode && !lazy) {
|
||||
//Finish the project creation, write all.
|
||||
for(auto i : rrset) {
|
||||
ohandle.write(reinterpret_cast<const char*>(i.bytes), RRDATA_BYTES);
|
||||
ohandle.flush();
|
||||
}
|
||||
}
|
||||
rrset = new_rrset;
|
||||
current_project = project;
|
||||
lazy_mode = lazy;
|
||||
}
|
||||
|
||||
void rrdata::close() throw()
|
||||
|
|
|
@ -387,7 +387,14 @@ bool lsnes_app::OnInit()
|
|||
msg_window = new wxwin_messages();
|
||||
msg_window->Show();
|
||||
|
||||
open_rom_select_window();
|
||||
do_basic_core_init();
|
||||
loaded_rom* rom = new loaded_rom;
|
||||
moviefile mov;
|
||||
mov.port1 = &porttype_info::port_default(0);
|
||||
mov.port2 = &porttype_info::port_default(1);
|
||||
mov.input.clear(*mov.port1, *mov.port2);
|
||||
mov.start_paused = true;
|
||||
boot_emulator(*rom, mov);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
|
|
@ -92,7 +92,8 @@ enum
|
|||
wxID_LOAD_LIBRARY,
|
||||
wxID_SETTINGS,
|
||||
wxID_RELOAD_ROM_IMAGE,
|
||||
wxID_LOAD_ROM_IMAGE
|
||||
wxID_LOAD_ROM_IMAGE,
|
||||
wxID_NEW_MOVIE,
|
||||
};
|
||||
|
||||
|
||||
|
@ -459,12 +460,33 @@ namespace
|
|||
}
|
||||
|
||||
path_setting moviepath_setting("moviepath");
|
||||
path_setting rompath_setting("rompath");
|
||||
|
||||
std::string movie_path()
|
||||
{
|
||||
return setting::get("moviepath");
|
||||
}
|
||||
|
||||
std::string rom_path()
|
||||
{
|
||||
return setting::get("rompath");
|
||||
}
|
||||
|
||||
bool is_lsnes_movie(const std::string& filename)
|
||||
{
|
||||
try {
|
||||
zip_reader r(filename);
|
||||
std::istream& s = r["systemid"];
|
||||
std::string s2;
|
||||
std::getline(s, s2);
|
||||
delete &s;
|
||||
istrip_CR(s2);
|
||||
return (s2 == "lsnes-rr1");
|
||||
} catch(...) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
class loadfile : public wxFileDropTarget
|
||||
{
|
||||
public:
|
||||
|
@ -472,7 +494,10 @@ namespace
|
|||
{
|
||||
if(filenames.Count() != 1)
|
||||
return false;
|
||||
platform::queue("load " + tostdstring(filenames[0]));
|
||||
if(is_lsnes_movie(tostdstring(filenames[0])))
|
||||
platform::queue("load-smart " + tostdstring(filenames[0]));
|
||||
else
|
||||
platform::queue("reload-rom " + tostdstring(filenames[0]));
|
||||
return true;
|
||||
}
|
||||
};
|
||||
|
@ -688,6 +713,9 @@ wxwin_mainwindow::wxwin_mainwindow()
|
|||
menu_separator();
|
||||
menu_entry(wxID_ABOUT, wxT("About..."));
|
||||
menu_start(wxT("System"));
|
||||
menu_start_sub(wxT("New"));
|
||||
menu_entry(wxID_NEW_MOVIE, wxT("Movie..."));
|
||||
menu_end_sub();
|
||||
menu_start_sub(wxT("Load"));
|
||||
menu_entry(wxID_LOAD_STATE, wxT("State..."));
|
||||
menu_entry(wxID_LOAD_STATE_RO, wxT("State (readonly)..."));
|
||||
|
@ -1068,10 +1096,13 @@ void wxwin_mainwindow::handle_menu_click_cancelable(wxCommandEvent& e)
|
|||
wxsetingsdialog_display(this);
|
||||
break;
|
||||
case wxID_LOAD_ROM_IMAGE:
|
||||
platform::queue("reload-rom " + pick_file_member(this, "Select new ROM image", "."));
|
||||
platform::queue("reload-rom " + pick_file_member(this, "Select new ROM image", rom_path()));
|
||||
return;
|
||||
case wxID_RELOAD_ROM_IMAGE:
|
||||
platform::queue("reload-rom");
|
||||
return;
|
||||
case wxID_NEW_MOVIE:
|
||||
show_projectwindow(this);
|
||||
return;
|
||||
};
|
||||
}
|
||||
|
|
|
@ -18,8 +18,8 @@
|
|||
#define wxID_BUTTONS_BASE (wxID_HIGHEST + 128)
|
||||
|
||||
#define DATATYPES 8
|
||||
#define BROW_SIZE 8
|
||||
#define PRIMITIVES 7
|
||||
#define BROW_SIZE 13
|
||||
#define PRIMITIVES 12
|
||||
|
||||
#define CANDIDATE_LIMIT 200
|
||||
|
||||
|
@ -40,12 +40,17 @@ namespace
|
|||
|
||||
const char* searchtypes[] = {
|
||||
"value",
|
||||
"diff.",
|
||||
"<",
|
||||
"<=",
|
||||
"==",
|
||||
"!=",
|
||||
">=",
|
||||
">",
|
||||
"seq<",
|
||||
"seq<=",
|
||||
"seq>=",
|
||||
"seq>",
|
||||
"true"
|
||||
};
|
||||
|
||||
|
@ -53,21 +58,37 @@ namespace
|
|||
|
||||
primitive_search_t primitive_searches[DATATYPES][PRIMITIVES] = {
|
||||
{ &memorysearch::byte_slt, &memorysearch::byte_sle, &memorysearch::byte_seq, &memorysearch::byte_sne,
|
||||
&memorysearch::byte_sge, &memorysearch::byte_sgt, &memorysearch::update },
|
||||
&memorysearch::byte_sge, &memorysearch::byte_sgt, &memorysearch::byte_seqlt,
|
||||
&memorysearch::byte_seqle, &memorysearch::byte_seqge, &memorysearch::byte_seqgt,
|
||||
&memorysearch::update },
|
||||
{ &memorysearch::byte_ult, &memorysearch::byte_ule, &memorysearch::byte_ueq, &memorysearch::byte_une,
|
||||
&memorysearch::byte_uge, &memorysearch::byte_ugt, &memorysearch::update },
|
||||
&memorysearch::byte_uge, &memorysearch::byte_ugt, &memorysearch::byte_seqlt,
|
||||
&memorysearch::byte_seqle, &memorysearch::byte_seqge, &memorysearch::byte_seqgt,
|
||||
&memorysearch::update },
|
||||
{ &memorysearch::word_slt, &memorysearch::word_sle, &memorysearch::word_seq, &memorysearch::word_sne,
|
||||
&memorysearch::word_sge, &memorysearch::word_sgt, &memorysearch::update },
|
||||
&memorysearch::word_sge, &memorysearch::word_sgt, &memorysearch::word_seqlt,
|
||||
&memorysearch::word_seqle, &memorysearch::word_seqge, &memorysearch::word_seqgt,
|
||||
&memorysearch::update },
|
||||
{ &memorysearch::word_ult, &memorysearch::word_ule, &memorysearch::word_ueq, &memorysearch::word_une,
|
||||
&memorysearch::word_uge, &memorysearch::word_ugt, &memorysearch::update },
|
||||
&memorysearch::word_uge, &memorysearch::word_ugt, &memorysearch::word_seqlt,
|
||||
&memorysearch::word_seqle, &memorysearch::word_seqge, &memorysearch::word_seqgt,
|
||||
&memorysearch::update },
|
||||
{ &memorysearch::dword_slt, &memorysearch::dword_sle, &memorysearch::dword_seq,
|
||||
&memorysearch::dword_sne, &memorysearch::dword_sge, &memorysearch::dword_sgt, &memorysearch::update },
|
||||
&memorysearch::dword_sne, &memorysearch::dword_sge, &memorysearch::dword_sgt,
|
||||
&memorysearch::dword_seqlt, &memorysearch::dword_seqle, &memorysearch::dword_seqge,
|
||||
&memorysearch::dword_seqgt, &memorysearch::update },
|
||||
{ &memorysearch::dword_ult, &memorysearch::dword_ule, &memorysearch::dword_ueq,
|
||||
&memorysearch::dword_une, &memorysearch::dword_uge, &memorysearch::dword_ugt, &memorysearch::update },
|
||||
&memorysearch::dword_une, &memorysearch::dword_uge, &memorysearch::dword_ugt,
|
||||
&memorysearch::dword_seqlt, &memorysearch::dword_seqle, &memorysearch::dword_seqge,
|
||||
&memorysearch::dword_seqgt, &memorysearch::update },
|
||||
{ &memorysearch::qword_slt, &memorysearch::qword_sle, &memorysearch::qword_seq,
|
||||
&memorysearch::qword_sne, &memorysearch::qword_sge, &memorysearch::qword_sgt, &memorysearch::update },
|
||||
&memorysearch::qword_sne, &memorysearch::qword_sge, &memorysearch::qword_sgt,
|
||||
&memorysearch::qword_seqlt, &memorysearch::qword_seqle, &memorysearch::qword_seqge,
|
||||
&memorysearch::qword_seqgt, &memorysearch::update },
|
||||
{ &memorysearch::qword_ult, &memorysearch::qword_ule, &memorysearch::qword_ueq,
|
||||
&memorysearch::qword_une, &memorysearch::qword_uge, &memorysearch::qword_ugt, &memorysearch::update }
|
||||
&memorysearch::qword_une, &memorysearch::qword_uge, &memorysearch::qword_ugt,
|
||||
&memorysearch::qword_seqlt, &memorysearch::qword_seqle, &memorysearch::qword_seqge,
|
||||
&memorysearch::qword_seqgt, &memorysearch::update }
|
||||
};
|
||||
|
||||
std::string hexformat_address(uint64_t addr)
|
||||
|
@ -158,8 +179,9 @@ public:
|
|||
void on_button_click(wxCommandEvent& e);
|
||||
bool update_queued;
|
||||
private:
|
||||
template<typename T> void valuesearch();
|
||||
template<typename T> void valuesearch(bool diff);
|
||||
template<typename T> void valuesearch2(T value);
|
||||
template<typename T> void valuesearch3(T value);
|
||||
void update();
|
||||
memorysearch* msearch;
|
||||
wxStaticText* count;
|
||||
|
@ -290,27 +312,28 @@ void wxwindow_memorysearch::on_button_click(wxCommandEvent& e)
|
|||
typecode = i;
|
||||
} else if(id == wxID_HEX_SELECT) {
|
||||
hexmode = hexmode2->GetValue();
|
||||
} else if(id == wxID_BUTTONS_BASE) {
|
||||
} else if(id == wxID_BUTTONS_BASE || id == wxID_BUTTONS_BASE + 1) {
|
||||
//Value search.
|
||||
bool diff = (id == wxID_BUTTONS_BASE + 1);
|
||||
switch(typecode)
|
||||
{
|
||||
case 0: valuesearch<int8_t>(); break;
|
||||
case 1: valuesearch<uint8_t>(); break;
|
||||
case 2: valuesearch<int16_t>(); break;
|
||||
case 3: valuesearch<uint16_t>(); break;
|
||||
case 4: valuesearch<int32_t>(); break;
|
||||
case 5: valuesearch<uint32_t>(); break;
|
||||
case 6: valuesearch<int64_t>(); break;
|
||||
case 7: valuesearch<uint64_t>(); break;
|
||||
case 0: valuesearch<int8_t>(diff); break;
|
||||
case 1: valuesearch<uint8_t>(diff); break;
|
||||
case 2: valuesearch<int16_t>(diff); break;
|
||||
case 3: valuesearch<uint16_t>(diff); break;
|
||||
case 4: valuesearch<int32_t>(diff); break;
|
||||
case 5: valuesearch<uint32_t>(diff); break;
|
||||
case 6: valuesearch<int64_t>(diff); break;
|
||||
case 7: valuesearch<uint64_t>(diff); break;
|
||||
};
|
||||
} else if(id > wxID_BUTTONS_BASE && id < wxID_BUTTONS_BASE + 1 + PRIMITIVES ) {
|
||||
int button = id - wxID_BUTTONS_BASE - 1;
|
||||
} else if(id > wxID_BUTTONS_BASE + 1 && id < wxID_BUTTONS_BASE + 2 + PRIMITIVES ) {
|
||||
int button = id - wxID_BUTTONS_BASE - 2;
|
||||
(msearch->*(primitive_searches[typecode][button]))();
|
||||
}
|
||||
update();
|
||||
}
|
||||
|
||||
template<typename T> void wxwindow_memorysearch::valuesearch()
|
||||
template<typename T> void wxwindow_memorysearch::valuesearch(bool diff)
|
||||
{
|
||||
std::string v;
|
||||
wxTextEntryDialog* d = new wxTextEntryDialog(this, wxT("Enter value to search for:"), wxT("Memory search"),
|
||||
|
@ -325,10 +348,53 @@ template<typename T> void wxwindow_memorysearch::valuesearch()
|
|||
} catch(...) {
|
||||
wxMessageBox(towxstring("Bad value '" + v + "'"), _T("Error"), wxICON_WARNING | wxOK, this);
|
||||
}
|
||||
if(diff)
|
||||
valuesearch3(val2);
|
||||
else
|
||||
valuesearch2(val2);
|
||||
update();
|
||||
}
|
||||
|
||||
template<> void wxwindow_memorysearch::valuesearch3<int8_t>(int8_t val)
|
||||
{
|
||||
msearch->byte_difference(static_cast<uint8_t>(val));
|
||||
}
|
||||
|
||||
template<> void wxwindow_memorysearch::valuesearch3<uint8_t>(uint8_t val)
|
||||
{
|
||||
msearch->byte_difference(static_cast<uint8_t>(val));
|
||||
}
|
||||
|
||||
template<> void wxwindow_memorysearch::valuesearch3<int16_t>(int16_t val)
|
||||
{
|
||||
msearch->word_difference(static_cast<uint16_t>(val));
|
||||
}
|
||||
|
||||
template<> void wxwindow_memorysearch::valuesearch3<uint16_t>(uint16_t val)
|
||||
{
|
||||
msearch->word_difference(static_cast<uint16_t>(val));
|
||||
}
|
||||
|
||||
template<> void wxwindow_memorysearch::valuesearch3<int32_t>(int32_t val)
|
||||
{
|
||||
msearch->dword_difference(static_cast<uint32_t>(val));
|
||||
}
|
||||
|
||||
template<> void wxwindow_memorysearch::valuesearch3<uint32_t>(uint32_t val)
|
||||
{
|
||||
msearch->dword_difference(static_cast<uint32_t>(val));
|
||||
}
|
||||
|
||||
template<> void wxwindow_memorysearch::valuesearch3<int64_t>(int64_t val)
|
||||
{
|
||||
msearch->qword_difference(static_cast<uint64_t>(val));
|
||||
}
|
||||
|
||||
template<> void wxwindow_memorysearch::valuesearch3<uint64_t>(uint64_t val)
|
||||
{
|
||||
msearch->qword_difference(static_cast<uint64_t>(val));
|
||||
}
|
||||
|
||||
template<> void wxwindow_memorysearch::valuesearch2<int8_t>(int8_t val)
|
||||
{
|
||||
msearch->byte_value(static_cast<uint8_t>(val));
|
||||
|
|
|
@ -10,6 +10,7 @@
|
|||
#include "core/moviedata.hpp"
|
||||
#include "core/framerate.hpp"
|
||||
#include "core/settings.hpp"
|
||||
#include "core/window.hpp"
|
||||
#include "library/zip.hpp"
|
||||
|
||||
#include "platform/wxwidgets/platform.hpp"
|
||||
|
@ -159,205 +160,12 @@ namespace
|
|||
private:
|
||||
wxTextCtrl* ctrl;
|
||||
};
|
||||
|
||||
path_setting rompath_setting("rompath");
|
||||
|
||||
std::string rom_path()
|
||||
{
|
||||
//This is pre-boot, so read directly.
|
||||
return rompath_setting;
|
||||
}
|
||||
|
||||
struct rom_slot_callback
|
||||
{
|
||||
virtual void on_file_change() = 0;
|
||||
};
|
||||
|
||||
class rom_slot : public wxEvtHandler
|
||||
class wxwin_project : public wxDialog
|
||||
{
|
||||
public:
|
||||
rom_slot(wxWindow* inWindow, rom_slot_callback* _cb);
|
||||
void show(wxSizer* sizer);
|
||||
void hide(wxSizer* sizer);
|
||||
void change(const std::string& name, bool has_markup);
|
||||
std::string get_filename();
|
||||
std::string get_markup();
|
||||
void on_change(wxCommandEvent& e);
|
||||
void on_filename_b(wxCommandEvent& e);
|
||||
void on_markup_b(wxCommandEvent& e);
|
||||
private:
|
||||
wxPanel* panel;
|
||||
wxBoxSizer* top;
|
||||
wxStaticBox* box;
|
||||
wxButton* filename_pick;
|
||||
wxButton* markup_pick;
|
||||
wxTextCtrl* filename;
|
||||
wxTextCtrl* markup;
|
||||
bool markup_flag;
|
||||
bool enabled;
|
||||
rom_slot_callback* cb;
|
||||
wxStaticBoxSizer* intsizer;
|
||||
};
|
||||
|
||||
rom_slot::rom_slot(wxWindow* in_window, rom_slot_callback* _cb)
|
||||
{
|
||||
wxSizer* tmp;
|
||||
cb = _cb;
|
||||
panel = new wxPanel(in_window);
|
||||
top = new wxBoxSizer(wxVERTICAL);
|
||||
panel->SetSizer(top);
|
||||
box = new wxStaticBox(panel, wxID_ANY, wxT(""));
|
||||
intsizer = new wxStaticBoxSizer(box, wxVERTICAL);
|
||||
intsizer->Add(new wxStaticText(panel, wxID_ANY, wxT("File")));
|
||||
tmp = new wxBoxSizer(wxHORIZONTAL);
|
||||
tmp->Add(filename = new wxTextCtrl(panel, wxID_ANY, wxT(""), wxDefaultPosition,
|
||||
wxSize(400,-1)), 1, wxGROW);
|
||||
filename->Connect(wxEVT_COMMAND_TEXT_UPDATED, wxCommandEventHandler(rom_slot::on_change), NULL, this);
|
||||
filename->SetDropTarget(new textboxloadfilename(filename));
|
||||
tmp->Add(filename_pick = new wxButton(panel, wxID_ANY, wxT("Pick...")));
|
||||
filename_pick->Connect(wxEVT_COMMAND_BUTTON_CLICKED, wxCommandEventHandler(rom_slot::on_filename_b),
|
||||
NULL, this);;
|
||||
intsizer->Add(tmp);
|
||||
intsizer->Add(new wxStaticText(panel, wxID_ANY, wxT("Default mappings override file (optional) ")));
|
||||
tmp = new wxBoxSizer(wxHORIZONTAL);
|
||||
tmp->Add(markup = new wxTextCtrl(panel, wxID_ANY, wxT(""), wxDefaultPosition,
|
||||
wxSize(400,-1)), 1, wxGROW);
|
||||
markup->Connect(wxEVT_COMMAND_TEXT_UPDATED, wxCommandEventHandler(rom_slot::on_change), NULL, this);
|
||||
markup->SetDropTarget(new textboxloadfilename(markup));
|
||||
tmp->Add(markup_pick = new wxButton(panel, wxID_ANY, wxT("Pick...")));
|
||||
markup_pick->Connect(wxEVT_COMMAND_BUTTON_CLICKED, wxCommandEventHandler(rom_slot::on_markup_b),
|
||||
NULL, this);
|
||||
intsizer->Add(tmp);
|
||||
markup->Enable(markup_flag = false);
|
||||
top->Add(intsizer);
|
||||
hide(NULL);
|
||||
enabled = false;
|
||||
}
|
||||
|
||||
void rom_slot::on_change(wxCommandEvent& e)
|
||||
{
|
||||
if(cb)
|
||||
cb->on_file_change();
|
||||
}
|
||||
|
||||
void rom_slot::show(wxSizer* sizer)
|
||||
{
|
||||
panel->Show();
|
||||
sizer->Add(panel);
|
||||
enabled = true;
|
||||
intsizer->Layout();
|
||||
top->Layout();
|
||||
sizer->Layout();
|
||||
}
|
||||
|
||||
void rom_slot::hide(wxSizer* sizer)
|
||||
{
|
||||
if(sizer)
|
||||
sizer->Detach(panel);
|
||||
enabled = false;
|
||||
panel->Hide();
|
||||
if(sizer)
|
||||
sizer->Layout();
|
||||
}
|
||||
|
||||
void rom_slot::change(const std::string& name, bool has_markup)
|
||||
{
|
||||
box->SetLabel(towxstring(name));
|
||||
markup_flag = has_markup;
|
||||
markup->Enable(has_markup);
|
||||
markup_pick->Enable(has_markup);
|
||||
}
|
||||
|
||||
std::string rom_slot::get_filename()
|
||||
{
|
||||
if(!enabled)
|
||||
return "";
|
||||
return tostdstring(filename->GetValue());
|
||||
}
|
||||
|
||||
std::string rom_slot::get_markup()
|
||||
{
|
||||
if(!enabled || !markup_flag)
|
||||
return "";
|
||||
return tostdstring(markup->GetValue());
|
||||
}
|
||||
|
||||
void rom_slot::on_filename_b(wxCommandEvent& e)
|
||||
{
|
||||
try {
|
||||
std::string fname = pick_file_member(panel, "Choose ROM file", rom_path());
|
||||
filename->SetValue(towxstring(fname));
|
||||
on_change(e);
|
||||
} catch(canceled_exception& e) {
|
||||
}
|
||||
}
|
||||
|
||||
void rom_slot::on_markup_b(wxCommandEvent& e)
|
||||
{
|
||||
try {
|
||||
std::string fname = pick_file_member(panel, "Choose markup file", rom_path());
|
||||
markup->SetValue(towxstring(fname));
|
||||
on_change(e);
|
||||
} catch(canceled_exception& e) {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
class wxwin_romselect : public wxFrame, rom_slot_callback
|
||||
{
|
||||
public:
|
||||
wxwin_romselect();
|
||||
~wxwin_romselect();
|
||||
void on_filename_change(wxCommandEvent& e);
|
||||
void on_romtype_change(wxCommandEvent& e);
|
||||
void on_quit(wxCommandEvent& e);
|
||||
void on_open_rom(wxCommandEvent& e);
|
||||
void on_apply_rom(wxCommandEvent& e);
|
||||
void on_openapply_rom(wxCommandEvent& e, bool apply);
|
||||
void on_file_change();
|
||||
loaded_rom* our_rom;
|
||||
private:
|
||||
wxComboBox* romtype_combo;
|
||||
wxComboBox* region_combo;
|
||||
wxBoxSizer* romgrid;
|
||||
rom_slot* slots[ROMSELECT_ROM_COUNT];
|
||||
wxButton* apply_rom;
|
||||
wxButton* open_rom;
|
||||
wxButton* quit_button;
|
||||
std::string current_rtype;
|
||||
void set_rtype(std::string rtype);
|
||||
};
|
||||
|
||||
void open_rom_select_window()
|
||||
{
|
||||
wxwin_romselect* romwin = new wxwin_romselect();
|
||||
romwin->Show();
|
||||
}
|
||||
|
||||
class wxwin_patch : public wxFrame
|
||||
{
|
||||
public:
|
||||
wxwin_patch(loaded_rom& rom);
|
||||
~wxwin_patch();
|
||||
void on_patchfile_change(wxCommandEvent& e);
|
||||
void on_ask_patchfile(wxCommandEvent& e);
|
||||
void on_do_patch(wxCommandEvent& e);
|
||||
void on_quit(wxCommandEvent& e);
|
||||
void on_done(wxCommandEvent& e);
|
||||
loaded_rom* our_rom;
|
||||
private:
|
||||
wxComboBox* patch_what;
|
||||
wxStaticText* checksums[ROMSELECT_ROM_COUNT];
|
||||
wxTextCtrl* patchfile;
|
||||
wxButton* choosefile;
|
||||
wxButton* dopatch;
|
||||
wxTextCtrl* patch_offset;
|
||||
};
|
||||
|
||||
class wxwin_project : public wxFrame
|
||||
{
|
||||
public:
|
||||
wxwin_project(loaded_rom& rom);
|
||||
wxwin_project();
|
||||
~wxwin_project();
|
||||
void on_file_select(wxCommandEvent& e);
|
||||
void on_new_select(wxCommandEvent& e);
|
||||
|
@ -365,19 +173,12 @@ public:
|
|||
void on_ask_filename(wxCommandEvent& e);
|
||||
void on_quit(wxCommandEvent& e);
|
||||
void on_load(wxCommandEvent& e);
|
||||
void on_tab_select(wxNotebookEvent& e);
|
||||
loaded_rom* our_rom;
|
||||
private:
|
||||
bool load_file;
|
||||
struct moviefile make_movie();
|
||||
wxTextCtrl* savefile;
|
||||
wxButton* ask_savefile;
|
||||
wxNotebook* notebook;
|
||||
std::map<std::string, wxTextCtrl*> sram_files;
|
||||
std::map<std::string, wxButton*> sram_choosers;
|
||||
wxComboBox* controller1type;
|
||||
wxComboBox* controller2type;
|
||||
wxCheckBox* start_pause;
|
||||
wxTextCtrl* projectname;
|
||||
wxTextCtrl* prefix;
|
||||
wxTextCtrl* rtc_sec;
|
||||
|
@ -389,349 +190,24 @@ private:
|
|||
};
|
||||
|
||||
|
||||
wxwin_romselect::wxwin_romselect()
|
||||
: wxFrame(NULL, wxID_ANY, wxT("Select ROM"), wxDefaultPosition, wxSize(-1, -1),
|
||||
wxMINIMIZE_BOX | wxSYSTEM_MENU | wxCAPTION | wxCLIP_CHILDREN | wxCLOSE_BOX)
|
||||
|
||||
void show_projectwindow(wxWindow* modwin)
|
||||
{
|
||||
std::vector<wxString> rtchoices;
|
||||
std::vector<wxString> rrchoices;
|
||||
size_t systems = populate_system_choices(rtchoices);
|
||||
size_t regions = populate_region_choices(rrchoices);
|
||||
|
||||
Centre();
|
||||
|
||||
//The toplevel sizer contains three sizers:
|
||||
//- The top bar having ROM type / Region selects.
|
||||
//- The middle area having ROM filename boxes.
|
||||
//- The bottom bar having OK/Quit buttons.
|
||||
wxFlexGridSizer* toplevel = new wxFlexGridSizer(3, 1, 0, 0);
|
||||
SetSizer(toplevel);
|
||||
|
||||
//The ROM type / Region selects.
|
||||
wxBoxSizer* selects = new wxBoxSizer(wxHORIZONTAL);
|
||||
selects->Add(new wxStaticText(this, wxID_ANY, wxT("ROM type:")), 0, wxGROW);
|
||||
selects->Add(romtype_combo = new wxComboBox(this, wxID_ANY, rtchoices[0], wxDefaultPosition, wxDefaultSize,
|
||||
systems, &rtchoices[0], wxCB_READONLY), 0, wxGROW);
|
||||
selects->Add(new wxStaticText(this, wxID_ANY, wxT("Region:")), 0, wxGROW);
|
||||
selects->Add(region_combo = new wxComboBox(this, wxID_ANY, rrchoices[0], wxDefaultPosition, wxDefaultSize,
|
||||
regions, &rrchoices[0], wxCB_READONLY), 0, wxGROW);
|
||||
romtype_combo->Connect(wxEVT_COMMAND_COMBOBOX_SELECTED,
|
||||
wxCommandEventHandler(wxwin_romselect::on_romtype_change), NULL, this);
|
||||
region_combo->Connect(wxEVT_COMMAND_COMBOBOX_SELECTED,
|
||||
wxCommandEventHandler(wxwin_romselect::on_romtype_change), NULL, this);
|
||||
toplevel->Add(selects, 0, wxGROW);
|
||||
|
||||
//ROM filename selects
|
||||
romgrid = new wxBoxSizer(wxVERTICAL);
|
||||
for(unsigned i = 0; i < ROMSELECT_ROM_COUNT; i++)
|
||||
slots[i] = new rom_slot(this, this);
|
||||
toplevel->Add(romgrid, 1, wxGROW);
|
||||
|
||||
//Button bar.
|
||||
wxBoxSizer* buttons = new wxBoxSizer(wxHORIZONTAL);
|
||||
buttons->Add(apply_rom = new wxButton(this, wxID_ANY, wxT("Apply patches")), 0, wxALIGN_RIGHT);
|
||||
buttons->Add(open_rom = new wxButton(this, wxID_OPEN, wxT("Open ROM")), 0, wxALIGN_RIGHT);
|
||||
buttons->AddStretchSpacer();
|
||||
buttons->Add(quit_button = new wxButton(this, wxID_EXIT, wxT("Quit")), 0, wxALIGN_RIGHT);
|
||||
apply_rom->Connect(wxEVT_COMMAND_BUTTON_CLICKED,
|
||||
wxCommandEventHandler(wxwin_romselect::on_apply_rom), NULL, this);
|
||||
open_rom->Connect(wxEVT_COMMAND_BUTTON_CLICKED,
|
||||
wxCommandEventHandler(wxwin_romselect::on_open_rom), NULL, this);
|
||||
open_rom->Disable();
|
||||
apply_rom->Disable();
|
||||
quit_button->Connect(wxEVT_COMMAND_BUTTON_CLICKED,
|
||||
wxCommandEventHandler(wxwin_romselect::on_quit), NULL, this);
|
||||
toplevel->Add(buttons, 1, wxGROW);
|
||||
|
||||
//Initialize form.
|
||||
set_rtype("");
|
||||
|
||||
//Display it.
|
||||
toplevel->SetSizeHints(this);
|
||||
Fit();
|
||||
}
|
||||
|
||||
wxwin_romselect::~wxwin_romselect()
|
||||
{
|
||||
for(size_t i = 0; i < ROMSELECT_ROM_COUNT; i++)
|
||||
delete slots[i];
|
||||
}
|
||||
|
||||
void wxwin_romselect::set_rtype(std::string rtype)
|
||||
{
|
||||
bool no_rtype = (current_rtype == "");
|
||||
if(rtype == "")
|
||||
rtype = tostdstring(romtype_combo->GetValue());
|
||||
if(rtype == current_rtype)
|
||||
return;
|
||||
region_combo->Clear();
|
||||
for(auto i : romtype_from_string(rtype).get_regions())
|
||||
region_combo->Append(towxstring(i->get_hname()));
|
||||
region_combo->SetSelection(0);
|
||||
if(has_forced_region(rtype))
|
||||
region_combo->Disable();
|
||||
else
|
||||
region_combo->Enable();
|
||||
std::string tmp[ROMSELECT_ROM_COUNT];
|
||||
unsigned c = fill_rom_names(romtype_from_string(rtype), tmp);
|
||||
for(unsigned i = 0; i < ROMSELECT_ROM_COUNT; i++)
|
||||
slots[i]->hide(romgrid);
|
||||
for(unsigned i = 0; i < c; i++) {
|
||||
slots[i]->change(tmp[i], true);
|
||||
slots[i]->show(romgrid);
|
||||
}
|
||||
romgrid->Layout();
|
||||
current_rtype = rtype;
|
||||
Fit();
|
||||
}
|
||||
|
||||
void wxwin_romselect::on_file_change()
|
||||
{
|
||||
bool ok = true;
|
||||
core_type& rtype = romtype_from_string(tostdstring(romtype_combo->GetValue()));
|
||||
unsigned flags = 0;
|
||||
for(unsigned i = 0; i < ROMSELECT_ROM_COUNT; i++)
|
||||
flags |= ((slots[i]->get_filename() != "") ? (1 << i) : 0);
|
||||
open_rom->Enable(check_present_roms(rtype, flags));
|
||||
apply_rom->Enable(check_present_roms(rtype, flags));
|
||||
}
|
||||
|
||||
void wxwin_romselect::on_romtype_change(wxCommandEvent& e)
|
||||
{
|
||||
set_rtype(tostdstring(romtype_combo->GetValue()));
|
||||
on_file_change();
|
||||
}
|
||||
|
||||
void wxwin_romselect::on_quit(wxCommandEvent& e)
|
||||
{
|
||||
Close(true);
|
||||
}
|
||||
|
||||
void wxwin_romselect::on_open_rom(wxCommandEvent& e)
|
||||
{
|
||||
on_openapply_rom(e, false);
|
||||
}
|
||||
|
||||
void wxwin_romselect::on_apply_rom(wxCommandEvent& e)
|
||||
{
|
||||
on_openapply_rom(e, true);
|
||||
}
|
||||
|
||||
|
||||
void wxwin_romselect::on_openapply_rom(wxCommandEvent& e, bool apply)
|
||||
{
|
||||
rom_files rfiles;
|
||||
rfiles.base_file = "";
|
||||
rfiles.rtype = &romtype_from_string(tostdstring(romtype_combo->GetValue()));
|
||||
rfiles.region = ®ion_from_string(*rfiles.rtype, tostdstring(region_combo->GetValue()));
|
||||
for(size_t i = 0; i < ROMSELECT_ROM_COUNT && i < sizeof(rfiles.romimg) / sizeof(rfiles.romimg[0]); i++) {
|
||||
rfiles.romimg[i] = slots[i]->get_filename();
|
||||
rfiles.romxml[i] = slots[i]->get_markup();
|
||||
}
|
||||
try {
|
||||
our_rom = new loaded_rom(rfiles);
|
||||
our_rom_name = "";
|
||||
for(size_t i = 1; i < sizeof(our_rom->romimg) / sizeof(our_rom->romimg[0]); i++)
|
||||
if(our_rom->romimg[i].valid && our_rom_name == "")
|
||||
our_rom_name = our_rom->romimg[i].sha256;
|
||||
if(our_rom_name == "")
|
||||
our_rom_name = our_rom->romimg[0].sha256;
|
||||
} catch(std::exception& e) {
|
||||
show_message_ok(this, "Error loading ROM", e.what(), wxICON_EXCLAMATION);
|
||||
if(!our_rom->rtype) {
|
||||
show_message_ok(modwin, "Can't start new movie", "No ROM loaded", wxICON_EXCLAMATION);
|
||||
return;
|
||||
}
|
||||
if(apply) {
|
||||
wxwin_patch* projwin = new wxwin_patch(*our_rom);
|
||||
projwin->Show();
|
||||
} else {
|
||||
patching_done(*our_rom, this);
|
||||
}
|
||||
Destroy();
|
||||
}
|
||||
//---------------------------------------------------
|
||||
wxwin_patch::wxwin_patch(loaded_rom& rom)
|
||||
: wxFrame(NULL, wxID_ANY, wxT("Patch ROM"), wxDefaultPosition, wxSize(-1, -1),
|
||||
wxMINIMIZE_BOX | wxSYSTEM_MENU | wxCAPTION | wxCLIP_CHILDREN | wxCLOSE_BOX)
|
||||
{
|
||||
our_rom = &rom;
|
||||
wxString targets[2 * ROMSELECT_ROM_COUNT];
|
||||
std::string _targets[ROMSELECT_ROM_COUNT];
|
||||
size_t _target_count = fill_rom_names(*rom.rtype, _targets);
|
||||
size_t target_count = 0;
|
||||
for(auto i = 0; i < _target_count; i++) {
|
||||
targets[2 * i] = towxstring(_targets[i]);
|
||||
targets[2 * i + 1] = towxstring(_targets[i] + MARKUP_POSTFIX);
|
||||
target_count += 2;
|
||||
wxwin_project* projwin = new wxwin_project();
|
||||
projwin->ShowModal();
|
||||
projwin->Destroy();
|
||||
}
|
||||
|
||||
//Toplevel has 5 blocks:
|
||||
//- Checksums for ROMs.
|
||||
//- Patch what select.
|
||||
//- Filename select.
|
||||
//- Patch offset.
|
||||
//- Button bar.
|
||||
Centre();
|
||||
wxFlexGridSizer* toplevel = new wxFlexGridSizer(5, 1, 0, 0);
|
||||
SetSizer(toplevel);
|
||||
|
||||
//Checksums block.
|
||||
wxFlexGridSizer* hashes = new wxFlexGridSizer(target_count, 2, 0, 0);
|
||||
for(unsigned i = 0; i < ROMSELECT_ROM_COUNT; i++)
|
||||
checksums[i] = NULL;
|
||||
for(unsigned i = 0; i < target_count; i++) {
|
||||
std::string hash = get_rom_slot(*our_rom, i).sha256;
|
||||
if(hash == "")
|
||||
hash = "<Not present>";
|
||||
hashes->Add(new wxStaticText(this, wxID_ANY, targets[i]), 0, wxGROW);
|
||||
hashes->Add(checksums[i] = new wxStaticText(this, wxID_ANY, towxstring(hash)), 0, wxGROW);
|
||||
}
|
||||
toplevel->Add(hashes, 0, wxGROW);
|
||||
|
||||
//Target select.
|
||||
wxFlexGridSizer* targetselect = new wxFlexGridSizer(1, 2, 0, 0);
|
||||
targetselect->Add(new wxStaticText(this, wxID_ANY, wxT("Patch what:")), 0, wxGROW);
|
||||
targetselect->Add(patch_what = new wxComboBox(this, wxID_ANY, targets[0], wxDefaultPosition, wxDefaultSize,
|
||||
target_count, targets, wxCB_READONLY), 0, wxGROW);
|
||||
toplevel->Add(targetselect, 0, wxGROW);
|
||||
|
||||
//Patchfile.
|
||||
wxFlexGridSizer* patchsel = new wxFlexGridSizer(1, 3, 0, 0);
|
||||
patchsel->Add(new wxStaticText(this, wxID_ANY, wxT("File:")), 0, wxGROW);
|
||||
patchsel->Add(patchfile = new wxTextCtrl(this, wxID_ANY, wxT(""), wxDefaultPosition, wxSize(500, -1)),
|
||||
1, wxGROW);
|
||||
patchsel->Add(choosefile = new wxButton(this, wxID_ANY, wxT("Pick")), 0, wxGROW);
|
||||
patchfile->Connect(wxEVT_COMMAND_TEXT_UPDATED,
|
||||
wxCommandEventHandler(wxwin_patch::on_patchfile_change), NULL, this);
|
||||
choosefile->Connect(wxEVT_COMMAND_BUTTON_CLICKED,
|
||||
wxCommandEventHandler(wxwin_patch::on_ask_patchfile), NULL, this);
|
||||
patchfile->SetDropTarget(new textboxloadfilename(patchfile));
|
||||
toplevel->Add(patchsel, 0, wxGROW);
|
||||
|
||||
//Patch offset.
|
||||
wxFlexGridSizer* offsetselect = new wxFlexGridSizer(1, 2, 0, 0);
|
||||
offsetselect->Add(new wxStaticText(this, wxID_ANY, wxT("Patch offset:")), 0, wxGROW);
|
||||
offsetselect->Add(patch_offset = new wxTextCtrl(this, wxID_ANY, wxT("")), 0, wxGROW);
|
||||
patch_offset->Connect(wxEVT_COMMAND_TEXT_UPDATED,
|
||||
wxCommandEventHandler(wxwin_patch::on_patchfile_change), NULL, this);
|
||||
toplevel->Add(offsetselect, 0, wxGROW);
|
||||
|
||||
//Button bar
|
||||
wxBoxSizer* buttonbar = new wxBoxSizer(wxHORIZONTAL);
|
||||
buttonbar->AddStretchSpacer();
|
||||
wxButton* thats_enough = new wxButton(this, wxID_ANY, wxT("Enough"));
|
||||
buttonbar->Add(thats_enough, 0, wxGROW);
|
||||
thats_enough->Connect(wxEVT_COMMAND_BUTTON_CLICKED,
|
||||
wxCommandEventHandler(wxwin_patch::on_done), NULL, this);
|
||||
dopatch = new wxButton(this, wxID_ANY, wxT("Patch"));
|
||||
buttonbar->Add(dopatch, 0, wxGROW);
|
||||
dopatch->Connect(wxEVT_COMMAND_BUTTON_CLICKED,
|
||||
wxCommandEventHandler(wxwin_patch::on_do_patch), NULL, this);
|
||||
dopatch->Disable();
|
||||
wxButton* quitbutton = new wxButton(this, wxID_EXIT, wxT("Quit"));
|
||||
buttonbar->Add(quitbutton, 0, wxGROW);
|
||||
quitbutton->Connect(wxEVT_COMMAND_BUTTON_CLICKED,
|
||||
wxCommandEventHandler(wxwin_patch::on_quit), NULL, this);
|
||||
toplevel->Add(buttonbar, 0, wxGROW);
|
||||
|
||||
patch_offset->SetValue(wxT("0"));
|
||||
|
||||
hashes->SetSizeHints(this);
|
||||
targetselect->SetSizeHints(this);
|
||||
buttonbar->SetSizeHints(this);
|
||||
toplevel->SetSizeHints(this);
|
||||
Fit();
|
||||
}
|
||||
|
||||
void wxwin_patch::on_ask_patchfile(wxCommandEvent& e)
|
||||
{
|
||||
try {
|
||||
std::string fname = pick_file_member(this, "Choose patch file", rom_path());
|
||||
patchfile->SetValue(towxstring(fname));
|
||||
on_patchfile_change(e);
|
||||
} catch(canceled_exception& e) {
|
||||
}
|
||||
}
|
||||
|
||||
wxwin_patch::~wxwin_patch()
|
||||
{
|
||||
}
|
||||
|
||||
void wxwin_patch::on_patchfile_change(wxCommandEvent& e)
|
||||
{
|
||||
bool ok = true;
|
||||
ok = ok && (patchfile->GetValue().Length() != 0);
|
||||
std::string offsetv = tostdstring(patch_offset->GetValue());
|
||||
try {
|
||||
int32_t offset = boost::lexical_cast<int32_t>(offsetv);
|
||||
} catch(...) {
|
||||
ok = false;
|
||||
}
|
||||
if(dopatch)
|
||||
dopatch->Enable(ok);
|
||||
}
|
||||
|
||||
void wxwin_patch::on_do_patch(wxCommandEvent& e)
|
||||
{
|
||||
try {
|
||||
auto patch_contents = read_file_relative(tostdstring(patchfile->GetValue()), "");
|
||||
size_t patch_index = romname_to_index(*our_rom->rtype, patch_what->GetValue());
|
||||
if(patch_index > 2 * ROMSELECT_ROM_COUNT)
|
||||
throw std::runtime_error("Internal error: Patch WHAT?");
|
||||
loaded_slot& s = get_rom_slot(*our_rom, patch_index);
|
||||
std::string offsetv = tostdstring(patch_offset->GetValue());
|
||||
int32_t offset = boost::lexical_cast<int32_t>(offsetv);
|
||||
s.patch(patch_contents, offset);
|
||||
checksums[patch_index]->SetLabel(towxstring(s.sha256));
|
||||
} catch(std::exception& e) {
|
||||
show_message_ok(this, "Error patching ROM", e.what(), wxICON_EXCLAMATION);
|
||||
return;
|
||||
}
|
||||
patchfile->SetValue(wxT(""));
|
||||
}
|
||||
|
||||
void wxwin_patch::on_quit(wxCommandEvent& e)
|
||||
{
|
||||
Close(true);
|
||||
}
|
||||
|
||||
void patching_done(struct loaded_rom& rom, wxWindow* modwin)
|
||||
{
|
||||
struct loaded_rom* our_rom = &rom;
|
||||
try {
|
||||
do_basic_core_init();
|
||||
our_rom_name = "";
|
||||
for(size_t i = 1; i < sizeof(our_rom->romimg) / sizeof(our_rom->romimg[0]); i++)
|
||||
if(our_rom->romimg[i].valid && our_rom_name == "")
|
||||
our_rom_name = our_rom->romimg[i].sha256;
|
||||
if(our_rom_name == "")
|
||||
our_rom_name = our_rom->romimg[0].sha256;
|
||||
our_rom->load(1000000000, 0);
|
||||
} catch(std::exception& e) {
|
||||
show_message_ok(modwin, "Error loading ROM", e.what(), wxICON_EXCLAMATION);
|
||||
return;
|
||||
}
|
||||
messages << "Detected region: " << our_rom->rtype->combine_region(*our_rom->region).get_name() << std::endl;
|
||||
set_nominal_framerate(our_rom->region->approx_framerate());
|
||||
|
||||
messages << "--- Internal memory mappings ---" << std::endl;
|
||||
dump_region_map();
|
||||
messages << "--- End of Startup --- " << std::endl;
|
||||
wxwin_project* projwin = new wxwin_project(*our_rom);
|
||||
projwin->Show();
|
||||
}
|
||||
|
||||
void wxwin_patch::on_done(wxCommandEvent& e)
|
||||
{
|
||||
patching_done(*our_rom, this);
|
||||
Destroy();
|
||||
}
|
||||
//------------------------------------------------------------
|
||||
|
||||
wxwin_project::wxwin_project(loaded_rom& rom)
|
||||
: wxFrame(NULL, wxID_ANY, wxT("Project settings"), wxDefaultPosition, wxSize(-1, -1),
|
||||
wxwin_project::wxwin_project()
|
||||
: wxDialog(NULL, wxID_ANY, wxT("Project settings"), wxDefaultPosition, wxSize(-1, -1),
|
||||
wxMINIMIZE_BOX | wxSYSTEM_MENU | wxCAPTION | wxCLIP_CHILDREN | wxCLOSE_BOX)
|
||||
{
|
||||
our_rom = &rom;
|
||||
std::vector<wxString> cchoices;
|
||||
unsigned dfltidx;
|
||||
|
||||
|
@ -743,27 +219,7 @@ wxwin_project::wxwin_project(loaded_rom& rom)
|
|||
//- Button bar.
|
||||
wxBoxSizer* toplevel = new wxBoxSizer(wxVERTICAL);
|
||||
SetSizer(toplevel);
|
||||
notebook = new wxNotebook(this, wxID_ANY, wxDefaultPosition, wxDefaultSize, wxNB_TOP);
|
||||
wxPanel* load_panel = new wxPanel(notebook);
|
||||
wxPanel* new_panel = new wxPanel(notebook);
|
||||
|
||||
//The load page.
|
||||
wxSizer* load_sizer = new wxFlexGridSizer(1, 3, 0, 0);
|
||||
wxSizer* load_sizer2 = new wxBoxSizer(wxVERTICAL);
|
||||
load_panel->SetSizer(load_sizer2);
|
||||
load_sizer2->Add(load_sizer, 0, wxGROW);
|
||||
load_sizer->Add(new wxStaticText(load_panel, wxID_ANY, wxT("File to load:")), 0, wxGROW);
|
||||
load_sizer->Add(savefile = new wxTextCtrl(load_panel, wxID_ANY, wxT(""), wxDefaultPosition, wxSize(500, -1)),
|
||||
1, wxGROW);
|
||||
savefile->SetDropTarget(new textboxloadfilename(savefile));
|
||||
|
||||
load_sizer->Add(ask_savefile = new wxButton(load_panel, ASK_FILENAME_BUTTON, wxT("Pick")), 0, wxGROW);
|
||||
load_sizer2->Add(start_pause = new wxCheckBox(load_panel, wxID_ANY, wxT("Start paused")), 0, wxGROW);
|
||||
savefile->Connect(wxEVT_COMMAND_TEXT_UPDATED,
|
||||
wxCommandEventHandler(wxwin_project::on_filename_change), NULL, this);
|
||||
ask_savefile->Connect(wxEVT_COMMAND_BUTTON_CLICKED,
|
||||
wxCommandEventHandler(wxwin_project::on_ask_filename), NULL, this);
|
||||
notebook->AddPage(load_panel, wxT("Load save/movie"));
|
||||
wxPanel* new_panel = new wxPanel(this);
|
||||
|
||||
//The new page.
|
||||
//3 Page-level blocks.
|
||||
|
@ -827,10 +283,7 @@ wxwin_project::wxwin_project(loaded_rom& rom)
|
|||
authors->Connect(wxEVT_COMMAND_TEXT_UPDATED, wxCommandEventHandler(wxwin_project::on_filename_change), NULL,
|
||||
this);
|
||||
|
||||
notebook->Connect(wxEVT_COMMAND_NOTEBOOK_PAGE_CHANGED, wxNotebookEventHandler(wxwin_project::on_tab_select),
|
||||
NULL, this);
|
||||
notebook->AddPage(new_panel, wxT("New movie"));
|
||||
toplevel->Add(notebook, 1, wxGROW);
|
||||
toplevel->Add(new_panel, 1, wxGROW);
|
||||
|
||||
//Button bar.
|
||||
wxBoxSizer* buttonbar = new wxBoxSizer(wxHORIZONTAL);
|
||||
|
@ -843,25 +296,13 @@ wxwin_project::wxwin_project(loaded_rom& rom)
|
|||
wxCommandEventHandler(wxwin_project::on_quit), NULL, this);
|
||||
toplevel->Add(buttonbar, 0, wxGROW);
|
||||
|
||||
bool file_filled = false;
|
||||
{
|
||||
std::ifstream s(get_config_path() + "/" + our_rom_name + ".ls");
|
||||
std::getline(s, last_save);
|
||||
savefile->SetValue(towxstring(last_save));
|
||||
if(last_save != "")
|
||||
file_filled = true;
|
||||
}
|
||||
|
||||
//This gets re-enabled later if needed.
|
||||
load_file = true;
|
||||
load->Disable();
|
||||
notebook->SetSelection(file_filled ? 0 : 1);
|
||||
wxCommandEvent e2;
|
||||
on_filename_change(e2);
|
||||
|
||||
mainblock->SetSizeHints(this);
|
||||
new_sizer->SetSizeHints(this);
|
||||
load_sizer->SetSizeHints(this);
|
||||
toplevel->SetSizeHints(this);
|
||||
Fit();
|
||||
}
|
||||
|
@ -870,32 +311,11 @@ wxwin_project::~wxwin_project()
|
|||
{
|
||||
}
|
||||
|
||||
void wxwin_project::on_tab_select(wxNotebookEvent& e)
|
||||
{
|
||||
int p = e.GetSelection();
|
||||
if(p < 0) {
|
||||
load->Disable();
|
||||
return;
|
||||
} else if(p == 0) {
|
||||
load_file = true;
|
||||
load->SetLabel(wxT("Load"));
|
||||
} else if(p == 1) {
|
||||
load_file = false;
|
||||
load->SetLabel(wxT("Start"));
|
||||
}
|
||||
wxCommandEvent e2;
|
||||
on_filename_change(e2);
|
||||
e.Skip();
|
||||
}
|
||||
|
||||
void wxwin_project::on_ask_filename(wxCommandEvent& e)
|
||||
{
|
||||
int id = e.GetId();
|
||||
try {
|
||||
if(id == ASK_FILENAME_BUTTON) {
|
||||
std::string fname = pick_file(this, "Choose save/movie", ".");
|
||||
savefile->SetValue(towxstring(fname));
|
||||
} else if(id >= ASK_SRAMS_BASE && id <= ASK_SRAMS_LAST) {
|
||||
if(id >= ASK_SRAMS_BASE && id <= ASK_SRAMS_LAST) {
|
||||
std::string fname = pick_file_member(this, "Choose " + sram_names[id - ASK_SRAMS_BASE], ".");
|
||||
sram_files[sram_names[id - ASK_SRAMS_BASE]]->SetValue(towxstring(fname));
|
||||
}
|
||||
|
@ -906,9 +326,6 @@ void wxwin_project::on_ask_filename(wxCommandEvent& e)
|
|||
|
||||
void wxwin_project::on_filename_change(wxCommandEvent& e)
|
||||
{
|
||||
if(load_file) {
|
||||
load->Enable(savefile->GetValue().Length() != 0);
|
||||
} else {
|
||||
try {
|
||||
boost::lexical_cast<int64_t>(tostdstring(rtc_sec->GetValue()));
|
||||
if(boost::lexical_cast<int64_t>(tostdstring(rtc_subsec->GetValue())) < 0)
|
||||
|
@ -924,26 +341,20 @@ void wxwin_project::on_filename_change(wxCommandEvent& e)
|
|||
load->Disable();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void wxwin_project::on_quit(wxCommandEvent& e)
|
||||
{
|
||||
Close(true);
|
||||
EndModal(0);
|
||||
}
|
||||
|
||||
void wxwin_project::on_load(wxCommandEvent& e)
|
||||
{
|
||||
try {
|
||||
if(load_file) {
|
||||
moviefile& mov = *new moviefile(tostdstring(savefile->GetValue()));
|
||||
mov.start_paused = start_pause->GetValue();
|
||||
boot_emulator(*our_rom, mov);
|
||||
} else {
|
||||
moviefile& mov = *new moviefile(make_movie());
|
||||
mov.start_paused = start_pause->GetValue();
|
||||
boot_emulator(*our_rom, mov);
|
||||
}
|
||||
Destroy();
|
||||
moviefile mov = make_movie();
|
||||
mov.start_paused = false;
|
||||
mov.save(get_config_path() + "/movie.tmp", 0);
|
||||
platform::queue("load-state " + get_config_path() + "/movie.tmp");
|
||||
EndModal(0);
|
||||
} catch(std::exception& e) {
|
||||
show_message_ok(this, "Error loading movie", e.what(), wxICON_EXCLAMATION);
|
||||
return;
|
||||
|
|
|
@ -6,6 +6,19 @@
|
|||
#include <string>
|
||||
#include <sstream>
|
||||
|
||||
std::string name_subrom(core_type& major, unsigned romnumber) throw(std::bad_alloc)
|
||||
{
|
||||
std::string name = "UNKNOWN";
|
||||
if(romnumber < 2 * major.get_image_count())
|
||||
name = major.get_image_info(romnumber / 2).hname;
|
||||
if(romnumber % 2)
|
||||
return name + " XML";
|
||||
else if(name != "ROM")
|
||||
return name + " ROM";
|
||||
else
|
||||
return "ROM";
|
||||
}
|
||||
|
||||
std::string escape_string(std::string x)
|
||||
{
|
||||
std::ostringstream out;
|
||||
|
|
Loading…
Add table
Reference in a new issue