Merge branch 'rr1-maint' into rr1-gambatte

This commit is contained in:
Ilari Liusvaara 2012-08-24 20:42:33 +03:00
commit 89ed1d5a2c
21 changed files with 826 additions and 1075 deletions

View file

@ -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)

View file

@ -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.
*

View file

@ -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

View file

@ -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;
};

View file

@ -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.
*/

View file

@ -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);

View file

@ -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);

View file

@ -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) {

View file

@ -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"

View file

@ -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;
}

View file

@ -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;

View file

@ -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.
rrdata::add_internal();
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,13 +430,15 @@ 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());
messages << "ROM Type " << our_rom->rtype->get_hname() << " region " << our_rom->region->get_hname()
<< std::endl;
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();
{
mlength += 999999;
@ -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;

View file

@ -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]);

View file

@ -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];
}
if(!files.rtype) {
rtype = NULL;
region = orig_region = files.region;
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(!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;
}
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
cromxml[idx] = tmp[3];
}
orig_region = region = files.region;
//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], files.base_file);
msu1_base = resolve_file_relative(cromimg[1], file);
else
msu1_base = resolve_file_relative(cromimg[0], files.base_file);
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->load(images, rtc_sec, rtc_subsec))
throw std::runtime_error("Can't load cartridge ROM");
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");
}

View file

@ -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, &region));

View file

@ -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()

View file

@ -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;
}

View file

@ -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;
};
}

View file

@ -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);
}
valuesearch2(val2);
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));

View file

@ -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
{
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
class wxwin_project : public wxDialog
{
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 = &region_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;
}
//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();
wxwin_project* projwin = new wxwin_project();
projwin->ShowModal();
projwin->Destroy();
}
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,44 +326,35 @@ 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)
throw 42;
size_t lines = authors->GetNumberOfLines();
for(size_t i = 0; i < lines; i++) {
std::string l = tostdstring(authors->GetLineText(i));
if(l == "|")
throw 43;
}
load->Enable();
} catch(...) {
load->Disable();
try {
boost::lexical_cast<int64_t>(tostdstring(rtc_sec->GetValue()));
if(boost::lexical_cast<int64_t>(tostdstring(rtc_subsec->GetValue())) < 0)
throw 42;
size_t lines = authors->GetNumberOfLines();
for(size_t i = 0; i < lines; i++) {
std::string l = tostdstring(authors->GetLineText(i));
if(l == "|")
throw 43;
}
load->Enable();
} catch(...) {
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;

View file

@ -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;