mirror of https://github.com/bsnes-emu/bsnes.git
Update to v092r07 release.
byuu says: - OpenGL should work on OS X now; it uses VAOs and VBOs, and is fully OpenGL 3.2 core compliant - all configuration files are now stored in BML format, instead of CFG format (half the size, much more readable) - some old nall libraries that were never used have been removed - make install works with or without root now (copies core files to /usr/share/higan [non-configurable]) - make install also works on OS X (copies to /Library/Application Support/higan)
This commit is contained in:
parent
0d75524791
commit
177e222ca7
|
@ -3,7 +3,7 @@
|
||||||
|
|
||||||
namespace Emulator {
|
namespace Emulator {
|
||||||
static const char Name[] = "higan";
|
static const char Name[] = "higan";
|
||||||
static const char Version[] = "092.06";
|
static const char Version[] = "092.07";
|
||||||
static const char Author[] = "byuu";
|
static const char Author[] = "byuu";
|
||||||
static const char License[] = "GPLv3";
|
static const char License[] = "GPLv3";
|
||||||
static const char Website[] = "http://byuu.org/";
|
static const char Website[] = "http://byuu.org/";
|
||||||
|
|
|
@ -1,126 +1,103 @@
|
||||||
#ifndef NALL_CONFIG_HPP
|
#ifndef NALL_CONFIG_HPP
|
||||||
#define NALL_CONFIG_HPP
|
#define NALL_CONFIG_HPP
|
||||||
|
|
||||||
|
#include <nall/platform.hpp>
|
||||||
#include <nall/file.hpp>
|
#include <nall/file.hpp>
|
||||||
#include <nall/string.hpp>
|
#include <nall/string.hpp>
|
||||||
#include <nall/vector.hpp>
|
|
||||||
|
|
||||||
namespace nall {
|
namespace nall {
|
||||||
namespace configuration_traits {
|
namespace Configuration {
|
||||||
template<typename T> struct is_boolean { enum { value = false }; };
|
|
||||||
template<> struct is_boolean<bool> { enum { value = true }; };
|
|
||||||
|
|
||||||
template<typename T> struct is_signed { enum { value = false }; };
|
struct Node {
|
||||||
template<> struct is_signed<signed> { enum { value = true }; };
|
string name;
|
||||||
|
string desc;
|
||||||
|
enum class Type : unsigned { Null, Bool, Signed, Unsigned, Double, String } type = Type::Null;
|
||||||
|
void* data = nullptr;
|
||||||
|
vector<Node> children;
|
||||||
|
|
||||||
template<typename T> struct is_unsigned { enum { value = false }; };
|
bool empty() const {
|
||||||
template<> struct is_unsigned<unsigned> { enum { value = true }; };
|
return data == nullptr;
|
||||||
|
|
||||||
template<typename T> struct is_double { enum { value = false }; };
|
|
||||||
template<> struct is_double<double> { enum { value = true }; };
|
|
||||||
|
|
||||||
template<typename T> struct is_string { enum { value = false }; };
|
|
||||||
template<> struct is_string<string> { enum { value = true }; };
|
|
||||||
}
|
}
|
||||||
|
|
||||||
class configuration {
|
string get() const {
|
||||||
public:
|
switch(type) {
|
||||||
enum type_t { boolean_t, signed_t, unsigned_t, double_t, string_t, unknown_t };
|
case Type::Bool: return {*(bool*)data};
|
||||||
struct item_t {
|
case Type::Signed: return {*(signed*)data};
|
||||||
uintptr_t data;
|
case Type::Unsigned: return {*(unsigned*)data};
|
||||||
string name;
|
case Type::Double: return {*(double*)data};
|
||||||
string desc;
|
case Type::String: return {*(string*)data};
|
||||||
type_t type;
|
|
||||||
|
|
||||||
inline string get() const {
|
|
||||||
switch(type) {
|
|
||||||
case boolean_t: return { *(bool*)data };
|
|
||||||
case signed_t: return { *(signed*)data };
|
|
||||||
case unsigned_t: return { *(unsigned*)data };
|
|
||||||
case double_t: return { *(double*)data };
|
|
||||||
case string_t: return { "\"", *(string*)data, "\"" };
|
|
||||||
}
|
|
||||||
return "???";
|
|
||||||
}
|
|
||||||
|
|
||||||
inline void set(string s) {
|
|
||||||
switch(type) {
|
|
||||||
case boolean_t: *(bool*)data = (s == "true"); break;
|
|
||||||
case signed_t: *(signed*)data = integer(s); break;
|
|
||||||
case unsigned_t: *(unsigned*)data = decimal(s); break;
|
|
||||||
case double_t: *(double*)data = fp(s); break;
|
|
||||||
case string_t: s.trim("\""); *(string*)data = s; break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
};
|
|
||||||
vector<item_t> list;
|
|
||||||
|
|
||||||
template<typename T>
|
|
||||||
inline void append(T &data, const char *name, const char *desc = "") {
|
|
||||||
item_t item = { (uintptr_t)&data, name, desc };
|
|
||||||
if(configuration_traits::is_boolean<T>::value) item.type = boolean_t;
|
|
||||||
else if(configuration_traits::is_signed<T>::value) item.type = signed_t;
|
|
||||||
else if(configuration_traits::is_unsigned<T>::value) item.type = unsigned_t;
|
|
||||||
else if(configuration_traits::is_double<T>::value) item.type = double_t;
|
|
||||||
else if(configuration_traits::is_string<T>::value) item.type = string_t;
|
|
||||||
else item.type = unknown_t;
|
|
||||||
list.append(item);
|
|
||||||
}
|
}
|
||||||
|
return "";
|
||||||
|
}
|
||||||
|
|
||||||
//deprecated
|
void set(const string& value) {
|
||||||
template<typename T>
|
switch(type) {
|
||||||
inline void attach(T &data, const char *name, const char *desc = "") {
|
case Type::Bool: *(bool*)data = (value == "true"); break;
|
||||||
append(data, name, desc);
|
case Type::Signed: *(signed*)data = integer(value); break;
|
||||||
|
case Type::Unsigned: *(unsigned*)data = decimal(value); break;
|
||||||
|
case Type::Double: *(double*)data = fp(value); break;
|
||||||
|
case Type::String: *(string*)data = value; break;
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
inline virtual bool load(const string &filename) {
|
void assign() { type = Type::Null; data = nullptr; }
|
||||||
string data;
|
void assign(bool& bind) { type = Type::Bool; data = (void*)&bind; }
|
||||||
if(data.readfile(filename) == true) {
|
void assign(signed& bind) { type = Type::Signed; data = (void*)&bind; }
|
||||||
data.replace("\r", "");
|
void assign(unsigned& bind) { type = Type::Unsigned; data = (void*)&bind; }
|
||||||
lstring line;
|
void assign(double& bind) { type = Type::Double; data = (void*)&bind; }
|
||||||
line.split("\n", data);
|
void assign(string& bind) { type = Type::String; data = (void*)&bind; }
|
||||||
|
void assign(const Node& node) { operator=(node); }
|
||||||
|
|
||||||
for(unsigned i = 0; i < line.size(); i++) {
|
template<typename T> void append(T& data, const string& name, const string& desc = "") {
|
||||||
if(auto position = qstrpos(line[i], "#")) line[i][position()] = 0;
|
Node node;
|
||||||
if(!qstrpos(line[i], " = ")) continue;
|
node.assign(data);
|
||||||
|
node.name = name;
|
||||||
|
node.desc = desc;
|
||||||
|
children.append(node);
|
||||||
|
}
|
||||||
|
|
||||||
lstring part;
|
void load(Markup::Node path) {
|
||||||
part.qsplit(" = ", line[i]);
|
for(auto& child : children) {
|
||||||
part[0].trim();
|
auto leaf = path[child.name];
|
||||||
part[1].trim();
|
if(!leaf.exists()) continue;
|
||||||
|
if(!child.empty()) child.set(leaf.data.trim<1>(" ", "\r"));
|
||||||
|
child.load(leaf);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
for(unsigned n = 0; n < list.size(); n++) {
|
void save(file& fp, unsigned depth = 0) {
|
||||||
if(part[0] == list[n].name) {
|
for(auto& child : children) {
|
||||||
list[n].set(part[1]);
|
if(child.desc) {
|
||||||
break;
|
for(unsigned n = 0; n < depth; n++) fp.print(" ");
|
||||||
}
|
fp.print("//", child.desc, "\n");
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return true;
|
|
||||||
} else {
|
|
||||||
return false;
|
|
||||||
}
|
}
|
||||||
|
for(unsigned n = 0; n < depth; n++) fp.print(" ");
|
||||||
|
fp.print(child.name);
|
||||||
|
if(!child.empty()) fp.print(": ", child.get());
|
||||||
|
fp.print("\n");
|
||||||
|
child.save(fp, depth + 1);
|
||||||
|
if(depth == 0) fp.print("\n");
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
inline virtual bool save(const string &filename) const {
|
struct Document : Node {
|
||||||
file fp;
|
bool load(const string& filename) {
|
||||||
if(fp.open(filename, file::mode::write)) {
|
if(!file::exists(filename)) return false;
|
||||||
for(unsigned i = 0; i < list.size(); i++) {
|
auto document = Markup::Document(string::read(filename));
|
||||||
string output;
|
Node::load(document);
|
||||||
output.append(list[i].name, " = ", list[i].get());
|
return true;
|
||||||
if(list[i].desc != "") output.append(" # ", list[i].desc);
|
}
|
||||||
output.append("\r\n");
|
|
||||||
fp.print(output);
|
|
||||||
}
|
|
||||||
|
|
||||||
fp.close();
|
bool save(const string& filename) {
|
||||||
return true;
|
file fp(filename, file::mode::write);
|
||||||
} else {
|
if(!fp.open()) return false;
|
||||||
return false;
|
Node::save(fp);
|
||||||
}
|
return true;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
|
@ -1,46 +1,25 @@
|
||||||
#ifndef NALL_SET_HPP
|
#ifndef NALL_GROUP_HPP
|
||||||
#define NALL_SET_HPP
|
#define NALL_GROUP_HPP
|
||||||
|
|
||||||
//set
|
//group: a vector of unique references
|
||||||
//* unordered
|
|
||||||
//* intended for unique items
|
|
||||||
//* dynamic growth
|
|
||||||
//* reference-based variant
|
|
||||||
|
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
#include <algorithm>
|
#include <algorithm>
|
||||||
#include <initializer_list>
|
#include <initializer_list>
|
||||||
#include <utility>
|
#include <utility>
|
||||||
#include <nall/algorithm.hpp>
|
|
||||||
#include <nall/bit.hpp>
|
#include <nall/bit.hpp>
|
||||||
#include <nall/sort.hpp>
|
|
||||||
#include <nall/traits.hpp>
|
#include <nall/traits.hpp>
|
||||||
#include <nall/utility.hpp>
|
|
||||||
|
|
||||||
namespace nall {
|
namespace nall {
|
||||||
|
|
||||||
template<typename T, typename Enable = void> struct set;
|
template<typename TR> struct group {
|
||||||
|
|
||||||
template<typename T> struct set<T, typename std::enable_if<!std::is_reference<T>::value>::type> {
|
|
||||||
struct exception_out_of_bounds{};
|
struct exception_out_of_bounds{};
|
||||||
|
|
||||||
protected:
|
|
||||||
T *pool;
|
|
||||||
unsigned poolsize, objectsize;
|
|
||||||
|
|
||||||
public:
|
|
||||||
unsigned size() const { return objectsize; }
|
|
||||||
unsigned capacity() const { return poolsize; }
|
|
||||||
};
|
|
||||||
|
|
||||||
//reference set
|
|
||||||
template<typename TR> struct set<TR, typename std::enable_if<std::is_reference<TR>::value>::type> {
|
|
||||||
struct exception_out_of_bounds{};
|
|
||||||
|
|
||||||
protected:
|
|
||||||
typedef typename std::remove_reference<TR>::type T;
|
typedef typename std::remove_reference<TR>::type T;
|
||||||
T **pool;
|
|
||||||
unsigned poolsize, objectsize;
|
protected:
|
||||||
|
T** pool = nullptr;
|
||||||
|
unsigned poolsize = 0;
|
||||||
|
unsigned objectsize = 0;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
unsigned size() const { return objectsize; }
|
unsigned size() const { return objectsize; }
|
||||||
|
@ -94,27 +73,26 @@ public:
|
||||||
return {false, 0u};
|
return {false, 0u};
|
||||||
}
|
}
|
||||||
|
|
||||||
template<typename... Args> set(Args&&... args) : pool(nullptr), poolsize(0), objectsize(0) {
|
template<typename... Args> group(Args&&... args) {
|
||||||
construct(std::forward<Args>(args)...);
|
construct(std::forward<Args>(args)...);
|
||||||
}
|
}
|
||||||
|
|
||||||
~set() {
|
~group() {
|
||||||
reset();
|
reset();
|
||||||
}
|
}
|
||||||
|
|
||||||
set& operator=(const set &source) {
|
group& operator=(const group& source) {
|
||||||
if(&source == this) return *this;
|
if(&source == this) return *this;
|
||||||
if(pool) free(pool);
|
reset();
|
||||||
objectsize = source.objectsize;
|
reserve(source.poolsize);
|
||||||
poolsize = source.poolsize;
|
resize(source.objectsize);
|
||||||
pool = (T**)malloc(sizeof(T*) * poolsize);
|
|
||||||
memcpy(pool, source.pool, sizeof(T*) * objectsize);
|
memcpy(pool, source.pool, sizeof(T*) * objectsize);
|
||||||
return *this;
|
return *this;
|
||||||
}
|
}
|
||||||
|
|
||||||
set& operator=(const set &&source) {
|
group& operator=(const group&& source) {
|
||||||
if(&source == this) return *this;
|
if(&source == this) return *this;
|
||||||
if(pool) free(pool);
|
reset();
|
||||||
pool = source.pool;
|
pool = source.pool;
|
||||||
poolsize = source.poolsize;
|
poolsize = source.poolsize;
|
||||||
objectsize = source.objectsize;
|
objectsize = source.objectsize;
|
||||||
|
@ -129,12 +107,12 @@ public:
|
||||||
}
|
}
|
||||||
|
|
||||||
struct iterator {
|
struct iterator {
|
||||||
bool operator!=(const iterator &source) const { return position != source.position; }
|
bool operator!=(const iterator& source) const { return position != source.position; }
|
||||||
T& operator*() { return source.operator[](position); }
|
T& operator*() { return source.operator[](position); }
|
||||||
iterator& operator++() { position++; return *this; }
|
iterator& operator++() { position++; return *this; }
|
||||||
iterator(const set &source, unsigned position) : source(source), position(position) {}
|
iterator(const group& source, unsigned position) : source(source), position(position) {}
|
||||||
private:
|
private:
|
||||||
const set &source;
|
const group& source;
|
||||||
unsigned position;
|
unsigned position;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -145,8 +123,8 @@ public:
|
||||||
|
|
||||||
private:
|
private:
|
||||||
void construct() {}
|
void construct() {}
|
||||||
void construct(const set &source) { operator=(source); }
|
void construct(const group& source) { operator=(source); }
|
||||||
void construct(const set &&source) { operator=(std::move(source)); }
|
void construct(const group&& source) { operator=(std::move(source)); }
|
||||||
template<typename... Args> void construct(T& data, Args&&... args) {
|
template<typename... Args> void construct(T& data, Args&&... args) {
|
||||||
append(data);
|
append(data);
|
||||||
construct(std::forward<Args>(args)...);
|
construct(std::forward<Args>(args)...);
|
|
@ -1,165 +0,0 @@
|
||||||
#ifndef NALL_LZSS_HPP
|
|
||||||
#define NALL_LZSS_HPP
|
|
||||||
|
|
||||||
#include <nall/file.hpp>
|
|
||||||
#include <nall/filemap.hpp>
|
|
||||||
#include <nall/stdint.hpp>
|
|
||||||
#include <nall/string.hpp>
|
|
||||||
|
|
||||||
namespace nall {
|
|
||||||
|
|
||||||
//19:5 pulldown
|
|
||||||
//8:1 marker: d7-d0
|
|
||||||
//length: { 4 - 35 }, offset: { 1 - 0x80000 }
|
|
||||||
//4-byte file size header
|
|
||||||
//little-endian encoding
|
|
||||||
struct lzss {
|
|
||||||
inline void source(const uint8_t *data, unsigned size);
|
|
||||||
inline bool source(const string &filename);
|
|
||||||
inline unsigned size() const;
|
|
||||||
inline bool compress(const string &filename);
|
|
||||||
inline bool decompress(uint8_t *targetData, unsigned targetSize);
|
|
||||||
inline bool decompress(const string &filename);
|
|
||||||
|
|
||||||
protected:
|
|
||||||
struct Node {
|
|
||||||
unsigned offset;
|
|
||||||
Node *next;
|
|
||||||
inline Node() : offset(0), next(nullptr) {}
|
|
||||||
inline ~Node() { if(next) delete next; }
|
|
||||||
} *tree[65536];
|
|
||||||
|
|
||||||
filemap sourceFile;
|
|
||||||
const uint8_t *sourceData;
|
|
||||||
unsigned sourceSize;
|
|
||||||
|
|
||||||
public:
|
|
||||||
inline lzss() : sourceData(nullptr), sourceSize(0) {}
|
|
||||||
};
|
|
||||||
|
|
||||||
void lzss::source(const uint8_t *data, unsigned size) {
|
|
||||||
sourceData = data;
|
|
||||||
sourceSize = size;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool lzss::source(const string &filename) {
|
|
||||||
if(sourceFile.open(filename, filemap::mode::read) == false) return false;
|
|
||||||
sourceData = sourceFile.data();
|
|
||||||
sourceSize = sourceFile.size();
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
unsigned lzss::size() const {
|
|
||||||
unsigned size = 0;
|
|
||||||
if(sourceSize < 4) return size;
|
|
||||||
for(unsigned n = 0; n < 32; n += 8) size |= sourceData[n >> 3] << n;
|
|
||||||
return size;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool lzss::compress(const string &filename) {
|
|
||||||
file targetFile;
|
|
||||||
if(targetFile.open(filename, file::mode::write) == false) return false;
|
|
||||||
|
|
||||||
for(unsigned n = 0; n < 32; n += 8) targetFile.write(sourceSize >> n);
|
|
||||||
for(unsigned n = 0; n < 65536; n++) tree[n] = nullptr;
|
|
||||||
|
|
||||||
uint8_t buffer[25];
|
|
||||||
unsigned sourceOffset = 0;
|
|
||||||
|
|
||||||
while(sourceOffset < sourceSize) {
|
|
||||||
uint8_t mask = 0x00;
|
|
||||||
unsigned bufferOffset = 1;
|
|
||||||
|
|
||||||
for(unsigned iteration = 0; iteration < 8; iteration++) {
|
|
||||||
if(sourceOffset >= sourceSize) break;
|
|
||||||
|
|
||||||
uint16_t symbol = sourceData[sourceOffset + 0];
|
|
||||||
if(sourceOffset < sourceSize - 1) symbol |= sourceData[sourceOffset + 1] << 8;
|
|
||||||
Node *node = tree[symbol];
|
|
||||||
unsigned maxLength = 0, maxOffset = 0;
|
|
||||||
|
|
||||||
while(node) {
|
|
||||||
if(node->offset < sourceOffset - 0x80000) {
|
|
||||||
//out-of-range: all subsequent nodes will also be, so free up their memory
|
|
||||||
if(node->next) { delete node->next; node->next = nullptr; }
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
unsigned length = 0, x = sourceOffset, y = node->offset;
|
|
||||||
while(length < 35 && x < sourceSize && sourceData[x++] == sourceData[y++]) length++;
|
|
||||||
if(length > maxLength) maxLength = length, maxOffset = node->offset;
|
|
||||||
if(length == 35) break;
|
|
||||||
|
|
||||||
node = node->next;
|
|
||||||
}
|
|
||||||
|
|
||||||
//attach current symbol to top of tree for subsequent searches
|
|
||||||
node = new Node;
|
|
||||||
node->offset = sourceOffset;
|
|
||||||
node->next = tree[symbol];
|
|
||||||
tree[symbol] = node;
|
|
||||||
|
|
||||||
if(maxLength < 4) {
|
|
||||||
buffer[bufferOffset++] = sourceData[sourceOffset++];
|
|
||||||
} else {
|
|
||||||
unsigned output = ((maxLength - 4) << 19) | (sourceOffset - 1 - maxOffset);
|
|
||||||
for(unsigned n = 0; n < 24; n += 8) buffer[bufferOffset++] = output >> n;
|
|
||||||
mask |= 0x80 >> iteration;
|
|
||||||
sourceOffset += maxLength;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
buffer[0] = mask;
|
|
||||||
targetFile.write(buffer, bufferOffset);
|
|
||||||
}
|
|
||||||
|
|
||||||
sourceFile.close();
|
|
||||||
targetFile.close();
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool lzss::decompress(uint8_t *targetData, unsigned targetSize) {
|
|
||||||
if(targetSize < size()) return false;
|
|
||||||
|
|
||||||
unsigned sourceOffset = 4, targetOffset = 0;
|
|
||||||
while(sourceOffset < sourceSize) {
|
|
||||||
uint8_t mask = sourceData[sourceOffset++];
|
|
||||||
|
|
||||||
for(unsigned iteration = 0; iteration < 8; iteration++) {
|
|
||||||
if(sourceOffset >= sourceSize) break;
|
|
||||||
|
|
||||||
if((mask & (0x80 >> iteration)) == 0) {
|
|
||||||
targetData[targetOffset++] = sourceData[sourceOffset++];
|
|
||||||
} else {
|
|
||||||
unsigned code = 0;
|
|
||||||
for(unsigned n = 0; n < 24; n += 8) code |= sourceData[sourceOffset++] << n;
|
|
||||||
unsigned length = (code >> 19) + 4;
|
|
||||||
unsigned offset = targetOffset - 1 - (code & 0x7ffff);
|
|
||||||
while(length--) targetData[targetOffset++] = targetData[offset++];
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
bool lzss::decompress(const string &filename) {
|
|
||||||
if(sourceSize < 4) return false;
|
|
||||||
unsigned targetSize = size();
|
|
||||||
|
|
||||||
file fp;
|
|
||||||
if(fp.open(filename, file::mode::write) == false) return false;
|
|
||||||
fp.truncate(targetSize);
|
|
||||||
fp.close();
|
|
||||||
|
|
||||||
filemap targetFile;
|
|
||||||
if(targetFile.open(filename, filemap::mode::readwrite) == false) return false;
|
|
||||||
uint8_t *targetData = targetFile.data();
|
|
||||||
|
|
||||||
bool result = decompress(targetData, targetSize);
|
|
||||||
sourceFile.close();
|
|
||||||
targetFile.close();
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
#endif
|
|
|
@ -21,6 +21,7 @@
|
||||||
#include <nall/file.hpp>
|
#include <nall/file.hpp>
|
||||||
#include <nall/filemap.hpp>
|
#include <nall/filemap.hpp>
|
||||||
#include <nall/function.hpp>
|
#include <nall/function.hpp>
|
||||||
|
#include <nall/group.hpp>
|
||||||
#include <nall/gzip.hpp>
|
#include <nall/gzip.hpp>
|
||||||
#include <nall/http.hpp>
|
#include <nall/http.hpp>
|
||||||
#include <nall/image.hpp>
|
#include <nall/image.hpp>
|
||||||
|
@ -34,7 +35,6 @@
|
||||||
#include <nall/property.hpp>
|
#include <nall/property.hpp>
|
||||||
#include <nall/random.hpp>
|
#include <nall/random.hpp>
|
||||||
#include <nall/serializer.hpp>
|
#include <nall/serializer.hpp>
|
||||||
#include <nall/set.hpp>
|
|
||||||
#include <nall/sha256.hpp>
|
#include <nall/sha256.hpp>
|
||||||
#include <nall/sort.hpp>
|
#include <nall/sort.hpp>
|
||||||
#include <nall/stdint.hpp>
|
#include <nall/stdint.hpp>
|
||||||
|
|
|
@ -29,6 +29,7 @@ namespace nall {
|
||||||
inline static string time();
|
inline static string time();
|
||||||
inline static string datetime();
|
inline static string datetime();
|
||||||
|
|
||||||
|
inline void reset();
|
||||||
inline void reserve(unsigned);
|
inline void reserve(unsigned);
|
||||||
inline void resize(unsigned);
|
inline void resize(unsigned);
|
||||||
inline void clear(char);
|
inline void clear(char);
|
||||||
|
|
|
@ -11,6 +11,11 @@ static void istring(string &output, const T &value, Args&&... args) {
|
||||||
istring(output, std::forward<Args>(args)...);
|
istring(output, std::forward<Args>(args)...);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void string::reset() {
|
||||||
|
resize(64);
|
||||||
|
*data = 0;
|
||||||
|
}
|
||||||
|
|
||||||
void string::reserve(unsigned size_) {
|
void string::reserve(unsigned size_) {
|
||||||
if(size_ > size) resize(size_);
|
if(size_ > size) resize(size_);
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
#ifdef NALL_STRING_INTERNAL_HPP
|
#ifdef NALL_STRING_INTERNAL_HPP
|
||||||
|
|
||||||
//BML v1.0 parser
|
//BML v1.0 parser
|
||||||
//revision 0.02
|
//revision 0.03
|
||||||
|
|
||||||
namespace nall {
|
namespace nall {
|
||||||
namespace BML {
|
namespace BML {
|
||||||
|
@ -9,8 +9,8 @@ namespace BML {
|
||||||
struct Node : Markup::Node {
|
struct Node : Markup::Node {
|
||||||
protected:
|
protected:
|
||||||
//test to verify if a valid character for a node name
|
//test to verify if a valid character for a node name
|
||||||
bool valid(char p) const { //A-Z, a-z, 0-9, -./
|
bool valid(char p) const { //A-Z, a-z, 0-9, -.
|
||||||
return p - 'A' < 26u || p - 'a' < 26u || p - '0' < 10u || p - '-' < 3u;
|
return p - 'A' < 26u || p - 'a' < 26u || p - '0' < 10u || p - '-' < 2u;
|
||||||
}
|
}
|
||||||
|
|
||||||
//determine indentation level, without incrementing pointer
|
//determine indentation level, without incrementing pointer
|
||||||
|
@ -41,13 +41,13 @@ protected:
|
||||||
unsigned length = 2;
|
unsigned length = 2;
|
||||||
while(p[length] && p[length] != '\n' && p[length] != '\"') length++;
|
while(p[length] && p[length] != '\n' && p[length] != '\"') length++;
|
||||||
if(p[length] != '\"') throw "Unescaped value";
|
if(p[length] != '\"') throw "Unescaped value";
|
||||||
data = substr(p, 2, length - 2);
|
data = {substr(p, 2, length - 2), "\n"};
|
||||||
p += length + 1;
|
p += length + 1;
|
||||||
} else if(*p == '=') {
|
} else if(*p == '=') {
|
||||||
unsigned length = 1;
|
unsigned length = 1;
|
||||||
while(p[length] && p[length] != '\n' && p[length] != '\"' && p[length] != ' ') length++;
|
while(p[length] && p[length] != '\n' && p[length] != '\"' && p[length] != ' ') length++;
|
||||||
if(p[length] == '\"') throw "Illegal character in value";
|
if(p[length] == '\"') throw "Illegal character in value";
|
||||||
data = substr(p, 1, length - 1);
|
data = {substr(p, 1, length - 1), "\n"};
|
||||||
p += length;
|
p += length;
|
||||||
} else if(*p == ':') {
|
} else if(*p == ':') {
|
||||||
unsigned length = 1;
|
unsigned length = 1;
|
||||||
|
@ -62,6 +62,7 @@ protected:
|
||||||
while(*p && *p != '\n') {
|
while(*p && *p != '\n') {
|
||||||
if(*p != ' ') throw "Invalid node name";
|
if(*p != ' ') throw "Invalid node name";
|
||||||
while(*p == ' ') p++; //skip excess spaces
|
while(*p == ' ') p++; //skip excess spaces
|
||||||
|
if(*(p + 0) == '/' && *(p + 1) == '/') break; //skip comments
|
||||||
|
|
||||||
Node node;
|
Node node;
|
||||||
node.attribute = true;
|
node.attribute = true;
|
||||||
|
@ -70,35 +71,30 @@ protected:
|
||||||
if(length == 0) throw "Invalid attribute name";
|
if(length == 0) throw "Invalid attribute name";
|
||||||
node.name = substr(p, 0, length);
|
node.name = substr(p, 0, length);
|
||||||
node.parseData(p += length);
|
node.parseData(p += length);
|
||||||
|
node.data.rtrim<1>("\n");
|
||||||
children.append(node);
|
children.append(node);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
//read a node and all of its children nodes
|
//read a node and all of its child nodes
|
||||||
void parseNode(const char *&p) {
|
void parseNode(const lstring &text, unsigned &y) {
|
||||||
|
const char *p = text[y++];
|
||||||
level = parseDepth(p);
|
level = parseDepth(p);
|
||||||
parseName(p);
|
parseName(p);
|
||||||
parseData(p);
|
parseData(p);
|
||||||
parseAttributes(p);
|
parseAttributes(p);
|
||||||
if(*p && *p++ != '\n') throw "Missing line feed";
|
|
||||||
|
|
||||||
while(*p) {
|
while(y < text.size()) {
|
||||||
if(*p == '\n') { p++; continue; }
|
unsigned depth = readDepth(text[y]);
|
||||||
|
|
||||||
unsigned depth = readDepth(p);
|
|
||||||
if(depth <= level) break;
|
if(depth <= level) break;
|
||||||
|
|
||||||
if(p[depth] == ':') {
|
if(text[y][depth] == ':') {
|
||||||
p += depth;
|
data.append(substr(text[y++], depth + 1), "\n");
|
||||||
unsigned length = 0;
|
|
||||||
while(p[length] && p[length] != '\n') length++;
|
|
||||||
data.append(substr(p, 1, length - 1), "\n");
|
|
||||||
p += length;
|
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
Node node;
|
Node node;
|
||||||
node.parseNode(p);
|
node.parseNode(text, y);
|
||||||
children.append(node);
|
children.append(node);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -106,10 +102,27 @@ protected:
|
||||||
}
|
}
|
||||||
|
|
||||||
//read top-level nodes
|
//read top-level nodes
|
||||||
void parse(const char *p) {
|
void parse(const string &document) {
|
||||||
while(*p) {
|
lstring text = document.split("\n");
|
||||||
|
|
||||||
|
//remove empty lines and comment lines
|
||||||
|
for(unsigned y = 0; y < text.size();) {
|
||||||
|
text[y].rtrim<1>("\n");
|
||||||
|
unsigned x = 0;
|
||||||
|
bool empty = true;
|
||||||
|
while(text[y][x]) {
|
||||||
|
if(text[y][x] == ' ' || text[y][x] == '\t') { x++; continue; }
|
||||||
|
empty = (text[y][x + 0] == '/' && text[y][x + 1] == '/');
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
if(empty) text.remove(y);
|
||||||
|
else y++;
|
||||||
|
}
|
||||||
|
|
||||||
|
unsigned y = 0;
|
||||||
|
while(y < text.size()) {
|
||||||
Node node;
|
Node node;
|
||||||
node.parseNode(p);
|
node.parseNode(text, y);
|
||||||
if(node.level > 0) throw "Root nodes cannot be indented";
|
if(node.level > 0) throw "Root nodes cannot be indented";
|
||||||
children.append(node);
|
children.append(node);
|
||||||
}
|
}
|
||||||
|
@ -121,15 +134,13 @@ protected:
|
||||||
struct Document : Node {
|
struct Document : Node {
|
||||||
string error;
|
string error;
|
||||||
|
|
||||||
bool load(string document) {
|
bool load(const string &document) {
|
||||||
name = "{root}", data = "";
|
name = "", data = "";
|
||||||
|
|
||||||
try {
|
try {
|
||||||
document.replace("\r", "");
|
|
||||||
while(document.position("\n\n")) document.replace("\n\n", "\n");
|
|
||||||
parse(document);
|
parse(document);
|
||||||
} catch(const char *perror) {
|
} catch(const char *error) {
|
||||||
error = perror;
|
this->error = error;
|
||||||
children.reset();
|
children.reset();
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
|
@ -80,7 +80,7 @@ string sharedpath() {
|
||||||
#elif defined(PLATFORM_OSX)
|
#elif defined(PLATFORM_OSX)
|
||||||
result = "/Library/Application Support/";
|
result = "/Library/Application Support/";
|
||||||
#else
|
#else
|
||||||
result = "/etc/";
|
result = "/usr/share/";
|
||||||
#endif
|
#endif
|
||||||
if(result.empty()) result = ".";
|
if(result.empty()) result = ".";
|
||||||
if(result.endswith("/") == false) result.append("/");
|
if(result.endswith("/") == false) result.append("/");
|
||||||
|
|
|
@ -5,6 +5,7 @@
|
||||||
#include <nall/string.hpp>
|
#include <nall/string.hpp>
|
||||||
|
|
||||||
#include <shlwapi.h>
|
#include <shlwapi.h>
|
||||||
|
#undef interface
|
||||||
#ifndef KEY_WOW64_64KEY
|
#ifndef KEY_WOW64_64KEY
|
||||||
#define KEY_WOW64_64KEY 0x0100
|
#define KEY_WOW64_64KEY 0x0100
|
||||||
#endif
|
#endif
|
||||||
|
|
|
@ -4,6 +4,7 @@
|
||||||
#define None
|
#define None
|
||||||
#undef XlibNone
|
#undef XlibNone
|
||||||
#define XlibNone 0L
|
#define XlibNone 0L
|
||||||
|
#define Bool XlibBool
|
||||||
#define Button1 XlibButton1
|
#define Button1 XlibButton1
|
||||||
#define Button2 XlibButton2
|
#define Button2 XlibButton2
|
||||||
#define Button3 XlibButton3
|
#define Button3 XlibButton3
|
||||||
|
@ -17,6 +18,7 @@
|
||||||
#undef NALL_XORG_GUARD_HPP
|
#undef NALL_XORG_GUARD_HPP
|
||||||
|
|
||||||
#undef None
|
#undef None
|
||||||
|
#undef Bool
|
||||||
#undef Button1
|
#undef Button1
|
||||||
#undef Button2
|
#undef Button2
|
||||||
#undef Button3
|
#undef Button3
|
||||||
|
|
|
@ -34,7 +34,7 @@ void pRadioItem::setChecked() {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void pRadioItem::setGroup(const set<RadioItem&> &group) {
|
void pRadioItem::setGroup(const group<RadioItem&> &group) {
|
||||||
}
|
}
|
||||||
|
|
||||||
void pRadioItem::setText(const string &text) {
|
void pRadioItem::setText(const string &text) {
|
||||||
|
|
|
@ -14,7 +14,7 @@ struct pRadioItem : public pAction {
|
||||||
|
|
||||||
bool checked();
|
bool checked();
|
||||||
void setChecked();
|
void setChecked();
|
||||||
void setGroup(const set<RadioItem&> &group);
|
void setGroup(const group<RadioItem&> &group);
|
||||||
void setText(const string &text);
|
void setText(const string &text);
|
||||||
|
|
||||||
pRadioItem(RadioItem &radioItem) : pAction(radioItem), radioItem(radioItem) {}
|
pRadioItem(RadioItem &radioItem) : pAction(radioItem), radioItem(radioItem) {}
|
||||||
|
|
|
@ -47,7 +47,7 @@ void pRadioButton::setGeometry(const Geometry &geometry) {
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
void pRadioButton::setGroup(const set<RadioButton&> &group) {
|
void pRadioButton::setGroup(const group<RadioButton&> &group) {
|
||||||
}
|
}
|
||||||
|
|
||||||
void pRadioButton::setText(const string &text) {
|
void pRadioButton::setText(const string &text) {
|
||||||
|
|
|
@ -16,7 +16,7 @@ struct pRadioButton : public pWidget {
|
||||||
Size minimumSize();
|
Size minimumSize();
|
||||||
void setChecked();
|
void setChecked();
|
||||||
void setGeometry(const Geometry &geometry);
|
void setGeometry(const Geometry &geometry);
|
||||||
void setGroup(const set<RadioButton&> &group);
|
void setGroup(const group<RadioButton&> &group);
|
||||||
void setText(const string &text);
|
void setText(const string &text);
|
||||||
|
|
||||||
pRadioButton(RadioButton &radioButton) : pWidget(radioButton), radioButton(radioButton) {}
|
pRadioButton(RadioButton &radioButton) : pWidget(radioButton), radioButton(radioButton) {}
|
||||||
|
|
|
@ -525,7 +525,7 @@ Action::~Action() {
|
||||||
//Menu
|
//Menu
|
||||||
//====
|
//====
|
||||||
|
|
||||||
void Menu::append(const set<Action&> &list) {
|
void Menu::append(const group<Action&> &list) {
|
||||||
for(auto &action : list) {
|
for(auto &action : list) {
|
||||||
if(state.action.append(action)) {
|
if(state.action.append(action)) {
|
||||||
action.state.menu = this;
|
action.state.menu = this;
|
||||||
|
@ -534,7 +534,7 @@ void Menu::append(const set<Action&> &list) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void Menu::remove(const set<Action&> &list) {
|
void Menu::remove(const group<Action&> &list) {
|
||||||
for(auto &action : list) {
|
for(auto &action : list) {
|
||||||
if(state.action.remove(action)) {
|
if(state.action.remove(action)) {
|
||||||
action.state.menu = nullptr;
|
action.state.menu = nullptr;
|
||||||
|
@ -639,7 +639,7 @@ CheckItem::~CheckItem() {
|
||||||
//RadioItem
|
//RadioItem
|
||||||
//=========
|
//=========
|
||||||
|
|
||||||
void RadioItem::group(const set<RadioItem&> &list) {
|
void RadioItem::group(const nall::group<RadioItem&> &list) {
|
||||||
for(auto &item : list) item.p.setGroup(item.state.group = list);
|
for(auto &item : list) item.p.setGroup(item.state.group = list);
|
||||||
if(list.size()) list[0].setChecked();
|
if(list.size()) list[0].setChecked();
|
||||||
}
|
}
|
||||||
|
@ -1261,7 +1261,7 @@ ProgressBar::~ProgressBar() {
|
||||||
//RadioButton
|
//RadioButton
|
||||||
//===========
|
//===========
|
||||||
|
|
||||||
void RadioButton::group(const set<RadioButton&> &list) {
|
void RadioButton::group(const nall::group<RadioButton&> &list) {
|
||||||
for(auto &item : list) item.p.setGroup(item.state.group = list);
|
for(auto &item : list) item.p.setGroup(item.state.group = list);
|
||||||
if(list.size()) list[0].setChecked();
|
if(list.size()) list[0].setChecked();
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,9 +1,10 @@
|
||||||
#include <nall/platform.hpp>
|
#include <nall/platform.hpp>
|
||||||
#include <nall/config.hpp>
|
#include <nall/config.hpp>
|
||||||
|
#include <nall/directory.hpp>
|
||||||
#include <nall/function.hpp>
|
#include <nall/function.hpp>
|
||||||
|
#include <nall/group.hpp>
|
||||||
#include <nall/image.hpp>
|
#include <nall/image.hpp>
|
||||||
#include <nall/map.hpp>
|
#include <nall/map.hpp>
|
||||||
#include <nall/set.hpp>
|
|
||||||
#include <nall/stdint.hpp>
|
#include <nall/stdint.hpp>
|
||||||
#include <nall/string.hpp>
|
#include <nall/string.hpp>
|
||||||
#include <nall/utility.hpp>
|
#include <nall/utility.hpp>
|
||||||
|
@ -279,8 +280,8 @@ struct Menu : private nall::base_from_member<pMenu&>, Action {
|
||||||
template<typename... Args> void append(Args&... args) { append({args...}); }
|
template<typename... Args> void append(Args&... args) { append({args...}); }
|
||||||
template<typename... Args> void remove(Args&... args) { remove({args...}); }
|
template<typename... Args> void remove(Args&... args) { remove({args...}); }
|
||||||
|
|
||||||
void append(const nall::set<Action&> &list);
|
void append(const nall::group<Action&> &list);
|
||||||
void remove(const nall::set<Action&> &list);
|
void remove(const nall::group<Action&> &list);
|
||||||
void setImage(const nall::image &image = nall::image{});
|
void setImage(const nall::image &image = nall::image{});
|
||||||
void setText(const nall::string &text);
|
void setText(const nall::string &text);
|
||||||
|
|
||||||
|
@ -326,7 +327,7 @@ struct CheckItem : private nall::base_from_member<pCheckItem&>, Action {
|
||||||
|
|
||||||
struct RadioItem : private nall::base_from_member<pRadioItem&>, Action {
|
struct RadioItem : private nall::base_from_member<pRadioItem&>, Action {
|
||||||
template<typename... Args> static void group(Args&... args) { group({args...}); }
|
template<typename... Args> static void group(Args&... args) { group({args...}); }
|
||||||
static void group(const nall::set<RadioItem&> &list);
|
static void group(const nall::group<RadioItem&> &list);
|
||||||
|
|
||||||
nall::function<void ()> onActivate;
|
nall::function<void ()> onActivate;
|
||||||
|
|
||||||
|
@ -577,7 +578,7 @@ struct ProgressBar : private nall::base_from_member<pProgressBar&>, Widget {
|
||||||
|
|
||||||
struct RadioButton : private nall::base_from_member<pRadioButton&>, Widget {
|
struct RadioButton : private nall::base_from_member<pRadioButton&>, Widget {
|
||||||
template<typename... Args> static void group(Args&... args) { group({args...}); }
|
template<typename... Args> static void group(Args&... args) { group({args...}); }
|
||||||
static void group(const nall::set<RadioButton&> &list);
|
static void group(const nall::group<RadioButton&> &list);
|
||||||
|
|
||||||
nall::function<void ()> onActivate;
|
nall::function<void ()> onActivate;
|
||||||
|
|
||||||
|
|
|
@ -27,8 +27,8 @@ struct Window::State {
|
||||||
Color backgroundColor = {0, 0, 0, 255};
|
Color backgroundColor = {0, 0, 0, 255};
|
||||||
bool fullScreen = false;
|
bool fullScreen = false;
|
||||||
Geometry geometry = {128, 128, 256, 256};
|
Geometry geometry = {128, 128, 256, 256};
|
||||||
set<Layout&> layout;
|
group<Layout&> layout;
|
||||||
set<Menu&> menu;
|
group<Menu&> menu;
|
||||||
string menuFont;
|
string menuFont;
|
||||||
bool menuVisible = false;
|
bool menuVisible = false;
|
||||||
bool modal = false;
|
bool modal = false;
|
||||||
|
@ -38,7 +38,7 @@ struct Window::State {
|
||||||
bool statusVisible = false;
|
bool statusVisible = false;
|
||||||
string title;
|
string title;
|
||||||
bool visible = false;
|
bool visible = false;
|
||||||
set<Widget&> widget;
|
group<Widget&> widget;
|
||||||
string widgetFont;
|
string widgetFont;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -50,7 +50,7 @@ struct Action::State {
|
||||||
};
|
};
|
||||||
|
|
||||||
struct Menu::State {
|
struct Menu::State {
|
||||||
set<Action&> action;
|
group<Action&> action;
|
||||||
nall::image image = {0, 32, 255u << 24, 255u << 16, 255u << 8, 255u << 0};
|
nall::image image = {0, 32, 255u << 24, 255u << 16, 255u << 8, 255u << 0};
|
||||||
string text;
|
string text;
|
||||||
};
|
};
|
||||||
|
@ -67,7 +67,7 @@ struct CheckItem::State {
|
||||||
|
|
||||||
struct RadioItem::State {
|
struct RadioItem::State {
|
||||||
bool checked = true;
|
bool checked = true;
|
||||||
set<RadioItem&> group;
|
nall::group<RadioItem&> group;
|
||||||
string text;
|
string text;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -152,7 +152,7 @@ struct ProgressBar::State {
|
||||||
|
|
||||||
struct RadioButton::State {
|
struct RadioButton::State {
|
||||||
bool checked = true;
|
bool checked = true;
|
||||||
set<RadioButton&> group;
|
nall::group<RadioButton&> group;
|
||||||
string text;
|
string text;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -16,7 +16,7 @@ void pRadioItem::setChecked() {
|
||||||
locked = false;
|
locked = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
void pRadioItem::setGroup(const set<RadioItem&> &group) {
|
void pRadioItem::setGroup(const group<RadioItem&> &group) {
|
||||||
for(unsigned n = 0; n < group.size(); n++) {
|
for(unsigned n = 0; n < group.size(); n++) {
|
||||||
if(n == 0) continue;
|
if(n == 0) continue;
|
||||||
GSList *currentGroup = gtk_radio_menu_item_get_group(GTK_RADIO_MENU_ITEM(group[0].p.widget));
|
GSList *currentGroup = gtk_radio_menu_item_get_group(GTK_RADIO_MENU_ITEM(group[0].p.widget));
|
||||||
|
|
|
@ -11,16 +11,21 @@ struct pApplication {
|
||||||
static void initialize();
|
static void initialize();
|
||||||
};
|
};
|
||||||
|
|
||||||
struct Settings : public configuration {
|
struct Settings : Configuration::Document {
|
||||||
bidirectional_map<Keyboard::Scancode, unsigned> keymap;
|
bidirectional_map<Keyboard::Scancode, unsigned> keymap;
|
||||||
|
|
||||||
unsigned frameGeometryX;
|
struct Geometry : Configuration::Node {
|
||||||
unsigned frameGeometryY;
|
unsigned frameX;
|
||||||
unsigned frameGeometryWidth;
|
unsigned frameY;
|
||||||
unsigned frameGeometryHeight;
|
unsigned frameWidth;
|
||||||
unsigned menuGeometryHeight;
|
unsigned frameHeight;
|
||||||
unsigned statusGeometryHeight;
|
unsigned menuHeight;
|
||||||
unsigned windowBackgroundColor;
|
unsigned statusHeight;
|
||||||
|
} geometry;
|
||||||
|
|
||||||
|
struct Window : Configuration::Node {
|
||||||
|
unsigned backgroundColor;
|
||||||
|
} window;
|
||||||
|
|
||||||
void load();
|
void load();
|
||||||
void save();
|
void save();
|
||||||
|
@ -209,7 +214,7 @@ struct pRadioItem : public pAction {
|
||||||
|
|
||||||
bool checked();
|
bool checked();
|
||||||
void setChecked();
|
void setChecked();
|
||||||
void setGroup(const set<RadioItem&> &group);
|
void setGroup(const group<RadioItem&> &group);
|
||||||
void setText(const string &text);
|
void setText(const string &text);
|
||||||
|
|
||||||
pRadioItem(RadioItem &radioItem) : pAction(radioItem), radioItem(radioItem) {}
|
pRadioItem(RadioItem &radioItem) : pAction(radioItem), radioItem(radioItem) {}
|
||||||
|
@ -442,7 +447,7 @@ struct pRadioButton : public pWidget {
|
||||||
bool checked();
|
bool checked();
|
||||||
Size minimumSize();
|
Size minimumSize();
|
||||||
void setChecked();
|
void setChecked();
|
||||||
void setGroup(const set<RadioButton&> &group);
|
void setGroup(const group<RadioButton&> &group);
|
||||||
void setText(const string &text);
|
void setText(const string &text);
|
||||||
|
|
||||||
pRadioButton(RadioButton &radioButton) : pWidget(radioButton), radioButton(radioButton) {}
|
pRadioButton(RadioButton &radioButton) : pWidget(radioButton), radioButton(radioButton) {}
|
||||||
|
|
|
@ -3,27 +3,27 @@ namespace phoenix {
|
||||||
static Settings *settings = nullptr;
|
static Settings *settings = nullptr;
|
||||||
|
|
||||||
void Settings::load() {
|
void Settings::load() {
|
||||||
string path = {userpath(), ".config/phoenix/gtk.cfg"};
|
string path = {userpath(), ".config/phoenix/gtk.bml"};
|
||||||
configuration::load(path);
|
Configuration::Document::load(path);
|
||||||
}
|
}
|
||||||
|
|
||||||
void Settings::save() {
|
void Settings::save() {
|
||||||
string path = { userpath(), ".config/" };
|
string path = {userpath(), ".config/phoenix/"};
|
||||||
mkdir(path, 0755);
|
directory::create(path, 0755);
|
||||||
path.append("phoenix/");
|
path.append("gtk.bml");
|
||||||
mkdir(path, 0755);
|
Configuration::Document::save(path);
|
||||||
path.append("gtk.cfg");
|
|
||||||
configuration::save(path);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
Settings::Settings() {
|
Settings::Settings() {
|
||||||
append(frameGeometryX = 4, "frameGeometryX");
|
geometry.append(geometry.frameX = 4, "FrameX");
|
||||||
append(frameGeometryY = 24, "frameGeometryY");
|
geometry.append(geometry.frameY = 24, "FrameY");
|
||||||
append(frameGeometryWidth = 8, "frameGeometryWidth");
|
geometry.append(geometry.frameWidth = 8, "FrameWidth");
|
||||||
append(frameGeometryHeight = 28, "frameGeometryHeight");
|
geometry.append(geometry.frameHeight = 28, "FrameHeight");
|
||||||
append(menuGeometryHeight = 20, "menuGeometryHeight");
|
geometry.append(geometry.menuHeight = 20, "MenuHeight");
|
||||||
append(statusGeometryHeight = 20, "statusGeometryHeight");
|
geometry.append(geometry.statusHeight = 20, "StatusHeight");
|
||||||
append(windowBackgroundColor = 0xedeceb, "windowBackgroundColor");
|
append(geometry, "Geometry");
|
||||||
|
window.append(window.backgroundColor = 0xedeceb, "BackgroundColor");
|
||||||
|
append(window, "Window");
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -20,7 +20,7 @@ void pRadioButton::setChecked() {
|
||||||
parent().locked = false;
|
parent().locked = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
void pRadioButton::setGroup(const set<RadioButton&> &group) {
|
void pRadioButton::setGroup(const group<RadioButton&> &group) {
|
||||||
parent().locked = true;
|
parent().locked = true;
|
||||||
if(radioButton.state.group.size() == 0 || &radioButton.state.group[0].p == this) return;
|
if(radioButton.state.group.size() == 0 || &radioButton.state.group[0].p == this) return;
|
||||||
gtk_radio_button_set_group(
|
gtk_radio_button_set_group(
|
||||||
|
|
|
@ -42,13 +42,13 @@ static gboolean Window_configure(GtkWidget *widget, GdkEvent *event, Window *win
|
||||||
|
|
||||||
if(window->state.fullScreen == false) {
|
if(window->state.fullScreen == false) {
|
||||||
//update geometry settings
|
//update geometry settings
|
||||||
settings->frameGeometryX = client.x - border.x;
|
settings->geometry.frameX = client.x - border.x;
|
||||||
settings->frameGeometryY = client.y - border.y;
|
settings->geometry.frameY = client.y - border.y;
|
||||||
settings->frameGeometryWidth = border.width - client.width;
|
settings->geometry.frameWidth = border.width - client.width;
|
||||||
settings->frameGeometryHeight = border.height - client.height;
|
settings->geometry.frameHeight = border.height - client.height;
|
||||||
if(window->state.backgroundColorOverride == false) {
|
if(window->state.backgroundColorOverride == false) {
|
||||||
GdkColor color = widget->style->bg[GTK_STATE_NORMAL];
|
GdkColor color = widget->style->bg[GTK_STATE_NORMAL];
|
||||||
settings->windowBackgroundColor
|
settings->window.backgroundColor
|
||||||
= ((uint8_t)(color.red >> 8) << 16)
|
= ((uint8_t)(color.red >> 8) << 16)
|
||||||
+ ((uint8_t)(color.green >> 8) << 8)
|
+ ((uint8_t)(color.green >> 8) << 8)
|
||||||
+ ((uint8_t)(color.blue >> 8) << 0);
|
+ ((uint8_t)(color.blue >> 8) << 0);
|
||||||
|
@ -154,9 +154,9 @@ void pWindow::append(Widget &widget) {
|
||||||
Color pWindow::backgroundColor() {
|
Color pWindow::backgroundColor() {
|
||||||
if(window.state.backgroundColorOverride) return window.state.backgroundColor;
|
if(window.state.backgroundColorOverride) return window.state.backgroundColor;
|
||||||
return {
|
return {
|
||||||
(uint8_t)(settings->windowBackgroundColor >> 16),
|
(uint8_t)(settings->window.backgroundColor >> 16),
|
||||||
(uint8_t)(settings->windowBackgroundColor >> 8),
|
(uint8_t)(settings->window.backgroundColor >> 8),
|
||||||
(uint8_t)(settings->windowBackgroundColor >> 0),
|
(uint8_t)(settings->window.backgroundColor >> 0),
|
||||||
255
|
255
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
@ -170,10 +170,10 @@ Geometry pWindow::frameMargin() {
|
||||||
};
|
};
|
||||||
|
|
||||||
return {
|
return {
|
||||||
settings->frameGeometryX,
|
settings->geometry.frameX,
|
||||||
settings->frameGeometryY + menuHeight(),
|
settings->geometry.frameY + menuHeight(),
|
||||||
settings->frameGeometryWidth,
|
settings->geometry.frameWidth,
|
||||||
settings->frameGeometryHeight + menuHeight() + statusHeight()
|
settings->geometry.frameHeight + menuHeight() + statusHeight()
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -291,13 +291,13 @@ void pWindow::setVisible(bool visible) {
|
||||||
if(gtk_widget_get_visible(menu)) {
|
if(gtk_widget_get_visible(menu)) {
|
||||||
GtkAllocation allocation;
|
GtkAllocation allocation;
|
||||||
gtk_widget_get_allocation(menu, &allocation);
|
gtk_widget_get_allocation(menu, &allocation);
|
||||||
settings->menuGeometryHeight = allocation.height;
|
settings->geometry.menuHeight = allocation.height;
|
||||||
}
|
}
|
||||||
|
|
||||||
if(gtk_widget_get_visible(status)) {
|
if(gtk_widget_get_visible(status)) {
|
||||||
GtkAllocation allocation;
|
GtkAllocation allocation;
|
||||||
gtk_widget_get_allocation(status, &allocation);
|
gtk_widget_get_allocation(status, &allocation);
|
||||||
settings->statusGeometryHeight = allocation.height;
|
settings->geometry.statusHeight = allocation.height;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -370,11 +370,11 @@ void pWindow::constructor() {
|
||||||
}
|
}
|
||||||
|
|
||||||
unsigned pWindow::menuHeight() {
|
unsigned pWindow::menuHeight() {
|
||||||
return window.state.menuVisible ? settings->menuGeometryHeight : 0;
|
return window.state.menuVisible ? settings->geometry.menuHeight : 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
unsigned pWindow::statusHeight() {
|
unsigned pWindow::statusHeight() {
|
||||||
return window.state.statusVisible ? settings->statusGeometryHeight : 0;
|
return window.state.statusVisible ? settings->geometry.statusHeight : 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,131 +0,0 @@
|
||||||
# Makefile
|
|
||||||
# author: byuu
|
|
||||||
# license: public domain
|
|
||||||
|
|
||||||
[A-Z] = A B C D E F G H I J K L M N O P Q R S T U V W X Y Z
|
|
||||||
[a-z] = a b c d e f g h i j k l m n o p q r s t u v w x y z
|
|
||||||
[0-9] = 0 1 2 3 4 5 6 7 8 9
|
|
||||||
[markup] = ` ~ ! @ \# $$ % ^ & * ( ) - _ = + [ { ] } \ | ; : ' " , < . > / ?
|
|
||||||
[all] = $([A-Z]) $([a-z]) $([0-9]) $([markup])
|
|
||||||
[space] :=
|
|
||||||
[space] +=
|
|
||||||
|
|
||||||
#####
|
|
||||||
# platform detection
|
|
||||||
#####
|
|
||||||
|
|
||||||
ifeq ($(platform),)
|
|
||||||
uname := $(shell uname -a)
|
|
||||||
ifeq ($(uname),)
|
|
||||||
platform := win
|
|
||||||
delete = del $(subst /,\,$1)
|
|
||||||
else ifneq ($(findstring Windows,$(uname)),)
|
|
||||||
platform := win
|
|
||||||
delete = del $(subst /,\,$1)
|
|
||||||
else ifneq ($(findstring CYGWIN,$(uname)),)
|
|
||||||
platform := win
|
|
||||||
delete = del $(subst /,\,$1)
|
|
||||||
else ifneq ($(findstring Darwin,$(uname)),)
|
|
||||||
platform := osx
|
|
||||||
delete = rm -f $1
|
|
||||||
else
|
|
||||||
platform := x
|
|
||||||
delete = rm -f $1
|
|
||||||
endif
|
|
||||||
endif
|
|
||||||
|
|
||||||
ifeq ($(compiler),)
|
|
||||||
ifeq ($(platform),win)
|
|
||||||
compiler := g++
|
|
||||||
flags :=
|
|
||||||
link :=
|
|
||||||
else ifeq ($(platform),osx)
|
|
||||||
compiler := clang
|
|
||||||
flags := -w -stdlib=libc++
|
|
||||||
link := -lc++ -lobjc
|
|
||||||
else
|
|
||||||
compiler := g++-4.7
|
|
||||||
flags :=
|
|
||||||
link :=
|
|
||||||
endif
|
|
||||||
|
|
||||||
cflags := -x c -std=gnu99
|
|
||||||
objcflags := -x objective-c -std=gnu99
|
|
||||||
cppflags := -x c++ -std=gnu++11
|
|
||||||
objcppflags := -x objective-c++ -std=gnu++11
|
|
||||||
endif
|
|
||||||
|
|
||||||
ifeq ($(arch),x86)
|
|
||||||
flags := -m32 $(flags)
|
|
||||||
link := -m32 $(link)
|
|
||||||
endif
|
|
||||||
|
|
||||||
ifeq ($(prefix),)
|
|
||||||
prefix := /usr/local
|
|
||||||
endif
|
|
||||||
|
|
||||||
#####
|
|
||||||
# function rwildcard(directory, pattern)
|
|
||||||
#####
|
|
||||||
rwildcard = \
|
|
||||||
$(strip \
|
|
||||||
$(filter $(if $2,$2,%), \
|
|
||||||
$(foreach f, \
|
|
||||||
$(wildcard $1*), \
|
|
||||||
$(eval t = $(call rwildcard,$f/)) \
|
|
||||||
$(if $t,$t,$f) \
|
|
||||||
) \
|
|
||||||
) \
|
|
||||||
)
|
|
||||||
|
|
||||||
#####
|
|
||||||
# function strtr(source, from, to)
|
|
||||||
#####
|
|
||||||
strtr = \
|
|
||||||
$(eval __temp := $1) \
|
|
||||||
$(strip \
|
|
||||||
$(foreach c, \
|
|
||||||
$(join $(addsuffix :,$2),$3), \
|
|
||||||
$(eval __temp := \
|
|
||||||
$(subst $(word 1,$(subst :, ,$c)),$(word 2,$(subst :, ,$c)),$(__temp)) \
|
|
||||||
) \
|
|
||||||
) \
|
|
||||||
$(__temp) \
|
|
||||||
)
|
|
||||||
|
|
||||||
#####
|
|
||||||
# function strupper(source)
|
|
||||||
#####
|
|
||||||
strupper = $(call strtr,$1,$([a-z]),$([A-Z]))
|
|
||||||
|
|
||||||
#####
|
|
||||||
# function strlower(source)
|
|
||||||
#####
|
|
||||||
strlower = $(call strtr,$1,$([A-Z]),$([a-z]))
|
|
||||||
|
|
||||||
#####
|
|
||||||
# function strlen(source)
|
|
||||||
#####
|
|
||||||
strlen = \
|
|
||||||
$(eval __temp := $(subst $([space]),_,$1)) \
|
|
||||||
$(words \
|
|
||||||
$(strip \
|
|
||||||
$(foreach c, \
|
|
||||||
$([all]), \
|
|
||||||
$(eval __temp := \
|
|
||||||
$(subst $c,$c ,$(__temp)) \
|
|
||||||
) \
|
|
||||||
) \
|
|
||||||
$(__temp) \
|
|
||||||
) \
|
|
||||||
)
|
|
||||||
|
|
||||||
#####
|
|
||||||
# function streq(source)
|
|
||||||
#####
|
|
||||||
streq = $(if $(filter-out xx,x$(subst $1,,$2)$(subst $2,,$1)x),,1)
|
|
||||||
|
|
||||||
#####
|
|
||||||
# function strne(source)
|
|
||||||
#####
|
|
||||||
strne = $(if $(filter-out xx,x$(subst $1,,$2)$(subst $2,,$1)x),1,)
|
|
|
@ -1,17 +0,0 @@
|
||||||
#ifndef NALL_ALGORITHM_HPP
|
|
||||||
#define NALL_ALGORITHM_HPP
|
|
||||||
|
|
||||||
#undef min
|
|
||||||
#undef max
|
|
||||||
|
|
||||||
namespace nall {
|
|
||||||
template<typename T, typename U> T min(const T &t, const U &u) {
|
|
||||||
return t < u ? t : u;
|
|
||||||
}
|
|
||||||
|
|
||||||
template<typename T, typename U> T max(const T &t, const U &u) {
|
|
||||||
return t > u ? t : u;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#endif
|
|
|
@ -1,73 +0,0 @@
|
||||||
#ifndef NALL_ANY_HPP
|
|
||||||
#define NALL_ANY_HPP
|
|
||||||
|
|
||||||
#include <typeinfo>
|
|
||||||
#include <nall/traits.hpp>
|
|
||||||
|
|
||||||
namespace nall {
|
|
||||||
struct any {
|
|
||||||
bool empty() const { return container; }
|
|
||||||
const std::type_info& type() const { return container ? container->type() : typeid(void); }
|
|
||||||
|
|
||||||
template<typename T> any& operator=(const T& value_) {
|
|
||||||
typedef typename type_if<
|
|
||||||
std::is_array<T>::value,
|
|
||||||
typename std::remove_extent<typename std::add_const<T>::type>::type*,
|
|
||||||
T
|
|
||||||
>::type auto_t;
|
|
||||||
|
|
||||||
if(type() == typeid(auto_t)) {
|
|
||||||
static_cast<holder<auto_t>*>(container)->value = (auto_t)value_;
|
|
||||||
} else {
|
|
||||||
if(container) delete container;
|
|
||||||
container = new holder<auto_t>((auto_t)value_);
|
|
||||||
}
|
|
||||||
|
|
||||||
return *this;
|
|
||||||
}
|
|
||||||
|
|
||||||
any() : container(nullptr) {}
|
|
||||||
~any() { if(container) delete container; }
|
|
||||||
template<typename T> any(const T& value_) : container(nullptr) { operator=(value_); }
|
|
||||||
|
|
||||||
private:
|
|
||||||
struct placeholder {
|
|
||||||
virtual const std::type_info& type() const = 0;
|
|
||||||
} *container;
|
|
||||||
|
|
||||||
template<typename T> struct holder : placeholder {
|
|
||||||
T value;
|
|
||||||
const std::type_info& type() const { return typeid(T); }
|
|
||||||
holder(const T& value_) : value(value_) {}
|
|
||||||
};
|
|
||||||
|
|
||||||
template<typename T> friend T any_cast(any&);
|
|
||||||
template<typename T> friend T any_cast(const any&);
|
|
||||||
template<typename T> friend T* any_cast(any*);
|
|
||||||
template<typename T> friend const T* any_cast(const any*);
|
|
||||||
};
|
|
||||||
|
|
||||||
template<typename T> T any_cast(any &value) {
|
|
||||||
typedef typename std::remove_reference<T>::type nonref;
|
|
||||||
if(value.type() != typeid(nonref)) throw;
|
|
||||||
return static_cast<any::holder<nonref>*>(value.container)->value;
|
|
||||||
}
|
|
||||||
|
|
||||||
template<typename T> T any_cast(const any &value) {
|
|
||||||
typedef const typename std::remove_reference<T>::type nonref;
|
|
||||||
if(value.type() != typeid(nonref)) throw;
|
|
||||||
return static_cast<any::holder<nonref>*>(value.container)->value;
|
|
||||||
}
|
|
||||||
|
|
||||||
template<typename T> T* any_cast(any *value) {
|
|
||||||
if(!value || value->type() != typeid(T)) return nullptr;
|
|
||||||
return &static_cast<any::holder<T>*>(value->container)->value;
|
|
||||||
}
|
|
||||||
|
|
||||||
template<typename T> const T* any_cast(const any *value) {
|
|
||||||
if(!value || value->type() != typeid(T)) return nullptr;
|
|
||||||
return &static_cast<any::holder<T>*>(value->container)->value;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#endif
|
|
|
@ -1,103 +0,0 @@
|
||||||
#ifndef NALL_ATOI_HPP
|
|
||||||
#define NALL_ATOI_HPP
|
|
||||||
|
|
||||||
#include <nall/stdint.hpp>
|
|
||||||
|
|
||||||
namespace nall {
|
|
||||||
|
|
||||||
//note: this header is intended to form the base for user-defined literals;
|
|
||||||
//once they are supported by GCC. eg:
|
|
||||||
//unsigned operator "" b(const char *s) { return binary(s); }
|
|
||||||
//-> signed data = 1001b;
|
|
||||||
//(0b1001 is nicer, but is not part of the C++ standard)
|
|
||||||
|
|
||||||
constexpr inline uintmax_t binary_(const char *s, uintmax_t sum = 0) {
|
|
||||||
return (
|
|
||||||
*s == '0' || *s == '1' ? binary_(s + 1, (sum << 1) | *s - '0') :
|
|
||||||
sum
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
constexpr inline uintmax_t octal_(const char *s, uintmax_t sum = 0) {
|
|
||||||
return (
|
|
||||||
*s >= '0' && *s <= '7' ? octal_(s + 1, (sum << 3) | *s - '0') :
|
|
||||||
sum
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
constexpr inline uintmax_t decimal_(const char *s, uintmax_t sum = 0) {
|
|
||||||
return (
|
|
||||||
*s >= '0' && *s <= '9' ? decimal_(s + 1, (sum * 10) + *s - '0') :
|
|
||||||
sum
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
constexpr inline uintmax_t hex_(const char *s, uintmax_t sum = 0) {
|
|
||||||
return (
|
|
||||||
*s >= 'A' && *s <= 'F' ? hex_(s + 1, (sum << 4) | *s - 'A' + 10) :
|
|
||||||
*s >= 'a' && *s <= 'f' ? hex_(s + 1, (sum << 4) | *s - 'a' + 10) :
|
|
||||||
*s >= '0' && *s <= '9' ? hex_(s + 1, (sum << 4) | *s - '0') :
|
|
||||||
sum
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
//
|
|
||||||
|
|
||||||
constexpr inline uintmax_t binary(const char *s) {
|
|
||||||
return (
|
|
||||||
*s == '0' && *(s + 1) == 'B' ? binary_(s + 2) :
|
|
||||||
*s == '0' && *(s + 1) == 'b' ? binary_(s + 2) :
|
|
||||||
*s == '%' ? binary_(s + 1) :
|
|
||||||
binary_(s)
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
constexpr inline uintmax_t octal(const char *s) {
|
|
||||||
return (
|
|
||||||
octal_(s)
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
constexpr inline intmax_t integer(const char *s) {
|
|
||||||
return (
|
|
||||||
*s == '+' ? +decimal_(s + 1) :
|
|
||||||
*s == '-' ? -decimal_(s + 1) :
|
|
||||||
decimal_(s)
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
constexpr inline uintmax_t decimal(const char *s) {
|
|
||||||
return (
|
|
||||||
decimal_(s)
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
constexpr inline uintmax_t hex(const char *s) {
|
|
||||||
return (
|
|
||||||
*s == '0' && *(s + 1) == 'X' ? hex_(s + 2) :
|
|
||||||
*s == '0' && *(s + 1) == 'x' ? hex_(s + 2) :
|
|
||||||
*s == '$' ? hex_(s + 1) :
|
|
||||||
hex_(s)
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
constexpr inline intmax_t numeral(const char *s) {
|
|
||||||
return (
|
|
||||||
*s == '0' && *(s + 1) == 'X' ? hex_(s + 2) :
|
|
||||||
*s == '0' && *(s + 1) == 'x' ? hex_(s + 2) :
|
|
||||||
*s == '0' && *(s + 1) == 'B' ? binary_(s + 2) :
|
|
||||||
*s == '0' && *(s + 1) == 'b' ? binary_(s + 2) :
|
|
||||||
*s == '0' ? octal_(s + 1) :
|
|
||||||
*s == '+' ? +decimal_(s + 1) :
|
|
||||||
*s == '-' ? -decimal_(s + 1) :
|
|
||||||
decimal_(s)
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
inline double fp(const char *s) {
|
|
||||||
return atof(s);
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
#endif
|
|
|
@ -1,118 +0,0 @@
|
||||||
#ifndef NALL_BASE64_HPP
|
|
||||||
#define NALL_BASE64_HPP
|
|
||||||
|
|
||||||
#include <nall/stdint.hpp>
|
|
||||||
#include <nall/string.hpp>
|
|
||||||
|
|
||||||
namespace nall {
|
|
||||||
struct base64 {
|
|
||||||
static bool encode(char *&output, const uint8_t* input, unsigned inlength) {
|
|
||||||
output = new char[inlength * 8 / 6 + 8]();
|
|
||||||
|
|
||||||
unsigned i = 0, o = 0;
|
|
||||||
while(i < inlength) {
|
|
||||||
switch(i % 3) {
|
|
||||||
|
|
||||||
case 0: {
|
|
||||||
output[o++] = enc(input[i] >> 2);
|
|
||||||
output[o] = enc((input[i] & 3) << 4);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
case 1: {
|
|
||||||
uint8_t prev = dec(output[o]);
|
|
||||||
output[o++] = enc(prev + (input[i] >> 4));
|
|
||||||
output[o] = enc((input[i] & 15) << 2);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
case 2: {
|
|
||||||
uint8_t prev = dec(output[o]);
|
|
||||||
output[o++] = enc(prev + (input[i] >> 6));
|
|
||||||
output[o++] = enc(input[i] & 63);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
i++;
|
|
||||||
}
|
|
||||||
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
static string encode(const string &data) {
|
|
||||||
char *buffer = nullptr;
|
|
||||||
encode(buffer, (const uint8_t*)(const char*)data, data.length());
|
|
||||||
string result = buffer;
|
|
||||||
delete[] buffer;
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
static bool decode(uint8_t *&output, unsigned &outlength, const char *input) {
|
|
||||||
unsigned inlength = strlen(input), infix = 0;
|
|
||||||
output = new uint8_t[inlength + 1]();
|
|
||||||
|
|
||||||
unsigned i = 0, o = 0;
|
|
||||||
while(i < inlength) {
|
|
||||||
uint8_t x = dec(input[i]);
|
|
||||||
|
|
||||||
switch(i++ & 3) {
|
|
||||||
|
|
||||||
case 0: {
|
|
||||||
output[o] = x << 2;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
case 1: {
|
|
||||||
output[o++] |= x >> 4;
|
|
||||||
output[o] = (x & 15) << 4;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
case 2: {
|
|
||||||
output[o++] |= x >> 2;
|
|
||||||
output[o] = (x & 3) << 6;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
case 3: {
|
|
||||||
output[o++] |= x;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
outlength = o;
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
static string decode(const string &data) {
|
|
||||||
uint8_t *buffer = nullptr;
|
|
||||||
unsigned size = 0;
|
|
||||||
decode(buffer, size, (const char*)data);
|
|
||||||
string result = (const char*)buffer;
|
|
||||||
delete[] buffer;
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
private:
|
|
||||||
static char enc(uint8_t n) {
|
|
||||||
//base64 for URL encodings (URL = -_, MIME = +/)
|
|
||||||
static char lookup_table[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-_";
|
|
||||||
return lookup_table[n & 63];
|
|
||||||
}
|
|
||||||
|
|
||||||
static uint8_t dec(char n) {
|
|
||||||
if(n >= 'A' && n <= 'Z') return n - 'A';
|
|
||||||
if(n >= 'a' && n <= 'z') return n - 'a' + 26;
|
|
||||||
if(n >= '0' && n <= '9') return n - '0' + 52;
|
|
||||||
if(n == '-') return 62;
|
|
||||||
if(n == '_') return 63;
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
#endif
|
|
|
@ -1,84 +0,0 @@
|
||||||
#ifndef NALL_BEAT_ARCHIVE_HPP
|
|
||||||
#define NALL_BEAT_ARCHIVE_HPP
|
|
||||||
|
|
||||||
#include <nall/beat/base.hpp>
|
|
||||||
|
|
||||||
namespace nall {
|
|
||||||
|
|
||||||
struct beatArchive : beatBase {
|
|
||||||
bool create(const string &beatname, string pathname, const string &metadata = "") {
|
|
||||||
if(fp.open(beatname, file::mode::write) == false) return false;
|
|
||||||
if(pathname.endswith("/") == false) pathname.append("/");
|
|
||||||
|
|
||||||
checksum = ~0;
|
|
||||||
writeString("BPA1");
|
|
||||||
writeNumber(metadata.length());
|
|
||||||
writeString(metadata);
|
|
||||||
|
|
||||||
lstring list;
|
|
||||||
ls(list, pathname, pathname);
|
|
||||||
for(auto &name : list) {
|
|
||||||
if(name.endswith("/")) {
|
|
||||||
name.rtrim<1>("/");
|
|
||||||
writeNumber(0 | ((name.length() - 1) << 1));
|
|
||||||
writeString(name);
|
|
||||||
} else {
|
|
||||||
file stream;
|
|
||||||
if(stream.open({pathname, name}, file::mode::read) == false) return false;
|
|
||||||
writeNumber(1 | ((name.length() - 1) << 1));
|
|
||||||
writeString(name);
|
|
||||||
unsigned size = stream.size();
|
|
||||||
writeNumber(size);
|
|
||||||
uint32_t checksum = ~0;
|
|
||||||
while(size--) {
|
|
||||||
uint8_t data = stream.read();
|
|
||||||
write(data);
|
|
||||||
checksum = crc32_adjust(checksum, data);
|
|
||||||
}
|
|
||||||
writeChecksum(~checksum);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
writeChecksum(~checksum);
|
|
||||||
fp.close();
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool unpack(const string &beatname, string pathname) {
|
|
||||||
if(fp.open(beatname, file::mode::read) == false) return false;
|
|
||||||
if(pathname.endswith("/") == false) pathname.append("/");
|
|
||||||
|
|
||||||
checksum = ~0;
|
|
||||||
if(readString(4) != "BPA1") return false;
|
|
||||||
unsigned length = readNumber();
|
|
||||||
while(length--) read();
|
|
||||||
|
|
||||||
directory::create(pathname);
|
|
||||||
while(fp.offset() < fp.size() - 4) {
|
|
||||||
unsigned data = readNumber();
|
|
||||||
string name = readString((data >> 1) + 1);
|
|
||||||
if(name.position("\\") || name.position("../")) return false; //block path exploits
|
|
||||||
|
|
||||||
if((data & 1) == 0) {
|
|
||||||
directory::create({pathname, name});
|
|
||||||
} else {
|
|
||||||
file stream;
|
|
||||||
if(stream.open({pathname, name}, file::mode::write) == false) return false;
|
|
||||||
unsigned size = readNumber();
|
|
||||||
uint32_t checksum = ~0;
|
|
||||||
while(size--) {
|
|
||||||
uint8_t data = read();
|
|
||||||
stream.write(data);
|
|
||||||
checksum = crc32_adjust(checksum, data);
|
|
||||||
}
|
|
||||||
if(readChecksum(~checksum) == false) return false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return readChecksum(~checksum);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
#endif
|
|
|
@ -1,92 +0,0 @@
|
||||||
#ifndef NALL_BEAT_BASE_HPP
|
|
||||||
#define NALL_BEAT_BASE_HPP
|
|
||||||
|
|
||||||
namespace nall {
|
|
||||||
|
|
||||||
struct beatBase {
|
|
||||||
protected:
|
|
||||||
file fp;
|
|
||||||
uint32_t checksum;
|
|
||||||
|
|
||||||
void ls(lstring &list, const string &path, const string &basepath) {
|
|
||||||
lstring paths = directory::folders(path);
|
|
||||||
for(auto &pathname : paths) {
|
|
||||||
list.append(string{path, pathname}.ltrim<1>(basepath));
|
|
||||||
ls(list, {path, pathname}, basepath);
|
|
||||||
}
|
|
||||||
|
|
||||||
lstring files = directory::files(path);
|
|
||||||
for(auto &filename : files) {
|
|
||||||
list.append(string{path, filename}.ltrim<1>(basepath));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void write(uint8_t data) {
|
|
||||||
fp.write(data);
|
|
||||||
checksum = crc32_adjust(checksum, data);
|
|
||||||
}
|
|
||||||
|
|
||||||
void writeNumber(uint64_t data) {
|
|
||||||
while(true) {
|
|
||||||
uint64_t x = data & 0x7f;
|
|
||||||
data >>= 7;
|
|
||||||
if(data == 0) return write(0x80 | x);
|
|
||||||
write(x);
|
|
||||||
data--;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void writeString(const string &text) {
|
|
||||||
unsigned length = text.length();
|
|
||||||
for(unsigned n = 0; n < length; n++) write(text[n]);
|
|
||||||
}
|
|
||||||
|
|
||||||
void writeChecksum(uint32_t checksum) {
|
|
||||||
write(checksum >> 0);
|
|
||||||
write(checksum >> 8);
|
|
||||||
write(checksum >> 16);
|
|
||||||
write(checksum >> 24);
|
|
||||||
}
|
|
||||||
|
|
||||||
uint8_t read() {
|
|
||||||
uint8_t data = fp.read();
|
|
||||||
checksum = crc32_adjust(checksum, data);
|
|
||||||
return data;
|
|
||||||
}
|
|
||||||
|
|
||||||
uint64_t readNumber() {
|
|
||||||
uint64_t data = 0, shift = 1;
|
|
||||||
while(true) {
|
|
||||||
uint8_t x = read();
|
|
||||||
data += (x & 0x7f) * shift;
|
|
||||||
if(x & 0x80) break;
|
|
||||||
shift <<= 7;
|
|
||||||
data += shift;
|
|
||||||
}
|
|
||||||
return data;
|
|
||||||
}
|
|
||||||
|
|
||||||
string readString(unsigned length) {
|
|
||||||
string text;
|
|
||||||
text.reserve(length + 1);
|
|
||||||
for(unsigned n = 0; n < length; n++) {
|
|
||||||
text[n] = fp.read();
|
|
||||||
checksum = crc32_adjust(checksum, text[n]);
|
|
||||||
}
|
|
||||||
text[length] = 0;
|
|
||||||
return text;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool readChecksum(uint32_t source) {
|
|
||||||
uint32_t checksum = 0;
|
|
||||||
checksum |= read() << 0;
|
|
||||||
checksum |= read() << 8;
|
|
||||||
checksum |= read() << 16;
|
|
||||||
checksum |= read() << 24;
|
|
||||||
return checksum == source;
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
#endif
|
|
|
@ -1,214 +0,0 @@
|
||||||
#ifndef NALL_BEAT_DELTA_HPP
|
|
||||||
#define NALL_BEAT_DELTA_HPP
|
|
||||||
|
|
||||||
#include <nall/crc32.hpp>
|
|
||||||
#include <nall/file.hpp>
|
|
||||||
#include <nall/filemap.hpp>
|
|
||||||
#include <nall/stdint.hpp>
|
|
||||||
#include <nall/string.hpp>
|
|
||||||
|
|
||||||
namespace nall {
|
|
||||||
|
|
||||||
struct bpsdelta {
|
|
||||||
inline void source(const uint8_t *data, unsigned size);
|
|
||||||
inline void target(const uint8_t *data, unsigned size);
|
|
||||||
|
|
||||||
inline bool source(const string &filename);
|
|
||||||
inline bool target(const string &filename);
|
|
||||||
inline bool create(const string &filename, const string &metadata = "");
|
|
||||||
|
|
||||||
protected:
|
|
||||||
enum : unsigned { SourceRead, TargetRead, SourceCopy, TargetCopy };
|
|
||||||
enum : unsigned { Granularity = 1 };
|
|
||||||
|
|
||||||
struct Node {
|
|
||||||
unsigned offset;
|
|
||||||
Node *next;
|
|
||||||
inline Node() : offset(0), next(nullptr) {}
|
|
||||||
inline ~Node() { if(next) delete next; }
|
|
||||||
};
|
|
||||||
|
|
||||||
filemap sourceFile;
|
|
||||||
const uint8_t *sourceData;
|
|
||||||
unsigned sourceSize;
|
|
||||||
|
|
||||||
filemap targetFile;
|
|
||||||
const uint8_t *targetData;
|
|
||||||
unsigned targetSize;
|
|
||||||
};
|
|
||||||
|
|
||||||
void bpsdelta::source(const uint8_t *data, unsigned size) {
|
|
||||||
sourceData = data;
|
|
||||||
sourceSize = size;
|
|
||||||
}
|
|
||||||
|
|
||||||
void bpsdelta::target(const uint8_t *data, unsigned size) {
|
|
||||||
targetData = data;
|
|
||||||
targetSize = size;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool bpsdelta::source(const string &filename) {
|
|
||||||
if(sourceFile.open(filename, filemap::mode::read) == false) return false;
|
|
||||||
source(sourceFile.data(), sourceFile.size());
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool bpsdelta::target(const string &filename) {
|
|
||||||
if(targetFile.open(filename, filemap::mode::read) == false) return false;
|
|
||||||
target(targetFile.data(), targetFile.size());
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool bpsdelta::create(const string &filename, const string &metadata) {
|
|
||||||
file modifyFile;
|
|
||||||
if(modifyFile.open(filename, file::mode::write) == false) return false;
|
|
||||||
|
|
||||||
uint32_t sourceChecksum = ~0, modifyChecksum = ~0;
|
|
||||||
unsigned sourceRelativeOffset = 0, targetRelativeOffset = 0, outputOffset = 0;
|
|
||||||
|
|
||||||
auto write = [&](uint8_t data) {
|
|
||||||
modifyFile.write(data);
|
|
||||||
modifyChecksum = crc32_adjust(modifyChecksum, data);
|
|
||||||
};
|
|
||||||
|
|
||||||
auto encode = [&](uint64_t data) {
|
|
||||||
while(true) {
|
|
||||||
uint64_t x = data & 0x7f;
|
|
||||||
data >>= 7;
|
|
||||||
if(data == 0) {
|
|
||||||
write(0x80 | x);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
write(x);
|
|
||||||
data--;
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
write('B');
|
|
||||||
write('P');
|
|
||||||
write('S');
|
|
||||||
write('1');
|
|
||||||
|
|
||||||
encode(sourceSize);
|
|
||||||
encode(targetSize);
|
|
||||||
|
|
||||||
unsigned markupSize = metadata.length();
|
|
||||||
encode(markupSize);
|
|
||||||
for(unsigned n = 0; n < markupSize; n++) write(metadata[n]);
|
|
||||||
|
|
||||||
Node *sourceTree[65536], *targetTree[65536];
|
|
||||||
for(unsigned n = 0; n < 65536; n++) sourceTree[n] = nullptr, targetTree[n] = nullptr;
|
|
||||||
|
|
||||||
//source tree creation
|
|
||||||
for(unsigned offset = 0; offset < sourceSize; offset++) {
|
|
||||||
uint16_t symbol = sourceData[offset + 0];
|
|
||||||
sourceChecksum = crc32_adjust(sourceChecksum, symbol);
|
|
||||||
if(offset < sourceSize - 1) symbol |= sourceData[offset + 1] << 8;
|
|
||||||
Node *node = new Node;
|
|
||||||
node->offset = offset;
|
|
||||||
node->next = sourceTree[symbol];
|
|
||||||
sourceTree[symbol] = node;
|
|
||||||
}
|
|
||||||
|
|
||||||
unsigned targetReadLength = 0;
|
|
||||||
|
|
||||||
auto targetReadFlush = [&]() {
|
|
||||||
if(targetReadLength) {
|
|
||||||
encode(TargetRead | ((targetReadLength - 1) << 2));
|
|
||||||
unsigned offset = outputOffset - targetReadLength;
|
|
||||||
while(targetReadLength) write(targetData[offset++]), targetReadLength--;
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
while(outputOffset < targetSize) {
|
|
||||||
unsigned maxLength = 0, maxOffset = 0, mode = TargetRead;
|
|
||||||
|
|
||||||
uint16_t symbol = targetData[outputOffset + 0];
|
|
||||||
if(outputOffset < targetSize - 1) symbol |= targetData[outputOffset + 1] << 8;
|
|
||||||
|
|
||||||
{ //source read
|
|
||||||
unsigned length = 0, offset = outputOffset;
|
|
||||||
while(offset < sourceSize && offset < targetSize && sourceData[offset] == targetData[offset]) {
|
|
||||||
length++;
|
|
||||||
offset++;
|
|
||||||
}
|
|
||||||
if(length > maxLength) maxLength = length, mode = SourceRead;
|
|
||||||
}
|
|
||||||
|
|
||||||
{ //source copy
|
|
||||||
Node *node = sourceTree[symbol];
|
|
||||||
while(node) {
|
|
||||||
unsigned length = 0, x = node->offset, y = outputOffset;
|
|
||||||
while(x < sourceSize && y < targetSize && sourceData[x++] == targetData[y++]) length++;
|
|
||||||
if(length > maxLength) maxLength = length, maxOffset = node->offset, mode = SourceCopy;
|
|
||||||
node = node->next;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
{ //target copy
|
|
||||||
Node *node = targetTree[symbol];
|
|
||||||
while(node) {
|
|
||||||
unsigned length = 0, x = node->offset, y = outputOffset;
|
|
||||||
while(y < targetSize && targetData[x++] == targetData[y++]) length++;
|
|
||||||
if(length > maxLength) maxLength = length, maxOffset = node->offset, mode = TargetCopy;
|
|
||||||
node = node->next;
|
|
||||||
}
|
|
||||||
|
|
||||||
//target tree append
|
|
||||||
node = new Node;
|
|
||||||
node->offset = outputOffset;
|
|
||||||
node->next = targetTree[symbol];
|
|
||||||
targetTree[symbol] = node;
|
|
||||||
}
|
|
||||||
|
|
||||||
{ //target read
|
|
||||||
if(maxLength < 4) {
|
|
||||||
maxLength = min((unsigned)Granularity, targetSize - outputOffset);
|
|
||||||
mode = TargetRead;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if(mode != TargetRead) targetReadFlush();
|
|
||||||
|
|
||||||
switch(mode) {
|
|
||||||
case SourceRead:
|
|
||||||
encode(SourceRead | ((maxLength - 1) << 2));
|
|
||||||
break;
|
|
||||||
case TargetRead:
|
|
||||||
//delay write to group sequential TargetRead commands into one
|
|
||||||
targetReadLength += maxLength;
|
|
||||||
break;
|
|
||||||
case SourceCopy:
|
|
||||||
case TargetCopy:
|
|
||||||
encode(mode | ((maxLength - 1) << 2));
|
|
||||||
signed relativeOffset;
|
|
||||||
if(mode == SourceCopy) {
|
|
||||||
relativeOffset = maxOffset - sourceRelativeOffset;
|
|
||||||
sourceRelativeOffset = maxOffset + maxLength;
|
|
||||||
} else {
|
|
||||||
relativeOffset = maxOffset - targetRelativeOffset;
|
|
||||||
targetRelativeOffset = maxOffset + maxLength;
|
|
||||||
}
|
|
||||||
encode((relativeOffset < 0) | (abs(relativeOffset) << 1));
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
outputOffset += maxLength;
|
|
||||||
}
|
|
||||||
|
|
||||||
targetReadFlush();
|
|
||||||
|
|
||||||
sourceChecksum = ~sourceChecksum;
|
|
||||||
for(unsigned n = 0; n < 32; n += 8) write(sourceChecksum >> n);
|
|
||||||
uint32_t targetChecksum = crc32_calculate(targetData, targetSize);
|
|
||||||
for(unsigned n = 0; n < 32; n += 8) write(targetChecksum >> n);
|
|
||||||
uint32_t outputChecksum = ~modifyChecksum;
|
|
||||||
for(unsigned n = 0; n < 32; n += 8) write(outputChecksum >> n);
|
|
||||||
|
|
||||||
modifyFile.close();
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
#endif
|
|
|
@ -1,152 +0,0 @@
|
||||||
#ifndef NALL_BEAT_LINEAR_HPP
|
|
||||||
#define NALL_BEAT_LINEAR_HPP
|
|
||||||
|
|
||||||
#include <nall/crc32.hpp>
|
|
||||||
#include <nall/file.hpp>
|
|
||||||
#include <nall/filemap.hpp>
|
|
||||||
#include <nall/stdint.hpp>
|
|
||||||
#include <nall/string.hpp>
|
|
||||||
|
|
||||||
namespace nall {
|
|
||||||
|
|
||||||
struct bpslinear {
|
|
||||||
inline void source(const uint8_t *data, unsigned size);
|
|
||||||
inline void target(const uint8_t *data, unsigned size);
|
|
||||||
|
|
||||||
inline bool source(const string &filename);
|
|
||||||
inline bool target(const string &filename);
|
|
||||||
inline bool create(const string &filename, const string &metadata = "");
|
|
||||||
|
|
||||||
protected:
|
|
||||||
enum : unsigned { SourceRead, TargetRead, SourceCopy, TargetCopy };
|
|
||||||
enum : unsigned { Granularity = 1 };
|
|
||||||
|
|
||||||
filemap sourceFile;
|
|
||||||
const uint8_t *sourceData;
|
|
||||||
unsigned sourceSize;
|
|
||||||
|
|
||||||
filemap targetFile;
|
|
||||||
const uint8_t *targetData;
|
|
||||||
unsigned targetSize;
|
|
||||||
};
|
|
||||||
|
|
||||||
void bpslinear::source(const uint8_t *data, unsigned size) {
|
|
||||||
sourceData = data;
|
|
||||||
sourceSize = size;
|
|
||||||
}
|
|
||||||
|
|
||||||
void bpslinear::target(const uint8_t *data, unsigned size) {
|
|
||||||
targetData = data;
|
|
||||||
targetSize = size;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool bpslinear::source(const string &filename) {
|
|
||||||
if(sourceFile.open(filename, filemap::mode::read) == false) return false;
|
|
||||||
source(sourceFile.data(), sourceFile.size());
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool bpslinear::target(const string &filename) {
|
|
||||||
if(targetFile.open(filename, filemap::mode::read) == false) return false;
|
|
||||||
target(targetFile.data(), targetFile.size());
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool bpslinear::create(const string &filename, const string &metadata) {
|
|
||||||
file modifyFile;
|
|
||||||
if(modifyFile.open(filename, file::mode::write) == false) return false;
|
|
||||||
|
|
||||||
uint32_t modifyChecksum = ~0;
|
|
||||||
unsigned targetRelativeOffset = 0, outputOffset = 0;
|
|
||||||
|
|
||||||
auto write = [&](uint8_t data) {
|
|
||||||
modifyFile.write(data);
|
|
||||||
modifyChecksum = crc32_adjust(modifyChecksum, data);
|
|
||||||
};
|
|
||||||
|
|
||||||
auto encode = [&](uint64_t data) {
|
|
||||||
while(true) {
|
|
||||||
uint64_t x = data & 0x7f;
|
|
||||||
data >>= 7;
|
|
||||||
if(data == 0) {
|
|
||||||
write(0x80 | x);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
write(x);
|
|
||||||
data--;
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
unsigned targetReadLength = 0;
|
|
||||||
|
|
||||||
auto targetReadFlush = [&]() {
|
|
||||||
if(targetReadLength) {
|
|
||||||
encode(TargetRead | ((targetReadLength - 1) << 2));
|
|
||||||
unsigned offset = outputOffset - targetReadLength;
|
|
||||||
while(targetReadLength) write(targetData[offset++]), targetReadLength--;
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
write('B');
|
|
||||||
write('P');
|
|
||||||
write('S');
|
|
||||||
write('1');
|
|
||||||
|
|
||||||
encode(sourceSize);
|
|
||||||
encode(targetSize);
|
|
||||||
|
|
||||||
unsigned markupSize = metadata.length();
|
|
||||||
encode(markupSize);
|
|
||||||
for(unsigned n = 0; n < markupSize; n++) write(metadata[n]);
|
|
||||||
|
|
||||||
while(outputOffset < targetSize) {
|
|
||||||
unsigned sourceLength = 0;
|
|
||||||
for(unsigned n = 0; outputOffset + n < min(sourceSize, targetSize); n++) {
|
|
||||||
if(sourceData[outputOffset + n] != targetData[outputOffset + n]) break;
|
|
||||||
sourceLength++;
|
|
||||||
}
|
|
||||||
|
|
||||||
unsigned rleLength = 0;
|
|
||||||
for(unsigned n = 1; outputOffset + n < targetSize; n++) {
|
|
||||||
if(targetData[outputOffset] != targetData[outputOffset + n]) break;
|
|
||||||
rleLength++;
|
|
||||||
}
|
|
||||||
|
|
||||||
if(rleLength >= 4) {
|
|
||||||
//write byte to repeat
|
|
||||||
targetReadLength++;
|
|
||||||
outputOffset++;
|
|
||||||
targetReadFlush();
|
|
||||||
|
|
||||||
//copy starting from repetition byte
|
|
||||||
encode(TargetCopy | ((rleLength - 1) << 2));
|
|
||||||
unsigned relativeOffset = (outputOffset - 1) - targetRelativeOffset;
|
|
||||||
encode(relativeOffset << 1);
|
|
||||||
outputOffset += rleLength;
|
|
||||||
targetRelativeOffset = outputOffset - 1;
|
|
||||||
} else if(sourceLength >= 4) {
|
|
||||||
targetReadFlush();
|
|
||||||
encode(SourceRead | ((sourceLength - 1) << 2));
|
|
||||||
outputOffset += sourceLength;
|
|
||||||
} else {
|
|
||||||
targetReadLength += Granularity;
|
|
||||||
outputOffset += Granularity;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
targetReadFlush();
|
|
||||||
|
|
||||||
uint32_t sourceChecksum = crc32_calculate(sourceData, sourceSize);
|
|
||||||
for(unsigned n = 0; n < 32; n += 8) write(sourceChecksum >> n);
|
|
||||||
uint32_t targetChecksum = crc32_calculate(targetData, targetSize);
|
|
||||||
for(unsigned n = 0; n < 32; n += 8) write(targetChecksum >> n);
|
|
||||||
uint32_t outputChecksum = ~modifyChecksum;
|
|
||||||
for(unsigned n = 0; n < 32; n += 8) write(outputChecksum >> n);
|
|
||||||
|
|
||||||
modifyFile.close();
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
#endif
|
|
|
@ -1,121 +0,0 @@
|
||||||
#ifndef NALL_BEAT_METADATA_HPP
|
|
||||||
#define NALL_BEAT_METADATA_HPP
|
|
||||||
|
|
||||||
#include <nall/crc32.hpp>
|
|
||||||
#include <nall/file.hpp>
|
|
||||||
#include <nall/filemap.hpp>
|
|
||||||
#include <nall/stdint.hpp>
|
|
||||||
#include <nall/string.hpp>
|
|
||||||
|
|
||||||
namespace nall {
|
|
||||||
|
|
||||||
struct bpsmetadata {
|
|
||||||
inline bool load(const string &filename);
|
|
||||||
inline bool save(const string &filename, const string &metadata);
|
|
||||||
inline string metadata() const;
|
|
||||||
|
|
||||||
protected:
|
|
||||||
file sourceFile;
|
|
||||||
string metadataString;
|
|
||||||
};
|
|
||||||
|
|
||||||
bool bpsmetadata::load(const string &filename) {
|
|
||||||
if(sourceFile.open(filename, file::mode::read) == false) return false;
|
|
||||||
|
|
||||||
auto read = [&]() -> uint8_t {
|
|
||||||
return sourceFile.read();
|
|
||||||
};
|
|
||||||
|
|
||||||
auto decode = [&]() -> uint64_t {
|
|
||||||
uint64_t data = 0, shift = 1;
|
|
||||||
while(true) {
|
|
||||||
uint8_t x = read();
|
|
||||||
data += (x & 0x7f) * shift;
|
|
||||||
if(x & 0x80) break;
|
|
||||||
shift <<= 7;
|
|
||||||
data += shift;
|
|
||||||
}
|
|
||||||
return data;
|
|
||||||
};
|
|
||||||
|
|
||||||
if(read() != 'B') return false;
|
|
||||||
if(read() != 'P') return false;
|
|
||||||
if(read() != 'S') return false;
|
|
||||||
if(read() != '1') return false;
|
|
||||||
decode();
|
|
||||||
decode();
|
|
||||||
unsigned metadataSize = decode();
|
|
||||||
char data[metadataSize + 1];
|
|
||||||
for(unsigned n = 0; n < metadataSize; n++) data[n] = read();
|
|
||||||
data[metadataSize] = 0;
|
|
||||||
metadataString = (const char*)data;
|
|
||||||
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool bpsmetadata::save(const string &filename, const string &metadata) {
|
|
||||||
file targetFile;
|
|
||||||
if(targetFile.open(filename, file::mode::write) == false) return false;
|
|
||||||
if(sourceFile.open() == false) return false;
|
|
||||||
sourceFile.seek(0);
|
|
||||||
|
|
||||||
auto read = [&]() -> uint8_t {
|
|
||||||
return sourceFile.read();
|
|
||||||
};
|
|
||||||
|
|
||||||
auto decode = [&]() -> uint64_t {
|
|
||||||
uint64_t data = 0, shift = 1;
|
|
||||||
while(true) {
|
|
||||||
uint8_t x = read();
|
|
||||||
data += (x & 0x7f) * shift;
|
|
||||||
if(x & 0x80) break;
|
|
||||||
shift <<= 7;
|
|
||||||
data += shift;
|
|
||||||
}
|
|
||||||
return data;
|
|
||||||
};
|
|
||||||
|
|
||||||
uint32_t checksum = ~0;
|
|
||||||
|
|
||||||
auto write = [&](uint8_t data) {
|
|
||||||
targetFile.write(data);
|
|
||||||
checksum = crc32_adjust(checksum, data);
|
|
||||||
};
|
|
||||||
|
|
||||||
auto encode = [&](uint64_t data) {
|
|
||||||
while(true) {
|
|
||||||
uint64_t x = data & 0x7f;
|
|
||||||
data >>= 7;
|
|
||||||
if(data == 0) {
|
|
||||||
write(0x80 | x);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
write(x);
|
|
||||||
data--;
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
for(unsigned n = 0; n < 4; n++) write(read());
|
|
||||||
encode(decode());
|
|
||||||
encode(decode());
|
|
||||||
unsigned sourceLength = decode();
|
|
||||||
unsigned targetLength = metadata.length();
|
|
||||||
encode(targetLength);
|
|
||||||
sourceFile.seek(sourceLength, file::index::relative);
|
|
||||||
for(unsigned n = 0; n < targetLength; n++) write(metadata[n]);
|
|
||||||
unsigned length = sourceFile.size() - sourceFile.offset() - 4;
|
|
||||||
for(unsigned n = 0; n < length; n++) write(read());
|
|
||||||
uint32_t outputChecksum = ~checksum;
|
|
||||||
for(unsigned n = 0; n < 32; n += 8) write(outputChecksum >> n);
|
|
||||||
|
|
||||||
targetFile.close();
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
string bpsmetadata::metadata() const {
|
|
||||||
return metadataString;
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
#endif
|
|
|
@ -1,242 +0,0 @@
|
||||||
#ifndef NALL_BEAT_MULTI_HPP
|
|
||||||
#define NALL_BEAT_MULTI_HPP
|
|
||||||
|
|
||||||
#include <nall/beat/patch.hpp>
|
|
||||||
#include <nall/beat/linear.hpp>
|
|
||||||
#include <nall/beat/delta.hpp>
|
|
||||||
|
|
||||||
namespace nall {
|
|
||||||
|
|
||||||
struct bpsmulti {
|
|
||||||
enum : unsigned {
|
|
||||||
CreatePath = 0,
|
|
||||||
CreateFile = 1,
|
|
||||||
ModifyFile = 2,
|
|
||||||
MirrorFile = 3,
|
|
||||||
};
|
|
||||||
|
|
||||||
enum : unsigned {
|
|
||||||
OriginSource = 0,
|
|
||||||
OriginTarget = 1,
|
|
||||||
};
|
|
||||||
|
|
||||||
bool create(const string &patchName, const string &sourcePath, const string &targetPath, bool delta = false, const string &metadata = "") {
|
|
||||||
if(fp.open()) fp.close();
|
|
||||||
fp.open(patchName, file::mode::write);
|
|
||||||
checksum = ~0;
|
|
||||||
|
|
||||||
writeString("BPM1"); //signature
|
|
||||||
writeNumber(metadata.length());
|
|
||||||
writeString(metadata);
|
|
||||||
|
|
||||||
lstring sourceList, targetList;
|
|
||||||
ls(sourceList, sourcePath, sourcePath);
|
|
||||||
ls(targetList, targetPath, targetPath);
|
|
||||||
|
|
||||||
for(auto &targetName : targetList) {
|
|
||||||
if(targetName.endswith("/")) {
|
|
||||||
targetName.rtrim<1>("/");
|
|
||||||
writeNumber(CreatePath | ((targetName.length() - 1) << 2));
|
|
||||||
writeString(targetName);
|
|
||||||
} else if(auto position = sourceList.find(targetName)) { //if sourceName == targetName
|
|
||||||
file sp, dp;
|
|
||||||
sp.open({sourcePath, targetName}, file::mode::read);
|
|
||||||
dp.open({targetPath, targetName}, file::mode::read);
|
|
||||||
|
|
||||||
bool identical = sp.size() == dp.size();
|
|
||||||
uint32_t cksum = ~0;
|
|
||||||
|
|
||||||
for(unsigned n = 0; n < sp.size(); n++) {
|
|
||||||
uint8_t byte = sp.read();
|
|
||||||
if(identical && byte != dp.read()) identical = false;
|
|
||||||
cksum = crc32_adjust(cksum, byte);
|
|
||||||
}
|
|
||||||
|
|
||||||
if(identical) {
|
|
||||||
writeNumber(MirrorFile | ((targetName.length() - 1) << 2));
|
|
||||||
writeString(targetName);
|
|
||||||
writeNumber(OriginSource);
|
|
||||||
writeChecksum(~cksum);
|
|
||||||
} else {
|
|
||||||
writeNumber(ModifyFile | ((targetName.length() - 1) << 2));
|
|
||||||
writeString(targetName);
|
|
||||||
writeNumber(OriginSource);
|
|
||||||
|
|
||||||
if(delta == false) {
|
|
||||||
bpslinear patch;
|
|
||||||
patch.source({sourcePath, targetName});
|
|
||||||
patch.target({targetPath, targetName});
|
|
||||||
patch.create({temppath(), "temp.bps"});
|
|
||||||
} else {
|
|
||||||
bpsdelta patch;
|
|
||||||
patch.source({sourcePath, targetName});
|
|
||||||
patch.target({targetPath, targetName});
|
|
||||||
patch.create({temppath(), "temp.bps"});
|
|
||||||
}
|
|
||||||
|
|
||||||
auto buffer = file::read({temppath(), "temp.bps"});
|
|
||||||
writeNumber(buffer.size());
|
|
||||||
for(auto &byte : buffer) write(byte);
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
writeNumber(CreateFile | ((targetName.length() - 1) << 2));
|
|
||||||
writeString(targetName);
|
|
||||||
auto buffer = file::read({targetPath, targetName});
|
|
||||||
writeNumber(buffer.size());
|
|
||||||
for(auto &byte : buffer) write(byte);
|
|
||||||
writeChecksum(crc32_calculate(buffer.data(), buffer.size()));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
//checksum
|
|
||||||
writeChecksum(~checksum);
|
|
||||||
fp.close();
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool apply(const string &patchName, const string &sourcePath, const string &targetPath) {
|
|
||||||
directory::remove(targetPath); //start with a clean directory
|
|
||||||
directory::create(targetPath);
|
|
||||||
|
|
||||||
if(fp.open()) fp.close();
|
|
||||||
fp.open(patchName, file::mode::read);
|
|
||||||
checksum = ~0;
|
|
||||||
|
|
||||||
if(readString(4) != "BPM1") return false;
|
|
||||||
auto metadataLength = readNumber();
|
|
||||||
while(metadataLength--) read();
|
|
||||||
|
|
||||||
while(fp.offset() < fp.size() - 4) {
|
|
||||||
auto encoding = readNumber();
|
|
||||||
unsigned action = encoding & 3;
|
|
||||||
unsigned targetLength = (encoding >> 2) + 1;
|
|
||||||
string targetName = readString(targetLength);
|
|
||||||
|
|
||||||
if(action == CreatePath) {
|
|
||||||
directory::create({targetPath, targetName, "/"});
|
|
||||||
} else if(action == CreateFile) {
|
|
||||||
file fp;
|
|
||||||
fp.open({targetPath, targetName}, file::mode::write);
|
|
||||||
auto fileSize = readNumber();
|
|
||||||
while(fileSize--) fp.write(read());
|
|
||||||
uint32_t cksum = readChecksum();
|
|
||||||
} else if(action == ModifyFile) {
|
|
||||||
auto encoding = readNumber();
|
|
||||||
string originPath = encoding & 1 ? targetPath : sourcePath;
|
|
||||||
string sourceName = (encoding >> 1) == 0 ? targetName : readString(encoding >> 1);
|
|
||||||
auto patchSize = readNumber();
|
|
||||||
vector<uint8_t> buffer;
|
|
||||||
buffer.resize(patchSize);
|
|
||||||
for(unsigned n = 0; n < patchSize; n++) buffer[n] = read();
|
|
||||||
bpspatch patch;
|
|
||||||
patch.modify(buffer.data(), buffer.size());
|
|
||||||
patch.source({originPath, sourceName});
|
|
||||||
patch.target({targetPath, targetName});
|
|
||||||
if(patch.apply() != bpspatch::result::success) return false;
|
|
||||||
} else if(action == MirrorFile) {
|
|
||||||
auto encoding = readNumber();
|
|
||||||
string originPath = encoding & 1 ? targetPath : sourcePath;
|
|
||||||
string sourceName = (encoding >> 1) == 0 ? targetName : readString(encoding >> 1);
|
|
||||||
file::copy({originPath, sourceName}, {targetPath, targetName});
|
|
||||||
uint32_t cksum = readChecksum();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
uint32_t cksum = ~checksum;
|
|
||||||
if(read() != (uint8_t)(cksum >> 0)) return false;
|
|
||||||
if(read() != (uint8_t)(cksum >> 8)) return false;
|
|
||||||
if(read() != (uint8_t)(cksum >> 16)) return false;
|
|
||||||
if(read() != (uint8_t)(cksum >> 24)) return false;
|
|
||||||
|
|
||||||
fp.close();
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
protected:
|
|
||||||
file fp;
|
|
||||||
uint32_t checksum;
|
|
||||||
|
|
||||||
//create() functions
|
|
||||||
void ls(lstring &list, const string &path, const string &basepath) {
|
|
||||||
lstring paths = directory::folders(path);
|
|
||||||
for(auto &pathname : paths) {
|
|
||||||
list.append(string{path, pathname}.ltrim<1>(basepath));
|
|
||||||
ls(list, {path, pathname}, basepath);
|
|
||||||
}
|
|
||||||
|
|
||||||
lstring files = directory::files(path);
|
|
||||||
for(auto &filename : files) {
|
|
||||||
list.append(string{path, filename}.ltrim<1>(basepath));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void write(uint8_t data) {
|
|
||||||
fp.write(data);
|
|
||||||
checksum = crc32_adjust(checksum, data);
|
|
||||||
}
|
|
||||||
|
|
||||||
void writeNumber(uint64_t data) {
|
|
||||||
while(true) {
|
|
||||||
uint64_t x = data & 0x7f;
|
|
||||||
data >>= 7;
|
|
||||||
if(data == 0) {
|
|
||||||
write(0x80 | x);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
write(x);
|
|
||||||
data--;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void writeString(const string &text) {
|
|
||||||
unsigned length = text.length();
|
|
||||||
for(unsigned n = 0; n < length; n++) write(text[n]);
|
|
||||||
}
|
|
||||||
|
|
||||||
void writeChecksum(uint32_t cksum) {
|
|
||||||
write(cksum >> 0);
|
|
||||||
write(cksum >> 8);
|
|
||||||
write(cksum >> 16);
|
|
||||||
write(cksum >> 24);
|
|
||||||
}
|
|
||||||
|
|
||||||
//apply() functions
|
|
||||||
uint8_t read() {
|
|
||||||
uint8_t data = fp.read();
|
|
||||||
checksum = crc32_adjust(checksum, data);
|
|
||||||
return data;
|
|
||||||
}
|
|
||||||
|
|
||||||
uint64_t readNumber() {
|
|
||||||
uint64_t data = 0, shift = 1;
|
|
||||||
while(true) {
|
|
||||||
uint8_t x = read();
|
|
||||||
data += (x & 0x7f) * shift;
|
|
||||||
if(x & 0x80) break;
|
|
||||||
shift <<= 7;
|
|
||||||
data += shift;
|
|
||||||
}
|
|
||||||
return data;
|
|
||||||
}
|
|
||||||
|
|
||||||
string readString(unsigned length) {
|
|
||||||
string text;
|
|
||||||
text.reserve(length + 1);
|
|
||||||
for(unsigned n = 0; n < length; n++) text[n] = read();
|
|
||||||
text[length] = 0;
|
|
||||||
return text;
|
|
||||||
}
|
|
||||||
|
|
||||||
uint32_t readChecksum() {
|
|
||||||
uint32_t checksum = 0;
|
|
||||||
checksum |= read() << 0;
|
|
||||||
checksum |= read() << 8;
|
|
||||||
checksum |= read() << 16;
|
|
||||||
checksum |= read() << 24;
|
|
||||||
return checksum;
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
#endif
|
|
|
@ -1,219 +0,0 @@
|
||||||
#ifndef NALL_BEAT_PATCH_HPP
|
|
||||||
#define NALL_BEAT_PATCH_HPP
|
|
||||||
|
|
||||||
#include <nall/crc32.hpp>
|
|
||||||
#include <nall/file.hpp>
|
|
||||||
#include <nall/filemap.hpp>
|
|
||||||
#include <nall/stdint.hpp>
|
|
||||||
#include <nall/string.hpp>
|
|
||||||
|
|
||||||
namespace nall {
|
|
||||||
|
|
||||||
struct bpspatch {
|
|
||||||
inline bool modify(const uint8_t *data, unsigned size);
|
|
||||||
inline void source(const uint8_t *data, unsigned size);
|
|
||||||
inline void target(uint8_t *data, unsigned size);
|
|
||||||
|
|
||||||
inline bool modify(const string &filename);
|
|
||||||
inline bool source(const string &filename);
|
|
||||||
inline bool target(const string &filename);
|
|
||||||
|
|
||||||
inline string metadata() const;
|
|
||||||
inline unsigned size() const;
|
|
||||||
|
|
||||||
enum result : unsigned {
|
|
||||||
unknown,
|
|
||||||
success,
|
|
||||||
patch_too_small,
|
|
||||||
patch_invalid_header,
|
|
||||||
source_too_small,
|
|
||||||
target_too_small,
|
|
||||||
source_checksum_invalid,
|
|
||||||
target_checksum_invalid,
|
|
||||||
patch_checksum_invalid,
|
|
||||||
};
|
|
||||||
|
|
||||||
inline result apply();
|
|
||||||
|
|
||||||
protected:
|
|
||||||
enum : unsigned { SourceRead, TargetRead, SourceCopy, TargetCopy };
|
|
||||||
|
|
||||||
filemap modifyFile;
|
|
||||||
const uint8_t *modifyData;
|
|
||||||
unsigned modifySize;
|
|
||||||
|
|
||||||
filemap sourceFile;
|
|
||||||
const uint8_t *sourceData;
|
|
||||||
unsigned sourceSize;
|
|
||||||
|
|
||||||
filemap targetFile;
|
|
||||||
uint8_t *targetData;
|
|
||||||
unsigned targetSize;
|
|
||||||
|
|
||||||
unsigned modifySourceSize;
|
|
||||||
unsigned modifyTargetSize;
|
|
||||||
unsigned modifyMarkupSize;
|
|
||||||
string metadataString;
|
|
||||||
};
|
|
||||||
|
|
||||||
bool bpspatch::modify(const uint8_t *data, unsigned size) {
|
|
||||||
if(size < 19) return false;
|
|
||||||
modifyData = data;
|
|
||||||
modifySize = size;
|
|
||||||
|
|
||||||
unsigned offset = 4;
|
|
||||||
auto decode = [&]() -> uint64_t {
|
|
||||||
uint64_t data = 0, shift = 1;
|
|
||||||
while(true) {
|
|
||||||
uint8_t x = modifyData[offset++];
|
|
||||||
data += (x & 0x7f) * shift;
|
|
||||||
if(x & 0x80) break;
|
|
||||||
shift <<= 7;
|
|
||||||
data += shift;
|
|
||||||
}
|
|
||||||
return data;
|
|
||||||
};
|
|
||||||
|
|
||||||
modifySourceSize = decode();
|
|
||||||
modifyTargetSize = decode();
|
|
||||||
modifyMarkupSize = decode();
|
|
||||||
|
|
||||||
char buffer[modifyMarkupSize + 1];
|
|
||||||
for(unsigned n = 0; n < modifyMarkupSize; n++) buffer[n] = modifyData[offset++];
|
|
||||||
buffer[modifyMarkupSize] = 0;
|
|
||||||
metadataString = (const char*)buffer;
|
|
||||||
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
void bpspatch::source(const uint8_t *data, unsigned size) {
|
|
||||||
sourceData = data;
|
|
||||||
sourceSize = size;
|
|
||||||
}
|
|
||||||
|
|
||||||
void bpspatch::target(uint8_t *data, unsigned size) {
|
|
||||||
targetData = data;
|
|
||||||
targetSize = size;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool bpspatch::modify(const string &filename) {
|
|
||||||
if(modifyFile.open(filename, filemap::mode::read) == false) return false;
|
|
||||||
return modify(modifyFile.data(), modifyFile.size());
|
|
||||||
}
|
|
||||||
|
|
||||||
bool bpspatch::source(const string &filename) {
|
|
||||||
if(sourceFile.open(filename, filemap::mode::read) == false) return false;
|
|
||||||
source(sourceFile.data(), sourceFile.size());
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool bpspatch::target(const string &filename) {
|
|
||||||
file fp;
|
|
||||||
if(fp.open(filename, file::mode::write) == false) return false;
|
|
||||||
fp.truncate(modifyTargetSize);
|
|
||||||
fp.close();
|
|
||||||
|
|
||||||
if(targetFile.open(filename, filemap::mode::readwrite) == false) return false;
|
|
||||||
target(targetFile.data(), targetFile.size());
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
string bpspatch::metadata() const {
|
|
||||||
return metadataString;
|
|
||||||
}
|
|
||||||
|
|
||||||
unsigned bpspatch::size() const {
|
|
||||||
return modifyTargetSize;
|
|
||||||
}
|
|
||||||
|
|
||||||
bpspatch::result bpspatch::apply() {
|
|
||||||
if(modifySize < 19) return result::patch_too_small;
|
|
||||||
|
|
||||||
uint32_t modifyChecksum = ~0, targetChecksum = ~0;
|
|
||||||
unsigned modifyOffset = 0, sourceRelativeOffset = 0, targetRelativeOffset = 0, outputOffset = 0;
|
|
||||||
|
|
||||||
auto read = [&]() -> uint8_t {
|
|
||||||
uint8_t data = modifyData[modifyOffset++];
|
|
||||||
modifyChecksum = crc32_adjust(modifyChecksum, data);
|
|
||||||
return data;
|
|
||||||
};
|
|
||||||
|
|
||||||
auto decode = [&]() -> uint64_t {
|
|
||||||
uint64_t data = 0, shift = 1;
|
|
||||||
while(true) {
|
|
||||||
uint8_t x = read();
|
|
||||||
data += (x & 0x7f) * shift;
|
|
||||||
if(x & 0x80) break;
|
|
||||||
shift <<= 7;
|
|
||||||
data += shift;
|
|
||||||
}
|
|
||||||
return data;
|
|
||||||
};
|
|
||||||
|
|
||||||
auto write = [&](uint8_t data) {
|
|
||||||
targetData[outputOffset++] = data;
|
|
||||||
targetChecksum = crc32_adjust(targetChecksum, data);
|
|
||||||
};
|
|
||||||
|
|
||||||
if(read() != 'B') return result::patch_invalid_header;
|
|
||||||
if(read() != 'P') return result::patch_invalid_header;
|
|
||||||
if(read() != 'S') return result::patch_invalid_header;
|
|
||||||
if(read() != '1') return result::patch_invalid_header;
|
|
||||||
|
|
||||||
modifySourceSize = decode();
|
|
||||||
modifyTargetSize = decode();
|
|
||||||
modifyMarkupSize = decode();
|
|
||||||
for(unsigned n = 0; n < modifyMarkupSize; n++) read();
|
|
||||||
|
|
||||||
if(modifySourceSize > sourceSize) return result::source_too_small;
|
|
||||||
if(modifyTargetSize > targetSize) return result::target_too_small;
|
|
||||||
|
|
||||||
while(modifyOffset < modifySize - 12) {
|
|
||||||
unsigned length = decode();
|
|
||||||
unsigned mode = length & 3;
|
|
||||||
length = (length >> 2) + 1;
|
|
||||||
|
|
||||||
switch(mode) {
|
|
||||||
case SourceRead:
|
|
||||||
while(length--) write(sourceData[outputOffset]);
|
|
||||||
break;
|
|
||||||
case TargetRead:
|
|
||||||
while(length--) write(read());
|
|
||||||
break;
|
|
||||||
case SourceCopy:
|
|
||||||
case TargetCopy:
|
|
||||||
signed offset = decode();
|
|
||||||
bool negative = offset & 1;
|
|
||||||
offset >>= 1;
|
|
||||||
if(negative) offset = -offset;
|
|
||||||
|
|
||||||
if(mode == SourceCopy) {
|
|
||||||
sourceRelativeOffset += offset;
|
|
||||||
while(length--) write(sourceData[sourceRelativeOffset++]);
|
|
||||||
} else {
|
|
||||||
targetRelativeOffset += offset;
|
|
||||||
while(length--) write(targetData[targetRelativeOffset++]);
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
uint32_t modifySourceChecksum = 0, modifyTargetChecksum = 0, modifyModifyChecksum = 0;
|
|
||||||
for(unsigned n = 0; n < 32; n += 8) modifySourceChecksum |= read() << n;
|
|
||||||
for(unsigned n = 0; n < 32; n += 8) modifyTargetChecksum |= read() << n;
|
|
||||||
uint32_t checksum = ~modifyChecksum;
|
|
||||||
for(unsigned n = 0; n < 32; n += 8) modifyModifyChecksum |= read() << n;
|
|
||||||
|
|
||||||
uint32_t sourceChecksum = crc32_calculate(sourceData, modifySourceSize);
|
|
||||||
targetChecksum = ~targetChecksum;
|
|
||||||
|
|
||||||
if(sourceChecksum != modifySourceChecksum) return result::source_checksum_invalid;
|
|
||||||
if(targetChecksum != modifyTargetChecksum) return result::target_checksum_invalid;
|
|
||||||
if(checksum != modifyModifyChecksum) return result::patch_checksum_invalid;
|
|
||||||
|
|
||||||
return result::success;
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
#endif
|
|
|
@ -1,82 +0,0 @@
|
||||||
#ifndef NALL_BIT_HPP
|
|
||||||
#define NALL_BIT_HPP
|
|
||||||
|
|
||||||
#include <nall/stdint.hpp>
|
|
||||||
|
|
||||||
namespace nall {
|
|
||||||
template<unsigned bits>
|
|
||||||
inline uintmax_t uclamp(const uintmax_t x) {
|
|
||||||
enum : uintmax_t { b = 1ull << (bits - 1), y = b * 2 - 1 };
|
|
||||||
return y + ((x - y) & -(x < y)); //min(x, y);
|
|
||||||
}
|
|
||||||
|
|
||||||
template<unsigned bits>
|
|
||||||
inline uintmax_t uclip(const uintmax_t x) {
|
|
||||||
enum : uintmax_t { b = 1ull << (bits - 1), m = b * 2 - 1 };
|
|
||||||
return (x & m);
|
|
||||||
}
|
|
||||||
|
|
||||||
template<unsigned bits>
|
|
||||||
inline intmax_t sclamp(const intmax_t x) {
|
|
||||||
enum : intmax_t { b = 1ull << (bits - 1), m = b - 1 };
|
|
||||||
return (x > m) ? m : (x < -b) ? -b : x;
|
|
||||||
}
|
|
||||||
|
|
||||||
template<unsigned bits>
|
|
||||||
inline intmax_t sclip(const intmax_t x) {
|
|
||||||
enum : uintmax_t { b = 1ull << (bits - 1), m = b * 2 - 1 };
|
|
||||||
return ((x & m) ^ b) - b;
|
|
||||||
}
|
|
||||||
|
|
||||||
namespace bit {
|
|
||||||
constexpr inline uintmax_t mask(const char *s, uintmax_t sum = 0) {
|
|
||||||
return (
|
|
||||||
*s == '0' || *s == '1' ? mask(s + 1, (sum << 1) | 1) :
|
|
||||||
*s == ' ' || *s == '_' ? mask(s + 1, sum) :
|
|
||||||
*s ? mask(s + 1, sum << 1) :
|
|
||||||
sum
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
constexpr inline uintmax_t test(const char *s, uintmax_t sum = 0) {
|
|
||||||
return (
|
|
||||||
*s == '0' || *s == '1' ? test(s + 1, (sum << 1) | (*s - '0')) :
|
|
||||||
*s == ' ' || *s == '_' ? test(s + 1, sum) :
|
|
||||||
*s ? test(s + 1, sum << 1) :
|
|
||||||
sum
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
//lowest(0b1110) == 0b0010
|
|
||||||
constexpr inline uintmax_t lowest(const uintmax_t x) {
|
|
||||||
return x & -x;
|
|
||||||
}
|
|
||||||
|
|
||||||
//clear_lowest(0b1110) == 0b1100
|
|
||||||
constexpr inline uintmax_t clear_lowest(const uintmax_t x) {
|
|
||||||
return x & (x - 1);
|
|
||||||
}
|
|
||||||
|
|
||||||
//set_lowest(0b0101) == 0b0111
|
|
||||||
constexpr inline uintmax_t set_lowest(const uintmax_t x) {
|
|
||||||
return x | (x + 1);
|
|
||||||
}
|
|
||||||
|
|
||||||
//count number of bits set in a byte
|
|
||||||
inline unsigned count(uintmax_t x) {
|
|
||||||
unsigned count = 0;
|
|
||||||
do count += x & 1; while(x >>= 1);
|
|
||||||
return count;
|
|
||||||
}
|
|
||||||
|
|
||||||
//round up to next highest single bit:
|
|
||||||
//round(15) == 16, round(16) == 16, round(17) == 32
|
|
||||||
inline uintmax_t round(uintmax_t x) {
|
|
||||||
if((x & (x - 1)) == 0) return x;
|
|
||||||
while(x & (x - 1)) x &= x - 1;
|
|
||||||
return x << 1;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#endif
|
|
|
@ -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 bool read(const string &filename, uint32_t *&data, unsigned &width, unsigned &height);
|
|
||||||
inline static bool write(const string &filename, const uint32_t *data, unsigned width, unsigned height, unsigned pitch, bool alpha = false);
|
|
||||||
};
|
|
||||||
|
|
||||||
bool bmp::read(const string &filename, uint32_t *&data, unsigned &width, unsigned &height) {
|
|
||||||
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;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool bmp::write(const string &filename, const uint32_t *data, unsigned width, unsigned height, unsigned pitch, bool alpha) {
|
|
||||||
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
|
|
|
@ -1,152 +0,0 @@
|
||||||
#ifndef NALL_COMPOSITOR_HPP
|
|
||||||
#define NALL_COMPOSITOR_HPP
|
|
||||||
|
|
||||||
#include <nall/intrinsics.hpp>
|
|
||||||
|
|
||||||
namespace nall {
|
|
||||||
|
|
||||||
struct compositor {
|
|
||||||
inline static bool enabled();
|
|
||||||
inline static bool enable(bool status);
|
|
||||||
|
|
||||||
#if defined(PLATFORM_X)
|
|
||||||
enum class Compositor : unsigned { Unknown, Metacity, Xfwm4 };
|
|
||||||
inline static Compositor detect();
|
|
||||||
|
|
||||||
inline static bool enabled_metacity();
|
|
||||||
inline static bool enable_metacity(bool status);
|
|
||||||
|
|
||||||
inline static bool enabled_xfwm4();
|
|
||||||
inline static bool enable_xfwm4(bool status);
|
|
||||||
#endif
|
|
||||||
};
|
|
||||||
|
|
||||||
#if defined(PLATFORM_X)
|
|
||||||
|
|
||||||
//Metacity
|
|
||||||
|
|
||||||
bool compositor::enabled_metacity() {
|
|
||||||
FILE *fp = popen("gconftool-2 --get /apps/metacity/general/compositing_manager", "r");
|
|
||||||
if(!fp) return false;
|
|
||||||
|
|
||||||
char buffer[512];
|
|
||||||
if(!fgets(buffer, sizeof buffer, fp)) return false;
|
|
||||||
|
|
||||||
if(!memcmp(buffer, "true", 4)) return true;
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool compositor::enable_metacity(bool status) {
|
|
||||||
FILE *fp;
|
|
||||||
if(status) {
|
|
||||||
fp = popen("gconftool-2 --set --type bool /apps/metacity/general/compositing_manager true", "r");
|
|
||||||
} else {
|
|
||||||
fp = popen("gconftool-2 --set --type bool /apps/metacity/general/compositing_manager false", "r");
|
|
||||||
}
|
|
||||||
if(!fp) return false;
|
|
||||||
pclose(fp);
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
//Xfwm4
|
|
||||||
|
|
||||||
bool compositor::enabled_xfwm4() {
|
|
||||||
FILE *fp = popen("xfconf-query -c xfwm4 -p '/general/use_compositing'", "r");
|
|
||||||
if(!fp) return false;
|
|
||||||
|
|
||||||
char buffer[512];
|
|
||||||
if(!fgets(buffer, sizeof buffer, fp)) return false;
|
|
||||||
|
|
||||||
if(!memcmp(buffer, "true", 4)) return true;
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool compositor::enable_xfwm4(bool status) {
|
|
||||||
FILE *fp;
|
|
||||||
if(status) {
|
|
||||||
fp = popen("xfconf-query -c xfwm4 -p '/general/use_compositing' -t 'bool' -s 'true'", "r");
|
|
||||||
} else {
|
|
||||||
fp = popen("xfconf-query -c xfwm4 -p '/general/use_compositing' -t 'bool' -s 'false'", "r");
|
|
||||||
}
|
|
||||||
if(!fp) return false;
|
|
||||||
pclose(fp);
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
//General
|
|
||||||
|
|
||||||
compositor::Compositor compositor::detect() {
|
|
||||||
Compositor result = Compositor::Unknown;
|
|
||||||
|
|
||||||
FILE *fp;
|
|
||||||
char buffer[512];
|
|
||||||
|
|
||||||
fp = popen("pidof metacity", "r");
|
|
||||||
if(fp && fgets(buffer, sizeof buffer, fp)) result = Compositor::Metacity;
|
|
||||||
pclose(fp);
|
|
||||||
|
|
||||||
fp = popen("pidof xfwm4", "r");
|
|
||||||
if(fp && fgets(buffer, sizeof buffer, fp)) result = Compositor::Xfwm4;
|
|
||||||
pclose(fp);
|
|
||||||
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool compositor::enabled() {
|
|
||||||
switch(detect()) {
|
|
||||||
case Compositor::Metacity: return enabled_metacity();
|
|
||||||
case Compositor::Xfwm4: return enabled_xfwm4();
|
|
||||||
default: return false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
bool compositor::enable(bool status) {
|
|
||||||
switch(detect()) {
|
|
||||||
case Compositor::Metacity: return enable_metacity(status);
|
|
||||||
case Compositor::Xfwm4: return enable_xfwm4(status);
|
|
||||||
default: return false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#elif defined(PLATFORM_WINDOWS)
|
|
||||||
|
|
||||||
bool compositor::enabled() {
|
|
||||||
HMODULE module = GetModuleHandleW(L"dwmapi");
|
|
||||||
if(module == nullptr) module = LoadLibraryW(L"dwmapi");
|
|
||||||
if(module == nullptr) return false;
|
|
||||||
|
|
||||||
auto pDwmIsCompositionEnabled = (HRESULT (WINAPI*)(BOOL*))GetProcAddress(module, "DwmIsCompositionEnabled");
|
|
||||||
if(pDwmIsCompositionEnabled == nullptr) return false;
|
|
||||||
|
|
||||||
BOOL result;
|
|
||||||
if(pDwmIsCompositionEnabled(&result) != S_OK) return false;
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool compositor::enable(bool status) {
|
|
||||||
HMODULE module = GetModuleHandleW(L"dwmapi");
|
|
||||||
if(module == nullptr) module = LoadLibraryW(L"dwmapi");
|
|
||||||
if(module == nullptr) return false;
|
|
||||||
|
|
||||||
auto pDwmEnableComposition = (HRESULT (WINAPI*)(UINT))GetProcAddress(module, "DwmEnableComposition");
|
|
||||||
if(pDwmEnableComposition == nullptr) return false;
|
|
||||||
|
|
||||||
if(pDwmEnableComposition(status) != S_OK) return false;
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
#else
|
|
||||||
|
|
||||||
bool compositor::enabled() {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool compositor::enable(bool) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
#endif
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
#endif
|
|
|
@ -1,126 +0,0 @@
|
||||||
#ifndef NALL_CONFIG_HPP
|
|
||||||
#define NALL_CONFIG_HPP
|
|
||||||
|
|
||||||
#include <nall/file.hpp>
|
|
||||||
#include <nall/string.hpp>
|
|
||||||
#include <nall/vector.hpp>
|
|
||||||
|
|
||||||
namespace nall {
|
|
||||||
namespace configuration_traits {
|
|
||||||
template<typename T> struct is_boolean { enum { value = false }; };
|
|
||||||
template<> struct is_boolean<bool> { enum { value = true }; };
|
|
||||||
|
|
||||||
template<typename T> struct is_signed { enum { value = false }; };
|
|
||||||
template<> struct is_signed<signed> { enum { value = true }; };
|
|
||||||
|
|
||||||
template<typename T> struct is_unsigned { enum { value = false }; };
|
|
||||||
template<> struct is_unsigned<unsigned> { enum { value = true }; };
|
|
||||||
|
|
||||||
template<typename T> struct is_double { enum { value = false }; };
|
|
||||||
template<> struct is_double<double> { enum { value = true }; };
|
|
||||||
|
|
||||||
template<typename T> struct is_string { enum { value = false }; };
|
|
||||||
template<> struct is_string<string> { enum { value = true }; };
|
|
||||||
}
|
|
||||||
|
|
||||||
class configuration {
|
|
||||||
public:
|
|
||||||
enum type_t { boolean_t, signed_t, unsigned_t, double_t, string_t, unknown_t };
|
|
||||||
struct item_t {
|
|
||||||
uintptr_t data;
|
|
||||||
string name;
|
|
||||||
string desc;
|
|
||||||
type_t type;
|
|
||||||
|
|
||||||
inline string get() const {
|
|
||||||
switch(type) {
|
|
||||||
case boolean_t: return { *(bool*)data };
|
|
||||||
case signed_t: return { *(signed*)data };
|
|
||||||
case unsigned_t: return { *(unsigned*)data };
|
|
||||||
case double_t: return { *(double*)data };
|
|
||||||
case string_t: return { "\"", *(string*)data, "\"" };
|
|
||||||
}
|
|
||||||
return "???";
|
|
||||||
}
|
|
||||||
|
|
||||||
inline void set(string s) {
|
|
||||||
switch(type) {
|
|
||||||
case boolean_t: *(bool*)data = (s == "true"); break;
|
|
||||||
case signed_t: *(signed*)data = integer(s); break;
|
|
||||||
case unsigned_t: *(unsigned*)data = decimal(s); break;
|
|
||||||
case double_t: *(double*)data = fp(s); break;
|
|
||||||
case string_t: s.trim("\""); *(string*)data = s; break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
};
|
|
||||||
vector<item_t> list;
|
|
||||||
|
|
||||||
template<typename T>
|
|
||||||
inline void append(T &data, const char *name, const char *desc = "") {
|
|
||||||
item_t item = { (uintptr_t)&data, name, desc };
|
|
||||||
if(configuration_traits::is_boolean<T>::value) item.type = boolean_t;
|
|
||||||
else if(configuration_traits::is_signed<T>::value) item.type = signed_t;
|
|
||||||
else if(configuration_traits::is_unsigned<T>::value) item.type = unsigned_t;
|
|
||||||
else if(configuration_traits::is_double<T>::value) item.type = double_t;
|
|
||||||
else if(configuration_traits::is_string<T>::value) item.type = string_t;
|
|
||||||
else item.type = unknown_t;
|
|
||||||
list.append(item);
|
|
||||||
}
|
|
||||||
|
|
||||||
//deprecated
|
|
||||||
template<typename T>
|
|
||||||
inline void attach(T &data, const char *name, const char *desc = "") {
|
|
||||||
append(data, name, desc);
|
|
||||||
}
|
|
||||||
|
|
||||||
inline virtual bool load(const string &filename) {
|
|
||||||
string data;
|
|
||||||
if(data.readfile(filename) == true) {
|
|
||||||
data.replace("\r", "");
|
|
||||||
lstring line;
|
|
||||||
line.split("\n", data);
|
|
||||||
|
|
||||||
for(unsigned i = 0; i < line.size(); i++) {
|
|
||||||
if(auto position = qstrpos(line[i], "#")) line[i][position()] = 0;
|
|
||||||
if(!qstrpos(line[i], " = ")) continue;
|
|
||||||
|
|
||||||
lstring part;
|
|
||||||
part.qsplit(" = ", line[i]);
|
|
||||||
part[0].trim();
|
|
||||||
part[1].trim();
|
|
||||||
|
|
||||||
for(unsigned n = 0; n < list.size(); n++) {
|
|
||||||
if(part[0] == list[n].name) {
|
|
||||||
list[n].set(part[1]);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return true;
|
|
||||||
} else {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
inline virtual bool save(const string &filename) const {
|
|
||||||
file fp;
|
|
||||||
if(fp.open(filename, file::mode::write)) {
|
|
||||||
for(unsigned i = 0; i < list.size(); i++) {
|
|
||||||
string output;
|
|
||||||
output.append(list[i].name, " = ", list[i].get());
|
|
||||||
if(list[i].desc != "") output.append(" # ", list[i].desc);
|
|
||||||
output.append("\r\n");
|
|
||||||
fp.print(output);
|
|
||||||
}
|
|
||||||
|
|
||||||
fp.close();
|
|
||||||
return true;
|
|
||||||
} else {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
#endif
|
|
|
@ -1,25 +0,0 @@
|
||||||
#ifndef NALL_CRC16_HPP
|
|
||||||
#define NALL_CRC16_HPP
|
|
||||||
|
|
||||||
#include <nall/stdint.hpp>
|
|
||||||
|
|
||||||
namespace nall {
|
|
||||||
inline uint16_t crc16_adjust(uint16_t crc16, uint8_t data) {
|
|
||||||
for(unsigned n = 0; n < 8; n++) {
|
|
||||||
if((crc16 & 1) ^ (data & 1)) crc16 = (crc16 >> 1) ^ 0x8408;
|
|
||||||
else crc16 >>= 1;
|
|
||||||
data >>= 1;
|
|
||||||
}
|
|
||||||
return crc16;
|
|
||||||
}
|
|
||||||
|
|
||||||
inline uint16_t crc16_calculate(const uint8_t *data, unsigned length) {
|
|
||||||
uint16_t crc16 = ~0;
|
|
||||||
for(unsigned n = 0; n < length; n++) {
|
|
||||||
crc16 = crc16_adjust(crc16, data[n]);
|
|
||||||
}
|
|
||||||
return ~crc16;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#endif
|
|
|
@ -1,66 +0,0 @@
|
||||||
#ifndef NALL_CRC32_HPP
|
|
||||||
#define NALL_CRC32_HPP
|
|
||||||
|
|
||||||
#include <nall/stdint.hpp>
|
|
||||||
|
|
||||||
namespace nall {
|
|
||||||
const uint32_t crc32_table[256] = {
|
|
||||||
0x00000000, 0x77073096, 0xee0e612c, 0x990951ba, 0x076dc419, 0x706af48f,
|
|
||||||
0xe963a535, 0x9e6495a3, 0x0edb8832, 0x79dcb8a4, 0xe0d5e91e, 0x97d2d988,
|
|
||||||
0x09b64c2b, 0x7eb17cbd, 0xe7b82d07, 0x90bf1d91, 0x1db71064, 0x6ab020f2,
|
|
||||||
0xf3b97148, 0x84be41de, 0x1adad47d, 0x6ddde4eb, 0xf4d4b551, 0x83d385c7,
|
|
||||||
0x136c9856, 0x646ba8c0, 0xfd62f97a, 0x8a65c9ec, 0x14015c4f, 0x63066cd9,
|
|
||||||
0xfa0f3d63, 0x8d080df5, 0x3b6e20c8, 0x4c69105e, 0xd56041e4, 0xa2677172,
|
|
||||||
0x3c03e4d1, 0x4b04d447, 0xd20d85fd, 0xa50ab56b, 0x35b5a8fa, 0x42b2986c,
|
|
||||||
0xdbbbc9d6, 0xacbcf940, 0x32d86ce3, 0x45df5c75, 0xdcd60dcf, 0xabd13d59,
|
|
||||||
0x26d930ac, 0x51de003a, 0xc8d75180, 0xbfd06116, 0x21b4f4b5, 0x56b3c423,
|
|
||||||
0xcfba9599, 0xb8bda50f, 0x2802b89e, 0x5f058808, 0xc60cd9b2, 0xb10be924,
|
|
||||||
0x2f6f7c87, 0x58684c11, 0xc1611dab, 0xb6662d3d, 0x76dc4190, 0x01db7106,
|
|
||||||
0x98d220bc, 0xefd5102a, 0x71b18589, 0x06b6b51f, 0x9fbfe4a5, 0xe8b8d433,
|
|
||||||
0x7807c9a2, 0x0f00f934, 0x9609a88e, 0xe10e9818, 0x7f6a0dbb, 0x086d3d2d,
|
|
||||||
0x91646c97, 0xe6635c01, 0x6b6b51f4, 0x1c6c6162, 0x856530d8, 0xf262004e,
|
|
||||||
0x6c0695ed, 0x1b01a57b, 0x8208f4c1, 0xf50fc457, 0x65b0d9c6, 0x12b7e950,
|
|
||||||
0x8bbeb8ea, 0xfcb9887c, 0x62dd1ddf, 0x15da2d49, 0x8cd37cf3, 0xfbd44c65,
|
|
||||||
0x4db26158, 0x3ab551ce, 0xa3bc0074, 0xd4bb30e2, 0x4adfa541, 0x3dd895d7,
|
|
||||||
0xa4d1c46d, 0xd3d6f4fb, 0x4369e96a, 0x346ed9fc, 0xad678846, 0xda60b8d0,
|
|
||||||
0x44042d73, 0x33031de5, 0xaa0a4c5f, 0xdd0d7cc9, 0x5005713c, 0x270241aa,
|
|
||||||
0xbe0b1010, 0xc90c2086, 0x5768b525, 0x206f85b3, 0xb966d409, 0xce61e49f,
|
|
||||||
0x5edef90e, 0x29d9c998, 0xb0d09822, 0xc7d7a8b4, 0x59b33d17, 0x2eb40d81,
|
|
||||||
0xb7bd5c3b, 0xc0ba6cad, 0xedb88320, 0x9abfb3b6, 0x03b6e20c, 0x74b1d29a,
|
|
||||||
0xead54739, 0x9dd277af, 0x04db2615, 0x73dc1683, 0xe3630b12, 0x94643b84,
|
|
||||||
0x0d6d6a3e, 0x7a6a5aa8, 0xe40ecf0b, 0x9309ff9d, 0x0a00ae27, 0x7d079eb1,
|
|
||||||
0xf00f9344, 0x8708a3d2, 0x1e01f268, 0x6906c2fe, 0xf762575d, 0x806567cb,
|
|
||||||
0x196c3671, 0x6e6b06e7, 0xfed41b76, 0x89d32be0, 0x10da7a5a, 0x67dd4acc,
|
|
||||||
0xf9b9df6f, 0x8ebeeff9, 0x17b7be43, 0x60b08ed5, 0xd6d6a3e8, 0xa1d1937e,
|
|
||||||
0x38d8c2c4, 0x4fdff252, 0xd1bb67f1, 0xa6bc5767, 0x3fb506dd, 0x48b2364b,
|
|
||||||
0xd80d2bda, 0xaf0a1b4c, 0x36034af6, 0x41047a60, 0xdf60efc3, 0xa867df55,
|
|
||||||
0x316e8eef, 0x4669be79, 0xcb61b38c, 0xbc66831a, 0x256fd2a0, 0x5268e236,
|
|
||||||
0xcc0c7795, 0xbb0b4703, 0x220216b9, 0x5505262f, 0xc5ba3bbe, 0xb2bd0b28,
|
|
||||||
0x2bb45a92, 0x5cb36a04, 0xc2d7ffa7, 0xb5d0cf31, 0x2cd99e8b, 0x5bdeae1d,
|
|
||||||
0x9b64c2b0, 0xec63f226, 0x756aa39c, 0x026d930a, 0x9c0906a9, 0xeb0e363f,
|
|
||||||
0x72076785, 0x05005713, 0x95bf4a82, 0xe2b87a14, 0x7bb12bae, 0x0cb61b38,
|
|
||||||
0x92d28e9b, 0xe5d5be0d, 0x7cdcefb7, 0x0bdbdf21, 0x86d3d2d4, 0xf1d4e242,
|
|
||||||
0x68ddb3f8, 0x1fda836e, 0x81be16cd, 0xf6b9265b, 0x6fb077e1, 0x18b74777,
|
|
||||||
0x88085ae6, 0xff0f6a70, 0x66063bca, 0x11010b5c, 0x8f659eff, 0xf862ae69,
|
|
||||||
0x616bffd3, 0x166ccf45, 0xa00ae278, 0xd70dd2ee, 0x4e048354, 0x3903b3c2,
|
|
||||||
0xa7672661, 0xd06016f7, 0x4969474d, 0x3e6e77db, 0xaed16a4a, 0xd9d65adc,
|
|
||||||
0x40df0b66, 0x37d83bf0, 0xa9bcae53, 0xdebb9ec5, 0x47b2cf7f, 0x30b5ffe9,
|
|
||||||
0xbdbdf21c, 0xcabac28a, 0x53b39330, 0x24b4a3a6, 0xbad03605, 0xcdd70693,
|
|
||||||
0x54de5729, 0x23d967bf, 0xb3667a2e, 0xc4614ab8, 0x5d681b02, 0x2a6f2b94,
|
|
||||||
0xb40bbe37, 0xc30c8ea1, 0x5a05df1b, 0x2d02ef8d
|
|
||||||
};
|
|
||||||
|
|
||||||
inline uint32_t crc32_adjust(uint32_t crc32, uint8_t input) {
|
|
||||||
return ((crc32 >> 8) & 0x00ffffff) ^ crc32_table[(crc32 ^ input) & 0xff];
|
|
||||||
}
|
|
||||||
|
|
||||||
inline uint32_t crc32_calculate(const uint8_t *data, unsigned length) {
|
|
||||||
uint32_t crc32 = ~0;
|
|
||||||
for(unsigned i = 0; i < length; i++) {
|
|
||||||
crc32 = crc32_adjust(crc32, data[i]);
|
|
||||||
}
|
|
||||||
return ~crc32;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#endif
|
|
|
@ -1,224 +0,0 @@
|
||||||
#ifndef NALL_DIRECTORY_HPP
|
|
||||||
#define NALL_DIRECTORY_HPP
|
|
||||||
|
|
||||||
#include <nall/file.hpp>
|
|
||||||
#include <nall/intrinsics.hpp>
|
|
||||||
#include <nall/sort.hpp>
|
|
||||||
#include <nall/string.hpp>
|
|
||||||
#include <nall/vector.hpp>
|
|
||||||
|
|
||||||
#if defined(PLATFORM_WINDOWS)
|
|
||||||
#include <nall/windows/utf8.hpp>
|
|
||||||
#else
|
|
||||||
#include <dirent.h>
|
|
||||||
#include <stdio.h>
|
|
||||||
#include <sys/types.h>
|
|
||||||
#endif
|
|
||||||
|
|
||||||
namespace nall {
|
|
||||||
|
|
||||||
struct directory {
|
|
||||||
static bool create(const string &pathname, unsigned permissions = 0755); //recursive
|
|
||||||
static bool remove(const string &pathname); //recursive
|
|
||||||
static bool exists(const string &pathname);
|
|
||||||
|
|
||||||
static lstring folders(const string &pathname, const string &pattern = "*") {
|
|
||||||
lstring folders = directory::ufolders(pathname, pattern);
|
|
||||||
folders.sort();
|
|
||||||
return folders;
|
|
||||||
}
|
|
||||||
|
|
||||||
static lstring files(const string &pathname, const string &pattern = "*") {
|
|
||||||
lstring files = directory::ufiles(pathname, pattern);
|
|
||||||
files.sort();
|
|
||||||
return files;
|
|
||||||
}
|
|
||||||
|
|
||||||
static lstring contents(const string &pathname, const string &pattern = "*") {
|
|
||||||
lstring folders = directory::ufolders(pathname); //pattern search of contents should only filter files
|
|
||||||
lstring files = directory::ufiles(pathname, pattern);
|
|
||||||
folders.sort();
|
|
||||||
files.sort();
|
|
||||||
for(auto &file : files) folders.append(file);
|
|
||||||
return folders;
|
|
||||||
}
|
|
||||||
|
|
||||||
static lstring ifolders(const string &pathname, const string &pattern = "*") {
|
|
||||||
lstring folders = ufolders(pathname, pattern);
|
|
||||||
folders.isort();
|
|
||||||
return folders;
|
|
||||||
}
|
|
||||||
|
|
||||||
static lstring ifiles(const string &pathname, const string &pattern = "*") {
|
|
||||||
lstring files = ufiles(pathname, pattern);
|
|
||||||
files.isort();
|
|
||||||
return files;
|
|
||||||
}
|
|
||||||
|
|
||||||
static lstring icontents(const string &pathname, const string &pattern = "*") {
|
|
||||||
lstring folders = directory::ufolders(pathname); //pattern search of contents should only filter files
|
|
||||||
lstring files = directory::ufiles(pathname, pattern);
|
|
||||||
folders.isort();
|
|
||||||
files.isort();
|
|
||||||
for(auto &file : files) folders.append(file);
|
|
||||||
return folders;
|
|
||||||
}
|
|
||||||
|
|
||||||
private:
|
|
||||||
//internal functions; these return unsorted lists
|
|
||||||
static lstring ufolders(const string &pathname, const string &pattern = "*");
|
|
||||||
static lstring ufiles(const string &pathname, const string &pattern = "*");
|
|
||||||
};
|
|
||||||
|
|
||||||
#if defined(PLATFORM_WINDOWS)
|
|
||||||
inline bool directory::create(const string &pathname, unsigned permissions) {
|
|
||||||
string path;
|
|
||||||
lstring list = string{pathname}.transform("\\", "/").rtrim<1>("/").split("/");
|
|
||||||
bool result = true;
|
|
||||||
for(auto &part : list) {
|
|
||||||
path.append(part, "/");
|
|
||||||
result &= (_wmkdir(utf16_t(path)) == 0);
|
|
||||||
}
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
inline bool directory::remove(const string &pathname) {
|
|
||||||
lstring list = directory::contents(pathname);
|
|
||||||
for(auto &name : list) {
|
|
||||||
if(name.endswith("/")) directory::remove({pathname, name});
|
|
||||||
else file::remove({pathname, name});
|
|
||||||
}
|
|
||||||
return _wrmdir(utf16_t(pathname)) == 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
inline bool directory::exists(const string &pathname) {
|
|
||||||
string name = pathname;
|
|
||||||
name.trim<1>("\"");
|
|
||||||
DWORD result = GetFileAttributes(utf16_t(name));
|
|
||||||
if(result == INVALID_FILE_ATTRIBUTES) return false;
|
|
||||||
return (result & FILE_ATTRIBUTE_DIRECTORY);
|
|
||||||
}
|
|
||||||
|
|
||||||
inline lstring directory::ufolders(const string &pathname, const string &pattern) {
|
|
||||||
lstring list;
|
|
||||||
string path = pathname;
|
|
||||||
path.transform("/", "\\");
|
|
||||||
if(!strend(path, "\\")) path.append("\\");
|
|
||||||
path.append("*");
|
|
||||||
HANDLE handle;
|
|
||||||
WIN32_FIND_DATA data;
|
|
||||||
handle = FindFirstFile(utf16_t(path), &data);
|
|
||||||
if(handle != INVALID_HANDLE_VALUE) {
|
|
||||||
if(wcscmp(data.cFileName, L".") && wcscmp(data.cFileName, L"..")) {
|
|
||||||
if(data.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) {
|
|
||||||
string name = (const char*)utf8_t(data.cFileName);
|
|
||||||
if(wildcard(name, pattern)) list.append(name);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
while(FindNextFile(handle, &data) != false) {
|
|
||||||
if(wcscmp(data.cFileName, L".") && wcscmp(data.cFileName, L"..")) {
|
|
||||||
if(data.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) {
|
|
||||||
string name = (const char*)utf8_t(data.cFileName);
|
|
||||||
if(wildcard(name, pattern)) list.append(name);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
FindClose(handle);
|
|
||||||
}
|
|
||||||
for(auto &name : list) name.append("/"); //must append after sorting
|
|
||||||
return list;
|
|
||||||
}
|
|
||||||
|
|
||||||
inline lstring directory::ufiles(const string &pathname, const string &pattern) {
|
|
||||||
lstring list;
|
|
||||||
string path = pathname;
|
|
||||||
path.transform("/", "\\");
|
|
||||||
if(!strend(path, "\\")) path.append("\\");
|
|
||||||
path.append("*");
|
|
||||||
HANDLE handle;
|
|
||||||
WIN32_FIND_DATA data;
|
|
||||||
handle = FindFirstFile(utf16_t(path), &data);
|
|
||||||
if(handle != INVALID_HANDLE_VALUE) {
|
|
||||||
if((data.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) == 0) {
|
|
||||||
string name = (const char*)utf8_t(data.cFileName);
|
|
||||||
if(wildcard(name, pattern)) list.append(name);
|
|
||||||
}
|
|
||||||
while(FindNextFile(handle, &data) != false) {
|
|
||||||
if((data.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) == 0) {
|
|
||||||
string name = (const char*)utf8_t(data.cFileName);
|
|
||||||
if(wildcard(name, pattern)) list.append(name);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
FindClose(handle);
|
|
||||||
}
|
|
||||||
return list;
|
|
||||||
}
|
|
||||||
#else
|
|
||||||
inline bool directory::create(const string &pathname, unsigned permissions) {
|
|
||||||
string path;
|
|
||||||
lstring list = string{pathname}.rtrim<1>("/").split("/");
|
|
||||||
bool result = true;
|
|
||||||
for(auto &part : list) {
|
|
||||||
path.append(part, "/");
|
|
||||||
result &= (mkdir(path, permissions) == 0);
|
|
||||||
}
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
inline bool directory::remove(const string &pathname) {
|
|
||||||
lstring list = directory::contents(pathname);
|
|
||||||
for(auto &name : list) {
|
|
||||||
if(name.endswith("/")) directory::remove({pathname, name});
|
|
||||||
else file::remove({pathname, name});
|
|
||||||
}
|
|
||||||
return rmdir(pathname) == 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
inline bool directory::exists(const string &pathname) {
|
|
||||||
DIR *dp = opendir(pathname);
|
|
||||||
if(!dp) return false;
|
|
||||||
closedir(dp);
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
inline lstring directory::ufolders(const string &pathname, const string &pattern) {
|
|
||||||
lstring list;
|
|
||||||
DIR *dp;
|
|
||||||
struct dirent *ep;
|
|
||||||
dp = opendir(pathname);
|
|
||||||
if(dp) {
|
|
||||||
while(ep = readdir(dp)) {
|
|
||||||
if(!strcmp(ep->d_name, ".")) continue;
|
|
||||||
if(!strcmp(ep->d_name, "..")) continue;
|
|
||||||
if(ep->d_type & DT_DIR) {
|
|
||||||
if(wildcard(ep->d_name, pattern)) list.append(ep->d_name);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
closedir(dp);
|
|
||||||
}
|
|
||||||
for(auto &name : list) name.append("/"); //must append after sorting
|
|
||||||
return list;
|
|
||||||
}
|
|
||||||
|
|
||||||
inline lstring directory::ufiles(const string &pathname, const string &pattern) {
|
|
||||||
lstring list;
|
|
||||||
DIR *dp;
|
|
||||||
struct dirent *ep;
|
|
||||||
dp = opendir(pathname);
|
|
||||||
if(dp) {
|
|
||||||
while(ep = readdir(dp)) {
|
|
||||||
if(!strcmp(ep->d_name, ".")) continue;
|
|
||||||
if(!strcmp(ep->d_name, "..")) continue;
|
|
||||||
if((ep->d_type & DT_DIR) == 0) {
|
|
||||||
if(wildcard(ep->d_name, pattern)) list.append(ep->d_name);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
closedir(dp);
|
|
||||||
}
|
|
||||||
return list;
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
#endif
|
|
|
@ -1,117 +0,0 @@
|
||||||
#ifndef NALL_DL_HPP
|
|
||||||
#define NALL_DL_HPP
|
|
||||||
|
|
||||||
//dynamic linking support
|
|
||||||
|
|
||||||
#include <nall/intrinsics.hpp>
|
|
||||||
#include <nall/stdint.hpp>
|
|
||||||
#include <nall/string.hpp>
|
|
||||||
#include <nall/utility.hpp>
|
|
||||||
|
|
||||||
#if defined(PLATFORM_X) || defined(PLATFORM_OSX)
|
|
||||||
#include <dlfcn.h>
|
|
||||||
#elif defined(PLATFORM_WINDOWS)
|
|
||||||
#include <windows.h>
|
|
||||||
#include <nall/windows/utf8.hpp>
|
|
||||||
#endif
|
|
||||||
|
|
||||||
namespace nall {
|
|
||||||
struct library {
|
|
||||||
explicit operator bool() const { return open(); }
|
|
||||||
bool open() const { return handle; }
|
|
||||||
bool open(const char*, const char* = "");
|
|
||||||
bool open_absolute(const char*);
|
|
||||||
void* sym(const char*);
|
|
||||||
void close();
|
|
||||||
|
|
||||||
library() : handle(0) {}
|
|
||||||
~library() { close(); }
|
|
||||||
|
|
||||||
library& operator=(const library&) = delete;
|
|
||||||
library(const library&) = delete;
|
|
||||||
|
|
||||||
private:
|
|
||||||
uintptr_t handle;
|
|
||||||
};
|
|
||||||
|
|
||||||
#if defined(PLATFORM_X)
|
|
||||||
inline bool library::open(const char *name, const char *path) {
|
|
||||||
if(handle) close();
|
|
||||||
handle = (uintptr_t)dlopen(string(path, *path && !strend(path, "/") ? "/" : "", "lib", name, ".so"), RTLD_LAZY);
|
|
||||||
if(!handle) handle = (uintptr_t)dlopen(string("/usr/local/lib/lib", name, ".so"), RTLD_LAZY);
|
|
||||||
return handle;
|
|
||||||
}
|
|
||||||
|
|
||||||
inline bool library::open_absolute(const char *name) {
|
|
||||||
if(handle) close();
|
|
||||||
handle = (uintptr_t)dlopen(name, RTLD_LAZY);
|
|
||||||
return handle;
|
|
||||||
}
|
|
||||||
|
|
||||||
inline void* library::sym(const char *name) {
|
|
||||||
if(!handle) return nullptr;
|
|
||||||
return dlsym((void*)handle, name);
|
|
||||||
}
|
|
||||||
|
|
||||||
inline void library::close() {
|
|
||||||
if(!handle) return;
|
|
||||||
dlclose((void*)handle);
|
|
||||||
handle = 0;
|
|
||||||
}
|
|
||||||
#elif defined(PLATFORM_OSX)
|
|
||||||
inline bool library::open(const char *name, const char *path) {
|
|
||||||
if(handle) close();
|
|
||||||
handle = (uintptr_t)dlopen(string(path, *path && !strend(path, "/") ? "/" : "", "lib", name, ".dylib"), RTLD_LAZY);
|
|
||||||
if(!handle) handle = (uintptr_t)dlopen(string("/usr/local/lib/lib", name, ".dylib"), RTLD_LAZY);
|
|
||||||
return handle;
|
|
||||||
}
|
|
||||||
|
|
||||||
inline bool library::open_absolute(const char *name) {
|
|
||||||
if(handle) close();
|
|
||||||
handle = (uintptr_t)dlopen(name, RTLD_LAZY);
|
|
||||||
return handle;
|
|
||||||
}
|
|
||||||
|
|
||||||
inline void* library::sym(const char *name) {
|
|
||||||
if(!handle) return nullptr;
|
|
||||||
return dlsym((void*)handle, name);
|
|
||||||
}
|
|
||||||
|
|
||||||
inline void library::close() {
|
|
||||||
if(!handle) return;
|
|
||||||
dlclose((void*)handle);
|
|
||||||
handle = 0;
|
|
||||||
}
|
|
||||||
#elif defined(PLATFORM_WINDOWS)
|
|
||||||
inline bool library::open(const char *name, const char *path) {
|
|
||||||
if(handle) close();
|
|
||||||
string filepath(path, *path && !strend(path, "/") && !strend(path, "\\") ? "\\" : "", name, ".dll");
|
|
||||||
handle = (uintptr_t)LoadLibraryW(utf16_t(filepath));
|
|
||||||
return handle;
|
|
||||||
}
|
|
||||||
|
|
||||||
inline bool library::open_absolute(const char *name) {
|
|
||||||
if(handle) close();
|
|
||||||
handle = (uintptr_t)LoadLibraryW(utf16_t(name));
|
|
||||||
return handle;
|
|
||||||
}
|
|
||||||
|
|
||||||
inline void* library::sym(const char *name) {
|
|
||||||
if(!handle) return nullptr;
|
|
||||||
return (void*)GetProcAddress((HMODULE)handle, name);
|
|
||||||
}
|
|
||||||
|
|
||||||
inline void library::close() {
|
|
||||||
if(!handle) return;
|
|
||||||
FreeLibrary((HMODULE)handle);
|
|
||||||
handle = 0;
|
|
||||||
}
|
|
||||||
#else
|
|
||||||
inline bool library::open(const char*, const char*) { return false; }
|
|
||||||
inline bool library::open_absolute(const char*) { return false; }
|
|
||||||
inline void* library::sym(const char*) { return nullptr; }
|
|
||||||
inline void library::close() {}
|
|
||||||
#endif
|
|
||||||
};
|
|
||||||
|
|
||||||
#endif
|
|
|
@ -1,13 +0,0 @@
|
||||||
#ifndef NALL_DSP_HPP
|
|
||||||
#define NALL_DSP_HPP
|
|
||||||
|
|
||||||
#include <algorithm>
|
|
||||||
#ifdef __SSE__
|
|
||||||
#include <xmmintrin.h>
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#define NALL_DSP_INTERNAL_HPP
|
|
||||||
#include <nall/dsp/core.hpp>
|
|
||||||
#undef NALL_DSP_INTERNAL_HPP
|
|
||||||
|
|
||||||
#endif
|
|
|
@ -1,52 +0,0 @@
|
||||||
#ifdef NALL_DSP_INTERNAL_HPP
|
|
||||||
|
|
||||||
struct Buffer {
|
|
||||||
double **sample = nullptr;
|
|
||||||
uint16_t rdoffset = 0;
|
|
||||||
uint16_t wroffset = 0;
|
|
||||||
unsigned channels = 0;
|
|
||||||
|
|
||||||
void setChannels(unsigned channels) {
|
|
||||||
if(sample) {
|
|
||||||
for(unsigned c = 0; c < this->channels; c++) {
|
|
||||||
if(sample[c]) delete[] sample[c];
|
|
||||||
}
|
|
||||||
delete[] sample;
|
|
||||||
}
|
|
||||||
|
|
||||||
this->channels = channels;
|
|
||||||
if(channels == 0) return;
|
|
||||||
|
|
||||||
sample = new double*[channels];
|
|
||||||
for(unsigned c = 0; c < channels; c++) {
|
|
||||||
sample[c] = new double[65536]();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
inline double& read(unsigned channel, signed offset = 0) {
|
|
||||||
return sample[channel][(uint16_t)(rdoffset + offset)];
|
|
||||||
}
|
|
||||||
|
|
||||||
inline double& write(unsigned channel, signed offset = 0) {
|
|
||||||
return sample[channel][(uint16_t)(wroffset + offset)];
|
|
||||||
}
|
|
||||||
|
|
||||||
inline void clear() {
|
|
||||||
for(unsigned c = 0; c < channels; c++) {
|
|
||||||
for(unsigned n = 0; n < 65536; n++) {
|
|
||||||
sample[c][n] = 0;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
rdoffset = 0;
|
|
||||||
wroffset = 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
Buffer() {
|
|
||||||
}
|
|
||||||
|
|
||||||
~Buffer() {
|
|
||||||
setChannels(0);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
#endif
|
|
|
@ -1,168 +0,0 @@
|
||||||
#ifdef NALL_DSP_INTERNAL_HPP
|
|
||||||
|
|
||||||
#include <math.h>
|
|
||||||
#include <vector>
|
|
||||||
#include <nall/stdint.hpp>
|
|
||||||
|
|
||||||
namespace nall {
|
|
||||||
|
|
||||||
//precision: can be float, double or long double
|
|
||||||
#define real float
|
|
||||||
|
|
||||||
struct DSP;
|
|
||||||
|
|
||||||
struct Resampler {
|
|
||||||
DSP &dsp;
|
|
||||||
real frequency;
|
|
||||||
|
|
||||||
virtual void setFrequency() = 0;
|
|
||||||
virtual void clear() = 0;
|
|
||||||
virtual void sample() = 0;
|
|
||||||
Resampler(DSP &dsp) : dsp(dsp) {}
|
|
||||||
};
|
|
||||||
|
|
||||||
struct DSP {
|
|
||||||
enum class ResampleEngine : unsigned {
|
|
||||||
Nearest,
|
|
||||||
Linear,
|
|
||||||
Cosine,
|
|
||||||
Cubic,
|
|
||||||
Hermite,
|
|
||||||
Average,
|
|
||||||
Sinc,
|
|
||||||
};
|
|
||||||
|
|
||||||
inline void setChannels(unsigned channels);
|
|
||||||
inline void setPrecision(unsigned precision);
|
|
||||||
inline void setFrequency(real frequency); //inputFrequency
|
|
||||||
inline void setVolume(real volume);
|
|
||||||
inline void setBalance(real balance);
|
|
||||||
|
|
||||||
inline void setResampler(ResampleEngine resamplingEngine);
|
|
||||||
inline void setResamplerFrequency(real frequency); //outputFrequency
|
|
||||||
|
|
||||||
inline void sample(signed channel[]);
|
|
||||||
inline bool pending();
|
|
||||||
inline void read(signed channel[]);
|
|
||||||
|
|
||||||
inline void clear();
|
|
||||||
inline DSP();
|
|
||||||
inline ~DSP();
|
|
||||||
|
|
||||||
protected:
|
|
||||||
friend class ResampleNearest;
|
|
||||||
friend class ResampleLinear;
|
|
||||||
friend class ResampleCosine;
|
|
||||||
friend class ResampleCubic;
|
|
||||||
friend class ResampleAverage;
|
|
||||||
friend class ResampleHermite;
|
|
||||||
friend class ResampleSinc;
|
|
||||||
|
|
||||||
struct Settings {
|
|
||||||
unsigned channels;
|
|
||||||
unsigned precision;
|
|
||||||
real frequency;
|
|
||||||
real volume;
|
|
||||||
real balance;
|
|
||||||
|
|
||||||
//internal
|
|
||||||
real intensity;
|
|
||||||
real intensityInverse;
|
|
||||||
} settings;
|
|
||||||
|
|
||||||
Resampler *resampler = nullptr;
|
|
||||||
inline void write(real channel[]);
|
|
||||||
|
|
||||||
#include "buffer.hpp"
|
|
||||||
Buffer buffer;
|
|
||||||
Buffer output;
|
|
||||||
|
|
||||||
inline void adjustVolume();
|
|
||||||
inline void adjustBalance();
|
|
||||||
inline signed clamp(const unsigned bits, const signed x);
|
|
||||||
};
|
|
||||||
|
|
||||||
#include "resample/nearest.hpp"
|
|
||||||
#include "resample/linear.hpp"
|
|
||||||
#include "resample/cosine.hpp"
|
|
||||||
#include "resample/cubic.hpp"
|
|
||||||
#include "resample/hermite.hpp"
|
|
||||||
#include "resample/average.hpp"
|
|
||||||
#include "resample/sinc.hpp"
|
|
||||||
#include "settings.hpp"
|
|
||||||
|
|
||||||
void DSP::sample(signed channel[]) {
|
|
||||||
for(unsigned c = 0; c < settings.channels; c++) {
|
|
||||||
buffer.write(c) = (real)channel[c] * settings.intensityInverse;
|
|
||||||
}
|
|
||||||
buffer.wroffset++;
|
|
||||||
resampler->sample();
|
|
||||||
}
|
|
||||||
|
|
||||||
bool DSP::pending() {
|
|
||||||
return output.rdoffset != output.wroffset;
|
|
||||||
}
|
|
||||||
|
|
||||||
void DSP::read(signed channel[]) {
|
|
||||||
adjustVolume();
|
|
||||||
adjustBalance();
|
|
||||||
|
|
||||||
for(unsigned c = 0; c < settings.channels; c++) {
|
|
||||||
channel[c] = clamp(settings.precision, output.read(c) * settings.intensity);
|
|
||||||
}
|
|
||||||
output.rdoffset++;
|
|
||||||
}
|
|
||||||
|
|
||||||
void DSP::write(real channel[]) {
|
|
||||||
for(unsigned c = 0; c < settings.channels; c++) {
|
|
||||||
output.write(c) = channel[c];
|
|
||||||
}
|
|
||||||
output.wroffset++;
|
|
||||||
}
|
|
||||||
|
|
||||||
void DSP::adjustVolume() {
|
|
||||||
for(unsigned c = 0; c < settings.channels; c++) {
|
|
||||||
output.read(c) *= settings.volume;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void DSP::adjustBalance() {
|
|
||||||
if(settings.channels != 2) return; //TODO: support > 2 channels
|
|
||||||
if(settings.balance < 0.0) output.read(1) *= 1.0 + settings.balance;
|
|
||||||
if(settings.balance > 0.0) output.read(0) *= 1.0 - settings.balance;
|
|
||||||
}
|
|
||||||
|
|
||||||
signed DSP::clamp(const unsigned bits, const signed x) {
|
|
||||||
const signed b = 1U << (bits - 1);
|
|
||||||
const signed m = (1U << (bits - 1)) - 1;
|
|
||||||
return (x > m) ? m : (x < -b) ? -b : x;
|
|
||||||
}
|
|
||||||
|
|
||||||
void DSP::clear() {
|
|
||||||
buffer.clear();
|
|
||||||
output.clear();
|
|
||||||
resampler->clear();
|
|
||||||
}
|
|
||||||
|
|
||||||
DSP::DSP() {
|
|
||||||
setResampler(ResampleEngine::Hermite);
|
|
||||||
setResamplerFrequency(44100.0);
|
|
||||||
|
|
||||||
setChannels(2);
|
|
||||||
setPrecision(16);
|
|
||||||
setFrequency(44100.0);
|
|
||||||
setVolume(1.0);
|
|
||||||
setBalance(0.0);
|
|
||||||
|
|
||||||
clear();
|
|
||||||
}
|
|
||||||
|
|
||||||
DSP::~DSP() {
|
|
||||||
if(resampler) delete resampler;
|
|
||||||
}
|
|
||||||
|
|
||||||
#undef real
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
#endif
|
|
|
@ -1,72 +0,0 @@
|
||||||
#ifdef NALL_DSP_INTERNAL_HPP
|
|
||||||
|
|
||||||
struct ResampleAverage : Resampler {
|
|
||||||
inline void setFrequency();
|
|
||||||
inline void clear();
|
|
||||||
inline void sample();
|
|
||||||
inline void sampleLinear();
|
|
||||||
ResampleAverage(DSP &dsp) : Resampler(dsp) {}
|
|
||||||
|
|
||||||
real fraction;
|
|
||||||
real step;
|
|
||||||
};
|
|
||||||
|
|
||||||
void ResampleAverage::setFrequency() {
|
|
||||||
fraction = 0.0;
|
|
||||||
step = dsp.settings.frequency / frequency;
|
|
||||||
}
|
|
||||||
|
|
||||||
void ResampleAverage::clear() {
|
|
||||||
fraction = 0.0;
|
|
||||||
}
|
|
||||||
|
|
||||||
void ResampleAverage::sample() {
|
|
||||||
//can only average if input frequency >= output frequency
|
|
||||||
if(step < 1.0) return sampleLinear();
|
|
||||||
|
|
||||||
fraction += 1.0;
|
|
||||||
|
|
||||||
real scalar = 1.0;
|
|
||||||
if(fraction > step) scalar = 1.0 - (fraction - step);
|
|
||||||
|
|
||||||
for(unsigned c = 0; c < dsp.settings.channels; c++) {
|
|
||||||
dsp.output.write(c) += dsp.buffer.read(c) * scalar;
|
|
||||||
}
|
|
||||||
|
|
||||||
if(fraction >= step) {
|
|
||||||
for(unsigned c = 0; c < dsp.settings.channels; c++) {
|
|
||||||
dsp.output.write(c) /= step;
|
|
||||||
}
|
|
||||||
dsp.output.wroffset++;
|
|
||||||
|
|
||||||
fraction -= step;
|
|
||||||
for(unsigned c = 0; c < dsp.settings.channels; c++) {
|
|
||||||
dsp.output.write(c) = dsp.buffer.read(c) * fraction;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
dsp.buffer.rdoffset++;
|
|
||||||
}
|
|
||||||
|
|
||||||
void ResampleAverage::sampleLinear() {
|
|
||||||
while(fraction <= 1.0) {
|
|
||||||
real channel[dsp.settings.channels];
|
|
||||||
|
|
||||||
for(unsigned n = 0; n < dsp.settings.channels; n++) {
|
|
||||||
real a = dsp.buffer.read(n, -1);
|
|
||||||
real b = dsp.buffer.read(n, -0);
|
|
||||||
|
|
||||||
real mu = fraction;
|
|
||||||
|
|
||||||
channel[n] = a * (1.0 - mu) + b * mu;
|
|
||||||
}
|
|
||||||
|
|
||||||
dsp.write(channel);
|
|
||||||
fraction += step;
|
|
||||||
}
|
|
||||||
|
|
||||||
dsp.buffer.rdoffset++;
|
|
||||||
fraction -= 1.0;
|
|
||||||
}
|
|
||||||
|
|
||||||
#endif
|
|
|
@ -1,44 +0,0 @@
|
||||||
#ifdef NALL_DSP_INTERNAL_HPP
|
|
||||||
|
|
||||||
struct ResampleCosine : Resampler {
|
|
||||||
inline void setFrequency();
|
|
||||||
inline void clear();
|
|
||||||
inline void sample();
|
|
||||||
ResampleCosine(DSP &dsp) : Resampler(dsp) {}
|
|
||||||
|
|
||||||
real fraction;
|
|
||||||
real step;
|
|
||||||
};
|
|
||||||
|
|
||||||
void ResampleCosine::setFrequency() {
|
|
||||||
fraction = 0.0;
|
|
||||||
step = dsp.settings.frequency / frequency;
|
|
||||||
}
|
|
||||||
|
|
||||||
void ResampleCosine::clear() {
|
|
||||||
fraction = 0.0;
|
|
||||||
}
|
|
||||||
|
|
||||||
void ResampleCosine::sample() {
|
|
||||||
while(fraction <= 1.0) {
|
|
||||||
real channel[dsp.settings.channels];
|
|
||||||
|
|
||||||
for(unsigned n = 0; n < dsp.settings.channels; n++) {
|
|
||||||
real a = dsp.buffer.read(n, -1);
|
|
||||||
real b = dsp.buffer.read(n, -0);
|
|
||||||
|
|
||||||
real mu = fraction;
|
|
||||||
mu = (1.0 - cos(mu * 3.14159265)) / 2.0;
|
|
||||||
|
|
||||||
channel[n] = a * (1.0 - mu) + b * mu;
|
|
||||||
}
|
|
||||||
|
|
||||||
dsp.write(channel);
|
|
||||||
fraction += step;
|
|
||||||
}
|
|
||||||
|
|
||||||
dsp.buffer.rdoffset++;
|
|
||||||
fraction -= 1.0;
|
|
||||||
}
|
|
||||||
|
|
||||||
#endif
|
|
|
@ -1,50 +0,0 @@
|
||||||
#ifdef NALL_DSP_INTERNAL_HPP
|
|
||||||
|
|
||||||
struct ResampleCubic : Resampler {
|
|
||||||
inline void setFrequency();
|
|
||||||
inline void clear();
|
|
||||||
inline void sample();
|
|
||||||
ResampleCubic(DSP &dsp) : Resampler(dsp) {}
|
|
||||||
|
|
||||||
real fraction;
|
|
||||||
real step;
|
|
||||||
};
|
|
||||||
|
|
||||||
void ResampleCubic::setFrequency() {
|
|
||||||
fraction = 0.0;
|
|
||||||
step = dsp.settings.frequency / frequency;
|
|
||||||
}
|
|
||||||
|
|
||||||
void ResampleCubic::clear() {
|
|
||||||
fraction = 0.0;
|
|
||||||
}
|
|
||||||
|
|
||||||
void ResampleCubic::sample() {
|
|
||||||
while(fraction <= 1.0) {
|
|
||||||
real channel[dsp.settings.channels];
|
|
||||||
|
|
||||||
for(unsigned n = 0; n < dsp.settings.channels; n++) {
|
|
||||||
real a = dsp.buffer.read(n, -3);
|
|
||||||
real b = dsp.buffer.read(n, -2);
|
|
||||||
real c = dsp.buffer.read(n, -1);
|
|
||||||
real d = dsp.buffer.read(n, -0);
|
|
||||||
|
|
||||||
real mu = fraction;
|
|
||||||
|
|
||||||
real A = d - c - a + b;
|
|
||||||
real B = a - b - A;
|
|
||||||
real C = c - a;
|
|
||||||
real D = b;
|
|
||||||
|
|
||||||
channel[n] = A * (mu * 3) + B * (mu * 2) + C * mu + D;
|
|
||||||
}
|
|
||||||
|
|
||||||
dsp.write(channel);
|
|
||||||
fraction += step;
|
|
||||||
}
|
|
||||||
|
|
||||||
dsp.buffer.rdoffset++;
|
|
||||||
fraction -= 1.0;
|
|
||||||
}
|
|
||||||
|
|
||||||
#endif
|
|
|
@ -1,62 +0,0 @@
|
||||||
#ifdef NALL_DSP_INTERNAL_HPP
|
|
||||||
|
|
||||||
struct ResampleHermite : Resampler {
|
|
||||||
inline void setFrequency();
|
|
||||||
inline void clear();
|
|
||||||
inline void sample();
|
|
||||||
ResampleHermite(DSP &dsp) : Resampler(dsp) {}
|
|
||||||
|
|
||||||
real fraction;
|
|
||||||
real step;
|
|
||||||
};
|
|
||||||
|
|
||||||
void ResampleHermite::setFrequency() {
|
|
||||||
fraction = 0.0;
|
|
||||||
step = dsp.settings.frequency / frequency;
|
|
||||||
}
|
|
||||||
|
|
||||||
void ResampleHermite::clear() {
|
|
||||||
fraction = 0.0;
|
|
||||||
}
|
|
||||||
|
|
||||||
void ResampleHermite::sample() {
|
|
||||||
while(fraction <= 1.0) {
|
|
||||||
real channel[dsp.settings.channels];
|
|
||||||
|
|
||||||
for(unsigned n = 0; n < dsp.settings.channels; n++) {
|
|
||||||
real a = dsp.buffer.read(n, -3);
|
|
||||||
real b = dsp.buffer.read(n, -2);
|
|
||||||
real c = dsp.buffer.read(n, -1);
|
|
||||||
real d = dsp.buffer.read(n, -0);
|
|
||||||
|
|
||||||
const real tension = 0.0; //-1 = low, 0 = normal, +1 = high
|
|
||||||
const real bias = 0.0; //-1 = left, 0 = even, +1 = right
|
|
||||||
|
|
||||||
real mu1, mu2, mu3, m0, m1, a0, a1, a2, a3;
|
|
||||||
|
|
||||||
mu1 = fraction;
|
|
||||||
mu2 = mu1 * mu1;
|
|
||||||
mu3 = mu2 * mu1;
|
|
||||||
|
|
||||||
m0 = (b - a) * (1.0 + bias) * (1.0 - tension) / 2.0;
|
|
||||||
m0 += (c - b) * (1.0 - bias) * (1.0 - tension) / 2.0;
|
|
||||||
m1 = (c - b) * (1.0 + bias) * (1.0 - tension) / 2.0;
|
|
||||||
m1 += (d - c) * (1.0 - bias) * (1.0 - tension) / 2.0;
|
|
||||||
|
|
||||||
a0 = +2 * mu3 - 3 * mu2 + 1;
|
|
||||||
a1 = mu3 - 2 * mu2 + mu1;
|
|
||||||
a2 = mu3 - mu2;
|
|
||||||
a3 = -2 * mu3 + 3 * mu2;
|
|
||||||
|
|
||||||
channel[n] = (a0 * b) + (a1 * m0) + (a2 * m1) + (a3 * c);
|
|
||||||
}
|
|
||||||
|
|
||||||
dsp.write(channel);
|
|
||||||
fraction += step;
|
|
||||||
}
|
|
||||||
|
|
||||||
dsp.buffer.rdoffset++;
|
|
||||||
fraction -= 1.0;
|
|
||||||
}
|
|
||||||
|
|
||||||
#endif
|
|
|
@ -1,600 +0,0 @@
|
||||||
// If these types are changed to anything other than "float", you should comment out the SSE detection directives below
|
|
||||||
// so that the SSE code is not used.
|
|
||||||
|
|
||||||
typedef float resample_coeff_t; // note: sizeof(resample_coeff_t) must be == to a power of 2, and not larger than 16
|
|
||||||
typedef float resample_samp_t;
|
|
||||||
|
|
||||||
|
|
||||||
// ...but don't comment this single RESAMPLE_SSEREGPARM define out when disabling SSE.
|
|
||||||
#define RESAMPLE_SSEREGPARM
|
|
||||||
|
|
||||||
#if defined(__SSE__)
|
|
||||||
#define SINCRESAMPLE_USE_SSE 1
|
|
||||||
#ifndef __x86_64__
|
|
||||||
#undef RESAMPLE_SSEREGPARM
|
|
||||||
#define RESAMPLE_SSEREGPARM __attribute__((sseregparm))
|
|
||||||
#endif
|
|
||||||
#else
|
|
||||||
// TODO: altivec here
|
|
||||||
#endif
|
|
||||||
|
|
||||||
namespace ResampleUtility
|
|
||||||
{
|
|
||||||
inline void kaiser_window(double* io, int count, double beta);
|
|
||||||
inline void gen_sinc(double* out, int size, double cutoff, double kaiser);
|
|
||||||
inline void gen_sinc_os(double* out, int size, double cutoff, double kaiser);
|
|
||||||
inline void normalize(double* io, int size, double gain = 1.0);
|
|
||||||
|
|
||||||
inline void* make_aligned(void* ptr, unsigned boundary); // boundary must be a power of 2
|
|
||||||
}
|
|
||||||
|
|
||||||
class SincResampleHR
|
|
||||||
{
|
|
||||||
private:
|
|
||||||
|
|
||||||
inline void Init(unsigned ratio_arg, double desired_bandwidth, double beta, double d);
|
|
||||||
|
|
||||||
inline void write(resample_samp_t sample) RESAMPLE_SSEREGPARM;
|
|
||||||
inline resample_samp_t read(void) RESAMPLE_SSEREGPARM;
|
|
||||||
inline bool output_avail(void);
|
|
||||||
|
|
||||||
private:
|
|
||||||
|
|
||||||
inline resample_samp_t mac(const resample_samp_t *wave, const resample_coeff_t *coeff, unsigned count);
|
|
||||||
|
|
||||||
unsigned ratio;
|
|
||||||
unsigned num_convolutions;
|
|
||||||
|
|
||||||
resample_coeff_t *coeffs;
|
|
||||||
std::vector<unsigned char> coeffs_mem;
|
|
||||||
|
|
||||||
// second half of ringbuffer should be copy of first half.
|
|
||||||
resample_samp_t *rb;
|
|
||||||
std::vector<unsigned char> rb_mem;
|
|
||||||
|
|
||||||
signed rb_readpos;
|
|
||||||
signed rb_writepos;
|
|
||||||
signed rb_in;
|
|
||||||
signed rb_eff_size;
|
|
||||||
|
|
||||||
friend class SincResample;
|
|
||||||
};
|
|
||||||
|
|
||||||
class SincResample
|
|
||||||
{
|
|
||||||
public:
|
|
||||||
|
|
||||||
enum
|
|
||||||
{
|
|
||||||
QUALITY_LOW = 0,
|
|
||||||
QUALITY_MEDIUM = 2,
|
|
||||||
QUALITY_HIGH = 4
|
|
||||||
};
|
|
||||||
|
|
||||||
inline SincResample(double input_rate, double output_rate, double desired_bandwidth, unsigned quality = QUALITY_HIGH);
|
|
||||||
|
|
||||||
inline void write(resample_samp_t sample) RESAMPLE_SSEREGPARM;
|
|
||||||
inline resample_samp_t read(void) RESAMPLE_SSEREGPARM;
|
|
||||||
inline bool output_avail(void);
|
|
||||||
|
|
||||||
private:
|
|
||||||
|
|
||||||
inline void Init(double input_rate, double output_rate, double desired_bandwidth, double beta, double d, unsigned pn_nume, unsigned phases_min);
|
|
||||||
|
|
||||||
inline resample_samp_t mac(const resample_samp_t *wave, const resample_coeff_t *coeffs_a, const resample_coeff_t *coeffs_b, const double ffract, unsigned count) RESAMPLE_SSEREGPARM;
|
|
||||||
|
|
||||||
unsigned num_convolutions;
|
|
||||||
unsigned num_phases;
|
|
||||||
|
|
||||||
unsigned step_int;
|
|
||||||
double step_fract;
|
|
||||||
|
|
||||||
double input_pos_fract;
|
|
||||||
|
|
||||||
|
|
||||||
std::vector<resample_coeff_t *> coeffs; // Pointers into coeff_mem.
|
|
||||||
std::vector<unsigned char> coeff_mem;
|
|
||||||
|
|
||||||
|
|
||||||
std::vector<resample_samp_t> rb; // second half should be copy of first half.
|
|
||||||
signed rb_readpos;
|
|
||||||
signed rb_writepos;
|
|
||||||
signed rb_in;
|
|
||||||
|
|
||||||
bool hr_used;
|
|
||||||
SincResampleHR hr;
|
|
||||||
};
|
|
||||||
|
|
||||||
|
|
||||||
//
|
|
||||||
// Code:
|
|
||||||
//
|
|
||||||
//#include "resample.hpp"
|
|
||||||
|
|
||||||
#if 0
|
|
||||||
namespace bit
|
|
||||||
{
|
|
||||||
inline unsigned round(unsigned x) {
|
|
||||||
if((x & (x - 1)) == 0) return x;
|
|
||||||
while(x & (x - 1)) x &= x - 1;
|
|
||||||
return x << 1;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
|
|
||||||
void SincResampleHR::Init(unsigned ratio_arg, double desired_bandwidth, double beta, double d)
|
|
||||||
{
|
|
||||||
const unsigned align_boundary = 16;
|
|
||||||
std::vector<double> coeffs_tmp;
|
|
||||||
double cutoff; // 1.0 = f/2
|
|
||||||
|
|
||||||
ratio = ratio_arg;
|
|
||||||
|
|
||||||
//num_convolutions = ((unsigned)ceil(d / ((1.0 - desired_bandwidth) / ratio)) + 1) &~ 1; // round up to be even
|
|
||||||
num_convolutions = ((unsigned)ceil(d / ((1.0 - desired_bandwidth) / ratio)) | 1);
|
|
||||||
|
|
||||||
cutoff = (1.0 / ratio) - (d / num_convolutions);
|
|
||||||
|
|
||||||
//printf("%d %d %.20f\n", ratio, num_convolutions, cutoff);
|
|
||||||
assert(num_convolutions > ratio);
|
|
||||||
|
|
||||||
|
|
||||||
// Generate windowed sinc of POWER
|
|
||||||
coeffs_tmp.resize(num_convolutions);
|
|
||||||
//ResampleUtility::gen_sinc(&coeffs_tmp[0], num_convolutions, cutoff, beta);
|
|
||||||
ResampleUtility::gen_sinc_os(&coeffs_tmp[0], num_convolutions, cutoff, beta);
|
|
||||||
ResampleUtility::normalize(&coeffs_tmp[0], num_convolutions);
|
|
||||||
|
|
||||||
// Copy from coeffs_tmp to coeffs~
|
|
||||||
// We multiply many coefficients at a time in the mac loop, so make sure the last few that don't really
|
|
||||||
// exist are allocated, zero'd mem.
|
|
||||||
|
|
||||||
coeffs_mem.resize(((num_convolutions + 7) &~ 7) * sizeof(resample_coeff_t) + (align_boundary - 1));
|
|
||||||
coeffs = (resample_coeff_t *)ResampleUtility::make_aligned(&coeffs_mem[0], align_boundary);
|
|
||||||
|
|
||||||
|
|
||||||
for(unsigned i = 0; i < num_convolutions; i++)
|
|
||||||
coeffs[i] = coeffs_tmp[i];
|
|
||||||
|
|
||||||
rb_eff_size = nall::bit::round(num_convolutions * 2) >> 1;
|
|
||||||
rb_readpos = 0;
|
|
||||||
rb_writepos = 0;
|
|
||||||
rb_in = 0;
|
|
||||||
|
|
||||||
rb_mem.resize(rb_eff_size * 2 * sizeof(resample_samp_t) + (align_boundary - 1));
|
|
||||||
rb = (resample_samp_t *)ResampleUtility::make_aligned(&rb_mem[0], align_boundary);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
inline bool SincResampleHR::output_avail(void)
|
|
||||||
{
|
|
||||||
return(rb_in >= (signed)num_convolutions);
|
|
||||||
}
|
|
||||||
|
|
||||||
inline void SincResampleHR::write(resample_samp_t sample)
|
|
||||||
{
|
|
||||||
assert(!output_avail());
|
|
||||||
|
|
||||||
rb[rb_writepos] = sample;
|
|
||||||
rb[rb_writepos + rb_eff_size] = sample;
|
|
||||||
rb_writepos = (rb_writepos + 1) & (rb_eff_size - 1);
|
|
||||||
rb_in++;
|
|
||||||
}
|
|
||||||
|
|
||||||
resample_samp_t SincResampleHR::mac(const resample_samp_t *wave, const resample_coeff_t *coeff, unsigned count)
|
|
||||||
{
|
|
||||||
#if SINCRESAMPLE_USE_SSE
|
|
||||||
__m128 accum_veca[2] = { _mm_set1_ps(0), _mm_set1_ps(0) };
|
|
||||||
|
|
||||||
resample_samp_t accum;
|
|
||||||
|
|
||||||
for(unsigned c = 0; c < count; c += 8)
|
|
||||||
{
|
|
||||||
for(unsigned i = 0; i < 2; i++)
|
|
||||||
{
|
|
||||||
__m128 co[2];
|
|
||||||
__m128 w[2];
|
|
||||||
|
|
||||||
co[i] = _mm_load_ps(&coeff[c + i * 4]);
|
|
||||||
w[i] = _mm_load_ps(&wave[c + i * 4]);
|
|
||||||
|
|
||||||
w[i] = _mm_mul_ps(w[i], co[i]);
|
|
||||||
|
|
||||||
accum_veca[i] = _mm_add_ps(w[i], accum_veca[i]);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
__m128 accum_vec = _mm_add_ps(accum_veca[0], accum_veca[1]); //_mm_add_ps(_mm_add_ps(accum_veca[0], accum_veca[1]), _mm_add_ps(accum_veca[2], accum_veca[3]));
|
|
||||||
|
|
||||||
accum_vec = _mm_add_ps(accum_vec, _mm_shuffle_ps(accum_vec, accum_vec, (3 << 0) | (2 << 2) | (1 << 4) | (0 << 6)));
|
|
||||||
accum_vec = _mm_add_ps(accum_vec, _mm_shuffle_ps(accum_vec, accum_vec, (1 << 0) | (0 << 2) | (1 << 4) | (0 << 6)));
|
|
||||||
|
|
||||||
_mm_store_ss(&accum, accum_vec);
|
|
||||||
|
|
||||||
return accum;
|
|
||||||
#else
|
|
||||||
resample_samp_t accum[4] = { 0, 0, 0, 0 };
|
|
||||||
|
|
||||||
for(unsigned c = 0; c < count; c+= 4)
|
|
||||||
{
|
|
||||||
accum[0] += wave[c + 0] * coeff[c + 0];
|
|
||||||
accum[1] += wave[c + 1] * coeff[c + 1];
|
|
||||||
accum[2] += wave[c + 2] * coeff[c + 2];
|
|
||||||
accum[3] += wave[c + 3] * coeff[c + 3];
|
|
||||||
}
|
|
||||||
|
|
||||||
return (accum[0] + accum[1]) + (accum[2] + accum[3]); // don't mess with parentheses(assuming compiler doesn't already, which it may...
|
|
||||||
|
|
||||||
#endif
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
resample_samp_t SincResampleHR::read(void)
|
|
||||||
{
|
|
||||||
assert(output_avail());
|
|
||||||
resample_samp_t ret;
|
|
||||||
|
|
||||||
ret = mac(&rb[rb_readpos], &coeffs[0], num_convolutions);
|
|
||||||
|
|
||||||
rb_readpos = (rb_readpos + ratio) & (rb_eff_size - 1);
|
|
||||||
rb_in -= ratio;
|
|
||||||
|
|
||||||
return ret;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
SincResample::SincResample(double input_rate, double output_rate, double desired_bandwidth, unsigned quality)
|
|
||||||
{
|
|
||||||
const struct
|
|
||||||
{
|
|
||||||
double beta;
|
|
||||||
double d;
|
|
||||||
unsigned pn_nume;
|
|
||||||
unsigned phases_min;
|
|
||||||
} qtab[5] =
|
|
||||||
{
|
|
||||||
{ 5.658, 3.62, 4096, 4 },
|
|
||||||
{ 6.764, 4.32, 8192, 4 },
|
|
||||||
{ 7.865, 5.0, 16384, 8 },
|
|
||||||
{ 8.960, 5.7, 32768, 16 },
|
|
||||||
{ 10.056, 6.4, 65536, 32 }
|
|
||||||
};
|
|
||||||
|
|
||||||
// Sanity checks
|
|
||||||
assert(ceil(input_rate) > 0);
|
|
||||||
assert(ceil(output_rate) > 0);
|
|
||||||
assert(ceil(input_rate / output_rate) <= 1024);
|
|
||||||
assert(ceil(output_rate / input_rate) <= 1024);
|
|
||||||
|
|
||||||
// The simplistic number-of-phases calculation code doesn't work well enough for when desired_bandwidth is close to 1.0 and when
|
|
||||||
// upsampling.
|
|
||||||
assert(desired_bandwidth >= 0.25 && desired_bandwidth < 0.96);
|
|
||||||
assert(quality >= 0 && quality <= 4);
|
|
||||||
|
|
||||||
hr_used = false;
|
|
||||||
|
|
||||||
#if 1
|
|
||||||
// Round down to the nearest multiple of 4(so wave buffer remains aligned)
|
|
||||||
// It also adjusts the effective intermediate sampling rate up slightly, so that the upper frequencies below f/2
|
|
||||||
// aren't overly attenuated so much. In the future, we might want to do an FFT or something to choose the intermediate rate more accurately
|
|
||||||
// to virtually eliminate over-attenuation.
|
|
||||||
unsigned ioratio_rd = (unsigned)floor(input_rate / (output_rate * (1.0 + (1.0 - desired_bandwidth) / 2) )) & ~3;
|
|
||||||
|
|
||||||
if(ioratio_rd >= 8)
|
|
||||||
{
|
|
||||||
hr.Init(ioratio_rd, desired_bandwidth, qtab[quality].beta, qtab[quality].d); //10.056, 6.4);
|
|
||||||
hr_used = true;
|
|
||||||
|
|
||||||
input_rate /= ioratio_rd;
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
|
|
||||||
Init(input_rate, output_rate, desired_bandwidth, qtab[quality].beta, qtab[quality].d, qtab[quality].pn_nume, qtab[quality].phases_min);
|
|
||||||
}
|
|
||||||
|
|
||||||
void SincResample::Init(double input_rate, double output_rate, double desired_bandwidth, double beta, double d, unsigned pn_nume, unsigned phases_min)
|
|
||||||
{
|
|
||||||
const unsigned max_mult_atatime = 8; // multiply "granularity". must be power of 2.
|
|
||||||
const unsigned max_mult_minus1 = (max_mult_atatime - 1);
|
|
||||||
const unsigned conv_alignment_bytes = 16; // must be power of 2
|
|
||||||
const double input_to_output_ratio = input_rate / output_rate;
|
|
||||||
const double output_to_input_ratio = output_rate / input_rate;
|
|
||||||
double cutoff; // 1.0 = input_rate / 2
|
|
||||||
std::vector<double> coeff_init_buffer;
|
|
||||||
|
|
||||||
// Round up num_convolutions to be even.
|
|
||||||
if(output_rate > input_rate)
|
|
||||||
num_convolutions = ((unsigned)ceil(d / (1.0 - desired_bandwidth)) + 1) & ~1;
|
|
||||||
else
|
|
||||||
num_convolutions = ((unsigned)ceil(d / (output_to_input_ratio * (1.0 - desired_bandwidth))) + 1) & ~1;
|
|
||||||
|
|
||||||
if(output_rate > input_rate) // Upsampling
|
|
||||||
cutoff = desired_bandwidth;
|
|
||||||
else // Downsampling
|
|
||||||
cutoff = output_to_input_ratio * desired_bandwidth;
|
|
||||||
|
|
||||||
// Round up to be even.
|
|
||||||
num_phases = (std::max<unsigned>(pn_nume / num_convolutions, phases_min) + 1) &~1;
|
|
||||||
|
|
||||||
// Adjust cutoff to account for the multiple phases.
|
|
||||||
cutoff = cutoff / num_phases;
|
|
||||||
|
|
||||||
assert((num_convolutions & 1) == 0);
|
|
||||||
assert((num_phases & 1) == 0);
|
|
||||||
|
|
||||||
// fprintf(stderr, "num_convolutions=%u, num_phases=%u, total expected coeff byte size=%lu\n", num_convolutions, num_phases,
|
|
||||||
// (long)((num_phases + 2) * ((num_convolutions + max_mult_minus1) & ~max_mult_minus1) * sizeof(float) + conv_alignment_bytes));
|
|
||||||
|
|
||||||
coeff_init_buffer.resize(num_phases * num_convolutions);
|
|
||||||
|
|
||||||
coeffs.resize(num_phases + 1 + 1);
|
|
||||||
|
|
||||||
coeff_mem.resize((num_phases + 1 + 1) * ((num_convolutions + max_mult_minus1) &~ max_mult_minus1) * sizeof(resample_coeff_t) + conv_alignment_bytes);
|
|
||||||
|
|
||||||
// Assign aligned pointers into coeff_mem
|
|
||||||
{
|
|
||||||
resample_coeff_t *base_ptr = (resample_coeff_t *)ResampleUtility::make_aligned(&coeff_mem[0], conv_alignment_bytes);
|
|
||||||
|
|
||||||
for(unsigned phase = 0; phase < (num_phases + 1 + 1); phase++)
|
|
||||||
{
|
|
||||||
coeffs[phase] = base_ptr + (((num_convolutions + max_mult_minus1) & ~max_mult_minus1) * phase);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
ResampleUtility::gen_sinc(&coeff_init_buffer[0], num_phases * num_convolutions, cutoff, beta);
|
|
||||||
ResampleUtility::normalize(&coeff_init_buffer[0], num_phases * num_convolutions, num_phases);
|
|
||||||
|
|
||||||
// Reorder coefficients to allow for more efficient convolution.
|
|
||||||
for(int phase = -1; phase < ((int)num_phases + 1); phase++)
|
|
||||||
{
|
|
||||||
for(int conv = 0; conv < (int)num_convolutions; conv++)
|
|
||||||
{
|
|
||||||
double coeff;
|
|
||||||
|
|
||||||
if(phase == -1 && conv == 0)
|
|
||||||
coeff = 0;
|
|
||||||
else if(phase == (int)num_phases && conv == ((int)num_convolutions - 1))
|
|
||||||
coeff = 0;
|
|
||||||
else
|
|
||||||
coeff = coeff_init_buffer[conv * num_phases + phase];
|
|
||||||
|
|
||||||
coeffs[phase + 1][conv] = coeff;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Free a bit of mem
|
|
||||||
coeff_init_buffer.resize(0);
|
|
||||||
|
|
||||||
step_int = floor(input_to_output_ratio);
|
|
||||||
step_fract = input_to_output_ratio - step_int;
|
|
||||||
|
|
||||||
input_pos_fract = 0;
|
|
||||||
|
|
||||||
// Do NOT use rb.size() later in the code, since it'll include the padding.
|
|
||||||
// We should only need one "max_mult_minus1" here, not two, since it won't matter if it over-reads(due to doing "max_mult_atatime" multiplications at a time
|
|
||||||
// rather than just 1, in which case this over-read wouldn't happen), from the first half into the duplicated half,
|
|
||||||
// since those corresponding coefficients will be zero anyway; this is just to handle the case of reading off the end of the duplicated half to
|
|
||||||
// prevent illegal memory accesses.
|
|
||||||
rb.resize(num_convolutions * 2 + max_mult_minus1);
|
|
||||||
|
|
||||||
rb_readpos = 0;
|
|
||||||
rb_writepos = 0;
|
|
||||||
rb_in = 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
resample_samp_t SincResample::mac(const resample_samp_t *wave, const resample_coeff_t *coeffs_a, const resample_coeff_t *coeffs_b, const double ffract, unsigned count)
|
|
||||||
{
|
|
||||||
resample_samp_t accum = 0;
|
|
||||||
#if SINCRESAMPLE_USE_SSE
|
|
||||||
__m128 accum_vec_a[2] = { _mm_set1_ps(0), _mm_set1_ps(0) };
|
|
||||||
__m128 accum_vec_b[2] = { _mm_set1_ps(0), _mm_set1_ps(0) };
|
|
||||||
|
|
||||||
for(unsigned c = 0; c < count; c += 8) //8) //4)
|
|
||||||
{
|
|
||||||
__m128 coeff_a[2];
|
|
||||||
__m128 coeff_b[2];
|
|
||||||
__m128 w[2];
|
|
||||||
__m128 result_a[2], result_b[2];
|
|
||||||
|
|
||||||
for(unsigned i = 0; i < 2; i++)
|
|
||||||
{
|
|
||||||
coeff_a[i] = _mm_load_ps(&coeffs_a[c + (i * 4)]);
|
|
||||||
coeff_b[i] = _mm_load_ps(&coeffs_b[c + (i * 4)]);
|
|
||||||
w[i] = _mm_loadu_ps(&wave[c + (i * 4)]);
|
|
||||||
|
|
||||||
result_a[i] = _mm_mul_ps(coeff_a[i], w[i]);
|
|
||||||
result_b[i] = _mm_mul_ps(coeff_b[i], w[i]);
|
|
||||||
|
|
||||||
accum_vec_a[i] = _mm_add_ps(result_a[i], accum_vec_a[i]);
|
|
||||||
accum_vec_b[i] = _mm_add_ps(result_b[i], accum_vec_b[i]);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
__m128 accum_vec, av_a, av_b;
|
|
||||||
__m128 mult_a_vec = _mm_set1_ps(1.0 - ffract);
|
|
||||||
__m128 mult_b_vec = _mm_set1_ps(ffract);
|
|
||||||
|
|
||||||
av_a = _mm_mul_ps(mult_a_vec, /*accum_vec_a[0]);*/ _mm_add_ps(accum_vec_a[0], accum_vec_a[1]));
|
|
||||||
av_b = _mm_mul_ps(mult_b_vec, /*accum_vec_b[0]);*/ _mm_add_ps(accum_vec_b[0], accum_vec_b[1]));
|
|
||||||
|
|
||||||
accum_vec = _mm_add_ps(av_a, av_b);
|
|
||||||
|
|
||||||
accum_vec = _mm_add_ps(accum_vec, _mm_shuffle_ps(accum_vec, accum_vec, (3 << 0) | (2 << 2) | (1 << 4) | (0 << 6)));
|
|
||||||
accum_vec = _mm_add_ps(accum_vec, _mm_shuffle_ps(accum_vec, accum_vec, (1 << 0) | (0 << 2) | (1 << 4) | (0 << 6)));
|
|
||||||
|
|
||||||
_mm_store_ss(&accum, accum_vec);
|
|
||||||
#else
|
|
||||||
resample_coeff_t mult_a = 1.0 - ffract;
|
|
||||||
resample_coeff_t mult_b = ffract;
|
|
||||||
|
|
||||||
for(unsigned c = 0; c < count; c += 4)
|
|
||||||
{
|
|
||||||
accum += wave[c + 0] * (coeffs_a[c + 0] * mult_a + coeffs_b[c + 0] * mult_b);
|
|
||||||
accum += wave[c + 1] * (coeffs_a[c + 1] * mult_a + coeffs_b[c + 1] * mult_b);
|
|
||||||
accum += wave[c + 2] * (coeffs_a[c + 2] * mult_a + coeffs_b[c + 2] * mult_b);
|
|
||||||
accum += wave[c + 3] * (coeffs_a[c + 3] * mult_a + coeffs_b[c + 3] * mult_b);
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
|
|
||||||
return accum;
|
|
||||||
}
|
|
||||||
|
|
||||||
inline bool SincResample::output_avail(void)
|
|
||||||
{
|
|
||||||
return(rb_in >= (int)num_convolutions);
|
|
||||||
}
|
|
||||||
|
|
||||||
resample_samp_t SincResample::read(void)
|
|
||||||
{
|
|
||||||
assert(output_avail());
|
|
||||||
double phase = input_pos_fract * num_phases - 0.5;
|
|
||||||
signed phase_int = (signed)floor(phase);
|
|
||||||
double phase_fract = phase - phase_int;
|
|
||||||
unsigned phase_a = num_phases - 1 - phase_int;
|
|
||||||
unsigned phase_b = phase_a - 1;
|
|
||||||
resample_samp_t ret;
|
|
||||||
|
|
||||||
ret = mac(&rb[rb_readpos], &coeffs[phase_a + 1][0], &coeffs[phase_b + 1][0], phase_fract, num_convolutions);
|
|
||||||
|
|
||||||
unsigned int_increment = step_int;
|
|
||||||
|
|
||||||
input_pos_fract += step_fract;
|
|
||||||
int_increment += floor(input_pos_fract);
|
|
||||||
input_pos_fract -= floor(input_pos_fract);
|
|
||||||
|
|
||||||
rb_readpos = (rb_readpos + int_increment) % num_convolutions;
|
|
||||||
rb_in -= int_increment;
|
|
||||||
|
|
||||||
return ret;
|
|
||||||
}
|
|
||||||
|
|
||||||
inline void SincResample::write(resample_samp_t sample)
|
|
||||||
{
|
|
||||||
assert(!output_avail());
|
|
||||||
|
|
||||||
if(hr_used)
|
|
||||||
{
|
|
||||||
hr.write(sample);
|
|
||||||
|
|
||||||
if(hr.output_avail())
|
|
||||||
{
|
|
||||||
sample = hr.read();
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
rb[rb_writepos + 0 * num_convolutions] = sample;
|
|
||||||
rb[rb_writepos + 1 * num_convolutions] = sample;
|
|
||||||
rb_writepos = (rb_writepos + 1) % num_convolutions;
|
|
||||||
rb_in++;
|
|
||||||
}
|
|
||||||
|
|
||||||
void ResampleUtility::kaiser_window( double* io, int count, double beta)
|
|
||||||
{
|
|
||||||
int const accuracy = 24; //16; //12;
|
|
||||||
|
|
||||||
double* end = io + count;
|
|
||||||
|
|
||||||
double beta2 = beta * beta * (double) -0.25;
|
|
||||||
double to_fract = beta2 / ((double) count * count);
|
|
||||||
double i = 0;
|
|
||||||
double rescale = 0; // Doesn't need an initializer, to shut up gcc
|
|
||||||
|
|
||||||
for ( ; io < end; ++io, i += 1 )
|
|
||||||
{
|
|
||||||
double x = i * i * to_fract - beta2;
|
|
||||||
double u = x;
|
|
||||||
double k = x + 1;
|
|
||||||
|
|
||||||
double n = 2;
|
|
||||||
do
|
|
||||||
{
|
|
||||||
u *= x / (n * n);
|
|
||||||
n += 1;
|
|
||||||
k += u;
|
|
||||||
}
|
|
||||||
while ( k <= u * (1 << accuracy) );
|
|
||||||
|
|
||||||
if ( !i )
|
|
||||||
rescale = 1 / k; // otherwise values get large
|
|
||||||
|
|
||||||
*io *= k * rescale;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void ResampleUtility::gen_sinc(double* out, int size, double cutoff, double kaiser)
|
|
||||||
{
|
|
||||||
assert( size % 2 == 0 ); // size must be even
|
|
||||||
|
|
||||||
int const half_size = size / 2;
|
|
||||||
double* const mid = &out [half_size];
|
|
||||||
|
|
||||||
// Generate right half of sinc
|
|
||||||
for ( int i = 0; i < half_size; i++ )
|
|
||||||
{
|
|
||||||
double angle = (i * 2 + 1) * (M_PI / 2);
|
|
||||||
mid [i] = sin( angle * cutoff ) / angle;
|
|
||||||
}
|
|
||||||
|
|
||||||
kaiser_window( mid, half_size, kaiser );
|
|
||||||
|
|
||||||
// Mirror for left half
|
|
||||||
for ( int i = 0; i < half_size; i++ )
|
|
||||||
out [i] = mid [half_size - 1 - i];
|
|
||||||
}
|
|
||||||
|
|
||||||
void ResampleUtility::gen_sinc_os(double* out, int size, double cutoff, double kaiser)
|
|
||||||
{
|
|
||||||
assert( size % 2 == 1); // size must be odd
|
|
||||||
|
|
||||||
for(int i = 0; i < size; i++)
|
|
||||||
{
|
|
||||||
if(i == (size / 2))
|
|
||||||
out[i] = 2 * M_PI * (cutoff / 2); //0.078478; //1.0; //sin(2 * M_PI * (cutoff / 2) * (i - size / 2)) / (i - (size / 2));
|
|
||||||
else
|
|
||||||
out[i] = sin(2 * M_PI * (cutoff / 2) * (i - size / 2)) / (i - (size / 2));
|
|
||||||
|
|
||||||
// out[i] *= 0.3635819 - 0.4891775 * cos(2 * M_PI * i / (size - 1)) + 0.1365995 * cos(4 * M_PI * i / (size - 1)) - 0.0106411 * cos(6 * M_PI * i / (size - 1));
|
|
||||||
//0.42 - 0.5 * cos(2 * M_PI * i / (size - 1)) + 0.08 * cos(4 * M_PI * i / (size - 1));
|
|
||||||
|
|
||||||
// printf("%d %f\n", i, out[i]);
|
|
||||||
}
|
|
||||||
|
|
||||||
kaiser_window(&out[size / 2], size / 2 + 1, kaiser);
|
|
||||||
|
|
||||||
// Mirror for left half
|
|
||||||
for ( int i = 0; i < size / 2; i++ )
|
|
||||||
out [i] = out [size - 1 - i];
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
void ResampleUtility::normalize(double* io, int size, double gain)
|
|
||||||
{
|
|
||||||
double sum = 0;
|
|
||||||
for ( int i = 0; i < size; i++ )
|
|
||||||
sum += io [i];
|
|
||||||
|
|
||||||
double scale = gain / sum;
|
|
||||||
for ( int i = 0; i < size; i++ )
|
|
||||||
io [i] *= scale;
|
|
||||||
}
|
|
||||||
|
|
||||||
void* ResampleUtility::make_aligned(void* ptr, unsigned boundary)
|
|
||||||
{
|
|
||||||
unsigned char* null_ptr = (unsigned char *)nullptr;
|
|
||||||
unsigned char* uc_ptr = (unsigned char *)ptr;
|
|
||||||
|
|
||||||
uc_ptr += (boundary - ((uc_ptr - null_ptr) & (boundary - 1))) & (boundary - 1);
|
|
||||||
|
|
||||||
//while((uc_ptr - null_ptr) & (boundary - 1))
|
|
||||||
// uc_ptr++;
|
|
||||||
|
|
||||||
//printf("%16llx %16llx\n", (unsigned long long)ptr, (unsigned long long)uc_ptr);
|
|
||||||
|
|
||||||
assert((uc_ptr - (unsigned char *)ptr) < boundary && (uc_ptr >= (unsigned char *)ptr));
|
|
||||||
|
|
||||||
return uc_ptr;
|
|
||||||
}
|
|
|
@ -1,43 +0,0 @@
|
||||||
#ifdef NALL_DSP_INTERNAL_HPP
|
|
||||||
|
|
||||||
struct ResampleLinear : Resampler {
|
|
||||||
inline void setFrequency();
|
|
||||||
inline void clear();
|
|
||||||
inline void sample();
|
|
||||||
ResampleLinear(DSP &dsp) : Resampler(dsp) {}
|
|
||||||
|
|
||||||
real fraction;
|
|
||||||
real step;
|
|
||||||
};
|
|
||||||
|
|
||||||
void ResampleLinear::setFrequency() {
|
|
||||||
fraction = 0.0;
|
|
||||||
step = dsp.settings.frequency / frequency;
|
|
||||||
}
|
|
||||||
|
|
||||||
void ResampleLinear::clear() {
|
|
||||||
fraction = 0.0;
|
|
||||||
}
|
|
||||||
|
|
||||||
void ResampleLinear::sample() {
|
|
||||||
while(fraction <= 1.0) {
|
|
||||||
real channel[dsp.settings.channels];
|
|
||||||
|
|
||||||
for(unsigned n = 0; n < dsp.settings.channels; n++) {
|
|
||||||
real a = dsp.buffer.read(n, -1);
|
|
||||||
real b = dsp.buffer.read(n, -0);
|
|
||||||
|
|
||||||
real mu = fraction;
|
|
||||||
|
|
||||||
channel[n] = a * (1.0 - mu) + b * mu;
|
|
||||||
}
|
|
||||||
|
|
||||||
dsp.write(channel);
|
|
||||||
fraction += step;
|
|
||||||
}
|
|
||||||
|
|
||||||
dsp.buffer.rdoffset++;
|
|
||||||
fraction -= 1.0;
|
|
||||||
}
|
|
||||||
|
|
||||||
#endif
|
|
|
@ -1,43 +0,0 @@
|
||||||
#ifdef NALL_DSP_INTERNAL_HPP
|
|
||||||
|
|
||||||
struct ResampleNearest : Resampler {
|
|
||||||
inline void setFrequency();
|
|
||||||
inline void clear();
|
|
||||||
inline void sample();
|
|
||||||
ResampleNearest(DSP &dsp) : Resampler(dsp) {}
|
|
||||||
|
|
||||||
real fraction;
|
|
||||||
real step;
|
|
||||||
};
|
|
||||||
|
|
||||||
void ResampleNearest::setFrequency() {
|
|
||||||
fraction = 0.0;
|
|
||||||
step = dsp.settings.frequency / frequency;
|
|
||||||
}
|
|
||||||
|
|
||||||
void ResampleNearest::clear() {
|
|
||||||
fraction = 0.0;
|
|
||||||
}
|
|
||||||
|
|
||||||
void ResampleNearest::sample() {
|
|
||||||
while(fraction <= 1.0) {
|
|
||||||
real channel[dsp.settings.channels];
|
|
||||||
|
|
||||||
for(unsigned n = 0; n < dsp.settings.channels; n++) {
|
|
||||||
real a = dsp.buffer.read(n, -1);
|
|
||||||
real b = dsp.buffer.read(n, -0);
|
|
||||||
|
|
||||||
real mu = fraction;
|
|
||||||
|
|
||||||
channel[n] = mu < 0.5 ? a : b;
|
|
||||||
}
|
|
||||||
|
|
||||||
dsp.write(channel);
|
|
||||||
fraction += step;
|
|
||||||
}
|
|
||||||
|
|
||||||
dsp.buffer.rdoffset++;
|
|
||||||
fraction -= 1.0;
|
|
||||||
}
|
|
||||||
|
|
||||||
#endif
|
|
|
@ -1,54 +0,0 @@
|
||||||
#ifdef NALL_DSP_INTERNAL_HPP
|
|
||||||
|
|
||||||
#include "lib/sinc.hpp"
|
|
||||||
|
|
||||||
struct ResampleSinc : Resampler {
|
|
||||||
inline void setFrequency();
|
|
||||||
inline void clear();
|
|
||||||
inline void sample();
|
|
||||||
inline ResampleSinc(DSP &dsp);
|
|
||||||
|
|
||||||
private:
|
|
||||||
inline void remakeSinc();
|
|
||||||
SincResample *sinc_resampler[8];
|
|
||||||
};
|
|
||||||
|
|
||||||
void ResampleSinc::setFrequency() {
|
|
||||||
remakeSinc();
|
|
||||||
}
|
|
||||||
|
|
||||||
void ResampleSinc::clear() {
|
|
||||||
remakeSinc();
|
|
||||||
}
|
|
||||||
|
|
||||||
void ResampleSinc::sample() {
|
|
||||||
for(unsigned c = 0; c < dsp.settings.channels; c++) {
|
|
||||||
sinc_resampler[c]->write(dsp.buffer.read(c));
|
|
||||||
}
|
|
||||||
|
|
||||||
if(sinc_resampler[0]->output_avail()) {
|
|
||||||
do {
|
|
||||||
for(unsigned c = 0; c < dsp.settings.channels; c++) {
|
|
||||||
dsp.output.write(c) = sinc_resampler[c]->read();
|
|
||||||
}
|
|
||||||
dsp.output.wroffset++;
|
|
||||||
} while(sinc_resampler[0]->output_avail());
|
|
||||||
}
|
|
||||||
|
|
||||||
dsp.buffer.rdoffset++;
|
|
||||||
}
|
|
||||||
|
|
||||||
ResampleSinc::ResampleSinc(DSP &dsp) : Resampler(dsp) {
|
|
||||||
for(unsigned n = 0; n < 8; n++) sinc_resampler[n] = nullptr;
|
|
||||||
}
|
|
||||||
|
|
||||||
void ResampleSinc::remakeSinc() {
|
|
||||||
assert(dsp.settings.channels < 8);
|
|
||||||
|
|
||||||
for(unsigned c = 0; c < dsp.settings.channels; c++) {
|
|
||||||
if(sinc_resampler[c]) delete sinc_resampler[c];
|
|
||||||
sinc_resampler[c] = new SincResample(dsp.settings.frequency, frequency, 0.85, SincResample::QUALITY_HIGH);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#endif
|
|
|
@ -1,50 +0,0 @@
|
||||||
#ifdef NALL_DSP_INTERNAL_HPP
|
|
||||||
|
|
||||||
void DSP::setChannels(unsigned channels) {
|
|
||||||
assert(channels > 0);
|
|
||||||
buffer.setChannels(channels);
|
|
||||||
output.setChannels(channels);
|
|
||||||
settings.channels = channels;
|
|
||||||
}
|
|
||||||
|
|
||||||
void DSP::setPrecision(unsigned precision) {
|
|
||||||
settings.precision = precision;
|
|
||||||
settings.intensity = 1 << (settings.precision - 1);
|
|
||||||
settings.intensityInverse = 1.0 / settings.intensity;
|
|
||||||
}
|
|
||||||
|
|
||||||
void DSP::setFrequency(real frequency) {
|
|
||||||
settings.frequency = frequency;
|
|
||||||
resampler->setFrequency();
|
|
||||||
}
|
|
||||||
|
|
||||||
void DSP::setVolume(real volume) {
|
|
||||||
settings.volume = volume;
|
|
||||||
}
|
|
||||||
|
|
||||||
void DSP::setBalance(real balance) {
|
|
||||||
settings.balance = balance;
|
|
||||||
}
|
|
||||||
|
|
||||||
void DSP::setResampler(ResampleEngine engine) {
|
|
||||||
if(resampler) delete resampler;
|
|
||||||
|
|
||||||
switch(engine) {
|
|
||||||
case ResampleEngine::Nearest: resampler = new ResampleNearest(*this); return;
|
|
||||||
case ResampleEngine::Linear: resampler = new ResampleLinear (*this); return;
|
|
||||||
case ResampleEngine::Cosine: resampler = new ResampleCosine (*this); return;
|
|
||||||
case ResampleEngine::Cubic: resampler = new ResampleCubic (*this); return;
|
|
||||||
case ResampleEngine::Hermite: resampler = new ResampleHermite(*this); return;
|
|
||||||
case ResampleEngine::Average: resampler = new ResampleAverage(*this); return;
|
|
||||||
case ResampleEngine::Sinc: resampler = new ResampleSinc (*this); return;
|
|
||||||
}
|
|
||||||
|
|
||||||
throw;
|
|
||||||
}
|
|
||||||
|
|
||||||
void DSP::setResamplerFrequency(real frequency) {
|
|
||||||
resampler->frequency = frequency;
|
|
||||||
resampler->setFrequency();
|
|
||||||
}
|
|
||||||
|
|
||||||
#endif
|
|
|
@ -1,103 +0,0 @@
|
||||||
#ifndef NALL_EMULATION_SUPER_FAMICOM_USART_HPP
|
|
||||||
#define NALL_EMULATION_SUPER_FAMICOM_USART_HPP
|
|
||||||
|
|
||||||
#include <nall/platform.hpp>
|
|
||||||
#include <nall/function.hpp>
|
|
||||||
#include <nall/serial.hpp>
|
|
||||||
#include <nall/stdint.hpp>
|
|
||||||
|
|
||||||
#include <signal.h>
|
|
||||||
#include <sys/time.h>
|
|
||||||
#include <sys/resource.h>
|
|
||||||
|
|
||||||
#define usartproc dllexport
|
|
||||||
|
|
||||||
static nall::function<bool ()> usart_quit;
|
|
||||||
static nall::function<void (unsigned milliseconds)> usart_usleep;
|
|
||||||
static nall::function<bool ()> usart_readable;
|
|
||||||
static nall::function<uint8_t ()> usart_read;
|
|
||||||
static nall::function<bool ()> usart_writable;
|
|
||||||
static nall::function<void (uint8_t data)> usart_write;
|
|
||||||
|
|
||||||
extern "C" usartproc void usart_init(
|
|
||||||
nall::function<bool ()> quit,
|
|
||||||
nall::function<void (unsigned milliseconds)> usleep,
|
|
||||||
nall::function<bool ()> readable,
|
|
||||||
nall::function<uint8_t ()> read,
|
|
||||||
nall::function<bool ()> writable,
|
|
||||||
nall::function<void (uint8_t data)> write
|
|
||||||
) {
|
|
||||||
usart_quit = quit;
|
|
||||||
usart_usleep = usleep;
|
|
||||||
usart_readable = readable;
|
|
||||||
usart_read = read;
|
|
||||||
usart_writable = writable;
|
|
||||||
usart_write = write;
|
|
||||||
}
|
|
||||||
|
|
||||||
extern "C" usartproc void usart_main(int, char**);
|
|
||||||
|
|
||||||
//
|
|
||||||
|
|
||||||
static nall::serial usart;
|
|
||||||
static bool usart_is_virtual = true;
|
|
||||||
static bool usart_sigint = false;
|
|
||||||
|
|
||||||
static bool usart_virtual() {
|
|
||||||
return usart_is_virtual;
|
|
||||||
}
|
|
||||||
|
|
||||||
//
|
|
||||||
|
|
||||||
static bool usarthw_quit() {
|
|
||||||
return usart_sigint;
|
|
||||||
}
|
|
||||||
|
|
||||||
static void usarthw_usleep(unsigned milliseconds) {
|
|
||||||
usleep(milliseconds);
|
|
||||||
}
|
|
||||||
|
|
||||||
static bool usarthw_readable() {
|
|
||||||
return usart.readable();
|
|
||||||
}
|
|
||||||
|
|
||||||
static uint8_t usarthw_read() {
|
|
||||||
while(true) {
|
|
||||||
uint8_t buffer[1];
|
|
||||||
signed length = usart.read((uint8_t*)&buffer, 1);
|
|
||||||
if(length > 0) return buffer[0];
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
static bool usarthw_writable() {
|
|
||||||
return usart.writable();
|
|
||||||
}
|
|
||||||
|
|
||||||
static void usarthw_write(uint8_t data) {
|
|
||||||
uint8_t buffer[1] = { data };
|
|
||||||
usart.write((uint8_t*)&buffer, 1);
|
|
||||||
}
|
|
||||||
|
|
||||||
static void sigint(int) {
|
|
||||||
signal(SIGINT, SIG_DFL);
|
|
||||||
usart_sigint = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
int main(int argc, char **argv) {
|
|
||||||
setpriority(PRIO_PROCESS, 0, -20); //requires superuser privileges; otherwise priority = +0
|
|
||||||
signal(SIGINT, sigint);
|
|
||||||
|
|
||||||
if(usart.open("/dev/ttyACM0", 57600, true) == false) {
|
|
||||||
printf("error: unable to open USART hardware device\n");
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
usart_is_virtual = false;
|
|
||||||
usart_init(usarthw_quit, usarthw_usleep, usarthw_readable, usarthw_read, usarthw_writable, usarthw_write);
|
|
||||||
usart_main(argc, argv);
|
|
||||||
usart.close();
|
|
||||||
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
#endif
|
|
|
@ -1,42 +0,0 @@
|
||||||
#ifndef NALL_ENDIAN_HPP
|
|
||||||
#define NALL_ENDIAN_HPP
|
|
||||||
|
|
||||||
#include <nall/intrinsics.hpp>
|
|
||||||
|
|
||||||
#if defined(ENDIAN_LSB)
|
|
||||||
//little-endian: uint8_t[] { 0x01, 0x02, 0x03, 0x04 } == 0x04030201
|
|
||||||
#define order_lsb2(a,b) a,b
|
|
||||||
#define order_lsb3(a,b,c) a,b,c
|
|
||||||
#define order_lsb4(a,b,c,d) a,b,c,d
|
|
||||||
#define order_lsb5(a,b,c,d,e) a,b,c,d,e
|
|
||||||
#define order_lsb6(a,b,c,d,e,f) a,b,c,d,e,f
|
|
||||||
#define order_lsb7(a,b,c,d,e,f,g) a,b,c,d,e,f,g
|
|
||||||
#define order_lsb8(a,b,c,d,e,f,g,h) a,b,c,d,e,f,g,h
|
|
||||||
#define order_msb2(a,b) b,a
|
|
||||||
#define order_msb3(a,b,c) c,b,a
|
|
||||||
#define order_msb4(a,b,c,d) d,c,b,a
|
|
||||||
#define order_msb5(a,b,c,d,e) e,d,c,b,a
|
|
||||||
#define order_msb6(a,b,c,d,e,f) f,e,d,c,b,a
|
|
||||||
#define order_msb7(a,b,c,d,e,f,g) g,f,e,d,c,b,a
|
|
||||||
#define order_msb8(a,b,c,d,e,f,g,h) h,g,f,e,d,c,b,a
|
|
||||||
#elif defined(ENDIAN_MSB)
|
|
||||||
//big-endian: uint8_t[] { 0x01, 0x02, 0x03, 0x04 } == 0x01020304
|
|
||||||
#define order_lsb2(a,b) b,a
|
|
||||||
#define order_lsb3(a,b,c) c,b,a
|
|
||||||
#define order_lsb4(a,b,c,d) d,c,b,a
|
|
||||||
#define order_lsb5(a,b,c,d,e) e,d,c,b,a
|
|
||||||
#define order_lsb6(a,b,c,d,e,f) f,e,d,c,b,a
|
|
||||||
#define order_lsb7(a,b,c,d,e,f,g) g,f,e,d,c,b,a
|
|
||||||
#define order_lsb8(a,b,c,d,e,f,g,h) h,g,f,e,d,c,b,a
|
|
||||||
#define order_msb2(a,b) a,b
|
|
||||||
#define order_msb3(a,b,c) a,b,c
|
|
||||||
#define order_msb4(a,b,c,d) a,b,c,d
|
|
||||||
#define order_msb5(a,b,c,d,e) a,b,c,d,e
|
|
||||||
#define order_msb6(a,b,c,d,e,f) a,b,c,d,e,f
|
|
||||||
#define order_msb7(a,b,c,d,e,f,g) a,b,c,d,e,f,g
|
|
||||||
#define order_msb8(a,b,c,d,e,f,g,h) a,b,c,d,e,f,g,h
|
|
||||||
#else
|
|
||||||
#error "Unknown endian. Please specify in nall/intrinsics.hpp"
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#endif
|
|
|
@ -1,352 +0,0 @@
|
||||||
#ifndef NALL_FILE_HPP
|
|
||||||
#define NALL_FILE_HPP
|
|
||||||
|
|
||||||
#include <nall/platform.hpp>
|
|
||||||
#include <nall/stdint.hpp>
|
|
||||||
#include <nall/string.hpp>
|
|
||||||
#include <nall/utility.hpp>
|
|
||||||
#include <nall/windows/utf8.hpp>
|
|
||||||
#include <nall/stream/memory.hpp>
|
|
||||||
|
|
||||||
namespace nall {
|
|
||||||
inline FILE* fopen_utf8(const string &utf8_filename, const char *mode) {
|
|
||||||
#if !defined(_WIN32)
|
|
||||||
return fopen(utf8_filename, mode);
|
|
||||||
#else
|
|
||||||
return _wfopen(utf16_t(utf8_filename), utf16_t(mode));
|
|
||||||
#endif
|
|
||||||
}
|
|
||||||
|
|
||||||
struct file {
|
|
||||||
enum class mode : unsigned { read, write, modify, append, readwrite = modify, writeread = append };
|
|
||||||
enum class index : unsigned { absolute, relative };
|
|
||||||
enum class time : unsigned { create, modify, access };
|
|
||||||
|
|
||||||
static bool copy(const string &sourcename, const string &targetname) {
|
|
||||||
file rd, wr;
|
|
||||||
if(rd.open(sourcename, mode::read) == false) return false;
|
|
||||||
if(wr.open(targetname, mode::write) == false) return false;
|
|
||||||
for(unsigned n = 0; n < rd.size(); n++) wr.write(rd.read());
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
static bool move(const string &sourcename, const string &targetname) {
|
|
||||||
#if !defined(_WIN32)
|
|
||||||
return rename(sourcename, targetname) == 0;
|
|
||||||
#else
|
|
||||||
return _wrename(utf16_t(sourcename), utf16_t(targetname)) == 0;
|
|
||||||
#endif
|
|
||||||
}
|
|
||||||
|
|
||||||
static bool remove(const string &filename) {
|
|
||||||
return unlink(filename) == 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
static bool truncate(const string &filename, unsigned size) {
|
|
||||||
#if !defined(_WIN32)
|
|
||||||
return truncate(filename, size) == 0;
|
|
||||||
#else
|
|
||||||
bool result = false;
|
|
||||||
FILE *fp = fopen(filename, "rb+");
|
|
||||||
if(fp) {
|
|
||||||
result = _chsize(fileno(fp), size) == 0;
|
|
||||||
fclose(fp);
|
|
||||||
}
|
|
||||||
return result;
|
|
||||||
#endif
|
|
||||||
}
|
|
||||||
|
|
||||||
static vector<uint8_t> read(const string &filename) {
|
|
||||||
vector<uint8_t> memory;
|
|
||||||
file fp;
|
|
||||||
if(fp.open(filename, mode::read)) {
|
|
||||||
memory.resize(fp.size());
|
|
||||||
fp.read(memory.data(), memory.size());
|
|
||||||
}
|
|
||||||
return memory;
|
|
||||||
}
|
|
||||||
|
|
||||||
static bool read(const string &filename, uint8_t *data, unsigned size) {
|
|
||||||
file fp;
|
|
||||||
if(fp.open(filename, mode::read) == false) return false;
|
|
||||||
fp.read(data, size);
|
|
||||||
fp.close();
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
static bool write(const string &filename, const string &text) {
|
|
||||||
file fp;
|
|
||||||
if(fp.open(filename, mode::write) == false) return false;
|
|
||||||
fp.print(text);
|
|
||||||
fp.close();
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
static bool write(const string &filename, const vector<uint8_t> &buffer) {
|
|
||||||
file fp;
|
|
||||||
if(fp.open(filename, mode::write) == false) return false;
|
|
||||||
fp.write(buffer.data(), buffer.size());
|
|
||||||
fp.close();
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
static bool write(const string &filename, const uint8_t *data, unsigned size) {
|
|
||||||
file fp;
|
|
||||||
if(fp.open(filename, mode::write) == false) return false;
|
|
||||||
fp.write(data, size);
|
|
||||||
fp.close();
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
static bool create(const string &filename) {
|
|
||||||
//create an empty file (will replace existing files)
|
|
||||||
file fp;
|
|
||||||
if(fp.open(filename, mode::write) == false) return false;
|
|
||||||
fp.close();
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
static string sha256(const string &filename) {
|
|
||||||
auto buffer = read(filename);
|
|
||||||
return nall::sha256(buffer.data(), buffer.size());
|
|
||||||
}
|
|
||||||
|
|
||||||
uint8_t read() {
|
|
||||||
if(!fp) return 0xff; //file not open
|
|
||||||
if(file_mode == mode::write) return 0xff; //reads not permitted
|
|
||||||
if(file_offset >= file_size) return 0xff; //cannot read past end of file
|
|
||||||
buffer_sync();
|
|
||||||
return buffer[(file_offset++) & buffer_mask];
|
|
||||||
}
|
|
||||||
|
|
||||||
uintmax_t readl(unsigned length = 1) {
|
|
||||||
uintmax_t data = 0;
|
|
||||||
for(int i = 0; i < length; i++) {
|
|
||||||
data |= (uintmax_t)read() << (i << 3);
|
|
||||||
}
|
|
||||||
return data;
|
|
||||||
}
|
|
||||||
|
|
||||||
uintmax_t readm(unsigned length = 1) {
|
|
||||||
uintmax_t data = 0;
|
|
||||||
while(length--) {
|
|
||||||
data <<= 8;
|
|
||||||
data |= read();
|
|
||||||
}
|
|
||||||
return data;
|
|
||||||
}
|
|
||||||
|
|
||||||
void read(uint8_t *buffer, unsigned length) {
|
|
||||||
while(length--) *buffer++ = read();
|
|
||||||
}
|
|
||||||
|
|
||||||
void write(uint8_t data) {
|
|
||||||
if(!fp) return; //file not open
|
|
||||||
if(file_mode == mode::read) return; //writes not permitted
|
|
||||||
buffer_sync();
|
|
||||||
buffer[(file_offset++) & buffer_mask] = data;
|
|
||||||
buffer_dirty = true;
|
|
||||||
if(file_offset > file_size) file_size = file_offset;
|
|
||||||
}
|
|
||||||
|
|
||||||
void writel(uintmax_t data, unsigned length = 1) {
|
|
||||||
while(length--) {
|
|
||||||
write(data);
|
|
||||||
data >>= 8;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void writem(uintmax_t data, unsigned length = 1) {
|
|
||||||
for(int i = length - 1; i >= 0; i--) {
|
|
||||||
write(data >> (i << 3));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void write(const uint8_t *buffer, unsigned length) {
|
|
||||||
while(length--) write(*buffer++);
|
|
||||||
}
|
|
||||||
|
|
||||||
template<typename... Args> void print(Args... args) {
|
|
||||||
string data(args...);
|
|
||||||
const char *p = data;
|
|
||||||
while(*p) write(*p++);
|
|
||||||
}
|
|
||||||
|
|
||||||
void flush() {
|
|
||||||
buffer_flush();
|
|
||||||
fflush(fp);
|
|
||||||
}
|
|
||||||
|
|
||||||
void seek(int offset, index index_ = index::absolute) {
|
|
||||||
if(!fp) return; //file not open
|
|
||||||
buffer_flush();
|
|
||||||
|
|
||||||
uintmax_t req_offset = file_offset;
|
|
||||||
switch(index_) {
|
|
||||||
case index::absolute: req_offset = offset; break;
|
|
||||||
case index::relative: req_offset += offset; break;
|
|
||||||
}
|
|
||||||
|
|
||||||
if(req_offset < 0) req_offset = 0; //cannot seek before start of file
|
|
||||||
if(req_offset > file_size) {
|
|
||||||
if(file_mode == mode::read) { //cannot seek past end of file
|
|
||||||
req_offset = file_size;
|
|
||||||
} else { //pad file to requested location
|
|
||||||
file_offset = file_size;
|
|
||||||
while(file_size < req_offset) write(0x00);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
file_offset = req_offset;
|
|
||||||
}
|
|
||||||
|
|
||||||
unsigned offset() const {
|
|
||||||
if(!fp) return 0; //file not open
|
|
||||||
return file_offset;
|
|
||||||
}
|
|
||||||
|
|
||||||
unsigned size() const {
|
|
||||||
if(!fp) return 0; //file not open
|
|
||||||
return file_size;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool truncate(unsigned size) {
|
|
||||||
if(!fp) return false; //file not open
|
|
||||||
#if !defined(_WIN32)
|
|
||||||
return ftruncate(fileno(fp), size) == 0;
|
|
||||||
#else
|
|
||||||
return _chsize(fileno(fp), size) == 0;
|
|
||||||
#endif
|
|
||||||
}
|
|
||||||
|
|
||||||
bool end() {
|
|
||||||
if(!fp) return true; //file not open
|
|
||||||
return file_offset >= file_size;
|
|
||||||
}
|
|
||||||
|
|
||||||
static bool exists(const string &filename) {
|
|
||||||
#if !defined(_WIN32)
|
|
||||||
struct stat64 data;
|
|
||||||
return stat64(filename, &data) == 0;
|
|
||||||
#else
|
|
||||||
struct __stat64 data;
|
|
||||||
return _wstat64(utf16_t(filename), &data) == 0;
|
|
||||||
#endif
|
|
||||||
}
|
|
||||||
|
|
||||||
static uintmax_t size(const string &filename) {
|
|
||||||
#if !defined(_WIN32)
|
|
||||||
struct stat64 data;
|
|
||||||
stat64(filename, &data);
|
|
||||||
#else
|
|
||||||
struct __stat64 data;
|
|
||||||
_wstat64(utf16_t(filename), &data);
|
|
||||||
#endif
|
|
||||||
return S_ISREG(data.st_mode) ? data.st_size : 0u;
|
|
||||||
}
|
|
||||||
|
|
||||||
static time_t timestamp(const string &filename, file::time mode = file::time::create) {
|
|
||||||
#if !defined(_WIN32)
|
|
||||||
struct stat64 data;
|
|
||||||
stat64(filename, &data);
|
|
||||||
#else
|
|
||||||
struct __stat64 data;
|
|
||||||
_wstat64(utf16_t(filename), &data);
|
|
||||||
#endif
|
|
||||||
switch(mode) { default:
|
|
||||||
case file::time::create: return data.st_ctime;
|
|
||||||
case file::time::modify: return data.st_mtime;
|
|
||||||
case file::time::access: return data.st_atime;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
bool open() const {
|
|
||||||
return fp;
|
|
||||||
}
|
|
||||||
|
|
||||||
explicit operator bool() const {
|
|
||||||
return open();
|
|
||||||
}
|
|
||||||
|
|
||||||
bool open(const string &filename, mode mode_) {
|
|
||||||
if(fp) return false;
|
|
||||||
|
|
||||||
switch(file_mode = mode_) {
|
|
||||||
#if !defined(_WIN32)
|
|
||||||
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
|
|
||||||
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;
|
|
||||||
case mode::writeread: fp = _wfopen(utf16_t(filename), L"wb+"); break;
|
|
||||||
#endif
|
|
||||||
}
|
|
||||||
if(!fp) return false;
|
|
||||||
buffer_offset = -1; //invalidate buffer
|
|
||||||
file_offset = 0;
|
|
||||||
fseek(fp, 0, SEEK_END);
|
|
||||||
file_size = ftell(fp);
|
|
||||||
fseek(fp, 0, SEEK_SET);
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
void close() {
|
|
||||||
if(!fp) return;
|
|
||||||
buffer_flush();
|
|
||||||
fclose(fp);
|
|
||||||
fp = nullptr;
|
|
||||||
}
|
|
||||||
|
|
||||||
file() {
|
|
||||||
}
|
|
||||||
|
|
||||||
file(const string &filename, mode mode_) {
|
|
||||||
open(filename, mode_);
|
|
||||||
}
|
|
||||||
|
|
||||||
~file() {
|
|
||||||
close();
|
|
||||||
}
|
|
||||||
|
|
||||||
file& operator=(const file&) = delete;
|
|
||||||
file(const file&) = delete;
|
|
||||||
|
|
||||||
private:
|
|
||||||
enum { buffer_size = 1 << 12, buffer_mask = buffer_size - 1 };
|
|
||||||
char buffer[buffer_size] = {0};
|
|
||||||
int buffer_offset = -1; //invalidate buffer
|
|
||||||
bool buffer_dirty = false;
|
|
||||||
FILE *fp = nullptr;
|
|
||||||
unsigned file_offset = 0;
|
|
||||||
unsigned file_size = 0;
|
|
||||||
mode file_mode = mode::read;
|
|
||||||
|
|
||||||
void buffer_sync() {
|
|
||||||
if(!fp) return; //file not open
|
|
||||||
if(buffer_offset != (file_offset & ~buffer_mask)) {
|
|
||||||
buffer_flush();
|
|
||||||
buffer_offset = file_offset & ~buffer_mask;
|
|
||||||
fseek(fp, buffer_offset, SEEK_SET);
|
|
||||||
unsigned length = (buffer_offset + buffer_size) <= file_size ? buffer_size : (file_size & buffer_mask);
|
|
||||||
if(length) unsigned unused = fread(buffer, 1, length, fp);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void buffer_flush() {
|
|
||||||
if(!fp) return; //file not open
|
|
||||||
if(file_mode == mode::read) return; //buffer cannot be written to
|
|
||||||
if(buffer_offset < 0) return; //buffer unused
|
|
||||||
if(buffer_dirty == false) return; //buffer unmodified since read
|
|
||||||
fseek(fp, buffer_offset, SEEK_SET);
|
|
||||||
unsigned length = (buffer_offset + buffer_size) <= file_size ? buffer_size : (file_size & buffer_mask);
|
|
||||||
if(length) unsigned unused = fwrite(buffer, 1, length, fp);
|
|
||||||
buffer_offset = -1; //invalidate buffer
|
|
||||||
buffer_dirty = false;
|
|
||||||
}
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
#endif
|
|
|
@ -1,214 +0,0 @@
|
||||||
#ifndef NALL_FILEMAP_HPP
|
|
||||||
#define NALL_FILEMAP_HPP
|
|
||||||
|
|
||||||
#include <nall/file.hpp>
|
|
||||||
#include <nall/stdint.hpp>
|
|
||||||
#include <nall/windows/utf8.hpp>
|
|
||||||
|
|
||||||
#include <stdio.h>
|
|
||||||
#include <stdlib.h>
|
|
||||||
#if defined(_WIN32)
|
|
||||||
#include <windows.h>
|
|
||||||
#else
|
|
||||||
#include <fcntl.h>
|
|
||||||
#include <unistd.h>
|
|
||||||
#include <sys/mman.h>
|
|
||||||
#include <sys/stat.h>
|
|
||||||
#include <sys/types.h>
|
|
||||||
#endif
|
|
||||||
|
|
||||||
namespace nall {
|
|
||||||
class filemap {
|
|
||||||
public:
|
|
||||||
enum class mode : unsigned { read, write, readwrite, writeread };
|
|
||||||
|
|
||||||
explicit operator bool() const { return open(); }
|
|
||||||
bool open() const { return p_open(); }
|
|
||||||
bool open(const char *filename, mode mode_) { return p_open(filename, mode_); }
|
|
||||||
void close() { return p_close(); }
|
|
||||||
unsigned size() const { return p_size; }
|
|
||||||
uint8_t* data() { return p_handle; }
|
|
||||||
const uint8_t* data() const { return p_handle; }
|
|
||||||
filemap() : p_size(0), p_handle(nullptr) { p_ctor(); }
|
|
||||||
filemap(const char *filename, mode mode_) : p_size(0), p_handle(nullptr) { p_ctor(); p_open(filename, mode_); }
|
|
||||||
~filemap() { p_dtor(); }
|
|
||||||
|
|
||||||
private:
|
|
||||||
unsigned p_size;
|
|
||||||
uint8_t *p_handle;
|
|
||||||
|
|
||||||
#if defined(_WIN32)
|
|
||||||
//=============
|
|
||||||
//MapViewOfFile
|
|
||||||
//=============
|
|
||||||
|
|
||||||
HANDLE p_filehandle, p_maphandle;
|
|
||||||
|
|
||||||
bool p_open() const {
|
|
||||||
return p_handle;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool p_open(const char *filename, mode mode_) {
|
|
||||||
if(file::exists(filename) && file::size(filename) == 0) {
|
|
||||||
p_handle = nullptr;
|
|
||||||
p_size = 0;
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
int desired_access, creation_disposition, flprotect, map_access;
|
|
||||||
|
|
||||||
switch(mode_) {
|
|
||||||
default: return false;
|
|
||||||
case mode::read:
|
|
||||||
desired_access = GENERIC_READ;
|
|
||||||
creation_disposition = OPEN_EXISTING;
|
|
||||||
flprotect = PAGE_READONLY;
|
|
||||||
map_access = FILE_MAP_READ;
|
|
||||||
break;
|
|
||||||
case mode::write:
|
|
||||||
//write access requires read access
|
|
||||||
desired_access = GENERIC_WRITE;
|
|
||||||
creation_disposition = CREATE_ALWAYS;
|
|
||||||
flprotect = PAGE_READWRITE;
|
|
||||||
map_access = FILE_MAP_ALL_ACCESS;
|
|
||||||
break;
|
|
||||||
case mode::readwrite:
|
|
||||||
desired_access = GENERIC_READ | GENERIC_WRITE;
|
|
||||||
creation_disposition = OPEN_EXISTING;
|
|
||||||
flprotect = PAGE_READWRITE;
|
|
||||||
map_access = FILE_MAP_ALL_ACCESS;
|
|
||||||
break;
|
|
||||||
case mode::writeread:
|
|
||||||
desired_access = GENERIC_READ | GENERIC_WRITE;
|
|
||||||
creation_disposition = CREATE_NEW;
|
|
||||||
flprotect = PAGE_READWRITE;
|
|
||||||
map_access = FILE_MAP_ALL_ACCESS;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
p_filehandle = CreateFileW(utf16_t(filename), desired_access, FILE_SHARE_READ, nullptr,
|
|
||||||
creation_disposition, FILE_ATTRIBUTE_NORMAL, nullptr);
|
|
||||||
if(p_filehandle == INVALID_HANDLE_VALUE) return false;
|
|
||||||
|
|
||||||
p_size = GetFileSize(p_filehandle, nullptr);
|
|
||||||
|
|
||||||
p_maphandle = CreateFileMapping(p_filehandle, nullptr, flprotect, 0, p_size, nullptr);
|
|
||||||
if(p_maphandle == INVALID_HANDLE_VALUE) {
|
|
||||||
CloseHandle(p_filehandle);
|
|
||||||
p_filehandle = INVALID_HANDLE_VALUE;
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
p_handle = (uint8_t*)MapViewOfFile(p_maphandle, map_access, 0, 0, p_size);
|
|
||||||
return p_handle;
|
|
||||||
}
|
|
||||||
|
|
||||||
void p_close() {
|
|
||||||
if(p_handle) {
|
|
||||||
UnmapViewOfFile(p_handle);
|
|
||||||
p_handle = nullptr;
|
|
||||||
}
|
|
||||||
|
|
||||||
if(p_maphandle != INVALID_HANDLE_VALUE) {
|
|
||||||
CloseHandle(p_maphandle);
|
|
||||||
p_maphandle = INVALID_HANDLE_VALUE;
|
|
||||||
}
|
|
||||||
|
|
||||||
if(p_filehandle != INVALID_HANDLE_VALUE) {
|
|
||||||
CloseHandle(p_filehandle);
|
|
||||||
p_filehandle = INVALID_HANDLE_VALUE;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void p_ctor() {
|
|
||||||
p_filehandle = INVALID_HANDLE_VALUE;
|
|
||||||
p_maphandle = INVALID_HANDLE_VALUE;
|
|
||||||
}
|
|
||||||
|
|
||||||
void p_dtor() {
|
|
||||||
close();
|
|
||||||
}
|
|
||||||
|
|
||||||
#else
|
|
||||||
//====
|
|
||||||
//mmap
|
|
||||||
//====
|
|
||||||
|
|
||||||
int p_fd;
|
|
||||||
|
|
||||||
bool p_open() const {
|
|
||||||
return p_handle;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool p_open(const char *filename, mode mode_) {
|
|
||||||
if(file::exists(filename) && file::size(filename) == 0) {
|
|
||||||
p_handle = nullptr;
|
|
||||||
p_size = 0;
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
int open_flags, mmap_flags;
|
|
||||||
|
|
||||||
switch(mode_) {
|
|
||||||
default: return false;
|
|
||||||
case mode::read:
|
|
||||||
open_flags = O_RDONLY;
|
|
||||||
mmap_flags = PROT_READ;
|
|
||||||
break;
|
|
||||||
case mode::write:
|
|
||||||
open_flags = O_RDWR | O_CREAT; //mmap() requires read access
|
|
||||||
mmap_flags = PROT_WRITE;
|
|
||||||
break;
|
|
||||||
case mode::readwrite:
|
|
||||||
open_flags = O_RDWR;
|
|
||||||
mmap_flags = PROT_READ | PROT_WRITE;
|
|
||||||
break;
|
|
||||||
case mode::writeread:
|
|
||||||
open_flags = O_RDWR | O_CREAT;
|
|
||||||
mmap_flags = PROT_READ | PROT_WRITE;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
p_fd = ::open(filename, open_flags, S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP);
|
|
||||||
if(p_fd < 0) return false;
|
|
||||||
|
|
||||||
struct stat p_stat;
|
|
||||||
fstat(p_fd, &p_stat);
|
|
||||||
p_size = p_stat.st_size;
|
|
||||||
|
|
||||||
p_handle = (uint8_t*)mmap(nullptr, p_size, mmap_flags, MAP_SHARED, p_fd, 0);
|
|
||||||
if(p_handle == MAP_FAILED) {
|
|
||||||
p_handle = nullptr;
|
|
||||||
::close(p_fd);
|
|
||||||
p_fd = -1;
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
return p_handle;
|
|
||||||
}
|
|
||||||
|
|
||||||
void p_close() {
|
|
||||||
if(p_handle) {
|
|
||||||
munmap(p_handle, p_size);
|
|
||||||
p_handle = nullptr;
|
|
||||||
}
|
|
||||||
|
|
||||||
if(p_fd >= 0) {
|
|
||||||
::close(p_fd);
|
|
||||||
p_fd = -1;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void p_ctor() {
|
|
||||||
p_fd = -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
void p_dtor() {
|
|
||||||
p_close();
|
|
||||||
}
|
|
||||||
|
|
||||||
#endif
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
#endif
|
|
|
@ -1,60 +0,0 @@
|
||||||
#ifndef NALL_FUNCTION_HPP
|
|
||||||
#define NALL_FUNCTION_HPP
|
|
||||||
|
|
||||||
namespace nall {
|
|
||||||
template<typename T> class function;
|
|
||||||
|
|
||||||
template<typename R, typename... P> class function<R (P...)> {
|
|
||||||
struct container {
|
|
||||||
virtual R operator()(P... p) const = 0;
|
|
||||||
virtual container* copy() const = 0;
|
|
||||||
virtual ~container() {}
|
|
||||||
} *callback;
|
|
||||||
|
|
||||||
struct global : container {
|
|
||||||
R (*function)(P...);
|
|
||||||
R operator()(P... p) const { return function(std::forward<P>(p)...); }
|
|
||||||
container* copy() const { return new global(function); }
|
|
||||||
global(R (*function)(P...)) : function(function) {}
|
|
||||||
};
|
|
||||||
|
|
||||||
template<typename C> struct member : container {
|
|
||||||
R (C::*function)(P...);
|
|
||||||
C *object;
|
|
||||||
R operator()(P... p) const { return (object->*function)(std::forward<P>(p)...); }
|
|
||||||
container* copy() const { return new member(function, object); }
|
|
||||||
member(R (C::*function)(P...), C *object) : function(function), object(object) {}
|
|
||||||
};
|
|
||||||
|
|
||||||
template<typename L> struct lambda : container {
|
|
||||||
mutable L object;
|
|
||||||
R operator()(P... p) const { return object(std::forward<P>(p)...); }
|
|
||||||
container* copy() const { return new lambda(object); }
|
|
||||||
lambda(const L& object) : object(object) {}
|
|
||||||
};
|
|
||||||
|
|
||||||
public:
|
|
||||||
explicit operator bool() const { return callback; }
|
|
||||||
R operator()(P... p) const { return (*callback)(std::forward<P>(p)...); }
|
|
||||||
void reset() { if(callback) { delete callback; callback = nullptr; } }
|
|
||||||
|
|
||||||
function& operator=(const function &source) {
|
|
||||||
if(this != &source) {
|
|
||||||
if(callback) { delete callback; callback = nullptr; }
|
|
||||||
if(source.callback) callback = source.callback->copy();
|
|
||||||
}
|
|
||||||
return *this;
|
|
||||||
}
|
|
||||||
|
|
||||||
function(const function &source) : callback(nullptr) { operator=(source); }
|
|
||||||
function() : callback(nullptr) {}
|
|
||||||
function(void *function) : callback(nullptr) { if(function) callback = new global((R (*)(P...))function); }
|
|
||||||
function(R (*function)(P...)) { callback = new global(function); }
|
|
||||||
template<typename C> function(R (C::*function)(P...), C *object) { callback = new member<C>(function, object); }
|
|
||||||
template<typename C> function(R (C::*function)(P...) const, C *object) { callback = new member<C>((R (C::*)(P...))function, object); }
|
|
||||||
template<typename L> function(const L& object) { callback = new lambda<L>(object); }
|
|
||||||
~function() { if(callback) delete callback; }
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
#endif
|
|
|
@ -1,85 +0,0 @@
|
||||||
#ifndef NALL_GZIP_HPP
|
|
||||||
#define NALL_GZIP_HPP
|
|
||||||
|
|
||||||
#include <nall/file.hpp>
|
|
||||||
#include <nall/inflate.hpp>
|
|
||||||
|
|
||||||
namespace nall {
|
|
||||||
|
|
||||||
struct gzip {
|
|
||||||
string filename;
|
|
||||||
uint8_t *data;
|
|
||||||
unsigned size;
|
|
||||||
|
|
||||||
inline bool decompress(const string &filename);
|
|
||||||
inline bool decompress(const uint8_t *data, unsigned size);
|
|
||||||
|
|
||||||
inline gzip();
|
|
||||||
inline ~gzip();
|
|
||||||
};
|
|
||||||
|
|
||||||
bool gzip::decompress(const string &filename) {
|
|
||||||
if(auto memory = file::read(filename)) {
|
|
||||||
return decompress(memory.data(), memory.size());
|
|
||||||
}
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool gzip::decompress(const uint8_t *data, unsigned size) {
|
|
||||||
if(size < 18) return false;
|
|
||||||
if(data[0] != 0x1f) return false;
|
|
||||||
if(data[1] != 0x8b) return false;
|
|
||||||
unsigned cm = data[2];
|
|
||||||
unsigned flg = data[3];
|
|
||||||
unsigned mtime = data[4];
|
|
||||||
mtime |= data[5] << 8;
|
|
||||||
mtime |= data[6] << 16;
|
|
||||||
mtime |= data[7] << 24;
|
|
||||||
unsigned xfl = data[8];
|
|
||||||
unsigned os = data[9];
|
|
||||||
unsigned p = 10;
|
|
||||||
unsigned isize = data[size - 4];
|
|
||||||
isize |= data[size - 3] << 8;
|
|
||||||
isize |= data[size - 2] << 16;
|
|
||||||
isize |= data[size - 1] << 24;
|
|
||||||
filename = "";
|
|
||||||
|
|
||||||
if(flg & 0x04) { //FEXTRA
|
|
||||||
unsigned xlen = data[p + 0];
|
|
||||||
xlen |= data[p + 1] << 8;
|
|
||||||
p += 2 + xlen;
|
|
||||||
}
|
|
||||||
|
|
||||||
if(flg & 0x08) { //FNAME
|
|
||||||
char buffer[PATH_MAX];
|
|
||||||
for(unsigned n = 0; n < PATH_MAX; n++, p++) {
|
|
||||||
buffer[n] = data[p];
|
|
||||||
if(data[p] == 0) break;
|
|
||||||
}
|
|
||||||
if(data[p++]) return false;
|
|
||||||
filename = buffer;
|
|
||||||
}
|
|
||||||
|
|
||||||
if(flg & 0x10) { //FCOMMENT
|
|
||||||
while(data[p++]);
|
|
||||||
}
|
|
||||||
|
|
||||||
if(flg & 0x02) { //FHCRC
|
|
||||||
p += 2;
|
|
||||||
}
|
|
||||||
|
|
||||||
this->size = isize;
|
|
||||||
this->data = new uint8_t[this->size];
|
|
||||||
return inflate(this->data, this->size, data + p, size - p - 8);
|
|
||||||
}
|
|
||||||
|
|
||||||
gzip::gzip() : data(nullptr) {
|
|
||||||
}
|
|
||||||
|
|
||||||
gzip::~gzip() {
|
|
||||||
if(data) delete[] data;
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
#endif
|
|
|
@ -1,176 +0,0 @@
|
||||||
#ifndef NALL_HTTP_HPP
|
|
||||||
#define NALL_HTTP_HPP
|
|
||||||
|
|
||||||
#if !defined(_WIN32)
|
|
||||||
#include <sys/types.h>
|
|
||||||
#include <sys/socket.h>
|
|
||||||
#include <netinet/in.h>
|
|
||||||
#include <netdb.h>
|
|
||||||
#else
|
|
||||||
#include <winsock2.h>
|
|
||||||
#include <ws2tcpip.h>
|
|
||||||
#include <windows.h>
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#include <nall/platform.hpp>
|
|
||||||
#include <nall/string.hpp>
|
|
||||||
|
|
||||||
namespace nall {
|
|
||||||
|
|
||||||
struct http {
|
|
||||||
string hostname;
|
|
||||||
addrinfo *serverinfo;
|
|
||||||
int serversocket;
|
|
||||||
string header;
|
|
||||||
|
|
||||||
inline void download(const string &path, uint8_t *&data, unsigned &size) {
|
|
||||||
data = nullptr;
|
|
||||||
size = 0;
|
|
||||||
|
|
||||||
send({
|
|
||||||
"GET ", path, " HTTP/1.1\r\n"
|
|
||||||
"Host: ", hostname, "\r\n"
|
|
||||||
"Connection: close\r\n"
|
|
||||||
"\r\n"
|
|
||||||
});
|
|
||||||
|
|
||||||
header = downloadHeader();
|
|
||||||
downloadContent(data, size);
|
|
||||||
}
|
|
||||||
|
|
||||||
inline bool connect(string host, unsigned port) {
|
|
||||||
hostname = host;
|
|
||||||
|
|
||||||
addrinfo hints;
|
|
||||||
memset(&hints, 0, sizeof(addrinfo));
|
|
||||||
hints.ai_family = AF_UNSPEC;
|
|
||||||
hints.ai_socktype = SOCK_STREAM;
|
|
||||||
hints.ai_flags = AI_PASSIVE;
|
|
||||||
|
|
||||||
int status = getaddrinfo(hostname, string(port), &hints, &serverinfo);
|
|
||||||
if(status != 0) return false;
|
|
||||||
|
|
||||||
serversocket = socket(serverinfo->ai_family, serverinfo->ai_socktype, serverinfo->ai_protocol);
|
|
||||||
if(serversocket == -1) return false;
|
|
||||||
|
|
||||||
int result = ::connect(serversocket, serverinfo->ai_addr, serverinfo->ai_addrlen);
|
|
||||||
if(result == -1) return false;
|
|
||||||
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
inline bool send(const string &data) {
|
|
||||||
return send((const uint8_t*)(const char*)data, data.length());
|
|
||||||
}
|
|
||||||
|
|
||||||
inline bool send(const uint8_t *data, unsigned size) {
|
|
||||||
while(size) {
|
|
||||||
int length = ::send(serversocket, (const char*)data, size, 0);
|
|
||||||
if(length == -1) return false;
|
|
||||||
data += length;
|
|
||||||
size -= length;
|
|
||||||
}
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
inline string downloadHeader() {
|
|
||||||
string output;
|
|
||||||
do {
|
|
||||||
char buffer[2];
|
|
||||||
int length = recv(serversocket, buffer, 1, 0);
|
|
||||||
if(length <= 0) return output;
|
|
||||||
buffer[1] = 0;
|
|
||||||
output.append(buffer);
|
|
||||||
} while(output.endswith("\r\n\r\n") == false);
|
|
||||||
return output;
|
|
||||||
}
|
|
||||||
|
|
||||||
inline string downloadChunkLength() {
|
|
||||||
string output;
|
|
||||||
do {
|
|
||||||
char buffer[2];
|
|
||||||
int length = recv(serversocket, buffer, 1, 0);
|
|
||||||
if(length <= 0) return output;
|
|
||||||
buffer[1] = 0;
|
|
||||||
output.append(buffer);
|
|
||||||
} while(output.endswith("\r\n") == false);
|
|
||||||
return output;
|
|
||||||
}
|
|
||||||
|
|
||||||
inline void downloadContent(uint8_t *&data, unsigned &size) {
|
|
||||||
unsigned capacity = 0;
|
|
||||||
|
|
||||||
if(header.iposition("\r\nTransfer-Encoding: chunked\r\n")) {
|
|
||||||
while(true) {
|
|
||||||
unsigned length = hex(downloadChunkLength());
|
|
||||||
if(length == 0) break;
|
|
||||||
capacity += length;
|
|
||||||
data = (uint8_t*)realloc(data, capacity);
|
|
||||||
|
|
||||||
char buffer[length];
|
|
||||||
while(length) {
|
|
||||||
int packetlength = recv(serversocket, buffer, length, 0);
|
|
||||||
if(packetlength <= 0) break;
|
|
||||||
memcpy(data + size, buffer, packetlength);
|
|
||||||
size += packetlength;
|
|
||||||
length -= packetlength;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} else if(auto position = header.iposition("\r\nContent-Length: ")) {
|
|
||||||
unsigned length = decimal((const char*)header + position() + 18);
|
|
||||||
while(length) {
|
|
||||||
char buffer[256];
|
|
||||||
int packetlength = recv(serversocket, buffer, min(256, length), 0);
|
|
||||||
if(packetlength <= 0) break;
|
|
||||||
capacity += packetlength;
|
|
||||||
data = (uint8_t*)realloc(data, capacity);
|
|
||||||
memcpy(data + size, buffer, packetlength);
|
|
||||||
size += packetlength;
|
|
||||||
length -= packetlength;
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
while(true) {
|
|
||||||
char buffer[256];
|
|
||||||
int packetlength = recv(serversocket, buffer, 256, 0);
|
|
||||||
if(packetlength <= 0) break;
|
|
||||||
capacity += packetlength;
|
|
||||||
data = (uint8_t*)realloc(data, capacity);
|
|
||||||
memcpy(data + size, buffer, packetlength);
|
|
||||||
size += packetlength;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
data = (uint8_t*)realloc(data, capacity + 1);
|
|
||||||
data[capacity] = 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
inline void disconnect() {
|
|
||||||
close(serversocket);
|
|
||||||
freeaddrinfo(serverinfo);
|
|
||||||
serverinfo = nullptr;
|
|
||||||
serversocket = -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
#ifdef _WIN32
|
|
||||||
inline int close(int sock) {
|
|
||||||
return closesocket(sock);
|
|
||||||
}
|
|
||||||
|
|
||||||
inline http() {
|
|
||||||
int sock = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
|
|
||||||
if(sock == INVALID_SOCKET && WSAGetLastError() == WSANOTINITIALISED) {
|
|
||||||
WSADATA wsaData;
|
|
||||||
if(WSAStartup(MAKEWORD(2, 2), &wsaData) != 0) {
|
|
||||||
WSACleanup();
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
close(sock);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
};
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
#endif
|
|
|
@ -1,539 +0,0 @@
|
||||||
#ifndef NALL_IMAGE_HPP
|
|
||||||
#define NALL_IMAGE_HPP
|
|
||||||
|
|
||||||
#include <nall/bmp.hpp>
|
|
||||||
#include <nall/filemap.hpp>
|
|
||||||
#include <nall/interpolation.hpp>
|
|
||||||
#include <nall/png.hpp>
|
|
||||||
#include <nall/stdint.hpp>
|
|
||||||
#include <algorithm>
|
|
||||||
|
|
||||||
namespace nall {
|
|
||||||
|
|
||||||
struct image {
|
|
||||||
uint8_t *data;
|
|
||||||
unsigned width;
|
|
||||||
unsigned height;
|
|
||||||
unsigned pitch;
|
|
||||||
|
|
||||||
bool endian; //0 = little, 1 = big
|
|
||||||
unsigned depth;
|
|
||||||
unsigned stride;
|
|
||||||
|
|
||||||
struct Channel {
|
|
||||||
uint64_t mask;
|
|
||||||
unsigned depth;
|
|
||||||
unsigned shift;
|
|
||||||
|
|
||||||
inline bool operator==(const Channel &source) {
|
|
||||||
return mask == source.mask && depth == source.depth && shift == source.shift;
|
|
||||||
}
|
|
||||||
|
|
||||||
inline bool operator!=(const Channel &source) {
|
|
||||||
return !operator==(source);
|
|
||||||
}
|
|
||||||
} alpha, red, green, blue;
|
|
||||||
|
|
||||||
typedef double (*interpolation)(double, double, double, double, double);
|
|
||||||
static inline unsigned bitDepth(uint64_t color);
|
|
||||||
static inline unsigned bitShift(uint64_t color);
|
|
||||||
static inline uint64_t normalize(uint64_t color, unsigned sourceDepth, unsigned targetDepth);
|
|
||||||
|
|
||||||
inline bool operator==(const image &source);
|
|
||||||
inline bool operator!=(const image &source);
|
|
||||||
|
|
||||||
inline image& operator=(const image &source);
|
|
||||||
inline image& operator=(image &&source);
|
|
||||||
inline image(const image &source);
|
|
||||||
inline image(image &&source);
|
|
||||||
inline image(bool endian, unsigned depth, uint64_t alphaMask, uint64_t redMask, uint64_t greenMask, uint64_t blueMask);
|
|
||||||
inline image(const string &filename);
|
|
||||||
inline image(const uint8_t *data, unsigned size);
|
|
||||||
inline image();
|
|
||||||
inline ~image();
|
|
||||||
|
|
||||||
inline uint64_t read(const uint8_t *data) const;
|
|
||||||
inline void write(uint8_t *data, uint64_t value) const;
|
|
||||||
|
|
||||||
inline void free();
|
|
||||||
inline bool empty() const;
|
|
||||||
inline void allocate(unsigned width, unsigned height);
|
|
||||||
inline void clear(uint64_t color);
|
|
||||||
inline bool load(const string &filename);
|
|
||||||
//inline bool loadBMP(const uint8_t *data, unsigned size);
|
|
||||||
inline bool loadPNG(const uint8_t *data, unsigned size);
|
|
||||||
inline void scale(unsigned width, unsigned height, interpolation op);
|
|
||||||
inline void transform(bool endian, unsigned depth, uint64_t alphaMask, uint64_t redMask, uint64_t greenMask, uint64_t blueMask);
|
|
||||||
inline void alphaBlend(uint64_t alphaColor);
|
|
||||||
|
|
||||||
protected:
|
|
||||||
inline uint64_t interpolate(double mu, const uint64_t *s, interpolation op);
|
|
||||||
inline void scaleX(unsigned width, interpolation op);
|
|
||||||
inline void scaleY(unsigned height, interpolation op);
|
|
||||||
inline bool loadBMP(const string &filename);
|
|
||||||
inline bool loadPNG(const string &filename);
|
|
||||||
};
|
|
||||||
|
|
||||||
//static
|
|
||||||
|
|
||||||
unsigned image::bitDepth(uint64_t color) {
|
|
||||||
unsigned depth = 0;
|
|
||||||
if(color) while((color & 1) == 0) color >>= 1;
|
|
||||||
while((color & 1) == 1) { color >>= 1; depth++; }
|
|
||||||
return depth;
|
|
||||||
}
|
|
||||||
|
|
||||||
unsigned image::bitShift(uint64_t color) {
|
|
||||||
unsigned shift = 0;
|
|
||||||
if(color) while((color & 1) == 0) { color >>= 1; shift++; }
|
|
||||||
return shift;
|
|
||||||
}
|
|
||||||
|
|
||||||
uint64_t image::normalize(uint64_t color, unsigned sourceDepth, unsigned targetDepth) {
|
|
||||||
while(sourceDepth < targetDepth) {
|
|
||||||
color = (color << sourceDepth) | color;
|
|
||||||
sourceDepth += sourceDepth;
|
|
||||||
}
|
|
||||||
if(targetDepth < sourceDepth) color >>= (sourceDepth - targetDepth);
|
|
||||||
return color;
|
|
||||||
}
|
|
||||||
|
|
||||||
//public
|
|
||||||
|
|
||||||
bool image::operator==(const image &source) {
|
|
||||||
if(width != source.width) return false;
|
|
||||||
if(height != source.height) return false;
|
|
||||||
if(pitch != source.pitch) return false;
|
|
||||||
|
|
||||||
if(endian != source.endian) return false;
|
|
||||||
if(stride != source.stride) return false;
|
|
||||||
|
|
||||||
if(alpha != source.alpha) return false;
|
|
||||||
if(red != source.red) return false;
|
|
||||||
if(green != source.green) return false;
|
|
||||||
if(blue != source.blue) return false;
|
|
||||||
|
|
||||||
return memcmp(data, source.data, width * height * stride) == 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool image::operator!=(const image &source) {
|
|
||||||
return !operator==(source);
|
|
||||||
}
|
|
||||||
|
|
||||||
image& image::operator=(const image &source) {
|
|
||||||
free();
|
|
||||||
|
|
||||||
width = source.width;
|
|
||||||
height = source.height;
|
|
||||||
pitch = source.pitch;
|
|
||||||
|
|
||||||
endian = source.endian;
|
|
||||||
stride = source.stride;
|
|
||||||
|
|
||||||
alpha = source.alpha;
|
|
||||||
red = source.red;
|
|
||||||
green = source.green;
|
|
||||||
blue = source.blue;
|
|
||||||
|
|
||||||
data = new uint8_t[width * height * stride];
|
|
||||||
memcpy(data, source.data, width * height * stride);
|
|
||||||
return *this;
|
|
||||||
}
|
|
||||||
|
|
||||||
image& image::operator=(image &&source) {
|
|
||||||
free();
|
|
||||||
|
|
||||||
width = source.width;
|
|
||||||
height = source.height;
|
|
||||||
pitch = source.pitch;
|
|
||||||
|
|
||||||
endian = source.endian;
|
|
||||||
stride = source.stride;
|
|
||||||
|
|
||||||
alpha = source.alpha;
|
|
||||||
red = source.red;
|
|
||||||
green = source.green;
|
|
||||||
blue = source.blue;
|
|
||||||
|
|
||||||
data = source.data;
|
|
||||||
source.data = nullptr;
|
|
||||||
return *this;
|
|
||||||
}
|
|
||||||
|
|
||||||
image::image(const image &source) : data(nullptr) {
|
|
||||||
operator=(source);
|
|
||||||
}
|
|
||||||
|
|
||||||
image::image(image &&source) : data(nullptr) {
|
|
||||||
operator=(std::forward<image>(source));
|
|
||||||
}
|
|
||||||
|
|
||||||
image::image(bool endian, unsigned depth, uint64_t alphaMask, uint64_t redMask, uint64_t greenMask, uint64_t blueMask) : data(nullptr) {
|
|
||||||
width = 0, height = 0, pitch = 0;
|
|
||||||
|
|
||||||
this->endian = endian;
|
|
||||||
this->depth = depth;
|
|
||||||
this->stride = (depth / 8) + ((depth & 7) > 0);
|
|
||||||
|
|
||||||
alpha.mask = alphaMask, red.mask = redMask, green.mask = greenMask, blue.mask = blueMask;
|
|
||||||
alpha.depth = bitDepth(alpha.mask), alpha.shift = bitShift(alpha.mask);
|
|
||||||
red.depth = bitDepth(red.mask), red.shift = bitShift(red.mask);
|
|
||||||
green.depth = bitDepth(green.mask), green.shift = bitShift(green.mask);
|
|
||||||
blue.depth = bitDepth(blue.mask), blue.shift = bitShift(blue.mask);
|
|
||||||
}
|
|
||||||
|
|
||||||
image::image(const string &filename) : data(nullptr) {
|
|
||||||
width = 0, height = 0, pitch = 0;
|
|
||||||
|
|
||||||
this->endian = 0;
|
|
||||||
this->depth = 32;
|
|
||||||
this->stride = 4;
|
|
||||||
|
|
||||||
alpha.mask = 255u << 24, red.mask = 255u << 16, green.mask = 255u << 8, blue.mask = 255u << 0;
|
|
||||||
alpha.depth = bitDepth(alpha.mask), alpha.shift = bitShift(alpha.mask);
|
|
||||||
red.depth = bitDepth(red.mask), red.shift = bitShift(red.mask);
|
|
||||||
green.depth = bitDepth(green.mask), green.shift = bitShift(green.mask);
|
|
||||||
blue.depth = bitDepth(blue.mask), blue.shift = bitShift(blue.mask);
|
|
||||||
|
|
||||||
load(filename);
|
|
||||||
}
|
|
||||||
|
|
||||||
image::image(const uint8_t *data, unsigned size) : data(nullptr) {
|
|
||||||
width = 0, height = 0, pitch = 0;
|
|
||||||
|
|
||||||
this->endian = 0;
|
|
||||||
this->depth = 32;
|
|
||||||
this->stride = 4;
|
|
||||||
|
|
||||||
alpha.mask = 255u << 24, red.mask = 255u << 16, green.mask = 255u << 8, blue.mask = 255u << 0;
|
|
||||||
alpha.depth = bitDepth(alpha.mask), alpha.shift = bitShift(alpha.mask);
|
|
||||||
red.depth = bitDepth(red.mask), red.shift = bitShift(red.mask);
|
|
||||||
green.depth = bitDepth(green.mask), green.shift = bitShift(green.mask);
|
|
||||||
blue.depth = bitDepth(blue.mask), blue.shift = bitShift(blue.mask);
|
|
||||||
|
|
||||||
loadPNG(data, size);
|
|
||||||
}
|
|
||||||
|
|
||||||
image::image() : data(nullptr) {
|
|
||||||
width = 0, height = 0, pitch = 0;
|
|
||||||
|
|
||||||
this->endian = 0;
|
|
||||||
this->depth = 32;
|
|
||||||
this->stride = 4;
|
|
||||||
|
|
||||||
alpha.mask = 255u << 24, red.mask = 255u << 16, green.mask = 255u << 8, blue.mask = 255u << 0;
|
|
||||||
alpha.depth = bitDepth(alpha.mask), alpha.shift = bitShift(alpha.mask);
|
|
||||||
red.depth = bitDepth(red.mask), red.shift = bitShift(red.mask);
|
|
||||||
green.depth = bitDepth(green.mask), green.shift = bitShift(green.mask);
|
|
||||||
blue.depth = bitDepth(blue.mask), blue.shift = bitShift(blue.mask);
|
|
||||||
}
|
|
||||||
|
|
||||||
image::~image() {
|
|
||||||
free();
|
|
||||||
}
|
|
||||||
|
|
||||||
uint64_t image::read(const uint8_t *data) const {
|
|
||||||
uint64_t result = 0;
|
|
||||||
if(endian == 0) {
|
|
||||||
for(signed n = stride - 1; n >= 0; n--) result = (result << 8) | data[n];
|
|
||||||
} else {
|
|
||||||
for(signed n = 0; n < stride; n++) result = (result << 8) | data[n];
|
|
||||||
}
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
void image::write(uint8_t *data, uint64_t value) const {
|
|
||||||
if(endian == 0) {
|
|
||||||
for(signed n = 0; n < stride; n++) { data[n] = value; value >>= 8; }
|
|
||||||
} else {
|
|
||||||
for(signed n = stride - 1; n >= 0; n--) { data[n] = value; value >>= 8; }
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void image::free() {
|
|
||||||
if(data) delete[] data;
|
|
||||||
data = nullptr;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool image::empty() const {
|
|
||||||
if(data == nullptr) return true;
|
|
||||||
if(width == 0 || height == 0) return true;
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
void image::allocate(unsigned width, unsigned height) {
|
|
||||||
if(data != nullptr && this->width == width && this->height == height) return;
|
|
||||||
free();
|
|
||||||
data = new uint8_t[width * height * stride]();
|
|
||||||
pitch = width * stride;
|
|
||||||
this->width = width;
|
|
||||||
this->height = height;
|
|
||||||
}
|
|
||||||
|
|
||||||
void image::clear(uint64_t color) {
|
|
||||||
uint8_t *dp = data;
|
|
||||||
for(unsigned n = 0; n < width * height; n++) {
|
|
||||||
write(dp, color);
|
|
||||||
dp += stride;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
bool image::load(const string &filename) {
|
|
||||||
if(loadBMP(filename) == true) return true;
|
|
||||||
if(loadPNG(filename) == true) return true;
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
void image::scale(unsigned outputWidth, unsigned outputHeight, interpolation op) {
|
|
||||||
if(width != outputWidth) scaleX(outputWidth, op);
|
|
||||||
if(height != outputHeight) scaleY(outputHeight, op);
|
|
||||||
}
|
|
||||||
|
|
||||||
void image::transform(bool outputEndian, unsigned outputDepth, uint64_t outputAlphaMask, uint64_t outputRedMask, uint64_t outputGreenMask, uint64_t outputBlueMask) {
|
|
||||||
image output(outputEndian, outputDepth, outputAlphaMask, outputRedMask, outputGreenMask, outputBlueMask);
|
|
||||||
output.allocate(width, height);
|
|
||||||
|
|
||||||
#pragma omp parallel for
|
|
||||||
for(unsigned y = 0; y < height; y++) {
|
|
||||||
uint8_t *dp = output.data + output.pitch * y;
|
|
||||||
uint8_t *sp = data + pitch * y;
|
|
||||||
for(unsigned x = 0; x < width; x++) {
|
|
||||||
uint64_t color = read(sp);
|
|
||||||
sp += stride;
|
|
||||||
|
|
||||||
uint64_t a = (color & alpha.mask) >> alpha.shift;
|
|
||||||
uint64_t r = (color & red.mask) >> red.shift;
|
|
||||||
uint64_t g = (color & green.mask) >> green.shift;
|
|
||||||
uint64_t b = (color & blue.mask) >> blue.shift;
|
|
||||||
|
|
||||||
a = normalize(a, alpha.depth, output.alpha.depth);
|
|
||||||
r = normalize(r, red.depth, output.red.depth);
|
|
||||||
g = normalize(g, green.depth, output.green.depth);
|
|
||||||
b = normalize(b, blue.depth, output.blue.depth);
|
|
||||||
|
|
||||||
output.write(dp, (a << output.alpha.shift) | (r << output.red.shift) | (g << output.green.shift) | (b << output.blue.shift));
|
|
||||||
dp += output.stride;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
operator=(std::move(output));
|
|
||||||
}
|
|
||||||
|
|
||||||
void image::alphaBlend(uint64_t alphaColor) {
|
|
||||||
uint64_t alphaR = (alphaColor & red.mask) >> red.shift;
|
|
||||||
uint64_t alphaG = (alphaColor & green.mask) >> green.shift;
|
|
||||||
uint64_t alphaB = (alphaColor & blue.mask) >> blue.shift;
|
|
||||||
|
|
||||||
#pragma omp parallel for
|
|
||||||
for(unsigned y = 0; y < height; y++) {
|
|
||||||
uint8_t *dp = data + pitch * y;
|
|
||||||
for(unsigned x = 0; x < width; x++) {
|
|
||||||
uint64_t color = read(dp);
|
|
||||||
|
|
||||||
uint64_t colorA = (color & alpha.mask) >> alpha.shift;
|
|
||||||
uint64_t colorR = (color & red.mask) >> red.shift;
|
|
||||||
uint64_t colorG = (color & green.mask) >> green.shift;
|
|
||||||
uint64_t colorB = (color & blue.mask) >> blue.shift;
|
|
||||||
double alphaScale = (double)colorA / (double)((1 << alpha.depth) - 1);
|
|
||||||
|
|
||||||
colorA = (1 << alpha.depth) - 1;
|
|
||||||
colorR = (colorR * alphaScale) + (alphaR * (1.0 - alphaScale));
|
|
||||||
colorG = (colorG * alphaScale) + (alphaG * (1.0 - alphaScale));
|
|
||||||
colorB = (colorB * alphaScale) + (alphaB * (1.0 - alphaScale));
|
|
||||||
|
|
||||||
write(dp, (colorA << alpha.shift) | (colorR << red.shift) | (colorG << green.shift) | (colorB << blue.shift));
|
|
||||||
dp += stride;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
//protected
|
|
||||||
|
|
||||||
uint64_t image::interpolate(double mu, const uint64_t *s, double (*op)(double, double, double, double, double)) {
|
|
||||||
uint64_t aa = (s[0] & alpha.mask) >> alpha.shift, ar = (s[0] & red.mask) >> red.shift,
|
|
||||||
ag = (s[0] & green.mask) >> green.shift, ab = (s[0] & blue.mask) >> blue.shift;
|
|
||||||
uint64_t ba = (s[1] & alpha.mask) >> alpha.shift, br = (s[1] & red.mask) >> red.shift,
|
|
||||||
bg = (s[1] & green.mask) >> green.shift, bb = (s[1] & blue.mask) >> blue.shift;
|
|
||||||
uint64_t ca = (s[2] & alpha.mask) >> alpha.shift, cr = (s[2] & red.mask) >> red.shift,
|
|
||||||
cg = (s[2] & green.mask) >> green.shift, cb = (s[2] & blue.mask) >> blue.shift;
|
|
||||||
uint64_t da = (s[3] & alpha.mask) >> alpha.shift, dr = (s[3] & red.mask) >> red.shift,
|
|
||||||
dg = (s[3] & green.mask) >> green.shift, db = (s[3] & blue.mask) >> blue.shift;
|
|
||||||
|
|
||||||
int64_t A = op(mu, aa, ba, ca, da);
|
|
||||||
int64_t R = op(mu, ar, br, cr, dr);
|
|
||||||
int64_t G = op(mu, ag, bg, cg, dg);
|
|
||||||
int64_t B = op(mu, ab, bb, cb, db);
|
|
||||||
|
|
||||||
A = max(0, min(A, (1 << alpha.depth) - 1));
|
|
||||||
R = max(0, min(R, (1 << red.depth) - 1));
|
|
||||||
G = max(0, min(G, (1 << green.depth) - 1));
|
|
||||||
B = max(0, min(B, (1 << blue.depth) - 1));
|
|
||||||
|
|
||||||
return (A << alpha.shift) | (R << red.shift) | (G << green.shift) | (B << blue.shift);
|
|
||||||
}
|
|
||||||
|
|
||||||
void image::scaleX(unsigned outputWidth, interpolation op) {
|
|
||||||
uint8_t *outputData = new uint8_t[outputWidth * height * stride];
|
|
||||||
unsigned outputPitch = outputWidth * stride;
|
|
||||||
double step = (double)width / (double)outputWidth;
|
|
||||||
const uint8_t *terminal = data + pitch * height;
|
|
||||||
|
|
||||||
#pragma omp parallel for
|
|
||||||
for(unsigned y = 0; y < height; y++) {
|
|
||||||
uint8_t *dp = outputData + outputPitch * y;
|
|
||||||
uint8_t *sp = data + pitch * y;
|
|
||||||
|
|
||||||
double fraction = 0.0;
|
|
||||||
uint64_t s[4] = { sp < terminal ? read(sp) : 0 }; //B,C (0,1) = center of kernel { 0, 0, 1, 2 }
|
|
||||||
s[1] = s[0];
|
|
||||||
s[2] = sp + stride < terminal ? read(sp += stride) : s[1];
|
|
||||||
s[3] = sp + stride < terminal ? read(sp += stride) : s[2];
|
|
||||||
|
|
||||||
for(unsigned x = 0; x < width; x++) {
|
|
||||||
while(fraction <= 1.0) {
|
|
||||||
if(dp >= outputData + outputPitch * height) break;
|
|
||||||
write(dp, interpolate(fraction, (const uint64_t*)&s, op));
|
|
||||||
dp += stride;
|
|
||||||
fraction += step;
|
|
||||||
}
|
|
||||||
|
|
||||||
s[0] = s[1]; s[1] = s[2]; s[2] = s[3];
|
|
||||||
if(sp + stride < terminal) s[3] = read(sp += stride);
|
|
||||||
fraction -= 1.0;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
free();
|
|
||||||
data = outputData;
|
|
||||||
width = outputWidth;
|
|
||||||
pitch = width * stride;
|
|
||||||
}
|
|
||||||
|
|
||||||
void image::scaleY(unsigned outputHeight, interpolation op) {
|
|
||||||
uint8_t *outputData = new uint8_t[width * outputHeight * stride];
|
|
||||||
double step = (double)height / (double)outputHeight;
|
|
||||||
const uint8_t *terminal = data + pitch * height;
|
|
||||||
|
|
||||||
#pragma omp parallel for
|
|
||||||
for(unsigned x = 0; x < width; x++) {
|
|
||||||
uint8_t *dp = outputData + stride * x;
|
|
||||||
uint8_t *sp = data + stride * x;
|
|
||||||
|
|
||||||
double fraction = 0.0;
|
|
||||||
uint64_t s[4] = { sp < terminal ? read(sp) : 0 };
|
|
||||||
s[1] = s[0];
|
|
||||||
s[2] = sp + pitch < terminal ? read(sp += pitch) : s[1];
|
|
||||||
s[3] = sp + pitch < terminal ? read(sp += pitch) : s[2];
|
|
||||||
|
|
||||||
for(unsigned y = 0; y < height; y++) {
|
|
||||||
while(fraction <= 1.0) {
|
|
||||||
if(dp >= outputData + pitch * outputHeight) break;
|
|
||||||
write(dp, interpolate(fraction, (const uint64_t*)&s, op));
|
|
||||||
dp += pitch;
|
|
||||||
fraction += step;
|
|
||||||
}
|
|
||||||
|
|
||||||
s[0] = s[1]; s[1] = s[2]; s[2] = s[3];
|
|
||||||
if(sp + pitch < terminal) s[3] = read(sp += pitch);
|
|
||||||
fraction -= 1.0;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
free();
|
|
||||||
data = outputData;
|
|
||||||
height = outputHeight;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool image::loadBMP(const string &filename) {
|
|
||||||
uint32_t *outputData;
|
|
||||||
unsigned outputWidth, outputHeight;
|
|
||||||
if(bmp::read(filename, outputData, outputWidth, outputHeight) == false) return false;
|
|
||||||
|
|
||||||
allocate(outputWidth, outputHeight);
|
|
||||||
const uint32_t *sp = outputData;
|
|
||||||
uint8_t *dp = data;
|
|
||||||
|
|
||||||
for(unsigned y = 0; y < outputHeight; y++) {
|
|
||||||
for(unsigned x = 0; x < outputWidth; 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);
|
|
||||||
uint64_t g = normalize((uint8_t)(color >> 8), 8, green.depth);
|
|
||||||
uint64_t b = normalize((uint8_t)(color >> 0), 8, blue.depth);
|
|
||||||
write(dp, (a << alpha.shift) | (r << red.shift) | (g << green.shift) | (b << blue.shift));
|
|
||||||
dp += stride;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
delete[] outputData;
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool image::loadPNG(const uint8_t *pngData, unsigned pngSize) {
|
|
||||||
png source;
|
|
||||||
if(source.decode(pngData, pngSize) == false) return false;
|
|
||||||
|
|
||||||
allocate(source.info.width, source.info.height);
|
|
||||||
const uint8_t *sp = source.data;
|
|
||||||
uint8_t *dp = data;
|
|
||||||
|
|
||||||
auto decode = [&]() -> uint64_t {
|
|
||||||
uint64_t p, r, g, b, a;
|
|
||||||
|
|
||||||
switch(source.info.colorType) {
|
|
||||||
case 0: //L
|
|
||||||
r = g = b = source.readbits(sp);
|
|
||||||
a = (1 << source.info.bitDepth) - 1;
|
|
||||||
break;
|
|
||||||
case 2: //R,G,B
|
|
||||||
r = source.readbits(sp);
|
|
||||||
g = source.readbits(sp);
|
|
||||||
b = source.readbits(sp);
|
|
||||||
a = (1 << source.info.bitDepth) - 1;
|
|
||||||
break;
|
|
||||||
case 3: //P
|
|
||||||
p = source.readbits(sp);
|
|
||||||
r = source.info.palette[p][0];
|
|
||||||
g = source.info.palette[p][1];
|
|
||||||
b = source.info.palette[p][2];
|
|
||||||
a = (1 << source.info.bitDepth) - 1;
|
|
||||||
break;
|
|
||||||
case 4: //L,A
|
|
||||||
r = g = b = source.readbits(sp);
|
|
||||||
a = source.readbits(sp);
|
|
||||||
break;
|
|
||||||
case 6: //R,G,B,A
|
|
||||||
r = source.readbits(sp);
|
|
||||||
g = source.readbits(sp);
|
|
||||||
b = source.readbits(sp);
|
|
||||||
a = source.readbits(sp);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
a = normalize(a, source.info.bitDepth, alpha.depth);
|
|
||||||
r = normalize(r, source.info.bitDepth, red.depth);
|
|
||||||
g = normalize(g, source.info.bitDepth, green.depth);
|
|
||||||
b = normalize(b, source.info.bitDepth, blue.depth);
|
|
||||||
|
|
||||||
return (a << alpha.shift) | (r << red.shift) | (g << green.shift) | (b << blue.shift);
|
|
||||||
};
|
|
||||||
|
|
||||||
for(unsigned y = 0; y < height; y++) {
|
|
||||||
for(unsigned x = 0; x < width; x++) {
|
|
||||||
write(dp, decode());
|
|
||||||
dp += stride;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool image::loadPNG(const string &filename) {
|
|
||||||
filemap map;
|
|
||||||
if(map.open(filename, filemap::mode::read) == false) return false;
|
|
||||||
return loadPNG(map.data(), map.size());
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
#endif
|
|
|
@ -1,358 +0,0 @@
|
||||||
#ifndef NALL_INFLATE_HPP
|
|
||||||
#define NALL_INFLATE_HPP
|
|
||||||
|
|
||||||
#include <setjmp.h>
|
|
||||||
|
|
||||||
namespace nall {
|
|
||||||
|
|
||||||
namespace puff {
|
|
||||||
inline int puff(
|
|
||||||
unsigned char *dest, unsigned long *destlen,
|
|
||||||
unsigned char *source, unsigned long *sourcelen
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
inline bool inflate(
|
|
||||||
uint8_t *target, unsigned targetLength,
|
|
||||||
const uint8_t *source, unsigned sourceLength
|
|
||||||
) {
|
|
||||||
unsigned long tl = targetLength, sl = sourceLength;
|
|
||||||
int result = puff::puff((unsigned char*)target, &tl, (unsigned char*)source, &sl);
|
|
||||||
return result == 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
namespace puff {
|
|
||||||
|
|
||||||
//zlib/contrib/puff.c
|
|
||||||
//version 2.1*
|
|
||||||
//author: Mark Adler
|
|
||||||
//license: zlib
|
|
||||||
//ported by: byuu
|
|
||||||
|
|
||||||
//* I have corrected a bug in fixed(), where it was accessing uninitialized
|
|
||||||
// memory: calling construct() with lencode prior to initializing lencode.count
|
|
||||||
|
|
||||||
enum {
|
|
||||||
MAXBITS = 15,
|
|
||||||
MAXLCODES = 286,
|
|
||||||
MAXDCODES = 30,
|
|
||||||
FIXLCODES = 288,
|
|
||||||
MAXCODES = MAXLCODES + MAXDCODES,
|
|
||||||
};
|
|
||||||
|
|
||||||
struct state {
|
|
||||||
unsigned char *out;
|
|
||||||
unsigned long outlen;
|
|
||||||
unsigned long outcnt;
|
|
||||||
|
|
||||||
unsigned char *in;
|
|
||||||
unsigned long inlen;
|
|
||||||
unsigned long incnt;
|
|
||||||
int bitbuf;
|
|
||||||
int bitcnt;
|
|
||||||
|
|
||||||
jmp_buf env;
|
|
||||||
};
|
|
||||||
|
|
||||||
struct huffman {
|
|
||||||
short *count;
|
|
||||||
short *symbol;
|
|
||||||
};
|
|
||||||
|
|
||||||
inline int bits(state *s, int need) {
|
|
||||||
long val;
|
|
||||||
|
|
||||||
val = s->bitbuf;
|
|
||||||
while(s->bitcnt < need) {
|
|
||||||
if(s->incnt == s->inlen) longjmp(s->env, 1);
|
|
||||||
val |= (long)(s->in[s->incnt++]) << s->bitcnt;
|
|
||||||
s->bitcnt += 8;
|
|
||||||
}
|
|
||||||
|
|
||||||
s->bitbuf = (int)(val >> need);
|
|
||||||
s->bitcnt -= need;
|
|
||||||
|
|
||||||
return (int)(val & ((1L << need) - 1));
|
|
||||||
}
|
|
||||||
|
|
||||||
inline int stored(state *s) {
|
|
||||||
unsigned len;
|
|
||||||
|
|
||||||
s->bitbuf = 0;
|
|
||||||
s->bitcnt = 0;
|
|
||||||
|
|
||||||
if(s->incnt + 4 > s->inlen) return 2;
|
|
||||||
len = s->in[s->incnt++];
|
|
||||||
len |= s->in[s->incnt++] << 8;
|
|
||||||
if(s->in[s->incnt++] != (~len & 0xff) ||
|
|
||||||
s->in[s->incnt++] != ((~len >> 8) & 0xff)
|
|
||||||
) return 2;
|
|
||||||
|
|
||||||
if(s->incnt + len > s->inlen) return 2;
|
|
||||||
if(s->out != nullptr) {
|
|
||||||
if(s->outcnt + len > s->outlen) return 1;
|
|
||||||
while(len--) s->out[s->outcnt++] = s->in[s->incnt++];
|
|
||||||
} else {
|
|
||||||
s->outcnt += len;
|
|
||||||
s->incnt += len;
|
|
||||||
}
|
|
||||||
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
inline int decode(state *s, huffman *h) {
|
|
||||||
int len, code, first, count, index, bitbuf, left;
|
|
||||||
short *next;
|
|
||||||
|
|
||||||
bitbuf = s->bitbuf;
|
|
||||||
left = s->bitcnt;
|
|
||||||
code = first = index = 0;
|
|
||||||
len = 1;
|
|
||||||
next = h->count + 1;
|
|
||||||
while(true) {
|
|
||||||
while(left--) {
|
|
||||||
code |= bitbuf & 1;
|
|
||||||
bitbuf >>= 1;
|
|
||||||
count = *next++;
|
|
||||||
if(code - count < first) {
|
|
||||||
s->bitbuf = bitbuf;
|
|
||||||
s->bitcnt = (s->bitcnt - len) & 7;
|
|
||||||
return h->symbol[index + (code - first)];
|
|
||||||
}
|
|
||||||
index += count;
|
|
||||||
first += count;
|
|
||||||
first <<= 1;
|
|
||||||
code <<= 1;
|
|
||||||
len++;
|
|
||||||
}
|
|
||||||
left = (MAXBITS + 1) - len;
|
|
||||||
if(left == 0) break;
|
|
||||||
if(s->incnt == s->inlen) longjmp(s->env, 1);
|
|
||||||
bitbuf = s->in[s->incnt++];
|
|
||||||
if(left > 8) left = 8;
|
|
||||||
}
|
|
||||||
|
|
||||||
return -10;
|
|
||||||
}
|
|
||||||
|
|
||||||
inline int construct(huffman *h, short *length, int n) {
|
|
||||||
int symbol, len, left;
|
|
||||||
short offs[MAXBITS + 1];
|
|
||||||
|
|
||||||
for(len = 0; len <= MAXBITS; len++) h->count[len] = 0;
|
|
||||||
for(symbol = 0; symbol < n; symbol++) h->count[length[symbol]]++;
|
|
||||||
if(h->count[0] == n) return 0;
|
|
||||||
|
|
||||||
left = 1;
|
|
||||||
for(len = 1; len <= MAXBITS; len++) {
|
|
||||||
left <<= 1;
|
|
||||||
left -= h->count[len];
|
|
||||||
if(left < 0) return left;
|
|
||||||
}
|
|
||||||
|
|
||||||
offs[1] = 0;
|
|
||||||
for(len = 1; len < MAXBITS; len++) offs[len + 1] = offs[len] + h->count[len];
|
|
||||||
|
|
||||||
for(symbol = 0; symbol < n; symbol++) {
|
|
||||||
if(length[symbol] != 0) h->symbol[offs[length[symbol]]++] = symbol;
|
|
||||||
}
|
|
||||||
|
|
||||||
return left;
|
|
||||||
}
|
|
||||||
|
|
||||||
inline int codes(state *s, huffman *lencode, huffman *distcode) {
|
|
||||||
int symbol, len;
|
|
||||||
unsigned dist;
|
|
||||||
static const short lens[29] = {
|
|
||||||
3, 4, 5, 6, 7, 8, 9, 10, 11, 13, 15, 17, 19, 23, 27, 31,
|
|
||||||
35, 43, 51, 59, 67, 83, 99, 115, 131, 163, 195, 227, 258
|
|
||||||
};
|
|
||||||
static const short lext[29] = {
|
|
||||||
0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 2, 2, 2, 2,
|
|
||||||
3, 3, 3, 3, 4, 4, 4, 4, 5, 5, 5, 5, 0
|
|
||||||
};
|
|
||||||
static const short dists[30] = {
|
|
||||||
1, 2, 3, 4, 5, 7, 9, 13, 17, 25, 33, 49, 65, 97, 129, 193,
|
|
||||||
257, 385, 513, 769, 1025, 1537, 2049, 3073, 4097, 6145,
|
|
||||||
8193, 12289, 16385, 24577
|
|
||||||
};
|
|
||||||
static const short dext[30] = {
|
|
||||||
0, 0, 0, 0, 1, 1, 2, 2, 3, 3, 4, 4, 5, 5, 6, 6,
|
|
||||||
7, 7, 8, 8, 9, 9, 10, 10, 11, 11,
|
|
||||||
12, 12, 13, 13
|
|
||||||
};
|
|
||||||
|
|
||||||
do {
|
|
||||||
symbol = decode(s, lencode);
|
|
||||||
if(symbol < 0) return symbol;
|
|
||||||
if(symbol < 256) {
|
|
||||||
if(s->out != nullptr) {
|
|
||||||
if(s->outcnt == s->outlen) return 1;
|
|
||||||
s->out[s->outcnt] = symbol;
|
|
||||||
}
|
|
||||||
s->outcnt++;
|
|
||||||
} else if(symbol > 256) {
|
|
||||||
symbol -= 257;
|
|
||||||
if(symbol >= 29) return -10;
|
|
||||||
len = lens[symbol] + bits(s, lext[symbol]);
|
|
||||||
|
|
||||||
symbol = decode(s, distcode);
|
|
||||||
if(symbol < 0) return symbol;
|
|
||||||
dist = dists[symbol] + bits(s, dext[symbol]);
|
|
||||||
#ifndef INFLATE_ALLOW_INVALID_DISTANCE_TOO_FAR
|
|
||||||
if(dist > s->outcnt) return -11;
|
|
||||||
#endif
|
|
||||||
|
|
||||||
if(s->out != nullptr) {
|
|
||||||
if(s->outcnt + len > s->outlen) return 1;
|
|
||||||
while(len--) {
|
|
||||||
s->out[s->outcnt] =
|
|
||||||
#ifdef INFLATE_ALLOW_INVALID_DISTANCE_TOO_FAR
|
|
||||||
dist > s->outcnt ? 0 :
|
|
||||||
#endif
|
|
||||||
s->out[s->outcnt - dist];
|
|
||||||
s->outcnt++;
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
s->outcnt += len;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} while(symbol != 256);
|
|
||||||
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
inline int fixed(state *s) {
|
|
||||||
static int virgin = 1;
|
|
||||||
static short lencnt[MAXBITS + 1], lensym[FIXLCODES];
|
|
||||||
static short distcnt[MAXBITS + 1], distsym[MAXDCODES];
|
|
||||||
static huffman lencode, distcode;
|
|
||||||
|
|
||||||
if(virgin) {
|
|
||||||
int symbol = 0;
|
|
||||||
short lengths[FIXLCODES];
|
|
||||||
|
|
||||||
lencode.count = lencnt;
|
|
||||||
lencode.symbol = lensym;
|
|
||||||
distcode.count = distcnt;
|
|
||||||
distcode.symbol = distsym;
|
|
||||||
|
|
||||||
for(; symbol < 144; symbol++) lengths[symbol] = 8;
|
|
||||||
for(; symbol < 256; symbol++) lengths[symbol] = 9;
|
|
||||||
for(; symbol < 280; symbol++) lengths[symbol] = 7;
|
|
||||||
for(; symbol < FIXLCODES; symbol++) lengths[symbol] = 8;
|
|
||||||
construct(&lencode, lengths, FIXLCODES);
|
|
||||||
|
|
||||||
for(symbol = 0; symbol < MAXDCODES; symbol++) lengths[symbol] = 5;
|
|
||||||
construct(&distcode, lengths, MAXDCODES);
|
|
||||||
|
|
||||||
virgin = 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
return codes(s, &lencode, &distcode);
|
|
||||||
}
|
|
||||||
|
|
||||||
inline int dynamic(state *s) {
|
|
||||||
int nlen, ndist, ncode, index, err;
|
|
||||||
short lengths[MAXCODES];
|
|
||||||
short lencnt[MAXBITS + 1], lensym[MAXLCODES];
|
|
||||||
short distcnt[MAXBITS + 1], distsym[MAXDCODES];
|
|
||||||
huffman lencode, distcode;
|
|
||||||
static const short order[19] = {
|
|
||||||
16, 17, 18, 0, 8, 7, 9, 6, 10, 5, 11, 4, 12, 3, 13, 2, 14, 1, 15
|
|
||||||
};
|
|
||||||
|
|
||||||
lencode.count = lencnt;
|
|
||||||
lencode.symbol = lensym;
|
|
||||||
distcode.count = distcnt;
|
|
||||||
distcode.symbol = distsym;
|
|
||||||
|
|
||||||
nlen = bits(s, 5) + 257;
|
|
||||||
ndist = bits(s, 5) + 1;
|
|
||||||
ncode = bits(s, 4) + 4;
|
|
||||||
if(nlen > MAXLCODES || ndist > MAXDCODES) return -3;
|
|
||||||
|
|
||||||
for(index = 0; index < ncode; index++) lengths[order[index]] = bits(s, 3);
|
|
||||||
for(; index < 19; index++) lengths[order[index]] = 0;
|
|
||||||
|
|
||||||
err = construct(&lencode, lengths, 19);
|
|
||||||
if(err != 0) return -4;
|
|
||||||
|
|
||||||
index = 0;
|
|
||||||
while(index < nlen + ndist) {
|
|
||||||
int symbol, len;
|
|
||||||
|
|
||||||
symbol = decode(s, &lencode);
|
|
||||||
if(symbol < 16) {
|
|
||||||
lengths[index++] = symbol;
|
|
||||||
} else {
|
|
||||||
len = 0;
|
|
||||||
if(symbol == 16) {
|
|
||||||
if(index == 0) return -5;
|
|
||||||
len = lengths[index - 1];
|
|
||||||
symbol = 3 + bits(s, 2);
|
|
||||||
} else if(symbol == 17) {
|
|
||||||
symbol = 3 + bits(s, 3);
|
|
||||||
} else {
|
|
||||||
symbol = 11 + bits(s, 7);
|
|
||||||
}
|
|
||||||
if(index + symbol > nlen + ndist) return -6;
|
|
||||||
while(symbol--) lengths[index++] = len;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if(lengths[256] == 0) return -9;
|
|
||||||
|
|
||||||
err = construct(&lencode, lengths, nlen);
|
|
||||||
if(err < 0 || (err > 0 && nlen - lencode.count[0] != 1)) return -7;
|
|
||||||
|
|
||||||
err = construct(&distcode, lengths + nlen, ndist);
|
|
||||||
if(err < 0 || (err > 0 && ndist - distcode.count[0] != 1)) return -8;
|
|
||||||
|
|
||||||
return codes(s, &lencode, &distcode);
|
|
||||||
}
|
|
||||||
|
|
||||||
inline int puff(
|
|
||||||
unsigned char *dest, unsigned long *destlen,
|
|
||||||
unsigned char *source, unsigned long *sourcelen
|
|
||||||
) {
|
|
||||||
state s;
|
|
||||||
int last, type, err;
|
|
||||||
|
|
||||||
s.out = dest;
|
|
||||||
s.outlen = *destlen;
|
|
||||||
s.outcnt = 0;
|
|
||||||
|
|
||||||
s.in = source;
|
|
||||||
s.inlen = *sourcelen;
|
|
||||||
s.incnt = 0;
|
|
||||||
s.bitbuf = 0;
|
|
||||||
s.bitcnt = 0;
|
|
||||||
|
|
||||||
if(setjmp(s.env) != 0) {
|
|
||||||
err = 2;
|
|
||||||
} else {
|
|
||||||
do {
|
|
||||||
last = bits(&s, 1);
|
|
||||||
type = bits(&s, 2);
|
|
||||||
err = type == 0 ? stored(&s)
|
|
||||||
: type == 1 ? fixed(&s)
|
|
||||||
: type == 2 ? dynamic(&s)
|
|
||||||
: -1;
|
|
||||||
if(err != 0) break;
|
|
||||||
} while(!last);
|
|
||||||
}
|
|
||||||
|
|
||||||
if(err <= 0) {
|
|
||||||
*destlen = s.outcnt;
|
|
||||||
*sourcelen = s.incnt;
|
|
||||||
}
|
|
||||||
|
|
||||||
return err;
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
#endif
|
|
|
@ -1,386 +0,0 @@
|
||||||
#ifndef NALL_INPUT_HPP
|
|
||||||
#define NALL_INPUT_HPP
|
|
||||||
|
|
||||||
#include <stdio.h>
|
|
||||||
#include <stdlib.h>
|
|
||||||
#include <string.h>
|
|
||||||
|
|
||||||
#include <nall/stdint.hpp>
|
|
||||||
#include <nall/string.hpp>
|
|
||||||
|
|
||||||
namespace nall {
|
|
||||||
|
|
||||||
struct Keyboard;
|
|
||||||
Keyboard& keyboard(unsigned = 0);
|
|
||||||
|
|
||||||
static const char KeyboardScancodeName[][64] = {
|
|
||||||
"Escape", "F1", "F2", "F3", "F4", "F5", "F6", "F7", "F8", "F9", "F10", "F11", "F12",
|
|
||||||
"PrintScreen", "ScrollLock", "Pause", "Tilde",
|
|
||||||
"Num1", "Num2", "Num3", "Num4", "Num5", "Num6", "Num7", "Num8", "Num9", "Num0",
|
|
||||||
"Dash", "Equal", "Backspace",
|
|
||||||
"Insert", "Delete", "Home", "End", "PageUp", "PageDown",
|
|
||||||
"A", "B", "C", "D", "E", "F", "G", "H", "I", "J", "K", "L", "M",
|
|
||||||
"N", "O", "P", "Q", "R", "S", "T", "U", "V", "W", "X", "Y", "Z",
|
|
||||||
"LeftBracket", "RightBracket", "Backslash", "Semicolon", "Apostrophe", "Comma", "Period", "Slash",
|
|
||||||
"Keypad1", "Keypad2", "Keypad3", "Keypad4", "Keypad5", "Keypad6", "Keypad7", "Keypad8", "Keypad9", "Keypad0",
|
|
||||||
"Point", "Enter", "Add", "Subtract", "Multiply", "Divide",
|
|
||||||
"NumLock", "CapsLock",
|
|
||||||
"Up", "Down", "Left", "Right",
|
|
||||||
"Tab", "Return", "Spacebar", "Menu",
|
|
||||||
"Shift", "Control", "Alt", "Super",
|
|
||||||
};
|
|
||||||
|
|
||||||
struct Keyboard {
|
|
||||||
const unsigned ID;
|
|
||||||
enum { Base = 1 };
|
|
||||||
enum { Count = 8, Size = 128 };
|
|
||||||
|
|
||||||
enum Scancode {
|
|
||||||
Escape, F1, F2, F3, F4, F5, F6, F7, F8, F9, F10, F11, F12,
|
|
||||||
PrintScreen, ScrollLock, Pause, Tilde,
|
|
||||||
Num1, Num2, Num3, Num4, Num5, Num6, Num7, Num8, Num9, Num0,
|
|
||||||
Dash, Equal, Backspace,
|
|
||||||
Insert, Delete, Home, End, PageUp, PageDown,
|
|
||||||
A, B, C, D, E, F, G, H, I, J, K, L, M,
|
|
||||||
N, O, P, Q, R, S, T, U, V, W, X, Y, Z,
|
|
||||||
LeftBracket, RightBracket, Backslash, Semicolon, Apostrophe, Comma, Period, Slash,
|
|
||||||
Keypad1, Keypad2, Keypad3, Keypad4, Keypad5, Keypad6, Keypad7, Keypad8, Keypad9, Keypad0,
|
|
||||||
Point, Enter, Add, Subtract, Multiply, Divide,
|
|
||||||
NumLock, CapsLock,
|
|
||||||
Up, Down, Left, Right,
|
|
||||||
Tab, Return, Spacebar, Menu,
|
|
||||||
Shift, Control, Alt, Super,
|
|
||||||
Limit,
|
|
||||||
};
|
|
||||||
|
|
||||||
static signed numberDecode(uint16_t scancode) {
|
|
||||||
for(unsigned i = 0; i < Count; i++) {
|
|
||||||
if(keyboard(i).belongsTo(scancode)) return i;
|
|
||||||
}
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
static signed keyDecode(uint16_t scancode) {
|
|
||||||
for(unsigned i = 0; i < Count; i++) {
|
|
||||||
if(keyboard(i).isKey(scancode)) return scancode - keyboard(i).key(Escape);
|
|
||||||
}
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
static signed modifierDecode(uint16_t scancode) {
|
|
||||||
for(unsigned i = 0; i < Count; i++) {
|
|
||||||
if(keyboard(i).isModifier(scancode)) return scancode - keyboard(i).key(Shift);
|
|
||||||
}
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
static bool isAnyKey(uint16_t scancode) {
|
|
||||||
for(unsigned i = 0; i < Count; i++) {
|
|
||||||
if(keyboard(i).isKey(scancode)) return true;
|
|
||||||
}
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
static bool isAnyModifier(uint16_t scancode) {
|
|
||||||
for(unsigned i = 0; i < Count; i++) {
|
|
||||||
if(keyboard(i).isModifier(scancode)) return true;
|
|
||||||
}
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
static uint16_t decode(const char *name) {
|
|
||||||
string s(name);
|
|
||||||
if(!strbegin(name, "KB")) return 0;
|
|
||||||
s.ltrim("KB");
|
|
||||||
unsigned id = decimal(s);
|
|
||||||
auto pos = strpos(s, "::");
|
|
||||||
if(!pos) return 0;
|
|
||||||
s = substr(s, pos() + 2);
|
|
||||||
for(unsigned i = 0; i < Limit; i++) {
|
|
||||||
if(s == KeyboardScancodeName[i]) return Base + Size * id + i;
|
|
||||||
}
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
string encode(uint16_t code) const {
|
|
||||||
unsigned index = 0;
|
|
||||||
for(unsigned i = 0; i < Count; i++) {
|
|
||||||
if(code >= Base + Size * i && code < Base + Size * (i + 1)) {
|
|
||||||
index = code - (Base + Size * i);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return { "KB", ID, "::", KeyboardScancodeName[index] };
|
|
||||||
}
|
|
||||||
|
|
||||||
uint16_t operator[](Scancode code) const { return Base + ID * Size + code; }
|
|
||||||
uint16_t key(unsigned id) const { return Base + Size * ID + id; }
|
|
||||||
bool isKey(unsigned id) const { return id >= key(Escape) && id <= key(Menu); }
|
|
||||||
bool isModifier(unsigned id) const { return id >= key(Shift) && id <= key(Super); }
|
|
||||||
bool belongsTo(uint16_t scancode) const { return isKey(scancode) || isModifier(scancode); }
|
|
||||||
|
|
||||||
Keyboard(unsigned ID_) : ID(ID_) {}
|
|
||||||
};
|
|
||||||
|
|
||||||
inline Keyboard& keyboard(unsigned id) {
|
|
||||||
static Keyboard kb0(0), kb1(1), kb2(2), kb3(3), kb4(4), kb5(5), kb6(6), kb7(7);
|
|
||||||
switch(id) { default:
|
|
||||||
case 0: return kb0; case 1: return kb1; case 2: return kb2; case 3: return kb3;
|
|
||||||
case 4: return kb4; case 5: return kb5; case 6: return kb6; case 7: return kb7;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
static const char MouseScancodeName[][64] = {
|
|
||||||
"Xaxis", "Yaxis", "Zaxis",
|
|
||||||
"Button0", "Button1", "Button2", "Button3", "Button4", "Button5", "Button6", "Button7",
|
|
||||||
};
|
|
||||||
|
|
||||||
struct Mouse;
|
|
||||||
Mouse& mouse(unsigned = 0);
|
|
||||||
|
|
||||||
struct Mouse {
|
|
||||||
const unsigned ID;
|
|
||||||
enum { Base = Keyboard::Base + Keyboard::Size * Keyboard::Count };
|
|
||||||
enum { Count = 8, Size = 16 };
|
|
||||||
enum { Axes = 3, Buttons = 8 };
|
|
||||||
|
|
||||||
enum Scancode {
|
|
||||||
Xaxis, Yaxis, Zaxis,
|
|
||||||
Button0, Button1, Button2, Button3, Button4, Button5, Button6, Button7,
|
|
||||||
Limit,
|
|
||||||
};
|
|
||||||
|
|
||||||
static signed numberDecode(uint16_t scancode) {
|
|
||||||
for(unsigned i = 0; i < Count; i++) {
|
|
||||||
if(mouse(i).belongsTo(scancode)) return i;
|
|
||||||
}
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
static signed axisDecode(uint16_t scancode) {
|
|
||||||
for(unsigned i = 0; i < Count; i++) {
|
|
||||||
if(mouse(i).isAxis(scancode)) return scancode - mouse(i).axis(0);
|
|
||||||
}
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
static signed buttonDecode(uint16_t scancode) {
|
|
||||||
for(unsigned i = 0; i < Count; i++) {
|
|
||||||
if(mouse(i).isButton(scancode)) return scancode - mouse(i).button(0);
|
|
||||||
}
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
static bool isAnyAxis(uint16_t scancode) {
|
|
||||||
for(unsigned i = 0; i < Count; i++) {
|
|
||||||
if(mouse(i).isAxis(scancode)) return true;
|
|
||||||
}
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
static bool isAnyButton(uint16_t scancode) {
|
|
||||||
for(unsigned i = 0; i < Count; i++) {
|
|
||||||
if(mouse(i).isButton(scancode)) return true;
|
|
||||||
}
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
static uint16_t decode(const char *name) {
|
|
||||||
string s(name);
|
|
||||||
if(!strbegin(name, "MS")) return 0;
|
|
||||||
s.ltrim("MS");
|
|
||||||
unsigned id = decimal(s);
|
|
||||||
auto pos = strpos(s, "::");
|
|
||||||
if(!pos) return 0;
|
|
||||||
s = substr(s, pos() + 2);
|
|
||||||
for(unsigned i = 0; i < Limit; i++) {
|
|
||||||
if(s == MouseScancodeName[i]) return Base + Size * id + i;
|
|
||||||
}
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
string encode(uint16_t code) const {
|
|
||||||
unsigned index = 0;
|
|
||||||
for(unsigned i = 0; i < Count; i++) {
|
|
||||||
if(code >= Base + Size * i && code < Base + Size * (i + 1)) {
|
|
||||||
index = code - (Base + Size * i);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return { "MS", ID, "::", MouseScancodeName[index] };
|
|
||||||
}
|
|
||||||
|
|
||||||
uint16_t operator[](Scancode code) const { return Base + ID * Size + code; }
|
|
||||||
uint16_t axis(unsigned id) const { return Base + Size * ID + Xaxis + id; }
|
|
||||||
uint16_t button(unsigned id) const { return Base + Size * ID + Button0 + id; }
|
|
||||||
bool isAxis(unsigned id) const { return id >= axis(0) && id <= axis(2); }
|
|
||||||
bool isButton(unsigned id) const { return id >= button(0) && id <= button(7); }
|
|
||||||
bool belongsTo(uint16_t scancode) const { return isAxis(scancode) || isButton(scancode); }
|
|
||||||
|
|
||||||
Mouse(unsigned ID_) : ID(ID_) {}
|
|
||||||
};
|
|
||||||
|
|
||||||
inline Mouse& mouse(unsigned id) {
|
|
||||||
static Mouse ms0(0), ms1(1), ms2(2), ms3(3), ms4(4), ms5(5), ms6(6), ms7(7);
|
|
||||||
switch(id) { default:
|
|
||||||
case 0: return ms0; case 1: return ms1; case 2: return ms2; case 3: return ms3;
|
|
||||||
case 4: return ms4; case 5: return ms5; case 6: return ms6; case 7: return ms7;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
static const char JoypadScancodeName[][64] = {
|
|
||||||
"Hat0", "Hat1", "Hat2", "Hat3", "Hat4", "Hat5", "Hat6", "Hat7",
|
|
||||||
"Axis0", "Axis1", "Axis2", "Axis3", "Axis4", "Axis5", "Axis6", "Axis7",
|
|
||||||
"Axis8", "Axis9", "Axis10", "Axis11", "Axis12", "Axis13", "Axis14", "Axis15",
|
|
||||||
"Button0", "Button1", "Button2", "Button3", "Button4", "Button5", "Button6", "Button7",
|
|
||||||
"Button8", "Button9", "Button10", "Button11", "Button12", "Button13", "Button14", "Button15",
|
|
||||||
"Button16", "Button17", "Button18", "Button19", "Button20", "Button21", "Button22", "Button23",
|
|
||||||
"Button24", "Button25", "Button26", "Button27", "Button28", "Button29", "Button30", "Button31",
|
|
||||||
};
|
|
||||||
|
|
||||||
struct Joypad;
|
|
||||||
Joypad& joypad(unsigned = 0);
|
|
||||||
|
|
||||||
struct Joypad {
|
|
||||||
const unsigned ID;
|
|
||||||
enum { Base = Mouse::Base + Mouse::Size * Mouse::Count };
|
|
||||||
enum { Count = 8, Size = 64 };
|
|
||||||
enum { Hats = 8, Axes = 16, Buttons = 32 };
|
|
||||||
|
|
||||||
enum Scancode {
|
|
||||||
Hat0, Hat1, Hat2, Hat3, Hat4, Hat5, Hat6, Hat7,
|
|
||||||
Axis0, Axis1, Axis2, Axis3, Axis4, Axis5, Axis6, Axis7,
|
|
||||||
Axis8, Axis9, Axis10, Axis11, Axis12, Axis13, Axis14, Axis15,
|
|
||||||
Button0, Button1, Button2, Button3, Button4, Button5, Button6, Button7,
|
|
||||||
Button8, Button9, Button10, Button11, Button12, Button13, Button14, Button15,
|
|
||||||
Button16, Button17, Button18, Button19, Button20, Button21, Button22, Button23,
|
|
||||||
Button24, Button25, Button26, Button27, Button28, Button29, Button30, Button31,
|
|
||||||
Limit,
|
|
||||||
};
|
|
||||||
|
|
||||||
enum Hat { HatCenter = 0, HatUp = 1, HatRight = 2, HatDown = 4, HatLeft = 8 };
|
|
||||||
|
|
||||||
static signed numberDecode(uint16_t scancode) {
|
|
||||||
for(unsigned i = 0; i < Count; i++) {
|
|
||||||
if(joypad(i).belongsTo(scancode)) return i;
|
|
||||||
}
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
static signed hatDecode(uint16_t scancode) {
|
|
||||||
for(unsigned i = 0; i < Count; i++) {
|
|
||||||
if(joypad(i).isHat(scancode)) return scancode - joypad(i).hat(0);
|
|
||||||
}
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
static signed axisDecode(uint16_t scancode) {
|
|
||||||
for(unsigned i = 0; i < Count; i++) {
|
|
||||||
if(joypad(i).isAxis(scancode)) return scancode - joypad(i).axis(0);
|
|
||||||
}
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
static signed buttonDecode(uint16_t scancode) {
|
|
||||||
for(unsigned i = 0; i < Count; i++) {
|
|
||||||
if(joypad(i).isButton(scancode)) return scancode - joypad(i).button(0);
|
|
||||||
}
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
static bool isAnyHat(uint16_t scancode) {
|
|
||||||
for(unsigned i = 0; i < Count; i++) {
|
|
||||||
if(joypad(i).isHat(scancode)) return true;
|
|
||||||
}
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
static bool isAnyAxis(uint16_t scancode) {
|
|
||||||
for(unsigned i = 0; i < Count; i++) {
|
|
||||||
if(joypad(i).isAxis(scancode)) return true;
|
|
||||||
}
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
static bool isAnyButton(uint16_t scancode) {
|
|
||||||
for(unsigned i = 0; i < Count; i++) {
|
|
||||||
if(joypad(i).isButton(scancode)) return true;
|
|
||||||
}
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
static uint16_t decode(const char *name) {
|
|
||||||
string s(name);
|
|
||||||
if(!strbegin(name, "JP")) return 0;
|
|
||||||
s.ltrim("JP");
|
|
||||||
unsigned id = decimal(s);
|
|
||||||
auto pos = strpos(s, "::");
|
|
||||||
if(!pos) return 0;
|
|
||||||
s = substr(s, pos() + 2);
|
|
||||||
for(unsigned i = 0; i < Limit; i++) {
|
|
||||||
if(s == JoypadScancodeName[i]) return Base + Size * id + i;
|
|
||||||
}
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
string encode(uint16_t code) const {
|
|
||||||
unsigned index = 0;
|
|
||||||
for(unsigned i = 0; i < Count; i++) {
|
|
||||||
if(code >= Base + Size * i && code < Base + Size * (i + 1)) {
|
|
||||||
index = code - (Base + Size * i);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return { "JP", ID, "::", JoypadScancodeName[index] };
|
|
||||||
}
|
|
||||||
|
|
||||||
uint16_t operator[](Scancode code) const { return Base + ID * Size + code; }
|
|
||||||
uint16_t hat(unsigned id) const { return Base + Size * ID + Hat0 + id; }
|
|
||||||
uint16_t axis(unsigned id) const { return Base + Size * ID + Axis0 + id; }
|
|
||||||
uint16_t button(unsigned id) const { return Base + Size * ID + Button0 + id; }
|
|
||||||
bool isHat(unsigned id) const { return id >= hat(0) && id <= hat(7); }
|
|
||||||
bool isAxis(unsigned id) const { return id >= axis(0) && id <= axis(15); }
|
|
||||||
bool isButton(unsigned id) const { return id >= button(0) && id <= button(31); }
|
|
||||||
bool belongsTo(uint16_t scancode) const { return isHat(scancode) || isAxis(scancode) || isButton(scancode); }
|
|
||||||
|
|
||||||
Joypad(unsigned ID_) : ID(ID_) {}
|
|
||||||
};
|
|
||||||
|
|
||||||
inline Joypad& joypad(unsigned id) {
|
|
||||||
static Joypad jp0(0), jp1(1), jp2(2), jp3(3), jp4(4), jp5(5), jp6(6), jp7(7);
|
|
||||||
switch(id) { default:
|
|
||||||
case 0: return jp0; case 1: return jp1; case 2: return jp2; case 3: return jp3;
|
|
||||||
case 4: return jp4; case 5: return jp5; case 6: return jp6; case 7: return jp7;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
struct Scancode {
|
|
||||||
enum { None = 0, Limit = Joypad::Base + Joypad::Size * Joypad::Count };
|
|
||||||
|
|
||||||
static uint16_t decode(const char *name) {
|
|
||||||
uint16_t code;
|
|
||||||
code = Keyboard::decode(name);
|
|
||||||
if(code) return code;
|
|
||||||
code = Mouse::decode(name);
|
|
||||||
if(code) return code;
|
|
||||||
code = Joypad::decode(name);
|
|
||||||
if(code) return code;
|
|
||||||
return None;
|
|
||||||
}
|
|
||||||
|
|
||||||
static string encode(uint16_t code) {
|
|
||||||
for(unsigned i = 0; i < Keyboard::Count; i++) {
|
|
||||||
if(keyboard(i).belongsTo(code)) return keyboard(i).encode(code);
|
|
||||||
}
|
|
||||||
for(unsigned i = 0; i < Mouse::Count; i++) {
|
|
||||||
if(mouse(i).belongsTo(code)) return mouse(i).encode(code);
|
|
||||||
}
|
|
||||||
for(unsigned i = 0; i < Joypad::Count; i++) {
|
|
||||||
if(joypad(i).belongsTo(code)) return joypad(i).encode(code);
|
|
||||||
}
|
|
||||||
return "None";
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
#endif
|
|
|
@ -1,59 +0,0 @@
|
||||||
#ifndef NALL_INTERPOLATION_HPP
|
|
||||||
#define NALL_INTERPOLATION_HPP
|
|
||||||
|
|
||||||
namespace nall {
|
|
||||||
|
|
||||||
struct Interpolation {
|
|
||||||
static inline double Nearest(double mu, double a, double b, double c, double d) {
|
|
||||||
return (mu <= 0.5 ? b : c);
|
|
||||||
}
|
|
||||||
|
|
||||||
static inline double Sublinear(double mu, double a, double b, double c, double d) {
|
|
||||||
mu = ((mu - 0.5) * 2.0) + 0.5;
|
|
||||||
if(mu < 0) mu = 0;
|
|
||||||
if(mu > 1) mu = 1;
|
|
||||||
return b * (1.0 - mu) + c * mu;
|
|
||||||
}
|
|
||||||
|
|
||||||
static inline double Linear(double mu, double a, double b, double c, double d) {
|
|
||||||
return b * (1.0 - mu) + c * mu;
|
|
||||||
}
|
|
||||||
|
|
||||||
static inline double Cosine(double mu, double a, double b, double c, double d) {
|
|
||||||
mu = (1.0 - cos(mu * 3.14159265)) / 2.0;
|
|
||||||
return b * (1.0 - mu) + c * mu;
|
|
||||||
}
|
|
||||||
|
|
||||||
static inline double Cubic(double mu, double a, double b, double c, double d) {
|
|
||||||
double A = d - c - a + b;
|
|
||||||
double B = a - b - A;
|
|
||||||
double C = c - a;
|
|
||||||
double D = b;
|
|
||||||
return A * (mu * mu * mu) + B * (mu * mu) + C * mu + D;
|
|
||||||
}
|
|
||||||
|
|
||||||
static inline double Hermite(double mu1, double a, double b, double c, double d) {
|
|
||||||
const double tension = 0.0; //-1 = low, 0 = normal, +1 = high
|
|
||||||
const double bias = 0.0; //-1 = left, 0 = even, +1 = right
|
|
||||||
double mu2, mu3, m0, m1, a0, a1, a2, a3;
|
|
||||||
|
|
||||||
mu2 = mu1 * mu1;
|
|
||||||
mu3 = mu2 * mu1;
|
|
||||||
|
|
||||||
m0 = (b - a) * (1.0 + bias) * (1.0 - tension) / 2.0;
|
|
||||||
m0 += (c - b) * (1.0 - bias) * (1.0 - tension) / 2.0;
|
|
||||||
m1 = (c - b) * (1.0 + bias) * (1.0 - tension) / 2.0;
|
|
||||||
m1 += (d - c) * (1.0 - bias) * (1.0 - tension) / 2.0;
|
|
||||||
|
|
||||||
a0 = +2 * mu3 - 3 * mu2 + 1;
|
|
||||||
a1 = mu3 - 2 * mu2 + mu1;
|
|
||||||
a2 = mu3 - mu2;
|
|
||||||
a3 = -2 * mu3 + 3 * mu2;
|
|
||||||
|
|
||||||
return (a0 * b) + (a1 * m0) + (a2 * m1) + (a3 * c);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
#endif
|
|
|
@ -1,66 +0,0 @@
|
||||||
#ifndef NALL_INTRINSICS_HPP
|
|
||||||
#define NALL_INTRINSICS_HPP
|
|
||||||
|
|
||||||
struct Intrinsics {
|
|
||||||
enum class Compiler : unsigned { Clang, GCC, VisualC, Unknown };
|
|
||||||
enum class Platform : unsigned { X, OSX, Windows, Unknown };
|
|
||||||
enum class Endian : unsigned { LSB, MSB, Unknown };
|
|
||||||
|
|
||||||
static inline Compiler compiler();
|
|
||||||
static inline Platform platform();
|
|
||||||
static inline Endian endian();
|
|
||||||
};
|
|
||||||
|
|
||||||
/* Compiler detection */
|
|
||||||
|
|
||||||
#if defined(__clang__)
|
|
||||||
#define COMPILER_CLANG
|
|
||||||
Intrinsics::Compiler Intrinsics::compiler() { return Intrinsics::Compiler::Clang; }
|
|
||||||
#elif defined(__GNUC__)
|
|
||||||
#define COMPILER_GCC
|
|
||||||
Intrinsics::Compiler Intrinsics::compiler() { return Intrinsics::Compiler::GCC; }
|
|
||||||
#elif defined(_MSC_VER)
|
|
||||||
#define COMPILER_VISUALC
|
|
||||||
Intrinsics::Compiler Intrinsics::compiler() { return Intrinsics::Compiler::VisualC; }
|
|
||||||
#else
|
|
||||||
#warning "unable to detect compiler"
|
|
||||||
#define COMPILER_UNKNOWN
|
|
||||||
Intrinsics::Compiler Intrinsics::compiler() { return Intrinsics::Compiler::Unknown; }
|
|
||||||
#endif
|
|
||||||
|
|
||||||
/* Platform detection */
|
|
||||||
|
|
||||||
#if defined(linux) || defined(__sun__) || defined(__FreeBSD__) || defined(__FreeBSD_kernel__) || defined(__NetBSD__) || defined(__OpenBSD__)
|
|
||||||
#define PLATFORM_X
|
|
||||||
Intrinsics::Platform Intrinsics::platform() { return Intrinsics::Platform::X; }
|
|
||||||
#elif defined(__APPLE__)
|
|
||||||
#define PLATFORM_OSX
|
|
||||||
Intrinsics::Platform Intrinsics::platform() { return Intrinsics::Platform::OSX; }
|
|
||||||
#elif defined(_WIN32)
|
|
||||||
#define PLATFORM_WINDOWS
|
|
||||||
#define PLATFORM_WIN
|
|
||||||
Intrinsics::Platform Intrinsics::platform() { return Intrinsics::Platform::Windows; }
|
|
||||||
#else
|
|
||||||
#warning "unable to detect platform"
|
|
||||||
#define PLATFORM_UNKNOWN
|
|
||||||
Intrinsics::Platform Intrinsics::platform() { return Intrinsics::Platform::Unknown; }
|
|
||||||
#endif
|
|
||||||
|
|
||||||
/* Endian detection */
|
|
||||||
|
|
||||||
#if defined(__i386__) || defined(__amd64__) || defined(_M_IX86) || defined(_M_AMD64)
|
|
||||||
#define ENDIAN_LSB
|
|
||||||
#define ARCH_LSB
|
|
||||||
Intrinsics::Endian Intrinsics::endian() { return Intrinsics::Endian::LSB; }
|
|
||||||
#elif defined(__powerpc__) || defined(_M_PPC) || defined(__BIG_ENDIAN__)
|
|
||||||
#define ENDIAN_MSB
|
|
||||||
#define ARCH_MSB
|
|
||||||
Intrinsics::Endian Intrinsics::endian() { return Intrinsics::Endian::MSB; }
|
|
||||||
#else
|
|
||||||
#warning "unable to detect endian"
|
|
||||||
#define ENDIAN_UNKNOWN
|
|
||||||
#define ARCH_UNKNOWN
|
|
||||||
Intrinsics::Endian Intrinsics::endian() { return Intrinsics::Endian::Unknown; }
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#endif
|
|
|
@ -1,60 +0,0 @@
|
||||||
#ifndef NALL_INVOKE_HPP
|
|
||||||
#define NALL_INVOKE_HPP
|
|
||||||
|
|
||||||
//void invoke(const string &name, const string& args...);
|
|
||||||
//if a program is specified, it is executed with the arguments provided
|
|
||||||
//if a file is specified, the file is opened using the program associated with said file type
|
|
||||||
//if a folder is specified, the folder is opened using the associated file explorer
|
|
||||||
//if a URL is specified, the default web browser is opened and pointed at the URL requested
|
|
||||||
//path environment variable is always consulted
|
|
||||||
//execution is asynchronous (non-blocking); use system() for synchronous execution
|
|
||||||
|
|
||||||
#include <nall/intrinsics.hpp>
|
|
||||||
#include <nall/string.hpp>
|
|
||||||
|
|
||||||
#if defined(PLATFORM_WINDOWS)
|
|
||||||
#include <nall/windows/utf8.hpp>
|
|
||||||
#endif
|
|
||||||
|
|
||||||
namespace nall {
|
|
||||||
|
|
||||||
#if defined(PLATFORM_WINDOWS)
|
|
||||||
|
|
||||||
template<typename... Args>
|
|
||||||
inline void invoke(const string &name, Args&&... args) {
|
|
||||||
lstring argl(std::forward<Args>(args)...);
|
|
||||||
for(auto &arg : argl) if(arg.position(" ")) arg = {"\"", arg, "\""};
|
|
||||||
string arguments = argl.concatenate(" ");
|
|
||||||
ShellExecuteW(NULL, NULL, utf16_t(name), utf16_t(arguments), NULL, SW_SHOWNORMAL);
|
|
||||||
}
|
|
||||||
|
|
||||||
#elif defined(PLATFORM_X)
|
|
||||||
|
|
||||||
template<typename... Args>
|
|
||||||
inline void invoke(const string &name, Args&&... args) {
|
|
||||||
pid_t pid = fork();
|
|
||||||
if(pid == 0) {
|
|
||||||
const char *argv[1 + sizeof...(args) + 1], **argp = argv;
|
|
||||||
lstring argl(std::forward<Args>(args)...);
|
|
||||||
*argp++ = (const char*)name;
|
|
||||||
for(auto &arg : argl) *argp++ = (const char*)arg;
|
|
||||||
*argp++ = nullptr;
|
|
||||||
|
|
||||||
if(execvp(name, (char* const*)argv) < 0) {
|
|
||||||
execlp("xdg-open", "xdg-open", (const char*)name, nullptr);
|
|
||||||
}
|
|
||||||
exit(0);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#else
|
|
||||||
|
|
||||||
template<typename... Args>
|
|
||||||
inline void invoke(const string &name, Args&&... args) {
|
|
||||||
}
|
|
||||||
|
|
||||||
#endif
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
#endif
|
|
|
@ -1,100 +0,0 @@
|
||||||
#ifndef NALL_IPS_HPP
|
|
||||||
#define NALL_IPS_HPP
|
|
||||||
|
|
||||||
#include <nall/file.hpp>
|
|
||||||
#include <nall/stdint.hpp>
|
|
||||||
#include <nall/string.hpp>
|
|
||||||
|
|
||||||
namespace nall {
|
|
||||||
|
|
||||||
struct ips {
|
|
||||||
inline bool apply();
|
|
||||||
inline void source(const uint8_t *data, unsigned size);
|
|
||||||
inline void modify(const uint8_t *data, unsigned size);
|
|
||||||
inline ips();
|
|
||||||
inline ~ips();
|
|
||||||
|
|
||||||
uint8_t *data;
|
|
||||||
unsigned size;
|
|
||||||
const uint8_t *sourceData;
|
|
||||||
unsigned sourceSize;
|
|
||||||
const uint8_t *modifyData;
|
|
||||||
unsigned modifySize;
|
|
||||||
};
|
|
||||||
|
|
||||||
bool ips::apply() {
|
|
||||||
if(modifySize < 8) return false;
|
|
||||||
if(modifyData[0] != 'P') return false;
|
|
||||||
if(modifyData[1] != 'A') return false;
|
|
||||||
if(modifyData[2] != 'T') return false;
|
|
||||||
if(modifyData[3] != 'C') return false;
|
|
||||||
if(modifyData[4] != 'H') return false;
|
|
||||||
|
|
||||||
if(data) delete[] data;
|
|
||||||
data = new uint8_t[16 * 1024 * 1024 + 65536](); //maximum size of IPS patch + single-tag padding
|
|
||||||
size = sourceSize;
|
|
||||||
memcpy(data, sourceData, sourceSize);
|
|
||||||
unsigned offset = 5;
|
|
||||||
|
|
||||||
while(true) {
|
|
||||||
unsigned address, length;
|
|
||||||
|
|
||||||
if(offset > modifySize - 3) break;
|
|
||||||
address = modifyData[offset++] << 16;
|
|
||||||
address |= modifyData[offset++] << 8;
|
|
||||||
address |= modifyData[offset++] << 0;
|
|
||||||
|
|
||||||
if(address == 0x454f46) { //EOF
|
|
||||||
if(offset == modifySize) return true;
|
|
||||||
if(offset == modifySize - 3) {
|
|
||||||
size = modifyData[offset++] << 16;
|
|
||||||
size |= modifyData[offset++] << 8;
|
|
||||||
size |= modifyData[offset++] << 0;
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if(offset > modifySize - 2) break;
|
|
||||||
length = modifyData[offset++] << 8;
|
|
||||||
length |= modifyData[offset++] << 0;
|
|
||||||
|
|
||||||
if(length) { //Copy
|
|
||||||
if(offset > modifySize - length) break;
|
|
||||||
while(length--) data[address++] = modifyData[offset++];
|
|
||||||
} else { //RLE
|
|
||||||
if(offset > modifySize - 3) break;
|
|
||||||
length = modifyData[offset++] << 8;
|
|
||||||
length |= modifyData[offset++] << 0;
|
|
||||||
if(length == 0) break; //illegal
|
|
||||||
while(length--) data[address++] = modifyData[offset];
|
|
||||||
offset++;
|
|
||||||
}
|
|
||||||
|
|
||||||
size = max(size, address);
|
|
||||||
}
|
|
||||||
|
|
||||||
delete[] data;
|
|
||||||
data = nullptr;
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
void ips::source(const uint8_t *data, unsigned size) {
|
|
||||||
sourceData = data, sourceSize = size;
|
|
||||||
}
|
|
||||||
|
|
||||||
void ips::modify(const uint8_t *data, unsigned size) {
|
|
||||||
modifyData = data, modifySize = size;
|
|
||||||
}
|
|
||||||
|
|
||||||
ips::ips() : data(nullptr), sourceData(nullptr), modifyData(nullptr) {
|
|
||||||
}
|
|
||||||
|
|
||||||
ips::~ips() {
|
|
||||||
if(data) delete[] data;
|
|
||||||
if(sourceData) delete[] sourceData;
|
|
||||||
if(modifyData) delete[] modifyData;
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
#endif
|
|
|
@ -1,165 +0,0 @@
|
||||||
#ifndef NALL_LZSS_HPP
|
|
||||||
#define NALL_LZSS_HPP
|
|
||||||
|
|
||||||
#include <nall/file.hpp>
|
|
||||||
#include <nall/filemap.hpp>
|
|
||||||
#include <nall/stdint.hpp>
|
|
||||||
#include <nall/string.hpp>
|
|
||||||
|
|
||||||
namespace nall {
|
|
||||||
|
|
||||||
//19:5 pulldown
|
|
||||||
//8:1 marker: d7-d0
|
|
||||||
//length: { 4 - 35 }, offset: { 1 - 0x80000 }
|
|
||||||
//4-byte file size header
|
|
||||||
//little-endian encoding
|
|
||||||
struct lzss {
|
|
||||||
inline void source(const uint8_t *data, unsigned size);
|
|
||||||
inline bool source(const string &filename);
|
|
||||||
inline unsigned size() const;
|
|
||||||
inline bool compress(const string &filename);
|
|
||||||
inline bool decompress(uint8_t *targetData, unsigned targetSize);
|
|
||||||
inline bool decompress(const string &filename);
|
|
||||||
|
|
||||||
protected:
|
|
||||||
struct Node {
|
|
||||||
unsigned offset;
|
|
||||||
Node *next;
|
|
||||||
inline Node() : offset(0), next(nullptr) {}
|
|
||||||
inline ~Node() { if(next) delete next; }
|
|
||||||
} *tree[65536];
|
|
||||||
|
|
||||||
filemap sourceFile;
|
|
||||||
const uint8_t *sourceData;
|
|
||||||
unsigned sourceSize;
|
|
||||||
|
|
||||||
public:
|
|
||||||
inline lzss() : sourceData(nullptr), sourceSize(0) {}
|
|
||||||
};
|
|
||||||
|
|
||||||
void lzss::source(const uint8_t *data, unsigned size) {
|
|
||||||
sourceData = data;
|
|
||||||
sourceSize = size;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool lzss::source(const string &filename) {
|
|
||||||
if(sourceFile.open(filename, filemap::mode::read) == false) return false;
|
|
||||||
sourceData = sourceFile.data();
|
|
||||||
sourceSize = sourceFile.size();
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
unsigned lzss::size() const {
|
|
||||||
unsigned size = 0;
|
|
||||||
if(sourceSize < 4) return size;
|
|
||||||
for(unsigned n = 0; n < 32; n += 8) size |= sourceData[n >> 3] << n;
|
|
||||||
return size;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool lzss::compress(const string &filename) {
|
|
||||||
file targetFile;
|
|
||||||
if(targetFile.open(filename, file::mode::write) == false) return false;
|
|
||||||
|
|
||||||
for(unsigned n = 0; n < 32; n += 8) targetFile.write(sourceSize >> n);
|
|
||||||
for(unsigned n = 0; n < 65536; n++) tree[n] = nullptr;
|
|
||||||
|
|
||||||
uint8_t buffer[25];
|
|
||||||
unsigned sourceOffset = 0;
|
|
||||||
|
|
||||||
while(sourceOffset < sourceSize) {
|
|
||||||
uint8_t mask = 0x00;
|
|
||||||
unsigned bufferOffset = 1;
|
|
||||||
|
|
||||||
for(unsigned iteration = 0; iteration < 8; iteration++) {
|
|
||||||
if(sourceOffset >= sourceSize) break;
|
|
||||||
|
|
||||||
uint16_t symbol = sourceData[sourceOffset + 0];
|
|
||||||
if(sourceOffset < sourceSize - 1) symbol |= sourceData[sourceOffset + 1] << 8;
|
|
||||||
Node *node = tree[symbol];
|
|
||||||
unsigned maxLength = 0, maxOffset = 0;
|
|
||||||
|
|
||||||
while(node) {
|
|
||||||
if(node->offset < sourceOffset - 0x80000) {
|
|
||||||
//out-of-range: all subsequent nodes will also be, so free up their memory
|
|
||||||
if(node->next) { delete node->next; node->next = nullptr; }
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
unsigned length = 0, x = sourceOffset, y = node->offset;
|
|
||||||
while(length < 35 && x < sourceSize && sourceData[x++] == sourceData[y++]) length++;
|
|
||||||
if(length > maxLength) maxLength = length, maxOffset = node->offset;
|
|
||||||
if(length == 35) break;
|
|
||||||
|
|
||||||
node = node->next;
|
|
||||||
}
|
|
||||||
|
|
||||||
//attach current symbol to top of tree for subsequent searches
|
|
||||||
node = new Node;
|
|
||||||
node->offset = sourceOffset;
|
|
||||||
node->next = tree[symbol];
|
|
||||||
tree[symbol] = node;
|
|
||||||
|
|
||||||
if(maxLength < 4) {
|
|
||||||
buffer[bufferOffset++] = sourceData[sourceOffset++];
|
|
||||||
} else {
|
|
||||||
unsigned output = ((maxLength - 4) << 19) | (sourceOffset - 1 - maxOffset);
|
|
||||||
for(unsigned n = 0; n < 24; n += 8) buffer[bufferOffset++] = output >> n;
|
|
||||||
mask |= 0x80 >> iteration;
|
|
||||||
sourceOffset += maxLength;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
buffer[0] = mask;
|
|
||||||
targetFile.write(buffer, bufferOffset);
|
|
||||||
}
|
|
||||||
|
|
||||||
sourceFile.close();
|
|
||||||
targetFile.close();
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool lzss::decompress(uint8_t *targetData, unsigned targetSize) {
|
|
||||||
if(targetSize < size()) return false;
|
|
||||||
|
|
||||||
unsigned sourceOffset = 4, targetOffset = 0;
|
|
||||||
while(sourceOffset < sourceSize) {
|
|
||||||
uint8_t mask = sourceData[sourceOffset++];
|
|
||||||
|
|
||||||
for(unsigned iteration = 0; iteration < 8; iteration++) {
|
|
||||||
if(sourceOffset >= sourceSize) break;
|
|
||||||
|
|
||||||
if((mask & (0x80 >> iteration)) == 0) {
|
|
||||||
targetData[targetOffset++] = sourceData[sourceOffset++];
|
|
||||||
} else {
|
|
||||||
unsigned code = 0;
|
|
||||||
for(unsigned n = 0; n < 24; n += 8) code |= sourceData[sourceOffset++] << n;
|
|
||||||
unsigned length = (code >> 19) + 4;
|
|
||||||
unsigned offset = targetOffset - 1 - (code & 0x7ffff);
|
|
||||||
while(length--) targetData[targetOffset++] = targetData[offset++];
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
bool lzss::decompress(const string &filename) {
|
|
||||||
if(sourceSize < 4) return false;
|
|
||||||
unsigned targetSize = size();
|
|
||||||
|
|
||||||
file fp;
|
|
||||||
if(fp.open(filename, file::mode::write) == false) return false;
|
|
||||||
fp.truncate(targetSize);
|
|
||||||
fp.close();
|
|
||||||
|
|
||||||
filemap targetFile;
|
|
||||||
if(targetFile.open(filename, filemap::mode::readwrite) == false) return false;
|
|
||||||
uint8_t *targetData = targetFile.data();
|
|
||||||
|
|
||||||
bool result = decompress(targetData, targetSize);
|
|
||||||
sourceFile.close();
|
|
||||||
targetFile.close();
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
#endif
|
|
|
@ -1,117 +0,0 @@
|
||||||
#ifndef NALL_MAP_HPP
|
|
||||||
#define NALL_MAP_HPP
|
|
||||||
|
|
||||||
#include <nall/vector.hpp>
|
|
||||||
|
|
||||||
namespace nall {
|
|
||||||
|
|
||||||
template<typename LHS, typename RHS>
|
|
||||||
struct map {
|
|
||||||
struct pair {
|
|
||||||
LHS name;
|
|
||||||
RHS data;
|
|
||||||
};
|
|
||||||
|
|
||||||
inline void reset() {
|
|
||||||
list.reset();
|
|
||||||
}
|
|
||||||
|
|
||||||
inline unsigned size() const {
|
|
||||||
return list.size();
|
|
||||||
}
|
|
||||||
|
|
||||||
//O(log n) find
|
|
||||||
inline optional<unsigned> find(const LHS &name) const {
|
|
||||||
signed first = 0, last = size() - 1;
|
|
||||||
while(first <= last) {
|
|
||||||
signed middle = (first + last) / 2;
|
|
||||||
if(name < list[middle].name) last = middle - 1; //search lower half
|
|
||||||
else if(list[middle].name < name) first = middle + 1; //search upper half
|
|
||||||
else return { true, (unsigned)middle }; //match found
|
|
||||||
}
|
|
||||||
return { false, 0u };
|
|
||||||
}
|
|
||||||
|
|
||||||
//O(n) insert + O(log n) find
|
|
||||||
inline RHS& insert(const LHS &name, const RHS &data) {
|
|
||||||
if(auto position = find(name)) {
|
|
||||||
list[position()].data = data;
|
|
||||||
return list[position()].data;
|
|
||||||
}
|
|
||||||
signed offset = size();
|
|
||||||
for(unsigned n = 0; n < size(); n++) {
|
|
||||||
if(name < list[n].name) { offset = n; break; }
|
|
||||||
}
|
|
||||||
list.insert(offset, { name, data });
|
|
||||||
return list[offset].data;
|
|
||||||
}
|
|
||||||
|
|
||||||
//O(log n) find
|
|
||||||
inline void modify(const LHS &name, const RHS &data) {
|
|
||||||
if(auto position = find(name)) list[position()].data = data;
|
|
||||||
}
|
|
||||||
|
|
||||||
//O(n) remove + O(log n) find
|
|
||||||
inline void remove(const LHS &name) {
|
|
||||||
if(auto position = find(name)) list.remove(position());
|
|
||||||
}
|
|
||||||
|
|
||||||
//O(log n) find
|
|
||||||
inline RHS& operator[](const LHS &name) {
|
|
||||||
if(auto position = find(name)) return list[position()].data;
|
|
||||||
throw;
|
|
||||||
}
|
|
||||||
|
|
||||||
inline const RHS& operator[](const LHS &name) const {
|
|
||||||
if(auto position = find(name)) return list[position()].data;
|
|
||||||
throw;
|
|
||||||
}
|
|
||||||
|
|
||||||
inline RHS& operator()(const LHS &name) {
|
|
||||||
if(auto position = find(name)) return list[position()].data;
|
|
||||||
return insert(name, RHS());
|
|
||||||
}
|
|
||||||
|
|
||||||
inline const RHS& operator()(const LHS &name, const RHS &data) const {
|
|
||||||
if(auto position = find(name)) return list[position()].data;
|
|
||||||
return data;
|
|
||||||
}
|
|
||||||
|
|
||||||
inline pair* begin() { return list.begin(); }
|
|
||||||
inline pair* end() { return list.end(); }
|
|
||||||
inline const pair* begin() const { return list.begin(); }
|
|
||||||
inline const pair* end() const { return list.end(); }
|
|
||||||
|
|
||||||
protected:
|
|
||||||
vector<pair> list;
|
|
||||||
};
|
|
||||||
|
|
||||||
template<typename LHS, typename RHS>
|
|
||||||
struct bidirectional_map {
|
|
||||||
const map<LHS, RHS> &lhs;
|
|
||||||
const map<RHS, LHS> &rhs;
|
|
||||||
|
|
||||||
inline void reset() {
|
|
||||||
llist.reset();
|
|
||||||
rlist.reset();
|
|
||||||
}
|
|
||||||
|
|
||||||
inline unsigned size() const {
|
|
||||||
return llist.size();
|
|
||||||
}
|
|
||||||
|
|
||||||
inline void insert(const LHS &ldata, const RHS &rdata) {
|
|
||||||
llist.insert(ldata, rdata);
|
|
||||||
rlist.insert(rdata, ldata);
|
|
||||||
}
|
|
||||||
|
|
||||||
inline bidirectional_map() : lhs(llist), rhs(rlist) {}
|
|
||||||
|
|
||||||
protected:
|
|
||||||
map<LHS, RHS> llist;
|
|
||||||
map<RHS, LHS> rlist;
|
|
||||||
};
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
#endif
|
|
|
@ -1,10 +0,0 @@
|
||||||
#ifndef NALL_MOSAIC_HPP
|
|
||||||
#define NALL_MOSAIC_HPP
|
|
||||||
|
|
||||||
#define NALL_MOSAIC_INTERNAL_HPP
|
|
||||||
#include <nall/mosaic/bitstream.hpp>
|
|
||||||
#include <nall/mosaic/context.hpp>
|
|
||||||
#include <nall/mosaic/parser.hpp>
|
|
||||||
#undef NALL_MOSAIC_INTERNAL_HPP
|
|
||||||
|
|
||||||
#endif
|
|
|
@ -1,55 +0,0 @@
|
||||||
#ifdef NALL_MOSAIC_INTERNAL_HPP
|
|
||||||
|
|
||||||
namespace nall {
|
|
||||||
namespace mosaic {
|
|
||||||
|
|
||||||
struct bitstream {
|
|
||||||
filemap fp;
|
|
||||||
uint8_t *data;
|
|
||||||
unsigned size;
|
|
||||||
bool readonly;
|
|
||||||
bool endian;
|
|
||||||
|
|
||||||
inline bool read(uint64_t addr) const {
|
|
||||||
if(data == nullptr || (addr >> 3) >= size) return 0;
|
|
||||||
unsigned mask = endian == 0 ? (0x01 << (addr & 7)) : (0x80 >> (addr & 7));
|
|
||||||
return data[addr >> 3] & mask;
|
|
||||||
}
|
|
||||||
|
|
||||||
inline void write(uint64_t addr, bool value) {
|
|
||||||
if(data == nullptr || readonly == true || (addr >> 3) >= size) return;
|
|
||||||
unsigned mask = endian == 0 ? (0x01 << (addr & 7)) : (0x80 >> (addr & 7));
|
|
||||||
if(value == 0) data[addr >> 3] &= ~mask;
|
|
||||||
if(value == 1) data[addr >> 3] |= mask;
|
|
||||||
}
|
|
||||||
|
|
||||||
inline bool open(const string &filename) {
|
|
||||||
readonly = false;
|
|
||||||
if(fp.open(filename, filemap::mode::readwrite) == false) {
|
|
||||||
readonly = true;
|
|
||||||
if(fp.open(filename, filemap::mode::read) == false) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
data = fp.data();
|
|
||||||
size = fp.size();
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
inline void close() {
|
|
||||||
fp.close();
|
|
||||||
data = nullptr;
|
|
||||||
}
|
|
||||||
|
|
||||||
inline bitstream() : data(nullptr), endian(1) {
|
|
||||||
}
|
|
||||||
|
|
||||||
inline ~bitstream() {
|
|
||||||
close();
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#endif
|
|
|
@ -1,224 +0,0 @@
|
||||||
#ifdef NALL_MOSAIC_INTERNAL_HPP
|
|
||||||
|
|
||||||
namespace nall {
|
|
||||||
namespace mosaic {
|
|
||||||
|
|
||||||
struct context {
|
|
||||||
unsigned offset;
|
|
||||||
unsigned width;
|
|
||||||
unsigned height;
|
|
||||||
unsigned count;
|
|
||||||
|
|
||||||
bool endian; //0 = lsb, 1 = msb
|
|
||||||
bool order; //0 = linear, 1 = planar
|
|
||||||
unsigned depth; //1 - 24bpp
|
|
||||||
|
|
||||||
unsigned blockWidth;
|
|
||||||
unsigned blockHeight;
|
|
||||||
unsigned blockStride;
|
|
||||||
unsigned blockOffset;
|
|
||||||
vector<unsigned> block;
|
|
||||||
|
|
||||||
unsigned tileWidth;
|
|
||||||
unsigned tileHeight;
|
|
||||||
unsigned tileStride;
|
|
||||||
unsigned tileOffset;
|
|
||||||
vector<unsigned> tile;
|
|
||||||
|
|
||||||
unsigned mosaicWidth;
|
|
||||||
unsigned mosaicHeight;
|
|
||||||
unsigned mosaicStride;
|
|
||||||
unsigned mosaicOffset;
|
|
||||||
vector<unsigned> mosaic;
|
|
||||||
|
|
||||||
unsigned paddingWidth;
|
|
||||||
unsigned paddingHeight;
|
|
||||||
unsigned paddingColor;
|
|
||||||
vector<unsigned> palette;
|
|
||||||
|
|
||||||
inline unsigned objectWidth() const { return blockWidth * tileWidth * mosaicWidth + paddingWidth; }
|
|
||||||
inline unsigned objectHeight() const { return blockHeight * tileHeight * mosaicHeight + paddingHeight; }
|
|
||||||
inline unsigned objectSize() const {
|
|
||||||
unsigned size = blockStride * tileWidth * tileHeight * mosaicWidth * mosaicHeight
|
|
||||||
+ blockOffset * tileHeight * mosaicWidth * mosaicHeight
|
|
||||||
+ tileStride * mosaicWidth * mosaicHeight
|
|
||||||
+ tileOffset * mosaicHeight;
|
|
||||||
return max(1u, size);
|
|
||||||
}
|
|
||||||
|
|
||||||
inline unsigned eval(const string &expression) {
|
|
||||||
intmax_t result;
|
|
||||||
if(fixedpoint::eval(expression, result) == false) return 0u;
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
inline void eval(vector<unsigned> &buffer, const string &expression_) {
|
|
||||||
string expression = expression_;
|
|
||||||
bool function = false;
|
|
||||||
for(auto &c : expression) {
|
|
||||||
if(c == '(') function = true;
|
|
||||||
if(c == ')') function = false;
|
|
||||||
if(c == ',' && function == true) c = ';';
|
|
||||||
}
|
|
||||||
|
|
||||||
lstring list = expression.split(",");
|
|
||||||
for(auto &item : list) {
|
|
||||||
item.trim();
|
|
||||||
if(item.wildcard("f(?*) ?*")) {
|
|
||||||
item.ltrim<1>("f(");
|
|
||||||
lstring part = item.split<1>(") ");
|
|
||||||
lstring args = part[0].split<3>(";");
|
|
||||||
for(auto &item : args) item.trim();
|
|
||||||
|
|
||||||
unsigned length = eval(args(0, "0"));
|
|
||||||
unsigned offset = eval(args(1, "0"));
|
|
||||||
unsigned stride = eval(args(2, "0"));
|
|
||||||
if(args.size() < 2) offset = buffer.size();
|
|
||||||
if(args.size() < 3) stride = 1;
|
|
||||||
|
|
||||||
for(unsigned n = 0; n < length; n++) {
|
|
||||||
string fn = part[1];
|
|
||||||
fn.replace("n", decimal(n));
|
|
||||||
fn.replace("o", decimal(offset));
|
|
||||||
fn.replace("p", decimal(buffer.size()));
|
|
||||||
buffer.resize(offset + 1);
|
|
||||||
buffer[offset] = eval(fn);
|
|
||||||
offset += stride;
|
|
||||||
}
|
|
||||||
} else if(item.wildcard("base64*")) {
|
|
||||||
unsigned offset = 0;
|
|
||||||
item.ltrim<1>("base64");
|
|
||||||
if(item.wildcard("(?*) *")) {
|
|
||||||
item.ltrim<1>("(");
|
|
||||||
lstring part = item.split<1>(") ");
|
|
||||||
offset = eval(part[0]);
|
|
||||||
item = part(1, "");
|
|
||||||
}
|
|
||||||
item.trim();
|
|
||||||
for(auto &c : item) {
|
|
||||||
if(c >= 'A' && c <= 'Z') buffer.append(offset + c - 'A' + 0);
|
|
||||||
if(c >= 'a' && c <= 'z') buffer.append(offset + c - 'a' + 26);
|
|
||||||
if(c >= '0' && c <= '9') buffer.append(offset + c - '0' + 52);
|
|
||||||
if(c == '-') buffer.append(offset + 62);
|
|
||||||
if(c == '_') buffer.append(offset + 63);
|
|
||||||
}
|
|
||||||
} else if(item.wildcard("file *")) {
|
|
||||||
item.ltrim<1>("file ");
|
|
||||||
item.trim();
|
|
||||||
//...
|
|
||||||
} else if(item.empty() == false) {
|
|
||||||
buffer.append(eval(item));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
inline void parse(const string &data) {
|
|
||||||
reset();
|
|
||||||
|
|
||||||
lstring lines = data.split("\n");
|
|
||||||
for(auto &line : lines) {
|
|
||||||
lstring part = line.split<1>(":");
|
|
||||||
if(part.size() != 2) continue;
|
|
||||||
part[0].trim();
|
|
||||||
part[1].trim();
|
|
||||||
|
|
||||||
if(part[0] == "offset") offset = eval(part[1]);
|
|
||||||
if(part[0] == "width") width = eval(part[1]);
|
|
||||||
if(part[0] == "height") height = eval(part[1]);
|
|
||||||
if(part[0] == "count") count = eval(part[1]);
|
|
||||||
|
|
||||||
if(part[0] == "endian") endian = eval(part[1]);
|
|
||||||
if(part[0] == "order") order = eval(part[1]);
|
|
||||||
if(part[0] == "depth") depth = eval(part[1]);
|
|
||||||
|
|
||||||
if(part[0] == "blockWidth") blockWidth = eval(part[1]);
|
|
||||||
if(part[0] == "blockHeight") blockHeight = eval(part[1]);
|
|
||||||
if(part[0] == "blockStride") blockStride = eval(part[1]);
|
|
||||||
if(part[0] == "blockOffset") blockOffset = eval(part[1]);
|
|
||||||
if(part[0] == "block") eval(block, part[1]);
|
|
||||||
|
|
||||||
if(part[0] == "tileWidth") tileWidth = eval(part[1]);
|
|
||||||
if(part[0] == "tileHeight") tileHeight = eval(part[1]);
|
|
||||||
if(part[0] == "tileStride") tileStride = eval(part[1]);
|
|
||||||
if(part[0] == "tileOffset") tileOffset = eval(part[1]);
|
|
||||||
if(part[0] == "tile") eval(tile, part[1]);
|
|
||||||
|
|
||||||
if(part[0] == "mosaicWidth") mosaicWidth = eval(part[1]);
|
|
||||||
if(part[0] == "mosaicHeight") mosaicHeight = eval(part[1]);
|
|
||||||
if(part[0] == "mosaicStride") mosaicStride = eval(part[1]);
|
|
||||||
if(part[0] == "mosaicOffset") mosaicOffset = eval(part[1]);
|
|
||||||
if(part[0] == "mosaic") eval(mosaic, part[1]);
|
|
||||||
|
|
||||||
if(part[0] == "paddingWidth") paddingWidth = eval(part[1]);
|
|
||||||
if(part[0] == "paddingHeight") paddingHeight = eval(part[1]);
|
|
||||||
if(part[0] == "paddingColor") paddingColor = eval(part[1]);
|
|
||||||
if(part[0] == "palette") eval(palette, part[1]);
|
|
||||||
}
|
|
||||||
|
|
||||||
sanitize();
|
|
||||||
}
|
|
||||||
|
|
||||||
inline bool load(const string &filename) {
|
|
||||||
string filedata;
|
|
||||||
if(filedata.readfile(filename) == false) return false;
|
|
||||||
parse(filedata);
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
inline void sanitize() {
|
|
||||||
if(depth < 1) depth = 1;
|
|
||||||
if(depth > 24) depth = 24;
|
|
||||||
|
|
||||||
if(blockWidth < 1) blockWidth = 1;
|
|
||||||
if(blockHeight < 1) blockHeight = 1;
|
|
||||||
|
|
||||||
if(tileWidth < 1) tileWidth = 1;
|
|
||||||
if(tileHeight < 1) tileHeight = 1;
|
|
||||||
|
|
||||||
if(mosaicWidth < 1) mosaicWidth = 1;
|
|
||||||
if(mosaicHeight < 1) mosaicHeight = 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
inline void reset() {
|
|
||||||
offset = 0;
|
|
||||||
width = 0;
|
|
||||||
height = 0;
|
|
||||||
count = 0;
|
|
||||||
|
|
||||||
endian = 1;
|
|
||||||
order = 0;
|
|
||||||
depth = 1;
|
|
||||||
|
|
||||||
blockWidth = 1;
|
|
||||||
blockHeight = 1;
|
|
||||||
blockStride = 0;
|
|
||||||
blockOffset = 0;
|
|
||||||
block.reset();
|
|
||||||
|
|
||||||
tileWidth = 1;
|
|
||||||
tileHeight = 1;
|
|
||||||
tileStride = 0;
|
|
||||||
tileOffset = 0;
|
|
||||||
tile.reset();
|
|
||||||
|
|
||||||
mosaicWidth = 1;
|
|
||||||
mosaicHeight = 1;
|
|
||||||
mosaicStride = 0;
|
|
||||||
mosaicOffset = 0;
|
|
||||||
mosaic.reset();
|
|
||||||
|
|
||||||
paddingWidth = 0;
|
|
||||||
paddingHeight = 0;
|
|
||||||
paddingColor = 0x000000;
|
|
||||||
palette.reset();
|
|
||||||
}
|
|
||||||
|
|
||||||
inline context() {
|
|
||||||
reset();
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#endif
|
|
|
@ -1,126 +0,0 @@
|
||||||
#ifdef NALL_MOSAIC_INTERNAL_HPP
|
|
||||||
|
|
||||||
namespace nall {
|
|
||||||
namespace mosaic {
|
|
||||||
|
|
||||||
struct parser {
|
|
||||||
image canvas;
|
|
||||||
|
|
||||||
//export from bitstream to canvas
|
|
||||||
inline void load(bitstream &stream, uint64_t offset, context &ctx, unsigned width, unsigned height) {
|
|
||||||
canvas.allocate(width, height);
|
|
||||||
canvas.clear(ctx.paddingColor);
|
|
||||||
parse(1, stream, offset, ctx, width, height);
|
|
||||||
}
|
|
||||||
|
|
||||||
//import from canvas to bitstream
|
|
||||||
inline bool save(bitstream &stream, uint64_t offset, context &ctx) {
|
|
||||||
if(stream.readonly) return false;
|
|
||||||
parse(0, stream, offset, ctx, canvas.width, canvas.height);
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
inline parser() : canvas(0, 32, 0u, 255u << 16, 255u << 8, 255u << 0) {
|
|
||||||
}
|
|
||||||
|
|
||||||
private:
|
|
||||||
inline uint32_t read(unsigned x, unsigned y) const {
|
|
||||||
unsigned addr = y * canvas.width + x;
|
|
||||||
if(addr >= canvas.width * canvas.height) return 0u;
|
|
||||||
uint32_t *buffer = (uint32_t*)canvas.data;
|
|
||||||
return buffer[addr];
|
|
||||||
}
|
|
||||||
|
|
||||||
inline void write(unsigned x, unsigned y, uint32_t data) {
|
|
||||||
unsigned addr = y * canvas.width + x;
|
|
||||||
if(addr >= canvas.width * canvas.height) return;
|
|
||||||
uint32_t *buffer = (uint32_t*)canvas.data;
|
|
||||||
buffer[addr] = data;
|
|
||||||
}
|
|
||||||
|
|
||||||
inline void parse(bool load, bitstream &stream, uint64_t offset, context &ctx, unsigned width, unsigned height) {
|
|
||||||
stream.endian = ctx.endian;
|
|
||||||
unsigned canvasWidth = width / (ctx.mosaicWidth * ctx.tileWidth * ctx.blockWidth + ctx.paddingWidth);
|
|
||||||
unsigned canvasHeight = height / (ctx.mosaicHeight * ctx.tileHeight * ctx.blockHeight + ctx.paddingHeight);
|
|
||||||
unsigned bitsPerBlock = ctx.depth * ctx.blockWidth * ctx.blockHeight;
|
|
||||||
|
|
||||||
unsigned objectOffset = 0;
|
|
||||||
for(unsigned objectY = 0; objectY < canvasHeight; objectY++) {
|
|
||||||
for(unsigned objectX = 0; objectX < canvasWidth; objectX++) {
|
|
||||||
if(objectOffset >= ctx.count && ctx.count > 0) break;
|
|
||||||
unsigned objectIX = objectX * ctx.objectWidth();
|
|
||||||
unsigned objectIY = objectY * ctx.objectHeight();
|
|
||||||
objectOffset++;
|
|
||||||
|
|
||||||
unsigned mosaicOffset = 0;
|
|
||||||
for(unsigned mosaicY = 0; mosaicY < ctx.mosaicHeight; mosaicY++) {
|
|
||||||
for(unsigned mosaicX = 0; mosaicX < ctx.mosaicWidth; mosaicX++) {
|
|
||||||
unsigned mosaicData = ctx.mosaic(mosaicOffset, mosaicOffset);
|
|
||||||
unsigned mosaicIX = (mosaicData % ctx.mosaicWidth) * (ctx.tileWidth * ctx.blockWidth);
|
|
||||||
unsigned mosaicIY = (mosaicData / ctx.mosaicWidth) * (ctx.tileHeight * ctx.blockHeight);
|
|
||||||
mosaicOffset++;
|
|
||||||
|
|
||||||
unsigned tileOffset = 0;
|
|
||||||
for(unsigned tileY = 0; tileY < ctx.tileHeight; tileY++) {
|
|
||||||
for(unsigned tileX = 0; tileX < ctx.tileWidth; tileX++) {
|
|
||||||
unsigned tileData = ctx.tile(tileOffset, tileOffset);
|
|
||||||
unsigned tileIX = (tileData % ctx.tileWidth) * ctx.blockWidth;
|
|
||||||
unsigned tileIY = (tileData / ctx.tileWidth) * ctx.blockHeight;
|
|
||||||
tileOffset++;
|
|
||||||
|
|
||||||
unsigned blockOffset = 0;
|
|
||||||
for(unsigned blockY = 0; blockY < ctx.blockHeight; blockY++) {
|
|
||||||
for(unsigned blockX = 0; blockX < ctx.blockWidth; blockX++) {
|
|
||||||
if(load) {
|
|
||||||
unsigned palette = 0;
|
|
||||||
for(unsigned n = 0; n < ctx.depth; n++) {
|
|
||||||
unsigned index = blockOffset++;
|
|
||||||
if(ctx.order == 1) index = (index % ctx.depth) * ctx.blockWidth * ctx.blockHeight + (index / ctx.depth);
|
|
||||||
palette |= stream.read(offset + ctx.block(index, index)) << n;
|
|
||||||
}
|
|
||||||
|
|
||||||
write(
|
|
||||||
objectIX + mosaicIX + tileIX + blockX,
|
|
||||||
objectIY + mosaicIY + tileIY + blockY,
|
|
||||||
ctx.palette(palette, palette)
|
|
||||||
);
|
|
||||||
} else /* save */ {
|
|
||||||
uint32_t palette = read(
|
|
||||||
objectIX + mosaicIX + tileIX + blockX,
|
|
||||||
objectIY + mosaicIY + tileIY + blockY
|
|
||||||
);
|
|
||||||
|
|
||||||
for(unsigned n = 0; n < ctx.depth; n++) {
|
|
||||||
unsigned index = blockOffset++;
|
|
||||||
if(ctx.order == 1) index = (index % ctx.depth) * ctx.blockWidth * ctx.blockHeight + (index / ctx.depth);
|
|
||||||
stream.write(offset + ctx.block(index, index), palette & 1);
|
|
||||||
palette >>= 1;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} //blockX
|
|
||||||
} //blockY
|
|
||||||
|
|
||||||
offset += ctx.blockStride;
|
|
||||||
} //tileX
|
|
||||||
|
|
||||||
offset += ctx.blockOffset;
|
|
||||||
} //tileY
|
|
||||||
|
|
||||||
offset += ctx.tileStride;
|
|
||||||
} //mosaicX
|
|
||||||
|
|
||||||
offset += ctx.tileOffset;
|
|
||||||
} //mosaicY
|
|
||||||
|
|
||||||
offset += ctx.mosaicStride;
|
|
||||||
} //objectX
|
|
||||||
|
|
||||||
offset += ctx.mosaicOffset;
|
|
||||||
} //objectY
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#endif
|
|
|
@ -1,59 +0,0 @@
|
||||||
#ifndef NALL_HPP
|
|
||||||
#define NALL_HPP
|
|
||||||
|
|
||||||
//include the most common nall headers with one statement
|
|
||||||
//does not include the most obscure components with high cost and low usage
|
|
||||||
|
|
||||||
#include <nall/platform.hpp>
|
|
||||||
|
|
||||||
#include <nall/algorithm.hpp>
|
|
||||||
#include <nall/any.hpp>
|
|
||||||
#include <nall/atoi.hpp>
|
|
||||||
#include <nall/base64.hpp>
|
|
||||||
#include <nall/bit.hpp>
|
|
||||||
#include <nall/bmp.hpp>
|
|
||||||
#include <nall/config.hpp>
|
|
||||||
#include <nall/crc16.hpp>
|
|
||||||
#include <nall/crc32.hpp>
|
|
||||||
#include <nall/directory.hpp>
|
|
||||||
#include <nall/dl.hpp>
|
|
||||||
#include <nall/endian.hpp>
|
|
||||||
#include <nall/file.hpp>
|
|
||||||
#include <nall/filemap.hpp>
|
|
||||||
#include <nall/function.hpp>
|
|
||||||
#include <nall/gzip.hpp>
|
|
||||||
#include <nall/http.hpp>
|
|
||||||
#include <nall/image.hpp>
|
|
||||||
#include <nall/inflate.hpp>
|
|
||||||
#include <nall/interpolation.hpp>
|
|
||||||
#include <nall/intrinsics.hpp>
|
|
||||||
#include <nall/invoke.hpp>
|
|
||||||
#include <nall/map.hpp>
|
|
||||||
#include <nall/png.hpp>
|
|
||||||
#include <nall/property.hpp>
|
|
||||||
#include <nall/random.hpp>
|
|
||||||
#include <nall/serializer.hpp>
|
|
||||||
#include <nall/set.hpp>
|
|
||||||
#include <nall/sha256.hpp>
|
|
||||||
#include <nall/sort.hpp>
|
|
||||||
#include <nall/stdint.hpp>
|
|
||||||
#include <nall/stream.hpp>
|
|
||||||
#include <nall/string.hpp>
|
|
||||||
#include <nall/thread.hpp>
|
|
||||||
#include <nall/traits.hpp>
|
|
||||||
#include <nall/unzip.hpp>
|
|
||||||
#include <nall/utility.hpp>
|
|
||||||
#include <nall/varint.hpp>
|
|
||||||
#include <nall/vector.hpp>
|
|
||||||
#include <nall/zip.hpp>
|
|
||||||
|
|
||||||
#if defined(PLATFORM_WINDOWS)
|
|
||||||
#include <nall/windows/registry.hpp>
|
|
||||||
#include <nall/windows/utf8.hpp>
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#if defined(PLATFORM_X)
|
|
||||||
#include <nall/serial.hpp>
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#endif
|
|
|
@ -1,96 +0,0 @@
|
||||||
#ifndef NALL_PLATFORM_HPP
|
|
||||||
#define NALL_PLATFORM_HPP
|
|
||||||
|
|
||||||
#if defined(_WIN32)
|
|
||||||
//minimum version needed for _wstat64, etc
|
|
||||||
#undef __MSVCRT_VERSION__
|
|
||||||
#define __MSVCRT_VERSION__ 0x0601
|
|
||||||
#include <nall/windows/utf8.hpp>
|
|
||||||
#endif
|
|
||||||
|
|
||||||
//=========================
|
|
||||||
//standard platform headers
|
|
||||||
//=========================
|
|
||||||
|
|
||||||
#include <limits>
|
|
||||||
|
|
||||||
#include <assert.h>
|
|
||||||
#include <limits.h>
|
|
||||||
#include <math.h>
|
|
||||||
#include <stdarg.h>
|
|
||||||
#include <stdio.h>
|
|
||||||
#include <stdlib.h>
|
|
||||||
#include <string.h>
|
|
||||||
#include <time.h>
|
|
||||||
|
|
||||||
#include <sys/types.h>
|
|
||||||
#include <sys/stat.h>
|
|
||||||
|
|
||||||
#if defined(_WIN32)
|
|
||||||
#include <io.h>
|
|
||||||
#include <direct.h>
|
|
||||||
#include <shlobj.h>
|
|
||||||
#include <wchar.h>
|
|
||||||
#undef interface
|
|
||||||
#define dllexport __declspec(dllexport)
|
|
||||||
#else
|
|
||||||
#include <unistd.h>
|
|
||||||
#include <pwd.h>
|
|
||||||
#define dllexport
|
|
||||||
#endif
|
|
||||||
|
|
||||||
//==================
|
|
||||||
//warning supression
|
|
||||||
//==================
|
|
||||||
|
|
||||||
//Visual C++
|
|
||||||
#if defined(_MSC_VER)
|
|
||||||
//disable libc "deprecation" warnings
|
|
||||||
#pragma warning(disable:4996)
|
|
||||||
#endif
|
|
||||||
|
|
||||||
//================
|
|
||||||
//POSIX compliance
|
|
||||||
//================
|
|
||||||
|
|
||||||
#if defined(_MSC_VER)
|
|
||||||
#define PATH_MAX _MAX_PATH
|
|
||||||
#define va_copy(dest, src) ((dest) = (src))
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#if defined(_WIN32)
|
|
||||||
#define getcwd _getcwd
|
|
||||||
#define putenv _putenv
|
|
||||||
#define vsnprintf _vsnprintf
|
|
||||||
inline void usleep(unsigned milliseconds) { Sleep(milliseconds / 1000); }
|
|
||||||
#endif
|
|
||||||
|
|
||||||
//================
|
|
||||||
//inline expansion
|
|
||||||
//================
|
|
||||||
|
|
||||||
#if defined(__clang__) || defined(__GNUC__)
|
|
||||||
#define noinline __attribute__((noinline))
|
|
||||||
#define inline inline
|
|
||||||
#define alwaysinline inline __attribute__((always_inline))
|
|
||||||
#elif defined(_MSC_VER)
|
|
||||||
#define noinline __declspec(noinline)
|
|
||||||
#define inline inline
|
|
||||||
#define alwaysinline inline __forceinline
|
|
||||||
#else
|
|
||||||
#define noinline
|
|
||||||
#define inline inline
|
|
||||||
#define alwaysinline inline
|
|
||||||
#endif
|
|
||||||
|
|
||||||
//===========
|
|
||||||
//unreachable
|
|
||||||
//===========
|
|
||||||
|
|
||||||
#if defined(__clang__) || defined(__GNUC__)
|
|
||||||
#define unreachable __builtin_unreachable()
|
|
||||||
#else
|
|
||||||
#define unreachable throw
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#endif
|
|
|
@ -1,337 +0,0 @@
|
||||||
#ifndef NALL_PNG_HPP
|
|
||||||
#define NALL_PNG_HPP
|
|
||||||
|
|
||||||
//PNG image decoder
|
|
||||||
//author: byuu
|
|
||||||
|
|
||||||
#include <nall/inflate.hpp>
|
|
||||||
#include <nall/string.hpp>
|
|
||||||
|
|
||||||
namespace nall {
|
|
||||||
|
|
||||||
struct png {
|
|
||||||
//colorType:
|
|
||||||
//0 = L
|
|
||||||
//2 = R,G,B
|
|
||||||
//3 = P
|
|
||||||
//4 = L,A
|
|
||||||
//6 = R,G,B,A
|
|
||||||
struct Info {
|
|
||||||
unsigned width;
|
|
||||||
unsigned height;
|
|
||||||
unsigned bitDepth;
|
|
||||||
unsigned colorType;
|
|
||||||
unsigned compressionMethod;
|
|
||||||
unsigned filterType;
|
|
||||||
unsigned interlaceMethod;
|
|
||||||
|
|
||||||
unsigned bytesPerPixel;
|
|
||||||
unsigned pitch;
|
|
||||||
|
|
||||||
uint8_t palette[256][3];
|
|
||||||
} info;
|
|
||||||
|
|
||||||
uint8_t *data;
|
|
||||||
unsigned size;
|
|
||||||
|
|
||||||
inline bool decode(const string &filename);
|
|
||||||
inline bool decode(const uint8_t *sourceData, unsigned sourceSize);
|
|
||||||
inline unsigned readbits(const uint8_t *&data);
|
|
||||||
unsigned bitpos;
|
|
||||||
|
|
||||||
inline png();
|
|
||||||
inline ~png();
|
|
||||||
|
|
||||||
protected:
|
|
||||||
enum class FourCC : unsigned {
|
|
||||||
IHDR = 0x49484452,
|
|
||||||
PLTE = 0x504c5445,
|
|
||||||
IDAT = 0x49444154,
|
|
||||||
IEND = 0x49454e44,
|
|
||||||
};
|
|
||||||
|
|
||||||
inline unsigned interlace(unsigned pass, unsigned index);
|
|
||||||
inline unsigned inflateSize();
|
|
||||||
inline bool deinterlace(const uint8_t *&inputData, unsigned pass);
|
|
||||||
inline bool filter(uint8_t *outputData, const uint8_t *inputData, unsigned width, unsigned height);
|
|
||||||
inline unsigned read(const uint8_t *data, unsigned length);
|
|
||||||
};
|
|
||||||
|
|
||||||
bool png::decode(const string &filename) {
|
|
||||||
if(auto memory = file::read(filename)) {
|
|
||||||
return decode(memory.data(), memory.size());
|
|
||||||
}
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool png::decode(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;
|
|
||||||
|
|
||||||
uint8_t *compressedData = nullptr;
|
|
||||||
unsigned compressedSize = 0;
|
|
||||||
|
|
||||||
unsigned offset = 8;
|
|
||||||
while(offset < sourceSize) {
|
|
||||||
unsigned length = read(sourceData + offset + 0, 4);
|
|
||||||
unsigned fourCC = read(sourceData + offset + 4, 4);
|
|
||||||
unsigned checksum = read(sourceData + offset + 8 + length, 4);
|
|
||||||
|
|
||||||
if(fourCC == (unsigned)FourCC::IHDR) {
|
|
||||||
info.width = read(sourceData + offset + 8, 4);
|
|
||||||
info.height = read(sourceData + offset + 12, 4);
|
|
||||||
info.bitDepth = read(sourceData + offset + 16, 1);
|
|
||||||
info.colorType = read(sourceData + offset + 17, 1);
|
|
||||||
info.compressionMethod = read(sourceData + offset + 18, 1);
|
|
||||||
info.filterType = read(sourceData + offset + 19, 1);
|
|
||||||
info.interlaceMethod = read(sourceData + offset + 20, 1);
|
|
||||||
|
|
||||||
if(info.bitDepth == 0 || info.bitDepth > 16) return false;
|
|
||||||
if(info.bitDepth & (info.bitDepth - 1)) return false; //not a power of two
|
|
||||||
if(info.compressionMethod != 0) return false;
|
|
||||||
if(info.filterType != 0) return false;
|
|
||||||
if(info.interlaceMethod != 0 && info.interlaceMethod != 1) return false;
|
|
||||||
|
|
||||||
switch(info.colorType) {
|
|
||||||
case 0: info.bytesPerPixel = info.bitDepth * 1; break; //L
|
|
||||||
case 2: info.bytesPerPixel = info.bitDepth * 3; break; //R,G,B
|
|
||||||
case 3: info.bytesPerPixel = info.bitDepth * 1; break; //P
|
|
||||||
case 4: info.bytesPerPixel = info.bitDepth * 2; break; //L,A
|
|
||||||
case 6: info.bytesPerPixel = info.bitDepth * 4; break; //R,G,B,A
|
|
||||||
default: return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
if(info.colorType == 2 || info.colorType == 4 || info.colorType == 6)
|
|
||||||
if(info.bitDepth != 8 && info.bitDepth != 16) return false;
|
|
||||||
if(info.colorType == 3 && info.bitDepth == 16) return false;
|
|
||||||
|
|
||||||
info.bytesPerPixel = (info.bytesPerPixel + 7) / 8;
|
|
||||||
info.pitch = (int)info.width * info.bytesPerPixel;
|
|
||||||
}
|
|
||||||
|
|
||||||
if(fourCC == (unsigned)FourCC::PLTE) {
|
|
||||||
if(length % 3) return false;
|
|
||||||
for(unsigned n = 0, p = offset + 8; n < length / 3; n++) {
|
|
||||||
info.palette[n][0] = sourceData[p++];
|
|
||||||
info.palette[n][1] = sourceData[p++];
|
|
||||||
info.palette[n][2] = sourceData[p++];
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if(fourCC == (unsigned)FourCC::IDAT) {
|
|
||||||
compressedData = (uint8_t*)realloc(compressedData, compressedSize + length);
|
|
||||||
memcpy(compressedData + compressedSize, sourceData + offset + 8, length);
|
|
||||||
compressedSize += length;
|
|
||||||
}
|
|
||||||
|
|
||||||
if(fourCC == (unsigned)FourCC::IEND) {
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
offset += 4 + 4 + length + 4;
|
|
||||||
}
|
|
||||||
|
|
||||||
unsigned interlacedSize = inflateSize();
|
|
||||||
uint8_t *interlacedData = new uint8_t[interlacedSize];
|
|
||||||
|
|
||||||
bool result = inflate(interlacedData, interlacedSize, compressedData + 2, compressedSize - 6);
|
|
||||||
delete[] compressedData;
|
|
||||||
|
|
||||||
if(result == false) {
|
|
||||||
delete[] interlacedData;
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
size = info.width * info.height * info.bytesPerPixel;
|
|
||||||
data = new uint8_t[size];
|
|
||||||
|
|
||||||
if(info.interlaceMethod == 0) {
|
|
||||||
if(filter(data, interlacedData, info.width, info.height) == false) {
|
|
||||||
delete[] interlacedData;
|
|
||||||
delete[] data;
|
|
||||||
data = nullptr;
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
const uint8_t *passData = interlacedData;
|
|
||||||
for(unsigned pass = 0; pass < 7; pass++) {
|
|
||||||
if(deinterlace(passData, pass) == false) {
|
|
||||||
delete[] interlacedData;
|
|
||||||
delete[] data;
|
|
||||||
data = nullptr;
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
delete[] interlacedData;
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
unsigned png::interlace(unsigned pass, unsigned index) {
|
|
||||||
static const unsigned data[7][4] = {
|
|
||||||
//x-distance, y-distance, x-origin, y-origin
|
|
||||||
{8, 8, 0, 0},
|
|
||||||
{8, 8, 4, 0},
|
|
||||||
{4, 8, 0, 4},
|
|
||||||
{4, 4, 2, 0},
|
|
||||||
{2, 4, 0, 2},
|
|
||||||
{2, 2, 1, 0},
|
|
||||||
{1, 2, 0, 1},
|
|
||||||
};
|
|
||||||
return data[pass][index];
|
|
||||||
}
|
|
||||||
|
|
||||||
unsigned png::inflateSize() {
|
|
||||||
if(info.interlaceMethod == 0) {
|
|
||||||
return info.width * info.height * info.bytesPerPixel + info.height;
|
|
||||||
}
|
|
||||||
|
|
||||||
unsigned size = 0;
|
|
||||||
for(unsigned pass = 0; pass < 7; pass++) {
|
|
||||||
unsigned xd = interlace(pass, 0), yd = interlace(pass, 1);
|
|
||||||
unsigned xo = interlace(pass, 2), yo = interlace(pass, 3);
|
|
||||||
unsigned width = (info.width + (xd - xo - 1)) / xd;
|
|
||||||
unsigned height = (info.height + (yd - yo - 1)) / yd;
|
|
||||||
if(width == 0 || height == 0) continue;
|
|
||||||
size += width * height * info.bytesPerPixel + height;
|
|
||||||
}
|
|
||||||
return size;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool png::deinterlace(const uint8_t *&inputData, unsigned pass) {
|
|
||||||
unsigned xd = interlace(pass, 0), yd = interlace(pass, 1);
|
|
||||||
unsigned xo = interlace(pass, 2), yo = interlace(pass, 3);
|
|
||||||
unsigned width = (info.width + (xd - xo - 1)) / xd;
|
|
||||||
unsigned height = (info.height + (yd - yo - 1)) / yd;
|
|
||||||
if(width == 0 || height == 0) return true;
|
|
||||||
|
|
||||||
unsigned outputSize = width * height * info.bytesPerPixel;
|
|
||||||
uint8_t *outputData = new uint8_t[outputSize];
|
|
||||||
bool result = filter(outputData, inputData, width, height);
|
|
||||||
|
|
||||||
const uint8_t *rd = outputData;
|
|
||||||
for(unsigned y = yo; y < info.height; y += yd) {
|
|
||||||
uint8_t *wr = data + y * info.pitch;
|
|
||||||
for(unsigned x = xo; x < info.width; x += xd) {
|
|
||||||
for(unsigned b = 0; b < info.bytesPerPixel; b++) {
|
|
||||||
wr[x * info.bytesPerPixel + b] = *rd++;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
inputData += outputSize + height;
|
|
||||||
delete[] outputData;
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool png::filter(uint8_t *outputData, const uint8_t *inputData, unsigned width, unsigned height) {
|
|
||||||
uint8_t *wr = outputData;
|
|
||||||
const uint8_t *rd = inputData;
|
|
||||||
int bpp = info.bytesPerPixel, pitch = width * bpp;
|
|
||||||
for(int y = 0; y < height; y++) {
|
|
||||||
uint8_t filter = *rd++;
|
|
||||||
|
|
||||||
switch(filter) {
|
|
||||||
case 0x00: //None
|
|
||||||
for(int x = 0; x < pitch; x++) {
|
|
||||||
wr[x] = rd[x];
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
|
|
||||||
case 0x01: //Subtract
|
|
||||||
for(int x = 0; x < pitch; x++) {
|
|
||||||
wr[x] = rd[x] + (x - bpp < 0 ? 0 : wr[x - bpp]);
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
|
|
||||||
case 0x02: //Above
|
|
||||||
for(int x = 0; x < pitch; x++) {
|
|
||||||
wr[x] = rd[x] + (y - 1 < 0 ? 0 : wr[x - pitch]);
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
|
|
||||||
case 0x03: //Average
|
|
||||||
for(int x = 0; x < pitch; x++) {
|
|
||||||
short a = x - bpp < 0 ? 0 : wr[x - bpp];
|
|
||||||
short b = y - 1 < 0 ? 0 : wr[x - pitch];
|
|
||||||
|
|
||||||
wr[x] = rd[x] + (uint8_t)((a + b) / 2);
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
|
|
||||||
case 0x04: //Paeth
|
|
||||||
for(int x = 0; x < pitch; x++) {
|
|
||||||
short a = x - bpp < 0 ? 0 : wr[x - bpp];
|
|
||||||
short b = y - 1 < 0 ? 0 : wr[x - pitch];
|
|
||||||
short c = x - bpp < 0 || y - 1 < 0 ? 0 : wr[x - pitch - bpp];
|
|
||||||
|
|
||||||
short p = a + b - c;
|
|
||||||
short pa = p > a ? p - a : a - p;
|
|
||||||
short pb = p > b ? p - b : b - p;
|
|
||||||
short pc = p > c ? p - c : c - p;
|
|
||||||
|
|
||||||
uint8_t paeth = (uint8_t)((pa <= pb && pa <= pc) ? a : (pb <= pc) ? b : c);
|
|
||||||
|
|
||||||
wr[x] = rd[x] + paeth;
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
|
|
||||||
default: //Invalid
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
rd += pitch;
|
|
||||||
wr += pitch;
|
|
||||||
}
|
|
||||||
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
unsigned png::read(const uint8_t *data, unsigned length) {
|
|
||||||
unsigned result = 0;
|
|
||||||
while(length--) result = (result << 8) | (*data++);
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
unsigned png::readbits(const uint8_t *&data) {
|
|
||||||
unsigned result = 0;
|
|
||||||
switch(info.bitDepth) {
|
|
||||||
case 1:
|
|
||||||
result = (*data >> bitpos) & 1;
|
|
||||||
bitpos++;
|
|
||||||
if(bitpos == 8) { data++; bitpos = 0; }
|
|
||||||
break;
|
|
||||||
case 2:
|
|
||||||
result = (*data >> bitpos) & 3;
|
|
||||||
bitpos += 2;
|
|
||||||
if(bitpos == 8) { data++; bitpos = 0; }
|
|
||||||
break;
|
|
||||||
case 4:
|
|
||||||
result = (*data >> bitpos) & 15;
|
|
||||||
bitpos += 4;
|
|
||||||
if(bitpos == 8) { data++; bitpos = 0; }
|
|
||||||
break;
|
|
||||||
case 8:
|
|
||||||
result = *data++;
|
|
||||||
break;
|
|
||||||
case 16:
|
|
||||||
result = (data[0] << 8) | (data[1] << 0);
|
|
||||||
data += 2;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
png::png() : data(nullptr) {
|
|
||||||
bitpos = 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
png::~png() {
|
|
||||||
if(data) delete[] data;
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
#endif
|
|
|
@ -1,109 +0,0 @@
|
||||||
#ifndef NALL_PRIORITY_QUEUE_HPP
|
|
||||||
#define NALL_PRIORITY_QUEUE_HPP
|
|
||||||
|
|
||||||
#include <limits>
|
|
||||||
#include <nall/function.hpp>
|
|
||||||
#include <nall/serializer.hpp>
|
|
||||||
#include <nall/utility.hpp>
|
|
||||||
|
|
||||||
namespace nall {
|
|
||||||
template<typename type_t> void priority_queue_nocallback(type_t) {}
|
|
||||||
|
|
||||||
//priority queue implementation using binary min-heap array;
|
|
||||||
//does not require normalize() function.
|
|
||||||
//O(1) find (tick)
|
|
||||||
//O(log n) append (enqueue)
|
|
||||||
//O(log n) remove (dequeue)
|
|
||||||
template<typename type_t> class priority_queue {
|
|
||||||
public:
|
|
||||||
inline void tick(unsigned ticks) {
|
|
||||||
basecounter += ticks;
|
|
||||||
while(heapsize && gte(basecounter, heap[0].counter)) callback(dequeue());
|
|
||||||
}
|
|
||||||
|
|
||||||
//counter is relative to current time (eg enqueue(64, ...) fires in 64 ticks);
|
|
||||||
//counter cannot exceed std::numeric_limits<unsigned>::max() >> 1.
|
|
||||||
void enqueue(unsigned counter, type_t event) {
|
|
||||||
unsigned child = heapsize++;
|
|
||||||
counter += basecounter;
|
|
||||||
|
|
||||||
while(child) {
|
|
||||||
unsigned parent = (child - 1) >> 1;
|
|
||||||
if(gte(counter, heap[parent].counter)) break;
|
|
||||||
|
|
||||||
heap[child].counter = heap[parent].counter;
|
|
||||||
heap[child].event = heap[parent].event;
|
|
||||||
child = parent;
|
|
||||||
}
|
|
||||||
|
|
||||||
heap[child].counter = counter;
|
|
||||||
heap[child].event = event;
|
|
||||||
}
|
|
||||||
|
|
||||||
type_t dequeue() {
|
|
||||||
type_t event(heap[0].event);
|
|
||||||
unsigned parent = 0;
|
|
||||||
unsigned counter = heap[--heapsize].counter;
|
|
||||||
|
|
||||||
while(true) {
|
|
||||||
unsigned child = (parent << 1) + 1;
|
|
||||||
if(child >= heapsize) break;
|
|
||||||
if(child + 1 < heapsize && gte(heap[child].counter, heap[child + 1].counter)) child++;
|
|
||||||
if(gte(heap[child].counter, counter)) break;
|
|
||||||
|
|
||||||
heap[parent].counter = heap[child].counter;
|
|
||||||
heap[parent].event = heap[child].event;
|
|
||||||
parent = child;
|
|
||||||
}
|
|
||||||
|
|
||||||
heap[parent].counter = counter;
|
|
||||||
heap[parent].event = heap[heapsize].event;
|
|
||||||
return event;
|
|
||||||
}
|
|
||||||
|
|
||||||
void reset() {
|
|
||||||
basecounter = 0;
|
|
||||||
heapsize = 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
void serialize(serializer &s) {
|
|
||||||
s.integer(basecounter);
|
|
||||||
s.integer(heapsize);
|
|
||||||
for(unsigned n = 0; n < heapcapacity; n++) {
|
|
||||||
s.integer(heap[n].counter);
|
|
||||||
s.integer(heap[n].event);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
priority_queue(unsigned size, function<void (type_t)> callback_ = &priority_queue_nocallback<type_t>)
|
|
||||||
: callback(callback_) {
|
|
||||||
heap = new heap_t[size];
|
|
||||||
heapcapacity = size;
|
|
||||||
reset();
|
|
||||||
}
|
|
||||||
|
|
||||||
~priority_queue() {
|
|
||||||
delete[] heap;
|
|
||||||
}
|
|
||||||
|
|
||||||
priority_queue& operator=(const priority_queue&) = delete;
|
|
||||||
priority_queue(const priority_queue&) = delete;
|
|
||||||
|
|
||||||
private:
|
|
||||||
function<void (type_t)> callback;
|
|
||||||
unsigned basecounter;
|
|
||||||
unsigned heapsize;
|
|
||||||
unsigned heapcapacity;
|
|
||||||
struct heap_t {
|
|
||||||
unsigned counter;
|
|
||||||
type_t event;
|
|
||||||
} *heap;
|
|
||||||
|
|
||||||
//return true if x is greater than or equal to y
|
|
||||||
inline bool gte(unsigned x, unsigned y) {
|
|
||||||
return x - y < (std::numeric_limits<unsigned>::max() >> 1);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
#endif
|
|
|
@ -1,83 +0,0 @@
|
||||||
#ifndef NALL_PROPERTY_HPP
|
|
||||||
#define NALL_PROPERTY_HPP
|
|
||||||
|
|
||||||
//nall::property implements ownership semantics into container classes
|
|
||||||
//example: property<owner>::readonly<type> implies that only owner has full
|
|
||||||
//access to type; and all other code has readonly access.
|
|
||||||
//
|
|
||||||
//property can be used either of two ways:
|
|
||||||
//struct foo {
|
|
||||||
// property<foo>::readonly<bool> x;
|
|
||||||
// property<foo>::readwrite<int> y;
|
|
||||||
//};
|
|
||||||
//-or-
|
|
||||||
//struct foo : property<foo> {
|
|
||||||
// readonly<bool> x;
|
|
||||||
// readwrite<int> y;
|
|
||||||
//};
|
|
||||||
|
|
||||||
//return types are const T& (byref) instead of T (byval) to avoid major speed
|
|
||||||
//penalties for objects with expensive copy constructors
|
|
||||||
|
|
||||||
//operator-> provides access to underlying object type:
|
|
||||||
//readonly<Object> foo;
|
|
||||||
//foo->bar();
|
|
||||||
//... will call Object::bar();
|
|
||||||
|
|
||||||
//operator='s reference is constant so as to avoid leaking a reference handle
|
|
||||||
//that could bypass access restrictions
|
|
||||||
|
|
||||||
//both constant and non-constant operators are provided, though it may be
|
|
||||||
//necessary to cast first, for instance:
|
|
||||||
//struct foo : property<foo> { readonly<int> bar; } object;
|
|
||||||
//int main() { int value = const_cast<const foo&>(object); }
|
|
||||||
|
|
||||||
//writeonly is useful for objects that have non-const reads, but const writes.
|
|
||||||
//however, to avoid leaking handles, the interface is very restricted. the only
|
|
||||||
//way to write is via operator=, which requires conversion via eg copy
|
|
||||||
//constructor. example:
|
|
||||||
//struct foo {
|
|
||||||
// foo(bool value) { ... }
|
|
||||||
//};
|
|
||||||
//writeonly<foo> bar;
|
|
||||||
//bar = true;
|
|
||||||
|
|
||||||
namespace nall {
|
|
||||||
template<typename C> struct property {
|
|
||||||
template<typename T> struct readonly {
|
|
||||||
const T* operator->() const { return &value; }
|
|
||||||
const T& operator()() const { return value; }
|
|
||||||
operator const T&() const { return value; }
|
|
||||||
private:
|
|
||||||
T* operator->() { return &value; }
|
|
||||||
operator T&() { return value; }
|
|
||||||
const T& operator=(const T& value_) { return value = value_; }
|
|
||||||
T value;
|
|
||||||
friend C;
|
|
||||||
};
|
|
||||||
|
|
||||||
template<typename T> struct writeonly {
|
|
||||||
void operator=(const T& value_) { value = value_; }
|
|
||||||
private:
|
|
||||||
const T* operator->() const { return &value; }
|
|
||||||
const T& operator()() const { return value; }
|
|
||||||
operator const T&() const { return value; }
|
|
||||||
T* operator->() { return &value; }
|
|
||||||
operator T&() { return value; }
|
|
||||||
T value;
|
|
||||||
friend C;
|
|
||||||
};
|
|
||||||
|
|
||||||
template<typename T> struct readwrite {
|
|
||||||
const T* operator->() const { return &value; }
|
|
||||||
const T& operator()() const { return value; }
|
|
||||||
operator const T&() const { return value; }
|
|
||||||
T* operator->() { return &value; }
|
|
||||||
operator T&() { return value; }
|
|
||||||
const T& operator=(const T& value_) { return value = value_; }
|
|
||||||
T value;
|
|
||||||
};
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
#endif
|
|
|
@ -1,32 +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
|
|
|
@ -1,28 +0,0 @@
|
||||||
#ifndef NALL_RANDOM_HPP
|
|
||||||
#define NALL_RANDOM_HPP
|
|
||||||
|
|
||||||
namespace nall {
|
|
||||||
//pseudo-random number generator
|
|
||||||
inline unsigned prng() {
|
|
||||||
static unsigned n = 0;
|
|
||||||
return n = (n >> 1) ^ (((n & 1) - 1) & 0xedb88320);
|
|
||||||
}
|
|
||||||
|
|
||||||
struct random_lfsr {
|
|
||||||
inline void seed(unsigned seed__) {
|
|
||||||
seed_ = seed__;
|
|
||||||
}
|
|
||||||
|
|
||||||
inline unsigned operator()() {
|
|
||||||
return seed_ = (seed_ >> 1) ^ (((seed_ & 1) - 1) & 0xedb88320);
|
|
||||||
}
|
|
||||||
|
|
||||||
random_lfsr() : seed_(0) {
|
|
||||||
}
|
|
||||||
|
|
||||||
private:
|
|
||||||
unsigned seed_;
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
#endif
|
|
|
@ -1,110 +0,0 @@
|
||||||
#ifndef NALL_SERIAL_HPP
|
|
||||||
#define NALL_SERIAL_HPP
|
|
||||||
|
|
||||||
#include <sys/ioctl.h>
|
|
||||||
#include <fcntl.h>
|
|
||||||
#include <termios.h>
|
|
||||||
#include <unistd.h>
|
|
||||||
|
|
||||||
#include <nall/stdint.hpp>
|
|
||||||
|
|
||||||
namespace nall {
|
|
||||||
struct serial {
|
|
||||||
bool readable() {
|
|
||||||
if(port_open == false) return false;
|
|
||||||
fd_set fdset;
|
|
||||||
FD_ZERO(&fdset);
|
|
||||||
FD_SET(port, &fdset);
|
|
||||||
timeval timeout;
|
|
||||||
timeout.tv_sec = 0;
|
|
||||||
timeout.tv_usec = 0;
|
|
||||||
int result = select(FD_SETSIZE, &fdset, nullptr, nullptr, &timeout);
|
|
||||||
if(result < 1) return false;
|
|
||||||
return FD_ISSET(port, &fdset);
|
|
||||||
}
|
|
||||||
|
|
||||||
//-1 on error, otherwise return bytes read
|
|
||||||
int read(uint8_t *data, unsigned length) {
|
|
||||||
if(port_open == false) return -1;
|
|
||||||
return ::read(port, (void*)data, length);
|
|
||||||
}
|
|
||||||
|
|
||||||
bool writable() {
|
|
||||||
if(port_open == false) return false;
|
|
||||||
fd_set fdset;
|
|
||||||
FD_ZERO(&fdset);
|
|
||||||
FD_SET(port, &fdset);
|
|
||||||
timeval timeout;
|
|
||||||
timeout.tv_sec = 0;
|
|
||||||
timeout.tv_usec = 0;
|
|
||||||
int result = select(FD_SETSIZE, nullptr, &fdset, nullptr, &timeout);
|
|
||||||
if(result < 1) return false;
|
|
||||||
return FD_ISSET(port, &fdset);
|
|
||||||
}
|
|
||||||
|
|
||||||
//-1 on error, otherwise return bytes written
|
|
||||||
int write(const uint8_t *data, unsigned length) {
|
|
||||||
if(port_open == false) return -1;
|
|
||||||
return ::write(port, (void*)data, length);
|
|
||||||
}
|
|
||||||
|
|
||||||
bool open(const char *portname, unsigned rate, bool flowcontrol) {
|
|
||||||
close();
|
|
||||||
|
|
||||||
port = ::open(portname, O_RDWR | O_NOCTTY | O_NDELAY | O_NONBLOCK);
|
|
||||||
if(port == -1) return false;
|
|
||||||
|
|
||||||
if(ioctl(port, TIOCEXCL) == -1) { close(); return false; }
|
|
||||||
if(fcntl(port, F_SETFL, 0) == -1) { close(); return false; }
|
|
||||||
if(tcgetattr(port, &original_attr) == -1) { close(); return false; }
|
|
||||||
|
|
||||||
termios attr = original_attr;
|
|
||||||
cfmakeraw(&attr);
|
|
||||||
cfsetspeed(&attr, rate);
|
|
||||||
|
|
||||||
attr.c_lflag &=~ (ECHO | ECHONL | ISIG | ICANON | IEXTEN);
|
|
||||||
attr.c_iflag &=~ (BRKINT | PARMRK | INPCK | ISTRIP | INLCR | IGNCR | ICRNL | IXON | IXOFF | IXANY);
|
|
||||||
attr.c_iflag |= (IGNBRK | IGNPAR);
|
|
||||||
attr.c_oflag &=~ (OPOST);
|
|
||||||
attr.c_cflag &=~ (CSIZE | CSTOPB | PARENB | CLOCAL);
|
|
||||||
attr.c_cflag |= (CS8 | CREAD);
|
|
||||||
if(flowcontrol == false) {
|
|
||||||
attr.c_cflag &= ~CRTSCTS;
|
|
||||||
} else {
|
|
||||||
attr.c_cflag |= CRTSCTS;
|
|
||||||
}
|
|
||||||
attr.c_cc[VTIME] = attr.c_cc[VMIN] = 0;
|
|
||||||
|
|
||||||
if(tcsetattr(port, TCSANOW, &attr) == -1) { close(); return false; }
|
|
||||||
return port_open = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
void close() {
|
|
||||||
if(port != -1) {
|
|
||||||
tcdrain(port);
|
|
||||||
if(port_open == true) {
|
|
||||||
tcsetattr(port, TCSANOW, &original_attr);
|
|
||||||
port_open = false;
|
|
||||||
}
|
|
||||||
::close(port);
|
|
||||||
port = -1;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
serial() {
|
|
||||||
port = -1;
|
|
||||||
port_open = false;
|
|
||||||
}
|
|
||||||
|
|
||||||
~serial() {
|
|
||||||
close();
|
|
||||||
}
|
|
||||||
|
|
||||||
private:
|
|
||||||
int port;
|
|
||||||
bool port_open;
|
|
||||||
termios original_attr;
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
#endif
|
|
|
@ -1,146 +0,0 @@
|
||||||
#ifndef NALL_SERIALIZER_HPP
|
|
||||||
#define NALL_SERIALIZER_HPP
|
|
||||||
|
|
||||||
#include <type_traits>
|
|
||||||
#include <utility>
|
|
||||||
#include <nall/stdint.hpp>
|
|
||||||
#include <nall/utility.hpp>
|
|
||||||
|
|
||||||
namespace nall {
|
|
||||||
//serializer: a class designed to save and restore the state of classes.
|
|
||||||
//
|
|
||||||
//benefits:
|
|
||||||
//- data() will be portable in size (it is not necessary to specify type sizes.)
|
|
||||||
//- data() will be portable in endianness (always stored internally as little-endian.)
|
|
||||||
//- one serialize function can both save and restore class states.
|
|
||||||
//
|
|
||||||
//caveats:
|
|
||||||
//- only plain-old-data can be stored. complex classes must provide serialize(serializer&);
|
|
||||||
//- floating-point usage is not portable across platforms
|
|
||||||
|
|
||||||
class serializer {
|
|
||||||
public:
|
|
||||||
enum mode_t { Load, Save, Size };
|
|
||||||
|
|
||||||
mode_t mode() const {
|
|
||||||
return imode;
|
|
||||||
}
|
|
||||||
|
|
||||||
const uint8_t* data() const {
|
|
||||||
return idata;
|
|
||||||
}
|
|
||||||
|
|
||||||
unsigned size() const {
|
|
||||||
return isize;
|
|
||||||
}
|
|
||||||
|
|
||||||
unsigned capacity() const {
|
|
||||||
return icapacity;
|
|
||||||
}
|
|
||||||
|
|
||||||
template<typename T> void floatingpoint(T &value) {
|
|
||||||
enum { size = sizeof(T) };
|
|
||||||
//this is rather dangerous, and not cross-platform safe;
|
|
||||||
//but there is no standardized way to export FP-values
|
|
||||||
uint8_t *p = (uint8_t*)&value;
|
|
||||||
if(imode == Save) {
|
|
||||||
for(unsigned n = 0; n < size; n++) idata[isize++] = p[n];
|
|
||||||
} else if(imode == Load) {
|
|
||||||
for(unsigned n = 0; n < size; n++) p[n] = idata[isize++];
|
|
||||||
} else {
|
|
||||||
isize += size;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
template<typename T> void integer(T &value) {
|
|
||||||
enum { size = std::is_same<bool, T>::value ? 1 : sizeof(T) };
|
|
||||||
if(imode == Save) {
|
|
||||||
for(unsigned n = 0; n < size; n++) idata[isize++] = (uintmax_t)value >> (n << 3);
|
|
||||||
} else if(imode == Load) {
|
|
||||||
value = 0;
|
|
||||||
for(unsigned n = 0; n < size; n++) value |= (uintmax_t)idata[isize++] << (n << 3);
|
|
||||||
} else if(imode == Size) {
|
|
||||||
isize += size;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
template<typename T> void array(T &array) {
|
|
||||||
enum { size = sizeof(T) / sizeof(typename std::remove_extent<T>::type) };
|
|
||||||
for(unsigned n = 0; n < size; n++) integer(array[n]);
|
|
||||||
}
|
|
||||||
|
|
||||||
template<typename T> void array(T array, unsigned size) {
|
|
||||||
for(unsigned n = 0; n < size; n++) integer(array[n]);
|
|
||||||
}
|
|
||||||
|
|
||||||
//copy
|
|
||||||
serializer& operator=(const serializer &s) {
|
|
||||||
if(idata) delete[] idata;
|
|
||||||
|
|
||||||
imode = s.imode;
|
|
||||||
idata = new uint8_t[s.icapacity];
|
|
||||||
isize = s.isize;
|
|
||||||
icapacity = s.icapacity;
|
|
||||||
|
|
||||||
memcpy(idata, s.idata, s.icapacity);
|
|
||||||
return *this;
|
|
||||||
}
|
|
||||||
|
|
||||||
serializer(const serializer &s) : idata(nullptr) {
|
|
||||||
operator=(s);
|
|
||||||
}
|
|
||||||
|
|
||||||
//move
|
|
||||||
serializer& operator=(serializer &&s) {
|
|
||||||
if(idata) delete[] idata;
|
|
||||||
|
|
||||||
imode = s.imode;
|
|
||||||
idata = s.idata;
|
|
||||||
isize = s.isize;
|
|
||||||
icapacity = s.icapacity;
|
|
||||||
|
|
||||||
s.idata = nullptr;
|
|
||||||
return *this;
|
|
||||||
}
|
|
||||||
|
|
||||||
serializer(serializer &&s) {
|
|
||||||
operator=(std::move(s));
|
|
||||||
}
|
|
||||||
|
|
||||||
//construction
|
|
||||||
serializer() {
|
|
||||||
imode = Size;
|
|
||||||
idata = nullptr;
|
|
||||||
isize = 0;
|
|
||||||
icapacity = 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
serializer(unsigned capacity) {
|
|
||||||
imode = Save;
|
|
||||||
idata = new uint8_t[capacity]();
|
|
||||||
isize = 0;
|
|
||||||
icapacity = capacity;
|
|
||||||
}
|
|
||||||
|
|
||||||
serializer(const uint8_t *data, unsigned capacity) {
|
|
||||||
imode = Load;
|
|
||||||
idata = new uint8_t[capacity];
|
|
||||||
isize = 0;
|
|
||||||
icapacity = capacity;
|
|
||||||
memcpy(idata, data, capacity);
|
|
||||||
}
|
|
||||||
|
|
||||||
~serializer() {
|
|
||||||
if(idata) delete[] idata;
|
|
||||||
}
|
|
||||||
|
|
||||||
private:
|
|
||||||
mode_t imode;
|
|
||||||
uint8_t *idata;
|
|
||||||
unsigned isize;
|
|
||||||
unsigned icapacity;
|
|
||||||
};
|
|
||||||
|
|
||||||
};
|
|
||||||
|
|
||||||
#endif
|
|
|
@ -1,158 +0,0 @@
|
||||||
#ifndef NALL_SET_HPP
|
|
||||||
#define NALL_SET_HPP
|
|
||||||
|
|
||||||
//set
|
|
||||||
//* unordered
|
|
||||||
//* intended for unique items
|
|
||||||
//* dynamic growth
|
|
||||||
//* reference-based variant
|
|
||||||
|
|
||||||
#include <stdlib.h>
|
|
||||||
#include <algorithm>
|
|
||||||
#include <initializer_list>
|
|
||||||
#include <utility>
|
|
||||||
#include <nall/algorithm.hpp>
|
|
||||||
#include <nall/bit.hpp>
|
|
||||||
#include <nall/sort.hpp>
|
|
||||||
#include <nall/traits.hpp>
|
|
||||||
#include <nall/utility.hpp>
|
|
||||||
|
|
||||||
namespace nall {
|
|
||||||
|
|
||||||
template<typename T, typename Enable = void> struct set;
|
|
||||||
|
|
||||||
template<typename T> struct set<T, typename std::enable_if<!std::is_reference<T>::value>::type> {
|
|
||||||
struct exception_out_of_bounds{};
|
|
||||||
|
|
||||||
protected:
|
|
||||||
T *pool;
|
|
||||||
unsigned poolsize, objectsize;
|
|
||||||
|
|
||||||
public:
|
|
||||||
unsigned size() const { return objectsize; }
|
|
||||||
unsigned capacity() const { return poolsize; }
|
|
||||||
};
|
|
||||||
|
|
||||||
//reference set
|
|
||||||
template<typename TR> struct set<TR, typename std::enable_if<std::is_reference<TR>::value>::type> {
|
|
||||||
struct exception_out_of_bounds{};
|
|
||||||
|
|
||||||
protected:
|
|
||||||
typedef typename std::remove_reference<TR>::type T;
|
|
||||||
T **pool;
|
|
||||||
unsigned poolsize, objectsize;
|
|
||||||
|
|
||||||
public:
|
|
||||||
unsigned size() const { return objectsize; }
|
|
||||||
unsigned capacity() const { return poolsize; }
|
|
||||||
|
|
||||||
void reset() {
|
|
||||||
if(pool) free(pool);
|
|
||||||
pool = nullptr;
|
|
||||||
poolsize = 0;
|
|
||||||
objectsize = 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
void reserve(unsigned size) {
|
|
||||||
if(size == poolsize) return;
|
|
||||||
pool = (T**)realloc(pool, sizeof(T*) * size);
|
|
||||||
poolsize = size;
|
|
||||||
objectsize = min(objectsize, size);
|
|
||||||
}
|
|
||||||
|
|
||||||
void resize(unsigned size) {
|
|
||||||
if(size > poolsize) reserve(bit::round(size)); //amortize growth
|
|
||||||
objectsize = size;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool append(T& data) {
|
|
||||||
if(find(data)) return false;
|
|
||||||
unsigned offset = objectsize++;
|
|
||||||
if(offset >= poolsize) resize(offset + 1);
|
|
||||||
pool[offset] = &data;
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
template<typename... Args>
|
|
||||||
bool append(T& data, Args&&... args) {
|
|
||||||
bool result = append(data);
|
|
||||||
append(std::forward<Args>(args)...);
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool remove(T& data) {
|
|
||||||
if(auto position = find(data)) {
|
|
||||||
for(signed i = position(); i < objectsize - 1; i++) pool[i] = pool[i + 1];
|
|
||||||
resize(objectsize - 1);
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
optional<unsigned> find(const T& data) {
|
|
||||||
for(unsigned n = 0; n < objectsize; n++) if(pool[n] == &data) return {true, n};
|
|
||||||
return {false, 0u};
|
|
||||||
}
|
|
||||||
|
|
||||||
template<typename... Args> set(Args&&... args) : pool(nullptr), poolsize(0), objectsize(0) {
|
|
||||||
construct(std::forward<Args>(args)...);
|
|
||||||
}
|
|
||||||
|
|
||||||
~set() {
|
|
||||||
reset();
|
|
||||||
}
|
|
||||||
|
|
||||||
set& operator=(const set &source) {
|
|
||||||
if(&source == this) return *this;
|
|
||||||
if(pool) free(pool);
|
|
||||||
objectsize = source.objectsize;
|
|
||||||
poolsize = source.poolsize;
|
|
||||||
pool = (T**)malloc(sizeof(T*) * poolsize);
|
|
||||||
memcpy(pool, source.pool, sizeof(T*) * objectsize);
|
|
||||||
return *this;
|
|
||||||
}
|
|
||||||
|
|
||||||
set& operator=(const set &&source) {
|
|
||||||
if(&source == this) return *this;
|
|
||||||
if(pool) free(pool);
|
|
||||||
pool = source.pool;
|
|
||||||
poolsize = source.poolsize;
|
|
||||||
objectsize = source.objectsize;
|
|
||||||
source.pool = nullptr;
|
|
||||||
source.reset();
|
|
||||||
return *this;
|
|
||||||
}
|
|
||||||
|
|
||||||
T& operator[](unsigned position) const {
|
|
||||||
if(position >= objectsize) throw exception_out_of_bounds();
|
|
||||||
return *pool[position];
|
|
||||||
}
|
|
||||||
|
|
||||||
struct iterator {
|
|
||||||
bool operator!=(const iterator &source) const { return position != source.position; }
|
|
||||||
T& operator*() { return source.operator[](position); }
|
|
||||||
iterator& operator++() { position++; return *this; }
|
|
||||||
iterator(const set &source, unsigned position) : source(source), position(position) {}
|
|
||||||
private:
|
|
||||||
const set &source;
|
|
||||||
unsigned position;
|
|
||||||
};
|
|
||||||
|
|
||||||
iterator begin() { return iterator(*this, 0); }
|
|
||||||
iterator end() { return iterator(*this, objectsize); }
|
|
||||||
const iterator begin() const { return iterator(*this, 0); }
|
|
||||||
const iterator end() const { return iterator(*this, objectsize); }
|
|
||||||
|
|
||||||
private:
|
|
||||||
void construct() {}
|
|
||||||
void construct(const set &source) { operator=(source); }
|
|
||||||
void construct(const set &&source) { operator=(std::move(source)); }
|
|
||||||
template<typename... Args> void construct(T& data, Args&&... args) {
|
|
||||||
append(data);
|
|
||||||
construct(std::forward<Args>(args)...);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
#endif
|
|
|
@ -1,145 +0,0 @@
|
||||||
#ifndef NALL_SHA256_HPP
|
|
||||||
#define NALL_SHA256_HPP
|
|
||||||
|
|
||||||
//author: vladitx
|
|
||||||
|
|
||||||
#include <nall/stdint.hpp>
|
|
||||||
|
|
||||||
namespace nall {
|
|
||||||
#define PTR(t, a) ((t*)(a))
|
|
||||||
|
|
||||||
#define SWAP32(x) ((uint32_t)( \
|
|
||||||
(((uint32_t)(x) & 0x000000ff) << 24) | \
|
|
||||||
(((uint32_t)(x) & 0x0000ff00) << 8) | \
|
|
||||||
(((uint32_t)(x) & 0x00ff0000) >> 8) | \
|
|
||||||
(((uint32_t)(x) & 0xff000000) >> 24) \
|
|
||||||
))
|
|
||||||
|
|
||||||
#define ST32(a, d) *PTR(uint32_t, a) = (d)
|
|
||||||
#define ST32BE(a, d) ST32(a, SWAP32(d))
|
|
||||||
|
|
||||||
#define LD32(a) *PTR(uint32_t, a)
|
|
||||||
#define LD32BE(a) SWAP32(LD32(a))
|
|
||||||
|
|
||||||
#define LSL32(x, n) ((uint32_t)(x) << (n))
|
|
||||||
#define LSR32(x, n) ((uint32_t)(x) >> (n))
|
|
||||||
#define ROR32(x, n) (LSR32(x, n) | LSL32(x, 32 - (n)))
|
|
||||||
|
|
||||||
//first 32 bits of the fractional parts of the square roots of the first 8 primes 2..19
|
|
||||||
static const uint32_t T_H[8] = {
|
|
||||||
0x6a09e667, 0xbb67ae85, 0x3c6ef372, 0xa54ff53a, 0x510e527f, 0x9b05688c, 0x1f83d9ab, 0x5be0cd19,
|
|
||||||
};
|
|
||||||
|
|
||||||
//first 32 bits of the fractional parts of the cube roots of the first 64 primes 2..311
|
|
||||||
static const uint32_t T_K[64] = {
|
|
||||||
0x428a2f98, 0x71374491, 0xb5c0fbcf, 0xe9b5dba5, 0x3956c25b, 0x59f111f1, 0x923f82a4, 0xab1c5ed5,
|
|
||||||
0xd807aa98, 0x12835b01, 0x243185be, 0x550c7dc3, 0x72be5d74, 0x80deb1fe, 0x9bdc06a7, 0xc19bf174,
|
|
||||||
0xe49b69c1, 0xefbe4786, 0x0fc19dc6, 0x240ca1cc, 0x2de92c6f, 0x4a7484aa, 0x5cb0a9dc, 0x76f988da,
|
|
||||||
0x983e5152, 0xa831c66d, 0xb00327c8, 0xbf597fc7, 0xc6e00bf3, 0xd5a79147, 0x06ca6351, 0x14292967,
|
|
||||||
0x27b70a85, 0x2e1b2138, 0x4d2c6dfc, 0x53380d13, 0x650a7354, 0x766a0abb, 0x81c2c92e, 0x92722c85,
|
|
||||||
0xa2bfe8a1, 0xa81a664b, 0xc24b8b70, 0xc76c51a3, 0xd192e819, 0xd6990624, 0xf40e3585, 0x106aa070,
|
|
||||||
0x19a4c116, 0x1e376c08, 0x2748774c, 0x34b0bcb5, 0x391c0cb3, 0x4ed8aa4a, 0x5b9cca4f, 0x682e6ff3,
|
|
||||||
0x748f82ee, 0x78a5636f, 0x84c87814, 0x8cc70208, 0x90befffa, 0xa4506ceb, 0xbef9a3f7, 0xc67178f2,
|
|
||||||
};
|
|
||||||
|
|
||||||
struct sha256_ctx {
|
|
||||||
uint8_t in[64];
|
|
||||||
unsigned inlen;
|
|
||||||
|
|
||||||
uint32_t w[64];
|
|
||||||
uint32_t h[8];
|
|
||||||
uint64_t len;
|
|
||||||
};
|
|
||||||
|
|
||||||
inline void sha256_init(sha256_ctx *p) {
|
|
||||||
memset(p, 0, sizeof(sha256_ctx));
|
|
||||||
memcpy(p->h, T_H, sizeof(T_H));
|
|
||||||
}
|
|
||||||
|
|
||||||
static void sha256_block(sha256_ctx *p) {
|
|
||||||
unsigned i;
|
|
||||||
uint32_t s0, s1;
|
|
||||||
uint32_t a, b, c, d, e, f, g, h;
|
|
||||||
uint32_t t1, t2, maj, ch;
|
|
||||||
|
|
||||||
for(i = 0; i < 16; i++) p->w[i] = LD32BE(p->in + i * 4);
|
|
||||||
|
|
||||||
for(i = 16; i < 64; i++) {
|
|
||||||
s0 = ROR32(p->w[i - 15], 7) ^ ROR32(p->w[i - 15], 18) ^ LSR32(p->w[i - 15], 3);
|
|
||||||
s1 = ROR32(p->w[i - 2], 17) ^ ROR32(p->w[i - 2], 19) ^ LSR32(p->w[i - 2], 10);
|
|
||||||
p->w[i] = p->w[i - 16] + s0 + p->w[i - 7] + s1;
|
|
||||||
}
|
|
||||||
|
|
||||||
a = p->h[0]; b = p->h[1]; c = p->h[2]; d = p->h[3];
|
|
||||||
e = p->h[4]; f = p->h[5]; g = p->h[6]; h = p->h[7];
|
|
||||||
|
|
||||||
for(i = 0; i < 64; i++) {
|
|
||||||
s0 = ROR32(a, 2) ^ ROR32(a, 13) ^ ROR32(a, 22);
|
|
||||||
maj = (a & b) ^ (a & c) ^ (b & c);
|
|
||||||
t2 = s0 + maj;
|
|
||||||
s1 = ROR32(e, 6) ^ ROR32(e, 11) ^ ROR32(e, 25);
|
|
||||||
ch = (e & f) ^ (~e & g);
|
|
||||||
t1 = h + s1 + ch + T_K[i] + p->w[i];
|
|
||||||
|
|
||||||
h = g; g = f; f = e; e = d + t1;
|
|
||||||
d = c; c = b; b = a; a = t1 + t2;
|
|
||||||
}
|
|
||||||
|
|
||||||
p->h[0] += a; p->h[1] += b; p->h[2] += c; p->h[3] += d;
|
|
||||||
p->h[4] += e; p->h[5] += f; p->h[6] += g; p->h[7] += h;
|
|
||||||
|
|
||||||
//next block
|
|
||||||
p->inlen = 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
inline void sha256_chunk(sha256_ctx *p, const uint8_t *s, unsigned len) {
|
|
||||||
unsigned l;
|
|
||||||
p->len += len;
|
|
||||||
|
|
||||||
while(len) {
|
|
||||||
l = 64 - p->inlen;
|
|
||||||
l = (len < l) ? len : l;
|
|
||||||
|
|
||||||
memcpy(p->in + p->inlen, s, l);
|
|
||||||
s += l;
|
|
||||||
p->inlen += l;
|
|
||||||
len -= l;
|
|
||||||
|
|
||||||
if(p->inlen == 64) sha256_block(p);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
inline void sha256_final(sha256_ctx *p) {
|
|
||||||
uint64_t len;
|
|
||||||
p->in[p->inlen++] = 0x80;
|
|
||||||
|
|
||||||
if(p->inlen > 56) {
|
|
||||||
memset(p->in + p->inlen, 0, 64 - p->inlen);
|
|
||||||
sha256_block(p);
|
|
||||||
}
|
|
||||||
|
|
||||||
memset(p->in + p->inlen, 0, 56 - p->inlen);
|
|
||||||
|
|
||||||
len = p->len << 3;
|
|
||||||
ST32BE(p->in + 56, len >> 32);
|
|
||||||
ST32BE(p->in + 60, len);
|
|
||||||
sha256_block(p);
|
|
||||||
}
|
|
||||||
|
|
||||||
inline void sha256_hash(sha256_ctx *p, uint8_t *s) {
|
|
||||||
uint32_t *t = (uint32_t*)s;
|
|
||||||
for(unsigned i = 0; i < 8; i++) ST32BE(t++, p->h[i]);
|
|
||||||
}
|
|
||||||
|
|
||||||
#undef PTR
|
|
||||||
#undef SWAP32
|
|
||||||
#undef ST32
|
|
||||||
#undef ST32BE
|
|
||||||
#undef LD32
|
|
||||||
#undef LD32BE
|
|
||||||
#undef LSL32
|
|
||||||
#undef LSR32
|
|
||||||
#undef ROR32
|
|
||||||
}
|
|
||||||
|
|
||||||
#endif
|
|
|
@ -1,77 +0,0 @@
|
||||||
#ifndef NALL_SORT_HPP
|
|
||||||
#define NALL_SORT_HPP
|
|
||||||
|
|
||||||
#include <algorithm>
|
|
||||||
#include <nall/utility.hpp>
|
|
||||||
|
|
||||||
//class: merge sort
|
|
||||||
//average: O(n log n)
|
|
||||||
//worst: O(n log n)
|
|
||||||
//memory: O(n)
|
|
||||||
//stack: O(log n)
|
|
||||||
//stable?: yes
|
|
||||||
|
|
||||||
//note: merge sort was chosen over quick sort, because:
|
|
||||||
//* it is a stable sort
|
|
||||||
//* it lacks O(n^2) worst-case overhead
|
|
||||||
|
|
||||||
#define NALL_SORT_INSERTION
|
|
||||||
//#define NALL_SORT_SELECTION
|
|
||||||
|
|
||||||
namespace nall {
|
|
||||||
template<typename T, typename Comparator>
|
|
||||||
void sort(T list[], unsigned size, const Comparator &lessthan) {
|
|
||||||
if(size <= 1) return; //nothing to sort
|
|
||||||
|
|
||||||
//use insertion sort to quickly sort smaller blocks
|
|
||||||
if(size < 64) {
|
|
||||||
#if defined(NALL_SORT_INSERTION)
|
|
||||||
for(signed i = 1, j; i < size; i++) {
|
|
||||||
T copy = std::move(list[i]);
|
|
||||||
for(j = i - 1; j >= 0; j--) {
|
|
||||||
if(!lessthan(copy, list[j])) break;
|
|
||||||
list[j + 1] = std::move(list[j]);
|
|
||||||
}
|
|
||||||
list[j + 1] = std::move(copy);
|
|
||||||
}
|
|
||||||
#elif defined(NALL_SORT_SELECTION)
|
|
||||||
for(unsigned i = 0; i < size; i++) {
|
|
||||||
unsigned min = i;
|
|
||||||
for(unsigned j = i + 1; j < size; j++) {
|
|
||||||
if(lessthan(list[j], list[min])) min = j;
|
|
||||||
}
|
|
||||||
if(min != i) std::swap(list[i], list[min]);
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
//split list in half and recursively sort both
|
|
||||||
unsigned middle = size / 2;
|
|
||||||
sort(list, middle, lessthan);
|
|
||||||
sort(list + middle, size - middle, lessthan);
|
|
||||||
|
|
||||||
//left and right are sorted here; perform merge sort
|
|
||||||
T *buffer = new T[size];
|
|
||||||
unsigned offset = 0, left = 0, right = middle;
|
|
||||||
while(left < middle && right < size) {
|
|
||||||
if(!lessthan(list[right], list[left])) {
|
|
||||||
buffer[offset++] = std::move(list[left++]);
|
|
||||||
} else {
|
|
||||||
buffer[offset++] = std::move(list[right++]);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
while(left < middle) buffer[offset++] = std::move(list[left++]);
|
|
||||||
while(right < size) buffer[offset++] = std::move(list[right++]);
|
|
||||||
|
|
||||||
for(unsigned i = 0; i < size; i++) list[i] = std::move(buffer[i]);
|
|
||||||
delete[] buffer;
|
|
||||||
}
|
|
||||||
|
|
||||||
template<typename T>
|
|
||||||
void sort(T list[], unsigned size) {
|
|
||||||
return sort(list, size, [](const T &l, const T &r) { return l < r; });
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#endif
|
|
|
@ -1,42 +0,0 @@
|
||||||
#ifndef NALL_STDINT_HPP
|
|
||||||
#define NALL_STDINT_HPP
|
|
||||||
|
|
||||||
#if defined(_MSC_VER)
|
|
||||||
typedef signed char int8_t;
|
|
||||||
typedef signed short int16_t;
|
|
||||||
typedef signed int int32_t;
|
|
||||||
typedef signed long long int64_t;
|
|
||||||
typedef int64_t intmax_t;
|
|
||||||
#if defined(_WIN64)
|
|
||||||
typedef int64_t intptr_t;
|
|
||||||
#else
|
|
||||||
typedef int32_t intptr_t;
|
|
||||||
#endif
|
|
||||||
|
|
||||||
typedef unsigned char uint8_t;
|
|
||||||
typedef unsigned short uint16_t;
|
|
||||||
typedef unsigned int uint32_t;
|
|
||||||
typedef unsigned long long uint64_t;
|
|
||||||
typedef uint64_t uintmax_t;
|
|
||||||
#if defined(_WIN64)
|
|
||||||
typedef uint64_t uintptr_t;
|
|
||||||
#else
|
|
||||||
typedef uint32_t uintptr_t;
|
|
||||||
#endif
|
|
||||||
#else
|
|
||||||
#include <stdint.h>
|
|
||||||
#endif
|
|
||||||
|
|
||||||
namespace nall {
|
|
||||||
static_assert(sizeof(int8_t) == 1, "int8_t is not of the correct size" );
|
|
||||||
static_assert(sizeof(int16_t) == 2, "int16_t is not of the correct size");
|
|
||||||
static_assert(sizeof(int32_t) == 4, "int32_t is not of the correct size");
|
|
||||||
static_assert(sizeof(int64_t) == 8, "int64_t is not of the correct size");
|
|
||||||
|
|
||||||
static_assert(sizeof(uint8_t) == 1, "int8_t is not of the correct size" );
|
|
||||||
static_assert(sizeof(uint16_t) == 2, "int16_t is not of the correct size");
|
|
||||||
static_assert(sizeof(uint32_t) == 4, "int32_t is not of the correct size");
|
|
||||||
static_assert(sizeof(uint64_t) == 8, "int64_t is not of the correct size");
|
|
||||||
}
|
|
||||||
|
|
||||||
#endif
|
|
|
@ -1,26 +0,0 @@
|
||||||
#ifndef NALL_STREAM_HPP
|
|
||||||
#define NALL_STREAM_HPP
|
|
||||||
|
|
||||||
#include <algorithm>
|
|
||||||
#include <memory>
|
|
||||||
|
|
||||||
#include <nall/file.hpp>
|
|
||||||
#include <nall/filemap.hpp>
|
|
||||||
#include <nall/gzip.hpp>
|
|
||||||
#include <nall/http.hpp>
|
|
||||||
#include <nall/stdint.hpp>
|
|
||||||
#include <nall/string.hpp>
|
|
||||||
#include <nall/zip.hpp>
|
|
||||||
|
|
||||||
#define NALL_STREAM_INTERNAL_HPP
|
|
||||||
#include <nall/stream/stream.hpp>
|
|
||||||
#include <nall/stream/memory.hpp>
|
|
||||||
#include <nall/stream/mmap.hpp>
|
|
||||||
#include <nall/stream/file.hpp>
|
|
||||||
#include <nall/stream/http.hpp>
|
|
||||||
#include <nall/stream/gzip.hpp>
|
|
||||||
#include <nall/stream/zip.hpp>
|
|
||||||
#include <nall/stream/auto.hpp>
|
|
||||||
#undef NALL_STREAM_INTERNAL_HPP
|
|
||||||
|
|
||||||
#endif
|
|
|
@ -1,25 +0,0 @@
|
||||||
#ifndef NALL_STREAM_AUTO_HPP
|
|
||||||
#define NALL_STREAM_AUTO_HPP
|
|
||||||
|
|
||||||
namespace nall {
|
|
||||||
|
|
||||||
#define autostream(...) (*makestream(__VA_ARGS__))
|
|
||||||
|
|
||||||
inline std::unique_ptr<stream> makestream(const string &path) {
|
|
||||||
if(path.ibeginswith("http://")) return std::unique_ptr<stream>(new httpstream(path, 80));
|
|
||||||
if(path.iendswith(".gz")) return std::unique_ptr<stream>(new gzipstream(filestream{path}));
|
|
||||||
if(path.iendswith(".zip")) return std::unique_ptr<stream>(new zipstream(filestream{path}));
|
|
||||||
return std::unique_ptr<stream>(new mmapstream(path));
|
|
||||||
}
|
|
||||||
|
|
||||||
inline std::unique_ptr<stream> makestream(uint8_t *data, unsigned size) {
|
|
||||||
return std::unique_ptr<stream>(new memorystream(data, size));
|
|
||||||
}
|
|
||||||
|
|
||||||
inline std::unique_ptr<stream> makestream(const uint8_t *data, unsigned size) {
|
|
||||||
return std::unique_ptr<stream>(new memorystream(data, size));
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
#endif
|
|
|
@ -1,42 +0,0 @@
|
||||||
#ifndef NALL_STREAM_FILE_HPP
|
|
||||||
#define NALL_STREAM_FILE_HPP
|
|
||||||
|
|
||||||
#include <nall/file.hpp>
|
|
||||||
|
|
||||||
namespace nall {
|
|
||||||
|
|
||||||
struct filestream : stream {
|
|
||||||
using stream::read;
|
|
||||||
using stream::write;
|
|
||||||
|
|
||||||
bool seekable() const { return true; }
|
|
||||||
bool readable() const { return true; }
|
|
||||||
bool writable() const { return pwritable; }
|
|
||||||
bool randomaccess() const { return false; }
|
|
||||||
|
|
||||||
unsigned size() const { return pfile.size(); }
|
|
||||||
unsigned offset() const { return pfile.offset(); }
|
|
||||||
void seek(unsigned offset) const { pfile.seek(offset); }
|
|
||||||
|
|
||||||
uint8_t read() const { return pfile.read(); }
|
|
||||||
void write(uint8_t data) const { pfile.write(data); }
|
|
||||||
|
|
||||||
filestream(const string &filename) {
|
|
||||||
pfile.open(filename, file::mode::readwrite);
|
|
||||||
pwritable = pfile.open();
|
|
||||||
if(!pwritable) pfile.open(filename, file::mode::read);
|
|
||||||
}
|
|
||||||
|
|
||||||
filestream(const string &filename, file::mode mode) {
|
|
||||||
pfile.open(filename, mode);
|
|
||||||
pwritable = mode == file::mode::write || mode == file::mode::readwrite;
|
|
||||||
}
|
|
||||||
|
|
||||||
private:
|
|
||||||
mutable file pfile;
|
|
||||||
bool pwritable;
|
|
||||||
};
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
#endif
|
|
|
@ -1,34 +0,0 @@
|
||||||
#ifndef NALL_STREAM_GZIP_HPP
|
|
||||||
#define NALL_STREAM_GZIP_HPP
|
|
||||||
|
|
||||||
#include <nall/gzip.hpp>
|
|
||||||
|
|
||||||
namespace nall {
|
|
||||||
|
|
||||||
struct gzipstream : memorystream {
|
|
||||||
using stream::read;
|
|
||||||
using stream::write;
|
|
||||||
|
|
||||||
gzipstream(const stream &stream) {
|
|
||||||
unsigned size = stream.size();
|
|
||||||
uint8_t *data = new uint8_t[size];
|
|
||||||
stream.read(data, size);
|
|
||||||
|
|
||||||
gzip archive;
|
|
||||||
bool result = archive.decompress(data, size);
|
|
||||||
delete[] data;
|
|
||||||
if(result == false) return;
|
|
||||||
|
|
||||||
psize = archive.size;
|
|
||||||
pdata = new uint8_t[psize];
|
|
||||||
memcpy(pdata, archive.data, psize);
|
|
||||||
}
|
|
||||||
|
|
||||||
~gzipstream() {
|
|
||||||
if(pdata) delete[] pdata;
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
#endif
|
|
|
@ -1,49 +0,0 @@
|
||||||
#ifndef NALL_STREAM_HTTP_HPP
|
|
||||||
#define NALL_STREAM_HTTP_HPP
|
|
||||||
|
|
||||||
#include <nall/http.hpp>
|
|
||||||
|
|
||||||
namespace nall {
|
|
||||||
|
|
||||||
struct httpstream : stream {
|
|
||||||
using stream::read;
|
|
||||||
using stream::write;
|
|
||||||
|
|
||||||
bool seekable() const { return true; }
|
|
||||||
bool readable() const { return true; }
|
|
||||||
bool writable() const { return true; }
|
|
||||||
bool randomaccess() const { return true; }
|
|
||||||
|
|
||||||
unsigned size() const { return psize; }
|
|
||||||
unsigned offset() const { return poffset; }
|
|
||||||
void seek(unsigned offset) const { poffset = offset; }
|
|
||||||
|
|
||||||
uint8_t read() const { return pdata[poffset++]; }
|
|
||||||
void write(uint8_t data) const { pdata[poffset++] = data; }
|
|
||||||
|
|
||||||
uint8_t read(unsigned offset) const { return pdata[offset]; }
|
|
||||||
void write(unsigned offset, uint8_t data) const { pdata[offset] = data; }
|
|
||||||
|
|
||||||
httpstream(const string &url, unsigned port) : pdata(nullptr), psize(0), poffset(0) {
|
|
||||||
string uri = url;
|
|
||||||
uri.ltrim<1>("http://");
|
|
||||||
lstring part = uri.split<1>("/");
|
|
||||||
part[1] = { "/", part[1] };
|
|
||||||
|
|
||||||
http connection;
|
|
||||||
if(connection.connect(part[0], port) == false) return;
|
|
||||||
connection.download(part[1], pdata, psize);
|
|
||||||
}
|
|
||||||
|
|
||||||
~httpstream() {
|
|
||||||
if(pdata) delete[] pdata;
|
|
||||||
}
|
|
||||||
|
|
||||||
private:
|
|
||||||
mutable uint8_t *pdata;
|
|
||||||
mutable unsigned psize, poffset;
|
|
||||||
};
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
#endif
|
|
|
@ -1,47 +0,0 @@
|
||||||
#ifndef NALL_STREAM_MEMORY_HPP
|
|
||||||
#define NALL_STREAM_MEMORY_HPP
|
|
||||||
|
|
||||||
#include <nall/stream/stream.hpp>
|
|
||||||
|
|
||||||
namespace nall {
|
|
||||||
|
|
||||||
struct memorystream : stream {
|
|
||||||
using stream::read;
|
|
||||||
using stream::write;
|
|
||||||
|
|
||||||
bool seekable() const { return true; }
|
|
||||||
bool readable() const { return true; }
|
|
||||||
bool writable() const { return pwritable; }
|
|
||||||
bool randomaccess() const { return true; }
|
|
||||||
|
|
||||||
uint8_t *data() const { return pdata; }
|
|
||||||
unsigned size() const { return psize; }
|
|
||||||
unsigned offset() const { return poffset; }
|
|
||||||
void seek(unsigned offset) const { poffset = offset; }
|
|
||||||
|
|
||||||
uint8_t read() const { return pdata[poffset++]; }
|
|
||||||
void write(uint8_t data) const { pdata[poffset++] = data; }
|
|
||||||
|
|
||||||
uint8_t read(unsigned offset) const { return pdata[offset]; }
|
|
||||||
void write(unsigned offset, uint8_t data) const { pdata[offset] = data; }
|
|
||||||
|
|
||||||
memorystream() : pdata(nullptr), psize(0), poffset(0), pwritable(true) {}
|
|
||||||
|
|
||||||
memorystream(uint8_t *data, unsigned size) {
|
|
||||||
pdata = data, psize = size, poffset = 0;
|
|
||||||
pwritable = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
memorystream(const uint8_t *data, unsigned size) {
|
|
||||||
pdata = (uint8_t*)data, psize = size, poffset = 0;
|
|
||||||
pwritable = false;
|
|
||||||
}
|
|
||||||
|
|
||||||
protected:
|
|
||||||
mutable uint8_t *pdata;
|
|
||||||
mutable unsigned psize, poffset, pwritable;
|
|
||||||
};
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
#endif
|
|
|
@ -1,42 +0,0 @@
|
||||||
#ifndef NALL_STREAM_MMAP_HPP
|
|
||||||
#define NALL_STREAM_MMAP_HPP
|
|
||||||
|
|
||||||
#include <nall/filemap.hpp>
|
|
||||||
|
|
||||||
namespace nall {
|
|
||||||
|
|
||||||
struct mmapstream : stream {
|
|
||||||
using stream::read;
|
|
||||||
using stream::write;
|
|
||||||
|
|
||||||
bool seekable() const { return true; }
|
|
||||||
bool readable() const { return true; }
|
|
||||||
bool writable() const { return pwritable; }
|
|
||||||
bool randomaccess() const { return true; }
|
|
||||||
|
|
||||||
unsigned size() const { return pmmap.size(); }
|
|
||||||
unsigned offset() const { return poffset; }
|
|
||||||
void seek(unsigned offset) const { poffset = offset; }
|
|
||||||
|
|
||||||
uint8_t read() const { return pdata[poffset++]; }
|
|
||||||
void write(uint8_t data) const { pdata[poffset++] = data; }
|
|
||||||
|
|
||||||
uint8_t read(unsigned offset) const { return pdata[offset]; }
|
|
||||||
void write(unsigned offset, uint8_t data) const { pdata[offset] = data; }
|
|
||||||
|
|
||||||
mmapstream(const string &filename) {
|
|
||||||
pmmap.open(filename, filemap::mode::readwrite);
|
|
||||||
pwritable = pmmap.open();
|
|
||||||
if(!pwritable) pmmap.open(filename, filemap::mode::read);
|
|
||||||
pdata = pmmap.data(), poffset = 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
private:
|
|
||||||
mutable filemap pmmap;
|
|
||||||
mutable uint8_t *pdata;
|
|
||||||
mutable unsigned pwritable, poffset;
|
|
||||||
};
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
#endif
|
|
|
@ -1,101 +0,0 @@
|
||||||
#ifndef NALL_STREAM_STREAM_HPP
|
|
||||||
#define NALL_STREAM_STREAM_HPP
|
|
||||||
|
|
||||||
namespace nall {
|
|
||||||
|
|
||||||
struct stream {
|
|
||||||
virtual bool seekable() const = 0;
|
|
||||||
virtual bool readable() const = 0;
|
|
||||||
virtual bool writable() const = 0;
|
|
||||||
virtual bool randomaccess() const = 0;
|
|
||||||
|
|
||||||
virtual uint8_t* data() const { return nullptr; }
|
|
||||||
virtual unsigned size() const = 0;
|
|
||||||
virtual unsigned offset() const = 0;
|
|
||||||
virtual void seek(unsigned offset) const = 0;
|
|
||||||
|
|
||||||
virtual uint8_t read() const = 0;
|
|
||||||
virtual void write(uint8_t data) const = 0;
|
|
||||||
|
|
||||||
virtual uint8_t read(unsigned) const { return 0; }
|
|
||||||
virtual void write(unsigned, uint8_t) const {}
|
|
||||||
|
|
||||||
operator bool() const {
|
|
||||||
return size();
|
|
||||||
}
|
|
||||||
|
|
||||||
bool empty() const {
|
|
||||||
return size() == 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool end() const {
|
|
||||||
return offset() >= size();
|
|
||||||
}
|
|
||||||
|
|
||||||
uintmax_t readl(unsigned length = 1) const {
|
|
||||||
uintmax_t data = 0, shift = 0;
|
|
||||||
while(length--) { data |= read() << shift; shift += 8; }
|
|
||||||
return data;
|
|
||||||
}
|
|
||||||
|
|
||||||
uintmax_t readm(unsigned length = 1) const {
|
|
||||||
uintmax_t data = 0;
|
|
||||||
while(length--) data = (data << 8) | read();
|
|
||||||
return data;
|
|
||||||
}
|
|
||||||
|
|
||||||
void read(uint8_t *data, unsigned length) const {
|
|
||||||
while(length--) *data++ = read();
|
|
||||||
}
|
|
||||||
|
|
||||||
string text() const {
|
|
||||||
string buffer;
|
|
||||||
buffer.resize(size() + 1);
|
|
||||||
buffer[size()] = 0;
|
|
||||||
seek(0);
|
|
||||||
read((uint8_t*)buffer(), size());
|
|
||||||
return buffer;
|
|
||||||
}
|
|
||||||
|
|
||||||
void writel(uintmax_t data, unsigned length = 1) const {
|
|
||||||
while(length--) {
|
|
||||||
write(data);
|
|
||||||
data >>= 8;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void writem(uintmax_t data, unsigned length = 1) const {
|
|
||||||
uintmax_t shift = 8 * length;
|
|
||||||
while(length--) {
|
|
||||||
shift -= 8;
|
|
||||||
write(data >> shift);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void write(const uint8_t *data, unsigned length) const {
|
|
||||||
while(length--) write(*data++);
|
|
||||||
}
|
|
||||||
|
|
||||||
struct byte {
|
|
||||||
operator uint8_t() const { return s.read(offset); }
|
|
||||||
byte& operator=(uint8_t data) { s.write(offset, data); return *this; }
|
|
||||||
byte(const stream &s, unsigned offset) : s(s), offset(offset) {}
|
|
||||||
|
|
||||||
private:
|
|
||||||
const stream &s;
|
|
||||||
const unsigned offset;
|
|
||||||
};
|
|
||||||
|
|
||||||
byte operator[](unsigned offset) const {
|
|
||||||
return byte(*this, offset);
|
|
||||||
}
|
|
||||||
|
|
||||||
stream() {}
|
|
||||||
virtual ~stream() {}
|
|
||||||
stream(const stream&) = delete;
|
|
||||||
stream& operator=(const stream&) = delete;
|
|
||||||
};
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
#endif
|
|
|
@ -1,39 +0,0 @@
|
||||||
#ifndef NALL_STREAM_VECTOR_HPP
|
|
||||||
#define NALL_STREAM_VECTOR_HPP
|
|
||||||
|
|
||||||
#include <nall/stream/stream.hpp>
|
|
||||||
#include <nall/vector.hpp>
|
|
||||||
|
|
||||||
namespace nall {
|
|
||||||
|
|
||||||
struct vectorstream : stream {
|
|
||||||
using stream::read;
|
|
||||||
using stream::write;
|
|
||||||
|
|
||||||
bool seekable() const { return true; }
|
|
||||||
bool readable() const { return true; }
|
|
||||||
bool writable() const { return pwritable; }
|
|
||||||
bool randomaccess() const { return true; }
|
|
||||||
|
|
||||||
uint8_t* data() const { return memory.data(); }
|
|
||||||
unsigned size() const { return memory.size(); }
|
|
||||||
unsigned offset() const { return poffset; }
|
|
||||||
void seek(unsigned offset) const { poffset = offset; }
|
|
||||||
|
|
||||||
uint8_t read() const { return memory[poffset++]; }
|
|
||||||
void write(uint8_t data) const { memory[poffset++] = data; }
|
|
||||||
|
|
||||||
uint8_t read(unsigned offset) const { return memory[offset]; }
|
|
||||||
void write(unsigned offset, uint8_t data) const { memory[offset] = data; }
|
|
||||||
|
|
||||||
vectorstream(vector<uint8_t> &memory) : memory(memory), poffset(0), pwritable(true) {}
|
|
||||||
vectorstream(const vector<uint8_t> &memory) : memory((vector<uint8_t>&)memory), poffset(0), pwritable(false) {}
|
|
||||||
|
|
||||||
protected:
|
|
||||||
vector<uint8_t> &memory;
|
|
||||||
mutable unsigned poffset, pwritable;
|
|
||||||
};
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
#endif
|
|
|
@ -1,38 +0,0 @@
|
||||||
#ifndef NALL_STREAM_ZIP_HPP
|
|
||||||
#define NALL_STREAM_ZIP_HPP
|
|
||||||
|
|
||||||
#include <nall/unzip.hpp>
|
|
||||||
|
|
||||||
namespace nall {
|
|
||||||
|
|
||||||
struct zipstream : memorystream {
|
|
||||||
using stream::read;
|
|
||||||
using stream::write;
|
|
||||||
|
|
||||||
zipstream(const stream &stream, const string &filter = "*") {
|
|
||||||
unsigned size = stream.size();
|
|
||||||
uint8_t *data = new uint8_t[size];
|
|
||||||
stream.read(data, size);
|
|
||||||
|
|
||||||
unzip archive;
|
|
||||||
if(archive.open(data, size) == false) return;
|
|
||||||
delete[] data;
|
|
||||||
|
|
||||||
for(auto &file : archive.file) {
|
|
||||||
if(file.name.wildcard(filter)) {
|
|
||||||
auto buffer = archive.extract(file);
|
|
||||||
psize = buffer.size();
|
|
||||||
pdata = buffer.move();
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
~zipstream() {
|
|
||||||
if(pdata) delete[] pdata;
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
#endif
|
|
|
@ -1,54 +0,0 @@
|
||||||
#ifndef NALL_STRING_HPP
|
|
||||||
#define NALL_STRING_HPP
|
|
||||||
|
|
||||||
#include <stdarg.h>
|
|
||||||
#include <stdio.h>
|
|
||||||
#include <stdlib.h>
|
|
||||||
#include <string.h>
|
|
||||||
|
|
||||||
#include <algorithm>
|
|
||||||
#include <initializer_list>
|
|
||||||
|
|
||||||
#include <nall/atoi.hpp>
|
|
||||||
#include <nall/function.hpp>
|
|
||||||
#include <nall/platform.hpp>
|
|
||||||
#include <nall/sha256.hpp>
|
|
||||||
#include <nall/stdint.hpp>
|
|
||||||
#include <nall/utility.hpp>
|
|
||||||
#include <nall/varint.hpp>
|
|
||||||
#include <nall/vector.hpp>
|
|
||||||
|
|
||||||
#include <nall/windows/utf8.hpp>
|
|
||||||
|
|
||||||
#define NALL_STRING_INTERNAL_HPP
|
|
||||||
#include <nall/string/base.hpp>
|
|
||||||
#include <nall/string/bsv.hpp>
|
|
||||||
#include <nall/string/cast.hpp>
|
|
||||||
#include <nall/string/compare.hpp>
|
|
||||||
#include <nall/string/convert.hpp>
|
|
||||||
#include <nall/string/core.hpp>
|
|
||||||
#include <nall/string/cstring.hpp>
|
|
||||||
#include <nall/string/datetime.hpp>
|
|
||||||
#include <nall/string/filename.hpp>
|
|
||||||
#include <nall/string/format.hpp>
|
|
||||||
#include <nall/string/math-fixed-point.hpp>
|
|
||||||
#include <nall/string/math-floating-point.hpp>
|
|
||||||
#include <nall/string/platform.hpp>
|
|
||||||
#include <nall/string/strm.hpp>
|
|
||||||
#include <nall/string/strpos.hpp>
|
|
||||||
#include <nall/string/trim.hpp>
|
|
||||||
#include <nall/string/replace.hpp>
|
|
||||||
#include <nall/string/split.hpp>
|
|
||||||
#include <nall/string/static.hpp>
|
|
||||||
#include <nall/string/utf8.hpp>
|
|
||||||
#include <nall/string/utility.hpp>
|
|
||||||
#include <nall/string/variadic.hpp>
|
|
||||||
#include <nall/string/wildcard.hpp>
|
|
||||||
#include <nall/string/wrapper.hpp>
|
|
||||||
#include <nall/string/markup/node.hpp>
|
|
||||||
#include <nall/string/markup/bml.hpp>
|
|
||||||
#include <nall/string/markup/xml.hpp>
|
|
||||||
#include <nall/string/markup/document.hpp>
|
|
||||||
#undef NALL_STRING_INTERNAL_HPP
|
|
||||||
|
|
||||||
#endif
|
|
|
@ -1,231 +0,0 @@
|
||||||
#ifdef NALL_STRING_INTERNAL_HPP
|
|
||||||
|
|
||||||
namespace nall {
|
|
||||||
struct cstring;
|
|
||||||
struct string;
|
|
||||||
struct lstring;
|
|
||||||
template<typename T> inline const char* to_string(T);
|
|
||||||
|
|
||||||
struct cstring {
|
|
||||||
inline operator const char*() const;
|
|
||||||
inline unsigned length() const;
|
|
||||||
inline bool operator==(const char*) const;
|
|
||||||
inline bool operator!=(const char*) const;
|
|
||||||
inline optional<unsigned> position(const char *key) const;
|
|
||||||
inline optional<unsigned> iposition(const char *key) const;
|
|
||||||
inline cstring& operator=(const char *data);
|
|
||||||
inline cstring(const char *data);
|
|
||||||
inline cstring();
|
|
||||||
|
|
||||||
protected:
|
|
||||||
const char *data;
|
|
||||||
};
|
|
||||||
|
|
||||||
struct string {
|
|
||||||
//deprecated: use string text = file::read(filename);
|
|
||||||
inline static string read(const string &filename);
|
|
||||||
|
|
||||||
inline static string date();
|
|
||||||
inline static string time();
|
|
||||||
inline static string datetime();
|
|
||||||
|
|
||||||
inline void reserve(unsigned);
|
|
||||||
inline void resize(unsigned);
|
|
||||||
inline void clear(char);
|
|
||||||
inline bool empty() const;
|
|
||||||
|
|
||||||
template<typename... Args> inline string& assign(Args&&... args);
|
|
||||||
template<typename... Args> inline string& append(Args&&... args);
|
|
||||||
|
|
||||||
inline bool readfile(const string&);
|
|
||||||
|
|
||||||
template<unsigned Limit = 0> inline string& replace(const char*, const char*);
|
|
||||||
template<unsigned Limit = 0> inline string& ireplace(const char*, const char*);
|
|
||||||
template<unsigned Limit = 0> inline string& qreplace(const char*, const char*);
|
|
||||||
template<unsigned Limit = 0> inline string& iqreplace(const char*, const char*);
|
|
||||||
|
|
||||||
inline unsigned length() const;
|
|
||||||
inline unsigned capacity() const;
|
|
||||||
|
|
||||||
template<unsigned Limit = 0> inline lstring split(const char*) const;
|
|
||||||
template<unsigned Limit = 0> inline lstring isplit(const char*) const;
|
|
||||||
template<unsigned Limit = 0> inline lstring qsplit(const char*) const;
|
|
||||||
template<unsigned Limit = 0> inline lstring iqsplit(const char*) const;
|
|
||||||
|
|
||||||
inline bool equals(const char*) const;
|
|
||||||
inline bool iequals(const char*) const;
|
|
||||||
|
|
||||||
inline bool wildcard(const char*) const;
|
|
||||||
inline bool iwildcard(const char*) const;
|
|
||||||
|
|
||||||
inline bool beginswith(const char*) const;
|
|
||||||
inline bool ibeginswith(const char*) const;
|
|
||||||
inline bool endswith(const char*) const;
|
|
||||||
inline bool iendswith(const char*) const;
|
|
||||||
|
|
||||||
inline string& lower();
|
|
||||||
inline string& upper();
|
|
||||||
inline string& qlower();
|
|
||||||
inline string& qupper();
|
|
||||||
inline string& transform(const char *before, const char *after);
|
|
||||||
inline string& reverse();
|
|
||||||
|
|
||||||
template<unsigned limit = 0> inline string& ltrim(const char *key = " ");
|
|
||||||
template<unsigned limit = 0> inline string& rtrim(const char *key = " ");
|
|
||||||
template<unsigned limit = 0> inline string& trim(const char *key = " ", const char *rkey = nullptr);
|
|
||||||
inline string& strip();
|
|
||||||
|
|
||||||
inline optional<unsigned> position(const char *key) const;
|
|
||||||
inline optional<unsigned> iposition(const char *key) const;
|
|
||||||
inline optional<unsigned> qposition(const char *key) const;
|
|
||||||
inline optional<unsigned> iqposition(const char *key) const;
|
|
||||||
|
|
||||||
inline explicit operator bool() const;
|
|
||||||
inline operator const char*() const;
|
|
||||||
inline char* operator()();
|
|
||||||
inline char& operator[](int);
|
|
||||||
|
|
||||||
inline bool operator==(const char*) const;
|
|
||||||
inline bool operator!=(const char*) const;
|
|
||||||
inline bool operator< (const char*) const;
|
|
||||||
inline bool operator<=(const char*) const;
|
|
||||||
inline bool operator> (const char*) const;
|
|
||||||
inline bool operator>=(const char*) const;
|
|
||||||
|
|
||||||
inline string& operator=(const string&);
|
|
||||||
inline string& operator=(string&&);
|
|
||||||
|
|
||||||
template<typename... Args> inline string(Args&&... args);
|
|
||||||
inline string(const string&);
|
|
||||||
inline string(string&&);
|
|
||||||
inline ~string();
|
|
||||||
|
|
||||||
inline char* begin() { return &data[0]; }
|
|
||||||
inline char* end() { return &data[length()]; }
|
|
||||||
inline const char* begin() const { return &data[0]; }
|
|
||||||
inline const char* end() const { return &data[length()]; }
|
|
||||||
|
|
||||||
//internal functions
|
|
||||||
inline string& assign_(const char*);
|
|
||||||
inline string& append_(const char*);
|
|
||||||
|
|
||||||
protected:
|
|
||||||
char *data;
|
|
||||||
unsigned size;
|
|
||||||
|
|
||||||
template<unsigned Limit, bool Insensitive, bool Quoted> inline string& ureplace(const char*, const char*);
|
|
||||||
|
|
||||||
#if defined(QSTRING_H)
|
|
||||||
public:
|
|
||||||
inline operator QString() const;
|
|
||||||
#endif
|
|
||||||
};
|
|
||||||
|
|
||||||
struct lstring : vector<string> {
|
|
||||||
inline optional<unsigned> find(const char*) const;
|
|
||||||
inline string concatenate(const char*) const;
|
|
||||||
inline void append() {}
|
|
||||||
inline void isort();
|
|
||||||
template<typename... Args> inline void append(const string&, Args&&...);
|
|
||||||
|
|
||||||
template<unsigned Limit = 0> inline lstring& split(const char*, const char*);
|
|
||||||
template<unsigned Limit = 0> inline lstring& isplit(const char*, const char*);
|
|
||||||
template<unsigned Limit = 0> inline lstring& qsplit(const char*, const char*);
|
|
||||||
template<unsigned Limit = 0> inline lstring& iqsplit(const char*, const char*);
|
|
||||||
|
|
||||||
inline bool operator==(const lstring&) const;
|
|
||||||
inline bool operator!=(const lstring&) const;
|
|
||||||
|
|
||||||
inline lstring& operator=(const lstring&);
|
|
||||||
inline lstring& operator=(lstring&);
|
|
||||||
inline lstring& operator=(lstring&&);
|
|
||||||
|
|
||||||
template<typename... Args> inline lstring(Args&&... args);
|
|
||||||
inline lstring(const lstring&);
|
|
||||||
inline lstring(lstring&);
|
|
||||||
inline lstring(lstring&&);
|
|
||||||
|
|
||||||
protected:
|
|
||||||
template<unsigned Limit, bool Insensitive, bool Quoted> inline lstring& usplit(const char*, const char*);
|
|
||||||
};
|
|
||||||
|
|
||||||
//compare.hpp
|
|
||||||
inline char chrlower(char c);
|
|
||||||
inline char chrupper(char c);
|
|
||||||
inline int istrcmp(const char *str1, const char *str2);
|
|
||||||
inline bool strbegin(const char *str, const char *key);
|
|
||||||
inline bool istrbegin(const char *str, const char *key);
|
|
||||||
inline bool strend(const char *str, const char *key);
|
|
||||||
inline bool istrend(const char *str, const char *key);
|
|
||||||
|
|
||||||
//convert.hpp
|
|
||||||
inline char* strlower(char *str);
|
|
||||||
inline char* strupper(char *str);
|
|
||||||
inline char* qstrlower(char *str);
|
|
||||||
inline char* qstrupper(char *str);
|
|
||||||
inline char* strtr(char *dest, const char *before, const char *after);
|
|
||||||
|
|
||||||
//format.hpp
|
|
||||||
template<signed precision = 0, char padchar = ' '> inline string format(const string &value);
|
|
||||||
template<signed precision = 0, char padchar = '0'> inline string hex(uintmax_t value);
|
|
||||||
template<signed precision = 0, char padchar = '0'> inline string octal(uintmax_t value);
|
|
||||||
template<signed precision = 0, char padchar = '0'> inline string binary(uintmax_t value);
|
|
||||||
|
|
||||||
//math.hpp
|
|
||||||
inline bool strint(const char *str, int &result);
|
|
||||||
inline bool strmath(const char *str, int &result);
|
|
||||||
|
|
||||||
//platform.hpp
|
|
||||||
inline string activepath();
|
|
||||||
inline string realpath(const string &name);
|
|
||||||
inline string userpath();
|
|
||||||
inline string configpath();
|
|
||||||
inline string temppath();
|
|
||||||
|
|
||||||
//strm.hpp
|
|
||||||
inline unsigned strmcpy(char *target, const char *source, unsigned length);
|
|
||||||
inline unsigned strmcat(char *target, const char *source, unsigned length);
|
|
||||||
inline bool strccpy(char *target, const char *source, unsigned length);
|
|
||||||
inline bool strccat(char *target, const char *source, unsigned length);
|
|
||||||
inline void strpcpy(char *&target, const char *source, unsigned &length);
|
|
||||||
|
|
||||||
//strpos.hpp
|
|
||||||
inline optional<unsigned> strpos(const char *str, const char *key);
|
|
||||||
inline optional<unsigned> istrpos(const char *str, const char *key);
|
|
||||||
inline optional<unsigned> qstrpos(const char *str, const char *key);
|
|
||||||
inline optional<unsigned> iqstrpos(const char *str, const char *key);
|
|
||||||
template<bool Insensitive = false, bool Quoted = false> inline optional<unsigned> ustrpos(const char *str, const char *key);
|
|
||||||
|
|
||||||
//trim.hpp
|
|
||||||
template<unsigned limit = 0> inline char* ltrim(char *str, const char *key = " ");
|
|
||||||
template<unsigned limit = 0> inline char* rtrim(char *str, const char *key = " ");
|
|
||||||
template<unsigned limit = 0> inline char* trim(char *str, const char *key = " ", const char *rkey = nullptr);
|
|
||||||
inline char* strip(char *s);
|
|
||||||
|
|
||||||
//utility.hpp
|
|
||||||
template<bool Insensitive> alwaysinline bool chrequal(char x, char y);
|
|
||||||
template<bool Quoted, typename T> alwaysinline bool quoteskip(T *&p);
|
|
||||||
template<bool Quoted, typename T> alwaysinline bool quotecopy(char *&t, T *&p);
|
|
||||||
inline string substr(const char *src, unsigned start = 0, unsigned length = ~0u);
|
|
||||||
inline string sha256(const uint8_t *data, unsigned size);
|
|
||||||
|
|
||||||
inline char* integer(char *result, intmax_t value);
|
|
||||||
inline char* decimal(char *result, uintmax_t value);
|
|
||||||
|
|
||||||
//these functions are deprecated, use format() instead:
|
|
||||||
template<unsigned length = 0, char padding = ' '> inline string integer(intmax_t value);
|
|
||||||
template<unsigned length = 0, char padding = ' '> inline string linteger(intmax_t value);
|
|
||||||
template<unsigned length = 0, char padding = ' '> inline string decimal(uintmax_t value);
|
|
||||||
template<unsigned length = 0, char padding = ' '> inline string ldecimal(uintmax_t value);
|
|
||||||
inline unsigned fp(char *str, long double value);
|
|
||||||
inline string fp(long double value);
|
|
||||||
|
|
||||||
//variadic.hpp
|
|
||||||
template<typename... Args> inline void print(Args&&... args);
|
|
||||||
|
|
||||||
//wildcard.hpp
|
|
||||||
inline bool wildcard(const char *str, const char *pattern);
|
|
||||||
inline bool iwildcard(const char *str, const char *pattern);
|
|
||||||
};
|
|
||||||
|
|
||||||
#endif
|
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue