Update to ananke v00r02 release.

byuu says:

This should be basically final now.

Works with all media types (nes, sfc, gb, gbc, gba, bs, st), strips
headers, can use internal or external firmware, imports saves on first
run.

Added a custom file dialog. It seems both GTK+ and Windows XP have
(un)intelligent file sorting, which puts eg "ActRaiser 2 (NA)" before
"ActRaiser (NA)". So, screw 'em.
This commit is contained in:
Tim Allen 2012-12-24 16:48:23 +11:00
parent 019fc1a2c6
commit 85f2e9a6d4
24 changed files with 13615 additions and 6648 deletions

View File

@ -8,14 +8,15 @@ all:
$(cpp) $(flags) -fPIC -o ananke.o -c ananke.cpp
$(cpp) $(flags) -shared -Wl,-soname,libananke.so.1 -o libananke.so ananke.o
resource: force
sourcery resource/resource.bml resource/resource.cpp resource/resource.hpp
clean:
-@$(call delete,*.o)
-@$(call delete,*.so)
install: uninstall
if [ ! -d ~/.config/ananke ]; then mkdir ~/.config/ananke; fi
if [ -d ~/.config/ananke/database ]; then rm -r ~/.config/ananke/database; fi
cp -r database ~/.config/ananke/database
sudo cp libananke.so $(path)/libananke.so.1
sudo ln -s $(path)/libananke.so.1 $(path)/libananke.so

View File

