diff --git a/lib/external/pattern_language b/lib/external/pattern_language index 45c0e06bc..a6a58d794 160000 --- a/lib/external/pattern_language +++ b/lib/external/pattern_language @@ -1 +1 @@ -Subproject commit 45c0e06bcb720113252dbf25f1a1c2cd1d95a8ee +Subproject commit a6a58d79491c2a5a9cf37cb6dd9bd750cfa2c8e4 diff --git a/lib/libimhex/CMakeLists.txt b/lib/libimhex/CMakeLists.txt index 720363846..fdec2a9b1 100644 --- a/lib/libimhex/CMakeLists.txt +++ b/lib/libimhex/CMakeLists.txt @@ -110,6 +110,7 @@ set(LIBIMHEX_SOURCES source/api/keybinding.cpp source/api/plugin_manager.cpp source/api/localization.cpp + source/api/project_file_manager.cpp source/data_processor/attribute.cpp source/data_processor/link.cpp @@ -123,7 +124,6 @@ set(LIBIMHEX_SOURCES source/helpers/file.cpp source/helpers/socket.cpp source/helpers/patches.cpp - source/helpers/project_file_handler.cpp source/helpers/encoding_file.cpp source/helpers/logger.cpp source/helpers/tar.cpp diff --git a/lib/libimhex/include/hex/api/content_registry.hpp b/lib/libimhex/include/hex/api/content_registry.hpp index 15f04a899..f16d30151 100644 --- a/lib/libimhex/include/hex/api/content_registry.hpp +++ b/lib/libimhex/include/hex/api/content_registry.hpp @@ -224,7 +224,7 @@ namespace hex { namespace impl { - using CreatorFunction = std::function; + using CreatorFunction = std::function()>; struct Entry { std::string category; @@ -239,11 +239,15 @@ namespace hex { template T, typename... Args> void add(const std::string &unlocalizedCategory, const std::string &unlocalizedName, Args &&...args) { - add(impl::Entry { unlocalizedCategory.c_str(), unlocalizedName.c_str(), [=] { - auto node = new T(std::forward(args)...); - node->setUnlocalizedName(unlocalizedName); - return node; - } }); + add(impl::Entry { + unlocalizedCategory.c_str(), + unlocalizedName.c_str(), + [=] { + auto node = std::make_unique(std::forward(args)...); + node->setUnlocalizedName(unlocalizedName); + return node; + } + }); } void addSeparator(); @@ -330,8 +334,10 @@ namespace hex { } template T> - void add(const std::string &unlocalizedName, bool addToList = true) { - (void)EventManager::subscribe([expectedName = unlocalizedName](const std::string &name, hex::prv::Provider **provider) { + void add(bool addToList = true) { + auto typeName = T().getTypeName(); + + (void)EventManager::subscribe([expectedName = typeName](const std::string &name, hex::prv::Provider **provider) { if (name != expectedName) return; auto newProvider = new T(); @@ -343,7 +349,7 @@ namespace hex { }); if (addToList) - impl::addProviderName(unlocalizedName); + impl::addProviderName(typeName); } std::vector &getEntries(); diff --git a/lib/libimhex/include/hex/api/event.hpp b/lib/libimhex/include/hex/api/event.hpp index 9ae5afd4d..7e264d068 100644 --- a/lib/libimhex/include/hex/api/event.hpp +++ b/lib/libimhex/include/hex/api/event.hpp @@ -107,13 +107,14 @@ namespace hex { EVENT_DEF(EventHighlightingChanged); EVENT_DEF(EventWindowClosing, GLFWwindow *); EVENT_DEF(EventRegionSelected, Region); - EVENT_DEF(EventProjectFileStore); - EVENT_DEF(EventProjectFileLoad); EVENT_DEF(EventSettingsChanged); EVENT_DEF(EventAbnormalTermination, int); EVENT_DEF(EventOSThemeChanged); EVENT_DEF(EventProviderCreated, prv::Provider *); EVENT_DEF(EventProviderChanged, prv::Provider *, prv::Provider *); + EVENT_DEF(EventProviderOpened, prv::Provider *); + EVENT_DEF(EventProviderClosing, prv::Provider *, bool *); + EVENT_DEF(EventProviderClosed, prv::Provider *); EVENT_DEF(EventProviderDeleted, prv::Provider *); EVENT_DEF(EventFrameBegin); EVENT_DEF(EventFrameEnd); diff --git a/lib/libimhex/include/hex/api/imhex_api.hpp b/lib/libimhex/include/hex/api/imhex_api.hpp index eb987c854..d97be04c7 100644 --- a/lib/libimhex/include/hex/api/imhex_api.hpp +++ b/lib/libimhex/include/hex/api/imhex_api.hpp @@ -119,6 +119,13 @@ namespace hex { namespace Provider { + namespace impl { + + void resetClosingProvider(); + prv::Provider* getClosingProvider(); + + } + prv::Provider *get(); const std::vector &getProviders(); @@ -126,6 +133,10 @@ namespace hex { bool isValid(); + void markDirty(); + void resetDirty(); + bool isDirty(); + void add(prv::Provider *provider); template T> @@ -133,7 +144,7 @@ namespace hex { add(new T(std::forward(args)...)); } - void remove(prv::Provider *provider); + void remove(prv::Provider *provider, bool noQuestions = false); prv::Provider* createProvider(const std::string &unlocalizedName); diff --git a/lib/libimhex/include/hex/api/project_file_manager.hpp b/lib/libimhex/include/hex/api/project_file_manager.hpp new file mode 100644 index 000000000..3f3ae36d8 --- /dev/null +++ b/lib/libimhex/include/hex/api/project_file_manager.hpp @@ -0,0 +1,58 @@ +#pragma once + +#include +#include +#include + +#include +#include + +#include +#include +#include +#include + +namespace hex { + + class ProjectFile { + public: + struct Handler { + using Function = std::function; + std::fs::path basePath; + Function load, store; + }; + + struct ProviderHandler { + using Function = std::function; + std::fs::path basePath; + Function load, store; + }; + + static bool load(const std::fs::path &filePath); + static bool store(std::optional filePath = std::nullopt); + + static void registerHandler(const Handler &handler) { + getHandlers().push_back(handler); + } + + static void registerPerProviderHandler(const ProviderHandler &handler) { + getProviderHandlers().push_back(handler); + } + + static std::vector& getHandlers() { + return s_handlers; + } + + static std::vector& getProviderHandlers() { + return s_providerHandlers; + } + + private: + ProjectFile() = default; + + static std::fs::path s_currProjectPath; + static std::vector s_handlers; + static std::vector s_providerHandlers; + }; + +} \ No newline at end of file diff --git a/lib/libimhex/include/hex/data_processor/node.hpp b/lib/libimhex/include/hex/data_processor/node.hpp index abb08a1c9..c5fcde804 100644 --- a/lib/libimhex/include/hex/data_processor/node.hpp +++ b/lib/libimhex/include/hex/data_processor/node.hpp @@ -42,7 +42,10 @@ namespace hex::dp { virtual void store(nlohmann::json &j) { hex::unused(j); } virtual void load(nlohmann::json &j) { hex::unused(j); } - using NodeError = std::pair; + struct NodeError { + Node *node; + std::string message; + }; void resetOutputData() { for (auto &attribute : this->m_attributes) diff --git a/lib/libimhex/include/hex/helpers/fs.hpp b/lib/libimhex/include/hex/helpers/fs.hpp index ccd7873f1..130312316 100644 --- a/lib/libimhex/include/hex/helpers/fs.hpp +++ b/lib/libimhex/include/hex/helpers/fs.hpp @@ -65,6 +65,12 @@ namespace hex::fs { else return size; } + static inline bool isSubPath(const std::fs::path& base, const std::fs::path& destination) { + const auto relative = std::fs::relative(destination, base).string(); + + return relative.size() == 1 || (relative[0] != '.' && relative[1] != '.'); + } + bool isPathWritable(const std::fs::path &path); std::fs::path toShortPath(const std::fs::path &path); diff --git a/lib/libimhex/include/hex/helpers/project_file_handler.hpp b/lib/libimhex/include/hex/helpers/project_file_handler.hpp deleted file mode 100644 index 87edde6ac..000000000 --- a/lib/libimhex/include/hex/helpers/project_file_handler.hpp +++ /dev/null @@ -1,105 +0,0 @@ -#pragma once - -#include -#include -#include - -#include "patches.hpp" -#include -#include - -#include - -namespace hex { - - class ProjectFile { - public: - ProjectFile() = delete; - - static bool load(const std::fs::path &filePath); - static bool store(std::fs::path filePath = {}); - - [[nodiscard]] static bool hasUnsavedChanges() { - return ProjectFile::s_hasUnsavedChanged; - } - - static void markDirty() { - bool setWindowTitle = !hasUnsavedChanges(); - - ProjectFile::s_hasUnsavedChanged = true; - - if (setWindowTitle) - EventManager::post(std::fs::path(getFilePath()).filename().string()); - } - - [[nodiscard]] static const std::fs::path &getProjectFilePath() { - return ProjectFile::s_currProjectFilePath; - } - - static void clearProjectFilePath() { - ProjectFile::s_currProjectFilePath.clear(); - } - - - [[nodiscard]] static const std::fs::path &getFilePath() { - return ProjectFile::s_filePath; - } - - static void setFilePath(const std::fs::path &filePath) { - ProjectFile::s_filePath = filePath; - - EventManager::post(filePath.filename().string()); - } - - - [[nodiscard]] static const std::string &getPattern() { - return ProjectFile::s_pattern; - } - - static void setPattern(const std::string &pattern) { - markDirty(); - ProjectFile::s_pattern = pattern; - } - - - [[nodiscard]] static const Patches &getPatches() { - return ProjectFile::s_patches; - } - - static void setPatches(const Patches &patches) { - markDirty(); - ProjectFile::s_patches = patches; - } - - - [[nodiscard]] static const std::list &getBookmarks() { - return ProjectFile::s_bookmarks; - } - - static void setBookmarks(const std::list &bookmarks) { - markDirty(); - ProjectFile::s_bookmarks = bookmarks; - } - - - [[nodiscard]] static const std::string &getDataProcessorContent() { - return ProjectFile::s_dataProcessorContent; - } - - static void setDataProcessorContent(const std::string &json) { - markDirty(); - ProjectFile::s_dataProcessorContent = json; - } - - private: - static std::fs::path s_currProjectFilePath; - static bool s_hasUnsavedChanged; - - static std::fs::path s_filePath; - static std::string s_pattern; - static Patches s_patches; - static std::list s_bookmarks; - static std::string s_dataProcessorContent; - }; - -} \ No newline at end of file diff --git a/lib/libimhex/include/hex/helpers/tar.hpp b/lib/libimhex/include/hex/helpers/tar.hpp index e8d9f276d..22a5bf578 100644 --- a/lib/libimhex/include/hex/helpers/tar.hpp +++ b/lib/libimhex/include/hex/helpers/tar.hpp @@ -19,17 +19,31 @@ namespace hex { Tar() = default; Tar(const std::fs::path &path, Mode mode); ~Tar(); + Tar(const Tar&) = delete; + Tar(Tar&&) noexcept; + + Tar &operator=(Tar &&other) noexcept; + + void close(); + + [[nodiscard]] std::vector read(const std::fs::path &path); + [[nodiscard]] std::string readString(const std::fs::path &path); - std::vector read(const std::fs::path &path); void write(const std::fs::path &path, const std::vector &data); + void write(const std::fs::path &path, const std::string &data); - std::vector listEntries(); + [[nodiscard]] std::vector listEntries(const std::fs::path &basePath = "/"); + [[nodiscard]] bool contains(const std::fs::path &path); void extract(const std::fs::path &path, const std::fs::path &outputPath); void extractAll(const std::fs::path &outputPath); + [[nodiscard]] bool isValid() const { return this->m_valid; } + private: mtar_t m_ctx = { }; + + bool m_valid = false; }; } \ No newline at end of file diff --git a/lib/libimhex/include/hex/providers/provider.hpp b/lib/libimhex/include/hex/providers/provider.hpp index 06037227c..2cc2fdf5c 100644 --- a/lib/libimhex/include/hex/providers/provider.hpp +++ b/lib/libimhex/include/hex/providers/provider.hpp @@ -8,9 +8,12 @@ #include #include +#include #include #include +#include + namespace pl { class PatternLanguage; } @@ -67,8 +70,8 @@ namespace hex::prv { [[nodiscard]] virtual std::string getName() const = 0; [[nodiscard]] virtual std::vector> getDataInformation() const = 0; - [[nodiscard]] virtual bool open() = 0; - virtual void close() = 0; + [[nodiscard]] virtual bool open(); + virtual void close(); void addPatch(u64 offset, const void *buffer, size_t size, bool createUndo = false); void createUndoPoint(); @@ -84,8 +87,17 @@ namespace hex::prv { virtual void drawLoadInterface(); virtual void drawInterface(); - pl::PatternLanguage &getPatternLanguageRuntime() { return *this->m_patternLanguageRuntime; } - std::string &getPatternLanguageSourceCode() { return this->m_patternLanguageSourceCode; } + [[nodiscard]] u32 getID() const { + return this->m_id; + } + + [[nodiscard]] virtual nlohmann::json storeSettings(nlohmann::json settings = { }) const; + virtual void loadSettings(const nlohmann::json &settings); + + [[nodiscard]] virtual std::string getTypeName() const = 0; + + void markDirty(bool dirty = true) { this->m_dirty = dirty; } + [[nodiscard]] bool isDirty() const { return this->m_dirty; } protected: u32 m_currPage = 0; @@ -95,8 +107,12 @@ namespace hex::prv { std::list> m_patches; std::list m_overlays; - std::unique_ptr m_patternLanguageRuntime; - std::string m_patternLanguageSourceCode; + u32 m_id; + + bool m_dirty = false; + + private: + static u32 s_idCounter; }; } \ No newline at end of file diff --git a/lib/libimhex/source/api/content_registry.cpp b/lib/libimhex/source/api/content_registry.cpp index a229a9082..d97c8d51b 100644 --- a/lib/libimhex/source/api/content_registry.cpp +++ b/lib/libimhex/source/api/content_registry.cpp @@ -10,6 +10,8 @@ #include +#include + namespace hex { namespace ContentRegistry::Settings { diff --git a/lib/libimhex/source/api/imhex_api.cpp b/lib/libimhex/source/api/imhex_api.cpp index 726bbf165..f16b5403a 100644 --- a/lib/libimhex/source/api/imhex_api.cpp +++ b/lib/libimhex/source/api/imhex_api.cpp @@ -214,6 +214,19 @@ namespace hex { static u32 s_currentProvider; static std::vector s_providers; + namespace impl { + + static prv::Provider *s_closingProvider = nullptr; + void resetClosingProvider() { + s_closingProvider = nullptr; + } + + prv::Provider* getClosingProvider() { + return s_closingProvider; + } + + } + prv::Provider *get() { if (!ImHexApi::Provider::isValid()) return nullptr; @@ -240,6 +253,21 @@ namespace hex { return !s_providers.empty() && s_currentProvider < s_providers.size(); } + void markDirty() { + get()->markDirty(); + } + + void resetDirty() { + for (auto &provider : s_providers) + provider->markDirty(false); + } + + bool isDirty() { + return std::ranges::any_of(s_providers, [](const auto &provider) { + return provider->isDirty(); + }); + } + void add(prv::Provider *provider) { if (Task::getRunningTaskCount() > 0) return; @@ -250,13 +278,22 @@ namespace hex { setCurrentProvider(s_providers.size() - 1); } - void remove(prv::Provider *provider) { + void remove(prv::Provider *provider, bool noQuestions) { if (provider == nullptr) return; if (Task::getRunningTaskCount() > 0) return; + if (!noQuestions) { + impl::s_closingProvider = provider; + + bool shouldClose = true; + EventManager::post(provider, &shouldClose); + if (!shouldClose) + return; + } + auto it = std::find(s_providers.begin(), s_providers.end(), provider); if (it == s_providers.end()) return; diff --git a/lib/libimhex/source/api/project_file_manager.cpp b/lib/libimhex/source/api/project_file_manager.cpp new file mode 100644 index 000000000..7ef0dc1eb --- /dev/null +++ b/lib/libimhex/source/api/project_file_manager.cpp @@ -0,0 +1,107 @@ +#include + +#include +#include +#include + +#include + +namespace hex { + + constexpr static auto MetadataHeaderMagic = "HEX"; + constexpr static auto MetadataPath = "IMHEX_METADATA"; + + std::vector ProjectFile::s_handlers; + std::vector ProjectFile::s_providerHandlers; + + std::fs::path ProjectFile::s_currProjectPath; + + bool ProjectFile::load(const std::fs::path &filePath) { + if (!fs::exists(filePath) || !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.read(MetadataPath); + + if (!std::string(metadataContent.begin(), metadataContent.end()).starts_with(MetadataHeaderMagic)) + return false; + } + + bool result = true; + for (const auto &handler : ProjectFile::getHandlers()) { + try { + if (!handler.load(handler.basePath, tar)) + result = false; + } catch (std::exception &e) { + log::info("{}", e.what()); + 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.load(provider, basePath / handler.basePath, tar)) + result = false; + } catch (std::exception &e) { + log::info("{}", e.what()); + result = false; + } + } + } + + ProjectFile::s_currProjectPath = filePath; + + return result; + } + + bool ProjectFile::store(std::optional filePath) { + if (!filePath.has_value()) + filePath = ProjectFile::s_currProjectPath; + + 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)) + result = false; + } catch (std::exception &e) { + log::info("{}", e.what()); + 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)) + result = false; + } catch (std::exception &e) { + log::info("{}", e.what()); + result = false; + } + } + } + + { + const auto metadataContent = hex::format("{}\n{}", MetadataHeaderMagic, IMHEX_VERSION); + tar.write(MetadataPath, metadataContent); + } + + return result; + } + +} \ No newline at end of file diff --git a/lib/libimhex/source/helpers/project_file_handler.cpp b/lib/libimhex/source/helpers/project_file_handler.cpp deleted file mode 100644 index e3605e150..000000000 --- a/lib/libimhex/source/helpers/project_file_handler.cpp +++ /dev/null @@ -1,115 +0,0 @@ -#include - -#include - -#include -#include - -using json = nlohmann::json; - -namespace hex { - - std::fs::path ProjectFile::s_currProjectFilePath; - bool ProjectFile::s_hasUnsavedChanged = false; - - std::fs::path ProjectFile::s_filePath; - std::string ProjectFile::s_pattern; - Patches ProjectFile::s_patches; - std::list ProjectFile::s_bookmarks; - std::string ProjectFile::s_dataProcessorContent; - - void to_json(json &j, const ImHexApi::Bookmarks::Entry &b) { - j = json { - {"address", b.region.address}, - { "size", b.region.size }, - { "name", b.name.data() }, - { "comment", b.comment.data()}, - { "locked", b.locked }, - { "color", b.color } - }; - } - - void from_json(const json &j, ImHexApi::Bookmarks::Entry &b) { - std::string name, comment; - - if (j.contains("address")) j.at("address").get_to(b.region.address); - if (j.contains("size")) j.at("size").get_to(b.region.size); - if (j.contains("name")) j.at("name").get_to(name); - if (j.contains("comment")) j.at("comment").get_to(comment); - if (j.contains("locked")) j.at("locked").get_to(b.locked); - if (j.contains("color")) j.at("color").get_to(b.color); - - std::copy(name.begin(), name.end(), std::back_inserter(b.name)); - b.name.push_back('\0'); - std::copy(comment.begin(), comment.end(), std::back_inserter(b.comment)); - b.comment.push_back('\0'); - } - - - bool ProjectFile::load(const std::fs::path &filePath) { - ProjectFile::s_hasUnsavedChanged = false; - - json projectFileData; - - try { - std::ifstream projectFile(filePath); - projectFile >> projectFileData; - - ProjectFile::s_filePath = std::fs::path(projectFileData["filePath"].get()); - ProjectFile::s_pattern = projectFileData["pattern"]; - ProjectFile::s_patches = projectFileData["patches"].get(); - ProjectFile::s_dataProcessorContent = projectFileData["dataProcessor"]; - - ProjectFile::s_bookmarks.clear(); - for (auto &element : projectFileData["bookmarks"].items()) { - ImHexApi::Bookmarks::Entry entry; - from_json(element.value(), entry); - ProjectFile::s_bookmarks.emplace_back(std::move(entry)); - } - - } catch (json::exception &e) { - return false; - } catch (std::ofstream::failure &e) { - return false; - } - - ProjectFile::s_currProjectFilePath = filePath; - - EventManager::post(); - - return true; - } - - bool ProjectFile::store(std::fs::path filePath) { - EventManager::post(); - - json projectFileData; - - if (filePath.empty()) - filePath = ProjectFile::s_currProjectFilePath; - - try { - projectFileData["filePath"] = ProjectFile::s_filePath.u8string(); - projectFileData["pattern"] = ProjectFile::s_pattern; - projectFileData["patches"] = ProjectFile::s_patches; - projectFileData["dataProcessor"] = ProjectFile::s_dataProcessorContent; - - for (auto &bookmark : ProjectFile::s_bookmarks) { - to_json(projectFileData["bookmarks"].emplace_back(), bookmark); - } - - std::ofstream projectFile(filePath.c_str(), std::fstream::trunc); - projectFile << projectFileData; - } catch (json::exception &e) { - return false; - } catch (std::ifstream::failure &e) { - return false; - } - - ProjectFile::s_hasUnsavedChanged = false; - ProjectFile::s_currProjectFilePath = filePath; - - return true; - } - -} \ No newline at end of file diff --git a/lib/libimhex/source/helpers/tar.cpp b/lib/libimhex/source/helpers/tar.cpp index 2035599b3..033bdbfa5 100644 --- a/lib/libimhex/source/helpers/tar.cpp +++ b/lib/libimhex/source/helpers/tar.cpp @@ -7,26 +7,50 @@ namespace hex { using namespace hex::literals; Tar::Tar(const std::fs::path &path, Mode mode) { + int error = MTAR_ESUCCESS; + if (mode == Tar::Mode::Read) - mtar_open(&this->m_ctx, path.string().c_str(), "r"); + error = mtar_open(&this->m_ctx, path.string().c_str(), "r"); else if (mode == Tar::Mode::Write) - mtar_open(&this->m_ctx, path.string().c_str(), "a"); + error = mtar_open(&this->m_ctx, path.string().c_str(), "a"); else if (mode == Tar::Mode::Create) - mtar_open(&this->m_ctx, path.string().c_str(), "w"); + error = mtar_open(&this->m_ctx, path.string().c_str(), "w"); + else + error = MTAR_EFAILURE; + + this->m_valid = (error == MTAR_ESUCCESS); } Tar::~Tar() { - mtar_finalize(&this->m_ctx); - mtar_close(&this->m_ctx); + this->close(); } - std::vector Tar::listEntries() { + Tar::Tar(hex::Tar &&other) noexcept { + this->m_ctx = other.m_ctx; + this->m_valid = other.m_valid; + + other.m_ctx = { }; + other.m_valid = false; + } + + Tar &Tar::operator=(Tar &&other) noexcept { + this->m_ctx = other.m_ctx; + other.m_ctx = { }; + + this->m_valid = other.m_valid; + other.m_valid = false; + + return *this; + } + + std::vector Tar::listEntries(const std::fs::path &basePath) { std::vector result; const std::string PaxHeaderName = "@PaxHeader"; mtar_header_t header; while (mtar_read_header(&this->m_ctx, &header) != MTAR_ENULLRECORD) { - if (header.name != PaxHeaderName) { + std::fs::path path = header.name; + if (header.name != PaxHeaderName && fs::isSubPath(basePath, path)) { result.emplace_back(header.name); } @@ -36,9 +60,29 @@ namespace hex { return result; } + bool Tar::contains(const std::fs::path &path) { + mtar_header_t header; + return mtar_find(&this->m_ctx, path.string().c_str(), &header) == MTAR_ESUCCESS; + } + + void Tar::close() { + if (this->m_valid) { + mtar_finalize(&this->m_ctx); + mtar_close(&this->m_ctx); + } + + this->m_ctx = { }; + this->m_valid = false; + } + std::vector Tar::read(const std::fs::path &path) { mtar_header_t header; - mtar_find(&this->m_ctx, path.string().c_str(), &header); + + auto fixedPath = path.string(); + #if defined(OS_WINDOWS) + std::replace(fixedPath.begin(), fixedPath.end(), '\\', '/'); + #endif + mtar_find(&this->m_ctx, fixedPath.c_str(), &header); std::vector result(header.size, 0x00); mtar_read_data(&this->m_ctx, result.data(), result.size()); @@ -46,19 +90,37 @@ namespace hex { return result; } + std::string Tar::readString(const std::fs::path &path) { + auto result = this->read(path); + return { result.begin(), result.end() }; + } + void Tar::write(const std::fs::path &path, const std::vector &data) { if (path.has_parent_path()) { std::fs::path pathPart; for (const auto &part : path.parent_path()) { pathPart /= part; - mtar_write_dir_header(&this->m_ctx, pathPart.string().c_str()); + + auto fixedPath = pathPart.string(); + #if defined(OS_WINDOWS) + std::replace(fixedPath.begin(), fixedPath.end(), '\\', '/'); + #endif + mtar_write_dir_header(&this->m_ctx, fixedPath.c_str()); } } - mtar_write_file_header(&this->m_ctx, path.string().c_str(), data.size()); + auto fixedPath = path.string(); + #if defined(OS_WINDOWS) + std::replace(fixedPath.begin(), fixedPath.end(), '\\', '/'); + #endif + mtar_write_file_header(&this->m_ctx, fixedPath.c_str(), data.size()); mtar_write_data(&this->m_ctx, data.data(), data.size()); } + void Tar::write(const std::fs::path &path, const std::string &data) { + this->write(path, std::vector(data.begin(), data.end())); + } + static void writeFile(mtar_t *ctx, mtar_header_t *header, const std::fs::path &path) { constexpr static u64 BufferSize = 1_MiB; diff --git a/lib/libimhex/source/providers/provider.cpp b/lib/libimhex/source/providers/provider.cpp index e7f9179dc..749946ce0 100644 --- a/lib/libimhex/source/providers/provider.cpp +++ b/lib/libimhex/source/providers/provider.cpp @@ -1,7 +1,7 @@ #include #include -#include +#include #include #include @@ -10,9 +10,10 @@ namespace hex::prv { - Provider::Provider() { + u32 Provider::s_idCounter = 0; + + Provider::Provider() : m_id(s_idCounter++) { this->m_patches.emplace_back(); - this->m_patternLanguageRuntime = ContentRegistry::PatternLanguage::createDefaultRuntime(this); } Provider::~Provider() { @@ -28,6 +29,7 @@ namespace hex::prv { void Provider::write(u64 offset, const void *buffer, size_t size) { this->writeRaw(offset - this->getBaseAddress(), buffer, size); + this->markDirty(); } void Provider::save() { } @@ -36,7 +38,9 @@ namespace hex::prv { } void Provider::resize(size_t newSize) { - this->m_patternLanguageRuntime->setDataSize(newSize); + hex::unused(newSize); + + this->markDirty(); } void Provider::insert(u64 offset, size_t size) { @@ -53,6 +57,8 @@ namespace hex::prv { patches.erase(address); for (const auto &[address, value] : patchesToMove) patches.insert({ address + size, value }); + + this->markDirty(); } void Provider::remove(u64 offset, size_t size) { @@ -69,6 +75,8 @@ namespace hex::prv { patches.erase(address); for (const auto &[address, value] : patchesToMove) patches.insert({ address - size, value }); + + this->markDirty(); } void Provider::applyOverlays(u64 offset, void *buffer, size_t size) { @@ -104,6 +112,7 @@ namespace hex::prv { for (auto &[patchAddress, patch] : getPatches()) { this->writeRaw(patchAddress - this->getBaseAddress(), &patch, 1); } + this->markDirty(); } @@ -137,7 +146,7 @@ namespace hex::prv { void Provider::setBaseAddress(u64 address) { this->m_baseAddress = address; - this->m_patternLanguageRuntime->setDataBaseAddress(address); + this->markDirty(); } u64 Provider::getBaseAddress() const { @@ -161,6 +170,14 @@ namespace hex::prv { return page; } + bool Provider::open() { + EventManager::post(this); + return true; + } + void Provider::close() { + EventManager::post(this); + } + void Provider::addPatch(u64 offset, const void *buffer, size_t size, bool createUndo) { if (this->m_patchTreeOffset > 0) { auto iter = this->m_patches.end(); @@ -184,6 +201,8 @@ namespace hex::prv { else getPatches()[offset + i] = patch; } + + this->markDirty(); } void Provider::createUndoPoint() { @@ -223,4 +242,16 @@ namespace hex::prv { void Provider::drawInterface() { } + nlohmann::json Provider::storeSettings(nlohmann::json settings) const { + settings["baseAddress"] = this->m_baseAddress; + settings["currPage"] = this->m_currPage; + + return settings; + } + + void Provider::loadSettings(const nlohmann::json &settings) { + this->m_baseAddress = settings["baseAddress"]; + this->m_currPage = settings["currPage"]; + } + } diff --git a/main/source/main.cpp b/main/source/main.cpp index 60bb72b24..3954aab56 100644 --- a/main/source/main.cpp +++ b/main/source/main.cpp @@ -8,11 +8,12 @@ #include "init/splash_window.hpp" #include "init/tasks.hpp" +#include + int main(int argc, char **argv, char **envp) { using namespace hex; ImHexApi::System::impl::setProgramArguments(argc, argv, envp); - #if defined(OS_WINDOWS) ImHexApi::System::impl::setBorderlessWindowMode(true); #endif diff --git a/main/source/window/window.cpp b/main/source/window/window.cpp index 6110948c5..8574e30f3 100644 --- a/main/source/window/window.cpp +++ b/main/source/window/window.cpp @@ -32,7 +32,7 @@ #include -#include +#include #include @@ -63,6 +63,20 @@ namespace hex { buf->append("\n"); } + static void signalHandler(int signalNumber) { + log::fatal("Terminating with signal {}", signalNumber); + EventManager::post(signalNumber); + + if (std::uncaught_exceptions() > 0) { + log::fatal("Uncaught exception thrown!"); + } + + // Let's not loop on this... + std::signal(signalNumber, nullptr); + + std::raise(signalNumber); + }; + Window::Window() { { for (const auto &[argument, value] : ImHexApi::System::getInitArguments()) { @@ -81,7 +95,7 @@ namespace hex { this->setupNativeWindow(); EventManager::subscribe(this, [this](bool noQuestions) { - glfwSetWindowShouldClose(this->m_window, true); + glfwSetWindowShouldClose(this->m_window, GLFW_TRUE); if (!noQuestions) EventManager::post(this->m_window); @@ -95,13 +109,14 @@ namespace hex { std::string title = "ImHex"; if (ImHexApi::Provider::isValid()) { + auto provider = ImHexApi::Provider::get(); if (!windowTitle.empty()) title += " - " + windowTitle; - if (ProjectFile::hasUnsavedChanges()) + if (provider->isDirty()) title += " (*)"; - if (!ImHexApi::Provider::get()->isWritable()) + if (!provider->isWritable()) title += " (Read Only)"; } @@ -114,11 +129,11 @@ namespace hex { EventManager::subscribe(this, [this, CrashBackupFileName](int) { ImGui::SaveIniSettingsToDisk(this->m_imguiSettingsPath.string().c_str()); - if (!ProjectFile::hasUnsavedChanges()) + if (!ImHexApi::Provider::isDirty()) return; for (const auto &path : fs::getDefaultPaths(fs::ImHexPath::Config)) { - if (ProjectFile::store(std::fs::path(path) / CrashBackupFileName)) + if (ProjectFile::store((std::fs::path(path) / CrashBackupFileName).string())) break; } }); @@ -127,29 +142,9 @@ namespace hex { this->m_popupsToOpen.push_back(name); }); - auto signalHandler = [](int signalNumber) { - EventManager::post(signalNumber); - - if (std::uncaught_exceptions() > 0) { - log::fatal("Uncaught exception thrown!"); - } - - // Let's not loop on this... - std::signal(signalNumber, nullptr); - -#if defined(DEBUG) - assert(false); -#else - std::raise(signalNumber); -#endif - }; - - std::signal(SIGTERM, signalHandler); - std::signal(SIGSEGV, signalHandler); - std::signal(SIGINT, signalHandler); - std::signal(SIGILL, signalHandler); - std::signal(SIGABRT, signalHandler); - std::signal(SIGFPE, signalHandler); + for (u32 signal = 0; signal < NSIG; signal++) + std::signal(signal, signalHandler); + std::set_terminate([]{ signalHandler(SIGTERM); }); auto imhexLogo = romfs::get("logo.png"); this->m_logoTexture = ImGui::LoadImageFromMemory(reinterpret_cast(imhexLogo.data()), imhexLogo.size()); @@ -199,6 +194,13 @@ namespace hex { this->frameBegin(); this->frame(); this->frameEnd(); + + const auto targetFps = ImHexApi::System::getTargetFPS(); + if (targetFps <= 200) + std::this_thread::sleep_for(std::chrono::milliseconds(u64((this->m_lastFrameTime + 1 / targetFps - glfwGetTime()) * 1000))); + + this->m_lastFrameTime = glfwGetTime(); + this->m_hadEvent = false; } } @@ -493,12 +495,6 @@ namespace hex { glfwMakeContextCurrent(backup_current_context); glfwSwapBuffers(this->m_window); - - const auto targetFps = ImHexApi::System::getTargetFPS(); - if (targetFps <= 200) - std::this_thread::sleep_for(std::chrono::milliseconds(u64((this->m_lastFrameTime + 1 / targetFps - glfwGetTime()) * 1000))); - - this->m_lastFrameTime = glfwGetTime(); } void Window::initGLFW() { diff --git a/plugins/builtin/include/content/providers/disk_provider.hpp b/plugins/builtin/include/content/providers/disk_provider.hpp index 1a7e98ea1..f2aea16ab 100644 --- a/plugins/builtin/include/content/providers/disk_provider.hpp +++ b/plugins/builtin/include/content/providers/disk_provider.hpp @@ -38,6 +38,13 @@ namespace hex::plugin::builtin::prv { [[nodiscard]] bool hasLoadInterface() const override { return true; } void drawLoadInterface() override; + void loadSettings(const nlohmann::json &settings) override; + [[nodiscard]] nlohmann::json storeSettings(nlohmann::json settings = { }) const override; + + [[nodiscard]] std::string getTypeName() const override { + return "hex.builtin.provider.disk"; + } + protected: void reloadDrives(); diff --git a/plugins/builtin/include/content/providers/file_provider.hpp b/plugins/builtin/include/content/providers/file_provider.hpp index 55a8ce352..4df8a289d 100644 --- a/plugins/builtin/include/content/providers/file_provider.hpp +++ b/plugins/builtin/include/content/providers/file_provider.hpp @@ -7,11 +7,15 @@ #include #if defined(OS_WINDOWS) + #include + #else + #include #include #include + #endif namespace hex::plugin::builtin::prv { @@ -50,13 +54,24 @@ namespace hex::plugin::builtin::prv { [[nodiscard]] bool open() override; void close() override; + void loadSettings(const nlohmann::json &settings) override; + [[nodiscard]] nlohmann::json storeSettings(nlohmann::json settings) const override; + + [[nodiscard]] std::string getTypeName() const override { + return "hex.builtin.provider.file"; + } + protected: -#if defined(OS_WINDOWS) - HANDLE m_file = INVALID_HANDLE_VALUE; - HANDLE m_mapping = INVALID_HANDLE_VALUE; -#else - int m_file = -1; -#endif + #if defined(OS_WINDOWS) + + HANDLE m_file = INVALID_HANDLE_VALUE; + HANDLE m_mapping = INVALID_HANDLE_VALUE; + + #else + + int m_file = -1; + + #endif std::fs::path m_path; void *m_mappedFile = nullptr; diff --git a/plugins/builtin/include/content/providers/gdb_provider.hpp b/plugins/builtin/include/content/providers/gdb_provider.hpp index 7c042bac1..abbfce6b7 100644 --- a/plugins/builtin/include/content/providers/gdb_provider.hpp +++ b/plugins/builtin/include/content/providers/gdb_provider.hpp @@ -12,7 +12,7 @@ namespace hex::plugin::builtin::prv { class GDBProvider : public hex::prv::Provider { public: - explicit GDBProvider(); + GDBProvider(); ~GDBProvider() override; [[nodiscard]] bool isAvailable() const override; @@ -42,6 +42,13 @@ namespace hex::plugin::builtin::prv { [[nodiscard]] bool hasLoadInterface() const override { return true; } void drawLoadInterface() override; + void loadSettings(const nlohmann::json &settings) override; + [[nodiscard]] nlohmann::json storeSettings(nlohmann::json settings) const override; + + [[nodiscard]] std::string getTypeName() const override { + return "hex.builtin.provider.gdb"; + } + protected: hex::Socket m_socket; diff --git a/plugins/builtin/include/content/views/view_bookmarks.hpp b/plugins/builtin/include/content/views/view_bookmarks.hpp index 3752b53d5..4aeb4da55 100644 --- a/plugins/builtin/include/content/views/view_bookmarks.hpp +++ b/plugins/builtin/include/content/views/view_bookmarks.hpp @@ -15,7 +15,6 @@ namespace hex::plugin::builtin { void drawContent() override; private: - std::list m_bookmarks; std::string m_currFilter; }; diff --git a/plugins/builtin/include/content/views/view_data_processor.hpp b/plugins/builtin/include/content/views/view_data_processor.hpp index 422db0765..6e7a5cfc4 100644 --- a/plugins/builtin/include/content/views/view_data_processor.hpp +++ b/plugins/builtin/include/content/views/view_data_processor.hpp @@ -20,25 +20,17 @@ namespace hex::plugin::builtin { void drawContent() override; private: - std::list m_endNodes; - std::list m_nodes; - std::list m_links; - - std::vector m_dataOverlays; - int m_rightClickedId = -1; ImVec2 m_rightClickedCoords; - std::optional m_currNodeError; - bool m_continuousEvaluation = false; void eraseLink(u32 id); void eraseNodes(const std::vector &ids); void processNodes(); - std::string saveNodes(); - void loadNodes(const std::string &data); + std::string saveNodes(prv::Provider *provider); + void loadNodes(prv::Provider *provider, const std::string &data); }; } \ No newline at end of file diff --git a/plugins/builtin/include/provider_extra_data.hpp b/plugins/builtin/include/provider_extra_data.hpp new file mode 100644 index 000000000..3fce67b20 --- /dev/null +++ b/plugins/builtin/include/provider_extra_data.hpp @@ -0,0 +1,56 @@ +#pragma once + +#include +#include + +#include +#include +#include +#include + +namespace hex::plugin::builtin { + + class ProviderExtraData { + public: + struct Data { + bool dataDirty = false; + + struct { + std::string sourceCode; + std::unique_ptr runtime; + } patternLanguage; + + std::list bookmarks; + + struct { + std::list endNodes; + std::list> nodes; + std::list links; + + std::vector dataOverlays; + std::optional currNodeError; + } dataProcessor; + }; + + static Data& getCurrent() { + return get(ImHexApi::Provider::get()); + } + + static Data& get(hex::prv::Provider *provider) { + return s_data[provider]; + } + + static void erase(hex::prv::Provider *provider) { + s_data.erase(provider); + } + + static bool markDirty() { + return getCurrent().dataDirty = true; + } + + private: + ProviderExtraData() = default; + static inline std::map s_data = {}; + }; + +} \ No newline at end of file diff --git a/plugins/builtin/source/content/data_processor_nodes.cpp b/plugins/builtin/source/content/data_processor_nodes.cpp index 7153b7b7a..fa670e571 100644 --- a/plugins/builtin/source/content/data_processor_nodes.cpp +++ b/plugins/builtin/source/content/data_processor_nodes.cpp @@ -196,11 +196,11 @@ namespace hex::plugin::builtin { class NodeComment : public dp::Node { public: NodeComment() : Node("hex.builtin.nodes.constants.comment.header", {}) { - this->m_comment.resize(0xFFF, 0x00); + } void drawNode() override { - ImGui::InputTextMultiline("##string", reinterpret_cast(this->m_comment.data()), this->m_comment.size() - 1, ImVec2(150, 100)); + ImGui::InputTextMultiline("##string", this->m_comment, scaled(ImVec2(150, 100))); } void process() override { diff --git a/plugins/builtin/source/content/events.cpp b/plugins/builtin/source/content/events.cpp index 894a51daa..b0ffa6f46 100644 --- a/plugins/builtin/source/content/events.cpp +++ b/plugins/builtin/source/content/events.cpp @@ -3,14 +3,16 @@ #include #include -#include #include #include #include +#include #include +#include #include "content/providers/file_provider.hpp" +#include "provider_extra_data.hpp" namespace hex::plugin::builtin { @@ -38,25 +40,27 @@ namespace hex::plugin::builtin { return; } - ProjectFile::setFilePath(path); - EventManager::post(path); EventManager::post(); EventManager::post(); } void registerEventHandlers() { - EventManager::subscribe([]() { - EventManager::post(ProjectFile::getFilePath()); - }); EventManager::subscribe([](GLFWwindow *window) { - if (ProjectFile::hasUnsavedChanges()) { + if (ImHexApi::Provider::isDirty()) { glfwSetWindowShouldClose(window, GLFW_FALSE); ImHexApi::Tasks::doLater([] { ImGui::OpenPopup("hex.builtin.popup.exit_application.title"_lang); }); } }); + EventManager::subscribe([](hex::prv::Provider *provider, bool *shouldClose) { + if (provider->isDirty()) { + *shouldClose = false; + ImHexApi::Tasks::doLater([] { ImGui::OpenPopup("hex.builtin.popup.close_provider.title"_lang); }); + } + }); + EventManager::subscribe(openFile); EventManager::subscribe([](const std::string &name) { @@ -93,6 +97,11 @@ namespace hex::plugin::builtin { if (provider->hasLoadInterface()) EventManager::post(View::toWindowName("hex.builtin.view.provider_settings.load_popup")); }); + + EventManager::subscribe([](hex::prv::Provider *provider) { + ProviderExtraData::erase(provider); + }); + } } \ No newline at end of file diff --git a/plugins/builtin/source/content/main_menu_items.cpp b/plugins/builtin/source/content/main_menu_items.cpp index accaeef51..4ce2d701b 100644 --- a/plugins/builtin/source/content/main_menu_items.cpp +++ b/plugins/builtin/source/content/main_menu_items.cpp @@ -4,9 +4,10 @@ #include #include -#include +#include #include #include +#include #include @@ -69,18 +70,14 @@ namespace hex::plugin::builtin { } if (ImGui::MenuItem("hex.builtin.menu.file.save_project"_lang, "", false, providerValid && provider->isWritable())) { - if (ProjectFile::getProjectFilePath() == "") { - fs::openFileBrowser(fs::DialogMode::Save, { {"Project File", "hexproj"} - }, - [](std::fs::path path) { - if (path.extension() != ".hexproj") { - path.replace_extension(".hexproj"); - } + fs::openFileBrowser(fs::DialogMode::Save, { {"Project File", "hexproj"} }, + [](std::fs::path path) { + if (path.extension() != ".hexproj") { + path.replace_extension(".hexproj"); + } - ProjectFile::store(path); - }); - } else - ProjectFile::store(); + ProjectFile::store(path); + }); } }); diff --git a/plugins/builtin/source/content/pl_pragmas.cpp b/plugins/builtin/source/content/pl_pragmas.cpp index 9aceeb113..947ba175b 100644 --- a/plugins/builtin/source/content/pl_pragmas.cpp +++ b/plugins/builtin/source/content/pl_pragmas.cpp @@ -6,59 +6,6 @@ namespace hex::plugin::builtin { void registerPatternLanguagePragmas() { - ContentRegistry::PatternLanguage::addPragma("endian", [](pl::PatternLanguage &runtime, const std::string &value) { - if (value == "big") { - runtime.getInternals().evaluator->setDefaultEndian(std::endian::big); - return true; - } else if (value == "little") { - runtime.getInternals().evaluator->setDefaultEndian(std::endian::little); - return true; - } else if (value == "native") { - runtime.getInternals().evaluator->setDefaultEndian(std::endian::native); - return true; - } else - return false; - }); - - ContentRegistry::PatternLanguage::addPragma("eval_depth", [](pl::PatternLanguage &runtime, const std::string &value) { - auto limit = strtol(value.c_str(), nullptr, 0); - - if (limit <= 0) - return false; - - runtime.getInternals().evaluator->setEvaluationDepth(limit); - return true; - }); - - ContentRegistry::PatternLanguage::addPragma("array_limit", [](pl::PatternLanguage &runtime, const std::string &value) { - auto limit = strtol(value.c_str(), nullptr, 0); - - if (limit <= 0) - return false; - - runtime.getInternals().evaluator->setArrayLimit(limit); - return true; - }); - - ContentRegistry::PatternLanguage::addPragma("pattern_limit", [](pl::PatternLanguage &runtime, const std::string &value) { - auto limit = strtol(value.c_str(), nullptr, 0); - - if (limit <= 0) - return false; - - runtime.getInternals().evaluator->setPatternLimit(limit); - return true; - }); - - ContentRegistry::PatternLanguage::addPragma("loop_limit", [](pl::PatternLanguage &runtime, const std::string &value) { - auto limit = strtol(value.c_str(), nullptr, 0); - - if (limit <= 0) - return false; - - runtime.getInternals().evaluator->setLoopLimit(limit); - return true; - }); ContentRegistry::PatternLanguage::addPragma("base_address", [](pl::PatternLanguage &runtime, const std::string &value) { hex::unused(runtime); @@ -69,18 +16,6 @@ namespace hex::plugin::builtin { return true; }); - ContentRegistry::PatternLanguage::addPragma("bitfield_order", [](pl::PatternLanguage &runtime, const std::string &value) { - if (value == "left_to_right") { - runtime.getInternals().evaluator->setBitfieldOrder(pl::core::BitfieldOrder::LeftToRight); - return true; - } else if (value == "right_to_left") { - runtime.getInternals().evaluator->setBitfieldOrder(pl::core::BitfieldOrder::RightToLeft); - return true; - } else { - return false; - } - }); - ContentRegistry::PatternLanguage::addPragma("MIME", [](pl::PatternLanguage&, const std::string &value) { return !value.empty(); }); } diff --git a/plugins/builtin/source/content/providers.cpp b/plugins/builtin/source/content/providers.cpp index 1d5e10187..200eff78b 100644 --- a/plugins/builtin/source/content/providers.cpp +++ b/plugins/builtin/source/content/providers.cpp @@ -4,13 +4,63 @@ #include "content/providers/file_provider.hpp" #include "content/providers/disk_provider.hpp" +#include +#include +#include + namespace hex::plugin::builtin { void registerProviders() { - ContentRegistry::Provider::add("hex.builtin.provider.file", false); - ContentRegistry::Provider::add("hex.builtin.provider.gdb"); - ContentRegistry::Provider::add("hex.builtin.provider.disk"); + ContentRegistry::Provider::add(false); + ContentRegistry::Provider::add(); + ContentRegistry::Provider::add(); + + ProjectFile::registerHandler({ + .basePath = "providers", + .load = [](const std::fs::path &basePath, Tar &tar) { + auto json = nlohmann::json::parse(tar.readString(basePath / "providers.json")); + auto providerIds = json["providers"].get>(); + + bool success = true; + for (const auto &id : providerIds) { + auto providerSettings = nlohmann::json::parse(tar.readString(basePath / hex::format("{}.json", id))); + + auto provider = ImHexApi::Provider::createProvider(providerSettings["type"].get()); + if (provider == nullptr) { + success = false; + continue; + } + + provider->loadSettings(providerSettings["settings"]); + if (!provider->open()) + success = false; + } + + return success; + }, + .store = [](const std::fs::path &basePath, Tar &tar) { + std::vector 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.write(basePath / hex::format("{}.json", id), json.dump(4)); + } + + tar.write(basePath / "providers.json", + nlohmann::json({ + {"providers", providerIds} + }).dump(4) + ); + + return true; + } + }); } } \ No newline at end of file diff --git a/plugins/builtin/source/content/providers/disk_provider.cpp b/plugins/builtin/source/content/providers/disk_provider.cpp index 7c00d6c2f..299f06a42 100644 --- a/plugins/builtin/source/content/providers/disk_provider.cpp +++ b/plugins/builtin/source/content/providers/disk_provider.cpp @@ -12,17 +12,21 @@ #include #if defined(OS_LINUX) + #include #include #include #include #define lseek lseek64 + #elif defined(OS_MACOS) + #include #include #include #include + #endif namespace hex::plugin::builtin::prv { @@ -36,11 +40,15 @@ namespace hex::plugin::builtin::prv { } bool DiskProvider::isAvailable() const { -#if defined(OS_WINDOWS) - return this->m_diskHandle != INVALID_HANDLE_VALUE; -#else - return this->m_diskHandle != -1; -#endif + #if defined(OS_WINDOWS) + + return this->m_diskHandle != INVALID_HANDLE_VALUE; + + #else + + return this->m_diskHandle != -1; + + #endif } bool DiskProvider::isReadable() const { @@ -68,113 +76,120 @@ namespace hex::plugin::builtin::prv { this->m_readable = true; this->m_writable = true; -#if defined(OS_WINDOWS) + #if defined(OS_WINDOWS) - const auto &path = this->m_path.native(); + const auto &path = this->m_path.native(); - this->m_diskHandle = reinterpret_cast(CreateFileW(path.c_str(), GENERIC_READ | GENERIC_WRITE, FILE_SHARE_READ, nullptr, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, nullptr)); - if (this->m_diskHandle == INVALID_HANDLE_VALUE) { - this->m_diskHandle = reinterpret_cast(CreateFileW(path.c_str(), GENERIC_READ, FILE_SHARE_READ, nullptr, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, nullptr)); - this->m_writable = false; + this->m_diskHandle = reinterpret_cast(CreateFileW(path.c_str(), GENERIC_READ | GENERIC_WRITE, FILE_SHARE_READ, nullptr, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, nullptr)); + if (this->m_diskHandle == INVALID_HANDLE_VALUE) { + this->m_diskHandle = reinterpret_cast(CreateFileW(path.c_str(), GENERIC_READ, FILE_SHARE_READ, nullptr, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, nullptr)); + this->m_writable = false; - if (this->m_diskHandle == INVALID_HANDLE_VALUE) - return false; - } - - { - DISK_GEOMETRY_EX diskGeometry = { }; - DWORD bytesRead = 0; - if (DeviceIoControl( - this->m_diskHandle, - IOCTL_DISK_GET_DRIVE_GEOMETRY_EX, - nullptr, - 0, - &diskGeometry, - sizeof(DISK_GEOMETRY_EX), - &bytesRead, - nullptr)) { - this->m_diskSize = diskGeometry.DiskSize.QuadPart; - this->m_sectorSize = diskGeometry.Geometry.BytesPerSector; - this->m_sectorBuffer.resize(this->m_sectorSize); + if (this->m_diskHandle == INVALID_HANDLE_VALUE) + return false; } - } - if (this->m_diskHandle == nullptr || this->m_diskHandle == INVALID_HANDLE_VALUE) { - this->m_readable = false; - this->m_diskHandle = nullptr; - CloseHandle(this->m_diskHandle); + { + DISK_GEOMETRY_EX diskGeometry = { }; + DWORD bytesRead = 0; + if (DeviceIoControl( + this->m_diskHandle, + IOCTL_DISK_GET_DRIVE_GEOMETRY_EX, + nullptr, + 0, + &diskGeometry, + sizeof(DISK_GEOMETRY_EX), + &bytesRead, + nullptr)) { + this->m_diskSize = diskGeometry.DiskSize.QuadPart; + this->m_sectorSize = diskGeometry.Geometry.BytesPerSector; + this->m_sectorBuffer.resize(this->m_sectorSize); + } + } - return false; - } + if (this->m_diskHandle == nullptr || this->m_diskHandle == INVALID_HANDLE_VALUE) { + this->m_readable = false; + this->m_diskHandle = nullptr; + CloseHandle(this->m_diskHandle); + return false; + } -#else - const auto &path = this->m_path.native(); + #else - struct stat driveStat; + const auto &path = this->m_path.native(); - if (::stat(path.c_str(), &driveStat) == 0) - this->m_diskSize = driveStat.st_size; - else - this->m_diskSize = 0; + struct stat driveStat; - this->m_sectorSize = 0; + if (::stat(path.c_str(), &driveStat) == 0) + this->m_diskSize = driveStat.st_size; + else + this->m_diskSize = 0; - this->m_diskHandle = ::open(path.c_str(), O_RDWR); - if (this->m_diskHandle == -1) { - this->m_diskHandle = ::open(path.c_str(), O_RDONLY); - this->m_writable = false; - } + this->m_sectorSize = 0; - if (this->m_diskHandle == -1) { - this->m_readable = false; - return false; - } + this->m_diskHandle = ::open(path.c_str(), O_RDWR); + if (this->m_diskHandle == -1) { + this->m_diskHandle = ::open(path.c_str(), O_RDONLY); + this->m_writable = false; + } -#endif + if (this->m_diskHandle == -1) { + this->m_readable = false; + return false; + } - Provider::resize(this->getActualSize()); + #endif - return true; + return Provider::open(); } void DiskProvider::close() { -#if defined(OS_WINDOWS) - if (this->m_diskHandle != INVALID_HANDLE_VALUE) - ::CloseHandle(this->m_diskHandle); + #if defined(OS_WINDOWS) - this->m_diskHandle = INVALID_HANDLE_VALUE; -#else - if (this->m_diskHandle != -1) - ::close(this->m_diskHandle); + if (this->m_diskHandle != INVALID_HANDLE_VALUE) + ::CloseHandle(this->m_diskHandle); - this->m_diskHandle = -1; -#endif + this->m_diskHandle = INVALID_HANDLE_VALUE; + + #else + + if (this->m_diskHandle != -1) + ::close(this->m_diskHandle); + + this->m_diskHandle = -1; + + #endif + + Provider::close(); } void DiskProvider::readRaw(u64 offset, void *buffer, size_t size) { -#if defined(OS_WINDOWS) - DWORD bytesRead = 0; + #if defined(OS_WINDOWS) - u64 startOffset = offset; + DWORD bytesRead = 0; - while (size > 0) { - LARGE_INTEGER seekPosition; - seekPosition.LowPart = (offset & 0xFFFF'FFFF) - (offset % this->m_sectorSize); - seekPosition.HighPart = offset >> 32; + u64 startOffset = offset; - if (this->m_sectorBufferAddress != static_cast(seekPosition.QuadPart)) { - ::SetFilePointer(this->m_diskHandle, seekPosition.LowPart, &seekPosition.HighPart, FILE_BEGIN); - ::ReadFile(this->m_diskHandle, this->m_sectorBuffer.data(), this->m_sectorBuffer.size(), &bytesRead, nullptr); - this->m_sectorBufferAddress = seekPosition.QuadPart; + while (size > 0) { + LARGE_INTEGER seekPosition; + seekPosition.LowPart = (offset & 0xFFFF'FFFF) - (offset % this->m_sectorSize); + seekPosition.HighPart = offset >> 32; + + if (this->m_sectorBufferAddress != static_cast(seekPosition.QuadPart)) { + ::SetFilePointer(this->m_diskHandle, seekPosition.LowPart, &seekPosition.HighPart, FILE_BEGIN); + ::ReadFile(this->m_diskHandle, this->m_sectorBuffer.data(), this->m_sectorBuffer.size(), &bytesRead, nullptr); + this->m_sectorBufferAddress = seekPosition.QuadPart; + } + + std::memcpy(reinterpret_cast(buffer) + (offset - startOffset), this->m_sectorBuffer.data() + (offset & (this->m_sectorSize - 1)), std::min(this->m_sectorSize, size)); + + size = std::max(static_cast(size) - this->m_sectorSize, 0); + offset += this->m_sectorSize; } - std::memcpy(reinterpret_cast(buffer) + (offset - startOffset), this->m_sectorBuffer.data() + (offset & (this->m_sectorSize - 1)), std::min(this->m_sectorSize, size)); + #else - size = std::max(static_cast(size) - this->m_sectorSize, 0); - offset += this->m_sectorSize; - } -#else u64 startOffset = offset; while (size > 0) { @@ -193,59 +208,61 @@ namespace hex::plugin::builtin::prv { size = std::max(static_cast(size) - this->m_sectorSize, 0); offset += this->m_sectorSize; } -#endif + + #endif } void DiskProvider::writeRaw(u64 offset, const void *buffer, size_t size) { -#if defined(OS_WINDOWS) - DWORD bytesWritten = 0; + #if defined(OS_WINDOWS) - u64 startOffset = offset; + DWORD bytesWritten = 0; - std::vector modifiedSectorBuffer; - modifiedSectorBuffer.resize(this->m_sectorSize); + u64 startOffset = offset; - while (size > 0) { - u64 sectorBase = offset - (offset % this->m_sectorSize); - size_t currSize = std::min(size, this->m_sectorSize); + std::vector modifiedSectorBuffer; + modifiedSectorBuffer.resize(this->m_sectorSize); - this->readRaw(sectorBase, modifiedSectorBuffer.data(), modifiedSectorBuffer.size()); - std::memcpy(modifiedSectorBuffer.data() + ((offset - sectorBase) % this->m_sectorSize), reinterpret_cast(buffer) + (startOffset - offset), currSize); + while (size > 0) { + u64 sectorBase = offset - (offset % this->m_sectorSize); + size_t currSize = std::min(size, this->m_sectorSize); - LARGE_INTEGER seekPosition; - seekPosition.LowPart = (offset & 0xFFFF'FFFF) - (offset % this->m_sectorSize); - seekPosition.HighPart = offset >> 32; + this->readRaw(sectorBase, modifiedSectorBuffer.data(), modifiedSectorBuffer.size()); + std::memcpy(modifiedSectorBuffer.data() + ((offset - sectorBase) % this->m_sectorSize), reinterpret_cast(buffer) + (startOffset - offset), currSize); - ::SetFilePointer(this->m_diskHandle, seekPosition.LowPart, &seekPosition.HighPart, FILE_BEGIN); - ::WriteFile(this->m_diskHandle, modifiedSectorBuffer.data(), modifiedSectorBuffer.size(), &bytesWritten, nullptr); + LARGE_INTEGER seekPosition; + seekPosition.LowPart = (offset & 0xFFFF'FFFF) - (offset % this->m_sectorSize); + seekPosition.HighPart = offset >> 32; - offset += currSize; - size -= currSize; - } + ::SetFilePointer(this->m_diskHandle, seekPosition.LowPart, &seekPosition.HighPart, FILE_BEGIN); + ::WriteFile(this->m_diskHandle, modifiedSectorBuffer.data(), modifiedSectorBuffer.size(), &bytesWritten, nullptr); -#else + offset += currSize; + size -= currSize; + } - u64 startOffset = offset; + #else - std::vector modifiedSectorBuffer; - modifiedSectorBuffer.resize(this->m_sectorSize); + u64 startOffset = offset; - while (size > 0) { - u64 sectorBase = offset - (offset % this->m_sectorSize); - size_t currSize = std::min(size, this->m_sectorSize); + std::vector modifiedSectorBuffer; + modifiedSectorBuffer.resize(this->m_sectorSize); - this->readRaw(sectorBase, modifiedSectorBuffer.data(), modifiedSectorBuffer.size()); - std::memcpy(modifiedSectorBuffer.data() + ((offset - sectorBase) % this->m_sectorSize), reinterpret_cast(buffer) + (startOffset - offset), currSize); + while (size > 0) { + u64 sectorBase = offset - (offset % this->m_sectorSize); + size_t currSize = std::min(size, this->m_sectorSize); - ::lseek(this->m_diskHandle, sectorBase, SEEK_SET); - if (::write(this->m_diskHandle, modifiedSectorBuffer.data(), modifiedSectorBuffer.size()) < 0) - break; + this->readRaw(sectorBase, modifiedSectorBuffer.data(), modifiedSectorBuffer.size()); + std::memcpy(modifiedSectorBuffer.data() + ((offset - sectorBase) % this->m_sectorSize), reinterpret_cast(buffer) + (startOffset - offset), currSize); - offset += currSize; - size -= currSize; - } + ::lseek(this->m_diskHandle, sectorBase, SEEK_SET); + if (::write(this->m_diskHandle, modifiedSectorBuffer.data(), modifiedSectorBuffer.size()) < 0) + break; -#endif + offset += currSize; + size -= currSize; + } + + #endif } size_t DiskProvider::getActualSize() const { @@ -266,66 +283,82 @@ namespace hex::plugin::builtin::prv { void DiskProvider::reloadDrives() { -#if defined(OS_WINDOWS) - this->m_availableDrives.clear(); - std::bitset<32> drives = ::GetLogicalDrives(); - for (char i = 0; i < 26; i++) { - if (drives[i]) - this->m_availableDrives.insert(hex::format(R"(\\.\{:c}:)", 'A' + i)); - } + #if defined(OS_WINDOWS) - auto logicalDrives = this->m_availableDrives; - for (const auto &drive : logicalDrives) { - auto handle = reinterpret_cast(::CreateFile(drive.data(), GENERIC_READ, FILE_SHARE_READ | FILE_SHARE_WRITE, nullptr, OPEN_EXISTING, 0, nullptr)); - - if (handle == INVALID_HANDLE_VALUE) continue; - - VOLUME_DISK_EXTENTS diskExtents = { }; - DWORD bytesRead = 0; - auto result = ::DeviceIoControl( - handle, - IOCTL_VOLUME_GET_VOLUME_DISK_EXTENTS, - nullptr, - 0, - &diskExtents, - sizeof(VOLUME_DISK_EXTENTS), - &bytesRead, - nullptr); - - if (result) { - auto diskPath = hex::format(R"(\\.\PhysicalDrive{})", diskExtents.Extents[0].DiskNumber); - this->m_availableDrives.insert(diskPath); + this->m_availableDrives.clear(); + std::bitset<32> drives = ::GetLogicalDrives(); + for (char i = 0; i < 26; i++) { + if (drives[i]) + this->m_availableDrives.insert(hex::format(R"(\\.\{:c}:)", 'A' + i)); } - ::CloseHandle(handle); - } -#endif + auto logicalDrives = this->m_availableDrives; + for (const auto &drive : logicalDrives) { + auto handle = reinterpret_cast(::CreateFile(drive.data(), GENERIC_READ, FILE_SHARE_READ | FILE_SHARE_WRITE, nullptr, OPEN_EXISTING, 0, nullptr)); + + if (handle == INVALID_HANDLE_VALUE) continue; + + VOLUME_DISK_EXTENTS diskExtents = { }; + DWORD bytesRead = 0; + auto result = ::DeviceIoControl( + handle, + IOCTL_VOLUME_GET_VOLUME_DISK_EXTENTS, + nullptr, + 0, + &diskExtents, + sizeof(VOLUME_DISK_EXTENTS), + &bytesRead, + nullptr); + + if (result) { + auto diskPath = hex::format(R"(\\.\PhysicalDrive{})", diskExtents.Extents[0].DiskNumber); + this->m_availableDrives.insert(diskPath); + } + + ::CloseHandle(handle); + } + + #endif } void DiskProvider::drawLoadInterface() { -#if defined(OS_WINDOWS) - if (ImGui::BeginListBox("hex.builtin.provider.disk.selected_disk"_lang)) { + #if defined(OS_WINDOWS) - for (const auto &drive : this->m_availableDrives) { - if (ImGui::Selectable(drive.c_str(), this->m_path == drive)) - this->m_path = drive; + if (ImGui::BeginListBox("hex.builtin.provider.disk.selected_disk"_lang)) { + + for (const auto &drive : this->m_availableDrives) { + if (ImGui::Selectable(drive.c_str(), this->m_path == drive)) + this->m_path = drive; + } + + ImGui::EndListBox(); } - ImGui::EndListBox(); + ImGui::SameLine(); + + if (ImGui::Button("hex.builtin.provider.disk.reload"_lang)) { + this->reloadDrives(); } - ImGui::SameLine(); + #else - if (ImGui::Button("hex.builtin.provider.disk.reload"_lang)) { - this->reloadDrives(); - } + if (ImGui::InputText("hex.builtin.provider.disk.selected_disk"_lang, this->m_pathBuffer.data(), this->m_pathBuffer.size(), ImGuiInputTextFlags_CallbackResize, ImGui::UpdateStringSizeCallback, &this->m_pathBuffer)) + this->m_path = this->m_pathBuffer; -#else + #endif + } - if (ImGui::InputText("hex.builtin.provider.disk.selected_disk"_lang, this->m_pathBuffer.data(), this->m_pathBuffer.size(), ImGuiInputTextFlags_CallbackResize, ImGui::UpdateStringSizeCallback, &this->m_pathBuffer)) - this->m_path = this->m_pathBuffer; + nlohmann::json DiskProvider::storeSettings(nlohmann::json settings) const { + settings["path"] = this->m_path.string(); -#endif + return Provider::storeSettings(settings); + } + + void DiskProvider::loadSettings(const nlohmann::json &settings) { + Provider::loadSettings(settings); + + this->setPath(settings["path"].get()); + this->reloadDrives(); } } \ No newline at end of file diff --git a/plugins/builtin/source/content/providers/file_provider.cpp b/plugins/builtin/source/content/providers/file_provider.cpp index a2340b504..3aafffc67 100644 --- a/plugins/builtin/source/content/providers/file_provider.cpp +++ b/plugins/builtin/source/content/providers/file_provider.cpp @@ -2,11 +2,13 @@ #include +#include #include #include #include #include -#include + +#include namespace hex::plugin::builtin::prv { @@ -19,11 +21,11 @@ namespace hex::plugin::builtin::prv { bool FileProvider::isAvailable() const { -#if defined(OS_WINDOWS) - return this->m_file != INVALID_HANDLE_VALUE && this->m_mapping != INVALID_HANDLE_VALUE && this->m_mappedFile != nullptr; -#else - return this->m_file != -1 && this->m_mappedFile != nullptr; -#endif + #if defined(OS_WINDOWS) + return this->m_file != INVALID_HANDLE_VALUE && this->m_mapping != INVALID_HANDLE_VALUE && this->m_mappedFile != nullptr; + #else + return this->m_file != -1 && this->m_mappedFile != nullptr; + #endif } bool FileProvider::isReadable() const { @@ -202,121 +204,137 @@ namespace hex::plugin::builtin::prv { this->m_readable = true; this->m_writable = true; -#if defined(OS_WINDOWS) - const auto &path = this->m_path.native(); + #if defined(OS_WINDOWS) + const auto &path = this->m_path.native(); - this->m_fileStatsValid = wstat(path.c_str(), &this->m_fileStats) == 0; + this->m_fileStatsValid = wstat(path.c_str(), &this->m_fileStats) == 0; - LARGE_INTEGER fileSize = {}; - this->m_file = reinterpret_cast(CreateFileW(path.c_str(), GENERIC_READ, FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE, nullptr, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, nullptr)); + LARGE_INTEGER fileSize = {}; + this->m_file = reinterpret_cast(CreateFileW(path.c_str(), GENERIC_READ, FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE, nullptr, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, nullptr)); - GetFileSizeEx(this->m_file, &fileSize); - this->m_fileSize = fileSize.QuadPart; - CloseHandle(this->m_file); - - this->m_file = reinterpret_cast(CreateFileW(path.c_str(), GENERIC_READ | GENERIC_WRITE, FILE_SHARE_READ | FILE_SHARE_WRITE, nullptr, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, nullptr)); - if (this->m_file == nullptr || this->m_file == INVALID_HANDLE_VALUE) { - this->m_file = reinterpret_cast(CreateFileW(path.c_str(), GENERIC_READ, FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE, nullptr, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, nullptr)); - this->m_writable = false; - } - - auto fileCleanup = SCOPE_GUARD { + GetFileSizeEx(this->m_file, &fileSize); + this->m_fileSize = fileSize.QuadPart; CloseHandle(this->m_file); - this->m_readable = false; - this->m_file = nullptr; - }; - - if (this->m_file == nullptr || this->m_file == INVALID_HANDLE_VALUE) { - return false; - } - - if (this->m_fileSize > 0) { - this->m_mapping = CreateFileMapping(this->m_file, nullptr, PAGE_READWRITE, 0, 0, nullptr); - if (this->m_mapping == nullptr || this->m_mapping == INVALID_HANDLE_VALUE) { - - this->m_mapping = CreateFileMapping(this->m_file, nullptr, PAGE_READONLY, 0, 0, nullptr); - - if (this->m_mapping == nullptr || this->m_mapping == INVALID_HANDLE_VALUE) - return false; + this->m_file = reinterpret_cast(CreateFileW(path.c_str(), GENERIC_READ | GENERIC_WRITE, FILE_SHARE_READ | FILE_SHARE_WRITE, nullptr, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, nullptr)); + if (this->m_file == nullptr || this->m_file == INVALID_HANDLE_VALUE) { + this->m_file = reinterpret_cast(CreateFileW(path.c_str(), GENERIC_READ, FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE, nullptr, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, nullptr)); + this->m_writable = false; } - auto mappingCleanup = SCOPE_GUARD { - CloseHandle(this->m_mapping); + auto fileCleanup = SCOPE_GUARD { + CloseHandle(this->m_file); - this->m_mapping = nullptr; this->m_readable = false; + this->m_file = nullptr; }; - this->m_mappedFile = MapViewOfFile(this->m_mapping, FILE_MAP_ALL_ACCESS, 0, 0, this->m_fileSize); - if (this->m_mappedFile == nullptr) { - - this->m_mappedFile = MapViewOfFile(this->m_mapping, FILE_MAP_READ, 0, 0, this->m_fileSize); - if (this->m_mappedFile == nullptr) { - this->m_readable = false; - - return false; - } + if (this->m_file == nullptr || this->m_file == INVALID_HANDLE_VALUE) { + return false; } - mappingCleanup.release(); + if (this->m_fileSize > 0) { + this->m_mapping = CreateFileMapping(this->m_file, nullptr, PAGE_READWRITE, 0, 0, nullptr); + if (this->m_mapping == nullptr || this->m_mapping == INVALID_HANDLE_VALUE) { - ProjectFile::setFilePath(this->m_path); - } else if (!this->m_emptyFile) { - this->m_emptyFile = true; - this->resize(1); - } else { - return false; - } + this->m_mapping = CreateFileMapping(this->m_file, nullptr, PAGE_READONLY, 0, 0, nullptr); - fileCleanup.release(); + if (this->m_mapping == nullptr || this->m_mapping == INVALID_HANDLE_VALUE) + return false; + } -#else - const auto &path = this->m_path.native(); - this->m_fileStatsValid = stat(path.c_str(), &this->m_fileStats) == 0; + auto mappingCleanup = SCOPE_GUARD { + CloseHandle(this->m_mapping); - int mmapprot = PROT_READ | PROT_WRITE; + this->m_mapping = nullptr; + this->m_readable = false; + }; - this->m_file = ::open(path.c_str(), O_RDWR); - if (this->m_file == -1) { - this->m_file = ::open(path.c_str(), O_RDONLY); - this->m_writable = false; - mmapprot &= ~(PROT_WRITE); - } + this->m_mappedFile = MapViewOfFile(this->m_mapping, FILE_MAP_ALL_ACCESS, 0, 0, this->m_fileSize); + if (this->m_mappedFile == nullptr) { - if (this->m_file == -1) { - this->m_readable = false; - return false; - } + this->m_mappedFile = MapViewOfFile(this->m_mapping, FILE_MAP_READ, 0, 0, this->m_fileSize); + if (this->m_mappedFile == nullptr) { + this->m_readable = false; - this->m_fileSize = this->m_fileStats.st_size; + return false; + } + } - this->m_mappedFile = ::mmap(nullptr, this->m_fileSize, mmapprot, MAP_SHARED, this->m_file, 0); - if (this->m_mappedFile == MAP_FAILED) { - ::close(this->m_file); - this->m_file = -1; + mappingCleanup.release(); + } else if (!this->m_emptyFile) { + this->m_emptyFile = true; + this->resize(1); + } else { + return false; + } - return false; - } -#endif + fileCleanup.release(); - Provider::resize(this->getActualSize()); + #else - return true; + const auto &path = this->m_path.native(); + this->m_fileStatsValid = stat(path.c_str(), &this->m_fileStats) == 0; + + int mmapprot = PROT_READ | PROT_WRITE; + + this->m_file = ::open(path.c_str(), O_RDWR); + if (this->m_file == -1) { + this->m_file = ::open(path.c_str(), O_RDONLY); + this->m_writable = false; + mmapprot &= ~(PROT_WRITE); + } + + if (this->m_file == -1) { + this->m_readable = false; + return false; + } + + this->m_fileSize = this->m_fileStats.st_size; + + this->m_mappedFile = ::mmap(nullptr, this->m_fileSize, mmapprot, MAP_SHARED, this->m_file, 0); + if (this->m_mappedFile == MAP_FAILED) { + ::close(this->m_file); + this->m_file = -1; + + return false; + } + + #endif + + return Provider::open(); } void FileProvider::close() { -#if defined(OS_WINDOWS) - if (this->m_mappedFile != nullptr) - ::UnmapViewOfFile(this->m_mappedFile); - if (this->m_mapping != nullptr) - ::CloseHandle(this->m_mapping); - if (this->m_file != nullptr) - ::CloseHandle(this->m_file); -#else - ::munmap(this->m_mappedFile, this->m_fileSize); - ::close(this->m_file); -#endif + #if defined(OS_WINDOWS) + + if (this->m_mappedFile != nullptr) + ::UnmapViewOfFile(this->m_mappedFile); + if (this->m_mapping != nullptr) + ::CloseHandle(this->m_mapping); + if (this->m_file != nullptr) + ::CloseHandle(this->m_file); + + #else + + ::munmap(this->m_mappedFile, this->m_fileSize); + ::close(this->m_file); + + #endif + + Provider::close(); + } + + void FileProvider::loadSettings(const nlohmann::json &settings) { + Provider::loadSettings(settings); + + this->setPath(settings["path"].get()); + } + + nlohmann::json FileProvider::storeSettings(nlohmann::json settings) const { + settings["path"] = this->m_path.string(); + + return Provider::storeSettings(settings); } } diff --git a/plugins/builtin/source/content/providers/gdb_provider.cpp b/plugins/builtin/source/content/providers/gdb_provider.cpp index 97d8dd863..6d2c625ff 100644 --- a/plugins/builtin/source/content/providers/gdb_provider.cpp +++ b/plugins/builtin/source/content/providers/gdb_provider.cpp @@ -11,6 +11,8 @@ #include #include +#include + namespace hex::plugin::builtin::prv { using namespace std::chrono_literals; @@ -276,9 +278,7 @@ namespace hex::plugin::builtin::prv { } }); - Provider::resize(this->getActualSize()); - - return true; + return Provider::open(); } else { return false; } @@ -290,6 +290,8 @@ namespace hex::plugin::builtin::prv { if (this->m_cacheUpdateThread.joinable()) { this->m_cacheUpdateThread.join(); } + + Provider::close(); } bool GDBProvider::isConnected() const { @@ -311,4 +313,20 @@ namespace hex::plugin::builtin::prv { this->m_port = 0xFFFF; } + void GDBProvider::loadSettings(const nlohmann::json &settings) { + Provider::loadSettings(settings); + + this->m_ipAddress = settings["ip"].get(); + this->m_port = settings["port"].get(); + this->m_size = settings["size"].get(); + } + + nlohmann::json GDBProvider::storeSettings(nlohmann::json settings) const { + settings["ip"] = this->m_ipAddress; + settings["port"] = this->m_port; + settings["size"] = this->m_size; + + return Provider::storeSettings(settings); + } + } \ No newline at end of file diff --git a/plugins/builtin/source/content/ui_items.cpp b/plugins/builtin/source/content/ui_items.cpp index 24d297da0..8367aa31b 100644 --- a/plugins/builtin/source/content/ui_items.cpp +++ b/plugins/builtin/source/content/ui_items.cpp @@ -28,8 +28,27 @@ namespace hex::plugin::builtin { ImGui::TextUnformatted("hex.builtin.popup.exit_application.desc"_lang); ImGui::NewLine(); - View::confirmButtons( - "hex.builtin.common.yes"_lang, "hex.builtin.common.no"_lang, [] { ImHexApi::Common::closeImHex(true); }, [] { ImGui::CloseCurrentPopup(); }); + View::confirmButtons("hex.builtin.common.yes"_lang, "hex.builtin.common.no"_lang, + [] { ImHexApi::Common::closeImHex(true); }, + [] { ImGui::CloseCurrentPopup(); } + ); + + if (ImGui::IsKeyDown(ImGui::GetKeyIndex(ImGuiKey_Escape))) + ImGui::CloseCurrentPopup(); + + ImGui::EndPopup(); + } + + // "Are you sure you want to close provider?" Popup + if (ImGui::BeginPopupModal("hex.builtin.popup.close_provider.title"_lang, nullptr, ImGuiWindowFlags_AlwaysAutoResize)) { + ImGui::NewLine(); + ImGui::TextUnformatted("hex.builtin.popup.close_provider.desc"_lang); + ImGui::NewLine(); + + View::confirmButtons("hex.builtin.common.yes"_lang, "hex.builtin.common.no"_lang, + [] { ImHexApi::Provider::remove(ImHexApi::Provider::impl::getClosingProvider(), true); ImGui::CloseCurrentPopup(); }, + [] { ImGui::CloseCurrentPopup(); } + ); if (ImGui::IsKeyDown(ImGui::GetKeyIndex(ImGuiKey_Escape))) ImGui::CloseCurrentPopup(); @@ -313,7 +332,7 @@ namespace hex::plugin::builtin { bool open = true; ImGui::PushID(tabProvider); - if (ImGui::BeginTabItem(tabProvider->getName().c_str(), &open)) { + if (ImGui::BeginTabItem(tabProvider->getName().c_str(), &open, provider->isDirty() ? ImGuiTabItemFlags_UnsavedDocument : ImGuiTabItemFlags_None)) { ImHexApi::Provider::setCurrentProvider(i); ImGui::EndTabItem(); } diff --git a/plugins/builtin/source/content/views/view_bookmarks.cpp b/plugins/builtin/source/content/views/view_bookmarks.cpp index a272d7063..6332019d4 100644 --- a/plugins/builtin/source/content/views/view_bookmarks.cpp +++ b/plugins/builtin/source/content/views/view_bookmarks.cpp @@ -1,16 +1,18 @@ #include "content/views/view_bookmarks.hpp" +#include #include #include -#include - +#include #include +#include + namespace hex::plugin::builtin { ViewBookmarks::ViewBookmarks() : View("hex.builtin.view.bookmarks.name") { - EventManager::subscribe(this, [this](Region region, std::string name, std::string comment, color_t color) { + EventManager::subscribe(this, [](Region region, std::string name, std::string comment, color_t color) { if (name.empty()) { name = hex::format("hex.builtin.view.bookmarks.default_title"_lang, region.address, region.address + region.size - 1); } @@ -18,34 +20,21 @@ namespace hex::plugin::builtin { if (color == 0x00) color = ImGui::GetColorU32(ImGuiCol_Header); - - this->m_bookmarks.push_back({ region, + ProviderExtraData::getCurrent().bookmarks.push_back({ + region, name, std::move(comment), color, false }); - ProjectFile::markDirty(); + ImHexApi::Provider::markDirty(); }); - EventManager::subscribe(this, [this] { - this->m_bookmarks = ProjectFile::getBookmarks(); - }); - - EventManager::subscribe(this, [this] { - ProjectFile::setBookmarks(this->m_bookmarks); - }); - - EventManager::subscribe(this, [this](const auto*) { - this->m_bookmarks.clear(); - }); - - - ImHexApi::HexEditor::addBackgroundHighlightingProvider([this](u64 address, const u8* data, size_t size) -> std::optional { + ImHexApi::HexEditor::addBackgroundHighlightingProvider([](u64 address, const u8* data, size_t size) -> std::optional { hex::unused(data); - for (const auto &bookmark : this->m_bookmarks) { + for (const auto &bookmark : ProviderExtraData::getCurrent().bookmarks) { if (Region { address, size }.isWithin(bookmark.region)) return bookmark.color; } @@ -53,9 +42,9 @@ namespace hex::plugin::builtin { return std::nullopt; }); - ImHexApi::HexEditor::addTooltipProvider([this](u64 address, const u8 *data, size_t size) { + ImHexApi::HexEditor::addTooltipProvider([](u64 address, const u8 *data, size_t size) { hex::unused(data); - for (const auto &bookmark : this->m_bookmarks) { + for (const auto &bookmark : ProviderExtraData::getCurrent().bookmarks) { if (!Region { address, size }.isWithin(bookmark.region)) continue; @@ -109,15 +98,69 @@ namespace hex::plugin::builtin { ImGui::EndTooltip(); } }); + + ProjectFile::registerPerProviderHandler({ + .basePath = "bookmarks.json", + .load = [](prv::Provider *provider, const std::fs::path &basePath, Tar &tar) -> bool { + auto fileContent = tar.read(basePath); + if (fileContent.empty()) + return true; + + auto data = nlohmann::json::parse(fileContent.begin(), fileContent.end()); + if (!data.contains("bookmarks")) + return false; + + auto &bookmarks = ProviderExtraData::get(provider).bookmarks; + bookmarks.clear(); + for (const auto &bookmark : data["bookmarks"]) { + if (!bookmark.contains("name") || !bookmark.contains("comment") || !bookmark.contains("color") || !bookmark.contains("region") || !bookmark.contains("locked")) + continue; + + const auto ®ion = bookmark["region"]; + if (!region.contains("address") || !region.contains("size")) + continue; + + bookmarks.push_back({ + .region = { region["address"], region["size"] }, + .name = bookmark["name"], + .comment = bookmark["comment"], + .color = bookmark["color"], + .locked = bookmark["locked"] + }); + } + + return true; + }, + .store = [](prv::Provider *provider, const std::fs::path &basePath, Tar &tar) -> bool { + nlohmann::json data; + + data["bookmarks"] = nlohmann::json::array(); + size_t index = 0; + for (const auto &bookmark : ProviderExtraData::get(provider).bookmarks) { + data["bookmarks"][index] = { + { "name", bookmark.name }, + { "comment", bookmark.comment }, + { "color", bookmark.color }, + { "region", { + { "address", bookmark.region.address }, + { "size", bookmark.region.size } + } + }, + { "locked", bookmark.locked } + }; + index++; + } + + tar.write(basePath, data.dump(4)); + + return true; + } + }); } ViewBookmarks::~ViewBookmarks() { EventManager::unsubscribe(this); - EventManager::unsubscribe(this); - EventManager::unsubscribe(this); EventManager::unsubscribe(this); - - this->m_bookmarks.clear(); } void ViewBookmarks::drawContent() { @@ -130,14 +173,14 @@ namespace hex::plugin::builtin { ImGui::NewLine(); if (ImGui::BeginChild("##bookmarks")) { - - if (this->m_bookmarks.empty()) { + auto &bookmarks = ProviderExtraData::getCurrent().bookmarks; + if (bookmarks.empty()) { ImGui::TextFormattedCentered("hex.builtin.view.bookmarks.no_bookmarks"_lang); } u32 id = 1; - auto bookmarkToRemove = this->m_bookmarks.end(); - for (auto iter = this->m_bookmarks.begin(); iter != this->m_bookmarks.end(); iter++) { + auto bookmarkToRemove = bookmarks.end(); + for (auto iter = bookmarks.begin(); iter != bookmarks.end(); iter++) { auto &[region, name, comment, color, locked] = *iter; if (!this->m_currFilter.empty()) { @@ -248,9 +291,8 @@ namespace hex::plugin::builtin { id++; } - if (bookmarkToRemove != this->m_bookmarks.end()) { - this->m_bookmarks.erase(bookmarkToRemove); - ProjectFile::markDirty(); + if (bookmarkToRemove != bookmarks.end()) { + bookmarks.erase(bookmarkToRemove); } } ImGui::EndChild(); diff --git a/plugins/builtin/source/content/views/view_data_processor.cpp b/plugins/builtin/source/content/views/view_data_processor.cpp index f36288edf..e32a2467c 100644 --- a/plugins/builtin/source/content/views/view_data_processor.cpp +++ b/plugins/builtin/source/content/views/view_data_processor.cpp @@ -5,11 +5,13 @@ #include #include -#include +#include #include #include +#include "provider_extra_data.hpp" + namespace hex::plugin::builtin { ViewDataProcessor::ViewDataProcessor() : View("hex.builtin.view.data_processor.name") { @@ -30,24 +32,28 @@ namespace hex::plugin::builtin { ImNodes::GetStyle().Flags = ImNodesStyleFlags_NodeOutline | ImNodesStyleFlags_GridLines; }); - EventManager::subscribe(this, [this] { - ProjectFile::setDataProcessorContent(this->saveNodes()); - }); + ProjectFile::registerPerProviderHandler({ + .basePath = "data_processor.json", + .load = [this](prv::Provider *provider, const std::fs::path &basePath, Tar &tar) { + auto save = tar.readString(basePath); - EventManager::subscribe(this, [this] { - try { - this->loadNodes(ProjectFile::getDataProcessorContent()); - } catch (nlohmann::json::exception &e) { + this->loadNodes(provider, save); + + return true; + }, + .store = [this](prv::Provider *provider, const std::fs::path &basePath, Tar &tar) { + tar.write(basePath, this->saveNodes(provider)); + + return true; } }); - EventManager::subscribe(this, [this](const std::fs::path &path) { - hex::unused(path); - - for (auto &node : this->m_nodes) { + EventManager::subscribe(this, [](const auto &, const auto &) { + auto &data = ProviderExtraData::getCurrent().dataProcessor; + for (auto &node : data.nodes) { node->setCurrentOverlay(nullptr); } - this->m_dataOverlays.clear(); + data.dataOverlays.clear(); }); EventManager::subscribe(this, [this] { @@ -56,22 +62,25 @@ namespace hex::plugin::builtin { ContentRegistry::Interface::addMenuItem("hex.builtin.menu.file", 3000, [&, this] { bool providerValid = ImHexApi::Provider::isValid(); + auto provider = ImHexApi::Provider::get(); + + auto &data = ProviderExtraData::getCurrent().dataProcessor; if (ImGui::MenuItem("hex.builtin.view.data_processor.menu.file.load_processor"_lang, nullptr, false, providerValid)) { fs::openFileBrowser(fs::DialogMode::Open, { {"hex.builtin.view.data_processor.name"_lang, "hexnode"} }, - [this](const std::fs::path &path) { + [&, this](const std::fs::path &path) { fs::File file(path, fs::File::Mode::Read); if (file.isValid()) - this->loadNodes(file.readString()); + this->loadNodes(provider, file.readString()); }); } - if (ImGui::MenuItem("hex.builtin.view.data_processor.menu.file.save_processor"_lang, nullptr, false, !this->m_nodes.empty() && providerValid)) { + if (ImGui::MenuItem("hex.builtin.view.data_processor.menu.file.save_processor"_lang, nullptr, false, !data.nodes.empty() && providerValid)) { fs::openFileBrowser(fs::DialogMode::Save, { {"hex.builtin.view.data_processor.name"_lang, "hexnode"} }, - [this](const std::fs::path &path) { + [&, this](const std::fs::path &path) { fs::File file(path, fs::File::Mode::Create); if (file.isValid()) - file.write(this->saveNodes()); + file.write(this->saveNodes(provider)); }); } }); @@ -80,44 +89,45 @@ namespace hex::plugin::builtin { fs::File file(path, fs::File::Mode::Read); if (!file.isValid()) return false; - this->loadNodes(file.readString()); + this->loadNodes(ImHexApi::Provider::get(), file.readString()); return true; }); } ViewDataProcessor::~ViewDataProcessor() { - for (auto &node : this->m_nodes) - delete node; - EventManager::unsubscribe(this); EventManager::unsubscribe(this); - EventManager::unsubscribe(this); - EventManager::unsubscribe(this); EventManager::unsubscribe(this); } void ViewDataProcessor::eraseLink(u32 id) { - auto link = std::find_if(this->m_links.begin(), this->m_links.end(), [&id](auto link) { return link.getId() == id; }); + auto &data = ProviderExtraData::getCurrent().dataProcessor; - if (link == this->m_links.end()) + auto link = std::find_if(data.links.begin(), data.links.end(), [&id](auto link) { return link.getId() == id; }); + + if (link == data.links.end()) return; - for (auto &node : this->m_nodes) { + for (auto &node : data.nodes) { for (auto &attribute : node->getAttributes()) { attribute.removeConnectedAttribute(id); } } - this->m_links.erase(link); + data.links.erase(link); - ProjectFile::markDirty(); + ImHexApi::Provider::markDirty(); } void ViewDataProcessor::eraseNodes(const std::vector &ids) { + auto &data = ProviderExtraData::getCurrent().dataProcessor; for (u32 id : ids) { - auto node = std::find_if(this->m_nodes.begin(), this->m_nodes.end(), [&id](auto node) { return node->getId() == id; }); + auto node = std::find_if(data.nodes.begin(), data.nodes.end(), + [&id](const auto &node) { + return node->getId() == id; + }); for (auto &attr : (*node)->getAttributes()) { std::vector linksToRemove; @@ -130,52 +140,51 @@ namespace hex::plugin::builtin { } for (u32 id : ids) { - auto node = std::find_if(this->m_nodes.begin(), this->m_nodes.end(), [&id](auto node) { return node->getId() == id; }); + auto node = std::find_if(data.nodes.begin(), data.nodes.end(), [&id](const auto &node) { return node->getId() == id; }); - std::erase_if(this->m_endNodes, [&id](auto node) { return node->getId() == id; }); + std::erase_if(data.endNodes, [&id](const auto &node) { return node->getId() == id; }); - delete *node; - - this->m_nodes.erase(node); + data.nodes.erase(node); } - ProjectFile::markDirty(); + ImHexApi::Provider::markDirty(); } void ViewDataProcessor::processNodes() { + auto &data = ProviderExtraData::getCurrent().dataProcessor; - if (this->m_dataOverlays.size() != this->m_endNodes.size()) { - for (auto overlay : this->m_dataOverlays) + if (data.dataOverlays.size() != data.endNodes.size()) { + for (auto overlay : data.dataOverlays) ImHexApi::Provider::get()->deleteOverlay(overlay); - this->m_dataOverlays.clear(); + data.dataOverlays.clear(); - for (u32 i = 0; i < this->m_endNodes.size(); i++) - this->m_dataOverlays.push_back(ImHexApi::Provider::get()->newOverlay()); + for (u32 i = 0; i < data.endNodes.size(); i++) + data.dataOverlays.push_back(ImHexApi::Provider::get()->newOverlay()); u32 overlayIndex = 0; - for (auto endNode : this->m_endNodes) { - endNode->setCurrentOverlay(this->m_dataOverlays[overlayIndex]); + for (auto endNode : data.endNodes) { + endNode->setCurrentOverlay(data.dataOverlays[overlayIndex]); overlayIndex++; } } - this->m_currNodeError.reset(); + data.currNodeError.reset(); try { - for (auto &endNode : this->m_endNodes) { + for (auto &endNode : data.endNodes) { endNode->resetOutputData(); - for (auto &node : this->m_nodes) + for (auto &node : data.nodes) node->resetProcessedInputs(); endNode->process(); } } catch (dp::Node::NodeError &e) { - this->m_currNodeError = e; + data.currNodeError = e; - for (auto overlay : this->m_dataOverlays) + for (auto overlay : data.dataOverlays) ImHexApi::Provider::get()->deleteOverlay(overlay); - this->m_dataOverlays.clear(); + data.dataOverlays.clear(); } catch (std::runtime_error &e) { printf("Node implementation bug! %s\n", e.what()); @@ -183,6 +192,8 @@ namespace hex::plugin::builtin { } void ViewDataProcessor::drawContent() { + auto &data = ProviderExtraData::getCurrent().dataProcessor; + if (ImGui::Begin(View::toWindowName("hex.builtin.view.data_processor.name").c_str(), &this->getWindowOpenState(), ImGuiWindowFlags_NoCollapse)) { if (ImGui::IsMouseReleased(ImGuiMouseButton_Right) && ImGui::IsWindowHovered(ImGuiHoveredFlags_ChildWindows)) { @@ -200,7 +211,7 @@ namespace hex::plugin::builtin { } if (ImGui::BeginPopup("Context Menu")) { - dp::Node *node = nullptr; + std::unique_ptr node; if (ImNodes::NumSelectedNodes() > 0 || ImNodes::NumSelectedLinks() > 0) { if (ImGui::MenuItem("hex.builtin.view.data_processor.name"_lang)) { @@ -226,13 +237,11 @@ namespace hex::plugin::builtin { } else if (unlocalizedCategory.empty()) { if (ImGui::MenuItem(LangEntry(unlocalizedName))) { node = function(); - ProjectFile::markDirty(); } } else { if (ImGui::BeginMenu(LangEntry(unlocalizedCategory))) { if (ImGui::MenuItem(LangEntry(unlocalizedName))) { node = function(); - ProjectFile::markDirty(); } ImGui::EndMenu(); } @@ -240,8 +249,6 @@ namespace hex::plugin::builtin { } if (node != nullptr) { - this->m_nodes.push_back(node); - bool hasOutput = false; bool hasInput = false; for (auto &attr : node->getAttributes()) { @@ -253,9 +260,11 @@ namespace hex::plugin::builtin { } if (hasInput && !hasOutput) - this->m_endNodes.push_back(node); + data.endNodes.push_back(node.get()); ImNodes::SetNodeScreenSpacePos(node->getId(), this->m_rightClickedCoords); + data.nodes.push_back(std::move(node)); + ImHexApi::Provider::markDirty(); } ImGui::EndPopup(); @@ -277,11 +286,11 @@ namespace hex::plugin::builtin { { int nodeId; - if (ImNodes::IsNodeHovered(&nodeId) && this->m_currNodeError.has_value() && this->m_currNodeError->first->getId() == static_cast(nodeId)) { + if (ImNodes::IsNodeHovered(&nodeId) && data.currNodeError.has_value() && data.currNodeError->node->getId() == static_cast(nodeId)) { ImGui::BeginTooltip(); ImGui::TextUnformatted("hex.builtin.common.error"_lang); ImGui::Separator(); - ImGui::TextUnformatted(this->m_currNodeError->second.c_str()); + ImGui::TextUnformatted(data.currNodeError->message.c_str()); ImGui::EndTooltip(); } } @@ -289,8 +298,8 @@ namespace hex::plugin::builtin { if (ImGui::BeginChild("##node_editor", ImGui::GetContentRegionAvail() - ImVec2(0, ImGui::GetTextLineHeightWithSpacing() * 1.3))) { ImNodes::BeginNodeEditor(); - for (auto &node : this->m_nodes) { - const bool hasError = this->m_currNodeError.has_value() && this->m_currNodeError->first == node; + for (auto &node : data.nodes) { + const bool hasError = data.currNodeError.has_value() && data.currNodeError->node == node.get(); if (hasError) ImNodes::PushColorStyle(ImNodesCol_NodeOutline, 0xFF0000FF); @@ -336,12 +345,12 @@ namespace hex::plugin::builtin { ImNodes::PopColorStyle(); } - for (const auto &link : this->m_links) + for (const auto &link : data.links) ImNodes::Link(link.getId(), link.getFromId(), link.getToId()); ImNodes::MiniMap(0.2F, ImNodesMiniMapLocation_BottomRight); - if (this->m_nodes.empty()) + if (data.nodes.empty()) ImGui::TextFormattedCentered("{}", "hex.builtin.view.data_processor.help_text"_lang); ImNodes::EndNodeEditor(); @@ -367,7 +376,7 @@ namespace hex::plugin::builtin { do { dp::Attribute *fromAttr = nullptr, *toAttr = nullptr; - for (auto &node : this->m_nodes) { + for (auto &node : data.nodes) { for (auto &attribute : node->getAttributes()) { if (attribute.getId() == static_cast(from)) fromAttr = &attribute; @@ -388,7 +397,7 @@ namespace hex::plugin::builtin { if (!toAttr->getConnectedAttributes().empty()) break; - auto newLink = this->m_links.emplace_back(from, to); + auto newLink = data.links.emplace_back(from, to); fromAttr->addConnectedAttribute(newLink.getId(), toAttr); toAttr->addConnectedAttribute(newLink.getId(), fromAttr); @@ -423,12 +432,14 @@ namespace hex::plugin::builtin { ImGui::End(); } - std::string ViewDataProcessor::saveNodes() { + std::string ViewDataProcessor::saveNodes(prv::Provider *provider) { + auto &data = ProviderExtraData::get(provider).dataProcessor; + using json = nlohmann::json; json output; output["nodes"] = json::object(); - for (auto &node : this->m_nodes) { + for (auto &node : data.nodes) { auto id = node->getId(); auto &currNodeOutput = output["nodes"][std::to_string(id)]; auto pos = ImNodes::GetNodeGridSpacePos(id); @@ -453,7 +464,7 @@ namespace hex::plugin::builtin { } output["links"] = json::object(); - for (auto &link : this->m_links) { + for (auto &link : data.links) { auto id = link.getId(); auto &currOutput = output["links"][std::to_string(id)]; @@ -462,30 +473,29 @@ namespace hex::plugin::builtin { currOutput["to"] = link.getToId(); } - return output.dump(); + return output.dump(4); } - void ViewDataProcessor::loadNodes(const std::string &data) { + void ViewDataProcessor::loadNodes(prv::Provider *provider, const std::string &jsonData) { if (!ImHexApi::Provider::isValid()) return; + auto &data = ProviderExtraData::get(provider).dataProcessor; + using json = nlohmann::json; - json input = json::parse(data); + json input = json::parse(jsonData); u32 maxNodeId = 0; u32 maxAttrId = 0; u32 maxLinkId = 0; - for (auto &node : this->m_nodes) - delete node; - - this->m_nodes.clear(); - this->m_endNodes.clear(); - this->m_links.clear(); + data.nodes.clear(); + data.endNodes.clear(); + data.links.clear(); auto &nodeEntries = ContentRegistry::DataProcessorNode::getEntries(); for (auto &node : input["nodes"]) { - dp::Node *newNode = nullptr; + std::unique_ptr newNode; for (auto &entry : nodeEntries) { if (entry.name == node["type"]) newNode = entry.creatorFunction(); @@ -520,9 +530,9 @@ namespace hex::plugin::builtin { newNode->load(node["data"]); if (hasInput && !hasOutput) - this->m_endNodes.push_back(newNode); + data.endNodes.push_back(newNode.get()); - this->m_nodes.push_back(newNode); + data.nodes.push_back(std::move(newNode)); ImNodes::SetNodeGridSpacePos(nodeId, ImVec2(node["pos"]["x"], node["pos"]["y"])); } @@ -533,10 +543,10 @@ namespace hex::plugin::builtin { maxLinkId = std::max(linkId, maxLinkId); newLink.setID(linkId); - this->m_links.push_back(newLink); + data.links.push_back(newLink); dp::Attribute *fromAttr = nullptr, *toAttr = nullptr; - for (auto &node : this->m_nodes) { + for (auto &node : data.nodes) { for (auto &attribute : node->getAttributes()) { if (attribute.getId() == newLink.getFromId()) fromAttr = &attribute; diff --git a/plugins/builtin/source/content/views/view_hex_editor.cpp b/plugins/builtin/source/content/views/view_hex_editor.cpp index ab67ab008..7d20481d4 100644 --- a/plugins/builtin/source/content/views/view_hex_editor.cpp +++ b/plugins/builtin/source/content/views/view_hex_editor.cpp @@ -1,7 +1,6 @@ #include "content/views/view_hex_editor.hpp" #include -#include #include #include #include @@ -9,6 +8,7 @@ #include "math_evaluator.hpp" #include +#include #include diff --git a/plugins/builtin/source/content/views/view_patches.cpp b/plugins/builtin/source/content/views/view_patches.cpp index cf58e97db..2af2b5d0c 100644 --- a/plugins/builtin/source/content/views/view_patches.cpp +++ b/plugins/builtin/source/content/views/view_patches.cpp @@ -2,7 +2,8 @@ #include -#include +#include +#include #include @@ -11,22 +12,26 @@ using namespace std::literals::string_literals; namespace hex::plugin::builtin { ViewPatches::ViewPatches() : View("hex.builtin.view.patches.name") { - EventManager::subscribe(this, [] { - auto provider = ImHexApi::Provider::get(); - if (ImHexApi::Provider::isValid()) - ProjectFile::setPatches(provider->getPatches()); - }); - EventManager::subscribe(this, [] { - auto provider = ImHexApi::Provider::get(); - if (ImHexApi::Provider::isValid()) - provider->getPatches() = ProjectFile::getPatches(); + ProjectFile::registerPerProviderHandler({ + .basePath = "patches.json", + .load = [](prv::Provider *provider, const std::fs::path &basePath, Tar &tar) { + auto json = nlohmann::json::parse(tar.read(basePath)); + provider->getPatches() = json["patches"].get>(); + return true; + }, + .store = [](prv::Provider *provider, const std::fs::path &basePath, Tar &tar) { + nlohmann::json json; + json["patches"] = provider->getPatches(); + tar.write(basePath, json.dump(4)); + + return true; + } }); } ViewPatches::~ViewPatches() { - EventManager::unsubscribe(this); - EventManager::unsubscribe(this); + } void ViewPatches::drawContent() { @@ -86,7 +91,6 @@ namespace hex::plugin::builtin { if (ImGui::BeginPopup("PatchContextMenu")) { if (ImGui::MenuItem("hex.builtin.view.patches.remove"_lang)) { patches.erase(this->m_selectedPatch); - ProjectFile::markDirty(); } ImGui::EndPopup(); } diff --git a/plugins/builtin/source/content/views/view_pattern_data.cpp b/plugins/builtin/source/content/views/view_pattern_data.cpp index 1cb8bc262..48733f007 100644 --- a/plugins/builtin/source/content/views/view_pattern_data.cpp +++ b/plugins/builtin/source/content/views/view_pattern_data.cpp @@ -5,6 +5,8 @@ #include #include +#include + namespace hex::plugin::builtin { ViewPatternData::ViewPatternData() : View("hex.builtin.view.pattern_data.name") { @@ -109,7 +111,7 @@ namespace hex::plugin::builtin { if (ImHexApi::Provider::isValid() && provider->isReadable()) { auto &sortedPatterns = this->m_sortedPatterns[ImHexApi::Provider::get()]; - if (beginPatternTable(provider, provider->getPatternLanguageRuntime().getPatterns(), sortedPatterns)) { + if (beginPatternTable(provider, ProviderExtraData::get(provider).patternLanguage.runtime->getPatterns(), sortedPatterns)) { ImGui::TableHeadersRow(); if (!sortedPatterns.empty()) { diff --git a/plugins/builtin/source/content/views/view_pattern_editor.cpp b/plugins/builtin/source/content/views/view_pattern_editor.cpp index 2cd8764c4..5e76c63e8 100644 --- a/plugins/builtin/source/content/views/view_pattern_editor.cpp +++ b/plugins/builtin/source/content/views/view_pattern_editor.cpp @@ -11,9 +11,11 @@ #include #include #include -#include +#include #include +#include + #include namespace hex::plugin::builtin { @@ -86,15 +88,6 @@ namespace hex::plugin::builtin { this->m_envVarEntries.push_back({ 0, "", 0, EnvVarType::Integer }); this->m_envVarIdCounter = 1; - EventManager::subscribe(this, [this]() { - ProjectFile::setPattern(this->m_textEditor.GetText()); - }); - - EventManager::subscribe(this, [this]() { - this->m_textEditor.SetText(ProjectFile::getPattern()); - this->evaluatePattern(this->m_textEditor.GetText()); - }); - EventManager::subscribe(this, [this](const std::string &code) { this->m_textEditor.SetText(code); }); @@ -115,21 +108,25 @@ namespace hex::plugin::builtin { } }); - EventManager::subscribe(this, [this](prv::Provider *provider) { + EventManager::subscribe(this, [this](prv::Provider *provider) { if (!this->m_autoLoadPatterns) return; + auto &patternLanguageData = ProviderExtraData::get(provider).patternLanguage; + + patternLanguageData.runtime = ContentRegistry::PatternLanguage::createDefaultRuntime(provider); + // Copy over current pattern source code to the new provider if (!this->m_syncPatternSourceCode) { - provider->getPatternLanguageSourceCode() = this->m_textEditor.GetText(); + patternLanguageData.sourceCode = this->m_textEditor.GetText(); } - auto &runtime = provider->getPatternLanguageRuntime(); + auto &runtime = patternLanguageData.runtime; - auto mimeType = magic::getMIMEType(ImHexApi::Provider::get()); + auto mimeType = magic::getMIMEType(provider); bool foundCorrectType = false; - runtime.addPragma("MIME", [&mimeType, &foundCorrectType](pl::PatternLanguage &runtime, const std::string &value) { + runtime->addPragma("MIME", [&mimeType, &foundCorrectType](pl::PatternLanguage &runtime, const std::string &value) { hex::unused(runtime); if (value == mimeType) { @@ -152,16 +149,16 @@ namespace hex::plugin::builtin { if (!file.isValid()) continue; - runtime.getInternals().preprocessor->preprocess(runtime, file.readString()); + runtime->getInternals().preprocessor->preprocess(*runtime, file.readString()); if (foundCorrectType) this->m_possiblePatternFiles.push_back(entry.path()); - runtime.reset(); + runtime->reset(); } } - runtime.addPragma("MIME", [](pl::PatternLanguage&, const std::string &value) { return !value.empty(); }); + runtime->addPragma("MIME", [](pl::PatternLanguage&, const std::string &value) { return !value.empty(); }); if (!this->m_possiblePatternFiles.empty()) { this->m_selectedPatternFile = 0; @@ -170,14 +167,14 @@ namespace hex::plugin::builtin { } }); - EventManager::subscribe(this, [](auto *provider) { - provider->getPatternLanguageRuntime().abort(); - }); - EventManager::subscribe(this, [this](prv::Provider *oldProvider, prv::Provider *newProvider) { if (!this->m_syncPatternSourceCode) { - if (oldProvider != nullptr) oldProvider->getPatternLanguageSourceCode() = this->m_textEditor.GetText(); - if (newProvider != nullptr) this->m_textEditor.SetText(newProvider->getPatternLanguageSourceCode()); + if (oldProvider != nullptr) ProviderExtraData::get(oldProvider).patternLanguage.sourceCode = this->m_textEditor.GetText(); + + if (newProvider != nullptr) + this->m_textEditor.SetText(ProviderExtraData::get(newProvider).patternLanguage.sourceCode); + else + this->m_textEditor.SetText(""); auto lines = this->m_textEditor.GetTextLines(); lines.pop_back(); @@ -257,7 +254,7 @@ namespace hex::plugin::builtin { return std::nullopt; std::optional color; - for (const auto &pattern : ImHexApi::Provider::get()->getPatternLanguageRuntime().getPatterns(address)) { + for (const auto &pattern : ProviderExtraData::getCurrent().patternLanguage.runtime->getPatterns(address)) { if (pattern->isHidden()) continue; @@ -273,7 +270,7 @@ namespace hex::plugin::builtin { ImHexApi::HexEditor::addTooltipProvider([this](u64 address, const u8 *data, size_t size) { hex::unused(data, size); - auto patterns = ImHexApi::Provider::get()->getPatternLanguageRuntime().getPatterns(address); + auto patterns = ProviderExtraData::getCurrent().patternLanguage.runtime->getPatterns(address); if (!patterns.empty() && !std::all_of(patterns.begin(), patterns.end(), [](const auto &pattern) { return pattern->isHidden(); })) { ImGui::BeginTooltip(); for (const auto &pattern : patterns) { @@ -298,11 +295,37 @@ namespace hex::plugin::builtin { ImGui::EndTooltip(); } }); + + ProjectFile::registerPerProviderHandler({ + .basePath = "pattern_source_code.hexpat", + .load = [this](prv::Provider *provider, const std::fs::path &basePath, Tar &tar) { + std::string sourceCode = tar.readString(basePath); + + if (!this->m_syncPatternSourceCode) + ProviderExtraData::get(provider).patternLanguage.sourceCode = sourceCode; + + this->m_textEditor.SetText(sourceCode); + + return true; + }, + .store = [this](prv::Provider *provider, const std::fs::path &basePath, Tar &tar) { + std::string sourceCode; + + if (provider == ImHexApi::Provider::get()) + ProviderExtraData::get(provider).patternLanguage.sourceCode = this->m_textEditor.GetText(); + + if (this->m_syncPatternSourceCode) + sourceCode = this->m_textEditor.GetText(); + else + sourceCode = ProviderExtraData::get(provider).patternLanguage.sourceCode; + + tar.write(basePath, sourceCode); + return true; + } + }); } ViewPatternEditor::~ViewPatternEditor() { - EventManager::unsubscribe(this); - EventManager::unsubscribe(this); EventManager::unsubscribe(this); EventManager::unsubscribe(this); EventManager::unsubscribe(this); @@ -342,10 +365,10 @@ namespace hex::plugin::builtin { ImGui::PushStyleVar(ImGuiStyleVar_FrameBorderSize, 1); - auto &runtime = provider->getPatternLanguageRuntime(); - if (runtime.isRunning()) { + auto &runtime = ProviderExtraData::getCurrent().patternLanguage.runtime; + if (runtime->isRunning()) { if (ImGui::IconButton(ICON_VS_DEBUG_STOP, ImGui::GetCustomColorVec4(ImGuiCustomCol_ToolbarRed))) - runtime.abort(); + runtime->abort(); } else { if (ImGui::IconButton(ICON_VS_DEBUG_START, ImGui::GetCustomColorVec4(ImGuiCustomCol_ToolbarGreen))) { this->evaluatePattern(this->m_textEditor.GetText()); @@ -369,13 +392,13 @@ namespace hex::plugin::builtin { ImGui::SameLine(); ImGui::TextFormatted("{} / {}", - provider->getPatternLanguageRuntime().getCreatedPatternCount(), - provider->getPatternLanguageRuntime().getMaximumPatternCount()); + runtime->getCreatedPatternCount(), + runtime->getMaximumPatternCount()); } if (this->m_textEditor.IsTextChanged()) { - ProjectFile::markDirty(); this->m_hasUnevaluatedChanges = true; + ImHexApi::Provider::markDirty(); } if (this->m_hasUnevaluatedChanges && this->m_runningEvaluators == 0 && this->m_runningParsers == 0) { @@ -785,14 +808,16 @@ namespace hex::plugin::builtin { this->m_textEditor.SetErrorMarkers({}); this->m_console.clear(); - ImHexApi::Provider::get()->getPatternLanguageRuntime().reset(); + + auto &runtime = ProviderExtraData::getCurrent().patternLanguage.runtime; + runtime->reset(); EventManager::post(); - auto provider = ImHexApi::Provider::get(); - std::thread([this, code, provider] { + std::thread([this, code, &runtime] { auto task = ImHexApi::Tasks::createTask("hex.builtin.view.pattern_editor.evaluating", 1); + std::map envVars; for (const auto &[id, name, value, type] : this->m_envVarEntries) envVars.insert({ name, value }); @@ -805,9 +830,7 @@ namespace hex::plugin::builtin { inVariables[name] = variable.value; } - auto &runtime = provider->getPatternLanguageRuntime(); - - runtime.setDangerousFunctionCallHandler([this]{ + runtime->setDangerousFunctionCallHandler([this]{ this->m_dangerousFunctionCalled = true; while (this->m_dangerousFunctionsAllowed == DangerousFunctionPerms::Ask) { @@ -817,15 +840,15 @@ namespace hex::plugin::builtin { return this->m_dangerousFunctionsAllowed == DangerousFunctionPerms::Allow; }); - this->m_lastEvaluationResult = runtime.executeString(code, envVars, inVariables); + this->m_lastEvaluationResult = runtime->executeString(code, envVars, inVariables); if (!this->m_lastEvaluationResult) { - this->m_lastEvaluationError = runtime.getError(); + this->m_lastEvaluationError = runtime->getError(); } - runtime.flattenPatterns(); + runtime->flattenPatterns(); - this->m_lastEvaluationLog = runtime.getConsoleLog(); - this->m_lastEvaluationOutVars = runtime.getOutVariables(); + this->m_lastEvaluationLog = runtime->getConsoleLog(); + this->m_lastEvaluationOutVars = runtime->getOutVariables(); this->m_runningEvaluators--; this->m_lastEvaluationProcessed = false; diff --git a/plugins/builtin/source/content/welcome_screen.cpp b/plugins/builtin/source/content/welcome_screen.cpp index a563cb35d..c1a541c55 100644 --- a/plugins/builtin/source/content/welcome_screen.cpp +++ b/plugins/builtin/source/content/welcome_screen.cpp @@ -7,8 +7,7 @@ #include #include - -#include +#include #include #include @@ -90,9 +89,6 @@ namespace hex::plugin::builtin { ImGui::SetCursorPosX(width / 9); if (ImGui::Button("hex.builtin.welcome.safety_backup.restore"_lang, ImVec2(width / 3, 0))) { ProjectFile::load(s_safetyBackupPath); - ProjectFile::markDirty(); - - ProjectFile::clearProjectFilePath(); fs::remove(s_safetyBackupPath); ImGui::CloseCurrentPopup(); diff --git a/plugins/builtin/source/lang/de_DE.cpp b/plugins/builtin/source/lang/de_DE.cpp index a42c81f0a..83864b479 100644 --- a/plugins/builtin/source/lang/de_DE.cpp +++ b/plugins/builtin/source/lang/de_DE.cpp @@ -94,7 +94,9 @@ namespace hex::plugin::builtin { { "hex.builtin.common.encoding.utf8", "UTF-8" }, { "hex.builtin.popup.exit_application.title", "Applikation verlassen?" }, - { "hex.builtin.popup.exit_application.desc", "Es wurden ungespeicherte Änderungen an diesem Projekt vorgenommen\nBist du sicher, dass du ImHex schliessen willst?" }, + { "hex.builtin.popup.exit_application.desc", "Es wurden ungespeicherte Änderungen an diesem Projekt vorgenommen.\nBist du sicher, dass du ImHex schliessen willst?" }, + { "hex.builtin.popup.close_provider.title", "Provider schliessen?" }, + { "hex.builtin.popup.close_provider.desc", "Es wurden ungespeicherte Änderungen an diesem Provider vorgenommen.\nBist du sicher, dass du ihn schliessen willst?" }, { "hex.builtin.popup.error.read_only", "Schreibzugriff konnte nicht erlangt werden. Datei wurde im Lesemodus geöffnet." }, { "hex.builtin.popup.error.open", "Öffnen der Datei fehlgeschlagen!" }, { "hex.builtin.popup.error.create", "Erstellen der neuen Datei fehlgeschlagen!" }, diff --git a/plugins/builtin/source/lang/en_US.cpp b/plugins/builtin/source/lang/en_US.cpp index 7bbcd1021..94a500651 100644 --- a/plugins/builtin/source/lang/en_US.cpp +++ b/plugins/builtin/source/lang/en_US.cpp @@ -97,6 +97,8 @@ namespace hex::plugin::builtin { { "hex.builtin.popup.exit_application.title", "Exit Application?" }, { "hex.builtin.popup.exit_application.desc", "You have unsaved changes made to your Project.\nAre you sure you want to exit?" }, + { "hex.builtin.popup.close_provider.title", "Close Provider?" }, + { "hex.builtin.popup.close_provider.desc", "You have unsaved changes made to this Provider.\nAre you sure you want to close it?" }, { "hex.builtin.popup.error.read_only", "Couldn't get write access. File opened in read-only mode." }, { "hex.builtin.popup.error.open", "Failed to open file!" }, { "hex.builtin.popup.error.create", "Failed to create new file!" }, diff --git a/plugins/builtin/source/lang/it_IT.cpp b/plugins/builtin/source/lang/it_IT.cpp index 9b873c020..ba2120fb8 100644 --- a/plugins/builtin/source/lang/it_IT.cpp +++ b/plugins/builtin/source/lang/it_IT.cpp @@ -95,6 +95,8 @@ namespace hex::plugin::builtin { { "hex.builtin.popup.exit_application.title", "Uscire dall'applicazione?" }, { "hex.builtin.popup.exit_application.desc", "Hai delle modifiche non salvate nel tuo progetto.\nSei sicuro di voler uscire?" }, + //{ "hex.builtin.popup.close_provider.title", "Close Provider?" }, + //{ "hex.builtin.popup.close_provider.desc", "You have unsaved changes made to this Provider.\nAre you sure you want to close it?" }, { "hex.builtin.popup.error.read_only", "Impossibile scrivere sul File. File aperto solo in modalità lettura" }, { "hex.builtin.popup.error.open", "Impossibile aprire il File!" }, { "hex.builtin.popup.error.create", "Impossibile creare il nuovo File!" }, diff --git a/plugins/builtin/source/lang/ja_JP.cpp b/plugins/builtin/source/lang/ja_JP.cpp index 6550667e9..0bbb0de0e 100644 --- a/plugins/builtin/source/lang/ja_JP.cpp +++ b/plugins/builtin/source/lang/ja_JP.cpp @@ -95,6 +95,8 @@ namespace hex::plugin::builtin { { "hex.builtin.popup.exit_application.title", "アプリケーションを終了しますか?" }, { "hex.builtin.popup.exit_application.desc", "プロジェクトに保存されていない変更があります。\n終了してもよろしいですか?" }, + //{ "hex.builtin.popup.close_provider.title", "Close Provider?" }, + //{ "hex.builtin.popup.close_provider.desc", "You have unsaved changes made to this Provider.\nAre you sure you want to close it?" }, { "hex.builtin.popup.error.read_only", "書き込み権限を取得できませんでした。ファイルが読み取り専用で開かれました。" }, { "hex.builtin.popup.error.open", "ファイルを開けませんでした。" }, { "hex.builtin.popup.error.create", "新しいファイルを作成できませんでした。" }, diff --git a/plugins/builtin/source/lang/pt_BR.cpp b/plugins/builtin/source/lang/pt_BR.cpp index ba541327a..d32907595 100644 --- a/plugins/builtin/source/lang/pt_BR.cpp +++ b/plugins/builtin/source/lang/pt_BR.cpp @@ -95,6 +95,8 @@ namespace hex::plugin::builtin { { "hex.builtin.popup.exit_application.title", "Sair da aplicação?" }, { "hex.builtin.popup.exit_application.desc", "Você tem alterações não salvas feitas em seu projeto.\nVocê tem certeza que quer sair?" }, + //{ "hex.builtin.popup.close_provider.title", "Close Provider?" }, + //{ "hex.builtin.popup.close_provider.desc", "You have unsaved changes made to this Provider.\nAre you sure you want to close it?" }, { "hex.builtin.popup.error.read_only", "Não foi possível obter acesso de gravação. Arquivo aberto no modo somente leitura." }, { "hex.builtin.popup.error.open", "Falha ao abrir o arquivo!" }, { "hex.builtin.popup.error.create", "Falha ao criar um novo arquivo!" }, diff --git a/plugins/builtin/source/lang/zh_CN.cpp b/plugins/builtin/source/lang/zh_CN.cpp index 741ff4e02..3ab522350 100644 --- a/plugins/builtin/source/lang/zh_CN.cpp +++ b/plugins/builtin/source/lang/zh_CN.cpp @@ -95,6 +95,8 @@ namespace hex::plugin::builtin { { "hex.builtin.popup.exit_application.title", "退出?" }, { "hex.builtin.popup.exit_application.desc", "工程还有未保存的更改。\n确定要退出吗?" }, + //{ "hex.builtin.popup.close_provider.title", "Close Provider?" }, + //{ "hex.builtin.popup.close_provider.desc", "You have unsaved changes made to this Provider.\nAre you sure you want to close it?" }, { "hex.builtin.popup.error.read_only", "无法获得写权限,文件以只读方式打开。" }, { "hex.builtin.popup.error.open", "打开文件失败!" }, { "hex.builtin.popup.error.create", "创建新文件失败!" }, diff --git a/plugins/builtin/source/lang/zh_TW.cpp b/plugins/builtin/source/lang/zh_TW.cpp index f176e6337..615f0162b 100644 --- a/plugins/builtin/source/lang/zh_TW.cpp +++ b/plugins/builtin/source/lang/zh_TW.cpp @@ -95,6 +95,8 @@ namespace hex::plugin::builtin { { "hex.builtin.popup.exit_application.title", "離開應用程式?" }, { "hex.builtin.popup.exit_application.desc", "您的專案有未儲存的更動。\n您確定要離開嗎?" }, + //{ "hex.builtin.popup.close_provider.title", "Close Provider?" }, + //{ "hex.builtin.popup.close_provider.desc", "You have unsaved changes made to this Provider.\nAre you sure you want to close it?" }, { "hex.builtin.popup.error.read_only", "無法取得寫入權限。檔案已以唯讀模式開啟。" }, { "hex.builtin.popup.error.open", "無法開啟檔案!" }, { "hex.builtin.popup.error.create", "無法建立新檔案!" }, diff --git a/tests/common/include/hex/test/test_provider.hpp b/tests/common/include/hex/test/test_provider.hpp index 90ab152b8..63980630c 100644 --- a/tests/common/include/hex/test/test_provider.hpp +++ b/tests/common/include/hex/test/test_provider.hpp @@ -48,6 +48,8 @@ namespace hex::test { return this->m_data->size(); } + [[nodiscard]] virtual std::string getTypeName() const { return "hex.test.provider.test"; } + bool open() override { return true; } void close() override { } diff --git a/tests/helpers/source/common.cpp b/tests/helpers/source/common.cpp index e912b048f..d4d4c44a4 100644 --- a/tests/helpers/source/common.cpp +++ b/tests/helpers/source/common.cpp @@ -53,9 +53,6 @@ TEST_SEQUENCE("TestProvider_write") { std::fill(std::begin(buff), std::end(buff), 22); provider2->write(1, data, 4); provider2->applyPatches(); - hex::log::error("asd {:#x}", buff[0]); - hex::log::error("asd {:#x}", buff[1]); - hex::log::error("asd {:#x}", buff[2]); TEST_ASSERT(buff[0] == 22); // should be unchanged TEST_ASSERT(buff[1] == 0xde); TEST_ASSERT(buff[2] == 0xad);