From 36795e80611d104c7bb0dc22393aac6c5db1f13c Mon Sep 17 00:00:00 2001 From: Tim Allen Date: Mon, 18 Jun 2012 20:13:51 +1000 Subject: [PATCH] Update to v089r12 release. byuu says: Changelog: - Game Boy XML uses instead of - if you run bsnes with a filename argument, it will invoke "purify filename" and exit immediately - this chains: purify will turn the file into a game folder, and then invoke bsnes with the game folder name - net result: you can drag a ZIP file onto bsnes or associate SMC headered ROMs with bsnes and they'll just work - new nall: unified usage of - vs _ vs nothing on filenames; fancier lstring; fancier image (constructor for creating from filename or from memory); etc - new phoenix: images in ListView, GTK+ merges the check box into the first column like the other targets do, etc - browser list now uses icons to differentiate system folders from game folders (the game folder icon sucks, I'm open to suggestions though, as long as it's available on Debian Squeeze in /usr/share/icons, no custom stuff please) --- bsnes/emulator/emulator.hpp | 4 +- bsnes/gb/cartridge/cartridge.cpp | 6 +- bsnes/nall/any.hpp | 2 +- bsnes/nall/directory.hpp | 22 +- .../cartridge.hpp => emulation/famicom.hpp} | 33 +- .../game-boy-advance.hpp} | 19 +- .../cartridge.hpp => emulation/game-boy.hpp} | 20 +- .../super-famicom-usart.hpp} | 4 +- .../super-famicom.hpp} | 181 +++-- bsnes/nall/http.hpp | 2 +- bsnes/nall/image.hpp | 41 ++ bsnes/nall/invoke.hpp | 52 ++ bsnes/nall/platform.hpp | 59 +- .../{priorityqueue.hpp => priority-queue.hpp} | 4 +- .../nall/{public_cast.hpp => public-cast.hpp} | 0 bsnes/nall/set.hpp | 2 +- bsnes/nall/snes/cpu.hpp | 458 ------------- bsnes/nall/snes/smp.hpp | 639 ------------------ bsnes/nall/string/base.hpp | 17 +- bsnes/nall/string/core.hpp | 35 +- bsnes/nall/string/platform.hpp | 72 +- bsnes/nall/{type_traits.hpp => traits.hpp} | 4 +- bsnes/nall/varint.hpp | 2 +- bsnes/nall/windows/guid.hpp | 30 + bsnes/nall/windows/registry.hpp | 120 ++++ bsnes/nall/windows/utf8.hpp | 1 + bsnes/nall/zip.hpp | 22 +- bsnes/phoenix/core/core.cpp | 6 + bsnes/phoenix/core/core.hpp | 23 +- bsnes/phoenix/core/state.hpp | 1 + bsnes/phoenix/gtk/action/item.cpp | 8 +- bsnes/phoenix/gtk/action/menu.cpp | 8 +- bsnes/phoenix/gtk/platform.hpp | 5 +- bsnes/phoenix/gtk/utility.cpp | 13 +- bsnes/phoenix/gtk/widget/button.cpp | 8 +- bsnes/phoenix/gtk/widget/list-view.cpp | 93 ++- bsnes/phoenix/phoenix.cpp | 1 + bsnes/phoenix/qt/action/item.cpp | 7 +- bsnes/phoenix/qt/action/menu.cpp | 7 +- bsnes/phoenix/qt/platform.moc | 2 +- bsnes/phoenix/qt/platform.moc.hpp | 1 + bsnes/phoenix/qt/utility.cpp | 8 + bsnes/phoenix/qt/widget/button.cpp | 9 +- bsnes/phoenix/qt/widget/list-view.cpp | 9 + bsnes/phoenix/windows/platform.hpp | 5 +- bsnes/phoenix/windows/widget/list-view.cpp | 39 +- bsnes/target-ethos/Makefile | 3 + bsnes/target-ethos/ethos.cpp | 17 +- bsnes/target-ethos/ethos.hpp | 2 + bsnes/target-ethos/general/browser.cpp | 7 +- bsnes/target-ethos/resource/folder.png | Bin 0 -> 1176 bytes bsnes/target-ethos/resource/game.png | Bin 0 -> 844 bytes bsnes/target-ethos/resource/home.png | Bin 0 -> 1774 bytes bsnes/target-ethos/resource/resource.cpp | 173 +++++ bsnes/target-ethos/resource/resource.hpp | 6 + bsnes/target-ethos/resource/resource.xml | 7 + bsnes/target-ethos/resource/up.png | Bin 0 -> 1193 bytes 57 files changed, 892 insertions(+), 1427 deletions(-) rename bsnes/nall/{nes/cartridge.hpp => emulation/famicom.hpp} (83%) rename bsnes/nall/{gba/cartridge.hpp => emulation/game-boy-advance.hpp} (77%) rename bsnes/nall/{gb/cartridge.hpp => emulation/game-boy.hpp} (88%) rename bsnes/nall/{snes/usart.hpp => emulation/super-famicom-usart.hpp} (96%) rename bsnes/nall/{snes/cartridge.hpp => emulation/super-famicom.hpp} (86%) create mode 100755 bsnes/nall/invoke.hpp rename bsnes/nall/{priorityqueue.hpp => priority-queue.hpp} (97%) rename bsnes/nall/{public_cast.hpp => public-cast.hpp} (100%) delete mode 100755 bsnes/nall/snes/cpu.hpp delete mode 100755 bsnes/nall/snes/smp.hpp rename bsnes/nall/{type_traits.hpp => traits.hpp} (95%) create mode 100755 bsnes/nall/windows/guid.hpp create mode 100755 bsnes/nall/windows/registry.hpp create mode 100755 bsnes/target-ethos/resource/folder.png create mode 100755 bsnes/target-ethos/resource/game.png create mode 100755 bsnes/target-ethos/resource/home.png create mode 100755 bsnes/target-ethos/resource/resource.cpp create mode 100755 bsnes/target-ethos/resource/resource.hpp create mode 100755 bsnes/target-ethos/resource/resource.xml create mode 100755 bsnes/target-ethos/resource/up.png diff --git a/bsnes/emulator/emulator.hpp b/bsnes/emulator/emulator.hpp index 934491506..991320fd3 100755 --- a/bsnes/emulator/emulator.hpp +++ b/bsnes/emulator/emulator.hpp @@ -3,7 +3,7 @@ namespace Emulator { static const char Name[] = "bsnes"; - static const char Version[] = "089.11"; + static const char Version[] = "089.12"; static const char Author[] = "byuu"; static const char License[] = "GPLv3"; } @@ -15,7 +15,7 @@ namespace Emulator { #include #include #include -#include +#include #include #include #include diff --git a/bsnes/gb/cartridge/cartridge.cpp b/bsnes/gb/cartridge/cartridge.cpp index 062f975ee..991846c06 100755 --- a/bsnes/gb/cartridge/cartridge.cpp +++ b/bsnes/gb/cartridge/cartridge.cpp @@ -27,7 +27,7 @@ void Cartridge::load(System::Revision revision, const string &manifest) { XML::Document document(manifest); - auto &mapperid = document["cartridge"]["mapper"].data; + auto &mapperid = document["cartridge"]["board"]["type"].data; if(mapperid == "none" ) information.mapper = Mapper::MBC0; if(mapperid == "MBC1" ) information.mapper = Mapper::MBC1; if(mapperid == "MBC2" ) information.mapper = Mapper::MBC2; @@ -37,8 +37,8 @@ void Cartridge::load(System::Revision revision, const string &manifest) { if(mapperid == "HuC1" ) information.mapper = Mapper::HuC1; if(mapperid == "HuC3" ) information.mapper = Mapper::HuC3; - information.rtc = document["cartridge"]["rtc"].data == "true"; - information.rumble = document["cartridge"]["rumble"].data == "true"; + information.rtc = false; + information.rumble = false; auto &rom = document["cartridge"]["rom"]; auto &ram = document["cartridge"]["ram"]; diff --git a/bsnes/nall/any.hpp b/bsnes/nall/any.hpp index 168a9fd9c..7661a2a40 100755 --- a/bsnes/nall/any.hpp +++ b/bsnes/nall/any.hpp @@ -2,7 +2,7 @@ #define NALL_ANY_HPP #include -#include +#include namespace nall { struct any { diff --git a/bsnes/nall/directory.hpp b/bsnes/nall/directory.hpp index 5d832e431..b360f636a 100755 --- a/bsnes/nall/directory.hpp +++ b/bsnes/nall/directory.hpp @@ -17,7 +17,7 @@ namespace nall { struct directory { - static bool create(const string &pathname, unsigned permissions = 0755); + static bool create(const string &pathname, unsigned permissions = 0755); //recursive static bool remove(const string &pathname); static bool exists(const string &pathname); static lstring folders(const string &pathname, const string &pattern = "*"); @@ -27,7 +27,16 @@ struct directory { #if defined(PLATFORM_WINDOWS) inline bool directory::create(const string &pathname, unsigned permissions) { - return _wmkdir(utf16_t(pathname)) == 0; + string fullpath = pathname, path; + fullpath.transform("/", "\\"); + fullpath.rtrim<1>("\\"); + lstring pathpart = fullpath.split("\\"); + bool result = false; + for(auto &part : pathpart) { + path.append(part, "\\"); + result = _wmkdir(utf16_t(path)) == 0; + } + return result; } inline bool directory::remove(const string &pathname) { @@ -105,7 +114,14 @@ struct directory { } #else inline bool directory::create(const string &pathname, unsigned permissions) { - return mkdir(pathname, permissions) == 0; + string fullpath = pathname, path = "/"; + fullpath.trim<1>("/"); + lstring pathpart = fullpath.split("/"); + for(auto &part : pathpart) { + if(!directory::exists(path)) mkdir(path, permissions); + path.append(part, "/"); + } + return mkdir(path, permissions) == 0; } inline bool directory::remove(const string &pathname) { diff --git a/bsnes/nall/nes/cartridge.hpp b/bsnes/nall/emulation/famicom.hpp similarity index 83% rename from bsnes/nall/nes/cartridge.hpp rename to bsnes/nall/emulation/famicom.hpp index 49e78de1c..a625d4ded 100755 --- a/bsnes/nall/nes/cartridge.hpp +++ b/bsnes/nall/emulation/famicom.hpp @@ -1,13 +1,22 @@ -#ifndef NALL_NES_CARTRIDGE_HPP -#define NALL_NES_CARTRIDGE_HPP +#ifndef NALL_EMULATION_FAMICOM_HPP +#define NALL_EMULATION_FAMICOM_HPP #include +#include namespace nall { struct FamicomCartridge { string markup; inline FamicomCartridge(const uint8_t *data, unsigned size); + +//private: + unsigned mapper; + unsigned mirror; + unsigned prgrom; + unsigned prgram; + unsigned chrrom; + unsigned chrram; }; FamicomCartridge::FamicomCartridge(const uint8_t *data, unsigned size) { @@ -18,12 +27,12 @@ FamicomCartridge::FamicomCartridge(const uint8_t *data, unsigned size) { if(data[2] != 'S') return; if(data[3] != 26) return; - unsigned mapper = ((data[7] >> 4) << 4) | (data[6] >> 4); - unsigned mirror = ((data[6] & 0x08) >> 2) | (data[6] & 0x01); - unsigned prgrom = data[4] * 0x4000; - unsigned chrrom = data[5] * 0x2000; - unsigned prgram = 0u; - unsigned chrram = chrrom == 0u ? 8192u : 0u; + mapper = ((data[7] >> 4) << 4) | (data[6] >> 4); + mirror = ((data[6] & 0x08) >> 2) | (data[6] & 0x01); + prgrom = data[4] * 0x4000; + chrrom = data[5] * 0x2000; + prgram = 0u; + chrram = chrrom == 0u ? 8192u : 0u; markup.append("\n"); @@ -153,13 +162,13 @@ FamicomCartridge::FamicomCartridge(const uint8_t *data, unsigned size) { } markup.append(" \n"); - if(prgrom) markup.append(" \n"); - if(prgram) markup.append(" \n"); + if(prgrom) markup.append(" \n"); + if(prgram) markup.append(" \n"); markup.append(" \n"); markup.append(" \n"); - if(chrrom) markup.append(" \n"); - if(chrram) markup.append(" \n"); + if(chrrom) markup.append(" \n"); + if(chrram) markup.append(" \n"); markup.append(" \n"); markup.append("\n"); diff --git a/bsnes/nall/gba/cartridge.hpp b/bsnes/nall/emulation/game-boy-advance.hpp similarity index 77% rename from bsnes/nall/gba/cartridge.hpp rename to bsnes/nall/emulation/game-boy-advance.hpp index d6ed002f4..c70be7877 100755 --- a/bsnes/nall/gba/cartridge.hpp +++ b/bsnes/nall/emulation/game-boy-advance.hpp @@ -1,7 +1,8 @@ -#ifndef NALL_GBA_CARTRIDGE_HPP -#define NALL_GBA_CARTRIDGE_HPP +#ifndef NALL_EMULATION_GAME_BOY_ADVANCE_HPP +#define NALL_EMULATION_GAME_BOY_ADVANCE_HPP #include +#include #include namespace nall { @@ -46,14 +47,14 @@ GameBoyAdvanceCartridge::GameBoyAdvanceCartridge(const uint8_t *data, unsigned s markup = "\n"; markup.append("\n"); - markup.append(" \n"); + markup.append(" \n"); if(0); - else if(identifiers.beginswith("SRAM_V" )) markup.append(" \n"); - else if(identifiers.beginswith("SRAM_F_V" )) markup.append(" \n"); - else if(identifiers.beginswith("EEPROM_V" )) markup.append(" \n"); - else if(identifiers.beginswith("FLASH_V" )) markup.append(" \n"); - else if(identifiers.beginswith("FLASH512_V")) markup.append(" \n"); - else if(identifiers.beginswith("FLASH1M_V" )) markup.append(" \n"); + else if(identifiers.beginswith("SRAM_V" )) markup.append(" \n"); + else if(identifiers.beginswith("SRAM_F_V" )) markup.append(" \n"); + else if(identifiers.beginswith("EEPROM_V" )) markup.append(" \n"); + else if(identifiers.beginswith("FLASH_V" )) markup.append(" \n"); + else if(identifiers.beginswith("FLASH512_V")) markup.append(" \n"); + else if(identifiers.beginswith("FLASH1M_V" )) markup.append(" \n"); if(identifiers.empty() == false) markup.append(" \n"); markup.append("\n"); diff --git a/bsnes/nall/gb/cartridge.hpp b/bsnes/nall/emulation/game-boy.hpp similarity index 88% rename from bsnes/nall/gb/cartridge.hpp rename to bsnes/nall/emulation/game-boy.hpp index 326c88528..ef1f3da94 100755 --- a/bsnes/nall/gb/cartridge.hpp +++ b/bsnes/nall/emulation/game-boy.hpp @@ -1,5 +1,8 @@ -#ifndef NALL_GB_CARTRIDGE_HPP -#define NALL_GB_CARTRIDGE_HPP +#ifndef NALL_EMULATION_GAME_BOY_HPP +#define NALL_EMULATION_GAME_BOY_HPP + +#include +#include namespace nall { @@ -17,6 +20,9 @@ struct GameBoyCartridge { unsigned romsize; unsigned ramsize; + + bool cgb; + bool cgbonly; } info; }; @@ -47,6 +53,9 @@ GameBoyCartridge::GameBoyCartridge(uint8_t *romdata, unsigned romsize) { memcpy(romdata, header, 0x8000); } + info.cgb = (romdata[0x0143] & 0x80) == 0x80; + info.cgbonly = (romdata[0x0143] & 0xc0) == 0xc0; + switch(romdata[0x0147]) { case 0x00: info.mapper = "none"; break; case 0x01: info.mapper = "MBC1"; break; @@ -100,9 +109,10 @@ GameBoyCartridge::GameBoyCartridge(uint8_t *romdata, unsigned romsize) { if(info.mapper == "MBC2") info.ramsize = 512; //512 x 4-bit markup = "\n"; - markup.append("\n"); - markup.append(" \n"); - if(info.ramsize > 0) markup.append(" \n"); + markup.append("\n"); + markup.append(" \n"); + markup.append(" \n"); + if(info.ramsize > 0) markup.append(" \n"); markup.append("\n"); markup.transform("'", "\""); } diff --git a/bsnes/nall/snes/usart.hpp b/bsnes/nall/emulation/super-famicom-usart.hpp similarity index 96% rename from bsnes/nall/snes/usart.hpp rename to bsnes/nall/emulation/super-famicom-usart.hpp index 63edaad6b..60d8ebbdb 100755 --- a/bsnes/nall/snes/usart.hpp +++ b/bsnes/nall/emulation/super-famicom-usart.hpp @@ -1,5 +1,5 @@ -#ifndef NALL_SNES_USART_HPP -#define NALL_SNES_USART_HPP +#ifndef NALL_EMULATION_SUPER_FAMICOM_USART_HPP +#define NALL_EMULATION_SUPER_FAMICOM_USART_HPP #include #include diff --git a/bsnes/nall/snes/cartridge.hpp b/bsnes/nall/emulation/super-famicom.hpp similarity index 86% rename from bsnes/nall/snes/cartridge.hpp rename to bsnes/nall/emulation/super-famicom.hpp index 4059df92b..18e893304 100755 --- a/bsnes/nall/snes/cartridge.hpp +++ b/bsnes/nall/emulation/super-famicom.hpp @@ -1,5 +1,8 @@ -#ifndef NALL_SNES_CARTRIDGE_HPP -#define NALL_SNES_CARTRIDGE_HPP +#ifndef NALL_EMULATION_SUPER_FAMICOM_HPP +#define NALL_EMULATION_SUPER_FAMICOM_HPP + +#include +#include namespace nall { @@ -11,8 +14,6 @@ struct SuperFamicomCartridge { inline void read_header(const uint8_t *data, unsigned size); inline unsigned find_header(const uint8_t *data, unsigned size); inline unsigned score_header(const uint8_t *data, unsigned size, unsigned addr); - inline unsigned gameboy_ram_size(const uint8_t *data, unsigned size); - inline bool gameboy_has_rtc(const uint8_t *data, unsigned size); enum HeaderField { CartName = 0x00, @@ -121,11 +122,7 @@ SuperFamicomCartridge::SuperFamicomCartridge(const uint8_t *data, unsigned size) } if(type == TypeGameBoy) { - markup.append(" 0) { - markup.append(" \n"); - } - markup.append("\n"); + markup.append("\n"); return; } @@ -133,7 +130,7 @@ SuperFamicomCartridge::SuperFamicomCartridge(const uint8_t *data, unsigned size) markup.append("\n"); if(type == TypeSuperGameBoy1Bios || type == TypeSuperGameBoy2Bios) markup.append( - " \n" + " \n" " \n" " \n" " \n" @@ -144,6 +141,7 @@ SuperFamicomCartridge::SuperFamicomCartridge(const uint8_t *data, unsigned size) ); else if(has_cx4) markup.append( + " \n" " \n" " \n" " \n" @@ -158,6 +156,8 @@ SuperFamicomCartridge::SuperFamicomCartridge(const uint8_t *data, unsigned size) else if(has_spc7110) { markup.append( + " \n" + " \n" " \n" " \n" " \n" @@ -174,7 +174,7 @@ SuperFamicomCartridge::SuperFamicomCartridge(const uint8_t *data, unsigned size) " \n" " \n" " \n" - " \n" + " \n" " \n" " \n" " \n" @@ -182,7 +182,7 @@ SuperFamicomCartridge::SuperFamicomCartridge(const uint8_t *data, unsigned size) " \n" ); if(has_spc7110rtc) markup.append( - " \n" + " \n" " \n" " \n" " \n" @@ -191,13 +191,13 @@ SuperFamicomCartridge::SuperFamicomCartridge(const uint8_t *data, unsigned size) else if(mapper == LoROM) { markup.append( - " \n" + " \n" " \n" " \n" " \n" ); if(ram_size > 0) markup.append( - " \n" + " \n" " \n" " \n" " \n" @@ -208,7 +208,7 @@ SuperFamicomCartridge::SuperFamicomCartridge(const uint8_t *data, unsigned size) else if(mapper == HiROM) { markup.append( - " \n" + " \n" " \n" " \n" " \n" @@ -216,7 +216,7 @@ SuperFamicomCartridge::SuperFamicomCartridge(const uint8_t *data, unsigned size) " \n" ); if(ram_size > 0) markup.append( - " \n" + " \n" " \n" " \n" " \n" @@ -226,14 +226,14 @@ SuperFamicomCartridge::SuperFamicomCartridge(const uint8_t *data, unsigned size) else if(mapper == ExLoROM) { markup.append( - " \n" + " \n" " \n" " \n" " \n" " \n" ); if(ram_size > 0) markup.append( - " \n" + " \n" " \n" " \n" " \n" @@ -243,7 +243,7 @@ SuperFamicomCartridge::SuperFamicomCartridge(const uint8_t *data, unsigned size) else if(mapper == ExHiROM) { markup.append( - " \n" + " \n" " \n" " \n" " \n" @@ -251,7 +251,7 @@ SuperFamicomCartridge::SuperFamicomCartridge(const uint8_t *data, unsigned size) " \n" ); if(ram_size > 0) markup.append( - " \n" + " \n" " \n" " \n" " \n" @@ -259,62 +259,72 @@ SuperFamicomCartridge::SuperFamicomCartridge(const uint8_t *data, unsigned size) ); } - else if(mapper == SuperFXROM) markup.append( - " \n" - " \n" - " \n" - " \n" - " \n" - " \n" - " \n" - " \n" - " \n" - " \n" - " \n" - " \n" - " \n" - " \n" - " \n" - " \n" - " \n" - " \n" - ); + else if(mapper == SuperFXROM) { + markup.append(" \n"); + if(ram_size > 0) + markup.append(" \n"); + markup.append( + " \n" + " \n" + " \n" + " \n" + " \n" + " \n" + " \n" + " \n" + " \n" + " \n" + " \n" + " \n" + " \n" + " \n" + " \n" + " \n" + " \n" + " \n" + ); + } - else if(mapper == SA1ROM) markup.append( - " \n" - " \n" - " \n" - " \n" - " \n" - " \n" - " \n" - " \n" - " \n" - " \n" - " \n" - " \n" - " \n" - " \n" - " \n" - " \n" - " \n" - " \n" - " \n" - " \n" - " \n" - " \n" - " \n" - " \n" - ); + else if(mapper == SA1ROM) { + markup.append(" \n"); + if(ram_size > 0) + markup.append(" \n"); + markup.append( + " \n" + " \n" + " \n" + " \n" + " \n" + " \n" + " \n" + " \n" + " \n" + " \n" + " \n" + " \n" + " \n" + " \n" + " \n" + " \n" + " \n" + " \n" + " \n" + " \n" + " \n" + " \n" + " \n" + " \n" + ); + } else if(mapper == BSCLoROM) markup.append( - " \n" + " \n" " \n" " \n" " \n" " \n" " \n" - " \n" + " \n" " \n" " \n" " \n" @@ -326,13 +336,13 @@ SuperFamicomCartridge::SuperFamicomCartridge(const uint8_t *data, unsigned size) ); else if(mapper == BSCHiROM) markup.append( - " \n" + " \n" " \n" " \n" " \n" " \n" " \n" - " \n" + " \n" " \n" " \n" " \n" @@ -347,6 +357,9 @@ SuperFamicomCartridge::SuperFamicomCartridge(const uint8_t *data, unsigned size) ); else if(mapper == BSXROM) markup.append( + " \n" + " \n" + " \n" " \n" " \n" " \n" @@ -363,7 +376,7 @@ SuperFamicomCartridge::SuperFamicomCartridge(const uint8_t *data, unsigned size) ); else if(mapper == STROM) markup.append( - " \n" + " \n" " \n" " \n" " \n" @@ -373,7 +386,7 @@ SuperFamicomCartridge::SuperFamicomCartridge(const uint8_t *data, unsigned size) " \n" " \n" " \n" - " \n" + " \n" " \n" " \n" " \n" @@ -383,7 +396,7 @@ SuperFamicomCartridge::SuperFamicomCartridge(const uint8_t *data, unsigned size) " \n" " \n" " \n" - " \n" + " \n" " \n" " \n" " \n" @@ -392,7 +405,7 @@ SuperFamicomCartridge::SuperFamicomCartridge(const uint8_t *data, unsigned size) ); if(has_srtc) markup.append( - " \n" + " \n" " \n" " \n" " \n" @@ -534,6 +547,7 @@ SuperFamicomCartridge::SuperFamicomCartridge(const uint8_t *data, unsigned size) ); markup.append("\n"); + markup.transform("'", "\""); } void SuperFamicomCartridge::read_header(const uint8_t *data, unsigned size) { @@ -860,25 +874,6 @@ unsigned SuperFamicomCartridge::score_header(const uint8_t *data, unsigned size, return score; } -unsigned SuperFamicomCartridge::gameboy_ram_size(const uint8_t *data, unsigned size) { - if(size < 512) return 0; - switch(data[0x0149]) { - case 0x00: return 0 * 1024; - case 0x01: return 8 * 1024; - case 0x02: return 8 * 1024; - case 0x03: return 32 * 1024; - case 0x04: return 128 * 1024; - case 0x05: return 128 * 1024; - default: return 128 * 1024; - } -} - -bool SuperFamicomCartridge::gameboy_has_rtc(const uint8_t *data, unsigned size) { - if(size < 512) return false; - if(data[0x0147] == 0x0f ||data[0x0147] == 0x10) return true; - return false; -} - } #endif diff --git a/bsnes/nall/http.hpp b/bsnes/nall/http.hpp index 55190e820..48aeb0978 100755 --- a/bsnes/nall/http.hpp +++ b/bsnes/nall/http.hpp @@ -7,9 +7,9 @@ #include #include #else - #include #include #include + #include #endif #include diff --git a/bsnes/nall/image.hpp b/bsnes/nall/image.hpp index 986aabc31..552a3e304 100755 --- a/bsnes/nall/image.hpp +++ b/bsnes/nall/image.hpp @@ -36,6 +36,8 @@ struct image { inline image(const image &source); inline image(image &&source); inline image(bool endian, unsigned depth, uint64_t alphaMask, uint64_t redMask, uint64_t greenMask, uint64_t blueMask); + inline image(const string &filename); + inline image(const uint8_t *data, unsigned size); inline image(); inline ~image(); @@ -43,6 +45,7 @@ struct image { inline void write(uint8_t *data, uint64_t value) const; inline void free(); + inline bool empty() const; inline void allocate(unsigned width, unsigned height); inline void clear(uint64_t color); inline bool load(const string &filename); @@ -146,6 +149,38 @@ image::image(bool endian, unsigned depth, uint64_t alphaMask, uint64_t redMask, blue.depth = bitDepth(blue.mask), blue.shift = bitShift(blue.mask); } +image::image(const string &filename) : data(nullptr) { + width = 0, height = 0, pitch = 0; + + this->endian = 0; + this->depth = 32; + this->stride = 4; + + alpha.mask = 255u << 24, red.mask = 255u << 16, green.mask = 255u << 8, blue.mask = 255u << 0; + alpha.depth = bitDepth(alpha.mask), alpha.shift = bitShift(alpha.mask); + red.depth = bitDepth(red.mask), red.shift = bitShift(red.mask); + green.depth = bitDepth(green.mask), green.shift = bitShift(green.mask); + blue.depth = bitDepth(blue.mask), blue.shift = bitShift(blue.mask); + + load(filename); +} + +image::image(const uint8_t *data, unsigned size) : data(nullptr) { + width = 0, height = 0, pitch = 0; + + this->endian = 0; + this->depth = 32; + this->stride = 4; + + alpha.mask = 255u << 24, red.mask = 255u << 16, green.mask = 255u << 8, blue.mask = 255u << 0; + alpha.depth = bitDepth(alpha.mask), alpha.shift = bitShift(alpha.mask); + red.depth = bitDepth(red.mask), red.shift = bitShift(red.mask); + green.depth = bitDepth(green.mask), green.shift = bitShift(green.mask); + blue.depth = bitDepth(blue.mask), blue.shift = bitShift(blue.mask); + + loadPNG(data, size); +} + image::image() : data(nullptr) { width = 0, height = 0, pitch = 0; @@ -187,6 +222,12 @@ void image::free() { data = nullptr; } +bool image::empty() const { + if(data == nullptr) return true; + if(width == 0 || height == 0) return true; + return false; +} + void image::allocate(unsigned width, unsigned height) { if(data != nullptr && this->width == width && this->height == height) return; free(); diff --git a/bsnes/nall/invoke.hpp b/bsnes/nall/invoke.hpp new file mode 100755 index 000000000..9dfb7d0bc --- /dev/null +++ b/bsnes/nall/invoke.hpp @@ -0,0 +1,52 @@ +#ifndef NALL_INVOKE_HPP +#define NALL_INVOKE_HPP + +//void invoke(const string &name, const string& args...); +//if a program is specified, it is executed with the arguments provided +//if a file is specified, the file is opened using the program associated with said file type +//if a folder is specified, the folder is opened using the associated file explorer +//if a URL is specified, the default web browser is opened and pointed at the URL requested +//path environment variable is always consulted +//execution is asynchronous (non-blocking); use system() for synchronous execution + +#include +#ifdef _WIN32 + #include +#endif + +namespace nall { + +#ifdef _WIN32 + +template +inline void invoke(const string &name, Args&&... args) { + lstring argl(std::forward(args)...); + for(auto &arg : argl) if(arg.position(" ")) arg = {"\"", arg, "\""}; + string arguments = argl.concatenate(" "); + ShellExecuteW(NULL, NULL, utf16_t(name), utf16_t(arguments), NULL, SW_SHOWNORMAL); +} + +#else + +template +inline void invoke(const string &name, Args&&... args) { + pid_t pid = fork(); + if(pid == 0) { + const char *argv[1 + sizeof...(args) + 1], **argp = argv; + lstring argl(std::forward(args)...); + *argp++ = (const char*)name; + for(auto &arg : argl) *argp++ = (const char*)arg; + *argp++ = nullptr; + + if(execvp(name, (char* const*)argv) < 0) { + execlp("xdg-open", "xdg-open", (const char*)name, nullptr); + } + exit(0); + } +} + +#endif + +} + +#endif diff --git a/bsnes/nall/platform.hpp b/bsnes/nall/platform.hpp index e1a8f5d62..a45a6723e 100755 --- a/bsnes/nall/platform.hpp +++ b/bsnes/nall/platform.hpp @@ -59,9 +59,9 @@ #endif #if defined(_WIN32) - #define getcwd _getcwd - #define putenv _putenv - #define vsnprintf _vsnprintf + #define getcwd _getcwd + #define putenv _putenv + #define vsnprintf _vsnprintf inline void usleep(unsigned milliseconds) { Sleep(milliseconds / 1000); } #endif @@ -83,57 +83,4 @@ #define alwaysinline inline #endif -//========================= -//file system functionality -//========================= - -#if defined(_WIN32) - inline char* realpath(const char *filename, char *resolvedname) { - wchar_t fn[_MAX_PATH] = L""; - _wfullpath(fn, nall::utf16_t(filename), _MAX_PATH); - strcpy(resolvedname, nall::utf8_t(fn)); - for(unsigned n = 0; resolvedname[n]; n++) if(resolvedname[n] == '\\') resolvedname[n] = '/'; - return resolvedname; - } - - inline char* userpath(char *path) { - wchar_t fp[_MAX_PATH] = L""; - SHGetFolderPathW(0, CSIDL_APPDATA | CSIDL_FLAG_CREATE, 0, 0, fp); - strcpy(path, nall::utf8_t(fp)); - for(unsigned n = 0; path[n]; n++) if(path[n] == '\\') path[n] = '/'; - unsigned length = strlen(path); - if(path[length] != '/') strcpy(path + length, "/"); - return path; - } - - inline char* getcwd(char *path) { - wchar_t fp[_MAX_PATH] = L""; - _wgetcwd(fp, _MAX_PATH); - strcpy(path, nall::utf8_t(fp)); - for(unsigned n = 0; path[n]; n++) if(path[n] == '\\') path[n] = '/'; - unsigned length = strlen(path); - if(path[length] != '/') strcpy(path + length, "/"); - return path; - } -#else - //realpath() already exists - - inline char* userpath(char *path) { - *path = 0; - struct passwd *userinfo = getpwuid(getuid()); - if(userinfo) strcpy(path, userinfo->pw_dir); - unsigned length = strlen(path); - if(path[length] != '/') strcpy(path + length, "/"); - return path; - } - - inline char *getcwd(char *path) { - auto unused = getcwd(path, PATH_MAX); - unsigned length = strlen(path); - if(path[length] != '/') strcpy(path + length, "/"); - return path; - } #endif - -#endif - diff --git a/bsnes/nall/priorityqueue.hpp b/bsnes/nall/priority-queue.hpp similarity index 97% rename from bsnes/nall/priorityqueue.hpp rename to bsnes/nall/priority-queue.hpp index 443eac21b..1aedc6f18 100755 --- a/bsnes/nall/priorityqueue.hpp +++ b/bsnes/nall/priority-queue.hpp @@ -1,5 +1,5 @@ -#ifndef NALL_PRIORITYQUEUE_HPP -#define NALL_PRIORITYQUEUE_HPP +#ifndef NALL_PRIORITY_QUEUE_HPP +#define NALL_PRIORITY_QUEUE_HPP #include #include diff --git a/bsnes/nall/public_cast.hpp b/bsnes/nall/public-cast.hpp similarity index 100% rename from bsnes/nall/public_cast.hpp rename to bsnes/nall/public-cast.hpp diff --git a/bsnes/nall/set.hpp b/bsnes/nall/set.hpp index 1666c8cd9..c6d3d06e4 100755 --- a/bsnes/nall/set.hpp +++ b/bsnes/nall/set.hpp @@ -14,7 +14,7 @@ #include #include #include -#include +#include #include namespace nall { diff --git a/bsnes/nall/snes/cpu.hpp b/bsnes/nall/snes/cpu.hpp deleted file mode 100755 index 28f5ddb58..000000000 --- a/bsnes/nall/snes/cpu.hpp +++ /dev/null @@ -1,458 +0,0 @@ -#ifndef NALL_SNES_CPU_HPP -#define NALL_SNES_CPU_HPP - -namespace nall { - -struct SNESCPU { - enum : unsigned { - Implied, // - Constant, //#$00 - AccumConstant, //#$00 - IndexConstant, //#$00 - Direct, //$00 - DirectX, //$00,x - DirectY, //$00,y - IDirect, //($00) - IDirectX, //($00,x) - IDirectY, //($00),y - ILDirect, //[$00] - ILDirectY, //[$00],y - Address, //$0000 - AddressX, //$0000,x - AddressY, //$0000,y - IAddressX, //($0000,x) - ILAddress, //[$0000] - PAddress, //PBR:$0000 - PIAddress, //PBR:($0000) - Long, //$000000 - LongX, //$000000,x - Stack, //$00,s - IStackY, //($00,s),y - BlockMove, //$00,$00 - RelativeShort, //+/- $00 - RelativeLong, //+/- $0000 - }; - - struct OpcodeInfo { - char name[4]; - unsigned mode; - }; - - static const OpcodeInfo opcodeInfo[256]; - - static unsigned getOpcodeLength(bool accum, bool index, uint8_t opcode); - static string disassemble(unsigned pc, bool accum, bool index, uint8_t opcode, uint8_t pl, uint8_t ph, uint8_t pb); -}; - -const SNESCPU::OpcodeInfo SNESCPU::opcodeInfo[256] = { - //0x00 - 0x0f - { "brk", Constant }, - { "ora", IDirectX }, - { "cop", Constant }, - { "ora", Stack }, - - { "tsb", Direct }, - { "ora", Direct }, - { "asl", Direct }, - { "ora", ILDirect }, - - { "php", Implied }, - { "ora", AccumConstant }, - { "asl", Implied }, - { "phd", Implied }, - - { "tsb", Address }, - { "ora", Address }, - { "asl", Address }, - { "ora", Long }, - - //0x10 - 0x1f - { "bpl", RelativeShort }, - { "ora", IDirectY }, - { "ora", IDirect }, - { "ora", IStackY }, - - { "trb", Direct }, - { "ora", DirectX }, - { "asl", DirectX }, - { "ora", ILDirectY }, - - { "clc", Implied }, - { "ora", AddressY }, - { "inc", Implied }, - { "tcs", Implied }, - - { "trb", Address }, - { "ora", AddressX }, - { "asl", AddressX }, - { "ora", LongX }, - - //0x20 - 0x2f - { "jsr", Address }, - { "and", IDirectX }, - { "jsl", Long }, - { "and", Stack }, - - { "bit", Direct }, - { "and", Direct }, - { "rol", Direct }, - { "and", ILDirect }, - - { "plp", Implied }, - { "and", AccumConstant }, - { "rol", Implied }, - { "pld", Implied }, - - { "bit", Address }, - { "and", Address }, - { "rol", Address }, - { "and", Long }, - - //0x30 - 0x3f - { "bmi", RelativeShort }, - { "and", IDirectY }, - { "and", IDirect }, - { "and", IStackY }, - - { "bit", DirectX }, - { "and", DirectX }, - { "rol", DirectX }, - { "and", ILDirectY }, - - { "sec", Implied }, - { "and", AddressY }, - { "dec", Implied }, - { "tsc", Implied }, - - { "bit", AddressX }, - { "and", AddressX }, - { "rol", AddressX }, - { "and", LongX }, - - //0x40 - 0x4f - { "rti", Implied }, - { "eor", IDirectX }, - { "wdm", Constant }, - { "eor", Stack }, - - { "mvp", BlockMove }, - { "eor", Direct }, - { "lsr", Direct }, - { "eor", ILDirect }, - - { "pha", Implied }, - { "eor", AccumConstant }, - { "lsr", Implied }, - { "phk", Implied }, - - { "jmp", PAddress }, - { "eor", Address }, - { "lsr", Address }, - { "eor", Long }, - - //0x50 - 0x5f - { "bvc", RelativeShort }, - { "eor", IDirectY }, - { "eor", IDirect }, - { "eor", IStackY }, - - { "mvn", BlockMove }, - { "eor", DirectX }, - { "lsr", DirectX }, - { "eor", ILDirectY }, - - { "cli", Implied }, - { "eor", AddressY }, - { "phy", Implied }, - { "tcd", Implied }, - - { "jml", Long }, - { "eor", AddressX }, - { "lsr", AddressX }, - { "eor", LongX }, - - //0x60 - 0x6f - { "rts", Implied }, - { "adc", IDirectX }, - { "per", Address }, - { "adc", Stack }, - - { "stz", Direct }, - { "adc", Direct }, - { "ror", Direct }, - { "adc", ILDirect }, - - { "pla", Implied }, - { "adc", AccumConstant }, - { "ror", Implied }, - { "rtl", Implied }, - - { "jmp", PIAddress }, - { "adc", Address }, - { "ror", Address }, - { "adc", Long }, - - //0x70 - 0x7f - { "bvs", RelativeShort }, - { "adc", IDirectY }, - { "adc", IDirect }, - { "adc", IStackY }, - - { "stz", DirectX }, - { "adc", DirectX }, - { "ror", DirectX }, - { "adc", ILDirectY }, - - { "sei", Implied }, - { "adc", AddressY }, - { "ply", Implied }, - { "tdc", Implied }, - - { "jmp", IAddressX }, - { "adc", AddressX }, - { "ror", AddressX }, - { "adc", LongX }, - - //0x80 - 0x8f - { "bra", RelativeShort }, - { "sta", IDirectX }, - { "brl", RelativeLong }, - { "sta", Stack }, - - { "sty", Direct }, - { "sta", Direct }, - { "stx", Direct }, - { "sta", ILDirect }, - - { "dey", Implied }, - { "bit", AccumConstant }, - { "txa", Implied }, - { "phb", Implied }, - - { "sty", Address }, - { "sta", Address }, - { "stx", Address }, - { "sta", Long }, - - //0x90 - 0x9f - { "bcc", RelativeShort }, - { "sta", IDirectY }, - { "sta", IDirect }, - { "sta", IStackY }, - - { "sty", DirectX }, - { "sta", DirectX }, - { "stx", DirectY }, - { "sta", ILDirectY }, - - { "tya", Implied }, - { "sta", AddressY }, - { "txs", Implied }, - { "txy", Implied }, - - { "stz", Address }, - { "sta", AddressX }, - { "stz", AddressX }, - { "sta", LongX }, - - //0xa0 - 0xaf - { "ldy", IndexConstant }, - { "lda", IDirectX }, - { "ldx", IndexConstant }, - { "lda", Stack }, - - { "ldy", Direct }, - { "lda", Direct }, - { "ldx", Direct }, - { "lda", ILDirect }, - - { "tay", Implied }, - { "lda", AccumConstant }, - { "tax", Implied }, - { "plb", Implied }, - - { "ldy", Address }, - { "lda", Address }, - { "ldx", Address }, - { "lda", Long }, - - //0xb0 - 0xbf - { "bcs", RelativeShort }, - { "lda", IDirectY }, - { "lda", IDirect }, - { "lda", IStackY }, - - { "ldy", DirectX }, - { "lda", DirectX }, - { "ldx", DirectY }, - { "lda", ILDirectY }, - - { "clv", Implied }, - { "lda", AddressY }, - { "tsx", Implied }, - { "tyx", Implied }, - - { "ldy", AddressX }, - { "lda", AddressX }, - { "ldx", AddressY }, - { "lda", LongX }, - - //0xc0 - 0xcf - { "cpy", IndexConstant }, - { "cmp", IDirectX }, - { "rep", Constant }, - { "cmp", Stack }, - - { "cpy", Direct }, - { "cmp", Direct }, - { "dec", Direct }, - { "cmp", ILDirect }, - - { "iny", Implied }, - { "cmp", AccumConstant }, - { "dex", Implied }, - { "wai", Implied }, - - { "cpy", Address }, - { "cmp", Address }, - { "dec", Address }, - { "cmp", Long }, - - //0xd0 - 0xdf - { "bne", RelativeShort }, - { "cmp", IDirectY }, - { "cmp", IDirect }, - { "cmp", IStackY }, - - { "pei", IDirect }, - { "cmp", DirectX }, - { "dec", DirectX }, - { "cmp", ILDirectY }, - - { "cld", Implied }, - { "cmp", AddressY }, - { "phx", Implied }, - { "stp", Implied }, - - { "jmp", ILAddress }, - { "cmp", AddressX }, - { "dec", AddressX }, - { "cmp", LongX }, - - //0xe0 - 0xef - { "cpx", IndexConstant }, - { "sbc", IDirectX }, - { "sep", Constant }, - { "sbc", Stack }, - - { "cpx", Direct }, - { "sbc", Direct }, - { "inc", Direct }, - { "sbc", ILDirect }, - - { "inx", Implied }, - { "sbc", AccumConstant }, - { "nop", Implied }, - { "xba", Implied }, - - { "cpx", Address }, - { "sbc", Address }, - { "inc", Address }, - { "sbc", Long }, - - //0xf0 - 0xff - { "beq", RelativeShort }, - { "sbc", IDirectY }, - { "sbc", IDirect }, - { "sbc", IStackY }, - - { "pea", Address }, - { "sbc", DirectX }, - { "inc", DirectX }, - { "sbc", ILDirectY }, - - { "sed", Implied }, - { "sbc", AddressY }, - { "plx", Implied }, - { "xce", Implied }, - - { "jsr", IAddressX }, - { "sbc", AddressX }, - { "inc", AddressX }, - { "sbc", LongX }, -}; - -inline unsigned SNESCPU::getOpcodeLength(bool accum, bool index, uint8_t opcode) { - switch(opcodeInfo[opcode].mode) { default: - case Implied: return 1; - case Constant: return 2; - case AccumConstant: return 3 - accum; - case IndexConstant: return 3 - index; - case Direct: return 2; - case DirectX: return 2; - case DirectY: return 2; - case IDirect: return 2; - case IDirectX: return 2; - case IDirectY: return 2; - case ILDirect: return 2; - case ILDirectY: return 2; - case Address: return 3; - case AddressX: return 3; - case AddressY: return 3; - case IAddressX: return 3; - case ILAddress: return 3; - case PAddress: return 3; - case PIAddress: return 3; - case Long: return 4; - case LongX: return 4; - case Stack: return 2; - case IStackY: return 2; - case BlockMove: return 3; - case RelativeShort: return 2; - case RelativeLong: return 3; - } -} - -inline string SNESCPU::disassemble(unsigned pc, bool accum, bool index, uint8_t opcode, uint8_t pl, uint8_t ph, uint8_t pb) { - string name = opcodeInfo[opcode].name; - unsigned mode = opcodeInfo[opcode].mode; - - if(mode == Implied) return name; - if(mode == Constant) return { name, " #$", hex<2>(pl) }; - if(mode == AccumConstant) return { name, " #$", accum ? "" : hex<2>(ph), hex<2>(pl) }; - if(mode == IndexConstant) return { name, " #$", index ? "" : hex<2>(ph), hex<2>(pl) }; - if(mode == Direct) return { name, " $", hex<2>(pl) }; - if(mode == DirectX) return { name, " $", hex<2>(pl), ",x" }; - if(mode == DirectY) return { name, " $", hex<2>(pl), ",y" }; - if(mode == IDirect) return { name, " ($", hex<2>(pl), ")" }; - if(mode == IDirectX) return { name, " ($", hex<2>(pl), ",x)" }; - if(mode == IDirectY) return { name, " ($", hex<2>(pl), "),y" }; - if(mode == ILDirect) return { name, " [$", hex<2>(pl), "]" }; - if(mode == ILDirectY) return { name, " [$", hex<2>(pl), "],y" }; - if(mode == Address) return { name, " $", hex<2>(ph), hex<2>(pl) }; - if(mode == AddressX) return { name, " $", hex<2>(ph), hex<2>(pl), ",x" }; - if(mode == AddressY) return { name, " $", hex<2>(ph), hex<2>(pl), ",y" }; - if(mode == IAddressX) return { name, " ($", hex<2>(ph), hex<2>(pl), ",x)" }; - if(mode == ILAddress) return { name, " [$", hex<2>(ph), hex<2>(pl), "]" }; - if(mode == PAddress) return { name, " $", hex<2>(ph), hex<2>(pl) }; - if(mode == PIAddress) return { name, " ($", hex<2>(ph), hex<2>(pl), ")" }; - if(mode == Long) return { name, " $", hex<2>(pb), hex<2>(ph), hex<2>(pl) }; - if(mode == LongX) return { name, " $", hex<2>(pb), hex<2>(ph), hex<2>(pl), ",x" }; - if(mode == Stack) return { name, " $", hex<2>(pl), ",s" }; - if(mode == IStackY) return { name, " ($", hex<2>(pl), ",s),y" }; - if(mode == BlockMove) return { name, " $", hex<2>(ph), ",$", hex<2>(pl) }; - if(mode == RelativeShort) { - unsigned addr = (pc + 2) + (int8_t)(pl << 0); - return { name, " $", hex<4>(addr) }; - } - if(mode == RelativeLong) { - unsigned addr = (pc + 3) + (int16_t)((ph << 8) + (pl << 0)); - return { name, " $", hex<4>(addr) }; - } - - return ""; -} - -} - -#endif diff --git a/bsnes/nall/snes/smp.hpp b/bsnes/nall/snes/smp.hpp deleted file mode 100755 index 7a1ac47b6..000000000 --- a/bsnes/nall/snes/smp.hpp +++ /dev/null @@ -1,639 +0,0 @@ -#ifndef NALL_SNES_SMP_HPP -#define NALL_SNES_SMP_HPP - -namespace nall { - -struct SNESSMP { - enum : unsigned { - Implied, // - TVector, //0 - Direct, //$00 - DirectRelative, //$00,+/-$00 - ADirect, //a,$00 - AAbsolute, //a,$0000 - AIX, //a,(x) - AIDirectX, //a,($00+x) - AConstant, //a,#$00 - DirectDirect, //$00,$00 - CAbsoluteBit, //c,$0000:0 - Absolute, //$0000 - P, //p - AbsoluteA, //$0000,a - Relative, //+/-$00 - ADirectX, //a,$00+x - AAbsoluteX, //a,$0000+x - AAbsoluteY, //a,$0000+y - AIDirectY, //a,($00)+y - DirectConstant, //$00,#$00 - IXIY, //(x),(y) - DirectX, //$00+x - A, //a - X, //x - XAbsolute, //x,$0000 - IAbsoluteX, //($0000+x) - CNAbsoluteBit, //c,!$0000:0 - XDirect, //x,$00 - PVector, //$ff00 - YaDirect, //ya,$00 - XA, //x,a - YAbsolute, //y,$0000 - Y, //y - AX, //a,x - YDirect, //y,$00 - YConstant, //y,#$00 - XSp, //x,sp - YaX, //ya,x - IXPA, //(x)+,a - SpX, //sp,x - AIXP, //a,(x)+ - DirectA, //$00,a - IXA, //(x),a - IDirectXA, //($00+x),a - XConstant, //x,#$00 - AbsoluteX, //$0000,x - AbsoluteBitC, //$0000:0,c - DirectY, //$00,y - AbsoluteY, //$0000,y - Ya, //ya - DirectXA, //$00+x,a - AbsoluteXA, //$0000+x,a - AbsoluteYA, //$0000+y,a - IDirectYA, //($00)+y,a - DirectYX, //$00+y,x - DirectYa, //$00,ya - DirectXY, //$00+x,y - AY, //a,y - DirectXRelative, //$00+x,+/-$00 - XDirectY, //x,$00+y - YDirectX, //y,$00+x - YA, //y,a - YRelative, //y,+/-$00 - }; - - struct OpcodeInfo { - char name[6]; - unsigned mode; - }; - - static const OpcodeInfo opcodeInfo[256]; - - static unsigned getOpcodeLength(uint8_t opcode); - static string disassemble(uint16_t pc, uint8_t opcode, uint8_t pl, uint8_t ph); - static string disassemble(uint16_t pc, bool p, uint8_t opcode, uint8_t pl, uint8_t ph); -}; - -const SNESSMP::OpcodeInfo SNESSMP::opcodeInfo[256] = { - //0x00 - 0x0f - { "nop ", Implied }, - { "tcall", TVector }, - { "set0 ", Direct }, - { "bbs0 ", DirectRelative }, - - { "or ", ADirect }, - { "or ", AAbsolute }, - { "or ", AIX }, - { "or ", AIDirectX }, - - { "or ", AConstant }, - { "or ", DirectDirect }, - { "or1 ", CAbsoluteBit }, - { "asl ", Direct }, - - { "asl ", Absolute }, - { "push ", P }, - { "tset ", AbsoluteA }, - { "brk ", Implied }, - - //0x10 - 0x1f - { "bpl ", Relative }, - { "tcall", TVector }, - { "clr0 ", Direct }, - { "bbc0 ", DirectRelative }, - - { "or ", ADirectX }, - { "or ", AAbsoluteX }, - { "or ", AAbsoluteY }, - { "or ", AIDirectY }, - - { "or ", DirectConstant }, - { "or ", IXIY }, - { "decw ", Direct }, - { "asl ", DirectX }, - - { "asl ", A }, - { "dec ", X }, - { "cmp ", XAbsolute }, - { "jmp ", IAbsoluteX }, - - //0x20 - 0x2f - { "clrp ", Implied }, - { "tcall", TVector }, - { "set1 ", Direct }, - { "bbs1 ", DirectRelative }, - - { "and ", ADirect }, - { "and ", AAbsolute }, - { "and ", AIX }, - { "and ", AIDirectX }, - - { "and ", AConstant }, - { "and ", DirectDirect }, - { "or1 ", CNAbsoluteBit }, - { "rol ", Direct }, - - { "rol ", Absolute }, - { "push ", A }, - { "cbne ", DirectRelative }, - { "bra ", Relative }, - - //0x30 - 0x3f - { "bmi ", Relative }, - { "tcall", TVector }, - { "clr1 ", Direct }, - { "bbc1 ", DirectRelative }, - - { "and ", ADirectX }, - { "and ", AAbsoluteX }, - { "and ", AAbsoluteY }, - { "and ", AIDirectY }, - - { "and ", DirectConstant }, - { "and ", IXIY }, - { "incw ", Direct }, - { "rol ", DirectX }, - - { "rol ", A }, - { "inc ", X }, - { "cmp ", XDirect }, - { "call ", Absolute }, - - //0x40 - 0x4f - { "setp ", Implied }, - { "tcall", TVector }, - { "set2 ", Direct }, - { "bbs2 ", DirectRelative }, - - { "eor ", ADirect }, - { "eor ", AAbsolute }, - { "eor ", AIX }, - { "eor ", AIDirectX }, - - { "eor ", AConstant }, - { "eor ", DirectDirect }, - { "and1 ", CAbsoluteBit }, - { "lsr ", Direct }, - - { "lsr ", Absolute }, - { "push ", X }, - { "tclr ", AbsoluteA }, - { "pcall", PVector }, - - //0x50 - 0x5f - { "bvc ", Relative }, - { "tcall", TVector }, - { "clr2 ", Direct }, - { "bbc2 ", DirectRelative }, - - { "eor ", ADirectX }, - { "eor ", AAbsoluteX }, - { "eor ", AAbsoluteY }, - { "eor ", AIDirectY }, - - { "eor ", DirectConstant }, - { "eor ", IXIY }, - { "cmpw ", YaDirect }, - { "lsr ", DirectX }, - - { "lsr ", A }, - { "mov ", XA }, - { "cmp ", YAbsolute }, - { "jmp ", Absolute }, - - //0x60 - 0x6f - { "clrc ", Implied }, - { "tcall", TVector }, - { "set3 ", Direct }, - { "bbs3 ", DirectRelative }, - - { "cmp ", ADirect }, - { "cmp ", AAbsolute }, - { "cmp ", AIX }, - { "cmp ", AIDirectX }, - - { "cmp ", AConstant }, - { "cmp ", DirectDirect }, - { "and1 ", CNAbsoluteBit }, - { "ror ", Direct }, - - { "ror ", Absolute }, - { "push ", Y }, - { "dbnz ", DirectRelative }, - { "ret ", Implied }, - - //0x70 - 0x7f - { "bvs ", Relative }, - { "tcall", TVector }, - { "clr3 ", Direct }, - { "bbc3 ", DirectRelative }, - - { "cmp ", ADirectX }, - { "cmp ", AAbsoluteX }, - { "cmp ", AAbsoluteY }, - { "cmp ", AIDirectY }, - - { "cmp ", DirectConstant }, - { "cmp ", IXIY }, - { "addw ", YaDirect }, - { "ror ", DirectX }, - - { "ror ", A }, - { "mov ", AX }, - { "cmp ", YDirect }, - { "reti ", Implied }, - - //0x80 - 0x8f - { "setc ", Implied }, - { "tcall", TVector }, - { "set4 ", Direct }, - { "bbs4 ", DirectRelative }, - - { "adc ", ADirect }, - { "adc ", AAbsolute }, - { "adc ", AIX }, - { "adc ", AIDirectX }, - - { "adc ", AConstant }, - { "adc ", DirectDirect }, - { "eor1 ", CAbsoluteBit }, - { "dec ", Direct }, - - { "dec ", Absolute }, - { "mov ", YConstant }, - { "pop ", P }, - { "mov ", DirectConstant }, - - //0x90 - 0x9f - { "bcc ", Relative }, - { "tcall", TVector }, - { "clr4 ", Direct }, - { "bbc4 ", DirectRelative }, - - { "adc ", ADirectX }, - { "adc ", AAbsoluteX }, - { "adc ", AAbsoluteY }, - { "adc ", AIDirectY }, - - { "adc ", DirectRelative }, - { "adc ", IXIY }, - { "subw ", YaDirect }, - { "dec ", DirectX }, - - { "dec ", A }, - { "mov ", XSp }, - { "div ", YaX }, - { "xcn ", A }, - - //0xa0 - 0xaf - { "ei ", Implied }, - { "tcall", TVector }, - { "set5 ", Direct }, - { "bbs5 ", DirectRelative }, - - { "sbc ", ADirect }, - { "sbc ", AAbsolute }, - { "sbc ", AIX }, - { "sbc ", AIDirectX }, - - { "sbc ", AConstant }, - { "sbc ", DirectDirect }, - { "mov1 ", CAbsoluteBit }, - { "inc ", Direct }, - - { "inc ", Absolute }, - { "cmp ", YConstant }, - { "pop ", A }, - { "mov ", IXPA }, - - //0xb0 - 0xbf - { "bcs ", Relative }, - { "tcall", TVector }, - { "clr5 ", Direct }, - { "bbc5 ", DirectRelative }, - - { "sbc ", ADirectX }, - { "sbc ", AAbsoluteX }, - { "sbc ", AAbsoluteY }, - { "sbc ", AIDirectY }, - - { "sbc ", DirectConstant }, - { "sbc ", IXIY }, - { "movw ", YaDirect }, - { "inc ", DirectX }, - - { "inc ", A }, - { "mov ", SpX }, - { "das ", A }, - { "mov ", AIXP }, - - //0xc0 - 0xcf - { "di ", Implied }, - { "tcall", TVector }, - { "set6 ", Direct }, - { "bbs6 ", DirectRelative }, - - { "mov ", DirectA }, - { "mov ", AbsoluteA }, - { "mov ", IXA }, - { "mov ", IDirectXA }, - - { "cmp ", XConstant }, - { "mov ", AbsoluteX }, - { "mov1 ", AbsoluteBitC }, - { "mov ", DirectY }, - - { "mov ", AbsoluteY }, - { "mov ", XConstant }, - { "pop ", X }, - { "mul ", Ya }, - - //0xd0 - 0xdf - { "bne ", Relative }, - { "tcall", TVector }, - { "clr6 ", Relative }, - { "bbc6 ", DirectRelative }, - - { "mov ", DirectXA }, - { "mov ", AbsoluteXA }, - { "mov ", AbsoluteYA }, - { "mov ", IDirectYA }, - - { "mov ", DirectX }, - { "mov ", DirectYX }, - { "movw ", DirectYa }, - { "mov ", DirectXY }, - - { "dec ", Y }, - { "mov ", AY }, - { "cbne ", DirectXRelative }, - { "daa ", A }, - - //0xe0 - 0xef - { "clrv ", Implied }, - { "tcall", TVector }, - { "set7 ", Direct }, - { "bbs7 ", DirectRelative }, - - { "mov ", ADirect }, - { "mov ", AAbsolute }, - { "mov ", AIX }, - { "mov ", AIDirectX }, - - { "mov ", AConstant }, - { "mov ", XAbsolute }, - { "not1 ", CAbsoluteBit }, - { "mov ", YDirect }, - - { "mov ", YAbsolute }, - { "notc ", Implied }, - { "pop ", Y }, - { "sleep", Implied }, - - //0xf0 - 0xff - { "beq ", Relative }, - { "tcall", TVector }, - { "clr7 ", Direct }, - { "bbc7 ", DirectRelative }, - - { "mov ", ADirectX }, - { "mov ", AAbsoluteX }, - { "mov ", AAbsoluteY }, - { "mov ", AIDirectY }, - - { "mov ", XDirect }, - { "mov ", XDirectY }, - { "mov ", DirectDirect }, - { "mov ", YDirectX }, - - { "inc ", Y }, - { "mov ", YA }, - { "dbz ", YRelative }, - { "stop ", Implied }, -}; - -inline unsigned SNESSMP::getOpcodeLength(uint8_t opcode) { - switch(opcodeInfo[opcode].mode) { default: - case Implied: return 1; // - case TVector: return 1; //0 - case Direct: return 2; //$00 - case DirectRelative: return 3; //$00,+/-$00 - case ADirect: return 2; //a,$00 - case AAbsolute: return 3; //a,$0000 - case AIX: return 1; //a,(x) - case AIDirectX: return 2; //a,($00+x) - case AConstant: return 2; //a,#$00 - case DirectDirect: return 3; //$00,$00 - case CAbsoluteBit: return 3; //c,$0000:0 - case Absolute: return 3; //$0000 - case P: return 1; //p - case AbsoluteA: return 3; //$0000,a - case Relative: return 2; //+/-$00 - case ADirectX: return 2; //a,$00+x - case AAbsoluteX: return 3; //a,$0000+x - case AAbsoluteY: return 3; //a,$0000+y - case AIDirectY: return 2; //a,($00)+y - case DirectConstant: return 3; //$00,#$00 - case IXIY: return 1; //(x),(y) - case DirectX: return 2; //$00+x - case A: return 1; //a - case X: return 1; //x - case XAbsolute: return 3; //x,$0000 - case IAbsoluteX: return 3; //($0000+x) - case CNAbsoluteBit: return 3; //c,!$0000:0 - case XDirect: return 2; //x,$00 - case PVector: return 2; //$ff00 - case YaDirect: return 2; //ya,$00 - case XA: return 1; //x,a - case YAbsolute: return 3; //y,$0000 - case Y: return 1; //y - case AX: return 1; //a,x - case YDirect: return 2; //y,$00 - case YConstant: return 2; //y,#$00 - case XSp: return 1; //x,sp - case YaX: return 1; //ya,x - case IXPA: return 1; //(x)+,a - case SpX: return 1; //sp,x - case AIXP: return 1; //a,(x)+ - case DirectA: return 2; //$00,a - case IXA: return 1; //(x),a - case IDirectXA: return 2; //($00+x),a - case XConstant: return 2; //x,#$00 - case AbsoluteX: return 3; //$0000,x - case AbsoluteBitC: return 3; //$0000:0,c - case DirectY: return 2; //$00,y - case AbsoluteY: return 3; //$0000,y - case Ya: return 1; //ya - case DirectXA: return 2; //$00+x,a - case AbsoluteXA: return 3; //$0000+x,a - case AbsoluteYA: return 3; //$0000+y,a - case IDirectYA: return 2; //($00)+y,a - case DirectYX: return 2; //$00+y,x - case DirectYa: return 2; //$00,ya - case DirectXY: return 2; //$00+x,y - case AY: return 1; //a,y - case DirectXRelative: return 3; //$00+x,+/-$00 - case XDirectY: return 2; //x,$00+y - case YDirectX: return 2; //y,$00+x - case YA: return 1; //y,a - case YRelative: return 2; //y,+/-$00 - } -} - -inline string SNESSMP::disassemble(uint16_t pc, uint8_t opcode, uint8_t pl, uint8_t ph) { - string name = opcodeInfo[opcode].name; - unsigned mode = opcodeInfo[opcode].mode; - unsigned pa = (ph << 8) + pl; - - if(mode == Implied) return name; - if(mode == TVector) return { name, " ", opcode >> 4 }; - if(mode == Direct) return { name, " $", hex<2>(pl) }; - if(mode == DirectRelative) return { name, " $", hex<2>(pl), ",$", hex<4>(pc + 3 + (int8_t)ph) }; - if(mode == ADirect) return { name, " a,$", hex<2>(pl) }; - if(mode == AAbsolute) return { name, " a,$", hex<4>(pa) }; - if(mode == AIX) return { name, "a,(x)" }; - if(mode == AIDirectX) return { name, " a,($", hex<2>(pl), "+x)" }; - if(mode == AConstant) return { name, " a,#$", hex<2>(pl) }; - if(mode == DirectDirect) return { name, " $", hex<2>(ph), ",$", hex<2>(pl) }; - if(mode == CAbsoluteBit) return { name, " c,$", hex<4>(pa & 0x1fff), ":", pa >> 13 }; - if(mode == Absolute) return { name, " $", hex<4>(pa) }; - if(mode == P) return { name, " p" }; - if(mode == AbsoluteA) return { name, " $", hex<4>(pa), ",a" }; - if(mode == Relative) return { name, " $", hex<4>(pc + 2 + (int8_t)pl) }; - if(mode == ADirectX) return { name, " a,$", hex<2>(pl), "+x" }; - if(mode == AAbsoluteX) return { name, " a,$", hex<4>(pa), "+x" }; - if(mode == AAbsoluteY) return { name, " a,$", hex<4>(pa), "+y" }; - if(mode == AIDirectY) return { name, " a,($", hex<2>(pl), ")+y" }; - if(mode == DirectConstant) return { name, " $", hex<2>(ph), ",#$", hex<2>(pl) }; - if(mode == IXIY) return { name, " (x),(y)" }; - if(mode == DirectX) return { name, " $", hex<2>(pl), "+x" }; - if(mode == A) return { name, " a" }; - if(mode == X) return { name, " x" }; - if(mode == XAbsolute) return { name, " x,$", hex<4>(pa) }; - if(mode == IAbsoluteX) return { name, " ($", hex<4>(pa), "+x)" }; - if(mode == CNAbsoluteBit) return { name, " c,!$", hex<4>(pa & 0x1fff), ":", pa >> 13 }; - if(mode == XDirect) return { name, " x,$", hex<2>(pl) }; - if(mode == PVector) return { name, " $ff", hex<2>(pl) }; - if(mode == YaDirect) return { name, " ya,$", hex<2>(pl) }; - if(mode == XA) return { name, " x,a" }; - if(mode == YAbsolute) return { name, " y,$", hex<4>(pa) }; - if(mode == Y) return { name, " y" }; - if(mode == AX) return { name, " a,x" }; - if(mode == YDirect) return { name, " y,$", hex<2>(pl) }; - if(mode == YConstant) return { name, " y,#$", hex<2>(pl) }; - if(mode == XSp) return { name, " x,sp" }; - if(mode == YaX) return { name, " ya,x" }; - if(mode == IXPA) return { name, " (x)+,a" }; - if(mode == SpX) return { name, " sp,x" }; - if(mode == AIXP) return { name, " a,(x)+" }; - if(mode == DirectA) return { name, " $", hex<2>(pl), ",a" }; - if(mode == IXA) return { name, " (x),a" }; - if(mode == IDirectXA) return { name, " ($", hex<2>(pl), "+x),a" }; - if(mode == XConstant) return { name, " x,#$", hex<2>(pl) }; - if(mode == AbsoluteX) return { name, " $", hex<4>(pa), ",x" }; - if(mode == AbsoluteBitC) return { name, " $", hex<4>(pa & 0x1fff), ":", pa >> 13, ",c" }; - if(mode == DirectY) return { name, " $", hex<2>(pl), ",y" }; - if(mode == AbsoluteY) return { name, " $", hex<4>(pa), ",y" }; - if(mode == Ya) return { name, " ya" }; - if(mode == DirectXA) return { name, " $", hex<2>(pl), "+x,a" }; - if(mode == AbsoluteXA) return { name, " $", hex<4>(pa), "+x,a" }; - if(mode == AbsoluteYA) return { name, " $", hex<4>(pa), "+y,a" }; - if(mode == IDirectYA) return { name, " ($", hex<2>(pl), ")+y,a" }; - if(mode == DirectYX) return { name, " $", hex<2>(pl), "+y,x" }; - if(mode == DirectYa) return { name, " $", hex<2>(pl), ",ya" }; - if(mode == DirectXY) return { name, " $", hex<2>(pl), "+x,y" }; - if(mode == AY) return { name, " a,y" }; - if(mode == DirectXRelative) return { name, " $", hex<2>(pl), ",$", hex<4>(pc + 3 + (int8_t)ph) }; - if(mode == XDirectY) return { name, " x,$", hex<2>(pl), "+y" }; - if(mode == YDirectX) return { name, " y,$", hex<2>(pl), "+x" }; - if(mode == YA) return { name, " y,a" }; - if(mode == YRelative) return { name, " y,$", hex<4>(pc + 2 + (int8_t)pl) }; - - return ""; -} - -inline string SNESSMP::disassemble(uint16_t pc, bool p, uint8_t opcode, uint8_t pl, uint8_t ph) { - string name = opcodeInfo[opcode].name; - unsigned mode = opcodeInfo[opcode].mode; - unsigned pdl = (p << 8) + pl; - unsigned pdh = (p << 8) + ph; - unsigned pa = (ph << 8) + pl; - - if(mode == Implied) return name; - if(mode == TVector) return { name, " ", opcode >> 4 }; - if(mode == Direct) return { name, " $", hex<3>(pdl) }; - if(mode == DirectRelative) return { name, " $", hex<3>(pdl), ",$", hex<4>(pc + 3 + (int8_t)ph) }; - if(mode == ADirect) return { name, " a,$", hex<3>(pdl) }; - if(mode == AAbsolute) return { name, " a,$", hex<4>(pa) }; - if(mode == AIX) return { name, "a,(x)" }; - if(mode == AIDirectX) return { name, " a,($", hex<3>(pdl), "+x)" }; - if(mode == AConstant) return { name, " a,#$", hex<2>(pl) }; - if(mode == DirectDirect) return { name, " $", hex<3>(pdh), ",$", hex<3>(pdl) }; - if(mode == CAbsoluteBit) return { name, " c,$", hex<4>(pa & 0x1fff), ":", pa >> 13 }; - if(mode == Absolute) return { name, " $", hex<4>(pa) }; - if(mode == P) return { name, " p" }; - if(mode == AbsoluteA) return { name, " $", hex<4>(pa), ",a" }; - if(mode == Relative) return { name, " $", hex<4>(pc + 2 + (int8_t)pl) }; - if(mode == ADirectX) return { name, " a,$", hex<3>(pdl), "+x" }; - if(mode == AAbsoluteX) return { name, " a,$", hex<4>(pa), "+x" }; - if(mode == AAbsoluteY) return { name, " a,$", hex<4>(pa), "+y" }; - if(mode == AIDirectY) return { name, " a,($", hex<3>(pdl), ")+y" }; - if(mode == DirectConstant) return { name, " $", hex<3>(pdh), ",#$", hex<2>(pl) }; - if(mode == IXIY) return { name, " (x),(y)" }; - if(mode == DirectX) return { name, " $", hex<3>(pdl), "+x" }; - if(mode == A) return { name, " a" }; - if(mode == X) return { name, " x" }; - if(mode == XAbsolute) return { name, " x,$", hex<4>(pa) }; - if(mode == IAbsoluteX) return { name, " ($", hex<4>(pa), "+x)" }; - if(mode == CNAbsoluteBit) return { name, " c,!$", hex<4>(pa & 0x1fff), ":", pa >> 13 }; - if(mode == XDirect) return { name, " x,$", hex<3>(pdl) }; - if(mode == PVector) return { name, " $ff", hex<2>(pl) }; - if(mode == YaDirect) return { name, " ya,$", hex<3>(pdl) }; - if(mode == XA) return { name, " x,a" }; - if(mode == YAbsolute) return { name, " y,$", hex<4>(pa) }; - if(mode == Y) return { name, " y" }; - if(mode == AX) return { name, " a,x" }; - if(mode == YDirect) return { name, " y,$", hex<3>(pdl) }; - if(mode == YConstant) return { name, " y,#$", hex<2>(pl) }; - if(mode == XSp) return { name, " x,sp" }; - if(mode == YaX) return { name, " ya,x" }; - if(mode == IXPA) return { name, " (x)+,a" }; - if(mode == SpX) return { name, " sp,x" }; - if(mode == AIXP) return { name, " a,(x)+" }; - if(mode == DirectA) return { name, " $", hex<3>(pdl), ",a" }; - if(mode == IXA) return { name, " (x),a" }; - if(mode == IDirectXA) return { name, " ($", hex<3>(pdl), "+x),a" }; - if(mode == XConstant) return { name, " x,#$", hex<2>(pl) }; - if(mode == AbsoluteX) return { name, " $", hex<4>(pa), ",x" }; - if(mode == AbsoluteBitC) return { name, " $", hex<4>(pa & 0x1fff), ":", pa >> 13, ",c" }; - if(mode == DirectY) return { name, " $", hex<3>(pdl), ",y" }; - if(mode == AbsoluteY) return { name, " $", hex<4>(pa), ",y" }; - if(mode == Ya) return { name, " ya" }; - if(mode == DirectXA) return { name, " $", hex<3>(pdl), "+x,a" }; - if(mode == AbsoluteXA) return { name, " $", hex<4>(pa), "+x,a" }; - if(mode == AbsoluteYA) return { name, " $", hex<4>(pa), "+y,a" }; - if(mode == IDirectYA) return { name, " ($", hex<3>(pdl), ")+y,a" }; - if(mode == DirectYX) return { name, " $", hex<3>(pdl), "+y,x" }; - if(mode == DirectYa) return { name, " $", hex<3>(pdl), ",ya" }; - if(mode == DirectXY) return { name, " $", hex<3>(pdl), "+x,y" }; - if(mode == AY) return { name, " a,y" }; - if(mode == DirectXRelative) return { name, " $", hex<3>(pdl), ",$", hex<4>(pc + 3 + (int8_t)ph) }; - if(mode == XDirectY) return { name, " x,$", hex<3>(pdl), "+y" }; - if(mode == YDirectX) return { name, " y,$", hex<3>(pdl), "+x" }; - if(mode == YA) return { name, " y,a" }; - if(mode == YRelative) return { name, " y,$", hex<4>(pc + 2 + (int8_t)pl) }; - - return ""; -} - -} - -#endif diff --git a/bsnes/nall/string/base.hpp b/bsnes/nall/string/base.hpp index 6bbc7ee4b..c3b01bb33 100755 --- a/bsnes/nall/string/base.hpp +++ b/bsnes/nall/string/base.hpp @@ -112,6 +112,8 @@ namespace nall { struct lstring : vector { inline optional find(const char*) const; inline string concatenate(const char*) const; + inline void append() {} + template inline void append(const string&, Args&&...); template inline lstring& split(const char*, const char*); template inline lstring& isplit(const char*, const char*); @@ -121,8 +123,14 @@ namespace nall { inline bool operator==(const lstring&) const; inline bool operator!=(const lstring&) const; - inline lstring(); - inline lstring(std::initializer_list); + inline lstring& operator=(const lstring&); + inline lstring& operator=(lstring&); + inline lstring& operator=(lstring&&); + + template inline lstring(Args&&... args); + inline lstring(const lstring&); + inline lstring(lstring&); + inline lstring(lstring&&); protected: template inline lstring& usplit(const char*, const char*); @@ -149,9 +157,10 @@ namespace nall { inline bool strmath(const char *str, int &result); //platform.hpp - inline string realpath(const char *name); + inline string activepath(); + inline string realpath(const string &name); inline string userpath(); - inline string currentpath(); + inline string configpath(); //strm.hpp inline unsigned strmcpy(char *target, const char *source, unsigned length); diff --git a/bsnes/nall/string/core.hpp b/bsnes/nall/string/core.hpp index c62457231..d5f75f3ad 100755 --- a/bsnes/nall/string/core.hpp +++ b/bsnes/nall/string/core.hpp @@ -146,6 +146,11 @@ string lstring::concatenate(const char *separator) const { return output; } +template void lstring::append(const string &data, Args&&... args) { + vector::append(data); + append(std::forward(args)...); +} + bool lstring::operator==(const lstring &source) const { if(this == &source) return true; if(size() != source.size()) return false; @@ -159,11 +164,35 @@ bool lstring::operator!=(const lstring &source) const { return !operator==(source); } -inline lstring::lstring() { +lstring& lstring::operator=(const lstring &source) { + vector::operator=(source); + return *this; } -inline lstring::lstring(std::initializer_list list) { - for(auto &data : list) append(data); +lstring& lstring::operator=(lstring &source) { + vector::operator=(source); + return *this; +} + +lstring& lstring::operator=(lstring &&source) { + vector::operator=(std::move(source)); + return *this; +} + +template lstring::lstring(Args&&... args) { + append(std::forward(args)...); +} + +lstring::lstring(const lstring &source) { + vector::operator=(source); +} + +lstring::lstring(lstring &source) { + vector::operator=(source); +} + +lstring::lstring(lstring &&source) { + vector::operator=(std::move(source)); } } diff --git a/bsnes/nall/string/platform.hpp b/bsnes/nall/string/platform.hpp index 83a5fbae9..469d79b3c 100755 --- a/bsnes/nall/string/platform.hpp +++ b/bsnes/nall/string/platform.hpp @@ -2,36 +2,60 @@ namespace nall { -string currentpath() { - char path[PATH_MAX]; - if(::getcwd(path)) { - string result(path); - result.transform("\\", "/"); - if(result.endswith("/") == false) result.append("/"); - return result; - } - return "./"; +string activepath() { + string result; + #ifdef _WIN32 + wchar_t path[PATH_MAX] = L""; + _wgetcwd(path, PATH_MAX); + result = (const char*)utf8_t(path); + result.transform("\\", "/"); + #else + char path[PATH_MAX] = ""; + getcwd(path, PATH_MAX); + result = path; + #endif + if(result.empty()) result = "."; + if(result.endswith("/") == false) result.append("/"); + return result; +} + +string realpath(const string &name) { + string result; + #ifdef _WIN32 + wchar_t path[PATH_MAX] = L""; + if(_wfullpath(path, utf16_t(name), PATH_MAX)) result = (const char*)utf8_t(path); + result.transform("\\", "/"); + #else + char path[PATH_MAX] = ""; + if(::realpath(name, path)) result = path; + #endif + return result; } string userpath() { - char path[PATH_MAX]; - if(::userpath(path)) { - string result(path); - result.transform("\\", "/"); - if(result.endswith("/") == false) result.append("/"); - return result; - } - return currentpath(); + string result; + #ifdef _WIN32 + wchar_t path[PATH_MAX] = L""; + SHGetFolderPathW(0, CSIDL_APPDATA | CSIDL_FLAG_CREATE, 0, 0, path); + result = (const char*)utf8_t(path); + result.transform("\\", "/"); + #else + char path[PATH_MAX] = ""; + struct passwd *userinfo = getpwuid(getuid()); + if(userinfo) strcpy(path, userinfo->pw_dir); + result = path; + #endif + if(result.empty()) result = "."; + if(result.endswith("/") == false) result.append("/"); + return result; } -string realpath(const char *name) { - char path[PATH_MAX]; - if(::realpath(name, path)) { - string result(path); - result.transform("\\", "/"); - return result; - } +string configpath() { + #ifdef _WIN32 return userpath(); + #else + return {userpath(), ".config/"}; + #endif } } diff --git a/bsnes/nall/type_traits.hpp b/bsnes/nall/traits.hpp similarity index 95% rename from bsnes/nall/type_traits.hpp rename to bsnes/nall/traits.hpp index 1be3bf79c..6a140c2b9 100755 --- a/bsnes/nall/type_traits.hpp +++ b/bsnes/nall/traits.hpp @@ -1,5 +1,5 @@ -#ifndef NALL_STATIC_HPP -#define NALL_STATIC_HPP +#ifndef NALL_TRAITS_HPP +#define NALL_TRAITS_HPP #include diff --git a/bsnes/nall/varint.hpp b/bsnes/nall/varint.hpp index 6bfd1c155..98e189db7 100755 --- a/bsnes/nall/varint.hpp +++ b/bsnes/nall/varint.hpp @@ -2,7 +2,7 @@ #define NALL_VARINT_HPP #include -#include +#include namespace nall { template struct uint_t { diff --git a/bsnes/nall/windows/guid.hpp b/bsnes/nall/windows/guid.hpp new file mode 100755 index 000000000..386cfc75d --- /dev/null +++ b/bsnes/nall/windows/guid.hpp @@ -0,0 +1,30 @@ +#ifndef NALL_WINDOWS_GUID_HPP +#define NALL_WINDOWS_GUID_HPP + +#include +#include + +namespace nall { + +//generate unique GUID +inline string guid() { + random_lfsr lfsr; + lfsr.seed(time(0)); + for(unsigned n = 0; n < 256; n++) lfsr(); + + string output; + for(unsigned n = 0; n < 4; n++) output.append(hex<2>(lfsr())); + output.append("-"); + for(unsigned n = 0; n < 2; n++) output.append(hex<2>(lfsr())); + output.append("-"); + for(unsigned n = 0; n < 2; n++) output.append(hex<2>(lfsr())); + output.append("-"); + for(unsigned n = 0; n < 2; n++) output.append(hex<2>(lfsr())); + output.append("-"); + for(unsigned n = 0; n < 6; n++) output.append(hex<2>(lfsr())); + return {"{", output, "}"}; +} + +} + +#endif diff --git a/bsnes/nall/windows/registry.hpp b/bsnes/nall/windows/registry.hpp new file mode 100755 index 000000000..0774e04ae --- /dev/null +++ b/bsnes/nall/windows/registry.hpp @@ -0,0 +1,120 @@ +#ifndef NALL_WINDOWS_REGISTRY_HPP +#define NALL_WINDOWS_REGISTRY_HPP + +#include +#include + +#include +#ifndef KEY_WOW64_64KEY + #define KEY_WOW64_64KEY 0x0100 +#endif +#ifndef KEY_WOW64_32KEY + #define KEY_WOW64_32KEY 0x0200 +#endif + +#ifndef NWR_FLAGS + #define NWR_FLAGS KEY_WOW64_64KEY +#endif + +#ifndef NWR_SIZE + #define NWR_SIZE 4096 +#endif + +namespace nall { + +struct registry { + static bool exists(const string &name) { + lstring part = name.split("/"); + HKEY handle, rootKey = root(part.take(0)); + string node = part.take(); + string path = part.concatenate("\\"); + if(RegOpenKeyExW(rootKey, utf16_t(path), 0, NWR_FLAGS | KEY_READ, &handle) == ERROR_SUCCESS) { + wchar_t data[NWR_SIZE] = L""; + DWORD size = NWR_SIZE * sizeof(wchar_t); + LONG result = RegQueryValueExW(handle, utf16_t(node), NULL, NULL, (LPBYTE)&data, (LPDWORD)&size); + RegCloseKey(handle); + if(result == ERROR_SUCCESS) return true; + } + return false; + } + + static string read(const string &name) { + lstring part = name.split("/"); + HKEY handle, rootKey = root(part.take(0)); + string node = part.take(); + string path = part.concatenate("\\"); + if(RegOpenKeyExW(rootKey, utf16_t(path), 0, NWR_FLAGS | KEY_READ, &handle) == ERROR_SUCCESS) { + wchar_t data[NWR_SIZE] = L""; + DWORD size = NWR_SIZE * sizeof(wchar_t); + LONG result = RegQueryValueExW(handle, utf16_t(node), NULL, NULL, (LPBYTE)&data, (LPDWORD)&size); + RegCloseKey(handle); + if(result == ERROR_SUCCESS) return (const char*)utf8_t(data); + } + return ""; + } + + static void write(const string &name, const string &data = "") { + lstring part = name.split("/"); + HKEY handle, rootKey = root(part.take(0)); + string node = part.take(), path; + DWORD disposition; + for(unsigned n = 0; n < part.size(); n++) { + path.append(part[n]); + if(RegCreateKeyExW(rootKey, utf16_t(path), 0, NULL, 0, NWR_FLAGS | KEY_ALL_ACCESS, NULL, &handle, &disposition) == ERROR_SUCCESS) { + if(n == part.size() - 1) { + RegSetValueExW(handle, utf16_t(node), 0, REG_SZ, (BYTE*)(wchar_t*)utf16_t(data), (data.length() + 1) * sizeof(wchar_t)); + } + RegCloseKey(handle); + } + path.append("\\"); + } + } + + static bool remove(const string &name) { + lstring part = name.split("/"); + HKEY rootKey = root(part.take(0)); + string node = part.take(); + string path = part.concatenate("\\"); + if(node.empty()) return SHDeleteKeyW(rootKey, utf16_t(path)) == ERROR_SUCCESS; + return SHDeleteValueW(rootKey, utf16_t(path), utf16_t(node)) == ERROR_SUCCESS; + } + + static lstring contents(const string &name) { + lstring part = name.split("/"), result; + HKEY handle, rootKey = root(part.take(0)); + part.remove(); + string path = part.concatenate("\\"); + if(RegOpenKeyExW(rootKey, utf16_t(path), 0, NWR_FLAGS | KEY_READ, &handle) == ERROR_SUCCESS) { + DWORD folders, nodes; + RegQueryInfoKey(handle, NULL, NULL, NULL, &folders, NULL, NULL, &nodes, NULL, NULL, NULL, NULL); + for(unsigned n = 0; n < folders; n++) { + wchar_t name[NWR_SIZE] = L""; + DWORD size = NWR_SIZE * sizeof(wchar_t); + RegEnumKeyEx(handle, n, (wchar_t*)&name, &size, NULL, NULL, NULL, NULL); + result.append({(const char*)utf8_t(name), "/"}); + } + for(unsigned n = 0; n < nodes; n++) { + wchar_t name[NWR_SIZE] = L""; + DWORD size = NWR_SIZE * sizeof(wchar_t); + RegEnumValueW(handle, n, (wchar_t*)&name, &size, NULL, NULL, NULL, NULL); + result.append((const char*)utf8_t(name)); + } + RegCloseKey(handle); + } + return result; + } + +private: + static HKEY root(const string &name) { + if(name == "HKCR") return HKEY_CLASSES_ROOT; + if(name == "HKCC") return HKEY_CURRENT_CONFIG; + if(name == "HKCU") return HKEY_CURRENT_USER; + if(name == "HKLM") return HKEY_LOCAL_MACHINE; + if(name == "HKU" ) return HKEY_USERS; + return NULL; + } +}; + +} + +#endif diff --git a/bsnes/nall/windows/utf8.hpp b/bsnes/nall/windows/utf8.hpp index f5597b857..b13749430 100755 --- a/bsnes/nall/windows/utf8.hpp +++ b/bsnes/nall/windows/utf8.hpp @@ -12,6 +12,7 @@ #define UNICODE #define _WIN32_WINNT 0x0501 #define NOMINMAX +#include #include #undef interface diff --git a/bsnes/nall/zip.hpp b/bsnes/nall/zip.hpp index 3daacd045..779b067ef 100755 --- a/bsnes/nall/zip.hpp +++ b/bsnes/nall/zip.hpp @@ -80,28 +80,22 @@ struct zip { return true; } - inline bool extract(File &file, uint8_t *&data, unsigned &size) { - data = 0, size = 0; + inline vector extract(File &file) { + vector buffer; if(file.cmode == 0) { - size = file.size; - data = new uint8_t[size]; - memcpy(data, file.data, size); - return true; + buffer.resize(file.size); + memcpy(buffer.data(), file.data, file.size); } if(file.cmode == 8) { - size = file.size; - data = new uint8_t[size]; - if(inflate(data, size, file.data, file.csize) == false) { - delete[] data; - size = 0; - return false; + buffer.resize(file.size); + if(inflate(buffer.data(), buffer.size(), file.data, file.csize) == false) { + buffer.reset(); } - return true; } - return false; + return buffer; } inline void close() { diff --git a/bsnes/phoenix/core/core.cpp b/bsnes/phoenix/core/core.cpp index 277c57286..77ccbbbed 100755 --- a/bsnes/phoenix/core/core.cpp +++ b/bsnes/phoenix/core/core.cpp @@ -1058,6 +1058,7 @@ void ListView::modify_(unsigned row, const lstring &text) { void ListView::reset() { state.checked.reset(); + state.image.reset(); state.text.reset(); return p.reset(); } @@ -1090,6 +1091,11 @@ void ListView::setHeaderVisible(bool visible) { return p.setHeaderVisible(visible); } +void ListView::setImage(unsigned row, unsigned column, const nall::image &image) { + state.image(row)(column) = image; + return p.setImage(row, column, image); +} + void ListView::setSelected(bool selected) { state.selected = selected; return p.setSelected(selected); diff --git a/bsnes/phoenix/core/core.hpp b/bsnes/phoenix/core/core.hpp index d4172fee8..07864bfce 100755 --- a/bsnes/phoenix/core/core.hpp +++ b/bsnes/phoenix/core/core.hpp @@ -232,12 +232,12 @@ struct Action : Object { }; struct Menu : private nall::base_from_member, Action { - template void append(Args&... args) { append({ args... }); } - template void remove(Args&... args) { remove({ args... }); } + template void append(Args&... args) { append({args...}); } + template void remove(Args&... args) { remove({args...}); } void append(const nall::set &list); void remove(const nall::set &list); - void setImage(const nall::image &image); + void setImage(const nall::image &image = nall::image{}); void setText(const nall::string &text); Menu(); @@ -256,7 +256,7 @@ struct Separator : private nall::base_from_member, Action { struct Item : private nall::base_from_member, Action { nall::function onActivate; - void setImage(const nall::image &image); + void setImage(const nall::image &image = nall::image{}); void setText(const nall::string &text); Item(); @@ -281,7 +281,7 @@ struct CheckItem : private nall::base_from_member, Action { }; struct RadioItem : private nall::base_from_member, Action { - template static void group(Args&... args) { group({ args... }); } + template static void group(Args&... args) { group({args...}); } static void group(const nall::set &list); nall::function onActivate; @@ -352,7 +352,7 @@ struct Widget : private nall::base_from_member, Sizable { struct Button : private nall::base_from_member, Widget { nall::function onActivate; - void setImage(const nall::image &image, Orientation = Orientation::Horizontal); + void setImage(const nall::image &image = nall::image{}, Orientation = Orientation::Horizontal); void setText(const nall::string &text); Button(); @@ -398,7 +398,7 @@ struct CheckBox : private nall::base_from_member, Widget { struct ComboBox : private nall::base_from_member, Widget { nall::function onChange; - template void append(const Args&... args) { append_({ args... }); } + template void append(const Args&... args) { append_({args...}); } void append_(const nall::lstring &list); void reset(); @@ -491,9 +491,9 @@ struct ListView : private nall::base_from_member, Widget { nall::function onChange; nall::function onToggle; - template void append(const Args&... args) { append_({ args... }); } - template void modify(unsigned row, const Args&... args) { modify_(row, { args... }); } - template void setHeaderText(const Args&... args) { setHeaderText_({ args... }); } + template void append(const Args&... args) { append_({args...}); } + template void modify(unsigned row, const Args&... args) { modify_(row, {args...}); } + template void setHeaderText(const Args&... args) { setHeaderText_({args...}); } void append_(const nall::lstring &list); void autoSizeColumns(); @@ -506,6 +506,7 @@ struct ListView : private nall::base_from_member, Widget { void setChecked(unsigned row, bool checked = true); void setHeaderText_(const nall::lstring &list); void setHeaderVisible(bool visible = true); + void setImage(unsigned row, unsigned column, const nall::image &image = nall::image{}); void setSelected(bool selected = true); void setSelection(unsigned row); @@ -527,7 +528,7 @@ struct ProgressBar : private nall::base_from_member, Widget { }; struct RadioBox : private nall::base_from_member, Widget { - template static void group(Args&... args) { group({ args... }); } + template static void group(Args&... args) { group({args...}); } static void group(const nall::set &list); nall::function onActivate; diff --git a/bsnes/phoenix/core/state.hpp b/bsnes/phoenix/core/state.hpp index e87dfc3cf..2d46ca2f4 100755 --- a/bsnes/phoenix/core/state.hpp +++ b/bsnes/phoenix/core/state.hpp @@ -213,6 +213,7 @@ struct ListView::State { vector checked; lstring headerText; bool headerVisible; + vector> image; bool selected; unsigned selection; vector text; diff --git a/bsnes/phoenix/gtk/action/item.cpp b/bsnes/phoenix/gtk/action/item.cpp index 1cd0db148..afab955e4 100755 --- a/bsnes/phoenix/gtk/action/item.cpp +++ b/bsnes/phoenix/gtk/action/item.cpp @@ -3,8 +3,12 @@ static void Item_activate(Item *self) { } void pItem::setImage(const image &image) { - GtkImage *gtkImage = CreateImage(image, /* menuIcon = */ true); - gtk_image_menu_item_set_image(GTK_IMAGE_MENU_ITEM(widget), (GtkWidget*)gtkImage); + if(image.empty() == false) { + GtkImage *gtkImage = CreateImage(image, true); + gtk_image_menu_item_set_image(GTK_IMAGE_MENU_ITEM(widget), (GtkWidget*)gtkImage); + } else { + gtk_image_menu_item_set_image(GTK_IMAGE_MENU_ITEM(widget), nullptr); + } } void pItem::setText(const string &text) { diff --git a/bsnes/phoenix/gtk/action/menu.cpp b/bsnes/phoenix/gtk/action/menu.cpp index bcdca46a9..922520854 100755 --- a/bsnes/phoenix/gtk/action/menu.cpp +++ b/bsnes/phoenix/gtk/action/menu.cpp @@ -14,8 +14,12 @@ void pMenu::remove(Action &action) { } void pMenu::setImage(const image &image) { - GtkImage *gtkImage = CreateImage(image, /* menuIcon = */ true); - gtk_image_menu_item_set_image(GTK_IMAGE_MENU_ITEM(widget), (GtkWidget*)gtkImage); + if(image.empty() == false) { + GtkImage *gtkImage = CreateImage(image, true); + gtk_image_menu_item_set_image(GTK_IMAGE_MENU_ITEM(widget), (GtkWidget*)gtkImage); + } else { + gtk_image_menu_item_set_image(GTK_IMAGE_MENU_ITEM(widget), nullptr); + } } void pMenu::setText(const string &text) { diff --git a/bsnes/phoenix/gtk/platform.hpp b/bsnes/phoenix/gtk/platform.hpp index 34fb2e5fd..0f3134510 100755 --- a/bsnes/phoenix/gtk/platform.hpp +++ b/bsnes/phoenix/gtk/platform.hpp @@ -383,11 +383,11 @@ struct pListView : public pWidget { GtkWidget *subWidget; GtkListStore *store; struct GtkColumn { - GtkCellRenderer *renderer; GtkTreeViewColumn *column; + GtkCellRenderer *checkbox, *icon, *text; GtkWidget *label; }; - linear_vector column; + vector column; void append(const lstring &text); void autoSizeColumns(); @@ -400,6 +400,7 @@ struct pListView : public pWidget { void setChecked(unsigned row, bool checked); void setHeaderText(const lstring &text); void setHeaderVisible(bool visible); + void setImage(unsigned row, unsigned column, const nall::image &image); void setSelected(bool selected); void setSelection(unsigned row); diff --git a/bsnes/phoenix/gtk/utility.cpp b/bsnes/phoenix/gtk/utility.cpp index 360e51e34..29e87bb86 100755 --- a/bsnes/phoenix/gtk/utility.cpp +++ b/bsnes/phoenix/gtk/utility.cpp @@ -1,13 +1,18 @@ -static GtkImage* CreateImage(const nall::image &image, bool menuIcon = false) { +static GdkPixbuf* CreatePixbuf(const nall::image &image, bool scale = false) { nall::image gdkImage = image; - gdkImage.transform(0, 32, 255u << 24, 255u << 0, 255u << 8, 255u << 16); //GTK+ uses ABGR format - if(menuIcon) gdkImage.scale(16, 16, Interpolation::Linear); + gdkImage.transform(0, 32, 255u << 24, 255u << 0, 255u << 8, 255u << 16); + if(scale) gdkImage.scale(15, 15, Interpolation::Linear); GdkPixbuf *pixbuf = gdk_pixbuf_new(GDK_COLORSPACE_RGB, true, 8, gdkImage.width, gdkImage.height); memcpy(gdk_pixbuf_get_pixels(pixbuf), gdkImage.data, gdkImage.width * gdkImage.height * 4); + + return pixbuf; +} + +static GtkImage* CreateImage(const nall::image &image, bool scale = false) { + GdkPixbuf *pixbuf = CreatePixbuf(image, scale); GtkImage *gtkImage = (GtkImage*)gtk_image_new_from_pixbuf(pixbuf); g_object_unref(pixbuf); - return gtkImage; } diff --git a/bsnes/phoenix/gtk/widget/button.cpp b/bsnes/phoenix/gtk/widget/button.cpp index 485fdacb1..6f646a25b 100755 --- a/bsnes/phoenix/gtk/widget/button.cpp +++ b/bsnes/phoenix/gtk/widget/button.cpp @@ -19,8 +19,12 @@ Geometry pButton::minimumGeometry() { } void pButton::setImage(const image &image, Orientation orientation) { - GtkImage *gtkImage = CreateImage(image); - gtk_button_set_image(GTK_BUTTON(gtkWidget), (GtkWidget*)gtkImage); + if(image.empty() == false) { + GtkImage *gtkImage = CreateImage(image); + gtk_button_set_image(GTK_BUTTON(gtkWidget), (GtkWidget*)gtkImage); + } else { + gtk_button_set_image(GTK_BUTTON(gtkWidget), nullptr); + } switch(orientation) { case Orientation::Horizontal: gtk_button_set_image_position(GTK_BUTTON(gtkWidget), GTK_POS_LEFT); break; case Orientation::Vertical: gtk_button_set_image_position(GTK_BUTTON(gtkWidget), GTK_POS_TOP); break; diff --git a/bsnes/phoenix/gtk/widget/list-view.cpp b/bsnes/phoenix/gtk/widget/list-view.cpp index 9ace5a557..4ce367b1b 100755 --- a/bsnes/phoenix/gtk/widget/list-view.cpp +++ b/bsnes/phoenix/gtk/widget/list-view.cpp @@ -10,8 +10,8 @@ static void ListView_change(ListView *self) { } } -static void ListView_toggle(GtkCellRendererToggle *cell, gchar *path_string, ListView *self) { - unsigned row = decimal(path_string); +static void ListView_toggle(GtkCellRendererToggle *cell, gchar *path, ListView *self) { + unsigned row = decimal(path); self->setChecked(row, !self->checked(row)); if(self->onToggle) self->onToggle(row); } @@ -19,7 +19,7 @@ static void ListView_toggle(GtkCellRendererToggle *cell, gchar *path_string, Lis void pListView::append(const lstring &text) { GtkTreeIter iter; gtk_list_store_append(store, &iter); - for(unsigned n = 0; n < text.size(); n++) gtk_list_store_set(store, &iter, 1 + n, (const char*)text[n], -1); + for(unsigned n = 0; n < text.size(); n++) gtk_list_store_set(store, &iter, 1 + n * 2 + 1, (const char*)text[n], -1); } void pListView::autoSizeColumns() { @@ -39,7 +39,7 @@ void pListView::modify(unsigned row, const lstring &text) { GtkTreeModel *model = gtk_tree_view_get_model(GTK_TREE_VIEW(subWidget)); GtkTreeIter iter; gtk_tree_model_get_iter_from_string(model, &iter, string(row)); - for(unsigned n = 0; n < text.size(); n++) gtk_list_store_set(store, &iter, 1 + n, (const char*)text[n], -1); + for(unsigned n = 0; n < text.size(); n++) gtk_list_store_set(store, &iter, 1 + n * 2 + 1, (const char*)text[n], -1); } void pListView::reset() { @@ -69,7 +69,7 @@ unsigned pListView::selection() { } void pListView::setCheckable(bool checkable) { - gtk_tree_view_column_set_visible(column[0].column, checkable); + gtk_cell_renderer_set_visible(column(0).checkbox, checkable); } void pListView::setChecked(unsigned row, bool checked) { @@ -88,6 +88,18 @@ void pListView::setHeaderVisible(bool visible) { gtk_tree_view_set_headers_visible(GTK_TREE_VIEW(subWidget), visible); } +void pListView::setImage(unsigned row, unsigned column, const nall::image &image) { + GtkTreeModel *model = gtk_tree_view_get_model(GTK_TREE_VIEW(subWidget)); + GtkTreeIter iter; + gtk_tree_model_get_iter_from_string(model, &iter, string(row)); + if(image.empty() == false) { + GdkPixbuf *pixbuf = CreatePixbuf(image, true); + gtk_list_store_set(store, &iter, 1 + column * 2, pixbuf, -1); + } else { + gtk_list_store_set(store, &iter, 1 + column * 2, nullptr, -1); + } +} + void pListView::setSelected(bool selected) { if(selected == false) { GtkTreeSelection *selection = gtk_tree_view_get_selection(GTK_TREE_VIEW(subWidget)); @@ -114,47 +126,56 @@ void pListView::setSelection(unsigned row) { } void pListView::constructor() { - gtkWidget = 0; - subWidget = 0; - gtkWidget = gtk_scrolled_window_new(0, 0); gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(gtkWidget), GTK_POLICY_AUTOMATIC, GTK_POLICY_AUTOMATIC); gtk_scrolled_window_set_shadow_type(GTK_SCROLLED_WINDOW(gtkWidget), GTK_SHADOW_ETCHED_IN); - lstring headerText; - headerText.append(""); //checkbox column - for(auto &headerItem : listView.state.headerText) headerText.append(headerItem); - if(headerText.size() == 1) headerText.append(""); + lstring headerText = listView.state.headerText; + if(headerText.size() == 0) headerText.append(""); //ListView must have at least one column - GType *v = (GType*)malloc(headerText.size() * sizeof(GType)); - for(unsigned n = 0; n < headerText.size(); n++) v[n] = (n == 0 ? G_TYPE_BOOLEAN : G_TYPE_STRING); - store = gtk_list_store_newv(headerText.size(), v); - free(v); + column.reset(); + vector gtype; + for(auto &text : headerText) { + GtkColumn cell; + cell.label = gtk_label_new(text); + cell.column = gtk_tree_view_column_new(); + gtk_tree_view_column_set_resizable(cell.column, true); + gtk_tree_view_column_set_title(cell.column, ""); + if(column.size() == 0) { //first column checkbox + cell.checkbox = gtk_cell_renderer_toggle_new(); + gtk_tree_view_column_pack_start(cell.column, cell.checkbox, false); + gtk_tree_view_column_set_attributes(cell.column, cell.checkbox, "active", gtype.size(), nullptr); + gtype.append(G_TYPE_BOOLEAN); + g_signal_connect(cell.checkbox, "toggled", G_CALLBACK(ListView_toggle), (gpointer)&listView); + } + + cell.icon = gtk_cell_renderer_pixbuf_new(); + gtk_tree_view_column_pack_start(cell.column, cell.icon, false); + gtk_tree_view_column_set_attributes(cell.column, cell.icon, "pixbuf", gtype.size(), nullptr); + gtype.append(GDK_TYPE_PIXBUF); + + cell.text = gtk_cell_renderer_text_new(); + gtk_tree_view_column_pack_start(cell.column, cell.text, false); + gtk_tree_view_column_set_attributes(cell.column, cell.text, "text", gtype.size(), nullptr); + gtype.append(G_TYPE_STRING); + + column.append(cell); + } + + store = gtk_list_store_newv(gtype.size(), gtype.data()); subWidget = gtk_tree_view_new_with_model(GTK_TREE_MODEL(store)); gtk_container_add(GTK_CONTAINER(gtkWidget), subWidget); g_object_unref(G_OBJECT(store)); - for(unsigned n = 0; n < headerText.size(); n++) { - if(n == 0) { - column[n].renderer = gtk_cell_renderer_toggle_new(); - column[n].column = gtk_tree_view_column_new_with_attributes("", column[n].renderer, "active", n, (void*)0); - gtk_tree_view_column_set_resizable(column[n].column, false); - gtk_tree_view_column_set_visible(column[n].column, false); - g_signal_connect(column[n].renderer, "toggled", G_CALLBACK(ListView_toggle), (gpointer)&listView); - } else { - column[n].renderer = gtk_cell_renderer_text_new(); - column[n].column = gtk_tree_view_column_new_with_attributes("", column[n].renderer, "text", n, (void*)0); - gtk_tree_view_column_set_resizable(column[n].column, true); - } - column[n].label = gtk_label_new(headerText[n]); - gtk_tree_view_column_set_widget(GTK_TREE_VIEW_COLUMN(column[n].column), column[n].label); - gtk_tree_view_append_column(GTK_TREE_VIEW(subWidget), column[n].column); - gtk_widget_show(column[n].label); + for(auto &cell : column) { + gtk_tree_view_column_set_widget(GTK_TREE_VIEW_COLUMN(cell.column), cell.label); + gtk_tree_view_append_column(GTK_TREE_VIEW(subWidget), cell.column); + gtk_widget_show(cell.label); } - gtk_tree_view_set_rules_hint(GTK_TREE_VIEW(subWidget), headerText.size() >= 3); //two or more columns + checkbox column - gtk_tree_view_set_search_column(GTK_TREE_VIEW(subWidget), 1); + gtk_tree_view_set_rules_hint(GTK_TREE_VIEW(subWidget), headerText.size() >= 2); //two or more columns + checkbox column + gtk_tree_view_set_search_column(GTK_TREE_VIEW(subWidget), 2); g_signal_connect_swapped(G_OBJECT(subWidget), "cursor-changed", G_CALLBACK(ListView_change), (gpointer)&listView); g_signal_connect_swapped(G_OBJECT(subWidget), "row-activated", G_CALLBACK(ListView_activate), (gpointer)&listView); @@ -185,7 +206,5 @@ void pListView::setFocused() { void pListView::setFont(const string &font) { pFont::setFont(gtkWidget, font); - for(unsigned n = 0; n < 1 + listView.state.headerText.size(); n++) { - pFont::setFont(column[n].label, font); - } + for(auto &cell : column) pFont::setFont(cell.label, font); } diff --git a/bsnes/phoenix/phoenix.cpp b/bsnes/phoenix/phoenix.cpp index 422ab29eb..6e1b94bab 100755 --- a/bsnes/phoenix/phoenix.cpp +++ b/bsnes/phoenix/phoenix.cpp @@ -9,6 +9,7 @@ #define __MSVCRT_VERSION__ 0x0601 #define NOMINMAX + #include #include #include #include diff --git a/bsnes/phoenix/qt/action/item.cpp b/bsnes/phoenix/qt/action/item.cpp index a516909d6..7f1422893 100755 --- a/bsnes/phoenix/qt/action/item.cpp +++ b/bsnes/phoenix/qt/action/item.cpp @@ -1,10 +1,5 @@ void pItem::setImage(const image &image) { - nall::image qtBuffer = image; - qtBuffer.transform(0, 32u, 255u << 24, 255u << 16, 255u << 8, 255u << 0); - - QImage qtImage(qtBuffer.data, qtBuffer.width, qtBuffer.height, QImage::Format_ARGB32); - QIcon qtIcon(QPixmap::fromImage(qtImage)); - qtAction->setIcon(qtIcon); + qtAction->setIcon(CreateIcon(image)); } void pItem::setText(const string &text) { diff --git a/bsnes/phoenix/qt/action/menu.cpp b/bsnes/phoenix/qt/action/menu.cpp index de3a73418..43d89a1ef 100755 --- a/bsnes/phoenix/qt/action/menu.cpp +++ b/bsnes/phoenix/qt/action/menu.cpp @@ -34,12 +34,7 @@ void pMenu::setFont(const string &font) { } void pMenu::setImage(const image &image) { - nall::image qtBuffer = image; - qtBuffer.transform(0, 32u, 255u << 24, 255u << 16, 255u << 8, 255u << 0); - - QImage qtImage(qtBuffer.data, qtBuffer.width, qtBuffer.height, QImage::Format_ARGB32); - QIcon qtIcon(QPixmap::fromImage(qtImage)); - qtMenu->setIcon(qtIcon); + qtMenu->setIcon(CreateIcon(image)); } void pMenu::setText(const string &text) { diff --git a/bsnes/phoenix/qt/platform.moc b/bsnes/phoenix/qt/platform.moc index d27d94f66..564ff34d7 100755 --- a/bsnes/phoenix/qt/platform.moc +++ b/bsnes/phoenix/qt/platform.moc @@ -1,7 +1,7 @@ /**************************************************************************** ** Meta object code from reading C++ file 'platform.moc.hpp' ** -** Created: Tue May 1 09:36:37 2012 +** Created: Sun Jun 17 11:38:40 2012 ** by: The Qt Meta Object Compiler version 62 (Qt 4.6.3) ** ** WARNING! All changes made in this file will be lost! diff --git a/bsnes/phoenix/qt/platform.moc.hpp b/bsnes/phoenix/qt/platform.moc.hpp index 915ce82ac..510a1ee64 100755 --- a/bsnes/phoenix/qt/platform.moc.hpp +++ b/bsnes/phoenix/qt/platform.moc.hpp @@ -493,6 +493,7 @@ public: void setChecked(unsigned row, bool checked); void setHeaderText(const lstring &text); void setHeaderVisible(bool visible); + void setImage(unsigned row, unsigned column, const nall::image &image); void setSelected(bool selected); void setSelection(unsigned row); diff --git a/bsnes/phoenix/qt/utility.cpp b/bsnes/phoenix/qt/utility.cpp index 4f06c202f..400df0a2b 100755 --- a/bsnes/phoenix/qt/utility.cpp +++ b/bsnes/phoenix/qt/utility.cpp @@ -1,3 +1,11 @@ +static QIcon CreateIcon(const nall::image &image, bool scale = false) { + nall::image qtBuffer = image; + qtBuffer.transform(0, 32, 255u << 24, 255u << 16, 255u << 8, 255u << 0); + if(scale) qtBuffer.scale(16, 16, Interpolation::Linear); + QImage qtImage(qtBuffer.data, qtBuffer.width, qtBuffer.height, QImage::Format_ARGB32); + return QIcon(QPixmap::fromImage(qtImage)); +} + static Keyboard::Keycode Keysym(int keysym) { switch(keysym) { case XK_Escape: return Keyboard::Keycode::Escape; diff --git a/bsnes/phoenix/qt/widget/button.cpp b/bsnes/phoenix/qt/widget/button.cpp index dfcc6813d..0e1522b3d 100755 --- a/bsnes/phoenix/qt/widget/button.cpp +++ b/bsnes/phoenix/qt/widget/button.cpp @@ -15,13 +15,8 @@ Geometry pButton::minimumGeometry() { } void pButton::setImage(const image &image, Orientation orientation) { - nall::image qtBuffer = image; - qtBuffer.transform(0, 32, 255u << 24, 255u << 16, 255u << 8, 255u << 0); - - QImage qtImage(qtBuffer.data, qtBuffer.width, qtBuffer.height, QImage::Format_ARGB32); - QIcon qtIcon(QPixmap::fromImage(qtImage)); - qtButton->setIconSize(QSize(qtBuffer.width, qtBuffer.height)); - qtButton->setIcon(qtIcon); + qtButton->setIconSize(QSize(image.width, image.height)); + qtButton->setIcon(CreateIcon(image)); qtButton->setStyleSheet("text-align: top;"); switch(orientation) { case Orientation::Horizontal: qtButton->setToolButtonStyle(Qt::ToolButtonTextBesideIcon); break; diff --git a/bsnes/phoenix/qt/widget/list-view.cpp b/bsnes/phoenix/qt/widget/list-view.cpp index fa6317400..e1fdc73d6 100755 --- a/bsnes/phoenix/qt/widget/list-view.cpp +++ b/bsnes/phoenix/qt/widget/list-view.cpp @@ -2,6 +2,7 @@ void pListView::append(const lstring &text) { locked = true; auto items = qtListView->findItems("", Qt::MatchContains); QTreeWidgetItem *item = new QTreeWidgetItem(qtListView); + item->setData(0, Qt::UserRole, (unsigned)items.size()); if(listView.state.checkable) item->setCheckState(0, Qt::Unchecked); for(unsigned n = 0; n < text.size(); n++) { @@ -73,6 +74,14 @@ void pListView::setHeaderVisible(bool visible) { autoSizeColumns(); } +void pListView::setImage(unsigned row, unsigned column, const nall::image &image) { + QTreeWidgetItem *item = qtListView->topLevelItem(row); + if(item) { + if(image.empty() == 0) item->setIcon(column, CreateIcon(image)); + if(image.empty() == 1) item->setIcon(column, QIcon()); + } +} + void pListView::setSelected(bool selected) { QTreeWidgetItem *item = qtListView->currentItem(); if(item) item->setSelected(selected); diff --git a/bsnes/phoenix/windows/platform.hpp b/bsnes/phoenix/windows/platform.hpp index 701da25d1..aa797ebff 100755 --- a/bsnes/phoenix/windows/platform.hpp +++ b/bsnes/phoenix/windows/platform.hpp @@ -368,6 +368,7 @@ struct pLineEdit : public pWidget { struct pListView : public pWidget { ListView &listView; + HIMAGELIST imageList; bool lostFocus; void append(const lstring &text); @@ -381,14 +382,16 @@ struct pListView : public pWidget { void setChecked(unsigned row, bool checked); void setHeaderText(const lstring &text); void setHeaderVisible(bool visible); + void setImage(unsigned row, unsigned column, const image &image); void setSelected(bool selected); void setSelection(unsigned row); - pListView(ListView &listView) : pWidget(listView), listView(listView) {} + pListView(ListView &listView) : pWidget(listView), listView(listView), imageList(nullptr) {} void constructor(); void destructor(); void orphan(); void setGeometry(const Geometry &geometry); + void setImageList(); }; struct pProgressBar : public pWidget { diff --git a/bsnes/phoenix/windows/widget/list-view.cpp b/bsnes/phoenix/windows/widget/list-view.cpp index efa66f6b8..cb99023b2 100755 --- a/bsnes/phoenix/windows/widget/list-view.cpp +++ b/bsnes/phoenix/windows/widget/list-view.cpp @@ -2,9 +2,10 @@ void pListView::append(const lstring &list) { wchar_t empty[] = L""; unsigned row = ListView_GetItemCount(hwnd); LVITEM item; - item.mask = LVIF_TEXT; + item.mask = LVIF_TEXT | LVIF_IMAGE; item.iItem = row; item.iSubItem = 0; + item.iImage = row; item.pszText = empty; locked = true; ListView_InsertItem(hwnd, &item); @@ -88,6 +89,11 @@ void pListView::setHeaderVisible(bool visible) { ); } +void pListView::setImage(unsigned row, unsigned column, const image &image) { + if(column != 0) return; //ListView can only set icons on first column + setImageList(); +} + void pListView::setSelected(bool selected) { locked = true; lostFocus = false; @@ -118,6 +124,7 @@ void pListView::constructor() { setHeaderText(listView.state.headerText); setHeaderVisible(listView.state.headerVisible); setCheckable(listView.state.checkable); + setImageList(); for(auto &text : listView.state.text) append(text); for(unsigned n = 0; n < listView.state.checked.size(); n++) setChecked(n, listView.state.checked[n]); if(listView.state.selected) setSelection(listView.state.selection); @@ -138,3 +145,33 @@ void pListView::setGeometry(const Geometry &geometry) { pWidget::setGeometry(geometry); autoSizeColumns(); } + +void pListView::setImageList() { + if(imageList) { + ImageList_Destroy(imageList); + imageList = nullptr; + } + + unsigned images = 0; + for(auto &image : listView.state.image) { + if(image.empty() == false) images++; + } + if(images == 0) return; + + imageList = ImageList_Create(16, 16, ILC_COLOR32, listView.state.text.size(), 0); + + for(unsigned rowID = 0; rowID < listView.state.image.size(); rowID++) { + auto &row = listView.state.image(rowID); + nall::image image = row(0); + if(image.empty()) { + image.allocate(16, 16); + image.clear(~0); + } + image.transform(0, 32, 255u << 24, 255u << 16, 255u << 8, 255u << 0); + image.scale(16, 16, Interpolation::Linear); + HBITMAP hbitmap = CreateBitmap(image); + ImageList_Add(imageList, hbitmap, NULL); + } + + ListView_SetImageList(hwnd, imageList, LVSIL_SMALL); +} diff --git a/bsnes/target-ethos/Makefile b/bsnes/target-ethos/Makefile index fdcf497b7..a7606d945 100755 --- a/bsnes/target-ethos/Makefile +++ b/bsnes/target-ethos/Makefile @@ -68,6 +68,9 @@ else $(strip $(cpp) -o out/$(name) $(objects) $(link)) endif +resource: + sourcery $(ui)/resource/resource.xml $(ui)/resource/resource.cpp $(ui)/resource/resource.hpp + install: ifeq ($(USER),root) @echo Please do not run make install as root. diff --git a/bsnes/target-ethos/ethos.cpp b/bsnes/target-ethos/ethos.cpp index 379f87dc3..afb0c7184 100755 --- a/bsnes/target-ethos/ethos.cpp +++ b/bsnes/target-ethos/ethos.cpp @@ -1,5 +1,6 @@ #include "ethos.hpp" #include "bootstrap.cpp" +#include "resource/resource.cpp" Application *application = nullptr; DSP dspaudio; @@ -57,13 +58,8 @@ Application::Application(int argc, char **argv) { pause = false; autopause = false; - char path[PATH_MAX]; - auto unused = ::realpath(argv[0], path); - basepath = dir(path); - unused = ::userpath(path); - userpath = path; - if(Intrinsics::platform() != Intrinsics::Platform::Windows) userpath.append(".config/"); - userpath.append("bsnes/"); + basepath = realpath(argv[0]); + userpath = {nall::configpath(), "bsnes/"}; directory::create(userpath); bootstrap(); @@ -145,6 +141,13 @@ int main(int argc, char **argv) { #if defined(PLATFORM_WINDOWS) utf8_args(argc, argv); #endif + + //convert file to game folder; purify will then invoke bsnes with game folder + if(argc == 2 && !directory::exists(argv[1]) && file::exists(argv[1])) { + invoke("purify", argv[1]); + return 0; + } + new Application(argc, argv); delete application; return 0; diff --git a/bsnes/target-ethos/ethos.hpp b/bsnes/target-ethos/ethos.hpp index e05819570..93937c5db 100755 --- a/bsnes/target-ethos/ethos.hpp +++ b/bsnes/target-ethos/ethos.hpp @@ -4,6 +4,7 @@ #include #include #include +#include #include #include #include @@ -25,6 +26,7 @@ using namespace ruby; #include "general/general.hpp" #include "settings/settings.hpp" #include "tools/tools.hpp" +#include "resource/resource.hpp" Emulator::Interface& system(); diff --git a/bsnes/target-ethos/general/browser.cpp b/bsnes/target-ethos/general/browser.cpp index a385321bf..607eafa67 100755 --- a/bsnes/target-ethos/general/browser.cpp +++ b/bsnes/target-ethos/general/browser.cpp @@ -163,9 +163,9 @@ void Browser::setPath(const string &path, unsigned selection) { if(!filename.wildcard(R"(*.??/)") && !filename.wildcard(R"(*.???/)")) { string name = filename; name.rtrim<1>("/"); - name = {"[ ", name, " ]"}; - filenameList.append(filename); fileList.append(name); + fileList.setImage(filenameList.size(), 0, image(resource::folder, sizeof resource::folder)); + filenameList.append(filename); } } @@ -175,8 +175,9 @@ void Browser::setPath(const string &path, unsigned selection) { if(filename.endswith(suffix)) { string name = filename; name.rtrim<1>(suffix); - filenameList.append(filename); fileList.append(name); + fileList.setImage(filenameList.size(), 0, image(resource::game, sizeof resource::game)); + filenameList.append(filename); } } } diff --git a/bsnes/target-ethos/resource/folder.png b/bsnes/target-ethos/resource/folder.png new file mode 100755 index 0000000000000000000000000000000000000000..472484f11279c3e37a20ddcc8277c516ad246115 GIT binary patch literal 1176 zcmV;J1ZVq+P)1yxd$0C6kuV7bR+PdY00{*lQ*M=l z8i@j0IzB)oK0r!@M1^RfLrAAU7s-kOiqb{G#>6NV#`n5+-j|u38H#(!I(Lo}a#ASx zOOJMTcK3OH^E@-NyCMujUZ>=1js9N%@BwbzxZx|Mem2IuchLhvh}>HH`NM|~zg!tW znx z&Mh?nAq1P7oB6@P!AHRDl>lh1(=5xxrAr$aW3bkq30%yC5Q1v8T0cBI{9=21`_`;~ znVfUlTKn$b$Z5|!&XdlVufDtg z{_MP%0o`cSt6FQ+AChLZ%>LhFqBx(7Z0TsvBM}Qt0W>N;D$@u-XLfnM6&qu8zdxYc z?Gk5}dbNZ#lN;pJ!Lx=t&)ie96SLNlWQH`$!HM|>RxCkQsRXoIEixmh1tqLgcycwb zi*cG$Z~BaeIo7%-3jleZt0)@L?+?)C4XS~Ua}H0Qo97pkgHfu{xh3!=ajLB``OyM^ zF(xaQOH`X1tkudmKnk(E_%A5q9HUf|TZiWfg0jbHk|`m?$pV12HXDt`91j%h^-Jj7 zzS8J3ZHY4jPT)`dls(DlRON!Fldzb9)c1Y7AfQQ^OxX*AOy-!wy2(Ca?8H=Vm#s*g zgTW}ZxpRvE*4kt|9@824R9a=CM3d?1O9;q~MH`3CExDO)%P*OgL>Y$T#1qn6T7pyv zfeadyNs60>X%$s}D(4*iBtcj^SO93Z+hS*D$3(GWaO(K; zWQgp(;tse($HzmPB*O>0?RG5;!*~t=cu^Gn^vj|6Os(Vpw*Sf>yJzIU0$80M96$Ks z>*6&r`!#E~+s$BY?af-y+H^Q6giTsi)!sWzk*lz?LPeE-Uo}T%@-s zQdt!whEz-vJ1kmTj`L?S6+1r3isN|f_r3T0B?JF^h;-oU>gq$5Wj8>jltN00a}H~5 zXkFKZYusNN19n~4eZ0B3`5Nz+jSvZOeQ|M7J@>AkgHN z>rh<$^T)@><@90FtOq5CT`#4isw%Q9LkPji$w}y!WjUBX#lnjvh)t-q##$RHVb^tG z-qLYg&4AZ3&E97aOX8dh40u33%PA&~k|5Q-?|ZDZ;YH+WkHOY;jdN~RhNA$)3kxC0 zvW%*#26OAW4sv);D5XZ59L+#VwFe-j9QeZ+L!RdWtWs)qS)K)up6ApDaVVt*40x&1 zs<;%Zj-f9$vHt$-d(GoIvD@ud1DN_E8c-#KV6)j!mgUG`o6QET^IgQ>!(=g`yQ?JBsgD3{P*Qjq^F>gQvT}u{?*yp zSs0wtxhRUo#nbYe=lKqJ2mA!~DS!%ibANyT`TYF+6HqR$zB2MWr)e655P$CO?!Ex; z0R?;qT%1}CyaiqZTfjU|{1@?ur(|p32k;H}4HJJ(pEoX^0j(=%hrX>3&26~}*fd2cq4$6&{HFnA2O$P@^>+9F2?x;Sc3rJ^dd zX^MoDs7fM1R0XNu+DiG9PZ3d-E)oQ~P*y2vE0qQnH3W&c4TK1qKw{!zFxX%`*kjN3 z?!Emm3tom*%7-55N_XBp@0|ZR=YP)J2mjBqPs*47AjGY`Fy~=yh=+M;KlmuMr?H{o ziI$q0+S9$g{edyxcp5(W!U61o#)#JMESNWMLEEfZ;oQ&=Bk44!`}zj*LGYa)LidB% zlMkZ&J6I75g-)+pzI<_8TU!_@aX`fPS>D>(6!yHo{t>?Ug#g&E)Q@UwYX08Y**UAe zu~8x=CaI~k;t{Qnws&+qv1Ik?TB%CvLSTo6aKpnC zj3J~H#yO00AO!WbwULor?yKLmw)TLv|9Gej?1lv~&pWbg&6?Rwt*shs!5CZ+U@u)F zxOIy&!$Vvhyur$3lICcXacjvshXX8dabRF%G@U;9J!75~#RN^0svOv>)RVO}HScw9 z*wEJ0-mXy!q{JD6y?BxFn>TrXXpqE9+gNq#6#q@c=t++fm6C9Y6FA4*#>U#2iNsR} zw0`Rt==;jR0j+-)Z)n)|m9DNCUL;bC+FIPm2G7CgRq{rb3=NVb6i z%!LbFN~gIJ2{ZrA-N^cSf*?RjiIfs+EknP0gY@3LEKk&7gdk-M7I4myN~d%EH*TCy z2f^AckShCC0KbRXQLRrb?d)9nrL}9L<@Q1dY;P~Yg$tZZr%8W#A?>^OAmee2F+?H} zX3m^REEdBULwLnXyw*8cDf=Ja zxUo4ge||9|*5ZNy^U+6S`}+8Bbd(vJH`DaO3m9Xt))I@w2#3Ry%9qJx$Ye5P&z_~{ z`R7>@3Q-dZaordSC35DoS=)Q{>J@9uy6;1e1kg(567B5*r9dg1F$CS+jC}q%-6JE+ ze)UzFUwjeg97-t?i3GmyW38<$V+_9UQ&UqzZ0S-u4jtmGl-$Tzq!2;O~{YnLzcp|vbJc#y=pbvWnHS`&>%OG%pSyu24e5Q#(xx3sYM z?YFtq*huf#7>!yJDS?olhgQl>YeP3MK;hUiE({KG>Cs17e&h(@dGi49JP*(FCOMw! zeB$yv4=<5m;r{)MtzON4Mn`!>DdJKh#qH*+05G3@M(+4=PWJZ`tY6P#hYus;ah!8V zDG@^4m-DIFkeTSD)^*U9H|)6M}rKg3Jhwvx~18Js^q zXghJ@TOaiI|D|BqEiuNDFIaMg0IvKE=NyGX0i{%CV}Jj9K;1MBOq6mBTj#W*wXP7*_x;M=^E{HR zNvyRcU?2r3A&MlMkg#$YthLi>RP_(SIfu2DWHO1?RaF3JXlSSa7|#ae@`mwTz^$hWDmP + + + + + + diff --git a/bsnes/target-ethos/resource/up.png b/bsnes/target-ethos/resource/up.png new file mode 100755 index 0000000000000000000000000000000000000000..afb307b18c130d44b130c57f64075744d703b791 GIT binary patch literal 1193 zcmV;a1XlZrP)&(@4;J>BJ-*}|DX;Zk|IYy` zHv6y4ynX)KSD${HTk;CtEw8mJ{xg7zEw*w>!L7ThmpvQr4KA|!;pg(L^*>*-DR%e2 z4zTP^X89)P&{L0Wh+nvJisNTKBQOc7maH!DZ17d-Hl|D#z)W;v=?>y1v~_Eizc?)x zx6;t^ElxvPyZ>Op^oPWnSbkf3Q~BcQZhu1qI?=cjt$^hA+5^iMJuzq2opZc~*5iO6 zA~+5C{@fuJEm)j$*R=U%&2#LoiHgGnD^O8u-zuJ6^1{lpHMu96jxdnw!)ciIfMn25 zM{grb?|afe+jQ#wJ4zBwjrID|KLSu*YaTC}I%D@URU6~Kw$;;}Xde_0H5feZ9q6P# z)kE2WmHuz%PFBra%+ba=*F0YQF_)lXYwX@wEdJ^GRh!~1J*VmH|7*-(e_r~9*51=R zy0j)=Jr0*`W#)AQlx|~+y5Q*ZtKP^Dq>l?-zh84-2m9=5zo|NYZvGmZ3za1+3w^am zN_P;SG{D-mn3%I)R#&bsDw;Z7PPd;xRU=VR!~9w>awe)wSVvg#EjHL;Ve-;fNW;7$UN5H%srbEu?9xNZ_*4|opG z6T}0j0WDo;sa#lXTicsw-L~k8-&p64jifbcU=}KOpH@J-WVDMm2Q1Fbfd*3^VlENb-g3A-+i;)r@22i&v z5C{g(OJBy171$)6f^l5zKSx44u{i>gj+Yj9P7wp5gkfm!v3{ZpKn#QfBt}|-VF20o z!yZ!Qn*o$d1LsL-7seMPz1~rVf;vT<;CTWbVag^hfA=0;)P!Vs`hQBd@zMvD&fM+Cvu!5JafOCRK^gfWu=}#OW>H6?(47}7;2otGE zs8J(29b?DeAb_F>f(ns{FbLo>!ZK<72?5wNL3)2jnQAD6xad}xzNS}S%pE@x2L_0? zR4`KDu>cI<4{@yIP&NBCJdbDx$hA$F0do#e