mirror of https://github.com/bsnes-emu/bsnes.git
Update to v094r17 release.
byuu says: This updates higan to use the new Markup::Node changes. This is a really big change, and one slight typo anywhere could break certain classes of games from playing. I don't have ananke hooked up again yet, so I don't have the ability to test this much. If anyone with some v094 game folders wouldn't mind testing, I'd help out a great deal. I'm most concerned about testing one of each SNES special chip game. Most notably, systems like the SA-1, HitachiDSP and NEC-DSP were using the fancier lookups, eg node["rom[0]/name"], which I had to convert to a rather ugly node["rom"].at(0)["name"], which I'm fairly confident won't work. I'm going to blame that on the fumes from the shelves I just stained >.> Might work with node.find("rom[0]/name")(0) though ...? But so ugly ... ugh. That aside, this WIP adds the accuracy-PPU inlining, so the accuracy profile should run around 7.5% faster than before.
This commit is contained in:
parent
c335ee9d80
commit
39ca8a2fab
|
@ -3,7 +3,7 @@
|
||||||
|
|
||||||
namespace Emulator {
|
namespace Emulator {
|
||||||
static const char Name[] = "higan";
|
static const char Name[] = "higan";
|
||||||
static const char Version[] = "094.16";
|
static const char Version[] = "094.17";
|
||||||
static const char Author[] = "byuu";
|
static const char Author[] = "byuu";
|
||||||
static const char License[] = "GPLv3";
|
static const char License[] = "GPLv3";
|
||||||
static const char Website[] = "http://byuu.org/";
|
static const char Website[] = "http://byuu.org/";
|
||||||
|
|
|
@ -86,31 +86,31 @@ Board::Board(Markup::Node& document) {
|
||||||
cartridge.board = this;
|
cartridge.board = this;
|
||||||
auto cartridge = document["cartridge"];
|
auto cartridge = document["cartridge"];
|
||||||
|
|
||||||
information.type = cartridge["board/type"].data;
|
information.type = cartridge["board/type"].text();
|
||||||
information.battery = cartridge["prg/ram/name"].exists();
|
information.battery = (bool)cartridge["prg/ram/name"];
|
||||||
|
|
||||||
auto prom = cartridge["prg/rom"];
|
auto prom = cartridge["prg/rom"];
|
||||||
auto pram = cartridge["prg/ram"];
|
auto pram = cartridge["prg/ram"];
|
||||||
auto crom = cartridge["chr/rom"];
|
auto crom = cartridge["chr/rom"];
|
||||||
auto cram = cartridge["chr/ram"];
|
auto cram = cartridge["chr/ram"];
|
||||||
|
|
||||||
prgrom.size = numeral(prom["size"].data);
|
prgrom.size = prom["size"].text().numeral();
|
||||||
prgram.size = numeral(pram["size"].data);
|
prgram.size = pram["size"].text().numeral();
|
||||||
chrrom.size = numeral(crom["size"].data);
|
chrrom.size = crom["size"].text().numeral();
|
||||||
chrram.size = numeral(cram["size"].data);
|
chrram.size = cram["size"].text().numeral();
|
||||||
|
|
||||||
if(prgrom.size) prgrom.data = new uint8[prgrom.size]();
|
if(prgrom.size) prgrom.data = new uint8[prgrom.size]();
|
||||||
if(prgram.size) prgram.data = new uint8[prgram.size]();
|
if(prgram.size) prgram.data = new uint8[prgram.size]();
|
||||||
if(chrrom.size) chrrom.data = new uint8[chrrom.size]();
|
if(chrrom.size) chrrom.data = new uint8[chrrom.size]();
|
||||||
if(chrram.size) chrram.data = new uint8[chrram.size]();
|
if(chrram.size) chrram.data = new uint8[chrram.size]();
|
||||||
|
|
||||||
if(prom["name"].data) interface->loadRequest(ID::ProgramROM, prom["name"].data);
|
if(auto name = prom["name"].text()) interface->loadRequest(ID::ProgramROM, name);
|
||||||
if(pram["name"].data) interface->loadRequest(ID::ProgramRAM, pram["name"].data);
|
if(auto name = pram["name"].text()) interface->loadRequest(ID::ProgramRAM, name);
|
||||||
if(crom["name"].data) interface->loadRequest(ID::CharacterROM, crom["name"].data);
|
if(auto name = crom["name"].text()) interface->loadRequest(ID::CharacterROM, name);
|
||||||
if(cram["name"].data) interface->loadRequest(ID::CharacterRAM, cram["name"].data);
|
if(auto name = cram["name"].text()) interface->loadRequest(ID::CharacterRAM, name);
|
||||||
|
|
||||||
if(pram["name"].data) Famicom::cartridge.memory.append({ID::ProgramRAM, pram["name"].data});
|
if(auto name = pram["name"].text()) Famicom::cartridge.memory.append({ID::ProgramRAM, name});
|
||||||
if(cram["name"].data) Famicom::cartridge.memory.append({ID::CharacterRAM, cram["name"].data});
|
if(auto name = cram["name"].text()) Famicom::cartridge.memory.append({ID::CharacterRAM, name});
|
||||||
|
|
||||||
prgram.writable = true;
|
prgram.writable = true;
|
||||||
chrram.writable = true;
|
chrram.writable = true;
|
||||||
|
@ -120,7 +120,7 @@ Board::~Board() {
|
||||||
}
|
}
|
||||||
|
|
||||||
Board* Board::load(string manifest) {
|
Board* Board::load(string manifest) {
|
||||||
auto document = Markup::Document(manifest);
|
auto document = BML::unserialize(manifest);
|
||||||
cartridge.information.title = document["information/title"].text();
|
cartridge.information.title = document["information/title"].text();
|
||||||
|
|
||||||
string type = document["cartridge/board/type"].text();
|
string type = document["cartridge/board/type"].text();
|
||||||
|
|
|
@ -50,8 +50,8 @@ void serialize(serializer& s) {
|
||||||
}
|
}
|
||||||
|
|
||||||
KonamiVRC2(Markup::Node& document) : Board(document), vrc2(*this) {
|
KonamiVRC2(Markup::Node& document) : Board(document), vrc2(*this) {
|
||||||
settings.pinout.a0 = 1 << decimal(document["cartridge"]["chip"]["pinout"]["a0"].data);
|
settings.pinout.a0 = 1 << document["cartridge/chip/pinout/a0"].decimal();
|
||||||
settings.pinout.a1 = 1 << decimal(document["cartridge"]["chip"]["pinout"]["a1"].data);
|
settings.pinout.a1 = 1 << document["cartridge/chip/pinout/a1"].decimal();
|
||||||
}
|
}
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
|
@ -51,7 +51,7 @@ void serialize(serializer& s) {
|
||||||
}
|
}
|
||||||
|
|
||||||
KonamiVRC3(Markup::Node& document) : Board(document), vrc3(*this) {
|
KonamiVRC3(Markup::Node& document) : Board(document), vrc3(*this) {
|
||||||
settings.mirror = document["cartridge"]["mirror"]["mode"].data == "vertical" ? 1 : 0;
|
settings.mirror = document["cartridge/mirror/mode"].text() == "vertical" ? 1 : 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
|
@ -54,8 +54,8 @@ void serialize(serializer& s) {
|
||||||
}
|
}
|
||||||
|
|
||||||
KonamiVRC4(Markup::Node& document) : Board(document), vrc4(*this) {
|
KonamiVRC4(Markup::Node& document) : Board(document), vrc4(*this) {
|
||||||
settings.pinout.a0 = 1 << decimal(document["cartridge"]["chip"]["pinout"]["a0"].data);
|
settings.pinout.a0 = 1 << document["cartridge/chip/pinout/a0"].decimal();
|
||||||
settings.pinout.a1 = 1 << decimal(document["cartridge"]["chip"]["pinout"]["a1"].data);
|
settings.pinout.a1 = 1 << document["cartridge/chip/pinout/a1"].decimal();
|
||||||
}
|
}
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
|
@ -46,7 +46,7 @@ void serialize(serializer& s) {
|
||||||
}
|
}
|
||||||
|
|
||||||
NES_BNROM(Markup::Node& document) : Board(document) {
|
NES_BNROM(Markup::Node& document) : Board(document) {
|
||||||
settings.mirror = document["cartridge"]["mirror"]["mode"].data == "vertical" ? 1 : 0;
|
settings.mirror = document["cartridge/mirror/mode"].text() == "vertical" ? 1 : 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
|
@ -48,7 +48,7 @@ void serialize(serializer& s) {
|
||||||
}
|
}
|
||||||
|
|
||||||
NES_CNROM(Markup::Node& document) : Board(document) {
|
NES_CNROM(Markup::Node& document) : Board(document) {
|
||||||
settings.mirror = document["cartridge"]["mirror"]["mode"].data == "vertical" ? 1 : 0;
|
settings.mirror = document["cartridge/mirror/mode"].text() == "vertical" ? 1 : 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
|
@ -55,7 +55,7 @@ void serialize(serializer& s) {
|
||||||
}
|
}
|
||||||
|
|
||||||
NES_GxROM(Markup::Node& document) : Board(document) {
|
NES_GxROM(Markup::Node& document) : Board(document) {
|
||||||
settings.mirror = document["cartridge"]["mirror"]["mode"].data == "vertical" ? 1 : 0;
|
settings.mirror = document["cartridge/mirror/mode"].text() == "vertical" ? 1 : 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
|
@ -37,7 +37,7 @@ void serialize(serializer& s) {
|
||||||
}
|
}
|
||||||
|
|
||||||
NES_NROM(Markup::Node& document) : Board(document) {
|
NES_NROM(Markup::Node& document) : Board(document) {
|
||||||
settings.mirror = document["cartridge"]["mirror"]["mode"].data == "vertical" ? 1 : 0;
|
settings.mirror = document["cartridge/mirror/mode"].text() == "vertical" ? 1 : 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
|
@ -49,7 +49,7 @@ void serialize(serializer& s) {
|
||||||
}
|
}
|
||||||
|
|
||||||
NES_UxROM(Markup::Node& document) : Board(document) {
|
NES_UxROM(Markup::Node& document) : Board(document) {
|
||||||
settings.mirror = document["cartridge"]["mirror"]["mode"].data == "vertical" ? 1 : 0;
|
settings.mirror = document["cartridge/mirror/mode"].text() == "vertical" ? 1 : 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
|
@ -43,7 +43,7 @@ void System::runthreadtosave() {
|
||||||
|
|
||||||
void System::load() {
|
void System::load() {
|
||||||
string manifest = string::read({interface->path(ID::System), "manifest.bml"});
|
string manifest = string::read({interface->path(ID::System), "manifest.bml"});
|
||||||
auto document = Markup::Document(manifest);
|
auto document = BML::unserialize(manifest);
|
||||||
|
|
||||||
serialize_init();
|
serialize_init();
|
||||||
}
|
}
|
||||||
|
|
|
@ -47,7 +47,7 @@ void Cartridge::load(System::Revision revision) {
|
||||||
information.romsize = 0;
|
information.romsize = 0;
|
||||||
information.ramsize = 0;
|
information.ramsize = 0;
|
||||||
|
|
||||||
auto document = Markup::Document(information.markup);
|
auto document = BML::unserialize(information.markup);
|
||||||
information.title = document["information/title"].text();
|
information.title = document["information/title"].text();
|
||||||
|
|
||||||
auto mapperid = document["cartridge/board/type"].text();
|
auto mapperid = document["cartridge/board/type"].text();
|
||||||
|
@ -66,22 +66,22 @@ void Cartridge::load(System::Revision revision) {
|
||||||
auto rom = document["cartridge/rom"];
|
auto rom = document["cartridge/rom"];
|
||||||
auto ram = document["cartridge/ram"];
|
auto ram = document["cartridge/ram"];
|
||||||
|
|
||||||
romsize = numeral(rom["size"].data);
|
romsize = rom["size"].decimal();
|
||||||
romdata = allocate<uint8>(romsize, 0xff);
|
romdata = allocate<uint8>(romsize, 0xff);
|
||||||
|
|
||||||
ramsize = numeral(ram["size"].data);
|
ramsize = ram["size"].decimal();
|
||||||
ramdata = allocate<uint8>(ramsize, 0xff);
|
ramdata = allocate<uint8>(ramsize, 0xff);
|
||||||
|
|
||||||
//Super Game Boy core loads memory from Super Famicom core
|
//Super Game Boy core loads memory from Super Famicom core
|
||||||
if(revision != System::Revision::SuperGameBoy) {
|
if(revision != System::Revision::SuperGameBoy) {
|
||||||
if(rom["name"].exists()) interface->loadRequest(ID::ROM, rom["name"].data);
|
if(rom["name"]) interface->loadRequest(ID::ROM, rom["name"].text());
|
||||||
if(ram["name"].exists()) interface->loadRequest(ID::RAM, ram["name"].data);
|
if(ram["name"]) interface->loadRequest(ID::RAM, ram["name"].text());
|
||||||
if(ram["name"].exists()) memory.append({ID::RAM, ram["name"].data});
|
if(ram["name"]) memory.append({ID::RAM, ram["name"].text()});
|
||||||
}
|
}
|
||||||
|
|
||||||
information.romsize = numeral(rom["size"].data);
|
information.romsize = rom["size"].decimal();
|
||||||
information.ramsize = numeral(ram["size"].data);
|
information.ramsize = ram["size"].decimal();
|
||||||
information.battery = ram["name"].exists();
|
information.battery = (bool)ram["name"];
|
||||||
|
|
||||||
switch(information.mapper) { default:
|
switch(information.mapper) { default:
|
||||||
case Mapper::MBC0: mapper = &mbc0; break;
|
case Mapper::MBC0: mapper = &mbc0; break;
|
||||||
|
|
|
@ -50,13 +50,14 @@ void System::load(Revision revision) {
|
||||||
if(revision == Revision::SuperGameBoy) return; //Super Famicom core loads boot ROM for SGB
|
if(revision == Revision::SuperGameBoy) return; //Super Famicom core loads boot ROM for SGB
|
||||||
|
|
||||||
string manifest = string::read({interface->path(ID::System), "manifest.bml"});
|
string manifest = string::read({interface->path(ID::System), "manifest.bml"});
|
||||||
auto document = Markup::Document(manifest);
|
auto document = BML::unserialize(manifest);
|
||||||
|
|
||||||
|
auto bootROM = document["system/cpu/rom/name"].text();
|
||||||
interface->loadRequest(
|
interface->loadRequest(
|
||||||
revision == Revision::GameBoy ? ID::GameBoyBootROM : ID::GameBoyColorBootROM,
|
revision == Revision::GameBoy ? ID::GameBoyBootROM : ID::GameBoyColorBootROM,
|
||||||
document["system/cpu/rom/name"].data
|
bootROM
|
||||||
);
|
);
|
||||||
if(!file::exists({interface->path(ID::System), document["system/cpu/rom/name"].data})) {
|
if(!file::exists({interface->path(ID::System), bootROM})) {
|
||||||
interface->notify("Error: required Game Boy firmware boot.rom not found.\n");
|
interface->notify("Error: required Game Boy firmware boot.rom not found.\n");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -14,14 +14,14 @@ string Cartridge::title() {
|
||||||
void Cartridge::load() {
|
void Cartridge::load() {
|
||||||
interface->loadRequest(ID::Manifest, "manifest.bml");
|
interface->loadRequest(ID::Manifest, "manifest.bml");
|
||||||
|
|
||||||
auto document = Markup::Document(information.markup);
|
auto document = BML::unserialize(information.markup);
|
||||||
information.title = document["information/title"].text();
|
information.title = document["information/title"].text();
|
||||||
|
|
||||||
unsigned rom_size = 0;
|
unsigned rom_size = 0;
|
||||||
if(document["cartridge/rom"].exists()) {
|
if(document["cartridge/rom"]) {
|
||||||
auto info = document["cartridge/rom"];
|
auto info = document["cartridge/rom"];
|
||||||
interface->loadRequest(ID::ROM, info["name"].data);
|
interface->loadRequest(ID::ROM, info["name"].text());
|
||||||
rom_size = numeral(info["size"].data);
|
rom_size = info["size"].decimal();
|
||||||
for(unsigned addr = rom_size; addr < rom.size; addr++) {
|
for(unsigned addr = rom_size; addr < rom.size; addr++) {
|
||||||
rom.data[addr] = rom.data[Bus::mirror(addr, rom_size)];
|
rom.data[addr] = rom.data[Bus::mirror(addr, rom_size)];
|
||||||
}
|
}
|
||||||
|
@ -31,40 +31,40 @@ void Cartridge::load() {
|
||||||
has_eeprom = false;
|
has_eeprom = false;
|
||||||
has_flashrom = false;
|
has_flashrom = false;
|
||||||
|
|
||||||
if(document["cartridge/ram"].exists()) {
|
if(document["cartridge/ram"]) {
|
||||||
auto info = document["cartridge/ram"];
|
auto info = document["cartridge/ram"];
|
||||||
|
|
||||||
if(info["type"].data == "SRAM" || info["type"].data == "FRAM") {
|
if(info["type"].text() == "SRAM" || info["type"].text() == "FRAM") {
|
||||||
has_sram = true;
|
has_sram = true;
|
||||||
ram.size = numeral(info["size"].data);
|
ram.size = info["size"].decimal();
|
||||||
ram.mask = ram.size - 1;
|
ram.mask = ram.size - 1;
|
||||||
for(unsigned n = 0; n < ram.size; n++) ram.data[n] = 0xff;
|
for(unsigned n = 0; n < ram.size; n++) ram.data[n] = 0xff;
|
||||||
|
|
||||||
interface->loadRequest(ID::RAM, info["name"].data);
|
interface->loadRequest(ID::RAM, info["name"].text());
|
||||||
memory.append({ID::RAM, info["name"].data});
|
memory.append({ID::RAM, info["name"].text()});
|
||||||
}
|
}
|
||||||
|
|
||||||
if(info["type"].data == "EEPROM") {
|
if(info["type"].text() == "EEPROM") {
|
||||||
has_eeprom = true;
|
has_eeprom = true;
|
||||||
eeprom.size = numeral(info["size"].data);
|
eeprom.size = info["size"].decimal();
|
||||||
eeprom.bits = eeprom.size <= 512 ? 6 : 14;
|
eeprom.bits = eeprom.size <= 512 ? 6 : 14;
|
||||||
if(eeprom.size == 0) eeprom.size = 8192, eeprom.bits = 0; //auto-detect size
|
if(eeprom.size == 0) eeprom.size = 8192, eeprom.bits = 0; //auto-detect size
|
||||||
eeprom.mask = rom_size > 16 * 1024 * 1024 ? 0x0fffff00 : 0x0f000000;
|
eeprom.mask = rom_size > 16 * 1024 * 1024 ? 0x0fffff00 : 0x0f000000;
|
||||||
eeprom.test = rom_size > 16 * 1024 * 1024 ? 0x0dffff00 : 0x0d000000;
|
eeprom.test = rom_size > 16 * 1024 * 1024 ? 0x0dffff00 : 0x0d000000;
|
||||||
for(unsigned n = 0; n < eeprom.size; n++) eeprom.data[n] = 0xff;
|
for(unsigned n = 0; n < eeprom.size; n++) eeprom.data[n] = 0xff;
|
||||||
|
|
||||||
interface->loadRequest(ID::EEPROM, info["name"].data);
|
interface->loadRequest(ID::EEPROM, info["name"].text());
|
||||||
memory.append({ID::EEPROM, info["name"].data});
|
memory.append({ID::EEPROM, info["name"].text()});
|
||||||
}
|
}
|
||||||
|
|
||||||
if(info["type"].data == "FlashROM") {
|
if(info["type"].text() == "FlashROM") {
|
||||||
has_flashrom = true;
|
has_flashrom = true;
|
||||||
flashrom.id = numeral(info["id"].data);
|
flashrom.id = info["id"].decimal();
|
||||||
flashrom.size = numeral(info["size"].data);
|
flashrom.size = info["size"].decimal();
|
||||||
for(unsigned n = 0; n < flashrom.size; n++) flashrom.data[n] = 0xff;
|
for(unsigned n = 0; n < flashrom.size; n++) flashrom.data[n] = 0xff;
|
||||||
|
|
||||||
interface->loadRequest(ID::FlashROM, info["name"].data);
|
interface->loadRequest(ID::FlashROM, info["name"].text());
|
||||||
memory.append({ID::FlashROM, info["name"].data});
|
memory.append({ID::FlashROM, info["name"].text()});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -25,10 +25,11 @@ void System::power() {
|
||||||
|
|
||||||
void System::load() {
|
void System::load() {
|
||||||
string manifest = string::read({interface->path(ID::System), "manifest.bml"});
|
string manifest = string::read({interface->path(ID::System), "manifest.bml"});
|
||||||
auto document = Markup::Document(manifest);
|
auto document = BML::unserialize(manifest);
|
||||||
|
|
||||||
interface->loadRequest(ID::BIOS, document["system/cpu/rom/name"].data);
|
auto bios = document["system/cpu/rom/name"].text();
|
||||||
if(!file::exists({interface->path(ID::System), document["system/cpu/rom/name"].data})) {
|
interface->loadRequest(ID::BIOS, bios);
|
||||||
|
if(!file::exists({interface->path(ID::System), bios})) {
|
||||||
interface->notify("Error: required Game Boy Advance firmware bios.rom not found.\n");
|
interface->notify("Error: required Game Boy Advance firmware bios.rom not found.\n");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -77,7 +77,7 @@ vector<uint8_t> Base64::decode(const string& text) {
|
||||||
uint8_t buffer, output;
|
uint8_t buffer, output;
|
||||||
for(unsigned i = 0; i < text.size(); i++) {
|
for(unsigned i = 0; i < text.size(); i++) {
|
||||||
uint8_t buffer = value(text[i]);
|
uint8_t buffer = value(text[i]);
|
||||||
if(buffer == 0) break;
|
if(buffer > 63) break;
|
||||||
|
|
||||||
switch(i & 3) {
|
switch(i & 3) {
|
||||||
case 0:
|
case 0:
|
||||||
|
@ -129,7 +129,7 @@ uint8_t Base64::value(char n) {
|
||||||
if(n >= '0' && n <= '9') return n - '0' + 52;
|
if(n >= '0' && n <= '9') return n - '0' + 52;
|
||||||
if(n == '+' || n == '-') return 62;
|
if(n == '+' || n == '-') return 62;
|
||||||
if(n == '/' || n == '_') return 63;
|
if(n == '/' || n == '_') return 63;
|
||||||
return 0;
|
return 64; //error code
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -58,10 +58,10 @@ struct Node {
|
||||||
|
|
||||||
void load(Markup::Node path) {
|
void load(Markup::Node path) {
|
||||||
for(auto& child : children) {
|
for(auto& child : children) {
|
||||||
auto leaf = path[child.name];
|
if(auto leaf = path[child.name]) {
|
||||||
if(!leaf.exists()) continue;
|
if(!child.empty()) child.set(leaf.text());
|
||||||
if(!child.empty()) child.set(leaf.text());
|
child.load(leaf);
|
||||||
child.load(leaf);
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -84,7 +84,7 @@ struct Node {
|
||||||
struct Document : Node {
|
struct Document : Node {
|
||||||
bool load(const string& filename) {
|
bool load(const string& filename) {
|
||||||
if(!file::exists(filename)) return false;
|
if(!file::exists(filename)) return false;
|
||||||
auto document = Markup::Document(string::read(filename));
|
auto document = BML::unserialize(string::read(filename));
|
||||||
Node::load(document);
|
Node::load(document);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,36 @@
|
||||||
|
#ifndef NALL_DECODE_URL_HPP
|
||||||
|
#define NALL_DECODE_URL_HPP
|
||||||
|
|
||||||
|
namespace nall { namespace Decode {
|
||||||
|
|
||||||
|
//returns empty string on malformed content
|
||||||
|
inline auto URL(const string& input) -> string {
|
||||||
|
string output;
|
||||||
|
for(unsigned n = 0; n < input.size();) {
|
||||||
|
char c = input[n];
|
||||||
|
if(c >= 'A' && c <= 'Z') { output.append(c); n++; continue; }
|
||||||
|
if(c >= 'a' && c <= 'z') { output.append(c); n++; continue; }
|
||||||
|
if(c >= '0' && c <= '9') { output.append(c); n++; continue; }
|
||||||
|
if(c == '-' || c == '_' || c == '.' || c == '~') { output.append(c); n++; continue; }
|
||||||
|
if(c == '+') { output.append(' '); n++; continue; }
|
||||||
|
if(c != '%' || n + 2 >= input.size()) return "";
|
||||||
|
char hi = input[n + 1];
|
||||||
|
char lo = input[n + 2];
|
||||||
|
if(hi >= '0' && hi <= '9') hi -= '0';
|
||||||
|
else if(hi >= 'A' && hi <= 'F') hi -= 'A' - 10;
|
||||||
|
else if(hi >= 'a' && hi <= 'f') hi -= 'a' - 10;
|
||||||
|
else return "";
|
||||||
|
if(lo >= '0' && lo <= '9') lo -= '0';
|
||||||
|
else if(lo >= 'A' && lo <= 'F') lo -= 'A' - 10;
|
||||||
|
else if(lo >= 'a' && lo <= 'f') lo -= 'a' - 10;
|
||||||
|
else return "";
|
||||||
|
char byte = hi * 16 + lo;
|
||||||
|
output.append(byte);
|
||||||
|
n += 3;
|
||||||
|
}
|
||||||
|
return output;
|
||||||
|
}
|
||||||
|
|
||||||
|
}}
|
||||||
|
|
||||||
|
#endif
|
|
@ -16,7 +16,7 @@ struct file : storage, varint {
|
||||||
enum class mode : unsigned { read, write, modify, append, readwrite = modify, writeread = append };
|
enum class mode : unsigned { read, write, modify, append, readwrite = modify, writeread = append };
|
||||||
enum class index : unsigned { absolute, relative };
|
enum class index : unsigned { absolute, relative };
|
||||||
|
|
||||||
static bool copy(const string& sourcename, const string& targetname) {
|
static auto copy(const string& sourcename, const string& targetname) -> bool {
|
||||||
file rd, wr;
|
file rd, wr;
|
||||||
if(rd.open(sourcename, mode::read) == false) return false;
|
if(rd.open(sourcename, mode::read) == false) return false;
|
||||||
if(wr.open(targetname, mode::write) == false) return false;
|
if(wr.open(targetname, mode::write) == false) return false;
|
||||||
|
@ -26,7 +26,7 @@ struct file : storage, varint {
|
||||||
|
|
||||||
//attempt to rename file first
|
//attempt to rename file first
|
||||||
//this will fail if paths point to different file systems; fall back to copy+remove in this case
|
//this will fail if paths point to different file systems; fall back to copy+remove in this case
|
||||||
static bool move(const string& sourcename, const string& targetname) {
|
static auto move(const string& sourcename, const string& targetname) -> bool {
|
||||||
if(rename(sourcename, targetname)) return true;
|
if(rename(sourcename, targetname)) return true;
|
||||||
if(!writable(sourcename)) return false;
|
if(!writable(sourcename)) return false;
|
||||||
if(copy(sourcename, targetname)) {
|
if(copy(sourcename, targetname)) {
|
||||||
|
@ -36,7 +36,7 @@ struct file : storage, varint {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
static bool truncate(const string& filename, unsigned size) {
|
static auto truncate(const string& filename, unsigned size) -> bool {
|
||||||
#if !defined(_WIN32)
|
#if !defined(_WIN32)
|
||||||
return truncate(filename, size) == 0;
|
return truncate(filename, size) == 0;
|
||||||
#else
|
#else
|
||||||
|
@ -51,7 +51,7 @@ struct file : storage, varint {
|
||||||
}
|
}
|
||||||
|
|
||||||
//specialization of storage::exists(); returns false for folders
|
//specialization of storage::exists(); returns false for folders
|
||||||
static bool exists(const string& filename) {
|
static auto exists(const string& filename) -> bool {
|
||||||
#if !defined(_WIN32)
|
#if !defined(_WIN32)
|
||||||
struct stat data;
|
struct stat data;
|
||||||
if(stat(filename, &data) != 0) return false;
|
if(stat(filename, &data) != 0) return false;
|
||||||
|
@ -62,7 +62,7 @@ struct file : storage, varint {
|
||||||
return !(data.st_mode & S_IFDIR);
|
return !(data.st_mode & S_IFDIR);
|
||||||
}
|
}
|
||||||
|
|
||||||
static uintmax_t size(const string& filename) {
|
static auto size(const string& filename) -> uintmax_t {
|
||||||
#if !defined(_WIN32)
|
#if !defined(_WIN32)
|
||||||
struct stat data;
|
struct stat data;
|
||||||
stat(filename, &data);
|
stat(filename, &data);
|
||||||
|
@ -73,7 +73,7 @@ struct file : storage, varint {
|
||||||
return S_ISREG(data.st_mode) ? data.st_size : 0u;
|
return S_ISREG(data.st_mode) ? data.st_size : 0u;
|
||||||
}
|
}
|
||||||
|
|
||||||
static vector<uint8_t> read(const string& filename) {
|
static auto read(const string& filename) -> vector<uint8_t> {
|
||||||
vector<uint8_t> memory;
|
vector<uint8_t> memory;
|
||||||
file fp;
|
file fp;
|
||||||
if(fp.open(filename, mode::read)) {
|
if(fp.open(filename, mode::read)) {
|
||||||
|
@ -83,7 +83,7 @@ struct file : storage, varint {
|
||||||
return memory;
|
return memory;
|
||||||
}
|
}
|
||||||
|
|
||||||
static bool read(const string& filename, uint8_t* data, unsigned size) {
|
static auto read(const string& filename, uint8_t* data, unsigned size) -> bool {
|
||||||
file fp;
|
file fp;
|
||||||
if(fp.open(filename, mode::read) == false) return false;
|
if(fp.open(filename, mode::read) == false) return false;
|
||||||
fp.read(data, size);
|
fp.read(data, size);
|
||||||
|
@ -91,7 +91,7 @@ struct file : storage, varint {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
static bool write(const string& filename, const string& text) {
|
static auto write(const string& filename, const string& text) -> bool {
|
||||||
file fp;
|
file fp;
|
||||||
if(fp.open(filename, mode::write) == false) return false;
|
if(fp.open(filename, mode::write) == false) return false;
|
||||||
fp.print(text);
|
fp.print(text);
|
||||||
|
@ -99,7 +99,7 @@ struct file : storage, varint {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
static bool write(const string& filename, const vector<uint8_t>& buffer) {
|
static auto write(const string& filename, const vector<uint8_t>& buffer) -> bool {
|
||||||
file fp;
|
file fp;
|
||||||
if(fp.open(filename, mode::write) == false) return false;
|
if(fp.open(filename, mode::write) == false) return false;
|
||||||
fp.write(buffer.data(), buffer.size());
|
fp.write(buffer.data(), buffer.size());
|
||||||
|
@ -107,7 +107,7 @@ struct file : storage, varint {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
static bool write(const string& filename, const uint8_t* data, unsigned size) {
|
static auto write(const string& filename, const uint8_t* data, unsigned size) -> bool {
|
||||||
file fp;
|
file fp;
|
||||||
if(fp.open(filename, mode::write) == false) return false;
|
if(fp.open(filename, mode::write) == false) return false;
|
||||||
fp.write(data, size);
|
fp.write(data, size);
|
||||||
|
@ -115,7 +115,7 @@ struct file : storage, varint {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
static bool create(const string& filename) {
|
static auto create(const string& filename) -> bool {
|
||||||
//create an empty file (will replace existing files)
|
//create an empty file (will replace existing files)
|
||||||
file fp;
|
file fp;
|
||||||
if(fp.open(filename, mode::write) == false) return false;
|
if(fp.open(filename, mode::write) == false) return false;
|
||||||
|
@ -123,12 +123,12 @@ struct file : storage, varint {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
static string sha256(const string& filename) {
|
static auto sha256(const string& filename) -> string {
|
||||||
auto buffer = read(filename);
|
auto buffer = read(filename);
|
||||||
return Hash::SHA256(buffer.data(), buffer.size()).digest();
|
return Hash::SHA256(buffer.data(), buffer.size()).digest();
|
||||||
}
|
}
|
||||||
|
|
||||||
uint8_t read() {
|
auto read() -> uint8_t {
|
||||||
if(!fp) return 0xff; //file not open
|
if(!fp) return 0xff; //file not open
|
||||||
if(file_mode == mode::write) return 0xff; //reads not permitted
|
if(file_mode == mode::write) return 0xff; //reads not permitted
|
||||||
if(file_offset >= file_size) return 0xff; //cannot read past end of file
|
if(file_offset >= file_size) return 0xff; //cannot read past end of file
|
||||||
|
@ -136,7 +136,7 @@ struct file : storage, varint {
|
||||||
return buffer[(file_offset++) & buffer_mask];
|
return buffer[(file_offset++) & buffer_mask];
|
||||||
}
|
}
|
||||||
|
|
||||||
uintmax_t readl(unsigned length = 1) {
|
auto readl(unsigned length = 1) -> uintmax_t {
|
||||||
uintmax_t data = 0;
|
uintmax_t data = 0;
|
||||||
for(int i = 0; i < length; i++) {
|
for(int i = 0; i < length; i++) {
|
||||||
data |= (uintmax_t)read() << (i << 3);
|
data |= (uintmax_t)read() << (i << 3);
|
||||||
|
@ -144,7 +144,7 @@ struct file : storage, varint {
|
||||||
return data;
|
return data;
|
||||||
}
|
}
|
||||||
|
|
||||||
uintmax_t readm(unsigned length = 1) {
|
auto readm(unsigned length = 1) -> uintmax_t {
|
||||||
uintmax_t data = 0;
|
uintmax_t data = 0;
|
||||||
while(length--) {
|
while(length--) {
|
||||||
data <<= 8;
|
data <<= 8;
|
||||||
|
@ -153,11 +153,11 @@ struct file : storage, varint {
|
||||||
return data;
|
return data;
|
||||||
}
|
}
|
||||||
|
|
||||||
void read(uint8_t* buffer, unsigned length) {
|
auto read(uint8_t* buffer, unsigned length) -> void {
|
||||||
while(length--) *buffer++ = read();
|
while(length--) *buffer++ = read();
|
||||||
}
|
}
|
||||||
|
|
||||||
void write(uint8_t data) {
|
auto write(uint8_t data) -> void {
|
||||||
if(!fp) return; //file not open
|
if(!fp) return; //file not open
|
||||||
if(file_mode == mode::read) return; //writes not permitted
|
if(file_mode == mode::read) return; //writes not permitted
|
||||||
buffer_sync();
|
buffer_sync();
|
||||||
|
@ -166,35 +166,35 @@ struct file : storage, varint {
|
||||||
if(file_offset > file_size) file_size = file_offset;
|
if(file_offset > file_size) file_size = file_offset;
|
||||||
}
|
}
|
||||||
|
|
||||||
void writel(uintmax_t data, unsigned length = 1) {
|
auto writel(uintmax_t data, unsigned length = 1) -> void {
|
||||||
while(length--) {
|
while(length--) {
|
||||||
write(data);
|
write(data);
|
||||||
data >>= 8;
|
data >>= 8;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void writem(uintmax_t data, unsigned length = 1) {
|
auto writem(uintmax_t data, unsigned length = 1) -> void {
|
||||||
for(int i = length - 1; i >= 0; i--) {
|
for(int i = length - 1; i >= 0; i--) {
|
||||||
write(data >> (i << 3));
|
write(data >> (i << 3));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void write(const uint8_t* buffer, unsigned length) {
|
auto write(const uint8_t* buffer, unsigned length) -> void {
|
||||||
while(length--) write(*buffer++);
|
while(length--) write(*buffer++);
|
||||||
}
|
}
|
||||||
|
|
||||||
template<typename... Args> void print(Args... args) {
|
template<typename... Args> auto print(Args... args) -> void {
|
||||||
string data(args...);
|
string data(args...);
|
||||||
const char* p = data;
|
const char* p = data;
|
||||||
while(*p) write(*p++);
|
while(*p) write(*p++);
|
||||||
}
|
}
|
||||||
|
|
||||||
void flush() {
|
auto flush() -> void {
|
||||||
buffer_flush();
|
buffer_flush();
|
||||||
fflush(fp);
|
fflush(fp);
|
||||||
}
|
}
|
||||||
|
|
||||||
void seek(int offset, index index_ = index::absolute) {
|
auto seek(signed offset, index index_ = index::absolute) -> void {
|
||||||
if(!fp) return; //file not open
|
if(!fp) return; //file not open
|
||||||
buffer_flush();
|
buffer_flush();
|
||||||
|
|
||||||
|
@ -217,17 +217,17 @@ struct file : storage, varint {
|
||||||
file_offset = req_offset;
|
file_offset = req_offset;
|
||||||
}
|
}
|
||||||
|
|
||||||
unsigned offset() const {
|
auto offset() const -> unsigned {
|
||||||
if(!fp) return 0; //file not open
|
if(!fp) return 0; //file not open
|
||||||
return file_offset;
|
return file_offset;
|
||||||
}
|
}
|
||||||
|
|
||||||
unsigned size() const {
|
auto size() const -> unsigned {
|
||||||
if(!fp) return 0; //file not open
|
if(!fp) return 0; //file not open
|
||||||
return file_size;
|
return file_size;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool truncate(unsigned size) {
|
auto truncate(unsigned size) -> bool {
|
||||||
if(!fp) return false; //file not open
|
if(!fp) return false; //file not open
|
||||||
#if !defined(_WIN32)
|
#if !defined(_WIN32)
|
||||||
return ftruncate(fileno(fp), size) == 0;
|
return ftruncate(fileno(fp), size) == 0;
|
||||||
|
@ -236,12 +236,12 @@ struct file : storage, varint {
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
bool end() {
|
auto end() -> bool {
|
||||||
if(!fp) return true; //file not open
|
if(!fp) return true; //file not open
|
||||||
return file_offset >= file_size;
|
return file_offset >= file_size;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool open() const {
|
auto open() const -> bool {
|
||||||
return fp;
|
return fp;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -249,7 +249,7 @@ struct file : storage, varint {
|
||||||
return open();
|
return open();
|
||||||
}
|
}
|
||||||
|
|
||||||
bool open(const string& filename, mode mode_) {
|
auto open(const string& filename, mode mode_) -> bool {
|
||||||
if(fp) return false;
|
if(fp) return false;
|
||||||
|
|
||||||
switch(file_mode = mode_) {
|
switch(file_mode = mode_) {
|
||||||
|
@ -274,14 +274,14 @@ struct file : storage, varint {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
void close() {
|
auto close() -> void {
|
||||||
if(!fp) return;
|
if(!fp) return;
|
||||||
buffer_flush();
|
buffer_flush();
|
||||||
fclose(fp);
|
fclose(fp);
|
||||||
fp = nullptr;
|
fp = nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
file& operator=(const file&) = delete;
|
auto operator=(const file&) -> file& = delete;
|
||||||
file(const file&) = delete;
|
file(const file&) = delete;
|
||||||
file() = default;
|
file() = default;
|
||||||
|
|
||||||
|
@ -298,12 +298,12 @@ private:
|
||||||
char buffer[buffer_size] = {0};
|
char buffer[buffer_size] = {0};
|
||||||
int buffer_offset = -1; //invalidate buffer
|
int buffer_offset = -1; //invalidate buffer
|
||||||
bool buffer_dirty = false;
|
bool buffer_dirty = false;
|
||||||
FILE *fp = nullptr;
|
FILE* fp = nullptr;
|
||||||
unsigned file_offset = 0;
|
unsigned file_offset = 0;
|
||||||
unsigned file_size = 0;
|
unsigned file_size = 0;
|
||||||
mode file_mode = mode::read;
|
mode file_mode = mode::read;
|
||||||
|
|
||||||
void buffer_sync() {
|
auto buffer_sync() -> void {
|
||||||
if(!fp) return; //file not open
|
if(!fp) return; //file not open
|
||||||
if(buffer_offset != (file_offset & ~buffer_mask)) {
|
if(buffer_offset != (file_offset & ~buffer_mask)) {
|
||||||
buffer_flush();
|
buffer_flush();
|
||||||
|
@ -314,7 +314,7 @@ private:
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void buffer_flush() {
|
auto buffer_flush() -> void {
|
||||||
if(!fp) return; //file not open
|
if(!fp) return; //file not open
|
||||||
if(file_mode == mode::read) return; //buffer cannot be written to
|
if(file_mode == mode::read) return; //buffer cannot be written to
|
||||||
if(buffer_offset < 0) return; //buffer unused
|
if(buffer_offset < 0) return; //buffer unused
|
||||||
|
|
|
@ -32,11 +32,14 @@ struct httpRequest : httpMessage {
|
||||||
auto removeHeader(const string& name) -> type& { return httpMessage::removeHeader(name), *this; }
|
auto removeHeader(const string& name) -> type& { return httpMessage::removeHeader(name), *this; }
|
||||||
auto setHeader(const string& name, const string& value = "") -> type& { return httpMessage::setHeader(name, value), *this; }
|
auto setHeader(const string& name, const string& value = "") -> type& { return httpMessage::setHeader(name, value), *this; }
|
||||||
|
|
||||||
auto get(const string& name) -> string { return _get.get(name); }
|
auto cookie(const string& name) const -> string { return _cookie.get(name); }
|
||||||
auto setGet(const string& name, const string& value = "") -> void { return _get.set(name, value); }
|
auto setCookie(const string& name, const string& value = "") -> void { _cookie.set(name, value); }
|
||||||
|
|
||||||
auto post(const string& name) -> string { return _post.get(name); }
|
auto get(const string& name) const -> string { return _get.get(name); }
|
||||||
auto setPost(const string& name, const string& value = "") -> void { return _post.set(name, value); }
|
auto setGet(const string& name, const string& value = "") -> void { _get.set(name, value); }
|
||||||
|
|
||||||
|
auto post(const string& name) const -> string { return _post.get(name); }
|
||||||
|
auto setPost(const string& name, const string& value = "") -> void { _post.set(name, value); }
|
||||||
|
|
||||||
//private:
|
//private:
|
||||||
uint32_t _ip = 0;
|
uint32_t _ip = 0;
|
||||||
|
@ -112,6 +115,14 @@ auto httpRequest::setHead() -> bool {
|
||||||
auto part = header.split<1>(":").strip();
|
auto part = header.split<1>(":").strip();
|
||||||
if(!part[0] || part.size() != 2) continue;
|
if(!part[0] || part.size() != 2) continue;
|
||||||
appendHeader(part[0], part[1]);
|
appendHeader(part[0], part[1]);
|
||||||
|
|
||||||
|
if(part[0].iequals("Cookie")) {
|
||||||
|
for(auto& block : part[1].split(";")) {
|
||||||
|
lstring variable = block.split<1>("=").strip();
|
||||||
|
variable(1).ltrim("\"").rtrim("\"");
|
||||||
|
if(variable(0)) setCookie(variable(0), variable(1));
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if(requestHost) setHeader("Host", requestHost); //request URI overrides host header
|
if(requestHost) setHeader("Host", requestHost); //request URI overrides host header
|
||||||
|
@ -131,7 +142,7 @@ auto httpRequest::body(const function<bool (const uint8_t*, unsigned)>& callback
|
||||||
auto httpRequest::setBody() -> bool {
|
auto httpRequest::setBody() -> bool {
|
||||||
if(requestType() == RequestType::Post) {
|
if(requestType() == RequestType::Post) {
|
||||||
if(header("Content-Type").iequals("application/x-www-form-urlencoded")) {
|
if(header("Content-Type").iequals("application/x-www-form-urlencoded")) {
|
||||||
for(auto& block : _body.split("\n")) {
|
for(auto& block : _body.split("&")) {
|
||||||
lstring variable = block.rtrim("\r").split<1>("=");
|
lstring variable = block.rtrim("\r").split<1>("=");
|
||||||
if(variable(0)) setPost(variable(0), variable(1));
|
if(variable(0)) setPost(variable(0), variable(1));
|
||||||
}
|
}
|
||||||
|
|
|
@ -26,10 +26,10 @@ struct httpRole {
|
||||||
};
|
};
|
||||||
|
|
||||||
auto httpRole::configure(const string& parameters) -> bool {
|
auto httpRole::configure(const string& parameters) -> bool {
|
||||||
auto document = Markup::Document(parameters);
|
auto document = BML::unserialize(parameters);
|
||||||
for(auto& parameter : document) {
|
for(auto parameter : document) {
|
||||||
string& name = parameter.name;
|
auto name = parameter.name();
|
||||||
signed value = parameter.integer();
|
auto value = parameter.integer();
|
||||||
|
|
||||||
if(0);
|
if(0);
|
||||||
else if(name == "connectionLimit") settings.connectionLimit = value;
|
else if(name == "connectionLimit") settings.connectionLimit = value;
|
||||||
|
|
|
@ -21,7 +21,7 @@
|
||||||
#include <nall/bit.hpp>
|
#include <nall/bit.hpp>
|
||||||
#include <nall/bitvector.hpp>
|
#include <nall/bitvector.hpp>
|
||||||
#include <nall/bmp.hpp>
|
#include <nall/bmp.hpp>
|
||||||
#include <nall/config.hpp>
|
//#include <nall/config.hpp>
|
||||||
#include <nall/directory.hpp>
|
#include <nall/directory.hpp>
|
||||||
#include <nall/dl.hpp>
|
#include <nall/dl.hpp>
|
||||||
#include <nall/endian.hpp>
|
#include <nall/endian.hpp>
|
||||||
|
@ -60,6 +60,7 @@
|
||||||
#include <nall/decode/gzip.hpp>
|
#include <nall/decode/gzip.hpp>
|
||||||
#include <nall/decode/inflate.hpp>
|
#include <nall/decode/inflate.hpp>
|
||||||
#include <nall/decode/png.hpp>
|
#include <nall/decode/png.hpp>
|
||||||
|
#include <nall/decode/url.hpp>
|
||||||
#include <nall/decode/zip.hpp>
|
#include <nall/decode/zip.hpp>
|
||||||
#include <nall/hash/crc16.hpp>
|
#include <nall/hash/crc16.hpp>
|
||||||
#include <nall/hash/crc32.hpp>
|
#include <nall/hash/crc32.hpp>
|
||||||
|
|
|
@ -16,6 +16,7 @@
|
||||||
#include <nall/intrinsics.hpp>
|
#include <nall/intrinsics.hpp>
|
||||||
#include <nall/memory.hpp>
|
#include <nall/memory.hpp>
|
||||||
#include <nall/method.hpp>
|
#include <nall/method.hpp>
|
||||||
|
#include <nall/shared-pointer.hpp>
|
||||||
#include <nall/stdint.hpp>
|
#include <nall/stdint.hpp>
|
||||||
#include <nall/utility.hpp>
|
#include <nall/utility.hpp>
|
||||||
#include <nall/varint.hpp>
|
#include <nall/varint.hpp>
|
||||||
|
@ -48,9 +49,9 @@
|
||||||
#include <nall/string/eval/parser.hpp>
|
#include <nall/string/eval/parser.hpp>
|
||||||
#include <nall/string/eval/evaluator.hpp>
|
#include <nall/string/eval/evaluator.hpp>
|
||||||
#include <nall/string/markup/node.hpp>
|
#include <nall/string/markup/node.hpp>
|
||||||
|
#include <nall/string/markup/find.hpp>
|
||||||
#include <nall/string/markup/bml.hpp>
|
#include <nall/string/markup/bml.hpp>
|
||||||
#include <nall/string/markup/xml.hpp>
|
#include <nall/string/markup/xml.hpp>
|
||||||
#include <nall/string/markup/document.hpp>
|
|
||||||
#include <nall/string/transform/cml.hpp>
|
#include <nall/string/transform/cml.hpp>
|
||||||
#include <nall/string/transform/dml.hpp>
|
#include <nall/string/transform/dml.hpp>
|
||||||
#undef NALL_STRING_INTERNAL_HPP
|
#undef NALL_STRING_INTERNAL_HPP
|
||||||
|
|
|
@ -211,6 +211,8 @@ public:
|
||||||
auto operator> (const char* s) const -> bool { return strcmp(data(), s) > 0; }
|
auto operator> (const char* s) const -> bool { return strcmp(data(), s) > 0; }
|
||||||
auto operator>=(const char* s) const -> bool { return strcmp(data(), s) >= 0; }
|
auto operator>=(const char* s) const -> bool { return strcmp(data(), s) >= 0; }
|
||||||
|
|
||||||
|
auto operator+=(const string& s) -> type& { return append(s); }
|
||||||
|
|
||||||
string(const string& source) : string() { operator=(source); }
|
string(const string& source) : string() { operator=(source); }
|
||||||
string(string&& source) : string() { operator=(std::move(source)); }
|
string(string&& source) : string() { operator=(std::move(source)); }
|
||||||
|
|
||||||
|
@ -223,6 +225,7 @@ public:
|
||||||
inline auto integer() const -> intmax_t { return nall::integer(*this); }
|
inline auto integer() const -> intmax_t { return nall::integer(*this); }
|
||||||
inline auto decimal() const -> uintmax_t { return nall::decimal(*this); }
|
inline auto decimal() const -> uintmax_t { return nall::decimal(*this); }
|
||||||
inline auto hex() const -> uintmax_t { return nall::hex(*this); }
|
inline auto hex() const -> uintmax_t { return nall::hex(*this); }
|
||||||
|
inline auto numeral() const -> intmax_t { return nall::numeral(*this); }
|
||||||
|
|
||||||
//core.hpp
|
//core.hpp
|
||||||
inline auto operator[](signed) const -> const char&;
|
inline auto operator[](signed) const -> const char&;
|
||||||
|
@ -244,7 +247,7 @@ public:
|
||||||
|
|
||||||
//compare.hpp
|
//compare.hpp
|
||||||
auto compare(rstring source) const -> signed { return nall::compare(*this, source); }
|
auto compare(rstring source) const -> signed { return nall::compare(*this, source); }
|
||||||
auto icompare(rstring source) const -> signed { return nall::compare(*this, source); }
|
auto icompare(rstring source) const -> signed { return nall::icompare(*this, source); }
|
||||||
|
|
||||||
auto equals(rstring source) const -> bool { return nall::equals(*this, source); }
|
auto equals(rstring source) const -> bool { return nall::equals(*this, source); }
|
||||||
auto iequals(rstring source) const -> bool { return nall::iequals(*this, source); }
|
auto iequals(rstring source) const -> bool { return nall::iequals(*this, source); }
|
||||||
|
|
|
@ -1,12 +1,17 @@
|
||||||
#ifdef NALL_STRING_INTERNAL_HPP
|
#ifdef NALL_STRING_INTERNAL_HPP
|
||||||
|
|
||||||
//BML v1.0 parser
|
//BML v1.0 parser
|
||||||
//revision 0.03
|
//revision 0.04
|
||||||
|
|
||||||
namespace nall {
|
namespace nall {
|
||||||
namespace BML {
|
namespace BML {
|
||||||
|
|
||||||
struct Node : Markup::Node {
|
//metadata is used to store nesting level
|
||||||
|
|
||||||
|
struct ManagedNode;
|
||||||
|
using SharedNode = shared_pointer<ManagedNode>;
|
||||||
|
|
||||||
|
struct ManagedNode : Markup::ManagedNode {
|
||||||
protected:
|
protected:
|
||||||
//test to verify if a valid character for a node name
|
//test to verify if a valid character for a node name
|
||||||
bool valid(char p) const { //A-Z, a-z, 0-9, -.
|
bool valid(char p) const { //A-Z, a-z, 0-9, -.
|
||||||
|
@ -32,7 +37,7 @@ protected:
|
||||||
unsigned length = 0;
|
unsigned length = 0;
|
||||||
while(valid(p[length])) length++;
|
while(valid(p[length])) length++;
|
||||||
if(length == 0) throw "Invalid node name";
|
if(length == 0) throw "Invalid node name";
|
||||||
name = substr(p, 0, length);
|
_name = substr(p, 0, length);
|
||||||
p += length;
|
p += length;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -41,18 +46,18 @@ protected:
|
||||||
unsigned length = 2;
|
unsigned length = 2;
|
||||||
while(p[length] && p[length] != '\n' && p[length] != '\"') length++;
|
while(p[length] && p[length] != '\n' && p[length] != '\"') length++;
|
||||||
if(p[length] != '\"') throw "Unescaped value";
|
if(p[length] != '\"') throw "Unescaped value";
|
||||||
data = {substr(p, 2, length - 2), "\n"};
|
_value = {substr(p, 2, length - 2), "\n"};
|
||||||
p += length + 1;
|
p += length + 1;
|
||||||
} else if(*p == '=') {
|
} else if(*p == '=') {
|
||||||
unsigned length = 1;
|
unsigned length = 1;
|
||||||
while(p[length] && p[length] != '\n' && p[length] != '\"' && p[length] != ' ') length++;
|
while(p[length] && p[length] != '\n' && p[length] != '\"' && p[length] != ' ') length++;
|
||||||
if(p[length] == '\"') throw "Illegal character in value";
|
if(p[length] == '\"') throw "Illegal character in value";
|
||||||
data = {substr(p, 1, length - 1), "\n"};
|
_value = {substr(p, 1, length - 1), "\n"};
|
||||||
p += length;
|
p += length;
|
||||||
} else if(*p == ':') {
|
} else if(*p == ':') {
|
||||||
unsigned length = 1;
|
unsigned length = 1;
|
||||||
while(p[length] && p[length] != '\n') length++;
|
while(p[length] && p[length] != '\n') length++;
|
||||||
data = {substr(p, 1, length - 1), "\n"};
|
_value = {substr(p, 1, length - 1), "\n"};
|
||||||
p += length;
|
p += length;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -64,41 +69,40 @@ protected:
|
||||||
while(*p == ' ') p++; //skip excess spaces
|
while(*p == ' ') p++; //skip excess spaces
|
||||||
if(*(p + 0) == '/' && *(p + 1) == '/') break; //skip comments
|
if(*(p + 0) == '/' && *(p + 1) == '/') break; //skip comments
|
||||||
|
|
||||||
Node node;
|
SharedNode node(new ManagedNode);
|
||||||
node.attribute = true;
|
|
||||||
unsigned length = 0;
|
unsigned length = 0;
|
||||||
while(valid(p[length])) length++;
|
while(valid(p[length])) length++;
|
||||||
if(length == 0) throw "Invalid attribute name";
|
if(length == 0) throw "Invalid attribute name";
|
||||||
node.name = substr(p, 0, length);
|
node->_name = substr(p, 0, length);
|
||||||
node.parseData(p += length);
|
node->parseData(p += length);
|
||||||
node.data.rtrim("\n");
|
node->_value.rtrim("\n");
|
||||||
children.append(node);
|
_children.append(node);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
//read a node and all of its child nodes
|
//read a node and all of its child nodes
|
||||||
void parseNode(const lstring& text, unsigned& y) {
|
void parseNode(const lstring& text, unsigned& y) {
|
||||||
const char* p = text[y++];
|
const char* p = text[y++];
|
||||||
level = parseDepth(p);
|
_metadata = parseDepth(p);
|
||||||
parseName(p);
|
parseName(p);
|
||||||
parseData(p);
|
parseData(p);
|
||||||
parseAttributes(p);
|
parseAttributes(p);
|
||||||
|
|
||||||
while(y < text.size()) {
|
while(y < text.size()) {
|
||||||
unsigned depth = readDepth(text[y]);
|
unsigned depth = readDepth(text[y]);
|
||||||
if(depth <= level) break;
|
if(depth <= _metadata) break;
|
||||||
|
|
||||||
if(text[y][depth] == ':') {
|
if(text[y][depth] == ':') {
|
||||||
data.append(substr(text[y++], depth + 1), "\n");
|
_value.append(substr(text[y++], depth + 1), "\n");
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
Node node;
|
SharedNode node(new ManagedNode);
|
||||||
node.parseNode(text, y);
|
node->parseNode(text, y);
|
||||||
children.append(node);
|
_children.append(node);
|
||||||
}
|
}
|
||||||
|
|
||||||
data.rtrim("\n");
|
_value.rtrim("\n");
|
||||||
}
|
}
|
||||||
|
|
||||||
//read top-level nodes
|
//read top-level nodes
|
||||||
|
@ -120,36 +124,58 @@ protected:
|
||||||
|
|
||||||
unsigned y = 0;
|
unsigned y = 0;
|
||||||
while(y < text.size()) {
|
while(y < text.size()) {
|
||||||
Node node;
|
SharedNode node(new ManagedNode);
|
||||||
node.parseNode(text, y);
|
node->parseNode(text, y);
|
||||||
if(node.level > 0) throw "Root nodes cannot be indented";
|
if(node->_metadata > 0) throw "Root nodes cannot be indented";
|
||||||
children.append(node);
|
_children.append(node);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
friend class Document;
|
friend auto unserialize(const string&) -> Markup::Node;
|
||||||
};
|
};
|
||||||
|
|
||||||
struct Document : Node {
|
inline auto unserialize(const string& markup) -> Markup::Node {
|
||||||
string error;
|
SharedNode node(new ManagedNode);
|
||||||
|
try {
|
||||||
|
node->parse(markup);
|
||||||
|
} catch(const char* error) {
|
||||||
|
node.reset();
|
||||||
|
}
|
||||||
|
return (Markup::SharedNode&)node;
|
||||||
|
}
|
||||||
|
|
||||||
bool load(const string& document) {
|
inline auto serialize(const Markup::Node& node, unsigned depth = 0) -> string {
|
||||||
name = "", data = "";
|
if(!node.name()) {
|
||||||
|
string result;
|
||||||
try {
|
for(auto leaf : node) {
|
||||||
parse(document);
|
result.append(serialize(leaf, depth));
|
||||||
} catch(const char* error) {
|
|
||||||
this->error = error;
|
|
||||||
children.reset();
|
|
||||||
return false;
|
|
||||||
}
|
}
|
||||||
return true;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
Document(const string& document = "") {
|
string padding;
|
||||||
load(document);
|
padding.resize(depth * 2);
|
||||||
|
for(auto& byte : padding) byte = ' ';
|
||||||
|
|
||||||
|
lstring lines;
|
||||||
|
if(auto value = node.value()) lines = value.split("\n");
|
||||||
|
|
||||||
|
string result;
|
||||||
|
result.append(padding);
|
||||||
|
result.append(node.name());
|
||||||
|
if(lines.size() == 1) result.append(":", lines[0]);
|
||||||
|
result.append("\n");
|
||||||
|
if(lines.size() > 1) {
|
||||||
|
padding.append(" ");
|
||||||
|
for(auto& line : lines) {
|
||||||
|
result.append(padding, ":", line, "\n");
|
||||||
|
}
|
||||||
}
|
}
|
||||||
};
|
for(auto leaf : node) {
|
||||||
|
result.append(serialize(leaf, depth + 1));
|
||||||
|
}
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,14 +0,0 @@
|
||||||
#ifdef NALL_STRING_INTERNAL_HPP
|
|
||||||
|
|
||||||
namespace nall {
|
|
||||||
namespace Markup {
|
|
||||||
|
|
||||||
inline Node Document(const string& markup) {
|
|
||||||
if(markup.beginsWith("<")) return XML::Document(markup);
|
|
||||||
return BML::Document(markup);
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#endif
|
|
|
@ -0,0 +1,135 @@
|
||||||
|
#ifdef NALL_STRING_INTERNAL_HPP
|
||||||
|
|
||||||
|
namespace nall {
|
||||||
|
namespace Markup {
|
||||||
|
|
||||||
|
auto ManagedNode::_evaluate(string query) const -> bool {
|
||||||
|
if(!query) return true;
|
||||||
|
|
||||||
|
for(auto& rule : query.replace(" ", "").split(",")) {
|
||||||
|
enum class Comparator : unsigned { ID, EQ, NE, LT, LE, GT, GE };
|
||||||
|
auto comparator = Comparator::ID;
|
||||||
|
if(rule.match("*!=*")) comparator = Comparator::NE;
|
||||||
|
else if(rule.match("*<=*")) comparator = Comparator::LE;
|
||||||
|
else if(rule.match("*>=*")) comparator = Comparator::GE;
|
||||||
|
else if(rule.match ("*=*")) comparator = Comparator::EQ;
|
||||||
|
else if(rule.match ("*<*")) comparator = Comparator::LT;
|
||||||
|
else if(rule.match ("*>*")) comparator = Comparator::GT;
|
||||||
|
|
||||||
|
if(comparator == Comparator::ID) {
|
||||||
|
if(_find(rule).size()) continue;
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
lstring side;
|
||||||
|
switch(comparator) {
|
||||||
|
case Comparator::EQ: side = rule.split<1> ("="); break;
|
||||||
|
case Comparator::NE: side = rule.split<1>("!="); break;
|
||||||
|
case Comparator::LT: side = rule.split<1> ("<"); break;
|
||||||
|
case Comparator::LE: side = rule.split<1>("<="); break;
|
||||||
|
case Comparator::GT: side = rule.split<1> (">"); break;
|
||||||
|
case Comparator::GE: side = rule.split<1>(">="); break;
|
||||||
|
}
|
||||||
|
|
||||||
|
string data = string{_value}.strip();
|
||||||
|
if(side(0).empty() == false) {
|
||||||
|
auto result = _find(side(0));
|
||||||
|
if(result.size() == 0) return false;
|
||||||
|
data = result[0].value();
|
||||||
|
}
|
||||||
|
|
||||||
|
switch(comparator) {
|
||||||
|
case Comparator::EQ: if(data.match(side(1)) == true) continue; break;
|
||||||
|
case Comparator::NE: if(data.match(side(1)) == false) continue; break;
|
||||||
|
case Comparator::LT: if(numeral(data) < numeral(side(1))) continue; break;
|
||||||
|
case Comparator::LE: if(numeral(data) <= numeral(side(1))) continue; break;
|
||||||
|
case Comparator::GT: if(numeral(data) > numeral(side(1))) continue; break;
|
||||||
|
case Comparator::GE: if(numeral(data) >= numeral(side(1))) continue; break;
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
auto ManagedNode::_find(const string& query) const -> vector<Node> {
|
||||||
|
vector<Node> result;
|
||||||
|
|
||||||
|
lstring path = query.split("/");
|
||||||
|
string name = path.take(0), rule;
|
||||||
|
unsigned lo = 0u, hi = ~0u;
|
||||||
|
|
||||||
|
if(name.match("*[*]")) {
|
||||||
|
auto p = name.rtrim("]").split<1>("[");
|
||||||
|
name = p(0);
|
||||||
|
if(p(1).find("-")) {
|
||||||
|
p = p(1).split<1>("-");
|
||||||
|
lo = p(0).empty() ? 0u : numeral(p(0));
|
||||||
|
hi = p(1).empty() ? ~0u : numeral(p(1));
|
||||||
|
} else {
|
||||||
|
lo = hi = numeral(p(1));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if(name.match("*(*)")) {
|
||||||
|
auto p = name.rtrim(")").split<1>("(");
|
||||||
|
name = p(0);
|
||||||
|
rule = p(1);
|
||||||
|
}
|
||||||
|
|
||||||
|
unsigned position = 0;
|
||||||
|
for(auto& node : _children) {
|
||||||
|
if(!node->_name.match(name)) continue;
|
||||||
|
if(!node->_evaluate(rule)) continue;
|
||||||
|
|
||||||
|
bool inrange = position >= lo && position <= hi;
|
||||||
|
position++;
|
||||||
|
if(!inrange) continue;
|
||||||
|
|
||||||
|
if(path.size() == 0) {
|
||||||
|
result.append(node);
|
||||||
|
} else for(auto& item : node->_find(path.merge("/"))) {
|
||||||
|
result.append(item);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
auto ManagedNode::_lookup(const string& path) const -> Node {
|
||||||
|
if(auto position = path.find("/")) {
|
||||||
|
auto name = path.slice(0, *position);
|
||||||
|
for(auto& node : _children) {
|
||||||
|
if(name == node->_name) {
|
||||||
|
return node->_lookup(path.slice(*position + 1));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else for(auto& node : _children) {
|
||||||
|
if(path == node->_name) return node;
|
||||||
|
}
|
||||||
|
return {};
|
||||||
|
}
|
||||||
|
|
||||||
|
auto ManagedNode::_create(const string& path) -> Node {
|
||||||
|
if(auto position = path.find("/")) {
|
||||||
|
auto name = path.slice(0, *position);
|
||||||
|
for(auto& node : _children) {
|
||||||
|
if(name == node->_name) {
|
||||||
|
return node->_create(path.slice(*position + 1));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
_children.append(new ManagedNode(name));
|
||||||
|
return _children.last()->_create(path.slice(*position + 1));
|
||||||
|
}
|
||||||
|
for(auto& node : _children) {
|
||||||
|
if(path == node->_name) return node;
|
||||||
|
}
|
||||||
|
_children.append(new ManagedNode(path));
|
||||||
|
return _children.last();
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif
|
|
@ -1,151 +1,123 @@
|
||||||
#ifdef NALL_STRING_INTERNAL_HPP
|
#ifdef NALL_STRING_INTERNAL_HPP
|
||||||
|
|
||||||
//note: specific markups inherit from Markup::Node
|
|
||||||
//vector<Node> will slice any data; so derived nodes must not contain data nor virtual functions
|
|
||||||
//vector<Node*> would incur a large performance penalty and greatly increased complexity
|
|
||||||
|
|
||||||
namespace nall {
|
namespace nall {
|
||||||
namespace Markup {
|
namespace Markup {
|
||||||
|
|
||||||
struct Node {
|
struct Node;
|
||||||
string name;
|
struct ManagedNode;
|
||||||
string data;
|
using SharedNode = shared_pointer<ManagedNode>;
|
||||||
bool attribute;
|
|
||||||
|
|
||||||
bool exists() const {
|
struct ManagedNode {
|
||||||
return !name.empty();
|
ManagedNode() = default;
|
||||||
|
ManagedNode(const string& name) : _name(name) {}
|
||||||
|
ManagedNode(const string& name, const string& value) : _name(name), _value(value) {}
|
||||||
|
|
||||||
|
auto clone() const -> SharedNode {
|
||||||
|
SharedNode clone(new ManagedNode(_name, _value));
|
||||||
|
for(auto& child : _children) clone->_children.append(child->clone());
|
||||||
|
return clone;
|
||||||
}
|
}
|
||||||
|
|
||||||
string text() const {
|
|
||||||
return string{data}.strip();
|
|
||||||
}
|
|
||||||
|
|
||||||
bool boolean() const {
|
|
||||||
return text() != "false";
|
|
||||||
}
|
|
||||||
|
|
||||||
intmax_t integer() const {
|
|
||||||
return numeral(text());
|
|
||||||
}
|
|
||||||
|
|
||||||
uintmax_t decimal() const {
|
|
||||||
return numeral(text());
|
|
||||||
}
|
|
||||||
|
|
||||||
void reset() {
|
|
||||||
children.reset();
|
|
||||||
}
|
|
||||||
|
|
||||||
bool evaluate(const string& query) const {
|
|
||||||
if(query.empty()) return true;
|
|
||||||
lstring rules = string{query}.replace(" ", "").split(",");
|
|
||||||
|
|
||||||
for(auto& rule : rules) {
|
|
||||||
enum class Comparator : unsigned { ID, EQ, NE, LT, LE, GT, GE };
|
|
||||||
auto comparator = Comparator::ID;
|
|
||||||
if(rule.match("*!=*")) comparator = Comparator::NE;
|
|
||||||
else if(rule.match("*<=*")) comparator = Comparator::LE;
|
|
||||||
else if(rule.match("*>=*")) comparator = Comparator::GE;
|
|
||||||
else if(rule.match ("*=*")) comparator = Comparator::EQ;
|
|
||||||
else if(rule.match ("*<*")) comparator = Comparator::LT;
|
|
||||||
else if(rule.match ("*>*")) comparator = Comparator::GT;
|
|
||||||
|
|
||||||
if(comparator == Comparator::ID) {
|
|
||||||
if(find(rule).size()) continue;
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
lstring side;
|
|
||||||
switch(comparator) {
|
|
||||||
case Comparator::EQ: side = rule.split<1> ("="); break;
|
|
||||||
case Comparator::NE: side = rule.split<1>("!="); break;
|
|
||||||
case Comparator::LT: side = rule.split<1> ("<"); break;
|
|
||||||
case Comparator::LE: side = rule.split<1>("<="); break;
|
|
||||||
case Comparator::GT: side = rule.split<1> (">"); break;
|
|
||||||
case Comparator::GE: side = rule.split<1>(">="); break;
|
|
||||||
}
|
|
||||||
|
|
||||||
string data = text();
|
|
||||||
if(side(0).empty() == false) {
|
|
||||||
auto result = find(side(0));
|
|
||||||
if(result.size() == 0) return false;
|
|
||||||
data = result(0).data;
|
|
||||||
}
|
|
||||||
|
|
||||||
switch(comparator) {
|
|
||||||
case Comparator::EQ: if(data.match(side(1)) == true) continue; break;
|
|
||||||
case Comparator::NE: if(data.match(side(1)) == false) continue; break;
|
|
||||||
case Comparator::LT: if(numeral(data) < numeral(side(1))) continue; break;
|
|
||||||
case Comparator::LE: if(numeral(data) <= numeral(side(1))) continue; break;
|
|
||||||
case Comparator::GT: if(numeral(data) > numeral(side(1))) continue; break;
|
|
||||||
case Comparator::GE: if(numeral(data) >= numeral(side(1))) continue; break;
|
|
||||||
}
|
|
||||||
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
vector<Node> find(const string& query) const {
|
|
||||||
vector<Node> result;
|
|
||||||
|
|
||||||
lstring path = query.split("/");
|
|
||||||
string name = path.take(0), rule;
|
|
||||||
unsigned lo = 0u, hi = ~0u;
|
|
||||||
|
|
||||||
if(name.match("*[*]")) {
|
|
||||||
lstring side = name.split<1>("[");
|
|
||||||
name = side(0);
|
|
||||||
side = side(1).rtrim("]").split<1>("-");
|
|
||||||
lo = side(0).empty() ? 0u : numeral(side(0));
|
|
||||||
hi = side(1).empty() ? ~0u : numeral(side(1));
|
|
||||||
}
|
|
||||||
|
|
||||||
if(name.match("*(*)")) {
|
|
||||||
lstring side = name.split<1>("(");
|
|
||||||
name = side(0);
|
|
||||||
rule = side(1).rtrim(")");
|
|
||||||
}
|
|
||||||
|
|
||||||
unsigned position = 0;
|
|
||||||
for(auto& node : children) {
|
|
||||||
if(node.name.match(name) == false) continue;
|
|
||||||
if(node.evaluate(rule) == false) continue;
|
|
||||||
|
|
||||||
bool inrange = position >= lo && position <= hi;
|
|
||||||
position++;
|
|
||||||
if(inrange == false) continue;
|
|
||||||
|
|
||||||
if(path.size() == 0) result.append(node);
|
|
||||||
else {
|
|
||||||
auto list = node.find(path.merge("/"));
|
|
||||||
for(auto& item : list) result.append(item);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
Node operator[](const string& query) const {
|
|
||||||
auto result = find(query);
|
|
||||||
return result(0);
|
|
||||||
}
|
|
||||||
|
|
||||||
vector<Node>::iterator begin() { return children.begin(); }
|
|
||||||
vector<Node>::iterator end() { return children.end(); }
|
|
||||||
|
|
||||||
const vector<Node>::constIterator begin() const { return children.begin(); }
|
|
||||||
const vector<Node>::constIterator end() const { return children.end(); }
|
|
||||||
|
|
||||||
Node() : attribute(false), level(0) {}
|
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
unsigned level;
|
string _name;
|
||||||
vector<Node> children;
|
string _value;
|
||||||
|
uintptr_t _metadata = 0;
|
||||||
|
vector<SharedNode> _children;
|
||||||
|
|
||||||
|
inline auto _evaluate(string query) const -> bool;
|
||||||
|
inline auto _find(const string& query) const -> vector<Node>;
|
||||||
|
inline auto _lookup(const string& path) const -> Node;
|
||||||
|
inline auto _create(const string& path) -> Node;
|
||||||
|
|
||||||
|
friend class Node;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct Node {
|
||||||
|
Node() : shared(new ManagedNode) {}
|
||||||
|
Node(const SharedNode& source) : shared(source ? source : new ManagedNode) {}
|
||||||
|
Node(const string& name) : shared(new ManagedNode(name)) {}
|
||||||
|
Node(const string& name, const string& value) : shared(new ManagedNode(name, value)) {}
|
||||||
|
|
||||||
|
auto unique() const -> bool { return shared.unique(); }
|
||||||
|
auto clone() const -> Node { return shared->clone(); }
|
||||||
|
|
||||||
|
explicit operator bool() const { return shared->_name || shared->_children; }
|
||||||
|
auto name() const -> string { return shared->_name; }
|
||||||
|
auto value() const -> string { return shared->_value; }
|
||||||
|
|
||||||
|
auto text() const -> string { return value().strip(); }
|
||||||
|
auto boolean() const -> bool { return text() == "true"; }
|
||||||
|
auto integer() const -> intmax_t { return text().numeral(); }
|
||||||
|
auto decimal() const -> uintmax_t { return text().numeral(); }
|
||||||
|
|
||||||
|
auto setName(const string& name = "") -> void { shared->_name = name; }
|
||||||
|
auto setValue(const string& value = "") -> void { shared->_value = value; }
|
||||||
|
|
||||||
|
auto reset() -> void { shared->_children.reset(); }
|
||||||
|
auto size() const -> unsigned { return shared->_children.size(); }
|
||||||
|
|
||||||
|
auto prepend(const Node& node) -> void { shared->_children.prepend(node.shared); }
|
||||||
|
auto append(const Node& node) -> void { shared->_children.append(node.shared); }
|
||||||
|
auto remove(const Node& node) -> bool {
|
||||||
|
for(auto n : range(size())) {
|
||||||
|
if(node.shared == shared->_children[n]) {
|
||||||
|
return shared->_children.remove(n), true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
auto at(unsigned position) const -> Node {
|
||||||
|
if(position >= size()) return {};
|
||||||
|
return shared->_children[position];
|
||||||
|
}
|
||||||
|
|
||||||
|
auto swap(unsigned x, unsigned y) -> bool {
|
||||||
|
if(x >= size() || y >= size()) return false;
|
||||||
|
return std::swap(shared->_children[x], shared->_children[y]), true;
|
||||||
|
}
|
||||||
|
|
||||||
|
auto insert(unsigned position, const Node& node) -> bool {
|
||||||
|
if(position > size()) return false; //used > instead of >= to allow indexed-equivalent of append()
|
||||||
|
return shared->_children.insert(position, node.shared), true;
|
||||||
|
}
|
||||||
|
|
||||||
|
auto remove(unsigned position) -> bool {
|
||||||
|
if(position >= size()) return false;
|
||||||
|
return shared->_children.remove(position), true;
|
||||||
|
}
|
||||||
|
|
||||||
|
auto operator()(const string& path) -> Node { return shared->_create(path); }
|
||||||
|
auto operator[](const string& path) const -> Node { return shared->_lookup(path); }
|
||||||
|
auto find(const string& query) const -> vector<Node> { return shared->_find(query); }
|
||||||
|
|
||||||
|
struct iterator {
|
||||||
|
auto operator*() -> Node { return {source.shared->_children[position]}; }
|
||||||
|
auto operator!=(const iterator& source) const -> bool { return position != source.position; }
|
||||||
|
auto operator++() -> iterator& { return position++, *this; }
|
||||||
|
iterator(const Node& source, unsigned position) : source(source), position(position) {}
|
||||||
|
|
||||||
|
private:
|
||||||
|
const Node& source;
|
||||||
|
unsigned position;
|
||||||
|
};
|
||||||
|
|
||||||
|
auto begin() const -> iterator { return iterator(*this, 0); }
|
||||||
|
auto end() const -> iterator { return iterator(*this, size()); }
|
||||||
|
|
||||||
|
protected:
|
||||||
|
SharedNode shared;
|
||||||
};
|
};
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
namespace nall {
|
||||||
|
|
||||||
|
inline range_t range(const Markup::Node& node) {
|
||||||
|
return range_t{0, (signed)node.size(), 1};
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
|
@ -1,21 +1,29 @@
|
||||||
#ifdef NALL_STRING_INTERNAL_HPP
|
#ifdef NALL_STRING_INTERNAL_HPP
|
||||||
|
|
||||||
//XML v1.0 subset parser
|
//XML v1.0 subset parser
|
||||||
//revision 0.03
|
//revision 0.04
|
||||||
|
|
||||||
namespace nall {
|
namespace nall {
|
||||||
namespace XML {
|
namespace XML {
|
||||||
|
|
||||||
struct Node : Markup::Node {
|
//metadata:
|
||||||
|
// 0 = element
|
||||||
|
// 1 = attribute
|
||||||
|
|
||||||
|
struct ManagedNode;
|
||||||
|
using SharedNode = shared_pointer<ManagedNode>;
|
||||||
|
|
||||||
|
struct ManagedNode : Markup::ManagedNode {
|
||||||
protected:
|
protected:
|
||||||
inline string escape() const {
|
inline string escape() const {
|
||||||
string result = data;
|
string result = _value;
|
||||||
result.replace("&", "&");
|
result.replace("&", "&");
|
||||||
result.replace("<", "<");
|
result.replace("<", "<");
|
||||||
result.replace(">", ">");
|
result.replace(">", ">");
|
||||||
if(attribute == false) return result;
|
if(_metadata == 1) {
|
||||||
result.replace("\'", "'");
|
result.replace("\'", "'");
|
||||||
result.replace("\"", """);
|
result.replace("\"", """);
|
||||||
|
}
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -54,7 +62,7 @@ protected:
|
||||||
if(!memory::compare(source, """, 6)) { *output++ = '\"'; source += 6; length -= 6; continue; }
|
if(!memory::compare(source, """, 6)) { *output++ = '\"'; source += 6; length -= 6; continue; }
|
||||||
}
|
}
|
||||||
|
|
||||||
if(attribute == false && source[0] == '<' && source[1] == '!') {
|
if(_metadata == 0 && source[0] == '<' && source[1] == '!') {
|
||||||
//comment
|
//comment
|
||||||
if(!memory::compare(source, "<!--", 4)) {
|
if(!memory::compare(source, "<!--", 4)) {
|
||||||
source += 4, length -= 4;
|
source += 4, length -= 4;
|
||||||
|
@ -117,8 +125,8 @@ protected:
|
||||||
const char* nameStart = ++p; //skip '<'
|
const char* nameStart = ++p; //skip '<'
|
||||||
while(isName(*p)) p++;
|
while(isName(*p)) p++;
|
||||||
const char* nameEnd = p;
|
const char* nameEnd = p;
|
||||||
copy(name, nameStart, nameEnd - nameStart);
|
copy(_name, nameStart, nameEnd - nameStart);
|
||||||
if(name.empty()) throw "missing element name";
|
if(_name.empty()) throw "missing element name";
|
||||||
|
|
||||||
//parse attributes
|
//parse attributes
|
||||||
while(*p) {
|
while(*p) {
|
||||||
|
@ -127,14 +135,14 @@ protected:
|
||||||
if(*p == '?' || *p == '/' || *p == '>') break;
|
if(*p == '?' || *p == '/' || *p == '>') break;
|
||||||
|
|
||||||
//parse attribute name
|
//parse attribute name
|
||||||
Node attribute;
|
SharedNode attribute(new ManagedNode);
|
||||||
attribute.attribute = true;
|
attribute->_metadata = 1;
|
||||||
|
|
||||||
const char* nameStart = p;
|
const char* nameStart = p;
|
||||||
while(isName(*p)) p++;
|
while(isName(*p)) p++;
|
||||||
const char* nameEnd = p;
|
const char* nameEnd = p;
|
||||||
copy(attribute.name, nameStart, nameEnd - nameStart);
|
copy(attribute->_name, nameStart, nameEnd - nameStart);
|
||||||
if(attribute.name.empty()) throw "missing attribute name";
|
if(attribute->_name.empty()) throw "missing attribute name";
|
||||||
|
|
||||||
//parse attribute data
|
//parse attribute data
|
||||||
if(*p++ != '=') throw "missing attribute value";
|
if(*p++ != '=') throw "missing attribute value";
|
||||||
|
@ -145,8 +153,8 @@ protected:
|
||||||
if(!*p) throw "missing attribute data terminal";
|
if(!*p) throw "missing attribute data terminal";
|
||||||
const char* dataEnd = p++; //skip closing terminal
|
const char* dataEnd = p++; //skip closing terminal
|
||||||
|
|
||||||
copy(attribute.data, dataStart, dataEnd - dataStart);
|
copy(attribute->_value, dataStart, dataEnd - dataStart);
|
||||||
children.append(attribute);
|
_children.append(attribute);
|
||||||
}
|
}
|
||||||
|
|
||||||
//parse closure
|
//parse closure
|
||||||
|
@ -158,9 +166,9 @@ protected:
|
||||||
|
|
||||||
//parse element and all of its child elements
|
//parse element and all of its child elements
|
||||||
inline void parseElement(const char*& p) {
|
inline void parseElement(const char*& p) {
|
||||||
Node node;
|
SharedNode node(new ManagedNode);
|
||||||
if(node.parseHead(p) == false) node.parse(p);
|
if(node->parseHead(p) == false) node->parse(p);
|
||||||
children.append(node);
|
_children.append(node);
|
||||||
}
|
}
|
||||||
|
|
||||||
//return true if </tag> matches this node's name
|
//return true if </tag> matches this node's name
|
||||||
|
@ -171,7 +179,7 @@ protected:
|
||||||
while(*p && *p != '>') p++;
|
while(*p && *p != '>') p++;
|
||||||
if(*p != '>') throw "unclosed closure element";
|
if(*p != '>') throw "unclosed closure element";
|
||||||
const char* nameEnd = p++;
|
const char* nameEnd = p++;
|
||||||
if(memory::compare(name.data(), nameStart, nameEnd - nameStart)) throw "closure element name mismatch";
|
if(memory::compare(_name.data(), nameStart, nameEnd - nameStart)) throw "closure element name mismatch";
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -189,30 +197,24 @@ protected:
|
||||||
parseElement(p);
|
parseElement(p);
|
||||||
}
|
}
|
||||||
|
|
||||||
copy(data, dataStart, dataEnd - dataStart);
|
copy(_value, dataStart, dataEnd - dataStart);
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
struct Document : Node {
|
|
||||||
string error;
|
|
||||||
|
|
||||||
inline bool load(const char* document) {
|
|
||||||
if(document == nullptr) return false;
|
|
||||||
reset();
|
|
||||||
try {
|
|
||||||
parse(document);
|
|
||||||
} catch(const char* error) {
|
|
||||||
reset();
|
|
||||||
this->error = error;
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
return true;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
inline Document() {}
|
friend auto unserialize(const string&) -> Markup::SharedNode;
|
||||||
inline Document(const char* document) { load(document); }
|
|
||||||
};
|
};
|
||||||
|
|
||||||
|
inline auto unserialize(const string& markup) -> Markup::SharedNode {
|
||||||
|
auto node = new ManagedNode;
|
||||||
|
try {
|
||||||
|
const char* p = markup;
|
||||||
|
node->parse(p);
|
||||||
|
} catch(const char* error) {
|
||||||
|
delete node;
|
||||||
|
node = nullptr;
|
||||||
|
}
|
||||||
|
return node;
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -5,6 +5,7 @@
|
||||||
#include <utility>
|
#include <utility>
|
||||||
|
|
||||||
namespace nall {
|
namespace nall {
|
||||||
|
using std::nullptr_t;
|
||||||
using std::forward;
|
using std::forward;
|
||||||
using std::move;
|
using std::move;
|
||||||
using std::decay;
|
using std::decay;
|
||||||
|
|
|
@ -8,6 +8,7 @@
|
||||||
#include <nall/algorithm.hpp>
|
#include <nall/algorithm.hpp>
|
||||||
#include <nall/bit.hpp>
|
#include <nall/bit.hpp>
|
||||||
#include <nall/maybe.hpp>
|
#include <nall/maybe.hpp>
|
||||||
|
#include <nall/memory.hpp>
|
||||||
#include <nall/sort.hpp>
|
#include <nall/sort.hpp>
|
||||||
#include <nall/utility.hpp>
|
#include <nall/utility.hpp>
|
||||||
|
|
||||||
|
@ -43,7 +44,7 @@ public:
|
||||||
void reset() {
|
void reset() {
|
||||||
if(pool) {
|
if(pool) {
|
||||||
for(unsigned n = 0; n < objectsize; n++) pool[poolbase + n].~T();
|
for(unsigned n = 0; n < objectsize; n++) pool[poolbase + n].~T();
|
||||||
free(pool);
|
memory::free(pool);
|
||||||
}
|
}
|
||||||
pool = nullptr;
|
pool = nullptr;
|
||||||
poolbase = 0;
|
poolbase = 0;
|
||||||
|
@ -55,7 +56,7 @@ public:
|
||||||
if(size <= poolsize) return;
|
if(size <= poolsize) return;
|
||||||
size = bit::round(size); //amortize growth
|
size = bit::round(size); //amortize growth
|
||||||
|
|
||||||
T* copy = (T*)calloc(size, sizeof(T));
|
T* copy = (T*)memory::allocate(size * sizeof(T));
|
||||||
for(unsigned n = 0; n < objectsize; n++) new(copy + n) T(std::move(pool[poolbase + n]));
|
for(unsigned n = 0; n < objectsize; n++) new(copy + n) T(std::move(pool[poolbase + n]));
|
||||||
free(pool);
|
free(pool);
|
||||||
pool = copy;
|
pool = copy;
|
||||||
|
@ -63,9 +64,10 @@ public:
|
||||||
poolsize = size;
|
poolsize = size;
|
||||||
}
|
}
|
||||||
|
|
||||||
void resize(unsigned size) {
|
void resize(unsigned size, T value = T()) {
|
||||||
T* copy = (T*)calloc(size, sizeof(T));
|
T* copy = (T*)memory::allocate(size * sizeof(T));
|
||||||
for(unsigned n = 0; n < size && n < objectsize; n++) new(copy + n) T(std::move(pool[poolbase + n]));
|
for(unsigned n = 0; n < size && n < objectsize; n++) new(copy + n) T(std::move(pool[poolbase + n]));
|
||||||
|
for(unsigned n = objectsize; n < size; n++) new(copy + n) T(value);
|
||||||
reset();
|
reset();
|
||||||
pool = copy;
|
pool = copy;
|
||||||
poolbase = 0;
|
poolbase = 0;
|
||||||
|
|
|
@ -12,32 +12,32 @@ void OpenGL::shader(const char* pathname) {
|
||||||
|
|
||||||
unsigned historySize = 0;
|
unsigned historySize = 0;
|
||||||
if(pathname) {
|
if(pathname) {
|
||||||
auto document = Markup::Document(file::read({pathname, "manifest.bml"}));
|
auto document = BML::unserialize(file::read({pathname, "manifest.bml"}));
|
||||||
|
|
||||||
for(auto& node : document["settings"]) {
|
for(auto node : document["settings"]) {
|
||||||
settings.insert({node.name, node.text()});
|
settings.insert({node.name(), node.text()});
|
||||||
}
|
}
|
||||||
|
|
||||||
for(auto& node : document["input"]) {
|
for(auto node : document["input"]) {
|
||||||
if(node.name == "history") historySize = node.decimal();
|
if(node.name() == "history") historySize = node.decimal();
|
||||||
if(node.name == "format") format = glrFormat(node.text());
|
if(node.name() == "format") format = glrFormat(node.text());
|
||||||
if(node.name == "filter") filter = glrFilter(node.text());
|
if(node.name() == "filter") filter = glrFilter(node.text());
|
||||||
if(node.name == "wrap") wrap = glrWrap(node.text());
|
if(node.name() == "wrap") wrap = glrWrap(node.text());
|
||||||
}
|
}
|
||||||
|
|
||||||
for(auto& node : document["output"]) {
|
for(auto node : document["output"]) {
|
||||||
string text = node.text();
|
string text = node.text();
|
||||||
if(node.name == "width") {
|
if(node.name() == "width") {
|
||||||
if(text.endsWith("%")) relativeWidth = real(text.rtrim("%")) / 100.0;
|
if(text.endsWith("%")) relativeWidth = real(text.rtrim("%")) / 100.0;
|
||||||
else absoluteWidth = decimal(text);
|
else absoluteWidth = decimal(text);
|
||||||
}
|
}
|
||||||
if(node.name == "height") {
|
if(node.name() == "height") {
|
||||||
if(text.endsWith("%")) relativeHeight = real(text.rtrim("%")) / 100.0;
|
if(text.endsWith("%")) relativeHeight = real(text.rtrim("%")) / 100.0;
|
||||||
else absoluteHeight = decimal(text);
|
else absoluteHeight = decimal(text);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
for(auto& node : document.find("program")) {
|
for(auto node : document.find("program")) {
|
||||||
unsigned n = programs.size();
|
unsigned n = programs.size();
|
||||||
programs(n).bind(this, node, pathname);
|
programs(n).bind(this, node, pathname);
|
||||||
}
|
}
|
||||||
|
|
|
@ -54,9 +54,9 @@ void OpenGLProgram::bind(OpenGL* instance, const Markup::Node& node, const strin
|
||||||
pixmaps(n).format = format;
|
pixmaps(n).format = format;
|
||||||
pixmaps(n).filter = filter;
|
pixmaps(n).filter = filter;
|
||||||
pixmaps(n).wrap = wrap;
|
pixmaps(n).wrap = wrap;
|
||||||
if(leaf["format"].exists()) pixmaps(n).format = glrFormat(leaf["format"].text());
|
if(leaf["format"]) pixmaps(n).format = glrFormat(leaf["format"].text());
|
||||||
if(leaf["filter"].exists()) pixmaps(n).filter = glrFilter(leaf["filter"].text());
|
if(leaf["filter"]) pixmaps(n).filter = glrFilter(leaf["filter"].text());
|
||||||
if(leaf["wrap"].exists()) pixmaps(n).wrap = glrWrap(leaf["wrap"].text());
|
if(leaf["wrap"]) pixmaps(n).wrap = glrWrap(leaf["wrap"].text());
|
||||||
|
|
||||||
unsigned w = glrSize(image.width), h = glrSize(image.height);
|
unsigned w = glrSize(image.width), h = glrSize(image.height);
|
||||||
uint32_t* buffer = new uint32_t[w * h]();
|
uint32_t* buffer = new uint32_t[w * h]();
|
||||||
|
|
|
@ -115,7 +115,7 @@ void Cartridge::load() {
|
||||||
|
|
||||||
void Cartridge::load_super_game_boy() {
|
void Cartridge::load_super_game_boy() {
|
||||||
interface->loadRequest(ID::SuperGameBoyManifest, "manifest.bml");
|
interface->loadRequest(ID::SuperGameBoyManifest, "manifest.bml");
|
||||||
auto document = Markup::Document(information.markup.gameBoy);
|
auto document = BML::unserialize(information.markup.gameBoy);
|
||||||
information.title.gameBoy = document["information/title"].text();
|
information.title.gameBoy = document["information/title"].text();
|
||||||
|
|
||||||
auto rom = document["cartridge/rom"];
|
auto rom = document["cartridge/rom"];
|
||||||
|
@ -124,22 +124,22 @@ void Cartridge::load_super_game_boy() {
|
||||||
GameBoy::cartridge.information.markup = information.markup.gameBoy;
|
GameBoy::cartridge.information.markup = information.markup.gameBoy;
|
||||||
GameBoy::cartridge.load(GameBoy::System::Revision::SuperGameBoy);
|
GameBoy::cartridge.load(GameBoy::System::Revision::SuperGameBoy);
|
||||||
|
|
||||||
if(rom["name"].exists()) interface->loadRequest(ID::SuperGameBoyROM, rom["name"].data);
|
if(rom["name"]) interface->loadRequest(ID::SuperGameBoyROM, rom["name"].text());
|
||||||
if(ram["name"].exists()) interface->loadRequest(ID::SuperGameBoyRAM, ram["name"].data);
|
if(ram["name"]) interface->loadRequest(ID::SuperGameBoyRAM, ram["name"].text());
|
||||||
if(ram["name"].exists()) memory.append({ID::SuperGameBoyRAM, ram["name"].data});
|
if(ram["name"]) memory.append({ID::SuperGameBoyRAM, ram["name"].text()});
|
||||||
}
|
}
|
||||||
|
|
||||||
void Cartridge::load_satellaview() {
|
void Cartridge::load_satellaview() {
|
||||||
interface->loadRequest(ID::SatellaviewManifest, "manifest.bml");
|
interface->loadRequest(ID::SatellaviewManifest, "manifest.bml");
|
||||||
auto document = Markup::Document(information.markup.satellaview);
|
auto document = BML::unserialize(information.markup.satellaview);
|
||||||
information.title.satellaview = document["information/title"].text();
|
information.title.satellaview = document["information/title"].text();
|
||||||
|
|
||||||
auto rom = document["cartridge/rom"];
|
auto rom = document["cartridge/rom"];
|
||||||
|
|
||||||
if(rom["name"].exists()) {
|
if(rom["name"]) {
|
||||||
unsigned size = numeral(rom["size"].data);
|
unsigned size = rom["size"].decimal();
|
||||||
satellaviewcartridge.memory.map(allocate<uint8>(size, 0xff), size);
|
satellaviewcartridge.memory.map(allocate<uint8>(size, 0xff), size);
|
||||||
interface->loadRequest(ID::SatellaviewROM, rom["name"].data);
|
interface->loadRequest(ID::SatellaviewROM, rom["name"].text());
|
||||||
|
|
||||||
satellaviewcartridge.readonly = (rom["type"].text() == "MaskROM");
|
satellaviewcartridge.readonly = (rom["type"].text() == "MaskROM");
|
||||||
}
|
}
|
||||||
|
@ -147,49 +147,49 @@ void Cartridge::load_satellaview() {
|
||||||
|
|
||||||
void Cartridge::load_sufami_turbo_a() {
|
void Cartridge::load_sufami_turbo_a() {
|
||||||
interface->loadRequest(ID::SufamiTurboSlotAManifest, "manifest.bml");
|
interface->loadRequest(ID::SufamiTurboSlotAManifest, "manifest.bml");
|
||||||
auto document = Markup::Document(information.markup.sufamiTurboA);
|
auto document = BML::unserialize(information.markup.sufamiTurboA);
|
||||||
information.title.sufamiTurboA = document["information/title"].text();
|
information.title.sufamiTurboA = document["information/title"].text();
|
||||||
|
|
||||||
auto rom = document["cartridge/rom"];
|
auto rom = document["cartridge/rom"];
|
||||||
auto ram = document["cartridge/ram"];
|
auto ram = document["cartridge/ram"];
|
||||||
|
|
||||||
if(rom["name"].exists()) {
|
if(rom["name"]) {
|
||||||
unsigned size = numeral(rom["size"].data);
|
unsigned size = rom["size"].decimal();
|
||||||
sufamiturboA.rom.map(allocate<uint8>(size, 0xff), size);
|
sufamiturboA.rom.map(allocate<uint8>(size, 0xff), size);
|
||||||
interface->loadRequest(ID::SufamiTurboSlotAROM, rom["name"].data);
|
interface->loadRequest(ID::SufamiTurboSlotAROM, rom["name"].text());
|
||||||
}
|
}
|
||||||
|
|
||||||
if(ram["name"].exists()) {
|
if(ram["name"]) {
|
||||||
unsigned size = numeral(ram["size"].data);
|
unsigned size = ram["size"].decimal();
|
||||||
sufamiturboA.ram.map(allocate<uint8>(size, 0xff), size);
|
sufamiturboA.ram.map(allocate<uint8>(size, 0xff), size);
|
||||||
interface->loadRequest(ID::SufamiTurboSlotARAM, ram["name"].data);
|
interface->loadRequest(ID::SufamiTurboSlotARAM, ram["name"].text());
|
||||||
memory.append({ID::SufamiTurboSlotARAM, ram["name"].data});
|
memory.append({ID::SufamiTurboSlotARAM, ram["name"].text()});
|
||||||
}
|
}
|
||||||
|
|
||||||
if(document["cartridge/linkable"].exists()) {
|
if(document["cartridge/linkable"]) {
|
||||||
interface->loadRequest(ID::SufamiTurboSlotB, "Sufami Turbo - Slot B", "st");
|
interface->loadRequest(ID::SufamiTurboSlotB, "Sufami Turbo - Slot B", "st");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void Cartridge::load_sufami_turbo_b() {
|
void Cartridge::load_sufami_turbo_b() {
|
||||||
interface->loadRequest(ID::SufamiTurboSlotBManifest, "manifest.bml");
|
interface->loadRequest(ID::SufamiTurboSlotBManifest, "manifest.bml");
|
||||||
auto document = Markup::Document(information.markup.sufamiTurboB);
|
auto document = BML::unserialize(information.markup.sufamiTurboB);
|
||||||
information.title.sufamiTurboB = document["information/title"].text();
|
information.title.sufamiTurboB = document["information/title"].text();
|
||||||
|
|
||||||
auto rom = document["cartridge/rom"];
|
auto rom = document["cartridge/rom"];
|
||||||
auto ram = document["cartridge/ram"];
|
auto ram = document["cartridge/ram"];
|
||||||
|
|
||||||
if(rom["name"].exists()) {
|
if(rom["name"]) {
|
||||||
unsigned size = numeral(rom["size"].data);
|
unsigned size = rom["size"].decimal();
|
||||||
sufamiturboB.rom.map(allocate<uint8>(size, 0xff), size);
|
sufamiturboB.rom.map(allocate<uint8>(size, 0xff), size);
|
||||||
interface->loadRequest(ID::SufamiTurboSlotBROM, rom["name"].data);
|
interface->loadRequest(ID::SufamiTurboSlotBROM, rom["name"].text());
|
||||||
}
|
}
|
||||||
|
|
||||||
if(ram["name"].exists()) {
|
if(ram["name"]) {
|
||||||
unsigned size = numeral(ram["size"].data);
|
unsigned size = ram["size"].decimal();
|
||||||
sufamiturboB.ram.map(allocate<uint8>(size, 0xff), size);
|
sufamiturboB.ram.map(allocate<uint8>(size, 0xff), size);
|
||||||
interface->loadRequest(ID::SufamiTurboSlotBRAM, ram["name"].data);
|
interface->loadRequest(ID::SufamiTurboSlotBRAM, ram["name"].text());
|
||||||
memory.append({ID::SufamiTurboSlotBRAM, ram["name"].data});
|
memory.append({ID::SufamiTurboSlotBRAM, ram["name"].text()});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1,11 +1,11 @@
|
||||||
#ifdef CARTRIDGE_CPP
|
#ifdef CARTRIDGE_CPP
|
||||||
|
|
||||||
void Cartridge::parse_markup(const char* markup) {
|
void Cartridge::parse_markup(const char* markup) {
|
||||||
auto document = Markup::Document(markup);
|
auto document = BML::unserialize(markup);
|
||||||
information.title.cartridge = document["information/title"].text();
|
information.title.cartridge = document["information/title"].text();
|
||||||
|
|
||||||
auto cartridge = document["cartridge"];
|
auto cartridge = document["cartridge"];
|
||||||
region = cartridge["region"].data != "PAL" ? Region::NTSC : Region::PAL;
|
region = cartridge["region"].text() != "PAL" ? Region::NTSC : Region::PAL;
|
||||||
|
|
||||||
mapping.reset();
|
mapping.reset();
|
||||||
parse_markup_cartridge(cartridge);
|
parse_markup_cartridge(cartridge);
|
||||||
|
@ -19,7 +19,7 @@ void Cartridge::parse_markup(const char* markup) {
|
||||||
parse_markup_sa1(cartridge["sa1"]);
|
parse_markup_sa1(cartridge["sa1"]);
|
||||||
parse_markup_superfx(cartridge["superfx"]);
|
parse_markup_superfx(cartridge["superfx"]);
|
||||||
parse_markup_armdsp(cartridge["armdsp"]);
|
parse_markup_armdsp(cartridge["armdsp"]);
|
||||||
parse_markup_hitachidsp(cartridge["hitachidsp"], cartridge["board/type"].data.match("2DC*") ? 2 : 1);
|
parse_markup_hitachidsp(cartridge["hitachidsp"], cartridge["board/type"].text().match("2DC*") ? 2 : 1);
|
||||||
parse_markup_necdsp(cartridge["necdsp"]);
|
parse_markup_necdsp(cartridge["necdsp"]);
|
||||||
parse_markup_epsonrtc(cartridge["epsonrtc"]);
|
parse_markup_epsonrtc(cartridge["epsonrtc"]);
|
||||||
parse_markup_sharprtc(cartridge["sharprtc"]);
|
parse_markup_sharprtc(cartridge["sharprtc"]);
|
||||||
|
@ -32,17 +32,17 @@ void Cartridge::parse_markup(const char* markup) {
|
||||||
//
|
//
|
||||||
|
|
||||||
void Cartridge::parse_markup_map(Mapping& m, Markup::Node map) {
|
void Cartridge::parse_markup_map(Mapping& m, Markup::Node map) {
|
||||||
m.addr = map["address"].data;
|
m.addr = map["address"].text();
|
||||||
m.size = numeral(map["size"].data);
|
m.size = map["size"].decimal();
|
||||||
m.base = numeral(map["base"].data);
|
m.base = map["base"].decimal();
|
||||||
m.mask = numeral(map["mask"].data);
|
m.mask = map["mask"].decimal();
|
||||||
}
|
}
|
||||||
|
|
||||||
void Cartridge::parse_markup_memory(MappedRAM& ram, Markup::Node node, unsigned id, bool writable) {
|
void Cartridge::parse_markup_memory(MappedRAM& ram, Markup::Node node, unsigned id, bool writable) {
|
||||||
string name = node["name"].data;
|
string name = node["name"].text();
|
||||||
unsigned size = numeral(node["size"].data);
|
unsigned size = node["size"].decimal();
|
||||||
ram.map(allocate<uint8>(size, 0xff), size);
|
ram.map(allocate<uint8>(size, 0xff), size);
|
||||||
if(name.empty() == false) {
|
if(name) {
|
||||||
interface->loadRequest(id, name);
|
interface->loadRequest(id, name);
|
||||||
if(writable) memory.append({id, name});
|
if(writable) memory.append({id, name});
|
||||||
}
|
}
|
||||||
|
@ -51,22 +51,20 @@ void Cartridge::parse_markup_memory(MappedRAM& ram, Markup::Node node, unsigned
|
||||||
//
|
//
|
||||||
|
|
||||||
void Cartridge::parse_markup_cartridge(Markup::Node root) {
|
void Cartridge::parse_markup_cartridge(Markup::Node root) {
|
||||||
if(root.exists() == false) return;
|
if(!root) return;
|
||||||
|
|
||||||
parse_markup_memory(rom, root["rom"], ID::ROM, false);
|
parse_markup_memory(rom, root["rom"], ID::ROM, false);
|
||||||
parse_markup_memory(ram, root["ram"], ID::RAM, true);
|
parse_markup_memory(ram, root["ram"], ID::RAM, true);
|
||||||
|
|
||||||
for(auto& node : root) {
|
for(auto node : root.find("map")) {
|
||||||
if(node.name != "map") continue;
|
if(node["id"].text() == "rom") {
|
||||||
|
|
||||||
if(node["id"].data == "rom") {
|
|
||||||
Mapping m(rom);
|
Mapping m(rom);
|
||||||
parse_markup_map(m, node);
|
parse_markup_map(m, node);
|
||||||
if(m.size == 0) m.size = rom.size();
|
if(m.size == 0) m.size = rom.size();
|
||||||
mapping.append(m);
|
mapping.append(m);
|
||||||
}
|
}
|
||||||
|
|
||||||
if(node["id"].data == "ram") {
|
if(node["id"].text() == "ram") {
|
||||||
Mapping m(ram);
|
Mapping m(ram);
|
||||||
parse_markup_map(m, node);
|
parse_markup_map(m, node);
|
||||||
if(m.size == 0) m.size = ram.size();
|
if(m.size == 0) m.size = ram.size();
|
||||||
|
@ -76,20 +74,18 @@ void Cartridge::parse_markup_cartridge(Markup::Node root) {
|
||||||
}
|
}
|
||||||
|
|
||||||
void Cartridge::parse_markup_icd2(Markup::Node root) {
|
void Cartridge::parse_markup_icd2(Markup::Node root) {
|
||||||
if(root.exists() == false) return;
|
if(!root) return;
|
||||||
has_gb_slot = true;
|
has_gb_slot = true;
|
||||||
icd2.revision = max(1, numeral(root["revision"].data));
|
icd2.revision = max(1, root["revision"].decimal());
|
||||||
|
|
||||||
GameBoy::cartridge.load_empty(GameBoy::System::Revision::SuperGameBoy);
|
GameBoy::cartridge.load_empty(GameBoy::System::Revision::SuperGameBoy);
|
||||||
interface->loadRequest(ID::SuperGameBoy, "Game Boy", "gb");
|
interface->loadRequest(ID::SuperGameBoy, "Game Boy", "gb");
|
||||||
|
|
||||||
string bootROMName = root["rom"]["name"].data;
|
string bootROMName = root["rom/name"].text();
|
||||||
interface->loadRequest(ID::SuperGameBoyBootROM, bootROMName);
|
interface->loadRequest(ID::SuperGameBoyBootROM, bootROMName);
|
||||||
|
|
||||||
for(auto& node : root) {
|
for(auto node : root.find("map")) {
|
||||||
if(node.name != "map") continue;
|
if(node["id"].text() == "io") {
|
||||||
|
|
||||||
if(node["id"].data == "io") {
|
|
||||||
Mapping m({&ICD2::read, &icd2}, {&ICD2::write, &icd2});
|
Mapping m({&ICD2::read, &icd2}, {&ICD2::write, &icd2});
|
||||||
parse_markup_map(m, node);
|
parse_markup_map(m, node);
|
||||||
mapping.append(m);
|
mapping.append(m);
|
||||||
|
@ -98,7 +94,7 @@ void Cartridge::parse_markup_icd2(Markup::Node root) {
|
||||||
}
|
}
|
||||||
|
|
||||||
void Cartridge::parse_markup_bsx(Markup::Node root) {
|
void Cartridge::parse_markup_bsx(Markup::Node root) {
|
||||||
if(root.exists() == false) return;
|
if(!root) return;
|
||||||
has_bs_cart = true;
|
has_bs_cart = true;
|
||||||
has_bs_slot = true;
|
has_bs_slot = true;
|
||||||
|
|
||||||
|
@ -108,17 +104,15 @@ void Cartridge::parse_markup_bsx(Markup::Node root) {
|
||||||
parse_markup_memory(bsxcartridge.ram, root["ram"], ID::BsxRAM, true);
|
parse_markup_memory(bsxcartridge.ram, root["ram"], ID::BsxRAM, true);
|
||||||
parse_markup_memory(bsxcartridge.psram, root["psram"], ID::BsxPSRAM, true);
|
parse_markup_memory(bsxcartridge.psram, root["psram"], ID::BsxPSRAM, true);
|
||||||
|
|
||||||
for(auto& node : root) {
|
for(auto node : root.find("map")) {
|
||||||
if(node.name != "map") continue;
|
if(node["id"].text() == "rom"
|
||||||
|
|| node["id"].text() == "ram") {
|
||||||
if(node["id"].data == "rom"
|
|
||||||
|| node["id"].data == "ram") {
|
|
||||||
Mapping m({&BSXCartridge::mcu_read, &bsxcartridge}, {&BSXCartridge::mcu_write, &bsxcartridge});
|
Mapping m({&BSXCartridge::mcu_read, &bsxcartridge}, {&BSXCartridge::mcu_write, &bsxcartridge});
|
||||||
parse_markup_map(m, node);
|
parse_markup_map(m, node);
|
||||||
mapping.append(m);
|
mapping.append(m);
|
||||||
}
|
}
|
||||||
|
|
||||||
if(node["id"].data == "io") {
|
if(node["id"].text() == "io") {
|
||||||
Mapping m({&BSXCartridge::mmio_read, &bsxcartridge}, {&BSXCartridge::mmio_write, &bsxcartridge});
|
Mapping m({&BSXCartridge::mmio_read, &bsxcartridge}, {&BSXCartridge::mmio_write, &bsxcartridge});
|
||||||
parse_markup_map(m, node);
|
parse_markup_map(m, node);
|
||||||
mapping.append(m);
|
mapping.append(m);
|
||||||
|
@ -127,13 +121,13 @@ void Cartridge::parse_markup_bsx(Markup::Node root) {
|
||||||
}
|
}
|
||||||
|
|
||||||
void Cartridge::parse_markup_satellaview(Markup::Node root) {
|
void Cartridge::parse_markup_satellaview(Markup::Node root) {
|
||||||
if(root.exists() == false) return;
|
if(!root) return;
|
||||||
has_bs_slot = true;
|
has_bs_slot = true;
|
||||||
|
|
||||||
interface->loadRequest(ID::Satellaview, "BS-X Satellaview", "bs");
|
interface->loadRequest(ID::Satellaview, "BS-X Satellaview", "bs");
|
||||||
|
|
||||||
for(auto& node : root.find("map")) {
|
for(auto node : root.find("map")) {
|
||||||
if(node["id"].data == "rom") {
|
if(node["id"].text() == "rom") {
|
||||||
if(satellaviewcartridge.memory.size() == 0) continue;
|
if(satellaviewcartridge.memory.size() == 0) continue;
|
||||||
|
|
||||||
Mapping m(satellaviewcartridge);
|
Mapping m(satellaviewcartridge);
|
||||||
|
@ -144,7 +138,7 @@ void Cartridge::parse_markup_satellaview(Markup::Node root) {
|
||||||
}
|
}
|
||||||
|
|
||||||
void Cartridge::parse_markup_sufamiturbo(Markup::Node root, bool slot) {
|
void Cartridge::parse_markup_sufamiturbo(Markup::Node root, bool slot) {
|
||||||
if(root.exists() == false) return;
|
if(!root) return;
|
||||||
has_st_slots = true;
|
has_st_slots = true;
|
||||||
|
|
||||||
if(slot == 0) {
|
if(slot == 0) {
|
||||||
|
@ -152,10 +146,10 @@ void Cartridge::parse_markup_sufamiturbo(Markup::Node root, bool slot) {
|
||||||
interface->loadRequest(ID::SufamiTurboSlotA, "Sufami Turbo - Slot A", "st");
|
interface->loadRequest(ID::SufamiTurboSlotA, "Sufami Turbo - Slot A", "st");
|
||||||
}
|
}
|
||||||
|
|
||||||
for(auto& node : root.find("map")) {
|
for(auto node : root.find("map")) {
|
||||||
SufamiTurboCartridge &cart = (slot == 0 ? sufamiturboA : sufamiturboB);
|
SufamiTurboCartridge &cart = (slot == 0 ? sufamiturboA : sufamiturboB);
|
||||||
|
|
||||||
if(node["id"].data == "rom") {
|
if(node["id"].text() == "rom") {
|
||||||
if(cart.rom.size() == 0) continue;
|
if(cart.rom.size() == 0) continue;
|
||||||
|
|
||||||
Mapping m(cart.rom);
|
Mapping m(cart.rom);
|
||||||
|
@ -164,7 +158,7 @@ void Cartridge::parse_markup_sufamiturbo(Markup::Node root, bool slot) {
|
||||||
if(m.size) mapping.append(m);
|
if(m.size) mapping.append(m);
|
||||||
}
|
}
|
||||||
|
|
||||||
if(node["id"].data == "ram") {
|
if(node["id"].text() == "ram") {
|
||||||
if(cart.ram.size() == 0) continue;
|
if(cart.ram.size() == 0) continue;
|
||||||
|
|
||||||
Mapping m(cart.ram);
|
Mapping m(cart.ram);
|
||||||
|
@ -176,14 +170,12 @@ void Cartridge::parse_markup_sufamiturbo(Markup::Node root, bool slot) {
|
||||||
}
|
}
|
||||||
|
|
||||||
void Cartridge::parse_markup_nss(Markup::Node root) {
|
void Cartridge::parse_markup_nss(Markup::Node root) {
|
||||||
if(root.exists() == false) return;
|
if(!root) return;
|
||||||
has_nss_dip = true;
|
has_nss_dip = true;
|
||||||
nss.dip = interface->dipSettings(root);
|
nss.dip = interface->dipSettings(root);
|
||||||
|
|
||||||
for(auto& node : root) {
|
for(auto node : root.find("map")) {
|
||||||
if(node.name != "map") continue;
|
if(node["id"].text() == "io") {
|
||||||
|
|
||||||
if(node["id"].data == "io") {
|
|
||||||
Mapping m({&NSS::read, &nss}, {&NSS::write, &nss});
|
Mapping m({&NSS::read, &nss}, {&NSS::write, &nss});
|
||||||
parse_markup_map(m, node);
|
parse_markup_map(m, node);
|
||||||
mapping.append(m);
|
mapping.append(m);
|
||||||
|
@ -192,48 +184,45 @@ void Cartridge::parse_markup_nss(Markup::Node root) {
|
||||||
}
|
}
|
||||||
|
|
||||||
void Cartridge::parse_markup_event(Markup::Node root) {
|
void Cartridge::parse_markup_event(Markup::Node root) {
|
||||||
if(root.exists() == false) return;
|
if(!root) return;
|
||||||
has_event = true;
|
has_event = true;
|
||||||
|
|
||||||
for(auto& node : root) {
|
for(auto node : root.find("rom")) {
|
||||||
if(node.name != "rom") continue;
|
unsigned id = node["id"].decimal();
|
||||||
unsigned id = numeral(node["id"].data);
|
|
||||||
if(id > 3) continue;
|
if(id > 3) continue;
|
||||||
parse_markup_memory(event.rom[id], node, ID::EventROM0 + id, false);
|
parse_markup_memory(event.rom[id], node, ID::EventROM0 + id, false);
|
||||||
}
|
}
|
||||||
parse_markup_memory(event.ram, root["ram"], ID::EventRAM, true);
|
parse_markup_memory(event.ram, root["ram"], ID::EventRAM, true);
|
||||||
|
|
||||||
event.board = Event::Board::CampusChallenge92;
|
event.board = Event::Board::CampusChallenge92;
|
||||||
if(root["name"].data == "Campus Challenge '92") event.board = Event::Board::CampusChallenge92;
|
if(root["name"].text() == "Campus Challenge '92") event.board = Event::Board::CampusChallenge92;
|
||||||
if(root["name"].data == "Powerfest '94") event.board = Event::Board::Powerfest94;
|
if(root["name"].text() == "Powerfest '94") event.board = Event::Board::Powerfest94;
|
||||||
|
|
||||||
event.revision = root["revision"].data == "B" ? 2 : 1;
|
event.revision = root["revision"].text() == "B" ? 2 : 1;
|
||||||
lstring part = root["timer"].data.split<1>(":");
|
lstring part = root["timer"].text().split<1>(":");
|
||||||
if(part.size() == 1) event.timer = decimal(part(0));
|
if(part.size() == 1) event.timer = decimal(part(0));
|
||||||
if(part.size() == 2) event.timer = decimal(part(0)) * 60 + decimal(part(1));
|
if(part.size() == 2) event.timer = decimal(part(0)) * 60 + decimal(part(1));
|
||||||
|
|
||||||
for(auto& node : root) {
|
for(auto node : root.find("map")) {
|
||||||
if(node.name != "map") continue;
|
if(node["id"].text() == "rom") {
|
||||||
|
|
||||||
if(node["id"].data == "rom") {
|
|
||||||
Mapping m({&Event::rom_read, &event}, [](unsigned, uint8) {});
|
Mapping m({&Event::rom_read, &event}, [](unsigned, uint8) {});
|
||||||
parse_markup_map(m, node);
|
parse_markup_map(m, node);
|
||||||
mapping.append(m);
|
mapping.append(m);
|
||||||
}
|
}
|
||||||
|
|
||||||
if(node["id"].data == "ram") {
|
if(node["id"].text() == "ram") {
|
||||||
Mapping m({&Event::ram_read, &event}, {&Event::ram_write, &event});
|
Mapping m({&Event::ram_read, &event}, {&Event::ram_write, &event});
|
||||||
parse_markup_map(m, node);
|
parse_markup_map(m, node);
|
||||||
mapping.append(m);
|
mapping.append(m);
|
||||||
}
|
}
|
||||||
|
|
||||||
if(node["id"].data == "dr") {
|
if(node["id"].text() == "dr") {
|
||||||
Mapping m([](unsigned) -> uint8 { return cpu.regs.mdr; }, {&Event::dr, &event});
|
Mapping m([](unsigned) -> uint8 { return cpu.regs.mdr; }, {&Event::dr, &event});
|
||||||
parse_markup_map(m, node);
|
parse_markup_map(m, node);
|
||||||
mapping.append(m);
|
mapping.append(m);
|
||||||
}
|
}
|
||||||
|
|
||||||
if(node["id"].data == "sr") {
|
if(node["id"].text() == "sr") {
|
||||||
Mapping m({&Event::sr, &event}, [](unsigned, uint8) {});
|
Mapping m({&Event::sr, &event}, [](unsigned, uint8) {});
|
||||||
parse_markup_map(m, node);
|
parse_markup_map(m, node);
|
||||||
mapping.append(m);
|
mapping.append(m);
|
||||||
|
@ -242,35 +231,33 @@ void Cartridge::parse_markup_event(Markup::Node root) {
|
||||||
}
|
}
|
||||||
|
|
||||||
void Cartridge::parse_markup_sa1(Markup::Node root) {
|
void Cartridge::parse_markup_sa1(Markup::Node root) {
|
||||||
if(root.exists() == false) return;
|
if(!root) return;
|
||||||
has_sa1 = true;
|
has_sa1 = true;
|
||||||
|
|
||||||
parse_markup_memory(sa1.rom, root["rom"], ID::SA1ROM, false);
|
parse_markup_memory(sa1.rom, root["rom"], ID::SA1ROM, false);
|
||||||
parse_markup_memory(sa1.bwram, root["ram[0]"], ID::SA1BWRAM, true);
|
parse_markup_memory(sa1.bwram, root["ram"].at(0), ID::SA1BWRAM, true);
|
||||||
parse_markup_memory(sa1.iram, root["ram[1]"], ID::SA1IRAM, true);
|
parse_markup_memory(sa1.iram, root["ram"].at(1), ID::SA1IRAM, true);
|
||||||
|
|
||||||
for(auto& node : root) {
|
for(auto node : root.find("map")) {
|
||||||
if(node.name != "map") continue;
|
if(node["id"].text() == "io") {
|
||||||
|
|
||||||
if(node["id"].data == "io") {
|
|
||||||
Mapping m({&SA1::mmio_read, &sa1}, {&SA1::mmio_write, &sa1});
|
Mapping m({&SA1::mmio_read, &sa1}, {&SA1::mmio_write, &sa1});
|
||||||
parse_markup_map(m, node);
|
parse_markup_map(m, node);
|
||||||
mapping.append(m);
|
mapping.append(m);
|
||||||
}
|
}
|
||||||
|
|
||||||
if(node["id"].data == "rom") {
|
if(node["id"].text() == "rom") {
|
||||||
Mapping m({&SA1::mmcrom_read, &sa1}, {&SA1::mmcrom_write, &sa1});
|
Mapping m({&SA1::mmcrom_read, &sa1}, {&SA1::mmcrom_write, &sa1});
|
||||||
parse_markup_map(m, node);
|
parse_markup_map(m, node);
|
||||||
mapping.append(m);
|
mapping.append(m);
|
||||||
}
|
}
|
||||||
|
|
||||||
if(node["id"].data == "bwram") {
|
if(node["id"].text() == "bwram") {
|
||||||
Mapping m({&SA1::mmcbwram_read, &sa1}, {&SA1::mmcbwram_write, &sa1});
|
Mapping m({&SA1::mmcbwram_read, &sa1}, {&SA1::mmcbwram_write, &sa1});
|
||||||
parse_markup_map(m, node);
|
parse_markup_map(m, node);
|
||||||
mapping.append(m);
|
mapping.append(m);
|
||||||
}
|
}
|
||||||
|
|
||||||
if(node["id"].data == "iram") {
|
if(node["id"].text() == "iram") {
|
||||||
Mapping m(sa1.cpuiram);
|
Mapping m(sa1.cpuiram);
|
||||||
parse_markup_map(m, node);
|
parse_markup_map(m, node);
|
||||||
if(m.size == 0) m.size = sa1.cpuiram.size();
|
if(m.size == 0) m.size = sa1.cpuiram.size();
|
||||||
|
@ -280,29 +267,27 @@ void Cartridge::parse_markup_sa1(Markup::Node root) {
|
||||||
}
|
}
|
||||||
|
|
||||||
void Cartridge::parse_markup_superfx(Markup::Node root) {
|
void Cartridge::parse_markup_superfx(Markup::Node root) {
|
||||||
if(root.exists() == false) return;
|
if(!root) return;
|
||||||
has_superfx = true;
|
has_superfx = true;
|
||||||
|
|
||||||
parse_markup_memory(superfx.rom, root["rom"], ID::SuperFXROM, false);
|
parse_markup_memory(superfx.rom, root["rom"], ID::SuperFXROM, false);
|
||||||
parse_markup_memory(superfx.ram, root["ram"], ID::SuperFXRAM, true);
|
parse_markup_memory(superfx.ram, root["ram"], ID::SuperFXRAM, true);
|
||||||
|
|
||||||
for(auto& node : root) {
|
for(auto node : root.find("map")) {
|
||||||
if(node.name != "map") continue;
|
if(node["id"].text() == "io") {
|
||||||
|
|
||||||
if(node["id"].data == "io") {
|
|
||||||
Mapping m({&SuperFX::mmio_read, &superfx}, {&SuperFX::mmio_write, &superfx});
|
Mapping m({&SuperFX::mmio_read, &superfx}, {&SuperFX::mmio_write, &superfx});
|
||||||
parse_markup_map(m, node);
|
parse_markup_map(m, node);
|
||||||
mapping.append(m);
|
mapping.append(m);
|
||||||
}
|
}
|
||||||
|
|
||||||
if(node["id"].data == "rom") {
|
if(node["id"].text() == "rom") {
|
||||||
Mapping m(superfx.cpurom);
|
Mapping m(superfx.cpurom);
|
||||||
parse_markup_map(m, node);
|
parse_markup_map(m, node);
|
||||||
if(m.size == 0) m.size = superfx.rom.size();
|
if(m.size == 0) m.size = superfx.rom.size();
|
||||||
mapping.append(m);
|
mapping.append(m);
|
||||||
}
|
}
|
||||||
|
|
||||||
if(node["id"].data == "ram") {
|
if(node["id"].text() == "ram") {
|
||||||
Mapping m(superfx.cpuram);
|
Mapping m(superfx.cpuram);
|
||||||
parse_markup_map(m, node);
|
parse_markup_map(m, node);
|
||||||
if(m.size == 0) m.size = superfx.ram.size();
|
if(m.size == 0) m.size = superfx.ram.size();
|
||||||
|
@ -312,12 +297,12 @@ void Cartridge::parse_markup_superfx(Markup::Node root) {
|
||||||
}
|
}
|
||||||
|
|
||||||
void Cartridge::parse_markup_armdsp(Markup::Node root) {
|
void Cartridge::parse_markup_armdsp(Markup::Node root) {
|
||||||
if(root.exists() == false) return;
|
if(!root) return;
|
||||||
has_armdsp = true;
|
has_armdsp = true;
|
||||||
|
|
||||||
string programROMName = root["rom[0]/name"].data;
|
string programROMName = root["rom"].at(0)["name"].text();
|
||||||
string dataROMName = root["rom[1]/name"].data;
|
string dataROMName = root["rom"].at(1)["name"].text();
|
||||||
string dataRAMName = root["ram/name"].data;
|
string dataRAMName = root["ram/name"].text();
|
||||||
|
|
||||||
interface->loadRequest(ID::ArmDSPPROM, programROMName);
|
interface->loadRequest(ID::ArmDSPPROM, programROMName);
|
||||||
interface->loadRequest(ID::ArmDSPDROM, dataROMName);
|
interface->loadRequest(ID::ArmDSPDROM, dataROMName);
|
||||||
|
@ -326,10 +311,8 @@ void Cartridge::parse_markup_armdsp(Markup::Node root) {
|
||||||
memory.append({ID::ArmDSPRAM, dataRAMName});
|
memory.append({ID::ArmDSPRAM, dataRAMName});
|
||||||
}
|
}
|
||||||
|
|
||||||
for(auto& node : root) {
|
for(auto node : root.find("map")) {
|
||||||
if(node.name != "map") continue;
|
if(node["id"].text() == "io") {
|
||||||
|
|
||||||
if(node["id"].data == "io") {
|
|
||||||
Mapping m({&ArmDSP::mmio_read, &armdsp}, {&ArmDSP::mmio_write, &armdsp});
|
Mapping m({&ArmDSP::mmio_read, &armdsp}, {&ArmDSP::mmio_write, &armdsp});
|
||||||
parse_markup_map(m, node);
|
parse_markup_map(m, node);
|
||||||
mapping.append(m);
|
mapping.append(m);
|
||||||
|
@ -338,44 +321,42 @@ void Cartridge::parse_markup_armdsp(Markup::Node root) {
|
||||||
}
|
}
|
||||||
|
|
||||||
void Cartridge::parse_markup_hitachidsp(Markup::Node root, unsigned roms) {
|
void Cartridge::parse_markup_hitachidsp(Markup::Node root, unsigned roms) {
|
||||||
if(root.exists() == false) return;
|
if(!root) return;
|
||||||
has_hitachidsp = true;
|
has_hitachidsp = true;
|
||||||
|
|
||||||
parse_markup_memory(hitachidsp.rom, root["rom[0]"], ID::HitachiDSPROM, false);
|
parse_markup_memory(hitachidsp.rom, root["rom"].at(0), ID::HitachiDSPROM, false);
|
||||||
parse_markup_memory(hitachidsp.ram, root["ram[0]"], ID::HitachiDSPRAM, true);
|
parse_markup_memory(hitachidsp.ram, root["ram"].at(1), ID::HitachiDSPRAM, true);
|
||||||
|
|
||||||
for(auto& word : hitachidsp.dataROM) word = 0x000000;
|
for(auto& word : hitachidsp.dataROM) word = 0x000000;
|
||||||
for(auto& word : hitachidsp.dataRAM) word = 0x00;
|
for(auto& word : hitachidsp.dataRAM) word = 0x00;
|
||||||
|
|
||||||
hitachidsp.Frequency = numeral(root["frequency"].data);
|
hitachidsp.Frequency = root["frequency"].decimal();
|
||||||
if(hitachidsp.Frequency == 0) hitachidsp.frequency = 20000000;
|
if(hitachidsp.Frequency == 0) hitachidsp.frequency = 20000000;
|
||||||
hitachidsp.Roms = roms;
|
hitachidsp.Roms = roms;
|
||||||
|
|
||||||
string dataROMName = root["rom[1]/name"].data;
|
string dataROMName = root["rom"].at(1)["name"].text();
|
||||||
string dataRAMName = root["ram[1]/name"].data;
|
string dataRAMName = root["ram"].at(1)["name"].text();
|
||||||
|
|
||||||
interface->loadRequest(ID::HitachiDSPDROM, dataROMName);
|
interface->loadRequest(ID::HitachiDSPDROM, dataROMName);
|
||||||
if(dataRAMName.empty() == false) {
|
if(dataRAMName.empty() == false) {
|
||||||
interface->loadRequest(ID::HitachiDSPDRAM, dataRAMName);
|
interface->loadRequest(ID::HitachiDSPDRAM, dataRAMName);
|
||||||
}
|
}
|
||||||
|
|
||||||
for(auto& node : root) {
|
for(auto node : root.find("map")) {
|
||||||
if(node.name != "map") continue;
|
if(node["id"].text() == "io") {
|
||||||
|
|
||||||
if(node["id"].data == "io") {
|
|
||||||
Mapping m({&HitachiDSP::dsp_read, &hitachidsp}, {&HitachiDSP::dsp_write, &hitachidsp});
|
Mapping m({&HitachiDSP::dsp_read, &hitachidsp}, {&HitachiDSP::dsp_write, &hitachidsp});
|
||||||
parse_markup_map(m, node);
|
parse_markup_map(m, node);
|
||||||
mapping.append(m);
|
mapping.append(m);
|
||||||
}
|
}
|
||||||
|
|
||||||
if(node["id"].data == "rom") {
|
if(node["id"].text() == "rom") {
|
||||||
Mapping m({&HitachiDSP::rom_read, &hitachidsp}, {&HitachiDSP::rom_write, &hitachidsp});
|
Mapping m({&HitachiDSP::rom_read, &hitachidsp}, {&HitachiDSP::rom_write, &hitachidsp});
|
||||||
parse_markup_map(m, node);
|
parse_markup_map(m, node);
|
||||||
if(m.size == 0) m.size = hitachidsp.rom.size();
|
if(m.size == 0) m.size = hitachidsp.rom.size();
|
||||||
mapping.append(m);
|
mapping.append(m);
|
||||||
}
|
}
|
||||||
|
|
||||||
if(node["id"].data == "ram") {
|
if(node["id"].text() == "ram") {
|
||||||
Mapping m({&HitachiDSP::ram_read, &hitachidsp}, {&HitachiDSP::ram_write, &hitachidsp});
|
Mapping m({&HitachiDSP::ram_read, &hitachidsp}, {&HitachiDSP::ram_write, &hitachidsp});
|
||||||
parse_markup_map(m, node);
|
parse_markup_map(m, node);
|
||||||
if(m.size == 0) m.size = hitachidsp.ram.size();
|
if(m.size == 0) m.size = hitachidsp.ram.size();
|
||||||
|
@ -385,23 +366,23 @@ void Cartridge::parse_markup_hitachidsp(Markup::Node root, unsigned roms) {
|
||||||
}
|
}
|
||||||
|
|
||||||
void Cartridge::parse_markup_necdsp(Markup::Node root) {
|
void Cartridge::parse_markup_necdsp(Markup::Node root) {
|
||||||
if(root.exists() == false) return;
|
if(!root) return;
|
||||||
has_necdsp = true;
|
has_necdsp = true;
|
||||||
|
|
||||||
for(auto& word : necdsp.programROM) word = 0x000000;
|
for(auto& word : necdsp.programROM) word = 0x000000;
|
||||||
for(auto& word : necdsp.dataROM) word = 0x0000;
|
for(auto& word : necdsp.dataROM) word = 0x0000;
|
||||||
for(auto& word : necdsp.dataRAM) word = 0x0000;
|
for(auto& word : necdsp.dataRAM) word = 0x0000;
|
||||||
|
|
||||||
necdsp.frequency = numeral(root["frequency"].data);
|
necdsp.frequency = root["frequency"].decimal();
|
||||||
if(necdsp.frequency == 0) necdsp.frequency = 8000000;
|
if(necdsp.frequency == 0) necdsp.frequency = 8000000;
|
||||||
necdsp.revision
|
necdsp.revision
|
||||||
= root["model"].data == "uPD7725" ? NECDSP::Revision::uPD7725
|
= root["model"].text() == "uPD7725" ? NECDSP::Revision::uPD7725
|
||||||
: root["model"].data == "uPD96050" ? NECDSP::Revision::uPD96050
|
: root["model"].text() == "uPD96050" ? NECDSP::Revision::uPD96050
|
||||||
: NECDSP::Revision::uPD7725;
|
: NECDSP::Revision::uPD7725;
|
||||||
|
|
||||||
string programROMName = root["rom[0]/name"].data;
|
string programROMName = root["rom"].at(0)["name"].text();
|
||||||
string dataROMName = root["rom[1]/name"].data;
|
string dataROMName = root["rom"].at(1)["name"].text();
|
||||||
string dataRAMName = root["ram/name"].data;
|
string dataRAMName = root["ram/name"].text();
|
||||||
|
|
||||||
if(necdsp.revision == NECDSP::Revision::uPD7725) {
|
if(necdsp.revision == NECDSP::Revision::uPD7725) {
|
||||||
interface->loadRequest(ID::Nec7725DSPPROM, programROMName);
|
interface->loadRequest(ID::Nec7725DSPPROM, programROMName);
|
||||||
|
@ -421,17 +402,15 @@ void Cartridge::parse_markup_necdsp(Markup::Node root) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
for(auto& node : root) {
|
for(auto node : root.find("map")) {
|
||||||
if(node.name != "map") continue;
|
if(node["id"].text() == "io") {
|
||||||
|
|
||||||
if(node["id"].data == "io") {
|
|
||||||
Mapping m({&NECDSP::read, &necdsp}, {&NECDSP::write, &necdsp});
|
Mapping m({&NECDSP::read, &necdsp}, {&NECDSP::write, &necdsp});
|
||||||
parse_markup_map(m, node);
|
parse_markup_map(m, node);
|
||||||
mapping.append(m);
|
mapping.append(m);
|
||||||
necdsp.Select = numeral(node["select"].data);
|
necdsp.Select = node["select"].decimal();
|
||||||
}
|
}
|
||||||
|
|
||||||
if(node["id"].data == "ram") {
|
if(node["id"].text() == "ram") {
|
||||||
Mapping m({&NECDSP::ram_read, &necdsp}, {&NECDSP::ram_write, &necdsp});
|
Mapping m({&NECDSP::ram_read, &necdsp}, {&NECDSP::ram_write, &necdsp});
|
||||||
parse_markup_map(m, node);
|
parse_markup_map(m, node);
|
||||||
mapping.append(m);
|
mapping.append(m);
|
||||||
|
@ -440,17 +419,15 @@ void Cartridge::parse_markup_necdsp(Markup::Node root) {
|
||||||
}
|
}
|
||||||
|
|
||||||
void Cartridge::parse_markup_epsonrtc(Markup::Node root) {
|
void Cartridge::parse_markup_epsonrtc(Markup::Node root) {
|
||||||
if(root.exists() == false) return;
|
if(!root) return;
|
||||||
has_epsonrtc = true;
|
has_epsonrtc = true;
|
||||||
|
|
||||||
string name = root["ram"]["name"].data;
|
string name = root["ram/name"].text();
|
||||||
interface->loadRequest(ID::EpsonRTC, name);
|
interface->loadRequest(ID::EpsonRTC, name);
|
||||||
memory.append({ID::EpsonRTC, name});
|
memory.append({ID::EpsonRTC, name});
|
||||||
|
|
||||||
for(auto& node : root) {
|
for(auto node : root.find("map")) {
|
||||||
if(node.name != "map") continue;
|
if(node["id"].text() == "io") {
|
||||||
|
|
||||||
if(node["id"].data == "io") {
|
|
||||||
Mapping m({&EpsonRTC::read, &epsonrtc}, {&EpsonRTC::write, &epsonrtc});
|
Mapping m({&EpsonRTC::read, &epsonrtc}, {&EpsonRTC::write, &epsonrtc});
|
||||||
parse_markup_map(m, node);
|
parse_markup_map(m, node);
|
||||||
mapping.append(m);
|
mapping.append(m);
|
||||||
|
@ -459,17 +436,15 @@ void Cartridge::parse_markup_epsonrtc(Markup::Node root) {
|
||||||
}
|
}
|
||||||
|
|
||||||
void Cartridge::parse_markup_sharprtc(Markup::Node root) {
|
void Cartridge::parse_markup_sharprtc(Markup::Node root) {
|
||||||
if(root.exists() == false) return;
|
if(!root) return;
|
||||||
has_sharprtc = true;
|
has_sharprtc = true;
|
||||||
|
|
||||||
string name = root["ram"]["name"].data;
|
string name = root["ram/name"].text();
|
||||||
interface->loadRequest(ID::SharpRTC, name);
|
interface->loadRequest(ID::SharpRTC, name);
|
||||||
memory.append({ID::SharpRTC, name});
|
memory.append({ID::SharpRTC, name});
|
||||||
|
|
||||||
for(auto& node : root) {
|
for(auto node : root.find("map")) {
|
||||||
if(node.name != "map") continue;
|
if(node["id"].text() == "io") {
|
||||||
|
|
||||||
if(node["id"].data == "io") {
|
|
||||||
Mapping m({&SharpRTC::read, &sharprtc}, {&SharpRTC::write, &sharprtc});
|
Mapping m({&SharpRTC::read, &sharprtc}, {&SharpRTC::write, &sharprtc});
|
||||||
parse_markup_map(m, node);
|
parse_markup_map(m, node);
|
||||||
mapping.append(m);
|
mapping.append(m);
|
||||||
|
@ -478,29 +453,27 @@ void Cartridge::parse_markup_sharprtc(Markup::Node root) {
|
||||||
}
|
}
|
||||||
|
|
||||||
void Cartridge::parse_markup_spc7110(Markup::Node root) {
|
void Cartridge::parse_markup_spc7110(Markup::Node root) {
|
||||||
if(root.exists() == false) return;
|
if(!root) return;
|
||||||
has_spc7110 = true;
|
has_spc7110 = true;
|
||||||
|
|
||||||
parse_markup_memory(spc7110.prom, root["rom[0]"], ID::SPC7110PROM, false);
|
parse_markup_memory(spc7110.prom, root["rom"].at(0), ID::SPC7110PROM, false);
|
||||||
parse_markup_memory(spc7110.drom, root["rom[1]"], ID::SPC7110DROM, false);
|
parse_markup_memory(spc7110.drom, root["rom"].at(1), ID::SPC7110DROM, false);
|
||||||
parse_markup_memory(spc7110.ram, root["ram"], ID::SPC7110RAM, true);
|
parse_markup_memory(spc7110.ram, root["ram"], ID::SPC7110RAM, true);
|
||||||
|
|
||||||
for(auto& node : root) {
|
for(auto node : root.find("map")) {
|
||||||
if(node.name != "map") continue;
|
if(node["id"].text() == "io") {
|
||||||
|
|
||||||
if(node["id"].data == "io") {
|
|
||||||
Mapping m({&SPC7110::read, &spc7110}, {&SPC7110::write, &spc7110});
|
Mapping m({&SPC7110::read, &spc7110}, {&SPC7110::write, &spc7110});
|
||||||
parse_markup_map(m, node);
|
parse_markup_map(m, node);
|
||||||
mapping.append(m);
|
mapping.append(m);
|
||||||
}
|
}
|
||||||
|
|
||||||
if(node["id"].data == "rom") {
|
if(node["id"].text() == "rom") {
|
||||||
Mapping m({&SPC7110::mcurom_read, &spc7110}, {&SPC7110::mcurom_write, &spc7110});
|
Mapping m({&SPC7110::mcurom_read, &spc7110}, {&SPC7110::mcurom_write, &spc7110});
|
||||||
parse_markup_map(m, node);
|
parse_markup_map(m, node);
|
||||||
mapping.append(m);
|
mapping.append(m);
|
||||||
}
|
}
|
||||||
|
|
||||||
if(node["id"].data == "ram") {
|
if(node["id"].text() == "ram") {
|
||||||
Mapping m({&SPC7110::mcuram_read, &spc7110}, {&SPC7110::mcuram_write, &spc7110});
|
Mapping m({&SPC7110::mcuram_read, &spc7110}, {&SPC7110::mcuram_write, &spc7110});
|
||||||
parse_markup_map(m, node);
|
parse_markup_map(m, node);
|
||||||
mapping.append(m);
|
mapping.append(m);
|
||||||
|
@ -509,28 +482,26 @@ void Cartridge::parse_markup_spc7110(Markup::Node root) {
|
||||||
}
|
}
|
||||||
|
|
||||||
void Cartridge::parse_markup_sdd1(Markup::Node root) {
|
void Cartridge::parse_markup_sdd1(Markup::Node root) {
|
||||||
if(root.exists() == false) return;
|
if(!root) return;
|
||||||
has_sdd1 = true;
|
has_sdd1 = true;
|
||||||
|
|
||||||
parse_markup_memory(sdd1.rom, root["rom"], ID::SDD1ROM, false);
|
parse_markup_memory(sdd1.rom, root["rom"], ID::SDD1ROM, false);
|
||||||
parse_markup_memory(sdd1.ram, root["ram"], ID::SDD1RAM, true);
|
parse_markup_memory(sdd1.ram, root["ram"], ID::SDD1RAM, true);
|
||||||
|
|
||||||
for(auto& node : root) {
|
for(auto node : root.find("map")) {
|
||||||
if(node.name != "map") continue;
|
if(node["id"].text() == "io") {
|
||||||
|
|
||||||
if(node["id"].data == "io") {
|
|
||||||
Mapping m({&SDD1::read, &sdd1}, {&SDD1::write, &sdd1});
|
Mapping m({&SDD1::read, &sdd1}, {&SDD1::write, &sdd1});
|
||||||
parse_markup_map(m, node);
|
parse_markup_map(m, node);
|
||||||
mapping.append(m);
|
mapping.append(m);
|
||||||
}
|
}
|
||||||
|
|
||||||
if(node["id"].data == "rom") {
|
if(node["id"].text() == "rom") {
|
||||||
Mapping m({&SDD1::mcurom_read, &sdd1}, {&SDD1::mcurom_write, &sdd1});
|
Mapping m({&SDD1::mcurom_read, &sdd1}, {&SDD1::mcurom_write, &sdd1});
|
||||||
parse_markup_map(m, node);
|
parse_markup_map(m, node);
|
||||||
mapping.append(m);
|
mapping.append(m);
|
||||||
}
|
}
|
||||||
|
|
||||||
if(node["id"].data == "ram") {
|
if(node["id"].text() == "ram") {
|
||||||
Mapping m({&SDD1::mcuram_read, &sdd1}, {&SDD1::mcuram_write, &sdd1});
|
Mapping m({&SDD1::mcuram_read, &sdd1}, {&SDD1::mcuram_write, &sdd1});
|
||||||
parse_markup_map(m, node);
|
parse_markup_map(m, node);
|
||||||
mapping.append(m);
|
mapping.append(m);
|
||||||
|
@ -539,15 +510,13 @@ void Cartridge::parse_markup_sdd1(Markup::Node root) {
|
||||||
}
|
}
|
||||||
|
|
||||||
void Cartridge::parse_markup_obc1(Markup::Node root) {
|
void Cartridge::parse_markup_obc1(Markup::Node root) {
|
||||||
if(root.exists() == false) return;
|
if(!root) return;
|
||||||
has_obc1 = true;
|
has_obc1 = true;
|
||||||
|
|
||||||
parse_markup_memory(obc1.ram, root["ram"], ID::OBC1RAM, true);
|
parse_markup_memory(obc1.ram, root["ram"], ID::OBC1RAM, true);
|
||||||
|
|
||||||
for(auto& node : root) {
|
for(auto node : root.find("map")) {
|
||||||
if(node.name != "map") continue;
|
if(node["id"].text() == "io") {
|
||||||
|
|
||||||
if(node["id"].data == "io") {
|
|
||||||
Mapping m({&OBC1::read, &obc1}, {&OBC1::write, &obc1});
|
Mapping m({&OBC1::read, &obc1}, {&OBC1::write, &obc1});
|
||||||
parse_markup_map(m, node);
|
parse_markup_map(m, node);
|
||||||
mapping.append(m);
|
mapping.append(m);
|
||||||
|
@ -556,13 +525,11 @@ void Cartridge::parse_markup_obc1(Markup::Node root) {
|
||||||
}
|
}
|
||||||
|
|
||||||
void Cartridge::parse_markup_msu1(Markup::Node root) {
|
void Cartridge::parse_markup_msu1(Markup::Node root) {
|
||||||
if(root.exists() == false) return;
|
if(!root) return;
|
||||||
has_msu1 = true;
|
has_msu1 = true;
|
||||||
|
|
||||||
for(auto& node : root) {
|
for(auto node : root.find("map")) {
|
||||||
if(node.name != "map") continue;
|
if(node["id"].text() == "io") {
|
||||||
|
|
||||||
if(node["id"].data == "io") {
|
|
||||||
Mapping m({&MSU1::mmio_read, &msu1}, {&MSU1::mmio_write, &msu1});
|
Mapping m({&MSU1::mmio_read, &msu1}, {&MSU1::mmio_write, &msu1});
|
||||||
parse_markup_map(m, node);
|
parse_markup_map(m, node);
|
||||||
mapping.append(m);
|
mapping.append(m);
|
||||||
|
|
|
@ -88,9 +88,9 @@ void MSU1::reset() {
|
||||||
|
|
||||||
void MSU1::data_open() {
|
void MSU1::data_open() {
|
||||||
if(datafile.open()) datafile.close();
|
if(datafile.open()) datafile.close();
|
||||||
auto document = Markup::Document(cartridge.information.markup.cartridge);
|
auto document = BML::unserialize(cartridge.information.markup.cartridge);
|
||||||
string name = document["cartridge/msu1/rom/name"].data;
|
string name = document["cartridge/msu1/rom/name"].text();
|
||||||
if(name.empty()) name = "msu1.rom";
|
if(!name) name = "msu1.rom";
|
||||||
if(datafile.open({interface->path(ID::SuperFamicom), name}, file::mode::read)) {
|
if(datafile.open({interface->path(ID::SuperFamicom), name}, file::mode::read)) {
|
||||||
datafile.seek(mmio.data_read_offset);
|
datafile.seek(mmio.data_read_offset);
|
||||||
}
|
}
|
||||||
|
@ -98,11 +98,11 @@ void MSU1::data_open() {
|
||||||
|
|
||||||
void MSU1::audio_open() {
|
void MSU1::audio_open() {
|
||||||
if(audiofile.open()) audiofile.close();
|
if(audiofile.open()) audiofile.close();
|
||||||
auto document = Markup::Document(cartridge.information.markup.cartridge);
|
auto document = BML::unserialize(cartridge.information.markup.cartridge);
|
||||||
string name = {"track-", mmio.audio_track, ".pcm"};
|
string name = {"track-", mmio.audio_track, ".pcm"};
|
||||||
for(auto track : document.find("cartridge/msu1/track")) {
|
for(auto track : document.find("cartridge/msu1/track")) {
|
||||||
if(numeral(track["number"].data) != mmio.audio_track) continue;
|
if(track["number"].decimal() != mmio.audio_track) continue;
|
||||||
name = track["name"].data;
|
name = track["name"].text();
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
if(audiofile.open({interface->path(ID::SuperFamicom), name}, file::mode::read)) {
|
if(audiofile.open({interface->path(ID::SuperFamicom), name}, file::mode::read)) {
|
||||||
|
|
|
@ -107,7 +107,7 @@ void SA1::tick() {
|
||||||
case 0: break;
|
case 0: break;
|
||||||
case 1: if(status.hcounter == (mmio.hcnt << 2)) trigger_irq(); break;
|
case 1: if(status.hcounter == (mmio.hcnt << 2)) trigger_irq(); break;
|
||||||
case 2: if(status.vcounter == mmio.vcnt && status.hcounter == 0) trigger_irq(); break;
|
case 2: if(status.vcounter == mmio.vcnt && status.hcounter == 0) trigger_irq(); break;
|
||||||
case 3: if(status.vcounter == mmio.hcnt && status.hcounter == (mmio.hcnt << 2)) trigger_irq(); break;
|
case 3: if(status.vcounter == mmio.vcnt && status.hcounter == (mmio.hcnt << 2)) trigger_irq(); break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -30,8 +30,8 @@ struct Background {
|
||||||
uint16 voffset;
|
uint16 voffset;
|
||||||
} cache;
|
} cache;
|
||||||
|
|
||||||
unsigned voffset() const;
|
alwaysinline unsigned voffset() const;
|
||||||
unsigned hoffset() const;
|
alwaysinline unsigned hoffset() const;
|
||||||
|
|
||||||
struct Output {
|
struct Output {
|
||||||
struct Pixel {
|
struct Pixel {
|
||||||
|
@ -69,7 +69,7 @@ struct Background {
|
||||||
void get_tile();
|
void get_tile();
|
||||||
unsigned get_tile_color();
|
unsigned get_tile_color();
|
||||||
unsigned get_tile(unsigned x, unsigned y);
|
unsigned get_tile(unsigned x, unsigned y);
|
||||||
signed clip(signed n);
|
alwaysinline signed clip(signed n);
|
||||||
void begin_mode7();
|
void begin_mode7();
|
||||||
void run_mode7();
|
void run_mode7();
|
||||||
|
|
||||||
|
|
|
@ -87,13 +87,13 @@ struct {
|
||||||
uint16 vcounter;
|
uint16 vcounter;
|
||||||
} regs;
|
} regs;
|
||||||
|
|
||||||
uint16 get_vram_address();
|
alwaysinline uint16 get_vram_address();
|
||||||
uint8 vram_read(unsigned addr);
|
alwaysinline uint8 vram_read(unsigned addr);
|
||||||
void vram_write(unsigned addr, uint8 data);
|
alwaysinline void vram_write(unsigned addr, uint8 data);
|
||||||
uint8 oam_read(unsigned addr);
|
alwaysinline uint8 oam_read(unsigned addr);
|
||||||
void oam_write(unsigned addr, uint8 data);
|
alwaysinline void oam_write(unsigned addr, uint8 data);
|
||||||
uint8 cgram_read(unsigned addr);
|
alwaysinline uint8 cgram_read(unsigned addr);
|
||||||
void cgram_write(unsigned addr, uint8 data);
|
alwaysinline void cgram_write(unsigned addr, uint8 data);
|
||||||
|
|
||||||
void mmio_update_video_mode();
|
void mmio_update_video_mode();
|
||||||
|
|
||||||
|
|
|
@ -48,7 +48,7 @@ privileged:
|
||||||
Screen screen;
|
Screen screen;
|
||||||
|
|
||||||
static void Enter();
|
static void Enter();
|
||||||
void add_clocks(unsigned);
|
alwaysinline void add_clocks(unsigned);
|
||||||
|
|
||||||
void scanline();
|
void scanline();
|
||||||
void frame();
|
void frame();
|
||||||
|
|
|
@ -30,15 +30,15 @@ struct Screen {
|
||||||
} math;
|
} math;
|
||||||
|
|
||||||
void scanline();
|
void scanline();
|
||||||
void run();
|
alwaysinline void run();
|
||||||
void reset();
|
void reset();
|
||||||
|
|
||||||
uint16 get_pixel_sub(bool hires);
|
uint16 get_pixel_sub(bool hires);
|
||||||
uint16 get_pixel_main();
|
uint16 get_pixel_main();
|
||||||
uint16 addsub(unsigned x, unsigned y);
|
uint16 addsub(unsigned x, unsigned y);
|
||||||
uint16 get_color(unsigned palette);
|
alwaysinline uint16 get_color(unsigned palette);
|
||||||
uint16 get_direct_color(unsigned palette, unsigned tile);
|
alwaysinline uint16 get_direct_color(unsigned palette, unsigned tile);
|
||||||
uint16 fixed_color() const;
|
alwaysinline uint16 fixed_color() const;
|
||||||
|
|
||||||
void serialize(serializer&);
|
void serialize(serializer&);
|
||||||
Screen(PPU& self);
|
Screen(PPU& self);
|
||||||
|
|
|
@ -9,8 +9,8 @@ struct Sprite {
|
||||||
uint8 priority;
|
uint8 priority;
|
||||||
uint8 palette;
|
uint8 palette;
|
||||||
bool size;
|
bool size;
|
||||||
unsigned width() const;
|
alwaysinline unsigned width() const;
|
||||||
unsigned height() const;
|
alwaysinline unsigned height() const;
|
||||||
} list[128];
|
} list[128];
|
||||||
|
|
||||||
struct TileItem {
|
struct TileItem {
|
||||||
|
@ -64,8 +64,8 @@ struct Sprite {
|
||||||
void synchronize();
|
void synchronize();
|
||||||
|
|
||||||
//sprite.cpp
|
//sprite.cpp
|
||||||
void address_reset();
|
alwaysinline void address_reset();
|
||||||
void set_first_sprite();
|
alwaysinline void set_first_sprite();
|
||||||
void frame();
|
void frame();
|
||||||
void scanline();
|
void scanline();
|
||||||
void run();
|
void run();
|
||||||
|
|
|
@ -94,10 +94,11 @@ void System::term() {
|
||||||
|
|
||||||
void System::load() {
|
void System::load() {
|
||||||
string manifest = string::read({interface->path(ID::System), "manifest.bml"});
|
string manifest = string::read({interface->path(ID::System), "manifest.bml"});
|
||||||
auto document = Markup::Document(manifest);
|
auto document = BML::unserialize(manifest);
|
||||||
|
|
||||||
interface->loadRequest(ID::IPLROM, document["system/smp/rom/name"].data);
|
auto iplrom = document["system/smp/rom/name"].text();
|
||||||
if(!file::exists({interface->path(ID::System), document["system/smp/rom/name"].data})) {
|
interface->loadRequest(ID::IPLROM, iplrom);
|
||||||
|
if(!file::exists({interface->path(ID::System), iplrom})) {
|
||||||
interface->notify("Error: required Super Famicom firmware ipl.rom not found.\n");
|
interface->notify("Error: required Super Famicom firmware ipl.rom not found.\n");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -16,17 +16,15 @@ auto CheatDatabase::findCodes() -> void {
|
||||||
auto sha256 = emulator->sha256();
|
auto sha256 = emulator->sha256();
|
||||||
|
|
||||||
auto contents = string::read({localpath(), "tomoko/cheats.bml"});
|
auto contents = string::read({localpath(), "tomoko/cheats.bml"});
|
||||||
auto document = Markup::Document(contents);
|
auto document = BML::unserialize(contents);
|
||||||
|
|
||||||
for(auto& cartridge : document) {
|
for(auto cartridge : document.find("cartridge")) {
|
||||||
if(cartridge.name != "cartridge") continue;
|
|
||||||
if(cartridge["sha256"].text() != sha256) continue;
|
if(cartridge["sha256"].text() != sha256) continue;
|
||||||
|
|
||||||
codes.reset();
|
codes.reset();
|
||||||
cheatList.reset();
|
cheatList.reset();
|
||||||
cheatList.append(ListViewColumn().setWidth(~0));
|
cheatList.append(ListViewColumn().setWidth(~0));
|
||||||
for(auto& cheat : cartridge) {
|
for(auto cheat : cartridge.find("cheat")) {
|
||||||
if(cheat.name != "cheat") continue;
|
|
||||||
codes.append(cheat["code"].text());
|
codes.append(cheat["code"].text());
|
||||||
cheatList.append(ListViewItem().setText(0, cheat["description"].text()));
|
cheatList.append(ListViewItem().setText(0, cheat["description"].text()));
|
||||||
}
|
}
|
||||||
|
|
|
@ -117,10 +117,9 @@ auto CheatEditor::addCode(const string& code, const string& description, bool en
|
||||||
auto CheatEditor::loadCheats() -> void {
|
auto CheatEditor::loadCheats() -> void {
|
||||||
doReset(true);
|
doReset(true);
|
||||||
auto contents = string::read({program->folderPaths[0], "cheats.bml"});
|
auto contents = string::read({program->folderPaths[0], "cheats.bml"});
|
||||||
auto document = Markup::Document(contents);
|
auto document = BML::unserialize(contents);
|
||||||
for(auto& cheat : document["cartridge"]) {
|
for(auto cheat : document["cartridge"].find("cheat")) {
|
||||||
if(cheat.name != "cheat") continue;
|
if(!addCode(cheat["code"].text(), cheat["description"].text(), (bool)cheat["enabled"])) break;
|
||||||
if(!addCode(cheat["code"].text(), cheat["description"].text(), cheat["enabled"].exists())) break;
|
|
||||||
}
|
}
|
||||||
doRefresh();
|
doRefresh();
|
||||||
synchronizeCodes();
|
synchronizeCodes();
|
||||||
|
|
Loading…
Reference in New Issue