Update to v094r44 release.

byuu says:

Changelog:
- return open bus instead of mirroring addresses on the bus (fixes
  Mario&Luigi, Minish Cap, etc) [Jonas Quinn]
- add boolean flag to load requests for slotted game carts (fixes slot
  load prompts)
- rename BS-X Town cart from psram to ram
- icarus: add support for game database

Note: I didn't rename "bsx" to "mcc" in the database for icarus before
uploading that. But I just fixed it locally, so it'll be in the next
WIP. For now, make it create the manifest for you and then rename it
yourself. I did fix the PSRAM size to 256kbit.
This commit is contained in:
Tim Allen 2015-09-28 21:56:46 +10:00
parent 0c87bdabed
commit 483fc81356
57 changed files with 14259 additions and 719 deletions

View File

@ -8,7 +8,7 @@ using namespace nall;
namespace Emulator {
static const string Name = "higan";
static const string Version = "094.43";
static const string Version = "094.44";
static const string Author = "byuu";
static const string License = "GPLv3";
static const string Website = "http://byuu.org/";

View File

@ -3,11 +3,12 @@ auto CPU::bus_idle() -> void {
}
auto CPU::bus_read(unsigned mode, uint32 addr) -> uint32 {
addr &= 0x0fff'ffff;
unsigned wait = bus_wait(mode, addr);
unsigned word = pipeline.fetch.instruction;
if(addr & 0x0800'0000) {
if(addr >= 0x1000'0000) {
prefetch_step(wait);
} else if(addr & 0x0800'0000) {
if(mode & Prefetch && regs.wait.control.prefetch) {
prefetch_sync(addr);
word = prefetch_read();
@ -35,10 +36,11 @@ auto CPU::bus_read(unsigned mode, uint32 addr) -> uint32 {
}
auto CPU::bus_write(unsigned mode, uint32 addr, uint32 word) -> void {
addr &= 0x0fff'ffff;
unsigned wait = bus_wait(mode, addr);
if(addr & 0x0800'0000) {
if(addr >= 0x1000'0000) {
prefetch_step(wait);
} else if(addr & 0x0800'0000) {
if(!active.dma) prefetch_wait();
step(wait);
addr < 0x0e00'0000 ? cartridge.rom_write(mode, addr, word) : cartridge.ram_write(mode, addr, word);
@ -56,11 +58,12 @@ auto CPU::bus_write(unsigned mode, uint32 addr, uint32 word) -> void {
}
auto CPU::bus_wait(unsigned mode, uint32 addr) -> unsigned {
if(addr < 0x0200'0000) return 1;
if(addr < 0x0300'0000) return (16 - regs.memory.control.ewramwait) * (mode & Word ? 2 : 1);
if(addr < 0x0500'0000) return 1;
if(addr < 0x0700'0000) return mode & Word ? 2 : 1;
if(addr < 0x0800'0000) return 1;
if(addr >= 0x1000'0000) return 1; //unmapped
if(addr < 0x0200'0000) return 1;
if(addr < 0x0300'0000) return (16 - regs.memory.control.ewramwait) * (mode & Word ? 2 : 1);
if(addr < 0x0500'0000) return 1;
if(addr < 0x0700'0000) return mode & Word ? 2 : 1;
if(addr < 0x0800'0000) return 1;
static unsigned timings[] = {5, 4, 3, 9};
unsigned n = timings[regs.wait.control.nwait[addr >> 25 & 3]];

View File

@ -8,14 +8,17 @@ BIOS::~BIOS() {
}
auto BIOS::read(unsigned mode, uint32 addr) -> uint32 {
//unmapped memory
if(addr >= 0x0000'4000) return cpu.pipeline.fetch.instruction; //0000'4000-01ff'ffff
//GBA BIOS is read-protected; only the BIOS itself can read its own memory
//when accessed elsewhere; this returns the last value read by the BIOS program
if(cpu.r(15) >= 0x02000000) return mdr;
//when accessed elsewhere; this should return the last value read by the BIOS program
if(cpu.r(15) >= 0x0000'4000) return mdr;
if(mode & Word) return mdr = read(Half, addr &~ 2) << 0 | read(Half, addr | 2) << 16;
if(mode & Half) return mdr = read(Byte, addr &~ 1) << 0 | read(Byte, addr | 1) << 8;
return mdr = data[addr & 0x3fff];
return mdr = data[addr];
}
auto BIOS::write(unsigned mode, uint32 addr, uint32 word) -> void {

View File

@ -255,7 +255,6 @@ struct Geometry {
Geometry();
Geometry(Position position, Size size);
Geometry(signed x, signed y, signed width, signed height);
Geometry(const string& text);
explicit operator bool() const;
auto operator==(const Geometry& source) const -> bool;
@ -276,7 +275,6 @@ struct Geometry {
auto setX(signed x) -> type&;
auto setY(signed y) -> type&;
auto size() const -> Size;
auto text() const -> string;
auto width() const -> signed;
auto x() const -> signed;
auto y() const -> signed;

View File

@ -12,14 +12,6 @@ Geometry::Geometry(signed x, signed y, signed width, signed height) {
setGeometry(x, y, width, height);
}
Geometry::Geometry(const string& text) {
lstring part = text.split(",").strip();
state.x = integer(part(0));
state.y = integer(part(1));
state.width = integer(part(2));
state.height = integer(part(3));
}
Geometry::operator bool() const {
return state.x || state.y || state.width || state.height;
}
@ -105,10 +97,6 @@ auto Geometry::size() const -> Size {
return {state.width, state.height};
}
auto Geometry::text() const -> string {
return {state.x, ",", state.y, ",", state.width, ",", state.height};
}
auto Geometry::width() const -> signed {
return state.width;
}

View File

@ -120,7 +120,7 @@ auto BrowserDialogWindow::run() -> lstring {
pathName.onActivate([&] { setPath(pathName.text()); });
pathRefresh.setBordered(false).setImage(Icon::Action::Refresh).onActivate([&] { setPath(state.path); });
pathHome.setBordered(false).setImage(Icon::Go::Home).onActivate([&] { setPath(userpath()); });
pathUp.setBordered(false).setImage(Icon::Go::Up).onActivate([&] { setPath(state.path.dirname()); });
pathUp.setBordered(false).setImage(Icon::Go::Up).onActivate([&] { setPath(dirname(state.path)); });
view.setBatchable(state.action == "openFiles").onActivate([&] { activate(); }).onChange([&] { change(); });
filterList.setVisible(state.action != "selectFolder").onChange([&] { setPath(state.path); });
for(auto& filter : state.filters) {

View File

@ -32,7 +32,7 @@ auto pMenuItem::setText(const string& text) -> void {
auto pMenuItem::_setState() -> void {
qtMenuItem->setIcon(CreateImage(state().image));
qtMenuItem->setText(state().text);
qtMenuItem->setText(QString::fromUtf8(state().text));
}
auto QtMenuItem::onActivate() -> void {

View File

@ -11,16 +11,16 @@ auto pFont::size(const QFont& qtFont, const string& text) -> Size {
signed maxWidth = 0;
auto lines = text.split("\n");
for(auto& line : lines) {
maxWidth = max(maxWidth, metrics.width(line));
maxWidth = max(maxWidth, metrics.width(QString::fromUtf8(line)));
}
return {maxWidth, metrics.height() * (signed)lines.size()};
}
auto pFont::family(const string& family) -> string {
auto pFont::family(const string& family) -> QString {
if(family == Font::Sans ) return "Sans";
if(family == Font::Serif) return "Serif";
if(family == Font::Mono ) return "Liberation Mono";
return family ? family : "Sans";
return family ? QString::fromUtf8(family) : "Sans";
}
auto pFont::create(const Font& font) -> QFont {

View File

@ -5,7 +5,7 @@ namespace hiro {
struct pFont {
static auto size(const Font& font, const string& text) -> Size;
static auto size(const QFont& qtFont, const string& text) -> Size;
static auto family(const string& family) -> string;
static auto family(const string& family) -> QString;
static auto create(const Font& font) -> QFont;
};

View File

@ -9,11 +9,11 @@ auto pWindow::construct() -> void {
//if program was given a name, try and set the window taskbar icon to a matching pixmap image
if(auto name = Application::state.name) {
if(file::exists({userpath(), ".local/share/icons/", name, ".png"})) {
qtWindow->setWindowIcon(QIcon(string{userpath(), ".local/share/icons/", name, ".png"}));
qtWindow->setWindowIcon(QIcon(QString::fromUtf8(string{userpath(), ".local/share/icons/", name, ".png"})));
} else if(file::exists({"/usr/local/share/pixmaps/", name, ".png"})) {
qtWindow->setWindowIcon(QIcon(string{"/usr/local/share/pixmaps/", name, ".png"}));
qtWindow->setWindowIcon(QIcon(QString::fromUtf8(string{"/usr/local/share/pixmaps/", name, ".png"})));
} else if(file::exists({"/usr/share/pixmaps/", name, ".png"})) {
qtWindow->setWindowIcon(QIcon(string{"/usr/share/pixmaps/", name, ".png"}));
qtWindow->setWindowIcon(QIcon(QString::fromUtf8(string{"/usr/share/pixmaps/", name, ".png"})));
}
}

View File

@ -10,7 +10,7 @@ auto Icarus::bsxSatellaviewManifest(vector<uint8_t>& buffer, const string& locat
markup.append("\n");
markup.append("information\n");
markup.append(" sha256: ", Hash::SHA256(buffer.data(), buffer.size()).digest(), "\n");
markup.append(" title: ", location.prefixname(), "\n");
markup.append(" title: ", prefixname(location), "\n");
markup.append(" note: ", "heuristically generated by icarus\n");
return markup;
}
@ -18,20 +18,36 @@ auto Icarus::bsxSatellaviewManifest(vector<uint8_t>& buffer, const string& locat
}
auto Icarus::bsxSatellaviewImport(vector<uint8_t>& buffer, const string& location) -> bool {
auto name = location.prefixname();
auto source = location.pathname();
auto name = prefixname(location);
auto source = pathname(location);
string target{settings.libraryPath, "BS-X Satellaview/", name, ".bs/"};
//if(directory::exists(target)) return failure("game already exists");
BsxSatellaviewCartridge cartridge{buffer.data(), buffer.size()};
auto markup = cartridge.markup;
if(!markup) return failure("does not appear to be a valid image");
string markup;
markup.append("\n");
markup.append("information\n");
markup.append(" title: ", name, "\n");
markup.append(" note: heuristically generated by icarus\n");
if(settings.useDatabase && !markup) {
auto digest = Hash::SHA256(buffer.data(), buffer.size()).digest();
for(auto node : database.bsxSatellaview) {
if(node.name() != "release") continue;
if(node["information/sha256"].text() == digest) {
markup.append(BML::serialize(node["cartridge"]), "\n");
markup.append(BML::serialize(node["information"]));
break;
}
}
}
if(settings.useHeuristics && !markup) {
BsxSatellaviewCartridge cartridge{buffer.data(), buffer.size()};
if(markup = cartridge.markup) {
markup.append("\n");
markup.append("information\n");
markup.append(" title: ", name, "\n");
markup.append(" note: heuristically generated by icarus\n");
}
}
if(!markup) return failure("failed to parse ROM image");
if(!directory::create(target)) return failure("library path unwritable");
if(settings.createManifests) file::write({target, "manifest.bml"}, markup);

View File

@ -1,3 +1,15 @@
namespace Database {
#include "../database/super-famicom.hpp"
#include "../database/bsx-satellaview.hpp"
#include "../database/sufami-turbo.hpp"
}
Icarus::Icarus() {
database.superFamicom = BML::unserialize(Database::SuperFamicom);
database.bsxSatellaview = BML::unserialize(Database::BsxSatellaview);
database.sufamiTurbo = BML::unserialize(Database::SufamiTurbo);
}
auto Icarus::error() const -> string {
return errorMessage;
}
@ -16,7 +28,7 @@ auto Icarus::manifest(string location) -> string {
location.transform("\\", "/").rtrim("/").append("/");
if(!directory::exists(location)) return "";
auto type = location.suffixname().downcase();
auto type = suffixname(location).downcase();
if(type == ".fc") return famicomManifest(location);
if(type == ".sfc") return superFamicomManifest(location);
if(type == ".gb") return gameBoyManifest(location);
@ -33,8 +45,8 @@ auto Icarus::import(string location) -> bool {
if(!file::exists(location)) return failure("file does not exist");
if(!file::readable(location)) return failure("file is unreadable");
auto name = location.prefixname();
auto type = location.suffixname().downcase();
auto name = prefixname(location);
auto type = suffixname(location).downcase();
if(!name || !type) return failure("invalid file name");
auto buffer = file::read(location);
@ -45,8 +57,8 @@ auto Icarus::import(string location) -> bool {
if(!zip.open(location)) return failure("ZIP archive is invalid");
if(!zip.file) return failure("ZIP archive is empty");
name = zip.file[0].name.prefixname();
type = zip.file[0].name.suffixname().downcase();
name = prefixname(zip.file[0].name);
type = suffixname(zip.file[0].name).downcase();
buffer = zip.extract(zip.file[0]);
}

View File

@ -1,5 +1,7 @@
struct Icarus {
//core.cpp
Icarus();
auto error() const -> string;
auto success() -> bool;
auto failure(const string& message) -> bool;
@ -47,4 +49,10 @@ struct Icarus {
private:
string errorMessage;
struct {
Markup::Node superFamicom;
Markup::Node bsxSatellaview;
Markup::Node sufamiTurbo;
} database;
};

View File

@ -12,7 +12,7 @@ auto Icarus::famicomManifest(vector<uint8_t>& buffer, const string& location) ->
markup.append("\n");
markup.append("information\n");
markup.append(" sha256: ", Hash::SHA256(buffer.data(), buffer.size()).digest(), "\n");
markup.append(" title: ", location.prefixname(), "\n");
markup.append(" title: ", prefixname(location), "\n");
markup.append(" note: ", "heuristically generated by icarus\n");
return markup;
}
@ -20,20 +20,24 @@ auto Icarus::famicomManifest(vector<uint8_t>& buffer, const string& location) ->
}
auto Icarus::famicomImport(vector<uint8_t>& buffer, const string& location) -> bool {
auto name = location.prefixname();
auto source = location.pathname();
auto name = prefixname(location);
auto source = pathname(location);
string target{settings.libraryPath, "Famicom/", name, ".fc/"};
//if(directory::exists(target)) return failure("game already exists");
FamicomCartridge cartridge{buffer.data(), buffer.size()};
auto markup = cartridge.markup;
if(!markup) return failure("does not appear to be a valid image");
string markup;
markup.append("\n");
markup.append("information\n");
markup.append(" title: ", name, "\n");
markup.append(" note: heuristically generated by icarus\n");
//if(settings.useHeuristics && !markup) {
FamicomCartridge cartridge{buffer.data(), buffer.size()};
if(markup = cartridge.markup) {
markup.append("\n");
markup.append("information\n");
markup.append(" title: ", name, "\n");
markup.append(" note: heuristically generated by icarus\n");
}
//}
if(!markup) return failure("failed to parse ROM image");
if(!directory::create(target)) return failure("library path unwritable");
if(settings.createManifests) file::write({target, "manifest.bml"}, markup);

View File

@ -10,7 +10,7 @@ auto Icarus::gameBoyAdvanceManifest(vector<uint8_t>& buffer, const string& locat
markup.append("\n");
markup.append("information\n");
markup.append(" sha256: ", Hash::SHA256(buffer.data(), buffer.size()).digest(), "\n");
markup.append(" title: ", location.prefixname(), "\n");
markup.append(" title: ", prefixname(location), "\n");
markup.append(" note: ", "heuristically generated by icarus\n");
return markup;
}
@ -18,20 +18,24 @@ auto Icarus::gameBoyAdvanceManifest(vector<uint8_t>& buffer, const string& locat
}
auto Icarus::gameBoyAdvanceImport(vector<uint8_t>& buffer, const string& location) -> bool {
auto name = location.prefixname();
auto source = location.pathname();
auto name = prefixname(location);
auto source = pathname(location);
string target{settings.libraryPath, "Game Boy Advance/", name, ".gba/"};
//if(directory::exists(target)) return failure("game already exists");
GameBoyAdvanceCartridge cartridge{buffer.data(), buffer.size()};
auto markup = cartridge.markup;
if(!markup) return failure("does not appear to be a valid image");
string markup;
markup.append("\n");
markup.append("information\n");
markup.append(" title: ", name, "\n");
markup.append(" note: heuristically generated by icarus\n");
if(settings.useHeuristics && !markup) {
GameBoyAdvanceCartridge cartridge{buffer.data(), buffer.size()};
if(markup = cartridge.markup) {
markup.append("\n");
markup.append("information\n");
markup.append(" title: ", name, "\n");
markup.append(" note: heuristically generated by icarus\n");
}
}
if(!markup) return failure("failed to parse ROM image");
if(!directory::create(target)) return failure("library path unwritable");
if(settings.createManifests) file::write({target, "manifest.bml"}, markup);

View File

@ -10,7 +10,7 @@ auto Icarus::gameBoyColorManifest(vector<uint8_t>& buffer, const string& locatio
markup.append("\n");
markup.append("information\n");
markup.append(" sha256: ", Hash::SHA256(buffer.data(), buffer.size()).digest(), "\n");
markup.append(" title: ", location.prefixname(), "\n");
markup.append(" title: ", prefixname(location), "\n");
markup.append(" note: ", "heuristically generated by icarus\n");
return markup;
}
@ -18,20 +18,24 @@ auto Icarus::gameBoyColorManifest(vector<uint8_t>& buffer, const string& locatio
}
auto Icarus::gameBoyColorImport(vector<uint8_t>& buffer, const string& location) -> bool {
auto name = location.prefixname();
auto source = location.pathname();
auto name = prefixname(location);
auto source = pathname(location);
string target{settings.libraryPath, "Game Boy Color/", name, ".gbc/"};
//if(directory::exists(target)) return failure("game already exists");
GameBoyCartridge cartridge{buffer.data(), buffer.size()};
auto markup = cartridge.markup;
if(!markup) return failure("does not appear to be a valid image");
string markup;
markup.append("\n");
markup.append("information\n");
markup.append(" title: ", name, "\n");
markup.append(" note: heuristically generated by icarus\n");
if(settings.useHeuristics && !markup) {
GameBoyCartridge cartridge{buffer.data(), buffer.size()};
if(markup = cartridge.markup) {
markup.append("\n");
markup.append("information\n");
markup.append(" title: ", name, "\n");
markup.append(" note: heuristically generated by icarus\n");
}
}
if(!markup) return failure("failed to parse ROM image");
if(!directory::create(target)) return failure("library path unwritable");
if(settings.createManifests) file::write({target, "manifest.bml"}, markup);

View File

@ -10,7 +10,7 @@ auto Icarus::gameBoyManifest(vector<uint8_t>& buffer, const string& location) ->
markup.append("\n");
markup.append("information\n");
markup.append(" sha256: ", Hash::SHA256(buffer.data(), buffer.size()).digest(), "\n");
markup.append(" title: ", location.prefixname(), "\n");
markup.append(" title: ", prefixname(location), "\n");
markup.append(" note: ", "heuristically generated by icarus\n");
return markup;
}
@ -18,20 +18,24 @@ auto Icarus::gameBoyManifest(vector<uint8_t>& buffer, const string& location) ->
}
auto Icarus::gameBoyImport(vector<uint8_t>& buffer, const string& location) -> bool {
auto name = location.prefixname();
auto source = location.pathname();
auto name = prefixname(location);
auto source = pathname(location);
string target{settings.libraryPath, "Game Boy/", name, ".gb/"};
//if(directory::exists(target)) return failure("game already exists");
GameBoyCartridge cartridge{buffer.data(), buffer.size()};
auto markup = cartridge.markup;
if(!markup) return failure("does not appear to be a valid image");
string markup;
markup.append("\n");
markup.append("information\n");
markup.append(" title: ", name, "\n");
markup.append(" note: heuristically generated by icarus\n");
if(settings.useHeuristics && !markup) {
GameBoyCartridge cartridge{buffer.data(), buffer.size()};
if(markup = cartridge.markup) {
markup.append("\n");
markup.append("information\n");
markup.append(" title: ", name, "\n");
markup.append(" note: heuristically generated by icarus\n");
}
}
if(!markup) return failure("failed to parse ROM image");
if(!directory::create(target)) return failure("library path unwritable");
if(settings.createManifests) file::write({target, "manifest.bml"}, markup);

View File

@ -10,7 +10,7 @@ auto Icarus::sufamiTurboManifest(vector<uint8_t>& buffer, const string& location
markup.append("\n");
markup.append("information\n");
markup.append(" sha256: ", Hash::SHA256(buffer.data(), buffer.size()).digest(), "\n");
markup.append(" title: ", location.prefixname(), "\n");
markup.append(" title: ", prefixname(location), "\n");
markup.append(" note: ", "heuristically generated by icarus\n");
return markup;
}
@ -18,20 +18,36 @@ auto Icarus::sufamiTurboManifest(vector<uint8_t>& buffer, const string& location
}
auto Icarus::sufamiTurboImport(vector<uint8_t>& buffer, const string& location) -> bool {
auto name = location.prefixname();
auto source = location.pathname();
auto name = prefixname(location);
auto source = pathname(location);
string target{settings.libraryPath, "Sufami Turbo/", name, ".st/"};
//if(directory::exists(target)) return failure("game already exists");
SufamiTurboCartridge cartridge{buffer.data(), buffer.size()};
auto markup = cartridge.markup;
if(!markup) return failure("does not appear to be a valid image");
string markup;
markup.append("\n");
markup.append("information\n");
markup.append(" title: ", name, "\n");
markup.append(" note: heuristically generated by icarus\n");
if(settings.useDatabase && !markup) {
auto digest = Hash::SHA256(buffer.data(), buffer.size()).digest();
for(auto node : database.sufamiTurbo) {
if(node.name() != "release") continue;
if(node["information/sha256"].text() == digest) {
markup.append(BML::serialize(node["cartridge"]), "\n");
markup.append(BML::serialize(node["information"]));
break;
}
}
}
if(settings.useHeuristics && !markup) {
SufamiTurboCartridge cartridge{buffer.data(), buffer.size()};
if(markup = cartridge.markup) {
markup.append("\n");
markup.append("information\n");
markup.append(" title: ", name, "\n");
markup.append(" note: heuristically generated by icarus\n");
}
}
if(!markup) return failure("failed to parse ROM image");
if(!directory::create(target)) return failure("library path unwritable");
if(settings.createManifests) file::write({target, "manifest.bml"}, markup);

View File

@ -15,7 +15,7 @@ auto Icarus::superFamicomManifest(vector<uint8_t>& buffer, const string& locatio
markup.append("\n");
markup.append("information\n");
markup.append(" sha256: ", Hash::SHA256(buffer.data(), buffer.size()).digest(), "\n");
markup.append(" title: ", location.prefixname(), "\n");
markup.append(" title: ", prefixname(location), "\n");
markup.append(" note: ", "heuristically generated by icarus\n");
return markup;
}
@ -23,31 +23,48 @@ auto Icarus::superFamicomManifest(vector<uint8_t>& buffer, const string& locatio
}
auto Icarus::superFamicomImport(vector<uint8_t>& buffer, const string& location) -> bool {
auto name = location.prefixname();
auto source = location.pathname();
auto name = prefixname(location);
auto source = pathname(location);
string target{settings.libraryPath, "Super Famicom/", name, ".sfc/"};
//if(directory::exists(target)) return failure("game already exists");
SuperFamicomCartridge cartridge{buffer.data(), buffer.size()};
auto markup = cartridge.markup;
if(!markup) return failure("does not appear to be a valid image");
string markup;
vector<Markup::Node> roms;
auto document = BML::unserialize(markup);
superFamicomImportScanManifest(roms, document);
bool firmwareAppended = true;
if(settings.useDatabase && !markup) {
auto digest = Hash::SHA256(buffer.data(), buffer.size()).digest();
for(auto node : database.superFamicom) {
if(node.name() != "release") continue;
if(node["information/sha256"].text() == digest) {
markup.append(BML::serialize(node["cartridge"]), "\n");
markup.append(BML::serialize(node["information"]));
break;
}
}
}
if(settings.useHeuristics && !markup) {
SuperFamicomCartridge cartridge{buffer.data(), buffer.size()};
if(markup = cartridge.markup) {
firmwareAppended = cartridge.firmware_appended;
markup.append("\n");
markup.append("information\n");
markup.append(" title: ", name, "\n");
markup.append(" note: ", "heuristically generated by icarus\n");
}
}
auto document = BML::unserialize(markup);
superFamicomImportScanManifest(roms, document["cartridge"]);
for(auto rom : roms) {
auto name = rom["name"].text();
auto size = rom["size"].decimal();
if(name == "program.rom" || name == "data.rom" || cartridge.firmware_appended) continue;
if(name == "program.rom" || name == "data.rom" || firmwareAppended) continue;
if(file::size({source, name}) != size) return failure({"firmware (", name, ") missing or invalid"});
}
markup.append("\n");
markup.append("information\n");
markup.append(" title: ", name, "\n");
markup.append(" note: ", "heuristically generated by icarus\n");
if(!markup) return failure("failed to parse ROM image");
if(!directory::create(target)) return failure("library path unwritable");
if(settings.createManifests) file::write({target, "manifest.bml"}, markup);
@ -55,7 +72,7 @@ auto Icarus::superFamicomImport(vector<uint8_t>& buffer, const string& location)
for(auto rom : roms) {
auto name = rom["name"].text();
auto size = rom["size"].decimal();
if(name == "program.rom" || name == "data.rom" || cartridge.firmware_appended) {
if(name == "program.rom" || name == "data.rom" || firmwareAppended) {
file::write({target, name}, buffer.data() + offset, size);
offset += size;
} else {

View File

@ -0,0 +1,19 @@
string BsxSatellaview = R"(
database revision=2013-01-22
release
cartridge
rom name=program.rom size=0x80000 type=MaskROM
information
title:
name: Same Game - Character Cassette
region: JP
revision: 1.0
board: BSMC-CR-01
serial: BSMC-ZS5J-JPN
sha256: 80c34b50817d58820bc8c88d2d9fa462550b4a76372e19c6467cbfbc8cf5d9ef
configuration
rom name=program.rom size=0x80000 type=MaskROM
)";

View File

@ -0,0 +1,162 @@
string SufamiTurbo = R"(
database revision=2013-01-22
release
cartridge linkable
rom name=program.rom size=0x80000
ram name=save.ram size=0x800
information
title: SDウルトラバトル
name: SD Ultra Battle - Ultraman Densetsu
region: JP
revision: 1.0
serial: SFT-0101-JPN
sha256: 2bb55214fb668ca603d7b944b14f105dfb10b987a8902d420fe4ae1cb69c1d4a
configuration
rom name=program.rom size=0x80000
ram name=save.ram size=0x800
linkable
release
cartridge linkable
rom name=program.rom size=0x80000
ram name=save.ram size=0x800
information
title: SDウルトラバトル
name: SD Ultra Battle - Seven Densetsu
region: JP
revision: 1.0
serial: SFT-0102-JPN
sha256: 2fec5f2bc7dee010af10569a3d2bc18715a79a126940800c3eade5abbd625e3f
configuration
rom name=program.rom size=0x80000
ram name=save.ram size=0x800
linkable
release
cartridge linkable
rom name=program.rom size=0x80000
ram name=save.ram size=0x800
information
title:
name: Poi Poi Ninja World
region: JP
revision: 1.0
serial: SFT-0103-JPN
sha256: 602b20b788640f5743487108a10f3f77bca5ce2d24208b25b1ca498a96eb0d69
configuration
rom name=program.rom size=0x80000
ram name=save.ram size=0x800
linkable
release
cartridge linkable
rom name=program.rom size=0x80000
ram name=save.ram size=0x2000
information
title: SDガンダムジェネレーション
name: SD Gundam Generation - Ichinen Sensouki
region: JP
revision: 1.0
serial: SFT-0104-JPN
sha256: 3e82215bed08274874b30d461fc4a965c6bca932229da5d46d56e36f484d65eb
configuration
rom name=program.rom size=0x80000
ram name=save.ram size=0x2000
linkable
release
cartridge linkable
rom name=program.rom size=0x80000
ram name=save.ram size=0x2000
information
title: SDガンダムジェネレーション
name: SD Gundam Generation - Grips Senki
region: JP
revision: 1.0
serial: SFT-0105-JPN
sha256: 8547a08ed11fe408eac282a90ac46654bd2e5f49bda3aec8e5edf166a0a4b9af
configuration
rom name=program.rom size=0x80000
ram name=save.ram size=0x2000
linkable
release
cartridge
rom name=program.rom size=0x80000
information
title:
name: Gegege no Kitarou - Youkai Donjara
region: JP
revision: 1.0
serial: SFT-0106-JPN
sha256: d93b3a570e7cf343f680ab0768a50b77e3577f9c555007e2de3decd6bc4765c8
configuration
rom name=program.rom size=0x80000
release
cartridge linkable
rom name=program.rom size=0x80000
ram name=save.ram size=0x2000
information
title: SDガンダムジェネレーション
name: SD Gundam Generation - Axis Senki
region: JP
revision: 1.0
serial: SFT-0107-JPN
sha256: 2a9d7c9a61318861028a73ca03e32a48cff162d76cba36fbaab8690b212efe9b
configuration
rom name=program.rom size=0x80000
ram name=save.ram size=0x2000
linkable
release
cartridge linkable
rom name=program.rom size=0x80000
ram name=save.ram size=0x2000
information
title: SDガンダムジェネレーション
name: SD Gundam Generation - Babylonia Kenkoku Senki
region: JP
revision: 1.0
serial: SFT-0108-JPN
sha256: 60ac017c18f534e8cf24ca7f38e22ce92db95ea6c30b2d59d76f13c4f1c8a6e4
configuration
rom name=program.rom size=0x80000
ram name=save.ram size=0x2000
linkable
release
cartridge linkable
rom name=program.rom size=0x80000
ram name=save.ram size=0x2000
information
title: SDガンダムジェネレーション
name: SD Gundam Generation - Zanscar Senki
region: JP
revision: 1.0
serial: SFT-0110-JPN
sha256: 5951a58a91d8e397d0a237ccc2b1248e17c7312cb9cc11cbc350200a97b4e021
configuration
rom name=program.rom size=0x80000
ram name=save.ram size=0x2000
linkable
release
cartridge linkable
rom name=program.rom size=0x80000
ram name=save.ram size=0x800
information
title: SDガンダムジェネレーション
name: SD Gundam Generation - Colony Kakutouki
region: JP
revision: 1.0
serial: SFT-0111-JPN
sha256: e639b5d5d722432b6809ccc6801dc584e1a3016379f34b335ed2dfa73b1ebf69
configuration
rom name=program.rom size=0x80000
ram name=save.ram size=0x800
linkable
)";

File diff suppressed because it is too large Load Diff

View File

@ -390,7 +390,7 @@ SuperFamicomCartridge::SuperFamicomCartridge(const uint8_t *data, unsigned size)
" mcc\n"
" rom name=program.rom size=0x", hex(rom_size), "\n"
" ram id=save name=save.ram size=0x", hex(ram_size), "\n"
" ram id=download name=bsx.ram size=0x80000\n"
" ram id=download name=download.ram size=0x80000\n"
" map id=io address=00-3f,80-bf:5000-5fff\n"
" map id=rom address=00-3f,80-bf:8000-ffff\n"
" map id=rom address=40-7f,c0-ff:0000-ffff\n"

View File

@ -6,12 +6,16 @@ struct Settings : Configuration::Document {
string activePath;
string libraryPath;
bool createManifests = false;
bool useDatabase = true;
bool useHeuristics = true;
};
Settings::Settings() {
root.append(activePath, "ActivePath");
root.append(libraryPath, "LibraryPath");
root.append(createManifests, "CreateManifests");
root.append(useDatabase, "UseDatabase");
root.append(useHeuristics, "UseHeuristics");
append(root, "Settings");
directory::create({configpath(), "icarus/"});

View File

@ -20,7 +20,7 @@ auto ImportDialog::run(lstring locations) -> void {
setVisible(true);
for(auto& location : locations) {
auto name = location.basename();
auto name = basename(location);
if(abort) {
errors.append(string{"[", name, "] aborted"});

View File

@ -4,16 +4,16 @@ ScanDialog::ScanDialog() {
onClose(&Application::quit);
layout.setMargin(5);
pathEdit.onActivate([&] { refresh(); });
refreshButton.setIcon(Icon::Action::Refresh).setBordered(false).onActivate([&] {
refreshButton.setImage(Icon::Action::Refresh).setBordered(false).onActivate([&] {
pathEdit.setText(settings.activePath);
refresh();
});
homeButton.setIcon(Icon::Go::Home).setBordered(false).onActivate([&] {
homeButton.setImage(Icon::Go::Home).setBordered(false).onActivate([&] {
pathEdit.setText(userpath());
refresh();
});
upButton.setIcon(Icon::Go::Up).setBordered(false).onActivate([&] {
pathEdit.setText(settings.activePath.dirname());
upButton.setImage(Icon::Go::Up).setBordered(false).onActivate([&] {
pathEdit.setText(dirname(settings.activePath));
refresh();
});
scanList.onActivate([&] { activate(); });
@ -51,14 +51,14 @@ auto ScanDialog::refresh() -> void {
for(auto& name : contents) {
if(!name.endsWith("/")) continue;
if(gamePakType(name.suffixname())) continue;
scanList.append(ListViewItem().append(ListViewCell().setIcon(Icon::Emblem::Folder).setText(name.rtrim("/"))));
if(gamePakType(suffixname(name))) continue;
scanList.append(ListViewItem().append(ListViewCell().setImage(Icon::Emblem::Folder).setText(name.rtrim("/"))));
}
for(auto& name : contents) {
if(name.endsWith("/")) continue;
if(!gameRomType(name.suffixname().downcase())) continue;
scanList.append(ListViewItem().append(ListViewCell().setCheckable().setIcon(Icon::Emblem::File).setText(name)));
if(!gameRomType(suffixname(name).downcase())) continue;
scanList.append(ListViewItem().append(ListViewCell().setCheckable().setImage(Icon::Emblem::File).setText(name)));
}
Application::processEvents();
@ -69,7 +69,7 @@ auto ScanDialog::refresh() -> void {
auto ScanDialog::activate() -> void {
if(auto item = scanList.selected()) {
string location{settings.activePath, item.cell(0).text()};
if(directory::exists(location) && !gamePakType(location.suffixname())) {
if(directory::exists(location) && !gamePakType(suffixname(location))) {
pathEdit.setText(location);
refresh();
}

View File

@ -171,7 +171,7 @@ auto Response::findContentLength() const -> unsigned {
auto Response::findContentType() const -> string {
if(auto contentType = header("Content-Type")) return contentType;
if(hasData()) return "application/octet-stream";
if(hasFile()) return findContentType(file().suffixname());
if(hasFile()) return findContentType(suffixname(file()));
return "text/html; charset=utf-8";
}

View File

@ -22,7 +22,7 @@ struct zipstream : memorystream {
if(file.name.match(filter)) {
auto buffer = archive.extract(file);
psize = buffer.size();
pdata = buffer.move();
pdata = buffer.release();
return;
}
}

View File

@ -26,7 +26,7 @@
#define NALL_STRING_INTERNAL_HPP
#include <nall/string/base.hpp>
#include <nall/string/ref.hpp>
#include <nall/string/view.hpp>
#include <nall/string/atoi.hpp>
#include <nall/string/cast.hpp>
#include <nall/string/compare.hpp>

View File

@ -2,12 +2,13 @@
namespace nall {
struct string_view;
struct string;
struct format;
struct stringref;
struct lstring;
using rstring = const string_view&;
using cstring = const string&;
using rstring = const stringref&;
#define NALL_STRING_ALLOCATOR_ADAPTIVE
//#define NALL_STRING_ALLOCATOR_COPY_ON_WRITE
@ -17,46 +18,6 @@ using rstring = const stringref&;
//cast.hpp
template<typename T> struct stringify;
//compare.hpp
inline auto compare(const string& self, rstring source) -> signed;
inline auto icompare(const string& self, rstring source) -> signed;
inline auto equals(const string& self, rstring source) -> bool;
inline auto iequals(const string& self, rstring source) -> bool;
inline auto beginsWith(const string& self, rstring source) -> bool;
inline auto ibeginsWith(const string& self, rstring source) -> bool;
inline auto endsWith(const string& self, rstring source) -> bool;
inline auto iendsWith(const string& self, rstring source) -> bool;
//convert.hpp
inline auto downcase(string& self) -> string&;
inline auto qdowncase(string& self) -> string&;
inline auto upcase(string& self) -> string&;
inline auto qupcase(string& self) -> string&;
inline auto transform(string& self, rstring from, rstring to) -> string&;
//core.hpp
template<typename... P> inline auto assign(string& self, P&&... p) -> string&;
template<typename T, typename... P> inline auto append(string& self, const T& value, P&&... p) -> string&;
template<typename... P> inline auto append(string& self, const format& value, P&&... p) -> string&;
inline auto append(string& self) -> string&;
template<typename T> inline auto _append(string& self, const stringify<T>& source) -> string&;
inline auto empty(const string& self) -> bool;
inline auto length(const string& self) -> unsigned;
//find.hpp
template<bool I, bool Q> inline auto _find(const string& self, signed offset, rstring source) -> maybe<unsigned>;
inline auto find(const string& self, rstring source) -> maybe<unsigned>;
inline auto ifind(const string& self, rstring source) -> maybe<unsigned>;
inline auto qfind(const string& self, rstring source) -> maybe<unsigned>;
inline auto iqfind(const string& self, rstring source) -> maybe<unsigned>;
inline auto findFrom(const string& self, signed offset, rstring source) -> maybe<unsigned>;
inline auto ifindFrom(const string& self, signed offset, rstring source) -> maybe<unsigned>;
//format.hpp
template<typename... P> inline auto print(P&&...) -> void;
inline auto integer(intmax_t value, long precision = 0, char padchar = '0') -> string;
@ -69,23 +30,22 @@ inline auto pointer(uintptr_t value, long precision = 0) -> string;
inline auto real(long double value) -> string;
//hash.hpp
inline auto crc16(const string& self) -> string;
inline auto crc32(const string& self) -> string;
inline auto sha256(const string& self) -> string;
inline auto crc16(rstring self) -> string;
inline auto crc32(rstring self) -> string;
inline auto sha256(rstring self) -> string;
//match.hpp
inline auto match(const string& self, rstring source) -> bool;
inline auto imatch(const string& self, rstring source) -> bool;
inline auto tokenize(const char* s, const char* p) -> bool;
inline auto tokenize(lstring& list, const char* s, const char* p) -> bool;
//path.hpp
inline auto pathname(const string& self) -> string;
inline auto filename(const string& self) -> string;
inline auto pathname(rstring self) -> string;
inline auto filename(rstring self) -> string;
inline auto dirname(const string& self) -> string;
inline auto basename(const string& self) -> string;
inline auto prefixname(const string& self) -> string;
inline auto suffixname(const string& self) -> string;
inline auto dirname(rstring self) -> string;
inline auto basename(rstring self) -> string;
inline auto prefixname(rstring self) -> string;
inline auto suffixname(rstring self) -> string;
//platform.hpp
inline auto activepath() -> string;
@ -97,41 +57,8 @@ inline auto localpath() -> string;
inline auto sharedpath() -> string;
inline auto temppath() -> string;
//replace.hpp
template<bool I, bool Q> inline auto _replace(string& self, rstring from, rstring to, long limit = LONG_MAX) -> string&;
inline auto replace(string& self, rstring from, rstring to, long limit = LONG_MAX) -> string&;
inline auto ireplace(string& self, rstring from, rstring to, long limit = LONG_MAX) -> string&;
inline auto qreplace(string& self, rstring from, rstring to, long limit = LONG_MAX) -> string&;
inline auto iqreplace(string& self, rstring from, rstring to, long limit = LONG_MAX) -> string&;
//split.hpp
template<bool I, bool Q> inline auto _split(lstring& self, rstring source, rstring find, long limit = LONG_MAX) -> lstring&;
inline auto split(string& self, rstring key, long limit = LONG_MAX) -> lstring;
inline auto isplit(string& self, rstring key, long limit = LONG_MAX) -> lstring;
inline auto qsplit(string& self, rstring key, long limit = LONG_MAX) -> lstring;
inline auto iqsplit(string& self, rstring key, long limit = LONG_MAX) -> lstring;
//trim.hpp
inline auto trim(string& self, rstring lhs, rstring rhs, long limit = LONG_MAX) -> string&;
inline auto ltrim(string& self, rstring lhs, long limit = LONG_MAX) -> string&;
inline auto rtrim(string& self, rstring rhs, long limit = LONG_MAX) -> string&;
inline auto itrim(string& self, rstring lhs, rstring rhs, long limit = LONG_MAX) -> string&;
inline auto iltrim(string& self, rstring lhs, long limit = LONG_MAX) -> string&;
inline auto irtrim(string& self, rstring rhs, long limit = LONG_MAX) -> string&;
inline auto strip(string& self) -> string&;
inline auto lstrip(string& self) -> string&;
inline auto rstrip(string& self) -> string&;
//utility.hpp
inline auto fill(string& self, char fill = ' ') -> string&;
inline auto hash(const string& self) -> unsigned;
inline auto remove(string& self, unsigned offset, unsigned length) -> string&;
inline auto reverse(string& self) -> string&;
inline auto size(string& self, signed length, char fill = ' ') -> string&;
inline auto slice(const string& self, signed offset = 0, signed length = -1) -> string;
inline auto substr(rstring source, signed offset = 0, signed length = -1) -> string;
inline auto slice(rstring self, signed offset = 0, signed length = -1) -> string;
inline auto integer(char* result, intmax_t value) -> char*;
inline auto decimal(char* result, uintmax_t value) -> char*;
@ -212,7 +139,7 @@ public:
auto operator>=(const char* s) const -> bool { return strcmp(data(), s) >= 0; }
string(const string& source) : string() { operator=(source); }
string(string&& source) : string() { operator=(std::move(source)); }
string(string&& source) : string() { operator=(move(source)); }
auto begin() -> char* { return &get()[0]; }
auto end() -> char* { return &get()[size()]; }
@ -226,82 +153,67 @@ public:
//core.hpp
inline auto operator[](signed) const -> const char&;
template<typename... P> inline auto assign(P&&...) -> type&;
template<typename T, typename... P> inline auto append(const T&, P&&...) -> type&;
template<typename... P> inline auto append(const nall::format&, P&&...) -> type&;
inline auto append() -> type&;
template<typename T> inline auto _append(const stringify<T>&) -> string&;
inline auto empty() const -> bool;
inline auto length() const -> unsigned;
//datetime.hpp
inline static auto date(time_t = 0) -> string;
inline static auto time(time_t = 0) -> string;
inline static auto datetime(time_t = 0) -> string;
//find.hpp
template<bool, bool> inline auto _find(signed, rstring) const -> maybe<unsigned>;
inline auto find(rstring source) const -> maybe<unsigned>;
inline auto ifind(rstring source) const -> maybe<unsigned>;
inline auto qfind(rstring source) const -> maybe<unsigned>;
inline auto iqfind(rstring source) const -> maybe<unsigned>;
inline auto findFrom(signed offset, rstring source) const -> maybe<unsigned>;
inline auto ifindFrom(signed offset, rstring source) const -> maybe<unsigned>;
//format.hpp
inline auto format(const nall::format& params) -> type&;
//utility.hpp
inline static auto read(const string& filename) -> string;
inline static auto repeat(const string& pattern, unsigned times) -> string;
//extension methods
//=================
//compare.hpp
auto compare(rstring source) const -> signed { return nall::compare(*this, source); }
auto icompare(rstring source) const -> signed { return nall::icompare(*this, source); }
template<bool> inline static auto _compare(const char*, unsigned, const char*, unsigned) -> signed;
auto equals(rstring source) const -> bool { return nall::equals(*this, source); }
auto iequals(rstring source) const -> bool { return nall::iequals(*this, source); }
inline auto compare(rstring source) const -> signed;
inline auto icompare(rstring source) const -> signed;
auto beginsWith(rstring source) const -> bool { return nall::beginsWith(*this, source); }
auto ibeginsWith(rstring source) const -> bool { return nall::ibeginsWith(*this, source); }
inline auto equals(rstring source) const -> bool;
inline auto iequals(rstring source) const -> bool;
auto endsWith(rstring source) const -> bool { return nall::endsWith(*this, source); }
auto iendsWith(rstring source) const -> bool { return nall::iendsWith(*this, source); }
inline auto beginsWith(rstring source) const -> bool;
inline auto ibeginsWith(rstring source) const -> bool;
inline auto endsWith(rstring source) const -> bool;
inline auto iendsWith(rstring source) const -> bool;
//convert.hpp
auto downcase() -> type& { return nall::downcase(*this); }
auto upcase() -> type& { return nall::upcase(*this); }
inline auto downcase() -> type&;
inline auto upcase() -> type&;
auto qdowncase() -> type& { return nall::qdowncase(*this); }
auto qupcase() -> type& { return nall::qupcase(*this); }
inline auto qdowncase() -> type&;
inline auto qupcase() -> type&;
auto transform(rstring from, rstring to) -> type& { return nall::transform(*this, from, to); }
//core.hpp
template<typename... P> auto assign(P&&... p) -> type& { return nall::assign(*this, forward<P>(p)...); }
template<typename... P> auto append(P&&... p) -> type& { return nall::append(*this, forward<P>(p)...); }
auto empty() const -> bool { return nall::empty(*this); }
auto length() const -> unsigned { return nall::length(*this); }
//find.hpp
auto find(rstring source) const -> maybe<unsigned> { return nall::find(*this, source); }
auto ifind(rstring source) const -> maybe<unsigned> { return nall::ifind(*this, source); }
auto qfind(rstring source) const -> maybe<unsigned> { return nall::qfind(*this, source); }
auto iqfind(rstring source) const -> maybe<unsigned> { return nall::iqfind(*this, source); }
auto findFrom(signed offset, rstring source) const -> maybe<unsigned> { return nall::findFrom(*this, offset, source); }
auto ifindFrom(signed offset, rstring source) const -> maybe<unsigned> { return nall::ifindFrom(*this, offset, source); }
//hash.hpp
auto crc16() const -> string { return nall::crc16(*this); }
auto crc32() const -> string { return nall::crc32(*this); }
auto sha256() const -> string { return nall::sha256(*this); }
inline auto transform(rstring from, rstring to) -> type&;
//match.hpp
auto match(rstring source) const -> bool { return nall::match(*this, source); }
auto imatch(rstring source) const -> bool { return nall::imatch(*this, source); }
//path.hpp
auto pathname() const -> string { return nall::pathname(*this); }
auto filename() const -> string { return nall::filename(*this); }
auto dirname() const -> string { return nall::dirname(*this); }
auto basename() const -> string { return nall::basename(*this); }
auto prefixname() const -> string { return nall::prefixname(*this); }
auto suffixname() const -> string { return nall::suffixname(*this); }
inline auto match(rstring source) const -> bool;
inline auto imatch(rstring source) const -> bool;
//replace.hpp
auto replace(rstring from, rstring to, long limit = LONG_MAX) -> type& { return nall::_replace<0, 0>(*this, from, to, limit); }
auto ireplace(rstring from, rstring to, long limit = LONG_MAX) -> type& { return nall::_replace<1, 0>(*this, from, to, limit); }
auto qreplace(rstring from, rstring to, long limit = LONG_MAX) -> type& { return nall::_replace<0, 1>(*this, from, to, limit); }
auto iqreplace(rstring from, rstring to, long limit = LONG_MAX) -> type& { return nall::_replace<1, 1>(*this, from, to, limit); }
template<bool, bool> inline auto _replace(rstring, rstring, long) -> type&;
inline auto replace(rstring from, rstring to, long limit = LONG_MAX) -> type&;
inline auto ireplace(rstring from, rstring to, long limit = LONG_MAX) -> type&;
inline auto qreplace(rstring from, rstring to, long limit = LONG_MAX) -> type&;
inline auto iqreplace(rstring from, rstring to, long limit = LONG_MAX) -> type&;
//split.hpp
inline auto split(rstring key, long limit = LONG_MAX) const -> lstring;
@ -310,40 +222,28 @@ public:
inline auto iqsplit(rstring key, long limit = LONG_MAX) const -> lstring;
//trim.hpp
auto trim(rstring lhs, rstring rhs, long limit = LONG_MAX) -> type& { return nall::trim(*this, lhs, rhs, limit); }
auto ltrim(rstring lhs, long limit = LONG_MAX) -> type& { return nall::ltrim(*this, lhs, limit); }
auto rtrim(rstring rhs, long limit = LONG_MAX) -> type& { return nall::rtrim(*this, rhs, limit); }
inline auto trim(rstring lhs, rstring rhs, long limit = LONG_MAX) -> type&;
inline auto ltrim(rstring lhs, long limit = LONG_MAX) -> type&;
inline auto rtrim(rstring rhs, long limit = LONG_MAX) -> type&;
auto itrim(rstring lhs, rstring rhs, long limit = LONG_MAX) -> type& { return nall::itrim(*this, lhs, rhs, limit); }
auto iltrim(rstring lhs, long limit = LONG_MAX) -> type& { return nall::iltrim(*this, lhs, limit); }
auto irtrim(rstring rhs, long limit = LONG_MAX) -> type& { return nall::irtrim(*this, rhs, limit); }
inline auto itrim(rstring lhs, rstring rhs, long limit = LONG_MAX) -> type&;
inline auto iltrim(rstring lhs, long limit = LONG_MAX) -> type&;
inline auto irtrim(rstring rhs, long limit = LONG_MAX) -> type&;
auto strip() -> type& { return nall::strip(*this); }
auto lstrip() -> type& { return nall::lstrip(*this); }
auto rstrip() -> type& { return nall::rstrip(*this); }
inline auto strip() -> type&;
inline auto lstrip() -> type&;
inline auto rstrip() -> type&;
//utility.hpp
auto fill(char fill = ' ') -> type& { return nall::fill(*this, fill); }
auto hash() const -> const type& { return nall::hash(*this), *this; }
auto remove(unsigned offset, unsigned length) -> type& { return nall::remove(*this, offset, length); }
auto reverse() -> type& { return nall::reverse(*this); }
auto size(signed length, char fill = ' ') -> type& { return nall::size(*this, length, fill); }
auto slice(signed offset = 0, signed length = -1) const -> string { return nall::slice(*this, offset, length); }
#if defined(QSTRING_H)
inline operator QString() const;
#endif
inline static auto read(rstring filename) -> string;
inline static auto repeat(rstring pattern, unsigned times) -> string;
inline auto fill(char fill = ' ') -> type&;
inline auto hash() const -> unsigned;
inline auto remove(unsigned offset, unsigned length) -> type&;
inline auto reverse() -> type&;
inline auto size(signed length, char fill = ' ') -> type&;
};
//list.hpp
template<typename... P> auto append(lstring& self, const string& value, P&&... p) -> lstring&;
inline auto append(lstring& self) -> lstring&;
inline auto find(const lstring& self, const string& source) -> maybe<unsigned>;
inline auto ifind(const lstring& self, const string& source) -> maybe<unsigned>;
inline auto match(const lstring& self, const string& pattern) -> lstring;
inline auto merge(const lstring& self, const string& separator) -> string;
inline auto strip(lstring& self) -> lstring&;
struct lstring : vector<string> {
using type = lstring;
@ -362,33 +262,25 @@ struct lstring : vector<string> {
inline auto isort() -> type&;
//extension methods
//=================
template<typename... P> inline auto append(const string&, P&&...) -> type&;
inline auto append() -> type&;
//list.hpp
template<typename... P> auto append(P&&... p) -> type& { return nall::append(*this, forward<P>(p)...); }
auto find(const string& source) const -> maybe<unsigned> { return nall::find(*this, source); }
auto ifind(const string& source) const -> maybe<unsigned> { return nall::ifind(*this, source); }
auto match(const string& pattern) const -> lstring { return nall::match(*this, pattern); }
auto merge(const string& separator) const -> string { return nall::merge(*this, separator); }
auto strip() -> type& { return nall::strip(*this); }
inline auto find(rstring source) const -> maybe<unsigned>;
inline auto ifind(rstring source) const -> maybe<unsigned>;
inline auto match(rstring pattern) const -> lstring;
inline auto merge(rstring separator) const -> string;
inline auto strip() -> type&;
//split.hpp
auto split(rstring source, rstring on, long limit = LONG_MAX) -> type& { return nall::_split<0, 0>(*this, source, on, limit); }
auto isplit(rstring source, rstring on, long limit = LONG_MAX) -> type& { return nall::_split<1, 0>(*this, source, on, limit); }
auto qsplit(rstring source, rstring on, long limit = LONG_MAX) -> type& { return nall::_split<0, 1>(*this, source, on, limit); }
auto iqsplit(rstring source, rstring on, long limit = LONG_MAX) -> type& { return nall::_split<1, 1>(*this, source, on, limit); }
template<bool, bool> inline auto _split(rstring, rstring, long) -> lstring&;
};
//format.hpp
template<typename T, typename... P> inline auto append(format& self, const T& value, P&&... p) -> format&;
inline auto append(format& self) -> format&;
struct format : vector<string> {
using type = format;
template<typename... P> format(P&&... p) { reserve(sizeof...(p)); append(forward<P>(p)...); }
template<typename... P> auto append(P&&... p) -> type& { return nall::append(*this, forward<P>(p)...); }
template<typename T, typename... P> inline auto append(const T&, P&&... p) -> type&;
inline auto append() -> type&;
};
}

View File

@ -186,34 +186,24 @@ template<> struct stringify<const string&> {
stringify(const string& source) : _text(source) {}
};
#if defined(QSTRING_H)
//Qt
template<> struct stringify<QString> {
const QString& _text;
auto data() const -> const char* { return _text.toUtf8().constData(); }
auto size() const -> unsigned { return _text.size(); }
stringify(const QString& source) : _text(source) {}
template<> struct stringify<string_view> {
const string_view& _view;
auto data() const -> const char* { return _view.data(); }
auto size() const -> unsigned { return _view.size(); }
stringify(const string_view& source) : _view(source) {}
};
template<> struct stringify<const QString&> {
const QString& _text;
auto data() const -> const char* { return _text.toUtf8().constData(); }
auto size() const -> unsigned { return _text.size(); }
stringify(const QString& source) : _text(source) {}
template<> struct stringify<const string_view&> {
const string_view& _view;
auto data() const -> const char* { return _view.data(); }
auto size() const -> unsigned { return _view.size(); }
stringify(const string_view& source) : _view(source) {}
};
string::operator QString() const {
return QString::fromUtf8(*this);
}
#endif
//
template<typename T> auto make_string(T value) -> stringify<T> {
return stringify<T>(std::forward<T>(value));
return stringify<T>(forward<T>(value));
}
}

View File

@ -2,47 +2,48 @@
namespace nall {
template<bool Insensitive> inline auto _compare(const char* target, unsigned capacity, const char* source, unsigned size) -> signed {
template<bool Insensitive>
auto string::_compare(const char* target, unsigned capacity, const char* source, unsigned size) -> signed {
if(Insensitive) return memory::icompare(target, capacity, source, size);
return memory::compare(target, capacity, source, size);
}
auto compare(const string& self, rstring source) -> signed {
return memory::compare(self.data(), self.size(), source.data(), source.size());
auto string::compare(rstring source) const -> signed {
return memory::compare(data(), size(), source.data(), source.size());
}
auto icompare(const string& self, rstring source) -> signed {
return memory::icompare(self.data(), self.size(), source.data(), source.size());
auto string::icompare(rstring source) const -> signed {
return memory::icompare(data(), size(), source.data(), source.size());
}
auto equals(const string& self, rstring source) -> bool {
if(self.size() != source.size()) return false;
return memory::compare(self.data(), source.data(), source.size()) == 0;
auto string::equals(rstring source) const -> bool {
if(size() != source.size()) return false;
return memory::compare(data(), source.data(), source.size()) == 0;
}
auto iequals(const string& self, rstring source) -> bool {
if(self.size() != source.size()) return false;
return memory::icompare(self.data(), source.data(), source.size()) == 0;
auto string::iequals(rstring source) const -> bool {
if(size() != source.size()) return false;
return memory::icompare(data(), source.data(), source.size()) == 0;
}
auto beginsWith(const string& self, rstring source) -> bool {
if(source.size() > self.size()) return false;
return memory::compare(self.data(), source.data(), source.size()) == 0;
auto string::beginsWith(rstring source) const -> bool {
if(source.size() > size()) return false;
return memory::compare(data(), source.data(), source.size()) == 0;
}
auto ibeginsWith(const string& self, rstring source) -> bool {
if(source.size() > self.size()) return false;
return memory::icompare(self.data(), source.data(), source.size()) == 0;
auto string::ibeginsWith(rstring source) const -> bool {
if(source.size() > size()) return false;
return memory::icompare(data(), source.data(), source.size()) == 0;
}
auto endsWith(const string& self, rstring source) -> bool {
if(source.size() > self.size()) return false;
return memory::compare(self.data() + self.size() - source.size(), source.data(), source.size()) == 0;
auto string::endsWith(rstring source) const -> bool {
if(source.size() > size()) return false;
return memory::compare(data() + size() - source.size(), source.data(), source.size()) == 0;
}
auto iendsWith(const string& self, rstring source) -> bool {
if(source.size() > self.size()) return false;
return memory::icompare(self.data() + self.size() - source.size(), source.data(), source.size()) == 0;
auto string::iendsWith(rstring source) const -> bool {
if(source.size() > size()) return false;
return memory::icompare(data() + size() - source.size(), source.data(), source.size()) == 0;
}
}

View File

@ -2,44 +2,44 @@
namespace nall {
auto downcase(string& self) -> string& {
char* p = self.get();
for(unsigned n = 0; n < self.size(); n++) {
auto string::downcase() -> string& {
char* p = get();
for(unsigned n = 0; n < size(); n++) {
if(p[n] >= 'A' && p[n] <= 'Z') p[n] += 0x20;
}
return self;
return *this;
}
auto qdowncase(string& self) -> string& {
char* p = self.get();
for(unsigned n = 0, quoted = 0; n < self.size(); n++) {
auto string::qdowncase() -> string& {
char* p = get();
for(unsigned n = 0, quoted = 0; n < size(); n++) {
if(p[n] == '\"') quoted ^= 1;
if(!quoted && p[n] >= 'A' && p[n] <= 'Z') p[n] += 0x20;
}
return self;
return *this;
}
auto upcase(string& self) -> string& {
char* p = self.get();
for(unsigned n = 0; n < self.size(); n++) {
auto string::upcase() -> string& {
char* p = get();
for(unsigned n = 0; n < size(); n++) {
if(p[n] >= 'a' && p[n] <= 'z') p[n] -= 0x20;
}
return self;
return *this;
}
auto qupcase(string& self) -> string& {
char* p = self.get();
for(unsigned n = 0, quoted = 0; n < self.size(); n++) {
auto string::qupcase() -> string& {
char* p = get();
for(unsigned n = 0, quoted = 0; n < size(); n++) {
if(p[n] == '\"') quoted ^= 1;
if(!quoted && p[n] >= 'a' && p[n] <= 'z') p[n] -= 0x20;
}
return self;
return *this;
}
auto transform(string& self, rstring from, rstring to) -> string& {
if(from.size() != to.size() || from.size() == 0) return self; //patterns must be the same length
char* p = self.get();
for(unsigned n = 0; n < self.size(); n++) {
auto string::transform(rstring from, rstring to) -> string& {
if(from.size() != to.size() || from.size() == 0) return *this; //patterns must be the same length
char* p = get();
for(unsigned n = 0; n < size(); n++) {
for(unsigned s = 0; s < from.size(); s++) {
if(p[n] == from[s]) {
p[n] = to[s];
@ -47,7 +47,7 @@ auto transform(string& self, rstring from, rstring to) -> string& {
}
}
}
return self;
return *this;
}
}

View File

@ -20,39 +20,37 @@ auto string::operator[](signed position) const -> const char& {
return data()[position];
}
template<typename... P> auto assign(string& self, P&&... p) -> string& {
self.resize(0);
return self.append(std::forward<P>(p)...);
template<typename... P> auto string::assign(P&&... p) -> string& {
resize(0);
return append(forward<P>(p)...);
}
template<typename T, typename... P> auto append(string& self, const T& value, P&&... p) -> string& {
_append(self, make_string(value));
return self.append(std::forward<P>(p)...);
template<typename T, typename... P> auto string::append(const T& value, P&&... p) -> string& {
_append(make_string(value));
return append(forward<P>(p)...);
}
template<typename... P> auto append(string& self, const format& value, P&&... p) -> string& {
self.format(value);
return self.append(std::forward<P>(p)...);
template<typename... P> auto string::append(const nall::format& value, P&&... p) -> string& {
format(value);
return append(forward<P>(p)...);
}
auto append(string& self) -> string& {
return self;
auto string::append() -> string& {
return *this;
}
template<typename T> auto _append(string& self, const stringify<T>& source) -> string& {
unsigned size = self.size();
unsigned length = source.size();
self.resize(size + length);
memory::copy(self.get() + size, source.data(), length);
return self;
template<typename T> auto string::_append(const stringify<T>& source) -> string& {
resize(size() + source.size());
memory::copy(get() + size() - source.size(), source.data(), source.size());
return *this;
}
auto empty(const string& self) -> bool {
return self.size() == 0;
auto string::empty() const -> bool {
return size() == 0;
}
auto length(const string& self) -> unsigned {
return strlen(self.data());
auto string::length() const -> unsigned {
return strlen(data());
}
}

View File

@ -21,7 +21,7 @@ inline string literalNumber(const char*& s) {
p += prefix;
while(p[0] == '\'' || p[0] == '0' || p[0] == '1') p++;
if(p - s <= prefix) throw "invalid binary literal";
string result = substr(s, 0, p - s);
string result = slice(s, 0, p - s);
s = p;
return result;
}
@ -32,7 +32,7 @@ inline string literalNumber(const char*& s) {
p += prefix;
while(p[0] == '\'' || (p[0] >= '0' && p[0] <= '7')) p++;
if(p - s <= prefix) throw "invalid octal literal";
string result = substr(s, 0, p - s);
string result = slice(s, 0, p - s);
s = p;
return result;
}
@ -43,7 +43,7 @@ inline string literalNumber(const char*& s) {
p += prefix;
while(p[0] == '\'' || (p[0] >= '0' && p[0] <= '9') || (p[0] >= 'A' && p[0] <= 'F') || (p[0] >= 'a' && p[0] <= 'f')) p++;
if(p - s <= prefix) throw "invalid hex literal";
string result = substr(s, 0, p - s);
string result = slice(s, 0, p - s);
s = p;
return result;
}
@ -51,7 +51,7 @@ inline string literalNumber(const char*& s) {
//decimal
while(p[0] == '\'' || (p[0] >= '0' && p[0] <= '9')) p++;
if(p[0] != '.') {
string result = substr(s, 0, p - s);
string result = slice(s, 0, p - s);
s = p;
return result;
}
@ -59,7 +59,7 @@ inline string literalNumber(const char*& s) {
//floating-point
p++;
while(p[0] == '\'' || (p[0] >= '0' && p[0] <= '9')) p++;
string result = substr(s, 0, p - s);
string result = slice(s, 0, p - s);
s = p;
return result;
}
@ -71,7 +71,7 @@ inline string literalString(const char*& s) {
while(p[0] && p[0] != escape) p++;
if(*p++ != escape) throw "unclosed string literal";
string result = substr(s, 0, p - s);
string result = slice(s, 0, p - s);
s = p;
return result;
}
@ -81,7 +81,7 @@ inline string literalVariable(const char*& s) {
while(p[0] == '_' || p[0] == '.' || (p[0] >= 'A' && p[0] <= 'Z') || (p[0] >= 'a' && p[0] <= 'z') || (p[0] >= '0' && p[0] <= '9')) p++;
string result = substr(s, 0, p - s);
string result = slice(s, 0, p - s);
s = p;
return result;
}

View File

@ -2,28 +2,26 @@
namespace nall {
template<bool Insensitive, bool Quoted> auto _find(const string& self, signed offset, rstring source) -> maybe<unsigned> {
template<bool Insensitive, bool Quoted> auto string::_find(signed offset, rstring source) const -> maybe<unsigned> {
if(source.size() == 0) return nothing;
const char* p = self.data();
unsigned size = self.size();
for(unsigned n = offset, quoted = 0; n < size;) {
auto p = data();
for(unsigned n = offset, quoted = 0; n < size();) {
if(Quoted) { if(p[n] == '\"') { quoted ^= 1; n++; continue; } if(quoted) { n++; continue; } }
if(_compare<Insensitive>(p + n, size - n, source.data(), source.size())) { n++; continue; }
if(_compare<Insensitive>(p + n, size() - n, source.data(), source.size())) { n++; continue; }
return n - offset;
}
return nothing;
}
auto find(const string& self, rstring source) -> maybe<unsigned> { return _find<0, 0>(self, 0, source); }
auto ifind(const string& self, rstring source) -> maybe<unsigned> { return _find<1, 0>(self, 0, source); }
auto qfind(const string& self, rstring source) -> maybe<unsigned> { return _find<0, 1>(self, 0, source); }
auto iqfind(const string& self, rstring source) -> maybe<unsigned> { return _find<1, 1>(self, 0, source); }
auto string::find(rstring source) const -> maybe<unsigned> { return _find<0, 0>(0, source); }
auto string::ifind(rstring source) const -> maybe<unsigned> { return _find<1, 0>(0, source); }
auto string::qfind(rstring source) const -> maybe<unsigned> { return _find<0, 1>(0, source); }
auto string::iqfind(rstring source) const -> maybe<unsigned> { return _find<1, 1>(0, source); }
auto findFrom(const string& self, signed offset, rstring source) -> maybe<unsigned> { return _find<0, 0>(self, offset, source); }
auto ifindFrom(const string& self, signed offset, rstring source) -> maybe<unsigned> { return _find<1, 0>(self, offset, source); }
auto string::findFrom(signed offset, rstring source) const -> maybe<unsigned> { return _find<0, 0>(offset, source); }
auto string::ifindFrom(signed offset, rstring source) const -> maybe<unsigned> { return _find<1, 0>(offset, source); }
}

View File

@ -59,17 +59,17 @@ auto string::format(const nall::format& params) -> type& {
return *this;
}
template<typename T, typename... P> auto append(format& self, const T& value, P&&... p) -> format& {
self.vector<string>::append(value);
append(self, std::forward<P>(p)...);
template<typename T, typename... P> auto format::append(const T& value, P&&... p) -> format& {
vector<string>::append(value);
return append(forward<P>(p)...);
}
auto append(format& self) -> format& {
return self;
auto format::append() -> format& {
return *this;
}
template<typename... P> auto print(P&&... p) -> void {
string s{std::forward<P>(p)...};
string s{forward<P>(p)...};
fputs(s.data(), stdout);
}

View File

@ -18,15 +18,15 @@ namespace Hash {
}
}
auto crc16(const string& self) -> string {
auto crc16(rstring self) -> string {
return Hash::CRC16(self.data(), self.size()).digest();
}
auto crc32(const string& self) -> string {
auto crc32(rstring self) -> string {
return Hash::CRC32(self.data(), self.size()).digest();
}
auto sha256(const string& self) -> string {
auto sha256(rstring self) -> string {
return Hash::SHA256(self.data(), self.size()).digest();
}

View File

@ -22,52 +22,52 @@ auto lstring::isort() -> lstring& {
return *this;
}
template<typename... P> auto append(lstring& self, const string& data, P&&... p) -> lstring& {
self.vector::append(data);
append(self, std::forward<P>(p)...);
return self;
template<typename... P> auto lstring::append(const string& data, P&&... p) -> lstring& {
vector::append(data);
append(forward<P>(p)...);
return *this;
}
auto append(lstring& self) -> lstring& {
return self;
auto lstring::append() -> lstring& {
return *this;
}
auto find(const lstring& self, const string& source) -> maybe<unsigned> {
for(unsigned n = 0; n < self.size(); n++) {
if(self[n].equals(source)) return n;
auto lstring::find(rstring source) const -> maybe<unsigned> {
for(unsigned n = 0; n < size(); n++) {
if(operator[](n).equals(source)) return n;
}
return nothing;
}
auto ifind(const lstring& self, const string& source) -> maybe<unsigned> {
for(unsigned n = 0; n < self.size(); n++) {
if(self[n].iequals(source)) return n;
auto lstring::ifind(rstring source) const -> maybe<unsigned> {
for(unsigned n = 0; n < size(); n++) {
if(operator[](n).iequals(source)) return n;
}
return nothing;
}
auto match(const lstring& self, const string& pattern) -> lstring {
auto lstring::match(rstring pattern) const -> lstring {
lstring result;
for(unsigned n = 0; n < self.size(); n++) {
if(self[n].match(pattern)) result.append(self[n]);
for(unsigned n = 0; n < size(); n++) {
if(operator[](n).match(pattern)) result.append(operator[](n));
}
return result;
}
auto merge(const lstring& self, const string& separator) -> string {
auto lstring::merge(rstring separator) const -> string {
string output;
for(unsigned n = 0; n < self.size(); n++) {
output.append(self[n]);
if(n < self.size() - 1) output.append(separator);
for(unsigned n = 0; n < size(); n++) {
output.append(operator[](n));
if(n < size() - 1) output.append(separator.data());
}
return output;
}
auto strip(lstring& self) -> lstring& {
for(unsigned n = 0; n < self.size(); n++) {
self[n].strip();
auto lstring::strip() -> lstring& {
for(unsigned n = 0; n < size(); n++) {
operator[](n).strip();
}
return self;
return *this;
}
}

View File

@ -37,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 = slice(p, 0, length);
p += length;
}
@ -46,18 +46,18 @@ protected:
unsigned length = 2;
while(p[length] && p[length] != '\n' && p[length] != '\"') length++;
if(p[length] != '\"') throw "Unescaped value";
_value = {substr(p, 2, length - 2), "\n"};
_value = {slice(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";
_value = {substr(p, 1, length - 1), "\n"};
_value = {slice(p, 1, length - 1), "\n"};
p += length;
} else if(*p == ':') {
unsigned length = 1;
while(p[length] && p[length] != '\n') length++;
_value = {substr(p, 1, length - 1), "\n"};
_value = {slice(p, 1, length - 1), "\n"};
p += length;
}
}
@ -73,7 +73,7 @@ protected:
unsigned length = 0;
while(valid(p[length])) length++;
if(length == 0) throw "Invalid attribute name";
node->_name = substr(p, 0, length);
node->_name = slice(p, 0, length);
node->parseData(p += length);
node->_value.rtrim("\n", 1L);
_children.append(node);
@ -93,7 +93,7 @@ protected:
if(depth <= _metadata) break;
if(text[y][depth] == ':') {
_value.append(substr(text[y++], depth + 1), "\n");
_value.append(slice(text[y++], depth + 1), "\n");
continue;
}

View File

@ -99,10 +99,10 @@ auto ManagedNode::_find(const string& query) const -> vector<Node> {
auto ManagedNode::_lookup(const string& path) const -> Node {
if(auto position = path.find("/")) {
auto name = path.slice(0, *position);
auto name = slice(path, 0, *position);
for(auto& node : _children) {
if(name == node->_name) {
return node->_lookup(path.slice(*position + 1));
return node->_lookup(slice(path, *position + 1));
}
}
} else for(auto& node : _children) {
@ -113,14 +113,14 @@ auto ManagedNode::_lookup(const string& path) const -> Node {
auto ManagedNode::_create(const string& path) -> Node {
if(auto position = path.find("/")) {
auto name = path.slice(0, *position);
auto name = slice(path, 0, *position);
for(auto& node : _children) {
if(name == node->_name) {
return node->_create(path.slice(*position + 1));
return node->_create(slice(path, *position + 1));
}
}
_children.append(new ManagedNode(name));
return _children.last()->_create(path.slice(*position + 1));
return _children.last()->_create(slice(path, *position + 1));
}
for(auto& node : _children) {
if(path == node->_name) return node;

View File

@ -4,8 +4,8 @@ namespace nall {
//todo: these functions are not binary-safe
auto match(const string& self, rstring source) -> bool {
const char* s = self.data();
auto string::match(rstring source) const -> bool {
const char* s = data();
const char* p = source.data();
const char* cp = nullptr;
@ -28,12 +28,12 @@ auto match(const string& self, rstring source) -> bool {
return !*p;
}
auto imatch(const string& self, rstring source) -> bool {
auto string::imatch(rstring source) const -> bool {
static auto chrlower = [](char c) -> char {
return (c >= 'A' && c <= 'Z') ? c + ('a' - 'A') : c;
};
const char* s = self.data();
const char* s = data();
const char* p = source.data();
const char* cp = nullptr;
@ -56,7 +56,7 @@ auto imatch(const string& self, rstring source) -> bool {
return !*p;
}
inline bool tokenize(const char* s, const char* p) {
auto tokenize(const char* s, const char* p) -> bool {
while(*s) {
if(*p == '*') {
while(*s) if(tokenize(s++, p + 1)) return true;
@ -74,7 +74,7 @@ auto tokenize(lstring& list, const char* s, const char* p) -> bool {
const char* b = s;
while(*s) {
if(tokenize(list, s++, p + 1)) {
list.prepend(substr(b, 0, --s - b));
list.prepend(slice(b, 0, --s - b));
return true;
}
}

View File

@ -4,7 +4,7 @@ namespace nall {
// (/parent/child.type/)
// (/parent/child.type/)name.type
auto pathname(const string& self) -> string {
auto pathname(rstring self) -> string {
const char* p = self.data() + self.size() - 1;
for(signed offset = self.size() - 1; offset >= 0; offset--, p--) {
if(*p == '/') return slice(self, 0, offset + 1);
@ -14,7 +14,7 @@ auto pathname(const string& self) -> string {
// /parent/child.type/()
// /parent/child.type/(name.type)
auto filename(const string& self) -> string {
auto filename(rstring self) -> string {
const char* p = self.data() + self.size() - 1;
for(signed offset = self.size() - 1; offset >= 0; offset--, p--) {
if(*p == '/') return slice(self, offset + 1);
@ -24,18 +24,18 @@ auto filename(const string& self) -> string {
// (/parent/)child.type/
// (/parent/child.type/)name.type
auto dirname(const string& self) -> string {
auto dirname(rstring self) -> string {
const char* p = self.data() + self.size() - 1, *last = p;
for(signed offset = self.size() - 1; offset >= 0; offset--, p--) {
if(*p == '/' && p == last) continue;
if(*p == '/') return slice(self, 0, offset + 1);
}
return self; //this is the root directory
return self.data(); //this is the root directory
}
// /parent/(child.type/)
// /parent/child.type/(name.type)
auto basename(const string& self) -> string {
auto basename(rstring self) -> string {
const char* p = self.data() + self.size() - 1, *last = p;
for(signed offset = self.size() - 1; offset >= 0; offset--, p--) {
if(*p == '/' && p == last) continue;
@ -46,7 +46,7 @@ auto basename(const string& self) -> string {
// /parent/(child).type/
// /parent/child.type/(name).type
auto prefixname(const string& self) -> string {
auto prefixname(rstring self) -> string {
const char* p = self.data() + self.size() - 1, *last = p;
for(signed offset = self.size() - 1, suffix = -1; offset >= 0; offset--, p--) {
if(*p == '/' && p == last) continue;
@ -59,7 +59,7 @@ auto prefixname(const string& self) -> string {
// /parent/child(.type)/
// /parent/child.type/name(.type)
auto suffixname(const string& self) -> string {
auto suffixname(rstring self) -> string {
const char* p = self.data() + self.size() - 1, *last = p;
for(signed offset = self.size() - 1; offset >= 0; offset--, p--) {
if(*p == '/' && p == last) continue;

View File

@ -15,7 +15,7 @@ auto activepath() -> string {
auto realpath(rstring name) -> string {
string result;
char path[PATH_MAX] = "";
if(::realpath(name, path)) result = string{path}.transform("\\", "/").pathname();
if(::realpath(name, path)) result = pathname(string{path}.transform("\\", "/"));
if(result.empty()) return activepath();
result.transform("\\", "/");
if(result.endsWith("/") == false) result.append("/");

View File

@ -1,62 +0,0 @@
#ifdef NALL_STRING_INTERNAL_HPP
namespace nall {
struct stringref {
operator const char*() const {
return _data;
}
auto data() const -> const char* {
return _data;
}
auto size() const -> unsigned {
if(!_initialized) _size = strlen(_data), _initialized = true;
return _size;
}
stringref() {
_string = nullptr;
_data = "";
_size = 0;
_initialized = true;
}
stringref(const char* source) {
_string = nullptr;
_data = source;
_initialized = false;
}
stringref(const string& source) {
_string = nullptr;
_data = source.data();
_size = source.size();
_initialized = true;
}
template<typename... P> stringref(P&&... p) {
_string = new string{std::forward<P>(p)...};
_data = _string->data();
_size = _string->size();
_initialized = true;
}
~stringref() {
if(_string) delete _string;
}
stringref(const stringref& source) = delete;
stringref(stringref&& source) = delete;
protected:
string* _string;
const char* _data;
mutable signed _size;
mutable unsigned _initialized;
};
}
#endif

View File

@ -3,16 +3,16 @@
namespace nall {
template<bool Insensitive, bool Quoted>
auto _replace(string& self, rstring from, rstring to, long limit) -> string& {
if(limit <= 0 || from.size() == 0) return self;
auto string::_replace(rstring from, rstring to, long limit) -> string& {
if(limit <= 0 || from.size() == 0) return *this;
signed size = self.size();
signed size = this->size();
signed matches = 0;
signed quoted = 0;
//count matches first, so that we only need to reallocate memory once
//(recording matches would also require memory allocation, so this is not done)
{ const char* p = self.data();
{ const char* p = data();
for(signed n = 0; n <= size - (signed)from.size();) {
if(Quoted) { if(p[n] == '\"') { quoted ^= 1; n++; continue; } if(quoted) { n++; continue; } }
if(_compare<Insensitive>(p + n, size - n, from.data(), from.size())) { n++; continue; }
@ -21,11 +21,11 @@ auto _replace(string& self, rstring from, rstring to, long limit) -> string& {
n += from.size();
}
}
if(matches == 0) return self;
if(matches == 0) return *this;
//in-place overwrite
if(to.size() == from.size()) {
char* p = self.get();
char* p = get();
for(signed n = 0, remaining = matches, quoted = 0; n <= size - (signed)from.size();) {
if(Quoted) { if(p[n] == '\"') { quoted ^= 1; n++; continue; } if(quoted) { n++; continue; } }
@ -40,7 +40,7 @@ auto _replace(string& self, rstring from, rstring to, long limit) -> string& {
//left-to-right shrink
else if(to.size() < from.size()) {
char* p = self.get();
char* p = get();
signed offset = 0;
signed base = 0;
@ -58,15 +58,15 @@ auto _replace(string& self, rstring from, rstring to, long limit) -> string& {
}
memory::move(p + offset, p + base, size - base);
self.resize(size - matches * (from.size() - to.size()));
resize(size - matches * (from.size() - to.size()));
}
//right-to-left expand
else if(to.size() > from.size()) {
self.resize(size + matches * (to.size() - from.size()));
char* p = self.get();
resize(size + matches * (to.size() - from.size()));
char* p = get();
signed offset = self.size();
signed offset = this->size();
signed base = size;
for(signed n = size, remaining = matches; n >= (signed)from.size();) { //quoted reused from parent scope since we are iterating backward
@ -83,13 +83,13 @@ auto _replace(string& self, rstring from, rstring to, long limit) -> string& {
}
}
return self;
return *this;
}
auto replace(string& self, rstring from, rstring to, long limit) -> string& { return _replace<0, 0>(self, from, to, limit); }
auto ireplace(string& self, rstring from, rstring to, long limit) -> string& { return _replace<1, 0>(self, from, to, limit); }
auto qreplace(string& self, rstring from, rstring to, long limit) -> string& { return _replace<0, 1>(self, from, to, limit); }
auto iqreplace(string& self, rstring from, rstring to, long limit) -> string& { return _replace<1, 1>(self, from, to, limit); }
auto string::replace(rstring from, rstring to, long limit) -> string& { return _replace<0, 0>(from, to, limit); }
auto string::ireplace(rstring from, rstring to, long limit) -> string& { return _replace<1, 0>(from, to, limit); }
auto string::qreplace(rstring from, rstring to, long limit) -> string& { return _replace<0, 1>(from, to, limit); }
auto string::iqreplace(rstring from, rstring to, long limit) -> string& { return _replace<1, 1>(from, to, limit); }
};

View File

@ -2,9 +2,10 @@
namespace nall {
template<bool Insensitive, bool Quoted> auto _split(lstring& self, rstring source, rstring find, long limit) -> lstring& {
self.reset();
if(limit <= 0 || find.size() == 0) return self;
template<bool Insensitive, bool Quoted>
auto lstring::_split(rstring source, rstring find, long limit) -> lstring& {
reset();
if(limit <= 0 || find.size() == 0) return *this;
const char* p = source.data();
signed size = source.size();
@ -13,10 +14,10 @@ template<bool Insensitive, bool Quoted> auto _split(lstring& self, rstring sourc
for(signed n = 0, quoted = 0; n <= size - (signed)find.size();) {
if(Quoted) { if(p[n] == '\"') { quoted ^= 1; n++; continue; } if(quoted) { n++; continue; } }
if(_compare<Insensitive>(p + n, size - n, find.data(), find.size())) { n++; continue; }
if(string::_compare<Insensitive>(p + n, size - n, find.data(), find.size())) { n++; continue; }
if(matches >= limit) break;
string& s = self(matches);
string& s = operator()(matches);
s.resize(n - base);
memory::copy(s.get(), p + base, n - base);
@ -25,22 +26,17 @@ template<bool Insensitive, bool Quoted> auto _split(lstring& self, rstring sourc
matches++;
}
string& s = self(matches);
string& s = operator()(matches);
s.resize(size - base);
memory::copy(s.get(), p + base, size - base);
return self;
return *this;
}
auto split(string& self, rstring on, long limit) -> lstring { return lstring().split(self, on, limit); }
auto isplit(string& self, rstring on, long limit) -> lstring { return lstring().isplit(self, on, limit); }
auto qsplit(string& self, rstring on, long limit) -> lstring { return lstring().qsplit(self, on, limit); }
auto iqsplit(string& self, rstring on, long limit) -> lstring { return lstring().iqsplit(self, on, limit); }
auto string::split(rstring on, long limit) const -> lstring { return lstring().split(*this, on, limit); }
auto string::isplit(rstring on, long limit) const -> lstring { return lstring().isplit(*this, on, limit); }
auto string::qsplit(rstring on, long limit) const -> lstring { return lstring().qsplit(*this, on, limit); }
auto string::iqsplit(rstring on, long limit) const -> lstring { return lstring().iqsplit(*this, on, limit); }
auto string::split(rstring on, long limit) const -> lstring { return lstring()._split<0, 0>(*this, on, limit); }
auto string::isplit(rstring on, long limit) const -> lstring { return lstring()._split<1, 0>(*this, on, limit); }
auto string::qsplit(rstring on, long limit) const -> lstring { return lstring()._split<0, 1>(*this, on, limit); }
auto string::iqsplit(rstring on, long limit) const -> lstring { return lstring()._split<1, 1>(*this, on, limit); }
}

View File

@ -33,7 +33,7 @@ private:
};
auto CML::parse(const string& filename) -> string {
if(!settings.path) settings.path = filename.pathname();
if(!settings.path) settings.path = pathname(filename);
string document = settings.reader ? settings.reader(filename) : string::read(filename);
parseDocument(document, settings.path, 0);
return state.output;
@ -61,7 +61,7 @@ auto CML::parseDocument(const string& filedata, const string& pathname, unsigned
name.ltrim("include ", 1L);
string filename{pathname, name};
string document = settings.reader ? settings.reader(filename) : string::read(filename);
parseDocument(document, filename.pathname(), depth + 1);
parseDocument(document, nall::pathname(filename), depth + 1);
continue;
}
@ -80,10 +80,10 @@ auto CML::parseDocument(const string& filedata, const string& pathname, unsigned
while(auto offset = value.find("var(")) {
bool found = false;
if(auto length = value.findFrom(*offset, ")")) {
string name = value.slice(*offset + 4, *length - 4);
string name = slice(value, *offset + 4, *length - 4);
for(auto& variable : variables) {
if(variable.name == name) {
value = {value.slice(0, *offset), variable.value, value.slice(*offset + *length + 1)};
value = {slice(value, 0, *offset), variable.value, slice(value, *offset + *length + 1)};
found = true;
break;
}

View File

@ -45,7 +45,7 @@ auto DML::parse(const string& filedata, const string& pathname) -> string {
}
auto DML::parse(const string& filename) -> string {
if(!settings.path) settings.path = filename.pathname();
if(!settings.path) settings.path = pathname(filename);
string document = settings.reader ? settings.reader(filename) : string::read(filename);
parseDocument(document, settings.path, 0);
return state.output;
@ -68,7 +68,7 @@ auto DML::parseBlock(string& block, const string& pathname, unsigned depth) -> b
if(block.beginsWith("<include ") && block.endsWith(">")) {
string filename{pathname, block.trim("<include ", ">", 1L).strip()};
string document = settings.reader ? settings.reader(filename) : string::read(filename);
parseDocument(document, filename.pathname(), depth + 1);
parseDocument(document, nall::pathname(filename), depth + 1);
}
//html
@ -87,7 +87,7 @@ auto DML::parseBlock(string& block, const string& pathname, unsigned depth) -> b
}
auto content = lines.takeFirst().ltrim("# ", 1L).split(" => ", 1L);
auto data = markup(content[0]);
auto name = escape(content(1, data.crc32()));
auto name = escape(content(1, crc32(data)));
state.output.append("<header id=\"", name, "\">", data);
for(auto& line : lines) {
if(!line.beginsWith("# ")) continue;
@ -98,14 +98,14 @@ auto DML::parseBlock(string& block, const string& pathname, unsigned depth) -> b
//header
else if(auto depth = count(block, '=')) {
auto content = lines.takeFirst().slice(depth + 1).split(" => ", 1L);
auto content = slice(lines.takeFirst(), depth + 1).split(" => ", 1L);
auto data = markup(content[0]);
auto name = escape(content(1, data.crc32()));
auto name = escape(content(1, crc32(data)));
if(depth <= 6) {
state.output.append("<h", depth, " id=\"", name, "\">", data);
for(auto& line : lines) {
if(count(line, '=') != depth) continue;
state.output.append("<span>", line.slice(depth + 1), "</span>");
state.output.append("<span>", slice(line, depth + 1), "</span>");
}
state.output.append("</h", depth, ">\n");
}
@ -119,9 +119,9 @@ auto DML::parseBlock(string& block, const string& pathname, unsigned depth) -> b
if(auto depth = count(line, '-')) {
while(level < depth) level++, state.output.append("<ul>\n");
while(level > depth) level--, state.output.append("</ul>\n");
auto content = line.slice(depth + 1).split(" => ", 1L);
auto content = slice(line, depth + 1).split(" => ", 1L);
auto data = markup(content[0]);
auto name = escape(content(1, data.crc32()));
auto name = escape(content(1, crc32(data)));
state.output.append("<li><a href=\"#", name, "\">", data, "</a></li>\n");
}
}
@ -136,7 +136,7 @@ auto DML::parseBlock(string& block, const string& pathname, unsigned depth) -> b
if(auto depth = count(line, '*')) {
while(level < depth) level++, state.output.append("<ul>\n");
while(level > depth) level--, state.output.append("</ul>\n");
auto data = markup(line.slice(depth + 1));
auto data = markup(slice(line, depth + 1));
state.output.append("<li>", data, "</li>\n");
}
}
@ -150,7 +150,7 @@ auto DML::parseBlock(string& block, const string& pathname, unsigned depth) -> b
if(auto depth = count(line, '>')) {
while(level < depth) level++, state.output.append("<blockquote>\n");
while(level > depth) level--, state.output.append("</blockquote>\n");
auto data = markup(line.slice(depth + 1));
auto data = markup(slice(line, depth + 1));
state.output.append(data, "\n");
}
}
@ -231,7 +231,7 @@ auto DML::markup(const string& text) -> string {
if(match && b == match && !f) {
match = 0;
auto content = text.slice(offset, n - offset - 1);
auto content = slice(text, offset, n - offset - 1);
if(b == '*') { output.append("<strong>", escape(content), "</strong>"); continue; }
if(b == '/') { output.append("<em>", escape(content), "</em>"); continue; }
if(b == '_') { output.append("<ins>", escape(content), "</ins>"); continue; }

View File

@ -2,101 +2,101 @@
namespace nall {
auto trim(string& self, rstring lhs, rstring rhs, long limit) -> string& {
rtrim(self, rhs, limit);
ltrim(self, lhs, limit);
return self;
auto string::trim(rstring lhs, rstring rhs, long limit) -> string& {
rtrim(rhs, limit);
ltrim(lhs, limit);
return *this;
}
auto ltrim(string& self, rstring lhs, long limit) -> string& {
if(lhs.size() == 0) return self;
auto string::ltrim(rstring lhs, long limit) -> string& {
if(lhs.size() == 0) return *this;
long matches = 0;
while(matches < limit) {
signed offset = lhs.size() * matches;
signed size = (signed)self.size() - offset;
if(size < (signed)lhs.size()) break;
if(memory::compare(self.data() + offset, lhs.data(), lhs.size()) != 0) break;
signed length = (signed)size() - offset;
if(length < (signed)lhs.size()) break;
if(memory::compare(data() + offset, lhs.data(), lhs.size()) != 0) break;
matches++;
}
if(matches) self.remove(0, lhs.size() * matches);
return self;
if(matches) remove(0, lhs.size() * matches);
return *this;
}
auto rtrim(string& self, rstring rhs, long limit) -> string& {
if(rhs.size() == 0) return self;
auto string::rtrim(rstring rhs, long limit) -> string& {
if(rhs.size() == 0) return *this;
long matches = 0;
while(matches < limit) {
signed offset = (signed)self.size() - rhs.size() * (matches + 1);
signed size = (signed)self.size() - offset;
if(offset < 0 || size < (signed)rhs.size()) break;
if(memory::compare(self.data() + offset, rhs.data(), rhs.size()) != 0) break;
signed offset = (signed)size() - rhs.size() * (matches + 1);
signed length = (signed)size() - offset;
if(offset < 0 || length < (signed)rhs.size()) break;
if(memory::compare(data() + offset, rhs.data(), rhs.size()) != 0) break;
matches++;
}
if(matches) self.resize(self.size() - rhs.size() * matches);
return self;
if(matches) resize(size() - rhs.size() * matches);
return *this;
}
auto itrim(string& self, rstring lhs, rstring rhs, long limit) -> string& {
irtrim(self, rhs, limit);
iltrim(self, lhs, limit);
return self;
auto string::itrim(rstring lhs, rstring rhs, long limit) -> string& {
irtrim(rhs, limit);
iltrim(lhs, limit);
return *this;
}
auto iltrim(string& self, rstring lhs, long limit) -> string& {
if(lhs.size() == 0) return self;
auto string::iltrim(rstring lhs, long limit) -> string& {
if(lhs.size() == 0) return *this;
long matches = 0;
while(matches < limit) {
signed offset = lhs.size() * matches;
signed size = (signed)self.size() - offset;
if(size < (signed)lhs.size()) break;
if(memory::icompare(self.data() + offset, lhs.data(), lhs.size()) != 0) break;
signed length = (signed)size() - offset;
if(length < (signed)lhs.size()) break;
if(memory::icompare(data() + offset, lhs.data(), lhs.size()) != 0) break;
matches++;
}
if(matches) self.remove(0, lhs.size() * matches);
return self;
if(matches) remove(0, lhs.size() * matches);
return *this;
}
auto irtrim(string& self, rstring rhs, long limit) -> string& {
if(rhs.size() == 0) return self;
auto string::irtrim(rstring rhs, long limit) -> string& {
if(rhs.size() == 0) return *this;
long matches = 0;
while(matches < limit) {
signed offset = (signed)self.size() - rhs.size() * (matches + 1);
signed size = (signed)self.size() - offset;
if(offset < 0 || size < (signed)rhs.size()) break;
if(memory::icompare(self.data() + offset, rhs.data(), rhs.size()) != 0) break;
signed offset = (signed)size() - rhs.size() * (matches + 1);
signed length = (signed)size() - offset;
if(offset < 0 || length < (signed)rhs.size()) break;
if(memory::icompare(data() + offset, rhs.data(), rhs.size()) != 0) break;
matches++;
}
if(matches) self.resize(self.size() - rhs.size() * matches);
return self;
if(matches) resize(size() - rhs.size() * matches);
return *this;
}
auto strip(string& self) -> string& {
rstrip(self);
lstrip(self);
return self;
auto string::strip() -> string& {
rstrip();
lstrip();
return *this;
}
auto lstrip(string& self) -> string& {
unsigned size = 0;
while(size < self.size()) {
char input = self[size];
auto string::lstrip() -> string& {
unsigned length = 0;
while(length < size()) {
char input = operator[](length);
if(input != ' ' && input != '\t' && input != '\r' && input != '\n') break;
size++;
length++;
}
if(size) self.remove(0, size);
return self;
if(length) remove(0, length);
return *this;
}
auto rstrip(string& self) -> string& {
unsigned size = 0;
while(size < self.size()) {
auto string::rstrip() -> string& {
unsigned length = 0;
while(length < size()) {
bool matched = false;
char input = self[self.size() - size - 1];
char input = operator[](size() - length - 1);
if(input != ' ' && input != '\t' && input != '\r' && input != '\n') break;
size++;
length++;
}
if(size) self.resize(self.size() - size);
return self;
if(length) resize(size() - length);
return *this;
}
}

View File

@ -2,7 +2,7 @@
namespace nall {
auto string::read(const string& filename) -> string {
auto string::read(rstring filename) -> string {
#if !defined(_WIN32)
FILE* fp = fopen(filename, "rb");
#else
@ -22,67 +22,67 @@ auto string::read(const string& filename) -> string {
return fclose(fp), result;
}
auto string::repeat(const string& pattern, unsigned times) -> string {
auto string::repeat(rstring pattern, unsigned times) -> string {
string result;
while(times--) result.append(pattern);
while(times--) result.append(pattern.data());
return result;
}
auto fill(string& self, char fill) -> string& {
memory::fill(self.get(), self.size(), fill);
return self;
auto string::fill(char fill) -> string& {
memory::fill(get(), size(), fill);
return *this;
}
auto hash(const string& self) -> unsigned {
const char* p = self.data();
unsigned size = self.size();
auto string::hash() const -> unsigned {
const char* p = data();
unsigned length = size();
unsigned result = 5381;
while(size--) result = (result << 5) + result + *p++;
while(length--) result = (result << 5) + result + *p++;
return result;
}
auto remove(string& self, unsigned offset, unsigned length) -> string& {
char* p = self.get();
length = min(length, self.size());
memory::move(p + offset, p + offset + length, self.size() - length);
return self.resize(self.size() - length);
auto string::remove(unsigned offset, unsigned length) -> string& {
char* p = get();
length = min(length, size());
memory::move(p + offset, p + offset + length, size() - length);
return resize(size() - length);
}
auto reverse(string& self) -> string& {
char* p = self.get();
unsigned size = self.size();
unsigned pivot = size >> 1;
for(signed x = 0, y = size - 1; x < pivot && y >= 0; x++, y--) std::swap(p[x], p[y]);
return self;
auto string::reverse() -> string& {
char* p = get();
unsigned length = size();
unsigned pivot = length >> 1;
for(signed x = 0, y = length - 1; x < pivot && y >= 0; x++, y--) std::swap(p[x], p[y]);
return *this;
}
//+length => insert/delete from start (right justify)
//-length => insert/delete from end (left justify)
auto size(string& self, signed length, char fill) -> string& {
unsigned size = self.size();
if(size == length) return self;
auto string::size(signed length, char fill) -> string& {
unsigned size = this->size();
if(size == length) return *this;
bool right = length >= 0;
length = abs(length);
if(size < length) { //expand
self.resize(length);
char* p = self.get();
resize(length);
char* p = get();
unsigned displacement = length - size;
if(right) memory::move(p + displacement, p, size);
else p += size;
while(displacement--) *p++ = fill;
} else { //shrink
char* p = self.get();
char* p = get();
unsigned displacement = size - length;
if(right) memory::move(p, p + displacement, length);
self.resize(length);
resize(length);
}
return self;
return *this;
}
auto slice(const string& self, signed offset, signed length) -> string {
auto slice(rstring self, signed offset, signed length) -> string {
string result;
if(offset < self.size()) {
if(length < 0) length = self.size() - offset;
@ -92,15 +92,6 @@ auto slice(const string& self, signed offset, signed length) -> string {
return result;
}
//legacy function: required for some library functions, do not use in newly written code
auto substr(rstring source, signed offset, signed length) -> string {
string result;
if(length < 0) length = source.size() - offset;
result.resize(length);
memory::copy(result.get(), source.data() + offset, length);
return result;
}
auto integer(char* result, intmax_t value) -> char* {
bool negative = value < 0;
if(negative) value = -value;

90
nall/string/view.hpp Normal file
View File

@ -0,0 +1,90 @@
#ifdef NALL_STRING_INTERNAL_HPP
namespace nall {
struct string_view {
string_view() {
_string = nullptr;
_data = "";
_size = 0;
}
string_view(const char* data) {
_string = nullptr;
_data = data;
_size = -1; //defer length calculation, as it is often unnecessary
}
string_view(const char* data, unsigned size) {
_string = nullptr;
_data = data;
_size = size;
}
string_view(const string& source) {
_string = nullptr;
_data = source.data();
_size = source.size();
}
template<typename... P>
string_view(P&&... p) {
_string = new string{forward<P>(p)...};
_data = _string->data();
_size = _string->size();
}
~string_view() {
if(_string) delete _string;
}
string_view(const string_view& source) {
_string = nullptr;
_data = source._data;
_size = source._size;
}
string_view(string_view&& source) {
_string = source._string;
_data = source._data;
_size = source._size;
source._string = nullptr;
}
auto operator=(const string_view& source) -> string_view& {
_string = nullptr;
_data = source._data;
_size = source._size;
return *this;
};
auto operator=(string_view&& source) -> string_view& {
_string = source._string;
_data = source._data;
_size = source._size;
source._string = nullptr;
return *this;
};
operator const char*() const {
return _data;
}
auto data() const -> const char* {
return _data;
}
auto size() const -> unsigned {
if(_size < 0) _size = strlen(_data);
return _size;
}
protected:
string* _string;
const char* _data;
mutable signed _size;
};
}
#endif

View File

@ -5,23 +5,23 @@
#include <utility>
namespace nall {
using std::nullptr_t;
using std::forward;
using std::move;
using std::add_const;
using std::decay;
using std::declval;
using true_type = std::true_type;
using false_type = std::false_type;
template<typename T, typename U> using is_same = std::is_same<T, U>;
template<typename T, typename U> using is_base_of = std::is_base_of<T, U>;
template<typename T> using is_array = std::is_array<T>;
template<typename T> using is_function = std::is_function<T>;
template<typename T> using is_integral = std::is_integral<T>;
template<typename T> using add_const = std::add_const<T>;
template<typename T> using remove_extent = std::remove_extent<T>;
template<typename T> using remove_reference = std::remove_reference<T>;
using std::false_type;
using std::forward;
using std::initializer_list;
using std::is_array;
using std::is_base_of;
using std::is_function;
using std::is_integral;
using std::is_same;
using std::move;
using std::nullptr_t;
using std::remove_extent;
using std::remove_reference;
using std::swap;
using std::true_type;
}
namespace nall {

View File

@ -25,7 +25,7 @@ template<typename T> struct vector {
auto size() const -> unsigned { return objectsize; }
auto capacity() const -> unsigned { return poolsize; }
auto move() -> T* {
auto release() -> T* {
T* result = pool + poolbase;
pool = nullptr;
poolbase = 0;
@ -50,7 +50,7 @@ template<typename T> struct vector {
size = bit::round(size); //amortize growth
T* copy = (T*)memory::allocate(size * sizeof(T));
for(unsigned n = 0; n < objectsize; n++) new(copy + n) T(std::move(pool[poolbase + n]));
for(unsigned n = 0; n < objectsize; n++) new(copy + n) T(move(pool[poolbase + n]));
free(pool);
pool = copy;
poolbase = 0;
@ -59,7 +59,7 @@ template<typename T> struct vector {
auto resize(unsigned size, T value = T()) -> void {
T* copy = (T*)memory::allocate(size * sizeof(T));
for(unsigned n = 0; n < size && n < objectsize; n++) new(copy + n) T(std::move(pool[poolbase + n]));
for(unsigned n = 0; n < size && n < objectsize; n++) new(copy + n) T(move(pool[poolbase + n]));
for(unsigned n = objectsize; n < size; n++) new(copy + n) T(value);
reset();
pool = copy;
@ -84,7 +84,7 @@ template<typename T> struct vector {
unsigned available = poolsize - objectsize;
poolbase = max(1u, available >> 1);
for(signed n = objectsize - 1; n >= 0; n--) {
pool[poolbase + n] = std::move(pool[n]);
pool[poolbase + n] = move(pool[n]);
}
}
new(pool + --poolbase) T(data);
@ -116,7 +116,7 @@ template<typename T> struct vector {
append(data);
if(position == ~0u) return;
for(signed n = objectsize - 1; n > position; n--) {
pool[poolbase + n] = std::move(pool[poolbase + n - 1]);
pool[poolbase + n] = move(pool[poolbase + n - 1]);
}
pool[poolbase + position] = data;
}
@ -131,7 +131,7 @@ template<typename T> struct vector {
} else {
for(unsigned n = position; n < objectsize; n++) {
if(n + length < objectsize) {
pool[poolbase + n] = std::move(pool[poolbase + n + length]);
pool[poolbase + n] = move(pool[poolbase + n + length]);
} else {
pool[poolbase + n].~T();
}
@ -156,7 +156,7 @@ template<typename T> struct vector {
auto reverse() -> void {
unsigned pivot = size() / 2;
for(unsigned l = 0, r = size() - 1; l < pivot; l++, r--) {
std::swap(pool[poolbase + l], pool[poolbase + r]);
swap(pool[poolbase + l], pool[poolbase + r]);
}
}
@ -270,9 +270,9 @@ template<typename T> struct vector {
//construction and destruction
vector() = default;
vector(std::initializer_list<T> list) { for(auto& data : list) append(data); }
vector(initializer_list<T> list) { for(auto& data : list) append(data); }
vector(const vector& source) { operator=(source); }
vector(vector&& source) { operator=(std::move(source)); }
vector(vector&& source) { operator=(move(source)); }
~vector() { reset(); }
protected:

View File

@ -101,11 +101,14 @@ auto Cartridge::parseMarkupMCC(Markup::Node root) -> void {
hasSatellaviewSlot = true;
hasMCC = true;
interface->loadRequest(ID::Satellaview, "BS-X Satellaview", "bs");
interface->loadRequest(ID::Satellaview, "BS-X Satellaview", "bs", false);
parseMarkupMemory(mcc.rom, root["rom"], ID::MCCROM, false);
parseMarkupMemory(mcc.ram, root["ram"], ID::MCCRAM, true);
parseMarkupMemory(mcc.psram, root["psram"], ID::MCCPSRAM, true);
auto rom = root.find("rom");
auto ram = root.find("ram");
parseMarkupMemory(mcc.rom, rom(0), ID::MCCROM, false);
parseMarkupMemory(mcc.ram, ram(0), ID::MCCRAM, true);
parseMarkupMemory(mcc.psram, ram(1), ID::MCCPSRAM, true);
for(auto node : root.find("map")) {
if(node["id"].text() == "rom"
@ -126,7 +129,7 @@ auto Cartridge::parseMarkupMCC(Markup::Node root) -> void {
auto Cartridge::parseMarkupSatellaview(Markup::Node root) -> void {
hasSatellaviewSlot = true;
interface->loadRequest(ID::Satellaview, "BS-X Satellaview", "bs");
interface->loadRequest(ID::Satellaview, "BS-X Satellaview", "bs", false);
for(auto node : root.find("map")) {
if(node["id"].text() == "rom") {
@ -144,7 +147,7 @@ auto Cartridge::parseMarkupSufamiTurbo(Markup::Node root, bool slot) -> void {
if(slot == 0) {
//load required slot A (will request slot B if slot A cartridge is linkable)
interface->loadRequest(ID::SufamiTurboSlotA, "Sufami Turbo - Slot A", "st");
interface->loadRequest(ID::SufamiTurboSlotA, "Sufami Turbo - Slot A", "st", false);
}
for(auto node : root.find("map")) {

View File

@ -36,8 +36,8 @@ auto Program::loadRequest(unsigned id, string filename, bool required) -> void {
}
}
if(required) MessageDialog().setTitle("higan").setText({
"Missing required file: ", location.filename(), "\n\n",
"From location:\n", location.pathname()
"Missing required file: ", nall::filename(location), "\n\n",
"From location:\n", nall::pathname(location)
}).error();
}

View File

@ -21,7 +21,7 @@ auto Program::saveState(unsigned slot, bool manager) -> bool {
auto location = stateName(slot, manager);
serializer s = emulator->serialize();
if(s.size() == 0) return showMessage({"Failed to save state to slot ", slot}), false;
directory::create(location.pathname());
directory::create(pathname(location));
if(file::write(location, s.data(), s.size()) == false) {
return showMessage({"Unable to write to slot ", slot}), false;
}