impr: Handle provider opening more centrally, switch to existing provider if same file is being opened again

(cherry picked from commit 89004574d3)
This commit is contained in:
WerWolv
2025-12-17 12:55:24 +01:00
parent cae063985a
commit 51d773cf14
46 changed files with 208 additions and 155 deletions

View File

@@ -15,7 +15,7 @@ namespace hex {
* This event is responsible for (optionally) initializing the provider and calling EventProviderOpened
* (although the event can also be called manually without problem)
*/
EVENT_DEF(EventProviderCreated, prv::Provider *);
EVENT_DEF(EventProviderCreated, std::shared_ptr<prv::Provider>);
/**
* @brief Called as a continuation of EventProviderCreated

View File

@@ -10,6 +10,11 @@ namespace hex {
*/
EVENT_DEF(RequestCreateProvider, std::string, bool, bool, std::shared_ptr<hex::prv::Provider> *);
/**
* @brief Used internally when opening a provider through the API
*/
EVENT_DEF(RequestOpenProvider, std::shared_ptr<prv::Provider>);
/**
* @brief Move the data from all PerProvider instances from one provider to another
*

View File

@@ -117,6 +117,12 @@ EXPORT_MODULE namespace hex {
bool select = true
);
/**
* @brief Opens a provider, making its data available to ImHex and handling any error that may occur
* @param provider The provider to open
*/
void openProvider(std::shared_ptr<prv::Provider> provider);
}
}

View File

@@ -21,7 +21,7 @@ namespace hex::prv {
CachedProvider(size_t cacheBlockSize = 4096, size_t maxBlocks = 1024);
~CachedProvider() override;
bool open() override;
OpenResult open() override;
void close() override;
void readRaw(u64 offset, void *buffer, size_t size) override;

View File

@@ -27,7 +27,7 @@ namespace hex::prv {
[[nodiscard]] bool isSavable() const override { return m_name.empty(); }
[[nodiscard]] bool isSavableAsRecent() const override { return false; }
[[nodiscard]] bool open() override;
[[nodiscard]] OpenResult open() override;
void close() override { }
void readRaw(u64 offset, void *buffer, size_t size) override;

View File

@@ -79,6 +79,65 @@ namespace hex::prv {
public:
constexpr static u64 MaxPageSize = 0xFFFF'FFFF'FFFF'FFFF;
class OpenResult {
public:
OpenResult() : m_result(std::monostate{}) {}
[[nodiscard]] static OpenResult failure(std::string errorMessage) {
OpenResult result;
result.m_result = std::move(errorMessage);
return result;
}
[[nodiscard]] static OpenResult warning(std::string warningMessage) {
OpenResult result;
result.m_result = std::move(warningMessage);
result.m_warning = true;
return result;
}
[[nodiscard]] static OpenResult redirect(Provider *provider) {
OpenResult result;
result.m_result = provider;
return result;
}
[[nodiscard]] bool isSuccess() const {
return std::holds_alternative<std::monostate>(m_result);
}
[[nodiscard]] bool isFailure() const {
return std::holds_alternative<std::string>(m_result) && !m_warning;
}
[[nodiscard]] bool isWarning() const {
return std::holds_alternative<std::string>(m_result) && m_warning;
}
[[nodiscard]] bool isRedirecting() const {
return std::holds_alternative<Provider*>(m_result);
}
[[nodiscard]] Provider* getRedirectProvider() const {
if (std::holds_alternative<Provider*>(m_result)) {
return std::get<Provider*>(m_result);
}
return nullptr;
}
[[nodiscard]] std::string_view getErrorMessage() const {
if (std::holds_alternative<std::string>(m_result)) {
return std::get<std::string>(m_result);
}
return "";
}
private:
std::variant<std::monostate, std::string, Provider*> m_result;
bool m_warning = false;
};
Provider();
virtual ~Provider();
Provider(const Provider&) = delete;
@@ -94,7 +153,7 @@ namespace hex::prv {
* @note This is not related to the EventProviderOpened event
* @return true if the provider was opened successfully, else false
*/
[[nodiscard]] virtual bool open() = 0;
[[nodiscard]] virtual OpenResult open() = 0;
/**
* @brief Closes this provider
@@ -262,9 +321,6 @@ namespace hex::prv {
void skipLoadInterface() { m_skipLoadInterface = true; }
[[nodiscard]] bool shouldSkipLoadInterface() const { return m_skipLoadInterface; }
void setErrorMessage(const std::string &errorMessage) { m_errorMessage = errorMessage; }
[[nodiscard]] const std::string& getErrorMessage() const { return m_errorMessage; }
template<std::derived_from<undo::Operation> T>
bool addUndoableOperation(auto && ... args) {
return m_undoRedoStack.add<T>(std::forward<decltype(args)...>(args)...);
@@ -296,8 +352,6 @@ namespace hex::prv {
*/
bool m_skipLoadInterface = false;
std::string m_errorMessage = "Unspecified error";
u64 m_pageSize = MaxPageSize;
};

View File

@@ -391,7 +391,7 @@ namespace hex {
if (skipLoadInterface)
provider->skipLoadInterface();
EventProviderCreated::post(provider.get());
EventProviderCreated::post(provider);
s_providers->emplace_back(std::move(provider));
if (select || s_providers->size() == 1)
@@ -498,6 +498,10 @@ namespace hex {
return result;
}
void openProvider(std::shared_ptr<prv::Provider> provider) {
RequestOpenProvider::post(provider);
}
}
namespace ImHexApi::System {

View File

@@ -24,7 +24,7 @@ namespace hex {
[[nodiscard]] bool isSavable() const override { return false; }
[[nodiscard]] bool isSavableAsRecent() const override { return false; }
[[nodiscard]] bool open() override { return true; }
[[nodiscard]] OpenResult open() override { return {}; }
void close() override { }
void readRaw(u64 offset, void *buffer, size_t size) override {

View File

@@ -11,9 +11,9 @@ namespace hex::prv {
clearCache();
}
bool CachedProvider::open() {
Provider::OpenResult CachedProvider::open() {
clearCache();
return true;
return {};
}
void CachedProvider::close() {

View File

@@ -4,12 +4,12 @@
namespace hex::prv {
bool MemoryProvider::open() {
Provider::OpenResult MemoryProvider::open() {
if (m_data.empty()) {
m_data.resize(1);
}
return true;
return {};
}
void MemoryProvider::readRaw(u64 offset, void *buffer, size_t size) {