mirror of
https://github.com/libretro/bsnes-libretro.git
synced 2024-11-23 17:09:44 +00:00
Update to v094r38 release.
byuu says: I'll post more detailed changes later, but basically: - fixed Baldur's Gate bug - guess if no flash ROM ID present (fixes Magical Vacation, many many others) - nall cleanups - sfc/cartridge major cleanups - bsxcartridge/"bsx" renamed to mcc/"mcc" after the logic chip it uses (consistency with SGB/ICD2) - ... and more!
This commit is contained in:
parent
092cac9073
commit
1b0b54a690
@ -8,7 +8,7 @@ using namespace nall;
|
||||
|
||||
namespace Emulator {
|
||||
static const string Name = "higan";
|
||||
static const string Version = "094.37";
|
||||
static const string Version = "094.38";
|
||||
static const string Author = "byuu";
|
||||
static const string License = "GPLv3";
|
||||
static const string Website = "http://byuu.org/";
|
||||
|
@ -5,8 +5,8 @@ void APU::FIFO::read() {
|
||||
}
|
||||
|
||||
void APU::FIFO::write(int8 byte) {
|
||||
if(size == 32) return;
|
||||
size++;
|
||||
if(size == 32) rdoffset++;
|
||||
else size++;
|
||||
sample[wroffset++] = byte;
|
||||
}
|
||||
|
||||
|
@ -63,6 +63,11 @@ void Cartridge::load() {
|
||||
flashrom.size = info["size"].decimal();
|
||||
for(unsigned n = 0; n < flashrom.size; n++) flashrom.data[n] = 0xff;
|
||||
|
||||
//if FlashROM ID not provided; guess that it's a Macronix chip
|
||||
//this will not work for all games; in which case, the ID must be specified manually
|
||||
if(!flashrom.id && flashrom.size == 64 * 1024) flashrom.id = 0x1cc2;
|
||||
if(!flashrom.id && flashrom.size == 128 * 1024) flashrom.id = 0x09c2;
|
||||
|
||||
interface->loadRequest(ID::FlashROM, info["name"].text());
|
||||
memory.append({ID::FlashROM, info["name"].text()});
|
||||
}
|
||||
|
@ -50,22 +50,22 @@
|
||||
#define Hiro_CheckButton
|
||||
#define Hiro_CheckLabel
|
||||
#define Hiro_ComboButton
|
||||
#define Hiro_Console
|
||||
//#define Hiro_Console
|
||||
#define Hiro_Frame
|
||||
#define Hiro_HexEdit
|
||||
#define Hiro_HorizontalScroller
|
||||
#define Hiro_HorizontalSlider
|
||||
#define Hiro_IconView
|
||||
//#define Hiro_IconView
|
||||
#define Hiro_Label
|
||||
#define Hiro_LineEdit
|
||||
#define Hiro_ListView
|
||||
#define Hiro_ProgressBar
|
||||
#define Hiro_RadioButton
|
||||
#define Hiro_RadioLabel
|
||||
#define Hiro_SourceView
|
||||
//#define Hiro_SourceView
|
||||
#define Hiro_TabFrame
|
||||
#define Hiro_TextEdit
|
||||
#define Hiro_TreeView
|
||||
//#define Hiro_TreeView
|
||||
#define Hiro_VerticalScroller
|
||||
#define Hiro_VerticalSlider
|
||||
#define Hiro_Viewport
|
||||
|
@ -13,17 +13,17 @@ struct BrowserDialogWindow {
|
||||
private:
|
||||
Window window;
|
||||
VerticalLayout layout{&window};
|
||||
HorizontalLayout pathLayout{&layout, Size{~0, 0}, 8};
|
||||
HorizontalLayout pathLayout{&layout, Size{~0, 0}, 5};
|
||||
LineEdit pathName{&pathLayout, Size{~0, 0}, 0};
|
||||
Button pathHome{&pathLayout, Size{0, 0}, 0};
|
||||
Button pathRefresh{&pathLayout, Size{0, 0}, 0};
|
||||
Button pathUp{&pathLayout, Size{0, 0}, 0};
|
||||
ListView view{&layout, Size{~0, ~0}, 8};
|
||||
ListView view{&layout, Size{~0, ~0}, 5};
|
||||
HorizontalLayout controlLayout{&layout, Size{~0, 0}};
|
||||
ComboButton filterList{&controlLayout, Size{120, 0}, 8};
|
||||
LineEdit fileName{&controlLayout, Size{~0, 0}, 8};
|
||||
Button acceptButton{&controlLayout, Size{80, 0}, 8};
|
||||
Button cancelButton{&controlLayout, Size{80, 0}, 8};
|
||||
ComboButton filterList{&controlLayout, Size{120, 0}, 5};
|
||||
LineEdit fileName{&controlLayout, Size{~0, 0}, 5};
|
||||
Button acceptButton{&controlLayout, Size{80, 0}, 5};
|
||||
Button cancelButton{&controlLayout, Size{80, 0}, 5};
|
||||
|
||||
BrowserDialog::State& state;
|
||||
vector<lstring> filters;
|
||||
@ -116,7 +116,7 @@ auto BrowserDialogWindow::isMatch(const string& name) -> bool {
|
||||
auto BrowserDialogWindow::run() -> lstring {
|
||||
state.response.reset();
|
||||
|
||||
layout.setMargin(8);
|
||||
layout.setMargin(5);
|
||||
pathName.onActivate([&] { setPath(pathName.text()); });
|
||||
pathHome.setBordered(false).setIcon(Icon::Go::Home).onActivate([&] { setPath(userpath()); });
|
||||
pathRefresh.setBordered(false).setIcon(Icon::Action::Refresh).onActivate([&] { setPath(state.path); });
|
||||
@ -175,7 +175,7 @@ auto BrowserDialogWindow::setPath(string path) -> void {
|
||||
|
||||
view.append(ListViewItem()
|
||||
.append(ListViewCell().setText(content).setIcon(Icon::Emblem::Folder))
|
||||
.append(ListViewCell().setText(octal(storage::mode({path, content}) & 0777, 3L)))
|
||||
.append(ListViewCell().setText(octal(file_system_object::mode({path, content}) & 0777, 3L)))
|
||||
);
|
||||
}
|
||||
|
||||
@ -186,7 +186,7 @@ auto BrowserDialogWindow::setPath(string path) -> void {
|
||||
|
||||
view.append(ListViewItem()
|
||||
.append(ListViewCell().setText(content).setIcon(folderMode ? Icon::Action::Open : Icon::Emblem::File))
|
||||
.append(ListViewCell().setText(octal(storage::mode({path, content}) & 0777, 3L)))
|
||||
.append(ListViewCell().setText(octal(file_system_object::mode({path, content}) & 0777, 3L)))
|
||||
);
|
||||
}
|
||||
|
||||
|
@ -46,24 +46,24 @@ auto MessageDialog::warning(const lstring& buttons) -> string {
|
||||
auto MessageDialog::_run() -> string {
|
||||
Window window;
|
||||
VerticalLayout layout{&window};
|
||||
HorizontalLayout messageLayout{&layout, Size{~0, 0}, 8};
|
||||
Canvas messageIcon{&messageLayout, Size{16, 16}, 8};
|
||||
HorizontalLayout messageLayout{&layout, Size{~0, 0}, 5};
|
||||
Canvas messageIcon{&messageLayout, Size{16, 16}, 5};
|
||||
Label messageText{&messageLayout, Size{~0, 0}};
|
||||
HorizontalLayout controlLayout{&layout, Size{~0, 0}};
|
||||
Widget controlSpacer{&controlLayout, Size{~0, 0}};
|
||||
|
||||
layout.setMargin(8);
|
||||
layout.setMargin(5);
|
||||
messageIcon.setIcon(state.icon);
|
||||
messageText.setText(state.text);
|
||||
for(auto n : range(state.buttons)) {
|
||||
Button button{&controlLayout, Size{80, 0}, 8};
|
||||
Button button{&controlLayout, Size{80, 0}, 5};
|
||||
button.onActivate([&, n] { state.response = state.buttons[n]; window.setModal(false); });
|
||||
button.setText(state.buttons[n]);
|
||||
button.setFocused(); //the last button will have effective focus
|
||||
}
|
||||
|
||||
signed widthMessage = 8 + 16 + 8 + Font::size(Font::sans(), state.text).width() + 8;
|
||||
signed widthButtons = 8 + state.buttons.size() * 88;
|
||||
signed widthMessage = 5 + 16 + 5 + Font::size(Font::sans(), state.text).width() + 5;
|
||||
signed widthButtons = 5 + state.buttons.size() * 85;
|
||||
signed width = max(320, widthMessage, widthButtons);
|
||||
|
||||
window.onClose([&] { window.setModal(false); });
|
||||
|
@ -81,6 +81,14 @@ ifeq ($(platform),bsd)
|
||||
link += -Wl,-rpath=/usr/local/lib/gcc49
|
||||
endif
|
||||
|
||||
# threading support
|
||||
ifeq ($(threaded),true)
|
||||
ifneq ($(filter $(platform),linux bsd),)
|
||||
flags += -pthread
|
||||
link += -lrt
|
||||
endif
|
||||
endif
|
||||
|
||||
# cross-compilation support
|
||||
ifeq ($(arch),x86)
|
||||
flags := -m32 $(flags)
|
||||
|
@ -35,6 +35,11 @@ struct any {
|
||||
return static_cast<holder<typename remove_reference<T>::type>*>(container)->value;
|
||||
}
|
||||
|
||||
template<typename T> auto get(const T& fallback) const -> const T& {
|
||||
if(!is<T>()) return fallback;
|
||||
return static_cast<holder<typename remove_reference<T>::type>*>(container)->value;
|
||||
}
|
||||
|
||||
template<typename T> auto operator=(const T& value) -> any& {
|
||||
using auto_t = type_if<is_array<T>, typename remove_extent<typename add_const<T>::type>::type*, T>;
|
||||
|
||||
|
137
nall/base64.hpp
137
nall/base64.hpp
@ -1,137 +0,0 @@
|
||||
#ifndef NALL_BASE64_HPP
|
||||
#define NALL_BASE64_HPP
|
||||
|
||||
#include <nall/stdint.hpp>
|
||||
#include <nall/string.hpp>
|
||||
#include <nall/vector.hpp>
|
||||
|
||||
namespace nall {
|
||||
|
||||
struct Base64 {
|
||||
enum class Format : unsigned { MIME, URI };
|
||||
|
||||
inline static string encode(const uint8_t* data, unsigned size, Format format = Format::MIME);
|
||||
inline static string encode(const vector<uint8_t>& buffer, Format format = Format::MIME);
|
||||
inline static string encode(const string& text, Format format = Format::MIME);
|
||||
|
||||
inline static vector<uint8_t> decode(const string& text);
|
||||
|
||||
private:
|
||||
inline static void table(char* data, Format format);
|
||||
inline static uint8_t value(char data);
|
||||
};
|
||||
|
||||
string Base64::encode(const uint8_t* data, unsigned size, Format format) {
|
||||
vector<uint8_t> result;
|
||||
|
||||
char lookup[65];
|
||||
table(lookup, format);
|
||||
|
||||
unsigned overflow = (3 - (size % 3)) % 3; //bytes to round to nearest multiple of 3
|
||||
uint8_t buffer;
|
||||
|
||||
for(unsigned i = 0; i < size; i++) {
|
||||
switch(i % 3) {
|
||||
case 0:
|
||||
buffer = data[i] >> 2;
|
||||
result.append(lookup[buffer]);
|
||||
buffer = (data[i] & 3) << 4;
|
||||
result.append(lookup[buffer]);
|
||||
break;
|
||||
|
||||
case 1:
|
||||
buffer |= data[i] >> 4;
|
||||
result.last() = lookup[buffer];
|
||||
buffer = (data[i] & 15) << 2;
|
||||
result.append(lookup[buffer]);
|
||||
break;
|
||||
|
||||
case 2:
|
||||
buffer |= data[i] >> 6;
|
||||
result.last() = lookup[buffer];
|
||||
buffer = (data[i] & 63);
|
||||
result.append(lookup[buffer]);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if(lookup[64]) {
|
||||
if(overflow >= 1) result.append(lookup[64]);
|
||||
if(overflow >= 2) result.append(lookup[64]);
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
string Base64::encode(const vector<uint8_t>& buffer, Format format) {
|
||||
return encode(buffer.data(), buffer.size(), format);
|
||||
}
|
||||
|
||||
string Base64::encode(const string& text, Format format) {
|
||||
return encode((const uint8_t*)text.data(), text.size(), format);
|
||||
}
|
||||
|
||||
vector<uint8_t> Base64::decode(const string& text) {
|
||||
vector<uint8_t> result;
|
||||
|
||||
uint8_t buffer, output;
|
||||
for(unsigned i = 0; i < text.size(); i++) {
|
||||
uint8_t buffer = value(text[i]);
|
||||
if(buffer > 63) break;
|
||||
|
||||
switch(i & 3) {
|
||||
case 0:
|
||||
output = buffer << 2;
|
||||
break;
|
||||
|
||||
case 1:
|
||||
result.append(output | buffer >> 4);
|
||||
output = (buffer & 15) << 4;
|
||||
break;
|
||||
|
||||
case 2:
|
||||
result.append(output | buffer >> 2);
|
||||
output = (buffer & 3) << 6;
|
||||
break;
|
||||
|
||||
case 3:
|
||||
result.append(output | buffer);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
void Base64::table(char* data, Format format) {
|
||||
for(unsigned n = 0; n < 26; n++) data[ 0 + n] = 'A' + n;
|
||||
for(unsigned n = 0; n < 26; n++) data[26 + n] = 'a' + n;
|
||||
for(unsigned n = 0; n < 10; n++) data[52 + n] = '0' + n;
|
||||
|
||||
switch(format) {
|
||||
case Format::MIME:
|
||||
data[62] = '+';
|
||||
data[63] = '/';
|
||||
data[64] = '=';
|
||||
break;
|
||||
|
||||
case Format::URI:
|
||||
data[62] = '-';
|
||||
data[63] = '_';
|
||||
data[64] = 0;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
uint8_t Base64::value(char n) {
|
||||
if(n >= 'A' && n <= 'Z') return n - 'A' + 0;
|
||||
if(n >= 'a' && n <= 'z') return n - 'a' + 26;
|
||||
if(n >= '0' && n <= '9') return n - '0' + 52;
|
||||
if(n == '+' || n == '-') return 62;
|
||||
if(n == '/' || n == '_') return 63;
|
||||
return 64; //error code
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
#endif
|
@ -28,20 +28,26 @@ auto Archive::create(const string& beatname, const string& pathname, const strin
|
||||
scan(contents, pathname, pathname);
|
||||
|
||||
for(auto& name : contents) {
|
||||
if(name.endsWith("/")) {
|
||||
name.rtrim("/");
|
||||
beat.writevu(0 | ((name.length() - 1) << 1));
|
||||
beat.writes(name);
|
||||
} else {
|
||||
File input{{pathname, name}, file::mode::read};
|
||||
if(!input) return false;
|
||||
string location{pathname, name};
|
||||
bool directory = name.endsWith("/");
|
||||
bool readable = file_system_object::readable(location);
|
||||
bool writable = file_system_object::writable(location);
|
||||
bool executable = file_system_object::executable(location);
|
||||
unsigned info = directory << 0 | readable << 1 | writable << 2 | executable << 3 | (name.rtrim("/").size() - 1) << 4;
|
||||
|
||||
beat.writevu(1 | ((name.length() - 1) << 1));
|
||||
beat.writes(name);
|
||||
beat.writevu(info);
|
||||
beat.writes(name);
|
||||
if(directory) continue;
|
||||
|
||||
File input{location, file::mode::read};
|
||||
if(input) {
|
||||
auto size = input.size();
|
||||
beat.writevu(size);
|
||||
while(size--) beat.write(input.read());
|
||||
beat.writel(input.checksum.value(), 4);
|
||||
} else {
|
||||
beat.writevu(0);
|
||||
beat.writel(0x00000000, 4);
|
||||
}
|
||||
}
|
||||
|
||||
@ -61,14 +67,20 @@ auto Archive::unpack(const string& beatname, const string& pathname) -> bool {
|
||||
|
||||
directory::create(pathname);
|
||||
while(beat.offset() < beat.size() - 4) {
|
||||
auto data = beat.readvu();
|
||||
auto name = beat.reads((data >> 1) + 1);
|
||||
auto info = beat.readvu();
|
||||
auto name = beat.reads((info >> 4) + 1);
|
||||
if(name.find("\\") || name.find("../")) return false; //block path exploits
|
||||
|
||||
if((data & 1) == 0) {
|
||||
directory::create({pathname, name});
|
||||
string location{pathname, name};
|
||||
bool directory = info & 1;
|
||||
bool readable = info & 2;
|
||||
bool writable = info & 4;
|
||||
bool executable = info & 8;
|
||||
|
||||
if(directory) {
|
||||
if(!nall::directory::create(location)) return false;
|
||||
} else {
|
||||
File output{{pathname, name}, file::mode::write};
|
||||
File output{location, file::mode::write};
|
||||
if(!output) return false;
|
||||
|
||||
auto size = beat.readvu();
|
||||
@ -90,9 +102,10 @@ auto Archive::extract(const string& beatname, const string& filename) -> vector<
|
||||
beat.seek(beat.offset() + size);
|
||||
|
||||
while(beat.offset() < beat.size() - 4) {
|
||||
auto data = beat.readvu();
|
||||
auto name = beat.reads((data >> 1) + 1);
|
||||
if((data & 1) == 0) continue;
|
||||
auto info = beat.readvu();
|
||||
auto name = beat.reads((info >> 4) + 1);
|
||||
if(info & 1) continue; //ignore directories
|
||||
|
||||
auto size = beat.readvu();
|
||||
if(name != filename) {
|
||||
beat.seek(beat.offset() + size + 4);
|
||||
|
@ -222,7 +222,7 @@ protected:
|
||||
string readString(unsigned length) {
|
||||
string text;
|
||||
text.resize(length + 1);
|
||||
char* p = text.pointer();
|
||||
char* p = text.get();
|
||||
while(length--) *p++ = read();
|
||||
return text;
|
||||
}
|
||||
|
@ -1,6 +1,8 @@
|
||||
#ifndef NALL_BITVECTOR_HPP
|
||||
#define NALL_BITVECTOR_HPP
|
||||
|
||||
#include <nall/memory.hpp>
|
||||
|
||||
namespace nall {
|
||||
|
||||
struct bitvector {
|
||||
|
100
nall/bmp.hpp
100
nall/bmp.hpp
@ -1,100 +0,0 @@
|
||||
#ifndef NALL_BMP_HPP
|
||||
#define NALL_BMP_HPP
|
||||
|
||||
#include <nall/file.hpp>
|
||||
|
||||
//BMP reader / writer
|
||||
//note: only 24-bit RGB and 32-bit ARGB uncompressed images supported
|
||||
|
||||
namespace nall {
|
||||
|
||||
struct bmp {
|
||||
inline static auto read(const string& filename, uint32_t*& data, unsigned& width, unsigned& height) -> bool;
|
||||
inline static auto write(const string& filename, const uint32_t* data, unsigned width, unsigned height, unsigned pitch, bool alpha = false) -> bool;
|
||||
};
|
||||
|
||||
auto bmp::read(const string& filename, uint32_t*& data, unsigned& width, unsigned& height) -> bool {
|
||||
file fp;
|
||||
if(fp.open(filename, file::mode::read) == false) return false;
|
||||
if(fp.size() < 0x36) return false;
|
||||
|
||||
if(fp.readm(2) != 0x424d) return false;
|
||||
fp.seek(0x000a);
|
||||
unsigned offset = fp.readl(4);
|
||||
unsigned dibsize = fp.readl(4);
|
||||
if(dibsize != 40) return false;
|
||||
signed headerWidth = fp.readl(4);
|
||||
if(headerWidth < 0) return false;
|
||||
signed headerHeight = fp.readl(4);
|
||||
fp.readl(2);
|
||||
unsigned bitsPerPixel = fp.readl(2);
|
||||
if(bitsPerPixel != 24 && bitsPerPixel != 32) return false;
|
||||
unsigned compression = fp.readl(4);
|
||||
if(compression != 0) return false;
|
||||
fp.seek(offset);
|
||||
|
||||
bool noFlip = headerHeight < 0;
|
||||
width = headerWidth, height = abs(headerHeight);
|
||||
data = new uint32_t[width * height];
|
||||
|
||||
unsigned bytesPerPixel = bitsPerPixel / 8;
|
||||
unsigned alignedWidth = width * bytesPerPixel;
|
||||
unsigned paddingLength = 0;
|
||||
while(alignedWidth % 4) alignedWidth++, paddingLength++;
|
||||
|
||||
for(unsigned y = 0; y < height; y++) {
|
||||
uint32_t* p = noFlip ? data + y * width : data + (height - 1 - y) * width;
|
||||
for(unsigned x = 0; x < width; x++, p++) {
|
||||
*p = fp.readl(bytesPerPixel);
|
||||
if(bytesPerPixel == 3) *p |= 255 << 24;
|
||||
}
|
||||
if(paddingLength) fp.readl(paddingLength);
|
||||
}
|
||||
|
||||
fp.close();
|
||||
return true;
|
||||
}
|
||||
|
||||
auto bmp::write(const string& filename, const uint32_t* data, unsigned width, unsigned height, unsigned pitch, bool alpha) -> bool {
|
||||
file fp;
|
||||
if(fp.open(filename, file::mode::write) == false) return false;
|
||||
|
||||
unsigned bitsPerPixel = alpha ? 32 : 24;
|
||||
unsigned bytesPerPixel = bitsPerPixel / 8;
|
||||
unsigned alignedWidth = width * bytesPerPixel;
|
||||
unsigned paddingLength = 0;
|
||||
unsigned imageSize = alignedWidth * height;
|
||||
unsigned fileSize = 0x36 + imageSize;
|
||||
while(alignedWidth % 4) alignedWidth++, paddingLength++;
|
||||
|
||||
fp.writem(0x424d, 2); //signature
|
||||
fp.writel(fileSize, 4); //file size
|
||||
fp.writel(0, 2); //reserved
|
||||
fp.writel(0, 2); //reserved
|
||||
fp.writel(0x36, 4); //offset
|
||||
|
||||
fp.writel(40, 4); //DIB size
|
||||
fp.writel(width, 4); //width
|
||||
fp.writel(-height, 4); //height
|
||||
fp.writel(1, 2); //color planes
|
||||
fp.writel(bitsPerPixel, 2); //bits per pixel
|
||||
fp.writel(0, 4); //compression method (BI_RGB)
|
||||
fp.writel(imageSize, 4); //image data size
|
||||
fp.writel(3780, 4); //horizontal resolution
|
||||
fp.writel(3780, 4); //vertical resolution
|
||||
fp.writel(0, 4); //palette size
|
||||
fp.writel(0, 4); //important color count
|
||||
|
||||
for(unsigned y = 0; y < height; y++) {
|
||||
const uint32_t* p = (const uint32_t*)((const uint8_t*)data + y * pitch);
|
||||
for(unsigned x = 0; x < width; x++) fp.writel(*p++, bytesPerPixel);
|
||||
if(paddingLength) fp.writel(0, paddingLength);
|
||||
}
|
||||
|
||||
fp.close();
|
||||
return true;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
#endif
|
@ -20,44 +20,61 @@ struct ODBC {
|
||||
auto operator=(Statement&& source) -> Statement& {
|
||||
_statement = source._statement;
|
||||
_output = source._output;
|
||||
_values = move(source._values);
|
||||
source._statement = nullptr;
|
||||
source._output = 0;
|
||||
return *this;
|
||||
}
|
||||
|
||||
auto columns() -> unsigned {
|
||||
SQLSMALLINT columns = 0;
|
||||
if(statement()) SQLNumResultCols(statement(), &columns);
|
||||
return columns;
|
||||
}
|
||||
|
||||
auto integer(unsigned column) -> int64_t {
|
||||
if(auto value = _values(column)) return value.get<int64_t>(0);
|
||||
int64_t value = 0;
|
||||
SQLGetData(statement(), 1 + column, SQL_C_SBIGINT, &value, 0, nullptr);
|
||||
_values(column) = (int64_t)value;
|
||||
return value;
|
||||
}
|
||||
|
||||
auto decimal(unsigned column) -> uint64_t {
|
||||
if(auto value = _values(column)) return value.get<uint64_t>(0);
|
||||
uint64_t value = 0;
|
||||
SQLGetData(statement(), 1 + column, SQL_C_UBIGINT, &value, 0, nullptr);
|
||||
_values(column) = (uint64_t)value;
|
||||
return value;
|
||||
}
|
||||
|
||||
auto real(unsigned column) -> double {
|
||||
if(auto value = _values(column)) return value.get<double>(0.0);
|
||||
double value = 0.0;
|
||||
SQLGetData(statement(), 1 + column, SQL_C_DOUBLE, &value, 0, nullptr);
|
||||
_values(column) = (double)value;
|
||||
return value;
|
||||
}
|
||||
|
||||
auto text(unsigned column) -> string {
|
||||
if(auto value = _values(column)) return value.get<string>({});
|
||||
string value;
|
||||
value.resize(65535);
|
||||
SQLLEN size = 0;
|
||||
SQLGetData(statement(), 1 + column, SQL_C_CHAR, value.pointer(), value.size(), &size);
|
||||
SQLGetData(statement(), 1 + column, SQL_C_CHAR, value.get(), value.size(), &size);
|
||||
value.resize(size);
|
||||
_values(column) = (string)value;
|
||||
return value;
|
||||
}
|
||||
|
||||
auto data(unsigned column) -> vector<uint8_t> {
|
||||
if(auto value = _values(column)) return value.get<vector<uint8_t>>({});
|
||||
vector<uint8_t> value;
|
||||
value.resize(65535);
|
||||
SQLLEN size = 0;
|
||||
SQLGetData(statement(), 1 + column, SQL_C_CHAR, value.data(), value.size(), &size);
|
||||
value.resize(size);
|
||||
_values(column) = (vector<uint8_t>)value;
|
||||
return value;
|
||||
}
|
||||
|
||||
@ -72,6 +89,7 @@ struct ODBC {
|
||||
|
||||
SQLHANDLE _statement = nullptr;
|
||||
unsigned _output = 0;
|
||||
vector<any> _values; //some ODBC drivers (eg MS-SQL) do not allow the same column to be read more than once
|
||||
};
|
||||
|
||||
struct Query : Statement {
|
||||
@ -89,18 +107,23 @@ struct ODBC {
|
||||
}
|
||||
|
||||
auto operator=(Query&& source) -> Query& {
|
||||
Statement::operator=(move(source));
|
||||
_bindings = move(source._bindings);
|
||||
_statement = source._statement;
|
||||
_result = source._result;
|
||||
_input = source._input;
|
||||
_stepped = source._stepped;
|
||||
source._statement = nullptr;
|
||||
source._result = SQL_SUCCESS;
|
||||
source._input = 0;
|
||||
source._stepped = false;
|
||||
return *this;
|
||||
}
|
||||
|
||||
explicit operator bool() {
|
||||
//this is likely not the best way to test if the query has returned data ...
|
||||
//but I wasn't able to find an ODBC API for this seemingly simple task
|
||||
return statement() && success();
|
||||
}
|
||||
|
||||
//ODBC SQLBindParameter only holds pointers to data values
|
||||
//if the bound paramters go out of scope before the query is executed, binding would reference dangling pointers
|
||||
//so to work around this, we cache all parameters inside Query until the query is executed
|
||||
@ -140,11 +163,13 @@ struct ODBC {
|
||||
} else if(binding.value.is<double>()) {
|
||||
SQLBindParameter(_statement, 1 + binding.column, SQL_PARAM_INPUT, SQL_C_DOUBLE, SQL_DOUBLE, 0, 0, &binding.value.get<double>(), 0, nullptr);
|
||||
} else if(binding.value.is<string>()) {
|
||||
auto& value = binding.value.get<string>();
|
||||
SQLLEN length = SQL_NTS;
|
||||
SQLBindParameter(_statement, 1 + binding.column, SQL_PARAM_INPUT, SQL_C_CHAR, SQL_VARCHAR, 0, 0, (SQLPOINTER)binding.value.get<string>().data(), 0, &length);
|
||||
SQLBindParameter(_statement, 1 + binding.column, SQL_PARAM_INPUT, SQL_C_CHAR, SQL_VARCHAR, value.size(), 0, (SQLPOINTER)value.data(), 0, &length);
|
||||
} else if(binding.value.is<vector<uint8_t>>()) {
|
||||
SQLLEN length = binding.value.get<vector<uint8_t>>().size();
|
||||
SQLBindParameter(_statement, 1 + binding.column, SQL_PARAM_INPUT, SQL_C_CHAR, SQL_VARBINARY, 0, 0, (SQLPOINTER)binding.value.get<vector<uint8_t>>().data(), 0, &length);
|
||||
auto& value = binding.value.get<vector<uint8_t>>();
|
||||
SQLLEN length = value.size();
|
||||
SQLBindParameter(_statement, 1 + binding.column, SQL_PARAM_INPUT, SQL_C_CHAR, SQL_VARBINARY, value.size(), 0, (SQLPOINTER)value.data(), 0, &length);
|
||||
}
|
||||
}
|
||||
|
||||
@ -153,6 +178,7 @@ struct ODBC {
|
||||
if(!success()) return false;
|
||||
}
|
||||
|
||||
_values.reset(); //clear previous row's cached read results
|
||||
_result = SQLFetch(_statement);
|
||||
_output = 0;
|
||||
return success();
|
||||
|
@ -31,6 +31,14 @@ struct SQLite3 {
|
||||
return *this;
|
||||
}
|
||||
|
||||
explicit operator bool() {
|
||||
return sqlite3_data_count(statement());
|
||||
}
|
||||
|
||||
auto columns() -> unsigned {
|
||||
return sqlite3_column_count(statement());
|
||||
}
|
||||
|
||||
auto integer(unsigned column) -> int64_t {
|
||||
return sqlite3_column_int64(statement(), column);
|
||||
}
|
||||
@ -47,7 +55,7 @@ struct SQLite3 {
|
||||
string result;
|
||||
if(auto text = sqlite3_column_text(statement(), column)) {
|
||||
result.resize(sqlite3_column_bytes(statement(), column));
|
||||
memory::copy(result.pointer(), text, result.size());
|
||||
memory::copy(result.get(), text, result.size());
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
49
nall/decode/base64.hpp
Normal file
49
nall/decode/base64.hpp
Normal file
@ -0,0 +1,49 @@
|
||||
#ifndef NALL_DECODE_BASE64_HPP
|
||||
#define NALL_DECODE_BASE64_HPP
|
||||
|
||||
namespace nall { namespace Decode {
|
||||
|
||||
inline auto Base64(const string& text) -> vector<uint8_t> {
|
||||
auto value = [](char n) -> uint8_t {
|
||||
if(n >= 'A' && n <= 'Z') return n - 'A' + 0;
|
||||
if(n >= 'a' && n <= 'z') return n - 'a' + 26;
|
||||
if(n >= '0' && n <= '9') return n - '0' + 52;
|
||||
if(n == '+' || n == '-') return 62;
|
||||
if(n == '/' || n == '_') return 63;
|
||||
return 64; //error code
|
||||
};
|
||||
|
||||
vector<uint8_t> result;
|
||||
|
||||
uint8_t buffer, output;
|
||||
for(unsigned i = 0; i < text.size(); i++) {
|
||||
uint8_t buffer = value(text[i]);
|
||||
if(buffer > 63) break;
|
||||
|
||||
switch(i & 3) {
|
||||
case 0:
|
||||
output = buffer << 2;
|
||||
break;
|
||||
|
||||
case 1:
|
||||
result.append(output | buffer >> 4);
|
||||
output = (buffer & 15) << 4;
|
||||
break;
|
||||
|
||||
case 2:
|
||||
result.append(output | buffer >> 2);
|
||||
output = (buffer & 3) << 6;
|
||||
break;
|
||||
|
||||
case 3:
|
||||
result.append(output | buffer);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
}}
|
||||
|
||||
#endif
|
@ -1,8 +1,79 @@
|
||||
#ifndef NALL_DECODE_BMP_HPP
|
||||
#define NALL_DECODE_BMP_HPP
|
||||
|
||||
namespace nall {
|
||||
namespace nall { namespace Decode {
|
||||
|
||||
}
|
||||
struct BMP {
|
||||
BMP() = default;
|
||||
BMP(const string& filename) { load(filename); }
|
||||
BMP(const uint8_t* data, unsigned size) { load(data, size); }
|
||||
|
||||
explicit operator bool() const { return _data; }
|
||||
|
||||
auto reset() -> void {
|
||||
if(_data) { delete[] _data; _data = nullptr; }
|
||||
}
|
||||
|
||||
auto data() -> uint32_t* { return _data; }
|
||||
auto data() const -> const uint32_t* { return _data; }
|
||||
auto width() const -> unsigned { return _width; }
|
||||
auto height() const -> unsigned { return _height; }
|
||||
|
||||
auto load(const string& filename) -> bool {
|
||||
auto buffer = file::read(filename);
|
||||
return load(buffer.data(), buffer.size());
|
||||
}
|
||||
|
||||
auto load(const uint8_t* data, unsigned size) -> bool {
|
||||
if(size < 0x36) return false;
|
||||
const uint8_t* p = data;
|
||||
if(read(p, 2) != 0x4d42) return false; //signature
|
||||
read(p, 8);
|
||||
unsigned offset = read(p, 4);
|
||||
if(read(p, 4) != 40) return false; //DIB size
|
||||
signed width = read(p, 4);
|
||||
if(width < 0) return false;
|
||||
signed height = read(p, 4);
|
||||
bool flip = height < 0;
|
||||
if(flip) height = -height;
|
||||
read(p, 2);
|
||||
unsigned bitsPerPixel = read(p, 2);
|
||||
if(bitsPerPixel != 24 && bitsPerPixel != 32) return false;
|
||||
if(read(p, 4) != 0) return false; //compression type
|
||||
|
||||
_width = width;
|
||||
_height = height;
|
||||
_data = new uint32_t[width * height];
|
||||
|
||||
unsigned bytesPerPixel = bitsPerPixel / 8;
|
||||
unsigned alignedWidth = width * bytesPerPixel;
|
||||
unsigned paddingLength = 0;
|
||||
while(alignedWidth % 4) alignedWidth++, paddingLength++;
|
||||
|
||||
p = data + offset;
|
||||
for(auto y : range(height)) {
|
||||
uint32_t* output = flip ? _data + (height - 1 - y) * width : _data + y * width;
|
||||
for(auto x : range(width)) {
|
||||
*output++ = read(p, bytesPerPixel) | (bitsPerPixel == 24 ? 255u << 24 : 0);
|
||||
}
|
||||
if(paddingLength) read(p, paddingLength);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
private:
|
||||
uint32_t* _data = nullptr;
|
||||
unsigned _width = 0;
|
||||
unsigned _height = 0;
|
||||
|
||||
auto read(const uint8_t*& buffer, unsigned length) -> uintmax_t {
|
||||
uintmax_t result = 0;
|
||||
for(auto n : range(length)) result |= (uintmax_t)*buffer++ << (n << 3);
|
||||
return result;
|
||||
}
|
||||
};
|
||||
|
||||
}}
|
||||
|
||||
#endif
|
||||
|
@ -31,8 +31,8 @@ struct PNG {
|
||||
uint8_t* data = nullptr;
|
||||
unsigned size = 0;
|
||||
|
||||
inline bool decode(const string& filename);
|
||||
inline bool decode(const uint8_t* sourceData, unsigned sourceSize);
|
||||
inline bool load(const string& filename);
|
||||
inline bool load(const uint8_t* sourceData, unsigned sourceSize);
|
||||
inline unsigned readbits(const uint8_t*& data);
|
||||
unsigned bitpos = 0;
|
||||
|
||||
@ -54,14 +54,14 @@ protected:
|
||||
inline unsigned read(const uint8_t* data, unsigned length);
|
||||
};
|
||||
|
||||
bool PNG::decode(const string& filename) {
|
||||
bool PNG::load(const string& filename) {
|
||||
if(auto memory = file::read(filename)) {
|
||||
return decode(memory.data(), memory.size());
|
||||
return load(memory.data(), memory.size());
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
bool PNG::decode(const uint8_t* sourceData, unsigned sourceSize) {
|
||||
bool PNG::load(const uint8_t* sourceData, unsigned sourceSize) {
|
||||
if(sourceSize < 8) return false;
|
||||
if(read(sourceData + 0, 4) != 0x89504e47) return false;
|
||||
if(read(sourceData + 4, 4) != 0x0d0a1a0a) return false;
|
||||
|
@ -2,9 +2,9 @@
|
||||
#define NALL_DIRECTORY_HPP
|
||||
|
||||
#include <nall/file.hpp>
|
||||
#include <nall/file-system-object.hpp>
|
||||
#include <nall/intrinsics.hpp>
|
||||
#include <nall/sort.hpp>
|
||||
#include <nall/storage.hpp>
|
||||
#include <nall/string.hpp>
|
||||
#include <nall/vector.hpp>
|
||||
|
||||
@ -18,7 +18,7 @@
|
||||
|
||||
namespace nall {
|
||||
|
||||
struct directory : storage {
|
||||
struct directory : file_system_object {
|
||||
static auto create(const string& pathname, unsigned permissions = 0755) -> bool; //recursive
|
||||
static auto remove(const string& pathname) -> bool; //recursive
|
||||
static auto exists(const string& pathname) -> bool;
|
||||
@ -78,6 +78,7 @@ private:
|
||||
bool result = true;
|
||||
for(auto& part : list) {
|
||||
path.append(part, "/");
|
||||
if(directory::exists(path)) continue;
|
||||
result &= (_wmkdir(utf16_t(path)) == 0);
|
||||
}
|
||||
return result;
|
||||
|
70
nall/encode/base64.hpp
Normal file
70
nall/encode/base64.hpp
Normal file
@ -0,0 +1,70 @@
|
||||
#ifndef NALL_ENCODE_BASE64_HPP
|
||||
#define NALL_ENCODE_BASE64_HPP
|
||||
|
||||
namespace nall { namespace Encode {
|
||||
|
||||
inline auto Base64(const uint8_t* data, unsigned size, const string& format = "MIME") -> string {
|
||||
vector<uint8_t> result;
|
||||
|
||||
char lookup[65];
|
||||
for(unsigned n = 0; n < 26; n++) lookup[ 0 + n] = 'A' + n;
|
||||
for(unsigned n = 0; n < 26; n++) lookup[26 + n] = 'a' + n;
|
||||
for(unsigned n = 0; n < 10; n++) lookup[52 + n] = '0' + n;
|
||||
|
||||
if(format == "MIME") {
|
||||
lookup[62] = '+';
|
||||
lookup[63] = '/';
|
||||
lookup[64] = '=';
|
||||
} else if(format == "URI") {
|
||||
lookup[62] = '-';
|
||||
lookup[63] = '_';
|
||||
lookup[64] = 0;
|
||||
} else return "";
|
||||
|
||||
unsigned overflow = (3 - (size % 3)) % 3; //bytes to round to nearest multiple of 3
|
||||
uint8_t buffer;
|
||||
|
||||
for(unsigned i = 0; i < size; i++) {
|
||||
switch(i % 3) {
|
||||
case 0:
|
||||
buffer = data[i] >> 2;
|
||||
result.append(lookup[buffer]);
|
||||
buffer = (data[i] & 3) << 4;
|
||||
result.append(lookup[buffer]);
|
||||
break;
|
||||
|
||||
case 1:
|
||||
buffer |= data[i] >> 4;
|
||||
result.last() = lookup[buffer];
|
||||
buffer = (data[i] & 15) << 2;
|
||||
result.append(lookup[buffer]);
|
||||
break;
|
||||
|
||||
case 2:
|
||||
buffer |= data[i] >> 6;
|
||||
result.last() = lookup[buffer];
|
||||
buffer = (data[i] & 63);
|
||||
result.append(lookup[buffer]);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if(lookup[64]) {
|
||||
if(overflow >= 1) result.append(lookup[64]);
|
||||
if(overflow >= 2) result.append(lookup[64]);
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
inline auto Base64(const vector<uint8_t>& buffer, const string& format = "MIME") -> string {
|
||||
return Base64(buffer.data(), buffer.size(), format);
|
||||
}
|
||||
|
||||
inline auto Base64(const string& text, const string& format = "MIME") -> string {
|
||||
return Base64(text.binary(), text.size(), format);
|
||||
}
|
||||
|
||||
}}
|
||||
|
||||
#endif
|
49
nall/encode/bmp.hpp
Normal file
49
nall/encode/bmp.hpp
Normal file
@ -0,0 +1,49 @@
|
||||
#ifndef NALL_ENCODE_BMP_HPP
|
||||
#define NALL_ENCODE_BMP_HPP
|
||||
|
||||
namespace nall { namespace Encode {
|
||||
|
||||
struct BMP {
|
||||
static auto create(const string& filename, const uint32_t* data, unsigned width, unsigned height, bool alpha) -> bool {
|
||||
file fp{filename, file::mode::write};
|
||||
if(!fp) return false;
|
||||
|
||||
unsigned bitsPerPixel = alpha ? 32 : 24;
|
||||
unsigned bytesPerPixel = bitsPerPixel / 8;
|
||||
unsigned alignedWidth = width * bytesPerPixel;
|
||||
unsigned paddingLength = 0;
|
||||
unsigned imageSize = alignedWidth * height;
|
||||
unsigned fileSize = 0x36 + imageSize;
|
||||
while(alignedWidth % 4) alignedWidth++, paddingLength++;
|
||||
|
||||
fp.writel(0x4d42, 2); //signature
|
||||
fp.writel(fileSize, 4); //file size
|
||||
fp.writel(0, 2); //reserved
|
||||
fp.writel(0, 2); //reserved
|
||||
fp.writel(0x36, 4); //offset
|
||||
|
||||
fp.writel(40, 4); //DIB size
|
||||
fp.writel(width, 4); //width
|
||||
fp.writel(-height, 4); //height
|
||||
fp.writel(1, 2); //color planes
|
||||
fp.writel(bitsPerPixel, 2); //bits per pixel
|
||||
fp.writel(0, 4); //compression method (BI_RGB)
|
||||
fp.writel(imageSize, 4); //image data size
|
||||
fp.writel(3780, 4); //horizontal resolution
|
||||
fp.writel(3780, 4); //vertical resolution
|
||||
fp.writel(0, 4); //palette size
|
||||
fp.writel(0, 4); //important color count
|
||||
|
||||
for(auto y : range(height)) {
|
||||
const uint32_t* p = data + y * width;
|
||||
for(auto x : range(width)) fp.writel(*p++, bytesPerPixel);
|
||||
if(paddingLength) fp.writel(0, paddingLength);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
};
|
||||
|
||||
}}
|
||||
|
||||
#endif
|
@ -1,5 +1,5 @@
|
||||
#ifndef NALL_ZIP_HPP
|
||||
#define NALL_ZIP_HPP
|
||||
#ifndef NALL_ENCODE_ZIP_HPP
|
||||
#define NALL_ENCODE_ZIP_HPP
|
||||
|
||||
//creates uncompressed ZIP archives
|
||||
|
||||
@ -19,7 +19,7 @@ struct ZIP {
|
||||
|
||||
//append path: append("path/");
|
||||
//append file: append("path/file", data, size);
|
||||
void append(string filename, const uint8_t* data = nullptr, unsigned size = 0u) {
|
||||
auto append(string filename, const uint8_t* data = nullptr, unsigned size = 0u) -> void {
|
||||
filename.transform("\\", "/");
|
||||
uint32_t checksum = Hash::CRC32(data, size).value();
|
||||
directory.append({filename, checksum, size, fp.offset()});
|
||||
|
81
nall/file-system-object.hpp
Normal file
81
nall/file-system-object.hpp
Normal file
@ -0,0 +1,81 @@
|
||||
#ifndef NALL_STORAGE_HPP
|
||||
#define NALL_STORAGE_HPP
|
||||
|
||||
//generic abstraction layer for common storage operations against both files and directories
|
||||
//these functions are not recursive; use directory::create() and directory::remove() for recursion
|
||||
|
||||
#include <nall/platform.hpp>
|
||||
#include <nall/string.hpp>
|
||||
|
||||
namespace nall {
|
||||
|
||||
struct file_system_object {
|
||||
enum class time : unsigned { access, modify };
|
||||
|
||||
static auto exists(const string& name) -> bool {
|
||||
return access(name, F_OK) == 0;
|
||||
}
|
||||
|
||||
static auto readable(const string& name) -> bool {
|
||||
return access(name, R_OK) == 0;
|
||||
}
|
||||
|
||||
static auto writable(const string& name) -> bool {
|
||||
return access(name, W_OK) == 0;
|
||||
}
|
||||
|
||||
static auto executable(const string& name) -> bool {
|
||||
return access(name, X_OK) == 0;
|
||||
}
|
||||
|
||||
static auto uid(const string& name) -> unsigned {
|
||||
struct stat data{0};
|
||||
stat(name, &data);
|
||||
return data.st_uid;
|
||||
}
|
||||
|
||||
static auto gid(const string& name) -> unsigned {
|
||||
struct stat data{0};
|
||||
stat(name, &data);
|
||||
return data.st_gid;
|
||||
}
|
||||
|
||||
static auto mode(const string& name) -> unsigned {
|
||||
struct stat data{0};
|
||||
stat(name, &data);
|
||||
return data.st_mode;
|
||||
}
|
||||
|
||||
static auto timestamp(const string& name, time mode = time::modify) -> time_t {
|
||||
struct stat data = {0};
|
||||
stat(name, &data);
|
||||
switch(mode) { default:
|
||||
case time::access: return data.st_atime;
|
||||
case time::modify: return data.st_mtime;
|
||||
}
|
||||
}
|
||||
|
||||
//returns true if 'name' already exists
|
||||
static auto create(const string& name, unsigned permissions = 0755) -> bool {
|
||||
if(exists(name)) return true;
|
||||
if(name.endsWith("/")) return mkdir(name, permissions) == 0;
|
||||
int fd = open(name, O_CREAT | O_EXCL, permissions);
|
||||
if(fd < 0) return false;
|
||||
return close(fd), true;
|
||||
}
|
||||
|
||||
//returns false if 'name' and 'targetname' are on different file systems (requires copy)
|
||||
static auto rename(const string& name, const string& targetname) -> bool {
|
||||
return ::rename(name, targetname) == 0;
|
||||
}
|
||||
|
||||
//returns false if 'name' is a directory that is not empty
|
||||
static auto remove(const string& name) -> bool {
|
||||
if(name.endsWith("/")) return rmdir(name) == 0;
|
||||
return unlink(name) == 0;
|
||||
}
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
#endif
|
@ -2,8 +2,8 @@
|
||||
#define NALL_FILE_HPP
|
||||
|
||||
#include <nall/platform.hpp>
|
||||
#include <nall/file-system-object.hpp>
|
||||
#include <nall/stdint.hpp>
|
||||
#include <nall/storage.hpp>
|
||||
#include <nall/string.hpp>
|
||||
#include <nall/utility.hpp>
|
||||
#include <nall/varint.hpp>
|
||||
@ -12,7 +12,7 @@
|
||||
|
||||
namespace nall {
|
||||
|
||||
struct file : storage, varint {
|
||||
struct file : file_system_object, varint {
|
||||
enum class mode : unsigned { read, write, modify, append, readwrite = modify, writeread = append };
|
||||
enum class index : unsigned { absolute, relative };
|
||||
|
||||
@ -37,25 +37,24 @@ struct file : storage, varint {
|
||||
}
|
||||
|
||||
static auto truncate(const string& filename, unsigned size) -> bool {
|
||||
#if !defined(_WIN32)
|
||||
#if defined(API_POSIX)
|
||||
return truncate(filename, size) == 0;
|
||||
#else
|
||||
bool result = false;
|
||||
FILE* fp = _wfopen(utf16_t(filename), L"rb+");
|
||||
if(fp) {
|
||||
result = _chsize(fileno(fp), size) == 0;
|
||||
#elif defined(API_WINDOWS)
|
||||
if(auto fp = _wfopen(utf16_t(filename), L"rb+")) {
|
||||
bool result = _chsize(fileno(fp), size) == 0;
|
||||
fclose(fp);
|
||||
return result;
|
||||
}
|
||||
return result;
|
||||
return false;
|
||||
#endif
|
||||
}
|
||||
|
||||
//specialization of storage::exists(); returns false for folders
|
||||
//returns false if specified filename is a directory
|
||||
static auto exists(const string& filename) -> bool {
|
||||
#if !defined(_WIN32)
|
||||
#if defined(API_POSIX)
|
||||
struct stat data;
|
||||
if(stat(filename, &data) != 0) return false;
|
||||
#else
|
||||
#elif defined(API_WINDOWS)
|
||||
struct __stat64 data;
|
||||
if(_wstat64(utf16_t(filename), &data) != 0) return false;
|
||||
#endif
|
||||
@ -63,10 +62,10 @@ struct file : storage, varint {
|
||||
}
|
||||
|
||||
static auto size(const string& filename) -> uintmax_t {
|
||||
#if !defined(_WIN32)
|
||||
#if defined(API_POSIX)
|
||||
struct stat data;
|
||||
stat(filename, &data);
|
||||
#else
|
||||
#elif defined(API_WINDOWS)
|
||||
struct __stat64 data;
|
||||
_wstat64(utf16_t(filename), &data);
|
||||
#endif
|
||||
@ -240,9 +239,9 @@ struct file : storage, varint {
|
||||
|
||||
auto truncate(unsigned size) -> bool {
|
||||
if(!fp) return false; //file not open
|
||||
#if !defined(_WIN32)
|
||||
#if defined(API_POSIX)
|
||||
return ftruncate(fileno(fp), size) == 0;
|
||||
#else
|
||||
#elif defined(API_WINDOWS)
|
||||
return _chsize(fileno(fp), size) == 0;
|
||||
#endif
|
||||
}
|
||||
@ -264,12 +263,12 @@ struct file : storage, varint {
|
||||
if(fp) return false;
|
||||
|
||||
switch(file_mode = mode_) {
|
||||
#if !defined(_WIN32)
|
||||
#if defined(API_POSIX)
|
||||
case mode::read: fp = fopen(filename, "rb" ); break;
|
||||
case mode::write: fp = fopen(filename, "wb+"); break; //need read permission for buffering
|
||||
case mode::readwrite: fp = fopen(filename, "rb+"); break;
|
||||
case mode::writeread: fp = fopen(filename, "wb+"); break;
|
||||
#else
|
||||
#elif defined(API_WINDOWS)
|
||||
case mode::read: fp = _wfopen(utf16_t(filename), L"rb" ); break;
|
||||
case mode::write: fp = _wfopen(utf16_t(filename), L"wb+"); break;
|
||||
case mode::readwrite: fp = _wfopen(utf16_t(filename), L"rb+"); break;
|
||||
|
@ -3,21 +3,21 @@
|
||||
|
||||
#include <nall/http/role.hpp>
|
||||
|
||||
namespace nall {
|
||||
namespace nall { namespace HTTP {
|
||||
|
||||
struct httpClient : httpRole {
|
||||
struct Client : Role {
|
||||
inline auto open(const string& hostname, unsigned port = 80) -> bool;
|
||||
inline auto upload(const httpRequest& request) -> bool;
|
||||
inline auto download(const httpRequest& request) -> httpResponse;
|
||||
inline auto upload(const Request& request) -> bool;
|
||||
inline auto download(const Request& request) -> Response;
|
||||
inline auto close() -> void;
|
||||
~httpClient() { close(); }
|
||||
~Client() { close(); }
|
||||
|
||||
private:
|
||||
signed fd = -1;
|
||||
addrinfo* info = nullptr;
|
||||
};
|
||||
|
||||
auto httpClient::open(const string& hostname, unsigned port) -> bool {
|
||||
auto Client::open(const string& hostname, unsigned port) -> bool {
|
||||
addrinfo hint = {0};
|
||||
hint.ai_family = AF_UNSPEC;
|
||||
hint.ai_socktype = SOCK_STREAM;
|
||||
@ -32,17 +32,17 @@ auto httpClient::open(const string& hostname, unsigned port) -> bool {
|
||||
return true;
|
||||
}
|
||||
|
||||
auto httpClient::upload(const httpRequest& request) -> bool {
|
||||
return httpRole::upload(fd, request);
|
||||
auto Client::upload(const Request& request) -> bool {
|
||||
return Role::upload(fd, request);
|
||||
}
|
||||
|
||||
auto httpClient::download(const httpRequest& request) -> httpResponse {
|
||||
httpResponse response(request);
|
||||
httpRole::download(fd, response);
|
||||
auto Client::download(const Request& request) -> Response {
|
||||
Response response(request);
|
||||
Role::download(fd, response);
|
||||
return response;
|
||||
}
|
||||
|
||||
auto httpClient::close() -> void {
|
||||
auto Client::close() -> void {
|
||||
if(fd) {
|
||||
::close(fd);
|
||||
fd = -1;
|
||||
@ -54,6 +54,6 @@ auto httpClient::close() -> void {
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
}}
|
||||
|
||||
#endif
|
||||
|
@ -4,32 +4,32 @@
|
||||
//httpMessage: base class for httpRequest and httpResponse
|
||||
//provides shared functionality
|
||||
|
||||
namespace nall {
|
||||
namespace nall { namespace HTTP {
|
||||
|
||||
struct httpVariable {
|
||||
struct Variable {
|
||||
string name;
|
||||
string value;
|
||||
};
|
||||
|
||||
struct httpVariables : vector<httpVariable> {
|
||||
struct Variables : vector<Variable> {
|
||||
auto append(const string& name, const string& value) -> void;
|
||||
auto get(const string& name) const -> string;
|
||||
auto remove(const string& name) -> void;
|
||||
auto set(const string& name, const string& value) -> void;
|
||||
};
|
||||
|
||||
auto httpVariables::append(const string& name, const string& value) -> void {
|
||||
auto Variables::append(const string& name, const string& value) -> void {
|
||||
vector::append({name, value});
|
||||
}
|
||||
|
||||
auto httpVariables::get(const string& name) const -> string {
|
||||
auto Variables::get(const string& name) const -> string {
|
||||
for(auto& variable : *this) {
|
||||
if(variable.name.iequals(name)) return variable.value;
|
||||
}
|
||||
return "";
|
||||
}
|
||||
|
||||
auto httpVariables::remove(const string& name) -> void {
|
||||
auto Variables::remove(const string& name) -> void {
|
||||
while(true) {
|
||||
unsigned n = 0;
|
||||
bool found = false;
|
||||
@ -43,7 +43,7 @@ auto httpVariables::remove(const string& name) -> void {
|
||||
}
|
||||
}
|
||||
|
||||
auto httpVariables::set(const string& name, const string& value) -> void {
|
||||
auto Variables::set(const string& name, const string& value) -> void {
|
||||
for(auto& variable : *this) {
|
||||
if(!variable.name.iequals(name)) continue;
|
||||
variable.name = name;
|
||||
@ -53,8 +53,8 @@ auto httpVariables::set(const string& name, const string& value) -> void {
|
||||
vector::append({name, value});
|
||||
}
|
||||
|
||||
struct httpMessage {
|
||||
using type = httpMessage;
|
||||
struct Message {
|
||||
using type = Message;
|
||||
|
||||
virtual auto head(const function<bool (const uint8_t* data, unsigned size)>& callback) const -> bool = 0;
|
||||
virtual auto setHead() -> bool = 0;
|
||||
@ -69,9 +69,9 @@ struct httpMessage {
|
||||
|
||||
string _head;
|
||||
string _body;
|
||||
httpVariables _header;
|
||||
Variables _header;
|
||||
};
|
||||
|
||||
}
|
||||
}}
|
||||
|
||||
#endif
|
||||
|
@ -3,10 +3,10 @@
|
||||
|
||||
#include <nall/http/message.hpp>
|
||||
|
||||
namespace nall {
|
||||
namespace nall { namespace HTTP {
|
||||
|
||||
struct httpRequest : httpMessage {
|
||||
using type = httpRequest;
|
||||
struct Request : Message {
|
||||
using type = Request;
|
||||
|
||||
enum class RequestType : unsigned { None, Head, Get, Post };
|
||||
|
||||
@ -28,9 +28,9 @@ struct httpRequest : httpMessage {
|
||||
auto path() const -> string { return _path; }
|
||||
auto setPath(const string& value) -> void { _path = value; }
|
||||
|
||||
auto appendHeader(const string& name, const string& value = "") -> type& { return httpMessage::appendHeader(name, value), *this; }
|
||||
auto removeHeader(const string& name) -> type& { return httpMessage::removeHeader(name), *this; }
|
||||
auto setHeader(const string& name, const string& value = "") -> type& { return httpMessage::setHeader(name, value), *this; }
|
||||
auto appendHeader(const string& name, const string& value = "") -> type& { return Message::appendHeader(name, value), *this; }
|
||||
auto removeHeader(const string& name) -> type& { return Message::removeHeader(name), *this; }
|
||||
auto setHeader(const string& name, const string& value = "") -> type& { return Message::setHeader(name, value), *this; }
|
||||
|
||||
auto cookie(const string& name) const -> string { return _cookie.get(name); }
|
||||
auto setCookie(const string& name, const string& value = "") -> void { _cookie.set(name, value); }
|
||||
@ -46,12 +46,12 @@ struct httpRequest : httpMessage {
|
||||
string _ip;
|
||||
RequestType _requestType = RequestType::None;
|
||||
string _path;
|
||||
httpVariables _cookie;
|
||||
httpVariables _get;
|
||||
httpVariables _post;
|
||||
Variables _cookie;
|
||||
Variables _get;
|
||||
Variables _post;
|
||||
};
|
||||
|
||||
auto httpRequest::head(const function<bool (const uint8_t*, unsigned)>& callback) const -> bool {
|
||||
auto Request::head(const function<bool (const uint8_t*, unsigned)>& callback) const -> bool {
|
||||
if(!callback) return false;
|
||||
string output;
|
||||
|
||||
@ -79,7 +79,7 @@ auto httpRequest::head(const function<bool (const uint8_t*, unsigned)>& callback
|
||||
return callback(output.binary(), output.size());
|
||||
}
|
||||
|
||||
auto httpRequest::setHead() -> bool {
|
||||
auto Request::setHead() -> bool {
|
||||
lstring headers = _head.split("\n");
|
||||
string request = headers.takeFirst().rtrim("\r");
|
||||
string requestHost;
|
||||
@ -130,7 +130,7 @@ auto httpRequest::setHead() -> bool {
|
||||
return true;
|
||||
}
|
||||
|
||||
auto httpRequest::body(const function<bool (const uint8_t*, unsigned)>& callback) const -> bool {
|
||||
auto Request::body(const function<bool (const uint8_t*, unsigned)>& callback) const -> bool {
|
||||
if(!callback) return false;
|
||||
|
||||
if(_body) {
|
||||
@ -140,7 +140,7 @@ auto httpRequest::body(const function<bool (const uint8_t*, unsigned)>& callback
|
||||
return true;
|
||||
}
|
||||
|
||||
auto httpRequest::setBody() -> bool {
|
||||
auto Request::setBody() -> bool {
|
||||
if(requestType() == RequestType::Post) {
|
||||
if(header("Content-Type").iequals("application/x-www-form-urlencoded")) {
|
||||
for(auto& block : _body.split("&")) {
|
||||
@ -153,6 +153,6 @@ auto httpRequest::setBody() -> bool {
|
||||
return true;
|
||||
}
|
||||
|
||||
}
|
||||
}}
|
||||
|
||||
#endif
|
||||
|
@ -3,13 +3,13 @@
|
||||
|
||||
#include <nall/http/message.hpp>
|
||||
|
||||
namespace nall {
|
||||
namespace nall { namespace HTTP {
|
||||
|
||||
struct httpResponse : httpMessage {
|
||||
using type = httpResponse;
|
||||
struct Response : Message {
|
||||
using type = Response;
|
||||
|
||||
httpResponse() = default;
|
||||
httpResponse(const httpRequest& request) { setRequest(request); }
|
||||
Response() = default;
|
||||
Response(const Request& request) { setRequest(request); }
|
||||
|
||||
explicit operator bool() const { return responseType() != 0; }
|
||||
auto operator()(unsigned responseType) -> type& { return setResponseType(responseType); }
|
||||
@ -20,15 +20,15 @@ struct httpResponse : httpMessage {
|
||||
inline auto body(const function<bool (const uint8_t* data, unsigned size)>& callback) const -> bool;
|
||||
inline auto setBody() -> bool;
|
||||
|
||||
auto request() const -> const httpRequest* { return _request; }
|
||||
auto setRequest(const httpRequest& value) -> type& { _request = &value; return *this; }
|
||||
auto request() const -> const Request* { return _request; }
|
||||
auto setRequest(const Request& value) -> type& { _request = &value; return *this; }
|
||||
|
||||
auto responseType() const -> unsigned { return _responseType; }
|
||||
auto setResponseType(unsigned value) -> type& { _responseType = value; return *this; }
|
||||
|
||||
auto appendHeader(const string& name, const string& value = "") -> type& { return httpMessage::appendHeader(name, value), *this; }
|
||||
auto removeHeader(const string& name) -> type& { return httpMessage::removeHeader(name), *this; }
|
||||
auto setHeader(const string& name, const string& value = "") -> type& { return httpMessage::setHeader(name, value), *this; }
|
||||
auto appendHeader(const string& name, const string& value = "") -> type& { return Message::appendHeader(name, value), *this; }
|
||||
auto removeHeader(const string& name) -> type& { return Message::removeHeader(name), *this; }
|
||||
auto setHeader(const string& name, const string& value = "") -> type& { return Message::setHeader(name, value), *this; }
|
||||
|
||||
auto hasData() const -> bool { return (bool)_data; }
|
||||
auto data() const -> const vector<uint8_t>& { return _data; }
|
||||
@ -49,14 +49,14 @@ struct httpResponse : httpMessage {
|
||||
inline auto findResponseType() const -> string;
|
||||
inline auto setFileETag() -> void;
|
||||
|
||||
const httpRequest* _request = nullptr;
|
||||
const Request* _request = nullptr;
|
||||
unsigned _responseType = 0;
|
||||
vector<uint8_t> _data;
|
||||
string _file;
|
||||
string _text;
|
||||
};
|
||||
|
||||
auto httpResponse::head(const function<bool (const uint8_t*, unsigned)>& callback) const -> bool {
|
||||
auto Response::head(const function<bool (const uint8_t*, unsigned)>& callback) const -> bool {
|
||||
if(!callback) return false;
|
||||
string output;
|
||||
|
||||
@ -91,7 +91,7 @@ auto httpResponse::head(const function<bool (const uint8_t*, unsigned)>& callbac
|
||||
return callback(output.binary(), output.size());
|
||||
}
|
||||
|
||||
auto httpResponse::setHead() -> bool {
|
||||
auto Response::setHead() -> bool {
|
||||
lstring headers = _head.split("\n");
|
||||
string response = headers.takeFirst().rtrim("\r");
|
||||
|
||||
@ -111,7 +111,7 @@ auto httpResponse::setHead() -> bool {
|
||||
return true;
|
||||
}
|
||||
|
||||
auto httpResponse::body(const function<bool (const uint8_t*, unsigned)>& callback) const -> bool {
|
||||
auto Response::body(const function<bool (const uint8_t*, unsigned)>& callback) const -> bool {
|
||||
if(!callback) return false;
|
||||
if(!hasBody()) return true;
|
||||
bool chunked = header("Transfer-Encoding") == "chunked";
|
||||
@ -143,13 +143,13 @@ auto httpResponse::body(const function<bool (const uint8_t*, unsigned)>& callbac
|
||||
return true;
|
||||
}
|
||||
|
||||
auto httpResponse::setBody() -> bool {
|
||||
auto Response::setBody() -> bool {
|
||||
return true;
|
||||
}
|
||||
|
||||
auto httpResponse::hasBody() const -> bool {
|
||||
auto Response::hasBody() const -> bool {
|
||||
if(auto request = this->request()) {
|
||||
if(request->requestType() == httpRequest::RequestType::Head) return false;
|
||||
if(request->requestType() == Request::RequestType::Head) return false;
|
||||
}
|
||||
if(responseType() == 301) return false;
|
||||
if(responseType() == 302) return false;
|
||||
@ -159,7 +159,7 @@ auto httpResponse::hasBody() const -> bool {
|
||||
return true;
|
||||
}
|
||||
|
||||
auto httpResponse::findContentLength() const -> unsigned {
|
||||
auto Response::findContentLength() const -> unsigned {
|
||||
if(auto contentLength = header("Content-Length")) return decimal(contentLength);
|
||||
if(_body) return _body.size();
|
||||
if(hasData()) return data().size();
|
||||
@ -168,14 +168,14 @@ auto httpResponse::findContentLength() const -> unsigned {
|
||||
return findResponseType().size();
|
||||
}
|
||||
|
||||
auto httpResponse::findContentType() const -> string {
|
||||
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());
|
||||
return "text/html; charset=utf-8";
|
||||
}
|
||||
|
||||
auto httpResponse::findContentType(const string& s) const -> string {
|
||||
auto Response::findContentType(const string& s) const -> string {
|
||||
if(s == ".7z" ) return "application/x-7z-compressed";
|
||||
if(s == ".avi" ) return "video/avi";
|
||||
if(s == ".bml" ) return "text/plain; charset=utf-8";
|
||||
@ -209,7 +209,7 @@ auto httpResponse::findContentType(const string& s) const -> string {
|
||||
return "application/octet-stream"; //binary
|
||||
}
|
||||
|
||||
auto httpResponse::findResponseType() const -> string {
|
||||
auto Response::findResponseType() const -> string {
|
||||
switch(responseType()) {
|
||||
case 200: return "200 OK";
|
||||
case 301: return "301 Moved Permanently";
|
||||
@ -227,13 +227,13 @@ auto httpResponse::findResponseType() const -> string {
|
||||
return "501 Not Implemented";
|
||||
}
|
||||
|
||||
auto httpResponse::setData(const vector<uint8_t>& value) -> type& {
|
||||
auto Response::setData(const vector<uint8_t>& value) -> type& {
|
||||
_data = value;
|
||||
setHeader("Content-Length", value.size());
|
||||
return *this;
|
||||
}
|
||||
|
||||
auto httpResponse::setFile(const string& value) -> type& {
|
||||
auto Response::setFile(const string& value) -> type& {
|
||||
_file = value;
|
||||
string eTag = {"\"", string::datetime(file::timestamp(value, file::time::modify)), "\""};
|
||||
setHeader("Content-Length", file::size(value));
|
||||
@ -242,12 +242,12 @@ auto httpResponse::setFile(const string& value) -> type& {
|
||||
return *this;
|
||||
}
|
||||
|
||||
auto httpResponse::setText(const string& value) -> type& {
|
||||
auto Response::setText(const string& value) -> type& {
|
||||
_text = value;
|
||||
setHeader("Content-Length", value.size());
|
||||
return *this;
|
||||
}
|
||||
|
||||
}
|
||||
}}
|
||||
|
||||
#endif
|
||||
|
@ -1,15 +1,15 @@
|
||||
#ifndef NALL_HTTP_ROLE_HPP
|
||||
#define NALL_HTTP_ROLE_HPP
|
||||
|
||||
//httpRole: base class for httpClient and httpServer
|
||||
//Role: base class for Client and Server
|
||||
//provides shared functionality
|
||||
|
||||
#include <nall/http/request.hpp>
|
||||
#include <nall/http/response.hpp>
|
||||
|
||||
namespace nall {
|
||||
namespace nall { namespace HTTP {
|
||||
|
||||
struct httpRole {
|
||||
struct Role {
|
||||
struct Settings {
|
||||
signed connectionLimit = 1024; //server
|
||||
signed headSizeLimit = 16384; //client, server
|
||||
@ -21,11 +21,11 @@ struct httpRole {
|
||||
} settings;
|
||||
|
||||
inline auto configure(const string& parameters) -> bool;
|
||||
inline auto download(signed fd, httpMessage& message) -> bool;
|
||||
inline auto upload(signed fd, const httpMessage& message) -> bool;
|
||||
inline auto download(signed fd, Message& message) -> bool;
|
||||
inline auto upload(signed fd, const Message& message) -> bool;
|
||||
};
|
||||
|
||||
auto httpRole::configure(const string& parameters) -> bool {
|
||||
auto Role::configure(const string& parameters) -> bool {
|
||||
auto document = BML::unserialize(parameters);
|
||||
for(auto parameter : document) {
|
||||
auto name = parameter.name();
|
||||
@ -43,7 +43,7 @@ auto httpRole::configure(const string& parameters) -> bool {
|
||||
return true;
|
||||
}
|
||||
|
||||
auto httpRole::download(signed fd, httpMessage& message) -> bool {
|
||||
auto Role::download(signed fd, Message& message) -> bool {
|
||||
auto& head = message._head;
|
||||
auto& body = message._body;
|
||||
string chunk;
|
||||
@ -112,14 +112,14 @@ auto httpRole::download(signed fd, httpMessage& message) -> bool {
|
||||
|
||||
if(!chunked) {
|
||||
body.resize(body.size() + length);
|
||||
memory::copy(body.pointer() + body.size() - length, p, length);
|
||||
memory::copy(body.get() + body.size() - length, p, length);
|
||||
|
||||
p += length;
|
||||
length = 0;
|
||||
} else {
|
||||
signed transferLength = min(length, chunkLength);
|
||||
body.resize(body.size() + transferLength);
|
||||
memory::copy(body.pointer() + body.size() - transferLength, p, transferLength);
|
||||
memory::copy(body.get() + body.size() - transferLength, p, transferLength);
|
||||
|
||||
p += transferLength;
|
||||
length -= transferLength;
|
||||
@ -136,7 +136,7 @@ auto httpRole::download(signed fd, httpMessage& message) -> bool {
|
||||
return true;
|
||||
}
|
||||
|
||||
auto httpRole::upload(signed fd, const httpMessage& message) -> bool {
|
||||
auto Role::upload(signed fd, const Message& message) -> bool {
|
||||
auto transfer = [&](const uint8_t* data, unsigned size) -> bool {
|
||||
while(size) {
|
||||
signed length = send(fd, data, min(size, settings.chunkSize), MSG_NOSIGNAL);
|
||||
@ -156,6 +156,6 @@ auto httpRole::upload(signed fd, const httpMessage& message) -> bool {
|
||||
return false;
|
||||
}
|
||||
|
||||
}
|
||||
}}
|
||||
|
||||
#endif
|
||||
|
@ -4,17 +4,17 @@
|
||||
#include <nall/service.hpp>
|
||||
#include <nall/http/role.hpp>
|
||||
|
||||
namespace nall {
|
||||
namespace nall { namespace HTTP {
|
||||
|
||||
struct httpServer : httpRole, service {
|
||||
struct Server : Role, service {
|
||||
inline auto open(unsigned port = 8080, const string& serviceName = "", const string& command = "") -> bool;
|
||||
inline auto main(const function<httpResponse (httpRequest&)>& function = {}) -> void;
|
||||
inline auto main(const function<Response (Request&)>& function = {}) -> void;
|
||||
inline auto scan() -> string;
|
||||
inline auto close() -> void;
|
||||
~httpServer() { close(); }
|
||||
~Server() { close(); }
|
||||
|
||||
private:
|
||||
function<httpResponse (httpRequest&)> callback;
|
||||
function<Response (Request&)> callback;
|
||||
std::atomic<signed> connections{0};
|
||||
|
||||
signed fd4 = -1;
|
||||
@ -32,7 +32,7 @@ private:
|
||||
auto ipv6_scan() -> bool;
|
||||
};
|
||||
|
||||
auto httpServer::open(unsigned port, const string& serviceName, const string& command) -> bool {
|
||||
auto Server::open(unsigned port, const string& serviceName, const string& command) -> bool {
|
||||
if(serviceName) {
|
||||
if(!service::command(serviceName, command)) return false;
|
||||
}
|
||||
@ -94,11 +94,11 @@ auto httpServer::open(unsigned port, const string& serviceName, const string& co
|
||||
return ipv4() || ipv6();
|
||||
}
|
||||
|
||||
auto httpServer::main(const function<httpResponse (httpRequest&)>& function) -> void {
|
||||
auto Server::main(const function<Response (Request&)>& function) -> void {
|
||||
callback = function;
|
||||
}
|
||||
|
||||
auto httpServer::scan() -> string {
|
||||
auto Server::scan() -> string {
|
||||
if(auto command = service::receive()) return command;
|
||||
if(connections >= settings.connectionLimit) return "busy";
|
||||
if(ipv4() && ipv4_scan()) return "ok";
|
||||
@ -106,7 +106,7 @@ auto httpServer::scan() -> string {
|
||||
return "idle";
|
||||
}
|
||||
|
||||
auto httpServer::ipv4_scan() -> bool {
|
||||
auto Server::ipv4_scan() -> bool {
|
||||
struct pollfd query = {0};
|
||||
query.fd = fd4;
|
||||
query.events = POLLIN;
|
||||
@ -127,7 +127,7 @@ auto httpServer::ipv4_scan() -> bool {
|
||||
|
||||
uint32_t ip = ntohl(settings.sin_addr.s_addr);
|
||||
|
||||
httpRequest request;
|
||||
Request request;
|
||||
request._ipv6 = false;
|
||||
request._ip = {
|
||||
(uint8_t)(ip >> 24), ".",
|
||||
@ -140,7 +140,7 @@ auto httpServer::ipv4_scan() -> bool {
|
||||
auto response = callback(request);
|
||||
upload(clientfd, response);
|
||||
} else {
|
||||
upload(clientfd, httpResponse()); //"501 Not Implemented"
|
||||
upload(clientfd, Response()); //"501 Not Implemented"
|
||||
}
|
||||
|
||||
::close(clientfd);
|
||||
@ -153,7 +153,7 @@ auto httpServer::ipv4_scan() -> bool {
|
||||
return false;
|
||||
}
|
||||
|
||||
auto httpServer::ipv6_scan() -> bool {
|
||||
auto Server::ipv6_scan() -> bool {
|
||||
struct pollfd query = {0};
|
||||
query.fd = fd6;
|
||||
query.events = POLLIN;
|
||||
@ -172,23 +172,41 @@ auto httpServer::ipv6_scan() -> bool {
|
||||
clientfd = accept(fd6, (struct sockaddr*)&settings, &socklen);
|
||||
if(clientfd < 0) return;
|
||||
|
||||
unsigned char* ip = settings.sin6_addr.s6_addr;
|
||||
uint16_t ipSegment[8] = {0};
|
||||
uint8_t* ip = settings.sin6_addr.s6_addr;
|
||||
uint16_t ipSegment[8];
|
||||
for(auto n : range(8)) ipSegment[n] = ip[n * 2 + 0] * 256 + ip[n * 2 + 1];
|
||||
|
||||
httpRequest request;
|
||||
Request request;
|
||||
request._ipv6 = true;
|
||||
//RFC5952 IPv6 encoding: the first longest 2+ consecutive zero-sequence is compressed to "::"
|
||||
signed zeroOffset = -1;
|
||||
signed zeroLength = 0;
|
||||
signed zeroCounter = 0;
|
||||
for(auto n : range(8)) {
|
||||
uint16_t value = ip[n * 2 + 0] * 256 + ip[n * 2 + 1];
|
||||
request._ip.append(hex(value, 4L));
|
||||
if(n != 7) request._ip.append(":");
|
||||
uint16_t value = ipSegment[n];
|
||||
if(value == 0) zeroCounter++;
|
||||
if(zeroCounter > zeroLength) {
|
||||
zeroLength = zeroCounter;
|
||||
zeroOffset = 1 + n - zeroLength;
|
||||
}
|
||||
if(value != 0) zeroCounter = 0;
|
||||
}
|
||||
if(zeroLength == 1) zeroOffset = -1;
|
||||
for(unsigned n = 0; n < 8;) {
|
||||
if(n == zeroOffset) {
|
||||
request._ip.append(n == 0 ? "::" : ":");
|
||||
n += zeroLength;
|
||||
} else {
|
||||
uint16_t value = ipSegment[n];
|
||||
request._ip.append(hex(value), n++ != 7 ? ":" : "");
|
||||
}
|
||||
}
|
||||
|
||||
if(download(clientfd, request) && callback) {
|
||||
auto response = callback(request);
|
||||
upload(clientfd, response);
|
||||
} else {
|
||||
upload(clientfd, httpResponse()); //"501 Not Implemented"
|
||||
upload(clientfd, Response()); //"501 Not Implemented"
|
||||
}
|
||||
|
||||
::close(clientfd);
|
||||
@ -201,11 +219,11 @@ auto httpServer::ipv6_scan() -> bool {
|
||||
return false;
|
||||
}
|
||||
|
||||
auto httpServer::close() -> void {
|
||||
auto Server::close() -> void {
|
||||
ipv4_close();
|
||||
ipv6_close();
|
||||
}
|
||||
|
||||
}
|
||||
}}
|
||||
|
||||
#endif
|
||||
|
@ -3,10 +3,10 @@
|
||||
|
||||
#include <algorithm>
|
||||
|
||||
#include <nall/bmp.hpp>
|
||||
#include <nall/filemap.hpp>
|
||||
#include <nall/interpolation.hpp>
|
||||
#include <nall/stdint.hpp>
|
||||
#include <nall/decode/bmp.hpp>
|
||||
#include <nall/decode/png.hpp>
|
||||
#include <nall/image/base.hpp>
|
||||
#include <nall/image/static.hpp>
|
||||
|
@ -118,6 +118,7 @@ private:
|
||||
|
||||
//load.hpp
|
||||
inline auto loadBMP(const string& filename) -> bool;
|
||||
inline auto loadBMP(const uint8_t* data, unsigned size) -> bool;
|
||||
inline auto loadPNG(const string& filename) -> bool;
|
||||
inline auto loadPNG(const uint8_t* data, unsigned size) -> bool;
|
||||
|
||||
|
@ -26,11 +26,17 @@ image::image(const string& filename) {
|
||||
}
|
||||
|
||||
image::image(const vector<uint8_t>& buffer) {
|
||||
loadPNG(buffer.data(), buffer.size());
|
||||
auto data = buffer.data();
|
||||
auto size = buffer.size();
|
||||
if(0);
|
||||
else if(data[0] == 'B' && data[1] == 'M') loadBMP(data, size);
|
||||
else if(data[1] == 'P' && data[2] == 'N' && data[3] == 'G') loadPNG(data, size);
|
||||
}
|
||||
|
||||
image::image(const uint8_t* data, unsigned size) {
|
||||
loadPNG(data, size);
|
||||
if(0);
|
||||
else if(data[0] == 'B' && data[1] == 'M') loadBMP(data, size);
|
||||
else if(data[1] == 'P' && data[2] == 'N' && data[3] == 'G') loadPNG(data, size);
|
||||
}
|
||||
|
||||
image::image() {
|
||||
|
@ -4,16 +4,21 @@
|
||||
namespace nall {
|
||||
|
||||
auto image::loadBMP(const string& filename) -> bool {
|
||||
uint32_t* outputData;
|
||||
unsigned outputWidth, outputHeight;
|
||||
if(bmp::read(filename, outputData, outputWidth, outputHeight) == false) return false;
|
||||
if(!file::exists(filename)) return false;
|
||||
auto buffer = file::read(filename);
|
||||
return loadBMP(buffer.data(), buffer.size());
|
||||
}
|
||||
|
||||
allocate(outputWidth, outputHeight);
|
||||
const uint32_t* sp = outputData;
|
||||
auto image::loadBMP(const uint8_t* bmpData, unsigned bmpSize) -> bool {
|
||||
Decode::BMP source;
|
||||
if(!source.load(bmpData, bmpSize)) return false;
|
||||
|
||||
allocate(source.width(), source.height());
|
||||
const uint32_t* sp = source.data();
|
||||
uint8_t* dp = _data;
|
||||
|
||||
for(unsigned y = 0; y < outputHeight; y++) {
|
||||
for(unsigned x = 0; x < outputWidth; x++) {
|
||||
for(unsigned y = 0; y < _height; y++) {
|
||||
for(unsigned x = 0; x < _width; x++) {
|
||||
uint32_t color = *sp++;
|
||||
uint64_t a = normalize((uint8_t)(color >> 24), 8, _alpha.depth());
|
||||
uint64_t r = normalize((uint8_t)(color >> 16), 8, _red.depth());
|
||||
@ -23,9 +28,6 @@ auto image::loadBMP(const string& filename) -> bool {
|
||||
dp += stride();
|
||||
}
|
||||
}
|
||||
|
||||
delete[] outputData;
|
||||
return true;
|
||||
}
|
||||
|
||||
auto image::loadPNG(const string& filename) -> bool {
|
||||
@ -36,7 +38,7 @@ auto image::loadPNG(const string& filename) -> bool {
|
||||
|
||||
auto image::loadPNG(const uint8_t* pngData, unsigned pngSize) -> bool {
|
||||
Decode::PNG source;
|
||||
if(source.decode(pngData, pngSize) == false) return false;
|
||||
if(!source.load(pngData, pngSize)) return false;
|
||||
|
||||
allocate(source.info.width, source.info.height);
|
||||
const uint8_t* sp = source.data;
|
||||
|
161
nall/maybe.hpp
161
nall/maybe.hpp
@ -6,110 +6,87 @@ namespace nall {
|
||||
struct nothing_t {};
|
||||
static nothing_t nothing;
|
||||
|
||||
template<typename T, typename = void>
|
||||
class maybe {
|
||||
T* value = nullptr;
|
||||
template<typename T>
|
||||
struct maybe {
|
||||
inline maybe() {}
|
||||
inline maybe(nothing_t) {}
|
||||
inline maybe(const T& source) { operator=(source); }
|
||||
inline maybe(T&& source) { operator=(move(source)); }
|
||||
inline maybe(const maybe& source) { operator=(source); }
|
||||
inline maybe(maybe&& source) { operator=(move(source)); }
|
||||
inline ~maybe() { reset(); }
|
||||
|
||||
public:
|
||||
maybe() {}
|
||||
maybe(nothing_t) {}
|
||||
maybe(const T& source) { operator=(source); }
|
||||
maybe(const maybe& source) { operator=(source); }
|
||||
maybe(maybe&& source) { operator=(move(source)); }
|
||||
~maybe() { reset(); }
|
||||
inline auto operator=(nothing_t) -> maybe& { reset(); return *this; }
|
||||
inline auto operator=(const T& source) -> maybe& { reset(); _valid = true; new(&_value.t) T(source); return *this; }
|
||||
inline auto operator=(T&& source) -> maybe& { reset(); _valid = true; new(&_value.t) T(move(source)); return *this; }
|
||||
|
||||
auto operator=(nothing_t) -> maybe& { reset(); return *this; }
|
||||
auto operator=(const T& source) -> maybe& { reset(); value = new T(source); return *this; }
|
||||
auto operator=(const maybe& source) -> maybe& { reset(); if(source) value = new T(source()); return *this; }
|
||||
auto operator=(maybe&& source) -> maybe& { reset(); value = source.value; source.value = nullptr; return *this; }
|
||||
|
||||
auto operator==(const maybe& source) const -> bool {
|
||||
if(value && source.value) return *value == *source.value;
|
||||
return !value && !source.value;
|
||||
inline auto operator=(const maybe& source) -> maybe& {
|
||||
if(this == &source) return *this;
|
||||
reset();
|
||||
if(_valid = source._valid) new(&_value.t) T(source.get());
|
||||
return *this;
|
||||
}
|
||||
auto operator!=(const maybe& source) const -> bool { return !operator==(source); }
|
||||
|
||||
explicit operator bool() const { return value; }
|
||||
auto operator->() -> T* { assert(value); return value; }
|
||||
auto operator->() const -> T* { assert(value); return value; }
|
||||
auto operator*() -> T& { assert(value); return *value; }
|
||||
auto operator*() const -> T& { assert(value); return *value; }
|
||||
auto operator()() -> T& { assert(value); return *value; }
|
||||
auto operator()() const -> T& { assert(value); return *value; }
|
||||
auto operator()(const T& invalid) const -> T& { if(value) return *value; return invalid; }
|
||||
inline auto operator=(maybe&& source) -> maybe& {
|
||||
if(this == &source) return *this;
|
||||
reset();
|
||||
if(_valid = source._valid) new(&_value.t) T(move(source.get()));
|
||||
source._valid = false;
|
||||
return *this;
|
||||
}
|
||||
|
||||
auto empty() const -> bool { return value == nullptr; }
|
||||
auto reset() -> void { if(value) { delete value; value = nullptr; } }
|
||||
auto swap(maybe& source) -> void { std::swap(value, source.value); }
|
||||
inline explicit operator bool() const { return _valid; }
|
||||
inline auto reset() -> void { if(_valid) { _value.t.~T(); _valid = false; } }
|
||||
inline auto data() -> T* { return _valid ? &_value.t : nullptr; }
|
||||
inline auto get() -> T& { assert(_valid); return _value.t; }
|
||||
|
||||
inline auto data() const -> const T* { return ((maybe*)this)->data(); }
|
||||
inline auto get() const -> const T& { return ((maybe*)this)->get(); }
|
||||
inline auto operator->() -> T* { return data(); }
|
||||
inline auto operator->() const -> const T* { return data(); }
|
||||
inline auto operator*() -> T& { return get(); }
|
||||
inline auto operator*() const -> const T& { return get(); }
|
||||
inline auto operator()() -> T& { return get(); }
|
||||
inline auto operator()() const -> const T& { return get(); }
|
||||
inline auto operator()(const T& invalid) const -> const T& { return _valid ? get() : invalid; }
|
||||
|
||||
private:
|
||||
union U {
|
||||
T t;
|
||||
U() {}
|
||||
~U() {}
|
||||
} _value;
|
||||
bool _valid = false;
|
||||
};
|
||||
|
||||
template<typename T>
|
||||
class maybe<T&> {
|
||||
T* value = nullptr;
|
||||
struct maybe<T&> {
|
||||
inline maybe() : _value(nullptr) {}
|
||||
inline maybe(nothing_t) : _value(nullptr) {}
|
||||
inline maybe(const T& source) : _value((T*)&source) {}
|
||||
inline maybe(const maybe& source) : _value(source._value) {}
|
||||
|
||||
public:
|
||||
maybe() {}
|
||||
maybe(nothing_t) {}
|
||||
maybe(const T& source) { operator=(source); }
|
||||
maybe(const maybe& source) { operator=(source); }
|
||||
maybe(maybe&& source) { operator=(move(source)); }
|
||||
inline auto operator=(nothing_t) -> maybe& { _value = nullptr; return *this; }
|
||||
inline auto operator=(const T& source) -> maybe& { _value = (T*)&source; return *this; }
|
||||
inline auto operator=(const maybe& source) -> maybe& { _value = source._value; return *this; }
|
||||
|
||||
auto operator=(nothing_t) -> maybe& { value = nullptr; return *this; }
|
||||
auto operator=(const T& source) -> maybe& { value = (T*)&source; return *this; }
|
||||
auto operator=(const maybe& source) -> maybe& { value = source.value; return *this; }
|
||||
auto operator=(maybe&& source) -> maybe& { value = source.value; source.value = nullptr; return *this; }
|
||||
inline explicit operator bool() const { return _value; }
|
||||
inline auto reset() -> void { _value = nullptr; }
|
||||
inline auto data() -> T* { return _value; }
|
||||
inline auto get() -> T& { assert(_value); return *_value; }
|
||||
|
||||
auto operator==(const maybe& source) const -> bool {
|
||||
if(value && source.value) return *value == *source.value;
|
||||
return !value && !source.value;
|
||||
}
|
||||
auto operator!=(const maybe& source) const -> bool { return !operator==(source); }
|
||||
inline auto data() const -> const T* { return ((maybe*)this)->data(); }
|
||||
inline auto get() const -> const T& { return ((maybe*)this)->get(); }
|
||||
inline auto operator->() -> T* { return data(); }
|
||||
inline auto operator->() const -> const T* { return data(); }
|
||||
inline auto operator*() -> T& { return get(); }
|
||||
inline auto operator*() const -> const T& { return get(); }
|
||||
inline auto operator()() -> T& { return get(); }
|
||||
inline auto operator()() const -> const T& { return get(); }
|
||||
inline auto operator()(const T& invalid) const -> const T& { return _value ? get() : invalid; }
|
||||
|
||||
explicit operator bool() const { return value; }
|
||||
auto operator->() -> T* { assert(value); return value; }
|
||||
auto operator->() const -> T* { assert(value); return *value; }
|
||||
auto operator*() -> T& { assert(value); return *value; }
|
||||
auto operator*() const -> T& { assert(value); return *value; }
|
||||
auto operator()() -> T& { assert(value); return *value; }
|
||||
auto operator()() const -> T& { assert(value); return *value; }
|
||||
auto operator()(const T& invalid) const -> T& { if(value) return *value; return invalid; }
|
||||
|
||||
auto empty() const -> bool { return value == nullptr; }
|
||||
auto reset() -> void { value = nullptr; }
|
||||
auto swap(maybe& source) -> void { std::swap(value, source.value); }
|
||||
};
|
||||
|
||||
template<typename T>
|
||||
class maybe<T, enable_if<is_integral<T>>> {
|
||||
T value = 0;
|
||||
bool valid = false;
|
||||
|
||||
public:
|
||||
maybe() {}
|
||||
maybe(nothing_t) {}
|
||||
maybe(const T& source) { operator=(source); }
|
||||
maybe(const maybe& source) { operator=(source); }
|
||||
maybe(maybe&& source) { operator=(move(source)); }
|
||||
|
||||
auto operator=(nothing_t) -> maybe& { valid = false; return *this; }
|
||||
auto operator=(const T& source) -> maybe& { valid = true; value = source; return *this; }
|
||||
auto operator=(const maybe& source) -> maybe& { valid = source.valid; value = source.value; return *this; }
|
||||
auto operator=(maybe&& source) -> maybe& { valid = source.valid; value = source.value; source.valid = false; return *this; }
|
||||
|
||||
auto operator==(const maybe& source) const -> bool {
|
||||
if(valid && source.valid) return value == source.value;
|
||||
return !valid && !source.valid;
|
||||
}
|
||||
auto operator!=(const maybe& source) const -> bool { return !operator==(source); }
|
||||
|
||||
explicit operator bool() const { return valid; }
|
||||
auto operator*() const -> T { assert(valid); return value; }
|
||||
auto operator()() const -> T { assert(valid); return value; }
|
||||
auto operator()(const T& invalid) const -> T { if(valid) return value; return invalid; }
|
||||
|
||||
auto empty() const -> bool { return !valid; }
|
||||
auto reset() -> void { valid = false; }
|
||||
auto swap(maybe& source) -> void { std::swap(valid, source.valid); std::swap(value, source.value); }
|
||||
private:
|
||||
T* _value;
|
||||
};
|
||||
|
||||
}
|
||||
|
@ -1,59 +0,0 @@
|
||||
#ifndef NALL_METHOD_HPP
|
||||
#define NALL_METHOD_HPP
|
||||
|
||||
//provides extension-method and chaining-method support to classes
|
||||
//extension: class(function, params...);
|
||||
//chaining: class[function](params...)[function](params...);
|
||||
|
||||
//usage:
|
||||
//struct object : method<object> {
|
||||
// using method::operator[]; //if object::operator[] defined
|
||||
// using method::operator(); //if object::operator() defined
|
||||
//};
|
||||
|
||||
//note: extension-methods would be obsolete if C++17 introduces unified function call syntax
|
||||
//currently proposed as N4165 and N4174
|
||||
|
||||
namespace nall {
|
||||
|
||||
template<typename T> struct method {
|
||||
template<typename F> struct chain {
|
||||
chain(T& self, const F& f) : self(self), f(f) {}
|
||||
template<typename... P> auto operator()(P&&... p) -> T& {
|
||||
return f(self, forward<P>(p)...), self;
|
||||
}
|
||||
private:
|
||||
T& self;
|
||||
const F& f;
|
||||
};
|
||||
|
||||
template<typename F> struct const_chain {
|
||||
const_chain(const T& self, const F& f) : self(self), f(f) {}
|
||||
template<typename... P> auto operator()(P&&... p) const -> const T& {
|
||||
return f(self, forward<P>(p)...), self;
|
||||
}
|
||||
private:
|
||||
const T& self;
|
||||
const F& f;
|
||||
};
|
||||
|
||||
template<typename F, typename = enable_if<is_function<F>>>
|
||||
auto operator[](const F& f) -> chain<F> { return chain<F>((T&)*this, f); }
|
||||
|
||||
template<typename F, typename = enable_if<is_function<F>>>
|
||||
auto operator[](const F& f) const -> const_chain<F> { return const_chain<F>((const T&)*this, f); }
|
||||
|
||||
template<typename F, typename... P, typename = enable_if<is_function<F>>>
|
||||
auto operator()(const F& f, P&&... p) -> decltype(f((T&)*this, forward<P>(p)...)) {
|
||||
return f((T&)*this, forward<P>(p)...);
|
||||
}
|
||||
|
||||
template<typename F, typename... P, typename = enable_if<is_function<F>>>
|
||||
auto operator()(const F& f, P&&... p) const -> decltype(f((const T&)*this, forward<P>(p)...)) {
|
||||
return f((const T&)*this, forward<P>(p)...);
|
||||
}
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
#endif
|
@ -17,15 +17,14 @@
|
||||
#include <nall/algorithm.hpp>
|
||||
#include <nall/any.hpp>
|
||||
#include <nall/atoi.hpp>
|
||||
#include <nall/base64.hpp>
|
||||
#include <nall/bit.hpp>
|
||||
#include <nall/bitvector.hpp>
|
||||
#include <nall/bmp.hpp>
|
||||
#include <nall/config.hpp>
|
||||
#include <nall/directory.hpp>
|
||||
#include <nall/dl.hpp>
|
||||
#include <nall/endian.hpp>
|
||||
#include <nall/file.hpp>
|
||||
#include <nall/file-system-object.hpp>
|
||||
#include <nall/filemap.hpp>
|
||||
#include <nall/function.hpp>
|
||||
#include <nall/hashset.hpp>
|
||||
@ -46,7 +45,6 @@
|
||||
#include <nall/shared-pointer.hpp>
|
||||
#include <nall/sort.hpp>
|
||||
#include <nall/stdint.hpp>
|
||||
#include <nall/storage.hpp>
|
||||
#include <nall/stream.hpp>
|
||||
#include <nall/string.hpp>
|
||||
#include <nall/thread.hpp>
|
||||
@ -54,12 +52,14 @@
|
||||
#include <nall/utility.hpp>
|
||||
#include <nall/varint.hpp>
|
||||
#include <nall/vector.hpp>
|
||||
#include <nall/decode/base64.hpp>
|
||||
#include <nall/decode/bmp.hpp>
|
||||
#include <nall/decode/gzip.hpp>
|
||||
#include <nall/decode/inflate.hpp>
|
||||
#include <nall/decode/png.hpp>
|
||||
#include <nall/decode/url.hpp>
|
||||
#include <nall/decode/zip.hpp>
|
||||
#include <nall/encode/base64.hpp>
|
||||
#include <nall/hash/crc16.hpp>
|
||||
#include <nall/hash/crc32.hpp>
|
||||
#include <nall/hash/sha256.hpp>
|
||||
|
@ -83,7 +83,7 @@ auto service::receive() -> string {
|
||||
if(auto data = shared.acquire()) {
|
||||
if(*data) {
|
||||
command.resize(4095);
|
||||
memory::copy(command.pointer(), data, 4095);
|
||||
memory::copy(command.get(), data, 4095);
|
||||
memory::fill(data, 4096);
|
||||
}
|
||||
shared.release();
|
||||
|
@ -1,34 +0,0 @@
|
||||
#ifndef NALL_PUBLIC_CAST_HPP
|
||||
#define NALL_PUBLIC_CAST_HPP
|
||||
|
||||
//this is a proof-of-concept-*only* C++ access-privilege elevation exploit.
|
||||
//this code is 100% legal C++, per C++98 section 14.7.2 paragraph 8:
|
||||
//"access checking rules do not apply to names in explicit instantiations."
|
||||
//usage example:
|
||||
|
||||
//struct N { typedef void (Class::*)(); };
|
||||
//template class public_cast<N, &Class::Reference>;
|
||||
//(class.*public_cast<N>::value);
|
||||
|
||||
//Class::Reference may be public, protected or private
|
||||
//Class::Reference may be a function, object or variable
|
||||
|
||||
namespace nall {
|
||||
|
||||
template<typename T, typename T::type... P> struct public_cast;
|
||||
|
||||
template<typename T> struct public_cast<T> {
|
||||
static typename T::type value;
|
||||
};
|
||||
|
||||
template<typename T> typename T::type public_cast<T>::value;
|
||||
|
||||
template<typename T, typename T::type P> struct public_cast<T, P> {
|
||||
static typename T::type value;
|
||||
};
|
||||
|
||||
template<typename T, typename T::type P> typename T::type public_cast<T, P>::value = public_cast<T>::value = P;
|
||||
|
||||
}
|
||||
|
||||
#endif
|
40
nall/set.hpp
40
nall/set.hpp
@ -29,14 +29,27 @@ template<typename T> struct set {
|
||||
node_t* root = nullptr;
|
||||
unsigned nodes = 0;
|
||||
|
||||
auto operator=(const set& source) -> set& { copy(source); return *this; }
|
||||
auto operator=(set&& source) -> set& { move(std::move(source)); return *this; }
|
||||
set() = default;
|
||||
set(const set& source) { operator=(source); }
|
||||
set(set&& source) { operator=(move(source)); }
|
||||
set(std::initializer_list<T> list) { for(auto& value : list) insert(value); }
|
||||
set() = default;
|
||||
~set() { reset(); }
|
||||
|
||||
auto operator=(const set& source) -> set& {
|
||||
reset();
|
||||
copy(root, source.root);
|
||||
nodes = source.nodes;
|
||||
return *this;
|
||||
}
|
||||
|
||||
auto operator=(set&& source) -> set& {
|
||||
root = source.root;
|
||||
nodes = source.nodes;
|
||||
source.root = nullptr;
|
||||
source.nodes = 0;
|
||||
return *this;
|
||||
}
|
||||
|
||||
auto size() const -> unsigned { return nodes; }
|
||||
auto empty() const -> bool { return nodes == 0; }
|
||||
|
||||
@ -63,9 +76,9 @@ template<typename T> struct set {
|
||||
return v->value;
|
||||
}
|
||||
|
||||
template<typename... Args> auto insert(const T& value, Args&&... args) -> bool {
|
||||
template<typename... P> auto insert(const T& value, P&&... p) -> bool {
|
||||
bool result = insert(value);
|
||||
insert(forward<Args>(args)...) | result;
|
||||
insert(forward<P>(p)...) | result;
|
||||
return result;
|
||||
}
|
||||
|
||||
@ -77,9 +90,9 @@ template<typename T> struct set {
|
||||
return size() < count;
|
||||
}
|
||||
|
||||
template<typename... Args> auto remove(const T& value, Args&&... args) -> bool {
|
||||
template<typename... P> auto remove(const T& value, P&&... p) -> bool {
|
||||
bool result = remove(value);
|
||||
return remove(forward<Args>(args)...) | result;
|
||||
return remove(forward<P>(p)...) | result;
|
||||
}
|
||||
|
||||
struct base_iterator {
|
||||
@ -139,12 +152,6 @@ private:
|
||||
node = nullptr;
|
||||
}
|
||||
|
||||
auto copy(const set& source) -> void {
|
||||
reset();
|
||||
copy(root, source.root);
|
||||
nodes = source.nodes;
|
||||
}
|
||||
|
||||
auto copy(node_t*& target, const node_t* source) -> void {
|
||||
if(!source) return;
|
||||
target = new node_t(source->value);
|
||||
@ -153,13 +160,6 @@ private:
|
||||
copy(target->link[1], source->link[1]);
|
||||
}
|
||||
|
||||
auto move(set&& source) -> void {
|
||||
root = source.root;
|
||||
nodes = source.nodes;
|
||||
source.root = nullptr;
|
||||
source.nodes = 0;
|
||||
}
|
||||
|
||||
auto find(node_t* node, const T& value) const -> node_t* {
|
||||
if(node == nullptr) return nullptr;
|
||||
if(node->value == value) return node;
|
||||
|
@ -1,95 +0,0 @@
|
||||
#ifndef NALL_STORAGE_HPP
|
||||
#define NALL_STORAGE_HPP
|
||||
|
||||
//generic abstraction layer for common storage operations against both files and directories
|
||||
//these functions are not recursive; use directory::create() and directory::remove() for recursion
|
||||
|
||||
#include <nall/platform.hpp>
|
||||
#include <nall/string.hpp>
|
||||
|
||||
namespace nall {
|
||||
|
||||
struct storage {
|
||||
enum class time : unsigned { access, modify };
|
||||
|
||||
static auto exists(const string& name) -> bool;
|
||||
static auto readable(const string& name) -> bool;
|
||||
static auto writable(const string& name) -> bool;
|
||||
static auto executable(const string& name) -> bool;
|
||||
static auto uid(const string& name) -> unsigned;
|
||||
static auto gid(const string& name) -> unsigned;
|
||||
static auto mode(const string& name) -> unsigned;
|
||||
static auto timestamp(const string& name, storage::time mode = storage::time::modify) -> time_t;
|
||||
|
||||
static auto create(const string& name, unsigned permissions = 0755) -> bool;
|
||||
static auto rename(const string& name, const string& targetname) -> bool;
|
||||
static auto remove(const string& name) -> bool;
|
||||
};
|
||||
|
||||
inline auto storage::exists(const string& name) -> bool {
|
||||
return access(name, F_OK) == 0;
|
||||
}
|
||||
|
||||
inline auto storage::readable(const string& name) -> bool {
|
||||
return access(name, R_OK) == 0;
|
||||
}
|
||||
|
||||
inline auto storage::writable(const string& name) -> bool {
|
||||
return access(name, W_OK) == 0;
|
||||
}
|
||||
|
||||
inline auto storage::executable(const string& name) -> bool {
|
||||
return access(name, X_OK) == 0;
|
||||
}
|
||||
|
||||
inline auto storage::uid(const string& name) -> unsigned {
|
||||
struct stat data = {0};
|
||||
stat(name, &data);
|
||||
return data.st_uid;
|
||||
}
|
||||
|
||||
inline auto storage::gid(const string& name) -> unsigned {
|
||||
struct stat data = {0};
|
||||
stat(name, &data);
|
||||
return data.st_gid;
|
||||
}
|
||||
|
||||
inline auto storage::mode(const string& name) -> unsigned {
|
||||
struct stat data = {0};
|
||||
stat(name, &data);
|
||||
return data.st_mode;
|
||||
}
|
||||
|
||||
inline auto storage::timestamp(const string& name, storage::time mode) -> time_t {
|
||||
struct stat data = {0};
|
||||
stat(name, &data);
|
||||
switch(mode) {
|
||||
case storage::time::access: return data.st_atime;
|
||||
case storage::time::modify: return data.st_mtime;
|
||||
}
|
||||
throw;
|
||||
}
|
||||
|
||||
//returns true if 'name' already exists
|
||||
inline auto storage::create(const string& name, unsigned permissions) -> bool {
|
||||
if(storage::exists(name)) return true;
|
||||
if(name.endsWith("/")) return mkdir(name, permissions) == 0;
|
||||
int fd = open(name, O_CREAT | O_EXCL, permissions);
|
||||
if(fd < 0) return false;
|
||||
return close(fd), true;
|
||||
}
|
||||
|
||||
//returns false if 'name' and 'targetname' are on different file systems (requires copy)
|
||||
inline auto storage::rename(const string& name, const string& targetname) -> bool {
|
||||
return ::rename(name, targetname) == 0;
|
||||
}
|
||||
|
||||
//returns false if 'name' is a directory that is not empty
|
||||
inline auto storage::remove(const string& name) -> bool {
|
||||
if(name.endsWith("/")) return rmdir(name) == 0;
|
||||
return unlink(name) == 0;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
#endif
|
@ -15,7 +15,6 @@
|
||||
#include <nall/function.hpp>
|
||||
#include <nall/intrinsics.hpp>
|
||||
#include <nall/memory.hpp>
|
||||
#include <nall/method.hpp>
|
||||
#include <nall/shared-pointer.hpp>
|
||||
#include <nall/stdint.hpp>
|
||||
#include <nall/utility.hpp>
|
||||
|
@ -22,7 +22,7 @@ namespace nall {
|
||||
string::string() : _data(nullptr), _capacity(SSO - 1), _size(0) {
|
||||
}
|
||||
|
||||
auto string::pointer() -> char* {
|
||||
auto string::get() -> char* {
|
||||
if(_capacity < SSO) return _text;
|
||||
if(*_refs > 1) _copy();
|
||||
return _data;
|
||||
@ -59,7 +59,7 @@ auto string::reserve(unsigned capacity) -> type& {
|
||||
|
||||
auto string::resize(unsigned size) -> type& {
|
||||
reserve(size);
|
||||
pointer()[_size = size] = 0;
|
||||
get()[_size = size] = 0;
|
||||
return *this;
|
||||
}
|
||||
|
||||
|
@ -5,7 +5,7 @@ namespace nall {
|
||||
string::string() : _data(nullptr), _refs(nullptr), _capacity(0), _size(0) {
|
||||
}
|
||||
|
||||
auto string::pointer() -> char* {
|
||||
auto string::get() -> char* {
|
||||
static char _null[] = "";
|
||||
if(!_data) return _null;
|
||||
if(*_refs > 1) _data = _copy(); //make unique for write operations
|
||||
@ -38,7 +38,7 @@ auto string::reserve(unsigned capacity) -> type& {
|
||||
|
||||
auto string::resize(unsigned size) -> type& {
|
||||
reserve(size);
|
||||
pointer()[_size = size] = 0;
|
||||
get()[_size = size] = 0;
|
||||
return *this;
|
||||
}
|
||||
|
||||
|
@ -26,7 +26,7 @@ string::string() {
|
||||
_size = 0;
|
||||
}
|
||||
|
||||
auto string::pointer() -> char* {
|
||||
auto string::get() -> char* {
|
||||
if(_capacity < SSO) return _text;
|
||||
return _data;
|
||||
}
|
||||
@ -60,7 +60,7 @@ auto string::reserve(unsigned capacity) -> type& {
|
||||
|
||||
auto string::resize(unsigned size) -> type& {
|
||||
reserve(size);
|
||||
pointer()[_size = size] = 0;
|
||||
get()[_size = size] = 0;
|
||||
return *this;
|
||||
}
|
||||
|
||||
|
@ -19,7 +19,7 @@ cons:
|
||||
|
||||
namespace nall {
|
||||
|
||||
auto string::pointer() -> char* {
|
||||
auto string::get() -> char* {
|
||||
if(_capacity == 0) reserve(1);
|
||||
return _data;
|
||||
}
|
||||
@ -47,7 +47,7 @@ auto string::reserve(unsigned capacity) -> type& {
|
||||
|
||||
auto string::resize(unsigned size) -> type& {
|
||||
reserve(size);
|
||||
pointer()[_size = size] = 0;
|
||||
get()[_size = size] = 0;
|
||||
return *this;
|
||||
}
|
||||
|
||||
|
@ -182,7 +182,7 @@ protected:
|
||||
|
||||
public:
|
||||
inline string();
|
||||
inline auto pointer() -> char*;
|
||||
inline auto get() -> char*;
|
||||
inline auto data() const -> const char*;
|
||||
inline auto reset() -> type&;
|
||||
inline auto reserve(unsigned) -> type&;
|
||||
@ -214,8 +214,8 @@ public:
|
||||
string(const string& source) : string() { operator=(source); }
|
||||
string(string&& source) : string() { operator=(std::move(source)); }
|
||||
|
||||
auto begin() -> char* { return &pointer()[0]; }
|
||||
auto end() -> char* { return &pointer()[size()]; }
|
||||
auto begin() -> char* { return &get()[0]; }
|
||||
auto end() -> char* { return &get()[size()]; }
|
||||
auto begin() const -> const char* { return &data()[0]; }
|
||||
auto end() const -> const char* { return &data()[size()]; }
|
||||
|
||||
|
@ -3,7 +3,7 @@
|
||||
namespace nall {
|
||||
|
||||
auto downcase(string& self) -> string& {
|
||||
char* p = self.pointer();
|
||||
char* p = self.get();
|
||||
for(unsigned n = 0; n < self.size(); n++) {
|
||||
if(p[n] >= 'A' && p[n] <= 'Z') p[n] += 0x20;
|
||||
}
|
||||
@ -11,7 +11,7 @@ auto downcase(string& self) -> string& {
|
||||
}
|
||||
|
||||
auto qdowncase(string& self) -> string& {
|
||||
char* p = self.pointer();
|
||||
char* p = self.get();
|
||||
for(unsigned n = 0, quoted = 0; n < self.size(); n++) {
|
||||
if(p[n] == '\"') quoted ^= 1;
|
||||
if(!quoted && p[n] >= 'A' && p[n] <= 'Z') p[n] += 0x20;
|
||||
@ -20,7 +20,7 @@ auto qdowncase(string& self) -> string& {
|
||||
}
|
||||
|
||||
auto upcase(string& self) -> string& {
|
||||
char* p = self.pointer();
|
||||
char* p = self.get();
|
||||
for(unsigned n = 0; n < self.size(); n++) {
|
||||
if(p[n] >= 'a' && p[n] <= 'z') p[n] -= 0x20;
|
||||
}
|
||||
@ -28,7 +28,7 @@ auto upcase(string& self) -> string& {
|
||||
}
|
||||
|
||||
auto qupcase(string& self) -> string& {
|
||||
char* p = self.pointer();
|
||||
char* p = self.get();
|
||||
for(unsigned n = 0, quoted = 0; n < self.size(); n++) {
|
||||
if(p[n] == '\"') quoted ^= 1;
|
||||
if(!quoted && p[n] >= 'a' && p[n] <= 'z') p[n] -= 0x20;
|
||||
@ -38,7 +38,7 @@ auto qupcase(string& self) -> string& {
|
||||
|
||||
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.pointer();
|
||||
char* p = self.get();
|
||||
for(unsigned n = 0; n < self.size(); n++) {
|
||||
for(unsigned s = 0; s < from.size(); s++) {
|
||||
if(p[n] == from[s]) {
|
||||
|
@ -43,7 +43,7 @@ template<typename T> auto _append(string& self, const stringify<T>& source) -> s
|
||||
unsigned size = self.size();
|
||||
unsigned length = source.size();
|
||||
self.resize(size + length);
|
||||
memory::copy(self.pointer() + size, source.data(), length);
|
||||
memory::copy(self.get() + size, source.data(), length);
|
||||
return self;
|
||||
}
|
||||
|
||||
|
@ -54,7 +54,7 @@ auto string::format(const nall::format& params) -> type& {
|
||||
}
|
||||
|
||||
resize(size);
|
||||
memory::copy(pointer(), data, size);
|
||||
memory::copy(get(), data, size);
|
||||
memory::free(data);
|
||||
return *this;
|
||||
}
|
||||
@ -76,7 +76,7 @@ template<typename... P> auto print(P&&... p) -> void {
|
||||
auto integer(intmax_t value, long precision, char padchar) -> string {
|
||||
string buffer;
|
||||
buffer.resize(1 + sizeof(intmax_t) * 3);
|
||||
char* p = buffer.pointer();
|
||||
char* p = buffer.get();
|
||||
|
||||
bool negative = value < 0;
|
||||
value = abs(value);
|
||||
@ -95,7 +95,7 @@ auto integer(intmax_t value, long precision, char padchar) -> string {
|
||||
auto decimal(uintmax_t value, long precision, char padchar) -> string {
|
||||
string buffer;
|
||||
buffer.resize(sizeof(uintmax_t) * 3);
|
||||
char* p = buffer.pointer();
|
||||
char* p = buffer.get();
|
||||
|
||||
unsigned size = 0;
|
||||
do {
|
||||
@ -111,7 +111,7 @@ auto decimal(uintmax_t value, long precision, char padchar) -> string {
|
||||
auto hex(uintmax_t value, long precision, char padchar) -> string {
|
||||
string buffer;
|
||||
buffer.resize(sizeof(uintmax_t) * 2);
|
||||
char* p = buffer.pointer();
|
||||
char* p = buffer.get();
|
||||
|
||||
unsigned size = 0;
|
||||
do {
|
||||
@ -128,7 +128,7 @@ auto hex(uintmax_t value, long precision, char padchar) -> string {
|
||||
auto octal(uintmax_t value, long precision, char padchar) -> string {
|
||||
string buffer;
|
||||
buffer.resize(sizeof(uintmax_t) * 3);
|
||||
char* p = buffer.pointer();
|
||||
char* p = buffer.get();
|
||||
|
||||
unsigned size = 0;
|
||||
do {
|
||||
@ -144,7 +144,7 @@ auto octal(uintmax_t value, long precision, char padchar) -> string {
|
||||
auto binary(uintmax_t value, long precision, char padchar) -> string {
|
||||
string buffer;
|
||||
buffer.resize(sizeof(uintmax_t) * 8);
|
||||
char* p = buffer.pointer();
|
||||
char* p = buffer.get();
|
||||
|
||||
unsigned size = 0;
|
||||
do {
|
||||
@ -170,7 +170,7 @@ auto pointer(uintptr_t value, long precision) -> string {
|
||||
auto real(long double value) -> string {
|
||||
string temp;
|
||||
temp.resize(real(nullptr, value));
|
||||
real(temp.pointer(), value);
|
||||
real(temp.get(), value);
|
||||
return temp;
|
||||
}
|
||||
|
||||
|
@ -109,7 +109,7 @@ protected:
|
||||
auto parse(string document) -> void {
|
||||
//in order to simplify the parsing logic; we do an initial pass to normalize the data
|
||||
//the below code will turn '\r\n' into '\n'; skip empty lines; and skip comment lines
|
||||
char* p = document.pointer(), *output = p;
|
||||
char* p = document.get(), *output = p;
|
||||
while(*p) {
|
||||
char* origin = p;
|
||||
bool empty = true;
|
||||
|
@ -52,7 +52,7 @@ protected:
|
||||
return;
|
||||
#endif
|
||||
|
||||
char* output = target.pointer();
|
||||
char* output = target.get();
|
||||
while(length) {
|
||||
if(*source == '&') {
|
||||
if(!memory::compare(source, "<", 4)) { *output++ = '<'; source += 4; length -= 4; continue; }
|
||||
|
@ -48,10 +48,11 @@ auto basename(const string& self) -> string {
|
||||
// /parent/child.type/(name).type
|
||||
auto prefixname(const string& self) -> string {
|
||||
const char* p = self.data() + self.size() - 1, *last = p;
|
||||
for(signed offset = self.size() - 1, suffix = 0; offset >= 0; offset--, p--) {
|
||||
for(signed offset = self.size() - 1, suffix = -1; offset >= 0; offset--, p--) {
|
||||
if(*p == '/' && p == last) continue;
|
||||
if(*p == '/') return slice(self, offset + 1, suffix ? suffix - offset - 1 : 0).rtrim("/");
|
||||
if(*p == '.' && suffix == 0) suffix = offset;
|
||||
if(*p == '/') return slice(self, offset + 1, suffix >= 0 ? suffix - offset - 1 : 0).rtrim("/");
|
||||
if(*p == '.' && suffix == -1) { suffix = offset; continue; }
|
||||
if(offset == 0) return slice(self, offset, suffix).rtrim("/");
|
||||
}
|
||||
return "";
|
||||
}
|
||||
|
@ -25,7 +25,7 @@ auto _replace(string& self, rstring from, rstring to, long limit) -> string& {
|
||||
|
||||
//in-place overwrite
|
||||
if(to.size() == from.size()) {
|
||||
char* p = self.pointer();
|
||||
char* p = self.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.pointer();
|
||||
char* p = self.get();
|
||||
signed offset = 0;
|
||||
signed base = 0;
|
||||
|
||||
@ -64,7 +64,7 @@ auto _replace(string& self, rstring from, rstring to, long limit) -> string& {
|
||||
//right-to-left expand
|
||||
else if(to.size() > from.size()) {
|
||||
self.resize(size + matches * (to.size() - from.size()));
|
||||
char* p = self.pointer();
|
||||
char* p = self.get();
|
||||
|
||||
signed offset = self.size();
|
||||
signed base = size;
|
||||
|
@ -18,7 +18,7 @@ template<bool Insensitive, bool Quoted> auto _split(lstring& self, rstring sourc
|
||||
|
||||
string& s = self(matches);
|
||||
s.resize(n - base);
|
||||
memory::copy(s.pointer(), p + base, n - base);
|
||||
memory::copy(s.get(), p + base, n - base);
|
||||
|
||||
n += find.size();
|
||||
base = n;
|
||||
@ -27,7 +27,7 @@ template<bool Insensitive, bool Quoted> auto _split(lstring& self, rstring sourc
|
||||
|
||||
string& s = self(matches);
|
||||
s.resize(size - base);
|
||||
memory::copy(s.pointer(), p + base, size - base);
|
||||
memory::copy(s.get(), p + base, size - base);
|
||||
|
||||
return self;
|
||||
}
|
||||
|
@ -18,7 +18,7 @@ auto string::read(const string& filename) -> string {
|
||||
|
||||
rewind(fp);
|
||||
result.resize(filesize);
|
||||
fread(result.pointer(), 1, filesize, fp);
|
||||
auto unused = fread(result.get(), 1, filesize, fp);
|
||||
return fclose(fp), result;
|
||||
}
|
||||
|
||||
@ -29,7 +29,7 @@ auto string::repeat(const string& pattern, unsigned times) -> string {
|
||||
}
|
||||
|
||||
auto fill(string& self, char fill) -> string& {
|
||||
memory::fill(self.pointer(), self.size(), fill);
|
||||
memory::fill(self.get(), self.size(), fill);
|
||||
return self;
|
||||
}
|
||||
|
||||
@ -42,14 +42,14 @@ auto hash(const string& self) -> unsigned {
|
||||
}
|
||||
|
||||
auto remove(string& self, unsigned offset, unsigned length) -> string& {
|
||||
char* p = self.pointer();
|
||||
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 reverse(string& self) -> string& {
|
||||
char* p = self.pointer();
|
||||
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]);
|
||||
@ -67,13 +67,13 @@ auto size(string& self, signed length, char fill) -> string& {
|
||||
|
||||
if(size < length) { //expand
|
||||
self.resize(length);
|
||||
char* p = self.pointer();
|
||||
char* p = self.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.pointer();
|
||||
char* p = self.get();
|
||||
unsigned displacement = size - length;
|
||||
if(right) memory::move(p, p + displacement, length);
|
||||
self.resize(length);
|
||||
@ -87,7 +87,7 @@ auto slice(const string& self, signed offset, signed length) -> string {
|
||||
if(offset < self.size()) {
|
||||
if(length < 0) length = self.size() - offset;
|
||||
result.resize(length);
|
||||
memory::copy(result.pointer(), self.data() + offset, length);
|
||||
memory::copy(result.get(), self.data() + offset, length);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
@ -97,7 +97,7 @@ auto substr(rstring source, signed offset, signed length) -> string {
|
||||
string result;
|
||||
if(length < 0) length = source.size() - offset;
|
||||
result.resize(length);
|
||||
memory::copy(result.pointer(), source.data() + offset, length);
|
||||
memory::copy(result.get(), source.data() + offset, length);
|
||||
return result;
|
||||
}
|
||||
|
||||
|
@ -26,9 +26,9 @@ struct varint {
|
||||
|
||||
auto readvs() -> intmax_t {
|
||||
uintmax_t data = readvu();
|
||||
bool sign = data & 1;
|
||||
bool negate = data & 1;
|
||||
data >>= 1;
|
||||
if(sign) data = -data;
|
||||
if(negate) data = ~data;
|
||||
return data;
|
||||
}
|
||||
|
||||
@ -43,9 +43,9 @@ struct varint {
|
||||
}
|
||||
|
||||
auto writevs(intmax_t data) -> void {
|
||||
bool sign = data < 0;
|
||||
if(sign) data = -data;
|
||||
data = (data << 1) | sign;
|
||||
bool negate = data < 0;
|
||||
if(negate) data = ~data;
|
||||
data = (data << 1) | negate;
|
||||
writevu(data);
|
||||
}
|
||||
};
|
||||
|
@ -13,15 +13,15 @@ inline string guid() {
|
||||
for(unsigned n = 0; n < 256; n++) lfsr();
|
||||
|
||||
string output;
|
||||
for(unsigned n = 0; n < 4; n++) output.append(hex<2>(lfsr()));
|
||||
for(unsigned n = 0; n < 4; n++) output.append(hex(lfsr(), 2L));
|
||||
output.append("-");
|
||||
for(unsigned n = 0; n < 2; n++) output.append(hex<2>(lfsr()));
|
||||
for(unsigned n = 0; n < 2; n++) output.append(hex(lfsr(), 2L));
|
||||
output.append("-");
|
||||
for(unsigned n = 0; n < 2; n++) output.append(hex<2>(lfsr()));
|
||||
for(unsigned n = 0; n < 2; n++) output.append(hex(lfsr(), 2L));
|
||||
output.append("-");
|
||||
for(unsigned n = 0; n < 2; n++) output.append(hex<2>(lfsr()));
|
||||
for(unsigned n = 0; n < 2; n++) output.append(hex(lfsr(), 2L));
|
||||
output.append("-");
|
||||
for(unsigned n = 0; n < 6; n++) output.append(hex<2>(lfsr()));
|
||||
for(unsigned n = 0; n < 6; n++) output.append(hex(lfsr(), 2L));
|
||||
return {"{", output, "}"};
|
||||
}
|
||||
|
||||
|
@ -514,11 +514,15 @@ auto ARM::arm_op_move_multiple() {
|
||||
if(pre == 1 && up == 0) rn = rn - bit::count(list) * 4 + 0; //DB
|
||||
if(pre == 0 && up == 0) rn = rn - bit::count(list) * 4 + 4; //DA
|
||||
|
||||
if(writeback && l == 1) {
|
||||
if(up == 1) r(n) = r(n) + bit::count(list) * 4; //IA, IB
|
||||
if(up == 0) r(n) = r(n) - bit::count(list) * 4; //DA, DB
|
||||
}
|
||||
|
||||
Processor::Mode pmode = mode();
|
||||
bool usr = false;
|
||||
if(s && l == 1 && (list & 0x8000) == 0) usr = true;
|
||||
if(s && l == 0) usr = true;
|
||||
|
||||
if(usr) processor.setMode(Processor::Mode::USR);
|
||||
|
||||
unsigned sequential = Nonsequential;
|
||||
@ -545,7 +549,7 @@ auto ARM::arm_op_move_multiple() {
|
||||
pipeline.nonsequential = true;
|
||||
}
|
||||
|
||||
if(writeback) {
|
||||
if(writeback && l == 0) {
|
||||
if(up == 1) r(n) = r(n) + bit::count(list) * 4; //IA, IB
|
||||
if(up == 0) r(n) = r(n) - bit::count(list) * 4; //DA, DB
|
||||
}
|
||||
|
@ -107,7 +107,7 @@ struct InputJoypadUdev {
|
||||
play.type = EV_FF;
|
||||
play.code = jp.effectID;
|
||||
play.value = enable;
|
||||
write(jp.fd, &play, sizeof(input_event));
|
||||
auto unused = write(jp.fd, &play, sizeof(input_event));
|
||||
return true;
|
||||
}
|
||||
|
||||
|
@ -2,7 +2,7 @@ sfc_objects := sfc-interface sfc-system sfc-controller
|
||||
sfc_objects += sfc-cartridge sfc-cheat
|
||||
sfc_objects += sfc-memory sfc-cpu sfc-smp sfc-dsp sfc-ppu
|
||||
sfc_objects += sfc-satellaviewbase
|
||||
sfc_objects += sfc-icd2 sfc-bsx sfc-nss sfc-event
|
||||
sfc_objects += sfc-icd2 sfc-mcc sfc-nss sfc-event
|
||||
sfc_objects += sfc-sa1 sfc-superfx
|
||||
sfc_objects += sfc-armdsp sfc-hitachidsp sfc-necdsp
|
||||
sfc_objects += sfc-epsonrtc sfc-sharprtc
|
||||
@ -47,7 +47,7 @@ obj/sfc-ppu.o: $(sfcppu)/ppu.cpp $(call rwildcard,$(sfcppu)/)
|
||||
obj/sfc-satellaviewbase.o: $(sfc)/base/satellaview/satellaview.cpp $(call rwildcard,$(sfc)/base/satellaview/)
|
||||
|
||||
obj/sfc-icd2.o: $(sfc)/chip/icd2/icd2.cpp $(call rwildcard,$(sfc)/chip/icd2/)
|
||||
obj/sfc-bsx.o: $(sfc)/chip/bsx/bsx.cpp $(call rwildcard,$(sfc)/chip/bsx/)
|
||||
obj/sfc-mcc.o: $(sfc)/chip/mcc/mcc.cpp $(call rwildcard,$(sfc)/chip/mcc/)
|
||||
obj/sfc-nss.o: $(sfc)/chip/nss/nss.cpp $(call rwildcard,$(sfc)/chip/nss/)
|
||||
obj/sfc-event.o: $(sfc)/chip/event/event.cpp $(call rwildcard,$(sfc)/chip/event/)
|
||||
|
||||
|
@ -5,10 +5,10 @@ namespace SuperFamicom {
|
||||
|
||||
SatellaviewBaseUnit satellaviewbaseunit;
|
||||
|
||||
void SatellaviewBaseUnit::init() {
|
||||
auto SatellaviewBaseUnit::init() -> void {
|
||||
}
|
||||
|
||||
void SatellaviewBaseUnit::load() {
|
||||
auto SatellaviewBaseUnit::load() -> void {
|
||||
bus.map(
|
||||
{&SatellaviewBaseUnit::read, &satellaviewbaseunit},
|
||||
{&SatellaviewBaseUnit::write, &satellaviewbaseunit},
|
||||
@ -21,17 +21,17 @@ void SatellaviewBaseUnit::load() {
|
||||
);
|
||||
}
|
||||
|
||||
void SatellaviewBaseUnit::unload() {
|
||||
auto SatellaviewBaseUnit::unload() -> void {
|
||||
}
|
||||
|
||||
void SatellaviewBaseUnit::power() {
|
||||
auto SatellaviewBaseUnit::power() -> void {
|
||||
}
|
||||
|
||||
void SatellaviewBaseUnit::reset() {
|
||||
auto SatellaviewBaseUnit::reset() -> void {
|
||||
memset(®s, 0x00, sizeof regs);
|
||||
}
|
||||
|
||||
uint8 SatellaviewBaseUnit::read(unsigned addr) {
|
||||
auto SatellaviewBaseUnit::read(unsigned addr) -> uint8 {
|
||||
addr &= 0xffff;
|
||||
|
||||
switch(addr) {
|
||||
@ -89,7 +89,7 @@ uint8 SatellaviewBaseUnit::read(unsigned addr) {
|
||||
return cpu.regs.mdr;
|
||||
}
|
||||
|
||||
void SatellaviewBaseUnit::write(unsigned addr, uint8 data) {
|
||||
auto SatellaviewBaseUnit::write(unsigned addr, uint8 data) -> void {
|
||||
addr &= 0xffff;
|
||||
|
||||
switch(addr) {
|
||||
|
@ -1,12 +1,12 @@
|
||||
struct SatellaviewBaseUnit : Memory {
|
||||
void init();
|
||||
void load();
|
||||
void unload();
|
||||
void power();
|
||||
void reset();
|
||||
auto init() -> void;
|
||||
auto load() -> void;
|
||||
auto unload() -> void;
|
||||
auto power() -> void;
|
||||
auto reset() -> void;
|
||||
|
||||
uint8 read(unsigned addr);
|
||||
void write(unsigned addr, uint8 data);
|
||||
auto read(unsigned addr) -> uint8;
|
||||
auto write(unsigned addr, uint8 data) -> void;
|
||||
|
||||
private:
|
||||
struct {
|
||||
|
@ -7,7 +7,7 @@ namespace SuperFamicom {
|
||||
#include "serialization.cpp"
|
||||
Cartridge cartridge;
|
||||
|
||||
string Cartridge::title() {
|
||||
auto Cartridge::title() -> string {
|
||||
if(information.title.gameBoy.empty() == false) {
|
||||
return {information.title.cartridge, " + ", information.title.gameBoy};
|
||||
}
|
||||
@ -27,27 +27,28 @@ string Cartridge::title() {
|
||||
return information.title.cartridge;
|
||||
}
|
||||
|
||||
void Cartridge::load() {
|
||||
region = Region::NTSC;
|
||||
auto Cartridge::load() -> void {
|
||||
_region = Region::NTSC;
|
||||
|
||||
has_gb_slot = false;
|
||||
has_bs_cart = false;
|
||||
has_bs_slot = false;
|
||||
has_st_slots = false;
|
||||
has_nss_dip = false;
|
||||
has_event = false;
|
||||
has_sa1 = false;
|
||||
has_superfx = false;
|
||||
has_armdsp = false;
|
||||
has_hitachidsp = false;
|
||||
has_necdsp = false;
|
||||
has_epsonrtc = false;
|
||||
has_sharprtc = false;
|
||||
has_spc7110 = false;
|
||||
has_sdd1 = false;
|
||||
has_obc1 = false;
|
||||
has_hsu1 = false;
|
||||
has_msu1 = false;
|
||||
hasICD2 = false;
|
||||
hasMCC = false;
|
||||
hasNSSDIP = false;
|
||||
hasEvent = false;
|
||||
hasSA1 = false;
|
||||
hasSuperFX = false;
|
||||
hasARMDSP = false;
|
||||
hasHitachiDSP = false;
|
||||
hasNECDSP = false;
|
||||
hasEpsonRTC = false;
|
||||
hasSharpRTC = false;
|
||||
hasSPC7110 = false;
|
||||
hasSDD1 = false;
|
||||
hasOBC1 = false;
|
||||
hasMSU1 = false;
|
||||
|
||||
hasSuperGameBoySlot = false;
|
||||
hasSatellaviewSlot = false;
|
||||
hasSufamiTurboSlots = false;
|
||||
|
||||
information.markup.cartridge = "";
|
||||
information.markup.gameBoy = "";
|
||||
@ -62,24 +63,24 @@ void Cartridge::load() {
|
||||
information.title.sufamiTurboB = "";
|
||||
|
||||
interface->loadRequest(ID::Manifest, "manifest.bml");
|
||||
parse_markup(information.markup.cartridge);
|
||||
parseMarkup(information.markup.cartridge);
|
||||
|
||||
//Super Game Boy
|
||||
if(cartridge.has_gb_slot()) {
|
||||
sha256 = Hash::SHA256(GameBoy::cartridge.romdata, GameBoy::cartridge.romsize).digest();
|
||||
if(cartridge.hasICD2()) {
|
||||
_sha256 = Hash::SHA256(GameBoy::cartridge.romdata, GameBoy::cartridge.romsize).digest();
|
||||
}
|
||||
|
||||
//Broadcast Satellaview
|
||||
else if(cartridge.has_bs_cart() && cartridge.has_bs_slot()) {
|
||||
sha256 = Hash::SHA256(satellaviewcartridge.memory.data(), satellaviewcartridge.memory.size()).digest();
|
||||
else if(cartridge.hasMCC() && cartridge.hasSatellaviewSlot()) {
|
||||
_sha256 = Hash::SHA256(satellaviewcartridge.memory.data(), satellaviewcartridge.memory.size()).digest();
|
||||
}
|
||||
|
||||
//Sufami Turbo
|
||||
else if(cartridge.has_st_slots()) {
|
||||
else if(cartridge.hasSufamiTurboSlots()) {
|
||||
Hash::SHA256 sha;
|
||||
sha.data(sufamiturboA.rom.data(), sufamiturboA.rom.size());
|
||||
sha.data(sufamiturboB.rom.data(), sufamiturboB.rom.size());
|
||||
sha256 = sha.digest();
|
||||
_sha256 = sha.digest();
|
||||
}
|
||||
|
||||
//Super Famicom
|
||||
@ -87,7 +88,7 @@ void Cartridge::load() {
|
||||
Hash::SHA256 sha;
|
||||
//hash each ROM image that exists; any with size() == 0 is ignored by sha256_chunk()
|
||||
sha.data(rom.data(), rom.size());
|
||||
sha.data(bsxcartridge.rom.data(), bsxcartridge.rom.size());
|
||||
sha.data(mcc.rom.data(), mcc.rom.size());
|
||||
sha.data(sa1.rom.data(), sa1.rom.size());
|
||||
sha.data(superfx.rom.data(), superfx.rom.size());
|
||||
sha.data(hitachidsp.rom.data(), hitachidsp.rom.size());
|
||||
@ -103,17 +104,17 @@ void Cartridge::load() {
|
||||
buffer = necdsp.firmware();
|
||||
sha.data(buffer.data(), buffer.size());
|
||||
//finalize hash
|
||||
sha256 = sha.digest();
|
||||
_sha256 = sha.digest();
|
||||
}
|
||||
|
||||
rom.write_protect(true);
|
||||
ram.write_protect(false);
|
||||
|
||||
system.load();
|
||||
loaded = true;
|
||||
_loaded = true;
|
||||
}
|
||||
|
||||
void Cartridge::load_super_game_boy() {
|
||||
auto Cartridge::loadSuperGameBoy() -> void {
|
||||
interface->loadRequest(ID::SuperGameBoyManifest, "manifest.bml");
|
||||
auto document = BML::unserialize(information.markup.gameBoy);
|
||||
information.title.gameBoy = document["information/title"].text();
|
||||
@ -129,7 +130,7 @@ void Cartridge::load_super_game_boy() {
|
||||
if(auto name = ram["name"].text()) memory.append({ID::SuperGameBoyRAM, name});
|
||||
}
|
||||
|
||||
void Cartridge::load_satellaview() {
|
||||
auto Cartridge::loadSatellaview() -> void {
|
||||
interface->loadRequest(ID::SatellaviewManifest, "manifest.bml");
|
||||
auto document = BML::unserialize(information.markup.satellaview);
|
||||
information.title.satellaview = document["information/title"].text();
|
||||
@ -145,7 +146,7 @@ void Cartridge::load_satellaview() {
|
||||
}
|
||||
}
|
||||
|
||||
void Cartridge::load_sufami_turbo_a() {
|
||||
auto Cartridge::loadSufamiTurboA() -> void {
|
||||
interface->loadRequest(ID::SufamiTurboSlotAManifest, "manifest.bml");
|
||||
auto document = BML::unserialize(information.markup.sufamiTurboA);
|
||||
information.title.sufamiTurboA = document["information/title"].text();
|
||||
@ -171,7 +172,7 @@ void Cartridge::load_sufami_turbo_a() {
|
||||
}
|
||||
}
|
||||
|
||||
void Cartridge::load_sufami_turbo_b() {
|
||||
auto Cartridge::loadSufamiTurboB() -> void {
|
||||
interface->loadRequest(ID::SufamiTurboSlotBManifest, "manifest.bml");
|
||||
auto document = BML::unserialize(information.markup.sufamiTurboB);
|
||||
information.title.sufamiTurboB = document["information/title"].text();
|
||||
@ -193,23 +194,15 @@ void Cartridge::load_sufami_turbo_b() {
|
||||
}
|
||||
}
|
||||
|
||||
void Cartridge::unload() {
|
||||
if(loaded == false) return;
|
||||
auto Cartridge::unload() -> void {
|
||||
if(_loaded) {
|
||||
system.unload();
|
||||
rom.reset();
|
||||
ram.reset();
|
||||
|
||||
system.unload();
|
||||
rom.reset();
|
||||
ram.reset();
|
||||
|
||||
loaded = false;
|
||||
memory.reset();
|
||||
}
|
||||
|
||||
Cartridge::Cartridge() {
|
||||
loaded = false;
|
||||
}
|
||||
|
||||
Cartridge::~Cartridge() {
|
||||
unload();
|
||||
_loaded = false;
|
||||
memory.reset();
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -1,54 +1,42 @@
|
||||
struct Cartridge : property<Cartridge> {
|
||||
enum class Region : unsigned {
|
||||
NTSC,
|
||||
PAL,
|
||||
};
|
||||
|
||||
enum class Slot : unsigned {
|
||||
Base,
|
||||
Bsx,
|
||||
SufamiTurbo,
|
||||
SufamiTurboA,
|
||||
SufamiTurboB,
|
||||
GameBoy,
|
||||
};
|
||||
enum class Region : unsigned { NTSC, PAL };
|
||||
|
||||
MappedRAM rom;
|
||||
MappedRAM ram;
|
||||
|
||||
readonly<bool> loaded;
|
||||
readonly<string> sha256;
|
||||
auto loaded() const -> bool { return _loaded; }
|
||||
auto sha256() const -> string { return _sha256; }
|
||||
auto region() const -> Region { return _region; }
|
||||
|
||||
readonly<Region> region;
|
||||
readonly<bool> hasICD2;
|
||||
readonly<bool> hasMCC;
|
||||
readonly<bool> hasNSSDIP;
|
||||
readonly<bool> hasEvent;
|
||||
readonly<bool> hasSA1;
|
||||
readonly<bool> hasSuperFX;
|
||||
readonly<bool> hasARMDSP;
|
||||
readonly<bool> hasHitachiDSP;
|
||||
readonly<bool> hasNECDSP;
|
||||
readonly<bool> hasEpsonRTC;
|
||||
readonly<bool> hasSharpRTC;
|
||||
readonly<bool> hasSPC7110;
|
||||
readonly<bool> hasSDD1;
|
||||
readonly<bool> hasOBC1;
|
||||
readonly<bool> hasMSU1;
|
||||
|
||||
readonly<bool> has_gb_slot;
|
||||
readonly<bool> has_bs_cart;
|
||||
readonly<bool> has_bs_slot;
|
||||
readonly<bool> has_st_slots;
|
||||
readonly<bool> has_nss_dip;
|
||||
readonly<bool> has_event;
|
||||
readonly<bool> has_sa1;
|
||||
readonly<bool> has_superfx;
|
||||
readonly<bool> has_armdsp;
|
||||
readonly<bool> has_hitachidsp;
|
||||
readonly<bool> has_necdsp;
|
||||
readonly<bool> has_epsonrtc;
|
||||
readonly<bool> has_sharprtc;
|
||||
readonly<bool> has_spc7110;
|
||||
readonly<bool> has_sdd1;
|
||||
readonly<bool> has_obc1;
|
||||
readonly<bool> has_hsu1;
|
||||
readonly<bool> has_msu1;
|
||||
readonly<bool> hasSuperGameBoySlot;
|
||||
readonly<bool> hasSatellaviewSlot;
|
||||
readonly<bool> hasSufamiTurboSlots;
|
||||
|
||||
struct Mapping {
|
||||
function<uint8 (unsigned)> reader;
|
||||
function<void (unsigned, uint8)> writer;
|
||||
string addr;
|
||||
unsigned size;
|
||||
unsigned base;
|
||||
unsigned mask;
|
||||
unsigned size = 0;
|
||||
unsigned base = 0;
|
||||
unsigned mask = 0;
|
||||
|
||||
Mapping();
|
||||
Mapping() = default;
|
||||
Mapping(const function<uint8 (unsigned)>&, const function<void (unsigned, uint8)>&);
|
||||
Mapping(SuperFamicom::Memory&);
|
||||
};
|
||||
@ -78,45 +66,50 @@ struct Cartridge : property<Cartridge> {
|
||||
} title;
|
||||
} information;
|
||||
|
||||
string title();
|
||||
Cartridge() = default;
|
||||
~Cartridge() { unload(); }
|
||||
|
||||
void load();
|
||||
void unload();
|
||||
auto title() -> string;
|
||||
|
||||
void serialize(serializer&);
|
||||
Cartridge();
|
||||
~Cartridge();
|
||||
auto load() -> void;
|
||||
auto unload() -> void;
|
||||
|
||||
auto serialize(serializer&) -> void;
|
||||
|
||||
private:
|
||||
void load_super_game_boy();
|
||||
void load_satellaview();
|
||||
void load_sufami_turbo_a();
|
||||
void load_sufami_turbo_b();
|
||||
|
||||
void parse_markup(const char*);
|
||||
void parse_markup_map(Mapping&, Markup::Node);
|
||||
void parse_markup_memory(MappedRAM&, Markup::Node, unsigned id, bool writable);
|
||||
|
||||
void parse_markup_cartridge(Markup::Node);
|
||||
void parse_markup_icd2(Markup::Node);
|
||||
void parse_markup_bsx(Markup::Node);
|
||||
void parse_markup_satellaview(Markup::Node);
|
||||
void parse_markup_sufamiturbo(Markup::Node, bool slot);
|
||||
void parse_markup_nss(Markup::Node);
|
||||
void parse_markup_event(Markup::Node);
|
||||
void parse_markup_sa1(Markup::Node);
|
||||
void parse_markup_superfx(Markup::Node);
|
||||
void parse_markup_armdsp(Markup::Node);
|
||||
void parse_markup_hitachidsp(Markup::Node, unsigned roms);
|
||||
void parse_markup_necdsp(Markup::Node);
|
||||
void parse_markup_epsonrtc(Markup::Node);
|
||||
void parse_markup_sharprtc(Markup::Node);
|
||||
void parse_markup_spc7110(Markup::Node);
|
||||
void parse_markup_sdd1(Markup::Node);
|
||||
void parse_markup_obc1(Markup::Node);
|
||||
void parse_markup_msu1(Markup::Node);
|
||||
|
||||
auto loadSuperGameBoy() -> void;
|
||||
auto loadSatellaview() -> void;
|
||||
auto loadSufamiTurboA() -> void;
|
||||
auto loadSufamiTurboB() -> void;
|
||||
friend class Interface;
|
||||
|
||||
//markup.cpp
|
||||
auto parseMarkup(const string&) -> void;
|
||||
auto parseMarkupMap(Mapping&, Markup::Node) -> void;
|
||||
auto parseMarkupMemory(MappedRAM&, Markup::Node, unsigned id, bool writable) -> void;
|
||||
|
||||
auto parseMarkupCartridge(Markup::Node) -> void;
|
||||
auto parseMarkupICD2(Markup::Node) -> void;
|
||||
auto parseMarkupMCC(Markup::Node) -> void;
|
||||
auto parseMarkupSatellaview(Markup::Node) -> void;
|
||||
auto parseMarkupSufamiTurbo(Markup::Node, bool slot) -> void;
|
||||
auto parseMarkupNSS(Markup::Node) -> void;
|
||||
auto parseMarkupEvent(Markup::Node) -> void;
|
||||
auto parseMarkupSA1(Markup::Node) -> void;
|
||||
auto parseMarkupSuperFX(Markup::Node) -> void;
|
||||
auto parseMarkupARMDSP(Markup::Node) -> void;
|
||||
auto parseMarkupHitachiDSP(Markup::Node, unsigned roms) -> void;
|
||||
auto parseMarkupNECDSP(Markup::Node) -> void;
|
||||
auto parseMarkupEpsonRTC(Markup::Node) -> void;
|
||||
auto parseMarkupSharpRTC(Markup::Node) -> void;
|
||||
auto parseMarkupSPC7110(Markup::Node) -> void;
|
||||
auto parseMarkupSDD1(Markup::Node) -> void;
|
||||
auto parseMarkupOBC1(Markup::Node) -> void;
|
||||
auto parseMarkupMSU1(Markup::Node) -> void;
|
||||
|
||||
bool _loaded = false;
|
||||
string _sha256;
|
||||
Region _region = Region::NTSC;
|
||||
};
|
||||
|
||||
extern Cartridge cartridge;
|
||||
|
@ -1,44 +1,52 @@
|
||||
#ifdef CARTRIDGE_CPP
|
||||
|
||||
void Cartridge::parse_markup(const char* markup) {
|
||||
Cartridge::Mapping::Mapping(SuperFamicom::Memory& memory) {
|
||||
this->reader = {&SuperFamicom::Memory::read, &memory};
|
||||
this->writer = {&SuperFamicom::Memory::write, &memory};
|
||||
}
|
||||
|
||||
Cartridge::Mapping::Mapping(const function<uint8 (unsigned)>& reader, const function<void (unsigned, uint8)>& writer) {
|
||||
this->reader = reader;
|
||||
this->writer = writer;
|
||||
}
|
||||
|
||||
auto Cartridge::parseMarkup(const string& markup) -> void {
|
||||
auto document = BML::unserialize(markup);
|
||||
information.title.cartridge = document["information/title"].text();
|
||||
|
||||
auto cartridge = document["cartridge"];
|
||||
region = cartridge["region"].text() != "PAL" ? Region::NTSC : Region::PAL;
|
||||
_region = cartridge["region"].text() != "PAL" ? Region::NTSC : Region::PAL;
|
||||
|
||||
mapping.reset();
|
||||
parse_markup_cartridge(cartridge);
|
||||
parse_markup_icd2(cartridge["icd2"]);
|
||||
parse_markup_bsx(cartridge["bsx"]);
|
||||
parse_markup_satellaview(cartridge["satellaview"]);
|
||||
parse_markup_sufamiturbo(cartridge["sufamiturbo[0]"], 0);
|
||||
parse_markup_sufamiturbo(cartridge["sufamiturbo[1]"], 1);
|
||||
parse_markup_nss(cartridge["nss"]);
|
||||
parse_markup_event(cartridge["event"]);
|
||||
parse_markup_sa1(cartridge["sa1"]);
|
||||
parse_markup_superfx(cartridge["superfx"]);
|
||||
parse_markup_armdsp(cartridge["armdsp"]);
|
||||
parse_markup_hitachidsp(cartridge["hitachidsp"], cartridge["board/type"].text().match("2DC*") ? 2 : 1);
|
||||
parse_markup_necdsp(cartridge["necdsp"]);
|
||||
parse_markup_epsonrtc(cartridge["epsonrtc"]);
|
||||
parse_markup_sharprtc(cartridge["sharprtc"]);
|
||||
parse_markup_spc7110(cartridge["spc7110"]);
|
||||
parse_markup_sdd1(cartridge["sdd1"]);
|
||||
parse_markup_obc1(cartridge["obc1"]);
|
||||
parse_markup_msu1(cartridge["msu1"]);
|
||||
if(auto node = cartridge) parseMarkupCartridge(node);
|
||||
if(auto node = cartridge["icd2"]) parseMarkupICD2(node);
|
||||
if(auto node = cartridge["mcc"]) parseMarkupMCC(node);
|
||||
if(auto node = cartridge["satellaview"]) parseMarkupSatellaview(node);
|
||||
if(auto node = cartridge.find("sufamiturbo")) if(node(0)) parseMarkupSufamiTurbo(node(0), 0);
|
||||
if(auto node = cartridge.find("sufamiturbo")) if(node(1)) parseMarkupSufamiTurbo(node(1), 1);
|
||||
if(auto node = cartridge["nss"]) parseMarkupNSS(node);
|
||||
if(auto node = cartridge["event"]) parseMarkupEvent(node);
|
||||
if(auto node = cartridge["sa1"]) parseMarkupSA1(node);
|
||||
if(auto node = cartridge["superfx"]) parseMarkupSuperFX(node);
|
||||
if(auto node = cartridge["armdsp"]) parseMarkupARMDSP(node);
|
||||
if(auto node = cartridge["hitachidsp"]) parseMarkupHitachiDSP(node, cartridge["board/type"].text().match("2DC*") ? 2 : 1);
|
||||
if(auto node = cartridge["necdsp"]) parseMarkupNECDSP(node);
|
||||
if(auto node = cartridge["epsonrtc"]) parseMarkupEpsonRTC(node);
|
||||
if(auto node = cartridge["sharprtc"]) parseMarkupSharpRTC(node);
|
||||
if(auto node = cartridge["spc7110"]) parseMarkupSPC7110(node);
|
||||
if(auto node = cartridge["sdd1"]) parseMarkupSDD1(node);
|
||||
if(auto node = cartridge["obc1"]) parseMarkupOBC1(node);
|
||||
if(auto node = cartridge["msu1"]) parseMarkupMSU1(node);
|
||||
}
|
||||
|
||||
//
|
||||
|
||||
void Cartridge::parse_markup_map(Mapping& m, Markup::Node map) {
|
||||
auto Cartridge::parseMarkupMap(Mapping& m, Markup::Node map) -> void {
|
||||
m.addr = map["address"].text();
|
||||
m.size = map["size"].decimal();
|
||||
m.base = map["base"].decimal();
|
||||
m.mask = map["mask"].decimal();
|
||||
}
|
||||
|
||||
void Cartridge::parse_markup_memory(MappedRAM& ram, Markup::Node node, unsigned id, bool writable) {
|
||||
auto Cartridge::parseMarkupMemory(MappedRAM& ram, Markup::Node node, unsigned id, bool writable) -> void {
|
||||
string name = node["name"].text();
|
||||
unsigned size = node["size"].decimal();
|
||||
ram.map(allocate<uint8>(size, 0xff), size);
|
||||
@ -48,34 +56,30 @@ void Cartridge::parse_markup_memory(MappedRAM& ram, Markup::Node node, unsigned
|
||||
}
|
||||
}
|
||||
|
||||
//
|
||||
|
||||
void Cartridge::parse_markup_cartridge(Markup::Node root) {
|
||||
if(!root) return;
|
||||
|
||||
parse_markup_memory(rom, root["rom"], ID::ROM, false);
|
||||
parse_markup_memory(ram, root["ram"], ID::RAM, true);
|
||||
auto Cartridge::parseMarkupCartridge(Markup::Node root) -> void {
|
||||
parseMarkupMemory(rom, root["rom"], ID::ROM, false);
|
||||
parseMarkupMemory(ram, root["ram"], ID::RAM, true);
|
||||
|
||||
for(auto node : root.find("map")) {
|
||||
if(node["id"].text() == "rom") {
|
||||
Mapping m(rom);
|
||||
parse_markup_map(m, node);
|
||||
parseMarkupMap(m, node);
|
||||
if(m.size == 0) m.size = rom.size();
|
||||
mapping.append(m);
|
||||
}
|
||||
|
||||
if(node["id"].text() == "ram") {
|
||||
Mapping m(ram);
|
||||
parse_markup_map(m, node);
|
||||
parseMarkupMap(m, node);
|
||||
if(m.size == 0) m.size = ram.size();
|
||||
mapping.append(m);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void Cartridge::parse_markup_icd2(Markup::Node root) {
|
||||
if(!root) return;
|
||||
has_gb_slot = true;
|
||||
auto Cartridge::parseMarkupICD2(Markup::Node root) -> void {
|
||||
hasSuperGameBoySlot = true;
|
||||
hasICD2 = true;
|
||||
icd2.revision = max(1, root["revision"].decimal());
|
||||
|
||||
GameBoy::cartridge.load_empty(GameBoy::System::Revision::SuperGameBoy);
|
||||
@ -87,42 +91,40 @@ void Cartridge::parse_markup_icd2(Markup::Node root) {
|
||||
for(auto node : root.find("map")) {
|
||||
if(node["id"].text() == "io") {
|
||||
Mapping m({&ICD2::read, &icd2}, {&ICD2::write, &icd2});
|
||||
parse_markup_map(m, node);
|
||||
parseMarkupMap(m, node);
|
||||
mapping.append(m);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void Cartridge::parse_markup_bsx(Markup::Node root) {
|
||||
if(!root) return;
|
||||
has_bs_cart = true;
|
||||
has_bs_slot = true;
|
||||
auto Cartridge::parseMarkupMCC(Markup::Node root) -> void {
|
||||
hasSatellaviewSlot = true;
|
||||
hasMCC = true;
|
||||
|
||||
interface->loadRequest(ID::Satellaview, "BS-X Satellaview", "bs");
|
||||
|
||||
parse_markup_memory(bsxcartridge.rom, root["rom"], ID::BsxROM, false);
|
||||
parse_markup_memory(bsxcartridge.ram, root["ram"], ID::BsxRAM, true);
|
||||
parse_markup_memory(bsxcartridge.psram, root["psram"], ID::BsxPSRAM, true);
|
||||
parseMarkupMemory(mcc.rom, root["rom"], ID::MCCROM, false);
|
||||
parseMarkupMemory(mcc.ram, root["ram"], ID::MCCRAM, true);
|
||||
parseMarkupMemory(mcc.psram, root["psram"], ID::MCCPSRAM, true);
|
||||
|
||||
for(auto node : root.find("map")) {
|
||||
if(node["id"].text() == "rom"
|
||||
|| node["id"].text() == "ram") {
|
||||
Mapping m({&BSXCartridge::mcu_read, &bsxcartridge}, {&BSXCartridge::mcu_write, &bsxcartridge});
|
||||
parse_markup_map(m, node);
|
||||
Mapping m({&MCC::mcu_read, &mcc}, {&MCC::mcu_write, &mcc});
|
||||
parseMarkupMap(m, node);
|
||||
mapping.append(m);
|
||||
}
|
||||
|
||||
if(node["id"].text() == "io") {
|
||||
Mapping m({&BSXCartridge::mmio_read, &bsxcartridge}, {&BSXCartridge::mmio_write, &bsxcartridge});
|
||||
parse_markup_map(m, node);
|
||||
Mapping m({&MCC::mmio_read, &mcc}, {&MCC::mmio_write, &mcc});
|
||||
parseMarkupMap(m, node);
|
||||
mapping.append(m);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void Cartridge::parse_markup_satellaview(Markup::Node root) {
|
||||
if(!root) return;
|
||||
has_bs_slot = true;
|
||||
auto Cartridge::parseMarkupSatellaview(Markup::Node root) -> void {
|
||||
hasSatellaviewSlot = true;
|
||||
|
||||
interface->loadRequest(ID::Satellaview, "BS-X Satellaview", "bs");
|
||||
|
||||
@ -131,15 +133,14 @@ void Cartridge::parse_markup_satellaview(Markup::Node root) {
|
||||
if(satellaviewcartridge.memory.size() == 0) continue;
|
||||
|
||||
Mapping m(satellaviewcartridge);
|
||||
parse_markup_map(m, node);
|
||||
parseMarkupMap(m, node);
|
||||
mapping.append(m);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void Cartridge::parse_markup_sufamiturbo(Markup::Node root, bool slot) {
|
||||
if(!root) return;
|
||||
has_st_slots = true;
|
||||
auto Cartridge::parseMarkupSufamiTurbo(Markup::Node root, bool slot) -> void {
|
||||
hasSufamiTurboSlots = true;
|
||||
|
||||
if(slot == 0) {
|
||||
//load required slot A (will request slot B if slot A cartridge is linkable)
|
||||
@ -153,7 +154,7 @@ void Cartridge::parse_markup_sufamiturbo(Markup::Node root, bool slot) {
|
||||
if(cart.rom.size() == 0) continue;
|
||||
|
||||
Mapping m(cart.rom);
|
||||
parse_markup_map(m, node);
|
||||
parseMarkupMap(m, node);
|
||||
if(m.size == 0) m.size = cart.rom.size();
|
||||
if(m.size) mapping.append(m);
|
||||
}
|
||||
@ -162,37 +163,35 @@ void Cartridge::parse_markup_sufamiturbo(Markup::Node root, bool slot) {
|
||||
if(cart.ram.size() == 0) continue;
|
||||
|
||||
Mapping m(cart.ram);
|
||||
parse_markup_map(m, node);
|
||||
parseMarkupMap(m, node);
|
||||
if(m.size == 0) m.size = cart.ram.size();
|
||||
if(m.size) mapping.append(m);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void Cartridge::parse_markup_nss(Markup::Node root) {
|
||||
if(!root) return;
|
||||
has_nss_dip = true;
|
||||
auto Cartridge::parseMarkupNSS(Markup::Node root) -> void {
|
||||
hasNSSDIP = true;
|
||||
nss.dip = interface->dipSettings(root);
|
||||
|
||||
for(auto node : root.find("map")) {
|
||||
if(node["id"].text() == "io") {
|
||||
Mapping m({&NSS::read, &nss}, {&NSS::write, &nss});
|
||||
parse_markup_map(m, node);
|
||||
parseMarkupMap(m, node);
|
||||
mapping.append(m);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void Cartridge::parse_markup_event(Markup::Node root) {
|
||||
if(!root) return;
|
||||
has_event = true;
|
||||
auto Cartridge::parseMarkupEvent(Markup::Node root) -> void {
|
||||
hasEvent = true;
|
||||
|
||||
for(auto node : root.find("rom")) {
|
||||
unsigned id = node["id"].decimal();
|
||||
if(id > 3) continue;
|
||||
parse_markup_memory(event.rom[id], node, ID::EventROM0 + id, false);
|
||||
parseMarkupMemory(event.rom[id], node, ID::EventROM0 + id, false);
|
||||
}
|
||||
parse_markup_memory(event.ram, root["ram"], ID::EventRAM, true);
|
||||
parseMarkupMemory(event.ram, root["ram"], ID::EventRAM, true);
|
||||
|
||||
event.board = Event::Board::CampusChallenge92;
|
||||
if(root["name"].text() == "Campus Challenge '92") event.board = Event::Board::CampusChallenge92;
|
||||
@ -206,105 +205,102 @@ void Cartridge::parse_markup_event(Markup::Node root) {
|
||||
for(auto node : root.find("map")) {
|
||||
if(node["id"].text() == "rom") {
|
||||
Mapping m({&Event::rom_read, &event}, [](unsigned, uint8) {});
|
||||
parse_markup_map(m, node);
|
||||
parseMarkupMap(m, node);
|
||||
mapping.append(m);
|
||||
}
|
||||
|
||||
if(node["id"].text() == "ram") {
|
||||
Mapping m({&Event::ram_read, &event}, {&Event::ram_write, &event});
|
||||
parse_markup_map(m, node);
|
||||
parseMarkupMap(m, node);
|
||||
mapping.append(m);
|
||||
}
|
||||
|
||||
if(node["id"].text() == "dr") {
|
||||
Mapping m([](unsigned) -> uint8 { return cpu.regs.mdr; }, {&Event::dr, &event});
|
||||
parse_markup_map(m, node);
|
||||
parseMarkupMap(m, node);
|
||||
mapping.append(m);
|
||||
}
|
||||
|
||||
if(node["id"].text() == "sr") {
|
||||
Mapping m({&Event::sr, &event}, [](unsigned, uint8) {});
|
||||
parse_markup_map(m, node);
|
||||
parseMarkupMap(m, node);
|
||||
mapping.append(m);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void Cartridge::parse_markup_sa1(Markup::Node root) {
|
||||
if(!root) return;
|
||||
has_sa1 = true;
|
||||
auto Cartridge::parseMarkupSA1(Markup::Node root) -> void {
|
||||
hasSA1 = true;
|
||||
|
||||
auto rom = root.find("rom");
|
||||
auto ram = root.find("ram");
|
||||
|
||||
parse_markup_memory(sa1.rom, rom(0), ID::SA1ROM, false);
|
||||
parse_markup_memory(sa1.bwram, ram(0), ID::SA1BWRAM, true);
|
||||
parse_markup_memory(sa1.iram, ram(1), ID::SA1IRAM, true);
|
||||
parseMarkupMemory(sa1.rom, rom(0), ID::SA1ROM, false);
|
||||
parseMarkupMemory(sa1.bwram, ram(0), ID::SA1BWRAM, true);
|
||||
parseMarkupMemory(sa1.iram, ram(1), ID::SA1IRAM, true);
|
||||
|
||||
for(auto node : root.find("map")) {
|
||||
if(node["id"].text() == "io") {
|
||||
Mapping m({&SA1::mmio_read, &sa1}, {&SA1::mmio_write, &sa1});
|
||||
parse_markup_map(m, node);
|
||||
parseMarkupMap(m, node);
|
||||
mapping.append(m);
|
||||
}
|
||||
|
||||
if(node["id"].text() == "rom") {
|
||||
Mapping m({&SA1::mmcrom_read, &sa1}, {&SA1::mmcrom_write, &sa1});
|
||||
parse_markup_map(m, node);
|
||||
parseMarkupMap(m, node);
|
||||
mapping.append(m);
|
||||
}
|
||||
|
||||
if(node["id"].text() == "bwram") {
|
||||
Mapping m({&SA1::mmcbwram_read, &sa1}, {&SA1::mmcbwram_write, &sa1});
|
||||
parse_markup_map(m, node);
|
||||
parseMarkupMap(m, node);
|
||||
mapping.append(m);
|
||||
}
|
||||
|
||||
if(node["id"].text() == "iram") {
|
||||
Mapping m(sa1.cpuiram);
|
||||
parse_markup_map(m, node);
|
||||
parseMarkupMap(m, node);
|
||||
if(m.size == 0) m.size = sa1.cpuiram.size();
|
||||
mapping.append(m);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void Cartridge::parse_markup_superfx(Markup::Node root) {
|
||||
if(!root) return;
|
||||
has_superfx = true;
|
||||
auto Cartridge::parseMarkupSuperFX(Markup::Node root) -> void {
|
||||
hasSuperFX = true;
|
||||
|
||||
auto rom = root.find("rom");
|
||||
auto ram = root.find("ram");
|
||||
|
||||
parse_markup_memory(superfx.rom, rom(0), ID::SuperFXROM, false);
|
||||
parse_markup_memory(superfx.ram, ram(0), ID::SuperFXRAM, true);
|
||||
parseMarkupMemory(superfx.rom, rom(0), ID::SuperFXROM, false);
|
||||
parseMarkupMemory(superfx.ram, ram(0), ID::SuperFXRAM, true);
|
||||
|
||||
for(auto node : root.find("map")) {
|
||||
if(node["id"].text() == "io") {
|
||||
Mapping m({&SuperFX::mmio_read, &superfx}, {&SuperFX::mmio_write, &superfx});
|
||||
parse_markup_map(m, node);
|
||||
parseMarkupMap(m, node);
|
||||
mapping.append(m);
|
||||
}
|
||||
|
||||
if(node["id"].text() == "rom") {
|
||||
Mapping m(superfx.cpurom);
|
||||
parse_markup_map(m, node);
|
||||
parseMarkupMap(m, node);
|
||||
if(m.size == 0) m.size = superfx.rom.size();
|
||||
mapping.append(m);
|
||||
}
|
||||
|
||||
if(node["id"].text() == "ram") {
|
||||
Mapping m(superfx.cpuram);
|
||||
parse_markup_map(m, node);
|
||||
parseMarkupMap(m, node);
|
||||
if(m.size == 0) m.size = superfx.ram.size();
|
||||
mapping.append(m);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void Cartridge::parse_markup_armdsp(Markup::Node root) {
|
||||
if(!root) return;
|
||||
has_armdsp = true;
|
||||
auto Cartridge::parseMarkupARMDSP(Markup::Node root) -> void {
|
||||
hasARMDSP = true;
|
||||
|
||||
auto rom = root.find("rom");
|
||||
auto ram = root.find("ram");
|
||||
@ -323,21 +319,20 @@ void Cartridge::parse_markup_armdsp(Markup::Node root) {
|
||||
for(auto node : root.find("map")) {
|
||||
if(node["id"].text() == "io") {
|
||||
Mapping m({&ArmDSP::mmio_read, &armdsp}, {&ArmDSP::mmio_write, &armdsp});
|
||||
parse_markup_map(m, node);
|
||||
parseMarkupMap(m, node);
|
||||
mapping.append(m);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void Cartridge::parse_markup_hitachidsp(Markup::Node root, unsigned roms) {
|
||||
if(!root) return;
|
||||
has_hitachidsp = true;
|
||||
auto Cartridge::parseMarkupHitachiDSP(Markup::Node root, unsigned roms) -> void {
|
||||
hasHitachiDSP = true;
|
||||
|
||||
auto rom = root.find("rom");
|
||||
auto ram = root.find("ram");
|
||||
|
||||
parse_markup_memory(hitachidsp.rom, rom(0), ID::HitachiDSPROM, false);
|
||||
parse_markup_memory(hitachidsp.ram, ram(0), ID::HitachiDSPRAM, true);
|
||||
parseMarkupMemory(hitachidsp.rom, rom(0), ID::HitachiDSPROM, false);
|
||||
parseMarkupMemory(hitachidsp.ram, ram(0), ID::HitachiDSPRAM, true);
|
||||
|
||||
for(auto& word : hitachidsp.dataROM) word = 0x000000;
|
||||
for(auto& word : hitachidsp.dataRAM) word = 0x00;
|
||||
@ -357,29 +352,28 @@ void Cartridge::parse_markup_hitachidsp(Markup::Node root, unsigned roms) {
|
||||
for(auto node : root.find("map")) {
|
||||
if(node["id"].text() == "io") {
|
||||
Mapping m({&HitachiDSP::dsp_read, &hitachidsp}, {&HitachiDSP::dsp_write, &hitachidsp});
|
||||
parse_markup_map(m, node);
|
||||
parseMarkupMap(m, node);
|
||||
mapping.append(m);
|
||||
}
|
||||
|
||||
if(node["id"].text() == "rom") {
|
||||
Mapping m({&HitachiDSP::rom_read, &hitachidsp}, {&HitachiDSP::rom_write, &hitachidsp});
|
||||
parse_markup_map(m, node);
|
||||
parseMarkupMap(m, node);
|
||||
if(m.size == 0) m.size = hitachidsp.rom.size();
|
||||
mapping.append(m);
|
||||
}
|
||||
|
||||
if(node["id"].text() == "ram") {
|
||||
Mapping m({&HitachiDSP::ram_read, &hitachidsp}, {&HitachiDSP::ram_write, &hitachidsp});
|
||||
parse_markup_map(m, node);
|
||||
parseMarkupMap(m, node);
|
||||
if(m.size == 0) m.size = hitachidsp.ram.size();
|
||||
mapping.append(m);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void Cartridge::parse_markup_necdsp(Markup::Node root) {
|
||||
if(!root) return;
|
||||
has_necdsp = true;
|
||||
auto Cartridge::parseMarkupNECDSP(Markup::Node root) -> void {
|
||||
hasNECDSP = true;
|
||||
|
||||
for(auto& word : necdsp.programROM) word = 0x000000;
|
||||
for(auto& word : necdsp.dataROM) word = 0x0000;
|
||||
@ -420,22 +414,21 @@ void Cartridge::parse_markup_necdsp(Markup::Node root) {
|
||||
for(auto node : root.find("map")) {
|
||||
if(node["id"].text() == "io") {
|
||||
Mapping m({&NECDSP::read, &necdsp}, {&NECDSP::write, &necdsp});
|
||||
parse_markup_map(m, node);
|
||||
parseMarkupMap(m, node);
|
||||
mapping.append(m);
|
||||
necdsp.Select = node["select"].decimal();
|
||||
}
|
||||
|
||||
if(node["id"].text() == "ram") {
|
||||
Mapping m({&NECDSP::ram_read, &necdsp}, {&NECDSP::ram_write, &necdsp});
|
||||
parse_markup_map(m, node);
|
||||
parseMarkupMap(m, node);
|
||||
mapping.append(m);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void Cartridge::parse_markup_epsonrtc(Markup::Node root) {
|
||||
if(!root) return;
|
||||
has_epsonrtc = true;
|
||||
auto Cartridge::parseMarkupEpsonRTC(Markup::Node root) -> void {
|
||||
hasEpsonRTC = true;
|
||||
|
||||
string name = root["ram/name"].text();
|
||||
interface->loadRequest(ID::EpsonRTC, name);
|
||||
@ -444,15 +437,14 @@ void Cartridge::parse_markup_epsonrtc(Markup::Node root) {
|
||||
for(auto node : root.find("map")) {
|
||||
if(node["id"].text() == "io") {
|
||||
Mapping m({&EpsonRTC::read, &epsonrtc}, {&EpsonRTC::write, &epsonrtc});
|
||||
parse_markup_map(m, node);
|
||||
parseMarkupMap(m, node);
|
||||
mapping.append(m);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void Cartridge::parse_markup_sharprtc(Markup::Node root) {
|
||||
if(!root) return;
|
||||
has_sharprtc = true;
|
||||
auto Cartridge::parseMarkupSharpRTC(Markup::Node root) -> void {
|
||||
hasSharpRTC = true;
|
||||
|
||||
string name = root["ram/name"].text();
|
||||
interface->loadRequest(ID::SharpRTC, name);
|
||||
@ -461,117 +453,97 @@ void Cartridge::parse_markup_sharprtc(Markup::Node root) {
|
||||
for(auto node : root.find("map")) {
|
||||
if(node["id"].text() == "io") {
|
||||
Mapping m({&SharpRTC::read, &sharprtc}, {&SharpRTC::write, &sharprtc});
|
||||
parse_markup_map(m, node);
|
||||
parseMarkupMap(m, node);
|
||||
mapping.append(m);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void Cartridge::parse_markup_spc7110(Markup::Node root) {
|
||||
if(!root) return;
|
||||
has_spc7110 = true;
|
||||
auto Cartridge::parseMarkupSPC7110(Markup::Node root) -> void {
|
||||
hasSPC7110 = true;
|
||||
|
||||
auto rom = root.find("rom");
|
||||
auto ram = root.find("ram");
|
||||
|
||||
parse_markup_memory(spc7110.prom, rom(0), ID::SPC7110PROM, false);
|
||||
parse_markup_memory(spc7110.drom, rom(1), ID::SPC7110DROM, false);
|
||||
parse_markup_memory(spc7110.ram, ram(0), ID::SPC7110RAM, true);
|
||||
parseMarkupMemory(spc7110.prom, rom(0), ID::SPC7110PROM, false);
|
||||
parseMarkupMemory(spc7110.drom, rom(1), ID::SPC7110DROM, false);
|
||||
parseMarkupMemory(spc7110.ram, ram(0), ID::SPC7110RAM, true);
|
||||
|
||||
for(auto node : root.find("map")) {
|
||||
if(node["id"].text() == "io") {
|
||||
Mapping m({&SPC7110::read, &spc7110}, {&SPC7110::write, &spc7110});
|
||||
parse_markup_map(m, node);
|
||||
parseMarkupMap(m, node);
|
||||
mapping.append(m);
|
||||
}
|
||||
|
||||
if(node["id"].text() == "rom") {
|
||||
Mapping m({&SPC7110::mcurom_read, &spc7110}, {&SPC7110::mcurom_write, &spc7110});
|
||||
parse_markup_map(m, node);
|
||||
parseMarkupMap(m, node);
|
||||
mapping.append(m);
|
||||
}
|
||||
|
||||
if(node["id"].text() == "ram") {
|
||||
Mapping m({&SPC7110::mcuram_read, &spc7110}, {&SPC7110::mcuram_write, &spc7110});
|
||||
parse_markup_map(m, node);
|
||||
parseMarkupMap(m, node);
|
||||
mapping.append(m);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void Cartridge::parse_markup_sdd1(Markup::Node root) {
|
||||
if(!root) return;
|
||||
has_sdd1 = true;
|
||||
auto Cartridge::parseMarkupSDD1(Markup::Node root) -> void {
|
||||
hasSDD1 = true;
|
||||
|
||||
auto rom = root.find("rom");
|
||||
auto ram = root.find("ram");
|
||||
|
||||
parse_markup_memory(sdd1.rom, rom(0), ID::SDD1ROM, false);
|
||||
parse_markup_memory(sdd1.ram, ram(0), ID::SDD1RAM, true);
|
||||
parseMarkupMemory(sdd1.rom, rom(0), ID::SDD1ROM, false);
|
||||
parseMarkupMemory(sdd1.ram, ram(0), ID::SDD1RAM, true);
|
||||
|
||||
for(auto node : root.find("map")) {
|
||||
if(node["id"].text() == "io") {
|
||||
Mapping m({&SDD1::read, &sdd1}, {&SDD1::write, &sdd1});
|
||||
parse_markup_map(m, node);
|
||||
parseMarkupMap(m, node);
|
||||
mapping.append(m);
|
||||
}
|
||||
|
||||
if(node["id"].text() == "rom") {
|
||||
Mapping m({&SDD1::mcurom_read, &sdd1}, {&SDD1::mcurom_write, &sdd1});
|
||||
parse_markup_map(m, node);
|
||||
parseMarkupMap(m, node);
|
||||
mapping.append(m);
|
||||
}
|
||||
|
||||
if(node["id"].text() == "ram") {
|
||||
Mapping m({&SDD1::mcuram_read, &sdd1}, {&SDD1::mcuram_write, &sdd1});
|
||||
parse_markup_map(m, node);
|
||||
parseMarkupMap(m, node);
|
||||
mapping.append(m);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void Cartridge::parse_markup_obc1(Markup::Node root) {
|
||||
if(!root) return;
|
||||
has_obc1 = true;
|
||||
auto Cartridge::parseMarkupOBC1(Markup::Node root) -> void {
|
||||
hasOBC1 = true;
|
||||
|
||||
parse_markup_memory(obc1.ram, root["ram"], ID::OBC1RAM, true);
|
||||
parseMarkupMemory(obc1.ram, root["ram"], ID::OBC1RAM, true);
|
||||
|
||||
for(auto node : root.find("map")) {
|
||||
if(node["id"].text() == "io") {
|
||||
Mapping m({&OBC1::read, &obc1}, {&OBC1::write, &obc1});
|
||||
parse_markup_map(m, node);
|
||||
parseMarkupMap(m, node);
|
||||
mapping.append(m);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void Cartridge::parse_markup_msu1(Markup::Node root) {
|
||||
if(!root) return;
|
||||
has_msu1 = true;
|
||||
auto Cartridge::parseMarkupMSU1(Markup::Node root) -> void {
|
||||
hasMSU1 = true;
|
||||
|
||||
for(auto node : root.find("map")) {
|
||||
if(node["id"].text() == "io") {
|
||||
Mapping m({&MSU1::mmio_read, &msu1}, {&MSU1::mmio_write, &msu1});
|
||||
parse_markup_map(m, node);
|
||||
parseMarkupMap(m, node);
|
||||
mapping.append(m);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Cartridge::Mapping::Mapping() {
|
||||
size = base = mask = 0;
|
||||
}
|
||||
|
||||
Cartridge::Mapping::Mapping(SuperFamicom::Memory& memory) {
|
||||
reader = {&SuperFamicom::Memory::read, &memory};
|
||||
writer = {&SuperFamicom::Memory::write, &memory};
|
||||
size = base = mask = 0;
|
||||
}
|
||||
|
||||
Cartridge::Mapping::Mapping(const function<uint8 (unsigned)>& reader, const function<void (unsigned, uint8)>& writer) {
|
||||
this->reader = reader;
|
||||
this->writer = writer;
|
||||
size = base = mask = 0;
|
||||
}
|
||||
|
||||
#endif
|
||||
|
@ -1,6 +1,6 @@
|
||||
#ifdef CARTRIDGE_CPP
|
||||
|
||||
void Cartridge::serialize(serializer& s) {
|
||||
auto Cartridge::serialize(serializer& s) -> void {
|
||||
s.array(ram.data(), ram.size());
|
||||
}
|
||||
|
||||
|
@ -2,7 +2,7 @@
|
||||
|
||||
nall::vector<uint8> ArmDSP::firmware() {
|
||||
nall::vector<uint8> buffer;
|
||||
if(cartridge.has_armdsp() == false) return buffer;
|
||||
if(!cartridge.hasARMDSP()) return buffer;
|
||||
buffer.reserve(128 * 1024 + 32 * 1024);
|
||||
for(unsigned n = 0; n < 128 * 1024; n++) buffer.append(programROM[n]);
|
||||
for(unsigned n = 0; n < 32 * 1024; n++) buffer.append(dataROM[n]);
|
||||
|
@ -1,34 +0,0 @@
|
||||
struct BSXCartridge {
|
||||
MappedRAM rom;
|
||||
MappedRAM ram;
|
||||
MappedRAM psram;
|
||||
|
||||
void init();
|
||||
void load();
|
||||
void unload();
|
||||
void power();
|
||||
void reset();
|
||||
|
||||
uint8 memory_access(bool write, Memory& memory, unsigned addr, uint8 data);
|
||||
uint8 memory_read(Memory& memory, unsigned addr);
|
||||
void memory_write(Memory& memory, unsigned addr, uint8 data);
|
||||
|
||||
uint8 mcu_access(bool write, unsigned addr, uint8 data = 0x00);
|
||||
uint8 mcu_read(unsigned addr);
|
||||
void mcu_write(unsigned addr, uint8 data);
|
||||
|
||||
uint8 mmio_read(unsigned addr);
|
||||
void mmio_write(unsigned addr, uint8 data);
|
||||
void mmio_commit();
|
||||
|
||||
void serialize(serializer&);
|
||||
|
||||
private:
|
||||
uint8 r[16];
|
||||
bool r00, r01, r02, r03;
|
||||
bool r04, r05, r06, r07;
|
||||
bool r08, r09, r0a, r0b;
|
||||
bool r0c, r0d, r0e, r0f;
|
||||
};
|
||||
|
||||
extern BSXCartridge bsxcartridge;
|
@ -1,10 +1,10 @@
|
||||
struct Coprocessor : Thread {
|
||||
alwaysinline void step(unsigned clocks);
|
||||
alwaysinline void synchronize_cpu();
|
||||
alwaysinline auto step(unsigned clocks) -> void;
|
||||
alwaysinline auto synchronize_cpu() -> void;
|
||||
};
|
||||
|
||||
#include <sfc/chip/icd2/icd2.hpp>
|
||||
#include <sfc/chip/bsx/bsx.hpp>
|
||||
#include <sfc/chip/mcc/mcc.hpp>
|
||||
#include <sfc/chip/nss/nss.hpp>
|
||||
#include <sfc/chip/event/event.hpp>
|
||||
|
||||
@ -24,10 +24,10 @@ struct Coprocessor : Thread {
|
||||
|
||||
#include <sfc/chip/msu1/msu1.hpp>
|
||||
|
||||
void Coprocessor::step(unsigned clocks) {
|
||||
auto Coprocessor::step(unsigned clocks) -> void {
|
||||
clock += clocks * (uint64)cpu.frequency;
|
||||
}
|
||||
|
||||
void Coprocessor::synchronize_cpu() {
|
||||
auto Coprocessor::synchronize_cpu() -> void {
|
||||
if(clock >= 0 && scheduler.sync != Scheduler::SynchronizeMode::All) co_switch(cpu.thread);
|
||||
}
|
||||
|
@ -2,7 +2,7 @@
|
||||
|
||||
vector<uint8> HitachiDSP::firmware() {
|
||||
vector<uint8> buffer;
|
||||
if(cartridge.has_hitachidsp() == false) return buffer;
|
||||
if(!cartridge.hasHitachiDSP()) return buffer;
|
||||
buffer.reserve(1024 * 3);
|
||||
for(unsigned n = 0; n < 1024; n++) {
|
||||
buffer.append(dataROM[n] >> 0);
|
||||
|
@ -1,50 +1,50 @@
|
||||
#include <sfc/sfc.hpp>
|
||||
|
||||
#define BSX_CPP
|
||||
#define MCC_CPP
|
||||
namespace SuperFamicom {
|
||||
|
||||
#include "serialization.cpp"
|
||||
BSXCartridge bsxcartridge;
|
||||
MCC mcc;
|
||||
|
||||
void BSXCartridge::init() {
|
||||
auto MCC::init() -> void {
|
||||
}
|
||||
|
||||
void BSXCartridge::load() {
|
||||
auto MCC::load() -> void {
|
||||
}
|
||||
|
||||
void BSXCartridge::unload() {
|
||||
auto MCC::unload() -> void {
|
||||
rom.reset();
|
||||
ram.reset();
|
||||
psram.reset();
|
||||
}
|
||||
|
||||
void BSXCartridge::power() {
|
||||
auto MCC::power() -> void {
|
||||
}
|
||||
|
||||
void BSXCartridge::reset() {
|
||||
auto MCC::reset() -> void {
|
||||
for(unsigned i = 0; i < 16; i++) r[i] = 0x00;
|
||||
r[0x07] = 0x80;
|
||||
r[0x08] = 0x80;
|
||||
mmio_commit();
|
||||
}
|
||||
|
||||
uint8 BSXCartridge::memory_access(bool write, Memory& memory, unsigned addr, uint8 data) {
|
||||
auto MCC::memory_access(bool write, Memory& memory, unsigned addr, uint8 data) -> uint8 {
|
||||
if(write == 0) return memory_read(memory, addr);
|
||||
memory_write(memory, addr, data);
|
||||
}
|
||||
|
||||
uint8 BSXCartridge::memory_read(Memory& memory, unsigned addr) {
|
||||
auto MCC::memory_read(Memory& memory, unsigned addr) -> uint8 {
|
||||
addr = bus.mirror(addr, memory.size());
|
||||
return memory.read(addr);
|
||||
}
|
||||
|
||||
void BSXCartridge::memory_write(Memory& memory, unsigned addr, uint8 data) {
|
||||
auto MCC::memory_write(Memory& memory, unsigned addr, uint8 data) -> void {
|
||||
addr = bus.mirror(addr, memory.size());
|
||||
return memory.write(addr, data);
|
||||
}
|
||||
|
||||
//mcu_access() allows mcu_read() and mcu_write() to share decoding logic
|
||||
uint8 BSXCartridge::mcu_access(bool write, unsigned addr, uint8 data) {
|
||||
auto MCC::mcu_access(bool write, unsigned addr, uint8 data) -> uint8 {
|
||||
if((addr & 0xe08000) == 0x008000) { //$00-1f:8000-ffff
|
||||
if(r07 == 1) {
|
||||
addr = ((addr & 0x1f0000) >> 1) | (addr & 0x7fff);
|
||||
@ -90,15 +90,15 @@ uint8 BSXCartridge::mcu_access(bool write, unsigned addr, uint8 data) {
|
||||
return cpu.regs.mdr;
|
||||
}
|
||||
|
||||
uint8 BSXCartridge::mcu_read(unsigned addr) {
|
||||
auto MCC::mcu_read(unsigned addr) -> uint8 {
|
||||
return mcu_access(0, addr);
|
||||
}
|
||||
|
||||
void BSXCartridge::mcu_write(unsigned addr, uint8 data) {
|
||||
auto MCC::mcu_write(unsigned addr, uint8 data) -> void {
|
||||
mcu_access(1, addr, data);
|
||||
}
|
||||
|
||||
uint8 BSXCartridge::mmio_read(unsigned addr) {
|
||||
auto MCC::mmio_read(unsigned addr) -> uint8 {
|
||||
if((addr & 0xf0ffff) == 0x005000) { //$00-0f:5000
|
||||
uint8 n = (addr >> 16) & 15;
|
||||
return r[n];
|
||||
@ -111,7 +111,7 @@ uint8 BSXCartridge::mmio_read(unsigned addr) {
|
||||
return 0x00;
|
||||
}
|
||||
|
||||
void BSXCartridge::mmio_write(unsigned addr, uint8 data) {
|
||||
auto MCC::mmio_write(unsigned addr, uint8 data) -> void {
|
||||
if((addr & 0xf0ffff) == 0x005000) { //$00-0f:5000
|
||||
uint8 n = (addr >> 16) & 15;
|
||||
r[n] = data;
|
||||
@ -124,7 +124,7 @@ void BSXCartridge::mmio_write(unsigned addr, uint8 data) {
|
||||
}
|
||||
}
|
||||
|
||||
void BSXCartridge::mmio_commit() {
|
||||
auto MCC::mmio_commit() -> void {
|
||||
r00 = r[0x00] & 0x80;
|
||||
r01 = r[0x01] & 0x80;
|
||||
r02 = r[0x02] & 0x80;
|
36
sfc/chip/mcc/mcc.hpp
Normal file
36
sfc/chip/mcc/mcc.hpp
Normal file
@ -0,0 +1,36 @@
|
||||
//the MCC is the custom logic chip inside the BS-X Satellaview cartridge
|
||||
|
||||
struct MCC {
|
||||
MappedRAM rom;
|
||||
MappedRAM ram;
|
||||
MappedRAM psram;
|
||||
|
||||
auto init() -> void;
|
||||
auto load() -> void;
|
||||
auto unload() -> void;
|
||||
auto power() -> void;
|
||||
auto reset() -> void;
|
||||
|
||||
auto memory_access(bool write, Memory& memory, unsigned addr, uint8 data) -> uint8;
|
||||
auto memory_read(Memory& memory, unsigned addr) -> uint8;
|
||||
auto memory_write(Memory& memory, unsigned addr, uint8 data) -> void;
|
||||
|
||||
auto mcu_access(bool write, unsigned addr, uint8 data = 0x00) -> uint8;
|
||||
auto mcu_read(unsigned addr) -> uint8;
|
||||
auto mcu_write(unsigned addr, uint8 data) -> void;
|
||||
|
||||
auto mmio_read(unsigned addr) -> uint8;
|
||||
auto mmio_write(unsigned addr, uint8 data) -> void;
|
||||
auto mmio_commit() -> void;
|
||||
|
||||
auto serialize(serializer&) -> void;
|
||||
|
||||
private:
|
||||
uint8 r[16];
|
||||
bool r00, r01, r02, r03;
|
||||
bool r04, r05, r06, r07;
|
||||
bool r08, r09, r0a, r0b;
|
||||
bool r0c, r0d, r0e, r0f;
|
||||
};
|
||||
|
||||
extern MCC mcc;
|
@ -1,6 +1,6 @@
|
||||
#ifdef BSX_CPP
|
||||
#ifdef MCC_CPP
|
||||
|
||||
void BSXCartridge::serialize(serializer& s) {
|
||||
auto MCC::serialize(serializer& s) -> void {
|
||||
s.array(ram.data(), ram.size());
|
||||
s.array(psram.data(), psram.size());
|
||||
}
|
@ -2,7 +2,7 @@
|
||||
|
||||
vector<uint8> NECDSP::firmware() {
|
||||
vector<uint8> buffer;
|
||||
if(cartridge.has_necdsp() == false) return buffer;
|
||||
if(!cartridge.hasNECDSP()) return buffer;
|
||||
unsigned plength = 2048, dlength = 1024;
|
||||
if(revision == Revision::uPD96050) plength = 16384, dlength = 2048;
|
||||
buffer.reserve(plength * 3 + dlength * 2);
|
||||
|
@ -66,9 +66,9 @@ unsigned Interface::group(unsigned id) {
|
||||
case ID::SDD1RAM:
|
||||
case ID::OBC1RAM:
|
||||
case ID::SuperGameBoyBootROM:
|
||||
case ID::BsxROM:
|
||||
case ID::BsxRAM:
|
||||
case ID::BsxPSRAM:
|
||||
case ID::MCCROM:
|
||||
case ID::MCCRAM:
|
||||
case ID::MCCPSRAM:
|
||||
return 1;
|
||||
case ID::SuperGameBoy:
|
||||
case ID::SuperGameBoyManifest:
|
||||
@ -96,10 +96,10 @@ unsigned Interface::group(unsigned id) {
|
||||
|
||||
void Interface::load(unsigned id) {
|
||||
if(id == ID::SuperFamicom) cartridge.load();
|
||||
if(id == ID::SuperGameBoy) cartridge.load_super_game_boy();
|
||||
if(id == ID::Satellaview) cartridge.load_satellaview();
|
||||
if(id == ID::SufamiTurboSlotA) cartridge.load_sufami_turbo_a();
|
||||
if(id == ID::SufamiTurboSlotB) cartridge.load_sufami_turbo_b();
|
||||
if(id == ID::SuperGameBoy) cartridge.loadSuperGameBoy();
|
||||
if(id == ID::Satellaview) cartridge.loadSatellaview();
|
||||
if(id == ID::SufamiTurboSlotA) cartridge.loadSufamiTurboA();
|
||||
if(id == ID::SufamiTurboSlotB) cartridge.loadSufamiTurboB();
|
||||
}
|
||||
|
||||
void Interface::save() {
|
||||
@ -193,9 +193,9 @@ void Interface::load(unsigned id, const stream& stream) {
|
||||
stream.read(GameBoy::system.bootROM.sgb, min(stream.size(), 256u));
|
||||
}
|
||||
|
||||
if(id == ID::BsxROM) bsxcartridge.rom.read(stream);
|
||||
if(id == ID::BsxRAM) bsxcartridge.ram.read(stream);
|
||||
if(id == ID::BsxPSRAM) bsxcartridge.psram.read(stream);
|
||||
if(id == ID::MCCROM) mcc.rom.read(stream);
|
||||
if(id == ID::MCCRAM) mcc.ram.read(stream);
|
||||
if(id == ID::MCCPSRAM) mcc.psram.read(stream);
|
||||
|
||||
if(id == ID::SuperGameBoyManifest) cartridge.information.markup.gameBoy = stream.text();
|
||||
|
||||
@ -260,8 +260,8 @@ void Interface::save(unsigned id, const stream& stream) {
|
||||
|
||||
if(id == ID::SuperGameBoyRAM) stream.write(GameBoy::cartridge.ramdata, GameBoy::cartridge.ramsize);
|
||||
|
||||
if(id == ID::BsxRAM) stream.write(bsxcartridge.ram.data(), bsxcartridge.ram.size());
|
||||
if(id == ID::BsxPSRAM) stream.write(bsxcartridge.psram.data(), bsxcartridge.psram.size());
|
||||
if(id == ID::MCCRAM) stream.write(mcc.ram.data(), mcc.ram.size());
|
||||
if(id == ID::MCCPSRAM) stream.write(mcc.psram.data(), mcc.psram.size());
|
||||
|
||||
if(id == ID::SufamiTurboSlotARAM) stream.write(sufamiturboA.ram.data(), sufamiturboA.ram.size());
|
||||
if(id == ID::SufamiTurboSlotBRAM) stream.write(sufamiturboB.ram.data(), sufamiturboB.ram.size());
|
||||
@ -289,14 +289,14 @@ void Interface::run() {
|
||||
}
|
||||
|
||||
bool Interface::rtc() {
|
||||
if(cartridge.has_epsonrtc()) return true;
|
||||
if(cartridge.has_sharprtc()) return true;
|
||||
if(cartridge.hasEpsonRTC()) return true;
|
||||
if(cartridge.hasSharpRTC()) return true;
|
||||
return false;
|
||||
}
|
||||
|
||||
void Interface::rtcsync() {
|
||||
if(cartridge.has_epsonrtc()) epsonrtc.sync();
|
||||
if(cartridge.has_sharprtc()) sharprtc.sync();
|
||||
if(cartridge.hasEpsonRTC()) epsonrtc.sync();
|
||||
if(cartridge.hasSharpRTC()) sharprtc.sync();
|
||||
}
|
||||
|
||||
serializer Interface::serialize() {
|
||||
@ -312,7 +312,7 @@ void Interface::cheatSet(const lstring& list) {
|
||||
cheat.reset();
|
||||
|
||||
//Super Game Boy
|
||||
if(cartridge.has_gb_slot()) {
|
||||
if(cartridge.hasICD2()) {
|
||||
GameBoy::cheat.reset();
|
||||
for(auto& codeset : list) {
|
||||
lstring codes = codeset.split("+");
|
||||
|
@ -63,9 +63,9 @@ struct ID {
|
||||
|
||||
SuperGameBoyBootROM,
|
||||
|
||||
BsxROM,
|
||||
BsxRAM,
|
||||
BsxPSRAM,
|
||||
MCCROM,
|
||||
MCCRAM,
|
||||
MCCPSRAM,
|
||||
|
||||
SuperGameBoyManifest,
|
||||
SuperGameBoyROM,
|
||||
|
@ -57,21 +57,22 @@ void System::serialize_all(serializer& s) {
|
||||
ppu.serialize(s);
|
||||
dsp.serialize(s);
|
||||
|
||||
if(cartridge.has_gb_slot()) icd2.serialize(s);
|
||||
if(cartridge.has_bs_cart()) bsxcartridge.serialize(s);
|
||||
if(cartridge.has_event()) event.serialize(s);
|
||||
if(cartridge.has_sa1()) sa1.serialize(s);
|
||||
if(cartridge.has_superfx()) superfx.serialize(s);
|
||||
if(cartridge.has_armdsp()) armdsp.serialize(s);
|
||||
if(cartridge.has_hitachidsp()) hitachidsp.serialize(s);
|
||||
if(cartridge.has_necdsp()) necdsp.serialize(s);
|
||||
if(cartridge.has_epsonrtc()) epsonrtc.serialize(s);
|
||||
if(cartridge.has_sharprtc()) sharprtc.serialize(s);
|
||||
if(cartridge.has_spc7110()) spc7110.serialize(s);
|
||||
if(cartridge.has_sdd1()) sdd1.serialize(s);
|
||||
if(cartridge.has_obc1()) obc1.serialize(s);
|
||||
if(cartridge.has_msu1()) msu1.serialize(s);
|
||||
if(cartridge.has_st_slots()) sufamiturboA.serialize(s), sufamiturboB.serialize(s);
|
||||
if(cartridge.hasICD2()) icd2.serialize(s);
|
||||
if(cartridge.hasMCC()) mcc.serialize(s);
|
||||
if(cartridge.hasEvent()) event.serialize(s);
|
||||
if(cartridge.hasSA1()) sa1.serialize(s);
|
||||
if(cartridge.hasSuperFX()) superfx.serialize(s);
|
||||
if(cartridge.hasARMDSP()) armdsp.serialize(s);
|
||||
if(cartridge.hasHitachiDSP()) hitachidsp.serialize(s);
|
||||
if(cartridge.hasNECDSP()) necdsp.serialize(s);
|
||||
if(cartridge.hasEpsonRTC()) epsonrtc.serialize(s);
|
||||
if(cartridge.hasSharpRTC()) sharprtc.serialize(s);
|
||||
if(cartridge.hasSPC7110()) spc7110.serialize(s);
|
||||
if(cartridge.hasSDD1()) sdd1.serialize(s);
|
||||
if(cartridge.hasOBC1()) obc1.serialize(s);
|
||||
if(cartridge.hasMSU1()) msu1.serialize(s);
|
||||
|
||||
if(cartridge.hasSufamiTurboSlots()) sufamiturboA.serialize(s), sufamiturboB.serialize(s);
|
||||
}
|
||||
|
||||
//perform dry-run state save:
|
||||
|
@ -66,7 +66,7 @@ void System::init() {
|
||||
|
||||
satellaviewbaseunit.init();
|
||||
icd2.init();
|
||||
bsxcartridge.init();
|
||||
mcc.init();
|
||||
nss.init();
|
||||
event.init();
|
||||
sa1.init();
|
||||
@ -120,46 +120,48 @@ void System::load() {
|
||||
ppu.enable();
|
||||
|
||||
if(expansion() == ExpansionPortDevice::Satellaview) satellaviewbaseunit.load();
|
||||
if(cartridge.has_gb_slot()) icd2.load();
|
||||
if(cartridge.has_bs_cart()) bsxcartridge.load();
|
||||
if(cartridge.has_nss_dip()) nss.load();
|
||||
if(cartridge.has_event()) event.load();
|
||||
if(cartridge.has_sa1()) sa1.load();
|
||||
if(cartridge.has_superfx()) superfx.load();
|
||||
if(cartridge.has_armdsp()) armdsp.load();
|
||||
if(cartridge.has_hitachidsp()) hitachidsp.load();
|
||||
if(cartridge.has_necdsp()) necdsp.load();
|
||||
if(cartridge.has_epsonrtc()) epsonrtc.load();
|
||||
if(cartridge.has_sharprtc()) sharprtc.load();
|
||||
if(cartridge.has_spc7110()) spc7110.load();
|
||||
if(cartridge.has_sdd1()) sdd1.load();
|
||||
if(cartridge.has_obc1()) obc1.load();
|
||||
if(cartridge.has_msu1()) msu1.load();
|
||||
if(cartridge.has_bs_slot()) satellaviewcartridge.load();
|
||||
if(cartridge.has_st_slots()) sufamiturboA.load(), sufamiturboB.load();
|
||||
if(cartridge.hasICD2()) icd2.load();
|
||||
if(cartridge.hasMCC()) mcc.load();
|
||||
if(cartridge.hasNSSDIP()) nss.load();
|
||||
if(cartridge.hasEvent()) event.load();
|
||||
if(cartridge.hasSA1()) sa1.load();
|
||||
if(cartridge.hasSuperFX()) superfx.load();
|
||||
if(cartridge.hasARMDSP()) armdsp.load();
|
||||
if(cartridge.hasHitachiDSP()) hitachidsp.load();
|
||||
if(cartridge.hasNECDSP()) necdsp.load();
|
||||
if(cartridge.hasEpsonRTC()) epsonrtc.load();
|
||||
if(cartridge.hasSharpRTC()) sharprtc.load();
|
||||
if(cartridge.hasSPC7110()) spc7110.load();
|
||||
if(cartridge.hasSDD1()) sdd1.load();
|
||||
if(cartridge.hasOBC1()) obc1.load();
|
||||
if(cartridge.hasMSU1()) msu1.load();
|
||||
|
||||
if(cartridge.hasSatellaviewSlot()) satellaviewcartridge.load();
|
||||
if(cartridge.hasSufamiTurboSlots()) sufamiturboA.load(), sufamiturboB.load();
|
||||
|
||||
serialize_init();
|
||||
}
|
||||
|
||||
void System::unload() {
|
||||
if(expansion() == ExpansionPortDevice::Satellaview) satellaviewbaseunit.unload();
|
||||
if(cartridge.has_gb_slot()) icd2.unload();
|
||||
if(cartridge.has_bs_cart()) bsxcartridge.unload();
|
||||
if(cartridge.has_nss_dip()) nss.unload();
|
||||
if(cartridge.has_event()) event.unload();
|
||||
if(cartridge.has_sa1()) sa1.unload();
|
||||
if(cartridge.has_superfx()) superfx.unload();
|
||||
if(cartridge.has_armdsp()) armdsp.unload();
|
||||
if(cartridge.has_hitachidsp()) hitachidsp.unload();
|
||||
if(cartridge.has_necdsp()) necdsp.unload();
|
||||
if(cartridge.has_epsonrtc()) epsonrtc.unload();
|
||||
if(cartridge.has_sharprtc()) sharprtc.unload();
|
||||
if(cartridge.has_spc7110()) spc7110.unload();
|
||||
if(cartridge.has_sdd1()) sdd1.unload();
|
||||
if(cartridge.has_obc1()) obc1.unload();
|
||||
if(cartridge.has_msu1()) msu1.unload();
|
||||
if(cartridge.has_bs_slot()) satellaviewcartridge.unload();
|
||||
if(cartridge.has_st_slots()) sufamiturboA.unload(), sufamiturboB.unload();
|
||||
if(cartridge.hasICD2()) icd2.unload();
|
||||
if(cartridge.hasMCC()) mcc.unload();
|
||||
if(cartridge.hasNSSDIP()) nss.unload();
|
||||
if(cartridge.hasEvent()) event.unload();
|
||||
if(cartridge.hasSA1()) sa1.unload();
|
||||
if(cartridge.hasSuperFX()) superfx.unload();
|
||||
if(cartridge.hasARMDSP()) armdsp.unload();
|
||||
if(cartridge.hasHitachiDSP()) hitachidsp.unload();
|
||||
if(cartridge.hasNECDSP()) necdsp.unload();
|
||||
if(cartridge.hasEpsonRTC()) epsonrtc.unload();
|
||||
if(cartridge.hasSharpRTC()) sharprtc.unload();
|
||||
if(cartridge.hasSPC7110()) spc7110.unload();
|
||||
if(cartridge.hasSDD1()) sdd1.unload();
|
||||
if(cartridge.hasOBC1()) obc1.unload();
|
||||
if(cartridge.hasMSU1()) msu1.unload();
|
||||
|
||||
if(cartridge.hasSatellaviewSlot()) satellaviewcartridge.unload();
|
||||
if(cartridge.hasSufamiTurboSlots()) sufamiturboA.unload(), sufamiturboB.unload();
|
||||
}
|
||||
|
||||
void System::power() {
|
||||
@ -171,22 +173,23 @@ void System::power() {
|
||||
ppu.power();
|
||||
|
||||
if(expansion() == ExpansionPortDevice::Satellaview) satellaviewbaseunit.power();
|
||||
if(cartridge.has_gb_slot()) icd2.power();
|
||||
if(cartridge.has_bs_cart()) bsxcartridge.power();
|
||||
if(cartridge.has_nss_dip()) nss.power();
|
||||
if(cartridge.has_event()) event.power();
|
||||
if(cartridge.has_sa1()) sa1.power();
|
||||
if(cartridge.has_superfx()) superfx.power();
|
||||
if(cartridge.has_armdsp()) armdsp.power();
|
||||
if(cartridge.has_hitachidsp()) hitachidsp.power();
|
||||
if(cartridge.has_necdsp()) necdsp.power();
|
||||
if(cartridge.has_epsonrtc()) epsonrtc.power();
|
||||
if(cartridge.has_sharprtc()) sharprtc.power();
|
||||
if(cartridge.has_spc7110()) spc7110.power();
|
||||
if(cartridge.has_sdd1()) sdd1.power();
|
||||
if(cartridge.has_obc1()) obc1.power();
|
||||
if(cartridge.has_msu1()) msu1.power();
|
||||
if(cartridge.has_bs_slot()) satellaviewcartridge.power();
|
||||
if(cartridge.hasICD2()) icd2.power();
|
||||
if(cartridge.hasMCC()) mcc.power();
|
||||
if(cartridge.hasNSSDIP()) nss.power();
|
||||
if(cartridge.hasEvent()) event.power();
|
||||
if(cartridge.hasSA1()) sa1.power();
|
||||
if(cartridge.hasSuperFX()) superfx.power();
|
||||
if(cartridge.hasARMDSP()) armdsp.power();
|
||||
if(cartridge.hasHitachiDSP()) hitachidsp.power();
|
||||
if(cartridge.hasNECDSP()) necdsp.power();
|
||||
if(cartridge.hasEpsonRTC()) epsonrtc.power();
|
||||
if(cartridge.hasSharpRTC()) sharprtc.power();
|
||||
if(cartridge.hasSPC7110()) spc7110.power();
|
||||
if(cartridge.hasSDD1()) sdd1.power();
|
||||
if(cartridge.hasOBC1()) obc1.power();
|
||||
if(cartridge.hasMSU1()) msu1.power();
|
||||
|
||||
if(cartridge.hasSatellaviewSlot()) satellaviewcartridge.power();
|
||||
|
||||
reset();
|
||||
}
|
||||
@ -198,34 +201,35 @@ void System::reset() {
|
||||
ppu.reset();
|
||||
|
||||
if(expansion() == ExpansionPortDevice::Satellaview) satellaviewbaseunit.reset();
|
||||
if(cartridge.has_gb_slot()) icd2.reset();
|
||||
if(cartridge.has_bs_cart()) bsxcartridge.reset();
|
||||
if(cartridge.has_nss_dip()) nss.reset();
|
||||
if(cartridge.has_event()) event.reset();
|
||||
if(cartridge.has_sa1()) sa1.reset();
|
||||
if(cartridge.has_superfx()) superfx.reset();
|
||||
if(cartridge.has_armdsp()) armdsp.reset();
|
||||
if(cartridge.has_hitachidsp()) hitachidsp.reset();
|
||||
if(cartridge.has_necdsp()) necdsp.reset();
|
||||
if(cartridge.has_epsonrtc()) epsonrtc.reset();
|
||||
if(cartridge.has_sharprtc()) sharprtc.reset();
|
||||
if(cartridge.has_spc7110()) spc7110.reset();
|
||||
if(cartridge.has_sdd1()) sdd1.reset();
|
||||
if(cartridge.has_obc1()) obc1.reset();
|
||||
if(cartridge.has_msu1()) msu1.reset();
|
||||
if(cartridge.has_bs_slot()) satellaviewcartridge.reset();
|
||||
if(cartridge.hasICD2()) icd2.reset();
|
||||
if(cartridge.hasMCC()) mcc.reset();
|
||||
if(cartridge.hasNSSDIP()) nss.reset();
|
||||
if(cartridge.hasEvent()) event.reset();
|
||||
if(cartridge.hasSA1()) sa1.reset();
|
||||
if(cartridge.hasSuperFX()) superfx.reset();
|
||||
if(cartridge.hasARMDSP()) armdsp.reset();
|
||||
if(cartridge.hasHitachiDSP()) hitachidsp.reset();
|
||||
if(cartridge.hasNECDSP()) necdsp.reset();
|
||||
if(cartridge.hasEpsonRTC()) epsonrtc.reset();
|
||||
if(cartridge.hasSharpRTC()) sharprtc.reset();
|
||||
if(cartridge.hasSPC7110()) spc7110.reset();
|
||||
if(cartridge.hasSDD1()) sdd1.reset();
|
||||
if(cartridge.hasOBC1()) obc1.reset();
|
||||
if(cartridge.hasMSU1()) msu1.reset();
|
||||
|
||||
if(cartridge.has_gb_slot()) cpu.coprocessors.append(&icd2);
|
||||
if(cartridge.has_event()) cpu.coprocessors.append(&event);
|
||||
if(cartridge.has_sa1()) cpu.coprocessors.append(&sa1);
|
||||
if(cartridge.has_superfx()) cpu.coprocessors.append(&superfx);
|
||||
if(cartridge.has_armdsp()) cpu.coprocessors.append(&armdsp);
|
||||
if(cartridge.has_hitachidsp()) cpu.coprocessors.append(&hitachidsp);
|
||||
if(cartridge.has_necdsp()) cpu.coprocessors.append(&necdsp);
|
||||
if(cartridge.has_epsonrtc()) cpu.coprocessors.append(&epsonrtc);
|
||||
if(cartridge.has_sharprtc()) cpu.coprocessors.append(&sharprtc);
|
||||
if(cartridge.has_spc7110()) cpu.coprocessors.append(&spc7110);
|
||||
if(cartridge.has_msu1()) cpu.coprocessors.append(&msu1);
|
||||
if(cartridge.hasSatellaviewSlot()) satellaviewcartridge.reset();
|
||||
|
||||
if(cartridge.hasICD2()) cpu.coprocessors.append(&icd2);
|
||||
if(cartridge.hasEvent()) cpu.coprocessors.append(&event);
|
||||
if(cartridge.hasSA1()) cpu.coprocessors.append(&sa1);
|
||||
if(cartridge.hasSuperFX()) cpu.coprocessors.append(&superfx);
|
||||
if(cartridge.hasARMDSP()) cpu.coprocessors.append(&armdsp);
|
||||
if(cartridge.hasHitachiDSP()) cpu.coprocessors.append(&hitachidsp);
|
||||
if(cartridge.hasNECDSP()) cpu.coprocessors.append(&necdsp);
|
||||
if(cartridge.hasEpsonRTC()) cpu.coprocessors.append(&epsonrtc);
|
||||
if(cartridge.hasSharpRTC()) cpu.coprocessors.append(&sharprtc);
|
||||
if(cartridge.hasSPC7110()) cpu.coprocessors.append(&spc7110);
|
||||
if(cartridge.hasMSU1()) cpu.coprocessors.append(&msu1);
|
||||
|
||||
scheduler.init();
|
||||
input.connect(0, configuration.controller_port1);
|
||||
|
@ -7,8 +7,8 @@ Emulator::Interface* emulator = nullptr;
|
||||
//if file already exists in the same path as the binary; use it (portable mode)
|
||||
//if not, use default requested path (*nix/user mode)
|
||||
auto locate(string pathname, string filename) -> string {
|
||||
string location = {programpath(), filename};
|
||||
if(storage::exists(location)) return location;
|
||||
string location{programpath(), filename};
|
||||
if(file_system_object::exists(location)) return location;
|
||||
return {pathname, filename};
|
||||
}
|
||||
|
||||
|
@ -48,7 +48,7 @@ auto StateManager::doChangeSelected() -> void {
|
||||
if(buffer.size() >= 584) {
|
||||
string description;
|
||||
description.reserve(512);
|
||||
memory::copy(description.pointer(), buffer.data() + 72, 512);
|
||||
memory::copy(description.get(), buffer.data() + 72, 512);
|
||||
description.resize(description.length());
|
||||
descriptionValue.setEnabled(true).setText(description);
|
||||
return doUpdateControls();
|
||||
@ -65,7 +65,7 @@ auto StateManager::doRefresh() -> void {
|
||||
if(buffer.size() >= 584) {
|
||||
string description;
|
||||
description.reserve(512);
|
||||
memory::copy(description.pointer(), buffer.data() + 72, 512);
|
||||
memory::copy(description.get(), buffer.data() + 72, 512);
|
||||
description.resize(description.length());
|
||||
stateList.item(slot).cell(1).setText(description).setForegroundColor({0, 0, 0});
|
||||
} else {
|
||||
|
Loading…
Reference in New Issue
Block a user