mirror of
https://github.com/Alcaro/Flips.git
synced 2026-03-22 01:54:26 -05:00
Whatever changes I made since 1.31
This commit is contained in:
parent
24e6c77eb8
commit
990ee08ddb
28
Makefile
28
Makefile
|
|
@ -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$@
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
|
|
|||
99
flips.cpp
99
flips.cpp
|
|
@ -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
11
flips.h
|
|
@ -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()
|
||||
|
|
|
|||
8
flips.rc
8
flips.rc
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
|
|
|||
158
libbps.cpp
158
libbps.cpp
|
|
@ -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.
|
||||
|
|
|
|||
31
libbps.h
31
libbps.h
|
|
@ -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
|
||||
|
|
|
|||
2
libips.h
2
libips.h
|
|
@ -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
|
||||
|
|
|
|||
2
libups.h
2
libups.h
|
|
@ -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
|
||||
|
|
|
|||
6
make.sh
6
make.sh
|
|
@ -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
|
||||
|
|
|
|||
25
sais.cpp
25
sais.cpp
|
|
@ -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]
|
||||
|
|
|
|||
Loading…
Reference in New Issue
Block a user