mirror of
https://github.com/bsnes-emu/bsnes.git
synced 2025-09-14 18:42:13 +02:00
Compare commits
9 Commits
Author | SHA1 | Date | |
---|---|---|---|
|
064ca4c626 | ||
|
10906d8418 | ||
|
e88ab60663 | ||
|
564e38ea9f | ||
|
0c3f0834ab | ||
|
f38af85e0a | ||
|
8276700381 | ||
|
ec69109c0b | ||
|
8ae6444af7 |
@@ -1,11 +1,11 @@
|
||||
include nall/Makefile
|
||||
snes := snes
|
||||
gameboy := gameboy
|
||||
profile := compatibility
|
||||
profile := accuracy
|
||||
ui := ui
|
||||
# phoenix := gtk
|
||||
|
||||
# debugger
|
||||
options :=
|
||||
# options += debugger
|
||||
|
||||
# compiler
|
||||
c := $(compiler) -std=gnu99
|
||||
|
1228
bsnes/data/bsnes-logo.hpp
Executable file
1228
bsnes/data/bsnes-logo.hpp
Executable file
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
@@ -54,6 +54,10 @@ namespace nall {
|
||||
operator[](buffersize) = data;
|
||||
}
|
||||
|
||||
void remove() {
|
||||
if(size > 0) resize(size - 1); //remove last element only
|
||||
}
|
||||
|
||||
template<typename U> void insert(unsigned index, const U list) {
|
||||
unsigned listsize = container_size(list);
|
||||
resize(buffersize + listsize);
|
||||
@@ -133,6 +137,12 @@ namespace nall {
|
||||
if(index >= buffersize) throw "array[] out of bounds";
|
||||
return pool[index];
|
||||
}
|
||||
|
||||
//iteration
|
||||
T* begin() { return &pool[0]; }
|
||||
T* end() { return &pool[buffersize]; }
|
||||
const T* begin() const { return &pool[0]; }
|
||||
const T* end() const { return &pool[buffersize]; }
|
||||
};
|
||||
|
||||
template<typename T> struct has_size<array<T>> { enum { value = true }; };
|
||||
|
@@ -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];
|
||||
}
|
||||
|
101
bsnes/nall/bmp.hpp
Executable file
101
bsnes/nall/bmp.hpp
Executable file
@@ -0,0 +1,101 @@
|
||||
#ifndef NALL_BMP_HPP
|
||||
#define NALL_BMP_HPP
|
||||
|
||||
#include <nall/file.hpp>
|
||||
|
||||
//BMP reader / writer
|
||||
//author: byuu
|
||||
//note: only 24-bit RGB and 32-bit ARGB uncompressed images supported
|
||||
|
||||
namespace nall {
|
||||
|
||||
struct bmp {
|
||||
inline static bool read(const string &filename, uint32_t *&data, unsigned &width, unsigned &height);
|
||||
inline static bool write(const string &filename, const uint32_t *data, unsigned width, unsigned height, unsigned pitch, bool alpha = false);
|
||||
};
|
||||
|
||||
bool bmp::read(const string &filename, uint32_t *&data, unsigned &width, unsigned &height) {
|
||||
file fp;
|
||||
if(fp.open(filename, file::mode::read) == false) return false;
|
||||
if(fp.size() < 0x36) return false;
|
||||
|
||||
if(fp.readm(2) != 0x424d) return false;
|
||||
fp.seek(0x000a);
|
||||
unsigned offset = fp.readl(4);
|
||||
unsigned dibsize = fp.readl(4);
|
||||
if(dibsize != 40) return false;
|
||||
signed headerWidth = fp.readl(4);
|
||||
if(headerWidth < 0) return false;
|
||||
signed headerHeight = fp.readl(4);
|
||||
fp.readl(2);
|
||||
unsigned bitsPerPixel = fp.readl(2);
|
||||
if(bitsPerPixel != 24 && bitsPerPixel != 32) return false;
|
||||
unsigned compression = fp.readl(4);
|
||||
if(compression != 0) return false;
|
||||
fp.seek(offset);
|
||||
|
||||
bool noFlip = headerHeight < 0;
|
||||
width = headerWidth, height = abs(headerHeight);
|
||||
data = new uint32_t[width * height];
|
||||
|
||||
unsigned bytesPerPixel = bitsPerPixel / 8;
|
||||
unsigned alignedWidth = width * bytesPerPixel;
|
||||
unsigned paddingLength = 0;
|
||||
while(alignedWidth % 4) alignedWidth++, paddingLength++;
|
||||
|
||||
for(unsigned y = 0; y < height; y++) {
|
||||
uint32_t *p = noFlip ? data + y * width : data + (height - 1 - y) * width;
|
||||
for(unsigned x = 0; x < width; x++, p++) {
|
||||
*p = fp.readl(bytesPerPixel);
|
||||
if(bytesPerPixel == 3) *p |= 255 << 24;
|
||||
}
|
||||
if(paddingLength) fp.readl(paddingLength);
|
||||
}
|
||||
|
||||
fp.close();
|
||||
return true;
|
||||
}
|
||||
|
||||
bool bmp::write(const string &filename, const uint32_t *data, unsigned width, unsigned height, unsigned pitch, bool alpha) {
|
||||
file fp;
|
||||
if(fp.open(filename, file::mode::write) == false) return false;
|
||||
|
||||
unsigned bitsPerPixel = alpha ? 32 : 24;
|
||||
unsigned bytesPerPixel = bitsPerPixel / 8;
|
||||
unsigned alignedWidth = width * bytesPerPixel;
|
||||
unsigned paddingLength = 0;
|
||||
unsigned imageSize = alignedWidth * height;
|
||||
unsigned fileSize = 0x36 + imageSize;
|
||||
while(alignedWidth % 4) alignedWidth++, paddingLength++;
|
||||
|
||||
fp.writem(0x424d, 2); //signature
|
||||
fp.writel(fileSize, 4); //file size
|
||||
fp.writel(0, 2); //reserved
|
||||
fp.writel(0, 2); //reserved
|
||||
fp.writel(0x36, 4); //offset
|
||||
|
||||
fp.writel(40, 4); //DIB size
|
||||
fp.writel(width, 4); //width
|
||||
fp.writel(-height, 4); //height
|
||||
fp.writel(1, 2); //color planes
|
||||
fp.writel(bitsPerPixel, 2); //bits per pixel
|
||||
fp.writel(0, 4); //compression method (BI_RGB)
|
||||
fp.writel(imageSize, 4); //image data size
|
||||
fp.writel(3780, 4); //horizontal resolution
|
||||
fp.writel(3780, 4); //vertical resolution
|
||||
fp.writel(0, 4); //palette size
|
||||
fp.writel(0, 4); //important color count
|
||||
|
||||
for(unsigned y = 0; y < height; y++) {
|
||||
const uint32_t *p = (const uint32_t*)((const uint8_t*)data + y * pitch);
|
||||
for(unsigned x = 0; x < width; x++) fp.writel(*p++, bytesPerPixel);
|
||||
if(paddingLength) fp.writel(0, paddingLength);
|
||||
}
|
||||
|
||||
fp.close();
|
||||
return true;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
#endif
|
79
bsnes/nall/compositor.hpp
Executable file
79
bsnes/nall/compositor.hpp
Executable file
@@ -0,0 +1,79 @@
|
||||
#ifndef NALL_COMPOSITOR_HPP
|
||||
#define NALL_COMPOSITOR_HPP
|
||||
|
||||
#include <nall/detect.hpp>
|
||||
|
||||
namespace nall {
|
||||
|
||||
struct compositor {
|
||||
inline static bool enabled();
|
||||
inline static bool enable(bool status);
|
||||
};
|
||||
|
||||
#if defined(PLATFORM_X)
|
||||
|
||||
bool compositor::enabled() {
|
||||
FILE *fp = popen("xfconf-query -c xfwm4 -p '/general/use_compositing'", "r");
|
||||
if(fp == 0) return false;
|
||||
|
||||
char buffer[512];
|
||||
if(fgets(buffer, sizeof buffer, fp) == 0) return false;
|
||||
|
||||
if(!memcmp(buffer, "true", 4)) return true;
|
||||
return false;
|
||||
}
|
||||
|
||||
bool compositor::enable(bool status) {
|
||||
FILE *fp;
|
||||
if(status) {
|
||||
fp = popen("xfconf-query -c xfwm4 -p '/general/use_compositing' -t 'bool' -s 'true'", "r");
|
||||
} else {
|
||||
fp = popen("xfconf-query -c xfwm4 -p '/general/use_compositing' -t 'bool' -s 'false'", "r");
|
||||
}
|
||||
if(fp == 0) return false;
|
||||
pclose(fp);
|
||||
return true;
|
||||
}
|
||||
|
||||
#elif defined(PLATFORM_WIN)
|
||||
|
||||
bool compositor::enabled() {
|
||||
HMODULE module = GetModuleHandleW(L"dwmapi");
|
||||
if(module == 0) module = LoadLibraryW(L"dwmapi");
|
||||
if(module == 0) return false;
|
||||
|
||||
auto pDwmIsCompositionEnabled = (HRESULT (WINAPI*)(BOOL*))GetProcAddress(module, "DwmIsCompositionEnabled");
|
||||
if(pDwmIsCompositionEnabled == 0) return false;
|
||||
|
||||
BOOL result;
|
||||
if(pDwmIsCompositionEnabled(&result) != S_OK) return false;
|
||||
return result;
|
||||
}
|
||||
|
||||
bool compositor::enable(bool status) {
|
||||
HMODULE module = GetModuleHandleW(L"dwmapi");
|
||||
if(module == 0) module = LoadLibraryW(L"dwmapi");
|
||||
if(module == 0) return false;
|
||||
|
||||
auto pDwmEnableComposition = (HRESULT (WINAPI*)(UINT))GetProcAddress(module, "DwmEnableComposition");
|
||||
if(pDwmEnableComposition == 0) return false;
|
||||
|
||||
if(pDwmEnableComposition(status) != S_OK) return false;
|
||||
return true;
|
||||
}
|
||||
|
||||
#else
|
||||
|
||||
bool compositor::enabled() {
|
||||
return false;
|
||||
}
|
||||
|
||||
bool compositor::enable(bool) {
|
||||
return false;
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
}
|
||||
|
||||
#endif
|
@@ -34,11 +34,11 @@ namespace nall {
|
||||
|
||||
string get() const {
|
||||
switch(type) {
|
||||
case boolean_t: return string() << *(bool*)data;
|
||||
case signed_t: return string() << *(signed*)data;
|
||||
case unsigned_t: return string() << *(unsigned*)data;
|
||||
case double_t: return string() << *(double*)data;
|
||||
case string_t: return string() << "\"" << *(string*)data << "\"";
|
||||
case boolean_t: return { *(bool*)data };
|
||||
case signed_t: return { *(signed*)data };
|
||||
case unsigned_t: return { *(unsigned*)data };
|
||||
case double_t: return { *(double*)data };
|
||||
case string_t: return { "\"", *(string*)data, "\"" };
|
||||
}
|
||||
return "???";
|
||||
}
|
||||
@@ -105,9 +105,9 @@ namespace nall {
|
||||
if(fp.open(filename, file::mode::write)) {
|
||||
for(unsigned i = 0; i < list.size(); i++) {
|
||||
string output;
|
||||
output << list[i].name << " = " << list[i].get();
|
||||
if(list[i].desc != "") output << " # " << list[i].desc;
|
||||
output << "\r\n";
|
||||
output.append(list[i].name, " = ", list[i].get());
|
||||
if(list[i].desc != "") output.append(" # ", list[i].desc);
|
||||
output.append("\r\n");
|
||||
fp.print(output);
|
||||
}
|
||||
|
||||
|
@@ -1,75 +0,0 @@
|
||||
#ifndef NALL_DICTIONARY_HPP
|
||||
#define NALL_DICTIONARY_HPP
|
||||
|
||||
#include <nall/array.hpp>
|
||||
#include <nall/string.hpp>
|
||||
#include <nall/utility.hpp>
|
||||
|
||||
namespace nall {
|
||||
class dictionary {
|
||||
public:
|
||||
string operator[](const char *input) {
|
||||
for(unsigned i = 0; i < index_input.size(); i++) {
|
||||
if(index_input[i] == input) return index_output[i];
|
||||
}
|
||||
|
||||
//no match, use input; remove input identifier, if one exists
|
||||
if(strbegin(input, "{{")) {
|
||||
if(auto pos = strpos(input, "}}")) {
|
||||
string temp = substr(input, pos() + 2);
|
||||
return temp;
|
||||
}
|
||||
}
|
||||
|
||||
return input;
|
||||
}
|
||||
|
||||
bool import(const char *filename) {
|
||||
string data;
|
||||
if(data.readfile(filename) == false) return false;
|
||||
data.ltrim<1>("\xef\xbb\xbf"); //remove UTF-8 marker, if it exists
|
||||
data.replace("\r", "");
|
||||
|
||||
lstring line;
|
||||
line.split("\n", data);
|
||||
for(unsigned i = 0; i < line.size(); i++) {
|
||||
lstring part;
|
||||
//format: "Input" = "Output"
|
||||
part.qsplit("=", line[i]);
|
||||
if(part.size() != 2) continue;
|
||||
|
||||
//remove whitespace
|
||||
part[0].trim();
|
||||
part[1].trim();
|
||||
|
||||
//remove quotes
|
||||
part[0].trim<1>("\"");
|
||||
part[1].trim<1>("\"");
|
||||
|
||||
unsigned n = index_input.size();
|
||||
index_input[n] = part[0];
|
||||
index_output[n] = part[1];
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void reset() {
|
||||
index_input.reset();
|
||||
index_output.reset();
|
||||
}
|
||||
|
||||
~dictionary() {
|
||||
reset();
|
||||
}
|
||||
|
||||
dictionary& operator=(const dictionary&) = delete;
|
||||
dictionary(const dictionary&) = delete;
|
||||
|
||||
protected:
|
||||
lstring index_input;
|
||||
lstring index_output;
|
||||
};
|
||||
}
|
||||
|
||||
#endif
|
@@ -6,7 +6,7 @@
|
||||
#include <nall/string.hpp>
|
||||
|
||||
#if defined(_WIN32)
|
||||
#include <nall/utf8.hpp>
|
||||
#include <nall/windows/utf8.hpp>
|
||||
#else
|
||||
#include <dirent.h>
|
||||
#include <stdio.h>
|
||||
|
@@ -12,7 +12,7 @@
|
||||
#include <dlfcn.h>
|
||||
#elif defined(PLATFORM_WIN)
|
||||
#include <windows.h>
|
||||
#include <nall/utf8.hpp>
|
||||
#include <nall/windows/utf8.hpp>
|
||||
#endif
|
||||
|
||||
namespace nall {
|
||||
|
@@ -4,11 +4,11 @@
|
||||
#include <nall/platform.hpp>
|
||||
#include <nall/stdint.hpp>
|
||||
#include <nall/string.hpp>
|
||||
#include <nall/utf8.hpp>
|
||||
#include <nall/utility.hpp>
|
||||
#include <nall/windows/utf8.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
|
||||
@@ -22,6 +22,24 @@ namespace nall {
|
||||
enum class index : unsigned { absolute, relative };
|
||||
enum class time : unsigned { create, modify, access };
|
||||
|
||||
static bool read(const string &filename, uint8_t *&data, unsigned &size) {
|
||||
file fp;
|
||||
if(fp.open(filename, mode::read) == false) return false;
|
||||
size = fp.size();
|
||||
data = new uint8_t[size];
|
||||
fp.read(data, size);
|
||||
fp.close();
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool write(const string &filename, const uint8_t *data, unsigned size) {
|
||||
file fp;
|
||||
if(fp.open(filename, mode::write) == false) return false;
|
||||
fp.write(data, size);
|
||||
fp.close();
|
||||
return true;
|
||||
}
|
||||
|
||||
uint8_t read() {
|
||||
if(!fp) return 0xff; //file not open
|
||||
if(file_mode == mode::write) return 0xff; //reads not permitted
|
||||
@@ -135,7 +153,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 +163,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 +174,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 +193,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,7 +2,7 @@
|
||||
#define NALL_FILEMAP_HPP
|
||||
|
||||
#include <nall/stdint.hpp>
|
||||
#include <nall/utf8.hpp>
|
||||
#include <nall/windows/utf8.hpp>
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
|
@@ -86,17 +86,17 @@ GameBoyCartridge::GameBoyCartridge(const uint8_t *romdata, unsigned romsize) {
|
||||
|
||||
if(info.mapper == "MBC2") info.ramsize = 512; //512 x 4-bit
|
||||
|
||||
xml << "<cartridge mapper='" << info.mapper << "'";
|
||||
if(info.rtc) xml << " rtc='true'";
|
||||
if(info.rumble) xml << " rumble='true'";
|
||||
xml << ">\n";
|
||||
xml.append("<cartridge mapper='", info.mapper, "'");
|
||||
if(info.rtc) xml.append(" rtc='true'");
|
||||
if(info.rumble) xml.append(" rumble='true'");
|
||||
xml.append(">\n");
|
||||
|
||||
xml << " <rom size='" << hex(romsize) << "'/>\n"; //TODO: trust/check info.romsize?
|
||||
xml.append(" <rom size='", hex(romsize), "'/>\n"); //TODO: trust/check info.romsize?
|
||||
|
||||
if(info.ramsize > 0)
|
||||
xml << " <ram size='" << hex(info.ramsize) << "' battery='" << info.battery << "'/>\n";
|
||||
xml.append(" <ram size='", hex(info.ramsize), "' battery='", info.battery, "'/>\n");
|
||||
|
||||
xml << "</cartridge>\n";
|
||||
xml.append("</cartridge>\n");
|
||||
xml.transform("'", "\"");
|
||||
}
|
||||
|
||||
|
87
bsnes/nall/gzip.hpp
Executable file
87
bsnes/nall/gzip.hpp
Executable file
@@ -0,0 +1,87 @@
|
||||
#ifndef NALL_GZIP_HPP
|
||||
#define NALL_GZIP_HPP
|
||||
|
||||
#include <nall/file.hpp>
|
||||
#include <nall/inflate.hpp>
|
||||
|
||||
namespace nall {
|
||||
|
||||
struct gzip {
|
||||
string filename;
|
||||
uint8_t *data;
|
||||
unsigned size;
|
||||
|
||||
bool decompress(const string &filename);
|
||||
bool decompress(const uint8_t *data, unsigned size);
|
||||
|
||||
gzip();
|
||||
~gzip();
|
||||
};
|
||||
|
||||
bool gzip::decompress(const string &filename) {
|
||||
uint8_t *data;
|
||||
unsigned size;
|
||||
if(file::read(filename, data, size) == false) return false;
|
||||
bool result = decompress(data, size);
|
||||
delete[] data;
|
||||
return result;
|
||||
}
|
||||
|
||||
bool gzip::decompress(const uint8_t *data, unsigned size) {
|
||||
if(size < 18) return false;
|
||||
if(data[0] != 0x1f) return false;
|
||||
if(data[1] != 0x8b) return false;
|
||||
unsigned cm = data[2];
|
||||
unsigned flg = data[3];
|
||||
unsigned mtime = data[4];
|
||||
mtime |= data[5] << 8;
|
||||
mtime |= data[6] << 16;
|
||||
mtime |= data[7] << 24;
|
||||
unsigned xfl = data[8];
|
||||
unsigned os = data[9];
|
||||
unsigned p = 10;
|
||||
unsigned isize = data[size - 4];
|
||||
isize |= data[size - 3] << 8;
|
||||
isize |= data[size - 2] << 16;
|
||||
isize |= data[size - 1] << 24;
|
||||
filename = "";
|
||||
|
||||
if(flg & 0x04) { //FEXTRA
|
||||
unsigned xlen = data[p + 0];
|
||||
xlen |= data[p + 1] << 8;
|
||||
p += 2 + xlen;
|
||||
}
|
||||
|
||||
if(flg & 0x08) { //FNAME
|
||||
char buffer[PATH_MAX];
|
||||
for(unsigned n = 0; n < PATH_MAX; n++, p++) {
|
||||
buffer[n] = data[p];
|
||||
if(data[p] == 0) break;
|
||||
}
|
||||
if(data[p++]) return false;
|
||||
filename = buffer;
|
||||
}
|
||||
|
||||
if(flg & 0x10) { //FCOMMENT
|
||||
while(data[p++]);
|
||||
}
|
||||
|
||||
if(flg & 0x02) { //FHCRC
|
||||
p += 2;
|
||||
}
|
||||
|
||||
this->size = isize;
|
||||
this->data = new uint8_t[this->size];
|
||||
return inflate(this->data, this->size, data + p, size - p - 8);
|
||||
}
|
||||
|
||||
gzip::gzip() : data(0) {
|
||||
}
|
||||
|
||||
gzip::~gzip() {
|
||||
if(data) delete[] data;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
#endif
|
176
bsnes/nall/http.hpp
Executable file
176
bsnes/nall/http.hpp
Executable file
@@ -0,0 +1,176 @@
|
||||
#ifndef NALL_HTTP_HPP
|
||||
#define NALL_HTTP_HPP
|
||||
|
||||
#if !defined(_WIN32)
|
||||
#include <sys/types.h>
|
||||
#include <sys/socket.h>
|
||||
#include <netinet/in.h>
|
||||
#include <netdb.h>
|
||||
#else
|
||||
#include <windows.h>
|
||||
#include <winsock2.h>
|
||||
#include <ws2tcpip.h>
|
||||
#endif
|
||||
|
||||
#include <nall/platform.hpp>
|
||||
#include <nall/string.hpp>
|
||||
|
||||
namespace nall {
|
||||
|
||||
struct http {
|
||||
string hostname;
|
||||
addrinfo *serverinfo;
|
||||
int serversocket;
|
||||
string header;
|
||||
|
||||
inline void download(const string &path, uint8_t *&data, unsigned &size) {
|
||||
data = 0;
|
||||
size = 0;
|
||||
|
||||
send({
|
||||
"GET ", path, " HTTP/1.1\r\n"
|
||||
"Host: ", hostname, "\r\n"
|
||||
"Connection: close\r\n"
|
||||
"\r\n"
|
||||
});
|
||||
|
||||
header = downloadHeader();
|
||||
downloadContent(data, size);
|
||||
}
|
||||
|
||||
inline bool connect(string host, unsigned port) {
|
||||
hostname = host;
|
||||
|
||||
addrinfo hints;
|
||||
memset(&hints, 0, sizeof(addrinfo));
|
||||
hints.ai_family = AF_UNSPEC;
|
||||
hints.ai_socktype = SOCK_STREAM;
|
||||
hints.ai_flags = AI_PASSIVE;
|
||||
|
||||
int status = getaddrinfo(hostname, string(port), &hints, &serverinfo);
|
||||
if(status != 0) return false;
|
||||
|
||||
serversocket = socket(serverinfo->ai_family, serverinfo->ai_socktype, serverinfo->ai_protocol);
|
||||
if(serversocket == -1) return false;
|
||||
|
||||
int result = ::connect(serversocket, serverinfo->ai_addr, serverinfo->ai_addrlen);
|
||||
if(result == -1) return false;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
inline bool send(const string &data) {
|
||||
return send((const uint8_t*)(const char*)data, data.length());
|
||||
}
|
||||
|
||||
inline bool send(const uint8_t *data, unsigned size) {
|
||||
while(size) {
|
||||
int length = ::send(serversocket, (const char*)data, size, 0);
|
||||
if(length == -1) return false;
|
||||
data += length;
|
||||
size -= length;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
inline string downloadHeader() {
|
||||
string output;
|
||||
do {
|
||||
char buffer[2];
|
||||
int length = recv(serversocket, buffer, 1, 0);
|
||||
if(length <= 0) return output;
|
||||
buffer[1] = 0;
|
||||
output.append(buffer);
|
||||
} while(output.endswith("\r\n\r\n") == false);
|
||||
return output;
|
||||
}
|
||||
|
||||
inline string downloadChunkLength() {
|
||||
string output;
|
||||
do {
|
||||
char buffer[2];
|
||||
int length = recv(serversocket, buffer, 1, 0);
|
||||
if(length <= 0) return output;
|
||||
buffer[1] = 0;
|
||||
output.append(buffer);
|
||||
} while(output.endswith("\r\n") == false);
|
||||
return output;
|
||||
}
|
||||
|
||||
inline void downloadContent(uint8_t *&data, unsigned &size) {
|
||||
unsigned capacity = 0;
|
||||
|
||||
if(header.iposition("\r\nTransfer-Encoding: chunked\r\n")) {
|
||||
while(true) {
|
||||
unsigned length = hex(downloadChunkLength());
|
||||
if(length == 0) break;
|
||||
capacity += length;
|
||||
data = (uint8_t*)realloc(data, capacity);
|
||||
|
||||
char buffer[length];
|
||||
while(length) {
|
||||
int packetlength = recv(serversocket, buffer, length, 0);
|
||||
if(packetlength <= 0) break;
|
||||
memcpy(data + size, buffer, packetlength);
|
||||
size += packetlength;
|
||||
length -= packetlength;
|
||||
}
|
||||
}
|
||||
} else if(auto position = header.iposition("\r\nContent-Length: ")) {
|
||||
unsigned length = decimal((const char*)header + position() + 16);
|
||||
while(length) {
|
||||
char buffer[256];
|
||||
int packetlength = recv(serversocket, buffer, min(256, length), 0);
|
||||
if(packetlength <= 0) break;
|
||||
capacity += packetlength;
|
||||
data = (uint8_t*)realloc(data, capacity);
|
||||
memcpy(data + size, buffer, packetlength);
|
||||
size += packetlength;
|
||||
length -= packetlength;
|
||||
}
|
||||
} else {
|
||||
while(true) {
|
||||
char buffer[256];
|
||||
int packetlength = recv(serversocket, buffer, 256, 0);
|
||||
if(packetlength <= 0) break;
|
||||
capacity += packetlength;
|
||||
data = (uint8_t*)realloc(data, capacity);
|
||||
memcpy(data + size, buffer, packetlength);
|
||||
size += packetlength;
|
||||
}
|
||||
}
|
||||
|
||||
data = (uint8_t*)realloc(data, capacity + 1);
|
||||
data[capacity] = 0;
|
||||
}
|
||||
|
||||
inline void disconnect() {
|
||||
close(serversocket);
|
||||
freeaddrinfo(serverinfo);
|
||||
serverinfo = 0;
|
||||
serversocket = -1;
|
||||
}
|
||||
|
||||
#ifdef _WIN32
|
||||
inline int close(int sock) {
|
||||
return closesocket(sock);
|
||||
}
|
||||
|
||||
inline http() {
|
||||
int sock = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
|
||||
if(sock == INVALID_SOCKET && WSAGetLastError() == WSANOTINITIALISED) {
|
||||
WSADATA wsaData;
|
||||
if(WSAStartup(MAKEWORD(2, 2), &wsaData) != 0) {
|
||||
WSACleanup();
|
||||
return;
|
||||
}
|
||||
} else {
|
||||
close(sock);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
#endif
|
358
bsnes/nall/inflate.hpp
Executable file
358
bsnes/nall/inflate.hpp
Executable file
@@ -0,0 +1,358 @@
|
||||
#ifndef NALL_INFLATE_HPP
|
||||
#define NALL_INFLATE_HPP
|
||||
|
||||
#include <setjmp.h>
|
||||
|
||||
namespace nall {
|
||||
|
||||
namespace puff {
|
||||
inline int puff(
|
||||
unsigned char *dest, unsigned long *destlen,
|
||||
unsigned char *source, unsigned long *sourcelen
|
||||
);
|
||||
}
|
||||
|
||||
inline bool inflate(
|
||||
uint8_t *target, unsigned targetLength,
|
||||
const uint8_t *source, unsigned sourceLength
|
||||
) {
|
||||
unsigned long tl = targetLength, sl = sourceLength;
|
||||
int result = puff::puff((unsigned char*)target, &tl, (unsigned char*)source, &sl);
|
||||
return result == 0;
|
||||
}
|
||||
|
||||
namespace puff {
|
||||
|
||||
//zlib/contrib/puff.c
|
||||
//version 2.1*
|
||||
//author: Mark Adler
|
||||
//license: zlib
|
||||
//ported by: byuu
|
||||
|
||||
//* I have corrected a bug in fixed(), where it was accessing uninitialized
|
||||
// memory: calling construct() with lencode prior to initializing lencode.count
|
||||
|
||||
enum {
|
||||
MAXBITS = 15,
|
||||
MAXLCODES = 286,
|
||||
MAXDCODES = 30,
|
||||
FIXLCODES = 288,
|
||||
MAXCODES = MAXLCODES + MAXDCODES,
|
||||
};
|
||||
|
||||
struct state {
|
||||
unsigned char *out;
|
||||
unsigned long outlen;
|
||||
unsigned long outcnt;
|
||||
|
||||
unsigned char *in;
|
||||
unsigned long inlen;
|
||||
unsigned long incnt;
|
||||
int bitbuf;
|
||||
int bitcnt;
|
||||
|
||||
jmp_buf env;
|
||||
};
|
||||
|
||||
struct huffman {
|
||||
short *count;
|
||||
short *symbol;
|
||||
};
|
||||
|
||||
inline int bits(state *s, int need) {
|
||||
long val;
|
||||
|
||||
val = s->bitbuf;
|
||||
while(s->bitcnt < need) {
|
||||
if(s->incnt == s->inlen) longjmp(s->env, 1);
|
||||
val |= (long)(s->in[s->incnt++]) << s->bitcnt;
|
||||
s->bitcnt += 8;
|
||||
}
|
||||
|
||||
s->bitbuf = (int)(val >> need);
|
||||
s->bitcnt -= need;
|
||||
|
||||
return (int)(val & ((1L << need) - 1));
|
||||
}
|
||||
|
||||
inline int stored(state *s) {
|
||||
unsigned len;
|
||||
|
||||
s->bitbuf = 0;
|
||||
s->bitcnt = 0;
|
||||
|
||||
if(s->incnt + 4 > s->inlen) return 2;
|
||||
len = s->in[s->incnt++];
|
||||
len |= s->in[s->incnt++] << 8;
|
||||
if(s->in[s->incnt++] != (~len & 0xff) ||
|
||||
s->in[s->incnt++] != ((~len >> 8) & 0xff)
|
||||
) return 2;
|
||||
|
||||
if(s->incnt + len > s->inlen) return 2;
|
||||
if(s->out != 0) {
|
||||
if(s->outcnt + len > s->outlen) return 1;
|
||||
while(len--) s->out[s->outcnt++] = s->in[s->incnt++];
|
||||
} else {
|
||||
s->outcnt += len;
|
||||
s->incnt += len;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
inline int decode(state *s, huffman *h) {
|
||||
int len, code, first, count, index, bitbuf, left;
|
||||
short *next;
|
||||
|
||||
bitbuf = s->bitbuf;
|
||||
left = s->bitcnt;
|
||||
code = first = index = 0;
|
||||
len = 1;
|
||||
next = h->count + 1;
|
||||
while(true) {
|
||||
while(left--) {
|
||||
code |= bitbuf & 1;
|
||||
bitbuf >>= 1;
|
||||
count = *next++;
|
||||
if(code - count < first) {
|
||||
s->bitbuf = bitbuf;
|
||||
s->bitcnt = (s->bitcnt - len) & 7;
|
||||
return h->symbol[index + (code - first)];
|
||||
}
|
||||
index += count;
|
||||
first += count;
|
||||
first <<= 1;
|
||||
code <<= 1;
|
||||
len++;
|
||||
}
|
||||
left = (MAXBITS + 1) - len;
|
||||
if(left == 0) break;
|
||||
if(s->incnt == s->inlen) longjmp(s->env, 1);
|
||||
bitbuf = s->in[s->incnt++];
|
||||
if(left > 8) left = 8;
|
||||
}
|
||||
|
||||
return -10;
|
||||
}
|
||||
|
||||
inline int construct(huffman *h, short *length, int n) {
|
||||
int symbol, len, left;
|
||||
short offs[MAXBITS + 1];
|
||||
|
||||
for(len = 0; len <= MAXBITS; len++) h->count[len] = 0;
|
||||
for(symbol = 0; symbol < n; symbol++) h->count[length[symbol]]++;
|
||||
if(h->count[0] == n) return 0;
|
||||
|
||||
left = 1;
|
||||
for(len = 1; len <= MAXBITS; len++) {
|
||||
left <<= 1;
|
||||
left -= h->count[len];
|
||||
if(left < 0) return left;
|
||||
}
|
||||
|
||||
offs[1] = 0;
|
||||
for(len = 1; len < MAXBITS; len++) offs[len + 1] = offs[len] + h->count[len];
|
||||
|
||||
for(symbol = 0; symbol < n; symbol++) {
|
||||
if(length[symbol] != 0) h->symbol[offs[length[symbol]]++] = symbol;
|
||||
}
|
||||
|
||||
return left;
|
||||
}
|
||||
|
||||
inline int codes(state *s, huffman *lencode, huffman *distcode) {
|
||||
int symbol, len;
|
||||
unsigned dist;
|
||||
static const short lens[29] = {
|
||||
3, 4, 5, 6, 7, 8, 9, 10, 11, 13, 15, 17, 19, 23, 27, 31,
|
||||
35, 43, 51, 59, 67, 83, 99, 115, 131, 163, 195, 227, 258
|
||||
};
|
||||
static const short lext[29] = {
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 2, 2, 2, 2,
|
||||
3, 3, 3, 3, 4, 4, 4, 4, 5, 5, 5, 5, 0
|
||||
};
|
||||
static const short dists[30] = {
|
||||
1, 2, 3, 4, 5, 7, 9, 13, 17, 25, 33, 49, 65, 97, 129, 193,
|
||||
257, 385, 513, 769, 1025, 1537, 2049, 3073, 4097, 6145,
|
||||
8193, 12289, 16385, 24577
|
||||
};
|
||||
static const short dext[30] = {
|
||||
0, 0, 0, 0, 1, 1, 2, 2, 3, 3, 4, 4, 5, 5, 6, 6,
|
||||
7, 7, 8, 8, 9, 9, 10, 10, 11, 11,
|
||||
12, 12, 13, 13
|
||||
};
|
||||
|
||||
do {
|
||||
symbol = decode(s, lencode);
|
||||
if(symbol < 0) return symbol;
|
||||
if(symbol < 256) {
|
||||
if(s->out != 0) {
|
||||
if(s->outcnt == s->outlen) return 1;
|
||||
s->out[s->outcnt] = symbol;
|
||||
}
|
||||
s->outcnt++;
|
||||
} else if(symbol > 256) {
|
||||
symbol -= 257;
|
||||
if(symbol >= 29) return -10;
|
||||
len = lens[symbol] + bits(s, lext[symbol]);
|
||||
|
||||
symbol = decode(s, distcode);
|
||||
if(symbol < 0) return symbol;
|
||||
dist = dists[symbol] + bits(s, dext[symbol]);
|
||||
#ifndef INFLATE_ALLOW_INVALID_DISTANCE_TOO_FAR
|
||||
if(dist > s->outcnt) return -11;
|
||||
#endif
|
||||
|
||||
if(s->out != 0) {
|
||||
if(s->outcnt + len > s->outlen) return 1;
|
||||
while(len--) {
|
||||
s->out[s->outcnt] =
|
||||
#ifdef INFLATE_ALLOW_INVALID_DISTANCE_TOO_FAR
|
||||
dist > s->outcnt ? 0 :
|
||||
#endif
|
||||
s->out[s->outcnt - dist];
|
||||
s->outcnt++;
|
||||
}
|
||||
} else {
|
||||
s->outcnt += len;
|
||||
}
|
||||
}
|
||||
} while(symbol != 256);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
inline int fixed(state *s) {
|
||||
static int virgin = 1;
|
||||
static short lencnt[MAXBITS + 1], lensym[FIXLCODES];
|
||||
static short distcnt[MAXBITS + 1], distsym[MAXDCODES];
|
||||
static huffman lencode, distcode;
|
||||
|
||||
if(virgin) {
|
||||
int symbol = 0;
|
||||
short lengths[FIXLCODES];
|
||||
|
||||
lencode.count = lencnt;
|
||||
lencode.symbol = lensym;
|
||||
distcode.count = distcnt;
|
||||
distcode.symbol = distsym;
|
||||
|
||||
for(; symbol < 144; symbol++) lengths[symbol] = 8;
|
||||
for(; symbol < 256; symbol++) lengths[symbol] = 9;
|
||||
for(; symbol < 280; symbol++) lengths[symbol] = 7;
|
||||
for(; symbol < FIXLCODES; symbol++) lengths[symbol] = 8;
|
||||
construct(&lencode, lengths, FIXLCODES);
|
||||
|
||||
for(symbol = 0; symbol < MAXDCODES; symbol++) lengths[symbol] = 5;
|
||||
construct(&distcode, lengths, MAXDCODES);
|
||||
|
||||
virgin = 0;
|
||||
}
|
||||
|
||||
return codes(s, &lencode, &distcode);
|
||||
}
|
||||
|
||||
inline int dynamic(state *s) {
|
||||
int nlen, ndist, ncode, index, err;
|
||||
short lengths[MAXCODES];
|
||||
short lencnt[MAXBITS + 1], lensym[MAXLCODES];
|
||||
short distcnt[MAXBITS + 1], distsym[MAXDCODES];
|
||||
huffman lencode, distcode;
|
||||
static const short order[19] = {
|
||||
16, 17, 18, 0, 8, 7, 9, 6, 10, 5, 11, 4, 12, 3, 13, 2, 14, 1, 15
|
||||
};
|
||||
|
||||
lencode.count = lencnt;
|
||||
lencode.symbol = lensym;
|
||||
distcode.count = distcnt;
|
||||
distcode.symbol = distsym;
|
||||
|
||||
nlen = bits(s, 5) + 257;
|
||||
ndist = bits(s, 5) + 1;
|
||||
ncode = bits(s, 4) + 4;
|
||||
if(nlen > MAXLCODES || ndist > MAXDCODES) return -3;
|
||||
|
||||
for(index = 0; index < ncode; index++) lengths[order[index]] = bits(s, 3);
|
||||
for(; index < 19; index++) lengths[order[index]] = 0;
|
||||
|
||||
err = construct(&lencode, lengths, 19);
|
||||
if(err != 0) return -4;
|
||||
|
||||
index = 0;
|
||||
while(index < nlen + ndist) {
|
||||
int symbol, len;
|
||||
|
||||
symbol = decode(s, &lencode);
|
||||
if(symbol < 16) {
|
||||
lengths[index++] = symbol;
|
||||
} else {
|
||||
len = 0;
|
||||
if(symbol == 16) {
|
||||
if(index == 0) return -5;
|
||||
len = lengths[index - 1];
|
||||
symbol = 3 + bits(s, 2);
|
||||
} else if(symbol == 17) {
|
||||
symbol = 3 + bits(s, 3);
|
||||
} else {
|
||||
symbol = 11 + bits(s, 7);
|
||||
}
|
||||
if(index + symbol > nlen + ndist) return -6;
|
||||
while(symbol--) lengths[index++] = len;
|
||||
}
|
||||
}
|
||||
|
||||
if(lengths[256] == 0) return -9;
|
||||
|
||||
err = construct(&lencode, lengths, nlen);
|
||||
if(err < 0 || (err > 0 && nlen - lencode.count[0] != 1)) return -7;
|
||||
|
||||
err = construct(&distcode, lengths + nlen, ndist);
|
||||
if(err < 0 || (err > 0 && ndist - distcode.count[0] != 1)) return -8;
|
||||
|
||||
return codes(s, &lencode, &distcode);
|
||||
}
|
||||
|
||||
inline int puff(
|
||||
unsigned char *dest, unsigned long *destlen,
|
||||
unsigned char *source, unsigned long *sourcelen
|
||||
) {
|
||||
state s;
|
||||
int last, type, err;
|
||||
|
||||
s.out = dest;
|
||||
s.outlen = *destlen;
|
||||
s.outcnt = 0;
|
||||
|
||||
s.in = source;
|
||||
s.inlen = *sourcelen;
|
||||
s.incnt = 0;
|
||||
s.bitbuf = 0;
|
||||
s.bitcnt = 0;
|
||||
|
||||
if(setjmp(s.env) != 0) {
|
||||
err = 2;
|
||||
} else {
|
||||
do {
|
||||
last = bits(&s, 1);
|
||||
type = bits(&s, 2);
|
||||
err = type == 0 ? stored(&s)
|
||||
: type == 1 ? fixed(&s)
|
||||
: type == 2 ? dynamic(&s)
|
||||
: -1;
|
||||
if(err != 0) break;
|
||||
} while(!last);
|
||||
}
|
||||
|
||||
if(err <= 0) {
|
||||
*destlen = s.outcnt;
|
||||
*sourcelen = s.incnt;
|
||||
}
|
||||
|
||||
return err;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
#endif
|
@@ -110,7 +110,7 @@ struct Keyboard {
|
||||
break;
|
||||
}
|
||||
}
|
||||
return string() << "KB" << ID << "::" << KeyboardScancodeName[index];
|
||||
return { "KB", ID, "::", KeyboardScancodeName[index] };
|
||||
}
|
||||
|
||||
uint16_t operator[](Scancode code) const { return Base + ID * Size + code; }
|
||||
@@ -207,7 +207,7 @@ struct Mouse {
|
||||
break;
|
||||
}
|
||||
}
|
||||
return string() << "MS" << ID << "::" << MouseScancodeName[index];
|
||||
return { "MS", ID, "::", MouseScancodeName[index] };
|
||||
}
|
||||
|
||||
uint16_t operator[](Scancode code) const { return Base + ID * Size + code; }
|
||||
@@ -330,7 +330,7 @@ struct Joypad {
|
||||
index = code - (Base + Size * i);
|
||||
}
|
||||
}
|
||||
return string() << "JP" << ID << "::" << JoypadScancodeName[index];
|
||||
return { "JP", ID, "::", JoypadScancodeName[index] };
|
||||
}
|
||||
|
||||
uint16_t operator[](Scancode code) const { return Base + ID * Size + code; }
|
||||
|
@@ -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) {
|
||||
|
@@ -5,10 +5,9 @@
|
||||
//minimum version needed for _wstat64, etc
|
||||
#undef __MSVCRT_VERSION__
|
||||
#define __MSVCRT_VERSION__ 0x0601
|
||||
#include <nall/windows/utf8.hpp>
|
||||
#endif
|
||||
|
||||
#include <nall/utf8.hpp>
|
||||
|
||||
//=========================
|
||||
//standard platform headers
|
||||
//=========================
|
||||
|
423
bsnes/nall/png.hpp
Executable file
423
bsnes/nall/png.hpp
Executable file
@@ -0,0 +1,423 @@
|
||||
#ifndef NALL_PNG_HPP
|
||||
#define NALL_PNG_HPP
|
||||
|
||||
//PNG image decoder
|
||||
//author: byuu
|
||||
|
||||
#include <nall/inflate.hpp>
|
||||
#include <nall/string.hpp>
|
||||
|
||||
namespace nall {
|
||||
|
||||
struct png {
|
||||
uint32_t *data;
|
||||
unsigned size;
|
||||
|
||||
struct Info {
|
||||
unsigned width;
|
||||
unsigned height;
|
||||
unsigned bitDepth;
|
||||
unsigned colorType;
|
||||
unsigned compressionMethod;
|
||||
unsigned filterType;
|
||||
unsigned interlaceMethod;
|
||||
|
||||
unsigned bytesPerPixel;
|
||||
unsigned pitch;
|
||||
|
||||
uint8_t palette[256][3];
|
||||
} info;
|
||||
|
||||
uint8_t *rawData;
|
||||
unsigned rawSize;
|
||||
|
||||
inline bool decode(const string &filename);
|
||||
inline bool decode(const uint8_t *sourceData, unsigned sourceSize);
|
||||
inline void transform();
|
||||
inline void alphaTransform(uint32_t rgb = 0xffffff);
|
||||
inline png();
|
||||
inline ~png();
|
||||
|
||||
protected:
|
||||
enum class FourCC : unsigned {
|
||||
IHDR = 0x49484452,
|
||||
PLTE = 0x504c5445,
|
||||
IDAT = 0x49444154,
|
||||
IEND = 0x49454e44,
|
||||
};
|
||||
|
||||
static const unsigned interlace[7][4];
|
||||
unsigned bitpos;
|
||||
|
||||
inline unsigned inflateSize();
|
||||
inline bool deinterlace(const uint8_t *&inputData, unsigned pass);
|
||||
inline bool filter(uint8_t *outputData, const uint8_t *inputData, unsigned width, unsigned height);
|
||||
inline unsigned read(const uint8_t *data, unsigned length);
|
||||
inline unsigned decode(const uint8_t *&data);
|
||||
inline unsigned readbits(const uint8_t *&data);
|
||||
inline unsigned scale(unsigned n);
|
||||
};
|
||||
|
||||
bool png::decode(const string &filename) {
|
||||
uint8_t *data;
|
||||
unsigned size;
|
||||
if(file::read(filename, data, size) == false) return false;
|
||||
bool result = decode(data, size);
|
||||
delete[] data;
|
||||
return result;
|
||||
}
|
||||
|
||||
bool png::decode(const uint8_t *sourceData, unsigned sourceSize) {
|
||||
if(sourceSize < 8) return false;
|
||||
if(read(sourceData + 0, 4) != 0x89504e47) return false;
|
||||
if(read(sourceData + 4, 4) != 0x0d0a1a0a) return false;
|
||||
|
||||
uint8_t *compressedData = 0;
|
||||
unsigned compressedSize = 0;
|
||||
|
||||
unsigned offset = 8;
|
||||
while(offset < sourceSize) {
|
||||
unsigned length = read(sourceData + offset + 0, 4);
|
||||
unsigned fourCC = read(sourceData + offset + 4, 4);
|
||||
unsigned checksum = read(sourceData + offset + 8 + length, 4);
|
||||
|
||||
if(fourCC == (unsigned)FourCC::IHDR) {
|
||||
info.width = read(sourceData + offset + 8, 4);
|
||||
info.height = read(sourceData + offset + 12, 4);
|
||||
info.bitDepth = read(sourceData + offset + 16, 1);
|
||||
info.colorType = read(sourceData + offset + 17, 1);
|
||||
info.compressionMethod = read(sourceData + offset + 18, 1);
|
||||
info.filterType = read(sourceData + offset + 19, 1);
|
||||
info.interlaceMethod = read(sourceData + offset + 20, 1);
|
||||
|
||||
if(info.bitDepth == 0 || info.bitDepth > 16) return false;
|
||||
if(info.bitDepth & (info.bitDepth - 1)) return false; //not a power of two
|
||||
if(info.compressionMethod != 0) return false;
|
||||
if(info.filterType != 0) return false;
|
||||
if(info.interlaceMethod != 0 && info.interlaceMethod != 1) return false;
|
||||
|
||||
switch(info.colorType) {
|
||||
case 0: info.bytesPerPixel = info.bitDepth * 1; break; //L
|
||||
case 2: info.bytesPerPixel = info.bitDepth * 3; break; //R,G,B
|
||||
case 3: info.bytesPerPixel = info.bitDepth * 1; break; //P
|
||||
case 4: info.bytesPerPixel = info.bitDepth * 2; break; //L,A
|
||||
case 6: info.bytesPerPixel = info.bitDepth * 4; break; //R,G,B,A
|
||||
default: return false;
|
||||
}
|
||||
|
||||
if(info.colorType == 2 || info.colorType == 4 || info.colorType == 6)
|
||||
if(info.bitDepth != 8 && info.bitDepth != 16) return false;
|
||||
if(info.colorType == 3 && info.bitDepth == 16) return false;
|
||||
|
||||
info.bytesPerPixel = (info.bytesPerPixel + 7) / 8;
|
||||
info.pitch = (int)info.width * info.bytesPerPixel;
|
||||
}
|
||||
|
||||
if(fourCC == (unsigned)FourCC::PLTE) {
|
||||
if(length % 3) return false;
|
||||
for(unsigned n = 0, p = offset + 8; n < length / 3; n++) {
|
||||
info.palette[n][0] = sourceData[p++];
|
||||
info.palette[n][1] = sourceData[p++];
|
||||
info.palette[n][2] = sourceData[p++];
|
||||
}
|
||||
}
|
||||
|
||||
if(fourCC == (unsigned)FourCC::IDAT) {
|
||||
compressedData = (uint8_t*)realloc(compressedData, compressedSize + length);
|
||||
memcpy(compressedData + compressedSize, sourceData + offset + 8, length);
|
||||
compressedSize += length;
|
||||
}
|
||||
|
||||
if(fourCC == (unsigned)FourCC::IEND) {
|
||||
break;
|
||||
}
|
||||
|
||||
offset += 4 + 4 + length + 4;
|
||||
}
|
||||
|
||||
unsigned interlacedSize = inflateSize();
|
||||
uint8_t *interlacedData = new uint8_t[interlacedSize];
|
||||
|
||||
bool result = inflate(interlacedData, interlacedSize, compressedData + 2, compressedSize - 6);
|
||||
delete[] compressedData;
|
||||
|
||||
if(result == false) {
|
||||
delete[] interlacedData;
|
||||
return false;
|
||||
}
|
||||
|
||||
rawSize = info.width * info.height * info.bytesPerPixel;
|
||||
rawData = new uint8_t[rawSize];
|
||||
|
||||
if(info.interlaceMethod == 0) {
|
||||
if(filter(rawData, interlacedData, info.width, info.height) == false) {
|
||||
delete[] interlacedData;
|
||||
delete[] rawData;
|
||||
rawData = 0;
|
||||
return false;
|
||||
}
|
||||
} else {
|
||||
const uint8_t *passData = interlacedData;
|
||||
for(unsigned pass = 0; pass < 7; pass++) {
|
||||
if(deinterlace(passData, pass) == false) {
|
||||
delete[] interlacedData;
|
||||
delete[] rawData;
|
||||
rawData = 0;
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
delete[] interlacedData;
|
||||
return true;
|
||||
}
|
||||
|
||||
const unsigned png::interlace[7][4] = {
|
||||
//x-distance, y-distance, x-origin, y-origin
|
||||
{ 8, 8, 0, 0 },
|
||||
{ 8, 8, 4, 0 },
|
||||
{ 4, 8, 0, 4 },
|
||||
{ 4, 4, 2, 0 },
|
||||
{ 2, 4, 0, 2 },
|
||||
{ 2, 2, 1, 0 },
|
||||
{ 1, 2, 0, 1 },
|
||||
};
|
||||
|
||||
unsigned png::inflateSize() {
|
||||
if(info.interlaceMethod == 0) {
|
||||
return info.width * info.height * info.bytesPerPixel + info.height;
|
||||
}
|
||||
|
||||
unsigned size = 0;
|
||||
for(unsigned pass = 0; pass < 7; pass++) {
|
||||
unsigned xd = interlace[pass][0], yd = interlace[pass][1];
|
||||
unsigned xo = interlace[pass][2], yo = interlace[pass][3];
|
||||
unsigned width = (info.width + (xd - xo - 1)) / xd;
|
||||
unsigned height = (info.height + (yd - yo - 1)) / yd;
|
||||
if(width == 0 || height == 0) continue;
|
||||
size += width * height * info.bytesPerPixel + height;
|
||||
}
|
||||
return size;
|
||||
}
|
||||
|
||||
bool png::deinterlace(const uint8_t *&inputData, unsigned pass) {
|
||||
unsigned xd = interlace[pass][0], yd = interlace[pass][1];
|
||||
unsigned xo = interlace[pass][2], yo = interlace[pass][3];
|
||||
unsigned width = (info.width + (xd - xo - 1)) / xd;
|
||||
unsigned height = (info.height + (yd - yo - 1)) / yd;
|
||||
if(width == 0 || height == 0) return true;
|
||||
|
||||
unsigned outputSize = width * height * info.bytesPerPixel;
|
||||
uint8_t *outputData = new uint8_t[outputSize];
|
||||
bool result = filter(outputData, inputData, width, height);
|
||||
|
||||
const uint8_t *rd = outputData;
|
||||
for(unsigned y = yo; y < info.height; y += yd) {
|
||||
uint8_t *wr = rawData + y * info.pitch;
|
||||
for(unsigned x = xo; x < info.width; x += xd) {
|
||||
for(unsigned b = 0; b < info.bytesPerPixel; b++) {
|
||||
wr[x * info.bytesPerPixel + b] = *rd++;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
inputData += outputSize + height;
|
||||
delete[] outputData;
|
||||
return result;
|
||||
}
|
||||
|
||||
bool png::filter(uint8_t *outputData, const uint8_t *inputData, unsigned width, unsigned height) {
|
||||
uint8_t *wr = outputData;
|
||||
const uint8_t *rd = inputData;
|
||||
int bpp = info.bytesPerPixel, pitch = width * bpp;
|
||||
for(int y = 0; y < height; y++) {
|
||||
uint8_t filter = *rd++;
|
||||
|
||||
switch(filter) {
|
||||
case 0x00: //None
|
||||
for(int x = 0; x < pitch; x++) {
|
||||
wr[x] = rd[x];
|
||||
}
|
||||
break;
|
||||
|
||||
case 0x01: //Subtract
|
||||
for(int x = 0; x < pitch; x++) {
|
||||
wr[x] = rd[x] + (x - bpp < 0 ? 0 : wr[x - bpp]);
|
||||
}
|
||||
break;
|
||||
|
||||
case 0x02: //Above
|
||||
for(int x = 0; x < pitch; x++) {
|
||||
wr[x] = rd[x] + (y - 1 < 0 ? 0 : wr[x - pitch]);
|
||||
}
|
||||
break;
|
||||
|
||||
case 0x03: //Average
|
||||
for(int x = 0; x < pitch; x++) {
|
||||
short a = x - bpp < 0 ? 0 : wr[x - bpp];
|
||||
short b = y - 1 < 0 ? 0 : wr[x - pitch];
|
||||
|
||||
wr[x] = rd[x] + (uint8_t)((a + b) / 2);
|
||||
}
|
||||
break;
|
||||
|
||||
case 0x04: //Paeth
|
||||
for(int x = 0; x < pitch; x++) {
|
||||
short a = x - bpp < 0 ? 0 : wr[x - bpp];
|
||||
short b = y - 1 < 0 ? 0 : wr[x - pitch];
|
||||
short c = x - bpp < 0 || y - 1 < 0 ? 0 : wr[x - pitch - bpp];
|
||||
|
||||
short p = a + b - c;
|
||||
short pa = p > a ? p - a : a - p;
|
||||
short pb = p > b ? p - b : b - p;
|
||||
short pc = p > c ? p - c : c - p;
|
||||
|
||||
uint8_t paeth = (uint8_t)((pa <= pb && pa <= pc) ? a : (pb <= pc) ? b : c);
|
||||
|
||||
wr[x] = rd[x] + paeth;
|
||||
}
|
||||
break;
|
||||
|
||||
default: //Invalid
|
||||
return false;
|
||||
}
|
||||
|
||||
rd += pitch;
|
||||
wr += pitch;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
unsigned png::read(const uint8_t *data, unsigned length) {
|
||||
unsigned result = 0;
|
||||
while(length--) result = (result << 8) | (*data++);
|
||||
return result;
|
||||
}
|
||||
|
||||
unsigned png::decode(const uint8_t *&data) {
|
||||
unsigned p, r, g, b, a;
|
||||
|
||||
switch(info.colorType) {
|
||||
case 0: //L
|
||||
r = g = b = scale(readbits(data));
|
||||
a = 0xff;
|
||||
break;
|
||||
case 2: //R,G,B
|
||||
r = scale(readbits(data));
|
||||
g = scale(readbits(data));
|
||||
b = scale(readbits(data));
|
||||
a = 0xff;
|
||||
break;
|
||||
case 3: //P
|
||||
p = readbits(data);
|
||||
r = info.palette[p][0];
|
||||
g = info.palette[p][1];
|
||||
b = info.palette[p][2];
|
||||
a = 0xff;
|
||||
break;
|
||||
case 4: //L,A
|
||||
r = g = b = scale(readbits(data));
|
||||
a = scale(readbits(data));
|
||||
break;
|
||||
case 6: //R,G,B,A
|
||||
r = scale(readbits(data));
|
||||
g = scale(readbits(data));
|
||||
b = scale(readbits(data));
|
||||
a = scale(readbits(data));
|
||||
break;
|
||||
}
|
||||
|
||||
return (a << 24) | (r << 16) | (g << 8) | (b << 0);
|
||||
}
|
||||
|
||||
unsigned png::readbits(const uint8_t *&data) {
|
||||
unsigned result = 0;
|
||||
switch(info.bitDepth) {
|
||||
case 1:
|
||||
result = (*data >> bitpos) & 1;
|
||||
bitpos++;
|
||||
if(bitpos == 8) { data++; bitpos = 0; }
|
||||
break;
|
||||
case 2:
|
||||
result = (*data >> bitpos) & 3;
|
||||
bitpos += 2;
|
||||
if(bitpos == 8) { data++; bitpos = 0; }
|
||||
break;
|
||||
case 4:
|
||||
result = (*data >> bitpos) & 15;
|
||||
bitpos += 4;
|
||||
if(bitpos == 8) { data++; bitpos = 0; }
|
||||
break;
|
||||
case 8:
|
||||
result = *data++;
|
||||
break;
|
||||
case 16:
|
||||
result = (data[0] << 8) | (data[1] << 0);
|
||||
data += 2;
|
||||
break;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
unsigned png::scale(unsigned n) {
|
||||
switch(info.bitDepth) {
|
||||
case 1: return n ? 0xff : 0x00;
|
||||
case 2: return n * 0x55;
|
||||
case 4: return n * 0x11;
|
||||
case 8: return n;
|
||||
case 16: return n >> 8;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
void png::transform() {
|
||||
if(data) delete[] data;
|
||||
data = new uint32_t[info.width * info.height];
|
||||
|
||||
bitpos = 0;
|
||||
const uint8_t *rd = rawData;
|
||||
for(unsigned y = 0; y < info.height; y++) {
|
||||
uint32_t *wr = data + y * info.width;
|
||||
for(unsigned x = 0; x < info.width; x++) {
|
||||
wr[x] = decode(rd);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void png::alphaTransform(uint32_t rgb) {
|
||||
transform();
|
||||
|
||||
uint8_t ir = rgb >> 16;
|
||||
uint8_t ig = rgb >> 8;
|
||||
uint8_t ib = rgb >> 0;
|
||||
|
||||
uint32_t *p = data;
|
||||
for(unsigned y = 0; y < info.height; y++) {
|
||||
for(unsigned x = 0; x < info.width; x++) {
|
||||
uint32_t pixel = *p;
|
||||
uint8_t a = pixel >> 24;
|
||||
uint8_t r = pixel >> 16;
|
||||
uint8_t g = pixel >> 8;
|
||||
uint8_t b = pixel >> 0;
|
||||
|
||||
r = (r * a) + (ir * (255 - a)) >> 8;
|
||||
g = (g * a) + (ig * (255 - a)) >> 8;
|
||||
b = (b * a) + (ib * (255 - a)) >> 8;
|
||||
|
||||
*p++ = (255 << 24) | (r << 16) | (g << 8) | (b << 0);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
png::png() : data(0), rawData(0) {
|
||||
}
|
||||
|
||||
png::~png() {
|
||||
if(data) delete[] data;
|
||||
if(rawData) delete[] rawData;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
#endif
|
61
bsnes/nall/resource.hpp
Executable file
61
bsnes/nall/resource.hpp
Executable file
@@ -0,0 +1,61 @@
|
||||
#ifndef NALL_RESOURCE_HPP
|
||||
#define NALL_RESOURCE_HPP
|
||||
|
||||
#include <nall/file.hpp>
|
||||
#include <nall/zip.hpp>
|
||||
|
||||
namespace nall {
|
||||
|
||||
struct resource {
|
||||
//create resource with "zip -9 resource.zip resource"
|
||||
static bool encode(const char *outputFilename, const char *inputFilename) {
|
||||
file fp;
|
||||
if(fp.open(inputFilename, file::mode::read) == false) return false;
|
||||
unsigned size = fp.size();
|
||||
uint8_t *data = new uint8_t[size];
|
||||
fp.read(data, size);
|
||||
fp.close();
|
||||
|
||||
fp.open(outputFilename, file::mode::write);
|
||||
fp.print("static const uint8_t data[", size, "] = {\n");
|
||||
uint8_t *p = data;
|
||||
while(size) {
|
||||
fp.print(" ");
|
||||
for(unsigned n = 0; n < 32 && size; n++, size--) {
|
||||
fp.print((unsigned)*p++, ",");
|
||||
}
|
||||
fp.print("\n");
|
||||
}
|
||||
fp.print("};\n");
|
||||
fp.close();
|
||||
|
||||
delete[] data;
|
||||
}
|
||||
|
||||
uint8_t *data;
|
||||
unsigned size;
|
||||
|
||||
//extract first file from ZIP archive
|
||||
bool decode(const uint8_t *cdata, unsigned csize) {
|
||||
if(data) delete[] data;
|
||||
|
||||
zip archive;
|
||||
if(archive.open(cdata, csize) == false) return false;
|
||||
if(archive.file.size() == 0) return false;
|
||||
bool result = archive.extract(archive.file[0], data, size);
|
||||
archive.close();
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
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))
|
||||
|
||||
@@ -49,7 +51,7 @@ namespace nall {
|
||||
uint64_t len;
|
||||
};
|
||||
|
||||
void sha256_init(sha256_ctx *p) {
|
||||
inline void sha256_init(sha256_ctx *p) {
|
||||
memset(p, 0, sizeof(sha256_ctx));
|
||||
memcpy(p->h, T_H, sizeof(T_H));
|
||||
}
|
||||
@@ -90,7 +92,7 @@ namespace nall {
|
||||
p->inlen = 0;
|
||||
}
|
||||
|
||||
void sha256_chunk(sha256_ctx *p, const uint8_t *s, unsigned len) {
|
||||
inline void sha256_chunk(sha256_ctx *p, const uint8_t *s, unsigned len) {
|
||||
unsigned l;
|
||||
p->len += len;
|
||||
|
||||
@@ -107,7 +109,7 @@ namespace nall {
|
||||
}
|
||||
}
|
||||
|
||||
void sha256_final(sha256_ctx *p) {
|
||||
inline void sha256_final(sha256_ctx *p) {
|
||||
uint64_t len;
|
||||
p->in[p->inlen++] = 0x80;
|
||||
|
||||
@@ -124,7 +126,7 @@ namespace nall {
|
||||
sha256_block(p);
|
||||
}
|
||||
|
||||
void sha256_hash(sha256_ctx *p, uint8_t *s) {
|
||||
inline void sha256_hash(sha256_ctx *p, uint8_t *s) {
|
||||
uint32_t *t = (uint32_t*)s;
|
||||
for(unsigned i = 0; i < 8; i++) ST32BE(t++, p->h[i]);
|
||||
}
|
||||
|
@@ -111,426 +111,426 @@ SNESCartridge::SNESCartridge(const uint8_t *data, unsigned size) {
|
||||
string xml = "<?xml version='1.0' encoding='UTF-8'?>\n";
|
||||
|
||||
if(type == TypeBsx) {
|
||||
xml << "<cartridge/>";
|
||||
xml.append("<cartridge/>");
|
||||
xmlMemoryMap = xml.transform("'", "\"");
|
||||
return;
|
||||
}
|
||||
|
||||
if(type == TypeSufamiTurbo) {
|
||||
xml << "<cartridge/>";
|
||||
xml.append("<cartridge/>");
|
||||
xmlMemoryMap = xml.transform("'", "\"");
|
||||
return;
|
||||
}
|
||||
|
||||
if(type == TypeGameBoy) {
|
||||
xml << "<cartridge rtc='" << gameboy_has_rtc(data, size) << "'>\n";
|
||||
xml.append("<cartridge rtc='", gameboy_has_rtc(data, size), "'>\n");
|
||||
if(gameboy_ram_size(data, size) > 0) {
|
||||
xml << " <ram size='0x" << hex(gameboy_ram_size(data, size)) << "'/>\n";
|
||||
xml.append(" <ram size='0x", hex(gameboy_ram_size(data, size)), "'/>\n");
|
||||
}
|
||||
xml << "</cartridge>\n";
|
||||
xml.append("</cartridge>\n");
|
||||
xmlMemoryMap = xml.transform("'", "\"");
|
||||
return;
|
||||
}
|
||||
|
||||
xml << "<cartridge";
|
||||
xml.append("<cartridge");
|
||||
if(region == NTSC) {
|
||||
xml << " region='NTSC'";
|
||||
xml.append(" region='NTSC'");
|
||||
} else {
|
||||
xml << " region='PAL'";
|
||||
xml.append(" region='PAL'");
|
||||
}
|
||||
xml << ">\n";
|
||||
xml.append(">\n");
|
||||
|
||||
if(type == TypeSuperGameBoy1Bios) {
|
||||
xml << " <rom>\n";
|
||||
xml << " <map mode='linear' address='00-7f:8000-ffff'/>\n";
|
||||
xml << " <map mode='linear' address='80-ff:8000-ffff'/>\n";
|
||||
xml << " </rom>\n";
|
||||
xml << " <icd2 revision='1'>\n";
|
||||
xml << " <map address='00-3f:6000-7fff'/>\n";
|
||||
xml << " <map address='80-bf:6000-7fff'/>\n";
|
||||
xml << " </icd2>\n";
|
||||
xml.append(" <rom>\n");
|
||||
xml.append(" <map mode='linear' address='00-7f:8000-ffff'/>\n");
|
||||
xml.append(" <map mode='linear' address='80-ff:8000-ffff'/>\n");
|
||||
xml.append(" </rom>\n");
|
||||
xml.append(" <icd2 revision='1'>\n");
|
||||
xml.append(" <map address='00-3f:6000-7fff'/>\n");
|
||||
xml.append(" <map address='80-bf:6000-7fff'/>\n");
|
||||
xml.append(" </icd2>\n");
|
||||
} else if(type == TypeSuperGameBoy2Bios) {
|
||||
xml << " <rom>\n";
|
||||
xml << " <map mode='linear' address='00-7f:8000-ffff'/>\n";
|
||||
xml << " <map mode='linear' address='80-ff:8000-ffff'/>\n";
|
||||
xml << " </rom>\n";
|
||||
xml << " <icd2 revision='2'>\n";
|
||||
xml << " <map address='00-3f:6000-7fff'/>\n";
|
||||
xml << " <map address='80-bf:6000-7fff'/>\n";
|
||||
xml << " </icd2>\n";
|
||||
xml.append(" <rom>\n");
|
||||
xml.append(" <map mode='linear' address='00-7f:8000-ffff'/>\n");
|
||||
xml.append(" <map mode='linear' address='80-ff:8000-ffff'/>\n");
|
||||
xml.append(" </rom>\n");
|
||||
xml.append(" <icd2 revision='2'>\n");
|
||||
xml.append(" <map address='00-3f:6000-7fff'/>\n");
|
||||
xml.append(" <map address='80-bf:6000-7fff'/>\n");
|
||||
xml.append(" </icd2>\n");
|
||||
} else if(has_cx4) {
|
||||
xml << " <hitachidsp model='HG51B169' frequency='20000000' data='cx4.bin' sha256='ae8d4d1961b93421ff00b3caa1d0f0ce7783e749772a3369c36b3dbf0d37ef18'>\n";
|
||||
xml << " <rom>\n";
|
||||
xml << " <map mode='linear' address='00-7f:8000-ffff'/>\n";
|
||||
xml << " <map mode='linear' address='80-ff:8000-ffff'/>\n";
|
||||
xml << " </rom>\n";
|
||||
xml << " <mmio>\n";
|
||||
xml << " <map address='00-3f:6000-7fff'/>\n";
|
||||
xml << " <map address='80-bf:6000-7fff'/>\n";
|
||||
xml << " </mmio>\n";
|
||||
xml << " </hitachidsp>\n";
|
||||
xml.append(" <hitachidsp model='HG51B169' frequency='20000000' firmware='cx4.bin' sha256='ae8d4d1961b93421ff00b3caa1d0f0ce7783e749772a3369c36b3dbf0d37ef18'>\n");
|
||||
xml.append(" <rom>\n");
|
||||
xml.append(" <map mode='linear' address='00-7f:8000-ffff'/>\n");
|
||||
xml.append(" <map mode='linear' address='80-ff:8000-ffff'/>\n");
|
||||
xml.append(" </rom>\n");
|
||||
xml.append(" <mmio>\n");
|
||||
xml.append(" <map address='00-3f:6000-7fff'/>\n");
|
||||
xml.append(" <map address='80-bf:6000-7fff'/>\n");
|
||||
xml.append(" </mmio>\n");
|
||||
xml.append(" </hitachidsp>\n");
|
||||
} else if(has_spc7110) {
|
||||
xml << " <rom>\n";
|
||||
xml << " <map mode='shadow' address='00-0f:8000-ffff'/>\n";
|
||||
xml << " <map mode='shadow' address='80-bf:8000-ffff'/>\n";
|
||||
xml << " <map mode='linear' address='c0-cf:0000-ffff'/>\n";
|
||||
xml << " </rom>\n";
|
||||
xml.append(" <rom>\n");
|
||||
xml.append(" <map mode='shadow' address='00-0f:8000-ffff'/>\n");
|
||||
xml.append(" <map mode='shadow' address='80-bf:8000-ffff'/>\n");
|
||||
xml.append(" <map mode='linear' address='c0-cf:0000-ffff'/>\n");
|
||||
xml.append(" </rom>\n");
|
||||
|
||||
xml << " <spc7110>\n";
|
||||
xml << " <mcu>\n";
|
||||
xml << " <map address='d0-ff:0000-ffff' offset='0x100000' size='0x" << hex(size - 0x100000) << "'/>\n";
|
||||
xml << " </mcu>\n";
|
||||
xml << " <ram size='0x" << hex(ram_size) << "'>\n";
|
||||
xml << " <map mode='linear' address='00:6000-7fff'/>\n";
|
||||
xml << " <map mode='linear' address='30:6000-7fff'/>\n";
|
||||
xml << " </ram>\n";
|
||||
xml << " <mmio>\n";
|
||||
xml << " <map address='00-3f:4800-483f'/>\n";
|
||||
xml << " <map address='80-bf:4800-483f'/>\n";
|
||||
xml << " </mmio>\n";
|
||||
xml.append(" <spc7110>\n");
|
||||
xml.append(" <mcu>\n");
|
||||
xml.append(" <map address='d0-ff:0000-ffff' offset='0x100000' size='0x", hex(size - 0x100000), "'/>\n");
|
||||
xml.append(" </mcu>\n");
|
||||
xml.append(" <ram size='0x", hex(ram_size), "'>\n");
|
||||
xml.append(" <map mode='linear' address='00:6000-7fff'/>\n");
|
||||
xml.append(" <map mode='linear' address='30:6000-7fff'/>\n");
|
||||
xml.append(" </ram>\n");
|
||||
xml.append(" <mmio>\n");
|
||||
xml.append(" <map address='00-3f:4800-483f'/>\n");
|
||||
xml.append(" <map address='80-bf:4800-483f'/>\n");
|
||||
xml.append(" </mmio>\n");
|
||||
if(has_spc7110rtc) {
|
||||
xml << " <rtc>\n";
|
||||
xml << " <map address='00-3f:4840-4842'/>\n";
|
||||
xml << " <map address='80-bf:4840-4842'/>\n";
|
||||
xml << " </rtc>\n";
|
||||
xml.append(" <rtc>\n");
|
||||
xml.append(" <map address='00-3f:4840-4842'/>\n");
|
||||
xml.append(" <map address='80-bf:4840-4842'/>\n");
|
||||
xml.append(" </rtc>\n");
|
||||
}
|
||||
xml << " <dcu>\n";
|
||||
xml << " <map address='50:0000-ffff'/>\n";
|
||||
xml << " </dcu>\n";
|
||||
xml << " </spc7110>\n";
|
||||
xml.append(" <dcu>\n");
|
||||
xml.append(" <map address='50:0000-ffff'/>\n");
|
||||
xml.append(" </dcu>\n");
|
||||
xml.append(" </spc7110>\n");
|
||||
} else if(mapper == LoROM) {
|
||||
xml << " <rom>\n";
|
||||
xml << " <map mode='linear' address='00-7f:8000-ffff'/>\n";
|
||||
xml << " <map mode='linear' address='80-ff:8000-ffff'/>\n";
|
||||
xml << " </rom>\n";
|
||||
xml.append(" <rom>\n");
|
||||
xml.append(" <map mode='linear' address='00-7f:8000-ffff'/>\n");
|
||||
xml.append(" <map mode='linear' address='80-ff:8000-ffff'/>\n");
|
||||
xml.append(" </rom>\n");
|
||||
|
||||
if(ram_size > 0) {
|
||||
xml << " <ram size='0x" << hex(ram_size) << "'>\n";
|
||||
xml << " <map mode='linear' address='20-3f:6000-7fff'/>\n";
|
||||
xml << " <map mode='linear' address='a0-bf:6000-7fff'/>\n";
|
||||
xml.append(" <ram size='0x", hex(ram_size), "'>\n");
|
||||
xml.append(" <map mode='linear' address='20-3f:6000-7fff'/>\n");
|
||||
xml.append(" <map mode='linear' address='a0-bf:6000-7fff'/>\n");
|
||||
if((rom_size > 0x200000) || (ram_size > 32 * 1024)) {
|
||||
xml << " <map mode='linear' address='70-7f:0000-7fff'/>\n";
|
||||
xml << " <map mode='linear' address='f0-ff:0000-7fff'/>\n";
|
||||
xml.append(" <map mode='linear' address='70-7f:0000-7fff'/>\n");
|
||||
xml.append(" <map mode='linear' address='f0-ff:0000-7fff'/>\n");
|
||||
} else {
|
||||
xml << " <map mode='linear' address='70-7f:0000-ffff'/>\n";
|
||||
xml << " <map mode='linear' address='f0-ff:0000-ffff'/>\n";
|
||||
xml.append(" <map mode='linear' address='70-7f:0000-ffff'/>\n");
|
||||
xml.append(" <map mode='linear' address='f0-ff:0000-ffff'/>\n");
|
||||
}
|
||||
xml << " </ram>\n";
|
||||
xml.append(" </ram>\n");
|
||||
}
|
||||
} else if(mapper == HiROM) {
|
||||
xml << " <rom>\n";
|
||||
xml << " <map mode='shadow' address='00-3f:8000-ffff'/>\n";
|
||||
xml << " <map mode='linear' address='40-7f:0000-ffff'/>\n";
|
||||
xml << " <map mode='shadow' address='80-bf:8000-ffff'/>\n";
|
||||
xml << " <map mode='linear' address='c0-ff:0000-ffff'/>\n";
|
||||
xml << " </rom>\n";
|
||||
xml.append(" <rom>\n");
|
||||
xml.append(" <map mode='shadow' address='00-3f:8000-ffff'/>\n");
|
||||
xml.append(" <map mode='linear' address='40-7f:0000-ffff'/>\n");
|
||||
xml.append(" <map mode='shadow' address='80-bf:8000-ffff'/>\n");
|
||||
xml.append(" <map mode='linear' address='c0-ff:0000-ffff'/>\n");
|
||||
xml.append(" </rom>\n");
|
||||
|
||||
if(ram_size > 0) {
|
||||
xml << " <ram size='0x" << hex(ram_size) << "'>\n";
|
||||
xml << " <map mode='linear' address='20-3f:6000-7fff'/>\n";
|
||||
xml << " <map mode='linear' address='a0-bf:6000-7fff'/>\n";
|
||||
xml.append(" <ram size='0x", hex(ram_size), "'>\n");
|
||||
xml.append(" <map mode='linear' address='20-3f:6000-7fff'/>\n");
|
||||
xml.append(" <map mode='linear' address='a0-bf:6000-7fff'/>\n");
|
||||
if((rom_size > 0x200000) || (ram_size > 32 * 1024)) {
|
||||
xml << " <map mode='linear' address='70-7f:0000-7fff'/>\n";
|
||||
xml.append(" <map mode='linear' address='70-7f:0000-7fff'/>\n");
|
||||
} else {
|
||||
xml << " <map mode='linear' address='70-7f:0000-ffff'/>\n";
|
||||
xml.append(" <map mode='linear' address='70-7f:0000-ffff'/>\n");
|
||||
}
|
||||
xml << " </ram>\n";
|
||||
xml.append(" </ram>\n");
|
||||
}
|
||||
} else if(mapper == ExLoROM) {
|
||||
xml << " <rom>\n";
|
||||
xml << " <map mode='linear' address='00-3f:8000-ffff'/>\n";
|
||||
xml << " <map mode='linear' address='40-7f:0000-ffff'/>\n";
|
||||
xml << " <map mode='linear' address='80-bf:8000-ffff'/>\n";
|
||||
xml << " </rom>\n";
|
||||
xml.append(" <rom>\n");
|
||||
xml.append(" <map mode='linear' address='00-3f:8000-ffff'/>\n");
|
||||
xml.append(" <map mode='linear' address='40-7f:0000-ffff'/>\n");
|
||||
xml.append(" <map mode='linear' address='80-bf:8000-ffff'/>\n");
|
||||
xml.append(" </rom>\n");
|
||||
|
||||
if(ram_size > 0) {
|
||||
xml << " <ram size='0x" << hex(ram_size) << "'>\n";
|
||||
xml << " <map mode='linear' address='20-3f:6000-7fff'/>\n";
|
||||
xml << " <map mode='linear' address='a0-bf:6000-7fff'/>\n";
|
||||
xml << " <map mode='linear' address='70-7f:0000-7fff'/>\n";
|
||||
xml << " </ram>\n";
|
||||
xml.append(" <ram size='0x", hex(ram_size), "'>\n");
|
||||
xml.append(" <map mode='linear' address='20-3f:6000-7fff'/>\n");
|
||||
xml.append(" <map mode='linear' address='a0-bf:6000-7fff'/>\n");
|
||||
xml.append(" <map mode='linear' address='70-7f:0000-7fff'/>\n");
|
||||
xml.append(" </ram>\n");
|
||||
}
|
||||
} else if(mapper == ExHiROM) {
|
||||
xml << " <rom>\n";
|
||||
xml << " <map mode='shadow' address='00-3f:8000-ffff' offset='0x400000'/>\n";
|
||||
xml << " <map mode='linear' address='40-7f:0000-ffff' offset='0x400000'/>\n";
|
||||
xml << " <map mode='shadow' address='80-bf:8000-ffff' offset='0x000000'/>\n";
|
||||
xml << " <map mode='linear' address='c0-ff:0000-ffff' offset='0x000000'/>\n";
|
||||
xml << " </rom>\n";
|
||||
xml.append(" <rom>\n");
|
||||
xml.append(" <map mode='shadow' address='00-3f:8000-ffff' offset='0x400000'/>\n");
|
||||
xml.append(" <map mode='linear' address='40-7f:0000-ffff' offset='0x400000'/>\n");
|
||||
xml.append(" <map mode='shadow' address='80-bf:8000-ffff' offset='0x000000'/>\n");
|
||||
xml.append(" <map mode='linear' address='c0-ff:0000-ffff' offset='0x000000'/>\n");
|
||||
xml.append(" </rom>\n");
|
||||
|
||||
if(ram_size > 0) {
|
||||
xml << " <ram size='0x" << hex(ram_size) << "'>\n";
|
||||
xml << " <map mode='linear' address='20-3f:6000-7fff'/>\n";
|
||||
xml << " <map mode='linear' address='a0-bf:6000-7fff'/>\n";
|
||||
xml.append(" <ram size='0x", hex(ram_size), "'>\n");
|
||||
xml.append(" <map mode='linear' address='20-3f:6000-7fff'/>\n");
|
||||
xml.append(" <map mode='linear' address='a0-bf:6000-7fff'/>\n");
|
||||
if((rom_size > 0x200000) || (ram_size > 32 * 1024)) {
|
||||
xml << " <map mode='linear' address='70-7f:0000-7fff'/>\n";
|
||||
xml.append(" <map mode='linear' address='70-7f:0000-7fff'/>\n");
|
||||
} else {
|
||||
xml << " <map mode='linear' address='70-7f:0000-ffff'/>\n";
|
||||
xml.append(" <map mode='linear' address='70-7f:0000-ffff'/>\n");
|
||||
}
|
||||
xml << " </ram>\n";
|
||||
xml.append(" </ram>\n");
|
||||
}
|
||||
} else if(mapper == SuperFXROM) {
|
||||
xml << " <superfx revision='2'>\n";
|
||||
xml << " <rom>\n";
|
||||
xml << " <map mode='linear' address='00-3f:8000-ffff'/>\n";
|
||||
xml << " <map mode='linear' address='40-5f:0000-ffff'/>\n";
|
||||
xml << " <map mode='linear' address='80-bf:8000-ffff'/>\n";
|
||||
xml << " <map mode='linear' address='c0-df:0000-ffff'/>\n";
|
||||
xml << " </rom>\n";
|
||||
xml << " <ram size='0x" << hex(ram_size) << "'>\n";
|
||||
xml << " <map mode='linear' address='00-3f:6000-7fff' size='0x2000'/>\n";
|
||||
xml << " <map mode='linear' address='60-7f:0000-ffff'/>\n";
|
||||
xml << " <map mode='linear' address='80-bf:6000-7fff' size='0x2000'/>\n";
|
||||
xml << " <map mode='linear' address='e0-ff:0000-ffff'/>\n";
|
||||
xml << " </ram>\n";
|
||||
xml << " <mmio>\n";
|
||||
xml << " <map address='00-3f:3000-32ff'/>\n";
|
||||
xml << " <map address='80-bf:3000-32ff'/>\n";
|
||||
xml << " </mmio>\n";
|
||||
xml << " </superfx>\n";
|
||||
xml.append(" <superfx revision='2'>\n");
|
||||
xml.append(" <rom>\n");
|
||||
xml.append(" <map mode='linear' address='00-3f:8000-ffff'/>\n");
|
||||
xml.append(" <map mode='linear' address='40-5f:0000-ffff'/>\n");
|
||||
xml.append(" <map mode='linear' address='80-bf:8000-ffff'/>\n");
|
||||
xml.append(" <map mode='linear' address='c0-df:0000-ffff'/>\n");
|
||||
xml.append(" </rom>\n");
|
||||
xml.append(" <ram size='0x", hex(ram_size), "'>\n");
|
||||
xml.append(" <map mode='linear' address='00-3f:6000-7fff' size='0x2000'/>\n");
|
||||
xml.append(" <map mode='linear' address='60-7f:0000-ffff'/>\n");
|
||||
xml.append(" <map mode='linear' address='80-bf:6000-7fff' size='0x2000'/>\n");
|
||||
xml.append(" <map mode='linear' address='e0-ff:0000-ffff'/>\n");
|
||||
xml.append(" </ram>\n");
|
||||
xml.append(" <mmio>\n");
|
||||
xml.append(" <map address='00-3f:3000-32ff'/>\n");
|
||||
xml.append(" <map address='80-bf:3000-32ff'/>\n");
|
||||
xml.append(" </mmio>\n");
|
||||
xml.append(" </superfx>\n");
|
||||
} else if(mapper == SA1ROM) {
|
||||
xml << " <sa1>\n";
|
||||
xml << " <mcu>\n";
|
||||
xml << " <rom>\n";
|
||||
xml << " <map mode='direct' address='00-3f:8000-ffff'/>\n";
|
||||
xml << " <map mode='direct' address='80-bf:8000-ffff'/>\n";
|
||||
xml << " <map mode='direct' address='c0-ff:0000-ffff'/>\n";
|
||||
xml << " </rom>\n";
|
||||
xml << " <ram>\n";
|
||||
xml << " <map mode='direct' address='00-3f:6000-7fff'/>\n";
|
||||
xml << " <map mode='direct' address='80-bf:6000-7fff'/>\n";
|
||||
xml << " </ram>\n";
|
||||
xml << " </mcu>\n";
|
||||
xml << " <iram size='0x800'>\n";
|
||||
xml << " <map mode='linear' address='00-3f:3000-37ff'/>\n";
|
||||
xml << " <map mode='linear' address='80-bf:3000-37ff'/>\n";
|
||||
xml << " </iram>\n";
|
||||
xml << " <bwram size='0x" << hex(ram_size) << "'>\n";
|
||||
xml << " <map mode='linear' address='40-4f:0000-ffff'/>\n";
|
||||
xml << " </bwram>\n";
|
||||
xml << " <mmio>\n";
|
||||
xml << " <map address='00-3f:2200-23ff'/>\n";
|
||||
xml << " <map address='80-bf:2200-23ff'/>\n";
|
||||
xml << " </mmio>\n";
|
||||
xml << " </sa1>\n";
|
||||
xml.append(" <sa1>\n");
|
||||
xml.append(" <mcu>\n");
|
||||
xml.append(" <rom>\n");
|
||||
xml.append(" <map mode='direct' address='00-3f:8000-ffff'/>\n");
|
||||
xml.append(" <map mode='direct' address='80-bf:8000-ffff'/>\n");
|
||||
xml.append(" <map mode='direct' address='c0-ff:0000-ffff'/>\n");
|
||||
xml.append(" </rom>\n");
|
||||
xml.append(" <ram>\n");
|
||||
xml.append(" <map mode='direct' address='00-3f:6000-7fff'/>\n");
|
||||
xml.append(" <map mode='direct' address='80-bf:6000-7fff'/>\n");
|
||||
xml.append(" </ram>\n");
|
||||
xml.append(" </mcu>\n");
|
||||
xml.append(" <iram size='0x800'>\n");
|
||||
xml.append(" <map mode='linear' address='00-3f:3000-37ff'/>\n");
|
||||
xml.append(" <map mode='linear' address='80-bf:3000-37ff'/>\n");
|
||||
xml.append(" </iram>\n");
|
||||
xml.append(" <bwram size='0x", hex(ram_size), "'>\n");
|
||||
xml.append(" <map mode='linear' address='40-4f:0000-ffff'/>\n");
|
||||
xml.append(" </bwram>\n");
|
||||
xml.append(" <mmio>\n");
|
||||
xml.append(" <map address='00-3f:2200-23ff'/>\n");
|
||||
xml.append(" <map address='80-bf:2200-23ff'/>\n");
|
||||
xml.append(" </mmio>\n");
|
||||
xml.append(" </sa1>\n");
|
||||
} else if(mapper == BSCLoROM) {
|
||||
xml << " <rom>\n";
|
||||
xml << " <map mode='linear' address='00-1f:8000-ffff' offset='0x000000'/>\n";
|
||||
xml << " <map mode='linear' address='20-3f:8000-ffff' offset='0x100000'/>\n";
|
||||
xml << " <map mode='linear' address='80-9f:8000-ffff' offset='0x200000'/>\n";
|
||||
xml << " <map mode='linear' address='a0-bf:8000-ffff' offset='0x100000'/>\n";
|
||||
xml << " </rom>\n";
|
||||
xml << " <ram size='0x" << hex(ram_size) << "'>\n";
|
||||
xml << " <map mode='linear' address='70-7f:0000-7fff'/>\n";
|
||||
xml << " <map mode='linear' address='f0-ff:0000-7fff'/>\n";
|
||||
xml << " </ram>\n";
|
||||
xml << " <bsx>\n";
|
||||
xml << " <slot>\n";
|
||||
xml << " <map mode='linear' address='c0-ef:0000-ffff'/>\n";
|
||||
xml << " </slot>\n";
|
||||
xml << " </bsx>\n";
|
||||
xml.append(" <rom>\n");
|
||||
xml.append(" <map mode='linear' address='00-1f:8000-ffff' offset='0x000000'/>\n");
|
||||
xml.append(" <map mode='linear' address='20-3f:8000-ffff' offset='0x100000'/>\n");
|
||||
xml.append(" <map mode='linear' address='80-9f:8000-ffff' offset='0x200000'/>\n");
|
||||
xml.append(" <map mode='linear' address='a0-bf:8000-ffff' offset='0x100000'/>\n");
|
||||
xml.append(" </rom>\n");
|
||||
xml.append(" <ram size='0x", hex(ram_size), "'>\n");
|
||||
xml.append(" <map mode='linear' address='70-7f:0000-7fff'/>\n");
|
||||
xml.append(" <map mode='linear' address='f0-ff:0000-7fff'/>\n");
|
||||
xml.append(" </ram>\n");
|
||||
xml.append(" <bsx>\n");
|
||||
xml.append(" <slot>\n");
|
||||
xml.append(" <map mode='linear' address='c0-ef:0000-ffff'/>\n");
|
||||
xml.append(" </slot>\n");
|
||||
xml.append(" </bsx>\n");
|
||||
} else if(mapper == BSCHiROM) {
|
||||
xml << " <rom>\n";
|
||||
xml << " <map mode='shadow' address='00-1f:8000-ffff'/>\n";
|
||||
xml << " <map mode='linear' address='40-5f:0000-ffff'/>\n";
|
||||
xml << " <map mode='shadow' address='80-9f:8000-ffff'/>\n";
|
||||
xml << " <map mode='linear' address='c0-df:0000-ffff'/>\n";
|
||||
xml << " </rom>\n";
|
||||
xml << " <ram size='0x" << hex(ram_size) << "'>\n";
|
||||
xml << " <map mode='linear' address='20-3f:6000-7fff'/>\n";
|
||||
xml << " <map mode='linear' address='a0-bf:6000-7fff'/>\n";
|
||||
xml << " </ram>\n";
|
||||
xml << " <bsx>\n";
|
||||
xml << " <slot>\n";
|
||||
xml << " <map mode='shadow' address='20-3f:8000-ffff'/>\n";
|
||||
xml << " <map mode='linear' address='60-7f:0000-ffff'/>\n";
|
||||
xml << " <map mode='shadow' address='a0-bf:8000-ffff'/>\n";
|
||||
xml << " <map mode='linear' address='e0-ff:0000-ffff'/>\n";
|
||||
xml << " </slot>\n";
|
||||
xml << " </bsx>\n";
|
||||
xml.append(" <rom>\n");
|
||||
xml.append(" <map mode='shadow' address='00-1f:8000-ffff'/>\n");
|
||||
xml.append(" <map mode='linear' address='40-5f:0000-ffff'/>\n");
|
||||
xml.append(" <map mode='shadow' address='80-9f:8000-ffff'/>\n");
|
||||
xml.append(" <map mode='linear' address='c0-df:0000-ffff'/>\n");
|
||||
xml.append(" </rom>\n");
|
||||
xml.append(" <ram size='0x", hex(ram_size), "'>\n");
|
||||
xml.append(" <map mode='linear' address='20-3f:6000-7fff'/>\n");
|
||||
xml.append(" <map mode='linear' address='a0-bf:6000-7fff'/>\n");
|
||||
xml.append(" </ram>\n");
|
||||
xml.append(" <bsx>\n");
|
||||
xml.append(" <slot>\n");
|
||||
xml.append(" <map mode='shadow' address='20-3f:8000-ffff'/>\n");
|
||||
xml.append(" <map mode='linear' address='60-7f:0000-ffff'/>\n");
|
||||
xml.append(" <map mode='shadow' address='a0-bf:8000-ffff'/>\n");
|
||||
xml.append(" <map mode='linear' address='e0-ff:0000-ffff'/>\n");
|
||||
xml.append(" </slot>\n");
|
||||
xml.append(" </bsx>\n");
|
||||
} else if(mapper == BSXROM) {
|
||||
xml << " <bsx>\n";
|
||||
xml << " <mcu>\n";
|
||||
xml << " <map address='00-3f:8000-ffff'/>\n";
|
||||
xml << " <map address='80-bf:8000-ffff'/>\n";
|
||||
xml << " <map address='40-7f:0000-ffff'/>\n";
|
||||
xml << " <map address='c0-ff:0000-ffff'/>\n";
|
||||
xml << " <map address='20-3f:6000-7fff'/>\n";
|
||||
xml << " </mcu>\n";
|
||||
xml << " <mmio>\n";
|
||||
xml << " <map address='00-3f:5000-5fff'/>\n";
|
||||
xml << " <map address='80-bf:5000-5fff'/>\n";
|
||||
xml << " </mmio>\n";
|
||||
xml << " </bsx>\n";
|
||||
xml.append(" <bsx>\n");
|
||||
xml.append(" <mcu>\n");
|
||||
xml.append(" <map address='00-3f:8000-ffff'/>\n");
|
||||
xml.append(" <map address='80-bf:8000-ffff'/>\n");
|
||||
xml.append(" <map address='40-7f:0000-ffff'/>\n");
|
||||
xml.append(" <map address='c0-ff:0000-ffff'/>\n");
|
||||
xml.append(" <map address='20-3f:6000-7fff'/>\n");
|
||||
xml.append(" </mcu>\n");
|
||||
xml.append(" <mmio>\n");
|
||||
xml.append(" <map address='00-3f:5000-5fff'/>\n");
|
||||
xml.append(" <map address='80-bf:5000-5fff'/>\n");
|
||||
xml.append(" </mmio>\n");
|
||||
xml.append(" </bsx>\n");
|
||||
} else if(mapper == STROM) {
|
||||
xml << " <rom>\n";
|
||||
xml << " <map mode='linear' address='00-1f:8000-ffff'/>\n";
|
||||
xml << " <map mode='linear' address='80-9f:8000-ffff'/>\n";
|
||||
xml << " </rom>\n";
|
||||
xml << " <sufamiturbo>\n";
|
||||
xml << " <slot id='A'>\n";
|
||||
xml << " <rom>\n";
|
||||
xml << " <map mode='linear' address='20-3f:8000-ffff'/>\n";
|
||||
xml << " <map mode='linear' address='a0-bf:8000-ffff'/>\n";
|
||||
xml << " </rom>\n";
|
||||
xml << " <ram size='0x20000'>\n";
|
||||
xml << " <map mode='linear' address='60-63:8000-ffff'/>\n";
|
||||
xml << " <map mode='linear' address='e0-e3:8000-ffff'/>\n";
|
||||
xml << " </ram>\n";
|
||||
xml << " </slot>\n";
|
||||
xml << " <slot id='B'>\n";
|
||||
xml << " <rom>\n";
|
||||
xml << " <map mode='linear' address='40-5f:8000-ffff'/>\n";
|
||||
xml << " <map mode='linear' address='c0-df:8000-ffff'/>\n";
|
||||
xml << " </rom>\n";
|
||||
xml << " <ram size='0x20000'>\n";
|
||||
xml << " <map mode='linear' address='70-73:8000-ffff'/>\n";
|
||||
xml << " <map mode='linear' address='f0-f3:8000-ffff'/>\n";
|
||||
xml << " </ram>\n";
|
||||
xml << " </slot>\n";
|
||||
xml << " </sufamiturbo>\n";
|
||||
xml.append(" <rom>\n");
|
||||
xml.append(" <map mode='linear' address='00-1f:8000-ffff'/>\n");
|
||||
xml.append(" <map mode='linear' address='80-9f:8000-ffff'/>\n");
|
||||
xml.append(" </rom>\n");
|
||||
xml.append(" <sufamiturbo>\n");
|
||||
xml.append(" <slot id='A'>\n");
|
||||
xml.append(" <rom>\n");
|
||||
xml.append(" <map mode='linear' address='20-3f:8000-ffff'/>\n");
|
||||
xml.append(" <map mode='linear' address='a0-bf:8000-ffff'/>\n");
|
||||
xml.append(" </rom>\n");
|
||||
xml.append(" <ram size='0x20000'>\n");
|
||||
xml.append(" <map mode='linear' address='60-63:8000-ffff'/>\n");
|
||||
xml.append(" <map mode='linear' address='e0-e3:8000-ffff'/>\n");
|
||||
xml.append(" </ram>\n");
|
||||
xml.append(" </slot>\n");
|
||||
xml.append(" <slot id='B'>\n");
|
||||
xml.append(" <rom>\n");
|
||||
xml.append(" <map mode='linear' address='40-5f:8000-ffff'/>\n");
|
||||
xml.append(" <map mode='linear' address='c0-df:8000-ffff'/>\n");
|
||||
xml.append(" </rom>\n");
|
||||
xml.append(" <ram size='0x20000'>\n");
|
||||
xml.append(" <map mode='linear' address='70-73:8000-ffff'/>\n");
|
||||
xml.append(" <map mode='linear' address='f0-f3:8000-ffff'/>\n");
|
||||
xml.append(" </ram>\n");
|
||||
xml.append(" </slot>\n");
|
||||
xml.append(" </sufamiturbo>\n");
|
||||
}
|
||||
|
||||
if(has_srtc) {
|
||||
xml << " <srtc>\n";
|
||||
xml << " <map address='00-3f:2800-2801'/>\n";
|
||||
xml << " <map address='80-bf:2800-2801'/>\n";
|
||||
xml << " </srtc>\n";
|
||||
xml.append(" <srtc>\n");
|
||||
xml.append(" <map address='00-3f:2800-2801'/>\n");
|
||||
xml.append(" <map address='80-bf:2800-2801'/>\n");
|
||||
xml.append(" </srtc>\n");
|
||||
}
|
||||
|
||||
if(has_sdd1) {
|
||||
xml << " <sdd1>\n";
|
||||
xml << " <mcu>\n";
|
||||
xml << " <map address='c0-ff:0000-ffff'/>\n";
|
||||
xml << " </mcu>\n";
|
||||
xml << " <mmio>\n";
|
||||
xml << " <map address='00-3f:4800-4807'/>\n";
|
||||
xml << " <map address='80-bf:4800-4807'/>\n";
|
||||
xml << " </mmio>\n";
|
||||
xml << " </sdd1>\n";
|
||||
xml.append(" <sdd1>\n");
|
||||
xml.append(" <mcu>\n");
|
||||
xml.append(" <map address='c0-ff:0000-ffff'/>\n");
|
||||
xml.append(" </mcu>\n");
|
||||
xml.append(" <mmio>\n");
|
||||
xml.append(" <map address='00-3f:4800-4807'/>\n");
|
||||
xml.append(" <map address='80-bf:4800-4807'/>\n");
|
||||
xml.append(" </mmio>\n");
|
||||
xml.append(" </sdd1>\n");
|
||||
}
|
||||
|
||||
if(has_dsp1) {
|
||||
xml << " <necdsp model='uPD7725' frequency='8000000' program='dsp1b.bin' sha256='4d42db0f36faef263d6b93f508e8c1c4ae8fc2605fd35e3390ecc02905cd420c'>\n";
|
||||
xml.append(" <necdsp model='uPD7725' frequency='8000000' firmware='dsp1b.bin' sha256='4d42db0f36faef263d6b93f508e8c1c4ae8fc2605fd35e3390ecc02905cd420c'>\n");
|
||||
if(dsp1_mapper == DSP1LoROM1MB) {
|
||||
xml << " <dr>\n";
|
||||
xml << " <map address='20-3f:8000-bfff'/>\n";
|
||||
xml << " <map address='a0-bf:8000-bfff'/>\n";
|
||||
xml << " </dr>\n";
|
||||
xml << " <sr>\n";
|
||||
xml << " <map address='20-3f:c000-ffff'/>\n";
|
||||
xml << " <map address='a0-bf:c000-ffff'/>\n";
|
||||
xml << " </sr>\n";
|
||||
xml.append(" <dr>\n");
|
||||
xml.append(" <map address='20-3f:8000-bfff'/>\n");
|
||||
xml.append(" <map address='a0-bf:8000-bfff'/>\n");
|
||||
xml.append(" </dr>\n");
|
||||
xml.append(" <sr>\n");
|
||||
xml.append(" <map address='20-3f:c000-ffff'/>\n");
|
||||
xml.append(" <map address='a0-bf:c000-ffff'/>\n");
|
||||
xml.append(" </sr>\n");
|
||||
} else if(dsp1_mapper == DSP1LoROM2MB) {
|
||||
xml << " <dr>\n";
|
||||
xml << " <map address='60-6f:0000-3fff'/>\n";
|
||||
xml << " <map address='e0-ef:0000-3fff'/>\n";
|
||||
xml << " </dr>\n";
|
||||
xml << " <sr>\n";
|
||||
xml << " <map address='60-6f:4000-7fff'/>\n";
|
||||
xml << " <map address='e0-ef:4000-7fff'/>\n";
|
||||
xml << " </sr>\n";
|
||||
xml.append(" <dr>\n");
|
||||
xml.append(" <map address='60-6f:0000-3fff'/>\n");
|
||||
xml.append(" <map address='e0-ef:0000-3fff'/>\n");
|
||||
xml.append(" </dr>\n");
|
||||
xml.append(" <sr>\n");
|
||||
xml.append(" <map address='60-6f:4000-7fff'/>\n");
|
||||
xml.append(" <map address='e0-ef:4000-7fff'/>\n");
|
||||
xml.append(" </sr>\n");
|
||||
} else if(dsp1_mapper == DSP1HiROM) {
|
||||
xml << " <dr>\n";
|
||||
xml << " <map address='00-1f:6000-6fff'/>\n";
|
||||
xml << " <map address='80-9f:6000-6fff'/>\n";
|
||||
xml << " </dr>\n";
|
||||
xml << " <sr>\n";
|
||||
xml << " <map address='00-1f:7000-7fff'/>\n";
|
||||
xml << " <map address='80-9f:7000-7fff'/>\n";
|
||||
xml << " </sr>\n";
|
||||
xml.append(" <dr>\n");
|
||||
xml.append(" <map address='00-1f:6000-6fff'/>\n");
|
||||
xml.append(" <map address='80-9f:6000-6fff'/>\n");
|
||||
xml.append(" </dr>\n");
|
||||
xml.append(" <sr>\n");
|
||||
xml.append(" <map address='00-1f:7000-7fff'/>\n");
|
||||
xml.append(" <map address='80-9f:7000-7fff'/>\n");
|
||||
xml.append(" </sr>\n");
|
||||
}
|
||||
xml << " </necdsp>\n";
|
||||
xml.append(" </necdsp>\n");
|
||||
}
|
||||
|
||||
if(has_dsp2) {
|
||||
xml << " <necdsp model='uPD7725' frequency='8000000' program='dsp2.bin' sha256='5efbdf96ed0652790855225964f3e90e6a4d466cfa64df25b110933c6cf94ea1'>\n";
|
||||
xml << " <dr>\n";
|
||||
xml << " <map address='20-3f:8000-bfff'/>\n";
|
||||
xml << " <map address='a0-bf:8000-bfff'/>\n";
|
||||
xml << " </dr>\n";
|
||||
xml << " <sr>\n";
|
||||
xml << " <map address='20-3f:c000-ffff'/>\n";
|
||||
xml << " <map address='a0-bf:c000-ffff'/>\n";
|
||||
xml << " </sr>\n";
|
||||
xml << " </necdsp>\n";
|
||||
xml.append(" <necdsp model='uPD7725' frequency='8000000' firmware='dsp2.bin' sha256='5efbdf96ed0652790855225964f3e90e6a4d466cfa64df25b110933c6cf94ea1'>\n");
|
||||
xml.append(" <dr>\n");
|
||||
xml.append(" <map address='20-3f:8000-bfff'/>\n");
|
||||
xml.append(" <map address='a0-bf:8000-bfff'/>\n");
|
||||
xml.append(" </dr>\n");
|
||||
xml.append(" <sr>\n");
|
||||
xml.append(" <map address='20-3f:c000-ffff'/>\n");
|
||||
xml.append(" <map address='a0-bf:c000-ffff'/>\n");
|
||||
xml.append(" </sr>\n");
|
||||
xml.append(" </necdsp>\n");
|
||||
}
|
||||
|
||||
if(has_dsp3) {
|
||||
xml << " <necdsp model='uPD7725' frequency='8000000' program='dsp3.bin' sha256='2e635f72e4d4681148bc35429421c9b946e4f407590e74e31b93b8987b63ba90'>\n";
|
||||
xml << " <dr>\n";
|
||||
xml << " <map address='20-3f:8000-bfff'/>\n";
|
||||
xml << " <map address='a0-bf:8000-bfff'/>\n";
|
||||
xml << " </dr>\n";
|
||||
xml << " <sr>\n";
|
||||
xml << " <map address='20-3f:c000-ffff'/>\n";
|
||||
xml << " <map address='a0-bf:c000-ffff'/>\n";
|
||||
xml << " </sr>\n";
|
||||
xml << " </necdsp>\n";
|
||||
xml.append(" <necdsp model='uPD7725' frequency='8000000' firmware='dsp3.bin' sha256='2e635f72e4d4681148bc35429421c9b946e4f407590e74e31b93b8987b63ba90'>\n");
|
||||
xml.append(" <dr>\n");
|
||||
xml.append(" <map address='20-3f:8000-bfff'/>\n");
|
||||
xml.append(" <map address='a0-bf:8000-bfff'/>\n");
|
||||
xml.append(" </dr>\n");
|
||||
xml.append(" <sr>\n");
|
||||
xml.append(" <map address='20-3f:c000-ffff'/>\n");
|
||||
xml.append(" <map address='a0-bf:c000-ffff'/>\n");
|
||||
xml.append(" </sr>\n");
|
||||
xml.append(" </necdsp>\n");
|
||||
}
|
||||
|
||||
if(has_dsp4) {
|
||||
xml << " <necdsp model='uPD7725' frequency='8000000' program='dsp4.bin' sha256='63ede17322541c191ed1fdf683872554a0a57306496afc43c59de7c01a6e764a'>\n";
|
||||
xml << " <dr>\n";
|
||||
xml << " <map address='30-3f:8000-bfff'/>\n";
|
||||
xml << " <map address='b0-bf:8000-bfff'/>\n";
|
||||
xml << " </dr>\n";
|
||||
xml << " <sr>\n";
|
||||
xml << " <map address='30-3f:c000-ffff'/>\n";
|
||||
xml << " <map address='b0-bf:c000-ffff'/>\n";
|
||||
xml << " </sr>\n";
|
||||
xml << " </necdsp>\n";
|
||||
xml.append(" <necdsp model='uPD7725' frequency='8000000' firmware='dsp4.bin' sha256='63ede17322541c191ed1fdf683872554a0a57306496afc43c59de7c01a6e764a'>\n");
|
||||
xml.append(" <dr>\n");
|
||||
xml.append(" <map address='30-3f:8000-bfff'/>\n");
|
||||
xml.append(" <map address='b0-bf:8000-bfff'/>\n");
|
||||
xml.append(" </dr>\n");
|
||||
xml.append(" <sr>\n");
|
||||
xml.append(" <map address='30-3f:c000-ffff'/>\n");
|
||||
xml.append(" <map address='b0-bf:c000-ffff'/>\n");
|
||||
xml.append(" </sr>\n");
|
||||
xml.append(" </necdsp>\n");
|
||||
}
|
||||
|
||||
if(has_obc1) {
|
||||
xml << " <obc1>\n";
|
||||
xml << " <map address='00-3f:6000-7fff'/>\n";
|
||||
xml << " <map address='80-bf:6000-7fff'/>\n";
|
||||
xml << " </obc1>\n";
|
||||
xml.append(" <obc1>\n");
|
||||
xml.append(" <map address='00-3f:6000-7fff'/>\n");
|
||||
xml.append(" <map address='80-bf:6000-7fff'/>\n");
|
||||
xml.append(" </obc1>\n");
|
||||
}
|
||||
|
||||
if(has_st010) {
|
||||
xml << " <necdsp model='uPD96050' frequency='10000000' program='st0010.bin' sha256='55c697e864562445621cdf8a7bf6e84ae91361e393d382a3704e9aa55559041e'>\n";
|
||||
xml << " <dr>\n";
|
||||
xml << " <map address='60:0000'/>\n";
|
||||
xml << " <map address='e0:0000'/>\n";
|
||||
xml << " </dr>\n";
|
||||
xml << " <sr>\n";
|
||||
xml << " <map address='60:0001'/>\n";
|
||||
xml << " <map address='e0:0001'/>\n";
|
||||
xml << " </sr>\n";
|
||||
xml << " <dp>\n";
|
||||
xml << " <map address='68-6f:0000-0fff'/>\n";
|
||||
xml << " <map address='e8-ef:0000-0fff'/>\n";
|
||||
xml << " </dp>\n";
|
||||
xml << " </necdsp>\n";
|
||||
xml.append(" <necdsp model='uPD96050' frequency='10000000' firmware='st0010.bin' sha256='55c697e864562445621cdf8a7bf6e84ae91361e393d382a3704e9aa55559041e'>\n");
|
||||
xml.append(" <dr>\n");
|
||||
xml.append(" <map address='60:0000'/>\n");
|
||||
xml.append(" <map address='e0:0000'/>\n");
|
||||
xml.append(" </dr>\n");
|
||||
xml.append(" <sr>\n");
|
||||
xml.append(" <map address='60:0001'/>\n");
|
||||
xml.append(" <map address='e0:0001'/>\n");
|
||||
xml.append(" </sr>\n");
|
||||
xml.append(" <dp>\n");
|
||||
xml.append(" <map address='68-6f:0000-0fff'/>\n");
|
||||
xml.append(" <map address='e8-ef:0000-0fff'/>\n");
|
||||
xml.append(" </dp>\n");
|
||||
xml.append(" </necdsp>\n");
|
||||
}
|
||||
|
||||
if(has_st011) {
|
||||
xml << " <necdsp model='uPD96050' frequency='15000000' program='st0011.bin' sha256='651b82a1e26c4fa8dd549e91e7f923012ed2ca54c1d9fd858655ab30679c2f0e'>\n";
|
||||
xml << " <dr>\n";
|
||||
xml << " <map address='60:0000'/>\n";
|
||||
xml << " <map address='e0:0000'/>\n";
|
||||
xml << " </dr>\n";
|
||||
xml << " <sr>\n";
|
||||
xml << " <map address='60:0001'/>\n";
|
||||
xml << " <map address='e0:0001'/>\n";
|
||||
xml << " </sr>\n";
|
||||
xml << " <dp>\n";
|
||||
xml << " <map address='68-6f:0000-0fff'/>\n";
|
||||
xml << " <map address='e8-ef:0000-0fff'/>\n";
|
||||
xml << " </dp>\n";
|
||||
xml << " </necdsp>\n";
|
||||
xml.append(" <necdsp model='uPD96050' frequency='15000000' firmware='st0011.bin' sha256='651b82a1e26c4fa8dd549e91e7f923012ed2ca54c1d9fd858655ab30679c2f0e'>\n");
|
||||
xml.append(" <dr>\n");
|
||||
xml.append(" <map address='60:0000'/>\n");
|
||||
xml.append(" <map address='e0:0000'/>\n");
|
||||
xml.append(" </dr>\n");
|
||||
xml.append(" <sr>\n");
|
||||
xml.append(" <map address='60:0001'/>\n");
|
||||
xml.append(" <map address='e0:0001'/>\n");
|
||||
xml.append(" </sr>\n");
|
||||
xml.append(" <dp>\n");
|
||||
xml.append(" <map address='68-6f:0000-0fff'/>\n");
|
||||
xml.append(" <map address='e8-ef:0000-0fff'/>\n");
|
||||
xml.append(" </dp>\n");
|
||||
xml.append(" </necdsp>\n");
|
||||
}
|
||||
|
||||
if(has_st018) {
|
||||
xml << " <setarisc program='ST-0018'>\n";
|
||||
xml << " <map address='00-3f:3800-38ff'/>\n";
|
||||
xml << " <map address='80-bf:3800-38ff'/>\n";
|
||||
xml << " </setarisc>\n";
|
||||
xml.append(" <setarisc firmware='ST-0018'>\n");
|
||||
xml.append(" <map address='00-3f:3800-38ff'/>\n");
|
||||
xml.append(" <map address='80-bf:3800-38ff'/>\n");
|
||||
xml.append(" </setarisc>\n");
|
||||
}
|
||||
|
||||
xml << "</cartridge>\n";
|
||||
xml.append("</cartridge>\n");
|
||||
xmlMemoryMap = xml.transform("'", "\"");
|
||||
}
|
||||
|
||||
|
29
bsnes/nall/stack.hpp
Executable file
29
bsnes/nall/stack.hpp
Executable file
@@ -0,0 +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 : public linear_vector<T> {
|
||||
void push(const T &value) {
|
||||
linear_vector<T>::append(value);
|
||||
}
|
||||
|
||||
T pull() {
|
||||
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;
|
||||
}
|
||||
|
||||
T& operator()() {
|
||||
if(linear_vector<T>::size() == 0) throw;
|
||||
return linear_vector<T>::operator[](linear_vector<T>::size() - 1);
|
||||
}
|
||||
};
|
||||
|
||||
template<typename T> struct has_size<stack<T>> { enum { value = true }; };
|
||||
}
|
||||
|
||||
#endif
|
@@ -2,7 +2,9 @@
|
||||
#define NALL_STRING_HPP
|
||||
|
||||
#include <initializer_list>
|
||||
#include <nall/array.hpp>
|
||||
#include <nall/platform.hpp>
|
||||
#include <nall/sha256.hpp>
|
||||
#include <nall/utility.hpp>
|
||||
|
||||
#include <nall/string/base.hpp>
|
||||
|
@@ -6,12 +6,14 @@
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <nall/concept.hpp>
|
||||
#include <nall/function.hpp>
|
||||
#include <nall/stdint.hpp>
|
||||
#include <nall/utf8.hpp>
|
||||
#include <nall/vector.hpp>
|
||||
#include <nall/windows/utf8.hpp>
|
||||
|
||||
namespace nall {
|
||||
class string;
|
||||
class lstring;
|
||||
template<typename T> inline const char* to_string(T);
|
||||
|
||||
class string {
|
||||
@@ -20,13 +22,13 @@ namespace nall {
|
||||
|
||||
template<typename... Args> inline string& assign(Args&&... args);
|
||||
template<typename... Args> inline string& append(Args&&... args);
|
||||
inline string& assign_(const char*);
|
||||
inline string& append_(const char*);
|
||||
|
||||
inline bool readfile(const string&);
|
||||
|
||||
inline string& replace (const char*, const char*);
|
||||
inline string& qreplace(const char*, const char*);
|
||||
template<unsigned Limit = 0> inline string& replace(const char*, const char*);
|
||||
template<unsigned Limit = 0> inline string& ireplace(const char*, const char*);
|
||||
template<unsigned Limit = 0> inline string& qreplace(const char*, const char*);
|
||||
template<unsigned Limit = 0> inline string& iqreplace(const char*, const char*);
|
||||
|
||||
inline unsigned length() const;
|
||||
|
||||
@@ -43,17 +45,18 @@ namespace nall {
|
||||
|
||||
inline string& lower();
|
||||
inline string& upper();
|
||||
inline string& qlower();
|
||||
inline string& qupper();
|
||||
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 = " ");
|
||||
template<unsigned limit = 0> inline string& trim(const char *key = " ", const char *rkey = 0);
|
||||
|
||||
inline optional<unsigned> position(const char *key) const;
|
||||
inline optional<unsigned> iposition(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);
|
||||
inline optional<unsigned> iqposition(const char *key) const;
|
||||
|
||||
inline operator const char*() const;
|
||||
inline char* operator()();
|
||||
@@ -74,10 +77,16 @@ namespace nall {
|
||||
inline string(string&&);
|
||||
inline ~string();
|
||||
|
||||
//internal functions
|
||||
inline string& assign_(const char*);
|
||||
inline string& append_(const char*);
|
||||
|
||||
protected:
|
||||
char *data;
|
||||
unsigned size;
|
||||
|
||||
template<unsigned Limit, bool Insensitive, bool Quoted> inline string& ureplace(const char*, const char*);
|
||||
|
||||
#if defined(QSTRING_H)
|
||||
public:
|
||||
inline operator QString() const;
|
||||
@@ -89,36 +98,43 @@ namespace nall {
|
||||
template<typename T> inline lstring& operator<<(T value);
|
||||
|
||||
inline optional<unsigned> find(const char*) const;
|
||||
template<unsigned limit = 0> inline void split (const char*, const char*);
|
||||
template<unsigned limit = 0> inline void qsplit(const char*, const char*);
|
||||
template<unsigned Limit = 0> inline lstring& split(const char*, const char*);
|
||||
template<unsigned Limit = 0> inline lstring& isplit(const char*, const char*);
|
||||
template<unsigned Limit = 0> inline lstring& qsplit(const char*, const char*);
|
||||
template<unsigned Limit = 0> inline lstring& iqsplit(const char*, const char*);
|
||||
|
||||
lstring();
|
||||
lstring(std::initializer_list<string>);
|
||||
|
||||
protected:
|
||||
template<unsigned Limit, bool Insensitive, bool Quoted> inline lstring& usplit(const char*, const char*);
|
||||
};
|
||||
|
||||
//compare.hpp
|
||||
inline char chrlower(char c);
|
||||
inline char chrupper(char c);
|
||||
inline int stricmp(const char *str1, const char *str2);
|
||||
inline int istrcmp(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 stribegin(const char *str, const char *key);
|
||||
inline bool strend (const char *str, const char *key);
|
||||
inline bool striend(const char *str, const char *key);
|
||||
inline bool strbegin(const char *str, const char *key);
|
||||
inline bool istrbegin(const char *str, const char *key);
|
||||
inline bool strend(const char *str, const char *key);
|
||||
inline bool istrend(const char *str, const char *key);
|
||||
|
||||
//convert.hpp
|
||||
inline char* strlower(char *str);
|
||||
inline char* strupper(char *str);
|
||||
inline char* qstrlower(char *str);
|
||||
inline char* qstrupper(char *str);
|
||||
inline char* strtr(char *dest, const char *before, const char *after);
|
||||
inline uintmax_t hex (const char *str);
|
||||
inline intmax_t integer(const char *str);
|
||||
inline uintmax_t hex(const char *str);
|
||||
inline intmax_t integer(const char *str);
|
||||
inline uintmax_t decimal(const char *str);
|
||||
inline uintmax_t binary (const char *str);
|
||||
inline double fp (const char *str);
|
||||
inline uintmax_t binary(const char *str);
|
||||
inline double fp(const char *str);
|
||||
|
||||
//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);
|
||||
|
||||
//platform.hpp
|
||||
@@ -132,26 +148,31 @@ namespace nall {
|
||||
|
||||
//strpos.hpp
|
||||
inline optional<unsigned> strpos(const char *str, const char *key);
|
||||
inline optional<unsigned> istrpos(const char *str, const char *key);
|
||||
inline optional<unsigned> qstrpos(const char *str, const char *key);
|
||||
inline optional<unsigned> iqstrpos(const char *str, const char *key);
|
||||
template<bool Insensitive = false, bool Quoted = false> inline optional<unsigned> ustrpos(const char *str, const char *key);
|
||||
|
||||
//trim.hpp
|
||||
template<unsigned limit = 0> inline char* ltrim(char *str, const char *key = " ");
|
||||
template<unsigned limit = 0> inline char* rtrim(char *str, const char *key = " ");
|
||||
template<unsigned limit = 0> inline char* trim (char *str, const char *key = " ");
|
||||
template<unsigned limit = 0> inline char* trim(char *str, const char *key = " ", const char *rkey = 0);
|
||||
|
||||
//utility.hpp
|
||||
template<bool Insensitive> alwaysinline bool chrequal(char x, char y);
|
||||
template<bool Quoted, typename T> alwaysinline bool quoteskip(T *&p);
|
||||
template<bool Quoted, typename T> alwaysinline bool quotecopy(char *&t, T *&p);
|
||||
inline unsigned strlcpy(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 = ~0u);
|
||||
inline string sha256(const uint8_t *data, unsigned size);
|
||||
|
||||
inline string integer(intmax_t value);
|
||||
template<unsigned length = 0> inline string linteger(intmax_t value);
|
||||
template<unsigned length = 0> inline string rinteger(intmax_t value);
|
||||
inline string decimal(uintmax_t value);
|
||||
template<unsigned length = 0> inline string ldecimal(uintmax_t value);
|
||||
template<unsigned length = 0> inline string rdecimal(uintmax_t value);
|
||||
template<unsigned length = 0> inline string hex(uintmax_t value);
|
||||
template<unsigned length = 0> inline string binary(uintmax_t value);
|
||||
template<unsigned length = 0, char padding = ' '> inline string integer(intmax_t value);
|
||||
template<unsigned length = 0, char padding = ' '> inline string linteger(intmax_t value);
|
||||
template<unsigned length = 0, char padding = ' '> inline string decimal(uintmax_t value);
|
||||
template<unsigned length = 0, char padding = ' '> inline string ldecimal(uintmax_t value);
|
||||
template<unsigned length = 0, char padding = '0'> inline string hex(uintmax_t value);
|
||||
template<unsigned length = 0, char padding = '0'> inline string binary(uintmax_t value);
|
||||
inline unsigned fp(char *str, double value);
|
||||
inline string fp(double value);
|
||||
|
||||
|
@@ -15,9 +15,6 @@ template<> inline const char* to_string<const char*> (const char *v) { return
|
||||
template<> inline const char* to_string<string> (string v) { return v; }
|
||||
template<> inline const char* to_string<const string&>(const string &v) { return v; }
|
||||
|
||||
template<typename T> string& string::operator= (T value) { return assign(to_string<T>(value)); }
|
||||
template<typename T> string& string::operator<<(T value) { return append(to_string<T>(value)); }
|
||||
|
||||
template<typename T> lstring& lstring::operator<<(T value) {
|
||||
operator[](size()).assign(to_string<T>(value));
|
||||
return *this;
|
||||
|
@@ -11,7 +11,7 @@ char chrupper(char c) {
|
||||
return (c >= 'a' && c <= 'z') ? c - ('a' - 'A') : c;
|
||||
}
|
||||
|
||||
int stricmp(const char *str1, const char *str2) {
|
||||
int istrcmp(const char *str1, const char *str2) {
|
||||
while(*str1) {
|
||||
if(chrlower(*str1) != chrlower(*str2)) break;
|
||||
str1++, str2++;
|
||||
@@ -66,7 +66,7 @@ bool strbegin(const char *str, const char *key) {
|
||||
return (!memcmp(str, key, ksl));
|
||||
}
|
||||
|
||||
bool stribegin(const char *str, const char *key) {
|
||||
bool istrbegin(const char *str, const char *key) {
|
||||
int ssl = strlen(str), ksl = strlen(key);
|
||||
|
||||
if(ksl > ssl) return false;
|
||||
@@ -89,7 +89,7 @@ bool strend(const char *str, const char *key) {
|
||||
return (!memcmp(str + ssl - ksl, key, ksl));
|
||||
}
|
||||
|
||||
bool striend(const char *str, const char *key) {
|
||||
bool istrend(const char *str, const char *key) {
|
||||
int ssl = strlen(str), ksl = strlen(key);
|
||||
|
||||
if(ksl > ssl) return false;
|
||||
|
@@ -23,6 +23,26 @@ char* strupper(char *str) {
|
||||
return str;
|
||||
}
|
||||
|
||||
char* qstrlower(char *s) {
|
||||
if(!s) return 0;
|
||||
bool quoted = false;
|
||||
while(*s) {
|
||||
if(*s == '\"' || *s == '\'') quoted ^= 1;
|
||||
if(quoted == false && *s >= 'A' && *s <= 'Z') *s += 0x20;
|
||||
s++;
|
||||
}
|
||||
}
|
||||
|
||||
char* qstrupper(char *s) {
|
||||
if(!s) return 0;
|
||||
bool quoted = false;
|
||||
while(*s) {
|
||||
if(*s == '\"' || *s == '\'') quoted ^= 1;
|
||||
if(quoted == false && *s >= 'a' && *s <= 'z') *s -= 0x20;
|
||||
s++;
|
||||
}
|
||||
}
|
||||
|
||||
char* strtr(char *dest, const char *before, const char *after) {
|
||||
if(!dest || !before || !after) return dest;
|
||||
int sl = strlen(dest), bsl = strlen(before), asl = strlen(after);
|
||||
|
@@ -3,6 +3,8 @@
|
||||
|
||||
namespace nall {
|
||||
|
||||
static function<int64_t (const char *&)> eval_fallback;
|
||||
|
||||
static int eval_integer(const char *&s) {
|
||||
if(!*s) throw "unrecognized_integer";
|
||||
int value = 0, x = *s, y = *(s + 1);
|
||||
@@ -58,7 +60,7 @@ static int eval_integer(const char *&s) {
|
||||
}
|
||||
|
||||
static int eval(const char *&s, int depth = 0) {
|
||||
while(*s == ' ' || *s == '\t') s++; //trim whitespace
|
||||
while(*s == ' ' || *s == '\t') s++; //trim whitespace
|
||||
if(!*s) throw "unrecognized_token";
|
||||
int value = 0, x = *s, y = *(s + 1);
|
||||
|
||||
@@ -74,10 +76,12 @@ static int eval(const char *&s, int depth = 0) {
|
||||
|
||||
else if((x >= '0' && x <= '9') || x == '\'') value = eval_integer(s);
|
||||
|
||||
else if(eval_fallback) value = eval_fallback(s); //optional user-defined syntax parsing
|
||||
|
||||
else throw "unrecognized_token";
|
||||
|
||||
while(true) {
|
||||
while(*s == ' ' || *s == '\t') s++; //trim whitespace
|
||||
while(*s == ' ' || *s == '\t') s++; //trim whitespace
|
||||
if(!*s) break;
|
||||
x = *s, y = *(s + 1);
|
||||
|
||||
|
@@ -3,100 +3,49 @@
|
||||
|
||||
namespace nall {
|
||||
|
||||
string& string::replace(const char *key, const char *token) {
|
||||
int i, z, ksl = strlen(key), tsl = strlen(token), ssl = length();
|
||||
unsigned int replace_count = 0, size = ssl;
|
||||
char *buffer;
|
||||
template<unsigned Limit, bool Insensitive, bool Quoted>
|
||||
string& string::ureplace(const char *key, const char *token) {
|
||||
if(!key || !*key) return *this;
|
||||
enum : unsigned { limit = Limit ? Limit : ~0u };
|
||||
|
||||
if(ksl <= ssl) {
|
||||
if(tsl > ksl) { //the new string may be longer than the old string...
|
||||
for(i = 0; i <= ssl - ksl;) { //so let's find out how big of a string we'll need...
|
||||
if(!memcmp(data + i, key, ksl)) {
|
||||
replace_count++;
|
||||
i += ksl;
|
||||
} else i++;
|
||||
}
|
||||
size = ssl + ((tsl - ksl) * replace_count);
|
||||
reserve(size);
|
||||
const char *p = data;
|
||||
unsigned counter = 0, keyLength = 0;
|
||||
|
||||
while(*p) {
|
||||
if(quoteskip<Quoted>(p)) continue;
|
||||
for(unsigned n = 0;; n++) {
|
||||
if(key[n] == 0) { counter++; p += n; keyLength = n; break; }
|
||||
if(!chrequal<Insensitive>(key[n], p[n])) { p++; break; }
|
||||
}
|
||||
|
||||
buffer = new char[size + 1];
|
||||
for(i = z = 0; i < ssl;) {
|
||||
if(i <= ssl - ksl) {
|
||||
if(!memcmp(data + i, key, ksl)) {
|
||||
memcpy(buffer + z, token, tsl);
|
||||
z += tsl;
|
||||
i += ksl;
|
||||
} else buffer[z++] = data[i++];
|
||||
} else buffer[z++] = data[i++];
|
||||
}
|
||||
buffer[z] = 0;
|
||||
|
||||
assign(buffer);
|
||||
delete[] buffer;
|
||||
}
|
||||
if(counter == 0) return *this;
|
||||
if(Limit) counter = min(counter, Limit);
|
||||
|
||||
char *t = data, *base;
|
||||
unsigned tokenLength = strlen(token);
|
||||
if(tokenLength > keyLength) {
|
||||
t = base = strdup(data);
|
||||
reserve((unsigned)(p - data) + ((tokenLength - keyLength) * counter));
|
||||
}
|
||||
char *o = data;
|
||||
|
||||
while(*t && counter) {
|
||||
if(quotecopy<Quoted>(o, t)) continue;
|
||||
for(unsigned n = 0;; n++) {
|
||||
if(key[n] == 0) { counter--; memcpy(o, token, tokenLength); t += keyLength; o += tokenLength; break; }
|
||||
if(!chrequal<Insensitive>(key[n], t[n])) { *o++ = *t++; break; }
|
||||
}
|
||||
}
|
||||
do *o++ = *t; while(*t++);
|
||||
if(tokenLength > keyLength) free(base);
|
||||
|
||||
return *this;
|
||||
}
|
||||
|
||||
string& string::qreplace(const char *key, const char *token) {
|
||||
int i, l, z, ksl = strlen(key), tsl = strlen(token), ssl = length();
|
||||
unsigned int replace_count = 0, size = ssl;
|
||||
uint8_t x;
|
||||
char *buffer;
|
||||
|
||||
if(ksl <= ssl) {
|
||||
if(tsl > ksl) {
|
||||
for(i = 0; i <= ssl - ksl;) {
|
||||
x = data[i];
|
||||
if(x == '\"' || x == '\'') {
|
||||
l = i;
|
||||
i++;
|
||||
while(data[i++] != x) {
|
||||
if(i == ssl) {
|
||||
i = l;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
if(!memcmp(data + i, key, ksl)) {
|
||||
replace_count++;
|
||||
i += ksl;
|
||||
} else i++;
|
||||
}
|
||||
size = ssl + ((tsl - ksl) * replace_count);
|
||||
reserve(size);
|
||||
}
|
||||
|
||||
buffer = new char[size + 1];
|
||||
for(i = z = 0; i < ssl;) {
|
||||
x = data[i];
|
||||
if(x == '\"' || x == '\'') {
|
||||
l = i++;
|
||||
while(data[i] != x && i < ssl)i++;
|
||||
if(i >= ssl)i = l;
|
||||
else {
|
||||
memcpy(buffer + z, data + l, i - l);
|
||||
z += i - l;
|
||||
}
|
||||
}
|
||||
if(i <= ssl - ksl) {
|
||||
if(!memcmp(data + i, key, ksl)) {
|
||||
memcpy(buffer + z, token, tsl);
|
||||
z += tsl;
|
||||
i += ksl;
|
||||
replace_count++;
|
||||
} else buffer[z++] = data[i++];
|
||||
} else buffer[z++] = data[i++];
|
||||
}
|
||||
buffer[z] = 0;
|
||||
|
||||
assign(buffer);
|
||||
delete[] buffer;
|
||||
}
|
||||
|
||||
return *this;
|
||||
}
|
||||
template<unsigned Limit> string &string::replace(const char *key, const char *token) { return ureplace<Limit, false, false>(key, token); }
|
||||
template<unsigned Limit> string &string::ireplace(const char *key, const char *token) { return ureplace<Limit, true, false>(key, token); }
|
||||
template<unsigned Limit> string &string::qreplace(const char *key, const char *token) { return ureplace<Limit, false, true>(key, token); }
|
||||
template<unsigned Limit> string &string::iqreplace(const char *key, const char *token) { return ureplace<Limit, true, true>(key, token); }
|
||||
|
||||
};
|
||||
|
||||
|
@@ -3,56 +3,36 @@
|
||||
|
||||
namespace nall {
|
||||
|
||||
template<unsigned Limit> void lstring::split(const char *key, const char *src) {
|
||||
unsigned limit = Limit;
|
||||
template<unsigned Limit, bool Insensitive, bool Quoted> lstring& lstring::usplit(const char *key, const char *base) {
|
||||
reset();
|
||||
if(!key || !*key) return *this;
|
||||
|
||||
int ssl = strlen(src), ksl = strlen(key);
|
||||
int lp = 0, split_count = 0;
|
||||
const char *p = base;
|
||||
unsigned counter = 0;
|
||||
|
||||
for(int i = 0; i <= ssl - ksl;) {
|
||||
if(!memcmp(src + i, key, ksl)) {
|
||||
strlcpy(operator[](split_count++), src + lp, i - lp + 1);
|
||||
i += ksl;
|
||||
lp = i;
|
||||
if(!--limit) break;
|
||||
} else i++;
|
||||
}
|
||||
|
||||
operator[](split_count++) = src + lp;
|
||||
}
|
||||
|
||||
template<unsigned Limit> void lstring::qsplit(const char *key, const char *src) {
|
||||
unsigned limit = Limit;
|
||||
reset();
|
||||
|
||||
int ssl = strlen(src), ksl = strlen(key);
|
||||
int lp = 0, split_count = 0;
|
||||
|
||||
for(int i = 0; i <= ssl - ksl;) {
|
||||
uint8_t x = src[i];
|
||||
|
||||
if(x == '\"' || x == '\'') {
|
||||
int z = i++; //skip opening quote
|
||||
while(i < ssl && src[i] != x) i++;
|
||||
if(i >= ssl) i = z; //failed match, rewind i
|
||||
else {
|
||||
i++; //skip closing quote
|
||||
continue; //restart in case next char is also a quote
|
||||
while(*p) {
|
||||
if(Limit) if(counter >= Limit) break;
|
||||
if(quoteskip<Quoted>(p)) continue;
|
||||
for(unsigned n = 0;; n++) {
|
||||
if(key[n] == 0) {
|
||||
strlcpy(operator[](counter++), base, (unsigned)(p - base + 1));
|
||||
p += n;
|
||||
base = p;
|
||||
break;
|
||||
}
|
||||
if(!chrequal<Insensitive>(key[n], p[n])) { p++; break; }
|
||||
}
|
||||
|
||||
if(!memcmp(src + i, key, ksl)) {
|
||||
strlcpy(operator[](split_count++), src + lp, i - lp + 1);
|
||||
i += ksl;
|
||||
lp = i;
|
||||
if(!--limit) break;
|
||||
} else i++;
|
||||
}
|
||||
|
||||
operator[](split_count++) = src + lp;
|
||||
operator[](counter) = base;
|
||||
return *this;
|
||||
}
|
||||
|
||||
template<unsigned Limit> lstring& lstring::split(const char *key, const char *src) { return usplit<Limit, false, false>(key, src); }
|
||||
template<unsigned Limit> lstring& lstring::isplit(const char *key, const char *src) { return usplit<Limit, true, false>(key, src); }
|
||||
template<unsigned Limit> lstring& lstring::qsplit(const char *key, const char *src) { return usplit<Limit, false, true>(key, src); }
|
||||
template<unsigned Limit> lstring& lstring::iqsplit(const char *key, const char *src) { return usplit<Limit, true, true>(key, src); }
|
||||
|
||||
};
|
||||
|
||||
#endif
|
||||
|
@@ -2,40 +2,33 @@
|
||||
#define NALL_STRING_STRPOS_HPP
|
||||
|
||||
//usage example:
|
||||
//if(auto pos = strpos(str, key)) print(pos(), "\n");
|
||||
//prints position of key within str, only if it is found
|
||||
//if(auto position = strpos(str, key)) print(position(), "\n");
|
||||
//prints position of key within str; but only if it is found
|
||||
|
||||
namespace nall {
|
||||
|
||||
optional<unsigned> strpos(const char *str, const char *key) {
|
||||
unsigned ssl = strlen(str), ksl = strlen(key);
|
||||
if(ksl > ssl) return { false, 0 };
|
||||
template<bool Insensitive, bool Quoted>
|
||||
optional<unsigned> ustrpos(const char *str, const char *key) {
|
||||
const char *base = str;
|
||||
|
||||
for(unsigned i = 0; i <= ssl - ksl; i++) {
|
||||
if(!memcmp(str + i, key, ksl)) return { true, i };
|
||||
}
|
||||
|
||||
return { false, 0 };
|
||||
}
|
||||
|
||||
optional<unsigned> qstrpos(const char *str, const char *key) {
|
||||
unsigned ssl = strlen(str), ksl = strlen(key);
|
||||
if(ksl > ssl) return { false, 0 };
|
||||
|
||||
for(unsigned i = 0; i <= ssl - ksl;) {
|
||||
uint8_t x = str[i];
|
||||
if(x == '\"' || x == '\'') {
|
||||
uint8_t z = i++;
|
||||
while(str[i] != x && i < ssl) i++;
|
||||
if(i >= ssl) i = z;
|
||||
while(*str) {
|
||||
if(quoteskip<Quoted>(str)) continue;
|
||||
for(unsigned n = 0;; n++) {
|
||||
if(key[n] == 0) return { true, (unsigned)(str - base) };
|
||||
if(str[n] == 0) return { false, 0 };
|
||||
if(!chrequal<Insensitive>(str[n], key[n])) break;
|
||||
}
|
||||
if(!memcmp(str + i, key, ksl)) return { true, i };
|
||||
i++;
|
||||
str++;
|
||||
}
|
||||
|
||||
return { false, 0 };
|
||||
}
|
||||
|
||||
optional<unsigned> strpos(const char *str, const char *key) { return ustrpos<false, false>(str, key); }
|
||||
optional<unsigned> istrpos(const char *str, const char *key) { return ustrpos<true, false>(str, key); }
|
||||
optional<unsigned> qstrpos(const char *str, const char *key) { return ustrpos<false, true>(str, key); }
|
||||
optional<unsigned> iqstrpos(const char *str, const char *key) { return ustrpos<true, true>(str, key); }
|
||||
|
||||
}
|
||||
|
||||
#endif
|
||||
|
@@ -29,7 +29,8 @@ template<unsigned Limit> char* rtrim(char *str, const char *key) {
|
||||
return str;
|
||||
}
|
||||
|
||||
template<unsigned limit> char* trim(char *str, const char *key) {
|
||||
template<unsigned limit> char* trim(char *str, const char *key, const char *rkey) {
|
||||
if(rkey) return ltrim<limit>(rtrim<limit>(str, rkey), key);
|
||||
return ltrim<limit>(rtrim<limit>(str, key), key);
|
||||
}
|
||||
|
||||
|
@@ -3,6 +3,38 @@
|
||||
|
||||
namespace nall {
|
||||
|
||||
template<bool Insensitive>
|
||||
bool chrequal(char x, char y) {
|
||||
if(Insensitive) return chrlower(x) == chrlower(y);
|
||||
return x == y;
|
||||
}
|
||||
|
||||
template<bool Quoted, typename T>
|
||||
bool quoteskip(T *&p) {
|
||||
if(Quoted == false) return false;
|
||||
if(*p != '\'' && *p != '\"') return false;
|
||||
|
||||
while(*p == '\'' || *p == '\"') {
|
||||
char x = *p++;
|
||||
while(*p && *p++ != x);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
template<bool Quoted, typename T>
|
||||
bool quotecopy(char *&t, T *&p) {
|
||||
if(Quoted == false) return false;
|
||||
if(*p != '\'' && *p != '\"') return false;
|
||||
|
||||
while(*p == '\'' || *p == '\"') {
|
||||
char x = *p++;
|
||||
*t++ = x;
|
||||
while(*p && *p != x) *t++ = *p++;
|
||||
*t++ = *p++;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
unsigned strlcpy(string &dest, const char *src, unsigned length) {
|
||||
dest.reserve(length);
|
||||
return strlcpy(dest(), src, length);
|
||||
@@ -15,7 +47,7 @@ unsigned strlcat(string &dest, const char *src, unsigned length) {
|
||||
|
||||
string substr(const char *src, unsigned start, unsigned length) {
|
||||
string dest;
|
||||
if(length == 0) {
|
||||
if(length == ~0u) {
|
||||
//copy entire string
|
||||
dest = src + start;
|
||||
} else {
|
||||
@@ -25,35 +57,21 @@ string substr(const char *src, unsigned start, unsigned length) {
|
||||
return dest;
|
||||
}
|
||||
|
||||
string sha256(const uint8_t *data, unsigned size) {
|
||||
sha256_ctx sha;
|
||||
uint8_t hash[32];
|
||||
sha256_init(&sha);
|
||||
sha256_chunk(&sha, data, size);
|
||||
sha256_final(&sha);
|
||||
sha256_hash(&sha, hash);
|
||||
string result;
|
||||
foreach(byte, hash) result.append(hex<2>(byte));
|
||||
return result;
|
||||
}
|
||||
|
||||
/* arithmetic <> string */
|
||||
|
||||
string integer(intmax_t value) {
|
||||
bool negative = value < 0;
|
||||
if(negative) value = abs(value);
|
||||
|
||||
char buffer[64];
|
||||
unsigned size = 0;
|
||||
|
||||
do {
|
||||
unsigned n = value % 10;
|
||||
buffer[size++] = '0' + n;
|
||||
value /= 10;
|
||||
} while(value);
|
||||
buffer[size++] = negative ? '-' : '+';
|
||||
buffer[size] = 0;
|
||||
|
||||
char result[size + 1];
|
||||
memset(result, '0', size);
|
||||
result[size] = 0;
|
||||
|
||||
for(signed x = size - 1, y = 0; x >= 0 && y < size; x--, y++) {
|
||||
result[x] = buffer[y];
|
||||
}
|
||||
|
||||
return (const char*)result;
|
||||
}
|
||||
|
||||
template<unsigned length_> string linteger(intmax_t value) {
|
||||
template<unsigned length_, char padding> string integer(intmax_t value) {
|
||||
bool negative = value < 0;
|
||||
if(negative) value = abs(value);
|
||||
|
||||
@@ -70,34 +88,7 @@ template<unsigned length_> string linteger(intmax_t value) {
|
||||
|
||||
unsigned length = (length_ == 0 ? size : length_);
|
||||
char result[length + 1];
|
||||
memset(result, ' ', length);
|
||||
result[length] = 0;
|
||||
|
||||
for(signed x = 0, y = size - 1; x < length && y >= 0; x++, y--) {
|
||||
result[x] = buffer[y];
|
||||
}
|
||||
|
||||
return (const char*)result;
|
||||
}
|
||||
|
||||
template<unsigned length_> string rinteger(intmax_t value) {
|
||||
bool negative = value < 0;
|
||||
if(negative) value = abs(value);
|
||||
|
||||
char buffer[64];
|
||||
unsigned size = 0;
|
||||
|
||||
do {
|
||||
unsigned n = value % 10;
|
||||
buffer[size++] = '0' + n;
|
||||
value /= 10;
|
||||
} while(value);
|
||||
buffer[size++] = negative ? '-' : '+';
|
||||
buffer[size] = 0;
|
||||
|
||||
unsigned length = (length_ == 0 ? size : length_);
|
||||
char result[length + 1];
|
||||
memset(result, ' ', length);
|
||||
memset(result, padding, length);
|
||||
result[length] = 0;
|
||||
|
||||
for(signed x = length - 1, y = 0; x >= 0 && y < size; x--, y++) {
|
||||
@@ -107,29 +98,10 @@ template<unsigned length_> string rinteger(intmax_t value) {
|
||||
return (const char*)result;
|
||||
}
|
||||
|
||||
string decimal(uintmax_t value) {
|
||||
char buffer[64];
|
||||
unsigned size = 0;
|
||||
|
||||
do {
|
||||
unsigned n = value % 10;
|
||||
buffer[size++] = '0' + n;
|
||||
value /= 10;
|
||||
} while(value);
|
||||
buffer[size] = 0;
|
||||
|
||||
char result[size + 1];
|
||||
memset(result, '0', size);
|
||||
result[size] = 0;
|
||||
|
||||
for(signed x = size - 1, y = 0; x >= 0 && y < size; x--, y++) {
|
||||
result[x] = buffer[y];
|
||||
}
|
||||
|
||||
return (const char*)result;
|
||||
}
|
||||
|
||||
template<unsigned length_> string ldecimal(uintmax_t value) {
|
||||
template<unsigned length_, char padding> string linteger(intmax_t value) {
|
||||
bool negative = value < 0;
|
||||
if(negative) value = abs(value);
|
||||
|
||||
char buffer[64];
|
||||
unsigned size = 0;
|
||||
|
||||
@@ -138,11 +110,12 @@ template<unsigned length_> string ldecimal(uintmax_t value) {
|
||||
buffer[size++] = '0' + n;
|
||||
value /= 10;
|
||||
} while(value);
|
||||
buffer[size++] = negative ? '-' : '+';
|
||||
buffer[size] = 0;
|
||||
|
||||
unsigned length = (length_ == 0 ? size : length_);
|
||||
char result[length + 1];
|
||||
memset(result, ' ', length);
|
||||
memset(result, padding, length);
|
||||
result[length] = 0;
|
||||
|
||||
for(signed x = 0, y = size - 1; x < length && y >= 0; x++, y--) {
|
||||
@@ -152,7 +125,7 @@ template<unsigned length_> string ldecimal(uintmax_t value) {
|
||||
return (const char*)result;
|
||||
}
|
||||
|
||||
template<unsigned length_> string rdecimal(uintmax_t value) {
|
||||
template<unsigned length_, char padding> string decimal(uintmax_t value) {
|
||||
char buffer[64];
|
||||
unsigned size = 0;
|
||||
|
||||
@@ -165,7 +138,7 @@ template<unsigned length_> string rdecimal(uintmax_t value) {
|
||||
|
||||
unsigned length = (length_ == 0 ? size : length_);
|
||||
char result[length + 1];
|
||||
memset(result, ' ', length);
|
||||
memset(result, padding, length);
|
||||
result[length] = 0;
|
||||
|
||||
for(signed x = length - 1, y = 0; x >= 0 && y < size; x--, y++) {
|
||||
@@ -175,7 +148,30 @@ template<unsigned length_> string rdecimal(uintmax_t value) {
|
||||
return (const char*)result;
|
||||
}
|
||||
|
||||
template<unsigned length_> string hex(uintmax_t value) {
|
||||
template<unsigned length_, char padding> string ldecimal(uintmax_t value) {
|
||||
char buffer[64];
|
||||
unsigned size = 0;
|
||||
|
||||
do {
|
||||
unsigned n = value % 10;
|
||||
buffer[size++] = '0' + n;
|
||||
value /= 10;
|
||||
} while(value);
|
||||
buffer[size] = 0;
|
||||
|
||||
unsigned length = (length_ == 0 ? size : length_);
|
||||
char result[length + 1];
|
||||
memset(result, padding, length);
|
||||
result[length] = 0;
|
||||
|
||||
for(signed x = 0, y = size - 1; x < length && y >= 0; x++, y--) {
|
||||
result[x] = buffer[y];
|
||||
}
|
||||
|
||||
return (const char*)result;
|
||||
}
|
||||
|
||||
template<unsigned length_, char padding> string hex(uintmax_t value) {
|
||||
char buffer[64];
|
||||
unsigned size = 0;
|
||||
|
||||
@@ -187,7 +183,7 @@ template<unsigned length_> string hex(uintmax_t value) {
|
||||
|
||||
unsigned length = (length_ == 0 ? size : length_);
|
||||
char result[length + 1];
|
||||
memset(result, '0', length);
|
||||
memset(result, padding, length);
|
||||
result[length] = 0;
|
||||
|
||||
for(signed x = length - 1, y = 0; x >= 0 && y < size; x--, y++) {
|
||||
@@ -197,7 +193,7 @@ template<unsigned length_> string hex(uintmax_t value) {
|
||||
return (const char*)result;
|
||||
}
|
||||
|
||||
template<unsigned length_> string binary(uintmax_t value) {
|
||||
template<unsigned length_, char padding> string binary(uintmax_t value) {
|
||||
char buffer[256];
|
||||
unsigned size = 0;
|
||||
|
||||
@@ -209,7 +205,7 @@ template<unsigned length_> string binary(uintmax_t value) {
|
||||
|
||||
unsigned length = (length_ == 0 ? size : length_);
|
||||
char result[length + 1];
|
||||
memset(result, '0', length);
|
||||
memset(result, padding, length);
|
||||
result[length] = 0;
|
||||
|
||||
for(signed x = length - 1, y = 0; x >= 0 && y < size; x--, y++) {
|
||||
|
@@ -6,27 +6,31 @@ 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::iequals(const char *str) const { return !istrcmp(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::ibeginswith(const char *str) const { return istrbegin(data, str); }
|
||||
|
||||
bool string::endswith(const char *str) const { return strend(data, str); }
|
||||
bool string::iendswith(const char *str) const { return striend(data, str); }
|
||||
bool string::iendswith(const char *str) const { return istrend(data, str); }
|
||||
|
||||
string& string::lower() { nall::strlower(data); return *this; }
|
||||
string& string::upper() { nall::strupper(data); return *this; }
|
||||
string& string::qlower() { nall::qstrlower(data); return *this; }
|
||||
string& string::qupper() { nall::qstrupper(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; }
|
||||
template<unsigned limit> string& string::trim(const char *key, const char *rkey) { nall::trim <limit>(data, key, rkey); return *this; }
|
||||
|
||||
optional<unsigned> string::position(const char *key) const { return strpos(data, key); }
|
||||
optional<unsigned> string::iposition(const char *key) const { return istrpos(data, key); }
|
||||
optional<unsigned> string::qposition(const char *key) const { return qstrpos(data, key); }
|
||||
optional<unsigned> string::iqposition(const char *key) const { return iqstrpos(data, key); }
|
||||
|
||||
}
|
||||
|
||||
|
@@ -77,7 +77,7 @@ inline string xml_element::parse() const {
|
||||
if(auto pos = strpos(source, "]]>")) {
|
||||
if(pos() - 9 > 0) {
|
||||
string cdata = substr(source, 9, pos() - 9);
|
||||
data << cdata;
|
||||
data.append(cdata);
|
||||
offset += strlen(cdata);
|
||||
}
|
||||
source += 9 + offset + 3;
|
||||
|
@@ -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) {}
|
||||
};
|
||||
|
||||
|
@@ -94,14 +94,15 @@ namespace nall {
|
||||
else resize(objectsize - count);
|
||||
}
|
||||
|
||||
inline T& operator[](unsigned index) {
|
||||
if(index >= objectsize) resize(index + 1);
|
||||
return pool[index];
|
||||
linear_vector() : pool(0), poolsize(0), objectsize(0) {
|
||||
}
|
||||
|
||||
inline const T& operator[](unsigned index) const {
|
||||
if(index >= objectsize) throw "vector[] out of bounds";
|
||||
return pool[index];
|
||||
linear_vector(std::initializer_list<T> list) : pool(0), poolsize(0), objectsize(0) {
|
||||
for(const T *p = list.begin(); p != list.end(); ++p) append(*p);
|
||||
}
|
||||
|
||||
~linear_vector() {
|
||||
reset();
|
||||
}
|
||||
|
||||
//copy
|
||||
@@ -132,17 +133,22 @@ namespace nall {
|
||||
operator=(std::move(source));
|
||||
}
|
||||
|
||||
//construction
|
||||
linear_vector() : pool(0), poolsize(0), objectsize(0) {
|
||||
//index
|
||||
inline T& operator[](unsigned index) {
|
||||
if(index >= objectsize) resize(index + 1);
|
||||
return pool[index];
|
||||
}
|
||||
|
||||
linear_vector(std::initializer_list<T> list) : pool(0), poolsize(0), objectsize(0) {
|
||||
for(const T *p = list.begin(); p != list.end(); ++p) append(*p);
|
||||
inline const T& operator[](unsigned index) const {
|
||||
if(index >= objectsize) throw "vector[] out of bounds";
|
||||
return pool[index];
|
||||
}
|
||||
|
||||
~linear_vector() {
|
||||
reset();
|
||||
}
|
||||
//iteration
|
||||
T* begin() { return &pool[0]; }
|
||||
T* end() { return &pool[objectsize]; }
|
||||
const T* begin() const { return &pool[0]; }
|
||||
const T* end() const { return &pool[objectsize]; }
|
||||
};
|
||||
|
||||
//pointer_vector
|
||||
@@ -222,15 +228,15 @@ namespace nall {
|
||||
else resize(objectsize - count);
|
||||
}
|
||||
|
||||
inline T& operator[](unsigned index) {
|
||||
if(index >= objectsize) resize(index + 1);
|
||||
if(!pool[index]) pool[index] = new T;
|
||||
return *pool[index];
|
||||
pointer_vector() : pool(0), poolsize(0), objectsize(0) {
|
||||
}
|
||||
|
||||
inline const T& operator[](unsigned index) const {
|
||||
if(index >= objectsize || !pool[index]) throw "vector[] out of bounds";
|
||||
return *pool[index];
|
||||
pointer_vector(std::initializer_list<T> list) : pool(0), poolsize(0), objectsize(0) {
|
||||
for(const T *p = list.begin(); p != list.end(); ++p) append(*p);
|
||||
}
|
||||
|
||||
~pointer_vector() {
|
||||
reset();
|
||||
}
|
||||
|
||||
//copy
|
||||
@@ -261,17 +267,31 @@ namespace nall {
|
||||
operator=(std::move(source));
|
||||
}
|
||||
|
||||
//construction
|
||||
pointer_vector() : pool(0), poolsize(0), objectsize(0) {
|
||||
//index
|
||||
inline T& operator[](unsigned index) {
|
||||
if(index >= objectsize) resize(index + 1);
|
||||
if(!pool[index]) pool[index] = new T;
|
||||
return *pool[index];
|
||||
}
|
||||
|
||||
pointer_vector(std::initializer_list<T> list) : pool(0), poolsize(0), objectsize(0) {
|
||||
for(const T *p = list.begin(); p != list.end(); ++p) append(*p);
|
||||
inline const T& operator[](unsigned index) const {
|
||||
if(index >= objectsize || !pool[index]) throw "vector[] out of bounds";
|
||||
return *pool[index];
|
||||
}
|
||||
|
||||
~pointer_vector() {
|
||||
reset();
|
||||
}
|
||||
//iteration
|
||||
struct iterator {
|
||||
bool operator!=(const iterator &source) const { return index != source.index; }
|
||||
T& operator*() { return vector.operator[](index); }
|
||||
iterator& operator++() { index++; return *this; }
|
||||
iterator(pointer_vector &vector, unsigned index) : vector(vector), index(index) {}
|
||||
private:
|
||||
pointer_vector &vector;
|
||||
unsigned index;
|
||||
};
|
||||
|
||||
iterator begin() { return iterator(*this, 0); }
|
||||
iterator end() { return iterator(*this, objectsize); }
|
||||
};
|
||||
|
||||
template<typename T> struct has_size<linear_vector<T>> { enum { value = true }; };
|
||||
|
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
|
124
bsnes/nall/zip.hpp
Executable file
124
bsnes/nall/zip.hpp
Executable file
@@ -0,0 +1,124 @@
|
||||
#ifndef NALL_UNZIP_HPP
|
||||
#define NALL_UNZIP_HPP
|
||||
|
||||
#include <nall/filemap.hpp>
|
||||
#include <nall/inflate.hpp>
|
||||
#include <nall/string.hpp>
|
||||
#include <nall/vector.hpp>
|
||||
|
||||
namespace nall {
|
||||
|
||||
struct zip {
|
||||
struct File {
|
||||
string name;
|
||||
const uint8_t *data;
|
||||
unsigned size;
|
||||
unsigned csize;
|
||||
unsigned cmode; //0 = uncompressed, 8 = deflate
|
||||
unsigned crc32;
|
||||
};
|
||||
|
||||
inline bool open(const string &filename) {
|
||||
close();
|
||||
if(fm.open(filename, filemap::mode::read) == false) return false;
|
||||
if(open(fm.data(), fm.size()) == false) {
|
||||
fm.close();
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
inline bool open(const uint8_t *data, unsigned size) {
|
||||
if(size < 22) return false;
|
||||
|
||||
filedata = data;
|
||||
filesize = size;
|
||||
|
||||
file.reset();
|
||||
|
||||
const uint8_t *footer = data + size - 22;
|
||||
const uint8_t *directory = data + read(footer + 16, 4);
|
||||
|
||||
while(true) {
|
||||
unsigned signature = read(directory + 0, 4);
|
||||
if(signature != 0x02014b50) break;
|
||||
|
||||
File file;
|
||||
file.cmode = read(directory + 10, 2);
|
||||
file.crc32 = read(directory + 16, 4);
|
||||
file.csize = read(directory + 20, 4);
|
||||
file.size = read(directory + 24, 4);
|
||||
|
||||
unsigned namelength = read(directory + 28, 2);
|
||||
unsigned extralength = read(directory + 30, 2);
|
||||
unsigned commentlength = read(directory + 32, 2);
|
||||
|
||||
char *filename = new char[namelength + 1];
|
||||
memcpy(filename, directory + 46, namelength);
|
||||
filename[namelength] = 0;
|
||||
file.name = filename;
|
||||
delete[] filename;
|
||||
|
||||
unsigned offset = read(directory + 42, 4);
|
||||
unsigned offsetNL = read(data + offset + 26, 2);
|
||||
unsigned offsetEL = read(data + offset + 28, 2);
|
||||
file.data = data + offset + 30 + offsetNL + offsetEL;
|
||||
|
||||
directory += 46 + namelength + extralength + commentlength;
|
||||
|
||||
this->file.append(file);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
inline bool extract(File &file, uint8_t *&data, unsigned &size) {
|
||||
data = 0, size = 0;
|
||||
|
||||
if(file.cmode == 0) {
|
||||
size = file.size;
|
||||
data = new uint8_t[size];
|
||||
memcpy(data, file.data, size);
|
||||
return true;
|
||||
}
|
||||
|
||||
if(file.cmode == 8) {
|
||||
size = file.size;
|
||||
data = new uint8_t[size];
|
||||
if(inflate(data, size, file.data, file.csize) == false) {
|
||||
delete[] data;
|
||||
size = 0;
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
inline void close() {
|
||||
if(fm.open()) fm.close();
|
||||
}
|
||||
|
||||
~zip() {
|
||||
close();
|
||||
}
|
||||
|
||||
protected:
|
||||
filemap fm;
|
||||
const uint8_t *filedata;
|
||||
unsigned filesize;
|
||||
|
||||
unsigned read(const uint8_t *data, unsigned size) {
|
||||
unsigned result = 0, shift = 0;
|
||||
while(size--) { result |= *data++ << shift; shift += 8; }
|
||||
return result;
|
||||
}
|
||||
|
||||
public:
|
||||
linear_vector<File> file;
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
#endif
|
@@ -47,11 +47,12 @@ Window Window::None;
|
||||
void Window::append(Layout &layout) { state.layout.append(layout); return p.append(layout); }
|
||||
void Window::append(Menu &menu) { state.menu.append(menu); ((Action&)menu).state.parent = this; return p.append(menu); }
|
||||
void Window::append(Widget &widget) { state.widget.append(widget); return p.append(widget); }
|
||||
Color Window::backgroundColor() { return p.backgroundColor(); }
|
||||
Geometry Window::frameGeometry() { Geometry geometry = p.geometry(), margin = p.frameMargin(); return { geometry.x - margin.x, geometry.y - margin.y, geometry.width + margin.width, geometry.height + margin.height }; }
|
||||
Geometry Window::frameMargin() { return p.frameMargin(); }
|
||||
bool Window::focused() { return p.focused(); }
|
||||
Geometry Window::geometry() { return p.geometry(); }
|
||||
void Window::setBackgroundColor(uint8_t red, uint8_t green, uint8_t blue) { state.backgroundColor = true; state.backgroundColorRed = red; state.backgroundColorGreen = green; state.backgroundColorBlue = blue; return p.setBackgroundColor(red, green, blue); }
|
||||
void Window::setBackgroundColor(const Color &color) { state.backgroundColorOverride = true; state.backgroundColor = color; return p.setBackgroundColor(color); }
|
||||
void Window::setFrameGeometry(const Geometry &geometry) { Geometry margin = p.frameMargin(); return setGeometry({ geometry.x + margin.x, geometry.y + margin.y, geometry.width - margin.width, geometry.height - margin.height }); }
|
||||
void Window::setFocused() { return p.setFocused(); }
|
||||
void Window::setFullScreen(bool fullScreen) { state.fullScreen = fullScreen; return p.setFullScreen(fullScreen); }
|
||||
@@ -93,6 +94,7 @@ RadioItem::RadioItem() : state(*new State), base_from_member<pRadioItem&>(*new p
|
||||
|
||||
bool Widget::enabled() { return state.enabled; }
|
||||
Font& Widget::font() { return p.font(); }
|
||||
Geometry Widget::geometry() { return state.geometry; }
|
||||
Geometry Widget::minimumGeometry() { return p.minimumGeometry(); }
|
||||
void Widget::setEnabled(bool enabled) { state.enabled = enabled; return p.setEnabled(enabled); }
|
||||
void Widget::setFocused() { return p.setFocused(); }
|
||||
@@ -128,6 +130,11 @@ void HexEdit::setRows(unsigned rows) { state.rows = rows; return p.setRows(rows)
|
||||
void HexEdit::update() { return p.update(); }
|
||||
HexEdit::HexEdit() : state(*new State), base_from_member<pHexEdit&>(*new pHexEdit(*this)), Widget(base_from_member<pHexEdit&>::value), p(base_from_member<pHexEdit&>::value) { p.constructor(); }
|
||||
|
||||
unsigned HorizontalScrollBar::position() { return p.position(); }
|
||||
void HorizontalScrollBar::setLength(unsigned length) { state.length = length; return p.setLength(length); }
|
||||
void HorizontalScrollBar::setPosition(unsigned position) { state.position = position; return p.setPosition(position); }
|
||||
HorizontalScrollBar::HorizontalScrollBar() : state(*new State), base_from_member<pHorizontalScrollBar&>(*new pHorizontalScrollBar(*this)), Widget(base_from_member<pHorizontalScrollBar&>::value), p(base_from_member<pHorizontalScrollBar&>::value) { p.constructor(); }
|
||||
|
||||
unsigned HorizontalSlider::position() { return p.position(); }
|
||||
void HorizontalSlider::setLength(unsigned length) { state.length = length; return p.setLength(length); }
|
||||
void HorizontalSlider::setPosition(unsigned position) { state.position = position; return p.setPosition(position); }
|
||||
@@ -172,6 +179,11 @@ void TextEdit::setWordWrap(bool wordWrap) { state.wordWrap = wordWrap; return p.
|
||||
string TextEdit::text() { return p.text(); }
|
||||
TextEdit::TextEdit() : state(*new State), base_from_member<pTextEdit&>(*new pTextEdit(*this)), Widget(base_from_member<pTextEdit&>::value), p(base_from_member<pTextEdit&>::value) { p.constructor(); }
|
||||
|
||||
unsigned VerticalScrollBar::position() { return p.position(); }
|
||||
void VerticalScrollBar::setLength(unsigned length) { state.length = length; return p.setLength(length); }
|
||||
void VerticalScrollBar::setPosition(unsigned position) { state.position = position; return p.setPosition(position); }
|
||||
VerticalScrollBar::VerticalScrollBar() : state(*new State), base_from_member<pVerticalScrollBar&>(*new pVerticalScrollBar(*this)), Widget(base_from_member<pVerticalScrollBar&>::value), p(base_from_member<pVerticalScrollBar&>::value) { p.constructor(); }
|
||||
|
||||
unsigned VerticalSlider::position() { return p.position(); }
|
||||
void VerticalSlider::setLength(unsigned length) { state.length = length; return p.setLength(length); }
|
||||
void VerticalSlider::setPosition(unsigned position) { state.position = position; return p.setPosition(position); }
|
||||
|
@@ -21,6 +21,7 @@ struct pCanvas;
|
||||
struct pCheckBox;
|
||||
struct pComboBox;
|
||||
struct pHexEdit;
|
||||
struct pHorizontalScrollBar;
|
||||
struct pHorizontalSlider;
|
||||
struct pLabel;
|
||||
struct pLineEdit;
|
||||
@@ -28,6 +29,7 @@ struct pListView;
|
||||
struct pProgressBar;
|
||||
struct pRadioBox;
|
||||
struct pTextEdit;
|
||||
struct pVerticalScrollBar;
|
||||
struct pVerticalSlider;
|
||||
struct pViewport;
|
||||
|
||||
@@ -43,6 +45,12 @@ struct Geometry {
|
||||
inline Geometry(signed x, signed y, unsigned width, unsigned height) : x(x), y(y), width(width), height(height) {}
|
||||
};
|
||||
|
||||
struct Color {
|
||||
uint8_t red, green, blue, alpha;
|
||||
inline Color() : red(0), green(0), blue(0), alpha(255) {}
|
||||
inline Color(uint8_t red, uint8_t green, uint8_t blue, uint8_t alpha = 255) : red(red), green(green), blue(blue), alpha(alpha) {}
|
||||
};
|
||||
|
||||
struct Object {
|
||||
Object();
|
||||
Object& operator=(const Object&) = delete;
|
||||
@@ -124,11 +132,12 @@ struct Window : Object {
|
||||
void append(Layout &layout);
|
||||
void append(Menu &menu);
|
||||
void append(Widget &widget);
|
||||
Color backgroundColor();
|
||||
Geometry frameGeometry();
|
||||
Geometry frameMargin();
|
||||
bool focused();
|
||||
Geometry geometry();
|
||||
void setBackgroundColor(uint8_t red, uint8_t green, uint8_t blue);
|
||||
void setBackgroundColor(const Color &color);
|
||||
void setFrameGeometry(const Geometry &geometry);
|
||||
void setFocused();
|
||||
void setFullScreen(bool fullScreen = true);
|
||||
@@ -223,6 +232,7 @@ struct Layout : Object {
|
||||
struct Widget : Object {
|
||||
bool enabled();
|
||||
Font& font();
|
||||
Geometry geometry();
|
||||
Geometry minimumGeometry();
|
||||
void setEnabled(bool enabled = true);
|
||||
void setFocused();
|
||||
@@ -300,6 +310,19 @@ struct HexEdit : private nall::base_from_member<pHexEdit&>, Widget {
|
||||
pHexEdit &p;
|
||||
};
|
||||
|
||||
struct HorizontalScrollBar : private nall::base_from_member<pHorizontalScrollBar&>, Widget {
|
||||
nall::function<void ()> onChange;
|
||||
|
||||
unsigned position();
|
||||
void setLength(unsigned length);
|
||||
void setPosition(unsigned position);
|
||||
|
||||
HorizontalScrollBar();
|
||||
struct State;
|
||||
State &state;
|
||||
pHorizontalScrollBar &p;
|
||||
};
|
||||
|
||||
struct HorizontalSlider : private nall::base_from_member<pHorizontalSlider&>, Widget {
|
||||
nall::function<void ()> onChange;
|
||||
|
||||
@@ -406,6 +429,19 @@ struct TextEdit : private nall::base_from_member<pTextEdit&>, Widget {
|
||||
pTextEdit &p;
|
||||
};
|
||||
|
||||
struct VerticalScrollBar : private nall::base_from_member<pVerticalScrollBar&>, Widget {
|
||||
nall::function<void ()> onChange;
|
||||
|
||||
unsigned position();
|
||||
void setLength(unsigned length);
|
||||
void setPosition(unsigned position);
|
||||
|
||||
VerticalScrollBar();
|
||||
struct State;
|
||||
State &state;
|
||||
pVerticalScrollBar &p;
|
||||
};
|
||||
|
||||
struct VerticalSlider : private nall::base_from_member<pVerticalSlider&>, Widget {
|
||||
nall::function<void ()> onChange;
|
||||
|
||||
|
@@ -24,8 +24,8 @@ struct Timer::State {
|
||||
};
|
||||
|
||||
struct Window::State {
|
||||
bool backgroundColor;
|
||||
unsigned backgroundColorRed, backgroundColorGreen, backgroundColorBlue;
|
||||
bool backgroundColorOverride;
|
||||
Color backgroundColor;
|
||||
bool fullScreen;
|
||||
Geometry geometry;
|
||||
reference_array<Layout&> layout;
|
||||
@@ -42,10 +42,8 @@ struct Window::State {
|
||||
Font *widgetFont;
|
||||
|
||||
State() {
|
||||
backgroundColor = false;
|
||||
backgroundColorRed = 0;
|
||||
backgroundColorGreen = 0;
|
||||
backgroundColorBlue = 0;
|
||||
backgroundColorOverride = false;
|
||||
backgroundColor = { 0, 0, 0, 255 };
|
||||
fullScreen = false;
|
||||
geometry = { 128, 128, 256, 256 };
|
||||
menuFont = 0;
|
||||
@@ -152,6 +150,16 @@ struct HexEdit::State {
|
||||
}
|
||||
};
|
||||
|
||||
struct HorizontalScrollBar::State {
|
||||
unsigned length;
|
||||
unsigned position;
|
||||
|
||||
State() {
|
||||
length = 101;
|
||||
position = 0;
|
||||
}
|
||||
};
|
||||
|
||||
struct HorizontalSlider::State {
|
||||
unsigned length;
|
||||
unsigned position;
|
||||
@@ -223,6 +231,16 @@ struct TextEdit::State {
|
||||
}
|
||||
};
|
||||
|
||||
struct VerticalScrollBar::State {
|
||||
unsigned length;
|
||||
unsigned position;
|
||||
|
||||
State() {
|
||||
length = 101;
|
||||
position = 0;
|
||||
}
|
||||
};
|
||||
|
||||
struct VerticalSlider::State {
|
||||
unsigned length;
|
||||
unsigned position;
|
||||
|
@@ -29,4 +29,6 @@ void pFont::constructor() {
|
||||
gtkFont = pango_font_description_new();
|
||||
PangoContext *context = gdk_pango_context_get_for_screen(gdk_screen_get_default());
|
||||
gtkLayout = pango_layout_new(context);
|
||||
font.setFamily("Sans");
|
||||
font.setSize(8);
|
||||
}
|
||||
|
@@ -19,6 +19,7 @@
|
||||
#include "widget/check-box.cpp"
|
||||
#include "widget/combo-box.cpp"
|
||||
#include "widget/hex-edit.cpp"
|
||||
#include "widget/horizontal-scroll-bar.cpp"
|
||||
#include "widget/horizontal-slider.cpp"
|
||||
#include "widget/label.cpp"
|
||||
#include "widget/line-edit.cpp"
|
||||
@@ -26,6 +27,7 @@
|
||||
#include "widget/progress-bar.cpp"
|
||||
#include "widget/radio-box.cpp"
|
||||
#include "widget/text-edit.cpp"
|
||||
#include "widget/vertical-scroll-bar.cpp"
|
||||
#include "widget/vertical-slider.cpp"
|
||||
#include "widget/viewport.cpp"
|
||||
|
||||
@@ -169,7 +171,7 @@ void pOS::initialize() {
|
||||
" GtkComboBox::appears-as-list = 1\n"
|
||||
" GtkTreeView::vertical-separator = 0\n"
|
||||
"}\n"
|
||||
"class \"GtkComboBox\" style \"phoenix-gtk\"\n"
|
||||
//"class \"GtkComboBox\" style \"phoenix-gtk\"\n"
|
||||
"class \"GtkTreeView\" style \"phoenix-gtk\"\n"
|
||||
);
|
||||
}
|
||||
|
@@ -82,14 +82,16 @@ struct pWindow : public pObject {
|
||||
GtkWidget *statusContainer;
|
||||
GtkWidget *menu;
|
||||
GtkWidget *status;
|
||||
GdkEventConfigure lastConfigure;
|
||||
|
||||
void append(Layout &layout);
|
||||
void append(Menu &menu);
|
||||
void append(Widget &widget);
|
||||
Color backgroundColor();
|
||||
bool focused();
|
||||
Geometry frameMargin();
|
||||
Geometry geometry();
|
||||
void setBackgroundColor(uint8_t red, uint8_t green, uint8_t blue);
|
||||
void setBackgroundColor(const Color &color);
|
||||
void setFocused();
|
||||
void setFullScreen(bool fullScreen);
|
||||
void setGeometry(const Geometry &geometry);
|
||||
@@ -202,8 +204,7 @@ struct pButton : public pWidget {
|
||||
|
||||
struct pCanvas : public pWidget {
|
||||
Canvas &canvas;
|
||||
uint32_t *bufferRGB;
|
||||
uint32_t *bufferBGR;
|
||||
cairo_surface_t *surface;
|
||||
|
||||
uint32_t* buffer();
|
||||
void setGeometry(const Geometry &geometry);
|
||||
@@ -211,7 +212,6 @@ struct pCanvas : public pWidget {
|
||||
|
||||
pCanvas(Canvas &canvas) : pWidget(canvas), canvas(canvas) {}
|
||||
void constructor();
|
||||
void redraw();
|
||||
};
|
||||
|
||||
struct pCheckBox : public pWidget {
|
||||
@@ -264,6 +264,18 @@ struct pHexEdit : public pWidget {
|
||||
void updateScroll();
|
||||
};
|
||||
|
||||
struct pHorizontalScrollBar : public pWidget {
|
||||
HorizontalScrollBar &horizontalScrollBar;
|
||||
|
||||
Geometry minimumGeometry();
|
||||
unsigned position();
|
||||
void setLength(unsigned length);
|
||||
void setPosition(unsigned position);
|
||||
|
||||
pHorizontalScrollBar(HorizontalScrollBar &horizontalScrollBar) : pWidget(horizontalScrollBar), horizontalScrollBar(horizontalScrollBar) {}
|
||||
void constructor();
|
||||
};
|
||||
|
||||
struct pHorizontalSlider : public pWidget {
|
||||
HorizontalSlider &horizontalSlider;
|
||||
|
||||
@@ -368,6 +380,18 @@ struct pTextEdit : public pWidget {
|
||||
void constructor();
|
||||
};
|
||||
|
||||
struct pVerticalScrollBar : public pWidget {
|
||||
VerticalScrollBar &verticalScrollBar;
|
||||
|
||||
Geometry minimumGeometry();
|
||||
unsigned position();
|
||||
void setLength(unsigned length);
|
||||
void setPosition(unsigned position);
|
||||
|
||||
pVerticalScrollBar(VerticalScrollBar &verticalScrollBar) : pWidget(verticalScrollBar), verticalScrollBar(verticalScrollBar) {}
|
||||
void constructor();
|
||||
};
|
||||
|
||||
struct pVerticalSlider : public pWidget {
|
||||
VerticalSlider &verticalSlider;
|
||||
|
||||
|
@@ -5,7 +5,7 @@ static void Button_tick(Button *self) {
|
||||
Geometry pButton::minimumGeometry() {
|
||||
Font &font = pWidget::font();
|
||||
Geometry geometry = font.geometry(button.state.text);
|
||||
return { 0, 0, geometry.width + 24, geometry.height + 14 };
|
||||
return { 0, 0, geometry.width + 24, geometry.height + 12 };
|
||||
}
|
||||
|
||||
void pButton::setText(const string &text) {
|
||||
|
@@ -1,17 +1,21 @@
|
||||
static void Canvas_expose(pCanvas *self) {
|
||||
self->redraw();
|
||||
static gboolean Canvas_expose(GtkWidget *widget, GdkEvent *event, pCanvas *self) {
|
||||
cairo_t *context = gdk_cairo_create(gtk_widget_get_window(widget));
|
||||
cairo_set_source_surface(context, self->surface, 0, 0);
|
||||
cairo_paint(context);
|
||||
cairo_destroy(context);
|
||||
return true;
|
||||
}
|
||||
|
||||
uint32_t* pCanvas::buffer() {
|
||||
return bufferRGB;
|
||||
return (uint32_t*)cairo_image_surface_get_data(surface);
|
||||
}
|
||||
|
||||
void pCanvas::setGeometry(const Geometry &geometry) {
|
||||
delete[] bufferRGB;
|
||||
delete[] bufferBGR;
|
||||
if(geometry.width == cairo_image_surface_get_width(surface)
|
||||
&& geometry.height == cairo_image_surface_get_height(surface)) return;
|
||||
|
||||
bufferRGB = new uint32_t[geometry.width * geometry.height]();
|
||||
bufferBGR = new uint32_t[geometry.width * geometry.height]();
|
||||
cairo_surface_destroy(surface);
|
||||
surface = cairo_image_surface_create(CAIRO_FORMAT_RGB24, geometry.width, geometry.height);
|
||||
|
||||
pWidget::setGeometry(geometry);
|
||||
update();
|
||||
@@ -19,41 +23,16 @@ void pCanvas::setGeometry(const Geometry &geometry) {
|
||||
|
||||
void pCanvas::update() {
|
||||
if(gtk_widget_get_realized(gtkWidget) == false) return;
|
||||
GdkRectangle rect;
|
||||
rect.x = 0;
|
||||
rect.y = 0;
|
||||
rect.width = gtkWidget->allocation.width;
|
||||
rect.height = gtkWidget->allocation.height;
|
||||
gdk_window_invalidate_rect(gtkWidget->window, &rect, true);
|
||||
gdk_window_invalidate_rect(gtk_widget_get_window(gtkWidget), 0, true);
|
||||
}
|
||||
|
||||
void pCanvas::constructor() {
|
||||
bufferRGB = new uint32_t[256 * 256]();
|
||||
bufferBGR = new uint32_t[256 * 256]();
|
||||
|
||||
surface = cairo_image_surface_create(CAIRO_FORMAT_RGB24, 256, 256);
|
||||
gtkWidget = gtk_drawing_area_new();
|
||||
GdkColor color;
|
||||
color.pixel = color.red = color.green = color.blue = 0;
|
||||
gtk_widget_modify_bg(gtkWidget, GTK_STATE_NORMAL, &color);
|
||||
gtk_widget_set_double_buffered(gtkWidget, false);
|
||||
gtk_widget_add_events(gtkWidget, GDK_EXPOSURE_MASK);
|
||||
g_signal_connect_swapped(G_OBJECT(gtkWidget), "expose_event", G_CALLBACK(Canvas_expose), (gpointer)this);
|
||||
}
|
||||
|
||||
void pCanvas::redraw() {
|
||||
if(gtk_widget_get_realized(gtkWidget) == false) return;
|
||||
uint32_t *rgb = bufferRGB, *bgr = bufferBGR;
|
||||
for(unsigned y = gtkWidget->allocation.height; y; y--) {
|
||||
for(unsigned x = gtkWidget->allocation.width; x; x--) {
|
||||
uint32_t pixel = *rgb++;
|
||||
*bgr++ = ((pixel << 16) & 0xff0000) | (pixel & 0x00ff00) | ((pixel >> 16) & 0x0000ff);
|
||||
}
|
||||
}
|
||||
|
||||
gdk_draw_rgb_32_image(
|
||||
gtkWidget->window,
|
||||
gtkWidget->style->fg_gc[GTK_WIDGET_STATE(gtkWidget)],
|
||||
0, 0, gtkWidget->allocation.width, gtkWidget->allocation.height,
|
||||
GDK_RGB_DITHER_NONE, (guchar*)bufferBGR, sizeof(uint32_t) * gtkWidget->allocation.width
|
||||
);
|
||||
g_signal_connect(G_OBJECT(gtkWidget), "expose_event", G_CALLBACK(Canvas_expose), (gpointer)this);
|
||||
}
|
||||
|
@@ -13,14 +13,12 @@ Geometry pComboBox::minimumGeometry() {
|
||||
foreach(item, comboBox.state.text) maximumWidth = max(maximumWidth, font.geometry(item).width);
|
||||
|
||||
Geometry geometry = font.geometry(" ");
|
||||
return { 0, 0, maximumWidth + 44, geometry.height + 10 };
|
||||
return { 0, 0, maximumWidth + 44, geometry.height + 12 };
|
||||
}
|
||||
|
||||
void pComboBox::reset() {
|
||||
locked = true;
|
||||
for(signed n = itemCounter - 1; n >= 0; n--) {
|
||||
gtk_combo_box_remove_text(GTK_COMBO_BOX(gtkWidget), n);
|
||||
}
|
||||
gtk_list_store_clear(GTK_LIST_STORE(gtk_combo_box_get_model(GTK_COMBO_BOX(gtkWidget))));
|
||||
itemCounter = 0;
|
||||
locked = false;
|
||||
}
|
||||
|
@@ -112,17 +112,17 @@ bool pHexEdit::keyPress(unsigned scancode) {
|
||||
unsigned cursorY = position / lineWidth;
|
||||
unsigned cursorX = position % lineWidth;
|
||||
|
||||
if(scancode == GDK_Home) {
|
||||
if(scancode == GDK_KEY_Home) {
|
||||
setCursorPosition(cursorY * lineWidth + 10);
|
||||
return true;
|
||||
}
|
||||
|
||||
if(scancode == GDK_End) {
|
||||
if(scancode == GDK_KEY_End) {
|
||||
setCursorPosition(cursorY * lineWidth + 10 + (hexEdit.state.columns * 3 - 1));
|
||||
return true;
|
||||
}
|
||||
|
||||
if(scancode == GDK_Up) {
|
||||
if(scancode == GDK_KEY_Up) {
|
||||
if(cursorY != 0) return false;
|
||||
|
||||
signed newOffset = hexEdit.state.offset - hexEdit.state.columns;
|
||||
@@ -133,7 +133,7 @@ bool pHexEdit::keyPress(unsigned scancode) {
|
||||
return true;
|
||||
}
|
||||
|
||||
if(scancode == GDK_Down) {
|
||||
if(scancode == GDK_KEY_Down) {
|
||||
if(cursorY != hexEdit.state.rows - 1) return false;
|
||||
|
||||
signed newOffset = hexEdit.state.offset + hexEdit.state.columns;
|
||||
@@ -144,7 +144,7 @@ bool pHexEdit::keyPress(unsigned scancode) {
|
||||
return true;
|
||||
}
|
||||
|
||||
if(scancode == GDK_Page_Up) {
|
||||
if(scancode == GDK_KEY_Page_Up) {
|
||||
signed newOffset = hexEdit.state.offset - hexEdit.state.columns * hexEdit.state.rows;
|
||||
if(newOffset >= 0) {
|
||||
hexEdit.setOffset(newOffset);
|
||||
@@ -155,7 +155,7 @@ bool pHexEdit::keyPress(unsigned scancode) {
|
||||
return true;
|
||||
}
|
||||
|
||||
if(scancode == GDK_Page_Down) {
|
||||
if(scancode == GDK_KEY_Page_Down) {
|
||||
signed newOffset = hexEdit.state.offset + hexEdit.state.columns * hexEdit.state.rows;
|
||||
for(unsigned n = 0; n < hexEdit.state.rows; n++) {
|
||||
if(newOffset + hexEdit.state.columns * hexEdit.state.rows - (hexEdit.state.columns - 1) <= hexEdit.state.length) {
|
||||
|
29
bsnes/phoenix/gtk/widget/horizontal-scroll-bar.cpp
Executable file
29
bsnes/phoenix/gtk/widget/horizontal-scroll-bar.cpp
Executable file
@@ -0,0 +1,29 @@
|
||||
static void HorizontalScrollBar_change(HorizontalScrollBar *self) {
|
||||
if(self->state.position == self->position()) return;
|
||||
self->state.position = self->position();
|
||||
if(self->onChange) self->onChange();
|
||||
}
|
||||
|
||||
Geometry pHorizontalScrollBar::minimumGeometry() {
|
||||
return { 0, 0, 0, 20 };
|
||||
}
|
||||
|
||||
unsigned pHorizontalScrollBar::position() {
|
||||
return (unsigned)gtk_range_get_value(GTK_RANGE(gtkWidget));
|
||||
}
|
||||
|
||||
void pHorizontalScrollBar::setLength(unsigned length) {
|
||||
length += length == 0;
|
||||
gtk_range_set_range(GTK_RANGE(gtkWidget), 0, length - 1);
|
||||
gtk_range_set_increments(GTK_RANGE(gtkWidget), 1, length >> 3);
|
||||
}
|
||||
|
||||
void pHorizontalScrollBar::setPosition(unsigned position) {
|
||||
gtk_range_set_value(GTK_RANGE(gtkWidget), position);
|
||||
}
|
||||
|
||||
void pHorizontalScrollBar::constructor() {
|
||||
gtkWidget = gtk_hscrollbar_new(0);
|
||||
setLength(101);
|
||||
g_signal_connect_swapped(G_OBJECT(gtkWidget), "value-changed", G_CALLBACK(HorizontalScrollBar_change), (gpointer)&horizontalScrollBar);
|
||||
}
|
@@ -15,6 +15,7 @@ unsigned pHorizontalSlider::position() {
|
||||
void pHorizontalSlider::setLength(unsigned length) {
|
||||
length += length == 0;
|
||||
gtk_range_set_range(GTK_RANGE(gtkWidget), 0, length - 1);
|
||||
gtk_range_set_increments(GTK_RANGE(gtkWidget), 1, length >> 3);
|
||||
}
|
||||
|
||||
void pHorizontalSlider::setPosition(unsigned position) {
|
||||
@@ -24,5 +25,6 @@ void pHorizontalSlider::setPosition(unsigned position) {
|
||||
void pHorizontalSlider::constructor() {
|
||||
gtkWidget = gtk_hscale_new_with_range(0, 100, 1);
|
||||
gtk_scale_set_draw_value(GTK_SCALE(gtkWidget), false);
|
||||
setLength(101);
|
||||
g_signal_connect_swapped(G_OBJECT(gtkWidget), "value-changed", G_CALLBACK(HorizontalSlider_change), (gpointer)&horizontalSlider);
|
||||
}
|
||||
|
@@ -13,7 +13,7 @@ Geometry pLineEdit::minimumGeometry() {
|
||||
}
|
||||
|
||||
void pLineEdit::setEditable(bool editable) {
|
||||
gtk_entry_set_editable(GTK_ENTRY(gtkWidget), editable);
|
||||
gtk_editable_set_editable(GTK_EDITABLE(gtkWidget), editable);
|
||||
}
|
||||
|
||||
void pLineEdit::setText(const string &text) {
|
||||
|
29
bsnes/phoenix/gtk/widget/vertical-scroll-bar.cpp
Executable file
29
bsnes/phoenix/gtk/widget/vertical-scroll-bar.cpp
Executable file
@@ -0,0 +1,29 @@
|
||||
static void VerticalScrollBar_change(VerticalScrollBar *self) {
|
||||
if(self->state.position == self->position()) return;
|
||||
self->state.position = self->position();
|
||||
if(self->onChange) self->onChange();
|
||||
}
|
||||
|
||||
Geometry pVerticalScrollBar::minimumGeometry() {
|
||||
return { 0, 0, 20, 0 };
|
||||
}
|
||||
|
||||
unsigned pVerticalScrollBar::position() {
|
||||
return (unsigned)gtk_range_get_value(GTK_RANGE(gtkWidget));
|
||||
}
|
||||
|
||||
void pVerticalScrollBar::setLength(unsigned length) {
|
||||
length += length == 0;
|
||||
gtk_range_set_range(GTK_RANGE(gtkWidget), 0, length - 1);
|
||||
gtk_range_set_increments(GTK_RANGE(gtkWidget), 1, length >> 3);
|
||||
}
|
||||
|
||||
void pVerticalScrollBar::setPosition(unsigned position) {
|
||||
gtk_range_set_value(GTK_RANGE(gtkWidget), position);
|
||||
}
|
||||
|
||||
void pVerticalScrollBar::constructor() {
|
||||
gtkWidget = gtk_vscrollbar_new(0);
|
||||
setLength(101);
|
||||
g_signal_connect_swapped(G_OBJECT(gtkWidget), "value-changed", G_CALLBACK(VerticalScrollBar_change), (gpointer)&verticalScrollBar);
|
||||
}
|
@@ -15,6 +15,7 @@ unsigned pVerticalSlider::position() {
|
||||
void pVerticalSlider::setLength(unsigned length) {
|
||||
length += length == 0;
|
||||
gtk_range_set_range(GTK_RANGE(gtkWidget), 0, length - 1);
|
||||
gtk_range_set_increments(GTK_RANGE(gtkWidget), 1, length >> 3);
|
||||
}
|
||||
|
||||
void pVerticalSlider::setPosition(unsigned position) {
|
||||
@@ -24,5 +25,6 @@ void pVerticalSlider::setPosition(unsigned position) {
|
||||
void pVerticalSlider::constructor() {
|
||||
gtkWidget = gtk_vscale_new_with_range(0, 100, 1);
|
||||
gtk_scale_set_draw_value(GTK_SCALE(gtkWidget), false);
|
||||
setLength(101);
|
||||
g_signal_connect_swapped(G_OBJECT(gtkWidget), "value-changed", G_CALLBACK(VerticalSlider_change), (gpointer)&verticalSlider);
|
||||
}
|
||||
|
@@ -1,5 +1,5 @@
|
||||
uintptr_t pViewport::handle() {
|
||||
return GDK_WINDOW_XID(gtkWidget->window);
|
||||
return GDK_WINDOW_XID(gtk_widget_get_window(gtkWidget));
|
||||
}
|
||||
|
||||
void pViewport::constructor() {
|
||||
|
@@ -1,70 +1,79 @@
|
||||
static void Action_setFont(GtkWidget *widget, gpointer font);
|
||||
static void Widget_setFont(GtkWidget *widget, gpointer font);
|
||||
|
||||
static gint Window_close(Window *window) {
|
||||
static gint Window_close(GtkWidget *widget, GdkEvent *event, Window *window) {
|
||||
if(window->onClose) window->onClose();
|
||||
window->setVisible(false);
|
||||
return true;
|
||||
}
|
||||
|
||||
static gboolean Window_configure(Window *window) {
|
||||
static gboolean Window_expose(GtkWidget *widget, GdkEvent *event, Window *window) {
|
||||
cairo_t *context = gdk_cairo_create(widget->window);
|
||||
|
||||
Color color = window->backgroundColor();
|
||||
double red = (double)color.red / 255.0;
|
||||
double green = (double)color.green / 255.0;
|
||||
double blue = (double)color.blue / 255.0;
|
||||
double alpha = (double)color.alpha / 255.0;
|
||||
|
||||
if(gdk_screen_is_composited(gdk_screen_get_default())) {
|
||||
cairo_set_source_rgba(context, red, green, blue, alpha);
|
||||
} else {
|
||||
cairo_set_source_rgb(context, red, green, blue);
|
||||
}
|
||||
|
||||
cairo_set_operator(context, CAIRO_OPERATOR_SOURCE);
|
||||
cairo_paint(context);
|
||||
cairo_destroy(context);
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
static gboolean Window_configure(GtkWidget *widget, GdkEvent *event, Window *window) {
|
||||
if(gtk_widget_get_realized(window->p.widget) == false) return false;
|
||||
GdkWindow *gdkWindow = gtk_widget_get_window(widget);
|
||||
|
||||
//update geometry settings
|
||||
Display *display = XOpenDisplay(0);
|
||||
XWindowAttributes attributes, parentAttributes;
|
||||
XGetWindowAttributes(display, GDK_WINDOW_XID(window->p.widget->window), &attributes);
|
||||
X11Window rootWindow, parentWindow, *childWindow = 0;
|
||||
unsigned int childCount;
|
||||
XQueryTree(display, GDK_WINDOW_XID(window->p.widget->window), &rootWindow, &parentWindow, &childWindow, &childCount);
|
||||
XGetWindowAttributes(display, parentWindow, &parentAttributes);
|
||||
if(childWindow) XFree(childWindow);
|
||||
XCloseDisplay(display);
|
||||
GdkRectangle border, client;
|
||||
gdk_window_get_frame_extents(gdkWindow, &border);
|
||||
gdk_window_get_geometry(gdkWindow, 0, 0, &client.width, &client.height, 0);
|
||||
gdk_window_get_origin(gdkWindow, &client.x, &client.y);
|
||||
|
||||
settings.frameGeometryX = attributes.x;
|
||||
settings.frameGeometryY = attributes.y;
|
||||
settings.frameGeometryWidth = parentAttributes.width - attributes.width;
|
||||
settings.frameGeometryHeight = parentAttributes.height - attributes.height;
|
||||
|
||||
GtkAllocation menuAllocation, statusAllocation;
|
||||
gtk_widget_get_allocation(window->p.menu, &menuAllocation);
|
||||
gtk_widget_get_allocation(window->p.status, &statusAllocation);
|
||||
|
||||
if(menuAllocation.height > 1) settings.menuGeometryHeight = menuAllocation.height;
|
||||
if(statusAllocation.height > 1) settings.statusGeometryHeight = statusAllocation.height;
|
||||
|
||||
//calculate current window position
|
||||
signed eventX = parentAttributes.x + attributes.x;
|
||||
signed eventY = parentAttributes.y + attributes.y + window->p.menuHeight();
|
||||
unsigned eventWidth = attributes.width;
|
||||
unsigned eventHeight = attributes.height - window->p.menuHeight() - window->p.statusHeight();
|
||||
settings.frameGeometryX = client.x - border.x;
|
||||
settings.frameGeometryY = client.y - border.y;
|
||||
settings.frameGeometryWidth = border.width - client.width;
|
||||
settings.frameGeometryHeight = border.height - client.height;
|
||||
|
||||
//move
|
||||
if(window->p.locked == false && window->state.fullScreen == false) {
|
||||
if(window->state.geometry.x != eventX || window->state.geometry.y != eventY) {
|
||||
window->state.geometry.x = eventX;
|
||||
window->state.geometry.y = eventY;
|
||||
if(event->configure.x != window->p.lastConfigure.x
|
||||
|| event->configure.y != window->p.lastConfigure.y
|
||||
) {
|
||||
if(window->state.fullScreen == false) {
|
||||
window->state.geometry.x = client.x;
|
||||
window->state.geometry.y = client.y + window->p.menuHeight();
|
||||
}
|
||||
if(window->p.locked == false && window->onMove) window->onMove();
|
||||
}
|
||||
|
||||
if(window->onMove) window->onMove();
|
||||
|
||||
//size
|
||||
if(window->p.locked == false && window->state.fullScreen == false) {
|
||||
if(window->state.geometry.width != eventWidth || window->state.geometry.height != eventHeight) {
|
||||
window->state.geometry.width = eventWidth;
|
||||
window->state.geometry.height = eventHeight;
|
||||
if(event->configure.width != window->p.lastConfigure.width
|
||||
|| event->configure.height != window->p.lastConfigure.height
|
||||
) {
|
||||
if(window->state.fullScreen == false) {
|
||||
window->state.geometry.width = client.width;
|
||||
window->state.geometry.height = client.height - window->p.menuHeight() - window->p.statusHeight();
|
||||
}
|
||||
|
||||
foreach(layout, window->state.layout) {
|
||||
Geometry geometry = window->geometry();
|
||||
geometry.x = geometry.y = 0;
|
||||
layout.setGeometry(geometry);
|
||||
}
|
||||
|
||||
if(window->p.locked == false && window->onSize) window->onSize();
|
||||
}
|
||||
|
||||
foreach(layout, window->state.layout) {
|
||||
Geometry geometry = window->geometry();
|
||||
geometry.x = geometry.y = 0;
|
||||
layout.setGeometry(geometry);
|
||||
}
|
||||
|
||||
if(window->onSize) window->onSize();
|
||||
|
||||
window->p.lastConfigure = event->configure;
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -77,7 +86,7 @@ void pWindow::append(Layout &layout) {
|
||||
|
||||
void pWindow::append(Menu &subMenu) {
|
||||
if(window.state.menuFont) subMenu.p.setFont(*window.state.menuFont);
|
||||
gtk_menu_bar_append(menu, subMenu.p.widget);
|
||||
gtk_menu_shell_append(GTK_MENU_SHELL(menu), subMenu.p.widget);
|
||||
gtk_widget_show(subMenu.p.widget);
|
||||
}
|
||||
|
||||
@@ -90,6 +99,12 @@ void pWindow::append(Widget &widget) {
|
||||
widget.setVisible();
|
||||
}
|
||||
|
||||
Color pWindow::backgroundColor() {
|
||||
if(window.state.backgroundColorOverride) return window.state.backgroundColor;
|
||||
GdkColor color = widget->style->bg[GTK_STATE_NORMAL];
|
||||
return { (uint8_t)(color.red >> 8), (uint8_t)(color.green >> 8), (uint8_t)(color.blue >> 8), 255 };
|
||||
}
|
||||
|
||||
Geometry pWindow::frameMargin() {
|
||||
if(window.state.fullScreen) return { 0, menuHeight(), 0, menuHeight() + statusHeight() };
|
||||
return {
|
||||
@@ -111,13 +126,13 @@ Geometry pWindow::geometry() {
|
||||
return window.state.geometry;
|
||||
}
|
||||
|
||||
void pWindow::setBackgroundColor(uint8_t red, uint8_t green, uint8_t blue) {
|
||||
GdkColor color;
|
||||
color.pixel = (red << 16) | (green << 8) | (blue << 0);
|
||||
color.red = (red << 8) | (red << 0);
|
||||
color.green = (green << 8) | (green << 0);
|
||||
color.blue = (blue << 8) | (blue << 0);
|
||||
gtk_widget_modify_bg(widget, GTK_STATE_NORMAL, &color);
|
||||
void pWindow::setBackgroundColor(const Color &color) {
|
||||
GdkColor gdkColor;
|
||||
gdkColor.pixel = (color.red << 16) | (color.green << 8) | (color.blue << 0);
|
||||
gdkColor.red = (color.red << 8) | (color.red << 0);
|
||||
gdkColor.green = (color.green << 8) | (color.green << 0);
|
||||
gdkColor.blue = (color.blue << 8) | (color.blue << 0);
|
||||
gtk_widget_modify_bg(widget, GTK_STATE_NORMAL, &gdkColor);
|
||||
}
|
||||
|
||||
void pWindow::setFocused() {
|
||||
@@ -129,14 +144,12 @@ void pWindow::setFullScreen(bool fullScreen) {
|
||||
gtk_window_unfullscreen(GTK_WINDOW(widget));
|
||||
gtk_window_set_resizable(GTK_WINDOW(widget), window.state.resizable);
|
||||
gtk_window_set_decorated(GTK_WINDOW(widget), true);
|
||||
locked = true;
|
||||
for(unsigned n = 0; n < 4; n++) {
|
||||
setGeometry(window.state.geometry);
|
||||
gtk_widget_set_size_request(widget, -1, -1);
|
||||
OS::processEvents();
|
||||
usleep(2000);
|
||||
}
|
||||
locked = false;
|
||||
} else {
|
||||
gtk_window_fullscreen(GTK_WINDOW(widget));
|
||||
gtk_window_set_decorated(GTK_WINDOW(widget), false);
|
||||
@@ -198,7 +211,15 @@ void pWindow::setWidgetFont(Font &font) {
|
||||
}
|
||||
|
||||
void pWindow::constructor() {
|
||||
memset(&lastConfigure, 0, sizeof(GdkEventConfigure));
|
||||
widget = gtk_window_new(GTK_WINDOW_TOPLEVEL);
|
||||
|
||||
if(gdk_screen_is_composited(gdk_screen_get_default())) {
|
||||
gtk_widget_set_colormap(widget, gdk_screen_get_rgba_colormap(gdk_screen_get_default()));
|
||||
} else {
|
||||
gtk_widget_set_colormap(widget, gdk_screen_get_rgb_colormap(gdk_screen_get_default()));
|
||||
}
|
||||
|
||||
gtk_window_set_resizable(GTK_WINDOW(widget), true);
|
||||
gtk_widget_set_app_paintable(widget, true);
|
||||
gtk_widget_add_events(widget, GDK_CONFIGURE);
|
||||
@@ -224,8 +245,9 @@ void pWindow::constructor() {
|
||||
setTitle("");
|
||||
setGeometry(window.state.geometry);
|
||||
|
||||
g_signal_connect_swapped(G_OBJECT(widget), "delete-event", G_CALLBACK(Window_close), (gpointer)&window);
|
||||
g_signal_connect_swapped(G_OBJECT(widget), "configure-event", G_CALLBACK(Window_configure), (gpointer)&window);
|
||||
g_signal_connect(G_OBJECT(widget), "delete-event", G_CALLBACK(Window_close), (gpointer)&window);
|
||||
g_signal_connect(G_OBJECT(widget), "expose-event", G_CALLBACK(Window_expose), (gpointer)&window);
|
||||
g_signal_connect(G_OBJECT(widget), "configure-event", G_CALLBACK(Window_configure), (gpointer)&window);
|
||||
}
|
||||
|
||||
unsigned pWindow::menuHeight() {
|
||||
|
@@ -22,6 +22,7 @@
|
||||
#define X11None 0L
|
||||
|
||||
#include <gtk/gtk.h>
|
||||
#include <gdk/gdk.h>
|
||||
#include <gdk/gdkx.h>
|
||||
#include <cairo.h>
|
||||
#include <gdk/gdkkeysyms.h>
|
||||
|
@@ -20,6 +20,8 @@ void pFont::setUnderline(bool underline) { update(); }
|
||||
|
||||
void pFont::constructor() {
|
||||
qtFont = new QFont;
|
||||
font.setFamily("Sans");
|
||||
font.setSize(8);
|
||||
}
|
||||
|
||||
void pFont::update() {
|
||||
|
@@ -20,6 +20,7 @@
|
||||
#include "widget/check-box.cpp"
|
||||
#include "widget/combo-box.cpp"
|
||||
#include "widget/hex-edit.cpp"
|
||||
#include "widget/horizontal-scroll-bar.cpp"
|
||||
#include "widget/horizontal-slider.cpp"
|
||||
#include "widget/label.cpp"
|
||||
#include "widget/line-edit.cpp"
|
||||
@@ -27,6 +28,7 @@
|
||||
#include "widget/progress-bar.cpp"
|
||||
#include "widget/radio-box.cpp"
|
||||
#include "widget/text-edit.cpp"
|
||||
#include "widget/vertical-scroll-bar.cpp"
|
||||
#include "widget/vertical-slider.cpp"
|
||||
#include "widget/viewport.cpp"
|
||||
|
||||
|
@@ -1,7 +1,7 @@
|
||||
/****************************************************************************
|
||||
** Meta object code from reading C++ file 'qt.moc.hpp'
|
||||
**
|
||||
** Created: Tue May 24 19:33:16 2011
|
||||
** Created: Mon Aug 8 04:51:19 2011
|
||||
** by: The Qt Meta Object Compiler version 62 (Qt 4.7.0)
|
||||
**
|
||||
** WARNING! All changes made in this file will be lost!
|
||||
@@ -606,6 +606,67 @@ int pHexEdit::qt_metacall(QMetaObject::Call _c, int _id, void **_a)
|
||||
}
|
||||
return _id;
|
||||
}
|
||||
static const uint qt_meta_data_pHorizontalScrollBar[] = {
|
||||
|
||||
// content:
|
||||
5, // revision
|
||||
0, // classname
|
||||
0, 0, // classinfo
|
||||
1, 14, // methods
|
||||
0, 0, // properties
|
||||
0, 0, // enums/sets
|
||||
0, 0, // constructors
|
||||
0, // flags
|
||||
0, // signalCount
|
||||
|
||||
// slots: signature, parameters, type, tag, flags
|
||||
22, 21, 21, 21, 0x0a,
|
||||
|
||||
0 // eod
|
||||
};
|
||||
|
||||
static const char qt_meta_stringdata_pHorizontalScrollBar[] = {
|
||||
"pHorizontalScrollBar\0\0onChange()\0"
|
||||
};
|
||||
|
||||
const QMetaObject pHorizontalScrollBar::staticMetaObject = {
|
||||
{ &QObject::staticMetaObject, qt_meta_stringdata_pHorizontalScrollBar,
|
||||
qt_meta_data_pHorizontalScrollBar, 0 }
|
||||
};
|
||||
|
||||
#ifdef Q_NO_DATA_RELOCATION
|
||||
const QMetaObject &pHorizontalScrollBar::getStaticMetaObject() { return staticMetaObject; }
|
||||
#endif //Q_NO_DATA_RELOCATION
|
||||
|
||||
const QMetaObject *pHorizontalScrollBar::metaObject() const
|
||||
{
|
||||
return QObject::d_ptr->metaObject ? QObject::d_ptr->metaObject : &staticMetaObject;
|
||||
}
|
||||
|
||||
void *pHorizontalScrollBar::qt_metacast(const char *_clname)
|
||||
{
|
||||
if (!_clname) return 0;
|
||||
if (!strcmp(_clname, qt_meta_stringdata_pHorizontalScrollBar))
|
||||
return static_cast<void*>(const_cast< pHorizontalScrollBar*>(this));
|
||||
if (!strcmp(_clname, "pWidget"))
|
||||
return static_cast< pWidget*>(const_cast< pHorizontalScrollBar*>(this));
|
||||
return QObject::qt_metacast(_clname);
|
||||
}
|
||||
|
||||
int pHorizontalScrollBar::qt_metacall(QMetaObject::Call _c, int _id, void **_a)
|
||||
{
|
||||
_id = QObject::qt_metacall(_c, _id, _a);
|
||||
if (_id < 0)
|
||||
return _id;
|
||||
if (_c == QMetaObject::InvokeMetaMethod) {
|
||||
switch (_id) {
|
||||
case 0: onChange(); break;
|
||||
default: ;
|
||||
}
|
||||
_id -= 1;
|
||||
}
|
||||
return _id;
|
||||
}
|
||||
static const uint qt_meta_data_pHorizontalSlider[] = {
|
||||
|
||||
// content:
|
||||
@@ -745,15 +806,16 @@ static const uint qt_meta_data_pListView[] = {
|
||||
|
||||
// slots: signature, parameters, type, tag, flags
|
||||
11, 10, 10, 10, 0x0a,
|
||||
24, 10, 10, 10, 0x0a,
|
||||
40, 35, 10, 10, 0x0a,
|
||||
29, 24, 10, 10, 0x0a,
|
||||
56, 24, 10, 10, 0x0a,
|
||||
|
||||
0 // eod
|
||||
};
|
||||
|
||||
static const char qt_meta_stringdata_pListView[] = {
|
||||
"pListView\0\0onActivate()\0onChange()\0"
|
||||
"item\0onTick(QTreeWidgetItem*)\0"
|
||||
"pListView\0\0onActivate()\0item\0"
|
||||
"onChange(QTreeWidgetItem*)\0"
|
||||
"onTick(QTreeWidgetItem*)\0"
|
||||
};
|
||||
|
||||
const QMetaObject pListView::staticMetaObject = {
|
||||
@@ -788,7 +850,7 @@ int pListView::qt_metacall(QMetaObject::Call _c, int _id, void **_a)
|
||||
if (_c == QMetaObject::InvokeMetaMethod) {
|
||||
switch (_id) {
|
||||
case 0: onActivate(); break;
|
||||
case 1: onChange(); break;
|
||||
case 1: onChange((*reinterpret_cast< QTreeWidgetItem*(*)>(_a[1]))); break;
|
||||
case 2: onTick((*reinterpret_cast< QTreeWidgetItem*(*)>(_a[1]))); break;
|
||||
default: ;
|
||||
}
|
||||
@@ -918,6 +980,67 @@ int pTextEdit::qt_metacall(QMetaObject::Call _c, int _id, void **_a)
|
||||
}
|
||||
return _id;
|
||||
}
|
||||
static const uint qt_meta_data_pVerticalScrollBar[] = {
|
||||
|
||||
// content:
|
||||
5, // revision
|
||||
0, // classname
|
||||
0, 0, // classinfo
|
||||
1, 14, // methods
|
||||
0, 0, // properties
|
||||
0, 0, // enums/sets
|
||||
0, 0, // constructors
|
||||
0, // flags
|
||||
0, // signalCount
|
||||
|
||||
// slots: signature, parameters, type, tag, flags
|
||||
20, 19, 19, 19, 0x0a,
|
||||
|
||||
0 // eod
|
||||
};
|
||||
|
||||
static const char qt_meta_stringdata_pVerticalScrollBar[] = {
|
||||
"pVerticalScrollBar\0\0onChange()\0"
|
||||
};
|
||||
|
||||
const QMetaObject pVerticalScrollBar::staticMetaObject = {
|
||||
{ &QObject::staticMetaObject, qt_meta_stringdata_pVerticalScrollBar,
|
||||
qt_meta_data_pVerticalScrollBar, 0 }
|
||||
};
|
||||
|
||||
#ifdef Q_NO_DATA_RELOCATION
|
||||
const QMetaObject &pVerticalScrollBar::getStaticMetaObject() { return staticMetaObject; }
|
||||
#endif //Q_NO_DATA_RELOCATION
|
||||
|
||||
const QMetaObject *pVerticalScrollBar::metaObject() const
|
||||
{
|
||||
return QObject::d_ptr->metaObject ? QObject::d_ptr->metaObject : &staticMetaObject;
|
||||
}
|
||||
|
||||
void *pVerticalScrollBar::qt_metacast(const char *_clname)
|
||||
{
|
||||
if (!_clname) return 0;
|
||||
if (!strcmp(_clname, qt_meta_stringdata_pVerticalScrollBar))
|
||||
return static_cast<void*>(const_cast< pVerticalScrollBar*>(this));
|
||||
if (!strcmp(_clname, "pWidget"))
|
||||
return static_cast< pWidget*>(const_cast< pVerticalScrollBar*>(this));
|
||||
return QObject::qt_metacast(_clname);
|
||||
}
|
||||
|
||||
int pVerticalScrollBar::qt_metacall(QMetaObject::Call _c, int _id, void **_a)
|
||||
{
|
||||
_id = QObject::qt_metacall(_c, _id, _a);
|
||||
if (_id < 0)
|
||||
return _id;
|
||||
if (_c == QMetaObject::InvokeMetaMethod) {
|
||||
switch (_id) {
|
||||
case 0: onChange(); break;
|
||||
default: ;
|
||||
}
|
||||
_id -= 1;
|
||||
}
|
||||
return _id;
|
||||
}
|
||||
static const uint qt_meta_data_pVerticalSlider[] = {
|
||||
|
||||
// content:
|
||||
|
@@ -101,10 +101,11 @@ public:
|
||||
void append(Layout &layout);
|
||||
void append(Menu &menu);
|
||||
void append(Widget &widget);
|
||||
Color backgroundColor();
|
||||
Geometry frameMargin();
|
||||
bool focused();
|
||||
Geometry geometry();
|
||||
void setBackgroundColor(uint8_t red, uint8_t green, uint8_t blue);
|
||||
void setBackgroundColor(const Color &color);
|
||||
void setFocused();
|
||||
void setFullScreen(bool fullScreen);
|
||||
void setGeometry(const Geometry &geometry);
|
||||
@@ -330,6 +331,25 @@ public slots:
|
||||
void onScroll();
|
||||
};
|
||||
|
||||
struct pHorizontalScrollBar : public QObject, public pWidget {
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
HorizontalScrollBar &horizontalScrollBar;
|
||||
QScrollBar *qtScrollBar;
|
||||
|
||||
Geometry minimumGeometry();
|
||||
unsigned position();
|
||||
void setLength(unsigned length);
|
||||
void setPosition(unsigned position);
|
||||
|
||||
pHorizontalScrollBar(HorizontalScrollBar &horizontalScrollBar) : pWidget(horizontalScrollBar), horizontalScrollBar(horizontalScrollBar) {}
|
||||
void constructor();
|
||||
|
||||
public slots:
|
||||
void onChange();
|
||||
};
|
||||
|
||||
struct pHorizontalSlider : public QObject, public pWidget {
|
||||
Q_OBJECT
|
||||
|
||||
@@ -406,7 +426,7 @@ public:
|
||||
|
||||
public slots:
|
||||
void onActivate();
|
||||
void onChange();
|
||||
void onChange(QTreeWidgetItem *item);
|
||||
void onTick(QTreeWidgetItem *item);
|
||||
};
|
||||
|
||||
@@ -462,6 +482,25 @@ public slots:
|
||||
void onChange();
|
||||
};
|
||||
|
||||
struct pVerticalScrollBar : public QObject, public pWidget {
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
VerticalScrollBar &verticalScrollBar;
|
||||
QScrollBar *qtScrollBar;
|
||||
|
||||
Geometry minimumGeometry();
|
||||
unsigned position();
|
||||
void setLength(unsigned length);
|
||||
void setPosition(unsigned position);
|
||||
|
||||
pVerticalScrollBar(VerticalScrollBar &verticalScrollBar) : pWidget(verticalScrollBar), verticalScrollBar(verticalScrollBar) {}
|
||||
void constructor();
|
||||
|
||||
public slots:
|
||||
void onChange();
|
||||
};
|
||||
|
||||
struct pVerticalSlider : public QObject, public pWidget {
|
||||
Q_OBJECT
|
||||
|
||||
|
29
bsnes/phoenix/qt/widget/horizontal-scroll-bar.cpp
Executable file
29
bsnes/phoenix/qt/widget/horizontal-scroll-bar.cpp
Executable file
@@ -0,0 +1,29 @@
|
||||
Geometry pHorizontalScrollBar::minimumGeometry() {
|
||||
return { 0, 0, 0, 15 };
|
||||
}
|
||||
|
||||
unsigned pHorizontalScrollBar::position() {
|
||||
return qtScrollBar->value();
|
||||
}
|
||||
|
||||
void pHorizontalScrollBar::setLength(unsigned length) {
|
||||
length += length == 0;
|
||||
qtScrollBar->setRange(0, length - 1);
|
||||
qtScrollBar->setPageStep(length >> 3);
|
||||
}
|
||||
|
||||
void pHorizontalScrollBar::setPosition(unsigned position) {
|
||||
qtScrollBar->setValue(position);
|
||||
}
|
||||
|
||||
void pHorizontalScrollBar::constructor() {
|
||||
qtWidget = qtScrollBar = new QScrollBar(Qt::Horizontal);
|
||||
qtScrollBar->setRange(0, 100);
|
||||
qtScrollBar->setPageStep(101 >> 3);
|
||||
connect(qtScrollBar, SIGNAL(valueChanged(int)), SLOT(onChange()));
|
||||
}
|
||||
|
||||
void pHorizontalScrollBar::onChange() {
|
||||
horizontalScrollBar.state.position = position();
|
||||
if(horizontalScrollBar.onChange) horizontalScrollBar.onChange();
|
||||
}
|
@@ -82,6 +82,7 @@ void pListView::setSelection(unsigned row) {
|
||||
locked = true;
|
||||
QTreeWidgetItem *item = qtListView->currentItem();
|
||||
if(item) item->setSelected(false);
|
||||
qtListView->setCurrentItem(0);
|
||||
auto items = qtListView->findItems("", Qt::MatchContains);
|
||||
for(unsigned n = 0; n < items.size(); n++) {
|
||||
if(items[n]->data(0, Qt::UserRole).toUInt() == row) {
|
||||
@@ -100,7 +101,7 @@ void pListView::constructor() {
|
||||
qtListView->setRootIsDecorated(false);
|
||||
|
||||
connect(qtListView, SIGNAL(itemActivated(QTreeWidgetItem*, int)), SLOT(onActivate()));
|
||||
connect(qtListView, SIGNAL(itemSelectionChanged()), SLOT(onChange()));
|
||||
connect(qtListView, SIGNAL(currentItemChanged(QTreeWidgetItem*, QTreeWidgetItem*)), SLOT(onChange(QTreeWidgetItem*)));
|
||||
connect(qtListView, SIGNAL(itemChanged(QTreeWidgetItem*, int)), SLOT(onTick(QTreeWidgetItem*)));
|
||||
}
|
||||
|
||||
@@ -108,7 +109,9 @@ void pListView::onActivate() {
|
||||
if(locked == false && listView.onActivate) listView.onActivate();
|
||||
}
|
||||
|
||||
void pListView::onChange() {
|
||||
void pListView::onChange(QTreeWidgetItem *item) {
|
||||
//Qt bug workaround: clicking items with mouse does not mark items as selected
|
||||
if(item) item->setSelected(true);
|
||||
listView.state.selected = selected();
|
||||
if(listView.state.selected) listView.state.selection = selection();
|
||||
if(locked == false && listView.onChange) listView.onChange();
|
||||
|
29
bsnes/phoenix/qt/widget/vertical-scroll-bar.cpp
Executable file
29
bsnes/phoenix/qt/widget/vertical-scroll-bar.cpp
Executable file
@@ -0,0 +1,29 @@
|
||||
Geometry pVerticalScrollBar::minimumGeometry() {
|
||||
return { 0, 0, 15, 0 };
|
||||
}
|
||||
|
||||
unsigned pVerticalScrollBar::position() {
|
||||
return qtScrollBar->value();
|
||||
}
|
||||
|
||||
void pVerticalScrollBar::setLength(unsigned length) {
|
||||
length += length == 0;
|
||||
qtScrollBar->setRange(0, length - 1);
|
||||
qtScrollBar->setPageStep(length >> 3);
|
||||
}
|
||||
|
||||
void pVerticalScrollBar::setPosition(unsigned position) {
|
||||
qtScrollBar->setValue(position);
|
||||
}
|
||||
|
||||
void pVerticalScrollBar::constructor() {
|
||||
qtWidget = qtScrollBar = new QScrollBar(Qt::Vertical);
|
||||
qtScrollBar->setRange(0, 100);
|
||||
qtScrollBar->setPageStep(101 >> 3);
|
||||
connect(qtScrollBar, SIGNAL(valueChanged(int)), SLOT(onChange()));
|
||||
}
|
||||
|
||||
void pVerticalScrollBar::onChange() {
|
||||
verticalScrollBar.state.position = position();
|
||||
if(verticalScrollBar.onChange) verticalScrollBar.onChange();
|
||||
}
|
@@ -18,6 +18,12 @@ void pWindow::append(Widget &widget) {
|
||||
widget.setVisible(widget.state.visible);
|
||||
}
|
||||
|
||||
Color pWindow::backgroundColor() {
|
||||
if(window.state.backgroundColorOverride) return window.state.backgroundColor;
|
||||
QColor color = qtWindow->palette().color(QPalette::ColorRole::Window);
|
||||
return { (uint8_t)color.red(), (uint8_t)color.green(), (uint8_t)color.blue(), (uint8_t)color.alpha() };
|
||||
}
|
||||
|
||||
Geometry pWindow::frameMargin() {
|
||||
unsigned menuHeight = window.state.menuVisible ? qtMenu->height() : 0;
|
||||
unsigned statusHeight = window.state.statusVisible ? qtStatus->height() : 0;
|
||||
@@ -43,9 +49,9 @@ Geometry pWindow::geometry() {
|
||||
return window.state.geometry;
|
||||
}
|
||||
|
||||
void pWindow::setBackgroundColor(uint8_t red, uint8_t green, uint8_t blue) {
|
||||
void pWindow::setBackgroundColor(const Color &color) {
|
||||
QPalette palette;
|
||||
palette.setColor(QPalette::Window, QColor(red, green, blue));
|
||||
palette.setColor(QPalette::Window, QColor(color.red, color.green, color.blue));
|
||||
qtContainer->setPalette(palette);
|
||||
qtContainer->setAutoFillBackground(true);
|
||||
}
|
||||
|
@@ -18,6 +18,7 @@
|
||||
#include "widget/check-box.cpp"
|
||||
#include "widget/combo-box.cpp"
|
||||
#include "widget/hex-edit.cpp"
|
||||
#include "widget/horizontal-scroll-bar.cpp"
|
||||
#include "widget/horizontal-slider.cpp"
|
||||
#include "widget/label.cpp"
|
||||
#include "widget/line-edit.cpp"
|
||||
@@ -25,6 +26,7 @@
|
||||
#include "widget/progress-bar.cpp"
|
||||
#include "widget/radio-box.cpp"
|
||||
#include "widget/text-edit.cpp"
|
||||
#include "widget/vertical-scroll-bar.cpp"
|
||||
#include "widget/vertical-slider.cpp"
|
||||
#include "widget/viewport.cpp"
|
||||
|
||||
|
@@ -63,10 +63,11 @@ struct pWindow : public pObject {
|
||||
void append(Layout &layout);
|
||||
void append(Menu &menu);
|
||||
void append(Widget &widget);
|
||||
Color backgroundColor();
|
||||
bool focused();
|
||||
Geometry frameMargin();
|
||||
Geometry geometry();
|
||||
void setBackgroundColor(uint8_t red, uint8_t green, uint8_t blue);
|
||||
void setBackgroundColor(const Color &color);
|
||||
void setFocused();
|
||||
void setFullScreen(bool fullScreen);
|
||||
void setGeometry(const Geometry &geometry);
|
||||
@@ -214,6 +215,17 @@ struct pHexEdit : public pWidget {
|
||||
void constructor();
|
||||
};
|
||||
|
||||
struct pHorizontalScrollBar : public pWidget {
|
||||
HorizontalScrollBar &horizontalScrollBar;
|
||||
|
||||
unsigned position();
|
||||
void setLength(unsigned length);
|
||||
void setPosition(unsigned position);
|
||||
|
||||
pHorizontalScrollBar(HorizontalScrollBar &horizontalScrollBar) : pWidget(horizontalScrollBar), horizontalScrollBar(horizontalScrollBar) {}
|
||||
void constructor();
|
||||
};
|
||||
|
||||
struct pHorizontalSlider : public pWidget {
|
||||
HorizontalSlider &horizontalSlider;
|
||||
|
||||
@@ -300,6 +312,17 @@ struct pTextEdit : public pWidget {
|
||||
void constructor();
|
||||
};
|
||||
|
||||
struct pVerticalScrollBar : public pWidget {
|
||||
VerticalScrollBar &verticalScrollBar;
|
||||
|
||||
unsigned position();
|
||||
void setLength(unsigned length);
|
||||
void setPosition(unsigned position);
|
||||
|
||||
pVerticalScrollBar(VerticalScrollBar &verticalScrollBar) : pWidget(verticalScrollBar), verticalScrollBar(verticalScrollBar) {}
|
||||
void constructor();
|
||||
};
|
||||
|
||||
struct pVerticalSlider : public pWidget {
|
||||
VerticalSlider &verticalSlider;
|
||||
|
||||
|
12
bsnes/phoenix/reference/widget/horizontal-scroll-bar.cpp
Executable file
12
bsnes/phoenix/reference/widget/horizontal-scroll-bar.cpp
Executable file
@@ -0,0 +1,12 @@
|
||||
unsigned pHorizontalScrollBar::position() {
|
||||
return 0;
|
||||
}
|
||||
|
||||
void pHorizontalScrollBar::setLength(unsigned length) {
|
||||
}
|
||||
|
||||
void pHorizontalScrollBar::setPosition(unsigned position) {
|
||||
}
|
||||
|
||||
void pHorizontalScrollBar::constructor() {
|
||||
}
|
12
bsnes/phoenix/reference/widget/vertical-scroll-bar.cpp
Executable file
12
bsnes/phoenix/reference/widget/vertical-scroll-bar.cpp
Executable file
@@ -0,0 +1,12 @@
|
||||
unsigned pVerticalScrollBar::position() {
|
||||
return 0;
|
||||
}
|
||||
|
||||
void pVerticalScrollBar::setLength(unsigned length) {
|
||||
}
|
||||
|
||||
void pVerticalScrollBar::setPosition(unsigned position) {
|
||||
}
|
||||
|
||||
void pVerticalScrollBar::constructor() {
|
||||
}
|
@@ -7,6 +7,10 @@ void pWindow::append(Menu &menu) {
|
||||
void pWindow::append(Widget &widget) {
|
||||
}
|
||||
|
||||
Color pWindow::backgroundColor() {
|
||||
return { 0, 0, 0, 255 };
|
||||
}
|
||||
|
||||
bool pWindow::focused() {
|
||||
return false;
|
||||
}
|
||||
@@ -19,7 +23,7 @@ Geometry pWindow::geometry() {
|
||||
return { 0, 0, 0, 0 };
|
||||
}
|
||||
|
||||
void pWindow::setBackgroundColor(uint8_t red, uint8_t green, uint8_t blue) {
|
||||
void pWindow::setBackgroundColor(const Color &color) {
|
||||
}
|
||||
|
||||
void pWindow::setFocused() {
|
||||
|
@@ -6,3 +6,4 @@ synchronize() {
|
||||
}
|
||||
|
||||
synchronize "nall"
|
||||
rm -r nall/test
|
||||
|
@@ -46,4 +46,6 @@ void pFont::setUnderline(bool underline) {
|
||||
|
||||
void pFont::constructor() {
|
||||
hfont = Font_createFont("Tahoma", 8, false, false, false);
|
||||
font.setFamily("Tahoma");
|
||||
font.setSize(8);
|
||||
}
|
||||
|
33
bsnes/phoenix/windows/widget/horizontal-scroll-bar.cpp
Executable file
33
bsnes/phoenix/windows/widget/horizontal-scroll-bar.cpp
Executable file
@@ -0,0 +1,33 @@
|
||||
Geometry pHorizontalScrollBar::minimumGeometry() {
|
||||
return { 0, 0, 0, 18 };
|
||||
}
|
||||
|
||||
unsigned pHorizontalScrollBar::position() {
|
||||
return GetScrollPos(hwnd, SB_CTL);
|
||||
}
|
||||
|
||||
void pHorizontalScrollBar::setLength(unsigned length) {
|
||||
length += (length == 0);
|
||||
SetScrollRange(hwnd, SB_CTL, 0, length - 1, TRUE);
|
||||
horizontalScrollBar.setPosition(0);
|
||||
}
|
||||
|
||||
void pHorizontalScrollBar::setPosition(unsigned position) { return;
|
||||
SetScrollPos(hwnd, SB_CTL, position, TRUE);
|
||||
}
|
||||
|
||||
void pHorizontalScrollBar::constructor() {
|
||||
setParent(Window::None);
|
||||
}
|
||||
|
||||
void pHorizontalScrollBar::setParent(Window &parent) {
|
||||
if(hwnd) DestroyWindow(hwnd);
|
||||
hwnd = CreateWindow(
|
||||
L"SCROLLBAR", L"", WS_CHILD | WS_VISIBLE | WS_TABSTOP | SBS_HORZ,
|
||||
0, 0, 0, 0, parent.p.hwnd, (HMENU)id, GetModuleHandle(0), 0
|
||||
);
|
||||
SetWindowLongPtr(hwnd, GWLP_USERDATA, (LONG_PTR)&horizontalScrollBar);
|
||||
unsigned position = horizontalScrollBar.state.position;
|
||||
setLength(horizontalScrollBar.state.length);
|
||||
setPosition(position);
|
||||
}
|
@@ -28,6 +28,7 @@ void pHorizontalSlider::setParent(Window &parent) {
|
||||
0, 0, 0, 0, parent.p.hwnd, (HMENU)id, GetModuleHandle(0), 0
|
||||
);
|
||||
SetWindowLongPtr(hwnd, GWLP_USERDATA, (LONG_PTR)&horizontalSlider);
|
||||
unsigned position = horizontalSlider.state.position;
|
||||
setLength(horizontalSlider.state.length);
|
||||
setPosition(horizontalSlider.state.position);
|
||||
setPosition(position);
|
||||
}
|
||||
|
@@ -13,8 +13,6 @@ void pListView::append(const lstring &list) {
|
||||
utf16_t wtext(text);
|
||||
ListView_SetItemText(hwnd, row, n, wtext);
|
||||
}
|
||||
//workaround: when there is only one column, the horizontal scrollbar will always appear without this
|
||||
if(listView.state.headerText.size() <= 1) ListView_SetColumnWidth(hwnd, 0, LVSCW_AUTOSIZE_USEHEADER);
|
||||
}
|
||||
|
||||
void pListView::autoSizeColumns() {
|
||||
@@ -32,7 +30,6 @@ void pListView::modify(unsigned row, const lstring &list) {
|
||||
utf16_t wtext(text);
|
||||
ListView_SetItemText(hwnd, row, n, wtext);
|
||||
}
|
||||
if(listView.state.headerText.size() <= 1) ListView_SetColumnWidth(hwnd, 0, LVSCW_AUTOSIZE_USEHEADER);
|
||||
}
|
||||
|
||||
void pListView::reset() {
|
||||
@@ -110,6 +107,7 @@ void pListView::setSelection(unsigned row) {
|
||||
void pListView::constructor() {
|
||||
lostFocus = false;
|
||||
setParent(Window::None);
|
||||
listView.setHeaderText("");
|
||||
}
|
||||
|
||||
void pListView::setGeometry(const Geometry &geometry) {
|
||||
|
33
bsnes/phoenix/windows/widget/vertical-scroll-bar.cpp
Executable file
33
bsnes/phoenix/windows/widget/vertical-scroll-bar.cpp
Executable file
@@ -0,0 +1,33 @@
|
||||
Geometry pVerticalScrollBar::minimumGeometry() {
|
||||
return { 0, 0, 18, 0 };
|
||||
}
|
||||
|
||||
unsigned pVerticalScrollBar::position() {
|
||||
return GetScrollPos(hwnd, SB_CTL);
|
||||
}
|
||||
|
||||
void pVerticalScrollBar::setLength(unsigned length) {
|
||||
length += (length == 0);
|
||||
SetScrollRange(hwnd, SB_CTL, 0, length - 1, TRUE);
|
||||
verticalScrollBar.setPosition(0);
|
||||
}
|
||||
|
||||
void pVerticalScrollBar::setPosition(unsigned position) {
|
||||
SetScrollPos(hwnd, SB_CTL, position, TRUE);
|
||||
}
|
||||
|
||||
void pVerticalScrollBar::constructor() {
|
||||
setParent(Window::None);
|
||||
}
|
||||
|
||||
void pVerticalScrollBar::setParent(Window &parent) {
|
||||
if(hwnd) DestroyWindow(hwnd);
|
||||
hwnd = CreateWindow(
|
||||
L"SCROLLBAR", L"", WS_CHILD | WS_VISIBLE | SBS_VERT,
|
||||
0, 0, 0, 0, parent.p.hwnd, (HMENU)id, GetModuleHandle(0), 0
|
||||
);
|
||||
SetWindowLongPtr(hwnd, GWLP_USERDATA, (LONG_PTR)&verticalScrollBar);
|
||||
unsigned position = verticalScrollBar.state.position;
|
||||
setLength(verticalScrollBar.state.length);
|
||||
setPosition(position);
|
||||
}
|
@@ -1,5 +1,5 @@
|
||||
Geometry pVerticalSlider::minimumGeometry() {
|
||||
return { 0, 0, 25, 0 };
|
||||
return { 0, 0, 0, 25 };
|
||||
}
|
||||
|
||||
unsigned pVerticalSlider::position() {
|
||||
@@ -28,6 +28,7 @@ void pVerticalSlider::setParent(Window &parent) {
|
||||
0, 0, 0, 0, parent.p.hwnd, (HMENU)id, GetModuleHandle(0), 0
|
||||
);
|
||||
SetWindowLongPtr(hwnd, GWLP_USERDATA, (LONG_PTR)&verticalSlider);
|
||||
unsigned position = verticalSlider.state.position;
|
||||
setLength(verticalSlider.state.length);
|
||||
setPosition(verticalSlider.state.position);
|
||||
setPosition(position);
|
||||
}
|
||||
|
@@ -16,6 +16,12 @@ void pWindow::append(Widget &widget) {
|
||||
widget.p.setParent(window);
|
||||
}
|
||||
|
||||
Color pWindow::backgroundColor() {
|
||||
if(window.state.backgroundColorOverride) return window.state.backgroundColor;
|
||||
DWORD color = GetSysColor(COLOR_3DFACE);
|
||||
return { (uint8_t)(color >> 16), (uint8_t)(color >> 8), (uint8_t)(color >> 0), 255 };
|
||||
}
|
||||
|
||||
bool pWindow::focused() {
|
||||
return (GetForegroundWindow() == hwnd);
|
||||
}
|
||||
@@ -37,10 +43,15 @@ Geometry pWindow::frameMargin() {
|
||||
Geometry pWindow::geometry() {
|
||||
Geometry margin = frameMargin();
|
||||
|
||||
//note: GetWindowRect returns -32000(x),-32000(y) when window is minimized
|
||||
WINDOWPLACEMENT wp;
|
||||
GetWindowPlacement(hwnd, &wp);
|
||||
RECT rc = wp.rcNormalPosition;
|
||||
RECT rc;
|
||||
if(IsIconic(hwnd)) {
|
||||
//GetWindowRect returns -32000(x),-32000(y) when window is minimized
|
||||
WINDOWPLACEMENT wp;
|
||||
GetWindowPlacement(hwnd, &wp);
|
||||
rc = wp.rcNormalPosition;
|
||||
} else {
|
||||
GetWindowRect(hwnd, &rc);
|
||||
}
|
||||
|
||||
signed x = rc.left + margin.x;
|
||||
signed y = rc.top + margin.y;
|
||||
@@ -50,9 +61,9 @@ Geometry pWindow::geometry() {
|
||||
return { x, y, width, height };
|
||||
}
|
||||
|
||||
void pWindow::setBackgroundColor(uint8_t red, uint8_t green, uint8_t blue) {
|
||||
void pWindow::setBackgroundColor(const Color &color) {
|
||||
if(brush) DeleteObject(brush);
|
||||
brushColor = RGB(red, green, blue);
|
||||
brushColor = RGB(color.red, color.green, color.blue);
|
||||
brush = CreateSolidBrush(brushColor);
|
||||
}
|
||||
|
||||
|
@@ -19,6 +19,7 @@
|
||||
#include "widget/check-box.cpp"
|
||||
#include "widget/combo-box.cpp"
|
||||
#include "widget/hex-edit.cpp"
|
||||
#include "widget/horizontal-scroll-bar.cpp"
|
||||
#include "widget/horizontal-slider.cpp"
|
||||
#include "widget/label.cpp"
|
||||
#include "widget/line-edit.cpp"
|
||||
@@ -26,6 +27,7 @@
|
||||
#include "widget/progress-bar.cpp"
|
||||
#include "widget/radio-box.cpp"
|
||||
#include "widget/text-edit.cpp"
|
||||
#include "widget/vertical-scroll-bar.cpp"
|
||||
#include "widget/vertical-slider.cpp"
|
||||
#include "widget/viewport.cpp"
|
||||
|
||||
@@ -175,7 +177,7 @@ void pOS::initialize() {
|
||||
WNDCLASS wc;
|
||||
wc.cbClsExtra = 0;
|
||||
wc.cbWndExtra = 0;
|
||||
wc.hbrBackground = (HBRUSH)(COLOR_3DFACE + 1);
|
||||
wc.hbrBackground = GetSysColorBrush(COLOR_3DFACE);
|
||||
wc.hCursor = LoadCursor(0, IDC_ARROW);
|
||||
wc.hIcon = LoadIcon(GetModuleHandle(0), MAKEINTRESOURCE(2));
|
||||
wc.hInstance = GetModuleHandle(0);
|
||||
@@ -199,7 +201,7 @@ void pOS::initialize() {
|
||||
|
||||
wc.cbClsExtra = 0;
|
||||
wc.cbWndExtra = 0;
|
||||
wc.hbrBackground = (HBRUSH)(COLOR_3DFACE + 1);
|
||||
wc.hbrBackground = GetSysColorBrush(COLOR_3DFACE);
|
||||
wc.hCursor = LoadCursor(0, IDC_ARROW);
|
||||
wc.hIcon = LoadIcon(0, IDI_APPLICATION);
|
||||
wc.hInstance = GetModuleHandle(0);
|
||||
@@ -408,11 +410,58 @@ static LRESULT CALLBACK OS_windowProc(HWND hwnd, UINT msg, WPARAM wparam, LPARAM
|
||||
|
||||
case WM_HSCROLL:
|
||||
case WM_VSCROLL: {
|
||||
unsigned id = LOWORD(wparam);
|
||||
HWND control = GetDlgItem(window.p.hwnd, id);
|
||||
if(control == 0) break;
|
||||
Object *object = (Object*)GetWindowLongPtr(control, GWLP_USERDATA);
|
||||
Object *object = 0;
|
||||
if(lparam) {
|
||||
object = (Object*)GetWindowLongPtr((HWND)lparam, GWLP_USERDATA);
|
||||
} else {
|
||||
unsigned id = LOWORD(wparam);
|
||||
HWND control = GetDlgItem(window.p.hwnd, id);
|
||||
if(control == 0) break;
|
||||
object = (Object*)GetWindowLongPtr(control, GWLP_USERDATA);
|
||||
}
|
||||
if(object == 0) break;
|
||||
|
||||
if(dynamic_cast<HorizontalScrollBar*>(object)
|
||||
|| dynamic_cast<VerticalScrollBar*>(object)) {
|
||||
SCROLLINFO info;
|
||||
memset(&info, 0, sizeof(SCROLLINFO));
|
||||
info.cbSize = sizeof(SCROLLINFO);
|
||||
info.fMask = SIF_ALL;
|
||||
GetScrollInfo((HWND)lparam, SB_CTL, &info);
|
||||
|
||||
switch(LOWORD(wparam)) {
|
||||
case SB_LEFT: info.nPos = info.nMin; break;
|
||||
case SB_RIGHT: info.nPos = info.nMax; break;
|
||||
case SB_LINELEFT: info.nPos--; break;
|
||||
case SB_LINERIGHT: info.nPos++; break;
|
||||
case SB_PAGELEFT: info.nPos -= info.nMax >> 3; break;
|
||||
case SB_PAGERIGHT: info.nPos += info.nMax >> 3; break;
|
||||
case SB_THUMBTRACK: info.nPos = info.nTrackPos; break;
|
||||
}
|
||||
|
||||
info.fMask = SIF_POS;
|
||||
SetScrollInfo((HWND)lparam, SB_CTL, &info, TRUE);
|
||||
|
||||
//Windows may clamp position to scrollbar range
|
||||
GetScrollInfo((HWND)lparam, SB_CTL, &info);
|
||||
|
||||
if(dynamic_cast<HorizontalScrollBar*>(object)) {
|
||||
HorizontalScrollBar &horizontalScrollBar = (HorizontalScrollBar&)*object;
|
||||
if(horizontalScrollBar.state.position != info.nPos) {
|
||||
horizontalScrollBar.state.position = info.nPos;
|
||||
horizontalScrollBar.onChange();
|
||||
}
|
||||
} else {
|
||||
VerticalScrollBar &verticalScrollBar = (VerticalScrollBar&)*object;
|
||||
if(verticalScrollBar.state.position != info.nPos) {
|
||||
verticalScrollBar.state.position = info.nPos;
|
||||
verticalScrollBar.onChange();
|
||||
}
|
||||
}
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
if(dynamic_cast<HorizontalSlider*>(object)) {
|
||||
HorizontalSlider &horizontalSlider = (HorizontalSlider&)*object;
|
||||
if(horizontalSlider.state.position != horizontalSlider.position()) {
|
||||
|
@@ -78,10 +78,11 @@ struct pWindow : public pObject {
|
||||
void append(Layout &layout);
|
||||
void append(Menu &menu);
|
||||
void append(Widget &widget);
|
||||
Color backgroundColor();
|
||||
bool focused();
|
||||
Geometry frameMargin();
|
||||
Geometry geometry();
|
||||
void setBackgroundColor(uint8_t red, uint8_t green, uint8_t blue);
|
||||
void setBackgroundColor(const Color &color);
|
||||
void setFocused();
|
||||
void setFullScreen(bool fullScreen);
|
||||
void setGeometry(const Geometry &geometry);
|
||||
@@ -250,6 +251,19 @@ struct pHexEdit : public pWidget {
|
||||
void setParent(Window &parent);
|
||||
};
|
||||
|
||||
struct pHorizontalScrollBar : public pWidget {
|
||||
HorizontalScrollBar &horizontalScrollBar;
|
||||
|
||||
Geometry minimumGeometry();
|
||||
unsigned position();
|
||||
void setLength(unsigned length);
|
||||
void setPosition(unsigned position);
|
||||
|
||||
pHorizontalScrollBar(HorizontalScrollBar &horizontalScrollBar) : pWidget(horizontalScrollBar), horizontalScrollBar(horizontalScrollBar) {}
|
||||
void constructor();
|
||||
void setParent(Window &parent);
|
||||
};
|
||||
|
||||
struct pHorizontalSlider : public pWidget {
|
||||
HorizontalSlider &horizontalSlider;
|
||||
|
||||
@@ -350,6 +364,19 @@ struct pTextEdit : public pWidget {
|
||||
void setParent(Window &parent);
|
||||
};
|
||||
|
||||
struct pVerticalScrollBar : public pWidget {
|
||||
VerticalScrollBar &verticalScrollBar;
|
||||
|
||||
Geometry minimumGeometry();
|
||||
unsigned position();
|
||||
void setLength(unsigned length);
|
||||
void setPosition(unsigned position);
|
||||
|
||||
pVerticalScrollBar(VerticalScrollBar &verticalScrollBar) : pWidget(verticalScrollBar), verticalScrollBar(verticalScrollBar) {}
|
||||
void constructor();
|
||||
void setParent(Window &parent);
|
||||
};
|
||||
|
||||
struct pVerticalSlider : public pWidget {
|
||||
VerticalSlider &verticalSlider;
|
||||
|
||||
|
@@ -97,7 +97,7 @@ struct pInputSDL {
|
||||
//Keyboard
|
||||
//========
|
||||
|
||||
x_poll(table);
|
||||
x_poll(device.display, table);
|
||||
|
||||
//=====
|
||||
//Mouse
|
||||
@@ -172,7 +172,6 @@ struct pInputSDL {
|
||||
}
|
||||
|
||||
bool init() {
|
||||
x_init();
|
||||
SDL_InitSubSystem(SDL_INIT_JOYSTICK);
|
||||
SDL_JoystickEventState(SDL_IGNORE);
|
||||
|
||||
@@ -182,6 +181,7 @@ struct pInputSDL {
|
||||
XGetWindowAttributes(device.display, device.rootwindow, &attributes);
|
||||
device.screenwidth = attributes.width;
|
||||
device.screenheight = attributes.height;
|
||||
x_init(device.display);
|
||||
|
||||
//Xlib: "because XShowCursor(false) would be too easy."
|
||||
//create a fully transparent cursor named InvisibleCursor,
|
||||
|
@@ -30,13 +30,13 @@ public:
|
||||
|
||||
bool poll(int16_t *table) {
|
||||
memset(table, 0, Scancode::Limit * sizeof(int16_t));
|
||||
x_poll(table);
|
||||
x_poll(display, table);
|
||||
return true;
|
||||
}
|
||||
|
||||
bool init() {
|
||||
x_init();
|
||||
display = XOpenDisplay(0);
|
||||
x_init(display);
|
||||
return true;
|
||||
}
|
||||
|
||||
|
@@ -16,11 +16,11 @@ enum XScancode {
|
||||
LeftShift, RightShift, LeftControl, RightControl, LeftAlt, RightAlt, LeftSuper, RightSuper,
|
||||
};
|
||||
|
||||
void x_poll(int16_t *table) {
|
||||
void x_poll(Display *display, int16_t *table) {
|
||||
if(!display) return;
|
||||
|
||||
char state[32];
|
||||
Display *display = XOpenDisplay(0);
|
||||
XQueryKeymap(display, state);
|
||||
XCloseDisplay(display);
|
||||
|
||||
#define key(id) table[keyboard(0)[id]]
|
||||
#define pressed(id) (bool)(state[scancode[id] >> 3] & (1 << (scancode[id] & 7)))
|
||||
@@ -139,8 +139,9 @@ void x_poll(int16_t *table) {
|
||||
#undef pressed
|
||||
}
|
||||
|
||||
void x_init() {
|
||||
Display *display = XOpenDisplay(0);
|
||||
void x_init(Display *display) {
|
||||
if(!display) return;
|
||||
|
||||
memset(&scancode, 0, sizeof scancode);
|
||||
|
||||
#define assign(x, y) scancode[x] = XKeysymToKeycode(display, y)
|
||||
@@ -259,6 +260,4 @@ void x_init() {
|
||||
assign(Menu, XK_Menu);
|
||||
|
||||
#undef assign
|
||||
|
||||
XCloseDisplay(display);
|
||||
}
|
||||
|
@@ -34,7 +34,7 @@ void Cartridge::load(Mode cartridge_mode, const lstring &xml_list) {
|
||||
nvram.reset();
|
||||
|
||||
parse_xml(xml_list);
|
||||
print(xml_list[0], "\n\n");
|
||||
//print(xml_list[0], "\n\n");
|
||||
|
||||
if(ram_size > 0) {
|
||||
ram.map(allocate<uint8>(ram_size, 0xff), ram_size);
|
||||
@@ -54,7 +54,7 @@ void Cartridge::load(Mode cartridge_mode, const lstring &xml_list) {
|
||||
sha256_hash(&sha, shahash);
|
||||
|
||||
string hash;
|
||||
foreach(n, shahash) hash << hex<2>(n);
|
||||
foreach(n, shahash) hash.append(hex<2>(n));
|
||||
sha256 = hash;
|
||||
|
||||
system.load();
|
||||
|
@@ -284,8 +284,7 @@ void Cartridge::xml_parse_necdsp(xml_element &root) {
|
||||
for(unsigned n = 0; n < 16384; n++) necdsp.programROM[n] = 0x000000;
|
||||
for(unsigned n = 0; n < 2048; n++) necdsp.dataROM[n] = 0x0000;
|
||||
|
||||
string program, programhash;
|
||||
string sha256;
|
||||
string firmware, sha256;
|
||||
|
||||
foreach(attr, root.attribute) {
|
||||
if(attr.name == "model") {
|
||||
@@ -293,36 +292,39 @@ void Cartridge::xml_parse_necdsp(xml_element &root) {
|
||||
if(attr.content == "uPD96050") necdsp.revision = NECDSP::Revision::uPD96050;
|
||||
} else if(attr.name == "frequency") {
|
||||
necdsp.frequency = xml_parse_unsigned(attr.content);
|
||||
} else if(attr.name == "program") {
|
||||
program = attr.content;
|
||||
} else if(attr.name == "firmware") {
|
||||
firmware = attr.content;
|
||||
} else if(attr.name == "sha256") {
|
||||
sha256 = attr.content;
|
||||
}
|
||||
}
|
||||
|
||||
string path = { dir(system.interface->path(Slot::Base, ".dsp")), program };
|
||||
string path = { dir(system.interface->path(Slot::Base, ".dsp")), firmware };
|
||||
unsigned promsize = (necdsp.revision == NECDSP::Revision::uPD7725 ? 2048 : 16384);
|
||||
unsigned dromsize = (necdsp.revision == NECDSP::Revision::uPD7725 ? 1024 : 2048);
|
||||
unsigned filesize = promsize * 3 + dromsize * 2;
|
||||
|
||||
file fp;
|
||||
if(fp.open(path, file::mode::read)) {
|
||||
if(fp.size() == filesize) {
|
||||
for(unsigned n = 0; n < promsize; n++) necdsp.programROM[n] = fp.readm(3);
|
||||
for(unsigned n = 0; n < dromsize; n++) necdsp.dataROM[n] = fp.readm(2);
|
||||
if(fp.open(path, file::mode::read) == false) {
|
||||
system.interface->message({ "Warning: NEC DSP firmware ", firmware, " is missing." });
|
||||
} else if(fp.size() != filesize) {
|
||||
system.interface->message({ "Warning: NEC DSP firmware ", firmware, " is of the wrong file size." });
|
||||
fp.close();
|
||||
} else {
|
||||
for(unsigned n = 0; n < promsize; n++) necdsp.programROM[n] = fp.readm(3);
|
||||
for(unsigned n = 0; n < dromsize; n++) necdsp.dataROM[n] = fp.readm(2);
|
||||
|
||||
if(sha256 != "") {
|
||||
//XML file specified SHA256 sum for program. Verify file matches the hash.
|
||||
fp.seek(0);
|
||||
uint8_t data[filesize];
|
||||
fp.read(data, filesize);
|
||||
|
||||
sha256_ctx sha;
|
||||
uint8 shahash[32];
|
||||
sha256_init(&sha);
|
||||
sha256_chunk(&sha, data, filesize);
|
||||
sha256_final(&sha);
|
||||
sha256_hash(&sha, shahash);
|
||||
foreach(n, shahash) programhash.append(hex<2>(n));
|
||||
if(sha256 != nall::sha256(data, filesize)) {
|
||||
system.interface->message({ "Warning: Hitachi DSP firmware ", firmware, " SHA256 sum is incorrect." });
|
||||
}
|
||||
}
|
||||
|
||||
fp.close();
|
||||
}
|
||||
|
||||
@@ -359,16 +361,6 @@ void Cartridge::xml_parse_necdsp(xml_element &root) {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if(programhash == "") {
|
||||
system.interface->message({ "Warning: NEC DSP program ", program, " is missing." });
|
||||
} else if(sha256 != "" && sha256 != programhash) {
|
||||
system.interface->message({
|
||||
"Warning: NEC DSP program ", program, " SHA256 is incorrect.\n\n"
|
||||
"Expected:\n", sha256, "\n\n"
|
||||
"Actual:\n", programhash
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
void Cartridge::xml_parse_hitachidsp(xml_element &root) {
|
||||
@@ -377,24 +369,24 @@ void Cartridge::xml_parse_hitachidsp(xml_element &root) {
|
||||
|
||||
for(unsigned n = 0; n < 1024; n++) hitachidsp.dataROM[n] = 0x000000;
|
||||
|
||||
string dataROM, sha256;
|
||||
string firmware, sha256;
|
||||
|
||||
foreach(attr, root.attribute) {
|
||||
if(attr.name == "frequency") {
|
||||
hitachidsp.frequency = xml_parse_unsigned(attr.content);
|
||||
} else if(attr.name == "data") {
|
||||
dataROM = attr.content;
|
||||
} else if(attr.name == "firmware") {
|
||||
firmware = attr.content;
|
||||
} else if(attr.name == "sha256") {
|
||||
sha256 = attr.content;
|
||||
}
|
||||
}
|
||||
|
||||
string path = { dir(system.interface->path(Slot::Base, ".dsp")), dataROM };
|
||||
string path = { dir(system.interface->path(Slot::Base, ".dsp")), firmware };
|
||||
file fp;
|
||||
if(fp.open(path, file::mode::read) == false) {
|
||||
system.interface->message({ "Warning: Hitachi DSP data ", dataROM, " is missing." });
|
||||
system.interface->message({ "Warning: Hitachi DSP firmware ", firmware, " is missing." });
|
||||
} else if(fp.size() != 1024 * 3) {
|
||||
system.interface->message({ "Warning: Hitachi DSP data ", dataROM, " is of the wrong file size." });
|
||||
system.interface->message({ "Warning: Hitachi DSP firmware ", firmware, " is of the wrong file size." });
|
||||
fp.close();
|
||||
} else {
|
||||
for(unsigned n = 0; n < 1024; n++) hitachidsp.dataROM[n] = fp.readl(3);
|
||||
@@ -405,18 +397,8 @@ void Cartridge::xml_parse_hitachidsp(xml_element &root) {
|
||||
uint8 data[3072];
|
||||
fp.read(data, 3072);
|
||||
|
||||
sha256_ctx sha;
|
||||
uint8 hash[32];
|
||||
sha256_init(&sha);
|
||||
sha256_chunk(&sha, data, 3072);
|
||||
sha256_final(&sha);
|
||||
sha256_hash(&sha, hash);
|
||||
|
||||
string filehash;
|
||||
foreach(n, hash) filehash.append(hex<2>(n));
|
||||
|
||||
if(sha256 != filehash) {
|
||||
system.interface->message({ "Warning: Hitachi DSP data ", dataROM, " SHA256 sum is incorrect." });
|
||||
if(sha256 != nall::sha256(data, 3072)) {
|
||||
system.interface->message({ "Warning: Hitachi DSP firmware ", firmware, " SHA256 sum is incorrect." });
|
||||
}
|
||||
}
|
||||
|
||||
|
@@ -86,7 +86,7 @@ bool Cheat::decode(const char *s, unsigned &addr, uint8 &data, Type &type) {
|
||||
|
||||
if(strlen(t) == 8 || (strlen(t) == 9 && t[6] == ':')) {
|
||||
//strip ':'
|
||||
if(strlen(t) == 9 && t[6] == ':') t = string() << substr(t, 0, 6) << substr(t, 7);
|
||||
if(strlen(t) == 9 && t[6] == ':') t = { substr(t, 0, 6), substr(t, 7) };
|
||||
//validate input
|
||||
for(unsigned i = 0; i < 8; i++) if(!ischr(t[i])) return false;
|
||||
|
||||
@@ -97,7 +97,7 @@ bool Cheat::decode(const char *s, unsigned &addr, uint8 &data, Type &type) {
|
||||
return true;
|
||||
} else if(strlen(t) == 9 && t[4] == '-') {
|
||||
//strip '-'
|
||||
t = string() << substr(t, 0, 4) << substr(t, 5);
|
||||
t = { substr(t, 0, 4), substr(t, 5) };
|
||||
//validate input
|
||||
for(unsigned i = 0; i < 8; i++) if(!ischr(t[i])) return false;
|
||||
|
||||
|
@@ -101,7 +101,7 @@ bool ICD2::input_poll(unsigned id) {
|
||||
case 3: data = ~r6007; break;
|
||||
}
|
||||
|
||||
switch(id) {
|
||||
switch((GameBoy::Input)id) {
|
||||
case GameBoy::Input::Start: return data & 0x80;
|
||||
case GameBoy::Input::Select: return data & 0x40;
|
||||
case GameBoy::Input::B: return data & 0x20;
|
||||
|
@@ -16,114 +16,97 @@ string NECDSP::disassemble(uint14 ip) {
|
||||
uint4 dst = opcode >> 0;
|
||||
|
||||
switch(alu) {
|
||||
case 0: output << "nop "; break;
|
||||
case 1: output << "or "; break;
|
||||
case 2: output << "and "; break;
|
||||
case 3: output << "xor "; break;
|
||||
case 4: output << "sub "; break;
|
||||
case 5: output << "add "; break;
|
||||
case 6: output << "sbb "; break;
|
||||
case 7: output << "adc "; break;
|
||||
case 8: output << "dec "; break;
|
||||
case 9: output << "inc "; break;
|
||||
case 10: output << "cmp "; break;
|
||||
case 11: output << "shr1 "; break;
|
||||
case 12: output << "shl1 "; break;
|
||||
case 13: output << "shl2 "; break;
|
||||
case 14: output << "shl4 "; break;
|
||||
case 15: output << "xchg "; break;
|
||||
case 0: output.append("nop "); break;
|
||||
case 1: output.append("or "); break;
|
||||
case 2: output.append("and "); break;
|
||||
case 3: output.append("xor "); break;
|
||||
case 4: output.append("sub "); break;
|
||||
case 5: output.append("add "); break;
|
||||
case 6: output.append("sbb "); break;
|
||||
case 7: output.append("adc "); break;
|
||||
case 8: output.append("dec "); break;
|
||||
case 9: output.append("inc "); break;
|
||||
case 10: output.append("cmp "); break;
|
||||
case 11: output.append("shr1 "); break;
|
||||
case 12: output.append("shl1 "); break;
|
||||
case 13: output.append("shl2 "); break;
|
||||
case 14: output.append("shl4 "); break;
|
||||
case 15: output.append("xchg "); break;
|
||||
}
|
||||
|
||||
if(alu < 8) {
|
||||
switch(pselect) {
|
||||
case 0: output << "ram,"; break;
|
||||
case 1: output << "idb,"; break;
|
||||
case 2: output << "m,"; break;
|
||||
case 3: output << "n,"; break;
|
||||
case 0: output.append("ram,"); break;
|
||||
case 1: output.append("idb,"); break;
|
||||
case 2: output.append("m," ); break;
|
||||
case 3: output.append("n," ); break;
|
||||
}
|
||||
}
|
||||
|
||||
switch(asl) {
|
||||
case 0: output << "a"; break;
|
||||
case 1: output << "b"; break;
|
||||
case 0: output.append("a"); break;
|
||||
case 1: output.append("b"); break;
|
||||
}
|
||||
|
||||
output << "\n mov ";
|
||||
output.append("\n mov ");
|
||||
|
||||
switch(src) {
|
||||
case 0: output << "trb,"; break;
|
||||
case 1: output << "a,"; break;
|
||||
case 2: output << "b,"; break;
|
||||
case 3: output << "tr,"; break;
|
||||
case 4: output << "dp,"; break;
|
||||
case 5: output << "rp,"; break;
|
||||
case 6: output << "ro,"; break;
|
||||
case 7: output << "sgn,"; break;
|
||||
case 8: output << "dr,"; break;
|
||||
case 9: output << "drnf,"; break;
|
||||
case 10: output << "sr,"; break;
|
||||
case 11: output << "sim,"; break;
|
||||
case 12: output << "sil,"; break;
|
||||
case 13: output << "k,"; break;
|
||||
case 14: output << "l,"; break;
|
||||
case 15: output << "mem,"; break;
|
||||
case 0: output.append("trb," ); break;
|
||||
case 1: output.append("a," ); break;
|
||||
case 2: output.append("b," ); break;
|
||||
case 3: output.append("tr," ); break;
|
||||
case 4: output.append("dp," ); break;
|
||||
case 5: output.append("rp," ); break;
|
||||
case 6: output.append("ro," ); break;
|
||||
case 7: output.append("sgn," ); break;
|
||||
case 8: output.append("dr," ); break;
|
||||
case 9: output.append("drnf,"); break;
|
||||
case 10: output.append("sr," ); break;
|
||||
case 11: output.append("sim," ); break;
|
||||
case 12: output.append("sil," ); break;
|
||||
case 13: output.append("k," ); break;
|
||||
case 14: output.append("l," ); break;
|
||||
case 15: output.append("mem," ); break;
|
||||
}
|
||||
|
||||
switch(dst) {
|
||||
case 0: output << "non"; break;
|
||||
case 1: output << "a"; break;
|
||||
case 2: output << "b"; break;
|
||||
case 3: output << "tr"; break;
|
||||
case 4: output << "dp"; break;
|
||||
case 5: output << "rp"; break;
|
||||
case 6: output << "dr"; break;
|
||||
case 7: output << "sr"; break;
|
||||
case 8: output << "sol"; break;
|
||||
case 9: output << "som"; break;
|
||||
case 10: output << "k"; break;
|
||||
case 11: output << "klr"; break;
|
||||
case 12: output << "klm"; break;
|
||||
case 13: output << "l"; break;
|
||||
case 14: output << "trb"; break;
|
||||
case 15: output << "mem"; break;
|
||||
case 0: output.append("non"); break;
|
||||
case 1: output.append("a" ); break;
|
||||
case 2: output.append("b" ); break;
|
||||
case 3: output.append("tr" ); break;
|
||||
case 4: output.append("dp" ); break;
|
||||
case 5: output.append("rp" ); break;
|
||||
case 6: output.append("dr" ); break;
|
||||
case 7: output.append("sr" ); break;
|
||||
case 8: output.append("sol"); break;
|
||||
case 9: output.append("som"); break;
|
||||
case 10: output.append("k" ); break;
|
||||
case 11: output.append("klr"); break;
|
||||
case 12: output.append("klm"); break;
|
||||
case 13: output.append("l" ); break;
|
||||
case 14: output.append("trb"); break;
|
||||
case 15: output.append("mem"); break;
|
||||
}
|
||||
|
||||
if(dpl) {
|
||||
switch(dpl) {
|
||||
case 0: output << "\n dpnop"; break;
|
||||
case 1: output << "\n dpinc"; break;
|
||||
case 2: output << "\n dpdec"; break;
|
||||
case 3: output << "\n dpclr"; break;
|
||||
case 0: output.append("\n dpnop"); break;
|
||||
case 1: output.append("\n dpinc"); break;
|
||||
case 2: output.append("\n dpdec"); break;
|
||||
case 3: output.append("\n dpclr"); break;
|
||||
}
|
||||
}
|
||||
|
||||
if(dphm) {
|
||||
switch(dphm) {
|
||||
case 0: output << "\n m0"; break;
|
||||
case 1: output << "\n m1"; break;
|
||||
case 2: output << "\n m2"; break;
|
||||
case 3: output << "\n m3"; break;
|
||||
case 4: output << "\n m4"; break;
|
||||
case 5: output << "\n m5"; break;
|
||||
case 6: output << "\n m6"; break;
|
||||
case 7: output << "\n m7"; break;
|
||||
case 8: output << "\n m8"; break;
|
||||
case 9: output << "\n m9"; break;
|
||||
case 10: output << "\n ma"; break;
|
||||
case 11: output << "\n mb"; break;
|
||||
case 12: output << "\n mc"; break;
|
||||
case 13: output << "\n md"; break;
|
||||
case 14: output << "\n me"; break;
|
||||
case 15: output << "\n mf"; break;
|
||||
}
|
||||
output.append("\n m", hex<1>(dphm));
|
||||
}
|
||||
|
||||
if(rpdcr == 1) {
|
||||
output << "\n rpdec";
|
||||
output.append("\n rpdec");
|
||||
}
|
||||
|
||||
if(type == 1) {
|
||||
output << "\n ret";
|
||||
output.append("\n ret");
|
||||
}
|
||||
}
|
||||
|
||||
@@ -135,75 +118,75 @@ string NECDSP::disassemble(uint14 ip) {
|
||||
uint14 jp = (regs.pc & 0x2000) | (bank << 11) | (na << 0);
|
||||
|
||||
switch(brch) {
|
||||
case 0x000: output << "jmpso "; jp = 0; break;
|
||||
case 0x080: output << "jnca "; break;
|
||||
case 0x082: output << "jca "; break;
|
||||
case 0x084: output << "jncb "; break;
|
||||
case 0x086: output << "jcb "; break;
|
||||
case 0x088: output << "jnza "; break;
|
||||
case 0x08a: output << "jza "; break;
|
||||
case 0x08c: output << "jnzb "; break;
|
||||
case 0x08e: output << "jzb "; break;
|
||||
case 0x090: output << "jnova0 "; break;
|
||||
case 0x092: output << "jova0 "; break;
|
||||
case 0x094: output << "jnovb0 "; break;
|
||||
case 0x096: output << "jovb0 "; break;
|
||||
case 0x098: output << "jnova1 "; break;
|
||||
case 0x09a: output << "jova1 "; break;
|
||||
case 0x09c: output << "jnovb1 "; break;
|
||||
case 0x09e: output << "jovb1 "; break;
|
||||
case 0x0a0: output << "jnsa0 "; break;
|
||||
case 0x0a2: output << "jsa0 "; break;
|
||||
case 0x0a4: output << "jnsb0 "; break;
|
||||
case 0x0a6: output << "jsb0 "; break;
|
||||
case 0x0a8: output << "jnsa1 "; break;
|
||||
case 0x0aa: output << "jsa1 "; break;
|
||||
case 0x0ac: output << "jnsb1 "; break;
|
||||
case 0x0ae: output << "jsb1 "; break;
|
||||
case 0x0b0: output << "jdpl0 "; break;
|
||||
case 0x0b1: output << "jdpln0 "; break;
|
||||
case 0x0b2: output << "jdplf "; break;
|
||||
case 0x0b3: output << "jdplnf "; break;
|
||||
case 0x0b4: output << "jnsiak "; break;
|
||||
case 0x0b6: output << "jsiak "; break;
|
||||
case 0x0b8: output << "jnsoak "; break;
|
||||
case 0x0ba: output << "jsoak "; break;
|
||||
case 0x0bc: output << "jnrqm "; break;
|
||||
case 0x0be: output << "jrqm "; break;
|
||||
case 0x100: output << "ljmp "; jp &= ~0x2000; break;
|
||||
case 0x101: output << "hjmp "; jp |= 0x2000; break;
|
||||
case 0x140: output << "lcall "; jp &= ~0x2000; break;
|
||||
case 0x141: output << "hcall "; jp |= 0x2000; break;
|
||||
default: output << "?????? "; break;
|
||||
case 0x000: output.append("jmpso "); jp = 0; break;
|
||||
case 0x080: output.append("jnca "); break;
|
||||
case 0x082: output.append("jca "); break;
|
||||
case 0x084: output.append("jncb "); break;
|
||||
case 0x086: output.append("jcb "); break;
|
||||
case 0x088: output.append("jnza "); break;
|
||||
case 0x08a: output.append("jza "); break;
|
||||
case 0x08c: output.append("jnzb "); break;
|
||||
case 0x08e: output.append("jzb "); break;
|
||||
case 0x090: output.append("jnova0 "); break;
|
||||
case 0x092: output.append("jova0 "); break;
|
||||
case 0x094: output.append("jnovb0 "); break;
|
||||
case 0x096: output.append("jovb0 "); break;
|
||||
case 0x098: output.append("jnova1 "); break;
|
||||
case 0x09a: output.append("jova1 "); break;
|
||||
case 0x09c: output.append("jnovb1 "); break;
|
||||
case 0x09e: output.append("jovb1 "); break;
|
||||
case 0x0a0: output.append("jnsa0 "); break;
|
||||
case 0x0a2: output.append("jsa0 "); break;
|
||||
case 0x0a4: output.append("jnsb0 "); break;
|
||||
case 0x0a6: output.append("jsb0 "); break;
|
||||
case 0x0a8: output.append("jnsa1 "); break;
|
||||
case 0x0aa: output.append("jsa1 "); break;
|
||||
case 0x0ac: output.append("jnsb1 "); break;
|
||||
case 0x0ae: output.append("jsb1 "); break;
|
||||
case 0x0b0: output.append("jdpl0 "); break;
|
||||
case 0x0b1: output.append("jdpln0 "); break;
|
||||
case 0x0b2: output.append("jdplf "); break;
|
||||
case 0x0b3: output.append("jdplnf "); break;
|
||||
case 0x0b4: output.append("jnsiak "); break;
|
||||
case 0x0b6: output.append("jsiak "); break;
|
||||
case 0x0b8: output.append("jnsoak "); break;
|
||||
case 0x0ba: output.append("jsoak "); break;
|
||||
case 0x0bc: output.append("jnrqm "); break;
|
||||
case 0x0be: output.append("jrqm "); break;
|
||||
case 0x100: output.append("ljmp "); jp &= ~0x2000; break;
|
||||
case 0x101: output.append("hjmp "); jp |= 0x2000; break;
|
||||
case 0x140: output.append("lcall "); jp &= ~0x2000; break;
|
||||
case 0x141: output.append("hcall "); jp |= 0x2000; break;
|
||||
default: output.append("?????? "); break;
|
||||
}
|
||||
|
||||
output << "$" << hex<4>(jp);
|
||||
output.append("$", hex<4>(jp));
|
||||
}
|
||||
|
||||
if(type == 3) { //LD
|
||||
output << "ld ";
|
||||
output.append("ld ");
|
||||
uint16 id = opcode >> 6;
|
||||
uint4 dst = opcode >> 0;
|
||||
|
||||
output << "$" << hex<4>(id) << ",";
|
||||
output.append("$", hex<4>(id), ",");
|
||||
|
||||
switch(dst) {
|
||||
case 0: output << "non"; break;
|
||||
case 1: output << "a"; break;
|
||||
case 2: output << "b"; break;
|
||||
case 3: output << "tr"; break;
|
||||
case 4: output << "dp"; break;
|
||||
case 5: output << "rp"; break;
|
||||
case 6: output << "dr"; break;
|
||||
case 7: output << "sr"; break;
|
||||
case 8: output << "sol"; break;
|
||||
case 9: output << "som"; break;
|
||||
case 10: output << "k"; break;
|
||||
case 11: output << "klr"; break;
|
||||
case 12: output << "klm"; break;
|
||||
case 13: output << "l"; break;
|
||||
case 14: output << "trb"; break;
|
||||
case 15: output << "mem"; break;
|
||||
case 0: output.append("non"); break;
|
||||
case 1: output.append("a" ); break;
|
||||
case 2: output.append("b" ); break;
|
||||
case 3: output.append("tr" ); break;
|
||||
case 4: output.append("dp" ); break;
|
||||
case 5: output.append("rp" ); break;
|
||||
case 6: output.append("dr" ); break;
|
||||
case 7: output.append("sr" ); break;
|
||||
case 8: output.append("sol"); break;
|
||||
case 9: output.append("som"); break;
|
||||
case 10: output.append("k" ); break;
|
||||
case 11: output.append("klr"); break;
|
||||
case 12: output.append("klm"); break;
|
||||
case 13: output.append("l" ); break;
|
||||
case 14: output.append("trb"); break;
|
||||
case 15: output.append("mem"); break;
|
||||
}
|
||||
}
|
||||
|
||||
|
@@ -20,8 +20,6 @@ void OBC1::power() {
|
||||
}
|
||||
|
||||
void OBC1::reset() {
|
||||
for(unsigned i = 0x0000; i <= 0x1fff; i++) ram_write(i, 0xff);
|
||||
|
||||
status.baseptr = (ram_read(0x1ff5) & 1) ? 0x1800 : 0x1c00;
|
||||
status.address = (ram_read(0x1ff6) & 0x7f);
|
||||
status.shift = (ram_read(0x1ff6) & 3) << 1;
|
||||
|
287
bsnes/snes/chip/sdd1/decomp.cpp
Executable file
287
bsnes/snes/chip/sdd1/decomp.cpp
Executable file
@@ -0,0 +1,287 @@
|
||||
//S-DD1 decompression algorithm implementation
|
||||
//original code written by Andreas Naive (public domain license)
|
||||
//bsnes port written by byuu
|
||||
|
||||
//note: decompression module does not need to be serialized with bsnes
|
||||
//this is because decompression only runs during DMA, and bsnes will complete
|
||||
//any pending DMA transfers prior to serialization.
|
||||
|
||||
//input manager
|
||||
|
||||
void SDD1::Decomp::IM::init(unsigned offset_) {
|
||||
offset = offset_;
|
||||
bit_count = 4;
|
||||
}
|
||||
|
||||
uint8 SDD1::Decomp::IM::get_codeword(uint8 code_length) {
|
||||
uint8 codeword;
|
||||
uint8 comp_count;
|
||||
|
||||
codeword = self.rom_read(offset) << bit_count;
|
||||
bit_count++;
|
||||
|
||||
if(codeword & 0x80) {
|
||||
codeword |= self.rom_read(offset + 1) >> (9 - bit_count);
|
||||
bit_count += code_length;
|
||||
}
|
||||
|
||||
if(bit_count & 0x08) {
|
||||
offset++;
|
||||
bit_count &= 0x07;
|
||||
}
|
||||
|
||||
return codeword;
|
||||
}
|
||||
|
||||
//golomb-code decoder
|
||||
|
||||
const uint8 SDD1::Decomp::GCD::run_count[] = {
|
||||
0x00, 0x00, 0x01, 0x00, 0x03, 0x01, 0x02, 0x00,
|
||||
0x07, 0x03, 0x05, 0x01, 0x06, 0x02, 0x04, 0x00,
|
||||
0x0f, 0x07, 0x0b, 0x03, 0x0d, 0x05, 0x09, 0x01,
|
||||
0x0e, 0x06, 0x0a, 0x02, 0x0c, 0x04, 0x08, 0x00,
|
||||
0x1f, 0x0f, 0x17, 0x07, 0x1b, 0x0b, 0x13, 0x03,
|
||||
0x1d, 0x0d, 0x15, 0x05, 0x19, 0x09, 0x11, 0x01,
|
||||
0x1e, 0x0e, 0x16, 0x06, 0x1a, 0x0a, 0x12, 0x02,
|
||||
0x1c, 0x0c, 0x14, 0x04, 0x18, 0x08, 0x10, 0x00,
|
||||
0x3f, 0x1f, 0x2f, 0x0f, 0x37, 0x17, 0x27, 0x07,
|
||||
0x3b, 0x1b, 0x2b, 0x0b, 0x33, 0x13, 0x23, 0x03,
|
||||
0x3d, 0x1d, 0x2d, 0x0d, 0x35, 0x15, 0x25, 0x05,
|
||||
0x39, 0x19, 0x29, 0x09, 0x31, 0x11, 0x21, 0x01,
|
||||
0x3e, 0x1e, 0x2e, 0x0e, 0x36, 0x16, 0x26, 0x06,
|
||||
0x3a, 0x1a, 0x2a, 0x0a, 0x32, 0x12, 0x22, 0x02,
|
||||
0x3c, 0x1c, 0x2c, 0x0c, 0x34, 0x14, 0x24, 0x04,
|
||||
0x38, 0x18, 0x28, 0x08, 0x30, 0x10, 0x20, 0x00,
|
||||
0x7f, 0x3f, 0x5f, 0x1f, 0x6f, 0x2f, 0x4f, 0x0f,
|
||||
0x77, 0x37, 0x57, 0x17, 0x67, 0x27, 0x47, 0x07,
|
||||
0x7b, 0x3b, 0x5b, 0x1b, 0x6b, 0x2b, 0x4b, 0x0b,
|
||||
0x73, 0x33, 0x53, 0x13, 0x63, 0x23, 0x43, 0x03,
|
||||
0x7d, 0x3d, 0x5d, 0x1d, 0x6d, 0x2d, 0x4d, 0x0d,
|
||||
0x75, 0x35, 0x55, 0x15, 0x65, 0x25, 0x45, 0x05,
|
||||
0x79, 0x39, 0x59, 0x19, 0x69, 0x29, 0x49, 0x09,
|
||||
0x71, 0x31, 0x51, 0x11, 0x61, 0x21, 0x41, 0x01,
|
||||
0x7e, 0x3e, 0x5e, 0x1e, 0x6e, 0x2e, 0x4e, 0x0e,
|
||||
0x76, 0x36, 0x56, 0x16, 0x66, 0x26, 0x46, 0x06,
|
||||
0x7a, 0x3a, 0x5a, 0x1a, 0x6a, 0x2a, 0x4a, 0x0a,
|
||||
0x72, 0x32, 0x52, 0x12, 0x62, 0x22, 0x42, 0x02,
|
||||
0x7c, 0x3c, 0x5c, 0x1c, 0x6c, 0x2c, 0x4c, 0x0c,
|
||||
0x74, 0x34, 0x54, 0x14, 0x64, 0x24, 0x44, 0x04,
|
||||
0x78, 0x38, 0x58, 0x18, 0x68, 0x28, 0x48, 0x08,
|
||||
0x70, 0x30, 0x50, 0x10, 0x60, 0x20, 0x40, 0x00,
|
||||
};
|
||||
|
||||
void SDD1::Decomp::GCD::get_run_count(uint8 code_number, uint8 &mps_count, bool &lps_index) {
|
||||
uint8 codeword = self.im.get_codeword(code_number);
|
||||
|
||||
if(codeword & 0x80) {
|
||||
lps_index = 1;
|
||||
mps_count = run_count[codeword >> (code_number ^ 0x07)];
|
||||
} else {
|
||||
mps_count = 1 << code_number;
|
||||
}
|
||||
}
|
||||
|
||||
//bits generator
|
||||
|
||||
void SDD1::Decomp::BG::init() {
|
||||
mps_count = 0;
|
||||
lps_index = 0;
|
||||
}
|
||||
|
||||
uint8 SDD1::Decomp::BG::get_bit(bool &end_of_run) {
|
||||
if(!(mps_count || lps_index)) self.gcd.get_run_count(code_number, mps_count, lps_index);
|
||||
|
||||
uint8 bit;
|
||||
if(mps_count) {
|
||||
bit = 0;
|
||||
mps_count--;
|
||||
} else {
|
||||
bit = 1;
|
||||
lps_index = 0;
|
||||
}
|
||||
|
||||
end_of_run = !(mps_count || lps_index);
|
||||
return bit;
|
||||
}
|
||||
|
||||
//probability estimation module
|
||||
|
||||
const SDD1::Decomp::PEM::State SDD1::Decomp::PEM::evolution_table[33] = {
|
||||
{ 0, 25, 25 },
|
||||
{ 0, 2, 1 },
|
||||
{ 0, 3, 1 },
|
||||
{ 0, 4, 2 },
|
||||
{ 0, 5, 3 },
|
||||
{ 1, 6, 4 },
|
||||
{ 1, 7, 5 },
|
||||
{ 1, 8, 6 },
|
||||
{ 1, 9, 7 },
|
||||
{ 2, 10, 8 },
|
||||
{ 2, 11, 9 },
|
||||
{ 2, 12, 10 },
|
||||
{ 2, 13, 11 },
|
||||
{ 3, 14, 12 },
|
||||
{ 3, 15, 13 },
|
||||
{ 3, 16, 14 },
|
||||
{ 3, 17, 15 },
|
||||
{ 4, 18, 16 },
|
||||
{ 4, 19, 17 },
|
||||
{ 5, 20, 18 },
|
||||
{ 5, 21, 19 },
|
||||
{ 6, 22, 20 },
|
||||
{ 6, 23, 21 },
|
||||
{ 7, 24, 22 },
|
||||
{ 7, 24, 23 },
|
||||
{ 0, 26, 1 },
|
||||
{ 1, 27, 2 },
|
||||
{ 2, 28, 4 },
|
||||
{ 3, 29, 8 },
|
||||
{ 4, 30, 12 },
|
||||
{ 5, 31, 16 },
|
||||
{ 6, 32, 18 },
|
||||
{ 7, 24, 22 },
|
||||
};
|
||||
|
||||
void SDD1::Decomp::PEM::init() {
|
||||
for(unsigned i = 0; i < 32; i++) {
|
||||
context_info[i].status = 0;
|
||||
context_info[i].mps = 0;
|
||||
}
|
||||
}
|
||||
|
||||
uint8 SDD1::Decomp::PEM::get_bit(uint8 context) {
|
||||
ContextInfo &info = context_info[context];
|
||||
uint8 current_status = info.status;
|
||||
uint8 current_mps = info.mps;
|
||||
const State &s = SDD1::Decomp::PEM::evolution_table[current_status];
|
||||
|
||||
uint8 bit;
|
||||
bool end_of_run;
|
||||
switch(s.code_number) {
|
||||
case 0: bit = self.bg0.get_bit(end_of_run); break;
|
||||
case 1: bit = self.bg1.get_bit(end_of_run); break;
|
||||
case 2: bit = self.bg2.get_bit(end_of_run); break;
|
||||
case 3: bit = self.bg3.get_bit(end_of_run); break;
|
||||
case 4: bit = self.bg4.get_bit(end_of_run); break;
|
||||
case 5: bit = self.bg5.get_bit(end_of_run); break;
|
||||
case 6: bit = self.bg6.get_bit(end_of_run); break;
|
||||
case 7: bit = self.bg7.get_bit(end_of_run); break;
|
||||
}
|
||||
|
||||
if(end_of_run) {
|
||||
if(bit) {
|
||||
if(!(current_status & 0xfe)) info.mps ^= 0x01;
|
||||
info.status = s.next_if_lps;
|
||||
} else {
|
||||
info.status = s.next_if_mps;
|
||||
}
|
||||
}
|
||||
|
||||
return bit ^ current_mps;
|
||||
}
|
||||
|
||||
//context model
|
||||
|
||||
void SDD1::Decomp::CM::init(unsigned offset) {
|
||||
bitplanes_info = self.rom_read(offset) & 0xc0;
|
||||
context_bits_info = self.rom_read(offset) & 0x30;
|
||||
bit_number = 0;
|
||||
for(unsigned i = 0; i < 8; i++) previous_bitplane_bits[i] = 0;
|
||||
switch(bitplanes_info) {
|
||||
case 0x00: current_bitplane = 1; break;
|
||||
case 0x40: current_bitplane = 7; break;
|
||||
case 0x80: current_bitplane = 3; break;
|
||||
}
|
||||
}
|
||||
|
||||
uint8 SDD1::Decomp::CM::get_bit() {
|
||||
switch(bitplanes_info) {
|
||||
case 0x00:
|
||||
current_bitplane ^= 0x01;
|
||||
break;
|
||||
case 0x40:
|
||||
current_bitplane ^= 0x01;
|
||||
if(!(bit_number & 0x7f)) current_bitplane = ((current_bitplane + 2) & 0x07);
|
||||
break;
|
||||
case 0x80:
|
||||
current_bitplane ^= 0x01;
|
||||
if(!(bit_number & 0x7f)) current_bitplane ^= 0x02;
|
||||
break;
|
||||
case 0xc0:
|
||||
current_bitplane = bit_number & 0x07;
|
||||
break;
|
||||
}
|
||||
|
||||
uint16 &context_bits = previous_bitplane_bits[current_bitplane];
|
||||
uint8 current_context = (current_bitplane & 0x01) << 4;
|
||||
switch(context_bits_info) {
|
||||
case 0x00: current_context |= ((context_bits & 0x01c0) >> 5) | (context_bits & 0x0001); break;
|
||||
case 0x10: current_context |= ((context_bits & 0x0180) >> 5) | (context_bits & 0x0001); break;
|
||||
case 0x20: current_context |= ((context_bits & 0x00c0) >> 5) | (context_bits & 0x0001); break;
|
||||
case 0x30: current_context |= ((context_bits & 0x0180) >> 5) | (context_bits & 0x0003); break;
|
||||
}
|
||||
|
||||
uint8 bit = self.pem.get_bit(current_context);
|
||||
context_bits <<= 1;
|
||||
context_bits |= bit;
|
||||
bit_number++;
|
||||
return bit;
|
||||
}
|
||||
|
||||
//output logic
|
||||
|
||||
void SDD1::Decomp::OL::init(unsigned offset) {
|
||||
bitplanes_info = self.rom_read(offset) & 0xc0;
|
||||
r0 = 0x01;
|
||||
}
|
||||
|
||||
uint8 SDD1::Decomp::OL::decompress() {
|
||||
switch(bitplanes_info) {
|
||||
case 0x00: case 0x40: case 0x80:
|
||||
if(r0 == 0) {
|
||||
r0 = ~r0;
|
||||
return r2;
|
||||
}
|
||||
for(r0 = 0x80, r1 = 0, r2 = 0; r0; r0 >>= 1) {
|
||||
if(self.cm.get_bit()) r1 |= r0;
|
||||
if(self.cm.get_bit()) r2 |= r0;
|
||||
}
|
||||
return r1;
|
||||
case 0xc0:
|
||||
for(r0 = 0x01, r1 = 0; r0; r0 <<= 1) {
|
||||
if(self.cm.get_bit()) r1 |= r0;
|
||||
}
|
||||
return r1;
|
||||
}
|
||||
}
|
||||
|
||||
//core
|
||||
|
||||
void SDD1::Decomp::init(unsigned offset) {
|
||||
im.init(offset);
|
||||
bg0.init();
|
||||
bg1.init();
|
||||
bg2.init();
|
||||
bg3.init();
|
||||
bg4.init();
|
||||
bg5.init();
|
||||
bg6.init();
|
||||
bg7.init();
|
||||
pem.init();
|
||||
cm.init(offset);
|
||||
ol.init(offset);
|
||||
}
|
||||
|
||||
uint8 SDD1::Decomp::read() {
|
||||
return ol.decompress();
|
||||
}
|
||||
|
||||
uint8 SDD1::Decomp::rom_read(unsigned offset) {
|
||||
return sdd1.rom_read(offset);
|
||||
}
|
||||
|
||||
SDD1::Decomp::Decomp() : im(*this), gcd(*this),
|
||||
bg0(*this, 0), bg1(*this, 1), bg2(*this, 2), bg3(*this, 3),
|
||||
bg4(*this, 4), bg5(*this, 5), bg6(*this, 6), bg7(*this, 7),
|
||||
pem(*this), cm(*this), ol(*this) {
|
||||
}
|
82
bsnes/snes/chip/sdd1/decomp.hpp
Executable file
82
bsnes/snes/chip/sdd1/decomp.hpp
Executable file
@@ -0,0 +1,82 @@
|
||||
struct Decomp {
|
||||
struct IM { //input manager
|
||||
Decomp &self;
|
||||
void init(unsigned offset);
|
||||
uint8 get_codeword(uint8 code_length);
|
||||
IM(SDD1::Decomp &self) : self(self) {}
|
||||
private:
|
||||
unsigned offset;
|
||||
unsigned bit_count;
|
||||
};
|
||||
|
||||
struct GCD { //golomb-code decoder
|
||||
Decomp &self;
|
||||
static const uint8 run_count[256];
|
||||
void get_run_count(uint8 code_number, uint8 &mps_count, bool &lps_index);
|
||||
GCD(SDD1::Decomp &self) : self(self) {}
|
||||
};
|
||||
|
||||
struct BG { //bits generator
|
||||
Decomp &self;
|
||||
void init();
|
||||
uint8 get_bit(bool &end_of_run);
|
||||
BG(SDD1::Decomp &self, uint8 code_number) : self(self), code_number(code_number) {}
|
||||
private:
|
||||
const uint8 code_number;
|
||||
uint8 mps_count;
|
||||
bool lps_index;
|
||||
};
|
||||
|
||||
struct PEM { //probability estimation module
|
||||
Decomp &self;
|
||||
void init();
|
||||
uint8 get_bit(uint8 context);
|
||||
PEM(SDD1::Decomp &self) : self(self) {}
|
||||
private:
|
||||
struct State {
|
||||
uint8 code_number;
|
||||
uint8 next_if_mps;
|
||||
uint8 next_if_lps;
|
||||
};
|
||||
static const State evolution_table[33];
|
||||
struct ContextInfo {
|
||||
uint8 status;
|
||||
uint8 mps;
|
||||
} context_info[32];
|
||||
};
|
||||
|
||||
struct CM { //context model
|
||||
Decomp &self;
|
||||
void init(unsigned offset);
|
||||
uint8 get_bit();
|
||||
CM(SDD1::Decomp &self) : self(self) {}
|
||||
private:
|
||||
uint8 bitplanes_info;
|
||||
uint8 context_bits_info;
|
||||
uint8 bit_number;
|
||||
uint8 current_bitplane;
|
||||
uint16 previous_bitplane_bits[8];
|
||||
};
|
||||
|
||||
struct OL { //output logic
|
||||
Decomp &self;
|
||||
void init(unsigned offset);
|
||||
uint8 decompress();
|
||||
OL(SDD1::Decomp &self) : self(self) {}
|
||||
private:
|
||||
uint8 bitplanes_info;
|
||||
uint8 r0, r1, r2;
|
||||
};
|
||||
|
||||
void init(unsigned offset);
|
||||
uint8 read();
|
||||
uint8 rom_read(unsigned offset);
|
||||
Decomp();
|
||||
|
||||
IM im;
|
||||
GCD gcd;
|
||||
BG bg0, bg1, bg2, bg3, bg4, bg5, bg6, bg7;
|
||||
PEM pem;
|
||||
CM cm;
|
||||
OL ol;
|
||||
};
|
@@ -5,8 +5,8 @@ namespace SNES {
|
||||
|
||||
SDD1 sdd1;
|
||||
|
||||
#include "decomp.cpp"
|
||||
#include "serialization.cpp"
|
||||
#include "sdd1emu.cpp"
|
||||
|
||||
void SDD1::init() {
|
||||
}
|
||||
@@ -28,6 +28,7 @@ void SDD1::power() {
|
||||
void SDD1::reset() {
|
||||
sdd1_enable = 0x00;
|
||||
xfer_enable = 0x00;
|
||||
dma_ready = false;
|
||||
|
||||
mmc[0] = 0 << 20;
|
||||
mmc[1] = 1 << 20;
|
||||
@@ -38,8 +39,6 @@ void SDD1::reset() {
|
||||
dma[i].addr = 0;
|
||||
dma[i].size = 0;
|
||||
}
|
||||
|
||||
buffer.ready = false;
|
||||
}
|
||||
|
||||
uint8 SDD1::mmio_read(unsigned addr) {
|
||||
@@ -86,6 +85,10 @@ void SDD1::mmio_write(unsigned addr, uint8 data) {
|
||||
}
|
||||
}
|
||||
|
||||
uint8 SDD1::rom_read(unsigned addr) {
|
||||
return cartridge.rom.read(mmc[(addr >> 20) & 3] + (addr & 0x0fffff));
|
||||
}
|
||||
|
||||
//SDD1::mcu_read() is mapped to $c0-ff:0000-ffff
|
||||
//the design is meant to be as close to the hardware design as possible, thus this code
|
||||
//avoids adding S-DD1 hooks inside S-CPU::DMA emulation.
|
||||
@@ -111,26 +114,16 @@ uint8 SDD1::mcu_read(unsigned addr) {
|
||||
if(sdd1_enable & xfer_enable & (1 << i)) {
|
||||
//S-DD1 always uses fixed transfer mode, so address will not change during transfer
|
||||
if(addr == dma[i].addr) {
|
||||
if(!buffer.ready) {
|
||||
//first byte read for channel performs full decompression.
|
||||
//this really should stream byte-by-byte, but it's not necessary since the size is known
|
||||
buffer.offset = 0;
|
||||
buffer.size = dma[i].size ? dma[i].size : 65536;
|
||||
|
||||
//sdd1emu calls this function; it needs to access uncompressed data;
|
||||
//so temporarily disable decompression mode for decompress() call.
|
||||
uint8 temp = sdd1_enable;
|
||||
sdd1_enable = false;
|
||||
sdd1emu.decompress(addr, buffer.size, buffer.data);
|
||||
sdd1_enable = temp;
|
||||
|
||||
buffer.ready = true;
|
||||
if(!dma_ready) {
|
||||
//prepare streaming decompression
|
||||
decomp.init(addr);
|
||||
dma_ready = true;
|
||||
}
|
||||
|
||||
//fetch a decompressed byte; once buffer is depleted, disable channel and invalidate buffer
|
||||
uint8 data = buffer.data[(uint16)buffer.offset++];
|
||||
if(buffer.offset >= buffer.size) {
|
||||
buffer.ready = false;
|
||||
//fetch a decompressed byte; once finished, disable channel and invalidate buffer
|
||||
uint8 data = decomp.read();
|
||||
if(--dma[i].size == 0) {
|
||||
dma_ready = false;
|
||||
xfer_enable &= ~(1 << i);
|
||||
}
|
||||
|
||||
|
@@ -1,5 +1,3 @@
|
||||
#include "sdd1emu.hpp"
|
||||
|
||||
class SDD1 {
|
||||
public:
|
||||
void init();
|
||||
@@ -11,6 +9,7 @@ public:
|
||||
uint8 mmio_read(unsigned addr);
|
||||
void mmio_write(unsigned addr, uint8 data);
|
||||
|
||||
uint8 rom_read(unsigned addr);
|
||||
uint8 mcu_read(unsigned addr);
|
||||
void mcu_write(unsigned addr, uint8 data);
|
||||
|
||||
@@ -19,22 +18,19 @@ public:
|
||||
~SDD1();
|
||||
|
||||
private:
|
||||
uint8 sdd1_enable; //channel bit-mask
|
||||
uint8 xfer_enable; //channel bit-mask
|
||||
unsigned mmc[4]; //memory map controller ROM indices
|
||||
uint8 sdd1_enable; //channel bit-mask
|
||||
uint8 xfer_enable; //channel bit-mask
|
||||
bool dma_ready; //used to initialize decompression module
|
||||
unsigned mmc[4]; //memory map controller ROM indices
|
||||
|
||||
struct {
|
||||
unsigned addr; //$43x2-$43x4 -- DMA transfer address
|
||||
uint16 size; //$43x5-$43x6 -- DMA transfer size
|
||||
unsigned addr; //$43x2-$43x4 -- DMA transfer address
|
||||
uint16 size; //$43x5-$43x6 -- DMA transfer size
|
||||
} dma[8];
|
||||
|
||||
SDD1emu sdd1emu;
|
||||
struct {
|
||||
uint8 data[65536]; //pointer to decompressed S-DD1 data
|
||||
uint16 offset; //read index into S-DD1 decompression buffer
|
||||
unsigned size; //length of data buffer; reads decrement counter, set ready to false at 0
|
||||
bool ready; //true when data[] is valid; false to invoke sdd1emu.decompress()
|
||||
} buffer;
|
||||
public:
|
||||
#include "decomp.hpp"
|
||||
Decomp decomp;
|
||||
};
|
||||
|
||||
extern SDD1 sdd1;
|
||||
|
@@ -1,452 +0,0 @@
|
||||
#ifdef SDD1_CPP
|
||||
|
||||
/************************************************************************
|
||||
|
||||
S-DD1'algorithm emulation code
|
||||
------------------------------
|
||||
|
||||
Author: Andreas Naive
|
||||
Date: August 2003
|
||||
Last update: October 2004
|
||||
|
||||
This code is Public Domain. There is no copyright holded by the author.
|
||||
Said this, the author wish to explicitly emphasize his inalienable moral rights
|
||||
over this piece of intelectual work and the previous research that made it
|
||||
possible, as recognized by most of the copyright laws around the world.
|
||||
|
||||
This code is provided 'as-is', with no warranty, expressed or implied.
|
||||
No responsability is assumed by the author in connection with it.
|
||||
|
||||
The author is greatly indebted with The Dumper, without whose help and
|
||||
patience providing him with real S-DD1 data the research would have never been
|
||||
possible. He also wish to note that in the very beggining of his research,
|
||||
Neviksti had done some steps in the right direction. By last, the author is
|
||||
indirectly indebted to all the people that worked and contributed in the
|
||||
S-DD1 issue in the past.
|
||||
|
||||
An algorithm's documentation is available as a separate document.
|
||||
The implementation is obvious when the algorithm is
|
||||
understood.
|
||||
|
||||
************************************************************************/
|
||||
|
||||
typedef uint8 bool8;
|
||||
#define SDD1_read(__addr) (sdd1.mcu_read(__addr))
|
||||
|
||||
////////////////////////////////////////////////////
|
||||
|
||||
|
||||
void SDD1_IM::prepareDecomp(uint32 in_buf) {
|
||||
|
||||
byte_ptr=in_buf;
|
||||
bit_count=4;
|
||||
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////
|
||||
|
||||
|
||||
uint8 SDD1_IM::getCodeword(uint8 code_len) {
|
||||
|
||||
uint8 codeword;
|
||||
uint8 comp_count;
|
||||
|
||||
codeword = (SDD1_read(byte_ptr))<<bit_count;
|
||||
|
||||
++bit_count;
|
||||
|
||||
if (codeword & 0x80) {
|
||||
codeword |= SDD1_read(byte_ptr+1)>>(9-bit_count);
|
||||
bit_count+=code_len;
|
||||
}
|
||||
|
||||
if (bit_count & 0x08) {
|
||||
byte_ptr++;
|
||||
bit_count&=0x07;
|
||||
}
|
||||
|
||||
return codeword;
|
||||
|
||||
}
|
||||
|
||||
//////////////////////////////////////////////////////
|
||||
|
||||
|
||||
SDD1_GCD::SDD1_GCD(SDD1_IM *associatedIM) :
|
||||
IM(associatedIM)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
//////////////////////////////////////////////////////
|
||||
|
||||
|
||||
void SDD1_GCD::getRunCount(uint8 code_num, uint8 *MPScount, bool8 *LPSind) {
|
||||
|
||||
const uint8 run_count[] = {
|
||||
0x00, 0x00, 0x01, 0x00, 0x03, 0x01, 0x02, 0x00,
|
||||
0x07, 0x03, 0x05, 0x01, 0x06, 0x02, 0x04, 0x00,
|
||||
0x0f, 0x07, 0x0b, 0x03, 0x0d, 0x05, 0x09, 0x01,
|
||||
0x0e, 0x06, 0x0a, 0x02, 0x0c, 0x04, 0x08, 0x00,
|
||||
0x1f, 0x0f, 0x17, 0x07, 0x1b, 0x0b, 0x13, 0x03,
|
||||
0x1d, 0x0d, 0x15, 0x05, 0x19, 0x09, 0x11, 0x01,
|
||||
0x1e, 0x0e, 0x16, 0x06, 0x1a, 0x0a, 0x12, 0x02,
|
||||
0x1c, 0x0c, 0x14, 0x04, 0x18, 0x08, 0x10, 0x00,
|
||||
0x3f, 0x1f, 0x2f, 0x0f, 0x37, 0x17, 0x27, 0x07,
|
||||
0x3b, 0x1b, 0x2b, 0x0b, 0x33, 0x13, 0x23, 0x03,
|
||||
0x3d, 0x1d, 0x2d, 0x0d, 0x35, 0x15, 0x25, 0x05,
|
||||
0x39, 0x19, 0x29, 0x09, 0x31, 0x11, 0x21, 0x01,
|
||||
0x3e, 0x1e, 0x2e, 0x0e, 0x36, 0x16, 0x26, 0x06,
|
||||
0x3a, 0x1a, 0x2a, 0x0a, 0x32, 0x12, 0x22, 0x02,
|
||||
0x3c, 0x1c, 0x2c, 0x0c, 0x34, 0x14, 0x24, 0x04,
|
||||
0x38, 0x18, 0x28, 0x08, 0x30, 0x10, 0x20, 0x00,
|
||||
0x7f, 0x3f, 0x5f, 0x1f, 0x6f, 0x2f, 0x4f, 0x0f,
|
||||
0x77, 0x37, 0x57, 0x17, 0x67, 0x27, 0x47, 0x07,
|
||||
0x7b, 0x3b, 0x5b, 0x1b, 0x6b, 0x2b, 0x4b, 0x0b,
|
||||
0x73, 0x33, 0x53, 0x13, 0x63, 0x23, 0x43, 0x03,
|
||||
0x7d, 0x3d, 0x5d, 0x1d, 0x6d, 0x2d, 0x4d, 0x0d,
|
||||
0x75, 0x35, 0x55, 0x15, 0x65, 0x25, 0x45, 0x05,
|
||||
0x79, 0x39, 0x59, 0x19, 0x69, 0x29, 0x49, 0x09,
|
||||
0x71, 0x31, 0x51, 0x11, 0x61, 0x21, 0x41, 0x01,
|
||||
0x7e, 0x3e, 0x5e, 0x1e, 0x6e, 0x2e, 0x4e, 0x0e,
|
||||
0x76, 0x36, 0x56, 0x16, 0x66, 0x26, 0x46, 0x06,
|
||||
0x7a, 0x3a, 0x5a, 0x1a, 0x6a, 0x2a, 0x4a, 0x0a,
|
||||
0x72, 0x32, 0x52, 0x12, 0x62, 0x22, 0x42, 0x02,
|
||||
0x7c, 0x3c, 0x5c, 0x1c, 0x6c, 0x2c, 0x4c, 0x0c,
|
||||
0x74, 0x34, 0x54, 0x14, 0x64, 0x24, 0x44, 0x04,
|
||||
0x78, 0x38, 0x58, 0x18, 0x68, 0x28, 0x48, 0x08,
|
||||
0x70, 0x30, 0x50, 0x10, 0x60, 0x20, 0x40, 0x00,
|
||||
};
|
||||
|
||||
uint8 codeword=IM->getCodeword(code_num);
|
||||
|
||||
if (codeword & 0x80) {
|
||||
*LPSind=1;
|
||||
*MPScount=run_count[codeword>>(code_num^0x07)];
|
||||
}
|
||||
else {
|
||||
*MPScount=(1<<code_num);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
///////////////////////////////////////////////////////
|
||||
|
||||
SDD1_BG::SDD1_BG(SDD1_GCD *associatedGCD, uint8 code) :
|
||||
GCD(associatedGCD), code_num(code)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
///////////////////////////////////////////////
|
||||
|
||||
|
||||
void SDD1_BG::prepareDecomp(void) {
|
||||
|
||||
MPScount=0;
|
||||
LPSind=0;
|
||||
|
||||
}
|
||||
|
||||
//////////////////////////////////////////////
|
||||
|
||||
|
||||
uint8 SDD1_BG::getBit(bool8 *endOfRun) {
|
||||
|
||||
uint8 bit;
|
||||
|
||||
if (!(MPScount || LPSind)) GCD->getRunCount(code_num, &MPScount, &LPSind);
|
||||
|
||||
if (MPScount) {
|
||||
bit=0;
|
||||
MPScount--;
|
||||
}
|
||||
else {
|
||||
bit=1;
|
||||
LPSind=0;
|
||||
}
|
||||
|
||||
if (MPScount || LPSind) (*endOfRun)=0;
|
||||
else (*endOfRun)=1;
|
||||
|
||||
return bit;
|
||||
|
||||
}
|
||||
|
||||
/////////////////////////////////////////////////
|
||||
|
||||
|
||||
SDD1_PEM::SDD1_PEM(SDD1_BG *associatedBG0, SDD1_BG *associatedBG1,
|
||||
SDD1_BG *associatedBG2, SDD1_BG *associatedBG3,
|
||||
SDD1_BG *associatedBG4, SDD1_BG *associatedBG5,
|
||||
SDD1_BG *associatedBG6, SDD1_BG *associatedBG7) {
|
||||
|
||||
BG[0]=associatedBG0;
|
||||
BG[1]=associatedBG1;
|
||||
BG[2]=associatedBG2;
|
||||
BG[3]=associatedBG3;
|
||||
BG[4]=associatedBG4;
|
||||
BG[5]=associatedBG5;
|
||||
BG[6]=associatedBG6;
|
||||
BG[7]=associatedBG7;
|
||||
|
||||
}
|
||||
|
||||
/////////////////////////////////////////////////////////
|
||||
|
||||
|
||||
const SDD1_PEM::state SDD1_PEM::evolution_table[]={
|
||||
{ 0,25,25},
|
||||
{ 0, 2, 1},
|
||||
{ 0, 3, 1},
|
||||
{ 0, 4, 2},
|
||||
{ 0, 5, 3},
|
||||
{ 1, 6, 4},
|
||||
{ 1, 7, 5},
|
||||
{ 1, 8, 6},
|
||||
{ 1, 9, 7},
|
||||
{ 2,10, 8},
|
||||
{ 2,11, 9},
|
||||
{ 2,12,10},
|
||||
{ 2,13,11},
|
||||
{ 3,14,12},
|
||||
{ 3,15,13},
|
||||
{ 3,16,14},
|
||||
{ 3,17,15},
|
||||
{ 4,18,16},
|
||||
{ 4,19,17},
|
||||
{ 5,20,18},
|
||||
{ 5,21,19},
|
||||
{ 6,22,20},
|
||||
{ 6,23,21},
|
||||
{ 7,24,22},
|
||||
{ 7,24,23},
|
||||
{ 0,26, 1},
|
||||
{ 1,27, 2},
|
||||
{ 2,28, 4},
|
||||
{ 3,29, 8},
|
||||
{ 4,30,12},
|
||||
{ 5,31,16},
|
||||
{ 6,32,18},
|
||||
{ 7,24,22}
|
||||
};
|
||||
|
||||
//////////////////////////////////////////////////////
|
||||
|
||||
|
||||
void SDD1_PEM::prepareDecomp(void) {
|
||||
|
||||
for (uint8 i=0; i<32; i++) {
|
||||
contextInfo[i].status=0;
|
||||
contextInfo[i].MPS=0;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/////////////////////////////////////////////////////////
|
||||
|
||||
|
||||
uint8 SDD1_PEM::getBit(uint8 context) {
|
||||
|
||||
bool8 endOfRun;
|
||||
uint8 bit;
|
||||
|
||||
SDD1_ContextInfo *pContInfo=&contextInfo[context];
|
||||
uint8 currStatus = pContInfo->status;
|
||||
const state *pState=&SDD1_PEM::evolution_table[currStatus];
|
||||
uint8 currentMPS=pContInfo->MPS;
|
||||
|
||||
bit=(BG[pState->code_num])->getBit(&endOfRun);
|
||||
|
||||
if (endOfRun)
|
||||
if (bit) {
|
||||
if (!(currStatus & 0xfe)) (pContInfo->MPS)^=0x01;
|
||||
(pContInfo->status)=pState->nextIfLPS;
|
||||
}
|
||||
else
|
||||
(pContInfo->status)=pState->nextIfMPS;
|
||||
|
||||
return bit^currentMPS;
|
||||
|
||||
}
|
||||
|
||||
//////////////////////////////////////////////////////////////
|
||||
|
||||
|
||||
SDD1_CM::SDD1_CM(SDD1_PEM *associatedPEM) :
|
||||
PEM(associatedPEM)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
//////////////////////////////////////////////////////////////
|
||||
|
||||
|
||||
void SDD1_CM::prepareDecomp(uint32 first_byte) {
|
||||
|
||||
bitplanesInfo = SDD1_read(first_byte) & 0xc0;
|
||||
contextBitsInfo = SDD1_read(first_byte) & 0x30;
|
||||
bit_number=0;
|
||||
for (int i=0; i<8; i++) prevBitplaneBits[i]=0;
|
||||
switch (bitplanesInfo) {
|
||||
case 0x00:
|
||||
currBitplane = 1;
|
||||
break;
|
||||
case 0x40:
|
||||
currBitplane = 7;
|
||||
break;
|
||||
case 0x80:
|
||||
currBitplane = 3;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/////////////////////////////////////////////////////////////
|
||||
|
||||
|
||||
uint8 SDD1_CM::getBit(void) {
|
||||
|
||||
uint8 currContext;
|
||||
uint16 *context_bits;
|
||||
|
||||
switch (bitplanesInfo) {
|
||||
case 0x00:
|
||||
currBitplane ^= 0x01;
|
||||
break;
|
||||
case 0x40:
|
||||
currBitplane ^= 0x01;
|
||||
if (!(bit_number & 0x7f)) currBitplane = ((currBitplane+2) & 0x07);
|
||||
break;
|
||||
case 0x80:
|
||||
currBitplane ^= 0x01;
|
||||
if (!(bit_number & 0x7f)) currBitplane ^= 0x02;
|
||||
break;
|
||||
case 0xc0:
|
||||
currBitplane = bit_number & 0x07;
|
||||
}
|
||||
|
||||
context_bits = &prevBitplaneBits[currBitplane];
|
||||
|
||||
currContext=(currBitplane & 0x01)<<4;
|
||||
switch (contextBitsInfo) {
|
||||
case 0x00:
|
||||
currContext|=((*context_bits & 0x01c0)>>5)|(*context_bits & 0x0001);
|
||||
break;
|
||||
case 0x10:
|
||||
currContext|=((*context_bits & 0x0180)>>5)|(*context_bits & 0x0001);
|
||||
break;
|
||||
case 0x20:
|
||||
currContext|=((*context_bits & 0x00c0)>>5)|(*context_bits & 0x0001);
|
||||
break;
|
||||
case 0x30:
|
||||
currContext|=((*context_bits & 0x0180)>>5)|(*context_bits & 0x0003);
|
||||
}
|
||||
|
||||
uint8 bit=PEM->getBit(currContext);
|
||||
|
||||
*context_bits <<= 1;
|
||||
*context_bits |= bit;
|
||||
|
||||
bit_number++;
|
||||
|
||||
return bit;
|
||||
|
||||
}
|
||||
|
||||
//////////////////////////////////////////////////
|
||||
|
||||
|
||||
SDD1_OL::SDD1_OL(SDD1_CM *associatedCM) :
|
||||
CM(associatedCM)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
///////////////////////////////////////////////////
|
||||
|
||||
|
||||
void SDD1_OL::prepareDecomp(uint32 first_byte, uint16 out_len, uint8 *out_buf) {
|
||||
|
||||
bitplanesInfo = SDD1_read(first_byte) & 0xc0;
|
||||
length=out_len;
|
||||
buffer=out_buf;
|
||||
|
||||
}
|
||||
|
||||
///////////////////////////////////////////////////
|
||||
|
||||
|
||||
void SDD1_OL::launch(void) {
|
||||
|
||||
uint8 i;
|
||||
uint8 register1, register2;
|
||||
|
||||
switch (bitplanesInfo) {
|
||||
case 0x00:
|
||||
case 0x40:
|
||||
case 0x80:
|
||||
i=1;
|
||||
do { //if length==0, we output 2^16 bytes
|
||||
if (!i) {
|
||||
*(buffer++)=register2;
|
||||
i=~i;
|
||||
}
|
||||
else {
|
||||
for (register1=register2=0, i=0x80; i; i>>=1) {
|
||||
if (CM->getBit()) register1 |= i;
|
||||
if (CM->getBit()) register2 |= i;
|
||||
}
|
||||
*(buffer++)=register1;
|
||||
}
|
||||
} while (--length);
|
||||
break;
|
||||
case 0xc0:
|
||||
do {
|
||||
for (register1=0, i=0x01; i; i<<=1) {
|
||||
if (CM->getBit()) register1 |= i;
|
||||
}
|
||||
*(buffer++)=register1;
|
||||
} while (--length);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
///////////////////////////////////////////////////////
|
||||
|
||||
|
||||
void SDD1emu::decompress(uint32 in_buf, uint16 out_len, uint8 *out_buf) {
|
||||
|
||||
IM.prepareDecomp(in_buf);
|
||||
BG0.prepareDecomp();
|
||||
BG1.prepareDecomp();
|
||||
BG2.prepareDecomp();
|
||||
BG3.prepareDecomp();
|
||||
BG4.prepareDecomp();
|
||||
BG5.prepareDecomp();
|
||||
BG6.prepareDecomp();
|
||||
BG7.prepareDecomp();
|
||||
PEM.prepareDecomp();
|
||||
CM.prepareDecomp(in_buf);
|
||||
OL.prepareDecomp(in_buf, out_len, out_buf);
|
||||
|
||||
OL.launch();
|
||||
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
|
||||
|
||||
SDD1emu::SDD1emu() :
|
||||
GCD(&IM),
|
||||
BG0(&GCD, 0), BG1(&GCD, 1), BG2(&GCD, 2), BG3(&GCD, 3),
|
||||
BG4(&GCD, 4), BG5(&GCD, 5), BG6(&GCD, 6), BG7(&GCD, 7),
|
||||
PEM(&BG0, &BG1, &BG2, &BG3, &BG4, &BG5, &BG6, &BG7),
|
||||
CM(&PEM),
|
||||
OL(&CM)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
///////////////////////////////////////////////////////////
|
||||
|
||||
#endif
|
@@ -1,164 +0,0 @@
|
||||
/************************************************************************
|
||||
|
||||
S-DD1'algorithm emulation code
|
||||
------------------------------
|
||||
|
||||
Author: Andreas Naive
|
||||
Date: August 2003
|
||||
Last update: October 2004
|
||||
|
||||
This code is Public Domain. There is no copyright holded by the author.
|
||||
Said this, the author wish to explicitly emphasize his inalienable moral rights
|
||||
over this piece of intelectual work and the previous research that made it
|
||||
possible, as recognized by most of the copyright laws around the world.
|
||||
|
||||
This code is provided 'as-is', with no warranty, expressed or implied.
|
||||
No responsability is assumed by the author in connection with it.
|
||||
|
||||
The author is greatly indebted with The Dumper, without whose help and
|
||||
patience providing him with real S-DD1 data the research would have never been
|
||||
possible. He also wish to note that in the very beggining of his research,
|
||||
Neviksti had done some steps in the right direction. By last, the author is
|
||||
indirectly indebted to all the people that worked and contributed in the
|
||||
S-DD1 issue in the past.
|
||||
|
||||
An algorithm's documentation is available as a separate document.
|
||||
The implementation is obvious when the algorithm is
|
||||
understood.
|
||||
|
||||
************************************************************************/
|
||||
|
||||
#define bool8 uint8
|
||||
|
||||
class SDD1_IM { //Input Manager
|
||||
|
||||
public:
|
||||
SDD1_IM(void) {}
|
||||
void prepareDecomp(uint32 in_buf);
|
||||
uint8 getCodeword(const uint8 code_len);
|
||||
|
||||
private:
|
||||
uint32 byte_ptr;
|
||||
uint8 bit_count;
|
||||
|
||||
};
|
||||
|
||||
////////////////////////////////////////////////////
|
||||
|
||||
|
||||
class SDD1_GCD { //Golomb-Code Decoder
|
||||
|
||||
public:
|
||||
SDD1_GCD(SDD1_IM *associatedIM);
|
||||
void getRunCount(uint8 code_num, uint8 *MPScount, bool8 *LPSind);
|
||||
|
||||
private:
|
||||
SDD1_IM *const IM;
|
||||
|
||||
};
|
||||
|
||||
//////////////////////////////////////////////////////
|
||||
|
||||
|
||||
class SDD1_BG { // Bits Generator
|
||||
|
||||
public:
|
||||
SDD1_BG(SDD1_GCD *associatedGCD, uint8 code);
|
||||
void prepareDecomp(void);
|
||||
uint8 getBit(bool8 *endOfRun);
|
||||
|
||||
private:
|
||||
const uint8 code_num;
|
||||
uint8 MPScount;
|
||||
bool8 LPSind;
|
||||
SDD1_GCD *const GCD;
|
||||
|
||||
};
|
||||
|
||||
////////////////////////////////////////////////
|
||||
|
||||
|
||||
class SDD1_PEM { //Probability Estimation Module
|
||||
|
||||
public:
|
||||
SDD1_PEM(SDD1_BG *associatedBG0, SDD1_BG *associatedBG1,
|
||||
SDD1_BG *associatedBG2, SDD1_BG *associatedBG3,
|
||||
SDD1_BG *associatedBG4, SDD1_BG *associatedBG5,
|
||||
SDD1_BG *associatedBG6, SDD1_BG *associatedBG7);
|
||||
void prepareDecomp(void);
|
||||
uint8 getBit(uint8 context);
|
||||
|
||||
private:
|
||||
struct state {
|
||||
uint8 code_num;
|
||||
uint8 nextIfMPS;
|
||||
uint8 nextIfLPS;
|
||||
};
|
||||
static const state evolution_table[];
|
||||
struct SDD1_ContextInfo {
|
||||
uint8 status;
|
||||
uint8 MPS;
|
||||
} contextInfo[32];
|
||||
SDD1_BG * BG[8];
|
||||
|
||||
};
|
||||
|
||||
///////////////////////////////////////////////////
|
||||
|
||||
|
||||
class SDD1_CM { //Context Model
|
||||
|
||||
public:
|
||||
SDD1_CM(SDD1_PEM *associatedPEM);
|
||||
void prepareDecomp(uint32 first_byte);
|
||||
uint8 getBit(void);
|
||||
|
||||
private:
|
||||
uint8 bitplanesInfo;
|
||||
uint8 contextBitsInfo;
|
||||
uint8 bit_number;
|
||||
uint8 currBitplane;
|
||||
uint16 prevBitplaneBits[8];
|
||||
SDD1_PEM *const PEM;
|
||||
|
||||
};
|
||||
|
||||
///////////////////////////////////////////////////
|
||||
|
||||
|
||||
class SDD1_OL { //Output Logic
|
||||
|
||||
public:
|
||||
SDD1_OL(SDD1_CM *associatedCM);
|
||||
void prepareDecomp(uint32 first_byte, uint16 out_len, uint8 *out_buf);
|
||||
void launch(void);
|
||||
|
||||
private:
|
||||
uint8 bitplanesInfo;
|
||||
uint16 length;
|
||||
uint8 *buffer;
|
||||
SDD1_CM *const CM;
|
||||
|
||||
};
|
||||
|
||||
/////////////////////////////////////////////////////////
|
||||
|
||||
|
||||
class SDD1emu {
|
||||
|
||||
public:
|
||||
SDD1emu(void);
|
||||
void decompress(uint32 in_buf, uint16 out_len, uint8 *out_buf);
|
||||
|
||||
private:
|
||||
SDD1_IM IM;
|
||||
SDD1_GCD GCD;
|
||||
SDD1_BG BG0; SDD1_BG BG1; SDD1_BG BG2; SDD1_BG BG3;
|
||||
SDD1_BG BG4; SDD1_BG BG5; SDD1_BG BG6; SDD1_BG BG7;
|
||||
SDD1_PEM PEM;
|
||||
SDD1_CM CM;
|
||||
SDD1_OL OL;
|
||||
|
||||
};
|
||||
|
||||
#undef bool8
|
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user