#ifndef _library__fileimage__hpp__included__ #define _library__fileimage__hpp__included__ #include #include #include #include #include "threadtypes.hpp" class sha256_hasher; /** * Future for SHA-256 computation. */ class sha256_future { public: /** * Construct a null future, never resolves. */ sha256_future(); /** * Construct a future, with value that is immediately resolved. */ sha256_future(const std::string& value); /** * Is the result known? */ bool ready() const; /** * Read the result (or throw error). Waits until result is ready. */ std::string read() const; /** * Copy a future. */ sha256_future(const sha256_future& f); /** * Assign a future. */ sha256_future& operator=(const sha256_future& f); /** * Destroy a future. */ ~sha256_future(); private: /** * Create a new future. */ sha256_future(sha256_hasher& h, unsigned id); /** * Resolve a future. */ void resolve(unsigned id, const std::string& hash); void resolve_error(unsigned id, const std::string& err); friend class sha256_hasher; mutable mutex_class mutex; mutable cv_class condition; bool is_ready; unsigned cbid; std::string value; std::string error; sha256_future* prev; sha256_future* next; sha256_hasher* hasher; }; /** * Class performing SHA-256 hashing. */ class sha256_hasher { public: /** * Create a new SHA-256 hasher. */ sha256_hasher(); /** * Destroy a SHA-256 hasher. Causes all current jobs to fail. */ ~sha256_hasher(); /** * Set callback. */ void set_callback(std::function cb); /** * Compute SHA-256 of file. */ sha256_future operator()(const std::string& filename); /** * Thread entrypoint. */ void entrypoint(); private: void link(sha256_future& future); void unlink(sha256_future& future); void send_callback(uint64_t this_completed); void send_idle(); friend class sha256_future; struct queue_job { std::string filename; uint64_t size; unsigned cbid; volatile unsigned interested; }; sha256_hasher(const sha256_hasher&); sha256_hasher& operator=(const sha256_hasher&); thread_class* hash_thread; mutex_class mutex; cv_class condition; std::list queue; std::list::iterator current_job; sha256_future* first_future; sha256_future* last_future; unsigned next_cbid; std::function progresscb; bool quitting; uint64_t total_work; }; /** * Some loaded data or indication of no data. * * The loaded images are copied in CoW manner. */ struct loaded_image { /** * Information about image to load. */ struct info { enum _type { IT_NONE, //Only used in type field of image. IT_MEMORY, IT_MARKUP, IT_FILE }; _type type; unsigned headersize; }; /** * Construct empty image. * * throws std::bad_alloc: Not enough memory. */ loaded_image() throw(std::bad_alloc); /** * This constructor construct slot by reading data from file. If filename is "", constructs an empty slot. * * parameter hasher: Hasher to use. * parameter filename: The filename to read. If "", empty slot is constructed. * parameter base: Base filename to interpret the filename against. If "", no base filename is used. * parameter imginfo: Image information. * 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, const struct info& imginfo) throw(std::bad_alloc, std::runtime_error); /** * This method patches this slot using specified IPS patch. * * If the object was shared, this breaks the sharing, with this object gaining dedicated copy. * * parameter patch: The patch to apply * parameter offset: The amount to add to the offsets in the IPS file. Parts with offsets below zero are not patched. * throws std::bad_alloc: Not enough memory. * throws std::runtime_error: Bad IPS patch, or trying to patch file image. */ void patch(const std::vector& patch, int32_t offset) throw(std::bad_alloc, std::runtime_error); /** * Type. */ info::_type type; /** * Filename this is loaded from. */ std::string filename; /** * ROM name hint. */ std::string namehint; /** * The actual data for this slot. */ std::shared_ptr> data; /** * SHA-256 for the data in this slot if data is valid. If no valid data, this field is "". * * Note, for file images, this takes a bit of time to fill. */ sha256_future sha_256; /** * Get pointer to loaded data * * returns: Pointer to loaded data, or NULL if slot is blank. */ operator const char*() const throw() { return data ? reinterpret_cast(&(*data)[0]) : NULL; } /** * Get pointer to loaded data * * returns: Pointer to loaded data, or NULL if slot is blank. */ operator const uint8_t*() const throw() { return data ? reinterpret_cast(&(*data)[0]) : NULL; } /** * Get size of slot * * returns: The number of bytes in slot, or 0 if slot is blank. */ operator unsigned() const throw() { return data ? data->size() : 0; } }; #endif