Refactor library fileimage to dedicated namespace

This commit is contained in:
Ilari Liusvaara 2013-12-21 00:55:31 +02:00
parent 2ce7872f39
commit 371c6fd9e3
7 changed files with 105 additions and 98 deletions

View file

@ -64,11 +64,11 @@ struct loaded_rom
/**
* Loaded main ROM
*/
loaded_image romimg[ROM_SLOT_COUNT];
fileimage::image romimg[ROM_SLOT_COUNT];
/**
* Loaded main ROM XML
*/
loaded_image romxml[ROM_SLOT_COUNT];
fileimage::image romxml[ROM_SLOT_COUNT];
/**
* MSU-1 base.
*/
@ -131,7 +131,7 @@ extern std::map<std::string, core_type*> preferred_core;
//Preferred overall core.
extern std::string preferred_core_default;
//Main hasher
extern sha256_hasher lsnes_image_hasher;
extern fileimage::hash lsnes_image_hasher;
#endif

View file

@ -7,22 +7,24 @@
#include <vector>
#include "threadtypes.hpp"
class sha256_hasher;
namespace fileimage
{
class hash;
/**
* Future for SHA-256 computation.
*/
class sha256_future
class hashval
{
public:
/**
* Construct a null future, never resolves.
*/
sha256_future();
hashval();
/**
* Construct a future, with value that is immediately resolved.
*/
sha256_future(const std::string& value, uint64_t _prefix = 0);
hashval(const std::string& value, uint64_t _prefix = 0);
/**
* Is the result known?
*/
@ -38,27 +40,27 @@ public:
/**
* Copy a future.
*/
sha256_future(const sha256_future& f);
hashval(const hashval& f);
/**
* Assign a future.
*/
sha256_future& operator=(const sha256_future& f);
hashval& operator=(const hashval& f);
/**
* Destroy a future.
*/
~sha256_future();
~hashval();
private:
/**
* Create a new future.
*/
sha256_future(sha256_hasher& h, unsigned id);
hashval(hash& h, unsigned id);
/**
* Resolve a future.
*/
void resolve(unsigned id, const std::string& hash, uint64_t _prefix);
void resolve_error(unsigned id, const std::string& err);
friend class sha256_hasher;
friend class hash;
mutable mutex_class mutex;
mutable cv_class condition;
bool is_ready;
@ -66,25 +68,25 @@ private:
uint64_t prefixv;
std::string value;
std::string error;
sha256_future* prev;
sha256_future* next;
sha256_hasher* hasher;
hashval* prev;
hashval* next;
hash* hasher;
};
/**
* Class performing SHA-256 hashing.
*/
class sha256_hasher
class hash
{
public:
/**
* Create a new SHA-256 hasher.
*/
sha256_hasher();
hash();
/**
* Destroy a SHA-256 hasher. Causes all current jobs to fail.
*/
~sha256_hasher();
~hash();
/**
* Set callback.
*/
@ -92,22 +94,22 @@ public:
/**
* Compute SHA-256 of file.
*/
sha256_future operator()(const std::string& filename, uint64_t prefixlen = 0);
hashval operator()(const std::string& filename, uint64_t prefixlen = 0);
/**
* Compute SHA-256 of file.
*/
sha256_future operator()(const std::string& filename, std::function<uint64_t(uint64_t)> prefixlen);
hashval operator()(const std::string& filename, std::function<uint64_t(uint64_t)> prefixlen);
/**
* Thread entrypoint.
*/
void entrypoint();
private:
void link(sha256_future& future);
void unlink(sha256_future& future);
void link(hashval& future);
void unlink(hashval& future);
void send_callback(uint64_t this_completed);
void send_idle();
friend class sha256_future;
friend class hashval;
struct queue_job
{
std::string filename;
@ -116,15 +118,15 @@ private:
unsigned cbid;
volatile unsigned interested;
};
sha256_hasher(const sha256_hasher&);
sha256_hasher& operator=(const sha256_hasher&);
hash(const hash&);
hash& operator=(const hash&);
thread_class* hash_thread;
mutex_class mutex;
cv_class condition;
std::list<queue_job> queue;
std::list<queue_job>::iterator current_job;
sha256_future* first_future;
sha256_future* last_future;
hashval* first_future;
hashval* last_future;
unsigned next_cbid;
std::function<void(uint64_t, uint64_t)> progresscb;
bool quitting;
@ -137,7 +139,7 @@ private:
*
* The loaded images are copied in CoW manner.
*/
struct loaded_image
struct image
{
/**
* Information about image to load.
@ -159,7 +161,7 @@ struct loaded_image
*
* throws std::bad_alloc: Not enough memory.
*/
loaded_image() throw(std::bad_alloc);
image() throw(std::bad_alloc);
/**
* This constructor construct slot by reading data from file. If filename is "", constructs an empty slot.
@ -171,7 +173,7 @@ struct loaded_image
* throws std::bad_alloc: Not enough memory.
* throws std::runtime_error: Can't load the data.
*/
loaded_image(sha256_hasher& hasher, const std::string& filename, const std::string& base,
image(hash& hasher, const std::string& filename, const std::string& base,
const struct info& imginfo) throw(std::bad_alloc, std::runtime_error);
/**
@ -210,7 +212,7 @@ struct loaded_image
*
* Note, for file images, this takes a bit of time to fill.
*/
sha256_future sha_256;
hashval sha_256;
/**
* Get pointer to loaded data
*
@ -244,5 +246,5 @@ struct loaded_image
* Get headersize function.
*/
std::function<uint64_t(uint64_t)> std_headersize_fn(uint64_t hdrsize);
}
#endif

View file

@ -79,7 +79,7 @@ namespace
messages << "Saved core state to " << name << std::endl;
});
bool warn_hash_mismatch(const std::string& mhash, const loaded_image& slot,
bool warn_hash_mismatch(const std::string& mhash, const fileimage::image& slot,
const std::string& name, bool fatal)
{
if(mhash == slot.sha_256.read())

View file

@ -185,19 +185,19 @@ namespace
return fallback;
}
struct loaded_image::info get_xml_info()
struct fileimage::image::info get_xml_info()
{
loaded_image::info i;
i.type = loaded_image::info::IT_MARKUP;
fileimage::image::info i;
i.type = fileimage::image::info::IT_MARKUP;
i.headersize = 0;
return i;
}
struct loaded_image::info xlate_info(core_romimage_info ri)
struct fileimage::image::info xlate_info(core_romimage_info ri)
{
loaded_image::info i;
if(ri.pass_mode == 0) i.type = loaded_image::info::IT_MEMORY;
if(ri.pass_mode == 1) i.type = loaded_image::info::IT_FILE;
fileimage::image::info i;
if(ri.pass_mode == 0) i.type = fileimage::image::info::IT_MEMORY;
if(ri.pass_mode == 1) i.type = fileimage::image::info::IT_FILE;
i.headersize = ri.headersize;
return i;
}
@ -217,7 +217,7 @@ namespace
}
}
sha256_hasher lsnes_image_hasher;
fileimage::hash lsnes_image_hasher;
std::pair<core_type*, core_region*> get_current_rom_info() throw()
{
@ -243,14 +243,14 @@ loaded_rom::loaded_rom(const std::string& file, core_type& ctype) throw(std::bad
//This thing has a BIOS.
romidx = 1;
std::string basename = lsnes_vset["firmwarepath"].str() + "/" + bios;
romimg[0] = loaded_image(lsnes_image_hasher, basename, "", xlate_info(ctype.get_image_info(0)));
romimg[0] = fileimage::image(lsnes_image_hasher, basename, "", xlate_info(ctype.get_image_info(0)));
if(zip::file_exists(basename + ".xml"))
romxml[0] = loaded_image(lsnes_image_hasher, basename + ".xml", "", get_xml_info());
romxml[0] = fileimage::image(lsnes_image_hasher, basename + ".xml", "", get_xml_info());
pmand |= ctype.get_image_info(0).mandatory;
}
romimg[romidx] = loaded_image(lsnes_image_hasher, file, "", xlate_info(ctype.get_image_info(romidx)));
romimg[romidx] = fileimage::image(lsnes_image_hasher, file, "", xlate_info(ctype.get_image_info(romidx)));
if(zip::file_exists(file + ".xml"))
romxml[romidx] = loaded_image(lsnes_image_hasher, file + ".xml", "", get_xml_info());
romxml[romidx] = fileimage::image(lsnes_image_hasher, file + ".xml", "", get_xml_info());
pmand |= ctype.get_image_info(romidx).mandatory;
msu1_base = zip::resolverel(file, "");
record_files(*this);
@ -284,16 +284,17 @@ loaded_rom::loaded_rom(const std::string& file, const std::string& tmpprefer) th
//This thing has a BIOS.
romidx = 1;
std::string basename = lsnes_vset["firmwarepath"].str() + "/" + bios;
romimg[0] = loaded_image(lsnes_image_hasher, basename, "",
romimg[0] = fileimage::image(lsnes_image_hasher, basename, "",
xlate_info(coretype->get_image_info(0)));
if(zip::file_exists(basename + ".xml"))
romxml[0] = loaded_image(lsnes_image_hasher, basename + ".xml", "", get_xml_info());
romxml[0] = fileimage::image(lsnes_image_hasher, basename + ".xml", "",
get_xml_info());
pmand |= rtype->get_image_info(0).mandatory;
}
romimg[romidx] = loaded_image(lsnes_image_hasher, file, "",
romimg[romidx] = fileimage::image(lsnes_image_hasher, file, "",
xlate_info(coretype->get_image_info(romidx)));
if(zip::file_exists(file + ".xml"))
romxml[romidx] = loaded_image(lsnes_image_hasher, file + ".xml", "", get_xml_info());
romxml[romidx] = fileimage::image(lsnes_image_hasher, file + ".xml", "", get_xml_info());
pmand |= rtype->get_image_info(romidx).mandatory;
msu1_base = zip::resolverel(file, "");
record_files(*this);
@ -369,8 +370,9 @@ loaded_rom::loaded_rom(const std::string& file, const std::string& tmpprefer) th
//Load ROMs.
for(size_t i = 0; i < rtype->get_image_count(); i++) {
romimg[i] = loaded_image(lsnes_image_hasher, cromimg[i], file, xlate_info(rtype->get_image_info(i)));
romxml[i] = loaded_image(lsnes_image_hasher, cromxml[i], file, get_xml_info());
romimg[i] = fileimage::image(lsnes_image_hasher, cromimg[i], file,
xlate_info(rtype->get_image_info(i)));
romxml[i] = fileimage::image(lsnes_image_hasher, cromxml[i], file, get_xml_info());
}
record_files(*this); //Have to do this before patching.
@ -483,14 +485,14 @@ loaded_rom::loaded_rom(const std::string& file, const std::string& core, const s
unsigned romidx = (bios != "") ? 1 : 0;
if(bios != "") {
std::string basename = lsnes_vset["firmwarepath"].str() + "/" + bios;
romimg[0] = loaded_image(lsnes_image_hasher, basename, "", xlate_info(t->get_image_info(0)));
romimg[0] = fileimage::image(lsnes_image_hasher, basename, "", xlate_info(t->get_image_info(0)));
if(zip::file_exists(basename + ".xml"))
romxml[0] = loaded_image(lsnes_image_hasher, basename + ".xml", "", get_xml_info());
romxml[0] = fileimage::image(lsnes_image_hasher, basename + ".xml", "", get_xml_info());
pmand |= t->get_image_info(0).mandatory;
}
romimg[romidx] = loaded_image(lsnes_image_hasher, file, "", xlate_info(t->get_image_info(romidx)));
romimg[romidx] = fileimage::image(lsnes_image_hasher, file, "", xlate_info(t->get_image_info(romidx)));
if(zip::file_exists(file + ".xml"))
romxml[romidx] = loaded_image(lsnes_image_hasher, file + ".xml", "", get_xml_info());
romxml[romidx] = fileimage::image(lsnes_image_hasher, file + ".xml", "", get_xml_info());
pmand |= t->get_image_info(romidx).mandatory;
msu1_base = zip::resolverel(file, "");
record_files(*this);
@ -532,9 +534,9 @@ loaded_rom::loaded_rom(const std::string file[ROM_SLOT_COUNT], const std::string
if(file[i] != "")
pmand |= t->get_image_info(i).mandatory;
tmand |= t->get_image_info(i).mandatory;
romimg[i] = loaded_image(lsnes_image_hasher, file[i], "", xlate_info(t->get_image_info(i)));
romimg[i] = fileimage::image(lsnes_image_hasher, file[i], "", xlate_info(t->get_image_info(i)));
if(zip::file_exists(file[i] + ".xml"))
romxml[i] = loaded_image(lsnes_image_hasher, file[i] + ".xml", "", get_xml_info());
romxml[i] = fileimage::image(lsnes_image_hasher, file[i] + ".xml", "", get_xml_info());
}
msu1_base = zip::resolverel(file[romidx], "");
record_files(*this);

View file

@ -94,7 +94,7 @@ namespace
return "";
}
try {
sha256_future f = lsnes_image_hasher(file, std_headersize_fn(hsize));
fileimage::hashval f = lsnes_image_hasher(file, fileimage::std_headersize_fn(hsize));
std::string hash = f.read();
uint64_t prefix = f.prefix();
record_hash(file, prefix, hash);

View file

@ -7,6 +7,8 @@
#include "directory.hpp"
#include <sstream>
namespace fileimage
{
namespace
{
std::map<std::string, std::pair<time_t, std::string>> cached_entries;
@ -24,7 +26,7 @@ namespace
return 0;
}
void* thread_trampoline(sha256_hasher* h)
void* thread_trampoline(hash* h)
{
h->entrypoint();
return NULL;
@ -94,7 +96,7 @@ namespace
}
}
sha256_future::sha256_future()
hashval::hashval()
{
is_ready = false;
cbid = 0;
@ -102,7 +104,7 @@ sha256_future::sha256_future()
hasher = NULL;
}
sha256_future::sha256_future(const std::string& _value, uint64_t _prefix)
hashval::hashval(const std::string& _value, uint64_t _prefix)
{
is_ready = true;
value = _value;
@ -112,7 +114,7 @@ sha256_future::sha256_future(const std::string& _value, uint64_t _prefix)
hasher = NULL;
}
sha256_future::sha256_future(sha256_hasher& h, unsigned id)
hashval::hashval(hash& h, unsigned id)
{
umutex_class h2(global_queue_mutex());
is_ready = false;
@ -122,7 +124,7 @@ sha256_future::sha256_future(sha256_hasher& h, unsigned id)
hasher->link(*this);
}
sha256_future::~sha256_future()
hashval::~hashval()
{
umutex_class h2(global_queue_mutex());
umutex_class h(mutex);
@ -130,13 +132,13 @@ sha256_future::~sha256_future()
hasher->unlink(*this);
}
bool sha256_future::ready() const
bool hashval::ready() const
{
umutex_class h(mutex);
return is_ready;
}
std::string sha256_future::read() const
std::string hashval::read() const
{
umutex_class h(mutex);
while(!is_ready)
@ -146,7 +148,7 @@ std::string sha256_future::read() const
return value;
}
uint64_t sha256_future::prefix() const
uint64_t hashval::prefix() const
{
umutex_class h(mutex);
while(!is_ready)
@ -156,7 +158,7 @@ uint64_t sha256_future::prefix() const
return prefixv;
}
sha256_future::sha256_future(const sha256_future& f)
hashval::hashval(const hashval& f)
{
umutex_class h2(global_queue_mutex());
umutex_class h(f.mutex);
@ -171,7 +173,7 @@ sha256_future::sha256_future(const sha256_future& f)
hasher->link(*this);
}
sha256_future& sha256_future::operator=(const sha256_future& f)
hashval& hashval::operator=(const hashval& f)
{
if(this == &f)
return *this;
@ -199,7 +201,7 @@ sha256_future& sha256_future::operator=(const sha256_future& f)
f.mutex.unlock();
}
void sha256_future::resolve(unsigned id, const std::string& hash, uint64_t _prefix)
void hashval::resolve(unsigned id, const std::string& hash, uint64_t _prefix)
{
umutex_class h(mutex);
hasher->unlink(*this);
@ -211,7 +213,7 @@ void sha256_future::resolve(unsigned id, const std::string& hash, uint64_t _pref
condition.notify_all();
}
void sha256_future::resolve_error(unsigned id, const std::string& err)
void hashval::resolve_error(unsigned id, const std::string& err)
{
umutex_class h(mutex);
hasher->unlink(*this);
@ -223,7 +225,7 @@ void sha256_future::resolve_error(unsigned id, const std::string& err)
condition.notify_all();
}
void sha256_hasher::link(sha256_future& future)
void hash::link(hashval& future)
{
//We assume caller holds global queue lock.
{
@ -242,7 +244,7 @@ void sha256_hasher::link(sha256_future& future)
first_future = &future;
}
void sha256_hasher::unlink(sha256_future& future)
void hash::unlink(hashval& future)
{
//We assume caller holds global queue lock.
{
@ -262,7 +264,7 @@ void sha256_hasher::unlink(sha256_future& future)
future.next->prev = future.prev;
}
sha256_future sha256_hasher::operator()(const std::string& filename, uint64_t prefixlen)
hashval hash::operator()(const std::string& filename, uint64_t prefixlen)
{
queue_job j;
j.filename = filename;
@ -270,7 +272,7 @@ sha256_future sha256_hasher::operator()(const std::string& filename, uint64_t pr
j.size = get_file_size(filename);
j.cbid = next_cbid++;
j.interested = 1;
sha256_future future(*this, j.cbid);
hashval future(*this, j.cbid);
queue.push_back(j);
umutex_class h(mutex);
total_work += j.size;
@ -279,7 +281,7 @@ sha256_future sha256_hasher::operator()(const std::string& filename, uint64_t pr
return future;
}
sha256_future sha256_hasher::operator()(const std::string& filename, std::function<uint64_t(uint64_t)> prefixlen)
hashval hash::operator()(const std::string& filename, std::function<uint64_t(uint64_t)> prefixlen)
{
queue_job j;
j.filename = filename;
@ -287,7 +289,7 @@ sha256_future sha256_hasher::operator()(const std::string& filename, std::functi
j.prefix = prefixlen(j.size);
j.cbid = next_cbid++;
j.interested = 1;
sha256_future future(*this, j.cbid);
hashval future(*this, j.cbid);
queue.push_back(j);
umutex_class h(mutex);
total_work += j.size;
@ -296,13 +298,13 @@ sha256_future sha256_hasher::operator()(const std::string& filename, std::functi
return future;
}
void sha256_hasher::set_callback(std::function<void(uint64_t, uint64_t)> cb)
void hash::set_callback(std::function<void(uint64_t, uint64_t)> cb)
{
umutex_class h(mutex);
progresscb = cb;
}
sha256_hasher::sha256_hasher()
hash::hash()
{
quitting = false;
first_future = NULL;
@ -314,7 +316,7 @@ sha256_hasher::sha256_hasher()
hash_thread = new thread_class(thread_trampoline, this);
}
sha256_hasher::~sha256_hasher()
hash::~hash()
{
{
umutex_class h(mutex);
@ -328,7 +330,7 @@ sha256_hasher::~sha256_hasher()
first_future->resolve_error(first_future->cbid, "Hasher deleted");
}
void sha256_hasher::entrypoint()
void hash::entrypoint()
{
FILE* fp;
while(true) {
@ -352,14 +354,14 @@ void sha256_hasher::entrypoint()
cached_hash = lookup_cache(current_job->filename, current_job->prefix);
if(cached_hash != "") {
umutex_class h2(global_queue_mutex());
for(sha256_future* fut = first_future; fut != NULL; fut = fut->next)
for(hashval* fut = first_future; fut != NULL; fut = fut->next)
fut->resolve(current_job->cbid, cached_hash, current_job->prefix);
goto finished;
}
fp = fopen(current_job->filename.c_str(), "rb");
if(!fp) {
umutex_class h2(global_queue_mutex());
for(sha256_future* fut = first_future; fut != NULL; fut = fut->next)
for(hashval* fut = first_future; fut != NULL; fut = fut->next)
fut->resolve_error(current_job->cbid, "Can't open file");
} else {
sha256 hash;
@ -382,12 +384,12 @@ void sha256_hasher::entrypoint()
}
if(ferror(fp)) {
umutex_class h2(global_queue_mutex());
for(sha256_future* fut = first_future; fut != NULL; fut = fut->next)
for(hashval* fut = first_future; fut != NULL; fut = fut->next)
fut->resolve_error(current_job->cbid, "Can't read file");
} else {
std::string hval = hash.read();
umutex_class h2(global_queue_mutex());
for(sha256_future* fut = first_future; fut != NULL; fut = fut->next)
for(hashval* fut = first_future; fut != NULL; fut = fut->next)
fut->resolve(current_job->cbid, hval, current_job->prefix);
store_cache(current_job->filename, current_job->prefix, hval);
}
@ -404,7 +406,7 @@ finished:
}
}
void sha256_hasher::send_callback(uint64_t this_completed)
void hash::send_callback(uint64_t this_completed)
{
uint64_t amount;
{
@ -417,28 +419,28 @@ void sha256_hasher::send_callback(uint64_t this_completed)
progresscb(amount, work_size);
}
void sha256_hasher::send_idle()
void hash::send_idle()
{
work_size = 0; //Delete work when idle.
progresscb(0xFFFFFFFFFFFFFFFFULL, 0);
}
loaded_image::loaded_image() throw(std::bad_alloc)
image::image() throw(std::bad_alloc)
{
type = info::IT_NONE;
sha_256 = sha256_future("");
sha_256 = hashval("");
filename = "";
}
loaded_image::loaded_image(sha256_hasher& h, const std::string& _filename, const std::string& base,
const struct loaded_image::info& info) throw(std::bad_alloc, std::runtime_error)
image::image(hash& h, const std::string& _filename, const std::string& base,
const struct image::info& info) throw(std::bad_alloc, std::runtime_error)
{
if(info.type == info::IT_NONE && _filename != "")
throw std::runtime_error("Tried to load NULL image");
if(_filename == "") {
//NULL.
type = info::IT_NONE;
sha_256 = sha256_future("");
sha_256 = hashval("");
stripped = 0;
return;
}
@ -472,7 +474,7 @@ loaded_image::loaded_image(sha256_hasher& h, const std::string& _filename, const
data->resize(0);
}
stripped = headered;
sha_256 = sha256_future(sha256::hash(*data), headered);
sha_256 = hashval(sha256::hash(*data), headered);
if(info.type == info::IT_MARKUP) {
size_t osize = data->size();
data->resize(osize + 1);
@ -493,7 +495,7 @@ loaded_image::loaded_image(sha256_hasher& h, const std::string& _filename, const
throw std::runtime_error("Unknown image type");
}
void loaded_image::patch(const std::vector<char>& patch, int32_t offset) throw(std::bad_alloc, std::runtime_error)
void image::patch(const std::vector<char>& patch, int32_t offset) throw(std::bad_alloc, std::runtime_error)
{
if(type == info::IT_NONE)
throw std::runtime_error("Not an image");
@ -512,7 +514,7 @@ void loaded_image::patch(const std::vector<char>& patch, int32_t offset) throw(s
data2[osize] = 0;
}
data.reset(new std::vector<char>(data2));
sha_256 = sha256_future(new_sha256);
sha_256 = hashval(new_sha256);
} catch(...) {
throw;
}
@ -523,3 +525,4 @@ std::function<uint64_t(uint64_t)> std_headersize_fn(uint64_t hdrsize)
uint64_t h = hdrsize;
return ([h](uint64_t x) -> uint64_t { return calculate_headersize(x, h); });
}
}

View file

@ -262,13 +262,13 @@ namespace
std::string filename = tostdstring(filenames[i]->GetValue());
if(!zip::file_exists(filename)) {
hashfutures[i] = sha256_future();
hashfutures[i] = fileimage::hashval();
hash_ready[i] = true;
hashes[i]->SetLabel(towxstring("Not found"));
return;
}
//TODO: Handle files inside ZIP files.
hashfutures[i] = lsnes_image_hasher(filename, std_headersize_fn(header));
hashfutures[i] = lsnes_image_hasher(filename, fileimage::std_headersize_fn(header));
if(hash_ready[i] = hashfutures[i].ready())
try {
hashes[i]->SetLabel(towxstring("Hash: " + hashfutures[i].read()));
@ -298,7 +298,7 @@ namespace
wxButton* fileselect[ROM_SLOT_COUNT];
wxStaticText* hashes[ROM_SLOT_COUNT];
bool hash_ready[ROM_SLOT_COUNT];
sha256_future hashfutures[ROM_SLOT_COUNT];
fileimage::hashval hashfutures[ROM_SLOT_COUNT];
wxButton* okb;
wxButton* cancelb;
update_timer* timer;
@ -408,7 +408,7 @@ again:
goto again;
}
try {
auto future = lsnes_image_hasher(req.filename[i], std_headersize_fn(header));
auto future = lsnes_image_hasher(req.filename[i], fileimage::std_headersize_fn(header));
//Dirty method to run the event loop until hashing finishes.
while(!future.ready()) {
wxSafeYield();