feat: Display detailed error message when loading of project fails (#1135)
In order to do this I add to make some other additions : - Add a warning popup (TODO, maybe add some icons to differentiate error/warning popups in a future PR ?) - create showError() and showWarning() functions, as helpers to show a message both to the logs and as a popup
This commit is contained in:
parent
3fe6cd057b
commit
b7d8e46288
@ -12,15 +12,15 @@
|
||||
#include <hex/helpers/concepts.hpp>
|
||||
#include <hex/helpers/tar.hpp>
|
||||
|
||||
/**
|
||||
* @brief Project file manager
|
||||
*
|
||||
* The project file manager is used to load and store project files. It is used by all features of ImHex
|
||||
* that want to store any data to a Project File.
|
||||
*
|
||||
*/
|
||||
namespace hex {
|
||||
|
||||
/**
|
||||
* @brief Project file manager
|
||||
*
|
||||
* The project file manager is used to load and store project files. It is used by all features of ImHex
|
||||
* that want to store any data to a Project File.
|
||||
*
|
||||
*/
|
||||
class ProjectFile {
|
||||
public:
|
||||
struct Handler {
|
||||
@ -39,6 +39,17 @@ namespace hex {
|
||||
Function load, store; //< Functions to load and store data
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief Set implementations for loading and restoring a project
|
||||
*
|
||||
* @param loadFun function to use to load a project in ImHex
|
||||
* @param storeFun function to use to store a project to disk
|
||||
*/
|
||||
static void setProjectFunctions(
|
||||
const std::function<bool(const std::fs::path&)> &loadFun,
|
||||
const std::function<bool(std::optional<std::fs::path>)> &storeFun
|
||||
);
|
||||
|
||||
/**
|
||||
* @brief Load a project file
|
||||
*
|
||||
@ -119,6 +130,9 @@ namespace hex {
|
||||
private:
|
||||
ProjectFile() = default;
|
||||
|
||||
static std::function<bool(const std::fs::path&)> s_loadProjectFunction;
|
||||
static std::function<bool(std::optional<std::fs::path>)> s_storeProjectFunction;
|
||||
|
||||
static std::fs::path s_currProjectPath;
|
||||
static std::vector<Handler> s_handlers;
|
||||
static std::vector<ProviderHandler> s_providerHandlers;
|
||||
|
@ -26,6 +26,12 @@ namespace hex {
|
||||
|
||||
void close();
|
||||
|
||||
/**
|
||||
* @brief get the error string explaining the error that occured when opening the file.
|
||||
* This error is a combination of the tar error and the native file open error
|
||||
*/
|
||||
std::string getOpenErrorString();
|
||||
|
||||
[[nodiscard]] std::vector<u8> readVector(const std::fs::path &path);
|
||||
[[nodiscard]] std::string readString(const std::fs::path &path);
|
||||
|
||||
@ -45,6 +51,10 @@ namespace hex {
|
||||
std::fs::path m_path;
|
||||
|
||||
bool m_valid = false;
|
||||
|
||||
// these will be updated when the constructor is called
|
||||
int m_tarOpenErrno = MTAR_ESUCCESS;
|
||||
int m_fileOpenErrno = 0;
|
||||
};
|
||||
|
||||
}
|
@ -11,138 +11,28 @@
|
||||
|
||||
namespace hex {
|
||||
|
||||
constexpr static auto MetadataHeaderMagic = "HEX";
|
||||
constexpr static auto MetadataPath = "IMHEX_METADATA";
|
||||
|
||||
std::vector<ProjectFile::Handler> ProjectFile::s_handlers;
|
||||
std::vector<ProjectFile::ProviderHandler> ProjectFile::s_providerHandlers;
|
||||
|
||||
std::fs::path ProjectFile::s_currProjectPath;
|
||||
|
||||
std::function<bool(const std::fs::path&)> ProjectFile::s_loadProjectFunction;
|
||||
std::function<bool(std::optional<std::fs::path>)> ProjectFile::s_storeProjectFunction;
|
||||
|
||||
void ProjectFile::setProjectFunctions(
|
||||
const std::function<bool(const std::fs::path&)> &loadFun,
|
||||
const std::function<bool(std::optional<std::fs::path>)> &storeFun
|
||||
) {
|
||||
ProjectFile::s_loadProjectFunction = loadFun;
|
||||
ProjectFile::s_storeProjectFunction = storeFun;
|
||||
}
|
||||
|
||||
bool ProjectFile::load(const std::fs::path &filePath) {
|
||||
auto originalPath = ProjectFile::s_currProjectPath;
|
||||
|
||||
ProjectFile::s_currProjectPath = filePath;
|
||||
auto resetPath = SCOPE_GUARD {
|
||||
ProjectFile::s_currProjectPath = originalPath;
|
||||
};
|
||||
|
||||
if (!wolv::io::fs::exists(filePath) || !wolv::io::fs::isRegularFile(filePath))
|
||||
return false;
|
||||
if (filePath.extension() != ".hexproj")
|
||||
return false;
|
||||
|
||||
Tar tar(filePath, Tar::Mode::Read);
|
||||
if (!tar.isValid())
|
||||
return false;
|
||||
|
||||
if (!tar.contains(MetadataPath))
|
||||
return false;
|
||||
|
||||
{
|
||||
const auto metadataContent = tar.readVector(MetadataPath);
|
||||
|
||||
if (!std::string(metadataContent.begin(), metadataContent.end()).starts_with(MetadataHeaderMagic))
|
||||
return false;
|
||||
}
|
||||
|
||||
auto providers = auto(ImHexApi::Provider::getProviders());
|
||||
for (const auto &provider : providers) {
|
||||
ImHexApi::Provider::remove(provider);
|
||||
}
|
||||
|
||||
bool result = true;
|
||||
for (const auto &handler : ProjectFile::getHandlers()) {
|
||||
try {
|
||||
if (!handler.load(handler.basePath, tar)) {
|
||||
log::warn("Project file handler for {} failed to load {}", filePath.string(), handler.basePath.string());
|
||||
result = false;
|
||||
}
|
||||
} catch (std::exception &e) {
|
||||
log::warn("Project file handler for {} failed to load {}: {}", filePath.string(), handler.basePath.string(), e.what());
|
||||
result = false;
|
||||
}
|
||||
|
||||
if (!result && handler.required) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
for (const auto &provider : ImHexApi::Provider::getProviders()) {
|
||||
const auto basePath = std::fs::path(std::to_string(provider->getID()));
|
||||
for (const auto &handler: ProjectFile::getProviderHandlers()) {
|
||||
try {
|
||||
if (!handler.load(provider, basePath / handler.basePath, tar))
|
||||
result = false;
|
||||
} catch (std::exception &e) {
|
||||
log::info("{}", e.what());
|
||||
result = false;
|
||||
}
|
||||
|
||||
if (!result && handler.required) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
resetPath.release();
|
||||
EventManager::post<EventProjectOpened>();
|
||||
EventManager::post<RequestUpdateWindowTitle>();
|
||||
|
||||
return true;
|
||||
return s_loadProjectFunction(filePath);
|
||||
}
|
||||
|
||||
bool ProjectFile::store(std::optional<std::fs::path> filePath) {
|
||||
auto originalPath = ProjectFile::s_currProjectPath;
|
||||
|
||||
if (!filePath.has_value())
|
||||
filePath = ProjectFile::s_currProjectPath;
|
||||
|
||||
ProjectFile::s_currProjectPath = filePath.value();
|
||||
auto resetPath = SCOPE_GUARD {
|
||||
ProjectFile::s_currProjectPath = originalPath;
|
||||
};
|
||||
|
||||
Tar tar(*filePath, Tar::Mode::Create);
|
||||
if (!tar.isValid())
|
||||
return false;
|
||||
|
||||
bool result = true;
|
||||
for (const auto &handler : ProjectFile::getHandlers()) {
|
||||
try {
|
||||
if (!handler.store(handler.basePath, tar) && handler.required)
|
||||
result = false;
|
||||
} catch (std::exception &e) {
|
||||
log::info("{}", e.what());
|
||||
|
||||
if (handler.required)
|
||||
result = false;
|
||||
}
|
||||
}
|
||||
for (const auto &provider : ImHexApi::Provider::getProviders()) {
|
||||
const auto basePath = std::fs::path(std::to_string(provider->getID()));
|
||||
for (const auto &handler: ProjectFile::getProviderHandlers()) {
|
||||
try {
|
||||
if (!handler.store(provider, basePath / handler.basePath, tar) && handler.required)
|
||||
result = false;
|
||||
} catch (std::exception &e) {
|
||||
log::info("{}", e.what());
|
||||
|
||||
if (handler.required)
|
||||
result = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
{
|
||||
const auto metadataContent = hex::format("{}\n{}", MetadataHeaderMagic, IMHEX_VERSION);
|
||||
tar.writeString(MetadataPath, metadataContent);
|
||||
}
|
||||
|
||||
ImHexApi::Provider::resetDirty();
|
||||
resetPath.release();
|
||||
|
||||
return result;
|
||||
return s_storeProjectFunction(filePath);
|
||||
}
|
||||
|
||||
bool ProjectFile::hasPath() {
|
||||
|
@ -2,6 +2,7 @@
|
||||
#include <hex/helpers/literals.hpp>
|
||||
#include <hex/helpers/fs.hpp>
|
||||
#include <hex/helpers/logger.hpp>
|
||||
#include <hex/helpers/fmt.hpp>
|
||||
|
||||
#include <wolv/io/file.hpp>
|
||||
|
||||
@ -10,7 +11,7 @@ namespace hex {
|
||||
using namespace hex::literals;
|
||||
|
||||
Tar::Tar(const std::fs::path &path, Mode mode) {
|
||||
int error = MTAR_ESUCCESS;
|
||||
int tar_error = MTAR_ESUCCESS;
|
||||
|
||||
// Explicitly create file so a short path gets generated
|
||||
if (mode == Mode::Create) {
|
||||
@ -20,16 +21,23 @@ namespace hex {
|
||||
|
||||
auto shortPath = wolv::io::fs::toShortPath(path);
|
||||
if (mode == Tar::Mode::Read)
|
||||
error = mtar_open(&this->m_ctx, shortPath.string().c_str(), "r");
|
||||
tar_error = mtar_open(&this->m_ctx, shortPath.string().c_str(), "r");
|
||||
else if (mode == Tar::Mode::Write)
|
||||
error = mtar_open(&this->m_ctx, shortPath.string().c_str(), "a");
|
||||
tar_error = mtar_open(&this->m_ctx, shortPath.string().c_str(), "a");
|
||||
else if (mode == Tar::Mode::Create)
|
||||
error = mtar_open(&this->m_ctx, shortPath.string().c_str(), "w");
|
||||
tar_error = mtar_open(&this->m_ctx, shortPath.string().c_str(), "w");
|
||||
else
|
||||
error = MTAR_EFAILURE;
|
||||
tar_error = MTAR_EFAILURE;
|
||||
|
||||
this->m_path = path;
|
||||
this->m_valid = (error == MTAR_ESUCCESS);
|
||||
this->m_valid = (tar_error == MTAR_ESUCCESS);
|
||||
|
||||
if (!this->m_valid) {
|
||||
this->m_tarOpenErrno = tar_error;
|
||||
|
||||
// hopefully this errno corresponds to the file open call in mtar_open
|
||||
this->m_fileOpenErrno = errno;
|
||||
}
|
||||
}
|
||||
|
||||
Tar::~Tar() {
|
||||
@ -40,6 +48,8 @@ namespace hex {
|
||||
this->m_ctx = other.m_ctx;
|
||||
this->m_path = other.m_path;
|
||||
this->m_valid = other.m_valid;
|
||||
this->m_tarOpenErrno = other.m_tarOpenErrno;
|
||||
this->m_fileOpenErrno = other.m_fileOpenErrno;
|
||||
|
||||
other.m_ctx = { };
|
||||
other.m_valid = false;
|
||||
@ -54,6 +64,8 @@ namespace hex {
|
||||
this->m_valid = other.m_valid;
|
||||
other.m_valid = false;
|
||||
|
||||
this->m_tarOpenErrno = other.m_tarOpenErrno;
|
||||
this->m_fileOpenErrno = other.m_fileOpenErrno;
|
||||
return *this;
|
||||
}
|
||||
|
||||
@ -79,6 +91,10 @@ namespace hex {
|
||||
return mtar_find(&this->m_ctx, path.string().c_str(), &header) == MTAR_ESUCCESS;
|
||||
}
|
||||
|
||||
std::string Tar::getOpenErrorString(){
|
||||
return hex::format("{}: {}", mtar_strerror(this->m_tarOpenErrno), std::strerror(this->m_fileOpenErrno));
|
||||
}
|
||||
|
||||
void Tar::close() {
|
||||
if (this->m_valid) {
|
||||
mtar_finalize(&this->m_ctx);
|
||||
|
@ -29,6 +29,7 @@ add_library(${PROJECT_NAME} SHARED
|
||||
source/content/themes.cpp
|
||||
source/content/recent.cpp
|
||||
source/content/file_handlers.cpp
|
||||
source/content/project.cpp
|
||||
|
||||
source/content/providers/file_provider.cpp
|
||||
source/content/providers/gdb_provider.cpp
|
||||
@ -60,6 +61,7 @@ add_library(${PROJECT_NAME} SHARED
|
||||
source/content/views/view_theme_manager.cpp
|
||||
|
||||
source/content/helpers/math_evaluator.cpp
|
||||
source/content/helpers/notification.cpp
|
||||
|
||||
source/ui/hex_editor.cpp
|
||||
source/ui/pattern_drawer.cpp
|
||||
|
10
plugins/builtin/include/content/helpers/notification.hpp
Normal file
10
plugins/builtin/include/content/helpers/notification.hpp
Normal file
@ -0,0 +1,10 @@
|
||||
#pragma once
|
||||
|
||||
#include <content/popups/popup_notification.hpp>
|
||||
|
||||
namespace hex::plugin::builtin {
|
||||
|
||||
void showError(const std::string& message);
|
||||
|
||||
void showWarning(const std::string& message);
|
||||
}
|
@ -1,6 +1,9 @@
|
||||
#pragma once
|
||||
|
||||
#include <hex/ui/popup.hpp>
|
||||
|
||||
#include <hex/api/localization.hpp>
|
||||
#include <hex/api/imhex_api.hpp>
|
||||
|
||||
#include <functional>
|
||||
#include <string>
|
||||
@ -53,6 +56,14 @@ namespace hex::plugin::builtin {
|
||||
}) { }
|
||||
};
|
||||
|
||||
class PopupWarning : public impl::PopupNotification<PopupWarning> {
|
||||
public:
|
||||
explicit PopupWarning(std::string message)
|
||||
: PopupNotification("hex.builtin.common.warning", std::move(message), [this]() {
|
||||
Popup::close();
|
||||
}) { }
|
||||
};
|
||||
|
||||
class PopupError : public impl::PopupNotification<PopupError> {
|
||||
public:
|
||||
explicit PopupError(std::string message)
|
||||
|
@ -30,6 +30,7 @@
|
||||
"hex.builtin.common.encoding.utf8": "UTF-8",
|
||||
"hex.builtin.common.end": "End",
|
||||
"hex.builtin.common.endian": "Endian",
|
||||
"hex.builtin.common.warning": "Warning",
|
||||
"hex.builtin.common.error": "Error",
|
||||
"hex.builtin.common.fatal": "Fatal Error",
|
||||
"hex.builtin.common.file": "File",
|
||||
@ -393,8 +394,14 @@
|
||||
"hex.builtin.popup.error.create": "Failed to create new file!",
|
||||
"hex.builtin.popup.error.file_dialog.common": "An error occurred while opening the file browser: {}",
|
||||
"hex.builtin.popup.error.file_dialog.portal": "There was an error while opening the file browser: {}.\nThis might be caused by your system not having a xdg-desktop-portal backend installed correctly.\n\nOn KDE, it's xdg-desktop-portal-kde.\nOn Gnome it's xdg-desktop-portal-gnome.\nOn wlroots it's xdg-desktop-portal-wlr.\nOtherwise, you can try to use xdg-desktop-portal-gtk.\n\nReboot your system after installing it.\n\nIf the file browser still doesn't work after this, submit an issue at https://github.com/WerWolv/ImHex/issues\n\nIn the meantime files can still be opened by dragging them onto the ImHex window!",
|
||||
"hex.builtin.popup.error.project.load": "Failed to load project!",
|
||||
"hex.builtin.popup.error.project.load": "Failed to load project: {}",
|
||||
"hex.builtin.popup.error.project.save": "Failed to save project!",
|
||||
"hex.builtin.popup.error.project.load.create_provider": "Failed to create provider with type {}",
|
||||
"hex.builtin.popup.error.project.load.no_providers": "There are no openable providers",
|
||||
"hex.builtin.popup.error.project.load.some_providers_failed": "Some providers failed to load: {}",
|
||||
"hex.builtin.popup.error.project.load.file_not_found": "Project file {} not found",
|
||||
"hex.builtin.popup.error.project.load.invalid_tar": "Could not open tarred project file: {}",
|
||||
"hex.builtin.popup.error.project.load.invalid_magic": "Invalid magic file in project file",
|
||||
"hex.builtin.popup.error.read_only": "Couldn't get write access. File opened in read-only mode.",
|
||||
"hex.builtin.popup.error.task_exception": "Exception thrown in Task '{}':\n\n{}",
|
||||
"hex.builtin.popup.exit_application.desc": "You have unsaved changes made to your Project.\nAre you sure you want to exit?",
|
||||
|
16
plugins/builtin/source/content/helpers/notification.cpp
Normal file
16
plugins/builtin/source/content/helpers/notification.cpp
Normal file
@ -0,0 +1,16 @@
|
||||
#include <hex/helpers/logger.hpp>
|
||||
|
||||
#include <content/popups/popup_notification.hpp>
|
||||
|
||||
namespace hex::plugin::builtin {
|
||||
|
||||
void showError(const std::string& message){
|
||||
PopupError::open(message);
|
||||
log::error(message);
|
||||
}
|
||||
|
||||
void showWarning(const std::string& message){
|
||||
PopupWarning::open(message);
|
||||
log::warn(message);
|
||||
}
|
||||
}
|
166
plugins/builtin/source/content/project.cpp
Normal file
166
plugins/builtin/source/content/project.cpp
Normal file
@ -0,0 +1,166 @@
|
||||
#include <filesystem>
|
||||
|
||||
#include <wolv/utils/guards.hpp>
|
||||
#include <wolv/utils/string.hpp>
|
||||
|
||||
#include <hex/api/project_file_manager.hpp>
|
||||
#include <hex/api/localization.hpp>
|
||||
#include <hex/providers/provider.hpp>
|
||||
#include <hex/helpers/fmt.hpp>
|
||||
|
||||
#include <content/helpers/notification.hpp>
|
||||
|
||||
namespace hex::plugin::builtin {
|
||||
|
||||
constexpr static auto MetadataHeaderMagic = "HEX";
|
||||
constexpr static auto MetadataPath = "IMHEX_METADATA";
|
||||
|
||||
bool load(const std::fs::path &filePath) {
|
||||
auto originalPath = ProjectFile::getPath();
|
||||
|
||||
ProjectFile::setPath(filePath);
|
||||
auto resetPath = SCOPE_GUARD {
|
||||
ProjectFile::setPath(originalPath);
|
||||
};
|
||||
|
||||
if (!wolv::io::fs::exists(filePath) || !wolv::io::fs::isRegularFile(filePath)) {
|
||||
showError(hex::format("hex.builtin.popup.error.project.load"_lang,
|
||||
hex::format("hex.builtin.popup.error.project.load.file_not_found"_lang,
|
||||
wolv::util::toUTF8String(filePath)
|
||||
)));
|
||||
return false;
|
||||
}
|
||||
|
||||
Tar tar(filePath, Tar::Mode::Read);
|
||||
if (!tar.isValid()) {
|
||||
showError(hex::format("hex.builtin.popup.error.project.load"_lang,
|
||||
hex::format("hex.builtin.popup.error.project.load.invalid_tar"_lang,
|
||||
tar.getOpenErrorString()
|
||||
)));
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!tar.contains(MetadataPath)) {
|
||||
showError(hex::format("hex.builtin.popup.error.project.load"_lang,
|
||||
hex::format("hex.builtin.popup.error.project.load.invalid_magic"_lang)
|
||||
));
|
||||
return false;
|
||||
}
|
||||
|
||||
{
|
||||
const auto metadataContent = tar.readVector(MetadataPath);
|
||||
|
||||
if (!std::string(metadataContent.begin(), metadataContent.end()).starts_with(MetadataHeaderMagic)) {
|
||||
showError(hex::format("hex.builtin.popup.error.project.load"_lang,
|
||||
hex::format("hex.builtin.popup.error.project.load.invalid_magic"_lang)
|
||||
));
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
auto providers = auto(ImHexApi::Provider::getProviders());
|
||||
for (const auto &provider : providers) {
|
||||
ImHexApi::Provider::remove(provider);
|
||||
}
|
||||
|
||||
for (const auto &handler : ProjectFile::getHandlers()) {
|
||||
bool result = true;
|
||||
// handlers are supposed to show the error/warning popup to the user themselves, so we don't show one here
|
||||
try {
|
||||
if (!handler.load(handler.basePath, tar)) {
|
||||
log::warn("Project file handler for {} failed to load {}", filePath.string(), handler.basePath.string());
|
||||
result = false;
|
||||
}
|
||||
} catch (std::exception &e) {
|
||||
log::warn("Project file handler for {} failed to load {}: {}", filePath.string(), handler.basePath.string(), e.what());
|
||||
result = false;
|
||||
}
|
||||
|
||||
if (!result && handler.required) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
for (const auto &provider : ImHexApi::Provider::getProviders()) {
|
||||
const auto basePath = std::fs::path(std::to_string(provider->getID()));
|
||||
for (const auto &handler: ProjectFile::getProviderHandlers()) {
|
||||
bool result = true;
|
||||
// Handlers are supposed to show the error/warning popup to the user themselves, so we don't show one here
|
||||
try {
|
||||
if (!handler.load(provider, basePath / handler.basePath, tar))
|
||||
result = false;
|
||||
} catch (std::exception &e) {
|
||||
log::info("{}", e.what());
|
||||
result = false;
|
||||
}
|
||||
|
||||
if (!result && handler.required) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
resetPath.release();
|
||||
EventManager::post<EventProjectOpened>();
|
||||
EventManager::post<RequestUpdateWindowTitle>();
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool store(std::optional<std::fs::path> filePath = std::nullopt) {
|
||||
auto originalPath = ProjectFile::getPath();
|
||||
|
||||
if (!filePath.has_value())
|
||||
filePath = originalPath;
|
||||
|
||||
ProjectFile::setPath(filePath.value());
|
||||
auto resetPath = SCOPE_GUARD {
|
||||
ProjectFile::setPath(originalPath);
|
||||
};
|
||||
|
||||
Tar tar(*filePath, Tar::Mode::Create);
|
||||
if (!tar.isValid())
|
||||
return false;
|
||||
|
||||
bool result = true;
|
||||
for (const auto &handler : ProjectFile::getHandlers()) {
|
||||
try {
|
||||
if (!handler.store(handler.basePath, tar) && handler.required)
|
||||
result = false;
|
||||
} catch (std::exception &e) {
|
||||
log::info("{}", e.what());
|
||||
|
||||
if (handler.required)
|
||||
result = false;
|
||||
}
|
||||
}
|
||||
for (const auto &provider : ImHexApi::Provider::getProviders()) {
|
||||
const auto basePath = std::fs::path(std::to_string(provider->getID()));
|
||||
for (const auto &handler: ProjectFile::getProviderHandlers()) {
|
||||
try {
|
||||
if (!handler.store(provider, basePath / handler.basePath, tar) && handler.required)
|
||||
result = false;
|
||||
} catch (std::exception &e) {
|
||||
log::info("{}", e.what());
|
||||
|
||||
if (handler.required)
|
||||
result = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
{
|
||||
const auto metadataContent = hex::format("{}\n{}", MetadataHeaderMagic, IMHEX_VERSION);
|
||||
tar.writeString(MetadataPath, metadataContent);
|
||||
}
|
||||
|
||||
ImHexApi::Provider::resetDirty();
|
||||
resetPath.release();
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
void registerProjectHandlers() {
|
||||
hex::ProjectFile::setProjectFunctions(load, store);
|
||||
}
|
||||
}
|
@ -8,6 +8,8 @@
|
||||
#include "content/providers/motorola_srec_provider.hpp"
|
||||
#include "content/providers/memory_file_provider.hpp"
|
||||
#include "content/providers/view_provider.hpp"
|
||||
#include "content/popups/popup_notification.hpp"
|
||||
#include "content/helpers/notification.hpp"
|
||||
|
||||
#include <hex/api/project_file_manager.hpp>
|
||||
#include <hex/api/task.hpp>
|
||||
@ -31,63 +33,93 @@ namespace hex::plugin::builtin {
|
||||
ContentRegistry::Provider::add<ViewProvider>(false);
|
||||
|
||||
ProjectFile::registerHandler({
|
||||
.basePath = "providers",
|
||||
.required = true,
|
||||
.load = [](const std::fs::path &basePath, Tar &tar) {
|
||||
auto json = nlohmann::json::parse(tar.readString(basePath / "providers.json"));
|
||||
auto providerIds = json.at("providers").get<std::vector<int>>();
|
||||
.basePath = "providers",
|
||||
.required = true,
|
||||
.load = [](const std::fs::path &basePath, Tar &tar) {
|
||||
auto json = nlohmann::json::parse(tar.readString(basePath / "providers.json"));
|
||||
auto providerIds = json.at("providers").get<std::vector<int>>();
|
||||
|
||||
bool success = true;
|
||||
for (const auto &id : providerIds) {
|
||||
auto providerSettings = nlohmann::json::parse(tar.readString(basePath / hex::format("{}.json", id)));
|
||||
bool success = true;
|
||||
std::map<hex::prv::Provider*, std::string> providerWarnings;
|
||||
for (const auto &id : providerIds) {
|
||||
auto providerSettings = nlohmann::json::parse(tar.readString(basePath / hex::format("{}.json", id)));
|
||||
|
||||
auto provider = ImHexApi::Provider::createProvider(providerSettings.at("type").get<std::string>(), true, false);
|
||||
ON_SCOPE_EXIT {
|
||||
if (!success) {
|
||||
for (auto &task : TaskManager::getRunningTasks())
|
||||
task->interrupt();
|
||||
auto providerType = providerSettings.at("type").get<std::string>();
|
||||
auto provider = ImHexApi::Provider::createProvider(providerType, true, false);
|
||||
ON_SCOPE_EXIT {
|
||||
if (!success) {
|
||||
for (auto &task : TaskManager::getRunningTasks())
|
||||
task->interrupt();
|
||||
|
||||
TaskManager::runWhenTasksFinished([]{
|
||||
for (auto provider : ImHexApi::Provider::getProviders())
|
||||
TaskManager::runWhenTasksFinished([]{
|
||||
for (auto provider : ImHexApi::Provider::getProviders())
|
||||
ImHexApi::Provider::remove(provider, true);
|
||||
});
|
||||
}
|
||||
};
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
if (provider == nullptr) {
|
||||
success = false;
|
||||
continue;
|
||||
}
|
||||
if (provider == nullptr) {
|
||||
// if a provider is not created, it will be overwritten when saving the project,
|
||||
// so we should prevent the project from loading at all
|
||||
showError(hex::format("hex.builtin.popup.error.project.load"_lang,
|
||||
hex::format("hex.builtin.popup.error.project.load.create_provider"_lang, providerType)
|
||||
));
|
||||
success = false;
|
||||
break;
|
||||
}
|
||||
|
||||
provider->setID(id);
|
||||
provider->loadSettings(providerSettings.at("settings"));
|
||||
if (!provider->open() || !provider->isAvailable() || !provider->isReadable())
|
||||
success = false;
|
||||
else
|
||||
EventManager::post<EventProviderOpened>(provider);
|
||||
}
|
||||
provider->setID(id);
|
||||
provider->loadSettings(providerSettings.at("settings"));
|
||||
if (!provider->open() || !provider->isAvailable() || !provider->isReadable()) {
|
||||
providerWarnings[provider] = provider->getErrorMessage();
|
||||
} else
|
||||
EventManager::post<EventProviderOpened>(provider);
|
||||
}
|
||||
|
||||
return success;
|
||||
},
|
||||
.store = [](const std::fs::path &basePath, Tar &tar) {
|
||||
std::vector<int> providerIds;
|
||||
for (const auto &provider : ImHexApi::Provider::getProviders()) {
|
||||
auto id = provider->getID();
|
||||
providerIds.push_back(id);
|
||||
std::string warningMsg;
|
||||
for(const auto &warning : providerWarnings){
|
||||
ImHexApi::Provider::remove(warning.first);
|
||||
warningMsg.append(
|
||||
hex::format("\n - {} : {}", warning.first->getName(), warning.second));
|
||||
}
|
||||
|
||||
nlohmann::json json;
|
||||
json["type"] = provider->getTypeName();
|
||||
json["settings"] = provider->storeSettings();
|
||||
// if no providers were opened, display an error with
|
||||
// the warnings that happened when opening them
|
||||
if (ImHexApi::Provider::getProviders().size() == 0) {
|
||||
showError(hex::format("hex.builtin.popup.error.project.load"_lang,
|
||||
hex::format("hex.builtin.popup.error.project.load.no_providers"_lang)) + warningMsg);
|
||||
|
||||
tar.writeString(basePath / hex::format("{}.json", id), json.dump(4));
|
||||
}
|
||||
return false;
|
||||
} else {
|
||||
|
||||
tar.writeString(basePath / "providers.json",
|
||||
// else, if are warnings, still display them
|
||||
if (warningMsg.empty()) return true;
|
||||
else {
|
||||
showWarning(
|
||||
hex::format("hex.builtin.popup.error.project.load.some_providers_failed"_lang, warningMsg));
|
||||
}
|
||||
return success;
|
||||
}
|
||||
},
|
||||
.store = [](const std::fs::path &basePath, Tar &tar) {
|
||||
std::vector<int> providerIds;
|
||||
for (const auto &provider : ImHexApi::Provider::getProviders()) {
|
||||
auto id = provider->getID();
|
||||
providerIds.push_back(id);
|
||||
|
||||
nlohmann::json json;
|
||||
json["type"] = provider->getTypeName();
|
||||
json["settings"] = provider->storeSettings();
|
||||
|
||||
tar.writeString(basePath / hex::format("{}.json", id), json.dump(4));
|
||||
}
|
||||
|
||||
tar.writeString(basePath / "providers.json",
|
||||
nlohmann::json({ { "providers", providerIds } }).dump(4)
|
||||
);
|
||||
);
|
||||
|
||||
return true;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
|
@ -205,6 +205,11 @@ namespace hex::plugin::builtin {
|
||||
this->m_readable = true;
|
||||
this->m_writable = true;
|
||||
|
||||
if (!std::fs::exists(this->m_path)) {
|
||||
this->setErrorMessage(hex::format("hex.builtin.provider.file.error.open"_lang, this->m_path.string(), ::strerror(ENOENT)));
|
||||
return false;
|
||||
}
|
||||
|
||||
wolv::io::File file(this->m_path, wolv::io::File::Mode::Write);
|
||||
if (!file.isValid()) {
|
||||
this->m_writable = false;
|
||||
|
@ -31,6 +31,7 @@ namespace hex::plugin::builtin {
|
||||
void registerBackgroundServices();
|
||||
void registerNetworkEndpoints();
|
||||
void registerFileHandlers();
|
||||
void registerProjectHandlers();
|
||||
|
||||
void addFooterItems();
|
||||
void addTitleBarButtons();
|
||||
@ -71,6 +72,7 @@ IMHEX_PLUGIN_SETUP("Built-in", "WerWolv", "Default ImHex functionality") {
|
||||
registerBackgroundServices();
|
||||
registerNetworkEndpoints();
|
||||
registerFileHandlers();
|
||||
registerProjectHandlers();
|
||||
|
||||
addFooterItems();
|
||||
addTitleBarButtons();
|
||||
|
Loading…
Reference in New Issue
Block a user