mirror of https://github.com/bsnes-emu/bsnes.git
Update to bsnes v059r02 release.
Changelog: - added folder-up button to the file loading window - hid new-folder button except on path selection window - removed "Assign Modifiers as Keys" button; replaced with input.modifierEnable in the configuration file - fixed a Qt signal issue that was causing ROM loading to take an extra second or two longer than necessary - scale 5x setting will now maintain an exact multiple in both width and height for both NTSC and PAL modes - re-added group assignment and unassignment to the input settings window - re-wrote mouse capture code to be more intuitive, now uses buttons to set assignment - re-added input.allowInvalidInput check to stop up+down and left+right key combinations by default [Jonas Quinn] - split "Tools Dialog" menu option into separate items for each tool (Cheat Editor, Cheat Finder, State Manager) - added S-SMP and S-DSP property information readouts to the debugger
This commit is contained in:
parent
97a3a28d86
commit
1d5e09ef07
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
|
@ -0,0 +1,14 @@
|
|||
//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;
|
||||
}
|
|
@ -0,0 +1,9 @@
|
|||
//HDRTV GLSL shader
|
||||
//license: GPL
|
||||
//original version by SimoneT
|
||||
//ruby port by byuu
|
||||
|
||||
void main(void) {
|
||||
gl_Position = ftransform();
|
||||
gl_TexCoord[0] = gl_MultiTexCoord0;
|
||||
}
|
|
@ -0,0 +1,49 @@
|
|||
//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;
|
||||
}
|
|
@ -0,0 +1,26 @@
|
|||
//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;
|
||||
}
|
|
@ -0,0 +1,36 @@
|
|||
//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;
|
||||
}
|
|
@ -0,0 +1,8 @@
|
|||
//Pixellate shader
|
||||
//license: GPL
|
||||
//author: Fes
|
||||
|
||||
void main() {
|
||||
gl_Position = ftransform();
|
||||
gl_TexCoord[0] = gl_MultiTexCoord0;
|
||||
}
|
|
@ -0,0 +1,28 @@
|
|||
//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;
|
||||
}
|
|
@ -0,0 +1,28 @@
|
|||
//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
|
||||
}
|
Binary file not shown.
|
@ -0,0 +1,132 @@
|
|||
//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;
|
||||
}
|
|
@ -0,0 +1,35 @@
|
|||
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
|
@ -0,0 +1,83 @@
|
|||
include nall/Makefile
|
||||
include nall/Makefile-qt
|
||||
|
||||
c := $(compiler)
|
||||
cpp := $(subst cc,++,$(compiler))
|
||||
flags := -O3 -I. -Iobj -fomit-frame-pointer $(qtinc)
|
||||
link :=
|
||||
|
||||
ifeq ($(platform),x)
|
||||
flags := -fPIC $(flags)
|
||||
link += -s
|
||||
else ifeq ($(platform),osx)
|
||||
flags := -fPIC $(flags)
|
||||
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)
|
|
@ -0,0 +1,2 @@
|
|||
@mingw32-make
|
||||
@pause
|
|
@ -0,0 +1 @@
|
|||
@mingw32-make clean
|
|
@ -0,0 +1,32 @@
|
|||
#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;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,5 @@
|
|||
class DirectFilter {
|
||||
public:
|
||||
void size(unsigned&, unsigned&, unsigned, unsigned);
|
||||
void render(uint32_t*, unsigned, const uint16_t*, unsigned, const unsigned*, unsigned, unsigned);
|
||||
} filter_direct;
|
|
@ -0,0 +1,205 @@
|
|||
//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;
|
||||
|
||||
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;
|
||||
|
||||
input++;
|
||||
*out0++ = 0; *out0++ = 0;
|
||||
*out1++ = 0; *out1++ = 0;
|
||||
|
||||
for(unsigned x = 1; x < 256 - 1; x++) {
|
||||
uint16_t A = *(input - prevline - 1);
|
||||
uint16_t B = *(input - prevline + 0);
|
||||
uint16_t C = *(input - prevline + 1);
|
||||
uint16_t D = *(input - 1);
|
||||
uint16_t E = *(input + 0);
|
||||
uint16_t F = *(input + 1);
|
||||
uint16_t G = *(input + nextline - 1);
|
||||
uint16_t H = *(input + nextline + 0);
|
||||
uint16_t I = *(input + 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)];
|
||||
|
||||
input++;
|
||||
out0 += 2;
|
||||
out1 += 2;
|
||||
}
|
||||
|
||||
input++;
|
||||
*out0++ = 0; *out0++ = 0;
|
||||
*out1++ = 0; *out1++ = 0;
|
||||
} else {
|
||||
for(unsigned x = 0; x < 512; x++) {
|
||||
*out0++ = *out1++ = colortable[*input++];
|
||||
}
|
||||
}
|
||||
|
||||
input += pitch - linewidth;
|
||||
out0 += outpitch + outpitch - 512;
|
||||
out1 += outpitch + outpitch - 512;
|
||||
}
|
||||
}
|
||||
|
||||
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,
|
||||
};
|
|
@ -0,0 +1,30 @@
|
|||
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;
|
|
@ -0,0 +1,61 @@
|
|||
#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;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,5 @@
|
|||
class LQ2xFilter {
|
||||
public:
|
||||
void size(unsigned&, unsigned&, unsigned, unsigned);
|
||||
void render(uint32_t*, unsigned, const uint16_t*, unsigned, const unsigned*, unsigned, unsigned);
|
||||
} filter_lq2x;
|
|
@ -0,0 +1,109 @@
|
|||
# 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),)
|
||||
compiler := gcc
|
||||
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,)
|
||||
|
||||
#####
|
||||
# function ifhas(needle, haystack, true, false)
|
||||
#####
|
||||
ifhas = $(if $(findstring $1,$2),$3,$4)
|
||||
|
|
@ -0,0 +1,55 @@
|
|||
# requires nall/Makefile
|
||||
|
||||
# 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 QtCore QtGui`
|
||||
qtlib := `pkg-config --libs QtCore QtGui`
|
||||
else ifeq ($(platform),osx)
|
||||
qtinc := -I/Library/Frameworks/QtCore.framework/Versions/4/Headers
|
||||
qtinc += -I/Library/Frameworks/QtGui.framework/Versions/4/Headers
|
||||
qtinc += -I/Library/Frameworks/QtOpenGL.framework/Versions/4/Headers
|
||||
|
||||
qtlib := -L/Library/Frameworks
|
||||
qtlib += -framework QtCore
|
||||
qtlib += -framework QtGui
|
||||
qtlib += -framework QtOpenGL
|
||||
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 += -I$(qtpath)/include/QtCore
|
||||
qtinc += -I$(qtpath)/include/QtGui
|
||||
|
||||
qtlib := -L$(qtpath)/lib
|
||||
qtlib += -L$(qtpath)/plugins/imageformats
|
||||
|
||||
qtlib += -lmingw32 -lqtmain -lQtGui4 -lcomdlg32 -loleaut32 -limm32 -lwinmm
|
||||
qtlib += -lwinspool -lmsimg32 -lQtCore4 -lole32 -ladvapi32 -lws2_32 -luuid -lgdi32
|
||||
|
||||
# optional image-file support:
|
||||
# qtlib += -lqjpeg -lqmng
|
||||
endif
|
|
@ -0,0 +1,23 @@
|
|||
#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
|
|
@ -0,0 +1,74 @@
|
|||
#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
|
|
@ -0,0 +1,94 @@
|
|||
#ifndef NALL_ARRAY_HPP
|
||||
#define NALL_ARRAY_HPP
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <nall/algorithm.hpp>
|
||||
#include <nall/bit.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() { reset(); }
|
||||
|
||||
array(const array &source) : pool(0) {
|
||||
operator=(source);
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
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];
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
#endif
|
|
@ -0,0 +1,90 @@
|
|||
#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
|
|
@ -0,0 +1,51 @@
|
|||
#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
|
|
@ -0,0 +1,124 @@
|
|||
#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;
|
||||
}
|
||||
}
|
||||
};
|
||||
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
|
|
@ -0,0 +1,66 @@
|
|||
#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
|
|
@ -0,0 +1,30 @@
|
|||
#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
|
|
@ -0,0 +1,73 @@
|
|||
#ifndef NALL_DICTIONARY_HPP
|
||||
#define NALL_DICTIONARY_HPP
|
||||
|
||||
#include <nall/array.hpp>
|
||||
#include <nall/string.hpp>
|
||||
#include <nall/utility.hpp>
|
||||
|
||||
namespace nall {
|
||||
class dictionary : noncopyable {
|
||||
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();
|
||||
}
|
||||
|
||||
protected:
|
||||
lstring index_input;
|
||||
lstring index_output;
|
||||
};
|
||||
}
|
||||
|
||||
#endif
|
|
@ -0,0 +1,88 @@
|
|||
#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)
|
||||
#include <dlfcn.h>
|
||||
#elif defined(PLATFORM_WIN)
|
||||
#include <windows.h>
|
||||
#include <nall/utf8.hpp>
|
||||
#endif
|
||||
|
||||
namespace nall {
|
||||
struct library : noncopyable {
|
||||
bool opened() const { return handle; }
|
||||
bool open(const char*);
|
||||
void* sym(const char*);
|
||||
void close();
|
||||
|
||||
library() : handle(0) {}
|
||||
~library() { close(); }
|
||||
|
||||
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_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
|
|
@ -0,0 +1,38 @@
|
|||
#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
|
|
@ -0,0 +1,256 @@
|
|||
#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 : noncopyable {
|
||||
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();
|
||||
}
|
||||
|
||||
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
|
|
@ -0,0 +1,190 @@
|
|||
#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
|
|
@ -0,0 +1,190 @@
|
|||
#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_call_global;
|
||||
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
|
|
@ -0,0 +1,386 @@
|
|||
#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
|
|
@ -0,0 +1,81 @@
|
|||
#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
|
|
@ -0,0 +1,40 @@
|
|||
#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
|
|
@ -0,0 +1,77 @@
|
|||
#ifndef NALL_PLATFORM_HPP
|
||||
#define NALL_PLATFORM_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 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
|
||||
|
|
@ -0,0 +1,106 @@
|
|||
#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 : noncopyable {
|
||||
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;
|
||||
}
|
||||
|
||||
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
|
|
@ -0,0 +1,45 @@
|
|||
#ifndef NALL_PROPERTY_HPP
|
||||
#define NALL_PROPERTY_HPP
|
||||
|
||||
//nall::property implements a variable container that disallows write access
|
||||
//to non-derived objects. This requires use of property::set(), as C++ lacks
|
||||
//the ability to make this implementation completely transparent.
|
||||
|
||||
namespace nall {
|
||||
class property {
|
||||
public:
|
||||
template<typename T> class property_t;
|
||||
|
||||
protected:
|
||||
template<typename T> T& get(property_t<T>&);
|
||||
template<typename T> property_t<T>& set(property_t<T>&, const T);
|
||||
|
||||
public:
|
||||
template<typename T>
|
||||
class property_t {
|
||||
public:
|
||||
const T& operator()() const { return value; }
|
||||
property_t() : value() {}
|
||||
property_t(const T value_) : value(value_) {}
|
||||
|
||||
protected:
|
||||
T value;
|
||||
operator T&() { return value; }
|
||||
property_t& operator=(const T newValue) { value = newValue; return *this; }
|
||||
friend T& property::get<T>(property_t<T>&);
|
||||
friend property_t<T>& property::set<T>(property_t<T>&, const T);
|
||||
};
|
||||
};
|
||||
|
||||
template<typename T>
|
||||
T& property::get(property::property_t<T> &p) {
|
||||
return p.operator T&();
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
property::property_t<T>& property::set(property::property_t<T> &p, const T value) {
|
||||
return p.operator=(value);
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
|
@ -0,0 +1,80 @@
|
|||
#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
|
|
@ -0,0 +1,126 @@
|
|||
#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]);
|
||||
}
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
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
|
|
@ -0,0 +1,143 @@
|
|||
#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
|
|
@ -0,0 +1,62 @@
|
|||
#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
|
|
@ -0,0 +1,17 @@
|
|||
#ifndef NALL_STATIC_HPP
|
||||
#define NALL_STATIC_HPP
|
||||
|
||||
namespace nall {
|
||||
template<bool condition> struct static_assert;
|
||||
template<> struct static_assert<true> {};
|
||||
|
||||
template<bool condition, typename true_type, typename false_type> struct static_if {
|
||||
typedef true_type type;
|
||||
};
|
||||
|
||||
template<typename true_type, typename false_type> struct static_if<false, true_type, false_type> {
|
||||
typedef false_type type;
|
||||
};
|
||||
}
|
||||
|
||||
#endif
|
|
@ -0,0 +1,44 @@
|
|||
#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 static_assert<sizeof(int8_t) == 1> int8_t_assert;
|
||||
static static_assert<sizeof(int16_t) == 2> int16_t_assert;
|
||||
static static_assert<sizeof(int32_t) == 4> int32_t_assert;
|
||||
static static_assert<sizeof(int64_t) == 8> int64_t_assert;
|
||||
|
||||
static static_assert<sizeof(uint8_t) == 1> uint8_t_assert;
|
||||
static static_assert<sizeof(uint16_t) == 2> uint16_t_assert;
|
||||
static static_assert<sizeof(uint32_t) == 4> uint32_t_assert;
|
||||
static static_assert<sizeof(uint64_t) == 8> uint64_t_assert;
|
||||
}
|
||||
|
||||
#endif
|
|
@ -0,0 +1,18 @@
|
|||
#ifndef NALL_STRING_HPP
|
||||
#define NALL_STRING_HPP
|
||||
|
||||
#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>
|
||||
|
||||
#endif
|
|
@ -0,0 +1,119 @@
|
|||
#ifndef NALL_STRING_BASE_HPP
|
||||
#define NALL_STRING_BASE_HPP
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#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 size_t strhex (char *str, uintmax_t value, size_t length = 0);
|
||||
inline size_t strsigned (char *str, intmax_t value, size_t length = 0);
|
||||
inline size_t strunsigned(char *str, uintmax_t value, size_t length = 0);
|
||||
inline size_t strbin (char *str, uintmax_t value, size_t length = 0);
|
||||
inline size_t strdouble (char *str, double value, size_t length = 0);
|
||||
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& operator=(const 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 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);
|
||||
};
|
||||
};
|
||||
|
||||
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);
|
||||
inline nall::string strhex (uintmax_t value);
|
||||
inline nall::string strsigned (intmax_t value);
|
||||
inline nall::string strunsigned(uintmax_t value);
|
||||
inline nall::string strbin (uintmax_t value);
|
||||
inline nall::string strdouble (double value);
|
||||
|
||||
#endif
|
|
@ -0,0 +1,30 @@
|
|||
#ifndef NALL_STRING_CAST_HPP
|
||||
#define NALL_STRING_CAST_HPP
|
||||
|
||||
namespace nall {
|
||||
//this is needed, as C++98 does not support explicit template specialization inside classes;
|
||||
//redundant memory allocation should hopefully be avoided via compiler optimizations.
|
||||
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
|
|
@ -0,0 +1,100 @@
|
|||
#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
|
|
@ -0,0 +1,285 @@
|
|||
#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;
|
||||
}
|
||||
|
||||
//
|
||||
|
||||
size_t strhex(char *str, uintmax_t value, size_t length /* = 0 */) {
|
||||
if(length == 0) length -= 1U; //"infinite" length
|
||||
size_t initial_length = length;
|
||||
|
||||
//count number of digits in value
|
||||
int digits_integral = 1;
|
||||
uintmax_t digits_integral_ = value;
|
||||
while(digits_integral_ /= 16) digits_integral++;
|
||||
|
||||
int digits = digits_integral;
|
||||
if(!str) return digits + 1; //only computing required length?
|
||||
|
||||
length = nall::min(digits, length - 1);
|
||||
str += length; //seek to end of target string
|
||||
*str = 0; //set null terminator
|
||||
|
||||
while(length--) {
|
||||
uint8_t x = value % 16;
|
||||
value /= 16;
|
||||
*--str = x < 10 ? (x + '0') : (x + 'a' - 10); //iterate backwards to write string
|
||||
}
|
||||
|
||||
return nall::min(initial_length, digits + 1);
|
||||
}
|
||||
|
||||
size_t strsigned(char *str, intmax_t value_, size_t length /* = 0 */) {
|
||||
if(length == 0) length = -1U; //"infinite" length
|
||||
size_t initial_length = length;
|
||||
|
||||
bool negate = value_ < 0;
|
||||
uintmax_t value = value_ >= 0 ? value_ : -value_;
|
||||
|
||||
//count number of digits in value
|
||||
int digits_integral = 1;
|
||||
uintmax_t digits_integral_ = value;
|
||||
while(digits_integral_ /= 10) digits_integral++;
|
||||
|
||||
int digits = (negate ? 1 : 0) + digits_integral;
|
||||
if(!str) return digits + 1; //only computing required length?
|
||||
|
||||
length = nall::min(digits, length - 1);
|
||||
str += length; //seek to end of target string
|
||||
*str = 0; //set null terminator
|
||||
while(length && digits_integral--) {
|
||||
uint8_t x = '0' + (value % 10);
|
||||
value /= 10;
|
||||
*--str = x; //iterate backwards to write string
|
||||
length--;
|
||||
}
|
||||
|
||||
if(length && negate) {
|
||||
*--str = '-';
|
||||
}
|
||||
|
||||
return nall::min(initial_length, digits + 1);
|
||||
}
|
||||
|
||||
size_t strunsigned(char *str, uintmax_t value, size_t length /* = 0 */) {
|
||||
if(length == 0) length = -1U; //"infinite" length
|
||||
size_t initial_length = length;
|
||||
|
||||
//count number of digits in value
|
||||
int digits_integral = 1;
|
||||
uintmax_t digits_integral_ = value;
|
||||
while(digits_integral_ /= 10) digits_integral++;
|
||||
|
||||
int digits = digits_integral;
|
||||
if(!str) return digits_integral + 1; //only computing required length?
|
||||
|
||||
length = nall::min(digits, length - 1);
|
||||
str += length; //seek to end of target string
|
||||
*str = 0; //set null terminator
|
||||
|
||||
while(length--) {
|
||||
uint8_t x = '0' + (value % 10);
|
||||
value /= 10;
|
||||
*--str = x; //iterate backwards to write string
|
||||
}
|
||||
|
||||
return nall::min(initial_length, digits + 1);
|
||||
}
|
||||
|
||||
size_t strbin(char *str, uintmax_t value, size_t length /* = 0 */) {
|
||||
if(length == 0) length = -1U; //"infinite" length
|
||||
size_t initial_length = length;
|
||||
|
||||
//count number of digits in value
|
||||
int digits_integral = 1;
|
||||
uintmax_t digits_integral_ = value;
|
||||
while(digits_integral_ /= 2) digits_integral++;
|
||||
|
||||
int digits = digits_integral;
|
||||
if(!str) return digits + 1; //only computing required length?
|
||||
|
||||
length = nall::min(digits, length - 1);
|
||||
str += length; //seek to end of target string
|
||||
*str = 0; //set null terminator
|
||||
|
||||
while(length--) {
|
||||
uint8_t x = '0' + (value % 2);
|
||||
value /= 2;
|
||||
*--str = x; //iterate backwards to write string
|
||||
}
|
||||
|
||||
return nall::min(initial_length, digits + 1);
|
||||
}
|
||||
|
||||
//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.
|
||||
//
|
||||
//note: length parameter is currently ignored.
|
||||
//it remains for consistency and possible future support.
|
||||
size_t strdouble(char *str, double value, size_t length /* = 0 */) {
|
||||
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;
|
||||
}
|
||||
}
|
||||
|
||||
length = strlen(buffer);
|
||||
if(str) strcpy(str, buffer);
|
||||
return length + 1;
|
||||
}
|
||||
|
||||
#endif
|
|
@ -0,0 +1,109 @@
|
|||
#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::operator=(const string &value) {
|
||||
assign(value);
|
||||
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;
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
#endif
|
|
@ -0,0 +1,48 @@
|
|||
#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;
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
|
@ -0,0 +1,72 @@
|
|||
#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
|
|
@ -0,0 +1,160 @@
|
|||
#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
|
|
@ -0,0 +1,103 @@
|
|||
#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
|
|
@ -0,0 +1,56 @@
|
|||
#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
|
|
@ -0,0 +1,48 @@
|
|||
#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
|
|
@ -0,0 +1,50 @@
|
|||
#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
|
|
@ -0,0 +1,75 @@
|
|||
#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 */
|
||||
|
||||
nall::string strhex(uintmax_t value) {
|
||||
nall::string temp;
|
||||
temp.reserve(strhex(0, value));
|
||||
strhex(temp(), value);
|
||||
return temp;
|
||||
}
|
||||
|
||||
nall::string strsigned(intmax_t value) {
|
||||
nall::string temp;
|
||||
temp.reserve(strsigned(0, value));
|
||||
strsigned(temp(), value);
|
||||
return temp;
|
||||
}
|
||||
|
||||
nall::string strunsigned(uintmax_t value) {
|
||||
nall::string temp;
|
||||
temp.reserve(strunsigned(0, value));
|
||||
strunsigned(temp(), value);
|
||||
return temp;
|
||||
}
|
||||
|
||||
nall::string strbin(uintmax_t value) {
|
||||
nall::string temp;
|
||||
temp.reserve(strbin(0, value));
|
||||
strbin(temp(), value);
|
||||
return temp;
|
||||
}
|
||||
|
||||
nall::string strdouble(double value) {
|
||||
nall::string temp;
|
||||
temp.reserve(strdouble(0, value));
|
||||
strdouble(temp(), value);
|
||||
return temp;
|
||||
}
|
||||
|
||||
#endif
|
|
@ -0,0 +1,97 @@
|
|||
#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
|
|
@ -0,0 +1,190 @@
|
|||
#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
|
|
@ -0,0 +1,72 @@
|
|||
#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
|
|
@ -0,0 +1,36 @@
|
|||
#ifndef NALL_UTILITY_HPP
|
||||
#define NALL_UTILITY_HPP
|
||||
|
||||
namespace nall {
|
||||
template<typename T>
|
||||
inline void swap(T &x, T &y) {
|
||||
T temp(x);
|
||||
x = y;
|
||||
y = temp;
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
struct base_from_member {
|
||||
T value;
|
||||
base_from_member(T value_) : value(value_) {}
|
||||
};
|
||||
|
||||
class noncopyable {
|
||||
protected:
|
||||
noncopyable() {}
|
||||
~noncopyable() {}
|
||||
|
||||
private:
|
||||
noncopyable(const noncopyable&);
|
||||
const noncopyable& operator=(const noncopyable&);
|
||||
};
|
||||
|
||||
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
|
|
@ -0,0 +1,92 @@
|
|||
#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
|
|
@ -0,0 +1,162 @@
|
|||
#ifndef NALL_VECTOR_HPP
|
||||
#define NALL_VECTOR_HPP
|
||||
|
||||
#include <new>
|
||||
#include <nall/algorithm.hpp>
|
||||
#include <nall/bit.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 : noncopyable {
|
||||
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];
|
||||
}
|
||||
|
||||
linear_vector() : pool(0), poolsize(0), objectsize(0) {}
|
||||
~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 : noncopyable {
|
||||
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];
|
||||
}
|
||||
|
||||
pointer_vector() : pool(0), poolsize(0), objectsize(0) {}
|
||||
~pointer_vector() { reset(); }
|
||||
};
|
||||
|
||||
//default vector type
|
||||
template<typename T> class vector : public linear_vector<T> {};
|
||||
}
|
||||
|
||||
#endif
|
|
@ -0,0 +1,396 @@
|
|||
#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);
|
||||
}
|
|
@ -0,0 +1,91 @@
|
|||
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;
|
|
@ -0,0 +1,251 @@
|
|||
/* 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
|
|
@ -0,0 +1,228 @@
|
|||
/* 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
|
|
@ -0,0 +1,26 @@
|
|||
/* 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
|
|
@ -0,0 +1,439 @@
|
|||
/* 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
|
|
@ -0,0 +1,39 @@
|
|||
#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;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,5 @@
|
|||
class Pixellate2xFilter {
|
||||
public:
|
||||
void size(unsigned&, unsigned&, unsigned, unsigned);
|
||||
void render(uint32_t*, unsigned, const uint16_t*, unsigned, const unsigned*, unsigned, unsigned);
|
||||
} filter_pixellate2x;
|
|
@ -0,0 +1,61 @@
|
|||
#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;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,5 @@
|
|||
class Scale2xFilter {
|
||||
public:
|
||||
void size(unsigned&, unsigned&, unsigned, unsigned);
|
||||
void render(uint32_t*, unsigned, const uint16_t*, unsigned, const unsigned*, unsigned, unsigned);
|
||||
} filter_scale2x;
|
|
@ -0,0 +1,84 @@
|
|||
#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();
|
||||
}
|
||||
}
|
|
@ -0,0 +1,16 @@
|
|||
#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);
|
||||
}
|
|
@ -0,0 +1,2 @@
|
|||
rm -r nall
|
||||
cp -r ../nall ./nall
|
Binary file not shown.
|
@ -0,0 +1,77 @@
|
|||
/* 7zAlloc.c -- Allocation functions
|
||||
2008-10-04 : Igor Pavlov : Public domain */
|
||||
|
||||
#include <stdlib.h>
|
||||
#include "7zAlloc.h"
|
||||
|
||||
/* #define _SZ_ALLOC_DEBUG */
|
||||
/* use _SZ_ALLOC_DEBUG to debug alloc/free operations */
|
||||
|
||||
#ifdef _SZ_ALLOC_DEBUG
|
||||
|
||||
#ifdef _WIN32
|
||||
#include <windows.h>
|
||||
#endif
|
||||
|
||||
#include <stdio.h>
|
||||
int g_allocCount = 0;
|
||||
int g_allocCountTemp = 0;
|
||||
|
||||
#endif
|
||||
|
||||
void *SzAlloc(void *p, size_t size)
|
||||
{
|
||||
p = p;
|
||||
if (size == 0)
|
||||
return 0;
|
||||
#ifdef _SZ_ALLOC_DEBUG
|
||||
fprintf(stderr, "\nAlloc %10d bytes; count = %10d", size, g_allocCount);
|
||||
g_allocCount++;
|
||||
#endif
|
||||
return malloc(size);
|
||||
}
|
||||
|
||||
void SzFree(void *p, void *address)
|
||||
{
|
||||
p = p;
|
||||
#ifdef _SZ_ALLOC_DEBUG
|
||||
if (address != 0)
|
||||
{
|
||||
g_allocCount--;
|
||||
fprintf(stderr, "\nFree; count = %10d", g_allocCount);
|
||||
}
|
||||
#endif
|
||||
free(address);
|
||||
}
|
||||
|
||||
void *SzAllocTemp(void *p, size_t size)
|
||||
{
|
||||
p = p;
|
||||
if (size == 0)
|
||||
return 0;
|
||||
#ifdef _SZ_ALLOC_DEBUG
|
||||
fprintf(stderr, "\nAlloc_temp %10d bytes; count = %10d", size, g_allocCountTemp);
|
||||
g_allocCountTemp++;
|
||||
#ifdef _WIN32
|
||||
return HeapAlloc(GetProcessHeap(), 0, size);
|
||||
#endif
|
||||
#endif
|
||||
return malloc(size);
|
||||
}
|
||||
|
||||
void SzFreeTemp(void *p, void *address)
|
||||
{
|
||||
p = p;
|
||||
#ifdef _SZ_ALLOC_DEBUG
|
||||
if (address != 0)
|
||||
{
|
||||
g_allocCountTemp--;
|
||||
fprintf(stderr, "\nFree_temp; count = %10d", g_allocCountTemp);
|
||||
}
|
||||
#ifdef _WIN32
|
||||
HeapFree(GetProcessHeap(), 0, address);
|
||||
return;
|
||||
#endif
|
||||
#endif
|
||||
free(address);
|
||||
}
|
|
@ -0,0 +1,23 @@
|
|||
/* 7zAlloc.h -- Allocation functions
|
||||
2008-10-04 : Igor Pavlov : Public domain */
|
||||
|
||||
#ifndef __7Z_ALLOC_H
|
||||
#define __7Z_ALLOC_H
|
||||
|
||||
#include <stddef.h>
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
void *SzAlloc(void *p, size_t size);
|
||||
void SzFree(void *p, void *address);
|
||||
|
||||
void *SzAllocTemp(void *p, size_t size);
|
||||
void SzFreeTemp(void *p, void *address);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif
|
|
@ -0,0 +1,36 @@
|
|||
/* 7zBuf.c -- Byte Buffer
|
||||
2008-03-28
|
||||
Igor Pavlov
|
||||
Public domain */
|
||||
|
||||
#include "7zBuf.h"
|
||||
|
||||
void Buf_Init(CBuf *p)
|
||||
{
|
||||
p->data = 0;
|
||||
p->size = 0;
|
||||
}
|
||||
|
||||
int Buf_Create(CBuf *p, size_t size, ISzAlloc *alloc)
|
||||
{
|
||||
p->size = 0;
|
||||
if (size == 0)
|
||||
{
|
||||
p->data = 0;
|
||||
return 1;
|
||||
}
|
||||
p->data = (Byte *)alloc->Alloc(alloc, size);
|
||||
if (p->data != 0)
|
||||
{
|
||||
p->size = size;
|
||||
return 1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
void Buf_Free(CBuf *p, ISzAlloc *alloc)
|
||||
{
|
||||
alloc->Free(alloc, p->data);
|
||||
p->data = 0;
|
||||
p->size = 0;
|
||||
}
|
|
@ -0,0 +1,31 @@
|
|||
/* 7zBuf.h -- Byte Buffer
|
||||
2008-10-04 : Igor Pavlov : Public domain */
|
||||
|
||||
#ifndef __7Z_BUF_H
|
||||
#define __7Z_BUF_H
|
||||
|
||||
#include "Types.h"
|
||||
|
||||
typedef struct
|
||||
{
|
||||
Byte *data;
|
||||
size_t size;
|
||||
} CBuf;
|
||||
|
||||
void Buf_Init(CBuf *p);
|
||||
int Buf_Create(CBuf *p, size_t size, ISzAlloc *alloc);
|
||||
void Buf_Free(CBuf *p, ISzAlloc *alloc);
|
||||
|
||||
typedef struct
|
||||
{
|
||||
Byte *data;
|
||||
size_t size;
|
||||
size_t pos;
|
||||
} CDynBuf;
|
||||
|
||||
void DynBuf_Construct(CDynBuf *p);
|
||||
void DynBuf_SeekToBeg(CDynBuf *p);
|
||||
int DynBuf_Write(CDynBuf *p, const Byte *buf, size_t size, ISzAlloc *alloc);
|
||||
void DynBuf_Free(CDynBuf *p, ISzAlloc *alloc);
|
||||
|
||||
#endif
|
|
@ -0,0 +1,194 @@
|
|||
7z ANSI-C Decoder 4.62
|
||||
----------------------
|
||||
|
||||
7z ANSI-C provides 7z/LZMA decoding.
|
||||
7z ANSI-C version is simplified version ported from C++ code.
|
||||
|
||||
LZMA is default and general compression method of 7z format
|
||||
in 7-Zip compression program (www.7-zip.org). LZMA provides high
|
||||
compression ratio and very fast decompression.
|
||||
|
||||
|
||||
LICENSE
|
||||
-------
|
||||
|
||||
7z ANSI-C Decoder is part of the LZMA SDK.
|
||||
LZMA SDK is written and placed in the public domain by Igor Pavlov.
|
||||
|
||||
Files
|
||||
---------------------
|
||||
|
||||
7zDecode.* - Low level 7z decoding
|
||||
7zExtract.* - High level 7z decoding
|
||||
7zHeader.* - .7z format constants
|
||||
7zIn.* - .7z archive opening
|
||||
7zItem.* - .7z structures
|
||||
7zMain.c - Test application
|
||||
|
||||
|
||||
How To Use
|
||||
----------
|
||||
|
||||
You must download 7-Zip program from www.7-zip.org.
|
||||
|
||||
You can create .7z archive with 7z.exe or 7za.exe:
|
||||
|
||||
7za.exe a archive.7z *.htm -r -mx -m0fb=255
|
||||
|
||||
If you have big number of files in archive, and you need fast extracting,
|
||||
you can use partly-solid archives:
|
||||
|
||||
7za.exe a archive.7z *.htm -ms=512K -r -mx -m0fb=255 -m0d=512K
|
||||
|
||||
In that example 7-Zip will use 512KB solid blocks. So it needs to decompress only
|
||||
512KB for extracting one file from such archive.
|
||||
|
||||
|
||||
Limitations of current version of 7z ANSI-C Decoder
|
||||
---------------------------------------------------
|
||||
|
||||
- It reads only "FileName", "Size", "LastWriteTime" and "CRC" information for each file in archive.
|
||||
- It supports only LZMA and Copy (no compression) methods with BCJ or BCJ2 filters.
|
||||
- It converts original UTF-16 Unicode file names to UTF-8 Unicode file names.
|
||||
|
||||
These limitations will be fixed in future versions.
|
||||
|
||||
|
||||
Using 7z ANSI-C Decoder Test application:
|
||||
-----------------------------------------
|
||||
|
||||
Usage: 7zDec <command> <archive_name>
|
||||
|
||||
<Command>:
|
||||
e: Extract files from archive
|
||||
l: List contents of archive
|
||||
t: Test integrity of archive
|
||||
|
||||
Example:
|
||||
|
||||
7zDec l archive.7z
|
||||
|
||||
lists contents of archive.7z
|
||||
|
||||
7zDec e archive.7z
|
||||
|
||||
extracts files from archive.7z to current folder.
|
||||
|
||||
|
||||
How to use .7z Decoder
|
||||
----------------------
|
||||
|
||||
Memory allocation
|
||||
~~~~~~~~~~~~~~~~~
|
||||
|
||||
7z Decoder uses two memory pools:
|
||||
1) Temporary pool
|
||||
2) Main pool
|
||||
Such scheme can allow you to avoid fragmentation of allocated blocks.
|
||||
|
||||
|
||||
Steps for using 7z decoder
|
||||
--------------------------
|
||||
|
||||
Use code at 7zMain.c as example.
|
||||
|
||||
1) Declare variables:
|
||||
inStream /* implements ILookInStream interface */
|
||||
CSzArEx db; /* 7z archive database structure */
|
||||
ISzAlloc allocImp; /* memory functions for main pool */
|
||||
ISzAlloc allocTempImp; /* memory functions for temporary pool */
|
||||
|
||||
2) call CrcGenerateTable(); function to initialize CRC structures.
|
||||
|
||||
3) call SzArEx_Init(&db); function to initialize db structures.
|
||||
|
||||
4) call SzArEx_Open(&db, inStream, &allocMain, &allocTemp) to open archive
|
||||
|
||||
This function opens archive "inStream" and reads headers to "db".
|
||||
All items in "db" will be allocated with "allocMain" functions.
|
||||
SzArEx_Open function allocates and frees temporary structures by "allocTemp" functions.
|
||||
|
||||
5) List items or Extract items
|
||||
|
||||
Listing code:
|
||||
~~~~~~~~~~~~~
|
||||
{
|
||||
UInt32 i;
|
||||
for (i = 0; i < db.db.NumFiles; i++)
|
||||
{
|
||||
CFileItem *f = db.db.Files + i;
|
||||
printf("%10d %s\n", (int)f->Size, f->Name);
|
||||
}
|
||||
}
|
||||
|
||||
Extracting code:
|
||||
~~~~~~~~~~~~~~~~
|
||||
|
||||
SZ_RESULT SzAr_Extract(
|
||||
CArchiveDatabaseEx *db,
|
||||
ILookInStream *inStream,
|
||||
UInt32 fileIndex, /* index of file */
|
||||
UInt32 *blockIndex, /* index of solid block */
|
||||
Byte **outBuffer, /* pointer to pointer to output buffer (allocated with allocMain) */
|
||||
size_t *outBufferSize, /* buffer size for output buffer */
|
||||
size_t *offset, /* offset of stream for required file in *outBuffer */
|
||||
size_t *outSizeProcessed, /* size of file in *outBuffer */
|
||||
ISzAlloc *allocMain,
|
||||
ISzAlloc *allocTemp);
|
||||
|
||||
If you need to decompress more than one file, you can send these values from previous call:
|
||||
blockIndex,
|
||||
outBuffer,
|
||||
outBufferSize,
|
||||
You can consider "outBuffer" as cache of solid block. If your archive is solid,
|
||||
it will increase decompression speed.
|
||||
|
||||
After decompressing you must free "outBuffer":
|
||||
allocImp.Free(outBuffer);
|
||||
|
||||
6) call SzArEx_Free(&db, allocImp.Free) to free allocated items in "db".
|
||||
|
||||
|
||||
|
||||
|
||||
Memory requirements for .7z decoding
|
||||
------------------------------------
|
||||
|
||||
Memory usage for Archive opening:
|
||||
- Temporary pool:
|
||||
- Memory for uncompressed .7z headers
|
||||
- some other temporary blocks
|
||||
- Main pool:
|
||||
- Memory for database:
|
||||
Estimated size of one file structures in solid archive:
|
||||
- Size (4 or 8 Bytes)
|
||||
- CRC32 (4 bytes)
|
||||
- LastWriteTime (8 bytes)
|
||||
- Some file information (4 bytes)
|
||||
- File Name (variable length) + pointer + allocation structures
|
||||
|
||||
Memory usage for archive Decompressing:
|
||||
- Temporary pool:
|
||||
- Memory for LZMA decompressing structures
|
||||
- Main pool:
|
||||
- Memory for decompressed solid block
|
||||
- Memory for temprorary buffers, if BCJ2 fileter is used. Usually these
|
||||
temprorary buffers can be about 15% of solid block size.
|
||||
|
||||
|
||||
7z Decoder doesn't allocate memory for compressed blocks.
|
||||
Instead of this, you must allocate buffer with desired
|
||||
size before calling 7z Decoder. Use 7zMain.c as example.
|
||||
|
||||
|
||||
Defines
|
||||
-------
|
||||
|
||||
_SZ_ALLOC_DEBUG - define it if you want to debug alloc/free operations to stderr.
|
||||
|
||||
|
||||
---
|
||||
|
||||
http://www.7-zip.org
|
||||
http://www.7-zip.org/sdk.html
|
||||
http://www.7-zip.org/support.html
|
|
@ -0,0 +1,35 @@
|
|||
/* 7zCrc.c -- CRC32 calculation
|
||||
2008-08-05
|
||||
Igor Pavlov
|
||||
Public domain */
|
||||
|
||||
#include "7zCrc.h"
|
||||
|
||||
#define kCrcPoly 0xEDB88320
|
||||
UInt32 g_CrcTable[256];
|
||||
|
||||
void MY_FAST_CALL CrcGenerateTable(void)
|
||||
{
|
||||
UInt32 i;
|
||||
for (i = 0; i < 256; i++)
|
||||
{
|
||||
UInt32 r = i;
|
||||
int j;
|
||||
for (j = 0; j < 8; j++)
|
||||
r = (r >> 1) ^ (kCrcPoly & ~((r & 1) - 1));
|
||||
g_CrcTable[i] = r;
|
||||
}
|
||||
}
|
||||
|
||||
UInt32 MY_FAST_CALL CrcUpdate(UInt32 v, const void *data, size_t size)
|
||||
{
|
||||
const Byte *p = (const Byte *)data;
|
||||
for (; size > 0 ; size--, p++)
|
||||
v = CRC_UPDATE_BYTE(v, *p);
|
||||
return v;
|
||||
}
|
||||
|
||||
UInt32 MY_FAST_CALL CrcCalc(const void *data, size_t size)
|
||||
{
|
||||
return CrcUpdate(CRC_INIT_VAL, data, size) ^ 0xFFFFFFFF;
|
||||
}
|
|
@ -0,0 +1,32 @@
|
|||
/* 7zCrc.h -- CRC32 calculation
|
||||
2008-03-13
|
||||
Igor Pavlov
|
||||
Public domain */
|
||||
|
||||
#ifndef __7Z_CRC_H
|
||||
#define __7Z_CRC_H
|
||||
|
||||
#include <stddef.h>
|
||||
|
||||
#include "Types.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
extern UInt32 g_CrcTable[];
|
||||
|
||||
void MY_FAST_CALL CrcGenerateTable(void);
|
||||
|
||||
#define CRC_INIT_VAL 0xFFFFFFFF
|
||||
#define CRC_GET_DIGEST(crc) ((crc) ^ 0xFFFFFFFF)
|
||||
#define CRC_UPDATE_BYTE(crc, b) (g_CrcTable[((crc) ^ (b)) & 0xFF] ^ ((crc) >> 8))
|
||||
|
||||
UInt32 MY_FAST_CALL CrcUpdate(UInt32 crc, const void *data, size_t size);
|
||||
UInt32 MY_FAST_CALL CrcCalc(const void *data, size_t size);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif
|
|
@ -0,0 +1,257 @@
|
|||
/* 7zDecode.c -- Decoding from 7z folder
|
||||
2008-11-23 : Igor Pavlov : Public domain */
|
||||
|
||||
#include <string.h>
|
||||
|
||||
#include "Bcj2.h"
|
||||
#include "Bra.h"
|
||||
#include "LzmaDec.h"
|
||||
#include "7zDecode.h"
|
||||
|
||||
#define k_Copy 0
|
||||
#define k_LZMA 0x30101
|
||||
#define k_BCJ 0x03030103
|
||||
#define k_BCJ2 0x0303011B
|
||||
|
||||
static SRes SzDecodeLzma(CSzCoderInfo *coder, UInt64 inSize, ILookInStream *inStream,
|
||||
Byte *outBuffer, SizeT outSize, ISzAlloc *allocMain)
|
||||
{
|
||||
CLzmaDec state;
|
||||
SRes res = SZ_OK;
|
||||
|
||||
LzmaDec_Construct(&state);
|
||||
RINOK(LzmaDec_AllocateProbs(&state, coder->Props.data, (unsigned)coder->Props.size, allocMain));
|
||||
state.dic = outBuffer;
|
||||
state.dicBufSize = outSize;
|
||||
LzmaDec_Init(&state);
|
||||
|
||||
for (;;)
|
||||
{
|
||||
Byte *inBuf = NULL;
|
||||
size_t lookahead = (1 << 18);
|
||||
if (lookahead > inSize)
|
||||
lookahead = (size_t)inSize;
|
||||
res = inStream->Look((void *)inStream, (void **)&inBuf, &lookahead);
|
||||
if (res != SZ_OK)
|
||||
break;
|
||||
|
||||
{
|
||||
SizeT inProcessed = (SizeT)lookahead, dicPos = state.dicPos;
|
||||
ELzmaStatus status;
|
||||
res = LzmaDec_DecodeToDic(&state, outSize, inBuf, &inProcessed, LZMA_FINISH_END, &status);
|
||||
lookahead -= inProcessed;
|
||||
inSize -= inProcessed;
|
||||
if (res != SZ_OK)
|
||||
break;
|
||||
if (state.dicPos == state.dicBufSize || (inProcessed == 0 && dicPos == state.dicPos))
|
||||
{
|
||||
if (state.dicBufSize != outSize || lookahead != 0 ||
|
||||
(status != LZMA_STATUS_FINISHED_WITH_MARK &&
|
||||
status != LZMA_STATUS_MAYBE_FINISHED_WITHOUT_MARK))
|
||||
res = SZ_ERROR_DATA;
|
||||
break;
|
||||
}
|
||||
res = inStream->Skip((void *)inStream, inProcessed);
|
||||
if (res != SZ_OK)
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
LzmaDec_FreeProbs(&state, allocMain);
|
||||
return res;
|
||||
}
|
||||
|
||||
static SRes SzDecodeCopy(UInt64 inSize, ILookInStream *inStream, Byte *outBuffer)
|
||||
{
|
||||
while (inSize > 0)
|
||||
{
|
||||
void *inBuf;
|
||||
size_t curSize = (1 << 18);
|
||||
if (curSize > inSize)
|
||||
curSize = (size_t)inSize;
|
||||
RINOK(inStream->Look((void *)inStream, (void **)&inBuf, &curSize));
|
||||
if (curSize == 0)
|
||||
return SZ_ERROR_INPUT_EOF;
|
||||
memcpy(outBuffer, inBuf, curSize);
|
||||
outBuffer += curSize;
|
||||
inSize -= curSize;
|
||||
RINOK(inStream->Skip((void *)inStream, curSize));
|
||||
}
|
||||
return SZ_OK;
|
||||
}
|
||||
|
||||
#define IS_UNSUPPORTED_METHOD(m) ((m) != k_Copy && (m) != k_LZMA)
|
||||
#define IS_UNSUPPORTED_CODER(c) (IS_UNSUPPORTED_METHOD(c.MethodID) || c.NumInStreams != 1 || c.NumOutStreams != 1)
|
||||
#define IS_NO_BCJ(c) (c.MethodID != k_BCJ || c.NumInStreams != 1 || c.NumOutStreams != 1)
|
||||
#define IS_NO_BCJ2(c) (c.MethodID != k_BCJ2 || c.NumInStreams != 4 || c.NumOutStreams != 1)
|
||||
|
||||
static
|
||||
SRes CheckSupportedFolder(const CSzFolder *f)
|
||||
{
|
||||
if (f->NumCoders < 1 || f->NumCoders > 4)
|
||||
return SZ_ERROR_UNSUPPORTED;
|
||||
if (IS_UNSUPPORTED_CODER(f->Coders[0]))
|
||||
return SZ_ERROR_UNSUPPORTED;
|
||||
if (f->NumCoders == 1)
|
||||
{
|
||||
if (f->NumPackStreams != 1 || f->PackStreams[0] != 0 || f->NumBindPairs != 0)
|
||||
return SZ_ERROR_UNSUPPORTED;
|
||||
return SZ_OK;
|
||||
}
|
||||
if (f->NumCoders == 2)
|
||||
{
|
||||
if (IS_NO_BCJ(f->Coders[1]) ||
|
||||
f->NumPackStreams != 1 || f->PackStreams[0] != 0 ||
|
||||
f->NumBindPairs != 1 ||
|
||||
f->BindPairs[0].InIndex != 1 || f->BindPairs[0].OutIndex != 0)
|
||||
return SZ_ERROR_UNSUPPORTED;
|
||||
return SZ_OK;
|
||||
}
|
||||
if (f->NumCoders == 4)
|
||||
{
|
||||
if (IS_UNSUPPORTED_CODER(f->Coders[1]) ||
|
||||
IS_UNSUPPORTED_CODER(f->Coders[2]) ||
|
||||
IS_NO_BCJ2(f->Coders[3]))
|
||||
return SZ_ERROR_UNSUPPORTED;
|
||||
if (f->NumPackStreams != 4 ||
|
||||
f->PackStreams[0] != 2 ||
|
||||
f->PackStreams[1] != 6 ||
|
||||
f->PackStreams[2] != 1 ||
|
||||
f->PackStreams[3] != 0 ||
|
||||
f->NumBindPairs != 3 ||
|
||||
f->BindPairs[0].InIndex != 5 || f->BindPairs[0].OutIndex != 0 ||
|
||||
f->BindPairs[1].InIndex != 4 || f->BindPairs[1].OutIndex != 1 ||
|
||||
f->BindPairs[2].InIndex != 3 || f->BindPairs[2].OutIndex != 2)
|
||||
return SZ_ERROR_UNSUPPORTED;
|
||||
return SZ_OK;
|
||||
}
|
||||
return SZ_ERROR_UNSUPPORTED;
|
||||
}
|
||||
|
||||
static
|
||||
UInt64 GetSum(const UInt64 *values, UInt32 index)
|
||||
{
|
||||
UInt64 sum = 0;
|
||||
UInt32 i;
|
||||
for (i = 0; i < index; i++)
|
||||
sum += values[i];
|
||||
return sum;
|
||||
}
|
||||
|
||||
static
|
||||
SRes SzDecode2(const UInt64 *packSizes, const CSzFolder *folder,
|
||||
ILookInStream *inStream, UInt64 startPos,
|
||||
Byte *outBuffer, SizeT outSize, ISzAlloc *allocMain,
|
||||
Byte *tempBuf[])
|
||||
{
|
||||
UInt32 ci;
|
||||
SizeT tempSizes[3] = { 0, 0, 0};
|
||||
SizeT tempSize3 = 0;
|
||||
Byte *tempBuf3 = 0;
|
||||
|
||||
RINOK(CheckSupportedFolder(folder));
|
||||
|
||||
for (ci = 0; ci < folder->NumCoders; ci++)
|
||||
{
|
||||
CSzCoderInfo *coder = &folder->Coders[ci];
|
||||
|
||||
if (coder->MethodID == k_Copy || coder->MethodID == k_LZMA)
|
||||
{
|
||||
UInt32 si = 0;
|
||||
UInt64 offset;
|
||||
UInt64 inSize;
|
||||
Byte *outBufCur = outBuffer;
|
||||
SizeT outSizeCur = outSize;
|
||||
if (folder->NumCoders == 4)
|
||||
{
|
||||
UInt32 indices[] = { 3, 2, 0 };
|
||||
UInt64 unpackSize = folder->UnpackSizes[ci];
|
||||
si = indices[ci];
|
||||
if (ci < 2)
|
||||
{
|
||||
Byte *temp;
|
||||
outSizeCur = (SizeT)unpackSize;
|
||||
if (outSizeCur != unpackSize)
|
||||
return SZ_ERROR_MEM;
|
||||
temp = (Byte *)IAlloc_Alloc(allocMain, outSizeCur);
|
||||
if (temp == 0 && outSizeCur != 0)
|
||||
return SZ_ERROR_MEM;
|
||||
outBufCur = tempBuf[1 - ci] = temp;
|
||||
tempSizes[1 - ci] = outSizeCur;
|
||||
}
|
||||
else if (ci == 2)
|
||||
{
|
||||
if (unpackSize > outSize) /* check it */
|
||||
return SZ_ERROR_PARAM;
|
||||
tempBuf3 = outBufCur = outBuffer + (outSize - (size_t)unpackSize);
|
||||
tempSize3 = outSizeCur = (SizeT)unpackSize;
|
||||
}
|
||||
else
|
||||
return SZ_ERROR_UNSUPPORTED;
|
||||
}
|
||||
offset = GetSum(packSizes, si);
|
||||
inSize = packSizes[si];
|
||||
RINOK(LookInStream_SeekTo(inStream, startPos + offset));
|
||||
|
||||
if (coder->MethodID == k_Copy)
|
||||
{
|
||||
if (inSize != outSizeCur) /* check it */
|
||||
return SZ_ERROR_DATA;
|
||||
RINOK(SzDecodeCopy(inSize, inStream, outBufCur));
|
||||
}
|
||||
else
|
||||
{
|
||||
RINOK(SzDecodeLzma(coder, inSize, inStream, outBufCur, outSizeCur, allocMain));
|
||||
}
|
||||
}
|
||||
else if (coder->MethodID == k_BCJ)
|
||||
{
|
||||
UInt32 state;
|
||||
if (ci != 1)
|
||||
return SZ_ERROR_UNSUPPORTED;
|
||||
x86_Convert_Init(state);
|
||||
x86_Convert(outBuffer, outSize, 0, &state, 0);
|
||||
}
|
||||
else if (coder->MethodID == k_BCJ2)
|
||||
{
|
||||
UInt64 offset = GetSum(packSizes, 1);
|
||||
UInt64 s3Size = packSizes[1];
|
||||
SRes res;
|
||||
if (ci != 3)
|
||||
return SZ_ERROR_UNSUPPORTED;
|
||||
RINOK(LookInStream_SeekTo(inStream, startPos + offset));
|
||||
tempSizes[2] = (SizeT)s3Size;
|
||||
if (tempSizes[2] != s3Size)
|
||||
return SZ_ERROR_MEM;
|
||||
tempBuf[2] = (Byte *)IAlloc_Alloc(allocMain, tempSizes[2]);
|
||||
if (tempBuf[2] == 0 && tempSizes[2] != 0)
|
||||
return SZ_ERROR_MEM;
|
||||
res = SzDecodeCopy(s3Size, inStream, tempBuf[2]);
|
||||
RINOK(res)
|
||||
|
||||
res = Bcj2_Decode(
|
||||
tempBuf3, tempSize3,
|
||||
tempBuf[0], tempSizes[0],
|
||||
tempBuf[1], tempSizes[1],
|
||||
tempBuf[2], tempSizes[2],
|
||||
outBuffer, outSize);
|
||||
RINOK(res)
|
||||
}
|
||||
else
|
||||
return SZ_ERROR_UNSUPPORTED;
|
||||
}
|
||||
return SZ_OK;
|
||||
}
|
||||
|
||||
SRes SzDecode(const UInt64 *packSizes, const CSzFolder *folder,
|
||||
ILookInStream *inStream, UInt64 startPos,
|
||||
Byte *outBuffer, size_t outSize, ISzAlloc *allocMain)
|
||||
{
|
||||
Byte *tempBuf[3] = { 0, 0, 0};
|
||||
int i;
|
||||
SRes res = SzDecode2(packSizes, folder, inStream, startPos,
|
||||
outBuffer, (SizeT)outSize, allocMain, tempBuf);
|
||||
for (i = 0; i < 3; i++)
|
||||
IAlloc_Free(allocMain, tempBuf[i]);
|
||||
return res;
|
||||
}
|
|
@ -0,0 +1,13 @@
|
|||
/* 7zDecode.h -- Decoding from 7z folder
|
||||
2008-11-23 : Igor Pavlov : Public domain */
|
||||
|
||||
#ifndef __7Z_DECODE_H
|
||||
#define __7Z_DECODE_H
|
||||
|
||||
#include "7zItem.h"
|
||||
|
||||
SRes SzDecode(const UInt64 *packSizes, const CSzFolder *folder,
|
||||
ILookInStream *stream, UInt64 startPos,
|
||||
Byte *outBuffer, size_t outSize, ISzAlloc *allocMain);
|
||||
|
||||
#endif
|
|
@ -0,0 +1,93 @@
|
|||
/* 7zExtract.c -- Extracting from 7z archive
|
||||
2008-11-23 : Igor Pavlov : Public domain */
|
||||
|
||||
#include "7zCrc.h"
|
||||
#include "7zDecode.h"
|
||||
#include "7zExtract.h"
|
||||
|
||||
SRes SzAr_Extract(
|
||||
const CSzArEx *p,
|
||||
ILookInStream *inStream,
|
||||
UInt32 fileIndex,
|
||||
UInt32 *blockIndex,
|
||||
Byte **outBuffer,
|
||||
size_t *outBufferSize,
|
||||
size_t *offset,
|
||||
size_t *outSizeProcessed,
|
||||
ISzAlloc *allocMain,
|
||||
ISzAlloc *allocTemp)
|
||||
{
|
||||
UInt32 folderIndex = p->FileIndexToFolderIndexMap[fileIndex];
|
||||
SRes res = SZ_OK;
|
||||
*offset = 0;
|
||||
*outSizeProcessed = 0;
|
||||
if (folderIndex == (UInt32)-1)
|
||||
{
|
||||
IAlloc_Free(allocMain, *outBuffer);
|
||||
*blockIndex = folderIndex;
|
||||
*outBuffer = 0;
|
||||
*outBufferSize = 0;
|
||||
return SZ_OK;
|
||||
}
|
||||
|
||||
if (*outBuffer == 0 || *blockIndex != folderIndex)
|
||||
{
|
||||
CSzFolder *folder = p->db.Folders + folderIndex;
|
||||
UInt64 unpackSizeSpec = SzFolder_GetUnpackSize(folder);
|
||||
size_t unpackSize = (size_t)unpackSizeSpec;
|
||||
UInt64 startOffset = SzArEx_GetFolderStreamPos(p, folderIndex, 0);
|
||||
|
||||
if (unpackSize != unpackSizeSpec)
|
||||
return SZ_ERROR_MEM;
|
||||
*blockIndex = folderIndex;
|
||||
IAlloc_Free(allocMain, *outBuffer);
|
||||
*outBuffer = 0;
|
||||
|
||||
RINOK(LookInStream_SeekTo(inStream, startOffset));
|
||||
|
||||
if (res == SZ_OK)
|
||||
{
|
||||
*outBufferSize = unpackSize;
|
||||
if (unpackSize != 0)
|
||||
{
|
||||
*outBuffer = (Byte *)IAlloc_Alloc(allocMain, unpackSize);
|
||||
if (*outBuffer == 0)
|
||||
res = SZ_ERROR_MEM;
|
||||
}
|
||||
if (res == SZ_OK)
|
||||
{
|
||||
res = SzDecode(p->db.PackSizes +
|
||||
p->FolderStartPackStreamIndex[folderIndex], folder,
|
||||
inStream, startOffset,
|
||||
*outBuffer, unpackSize, allocTemp);
|
||||
if (res == SZ_OK)
|
||||
{
|
||||
if (folder->UnpackCRCDefined)
|
||||
{
|
||||
if (CrcCalc(*outBuffer, unpackSize) != folder->UnpackCRC)
|
||||
res = SZ_ERROR_CRC;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
if (res == SZ_OK)
|
||||
{
|
||||
UInt32 i;
|
||||
CSzFileItem *fileItem = p->db.Files + fileIndex;
|
||||
*offset = 0;
|
||||
for (i = p->FolderStartFileIndex[folderIndex]; i < fileIndex; i++)
|
||||
*offset += (UInt32)p->db.Files[i].Size;
|
||||
*outSizeProcessed = (size_t)fileItem->Size;
|
||||
if (*offset + *outSizeProcessed > *outBufferSize)
|
||||
return SZ_ERROR_FAIL;
|
||||
{
|
||||
if (fileItem->FileCRCDefined)
|
||||
{
|
||||
if (CrcCalc(*outBuffer + *offset, *outSizeProcessed) != fileItem->FileCRC)
|
||||
res = SZ_ERROR_CRC;
|
||||
}
|
||||
}
|
||||
}
|
||||
return res;
|
||||
}
|
|
@ -0,0 +1,49 @@
|
|||
/* 7zExtract.h -- Extracting from 7z archive
|
||||
2008-11-23 : Igor Pavlov : Public domain */
|
||||
|
||||
#ifndef __7Z_EXTRACT_H
|
||||
#define __7Z_EXTRACT_H
|
||||
|
||||
#include "7zIn.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/*
|
||||
SzExtract extracts file from archive
|
||||
|
||||
*outBuffer must be 0 before first call for each new archive.
|
||||
|
||||
Extracting cache:
|
||||
If you need to decompress more than one file, you can send
|
||||
these values from previous call:
|
||||
*blockIndex,
|
||||
*outBuffer,
|
||||
*outBufferSize
|
||||
You can consider "*outBuffer" as cache of solid block. If your archive is solid,
|
||||
it will increase decompression speed.
|
||||
|
||||
If you use external function, you can declare these 3 cache variables
|
||||
(blockIndex, outBuffer, outBufferSize) as static in that external function.
|
||||
|
||||
Free *outBuffer and set *outBuffer to 0, if you want to flush cache.
|
||||
*/
|
||||
|
||||
SRes SzAr_Extract(
|
||||
const CSzArEx *db,
|
||||
ILookInStream *inStream,
|
||||
UInt32 fileIndex, /* index of file */
|
||||
UInt32 *blockIndex, /* index of solid block */
|
||||
Byte **outBuffer, /* pointer to pointer to output buffer (allocated with allocMain) */
|
||||
size_t *outBufferSize, /* buffer size for output buffer */
|
||||
size_t *offset, /* offset of stream for required file in *outBuffer */
|
||||
size_t *outSizeProcessed, /* size of file in *outBuffer */
|
||||
ISzAlloc *allocMain,
|
||||
ISzAlloc *allocTemp);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif
|
|
@ -0,0 +1,6 @@
|
|||
/* 7zHeader.c -- 7z Headers
|
||||
2008-10-04 : Igor Pavlov : Public domain */
|
||||
|
||||
#include "7zHeader.h"
|
||||
|
||||
Byte k7zSignature[k7zSignatureSize] = {'7', 'z', 0xBC, 0xAF, 0x27, 0x1C};
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue