Update to v095 release.

byuu says:

After 20 months of development, higan v095 is released at long last!

The most notable feature is vastly improved Game Boy Advance emulation.
With many thanks to endrift, Cydrak, Jonas Quinn and jchadwick, this
release contains substantially improved CPU timings and many bugfixes.
Being one of only two GBA emulators to offer ROM prefetch emulation,
higan is very near mGBA in terms of accuracy, and far ahead of all
others. As a result of these fixes, compatibility is also much higher
than in v094.

There are also several improvements to SNES emulation. Most
significantly is support for mid-scanline changes to the background mode
in the accuracy profile.

Due to substantial changes to the user interface library used by higan,
this release features yet again a brand-new UI. With the exception of
video shaders and NSS DIP switch selection, it is at feature-parity with
the previous UI. It also offers some new features that v094 lacked.

The cheat code database has also been updated to the latest version by
mightymo.
This commit is contained in:
Tim Allen 2015-10-08 22:04:42 +11:00
parent b113ecb5a3
commit b0e862613b
11 changed files with 1578 additions and 214 deletions

File diff suppressed because it is too large Load Diff

View File

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

View File

@ -1,7 +1,7 @@
include ../nall/GNUmakefile
include ../hiro/GNUmakefile
flags += -O3 -I..
flags += -I.. -O3
link +=
objects := obj/hiro.o obj/icarus.o
objects += $(if $(call streq,$(platform),windows),obj/resource.o)

25
nall/encode/url.hpp Normal file
View File

@ -0,0 +1,25 @@
#ifndef NALL_ENCODE_URL_HPP
#define NALL_ENCODE_URL_HPP
namespace nall { namespace Encode {
inline auto URL(const string& input) -> string {
string output;
for(auto c : input) {
if(c >= 'A' && c <= 'Z') { output.append(c); continue; }
if(c >= 'a' && c <= 'z') { output.append(c); continue; }
if(c >= '0' && c <= '9') { output.append(c); continue; }
if(c == '-' || c == '_' || c == '.' || c == '~') { output.append(c); continue; }
if(c == ' ') { output.append('+'); continue; }
unsigned hi = (c >> 4) & 15;
unsigned lo = (c >> 0) & 15;
output.append('%');
output.append((char)(hi < 10 ? ('0' + hi) : ('a' + hi - 10)));
output.append((char)(lo < 10 ? ('0' + lo) : ('a' + lo - 10)));
}
return output;
}
}}
#endif

View File

