mirror of https://github.com/bsnes-emu/bsnes.git
Update to v072 release.
byuu says: Just some very minor fixes.
This commit is contained in:
parent
6c3aec7dc9
commit
d0ef8e7488
|
@ -16,12 +16,19 @@
|
||||||
namespace nall {
|
namespace nall {
|
||||||
|
|
||||||
struct directory {
|
struct directory {
|
||||||
|
static bool exists(const string &pathname);
|
||||||
static lstring folders(const string &pathname, const string &pattern = "*");
|
static lstring folders(const string &pathname, const string &pattern = "*");
|
||||||
static lstring files(const string &pathname, const string &pattern = "*");
|
static lstring files(const string &pathname, const string &pattern = "*");
|
||||||
static lstring contents(const string &pathname, const string &pattern = "*");
|
static lstring contents(const string &pathname, const string &pattern = "*");
|
||||||
};
|
};
|
||||||
|
|
||||||
#if defined(_WIN32)
|
#if defined(_WIN32)
|
||||||
|
inline bool directory::exists(const string &pathname) {
|
||||||
|
DWORD result = GetFileAttributes(utf16_t(pathname));
|
||||||
|
if(result == INVALID_FILE_ATTRIBUTES) return false;
|
||||||
|
return (result & FILE_ATTRIBUTE_DIRECTORY);
|
||||||
|
}
|
||||||
|
|
||||||
inline lstring directory::folders(const string &pathname, const string &pattern) {
|
inline lstring directory::folders(const string &pathname, const string &pattern) {
|
||||||
lstring list;
|
lstring list;
|
||||||
string path = pathname;
|
string path = pathname;
|
||||||
|
@ -85,6 +92,13 @@ struct directory {
|
||||||
return folders;
|
return folders;
|
||||||
}
|
}
|
||||||
#else
|
#else
|
||||||
|
inline bool directory::exists(const string &pathname) {
|
||||||
|
DIR *dp = opendir(pathname);
|
||||||
|
if(!dp) return false;
|
||||||
|
closedir(dp);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
inline lstring directory::folders(const string &pathname, const string &pattern) {
|
inline lstring directory::folders(const string &pathname, const string &pattern) {
|
||||||
lstring list;
|
lstring list;
|
||||||
DIR *dp;
|
DIR *dp;
|
||||||
|
|
|
@ -12,7 +12,6 @@
|
||||||
#include <nall/string/compare.hpp>
|
#include <nall/string/compare.hpp>
|
||||||
#include <nall/string/convert.hpp>
|
#include <nall/string/convert.hpp>
|
||||||
#include <nall/string/filename.hpp>
|
#include <nall/string/filename.hpp>
|
||||||
#include <nall/string/match.hpp>
|
|
||||||
#include <nall/string/math.hpp>
|
#include <nall/string/math.hpp>
|
||||||
#include <nall/string/platform.hpp>
|
#include <nall/string/platform.hpp>
|
||||||
#include <nall/string/strl.hpp>
|
#include <nall/string/strl.hpp>
|
||||||
|
|
|
@ -119,9 +119,6 @@ namespace nall {
|
||||||
inline uintmax_t strbin (const char *str);
|
inline uintmax_t strbin (const char *str);
|
||||||
inline double strdouble (const char *str);
|
inline double strdouble (const char *str);
|
||||||
|
|
||||||
//match.hpp
|
|
||||||
inline bool match(const char *pattern, const char *str);
|
|
||||||
|
|
||||||
//math.hpp
|
//math.hpp
|
||||||
inline bool strint (const char *str, int &result);
|
inline bool strint (const char *str, int &result);
|
||||||
inline bool strmath(const char *str, int &result);
|
inline bool strmath(const char *str, int &result);
|
||||||
|
|
|
@ -1,76 +0,0 @@
|
||||||
#ifndef NALL_STRING_MATCH_HPP
|
|
||||||
#define NALL_STRING_MATCH_HPP
|
|
||||||
|
|
||||||
namespace nall {
|
|
||||||
|
|
||||||
bool match(const char *p, const char *s) {
|
|
||||||
const char *p_ = 0, *s_ = 0;
|
|
||||||
|
|
||||||
for(;;) {
|
|
||||||
if(!*s) {
|
|
||||||
while(*p == '*') p++;
|
|
||||||
return !*p;
|
|
||||||
}
|
|
||||||
|
|
||||||
//wildcard match
|
|
||||||
if(*p == '*') {
|
|
||||||
p_ = p++, s_ = s;
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
//any match
|
|
||||||
if(*p == '?') {
|
|
||||||
p++, s++;
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
//ranged match
|
|
||||||
if(*p == '{') {
|
|
||||||
#define pattern(name_, rule_) \
|
|
||||||
if(strbegin(p, name_)) { \
|
|
||||||
if(rule_) { \
|
|
||||||
p += sizeof(name_) - 1, s++; \
|
|
||||||
continue; \
|
|
||||||
} \
|
|
||||||
goto failure; \
|
|
||||||
}
|
|
||||||
|
|
||||||
pattern("{alpha}", (*s >= 'A' && *s <= 'Z') || (*s >= 'a' && *s <= 'z'))
|
|
||||||
pattern("{alphanumeric}", (*s >= 'A' && *s <= 'Z') || (*s >= 'a' && *s <= 'z') || (*s >= '0' && *s <= '9'))
|
|
||||||
pattern("{binary}", (*s == '0' || *s == '1'))
|
|
||||||
pattern("{hex}", (*s >= '0' && *s <= '9') || (*s >= 'A' && *s <= 'F') || (*s >= 'a' && *s <= 'f'))
|
|
||||||
pattern("{lowercase}", (*s >= 'a' && *s <= 'z'))
|
|
||||||
pattern("{numeric}", (*s >= '0' && *s <= '9'))
|
|
||||||
pattern("{uppercase}", (*s >= 'A' && *s <= 'Z'))
|
|
||||||
pattern("{whitespace}", (*s == ' ' || *s == '\t'))
|
|
||||||
|
|
||||||
#undef pattern
|
|
||||||
goto failure;
|
|
||||||
}
|
|
||||||
|
|
||||||
//reserved character match
|
|
||||||
if(*p == '\\') {
|
|
||||||
p++;
|
|
||||||
//fallthrough
|
|
||||||
}
|
|
||||||
|
|
||||||
//literal match
|
|
||||||
if(*p == *s) {
|
|
||||||
p++, *s++;
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
//attempt wildcard rematch
|
|
||||||
failure:
|
|
||||||
if(p_) {
|
|
||||||
p = p_, s = s_ + 1;
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
#endif
|
|
|
@ -117,6 +117,8 @@ struct ups {
|
||||||
if(patch_xor == 0) break;
|
if(patch_xor == 0) break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
while(source_offset < source_length) target_write(source_read());
|
||||||
|
while(target_offset < target_length) target_write(source_read());
|
||||||
|
|
||||||
uint32_t patch_read_checksum = 0, source_read_checksum = 0, target_read_checksum = 0;
|
uint32_t patch_read_checksum = 0, source_read_checksum = 0, target_read_checksum = 0;
|
||||||
for(unsigned i = 0; i < 4; i++) source_read_checksum |= patch_read() << (i * 8);
|
for(unsigned i = 0; i < 4; i++) source_read_checksum |= patch_read() << (i * 8);
|
||||||
|
|
|
@ -1,6 +1,8 @@
|
||||||
#include <ruby/ruby.hpp>
|
#include <ruby/ruby.hpp>
|
||||||
using namespace nall;
|
using namespace nall;
|
||||||
|
|
||||||
|
#undef mkdir
|
||||||
|
#undef usleep
|
||||||
#include <ruby/ruby_impl.cpp>
|
#include <ruby/ruby_impl.cpp>
|
||||||
|
|
||||||
namespace ruby {
|
namespace ruby {
|
||||||
|
|
|
@ -20,6 +20,7 @@ public:
|
||||||
HWND handle;
|
HWND handle;
|
||||||
bool synchronize;
|
bool synchronize;
|
||||||
unsigned filter;
|
unsigned filter;
|
||||||
|
string shader;
|
||||||
|
|
||||||
unsigned width;
|
unsigned width;
|
||||||
unsigned height;
|
unsigned height;
|
||||||
|
@ -49,7 +50,10 @@ public:
|
||||||
if(name == Video::Synchronize) {
|
if(name == Video::Synchronize) {
|
||||||
if(settings.synchronize != any_cast<bool>(value)) {
|
if(settings.synchronize != any_cast<bool>(value)) {
|
||||||
settings.synchronize = any_cast<bool>(value);
|
settings.synchronize = any_cast<bool>(value);
|
||||||
if(wglcontext) init();
|
if(wglcontext) {
|
||||||
|
init();
|
||||||
|
OpenGL::set_shader(settings.shader);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -59,7 +63,8 @@ public:
|
||||||
}
|
}
|
||||||
|
|
||||||
if(name == Video::Shader) {
|
if(name == Video::Shader) {
|
||||||
OpenGL::set_shader(any_cast<const char*>(value));
|
settings.shader = any_cast<const char*>(value);
|
||||||
|
OpenGL::set_shader(settings.shader);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
namespace SNES {
|
namespace SNES {
|
||||||
namespace Info {
|
namespace Info {
|
||||||
static const char Name[] = "bsnes";
|
static const char Name[] = "bsnes";
|
||||||
static const char Version[] = "071";
|
static const char Version[] = "072";
|
||||||
static const unsigned SerializerVersion = 14;
|
static const unsigned SerializerVersion = 14;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -24,7 +24,7 @@ void Application::main(int argc, char **argv) {
|
||||||
monospaceFont.create("Courier New", 8);
|
monospaceFont.create("Courier New", 8);
|
||||||
#else
|
#else
|
||||||
proportionalFont.create("Sans", 8);
|
proportionalFont.create("Sans", 8);
|
||||||
proportionalFontBold.create("Tahoma", 8, Font::Style::Bold);
|
proportionalFontBold.create("Sans", 8, Font::Style::Bold);
|
||||||
monospaceFont.create("Liberation Mono", 8);
|
monospaceFont.create("Liberation Mono", 8);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
|
|
@ -164,7 +164,7 @@ void SuperGameBoy::serialize(nall::serializer &s) {
|
||||||
s.array(savestate, 256 * 1024);
|
s.array(savestate, 256 * 1024);
|
||||||
|
|
||||||
file fp;
|
file fp;
|
||||||
if(fp.open("supergameboy-state.tmp", file::mode_write)) {
|
if(fp.open("supergameboy-state.tmp", file::mode::write)) {
|
||||||
fp.write(savestate, 256 * 1024);
|
fp.write(savestate, 256 * 1024);
|
||||||
fp.close();
|
fp.close();
|
||||||
|
|
||||||
|
@ -175,7 +175,7 @@ void SuperGameBoy::serialize(nall::serializer &s) {
|
||||||
gambatte->saveState("supergameboy-state.tmp");
|
gambatte->saveState("supergameboy-state.tmp");
|
||||||
|
|
||||||
file fp;
|
file fp;
|
||||||
if(fp.open("supergameboy-state.tmp", file::mode_read)) {
|
if(fp.open("supergameboy-state.tmp", file::mode::read)) {
|
||||||
fp.read(savestate, fp.size() < 256 * 1024 ? fp.size() : 256 * 1024);
|
fp.read(savestate, fp.size() < 256 * 1024 ? fp.size() : 256 * 1024);
|
||||||
fp.close();
|
fp.close();
|
||||||
}
|
}
|
||||||
|
|
|
@ -190,6 +190,8 @@ static void filter(Gambatte::uint_least32_t *pOut, const unsigned dstPitch,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//filters are unused by libsupergameboy
|
||||||
|
#if 0
|
||||||
switch (pattern)
|
switch (pattern)
|
||||||
{
|
{
|
||||||
case 0:
|
case 0:
|
||||||
|
@ -2832,6 +2834,7 @@ static void filter(Gambatte::uint_least32_t *pOut, const unsigned dstPitch,
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
#endif
|
||||||
++pIn;
|
++pIn;
|
||||||
pOut += 2;
|
pOut += 2;
|
||||||
}
|
}
|
||||||
|
|
|
@ -187,6 +187,8 @@ static void filter(Gambatte::uint_least32_t *pOut, const unsigned dstPitch,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//filters are unused by libsupergameboy
|
||||||
|
#if 0
|
||||||
switch (pattern)
|
switch (pattern)
|
||||||
{
|
{
|
||||||
case 0:
|
case 0:
|
||||||
|
@ -3802,6 +3804,7 @@ static void filter(Gambatte::uint_least32_t *pOut, const unsigned dstPitch,
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
#endif
|
||||||
++pIn;
|
++pIn;
|
||||||
pOut += 3;
|
pOut += 3;
|
||||||
}
|
}
|
||||||
|
|
|
@ -29,10 +29,12 @@ ifeq ($(platform),)
|
||||||
endif
|
endif
|
||||||
|
|
||||||
ifeq ($(compiler),)
|
ifeq ($(compiler),)
|
||||||
ifeq ($(platform),osx)
|
ifeq ($(platform),win)
|
||||||
compiler := gcc-mp-4.4
|
|
||||||
else
|
|
||||||
compiler := gcc
|
compiler := gcc
|
||||||
|
else ifeq ($(platform),osx)
|
||||||
|
compiler := gcc-mp-4.5
|
||||||
|
else
|
||||||
|
compiler := gcc-4.5
|
||||||
endif
|
endif
|
||||||
endif
|
endif
|
||||||
|
|
||||||
|
|
|
@ -49,7 +49,7 @@ namespace nall {
|
||||||
case signed_t: *(signed*)data = strsigned(s); break;
|
case signed_t: *(signed*)data = strsigned(s); break;
|
||||||
case unsigned_t: *(unsigned*)data = strunsigned(s); break;
|
case unsigned_t: *(unsigned*)data = strunsigned(s); break;
|
||||||
case double_t: *(double*)data = strdouble(s); break;
|
case double_t: *(double*)data = strdouble(s); break;
|
||||||
case string_t: trim(s, "\""); *(string*)data = s; break;
|
case string_t: s.trim("\""); *(string*)data = s; break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
@ -83,8 +83,8 @@ namespace nall {
|
||||||
|
|
||||||
lstring part;
|
lstring part;
|
||||||
part.qsplit(" = ", line[i]);
|
part.qsplit(" = ", line[i]);
|
||||||
trim(part[0]);
|
part[0].trim();
|
||||||
trim(part[1]);
|
part[1].trim();
|
||||||
|
|
||||||
for(unsigned n = 0; n < list.size(); n++) {
|
for(unsigned n = 0; n < list.size(); n++) {
|
||||||
if(part[0] == list[n].name) {
|
if(part[0] == list[n].name) {
|
||||||
|
@ -102,7 +102,7 @@ namespace nall {
|
||||||
|
|
||||||
virtual bool save(const char *filename) const {
|
virtual bool save(const char *filename) const {
|
||||||
file fp;
|
file fp;
|
||||||
if(fp.open(filename, file::mode_write)) {
|
if(fp.open(filename, file::mode::write)) {
|
||||||
for(unsigned i = 0; i < list.size(); i++) {
|
for(unsigned i = 0; i < list.size(); i++) {
|
||||||
string output;
|
string output;
|
||||||
output << list[i].name << " = " << list[i].get();
|
output << list[i].name << " = " << list[i].get();
|
||||||
|
|
|
@ -27,7 +27,7 @@ namespace nall {
|
||||||
bool import(const char *filename) {
|
bool import(const char *filename) {
|
||||||
string data;
|
string data;
|
||||||
if(data.readfile(filename) == false) return false;
|
if(data.readfile(filename) == false) return false;
|
||||||
ltrim_once(data, "\xef\xbb\xbf"); //remove UTF-8 marker, if it exists
|
data.ltrim<1>("\xef\xbb\xbf"); //remove UTF-8 marker, if it exists
|
||||||
data.replace("\r", "");
|
data.replace("\r", "");
|
||||||
|
|
||||||
lstring line;
|
lstring line;
|
||||||
|
@ -39,12 +39,12 @@ namespace nall {
|
||||||
if(part.size() != 2) continue;
|
if(part.size() != 2) continue;
|
||||||
|
|
||||||
//remove whitespace
|
//remove whitespace
|
||||||
trim(part[0]);
|
part[0].trim();
|
||||||
trim(part[1]);
|
part[1].trim();
|
||||||
|
|
||||||
//remove quotes
|
//remove quotes
|
||||||
trim_once(part[0], "\"");
|
part[0].trim<1>("\"");
|
||||||
trim_once(part[1], "\"");
|
part[1].trim<1>("\"");
|
||||||
|
|
||||||
unsigned n = index_input.size();
|
unsigned n = index_input.size();
|
||||||
index_input[n] = part[0];
|
index_input[n] = part[0];
|
||||||
|
|
|
@ -0,0 +1,151 @@
|
||||||
|
#ifndef NALL_DIRECTORY_HPP
|
||||||
|
#define NALL_DIRECTORY_HPP
|
||||||
|
|
||||||
|
#include <nall/foreach.hpp>
|
||||||
|
#include <nall/sort.hpp>
|
||||||
|
#include <nall/string.hpp>
|
||||||
|
|
||||||
|
#if defined(_WIN32)
|
||||||
|
#include <nall/utf8.hpp>
|
||||||
|
#else
|
||||||
|
#include <dirent.h>
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <sys/types.h>
|
||||||
|
#endif
|
||||||
|
|
||||||
|
namespace nall {
|
||||||
|
|
||||||
|
struct directory {
|
||||||
|
static bool exists(const string &pathname);
|
||||||
|
static lstring folders(const string &pathname, const string &pattern = "*");
|
||||||
|
static lstring files(const string &pathname, const string &pattern = "*");
|
||||||
|
static lstring contents(const string &pathname, const string &pattern = "*");
|
||||||
|
};
|
||||||
|
|
||||||
|
#if defined(_WIN32)
|
||||||
|
inline bool directory::exists(const string &pathname) {
|
||||||
|
DWORD result = GetFileAttributes(utf16_t(pathname));
|
||||||
|
if(result == INVALID_FILE_ATTRIBUTES) return false;
|
||||||
|
return (result & FILE_ATTRIBUTE_DIRECTORY);
|
||||||
|
}
|
||||||
|
|
||||||
|
inline lstring directory::folders(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 = utf8_t(data.cFileName);
|
||||||
|
if(wildcard(name, pattern)) list.append(string(name, "/"));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
while(FindNextFile(handle, &data) != false) {
|
||||||
|
if(wcscmp(data.cFileName, L".") && wcscmp(data.cFileName, L"..")) {
|
||||||
|
if(data.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) {
|
||||||
|
string name = utf8_t(data.cFileName);
|
||||||
|
if(wildcard(name, pattern)) list.append(string(name, "/"));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
FindClose(handle);
|
||||||
|
}
|
||||||
|
if(list.size() > 0) sort(&list[0], list.size());
|
||||||
|
return list;
|
||||||
|
}
|
||||||
|
|
||||||
|
inline lstring directory::files(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 = 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 = utf8_t(data.cFileName);
|
||||||
|
if(wildcard(name, pattern)) list.append(name);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
FindClose(handle);
|
||||||
|
}
|
||||||
|
if(list.size() > 0) sort(&list[0], list.size());
|
||||||
|
return list;
|
||||||
|
}
|
||||||
|
|
||||||
|
inline lstring directory::contents(const string &pathname, const string &pattern) {
|
||||||
|
lstring folders = directory::folders(pathname); //pattern search of contents() should only filter files
|
||||||
|
lstring files = directory::files(pathname, pattern);
|
||||||
|
foreach(file, files) folders.append(file);
|
||||||
|
return folders;
|
||||||
|
}
|
||||||
|
#else
|
||||||
|
inline bool directory::exists(const string &pathname) {
|
||||||
|
DIR *dp = opendir(pathname);
|
||||||
|
if(!dp) return false;
|
||||||
|
closedir(dp);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
inline lstring directory::folders(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(string(ep->d_name, "/"));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
closedir(dp);
|
||||||
|
}
|
||||||
|
if(list.size() > 0) sort(&list[0], list.size());
|
||||||
|
return list;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
inline lstring directory::files(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);
|
||||||
|
}
|
||||||
|
if(list.size() > 0) sort(&list[0], list.size());
|
||||||
|
return list;
|
||||||
|
}
|
||||||
|
|
||||||
|
inline lstring directory::contents(const string &pathname, const string &pattern) {
|
||||||
|
lstring folders = directory::folders(pathname); //pattern search of contents() should only filter files
|
||||||
|
lstring files = directory::files(pathname, pattern);
|
||||||
|
foreach(file, files) folders.append(file);
|
||||||
|
return folders;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif
|
|
@ -3,9 +3,9 @@
|
||||||
|
|
||||||
//dynamic linking support
|
//dynamic linking support
|
||||||
|
|
||||||
#include <string.h>
|
|
||||||
#include <nall/detect.hpp>
|
#include <nall/detect.hpp>
|
||||||
#include <nall/stdint.hpp>
|
#include <nall/stdint.hpp>
|
||||||
|
#include <nall/string.hpp>
|
||||||
#include <nall/utility.hpp>
|
#include <nall/utility.hpp>
|
||||||
|
|
||||||
#if defined(PLATFORM_X) || defined(PLATFORM_OSX)
|
#if defined(PLATFORM_X) || defined(PLATFORM_OSX)
|
||||||
|
@ -18,7 +18,7 @@
|
||||||
namespace nall {
|
namespace nall {
|
||||||
struct library {
|
struct library {
|
||||||
bool opened() const { return handle; }
|
bool opened() const { return handle; }
|
||||||
bool open(const char*);
|
bool open(const char*, const char* = "");
|
||||||
void* sym(const char*);
|
void* sym(const char*);
|
||||||
void close();
|
void close();
|
||||||
|
|
||||||
|
@ -33,20 +33,10 @@ namespace nall {
|
||||||
};
|
};
|
||||||
|
|
||||||
#if defined(PLATFORM_X)
|
#if defined(PLATFORM_X)
|
||||||
inline bool library::open(const char *name) {
|
inline bool library::open(const char *name, const char *path) {
|
||||||
if(handle) close();
|
if(handle) close();
|
||||||
char *t = new char[strlen(name) + 256];
|
handle = (uintptr_t)dlopen(string(path, *path && !strend(path, "/") ? "/" : "", "lib", name, ".so"), RTLD_LAZY);
|
||||||
strcpy(t, "lib");
|
if(!handle) handle = (uintptr_t)dlopen(string("/usr/local/lib/lib", name, ".so"), RTLD_LAZY);
|
||||||
strcat(t, name);
|
|
||||||
strcat(t, ".so");
|
|
||||||
handle = (uintptr_t)dlopen(t, RTLD_LAZY);
|
|
||||||
if(!handle) {
|
|
||||||
strcpy(t, "/usr/local/lib/lib");
|
|
||||||
strcat(t, name);
|
|
||||||
strcat(t, ".so");
|
|
||||||
handle = (uintptr_t)dlopen(t, RTLD_LAZY);
|
|
||||||
}
|
|
||||||
delete[] t;
|
|
||||||
return handle;
|
return handle;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -61,20 +51,10 @@ namespace nall {
|
||||||
handle = 0;
|
handle = 0;
|
||||||
}
|
}
|
||||||
#elif defined(PLATFORM_OSX)
|
#elif defined(PLATFORM_OSX)
|
||||||
inline bool library::open(const char *name) {
|
inline bool library::open(const char *name, const char *path) {
|
||||||
if(handle) close();
|
if(handle) close();
|
||||||
char *t = new char[strlen(name) + 256];
|
handle = (uintptr_t)dlopen(string(path, *path && !strend(path, "/") ? "/" : "", "lib", name, ".dylib"), RTLD_LAZY);
|
||||||
strcpy(t, "lib");
|
if(!handle) handle = (uintptr_t)dlopen(string("/usr/local/lib/lib", name, ".dylib"), RTLD_LAZY);
|
||||||
strcat(t, name);
|
|
||||||
strcat(t, ".dylib");
|
|
||||||
handle = (uintptr_t)dlopen(t, RTLD_LAZY);
|
|
||||||
if(!handle) {
|
|
||||||
strcpy(t, "/usr/local/lib/lib");
|
|
||||||
strcat(t, name);
|
|
||||||
strcat(t, ".dylib");
|
|
||||||
handle = (uintptr_t)dlopen(t, RTLD_LAZY);
|
|
||||||
}
|
|
||||||
delete[] t;
|
|
||||||
return handle;
|
return handle;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -89,13 +69,10 @@ namespace nall {
|
||||||
handle = 0;
|
handle = 0;
|
||||||
}
|
}
|
||||||
#elif defined(PLATFORM_WIN)
|
#elif defined(PLATFORM_WIN)
|
||||||
inline bool library::open(const char *name) {
|
inline bool library::open(const char *name, const char *path) {
|
||||||
if(handle) close();
|
if(handle) close();
|
||||||
char *t = new char[strlen(name) + 8];
|
string filepath(path, *path && !strend(path, "/") && !strend(path, "\\") ? "\\" : "", name, ".dll");
|
||||||
strcpy(t, name);
|
handle = (uintptr_t)LoadLibraryW(utf16_t(filepath));
|
||||||
strcat(t, ".dll");
|
|
||||||
handle = (uintptr_t)LoadLibraryW(utf16_t(t));
|
|
||||||
delete[] t;
|
|
||||||
return handle;
|
return handle;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -110,7 +87,7 @@ namespace nall {
|
||||||
handle = 0;
|
handle = 0;
|
||||||
}
|
}
|
||||||
#else
|
#else
|
||||||
inline bool library::open(const char*) { return false; }
|
inline bool library::open(const char*, const char*) { return false; }
|
||||||
inline void* library::sym(const char*) { return 0; }
|
inline void* library::sym(const char*) { return 0; }
|
||||||
inline void library::close() {}
|
inline void library::close() {}
|
||||||
#endif
|
#endif
|
||||||
|
|
|
@ -11,6 +11,7 @@
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#include <nall/stdint.hpp>
|
#include <nall/stdint.hpp>
|
||||||
|
#include <nall/string.hpp>
|
||||||
#include <nall/utf8.hpp>
|
#include <nall/utf8.hpp>
|
||||||
#include <nall/utility.hpp>
|
#include <nall/utility.hpp>
|
||||||
|
|
||||||
|
@ -25,12 +26,12 @@ namespace nall {
|
||||||
|
|
||||||
class file {
|
class file {
|
||||||
public:
|
public:
|
||||||
enum FileMode { mode_read, mode_write, mode_readwrite, mode_writeread };
|
enum class mode : unsigned { read, write, readwrite, writeread };
|
||||||
enum SeekMode { seek_absolute, seek_relative };
|
enum class index : unsigned { absolute, relative };
|
||||||
|
|
||||||
uint8_t read() {
|
uint8_t read() {
|
||||||
if(!fp) return 0xff; //file not open
|
if(!fp) return 0xff; //file not open
|
||||||
if(file_mode == mode_write) return 0xff; //reads not permitted
|
if(file_mode == mode::write) return 0xff; //reads not permitted
|
||||||
if(file_offset >= file_size) return 0xff; //cannot read past end of file
|
if(file_offset >= file_size) return 0xff; //cannot read past end of file
|
||||||
buffer_sync();
|
buffer_sync();
|
||||||
return buffer[(file_offset++) & buffer_mask];
|
return buffer[(file_offset++) & buffer_mask];
|
||||||
|
@ -58,8 +59,8 @@ namespace nall {
|
||||||
}
|
}
|
||||||
|
|
||||||
void write(uint8_t data) {
|
void write(uint8_t data) {
|
||||||
if(!fp) return; //file not open
|
if(!fp) return; //file not open
|
||||||
if(file_mode == mode_read) return; //writes not permitted
|
if(file_mode == mode::read) return; //writes not permitted
|
||||||
buffer_sync();
|
buffer_sync();
|
||||||
buffer[(file_offset++) & buffer_mask] = data;
|
buffer[(file_offset++) & buffer_mask] = data;
|
||||||
buffer_dirty = true;
|
buffer_dirty = true;
|
||||||
|
@ -83,9 +84,10 @@ namespace nall {
|
||||||
while(length--) write(*buffer++);
|
while(length--) write(*buffer++);
|
||||||
}
|
}
|
||||||
|
|
||||||
void print(const char *string) {
|
template<typename... Args> void print(Args... args) {
|
||||||
if(!string) return;
|
string data(args...);
|
||||||
while(*string) write(*string++);
|
const char *p = data;
|
||||||
|
while(*p) write(*p++);
|
||||||
}
|
}
|
||||||
|
|
||||||
void flush() {
|
void flush() {
|
||||||
|
@ -93,19 +95,19 @@ namespace nall {
|
||||||
fflush(fp);
|
fflush(fp);
|
||||||
}
|
}
|
||||||
|
|
||||||
void seek(int offset, SeekMode mode = seek_absolute) {
|
void seek(int offset, index index_ = index::absolute) {
|
||||||
if(!fp) return; //file not open
|
if(!fp) return; //file not open
|
||||||
buffer_flush();
|
buffer_flush();
|
||||||
|
|
||||||
uintmax_t req_offset = file_offset;
|
uintmax_t req_offset = file_offset;
|
||||||
switch(mode) {
|
switch(index_) {
|
||||||
case seek_absolute: req_offset = offset; break;
|
case index::absolute: req_offset = offset; break;
|
||||||
case seek_relative: 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 < 0) req_offset = 0; //cannot seek before start of file
|
||||||
if(req_offset > file_size) {
|
if(req_offset > file_size) {
|
||||||
if(file_mode == mode_read) { //cannot seek past end of file
|
if(file_mode == mode::read) { //cannot seek past end of file
|
||||||
req_offset = file_size;
|
req_offset = file_size;
|
||||||
} else { //pad file to requested location
|
} else { //pad file to requested location
|
||||||
file_offset = file_size;
|
file_offset = file_size;
|
||||||
|
@ -172,20 +174,20 @@ namespace nall {
|
||||||
return fp;
|
return fp;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool open(const char *fn, FileMode mode) {
|
bool open(const char *fn, mode mode_) {
|
||||||
if(fp) return false;
|
if(fp) return false;
|
||||||
|
|
||||||
switch(file_mode = mode) {
|
switch(file_mode = mode_) {
|
||||||
#if !defined(_WIN32)
|
#if !defined(_WIN32)
|
||||||
case mode_read: fp = fopen(fn, "rb"); break;
|
case mode::read: fp = fopen(fn, "rb"); break;
|
||||||
case mode_write: fp = fopen(fn, "wb+"); break; //need read permission for buffering
|
case mode::write: fp = fopen(fn, "wb+"); break; //need read permission for buffering
|
||||||
case mode_readwrite: fp = fopen(fn, "rb+"); break;
|
case mode::readwrite: fp = fopen(fn, "rb+"); break;
|
||||||
case mode_writeread: fp = fopen(fn, "wb+"); break;
|
case mode::writeread: fp = fopen(fn, "wb+"); break;
|
||||||
#else
|
#else
|
||||||
case mode_read: fp = _wfopen(utf16_t(fn), L"rb"); break;
|
case mode::read: fp = _wfopen(utf16_t(fn), L"rb"); break;
|
||||||
case mode_write: fp = _wfopen(utf16_t(fn), L"wb+"); break;
|
case mode::write: fp = _wfopen(utf16_t(fn), L"wb+"); break;
|
||||||
case mode_readwrite: fp = _wfopen(utf16_t(fn), L"rb+"); break;
|
case mode::readwrite: fp = _wfopen(utf16_t(fn), L"rb+"); break;
|
||||||
case mode_writeread: fp = _wfopen(utf16_t(fn), L"wb+"); break;
|
case mode::writeread: fp = _wfopen(utf16_t(fn), L"wb+"); break;
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
if(!fp) return false;
|
if(!fp) return false;
|
||||||
|
@ -211,7 +213,7 @@ namespace nall {
|
||||||
fp = 0;
|
fp = 0;
|
||||||
file_offset = 0;
|
file_offset = 0;
|
||||||
file_size = 0;
|
file_size = 0;
|
||||||
file_mode = mode_read;
|
file_mode = mode::read;
|
||||||
}
|
}
|
||||||
|
|
||||||
~file() {
|
~file() {
|
||||||
|
@ -229,7 +231,7 @@ namespace nall {
|
||||||
FILE *fp;
|
FILE *fp;
|
||||||
unsigned file_offset;
|
unsigned file_offset;
|
||||||
unsigned file_size;
|
unsigned file_size;
|
||||||
FileMode file_mode;
|
mode file_mode;
|
||||||
|
|
||||||
void buffer_sync() {
|
void buffer_sync() {
|
||||||
if(!fp) return; //file not open
|
if(!fp) return; //file not open
|
||||||
|
@ -243,14 +245,14 @@ namespace nall {
|
||||||
}
|
}
|
||||||
|
|
||||||
void buffer_flush() {
|
void buffer_flush() {
|
||||||
if(!fp) return; //file not open
|
if(!fp) return; //file not open
|
||||||
if(file_mode == mode_read) return; //buffer cannot be written to
|
if(file_mode == mode::read) return; //buffer cannot be written to
|
||||||
if(buffer_offset < 0) return; //buffer unused
|
if(buffer_offset < 0) return; //buffer unused
|
||||||
if(buffer_dirty == false) return; //buffer unmodified since read
|
if(buffer_dirty == false) return; //buffer unmodified since read
|
||||||
fseek(fp, buffer_offset, SEEK_SET);
|
fseek(fp, buffer_offset, SEEK_SET);
|
||||||
unsigned length = (buffer_offset + buffer_size) <= file_size ? buffer_size : (file_size & buffer_mask);
|
unsigned length = (buffer_offset + buffer_size) <= file_size ? buffer_size : (file_size & buffer_mask);
|
||||||
if(length) unsigned unused = fwrite(buffer, 1, length, fp);
|
if(length) unsigned unused = fwrite(buffer, 1, length, fp);
|
||||||
buffer_offset = -1; //invalidate buffer
|
buffer_offset = -1; //invalidate buffer
|
||||||
buffer_dirty = false;
|
buffer_dirty = false;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
|
@ -19,14 +19,16 @@
|
||||||
namespace nall {
|
namespace nall {
|
||||||
class filemap {
|
class filemap {
|
||||||
public:
|
public:
|
||||||
enum filemode { mode_read, mode_write, mode_readwrite, mode_writeread };
|
enum class mode : unsigned { read, write, readwrite, writeread };
|
||||||
|
|
||||||
bool open(const char *filename, filemode mode) { return p_open(filename, mode); }
|
bool opened() const { return p_opened(); }
|
||||||
|
bool open(const char *filename, mode mode_) { return p_open(filename, mode_); }
|
||||||
void close() { return p_close(); }
|
void close() { return p_close(); }
|
||||||
unsigned size() const { return p_size; }
|
unsigned size() const { return p_size; }
|
||||||
uint8_t* handle() { return p_handle; }
|
uint8_t* data() { return p_handle; }
|
||||||
const uint8_t* handle() const { return p_handle; }
|
const uint8_t* data() const { return p_handle; }
|
||||||
filemap() : p_size(0), p_handle(0) { p_ctor(); }
|
filemap() : p_size(0), p_handle(0) { p_ctor(); }
|
||||||
|
filemap(const char *filename, mode mode_) : p_size(0), p_handle(0) { p_ctor(); p_open(filename, mode_); }
|
||||||
~filemap() { p_dtor(); }
|
~filemap() { p_dtor(); }
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
@ -40,31 +42,35 @@ namespace nall {
|
||||||
|
|
||||||
HANDLE p_filehandle, p_maphandle;
|
HANDLE p_filehandle, p_maphandle;
|
||||||
|
|
||||||
bool p_open(const char *filename, filemode mode) {
|
bool p_opened() const {
|
||||||
|
return p_handle;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool p_open(const char *filename, mode mode_) {
|
||||||
int desired_access, creation_disposition, flprotect, map_access;
|
int desired_access, creation_disposition, flprotect, map_access;
|
||||||
|
|
||||||
switch(mode) {
|
switch(mode_) {
|
||||||
default: return false;
|
default: return false;
|
||||||
case mode_read:
|
case mode::read:
|
||||||
desired_access = GENERIC_READ;
|
desired_access = GENERIC_READ;
|
||||||
creation_disposition = OPEN_EXISTING;
|
creation_disposition = OPEN_EXISTING;
|
||||||
flprotect = PAGE_READONLY;
|
flprotect = PAGE_READONLY;
|
||||||
map_access = FILE_MAP_READ;
|
map_access = FILE_MAP_READ;
|
||||||
break;
|
break;
|
||||||
case mode_write:
|
case mode::write:
|
||||||
//write access requires read access
|
//write access requires read access
|
||||||
desired_access = GENERIC_WRITE;
|
desired_access = GENERIC_WRITE;
|
||||||
creation_disposition = CREATE_ALWAYS;
|
creation_disposition = CREATE_ALWAYS;
|
||||||
flprotect = PAGE_READWRITE;
|
flprotect = PAGE_READWRITE;
|
||||||
map_access = FILE_MAP_ALL_ACCESS;
|
map_access = FILE_MAP_ALL_ACCESS;
|
||||||
break;
|
break;
|
||||||
case mode_readwrite:
|
case mode::readwrite:
|
||||||
desired_access = GENERIC_READ | GENERIC_WRITE;
|
desired_access = GENERIC_READ | GENERIC_WRITE;
|
||||||
creation_disposition = OPEN_EXISTING;
|
creation_disposition = OPEN_EXISTING;
|
||||||
flprotect = PAGE_READWRITE;
|
flprotect = PAGE_READWRITE;
|
||||||
map_access = FILE_MAP_ALL_ACCESS;
|
map_access = FILE_MAP_ALL_ACCESS;
|
||||||
break;
|
break;
|
||||||
case mode_writeread:
|
case mode::writeread:
|
||||||
desired_access = GENERIC_READ | GENERIC_WRITE;
|
desired_access = GENERIC_READ | GENERIC_WRITE;
|
||||||
creation_disposition = CREATE_NEW;
|
creation_disposition = CREATE_NEW;
|
||||||
flprotect = PAGE_READWRITE;
|
flprotect = PAGE_READWRITE;
|
||||||
|
@ -122,30 +128,34 @@ namespace nall {
|
||||||
|
|
||||||
int p_fd;
|
int p_fd;
|
||||||
|
|
||||||
bool p_open(const char *filename, filemode mode) {
|
bool p_opened() const {
|
||||||
|
return p_handle;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool p_open(const char *filename, mode mode_) {
|
||||||
int open_flags, mmap_flags;
|
int open_flags, mmap_flags;
|
||||||
|
|
||||||
switch(mode) {
|
switch(mode_) {
|
||||||
default: return false;
|
default: return false;
|
||||||
case mode_read:
|
case mode::read:
|
||||||
open_flags = O_RDONLY;
|
open_flags = O_RDONLY;
|
||||||
mmap_flags = PROT_READ;
|
mmap_flags = PROT_READ;
|
||||||
break;
|
break;
|
||||||
case mode_write:
|
case mode::write:
|
||||||
open_flags = O_RDWR | O_CREAT; //mmap() requires read access
|
open_flags = O_RDWR | O_CREAT; //mmap() requires read access
|
||||||
mmap_flags = PROT_WRITE;
|
mmap_flags = PROT_WRITE;
|
||||||
break;
|
break;
|
||||||
case mode_readwrite:
|
case mode::readwrite:
|
||||||
open_flags = O_RDWR;
|
open_flags = O_RDWR;
|
||||||
mmap_flags = PROT_READ | PROT_WRITE;
|
mmap_flags = PROT_READ | PROT_WRITE;
|
||||||
break;
|
break;
|
||||||
case mode_writeread:
|
case mode::writeread:
|
||||||
open_flags = O_RDWR | O_CREAT;
|
open_flags = O_RDWR | O_CREAT;
|
||||||
mmap_flags = PROT_READ | PROT_WRITE;
|
mmap_flags = PROT_READ | PROT_WRITE;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
p_fd = ::open(filename, open_flags);
|
p_fd = ::open(filename, open_flags, S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP);
|
||||||
if(p_fd < 0) return false;
|
if(p_fd < 0) return false;
|
||||||
|
|
||||||
struct stat p_stat;
|
struct stat p_stat;
|
||||||
|
|
|
@ -1,89 +1,59 @@
|
||||||
#ifndef NALL_FUNCTION_HPP
|
#ifndef NALL_FUNCTION_HPP
|
||||||
#define NALL_FUNCTION_HPP
|
#define NALL_FUNCTION_HPP
|
||||||
|
|
||||||
#include <functional>
|
|
||||||
#include <type_traits>
|
|
||||||
|
|
||||||
namespace nall {
|
namespace nall {
|
||||||
template<typename T> class function;
|
template<typename T> class function;
|
||||||
|
|
||||||
template<typename R, typename... P>
|
template<typename R, typename... P> class function<R (P...)> {
|
||||||
class function<R (P...)> {
|
struct container {
|
||||||
private:
|
virtual R operator()(P... p) const = 0;
|
||||||
struct base1 { virtual void func1(P...) {} };
|
virtual container* copy() const = 0;
|
||||||
struct base2 { virtual void func2(P...) {} };
|
virtual ~container() {}
|
||||||
struct derived : base1, virtual base2 {};
|
} *callback;
|
||||||
|
|
||||||
struct data_t {
|
struct global : container {
|
||||||
R (*callback)(const data_t&, P...);
|
R (*function)(P...);
|
||||||
union {
|
R operator()(P... p) const { return function(std::forward<P>(p)...); }
|
||||||
R (*callback_global)(P...);
|
container* copy() const { return new global(function); }
|
||||||
struct {
|
global(R (*function)(P...)) : function(function) {}
|
||||||
R (derived::*callback_member)(P...);
|
};
|
||||||
void *object;
|
|
||||||
};
|
|
||||||
};
|
|
||||||
} data;
|
|
||||||
|
|
||||||
static R callback_global(const data_t &data, P... p) {
|
template<typename C> struct member : container {
|
||||||
return data.callback_global(p...);
|
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 C>
|
template<typename L> struct lambda : container {
|
||||||
static R callback_member(const data_t &data, P... p) {
|
L object;
|
||||||
return (((C*)data.object)->*((R (C::*&)(P...))data.callback_member))(p...);
|
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:
|
public:
|
||||||
R operator()(P... p) const { return data.callback(data, p...); }
|
operator bool() const { return callback; }
|
||||||
operator bool() const { return data.callback; }
|
R operator()(P... p) const { return (*callback)(std::forward<P>(p)...); }
|
||||||
void reset() { data.callback = 0; }
|
void reset() { if(callback) { delete callback; callback = 0; } }
|
||||||
|
|
||||||
|
function& operator=(const function &source) {
|
||||||
|
if(this != &source) {
|
||||||
|
if(callback) { delete callback; callback = 0; }
|
||||||
|
if(source.callback) callback = source.callback->copy();
|
||||||
|
}
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
|
||||||
function& operator=(const function &source) { memcpy(&data, &source.data, sizeof(data_t)); return *this; }
|
|
||||||
function(const function &source) { operator=(source); }
|
function(const function &source) { operator=(source); }
|
||||||
|
function() : callback(0) {}
|
||||||
//no pointer
|
function(void *function) : callback(0) { if(function) callback = new global((R (*)(P...))function); }
|
||||||
function() {
|
function(R (*function)(P...)) { callback = new global(function); }
|
||||||
data.callback = 0;
|
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); }
|
||||||
//symbolic link pointer (nall/dl.hpp::sym, etc)
|
~function() { if(callback) delete callback; }
|
||||||
function(void *callback) {
|
|
||||||
data.callback = callback ? &callback_global : 0;
|
|
||||||
data.callback_global = (R (*)(P...))callback;
|
|
||||||
}
|
|
||||||
|
|
||||||
//global function pointer
|
|
||||||
function(R (*callback)(P...)) {
|
|
||||||
data.callback = &callback_global;
|
|
||||||
data.callback_global = callback;
|
|
||||||
}
|
|
||||||
|
|
||||||
//member function pointer
|
|
||||||
template<typename C>
|
|
||||||
function(R (C::*callback)(P...), C *object) {
|
|
||||||
static_assert(sizeof data.callback_member >= sizeof callback, "callback_member is too small");
|
|
||||||
data.callback = &callback_member<C>;
|
|
||||||
(R (C::*&)(P...))data.callback_member = callback;
|
|
||||||
data.object = object;
|
|
||||||
}
|
|
||||||
|
|
||||||
//const member function pointer
|
|
||||||
template<typename C>
|
|
||||||
function(R (C::*callback)(P...) const, C *object) {
|
|
||||||
static_assert(sizeof data.callback_member >= sizeof callback, "callback_member is too small");
|
|
||||||
data.callback = &callback_member<C>;
|
|
||||||
(R (C::*&)(P...))data.callback_member = (R (C::*&)(P...))callback;
|
|
||||||
data.object = object;
|
|
||||||
}
|
|
||||||
|
|
||||||
//lambda function pointer
|
|
||||||
template<typename T>
|
|
||||||
function(T callback) {
|
|
||||||
static_assert(std::is_same<R, typename std::result_of<T(P...)>::type>::value, "lambda mismatch");
|
|
||||||
data.callback = &callback_global;
|
|
||||||
data.callback_global = (R (*)(P...))callback;
|
|
||||||
}
|
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -91,7 +91,7 @@ struct Keyboard {
|
||||||
static uint16_t decode(const char *name) {
|
static uint16_t decode(const char *name) {
|
||||||
string s(name);
|
string s(name);
|
||||||
if(!strbegin(name, "KB")) return 0;
|
if(!strbegin(name, "KB")) return 0;
|
||||||
ltrim(s, "KB");
|
s.ltrim("KB");
|
||||||
unsigned id = strunsigned(s);
|
unsigned id = strunsigned(s);
|
||||||
auto pos = strpos(s, "::");
|
auto pos = strpos(s, "::");
|
||||||
if(!pos) return 0;
|
if(!pos) return 0;
|
||||||
|
@ -188,7 +188,7 @@ struct Mouse {
|
||||||
static uint16_t decode(const char *name) {
|
static uint16_t decode(const char *name) {
|
||||||
string s(name);
|
string s(name);
|
||||||
if(!strbegin(name, "MS")) return 0;
|
if(!strbegin(name, "MS")) return 0;
|
||||||
ltrim(s, "MS");
|
s.ltrim("MS");
|
||||||
unsigned id = strunsigned(s);
|
unsigned id = strunsigned(s);
|
||||||
auto pos = strpos(s, "::");
|
auto pos = strpos(s, "::");
|
||||||
if(!pos) return 0;
|
if(!pos) return 0;
|
||||||
|
@ -312,7 +312,7 @@ struct Joypad {
|
||||||
static uint16_t decode(const char *name) {
|
static uint16_t decode(const char *name) {
|
||||||
string s(name);
|
string s(name);
|
||||||
if(!strbegin(name, "JP")) return 0;
|
if(!strbegin(name, "JP")) return 0;
|
||||||
ltrim(s, "JP");
|
s.ltrim("JP");
|
||||||
unsigned id = strunsigned(s);
|
unsigned id = strunsigned(s);
|
||||||
auto pos = strpos(s, "::");
|
auto pos = strpos(s, "::");
|
||||||
if(!pos) return 0;
|
if(!pos) return 0;
|
||||||
|
|
|
@ -23,10 +23,12 @@
|
||||||
#include <direct.h>
|
#include <direct.h>
|
||||||
#include <shlobj.h>
|
#include <shlobj.h>
|
||||||
#undef interface
|
#undef interface
|
||||||
|
#define dllexport __declspec(dllexport)
|
||||||
#else
|
#else
|
||||||
#include <unistd.h>
|
#include <unistd.h>
|
||||||
#include <pwd.h>
|
#include <pwd.h>
|
||||||
#include <sys/stat.h>
|
#include <sys/stat.h>
|
||||||
|
#define dllexport
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
//==================
|
//==================
|
||||||
|
@ -76,5 +78,45 @@
|
||||||
#define alwaysinline inline
|
#define alwaysinline inline
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
//=========================
|
||||||
|
//file system functionality
|
||||||
|
//=========================
|
||||||
|
|
||||||
|
#if defined(_WIN32)
|
||||||
|
inline char* realpath(const char *filename, char *resolvedname) {
|
||||||
|
wchar_t fn[_MAX_PATH] = L"";
|
||||||
|
_wfullpath(fn, nall::utf16_t(filename), _MAX_PATH);
|
||||||
|
strcpy(resolvedname, nall::utf8_t(fn));
|
||||||
|
return resolvedname;
|
||||||
|
}
|
||||||
|
|
||||||
|
inline char* userpath(char *path) {
|
||||||
|
wchar_t fp[_MAX_PATH] = L"";
|
||||||
|
SHGetFolderPathW(0, CSIDL_APPDATA | CSIDL_FLAG_CREATE, 0, 0, fp);
|
||||||
|
strcpy(path, nall::utf8_t(fp));
|
||||||
|
return path;
|
||||||
|
}
|
||||||
|
|
||||||
|
inline char* getcwd(char *path) {
|
||||||
|
wchar_t fp[_MAX_PATH] = L"";
|
||||||
|
_wgetcwd(fp, _MAX_PATH);
|
||||||
|
strcpy(path, nall::utf8_t(fp));
|
||||||
|
return path;
|
||||||
|
}
|
||||||
|
#else
|
||||||
|
//realpath() already exists
|
||||||
|
|
||||||
|
inline char* userpath(char *path) {
|
||||||
|
*path = 0;
|
||||||
|
struct passwd *userinfo = getpwuid(getuid());
|
||||||
|
if(userinfo) strcpy(path, userinfo->pw_dir);
|
||||||
|
return path;
|
||||||
|
}
|
||||||
|
|
||||||
|
inline char *getcwd(char *path) {
|
||||||
|
return getcwd(path, PATH_MAX);
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
|
|
@ -1,55 +0,0 @@
|
||||||
# requires nall/Makefile
|
|
||||||
|
|
||||||
# imports:
|
|
||||||
# $(qtlibs) -- list of Qt components to link against
|
|
||||||
|
|
||||||
# exports the following symbols:
|
|
||||||
# $(moc) -- meta-object compiler
|
|
||||||
# $(rcc) -- resource compiler
|
|
||||||
# $(qtinc) -- includes for compiling
|
|
||||||
# $(qtlib) -- libraries for linking
|
|
||||||
|
|
||||||
ifeq ($(moc),)
|
|
||||||
moc := moc
|
|
||||||
endif
|
|
||||||
|
|
||||||
ifeq ($(rcc),)
|
|
||||||
rcc := rcc
|
|
||||||
endif
|
|
||||||
|
|
||||||
ifeq ($(platform),x)
|
|
||||||
qtinc := `pkg-config --cflags $(qtlibs)`
|
|
||||||
qtlib := `pkg-config --libs $(qtlibs)`
|
|
||||||
else ifeq ($(platform),osx)
|
|
||||||
qtinc := $(foreach lib,$(qtlibs),-I/Library/Frameworks/$(lib).framework/Versions/4/Headers)
|
|
||||||
|
|
||||||
qtlib := -L/Library/Frameworks
|
|
||||||
qtlib += $(foreach lib,$(qtlibs),-framework $(lib))
|
|
||||||
qtlib += -framework Carbon
|
|
||||||
qtlib += -framework Cocoa
|
|
||||||
qtlib += -framework OpenGL
|
|
||||||
qtlib += -framework AppKit
|
|
||||||
qtlib += -framework ApplicationServices
|
|
||||||
else ifeq ($(platform),win)
|
|
||||||
ifeq ($(qtpath),)
|
|
||||||
# find Qt install directory from PATH environment variable
|
|
||||||
qtpath := $(foreach path,$(subst ;, ,$(PATH)),$(if $(wildcard $(path)/$(moc).exe),$(path)))
|
|
||||||
qtpath := $(strip $(qtpath))
|
|
||||||
qtpath := $(subst \,/,$(qtpath))
|
|
||||||
qtpath := $(patsubst %/bin,%,$(qtpath))
|
|
||||||
endif
|
|
||||||
|
|
||||||
qtinc := -I$(qtpath)/include
|
|
||||||
qtinc += $(foreach lib,$(qtlibs),-I$(qtpath)/include/$(lib))
|
|
||||||
|
|
||||||
qtlib := -L$(qtpath)/lib
|
|
||||||
qtlib += -L$(qtpath)/plugins/imageformats
|
|
||||||
|
|
||||||
qtlib += $(foreach lib,$(qtlibs),-l$(lib)4)
|
|
||||||
qtlib += -lmingw32 -lqtmain -lcomdlg32 -loleaut32 -limm32 -lwinmm
|
|
||||||
qtlib += -lwinspool -lmsimg32 -lole32 -ladvapi32 -lws2_32 -luuid -lgdi32
|
|
||||||
qtlib += $(foreach lib,$(qtlibs),-l$(lib)4)
|
|
||||||
|
|
||||||
# optional image-file support:
|
|
||||||
# qtlib += -lqjpeg -lqmng
|
|
||||||
endif
|
|
|
@ -1,41 +0,0 @@
|
||||||
#ifndef NALL_QT_CHECKACTION_HPP
|
|
||||||
#define NALL_QT_CHECKACTION_HPP
|
|
||||||
|
|
||||||
namespace nall {
|
|
||||||
|
|
||||||
class CheckAction : public QAction {
|
|
||||||
Q_OBJECT
|
|
||||||
|
|
||||||
public:
|
|
||||||
bool isChecked() const;
|
|
||||||
void setChecked(bool);
|
|
||||||
void toggleChecked();
|
|
||||||
CheckAction(const QString&, QObject*);
|
|
||||||
|
|
||||||
protected slots:
|
|
||||||
|
|
||||||
protected:
|
|
||||||
bool checked;
|
|
||||||
};
|
|
||||||
|
|
||||||
inline bool CheckAction::isChecked() const {
|
|
||||||
return checked;
|
|
||||||
}
|
|
||||||
|
|
||||||
inline void CheckAction::setChecked(bool checked_) {
|
|
||||||
checked = checked_;
|
|
||||||
if(checked) setIcon(QIcon(":/16x16/item-check-on.png"));
|
|
||||||
else setIcon(QIcon(":/16x16/item-check-off.png"));
|
|
||||||
}
|
|
||||||
|
|
||||||
inline void CheckAction::toggleChecked() {
|
|
||||||
setChecked(!isChecked());
|
|
||||||
}
|
|
||||||
|
|
||||||
inline CheckAction::CheckAction(const QString &text, QObject *parent) : QAction(text, parent) {
|
|
||||||
setChecked(false);
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
#endif
|
|
|
@ -1,10 +0,0 @@
|
||||||
#ifndef NALL_QT_CONCEPT_HPP
|
|
||||||
#define NALL_QT_CONCEPT_HPP
|
|
||||||
|
|
||||||
#include <nall/concept.hpp>
|
|
||||||
|
|
||||||
namespace nall {
|
|
||||||
template<typename T> struct has_count<QList<T>> { enum { value = true }; };
|
|
||||||
}
|
|
||||||
|
|
||||||
#endif
|
|
|
@ -1,392 +0,0 @@
|
||||||
#ifndef NALL_QT_FILEDIALOG_HPP
|
|
||||||
#define NALL_QT_FILEDIALOG_HPP
|
|
||||||
|
|
||||||
#include <nall/platform.hpp>
|
|
||||||
#include <nall/string.hpp>
|
|
||||||
#include <nall/qt/window.moc.hpp>
|
|
||||||
|
|
||||||
namespace nall {
|
|
||||||
|
|
||||||
class FileDialog;
|
|
||||||
|
|
||||||
class NewFolderDialog : public Window {
|
|
||||||
Q_OBJECT
|
|
||||||
|
|
||||||
public:
|
|
||||||
void show();
|
|
||||||
NewFolderDialog(FileDialog*);
|
|
||||||
|
|
||||||
protected slots:
|
|
||||||
void createFolderAction();
|
|
||||||
|
|
||||||
protected:
|
|
||||||
FileDialog *parent;
|
|
||||||
QVBoxLayout *layout;
|
|
||||||
QLineEdit *folderNameEdit;
|
|
||||||
QHBoxLayout *controlLayout;
|
|
||||||
QPushButton *okButton;
|
|
||||||
QPushButton *cancelButton;
|
|
||||||
};
|
|
||||||
|
|
||||||
class FileView : public QListView {
|
|
||||||
Q_OBJECT
|
|
||||||
|
|
||||||
protected:
|
|
||||||
void keyPressEvent(QKeyEvent*);
|
|
||||||
|
|
||||||
signals:
|
|
||||||
void changed(const QModelIndex&);
|
|
||||||
void browseUp();
|
|
||||||
|
|
||||||
protected slots:
|
|
||||||
void currentChanged(const QModelIndex&, const QModelIndex&);
|
|
||||||
};
|
|
||||||
|
|
||||||
class FileDialog : public Window {
|
|
||||||
Q_OBJECT
|
|
||||||
|
|
||||||
public:
|
|
||||||
void showLoad();
|
|
||||||
void showSave();
|
|
||||||
void showFolder();
|
|
||||||
|
|
||||||
void setPath(string path);
|
|
||||||
void setNameFilters(const string &filters);
|
|
||||||
FileDialog();
|
|
||||||
|
|
||||||
signals:
|
|
||||||
void changed(const string&);
|
|
||||||
void activated(const string&);
|
|
||||||
void accepted(const string&);
|
|
||||||
void rejected();
|
|
||||||
|
|
||||||
protected slots:
|
|
||||||
void fileViewChange(const QModelIndex&);
|
|
||||||
void fileViewActivate(const QModelIndex&);
|
|
||||||
void pathBoxChanged();
|
|
||||||
void filterBoxChanged();
|
|
||||||
void createNewFolder();
|
|
||||||
void browseUp();
|
|
||||||
void acceptAction();
|
|
||||||
void rejectAction();
|
|
||||||
|
|
||||||
protected:
|
|
||||||
NewFolderDialog *newFolderDialog;
|
|
||||||
QVBoxLayout *layout;
|
|
||||||
QHBoxLayout *navigationLayout;
|
|
||||||
QComboBox *pathBox;
|
|
||||||
QPushButton *newFolderButton;
|
|
||||||
QPushButton *upFolderButton;
|
|
||||||
QHBoxLayout *browseLayout;
|
|
||||||
QFileSystemModel *fileSystemModel;
|
|
||||||
FileView *fileView;
|
|
||||||
QGroupBox *previewFrame;
|
|
||||||
QLineEdit *fileNameEdit;
|
|
||||||
QHBoxLayout *controlLayout;
|
|
||||||
QComboBox *filterBox;
|
|
||||||
QPushButton *optionsButton;
|
|
||||||
QPushButton *acceptButton;
|
|
||||||
QPushButton *rejectButton;
|
|
||||||
bool lock;
|
|
||||||
void createFolderAction(const string &name);
|
|
||||||
void closeEvent(QCloseEvent*);
|
|
||||||
|
|
||||||
friend class NewFolderDialog;
|
|
||||||
};
|
|
||||||
|
|
||||||
inline void NewFolderDialog::show() {
|
|
||||||
folderNameEdit->setText("");
|
|
||||||
Window::show();
|
|
||||||
folderNameEdit->setFocus();
|
|
||||||
}
|
|
||||||
|
|
||||||
inline void NewFolderDialog::createFolderAction() {
|
|
||||||
string name = folderNameEdit->text().toUtf8().constData();
|
|
||||||
if(name == "") {
|
|
||||||
folderNameEdit->setFocus();
|
|
||||||
} else {
|
|
||||||
parent->createFolderAction(name);
|
|
||||||
close();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
inline NewFolderDialog::NewFolderDialog(FileDialog *fileDialog) : parent(fileDialog) {
|
|
||||||
setMinimumWidth(240);
|
|
||||||
setWindowTitle("Create New Folder");
|
|
||||||
|
|
||||||
layout = new QVBoxLayout;
|
|
||||||
layout->setAlignment(Qt::AlignTop);
|
|
||||||
layout->setMargin(5);
|
|
||||||
layout->setSpacing(5);
|
|
||||||
setLayout(layout);
|
|
||||||
|
|
||||||
folderNameEdit = new QLineEdit;
|
|
||||||
layout->addWidget(folderNameEdit);
|
|
||||||
|
|
||||||
controlLayout = new QHBoxLayout;
|
|
||||||
controlLayout->setAlignment(Qt::AlignRight);
|
|
||||||
layout->addLayout(controlLayout);
|
|
||||||
|
|
||||||
okButton = new QPushButton("Ok");
|
|
||||||
controlLayout->addWidget(okButton);
|
|
||||||
|
|
||||||
cancelButton = new QPushButton("Cancel");
|
|
||||||
controlLayout->addWidget(cancelButton);
|
|
||||||
|
|
||||||
connect(folderNameEdit, SIGNAL(returnPressed()), this, SLOT(createFolderAction()));
|
|
||||||
connect(okButton, SIGNAL(released()), this, SLOT(createFolderAction()));
|
|
||||||
connect(cancelButton, SIGNAL(released()), this, SLOT(close()));
|
|
||||||
}
|
|
||||||
|
|
||||||
inline void FileView::currentChanged(const QModelIndex ¤t, const QModelIndex &previous) {
|
|
||||||
QAbstractItemView::currentChanged(current, previous);
|
|
||||||
emit changed(current);
|
|
||||||
}
|
|
||||||
|
|
||||||
inline void FileView::keyPressEvent(QKeyEvent *event) {
|
|
||||||
//enhance consistency: force OS X to act like Windows and Linux; enter = activate item
|
|
||||||
if(event->key() == Qt::Key_Return || event->key() == Qt::Key_Enter) {
|
|
||||||
emit activated(currentIndex());
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
//simulate popular file manager behavior; backspace = go up one directory
|
|
||||||
if(event->key() == Qt::Key_Backspace) {
|
|
||||||
emit browseUp();
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
//fallback: unrecognized keypresses get handled by the widget itself
|
|
||||||
QListView::keyPressEvent(event);
|
|
||||||
}
|
|
||||||
|
|
||||||
inline void FileDialog::showLoad() {
|
|
||||||
acceptButton->setText("Load");
|
|
||||||
fileNameEdit->hide();
|
|
||||||
filterBox->show();
|
|
||||||
show();
|
|
||||||
}
|
|
||||||
|
|
||||||
inline void FileDialog::showSave() {
|
|
||||||
acceptButton->setText("Save");
|
|
||||||
fileNameEdit->show();
|
|
||||||
filterBox->show();
|
|
||||||
show();
|
|
||||||
}
|
|
||||||
|
|
||||||
inline void FileDialog::showFolder() {
|
|
||||||
acceptButton->setText("Choose");
|
|
||||||
fileNameEdit->hide();
|
|
||||||
filterBox->hide();
|
|
||||||
setNameFilters("Folders ()");
|
|
||||||
show();
|
|
||||||
}
|
|
||||||
|
|
||||||
inline void FileDialog::fileViewChange(const QModelIndex &index) {
|
|
||||||
string path = fileSystemModel->filePath(index).toUtf8().constData();
|
|
||||||
if(path == fileSystemModel->rootPath().toUtf8().constData()) path = "";
|
|
||||||
fileNameEdit->setText(notdir(path));
|
|
||||||
emit changed(path);
|
|
||||||
}
|
|
||||||
|
|
||||||
inline void FileDialog::fileViewActivate(const QModelIndex &index) {
|
|
||||||
string path = fileSystemModel->filePath(index).toUtf8().constData();
|
|
||||||
if(fileSystemModel->isDir(index)) {
|
|
||||||
emit activated(path);
|
|
||||||
setPath(path);
|
|
||||||
} else {
|
|
||||||
emit activated(path);
|
|
||||||
close();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
inline void FileDialog::pathBoxChanged() {
|
|
||||||
if(lock) return;
|
|
||||||
setPath(pathBox->currentText().toUtf8().constData());
|
|
||||||
}
|
|
||||||
|
|
||||||
inline void FileDialog::filterBoxChanged() {
|
|
||||||
if(lock) return;
|
|
||||||
string filters = filterBox->currentText().toUtf8().constData();
|
|
||||||
if(filters.length() == 0) {
|
|
||||||
fileSystemModel->setNameFilters(QStringList() << "*");
|
|
||||||
} else {
|
|
||||||
filters = substr(filters, strpos(filters, "(")());
|
|
||||||
ltrim(filters, "(");
|
|
||||||
rtrim(filters, ")");
|
|
||||||
lstring part;
|
|
||||||
part.split(" ", filters);
|
|
||||||
QStringList list;
|
|
||||||
for(unsigned i = 0; i < part.size(); i++) list << part[i];
|
|
||||||
fileSystemModel->setNameFilters(list);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
inline void FileDialog::createNewFolder() {
|
|
||||||
newFolderDialog->show();
|
|
||||||
}
|
|
||||||
|
|
||||||
inline void FileDialog::browseUp() {
|
|
||||||
if(pathBox->count() > 1) pathBox->setCurrentIndex(1);
|
|
||||||
}
|
|
||||||
|
|
||||||
inline void FileDialog::setPath(string path) {
|
|
||||||
lock = true;
|
|
||||||
newFolderDialog->close();
|
|
||||||
|
|
||||||
if(QDir(path).exists()) {
|
|
||||||
newFolderButton->setEnabled(true);
|
|
||||||
} else {
|
|
||||||
newFolderButton->setEnabled(false);
|
|
||||||
path = "";
|
|
||||||
}
|
|
||||||
|
|
||||||
fileSystemModel->setRootPath(path);
|
|
||||||
fileView->setRootIndex(fileSystemModel->index(path));
|
|
||||||
fileView->setCurrentIndex(fileView->rootIndex());
|
|
||||||
fileView->setFocus();
|
|
||||||
|
|
||||||
pathBox->clear();
|
|
||||||
if(path.length() > 0) {
|
|
||||||
QDir directory(path);
|
|
||||||
while(true) {
|
|
||||||
pathBox->addItem(directory.absolutePath());
|
|
||||||
if(directory.isRoot()) break;
|
|
||||||
directory.cdUp();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
pathBox->addItem("<root>");
|
|
||||||
fileNameEdit->setText("");
|
|
||||||
|
|
||||||
lock = false;
|
|
||||||
}
|
|
||||||
|
|
||||||
inline void FileDialog::setNameFilters(const string &filters) {
|
|
||||||
lock = true;
|
|
||||||
|
|
||||||
lstring list;
|
|
||||||
list.split("\n", filters);
|
|
||||||
|
|
||||||
filterBox->clear();
|
|
||||||
for(unsigned i = 0; i < list.size(); i++) {
|
|
||||||
filterBox->addItem(list[i]);
|
|
||||||
}
|
|
||||||
|
|
||||||
lock = false;
|
|
||||||
filterBoxChanged();
|
|
||||||
}
|
|
||||||
|
|
||||||
inline void FileDialog::acceptAction() {
|
|
||||||
string path = fileSystemModel->rootPath().toUtf8().constData();
|
|
||||||
path << "/" << notdir(fileNameEdit->text().toUtf8().constData());
|
|
||||||
rtrim(path, "/");
|
|
||||||
if(QDir(path).exists()) {
|
|
||||||
emit accepted(path);
|
|
||||||
setPath(path);
|
|
||||||
} else {
|
|
||||||
emit accepted(path);
|
|
||||||
close();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
inline void FileDialog::rejectAction() {
|
|
||||||
emit rejected();
|
|
||||||
close();
|
|
||||||
}
|
|
||||||
|
|
||||||
inline void FileDialog::createFolderAction(const string &name) {
|
|
||||||
string path = fileSystemModel->rootPath().toUtf8().constData();
|
|
||||||
path << "/" << notdir(name);
|
|
||||||
mkdir(path, 0755);
|
|
||||||
}
|
|
||||||
|
|
||||||
inline void FileDialog::closeEvent(QCloseEvent *event) {
|
|
||||||
newFolderDialog->close();
|
|
||||||
Window::closeEvent(event);
|
|
||||||
}
|
|
||||||
|
|
||||||
inline FileDialog::FileDialog() {
|
|
||||||
newFolderDialog = new NewFolderDialog(this);
|
|
||||||
resize(640, 360);
|
|
||||||
|
|
||||||
layout = new QVBoxLayout;
|
|
||||||
layout->setMargin(5);
|
|
||||||
layout->setSpacing(5);
|
|
||||||
setLayout(layout);
|
|
||||||
|
|
||||||
navigationLayout = new QHBoxLayout;
|
|
||||||
layout->addLayout(navigationLayout);
|
|
||||||
|
|
||||||
pathBox = new QComboBox;
|
|
||||||
pathBox->setEditable(true);
|
|
||||||
pathBox->setMinimumContentsLength(16);
|
|
||||||
pathBox->setSizeAdjustPolicy(QComboBox::AdjustToMinimumContentsLength);
|
|
||||||
pathBox->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Preferred);
|
|
||||||
navigationLayout->addWidget(pathBox);
|
|
||||||
|
|
||||||
newFolderButton = new QPushButton;
|
|
||||||
newFolderButton->setIconSize(QSize(16, 16));
|
|
||||||
newFolderButton->setIcon(QIcon(":/16x16/folder-new.png"));
|
|
||||||
navigationLayout->addWidget(newFolderButton);
|
|
||||||
|
|
||||||
upFolderButton = new QPushButton;
|
|
||||||
upFolderButton->setIconSize(QSize(16, 16));
|
|
||||||
upFolderButton->setIcon(QIcon(":/16x16/go-up.png"));
|
|
||||||
navigationLayout->addWidget(upFolderButton);
|
|
||||||
|
|
||||||
browseLayout = new QHBoxLayout;
|
|
||||||
layout->addLayout(browseLayout);
|
|
||||||
|
|
||||||
fileSystemModel = new QFileSystemModel;
|
|
||||||
fileSystemModel->setFilter(QDir::AllDirs | QDir::Files | QDir::NoDotAndDotDot);
|
|
||||||
fileSystemModel->setNameFilterDisables(false);
|
|
||||||
|
|
||||||
fileView = new FileView;
|
|
||||||
fileView->setMinimumWidth(320);
|
|
||||||
fileView->setModel(fileSystemModel);
|
|
||||||
fileView->setIconSize(QSize(16, 16));
|
|
||||||
browseLayout->addWidget(fileView);
|
|
||||||
|
|
||||||
previewFrame = new QGroupBox;
|
|
||||||
previewFrame->hide();
|
|
||||||
browseLayout->addWidget(previewFrame);
|
|
||||||
|
|
||||||
fileNameEdit = new QLineEdit;
|
|
||||||
layout->addWidget(fileNameEdit);
|
|
||||||
|
|
||||||
controlLayout = new QHBoxLayout;
|
|
||||||
controlLayout->setAlignment(Qt::AlignRight);
|
|
||||||
layout->addLayout(controlLayout);
|
|
||||||
|
|
||||||
filterBox = new QComboBox;
|
|
||||||
filterBox->setMinimumContentsLength(16);
|
|
||||||
filterBox->setSizeAdjustPolicy(QComboBox::AdjustToMinimumContentsLength);
|
|
||||||
filterBox->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Preferred);
|
|
||||||
controlLayout->addWidget(filterBox);
|
|
||||||
|
|
||||||
optionsButton = new QPushButton("Options");
|
|
||||||
optionsButton->hide();
|
|
||||||
controlLayout->addWidget(optionsButton);
|
|
||||||
|
|
||||||
acceptButton = new QPushButton("Ok");
|
|
||||||
controlLayout->addWidget(acceptButton);
|
|
||||||
|
|
||||||
rejectButton = new QPushButton("Cancel");
|
|
||||||
controlLayout->addWidget(rejectButton);
|
|
||||||
|
|
||||||
lock = false;
|
|
||||||
connect(pathBox, SIGNAL(currentIndexChanged(int)), this, SLOT(pathBoxChanged()));
|
|
||||||
connect(newFolderButton, SIGNAL(released()), this, SLOT(createNewFolder()));
|
|
||||||
connect(upFolderButton, SIGNAL(released()), this, SLOT(browseUp()));
|
|
||||||
connect(fileView, SIGNAL(changed(const QModelIndex&)), this, SLOT(fileViewChange(const QModelIndex&)));
|
|
||||||
connect(fileView, SIGNAL(activated(const QModelIndex&)), this, SLOT(fileViewActivate(const QModelIndex&)));
|
|
||||||
connect(fileView, SIGNAL(browseUp()), this, SLOT(browseUp()));
|
|
||||||
connect(fileNameEdit, SIGNAL(returnPressed()), this, SLOT(acceptAction()));
|
|
||||||
connect(filterBox, SIGNAL(currentIndexChanged(int)), this, SLOT(filterBoxChanged()));
|
|
||||||
connect(acceptButton, SIGNAL(released()), this, SLOT(acceptAction()));
|
|
||||||
connect(rejectButton, SIGNAL(released()), this, SLOT(rejectAction()));
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
#endif
|
|
|
@ -1,173 +0,0 @@
|
||||||
#ifndef NALL_QT_HEXEDITOR_HPP
|
|
||||||
#define NALL_QT_HEXEDITOR_HPP
|
|
||||||
|
|
||||||
#include <nall/function.hpp>
|
|
||||||
#include <nall/stdint.hpp>
|
|
||||||
#include <nall/string.hpp>
|
|
||||||
|
|
||||||
namespace nall {
|
|
||||||
|
|
||||||
class HexEditor : public QTextEdit {
|
|
||||||
Q_OBJECT
|
|
||||||
|
|
||||||
public:
|
|
||||||
function<uint8_t (unsigned)> reader;
|
|
||||||
function<void (unsigned, uint8_t)> writer;
|
|
||||||
|
|
||||||
void setColumns(unsigned columns);
|
|
||||||
void setRows(unsigned rows);
|
|
||||||
void setOffset(unsigned offset);
|
|
||||||
void setSize(unsigned size);
|
|
||||||
unsigned lineWidth() const;
|
|
||||||
void refresh();
|
|
||||||
|
|
||||||
HexEditor();
|
|
||||||
|
|
||||||
protected slots:
|
|
||||||
void scrolled();
|
|
||||||
|
|
||||||
protected:
|
|
||||||
QHBoxLayout *layout;
|
|
||||||
QScrollBar *scrollBar;
|
|
||||||
unsigned editorColumns;
|
|
||||||
unsigned editorRows;
|
|
||||||
unsigned editorOffset;
|
|
||||||
unsigned editorSize;
|
|
||||||
bool lock;
|
|
||||||
|
|
||||||
void keyPressEvent(QKeyEvent*);
|
|
||||||
};
|
|
||||||
|
|
||||||
inline void HexEditor::keyPressEvent(QKeyEvent *event) {
|
|
||||||
QTextCursor cursor = textCursor();
|
|
||||||
unsigned x = cursor.position() % lineWidth();
|
|
||||||
unsigned y = cursor.position() / lineWidth();
|
|
||||||
|
|
||||||
int hexCode = -1;
|
|
||||||
switch(event->key()) {
|
|
||||||
case Qt::Key_0: hexCode = 0; break;
|
|
||||||
case Qt::Key_1: hexCode = 1; break;
|
|
||||||
case Qt::Key_2: hexCode = 2; break;
|
|
||||||
case Qt::Key_3: hexCode = 3; break;
|
|
||||||
case Qt::Key_4: hexCode = 4; break;
|
|
||||||
case Qt::Key_5: hexCode = 5; break;
|
|
||||||
case Qt::Key_6: hexCode = 6; break;
|
|
||||||
case Qt::Key_7: hexCode = 7; break;
|
|
||||||
case Qt::Key_8: hexCode = 8; break;
|
|
||||||
case Qt::Key_9: hexCode = 9; break;
|
|
||||||
case Qt::Key_A: hexCode = 10; break;
|
|
||||||
case Qt::Key_B: hexCode = 11; break;
|
|
||||||
case Qt::Key_C: hexCode = 12; break;
|
|
||||||
case Qt::Key_D: hexCode = 13; break;
|
|
||||||
case Qt::Key_E: hexCode = 14; break;
|
|
||||||
case Qt::Key_F: hexCode = 15; break;
|
|
||||||
}
|
|
||||||
|
|
||||||
if(cursor.hasSelection() == false && hexCode != -1) {
|
|
||||||
bool cursorOffsetValid = (x >= 11 && ((x - 11) % 3) != 2);
|
|
||||||
if(cursorOffsetValid) {
|
|
||||||
bool nibble = (x - 11) % 3; //0 = top nibble, 1 = bottom nibble
|
|
||||||
unsigned cursorOffset = y * editorColumns + ((x - 11) / 3);
|
|
||||||
unsigned effectiveOffset = editorOffset + cursorOffset;
|
|
||||||
if(effectiveOffset >= editorSize) effectiveOffset %= editorSize;
|
|
||||||
|
|
||||||
uint8_t data = reader ? reader(effectiveOffset) : 0x00;
|
|
||||||
data &= (nibble == 0 ? 0x0f : 0xf0);
|
|
||||||
data |= (nibble == 0 ? (hexCode << 4) : (hexCode << 0));
|
|
||||||
if(writer) writer(effectiveOffset, data);
|
|
||||||
refresh();
|
|
||||||
|
|
||||||
cursor.setPosition(y * lineWidth() + x + 1); //advance cursor
|
|
||||||
setTextCursor(cursor);
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
//allow navigation keys to move cursor, but block text input
|
|
||||||
setTextInteractionFlags(Qt::TextSelectableByKeyboard | Qt::TextSelectableByMouse);
|
|
||||||
QTextEdit::keyPressEvent(event);
|
|
||||||
setTextInteractionFlags(Qt::TextEditorInteraction);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
inline void HexEditor::setColumns(unsigned columns) {
|
|
||||||
editorColumns = columns;
|
|
||||||
}
|
|
||||||
|
|
||||||
inline void HexEditor::setRows(unsigned rows) {
|
|
||||||
editorRows = rows;
|
|
||||||
scrollBar->setPageStep(editorRows);
|
|
||||||
}
|
|
||||||
|
|
||||||
inline void HexEditor::setOffset(unsigned offset) {
|
|
||||||
lock = true;
|
|
||||||
editorOffset = offset;
|
|
||||||
scrollBar->setSliderPosition(editorOffset / editorColumns);
|
|
||||||
lock = false;
|
|
||||||
}
|
|
||||||
|
|
||||||
inline void HexEditor::setSize(unsigned size) {
|
|
||||||
editorSize = size;
|
|
||||||
bool indivisible = (editorSize % editorColumns) != 0; //add one for incomplete row
|
|
||||||
scrollBar->setRange(0, editorSize / editorColumns + indivisible - editorRows);
|
|
||||||
}
|
|
||||||
|
|
||||||
inline unsigned HexEditor::lineWidth() const {
|
|
||||||
return 11 + 3 * editorColumns;
|
|
||||||
}
|
|
||||||
|
|
||||||
inline void HexEditor::refresh() {
|
|
||||||
string output;
|
|
||||||
char temp[256];
|
|
||||||
unsigned offset = editorOffset;
|
|
||||||
|
|
||||||
for(unsigned y = 0; y < editorRows; y++) {
|
|
||||||
if(offset >= editorSize) break;
|
|
||||||
sprintf(temp, "%.4x:%.4x", (offset >> 16) & 0xffff, (offset >> 0) & 0xffff);
|
|
||||||
output << "<font color='#808080'>" << temp << "</font> ";
|
|
||||||
|
|
||||||
for(unsigned x = 0; x < editorColumns; x++) {
|
|
||||||
if(offset >= editorSize) break;
|
|
||||||
sprintf(temp, "%.2x", reader ? reader(offset) : 0x00);
|
|
||||||
offset++;
|
|
||||||
output << "<font color='" << ((x & 1) ? "#000080" : "#0000ff") << "'>" << temp << "</font>";
|
|
||||||
if(x != (editorColumns - 1)) output << " ";
|
|
||||||
}
|
|
||||||
|
|
||||||
if(y != (editorRows - 1)) output << "<br>";
|
|
||||||
}
|
|
||||||
|
|
||||||
setHtml(output);
|
|
||||||
}
|
|
||||||
|
|
||||||
inline void HexEditor::scrolled() {
|
|
||||||
if(lock) return;
|
|
||||||
unsigned offset = scrollBar->sliderPosition();
|
|
||||||
editorOffset = offset * editorColumns;
|
|
||||||
refresh();
|
|
||||||
}
|
|
||||||
|
|
||||||
inline HexEditor::HexEditor() {
|
|
||||||
setHorizontalScrollBarPolicy(Qt::ScrollBarAlwaysOff);
|
|
||||||
setVerticalScrollBarPolicy(Qt::ScrollBarAlwaysOff);
|
|
||||||
|
|
||||||
layout = new QHBoxLayout;
|
|
||||||
layout->setAlignment(Qt::AlignRight);
|
|
||||||
layout->setMargin(0);
|
|
||||||
layout->setSpacing(0);
|
|
||||||
setLayout(layout);
|
|
||||||
|
|
||||||
scrollBar = new QScrollBar(Qt::Vertical);
|
|
||||||
scrollBar->setSingleStep(1);
|
|
||||||
layout->addWidget(scrollBar);
|
|
||||||
|
|
||||||
lock = false;
|
|
||||||
connect(scrollBar, SIGNAL(actionTriggered(int)), this, SLOT(scrolled()));
|
|
||||||
|
|
||||||
setColumns(16);
|
|
||||||
setRows(16);
|
|
||||||
setSize(0);
|
|
||||||
setOffset(0);
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
#endif
|
|
|
@ -1,41 +0,0 @@
|
||||||
#ifndef NALL_QT_RADIOACTION_HPP
|
|
||||||
#define NALL_QT_RADIOACTION_HPP
|
|
||||||
|
|
||||||
namespace nall {
|
|
||||||
|
|
||||||
class RadioAction : public QAction {
|
|
||||||
Q_OBJECT
|
|
||||||
|
|
||||||
public:
|
|
||||||
bool isChecked() const;
|
|
||||||
void setChecked(bool);
|
|
||||||
void toggleChecked();
|
|
||||||
RadioAction(const QString&, QObject*);
|
|
||||||
|
|
||||||
protected slots:
|
|
||||||
|
|
||||||
protected:
|
|
||||||
bool checked;
|
|
||||||
};
|
|
||||||
|
|
||||||
inline bool RadioAction::isChecked() const {
|
|
||||||
return checked;
|
|
||||||
}
|
|
||||||
|
|
||||||
inline void RadioAction::setChecked(bool checked_) {
|
|
||||||
checked = checked_;
|
|
||||||
if(checked) setIcon(QIcon(":/16x16/item-radio-on.png"));
|
|
||||||
else setIcon(QIcon(":/16x16/item-radio-off.png"));
|
|
||||||
}
|
|
||||||
|
|
||||||
inline void RadioAction::toggleChecked() {
|
|
||||||
setChecked(!isChecked());
|
|
||||||
}
|
|
||||||
|
|
||||||
inline RadioAction::RadioAction(const QString &text, QObject *parent) : QAction(text, parent) {
|
|
||||||
setChecked(false);
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
#endif
|
|
|
@ -1,105 +0,0 @@
|
||||||
#ifndef NALL_QT_WINDOW_HPP
|
|
||||||
#define NALL_QT_WINDOW_HPP
|
|
||||||
|
|
||||||
#include <nall/base64.hpp>
|
|
||||||
#include <nall/string.hpp>
|
|
||||||
|
|
||||||
namespace nall {
|
|
||||||
|
|
||||||
class Window : public QWidget {
|
|
||||||
Q_OBJECT
|
|
||||||
|
|
||||||
public:
|
|
||||||
void setGeometryString(string *geometryString);
|
|
||||||
void setCloseOnEscape(bool);
|
|
||||||
void show();
|
|
||||||
void hide();
|
|
||||||
void shrink();
|
|
||||||
|
|
||||||
Window();
|
|
||||||
|
|
||||||
protected slots:
|
|
||||||
|
|
||||||
protected:
|
|
||||||
string *geometryString;
|
|
||||||
bool closeOnEscape;
|
|
||||||
void keyReleaseEvent(QKeyEvent *event);
|
|
||||||
void closeEvent(QCloseEvent *event);
|
|
||||||
};
|
|
||||||
|
|
||||||
inline void Window::setGeometryString(string *geometryString_) {
|
|
||||||
geometryString = geometryString_;
|
|
||||||
if(geometryString && isVisible() == false) {
|
|
||||||
uint8_t *data;
|
|
||||||
unsigned length;
|
|
||||||
base64::decode(data, length, *geometryString);
|
|
||||||
QByteArray array((const char*)data, length);
|
|
||||||
delete[] data;
|
|
||||||
restoreGeometry(array);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
inline void Window::setCloseOnEscape(bool value) {
|
|
||||||
closeOnEscape = value;
|
|
||||||
}
|
|
||||||
|
|
||||||
inline void Window::show() {
|
|
||||||
if(geometryString && isVisible() == false) {
|
|
||||||
uint8_t *data;
|
|
||||||
unsigned length;
|
|
||||||
base64::decode(data, length, *geometryString);
|
|
||||||
QByteArray array((const char*)data, length);
|
|
||||||
delete[] data;
|
|
||||||
restoreGeometry(array);
|
|
||||||
}
|
|
||||||
QWidget::show();
|
|
||||||
QApplication::processEvents();
|
|
||||||
activateWindow();
|
|
||||||
raise();
|
|
||||||
}
|
|
||||||
|
|
||||||
inline void Window::hide() {
|
|
||||||
if(geometryString && isVisible() == true) {
|
|
||||||
char *data;
|
|
||||||
QByteArray geometry = saveGeometry();
|
|
||||||
base64::encode(data, (const uint8_t*)geometry.data(), geometry.length());
|
|
||||||
*geometryString = data;
|
|
||||||
delete[] data;
|
|
||||||
}
|
|
||||||
QWidget::hide();
|
|
||||||
}
|
|
||||||
|
|
||||||
inline void Window::shrink() {
|
|
||||||
if(isFullScreen()) return;
|
|
||||||
|
|
||||||
for(unsigned i = 0; i < 2; i++) {
|
|
||||||
resize(0, 0);
|
|
||||||
usleep(2000);
|
|
||||||
QApplication::processEvents();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
inline void Window::keyReleaseEvent(QKeyEvent *event) {
|
|
||||||
if(closeOnEscape && (event->key() == Qt::Key_Escape)) close();
|
|
||||||
QWidget::keyReleaseEvent(event);
|
|
||||||
}
|
|
||||||
|
|
||||||
inline void Window::closeEvent(QCloseEvent *event) {
|
|
||||||
if(geometryString) {
|
|
||||||
char *data;
|
|
||||||
QByteArray geometry = saveGeometry();
|
|
||||||
base64::encode(data, (const uint8_t*)geometry.data(), geometry.length());
|
|
||||||
*geometryString = data;
|
|
||||||
delete[] data;
|
|
||||||
}
|
|
||||||
QWidget::closeEvent(event);
|
|
||||||
}
|
|
||||||
|
|
||||||
inline Window::Window() {
|
|
||||||
geometryString = 0;
|
|
||||||
closeOnEscape = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
#endif
|
|
|
@ -23,7 +23,7 @@ namespace nall {
|
||||||
return ::write(port, (void*)data, length);
|
return ::write(port, (void*)data, length);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool open(const char *portname, unsigned rate) {
|
bool open(const char *portname, unsigned rate, bool flowcontrol) {
|
||||||
close();
|
close();
|
||||||
|
|
||||||
port = ::open(portname, O_RDWR | O_NOCTTY | O_NDELAY | O_NONBLOCK);
|
port = ::open(portname, O_RDWR | O_NOCTTY | O_NDELAY | O_NONBLOCK);
|
||||||
|
@ -41,8 +41,13 @@ namespace nall {
|
||||||
attr.c_iflag &=~ (BRKINT | PARMRK | INPCK | ISTRIP | INLCR | IGNCR | ICRNL | IXON | IXOFF | IXANY);
|
attr.c_iflag &=~ (BRKINT | PARMRK | INPCK | ISTRIP | INLCR | IGNCR | ICRNL | IXON | IXOFF | IXANY);
|
||||||
attr.c_iflag |= (IGNBRK | IGNPAR);
|
attr.c_iflag |= (IGNBRK | IGNPAR);
|
||||||
attr.c_oflag &=~ (OPOST);
|
attr.c_oflag &=~ (OPOST);
|
||||||
attr.c_cflag &=~ (CSIZE | CSTOPB | PARENB);
|
attr.c_cflag &=~ (CSIZE | CSTOPB | PARENB | CLOCAL);
|
||||||
attr.c_cflag |= (CS8 | CREAD | 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;
|
attr.c_cc[VTIME] = attr.c_cc[VMIN] = 0;
|
||||||
|
|
||||||
if(tcsetattr(port, TCSANOW, &attr) == -1) { close(); return false; }
|
if(tcsetattr(port, TCSANOW, &attr) == -1) { close(); return false; }
|
||||||
|
|
|
@ -112,6 +112,7 @@ namespace nall {
|
||||||
imode = Size;
|
imode = Size;
|
||||||
idata = 0;
|
idata = 0;
|
||||||
isize = 0;
|
isize = 0;
|
||||||
|
icapacity = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
serializer(unsigned capacity) {
|
serializer(unsigned capacity) {
|
||||||
|
|
|
@ -9,7 +9,7 @@ public:
|
||||||
|
|
||||||
inline snes_information(const uint8_t *data, unsigned size);
|
inline snes_information(const uint8_t *data, unsigned size);
|
||||||
|
|
||||||
private:
|
//private:
|
||||||
inline void read_header(const uint8_t *data, unsigned size);
|
inline void read_header(const uint8_t *data, unsigned size);
|
||||||
inline unsigned find_header(const uint8_t *data, unsigned size);
|
inline unsigned find_header(const uint8_t *data, unsigned size);
|
||||||
inline unsigned score_header(const uint8_t *data, unsigned size, unsigned addr);
|
inline unsigned score_header(const uint8_t *data, unsigned size, unsigned addr);
|
||||||
|
|
|
@ -2,16 +2,18 @@
|
||||||
#define NALL_STRING_HPP
|
#define NALL_STRING_HPP
|
||||||
|
|
||||||
#include <initializer_list>
|
#include <initializer_list>
|
||||||
|
#include <nall/platform.hpp>
|
||||||
#include <nall/utility.hpp>
|
#include <nall/utility.hpp>
|
||||||
|
|
||||||
#include <nall/string/base.hpp>
|
#include <nall/string/base.hpp>
|
||||||
|
#include <nall/string/bsv.hpp>
|
||||||
#include <nall/string/core.hpp>
|
#include <nall/string/core.hpp>
|
||||||
#include <nall/string/cast.hpp>
|
#include <nall/string/cast.hpp>
|
||||||
#include <nall/string/compare.hpp>
|
#include <nall/string/compare.hpp>
|
||||||
#include <nall/string/convert.hpp>
|
#include <nall/string/convert.hpp>
|
||||||
#include <nall/string/filename.hpp>
|
#include <nall/string/filename.hpp>
|
||||||
#include <nall/string/match.hpp>
|
|
||||||
#include <nall/string/math.hpp>
|
#include <nall/string/math.hpp>
|
||||||
|
#include <nall/string/platform.hpp>
|
||||||
#include <nall/string/strl.hpp>
|
#include <nall/string/strl.hpp>
|
||||||
#include <nall/string/strpos.hpp>
|
#include <nall/string/strpos.hpp>
|
||||||
#include <nall/string/trim.hpp>
|
#include <nall/string/trim.hpp>
|
||||||
|
@ -19,6 +21,7 @@
|
||||||
#include <nall/string/split.hpp>
|
#include <nall/string/split.hpp>
|
||||||
#include <nall/string/utility.hpp>
|
#include <nall/string/utility.hpp>
|
||||||
#include <nall/string/variadic.hpp>
|
#include <nall/string/variadic.hpp>
|
||||||
|
#include <nall/string/wrapper.hpp>
|
||||||
#include <nall/string/xml.hpp>
|
#include <nall/string/xml.hpp>
|
||||||
|
|
||||||
namespace nall {
|
namespace nall {
|
||||||
|
|
|
@ -17,10 +17,43 @@ namespace nall {
|
||||||
class string {
|
class string {
|
||||||
public:
|
public:
|
||||||
inline void reserve(unsigned);
|
inline void reserve(unsigned);
|
||||||
inline unsigned length() const;
|
|
||||||
|
|
||||||
inline string& assign(const char*);
|
inline string& assign(const char*);
|
||||||
inline string& append(const char*);
|
inline string& append(const char*);
|
||||||
|
inline string& append(bool);
|
||||||
|
inline string& append(signed int value);
|
||||||
|
inline string& append(unsigned int value);
|
||||||
|
inline string& append(double value);
|
||||||
|
|
||||||
|
inline bool readfile(const char*);
|
||||||
|
|
||||||
|
inline string& replace (const char*, const char*);
|
||||||
|
inline string& qreplace(const char*, const char*);
|
||||||
|
|
||||||
|
inline unsigned length() 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& transform(const char *before, const char *after);
|
||||||
|
|
||||||
|
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 = " ");
|
||||||
|
|
||||||
|
inline optional<unsigned> position(const char *key) const;
|
||||||
|
inline optional<unsigned> qposition(const char *key) const;
|
||||||
|
|
||||||
template<typename T> inline string& operator= (T value);
|
template<typename T> inline string& operator= (T value);
|
||||||
template<typename T> inline string& operator<<(T value);
|
template<typename T> inline string& operator<<(T value);
|
||||||
|
|
||||||
|
@ -38,16 +71,11 @@ namespace nall {
|
||||||
inline string& operator=(const string&);
|
inline string& operator=(const string&);
|
||||||
inline string& operator=(string&&);
|
inline string& operator=(string&&);
|
||||||
|
|
||||||
inline string();
|
template<typename... Args> inline string(Args&&... args);
|
||||||
inline string(const char*);
|
|
||||||
inline string(const string&);
|
inline string(const string&);
|
||||||
inline string(string&&);
|
inline string(string&&);
|
||||||
inline ~string();
|
inline ~string();
|
||||||
|
|
||||||
inline bool readfile(const char*);
|
|
||||||
inline string& replace (const char*, const char*);
|
|
||||||
inline string& qreplace(const char*, const char*);
|
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
char *data;
|
char *data;
|
||||||
unsigned size;
|
unsigned size;
|
||||||
|
@ -62,9 +90,9 @@ namespace nall {
|
||||||
public:
|
public:
|
||||||
template<typename T> inline lstring& operator<<(T value);
|
template<typename T> inline lstring& operator<<(T value);
|
||||||
|
|
||||||
inline int find(const char*);
|
inline optional<unsigned> find(const char*) const;
|
||||||
inline void split (const char*, const char*, unsigned = 0);
|
template<unsigned limit = 0> inline void split (const char*, const char*);
|
||||||
inline void qsplit(const char*, const char*, unsigned = 0);
|
template<unsigned limit = 0> inline void qsplit(const char*, const char*);
|
||||||
|
|
||||||
lstring();
|
lstring();
|
||||||
lstring(std::initializer_list<string>);
|
lstring(std::initializer_list<string>);
|
||||||
|
@ -73,7 +101,9 @@ namespace nall {
|
||||||
//compare.hpp
|
//compare.hpp
|
||||||
inline char chrlower(char c);
|
inline char chrlower(char c);
|
||||||
inline char chrupper(char c);
|
inline char chrupper(char c);
|
||||||
inline int stricmp(const char *dest, const char *src);
|
inline int stricmp(const char *str1, const char *str2);
|
||||||
|
inline bool wildcard(const char *str, const char *pattern);
|
||||||
|
inline bool iwildcard(const char *str, const char *pattern);
|
||||||
inline bool strbegin (const char *str, const char *key);
|
inline bool strbegin (const char *str, const char *key);
|
||||||
inline bool stribegin(const char *str, const char *key);
|
inline bool stribegin(const char *str, const char *key);
|
||||||
inline bool strend (const char *str, const char *key);
|
inline bool strend (const char *str, const char *key);
|
||||||
|
@ -89,38 +119,32 @@ namespace nall {
|
||||||
inline uintmax_t strbin (const char *str);
|
inline uintmax_t strbin (const char *str);
|
||||||
inline double strdouble (const char *str);
|
inline double strdouble (const char *str);
|
||||||
|
|
||||||
//match.hpp
|
|
||||||
inline bool match(const char *pattern, const char *str);
|
|
||||||
|
|
||||||
//math.hpp
|
//math.hpp
|
||||||
inline bool strint (const char *str, int &result);
|
inline bool strint (const char *str, int &result);
|
||||||
inline bool strmath(const char *str, int &result);
|
inline bool strmath(const char *str, int &result);
|
||||||
|
|
||||||
|
//platform.hpp
|
||||||
|
inline string realpath(const char *name);
|
||||||
|
inline string userpath();
|
||||||
|
inline string currentpath();
|
||||||
|
|
||||||
//strl.hpp
|
//strl.hpp
|
||||||
inline unsigned strlcpy(char *dest, const char *src, unsigned length);
|
inline unsigned strlcpy(char *dest, const char *src, unsigned length);
|
||||||
inline unsigned strlcat(char *dest, const char *src, unsigned length);
|
inline unsigned strlcat(char *dest, const char *src, unsigned length);
|
||||||
|
|
||||||
|
//strpos.hpp
|
||||||
|
inline optional<unsigned> strpos(const char *str, const char *key);
|
||||||
|
inline optional<unsigned> qstrpos(const char *str, const char *key);
|
||||||
|
|
||||||
//trim.hpp
|
//trim.hpp
|
||||||
inline char* ltrim(char *str, const char *key = " ");
|
template<unsigned limit = 0> inline char* ltrim(char *str, const char *key = " ");
|
||||||
inline char* rtrim(char *str, const char *key = " ");
|
template<unsigned limit = 0> inline char* rtrim(char *str, const char *key = " ");
|
||||||
inline char* trim (char *str, const char *key = " ");
|
template<unsigned limit = 0> inline char* trim (char *str, const char *key = " ");
|
||||||
inline char* ltrim_once(char *str, const char *key = " ");
|
|
||||||
inline char* rtrim_once(char *str, const char *key = " ");
|
|
||||||
inline char* trim_once (char *str, const char *key = " ");
|
|
||||||
|
|
||||||
//utility.hpp
|
//utility.hpp
|
||||||
inline unsigned strlcpy(string &dest, const char *src, unsigned length);
|
inline unsigned strlcpy(string &dest, const char *src, unsigned length);
|
||||||
inline unsigned strlcat(string &dest, const char *src, unsigned length);
|
inline unsigned strlcat(string &dest, const char *src, unsigned length);
|
||||||
inline string substr(const char *src, unsigned start = 0, unsigned length = 0);
|
inline string substr(const char *src, unsigned start = 0, unsigned length = 0);
|
||||||
inline string& strlower(string &str);
|
|
||||||
inline string& strupper(string &str);
|
|
||||||
inline string& strtr(string &dest, const char *before, const char *after);
|
|
||||||
inline string& ltrim(string &str, const char *key = " ");
|
|
||||||
inline string& rtrim(string &str, const char *key = " ");
|
|
||||||
inline string& trim (string &str, const char *key = " ");
|
|
||||||
inline string& ltrim_once(string &str, const char *key = " ");
|
|
||||||
inline string& rtrim_once(string &str, const char *key = " ");
|
|
||||||
inline string& trim_once (string &str, const char *key = " ");
|
|
||||||
template<unsigned length = 0, char padding = '0'> inline string strhex(uintmax_t value);
|
template<unsigned length = 0, char padding = '0'> inline string strhex(uintmax_t value);
|
||||||
template<unsigned length = 0, char padding = '0'> inline string strsigned(intmax_t value);
|
template<unsigned length = 0, char padding = '0'> inline string strsigned(intmax_t value);
|
||||||
template<unsigned length = 0, char padding = '0'> inline string strunsigned(uintmax_t value);
|
template<unsigned length = 0, char padding = '0'> inline string strunsigned(uintmax_t value);
|
||||||
|
@ -129,8 +153,7 @@ namespace nall {
|
||||||
inline string strdouble(double value);
|
inline string strdouble(double value);
|
||||||
|
|
||||||
//variadic.hpp
|
//variadic.hpp
|
||||||
template<typename... Args> inline string sprint(Args... args);
|
template<typename... Args> inline void print(Args&&... args);
|
||||||
template<typename... Args> inline void print(Args... args);
|
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
|
@ -0,0 +1,75 @@
|
||||||
|
#ifndef NALL_STRING_BSV_HPP
|
||||||
|
#define NALL_STRING_BSV_HPP
|
||||||
|
|
||||||
|
//BSV parser
|
||||||
|
//version 0.01
|
||||||
|
|
||||||
|
namespace nall {
|
||||||
|
|
||||||
|
inline string bsv_decode(const char *input) {
|
||||||
|
string output;
|
||||||
|
unsigned offset = 0;
|
||||||
|
while(*input) {
|
||||||
|
//illegal characters
|
||||||
|
if(*input == '}' ) return "";
|
||||||
|
if(*input == '\r') return "";
|
||||||
|
if(*input == '\n') return "";
|
||||||
|
|
||||||
|
//normal characters
|
||||||
|
if(*input != '{') { output[offset++] = *input++; continue; }
|
||||||
|
|
||||||
|
//entities
|
||||||
|
if(strbegin(input, "{lf}")) { output[offset++] = '\n'; input += 4; continue; }
|
||||||
|
if(strbegin(input, "{lb}")) { output[offset++] = '{'; input += 4; continue; }
|
||||||
|
if(strbegin(input, "{rb}")) { output[offset++] = '}'; input += 4; continue; }
|
||||||
|
|
||||||
|
//illegal entities
|
||||||
|
return "";
|
||||||
|
}
|
||||||
|
output[offset] = 0;
|
||||||
|
return output;
|
||||||
|
}
|
||||||
|
|
||||||
|
inline string bsv_encode(const char *input) {
|
||||||
|
string output;
|
||||||
|
unsigned offset = 0;
|
||||||
|
while(*input) {
|
||||||
|
//illegal characters
|
||||||
|
if(*input == '\r') return "";
|
||||||
|
|
||||||
|
if(*input == '\n') {
|
||||||
|
output[offset++] = '{';
|
||||||
|
output[offset++] = 'l';
|
||||||
|
output[offset++] = 'f';
|
||||||
|
output[offset++] = '}';
|
||||||
|
input++;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
if(*input == '{') {
|
||||||
|
output[offset++] = '{';
|
||||||
|
output[offset++] = 'l';
|
||||||
|
output[offset++] = 'b';
|
||||||
|
output[offset++] = '}';
|
||||||
|
input++;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
if(*input == '}') {
|
||||||
|
output[offset++] = '{';
|
||||||
|
output[offset++] = 'r';
|
||||||
|
output[offset++] = 'b';
|
||||||
|
output[offset++] = '}';
|
||||||
|
input++;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
output[offset++] = *input++;
|
||||||
|
}
|
||||||
|
output[offset] = 0;
|
||||||
|
return output;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif
|
|
@ -11,14 +11,52 @@ char chrupper(char c) {
|
||||||
return (c >= 'a' && c <= 'z') ? c - ('a' - 'A') : c;
|
return (c >= 'a' && c <= 'z') ? c - ('a' - 'A') : c;
|
||||||
}
|
}
|
||||||
|
|
||||||
int stricmp(const char *dest, const char *src) {
|
int stricmp(const char *str1, const char *str2) {
|
||||||
while(*dest) {
|
while(*str1) {
|
||||||
if(chrlower(*dest) != chrlower(*src)) break;
|
if(chrlower(*str1) != chrlower(*str2)) break;
|
||||||
dest++;
|
str1++, str2++;
|
||||||
src++;
|
|
||||||
}
|
}
|
||||||
|
return (int)chrlower(*str1) - (int)chrlower(*str2);
|
||||||
|
}
|
||||||
|
|
||||||
return (int)chrlower(*dest) - (int)chrlower(*src);
|
bool wildcard(const char *s, const char *p) {
|
||||||
|
const char *cp = 0, *mp = 0;
|
||||||
|
while(*s && *p != '*') {
|
||||||
|
if(*p != '?' && *s != *p) return false;
|
||||||
|
p++, s++;
|
||||||
|
}
|
||||||
|
while(*s) {
|
||||||
|
if(*p == '*') {
|
||||||
|
if(!*++p) return true;
|
||||||
|
mp = p, cp = s + 1;
|
||||||
|
} else if(*p == '?' || *p == *s) {
|
||||||
|
p++, s++;
|
||||||
|
} else {
|
||||||
|
p = mp, s = cp++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
while(*p == '*') p++;
|
||||||
|
return !*p;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool iwildcard(const char *s, const char *p) {
|
||||||
|
const char *cp = 0, *mp = 0;
|
||||||
|
while(*s && *p != '*') {
|
||||||
|
if(*p != '?' && chrlower(*s) != chrlower(*p)) return false;
|
||||||
|
p++, s++;
|
||||||
|
}
|
||||||
|
while(*s) {
|
||||||
|
if(*p == '*') {
|
||||||
|
if(!*++p) return true;
|
||||||
|
mp = p, cp = s + 1;
|
||||||
|
} else if(*p == '?' || chrlower(*p) == chrlower(*s)) {
|
||||||
|
p++, s++;
|
||||||
|
} else {
|
||||||
|
p = mp, s = cp++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
while(*p == '*') p++;
|
||||||
|
return !*p;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool strbegin(const char *str, const char *key) {
|
bool strbegin(const char *str, const char *key) {
|
||||||
|
|
|
@ -11,10 +11,6 @@ void string::reserve(unsigned size_) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
unsigned string::length() const {
|
|
||||||
return strlen(data);
|
|
||||||
}
|
|
||||||
|
|
||||||
string& string::assign(const char *s) {
|
string& string::assign(const char *s) {
|
||||||
unsigned length = strlen(s);
|
unsigned length = strlen(s);
|
||||||
reserve(length);
|
reserve(length);
|
||||||
|
@ -29,6 +25,11 @@ string& string::append(const char *s) {
|
||||||
return *this;
|
return *this;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
string& string::append(bool value) { append(value ? "true" : "false"); return *this; }
|
||||||
|
string& string::append(signed int value) { append(strsigned(value)); return *this; }
|
||||||
|
string& string::append(unsigned int value) { append(strunsigned(value)); return *this; }
|
||||||
|
string& string::append(double value) { append(strdouble(value)); return *this; }
|
||||||
|
|
||||||
string::operator const char*() const {
|
string::operator const char*() const {
|
||||||
return data;
|
return data;
|
||||||
}
|
}
|
||||||
|
@ -63,15 +64,20 @@ string& string::operator=(string &&source) {
|
||||||
return *this;
|
return *this;
|
||||||
}
|
}
|
||||||
|
|
||||||
string::string() {
|
static void istring(string &output) {
|
||||||
|
}
|
||||||
|
|
||||||
|
template<typename T, typename... Args>
|
||||||
|
static void istring(string &output, const T &value, Args&&... args) {
|
||||||
|
output.append(value);
|
||||||
|
istring(output, std::forward<Args>(args)...);
|
||||||
|
}
|
||||||
|
|
||||||
|
template<typename... Args> string::string(Args&&... args) {
|
||||||
size = 64;
|
size = 64;
|
||||||
data = (char*)malloc(size + 1);
|
data = (char*)malloc(size + 1);
|
||||||
*data = 0;
|
*data = 0;
|
||||||
}
|
istring(*this, std::forward<Args>(args)...);
|
||||||
|
|
||||||
string::string(const char *value) {
|
|
||||||
size = strlen(value);
|
|
||||||
data = strdup(value);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
string::string(const string &value) {
|
string::string(const string &value) {
|
||||||
|
@ -86,7 +92,7 @@ string::string(string &&source) {
|
||||||
}
|
}
|
||||||
|
|
||||||
string::~string() {
|
string::~string() {
|
||||||
free(data);
|
if(data) free(data);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool string::readfile(const char *filename) {
|
bool string::readfile(const char *filename) {
|
||||||
|
@ -112,11 +118,11 @@ bool string::readfile(const char *filename) {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
int lstring::find(const char *key) {
|
optional<unsigned> lstring::find(const char *key) const {
|
||||||
for(unsigned i = 0; i < size(); i++) {
|
for(unsigned i = 0; i < size(); i++) {
|
||||||
if(operator[](i) == key) return i;
|
if(operator[](i) == key) return { true, i };
|
||||||
}
|
}
|
||||||
return -1;
|
return { false, 0 };
|
||||||
}
|
}
|
||||||
|
|
||||||
inline lstring::lstring() {
|
inline lstring::lstring() {
|
||||||
|
|
|
@ -3,7 +3,9 @@
|
||||||
|
|
||||||
namespace nall {
|
namespace nall {
|
||||||
|
|
||||||
// "foo/bar.c" -> "foo/", "bar.c" -> "./"
|
// "foo/bar.c" -> "foo/"
|
||||||
|
// "foo/" -> "foo/"
|
||||||
|
// "bar.c" -> "./"
|
||||||
inline string dir(char const *name) {
|
inline string dir(char const *name) {
|
||||||
string result = name;
|
string result = name;
|
||||||
for(signed i = strlen(result); i >= 0; i--) {
|
for(signed i = strlen(result); i >= 0; i--) {
|
||||||
|
|
|
@ -1,76 +0,0 @@
|
||||||
#ifndef NALL_STRING_MATCH_HPP
|
|
||||||
#define NALL_STRING_MATCH_HPP
|
|
||||||
|
|
||||||
namespace nall {
|
|
||||||
|
|
||||||
bool match(const char *p, const char *s) {
|
|
||||||
const char *p_ = 0, *s_ = 0;
|
|
||||||
|
|
||||||
for(;;) {
|
|
||||||
if(!*s) {
|
|
||||||
while(*p == '*') p++;
|
|
||||||
return !*p;
|
|
||||||
}
|
|
||||||
|
|
||||||
//wildcard match
|
|
||||||
if(*p == '*') {
|
|
||||||
p_ = p++, s_ = s;
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
//any match
|
|
||||||
if(*p == '?') {
|
|
||||||
p++, s++;
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
//ranged match
|
|
||||||
if(*p == '{') {
|
|
||||||
#define pattern(name_, rule_) \
|
|
||||||
if(strbegin(p, name_)) { \
|
|
||||||
if(rule_) { \
|
|
||||||
p += sizeof(name_) - 1, s++; \
|
|
||||||
continue; \
|
|
||||||
} \
|
|
||||||
goto failure; \
|
|
||||||
}
|
|
||||||
|
|
||||||
pattern("{alpha}", (*s >= 'A' && *s <= 'Z') || (*s >= 'a' && *s <= 'z'))
|
|
||||||
pattern("{alphanumeric}", (*s >= 'A' && *s <= 'Z') || (*s >= 'a' && *s <= 'z') || (*s >= '0' && *s <= '9'))
|
|
||||||
pattern("{binary}", (*s == '0' || *s == '1'))
|
|
||||||
pattern("{hex}", (*s >= '0' && *s <= '9') || (*s >= 'A' && *s <= 'F') || (*s >= 'a' && *s <= 'f'))
|
|
||||||
pattern("{lowercase}", (*s >= 'a' && *s <= 'z'))
|
|
||||||
pattern("{numeric}", (*s >= '0' && *s <= '9'))
|
|
||||||
pattern("{uppercase}", (*s >= 'A' && *s <= 'Z'))
|
|
||||||
pattern("{whitespace}", (*s == ' ' || *s == '\t'))
|
|
||||||
|
|
||||||
#undef pattern
|
|
||||||
goto failure;
|
|
||||||
}
|
|
||||||
|
|
||||||
//reserved character match
|
|
||||||
if(*p == '\\') {
|
|
||||||
p++;
|
|
||||||
//fallthrough
|
|
||||||
}
|
|
||||||
|
|
||||||
//literal match
|
|
||||||
if(*p == *s) {
|
|
||||||
p++, *s++;
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
//attempt wildcard rematch
|
|
||||||
failure:
|
|
||||||
if(p_) {
|
|
||||||
p = p_, s = s_ + 1;
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
#endif
|
|
|
@ -0,0 +1,41 @@
|
||||||
|
#ifndef NALL_STRING_PLATFORM_HPP
|
||||||
|
#define NALL_STRING_PLATFORM_HPP
|
||||||
|
|
||||||
|
namespace nall {
|
||||||
|
|
||||||
|
string realpath(const char *name) {
|
||||||
|
char path[PATH_MAX];
|
||||||
|
if(::realpath(name, path)) {
|
||||||
|
string result(path);
|
||||||
|
result.transform("\\", "/");
|
||||||
|
if(result.endswith("/") == false) result.append("/");
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
return "";
|
||||||
|
}
|
||||||
|
|
||||||
|
string userpath() {
|
||||||
|
char path[PATH_MAX];
|
||||||
|
if(::userpath(path)) {
|
||||||
|
string result(path);
|
||||||
|
result.transform("\\", "/");
|
||||||
|
if(result.endswith("/") == false) result.append("/");
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
return "";
|
||||||
|
}
|
||||||
|
|
||||||
|
string currentpath() {
|
||||||
|
char path[PATH_MAX];
|
||||||
|
if(::getcwd(path)) {
|
||||||
|
string result(path);
|
||||||
|
result.transform("\\", "/");
|
||||||
|
if(result.endswith("/") == false) result.append("/");
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
return "";
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif
|
|
@ -3,7 +3,8 @@
|
||||||
|
|
||||||
namespace nall {
|
namespace nall {
|
||||||
|
|
||||||
void lstring::split(const char *key, const char *src, unsigned limit) {
|
template<unsigned Limit> void lstring::split(const char *key, const char *src) {
|
||||||
|
unsigned limit = Limit;
|
||||||
reset();
|
reset();
|
||||||
|
|
||||||
int ssl = strlen(src), ksl = strlen(key);
|
int ssl = strlen(src), ksl = strlen(key);
|
||||||
|
@ -21,7 +22,8 @@ void lstring::split(const char *key, const char *src, unsigned limit) {
|
||||||
operator[](split_count++) = src + lp;
|
operator[](split_count++) = src + lp;
|
||||||
}
|
}
|
||||||
|
|
||||||
void lstring::qsplit(const char *key, const char *src, unsigned limit) {
|
template<unsigned Limit> void lstring::qsplit(const char *key, const char *src) {
|
||||||
|
unsigned limit = Limit;
|
||||||
reset();
|
reset();
|
||||||
|
|
||||||
int ssl = strlen(src), ksl = strlen(key);
|
int ssl = strlen(src), ksl = strlen(key);
|
||||||
|
|
|
@ -7,7 +7,7 @@
|
||||||
|
|
||||||
namespace nall {
|
namespace nall {
|
||||||
|
|
||||||
optional<unsigned> inline strpos(const char *str, const char *key) {
|
optional<unsigned> strpos(const char *str, const char *key) {
|
||||||
unsigned ssl = strlen(str), ksl = strlen(key);
|
unsigned ssl = strlen(str), ksl = strlen(key);
|
||||||
if(ksl > ssl) return { false, 0 };
|
if(ksl > ssl) return { false, 0 };
|
||||||
|
|
||||||
|
@ -18,7 +18,7 @@ optional<unsigned> inline strpos(const char *str, const char *key) {
|
||||||
return { false, 0 };
|
return { false, 0 };
|
||||||
}
|
}
|
||||||
|
|
||||||
optional<unsigned> inline qstrpos(const char *str, const char *key) {
|
optional<unsigned> qstrpos(const char *str, const char *key) {
|
||||||
unsigned ssl = strlen(str), ksl = strlen(key);
|
unsigned ssl = strlen(str), ksl = strlen(key);
|
||||||
if(ksl > ssl) return { false, 0 };
|
if(ksl > ssl) return { false, 0 };
|
||||||
|
|
||||||
|
|
|
@ -3,7 +3,9 @@
|
||||||
|
|
||||||
namespace nall {
|
namespace nall {
|
||||||
|
|
||||||
char* ltrim(char *str, const char *key) {
|
//limit defaults to zero, which will underflow on first compare; equivalent to no limit
|
||||||
|
template<unsigned Limit> char* ltrim(char *str, const char *key) {
|
||||||
|
unsigned limit = Limit;
|
||||||
if(!key || !*key) return str;
|
if(!key || !*key) return str;
|
||||||
while(strbegin(str, key)) {
|
while(strbegin(str, key)) {
|
||||||
char *dest = str, *src = str + strlen(key);
|
char *dest = str, *src = str + strlen(key);
|
||||||
|
@ -12,41 +14,23 @@ char* ltrim(char *str, const char *key) {
|
||||||
if(!*dest) break;
|
if(!*dest) break;
|
||||||
dest++;
|
dest++;
|
||||||
}
|
}
|
||||||
|
if(--limit == 0) break;
|
||||||
}
|
}
|
||||||
return str;
|
return str;
|
||||||
}
|
}
|
||||||
|
|
||||||
char* rtrim(char *str, const char *key) {
|
template<unsigned Limit> char* rtrim(char *str, const char *key) {
|
||||||
|
unsigned limit = Limit;
|
||||||
if(!key || !*key) return str;
|
if(!key || !*key) return str;
|
||||||
while(strend(str, key)) str[strlen(str) - strlen(key)] = 0;
|
while(strend(str, key)) {
|
||||||
return str;
|
str[strlen(str) - strlen(key)] = 0;
|
||||||
}
|
if(--limit == 0) break;
|
||||||
|
|
||||||
char* trim(char *str, const char *key) {
|
|
||||||
return ltrim(rtrim(str, key), key);
|
|
||||||
}
|
|
||||||
|
|
||||||
char* ltrim_once(char *str, const char *key) {
|
|
||||||
if(!key || !*key) return str;
|
|
||||||
if(strbegin(str, key)) {
|
|
||||||
char *dest = str, *src = str + strlen(key);
|
|
||||||
while(true) {
|
|
||||||
*dest = *src++;
|
|
||||||
if(!*dest) break;
|
|
||||||
dest++;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
return str;
|
return str;
|
||||||
}
|
}
|
||||||
|
|
||||||
char* rtrim_once(char *str, const char *key) {
|
template<unsigned limit> char* trim(char *str, const char *key) {
|
||||||
if(!key || !*key) return str;
|
return ltrim<limit>(rtrim<limit>(str, key), key);
|
||||||
if(strend(str, key)) str[strlen(str) - strlen(key)] = 0;
|
|
||||||
return str;
|
|
||||||
}
|
|
||||||
|
|
||||||
char* trim_once(char *str, const char *key) {
|
|
||||||
return ltrim_once(rtrim_once(str, key), key);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -25,18 +25,6 @@ string substr(const char *src, unsigned start, unsigned length) {
|
||||||
return dest;
|
return dest;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* very simplistic wrappers to return string& instead of char* type */
|
|
||||||
|
|
||||||
string& strlower(string &str) { strlower(str()); return str; }
|
|
||||||
string& strupper(string &str) { strupper(str()); return str; }
|
|
||||||
string& strtr(string &dest, const char *before, const char *after) { strtr(dest(), before, after); return dest; }
|
|
||||||
string& ltrim(string &str, const char *key) { ltrim(str(), key); return str; }
|
|
||||||
string& rtrim(string &str, const char *key) { rtrim(str(), key); return str; }
|
|
||||||
string& trim (string &str, const char *key) { trim (str(), key); return str; }
|
|
||||||
string& ltrim_once(string &str, const char *key) { ltrim_once(str(), key); return str; }
|
|
||||||
string& rtrim_once(string &str, const char *key) { rtrim_once(str(), key); return str; }
|
|
||||||
string& trim_once (string &str, const char *key) { trim_once (str(), key); return str; }
|
|
||||||
|
|
||||||
/* arithmetic <> string */
|
/* arithmetic <> string */
|
||||||
|
|
||||||
template<unsigned length, char padding> string strhex(uintmax_t value) {
|
template<unsigned length, char padding> string strhex(uintmax_t value) {
|
||||||
|
|
|
@ -3,23 +3,8 @@
|
||||||
|
|
||||||
namespace nall {
|
namespace nall {
|
||||||
|
|
||||||
static void isprint(string &output) {
|
template<typename... Args> inline void print(Args&&... args) {
|
||||||
}
|
printf("%s", (const char*)string(std::forward<Args>(args)...));
|
||||||
|
|
||||||
template<typename T, typename... Args>
|
|
||||||
static void isprint(string &output, T value, Args... args) {
|
|
||||||
output << to_string<T>(value);
|
|
||||||
isprint(output, args...);
|
|
||||||
}
|
|
||||||
|
|
||||||
template<typename... Args> inline string sprint(Args... args) {
|
|
||||||
string output;
|
|
||||||
isprint(output, args...);
|
|
||||||
return output;
|
|
||||||
}
|
|
||||||
|
|
||||||
template<typename... Args> inline void print(Args... args) {
|
|
||||||
printf("%s", (const char*)sprint(args...));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,33 @@
|
||||||
|
#ifndef NALL_STRING_WRAPPER_HPP
|
||||||
|
#define NALL_STRING_WRAPPER_HPP
|
||||||
|
|
||||||
|
namespace nall {
|
||||||
|
|
||||||
|
unsigned string::length() const { return strlen(data); }
|
||||||
|
|
||||||
|
bool string::equals(const char *str) const { return !strcmp(data, str); }
|
||||||
|
bool string::iequals(const char *str) const { return !stricmp(data, str); }
|
||||||
|
|
||||||
|
bool string::wildcard(const char *str) const { return nall::wildcard(data, str); }
|
||||||
|
bool string::iwildcard(const char *str) const { return nall::iwildcard(data, str); }
|
||||||
|
|
||||||
|
bool string::beginswith(const char *str) const { return strbegin(data, str); }
|
||||||
|
bool string::ibeginswith(const char *str) const { return stribegin(data, str); }
|
||||||
|
|
||||||
|
bool string::endswith(const char *str) const { return strend(data, str); }
|
||||||
|
bool string::iendswith(const char *str) const { return striend(data, str); }
|
||||||
|
|
||||||
|
string& string::lower() { nall::strlower(data); return *this; }
|
||||||
|
string& string::upper() { nall::strupper(data); return *this; }
|
||||||
|
string& string::transform(const char *before, const char *after) { nall::strtr(data, before, after); return *this; }
|
||||||
|
|
||||||
|
template<unsigned limit> string& string::ltrim(const char *key) { nall::ltrim<limit>(data, key); return *this; }
|
||||||
|
template<unsigned limit> string& string::rtrim(const char *key) { nall::rtrim<limit>(data, key); return *this; }
|
||||||
|
template<unsigned limit> string& string::trim (const char *key) { nall::trim <limit>(data, key); return *this; }
|
||||||
|
|
||||||
|
optional<unsigned> string::position(const char *key) const { return strpos(data, key); }
|
||||||
|
optional<unsigned> string::qposition(const char *key) const { return qstrpos(data, key); }
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif
|
|
@ -75,11 +75,12 @@ inline string xml_element::parse() const {
|
||||||
|
|
||||||
if(strbegin(source, "<![CDATA[")) {
|
if(strbegin(source, "<![CDATA[")) {
|
||||||
if(auto pos = strpos(source, "]]>")) {
|
if(auto pos = strpos(source, "]]>")) {
|
||||||
string cdata = substr(source, 9, pos() - 9);
|
if(pos() - 9 > 0) {
|
||||||
data << cdata;
|
string cdata = substr(source, 9, pos() - 9);
|
||||||
offset += strlen(cdata);
|
data << cdata;
|
||||||
|
offset += strlen(cdata);
|
||||||
source += offset + 3;
|
}
|
||||||
|
source += 9 + offset + 3;
|
||||||
continue;
|
continue;
|
||||||
} else {
|
} else {
|
||||||
return "";
|
return "";
|
||||||
|
@ -122,7 +123,7 @@ inline bool xml_element::parse_head(string data) {
|
||||||
while(qstrpos(data, " ")) data.qreplace(" ", " ");
|
while(qstrpos(data, " ")) data.qreplace(" ", " ");
|
||||||
data.qreplace(" =", "=");
|
data.qreplace(" =", "=");
|
||||||
data.qreplace("= ", "=");
|
data.qreplace("= ", "=");
|
||||||
rtrim(data);
|
data.rtrim();
|
||||||
|
|
||||||
lstring part;
|
lstring part;
|
||||||
part.qsplit(" ", data);
|
part.qsplit(" ", data);
|
||||||
|
@ -138,8 +139,8 @@ inline bool xml_element::parse_head(string data) {
|
||||||
xml_attribute attr;
|
xml_attribute attr;
|
||||||
attr.name = side[0];
|
attr.name = side[0];
|
||||||
attr.content = side[1];
|
attr.content = side[1];
|
||||||
if(strbegin(attr.content, "\"") && strend(attr.content, "\"")) trim_once(attr.content, "\"");
|
if(strbegin(attr.content, "\"") && strend(attr.content, "\"")) attr.content.trim<1>("\"");
|
||||||
else if(strbegin(attr.content, "'") && strend(attr.content, "'")) trim_once(attr.content, "'");
|
else if(strbegin(attr.content, "'") && strend(attr.content, "'")) attr.content.trim<1>("'");
|
||||||
else throw "...";
|
else throw "...";
|
||||||
attribute.append(attr);
|
attribute.append(attr);
|
||||||
}
|
}
|
||||||
|
@ -185,10 +186,10 @@ inline bool xml_element::parse_body(const char *&data) {
|
||||||
|
|
||||||
if(strend(tag, "?") == true) {
|
if(strend(tag, "?") == true) {
|
||||||
self_terminating = true;
|
self_terminating = true;
|
||||||
rtrim_once(tag, "?");
|
tag.rtrim<1>("?");
|
||||||
} else if(strend(tag, "/") == true) {
|
} else if(strend(tag, "/") == true) {
|
||||||
self_terminating = true;
|
self_terminating = true;
|
||||||
rtrim_once(tag, "/");
|
tag.rtrim<1>("/");
|
||||||
}
|
}
|
||||||
|
|
||||||
parse_head(tag);
|
parse_head(tag);
|
||||||
|
@ -213,7 +214,7 @@ inline bool xml_element::parse_body(const char *&data) {
|
||||||
tag.replace("\r", " ");
|
tag.replace("\r", " ");
|
||||||
tag.replace("\n", " ");
|
tag.replace("\n", " ");
|
||||||
while(strpos(tag, " ")) tag.replace(" ", " ");
|
while(strpos(tag, " ")) tag.replace(" ", " ");
|
||||||
rtrim(tag);
|
tag.rtrim();
|
||||||
|
|
||||||
if(name != tag) throw "...";
|
if(name != tag) throw "...";
|
||||||
return true;
|
return true;
|
||||||
|
|
|
@ -1,190 +1,223 @@
|
||||||
#ifndef NALL_UPS_HPP
|
#ifndef NALL_UPS_HPP
|
||||||
#define NALL_UPS_HPP
|
#define NALL_UPS_HPP
|
||||||
|
|
||||||
#include <stdio.h>
|
|
||||||
|
|
||||||
#include <nall/algorithm.hpp>
|
|
||||||
#include <nall/crc32.hpp>
|
#include <nall/crc32.hpp>
|
||||||
#include <nall/file.hpp>
|
#include <nall/file.hpp>
|
||||||
|
#include <nall/function.hpp>
|
||||||
#include <nall/stdint.hpp>
|
#include <nall/stdint.hpp>
|
||||||
|
|
||||||
namespace nall {
|
namespace nall {
|
||||||
class ups {
|
|
||||||
public:
|
|
||||||
enum result {
|
|
||||||
ok,
|
|
||||||
patch_unreadable,
|
|
||||||
patch_unwritable,
|
|
||||||
patch_invalid,
|
|
||||||
input_invalid,
|
|
||||||
output_invalid,
|
|
||||||
patch_crc32_invalid,
|
|
||||||
input_crc32_invalid,
|
|
||||||
output_crc32_invalid,
|
|
||||||
};
|
|
||||||
|
|
||||||
ups::result create(const char *patch_fn, const uint8_t *x_data, unsigned x_size, const uint8_t *y_data, unsigned y_size) {
|
struct ups {
|
||||||
if(!fp.open(patch_fn, file::mode_write)) return patch_unwritable;
|
enum class result : unsigned {
|
||||||
|
unknown,
|
||||||
|
success,
|
||||||
|
patch_unwritable,
|
||||||
|
patch_invalid,
|
||||||
|
source_invalid,
|
||||||
|
target_invalid,
|
||||||
|
target_too_small,
|
||||||
|
patch_checksum_invalid,
|
||||||
|
source_checksum_invalid,
|
||||||
|
target_checksum_invalid,
|
||||||
|
};
|
||||||
|
|
||||||
crc32 = ~0;
|
function<void (unsigned offset, unsigned length)> progress;
|
||||||
uint32_t x_crc32 = crc32_calculate(x_data, x_size);
|
|
||||||
uint32_t y_crc32 = crc32_calculate(y_data, y_size);
|
|
||||||
|
|
||||||
//header
|
result create(
|
||||||
write('U');
|
const uint8_t *sourcedata, unsigned sourcelength,
|
||||||
write('P');
|
const uint8_t *targetdata, unsigned targetlength,
|
||||||
write('S');
|
const char *patchfilename
|
||||||
write('1');
|
) {
|
||||||
encptr(x_size);
|
source_data = (uint8_t*)sourcedata, target_data = (uint8_t*)targetdata;
|
||||||
encptr(y_size);
|
source_length = sourcelength, target_length = targetlength;
|
||||||
|
source_offset = target_offset = 0;
|
||||||
|
source_checksum = target_checksum = patch_checksum = ~0;
|
||||||
|
|
||||||
//body
|
if(patch_file.open(patchfilename, file::mode::write) == false) return result::patch_unwritable;
|
||||||
unsigned max_size = max(x_size, y_size);
|
|
||||||
unsigned relative = 0;
|
|
||||||
for(unsigned i = 0; i < max_size;) {
|
|
||||||
uint8_t x = i < x_size ? x_data[i] : 0x00;
|
|
||||||
uint8_t y = i < y_size ? y_data[i] : 0x00;
|
|
||||||
|
|
||||||
if(x == y) {
|
patch_write('U');
|
||||||
i++;
|
patch_write('P');
|
||||||
continue;
|
patch_write('S');
|
||||||
}
|
patch_write('1');
|
||||||
|
encode(source_length);
|
||||||
|
encode(target_length);
|
||||||
|
|
||||||
encptr(i++ - relative);
|
unsigned output_length = source_length > target_length ? source_length : target_length;
|
||||||
write(x ^ y);
|
unsigned relative = 0;
|
||||||
|
for(unsigned offset = 0; offset < output_length;) {
|
||||||
|
uint8_t x = source_read();
|
||||||
|
uint8_t y = target_read();
|
||||||
|
|
||||||
while(true) {
|
if(x == y) {
|
||||||
if(i >= max_size) {
|
offset++;
|
||||||
write(0x00);
|
continue;
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
x = i < x_size ? x_data[i] : 0x00;
|
|
||||||
y = i < y_size ? y_data[i] : 0x00;
|
|
||||||
i++;
|
|
||||||
write(x ^ y);
|
|
||||||
if(x == y) break;
|
|
||||||
}
|
|
||||||
|
|
||||||
relative = i;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
//footer
|
encode(offset++ - relative);
|
||||||
for(unsigned i = 0; i < 4; i++) write(x_crc32 >> (i << 3));
|
patch_write(x ^ y);
|
||||||
for(unsigned i = 0; i < 4; i++) write(y_crc32 >> (i << 3));
|
|
||||||
uint32_t p_crc32 = ~crc32;
|
|
||||||
for(unsigned i = 0; i < 4; i++) write(p_crc32 >> (i << 3));
|
|
||||||
|
|
||||||
fp.close();
|
|
||||||
return ok;
|
|
||||||
}
|
|
||||||
|
|
||||||
ups::result apply(const uint8_t *p_data, unsigned p_size, const uint8_t *x_data, unsigned x_size, uint8_t *&y_data, unsigned &y_size) {
|
|
||||||
if(p_size < 18) return patch_invalid;
|
|
||||||
p_buffer = p_data;
|
|
||||||
|
|
||||||
crc32 = ~0;
|
|
||||||
|
|
||||||
//header
|
|
||||||
if(read() != 'U') return patch_invalid;
|
|
||||||
if(read() != 'P') return patch_invalid;
|
|
||||||
if(read() != 'S') return patch_invalid;
|
|
||||||
if(read() != '1') return patch_invalid;
|
|
||||||
|
|
||||||
unsigned px_size = decptr();
|
|
||||||
unsigned py_size = decptr();
|
|
||||||
|
|
||||||
//mirror
|
|
||||||
if(x_size != px_size && x_size != py_size) return input_invalid;
|
|
||||||
y_size = (x_size == px_size) ? py_size : px_size;
|
|
||||||
y_data = new uint8_t[y_size]();
|
|
||||||
|
|
||||||
for(unsigned i = 0; i < x_size && i < y_size; i++) y_data[i] = x_data[i];
|
|
||||||
for(unsigned i = x_size; i < y_size; i++) y_data[i] = 0x00;
|
|
||||||
|
|
||||||
//body
|
|
||||||
unsigned relative = 0;
|
|
||||||
while(p_buffer < p_data + p_size - 12) {
|
|
||||||
relative += decptr();
|
|
||||||
|
|
||||||
while(true) {
|
|
||||||
uint8_t x = read();
|
|
||||||
if(x && relative < y_size) {
|
|
||||||
uint8_t y = relative < x_size ? x_data[relative] : 0x00;
|
|
||||||
y_data[relative] = x ^ y;
|
|
||||||
}
|
|
||||||
relative++;
|
|
||||||
if(!x) break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
//footer
|
|
||||||
unsigned px_crc32 = 0, py_crc32 = 0, pp_crc32 = 0;
|
|
||||||
for(unsigned i = 0; i < 4; i++) px_crc32 |= read() << (i << 3);
|
|
||||||
for(unsigned i = 0; i < 4; i++) py_crc32 |= read() << (i << 3);
|
|
||||||
uint32_t p_crc32 = ~crc32;
|
|
||||||
for(unsigned i = 0; i < 4; i++) pp_crc32 |= read() << (i << 3);
|
|
||||||
|
|
||||||
uint32_t x_crc32 = crc32_calculate(x_data, x_size);
|
|
||||||
uint32_t y_crc32 = crc32_calculate(y_data, y_size);
|
|
||||||
|
|
||||||
if(px_size != py_size) {
|
|
||||||
if(x_size == px_size && x_crc32 != px_crc32) return input_crc32_invalid;
|
|
||||||
if(x_size == py_size && x_crc32 != py_crc32) return input_crc32_invalid;
|
|
||||||
if(y_size == px_size && y_crc32 != px_crc32) return output_crc32_invalid;
|
|
||||||
if(y_size == py_size && y_crc32 != py_crc32) return output_crc32_invalid;
|
|
||||||
} else {
|
|
||||||
if(x_crc32 != px_crc32 && x_crc32 != py_crc32) return input_crc32_invalid;
|
|
||||||
if(y_crc32 != px_crc32 && y_crc32 != py_crc32) return output_crc32_invalid;
|
|
||||||
if(x_crc32 == y_crc32 && px_crc32 != py_crc32) return output_crc32_invalid;
|
|
||||||
if(x_crc32 != y_crc32 && px_crc32 == py_crc32) return output_crc32_invalid;
|
|
||||||
}
|
|
||||||
|
|
||||||
if(p_crc32 != pp_crc32) return patch_crc32_invalid;
|
|
||||||
return ok;
|
|
||||||
}
|
|
||||||
|
|
||||||
private:
|
|
||||||
file fp;
|
|
||||||
uint32_t crc32;
|
|
||||||
const uint8_t *p_buffer;
|
|
||||||
|
|
||||||
uint8_t read() {
|
|
||||||
uint8_t n = *p_buffer++;
|
|
||||||
crc32 = crc32_adjust(crc32, n);
|
|
||||||
return n;
|
|
||||||
}
|
|
||||||
|
|
||||||
void write(uint8_t n) {
|
|
||||||
fp.write(n);
|
|
||||||
crc32 = crc32_adjust(crc32, n);
|
|
||||||
}
|
|
||||||
|
|
||||||
void encptr(uint64_t offset) {
|
|
||||||
while(true) {
|
while(true) {
|
||||||
uint64_t x = offset & 0x7f;
|
if(offset >= output_length) {
|
||||||
offset >>= 7;
|
patch_write(0x00);
|
||||||
if(offset == 0) {
|
|
||||||
write(0x80 | x);
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
write(x);
|
|
||||||
offset--;
|
x = source_read();
|
||||||
|
y = target_read();
|
||||||
|
offset++;
|
||||||
|
patch_write(x ^ y);
|
||||||
|
if(x == y) break;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
relative = offset;
|
||||||
}
|
}
|
||||||
|
|
||||||
uint64_t decptr() {
|
source_checksum = ~source_checksum;
|
||||||
uint64_t offset = 0, shift = 1;
|
target_checksum = ~target_checksum;
|
||||||
|
for(unsigned i = 0; i < 4; i++) patch_write(source_checksum >> (i * 8));
|
||||||
|
for(unsigned i = 0; i < 4; i++) patch_write(target_checksum >> (i * 8));
|
||||||
|
uint32_t patch_result_checksum = ~patch_checksum;
|
||||||
|
for(unsigned i = 0; i < 4; i++) patch_write(patch_result_checksum >> (i * 8));
|
||||||
|
|
||||||
|
patch_file.close();
|
||||||
|
return result::success;
|
||||||
|
}
|
||||||
|
|
||||||
|
result apply(
|
||||||
|
const uint8_t *patchdata, unsigned patchlength,
|
||||||
|
const uint8_t *sourcedata, unsigned sourcelength,
|
||||||
|
uint8_t *targetdata, unsigned &targetlength
|
||||||
|
) {
|
||||||
|
patch_data = (uint8_t*)patchdata, source_data = (uint8_t*)sourcedata, target_data = targetdata;
|
||||||
|
patch_length = patchlength, source_length = sourcelength, target_length = targetlength;
|
||||||
|
patch_offset = source_offset = target_offset = 0;
|
||||||
|
patch_checksum = source_checksum = target_checksum = ~0;
|
||||||
|
|
||||||
|
if(patch_length < 18) return result::patch_invalid;
|
||||||
|
if(patch_read() != 'U') return result::patch_invalid;
|
||||||
|
if(patch_read() != 'P') return result::patch_invalid;
|
||||||
|
if(patch_read() != 'S') return result::patch_invalid;
|
||||||
|
if(patch_read() != '1') return result::patch_invalid;
|
||||||
|
|
||||||
|
unsigned source_read_length = decode();
|
||||||
|
unsigned target_read_length = decode();
|
||||||
|
|
||||||
|
if(source_length != source_read_length && source_length != target_read_length) return result::source_invalid;
|
||||||
|
targetlength = (source_length == source_read_length ? target_read_length : source_read_length);
|
||||||
|
if(target_length < targetlength) return result::target_too_small;
|
||||||
|
target_length = targetlength;
|
||||||
|
|
||||||
|
while(patch_offset < patch_length - 12) {
|
||||||
|
unsigned length = decode();
|
||||||
|
while(length--) target_write(source_read());
|
||||||
while(true) {
|
while(true) {
|
||||||
uint8_t x = read();
|
uint8_t patch_xor = patch_read();
|
||||||
offset += (x & 0x7f) * shift;
|
target_write(patch_xor ^ source_read());
|
||||||
if(x & 0x80) break;
|
if(patch_xor == 0) break;
|
||||||
shift <<= 7;
|
|
||||||
offset += shift;
|
|
||||||
}
|
}
|
||||||
return offset;
|
|
||||||
}
|
}
|
||||||
};
|
while(source_offset < source_length) target_write(source_read());
|
||||||
|
while(target_offset < target_length) target_write(source_read());
|
||||||
|
|
||||||
|
uint32_t patch_read_checksum = 0, source_read_checksum = 0, target_read_checksum = 0;
|
||||||
|
for(unsigned i = 0; i < 4; i++) source_read_checksum |= patch_read() << (i * 8);
|
||||||
|
for(unsigned i = 0; i < 4; i++) target_read_checksum |= patch_read() << (i * 8);
|
||||||
|
uint32_t patch_result_checksum = ~patch_checksum;
|
||||||
|
source_checksum = ~source_checksum;
|
||||||
|
target_checksum = ~target_checksum;
|
||||||
|
for(unsigned i = 0; i < 4; i++) patch_read_checksum |= patch_read() << (i * 8);
|
||||||
|
|
||||||
|
if(patch_result_checksum != patch_read_checksum) return result::patch_invalid;
|
||||||
|
if(source_checksum == source_read_checksum && source_length == source_read_length) {
|
||||||
|
if(target_checksum == target_read_checksum && target_length == target_read_length) return result::success;
|
||||||
|
return result::target_invalid;
|
||||||
|
} else if(source_checksum == target_read_checksum && source_length == target_read_length) {
|
||||||
|
if(target_checksum == source_read_checksum && target_length == source_read_length) return result::success;
|
||||||
|
return result::target_invalid;
|
||||||
|
} else {
|
||||||
|
return result::source_invalid;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
uint8_t *patch_data, *source_data, *target_data;
|
||||||
|
unsigned patch_length, source_length, target_length;
|
||||||
|
unsigned patch_offset, source_offset, target_offset;
|
||||||
|
unsigned patch_checksum, source_checksum, target_checksum;
|
||||||
|
file patch_file;
|
||||||
|
|
||||||
|
uint8_t patch_read() {
|
||||||
|
if(patch_offset < patch_length) {
|
||||||
|
uint8_t n = patch_data[patch_offset++];
|
||||||
|
patch_checksum = crc32_adjust(patch_checksum, n);
|
||||||
|
return n;
|
||||||
|
}
|
||||||
|
return 0x00;
|
||||||
|
}
|
||||||
|
|
||||||
|
uint8_t source_read() {
|
||||||
|
if(source_offset < source_length) {
|
||||||
|
uint8_t n = source_data[source_offset++];
|
||||||
|
source_checksum = crc32_adjust(source_checksum, n);
|
||||||
|
return n;
|
||||||
|
}
|
||||||
|
return 0x00;
|
||||||
|
}
|
||||||
|
|
||||||
|
uint8_t target_read() {
|
||||||
|
uint8_t result = 0x00;
|
||||||
|
if(target_offset < target_length) {
|
||||||
|
result = target_data[target_offset];
|
||||||
|
target_checksum = crc32_adjust(target_checksum, result);
|
||||||
|
}
|
||||||
|
if(((target_offset++ & 255) == 0) && progress) {
|
||||||
|
progress(target_offset, source_length > target_length ? source_length : target_length);
|
||||||
|
}
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
void patch_write(uint8_t n) {
|
||||||
|
patch_file.write(n);
|
||||||
|
patch_checksum = crc32_adjust(patch_checksum, n);
|
||||||
|
}
|
||||||
|
|
||||||
|
void target_write(uint8_t n) {
|
||||||
|
if(target_offset < target_length) {
|
||||||
|
target_data[target_offset] = n;
|
||||||
|
target_checksum = crc32_adjust(target_checksum, n);
|
||||||
|
}
|
||||||
|
if(((target_offset++ & 255) == 0) && progress) {
|
||||||
|
progress(target_offset, source_length > target_length ? source_length : target_length);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void encode(uint64_t offset) {
|
||||||
|
while(true) {
|
||||||
|
uint64_t x = offset & 0x7f;
|
||||||
|
offset >>= 7;
|
||||||
|
if(offset == 0) {
|
||||||
|
patch_write(0x80 | x);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
patch_write(x);
|
||||||
|
offset--;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
uint64_t decode() {
|
||||||
|
uint64_t offset = 0, shift = 1;
|
||||||
|
while(true) {
|
||||||
|
uint8_t x = patch_read();
|
||||||
|
offset += (x & 0x7f) * shift;
|
||||||
|
if(x & 0x80) break;
|
||||||
|
shift <<= 7;
|
||||||
|
offset += shift;
|
||||||
|
}
|
||||||
|
return offset;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
|
@ -6,9 +6,11 @@
|
||||||
|
|
||||||
#if defined(_WIN32)
|
#if defined(_WIN32)
|
||||||
|
|
||||||
|
#undef UNICODE
|
||||||
#undef _WIN32_WINNT
|
#undef _WIN32_WINNT
|
||||||
#define _WIN32_WINNT 0x0501
|
|
||||||
#undef NOMINMAX
|
#undef NOMINMAX
|
||||||
|
#define UNICODE
|
||||||
|
#define _WIN32_WINNT 0x0501
|
||||||
#define NOMINMAX
|
#define NOMINMAX
|
||||||
#include <windows.h>
|
#include <windows.h>
|
||||||
#undef interface
|
#undef interface
|
||||||
|
@ -62,9 +64,21 @@ namespace nall {
|
||||||
delete[] buffer;
|
delete[] buffer;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
utf8_t(const utf8_t&) = delete;
|
||||||
|
utf8_t& operator=(const utf8_t&) = delete;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
char *buffer;
|
char *buffer;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
inline void utf8_args(int &argc, char **&argv) {
|
||||||
|
wchar_t **wargv = CommandLineToArgvW(GetCommandLineW(), &argc);
|
||||||
|
argv = new char*[argc];
|
||||||
|
for(unsigned i = 0; i < argc; i++) {
|
||||||
|
argv[i] = new char[_MAX_PATH];
|
||||||
|
strcpy(argv[i], nall::utf8_t(wargv[i]));
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#endif //if defined(_WIN32)
|
#endif //if defined(_WIN32)
|
||||||
|
|
|
@ -1,9 +1,9 @@
|
||||||
#ifndef NALL_VARINT_HPP
|
#ifndef NALL_VARINT_HPP
|
||||||
#define NALL_VARINT_HPP
|
#define NALL_VARINT_HPP
|
||||||
|
|
||||||
|
#include <type_traits>
|
||||||
#include <nall/bit.hpp>
|
#include <nall/bit.hpp>
|
||||||
#include <nall/static.hpp>
|
#include <nall/static.hpp>
|
||||||
#include <nall/traits.hpp>
|
|
||||||
|
|
||||||
namespace nall {
|
namespace nall {
|
||||||
template<unsigned bits> class uint_t {
|
template<unsigned bits> class uint_t {
|
||||||
|
@ -22,7 +22,7 @@ namespace nall {
|
||||||
>::type
|
>::type
|
||||||
>::type
|
>::type
|
||||||
>::type T;
|
>::type T;
|
||||||
static_assert<!is_void<T>::value> uint_assert;
|
static_assert(!std::is_same<T, void>::value, "");
|
||||||
T data;
|
T data;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
|
@ -63,7 +63,7 @@ namespace nall {
|
||||||
>::type
|
>::type
|
||||||
>::type
|
>::type
|
||||||
>::type T;
|
>::type T;
|
||||||
static_assert<!is_void<T>::value> int_assert;
|
static_assert(!std::is_same<T, void>::value, "");
|
||||||
T data;
|
T data;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
|
|
Loading…
Reference in New Issue