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:
Tim Allen 2015-05-02 23:05:46 +10:00
parent c335ee9d80
commit 39ca8a2fab
45 changed files with 709 additions and 566 deletions

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

36
nall/decode/url.hpp Normal file
View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

135
nall/string/markup/find.hpp Normal file
View File

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

View File

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

View File

@ -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("&", "&amp;"); result.replace("&", "&amp;");
result.replace("<", "&lt;"); result.replace("<", "&lt;");
result.replace(">", "&gt;"); result.replace(">", "&gt;");
if(attribute == false) return result; if(_metadata == 1) {
result.replace("\'", "&apos;"); result.replace("\'", "&apos;");
result.replace("\"", "&quot;"); result.replace("\"", "&quot;");
}
return result; return result;
} }
@ -54,7 +62,7 @@ protected:
if(!memory::compare(source, "&quot;", 6)) { *output++ = '\"'; source += 6; length -= 6; continue; } if(!memory::compare(source, "&quot;", 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;
}
} }
} }

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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