mirror of
https://github.com/Alcaro/Flips.git
synced 2026-04-21 09:37:34 -05:00
Implement #5
This commit is contained in:
parent
9a062dda0f
commit
d2a8b2e701
8
.gitignore
vendored
Normal file
8
.gitignore
vendored
Normal file
|
|
@ -0,0 +1,8 @@
|
|||
obj/
|
||||
flips
|
||||
flips.exe
|
||||
|
||||
*.obj
|
||||
flips.res
|
||||
*.pgc
|
||||
*.pgd
|
||||
86
.vscode/c_cpp_properties.json
vendored
Normal file
86
.vscode/c_cpp_properties.json
vendored
Normal file
|
|
@ -0,0 +1,86 @@
|
|||
{
|
||||
"configurations": [
|
||||
{
|
||||
"name": "Mac",
|
||||
"includePath": [
|
||||
"/usr/include",
|
||||
"/usr/local/include",
|
||||
"${workspaceRoot}"
|
||||
],
|
||||
"defines": [],
|
||||
"intelliSenseMode": "clang-x64",
|
||||
"browse": {
|
||||
"path": [
|
||||
"/usr/include",
|
||||
"/usr/local/include",
|
||||
"${workspaceRoot}"
|
||||
],
|
||||
"limitSymbolsToIncludedHeaders": true,
|
||||
"databaseFilename": ""
|
||||
},
|
||||
"macFrameworkPath": [
|
||||
"/System/Library/Frameworks",
|
||||
"/Library/Frameworks"
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "Linux",
|
||||
"includePath": [
|
||||
"/usr/include/c++/7",
|
||||
"/usr/include/x86_64-linux-gnu/c++/7",
|
||||
"/usr/include/c++/7/backward",
|
||||
"/usr/lib/gcc/x86_64-linux-gnu/7/include",
|
||||
"/usr/local/include",
|
||||
"/usr/lib/gcc/x86_64-linux-gnu/7/include-fixed",
|
||||
"/usr/include/x86_64-linux-gnu",
|
||||
"/usr/include",
|
||||
"${workspaceRoot}",
|
||||
"/usr/include/glib-2.0",
|
||||
"/usr/include/gtk-3.0",
|
||||
"/usr/include/pango-1.0",
|
||||
"/usr/include/cairo",
|
||||
"/usr/include/gdk-pixbuf-2.0",
|
||||
"/usr/include/atk-1.0"
|
||||
],
|
||||
"defines": [],
|
||||
"intelliSenseMode": "clang-x64",
|
||||
"browse": {
|
||||
"path": [
|
||||
"/usr/include/c++/7",
|
||||
"/usr/include/x86_64-linux-gnu/c++/7",
|
||||
"/usr/include/c++/7/backward",
|
||||
"/usr/lib/gcc/x86_64-linux-gnu/7/include",
|
||||
"/usr/local/include",
|
||||
"/usr/lib/gcc/x86_64-linux-gnu/7/include-fixed",
|
||||
"/usr/include/x86_64-linux-gnu",
|
||||
"/usr/include",
|
||||
"${workspaceRoot}"
|
||||
],
|
||||
"limitSymbolsToIncludedHeaders": true,
|
||||
"databaseFilename": ""
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "Win32",
|
||||
"includePath": [
|
||||
"C:/Program Files (x86)/Microsoft Visual Studio 14.0/VC/include",
|
||||
"${workspaceRoot}"
|
||||
],
|
||||
"defines": [
|
||||
"_DEBUG",
|
||||
"UNICODE",
|
||||
"_UNICODE"
|
||||
],
|
||||
"intelliSenseMode": "msvc-x64",
|
||||
"browse": {
|
||||
"path": [
|
||||
"C:/Program Files (x86)/Microsoft Visual Studio 14.0/VC/include/*",
|
||||
"${workspaceRoot}"
|
||||
],
|
||||
"limitSymbolsToIncludedHeaders": true,
|
||||
"databaseFilename": ""
|
||||
}
|
||||
}
|
||||
],
|
||||
"version": 3
|
||||
}
|
||||
28
.vscode/launch.json
vendored
Normal file
28
.vscode/launch.json
vendored
Normal file
|
|
@ -0,0 +1,28 @@
|
|||
{
|
||||
// Use IntelliSense to learn about possible attributes.
|
||||
// Hover to view descriptions of existing attributes.
|
||||
// For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387
|
||||
"version": "0.2.0",
|
||||
"configurations": [
|
||||
{
|
||||
"name": "(gdb) Launch",
|
||||
"type": "cppdbg",
|
||||
"request": "launch",
|
||||
"program": "${workspaceFolder}/bin/Debug/flips",
|
||||
"args": [],
|
||||
"stopAtEntry": false,
|
||||
"cwd": "${workspaceFolder}",
|
||||
"environment": [],
|
||||
"externalConsole": true,
|
||||
"MIMode": "gdb",
|
||||
"setupCommands": [
|
||||
{
|
||||
"description": "Enable pretty-printing for gdb",
|
||||
"text": "-enable-pretty-printing",
|
||||
"ignoreFailures": true
|
||||
}
|
||||
],
|
||||
"preLaunchTask": "Build Debug"
|
||||
}
|
||||
]
|
||||
}
|
||||
3
.vscode/settings.json
vendored
Normal file
3
.vscode/settings.json
vendored
Normal file
|
|
@ -0,0 +1,3 @@
|
|||
{
|
||||
"C_Cpp.intelliSenseEngineFallback": "Enabled"
|
||||
}
|
||||
27
.vscode/tasks.json
vendored
Normal file
27
.vscode/tasks.json
vendored
Normal file
|
|
@ -0,0 +1,27 @@
|
|||
{
|
||||
// See https://go.microsoft.com/fwlink/?LinkId=733558
|
||||
// for the documentation about the tasks.json format
|
||||
"version": "2.0.0",
|
||||
"tasks": [
|
||||
{
|
||||
"label": "Build Release",
|
||||
"type": "shell",
|
||||
"command": "./make.sh",
|
||||
"group": {
|
||||
"kind": "build",
|
||||
"isDefault": true
|
||||
},
|
||||
"problemMatcher": [
|
||||
"$gcc"
|
||||
]
|
||||
},
|
||||
{
|
||||
"label": "Build Debug",
|
||||
"type": "shell",
|
||||
"command": "make CFLAGS='-O0 -g'",
|
||||
"problemMatcher": [
|
||||
"$gcc"
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
8
Makefile
8
Makefile
|
|
@ -56,11 +56,13 @@ ifeq ($(TARGET),gtk)
|
|||
endif
|
||||
|
||||
all: $(FNAME_$(TARGET))
|
||||
obj:
|
||||
mkdir obj
|
||||
|
||||
ifeq ($(TARGET),windows)
|
||||
XFILES += rc.o
|
||||
rc.o:
|
||||
windres flips.rc rc.o
|
||||
XFILES += obj/rc.o
|
||||
obj/rc.o: flips.rc | obj
|
||||
windres flips.rc obj/rc.o
|
||||
endif
|
||||
|
||||
MOREFLAGS := $(CFLAGS_$(TARGET))
|
||||
|
|
|
|||
366
libips.cpp
366
libips.cpp
|
|
@ -4,21 +4,21 @@
|
|||
//Licence: GPL v3.0 or higher
|
||||
|
||||
#ifndef __cplusplus
|
||||
#include <stdbool.h>//bool; if this does not exist, remove it and uncomment the following three lines.
|
||||
#include <stdbool.h> //bool; if this does not exist, remove it and uncomment the following three lines.
|
||||
//#define bool int
|
||||
//#define true 1
|
||||
//#define false 0
|
||||
#endif
|
||||
#include <stdlib.h>//malloc, realloc, free
|
||||
#include <string.h>//memcpy, memset
|
||||
#include <stdlib.h> //malloc, realloc, free
|
||||
#include <string.h> //memcpy, memset
|
||||
|
||||
#include "libips.h"
|
||||
|
||||
typedef unsigned char byte;
|
||||
|
||||
#define min(a,b) ((a)<(b)?(a):(b))
|
||||
#define max(a,b) ((a)>(b)?(a):(b))
|
||||
#define clamp(a,b,c) max(a,min(b,c))
|
||||
#define min(a, b) ((a)<(b) ? (a) : (b))
|
||||
#define max(a, b) ((a)>(b) ? (a) : (b))
|
||||
#define clamp(a, b, c) max(a, min(b, c))
|
||||
|
||||
struct ipsstudy {
|
||||
enum ipserror error;
|
||||
|
|
@ -29,120 +29,128 @@ struct ipsstudy {
|
|||
|
||||
enum ipserror ips_study(struct mem patch, struct ipsstudy * study)
|
||||
{
|
||||
study->error=ips_invalid;
|
||||
if (patch.len<8) return ips_invalid;
|
||||
const unsigned char * patchat=patch.ptr;
|
||||
const unsigned char * patchend=patchat+patch.len;
|
||||
#define read8() ((patchat<patchend)?(*patchat++):0)
|
||||
#define read16() ((patchat+1<patchend)?(patchat+=2,((patchat[-2]<<8)|patchat[-1])):0)
|
||||
#define read24() ((patchat+2<patchend)?(patchat+=3,((patchat[-3]<<16)|(patchat[-2]<<8)|patchat[-1])):0)
|
||||
if (read8()!='P' ||
|
||||
read8()!='A' ||
|
||||
read8()!='T' ||
|
||||
read8()!='C' ||
|
||||
read8()!='H')
|
||||
study->error = ips_invalid;
|
||||
if (patch.len < 8) return ips_invalid;
|
||||
const unsigned char * patchat = patch.ptr;
|
||||
const unsigned char * patchend = patchat + patch.len;
|
||||
#define read8() ((patchat < patchend) ? (*patchat++) : 0)
|
||||
#define read16() ((patchat+1 < patchend) ? (patchat += 2,( (patchat[-2] << 8) | patchat[-1])) : 0)
|
||||
#define read24() ((patchat+2 < patchend) ? (patchat += 3,((patchat[-3] << 16) | (patchat[-2] << 8) | patchat[-1])) : 0)
|
||||
if (read8() != 'P' ||
|
||||
read8() != 'A' ||
|
||||
read8() != 'T' ||
|
||||
read8() != 'C' ||
|
||||
read8() != 'H')
|
||||
{
|
||||
return ips_invalid;
|
||||
}
|
||||
unsigned int offset=read24();
|
||||
unsigned int outlen=0;
|
||||
unsigned int thisout=0;
|
||||
unsigned int lastoffset=0;
|
||||
bool w_scrambled=false;
|
||||
while (offset!=0x454F46)//454F46=EOF
|
||||
|
||||
unsigned int offset = read24();
|
||||
unsigned int outlen = 0;
|
||||
unsigned int thisout = 0;
|
||||
unsigned int lastoffset = 0;
|
||||
bool w_scrambled = false;
|
||||
while (offset != 0x454F46) // 454F46=EOF
|
||||
{
|
||||
unsigned int size=read16();
|
||||
if (size==0)
|
||||
unsigned int size = read16();
|
||||
if (size == 0)
|
||||
{
|
||||
size=read16();
|
||||
if (!size) w_scrambled=true;
|
||||
thisout=offset+size;
|
||||
size = read16();
|
||||
if (!size) return ips_invalid; // don't know what this means (65536 bytes? something else?),
|
||||
thisout = offset + size; // better reject it until I find out
|
||||
read8();
|
||||
}
|
||||
else
|
||||
{
|
||||
thisout=offset+size;
|
||||
patchat+=size;
|
||||
thisout = offset + size;
|
||||
patchat += size;
|
||||
}
|
||||
if (offset<lastoffset) w_scrambled=true;
|
||||
lastoffset=offset;
|
||||
if (thisout>outlen) outlen=thisout;
|
||||
if (patchat>=patchend) return ips_invalid;
|
||||
offset=read24();
|
||||
if (offset < lastoffset) w_scrambled = true;
|
||||
lastoffset = offset;
|
||||
if (thisout > outlen) outlen = thisout;
|
||||
if (patchat >= patchend) return ips_invalid;
|
||||
offset = read24();
|
||||
}
|
||||
study->outlen_min_mem=outlen;
|
||||
study->outlen_max=0xFFFFFFFF;
|
||||
if (patchat+3==patchend)
|
||||
study->outlen_min_mem = outlen;
|
||||
study->outlen_max = 0xFFFFFFFF;
|
||||
if (patchat+3 == patchend)
|
||||
{
|
||||
unsigned int truncate=read24();
|
||||
study->outlen_max=truncate;
|
||||
if (outlen>truncate)
|
||||
unsigned int truncate = read24();
|
||||
study->outlen_max = truncate;
|
||||
if (outlen > truncate)
|
||||
{
|
||||
outlen=truncate;
|
||||
w_scrambled=true;
|
||||
outlen = truncate;
|
||||
w_scrambled = true;
|
||||
}
|
||||
}
|
||||
if (patchat!=patchend) return ips_invalid;
|
||||
study->outlen_min=outlen;
|
||||
if (patchat != patchend) return ips_invalid;
|
||||
study->outlen_min = outlen;
|
||||
#undef read8
|
||||
#undef read16
|
||||
#undef read24
|
||||
study->error=ips_ok;
|
||||
if (w_scrambled) study->error=ips_scrambled;
|
||||
study->error = ips_ok;
|
||||
if (w_scrambled) study->error = ips_scrambled;
|
||||
return study->error;
|
||||
}
|
||||
|
||||
enum ipserror ips_apply_study(struct mem patch, struct ipsstudy * study, struct mem in, struct mem * out)
|
||||
{
|
||||
out->ptr=NULL;
|
||||
out->len=0;
|
||||
if (study->error==ips_invalid) return study->error;
|
||||
out->ptr = NULL;
|
||||
out->len = 0;
|
||||
if (study->error == ips_invalid) return study->error;
|
||||
#define read8() (*patchat++)//guaranteed to not overflow at this point, we already checked the patch
|
||||
#define read16() (patchat+=2,((patchat[-2]<<8)|patchat[-1]))
|
||||
#define read24() (patchat+=3,((patchat[-3]<<16)|(patchat[-2]<<8)|patchat[-1]))
|
||||
unsigned int outlen=clamp(study->outlen_min, in.len, study->outlen_max);
|
||||
out->ptr=(byte*)malloc(max(outlen, study->outlen_min_mem));
|
||||
out->len=outlen;
|
||||
#define read16() (patchat += 2,( (patchat[-2] << 8) | patchat[-1]))
|
||||
#define read24() (patchat += 3,((patchat[-3] << 16) | (patchat[-2] << 8) | patchat[-1]))
|
||||
unsigned int outlen = clamp(study->outlen_min, in.len, study->outlen_max);
|
||||
out->ptr = (byte*)malloc(max(outlen, study->outlen_min_mem));
|
||||
out->len = outlen;
|
||||
|
||||
bool anychanges=false;
|
||||
if (outlen!=in.len) anychanges=true;
|
||||
bool anychanges = false;
|
||||
if (outlen != in.len) anychanges = true;
|
||||
|
||||
if (out->len>in.len)
|
||||
if (out->len > in.len)
|
||||
{
|
||||
memcpy(out->ptr, in.ptr, in.len);
|
||||
memset(out->ptr+in.len, 0, out->len-in.len);
|
||||
memset(out->ptr + in.len, 0, out->len - in.len);
|
||||
}
|
||||
else memcpy(out->ptr, in.ptr, outlen);
|
||||
const unsigned char * patchat=patch.ptr+5;
|
||||
unsigned int offset=read24();
|
||||
while (offset!=0x454F46)
|
||||
|
||||
const unsigned char * patchat = patch.ptr+5;
|
||||
unsigned int offset = read24();
|
||||
while (offset != 0x454F46)
|
||||
{
|
||||
unsigned int size=read16();
|
||||
if (size==0)
|
||||
unsigned int size = read16();
|
||||
if (size == 0)
|
||||
{
|
||||
size=read16();
|
||||
if (!size) {}//no clue (fix the change detector if changing this)
|
||||
unsigned char b=read8();
|
||||
size = read16();
|
||||
//if (!size) return ips_invalid; // rejected in ips_study
|
||||
unsigned char b = read8();
|
||||
|
||||
if (size && (out->ptr[offset]!=b || memcmp(out->ptr+offset, out->ptr+offset, size-1))) anychanges=true;
|
||||
if (!anychanges && size && (out->ptr[offset] != b || memcmp(out->ptr + offset, out->ptr + offset, size - 1)))
|
||||
anychanges = true;
|
||||
|
||||
memset(out->ptr+offset, b, size);
|
||||
memset(out->ptr + offset, b, size);
|
||||
}
|
||||
else
|
||||
{
|
||||
if (memcmp(out->ptr+offset, patchat, size)) anychanges=true;
|
||||
if (!anychanges && memcmp(out->ptr + offset, patchat, size))
|
||||
anychanges = true;
|
||||
|
||||
memcpy(out->ptr+offset, patchat, size);
|
||||
patchat+=size;
|
||||
memcpy(out->ptr + offset, patchat, size);
|
||||
patchat += size;
|
||||
}
|
||||
offset=read24();
|
||||
offset = read24();
|
||||
}
|
||||
#undef read8
|
||||
#undef read16
|
||||
#undef read24
|
||||
|
||||
if (study->outlen_max!=0xFFFFFFFF && in.len<=study->outlen_max) study->error=ips_notthis;//truncate data without this being needed is a poor idea
|
||||
if (!anychanges) study->error=ips_thisout;
|
||||
//truncate data without this being needed is a poor idea
|
||||
if (study->outlen_max != 0xFFFFFFFF && in.len <= study->outlen_max)
|
||||
study->error = ips_notthis;
|
||||
|
||||
if (!anychanges)
|
||||
study->error = ips_thisout;
|
||||
return study->error;
|
||||
}
|
||||
|
||||
|
|
@ -182,121 +190,136 @@ enum ipserror ips_apply(struct mem patch, struct mem in, struct mem * out)
|
|||
|
||||
enum ipserror ips_create(struct mem sourcemem, struct mem targetmem, struct mem * patchmem)
|
||||
{
|
||||
unsigned int sourcelen=sourcemem.len;
|
||||
unsigned int targetlen=targetmem.len;
|
||||
const unsigned char * source=sourcemem.ptr;
|
||||
const unsigned char * target=targetmem.ptr;
|
||||
unsigned int sourcelen = sourcemem.len;
|
||||
unsigned int targetlen = targetmem.len;
|
||||
const unsigned char * source = sourcemem.ptr;
|
||||
const unsigned char * target = targetmem.ptr;
|
||||
|
||||
patchmem->ptr=NULL;
|
||||
patchmem->len=0;
|
||||
patchmem->ptr = NULL;
|
||||
patchmem->len = 0;
|
||||
|
||||
if (targetlen>=16777216) return ips_16MB;
|
||||
if (targetlen > 16777216) return ips_16MB;
|
||||
if (targetlen >= 16777216 && sourcelen > targetlen) return ips_16MB; // can't truncate to exactly 16MB
|
||||
|
||||
unsigned int offset=0;
|
||||
unsigned int outbuflen=4096;
|
||||
unsigned char * out=(byte*)malloc(outbuflen);
|
||||
unsigned int outlen=0;
|
||||
#define write8(val) do { out[outlen++]=(val); if (outlen==outbuflen) { outbuflen*=2; out=(byte*)realloc(out, outbuflen); } } while(0)
|
||||
#define write16(val) do { write8((val)>>8); write8((val)); } while(0)
|
||||
#define write24(val) do { write8((val)>>16); write8((val)>>8); write8((val)); } while(0)
|
||||
unsigned int offset = 0;
|
||||
unsigned int outbuflen = 4096;
|
||||
unsigned char * out = (byte*)malloc(outbuflen);
|
||||
unsigned int outlen = 0;
|
||||
#define write8(val) do { \
|
||||
out[outlen++] = (val); \
|
||||
if (outlen == outbuflen) { outbuflen *= 2; out = (byte*)realloc(out, outbuflen); } \
|
||||
} while(0)
|
||||
#define write16(val) do { write8((val) >> 8); write8((val)); } while(0)
|
||||
#define write24(val) do { write8((val) >> 16); write8((val) >> 8); write8((val)); } while(0)
|
||||
write8('P');
|
||||
write8('A');
|
||||
write8('T');
|
||||
write8('C');
|
||||
write8('H');
|
||||
int lastknownchange=0;
|
||||
//int forcewrite=(targetlen>sourcelen?1:0);
|
||||
while (offset<targetlen)
|
||||
int lastknownchange = 0;
|
||||
//int forcewrite = (targetlen > sourcelen ? 1 : 0);
|
||||
while (offset < targetlen)
|
||||
{
|
||||
while (offset<sourcelen && (offset<sourcelen?source[offset]:0)==target[offset]) offset++;
|
||||
while (offset < sourcelen && (offset < sourcelen ? source[offset] : 0) == target[offset])
|
||||
offset++;
|
||||
//check how much we need to edit until it starts getting similar
|
||||
int thislen=0;
|
||||
int consecutiveunchanged=0;
|
||||
thislen=lastknownchange-offset;
|
||||
if (thislen<0) thislen=0;
|
||||
int thislen = 0;
|
||||
int consecutiveunchanged = 0;
|
||||
thislen = lastknownchange - offset;
|
||||
if (thislen < 0) thislen = 0;
|
||||
while (true)
|
||||
{
|
||||
unsigned int thisbyte=offset+thislen+consecutiveunchanged;
|
||||
if (thisbyte<sourcelen && (thisbyte<sourcelen?source[thisbyte]:0)==target[thisbyte]) consecutiveunchanged++;
|
||||
unsigned int thisbyte = offset + thislen + consecutiveunchanged;
|
||||
if (thisbyte < sourcelen && (thisbyte < sourcelen ? source[thisbyte] : 0) == target[thisbyte])
|
||||
{
|
||||
consecutiveunchanged++;
|
||||
}
|
||||
else
|
||||
{
|
||||
thislen+=consecutiveunchanged+1;
|
||||
consecutiveunchanged=0;
|
||||
thislen += consecutiveunchanged + 1;
|
||||
consecutiveunchanged = 0;
|
||||
}
|
||||
if (consecutiveunchanged>=6 || thislen>=65536) break;
|
||||
if (consecutiveunchanged >= 6 || thislen >= 65536) break;
|
||||
}
|
||||
|
||||
//avoid premature EOF
|
||||
if (offset==0x454F46)
|
||||
if (offset == 0x454F46)
|
||||
{
|
||||
offset--;
|
||||
thislen++;
|
||||
}
|
||||
|
||||
lastknownchange=offset+thislen;
|
||||
if (thislen>65535) thislen=65535;
|
||||
if (offset+thislen>targetlen) thislen=targetlen-offset;
|
||||
if (offset==targetlen) continue;
|
||||
lastknownchange = offset + thislen;
|
||||
if (thislen > 65535) thislen = 65535;
|
||||
if (offset + thislen > targetlen) thislen = targetlen - offset;
|
||||
if (offset == targetlen) continue;
|
||||
|
||||
//check if RLE here is worthwhile
|
||||
int byteshere;
|
||||
for (byteshere=0;byteshere<thislen && target[offset]==target[offset+byteshere];byteshere++) {}
|
||||
if (byteshere==thislen)
|
||||
for (byteshere=0; byteshere<thislen && target[offset] == target[offset+byteshere]; byteshere++) {}
|
||||
if (byteshere == thislen)
|
||||
{
|
||||
int thisbyte=target[offset];
|
||||
int i=0;
|
||||
int thisbyte = target[offset];
|
||||
int i = 0;
|
||||
while (true)
|
||||
{
|
||||
unsigned int pos=offset+byteshere+i-1;
|
||||
if (pos>=targetlen || target[pos]!=thisbyte || byteshere+i>65535) break;
|
||||
if (pos>=sourcelen || (pos<sourcelen?source[pos]:0)!=thisbyte)
|
||||
unsigned int pos = offset + byteshere + i - 1;
|
||||
if (pos >= targetlen || target[pos] != thisbyte || byteshere + i > 65535)
|
||||
break;
|
||||
if (pos >= sourcelen || (pos < sourcelen ? source[pos] : 0) != thisbyte)
|
||||
{
|
||||
byteshere+=i;
|
||||
thislen+=i;
|
||||
i=0;
|
||||
byteshere += i;
|
||||
thislen += i;
|
||||
i = 0;
|
||||
}
|
||||
i++;
|
||||
}
|
||||
}
|
||||
if ((byteshere>8-5 && byteshere==thislen) || byteshere>8)
|
||||
if ((byteshere > 8-5 && byteshere == thislen) || byteshere > 8)
|
||||
{
|
||||
write24(offset);
|
||||
write16(0);
|
||||
write16(byteshere);
|
||||
write8(target[offset]);
|
||||
offset+=byteshere;
|
||||
offset += byteshere;
|
||||
}
|
||||
else
|
||||
{
|
||||
//check if we'd gain anything from ending the block early and switching to RLE
|
||||
int byteshere=0;
|
||||
int stopat=0;
|
||||
while (stopat+byteshere<thislen)
|
||||
int byteshere = 0;
|
||||
int stopat = 0;
|
||||
while (stopat + byteshere < thislen)
|
||||
{
|
||||
if (target[offset+stopat]==target[offset+stopat+byteshere]) byteshere++;
|
||||
if (target[offset + stopat] == target[offset + stopat + byteshere])
|
||||
{
|
||||
byteshere++;
|
||||
}
|
||||
else
|
||||
{
|
||||
stopat+=byteshere;
|
||||
byteshere=0;
|
||||
stopat += byteshere;
|
||||
byteshere = 0;
|
||||
}
|
||||
if (byteshere>8+5 || //rle-worthy despite two ips headers
|
||||
(byteshere>8 && stopat+byteshere==thislen) || //rle-worthy at end of data
|
||||
(byteshere>8 && !memcmp(&target[offset+stopat+byteshere], &target[offset+stopat+byteshere+1], 9-1)))//rle-worthy before another rle-worthy
|
||||
if (byteshere > 8+5 || //rle-worthy despite two ips headers
|
||||
(byteshere > 8 && stopat + byteshere == thislen) || //rle-worthy at end of data
|
||||
(byteshere > 8 && !memcmp(&target[offset +stopat + byteshere], //rle-worthy before another rle-worthy
|
||||
&target[offset +stopat + byteshere + 1],
|
||||
9-1)))
|
||||
{
|
||||
if (stopat) thislen=stopat;
|
||||
break;//we don't scan the entire block if we know we'll want to RLE, that'd gain nothing.
|
||||
if (stopat) thislen = stopat;
|
||||
break; //we don't scan the entire block if we know we'll want to RLE, that'd gain nothing.
|
||||
}
|
||||
}
|
||||
//don't write unchanged bytes at the end of a block if we want to RLE the next couple of bytes
|
||||
if (offset+thislen!=targetlen)
|
||||
if (offset + thislen != targetlen)
|
||||
{
|
||||
while (offset+thislen-1<sourcelen && target[offset+thislen-1]==(offset+thislen-1<sourcelen?source[offset+thislen-1]:0))
|
||||
while (offset + thislen - 1 < sourcelen &&
|
||||
target[offset + thislen - 1] == (offset + thislen - 1 < sourcelen ? source[offset + thislen - 1] : 0))
|
||||
{
|
||||
thislen--;
|
||||
}
|
||||
}
|
||||
|
||||
if (thislen>3 && !memcmp(&target[offset], &target[offset+1], thislen-1))//still worth it?
|
||||
if (thislen > 3 && !memcmp(&target[offset], &target[offset + 1], thislen - 1)) //still worth it?
|
||||
{
|
||||
write24(offset);
|
||||
write16(0);
|
||||
|
|
@ -308,22 +331,21 @@ enum ipserror ips_create(struct mem sourcemem, struct mem targetmem, struct mem
|
|||
write24(offset);
|
||||
write16(thislen);
|
||||
int i;
|
||||
for (i=0;i<thislen;i++)
|
||||
{
|
||||
write8(target[offset+i]);
|
||||
}
|
||||
for (i=0; i<thislen; i++)
|
||||
write8(target[offset + i]);
|
||||
}
|
||||
offset+=thislen;
|
||||
offset += thislen;
|
||||
}
|
||||
}
|
||||
write8('E');
|
||||
write8('O');
|
||||
write8('F');
|
||||
if (sourcelen>targetlen) write24(targetlen);
|
||||
if (sourcelen > targetlen) write24(targetlen);
|
||||
#undef write
|
||||
patchmem->ptr=out;
|
||||
patchmem->len=outlen;
|
||||
if (outlen==8) return ips_identical;
|
||||
patchmem->ptr = out;
|
||||
patchmem->len = outlen;
|
||||
if (outlen == 8)
|
||||
return ips_identical;
|
||||
return ips_ok;
|
||||
}
|
||||
|
||||
|
|
@ -339,61 +361,61 @@ void ips_free(struct mem mem)
|
|||
//Congratulations, you found the undocumented feature! I don't think it's useful for anything except debugging libips, though.
|
||||
void ips_dump(struct mem patch)
|
||||
{
|
||||
if (patch.len<8)
|
||||
if (patch.len < 8)
|
||||
{
|
||||
puts("Invalid");
|
||||
return;
|
||||
}
|
||||
const unsigned char * patchat=patch.ptr;
|
||||
const unsigned char * patchend=patchat+patch.len;
|
||||
#define read8() ((patchat<patchend)?(*patchat++):0)
|
||||
#define read16() ((patchat+1<patchend)?(patchat+=2,((patchat[-2]<<8)|patchat[-1])):0)
|
||||
#define read24() ((patchat+2<patchend)?(patchat+=3,((patchat[-3]<<16)|(patchat[-2]<<8)|patchat[-1])):0)
|
||||
if (read8()!='P' ||
|
||||
read8()!='A' ||
|
||||
read8()!='T' ||
|
||||
read8()!='C' ||
|
||||
read8()!='H')
|
||||
const unsigned char * patchat = patch.ptr;
|
||||
const unsigned char * patchend = patchat + patch.len;
|
||||
#define read8() ((patchat < patchend) ? (*patchat++) : 0)
|
||||
#define read16() ((patchat+1 < patchend) ? (patchat += 2, ( (patchat[-2] << 8) | patchat[-1])) : 0)
|
||||
#define read24() ((patchat+2 < patchend) ? (patchat += 3, ((patchat[-3] << 16) | (patchat[-2] << 8) | patchat[-1])) : 0)
|
||||
if (read8() != 'P' ||
|
||||
read8() != 'A' ||
|
||||
read8() != 'T' ||
|
||||
read8() != 'C' ||
|
||||
read8() != 'H')
|
||||
{
|
||||
puts("Invalid");
|
||||
return;
|
||||
}
|
||||
int blockstart=patchat-patch.ptr;
|
||||
int offset=read24();
|
||||
int outlen=0;
|
||||
int thisout=0;
|
||||
while (offset!=0x454F46)//454F46=EOF
|
||||
int blockstart = patchat - patch.ptr;
|
||||
int offset = read24();
|
||||
int outlen = 0;
|
||||
int thisout = 0;
|
||||
while (offset != 0x454F46)
|
||||
{
|
||||
int size=read16();
|
||||
if (size==0)
|
||||
int size = read16();
|
||||
if (size == 0)
|
||||
{
|
||||
int rlelen=read16();
|
||||
thisout=offset+rlelen;
|
||||
int rlelen = read16();
|
||||
thisout = offset + rlelen;
|
||||
printf("[%X] %X: %i (RLE)\n", blockstart, offset, rlelen);
|
||||
read8();
|
||||
}
|
||||
else
|
||||
{
|
||||
thisout=offset+size;
|
||||
thisout = offset + size;
|
||||
printf("[%X] %X: %i\n", blockstart, offset, size);
|
||||
patchat+=size;
|
||||
patchat += size;
|
||||
}
|
||||
if (thisout>outlen) outlen=thisout;
|
||||
if (patchat>=patchend)
|
||||
if (thisout > outlen) outlen = thisout;
|
||||
if (patchat >= patchend)
|
||||
{
|
||||
puts("Invalid");
|
||||
return;
|
||||
}
|
||||
blockstart=patchat-patch.ptr;
|
||||
offset=read24();
|
||||
blockstart = patchat - patch.ptr;
|
||||
offset = read24();
|
||||
}
|
||||
printf("Expand to 0x%X\n", outlen);
|
||||
if (patchat+3==patchend)
|
||||
if (patchat + 3 == patchend)
|
||||
{
|
||||
int truncate=read24();
|
||||
int truncate = read24();
|
||||
printf("Truncate to 0x%X\n", truncate);
|
||||
}
|
||||
if (patchat!=patchend) puts("Invalid");
|
||||
if (patchat != patchend) puts("Invalid");
|
||||
#undef read8
|
||||
#undef read16
|
||||
#undef read24
|
||||
|
|
|
|||
56
make.bat
Normal file
56
make.bat
Normal file
|
|
@ -0,0 +1,56 @@
|
|||
::This script creates a heavily optimized binary. For debugging, you're better off using 'mingw32-make'.
|
||||
|
||||
call "C:\Program Files (x86)\Microsoft Visual Studio 9.0\VC\bin\vcvars32.bat"
|
||||
::call "C:\Program Files (x86)\Microsoft Visual Studio 14.0\VC\bin\vcvars32.bat"
|
||||
::call "C:\Program Files (x86)\Microsoft Visual Studio 9.0\VC\bin\vcvars64.bat"
|
||||
|
||||
goto q
|
||||
:h
|
||||
pause
|
||||
:q
|
||||
cls
|
||||
del flips.exe
|
||||
if exist flips.exe goto h
|
||||
::/c - don't link
|
||||
::/Oy - omit frame pointer
|
||||
::/Oi - use intrinsics
|
||||
::/Os - smaller code
|
||||
::/Ox - all optimizations
|
||||
::/EHs-c- - no exceptions
|
||||
::/Gz - use stdcall
|
||||
::/D_CRT_bluh - shut the fuck up about strcpy
|
||||
::/WX - enable warnings
|
||||
::/wd4700 - uninitialized variable, I know what I'm doing
|
||||
::/nologo - I know your version, shut up
|
||||
::/TP - force C++ because void foo(int bar = 0); is syntax error in C
|
||||
::/MT - use static msvcrt
|
||||
::/GL - LTCG
|
||||
::/openmp - enable OpenMP
|
||||
::cl /c /Oy /Oi /Os /Ox /EHs-c- /Gz /D_CRT_SECURE_NO_WARNINGS /WX /wd4700 /nologo /TP /MT /GL *.cpp *.c
|
||||
rem /openmp
|
||||
cl /c /Oy /Oi /Os /Ox /EHs-c- /Gz /D_CRT_SECURE_NO_WARNINGS /WX /wd4700 /nologo /TP /MT /GL /Imsvc ^
|
||||
/DUSE_DIVSUFSORT /Ilibdivsufsort-2.0.1\include /DHAVE_CONFIG_H libdivsufsort-2.0.1\lib\*.c ^
|
||||
*.c *.cpp
|
||||
rc /nologo flips.rc
|
||||
|
||||
link /LTCG /nologo *.obj /subsystem:windows flips.res user32.lib gdi32.lib comctl32.lib shell32.lib comdlg32.lib advapi32.lib /out:flips.exe
|
||||
|
||||
::FOR %%G IN (2dland-dec2013,smwcp,nsmw-tll,senate13,kamek) DO (
|
||||
::FOR %%G IN (2dland-dec2013) DO (
|
||||
::flips --create --ips profile/smw.smc profile/%%G.smc profile/tmp
|
||||
::flips --apply --ips profile/tmp profile/smw.smc NUL.smc
|
||||
|
||||
::flips --create --bps-linear profile/smw.smc profile/%%G.smc profile/tmp
|
||||
::flips --apply --bps-linear profile/tmp profile/smw.smc NUL.smc
|
||||
|
||||
::flips --create --bps-delta profile/smw.smc profile/%%G.smc profile/tmp
|
||||
::flips --apply --bps-delta profile/tmp profile/smw.smc NUL.smc
|
||||
::)
|
||||
::del profile\tmp
|
||||
|
||||
::link /nologo /ltcg:pgoptimize *.obj /subsystem:windows flips.res user32.lib gdi32.lib comctl32.lib shell32.lib comdlg32.lib advapi32.lib /out:flips.exe
|
||||
|
||||
del *.obj flips.res *.pgc *.pgd
|
||||
goto h
|
||||
|
||||
::kernel32.lib shell32.lib user32.lib gdi32.lib comctl32.lib comdlg32.lib dinput8.lib
|
||||
11
make.sh
11
make.sh
|
|
@ -1,9 +1,11 @@
|
|||
#This script creates a heavily optimized binary. For debugging, you're better off using 'make'.
|
||||
|
||||
#clean up
|
||||
rm flips.exe floating.zip flips rc.o *.gcda
|
||||
rm flips.exe floating.zip flips obj/*
|
||||
|
||||
FLAGS='-Wall -Werror -O3 -fomit-frame-pointer -fmerge-all-constants -fvisibility=hidden'
|
||||
FLAGS+=' -fno-exceptions -fno-unwind-tables -fno-asynchronous-unwind-tables'
|
||||
FLAGS+=' -ffunction-sections -fdata-sections -Wl,--gc-sections'
|
||||
FLAGS+=' -ffunction-sections -fdata-sections -Wl,--gc-sections -fprofile-dir=obj/'
|
||||
|
||||
##create windows binary
|
||||
#echo 'Windows/Resource (Wine warmup)'
|
||||
|
|
@ -31,15 +33,14 @@ FLAGS+=' -ffunction-sections -fdata-sections -Wl,--gc-sections'
|
|||
|
||||
#create linux binary
|
||||
echo 'GTK+ (1/3)'
|
||||
rm flips; CFLAGS=$FLAGS' -fprofile-generate' make TARGET=gtk LFLAGS='-lgcov'
|
||||
rm flips; make TARGET=gtk CFLAGS=$FLAGS' -fprofile-generate' LFLAGS='-lgcov'
|
||||
[ -e flips ] || exit
|
||||
echo 'GTK+ (2/3)'
|
||||
profile/profile.sh ./flips
|
||||
echo 'GTK+ (3/3)'
|
||||
rm flips; CFLAGS=$FLAGS' -fprofile-use' make TARGET=gtk LFLAGS=''
|
||||
rm flips; make TARGET=gtk CFLAGS=$FLAGS' -fprofile-use' LFLAGS=''
|
||||
rm *.gcda
|
||||
echo mv flips '~/bin/flips'
|
||||
mv flips ~/bin/flips # keeping this one for myself
|
||||
|
||||
#echo Finishing
|
||||
##compress source
|
||||
|
|
|
|||
Loading…
Reference in New Issue
Block a user