Update to v094r17 release.

byuu says:

This updates higan to use the new Markup::Node changes. This is a really
big change, and one slight typo anywhere could break certain classes of
games from playing.

I don't have ananke hooked up again yet, so I don't have the ability to
test this much. If anyone with some v094 game folders wouldn't mind
testing, I'd help out a great deal.

I'm most concerned about testing one of each SNES special chip game.
Most notably, systems like the SA-1, HitachiDSP and NEC-DSP were using
the fancier lookups, eg node["rom[0]/name"], which I had to convert to
a rather ugly node["rom"].at(0)["name"], which I'm fairly confident
won't work. I'm going to blame that on the fumes from the shelves I just
stained >.> Might work with node.find("rom[0]/name")(0) though ...? But
so ugly ... ugh.

That aside, this WIP adds the accuracy-PPU inlining, so the accuracy
profile should run around 7.5% faster than before.
This commit is contained in:
Tim Allen 2015-05-02 23:05:46 +10:00
parent c335ee9d80
commit 39ca8a2fab
45 changed files with 709 additions and 566 deletions

View File

@ -3,7 +3,7 @@
namespace Emulator {
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/";

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

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

@ -0,0 +1,36 @@
#ifndef NALL_DECODE_URL_HPP
#define NALL_DECODE_URL_HPP
namespace nall { namespace Decode {
//returns empty string on malformed content
inline auto URL(const string& input) -> string {
string output;
for(unsigned n = 0; n < input.size();) {
char c = input[n];
if(c >= 'A' && c <= 'Z') { output.append(c); n++; continue; }
if(c >= 'a' && c <= 'z') { output.append(c); n++; continue; }
if(c >= '0' && c <= '9') { output.append(c); n++; continue; }
if(c == '-' || c == '_' || c == '.' || c == '~') { output.append(c); n++; continue; }
if(c == '+') { output.append(' '); n++; continue; }
if(c != '%' || n + 2 >= input.size()) return "";
char hi = input[n + 1];
char lo = input[n + 2];
if(hi >= '0' && hi <= '9') hi -= '0';
else if(hi >= 'A' && hi <= 'F') hi -= 'A' - 10;
else if(hi >= 'a' && hi <= 'f') hi -= 'a' - 10;
else return "";
if(lo >= '0' && lo <= '9') lo -= '0';
else if(lo >= 'A' && lo <= 'F') lo -= 'A' - 10;
else if(lo >= 'a' && lo <= 'f') lo -= 'a' - 10;
else return "";
char byte = hi * 16 + lo;
output.append(byte);
n += 3;
}
return output;
}
}}
#endif

View File

@ -16,7 +16,7 @@ struct file : storage, varint {
enum class mode : unsigned { read, write, modify, append, readwrite = modify, writeread = append };
enum class 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

View File

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

View File

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

View File

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

View File

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

View File

@ -211,6 +211,8 @@ public:
auto operator> (const char* s) const -> bool { return strcmp(data(), s) > 0; }
auto operator>=(const char* s) const -> bool { return strcmp(data(), s) >= 0; }
auto operator+=(const 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); }

View File

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

View File

@ -1,14 +0,0 @@
#ifdef NALL_STRING_INTERNAL_HPP
namespace nall {
namespace Markup {
inline Node Document(const string& markup) {
if(markup.beginsWith("<")) return XML::Document(markup);
return BML::Document(markup);
}
}
}
#endif

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

@ -0,0 +1,135 @@
#ifdef NALL_STRING_INTERNAL_HPP
namespace nall {
namespace Markup {
auto ManagedNode::_evaluate(string query) const -> bool {
if(!query) return true;
for(auto& rule : query.replace(" ", "").split(",")) {
enum class Comparator : unsigned { ID, EQ, NE, LT, LE, GT, GE };
auto comparator = Comparator::ID;
if(rule.match("*!=*")) comparator = Comparator::NE;
else if(rule.match("*<=*")) comparator = Comparator::LE;
else if(rule.match("*>=*")) comparator = Comparator::GE;
else if(rule.match ("*=*")) comparator = Comparator::EQ;
else if(rule.match ("*<*")) comparator = Comparator::LT;
else if(rule.match ("*>*")) comparator = Comparator::GT;
if(comparator == Comparator::ID) {
if(_find(rule).size()) continue;
return false;
}
lstring side;
switch(comparator) {
case Comparator::EQ: side = rule.split<1> ("="); break;
case Comparator::NE: side = rule.split<1>("!="); break;
case Comparator::LT: side = rule.split<1> ("<"); break;
case Comparator::LE: side = rule.split<1>("<="); break;
case Comparator::GT: side = rule.split<1> (">"); break;
case Comparator::GE: side = rule.split<1>(">="); break;
}
string data = string{_value}.strip();
if(side(0).empty() == false) {
auto result = _find(side(0));
if(result.size() == 0) return false;
data = result[0].value();
}
switch(comparator) {
case Comparator::EQ: if(data.match(side(1)) == true) continue; break;
case Comparator::NE: if(data.match(side(1)) == false) continue; break;
case Comparator::LT: if(numeral(data) < numeral(side(1))) continue; break;
case Comparator::LE: if(numeral(data) <= numeral(side(1))) continue; break;
case Comparator::GT: if(numeral(data) > numeral(side(1))) continue; break;
case Comparator::GE: if(numeral(data) >= numeral(side(1))) continue; break;
}
return false;
}
return true;
}
auto ManagedNode::_find(const string& query) const -> vector<Node> {
vector<Node> result;
lstring path = query.split("/");
string name = path.take(0), rule;
unsigned lo = 0u, hi = ~0u;
if(name.match("*[*]")) {
auto p = name.rtrim("]").split<1>("[");
name = p(0);
if(p(1).find("-")) {
p = p(1).split<1>("-");
lo = p(0).empty() ? 0u : numeral(p(0));
hi = p(1).empty() ? ~0u : numeral(p(1));
} else {
lo = hi = numeral(p(1));
}
}
if(name.match("*(*)")) {
auto p = name.rtrim(")").split<1>("(");
name = p(0);
rule = p(1);
}
unsigned position = 0;
for(auto& node : _children) {
if(!node->_name.match(name)) continue;
if(!node->_evaluate(rule)) continue;
bool inrange = position >= lo && position <= hi;
position++;
if(!inrange) continue;
if(path.size() == 0) {
result.append(node);
} else for(auto& item : node->_find(path.merge("/"))) {
result.append(item);
}
}
return result;
}
auto ManagedNode::_lookup(const string& path) const -> Node {
if(auto position = path.find("/")) {
auto name = path.slice(0, *position);
for(auto& node : _children) {
if(name == node->_name) {
return node->_lookup(path.slice(*position + 1));
}
}
} else for(auto& node : _children) {
if(path == node->_name) return node;
}
return {};
}
auto ManagedNode::_create(const string& path) -> Node {
if(auto position = path.find("/")) {
auto name = path.slice(0, *position);
for(auto& node : _children) {
if(name == node->_name) {
return node->_create(path.slice(*position + 1));
}
}
_children.append(new ManagedNode(name));
return _children.last()->_create(path.slice(*position + 1));
}
for(auto& node : _children) {
if(path == node->_name) return node;
}
_children.append(new ManagedNode(path));
return _children.last();
}
}
}
#endif

View File

@ -1,151 +1,123 @@
#ifdef NALL_STRING_INTERNAL_HPP
//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

View File

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

View File

@ -5,6 +5,7 @@
#include <utility>
namespace nall {
using std::nullptr_t;
using std::forward;
using std::move;
using std::decay;

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@ -48,7 +48,7 @@ privileged:
Screen screen;
static void Enter();
void add_clocks(unsigned);
alwaysinline void add_clocks(unsigned);
void scanline();
void frame();

View File

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

View File

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

View File

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

View File

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

View File

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