From 2cc9e855b8f946f8404a5a5aa1a6eb9464e42472 Mon Sep 17 00:00:00 2001 From: Alcaro Date: Sat, 21 Apr 2018 11:16:03 +0200 Subject: [PATCH] Use more mmap, per #10 --- flips-cli.cpp | 1 + flips-gtk.cpp | 31 +++++++++++++- flips-w32.cpp | 9 ++++- flips.cpp | 109 +++++++++++++++++++++++++++++++++++++++++--------- global.h | 12 ++++++ 5 files changed, 138 insertions(+), 24 deletions(-) diff --git a/flips-cli.cpp b/flips-cli.cpp index 332b20b..61544ba 100644 --- a/flips-cli.cpp +++ b/flips-cli.cpp @@ -8,6 +8,7 @@ #ifdef FLIPS_CLI file* file::create(const char * filename) { return file::create_libc(filename); } filewrite* filewrite::create(const char * filename) { return filewrite::create_libc(filename); } +filemap* filemap::create(const char * filename) { return filemap::create_fallback(filename); } int main(int argc, char * argv[]) diff --git a/flips-gtk.cpp b/flips-gtk.cpp index 5c4fecf..4e39eef 100644 --- a/flips-gtk.cpp +++ b/flips-gtk.cpp @@ -92,6 +92,32 @@ filewrite* filewrite::create(const char * filename) } +class filemap_gtk : public filemap { +public: + GMappedFile* mapfile; + + static filemap* create(const char * filename) + { + GMappedFile* mapfile = g_mapped_file_new(filename, false, NULL); + if (!mapfile) return NULL; + return new filemap_gtk(mapfile); + } + + filemap_gtk(GMappedFile* mapfile) : mapfile(mapfile) {} + + size_t len() { return g_mapped_file_get_length(mapfile); } + const uint8_t * ptr() { return (uint8_t*)g_mapped_file_get_contents(mapfile); } + + ~filemap_gtk() { g_mapped_file_unref(mapfile); } +}; +filemap* filemap::create(const char * filename) +{ + filemap* ret = filemap_gtk::create(filename); + if (!ret) ret = filemap::create_fallback(filename); + return ret; +} + + static bool canShowGUI; static GtkWidget* window; @@ -480,13 +506,14 @@ static void a_ApplyPatch(GtkButton* widget, gpointer user_data) if (!inromname) return; state.romext=GetExtension(inromname); if (!*state.romext) state.romext=".sfc"; - state.rommem=ReadWholeFile(inromname); + filemap* map=filemap::create(inromname); + state.rommem=map->get(); state.removeHeaders=shouldRemoveHeader(inromname, state.rommem.len); state.worsterror=e_none; state.anySuccess=false; g_slist_foreach(filenames, ApplyPatchMulti, &state); g_free(inromname); - FreeFileMemory(state.rommem); + delete map; struct errorinfo errormessages[2][8]={ { //no error-free diff --git a/flips-w32.cpp b/flips-w32.cpp index 6f81c7b..8e8e210 100644 --- a/flips-w32.cpp +++ b/flips-w32.cpp @@ -74,6 +74,10 @@ public: filewrite* filewrite::create(LPCWSTR filename) { return filewrite_w32::create(filename); } +//TODO: implement properly +filemap* filemap::create(LPCWSTR filename) { return filemap::create_fallback(filename); } + + HWND hwndMain=NULL; HWND hwndSettings=NULL; @@ -361,7 +365,8 @@ int a_ApplyPatch(LPCWSTR clipatchname) thisFileName++; LPWSTR thisPatchName=wcschr(patchnames, '\0')+1; LPCWSTR romExtension=GetExtension(inromname); - struct mem inrom=ReadWholeFile(inromname); + filemap* inrommap=filemap::create(inromname); + struct mem inrom=inrommap->get(); bool anySuccess=false; enum { e_none, e_notice, e_warning, e_invalid_this, e_invalid, e_io_write, e_io_read, e_io_read_rom } worsterror=e_none; enum errorlevel severity[2][8]={ @@ -419,7 +424,7 @@ int a_ApplyPatch(LPCWSTR clipatchname) } } else worsterror=e_io_read_rom; - FreeFileMemory(inrom); + delete inrommap; MessageBoxA(hwndMain, messages[anySuccess][worsterror], flipsversion, mboxtype[severity[anySuccess][worsterror]]); return severity[anySuccess][worsterror]; #undef max diff --git a/flips.cpp b/flips.cpp index db6b6b0..c40cea7 100644 --- a/flips.cpp +++ b/flips.cpp @@ -100,6 +100,32 @@ public: filewrite* filewrite::create_libc(const char * filename) { return filewrite_libc::create(filename); } +class filemap_fallback : public filemap { +public: + file* m_f; + size_t m_len; + uint8_t* m_ptr; + + static filemap* create(file* f) + { + size_t len = f->len(); + uint8_t* ptr = (uint8_t*)malloc(len); + if (!f->read(ptr, 0, len)) { free(ptr); return NULL; } + return new filemap_fallback(f, len, ptr); + } + + size_t len() { return m_len; } + const uint8_t * ptr() { return m_ptr; } + + filemap_fallback(file* f, size_t len, uint8_t* ptr) : m_f(f), m_len(len), m_ptr(ptr) {} + ~filemap_fallback() { free(m_ptr); delete m_f; } +}; +filemap* filemap::create_fallback(LPCWSTR filename) +{ + return filemap_fallback::create(file::create(filename)); +} + + @@ -181,6 +207,19 @@ public: ~fileheader() { delete child; } }; +class fileheadermap : public filemap { + filemap* child; + +public: + fileheadermap(filemap* child) : child(child) {} + + size_t len() { return child->len()-512; } + //bool read(uint8_t* target, size_t start, size_t len) { return child->read(target, start+512, len); } + const uint8_t* ptr() { return child->ptr()+512; } + + ~fileheadermap() { delete child; } +}; + @@ -751,15 +790,16 @@ bool shouldRemoveHeader(LPCWSTR romname, size_t romlen) struct errorinfo ApplyPatchMem(file* patch, LPCWSTR inromname, bool verifyinput, LPCWSTR outromname, struct manifestinfo * manifestinfo, bool update_rom_list) { - struct mem inrom=ReadWholeFile(inromname); - if (!inrom.ptr) + filemap* inrom = filemap::create(inromname); + if (!inrom) { if (update_rom_list) DeleteRomFromList(inromname); return error(el_broken, "Couldn't read ROM. What exactly are you doing?"); } - struct errorinfo errinf=ApplyPatchMem2(patch, inrom, verifyinput, shouldRemoveHeader(inromname, inrom.len), outromname, manifestinfo); + struct errorinfo errinf = ApplyPatchMem2(patch, inrom->get(), verifyinput, + shouldRemoveHeader(inromname, inrom->len()), outromname, manifestinfo); if (update_rom_list && errinf.level==el_ok) AddToRomList(patch, inromname); - FreeFileMemory(inrom); + delete inrom; return errinf; } @@ -810,19 +850,46 @@ bool bpsdeltaProgressCLI(void* userdata, size_t done, size_t total) struct errorinfo CreatePatchToMem(LPCWSTR inromname, LPCWSTR outromname, enum patchtype patchtype, struct manifestinfo * manifestinfo, struct mem * patchmem) { + bool usemmap = (patchtype!=ty_bps && patchtype!=ty_bps_moremem); + //pick roms + filemap* romsmap[2]={NULL, NULL}; file* roms[2]={NULL, NULL}; + size_t lens[2]; + for (int i=0;i<2;i++) { LPCWSTR romname=((i==0)?inromname:outromname); - roms[i] = file::create(romname); - if (!roms[i]) + + if (usemmap) { - return error(el_broken, "Couldn't read this ROM. What exactly are you doing?"); + romsmap[i] = filemap::create(romname); + lens[i] = romsmap[i]->len(); + + if (!romsmap[i]) + { + if (i==1) delete romsmap[0]; + return error(el_broken, "Couldn't read this ROM. What exactly are you doing?"); + } + if (shouldRemoveHeader(romname, romsmap[i]->len()) && (patchtype==ty_bps || patchtype==ty_bps_linear || patchtype==ty_bps_moremem)) + { + romsmap[i] = new fileheadermap(romsmap[i]); + } } - if (shouldRemoveHeader(romname, roms[i]->len()) && (patchtype==ty_bps || patchtype==ty_bps_linear || patchtype==ty_bps_moremem)) + else { - roms[i] = new fileheader(roms[i]); + roms[i] = file::create(romname); + lens[i] = roms[i]->len(); + + if (!roms[i]) + { + if (i==1) delete roms[0]; + return error(el_broken, "Couldn't read this ROM. What exactly are you doing?"); + } + if (shouldRemoveHeader(romname, roms[i]->len()) && (patchtype==ty_bps || patchtype==ty_bps_linear || patchtype==ty_bps_moremem)) + { + roms[i] = new fileheader(roms[i]); + } } } @@ -843,10 +910,7 @@ struct errorinfo CreatePatchToMem(LPCWSTR inromname, LPCWSTR outromname, enum pa struct errorinfo errinf={ el_broken, "Unknown patch format." }; if (patchtype==ty_ips) { - struct mem rommem[2]={ roms[0]->read(), roms[1]->read() }; - errinf=ipserrors[ips_create(rommem[0], rommem[1], patchmem)]; - free(rommem[0].ptr); - free(rommem[1].ptr); + errinf=ipserrors[ips_create(romsmap[0]->get(), romsmap[1]->get(), patchmem)]; } if (patchtype==ty_bps || patchtype==ty_bps_moremem) { @@ -865,24 +929,29 @@ struct errorinfo CreatePatchToMem(LPCWSTR inromname, LPCWSTR outromname, enum pa } if (patchtype==ty_bps_linear) { - struct mem rommem[2]={ roms[0]->read(), roms[1]->read() }; - errinf=bpserrors[bps_create_linear(rommem[0], rommem[1], manifest, patchmem)]; - free(rommem[0].ptr); - free(rommem[1].ptr); + errinf=bpserrors[bps_create_linear(romsmap[0]->get(), romsmap[1]->get(), manifest, patchmem)]; } FreeFileMemory(manifest); if (errinf.level==el_ok) errinf.description="The patch was created successfully!"; if (manifestinfo->required && errinf.level==el_ok && manifesterr.level!=el_ok) errinf=manifesterr; - if (errinf.level==el_ok && roms[0]->len() > roms[1]->len()) + if (errinf.level==el_ok && lens[0] > lens[1]) { errinf=error(el_warning, "The patch was created, but the input ROM is larger than the " "output ROM. Double check whether you've gotten them backwards."); } - delete roms[0]; - delete roms[1]; + if (usemmap) + { + delete romsmap[0]; + delete romsmap[1]; + } + else + { + delete roms[0]; + delete roms[1]; + } return errinf; } diff --git a/global.h b/global.h index ae8acbe..1c609c2 100644 --- a/global.h +++ b/global.h @@ -41,6 +41,18 @@ public: virtual ~file() {} }; +class filemap { +public: + static filemap* create(LPCWSTR filename); + static filemap* create_fallback(LPCWSTR filename); + + virtual size_t len() = 0; + virtual const uint8_t * ptr() = 0; + struct mem get() { return (struct mem){ (uint8_t*)ptr(), len() }; } + + virtual ~filemap() {} +}; + class filewrite { public: static filewrite* create(LPCWSTR filename);