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:
Tim Allen 2015-08-02 16:23:13 +10:00
parent 092cac9073
commit 1b0b54a690
81 changed files with 1191 additions and 1256 deletions

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@ -1,6 +1,8 @@
#ifndef NALL_BITVECTOR_HPP
#define NALL_BITVECTOR_HPP
#include <nall/memory.hpp>
namespace nall {
struct bitvector {

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View 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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@ -52,7 +52,7 @@ protected:
return;
#endif
char* output = target.pointer();
char* output = target.get();
while(length) {
if(*source == '&') {
if(!memory::compare(source, "&lt;", 4)) { *output++ = '<'; source += 4; length -= 4; continue; }

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@ -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(&regs, 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) {

View File

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

View File

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

View File

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

View File

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

View File

@ -1,6 +1,6 @@
#ifdef CARTRIDGE_CPP
void Cartridge::serialize(serializer& s) {
auto Cartridge::serialize(serializer& s) -> void {
s.array(ram.data(), ram.size());
}

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@ -63,9 +63,9 @@ struct ID {
SuperGameBoyBootROM,
BsxROM,
BsxRAM,
BsxPSRAM,
MCCROM,
MCCRAM,
MCCPSRAM,
SuperGameBoyManifest,
SuperGameBoyROM,

View File

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

View File

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

View File

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

View File

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