mirror of
https://github.com/libretro/bsnes-libretro.git
synced 2024-12-11 11:03:33 +00:00
Update to v080r03 release.
byuu says: Wow, nothing in 19 days. Anyway, I wanted to get Nick's logo back in on the about screen. Adds 80kb to both the binary and source archive, but eh. Gotta have some style. Nothing else new.
This commit is contained in:
parent
ec69109c0b
commit
8276700381
2553
bsnes/data/bsnes-logo.hpp
Executable file
2553
bsnes/data/bsnes-logo.hpp
Executable file
File diff suppressed because it is too large
Load Diff
@ -72,6 +72,7 @@ namespace nall {
|
||||
|
||||
private:
|
||||
static char enc(uint8_t n) {
|
||||
//base64 for URL encodings
|
||||
static char lookup_table[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-_";
|
||||
return lookup_table[n & 63];
|
||||
}
|
||||
|
@ -8,7 +8,7 @@
|
||||
#include <nall/utility.hpp>
|
||||
|
||||
namespace nall {
|
||||
inline FILE* fopen_utf8(const char *utf8_filename, const char *mode) {
|
||||
inline FILE* fopen_utf8(const string &utf8_filename, const char *mode) {
|
||||
#if !defined(_WIN32)
|
||||
return fopen(utf8_filename, mode);
|
||||
#else
|
||||
@ -135,7 +135,7 @@ namespace nall {
|
||||
return file_offset >= file_size;
|
||||
}
|
||||
|
||||
static bool exists(const char *filename) {
|
||||
static bool exists(const string &filename) {
|
||||
#if !defined(_WIN32)
|
||||
struct stat64 data;
|
||||
return stat64(filename, &data) == 0;
|
||||
@ -145,7 +145,7 @@ namespace nall {
|
||||
#endif
|
||||
}
|
||||
|
||||
static uintmax_t size(const char *filename) {
|
||||
static uintmax_t size(const string &filename) {
|
||||
#if !defined(_WIN32)
|
||||
struct stat64 data;
|
||||
stat64(filename, &data);
|
||||
@ -156,7 +156,7 @@ namespace nall {
|
||||
return S_ISREG(data.st_mode) ? data.st_size : 0u;
|
||||
}
|
||||
|
||||
static time_t timestamp(const char *filename, file::time mode = file::time::create) {
|
||||
static time_t timestamp(const string &filename, file::time mode = file::time::create) {
|
||||
#if !defined(_WIN32)
|
||||
struct stat64 data;
|
||||
stat64(filename, &data);
|
||||
@ -175,7 +175,7 @@ namespace nall {
|
||||
return fp;
|
||||
}
|
||||
|
||||
bool open(const char *filename, mode mode_) {
|
||||
bool open(const string &filename, mode mode_) {
|
||||
if(fp) return false;
|
||||
|
||||
switch(file_mode = mode_) {
|
||||
|
@ -2,14 +2,13 @@
|
||||
#define NALL_LZSS_HPP
|
||||
|
||||
#include <nall/array.hpp>
|
||||
#include <nall/new.hpp>
|
||||
#include <nall/stdint.hpp>
|
||||
|
||||
namespace nall {
|
||||
class lzss {
|
||||
public:
|
||||
static bool encode(uint8_t *&output, unsigned &outlength, const uint8_t *input, unsigned inlength) {
|
||||
output = new(zeromemory) uint8_t[inlength * 9 / 8 + 9];
|
||||
output = new uint8_t[inlength * 9 / 8 + 9]();
|
||||
|
||||
unsigned i = 0, o = 0;
|
||||
while(i < inlength) {
|
||||
@ -52,7 +51,7 @@ namespace nall {
|
||||
}
|
||||
|
||||
static bool decode(uint8_t *&output, const uint8_t *input, unsigned length) {
|
||||
output = new(zeromemory) uint8_t[length];
|
||||
output = new uint8_t[length]();
|
||||
|
||||
unsigned i = 0, o = 0;
|
||||
while(o < length) {
|
||||
|
59
bsnes/nall/resource.hpp
Executable file
59
bsnes/nall/resource.hpp
Executable file
@ -0,0 +1,59 @@
|
||||
#ifndef NALL_RESOURCE_HPP
|
||||
#define NALL_RESOURCE_HPP
|
||||
|
||||
#include <nall/file.hpp>
|
||||
#include <nall/lzss.hpp>
|
||||
|
||||
namespace nall {
|
||||
|
||||
struct resource {
|
||||
static bool encode(const char *outputFilename, const char *inputFilename) {
|
||||
file fp;
|
||||
if(fp.open(inputFilename, file::mode::read) == false) return false;
|
||||
unsigned inputSize = fp.size();
|
||||
uint8_t *inputData = new uint8_t[inputSize];
|
||||
fp.read(inputData, inputSize);
|
||||
fp.close();
|
||||
|
||||
unsigned outputSize;
|
||||
uint8_t *outputData;
|
||||
lzss::encode(outputData, outputSize, inputData, inputSize);
|
||||
|
||||
fp.open(outputFilename, file::mode::write);
|
||||
fp.print("static const unsigned size = ", inputSize, ";\n");
|
||||
fp.print("static const uint8_t data[", outputSize, "] = {\n");
|
||||
uint8_t *p = outputData;
|
||||
while(outputSize) {
|
||||
fp.print(" ");
|
||||
for(unsigned n = 0; n < 32 && outputSize; n++, outputSize--) {
|
||||
fp.print((unsigned)*p++, ",");
|
||||
}
|
||||
fp.print("\n");
|
||||
}
|
||||
fp.print("};\n");
|
||||
fp.close();
|
||||
|
||||
delete[] inputData;
|
||||
delete[] outputData;
|
||||
}
|
||||
|
||||
uint8_t *data;
|
||||
unsigned size;
|
||||
|
||||
bool decode(const uint8_t *inputData, unsigned outputSize) {
|
||||
if(data) delete[] data;
|
||||
lzss::decode(data, inputData, size = outputSize);
|
||||
return true;
|
||||
}
|
||||
|
||||
resource() : data(0), size(0) {
|
||||
}
|
||||
|
||||
~resource() {
|
||||
if(data) delete[] data;
|
||||
}
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
#endif
|
@ -3,6 +3,8 @@
|
||||
|
||||
//author: vladitx
|
||||
|
||||
#include <nall/stdint.hpp>
|
||||
|
||||
namespace nall {
|
||||
#define PTR(t, a) ((t*)(a))
|
||||
|
||||
|
@ -1,66 +1,29 @@
|
||||
#ifndef NALL_STACK_HPP
|
||||
#define NALL_STACK_HPP
|
||||
|
||||
#include <nall/concept.hpp>
|
||||
#include <nall/vector.hpp>
|
||||
|
||||
namespace nall {
|
||||
template<typename T> struct stack_fifo {
|
||||
T& operator()() {
|
||||
if(list.size() == 0) throw;
|
||||
return list[0];
|
||||
}
|
||||
|
||||
void reset() {
|
||||
list.reset();
|
||||
}
|
||||
|
||||
unsigned size() const {
|
||||
return list.size();
|
||||
}
|
||||
|
||||
template<typename T> struct stack : public linear_vector<T> {
|
||||
void push(const T &value) {
|
||||
list.append(value);
|
||||
linear_vector<T>::append(value);
|
||||
}
|
||||
|
||||
T pull() {
|
||||
if(list.size() == 0) throw;
|
||||
T value = list[0];
|
||||
list.remove(0);
|
||||
if(linear_vector<T>::size() == 0) throw;
|
||||
T value = linear_vector<T>::operator[](linear_vector<T>::size() - 1);
|
||||
linear_vector<T>::remove(linear_vector<T>::size() - 1);
|
||||
return value;
|
||||
}
|
||||
|
||||
private:
|
||||
linear_vector<T> list;
|
||||
};
|
||||
|
||||
template<typename T> struct stack_filo {
|
||||
T& operator()() {
|
||||
if(list.size() == 0) throw;
|
||||
return list[list.size() - 1];
|
||||
if(linear_vector<T>::size() == 0) throw;
|
||||
return linear_vector<T>::operator[](linear_vector<T>::size() - 1);
|
||||
}
|
||||
|
||||
void reset() {
|
||||
list.reset();
|
||||
}
|
||||
|
||||
unsigned size() const {
|
||||
return list.size();
|
||||
}
|
||||
|
||||
void push(const T &value) {
|
||||
list.append(value);
|
||||
}
|
||||
|
||||
T pull() {
|
||||
if(list.size() == 0) throw;
|
||||
T value = list[list.size() - 1];
|
||||
list.remove(list.size() - 1);
|
||||
return value;
|
||||
}
|
||||
|
||||
private:
|
||||
linear_vector<T> list;
|
||||
};
|
||||
|
||||
template<typename T> struct has_size<stack<T>> { enum { value = true }; };
|
||||
}
|
||||
|
||||
#endif
|
||||
|
@ -2,6 +2,7 @@
|
||||
#define NALL_STRING_HPP
|
||||
|
||||
#include <initializer_list>
|
||||
#include <nall/array.hpp>
|
||||
#include <nall/platform.hpp>
|
||||
#include <nall/sha256.hpp>
|
||||
#include <nall/utility.hpp>
|
||||
|
@ -13,6 +13,7 @@
|
||||
|
||||
namespace nall {
|
||||
class string;
|
||||
class lstring;
|
||||
template<typename T> inline const char* to_string(T);
|
||||
|
||||
class string {
|
||||
@ -36,6 +37,7 @@ namespace nall {
|
||||
|
||||
inline bool wildcard(const char*) const;
|
||||
inline bool iwildcard(const char*) const;
|
||||
inline lstring lwildcard(const char*) const;
|
||||
|
||||
inline bool beginswith(const char*) const;
|
||||
inline bool ibeginswith(const char*) const;
|
||||
@ -102,6 +104,7 @@ namespace nall {
|
||||
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 lstring lwildcard(const char *str, const char *pattern);
|
||||
inline bool strbegin (const char *str, const char *key);
|
||||
inline bool stribegin(const char *str, const char *key);
|
||||
inline bool strend (const char *str, const char *key);
|
||||
|
@ -59,6 +59,39 @@ bool iwildcard(const char *s, const char *p) {
|
||||
return !*p;
|
||||
}
|
||||
|
||||
lstring lwildcard(const char *s, const char *p) {
|
||||
lstring output;
|
||||
array<const char*> sp, ep;
|
||||
const char *cp = 0, *mp = 0;
|
||||
while(*s && *p != '*') {
|
||||
if(*p != '?' && *s != *p) return output;
|
||||
p++, s++;
|
||||
}
|
||||
while(*s) {
|
||||
if(*p == '*') {
|
||||
sp.append(s), ep.append(s);
|
||||
if(!*++p) {
|
||||
while(*s) s++;
|
||||
ep[ep.size() - 1] = s;
|
||||
break;
|
||||
}
|
||||
mp = p, cp = s + 1;
|
||||
} else if(*p == '?' || *p == *s) {
|
||||
p++, s++;
|
||||
} else {
|
||||
ep[ep.size() - 1] = cp;
|
||||
p = mp, s = cp++;
|
||||
}
|
||||
}
|
||||
while(*p == '*') p++;
|
||||
if(*p) return output;
|
||||
|
||||
for(unsigned n = 0; n < sp.size(); n++) {
|
||||
output.append(substr(sp[n], 0, ep[n] - sp[n]));
|
||||
}
|
||||
return output;
|
||||
}
|
||||
|
||||
bool strbegin(const char *str, const char *key) {
|
||||
int i, ssl = strlen(str), ksl = strlen(key);
|
||||
|
||||
|
@ -27,7 +27,7 @@ char* qstrlower(char *s) {
|
||||
if(!s) return 0;
|
||||
bool quoted = false;
|
||||
while(*s) {
|
||||
if(*s == '\"') quoted ^= 1;
|
||||
if(*s == '\"' || *s == '\'') quoted ^= 1;
|
||||
if(quoted == false && *s >= 'A' && *s <= 'Z') *s += 0x20;
|
||||
s++;
|
||||
}
|
||||
@ -37,7 +37,7 @@ char* qstrupper(char *s) {
|
||||
if(!s) return 0;
|
||||
bool quoted = false;
|
||||
while(*s) {
|
||||
if(*s == '\"') quoted ^= 1;
|
||||
if(*s == '\"' || *s == '\'') quoted ^= 1;
|
||||
if(quoted == false && *s >= 'a' && *s <= 'z') *s -= 0x20;
|
||||
s++;
|
||||
}
|
||||
|
@ -10,6 +10,7 @@ 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); }
|
||||
lstring string::lwildcard(const char *str) const { return nall::lwildcard(data, str); }
|
||||
|
||||
bool string::beginswith(const char *str) const { return strbegin(data, str); }
|
||||
bool string::ibeginswith(const char *str) const { return stribegin(data, str); }
|
||||
|
1
bsnes/nall/test/cc.sh
Executable file
1
bsnes/nall/test/cc.sh
Executable file
@ -0,0 +1 @@
|
||||
g++-4.5 -std=gnu++0x -O3 -fomit-frame-pointer -s -o test test.cpp -I../..
|
44
bsnes/nall/test/test.cpp
Executable file
44
bsnes/nall/test/test.cpp
Executable file
@ -0,0 +1,44 @@
|
||||
#include <nall/any.hpp>
|
||||
#include <nall/array.hpp>
|
||||
#include <nall/base64.hpp>
|
||||
#include <nall/concept.hpp>
|
||||
#include <nall/config.hpp>
|
||||
#include <nall/dictionary.hpp>
|
||||
#include <nall/directory.hpp>
|
||||
#include <nall/dl.hpp>
|
||||
#include <nall/file.hpp>
|
||||
#include <nall/filemap.hpp>
|
||||
#include <nall/foreach.hpp>
|
||||
#include <nall/function.hpp>
|
||||
#include <nall/input.hpp>
|
||||
#include <nall/lzss.hpp>
|
||||
#include <nall/priorityqueue.hpp>
|
||||
#include <nall/public_cast.hpp>
|
||||
#include <nall/reference_array.hpp>
|
||||
#include <nall/resource.hpp>
|
||||
#include <nall/serializer.hpp>
|
||||
#include <nall/stack.hpp>
|
||||
#include <nall/static.hpp>
|
||||
#include <nall/stdint.hpp>
|
||||
#include <nall/string.hpp>
|
||||
#include <nall/utility.hpp>
|
||||
#include <nall/varint.hpp>
|
||||
#include <nall/vector.hpp>
|
||||
#include <nall/snes/cpu.hpp>
|
||||
#include <nall/snes/smp.hpp>
|
||||
#include <nall/snes/cartridge.hpp>
|
||||
#include <nall/gameboy/cartridge.hpp>
|
||||
using namespace nall;
|
||||
|
||||
#include "bsnes-logo.hpp"
|
||||
|
||||
int main(int argc, char **argv) {
|
||||
// resource::encode("bsnes-logo.hpp", "bsnes-logo.bmp");
|
||||
resource logo;
|
||||
logo.decode(data, size);
|
||||
file fp;
|
||||
fp.open("output.bmp", file::mode::write);
|
||||
fp.write(logo.data, logo.size);
|
||||
fp.close();
|
||||
return 0;
|
||||
}
|
@ -26,6 +26,7 @@ namespace nall {
|
||||
public:
|
||||
inline operator bool() const { return valid; }
|
||||
inline const T& operator()() const { if(!valid) throw; return value; }
|
||||
inline optional<T>& operator=(const optional<T> &source) { valid = source.valid; value = source.value; return *this; }
|
||||
inline optional(bool valid, const T &value) : valid(valid), value(value) {}
|
||||
};
|
||||
|
||||
|
192
bsnes/nall/windows/detour.hpp
Executable file
192
bsnes/nall/windows/detour.hpp
Executable file
@ -0,0 +1,192 @@
|
||||
#ifndef NALL_WINDOWS_DETOUR_HPP
|
||||
#define NALL_WINDOWS_DETOUR_HPP
|
||||
|
||||
#include <nall/foreach.hpp>
|
||||
#include <nall/platform.hpp>
|
||||
#include <nall/stdint.hpp>
|
||||
#include <nall/string.hpp>
|
||||
#include <nall/utf8.hpp>
|
||||
|
||||
namespace nall {
|
||||
|
||||
#define Copy 0
|
||||
#define RelNear 1
|
||||
|
||||
struct detour {
|
||||
static bool insert(const string &moduleName, const string &functionName, void *&source, void *target);
|
||||
static bool remove(const string &moduleName, const string &functionName, void *&source);
|
||||
|
||||
protected:
|
||||
static unsigned length(const uint8_t *function);
|
||||
static unsigned mirror(uint8_t *target, const uint8_t *source);
|
||||
|
||||
struct opcode {
|
||||
uint16_t prefix;
|
||||
unsigned length;
|
||||
unsigned mode;
|
||||
uint16_t modify;
|
||||
};
|
||||
static opcode opcodes[];
|
||||
};
|
||||
|
||||
//TODO:
|
||||
//* fs:, gs: should force another opcode copy
|
||||
//* conditional branches within +5-byte range should fail
|
||||
detour::opcode detour::opcodes[] = {
|
||||
{ 0x50, 1 }, //push eax
|
||||
{ 0x51, 1 }, //push ecx
|
||||
{ 0x52, 1 }, //push edx
|
||||
{ 0x53, 1 }, //push ebx
|
||||
{ 0x54, 1 }, //push esp
|
||||
{ 0x55, 1 }, //push ebp
|
||||
{ 0x56, 1 }, //push esi
|
||||
{ 0x57, 1 }, //push edi
|
||||
{ 0x58, 1 }, //pop eax
|
||||
{ 0x59, 1 }, //pop ecx
|
||||
{ 0x5a, 1 }, //pop edx
|
||||
{ 0x5b, 1 }, //pop ebx
|
||||
{ 0x5c, 1 }, //pop esp
|
||||
{ 0x5d, 1 }, //pop ebp
|
||||
{ 0x5e, 1 }, //pop esi
|
||||
{ 0x5f, 1 }, //pop edi
|
||||
{ 0x64, 1 }, //fs:
|
||||
{ 0x65, 1 }, //gs:
|
||||
{ 0x68, 5 }, //push dword
|
||||
{ 0x6a, 2 }, //push byte
|
||||
{ 0x74, 2, RelNear, 0x0f84 }, //je near -> je far
|
||||
{ 0x75, 2, RelNear, 0x0f85 }, //jne near -> jne far
|
||||
{ 0x89, 2 }, //mov reg,reg
|
||||
{ 0x8b, 2 }, //mov reg,reg
|
||||
{ 0x90, 1 }, //nop
|
||||
{ 0xa1, 5 }, //mov eax,[dword]
|
||||
{ 0xeb, 2, RelNear, 0xe9 }, //jmp near -> jmp far
|
||||
};
|
||||
|
||||
bool detour::insert(const string &moduleName, const string &functionName, void *&source, void *target) {
|
||||
HMODULE module = GetModuleHandleW(utf16_t(moduleName));
|
||||
if(!module) return false;
|
||||
|
||||
uint8_t *sourceData = (uint8_t*)GetProcAddress(module, functionName);
|
||||
if(!sourceData) return false;
|
||||
|
||||
unsigned sourceLength = detour::length(sourceData);
|
||||
if(sourceLength < 5) {
|
||||
//unable to clone enough bytes to insert hook
|
||||
#if 1
|
||||
string output = { "detour::insert(", moduleName, "::", functionName, ") failed: " };
|
||||
for(unsigned n = 0; n < 16; n++) output.append(hex<2>(sourceData[n]), " ");
|
||||
output.rtrim<1>(" ");
|
||||
MessageBoxA(0, output, "nall::detour", MB_OK);
|
||||
#endif
|
||||
return false;
|
||||
}
|
||||
|
||||
uint8_t *mirrorData = new uint8_t[512]();
|
||||
detour::mirror(mirrorData, sourceData);
|
||||
|
||||
DWORD privileges;
|
||||
VirtualProtect((void*)mirrorData, 512, PAGE_EXECUTE_READWRITE, &privileges);
|
||||
VirtualProtect((void*)sourceData, 256, PAGE_EXECUTE_READWRITE, &privileges);
|
||||
uintmax_t address = (uintmax_t)target - ((uintmax_t)sourceData + 5);
|
||||
sourceData[0] = 0xe9; //jmp target
|
||||
sourceData[1] = address >> 0;
|
||||
sourceData[2] = address >> 8;
|
||||
sourceData[3] = address >> 16;
|
||||
sourceData[4] = address >> 24;
|
||||
VirtualProtect((void*)sourceData, 256, privileges, &privileges);
|
||||
|
||||
source = (void*)mirrorData;
|
||||
return true;
|
||||
}
|
||||
|
||||
bool detour::remove(const string &moduleName, const string &functionName, void *&source) {
|
||||
HMODULE module = GetModuleHandleW(utf16_t(moduleName));
|
||||
if(!module) return false;
|
||||
|
||||
uint8_t *sourceData = (uint8_t*)GetProcAddress(module, functionName);
|
||||
if(!sourceData) return false;
|
||||
|
||||
uint8_t *mirrorData = (uint8_t*)source;
|
||||
if(mirrorData == sourceData) return false; //hook was never installed
|
||||
|
||||
unsigned length = detour::length(256 + mirrorData);
|
||||
if(length < 5) return false;
|
||||
|
||||
DWORD privileges;
|
||||
VirtualProtect((void*)sourceData, 256, PAGE_EXECUTE_READWRITE, &privileges);
|
||||
for(unsigned n = 0; n < length; n++) sourceData[n] = mirrorData[256 + n];
|
||||
VirtualProtect((void*)sourceData, 256, privileges, &privileges);
|
||||
|
||||
source = (void*)sourceData;
|
||||
delete[] mirrorData;
|
||||
return true;
|
||||
}
|
||||
|
||||
unsigned detour::length(const uint8_t *function) {
|
||||
unsigned length = 0;
|
||||
while(length < 5) {
|
||||
detour::opcode *opcode = 0;
|
||||
foreach(op, detour::opcodes) {
|
||||
if(function[length] == op.prefix) {
|
||||
opcode = &op;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if(opcode == 0) break;
|
||||
length += opcode->length;
|
||||
}
|
||||
return length;
|
||||
}
|
||||
|
||||
unsigned detour::mirror(uint8_t *target, const uint8_t *source) {
|
||||
const uint8_t *entryPoint = source;
|
||||
for(unsigned n = 0; n < 256; n++) target[256 + n] = source[n];
|
||||
|
||||
unsigned size = detour::length(source);
|
||||
while(size) {
|
||||
detour::opcode *opcode = 0;
|
||||
foreach(op, detour::opcodes) {
|
||||
if(*source == op.prefix) {
|
||||
opcode = &op;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
switch(opcode->mode) {
|
||||
case Copy:
|
||||
for(unsigned n = 0; n < opcode->length; n++) *target++ = *source++;
|
||||
break;
|
||||
case RelNear: {
|
||||
source++;
|
||||
uintmax_t sourceAddress = (uintmax_t)source + 1 + (int8_t)*source;
|
||||
*target++ = opcode->modify;
|
||||
if(opcode->modify >> 8) *target++ = opcode->modify >> 8;
|
||||
uintmax_t targetAddress = (uintmax_t)target + 4;
|
||||
uintmax_t address = sourceAddress - targetAddress;
|
||||
*target++ = address >> 0;
|
||||
*target++ = address >> 8;
|
||||
*target++ = address >> 16;
|
||||
*target++ = address >> 24;
|
||||
source += 2;
|
||||
} break;
|
||||
}
|
||||
|
||||
size -= opcode->length;
|
||||
}
|
||||
|
||||
uintmax_t address = (entryPoint + detour::length(entryPoint)) - (target + 5);
|
||||
*target++ = 0xe9; //jmp entryPoint
|
||||
*target++ = address >> 0;
|
||||
*target++ = address >> 8;
|
||||
*target++ = address >> 16;
|
||||
*target++ = address >> 24;
|
||||
|
||||
return source - entryPoint;
|
||||
}
|
||||
|
||||
#undef Implied
|
||||
#undef RelNear
|
||||
|
||||
}
|
||||
|
||||
#endif
|
94
bsnes/nall/windows/launcher.hpp
Executable file
94
bsnes/nall/windows/launcher.hpp
Executable file
@ -0,0 +1,94 @@
|
||||
#ifndef NALL_WINDOWS_LAUNCHER_HPP
|
||||
#define NALL_WINDOWS_LAUNCHER_HPP
|
||||
|
||||
namespace nall {
|
||||
|
||||
//launch a new process and inject specified DLL into it
|
||||
|
||||
bool launch(const char *applicationName, const char *libraryName, uint32_t entryPoint) {
|
||||
//if a launcher does not send at least one message, a wait cursor will appear
|
||||
PostThreadMessage(GetCurrentThreadId(), WM_USER, 0, 0);
|
||||
MSG msg;
|
||||
GetMessage(&msg, 0, 0, 0);
|
||||
|
||||
STARTUPINFOW si;
|
||||
PROCESS_INFORMATION pi;
|
||||
|
||||
memset(&si, 0, sizeof(STARTUPINFOW));
|
||||
BOOL result = CreateProcessW(
|
||||
utf16_t(applicationName), GetCommandLineW(), NULL, NULL, TRUE,
|
||||
DEBUG_PROCESS | DEBUG_ONLY_THIS_PROCESS, //do not break if application creates its own processes
|
||||
NULL, NULL, &si, &pi
|
||||
);
|
||||
if(result == false) return false;
|
||||
|
||||
uint8_t entryData[1024], entryHook[1024] = {
|
||||
0x68, 0x00, 0x00, 0x00, 0x00, //push libraryName
|
||||
0xb8, 0x00, 0x00, 0x00, 0x00, //mov eax,LoadLibraryW
|
||||
0xff, 0xd0, //call eax
|
||||
0xcd, 0x03, //int 3
|
||||
};
|
||||
|
||||
entryHook[1] = (uint8_t)((entryPoint + 14) >> 0);
|
||||
entryHook[2] = (uint8_t)((entryPoint + 14) >> 8);
|
||||
entryHook[3] = (uint8_t)((entryPoint + 14) >> 16);
|
||||
entryHook[4] = (uint8_t)((entryPoint + 14) >> 24);
|
||||
|
||||
uint32_t pLoadLibraryW = (uint32_t)GetProcAddress(GetModuleHandleW(L"kernel32"), "LoadLibraryW");
|
||||
entryHook[6] = pLoadLibraryW >> 0;
|
||||
entryHook[7] = pLoadLibraryW >> 8;
|
||||
entryHook[8] = pLoadLibraryW >> 16;
|
||||
entryHook[9] = pLoadLibraryW >> 24;
|
||||
|
||||
utf16_t buffer = utf16_t(libraryName);
|
||||
memcpy(entryHook + 14, buffer, 2 * wcslen(buffer) + 2);
|
||||
|
||||
while(true) {
|
||||
DEBUG_EVENT event;
|
||||
WaitForDebugEvent(&event, INFINITE);
|
||||
|
||||
if(event.dwDebugEventCode == EXIT_PROCESS_DEBUG_EVENT) break;
|
||||
|
||||
if(event.dwDebugEventCode == EXCEPTION_DEBUG_EVENT) {
|
||||
if(event.u.Exception.ExceptionRecord.ExceptionCode == EXCEPTION_BREAKPOINT) {
|
||||
if(event.u.Exception.ExceptionRecord.ExceptionAddress == (void*)(entryPoint + 14 - 1)) {
|
||||
HANDLE hProcess = OpenProcess(0, FALSE, event.dwProcessId);
|
||||
HANDLE hThread = OpenThread(THREAD_ALL_ACCESS, FALSE, event.dwThreadId);
|
||||
|
||||
CONTEXT context;
|
||||
context.ContextFlags = CONTEXT_FULL;
|
||||
GetThreadContext(hThread, &context);
|
||||
|
||||
WriteProcessMemory(pi.hProcess, (void*)entryPoint, (void*)&entryData, sizeof entryData, NULL);
|
||||
context.Eip = entryPoint;
|
||||
SetThreadContext(hThread, &context);
|
||||
|
||||
CloseHandle(hThread);
|
||||
CloseHandle(hProcess);
|
||||
}
|
||||
|
||||
ContinueDebugEvent(event.dwProcessId, event.dwThreadId, DBG_CONTINUE);
|
||||
continue;
|
||||
}
|
||||
|
||||
ContinueDebugEvent(event.dwProcessId, event.dwThreadId, DBG_EXCEPTION_NOT_HANDLED);
|
||||
continue;
|
||||
}
|
||||
|
||||
if(event.dwDebugEventCode == CREATE_PROCESS_DEBUG_EVENT) {
|
||||
ReadProcessMemory(pi.hProcess, (void*)entryPoint, (void*)&entryData, sizeof entryData, NULL);
|
||||
WriteProcessMemory(pi.hProcess, (void*)entryPoint, (void*)&entryHook, sizeof entryHook, NULL);
|
||||
|
||||
ContinueDebugEvent(event.dwProcessId, event.dwThreadId, DBG_CONTINUE);
|
||||
continue;
|
||||
}
|
||||
|
||||
ContinueDebugEvent(event.dwProcessId, event.dwThreadId, DBG_CONTINUE);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
#endif
|
@ -1,7 +1,7 @@
|
||||
namespace SNES {
|
||||
namespace Info {
|
||||
static const char Name[] = "bsnes";
|
||||
static const char Version[] = "080.02";
|
||||
static const char Version[] = "080.03";
|
||||
static const unsigned SerializerVersion = 21;
|
||||
}
|
||||
}
|
||||
|
@ -5,6 +5,7 @@
|
||||
#include <nall/directory.hpp>
|
||||
#include <nall/filemap.hpp>
|
||||
#include <nall/input.hpp>
|
||||
#include <nall/resource.hpp>
|
||||
#include <nall/ups.hpp>
|
||||
#include <nall/snes/cartridge.hpp>
|
||||
#include <nall/gameboy/cartridge.hpp>
|
||||
|
37
bsnes/ui/general/about-window.cpp
Executable file
37
bsnes/ui/general/about-window.cpp
Executable file
@ -0,0 +1,37 @@
|
||||
#include <data/bsnes-logo.hpp>
|
||||
|
||||
AboutWindow aboutWindow;
|
||||
|
||||
void AboutWindow::create() {
|
||||
application.addWindow(this, "AboutWindow", "160,160");
|
||||
setTitle("About bsnes ...");
|
||||
setResizable(false);
|
||||
setBackgroundColor(255, 255, 255);
|
||||
|
||||
information.setText({
|
||||
"bsnes v", SNES::Info::Version, " ~ Profile: ", SNES::Info::Profile,
|
||||
" ~ Author: byuu ~ Website: http://byuu.org/"
|
||||
});
|
||||
|
||||
layout.setMargin(5);
|
||||
layout.append(canvas, 720, 180);
|
||||
informationLayout.append(spacer, ~0, 0);
|
||||
informationLayout.append(information, 0, 0);
|
||||
layout.append(informationLayout);
|
||||
append(layout);
|
||||
setGeometry({ 0, 0, layout.minimumGeometry().width, layout.minimumGeometry().height });
|
||||
}
|
||||
|
||||
void AboutWindow::show() {
|
||||
logo.decode(bsnesLogoData, bsnesLogoSize);
|
||||
setVisible();
|
||||
uint32_t *buffer = canvas.buffer();
|
||||
for(unsigned y = 0; y < 180; y++) {
|
||||
uint8_t *p = logo.data + 0x36 + (180 - 1 - y) * 720 * 3;
|
||||
for(unsigned x = 0; x < 720; x++) {
|
||||
*buffer++ = (p[0] << 0) | (p[1] << 8) | (p[2] << 16);
|
||||
p += 3;
|
||||
}
|
||||
}
|
||||
canvas.update();
|
||||
}
|
15
bsnes/ui/general/about-window.hpp
Executable file
15
bsnes/ui/general/about-window.hpp
Executable file
@ -0,0 +1,15 @@
|
||||
struct AboutWindow : TopLevelWindow {
|
||||
VerticalLayout layout;
|
||||
Canvas canvas;
|
||||
HorizontalLayout informationLayout;
|
||||
Widget spacer;
|
||||
Label information;
|
||||
|
||||
void create();
|
||||
void show();
|
||||
|
||||
private:
|
||||
resource logo;
|
||||
};
|
||||
|
||||
extern AboutWindow aboutWindow;
|
@ -3,3 +3,4 @@
|
||||
#include "file-browser.cpp"
|
||||
#include "slot-loader.cpp"
|
||||
#include "nss-dip-window.cpp"
|
||||
#include "about-window.cpp"
|
||||
|
@ -2,3 +2,4 @@
|
||||
#include "file-browser.hpp"
|
||||
#include "slot-loader.hpp"
|
||||
#include "nss-dip-window.hpp"
|
||||
#include "about-window.hpp"
|
||||
|
@ -362,13 +362,7 @@ void MainWindow::create() {
|
||||
#endif
|
||||
|
||||
helpAbout.onTick = []() {
|
||||
MessageWindow::information(mainWindow, {
|
||||
"bsnes\n\n",
|
||||
"Version: ", SNES::Info::Version, "\n",
|
||||
"Profile: ", SNES::Info::Profile, "\n",
|
||||
"Author: byuu\n",
|
||||
"Homepage: http://byuu.org/"
|
||||
});
|
||||
aboutWindow.show();
|
||||
};
|
||||
|
||||
onClose = []() {
|
||||
|
@ -55,6 +55,7 @@ void Application::main(int argc, char **argv) {
|
||||
singleSlotLoader.create();
|
||||
doubleSlotLoader.create();
|
||||
nssDipWindow.create();
|
||||
aboutWindow.create();
|
||||
videoSettings.create();
|
||||
audioSettings.create();
|
||||
inputSettings.create();
|
||||
|
Loading…
Reference in New Issue
Block a user