mirror of https://github.com/bsnes-emu/bsnes.git
Update to bsnes v061r02 release.
Complete rewrite of adc + sbc opcodes, should fix: - adc BCD overflow flag - sbc BCD overflow flag - sbc BCD invalid input value Testing is appreciated, I believe Sim Earth is probably the most likely to observe any difference.
This commit is contained in:
parent
79404ec523
commit
78e1a5b067
BIN
QtCore4.dll
BIN
QtCore4.dll
Binary file not shown.
BIN
QtGui4.dll
BIN
QtGui4.dll
Binary file not shown.
Binary file not shown.
BIN
libgomp-1.dll
BIN
libgomp-1.dll
Binary file not shown.
BIN
mingwm10.dll
BIN
mingwm10.dll
Binary file not shown.
|
@ -1,17 +0,0 @@
|
||||||
//CRT curvature shader
|
|
||||||
//license: GPL
|
|
||||||
//author: DOLLS
|
|
||||||
|
|
||||||
uniform sampler2D rubyTexture;
|
|
||||||
|
|
||||||
#define distortion 0.2
|
|
||||||
|
|
||||||
vec2 barrelDistortion(vec2 coord) {
|
|
||||||
vec2 cc = coord - 0.5;
|
|
||||||
float dist = dot(cc, cc);
|
|
||||||
return coord + cc * (dist + distortion * dist * dist) * distortion;
|
|
||||||
}
|
|
||||||
|
|
||||||
void main(void) {
|
|
||||||
gl_FragColor = texture2D(rubyTexture, barrelDistortion(gl_TexCoord[0].xy));
|
|
||||||
}
|
|
|
@ -1,14 +0,0 @@
|
||||||
//HDRTV GLSL shader
|
|
||||||
//license: GPL
|
|
||||||
//original version by SimoneT
|
|
||||||
//ruby port by byuu
|
|
||||||
|
|
||||||
uniform sampler2D rubyTexture;
|
|
||||||
|
|
||||||
void main(void) {
|
|
||||||
vec4 rgb = texture2D(rubyTexture, gl_TexCoord[0].xy);
|
|
||||||
vec4 intens = smoothstep(0.2,0.8,rgb) + normalize(vec4(rgb.xyz, 1.0));
|
|
||||||
|
|
||||||
if(fract(gl_FragCoord.y * 0.5) > 0.5) intens = rgb * 0.8;
|
|
||||||
gl_FragColor = intens;
|
|
||||||
}
|
|
|
@ -1,9 +0,0 @@
|
||||||
//HDRTV GLSL shader
|
|
||||||
//license: GPL
|
|
||||||
//original version by SimoneT
|
|
||||||
//ruby port by byuu
|
|
||||||
|
|
||||||
void main(void) {
|
|
||||||
gl_Position = ftransform();
|
|
||||||
gl_TexCoord[0] = gl_MultiTexCoord0;
|
|
||||||
}
|
|
|
@ -1,25 +0,0 @@
|
||||||
texture rubyTexture;
|
|
||||||
|
|
||||||
float4 vec;
|
|
||||||
|
|
||||||
sampler s0 = sampler_state { texture = <rubyTexture>; };
|
|
||||||
float3 LightColor = { 1.0, 0.7, 0.5 };
|
|
||||||
float3 DarkColor = { 0.2, 0.05, 0.0 };
|
|
||||||
|
|
||||||
float4 DiffColorPass(in float2 Tex : TEXCOORD0) : COLOR0
|
|
||||||
{
|
|
||||||
vec.x = 0.5;
|
|
||||||
vec.y = 1.0;
|
|
||||||
float3 scnColor = LightColor * tex2D(s0, Tex).xyz;
|
|
||||||
float3 grayXfer = float3(0.3, 0.59, 0.11);
|
|
||||||
float gray = dot(grayXfer, scnColor);
|
|
||||||
float3 muted = lerp(scnColor, gray.xxx, vec.x);
|
|
||||||
float3 sepia = lerp(DarkColor, LightColor, gray);
|
|
||||||
float3 result = lerp(muted, sepia, vec.y);
|
|
||||||
return float4(result, 1);
|
|
||||||
}
|
|
||||||
|
|
||||||
Technique T0
|
|
||||||
{
|
|
||||||
pass p0 { PixelShader = compile ps_2_0 DiffColorPass(); }
|
|
||||||
}
|
|
|
@ -1,49 +0,0 @@
|
||||||
//HQ2x GLSL shader
|
|
||||||
//license: GPL
|
|
||||||
//original version by guest(r)
|
|
||||||
//ruby port by byuu
|
|
||||||
|
|
||||||
uniform sampler2D rubyTexture;
|
|
||||||
|
|
||||||
const float mx = 0.325; // start smoothing wt.
|
|
||||||
const float k = -0.250; // wt. decrease factor
|
|
||||||
const float max_w = 0.25; // max filter weigth
|
|
||||||
const float min_w =-0.05; // min filter weigth
|
|
||||||
const float lum_add = 0.25; // effects smoothing
|
|
||||||
|
|
||||||
void main() {
|
|
||||||
vec3 c00 = texture2D(rubyTexture, gl_TexCoord[1].xy).xyz;
|
|
||||||
vec3 c10 = texture2D(rubyTexture, gl_TexCoord[1].zw).xyz;
|
|
||||||
vec3 c20 = texture2D(rubyTexture, gl_TexCoord[2].xy).xyz;
|
|
||||||
vec3 c01 = texture2D(rubyTexture, gl_TexCoord[4].zw).xyz;
|
|
||||||
vec3 c11 = texture2D(rubyTexture, gl_TexCoord[0].xy).xyz;
|
|
||||||
vec3 c21 = texture2D(rubyTexture, gl_TexCoord[2].zw).xyz;
|
|
||||||
vec3 c02 = texture2D(rubyTexture, gl_TexCoord[4].xy).xyz;
|
|
||||||
vec3 c12 = texture2D(rubyTexture, gl_TexCoord[3].zw).xyz;
|
|
||||||
vec3 c22 = texture2D(rubyTexture, gl_TexCoord[3].xy).xyz;
|
|
||||||
vec3 dt = vec3(1.0, 1.0, 1.0);
|
|
||||||
|
|
||||||
float md1 = dot(abs(c00 - c22), dt);
|
|
||||||
float md2 = dot(abs(c02 - c20), dt);
|
|
||||||
|
|
||||||
float w1 = dot(abs(c22 - c11), dt) * md2;
|
|
||||||
float w2 = dot(abs(c02 - c11), dt) * md1;
|
|
||||||
float w3 = dot(abs(c00 - c11), dt) * md2;
|
|
||||||
float w4 = dot(abs(c20 - c11), dt) * md1;
|
|
||||||
|
|
||||||
float t1 = w1 + w3;
|
|
||||||
float t2 = w2 + w4;
|
|
||||||
float ww = max(t1, t2) + 0.0001;
|
|
||||||
|
|
||||||
c11 = (w1 * c00 + w2 * c20 + w3 * c22 + w4 * c02 + ww * c11) / (t1 + t2 + ww);
|
|
||||||
|
|
||||||
float lc1 = k / (0.12 * dot(c10 + c12 + c11, dt) + lum_add);
|
|
||||||
float lc2 = k / (0.12 * dot(c01 + c21 + c11, dt) + lum_add);
|
|
||||||
|
|
||||||
w1 = clamp(lc1 * dot(abs(c11 - c10), dt) + mx, min_w, max_w);
|
|
||||||
w2 = clamp(lc2 * dot(abs(c11 - c21), dt) + mx, min_w, max_w);
|
|
||||||
w3 = clamp(lc1 * dot(abs(c11 - c12), dt) + mx, min_w, max_w);
|
|
||||||
w4 = clamp(lc2 * dot(abs(c11 - c01), dt) + mx, min_w, max_w);
|
|
||||||
|
|
||||||
gl_FragColor.xyz = w1 * c10 + w2 * c21 + w3 * c12 + w4 * c01 + (1.0 - w1 - w2 - w3 - w4) * c11;
|
|
||||||
}
|
|
|
@ -1,26 +0,0 @@
|
||||||
//HQ2x GLSL shader
|
|
||||||
//license: GPL
|
|
||||||
//original version by guest(r)
|
|
||||||
//ruby port by byuu
|
|
||||||
|
|
||||||
uniform vec2 rubyTextureSize;
|
|
||||||
|
|
||||||
void main() {
|
|
||||||
float x = 0.5 * (1.0 / rubyTextureSize.x);
|
|
||||||
float y = 0.5 * (1.0 / rubyTextureSize.y);
|
|
||||||
vec2 dg1 = vec2( x, y);
|
|
||||||
vec2 dg2 = vec2(-x, y);
|
|
||||||
vec2 dx = vec2(x, 0.0);
|
|
||||||
vec2 dy = vec2(0.0, y);
|
|
||||||
|
|
||||||
gl_Position = gl_ModelViewProjectionMatrix * gl_Vertex;
|
|
||||||
gl_TexCoord[0] = gl_MultiTexCoord0;
|
|
||||||
gl_TexCoord[1].xy = gl_TexCoord[0].xy - dg1;
|
|
||||||
gl_TexCoord[1].zw = gl_TexCoord[0].xy - dy;
|
|
||||||
gl_TexCoord[2].xy = gl_TexCoord[0].xy - dg2;
|
|
||||||
gl_TexCoord[2].zw = gl_TexCoord[0].xy + dx;
|
|
||||||
gl_TexCoord[3].xy = gl_TexCoord[0].xy + dg1;
|
|
||||||
gl_TexCoord[3].zw = gl_TexCoord[0].xy + dy;
|
|
||||||
gl_TexCoord[4].xy = gl_TexCoord[0].xy + dg2;
|
|
||||||
gl_TexCoord[4].zw = gl_TexCoord[0].xy - dx;
|
|
||||||
}
|
|
|
@ -1,36 +0,0 @@
|
||||||
//Pixellate shader
|
|
||||||
//license: GPL
|
|
||||||
//author: Fes
|
|
||||||
|
|
||||||
uniform sampler2D rubyTexture;
|
|
||||||
uniform vec2 rubyTextureSize;
|
|
||||||
|
|
||||||
void main() {
|
|
||||||
vec2 texelSize = 1.0 / rubyTextureSize;
|
|
||||||
|
|
||||||
vec2 range;
|
|
||||||
range.x = dFdx(gl_TexCoord[0].x) / 2.0 * 0.99;
|
|
||||||
range.y = dFdy(gl_TexCoord[0].y) / 2.0 * 0.99;
|
|
||||||
|
|
||||||
float left = gl_TexCoord[0].x - range.x;
|
|
||||||
float top = gl_TexCoord[0].y + range.y;
|
|
||||||
float right = gl_TexCoord[0].x + range.x;
|
|
||||||
float bottom = gl_TexCoord[0].y - range.y;
|
|
||||||
|
|
||||||
vec4 topLeftColor = texture2D(rubyTexture, (floor(vec2(left, top) / texelSize) + 0.5) * texelSize);
|
|
||||||
vec4 bottomRightColor = texture2D(rubyTexture, (floor(vec2(right, bottom) / texelSize) + 0.5) * texelSize);
|
|
||||||
vec4 bottomLeftColor = texture2D(rubyTexture, (floor(vec2(left, bottom) / texelSize) + 0.5) * texelSize);
|
|
||||||
vec4 topRightColor = texture2D(rubyTexture, (floor(vec2(right, top) / texelSize) + 0.5) * texelSize);
|
|
||||||
|
|
||||||
vec2 border = clamp(round(gl_TexCoord[0] / texelSize) * texelSize, vec2(left, bottom), vec2(right, top));
|
|
||||||
|
|
||||||
float totalArea = 4.0 * range.x * range.y;
|
|
||||||
|
|
||||||
vec4 averageColor;
|
|
||||||
averageColor = ((border.x - left) * (top - border.y) / totalArea) * topLeftColor;
|
|
||||||
averageColor += ((right - border.x) * (border.y - bottom) / totalArea) * bottomRightColor;
|
|
||||||
averageColor += ((border.x - left) * (border.y - bottom) / totalArea) * bottomLeftColor;
|
|
||||||
averageColor += ((right - border.x) * (top - border.y) / totalArea) * topRightColor;
|
|
||||||
|
|
||||||
gl_FragColor = averageColor;
|
|
||||||
}
|
|
|
@ -1,8 +0,0 @@
|
||||||
//Pixellate shader
|
|
||||||
//license: GPL
|
|
||||||
//author: Fes
|
|
||||||
|
|
||||||
void main() {
|
|
||||||
gl_Position = ftransform();
|
|
||||||
gl_TexCoord[0] = gl_MultiTexCoord0;
|
|
||||||
}
|
|
|
@ -1,28 +0,0 @@
|
||||||
//Scale2x GLSL shader
|
|
||||||
//license: GPL
|
|
||||||
//original version by Pete Bernert
|
|
||||||
//ruby port by byuu
|
|
||||||
uniform sampler2D rubyTexture;
|
|
||||||
uniform vec2 rubyTextureSize;
|
|
||||||
|
|
||||||
void main() {
|
|
||||||
vec4 colD, colF, colB, colH, col, tmp;
|
|
||||||
vec2 sel;
|
|
||||||
|
|
||||||
col = texture2DProj(rubyTexture, gl_TexCoord[0]); //central (can be E0-E3)
|
|
||||||
colD = texture2DProj(rubyTexture, gl_TexCoord[1]); //D (left)
|
|
||||||
colF = texture2DProj(rubyTexture, gl_TexCoord[2]); //F (right)
|
|
||||||
colB = texture2DProj(rubyTexture, gl_TexCoord[3]); //B (top)
|
|
||||||
colH = texture2DProj(rubyTexture, gl_TexCoord[4]); //H (bottom)
|
|
||||||
|
|
||||||
sel = fract(gl_TexCoord[0].xy * rubyTextureSize.xy); //where are we (E0-E3)?
|
|
||||||
//E0 is default
|
|
||||||
if(sel.y >= 0.5) { tmp = colB; colB = colH; colH = tmp; } //E1 (or E3): swap B and H
|
|
||||||
if(sel.x >= 0.5) { tmp = colF; colF = colD; colD = tmp; } //E2 (or E3): swap D and F
|
|
||||||
|
|
||||||
if(colB == colD && colB != colF && colD != colH) { //do the Scale2x rule
|
|
||||||
col = colD;
|
|
||||||
}
|
|
||||||
|
|
||||||
gl_FragColor = col;
|
|
||||||
}
|
|
|
@ -1,28 +0,0 @@
|
||||||
//Scale2x GLSL shader
|
|
||||||
//license: GPL
|
|
||||||
//original version by Pete Bernert
|
|
||||||
//ruby port by byuu
|
|
||||||
|
|
||||||
uniform vec2 rubyTextureSize;
|
|
||||||
|
|
||||||
void main() {
|
|
||||||
vec4 offsetx;
|
|
||||||
vec4 offsety;
|
|
||||||
|
|
||||||
gl_Position = gl_ModelViewProjectionMatrix * gl_Vertex;
|
|
||||||
|
|
||||||
offsetx.x = 1.0 / rubyTextureSize.x;
|
|
||||||
offsetx.y = 0.0;
|
|
||||||
offsetx.w = 0.0;
|
|
||||||
offsetx.z = 0.0;
|
|
||||||
offsety.y = 1.0 / rubyTextureSize.y;
|
|
||||||
offsety.x = 0.0;
|
|
||||||
offsety.w = 0.0;
|
|
||||||
offsety.z = 0.0;
|
|
||||||
|
|
||||||
gl_TexCoord[0] = gl_MultiTexCoord0; //center
|
|
||||||
gl_TexCoord[1] = gl_TexCoord[0] - offsetx; //left
|
|
||||||
gl_TexCoord[2] = gl_TexCoord[0] + offsetx; //right
|
|
||||||
gl_TexCoord[3] = gl_TexCoord[0] - offsety; //top
|
|
||||||
gl_TexCoord[4] = gl_TexCoord[0] + offsety; //bottom
|
|
||||||
}
|
|
BIN
pthreadGC2.dll
BIN
pthreadGC2.dll
Binary file not shown.
BIN
snesfilter.dll
BIN
snesfilter.dll
Binary file not shown.
|
@ -1,132 +0,0 @@
|
||||||
//2xSaI / Super 2xSaI / Super Eagle filter
|
|
||||||
//authors: kode54 and Kreed
|
|
||||||
//license: GPL
|
|
||||||
|
|
||||||
#include "2xsai.hpp"
|
|
||||||
#include "implementation.cpp"
|
|
||||||
|
|
||||||
//=====
|
|
||||||
//2xSaI
|
|
||||||
//=====
|
|
||||||
|
|
||||||
void _2xSaIFilter::size(unsigned &outwidth, unsigned &outheight, unsigned width, unsigned height) {
|
|
||||||
outwidth = width;
|
|
||||||
outheight = height;
|
|
||||||
|
|
||||||
if(width <= 256 && height <= 240) {
|
|
||||||
outwidth *= 2;
|
|
||||||
outheight *= 2;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void _2xSaIFilter::render(
|
|
||||||
uint32_t *output, unsigned outpitch, const uint16_t *input, unsigned pitch,
|
|
||||||
const unsigned *line, unsigned width, unsigned height
|
|
||||||
) {
|
|
||||||
if(width > 256 || height > 240) {
|
|
||||||
filter_direct.render(output, outpitch, input, pitch, line, width, height);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
for(unsigned y = 0; y < height; y++) {
|
|
||||||
const uint16_t *line_in = (const uint16_t *) (((const uint8_t*)input) + pitch * y);
|
|
||||||
uint32_t *line_out = temp + y * 256;
|
|
||||||
for(unsigned x = 0; x < width; x++) {
|
|
||||||
line_out[x] = colortable[line_in[x]];
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
_2xSaI32( (unsigned char *) temp, 1024, 0, (unsigned char *) output, outpitch, width, height );
|
|
||||||
}
|
|
||||||
|
|
||||||
_2xSaIFilter::_2xSaIFilter() {
|
|
||||||
temp = new uint32_t[256*240];
|
|
||||||
}
|
|
||||||
|
|
||||||
_2xSaIFilter::~_2xSaIFilter() {
|
|
||||||
delete[] temp;
|
|
||||||
}
|
|
||||||
|
|
||||||
//===========
|
|
||||||
//Super 2xSaI
|
|
||||||
//===========
|
|
||||||
|
|
||||||
void Super2xSaIFilter::size(unsigned &outwidth, unsigned &outheight, unsigned width, unsigned height) {
|
|
||||||
outwidth = width;
|
|
||||||
outheight = height;
|
|
||||||
|
|
||||||
if(width <= 256 && height <= 240) {
|
|
||||||
outwidth *= 2;
|
|
||||||
outheight *= 2;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void Super2xSaIFilter::render(
|
|
||||||
uint32_t *output, unsigned outpitch, const uint16_t *input, unsigned pitch,
|
|
||||||
const unsigned *line, unsigned width, unsigned height
|
|
||||||
) {
|
|
||||||
if(width > 256 || height > 240) {
|
|
||||||
filter_direct.render(output, outpitch, input, pitch, line, width, height);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
for(unsigned y = 0; y < height; y++) {
|
|
||||||
const uint16_t *line_in = (const uint16_t *) (((const uint8_t*)input) + pitch * y);
|
|
||||||
uint32_t *line_out = temp + y * 256;
|
|
||||||
for(unsigned x = 0; x < width; x++) {
|
|
||||||
line_out[x] = colortable[line_in[x]];
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
Super2xSaI32( (unsigned char *) temp, 1024, 0, (unsigned char *) output, outpitch, width, height );
|
|
||||||
}
|
|
||||||
|
|
||||||
Super2xSaIFilter::Super2xSaIFilter() {
|
|
||||||
temp = new uint32_t[256*240];
|
|
||||||
}
|
|
||||||
|
|
||||||
Super2xSaIFilter::~Super2xSaIFilter() {
|
|
||||||
delete[] temp;
|
|
||||||
}
|
|
||||||
|
|
||||||
//===========
|
|
||||||
//Super Eagle
|
|
||||||
//===========
|
|
||||||
|
|
||||||
void SuperEagleFilter::size(unsigned &outwidth, unsigned &outheight, unsigned width, unsigned height) {
|
|
||||||
outwidth = width;
|
|
||||||
outheight = height;
|
|
||||||
|
|
||||||
if(width <= 256 && height <= 240) {
|
|
||||||
outwidth *= 2;
|
|
||||||
outheight *= 2;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void SuperEagleFilter::render(
|
|
||||||
uint32_t *output, unsigned outpitch, const uint16_t *input, unsigned pitch,
|
|
||||||
const unsigned *line, unsigned width, unsigned height
|
|
||||||
) {
|
|
||||||
if(width > 256 || height > 240) {
|
|
||||||
filter_direct.render(output, outpitch, input, pitch, line, width, height);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
for(unsigned y = 0; y < height; y++) {
|
|
||||||
const uint16_t *line_in = (const uint16_t *) (((const uint8_t*)input) + pitch * y);
|
|
||||||
uint32_t *line_out = temp + y * 256;
|
|
||||||
for(unsigned x = 0; x < width; x++) {
|
|
||||||
line_out[x] = colortable[line_in[x]];
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
SuperEagle32( (unsigned char *) temp, 1024, 0, (unsigned char *) output, outpitch, width, height );
|
|
||||||
}
|
|
||||||
|
|
||||||
SuperEagleFilter::SuperEagleFilter() {
|
|
||||||
temp = new uint32_t[256*240];
|
|
||||||
}
|
|
||||||
|
|
||||||
SuperEagleFilter::~SuperEagleFilter() {
|
|
||||||
delete[] temp;
|
|
||||||
}
|
|
|
@ -1,35 +0,0 @@
|
||||||
class _2xSaIFilter {
|
|
||||||
public:
|
|
||||||
void size(unsigned&, unsigned&, unsigned, unsigned);
|
|
||||||
void render(uint32_t*, unsigned, const uint16_t*, unsigned, const unsigned*, unsigned, unsigned);
|
|
||||||
|
|
||||||
_2xSaIFilter();
|
|
||||||
~_2xSaIFilter();
|
|
||||||
|
|
||||||
private:
|
|
||||||
uint32_t *temp;
|
|
||||||
} filter_2xsai;
|
|
||||||
|
|
||||||
class Super2xSaIFilter {
|
|
||||||
public:
|
|
||||||
void size(unsigned&, unsigned&, unsigned, unsigned);
|
|
||||||
void render(uint32_t*, unsigned, const uint16_t*, unsigned, const unsigned*, unsigned, unsigned);
|
|
||||||
|
|
||||||
Super2xSaIFilter();
|
|
||||||
~Super2xSaIFilter();
|
|
||||||
|
|
||||||
private:
|
|
||||||
uint32_t *temp;
|
|
||||||
} filter_super2xsai;
|
|
||||||
|
|
||||||
class SuperEagleFilter {
|
|
||||||
public:
|
|
||||||
void size(unsigned&, unsigned&, unsigned, unsigned);
|
|
||||||
void render(uint32_t*, unsigned, const uint16_t*, unsigned, const unsigned*, unsigned, unsigned);
|
|
||||||
|
|
||||||
SuperEagleFilter();
|
|
||||||
~SuperEagleFilter();
|
|
||||||
|
|
||||||
private:
|
|
||||||
uint32_t *temp;
|
|
||||||
} filter_supereagle;
|
|
File diff suppressed because it is too large
Load Diff
|
@ -1,89 +0,0 @@
|
||||||
include nall/Makefile
|
|
||||||
|
|
||||||
qtlibs := QtCore QtGui
|
|
||||||
include nall/qt/Makefile
|
|
||||||
|
|
||||||
c := $(compiler) -std=gnu99
|
|
||||||
cpp := $(subst cc,++,$(compiler)) -std=gnu++0x
|
|
||||||
flags := -O3 -I. -Iobj -fomit-frame-pointer $(qtinc)
|
|
||||||
link :=
|
|
||||||
|
|
||||||
ifeq ($(platform),x)
|
|
||||||
flags := -fPIC -fopenmp $(flags)
|
|
||||||
link += -s -fopenmp -lpthread -lgomp
|
|
||||||
else ifeq ($(platform),osx)
|
|
||||||
flags := -fPIC -fopenmp $(flags)
|
|
||||||
link += -fopenmp -lpthread -lgomp
|
|
||||||
else ifeq ($(platform),win)
|
|
||||||
flags := -fopenmp $(flags)
|
|
||||||
link += -fopenmp -lpthread
|
|
||||||
endif
|
|
||||||
|
|
||||||
objects := snesfilter
|
|
||||||
|
|
||||||
compile = \
|
|
||||||
$(strip \
|
|
||||||
$(if $(filter %.c,$<), \
|
|
||||||
$(c) $(flags) $1 -c $< -o $@, \
|
|
||||||
$(if $(filter %.cpp,$<), \
|
|
||||||
$(cpp) $(flags) $1 -c $< -o $@ \
|
|
||||||
) \
|
|
||||||
) \
|
|
||||||
)
|
|
||||||
|
|
||||||
%.o: $<; $(call compile)
|
|
||||||
|
|
||||||
all: build;
|
|
||||||
|
|
||||||
objects := $(patsubst %,obj/%.o,$(objects))
|
|
||||||
moc_headers := $(call rwildcard,./,%.moc.hpp)
|
|
||||||
moc_objects := $(foreach f,$(moc_headers),obj/$(notdir $(patsubst %.moc.hpp,%.moc,$f)))
|
|
||||||
|
|
||||||
# automatically run moc on all .moc.hpp (MOC header) files
|
|
||||||
%.moc: $<; $(moc) -i $< -o $@
|
|
||||||
|
|
||||||
# automatically generate %.moc build rules
|
|
||||||
__list = $(moc_headers)
|
|
||||||
$(foreach f,$(moc_objects), \
|
|
||||||
$(eval __file = $(word 1,$(__list))) \
|
|
||||||
$(eval __list = $(wordlist 2,$(words $(__list)),$(__list))) \
|
|
||||||
$(eval $f: $(__file)) \
|
|
||||||
)
|
|
||||||
|
|
||||||
##################
|
|
||||||
### snesfilter ###
|
|
||||||
##################
|
|
||||||
|
|
||||||
obj/snesfilter.o: snesfilter.cpp *
|
|
||||||
|
|
||||||
###############
|
|
||||||
### targets ###
|
|
||||||
###############
|
|
||||||
|
|
||||||
build: $(moc_objects) $(objects)
|
|
||||||
ifeq ($(platform),x)
|
|
||||||
ar rcs libsnesfilter.a $(objects)
|
|
||||||
$(cpp) $(link) -o libsnesfilter.so -shared -Wl,-soname,libsnesfilter.so.1 $(objects) $(qtlib)
|
|
||||||
else ifeq ($(platform),osx)
|
|
||||||
ar rcs libsnesfilter.a $(objects)
|
|
||||||
$(cpp) $(link) -o libsnesfilter.dylib -shared -dynamiclib $(objects) $(qtlib)
|
|
||||||
else ifeq ($(platform),win)
|
|
||||||
$(cpp) $(link) -o snesfilter.dll -shared -Wl,--out-implib,libsnesfilter.a $(objects) $(qtlib)
|
|
||||||
endif
|
|
||||||
|
|
||||||
install:
|
|
||||||
ifeq ($(platform),x)
|
|
||||||
install -D -m 755 libsnesfilter.a $(DESTDIR)$(prefix)/lib
|
|
||||||
install -D -m 755 libsnesfilter.so $(DESTDIR)$(prefix)/lib
|
|
||||||
ldconfig -n $(DESTDIR)$(prefix)/lib
|
|
||||||
else ifeq ($(platform),osx)
|
|
||||||
cp libsnesfilter.dylib /usr/local/lib/libsnesfilter.dylib
|
|
||||||
endif
|
|
||||||
|
|
||||||
clean:
|
|
||||||
-@$(call delete,obj/*.o)
|
|
||||||
-@$(call delete,obj/*.moc)
|
|
||||||
-@$(call delete,libsnesfilter.a)
|
|
||||||
-@$(call delete,libsnesfilter.so)
|
|
||||||
-@$(call delete,libsnesfilter.dylib)
|
|
||||||
-@$(call delete,snesfilter.dll)
|
|
|
@ -1,2 +0,0 @@
|
||||||
@mingw32-make
|
|
||||||
@pause
|
|
|
@ -1 +0,0 @@
|
||||||
@mingw32-make clean
|
|
|
@ -1,32 +0,0 @@
|
||||||
#include "direct.hpp"
|
|
||||||
|
|
||||||
void DirectFilter::size(unsigned &outwidth, unsigned &outheight, unsigned width, unsigned height) {
|
|
||||||
outwidth = width;
|
|
||||||
outheight = height;
|
|
||||||
}
|
|
||||||
|
|
||||||
void DirectFilter::render(
|
|
||||||
uint32_t *output, unsigned outpitch, const uint16_t *input, unsigned pitch,
|
|
||||||
const unsigned *line, unsigned width, unsigned height
|
|
||||||
) {
|
|
||||||
pitch >>= 1;
|
|
||||||
outpitch >>= 2;
|
|
||||||
|
|
||||||
for(unsigned y = 0; y < height; y++) {
|
|
||||||
if(width == 512 && line[y] == 256) {
|
|
||||||
for(unsigned x = 0; x < 256; x++) {
|
|
||||||
uint16_t p = *input++;
|
|
||||||
*output++ = colortable[p];
|
|
||||||
*output++ = colortable[p];
|
|
||||||
}
|
|
||||||
input += 256;
|
|
||||||
} else {
|
|
||||||
for(unsigned x = 0; x < width; x++) {
|
|
||||||
uint16_t p = *input++;
|
|
||||||
*output++ = colortable[p];
|
|
||||||
}
|
|
||||||
}
|
|
||||||
input += pitch - width;
|
|
||||||
output += outpitch - width;
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,5 +0,0 @@
|
||||||
class DirectFilter {
|
|
||||||
public:
|
|
||||||
void size(unsigned&, unsigned&, unsigned, unsigned);
|
|
||||||
void render(uint32_t*, unsigned, const uint16_t*, unsigned, const unsigned*, unsigned, unsigned);
|
|
||||||
} filter_direct;
|
|
|
@ -1,203 +0,0 @@
|
||||||
//HQ2x filter
|
|
||||||
//authors: byuu and blargg
|
|
||||||
//license: public domain
|
|
||||||
//
|
|
||||||
//note: this is a clean reimplementation of the original HQ2x filter, which was
|
|
||||||
//written by Maxim Stepin (MaxSt). it is not 100% identical, but very similar.
|
|
||||||
|
|
||||||
#include "hq2x.hpp"
|
|
||||||
|
|
||||||
void HQ2xFilter::size(unsigned &outwidth, unsigned &outheight, unsigned width, unsigned height) {
|
|
||||||
if(height > 240) return filter_direct.size(outwidth, outheight, width, height);
|
|
||||||
outwidth = (width <= 256) ? width * 2 : width;
|
|
||||||
outheight = (height <= 240) ? height * 2 : height;
|
|
||||||
}
|
|
||||||
|
|
||||||
void HQ2xFilter::render(
|
|
||||||
uint32_t *output, unsigned outpitch, const uint16_t *input, unsigned pitch,
|
|
||||||
const unsigned *line, unsigned width, unsigned height
|
|
||||||
) {
|
|
||||||
if(height > 240) {
|
|
||||||
filter_direct.render(output, outpitch, input, pitch, line, width, height);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
pitch >>= 1;
|
|
||||||
outpitch >>= 2;
|
|
||||||
|
|
||||||
#pragma omp parallel for
|
|
||||||
for(unsigned y = 0; y < height; y++) {
|
|
||||||
const uint16_t *in = input + y * pitch;
|
|
||||||
uint32_t *out0 = output + y * pitch;
|
|
||||||
uint32_t *out1 = output + y * pitch + outpitch;
|
|
||||||
|
|
||||||
unsigned linewidth = line[y];
|
|
||||||
|
|
||||||
if(linewidth == 256) {
|
|
||||||
int prevline = (y == 0) || (linewidth != line[y - 1]) ? 0 : pitch;
|
|
||||||
int nextline = (y == height - 1) || (linewidth != line[y + 1]) ? 0 : pitch;
|
|
||||||
|
|
||||||
in++;
|
|
||||||
*out0++ = 0; *out0++ = 0;
|
|
||||||
*out1++ = 0; *out1++ = 0;
|
|
||||||
|
|
||||||
for(unsigned x = 1; x < 256 - 1; x++) {
|
|
||||||
uint16_t A = *(in - prevline - 1);
|
|
||||||
uint16_t B = *(in - prevline + 0);
|
|
||||||
uint16_t C = *(in - prevline + 1);
|
|
||||||
uint16_t D = *(in - 1);
|
|
||||||
uint16_t E = *(in + 0);
|
|
||||||
uint16_t F = *(in + 1);
|
|
||||||
uint16_t G = *(in + nextline - 1);
|
|
||||||
uint16_t H = *(in + nextline + 0);
|
|
||||||
uint16_t I = *(in + nextline + 1);
|
|
||||||
uint32_t e = yuvTable[E] + diff_offset;
|
|
||||||
|
|
||||||
uint8_t pattern;
|
|
||||||
pattern = diff(e, A) << 0;
|
|
||||||
pattern |= diff(e, B) << 1;
|
|
||||||
pattern |= diff(e, C) << 2;
|
|
||||||
pattern |= diff(e, D) << 3;
|
|
||||||
pattern |= diff(e, F) << 4;
|
|
||||||
pattern |= diff(e, G) << 5;
|
|
||||||
pattern |= diff(e, H) << 6;
|
|
||||||
pattern |= diff(e, I) << 7;
|
|
||||||
|
|
||||||
*(out0 + 0) = colortable[blend(hqTable[pattern], E, A, B, D, F, H)]; pattern = rotate[pattern];
|
|
||||||
*(out0 + 1) = colortable[blend(hqTable[pattern], E, C, F, B, H, D)]; pattern = rotate[pattern];
|
|
||||||
*(out1 + 1) = colortable[blend(hqTable[pattern], E, I, H, F, D, B)]; pattern = rotate[pattern];
|
|
||||||
*(out1 + 0) = colortable[blend(hqTable[pattern], E, G, D, H, B, F)];
|
|
||||||
|
|
||||||
in++;
|
|
||||||
out0 += 2;
|
|
||||||
out1 += 2;
|
|
||||||
}
|
|
||||||
|
|
||||||
in++;
|
|
||||||
*out0++ = 0; *out0++ = 0;
|
|
||||||
*out1++ = 0; *out1++ = 0;
|
|
||||||
} else {
|
|
||||||
for(unsigned x = 0; x < 512; x++) {
|
|
||||||
*out0++ = *out1++ = colortable[*in++];
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
HQ2xFilter::HQ2xFilter() {
|
|
||||||
yuvTable = new uint32_t[32768];
|
|
||||||
|
|
||||||
for(unsigned i = 0; i < 32768; i++) {
|
|
||||||
uint8_t R = (i >> 0) & 31;
|
|
||||||
uint8_t G = (i >> 5) & 31;
|
|
||||||
uint8_t B = (i >> 10) & 31;
|
|
||||||
|
|
||||||
//bgr555->bgr888
|
|
||||||
double r = (R << 3) | (R >> 2);
|
|
||||||
double g = (G << 3) | (G >> 2);
|
|
||||||
double b = (B << 3) | (B >> 2);
|
|
||||||
|
|
||||||
//bgr888->yuv888
|
|
||||||
double y = (r + g + b) * (0.25f * (63.5f / 48.0f));
|
|
||||||
double u = ((r - b) * 0.25f + 128.0f) * (7.5f / 7.0f);
|
|
||||||
double v = ((g * 2.0f - r - b) * 0.125f + 128.0f) * (7.5f / 6.0f);
|
|
||||||
|
|
||||||
yuvTable[i] = ((unsigned)y << 21) + ((unsigned)u << 11) + ((unsigned)v);
|
|
||||||
}
|
|
||||||
|
|
||||||
for(unsigned n = 0; n < 256; n++) {
|
|
||||||
rotate[n] = ((n >> 2) & 0x11) | ((n << 2) & 0x88)
|
|
||||||
| ((n & 0x01) << 5) | ((n & 0x08) << 3)
|
|
||||||
| ((n & 0x10) >> 3) | ((n & 0x80) >> 5);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
HQ2xFilter::~HQ2xFilter() {
|
|
||||||
delete[] yuvTable;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool HQ2xFilter::same(uint16_t x, uint16_t y) {
|
|
||||||
return !((yuvTable[x] - yuvTable[y] + diff_offset) & diff_mask);
|
|
||||||
}
|
|
||||||
|
|
||||||
bool HQ2xFilter::diff(uint32_t x, uint16_t y) {
|
|
||||||
return ((x - yuvTable[y]) & diff_mask);
|
|
||||||
}
|
|
||||||
|
|
||||||
void HQ2xFilter::grow(uint32_t &n) { n |= n << 16; n &= 0x03e07c1f; }
|
|
||||||
uint16_t HQ2xFilter::pack(uint32_t n) { n &= 0x03e07c1f; return n | (n >> 16); }
|
|
||||||
|
|
||||||
uint16_t HQ2xFilter::blend1(uint32_t A, uint32_t B) {
|
|
||||||
grow(A); grow(B);
|
|
||||||
A = (A * 3 + B) >> 2;
|
|
||||||
return pack(A);
|
|
||||||
}
|
|
||||||
|
|
||||||
uint16_t HQ2xFilter::blend2(uint32_t A, uint32_t B, uint32_t C) {
|
|
||||||
grow(A); grow(B); grow(C);
|
|
||||||
return pack((A * 2 + B + C) >> 2);
|
|
||||||
}
|
|
||||||
|
|
||||||
uint16_t HQ2xFilter::blend3(uint32_t A, uint32_t B, uint32_t C) {
|
|
||||||
grow(A); grow(B); grow(C);
|
|
||||||
return pack((A * 5 + B * 2 + C) >> 3);
|
|
||||||
}
|
|
||||||
|
|
||||||
uint16_t HQ2xFilter::blend4(uint32_t A, uint32_t B, uint32_t C) {
|
|
||||||
grow(A); grow(B); grow(C);
|
|
||||||
return pack((A * 6 + B + C) >> 3);
|
|
||||||
}
|
|
||||||
|
|
||||||
uint16_t HQ2xFilter::blend5(uint32_t A, uint32_t B, uint32_t C) {
|
|
||||||
grow(A); grow(B); grow(C);
|
|
||||||
return pack((A * 2 + (B + C) * 3) >> 3);
|
|
||||||
}
|
|
||||||
|
|
||||||
uint16_t HQ2xFilter::blend6(uint32_t A, uint32_t B, uint32_t C) {
|
|
||||||
grow(A); grow(B); grow(C);
|
|
||||||
return pack((A * 14 + B + C) >> 4);
|
|
||||||
}
|
|
||||||
|
|
||||||
uint16_t HQ2xFilter::blend(unsigned rule, uint16_t E, uint16_t A, uint16_t B, uint16_t D, uint16_t F, uint16_t H) {
|
|
||||||
switch(rule) { default:
|
|
||||||
case 0: return E;
|
|
||||||
case 1: return blend1(E, A);
|
|
||||||
case 2: return blend1(E, D);
|
|
||||||
case 3: return blend1(E, B);
|
|
||||||
case 4: return blend2(E, D, B);
|
|
||||||
case 5: return blend2(E, A, B);
|
|
||||||
case 6: return blend2(E, A, D);
|
|
||||||
case 7: return blend3(E, B, D);
|
|
||||||
case 8: return blend3(E, D, B);
|
|
||||||
case 9: return blend4(E, D, B);
|
|
||||||
case 10: return blend5(E, D, B);
|
|
||||||
case 11: return blend6(E, D, B);
|
|
||||||
case 12: return same(B, D) ? blend2(E, D, B) : E;
|
|
||||||
case 13: return same(B, D) ? blend5(E, D, B) : E;
|
|
||||||
case 14: return same(B, D) ? blend6(E, D, B) : E;
|
|
||||||
case 15: return same(B, D) ? blend2(E, D, B) : blend1(E, A);
|
|
||||||
case 16: return same(B, D) ? blend4(E, D, B) : blend1(E, A);
|
|
||||||
case 17: return same(B, D) ? blend5(E, D, B) : blend1(E, A);
|
|
||||||
case 18: return same(B, F) ? blend3(E, B, D) : blend1(E, D);
|
|
||||||
case 19: return same(D, H) ? blend3(E, D, B) : blend1(E, B);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
const uint8_t HQ2xFilter::hqTable[256] = {
|
|
||||||
4, 4, 6, 2, 4, 4, 6, 2, 5, 3, 15, 12, 5, 3, 17, 13,
|
|
||||||
4, 4, 6, 18, 4, 4, 6, 18, 5, 3, 12, 12, 5, 3, 1, 12,
|
|
||||||
4, 4, 6, 2, 4, 4, 6, 2, 5, 3, 17, 13, 5, 3, 16, 14,
|
|
||||||
4, 4, 6, 18, 4, 4, 6, 18, 5, 3, 16, 12, 5, 3, 1, 14,
|
|
||||||
4, 4, 6, 2, 4, 4, 6, 2, 5, 19, 12, 12, 5, 19, 16, 12,
|
|
||||||
4, 4, 6, 2, 4, 4, 6, 2, 5, 3, 16, 12, 5, 3, 16, 12,
|
|
||||||
4, 4, 6, 2, 4, 4, 6, 2, 5, 19, 1, 12, 5, 19, 1, 14,
|
|
||||||
4, 4, 6, 2, 4, 4, 6, 18, 5, 3, 16, 12, 5, 19, 1, 14,
|
|
||||||
4, 4, 6, 2, 4, 4, 6, 2, 5, 3, 15, 12, 5, 3, 17, 13,
|
|
||||||
4, 4, 6, 2, 4, 4, 6, 2, 5, 3, 16, 12, 5, 3, 16, 12,
|
|
||||||
4, 4, 6, 2, 4, 4, 6, 2, 5, 3, 17, 13, 5, 3, 16, 14,
|
|
||||||
4, 4, 6, 2, 4, 4, 6, 2, 5, 3, 16, 13, 5, 3, 1, 14,
|
|
||||||
4, 4, 6, 2, 4, 4, 6, 2, 5, 3, 16, 12, 5, 3, 16, 13,
|
|
||||||
4, 4, 6, 2, 4, 4, 6, 2, 5, 3, 16, 12, 5, 3, 1, 12,
|
|
||||||
4, 4, 6, 2, 4, 4, 6, 2, 5, 3, 16, 12, 5, 3, 1, 14,
|
|
||||||
4, 4, 6, 2, 4, 4, 6, 2, 5, 3, 1, 12, 5, 3, 1, 14,
|
|
||||||
};
|
|
|
@ -1,30 +0,0 @@
|
||||||
class HQ2xFilter {
|
|
||||||
public:
|
|
||||||
void size(unsigned&, unsigned&, unsigned, unsigned);
|
|
||||||
void render(uint32_t*, unsigned, const uint16_t*, unsigned, const unsigned*, unsigned, unsigned);
|
|
||||||
|
|
||||||
HQ2xFilter();
|
|
||||||
~HQ2xFilter();
|
|
||||||
|
|
||||||
private:
|
|
||||||
enum {
|
|
||||||
diff_offset = (0x440 << 21) + (0x207 << 11) + 0x407,
|
|
||||||
diff_mask = (0x380 << 21) + (0x1f0 << 11) + 0x3f0,
|
|
||||||
};
|
|
||||||
|
|
||||||
static const uint8_t hqTable[256];
|
|
||||||
uint32_t *yuvTable;
|
|
||||||
uint8_t rotate[256];
|
|
||||||
|
|
||||||
alwaysinline bool same(uint16_t x, uint16_t y);
|
|
||||||
alwaysinline bool diff(uint32_t x, uint16_t y);
|
|
||||||
alwaysinline void grow(uint32_t &n);
|
|
||||||
alwaysinline uint16_t pack(uint32_t n);
|
|
||||||
alwaysinline uint16_t blend1(uint32_t A, uint32_t B);
|
|
||||||
alwaysinline uint16_t blend2(uint32_t A, uint32_t B, uint32_t C);
|
|
||||||
alwaysinline uint16_t blend3(uint32_t A, uint32_t B, uint32_t C);
|
|
||||||
alwaysinline uint16_t blend4(uint32_t A, uint32_t B, uint32_t C);
|
|
||||||
alwaysinline uint16_t blend5(uint32_t A, uint32_t B, uint32_t C);
|
|
||||||
alwaysinline uint16_t blend6(uint32_t A, uint32_t B, uint32_t C);
|
|
||||||
alwaysinline uint16_t blend(unsigned rule, uint16_t E, uint16_t A, uint16_t B, uint16_t D, uint16_t F, uint16_t H);
|
|
||||||
} filter_hq2x;
|
|
|
@ -1,61 +0,0 @@
|
||||||
#include "lq2x.hpp"
|
|
||||||
|
|
||||||
void LQ2xFilter::size(unsigned &outwidth, unsigned &outheight, unsigned width, unsigned height) {
|
|
||||||
if(height > 240) return filter_direct.size(outwidth, outheight, width, height);
|
|
||||||
outwidth = (width <= 256) ? width * 2 : width;
|
|
||||||
outheight = (height <= 240) ? height * 2 : height;
|
|
||||||
}
|
|
||||||
|
|
||||||
void LQ2xFilter::render(
|
|
||||||
uint32_t *output, unsigned outpitch, const uint16_t *input, unsigned pitch,
|
|
||||||
const unsigned *line, unsigned width, unsigned height
|
|
||||||
) {
|
|
||||||
if(height > 240) {
|
|
||||||
filter_direct.render(output, outpitch, input, pitch, line, width, height);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
pitch >>= 1;
|
|
||||||
outpitch >>= 2;
|
|
||||||
|
|
||||||
uint32_t *out0 = output;
|
|
||||||
uint32_t *out1 = output + outpitch;
|
|
||||||
|
|
||||||
for(unsigned y = 0; y < height; y++) {
|
|
||||||
unsigned linewidth = line[y];
|
|
||||||
|
|
||||||
if(linewidth == 256) {
|
|
||||||
int prevline = (y == 0) || (linewidth != line[y - 1]) ? 0 : pitch;
|
|
||||||
int nextline = (y == height - 1) || (linewidth != line[y + 1]) ? 0 : pitch;
|
|
||||||
|
|
||||||
for(unsigned x = 0; x < 256; x++) {
|
|
||||||
uint16_t A = *(input - prevline);
|
|
||||||
uint16_t B = (x > 0) ? *(input - 1) : *input;
|
|
||||||
uint16_t C = *input;
|
|
||||||
uint16_t D = (x < 255) ? *(input + 1) : *input;
|
|
||||||
uint16_t E = *(input++ + nextline);
|
|
||||||
uint32_t c = colortable[C];
|
|
||||||
|
|
||||||
if(A != E && B != D) {
|
|
||||||
*out0++ = (A == B ? colortable[C + A - ((C ^ A) & 0x0421) >> 1] : c);
|
|
||||||
*out0++ = (A == D ? colortable[C + A - ((C ^ A) & 0x0421) >> 1] : c);
|
|
||||||
*out1++ = (E == B ? colortable[C + E - ((C ^ E) & 0x0421) >> 1] : c);
|
|
||||||
*out1++ = (E == D ? colortable[C + E - ((C ^ E) & 0x0421) >> 1] : c);
|
|
||||||
} else {
|
|
||||||
*out0++ = c;
|
|
||||||
*out0++ = c;
|
|
||||||
*out1++ = c;
|
|
||||||
*out1++ = c;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
for(unsigned x = 0; x < 512; x++) {
|
|
||||||
*out0++ = *out1++ = colortable[*input++];
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
input += pitch - linewidth;
|
|
||||||
out0 += outpitch + outpitch - 512;
|
|
||||||
out1 += outpitch + outpitch - 512;
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,5 +0,0 @@
|
||||||
class LQ2xFilter {
|
|
||||||
public:
|
|
||||||
void size(unsigned&, unsigned&, unsigned, unsigned);
|
|
||||||
void render(uint32_t*, unsigned, const uint16_t*, unsigned, const unsigned*, unsigned, unsigned);
|
|
||||||
} filter_lq2x;
|
|
|
@ -1,107 +0,0 @@
|
||||||
# Makefile
|
|
||||||
# author: byuu
|
|
||||||
# license: public domain
|
|
||||||
|
|
||||||
[A-Z] = A B C D E F G H I J K L M N O P Q R S T U V W X Y Z
|
|
||||||
[a-z] = a b c d e f g h i j k l m n o p q r s t u v w x y z
|
|
||||||
[0-9] = 0 1 2 3 4 5 6 7 8 9
|
|
||||||
[markup] = ` ~ ! @ \# $$ % ^ & * ( ) - _ = + [ { ] } \ | ; : ' " , < . > / ?
|
|
||||||
[all] = $([A-Z]) $([a-z]) $([0-9]) $([markup])
|
|
||||||
[space] :=
|
|
||||||
[space] +=
|
|
||||||
|
|
||||||
#####
|
|
||||||
# platform detection
|
|
||||||
#####
|
|
||||||
|
|
||||||
ifeq ($(platform),)
|
|
||||||
uname := $(shell uname -a)
|
|
||||||
ifeq ($(uname),)
|
|
||||||
platform := win
|
|
||||||
delete = del $(subst /,\,$1)
|
|
||||||
else ifneq ($(findstring Darwin,$(uname)),)
|
|
||||||
platform := osx
|
|
||||||
delete = rm -f $1
|
|
||||||
else
|
|
||||||
platform := x
|
|
||||||
delete = rm -f $1
|
|
||||||
endif
|
|
||||||
endif
|
|
||||||
|
|
||||||
ifeq ($(compiler),)
|
|
||||||
ifeq ($(platform),osx)
|
|
||||||
compiler := gcc-4.2
|
|
||||||
else
|
|
||||||
compiler := gcc
|
|
||||||
endif
|
|
||||||
endif
|
|
||||||
|
|
||||||
ifeq ($(prefix),)
|
|
||||||
prefix := /usr/local
|
|
||||||
endif
|
|
||||||
|
|
||||||
#####
|
|
||||||
# function rwildcard(directory, pattern)
|
|
||||||
#####
|
|
||||||
rwildcard = \
|
|
||||||
$(strip \
|
|
||||||
$(filter $(if $2,$2,%), \
|
|
||||||
$(foreach f, \
|
|
||||||
$(wildcard $1*), \
|
|
||||||
$(eval t = $(call rwildcard,$f/)) \
|
|
||||||
$(if $t,$t,$f) \
|
|
||||||
) \
|
|
||||||
) \
|
|
||||||
)
|
|
||||||
|
|
||||||
#####
|
|
||||||
# function strtr(source, from, to)
|
|
||||||
#####
|
|
||||||
strtr = \
|
|
||||||
$(eval __temp := $1) \
|
|
||||||
$(strip \
|
|
||||||
$(foreach c, \
|
|
||||||
$(join $(addsuffix :,$2),$3), \
|
|
||||||
$(eval __temp := \
|
|
||||||
$(subst $(word 1,$(subst :, ,$c)),$(word 2,$(subst :, ,$c)),$(__temp)) \
|
|
||||||
) \
|
|
||||||
) \
|
|
||||||
$(__temp) \
|
|
||||||
)
|
|
||||||
|
|
||||||
#####
|
|
||||||
# function strupper(source)
|
|
||||||
#####
|
|
||||||
strupper = $(call strtr,$1,$([a-z]),$([A-Z]))
|
|
||||||
|
|
||||||
#####
|
|
||||||
# function strlower(source)
|
|
||||||
#####
|
|
||||||
strlower = $(call strtr,$1,$([A-Z]),$([a-z]))
|
|
||||||
|
|
||||||
#####
|
|
||||||
# function strlen(source)
|
|
||||||
#####
|
|
||||||
strlen = \
|
|
||||||
$(eval __temp := $(subst $([space]),_,$1)) \
|
|
||||||
$(words \
|
|
||||||
$(strip \
|
|
||||||
$(foreach c, \
|
|
||||||
$([all]), \
|
|
||||||
$(eval __temp := \
|
|
||||||
$(subst $c,$c ,$(__temp)) \
|
|
||||||
) \
|
|
||||||
) \
|
|
||||||
$(__temp) \
|
|
||||||
) \
|
|
||||||
)
|
|
||||||
|
|
||||||
#####
|
|
||||||
# function streq(source)
|
|
||||||
#####
|
|
||||||
streq = $(if $(filter-out xx,x$(subst $1,,$2)$(subst $2,,$1)x),,1)
|
|
||||||
|
|
||||||
#####
|
|
||||||
# function strne(source)
|
|
||||||
#####
|
|
||||||
strne = $(if $(filter-out xx,x$(subst $1,,$2)$(subst $2,,$1)x),1,)
|
|
|
@ -1,23 +0,0 @@
|
||||||
#ifndef NALL_ALGORITHM_HPP
|
|
||||||
#define NALL_ALGORITHM_HPP
|
|
||||||
|
|
||||||
#undef min
|
|
||||||
#undef max
|
|
||||||
|
|
||||||
namespace nall {
|
|
||||||
template<typename T, typename U> T min(const T &t, const U &u) {
|
|
||||||
return t < u ? t : u;
|
|
||||||
}
|
|
||||||
|
|
||||||
template<typename T, typename U> T max(const T &t, const U &u) {
|
|
||||||
return t > u ? t : u;
|
|
||||||
}
|
|
||||||
|
|
||||||
//pseudo-random number generator
|
|
||||||
inline unsigned prng() {
|
|
||||||
static unsigned n = 0;
|
|
||||||
return n = (n >> 1) ^ (((n & 1) - 1) & 0xedb88320);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#endif
|
|
|
@ -1,74 +0,0 @@
|
||||||
#ifndef NALL_ANY_HPP
|
|
||||||
#define NALL_ANY_HPP
|
|
||||||
|
|
||||||
#include <typeinfo>
|
|
||||||
#include <nall/static.hpp>
|
|
||||||
#include <nall/traits.hpp>
|
|
||||||
|
|
||||||
namespace nall {
|
|
||||||
class any {
|
|
||||||
public:
|
|
||||||
bool empty() const { return container; }
|
|
||||||
const std::type_info& type() const { return container ? container->type() : typeid(void); }
|
|
||||||
|
|
||||||
template<typename T> any& operator=(const T& value_) {
|
|
||||||
typedef typename static_if<
|
|
||||||
is_array<T>::value,
|
|
||||||
typename remove_extent<typename add_const<T>::type>::type*,
|
|
||||||
T
|
|
||||||
>::type auto_t;
|
|
||||||
|
|
||||||
if(type() == typeid(auto_t)) {
|
|
||||||
static_cast<holder<auto_t>*>(container)->value = (auto_t)value_;
|
|
||||||
} else {
|
|
||||||
if(container) delete container;
|
|
||||||
container = new holder<auto_t>((auto_t)value_);
|
|
||||||
}
|
|
||||||
|
|
||||||
return *this;
|
|
||||||
}
|
|
||||||
|
|
||||||
any() : container(0) {}
|
|
||||||
template<typename T> any(const T& value_) : container(0) { operator=(value_); }
|
|
||||||
|
|
||||||
private:
|
|
||||||
struct placeholder {
|
|
||||||
virtual const std::type_info& type() const = 0;
|
|
||||||
} *container;
|
|
||||||
|
|
||||||
template<typename T> struct holder : placeholder {
|
|
||||||
T value;
|
|
||||||
const std::type_info& type() const { return typeid(T); }
|
|
||||||
holder(const T& value_) : value(value_) {}
|
|
||||||
};
|
|
||||||
|
|
||||||
template<typename T> friend T any_cast(any&);
|
|
||||||
template<typename T> friend T any_cast(const any&);
|
|
||||||
template<typename T> friend T* any_cast(any*);
|
|
||||||
template<typename T> friend const T* any_cast(const any*);
|
|
||||||
};
|
|
||||||
|
|
||||||
template<typename T> T any_cast(any &value) {
|
|
||||||
typedef typename remove_reference<T>::type nonref;
|
|
||||||
if(value.type() != typeid(nonref)) throw;
|
|
||||||
return static_cast<any::holder<nonref>*>(value.container)->value;
|
|
||||||
}
|
|
||||||
|
|
||||||
template<typename T> T any_cast(const any &value) {
|
|
||||||
typedef const typename remove_reference<T>::type nonref;
|
|
||||||
if(value.type() != typeid(nonref)) throw;
|
|
||||||
return static_cast<any::holder<nonref>*>(value.container)->value;
|
|
||||||
}
|
|
||||||
|
|
||||||
template<typename T> T* any_cast(any *value) {
|
|
||||||
if(!value || value->type() != typeid(T)) return 0;
|
|
||||||
return &static_cast<any::holder<T>*>(value->container)->value;
|
|
||||||
}
|
|
||||||
|
|
||||||
template<typename T> const T* any_cast(const any *value) {
|
|
||||||
if(!value || value->type() != typeid(T)) return 0;
|
|
||||||
return &static_cast<any::holder<T>*>(value->container)->value;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#endif
|
|
|
@ -1,118 +0,0 @@
|
||||||
#ifndef NALL_ARRAY_HPP
|
|
||||||
#define NALL_ARRAY_HPP
|
|
||||||
|
|
||||||
#include <stdlib.h>
|
|
||||||
#include <initializer_list>
|
|
||||||
#include <nall/algorithm.hpp>
|
|
||||||
#include <nall/bit.hpp>
|
|
||||||
#include <nall/concept.hpp>
|
|
||||||
#include <nall/traits.hpp>
|
|
||||||
|
|
||||||
namespace nall {
|
|
||||||
//dynamic vector array
|
|
||||||
//neither constructor nor destructor is ever invoked;
|
|
||||||
//thus, this should only be used for POD objects.
|
|
||||||
template<typename T> class array {
|
|
||||||
protected:
|
|
||||||
T *pool;
|
|
||||||
unsigned poolsize, buffersize;
|
|
||||||
|
|
||||||
public:
|
|
||||||
unsigned size() const { return buffersize; }
|
|
||||||
unsigned capacity() const { return poolsize; }
|
|
||||||
|
|
||||||
void reset() {
|
|
||||||
if(pool) free(pool);
|
|
||||||
pool = 0;
|
|
||||||
poolsize = 0;
|
|
||||||
buffersize = 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
void reserve(unsigned newsize) {
|
|
||||||
if(newsize == poolsize) return;
|
|
||||||
|
|
||||||
pool = (T*)realloc(pool, newsize * sizeof(T));
|
|
||||||
poolsize = newsize;
|
|
||||||
buffersize = min(buffersize, newsize);
|
|
||||||
}
|
|
||||||
|
|
||||||
void resize(unsigned newsize) {
|
|
||||||
if(newsize > poolsize) reserve(bit::round(newsize)); //round reserve size up to power of 2
|
|
||||||
buffersize = newsize;
|
|
||||||
}
|
|
||||||
|
|
||||||
T* get(unsigned minsize = 0) {
|
|
||||||
if(minsize > buffersize) resize(minsize);
|
|
||||||
if(minsize > buffersize) throw "array[] out of bounds";
|
|
||||||
return pool;
|
|
||||||
}
|
|
||||||
|
|
||||||
void add(const T data) {
|
|
||||||
operator[](buffersize) = data;
|
|
||||||
}
|
|
||||||
|
|
||||||
signed find(const T data) {
|
|
||||||
for(unsigned i = 0; i < size(); i++) if(pool[i] == data) return i;
|
|
||||||
return -1; //not found
|
|
||||||
}
|
|
||||||
|
|
||||||
void clear() {
|
|
||||||
memset(pool, 0, buffersize * sizeof(T));
|
|
||||||
}
|
|
||||||
|
|
||||||
array() : pool(0), poolsize(0), buffersize(0) {
|
|
||||||
}
|
|
||||||
|
|
||||||
array(std::initializer_list<T> list) : pool(0), poolsize(0), buffersize(0) {
|
|
||||||
for(const T *p = list.begin(); p != list.end(); ++p) add(*p);
|
|
||||||
}
|
|
||||||
|
|
||||||
~array() {
|
|
||||||
reset();
|
|
||||||
}
|
|
||||||
|
|
||||||
//copy
|
|
||||||
array& operator=(const array &source) {
|
|
||||||
if(pool) free(pool);
|
|
||||||
buffersize = source.buffersize;
|
|
||||||
poolsize = source.poolsize;
|
|
||||||
pool = (T*)malloc(sizeof(T) * poolsize); //allocate entire pool size,
|
|
||||||
memcpy(pool, source.pool, sizeof(T) * buffersize); //... but only copy used pool objects
|
|
||||||
return *this;
|
|
||||||
}
|
|
||||||
|
|
||||||
array(const array &source) : pool(0) {
|
|
||||||
operator=(source);
|
|
||||||
}
|
|
||||||
|
|
||||||
//move
|
|
||||||
array& operator=(array &&source) {
|
|
||||||
if(pool) free(pool);
|
|
||||||
pool = source.pool;
|
|
||||||
poolsize = source.poolsize;
|
|
||||||
buffersize = source.buffersize;
|
|
||||||
source.pool = 0;
|
|
||||||
return *this;
|
|
||||||
}
|
|
||||||
|
|
||||||
array(array &&source) {
|
|
||||||
operator=(move(source));
|
|
||||||
}
|
|
||||||
|
|
||||||
//index
|
|
||||||
inline T& operator[](unsigned index) {
|
|
||||||
if(index >= buffersize) resize(index + 1);
|
|
||||||
if(index >= buffersize) throw "array[] out of bounds";
|
|
||||||
return pool[index];
|
|
||||||
}
|
|
||||||
|
|
||||||
inline const T& operator[](unsigned index) const {
|
|
||||||
if(index >= buffersize) throw "array[] out of bounds";
|
|
||||||
return pool[index];
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
template<typename T> struct has_size<array<T>> { enum { value = true }; };
|
|
||||||
}
|
|
||||||
|
|
||||||
#endif
|
|
|
@ -1,90 +0,0 @@
|
||||||
#ifndef NALL_BASE64_HPP
|
|
||||||
#define NALL_BASE64_HPP
|
|
||||||
|
|
||||||
#include <string.h>
|
|
||||||
#include <nall/stdint.hpp>
|
|
||||||
|
|
||||||
namespace nall {
|
|
||||||
class base64 {
|
|
||||||
public:
|
|
||||||
static bool encode(char *&output, const uint8_t* input, unsigned inlength) {
|
|
||||||
output = new char[inlength * 8 / 6 + 6]();
|
|
||||||
|
|
||||||
unsigned i = 0, o = 0;
|
|
||||||
while(i < inlength) {
|
|
||||||
switch(i % 3) {
|
|
||||||
case 0: {
|
|
||||||
output[o++] = enc(input[i] >> 2);
|
|
||||||
output[o] = enc((input[i] & 3) << 4);
|
|
||||||
} break;
|
|
||||||
|
|
||||||
case 1: {
|
|
||||||
uint8_t prev = dec(output[o]);
|
|
||||||
output[o++] = enc(prev + (input[i] >> 4));
|
|
||||||
output[o] = enc((input[i] & 15) << 2);
|
|
||||||
} break;
|
|
||||||
|
|
||||||
case 2: {
|
|
||||||
uint8_t prev = dec(output[o]);
|
|
||||||
output[o++] = enc(prev + (input[i] >> 6));
|
|
||||||
output[o++] = enc(input[i] & 63);
|
|
||||||
} break;
|
|
||||||
}
|
|
||||||
|
|
||||||
i++;
|
|
||||||
}
|
|
||||||
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
static bool decode(uint8_t *&output, unsigned &outlength, const char *input) {
|
|
||||||
unsigned inlength = strlen(input), infix = 0;
|
|
||||||
output = new uint8_t[inlength]();
|
|
||||||
|
|
||||||
unsigned i = 0, o = 0;
|
|
||||||
while(i < inlength) {
|
|
||||||
uint8_t x = dec(input[i]);
|
|
||||||
|
|
||||||
switch(i++ & 3) {
|
|
||||||
case 0: {
|
|
||||||
output[o] = x << 2;
|
|
||||||
} break;
|
|
||||||
|
|
||||||
case 1: {
|
|
||||||
output[o++] |= x >> 4;
|
|
||||||
output[o] = (x & 15) << 4;
|
|
||||||
} break;
|
|
||||||
|
|
||||||
case 2: {
|
|
||||||
output[o++] |= x >> 2;
|
|
||||||
output[o] = (x & 3) << 6;
|
|
||||||
} break;
|
|
||||||
|
|
||||||
case 3: {
|
|
||||||
output[o++] |= x;
|
|
||||||
} break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
outlength = o;
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
private:
|
|
||||||
static char enc(uint8_t n) {
|
|
||||||
static char lookup_table[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-_";
|
|
||||||
return lookup_table[n & 63];
|
|
||||||
}
|
|
||||||
|
|
||||||
static uint8_t dec(char n) {
|
|
||||||
if(n >= 'A' && n <= 'Z') return n - 'A';
|
|
||||||
if(n >= 'a' && n <= 'z') return n - 'a' + 26;
|
|
||||||
if(n >= '0' && n <= '9') return n - '0' + 52;
|
|
||||||
if(n == '-') return 62;
|
|
||||||
if(n == '_') return 63;
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
#endif
|
|
|
@ -1,51 +0,0 @@
|
||||||
#ifndef NALL_BIT_HPP
|
|
||||||
#define NALL_BIT_HPP
|
|
||||||
|
|
||||||
namespace nall {
|
|
||||||
template<int bits> inline unsigned uclamp(const unsigned x) {
|
|
||||||
enum { y = (1U << bits) - 1 };
|
|
||||||
return y + ((x - y) & -(x < y)); //min(x, y);
|
|
||||||
}
|
|
||||||
|
|
||||||
template<int bits> inline unsigned uclip(const unsigned x) {
|
|
||||||
enum { m = (1U << bits) - 1 };
|
|
||||||
return (x & m);
|
|
||||||
}
|
|
||||||
|
|
||||||
template<int bits> inline signed sclamp(const signed x) {
|
|
||||||
enum { b = 1U << (bits - 1), m = (1U << (bits - 1)) - 1 };
|
|
||||||
return (x > m) ? m : (x < -b) ? -b : x;
|
|
||||||
}
|
|
||||||
|
|
||||||
template<int bits> inline signed sclip(const signed x) {
|
|
||||||
enum { b = 1U << (bits - 1), m = (1U << bits) - 1 };
|
|
||||||
return ((x & m) ^ b) - b;
|
|
||||||
}
|
|
||||||
|
|
||||||
namespace bit {
|
|
||||||
//lowest(0b1110) == 0b0010
|
|
||||||
template<typename T> inline T lowest(const T x) {
|
|
||||||
return x & -x;
|
|
||||||
}
|
|
||||||
|
|
||||||
//clear_lowest(0b1110) == 0b1100
|
|
||||||
template<typename T> inline T clear_lowest(const T x) {
|
|
||||||
return x & (x - 1);
|
|
||||||
}
|
|
||||||
|
|
||||||
//set_lowest(0b0101) == 0b0111
|
|
||||||
template<typename T> inline T set_lowest(const T x) {
|
|
||||||
return x | (x + 1);
|
|
||||||
}
|
|
||||||
|
|
||||||
//round up to next highest single bit:
|
|
||||||
//round(15) == 16, round(16) == 16, round(17) == 32
|
|
||||||
inline unsigned round(unsigned x) {
|
|
||||||
if((x & (x - 1)) == 0) return x;
|
|
||||||
while(x & (x - 1)) x &= x - 1;
|
|
||||||
return x << 1;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#endif
|
|
|
@ -1,15 +0,0 @@
|
||||||
#ifndef NALL_CONCEPT_HPP
|
|
||||||
#define NALL_CONCEPT_HPP
|
|
||||||
|
|
||||||
namespace nall {
|
|
||||||
//unsigned count() const;
|
|
||||||
template<typename T> struct has_count { enum { value = false }; };
|
|
||||||
|
|
||||||
//unsigned length() const;
|
|
||||||
template<typename T> struct has_length { enum { value = false }; };
|
|
||||||
|
|
||||||
//unsigned size() const;
|
|
||||||
template<typename T> struct has_size { enum { value = false }; };
|
|
||||||
}
|
|
||||||
|
|
||||||
#endif
|
|
|
@ -1,124 +0,0 @@
|
||||||
#ifndef NALL_CONFIG_HPP
|
|
||||||
#define NALL_CONFIG_HPP
|
|
||||||
|
|
||||||
#include <nall/file.hpp>
|
|
||||||
#include <nall/string.hpp>
|
|
||||||
#include <nall/vector.hpp>
|
|
||||||
|
|
||||||
namespace nall {
|
|
||||||
namespace configuration_traits {
|
|
||||||
template<typename T> struct is_boolean { enum { value = false }; };
|
|
||||||
template<> struct is_boolean<bool> { enum { value = true }; };
|
|
||||||
|
|
||||||
template<typename T> struct is_signed { enum { value = false }; };
|
|
||||||
template<> struct is_signed<signed> { enum { value = true }; };
|
|
||||||
|
|
||||||
template<typename T> struct is_unsigned { enum { value = false }; };
|
|
||||||
template<> struct is_unsigned<unsigned> { enum { value = true }; };
|
|
||||||
|
|
||||||
template<typename T> struct is_double { enum { value = false }; };
|
|
||||||
template<> struct is_double<double> { enum { value = true }; };
|
|
||||||
|
|
||||||
template<typename T> struct is_string { enum { value = false }; };
|
|
||||||
template<> struct is_string<string> { enum { value = true }; };
|
|
||||||
}
|
|
||||||
|
|
||||||
class configuration {
|
|
||||||
public:
|
|
||||||
enum type_t { boolean_t, signed_t, unsigned_t, double_t, string_t, unknown_t };
|
|
||||||
struct item_t {
|
|
||||||
uintptr_t data;
|
|
||||||
string name;
|
|
||||||
string desc;
|
|
||||||
type_t type;
|
|
||||||
|
|
||||||
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 << "\"";
|
|
||||||
}
|
|
||||||
return "???";
|
|
||||||
}
|
|
||||||
|
|
||||||
void set(string s) {
|
|
||||||
switch(type) {
|
|
||||||
case boolean_t: *(bool*)data = (s == "true"); break;
|
|
||||||
case signed_t: *(signed*)data = strsigned(s); break;
|
|
||||||
case unsigned_t: *(unsigned*)data = strunsigned(s); break;
|
|
||||||
case double_t: *(double*)data = strdouble(s); break;
|
|
||||||
case string_t: trim(s, "\""); *(string*)data = s; break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
};
|
|
||||||
linear_vector<item_t> list;
|
|
||||||
|
|
||||||
template<typename T>
|
|
||||||
void attach(T &data, const char *name, const char *desc = "") {
|
|
||||||
unsigned n = list.size();
|
|
||||||
list[n].data = (uintptr_t)&data;
|
|
||||||
list[n].name = name;
|
|
||||||
list[n].desc = desc;
|
|
||||||
|
|
||||||
if(configuration_traits::is_boolean<T>::value) list[n].type = boolean_t;
|
|
||||||
else if(configuration_traits::is_signed<T>::value) list[n].type = signed_t;
|
|
||||||
else if(configuration_traits::is_unsigned<T>::value) list[n].type = unsigned_t;
|
|
||||||
else if(configuration_traits::is_double<T>::value) list[n].type = double_t;
|
|
||||||
else if(configuration_traits::is_string<T>::value) list[n].type = string_t;
|
|
||||||
else list[n].type = unknown_t;
|
|
||||||
}
|
|
||||||
|
|
||||||
virtual bool load(const char *filename) {
|
|
||||||
string data;
|
|
||||||
if(data.readfile(filename) == true) {
|
|
||||||
data.replace("\r", "");
|
|
||||||
lstring line;
|
|
||||||
line.split("\n", data);
|
|
||||||
|
|
||||||
for(unsigned i = 0; i < line.size(); i++) {
|
|
||||||
int position = qstrpos(line[i], "#");
|
|
||||||
if(position >= 0) line[i][position] = 0;
|
|
||||||
if(qstrpos(line[i], " = ") < 0) continue;
|
|
||||||
|
|
||||||
lstring part;
|
|
||||||
part.qsplit(" = ", line[i]);
|
|
||||||
trim(part[0]);
|
|
||||||
trim(part[1]);
|
|
||||||
|
|
||||||
for(unsigned n = 0; n < list.size(); n++) {
|
|
||||||
if(part[0] == list[n].name) {
|
|
||||||
list[n].set(part[1]);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return true;
|
|
||||||
} else {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
virtual bool save(const char *filename) const {
|
|
||||||
file fp;
|
|
||||||
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";
|
|
||||||
fp.print(output);
|
|
||||||
}
|
|
||||||
|
|
||||||
fp.close();
|
|
||||||
return true;
|
|
||||||
} else {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
#endif
|
|
|
@ -1,66 +0,0 @@
|
||||||
#ifndef NALL_CRC32_HPP
|
|
||||||
#define NALL_CRC32_HPP
|
|
||||||
|
|
||||||
#include <nall/stdint.hpp>
|
|
||||||
|
|
||||||
namespace nall {
|
|
||||||
const uint32_t crc32_table[256] = {
|
|
||||||
0x00000000, 0x77073096, 0xee0e612c, 0x990951ba, 0x076dc419, 0x706af48f,
|
|
||||||
0xe963a535, 0x9e6495a3, 0x0edb8832, 0x79dcb8a4, 0xe0d5e91e, 0x97d2d988,
|
|
||||||
0x09b64c2b, 0x7eb17cbd, 0xe7b82d07, 0x90bf1d91, 0x1db71064, 0x6ab020f2,
|
|
||||||
0xf3b97148, 0x84be41de, 0x1adad47d, 0x6ddde4eb, 0xf4d4b551, 0x83d385c7,
|
|
||||||
0x136c9856, 0x646ba8c0, 0xfd62f97a, 0x8a65c9ec, 0x14015c4f, 0x63066cd9,
|
|
||||||
0xfa0f3d63, 0x8d080df5, 0x3b6e20c8, 0x4c69105e, 0xd56041e4, 0xa2677172,
|
|
||||||
0x3c03e4d1, 0x4b04d447, 0xd20d85fd, 0xa50ab56b, 0x35b5a8fa, 0x42b2986c,
|
|
||||||
0xdbbbc9d6, 0xacbcf940, 0x32d86ce3, 0x45df5c75, 0xdcd60dcf, 0xabd13d59,
|
|
||||||
0x26d930ac, 0x51de003a, 0xc8d75180, 0xbfd06116, 0x21b4f4b5, 0x56b3c423,
|
|
||||||
0xcfba9599, 0xb8bda50f, 0x2802b89e, 0x5f058808, 0xc60cd9b2, 0xb10be924,
|
|
||||||
0x2f6f7c87, 0x58684c11, 0xc1611dab, 0xb6662d3d, 0x76dc4190, 0x01db7106,
|
|
||||||
0x98d220bc, 0xefd5102a, 0x71b18589, 0x06b6b51f, 0x9fbfe4a5, 0xe8b8d433,
|
|
||||||
0x7807c9a2, 0x0f00f934, 0x9609a88e, 0xe10e9818, 0x7f6a0dbb, 0x086d3d2d,
|
|
||||||
0x91646c97, 0xe6635c01, 0x6b6b51f4, 0x1c6c6162, 0x856530d8, 0xf262004e,
|
|
||||||
0x6c0695ed, 0x1b01a57b, 0x8208f4c1, 0xf50fc457, 0x65b0d9c6, 0x12b7e950,
|
|
||||||
0x8bbeb8ea, 0xfcb9887c, 0x62dd1ddf, 0x15da2d49, 0x8cd37cf3, 0xfbd44c65,
|
|
||||||
0x4db26158, 0x3ab551ce, 0xa3bc0074, 0xd4bb30e2, 0x4adfa541, 0x3dd895d7,
|
|
||||||
0xa4d1c46d, 0xd3d6f4fb, 0x4369e96a, 0x346ed9fc, 0xad678846, 0xda60b8d0,
|
|
||||||
0x44042d73, 0x33031de5, 0xaa0a4c5f, 0xdd0d7cc9, 0x5005713c, 0x270241aa,
|
|
||||||
0xbe0b1010, 0xc90c2086, 0x5768b525, 0x206f85b3, 0xb966d409, 0xce61e49f,
|
|
||||||
0x5edef90e, 0x29d9c998, 0xb0d09822, 0xc7d7a8b4, 0x59b33d17, 0x2eb40d81,
|
|
||||||
0xb7bd5c3b, 0xc0ba6cad, 0xedb88320, 0x9abfb3b6, 0x03b6e20c, 0x74b1d29a,
|
|
||||||
0xead54739, 0x9dd277af, 0x04db2615, 0x73dc1683, 0xe3630b12, 0x94643b84,
|
|
||||||
0x0d6d6a3e, 0x7a6a5aa8, 0xe40ecf0b, 0x9309ff9d, 0x0a00ae27, 0x7d079eb1,
|
|
||||||
0xf00f9344, 0x8708a3d2, 0x1e01f268, 0x6906c2fe, 0xf762575d, 0x806567cb,
|
|
||||||
0x196c3671, 0x6e6b06e7, 0xfed41b76, 0x89d32be0, 0x10da7a5a, 0x67dd4acc,
|
|
||||||
0xf9b9df6f, 0x8ebeeff9, 0x17b7be43, 0x60b08ed5, 0xd6d6a3e8, 0xa1d1937e,
|
|
||||||
0x38d8c2c4, 0x4fdff252, 0xd1bb67f1, 0xa6bc5767, 0x3fb506dd, 0x48b2364b,
|
|
||||||
0xd80d2bda, 0xaf0a1b4c, 0x36034af6, 0x41047a60, 0xdf60efc3, 0xa867df55,
|
|
||||||
0x316e8eef, 0x4669be79, 0xcb61b38c, 0xbc66831a, 0x256fd2a0, 0x5268e236,
|
|
||||||
0xcc0c7795, 0xbb0b4703, 0x220216b9, 0x5505262f, 0xc5ba3bbe, 0xb2bd0b28,
|
|
||||||
0x2bb45a92, 0x5cb36a04, 0xc2d7ffa7, 0xb5d0cf31, 0x2cd99e8b, 0x5bdeae1d,
|
|
||||||
0x9b64c2b0, 0xec63f226, 0x756aa39c, 0x026d930a, 0x9c0906a9, 0xeb0e363f,
|
|
||||||
0x72076785, 0x05005713, 0x95bf4a82, 0xe2b87a14, 0x7bb12bae, 0x0cb61b38,
|
|
||||||
0x92d28e9b, 0xe5d5be0d, 0x7cdcefb7, 0x0bdbdf21, 0x86d3d2d4, 0xf1d4e242,
|
|
||||||
0x68ddb3f8, 0x1fda836e, 0x81be16cd, 0xf6b9265b, 0x6fb077e1, 0x18b74777,
|
|
||||||
0x88085ae6, 0xff0f6a70, 0x66063bca, 0x11010b5c, 0x8f659eff, 0xf862ae69,
|
|
||||||
0x616bffd3, 0x166ccf45, 0xa00ae278, 0xd70dd2ee, 0x4e048354, 0x3903b3c2,
|
|
||||||
0xa7672661, 0xd06016f7, 0x4969474d, 0x3e6e77db, 0xaed16a4a, 0xd9d65adc,
|
|
||||||
0x40df0b66, 0x37d83bf0, 0xa9bcae53, 0xdebb9ec5, 0x47b2cf7f, 0x30b5ffe9,
|
|
||||||
0xbdbdf21c, 0xcabac28a, 0x53b39330, 0x24b4a3a6, 0xbad03605, 0xcdd70693,
|
|
||||||
0x54de5729, 0x23d967bf, 0xb3667a2e, 0xc4614ab8, 0x5d681b02, 0x2a6f2b94,
|
|
||||||
0xb40bbe37, 0xc30c8ea1, 0x5a05df1b, 0x2d02ef8d
|
|
||||||
};
|
|
||||||
|
|
||||||
inline uint32_t crc32_adjust(uint32_t crc32, uint8_t input) {
|
|
||||||
return ((crc32 >> 8) & 0x00ffffff) ^ crc32_table[(crc32 ^ input) & 0xff];
|
|
||||||
}
|
|
||||||
|
|
||||||
inline uint32_t crc32_calculate(const uint8_t *data, unsigned length) {
|
|
||||||
uint32_t crc32 = ~0;
|
|
||||||
for(unsigned i = 0; i < length; i++) {
|
|
||||||
crc32 = crc32_adjust(crc32, data[i]);
|
|
||||||
}
|
|
||||||
return ~crc32;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#endif
|
|
|
@ -1,30 +0,0 @@
|
||||||
#ifndef NALL_DETECT_HPP
|
|
||||||
#define NALL_DETECT_HPP
|
|
||||||
|
|
||||||
/* Compiler detection */
|
|
||||||
|
|
||||||
#if defined(__GNUC__)
|
|
||||||
#define COMPILER_GCC
|
|
||||||
#elif defined(_MSC_VER)
|
|
||||||
#define COMPILER_VISUALC
|
|
||||||
#endif
|
|
||||||
|
|
||||||
/* Platform detection */
|
|
||||||
|
|
||||||
#if defined(_WIN32)
|
|
||||||
#define PLATFORM_WIN
|
|
||||||
#elif defined(__APPLE__)
|
|
||||||
#define PLATFORM_OSX
|
|
||||||
#elif defined(linux) || defined(__sun__) || defined(__FreeBSD__) || defined(__NetBSD__) || defined(__OpenBSD__)
|
|
||||||
#define PLATFORM_X
|
|
||||||
#endif
|
|
||||||
|
|
||||||
/* Endian detection */
|
|
||||||
|
|
||||||
#if defined(__i386__) || defined(__amd64__) || defined(_M_IX86) || defined(_M_AMD64)
|
|
||||||
#define ARCH_LSB
|
|
||||||
#elif defined(__powerpc__) || defined(_M_PPC) || defined(__BIG_ENDIAN__)
|
|
||||||
#define ARCH_MSB
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#endif
|
|
|
@ -1,76 +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, "{{")) {
|
|
||||||
int pos = strpos(input, "}}");
|
|
||||||
if(pos >= 0) {
|
|
||||||
string temp = substr(input, pos + 2);
|
|
||||||
return temp;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return input;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool import(const char *filename) {
|
|
||||||
string data;
|
|
||||||
if(data.readfile(filename) == false) return false;
|
|
||||||
ltrim_once(data, "\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
|
|
||||||
trim(part[0]);
|
|
||||||
trim(part[1]);
|
|
||||||
|
|
||||||
//remove quotes
|
|
||||||
trim_once(part[0], "\"");
|
|
||||||
trim_once(part[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
|
|
|
@ -1,119 +0,0 @@
|
||||||
#ifndef NALL_DL_HPP
|
|
||||||
#define NALL_DL_HPP
|
|
||||||
|
|
||||||
//dynamic linking support
|
|
||||||
|
|
||||||
#include <string.h>
|
|
||||||
#include <nall/detect.hpp>
|
|
||||||
#include <nall/stdint.hpp>
|
|
||||||
#include <nall/utility.hpp>
|
|
||||||
|
|
||||||
#if defined(PLATFORM_X) || defined(PLATFORM_OSX)
|
|
||||||
#include <dlfcn.h>
|
|
||||||
#elif defined(PLATFORM_WIN)
|
|
||||||
#include <windows.h>
|
|
||||||
#include <nall/utf8.hpp>
|
|
||||||
#endif
|
|
||||||
|
|
||||||
namespace nall {
|
|
||||||
struct library {
|
|
||||||
bool opened() const { return handle; }
|
|
||||||
bool open(const char*);
|
|
||||||
void* sym(const char*);
|
|
||||||
void close();
|
|
||||||
|
|
||||||
library() : handle(0) {}
|
|
||||||
~library() { close(); }
|
|
||||||
|
|
||||||
library& operator=(const library&) = delete;
|
|
||||||
library(const library&) = delete;
|
|
||||||
|
|
||||||
private:
|
|
||||||
uintptr_t handle;
|
|
||||||
};
|
|
||||||
|
|
||||||
#if defined(PLATFORM_X)
|
|
||||||
inline bool library::open(const char *name) {
|
|
||||||
if(handle) close();
|
|
||||||
char *t = new char[strlen(name) + 256];
|
|
||||||
strcpy(t, "lib");
|
|
||||||
strcat(t, name);
|
|
||||||
strcat(t, ".so");
|
|
||||||
handle = (uintptr_t)dlopen(t, RTLD_LAZY);
|
|
||||||
if(!handle) {
|
|
||||||
strcpy(t, "/usr/local/lib/lib");
|
|
||||||
strcat(t, name);
|
|
||||||
strcat(t, ".so");
|
|
||||||
handle = (uintptr_t)dlopen(t, RTLD_LAZY);
|
|
||||||
}
|
|
||||||
delete[] t;
|
|
||||||
return handle;
|
|
||||||
}
|
|
||||||
|
|
||||||
inline void* library::sym(const char *name) {
|
|
||||||
if(!handle) return 0;
|
|
||||||
return dlsym((void*)handle, name);
|
|
||||||
}
|
|
||||||
|
|
||||||
inline void library::close() {
|
|
||||||
if(!handle) return;
|
|
||||||
dlclose((void*)handle);
|
|
||||||
handle = 0;
|
|
||||||
}
|
|
||||||
#elif defined(PLATFORM_OSX)
|
|
||||||
inline bool library::open(const char *name) {
|
|
||||||
if(handle) close();
|
|
||||||
char *t = new char[strlen(name) + 256];
|
|
||||||
strcpy(t, "lib");
|
|
||||||
strcat(t, name);
|
|
||||||
strcat(t, ".dylib");
|
|
||||||
handle = (uintptr_t)dlopen(t, RTLD_LAZY);
|
|
||||||
if(!handle) {
|
|
||||||
strcpy(t, "/usr/local/lib/lib");
|
|
||||||
strcat(t, name);
|
|
||||||
strcat(t, ".dylib");
|
|
||||||
handle = (uintptr_t)dlopen(t, RTLD_LAZY);
|
|
||||||
}
|
|
||||||
delete[] t;
|
|
||||||
return handle;
|
|
||||||
}
|
|
||||||
|
|
||||||
inline void* library::sym(const char *name) {
|
|
||||||
if(!handle) return 0;
|
|
||||||
return dlsym((void*)handle, name);
|
|
||||||
}
|
|
||||||
|
|
||||||
inline void library::close() {
|
|
||||||
if(!handle) return;
|
|
||||||
dlclose((void*)handle);
|
|
||||||
handle = 0;
|
|
||||||
}
|
|
||||||
#elif defined(PLATFORM_WIN)
|
|
||||||
inline bool library::open(const char *name) {
|
|
||||||
if(handle) close();
|
|
||||||
char *t = new char[strlen(name) + 8];
|
|
||||||
strcpy(t, name);
|
|
||||||
strcat(t, ".dll");
|
|
||||||
handle = (uintptr_t)LoadLibraryW(utf16_t(t));
|
|
||||||
delete[] t;
|
|
||||||
return handle;
|
|
||||||
}
|
|
||||||
|
|
||||||
inline void* library::sym(const char *name) {
|
|
||||||
if(!handle) return 0;
|
|
||||||
return (void*)GetProcAddress((HMODULE)handle, name);
|
|
||||||
}
|
|
||||||
|
|
||||||
inline void library::close() {
|
|
||||||
if(!handle) return;
|
|
||||||
FreeLibrary((HMODULE)handle);
|
|
||||||
handle = 0;
|
|
||||||
}
|
|
||||||
#else
|
|
||||||
inline bool library::open(const char*) { return false; }
|
|
||||||
inline void* library::sym(const char*) { return 0; }
|
|
||||||
inline void library::close() {}
|
|
||||||
#endif
|
|
||||||
};
|
|
||||||
|
|
||||||
#endif
|
|
|
@ -1,38 +0,0 @@
|
||||||
#ifndef NALL_ENDIAN_HPP
|
|
||||||
#define NALL_ENDIAN_HPP
|
|
||||||
|
|
||||||
#if !defined(ARCH_MSB)
|
|
||||||
//little-endian: uint8_t[] { 0x01, 0x02, 0x03, 0x04 } == 0x04030201
|
|
||||||
#define order_lsb2(a,b) a,b
|
|
||||||
#define order_lsb3(a,b,c) a,b,c
|
|
||||||
#define order_lsb4(a,b,c,d) a,b,c,d
|
|
||||||
#define order_lsb5(a,b,c,d,e) a,b,c,d,e
|
|
||||||
#define order_lsb6(a,b,c,d,e,f) a,b,c,d,e,f
|
|
||||||
#define order_lsb7(a,b,c,d,e,f,g) a,b,c,d,e,f,g
|
|
||||||
#define order_lsb8(a,b,c,d,e,f,g,h) a,b,c,d,e,f,g,h
|
|
||||||
#define order_msb2(a,b) b,a
|
|
||||||
#define order_msb3(a,b,c) c,b,a
|
|
||||||
#define order_msb4(a,b,c,d) d,c,b,a
|
|
||||||
#define order_msb5(a,b,c,d,e) e,d,c,b,a
|
|
||||||
#define order_msb6(a,b,c,d,e,f) f,e,d,c,b,a
|
|
||||||
#define order_msb7(a,b,c,d,e,f,g) g,f,e,d,c,b,a
|
|
||||||
#define order_msb8(a,b,c,d,e,f,g,h) h,g,f,e,d,c,b,a
|
|
||||||
#else
|
|
||||||
//big-endian: uint8_t[] { 0x01, 0x02, 0x03, 0x04 } == 0x01020304
|
|
||||||
#define order_lsb2(a,b) b,a
|
|
||||||
#define order_lsb3(a,b,c) c,b,a
|
|
||||||
#define order_lsb4(a,b,c,d) d,c,b,a
|
|
||||||
#define order_lsb5(a,b,c,d,e) e,d,c,b,a
|
|
||||||
#define order_lsb6(a,b,c,d,e,f) f,e,d,c,b,a
|
|
||||||
#define order_lsb7(a,b,c,d,e,f,g) g,f,e,d,c,b,a
|
|
||||||
#define order_lsb8(a,b,c,d,e,f,g,h) h,g,f,e,d,c,b,a
|
|
||||||
#define order_msb2(a,b) a,b
|
|
||||||
#define order_msb3(a,b,c) a,b,c
|
|
||||||
#define order_msb4(a,b,c,d) a,b,c,d
|
|
||||||
#define order_msb5(a,b,c,d,e) a,b,c,d,e
|
|
||||||
#define order_msb6(a,b,c,d,e,f) a,b,c,d,e,f
|
|
||||||
#define order_msb7(a,b,c,d,e,f,g) a,b,c,d,e,f,g
|
|
||||||
#define order_msb8(a,b,c,d,e,f,g,h) a,b,c,d,e,f,g,h
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#endif
|
|
|
@ -1,259 +0,0 @@
|
||||||
#ifndef NALL_FILE_HPP
|
|
||||||
#define NALL_FILE_HPP
|
|
||||||
|
|
||||||
#include <stdio.h>
|
|
||||||
#include <string.h>
|
|
||||||
|
|
||||||
#if !defined(_WIN32)
|
|
||||||
#include <unistd.h>
|
|
||||||
#else
|
|
||||||
#include <io.h>
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#include <nall/stdint.hpp>
|
|
||||||
#include <nall/utf8.hpp>
|
|
||||||
#include <nall/utility.hpp>
|
|
||||||
|
|
||||||
namespace nall {
|
|
||||||
inline FILE* fopen_utf8(const char *utf8_filename, const char *mode) {
|
|
||||||
#if !defined(_WIN32)
|
|
||||||
return fopen(utf8_filename, mode);
|
|
||||||
#else
|
|
||||||
return _wfopen(utf16_t(utf8_filename), utf16_t(mode));
|
|
||||||
#endif
|
|
||||||
}
|
|
||||||
|
|
||||||
class file {
|
|
||||||
public:
|
|
||||||
enum FileMode { mode_read, mode_write, mode_readwrite, mode_writeread };
|
|
||||||
enum SeekMode { seek_absolute, seek_relative };
|
|
||||||
|
|
||||||
uint8_t read() {
|
|
||||||
if(!fp) return 0xff; //file not open
|
|
||||||
if(file_mode == mode_write) return 0xff; //reads not permitted
|
|
||||||
if(file_offset >= file_size) return 0xff; //cannot read past end of file
|
|
||||||
buffer_sync();
|
|
||||||
return buffer[(file_offset++) & buffer_mask];
|
|
||||||
}
|
|
||||||
|
|
||||||
uintmax_t readl(unsigned length = 1) {
|
|
||||||
uintmax_t data = 0;
|
|
||||||
for(int i = 0; i < length; i++) {
|
|
||||||
data |= (uintmax_t)read() << (i << 3);
|
|
||||||
}
|
|
||||||
return data;
|
|
||||||
}
|
|
||||||
|
|
||||||
uintmax_t readm(unsigned length = 1) {
|
|
||||||
uintmax_t data = 0;
|
|
||||||
while(length--) {
|
|
||||||
data <<= 8;
|
|
||||||
data |= read();
|
|
||||||
}
|
|
||||||
return data;
|
|
||||||
}
|
|
||||||
|
|
||||||
void read(uint8_t *buffer, unsigned length) {
|
|
||||||
while(length--) *buffer++ = read();
|
|
||||||
}
|
|
||||||
|
|
||||||
void write(uint8_t data) {
|
|
||||||
if(!fp) return; //file not open
|
|
||||||
if(file_mode == mode_read) return; //writes not permitted
|
|
||||||
buffer_sync();
|
|
||||||
buffer[(file_offset++) & buffer_mask] = data;
|
|
||||||
buffer_dirty = true;
|
|
||||||
if(file_offset > file_size) file_size = file_offset;
|
|
||||||
}
|
|
||||||
|
|
||||||
void writel(uintmax_t data, unsigned length = 1) {
|
|
||||||
while(length--) {
|
|
||||||
write(data);
|
|
||||||
data >>= 8;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void writem(uintmax_t data, unsigned length = 1) {
|
|
||||||
for(int i = length - 1; i >= 0; i--) {
|
|
||||||
write(data >> (i << 3));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void write(const uint8_t *buffer, unsigned length) {
|
|
||||||
while(length--) write(*buffer++);
|
|
||||||
}
|
|
||||||
|
|
||||||
void print(const char *string) {
|
|
||||||
if(!string) return;
|
|
||||||
while(*string) write(*string++);
|
|
||||||
}
|
|
||||||
|
|
||||||
void flush() {
|
|
||||||
buffer_flush();
|
|
||||||
fflush(fp);
|
|
||||||
}
|
|
||||||
|
|
||||||
void seek(int offset, SeekMode mode = seek_absolute) {
|
|
||||||
if(!fp) return; //file not open
|
|
||||||
buffer_flush();
|
|
||||||
|
|
||||||
uintmax_t req_offset = file_offset;
|
|
||||||
switch(mode) {
|
|
||||||
case seek_absolute: req_offset = offset; break;
|
|
||||||
case seek_relative: req_offset += offset; break;
|
|
||||||
}
|
|
||||||
|
|
||||||
if(req_offset < 0) req_offset = 0; //cannot seek before start of file
|
|
||||||
if(req_offset > file_size) {
|
|
||||||
if(file_mode == mode_read) { //cannot seek past end of file
|
|
||||||
req_offset = file_size;
|
|
||||||
} else { //pad file to requested location
|
|
||||||
file_offset = file_size;
|
|
||||||
while(file_size < req_offset) write(0x00);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
file_offset = req_offset;
|
|
||||||
}
|
|
||||||
|
|
||||||
int offset() {
|
|
||||||
if(!fp) return -1; //file not open
|
|
||||||
return file_offset;
|
|
||||||
}
|
|
||||||
|
|
||||||
int size() {
|
|
||||||
if(!fp) return -1; //file not open
|
|
||||||
return file_size;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool truncate(unsigned size) {
|
|
||||||
if(!fp) return false; //file not open
|
|
||||||
#if !defined(_WIN32)
|
|
||||||
return ftruncate(fileno(fp), size) == 0;
|
|
||||||
#else
|
|
||||||
return _chsize(fileno(fp), size) == 0;
|
|
||||||
#endif
|
|
||||||
}
|
|
||||||
|
|
||||||
bool end() {
|
|
||||||
if(!fp) return true; //file not open
|
|
||||||
return file_offset >= file_size;
|
|
||||||
}
|
|
||||||
|
|
||||||
static bool exists(const char *fn) {
|
|
||||||
#if !defined(_WIN32)
|
|
||||||
FILE *fp = fopen(fn, "rb");
|
|
||||||
#else
|
|
||||||
FILE *fp = _wfopen(utf16_t(fn), L"rb");
|
|
||||||
#endif
|
|
||||||
if(fp) {
|
|
||||||
fclose(fp);
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
static unsigned size(const char *fn) {
|
|
||||||
#if !defined(_WIN32)
|
|
||||||
FILE *fp = fopen(fn, "rb");
|
|
||||||
#else
|
|
||||||
FILE *fp = _wfopen(utf16_t(fn), L"rb");
|
|
||||||
#endif
|
|
||||||
unsigned filesize = 0;
|
|
||||||
if(fp) {
|
|
||||||
fseek(fp, 0, SEEK_END);
|
|
||||||
filesize = ftell(fp);
|
|
||||||
fclose(fp);
|
|
||||||
}
|
|
||||||
return filesize;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool open() {
|
|
||||||
return fp;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool open(const char *fn, FileMode mode) {
|
|
||||||
if(fp) return false;
|
|
||||||
|
|
||||||
switch(file_mode = mode) {
|
|
||||||
#if !defined(_WIN32)
|
|
||||||
case mode_read: fp = fopen(fn, "rb"); break;
|
|
||||||
case mode_write: fp = fopen(fn, "wb+"); break; //need read permission for buffering
|
|
||||||
case mode_readwrite: fp = fopen(fn, "rb+"); break;
|
|
||||||
case mode_writeread: fp = fopen(fn, "wb+"); break;
|
|
||||||
#else
|
|
||||||
case mode_read: fp = _wfopen(utf16_t(fn), L"rb"); break;
|
|
||||||
case mode_write: fp = _wfopen(utf16_t(fn), L"wb+"); break;
|
|
||||||
case mode_readwrite: fp = _wfopen(utf16_t(fn), L"rb+"); break;
|
|
||||||
case mode_writeread: fp = _wfopen(utf16_t(fn), L"wb+"); break;
|
|
||||||
#endif
|
|
||||||
}
|
|
||||||
if(!fp) return false;
|
|
||||||
buffer_offset = -1; //invalidate buffer
|
|
||||||
file_offset = 0;
|
|
||||||
fseek(fp, 0, SEEK_END);
|
|
||||||
file_size = ftell(fp);
|
|
||||||
fseek(fp, 0, SEEK_SET);
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
void close() {
|
|
||||||
if(!fp) return;
|
|
||||||
buffer_flush();
|
|
||||||
fclose(fp);
|
|
||||||
fp = 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
file() {
|
|
||||||
memset(buffer, 0, sizeof buffer);
|
|
||||||
buffer_offset = -1;
|
|
||||||
buffer_dirty = false;
|
|
||||||
fp = 0;
|
|
||||||
file_offset = 0;
|
|
||||||
file_size = 0;
|
|
||||||
file_mode = mode_read;
|
|
||||||
}
|
|
||||||
|
|
||||||
~file() {
|
|
||||||
close();
|
|
||||||
}
|
|
||||||
|
|
||||||
file& operator=(const file&) = delete;
|
|
||||||
file(const file&) = delete;
|
|
||||||
|
|
||||||
private:
|
|
||||||
enum { buffer_size = 1 << 12, buffer_mask = buffer_size - 1 };
|
|
||||||
char buffer[buffer_size];
|
|
||||||
int buffer_offset;
|
|
||||||
bool buffer_dirty;
|
|
||||||
FILE *fp;
|
|
||||||
unsigned file_offset;
|
|
||||||
unsigned file_size;
|
|
||||||
FileMode file_mode;
|
|
||||||
|
|
||||||
void buffer_sync() {
|
|
||||||
if(!fp) return; //file not open
|
|
||||||
if(buffer_offset != (file_offset & ~buffer_mask)) {
|
|
||||||
buffer_flush();
|
|
||||||
buffer_offset = file_offset & ~buffer_mask;
|
|
||||||
fseek(fp, buffer_offset, SEEK_SET);
|
|
||||||
unsigned length = (buffer_offset + buffer_size) <= file_size ? buffer_size : (file_size & buffer_mask);
|
|
||||||
if(length) unsigned unused = fread(buffer, 1, length, fp);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void buffer_flush() {
|
|
||||||
if(!fp) return; //file not open
|
|
||||||
if(file_mode == mode_read) return; //buffer cannot be written to
|
|
||||||
if(buffer_offset < 0) return; //buffer unused
|
|
||||||
if(buffer_dirty == false) return; //buffer unmodified since read
|
|
||||||
fseek(fp, buffer_offset, SEEK_SET);
|
|
||||||
unsigned length = (buffer_offset + buffer_size) <= file_size ? buffer_size : (file_size & buffer_mask);
|
|
||||||
if(length) unsigned unused = fwrite(buffer, 1, length, fp);
|
|
||||||
buffer_offset = -1; //invalidate buffer
|
|
||||||
buffer_dirty = false;
|
|
||||||
}
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
#endif
|
|
|
@ -1,190 +0,0 @@
|
||||||
#ifndef NALL_FILEMAP_HPP
|
|
||||||
#define NALL_FILEMAP_HPP
|
|
||||||
|
|
||||||
#include <nall/stdint.hpp>
|
|
||||||
#include <nall/utf8.hpp>
|
|
||||||
|
|
||||||
#include <stdio.h>
|
|
||||||
#include <stdlib.h>
|
|
||||||
#if defined(_WIN32)
|
|
||||||
#include <windows.h>
|
|
||||||
#else
|
|
||||||
#include <fcntl.h>
|
|
||||||
#include <unistd.h>
|
|
||||||
#include <sys/mman.h>
|
|
||||||
#include <sys/stat.h>
|
|
||||||
#include <sys/types.h>
|
|
||||||
#endif
|
|
||||||
|
|
||||||
namespace nall {
|
|
||||||
class filemap {
|
|
||||||
public:
|
|
||||||
enum filemode { mode_read, mode_write, mode_readwrite, mode_writeread };
|
|
||||||
|
|
||||||
bool open(const char *filename, filemode mode) { return p_open(filename, mode); }
|
|
||||||
void close() { return p_close(); }
|
|
||||||
unsigned size() const { return p_size; }
|
|
||||||
uint8_t* handle() { return p_handle; }
|
|
||||||
const uint8_t* handle() const { return p_handle; }
|
|
||||||
filemap() : p_size(0), p_handle(0) { p_ctor(); }
|
|
||||||
~filemap() { p_dtor(); }
|
|
||||||
|
|
||||||
private:
|
|
||||||
unsigned p_size;
|
|
||||||
uint8_t *p_handle;
|
|
||||||
|
|
||||||
#if defined(_WIN32)
|
|
||||||
//=============
|
|
||||||
//MapViewOfFile
|
|
||||||
//=============
|
|
||||||
|
|
||||||
HANDLE p_filehandle, p_maphandle;
|
|
||||||
|
|
||||||
bool p_open(const char *filename, filemode mode) {
|
|
||||||
int desired_access, creation_disposition, flprotect, map_access;
|
|
||||||
|
|
||||||
switch(mode) {
|
|
||||||
default: return false;
|
|
||||||
case mode_read:
|
|
||||||
desired_access = GENERIC_READ;
|
|
||||||
creation_disposition = OPEN_EXISTING;
|
|
||||||
flprotect = PAGE_READONLY;
|
|
||||||
map_access = FILE_MAP_READ;
|
|
||||||
break;
|
|
||||||
case mode_write:
|
|
||||||
//write access requires read access
|
|
||||||
desired_access = GENERIC_WRITE;
|
|
||||||
creation_disposition = CREATE_ALWAYS;
|
|
||||||
flprotect = PAGE_READWRITE;
|
|
||||||
map_access = FILE_MAP_ALL_ACCESS;
|
|
||||||
break;
|
|
||||||
case mode_readwrite:
|
|
||||||
desired_access = GENERIC_READ | GENERIC_WRITE;
|
|
||||||
creation_disposition = OPEN_EXISTING;
|
|
||||||
flprotect = PAGE_READWRITE;
|
|
||||||
map_access = FILE_MAP_ALL_ACCESS;
|
|
||||||
break;
|
|
||||||
case mode_writeread:
|
|
||||||
desired_access = GENERIC_READ | GENERIC_WRITE;
|
|
||||||
creation_disposition = CREATE_NEW;
|
|
||||||
flprotect = PAGE_READWRITE;
|
|
||||||
map_access = FILE_MAP_ALL_ACCESS;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
p_filehandle = CreateFileW(utf16_t(filename), desired_access, FILE_SHARE_READ, NULL,
|
|
||||||
creation_disposition, FILE_ATTRIBUTE_NORMAL, NULL);
|
|
||||||
if(p_filehandle == INVALID_HANDLE_VALUE) return false;
|
|
||||||
|
|
||||||
p_size = GetFileSize(p_filehandle, NULL);
|
|
||||||
|
|
||||||
p_maphandle = CreateFileMapping(p_filehandle, NULL, flprotect, 0, p_size, NULL);
|
|
||||||
if(p_maphandle == INVALID_HANDLE_VALUE) {
|
|
||||||
CloseHandle(p_filehandle);
|
|
||||||
p_filehandle = INVALID_HANDLE_VALUE;
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
p_handle = (uint8_t*)MapViewOfFile(p_maphandle, map_access, 0, 0, p_size);
|
|
||||||
return p_handle;
|
|
||||||
}
|
|
||||||
|
|
||||||
void p_close() {
|
|
||||||
if(p_handle) {
|
|
||||||
UnmapViewOfFile(p_handle);
|
|
||||||
p_handle = 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
if(p_maphandle != INVALID_HANDLE_VALUE) {
|
|
||||||
CloseHandle(p_maphandle);
|
|
||||||
p_maphandle = INVALID_HANDLE_VALUE;
|
|
||||||
}
|
|
||||||
|
|
||||||
if(p_filehandle != INVALID_HANDLE_VALUE) {
|
|
||||||
CloseHandle(p_filehandle);
|
|
||||||
p_filehandle = INVALID_HANDLE_VALUE;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void p_ctor() {
|
|
||||||
p_filehandle = INVALID_HANDLE_VALUE;
|
|
||||||
p_maphandle = INVALID_HANDLE_VALUE;
|
|
||||||
}
|
|
||||||
|
|
||||||
void p_dtor() {
|
|
||||||
close();
|
|
||||||
}
|
|
||||||
|
|
||||||
#else
|
|
||||||
//====
|
|
||||||
//mmap
|
|
||||||
//====
|
|
||||||
|
|
||||||
int p_fd;
|
|
||||||
|
|
||||||
bool p_open(const char *filename, filemode mode) {
|
|
||||||
int open_flags, mmap_flags;
|
|
||||||
|
|
||||||
switch(mode) {
|
|
||||||
default: return false;
|
|
||||||
case mode_read:
|
|
||||||
open_flags = O_RDONLY;
|
|
||||||
mmap_flags = PROT_READ;
|
|
||||||
break;
|
|
||||||
case mode_write:
|
|
||||||
open_flags = O_RDWR | O_CREAT; //mmap() requires read access
|
|
||||||
mmap_flags = PROT_WRITE;
|
|
||||||
break;
|
|
||||||
case mode_readwrite:
|
|
||||||
open_flags = O_RDWR;
|
|
||||||
mmap_flags = PROT_READ | PROT_WRITE;
|
|
||||||
break;
|
|
||||||
case mode_writeread:
|
|
||||||
open_flags = O_RDWR | O_CREAT;
|
|
||||||
mmap_flags = PROT_READ | PROT_WRITE;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
p_fd = ::open(filename, open_flags);
|
|
||||||
if(p_fd < 0) return false;
|
|
||||||
|
|
||||||
struct stat p_stat;
|
|
||||||
fstat(p_fd, &p_stat);
|
|
||||||
p_size = p_stat.st_size;
|
|
||||||
|
|
||||||
p_handle = (uint8_t*)mmap(0, p_size, mmap_flags, MAP_SHARED, p_fd, 0);
|
|
||||||
if(p_handle == MAP_FAILED) {
|
|
||||||
p_handle = 0;
|
|
||||||
::close(p_fd);
|
|
||||||
p_fd = -1;
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
return p_handle;
|
|
||||||
}
|
|
||||||
|
|
||||||
void p_close() {
|
|
||||||
if(p_handle) {
|
|
||||||
munmap(p_handle, p_size);
|
|
||||||
p_handle = 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
if(p_fd >= 0) {
|
|
||||||
::close(p_fd);
|
|
||||||
p_fd = -1;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void p_ctor() {
|
|
||||||
p_fd = -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
void p_dtor() {
|
|
||||||
p_close();
|
|
||||||
}
|
|
||||||
|
|
||||||
#endif
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
#endif
|
|
|
@ -1,31 +0,0 @@
|
||||||
#ifndef NALL_FOREACH_HPP
|
|
||||||
#define NALL_FOREACH_HPP
|
|
||||||
|
|
||||||
#undef foreach
|
|
||||||
#define foreach(iter, object) \
|
|
||||||
for(unsigned foreach_counter = 0, foreach_limit = foreach_size(object), foreach_once = 0, foreach_broken = 0; foreach_counter < foreach_limit && foreach_broken == 0; foreach_counter++, foreach_once = 0) \
|
|
||||||
for(auto &iter = object[foreach_counter]; foreach_once == 0 && (foreach_broken = 1); foreach_once++, foreach_broken = 0)
|
|
||||||
|
|
||||||
#include <nall/concept.hpp>
|
|
||||||
#include <nall/static.hpp>
|
|
||||||
#include <nall/traits.hpp>
|
|
||||||
|
|
||||||
namespace nall {
|
|
||||||
template<typename T> unsigned foreach_size(const T& object, typename mp_enable_if<has_count<T>>::type = 0) {
|
|
||||||
return object.count();
|
|
||||||
}
|
|
||||||
|
|
||||||
template<typename T> unsigned foreach_size(const T& object, typename mp_enable_if<has_length<T>>::type = 0) {
|
|
||||||
return object.length();
|
|
||||||
}
|
|
||||||
|
|
||||||
template<typename T> unsigned foreach_size(const T& object, typename mp_enable_if<has_size<T>>::type = 0) {
|
|
||||||
return object.size();
|
|
||||||
}
|
|
||||||
|
|
||||||
template<typename T> unsigned foreach_size(const T& object, typename mp_enable_if<is_array<T>>::type = 0) {
|
|
||||||
return sizeof(T) / sizeof(typename remove_extent<T>::type);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#endif
|
|
|
@ -1,190 +0,0 @@
|
||||||
#ifndef NALL_FUNCTION_HPP
|
|
||||||
#define NALL_FUNCTION_HPP
|
|
||||||
|
|
||||||
#include <assert.h>
|
|
||||||
|
|
||||||
//prologue
|
|
||||||
|
|
||||||
#define TN typename
|
|
||||||
|
|
||||||
namespace nall {
|
|
||||||
template<typename T> class function;
|
|
||||||
}
|
|
||||||
|
|
||||||
//parameters = 0
|
|
||||||
|
|
||||||
#define cat(n) n
|
|
||||||
#define TL typename R
|
|
||||||
#define PL
|
|
||||||
#define CL
|
|
||||||
|
|
||||||
#include "function.hpp"
|
|
||||||
|
|
||||||
//parameters = 1
|
|
||||||
|
|
||||||
#define cat(n) , n
|
|
||||||
#define TL TN R, TN P1
|
|
||||||
#define PL P1 p1
|
|
||||||
#define CL p1
|
|
||||||
|
|
||||||
#include "function.hpp"
|
|
||||||
|
|
||||||
//parameters = 2
|
|
||||||
|
|
||||||
#define cat(n) , n
|
|
||||||
#define TL TN R, TN P1, TN P2
|
|
||||||
#define PL P1 p1, P2 p2
|
|
||||||
#define CL p1, p2
|
|
||||||
|
|
||||||
#include "function.hpp"
|
|
||||||
|
|
||||||
//parameters = 3
|
|
||||||
|
|
||||||
#define cat(n) , n
|
|
||||||
#define TL TN R, TN P1, TN P2, TN P3
|
|
||||||
#define PL P1 p1, P2 p2, P3 p3
|
|
||||||
#define CL p1, p2, p3
|
|
||||||
|
|
||||||
#include "function.hpp"
|
|
||||||
|
|
||||||
//parameters = 4
|
|
||||||
|
|
||||||
#define cat(n) , n
|
|
||||||
#define TL TN R, TN P1, TN P2, TN P3, TN P4
|
|
||||||
#define PL P1 p1, P2 p2, P3 p3, P4 p4
|
|
||||||
#define CL p1, p2, p3, p4
|
|
||||||
|
|
||||||
#include "function.hpp"
|
|
||||||
|
|
||||||
//parameters = 5
|
|
||||||
|
|
||||||
#define cat(n) , n
|
|
||||||
#define TL TN R, TN P1, TN P2, TN P3, TN P4, TN P5
|
|
||||||
#define PL P1 p1, P2 p2, P3 p3, P4 p4, P5 p5
|
|
||||||
#define CL p1, p2, p3, p4, p5
|
|
||||||
|
|
||||||
#include "function.hpp"
|
|
||||||
|
|
||||||
//parameters = 6
|
|
||||||
|
|
||||||
#define cat(n) , n
|
|
||||||
#define TL TN R, TN P1, TN P2, TN P3, TN P4, TN P5, TN P6
|
|
||||||
#define PL P1 p1, P2 p2, P3 p3, P4 p4, P5 p5, P6 p6
|
|
||||||
#define CL p1, p2, p3, p4, p5, p6
|
|
||||||
|
|
||||||
#include "function.hpp"
|
|
||||||
|
|
||||||
//parameters = 7
|
|
||||||
|
|
||||||
#define cat(n) , n
|
|
||||||
#define TL TN R, TN P1, TN P2, TN P3, TN P4, TN P5, TN P6, TN P7
|
|
||||||
#define PL P1 p1, P2 p2, P3 p3, P4 p4, P5 p5, P6 p6, P7 p7
|
|
||||||
#define CL p1, p2, p3, p4, p5, p6, p7
|
|
||||||
|
|
||||||
#include "function.hpp"
|
|
||||||
|
|
||||||
//parameters = 8
|
|
||||||
|
|
||||||
#define cat(n) , n
|
|
||||||
#define TL TN R, TN P1, TN P2, TN P3, TN P4, TN P5, TN P6, TN P7, TN P8
|
|
||||||
#define PL P1 p1, P2 p2, P3 p3, P4 p4, P5 p5, P6 p6, P7 p7, P8 p8
|
|
||||||
#define CL p1, p2, p3, p4, p5, p6, p7, p8
|
|
||||||
|
|
||||||
#include "function.hpp"
|
|
||||||
|
|
||||||
//epilogue
|
|
||||||
|
|
||||||
#undef TN
|
|
||||||
#define NALL_FUNCTION_T
|
|
||||||
|
|
||||||
#elif !defined(NALL_FUNCTION_T)
|
|
||||||
|
|
||||||
//function implementation template class
|
|
||||||
|
|
||||||
namespace nall {
|
|
||||||
template<TL>
|
|
||||||
class function<R (PL)> {
|
|
||||||
private:
|
|
||||||
struct base1 { virtual void func1(PL) {} };
|
|
||||||
struct base2 { virtual void func2(PL) {} };
|
|
||||||
struct derived : base1, virtual base2 {};
|
|
||||||
|
|
||||||
struct data_t {
|
|
||||||
R (*fn_call)(const data_t& cat(PL));
|
|
||||||
union {
|
|
||||||
R (*fn_global)(PL);
|
|
||||||
struct {
|
|
||||||
R (derived::*fn_member)(PL);
|
|
||||||
void *object;
|
|
||||||
};
|
|
||||||
};
|
|
||||||
} data;
|
|
||||||
|
|
||||||
static R fn_call_global(const data_t &d cat(PL)) {
|
|
||||||
return d.fn_global(CL);
|
|
||||||
}
|
|
||||||
|
|
||||||
template<typename C>
|
|
||||||
static R fn_call_member(const data_t &d cat(PL)) {
|
|
||||||
return (((C*)d.object)->*((R (C::*&)(PL))d.fn_member))(CL);
|
|
||||||
}
|
|
||||||
|
|
||||||
public:
|
|
||||||
R operator()(PL) const { return data.fn_call(data cat(CL)); }
|
|
||||||
operator bool() const { return data.fn_call; }
|
|
||||||
|
|
||||||
function() { data.fn_call = 0; }
|
|
||||||
|
|
||||||
function(void *fn) {
|
|
||||||
data.fn_call = fn ? &fn_call_global : 0;
|
|
||||||
data.fn_global = (R (*)(PL))fn;
|
|
||||||
}
|
|
||||||
|
|
||||||
function(R (*fn)(PL)) {
|
|
||||||
data.fn_call = &fn_call_global;
|
|
||||||
data.fn_global = fn;
|
|
||||||
}
|
|
||||||
|
|
||||||
template<typename C>
|
|
||||||
function(R (C::*fn)(PL), C *obj) {
|
|
||||||
data.fn_call = &fn_call_member<C>;
|
|
||||||
(R (C::*&)(PL))data.fn_member = fn;
|
|
||||||
assert(sizeof data.fn_member >= sizeof fn);
|
|
||||||
data.object = obj;
|
|
||||||
}
|
|
||||||
|
|
||||||
template<typename C>
|
|
||||||
function(R (C::*fn)(PL) const, C *obj) {
|
|
||||||
data.fn_call = &fn_call_member<C>;
|
|
||||||
(R (C::*&)(PL))data.fn_member = (R (C::*&)(PL))fn;
|
|
||||||
assert(sizeof data.fn_member >= sizeof fn);
|
|
||||||
data.object = obj;
|
|
||||||
}
|
|
||||||
|
|
||||||
function& operator=(void *fn) { return operator=(function(fn)); }
|
|
||||||
function& operator=(const function &source) { memcpy(&data, &source.data, sizeof(data_t)); return *this; }
|
|
||||||
function(const function &source) { memcpy(&data, &source.data, sizeof(data_t)); }
|
|
||||||
};
|
|
||||||
|
|
||||||
template<TL>
|
|
||||||
function<R (PL)> bind(R (*fn)(PL)) {
|
|
||||||
return function<R (PL)>(fn);
|
|
||||||
}
|
|
||||||
|
|
||||||
template<typename C, TL>
|
|
||||||
function<R (PL)> bind(R (C::*fn)(PL), C *obj) {
|
|
||||||
return function<R (PL)>(fn, obj);
|
|
||||||
}
|
|
||||||
|
|
||||||
template<typename C, TL>
|
|
||||||
function<R (PL)> bind(R (C::*fn)(PL) const, C *obj) {
|
|
||||||
return function<R (PL)>(fn, obj);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#undef cat
|
|
||||||
#undef TL
|
|
||||||
#undef PL
|
|
||||||
#undef CL
|
|
||||||
|
|
||||||
#endif
|
|
|
@ -1,386 +0,0 @@
|
||||||
#ifndef NALL_INPUT_HPP
|
|
||||||
#define NALL_INPUT_HPP
|
|
||||||
|
|
||||||
#include <stdio.h>
|
|
||||||
#include <stdlib.h>
|
|
||||||
#include <string.h>
|
|
||||||
|
|
||||||
#include <nall/stdint.hpp>
|
|
||||||
#include <nall/string.hpp>
|
|
||||||
|
|
||||||
namespace nall {
|
|
||||||
|
|
||||||
struct Keyboard;
|
|
||||||
Keyboard& keyboard(unsigned = 0);
|
|
||||||
|
|
||||||
static const char KeyboardScancodeName[][64] = {
|
|
||||||
"Escape", "F1", "F2", "F3", "F4", "F5", "F6", "F7", "F8", "F9", "F10", "F11", "F12",
|
|
||||||
"PrintScreen", "ScrollLock", "Pause", "Tilde",
|
|
||||||
"Num1", "Num2", "Num3", "Num4", "Num5", "Num6", "Num7", "Num8", "Num9", "Num0",
|
|
||||||
"Dash", "Equal", "Backspace",
|
|
||||||
"Insert", "Delete", "Home", "End", "PageUp", "PageDown",
|
|
||||||
"A", "B", "C", "D", "E", "F", "G", "H", "I", "J", "K", "L", "M",
|
|
||||||
"N", "O", "P", "Q", "R", "S", "T", "U", "V", "W", "X", "Y", "Z",
|
|
||||||
"LeftBracket", "RightBracket", "Backslash", "Semicolon", "Apostrophe", "Comma", "Period", "Slash",
|
|
||||||
"Keypad1", "Keypad2", "Keypad3", "Keypad4", "Keypad5", "Keypad6", "Keypad7", "Keypad8", "Keypad9", "Keypad0",
|
|
||||||
"Point", "Enter", "Add", "Subtract", "Multiply", "Divide",
|
|
||||||
"NumLock", "CapsLock",
|
|
||||||
"Up", "Down", "Left", "Right",
|
|
||||||
"Tab", "Return", "Spacebar", "Menu",
|
|
||||||
"Shift", "Control", "Alt", "Super",
|
|
||||||
};
|
|
||||||
|
|
||||||
struct Keyboard {
|
|
||||||
const unsigned ID;
|
|
||||||
enum { Base = 1 };
|
|
||||||
enum { Count = 8, Size = 128 };
|
|
||||||
|
|
||||||
enum Scancode {
|
|
||||||
Escape, F1, F2, F3, F4, F5, F6, F7, F8, F9, F10, F11, F12,
|
|
||||||
PrintScreen, ScrollLock, Pause, Tilde,
|
|
||||||
Num1, Num2, Num3, Num4, Num5, Num6, Num7, Num8, Num9, Num0,
|
|
||||||
Dash, Equal, Backspace,
|
|
||||||
Insert, Delete, Home, End, PageUp, PageDown,
|
|
||||||
A, B, C, D, E, F, G, H, I, J, K, L, M,
|
|
||||||
N, O, P, Q, R, S, T, U, V, W, X, Y, Z,
|
|
||||||
LeftBracket, RightBracket, Backslash, Semicolon, Apostrophe, Comma, Period, Slash,
|
|
||||||
Keypad1, Keypad2, Keypad3, Keypad4, Keypad5, Keypad6, Keypad7, Keypad8, Keypad9, Keypad0,
|
|
||||||
Point, Enter, Add, Subtract, Multiply, Divide,
|
|
||||||
NumLock, CapsLock,
|
|
||||||
Up, Down, Left, Right,
|
|
||||||
Tab, Return, Spacebar, Menu,
|
|
||||||
Shift, Control, Alt, Super,
|
|
||||||
Limit,
|
|
||||||
};
|
|
||||||
|
|
||||||
static signed numberDecode(uint16_t scancode) {
|
|
||||||
for(unsigned i = 0; i < Count; i++) {
|
|
||||||
if(keyboard(i).belongsTo(scancode)) return i;
|
|
||||||
}
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
static signed keyDecode(uint16_t scancode) {
|
|
||||||
for(unsigned i = 0; i < Count; i++) {
|
|
||||||
if(keyboard(i).isKey(scancode)) return scancode - keyboard(i).key(Escape);
|
|
||||||
}
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
static signed modifierDecode(uint16_t scancode) {
|
|
||||||
for(unsigned i = 0; i < Count; i++) {
|
|
||||||
if(keyboard(i).isModifier(scancode)) return scancode - keyboard(i).key(Shift);
|
|
||||||
}
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
static bool isAnyKey(uint16_t scancode) {
|
|
||||||
for(unsigned i = 0; i < Count; i++) {
|
|
||||||
if(keyboard(i).isKey(scancode)) return true;
|
|
||||||
}
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
static bool isAnyModifier(uint16_t scancode) {
|
|
||||||
for(unsigned i = 0; i < Count; i++) {
|
|
||||||
if(keyboard(i).isModifier(scancode)) return true;
|
|
||||||
}
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
static uint16_t decode(const char *name) {
|
|
||||||
string s(name);
|
|
||||||
if(!strbegin(name, "KB")) return 0;
|
|
||||||
ltrim(s, "KB");
|
|
||||||
unsigned id = strunsigned(s);
|
|
||||||
int pos = strpos(s, "::");
|
|
||||||
if(pos < 0) return 0;
|
|
||||||
s = substr(s, pos + 2);
|
|
||||||
for(unsigned i = 0; i < Limit; i++) {
|
|
||||||
if(s == KeyboardScancodeName[i]) return Base + Size * id + i;
|
|
||||||
}
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
string encode(uint16_t code) const {
|
|
||||||
unsigned index = 0;
|
|
||||||
for(unsigned i = 0; i < Count; i++) {
|
|
||||||
if(code >= Base + Size * i && code < Base + Size * (i + 1)) {
|
|
||||||
index = code - (Base + Size * i);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return string() << "KB" << ID << "::" << KeyboardScancodeName[index];
|
|
||||||
}
|
|
||||||
|
|
||||||
uint16_t operator[](Scancode code) const { return Base + ID * Size + code; }
|
|
||||||
uint16_t key(unsigned id) const { return Base + Size * ID + id; }
|
|
||||||
bool isKey(unsigned id) const { return id >= key(Escape) && id <= key(Menu); }
|
|
||||||
bool isModifier(unsigned id) const { return id >= key(Shift) && id <= key(Super); }
|
|
||||||
bool belongsTo(uint16_t scancode) const { return isKey(scancode) || isModifier(scancode); }
|
|
||||||
|
|
||||||
Keyboard(unsigned ID_) : ID(ID_) {}
|
|
||||||
};
|
|
||||||
|
|
||||||
inline Keyboard& keyboard(unsigned id) {
|
|
||||||
static Keyboard kb0(0), kb1(1), kb2(2), kb3(3), kb4(4), kb5(5), kb6(6), kb7(7);
|
|
||||||
switch(id) { default:
|
|
||||||
case 0: return kb0; case 1: return kb1; case 2: return kb2; case 3: return kb3;
|
|
||||||
case 4: return kb4; case 5: return kb5; case 6: return kb6; case 7: return kb7;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
static const char MouseScancodeName[][64] = {
|
|
||||||
"Xaxis", "Yaxis", "Zaxis",
|
|
||||||
"Button0", "Button1", "Button2", "Button3", "Button4", "Button5", "Button6", "Button7",
|
|
||||||
};
|
|
||||||
|
|
||||||
struct Mouse;
|
|
||||||
Mouse& mouse(unsigned = 0);
|
|
||||||
|
|
||||||
struct Mouse {
|
|
||||||
const unsigned ID;
|
|
||||||
enum { Base = Keyboard::Base + Keyboard::Size * Keyboard::Count };
|
|
||||||
enum { Count = 8, Size = 16 };
|
|
||||||
enum { Axes = 3, Buttons = 8 };
|
|
||||||
|
|
||||||
enum Scancode {
|
|
||||||
Xaxis, Yaxis, Zaxis,
|
|
||||||
Button0, Button1, Button2, Button3, Button4, Button5, Button6, Button7,
|
|
||||||
Limit,
|
|
||||||
};
|
|
||||||
|
|
||||||
static signed numberDecode(uint16_t scancode) {
|
|
||||||
for(unsigned i = 0; i < Count; i++) {
|
|
||||||
if(mouse(i).belongsTo(scancode)) return i;
|
|
||||||
}
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
static signed axisDecode(uint16_t scancode) {
|
|
||||||
for(unsigned i = 0; i < Count; i++) {
|
|
||||||
if(mouse(i).isAxis(scancode)) return scancode - mouse(i).axis(0);
|
|
||||||
}
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
static signed buttonDecode(uint16_t scancode) {
|
|
||||||
for(unsigned i = 0; i < Count; i++) {
|
|
||||||
if(mouse(i).isButton(scancode)) return scancode - mouse(i).button(0);
|
|
||||||
}
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
static bool isAnyAxis(uint16_t scancode) {
|
|
||||||
for(unsigned i = 0; i < Count; i++) {
|
|
||||||
if(mouse(i).isAxis(scancode)) return true;
|
|
||||||
}
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
static bool isAnyButton(uint16_t scancode) {
|
|
||||||
for(unsigned i = 0; i < Count; i++) {
|
|
||||||
if(mouse(i).isButton(scancode)) return true;
|
|
||||||
}
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
static uint16_t decode(const char *name) {
|
|
||||||
string s(name);
|
|
||||||
if(!strbegin(name, "MS")) return 0;
|
|
||||||
ltrim(s, "MS");
|
|
||||||
unsigned id = strunsigned(s);
|
|
||||||
int pos = strpos(s, "::");
|
|
||||||
if(pos < 0) return 0;
|
|
||||||
s = substr(s, pos + 2);
|
|
||||||
for(unsigned i = 0; i < Limit; i++) {
|
|
||||||
if(s == MouseScancodeName[i]) return Base + Size * id + i;
|
|
||||||
}
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
string encode(uint16_t code) const {
|
|
||||||
unsigned index = 0;
|
|
||||||
for(unsigned i = 0; i < Count; i++) {
|
|
||||||
if(code >= Base + Size * i && code < Base + Size * (i + 1)) {
|
|
||||||
index = code - (Base + Size * i);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return string() << "MS" << ID << "::" << MouseScancodeName[index];
|
|
||||||
}
|
|
||||||
|
|
||||||
uint16_t operator[](Scancode code) const { return Base + ID * Size + code; }
|
|
||||||
uint16_t axis(unsigned id) const { return Base + Size * ID + Xaxis + id; }
|
|
||||||
uint16_t button(unsigned id) const { return Base + Size * ID + Button0 + id; }
|
|
||||||
bool isAxis(unsigned id) const { return id >= axis(0) && id <= axis(2); }
|
|
||||||
bool isButton(unsigned id) const { return id >= button(0) && id <= button(7); }
|
|
||||||
bool belongsTo(uint16_t scancode) const { return isAxis(scancode) || isButton(scancode); }
|
|
||||||
|
|
||||||
Mouse(unsigned ID_) : ID(ID_) {}
|
|
||||||
};
|
|
||||||
|
|
||||||
inline Mouse& mouse(unsigned id) {
|
|
||||||
static Mouse ms0(0), ms1(1), ms2(2), ms3(3), ms4(4), ms5(5), ms6(6), ms7(7);
|
|
||||||
switch(id) { default:
|
|
||||||
case 0: return ms0; case 1: return ms1; case 2: return ms2; case 3: return ms3;
|
|
||||||
case 4: return ms4; case 5: return ms5; case 6: return ms6; case 7: return ms7;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
static const char JoypadScancodeName[][64] = {
|
|
||||||
"Hat0", "Hat1", "Hat2", "Hat3", "Hat4", "Hat5", "Hat6", "Hat7",
|
|
||||||
"Axis0", "Axis1", "Axis2", "Axis3", "Axis4", "Axis5", "Axis6", "Axis7",
|
|
||||||
"Axis8", "Axis9", "Axis10", "Axis11", "Axis12", "Axis13", "Axis14", "Axis15",
|
|
||||||
"Button0", "Button1", "Button2", "Button3", "Button4", "Button5", "Button6", "Button7",
|
|
||||||
"Button8", "Button9", "Button10", "Button11", "Button12", "Button13", "Button14", "Button15",
|
|
||||||
"Button16", "Button17", "Button18", "Button19", "Button20", "Button21", "Button22", "Button23",
|
|
||||||
"Button24", "Button25", "Button26", "Button27", "Button28", "Button29", "Button30", "Button31",
|
|
||||||
};
|
|
||||||
|
|
||||||
struct Joypad;
|
|
||||||
Joypad& joypad(unsigned = 0);
|
|
||||||
|
|
||||||
struct Joypad {
|
|
||||||
const unsigned ID;
|
|
||||||
enum { Base = Mouse::Base + Mouse::Size * Mouse::Count };
|
|
||||||
enum { Count = 8, Size = 64 };
|
|
||||||
enum { Hats = 8, Axes = 16, Buttons = 32 };
|
|
||||||
|
|
||||||
enum Scancode {
|
|
||||||
Hat0, Hat1, Hat2, Hat3, Hat4, Hat5, Hat6, Hat7,
|
|
||||||
Axis0, Axis1, Axis2, Axis3, Axis4, Axis5, Axis6, Axis7,
|
|
||||||
Axis8, Axis9, Axis10, Axis11, Axis12, Axis13, Axis14, Axis15,
|
|
||||||
Button0, Button1, Button2, Button3, Button4, Button5, Button6, Button7,
|
|
||||||
Button8, Button9, Button10, Button11, Button12, Button13, Button14, Button15,
|
|
||||||
Button16, Button17, Button18, Button19, Button20, Button21, Button22, Button23,
|
|
||||||
Button24, Button25, Button26, Button27, Button28, Button29, Button30, Button31,
|
|
||||||
Limit,
|
|
||||||
};
|
|
||||||
|
|
||||||
enum Hat { HatCenter = 0, HatUp = 1, HatRight = 2, HatDown = 4, HatLeft = 8 };
|
|
||||||
|
|
||||||
static signed numberDecode(uint16_t scancode) {
|
|
||||||
for(unsigned i = 0; i < Count; i++) {
|
|
||||||
if(joypad(i).belongsTo(scancode)) return i;
|
|
||||||
}
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
static signed hatDecode(uint16_t scancode) {
|
|
||||||
for(unsigned i = 0; i < Count; i++) {
|
|
||||||
if(joypad(i).isHat(scancode)) return scancode - joypad(i).hat(0);
|
|
||||||
}
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
static signed axisDecode(uint16_t scancode) {
|
|
||||||
for(unsigned i = 0; i < Count; i++) {
|
|
||||||
if(joypad(i).isAxis(scancode)) return scancode - joypad(i).axis(0);
|
|
||||||
}
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
static signed buttonDecode(uint16_t scancode) {
|
|
||||||
for(unsigned i = 0; i < Count; i++) {
|
|
||||||
if(joypad(i).isButton(scancode)) return scancode - joypad(i).button(0);
|
|
||||||
}
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
static bool isAnyHat(uint16_t scancode) {
|
|
||||||
for(unsigned i = 0; i < Count; i++) {
|
|
||||||
if(joypad(i).isHat(scancode)) return true;
|
|
||||||
}
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
static bool isAnyAxis(uint16_t scancode) {
|
|
||||||
for(unsigned i = 0; i < Count; i++) {
|
|
||||||
if(joypad(i).isAxis(scancode)) return true;
|
|
||||||
}
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
static bool isAnyButton(uint16_t scancode) {
|
|
||||||
for(unsigned i = 0; i < Count; i++) {
|
|
||||||
if(joypad(i).isButton(scancode)) return true;
|
|
||||||
}
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
static uint16_t decode(const char *name) {
|
|
||||||
string s(name);
|
|
||||||
if(!strbegin(name, "JP")) return 0;
|
|
||||||
ltrim(s, "JP");
|
|
||||||
unsigned id = strunsigned(s);
|
|
||||||
int pos = strpos(s, "::");
|
|
||||||
if(pos < 0) return 0;
|
|
||||||
s = substr(s, pos + 2);
|
|
||||||
for(unsigned i = 0; i < Limit; i++) {
|
|
||||||
if(s == JoypadScancodeName[i]) return Base + Size * id + i;
|
|
||||||
}
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
string encode(uint16_t code) const {
|
|
||||||
unsigned index = 0;
|
|
||||||
for(unsigned i = 0; i < Count; i++) {
|
|
||||||
if(code >= Base + Size * i && code < Base + Size * (i + 1)) {
|
|
||||||
index = code - (Base + Size * i);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return string() << "JP" << ID << "::" << JoypadScancodeName[index];
|
|
||||||
}
|
|
||||||
|
|
||||||
uint16_t operator[](Scancode code) const { return Base + ID * Size + code; }
|
|
||||||
uint16_t hat(unsigned id) const { return Base + Size * ID + Hat0 + id; }
|
|
||||||
uint16_t axis(unsigned id) const { return Base + Size * ID + Axis0 + id; }
|
|
||||||
uint16_t button(unsigned id) const { return Base + Size * ID + Button0 + id; }
|
|
||||||
bool isHat(unsigned id) const { return id >= hat(0) && id <= hat(7); }
|
|
||||||
bool isAxis(unsigned id) const { return id >= axis(0) && id <= axis(15); }
|
|
||||||
bool isButton(unsigned id) const { return id >= button(0) && id <= button(31); }
|
|
||||||
bool belongsTo(uint16_t scancode) const { return isHat(scancode) || isAxis(scancode) || isButton(scancode); }
|
|
||||||
|
|
||||||
Joypad(unsigned ID_) : ID(ID_) {}
|
|
||||||
};
|
|
||||||
|
|
||||||
inline Joypad& joypad(unsigned id) {
|
|
||||||
static Joypad jp0(0), jp1(1), jp2(2), jp3(3), jp4(4), jp5(5), jp6(6), jp7(7);
|
|
||||||
switch(id) { default:
|
|
||||||
case 0: return jp0; case 1: return jp1; case 2: return jp2; case 3: return jp3;
|
|
||||||
case 4: return jp4; case 5: return jp5; case 6: return jp6; case 7: return jp7;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
struct Scancode {
|
|
||||||
enum { None = 0, Limit = Joypad::Base + Joypad::Size * Joypad::Count };
|
|
||||||
|
|
||||||
static uint16_t decode(const char *name) {
|
|
||||||
uint16_t code;
|
|
||||||
code = Keyboard::decode(name);
|
|
||||||
if(code) return code;
|
|
||||||
code = Mouse::decode(name);
|
|
||||||
if(code) return code;
|
|
||||||
code = Joypad::decode(name);
|
|
||||||
if(code) return code;
|
|
||||||
return None;
|
|
||||||
}
|
|
||||||
|
|
||||||
static string encode(uint16_t code) {
|
|
||||||
for(unsigned i = 0; i < Keyboard::Count; i++) {
|
|
||||||
if(keyboard(i).belongsTo(code)) return keyboard(i).encode(code);
|
|
||||||
}
|
|
||||||
for(unsigned i = 0; i < Mouse::Count; i++) {
|
|
||||||
if(mouse(i).belongsTo(code)) return mouse(i).encode(code);
|
|
||||||
}
|
|
||||||
for(unsigned i = 0; i < Joypad::Count; i++) {
|
|
||||||
if(joypad(i).belongsTo(code)) return joypad(i).encode(code);
|
|
||||||
}
|
|
||||||
return "None";
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
#endif
|
|
|
@ -1,81 +0,0 @@
|
||||||
#ifndef NALL_LZSS_HPP
|
|
||||||
#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];
|
|
||||||
|
|
||||||
unsigned i = 0, o = 0;
|
|
||||||
while(i < inlength) {
|
|
||||||
unsigned flagoffset = o++;
|
|
||||||
uint8_t flag = 0x00;
|
|
||||||
|
|
||||||
for(unsigned b = 0; b < 8 && i < inlength; b++) {
|
|
||||||
unsigned longest = 0, pointer;
|
|
||||||
for(unsigned index = 1; index < 4096; index++) {
|
|
||||||
unsigned count = 0;
|
|
||||||
while(true) {
|
|
||||||
if(count >= 15 + 3) break; //verify pattern match is not longer than max length
|
|
||||||
if(i + count >= inlength) break; //verify pattern match does not read past end of input
|
|
||||||
if(i + count < index) break; //verify read is not before start of input
|
|
||||||
if(input[i + count] != input[i + count - index]) break; //verify pattern still matches
|
|
||||||
count++;
|
|
||||||
}
|
|
||||||
|
|
||||||
if(count > longest) {
|
|
||||||
longest = count;
|
|
||||||
pointer = index;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if(longest < 3) output[o++] = input[i++];
|
|
||||||
else {
|
|
||||||
flag |= 1 << b;
|
|
||||||
uint16_t x = ((longest - 3) << 12) + pointer;
|
|
||||||
output[o++] = x;
|
|
||||||
output[o++] = x >> 8;
|
|
||||||
i += longest;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
output[flagoffset] = flag;
|
|
||||||
}
|
|
||||||
|
|
||||||
outlength = o;
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
static bool decode(uint8_t *&output, const uint8_t *input, unsigned length) {
|
|
||||||
output = new(zeromemory) uint8_t[length];
|
|
||||||
|
|
||||||
unsigned i = 0, o = 0;
|
|
||||||
while(o < length) {
|
|
||||||
uint8_t flag = input[i++];
|
|
||||||
|
|
||||||
for(unsigned b = 0; b < 8 && o < length; b++) {
|
|
||||||
if(!(flag & (1 << b))) output[o++] = input[i++];
|
|
||||||
else {
|
|
||||||
uint16_t offset = input[i++];
|
|
||||||
offset += input[i++] << 8;
|
|
||||||
uint16_t lookuplength = (offset >> 12) + 3;
|
|
||||||
offset &= 4095;
|
|
||||||
for(unsigned index = 0; index < lookuplength && o + index < length; index++) {
|
|
||||||
output[o + index] = output[o + index - offset];
|
|
||||||
}
|
|
||||||
o += lookuplength;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
#endif
|
|
|
@ -1,40 +0,0 @@
|
||||||
#ifndef NALL_MODULO_HPP
|
|
||||||
#define NALL_MODULO_HPP
|
|
||||||
|
|
||||||
#include <nall/serializer.hpp>
|
|
||||||
|
|
||||||
namespace nall {
|
|
||||||
template<typename T, int size> class modulo_array {
|
|
||||||
public:
|
|
||||||
inline T operator[](int index) const {
|
|
||||||
return buffer[size + index];
|
|
||||||
}
|
|
||||||
|
|
||||||
inline T read(int index) const {
|
|
||||||
return buffer[size + index];
|
|
||||||
}
|
|
||||||
|
|
||||||
inline void write(unsigned index, const T value) {
|
|
||||||
buffer[index] =
|
|
||||||
buffer[index + size] =
|
|
||||||
buffer[index + size + size] = value;
|
|
||||||
}
|
|
||||||
|
|
||||||
void serialize(serializer &s) {
|
|
||||||
s.array(buffer, size * 3);
|
|
||||||
}
|
|
||||||
|
|
||||||
modulo_array() {
|
|
||||||
buffer = new T[size * 3]();
|
|
||||||
}
|
|
||||||
|
|
||||||
~modulo_array() {
|
|
||||||
delete[] buffer;
|
|
||||||
}
|
|
||||||
|
|
||||||
private:
|
|
||||||
T *buffer;
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
#endif
|
|
|
@ -1,80 +0,0 @@
|
||||||
#ifndef NALL_PLATFORM_HPP
|
|
||||||
#define NALL_PLATFORM_HPP
|
|
||||||
|
|
||||||
#include <nall/utf8.hpp>
|
|
||||||
|
|
||||||
//=========================
|
|
||||||
//standard platform headers
|
|
||||||
//=========================
|
|
||||||
|
|
||||||
#include <limits>
|
|
||||||
|
|
||||||
#include <assert.h>
|
|
||||||
#include <limits.h>
|
|
||||||
#include <math.h>
|
|
||||||
#include <stdarg.h>
|
|
||||||
#include <stdio.h>
|
|
||||||
#include <stdlib.h>
|
|
||||||
#include <string.h>
|
|
||||||
#include <time.h>
|
|
||||||
|
|
||||||
#if defined(_WIN32)
|
|
||||||
#include <io.h>
|
|
||||||
#include <direct.h>
|
|
||||||
#include <shlobj.h>
|
|
||||||
#undef interface
|
|
||||||
#else
|
|
||||||
#include <unistd.h>
|
|
||||||
#include <pwd.h>
|
|
||||||
#include <sys/stat.h>
|
|
||||||
#endif
|
|
||||||
|
|
||||||
//==================
|
|
||||||
//warning supression
|
|
||||||
//==================
|
|
||||||
|
|
||||||
//Visual C++
|
|
||||||
#if defined(_MSC_VER)
|
|
||||||
//disable libc "deprecation" warnings
|
|
||||||
#pragma warning(disable:4996)
|
|
||||||
#endif
|
|
||||||
|
|
||||||
//================
|
|
||||||
//POSIX compliance
|
|
||||||
//================
|
|
||||||
|
|
||||||
#if defined(_MSC_VER)
|
|
||||||
#define PATH_MAX _MAX_PATH
|
|
||||||
#define va_copy(dest, src) ((dest) = (src))
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#if defined(_WIN32)
|
|
||||||
#define getcwd _getcwd
|
|
||||||
#define ftruncate _chsize
|
|
||||||
#define putenv _putenv
|
|
||||||
#define mkdir(n, m) _wmkdir(nall::utf16_t(n))
|
|
||||||
#define rmdir _rmdir
|
|
||||||
#define vsnprintf _vsnprintf
|
|
||||||
#define usleep(n) Sleep(n / 1000)
|
|
||||||
#endif
|
|
||||||
|
|
||||||
//================
|
|
||||||
//inline expansion
|
|
||||||
//================
|
|
||||||
|
|
||||||
#if defined(__GNUC__)
|
|
||||||
#define noinline __attribute__((noinline))
|
|
||||||
#define inline inline
|
|
||||||
#define alwaysinline inline __attribute__((always_inline))
|
|
||||||
#elif defined(_MSC_VER)
|
|
||||||
#define noinline __declspec(noinline)
|
|
||||||
#define inline inline
|
|
||||||
#define alwaysinline inline __forceinline
|
|
||||||
#else
|
|
||||||
#define noinline
|
|
||||||
#define inline inline
|
|
||||||
#define alwaysinline inline
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#endif
|
|
||||||
|
|
|
@ -1,109 +0,0 @@
|
||||||
#ifndef NALL_PRIORITYQUEUE_HPP
|
|
||||||
#define NALL_PRIORITYQUEUE_HPP
|
|
||||||
|
|
||||||
#include <limits>
|
|
||||||
#include <nall/function.hpp>
|
|
||||||
#include <nall/serializer.hpp>
|
|
||||||
#include <nall/utility.hpp>
|
|
||||||
|
|
||||||
namespace nall {
|
|
||||||
template<typename type_t> void priority_queue_nocallback(type_t) {}
|
|
||||||
|
|
||||||
//priority queue implementation using binary min-heap array;
|
|
||||||
//does not require normalize() function.
|
|
||||||
//O(1) find (tick)
|
|
||||||
//O(log n) insert (enqueue)
|
|
||||||
//O(log n) remove (dequeue)
|
|
||||||
template<typename type_t> class priority_queue {
|
|
||||||
public:
|
|
||||||
inline void tick(unsigned ticks) {
|
|
||||||
basecounter += ticks;
|
|
||||||
while(heapsize && gte(basecounter, heap[0].counter)) callback(dequeue());
|
|
||||||
}
|
|
||||||
|
|
||||||
//counter is relative to current time (eg enqueue(64, ...) fires in 64 ticks);
|
|
||||||
//counter cannot exceed std::numeric_limits<unsigned>::max() >> 1.
|
|
||||||
void enqueue(unsigned counter, type_t event) {
|
|
||||||
unsigned child = heapsize++;
|
|
||||||
counter += basecounter;
|
|
||||||
|
|
||||||
while(child) {
|
|
||||||
unsigned parent = (child - 1) >> 1;
|
|
||||||
if(gte(counter, heap[parent].counter)) break;
|
|
||||||
|
|
||||||
heap[child].counter = heap[parent].counter;
|
|
||||||
heap[child].event = heap[parent].event;
|
|
||||||
child = parent;
|
|
||||||
}
|
|
||||||
|
|
||||||
heap[child].counter = counter;
|
|
||||||
heap[child].event = event;
|
|
||||||
}
|
|
||||||
|
|
||||||
type_t dequeue() {
|
|
||||||
type_t event(heap[0].event);
|
|
||||||
unsigned parent = 0;
|
|
||||||
unsigned counter = heap[--heapsize].counter;
|
|
||||||
|
|
||||||
while(true) {
|
|
||||||
unsigned child = (parent << 1) + 1;
|
|
||||||
if(child >= heapsize) break;
|
|
||||||
if(child + 1 < heapsize && gte(heap[child].counter, heap[child + 1].counter)) child++;
|
|
||||||
if(gte(heap[child].counter, counter)) break;
|
|
||||||
|
|
||||||
heap[parent].counter = heap[child].counter;
|
|
||||||
heap[parent].event = heap[child].event;
|
|
||||||
parent = child;
|
|
||||||
}
|
|
||||||
|
|
||||||
heap[parent].counter = counter;
|
|
||||||
heap[parent].event = heap[heapsize].event;
|
|
||||||
return event;
|
|
||||||
}
|
|
||||||
|
|
||||||
void reset() {
|
|
||||||
basecounter = 0;
|
|
||||||
heapsize = 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
void serialize(serializer &s) {
|
|
||||||
s.integer(basecounter);
|
|
||||||
s.integer(heapsize);
|
|
||||||
for(unsigned n = 0; n < heapcapacity; n++) {
|
|
||||||
s.integer(heap[n].counter);
|
|
||||||
s.integer(heap[n].event);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
priority_queue(unsigned size, function<void (type_t)> callback_ = &priority_queue_nocallback<type_t>)
|
|
||||||
: callback(callback_) {
|
|
||||||
heap = new heap_t[size];
|
|
||||||
heapcapacity = size;
|
|
||||||
reset();
|
|
||||||
}
|
|
||||||
|
|
||||||
~priority_queue() {
|
|
||||||
delete[] heap;
|
|
||||||
}
|
|
||||||
|
|
||||||
priority_queue& operator=(const priority_queue&) = delete;
|
|
||||||
priority_queue(const priority_queue&) = delete;
|
|
||||||
|
|
||||||
private:
|
|
||||||
function<void (type_t)> callback;
|
|
||||||
unsigned basecounter;
|
|
||||||
unsigned heapsize;
|
|
||||||
unsigned heapcapacity;
|
|
||||||
struct heap_t {
|
|
||||||
unsigned counter;
|
|
||||||
type_t event;
|
|
||||||
} *heap;
|
|
||||||
|
|
||||||
//return true if x is greater than or equal to y
|
|
||||||
inline bool gte(unsigned x, unsigned y) {
|
|
||||||
return x - y < (std::numeric_limits<unsigned>::max() >> 1);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
#endif
|
|
|
@ -1,91 +0,0 @@
|
||||||
#ifndef NALL_PROPERTY_HPP
|
|
||||||
#define NALL_PROPERTY_HPP
|
|
||||||
|
|
||||||
//nall::property implements ownership semantics into container classes
|
|
||||||
//example: property<owner>::readonly<type> implies that only owner has full
|
|
||||||
//access to type; and all other code has readonly access.
|
|
||||||
//
|
|
||||||
//this code relies on extended friend semantics from C++0x to work, as it
|
|
||||||
//declares a friend class via a template paramter. it also exploits a bug in
|
|
||||||
//G++ 4.x to work even in C++98 mode.
|
|
||||||
//
|
|
||||||
//if compiling elsewhere, simply remove the friend class and private semantics
|
|
||||||
|
|
||||||
//property can be used either of two ways:
|
|
||||||
//struct foo {
|
|
||||||
// property<foo>::readonly<bool> x;
|
|
||||||
// property<foo>::readwrite<int> y;
|
|
||||||
//};
|
|
||||||
//-or-
|
|
||||||
//struct foo : property<foo> {
|
|
||||||
// readonly<bool> x;
|
|
||||||
// readwrite<int> y;
|
|
||||||
//};
|
|
||||||
|
|
||||||
//return types are const T& (byref) instead fo T (byval) to avoid major speed
|
|
||||||
//penalties for objects with expensive copy constructors
|
|
||||||
|
|
||||||
//operator-> provides access to underlying object type:
|
|
||||||
//readonly<Object> foo;
|
|
||||||
//foo->bar();
|
|
||||||
//... will call Object::bar();
|
|
||||||
|
|
||||||
//operator='s reference is constant so as to avoid leaking a reference handle
|
|
||||||
//that could bypass access restrictions
|
|
||||||
|
|
||||||
//both constant and non-constant operators are provided, though it may be
|
|
||||||
//necessary to cast first, for instance:
|
|
||||||
//struct foo : property<foo> { readonly<int> bar; } object;
|
|
||||||
//int main() { int value = const_cast<const foo&>(object); }
|
|
||||||
|
|
||||||
//writeonly is useful for objects that have non-const reads, but const writes.
|
|
||||||
//however, to avoid leaking handles, the interface is very restricted. the only
|
|
||||||
//way to write is via operator=, which requires conversion via eg copy
|
|
||||||
//constructor. example:
|
|
||||||
//struct foo {
|
|
||||||
// foo(bool value) { ... }
|
|
||||||
//};
|
|
||||||
//writeonly<foo> bar;
|
|
||||||
//bar = true;
|
|
||||||
|
|
||||||
namespace nall {
|
|
||||||
template<typename C> struct property {
|
|
||||||
template<typename T> struct traits { typedef T type; };
|
|
||||||
|
|
||||||
template<typename T> struct readonly {
|
|
||||||
const T* operator->() const { return &value; }
|
|
||||||
const T& operator()() const { return value; }
|
|
||||||
operator const T&() const { return value; }
|
|
||||||
private:
|
|
||||||
T* operator->() { return &value; }
|
|
||||||
operator T&() { return value; }
|
|
||||||
const T& operator=(const T& value_) { return value = value_; }
|
|
||||||
T value;
|
|
||||||
friend class traits<C>::type;
|
|
||||||
};
|
|
||||||
|
|
||||||
template<typename T> struct writeonly {
|
|
||||||
void operator=(const T& value_) { value = value_; }
|
|
||||||
private:
|
|
||||||
const T* operator->() const { return &value; }
|
|
||||||
const T& operator()() const { return value; }
|
|
||||||
operator const T&() const { return value; }
|
|
||||||
T* operator->() { return &value; }
|
|
||||||
operator T&() { return value; }
|
|
||||||
T value;
|
|
||||||
friend class traits<C>::type;
|
|
||||||
};
|
|
||||||
|
|
||||||
template<typename T> struct readwrite {
|
|
||||||
const T* operator->() const { return &value; }
|
|
||||||
const T& operator()() const { return value; }
|
|
||||||
operator const T&() const { return value; }
|
|
||||||
T* operator->() { return &value; }
|
|
||||||
operator T&() { return value; }
|
|
||||||
const T& operator=(const T& value_) { return value = value_; }
|
|
||||||
T value;
|
|
||||||
};
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
#endif
|
|
|
@ -1,55 +0,0 @@
|
||||||
# requires nall/Makefile
|
|
||||||
|
|
||||||
# imports:
|
|
||||||
# $(qtlibs) -- list of Qt components to link against
|
|
||||||
|
|
||||||
# exports the following symbols:
|
|
||||||
# $(moc) -- meta-object compiler
|
|
||||||
# $(rcc) -- resource compiler
|
|
||||||
# $(qtinc) -- includes for compiling
|
|
||||||
# $(qtlib) -- libraries for linking
|
|
||||||
|
|
||||||
ifeq ($(moc),)
|
|
||||||
moc := moc
|
|
||||||
endif
|
|
||||||
|
|
||||||
ifeq ($(rcc),)
|
|
||||||
rcc := rcc
|
|
||||||
endif
|
|
||||||
|
|
||||||
ifeq ($(platform),x)
|
|
||||||
qtinc := `pkg-config --cflags $(qtlibs)`
|
|
||||||
qtlib := `pkg-config --libs $(qtlibs)`
|
|
||||||
else ifeq ($(platform),osx)
|
|
||||||
qtinc := $(foreach lib,$(qtlibs),-I/Library/Frameworks/$(lib).framework/Versions/4/Headers)
|
|
||||||
|
|
||||||
qtlib := -L/Library/Frameworks
|
|
||||||
qtlib += $(foreach lib,$(qtlibs),-framework $(lib))
|
|
||||||
qtlib += -framework Carbon
|
|
||||||
qtlib += -framework Cocoa
|
|
||||||
qtlib += -framework OpenGL
|
|
||||||
qtlib += -framework AppKit
|
|
||||||
qtlib += -framework ApplicationServices
|
|
||||||
else ifeq ($(platform),win)
|
|
||||||
ifeq ($(qtpath),)
|
|
||||||
# find Qt install directory from PATH environment variable
|
|
||||||
qtpath := $(foreach path,$(subst ;, ,$(PATH)),$(if $(wildcard $(path)/$(moc).exe),$(path)))
|
|
||||||
qtpath := $(strip $(qtpath))
|
|
||||||
qtpath := $(subst \,/,$(qtpath))
|
|
||||||
qtpath := $(patsubst %/bin,%,$(qtpath))
|
|
||||||
endif
|
|
||||||
|
|
||||||
qtinc := -I$(qtpath)/include
|
|
||||||
qtinc += $(foreach lib,$(qtlibs),-I$(qtpath)/include/$(lib))
|
|
||||||
|
|
||||||
qtlib := -L$(qtpath)/lib
|
|
||||||
qtlib += -L$(qtpath)/plugins/imageformats
|
|
||||||
|
|
||||||
qtlib += $(foreach lib,$(qtlibs),-l$(lib)4)
|
|
||||||
qtlib += -lmingw32 -lqtmain -lcomdlg32 -loleaut32 -limm32 -lwinmm
|
|
||||||
qtlib += -lwinspool -lmsimg32 -lole32 -ladvapi32 -lws2_32 -luuid -lgdi32
|
|
||||||
qtlib += $(foreach lib,$(qtlibs),-l$(lib)4)
|
|
||||||
|
|
||||||
# optional image-file support:
|
|
||||||
# qtlib += -lqjpeg -lqmng
|
|
||||||
endif
|
|
|
@ -1,41 +0,0 @@
|
||||||
#ifndef NALL_QT_CHECKACTION_HPP
|
|
||||||
#define NALL_QT_CHECKACTION_HPP
|
|
||||||
|
|
||||||
namespace nall {
|
|
||||||
|
|
||||||
class CheckAction : public QAction {
|
|
||||||
Q_OBJECT
|
|
||||||
|
|
||||||
public:
|
|
||||||
bool isChecked() const;
|
|
||||||
void setChecked(bool);
|
|
||||||
void toggleChecked();
|
|
||||||
CheckAction(const QString&, QObject*);
|
|
||||||
|
|
||||||
protected slots:
|
|
||||||
|
|
||||||
protected:
|
|
||||||
bool checked;
|
|
||||||
};
|
|
||||||
|
|
||||||
inline bool CheckAction::isChecked() const {
|
|
||||||
return checked;
|
|
||||||
}
|
|
||||||
|
|
||||||
inline void CheckAction::setChecked(bool checked_) {
|
|
||||||
checked = checked_;
|
|
||||||
if(checked) setIcon(QIcon(":/16x16/item-check-on.png"));
|
|
||||||
else setIcon(QIcon(":/16x16/item-check-off.png"));
|
|
||||||
}
|
|
||||||
|
|
||||||
inline void CheckAction::toggleChecked() {
|
|
||||||
setChecked(!isChecked());
|
|
||||||
}
|
|
||||||
|
|
||||||
inline CheckAction::CheckAction(const QString &text, QObject *parent) : QAction(text, parent) {
|
|
||||||
setChecked(false);
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
#endif
|
|
|
@ -1,10 +0,0 @@
|
||||||
#ifndef NALL_QT_CONCEPT_HPP
|
|
||||||
#define NALL_QT_CONCEPT_HPP
|
|
||||||
|
|
||||||
#include <nall/concept.hpp>
|
|
||||||
|
|
||||||
namespace nall {
|
|
||||||
template<typename T> struct has_count<QList<T>> { enum { value = true }; };
|
|
||||||
}
|
|
||||||
|
|
||||||
#endif
|
|
|
@ -1,392 +0,0 @@
|
||||||
#ifndef NALL_QT_FILEDIALOG_HPP
|
|
||||||
#define NALL_QT_FILEDIALOG_HPP
|
|
||||||
|
|
||||||
#include <nall/platform.hpp>
|
|
||||||
#include <nall/string.hpp>
|
|
||||||
#include <nall/qt/window.moc.hpp>
|
|
||||||
|
|
||||||
namespace nall {
|
|
||||||
|
|
||||||
class FileDialog;
|
|
||||||
|
|
||||||
class NewFolderDialog : public Window {
|
|
||||||
Q_OBJECT
|
|
||||||
|
|
||||||
public:
|
|
||||||
void show();
|
|
||||||
NewFolderDialog(FileDialog*);
|
|
||||||
|
|
||||||
protected slots:
|
|
||||||
void createFolderAction();
|
|
||||||
|
|
||||||
protected:
|
|
||||||
FileDialog *parent;
|
|
||||||
QVBoxLayout *layout;
|
|
||||||
QLineEdit *folderNameEdit;
|
|
||||||
QHBoxLayout *controlLayout;
|
|
||||||
QPushButton *okButton;
|
|
||||||
QPushButton *cancelButton;
|
|
||||||
};
|
|
||||||
|
|
||||||
class FileView : public QListView {
|
|
||||||
Q_OBJECT
|
|
||||||
|
|
||||||
protected:
|
|
||||||
void keyPressEvent(QKeyEvent*);
|
|
||||||
|
|
||||||
signals:
|
|
||||||
void changed(const QModelIndex&);
|
|
||||||
void browseUp();
|
|
||||||
|
|
||||||
protected slots:
|
|
||||||
void currentChanged(const QModelIndex&, const QModelIndex&);
|
|
||||||
};
|
|
||||||
|
|
||||||
class FileDialog : public Window {
|
|
||||||
Q_OBJECT
|
|
||||||
|
|
||||||
public:
|
|
||||||
void showLoad();
|
|
||||||
void showSave();
|
|
||||||
void showFolder();
|
|
||||||
|
|
||||||
void setPath(string path);
|
|
||||||
void setNameFilters(const string &filters);
|
|
||||||
FileDialog();
|
|
||||||
|
|
||||||
signals:
|
|
||||||
void changed(const string&);
|
|
||||||
void activated(const string&);
|
|
||||||
void accepted(const string&);
|
|
||||||
void rejected();
|
|
||||||
|
|
||||||
protected slots:
|
|
||||||
void fileViewChange(const QModelIndex&);
|
|
||||||
void fileViewActivate(const QModelIndex&);
|
|
||||||
void pathBoxChanged();
|
|
||||||
void filterBoxChanged();
|
|
||||||
void createNewFolder();
|
|
||||||
void browseUp();
|
|
||||||
void acceptAction();
|
|
||||||
void rejectAction();
|
|
||||||
|
|
||||||
protected:
|
|
||||||
NewFolderDialog *newFolderDialog;
|
|
||||||
QVBoxLayout *layout;
|
|
||||||
QHBoxLayout *navigationLayout;
|
|
||||||
QComboBox *pathBox;
|
|
||||||
QPushButton *newFolderButton;
|
|
||||||
QPushButton *upFolderButton;
|
|
||||||
QHBoxLayout *browseLayout;
|
|
||||||
QFileSystemModel *fileSystemModel;
|
|
||||||
FileView *fileView;
|
|
||||||
QGroupBox *previewFrame;
|
|
||||||
QLineEdit *fileNameEdit;
|
|
||||||
QHBoxLayout *controlLayout;
|
|
||||||
QComboBox *filterBox;
|
|
||||||
QPushButton *optionsButton;
|
|
||||||
QPushButton *acceptButton;
|
|
||||||
QPushButton *rejectButton;
|
|
||||||
bool lock;
|
|
||||||
void createFolderAction(const string &name);
|
|
||||||
void closeEvent(QCloseEvent*);
|
|
||||||
|
|
||||||
friend class NewFolderDialog;
|
|
||||||
};
|
|
||||||
|
|
||||||
inline void NewFolderDialog::show() {
|
|
||||||
folderNameEdit->setText("");
|
|
||||||
Window::show();
|
|
||||||
folderNameEdit->setFocus();
|
|
||||||
}
|
|
||||||
|
|
||||||
inline void NewFolderDialog::createFolderAction() {
|
|
||||||
string name = folderNameEdit->text().toUtf8().constData();
|
|
||||||
if(name == "") {
|
|
||||||
folderNameEdit->setFocus();
|
|
||||||
} else {
|
|
||||||
parent->createFolderAction(name);
|
|
||||||
close();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
inline NewFolderDialog::NewFolderDialog(FileDialog *fileDialog) : parent(fileDialog) {
|
|
||||||
setMinimumWidth(240);
|
|
||||||
setWindowTitle("Create New Folder");
|
|
||||||
|
|
||||||
layout = new QVBoxLayout;
|
|
||||||
layout->setAlignment(Qt::AlignTop);
|
|
||||||
layout->setMargin(5);
|
|
||||||
layout->setSpacing(5);
|
|
||||||
setLayout(layout);
|
|
||||||
|
|
||||||
folderNameEdit = new QLineEdit;
|
|
||||||
layout->addWidget(folderNameEdit);
|
|
||||||
|
|
||||||
controlLayout = new QHBoxLayout;
|
|
||||||
controlLayout->setAlignment(Qt::AlignRight);
|
|
||||||
layout->addLayout(controlLayout);
|
|
||||||
|
|
||||||
okButton = new QPushButton("Ok");
|
|
||||||
controlLayout->addWidget(okButton);
|
|
||||||
|
|
||||||
cancelButton = new QPushButton("Cancel");
|
|
||||||
controlLayout->addWidget(cancelButton);
|
|
||||||
|
|
||||||
connect(folderNameEdit, SIGNAL(returnPressed()), this, SLOT(createFolderAction()));
|
|
||||||
connect(okButton, SIGNAL(released()), this, SLOT(createFolderAction()));
|
|
||||||
connect(cancelButton, SIGNAL(released()), this, SLOT(close()));
|
|
||||||
}
|
|
||||||
|
|
||||||
inline void FileView::currentChanged(const QModelIndex ¤t, const QModelIndex &previous) {
|
|
||||||
QAbstractItemView::currentChanged(current, previous);
|
|
||||||
emit changed(current);
|
|
||||||
}
|
|
||||||
|
|
||||||
inline void FileView::keyPressEvent(QKeyEvent *event) {
|
|
||||||
//enhance consistency: force OS X to act like Windows and Linux; enter = activate item
|
|
||||||
if(event->key() == Qt::Key_Return || event->key() == Qt::Key_Enter) {
|
|
||||||
emit activated(currentIndex());
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
//simulate popular file manager behavior; backspace = go up one directory
|
|
||||||
if(event->key() == Qt::Key_Backspace) {
|
|
||||||
emit browseUp();
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
//fallback: unrecognized keypresses get handled by the widget itself
|
|
||||||
QListView::keyPressEvent(event);
|
|
||||||
}
|
|
||||||
|
|
||||||
inline void FileDialog::showLoad() {
|
|
||||||
acceptButton->setText("Load");
|
|
||||||
fileNameEdit->hide();
|
|
||||||
filterBox->show();
|
|
||||||
show();
|
|
||||||
}
|
|
||||||
|
|
||||||
inline void FileDialog::showSave() {
|
|
||||||
acceptButton->setText("Save");
|
|
||||||
fileNameEdit->show();
|
|
||||||
filterBox->show();
|
|
||||||
show();
|
|
||||||
}
|
|
||||||
|
|
||||||
inline void FileDialog::showFolder() {
|
|
||||||
acceptButton->setText("Choose");
|
|
||||||
fileNameEdit->hide();
|
|
||||||
filterBox->hide();
|
|
||||||
setNameFilters("Folders ()");
|
|
||||||
show();
|
|
||||||
}
|
|
||||||
|
|
||||||
inline void FileDialog::fileViewChange(const QModelIndex &index) {
|
|
||||||
string path = fileSystemModel->filePath(index).toUtf8().constData();
|
|
||||||
if(path == fileSystemModel->rootPath().toUtf8().constData()) path = "";
|
|
||||||
fileNameEdit->setText(notdir(path));
|
|
||||||
emit changed(path);
|
|
||||||
}
|
|
||||||
|
|
||||||
inline void FileDialog::fileViewActivate(const QModelIndex &index) {
|
|
||||||
string path = fileSystemModel->filePath(index).toUtf8().constData();
|
|
||||||
if(fileSystemModel->isDir(index)) {
|
|
||||||
emit activated(path);
|
|
||||||
setPath(path);
|
|
||||||
} else {
|
|
||||||
emit activated(path);
|
|
||||||
close();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
inline void FileDialog::pathBoxChanged() {
|
|
||||||
if(lock) return;
|
|
||||||
setPath(pathBox->currentText().toUtf8().constData());
|
|
||||||
}
|
|
||||||
|
|
||||||
inline void FileDialog::filterBoxChanged() {
|
|
||||||
if(lock) return;
|
|
||||||
string filters = filterBox->currentText().toUtf8().constData();
|
|
||||||
if(filters.length() == 0) {
|
|
||||||
fileSystemModel->setNameFilters(QStringList() << "*");
|
|
||||||
} else {
|
|
||||||
filters = substr(filters, strpos(filters, "("));
|
|
||||||
ltrim(filters, "(");
|
|
||||||
rtrim(filters, ")");
|
|
||||||
lstring part;
|
|
||||||
part.split(" ", filters);
|
|
||||||
QStringList list;
|
|
||||||
for(unsigned i = 0; i < part.size(); i++) list << part[i];
|
|
||||||
fileSystemModel->setNameFilters(list);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
inline void FileDialog::createNewFolder() {
|
|
||||||
newFolderDialog->show();
|
|
||||||
}
|
|
||||||
|
|
||||||
inline void FileDialog::browseUp() {
|
|
||||||
if(pathBox->count() > 1) pathBox->setCurrentIndex(1);
|
|
||||||
}
|
|
||||||
|
|
||||||
inline void FileDialog::setPath(string path) {
|
|
||||||
lock = true;
|
|
||||||
newFolderDialog->close();
|
|
||||||
|
|
||||||
if(QDir(path).exists()) {
|
|
||||||
newFolderButton->setEnabled(true);
|
|
||||||
} else {
|
|
||||||
newFolderButton->setEnabled(false);
|
|
||||||
path = "";
|
|
||||||
}
|
|
||||||
|
|
||||||
fileSystemModel->setRootPath(path);
|
|
||||||
fileView->setRootIndex(fileSystemModel->index(path));
|
|
||||||
fileView->setCurrentIndex(fileView->rootIndex());
|
|
||||||
fileView->setFocus();
|
|
||||||
|
|
||||||
pathBox->clear();
|
|
||||||
if(path.length() > 0) {
|
|
||||||
QDir directory(path);
|
|
||||||
while(true) {
|
|
||||||
pathBox->addItem(directory.absolutePath());
|
|
||||||
if(directory.isRoot()) break;
|
|
||||||
directory.cdUp();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
pathBox->addItem("<root>");
|
|
||||||
fileNameEdit->setText("");
|
|
||||||
|
|
||||||
lock = false;
|
|
||||||
}
|
|
||||||
|
|
||||||
inline void FileDialog::setNameFilters(const string &filters) {
|
|
||||||
lock = true;
|
|
||||||
|
|
||||||
lstring list;
|
|
||||||
list.split("\n", filters);
|
|
||||||
|
|
||||||
filterBox->clear();
|
|
||||||
for(unsigned i = 0; i < list.size(); i++) {
|
|
||||||
filterBox->addItem(list[i]);
|
|
||||||
}
|
|
||||||
|
|
||||||
lock = false;
|
|
||||||
filterBoxChanged();
|
|
||||||
}
|
|
||||||
|
|
||||||
inline void FileDialog::acceptAction() {
|
|
||||||
string path = fileSystemModel->rootPath().toUtf8().constData();
|
|
||||||
path << "/" << notdir(fileNameEdit->text().toUtf8().constData());
|
|
||||||
rtrim(path, "/");
|
|
||||||
if(QDir(path).exists()) {
|
|
||||||
emit accepted(path);
|
|
||||||
setPath(path);
|
|
||||||
} else {
|
|
||||||
emit accepted(path);
|
|
||||||
close();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
inline void FileDialog::rejectAction() {
|
|
||||||
emit rejected();
|
|
||||||
close();
|
|
||||||
}
|
|
||||||
|
|
||||||
inline void FileDialog::createFolderAction(const string &name) {
|
|
||||||
string path = fileSystemModel->rootPath().toUtf8().constData();
|
|
||||||
path << "/" << notdir(name);
|
|
||||||
mkdir(path, 0755);
|
|
||||||
}
|
|
||||||
|
|
||||||
inline void FileDialog::closeEvent(QCloseEvent *event) {
|
|
||||||
newFolderDialog->close();
|
|
||||||
Window::closeEvent(event);
|
|
||||||
}
|
|
||||||
|
|
||||||
inline FileDialog::FileDialog() {
|
|
||||||
newFolderDialog = new NewFolderDialog(this);
|
|
||||||
resize(640, 360);
|
|
||||||
|
|
||||||
layout = new QVBoxLayout;
|
|
||||||
layout->setMargin(5);
|
|
||||||
layout->setSpacing(5);
|
|
||||||
setLayout(layout);
|
|
||||||
|
|
||||||
navigationLayout = new QHBoxLayout;
|
|
||||||
layout->addLayout(navigationLayout);
|
|
||||||
|
|
||||||
pathBox = new QComboBox;
|
|
||||||
pathBox->setEditable(true);
|
|
||||||
pathBox->setMinimumContentsLength(16);
|
|
||||||
pathBox->setSizeAdjustPolicy(QComboBox::AdjustToMinimumContentsLength);
|
|
||||||
pathBox->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Preferred);
|
|
||||||
navigationLayout->addWidget(pathBox);
|
|
||||||
|
|
||||||
newFolderButton = new QPushButton;
|
|
||||||
newFolderButton->setIconSize(QSize(16, 16));
|
|
||||||
newFolderButton->setIcon(QIcon(":/16x16/folder-new.png"));
|
|
||||||
navigationLayout->addWidget(newFolderButton);
|
|
||||||
|
|
||||||
upFolderButton = new QPushButton;
|
|
||||||
upFolderButton->setIconSize(QSize(16, 16));
|
|
||||||
upFolderButton->setIcon(QIcon(":/16x16/go-up.png"));
|
|
||||||
navigationLayout->addWidget(upFolderButton);
|
|
||||||
|
|
||||||
browseLayout = new QHBoxLayout;
|
|
||||||
layout->addLayout(browseLayout);
|
|
||||||
|
|
||||||
fileSystemModel = new QFileSystemModel;
|
|
||||||
fileSystemModel->setFilter(QDir::AllDirs | QDir::Files | QDir::NoDotAndDotDot);
|
|
||||||
fileSystemModel->setNameFilterDisables(false);
|
|
||||||
|
|
||||||
fileView = new FileView;
|
|
||||||
fileView->setMinimumWidth(320);
|
|
||||||
fileView->setModel(fileSystemModel);
|
|
||||||
fileView->setIconSize(QSize(16, 16));
|
|
||||||
browseLayout->addWidget(fileView);
|
|
||||||
|
|
||||||
previewFrame = new QGroupBox;
|
|
||||||
previewFrame->hide();
|
|
||||||
browseLayout->addWidget(previewFrame);
|
|
||||||
|
|
||||||
fileNameEdit = new QLineEdit;
|
|
||||||
layout->addWidget(fileNameEdit);
|
|
||||||
|
|
||||||
controlLayout = new QHBoxLayout;
|
|
||||||
controlLayout->setAlignment(Qt::AlignRight);
|
|
||||||
layout->addLayout(controlLayout);
|
|
||||||
|
|
||||||
filterBox = new QComboBox;
|
|
||||||
filterBox->setMinimumContentsLength(16);
|
|
||||||
filterBox->setSizeAdjustPolicy(QComboBox::AdjustToMinimumContentsLength);
|
|
||||||
filterBox->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Preferred);
|
|
||||||
controlLayout->addWidget(filterBox);
|
|
||||||
|
|
||||||
optionsButton = new QPushButton("Options");
|
|
||||||
optionsButton->hide();
|
|
||||||
controlLayout->addWidget(optionsButton);
|
|
||||||
|
|
||||||
acceptButton = new QPushButton("Ok");
|
|
||||||
controlLayout->addWidget(acceptButton);
|
|
||||||
|
|
||||||
rejectButton = new QPushButton("Cancel");
|
|
||||||
controlLayout->addWidget(rejectButton);
|
|
||||||
|
|
||||||
lock = false;
|
|
||||||
connect(pathBox, SIGNAL(currentIndexChanged(int)), this, SLOT(pathBoxChanged()));
|
|
||||||
connect(newFolderButton, SIGNAL(released()), this, SLOT(createNewFolder()));
|
|
||||||
connect(upFolderButton, SIGNAL(released()), this, SLOT(browseUp()));
|
|
||||||
connect(fileView, SIGNAL(changed(const QModelIndex&)), this, SLOT(fileViewChange(const QModelIndex&)));
|
|
||||||
connect(fileView, SIGNAL(activated(const QModelIndex&)), this, SLOT(fileViewActivate(const QModelIndex&)));
|
|
||||||
connect(fileView, SIGNAL(browseUp()), this, SLOT(browseUp()));
|
|
||||||
connect(fileNameEdit, SIGNAL(returnPressed()), this, SLOT(acceptAction()));
|
|
||||||
connect(filterBox, SIGNAL(currentIndexChanged(int)), this, SLOT(filterBoxChanged()));
|
|
||||||
connect(acceptButton, SIGNAL(released()), this, SLOT(acceptAction()));
|
|
||||||
connect(rejectButton, SIGNAL(released()), this, SLOT(rejectAction()));
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
#endif
|
|
|
@ -1,173 +0,0 @@
|
||||||
#ifndef NALL_QT_HEXEDITOR_HPP
|
|
||||||
#define NALL_QT_HEXEDITOR_HPP
|
|
||||||
|
|
||||||
#include <nall/function.hpp>
|
|
||||||
#include <nall/stdint.hpp>
|
|
||||||
#include <nall/string.hpp>
|
|
||||||
|
|
||||||
namespace nall {
|
|
||||||
|
|
||||||
class HexEditor : public QTextEdit {
|
|
||||||
Q_OBJECT
|
|
||||||
|
|
||||||
public:
|
|
||||||
function<uint8_t (unsigned)> reader;
|
|
||||||
function<void (unsigned, uint8_t)> writer;
|
|
||||||
|
|
||||||
void setColumns(unsigned columns);
|
|
||||||
void setRows(unsigned rows);
|
|
||||||
void setOffset(unsigned offset);
|
|
||||||
void setSize(unsigned size);
|
|
||||||
unsigned lineWidth() const;
|
|
||||||
void refresh();
|
|
||||||
|
|
||||||
HexEditor();
|
|
||||||
|
|
||||||
protected slots:
|
|
||||||
void scrolled();
|
|
||||||
|
|
||||||
protected:
|
|
||||||
QHBoxLayout *layout;
|
|
||||||
QScrollBar *scrollBar;
|
|
||||||
unsigned editorColumns;
|
|
||||||
unsigned editorRows;
|
|
||||||
unsigned editorOffset;
|
|
||||||
unsigned editorSize;
|
|
||||||
bool lock;
|
|
||||||
|
|
||||||
void keyPressEvent(QKeyEvent*);
|
|
||||||
};
|
|
||||||
|
|
||||||
inline void HexEditor::keyPressEvent(QKeyEvent *event) {
|
|
||||||
QTextCursor cursor = textCursor();
|
|
||||||
unsigned x = cursor.position() % lineWidth();
|
|
||||||
unsigned y = cursor.position() / lineWidth();
|
|
||||||
|
|
||||||
int hexCode = -1;
|
|
||||||
switch(event->key()) {
|
|
||||||
case Qt::Key_0: hexCode = 0; break;
|
|
||||||
case Qt::Key_1: hexCode = 1; break;
|
|
||||||
case Qt::Key_2: hexCode = 2; break;
|
|
||||||
case Qt::Key_3: hexCode = 3; break;
|
|
||||||
case Qt::Key_4: hexCode = 4; break;
|
|
||||||
case Qt::Key_5: hexCode = 5; break;
|
|
||||||
case Qt::Key_6: hexCode = 6; break;
|
|
||||||
case Qt::Key_7: hexCode = 7; break;
|
|
||||||
case Qt::Key_8: hexCode = 8; break;
|
|
||||||
case Qt::Key_9: hexCode = 9; break;
|
|
||||||
case Qt::Key_A: hexCode = 10; break;
|
|
||||||
case Qt::Key_B: hexCode = 11; break;
|
|
||||||
case Qt::Key_C: hexCode = 12; break;
|
|
||||||
case Qt::Key_D: hexCode = 13; break;
|
|
||||||
case Qt::Key_E: hexCode = 14; break;
|
|
||||||
case Qt::Key_F: hexCode = 15; break;
|
|
||||||
}
|
|
||||||
|
|
||||||
if(cursor.hasSelection() == false && hexCode != -1) {
|
|
||||||
bool cursorOffsetValid = (x >= 11 && ((x - 11) % 3) != 2);
|
|
||||||
if(cursorOffsetValid) {
|
|
||||||
bool nibble = (x - 11) % 3; //0 = top nibble, 1 = bottom nibble
|
|
||||||
unsigned cursorOffset = y * editorColumns + ((x - 11) / 3);
|
|
||||||
unsigned effectiveOffset = editorOffset + cursorOffset;
|
|
||||||
if(effectiveOffset >= editorSize) effectiveOffset %= editorSize;
|
|
||||||
|
|
||||||
uint8_t data = reader ? reader(effectiveOffset) : 0x00;
|
|
||||||
data &= (nibble == 0 ? 0x0f : 0xf0);
|
|
||||||
data |= (nibble == 0 ? (hexCode << 4) : (hexCode << 0));
|
|
||||||
if(writer) writer(effectiveOffset, data);
|
|
||||||
refresh();
|
|
||||||
|
|
||||||
cursor.setPosition(y * lineWidth() + x + 1); //advance cursor
|
|
||||||
setTextCursor(cursor);
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
//allow navigation keys to move cursor, but block text input
|
|
||||||
setTextInteractionFlags(Qt::TextSelectableByKeyboard | Qt::TextSelectableByMouse);
|
|
||||||
QTextEdit::keyPressEvent(event);
|
|
||||||
setTextInteractionFlags(Qt::TextEditorInteraction);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
inline void HexEditor::setColumns(unsigned columns) {
|
|
||||||
editorColumns = columns;
|
|
||||||
}
|
|
||||||
|
|
||||||
inline void HexEditor::setRows(unsigned rows) {
|
|
||||||
editorRows = rows;
|
|
||||||
scrollBar->setPageStep(editorRows);
|
|
||||||
}
|
|
||||||
|
|
||||||
inline void HexEditor::setOffset(unsigned offset) {
|
|
||||||
lock = true;
|
|
||||||
editorOffset = offset;
|
|
||||||
scrollBar->setSliderPosition(editorOffset / editorColumns);
|
|
||||||
lock = false;
|
|
||||||
}
|
|
||||||
|
|
||||||
inline void HexEditor::setSize(unsigned size) {
|
|
||||||
editorSize = size;
|
|
||||||
bool indivisible = (editorSize % editorColumns) != 0; //add one for incomplete row
|
|
||||||
scrollBar->setRange(0, editorSize / editorColumns + indivisible - editorRows);
|
|
||||||
}
|
|
||||||
|
|
||||||
inline unsigned HexEditor::lineWidth() const {
|
|
||||||
return 11 + 3 * editorColumns;
|
|
||||||
}
|
|
||||||
|
|
||||||
inline void HexEditor::refresh() {
|
|
||||||
string output;
|
|
||||||
char temp[256];
|
|
||||||
unsigned offset = editorOffset;
|
|
||||||
|
|
||||||
for(unsigned y = 0; y < editorRows; y++) {
|
|
||||||
if(offset >= editorSize) break;
|
|
||||||
sprintf(temp, "%.4x:%.4x", (offset >> 16) & 0xffff, (offset >> 0) & 0xffff);
|
|
||||||
output << "<font color='#808080'>" << temp << "</font> ";
|
|
||||||
|
|
||||||
for(unsigned x = 0; x < editorColumns; x++) {
|
|
||||||
if(offset >= editorSize) break;
|
|
||||||
sprintf(temp, "%.2x", reader ? reader(offset) : 0x00);
|
|
||||||
offset++;
|
|
||||||
output << "<font color='" << ((x & 1) ? "#000080" : "#0000ff") << "'>" << temp << "</font>";
|
|
||||||
if(x != (editorColumns - 1)) output << " ";
|
|
||||||
}
|
|
||||||
|
|
||||||
if(y != (editorRows - 1)) output << "<br>";
|
|
||||||
}
|
|
||||||
|
|
||||||
setHtml(output);
|
|
||||||
}
|
|
||||||
|
|
||||||
inline void HexEditor::scrolled() {
|
|
||||||
if(lock) return;
|
|
||||||
unsigned offset = scrollBar->sliderPosition();
|
|
||||||
editorOffset = offset * editorColumns;
|
|
||||||
refresh();
|
|
||||||
}
|
|
||||||
|
|
||||||
inline HexEditor::HexEditor() {
|
|
||||||
setHorizontalScrollBarPolicy(Qt::ScrollBarAlwaysOff);
|
|
||||||
setVerticalScrollBarPolicy(Qt::ScrollBarAlwaysOff);
|
|
||||||
|
|
||||||
layout = new QHBoxLayout;
|
|
||||||
layout->setAlignment(Qt::AlignRight);
|
|
||||||
layout->setMargin(0);
|
|
||||||
layout->setSpacing(0);
|
|
||||||
setLayout(layout);
|
|
||||||
|
|
||||||
scrollBar = new QScrollBar(Qt::Vertical);
|
|
||||||
scrollBar->setSingleStep(1);
|
|
||||||
layout->addWidget(scrollBar);
|
|
||||||
|
|
||||||
lock = false;
|
|
||||||
connect(scrollBar, SIGNAL(actionTriggered(int)), this, SLOT(scrolled()));
|
|
||||||
|
|
||||||
setColumns(16);
|
|
||||||
setRows(16);
|
|
||||||
setSize(0);
|
|
||||||
setOffset(0);
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
#endif
|
|
|
@ -1,41 +0,0 @@
|
||||||
#ifndef NALL_QT_RADIOACTION_HPP
|
|
||||||
#define NALL_QT_RADIOACTION_HPP
|
|
||||||
|
|
||||||
namespace nall {
|
|
||||||
|
|
||||||
class RadioAction : public QAction {
|
|
||||||
Q_OBJECT
|
|
||||||
|
|
||||||
public:
|
|
||||||
bool isChecked() const;
|
|
||||||
void setChecked(bool);
|
|
||||||
void toggleChecked();
|
|
||||||
RadioAction(const QString&, QObject*);
|
|
||||||
|
|
||||||
protected slots:
|
|
||||||
|
|
||||||
protected:
|
|
||||||
bool checked;
|
|
||||||
};
|
|
||||||
|
|
||||||
inline bool RadioAction::isChecked() const {
|
|
||||||
return checked;
|
|
||||||
}
|
|
||||||
|
|
||||||
inline void RadioAction::setChecked(bool checked_) {
|
|
||||||
checked = checked_;
|
|
||||||
if(checked) setIcon(QIcon(":/16x16/item-radio-on.png"));
|
|
||||||
else setIcon(QIcon(":/16x16/item-radio-off.png"));
|
|
||||||
}
|
|
||||||
|
|
||||||
inline void RadioAction::toggleChecked() {
|
|
||||||
setChecked(!isChecked());
|
|
||||||
}
|
|
||||||
|
|
||||||
inline RadioAction::RadioAction(const QString &text, QObject *parent) : QAction(text, parent) {
|
|
||||||
setChecked(false);
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
#endif
|
|
|
@ -1,105 +0,0 @@
|
||||||
#ifndef NALL_QT_WINDOW_HPP
|
|
||||||
#define NALL_QT_WINDOW_HPP
|
|
||||||
|
|
||||||
#include <nall/base64.hpp>
|
|
||||||
#include <nall/string.hpp>
|
|
||||||
|
|
||||||
namespace nall {
|
|
||||||
|
|
||||||
class Window : public QWidget {
|
|
||||||
Q_OBJECT
|
|
||||||
|
|
||||||
public:
|
|
||||||
void setGeometryString(string *geometryString);
|
|
||||||
void setCloseOnEscape(bool);
|
|
||||||
void show();
|
|
||||||
void hide();
|
|
||||||
void shrink();
|
|
||||||
|
|
||||||
Window();
|
|
||||||
|
|
||||||
protected slots:
|
|
||||||
|
|
||||||
protected:
|
|
||||||
string *geometryString;
|
|
||||||
bool closeOnEscape;
|
|
||||||
void keyReleaseEvent(QKeyEvent *event);
|
|
||||||
void closeEvent(QCloseEvent *event);
|
|
||||||
};
|
|
||||||
|
|
||||||
inline void Window::setGeometryString(string *geometryString_) {
|
|
||||||
geometryString = geometryString_;
|
|
||||||
if(geometryString && isVisible() == false) {
|
|
||||||
uint8_t *data;
|
|
||||||
unsigned length;
|
|
||||||
base64::decode(data, length, *geometryString);
|
|
||||||
QByteArray array((const char*)data, length);
|
|
||||||
delete[] data;
|
|
||||||
restoreGeometry(array);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
inline void Window::setCloseOnEscape(bool value) {
|
|
||||||
closeOnEscape = value;
|
|
||||||
}
|
|
||||||
|
|
||||||
inline void Window::show() {
|
|
||||||
if(geometryString && isVisible() == false) {
|
|
||||||
uint8_t *data;
|
|
||||||
unsigned length;
|
|
||||||
base64::decode(data, length, *geometryString);
|
|
||||||
QByteArray array((const char*)data, length);
|
|
||||||
delete[] data;
|
|
||||||
restoreGeometry(array);
|
|
||||||
}
|
|
||||||
QWidget::show();
|
|
||||||
QApplication::processEvents();
|
|
||||||
activateWindow();
|
|
||||||
raise();
|
|
||||||
}
|
|
||||||
|
|
||||||
inline void Window::hide() {
|
|
||||||
if(geometryString && isVisible() == true) {
|
|
||||||
char *data;
|
|
||||||
QByteArray geometry = saveGeometry();
|
|
||||||
base64::encode(data, (const uint8_t*)geometry.data(), geometry.length());
|
|
||||||
*geometryString = data;
|
|
||||||
delete[] data;
|
|
||||||
}
|
|
||||||
QWidget::hide();
|
|
||||||
}
|
|
||||||
|
|
||||||
inline void Window::shrink() {
|
|
||||||
if(isFullScreen()) return;
|
|
||||||
|
|
||||||
for(unsigned i = 0; i < 2; i++) {
|
|
||||||
resize(0, 0);
|
|
||||||
usleep(2000);
|
|
||||||
QApplication::processEvents();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
inline void Window::keyReleaseEvent(QKeyEvent *event) {
|
|
||||||
if(closeOnEscape && (event->key() == Qt::Key_Escape)) close();
|
|
||||||
QWidget::keyReleaseEvent(event);
|
|
||||||
}
|
|
||||||
|
|
||||||
inline void Window::closeEvent(QCloseEvent *event) {
|
|
||||||
if(geometryString) {
|
|
||||||
char *data;
|
|
||||||
QByteArray geometry = saveGeometry();
|
|
||||||
base64::encode(data, (const uint8_t*)geometry.data(), geometry.length());
|
|
||||||
*geometryString = data;
|
|
||||||
delete[] data;
|
|
||||||
}
|
|
||||||
QWidget::closeEvent(event);
|
|
||||||
}
|
|
||||||
|
|
||||||
inline Window::Window() {
|
|
||||||
geometryString = 0;
|
|
||||||
closeOnEscape = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
#endif
|
|
|
@ -1,80 +0,0 @@
|
||||||
#ifndef NALL_SERIAL_HPP
|
|
||||||
#define NALL_SERIAL_HPP
|
|
||||||
|
|
||||||
#include <sys/ioctl.h>
|
|
||||||
#include <fcntl.h>
|
|
||||||
#include <termios.h>
|
|
||||||
#include <unistd.h>
|
|
||||||
|
|
||||||
#include <nall/stdint.hpp>
|
|
||||||
|
|
||||||
namespace nall {
|
|
||||||
class serial {
|
|
||||||
public:
|
|
||||||
//-1 on error, otherwise return bytes read
|
|
||||||
int read(uint8_t *data, unsigned length) {
|
|
||||||
if(port_open == false) return -1;
|
|
||||||
return ::read(port, (void*)data, length);
|
|
||||||
}
|
|
||||||
|
|
||||||
//-1 on error, otherwise return bytes written
|
|
||||||
int write(const uint8_t *data, unsigned length) {
|
|
||||||
if(port_open == false) return -1;
|
|
||||||
return ::write(port, (void*)data, length);
|
|
||||||
}
|
|
||||||
|
|
||||||
bool open(const char *portname, unsigned rate) {
|
|
||||||
close();
|
|
||||||
|
|
||||||
port = ::open(portname, O_RDWR | O_NOCTTY | O_NDELAY | O_NONBLOCK);
|
|
||||||
if(port == -1) return false;
|
|
||||||
|
|
||||||
if(ioctl(port, TIOCEXCL) == -1) { close(); return false; }
|
|
||||||
if(fcntl(port, F_SETFL, 0) == -1) { close(); return false; }
|
|
||||||
if(tcgetattr(port, &original_attr) == -1) { close(); return false; }
|
|
||||||
|
|
||||||
termios attr = original_attr;
|
|
||||||
cfmakeraw(&attr);
|
|
||||||
cfsetspeed(&attr, rate);
|
|
||||||
|
|
||||||
attr.c_lflag &=~ (ECHO | ECHONL | ISIG | ICANON | IEXTEN);
|
|
||||||
attr.c_iflag &=~ (BRKINT | PARMRK | INPCK | ISTRIP | INLCR | IGNCR | ICRNL | IXON | IXOFF | IXANY);
|
|
||||||
attr.c_iflag |= (IGNBRK | IGNPAR);
|
|
||||||
attr.c_oflag &=~ (OPOST);
|
|
||||||
attr.c_cflag &=~ (CSIZE | CSTOPB | PARENB);
|
|
||||||
attr.c_cflag |= (CS8 | CREAD | CLOCAL);
|
|
||||||
attr.c_cc[VTIME] = attr.c_cc[VMIN] = 0;
|
|
||||||
|
|
||||||
if(tcsetattr(port, TCSANOW, &attr) == -1) { close(); return false; }
|
|
||||||
return port_open = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
void close() {
|
|
||||||
if(port != -1) {
|
|
||||||
tcdrain(port);
|
|
||||||
if(port_open == true) {
|
|
||||||
tcsetattr(port, TCSANOW, &original_attr);
|
|
||||||
port_open = false;
|
|
||||||
}
|
|
||||||
::close(port);
|
|
||||||
port = -1;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
serial() {
|
|
||||||
port = -1;
|
|
||||||
port_open = false;
|
|
||||||
}
|
|
||||||
|
|
||||||
~serial() {
|
|
||||||
close();
|
|
||||||
}
|
|
||||||
|
|
||||||
private:
|
|
||||||
int port;
|
|
||||||
bool port_open;
|
|
||||||
termios original_attr;
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
#endif
|
|
|
@ -1,143 +0,0 @@
|
||||||
#ifndef NALL_SERIALIZER_HPP
|
|
||||||
#define NALL_SERIALIZER_HPP
|
|
||||||
|
|
||||||
#include <nall/stdint.hpp>
|
|
||||||
#include <nall/traits.hpp>
|
|
||||||
#include <nall/utility.hpp>
|
|
||||||
|
|
||||||
namespace nall {
|
|
||||||
//serializer: a class designed to save and restore the state of classes.
|
|
||||||
//
|
|
||||||
//benefits:
|
|
||||||
//- data() will be portable in size (it is not necessary to specify type sizes.)
|
|
||||||
//- data() will be portable in endianness (always stored internally as little-endian.)
|
|
||||||
//- one serialize function can both save and restore class states.
|
|
||||||
//
|
|
||||||
//caveats:
|
|
||||||
//- only plain-old-data can be stored. complex classes must provide serialize(serializer&);
|
|
||||||
//- floating-point usage is not portable across platforms
|
|
||||||
class serializer {
|
|
||||||
public:
|
|
||||||
enum mode_t { Load, Save, Size };
|
|
||||||
|
|
||||||
mode_t mode() const {
|
|
||||||
return imode;
|
|
||||||
}
|
|
||||||
|
|
||||||
const uint8_t* data() const {
|
|
||||||
return idata;
|
|
||||||
}
|
|
||||||
|
|
||||||
unsigned size() const {
|
|
||||||
return isize;
|
|
||||||
}
|
|
||||||
|
|
||||||
unsigned capacity() const {
|
|
||||||
return icapacity;
|
|
||||||
}
|
|
||||||
|
|
||||||
template<typename T> void floatingpoint(T &value) {
|
|
||||||
enum { size = sizeof(T) };
|
|
||||||
//this is rather dangerous, and not cross-platform safe;
|
|
||||||
//but there is no standardized way to export FP-values
|
|
||||||
uint8_t *p = (uint8_t*)&value;
|
|
||||||
if(imode == Save) {
|
|
||||||
for(unsigned n = 0; n < size; n++) idata[isize++] = p[n];
|
|
||||||
} else if(imode == Load) {
|
|
||||||
for(unsigned n = 0; n < size; n++) p[n] = idata[isize++];
|
|
||||||
} else {
|
|
||||||
isize += size;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
template<typename T> void integer(T &value) {
|
|
||||||
enum { size = is_bool<T>::value ? 1 : sizeof(T) };
|
|
||||||
if(imode == Save) {
|
|
||||||
for(unsigned n = 0; n < size; n++) idata[isize++] = value >> (n << 3);
|
|
||||||
} else if(imode == Load) {
|
|
||||||
value = 0;
|
|
||||||
for(unsigned n = 0; n < size; n++) value |= idata[isize++] << (n << 3);
|
|
||||||
} else if(imode == Size) {
|
|
||||||
isize += size;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
template<typename T> void array(T &array) {
|
|
||||||
enum { size = sizeof(T) / sizeof(typename remove_extent<T>::type) };
|
|
||||||
for(unsigned n = 0; n < size; n++) integer(array[n]);
|
|
||||||
}
|
|
||||||
|
|
||||||
template<typename T> void array(T array, unsigned size) {
|
|
||||||
for(unsigned n = 0; n < size; n++) integer(array[n]);
|
|
||||||
}
|
|
||||||
|
|
||||||
//copy
|
|
||||||
serializer& operator=(const serializer &s) {
|
|
||||||
if(idata) delete[] idata;
|
|
||||||
|
|
||||||
imode = s.imode;
|
|
||||||
idata = new uint8_t[s.icapacity];
|
|
||||||
isize = s.isize;
|
|
||||||
icapacity = s.icapacity;
|
|
||||||
|
|
||||||
memcpy(idata, s.idata, s.icapacity);
|
|
||||||
return *this;
|
|
||||||
}
|
|
||||||
|
|
||||||
serializer(const serializer &s) : idata(0) {
|
|
||||||
operator=(s);
|
|
||||||
}
|
|
||||||
|
|
||||||
//move
|
|
||||||
serializer& operator=(serializer &&s) {
|
|
||||||
if(idata) delete[] idata;
|
|
||||||
|
|
||||||
imode = s.imode;
|
|
||||||
idata = s.idata;
|
|
||||||
isize = s.isize;
|
|
||||||
icapacity = s.icapacity;
|
|
||||||
|
|
||||||
s.idata = 0;
|
|
||||||
return *this;
|
|
||||||
}
|
|
||||||
|
|
||||||
serializer(serializer &&s) {
|
|
||||||
operator=(move(s));
|
|
||||||
}
|
|
||||||
|
|
||||||
//construction
|
|
||||||
serializer() {
|
|
||||||
imode = Size;
|
|
||||||
idata = 0;
|
|
||||||
isize = 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
serializer(unsigned capacity) {
|
|
||||||
imode = Save;
|
|
||||||
idata = new uint8_t[capacity]();
|
|
||||||
isize = 0;
|
|
||||||
icapacity = capacity;
|
|
||||||
}
|
|
||||||
|
|
||||||
serializer(const uint8_t *data, unsigned capacity) {
|
|
||||||
imode = Load;
|
|
||||||
idata = new uint8_t[capacity];
|
|
||||||
isize = 0;
|
|
||||||
icapacity = capacity;
|
|
||||||
memcpy(idata, data, capacity);
|
|
||||||
}
|
|
||||||
|
|
||||||
~serializer() {
|
|
||||||
if(idata) delete[] idata;
|
|
||||||
}
|
|
||||||
|
|
||||||
private:
|
|
||||||
mode_t imode;
|
|
||||||
uint8_t *idata;
|
|
||||||
unsigned isize;
|
|
||||||
unsigned icapacity;
|
|
||||||
};
|
|
||||||
|
|
||||||
};
|
|
||||||
|
|
||||||
#endif
|
|
|
@ -1,143 +0,0 @@
|
||||||
#ifndef NALL_SHA256_HPP
|
|
||||||
#define NALL_SHA256_HPP
|
|
||||||
|
|
||||||
//author: vladitx
|
|
||||||
|
|
||||||
namespace nall {
|
|
||||||
#define PTR(t, a) ((t*)(a))
|
|
||||||
|
|
||||||
#define SWAP32(x) ((uint32_t)( \
|
|
||||||
(((uint32_t)(x) & 0x000000ff) << 24) | \
|
|
||||||
(((uint32_t)(x) & 0x0000ff00) << 8) | \
|
|
||||||
(((uint32_t)(x) & 0x00ff0000) >> 8) | \
|
|
||||||
(((uint32_t)(x) & 0xff000000) >> 24) \
|
|
||||||
))
|
|
||||||
|
|
||||||
#define ST32(a, d) *PTR(uint32_t, a) = (d)
|
|
||||||
#define ST32BE(a, d) ST32(a, SWAP32(d))
|
|
||||||
|
|
||||||
#define LD32(a) *PTR(uint32_t, a)
|
|
||||||
#define LD32BE(a) SWAP32(LD32(a))
|
|
||||||
|
|
||||||
#define LSL32(x, n) ((uint32_t)(x) << (n))
|
|
||||||
#define LSR32(x, n) ((uint32_t)(x) >> (n))
|
|
||||||
#define ROR32(x, n) (LSR32(x, n) | LSL32(x, 32 - (n)))
|
|
||||||
|
|
||||||
//first 32 bits of the fractional parts of the square roots of the first 8 primes 2..19
|
|
||||||
static const uint32_t T_H[8] = {
|
|
||||||
0x6a09e667, 0xbb67ae85, 0x3c6ef372, 0xa54ff53a, 0x510e527f, 0x9b05688c, 0x1f83d9ab, 0x5be0cd19,
|
|
||||||
};
|
|
||||||
|
|
||||||
//first 32 bits of the fractional parts of the cube roots of the first 64 primes 2..311
|
|
||||||
static const uint32_t T_K[64] = {
|
|
||||||
0x428a2f98, 0x71374491, 0xb5c0fbcf, 0xe9b5dba5, 0x3956c25b, 0x59f111f1, 0x923f82a4, 0xab1c5ed5,
|
|
||||||
0xd807aa98, 0x12835b01, 0x243185be, 0x550c7dc3, 0x72be5d74, 0x80deb1fe, 0x9bdc06a7, 0xc19bf174,
|
|
||||||
0xe49b69c1, 0xefbe4786, 0x0fc19dc6, 0x240ca1cc, 0x2de92c6f, 0x4a7484aa, 0x5cb0a9dc, 0x76f988da,
|
|
||||||
0x983e5152, 0xa831c66d, 0xb00327c8, 0xbf597fc7, 0xc6e00bf3, 0xd5a79147, 0x06ca6351, 0x14292967,
|
|
||||||
0x27b70a85, 0x2e1b2138, 0x4d2c6dfc, 0x53380d13, 0x650a7354, 0x766a0abb, 0x81c2c92e, 0x92722c85,
|
|
||||||
0xa2bfe8a1, 0xa81a664b, 0xc24b8b70, 0xc76c51a3, 0xd192e819, 0xd6990624, 0xf40e3585, 0x106aa070,
|
|
||||||
0x19a4c116, 0x1e376c08, 0x2748774c, 0x34b0bcb5, 0x391c0cb3, 0x4ed8aa4a, 0x5b9cca4f, 0x682e6ff3,
|
|
||||||
0x748f82ee, 0x78a5636f, 0x84c87814, 0x8cc70208, 0x90befffa, 0xa4506ceb, 0xbef9a3f7, 0xc67178f2,
|
|
||||||
};
|
|
||||||
|
|
||||||
struct sha256_ctx {
|
|
||||||
uint8_t in[64];
|
|
||||||
unsigned inlen;
|
|
||||||
|
|
||||||
uint32_t w[64];
|
|
||||||
uint32_t h[8];
|
|
||||||
uint64_t len;
|
|
||||||
};
|
|
||||||
|
|
||||||
void sha256_init(sha256_ctx *p) {
|
|
||||||
memset(p, 0, sizeof(sha256_ctx));
|
|
||||||
memcpy(p->h, T_H, sizeof(T_H));
|
|
||||||
}
|
|
||||||
|
|
||||||
static void sha256_block(sha256_ctx *p) {
|
|
||||||
unsigned i;
|
|
||||||
uint32_t s0, s1;
|
|
||||||
uint32_t a, b, c, d, e, f, g, h;
|
|
||||||
uint32_t t1, t2, maj, ch;
|
|
||||||
|
|
||||||
for(i = 0; i < 16; i++) p->w[i] = LD32BE(p->in + i * 4);
|
|
||||||
|
|
||||||
for(i = 16; i < 64; i++) {
|
|
||||||
s0 = ROR32(p->w[i - 15], 7) ^ ROR32(p->w[i - 15], 18) ^ LSR32(p->w[i - 15], 3);
|
|
||||||
s1 = ROR32(p->w[i - 2], 17) ^ ROR32(p->w[i - 2], 19) ^ LSR32(p->w[i - 2], 10);
|
|
||||||
p->w[i] = p->w[i - 16] + s0 + p->w[i - 7] + s1;
|
|
||||||
}
|
|
||||||
|
|
||||||
a = p->h[0]; b = p->h[1]; c = p->h[2]; d = p->h[3];
|
|
||||||
e = p->h[4]; f = p->h[5]; g = p->h[6]; h = p->h[7];
|
|
||||||
|
|
||||||
for(i = 0; i < 64; i++) {
|
|
||||||
s0 = ROR32(a, 2) ^ ROR32(a, 13) ^ ROR32(a, 22);
|
|
||||||
maj = (a & b) ^ (a & c) ^ (b & c);
|
|
||||||
t2 = s0 + maj;
|
|
||||||
s1 = ROR32(e, 6) ^ ROR32(e, 11) ^ ROR32(e, 25);
|
|
||||||
ch = (e & f) ^ (~e & g);
|
|
||||||
t1 = h + s1 + ch + T_K[i] + p->w[i];
|
|
||||||
|
|
||||||
h = g; g = f; f = e; e = d + t1;
|
|
||||||
d = c; c = b; b = a; a = t1 + t2;
|
|
||||||
}
|
|
||||||
|
|
||||||
p->h[0] += a; p->h[1] += b; p->h[2] += c; p->h[3] += d;
|
|
||||||
p->h[4] += e; p->h[5] += f; p->h[6] += g; p->h[7] += h;
|
|
||||||
|
|
||||||
//next block
|
|
||||||
p->inlen = 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
void sha256_chunk(sha256_ctx *p, const uint8_t *s, unsigned len) {
|
|
||||||
unsigned l;
|
|
||||||
p->len += len;
|
|
||||||
|
|
||||||
while(len) {
|
|
||||||
l = 64 - p->inlen;
|
|
||||||
l = (len < l) ? len : l;
|
|
||||||
|
|
||||||
memcpy(p->in + p->inlen, s, l);
|
|
||||||
s += l;
|
|
||||||
p->inlen += l;
|
|
||||||
len -= l;
|
|
||||||
|
|
||||||
if(p->inlen == 64) sha256_block(p);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void sha256_final(sha256_ctx *p) {
|
|
||||||
uint64_t len;
|
|
||||||
p->in[p->inlen++] = 0x80;
|
|
||||||
|
|
||||||
if(p->inlen > 56) {
|
|
||||||
memset(p->in + p->inlen, 0, 64 - p->inlen);
|
|
||||||
sha256_block(p);
|
|
||||||
}
|
|
||||||
|
|
||||||
memset(p->in + p->inlen, 0, 56 - p->inlen);
|
|
||||||
|
|
||||||
len = p->len << 3;
|
|
||||||
ST32BE(p->in + 56, len >> 32);
|
|
||||||
ST32BE(p->in + 60, len);
|
|
||||||
sha256_block(p);
|
|
||||||
}
|
|
||||||
|
|
||||||
void sha256_hash(sha256_ctx *p, uint8_t *s) {
|
|
||||||
uint32_t *t = (uint32_t*)s;
|
|
||||||
for(unsigned i = 0; i < 8; i++) ST32BE(t++, p->h[i]);
|
|
||||||
}
|
|
||||||
|
|
||||||
#undef PTR
|
|
||||||
#undef SWAP32
|
|
||||||
#undef ST32
|
|
||||||
#undef ST32BE
|
|
||||||
#undef LD32
|
|
||||||
#undef LD32BE
|
|
||||||
#undef LSL32
|
|
||||||
#undef LSR32
|
|
||||||
#undef ROR32
|
|
||||||
}
|
|
||||||
|
|
||||||
#endif
|
|
|
@ -1,62 +0,0 @@
|
||||||
#ifndef NALL_SORT_HPP
|
|
||||||
#define NALL_SORT_HPP
|
|
||||||
|
|
||||||
#include <nall/utility.hpp>
|
|
||||||
|
|
||||||
//class: merge sort
|
|
||||||
//average: O(n log n)
|
|
||||||
//worst: O(n log n)
|
|
||||||
//memory: O(n)
|
|
||||||
//stack: O(log n)
|
|
||||||
//stable?: yes
|
|
||||||
|
|
||||||
//notes:
|
|
||||||
//there are two primary reasons for choosing merge sort
|
|
||||||
//over the (usually) faster quick sort*:
|
|
||||||
//1: it is a stable sort.
|
|
||||||
//2: it lacks O(n^2) worst-case overhead.
|
|
||||||
//(* which is also O(n log n) in the average case.)
|
|
||||||
|
|
||||||
namespace nall {
|
|
||||||
template<typename T>
|
|
||||||
void sort(T list[], unsigned length) {
|
|
||||||
if(length <= 1) return; //nothing to sort
|
|
||||||
|
|
||||||
//use insertion sort to quickly sort smaller blocks
|
|
||||||
if(length < 64) {
|
|
||||||
for(unsigned i = 0; i < length; i++) {
|
|
||||||
unsigned min = i;
|
|
||||||
for(unsigned j = i + 1; j < length; j++) {
|
|
||||||
if(list[j] < list[min]) min = j;
|
|
||||||
}
|
|
||||||
if(min != i) swap(list[i], list[min]);
|
|
||||||
}
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
//split list in half and recursively sort both
|
|
||||||
unsigned middle = length / 2;
|
|
||||||
sort(list, middle);
|
|
||||||
sort(list + middle, length - middle);
|
|
||||||
|
|
||||||
//left and right are sorted here; perform merge sort
|
|
||||||
T *buffer = new T[length];
|
|
||||||
unsigned offset = 0;
|
|
||||||
unsigned left = 0;
|
|
||||||
unsigned right = middle;
|
|
||||||
while(left < middle && right < length) {
|
|
||||||
if(list[left] < list[right]) {
|
|
||||||
buffer[offset++] = list[left++];
|
|
||||||
} else {
|
|
||||||
buffer[offset++] = list[right++];
|
|
||||||
}
|
|
||||||
}
|
|
||||||
while(left < middle) buffer[offset++] = list[left++];
|
|
||||||
while(right < length) buffer[offset++] = list[right++];
|
|
||||||
|
|
||||||
for(unsigned i = 0; i < length; i++) list[i] = buffer[i];
|
|
||||||
delete[] buffer;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#endif
|
|
|
@ -1,20 +0,0 @@
|
||||||
#ifndef NALL_STATIC_HPP
|
|
||||||
#define NALL_STATIC_HPP
|
|
||||||
|
|
||||||
namespace nall {
|
|
||||||
template<bool C, typename T, typename F> struct static_if { typedef T type; };
|
|
||||||
template<typename T, typename F> struct static_if<false, T, F> { typedef F type; };
|
|
||||||
template<typename C, typename T, typename F> struct mp_static_if { typedef typename static_if<C::type, T, F>::type type; };
|
|
||||||
|
|
||||||
template<bool A, bool B> struct static_and { enum { value = false }; };
|
|
||||||
template<> struct static_and<true, true> { enum { value = true }; };
|
|
||||||
template<typename A, typename B> struct mp_static_and { enum { value = static_and<A::value, B::value>::value }; };
|
|
||||||
|
|
||||||
template<bool A, bool B> struct static_or { enum { value = false }; };
|
|
||||||
template<> struct static_or<false, true> { enum { value = true }; };
|
|
||||||
template<> struct static_or<true, false> { enum { value = true }; };
|
|
||||||
template<> struct static_or<true, true> { enum { value = true }; };
|
|
||||||
template<typename A, typename B> struct mp_static_or { enum { value = static_or<A::value, B::value>::value }; };
|
|
||||||
}
|
|
||||||
|
|
||||||
#endif
|
|
|
@ -1,44 +0,0 @@
|
||||||
#ifndef NALL_STDINT_HPP
|
|
||||||
#define NALL_STDINT_HPP
|
|
||||||
|
|
||||||
#include <nall/static.hpp>
|
|
||||||
|
|
||||||
#if defined(_MSC_VER)
|
|
||||||
typedef signed char int8_t;
|
|
||||||
typedef signed short int16_t;
|
|
||||||
typedef signed int int32_t;
|
|
||||||
typedef signed long long int64_t;
|
|
||||||
typedef int64_t intmax_t;
|
|
||||||
#if defined(_WIN64)
|
|
||||||
typedef int64_t intptr_t;
|
|
||||||
#else
|
|
||||||
typedef int32_t intptr_t;
|
|
||||||
#endif
|
|
||||||
|
|
||||||
typedef unsigned char uint8_t;
|
|
||||||
typedef unsigned short uint16_t;
|
|
||||||
typedef unsigned int uint32_t;
|
|
||||||
typedef unsigned long long uint64_t;
|
|
||||||
typedef uint64_t uintmax_t;
|
|
||||||
#if defined(_WIN64)
|
|
||||||
typedef uint64_t uintptr_t;
|
|
||||||
#else
|
|
||||||
typedef uint32_t uintptr_t;
|
|
||||||
#endif
|
|
||||||
#else
|
|
||||||
#include <stdint.h>
|
|
||||||
#endif
|
|
||||||
|
|
||||||
namespace nall {
|
|
||||||
static_assert(sizeof(int8_t) == 1, "int8_t is not of the correct size" );
|
|
||||||
static_assert(sizeof(int16_t) == 2, "int16_t is not of the correct size");
|
|
||||||
static_assert(sizeof(int32_t) == 4, "int32_t is not of the correct size");
|
|
||||||
static_assert(sizeof(int64_t) == 8, "int64_t is not of the correct size");
|
|
||||||
|
|
||||||
static_assert(sizeof(uint8_t) == 1, "int8_t is not of the correct size" );
|
|
||||||
static_assert(sizeof(uint16_t) == 2, "int16_t is not of the correct size");
|
|
||||||
static_assert(sizeof(uint32_t) == 4, "int32_t is not of the correct size");
|
|
||||||
static_assert(sizeof(uint64_t) == 8, "int64_t is not of the correct size");
|
|
||||||
}
|
|
||||||
|
|
||||||
#endif
|
|
|
@ -1,26 +0,0 @@
|
||||||
#ifndef NALL_STRING_HPP
|
|
||||||
#define NALL_STRING_HPP
|
|
||||||
|
|
||||||
#include <initializer_list>
|
|
||||||
#include <nall/string/base.hpp>
|
|
||||||
#include <nall/string/core.hpp>
|
|
||||||
#include <nall/string/cast.hpp>
|
|
||||||
#include <nall/string/compare.hpp>
|
|
||||||
#include <nall/string/convert.hpp>
|
|
||||||
#include <nall/string/filename.hpp>
|
|
||||||
#include <nall/string/match.hpp>
|
|
||||||
#include <nall/string/math.hpp>
|
|
||||||
#include <nall/string/strl.hpp>
|
|
||||||
#include <nall/string/trim.hpp>
|
|
||||||
#include <nall/string/replace.hpp>
|
|
||||||
#include <nall/string/split.hpp>
|
|
||||||
#include <nall/string/utility.hpp>
|
|
||||||
#include <nall/string/variadic.hpp>
|
|
||||||
#include <nall/string/xml.hpp>
|
|
||||||
|
|
||||||
namespace nall {
|
|
||||||
template<> struct has_length<string> { enum { value = true }; };
|
|
||||||
template<> struct has_size<lstring> { enum { value = true }; };
|
|
||||||
}
|
|
||||||
|
|
||||||
#endif
|
|
|
@ -1,126 +0,0 @@
|
||||||
#ifndef NALL_STRING_BASE_HPP
|
|
||||||
#define NALL_STRING_BASE_HPP
|
|
||||||
|
|
||||||
#include <stdarg.h>
|
|
||||||
#include <stdio.h>
|
|
||||||
#include <stdlib.h>
|
|
||||||
#include <string.h>
|
|
||||||
#include <nall/concept.hpp>
|
|
||||||
#include <nall/stdint.hpp>
|
|
||||||
#include <nall/utf8.hpp>
|
|
||||||
#include <nall/vector.hpp>
|
|
||||||
|
|
||||||
inline char chrlower(char c);
|
|
||||||
inline char chrupper(char c);
|
|
||||||
inline int stricmp(const char *dest, const char *src);
|
|
||||||
inline int strpos (const char *str, const char *key);
|
|
||||||
inline int qstrpos(const char *str, const char *key);
|
|
||||||
inline bool strbegin (const char *str, const char *key);
|
|
||||||
inline bool stribegin(const char *str, const char *key);
|
|
||||||
inline bool strend (const char *str, const char *key);
|
|
||||||
inline bool striend(const char *str, const char *key);
|
|
||||||
inline char* strlower(char *str);
|
|
||||||
inline char* strupper(char *str);
|
|
||||||
inline char* strtr(char *dest, const char *before, const char *after);
|
|
||||||
inline uintmax_t strhex (const char *str);
|
|
||||||
inline intmax_t strsigned (const char *str);
|
|
||||||
inline uintmax_t strunsigned(const char *str);
|
|
||||||
inline uintmax_t strbin (const char *str);
|
|
||||||
inline double strdouble (const char *str);
|
|
||||||
inline bool match(const char *pattern, const char *str);
|
|
||||||
inline bool strint (const char *str, int &result);
|
|
||||||
inline bool strmath(const char *str, int &result);
|
|
||||||
inline size_t strlcpy(char *dest, const char *src, size_t length);
|
|
||||||
inline size_t strlcat(char *dest, const char *src, size_t length);
|
|
||||||
inline char* ltrim(char *str, const char *key = " ");
|
|
||||||
inline char* rtrim(char *str, const char *key = " ");
|
|
||||||
inline char* trim (char *str, const char *key = " ");
|
|
||||||
inline char* ltrim_once(char *str, const char *key = " ");
|
|
||||||
inline char* rtrim_once(char *str, const char *key = " ");
|
|
||||||
inline char* trim_once (char *str, const char *key = " ");
|
|
||||||
|
|
||||||
namespace nall {
|
|
||||||
class string;
|
|
||||||
template<typename T> inline string to_string(T);
|
|
||||||
|
|
||||||
class string {
|
|
||||||
public:
|
|
||||||
inline void reserve(size_t);
|
|
||||||
inline unsigned length() const;
|
|
||||||
|
|
||||||
inline string& assign(const char*);
|
|
||||||
inline string& append(const char*);
|
|
||||||
template<typename T> inline string& operator= (T value);
|
|
||||||
template<typename T> inline string& operator<<(T value);
|
|
||||||
|
|
||||||
inline operator const char*() const;
|
|
||||||
inline char* operator()();
|
|
||||||
inline char& operator[](int);
|
|
||||||
|
|
||||||
inline bool operator==(const char*) const;
|
|
||||||
inline bool operator!=(const char*) const;
|
|
||||||
inline bool operator< (const char*) const;
|
|
||||||
inline bool operator<=(const char*) const;
|
|
||||||
inline bool operator> (const char*) const;
|
|
||||||
inline bool operator>=(const char*) const;
|
|
||||||
|
|
||||||
inline string();
|
|
||||||
inline string(const char*);
|
|
||||||
inline string(const string&);
|
|
||||||
inline string(string&&);
|
|
||||||
inline string& operator=(const string&);
|
|
||||||
inline string& operator=(string&&);
|
|
||||||
inline ~string();
|
|
||||||
|
|
||||||
inline bool readfile(const char*);
|
|
||||||
inline string& replace (const char*, const char*);
|
|
||||||
inline string& qreplace(const char*, const char*);
|
|
||||||
|
|
||||||
protected:
|
|
||||||
char *data;
|
|
||||||
size_t size;
|
|
||||||
|
|
||||||
#if defined(QT_CORE_LIB)
|
|
||||||
public:
|
|
||||||
inline operator QString() const;
|
|
||||||
#endif
|
|
||||||
};
|
|
||||||
|
|
||||||
class lstring : public linear_vector<string> {
|
|
||||||
public:
|
|
||||||
template<typename T> inline lstring& operator<<(T value);
|
|
||||||
|
|
||||||
inline int find(const char*);
|
|
||||||
inline void split (const char*, const char*, unsigned = 0);
|
|
||||||
inline void qsplit(const char*, const char*, unsigned = 0);
|
|
||||||
|
|
||||||
lstring();
|
|
||||||
lstring(std::initializer_list<string>);
|
|
||||||
};
|
|
||||||
|
|
||||||
template<typename... Args> inline string sprint(const char *s, Args... args);
|
|
||||||
template<typename... Args> inline void print(const char *s, Args... args);
|
|
||||||
};
|
|
||||||
|
|
||||||
inline size_t strlcpy(nall::string &dest, const char *src, size_t length);
|
|
||||||
inline size_t strlcat(nall::string &dest, const char *src, size_t length);
|
|
||||||
|
|
||||||
inline nall::string& strlower(nall::string &str);
|
|
||||||
inline nall::string& strupper(nall::string &str);
|
|
||||||
inline nall::string& strtr(nall::string &dest, const char *before, const char *after);
|
|
||||||
inline nall::string& ltrim(nall::string &str, const char *key = " ");
|
|
||||||
inline nall::string& rtrim(nall::string &str, const char *key = " ");
|
|
||||||
inline nall::string& trim (nall::string &str, const char *key = " ");
|
|
||||||
inline nall::string& ltrim_once(nall::string &str, const char *key = " ");
|
|
||||||
inline nall::string& rtrim_once(nall::string &str, const char *key = " ");
|
|
||||||
inline nall::string& trim_once (nall::string &str, const char *key = " ");
|
|
||||||
|
|
||||||
inline nall::string substr(const char *src, size_t start = 0, size_t length = 0);
|
|
||||||
template<unsigned length = 0, char padding = '0'> inline nall::string strhex(uintmax_t value);
|
|
||||||
template<unsigned length = 0, char padding = '0'> inline nall::string strsigned(intmax_t value);
|
|
||||||
template<unsigned length = 0, char padding = '0'> inline nall::string strunsigned(uintmax_t value);
|
|
||||||
template<unsigned length = 0, char padding = '0'> inline nall::string strbin(uintmax_t value);
|
|
||||||
inline size_t strdouble(char *str, double value);
|
|
||||||
inline nall::string strdouble(double value);
|
|
||||||
|
|
||||||
#endif
|
|
|
@ -1,29 +0,0 @@
|
||||||
#ifndef NALL_STRING_CAST_HPP
|
|
||||||
#define NALL_STRING_CAST_HPP
|
|
||||||
|
|
||||||
namespace nall {
|
|
||||||
//this is needed, as C++0x does not support explicit template specialization inside classes
|
|
||||||
template<> inline string to_string<bool> (bool v) { return v ? "true" : "false"; }
|
|
||||||
template<> inline string to_string<signed int> (signed int v) { return strsigned(v); }
|
|
||||||
template<> inline string to_string<unsigned int> (unsigned int v) { return strunsigned(v); }
|
|
||||||
template<> inline string to_string<double> (double v) { return strdouble(v); }
|
|
||||||
template<> inline string to_string<char*> (char *v) { return v; }
|
|
||||||
template<> inline string to_string<const char*> (const char *v) { return v; }
|
|
||||||
template<> inline string to_string<string> (string v) { return v; }
|
|
||||||
template<> inline string 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;
|
|
||||||
}
|
|
||||||
|
|
||||||
#if defined(QT_CORE_LIB)
|
|
||||||
template<> inline string to_string<const QString&>(const QString &v) { return v.toUtf8().constData(); }
|
|
||||||
string::operator QString() const { return QString::fromUtf8(*this); }
|
|
||||||
#endif
|
|
||||||
}
|
|
||||||
|
|
||||||
#endif
|
|
|
@ -1,100 +0,0 @@
|
||||||
#ifndef NALL_STRING_COMPARE_HPP
|
|
||||||
#define NALL_STRING_COMPARE_HPP
|
|
||||||
|
|
||||||
char chrlower(char c) {
|
|
||||||
return (c >= 'A' && c <= 'Z') ? c + ('a' - 'A') : c;
|
|
||||||
}
|
|
||||||
|
|
||||||
char chrupper(char c) {
|
|
||||||
return (c >= 'a' && c <= 'z') ? c - ('a' - 'A') : c;
|
|
||||||
}
|
|
||||||
|
|
||||||
int stricmp(const char *dest, const char *src) {
|
|
||||||
while(*dest) {
|
|
||||||
if(chrlower(*dest) != chrlower(*src)) break;
|
|
||||||
dest++;
|
|
||||||
src++;
|
|
||||||
}
|
|
||||||
|
|
||||||
return (int)chrlower(*dest) - (int)chrlower(*src);
|
|
||||||
}
|
|
||||||
|
|
||||||
int strpos(const char *str, const char *key) {
|
|
||||||
int ssl = strlen(str), ksl = strlen(key);
|
|
||||||
|
|
||||||
if(ksl > ssl) return -1;
|
|
||||||
for(int i = 0; i <= ssl - ksl; i++) {
|
|
||||||
if(!memcmp(str + i, key, ksl)) {
|
|
||||||
return i;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
int qstrpos(const char *str, const char *key) {
|
|
||||||
int ssl = strlen(str), ksl = strlen(key);
|
|
||||||
|
|
||||||
if(ksl > ssl) return -1;
|
|
||||||
for(int 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;
|
|
||||||
}
|
|
||||||
if(!memcmp(str + i, key, ksl)) {
|
|
||||||
return i;
|
|
||||||
} else {
|
|
||||||
i++;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool strbegin(const char *str, const char *key) {
|
|
||||||
int i, ssl = strlen(str), ksl = strlen(key);
|
|
||||||
|
|
||||||
if(ksl > ssl) return false;
|
|
||||||
return (!memcmp(str, key, ksl));
|
|
||||||
}
|
|
||||||
|
|
||||||
bool stribegin(const char *str, const char *key) {
|
|
||||||
int ssl = strlen(str), ksl = strlen(key);
|
|
||||||
|
|
||||||
if(ksl > ssl) return false;
|
|
||||||
for(int i = 0; i < ksl; i++) {
|
|
||||||
if(str[i] >= 'A' && str[i] <= 'Z') {
|
|
||||||
if(str[i] != key[i] && str[i]+0x20 != key[i])return false;
|
|
||||||
} else if(str[i] >= 'a' && str[i] <= 'z') {
|
|
||||||
if(str[i] != key[i] && str[i]-0x20 != key[i])return false;
|
|
||||||
} else {
|
|
||||||
if(str[i] != key[i])return false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool strend(const char *str, const char *key) {
|
|
||||||
int ssl = strlen(str), ksl = strlen(key);
|
|
||||||
|
|
||||||
if(ksl > ssl) return false;
|
|
||||||
return (!memcmp(str + ssl - ksl, key, ksl));
|
|
||||||
}
|
|
||||||
|
|
||||||
bool striend(const char *str, const char *key) {
|
|
||||||
int ssl = strlen(str), ksl = strlen(key);
|
|
||||||
|
|
||||||
if(ksl > ssl) return false;
|
|
||||||
for(int i = ssl - ksl, z = 0; i < ssl; i++, z++) {
|
|
||||||
if(str[i] >= 'A' && str[i] <= 'Z') {
|
|
||||||
if(str[i] != key[z] && str[i]+0x20 != key[z])return false;
|
|
||||||
} else if(str[i] >= 'a' && str[i] <= 'z') {
|
|
||||||
if(str[i] != key[z] && str[i]-0x20 != key[z])return false;
|
|
||||||
} else {
|
|
||||||
if(str[i] != key[z])return false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
#endif
|
|
|
@ -1,149 +0,0 @@
|
||||||
#ifndef NALL_STRING_CONVERT_HPP
|
|
||||||
#define NALL_STRING_CONVERT_HPP
|
|
||||||
|
|
||||||
char* strlower(char *str) {
|
|
||||||
if(!str) return 0;
|
|
||||||
int i = 0;
|
|
||||||
while(str[i]) {
|
|
||||||
str[i] = chrlower(str[i]);
|
|
||||||
i++;
|
|
||||||
}
|
|
||||||
return str;
|
|
||||||
}
|
|
||||||
|
|
||||||
char* strupper(char *str) {
|
|
||||||
if(!str) return 0;
|
|
||||||
int i = 0;
|
|
||||||
while(str[i]) {
|
|
||||||
str[i] = chrupper(str[i]);
|
|
||||||
i++;
|
|
||||||
}
|
|
||||||
return str;
|
|
||||||
}
|
|
||||||
|
|
||||||
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);
|
|
||||||
|
|
||||||
if(bsl != asl || bsl == 0) return dest; //patterns must be the same length for 1:1 replace
|
|
||||||
for(unsigned i = 0; i < sl; i++) {
|
|
||||||
for(unsigned l = 0; l < bsl; l++) {
|
|
||||||
if(dest[i] == before[l]) {
|
|
||||||
dest[i] = after[l];
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return dest;
|
|
||||||
}
|
|
||||||
|
|
||||||
uintmax_t strhex(const char *str) {
|
|
||||||
if(!str) return 0;
|
|
||||||
uintmax_t result = 0;
|
|
||||||
|
|
||||||
//skip hex identifiers 0x and $, if present
|
|
||||||
if(*str == '0' && (*(str + 1) == 'X' || *(str + 1) == 'x')) str += 2;
|
|
||||||
else if(*str == '$') str++;
|
|
||||||
|
|
||||||
while(*str) {
|
|
||||||
uint8_t x = *str++;
|
|
||||||
if(x >= '0' && x <= '9') x -= '0';
|
|
||||||
else if(x >= 'A' && x <= 'F') x -= 'A' - 10;
|
|
||||||
else if(x >= 'a' && x <= 'f') x -= 'a' - 10;
|
|
||||||
else break; //stop at first invalid character
|
|
||||||
result = result * 16 + x;
|
|
||||||
}
|
|
||||||
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
intmax_t strsigned(const char *str) {
|
|
||||||
if(!str) return 0;
|
|
||||||
intmax_t result = 0;
|
|
||||||
bool negate = false;
|
|
||||||
|
|
||||||
//check for negation
|
|
||||||
if(*str == '-') {
|
|
||||||
negate = true;
|
|
||||||
str++;
|
|
||||||
}
|
|
||||||
|
|
||||||
while(*str) {
|
|
||||||
uint8_t x = *str++;
|
|
||||||
if(x >= '0' && x <= '9') x -= '0';
|
|
||||||
else break; //stop at first invalid character
|
|
||||||
result = result * 10 + x;
|
|
||||||
}
|
|
||||||
|
|
||||||
return !negate ? result : -result;
|
|
||||||
}
|
|
||||||
|
|
||||||
uintmax_t strunsigned(const char *str) {
|
|
||||||
if(!str) return 0;
|
|
||||||
uintmax_t result = 0;
|
|
||||||
|
|
||||||
while(*str) {
|
|
||||||
uint8_t x = *str++;
|
|
||||||
if(x >= '0' && x <= '9') x -= '0';
|
|
||||||
else break; //stop at first invalid character
|
|
||||||
result = result * 10 + x;
|
|
||||||
}
|
|
||||||
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
uintmax_t strbin(const char *str) {
|
|
||||||
if(!str) return 0;
|
|
||||||
uintmax_t result = 0;
|
|
||||||
|
|
||||||
//skip bin identifiers 0b and %, if present
|
|
||||||
if(*str == '0' && (*(str + 1) == 'B' || *(str + 1) == 'b')) str += 2;
|
|
||||||
else if(*str == '%') str++;
|
|
||||||
|
|
||||||
while(*str) {
|
|
||||||
uint8_t x = *str++;
|
|
||||||
if(x == '0' || x == '1') x -= '0';
|
|
||||||
else break; //stop at first invalid character
|
|
||||||
result = result * 2 + x;
|
|
||||||
}
|
|
||||||
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
double strdouble(const char *str) {
|
|
||||||
if(!str) return 0.0;
|
|
||||||
bool negate = false;
|
|
||||||
|
|
||||||
//check for negation
|
|
||||||
if(*str == '-') {
|
|
||||||
negate = true;
|
|
||||||
str++;
|
|
||||||
}
|
|
||||||
|
|
||||||
intmax_t result_integral = 0;
|
|
||||||
while(*str) {
|
|
||||||
uint8_t x = *str++;
|
|
||||||
if(x >= '0' && x <= '9') x -= '0';
|
|
||||||
else if(x == '.') break; //break loop and read fractional part
|
|
||||||
else return (double)result_integral; //invalid value, assume no fractional part
|
|
||||||
result_integral = result_integral * 10 + x;
|
|
||||||
}
|
|
||||||
|
|
||||||
intmax_t result_fractional = 0;
|
|
||||||
while(*str) {
|
|
||||||
uint8_t x = *str++;
|
|
||||||
if(x >= '0' && x <= '9') x -= '0';
|
|
||||||
else break; //stop at first invalid character
|
|
||||||
result_fractional = result_fractional * 10 + x;
|
|
||||||
}
|
|
||||||
|
|
||||||
//calculate fractional portion
|
|
||||||
double result = (double)result_fractional;
|
|
||||||
while((uintmax_t)result > 0) result /= 10.0;
|
|
||||||
result += (double)result_integral;
|
|
||||||
|
|
||||||
return !negate ? result : -result;
|
|
||||||
}
|
|
||||||
|
|
||||||
#endif
|
|
|
@ -1,132 +0,0 @@
|
||||||
#ifndef NALL_STRING_CORE_HPP
|
|
||||||
#define NALL_STRING_CORE_HPP
|
|
||||||
|
|
||||||
namespace nall {
|
|
||||||
|
|
||||||
void string::reserve(size_t size_) {
|
|
||||||
if(size_ > size) {
|
|
||||||
size = size_;
|
|
||||||
data = (char*)realloc(data, size + 1);
|
|
||||||
data[size] = 0;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
unsigned string::length() const {
|
|
||||||
return strlen(data);
|
|
||||||
}
|
|
||||||
|
|
||||||
string& string::assign(const char *s) {
|
|
||||||
unsigned length = strlen(s);
|
|
||||||
reserve(length);
|
|
||||||
strcpy(data, s);
|
|
||||||
return *this;
|
|
||||||
}
|
|
||||||
|
|
||||||
string& string::append(const char *s) {
|
|
||||||
unsigned length = strlen(data) + strlen(s);
|
|
||||||
reserve(length);
|
|
||||||
strcat(data, s);
|
|
||||||
return *this;
|
|
||||||
}
|
|
||||||
|
|
||||||
string::operator const char*() const {
|
|
||||||
return data;
|
|
||||||
}
|
|
||||||
|
|
||||||
char* string::operator()() {
|
|
||||||
return data;
|
|
||||||
}
|
|
||||||
|
|
||||||
char& string::operator[](int index) {
|
|
||||||
reserve(index);
|
|
||||||
return data[index];
|
|
||||||
}
|
|
||||||
|
|
||||||
bool string::operator==(const char *str) const { return strcmp(data, str) == 0; }
|
|
||||||
bool string::operator!=(const char *str) const { return strcmp(data, str) != 0; }
|
|
||||||
bool string::operator< (const char *str) const { return strcmp(data, str) < 0; }
|
|
||||||
bool string::operator<=(const char *str) const { return strcmp(data, str) <= 0; }
|
|
||||||
bool string::operator> (const char *str) const { return strcmp(data, str) > 0; }
|
|
||||||
bool string::operator>=(const char *str) const { return strcmp(data, str) >= 0; }
|
|
||||||
|
|
||||||
string::string() {
|
|
||||||
size = 64;
|
|
||||||
data = (char*)malloc(size + 1);
|
|
||||||
*data = 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
string::string(const char *value) {
|
|
||||||
size = strlen(value);
|
|
||||||
data = strdup(value);
|
|
||||||
}
|
|
||||||
|
|
||||||
string::string(const string &value) {
|
|
||||||
size = strlen(value);
|
|
||||||
data = strdup(value);
|
|
||||||
}
|
|
||||||
|
|
||||||
string::string(string &&source) {
|
|
||||||
size = source.size;
|
|
||||||
data = source.data;
|
|
||||||
source.data = 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
string& string::operator=(const string &value) {
|
|
||||||
assign(value);
|
|
||||||
return *this;
|
|
||||||
}
|
|
||||||
|
|
||||||
string& string::operator=(string &&source) {
|
|
||||||
if(data) free(data);
|
|
||||||
size = source.size;
|
|
||||||
data = source.data;
|
|
||||||
source.data = 0;
|
|
||||||
return *this;
|
|
||||||
}
|
|
||||||
|
|
||||||
string::~string() {
|
|
||||||
free(data);
|
|
||||||
}
|
|
||||||
|
|
||||||
bool string::readfile(const char *filename) {
|
|
||||||
assign("");
|
|
||||||
|
|
||||||
#if !defined(_WIN32)
|
|
||||||
FILE *fp = fopen(filename, "rb");
|
|
||||||
#else
|
|
||||||
FILE *fp = _wfopen(nall::utf16_t(filename), L"rb");
|
|
||||||
#endif
|
|
||||||
if(!fp) return false;
|
|
||||||
|
|
||||||
fseek(fp, 0, SEEK_END);
|
|
||||||
size_t size = ftell(fp);
|
|
||||||
rewind(fp);
|
|
||||||
char *fdata = new char[size + 1];
|
|
||||||
unsigned unused = fread(fdata, 1, size, fp);
|
|
||||||
fclose(fp);
|
|
||||||
fdata[size] = 0;
|
|
||||||
assign(fdata);
|
|
||||||
delete[] fdata;
|
|
||||||
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
int lstring::find(const char *key) {
|
|
||||||
for(unsigned i = 0; i < size(); i++) {
|
|
||||||
if(operator[](i) == key) return i;
|
|
||||||
}
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
inline lstring::lstring() {
|
|
||||||
}
|
|
||||||
|
|
||||||
inline lstring::lstring(std::initializer_list<string> list) {
|
|
||||||
for(const string *s = list.begin(); s != list.end(); ++s) {
|
|
||||||
operator<<(*s);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
#endif
|
|
|
@ -1,60 +0,0 @@
|
||||||
#ifndef NALL_FILENAME_HPP
|
|
||||||
#define NALL_FILENAME_HPP
|
|
||||||
|
|
||||||
namespace nall {
|
|
||||||
// "foo/bar.c" -> "foo/", "bar.c" -> "./"
|
|
||||||
inline string dir(char const *name) {
|
|
||||||
string result = name;
|
|
||||||
for(signed i = strlen(result); i >= 0; i--) {
|
|
||||||
if(result[i] == '/' || result[i] == '\\') {
|
|
||||||
result[i + 1] = 0;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
if(i == 0) result = "./";
|
|
||||||
}
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
// "foo/bar.c" -> "bar.c"
|
|
||||||
inline string notdir(char const *name) {
|
|
||||||
for(signed i = strlen(name); i >= 0; i--) {
|
|
||||||
if(name[i] == '/' || name[i] == '\\') {
|
|
||||||
name += i + 1;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
string result = name;
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
// "foo/bar.c" -> "foo/bar"
|
|
||||||
inline string basename(char const *name) {
|
|
||||||
string result = name;
|
|
||||||
for(signed i = strlen(result); i >= 0; i--) {
|
|
||||||
if(result[i] == '/' || result[i] == '\\') {
|
|
||||||
//file has no extension
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
if(result[i] == '.') {
|
|
||||||
result[i] = 0;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
// "foo/bar.c" -> "c"
|
|
||||||
inline string extension(char const *name) {
|
|
||||||
for(signed i = strlen(name); i >= 0; i--) {
|
|
||||||
if(name[i] == '.') {
|
|
||||||
name += i + 1;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
string result = name;
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#endif
|
|
|
@ -1,72 +0,0 @@
|
||||||
#ifndef NALL_STRING_MATCH_HPP
|
|
||||||
#define NALL_STRING_MATCH_HPP
|
|
||||||
|
|
||||||
bool match(const char *p, const char *s) {
|
|
||||||
const char *p_ = 0, *s_ = 0;
|
|
||||||
|
|
||||||
for(;;) {
|
|
||||||
if(!*s) {
|
|
||||||
while(*p == '*') p++;
|
|
||||||
return !*p;
|
|
||||||
}
|
|
||||||
|
|
||||||
//wildcard match
|
|
||||||
if(*p == '*') {
|
|
||||||
p_ = p++, s_ = s;
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
//any match
|
|
||||||
if(*p == '?') {
|
|
||||||
p++, s++;
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
//ranged match
|
|
||||||
if(*p == '{') {
|
|
||||||
#define pattern(name_, rule_) \
|
|
||||||
if(strbegin(p, name_)) { \
|
|
||||||
if(rule_) { \
|
|
||||||
p += sizeof(name_) - 1, s++; \
|
|
||||||
continue; \
|
|
||||||
} \
|
|
||||||
goto failure; \
|
|
||||||
}
|
|
||||||
|
|
||||||
pattern("{alpha}", (*s >= 'A' && *s <= 'Z') || (*s >= 'a' && *s <= 'z'))
|
|
||||||
pattern("{alphanumeric}", (*s >= 'A' && *s <= 'Z') || (*s >= 'a' && *s <= 'z') || (*s >= '0' && *s <= '9'))
|
|
||||||
pattern("{binary}", (*s == '0' || *s == '1'))
|
|
||||||
pattern("{hex}", (*s >= '0' && *s <= '9') || (*s >= 'A' && *s <= 'F') || (*s >= 'a' && *s <= 'f'))
|
|
||||||
pattern("{lowercase}", (*s >= 'a' && *s <= 'z'))
|
|
||||||
pattern("{numeric}", (*s >= '0' && *s <= '9'))
|
|
||||||
pattern("{uppercase}", (*s >= 'A' && *s <= 'Z'))
|
|
||||||
pattern("{whitespace}", (*s == ' ' || *s == '\t'))
|
|
||||||
|
|
||||||
#undef pattern
|
|
||||||
goto failure;
|
|
||||||
}
|
|
||||||
|
|
||||||
//reserved character match
|
|
||||||
if(*p == '\\') {
|
|
||||||
p++;
|
|
||||||
//fallthrough
|
|
||||||
}
|
|
||||||
|
|
||||||
//literal match
|
|
||||||
if(*p == *s) {
|
|
||||||
p++, *s++;
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
//attempt wildcard rematch
|
|
||||||
failure:
|
|
||||||
if(p_) {
|
|
||||||
p = p_, s = s_ + 1;
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#endif
|
|
|
@ -1,160 +0,0 @@
|
||||||
#ifndef NALL_STRING_MATH_HPP
|
|
||||||
#define NALL_STRING_MATH_HPP
|
|
||||||
|
|
||||||
static int eval_integer(const char *&s) {
|
|
||||||
if(!*s) throw "unrecognized_integer";
|
|
||||||
int value = 0, x = *s, y = *(s + 1);
|
|
||||||
|
|
||||||
//hexadecimal
|
|
||||||
if(x == '0' && (y == 'X' || y == 'x')) {
|
|
||||||
s += 2;
|
|
||||||
while(true) {
|
|
||||||
if(*s >= '0' && *s <= '9') { value = value * 16 + (*s++ - '0'); continue; }
|
|
||||||
if(*s >= 'A' && *s <= 'F') { value = value * 16 + (*s++ - 'A' + 10); continue; }
|
|
||||||
if(*s >= 'a' && *s <= 'f') { value = value * 16 + (*s++ - 'a' + 10); continue; }
|
|
||||||
return value;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
//binary
|
|
||||||
if(x == '0' && (y == 'B' || y == 'b')) {
|
|
||||||
s += 2;
|
|
||||||
while(true) {
|
|
||||||
if(*s == '0' || *s == '1') { value = value * 2 + (*s++ - '0'); continue; }
|
|
||||||
return value;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
//octal (or decimal '0')
|
|
||||||
if(x == '0') {
|
|
||||||
s += 1;
|
|
||||||
while(true) {
|
|
||||||
if(*s >= '0' && *s <= '7') { value = value * 8 + (*s++ - '0'); continue; }
|
|
||||||
return value;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
//decimal
|
|
||||||
if(x >= '0' && x <= '9') {
|
|
||||||
while(true) {
|
|
||||||
if(*s >= '0' && *s <= '9') { value = value * 10 + (*s++ - '0'); continue; }
|
|
||||||
return value;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
//char
|
|
||||||
if(x == '\'' && y != '\'') {
|
|
||||||
s += 1;
|
|
||||||
while(true) {
|
|
||||||
value = value * 256 + *s++;
|
|
||||||
if(*s == '\'') { s += 1; return value; }
|
|
||||||
if(!*s) throw "mismatched_char";
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
throw "unrecognized_integer";
|
|
||||||
}
|
|
||||||
|
|
||||||
static int eval(const char *&s, int depth = 0) {
|
|
||||||
while(*s == ' ' || *s == '\t') s++; //trim whitespace
|
|
||||||
if(!*s) throw "unrecognized_token";
|
|
||||||
int value = 0, x = *s, y = *(s + 1);
|
|
||||||
|
|
||||||
if(*s == '(') {
|
|
||||||
value = eval(++s, 1);
|
|
||||||
if(*s++ != ')') throw "mismatched_group";
|
|
||||||
}
|
|
||||||
|
|
||||||
else if(x == '!') value = !eval(++s, 13);
|
|
||||||
else if(x == '~') value = ~eval(++s, 13);
|
|
||||||
else if(x == '+') value = +eval(++s, 13);
|
|
||||||
else if(x == '-') value = -eval(++s, 13);
|
|
||||||
|
|
||||||
else if((x >= '0' && x <= '9') || x == '\'') value = eval_integer(s);
|
|
||||||
|
|
||||||
else throw "unrecognized_token";
|
|
||||||
|
|
||||||
while(true) {
|
|
||||||
while(*s == ' ' || *s == '\t') s++; //trim whitespace
|
|
||||||
if(!*s) break;
|
|
||||||
x = *s, y = *(s + 1);
|
|
||||||
|
|
||||||
if(depth >= 13) break;
|
|
||||||
if(x == '*') { value *= eval(++s, 13); continue; }
|
|
||||||
if(x == '/') { value /= eval(++s, 13); continue; }
|
|
||||||
if(x == '%') { value %= eval(++s, 13); continue; }
|
|
||||||
|
|
||||||
if(depth >= 12) break;
|
|
||||||
if(x == '+') { value += eval(++s, 12); continue; }
|
|
||||||
if(x == '-') { value -= eval(++s, 12); continue; }
|
|
||||||
|
|
||||||
if(depth >= 11) break;
|
|
||||||
if(x == '<' && y == '<') { value <<= eval(++++s, 11); continue; }
|
|
||||||
if(x == '>' && y == '>') { value >>= eval(++++s, 11); continue; }
|
|
||||||
|
|
||||||
if(depth >= 10) break;
|
|
||||||
if(x == '<' && y == '=') { value = value <= eval(++++s, 10); continue; }
|
|
||||||
if(x == '>' && y == '=') { value = value >= eval(++++s, 10); continue; }
|
|
||||||
if(x == '<') { value = value < eval(++s, 10); continue; }
|
|
||||||
if(x == '>') { value = value > eval(++s, 10); continue; }
|
|
||||||
|
|
||||||
if(depth >= 9) break;
|
|
||||||
if(x == '=' && y == '=') { value = value == eval(++++s, 9); continue; }
|
|
||||||
if(x == '!' && y == '=') { value = value != eval(++++s, 9); continue; }
|
|
||||||
|
|
||||||
if(depth >= 8) break;
|
|
||||||
if(x == '&' && y != '&') { value = value & eval(++s, 8); continue; }
|
|
||||||
|
|
||||||
if(depth >= 7) break;
|
|
||||||
if(x == '^' && y != '^') { value = value ^ eval(++s, 7); continue; }
|
|
||||||
|
|
||||||
if(depth >= 6) break;
|
|
||||||
if(x == '|' && y != '|') { value = value | eval(++s, 6); continue; }
|
|
||||||
|
|
||||||
if(depth >= 5) break;
|
|
||||||
if(x == '&' && y == '&') { value = eval(++++s, 5) && value; continue; }
|
|
||||||
|
|
||||||
if(depth >= 4) break;
|
|
||||||
if(x == '^' && y == '^') { value = (!eval(++++s, 4) != !value); continue; }
|
|
||||||
|
|
||||||
if(depth >= 3) break;
|
|
||||||
if(x == '|' && y == '|') { value = eval(++++s, 3) || value; continue; }
|
|
||||||
|
|
||||||
if(x == '?') {
|
|
||||||
int lhs = eval(++s, 2);
|
|
||||||
if(*s != ':') throw "mismatched_ternary";
|
|
||||||
int rhs = eval(++s, 2);
|
|
||||||
value = value ? lhs : rhs;
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
if(depth >= 2) break;
|
|
||||||
|
|
||||||
if(depth > 0 && x == ')') break;
|
|
||||||
|
|
||||||
throw "unrecognized_token";
|
|
||||||
}
|
|
||||||
|
|
||||||
return value;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool strint(const char *s, int &result) {
|
|
||||||
try {
|
|
||||||
result = eval_integer(s);
|
|
||||||
return true;
|
|
||||||
} catch(const char*) {
|
|
||||||
result = 0;
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
bool strmath(const char *s, int &result) {
|
|
||||||
try {
|
|
||||||
result = eval(s);
|
|
||||||
return true;
|
|
||||||
} catch(const char*) {
|
|
||||||
result = 0;
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#endif
|
|
|
@ -1,103 +0,0 @@
|
||||||
#ifndef NALL_STRING_REPLACE_HPP
|
|
||||||
#define NALL_STRING_REPLACE_HPP
|
|
||||||
|
|
||||||
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;
|
|
||||||
|
|
||||||
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);
|
|
||||||
}
|
|
||||||
|
|
||||||
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;
|
|
||||||
}
|
|
||||||
|
|
||||||
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;
|
|
||||||
}
|
|
||||||
|
|
||||||
};
|
|
||||||
|
|
||||||
#endif
|
|
|
@ -1,56 +0,0 @@
|
||||||
#ifndef NALL_STRING_SPLIT_HPP
|
|
||||||
#define NALL_STRING_SPLIT_HPP
|
|
||||||
|
|
||||||
namespace nall {
|
|
||||||
|
|
||||||
void lstring::split(const char *key, const char *src, unsigned limit) {
|
|
||||||
reset();
|
|
||||||
|
|
||||||
int ssl = strlen(src), ksl = strlen(key);
|
|
||||||
int lp = 0, split_count = 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;
|
|
||||||
}
|
|
||||||
|
|
||||||
void lstring::qsplit(const char *key, const char *src, unsigned 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
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
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;
|
|
||||||
}
|
|
||||||
|
|
||||||
};
|
|
||||||
|
|
||||||
#endif
|
|
|
@ -1,48 +0,0 @@
|
||||||
#ifndef NALL_STRING_STRL_HPP
|
|
||||||
#define NALL_STRING_STRL_HPP
|
|
||||||
|
|
||||||
//strlcpy, strlcat based on OpenBSD implementation by Todd C. Miller
|
|
||||||
|
|
||||||
//return = strlen(src)
|
|
||||||
size_t strlcpy(char *dest, const char *src, size_t length) {
|
|
||||||
char *d = dest;
|
|
||||||
const char *s = src;
|
|
||||||
size_t n = length;
|
|
||||||
|
|
||||||
if(n) {
|
|
||||||
while(--n && (*d++ = *s++)); //copy as many bytes as possible, or until null terminator reached
|
|
||||||
}
|
|
||||||
|
|
||||||
if(!n) {
|
|
||||||
if(length) *d = 0;
|
|
||||||
while(*s++); //traverse rest of s, so that s - src == strlen(src)
|
|
||||||
}
|
|
||||||
|
|
||||||
return (s - src - 1); //return length of copied string, sans null terminator
|
|
||||||
}
|
|
||||||
|
|
||||||
//return = strlen(src) + min(length, strlen(dest))
|
|
||||||
size_t strlcat(char *dest, const char *src, size_t length) {
|
|
||||||
char *d = dest;
|
|
||||||
const char *s = src;
|
|
||||||
size_t n = length;
|
|
||||||
|
|
||||||
while(n-- && *d) d++; //find end of dest
|
|
||||||
size_t dlength = d - dest;
|
|
||||||
n = length - dlength; //subtract length of dest from maximum string length
|
|
||||||
|
|
||||||
if(!n) return dlength + strlen(s);
|
|
||||||
|
|
||||||
while(*s) {
|
|
||||||
if(n != 1) {
|
|
||||||
*d++ = *s;
|
|
||||||
n--;
|
|
||||||
}
|
|
||||||
s++;
|
|
||||||
}
|
|
||||||
*d = 0;
|
|
||||||
|
|
||||||
return dlength + (s - src); //return length of resulting string, sans null terminator
|
|
||||||
}
|
|
||||||
|
|
||||||
#endif
|
|
|
@ -1,50 +0,0 @@
|
||||||
#ifndef NALL_STRING_TRIM_HPP
|
|
||||||
#define NALL_STRING_TRIM_HPP
|
|
||||||
|
|
||||||
char* ltrim(char *str, const char *key) {
|
|
||||||
if(!key || !*key) return str;
|
|
||||||
while(strbegin(str, key)) {
|
|
||||||
char *dest = str, *src = str + strlen(key);
|
|
||||||
while(true) {
|
|
||||||
*dest = *src++;
|
|
||||||
if(!*dest) break;
|
|
||||||
dest++;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return str;
|
|
||||||
}
|
|
||||||
|
|
||||||
char* rtrim(char *str, const char *key) {
|
|
||||||
if(!key || !*key) return str;
|
|
||||||
while(strend(str, key)) str[strlen(str) - strlen(key)] = 0;
|
|
||||||
return str;
|
|
||||||
}
|
|
||||||
|
|
||||||
char* trim(char *str, const char *key) {
|
|
||||||
return ltrim(rtrim(str, key), key);
|
|
||||||
}
|
|
||||||
|
|
||||||
char* ltrim_once(char *str, const char *key) {
|
|
||||||
if(!key || !*key) return str;
|
|
||||||
if(strbegin(str, key)) {
|
|
||||||
char *dest = str, *src = str + strlen(key);
|
|
||||||
while(true) {
|
|
||||||
*dest = *src++;
|
|
||||||
if(!*dest) break;
|
|
||||||
dest++;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return str;
|
|
||||||
}
|
|
||||||
|
|
||||||
char* rtrim_once(char *str, const char *key) {
|
|
||||||
if(!key || !*key) return str;
|
|
||||||
if(strend(str, key)) str[strlen(str) - strlen(key)] = 0;
|
|
||||||
return str;
|
|
||||||
}
|
|
||||||
|
|
||||||
char* trim_once(char *str, const char *key) {
|
|
||||||
return ltrim_once(rtrim_once(str, key), key);
|
|
||||||
}
|
|
||||||
|
|
||||||
#endif
|
|
|
@ -1,165 +0,0 @@
|
||||||
#ifndef NALL_STRING_UTILITY_HPP
|
|
||||||
#define NALL_STRING_UTILITY_HPP
|
|
||||||
|
|
||||||
size_t strlcpy(nall::string &dest, const char *src, size_t length) {
|
|
||||||
dest.reserve(length);
|
|
||||||
return strlcpy(dest(), src, length);
|
|
||||||
}
|
|
||||||
|
|
||||||
size_t strlcat(nall::string &dest, const char *src, size_t length) {
|
|
||||||
dest.reserve(length);
|
|
||||||
return strlcat(dest(), src, length);
|
|
||||||
}
|
|
||||||
|
|
||||||
nall::string substr(const char *src, size_t start, size_t length) {
|
|
||||||
nall::string dest;
|
|
||||||
if(length == 0) {
|
|
||||||
//copy entire string
|
|
||||||
dest = src + start;
|
|
||||||
} else {
|
|
||||||
//copy partial string
|
|
||||||
strlcpy(dest, src + start, length + 1);
|
|
||||||
}
|
|
||||||
return dest;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* very simplistic wrappers to return nall::string& instead of char* type */
|
|
||||||
|
|
||||||
nall::string& strlower(nall::string &str) { strlower(str()); return str; }
|
|
||||||
nall::string& strupper(nall::string &str) { strupper(str()); return str; }
|
|
||||||
nall::string& strtr(nall::string &dest, const char *before, const char *after) { strtr(dest(), before, after); return dest; }
|
|
||||||
nall::string& ltrim(nall::string &str, const char *key) { ltrim(str(), key); return str; }
|
|
||||||
nall::string& rtrim(nall::string &str, const char *key) { rtrim(str(), key); return str; }
|
|
||||||
nall::string& trim (nall::string &str, const char *key) { trim (str(), key); return str; }
|
|
||||||
nall::string& ltrim_once(nall::string &str, const char *key) { ltrim_once(str(), key); return str; }
|
|
||||||
nall::string& rtrim_once(nall::string &str, const char *key) { rtrim_once(str(), key); return str; }
|
|
||||||
nall::string& trim_once (nall::string &str, const char *key) { trim_once (str(), key); return str; }
|
|
||||||
|
|
||||||
/* arithmetic <> string */
|
|
||||||
|
|
||||||
template<unsigned length, char padding> nall::string strhex(uintmax_t value) {
|
|
||||||
nall::string output;
|
|
||||||
unsigned offset = 0;
|
|
||||||
|
|
||||||
//render string backwards, as we do not know its length yet
|
|
||||||
do {
|
|
||||||
unsigned n = value & 15;
|
|
||||||
output[offset++] = n < 10 ? '0' + n : 'a' + n - 10;
|
|
||||||
value >>= 4;
|
|
||||||
} while(value);
|
|
||||||
|
|
||||||
while(offset < length) output[offset++] = padding;
|
|
||||||
output[offset--] = 0;
|
|
||||||
|
|
||||||
//reverse the string in-place
|
|
||||||
for(unsigned i = 0; i < (offset + 1) >> 1; i++) {
|
|
||||||
char temp = output[i];
|
|
||||||
output[i] = output[offset - i];
|
|
||||||
output[offset - i] = temp;
|
|
||||||
}
|
|
||||||
|
|
||||||
return output;
|
|
||||||
}
|
|
||||||
|
|
||||||
template<unsigned length, char padding> nall::string strsigned(intmax_t value) {
|
|
||||||
nall::string output;
|
|
||||||
unsigned offset = 0;
|
|
||||||
|
|
||||||
bool negative = value < 0;
|
|
||||||
if(negative) value = abs(value);
|
|
||||||
|
|
||||||
do {
|
|
||||||
unsigned n = value % 10;
|
|
||||||
output[offset++] = '0' + n;
|
|
||||||
value /= 10;
|
|
||||||
} while(value);
|
|
||||||
|
|
||||||
while(offset < length) output[offset++] = padding;
|
|
||||||
if(negative) output[offset++] = '-';
|
|
||||||
output[offset--] = 0;
|
|
||||||
|
|
||||||
for(unsigned i = 0; i < (offset + 1) >> 1; i++) {
|
|
||||||
char temp = output[i];
|
|
||||||
output[i] = output[offset - i];
|
|
||||||
output[offset - i] = temp;
|
|
||||||
}
|
|
||||||
|
|
||||||
return output;
|
|
||||||
}
|
|
||||||
|
|
||||||
template<unsigned length, char padding> nall::string strunsigned(uintmax_t value) {
|
|
||||||
nall::string output;
|
|
||||||
unsigned offset = 0;
|
|
||||||
|
|
||||||
do {
|
|
||||||
unsigned n = value % 10;
|
|
||||||
output[offset++] = '0' + n;
|
|
||||||
value /= 10;
|
|
||||||
} while(value);
|
|
||||||
|
|
||||||
while(offset < length) output[offset++] = padding;
|
|
||||||
output[offset--] = 0;
|
|
||||||
|
|
||||||
for(unsigned i = 0; i < (offset + 1) >> 1; i++) {
|
|
||||||
char temp = output[i];
|
|
||||||
output[i] = output[offset - i];
|
|
||||||
output[offset - i] = temp;
|
|
||||||
}
|
|
||||||
|
|
||||||
return output;
|
|
||||||
}
|
|
||||||
|
|
||||||
template<unsigned length, char padding> nall::string strbin(uintmax_t value) {
|
|
||||||
nall::string output;
|
|
||||||
unsigned offset = 0;
|
|
||||||
|
|
||||||
do {
|
|
||||||
unsigned n = value & 1;
|
|
||||||
output[offset++] = '0' + n;
|
|
||||||
value >>= 1;
|
|
||||||
} while(value);
|
|
||||||
|
|
||||||
while(offset < length) output[offset++] = padding;
|
|
||||||
output[offset--] = 0;
|
|
||||||
|
|
||||||
for(unsigned i = 0; i < (offset + 1) >> 1; i++) {
|
|
||||||
char temp = output[i];
|
|
||||||
output[i] = output[offset - i];
|
|
||||||
output[offset - i] = temp;
|
|
||||||
}
|
|
||||||
|
|
||||||
return output;
|
|
||||||
}
|
|
||||||
|
|
||||||
//using sprintf is certainly not the most ideal method to convert
|
|
||||||
//a double to a string ... but attempting to parse a double by
|
|
||||||
//hand, digit-by-digit, results in subtle rounding errors.
|
|
||||||
size_t strdouble(char *str, double value) {
|
|
||||||
char buffer[256];
|
|
||||||
sprintf(buffer, "%f", value);
|
|
||||||
|
|
||||||
//remove excess 0's in fraction (2.500000 -> 2.5)
|
|
||||||
for(char *p = buffer; *p; p++) {
|
|
||||||
if(*p == '.') {
|
|
||||||
char *p = buffer + strlen(buffer) - 1;
|
|
||||||
while(*p == '0') {
|
|
||||||
if(*(p - 1) != '.') *p = 0; //... but not for eg 1.0 -> 1.
|
|
||||||
p--;
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
unsigned length = strlen(buffer);
|
|
||||||
if(str) strcpy(str, buffer);
|
|
||||||
return length + 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
nall::string strdouble(double value) {
|
|
||||||
nall::string temp;
|
|
||||||
temp.reserve(strdouble(0, value));
|
|
||||||
strdouble(temp(), value);
|
|
||||||
return temp;
|
|
||||||
}
|
|
||||||
|
|
||||||
#endif
|
|
|
@ -1,37 +0,0 @@
|
||||||
#ifndef NALL_STRING_VARIADIC_HPP
|
|
||||||
#define NALL_STRING_VARIADIC_HPP
|
|
||||||
|
|
||||||
namespace nall {
|
|
||||||
static void sprint(string &output, unsigned &offset, const char *&s) {
|
|
||||||
while(*s) output[offset++] = *s++;
|
|
||||||
}
|
|
||||||
|
|
||||||
template<typename T, typename... Args>
|
|
||||||
static void sprint(string &output, unsigned &offset, const char *&s, T value, Args... args) {
|
|
||||||
while(*s) {
|
|
||||||
if(*s == '$') {
|
|
||||||
string data = to_string<T>(value);
|
|
||||||
unsigned i = 0;
|
|
||||||
while(data[i]) output[offset++] = data[i++];
|
|
||||||
sprint(output, offset, ++s, args...);
|
|
||||||
return;
|
|
||||||
} else {
|
|
||||||
output[offset++] = *s++;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
template<typename... Args> inline string sprint(const char *s, Args... args) {
|
|
||||||
string output;
|
|
||||||
unsigned offset = 0;
|
|
||||||
sprint(output, offset, s, args...);
|
|
||||||
output[offset] = 0;
|
|
||||||
return output;
|
|
||||||
}
|
|
||||||
|
|
||||||
template<typename... Args> inline void print(const char *s, Args... args) {
|
|
||||||
printf("%s", (const char*)sprint(s, args...));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#endif
|
|
|
@ -1,268 +0,0 @@
|
||||||
#ifndef NALL_STRING_XML_HPP
|
|
||||||
#define NALL_STRING_XML_HPP
|
|
||||||
|
|
||||||
//XML subset parser
|
|
||||||
//version 0.04
|
|
||||||
|
|
||||||
#include <nall/array.hpp>
|
|
||||||
|
|
||||||
namespace nall {
|
|
||||||
|
|
||||||
struct xml_attribute {
|
|
||||||
string name;
|
|
||||||
string content;
|
|
||||||
virtual string parse() const;
|
|
||||||
};
|
|
||||||
|
|
||||||
struct xml_element : xml_attribute {
|
|
||||||
string parse() const;
|
|
||||||
array<xml_attribute*> attribute;
|
|
||||||
array<xml_element*> element;
|
|
||||||
~xml_element();
|
|
||||||
|
|
||||||
protected:
|
|
||||||
void parse_doctype(const char *&data);
|
|
||||||
bool parse_head(string data);
|
|
||||||
bool parse_body(const char *&data);
|
|
||||||
friend xml_element *xml_parse(const char *data);
|
|
||||||
};
|
|
||||||
|
|
||||||
inline string xml_attribute::parse() const {
|
|
||||||
string data;
|
|
||||||
unsigned offset = 0;
|
|
||||||
|
|
||||||
const char *source = content;
|
|
||||||
while(*source) {
|
|
||||||
if(*source == '&') {
|
|
||||||
if(strbegin(source, "<")) { data[offset++] = '<'; source += 4; continue; }
|
|
||||||
if(strbegin(source, ">")) { data[offset++] = '>'; source += 4; continue; }
|
|
||||||
if(strbegin(source, "&")) { data[offset++] = '&'; source += 5; continue; }
|
|
||||||
if(strbegin(source, "'")) { data[offset++] = '\''; source += 6; continue; }
|
|
||||||
if(strbegin(source, """)) { data[offset++] = '"'; source += 6; continue; }
|
|
||||||
}
|
|
||||||
|
|
||||||
//reject illegal characters
|
|
||||||
if(*source == '&') return "";
|
|
||||||
if(*source == '<') return "";
|
|
||||||
if(*source == '>') return "";
|
|
||||||
|
|
||||||
data[offset++] = *source++;
|
|
||||||
}
|
|
||||||
|
|
||||||
data[offset] = 0;
|
|
||||||
return data;
|
|
||||||
}
|
|
||||||
|
|
||||||
inline string xml_element::parse() const {
|
|
||||||
string data;
|
|
||||||
unsigned offset = 0;
|
|
||||||
|
|
||||||
const char *source = content;
|
|
||||||
while(*source) {
|
|
||||||
if(*source == '&') {
|
|
||||||
if(strbegin(source, "<")) { data[offset++] = '<'; source += 4; continue; }
|
|
||||||
if(strbegin(source, ">")) { data[offset++] = '>'; source += 4; continue; }
|
|
||||||
if(strbegin(source, "&")) { data[offset++] = '&'; source += 5; continue; }
|
|
||||||
if(strbegin(source, "'")) { data[offset++] = '\''; source += 6; continue; }
|
|
||||||
if(strbegin(source, """)) { data[offset++] = '"'; source += 6; continue; }
|
|
||||||
}
|
|
||||||
|
|
||||||
if(strbegin(source, "<!--")) {
|
|
||||||
signed pos = strpos(source, "-->");
|
|
||||||
if(pos == -1) return "";
|
|
||||||
source += pos + 3;
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
if(strbegin(source, "<![CDATA[")) {
|
|
||||||
signed pos = strpos(source, "]]>");
|
|
||||||
if(pos == -1) return "";
|
|
||||||
string cdata = substr(source, 9, pos - 9);
|
|
||||||
data << cdata;
|
|
||||||
offset += strlen(cdata);
|
|
||||||
|
|
||||||
source += offset + 3;
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
//reject illegal characters
|
|
||||||
if(*source == '&') return "";
|
|
||||||
if(*source == '<') return "";
|
|
||||||
if(*source == '>') return "";
|
|
||||||
|
|
||||||
data[offset++] = *source++;
|
|
||||||
}
|
|
||||||
|
|
||||||
data[offset] = 0;
|
|
||||||
return data;
|
|
||||||
}
|
|
||||||
|
|
||||||
inline void xml_element::parse_doctype(const char *&data) {
|
|
||||||
name = "!DOCTYPE";
|
|
||||||
const char *content_begin = data;
|
|
||||||
|
|
||||||
signed counter = 0;
|
|
||||||
while(*data) {
|
|
||||||
char value = *data++;
|
|
||||||
if(value == '<') counter++;
|
|
||||||
if(value == '>') counter--;
|
|
||||||
if(counter < 0) {
|
|
||||||
content = substr(content_begin, 0, data - content_begin - 1);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
throw "...";
|
|
||||||
}
|
|
||||||
|
|
||||||
inline bool xml_element::parse_head(string data) {
|
|
||||||
data.qreplace("\t", " ");
|
|
||||||
data.qreplace("\r", " ");
|
|
||||||
data.qreplace("\n", " ");
|
|
||||||
while(qstrpos(data, " ") >= 0) data.qreplace(" ", " ");
|
|
||||||
data.qreplace(" =", "=");
|
|
||||||
data.qreplace("= ", "=");
|
|
||||||
rtrim(data);
|
|
||||||
|
|
||||||
lstring part;
|
|
||||||
part.qsplit(" ", data);
|
|
||||||
|
|
||||||
name = part[0];
|
|
||||||
if(name == "") throw "...";
|
|
||||||
|
|
||||||
for(unsigned i = 1; i < part.size(); i++) {
|
|
||||||
lstring side;
|
|
||||||
side.qsplit("=", part[i]);
|
|
||||||
if(side.size() != 2) throw "...";
|
|
||||||
|
|
||||||
xml_attribute *attr = new xml_attribute;
|
|
||||||
attr->name = side[0];
|
|
||||||
attr->content = side[1];
|
|
||||||
if(strbegin(attr->content, "\"") && strend(attr->content, "\"")) trim_once(attr->content, "\"");
|
|
||||||
else if(strbegin(attr->content, "'") && strend(attr->content, "'")) trim_once(attr->content, "'");
|
|
||||||
else throw "...";
|
|
||||||
attribute.add(attr);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
inline bool xml_element::parse_body(const char *&data) {
|
|
||||||
while(true) {
|
|
||||||
if(!*data) return false;
|
|
||||||
if(*data++ != '<') continue;
|
|
||||||
if(*data == '/') return false;
|
|
||||||
|
|
||||||
if(strbegin(data, "!DOCTYPE") == true) {
|
|
||||||
parse_doctype(data);
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
if(strbegin(data, "!--")) {
|
|
||||||
signed offset = strpos(data, "-->");
|
|
||||||
if(offset == -1) throw "...";
|
|
||||||
data += offset + 3;
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
if(strbegin(data, "![CDATA[")) {
|
|
||||||
signed offset = strpos(data, "]]>");
|
|
||||||
if(offset == -1) throw "...";
|
|
||||||
data += offset + 3;
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
signed offset = strpos(data, ">");
|
|
||||||
if(offset == -1) throw "...";
|
|
||||||
|
|
||||||
string tag = substr(data, 0, offset);
|
|
||||||
data += offset + 1;
|
|
||||||
const char *content_begin = data;
|
|
||||||
|
|
||||||
bool self_terminating = false;
|
|
||||||
|
|
||||||
if(strend(tag, "?") == true) {
|
|
||||||
self_terminating = true;
|
|
||||||
rtrim_once(tag, "?");
|
|
||||||
} else if(strend(tag, "/") == true) {
|
|
||||||
self_terminating = true;
|
|
||||||
rtrim_once(tag, "/");
|
|
||||||
}
|
|
||||||
|
|
||||||
parse_head(tag);
|
|
||||||
if(self_terminating) return true;
|
|
||||||
|
|
||||||
while(*data) {
|
|
||||||
unsigned index = element.size();
|
|
||||||
xml_element *elem = new xml_element;
|
|
||||||
if(elem->parse_body(data) == false) {
|
|
||||||
delete elem;
|
|
||||||
|
|
||||||
if(*data == '/') {
|
|
||||||
signed length = data - content_begin - 1;
|
|
||||||
if(length > 0) content = substr(content_begin, 0, length);
|
|
||||||
|
|
||||||
data++;
|
|
||||||
offset = strpos(data, ">");
|
|
||||||
if(offset == -1) throw "...";
|
|
||||||
|
|
||||||
tag = substr(data, 0, offset);
|
|
||||||
data += offset + 1;
|
|
||||||
|
|
||||||
tag.replace("\t", " ");
|
|
||||||
tag.replace("\r", " ");
|
|
||||||
tag.replace("\n", " ");
|
|
||||||
while(strpos(tag, " ") >= 0) tag.replace(" ", " ");
|
|
||||||
rtrim(tag);
|
|
||||||
|
|
||||||
if(name != tag) throw "...";
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
element.add(elem);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
inline xml_element::~xml_element() {
|
|
||||||
for(unsigned i = 0; i < attribute.size(); i++) delete attribute[i];
|
|
||||||
for(unsigned i = 0; i < element.size(); i++) delete element[i];
|
|
||||||
}
|
|
||||||
|
|
||||||
//ensure there is only one root element
|
|
||||||
inline bool xml_validate(xml_element *document) {
|
|
||||||
unsigned root_counter = 0;
|
|
||||||
|
|
||||||
for(unsigned i = 0; i < document->element.size(); i++) {
|
|
||||||
string &name = document->element[i]->name;
|
|
||||||
if(strbegin(name, "?")) continue;
|
|
||||||
if(strbegin(name, "!")) continue;
|
|
||||||
if(++root_counter > 1) return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
inline xml_element* xml_parse(const char *data) {
|
|
||||||
xml_element *self = new xml_element;
|
|
||||||
|
|
||||||
try {
|
|
||||||
while(*data) {
|
|
||||||
xml_element *elem = new xml_element;
|
|
||||||
if(elem->parse_body(data) == false) {
|
|
||||||
delete elem;
|
|
||||||
break;
|
|
||||||
} else {
|
|
||||||
self->element.add(elem);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if(xml_validate(self) == false) throw "...";
|
|
||||||
return self;
|
|
||||||
} catch(const char*) {
|
|
||||||
delete self;
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
#endif
|
|
|
@ -1,97 +0,0 @@
|
||||||
#ifndef NALL_TRAITS_HPP
|
|
||||||
#define NALL_TRAITS_HPP
|
|
||||||
|
|
||||||
namespace nall {
|
|
||||||
//==
|
|
||||||
//is
|
|
||||||
//==
|
|
||||||
|
|
||||||
template<typename T> struct is_integral { enum { value = false }; };
|
|
||||||
template<> struct is_integral<bool> { enum { value = true }; };
|
|
||||||
template<> struct is_integral<char> { enum { value = true }; };
|
|
||||||
template<> struct is_integral<signed char> { enum { value = true }; };
|
|
||||||
template<> struct is_integral<unsigned char> { enum { value = true }; };
|
|
||||||
template<> struct is_integral<wchar_t> { enum { value = true }; };
|
|
||||||
template<> struct is_integral<short> { enum { value = true }; };
|
|
||||||
template<> struct is_integral<unsigned short> { enum { value = true }; };
|
|
||||||
template<> struct is_integral<long> { enum { value = true }; };
|
|
||||||
template<> struct is_integral<unsigned long> { enum { value = true }; };
|
|
||||||
template<> struct is_integral<long long> { enum { value = true }; };
|
|
||||||
template<> struct is_integral<unsigned long long> { enum { value = true }; };
|
|
||||||
template<> struct is_integral<int> { enum { value = true }; };
|
|
||||||
template<> struct is_integral<unsigned int> { enum { value = true }; };
|
|
||||||
|
|
||||||
template<typename T> struct is_floating_point { enum { value = false }; };
|
|
||||||
template<> struct is_floating_point<float> { enum { value = true }; };
|
|
||||||
template<> struct is_floating_point<double> { enum { value = true }; };
|
|
||||||
template<> struct is_floating_point<long double> { enum { value = true }; };
|
|
||||||
|
|
||||||
template<typename T> struct is_bool { enum { value = false }; };
|
|
||||||
template<> struct is_bool<bool> { enum { value = true }; };
|
|
||||||
|
|
||||||
template<typename T> struct is_void { enum { value = false }; };
|
|
||||||
template<> struct is_void<void> { enum { value = true }; };
|
|
||||||
|
|
||||||
template<typename T> struct is_arithmetic {
|
|
||||||
enum { value = is_integral<T>::value || is_floating_point<T>::value };
|
|
||||||
};
|
|
||||||
|
|
||||||
template<typename T> struct is_fundamental {
|
|
||||||
enum { value = is_integral<T>::value || is_floating_point<T>::value || is_void<T>::value };
|
|
||||||
};
|
|
||||||
|
|
||||||
template<typename T> struct is_compound {
|
|
||||||
enum { value = !is_fundamental<T>::value };
|
|
||||||
};
|
|
||||||
|
|
||||||
template<typename T> struct is_array { enum { value = false }; };
|
|
||||||
template<typename T> struct is_array<T[]> { enum { value = true }; };
|
|
||||||
template<typename T, int N> struct is_array<T[N]> { enum { value = true }; };
|
|
||||||
|
|
||||||
template<typename T> struct is_const { enum { value = false }; };
|
|
||||||
template<typename T> struct is_const<const T> { enum { value = true }; };
|
|
||||||
template<typename T> struct is_const<const T&> { enum { value = true }; };
|
|
||||||
|
|
||||||
template<typename T> struct is_pointer { enum { value = false }; };
|
|
||||||
template<typename T> struct is_pointer<T*> { enum { value = true }; };
|
|
||||||
|
|
||||||
template<typename T> struct is_reference { enum { value = false }; };
|
|
||||||
template<typename T> struct is_reference<T&> { enum { value = true }; };
|
|
||||||
|
|
||||||
template<typename T, typename U> struct is_same { enum { value = false }; };
|
|
||||||
template<typename T> struct is_same<T, T> { enum { value = true }; };
|
|
||||||
|
|
||||||
//===
|
|
||||||
//add
|
|
||||||
//===
|
|
||||||
|
|
||||||
template<typename T> struct add_const { typedef const T type; };
|
|
||||||
template<typename T> struct add_const<const T> { typedef const T type; };
|
|
||||||
template<typename T> struct add_const<const T&> { typedef const T& type; };
|
|
||||||
|
|
||||||
template<typename T> struct add_pointer { typedef T* type; };
|
|
||||||
template<typename T> struct add_pointer<T*> { typedef T** type; };
|
|
||||||
|
|
||||||
template<typename T> struct add_reference { typedef T& type; };
|
|
||||||
template<typename T> struct add_reference<T&> { typedef T& type; };
|
|
||||||
|
|
||||||
//======
|
|
||||||
//remove
|
|
||||||
//======
|
|
||||||
|
|
||||||
template<typename T> struct remove_const { typedef T type; };
|
|
||||||
template<typename T> struct remove_const<const T> { typedef T type; };
|
|
||||||
template<typename T> struct remove_const<const T&> { typedef T type; };
|
|
||||||
|
|
||||||
template<typename T> struct remove_extent { typedef T type; };
|
|
||||||
template<typename T> struct remove_extent<T[]> { typedef T type; };
|
|
||||||
template<typename T, int N> struct remove_extent<T[N]> { typedef T type; };
|
|
||||||
|
|
||||||
template<typename T> struct remove_pointer { typedef T type; };
|
|
||||||
template<typename T> struct remove_pointer<T*> { typedef T type; };
|
|
||||||
|
|
||||||
template<typename T> struct remove_reference { typedef T type; };
|
|
||||||
template<typename T> struct remove_reference<T&> { typedef T type; };
|
|
||||||
}
|
|
||||||
|
|
||||||
#endif
|
|
|
@ -1,190 +0,0 @@
|
||||||
#ifndef NALL_UPS_HPP
|
|
||||||
#define NALL_UPS_HPP
|
|
||||||
|
|
||||||
#include <stdio.h>
|
|
||||||
|
|
||||||
#include <nall/algorithm.hpp>
|
|
||||||
#include <nall/crc32.hpp>
|
|
||||||
#include <nall/file.hpp>
|
|
||||||
#include <nall/stdint.hpp>
|
|
||||||
|
|
||||||
namespace nall {
|
|
||||||
class ups {
|
|
||||||
public:
|
|
||||||
enum result {
|
|
||||||
ok,
|
|
||||||
patch_unreadable,
|
|
||||||
patch_unwritable,
|
|
||||||
patch_invalid,
|
|
||||||
input_invalid,
|
|
||||||
output_invalid,
|
|
||||||
patch_crc32_invalid,
|
|
||||||
input_crc32_invalid,
|
|
||||||
output_crc32_invalid,
|
|
||||||
};
|
|
||||||
|
|
||||||
ups::result create(const char *patch_fn, const uint8_t *x_data, unsigned x_size, const uint8_t *y_data, unsigned y_size) {
|
|
||||||
if(!fp.open(patch_fn, file::mode_write)) return patch_unwritable;
|
|
||||||
|
|
||||||
crc32 = ~0;
|
|
||||||
uint32_t x_crc32 = crc32_calculate(x_data, x_size);
|
|
||||||
uint32_t y_crc32 = crc32_calculate(y_data, y_size);
|
|
||||||
|
|
||||||
//header
|
|
||||||
write('U');
|
|
||||||
write('P');
|
|
||||||
write('S');
|
|
||||||
write('1');
|
|
||||||
encptr(x_size);
|
|
||||||
encptr(y_size);
|
|
||||||
|
|
||||||
//body
|
|
||||||
unsigned max_size = max(x_size, y_size);
|
|
||||||
unsigned relative = 0;
|
|
||||||
for(unsigned i = 0; i < max_size;) {
|
|
||||||
uint8_t x = i < x_size ? x_data[i] : 0x00;
|
|
||||||
uint8_t y = i < y_size ? y_data[i] : 0x00;
|
|
||||||
|
|
||||||
if(x == y) {
|
|
||||||
i++;
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
encptr(i++ - relative);
|
|
||||||
write(x ^ y);
|
|
||||||
|
|
||||||
while(true) {
|
|
||||||
if(i >= max_size) {
|
|
||||||
write(0x00);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
x = i < x_size ? x_data[i] : 0x00;
|
|
||||||
y = i < y_size ? y_data[i] : 0x00;
|
|
||||||
i++;
|
|
||||||
write(x ^ y);
|
|
||||||
if(x == y) break;
|
|
||||||
}
|
|
||||||
|
|
||||||
relative = i;
|
|
||||||
}
|
|
||||||
|
|
||||||
//footer
|
|
||||||
for(unsigned i = 0; i < 4; i++) write(x_crc32 >> (i << 3));
|
|
||||||
for(unsigned i = 0; i < 4; i++) write(y_crc32 >> (i << 3));
|
|
||||||
uint32_t p_crc32 = ~crc32;
|
|
||||||
for(unsigned i = 0; i < 4; i++) write(p_crc32 >> (i << 3));
|
|
||||||
|
|
||||||
fp.close();
|
|
||||||
return ok;
|
|
||||||
}
|
|
||||||
|
|
||||||
ups::result apply(const uint8_t *p_data, unsigned p_size, const uint8_t *x_data, unsigned x_size, uint8_t *&y_data, unsigned &y_size) {
|
|
||||||
if(p_size < 18) return patch_invalid;
|
|
||||||
p_buffer = p_data;
|
|
||||||
|
|
||||||
crc32 = ~0;
|
|
||||||
|
|
||||||
//header
|
|
||||||
if(read() != 'U') return patch_invalid;
|
|
||||||
if(read() != 'P') return patch_invalid;
|
|
||||||
if(read() != 'S') return patch_invalid;
|
|
||||||
if(read() != '1') return patch_invalid;
|
|
||||||
|
|
||||||
unsigned px_size = decptr();
|
|
||||||
unsigned py_size = decptr();
|
|
||||||
|
|
||||||
//mirror
|
|
||||||
if(x_size != px_size && x_size != py_size) return input_invalid;
|
|
||||||
y_size = (x_size == px_size) ? py_size : px_size;
|
|
||||||
y_data = new uint8_t[y_size]();
|
|
||||||
|
|
||||||
for(unsigned i = 0; i < x_size && i < y_size; i++) y_data[i] = x_data[i];
|
|
||||||
for(unsigned i = x_size; i < y_size; i++) y_data[i] = 0x00;
|
|
||||||
|
|
||||||
//body
|
|
||||||
unsigned relative = 0;
|
|
||||||
while(p_buffer < p_data + p_size - 12) {
|
|
||||||
relative += decptr();
|
|
||||||
|
|
||||||
while(true) {
|
|
||||||
uint8_t x = read();
|
|
||||||
if(x && relative < y_size) {
|
|
||||||
uint8_t y = relative < x_size ? x_data[relative] : 0x00;
|
|
||||||
y_data[relative] = x ^ y;
|
|
||||||
}
|
|
||||||
relative++;
|
|
||||||
if(!x) break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
//footer
|
|
||||||
unsigned px_crc32 = 0, py_crc32 = 0, pp_crc32 = 0;
|
|
||||||
for(unsigned i = 0; i < 4; i++) px_crc32 |= read() << (i << 3);
|
|
||||||
for(unsigned i = 0; i < 4; i++) py_crc32 |= read() << (i << 3);
|
|
||||||
uint32_t p_crc32 = ~crc32;
|
|
||||||
for(unsigned i = 0; i < 4; i++) pp_crc32 |= read() << (i << 3);
|
|
||||||
|
|
||||||
uint32_t x_crc32 = crc32_calculate(x_data, x_size);
|
|
||||||
uint32_t y_crc32 = crc32_calculate(y_data, y_size);
|
|
||||||
|
|
||||||
if(px_size != py_size) {
|
|
||||||
if(x_size == px_size && x_crc32 != px_crc32) return input_crc32_invalid;
|
|
||||||
if(x_size == py_size && x_crc32 != py_crc32) return input_crc32_invalid;
|
|
||||||
if(y_size == px_size && y_crc32 != px_crc32) return output_crc32_invalid;
|
|
||||||
if(y_size == py_size && y_crc32 != py_crc32) return output_crc32_invalid;
|
|
||||||
} else {
|
|
||||||
if(x_crc32 != px_crc32 && x_crc32 != py_crc32) return input_crc32_invalid;
|
|
||||||
if(y_crc32 != px_crc32 && y_crc32 != py_crc32) return output_crc32_invalid;
|
|
||||||
if(x_crc32 == y_crc32 && px_crc32 != py_crc32) return output_crc32_invalid;
|
|
||||||
if(x_crc32 != y_crc32 && px_crc32 == py_crc32) return output_crc32_invalid;
|
|
||||||
}
|
|
||||||
|
|
||||||
if(p_crc32 != pp_crc32) return patch_crc32_invalid;
|
|
||||||
return ok;
|
|
||||||
}
|
|
||||||
|
|
||||||
private:
|
|
||||||
file fp;
|
|
||||||
uint32_t crc32;
|
|
||||||
const uint8_t *p_buffer;
|
|
||||||
|
|
||||||
uint8_t read() {
|
|
||||||
uint8_t n = *p_buffer++;
|
|
||||||
crc32 = crc32_adjust(crc32, n);
|
|
||||||
return n;
|
|
||||||
}
|
|
||||||
|
|
||||||
void write(uint8_t n) {
|
|
||||||
fp.write(n);
|
|
||||||
crc32 = crc32_adjust(crc32, n);
|
|
||||||
}
|
|
||||||
|
|
||||||
void encptr(uint64_t offset) {
|
|
||||||
while(true) {
|
|
||||||
uint64_t x = offset & 0x7f;
|
|
||||||
offset >>= 7;
|
|
||||||
if(offset == 0) {
|
|
||||||
write(0x80 | x);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
write(x);
|
|
||||||
offset--;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
uint64_t decptr() {
|
|
||||||
uint64_t offset = 0, shift = 1;
|
|
||||||
while(true) {
|
|
||||||
uint8_t x = read();
|
|
||||||
offset += (x & 0x7f) * shift;
|
|
||||||
if(x & 0x80) break;
|
|
||||||
shift <<= 7;
|
|
||||||
offset += shift;
|
|
||||||
}
|
|
||||||
return offset;
|
|
||||||
}
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
#endif
|
|
|
@ -1,72 +0,0 @@
|
||||||
#ifndef NALL_UTF8_HPP
|
|
||||||
#define NALL_UTF8_HPP
|
|
||||||
|
|
||||||
//UTF-8 <> UTF-16 conversion
|
|
||||||
//used only for Win32; Linux, etc use UTF-8 internally
|
|
||||||
|
|
||||||
#if defined(_WIN32)
|
|
||||||
|
|
||||||
#undef _WIN32_WINNT
|
|
||||||
#define _WIN32_WINNT 0x0501
|
|
||||||
#undef NOMINMAX
|
|
||||||
#define NOMINMAX
|
|
||||||
#include <windows.h>
|
|
||||||
#undef interface
|
|
||||||
|
|
||||||
namespace nall {
|
|
||||||
//UTF-8 to UTF-16
|
|
||||||
class utf16_t {
|
|
||||||
public:
|
|
||||||
operator wchar_t*() {
|
|
||||||
return buffer;
|
|
||||||
}
|
|
||||||
|
|
||||||
operator const wchar_t*() const {
|
|
||||||
return buffer;
|
|
||||||
}
|
|
||||||
|
|
||||||
utf16_t(const char *s = "") {
|
|
||||||
if(!s) s = "";
|
|
||||||
unsigned length = MultiByteToWideChar(CP_UTF8, 0, s, -1, 0, 0);
|
|
||||||
buffer = new wchar_t[length + 1]();
|
|
||||||
MultiByteToWideChar(CP_UTF8, 0, s, -1, buffer, length);
|
|
||||||
}
|
|
||||||
|
|
||||||
~utf16_t() {
|
|
||||||
delete[] buffer;
|
|
||||||
}
|
|
||||||
|
|
||||||
private:
|
|
||||||
wchar_t *buffer;
|
|
||||||
};
|
|
||||||
|
|
||||||
//UTF-16 to UTF-8
|
|
||||||
class utf8_t {
|
|
||||||
public:
|
|
||||||
operator char*() {
|
|
||||||
return buffer;
|
|
||||||
}
|
|
||||||
|
|
||||||
operator const char*() const {
|
|
||||||
return buffer;
|
|
||||||
}
|
|
||||||
|
|
||||||
utf8_t(const wchar_t *s = L"") {
|
|
||||||
if(!s) s = L"";
|
|
||||||
unsigned length = WideCharToMultiByte(CP_UTF8, 0, s, -1, 0, 0, (const char*)0, (BOOL*)0);
|
|
||||||
buffer = new char[length + 1]();
|
|
||||||
WideCharToMultiByte(CP_UTF8, 0, s, -1, buffer, length, (const char*)0, (BOOL*)0);
|
|
||||||
}
|
|
||||||
|
|
||||||
~utf8_t() {
|
|
||||||
delete[] buffer;
|
|
||||||
}
|
|
||||||
|
|
||||||
private:
|
|
||||||
char *buffer;
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
#endif //if defined(_WIN32)
|
|
||||||
|
|
||||||
#endif
|
|
|
@ -1,41 +0,0 @@
|
||||||
#ifndef NALL_UTILITY_HPP
|
|
||||||
#define NALL_UTILITY_HPP
|
|
||||||
|
|
||||||
#include <nall/traits.hpp>
|
|
||||||
|
|
||||||
namespace nall {
|
|
||||||
template<typename T> struct identity {
|
|
||||||
typedef T type;
|
|
||||||
};
|
|
||||||
|
|
||||||
template<typename T> typename remove_reference<T>::type&& move(T &&value) {
|
|
||||||
return value;
|
|
||||||
}
|
|
||||||
|
|
||||||
template<typename T> T&& forward(typename identity<T>::type &&value) {
|
|
||||||
return value;
|
|
||||||
}
|
|
||||||
|
|
||||||
template<bool C, typename T = bool> struct enable_if { typedef T type; };
|
|
||||||
template<typename T> struct enable_if<false, T> {};
|
|
||||||
template<typename C, typename T = bool> struct mp_enable_if : enable_if<C::value, T> {};
|
|
||||||
|
|
||||||
template<typename T> inline void swap(T &x, T &y) {
|
|
||||||
T temp(move(x));
|
|
||||||
x = move(y);
|
|
||||||
y = move(temp);
|
|
||||||
}
|
|
||||||
|
|
||||||
template<typename T> struct base_from_member {
|
|
||||||
T value;
|
|
||||||
base_from_member(T value_) : value(value_) {}
|
|
||||||
};
|
|
||||||
|
|
||||||
template<typename T> inline T* allocate(size_t size, const T &value) {
|
|
||||||
T *array = new T[size];
|
|
||||||
for(size_t i = 0; i < size; i++) array[i] = value;
|
|
||||||
return array;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#endif
|
|
|
@ -1,92 +0,0 @@
|
||||||
#ifndef NALL_VARINT_HPP
|
|
||||||
#define NALL_VARINT_HPP
|
|
||||||
|
|
||||||
#include <nall/bit.hpp>
|
|
||||||
#include <nall/static.hpp>
|
|
||||||
#include <nall/traits.hpp>
|
|
||||||
|
|
||||||
namespace nall {
|
|
||||||
template<unsigned bits> class uint_t {
|
|
||||||
private:
|
|
||||||
enum { bytes = (bits + 7) >> 3 }; //minimum number of bytes needed to store value
|
|
||||||
typedef typename static_if<
|
|
||||||
sizeof(int) >= bytes,
|
|
||||||
unsigned int,
|
|
||||||
typename static_if<
|
|
||||||
sizeof(long) >= bytes,
|
|
||||||
unsigned long,
|
|
||||||
typename static_if<
|
|
||||||
sizeof(long long) >= bytes,
|
|
||||||
unsigned long long,
|
|
||||||
void
|
|
||||||
>::type
|
|
||||||
>::type
|
|
||||||
>::type T;
|
|
||||||
static_assert<!is_void<T>::value> uint_assert;
|
|
||||||
T data;
|
|
||||||
|
|
||||||
public:
|
|
||||||
inline operator T() const { return data; }
|
|
||||||
inline T operator ++(int) { T r = data; data = uclip<bits>(data + 1); return r; }
|
|
||||||
inline T operator --(int) { T r = data; data = uclip<bits>(data - 1); return r; }
|
|
||||||
inline T operator ++() { return data = uclip<bits>(data + 1); }
|
|
||||||
inline T operator --() { return data = uclip<bits>(data - 1); }
|
|
||||||
inline T operator =(const T i) { return data = uclip<bits>(i); }
|
|
||||||
inline T operator |=(const T i) { return data = uclip<bits>(data | i); }
|
|
||||||
inline T operator ^=(const T i) { return data = uclip<bits>(data ^ i); }
|
|
||||||
inline T operator &=(const T i) { return data = uclip<bits>(data & i); }
|
|
||||||
inline T operator<<=(const T i) { return data = uclip<bits>(data << i); }
|
|
||||||
inline T operator>>=(const T i) { return data = uclip<bits>(data >> i); }
|
|
||||||
inline T operator +=(const T i) { return data = uclip<bits>(data + i); }
|
|
||||||
inline T operator -=(const T i) { return data = uclip<bits>(data - i); }
|
|
||||||
inline T operator *=(const T i) { return data = uclip<bits>(data * i); }
|
|
||||||
inline T operator /=(const T i) { return data = uclip<bits>(data / i); }
|
|
||||||
inline T operator %=(const T i) { return data = uclip<bits>(data % i); }
|
|
||||||
|
|
||||||
inline uint_t() : data(0) {}
|
|
||||||
inline uint_t(const T i) : data(uclip<bits>(i)) {}
|
|
||||||
};
|
|
||||||
|
|
||||||
template<unsigned bits> class int_t {
|
|
||||||
private:
|
|
||||||
enum { bytes = (bits + 7) >> 3 }; //minimum number of bytes needed to store value
|
|
||||||
typedef typename static_if<
|
|
||||||
sizeof(int) >= bytes,
|
|
||||||
signed int,
|
|
||||||
typename static_if<
|
|
||||||
sizeof(long) >= bytes,
|
|
||||||
signed long,
|
|
||||||
typename static_if<
|
|
||||||
sizeof(long long) >= bytes,
|
|
||||||
signed long long,
|
|
||||||
void
|
|
||||||
>::type
|
|
||||||
>::type
|
|
||||||
>::type T;
|
|
||||||
static_assert<!is_void<T>::value> int_assert;
|
|
||||||
T data;
|
|
||||||
|
|
||||||
public:
|
|
||||||
inline operator T() const { return data; }
|
|
||||||
inline T operator ++(int) { T r = data; data = sclip<bits>(data + 1); return r; }
|
|
||||||
inline T operator --(int) { T r = data; data = sclip<bits>(data - 1); return r; }
|
|
||||||
inline T operator ++() { return data = sclip<bits>(data + 1); }
|
|
||||||
inline T operator --() { return data = sclip<bits>(data - 1); }
|
|
||||||
inline T operator =(const T i) { return data = sclip<bits>(i); }
|
|
||||||
inline T operator |=(const T i) { return data = sclip<bits>(data | i); }
|
|
||||||
inline T operator ^=(const T i) { return data = sclip<bits>(data ^ i); }
|
|
||||||
inline T operator &=(const T i) { return data = sclip<bits>(data & i); }
|
|
||||||
inline T operator<<=(const T i) { return data = sclip<bits>(data << i); }
|
|
||||||
inline T operator>>=(const T i) { return data = sclip<bits>(data >> i); }
|
|
||||||
inline T operator +=(const T i) { return data = sclip<bits>(data + i); }
|
|
||||||
inline T operator -=(const T i) { return data = sclip<bits>(data - i); }
|
|
||||||
inline T operator *=(const T i) { return data = sclip<bits>(data * i); }
|
|
||||||
inline T operator /=(const T i) { return data = sclip<bits>(data / i); }
|
|
||||||
inline T operator %=(const T i) { return data = sclip<bits>(data % i); }
|
|
||||||
|
|
||||||
inline int_t() : data(0) {}
|
|
||||||
inline int_t(const T i) : data(sclip<bits>(i)) {}
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
#endif
|
|
|
@ -1,235 +0,0 @@
|
||||||
#ifndef NALL_VECTOR_HPP
|
|
||||||
#define NALL_VECTOR_HPP
|
|
||||||
|
|
||||||
#include <initializer_list>
|
|
||||||
#include <new>
|
|
||||||
#include <nall/algorithm.hpp>
|
|
||||||
#include <nall/bit.hpp>
|
|
||||||
#include <nall/concept.hpp>
|
|
||||||
#include <nall/traits.hpp>
|
|
||||||
#include <nall/utility.hpp>
|
|
||||||
|
|
||||||
namespace nall {
|
|
||||||
//linear_vector
|
|
||||||
//memory: O(capacity * 2)
|
|
||||||
//
|
|
||||||
//linear_vector uses placement new + manual destructor calls to create a
|
|
||||||
//contiguous block of memory for all objects. accessing individual elements
|
|
||||||
//is fast, though resizing the array incurs significant overhead.
|
|
||||||
//reserve() overhead is reduced from quadratic time to amortized constant time
|
|
||||||
//by resizing twice as much as requested.
|
|
||||||
//
|
|
||||||
//if objects hold memory address references to themselves (introspection), a
|
|
||||||
//valid copy constructor will be needed to keep pointers valid.
|
|
||||||
|
|
||||||
template<typename T> class linear_vector {
|
|
||||||
protected:
|
|
||||||
T *pool;
|
|
||||||
unsigned poolsize, objectsize;
|
|
||||||
|
|
||||||
public:
|
|
||||||
unsigned size() const { return objectsize; }
|
|
||||||
unsigned capacity() const { return poolsize; }
|
|
||||||
|
|
||||||
void reset() {
|
|
||||||
if(pool) {
|
|
||||||
for(unsigned i = 0; i < objectsize; i++) pool[i].~T();
|
|
||||||
free(pool);
|
|
||||||
}
|
|
||||||
pool = 0;
|
|
||||||
poolsize = 0;
|
|
||||||
objectsize = 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
void reserve(unsigned newsize) {
|
|
||||||
newsize = bit::round(newsize); //round to nearest power of two (for amortized growth)
|
|
||||||
|
|
||||||
T *poolcopy = (T*)malloc(newsize * sizeof(T));
|
|
||||||
for(unsigned i = 0; i < min(objectsize, newsize); i++) new(poolcopy + i) T(pool[i]);
|
|
||||||
for(unsigned i = 0; i < objectsize; i++) pool[i].~T();
|
|
||||||
free(pool);
|
|
||||||
pool = poolcopy;
|
|
||||||
poolsize = newsize;
|
|
||||||
objectsize = min(objectsize, newsize);
|
|
||||||
}
|
|
||||||
|
|
||||||
void resize(unsigned newsize) {
|
|
||||||
if(newsize > poolsize) reserve(newsize);
|
|
||||||
|
|
||||||
if(newsize < objectsize) {
|
|
||||||
//vector is shrinking; destroy excess objects
|
|
||||||
for(unsigned i = newsize; i < objectsize; i++) pool[i].~T();
|
|
||||||
} else if(newsize > objectsize) {
|
|
||||||
//vector is expanding; allocate new objects
|
|
||||||
for(unsigned i = objectsize; i < newsize; i++) new(pool + i) T;
|
|
||||||
}
|
|
||||||
|
|
||||||
objectsize = newsize;
|
|
||||||
}
|
|
||||||
|
|
||||||
void add(const T data) {
|
|
||||||
if(objectsize + 1 > poolsize) reserve(objectsize + 1);
|
|
||||||
new(pool + objectsize++) T(data);
|
|
||||||
}
|
|
||||||
|
|
||||||
inline T& operator[](unsigned index) {
|
|
||||||
if(index >= objectsize) resize(index + 1);
|
|
||||||
return pool[index];
|
|
||||||
}
|
|
||||||
|
|
||||||
inline const T& operator[](unsigned index) const {
|
|
||||||
if(index >= objectsize) throw "vector[] out of bounds";
|
|
||||||
return pool[index];
|
|
||||||
}
|
|
||||||
|
|
||||||
//copy
|
|
||||||
inline linear_vector<T>& operator=(const linear_vector<T> &source) {
|
|
||||||
reset();
|
|
||||||
reserve(source.capacity());
|
|
||||||
for(unsigned i = 0; i < source.size(); i++) add(source[i]);
|
|
||||||
return *this;
|
|
||||||
}
|
|
||||||
|
|
||||||
linear_vector(const linear_vector<T> &source) {
|
|
||||||
operator=(source);
|
|
||||||
}
|
|
||||||
|
|
||||||
//move
|
|
||||||
inline linear_vector<T>& operator=(linear_vector<T> &&source) {
|
|
||||||
reset();
|
|
||||||
pool = source.pool;
|
|
||||||
poolsize = source.poolsize;
|
|
||||||
objectsize = source.objectsize;
|
|
||||||
source.pool = 0;
|
|
||||||
return *this;
|
|
||||||
}
|
|
||||||
|
|
||||||
linear_vector(linear_vector<T> &&source) {
|
|
||||||
operator=(move(source));
|
|
||||||
}
|
|
||||||
|
|
||||||
//construction
|
|
||||||
linear_vector() : pool(0), poolsize(0), objectsize(0) {
|
|
||||||
}
|
|
||||||
|
|
||||||
linear_vector(std::initializer_list<T> list) : pool(0), poolsize(0), objectsize(0) {
|
|
||||||
for(const T *p = list.begin(); p != list.end(); ++p) add(*p);
|
|
||||||
}
|
|
||||||
|
|
||||||
~linear_vector() {
|
|
||||||
reset();
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
//pointer_vector
|
|
||||||
//memory: O(1)
|
|
||||||
//
|
|
||||||
//pointer_vector keeps an array of pointers to each vector object. this adds
|
|
||||||
//significant overhead to individual accesses, but allows for optimal memory
|
|
||||||
//utilization.
|
|
||||||
//
|
|
||||||
//by guaranteeing that the base memory address of each objects never changes,
|
|
||||||
//this avoids the need for an object to have a valid copy constructor.
|
|
||||||
|
|
||||||
template<typename T> class pointer_vector {
|
|
||||||
protected:
|
|
||||||
T **pool;
|
|
||||||
unsigned poolsize, objectsize;
|
|
||||||
|
|
||||||
public:
|
|
||||||
unsigned size() const { return objectsize; }
|
|
||||||
unsigned capacity() const { return poolsize; }
|
|
||||||
|
|
||||||
void reset() {
|
|
||||||
if(pool) {
|
|
||||||
for(unsigned i = 0; i < objectsize; i++) { if(pool[i]) delete pool[i]; }
|
|
||||||
free(pool);
|
|
||||||
}
|
|
||||||
pool = 0;
|
|
||||||
poolsize = 0;
|
|
||||||
objectsize = 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
void reserve(unsigned newsize) {
|
|
||||||
newsize = bit::round(newsize); //round to nearest power of two (for amortized growth)
|
|
||||||
|
|
||||||
for(unsigned i = newsize; i < objectsize; i++) {
|
|
||||||
if(pool[i]) { delete pool[i]; pool[i] = 0; }
|
|
||||||
}
|
|
||||||
|
|
||||||
pool = (T**)realloc(pool, newsize * sizeof(T*));
|
|
||||||
for(unsigned i = poolsize; i < newsize; i++) pool[i] = 0;
|
|
||||||
poolsize = newsize;
|
|
||||||
objectsize = min(objectsize, newsize);
|
|
||||||
}
|
|
||||||
|
|
||||||
void resize(unsigned newsize) {
|
|
||||||
if(newsize > poolsize) reserve(newsize);
|
|
||||||
|
|
||||||
for(unsigned i = newsize; i < objectsize; i++) {
|
|
||||||
if(pool[i]) { delete pool[i]; pool[i] = 0; }
|
|
||||||
}
|
|
||||||
|
|
||||||
objectsize = newsize;
|
|
||||||
}
|
|
||||||
|
|
||||||
void add(const T data) {
|
|
||||||
if(objectsize + 1 > poolsize) reserve(objectsize + 1);
|
|
||||||
pool[objectsize++] = new T(data);
|
|
||||||
}
|
|
||||||
|
|
||||||
inline T& operator[](unsigned index) {
|
|
||||||
if(index >= objectsize) resize(index + 1);
|
|
||||||
if(!pool[index]) pool[index] = new T;
|
|
||||||
return *pool[index];
|
|
||||||
}
|
|
||||||
|
|
||||||
inline const T& operator[](unsigned index) const {
|
|
||||||
if(index >= objectsize || !pool[index]) throw "vector[] out of bounds";
|
|
||||||
return *pool[index];
|
|
||||||
}
|
|
||||||
|
|
||||||
//copy
|
|
||||||
inline pointer_vector<T>& operator=(const pointer_vector<T> &source) {
|
|
||||||
reset();
|
|
||||||
reserve(source.capacity());
|
|
||||||
for(unsigned i = 0; i < source.size(); i++) add(source[i]);
|
|
||||||
return *this;
|
|
||||||
}
|
|
||||||
|
|
||||||
pointer_vector(const pointer_vector<T> &source) {
|
|
||||||
operator=(source);
|
|
||||||
}
|
|
||||||
|
|
||||||
//move
|
|
||||||
inline pointer_vector<T>& operator=(pointer_vector<T> &&source) {
|
|
||||||
reset();
|
|
||||||
pool = source.pool;
|
|
||||||
poolsize = source.poolsize;
|
|
||||||
objectsize = source.objectsize;
|
|
||||||
source.pool = 0;
|
|
||||||
return *this;
|
|
||||||
}
|
|
||||||
|
|
||||||
pointer_vector(pointer_vector<T> &&source) {
|
|
||||||
operator=(move(source));
|
|
||||||
}
|
|
||||||
|
|
||||||
//construction
|
|
||||||
pointer_vector() : pool(0), poolsize(0), objectsize(0) {
|
|
||||||
}
|
|
||||||
|
|
||||||
pointer_vector(std::initializer_list<T> list) : pool(0), poolsize(0), objectsize(0) {
|
|
||||||
for(const T *p = list.begin(); p != list.end(); ++p) add(*p);
|
|
||||||
}
|
|
||||||
|
|
||||||
~pointer_vector() {
|
|
||||||
reset();
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
template<typename T> struct has_size<linear_vector<T>> { enum { value = true }; };
|
|
||||||
template<typename T> struct has_size<pointer_vector<T>> { enum { value = true }; };
|
|
||||||
}
|
|
||||||
|
|
||||||
#endif
|
|
|
@ -1,396 +0,0 @@
|
||||||
#include "snes_ntsc/snes_ntsc.h"
|
|
||||||
#include "snes_ntsc/snes_ntsc.c"
|
|
||||||
|
|
||||||
#include "ntsc.moc.hpp"
|
|
||||||
#include "ntsc.moc"
|
|
||||||
|
|
||||||
void NTSCFilter::bind(configuration &config) {
|
|
||||||
config.attach(hue = 0.0, "snesfilter.ntsc.hue");
|
|
||||||
config.attach(saturation = 0.0, "snesfilter.ntsc.saturation");
|
|
||||||
config.attach(contrast = 0.0, "snesfilter.ntsc.contrast");
|
|
||||||
config.attach(brightness = 0.0, "snesfilter.ntsc.brightness");
|
|
||||||
config.attach(sharpness = 0.0, "snesfilter.ntsc.sharpness");
|
|
||||||
config.attach(gamma = 0.0, "snesfilter.ntsc.gamma");
|
|
||||||
config.attach(resolution = 0.0, "snesfilter.ntsc.resolution");
|
|
||||||
config.attach(artifacts = 0.0, "snesfilter.ntsc.artifacts");
|
|
||||||
config.attach(fringing = 0.0, "snesfilter.ntsc.fringing");
|
|
||||||
config.attach(bleed = 0.0, "snesfilter.ntsc.bleed");
|
|
||||||
config.attach(mergeFields = true, "snesfilter.ntsc.mergeFields");
|
|
||||||
}
|
|
||||||
|
|
||||||
void NTSCFilter::size(unsigned &outwidth, unsigned &outheight, unsigned width, unsigned height) {
|
|
||||||
outwidth = SNES_NTSC_OUT_WIDTH(256);
|
|
||||||
outheight = height;
|
|
||||||
}
|
|
||||||
|
|
||||||
void NTSCFilter::render(
|
|
||||||
uint32_t *output, unsigned outpitch, const uint16_t *input, unsigned pitch,
|
|
||||||
const unsigned *line, unsigned width, unsigned height
|
|
||||||
) {
|
|
||||||
if(!ntsc) return;
|
|
||||||
|
|
||||||
width = SNES_NTSC_OUT_WIDTH(256);
|
|
||||||
burst ^= burst_toggle;
|
|
||||||
|
|
||||||
pitch >>= 1;
|
|
||||||
outpitch >>= 2;
|
|
||||||
|
|
||||||
unsigned line_burst = burst;
|
|
||||||
for(unsigned y = 0; y < height;) {
|
|
||||||
const uint16_t *in = input + y * pitch;
|
|
||||||
uint32_t *out = output + y * outpitch;
|
|
||||||
|
|
||||||
//render as many lines in one snes_ntsc_blit as possible:
|
|
||||||
//do this by determining for how many lines the width stays the same
|
|
||||||
unsigned rheight = 1;
|
|
||||||
unsigned rwidth = line[y];
|
|
||||||
while(y + rheight < height && rwidth == line[y + rheight]) rheight++;
|
|
||||||
|
|
||||||
if(rwidth == 256) {
|
|
||||||
snes_ntsc_blit (ntsc, in, pitch, line_burst, rwidth, rheight, out, outpitch << 2);
|
|
||||||
} else {
|
|
||||||
snes_ntsc_blit_hires(ntsc, in, pitch, line_burst, rwidth, rheight, out, outpitch << 2);
|
|
||||||
}
|
|
||||||
|
|
||||||
line_burst = (line_burst + rheight) % 3;
|
|
||||||
y += rheight;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
QWidget* NTSCFilter::settings() {
|
|
||||||
if(!widget) {
|
|
||||||
widget = new QWidget;
|
|
||||||
widget->setWindowTitle("NTSC Filter Configuration");
|
|
||||||
|
|
||||||
layout = new QVBoxLayout;
|
|
||||||
layout->setAlignment(Qt::AlignTop);
|
|
||||||
widget->setLayout(layout);
|
|
||||||
|
|
||||||
gridLayout = new QGridLayout;
|
|
||||||
layout->addLayout(gridLayout);
|
|
||||||
|
|
||||||
basicSettings = new QLabel("<b>Basic settings:</b>");
|
|
||||||
gridLayout->addWidget(basicSettings, 0, 0, 1, 3);
|
|
||||||
|
|
||||||
hueLabel = new QLabel("Hue:");
|
|
||||||
gridLayout->addWidget(hueLabel, 1, 0);
|
|
||||||
|
|
||||||
hueValue = new QLabel;
|
|
||||||
hueValue->setMinimumWidth(hueValue->fontMetrics().width("-100.0"));
|
|
||||||
hueValue->setAlignment(Qt::AlignHCenter);
|
|
||||||
gridLayout->addWidget(hueValue, 1, 1);
|
|
||||||
|
|
||||||
hueSlider = new QSlider(Qt::Horizontal);
|
|
||||||
hueSlider->setMinimum(-100);
|
|
||||||
hueSlider->setMaximum(+100);
|
|
||||||
gridLayout->addWidget(hueSlider, 1, 2);
|
|
||||||
|
|
||||||
saturationLabel = new QLabel("Saturation:");
|
|
||||||
gridLayout->addWidget(saturationLabel, 2, 0);
|
|
||||||
|
|
||||||
saturationValue = new QLabel;
|
|
||||||
saturationValue->setAlignment(Qt::AlignHCenter);
|
|
||||||
gridLayout->addWidget(saturationValue, 2, 1);
|
|
||||||
|
|
||||||
saturationSlider = new QSlider(Qt::Horizontal);
|
|
||||||
saturationSlider->setMinimum(-100);
|
|
||||||
saturationSlider->setMaximum(+100);
|
|
||||||
gridLayout->addWidget(saturationSlider, 2, 2);
|
|
||||||
|
|
||||||
contrastLabel = new QLabel("Contrast:");
|
|
||||||
gridLayout->addWidget(contrastLabel, 3, 0);
|
|
||||||
|
|
||||||
contrastValue = new QLabel;
|
|
||||||
contrastValue->setAlignment(Qt::AlignHCenter);
|
|
||||||
gridLayout->addWidget(contrastValue, 3, 1);
|
|
||||||
|
|
||||||
contrastSlider = new QSlider(Qt::Horizontal);
|
|
||||||
contrastSlider->setMinimum(-100);
|
|
||||||
contrastSlider->setMaximum(+100);
|
|
||||||
gridLayout->addWidget(contrastSlider, 3, 2);
|
|
||||||
|
|
||||||
brightnessLabel = new QLabel("Brightness:");
|
|
||||||
gridLayout->addWidget(brightnessLabel, 4, 0);
|
|
||||||
|
|
||||||
brightnessValue = new QLabel;
|
|
||||||
brightnessValue->setAlignment(Qt::AlignHCenter);
|
|
||||||
gridLayout->addWidget(brightnessValue, 4, 1);
|
|
||||||
|
|
||||||
brightnessSlider = new QSlider(Qt::Horizontal);
|
|
||||||
brightnessSlider->setMinimum(-100);
|
|
||||||
brightnessSlider->setMaximum(+100);
|
|
||||||
gridLayout->addWidget(brightnessSlider, 4, 2);
|
|
||||||
|
|
||||||
sharpnessLabel = new QLabel("Sharpness:");
|
|
||||||
gridLayout->addWidget(sharpnessLabel, 5, 0);
|
|
||||||
|
|
||||||
sharpnessValue = new QLabel;
|
|
||||||
sharpnessValue->setAlignment(Qt::AlignHCenter);
|
|
||||||
gridLayout->addWidget(sharpnessValue, 5, 1);
|
|
||||||
|
|
||||||
sharpnessSlider = new QSlider(Qt::Horizontal);
|
|
||||||
sharpnessSlider->setMinimum(-100);
|
|
||||||
sharpnessSlider->setMaximum(+100);
|
|
||||||
gridLayout->addWidget(sharpnessSlider, 5, 2);
|
|
||||||
|
|
||||||
advancedSettings = new QLabel("<b>Advanced settings:</b>");
|
|
||||||
gridLayout->addWidget(advancedSettings, 6, 0, 1, 3);
|
|
||||||
|
|
||||||
gammaLabel = new QLabel("Gamma:");
|
|
||||||
gridLayout->addWidget(gammaLabel, 7, 0);
|
|
||||||
|
|
||||||
gammaValue = new QLabel;
|
|
||||||
gammaValue->setAlignment(Qt::AlignHCenter);
|
|
||||||
gridLayout->addWidget(gammaValue, 7, 1);
|
|
||||||
|
|
||||||
gammaSlider = new QSlider(Qt::Horizontal);
|
|
||||||
gammaSlider->setMinimum(-100);
|
|
||||||
gammaSlider->setMaximum(+100);
|
|
||||||
gridLayout->addWidget(gammaSlider, 7, 2);
|
|
||||||
|
|
||||||
resolutionLabel = new QLabel("Resolution:");
|
|
||||||
gridLayout->addWidget(resolutionLabel, 8, 0);
|
|
||||||
|
|
||||||
resolutionValue = new QLabel;
|
|
||||||
resolutionValue->setAlignment(Qt::AlignHCenter);
|
|
||||||
gridLayout->addWidget(resolutionValue, 8, 1);
|
|
||||||
|
|
||||||
resolutionSlider = new QSlider(Qt::Horizontal);
|
|
||||||
resolutionSlider->setMinimum(-100);
|
|
||||||
resolutionSlider->setMaximum(+100);
|
|
||||||
gridLayout->addWidget(resolutionSlider, 8, 2);
|
|
||||||
|
|
||||||
artifactsLabel = new QLabel("Artifacts:");
|
|
||||||
gridLayout->addWidget(artifactsLabel, 9, 0);
|
|
||||||
|
|
||||||
artifactsValue = new QLabel;
|
|
||||||
artifactsValue->setAlignment(Qt::AlignHCenter);
|
|
||||||
gridLayout->addWidget(artifactsValue, 9, 1);
|
|
||||||
|
|
||||||
artifactsSlider = new QSlider(Qt::Horizontal);
|
|
||||||
artifactsSlider->setMinimum(-100);
|
|
||||||
artifactsSlider->setMaximum(+100);
|
|
||||||
gridLayout->addWidget(artifactsSlider, 9, 2);
|
|
||||||
|
|
||||||
fringingLabel = new QLabel("Fringing:");
|
|
||||||
gridLayout->addWidget(fringingLabel, 10, 0);
|
|
||||||
|
|
||||||
fringingValue = new QLabel;
|
|
||||||
fringingValue->setAlignment(Qt::AlignHCenter);
|
|
||||||
gridLayout->addWidget(fringingValue, 10, 1);
|
|
||||||
|
|
||||||
fringingSlider = new QSlider(Qt::Horizontal);
|
|
||||||
fringingSlider->setMinimum(-100);
|
|
||||||
fringingSlider->setMaximum(+100);
|
|
||||||
gridLayout->addWidget(fringingSlider, 10, 2);
|
|
||||||
|
|
||||||
bleedLabel = new QLabel("Color bleed:");
|
|
||||||
gridLayout->addWidget(bleedLabel, 11, 0);
|
|
||||||
|
|
||||||
bleedValue = new QLabel;
|
|
||||||
bleedValue->setAlignment(Qt::AlignHCenter);
|
|
||||||
gridLayout->addWidget(bleedValue, 11, 1);
|
|
||||||
|
|
||||||
bleedSlider = new QSlider(Qt::Horizontal);
|
|
||||||
bleedSlider->setMinimum(-100);
|
|
||||||
bleedSlider->setMaximum(+100);
|
|
||||||
gridLayout->addWidget(bleedSlider, 11, 2);
|
|
||||||
|
|
||||||
mergeFieldsBox = new QCheckBox("Merge even and odd fields to reduce flicker");
|
|
||||||
gridLayout->addWidget(mergeFieldsBox, 12, 0, 1, 3);
|
|
||||||
|
|
||||||
presets = new QLabel("<b>Presets:</b>");
|
|
||||||
gridLayout->addWidget(presets, 13, 0, 1, 3);
|
|
||||||
|
|
||||||
controlLayout = new QHBoxLayout;
|
|
||||||
layout->addLayout(controlLayout);
|
|
||||||
|
|
||||||
rfPreset = new QPushButton("RF");
|
|
||||||
controlLayout->addWidget(rfPreset);
|
|
||||||
|
|
||||||
compositePreset = new QPushButton("Composite");
|
|
||||||
controlLayout->addWidget(compositePreset);
|
|
||||||
|
|
||||||
svideoPreset = new QPushButton("S-Video");
|
|
||||||
controlLayout->addWidget(svideoPreset);
|
|
||||||
|
|
||||||
rgbPreset = new QPushButton("RGB");
|
|
||||||
controlLayout->addWidget(rgbPreset);
|
|
||||||
|
|
||||||
monoPreset = new QPushButton("Monochrome");
|
|
||||||
controlLayout->addWidget(monoPreset);
|
|
||||||
|
|
||||||
spacer = new QWidget;
|
|
||||||
spacer->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Fixed);
|
|
||||||
spacer->setMinimumWidth(50);
|
|
||||||
controlLayout->addWidget(spacer);
|
|
||||||
|
|
||||||
ok = new QPushButton("Ok");
|
|
||||||
controlLayout->addWidget(ok);
|
|
||||||
|
|
||||||
blockSignals = true;
|
|
||||||
loadSettingsFromConfig();
|
|
||||||
syncUiToSettings();
|
|
||||||
initialize();
|
|
||||||
|
|
||||||
connect(hueSlider, SIGNAL(valueChanged(int)), this, SLOT(syncSettingsToUi()));
|
|
||||||
connect(saturationSlider, SIGNAL(valueChanged(int)), this, SLOT(syncSettingsToUi()));
|
|
||||||
connect(contrastSlider, SIGNAL(valueChanged(int)), this, SLOT(syncSettingsToUi()));
|
|
||||||
connect(brightnessSlider, SIGNAL(valueChanged(int)), this, SLOT(syncSettingsToUi()));
|
|
||||||
connect(sharpnessSlider, SIGNAL(valueChanged(int)), this, SLOT(syncSettingsToUi()));
|
|
||||||
connect(gammaSlider, SIGNAL(valueChanged(int)), this, SLOT(syncSettingsToUi()));
|
|
||||||
connect(resolutionSlider, SIGNAL(valueChanged(int)), this, SLOT(syncSettingsToUi()));
|
|
||||||
connect(artifactsSlider, SIGNAL(valueChanged(int)), this, SLOT(syncSettingsToUi()));
|
|
||||||
connect(fringingSlider, SIGNAL(valueChanged(int)), this, SLOT(syncSettingsToUi()));
|
|
||||||
connect(bleedSlider, SIGNAL(valueChanged(int)), this, SLOT(syncSettingsToUi()));
|
|
||||||
connect(mergeFieldsBox, SIGNAL(stateChanged(int)), this, SLOT(syncSettingsToUi()));
|
|
||||||
connect(rfPreset, SIGNAL(released()), this, SLOT(setRfPreset()));
|
|
||||||
connect(compositePreset, SIGNAL(released()), this, SLOT(setCompositePreset()));
|
|
||||||
connect(svideoPreset, SIGNAL(released()), this, SLOT(setSvideoPreset()));
|
|
||||||
connect(rgbPreset, SIGNAL(released()), this, SLOT(setRgbPreset()));
|
|
||||||
connect(monoPreset, SIGNAL(released()), this, SLOT(setMonoPreset()));
|
|
||||||
connect(ok, SIGNAL(released()), widget, SLOT(hide()));
|
|
||||||
|
|
||||||
blockSignals = false;
|
|
||||||
}
|
|
||||||
|
|
||||||
return widget;
|
|
||||||
}
|
|
||||||
|
|
||||||
void NTSCFilter::initialize() {
|
|
||||||
burst = 0;
|
|
||||||
burst_toggle = (setup.merge_fields ? 0 : 1); //don't toggle burst when fields are merged
|
|
||||||
snes_ntsc_init(ntsc, &setup);
|
|
||||||
}
|
|
||||||
|
|
||||||
void NTSCFilter::loadSettingsFromConfig() {
|
|
||||||
setup.hue = hue;
|
|
||||||
setup.saturation = saturation;
|
|
||||||
setup.contrast = contrast;
|
|
||||||
setup.brightness = brightness;
|
|
||||||
setup.sharpness = sharpness;
|
|
||||||
|
|
||||||
setup.gamma = gamma;
|
|
||||||
setup.resolution = resolution;
|
|
||||||
setup.artifacts = artifacts;
|
|
||||||
setup.fringing = fringing;
|
|
||||||
setup.bleed = bleed;
|
|
||||||
|
|
||||||
setup.merge_fields = mergeFields;
|
|
||||||
}
|
|
||||||
|
|
||||||
void NTSCFilter::syncUiToSettings() {
|
|
||||||
blockSignals = true;
|
|
||||||
|
|
||||||
hue = setup.hue;
|
|
||||||
saturation = setup.saturation;
|
|
||||||
contrast = setup.contrast;
|
|
||||||
brightness = setup.brightness;
|
|
||||||
sharpness = setup.sharpness;
|
|
||||||
|
|
||||||
gamma = setup.gamma;
|
|
||||||
resolution = setup.resolution;
|
|
||||||
artifacts = setup.artifacts;
|
|
||||||
fringing = setup.fringing;
|
|
||||||
bleed = setup.bleed;
|
|
||||||
|
|
||||||
mergeFields = setup.merge_fields;
|
|
||||||
|
|
||||||
hueValue->setText(string() << hue);
|
|
||||||
hueSlider->setSliderPosition(hue * 100);
|
|
||||||
|
|
||||||
saturationValue->setText(string() << saturation);
|
|
||||||
saturationSlider->setSliderPosition(saturation * 100);
|
|
||||||
|
|
||||||
contrastValue->setText(string() << contrast);
|
|
||||||
contrastSlider->setSliderPosition(contrast * 100);
|
|
||||||
|
|
||||||
brightnessValue->setText(string() << brightness);
|
|
||||||
brightnessSlider->setSliderPosition(brightness * 100);
|
|
||||||
|
|
||||||
sharpnessValue->setText(string() << sharpness);
|
|
||||||
sharpnessSlider->setSliderPosition(sharpness * 100);
|
|
||||||
|
|
||||||
gammaValue->setText(string() << gamma);
|
|
||||||
gammaSlider->setSliderPosition(gamma * 100);
|
|
||||||
|
|
||||||
resolutionValue->setText(string() << resolution);
|
|
||||||
resolutionSlider->setSliderPosition(resolution * 100);
|
|
||||||
|
|
||||||
artifactsValue->setText(string() << artifacts);
|
|
||||||
artifactsSlider->setSliderPosition(artifacts * 100);
|
|
||||||
|
|
||||||
fringingValue->setText(string() << fringing);
|
|
||||||
fringingSlider->setSliderPosition(fringing * 100);
|
|
||||||
|
|
||||||
bleedValue->setText(string() << bleed);
|
|
||||||
bleedSlider->setSliderPosition(bleed * 100);
|
|
||||||
|
|
||||||
mergeFieldsBox->setChecked(mergeFields);
|
|
||||||
|
|
||||||
blockSignals = false;
|
|
||||||
}
|
|
||||||
|
|
||||||
void NTSCFilter::syncSettingsToUi() {
|
|
||||||
if(blockSignals) return;
|
|
||||||
|
|
||||||
hue = hueSlider->sliderPosition() / 100.0;
|
|
||||||
saturation = saturationSlider->sliderPosition() / 100.0;
|
|
||||||
contrast = contrastSlider->sliderPosition() / 100.0;
|
|
||||||
brightness = brightnessSlider->sliderPosition() / 100.0;
|
|
||||||
sharpness = sharpnessSlider->sliderPosition() / 100.0;
|
|
||||||
|
|
||||||
gamma = gammaSlider->sliderPosition() / 100.0;
|
|
||||||
resolution = resolutionSlider->sliderPosition() / 100.0;
|
|
||||||
artifacts = artifactsSlider->sliderPosition() / 100.0;
|
|
||||||
fringing = fringingSlider->sliderPosition() / 100.0;
|
|
||||||
bleed = bleedSlider->sliderPosition() / 100.0;
|
|
||||||
|
|
||||||
mergeFields = mergeFieldsBox->isChecked();
|
|
||||||
|
|
||||||
loadSettingsFromConfig();
|
|
||||||
syncUiToSettings();
|
|
||||||
initialize();
|
|
||||||
}
|
|
||||||
|
|
||||||
void NTSCFilter::setRfPreset() {
|
|
||||||
static snes_ntsc_setup_t defaults;
|
|
||||||
setup = defaults;
|
|
||||||
syncUiToSettings();
|
|
||||||
initialize();
|
|
||||||
}
|
|
||||||
|
|
||||||
void NTSCFilter::setCompositePreset() {
|
|
||||||
setup = snes_ntsc_composite;
|
|
||||||
syncUiToSettings();
|
|
||||||
initialize();
|
|
||||||
}
|
|
||||||
|
|
||||||
void NTSCFilter::setSvideoPreset() {
|
|
||||||
setup = snes_ntsc_svideo;
|
|
||||||
syncUiToSettings();
|
|
||||||
initialize();
|
|
||||||
}
|
|
||||||
|
|
||||||
void NTSCFilter::setRgbPreset() {
|
|
||||||
setup = snes_ntsc_rgb;
|
|
||||||
syncUiToSettings();
|
|
||||||
initialize();
|
|
||||||
}
|
|
||||||
|
|
||||||
void NTSCFilter::setMonoPreset() {
|
|
||||||
setup = snes_ntsc_monochrome;
|
|
||||||
syncUiToSettings();
|
|
||||||
initialize();
|
|
||||||
}
|
|
||||||
|
|
||||||
NTSCFilter::NTSCFilter() : widget(0) {
|
|
||||||
ntsc = (snes_ntsc_t*)malloc(sizeof *ntsc);
|
|
||||||
static snes_ntsc_setup_t defaults;
|
|
||||||
setup = defaults;
|
|
||||||
initialize();
|
|
||||||
}
|
|
||||||
|
|
||||||
NTSCFilter::~NTSCFilter() {
|
|
||||||
if(ntsc) free(ntsc);
|
|
||||||
}
|
|
|
@ -1,91 +0,0 @@
|
||||||
class NTSCFilter : public QObject {
|
|
||||||
Q_OBJECT
|
|
||||||
|
|
||||||
public:
|
|
||||||
void bind(configuration&);
|
|
||||||
void size(unsigned&, unsigned&, unsigned, unsigned);
|
|
||||||
void render(uint32_t*, unsigned, const uint16_t*, unsigned, const unsigned*, unsigned, unsigned);
|
|
||||||
QWidget* settings();
|
|
||||||
|
|
||||||
NTSCFilter();
|
|
||||||
~NTSCFilter();
|
|
||||||
|
|
||||||
private:
|
|
||||||
void initialize();
|
|
||||||
void loadSettingsFromConfig();
|
|
||||||
void syncUiToSettings();
|
|
||||||
|
|
||||||
private slots:
|
|
||||||
void syncSettingsToUi();
|
|
||||||
void setRfPreset();
|
|
||||||
void setCompositePreset();
|
|
||||||
void setSvideoPreset();
|
|
||||||
void setRgbPreset();
|
|
||||||
void setMonoPreset();
|
|
||||||
|
|
||||||
private:
|
|
||||||
QWidget *widget;
|
|
||||||
QVBoxLayout *layout;
|
|
||||||
QGridLayout *gridLayout;
|
|
||||||
QLabel *basicSettings;
|
|
||||||
QLabel *hueLabel;
|
|
||||||
QLabel *hueValue;
|
|
||||||
QSlider *hueSlider;
|
|
||||||
QLabel *saturationLabel;
|
|
||||||
QLabel *saturationValue;
|
|
||||||
QSlider *saturationSlider;
|
|
||||||
QLabel *contrastLabel;
|
|
||||||
QLabel *contrastValue;
|
|
||||||
QSlider *contrastSlider;
|
|
||||||
QLabel *brightnessLabel;
|
|
||||||
QLabel *brightnessValue;
|
|
||||||
QSlider *brightnessSlider;
|
|
||||||
QLabel *sharpnessLabel;
|
|
||||||
QLabel *sharpnessValue;
|
|
||||||
QSlider *sharpnessSlider;
|
|
||||||
QLabel *advancedSettings;
|
|
||||||
QLabel *gammaLabel;
|
|
||||||
QLabel *gammaValue;
|
|
||||||
QSlider *gammaSlider;
|
|
||||||
QLabel *resolutionLabel;
|
|
||||||
QLabel *resolutionValue;
|
|
||||||
QSlider *resolutionSlider;
|
|
||||||
QLabel *artifactsLabel;
|
|
||||||
QLabel *artifactsValue;
|
|
||||||
QSlider *artifactsSlider;
|
|
||||||
QLabel *fringingLabel;
|
|
||||||
QLabel *fringingValue;
|
|
||||||
QSlider *fringingSlider;
|
|
||||||
QLabel *bleedLabel;
|
|
||||||
QLabel *bleedValue;
|
|
||||||
QSlider *bleedSlider;
|
|
||||||
QCheckBox *mergeFieldsBox;
|
|
||||||
QLabel *presets;
|
|
||||||
QHBoxLayout *controlLayout;
|
|
||||||
QPushButton *rfPreset;
|
|
||||||
QPushButton *compositePreset;
|
|
||||||
QPushButton *svideoPreset;
|
|
||||||
QPushButton *rgbPreset;
|
|
||||||
QPushButton *monoPreset;
|
|
||||||
QWidget *spacer;
|
|
||||||
QPushButton *ok;
|
|
||||||
|
|
||||||
bool blockSignals;
|
|
||||||
|
|
||||||
struct snes_ntsc_t *ntsc;
|
|
||||||
snes_ntsc_setup_t setup;
|
|
||||||
int burst, burst_toggle;
|
|
||||||
|
|
||||||
//settings
|
|
||||||
double hue;
|
|
||||||
double saturation;
|
|
||||||
double contrast;
|
|
||||||
double brightness;
|
|
||||||
double sharpness;
|
|
||||||
double gamma;
|
|
||||||
double resolution;
|
|
||||||
double artifacts;
|
|
||||||
double fringing;
|
|
||||||
double bleed;
|
|
||||||
bool mergeFields;
|
|
||||||
} filter_ntsc;
|
|
|
@ -1,251 +0,0 @@
|
||||||
/* snes_ntsc 0.2.2. http://www.slack.net/~ant/ */
|
|
||||||
|
|
||||||
#include "snes_ntsc.h"
|
|
||||||
|
|
||||||
/* Copyright (C) 2006-2007 Shay Green. This module is free software; you
|
|
||||||
can redistribute it and/or modify it under the terms of the GNU Lesser
|
|
||||||
General Public License as published by the Free Software Foundation; either
|
|
||||||
version 2.1 of the License, or (at your option) any later version. This
|
|
||||||
module is distributed in the hope that it will be useful, but WITHOUT ANY
|
|
||||||
WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
|
|
||||||
FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more
|
|
||||||
details. You should have received a copy of the GNU Lesser General Public
|
|
||||||
License along with this module; if not, write to the Free Software Foundation,
|
|
||||||
Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */
|
|
||||||
|
|
||||||
snes_ntsc_setup_t const snes_ntsc_monochrome = { 0,-1, 0, 0,.2, 0,.2,-.2,-.2,-1, 1, 0, 0 };
|
|
||||||
snes_ntsc_setup_t const snes_ntsc_composite = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0 };
|
|
||||||
snes_ntsc_setup_t const snes_ntsc_svideo = { 0, 0, 0, 0,.2, 0,.2, -1, -1, 0, 1, 0, 0 };
|
|
||||||
snes_ntsc_setup_t const snes_ntsc_rgb = { 0, 0, 0, 0,.2, 0,.7, -1, -1,-1, 1, 0, 0 };
|
|
||||||
|
|
||||||
#define alignment_count 3
|
|
||||||
#define burst_count 3
|
|
||||||
#define rescale_in 8
|
|
||||||
#define rescale_out 7
|
|
||||||
|
|
||||||
#define artifacts_mid 1.0f
|
|
||||||
#define fringing_mid 1.0f
|
|
||||||
#define std_decoder_hue 0
|
|
||||||
|
|
||||||
#define rgb_bits 7 /* half normal range to allow for doubled hires pixels */
|
|
||||||
#define gamma_size 32
|
|
||||||
|
|
||||||
#include "snes_ntsc_impl.h"
|
|
||||||
|
|
||||||
/* 3 input pixels -> 8 composite samples */
|
|
||||||
pixel_info_t const snes_ntsc_pixels [alignment_count] = {
|
|
||||||
{ PIXEL_OFFSET( -4, -9 ), { 1, 1, .6667f, 0 } },
|
|
||||||
{ PIXEL_OFFSET( -2, -7 ), { .3333f, 1, 1, .3333f } },
|
|
||||||
{ PIXEL_OFFSET( 0, -5 ), { 0, .6667f, 1, 1 } },
|
|
||||||
};
|
|
||||||
|
|
||||||
static void merge_kernel_fields( snes_ntsc_rgb_t* io )
|
|
||||||
{
|
|
||||||
int n;
|
|
||||||
for ( n = burst_size; n; --n )
|
|
||||||
{
|
|
||||||
snes_ntsc_rgb_t p0 = io [burst_size * 0] + rgb_bias;
|
|
||||||
snes_ntsc_rgb_t p1 = io [burst_size * 1] + rgb_bias;
|
|
||||||
snes_ntsc_rgb_t p2 = io [burst_size * 2] + rgb_bias;
|
|
||||||
/* merge colors without losing precision */
|
|
||||||
io [burst_size * 0] =
|
|
||||||
((p0 + p1 - ((p0 ^ p1) & snes_ntsc_rgb_builder)) >> 1) - rgb_bias;
|
|
||||||
io [burst_size * 1] =
|
|
||||||
((p1 + p2 - ((p1 ^ p2) & snes_ntsc_rgb_builder)) >> 1) - rgb_bias;
|
|
||||||
io [burst_size * 2] =
|
|
||||||
((p2 + p0 - ((p2 ^ p0) & snes_ntsc_rgb_builder)) >> 1) - rgb_bias;
|
|
||||||
++io;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
static void correct_errors( snes_ntsc_rgb_t color, snes_ntsc_rgb_t* out )
|
|
||||||
{
|
|
||||||
int n;
|
|
||||||
for ( n = burst_count; n; --n )
|
|
||||||
{
|
|
||||||
unsigned i;
|
|
||||||
for ( i = 0; i < rgb_kernel_size / 2; i++ )
|
|
||||||
{
|
|
||||||
snes_ntsc_rgb_t error = color -
|
|
||||||
out [i ] - out [(i+12)%14+14] - out [(i+10)%14+28] -
|
|
||||||
out [i + 7] - out [i + 5 +14] - out [i + 3 +28];
|
|
||||||
DISTRIBUTE_ERROR( i+3+28, i+5+14, i+7 );
|
|
||||||
}
|
|
||||||
out += alignment_count * rgb_kernel_size;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void snes_ntsc_init( snes_ntsc_t* ntsc, snes_ntsc_setup_t const* setup )
|
|
||||||
{
|
|
||||||
int merge_fields;
|
|
||||||
int entry;
|
|
||||||
init_t impl;
|
|
||||||
if ( !setup )
|
|
||||||
setup = &snes_ntsc_composite;
|
|
||||||
init( &impl, setup );
|
|
||||||
|
|
||||||
merge_fields = setup->merge_fields;
|
|
||||||
if ( setup->artifacts <= -1 && setup->fringing <= -1 )
|
|
||||||
merge_fields = 1;
|
|
||||||
|
|
||||||
for ( entry = 0; entry < snes_ntsc_palette_size; entry++ )
|
|
||||||
{
|
|
||||||
/* Reduce number of significant bits of source color. Clearing the
|
|
||||||
low bits of R and B were least notictable. Modifying green was too
|
|
||||||
noticeable. */
|
|
||||||
int ir = entry >> 8 & 0x1E;
|
|
||||||
int ig = entry >> 4 & 0x1F;
|
|
||||||
int ib = entry << 1 & 0x1E;
|
|
||||||
|
|
||||||
#if SNES_NTSC_BSNES_COLORTBL
|
|
||||||
if ( setup->bsnes_colortbl )
|
|
||||||
{
|
|
||||||
int bgr15 = (ib << 10) | (ig << 5) | ir;
|
|
||||||
unsigned long rgb16 = setup->bsnes_colortbl [bgr15];
|
|
||||||
ir = rgb16 >> 11 & 0x1E;
|
|
||||||
ig = rgb16 >> 6 & 0x1F;
|
|
||||||
ib = rgb16 & 0x1E;
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
|
|
||||||
{
|
|
||||||
float rr = impl.to_float [ir];
|
|
||||||
float gg = impl.to_float [ig];
|
|
||||||
float bb = impl.to_float [ib];
|
|
||||||
|
|
||||||
float y, i, q = RGB_TO_YIQ( rr, gg, bb, y, i );
|
|
||||||
|
|
||||||
int r, g, b = YIQ_TO_RGB( y, i, q, impl.to_rgb, int, r, g );
|
|
||||||
snes_ntsc_rgb_t rgb = PACK_RGB( r, g, b );
|
|
||||||
|
|
||||||
snes_ntsc_rgb_t* out = ntsc->table [entry];
|
|
||||||
gen_kernel( &impl, y, i, q, out );
|
|
||||||
if ( merge_fields )
|
|
||||||
merge_kernel_fields( out );
|
|
||||||
correct_errors( rgb, out );
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#ifndef SNES_NTSC_NO_BLITTERS
|
|
||||||
|
|
||||||
void snes_ntsc_blit( snes_ntsc_t const* ntsc, SNES_NTSC_IN_T const* input, long in_row_width,
|
|
||||||
int burst_phase, int in_width, int in_height, void* rgb_out, long out_pitch )
|
|
||||||
{
|
|
||||||
int chunk_count = (in_width - 1) / snes_ntsc_in_chunk;
|
|
||||||
for ( ; in_height; --in_height )
|
|
||||||
{
|
|
||||||
SNES_NTSC_IN_T const* line_in = input;
|
|
||||||
SNES_NTSC_BEGIN_ROW( ntsc, burst_phase,
|
|
||||||
snes_ntsc_black, snes_ntsc_black, SNES_NTSC_ADJ_IN( *line_in ) );
|
|
||||||
snes_ntsc_out_t* restrict line_out = (snes_ntsc_out_t*) rgb_out;
|
|
||||||
int n;
|
|
||||||
++line_in;
|
|
||||||
|
|
||||||
for ( n = chunk_count; n; --n )
|
|
||||||
{
|
|
||||||
/* order of input and output pixels must not be altered */
|
|
||||||
SNES_NTSC_COLOR_IN( 0, SNES_NTSC_ADJ_IN( line_in [0] ) );
|
|
||||||
SNES_NTSC_RGB_OUT( 0, line_out [0], SNES_NTSC_OUT_DEPTH );
|
|
||||||
SNES_NTSC_RGB_OUT( 1, line_out [1], SNES_NTSC_OUT_DEPTH );
|
|
||||||
|
|
||||||
SNES_NTSC_COLOR_IN( 1, SNES_NTSC_ADJ_IN( line_in [1] ) );
|
|
||||||
SNES_NTSC_RGB_OUT( 2, line_out [2], SNES_NTSC_OUT_DEPTH );
|
|
||||||
SNES_NTSC_RGB_OUT( 3, line_out [3], SNES_NTSC_OUT_DEPTH );
|
|
||||||
|
|
||||||
SNES_NTSC_COLOR_IN( 2, SNES_NTSC_ADJ_IN( line_in [2] ) );
|
|
||||||
SNES_NTSC_RGB_OUT( 4, line_out [4], SNES_NTSC_OUT_DEPTH );
|
|
||||||
SNES_NTSC_RGB_OUT( 5, line_out [5], SNES_NTSC_OUT_DEPTH );
|
|
||||||
SNES_NTSC_RGB_OUT( 6, line_out [6], SNES_NTSC_OUT_DEPTH );
|
|
||||||
|
|
||||||
line_in += 3;
|
|
||||||
line_out += 7;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* finish final pixels */
|
|
||||||
SNES_NTSC_COLOR_IN( 0, snes_ntsc_black );
|
|
||||||
SNES_NTSC_RGB_OUT( 0, line_out [0], SNES_NTSC_OUT_DEPTH );
|
|
||||||
SNES_NTSC_RGB_OUT( 1, line_out [1], SNES_NTSC_OUT_DEPTH );
|
|
||||||
|
|
||||||
SNES_NTSC_COLOR_IN( 1, snes_ntsc_black );
|
|
||||||
SNES_NTSC_RGB_OUT( 2, line_out [2], SNES_NTSC_OUT_DEPTH );
|
|
||||||
SNES_NTSC_RGB_OUT( 3, line_out [3], SNES_NTSC_OUT_DEPTH );
|
|
||||||
|
|
||||||
SNES_NTSC_COLOR_IN( 2, snes_ntsc_black );
|
|
||||||
SNES_NTSC_RGB_OUT( 4, line_out [4], SNES_NTSC_OUT_DEPTH );
|
|
||||||
SNES_NTSC_RGB_OUT( 5, line_out [5], SNES_NTSC_OUT_DEPTH );
|
|
||||||
SNES_NTSC_RGB_OUT( 6, line_out [6], SNES_NTSC_OUT_DEPTH );
|
|
||||||
|
|
||||||
burst_phase = (burst_phase + 1) % snes_ntsc_burst_count;
|
|
||||||
input += in_row_width;
|
|
||||||
rgb_out = (char*) rgb_out + out_pitch;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void snes_ntsc_blit_hires( snes_ntsc_t const* ntsc, SNES_NTSC_IN_T const* input, long in_row_width,
|
|
||||||
int burst_phase, int in_width, int in_height, void* rgb_out, long out_pitch )
|
|
||||||
{
|
|
||||||
int chunk_count = (in_width - 2) / (snes_ntsc_in_chunk * 2);
|
|
||||||
for ( ; in_height; --in_height )
|
|
||||||
{
|
|
||||||
SNES_NTSC_IN_T const* line_in = input;
|
|
||||||
SNES_NTSC_HIRES_ROW( ntsc, burst_phase,
|
|
||||||
snes_ntsc_black, snes_ntsc_black, snes_ntsc_black,
|
|
||||||
SNES_NTSC_ADJ_IN( line_in [0] ),
|
|
||||||
SNES_NTSC_ADJ_IN( line_in [1] ) );
|
|
||||||
snes_ntsc_out_t* restrict line_out = (snes_ntsc_out_t*) rgb_out;
|
|
||||||
int n;
|
|
||||||
line_in += 2;
|
|
||||||
|
|
||||||
for ( n = chunk_count; n; --n )
|
|
||||||
{
|
|
||||||
/* twice as many input pixels per chunk */
|
|
||||||
SNES_NTSC_COLOR_IN( 0, SNES_NTSC_ADJ_IN( line_in [0] ) );
|
|
||||||
SNES_NTSC_HIRES_OUT( 0, line_out [0], SNES_NTSC_OUT_DEPTH );
|
|
||||||
|
|
||||||
SNES_NTSC_COLOR_IN( 1, SNES_NTSC_ADJ_IN( line_in [1] ) );
|
|
||||||
SNES_NTSC_HIRES_OUT( 1, line_out [1], SNES_NTSC_OUT_DEPTH );
|
|
||||||
|
|
||||||
SNES_NTSC_COLOR_IN( 2, SNES_NTSC_ADJ_IN( line_in [2] ) );
|
|
||||||
SNES_NTSC_HIRES_OUT( 2, line_out [2], SNES_NTSC_OUT_DEPTH );
|
|
||||||
|
|
||||||
SNES_NTSC_COLOR_IN( 3, SNES_NTSC_ADJ_IN( line_in [3] ) );
|
|
||||||
SNES_NTSC_HIRES_OUT( 3, line_out [3], SNES_NTSC_OUT_DEPTH );
|
|
||||||
|
|
||||||
SNES_NTSC_COLOR_IN( 4, SNES_NTSC_ADJ_IN( line_in [4] ) );
|
|
||||||
SNES_NTSC_HIRES_OUT( 4, line_out [4], SNES_NTSC_OUT_DEPTH );
|
|
||||||
|
|
||||||
SNES_NTSC_COLOR_IN( 5, SNES_NTSC_ADJ_IN( line_in [5] ) );
|
|
||||||
SNES_NTSC_HIRES_OUT( 5, line_out [5], SNES_NTSC_OUT_DEPTH );
|
|
||||||
SNES_NTSC_HIRES_OUT( 6, line_out [6], SNES_NTSC_OUT_DEPTH );
|
|
||||||
|
|
||||||
line_in += 6;
|
|
||||||
line_out += 7;
|
|
||||||
}
|
|
||||||
|
|
||||||
SNES_NTSC_COLOR_IN( 0, snes_ntsc_black );
|
|
||||||
SNES_NTSC_HIRES_OUT( 0, line_out [0], SNES_NTSC_OUT_DEPTH );
|
|
||||||
|
|
||||||
SNES_NTSC_COLOR_IN( 1, snes_ntsc_black );
|
|
||||||
SNES_NTSC_HIRES_OUT( 1, line_out [1], SNES_NTSC_OUT_DEPTH );
|
|
||||||
|
|
||||||
SNES_NTSC_COLOR_IN( 2, snes_ntsc_black );
|
|
||||||
SNES_NTSC_HIRES_OUT( 2, line_out [2], SNES_NTSC_OUT_DEPTH );
|
|
||||||
|
|
||||||
SNES_NTSC_COLOR_IN( 3, snes_ntsc_black );
|
|
||||||
SNES_NTSC_HIRES_OUT( 3, line_out [3], SNES_NTSC_OUT_DEPTH );
|
|
||||||
|
|
||||||
SNES_NTSC_COLOR_IN( 4, snes_ntsc_black );
|
|
||||||
SNES_NTSC_HIRES_OUT( 4, line_out [4], SNES_NTSC_OUT_DEPTH );
|
|
||||||
|
|
||||||
SNES_NTSC_COLOR_IN( 5, snes_ntsc_black );
|
|
||||||
SNES_NTSC_HIRES_OUT( 5, line_out [5], SNES_NTSC_OUT_DEPTH );
|
|
||||||
SNES_NTSC_HIRES_OUT( 6, line_out [6], SNES_NTSC_OUT_DEPTH );
|
|
||||||
|
|
||||||
burst_phase = (burst_phase + 1) % snes_ntsc_burst_count;
|
|
||||||
input += in_row_width;
|
|
||||||
rgb_out = (char*) rgb_out + out_pitch;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#endif
|
|
|
@ -1,228 +0,0 @@
|
||||||
/* SNES NTSC video filter */
|
|
||||||
|
|
||||||
/* snes_ntsc 0.2.2 */
|
|
||||||
#ifndef SNES_NTSC_H
|
|
||||||
#define SNES_NTSC_H
|
|
||||||
|
|
||||||
#include "snes_ntsc_config.h"
|
|
||||||
|
|
||||||
#ifdef __cplusplus
|
|
||||||
extern "C" {
|
|
||||||
#endif
|
|
||||||
|
|
||||||
/* Image parameters, ranging from -1.0 to 1.0. Actual internal values shown
|
|
||||||
in parenthesis and should remain fairly stable in future versions. */
|
|
||||||
typedef struct snes_ntsc_setup_t
|
|
||||||
{
|
|
||||||
/* Basic parameters */
|
|
||||||
double hue; /* -1 = -180 degrees +1 = +180 degrees */
|
|
||||||
double saturation; /* -1 = grayscale (0.0) +1 = oversaturated colors (2.0) */
|
|
||||||
double contrast; /* -1 = dark (0.5) +1 = light (1.5) */
|
|
||||||
double brightness; /* -1 = dark (0.5) +1 = light (1.5) */
|
|
||||||
double sharpness; /* edge contrast enhancement/blurring */
|
|
||||||
|
|
||||||
/* Advanced parameters */
|
|
||||||
double gamma; /* -1 = dark (1.5) +1 = light (0.5) */
|
|
||||||
double resolution; /* image resolution */
|
|
||||||
double artifacts; /* artifacts caused by color changes */
|
|
||||||
double fringing; /* color artifacts caused by brightness changes */
|
|
||||||
double bleed; /* color bleed (color resolution reduction) */
|
|
||||||
int merge_fields; /* if 1, merges even and odd fields together to reduce flicker */
|
|
||||||
float const* decoder_matrix; /* optional RGB decoder matrix, 6 elements */
|
|
||||||
|
|
||||||
unsigned long const* bsnes_colortbl; /* undocumented; set to 0 */
|
|
||||||
} snes_ntsc_setup_t;
|
|
||||||
|
|
||||||
/* Video format presets */
|
|
||||||
extern snes_ntsc_setup_t const snes_ntsc_composite; /* color bleeding + artifacts */
|
|
||||||
extern snes_ntsc_setup_t const snes_ntsc_svideo; /* color bleeding only */
|
|
||||||
extern snes_ntsc_setup_t const snes_ntsc_rgb; /* crisp image */
|
|
||||||
extern snes_ntsc_setup_t const snes_ntsc_monochrome;/* desaturated + artifacts */
|
|
||||||
|
|
||||||
/* Initializes and adjusts parameters. Can be called multiple times on the same
|
|
||||||
snes_ntsc_t object. Can pass NULL for either parameter. */
|
|
||||||
typedef struct snes_ntsc_t snes_ntsc_t;
|
|
||||||
void snes_ntsc_init( snes_ntsc_t* ntsc, snes_ntsc_setup_t const* setup );
|
|
||||||
|
|
||||||
/* Filters one or more rows of pixels. Input pixel format is set by SNES_NTSC_IN_FORMAT
|
|
||||||
and output RGB depth is set by SNES_NTSC_OUT_DEPTH. Both default to 16-bit RGB.
|
|
||||||
In_row_width is the number of pixels to get to the next input row. Out_pitch
|
|
||||||
is the number of *bytes* to get to the next output row. */
|
|
||||||
void snes_ntsc_blit( snes_ntsc_t const* ntsc, SNES_NTSC_IN_T const* input,
|
|
||||||
long in_row_width, int burst_phase, int in_width, int in_height,
|
|
||||||
void* rgb_out, long out_pitch );
|
|
||||||
|
|
||||||
void snes_ntsc_blit_hires( snes_ntsc_t const* ntsc, SNES_NTSC_IN_T const* input,
|
|
||||||
long in_row_width, int burst_phase, int in_width, int in_height,
|
|
||||||
void* rgb_out, long out_pitch );
|
|
||||||
|
|
||||||
/* Number of output pixels written by low-res blitter for given input width. Width
|
|
||||||
might be rounded down slightly; use SNES_NTSC_IN_WIDTH() on result to find rounded
|
|
||||||
value. Guaranteed not to round 256 down at all. */
|
|
||||||
#define SNES_NTSC_OUT_WIDTH( in_width ) \
|
|
||||||
((((in_width) - 1) / snes_ntsc_in_chunk + 1) * snes_ntsc_out_chunk)
|
|
||||||
|
|
||||||
/* Number of low-res input pixels that will fit within given output width. Might be
|
|
||||||
rounded down slightly; use SNES_NTSC_OUT_WIDTH() on result to find rounded
|
|
||||||
value. */
|
|
||||||
#define SNES_NTSC_IN_WIDTH( out_width ) \
|
|
||||||
(((out_width) / snes_ntsc_out_chunk - 1) * snes_ntsc_in_chunk + 1)
|
|
||||||
|
|
||||||
|
|
||||||
/* Interface for user-defined custom blitters */
|
|
||||||
|
|
||||||
enum { snes_ntsc_in_chunk = 3 }; /* number of input pixels read per chunk */
|
|
||||||
enum { snes_ntsc_out_chunk = 7 }; /* number of output pixels generated per chunk */
|
|
||||||
enum { snes_ntsc_black = 0 }; /* palette index for black */
|
|
||||||
enum { snes_ntsc_burst_count = 3 }; /* burst phase cycles through 0, 1, and 2 */
|
|
||||||
|
|
||||||
/* Begins outputting row and starts three pixels. First pixel will be cut off a bit.
|
|
||||||
Use snes_ntsc_black for unused pixels. Declares variables, so must be before first
|
|
||||||
statement in a block (unless you're using C++). */
|
|
||||||
#define SNES_NTSC_BEGIN_ROW( ntsc, burst, pixel0, pixel1, pixel2 ) \
|
|
||||||
char const* ktable = \
|
|
||||||
(char const*) (ntsc)->table + burst * (snes_ntsc_burst_size * sizeof (snes_ntsc_rgb_t));\
|
|
||||||
SNES_NTSC_BEGIN_ROW_6_( pixel0, pixel1, pixel2, SNES_NTSC_IN_FORMAT, ktable )
|
|
||||||
|
|
||||||
/* Begins input pixel */
|
|
||||||
#define SNES_NTSC_COLOR_IN( index, color ) \
|
|
||||||
SNES_NTSC_COLOR_IN_( index, color, SNES_NTSC_IN_FORMAT, ktable )
|
|
||||||
|
|
||||||
/* Generates output pixel. Bits can be 24, 16, 15, 14, 32 (treated as 24), or 0:
|
|
||||||
24: RRRRRRRR GGGGGGGG BBBBBBBB (8-8-8 RGB)
|
|
||||||
16: RRRRRGGG GGGBBBBB (5-6-5 RGB)
|
|
||||||
15: RRRRRGG GGGBBBBB (5-5-5 RGB)
|
|
||||||
14: BBBBBGG GGGRRRRR (5-5-5 BGR, native SNES format)
|
|
||||||
0: xxxRRRRR RRRxxGGG GGGGGxxB BBBBBBBx (native internal format; x = junk bits) */
|
|
||||||
#define SNES_NTSC_RGB_OUT( index, rgb_out, bits ) \
|
|
||||||
SNES_NTSC_RGB_OUT_14_( index, rgb_out, bits, 1 )
|
|
||||||
|
|
||||||
/* Hires equivalents */
|
|
||||||
#define SNES_NTSC_HIRES_ROW( ntsc, burst, pixel1, pixel2, pixel3, pixel4, pixel5 ) \
|
|
||||||
char const* ktable = \
|
|
||||||
(char const*) (ntsc)->table + burst * (snes_ntsc_burst_size * sizeof (snes_ntsc_rgb_t));\
|
|
||||||
unsigned const snes_ntsc_pixel1_ = (pixel1);\
|
|
||||||
snes_ntsc_rgb_t const* kernel1 = SNES_NTSC_IN_FORMAT( ktable, snes_ntsc_pixel1_ );\
|
|
||||||
unsigned const snes_ntsc_pixel2_ = (pixel2);\
|
|
||||||
snes_ntsc_rgb_t const* kernel2 = SNES_NTSC_IN_FORMAT( ktable, snes_ntsc_pixel2_ );\
|
|
||||||
unsigned const snes_ntsc_pixel3_ = (pixel3);\
|
|
||||||
snes_ntsc_rgb_t const* kernel3 = SNES_NTSC_IN_FORMAT( ktable, snes_ntsc_pixel3_ );\
|
|
||||||
unsigned const snes_ntsc_pixel4_ = (pixel4);\
|
|
||||||
snes_ntsc_rgb_t const* kernel4 = SNES_NTSC_IN_FORMAT( ktable, snes_ntsc_pixel4_ );\
|
|
||||||
unsigned const snes_ntsc_pixel5_ = (pixel5);\
|
|
||||||
snes_ntsc_rgb_t const* kernel5 = SNES_NTSC_IN_FORMAT( ktable, snes_ntsc_pixel5_ );\
|
|
||||||
snes_ntsc_rgb_t const* kernel0 = kernel1;\
|
|
||||||
snes_ntsc_rgb_t const* kernelx0;\
|
|
||||||
snes_ntsc_rgb_t const* kernelx1 = kernel1;\
|
|
||||||
snes_ntsc_rgb_t const* kernelx2 = kernel1;\
|
|
||||||
snes_ntsc_rgb_t const* kernelx3 = kernel1;\
|
|
||||||
snes_ntsc_rgb_t const* kernelx4 = kernel1;\
|
|
||||||
snes_ntsc_rgb_t const* kernelx5 = kernel1
|
|
||||||
|
|
||||||
#define SNES_NTSC_HIRES_OUT( x, rgb_out, bits ) {\
|
|
||||||
snes_ntsc_rgb_t raw_ =\
|
|
||||||
kernel0 [ x ] + kernel2 [(x+5)%7+14] + kernel4 [(x+3)%7+28] +\
|
|
||||||
kernelx0 [(x+7)%7+7] + kernelx2 [(x+5)%7+21] + kernelx4 [(x+3)%7+35] +\
|
|
||||||
kernel1 [(x+6)%7 ] + kernel3 [(x+4)%7+14] + kernel5 [(x+2)%7+28] +\
|
|
||||||
kernelx1 [(x+6)%7+7] + kernelx3 [(x+4)%7+21] + kernelx5 [(x+2)%7+35];\
|
|
||||||
SNES_NTSC_CLAMP_( raw_, 0 );\
|
|
||||||
SNES_NTSC_RGB_OUT_( rgb_out, (bits), 0 );\
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/* private */
|
|
||||||
enum { snes_ntsc_entry_size = 128 };
|
|
||||||
enum { snes_ntsc_palette_size = 0x2000 };
|
|
||||||
typedef unsigned long snes_ntsc_rgb_t;
|
|
||||||
struct snes_ntsc_t {
|
|
||||||
snes_ntsc_rgb_t table [snes_ntsc_palette_size] [snes_ntsc_entry_size];
|
|
||||||
};
|
|
||||||
enum { snes_ntsc_burst_size = snes_ntsc_entry_size / snes_ntsc_burst_count };
|
|
||||||
|
|
||||||
#define SNES_NTSC_RGB16( ktable, n ) \
|
|
||||||
(snes_ntsc_rgb_t const*) (ktable + ((n & 0x001E) | (n >> 1 & 0x03E0) | (n >> 2 & 0x3C00)) * \
|
|
||||||
(snes_ntsc_entry_size / 2 * sizeof (snes_ntsc_rgb_t)))
|
|
||||||
|
|
||||||
#define SNES_NTSC_BGR15( ktable, n ) \
|
|
||||||
(snes_ntsc_rgb_t const*) (ktable + ((n << 9 & 0x3C00) | (n & 0x03E0) | (n >> 10 & 0x001E)) * \
|
|
||||||
(snes_ntsc_entry_size / 2 * sizeof (snes_ntsc_rgb_t)))
|
|
||||||
|
|
||||||
/* common 3->7 ntsc macros */
|
|
||||||
#define SNES_NTSC_BEGIN_ROW_6_( pixel0, pixel1, pixel2, ENTRY, table ) \
|
|
||||||
unsigned const snes_ntsc_pixel0_ = (pixel0);\
|
|
||||||
snes_ntsc_rgb_t const* kernel0 = ENTRY( table, snes_ntsc_pixel0_ );\
|
|
||||||
unsigned const snes_ntsc_pixel1_ = (pixel1);\
|
|
||||||
snes_ntsc_rgb_t const* kernel1 = ENTRY( table, snes_ntsc_pixel1_ );\
|
|
||||||
unsigned const snes_ntsc_pixel2_ = (pixel2);\
|
|
||||||
snes_ntsc_rgb_t const* kernel2 = ENTRY( table, snes_ntsc_pixel2_ );\
|
|
||||||
snes_ntsc_rgb_t const* kernelx0;\
|
|
||||||
snes_ntsc_rgb_t const* kernelx1 = kernel0;\
|
|
||||||
snes_ntsc_rgb_t const* kernelx2 = kernel0
|
|
||||||
|
|
||||||
#define SNES_NTSC_RGB_OUT_14_( x, rgb_out, bits, shift ) {\
|
|
||||||
snes_ntsc_rgb_t raw_ =\
|
|
||||||
kernel0 [x ] + kernel1 [(x+12)%7+14] + kernel2 [(x+10)%7+28] +\
|
|
||||||
kernelx0 [(x+7)%14] + kernelx1 [(x+ 5)%7+21] + kernelx2 [(x+ 3)%7+35];\
|
|
||||||
SNES_NTSC_CLAMP_( raw_, shift );\
|
|
||||||
SNES_NTSC_RGB_OUT_( rgb_out, bits, shift );\
|
|
||||||
}
|
|
||||||
|
|
||||||
/* common ntsc macros */
|
|
||||||
#define snes_ntsc_rgb_builder ((1L << 21) | (1 << 11) | (1 << 1))
|
|
||||||
#define snes_ntsc_clamp_mask (snes_ntsc_rgb_builder * 3 / 2)
|
|
||||||
#define snes_ntsc_clamp_add (snes_ntsc_rgb_builder * 0x101)
|
|
||||||
#define SNES_NTSC_CLAMP_( io, shift ) {\
|
|
||||||
snes_ntsc_rgb_t sub = (io) >> (9-(shift)) & snes_ntsc_clamp_mask;\
|
|
||||||
snes_ntsc_rgb_t clamp = snes_ntsc_clamp_add - sub;\
|
|
||||||
io |= clamp;\
|
|
||||||
clamp -= sub;\
|
|
||||||
io &= clamp;\
|
|
||||||
}
|
|
||||||
|
|
||||||
#define SNES_NTSC_COLOR_IN_( index, color, ENTRY, table ) {\
|
|
||||||
unsigned color_;\
|
|
||||||
kernelx##index = kernel##index;\
|
|
||||||
kernel##index = (color_ = (color), ENTRY( table, color_ ));\
|
|
||||||
}
|
|
||||||
|
|
||||||
/* x is always zero except in snes_ntsc library */
|
|
||||||
/* original routine */
|
|
||||||
/*
|
|
||||||
#define SNES_NTSC_RGB_OUT_( rgb_out, bits, x ) {\
|
|
||||||
if ( bits == 16 )\
|
|
||||||
rgb_out = (raw_>>(13-x)& 0xF800)|(raw_>>(8-x)&0x07E0)|(raw_>>(4-x)&0x001F);\
|
|
||||||
if ( bits == 24 || bits == 32 )\
|
|
||||||
rgb_out = (raw_>>(5-x)&0xFF0000)|(raw_>>(3-x)&0xFF00)|(raw_>>(1-x)&0xFF);\
|
|
||||||
if ( bits == 15 )\
|
|
||||||
rgb_out = (raw_>>(14-x)& 0x7C00)|(raw_>>(9-x)&0x03E0)|(raw_>>(4-x)&0x001F);\
|
|
||||||
if ( bits == 14 )\
|
|
||||||
rgb_out = (raw_>>(24-x)& 0x001F)|(raw_>>(9-x)&0x03E0)|(raw_<<(6+x)&0x7C00);\
|
|
||||||
if ( bits == 0 )\
|
|
||||||
rgb_out = raw_ << x;\
|
|
||||||
}
|
|
||||||
*/
|
|
||||||
|
|
||||||
/* custom bsnes routine -- hooks into bsnes colortable */
|
|
||||||
#define SNES_NTSC_RGB_OUT_( rgb_out, bits, x ) {\
|
|
||||||
if ( bits == 16 ) {\
|
|
||||||
rgb_out = (raw_>>(13-x)& 0xF800)|(raw_>>(8-x)&0x07E0)|(raw_>>(4-x)&0x001F);\
|
|
||||||
rgb_out = ((rgb_out&0xf800)>>11)|((rgb_out&0x07c0)>>1)|((rgb_out&0x001f)<<10);\
|
|
||||||
rgb_out = colortable[rgb_out];\
|
|
||||||
} else if ( bits == 24 || bits == 32 ) {\
|
|
||||||
rgb_out = (raw_>>(5-x)&0xFF0000)|(raw_>>(3-x)&0xFF00)|(raw_>>(1-x)&0xFF);\
|
|
||||||
rgb_out = ((rgb_out&0xf80000)>>19)|((rgb_out&0x00f800)>>6)|((rgb_out&0x0000f8)<<7);\
|
|
||||||
rgb_out = colortable[rgb_out];\
|
|
||||||
} else if ( bits == 15 ) {\
|
|
||||||
rgb_out = (raw_>>(14-x)& 0x7C00)|(raw_>>(9-x)&0x03E0)|(raw_>>(4-x)&0x001F);\
|
|
||||||
rgb_out = ((rgb_out&0x7c00)>>10)|((rgb_out&0x03e0))|((rgb_out&0x001f)<<10);\
|
|
||||||
rgb_out = colortable[rgb_out];\
|
|
||||||
} else {\
|
|
||||||
rgb_out = raw_ << x;\
|
|
||||||
}\
|
|
||||||
}
|
|
||||||
|
|
||||||
#ifdef __cplusplus
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#endif
|
|
|
@ -1,26 +0,0 @@
|
||||||
/* Configure library by modifying this file */
|
|
||||||
|
|
||||||
#ifndef SNES_NTSC_CONFIG_H
|
|
||||||
#define SNES_NTSC_CONFIG_H
|
|
||||||
|
|
||||||
/* Format of source pixels */
|
|
||||||
/* #define SNES_NTSC_IN_FORMAT SNES_NTSC_RGB16 */
|
|
||||||
#define SNES_NTSC_IN_FORMAT SNES_NTSC_BGR15
|
|
||||||
|
|
||||||
/* The following affect the built-in blitter only; a custom blitter can
|
|
||||||
handle things however it wants. */
|
|
||||||
|
|
||||||
/* Bits per pixel of output. Can be 15, 16, 32, or 24 (same as 32). */
|
|
||||||
#define SNES_NTSC_OUT_DEPTH 32
|
|
||||||
|
|
||||||
/* Type of input pixel values */
|
|
||||||
#define SNES_NTSC_IN_T unsigned short
|
|
||||||
|
|
||||||
/* Each raw pixel input value is passed through this. You might want to mask
|
|
||||||
the pixel index if you use the high bits as flags, etc. */
|
|
||||||
#define SNES_NTSC_ADJ_IN( in ) in
|
|
||||||
|
|
||||||
/* For each pixel, this is the basic operation:
|
|
||||||
output_color = SNES_NTSC_ADJ_IN( SNES_NTSC_IN_T ) */
|
|
||||||
|
|
||||||
#endif
|
|
|
@ -1,439 +0,0 @@
|
||||||
/* snes_ntsc 0.2.2. http://www.slack.net/~ant/ */
|
|
||||||
|
|
||||||
/* Common implementation of NTSC filters */
|
|
||||||
|
|
||||||
#include <assert.h>
|
|
||||||
#include <math.h>
|
|
||||||
|
|
||||||
/* Copyright (C) 2006 Shay Green. This module is free software; you
|
|
||||||
can redistribute it and/or modify it under the terms of the GNU Lesser
|
|
||||||
General Public License as published by the Free Software Foundation; either
|
|
||||||
version 2.1 of the License, or (at your option) any later version. This
|
|
||||||
module is distributed in the hope that it will be useful, but WITHOUT ANY
|
|
||||||
WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
|
|
||||||
FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more
|
|
||||||
details. You should have received a copy of the GNU Lesser General Public
|
|
||||||
License along with this module; if not, write to the Free Software Foundation,
|
|
||||||
Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */
|
|
||||||
|
|
||||||
#define DISABLE_CORRECTION 0
|
|
||||||
|
|
||||||
#undef PI
|
|
||||||
#define PI 3.14159265358979323846f
|
|
||||||
|
|
||||||
#ifndef LUMA_CUTOFF
|
|
||||||
#define LUMA_CUTOFF 0.20
|
|
||||||
#endif
|
|
||||||
#ifndef gamma_size
|
|
||||||
#define gamma_size 1
|
|
||||||
#endif
|
|
||||||
#ifndef rgb_bits
|
|
||||||
#define rgb_bits 8
|
|
||||||
#endif
|
|
||||||
#ifndef artifacts_max
|
|
||||||
#define artifacts_max (artifacts_mid * 1.5f)
|
|
||||||
#endif
|
|
||||||
#ifndef fringing_max
|
|
||||||
#define fringing_max (fringing_mid * 2)
|
|
||||||
#endif
|
|
||||||
#ifndef STD_HUE_CONDITION
|
|
||||||
#define STD_HUE_CONDITION( setup ) 1
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#define ext_decoder_hue (std_decoder_hue + 15)
|
|
||||||
#define rgb_unit (1 << rgb_bits)
|
|
||||||
#define rgb_offset (rgb_unit * 2 + 0.5f)
|
|
||||||
|
|
||||||
enum { burst_size = snes_ntsc_entry_size / burst_count };
|
|
||||||
enum { kernel_half = 16 };
|
|
||||||
enum { kernel_size = kernel_half * 2 + 1 };
|
|
||||||
|
|
||||||
typedef struct init_t
|
|
||||||
{
|
|
||||||
float to_rgb [burst_count * 6];
|
|
||||||
float to_float [gamma_size];
|
|
||||||
float contrast;
|
|
||||||
float brightness;
|
|
||||||
float artifacts;
|
|
||||||
float fringing;
|
|
||||||
float kernel [rescale_out * kernel_size * 2];
|
|
||||||
} init_t;
|
|
||||||
|
|
||||||
#define ROTATE_IQ( i, q, sin_b, cos_b ) {\
|
|
||||||
float t;\
|
|
||||||
t = i * cos_b - q * sin_b;\
|
|
||||||
q = i * sin_b + q * cos_b;\
|
|
||||||
i = t;\
|
|
||||||
}
|
|
||||||
|
|
||||||
static void init_filters( init_t* impl, snes_ntsc_setup_t const* setup )
|
|
||||||
{
|
|
||||||
#if rescale_out > 1
|
|
||||||
float kernels [kernel_size * 2];
|
|
||||||
#else
|
|
||||||
float* const kernels = impl->kernel;
|
|
||||||
#endif
|
|
||||||
|
|
||||||
/* generate luma (y) filter using sinc kernel */
|
|
||||||
{
|
|
||||||
/* sinc with rolloff (dsf) */
|
|
||||||
float const rolloff = 1 + (float) setup->sharpness * (float) 0.032;
|
|
||||||
float const maxh = 32;
|
|
||||||
float const pow_a_n = (float) pow( rolloff, maxh );
|
|
||||||
float sum;
|
|
||||||
int i;
|
|
||||||
/* quadratic mapping to reduce negative (blurring) range */
|
|
||||||
float to_angle = (float) setup->resolution + 1;
|
|
||||||
to_angle = PI / maxh * (float) LUMA_CUTOFF * (to_angle * to_angle + 1);
|
|
||||||
|
|
||||||
kernels [kernel_size * 3 / 2] = maxh; /* default center value */
|
|
||||||
for ( i = 0; i < kernel_half * 2 + 1; i++ )
|
|
||||||
{
|
|
||||||
int x = i - kernel_half;
|
|
||||||
float angle = x * to_angle;
|
|
||||||
/* instability occurs at center point with rolloff very close to 1.0 */
|
|
||||||
if ( x || pow_a_n > (float) 1.056 || pow_a_n < (float) 0.981 )
|
|
||||||
{
|
|
||||||
float rolloff_cos_a = rolloff * (float) cos( angle );
|
|
||||||
float num = 1 - rolloff_cos_a -
|
|
||||||
pow_a_n * (float) cos( maxh * angle ) +
|
|
||||||
pow_a_n * rolloff * (float) cos( (maxh - 1) * angle );
|
|
||||||
float den = 1 - rolloff_cos_a - rolloff_cos_a + rolloff * rolloff;
|
|
||||||
float dsf = num / den;
|
|
||||||
kernels [kernel_size * 3 / 2 - kernel_half + i] = dsf - (float) 0.5;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/* apply blackman window and find sum */
|
|
||||||
sum = 0;
|
|
||||||
for ( i = 0; i < kernel_half * 2 + 1; i++ )
|
|
||||||
{
|
|
||||||
float x = PI * 2 / (kernel_half * 2) * i;
|
|
||||||
float blackman = 0.42f - 0.5f * (float) cos( x ) + 0.08f * (float) cos( x * 2 );
|
|
||||||
sum += (kernels [kernel_size * 3 / 2 - kernel_half + i] *= blackman);
|
|
||||||
}
|
|
||||||
|
|
||||||
/* normalize kernel */
|
|
||||||
sum = 1.0f / sum;
|
|
||||||
for ( i = 0; i < kernel_half * 2 + 1; i++ )
|
|
||||||
{
|
|
||||||
int x = kernel_size * 3 / 2 - kernel_half + i;
|
|
||||||
kernels [x] *= sum;
|
|
||||||
assert( kernels [x] == kernels [x] ); /* catch numerical instability */
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/* generate chroma (iq) filter using gaussian kernel */
|
|
||||||
{
|
|
||||||
float const cutoff_factor = -0.03125f;
|
|
||||||
float cutoff = (float) setup->bleed;
|
|
||||||
int i;
|
|
||||||
|
|
||||||
if ( cutoff < 0 )
|
|
||||||
{
|
|
||||||
/* keep extreme value accessible only near upper end of scale (1.0) */
|
|
||||||
cutoff *= cutoff;
|
|
||||||
cutoff *= cutoff;
|
|
||||||
cutoff *= cutoff;
|
|
||||||
cutoff *= -30.0f / 0.65f;
|
|
||||||
}
|
|
||||||
cutoff = cutoff_factor - 0.65f * cutoff_factor * cutoff;
|
|
||||||
|
|
||||||
for ( i = -kernel_half; i <= kernel_half; i++ )
|
|
||||||
kernels [kernel_size / 2 + i] = (float) exp( i * i * cutoff );
|
|
||||||
|
|
||||||
/* normalize even and odd phases separately */
|
|
||||||
for ( i = 0; i < 2; i++ )
|
|
||||||
{
|
|
||||||
float sum = 0;
|
|
||||||
int x;
|
|
||||||
for ( x = i; x < kernel_size; x += 2 )
|
|
||||||
sum += kernels [x];
|
|
||||||
|
|
||||||
sum = 1.0f / sum;
|
|
||||||
for ( x = i; x < kernel_size; x += 2 )
|
|
||||||
{
|
|
||||||
kernels [x] *= sum;
|
|
||||||
assert( kernels [x] == kernels [x] ); /* catch numerical instability */
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
printf( "luma:\n" );
|
|
||||||
for ( i = kernel_size; i < kernel_size * 2; i++ )
|
|
||||||
printf( "%f\n", kernels [i] );
|
|
||||||
printf( "chroma:\n" );
|
|
||||||
for ( i = 0; i < kernel_size; i++ )
|
|
||||||
printf( "%f\n", kernels [i] );
|
|
||||||
*/
|
|
||||||
|
|
||||||
/* generate linear rescale kernels */
|
|
||||||
#if rescale_out > 1
|
|
||||||
{
|
|
||||||
float weight = 1.0f;
|
|
||||||
float* out = impl->kernel;
|
|
||||||
int n = rescale_out;
|
|
||||||
do
|
|
||||||
{
|
|
||||||
float remain = 0;
|
|
||||||
int i;
|
|
||||||
weight -= 1.0f / rescale_in;
|
|
||||||
for ( i = 0; i < kernel_size * 2; i++ )
|
|
||||||
{
|
|
||||||
float cur = kernels [i];
|
|
||||||
float m = cur * weight;
|
|
||||||
*out++ = m + remain;
|
|
||||||
remain = cur - m;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
while ( --n );
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
}
|
|
||||||
|
|
||||||
static float const default_decoder [6] =
|
|
||||||
{ 0.956f, 0.621f, -0.272f, -0.647f, -1.105f, 1.702f };
|
|
||||||
|
|
||||||
static void init( init_t* impl, snes_ntsc_setup_t const* setup )
|
|
||||||
{
|
|
||||||
impl->brightness = (float) setup->brightness * (0.5f * rgb_unit) + rgb_offset;
|
|
||||||
impl->contrast = (float) setup->contrast * (0.5f * rgb_unit) + rgb_unit;
|
|
||||||
#ifdef default_palette_contrast
|
|
||||||
if ( !setup->palette )
|
|
||||||
impl->contrast *= default_palette_contrast;
|
|
||||||
#endif
|
|
||||||
|
|
||||||
impl->artifacts = (float) setup->artifacts;
|
|
||||||
if ( impl->artifacts > 0 )
|
|
||||||
impl->artifacts *= artifacts_max - artifacts_mid;
|
|
||||||
impl->artifacts = impl->artifacts * artifacts_mid + artifacts_mid;
|
|
||||||
|
|
||||||
impl->fringing = (float) setup->fringing;
|
|
||||||
if ( impl->fringing > 0 )
|
|
||||||
impl->fringing *= fringing_max - fringing_mid;
|
|
||||||
impl->fringing = impl->fringing * fringing_mid + fringing_mid;
|
|
||||||
|
|
||||||
init_filters( impl, setup );
|
|
||||||
|
|
||||||
/* generate gamma table */
|
|
||||||
if ( gamma_size > 1 )
|
|
||||||
{
|
|
||||||
float const to_float = 1.0f / (gamma_size - (gamma_size > 1));
|
|
||||||
float const gamma = 1.1333f - (float) setup->gamma * 0.5f;
|
|
||||||
/* match common PC's 2.2 gamma to TV's 2.65 gamma */
|
|
||||||
int i;
|
|
||||||
for ( i = 0; i < gamma_size; i++ )
|
|
||||||
impl->to_float [i] =
|
|
||||||
(float) pow( i * to_float, gamma ) * impl->contrast + impl->brightness;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* setup decoder matricies */
|
|
||||||
{
|
|
||||||
float hue = (float) setup->hue * PI + PI / 180 * ext_decoder_hue;
|
|
||||||
float sat = (float) setup->saturation + 1;
|
|
||||||
float const* decoder = setup->decoder_matrix;
|
|
||||||
if ( !decoder )
|
|
||||||
{
|
|
||||||
decoder = default_decoder;
|
|
||||||
if ( STD_HUE_CONDITION( setup ) )
|
|
||||||
hue += PI / 180 * (std_decoder_hue - ext_decoder_hue);
|
|
||||||
}
|
|
||||||
|
|
||||||
{
|
|
||||||
float s = (float) sin( hue ) * sat;
|
|
||||||
float c = (float) cos( hue ) * sat;
|
|
||||||
float* out = impl->to_rgb;
|
|
||||||
int n;
|
|
||||||
|
|
||||||
n = burst_count;
|
|
||||||
do
|
|
||||||
{
|
|
||||||
float const* in = decoder;
|
|
||||||
int n = 3;
|
|
||||||
do
|
|
||||||
{
|
|
||||||
float i = *in++;
|
|
||||||
float q = *in++;
|
|
||||||
*out++ = i * c - q * s;
|
|
||||||
*out++ = i * s + q * c;
|
|
||||||
}
|
|
||||||
while ( --n );
|
|
||||||
if ( burst_count <= 1 )
|
|
||||||
break;
|
|
||||||
ROTATE_IQ( s, c, 0.866025f, -0.5f ); /* +120 degrees */
|
|
||||||
}
|
|
||||||
while ( --n );
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/* kernel generation */
|
|
||||||
|
|
||||||
#define RGB_TO_YIQ( r, g, b, y, i ) (\
|
|
||||||
(y = (r) * 0.299f + (g) * 0.587f + (b) * 0.114f),\
|
|
||||||
(i = (r) * 0.596f - (g) * 0.275f - (b) * 0.321f),\
|
|
||||||
((r) * 0.212f - (g) * 0.523f + (b) * 0.311f)\
|
|
||||||
)
|
|
||||||
|
|
||||||
#define YIQ_TO_RGB( y, i, q, to_rgb, type, r, g ) (\
|
|
||||||
r = (type) (y + to_rgb [0] * i + to_rgb [1] * q),\
|
|
||||||
g = (type) (y + to_rgb [2] * i + to_rgb [3] * q),\
|
|
||||||
(type) (y + to_rgb [4] * i + to_rgb [5] * q)\
|
|
||||||
)
|
|
||||||
|
|
||||||
#define PACK_RGB( r, g, b ) ((r) << 21 | (g) << 11 | (b) << 1)
|
|
||||||
|
|
||||||
enum { rgb_kernel_size = burst_size / alignment_count };
|
|
||||||
enum { rgb_bias = rgb_unit * 2 * snes_ntsc_rgb_builder };
|
|
||||||
|
|
||||||
typedef struct pixel_info_t
|
|
||||||
{
|
|
||||||
int offset;
|
|
||||||
float negate;
|
|
||||||
float kernel [4];
|
|
||||||
} pixel_info_t;
|
|
||||||
|
|
||||||
#if rescale_in > 1
|
|
||||||
#define PIXEL_OFFSET_( ntsc, scaled ) \
|
|
||||||
(kernel_size / 2 + ntsc + (scaled != 0) + (rescale_out - scaled) % rescale_out + \
|
|
||||||
(kernel_size * 2 * scaled))
|
|
||||||
|
|
||||||
#define PIXEL_OFFSET( ntsc, scaled ) \
|
|
||||||
PIXEL_OFFSET_( ((ntsc) - (scaled) / rescale_out * rescale_in),\
|
|
||||||
(((scaled) + rescale_out * 10) % rescale_out) ),\
|
|
||||||
(1.0f - (((ntsc) + 100) & 2))
|
|
||||||
#else
|
|
||||||
#define PIXEL_OFFSET( ntsc, scaled ) \
|
|
||||||
(kernel_size / 2 + (ntsc) - (scaled)),\
|
|
||||||
(1.0f - (((ntsc) + 100) & 2))
|
|
||||||
#endif
|
|
||||||
|
|
||||||
extern pixel_info_t const snes_ntsc_pixels [alignment_count];
|
|
||||||
|
|
||||||
/* Generate pixel at all burst phases and column alignments */
|
|
||||||
static void gen_kernel( init_t* impl, float y, float i, float q, snes_ntsc_rgb_t* out )
|
|
||||||
{
|
|
||||||
/* generate for each scanline burst phase */
|
|
||||||
float const* to_rgb = impl->to_rgb;
|
|
||||||
int burst_remain = burst_count;
|
|
||||||
y -= rgb_offset;
|
|
||||||
do
|
|
||||||
{
|
|
||||||
/* Encode yiq into *two* composite signals (to allow control over artifacting).
|
|
||||||
Convolve these with kernels which: filter respective components, apply
|
|
||||||
sharpening, and rescale horizontally. Convert resulting yiq to rgb and pack
|
|
||||||
into integer. Based on algorithm by NewRisingSun. */
|
|
||||||
pixel_info_t const* pixel = snes_ntsc_pixels;
|
|
||||||
int alignment_remain = alignment_count;
|
|
||||||
do
|
|
||||||
{
|
|
||||||
/* negate is -1 when composite starts at odd multiple of 2 */
|
|
||||||
float const yy = y * impl->fringing * pixel->negate;
|
|
||||||
float const ic0 = (i + yy) * pixel->kernel [0];
|
|
||||||
float const qc1 = (q + yy) * pixel->kernel [1];
|
|
||||||
float const ic2 = (i - yy) * pixel->kernel [2];
|
|
||||||
float const qc3 = (q - yy) * pixel->kernel [3];
|
|
||||||
|
|
||||||
float const factor = impl->artifacts * pixel->negate;
|
|
||||||
float const ii = i * factor;
|
|
||||||
float const yc0 = (y + ii) * pixel->kernel [0];
|
|
||||||
float const yc2 = (y - ii) * pixel->kernel [2];
|
|
||||||
|
|
||||||
float const qq = q * factor;
|
|
||||||
float const yc1 = (y + qq) * pixel->kernel [1];
|
|
||||||
float const yc3 = (y - qq) * pixel->kernel [3];
|
|
||||||
|
|
||||||
float const* k = &impl->kernel [pixel->offset];
|
|
||||||
int n;
|
|
||||||
++pixel;
|
|
||||||
for ( n = rgb_kernel_size; n; --n )
|
|
||||||
{
|
|
||||||
float i = k[0]*ic0 + k[2]*ic2;
|
|
||||||
float q = k[1]*qc1 + k[3]*qc3;
|
|
||||||
float y = k[kernel_size+0]*yc0 + k[kernel_size+1]*yc1 +
|
|
||||||
k[kernel_size+2]*yc2 + k[kernel_size+3]*yc3 + rgb_offset;
|
|
||||||
if ( rescale_out <= 1 )
|
|
||||||
k--;
|
|
||||||
else if ( k < &impl->kernel [kernel_size * 2 * (rescale_out - 1)] )
|
|
||||||
k += kernel_size * 2 - 1;
|
|
||||||
else
|
|
||||||
k -= kernel_size * 2 * (rescale_out - 1) + 2;
|
|
||||||
{
|
|
||||||
int r, g, b = YIQ_TO_RGB( y, i, q, to_rgb, int, r, g );
|
|
||||||
*out++ = PACK_RGB( r, g, b ) - rgb_bias;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
while ( alignment_count > 1 && --alignment_remain );
|
|
||||||
|
|
||||||
if ( burst_count <= 1 )
|
|
||||||
break;
|
|
||||||
|
|
||||||
to_rgb += 6;
|
|
||||||
|
|
||||||
ROTATE_IQ( i, q, -0.866025f, -0.5f ); /* -120 degrees */
|
|
||||||
}
|
|
||||||
while ( --burst_remain );
|
|
||||||
}
|
|
||||||
|
|
||||||
static void correct_errors( snes_ntsc_rgb_t color, snes_ntsc_rgb_t* out );
|
|
||||||
|
|
||||||
#if DISABLE_CORRECTION
|
|
||||||
#define CORRECT_ERROR( a ) { out [i] += rgb_bias; }
|
|
||||||
#define DISTRIBUTE_ERROR( a, b, c ) { out [i] += rgb_bias; }
|
|
||||||
#else
|
|
||||||
#define CORRECT_ERROR( a ) { out [a] += error; }
|
|
||||||
#define DISTRIBUTE_ERROR( a, b, c ) {\
|
|
||||||
snes_ntsc_rgb_t fourth = (error + 2 * snes_ntsc_rgb_builder) >> 2;\
|
|
||||||
fourth &= (rgb_bias >> 1) - snes_ntsc_rgb_builder;\
|
|
||||||
fourth -= rgb_bias >> 2;\
|
|
||||||
out [a] += fourth;\
|
|
||||||
out [b] += fourth;\
|
|
||||||
out [c] += fourth;\
|
|
||||||
out [i] += error - (fourth * 3);\
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#define RGB_PALETTE_OUT( rgb, out_ )\
|
|
||||||
{\
|
|
||||||
unsigned char* out = (out_);\
|
|
||||||
snes_ntsc_rgb_t clamped = (rgb);\
|
|
||||||
SNES_NTSC_CLAMP_( clamped, (8 - rgb_bits) );\
|
|
||||||
out [0] = (unsigned char) (clamped >> 21);\
|
|
||||||
out [1] = (unsigned char) (clamped >> 11);\
|
|
||||||
out [2] = (unsigned char) (clamped >> 1);\
|
|
||||||
}
|
|
||||||
|
|
||||||
/* blitter related */
|
|
||||||
|
|
||||||
#ifndef restrict
|
|
||||||
#if defined (__GNUC__)
|
|
||||||
#define restrict __restrict__
|
|
||||||
#elif defined (_MSC_VER) && _MSC_VER > 1300
|
|
||||||
#define restrict __restrict
|
|
||||||
#else
|
|
||||||
/* no support for restricted pointers */
|
|
||||||
#define restrict
|
|
||||||
#endif
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#include <limits.h>
|
|
||||||
|
|
||||||
#if SNES_NTSC_OUT_DEPTH <= 16
|
|
||||||
#if USHRT_MAX == 0xFFFF
|
|
||||||
typedef unsigned short snes_ntsc_out_t;
|
|
||||||
#else
|
|
||||||
#error "Need 16-bit int type"
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#else
|
|
||||||
#if UINT_MAX == 0xFFFFFFFF
|
|
||||||
typedef unsigned int snes_ntsc_out_t;
|
|
||||||
#elif ULONG_MAX == 0xFFFFFFFF
|
|
||||||
typedef unsigned long snes_ntsc_out_t;
|
|
||||||
#else
|
|
||||||
#error "Need 32-bit int type"
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#endif
|
|
|
@ -1,39 +0,0 @@
|
||||||
#include "pixellate2x.hpp"
|
|
||||||
|
|
||||||
void Pixellate2xFilter::size(unsigned &outwidth, unsigned &outheight, unsigned width, unsigned height) {
|
|
||||||
outwidth = (width <= 256) ? width * 2 : width;
|
|
||||||
outheight = (height <= 240) ? height * 2 : height;
|
|
||||||
}
|
|
||||||
|
|
||||||
void Pixellate2xFilter::render(
|
|
||||||
uint32_t *output, unsigned outpitch, const uint16_t *input, unsigned pitch,
|
|
||||||
const unsigned *line, unsigned width, unsigned height
|
|
||||||
) {
|
|
||||||
pitch >>= 1;
|
|
||||||
outpitch >>= 2;
|
|
||||||
|
|
||||||
uint32_t *out0 = output;
|
|
||||||
uint32_t *out1 = output + outpitch;
|
|
||||||
|
|
||||||
for(unsigned y = 0; y < height; y++) {
|
|
||||||
unsigned linewidth = line[y];
|
|
||||||
for(unsigned x = 0; x < linewidth; x++) {
|
|
||||||
uint32_t p = colortable[*input++];
|
|
||||||
|
|
||||||
*out0++ = p;
|
|
||||||
if(height <= 240) *out1++ = p;
|
|
||||||
if(linewidth > 256) continue;
|
|
||||||
|
|
||||||
*out0++ = p;
|
|
||||||
if(height <= 240) *out1++ = p;
|
|
||||||
}
|
|
||||||
|
|
||||||
input += pitch - linewidth;
|
|
||||||
if(height <= 240) {
|
|
||||||
out0 += outpitch + outpitch - 512;
|
|
||||||
out1 += outpitch + outpitch - 512;
|
|
||||||
} else {
|
|
||||||
out0 += outpitch - 512;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,5 +0,0 @@
|
||||||
class Pixellate2xFilter {
|
|
||||||
public:
|
|
||||||
void size(unsigned&, unsigned&, unsigned, unsigned);
|
|
||||||
void render(uint32_t*, unsigned, const uint16_t*, unsigned, const unsigned*, unsigned, unsigned);
|
|
||||||
} filter_pixellate2x;
|
|
|
@ -1,61 +0,0 @@
|
||||||
#include "scale2x.hpp"
|
|
||||||
|
|
||||||
void Scale2xFilter::size(unsigned &outwidth, unsigned &outheight, unsigned width, unsigned height) {
|
|
||||||
if(height > 240) return filter_direct.size(outwidth, outheight, width, height);
|
|
||||||
outwidth = (width <= 256) ? width * 2 : width;
|
|
||||||
outheight = (height <= 240) ? height * 2 : height;
|
|
||||||
}
|
|
||||||
|
|
||||||
void Scale2xFilter::render(
|
|
||||||
uint32_t *output, unsigned outpitch, const uint16_t *input, unsigned pitch,
|
|
||||||
const unsigned *line, unsigned width, unsigned height
|
|
||||||
) {
|
|
||||||
if(height > 240) {
|
|
||||||
filter_direct.render(output, outpitch, input, pitch, line, width, height);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
pitch >>= 1;
|
|
||||||
outpitch >>= 2;
|
|
||||||
|
|
||||||
uint32_t *out0 = output;
|
|
||||||
uint32_t *out1 = output + outpitch;
|
|
||||||
|
|
||||||
for(unsigned y = 0; y < height; y++) {
|
|
||||||
unsigned linewidth = line[y];
|
|
||||||
|
|
||||||
if(linewidth == 256) {
|
|
||||||
int prevline = (y == 0) || (linewidth != line[y - 1]) ? 0 : pitch;
|
|
||||||
int nextline = (y == height - 1) || (linewidth != line[y + 1]) ? 0 : pitch;
|
|
||||||
|
|
||||||
for(unsigned x = 0; x < 256; x++) {
|
|
||||||
uint16_t A = *(input - prevline);
|
|
||||||
uint16_t B = (x > 0) ? *(input - 1) : *input;
|
|
||||||
uint16_t C = *input;
|
|
||||||
uint16_t D = (x < 255) ? *(input + 1) : *input;
|
|
||||||
uint16_t E = *(input++ + nextline);
|
|
||||||
uint32_t c = colortable[C];
|
|
||||||
|
|
||||||
if(A != E && B != D) {
|
|
||||||
*out0++ = (A == B ? colortable[A] : c);
|
|
||||||
*out0++ = (A == D ? colortable[A] : c);
|
|
||||||
*out1++ = (E == B ? colortable[E] : c);
|
|
||||||
*out1++ = (E == D ? colortable[E] : c);
|
|
||||||
} else {
|
|
||||||
*out0++ = c;
|
|
||||||
*out0++ = c;
|
|
||||||
*out1++ = c;
|
|
||||||
*out1++ = c;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
for(unsigned x = 0; x < 512; x++) {
|
|
||||||
*out0++ = *out1++ = colortable[*input++];
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
input += pitch - linewidth;
|
|
||||||
out0 += outpitch + outpitch - 512;
|
|
||||||
out1 += outpitch + outpitch - 512;
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,5 +0,0 @@
|
||||||
class Scale2xFilter {
|
|
||||||
public:
|
|
||||||
void size(unsigned&, unsigned&, unsigned, unsigned);
|
|
||||||
void render(uint32_t*, unsigned, const uint16_t*, unsigned, const unsigned*, unsigned, unsigned);
|
|
||||||
} filter_scale2x;
|
|
|
@ -1,84 +0,0 @@
|
||||||
#include "snesfilter.hpp"
|
|
||||||
|
|
||||||
#if defined(_WIN32)
|
|
||||||
#define dllexport __declspec(dllexport)
|
|
||||||
#else
|
|
||||||
#define dllexport
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#include <stdio.h>
|
|
||||||
#include <stdlib.h>
|
|
||||||
#include <string.h>
|
|
||||||
|
|
||||||
#define QT_CORE_LIB
|
|
||||||
#include <QtGui>
|
|
||||||
|
|
||||||
#include <nall/config.hpp>
|
|
||||||
#include <nall/platform.hpp>
|
|
||||||
#include <nall/string.hpp>
|
|
||||||
using namespace nall;
|
|
||||||
|
|
||||||
const uint32_t *colortable;
|
|
||||||
configuration *config;
|
|
||||||
|
|
||||||
#include "direct/direct.cpp"
|
|
||||||
#include "pixellate2x/pixellate2x.cpp"
|
|
||||||
#include "scale2x/scale2x.cpp"
|
|
||||||
#include "2xsai/2xsai.cpp"
|
|
||||||
#include "lq2x/lq2x.cpp"
|
|
||||||
#include "hq2x/hq2x.cpp"
|
|
||||||
#include "ntsc/ntsc.cpp"
|
|
||||||
|
|
||||||
dllexport const char* snesfilter_supported() {
|
|
||||||
return "Pixellate2x;Scale2x;2xSaI;Super 2xSaI;Super Eagle;LQ2x;HQ2x;NTSC";
|
|
||||||
}
|
|
||||||
|
|
||||||
dllexport void snesfilter_configuration(configuration &config_) {
|
|
||||||
config = &config_;
|
|
||||||
if(config) {
|
|
||||||
filter_ntsc.bind(*config);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
dllexport void snesfilter_colortable(const uint32_t *colortable_) {
|
|
||||||
colortable = colortable_;
|
|
||||||
}
|
|
||||||
|
|
||||||
dllexport void snesfilter_size(unsigned filter, unsigned &outwidth, unsigned &outheight, unsigned width, unsigned height) {
|
|
||||||
switch(filter) {
|
|
||||||
default: return filter_direct.size(outwidth, outheight, width, height);
|
|
||||||
case 1: return filter_pixellate2x.size(outwidth, outheight, width, height);
|
|
||||||
case 2: return filter_scale2x.size(outwidth, outheight, width, height);
|
|
||||||
case 3: return filter_2xsai.size(outwidth, outheight, width, height);
|
|
||||||
case 4: return filter_super2xsai.size(outwidth, outheight, width, height);
|
|
||||||
case 5: return filter_supereagle.size(outwidth, outheight, width, height);
|
|
||||||
case 6: return filter_lq2x.size(outwidth, outheight, width, height);
|
|
||||||
case 7: return filter_hq2x.size(outwidth, outheight, width, height);
|
|
||||||
case 8: return filter_ntsc.size(outwidth, outheight, width, height);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
dllexport void snesfilter_render(
|
|
||||||
unsigned filter, uint32_t *output, unsigned outpitch,
|
|
||||||
const uint16_t *input, unsigned pitch,
|
|
||||||
const unsigned *line, unsigned width, unsigned height
|
|
||||||
) {
|
|
||||||
switch(filter) {
|
|
||||||
default: return filter_direct.render(output, outpitch, input, pitch, line, width, height);
|
|
||||||
case 1: return filter_pixellate2x.render(output, outpitch, input, pitch, line, width, height);
|
|
||||||
case 2: return filter_scale2x.render(output, outpitch, input, pitch, line, width, height);
|
|
||||||
case 3: return filter_2xsai.render(output, outpitch, input, pitch, line, width, height);
|
|
||||||
case 4: return filter_super2xsai.render(output, outpitch, input, pitch, line, width, height);
|
|
||||||
case 5: return filter_supereagle.render(output, outpitch, input, pitch, line, width, height);
|
|
||||||
case 6: return filter_lq2x.render(output, outpitch, input, pitch, line, width, height);
|
|
||||||
case 7: return filter_hq2x.render(output, outpitch, input, pitch, line, width, height);
|
|
||||||
case 8: return filter_ntsc.render(output, outpitch, input, pitch, line, width, height);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
dllexport QWidget* snesfilter_settings(unsigned filter) {
|
|
||||||
switch(filter) {
|
|
||||||
default: return 0;
|
|
||||||
case 8: return filter_ntsc.settings();
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,16 +0,0 @@
|
||||||
#include <stdint.h>
|
|
||||||
class QWidget;
|
|
||||||
namespace nall { class configuration; }
|
|
||||||
|
|
||||||
extern "C" {
|
|
||||||
const char* snesfilter_supported();
|
|
||||||
void snesfilter_configuration(nall::configuration&);
|
|
||||||
void snesfilter_colortable(const uint32_t*);
|
|
||||||
void snesfilter_size(unsigned, unsigned&, unsigned&, unsigned, unsigned);
|
|
||||||
void snesfilter_render(
|
|
||||||
unsigned, uint32_t*, unsigned,
|
|
||||||
const uint16_t*, unsigned,
|
|
||||||
const unsigned*, unsigned, unsigned
|
|
||||||
);
|
|
||||||
QWidget* snesfilter_settings(unsigned);
|
|
||||||
}
|
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue