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

This commit is contained in:
WerWolv
2025-12-17 12:55:24 +01:00
parent c11c05a399
commit 89004574d3
48 changed files with 211 additions and 158 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

@@ -94,6 +94,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;
@@ -109,7 +168,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
@@ -277,9 +336,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)...);
@@ -311,8 +367,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) {

View File

@@ -29,7 +29,7 @@ namespace hex::plugin::builtin {
[[nodiscard]] std::string getName() const override;
[[nodiscard]] bool open() override;
[[nodiscard]] OpenResult open() override;
void close() override;
bool drawLoadInterface() override;

View File

@@ -30,7 +30,7 @@ namespace hex::plugin::builtin {
void setPath(const std::fs::path &path);
[[nodiscard]] bool open() override;
[[nodiscard]] OpenResult open() override;
void close() override;
[[nodiscard]] std::string getName() const override;

View File

@@ -44,7 +44,7 @@ namespace hex::plugin::builtin {
void setPath(const std::fs::path &path);
[[nodiscard]] bool open() override;
[[nodiscard]] OpenResult open() override;
void close() override;
void loadSettings(const nlohmann::json &settings) override;
@@ -66,7 +66,7 @@ namespace hex::plugin::builtin {
private:
void handleFileChange();
bool open(bool memoryMapped);
OpenResult open(bool memoryMapped);
protected:
std::fs::path m_path;

View File

@@ -35,7 +35,7 @@ namespace hex::plugin::builtin {
[[nodiscard]] std::string getName() const override;
[[nodiscard]] std::vector<Description> getDataDescription() const override;
[[nodiscard]] bool open() override;
[[nodiscard]] OpenResult open() override;
void close() override;
[[nodiscard]] bool isConnected() const;

View File

@@ -39,7 +39,7 @@ namespace hex::plugin::builtin {
[[nodiscard]] u64 getActualSize() const override;
void processMemoryRegions(wolv::util::Expected<std::map<u64, std::vector<u8>>, std::string> data);
static bool memoryRegionFilter(const std::string &search, const MemoryRegion &memoryRegion);
bool open() override;
OpenResult open() override;
void close() override;
[[nodiscard]] std::string getName() const override;

View File

@@ -18,7 +18,7 @@ namespace hex::plugin::builtin {
[[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

@@ -9,7 +9,7 @@ namespace hex::plugin::builtin {
MotorolaSRECProvider() = default;
~MotorolaSRECProvider() override = default;
bool open() override;
OpenResult open() override;
void close() override;
[[nodiscard]] std::string getName() const override;

View File

@@ -29,7 +29,7 @@ namespace hex::plugin::builtin {
[[nodiscard]] bool isResizable() const override { return false; }
[[nodiscard]] bool isSavable() 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

@@ -59,7 +59,7 @@ namespace hex::plugin::builtin {
};
}
[[nodiscard]] bool open() override;
[[nodiscard]] OpenResult open() override;
void close() override;
bool drawLoadInterface() override;

View File

@@ -30,7 +30,7 @@ namespace hex::plugin::builtin {
[[nodiscard]] bool drawLoadInterface() override;
void drawSidebarInterface() override;
[[nodiscard]] bool open() override;
[[nodiscard]] OpenResult open() override;
void close() override;
void loadSettings(const nlohmann::json &) override;

View File

@@ -20,7 +20,7 @@ namespace hex::plugin::builtin {
[[nodiscard]] bool isSavableAsRecent() const override;
void save() override;
[[nodiscard]] bool open() override;
[[nodiscard]] OpenResult open() override;
void close() override;
void resizeRaw(u64 newSize) override;

View File

@@ -420,7 +420,7 @@
"hex.builtin.provider.rename": "Rename",
"hex.builtin.provider.rename.desc": "Enter a name for this data source.",
"hex.builtin.provider.tooltip.show_more": "Hold SHIFT for more information",
"hex.builtin.provider.error.open": "Failed to open data provider: {}",
"hex.builtin.provider.error.open": "Failed to open data source: {}",
"hex.builtin.provider.base64": "Base64 File",
"hex.builtin.provider.command": "Terminal Command",
"hex.builtin.provider.command.name": "Command {0}",
@@ -442,6 +442,7 @@
"hex.builtin.provider.disk.error.read_rw": "Failed to open disk {} in read/write mode: {}",
"hex.builtin.provider.file": "Regular File",
"hex.builtin.provider.file.error.open": "Failed to open file {}: {}",
"hex.builtin.provider.file.error.already_open": "Same file is already open",
"hex.builtin.provider.file.access": "Last access time",
"hex.builtin.provider.file.creation": "Creation time",
"hex.builtin.provider.file.menu.direct_access": "Direct access file",
@@ -460,6 +461,7 @@
"hex.builtin.provider.gdb.name": "GDB Server <{0}:{1}>",
"hex.builtin.provider.gdb.port": "Port",
"hex.builtin.provider.gdb.server": "Server",
"hex.builtin.provider.gdb.server.error.not_connected": "Failed to open connection to GDB Server",
"hex.builtin.provider.intel_hex": "Intel Hex File",
"hex.builtin.provider.intel_hex.name": "Intel Hex {0}",
"hex.builtin.provider.mem_file": "In-Memory File",
@@ -470,6 +472,8 @@
"hex.builtin.provider.opening": "Opening Data Source...",
"hex.builtin.provider.process_memory": "Process Memory",
"hex.builtin.provider.process_memory.enumeration_failed": "Failed to enumerate processes",
"hex.builtin.provider.process_memory.error.no_process_selected": "No process selected",
"hex.builtin.provider.process_memory.error.open_process": "Failed to attach to process",
"hex.builtin.provider.process_memory.macos_limitations": "macOS doesn't properly allow reading memory from other processes, even when running as root. If System Integrity Protection (SIP) is enabled, it only works for applications that are unsigned or have the 'Get Task Allow' entitlement which generally only applies to applications compiled by yourself.",
"hex.builtin.provider.process_memory.memory_regions": "Memory Regions",
"hex.builtin.provider.process_memory.name": "'{0}' Process Memory",
@@ -488,6 +492,7 @@
"hex.builtin.provider.udp.port": "Server Port",
"hex.builtin.provider.udp.timestamp": "Timestamp",
"hex.builtin.provider.view": "View",
"hex.builtin.provider.view.error.no_provider": "No data source has been attached to this view",
"hex.builtin.setting.experiments": "Experiments",
"hex.builtin.setting.experiments.description": "Experiments are features that are still in development and may not work correctly yet.\n\nFeel free to try them out and report any issues you encounter!",
"hex.builtin.setting.folders": "Folders",

View File

@@ -360,10 +360,10 @@ namespace hex::plugin::builtin {
std::fs::path filePath = reinterpret_cast<const char8_t*>(args[0].data());
FileProvider provider;
provider.setPath(filePath);
if (!provider.open()) {
log::println("Failed to open file '{}'", args[0]);
auto result = provider.open();
if (!result.isFailure()) {
log::println("Failed to open file '{}': {}", args[0], result.getErrorMessage());
std::exit(EXIT_FAILURE);
}

View File

@@ -52,15 +52,10 @@ namespace hex::plugin::builtin {
auto provider = ImHexApi::Provider::createProvider("hex.builtin.provider.file", true);
if (auto *fileProvider = dynamic_cast<FileProvider*>(provider.get()); fileProvider != nullptr) {
fileProvider->setPath(path);
if (!provider->open() || !provider->isAvailable()) {
ui::ToastError::open(fmt::format("hex.builtin.provider.error.open"_lang, provider->getErrorMessage()));
TaskManager::doLater([provider] { ImHexApi::Provider::remove(provider.get()); });
return;
}
EventProviderOpened::post(fileProvider);
ImHexApi::Provider::openProvider(provider);
AchievementManager::unlockAchievement("hex.builtin.achievement.starting_out", "hex.builtin.achievement.starting_out.open_file.name");
ImHexApi::Provider::setCurrentProvider(provider.get());
glfwRequestWindowAttention(ImHexApi::System::getMainWindowHandle());
glfwFocusWindow(ImHexApi::System::getMainWindowHandle());
@@ -182,11 +177,8 @@ namespace hex::plugin::builtin {
RequestOpenWindow::subscribe([](const std::string &name) {
if (name == "Create File") {
auto newProvider = hex::ImHexApi::Provider::createProvider("hex.builtin.provider.mem_file", true);
if (newProvider != nullptr && !newProvider->open())
hex::ImHexApi::Provider::remove(newProvider.get());
else
EventProviderOpened::post(newProvider.get());
auto newProvider = ImHexApi::Provider::createProvider("hex.builtin.provider.mem_file", true);
ImHexApi::Provider::openProvider(newProvider);
} else if (name == "Open File") {
fs::openFileBrowser(fs::DialogMode::Open, { }, [](const auto &path) {
if (path.extension() == ".hexproj") {
@@ -204,12 +196,8 @@ namespace hex::plugin::builtin {
return;
newProvider->setPath(path);
if (!newProvider->open()) {
hex::ImHexApi::Provider::remove(newProvider);
} else {
EventProviderOpened::post(newProvider);
AchievementManager::unlockAchievement("hex.builtin.achievement.starting_out", "hex.builtin.achievement.starting_out.open_file.name");
}
ImHexApi::Provider::openProvider(provider);
AchievementManager::unlockAchievement("hex.builtin.achievement.starting_out", "hex.builtin.achievement.starting_out.open_file.name");
}, {}, true);
} else if (name == "Open Project") {
fs::openFileBrowser(fs::DialogMode::Open, { {"Project File", "hexproj"} },
@@ -226,34 +214,20 @@ namespace hex::plugin::builtin {
});
// Handles the provider initialization, and calls EventProviderOpened if successful
EventProviderCreated::subscribe([](hex::prv::Provider *provider) {
EventProviderCreated::subscribe([](std::shared_ptr<prv::Provider> provider) {
if (provider->shouldSkipLoadInterface())
return;
if (auto *filePickerProvider = dynamic_cast<prv::IProviderFilePicker*>(provider); filePickerProvider != nullptr) {
if (auto *filePickerProvider = dynamic_cast<prv::IProviderFilePicker*>(provider.get()); filePickerProvider != nullptr) {
if (!filePickerProvider->handleFilePicker()) {
TaskManager::doLater([provider] { ImHexApi::Provider::remove(provider); });
TaskManager::doLater([provider] { ImHexApi::Provider::remove(provider.get()); });
return;
}
TaskManager::createBlockingTask("hex.builtin.provider.opening", TaskManager::NoProgress, [provider]() {
if (!provider->open()) {
ui::ToastError::open(fmt::format("hex.builtin.provider.error.open"_lang, provider->getErrorMessage()));
TaskManager::doLater([provider] { ImHexApi::Provider::remove(provider); });
} else {
TaskManager::doLater([provider]{ EventProviderOpened::post(provider); });
}
});
ImHexApi::Provider::openProvider(provider);
}
else if (dynamic_cast<prv::IProviderLoadInterface*>(provider) == nullptr) {
TaskManager::createBlockingTask("hex.builtin.provider.opening", TaskManager::NoProgress, [provider]() {
if (!provider->open() || !provider->isAvailable()) {
ui::ToastError::open(fmt::format("hex.builtin.provider.error.open"_lang, provider->getErrorMessage()));
TaskManager::doLater([provider] { ImHexApi::Provider::remove(provider); });
} else {
TaskManager::doLater([provider]{ EventProviderOpened::post(provider); });
}
});
else if (dynamic_cast<prv::IProviderLoadInterface*>(provider.get()) == nullptr) {
ImHexApi::Provider::openProvider(provider);
}
});
@@ -419,6 +393,25 @@ namespace hex::plugin::builtin {
});
});
RequestOpenProvider::subscribe([](std::shared_ptr<prv::Provider> provider) {
TaskManager::createBlockingTask("hex.builtin.provider.opening", TaskManager::NoProgress, [provider]() {
auto result = provider->open();
if (result.isFailure()) {
ui::ToastError::open(fmt::format("hex.builtin.provider.error.open"_lang, result.getErrorMessage()));
TaskManager::doLater([provider] { ImHexApi::Provider::remove(provider.get()); });
} else if (result.isRedirecting()) {
TaskManager::doLater([result, provider] {
ImHexApi::Provider::remove(provider.get());
ImHexApi::Provider::setCurrentProvider(result.getRedirectProvider());
});
} else {
if (result.isWarning())
ui::ToastWarning::open(std::string(result.getErrorMessage()));
TaskManager::doLater([provider]{ EventProviderOpened::post(provider.get()); });
}
});
});
fs::setFileBrowserErrorCallback([](const std::string& errMsg){
#if defined(NFD_PORTAL)
ui::PopupError::open(fmt::format("hex.builtin.popup.error.file_dialog.portal"_lang, errMsg));

View File

@@ -377,7 +377,7 @@ namespace hex::plugin::builtin {
/* Create File */
ContentRegistry::UserInterface::addMenuItem({ "hex.builtin.menu.file", "hex.builtin.menu.file.create_file" }, ICON_VS_FILE, 1050, CTRLCMD + Keys::N + AllowWhileTyping + ShowOnWelcomeScreen, [] {
auto newProvider = hex::ImHexApi::Provider::createProvider("hex.builtin.provider.mem_file", true);
if (newProvider != nullptr && !newProvider->open())
if (newProvider != nullptr && newProvider->open().isFailure())
hex::ImHexApi::Provider::remove(newProvider.get());
else
EventProviderOpened::post(newProvider.get());
@@ -401,7 +401,7 @@ namespace hex::plugin::builtin {
auto provider = ImHexApi::Provider::get();
provider->close();
if (!provider->open())
if (provider->open().isFailure())
ImHexApi::Provider::remove(provider, true);
EventDataChanged::post(provider);

View File

@@ -92,8 +92,9 @@ namespace hex::plugin::builtin {
providerWarnings[newProvider.get()] = e.what();
}
if (loaded) {
if (!newProvider->open() || !newProvider->isAvailable() || !newProvider->isReadable()) {
providerWarnings[newProvider.get()] = newProvider->getErrorMessage();
auto result = newProvider->open();
if (result.isFailure() || !newProvider->isAvailable() || !newProvider->isReadable()) {
providerWarnings[newProvider.get()] = result.getErrorMessage();
} else {
EventProviderOpened::post(newProvider.get());
}

View File

@@ -242,9 +242,9 @@ namespace hex::plugin::builtin {
return fmt::format("hex.builtin.provider.command.name"_lang, m_name);
}
bool CommandProvider::open() {
prv::Provider::OpenResult CommandProvider::open() {
m_open = true;
return true;
return {};
}
void CommandProvider::close() {

View File

@@ -157,7 +157,7 @@ namespace hex::plugin::builtin {
}
#endif
bool DiskProvider::open() {
prv::Provider::OpenResult DiskProvider::open() {
m_readable = true;
m_writable = true;
@@ -207,18 +207,16 @@ namespace hex::plugin::builtin {
const auto &path = m_path.native();
m_diskHandle = ::open(path.c_str(), O_RDWR);
OpenResult result;
if (m_diskHandle == -1) {
this->setErrorMessage(fmt::format("hex.builtin.provider.disk.error.read_rw"_lang, path, formatSystemError(errno)));
log::warn("{}", this->getErrorMessage());
result = OpenResult::warning(fmt::format("hex.builtin.provider.disk.error.read_rw"_lang, path, formatSystemError(errno)));
m_diskHandle = ::open(path.c_str(), O_RDONLY);
m_writable = false;
}
if (m_diskHandle == -1) {
this->setErrorMessage(fmt::format("hex.builtin.provider.disk.error.read_ro"_lang, path, formatSystemError(errno)));
log::warn("{}", this->getErrorMessage());
m_readable = false;
return false;
return OpenResult::failure(fmt::format("hex.builtin.provider.disk.error.read_ro"_lang, path, formatSystemError(errno)));
}
u64 diskSize = 0;
@@ -228,7 +226,7 @@ namespace hex::plugin::builtin {
#endif
return true;
return result;
}
void DiskProvider::close() {

View File

@@ -203,24 +203,23 @@ namespace hex::plugin::builtin {
m_path.make_preferred();
}
bool FileProvider::open() {
prv::Provider::OpenResult FileProvider::open() {
const size_t maxMemoryFileSize = ContentRegistry::Settings::read<u64>("hex.builtin.setting.general", "hex.builtin.setting.general.max_mem_file_size", 128_MiB);
size_t fileSize = 0x00;
{
wolv::io::File file(m_path, wolv::io::File::Mode::Read);
if (!file.isValid()) {
this->setErrorMessage(fmt::format("hex.builtin.provider.file.error.open"_lang, m_path.string(), formatSystemError(file.getOpenError().value_or(0))));
return false;
return OpenResult::failure(fmt::format("hex.builtin.provider.file.error.open"_lang, m_path.string(), formatSystemError(file.getOpenError().value_or(0))));
}
fileSize = file.getSize();
}
const bool directAccess = fileSize >= maxMemoryFileSize;
const bool result = open(directAccess);
const auto result = open(directAccess);
if (result && directAccess) {
if (result.isSuccess() && directAccess) {
m_writable = false;
ui::BannerButton::open(ICON_VS_WARNING, "hex.builtin.provider.file.too_large", ImColor(135, 116, 66), "hex.builtin.provider.file.too_large.allow_write", [this]{
@@ -232,7 +231,7 @@ namespace hex::plugin::builtin {
return result;
}
bool FileProvider::open(bool directAccess) {
prv::Provider::OpenResult FileProvider::open(bool directAccess) {
m_readable = true;
m_writable = true;
@@ -243,8 +242,7 @@ namespace hex::plugin::builtin {
file = wolv::io::File(m_path, wolv::io::File::Mode::Read);
if (!file.isValid()) {
m_readable = false;
this->setErrorMessage(fmt::format("hex.builtin.provider.file.error.open"_lang, m_path.string(), formatSystemError(file.getOpenError().value_or(0))));
return false;
return OpenResult::failure(fmt::format("hex.builtin.provider.file.error.open"_lang, m_path.string(), formatSystemError(file.getOpenError().value_or(0))));
}
ui::ToastInfo::open("hex.builtin.popup.error.read_only"_lang);
@@ -263,8 +261,7 @@ namespace hex::plugin::builtin {
});
if (alreadyOpenedFileProvider != s_openedFiles.end()) {
ImHexApi::Provider::setCurrentProvider(*alreadyOpenedFileProvider);
return false;
return OpenResult::redirect(*alreadyOpenedFileProvider);
} else {
s_openedFiles.insert(this);
}
@@ -286,7 +283,7 @@ namespace hex::plugin::builtin {
m_changeEventAcknowledgementPending = false;
return true;
return {};
}
@@ -318,10 +315,6 @@ namespace hex::plugin::builtin {
if (!wolv::io::fs::exists(fullPath))
fullPath = path;
if (!wolv::io::fs::exists(fullPath)) {
this->setErrorMessage(fmt::format("hex.builtin.provider.file.error.open"_lang, m_path.string(), formatSystemError(ENOENT)));
}
path = std::move(fullPath);
}

View File

@@ -254,7 +254,7 @@ namespace hex::plugin::builtin {
};
}
bool GDBProvider::open() {
prv::Provider::OpenResult GDBProvider::open() {
std::scoped_lock lock(m_mutex);
CachedProvider::open();
@@ -264,11 +264,11 @@ namespace hex::plugin::builtin {
gdb::sendReceivePackage(m_socket, gdb::createPacket("!"));
gdb::sendReceivePackage(m_socket, gdb::createPacket("Hg0"));
if (m_socket.isConnected()) {
return true;
} else {
return false;
if (!m_socket.isConnected()) {
return OpenResult::failure("hex.builtin.provider.gdb.server.error.not_connected"_lang);
}
return {};
}
void GDBProvider::close() {

View File

@@ -245,21 +245,19 @@ namespace hex::plugin::builtin {
});
}
bool IntelHexProvider::open() {
prv::Provider::OpenResult IntelHexProvider::open() {
auto file = wolv::io::File(m_sourceFilePath, wolv::io::File::Mode::Read);
if (!file.isValid()) {
this->setErrorMessage(fmt::format("hex.builtin.provider.file.error.open"_lang, m_sourceFilePath.string(), formatSystemError(errno)));
return false;
return OpenResult::failure(fmt::format("hex.builtin.provider.file.error.open"_lang, m_sourceFilePath.string(), formatSystemError(errno)));
}
auto data = intel_hex::parseIntelHex(file.readString());
if (!data.has_value()) {
this->setErrorMessage(data.error());
return false;
return OpenResult::failure(data.error());
}
processMemoryRegions(data);
return true;
return {};
}
void IntelHexProvider::close() {

View File

@@ -16,12 +16,12 @@
namespace hex::plugin::builtin {
bool MemoryFileProvider::open() {
prv::Provider::OpenResult MemoryFileProvider::open() {
if (m_data.empty()) {
m_data.resize(1);
}
return true;
return {};
}
void MemoryFileProvider::readRaw(u64 offset, void *buffer, size_t size) {
@@ -54,7 +54,7 @@ namespace hex::plugin::builtin {
if (auto fileProvider = dynamic_cast<FileProvider*>(newProvider.get()); fileProvider != nullptr) {
fileProvider->setPath(path);
if (!fileProvider->open()) {
if (fileProvider->open().isFailure()) {
ImHexApi::Provider::remove(newProvider.get());
} else {
MovePerProviderData::post(this, fileProvider);

View File

@@ -170,21 +170,19 @@ namespace hex::plugin::builtin {
}
bool MotorolaSRECProvider::open() {
prv::Provider::OpenResult MotorolaSRECProvider::open() {
auto file = wolv::io::File(m_sourceFilePath, wolv::io::File::Mode::Read);
if (!file.isValid()) {
this->setErrorMessage(fmt::format("hex.builtin.provider.file.error.open"_lang, m_sourceFilePath.string(), formatSystemError(errno)));
return false;
return OpenResult::failure(fmt::format("hex.builtin.provider.file.error.open"_lang, m_sourceFilePath.string(), formatSystemError(errno)));
}
auto data = motorola_srec::parseMotorolaSREC(file.readString());
if (!data.has_value()) {
this->setErrorMessage(data.error());
return false;
return OpenResult::failure(data.error());
}
processMemoryRegions(data);
return true;
return {};
}
void MotorolaSRECProvider::close() {

View File

@@ -102,21 +102,21 @@ namespace hex::plugin::builtin {
#endif
bool ProcessMemoryProvider::open() {
prv::Provider::OpenResult ProcessMemoryProvider::open() {
if (m_selectedProcess == nullptr)
return false;
return OpenResult::failure("hex.builtin.provider.process_memory.error.no_process_selected"_lang);
#if defined(OS_WINDOWS)
m_processHandle = OpenProcess(PROCESS_ALL_ACCESS, FALSE, m_selectedProcess->id);
if (m_processHandle == nullptr)
return false;
return OpenResult::failure("hex.builtin.provider.process_memory.error.open_process"_lang);
#else
m_processId = pid_t(m_selectedProcess->id);
#endif
this->reloadProcessModules();
return true;
return {};
}
void ProcessMemoryProvider::close() {

View File

@@ -7,13 +7,13 @@
namespace hex::plugin::builtin {
bool UDPProvider::open() {
prv::Provider::OpenResult UDPProvider::open() {
m_udpServer = UDPServer(m_port, [this](std::span<const u8> data) {
this->receive(data);
});
m_udpServer.start();
return true;
return {};
}
void UDPProvider::close() {

View File

@@ -48,9 +48,9 @@ namespace hex::plugin::builtin {
m_provider->save();
}
[[nodiscard]] bool ViewProvider::open() {
[[nodiscard]] prv::Provider::OpenResult ViewProvider::open() {
if (m_provider == this)
return false;
return OpenResult::failure("hex.builtin.provider.view.error.no_provider"_lang);
EventProviderClosing::subscribe(this, [this](const prv::Provider *provider, bool*) {
if (m_provider == provider) {
@@ -59,7 +59,7 @@ namespace hex::plugin::builtin {
}
});
return true;
return {};
}
void ViewProvider::close() {
EventProviderClosing::unsubscribe(this);

View File

@@ -283,14 +283,7 @@ namespace hex::plugin::builtin::recent {
if (provider != nullptr) {
provider->loadSettings(recentEntry.data);
TaskManager::createBlockingTask("hex.builtin.provider.opening", TaskManager::NoProgress, [provider]() {
if (!provider->open() || !provider->isAvailable()) {
ui::ToastError::open(fmt::format("hex.builtin.provider.error.open"_lang, provider->getErrorMessage()));
TaskManager::doLater([provider] { ImHexApi::Provider::remove(provider.get()); });
} else {
TaskManager::doLater([provider]{ EventProviderOpened::post(provider.get()); });
}
});
ImHexApi::Provider::openProvider(provider);
updateRecentEntries();
}

View File

@@ -539,7 +539,6 @@ namespace hex::plugin::builtin {
flags |= ImGuiTabItemFlags_UnsavedDocument;
if (i64(i) == selectedProviderIndex && providerJustChanged) {
flags |= ImGuiTabItemFlags_SetSelected;
providerJustChanged = false;
}
static size_t lastSelectedProvider = 0;
@@ -550,7 +549,7 @@ namespace hex::plugin::builtin {
ImGui::EndTabItem();
}
if (isSelected && lastSelectedProvider != i) {
if (isSelected && lastSelectedProvider != i && !providerJustChanged) {
ImHexApi::Provider::setCurrentProvider(i);
lastSelectedProvider = i;
}
@@ -570,6 +569,8 @@ namespace hex::plugin::builtin {
}
}
ImGui::EndTabBar();
providerJustChanged = false;
}
}
ImGui::EndDisabled();

View File

@@ -15,8 +15,9 @@ namespace hex::plugin::builtin {
ViewFullScreenFileInfo::ViewFullScreenFileInfo(std::fs::path filePath) : m_filePath(std::move(filePath)) {
this->m_provider.setPath(m_filePath);
if (!this->m_provider.open()) {
if (this->m_provider.open().isFailure()) {
ui::ToastError::open("hex.builtin.view.fullscreen.file_info.error.file_not_readable"_lang);
return;
}
m_analysisTask = TaskManager::createBlockingTask("hex.builtin.view.fullscreen.file_info.analyzing", TaskManager::NoProgress, [this](Task &task) {

View File

@@ -67,8 +67,9 @@ namespace hex::plugin::builtin {
if (ImGuiExt::DimmedButton(fmt::format("{} {}", ICON_VS_OPEN_PREVIEW, "hex.builtin.view.fullscreen.save_editor.select_file"_lang).c_str(), ImVec2(-1, 0))) {
fs::openFileBrowser(fs::DialogMode::Open, {}, [this](const std::fs::path &path) {
this->m_provider.setPath(path);
if (!this->m_provider.open()) {
if (this->m_provider.open().isFailure()) {
ui::ToastError::open("hex.builtin.view.fullscreen.save_editor.error.not_readable"_lang);
return;
}
ContentRegistry::PatternLanguage::configureRuntime(m_runtime, &m_provider);

View File

@@ -394,10 +394,9 @@ namespace hex::plugin::builtin {
viewProvider->setProvider(region.getStartAddress(), region.getSize(), provider);
viewProvider->setName(fmt::format("'{}' View", name));
if (viewProvider->open()) {
EventProviderOpened::post(viewProvider);
AchievementManager::unlockAchievement("hex.builtin.achievement.hex_editor", "hex.builtin.achievement.hex_editor.open_new_view.name");
}
ImHexApi::Provider::openProvider(newProvider);
AchievementManager::unlockAchievement("hex.builtin.achievement.hex_editor", "hex.builtin.achievement.hex_editor.open_new_view.name");
}
});
}

View File

@@ -1170,8 +1170,7 @@ namespace hex::plugin::builtin {
auto newProvider = ImHexApi::Provider::createProvider("hex.builtin.provider.view", true);
if (auto *viewProvider = dynamic_cast<ViewProvider*>(newProvider.get()); viewProvider != nullptr) {
viewProvider->setProvider(selection->getStartAddress(), selection->getSize(), selection->getProvider());
if (viewProvider->open())
EventProviderOpened::post(viewProvider);
ImHexApi::Provider::openProvider(newProvider);
}
},
[] { return ImHexApi::HexEditor::isSelectionValid() && ImHexApi::Provider::isValid(); },

View File

@@ -11,8 +11,8 @@
namespace hex::plugin::builtin {
ViewProviderSettings::ViewProviderSettings() : View::Modal("hex.builtin.view.provider_settings.name", ICON_VS_SETTINGS) {
EventProviderCreated::subscribe(this, [this](const hex::prv::Provider *provider) {
if (dynamic_cast<const prv::IProviderLoadInterface*>(provider) != nullptr && !provider->shouldSkipLoadInterface())
EventProviderCreated::subscribe(this, [this](std::shared_ptr<prv::Provider> provider) {
if (dynamic_cast<const prv::IProviderLoadInterface*>(provider.get()) != nullptr && !provider->shouldSkipLoadInterface())
this->getWindowOpenState() = true;
});
@@ -43,7 +43,8 @@ namespace hex::plugin::builtin {
ImGui::BeginDisabled(!settingsValid);
if (ImGui::Button("hex.ui.common.open"_lang)) {
if (provider->open()) {
auto result = provider->open();
if (result.isSuccess()) {
EventProviderOpened::post(provider);
this->getWindowOpenState() = false;
@@ -52,7 +53,7 @@ namespace hex::plugin::builtin {
else {
this->getWindowOpenState() = false;
ImGui::CloseCurrentPopup();
auto errorMessage = provider->getErrorMessage();
auto errorMessage = result.getErrorMessage();
if (errorMessage.empty()) {
ui::ToastError::open("hex.builtin.view.provider_settings.load_error"_lang);
} else {

View File

@@ -346,7 +346,7 @@ namespace hex::plugin::builtin {
if (ImGuiExt::BeginSubWindow("hex.builtin.welcome.header.start"_lang, nullptr, ImVec2(), ImGuiChildFlags_AutoResizeX)) {
if (ImGuiExt::IconHyperlink(ICON_VS_NEW_FILE, "hex.builtin.welcome.start.create_file"_lang)) {
auto newProvider = hex::ImHexApi::Provider::createProvider("hex.builtin.provider.mem_file", true);
if (newProvider != nullptr && !newProvider->open())
if (newProvider != nullptr && newProvider->open().isFailure())
hex::ImHexApi::Provider::remove(newProvider.get());
else
EventProviderOpened::post(newProvider.get());

View File

@@ -15,7 +15,7 @@ namespace hex::plugin::remote {
bool isResizable() const override { return false; }
bool isSavable() const override { return isWritable(); }
bool open() override;
OpenResult open() override;
void close() override;
void save() override;

View File

@@ -7,5 +7,6 @@
"hex.plugin.remote.ssh_provider.key_file": "Private Key Path",
"hex.plugin.remote.ssh_provider.passphrase": "Passphrase",
"hex.plugin.remote.ssh_provider.connect": "Connect",
"hex.plugin.remote.ssh_provider.ssh_access": "Access file using raw SSH"
"hex.plugin.remote.ssh_provider.ssh_access": "Access file using raw SSH",
"hex.plugin.remote.ssh_provider.error.open_failed": "Failed to open remote file"
}

View File

@@ -11,7 +11,7 @@
namespace hex::plugin::remote {
bool SSHProvider::open() {
prv::Provider::OpenResult SSHProvider::open() {
if (!m_sftpClient.isConnected()) {
try {
if (m_authMethod == AuthMethod::Password) {
@@ -22,8 +22,7 @@ namespace hex::plugin::remote {
m_sftpClient = std::move(client);
}
} catch (const std::exception& e) {
setErrorMessage(e.what());
return false;
return OpenResult::failure(e.what());
}
}
@@ -33,11 +32,14 @@ namespace hex::plugin::remote {
else
m_remoteFile = m_sftpClient.openFileSFTP(m_remoteFilePath, SSHClient::OpenMode::ReadWrite);
} catch (const std::exception& e) {
setErrorMessage(e.what());
return false;
return OpenResult::failure(e.what());
}
return m_remoteFile->isOpen();
if (!m_remoteFile->isOpen()) {
return OpenResult::failure("hex.plugin.remote.ssh_provider.error.open_failed"_lang);
}
return {};
}
void SSHProvider::close() {

View File

@@ -60,7 +60,7 @@ public:
using GetSizeFunction = u64(*)();
using GetNameFunction = std::string(*)();
bool open() override { return true; }
OpenResult open() override { return {}; }
void close() override { }
[[nodiscard]] bool isAvailable() const override { return true; }