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