@ -91,19 +91,11 @@ struct file : file_system_object, varint {
}
static auto write(const string& filename, const string& text) -> bool {
file fp;
if(fp.open(filename, mode::write) == false) return false;
fp.print(text);
fp.close();
return true;
return write(filename, (const uint8_t*)text.data(), text.size());
}
static auto write(const string& filename, const vector<uint8_t>& buffer) -> bool {
file fp;
if(fp.open(filename, mode::write) == false) return false;
fp.write(buffer.data(), buffer.size());
fp.close();
return true;
return write(filename, buffer.data(), buffer.size());
}
static auto write(const string& filename, const uint8_t* data, unsigned size) -> bool {

View File

@ -11,47 +11,75 @@ struct Variable {
string value;
};
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;
struct SharedVariable {
SharedVariable(const string& name = "", const string& value = "") : shared(new Variable{name, value}) {}
explicit operator bool() const { return (bool)shared->name; }
auto operator()() const { return shared->value; }
auto& operator=(const string& value) { shared->value = value; return *this; }
auto name() const { return shared->name; }
auto value() const { return shared->value; }
auto& setName(const string& name) { shared->name = name; return *this; }
auto& setValue(const string& value = "") { shared->value = value; return *this; }
shared_pointer<Variable> shared;
};
auto Variables::append(const string& name, const string& value) -> void {
vector::append({name, value});
}
auto Variables::get(const string& name) const -> string {
for(auto& variable : *this) {
if(variable.name.iequals(name)) return variable.value;
}
return "";
}
auto Variables::remove(const string& name) -> void {
while(true) {
unsigned n = 0;
bool found = false;
for(auto& variable : *this) {
if(!variable.name.iequals(name)) { n++; continue; }
vector::remove(n);
found = true;
break;
struct Variables {
auto operator[](const string& name) const -> SharedVariable {
for(auto& variable : variables) {
if(variable.shared->name.iequals(name)) return variable;
}
if(found == false) break;
return {};
}
}
auto Variables::set(const string& name, const string& value) -> void {
for(auto& variable : *this) {
if(!variable.name.iequals(name)) continue;
variable.name = name;
variable.value = value;
return;
auto operator()(const string& name) -> SharedVariable {
for(auto& variable : variables) {
if(variable.shared->name.iequals(name)) return variable;
}
return append(name);
}
vector::append({name, value});
}
auto find(const string& name) const -> vector<SharedVariable> {
vector<SharedVariable> result;
for(auto& variable : variables) {
if(variable.shared->name.iequals(name)) result.append(variable);
}
return result;
}
auto assign(const string& name, const string& value = "") -> SharedVariable {
for(auto& variable : variables) {
if(variable.shared->name.iequals(name)) {
variable.shared->value = value;
return variable;
}
}
return append(name, value);
}
auto append(const string& name, const string& value = "") -> SharedVariable {
SharedVariable variable{name, value};
variables.append(variable);
return variable;
}
auto remove(const string& name) -> void {
for(auto n : rrange(variables)) {
if(variables[n].shared->name.iequals(name)) variables.remove(n);
}
}
auto size() const { return variables.size(); }
auto begin() const { return variables.begin(); }
auto end() const { return variables.end(); }
auto begin() { return variables.begin(); }
auto end() { return variables.end(); }
vector<SharedVariable> variables;
};
struct Message {
using type = Message;
@ -62,14 +90,11 @@ struct Message {
virtual auto body(const function<bool (const uint8_t* data, unsigned size)>& callback) const -> bool = 0;
virtual auto setBody() -> bool = 0;
virtual auto header(const string& name) const -> string { return _header.get(name); }
virtual auto appendHeader(const string& name, const string& value = "") -> type& { return _header.append(name, value), *this; }
virtual auto removeHeader(const string& name) -> type& { return _header.remove(name), *this; }
virtual auto setHeader(const string& name, const string& value = "") -> type& { return _header.set(name, value), *this; }
Variables header;
//private:
string _head;
string _body;
Variables _header;
};
}}

View File

@ -1,6 +1,8 @@
#ifndef NALL_HTTP_REQUEST_HPP
#define NALL_HTTP_REQUEST_HPP
#include <nall/decode/url.hpp>
#include <nall/encode/url.hpp>
#include <nall/http/message.hpp>
namespace nall { namespace HTTP {
@ -12,11 +14,11 @@ struct Request : Message {
explicit operator bool() const { return requestType() != RequestType::None; }
inline auto head(const function<bool (const uint8_t* data, unsigned size)>& callback) const -> bool;
inline auto setHead() -> bool;
inline auto head(const function<bool (const uint8_t* data, unsigned size)>& callback) const -> bool override;
inline auto setHead() -> bool override;
inline auto body(const function<bool (const uint8_t* data, unsigned size)>& callback) const -> bool;
inline auto setBody() -> bool;
inline auto body(const function<bool (const uint8_t* data, unsigned size)>& callback) const -> bool override;
inline auto setBody() -> bool override;
auto ipv4() const -> bool { return _ipv6 == false; }
auto ipv6() const -> bool { return _ipv6 == true; }
@ -28,27 +30,15 @@ struct Request : Message {
auto path() const -> string { return _path; }
auto setPath(const string& value) -> void { _path = value; }
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); }
auto get(const string& name) const -> string { return _get.get(name); }
auto setGet(const string& name, const string& value = "") -> void { _get.set(name, value); }
auto post(const string& name) const -> string { return _post.get(name); }
auto setPost(const string& name, const string& value = "") -> void { _post.set(name, value); }
Variables cookie;
Variables get;
Variables post;
//private:
bool _ipv6 = false;
string _ip;
RequestType _requestType = RequestType::None;
string _path;
Variables _cookie;
Variables _get;
Variables _post;
};
auto Request::head(const function<bool (const uint8_t*, unsigned)>& callback) const -> bool {
@ -56,10 +46,10 @@ auto Request::head(const function<bool (const uint8_t*, unsigned)>& callback) co
string output;
string request = path();
if(_get.size()) {
if(get.size()) {
request.append("?");
for(auto& get : _get) {
request.append(get.name, "=", get.value, "&");
for(auto& variable : get) {
request.append(Encode::URL(variable.name()), "=", Encode::URL(variable.value()), "&");
}
request.rtrim("&", 1L);
}
@ -71,8 +61,8 @@ auto Request::head(const function<bool (const uint8_t*, unsigned)>& callback) co
default: return false;
}
for(auto& header : _header) {
output.append(header.name, ": ", header.value, "\r\n");
for(auto& variable : header) {
output.append(variable.name(), ": ", variable.value(), "\r\n");
}
output.append("\r\n");
@ -81,7 +71,7 @@ auto Request::head(const function<bool (const uint8_t*, unsigned)>& callback) co
auto Request::setHead() -> bool {
lstring headers = _head.split("\n");
string request = headers.takeFirst().rtrim("\r");
string request = headers.takeFirst().rtrim("\r", 1L);
string requestHost;
if(request.iendsWith(" HTTP/1.0")) request.irtrim(" HTTP/1.0", 1L);
@ -106,8 +96,10 @@ auto Request::setHead() -> bool {
if(auto queryString = components(1)) {
for(auto& block : queryString.split("&")) {
lstring variable = block.split("=", 1L);
if(variable(0)) setGet(variable(0), variable(1));
auto p = block.split("=", 1L);
auto name = Decode::URL(p(0));
auto value = Decode::URL(p(1));
if(name) get.append(name, value);
}
}
@ -115,18 +107,19 @@ auto Request::setHead() -> bool {
if(header.beginsWith(" ") || header.beginsWith("\t")) continue;
auto part = header.split(":", 1L).strip();
if(!part[0] || part.size() != 2) continue;
appendHeader(part[0], part[1]);
this->header.append(part[0], part[1]);
if(part[0].iequals("Cookie")) {
for(auto& block : part[1].split(";")) {
lstring variable = block.split("=", 1L).strip();
variable(1).trim("\"", "\"");
if(variable(0)) setCookie(variable(0), variable(1));
auto p = block.split("=", 1L).strip();
auto name = p(0);
auto value = p(1).trim("\"", "\"", 1L);
if(name) cookie.append(name, value);
}
}
}
if(requestHost) setHeader("Host", requestHost); //request URI overrides host header
if(requestHost) header.assign("Host", requestHost); //request URI overrides host header
return true;
}
@ -142,10 +135,46 @@ auto Request::body(const function<bool (const uint8_t*, unsigned)>& callback) co
auto Request::setBody() -> bool {
if(requestType() == RequestType::Post) {
if(header("Content-Type").iequals("application/x-www-form-urlencoded")) {
auto contentType = header["Content-Type"].value();
if(contentType.iequals("application/x-www-form-urlencoded")) {
for(auto& block : _body.split("&")) {
lstring variable = block.rtrim("\r").split("=", 1L);
if(variable(0)) setPost(variable(0), variable(1));
auto p = block.rtrim("\r").split("=", 1L);
auto name = Decode::URL(p(0));
auto value = Decode::URL(p(1));
if(name) post.append(name, value);
}
} else if(contentType.imatch("multipart/form-data; boundary=?*")) {
auto boundary = contentType.iltrim("multipart/form-data; boundary=", 1L).trim("\"", "\"", 1L);
auto blocks = _body.split({"--", boundary}, 1024L); //limit blocks to prevent memory exhaustion
for(auto& block : blocks) block.trim("\r\n", "\r\n", 1L);
if(blocks.size() < 2 || (blocks.takeFirst(), !blocks.takeLast().beginsWith("--"))) return false;
for(auto& block : blocks) {
string name;
string filename;
string contentType;
auto segments = block.split("\r\n\r\n", 1L);
for(auto& segment : segments(0).split("\r\n")) {
auto statement = segment.split(":", 1L);
if(statement(0).ibeginsWith("Content-Disposition")) {
for(auto& component : statement(1).split(";")) {
auto part = component.split("=", 1L).strip();
if(part(0).iequals("name")) {
name = part(1).trim("\"", "\"", 1L);
} else if(part(0).iequals("filename")) {
filename = part(1).trim("\"", "\"", 1L);
}
}
} else if(statement(0).ibeginsWith("Content-Type")) {
contentType = statement(1).strip();
}
}
if(name) {
post.append(name, segments(1));
post.append({name, ".filename"}, filename);
post.append({name, ".content-type"}, contentType);
}
}
}
}

View File

@ -14,11 +14,11 @@ struct Response : Message {
explicit operator bool() const { return responseType() != 0; }
auto operator()(unsigned responseType) -> type& { return setResponseType(responseType); }
inline auto head(const function<bool (const uint8_t* data, unsigned size)>& callback) const -> bool;
inline auto setHead() -> bool;
inline auto head(const function<bool (const uint8_t* data, unsigned size)>& callback) const -> bool override;
inline auto setHead() -> bool override;
inline auto body(const function<bool (const uint8_t* data, unsigned size)>& callback) const -> bool;
inline auto setBody() -> bool;
inline auto body(const function<bool (const uint8_t* data, unsigned size)>& callback) const -> bool override;
inline auto setBody() -> bool override;
auto request() const -> const Request* { return _request; }
auto setRequest(const Request& value) -> type& { _request = &value; return *this; }
@ -26,10 +26,6 @@ struct Response : Message {
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 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; }
inline auto setData(const vector<uint8_t>& value) -> type&;
@ -61,8 +57,8 @@ auto Response::head(const function<bool (const uint8_t*, unsigned)>& callback) c
string output;
if(auto request = this->request()) {
if(auto eTag = header("ETag")) {
if(eTag == request->header("If-None-Match")) {
if(auto eTag = header["ETag"]) {
if(eTag.value() == request->header["If-None-Match"].value()) {
output.append("HTTP/1.1 304 Not Modified\r\n");
output.append("Connection: close\r\n");
output.append("\r\n");
@ -72,18 +68,18 @@ auto Response::head(const function<bool (const uint8_t*, unsigned)>& callback) c
}
output.append("HTTP/1.1 ", findResponseType(), "\r\n");
for(auto& header : _header) {
output.append(header.name, ": ", header.value, "\r\n");
for(auto& variable : header) {
output.append(variable.name(), ": ", variable.value(), "\r\n");
}
if(hasBody()) {
if(!header("Content-Length") && !header("Transfer-Encoding").iequals("chunked")) {
if(!header["Content-Length"] && !header["Transfer-Encoding"].value().iequals("chunked")) {
output.append("Content-Length: ", findContentLength(), "\r\n");
}
if(!header("Content-Type")) {
if(!header["Content-Type"]) {
output.append("Content-Type: ", findContentType(), "\r\n");
}
}
if(!header("Connection")) {
if(!header["Connection"]) {
output.append("Connection: close\r\n");
}
output.append("\r\n");
@ -105,7 +101,7 @@ auto Response::setHead() -> bool {
if(header.beginsWith(" ") || header.beginsWith("\t")) continue;
lstring variable = header.split(":", 1L).strip();
if(variable.size() != 2) continue;
appendHeader(variable[0], variable[1]);
this->header.append(variable[0], variable[1]);
}
return true;
@ -114,7 +110,7 @@ auto Response::setHead() -> 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";
bool chunked = header["Transfer-Encoding"].value() == "chunked";
if(chunked) {
string prefix = {hex(findContentLength()), "\r\n"};
@ -160,7 +156,7 @@ auto Response::hasBody() const -> bool {
}
auto Response::findContentLength() const -> unsigned {
if(auto contentLength = header("Content-Length")) return decimal(contentLength);
if(auto contentLength = header["Content-Length"]) return contentLength.value().decimal();
if(_body) return _body.size();
if(hasData()) return data().size();
if(hasFile()) return file::size(file());
@ -169,7 +165,7 @@ auto Response::findContentLength() const -> unsigned {
}
auto Response::findContentType() const -> string {
if(auto contentType = header("Content-Type")) return contentType;
if(auto contentType = header["Content-Type"]) return contentType.value();
if(hasData()) return "application/octet-stream";
if(hasFile()) return findContentType(suffixname(file()));
return "text/html; charset=utf-8";
@ -229,22 +225,22 @@ auto Response::findResponseType() const -> string {
auto Response::setData(const vector<uint8_t>& value) -> type& {
_data = value;
setHeader("Content-Length", value.size());
header.assign("Content-Length", value.size());
return *this;
}
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));
setHeader("Cache-Control", "public");
setHeader("ETag", eTag);
header.assign("Content-Length", file::size(value));
header.assign("Cache-Control", "public");
header.assign("ETag", eTag);
return *this;
}
auto Response::setText(const string& value) -> type& {
_text = value;
setHeader("Content-Length", value.size());
header.assign("Content-Length", value.size());
return *this;
}

View File

@ -11,13 +11,13 @@ namespace nall { namespace HTTP {
struct Role {
struct Settings {
signed connectionLimit = 1024; //server
signed headSizeLimit = 16384; //client, server
signed bodySizeLimit = 65536; //client, server
signed chunkSize = 32768; //client, server
signed threadStackSize = 131072; //server
signed timeoutReceive = 15000; //server
signed timeoutSend = 15000; //server
signed connectionLimit = 1 * 1024; //server
signed headSizeLimit = 16 * 1024; //client, server
signed bodySizeLimit = 8192 * 1024; //client, server
signed chunkSize = 32 * 1024; //client, server
signed threadStackSize = 128 * 1024; //server
signed timeoutReceive = 15 * 1000; //server
signed timeoutSend = 15 * 1000; //server
} settings;
inline auto configure(const string& parameters) -> bool;
@ -82,8 +82,8 @@ auto Role::download(signed fd, Message& message) -> bool {
if(head.endsWith("\r\n\r\n") || head.endsWith("\n\n")) {
headReceived = true;
if(!message.setHead()) return false;
chunked = message.header("Transfer-Encoding").iequals("chunked");
contentLength = decimal(message.header("Content-Length"));
chunked = message.header["Transfer-Encoding"].value().iequals("chunked");
contentLength = message.header["Content-Length"].value().decimal();
}
continue;

View File

@ -60,6 +60,7 @@
#include <nall/decode/url.hpp>
#include <nall/decode/zip.hpp>
#include <nall/encode/base64.hpp>
#include <nall/encode/url.hpp>
#include <nall/hash/crc16.hpp>
#include <nall/hash/crc32.hpp>
#include <nall/hash/sha256.hpp>

View File

@ -166,7 +166,7 @@ InputManager::InputManager() {
inputMapping->link = &input;
input.guid = (uintptr_t)inputMapping;
nodeDevice.append(inputMapping->assignment, inputMapping->name);
nodeDevice.append(inputMapping->assignment, string{inputMapping->name}.replace(" ", ""));
}
nodePort.append(nodeDevice, string{inputDevice.name}.replace(" ", ""));