@ -1,11 +1,18 @@
#include <nall/nall.hpp>
#include <nall/beat/patch.hpp>
#include <nall/emulation/famicom.hpp>
#include <nall/emulation/super-famicom.hpp>
#include <nall/emulation/game-boy.hpp>
#include <nall/emulation/game-boy-advance.hpp>
using namespace nall;
#include <phoenix/phoenix.hpp>
using namespace phoenix;
namespace Database {
#include "database/super-famicom.hpp"
};
struct Ananke {
#include "configuration.cpp"
@ -23,40 +30,72 @@ struct Ananke {
//patch.cpp
void applyBeatPatch(vector<uint8_t> &buffer);
//famicom.cpp
void copyFamicomSaves(const string &pathname);
string createFamicomHeuristic(vector<uint8_t> &buffer);
string openFamicom(vector<uint8_t> &buffer);
//super-famicom.cpp
void copySuperFamicomSaves(const string &pathname);
string createSuperFamicomDatabase(vector<uint8_t> &buffer, Markup::Node &document, const string &manifest);
string createSuperFamicomHeuristic(vector<uint8_t> &buffer);
void createSuperFamicomHeuristicFirmware(vector<uint8_t> &buffer, const string &pathname, bool firmware_appended);
string openSuperFamicom(vector<uint8_t> &buffer);
string open(string filename = "") {
if(filename.empty()) filename = DialogWindow::fileOpen(Window::none(), config.path);
if(filename.empty()) return "";
information.path = dir(filename);
information.name = notdir(filename);
config.path = information.path; //remember last used directory
vector<uint8_t> buffer;
if(filename.endswith(".zip")) {
information.archive = filename;
buffer = extractROM();
} else {
buffer = file::read(filename);
}
if(buffer.size() == 0) return ""; //failed to read file
applyBeatPatch(buffer);
if(information.name.endswith(".sfc")) return openSuperFamicom(buffer);
return "";
}
//game-boy.cpp
void copyGameBoySaves(const string &pathname);
string createGameBoyHeuristic(vector<uint8_t> &buffer);
string openGameBoy(vector<uint8_t> &buffer);
//game-boy-advance.cpp
void copyGameBoyAdvanceSaves(const string &pathname);
string createGameBoyAdvanceHeuristic(vector<uint8_t> &buffer);
string openGameBoyAdvance(vector<uint8_t> &buffer);
string open(string filename = "");
};
#include "resource/resource.cpp"
#include "file-dialog.cpp"
#include "archive.cpp"
#include "patch.cpp"
#include "famicom.cpp"
#include "super-famicom.cpp"
#include "game-boy.cpp"
#include "game-boy-advance.cpp"
FileDialog *fileDialog = nullptr;
string Ananke::open(string filename) {
if(filename.empty()) {
if(!fileDialog) fileDialog = new FileDialog;
fileDialog->setPath(config.path);
filename = fileDialog->open();
}
if(filename.empty()) return "";
information.path = dir(filename);
information.name = notdir(filename);
config.path = information.path; //remember last used directory
vector<uint8_t> buffer;
if(filename.endswith(".zip")) {
information.archive = filename;
buffer = extractROM();
} else {
buffer = file::read(filename);
}
if(buffer.size() == 0) return ""; //failed to read file
applyBeatPatch(buffer);
if(information.name.endswith(".fc") || information.name.endswith(".nes")) return openFamicom(buffer);
if(information.name.endswith(".sfc") || information.name.endswith(".smc")) return openSuperFamicom(buffer);
if(information.name.endswith(".gb") || information.name.endswith(".gbc")) return openGameBoy(buffer);
if(information.name.endswith(".gba")) return openGameBoyAdvance(buffer);
return "";
}
extern "C" string ananke_browse(const string &filename) {
Ananke ananke;

View File

@ -2,7 +2,12 @@ vector<uint8_t> Ananke::extractROM() {
unzip archive;
if(archive.open(information.archive)) {
for(auto &file : archive.file) {
if(file.name.endswith(".sfc")) {
if(
file.name.endswith(".fc") || file.name.endswith(".nes")
|| file.name.endswith(".sfc") || file.name.endswith(".smc")
|| file.name.endswith(".gb") || file.name.endswith(".gbc")
|| file.name.endswith(".gba")
) {
information.name = notdir(file.name);
return archive.extract(file);
}

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

31
ananke/famicom.cpp Normal file
View File

@ -0,0 +1,31 @@
void Ananke::copyFamicomSaves(const string &pathname) {
if(!file::exists({pathname, "save.ram"})) {
if(file::exists({information.path, nall::basename(information.name), ".sav"})) {
file::copy({information.path, nall::basename(information.name), ".srm"}, {pathname, "save.ram"});
}
}
}
string Ananke::createFamicomHeuristic(vector<uint8_t> &buffer) {
string pathname = {
userpath(), "Emulation/Famicom/",
nall::basename(information.name),
" (!).fc/"
};
directory::create(pathname);
FamicomCartridge info(buffer.data(), buffer.size());
string markup = info.markup();
if(!information.manifest.empty()) markup = information.manifest; //override with embedded beat manifest, if one exists
file::write({pathname, "manifest.bml"}, markup);
file::write({pathname, "program.rom"}, buffer.data() + 16, info.prgrom);
if(info.chrrom > 0) file::write({pathname, "character.rom"}, buffer.data() + 16 + info.prgrom, info.chrrom);
copyFamicomSaves(pathname);
return pathname;
}
string Ananke::openFamicom(vector<uint8_t> &buffer) {
return createFamicomHeuristic(buffer);
}

109
ananke/file-dialog.cpp Normal file
View File

@ -0,0 +1,109 @@
struct FileDialog : Window {
VerticalLayout layout;
HorizontalLayout pathLayout;
LineEdit pathEdit;
Button homeButton;
Button upButton;
ListView fileList;
HorizontalLayout controlLayout;
Widget spacer;
Button openButton;
string open() {
setModal();
setVisible();
fileList.setFocused();
filename = "";
dialogActive = true;
while(dialogActive) {
OS::processEvents();
if(Keyboard::pressed(Keyboard::Scancode::Escape)) onClose();
}
return filename;
}
void setPath(const string &path) {
pathname = string{path}.transform("\\", "/");
if(pathname.empty()) pathname = userpath();
if(pathname.endswith("/") == false) pathname.append("/");
pathEdit.setText(pathname);
fileList.reset();
filenameList.reset();
lstring folders = directory::ifolders(pathname);
for(auto &folder : folders) {
fileList.append(string{folder}.rtrim<1>("/"));
fileList.setImage(filenameList.size(), 0, {resource::folder, sizeof resource::folder});
filenameList.append({pathname, folder});
}
lstring files = directory::ifiles(pathname);
for(auto &file : files) {
fileList.append(file);
fileList.setImage(filenameList.size(), 0, {resource::file, sizeof resource::file});
filenameList.append({pathname, file});
}
fileList.setSelection(0);
fileList.setSelected();
fileList.setFocused();
}
FileDialog() {
setGeometry({64, 64, 480, 600});
setTitle("Load Image");
layout.setMargin(5);
homeButton.setImage({resource::home, sizeof resource::home});
upButton.setImage({resource::up, sizeof resource::up});
openButton.setText("Open");
append(layout);
layout.append(pathLayout, {~0, 0}, 5);
pathLayout.append(pathEdit, {~0, 0}, 5);
pathLayout.append(homeButton, {28, 28}, 5);
pathLayout.append(upButton, {28, 28});
layout.append(fileList, {~0, ~0}, 5);
layout.append(controlLayout, {~0, 0});
controlLayout.append(spacer, {~0, 0});
controlLayout.append(openButton, {80, 0});
pathEdit.onActivate = [&] {
string path = pathEdit.text();
setPath(path);
};
homeButton.onActivate = [&] {
setPath(userpath());
};
upButton.onActivate = [&] {
setPath(parentdir(pathname));
};
fileList.onActivate = openButton.onActivate = [&] {
if(fileList.selected() == false) return;
string name = filenameList(fileList.selection());
if(name.empty()) return;
if(name.endswith("/")) return setPath(name);
filename = name;
onClose();
};
onClose = [&] {
dialogActive = false;
setModal(false);
setVisible(false);
};
}
private:
bool dialogActive;
string pathname;
string filename;
lstring filenameList;
};

View File

@ -0,0 +1,36 @@
void Ananke::copyGameBoyAdvanceSaves(const string &pathname) {
if(!file::exists({pathname, "save.ram"})) {
if(file::exists({information.path, nall::basename(information.name), ".sav"})) {
file::copy({information.path, nall::basename(information.name), ".sav"}, {pathname, "save.ram"});
}
}
if(!file::exists({pathname, "rtc.ram"})) {
if(file::exists({information.path, nall::basename(information.name), ".rtc"})) {
file::copy({information.path, nall::basename(information.name), ".rtc"}, {pathname, "rtc.ram"});
}
}
}
string Ananke::createGameBoyAdvanceHeuristic(vector<uint8_t> &buffer) {
string pathname = {
userpath(), "Emulation/Game Boy Advance/",
nall::basename(information.name),
" (!).gba/"
};
directory::create(pathname);
GameBoyAdvanceCartridge info(buffer.data(), buffer.size());
string markup = info.markup;
if(!information.manifest.empty()) markup = information.manifest; //override with embedded beat manifest, if one exists
file::write({pathname, "manifest.bml"}, markup);
file::write({pathname, "program.rom"}, buffer);
copyGameBoyAdvanceSaves(pathname);
return pathname;
}
string Ananke::openGameBoyAdvance(vector<uint8_t> &buffer) {
return createGameBoyAdvanceHeuristic(buffer);
}

38
ananke/game-boy.cpp Normal file
View File

@ -0,0 +1,38 @@
void Ananke::copyGameBoySaves(const string &pathname) {
if(!file::exists({pathname, "save.ram"})) {
if(file::exists({information.path, nall::basename(information.name), ".sav"})) {
file::copy({information.path, nall::basename(information.name), ".sav"}, {pathname, "save.ram"});
}
}
if(!file::exists({pathname, "rtc.ram"})) {
if(file::exists({information.path, nall::basename(information.name), ".rtc"})) {
file::copy({information.path, nall::basename(information.name), ".rtc"}, {pathname, "rtc.ram"});
}
}
}
string Ananke::createGameBoyHeuristic(vector<uint8_t> &buffer) {
GameBoyCartridge info(buffer.data(), buffer.size());
string pathname = {
userpath(),
"Emulation/Game Boy/",
nall::basename(information.name),
" (!).", (info.info.cgb ? "gbc" : "gb"), "/"
};
directory::create(pathname);
string markup = info.markup;
if(!information.manifest.empty()) markup = information.manifest; //override with embedded beat manifest, if one exists
file::write({pathname, "manifest.bml"}, info.markup);
file::write({pathname, "program.rom"}, buffer);
copyGameBoySaves(pathname);
return pathname;
}
string Ananke::openGameBoy(vector<uint8_t> &buffer) {
return createGameBoyHeuristic(buffer);
}

View File

@ -21,9 +21,53 @@ struct directory {
static bool create(const string &pathname, unsigned permissions = 0755); //recursive
static bool remove(const string &pathname); //recursive
static bool exists(const string &pathname);
static lstring folders(const string &pathname, const string &pattern = "*");
static lstring files(const string &pathname, const string &pattern = "*");
static lstring contents(const string &pathname, const string &pattern = "*");
static lstring folders(const string &pathname, const string &pattern = "*") {
lstring folders = directory::ufolders(pathname, pattern);
folders.sort();
return folders;
}
static lstring files(const string &pathname, const string &pattern = "*") {
lstring files = directory::ufiles(pathname, pattern);
files.sort();
return files;
}
static lstring contents(const string &pathname, const string &pattern = "*") {
lstring folders = directory::ufolders(pathname); //pattern search of contents should only filter files
lstring files = directory::ufiles(pathname, pattern);
folders.sort();
files.sort();
for(auto &file : files) folders.append(file);
return folders;
}
static lstring ifolders(const string &pathname, const string &pattern = "*") {
lstring folders = ufolders(pathname, pattern);
folders.isort();
return folders;
}
static lstring ifiles(const string &pathname, const string &pattern = "*") {
lstring files = ufiles(pathname, pattern);
files.isort();
return files;
}
static lstring icontents(const string &pathname, const string &pattern = "*") {
lstring folders = directory::ufolders(pathname); //pattern search of contents should only filter files
lstring files = directory::ufiles(pathname, pattern);
folders.isort();
files.isort();
for(auto &file : files) folders.append(file);
return folders;
}
private:
//internal functions; these return unsorted lists
static lstring ufolders(const string &pathname, const string &pattern = "*");
static lstring ufiles(const string &pathname, const string &pattern = "*");
};
#if defined(PLATFORM_WINDOWS)
@ -55,7 +99,7 @@ struct directory {
return (result & FILE_ATTRIBUTE_DIRECTORY);
}
inline lstring directory::folders(const string &pathname, const string &pattern) {
inline lstring directory::ufolders(const string &pathname, const string &pattern) {
lstring list;
string path = pathname;
path.transform("/", "\\");
@ -81,12 +125,11 @@ struct directory {
}
FindClose(handle);
}
if(list.size() > 0) list.sort();
for(auto &name : list) name.append("/"); //must append after sorting
return list;
}
inline lstring directory::files(const string &pathname, const string &pattern) {
inline lstring directory::ufiles(const string &pathname, const string &pattern) {
lstring list;
string path = pathname;
path.transform("/", "\\");
@ -108,16 +151,8 @@ struct directory {
}
FindClose(handle);
}
if(list.size() > 0) list.sort();
return list;
}
inline lstring directory::contents(const string &pathname, const string &pattern) {
lstring folders = directory::folders(pathname); //pattern search of contents() should only filter files
lstring files = directory::files(pathname, pattern);
for(auto &file : files) folders.append(file);
return folders;
}
#else
inline bool directory::create(const string &pathname, unsigned permissions) {
string path;
@ -146,7 +181,7 @@ struct directory {
return true;
}
inline lstring directory::folders(const string &pathname, const string &pattern) {
inline lstring directory::ufolders(const string &pathname, const string &pattern) {
lstring list;
DIR *dp;
struct dirent *ep;
@ -161,12 +196,11 @@ struct directory {
}
closedir(dp);
}
if(list.size() > 0) list.sort();
for(auto &name : list) name.append("/"); //must append after sorting
return list;
}
inline lstring directory::files(const string &pathname, const string &pattern) {
inline lstring directory::ufiles(const string &pathname, const string &pattern) {
lstring list;
DIR *dp;
struct dirent *ep;
@ -181,16 +215,8 @@ struct directory {
}
closedir(dp);
}
if(list.size() > 0) list.sort();
return list;
}
inline lstring directory::contents(const string &pathname, const string &pattern) {
lstring folders = directory::folders(pathname); //pattern search of contents() should only filter files
lstring files = directory::files(pathname, pattern);
for(auto &file : files) folders.append(file);
return folders;
}
#endif
}

View File

@ -27,8 +27,6 @@ FamicomCartridge::FamicomCartridge(const uint8_t *data, unsigned size) {
if(data[2] != 'S') return;
if(data[3] != 26) return;
markup.append("<?xml version='1.0' encoding='UTF-8'?>\n");
mapper = ((data[7] >> 4) << 4) | (data[6] >> 4);
mirror = ((data[6] & 0x08) >> 2) | (data[6] & 0x01);
prgrom = data[4] * 0x4000;
@ -36,145 +34,138 @@ FamicomCartridge::FamicomCartridge(const uint8_t *data, unsigned size) {
prgram = 0u;
chrram = chrrom == 0u ? 8192u : 0u;
markup.append("<cartridge sha256='", sha256(data, size), "'>\n");
markup.append("cartridge\n");
switch(mapper) {
default:
markup.append(" <board type='NES-NROM-256'/>\n");
markup.append(" <mirror mode='", mirror == 0 ? "horizontal" : "vertical", "'/>\n");
markup.append(" board type=NES-NROM-256\n");
markup.append(" mirror mode=", mirror == 0 ? "horizontal" : "vertical", "\n");
break;
case 1:
markup.append(" <board type='NES-SXROM'/>\n");
markup.append(" <chip type='MMC1B2'/>\n");
markup.append(" board type=NES-SXROM\n");
markup.append(" chip type=MMC1B2\n");
prgram = 8192;
break;
case 2:
markup.append(" <board type='NES-UOROM'/>\n");
markup.append(" <mirror mode='", mirror == 0 ? "horizontal" : "vertical", "'/>\n");
markup.append(" board type=NES-UOROM\n");
markup.append(" mirror mode=", mirror == 0 ? "horizontal" : "vertical", "\n");
break;
case 3:
markup.append(" <board type='NES-CNROM'/>\n");
markup.append(" <mirror mode='", mirror == 0 ? "horizontal" : "vertical", "'/>\n");
markup.append(" board type=NES-CNROM\n");
markup.append(" mirror mode=", mirror == 0 ? "horizontal" : "vertical", "\n");
break;
case 4:
//MMC3
markup.append(" <board type='NES-TLROM'/>\n");
markup.append(" <chip type='MMC3B'/>\n");
markup.append(" board type=NES-TLROM\n");
markup.append(" chip type=MMC3B\n");
prgram = 8192;
//MMC6
//markup.append(" <board type='NES-HKROM'/>\n");
//markup.append(" <chip type='MMC6'/>\n");
//markup.append(" board type=NES-HKROM\n");
//markup.append(" chip type=MMC6n");
//prgram = 1024;
break;
case 5:
markup.append(" <board type='NES-ELROM'/>\n");
markup.append(" <chip type='MMC5'/>\n");
markup.append(" board type=NES-ELROM\n");
markup.append(" chip type=MMC5\n");
prgram = 65536;
break;
case 7:
markup.append(" <board type='NES-AOROM'/>\n");
markup.append(" board type=NES-AOROM\n");
break;
case 9:
markup.append(" <board type='NES-PNROM'/>\n");
markup.append(" <chip type='MMC2'/>\n");
markup.append(" board type=NES-PNROM\n");
markup.append(" chip type=MMC2\n");
prgram = 8192;
break;
case 10:
markup.append(" <board type='NES-FKROM'/>\n");
markup.append(" <chip type='MMC4'/>\n");
markup.append(" board type=NES-FKROM\n");
markup.append(" chip type=MMC4\n");
prgram = 8192;
break;
case 16:
markup.append(" <board type='BANDAI-FCG'/>\n");
markup.append(" <chip type='LZ93D50'/>\n");
markup.append(" board type=BANDAI-FCG\n");
markup.append(" chip type=LZ93D50\n");
break;
case 21:
case 23:
case 25:
//VRC4
markup.append(" <board type='KONAMI-VRC-4'/>\n");
markup.append(" <chip type='VRC4'>\n");
markup.append(" <pinout a0='1' a1='0'/>\n");
markup.append(" </chip>\n");
markup.append(" board type=KONAMI-VRC-4\n");
markup.append(" chip type=VRC4\n");
markup.append(" pinout a0=1 a1=0\n");
prgram = 8192;
break;
case 22:
//VRC2
markup.append(" <board type='KONAMI-VRC-2'/>\n");
markup.append(" <chip type='VRC2'>\n");
markup.append(" <pinout a0='0' a1='1'/>\n");
markup.append(" </chip>\n");
markup.append(" board type=KONAMI-VRC-2\n");
markup.append(" chip type=VRC2\n");
markup.append(" pinout a0=0 a1=1\n");
break;
case 24:
markup.append(" <board type='KONAMI-VRC-6'/>\n");
markup.append(" <chip type='VRC6'/>\n");
markup.append(" board type=KONAMI-VRC-6\n");
markup.append(" chip type=VRC6\n");
break;
case 26:
markup.append(" <board type='KONAMI-VRC-6'/>\n");
markup.append(" <chip type='VRC6'/>\n");
markup.append(" board type=KONAMI-VRC-6\n");
markup.append(" chip type=VRC6\n");
prgram = 8192;
break;
case 34:
markup.append(" <board type='NES-BNROM'/>\n");
markup.append(" <mirror mode='", mirror == 0 ? "horizontal" : "vertical", "'/>\n");
markup.append(" board type=NES-BNROM\n");
markup.append(" mirror mode=", mirror == 0 ? "horizontal" : "vertical", "\n");
break;
case 66:
markup.append(" <board type='NES-GNROM'/>\n");
markup.append(" <mirror mode='", mirror == 0 ? "horizontal" : "vertical", "'/>\n");
markup.append(" board type=NES-GNROM\n");
markup.append(" mirror mode=", mirror == 0 ? "horizontal" : "vertical", "\n");
break;
case 69:
markup.append(" <board type='SUNSOFT-5B'/>\n");
markup.append(" <chip type='5B'/>\n");
markup.append(" board type=SUNSOFT-5B\n");
markup.append(" chip type=5B\n");
prgram = 8192;
break;
case 73:
markup.append(" <board type='KONAMI-VRC-3'/>\n");
markup.append(" <chip type='VRC3'/>\n");
markup.append(" <mirror mode='", mirror == 0 ? "horizontal" : "vertical", "'/>\n");
markup.append(" board type=KONAMI-VRC-3\n");
markup.append(" chip type=VRC3\n");
markup.append(" mirror mode=", mirror == 0 ? "horizontal" : "vertical", "\n");
prgram = 8192;
break;
case 75:
markup.append(" <board type='KONAMI-VRC-1'/>\n");
markup.append(" <chip type='VRC1'/>\n");
markup.append(" board type=KONAMI-VRC-1\n");
markup.append(" chip type=VRC1\n");
break;
case 85:
markup.append(" <board type='KONAMI-VRC-7/'>\n");
markup.append(" <chip type='VRC7'/>\n");
markup.append(" board type=KONAMI-VRC-7\n");
markup.append(" chip type=VRC7\n");
prgram = 8192;
break;
}
markup.append(" <prg>\n");
if(prgrom) markup.append(" <rom name='program.rom' size='0x", hex(prgrom), "'/>\n");
if(prgram) markup.append(" <ram name='save.ram' size='0x", hex(prgram), "'/>\n");
markup.append(" </prg>\n");
markup.append(" prg\n");
if(prgrom) markup.append(" rom name=program.rom size=0x", hex(prgrom), "\n");
if(prgram) markup.append(" ram name=save.ram size=0x", hex(prgram), "\n");
markup.append(" <chr>\n");
if(chrrom) markup.append(" <rom name='character.rom' size='0x", hex(chrrom), "'/>\n");
if(chrram) markup.append(" <ram size='0x", hex(chrram), "'/>\n");
markup.append(" </chr>\n");
markup.append("</cartridge>\n");
markup.transform("'", "\"");
markup.append(" chr\n");
if(chrrom) markup.append(" rom name=character.rom size=0x", hex(chrrom), "\n");
if(chrram) markup.append(" ram size=0x", hex(chrram), "\n");
}
}

View File

@ -46,21 +46,16 @@ GameBoyAdvanceCartridge::GameBoyAdvanceCartridge(const uint8_t *data, unsigned s
identifiers = list.concatenate(",");
markup = "";
markup.append("<?xml version='1.0' encoding='UTF-8'?>\n");
markup.append("<cartridge sha256='", sha256(data, size), "'>\n");
markup.append(" <rom name='program.rom' size='0x", hex(size), "'/>\n");
markup.append("cartridge\n");
markup.append(" rom name=program.rom size=0x", hex(size), "\n");
if(0);
else if(identifiers.beginswith("SRAM_V" )) markup.append(" <ram name='save.ram' type='SRAM' size='0x8000'/>\n");
else if(identifiers.beginswith("SRAM_F_V" )) markup.append(" <ram name='save.ram' type='FRAM' size='0x8000'/>\n");
else if(identifiers.beginswith("EEPROM_V" )) markup.append(" <ram name='save.ram' type='EEPROM' size='0x0'/>\n");
else if(identifiers.beginswith("FLASH_V" )) markup.append(" <ram name='save.ram' type='FlashROM' size='0x10000'/>\n");
else if(identifiers.beginswith("FLASH512_V")) markup.append(" <ram name='save.ram' type='FlashROM' size='0x10000'/>\n");
else if(identifiers.beginswith("FLASH1M_V" )) markup.append(" <ram name='save.ram' type='FlashROM' size='0x20000'/>\n");
if(identifiers.empty() == false) markup.append(" <!-- detected: ", identifiers, " -->\n");
markup.append("</cartridge>\n");
markup.transform("'", "\"");
else if(identifiers.beginswith("SRAM_V" )) markup.append(" ram name=save.ram type=SRAM size=0x8000\n");
else if(identifiers.beginswith("SRAM_F_V" )) markup.append(" ram name=save.ram type=FRAM size=0x8000\n");
else if(identifiers.beginswith("EEPROM_V" )) markup.append(" ram name=save.ram type=EEPROM size=0x0\n");
else if(identifiers.beginswith("FLASH_V" )) markup.append(" ram name=save.ram type=FlashROM size=0x10000\n");
else if(identifiers.beginswith("FLASH512_V")) markup.append(" ram name=save.ram type=FlashROM size=0x10000\n");
else if(identifiers.beginswith("FLASH1M_V" )) markup.append(" ram name=save.ram type=FlashROM size=0x20000\n");
//if(identifiers.empty() == false) markup.append(" #detected: ", identifiers, "\n");
}
}

View File

@ -108,13 +108,11 @@ GameBoyCartridge::GameBoyCartridge(uint8_t *romdata, unsigned romsize) {
if(info.mapper == "MBC2") info.ramsize = 512; //512 x 4-bit
markup = "<?xml version='1.0' encoding='UTF-8'?>\n";
markup.append("<cartridge>\n");
markup.append(" <board type='", info.mapper, "'/>\n");
markup.append(" <rom name='program.rom' size='0x", hex(romsize), "'/>\n");
if(info.ramsize > 0) markup.append(" <ram name='save.ram' size='0x", hex(info.ramsize), "'/>\n");
markup.append("</cartridge>\n");
markup.transform("'", "\"");
markup = "";
markup.append("cartridge\n");
markup.append(" board type=", info.mapper, "\n");
markup.append(" rom name=program.rom size=0x", hex(romsize), "\n");
if(info.ramsize > 0) markup.append(" ram name=save.ram size=0x", hex(info.ramsize), "\n");
}
}

View File

@ -76,10 +76,11 @@ struct SuperFamicomCartridge {
DSP1HiROM,
};
bool loaded; //is a base cartridge inserted?
unsigned crc32; //crc32 of all cartridges (base+slot(s))
bool loaded; //is a base cartridge inserted?
unsigned crc32; //crc32 of all cartridges (base+slot(s))
unsigned rom_size;
unsigned ram_size;
bool firmware_appended; //true if firmware is appended to end of ROM data
Mode mode;
Type type;
@ -106,6 +107,8 @@ struct SuperFamicomCartridge {
};
SuperFamicomCartridge::SuperFamicomCartridge(const uint8_t *data, unsigned size) {
firmware_appended = false;
//skip copier header
if((size & 0x7fff) == 512) data += 512, size -= 512;
@ -122,35 +125,49 @@ SuperFamicomCartridge::SuperFamicomCartridge(const uint8_t *data, unsigned size)
const char *range = (rom_size > 0x200000) || (ram_size > 32 * 1024) ? "0000-7fff" : "0000-ffff";
markup.append("cartridge region=", region == NTSC ? "NTSC" : "PAL", "\n");
if(type == TypeSuperGameBoy1Bios || type == TypeSuperGameBoy2Bios) markup.append(
" rom name=program.rom size=0x", hex(rom_size), "\n"
" map id=rom address=00-7f,80-ff:8000-ffff\n"
" icd2 revision=1\n"
" rom name=boot.rom size=0x100\n"
" map id=io address=00-3f,80-bf:6000-7fff\n"
);
if(type == TypeSuperGameBoy1Bios || type == TypeSuperGameBoy2Bios) {
markup.append(
" rom name=program.rom size=0x", hex(rom_size), "\n"
" map id=rom address=00-7f,80-ff:8000-ffff\n"
" icd2 revision=1\n"
" rom name=boot.rom size=0x100\n"
" map id=io address=00-3f,80-bf:6000-7fff\n"
);
if((rom_size & 0x7fff) == 0x100) {
firmware_appended = true;
rom_size -= 0x100;
}
}
else if(has_cx4) markup.append(
" hitachidsp model=HG51B169 frequency=20000000\n"
" rom id=program name=program.rom size=0x", hex(rom_size), "\n"
" rom id=data name=cx4.data.rom size=0xc00\n"
" ram id=data size=0xc00\n"
" map id=io address=00-3f,80-bf:6000-7fff\n"
" map id=rom address=00-7f,80-ff:8000-ffff mask=0x8000\n"
" map id=ram address=70-77:0000-7fff\n"
);
else if(has_cx4) {
markup.append(
" hitachidsp model=HG51B169 frequency=20000000\n"
" rom id=program name=program.rom size=0x", hex(rom_size), "\n"
" rom id=data name=cx4.data.rom size=0xc00\n"
" ram id=data size=0xc00\n"
" map id=io address=00-3f,80-bf:6000-7fff\n"
" map id=rom address=00-7f,80-ff:8000-ffff mask=0x8000\n"
" map id=ram address=70-77:0000-7fff\n"
);
if((rom_size & 0x7fff) == 0xc00) {
firmware_appended = true;
rom_size -= 0xc00;
}
}
else if(has_spc7110) markup.append(
" spc7110\n"
" rom id=program name=program.rom size=0x100000\n"
" rom id=data name=data.rom size=0x", hex(rom_size - 0x100000), "\n"
" ram name=save.ram size=0x", hex(ram_size), "\n"
" map id=io address=00-3f,80-bf:4800-483f\n"
" map id=io address=50:0000-ffff\n"
" map id=rom address=00-3f,80-bf:8000-ffff\n"
" map id=rom address=c0-ff:0000-ffff\n"
" map id=ram address=00-3f,80-bf:6000-7fff mask=0xe000\n"
);
else if(has_spc7110) {
markup.append(
" spc7110\n"
" rom id=program name=program.rom size=0x100000\n"
" rom id=data name=data.rom size=0x", hex(rom_size - 0x100000), "\n"
" ram name=save.ram size=0x", hex(ram_size), "\n"
" map id=io address=00-3f,80-bf:4800-483f\n"
" map id=io address=50:0000-ffff\n"
" map id=rom address=00-3f,80-bf:8000-ffff\n"
" map id=rom address=c0-ff:0000-ffff\n"
" map id=ram address=00-3f,80-bf:6000-7fff mask=0xe000\n"
);
}
else if(has_sdd1) {
markup.append(
@ -280,69 +297,83 @@ SuperFamicomCartridge::SuperFamicomCartridge(const uint8_t *data, unsigned size)
);
}
else if(mapper == BSCLoROM) markup.append(
" rom name=program.rom size=0x", hex(rom_size), "\n"
" ram name=save.ram size=0x", hex(ram_size), "\n"
" map id=rom address=00-1f:8000-ffff offset=0x000000 mask=0x8000\n"
" map id=rom address=20-3f:8000-ffff offset=0x100000 mask=0x8000\n"
" map id=rom address=80-9f:8000-ffff offset=0x200000 mask=0x8000\n"
" map id=rom address=a0-bf:8000-ffff offset=0x100000 mask=0x8000\n"
" map id=ram address=70-7f,f0-ff:0000-7fff\n"
" bsxslot\n"
" map id=rom address=c0-ef:0000-ffff\n"
);
else if(mapper == BSCLoROM) {
markup.append(
" rom name=program.rom size=0x", hex(rom_size), "\n"
" ram name=save.ram size=0x", hex(ram_size), "\n"
" map id=rom address=00-1f:8000-ffff offset=0x000000 mask=0x8000\n"
" map id=rom address=20-3f:8000-ffff offset=0x100000 mask=0x8000\n"
" map id=rom address=80-9f:8000-ffff offset=0x200000 mask=0x8000\n"
" map id=rom address=a0-bf:8000-ffff offset=0x100000 mask=0x8000\n"
" map id=ram address=70-7f,f0-ff:0000-7fff\n"
" bsxslot\n"
" map id=rom address=c0-ef:0000-ffff\n"
);
}
else if(mapper == BSCHiROM) markup.append(
" rom name=program.rom size=0x", hex(rom_size), "\n"
" ram name=save.ram size=0x", hex(ram_size), "\n"
" map id=rom address=00-1f,80-9f:8000-ffff\n"
" map id=rom address=40-5f,c0-df:0000-ffff\n"
" map id=ram address=20-3f,a0-bf:6000-7fff\n"
" bsxslot\n"
" map id=rom address=20-3f,a0-bf:8000-ffff\n"
" map id=rom address=60-7f,e0-ff:0000-ffff\n"
);
else if(mapper == BSCHiROM) {
markup.append(
" rom name=program.rom size=0x", hex(rom_size), "\n"
" ram name=save.ram size=0x", hex(ram_size), "\n"
" map id=rom address=00-1f,80-9f:8000-ffff\n"
" map id=rom address=40-5f,c0-df:0000-ffff\n"
" map id=ram address=20-3f,a0-bf:6000-7fff\n"
" bsxslot\n"
" map id=rom address=20-3f,a0-bf:8000-ffff\n"
" map id=rom address=60-7f,e0-ff:0000-ffff\n"
);
}
else if(mapper == BSXROM) markup.append(
" bsx\n"
" rom name=program.rom size=0x", hex(rom_size), "\n"
" ram id=save name=save.ram size=0x", hex(ram_size), "\n"
" ram id=download name=bsx.ram size=0x40000\n"
" map id=io address=00-3f,80-bf:5000-5fff\n"
" map id=rom address=00-3f,80-bf:8000-ffff\n"
" map id=rom address=40-7f,c0-ff:0000-ffff\n"
" map id=ram address=20-3f:6000-7fff\n"
);
else if(mapper == BSXROM) {
markup.append(
" bsx\n"
" rom name=program.rom size=0x", hex(rom_size), "\n"
" ram id=save name=save.ram size=0x", hex(ram_size), "\n"
" ram id=download name=bsx.ram size=0x40000\n"
" map id=io address=00-3f,80-bf:5000-5fff\n"
" map id=rom address=00-3f,80-bf:8000-ffff\n"
" map id=rom address=40-7f,c0-ff:0000-ffff\n"
" map id=ram address=20-3f:6000-7fff\n"
);
}
else if(mapper == STROM) markup.append(
" rom name=program.rom size=0x", hex(rom_size), "\n"
" map id=rom address='00-1f,80-9f:8000-ffff mask=0x8000\n"
" sufamiturbo\n"
" slot id=A\n"
" map id=rom address=20-3f,a0-bf:8000-ffff mask=0x8000\n"
" map id=ram address=60-63,e0-e3:8000-ffff\n"
" slot id=B\n"
" map id=rom address=40-5f,c0-df:8000-ffff mask=0x8000\n"
" map id=ram address=70-73,f0-f3:8000-ffff\n"
);
else if(mapper == STROM) {
markup.append(
" rom name=program.rom size=0x", hex(rom_size), "\n"
" map id=rom address='00-1f,80-9f:8000-ffff mask=0x8000\n"
" sufamiturbo\n"
" slot id=A\n"
" map id=rom address=20-3f,a0-bf:8000-ffff mask=0x8000\n"
" map id=ram address=60-63,e0-e3:8000-ffff\n"
" slot id=B\n"
" map id=rom address=40-5f,c0-df:8000-ffff mask=0x8000\n"
" map id=ram address=70-73,f0-f3:8000-ffff\n"
);
}
if(has_spc7110rtc) markup.append(
" epsonrtc\n"
" ram name=rtc.ram size=0x10\n"
" map id=io address=00-3f,80-bf:4840-4842\n"
);
if(has_spc7110rtc) {
markup.append(
" epsonrtc\n"
" ram name=rtc.ram size=0x10\n"
" map id=io address=00-3f,80-bf:4840-4842\n"
);
}
if(has_srtc) markup.append(
" sharprtc\n"
" ram name=rtc.ram size=0x10\n"
" map id=io address=00-3f,80-bf:2800-2801\n"
);
if(has_srtc) {
markup.append(
" sharprtc\n"
" ram name=rtc.ram size=0x10\n"
" map id=io address=00-3f,80-bf:2800-2801\n"
);
}
if(has_obc1) markup.append(
" obc1\n"
" ram name=save.ram size=0x2000\n"
" map id=io address=00-3f,80-bf:6000-7fff\n"
);
if(has_obc1) {
markup.append(
" obc1\n"
" ram name=save.ram size=0x2000\n"
" map id=io address=00-3f,80-bf:6000-7fff\n"
);
}
if(has_dsp1) {
markup.append(
@ -360,57 +391,97 @@ SuperFamicomCartridge::SuperFamicomCartridge(const uint8_t *data, unsigned size)
if(dsp1_mapper == DSP1HiROM) markup.append(
" map id=io address=00-1f,80-9f:6000-7fff select=0x1000\n"
);
if((size & 0x7fff) == 0x2000) {
firmware_appended = true;
rom_size -= 0x2000;
}
}
if(has_dsp2) markup.append(
" necdsp model=uPD7725 frequency=8000000\n"
" rom id=program name=dsp2.program.rom size=0x1800\n"
" rom id=data name=dsp2.data.rom size=0x800\n"
" ram id=data size=0x200\n"
" map id=io address=20-3f,a0-bf:8000-ffff select=0x4000\n"
);
if(has_dsp2) {
markup.append(
" necdsp model=uPD7725 frequency=8000000\n"
" rom id=program name=dsp2.program.rom size=0x1800\n"
" rom id=data name=dsp2.data.rom size=0x800\n"
" ram id=data size=0x200\n"
" map id=io address=20-3f,a0-bf:8000-ffff select=0x4000\n"
);
if((size & 0x7fff) == 0x2000) {
firmware_appended = true;
rom_size -= 0x2000;
}
}
if(has_dsp3) markup.append(
" necdsp model=uPD7725 frequency=8000000\n"
" rom id=program name=dsp3.program.rom size=0x1800\n"
" rom id=data name=dsp3.data.rom size=0x800\n"
" ram id=data size=0x200\n"
" map id=io address=20-3f,a0-bf:8000-ffff select=0x4000\n"
);
if(has_dsp3) {
markup.append(
" necdsp model=uPD7725 frequency=8000000\n"
" rom id=program name=dsp3.program.rom size=0x1800\n"
" rom id=data name=dsp3.data.rom size=0x800\n"
" ram id=data size=0x200\n"
" map id=io address=20-3f,a0-bf:8000-ffff select=0x4000\n"
);
if((size & 0x7fff) == 0x2000) {
firmware_appended = true;
rom_size -= 0x2000;
}
}
if(has_dsp4) markup.append(
" necdsp model=uPD7725 frequency=8000000\n"
" rom id=program name=dsp4.program.rom size=0x1800\n"
" rom id=data name=dsp4.data.rom size=0x800\n"
" ram id=data size=0x200\n"
" map address=30-3f,b0-bf:8000-ffff select=0x4000\n"
);
if(has_dsp4) {
markup.append(
" necdsp model=uPD7725 frequency=8000000\n"
" rom id=program name=dsp4.program.rom size=0x1800\n"
" rom id=data name=dsp4.data.rom size=0x800\n"
" ram id=data size=0x200\n"
" map address=30-3f,b0-bf:8000-ffff select=0x4000\n"
);
if((size & 0x7fff) == 0x2000) {
firmware_appended = true;
rom_size -= 0x2000;
}
}
if(has_st010) markup.append(
" necdsp model=uPD96050 frequency=11000000\n"
" rom id=program name=st010.program.rom size=0xc000\n"
" rom id=data name=st010.data.rom size=0x1000\n"
" ram id=data name=save.ram size=0x1000\n"
" map id=io address=60-67,e0-e7:0000-3fff select=0x0001\n"
" map id=ram address=68-6f,e8-ef:0000-7fff\n"
);
if(has_st010) {
markup.append(
" necdsp model=uPD96050 frequency=11000000\n"
" rom id=program name=st010.program.rom size=0xc000\n"
" rom id=data name=st010.data.rom size=0x1000\n"
" ram id=data name=save.ram size=0x1000\n"
" map id=io address=60-67,e0-e7:0000-3fff select=0x0001\n"
" map id=ram address=68-6f,e8-ef:0000-7fff\n"
);
if((size & 0xffff) == 0xd000) {
firmware_appended = true;
rom_size -= 0xd000;
}
}
if(has_st011) markup.append(
" necdsp model=uPD96050 frequency=15000000\n"
" rom id=program name=st011.program.rom size=0xc000\n"
" rom id=data name=st011.data.rom size=0x1000\n"
" ram id=data name=save.ram size=0x1000\n"
" map id=io address=60-67,e0-e7:0000-3fff select=0x0001\n"
" map id=ram address=68-6f,e8-ef:0000-7fff\n"
);
if(has_st011) {
markup.append(
" necdsp model=uPD96050 frequency=15000000\n"
" rom id=program name=st011.program.rom size=0xc000\n"
" rom id=data name=st011.data.rom size=0x1000\n"
" ram id=data name=save.ram size=0x1000\n"
" map id=io address=60-67,e0-e7:0000-3fff select=0x0001\n"
" map id=ram address=68-6f,e8-ef:0000-7fff\n"
);
if((size & 0xffff) == 0xd000) {
firmware_appended = true;
rom_size -= 0xd000;
}
}
if(has_st018) markup.append(
" armdsp frequency=21477272\n"
" rom id=program name=st018.program.rom size=0x20000\n"
" rom id=data name=st018.data.rom size=0x8000\n"
" ram name=save.ram size=0x4000\n"
" map id=io address=00-3f,80-bf:3800-38ff\n"
);
if(has_st018) {
markup.append(
" armdsp frequency=21477272\n"
" rom id=program name=st018.program.rom size=0x20000\n"
" rom id=data name=st018.data.rom size=0x8000\n"
" ram name=save.ram size=0x4000\n"
" map id=io address=00-3f,80-bf:3800-38ff\n"
);
if((size & 0x3ffff) == 0x28000) {
firmware_appended = true;
rom_size -= 0x28000;
}
}
}
void SuperFamicomCartridge::read_header(const uint8_t *data, unsigned size) {
@ -464,6 +535,7 @@ void SuperFamicomCartridge::read_header(const uint8_t *data, unsigned size) {
ram_size = 1024 << (data[index + RamSize] & 7);
if(ram_size == 1024) ram_size = 0; //no RAM present
if(rom_size == 0 && ram_size) ram_size = 0; //fix for Bazooka Blitzkrieg's malformed header (swapped ROM and RAM sizes)
//0, 1, 13 = NTSC; 2 - 12 = PAL
region = (regionid <= 1 || regionid >= 13) ? NTSC : PAL;

View File

@ -119,6 +119,7 @@ namespace nall {
inline optional<unsigned> find(const char*) const;
inline string concatenate(const char*) const;
inline void append() {}
inline void isort();
template<typename... Args> inline void append(const string&, Args&&...);
template<unsigned Limit = 0> inline lstring& split(const char*, const char*);

View File

@ -151,6 +151,12 @@ template<typename... Args> void lstring::append(const string &data, Args&&... ar
append(std::forward<Args>(args)...);
}
void lstring::isort() {
nall::sort(pool, objectsize, [](const string &x, const string &y) {
return istrcmp(x, y) < 0;
});
}
bool lstring::operator==(const lstring &source) const {
if(this == &source) return true;
if(size() != source.size()) return false;

BIN
ananke/resource/file.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 844 B

BIN
ananke/resource/folder.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.1 KiB

BIN
ananke/resource/home.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 606 B

View File

@ -0,0 +1,5 @@
resource name=resource
binary id=home name=home.png
binary id=up name=up.png
binary id=folder name=folder.png
binary id=file name=file.png

View File

@ -0,0 +1,119 @@
namespace resource {
const uint8_t home[606] = {
137,80,78,71,13,10,26,10,0,0,0,13,73,72,68,82,0,0,0,16,0,0,0,16,8,6,0,0,0,31,243,255,
97,0,0,0,6,98,75,71,68,0,0,0,0,0,0,249,67,187,127,0,0,0,9,112,72,89,115,0,0,13,215,0,
0,13,215,1,66,40,155,120,0,0,0,7,116,73,77,69,7,213,10,14,20,37,19,83,42,210,59,0,0,1,235,73,
68,65,84,56,203,149,147,191,107,83,81,20,128,191,123,251,222,75,211,64,242,36,160,85,135,100,81,123,19,104,85,172,
17,92,28,140,66,19,167,135,212,74,39,145,162,163,24,92,58,180,110,193,169,254,24,234,212,37,139,245,199,96,19,240,
15,240,63,16,121,91,92,196,90,219,240,98,81,137,33,121,215,33,246,217,151,80,33,103,186,92,206,247,221,115,14,231,
194,1,225,41,85,172,128,174,128,246,148,122,200,48,177,7,123,74,105,79,169,61,73,113,104,120,177,56,163,203,55,111,
252,87,34,250,225,154,235,110,20,148,98,253,220,89,182,39,78,113,228,240,56,39,188,38,83,107,107,212,92,151,130,82,
215,14,185,110,117,64,176,31,126,83,156,97,247,248,49,148,202,50,22,141,210,106,181,24,219,252,74,182,92,30,144,136,
126,184,122,251,22,157,100,146,116,42,77,42,149,2,64,107,104,183,219,236,214,235,156,44,149,66,18,177,31,126,247,160,
68,199,48,201,229,46,96,219,118,208,154,214,26,0,223,247,249,185,181,69,114,110,46,144,136,10,232,130,82,188,127,84,
198,107,54,57,63,157,35,30,143,35,132,8,9,124,223,15,206,134,16,140,230,243,212,92,23,3,184,3,172,78,157,62,
195,253,210,61,54,170,111,3,240,201,202,51,86,30,63,69,139,17,116,167,133,48,70,209,221,223,44,47,45,209,238,165,
204,202,121,120,190,48,153,33,17,79,0,160,212,4,153,140,34,155,205,244,94,20,146,145,244,149,222,196,83,121,144,22,
90,107,22,38,51,204,195,186,236,239,211,178,44,76,211,196,48,140,224,254,75,227,7,0,31,234,59,116,187,126,144,11,
48,32,144,82,34,165,196,146,159,1,232,96,241,241,83,3,128,111,222,47,58,34,18,90,36,99,96,179,254,14,207,231,
40,0,151,46,78,115,53,26,67,234,113,46,75,147,237,77,66,21,24,253,21,252,155,126,239,165,239,222,14,162,217,56,
112,245,3,65,36,18,193,182,109,18,137,4,2,137,16,16,139,197,112,28,103,0,178,44,43,252,23,174,207,58,175,0,
135,225,98,245,229,139,215,119,255,0,86,248,213,163,133,187,128,26,0,0,0,0,73,69,78,68,174,66,96,130,
};
const uint8_t up[652] = {
137,80,78,71,13,10,26,10,0,0,0,13,73,72,68,82,0,0,0,16,0,0,0,16,8,6,0,0,0,31,243,255,
97,0,0,0,4,115,66,73,84,8,8,8,8,124,8,100,136,0,0,0,25,116,69,88,116,83,111,102,116,119,97,114,
101,0,119,119,119,46,105,110,107,115,99,97,112,101,46,111,114,103,155,238,60,26,0,0,2,30,73,68,65,84,56,141,
149,147,79,104,19,65,20,198,191,55,187,51,217,141,133,122,104,76,255,209,130,4,237,193,64,42,168,208,213,138,104,68,
98,69,45,20,114,107,74,201,73,144,98,22,193,171,199,82,145,160,23,15,69,79,30,165,66,241,226,77,42,94,68,80,
208,67,41,180,42,149,148,52,137,166,154,38,217,217,25,15,81,172,33,169,246,29,223,251,230,199,124,223,155,33,173,53,
218,213,201,155,124,30,0,150,102,189,233,118,26,214,110,224,184,60,221,223,21,73,246,117,29,76,58,46,79,239,9,224,
184,60,26,16,251,178,87,206,76,6,199,70,147,193,128,8,102,29,151,71,255,11,224,184,188,3,132,197,137,115,211,214,
150,151,199,150,183,137,248,200,37,11,132,69,199,229,29,255,4,16,225,209,232,112,162,167,55,52,72,159,75,31,240,177,
244,30,157,157,157,20,27,58,209,13,194,195,93,1,142,203,211,253,7,34,137,179,71,199,249,74,254,13,12,198,97,50,
142,87,107,11,136,13,29,23,161,253,61,137,230,60,216,142,195,81,193,237,108,42,225,218,235,229,101,104,242,32,132,137,
58,125,199,54,21,241,46,255,28,23,78,95,13,154,166,248,43,15,182,211,247,212,88,198,82,228,161,34,75,16,1,1,
30,224,40,203,117,8,219,64,65,174,162,168,86,113,254,212,69,139,216,159,60,216,111,223,241,99,227,221,135,250,98,148,
175,172,193,228,6,56,55,80,81,5,84,141,175,16,54,131,176,25,150,191,189,64,184,55,68,71,14,15,135,137,53,242,
160,145,140,153,30,232,142,100,111,76,220,177,5,15,64,65,194,135,135,215,185,5,188,45,60,131,100,21,16,35,36,6,
50,208,90,67,41,160,94,175,225,241,211,249,74,177,180,57,99,18,67,234,83,110,197,158,185,119,185,225,137,163,122,247,
250,19,171,44,115,240,141,109,112,193,192,76,130,193,9,115,15,110,87,101,77,91,191,236,7,137,33,101,46,205,122,78,
211,38,180,214,10,165,250,23,48,131,96,112,6,30,104,64,100,77,91,47,231,60,218,245,29,0,128,210,62,126,212,139,
141,43,251,26,178,174,160,85,235,63,99,182,106,250,74,162,90,219,134,50,53,160,21,124,73,240,189,61,0,164,47,17,
31,188,6,98,0,49,2,17,246,0,32,108,220,186,63,25,110,37,38,194,70,115,239,39,48,247,197,219,182,208,154,34,
0,0,0,0,73,69,78,68,174,66,96,130,
};
const uint8_t folder[1176] = {
137,80,78,71,13,10,26,10,0,0,0,13,73,72,68,82,0,0,0,32,0,0,0,32,8,6,0,0,0,115,122,122,
244,0,0,0,4,115,66,73,84,8,8,8,8,124,8,100,136,0,0,0,9,112,72,89,115,0,0,13,215,0,0,13,
215,1,66,40,155,120,0,0,0,25,116,69,88,116,83,111,102,116,119,97,114,101,0,119,119,119,46,105,110,107,115,99,
97,112,101,46,111,114,103,155,238,60,26,0,0,4,21,73,68,65,84,88,133,237,151,61,111,28,69,24,199,127,51,187,
119,123,175,246,57,145,48,9,5,86,148,194,31,0,9,5,33,83,110,149,130,26,137,2,90,58,62,64,36,62,64,74,
132,68,133,104,161,67,72,167,64,23,201,138,2,138,210,69,194,198,196,40,22,198,247,186,119,222,151,153,157,25,138,123,
201,58,119,142,19,114,82,40,248,75,143,118,118,118,247,121,126,243,60,51,179,187,34,12,67,94,167,228,107,141,254,95,
0,240,1,110,220,184,225,43,165,126,54,198,188,119,209,3,66,136,220,90,251,249,195,135,15,191,92,25,64,154,166,91,
149,74,229,157,155,55,111,250,73,146,224,156,3,192,90,11,48,63,159,182,253,59,119,238,220,222,222,222,254,254,209,163,
71,199,43,1,80,74,101,213,106,213,29,29,29,209,233,116,112,206,45,53,0,33,4,155,155,155,249,193,193,193,71,192,
237,149,0,104,173,211,44,203,196,165,75,27,24,99,176,214,158,9,92,204,132,16,130,106,181,90,63,60,60,252,98,123,
123,251,214,172,127,153,156,115,218,90,251,241,222,222,222,143,207,5,0,178,44,203,188,78,167,75,167,211,153,3,204,142,
179,32,197,64,91,91,91,245,70,163,65,179,217,68,8,129,16,2,0,41,229,188,29,69,17,247,238,221,187,5,60,31,
224,242,229,203,105,191,223,247,54,54,90,104,173,23,0,150,149,98,166,56,142,1,230,16,69,139,227,24,99,76,237,188,
224,115,128,221,221,93,117,237,218,53,217,235,245,230,25,0,150,130,204,178,81,212,108,196,197,224,82,202,25,64,229,66,
0,0,99,140,109,54,215,100,154,102,220,63,180,220,221,63,27,228,188,58,63,171,25,204,228,153,22,206,93,185,206,219,
31,232,226,61,158,39,190,93,255,253,155,79,206,0,56,231,116,183,219,245,187,221,46,143,59,13,62,253,240,93,174,191,
181,81,112,54,61,62,47,250,18,200,105,207,60,206,147,206,152,175,190,187,255,254,236,188,152,1,221,104,212,171,90,107,
212,31,146,102,181,204,254,223,99,162,56,159,140,108,233,104,207,35,17,11,77,1,52,42,62,42,211,8,65,103,118,121,
190,21,27,99,116,191,63,160,219,237,18,103,150,122,181,132,53,147,27,228,212,193,179,134,59,207,220,83,179,19,179,214,
145,100,134,52,203,193,137,249,6,86,44,65,86,169,4,180,90,45,50,35,168,5,37,172,83,120,114,53,175,139,113,154,
83,111,250,140,134,57,214,186,39,11,0,121,158,171,40,26,209,239,15,208,230,13,170,129,143,115,14,79,158,155,231,23,
147,131,81,170,209,185,37,240,37,113,170,173,49,249,209,2,128,49,38,43,151,75,84,155,27,172,213,202,56,64,10,177,
188,248,47,40,227,28,163,84,147,91,135,231,9,130,178,199,105,146,41,33,196,201,2,128,181,54,27,141,198,28,15,20,
235,245,75,232,220,190,210,232,51,109,137,51,3,78,224,79,253,148,61,201,232,84,229,130,167,147,176,152,129,212,247,125,
188,32,160,73,153,76,217,11,131,76,230,152,195,186,201,62,97,236,196,84,110,151,173,72,156,131,193,40,181,185,115,139,
0,214,218,100,60,30,211,25,248,84,90,101,162,68,147,233,233,75,8,200,141,69,27,135,206,45,185,153,110,203,47,153,
149,68,25,134,227,196,19,210,91,90,130,84,8,129,12,26,148,74,62,163,68,19,37,154,84,25,148,182,47,29,108,153,
226,44,231,52,209,62,231,148,32,142,227,83,122,81,133,74,13,30,159,196,12,99,189,212,209,191,145,0,134,177,66,25,
83,250,245,234,94,47,124,252,12,128,181,54,6,129,245,107,100,185,37,138,53,74,95,60,15,94,84,82,10,78,134,9,
82,200,56,220,221,157,59,62,51,7,146,36,33,74,12,87,175,4,84,3,143,160,188,186,111,86,41,4,105,170,144,82,
12,139,253,197,18,36,0,154,18,235,85,143,122,105,21,85,127,42,231,28,253,36,65,88,59,88,0,104,183,219,98,103,
103,199,68,177,98,112,234,248,243,100,136,236,190,226,14,184,68,199,199,67,155,36,195,7,187,237,118,45,12,195,120,14,
0,120,81,20,253,244,203,161,248,76,173,227,255,182,255,202,31,187,103,228,192,2,88,157,30,28,63,248,225,235,226,53,
49,251,53,107,183,219,205,96,109,237,205,90,208,218,116,56,41,133,92,201,18,200,141,49,42,75,107,185,16,121,62,58,
233,1,127,133,97,216,91,0,152,66,72,32,96,146,153,124,21,0,83,5,64,10,168,48,12,207,44,45,241,255,207,233,
235,6,248,7,188,50,165,151,203,8,55,43,0,0,0,0,73,69,78,68,174,66,96,130,
};
const uint8_t file[844] = {
137,80,78,71,13,10,26,10,0,0,0,13,73,72,68,82,0,0,0,32,0,0,0,32,8,6,0,0,0,115,122,122,
244,0,0,0,4,115,66,73,84,8,8,8,8,124,8,100,136,0,0,3,3,73,68,65,84,88,133,229,151,79,110,212,
48,24,197,127,182,227,56,81,39,116,36,132,0,169,167,226,2,101,209,93,239,192,150,37,171,46,43,245,4,92,164,183,
40,82,89,21,36,134,84,76,18,59,44,90,91,142,243,103,50,21,59,62,201,138,227,120,236,247,189,247,252,37,3,255,
123,136,116,224,234,234,234,67,150,101,55,64,165,148,66,74,137,115,14,107,109,104,93,215,133,107,220,95,26,3,118,93,
215,125,188,185,185,249,26,239,151,141,16,9,113,125,113,113,81,61,247,195,120,223,247,131,121,241,253,202,126,117,121,121,
121,13,44,3,176,214,110,1,110,111,111,17,66,32,165,12,87,41,37,74,41,148,82,8,33,80,74,177,221,110,209,90,
15,158,167,125,33,4,251,253,158,166,105,182,233,126,50,29,232,251,30,33,68,104,64,88,208,55,207,78,215,117,24,99,
70,191,247,109,77,140,24,112,206,133,13,98,6,210,38,165,164,40,138,48,127,42,60,16,159,200,20,168,17,3,206,185,
17,11,177,4,49,40,231,28,77,211,28,204,114,137,141,17,0,107,109,232,207,177,224,159,41,165,208,90,31,100,97,9,
200,36,3,233,230,233,189,181,150,60,207,41,203,146,186,174,233,186,46,204,91,202,124,21,0,207,192,156,9,1,140,49,
20,69,65,93,215,100,89,70,158,231,3,173,231,50,127,17,128,88,123,127,239,105,55,198,96,140,161,109,219,85,174,95,
13,96,202,132,41,35,62,218,182,5,240,213,110,113,211,163,25,72,179,23,66,208,52,13,90,235,80,92,252,243,199,199,
199,229,244,97,210,172,7,37,136,93,47,165,164,170,42,178,44,67,8,193,201,201,73,232,151,101,57,152,63,197,194,139,
37,136,77,168,181,198,90,27,42,97,215,117,97,222,210,113,92,205,128,215,50,205,222,103,16,75,226,156,11,12,120,64,
62,203,41,38,142,146,32,213,190,239,123,172,181,225,69,228,105,143,193,214,117,141,115,110,86,134,163,0,196,11,11,33,
200,178,140,170,170,6,115,235,186,14,114,120,79,40,165,70,155,28,205,64,74,181,7,32,165,28,248,195,24,67,158,231,
1,172,82,106,117,89,158,5,144,158,231,212,7,113,40,165,6,12,120,169,210,170,184,20,171,142,161,47,54,177,254,254,
236,123,205,227,58,177,219,237,86,3,152,250,34,26,80,37,132,96,179,217,80,150,229,200,96,155,205,6,173,245,96,190,
49,38,48,177,6,196,162,9,189,15,178,44,27,140,123,96,109,219,142,36,136,95,90,107,98,214,3,177,9,211,240,99,
190,8,77,197,161,162,52,11,32,149,96,238,37,3,79,18,164,0,60,232,135,135,135,17,107,171,1,132,135,82,6,157,
227,240,0,119,187,221,8,160,63,5,167,167,167,65,138,163,62,201,226,5,189,235,167,88,232,251,30,173,245,36,56,95,
71,252,247,229,82,164,167,160,146,82,254,234,251,254,213,217,217,89,24,156,211,185,40,138,197,197,211,242,155,231,249,14,
120,7,252,4,246,41,128,10,120,115,127,127,255,249,252,252,252,19,80,46,174,190,50,242,60,167,105,26,132,16,127,238,
238,238,190,0,239,1,5,124,7,92,156,90,14,188,5,94,3,91,192,60,79,252,23,241,135,167,100,107,224,7,240,13,
248,13,19,127,78,159,55,46,158,1,173,43,103,135,195,1,45,79,180,239,129,96,140,191,182,58,238,12,241,249,173,246,
0,0,0,0,73,69,78,68,174,66,96,130,
};
};

View File

@ -0,0 +1,6 @@
namespace resource {
extern const uint8_t home[606];
extern const uint8_t up[652];
extern const uint8_t folder[1176];
extern const uint8_t file[844];
};

BIN
ananke/resource/up.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 652 B

View File

@ -1,3 +1,17 @@
void Ananke::copySuperFamicomSaves(const string &pathname) {
if(!file::exists({pathname, "save.ram"})) {
if(file::exists({information.path, nall::basename(information.name), ".srm"})) {
file::copy({information.path, nall::basename(information.name), ".srm"}, {pathname, "save.ram"});
}
}
if(!file::exists({pathname, "rtc.ram"})) {
if(file::exists({information.path, nall::basename(information.name), ".rtc"})) {
file::copy({information.path, nall::basename(information.name), ".rtc"}, {pathname, "rtc.ram"});
}
}
}
string Ananke::createSuperFamicomDatabase(vector<uint8_t> &buffer, Markup::Node &document, const string &manifest) {
string pathname = {
userpath(), "Emulation/Super Famicom/",
@ -8,7 +22,7 @@ string Ananke::createSuperFamicomDatabase(vector<uint8_t> &buffer, Markup::Node
};
directory::create(pathname);
//strip "release" root node from database entry
//strip "release" root node from database entry (since a single game manifest isn't part of a database)
string markup = manifest;
markup.replace("\n ", "\n");
markup.replace("information", "\ninformation");
@ -25,6 +39,7 @@ string Ananke::createSuperFamicomDatabase(vector<uint8_t> &buffer, Markup::Node
offset += size;
}
copySuperFamicomSaves(pathname);
return pathname;
}
@ -32,7 +47,7 @@ string Ananke::createSuperFamicomHeuristic(vector<uint8_t> &buffer) {
string pathname = {
userpath(), "Emulation/Super Famicom/",
nall::basename(information.name),
" (unverified).sfc/"
" (!).sfc/"
};
directory::create(pathname);
@ -41,17 +56,36 @@ string Ananke::createSuperFamicomHeuristic(vector<uint8_t> &buffer) {
SuperFamicomCartridge info(buffer.data(), buffer.size());
string markup = info.markup;
if(!information.manifest.empty()) markup = information.manifest; //override with embedded beat manifest, if one exists
information.manifest = markup; //save for use with firmware routine below
file::write({pathname, "manifest.bml"}, markup);
if(!markup.position("spc7110")) {
file::write({pathname, "program.rom"}, buffer);
file::write({pathname, "program.rom"}, buffer.data(), info.rom_size);
} else {
file::write({pathname, "program.rom"}, buffer.data(), 0x100000);
file::write({pathname, "data.rom"}, buffer.data() + 0x100000, buffer.size() - 0x100000);
file::write({pathname, "data.rom"}, buffer.data() + 0x100000, info.rom_size - 0x100000);
}
auto copyFirmware = [&](const string &name, unsigned programSize, unsigned dataSize) {
createSuperFamicomHeuristicFirmware(buffer, pathname, info.firmware_appended);
copySuperFamicomSaves(pathname);
return pathname;
}
void Ananke::createSuperFamicomHeuristicFirmware(vector<uint8_t> &buffer, const string &pathname, bool firmware_appended) {
auto copyFirmwareInternal = [&](const string &name, unsigned programSize, unsigned dataSize) {
//firmware appended directly onto .sfc file
unsigned programOffset = buffer.size() - programSize - dataSize;
unsigned dataOffset = buffer.size() - dataSize;
string basename = nall::basename(name);
if(programSize) file::write({pathname, basename, ".program.rom"}, buffer.data() + programOffset, programSize);
if(dataSize) file::write({pathname, basename, ".data.rom"}, buffer.data() + dataOffset, dataSize);
};
auto copyFirmwareExternal = [&](const string &name, unsigned programSize, unsigned dataSize) {
//firmware stored in external file
auto buffer = file::read({information.path, name}); //try and read from the containing directory
if(buffer.size() == 0) buffer = extractFile(name); //try and read from the containing archive, if one exists
if(buffer.size() == 0) {
@ -67,6 +101,12 @@ string Ananke::createSuperFamicomHeuristic(vector<uint8_t> &buffer) {
if(dataSize) file::write({pathname, basename, ".data.rom"}, buffer.data() + programSize, dataSize);
};
auto copyFirmware = [&](const string &name, unsigned programSize, unsigned dataSize) {
if(firmware_appended == 1) copyFirmwareInternal(name, programSize, dataSize);
if(firmware_appended == 0) copyFirmwareExternal(name, programSize, dataSize);
};
string markup = information.manifest;
if(markup.position("dsp1.program.rom" )) copyFirmware("dsp1.rom", 0x001800, 0x000800);
if(markup.position("dsp1b.program.rom")) copyFirmware("dsp1b.rom", 0x001800, 0x000800);
if(markup.position("dsp2.program.rom" )) copyFirmware("dsp2.rom", 0x001800, 0x000800);
@ -76,14 +116,13 @@ string Ananke::createSuperFamicomHeuristic(vector<uint8_t> &buffer) {
if(markup.position("st011.program.rom")) copyFirmware("st011.rom", 0x00c000, 0x001000);
if(markup.position("st018.program.rom")) copyFirmware("st018.rom", 0x020000, 0x008000);
if(markup.position("cx4.data.rom" )) copyFirmware("cx4.rom", 0x000000, 0x000c00);
return pathname;
}
string Ananke::openSuperFamicom(vector<uint8_t> &buffer) {
string sha256 = nall::sha256(buffer.data(), buffer.size());
string databaseText = string::read({configpath(), "ananke/database/Super Famicom.bml"}).rtrim("\n");
if(databaseText.empty()) databaseText = string{Database::SuperFamicom}.strip();
lstring databaseItem = databaseText.split("\n\n");
for(auto &item : databaseItem) {