Whatever changes I made since 1.31

This commit is contained in:
Alcaro 2016-01-17 18:15:18 +01:00
parent 24e6c77eb8
commit 990ee08ddb
13 changed files with 335 additions and 153 deletions

View File

@ -3,19 +3,20 @@ CFLAGS_windows := -DFLIPS_WINDOWS -mwindows -lgdi32 -lcomdlg32 -lcomctl32 -luser
CFLAGS_win := $(CFLAGS_windows)
CFLAGS_cli := -DFLIPS_CLI
CFLAGS_G = -fno-rtti -fno-exceptions
CFLAGS_G = -fno-rtti -fno-exceptions -DNDEBUG
FNAME_gtk := flips
FNAME_windows := flips.exe
FNAME_win := $(FNAME_windows)
FNAME_cli := flips
CXX = g++
XFILES :=
SOURCES := *.cpp
ifeq ($(TARGET),)
targetmachine := $(shell $(CC) -dumpmachine)
targetmachine := $(shell $(CXX) -dumpmachine)
ifneq ($(findstring mingw,$(targetmachine)),)
TARGET := windows
else ifneq ($(findstring linux,$(targetmachine)),)
@ -48,7 +49,7 @@ ifeq ($(TARGET),gtk)
endif
ifeq ($(GTKFLAGS),)
$(warning pkg-config can't find gtk+-3.0, or pkg-config itself can't be found)
$(warning if you have the needed files installed, specify their locations and names with `make 'GTKFLAGS=-I/usr/include' 'GTKLIBS=-L/usr/lib -lgtk'')
$(warning if you have the needed files installed, specify their locations and names with `make GTKFLAGS='-I/usr/include' GTKLIBS='-L/usr/lib -lgtk'')
$(warning if not, the package name under Debian and derivates is `libgtk-3-dev'; on other distros, consult a search engine)
$(warning switching to CLI build)
TARGET := cli
@ -71,20 +72,21 @@ ifneq ($(DIVSUF),no)
DIVSUF := $(subst /include/config.h,,$(DIVSUF_EXIST))
ifneq ($(DIVSUF),)
DIVSUF_SOURCES := $(filter-out %/utils.c,$(wildcard $(DIVSUF)/lib/*.c))
ifeq ($(DIVSUF_OPENMP),)
ifeq ($(TARGET),gtk)
DIVSUF_OPENMP := -fopenmp
endif
endif
DIVSUF_CFLAGS := -DUSE_DIVSUFSORT -I$(DIVSUF)/include -DHAVE_CONFIG_H -DNDEBUG -D__STDC_FORMAT_MACROS $(DIVSUF_OPENMP)
DIVSUF_CFLAGS := -I$(DIVSUF)/include -DHAVE_CONFIG_H -D__STDC_FORMAT_MACROS
DIVSUF_LFLAGS :=
MOREFLAGS += $(DIVSUF_CFLAGS) $(DIVSUF_SOURCES) $(DIVSUF_LFLAGS)
else
$(warning no libdivsufsort-2.x detected; switching to fallback SA-IS)
$(warning libdivsufsort is approximately twice as fast as SA-IS)
$(warning no libdivsufsort-2.x detected; switching to fallback libdivsufsort-lite)
$(warning libdivsufsort is approximately 3% faster than lite)
SOURCES += divsufsort.c
endif
else
SOURCES += divsufsort.c
endif
ifeq ($(TARGET),gtk)
CFLAGS_G += -fopenmp
endif
$(FNAME_$(TARGET)): *.cpp $(XFILES)
$(FNAME_$(TARGET)): $(SOURCES) $(XFILES)
$(CXX) $^ -std=c++98 $(CFLAGS) $(LFLAGS) $(CFLAGS_G) $(MOREFLAGS) $(XFILES) -o$@

View File

@ -784,27 +784,19 @@ void a_SetEmulator(GtkButton* widget, gpointer user_data)
gtk_widget_destroy(dialog);
}
int ShowGUI(const char * filename)
gchar * get_cfgpath()
{
if (!canShowGUI)
{
g_warning("couldn't parse command line arguments, fix them or use command line");
usage();
}
static gchar * cfgpath=NULL;
if (!cfgpath) cfgpath=g_strconcat(g_get_user_config_dir(), "/flipscfg", NULL);
return cfgpath;
}
void GUILoadConfig()
{
if (!canShowGUI) return;
GdkDisplay* display=gdk_display_open(gdk_get_display_arg_name());
if (!display) display=gdk_display_get_default();
if (!display)
{
g_warning("couldn't connect to display, fix it or use command line");
usage();
}
gdk_display_manager_set_default_display(gdk_display_manager_get(), display);
const gchar * cfgdir=g_get_user_config_dir();
gchar * cfgpath=g_strndup(cfgdir, strlen(cfgdir)+strlen("/flipscfg")+1);
strcat(cfgpath, "/flipscfg");
struct mem cfgin = file::read(cfgpath);
struct mem cfgin = file::read(get_cfgpath());
if (cfgin.len>=10+1+1+1+1+4+4 && !memcmp(cfgin.ptr, "FlipscfgG", 9) && cfgin.ptr[9]==cfgversion)
{
state.lastPatchType=cfgin.ptr[10];
@ -836,6 +828,26 @@ int ShowGUI(const char * filename)
state.lastPatchType=ty_bps;
}
free(cfgin.ptr);
}
int GUIShow(const char * filename)
{
if (!canShowGUI)
{
g_warning("couldn't parse command line arguments, fix them or use command line");
usage();
}
GdkDisplay* display=gdk_display_open(gdk_get_display_arg_name());
if (!display) display=gdk_display_get_default();
if (!display)
{
g_warning("couldn't connect to display, fix it or use command line");
usage();
}
gdk_display_manager_set_default_display(gdk_display_manager_get(), display);
GUILoadConfig();
if (filename)
{
@ -891,7 +903,7 @@ int ShowGUI(const char * filename)
cfgout.ptr[21]=romlist.len>>0;
memcpy(cfgout.ptr+22, state.emulator, emulen);
memcpy(cfgout.ptr+22+emulen, romlist.ptr, romlist.len);
filewrite::write(cfgpath, cfgout);
filewrite::write(get_cfgpath(), cfgout);
return 0;
}

View File

@ -863,7 +863,7 @@ int ShowMainWindow(HINSTANCE hInstance, int nCmdShow)
return msg.wParam;
}
void ClaimConsole()
void GUIClaimConsole()
{
//this one makes it act like a console app in all cases except it doesn't create a new console if
// not launched from one (it'd swiftly go away on app exit anyways), and it doesn't like being
@ -884,16 +884,20 @@ void ClaimConsole()
HINSTANCE hInstance_;
int nCmdShow_;
int ShowGUI(LPCWSTR filename)
WCHAR * get_cfgpath()
{
WCHAR cfgfname[MAX_PATH+8];
static WCHAR cfgfname[MAX_PATH+8];
GetModuleFileNameW(NULL, cfgfname, MAX_PATH);
WCHAR * ext=GetExtension(cfgfname);
if (ext) *ext='\0';
wcscat(cfgfname, TEXT("cfg.bin"));
return cfgfname;
}
void GUILoadConfig()
{
memset(&state, 0, sizeof(state));
struct mem configbin=ReadWholeFile(cfgfname);
struct mem configbin=ReadWholeFile(get_cfgpath());
void* configbin_org=configbin.ptr;
if (configbin.len >= sizeof(state))
{
@ -925,6 +929,11 @@ int ShowGUI(LPCWSTR filename)
set_st_emulator(TEXT(""));
}
free(configbin_org);
}
int GUIShow(LPCWSTR filename)
{
GUILoadConfig();
INITCOMMONCONTROLSEX initctrls;
initctrls.dwSize=sizeof(initctrls);
@ -939,7 +948,7 @@ int ShowGUI(LPCWSTR filename)
}
else ret=ShowMainWindow(hInstance_, nCmdShow_);
HANDLE file=CreateFile(cfgfname, GENERIC_WRITE, FILE_SHARE_READ, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_HIDDEN, NULL);
HANDLE file=CreateFile(get_cfgpath(), GENERIC_WRITE, FILE_SHARE_READ, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_HIDDEN, NULL);
if (file!=INVALID_HANDLE_VALUE)
{
DWORD whocares;

View File

@ -136,6 +136,7 @@ const struct errorinfo bpserrors[]={
{ el_notthis, "That's the output file already." },//bps_to_output
{ el_notthis, "This patch is not intended for this ROM." },//bps_not_this
{ el_broken, "This patch is broken and can't be used." },//bps_broken
{ el_broken, "Couldn't read input patch. What exactly are you doing?" },//bps_io
{ el_warning, "The files are identical! The patch will do nothing." },//bps_identical
{ el_broken, "These files are too big for this program to handle." },//bps_too_big
@ -311,10 +312,10 @@ LPCWSTR FindRomForPatch(file* patch, bool * possibleToFind)
enum patchtype patchtype=IdentifyPatch(patch);
if (patchtype==ty_bps)
{
uint32_t crc;
if (bps_get_checksums(patch, &crc, NULL, NULL)!=bps_ok) return NULL;
struct bpsinfo info = bps_get_info(patch, false);
if (info.error) return NULL;
if (possibleToFind) *possibleToFind=true;
return FindRomForSum(ch_crc32, &crc);
return FindRomForSum(ch_crc32, &info.crc_in);
}
//UPS has checksums too, but screw UPS. Nobody cares.
return NULL;
@ -325,9 +326,9 @@ void AddToRomList(file* patch, LPCWSTR path)
enum patchtype patchtype=IdentifyPatch(patch);
if (patchtype==ty_bps)
{
uint32_t crc;
if (bps_get_checksums(patch, &crc, NULL, NULL)!=bps_ok) return;
AddRomForSum(ch_crc32, &crc, path);
struct bpsinfo info = bps_get_info(patch, false);
if (info.error) return;
AddRomForSum(ch_crc32, &info.crc_in, path);
}
}
@ -586,11 +587,59 @@ struct errorinfo CreatePatch(LPCWSTR inromname, LPCWSTR outromname, enum patchty
return errinf;
}
int patchinfo(LPCWSTR patchname)
{
GUIClaimConsole();
file* patch = file::create(patchname);
if (!patch)
{
puts("Couldn't read file");
return el_broken;
}
enum patchtype patchtype=IdentifyPatch(patch);
if (patchtype==ty_bps)
{
struct bpsinfo info = bps_get_info(patch, false);
if (info.error)
{
puts(bpserrors[info.error].description);
return bpserrors[info.error].level;
}
#ifndef FLIPS_CLI
GUILoadConfig();
LPCWSTR inromname = FindRomForPatch(patch, NULL);
#else
LPCWSTR inromname = NULL;
#endif
#ifdef FLIPS_WINDOWS
#define z "I"
#else
#define z "z"
#endif
printf("Input ROM: %" z "u bytes, CRC32 %.8X", info.size_in, info.crc_in);
if (inromname) wprintf(TEXT(", %s"), inromname);
puts("");
printf("Output ROM: %" z "u bytes, CRC32 %.8X\n", info.size_out, info.crc_out);
//floating point may lose a little precision, but it's easier than dodging overflows, and this
//is the output of inaccurate heuristics anyways, losing a little more makes no difference.
//Windows MulDiv could also work, but it's kinda nonportable.
//printf("Change index: %i / 1000\n", (int)(info.change_num / (float)info.change_denom * 1000));
return 0;
}
puts("No information available for this patch type");
return el_broken;
}
void usage()
{
ClaimConsole();
GUIClaimConsole();
puts(
// 12345678901234567890123456789012345678901234567890123456789012345678901234567890
"usage:\n"
@ -601,7 +650,7 @@ void usage()
"or "
#endif
"flips [--apply] [--exact] patch.bps rom.smc [outrom.smc]\n"
"or flips [--create] [--exact] [--ips | --bps | --bps-delta] clean.smc\n"
"or flips [--create] [--exact] [--bps | --bps-linear | --ips] clean.smc\n"
" hack.smc [patch.bps]\n"
#ifndef FLIPS_CLI
"(for scripting, only the latter two are sensible)\n"
@ -612,6 +661,9 @@ void usage()
"options:\n"
"-a --apply: apply patch (default if given two arguments)\n"
"-c --create: create patch (default if given three arguments)\n"
"-I --info: BPSes contain information about input and output roms, print it\n"
//" also estimates how much of the source file is retained\n"
//" anything under 400 is fine, anything over 600 should be treated with suspicion\n"
"-i --ips, -b -B --bps --bps-delta, --bps-linear, --bps-delta-moremem:\n"
" create this patch format instead of guessing based on file extension\n"
" ignored when applying\n"
@ -639,7 +691,7 @@ void usage()
int flipsmain(int argc, WCHAR * argv[])
{
enum patchtype patchtype=ty_null;
enum { a_default, a_apply_filepicker, a_apply_given, a_create } action=a_default;
enum { a_default, a_apply_filepicker, a_apply_given, a_create, a_info } action=a_default;
int numargs=0;
LPCWSTR arg[3]={NULL,NULL,NULL};
bool hasFlags=false;
@ -669,6 +721,11 @@ int flipsmain(int argc, WCHAR * argv[])
if (action==a_default) action=a_create;
else usage();
}
else if (!wcscmp(argv[i], TEXT("--info")) || !wcscmp(argv[i], TEXT("-I")))
{
if (action==a_default) action=a_info;
else usage();
}
else if (!wcscmp(argv[i], TEXT("--ips")) || !wcscmp(argv[i], TEXT("-i")))
{
if (patchtype==ty_null) patchtype=ty_ips;
@ -719,7 +776,7 @@ int flipsmain(int argc, WCHAR * argv[])
}
else if (!wcscmp(argv[i], TEXT("--version")) || !wcscmp(argv[i], TEXT("-v")))
{
ClaimConsole();
GUIClaimConsole();
puts(flipsversion);
return 0;
}
@ -746,7 +803,7 @@ int flipsmain(int argc, WCHAR * argv[])
if (numargs!=0 || hasFlags) usage();
#ifndef FLIPS_CLI
guiActive=true;
return ShowGUI(NULL);
return GUIShow(NULL);
#else
usage();
#endif
@ -756,7 +813,7 @@ int flipsmain(int argc, WCHAR * argv[])
if (numargs!=1 || hasFlags) usage();
#ifndef FLIPS_CLI
guiActive=true;
return ShowGUI(arg[0]);
return GUIShow(arg[0]);
#else
usage();
#endif
@ -764,7 +821,7 @@ int flipsmain(int argc, WCHAR * argv[])
case a_apply_given:
{
if (numargs!=2 && numargs!=3) usage();
ClaimConsole();
GUIClaimConsole();
struct errorinfo errinf=ApplyPatch(arg[0], arg[1], !ignoreChecksum, arg[2]?arg[2]:arg[1], &manifestinfo, false);
puts(errinf.description);
return errinf.level;
@ -772,7 +829,7 @@ int flipsmain(int argc, WCHAR * argv[])
case a_create:
{
if (numargs!=2 && numargs!=3) usage();
ClaimConsole();
GUIClaimConsole();
if (!arg[2])
{
if (patchtype==ty_null)
@ -808,6 +865,20 @@ int flipsmain(int argc, WCHAR * argv[])
puts(errinf.description);
return errinf.level;
}
case a_info:
{
if (numargs!=1) usage();
return patchinfo(arg[0]);
}
}
return 99;//doesn't happen
}

11
flips.h
View File

@ -34,7 +34,7 @@
//#define EXTERN_C
//#endif
#define flipsversion "Flips v1.31"
#define flipsversion "Flips v1.32"
#if defined(FLIPS_WINDOWS)
@ -87,7 +87,6 @@
#define wprintf printf
#define TEXT(text) text
//EXTERN_C int strcasecmp(const char *s1, const char *s2);
#define ClaimConsole() // all other platforms have consoles already
#define strdup strdup_flips
static inline char* strdup(const char * in)
@ -197,9 +196,13 @@ void bpsdeltaBegin();
bool bpsdeltaProgress(void* userdata, size_t done, size_t total);
void bpsdeltaEnd();
int ShowGUI(LPCWSTR filename);
int GUIShow(LPCWSTR filename);
void GUILoadConfig();
//LPCWSTR GUIGetFileFor(uint32_t crc32); // use FindRomForPatch instead
#ifdef FLIPS_WINDOWS
void ClaimConsole();
void GUIClaimConsole();
#else
#define GUIClaimConsole() // all other platforms have consoles already
#endif
//the OS port is responsible for main()

View File

@ -7,8 +7,8 @@
1 24 "flips.Manifest"
VS_VERSION_INFO VERSIONINFO
FILEVERSION 1,3,1,0
PRODUCTVERSION 1,3,1,0
FILEVERSION 1,3,2,0
PRODUCTVERSION 1,3,2,0
FILEFLAGSMASK VS_FFI_FILEFLAGSMASK
FILEFLAGS 0
//VS_FF_DEBUG VS_FF_PATCHED VS_FF_PRERELEASE VS_FF_PRIVATEBUILD VS_FF_SPECIALBUILD VS_FFI_FILEFLAGSMASK
@ -22,12 +22,12 @@ BEGIN
BEGIN
VALUE "CompanyName", "Alcaro"
VALUE "FileDescription", "Flips Patch Utility"
VALUE "FileVersion", "1.3.1.0"
VALUE "FileVersion", "1.3.2.0"
VALUE "InternalName", "Floating IPS"
VALUE "LegalCopyright", "©2013-2015 Alcaro"
VALUE "OriginalFilename", "flips.exe"
VALUE "ProductName", "Floating IPS"
VALUE "ProductVersion", "1.3.1.0"
VALUE "ProductVersion", "1.3.2.0"
END
END
END

View File

@ -108,8 +108,7 @@
#include "sais.cpp"
template<typename sais_index_type>
static void
sufsort(sais_index_type* SA, const uint8_t* T, sais_index_type n) {
static void sufsort(sais_index_type* SA, const uint8_t* T, sais_index_type n) {
if(n <= 1) { if(n == 1) SA[0] = 0; return; }
sais_main<sais_index_type>(T, SA, 0, n, 256);
}
@ -122,14 +121,12 @@ sufsort(sais_index_type* SA, const uint8_t* T, sais_index_type n) {
//I'd prefer to let them allocate from an array I give it, but divsuf doesn't allow that, and there
// are only half a dozen allocations per call anyways.
#ifdef USE_DIVSUFSORT
//This ends up in libdivsufsort if available, otherwise lite.
#include "divsufsort.h"
static void sufsort(int32_t* SA, uint8_t* T, int32_t n)
{
divsufsort(T, SA, n);
}
#endif
#ifdef USE_DIVSUFSORT64
#include "divsufsort64.h"
@ -196,6 +193,11 @@ struct bps_creator {
out[outlen++] = num>>24;
}
static size_t maxsize()
{
return SIZE_MAX>>2; // can be reduced to SIZE_MAX>>1 by amending append_cmd, but the mallocs overflow at that point anyways.
}
size_t sourcelen;
size_t targetlen;
const uint8_t* targetmem;
@ -660,6 +662,7 @@ off_t lerp(off_t x, off_t y, float frac)
template<typename off_t>
static bpserror bps_create_suf_core(file* source, file* target, bool moremem, struct bps_creator * out)
{
#define error(which) do { err = which; goto error; } while(0)
bpserror err;
size_t realsourcelen = source->len();
@ -677,18 +680,20 @@ static bpserror bps_create_suf_core(file* source, file* target, bool moremem, st
if ((off_t)overflowtest < 0) return bps_too_big;
//the mallocs would overflow
if ((size_t)realsourcelen+realtargetlen >= SIZE_MAX/sizeof(off_t)) return bps_too_big;
if (realsourcelen+realtargetlen >= SIZE_MAX/sizeof(off_t)) return bps_too_big;
if (realsourcelen+realtargetlen >= out->maxsize()) return bps_too_big;
off_t sourcelen = realsourcelen;
off_t targetlen = realtargetlen;
uint8_t* mem_joined = (uint8_t*)malloc(sizeof(uint8_t)*(sourcelen+targetlen));
uint8_t* mem_joined = (uint8_t*)malloc(sizeof(uint8_t)*(realsourcelen+realtargetlen));
off_t* sorted = (off_t*)malloc(sizeof(off_t)*(sourcelen+targetlen));
off_t* sorted = (off_t*)malloc(sizeof(off_t)*(realsourcelen+realtargetlen));
off_t* sorted_inverse = NULL;
if (moremem) sorted_inverse = (off_t*)malloc(sizeof(off_t)*(sourcelen+targetlen));
if (moremem) sorted_inverse = (off_t*)malloc(sizeof(off_t)*(realsourcelen+realtargetlen));
off_t* buckets = NULL;
if (!sorted_inverse) buckets = (off_t*)malloc(sizeof(off_t)*65537);
@ -731,33 +736,21 @@ static bpserror bps_create_suf_core(file* source, file* target, bool moremem, st
prevsortedsize = sortedsize;
if (!out->progress(progPreSort, targetlen))
{
err = bps_canceled;
goto error;
}
if (!out->progress(progPreSort, targetlen)) error(bps_canceled);
target->read(mem_joined, 0, sortedsize);
source->read(mem_joined+sortedsize, 0, sourcelen);
if (!target->read(mem_joined, 0, sortedsize)) error(bps_io);
if (!source->read(mem_joined+sortedsize, 0, sourcelen)) error(bps_io);
out->move_target(mem_joined);
sufsort(sorted, mem_joined, sortedsize+sourcelen);
if (!out->progress(progPreInv, targetlen))
{
err = bps_canceled;
goto error;
}
if (!out->progress(progPreInv, targetlen)) error(bps_canceled);
if (sorted_inverse)
create_reverse_index(sorted, sorted_inverse, sortedsize+sourcelen);
else
create_buckets(mem_joined, sorted, sortedsize+sourcelen, buckets);
if (!out->progress(progPreFind, targetlen))
{
err = bps_canceled;
goto error;
}
if (!out->progress(progPreFind, targetlen)) error(bps_canceled);
}
off_t matchlen = 0;

View File

@ -1,6 +1,6 @@
//Module name: libbps
//Author: Alcaro
//Date: December 20, 2014
//Date: November 7, 2015
//Licence: GPL v3.0 or higher
#include "libbps.h"
@ -22,6 +22,37 @@ static uint32_t read32(uint8_t * ptr)
enum { SourceRead, TargetRead, SourceCopy, TargetCopy };
static bool try_add(size_t& a, size_t b)
{
if (SIZE_MAX-a < b) return false;
a+=b;
return true;
}
static bool try_shift(size_t& a, size_t b)
{
if (SIZE_MAX>>b < a) return false;
a<<=b;
return true;
}
static bool decodenum(const uint8_t*& ptr, size_t& out)
{
out=0;
unsigned int shift=0;
while (true)
{
uint8_t next=*ptr++;
size_t addthis=(next&0x7F);
if (shift) addthis++;
if (!try_shift(addthis, shift)) return false;
// unchecked because if it was shifted, the lowest bit is zero, and if not, it's <=0x7F.
if (!try_add(out, addthis)) return false;
if (next&0x80) return true;
shift+=7;
}
}
#define error(which) do { error=which; goto exit; } while(0)
#define assert_sum(a,b) do { if (SIZE_MAX-(a)<(b)) error(bps_too_big); } while(0)
#define assert_shift(a,b) do { if (SIZE_MAX>>(b)<(a)) error(bps_too_big); } while(0)
@ -42,20 +73,7 @@ enum bpserror bps_apply(struct mem patch, struct mem in, struct mem * out, struc
#define read8() (*(patchat++))
#define decodeto(var) \
do { \
var=0; \
unsigned int shift=0; \
while (true) \
{ \
uint8_t next=read8(); \
assert_shift(next&0x7F, shift); \
size_t addthis=(next&0x7F)<<shift; \
assert_sum(var, addthis); \
var+=addthis; \
if (next&0x80) break; \
shift+=7; \
assert_sum(var, 1U<<shift); \
var+=1<<shift; \
} \
if (!decodenum(patchat, var)) error(bps_too_big); \
} while(false)
#define write8(byte) (*(outat++)=byte)
@ -197,6 +215,8 @@ exit:
return error;
}
#define write(val) \
do { \
out[outlen++]=(val); \
@ -367,26 +387,102 @@ enum bpserror bps_create_linear(struct mem sourcemem, struct mem targetmem, stru
#undef write
#undef writenum
enum bpserror bps_get_checksums(file* patch, uint32_t * inromsum, uint32_t * outromsum, uint32_t * patchsum)
{
size_t len = patch->len();
if (len<4+3+12) return bps_broken;
uint8_t verify[4];
if (!patch->read(verify, 0, 4) || memcmp(verify, "BPS1", 4)) return bps_broken;
uint8_t checksums[12];
if (!patch->read(checksums, len-12, 12)) return bps_broken;
if (inromsum) *inromsum =read32(checksums+0);
if (outromsum) *outromsum=read32(checksums+4);
if (patchsum) *patchsum =read32(checksums+8);
return bps_ok;
}
void bps_free(struct mem mem)
{
free(mem.ptr);
}
#undef error
struct bpsinfo bps_get_info(file* patch, bool changefrac)
{
#define error(why) do { ret.error=why; return ret; } while(0)
struct bpsinfo ret;
size_t len = patch->len();
if (len<4+3+12) error(bps_broken);
uint8_t top[256];
if (!patch->read(top, 0, len>256 ? 256 : len)) error(bps_io);
if (memcmp(top, "BPS1", 4)) error(bps_broken);
const uint8_t* patchdat=top+4;
if (!decodenum(patchdat, ret.size_in)) error(bps_too_big);
if (!decodenum(patchdat, ret.size_out)) error(bps_too_big);
uint8_t checksums[12];
if (!patch->read(checksums, len-12, 12)) error(bps_io);
ret.crc_in = read32(checksums+0);
ret.crc_out = read32(checksums+4);
ret.crc_patch=read32(checksums+8);
if (changefrac && ret.size_in>0)
{
//algorithm: each command adds its length to the numerator, unless it's above 32, in which case
// it adds 32; or if it's SourceRead, in which case it adds 0
//denominator is just input length
uint8_t* patchbin=(uint8_t*)malloc(len);
patch->read(patchbin, 0, len);
size_t outpos=0; // position in the output file
size_t changeamt=0; // change score
const uint8_t* patchat=patchbin+(patchdat-top);
size_t metasize;
if (!decodenum(patchat, metasize)) error(bps_too_big);
patchat+=metasize;
const uint8_t* patchend=patchbin+len-12;
while (patchat<patchend && outpos<ret.size_in)
{
size_t thisinstr;
decodenum(patchat, thisinstr);
size_t length=(thisinstr>>2)+1;
int action=(thisinstr&3);
int min_len_32 = (length<32 ? length : 32);
switch (action)
{
case SourceRead:
{
changeamt+=0;
}
break;
case TargetRead:
{
changeamt+=min_len_32;
patchat+=length;
}
break;
case SourceCopy:
case TargetCopy:
{
changeamt+=min_len_32;
size_t ignore;
decodenum(patchat, ignore);
}
break;
}
outpos+=length;
}
if (patchat>patchend || outpos>ret.size_out) error(bps_broken);
ret.change_num = (changeamt<ret.size_in ? changeamt : ret.size_in);
ret.change_denom = ret.size_in;
free(patchbin);
}
else
{
//this also happens if change fraction is not requested, but it's undefined behaviour anyways.
ret.change_num=1;
ret.change_denom=1;
}
ret.error=bps_ok;
return ret;
}
#if 0
#warning Disable this in release versions.

View File

@ -1,6 +1,6 @@
//Module name: libbps
//Author: Alcaro
//Date: June 18, 2015
//Date: November 30, 2015
//Licence: GPL v3.0 or higher
#include "global.h"
@ -23,13 +23,14 @@ enum bpserror {
bps_to_output,//You attempted to apply a patch to its output.
bps_not_this, //This is not the intended input file for this patch.
bps_broken, //This is not a BPS patch, or it's malformed somehow.
bps_io, //The patch could not be read.
bps_identical, //The input files are identical.
bps_too_big, //Somehow, you're asking for something a size_t can't represent.
bps_out_of_mem,//Memory allocation failure.
bps_canceled, //The callback returned false.
bps_shut_the_fuck_up_gcc//This one isn't used, it's just to kill a stray comma warning.
bps_shut_up_gcc//This one isn't used, it's just to kill a stray comma warning.
};
//Applies the given BPS patch to the given ROM and puts it in 'out'. Metadata, if present and
@ -48,7 +49,7 @@ enum bpserror bps_create_linear(struct mem source, struct mem target, struct mem
// call, and done/total is an approximate percentage counter. Anything else is undefined; for
// example, progress may or may not be called for done=0, progress may or may not be called for
// done=total, done may or may not increase by the same amount between each call, and the duration
// between each call may or may not be constant. In fact, it can
// between each call may or may not be constant.
//To cancel the patch creation, return false from the callback.
//It is safe to pass in NULL for the progress indicator if you're not interested. If the callback is
// NULL, it can obviously not be canceled that way (though if it's a CLI program, you can always
@ -58,13 +59,33 @@ enum bpserror bps_create_delta(file* source, file* target, struct mem metadata,
bool (*progress)(void* userdata, size_t done, size_t total), void* userdata,
bool moremem);
enum bpserror bps_get_checksums(file* patch, uint32_t * inromsum, uint32_t * outromsum, uint32_t * patchsum);
//Frees the memory returned in the output parameters of the above. Do not call it twice on the same
// input, nor on anything you got from anywhere else. bps_free is guaranteed to be equivalent to
// calling stdlib.h's free() on mem.ptr.
void bps_free(struct mem mem);
struct bpsinfo {
enum bpserror error; // If this is not bps_ok, all other values are undefined.
size_t size_in;
size_t size_out;
uint32_t crc_in;
uint32_t crc_out;
uint32_t crc_patch;
//Tells approximately how much of the input ROM is changed compared to the output ROM.
//It's quite heuristic. The algorithm may change with or without notice.
//As of writing, I believe this is accurate to 2 significant digits in base 10.
//It's also more expensive to calculate than the other data, so it's optional.
//If you don't want it, their values are undefined.
//The denominator is always guaranteed nonzero, even if something else says it's undefined.
//Note that this can return success for invalid patches.
size_t change_num;
size_t change_denom;
};
struct bpsinfo bps_get_info(file* patch, bool changefrac);
#ifdef __cplusplus
}
#endif

View File

@ -17,7 +17,7 @@ enum ipserror {
//patch contains only the differences to that point.
ips_identical,//The input buffers are identical.
ips_shut_the_fuck_up_gcc//This one isn't used, it's just to kill a stray comma warning.
ips_shut_up_gcc//This one isn't used, it's just to kill a stray comma warning.
};
//Applies the IPS patch in [patch, patchlen] to [in, inlen] and stores it to [out, outlen]. Send the

View File

@ -18,7 +18,7 @@ enum upserror {
ups_unused2, //bps_out_of_mem
ups_unused3, //bps_canceled
ups_shut_the_fuck_up_gcc//This one isn't used, it's just to kill a stray comma warning.
ups_shut_up_gcc//This one isn't used, it's just to kill a stray comma warning.
};
//Applies the UPS patch in [patch, patchlen] to [in, inlen] and stores it to [out, outlen]. Send the

View File

@ -1,7 +1,9 @@
#clean up
rm flips.exe floating.zip flips rc.o *.gcda
FLAGS='-Wall -Werror -O3 -fomit-frame-pointer -fmerge-all-constants -fno-exceptions -fno-asynchronous-unwind-tables'
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 -Wl,--gc-sections'
#create windows binary
echo 'Windows/Resource (Wine warmup)'
@ -9,13 +11,11 @@ wine windres flips.rc rc.o
echo 'Windows (1/3)'
rm flips.exe; CFLAGS=$FLAGS' -fprofile-generate' wine mingw32-make TARGET=windows LFLAGS='-s -lgcov'
#wine gcc -pipe -std=c99 $FLAGS -fprofile-generate *.c rc.o -mwindows -lgdi32 -lcomdlg32 -lcomctl32 -s -lgcov -oflips.exe
[ -e flips.exe ] || exit
echo 'Windows (2/3)'
profile/profile.sh 'wine flips.exe' NUL
echo 'Windows (3/3)'
rm flips.exe; CFLAGS=$FLAGS' -fprofile-use' wine mingw32-make TARGET=windows LFLAGS='-s'
#wine g++ -pipe -std=c99 $FLAGS -fprofile-use *.c rc.o -mwindows -lgdi32 -lcomdlg32 -lcomctl32 -s -oflips.exe
rm *.gcda rc.o
#verify there are no unexpected dependencies

View File

@ -42,31 +42,6 @@
#define SAIS_LMSSORT2_LIMIT 0x3fffffff
//static void* allocstack[256];
//static size_t allocstacklen[256];
//static size_t allocstackpos=0;
//static size_t allocstacksum=0;
//static size_t allocstackmax=0;
//static void* mymalloc(size_t n)
//{
// void* ret=malloc(n);
// allocstacksum+=n;
// if(allocstacksum>allocstackmax)allocstackmax=allocstacksum;
// printf("a %p(%i) (max %i)\n",ret,n,allocstackmax);
// allocstacklen[allocstackpos]=n;
// allocstack[allocstackpos]=ret;
// allocstackpos++;
// return ret;
//}
//static void myfree(void* p)
//{
// printf("f %p\n",p);
// allocstackpos--;
// allocstacksum-=allocstacklen[allocstackpos];
// if (p!=allocstack[allocstackpos]) printf("E: not stack\n");
// if (allocstackpos==0) allocstackmax=0;
// free(p);
//}
#define SAIS_MYMALLOC(_num, _type) ((_type *)malloc((_num) * sizeof(_type)))
#define SAIS_MYFREE(_ptr, _num, _type) free((_ptr))
#define chr(_a) T[_a]