diff --git a/.gitmodules b/.gitmodules index f14d636c8..4eba152b8 100644 --- a/.gitmodules +++ b/.gitmodules @@ -36,3 +36,6 @@ [submodule "lib/third_party/HashLibPlus"] path = lib/third_party/HashLibPlus url = https://github.com/WerWolv/HashLibPlus +[submodule "lib/third_party/edlib"] + path = lib/third_party/edlib + url = https://github.com/Martinsos/edlib diff --git a/cmake/build_helpers.cmake b/cmake/build_helpers.cmake index 5dfcccd4e..65734f912 100644 --- a/cmake/build_helpers.cmake +++ b/cmake/build_helpers.cmake @@ -350,6 +350,10 @@ macro(configureCMake) # display a warning about options being set using set() instead of option(). # Explicitly set the policy to NEW to suppress the warning. set(CMAKE_POLICY_DEFAULT_CMP0077 NEW) + + set(CMAKE_POLICY_DEFAULT_CMP0063 NEW) + + set(CMAKE_WARN_DEPRECATED OFF CACHE BOOL "Disable deprecated warnings" FORCE) endmacro() macro(setDefaultBuiltTypeIfUnset) diff --git a/lib/external/libwolv b/lib/external/libwolv index f7c78709e..a58bc52eb 160000 --- a/lib/external/libwolv +++ b/lib/external/libwolv @@ -1 +1 @@ -Subproject commit f7c78709e89f2c1c293ec60f897881e7e135580b +Subproject commit a58bc52eb69d440e1aa1df035fc405579644531b diff --git a/lib/libimhex/include/hex/api/content_registry.hpp b/lib/libimhex/include/hex/api/content_registry.hpp index c28baf810..ed9694c18 100644 --- a/lib/libimhex/include/hex/api/content_registry.hpp +++ b/lib/libimhex/include/hex/api/content_registry.hpp @@ -996,6 +996,56 @@ namespace hex { } + /* Diffing Registry. Allows adding new diffing algorithms */ + namespace Diffing { + + enum class DifferenceType : u8 { + Match = 0, + Insertion = 1, + Deletion = 2, + Mismatch = 3 + }; + + using DiffTree = wolv::container::IntervalTree; + + class Algorithm { + public: + explicit Algorithm(UnlocalizedString unlocalizedName, UnlocalizedString unlocalizedDescription) + : m_unlocalizedName(std::move(unlocalizedName)), + m_unlocalizedDescription(std::move(unlocalizedDescription)) { } + + virtual ~Algorithm() = default; + + virtual std::vector analyze(prv::Provider *providerA, prv::Provider *providerB) const = 0; + virtual void drawSettings() { } + + const UnlocalizedString& getUnlocalizedName() const { return m_unlocalizedName; } + const UnlocalizedString& getUnlocalizedDescription() const { return m_unlocalizedDescription; } + + private: + UnlocalizedString m_unlocalizedName, m_unlocalizedDescription; + }; + + namespace impl { + + std::vector> &getAlgorithms(); + + void addAlgorithm(std::unique_ptr &&hash); + + } + + /** + * @brief Adds a new hash + * @tparam T The hash type that extends hex::Hash + * @param args The arguments to pass to the constructor of the hash + */ + template + void addAlgorithm(Args && ... args) { + impl::addAlgorithm(std::make_unique(std::forward(args)...)); + } + + } + /* Hash Registry. Allows adding new hashes to the Hash view */ namespace Hashes { @@ -1061,6 +1111,7 @@ namespace hex { std::vector> &getHashes(); void add(std::unique_ptr &&hash); + } diff --git a/lib/libimhex/include/hex/api/task_manager.hpp b/lib/libimhex/include/hex/api/task_manager.hpp index b6cc8eb80..4afe54a7c 100644 --- a/lib/libimhex/include/hex/api/task_manager.hpp +++ b/lib/libimhex/include/hex/api/task_manager.hpp @@ -154,11 +154,25 @@ namespace hex { */ static void runWhenTasksFinished(const std::function &function); + /** + * @brief Sets the name of the current thread + * @param name Name of the thread + */ static void setCurrentThreadName(const std::string &name); + + /** + * @brief Gets the name of the current thread + * @return Name of the thread + */ static std::string getCurrentThreadName(); + /** + * @brief Cleans up finished tasks + */ static void collectGarbage(); + static Task& getCurrentTask(); + static size_t getRunningTaskCount(); static size_t getRunningBackgroundTaskCount(); diff --git a/lib/libimhex/include/hex/providers/provider_data.hpp b/lib/libimhex/include/hex/providers/provider_data.hpp index 1ef62e056..91154b562 100644 --- a/lib/libimhex/include/hex/providers/provider_data.hpp +++ b/lib/libimhex/include/hex/providers/provider_data.hpp @@ -22,8 +22,6 @@ namespace hex { PerProvider& operator=(const PerProvider&) = delete; PerProvider& operator=(PerProvider &&) = delete; - PerProvider(T data) : m_data({ { ImHexApi::Provider::get(), std::move(data) } }) { this->onCreate(); } - ~PerProvider() { this->onDestroy(); } T* operator->() { diff --git a/lib/libimhex/source/api/content_registry.cpp b/lib/libimhex/source/api/content_registry.cpp index c06ebd47f..db5e68175 100644 --- a/lib/libimhex/source/api/content_registry.cpp +++ b/lib/libimhex/source/api/content_registry.cpp @@ -995,6 +995,23 @@ namespace hex { return nullptr; } + } + + namespace ContentRegistry::Diffing { + + namespace impl { + + std::vector>& getAlgorithms() { + static std::vector> algorithms; + + return algorithms; + } + + void addAlgorithm(std::unique_ptr &&hash) { + getAlgorithms().emplace_back(std::move(hash)); + } + + } } diff --git a/lib/libimhex/source/api/task_manager.cpp b/lib/libimhex/source/api/task_manager.cpp index 12cc9573e..5de452b5c 100644 --- a/lib/libimhex/source/api/task_manager.cpp +++ b/lib/libimhex/source/api/task_manager.cpp @@ -31,6 +31,7 @@ namespace hex { std::vector s_workers; thread_local std::array s_currentThreadName; + thread_local Task* s_currentTask = nullptr; } @@ -228,6 +229,8 @@ namespace hex { // Grab the next task from the queue task = std::move(s_taskQueue.front()); s_taskQueue.pop_front(); + + s_currentTask = task.get(); } try { @@ -253,6 +256,7 @@ namespace hex { task->exception("Unknown Exception"); } + s_currentTask = nullptr; task->finish(); } }); @@ -326,6 +330,11 @@ namespace hex { } + Task& TaskManager::getCurrentTask() { + return *s_currentTask; + } + + std::list> &TaskManager::getRunningTasks() { return s_tasks; } diff --git a/lib/third_party/edlib b/lib/third_party/edlib new file mode 160000 index 000000000..931be2b09 --- /dev/null +++ b/lib/third_party/edlib @@ -0,0 +1 @@ +Subproject commit 931be2b0909985551eb17d767694a6e64e31ebfa diff --git a/plugins/builtin/CMakeLists.txt b/plugins/builtin/CMakeLists.txt index a0a7dcefb..1a33037af 100644 --- a/plugins/builtin/CMakeLists.txt +++ b/plugins/builtin/CMakeLists.txt @@ -102,7 +102,6 @@ add_imhex_plugin( source/content/views/view_data_processor.cpp source/content/views/view_constants.cpp source/content/views/view_store.cpp - source/content/views/view_diff.cpp source/content/views/view_provider_settings.cpp source/content/views/view_find.cpp source/content/views/view_theme_manager.cpp diff --git a/plugins/builtin/include/content/views/view_pattern_editor.hpp b/plugins/builtin/include/content/views/view_pattern_editor.hpp index d34525508..312ba0993 100644 --- a/plugins/builtin/include/content/views/view_pattern_editor.hpp +++ b/plugins/builtin/include/content/views/view_pattern_editor.hpp @@ -199,7 +199,7 @@ namespace hex::plugin::builtin { PatternSourceCode m_sourceCode; PerProvider> m_console; - PerProvider m_executionDone = true; + PerProvider m_executionDone; std::mutex m_logMutex; diff --git a/plugins/builtin/romfs/auto_extract/workspaces/default.hexws b/plugins/builtin/romfs/auto_extract/workspaces/default.hexws index 3efea8f5b..e452615c0 100644 --- a/plugins/builtin/romfs/auto_extract/workspaces/default.hexws +++ b/plugins/builtin/romfs/auto_extract/workspaces/default.hexws @@ -1,4 +1,4 @@ { - "layout": "[Window][ImHexDockSpace]\nPos=0,19\nSize=1393,765\nCollapsed=0\n\n[Window][Debug##Default]\nPos=0,55\nSize=400,400\nCollapsed=0\n\n[Window][###hex.builtin.view.settings.name]\nPos=346,191\nSize=700,400\nCollapsed=0\n\n[Window][Question]\nPos=496,338\nSize=400,105\nCollapsed=0\n\n[Window][Welcome Screen]\nPos=0,37\nSize=1393,728\nCollapsed=0\n\n[Window][###hex.builtin.view.hex_editor.name]\nPos=0,38\nSize=619,468\nCollapsed=0\nDockId=0x00000007,0\n\n[Window][###hex.builtin.view.data_inspector.name]\nPos=621,38\nSize=124,468\nCollapsed=0\nDockId=0x00000008,0\n\n[Window][###hex.builtin.view.pattern_data.name]\nPos=0,508\nSize=745,252\nCollapsed=0\nDockId=0x00000006,0\n\n[Window][###hex.builtin.view.pattern_editor.name]\nPos=747,38\nSize=646,722\nCollapsed=0\nDockId=0x00000009,0\n\n[Window][###hex.hashes.view.hashes.name]\nPos=1697,76\nSize=863,1427\nCollapsed=0\nDockId=0x00000009,4\n\n[Window][###hex.builtin.view.find.name]\nPos=1697,76\nSize=863,1427\nCollapsed=0\nDockId=0x00000009,3\n\n[Window][###hex.builtin.view.bookmarks.name]\nPos=1697,76\nSize=863,1427\nCollapsed=0\nDockId=0x00000009,2\n\n[Window][###hex.builtin.view.information.name]\nPos=-1889,-120\nSize=510,420\nCollapsed=0\n\n[Window][###hex.yara_rules.view.yara.name]\nPos=720,38\nSize=560,660\nCollapsed=0\n\n[Window][###hex.builtin.view.store.name]\nViewportPos=564,236\nViewportId=0xB51F9C4A\nSize=900,700\nCollapsed=0\n\n[Window][###hex.builtin.view.diff.name]\nPos=1372,38\nSize=1188,1333\nCollapsed=0\nDockId=0x00000009,1\n\n[Window][###hex.builtin.view.provider_settings.load_popup]\nPos=585,322\nSize=314,208\nCollapsed=0\n\n[Window][###hex.builtin.view.patches.name]\nPos=-1889,-120\nSize=510,420\nCollapsed=0\n\n[Window][###hex.builtin.view.data_processor.name]\nPos=747,38\nSize=646,722\nCollapsed=0\nDockId=0x00000009,1\n\n[Window][###hex.builtin.view.tools.name]\nPos=849,268\nSize=431,430\nCollapsed=0\nDockId=0x0000000A,0\n\n[Window][###hex.builtin.view.theme_manager.name]\nPos=391,302\nSize=469,400\nCollapsed=0\n\n[Window][###hex.builtin.tools.invariant_multiplication]\nPos=-1826,300\nSize=600,232\nCollapsed=0\n\n[Window][###hex.builtin.tools.regex_replacer]\nPos=-2091,104\nSize=600,305\nCollapsed=0\n\n[Window][###hex.builtin.tools.calc]\nPos=-1811,118\nSize=600,402\nCollapsed=0\n\n[Window][###hex.builtin.tools.permissions]\nPos=423,296\nSize=600,220\nCollapsed=0\n\n[Window][###hex.builtin.view.help.about.name]\nPos=377,193\nSize=677,400\nCollapsed=0\n\n[Window][###hex.builtin.view.constants.name]\nPos=419,-124\nSize=652,660\nCollapsed=0\n\n[Window][###hex.disassembler.view.disassembler.name]\nPos=1004,-204\nSize=1336,1320\nCollapsed=0\n\n[Window][##achievement_unlocked]\nPos=1093,0\nSize=200,55\nCollapsed=0\n\n[Window][hex.builtin.popup.blocking_task.title]\nPos=506,305\nSize=20,40\nCollapsed=0\n\n[Window][Waiting for Tasks]\nPos=60,60\nSize=16,35\nCollapsed=0\n\n[Window][Restore lost data]\nPos=555,349\nSize=283,84\nCollapsed=0\n\n[Window][Error]\nPos=440,301\nSize=400,118\nCollapsed=0\n\n[Window][###hex.builtin.view.highlight_rules.name]\nViewportPos=724,217\nViewportId=0x31C07F88\nSize=700,400\nCollapsed=0\n\n[Window][SideBarWindow]\nPos=19,37\nSize=660,1345\nCollapsed=0\n\n[Window][SideBarWindow/##Content_53A061AE]\nIsChild=1\nSize=644,1329\n\n[Window][Choose file]\nPos=382,131\nSize=516,458\nCollapsed=0\n\n[Window][###hex.builtin.view.logs.name]\nPos=60,60\nSize=549,466\nCollapsed=0\n\n[Window][###hex.builtin.view.achievements.name]\nPos=60,60\nSize=800,600\nCollapsed=0\n\n[Window][hex.builtin.welcome.start.recent.auto_backups]\nPos=580,365\nSize=233,52\nCollapsed=0\n\n[Window][Auto Backups]\nPos=580,331\nSize=233,120\nCollapsed=0\n\n[Window][hex.builtin.popup.create_workspace.title]\nPos=496,325\nSize=400,132\nCollapsed=0\n\n[Table][0x6A4694E4,3]\nRefScale=13\nColumn 0 Sort=0v\n\n[Table][0x7EE28D79,8]\nRefScale=13\nColumn 0 Width=13\nColumn 1 Weight=1.0000\nColumn 2 Weight=1.0000\nColumn 3 Weight=1.0000 Sort=0v\nColumn 4 Weight=1.0000\nColumn 5 Weight=1.0000\nColumn 6 Weight=1.0000\nColumn 7 Weight=1.0000\n\n[Table][0x6190819E,3]\nColumn 0 Weight=1.0000\nColumn 1 Weight=1.0000\nColumn 2 Weight=1.0000\n\n[Docking][Data]\nDockSpace ID=0x81A8BB71 Window=0xF9B0A590 Pos=225,133 Size=1393,722 Split=X\n DockNode ID=0x00000001 Parent=0x81A8BB71 SizeRef=1370,0 Split=Y\n DockNode ID=0x00000005 Parent=0x00000001 SizeRef=0,825 Split=X Selected=0x5708C63F\n DockNode ID=0x00000007 Parent=0x00000005 SizeRef=1140,701 Selected=0x5708C63F\n DockNode ID=0x00000008 Parent=0x00000005 SizeRef=228,701 Selected=0xFBA7A393\n DockNode ID=0x00000006 Parent=0x00000001 SizeRef=0,444 Selected=0x7AD1CDDD\n DockNode ID=0x00000002 Parent=0x81A8BB71 SizeRef=1188,0 Split=X\n DockNode ID=0x00000003 Parent=0x00000002 SizeRef=12,0\n DockNode ID=0x00000004 Parent=0x00000002 SizeRef=52,0 Split=Y Selected=0xCACA884B\n DockNode ID=0x00000009 Parent=0x00000004 SizeRef=420,228 Selected=0xCACA884B\n DockNode ID=0x0000000A Parent=0x00000004 SizeRef=420,430 Selected=0x1F041AD3\n\n[ImHex][General]\nhex.builtin.view.achievements.name=0\nhex.builtin.view.bookmarks.name=0\nhex.builtin.view.command_palette.name=0\nhex.builtin.view.constants.name=0\nhex.builtin.view.data_inspector.name=1\nhex.builtin.view.data_processor.name=1\nhex.builtin.view.diff.name=0\nhex.disassembler.view.disassembler.name=0\nhex.builtin.view.find.name=0\nhex.hashes.view.hashes.name=0\nhex.builtin.view.help.about.name=0\nhex.builtin.view.hex_editor.name=1\nhex.builtin.view.highlight_rules.name=0\nhex.builtin.view.information.name=0\nhex.builtin.view.logs.name=0\nhex.builtin.view.patches.name=0\nhex.builtin.view.pattern_data.name=1\nhex.builtin.view.pattern_editor.name=1\nhex.builtin.view.provider_settings.name=0\nhex.builtin.view.settings.name=0\nhex.builtin.view.store.name=0\nhex.builtin.view.theme_manager.name=0\nhex.builtin.view.tools.name=0\nhex.yara_rules.view.yara.name=0\nhex.windows.view.tty_console.name=0\nhex.builtin.tools.demangler=0\nhex.builtin.tools.ascii_table=0\nhex.builtin.tools.regex_replacer=0\nhex.builtin.tools.color=0\nhex.builtin.tools.calc=0\nhex.builtin.tools.graphing=0\nhex.builtin.tools.base_converter=0\nhex.builtin.tools.byte_swapper=0\nhex.builtin.tools.permissions=0\nhex.builtin.tools.wiki_explain=0\nhex.builtin.tools.file_tools=0\nhex.builtin.tools.ieee754=0\nhex.builtin.tools.invariant_multiplication=0\nhex.builtin.tools.tcp_client_server=0\nhex.builtin.tools.euclidean_algorithm=0\n\n", + "layout": "[Window][ImHexDockSpace]\nPos=0,19\nSize=1393,765\nCollapsed=0\n\n[Window][Debug##Default]\nPos=0,55\nSize=400,400\nCollapsed=0\n\n[Window][###hex.builtin.view.settings.name]\nPos=346,191\nSize=700,400\nCollapsed=0\n\n[Window][Question]\nPos=496,338\nSize=400,105\nCollapsed=0\n\n[Window][Welcome Screen]\nPos=0,37\nSize=1393,728\nCollapsed=0\n\n[Window][###hex.builtin.view.hex_editor.name]\nPos=0,38\nSize=619,468\nCollapsed=0\nDockId=0x00000007,0\n\n[Window][###hex.builtin.view.data_inspector.name]\nPos=621,38\nSize=124,468\nCollapsed=0\nDockId=0x00000008,0\n\n[Window][###hex.builtin.view.pattern_data.name]\nPos=0,508\nSize=745,252\nCollapsed=0\nDockId=0x00000006,0\n\n[Window][###hex.builtin.view.pattern_editor.name]\nPos=747,38\nSize=646,722\nCollapsed=0\nDockId=0x00000009,0\n\n[Window][###hex.hashes.view.hashes.name]\nPos=1697,76\nSize=863,1427\nCollapsed=0\nDockId=0x00000009,4\n\n[Window][###hex.builtin.view.find.name]\nPos=1697,76\nSize=863,1427\nCollapsed=0\nDockId=0x00000009,3\n\n[Window][###hex.builtin.view.bookmarks.name]\nPos=1697,76\nSize=863,1427\nCollapsed=0\nDockId=0x00000009,2\n\n[Window][###hex.builtin.view.information.name]\nPos=-1889,-120\nSize=510,420\nCollapsed=0\n\n[Window][###hex.yara_rules.view.yara.name]\nPos=720,38\nSize=560,660\nCollapsed=0\n\n[Window][###hex.builtin.view.store.name]\nViewportPos=564,236\nViewportId=0xB51F9C4A\nSize=900,700\nCollapsed=0\n\n[Window][###hex.diffing.view.diff.name]\nPos=1372,38\nSize=1188,1333\nCollapsed=0\nDockId=0x00000009,1\n\n[Window][###hex.builtin.view.provider_settings.load_popup]\nPos=585,322\nSize=314,208\nCollapsed=0\n\n[Window][###hex.builtin.view.patches.name]\nPos=-1889,-120\nSize=510,420\nCollapsed=0\n\n[Window][###hex.builtin.view.data_processor.name]\nPos=747,38\nSize=646,722\nCollapsed=0\nDockId=0x00000009,1\n\n[Window][###hex.builtin.view.tools.name]\nPos=849,268\nSize=431,430\nCollapsed=0\nDockId=0x0000000A,0\n\n[Window][###hex.builtin.view.theme_manager.name]\nPos=391,302\nSize=469,400\nCollapsed=0\n\n[Window][###hex.builtin.tools.invariant_multiplication]\nPos=-1826,300\nSize=600,232\nCollapsed=0\n\n[Window][###hex.builtin.tools.regex_replacer]\nPos=-2091,104\nSize=600,305\nCollapsed=0\n\n[Window][###hex.builtin.tools.calc]\nPos=-1811,118\nSize=600,402\nCollapsed=0\n\n[Window][###hex.builtin.tools.permissions]\nPos=423,296\nSize=600,220\nCollapsed=0\n\n[Window][###hex.builtin.view.help.about.name]\nPos=377,193\nSize=677,400\nCollapsed=0\n\n[Window][###hex.builtin.view.constants.name]\nPos=419,-124\nSize=652,660\nCollapsed=0\n\n[Window][###hex.disassembler.view.disassembler.name]\nPos=1004,-204\nSize=1336,1320\nCollapsed=0\n\n[Window][##achievement_unlocked]\nPos=1093,0\nSize=200,55\nCollapsed=0\n\n[Window][hex.builtin.popup.blocking_task.title]\nPos=506,305\nSize=20,40\nCollapsed=0\n\n[Window][Waiting for Tasks]\nPos=60,60\nSize=16,35\nCollapsed=0\n\n[Window][Restore lost data]\nPos=555,349\nSize=283,84\nCollapsed=0\n\n[Window][Error]\nPos=440,301\nSize=400,118\nCollapsed=0\n\n[Window][###hex.builtin.view.highlight_rules.name]\nViewportPos=724,217\nViewportId=0x31C07F88\nSize=700,400\nCollapsed=0\n\n[Window][SideBarWindow]\nPos=19,37\nSize=660,1345\nCollapsed=0\n\n[Window][SideBarWindow/##Content_53A061AE]\nIsChild=1\nSize=644,1329\n\n[Window][Choose file]\nPos=382,131\nSize=516,458\nCollapsed=0\n\n[Window][###hex.builtin.view.logs.name]\nPos=60,60\nSize=549,466\nCollapsed=0\n\n[Window][###hex.builtin.view.achievements.name]\nPos=60,60\nSize=800,600\nCollapsed=0\n\n[Window][hex.builtin.welcome.start.recent.auto_backups]\nPos=580,365\nSize=233,52\nCollapsed=0\n\n[Window][Auto Backups]\nPos=580,331\nSize=233,120\nCollapsed=0\n\n[Window][hex.builtin.popup.create_workspace.title]\nPos=496,325\nSize=400,132\nCollapsed=0\n\n[Table][0x6A4694E4,3]\nRefScale=13\nColumn 0 Sort=0v\n\n[Table][0x7EE28D79,8]\nRefScale=13\nColumn 0 Width=13\nColumn 1 Weight=1.0000\nColumn 2 Weight=1.0000\nColumn 3 Weight=1.0000 Sort=0v\nColumn 4 Weight=1.0000\nColumn 5 Weight=1.0000\nColumn 6 Weight=1.0000\nColumn 7 Weight=1.0000\n\n[Table][0x6190819E,3]\nColumn 0 Weight=1.0000\nColumn 1 Weight=1.0000\nColumn 2 Weight=1.0000\n\n[Docking][Data]\nDockSpace ID=0x81A8BB71 Window=0xF9B0A590 Pos=225,133 Size=1393,722 Split=X\n DockNode ID=0x00000001 Parent=0x81A8BB71 SizeRef=1370,0 Split=Y\n DockNode ID=0x00000005 Parent=0x00000001 SizeRef=0,825 Split=X Selected=0x5708C63F\n DockNode ID=0x00000007 Parent=0x00000005 SizeRef=1140,701 Selected=0x5708C63F\n DockNode ID=0x00000008 Parent=0x00000005 SizeRef=228,701 Selected=0xFBA7A393\n DockNode ID=0x00000006 Parent=0x00000001 SizeRef=0,444 Selected=0x7AD1CDDD\n DockNode ID=0x00000002 Parent=0x81A8BB71 SizeRef=1188,0 Split=X\n DockNode ID=0x00000003 Parent=0x00000002 SizeRef=12,0\n DockNode ID=0x00000004 Parent=0x00000002 SizeRef=52,0 Split=Y Selected=0xCACA884B\n DockNode ID=0x00000009 Parent=0x00000004 SizeRef=420,228 Selected=0xCACA884B\n DockNode ID=0x0000000A Parent=0x00000004 SizeRef=420,430 Selected=0x1F041AD3\n\n[ImHex][General]\nhex.builtin.view.achievements.name=0\nhex.builtin.view.bookmarks.name=0\nhex.builtin.view.command_palette.name=0\nhex.builtin.view.constants.name=0\nhex.builtin.view.data_inspector.name=1\nhex.builtin.view.data_processor.name=1\nhex.diffing.view.diff.name=0\nhex.disassembler.view.disassembler.name=0\nhex.builtin.view.find.name=0\nhex.hashes.view.hashes.name=0\nhex.builtin.view.help.about.name=0\nhex.builtin.view.hex_editor.name=1\nhex.builtin.view.highlight_rules.name=0\nhex.builtin.view.information.name=0\nhex.builtin.view.logs.name=0\nhex.builtin.view.patches.name=0\nhex.builtin.view.pattern_data.name=1\nhex.builtin.view.pattern_editor.name=1\nhex.builtin.view.provider_settings.name=0\nhex.builtin.view.settings.name=0\nhex.builtin.view.store.name=0\nhex.builtin.view.theme_manager.name=0\nhex.builtin.view.tools.name=0\nhex.yara_rules.view.yara.name=0\nhex.windows.view.tty_console.name=0\nhex.builtin.tools.demangler=0\nhex.builtin.tools.ascii_table=0\nhex.builtin.tools.regex_replacer=0\nhex.builtin.tools.color=0\nhex.builtin.tools.calc=0\nhex.builtin.tools.graphing=0\nhex.builtin.tools.base_converter=0\nhex.builtin.tools.byte_swapper=0\nhex.builtin.tools.permissions=0\nhex.builtin.tools.wiki_explain=0\nhex.builtin.tools.file_tools=0\nhex.builtin.tools.ieee754=0\nhex.builtin.tools.invariant_multiplication=0\nhex.builtin.tools.tcp_client_server=0\nhex.builtin.tools.euclidean_algorithm=0\n\n", "name": "Default" } \ No newline at end of file diff --git a/plugins/builtin/romfs/auto_extract/workspaces/minimal.hexws b/plugins/builtin/romfs/auto_extract/workspaces/minimal.hexws index dc7d5d73f..3a3fbfb73 100644 --- a/plugins/builtin/romfs/auto_extract/workspaces/minimal.hexws +++ b/plugins/builtin/romfs/auto_extract/workspaces/minimal.hexws @@ -1,4 +1,4 @@ { - "layout": "[Window][ImHexDockSpace]\nPos=0,19\nSize=600,783\nCollapsed=0\n\n[Window][Debug##Default]\nPos=0,55\nSize=400,400\nCollapsed=0\n\n[Window][###hex.builtin.view.settings.name]\nPos=259,200\nSize=700,400\nCollapsed=0\n\n[Window][Question]\nPos=496,338\nSize=400,105\nCollapsed=0\n\n[Window][Welcome Screen]\nPos=0,37\nSize=1393,728\nCollapsed=0\n\n[Window][###hex.builtin.view.hex_editor.name]\nPos=0,38\nSize=600,740\nCollapsed=0\nDockId=0x00000007,0\n\n[Window][###hex.builtin.view.data_inspector.name]\nPos=1142,76\nSize=553,980\nCollapsed=0\nDockId=0x00000008,0\n\n[Window][###hex.builtin.view.pattern_data.name]\nPos=0,1058\nSize=1695,445\nCollapsed=0\nDockId=0x00000006,0\n\n[Window][###hex.builtin.view.pattern_editor.name]\nPos=1697,76\nSize=863,1427\nCollapsed=0\nDockId=0x00000004,0\n\n[Window][###hex.hashes.view.hashes.name]\nPos=1697,76\nSize=863,1427\nCollapsed=0\nDockId=0x00000004,4\n\n[Window][###hex.builtin.view.find.name]\nPos=1697,76\nSize=863,1427\nCollapsed=0\nDockId=0x00000004,3\n\n[Window][###hex.builtin.view.bookmarks.name]\nPos=1697,76\nSize=863,1427\nCollapsed=0\nDockId=0x00000004,2\n\n[Window][###hex.builtin.view.information.name]\nPos=-1889,-120\nSize=510,420\nCollapsed=0\n\n[Window][###hex.yara_rules.view.yara.name]\nPos=720,38\nSize=560,660\nCollapsed=0\n\n[Window][###hex.builtin.view.store.name]\nPos=562,201\nSize=900,700\nCollapsed=0\n\n[Window][###hex.builtin.view.diff.name]\nPos=1233,38\nSize=687,1021\nCollapsed=0\n\n[Window][###hex.builtin.view.provider_settings.load_popup]\nPos=585,322\nSize=314,208\nCollapsed=0\n\n[Window][###hex.builtin.view.patches.name]\nPos=-1889,-120\nSize=510,420\nCollapsed=0\n\n[Window][###hex.builtin.view.data_processor.name]\nPos=1697,76\nSize=863,1427\nCollapsed=0\nDockId=0x00000004,1\n\n[Window][###hex.builtin.view.tools.name]\nViewportPos=952,218\nViewportId=0x9B385D8A\nSize=1306,1600\nCollapsed=0\n\n[Window][###hex.builtin.view.theme_manager.name]\nPos=391,302\nSize=469,400\nCollapsed=0\n\n[Window][###hex.builtin.tools.invariant_multiplication]\nPos=-1826,300\nSize=600,232\nCollapsed=0\n\n[Window][###hex.builtin.tools.regex_replacer]\nPos=-2091,104\nSize=600,305\nCollapsed=0\n\n[Window][###hex.builtin.tools.calc]\nPos=-1811,118\nSize=600,402\nCollapsed=0\n\n[Window][###hex.builtin.tools.permissions]\nPos=423,296\nSize=600,220\nCollapsed=0\n\n[Window][###hex.builtin.view.help.about.name]\nPos=214,201\nSize=600,350\nCollapsed=0\n\n[Window][###hex.builtin.view.constants.name]\nPos=419,-124\nSize=652,660\nCollapsed=0\n\n[Window][###hex.disassembler.view.disassembler.name]\nPos=1004,-204\nSize=1336,1320\nCollapsed=0\n\n[Window][##achievement_unlocked]\nPos=1093,0\nSize=200,55\nCollapsed=0\n\n[Window][hex.builtin.popup.blocking_task.title]\nPos=506,305\nSize=20,40\nCollapsed=0\n\n[Window][Waiting for Tasks]\nPos=60,60\nSize=16,35\nCollapsed=0\n\n[Window][Restore lost data]\nPos=555,349\nSize=283,84\nCollapsed=0\n\n[Window][Error]\nPos=440,301\nSize=400,118\nCollapsed=0\n\n[Window][###hex.builtin.view.highlight_rules.name]\nViewportPos=724,217\nViewportId=0x31C07F88\nSize=700,400\nCollapsed=0\n\n[Window][SideBarWindow]\nPos=19,37\nSize=660,1345\nCollapsed=0\n\n[Window][SideBarWindow/##Content_53A061AE]\nIsChild=1\nSize=644,1329\n\n[Window][Choose file]\nPos=382,131\nSize=516,458\nCollapsed=0\n\n[Window][###hex.builtin.view.logs.name]\nPos=60,60\nSize=549,466\nCollapsed=0\n\n[Window][###hex.builtin.view.achievements.name]\nPos=60,60\nSize=800,600\nCollapsed=0\n\n[Window][hex.builtin.welcome.start.recent.auto_backups]\nPos=580,365\nSize=233,52\nCollapsed=0\n\n[Window][Auto Backups]\nPos=580,331\nSize=233,120\nCollapsed=0\n\n[Window][hex.builtin.popup.create_workspace.title]\nPos=100,334\nSize=400,132\nCollapsed=0\n\n[Table][0x6A4694E4,3]\nRefScale=13\nColumn 0 Sort=0v\n\n[Table][0x7EE28D79,8]\nRefScale=13\nColumn 0 Width=13\nColumn 1 Weight=1.0000\nColumn 2 Weight=1.0000\nColumn 3 Weight=1.0000 Sort=0v\nColumn 4 Weight=1.0000\nColumn 5 Weight=1.0000\nColumn 6 Weight=1.0000\nColumn 7 Weight=1.0000\n\n[Table][0x6190819E,3]\nColumn 0 Weight=1.0000\nColumn 1 Weight=1.0000\nColumn 2 Weight=1.0000\n\n[Docking][Data]\nDockSpace ID=0x81A8BB71 Window=0xF9B0A590 Pos=220,131 Size=600,740 Split=X\n DockNode ID=0x00000001 Parent=0x81A8BB71 SizeRef=847,0 Split=Y\n DockNode ID=0x00000005 Parent=0x00000001 SizeRef=0,44 Split=X Selected=0x5708C63F\n DockNode ID=0x00000007 Parent=0x00000005 SizeRef=1140,701 Selected=0x5708C63F\n DockNode ID=0x00000008 Parent=0x00000005 SizeRef=553,701 Selected=0xFBA7A393\n DockNode ID=0x00000006 Parent=0x00000001 SizeRef=0,20 Selected=0x7AD1CDDD\n DockNode ID=0x00000002 Parent=0x81A8BB71 SizeRef=431,0 Split=X\n DockNode ID=0x00000003 Parent=0x00000002 SizeRef=12,0\n DockNode ID=0x00000004 Parent=0x00000002 SizeRef=52,0 Selected=0xCACA884B\n\n[ImHex][General]\nhex.builtin.view.achievements.name=0\nhex.builtin.view.bookmarks.name=0\nhex.builtin.view.command_palette.name=0\nhex.builtin.view.constants.name=0\nhex.builtin.view.data_inspector.name=0\nhex.builtin.view.data_processor.name=0\nhex.builtin.view.diff.name=0\nhex.disassembler.view.disassembler.name=0\nhex.builtin.view.find.name=0\nhex.hashes.view.hashes.name=0\nhex.builtin.view.help.about.name=0\nhex.builtin.view.hex_editor.name=1\nhex.builtin.view.highlight_rules.name=0\nhex.builtin.view.information.name=0\nhex.builtin.view.logs.name=0\nhex.builtin.view.patches.name=0\nhex.builtin.view.pattern_data.name=0\nhex.builtin.view.pattern_editor.name=0\nhex.builtin.view.provider_settings.name=0\nhex.builtin.view.settings.name=0\nhex.builtin.view.store.name=0\nhex.builtin.view.theme_manager.name=0\nhex.builtin.view.tools.name=0\nhex.yara_rules.view.yara.name=0\nhex.windows.view.tty_console.name=0\nhex.builtin.tools.demangler=0\nhex.builtin.tools.ascii_table=0\nhex.builtin.tools.regex_replacer=0\nhex.builtin.tools.color=0\nhex.builtin.tools.calc=0\nhex.builtin.tools.graphing=0\nhex.builtin.tools.base_converter=0\nhex.builtin.tools.byte_swapper=0\nhex.builtin.tools.permissions=0\nhex.builtin.tools.wiki_explain=0\nhex.builtin.tools.file_tools=0\nhex.builtin.tools.ieee754=0\nhex.builtin.tools.invariant_multiplication=0\nhex.builtin.tools.tcp_client_server=0\nhex.builtin.tools.euclidean_algorithm=0\n\n", + "layout": "[Window][ImHexDockSpace]\nPos=0,19\nSize=600,783\nCollapsed=0\n\n[Window][Debug##Default]\nPos=0,55\nSize=400,400\nCollapsed=0\n\n[Window][###hex.builtin.view.settings.name]\nPos=259,200\nSize=700,400\nCollapsed=0\n\n[Window][Question]\nPos=496,338\nSize=400,105\nCollapsed=0\n\n[Window][Welcome Screen]\nPos=0,37\nSize=1393,728\nCollapsed=0\n\n[Window][###hex.builtin.view.hex_editor.name]\nPos=0,38\nSize=600,740\nCollapsed=0\nDockId=0x00000007,0\n\n[Window][###hex.builtin.view.data_inspector.name]\nPos=1142,76\nSize=553,980\nCollapsed=0\nDockId=0x00000008,0\n\n[Window][###hex.builtin.view.pattern_data.name]\nPos=0,1058\nSize=1695,445\nCollapsed=0\nDockId=0x00000006,0\n\n[Window][###hex.builtin.view.pattern_editor.name]\nPos=1697,76\nSize=863,1427\nCollapsed=0\nDockId=0x00000004,0\n\n[Window][###hex.hashes.view.hashes.name]\nPos=1697,76\nSize=863,1427\nCollapsed=0\nDockId=0x00000004,4\n\n[Window][###hex.builtin.view.find.name]\nPos=1697,76\nSize=863,1427\nCollapsed=0\nDockId=0x00000004,3\n\n[Window][###hex.builtin.view.bookmarks.name]\nPos=1697,76\nSize=863,1427\nCollapsed=0\nDockId=0x00000004,2\n\n[Window][###hex.builtin.view.information.name]\nPos=-1889,-120\nSize=510,420\nCollapsed=0\n\n[Window][###hex.yara_rules.view.yara.name]\nPos=720,38\nSize=560,660\nCollapsed=0\n\n[Window][###hex.builtin.view.store.name]\nPos=562,201\nSize=900,700\nCollapsed=0\n\n[Window][###hex.diffing.view.diff.name]\nPos=1233,38\nSize=687,1021\nCollapsed=0\n\n[Window][###hex.builtin.view.provider_settings.load_popup]\nPos=585,322\nSize=314,208\nCollapsed=0\n\n[Window][###hex.builtin.view.patches.name]\nPos=-1889,-120\nSize=510,420\nCollapsed=0\n\n[Window][###hex.builtin.view.data_processor.name]\nPos=1697,76\nSize=863,1427\nCollapsed=0\nDockId=0x00000004,1\n\n[Window][###hex.builtin.view.tools.name]\nViewportPos=952,218\nViewportId=0x9B385D8A\nSize=1306,1600\nCollapsed=0\n\n[Window][###hex.builtin.view.theme_manager.name]\nPos=391,302\nSize=469,400\nCollapsed=0\n\n[Window][###hex.builtin.tools.invariant_multiplication]\nPos=-1826,300\nSize=600,232\nCollapsed=0\n\n[Window][###hex.builtin.tools.regex_replacer]\nPos=-2091,104\nSize=600,305\nCollapsed=0\n\n[Window][###hex.builtin.tools.calc]\nPos=-1811,118\nSize=600,402\nCollapsed=0\n\n[Window][###hex.builtin.tools.permissions]\nPos=423,296\nSize=600,220\nCollapsed=0\n\n[Window][###hex.builtin.view.help.about.name]\nPos=214,201\nSize=600,350\nCollapsed=0\n\n[Window][###hex.builtin.view.constants.name]\nPos=419,-124\nSize=652,660\nCollapsed=0\n\n[Window][###hex.disassembler.view.disassembler.name]\nPos=1004,-204\nSize=1336,1320\nCollapsed=0\n\n[Window][##achievement_unlocked]\nPos=1093,0\nSize=200,55\nCollapsed=0\n\n[Window][hex.builtin.popup.blocking_task.title]\nPos=506,305\nSize=20,40\nCollapsed=0\n\n[Window][Waiting for Tasks]\nPos=60,60\nSize=16,35\nCollapsed=0\n\n[Window][Restore lost data]\nPos=555,349\nSize=283,84\nCollapsed=0\n\n[Window][Error]\nPos=440,301\nSize=400,118\nCollapsed=0\n\n[Window][###hex.builtin.view.highlight_rules.name]\nViewportPos=724,217\nViewportId=0x31C07F88\nSize=700,400\nCollapsed=0\n\n[Window][SideBarWindow]\nPos=19,37\nSize=660,1345\nCollapsed=0\n\n[Window][SideBarWindow/##Content_53A061AE]\nIsChild=1\nSize=644,1329\n\n[Window][Choose file]\nPos=382,131\nSize=516,458\nCollapsed=0\n\n[Window][###hex.builtin.view.logs.name]\nPos=60,60\nSize=549,466\nCollapsed=0\n\n[Window][###hex.builtin.view.achievements.name]\nPos=60,60\nSize=800,600\nCollapsed=0\n\n[Window][hex.builtin.welcome.start.recent.auto_backups]\nPos=580,365\nSize=233,52\nCollapsed=0\n\n[Window][Auto Backups]\nPos=580,331\nSize=233,120\nCollapsed=0\n\n[Window][hex.builtin.popup.create_workspace.title]\nPos=100,334\nSize=400,132\nCollapsed=0\n\n[Table][0x6A4694E4,3]\nRefScale=13\nColumn 0 Sort=0v\n\n[Table][0x7EE28D79,8]\nRefScale=13\nColumn 0 Width=13\nColumn 1 Weight=1.0000\nColumn 2 Weight=1.0000\nColumn 3 Weight=1.0000 Sort=0v\nColumn 4 Weight=1.0000\nColumn 5 Weight=1.0000\nColumn 6 Weight=1.0000\nColumn 7 Weight=1.0000\n\n[Table][0x6190819E,3]\nColumn 0 Weight=1.0000\nColumn 1 Weight=1.0000\nColumn 2 Weight=1.0000\n\n[Docking][Data]\nDockSpace ID=0x81A8BB71 Window=0xF9B0A590 Pos=220,131 Size=600,740 Split=X\n DockNode ID=0x00000001 Parent=0x81A8BB71 SizeRef=847,0 Split=Y\n DockNode ID=0x00000005 Parent=0x00000001 SizeRef=0,44 Split=X Selected=0x5708C63F\n DockNode ID=0x00000007 Parent=0x00000005 SizeRef=1140,701 Selected=0x5708C63F\n DockNode ID=0x00000008 Parent=0x00000005 SizeRef=553,701 Selected=0xFBA7A393\n DockNode ID=0x00000006 Parent=0x00000001 SizeRef=0,20 Selected=0x7AD1CDDD\n DockNode ID=0x00000002 Parent=0x81A8BB71 SizeRef=431,0 Split=X\n DockNode ID=0x00000003 Parent=0x00000002 SizeRef=12,0\n DockNode ID=0x00000004 Parent=0x00000002 SizeRef=52,0 Selected=0xCACA884B\n\n[ImHex][General]\nhex.builtin.view.achievements.name=0\nhex.builtin.view.bookmarks.name=0\nhex.builtin.view.command_palette.name=0\nhex.builtin.view.constants.name=0\nhex.builtin.view.data_inspector.name=0\nhex.builtin.view.data_processor.name=0\nhex.diffing.view.diff.name=0\nhex.disassembler.view.disassembler.name=0\nhex.builtin.view.find.name=0\nhex.hashes.view.hashes.name=0\nhex.builtin.view.help.about.name=0\nhex.builtin.view.hex_editor.name=1\nhex.builtin.view.highlight_rules.name=0\nhex.builtin.view.information.name=0\nhex.builtin.view.logs.name=0\nhex.builtin.view.patches.name=0\nhex.builtin.view.pattern_data.name=0\nhex.builtin.view.pattern_editor.name=0\nhex.builtin.view.provider_settings.name=0\nhex.builtin.view.settings.name=0\nhex.builtin.view.store.name=0\nhex.builtin.view.theme_manager.name=0\nhex.builtin.view.tools.name=0\nhex.yara_rules.view.yara.name=0\nhex.windows.view.tty_console.name=0\nhex.builtin.tools.demangler=0\nhex.builtin.tools.ascii_table=0\nhex.builtin.tools.regex_replacer=0\nhex.builtin.tools.color=0\nhex.builtin.tools.calc=0\nhex.builtin.tools.graphing=0\nhex.builtin.tools.base_converter=0\nhex.builtin.tools.byte_swapper=0\nhex.builtin.tools.permissions=0\nhex.builtin.tools.wiki_explain=0\nhex.builtin.tools.file_tools=0\nhex.builtin.tools.ieee754=0\nhex.builtin.tools.invariant_multiplication=0\nhex.builtin.tools.tcp_client_server=0\nhex.builtin.tools.euclidean_algorithm=0\n\n", "name": "Minimal" } \ No newline at end of file diff --git a/plugins/builtin/romfs/lang/de_DE.json b/plugins/builtin/romfs/lang/de_DE.json index 568144a58..9c42a07bc 100644 --- a/plugins/builtin/romfs/lang/de_DE.json +++ b/plugins/builtin/romfs/lang/de_DE.json @@ -566,12 +566,6 @@ "hex.builtin.view.data_processor.menu.remove_selection": "Auswahl entfernen", "hex.builtin.view.data_processor.menu.save_node": "", "hex.builtin.view.data_processor.name": "Datenprozessor", - "hex.builtin.view.diff.name": "Diffing", - "hex.builtin.view.diff.added": "", - "hex.builtin.view.diff.modified": "", - "hex.builtin.view.diff.provider_a": "", - "hex.builtin.view.diff.provider_b": "", - "hex.builtin.view.diff.removed": "", "hex.builtin.view.find.binary_pattern": "Binärpattern", "hex.builtin.view.find.binary_pattern.alignment": "", "hex.builtin.view.find.context.copy": "Wert kopieren", diff --git a/plugins/builtin/romfs/lang/en_US.json b/plugins/builtin/romfs/lang/en_US.json index b92b2367c..a45732cdf 100644 --- a/plugins/builtin/romfs/lang/en_US.json +++ b/plugins/builtin/romfs/lang/en_US.json @@ -672,12 +672,7 @@ "hex.builtin.view.data_processor.menu.remove_selection": "Remove Selected", "hex.builtin.view.data_processor.menu.save_node": "Save Node", "hex.builtin.view.data_processor.name": "Data Processor", - "hex.builtin.view.diff.name": "Diffing", - "hex.builtin.view.diff.added": "Added", - "hex.builtin.view.diff.modified": "Modified", - "hex.builtin.view.diff.provider_a": "Provider A", - "hex.builtin.view.diff.provider_b": "Provider B", - "hex.builtin.view.diff.removed": "Removed", + "hex.builtin.view.find.binary_pattern": "Binary Pattern", "hex.builtin.view.find.binary_pattern.alignment": "Alignment", "hex.builtin.view.find.context.copy": "Copy Value", diff --git a/plugins/builtin/romfs/lang/es_ES.json b/plugins/builtin/romfs/lang/es_ES.json index 61519b4d7..170ce8283 100644 --- a/plugins/builtin/romfs/lang/es_ES.json +++ b/plugins/builtin/romfs/lang/es_ES.json @@ -565,12 +565,6 @@ "hex.builtin.view.data_processor.menu.remove_selection": "Eliminar Seleccionado", "hex.builtin.view.data_processor.menu.save_node": "Guardar Nodo", "hex.builtin.view.data_processor.name": "Procesador de Datos", - "hex.builtin.view.diff.name": "Análisis de diferencias", - "hex.builtin.view.diff.added": "Añadidas", - "hex.builtin.view.diff.modified": "Modificadas", - "hex.builtin.view.diff.provider_a": "Proveedor A", - "hex.builtin.view.diff.provider_b": "Proveedor B", - "hex.builtin.view.diff.removed": "Eliminados", "hex.builtin.view.find.binary_pattern": "Patrón Binario", "hex.builtin.view.find.binary_pattern.alignment": "Alineado", "hex.builtin.view.find.context.copy": "Copiar Valor", diff --git a/plugins/builtin/romfs/lang/it_IT.json b/plugins/builtin/romfs/lang/it_IT.json index bc7c0ab6b..80d4fa31d 100644 --- a/plugins/builtin/romfs/lang/it_IT.json +++ b/plugins/builtin/romfs/lang/it_IT.json @@ -565,12 +565,6 @@ "hex.builtin.view.data_processor.menu.remove_selection": "Rimuovi i selezionati", "hex.builtin.view.data_processor.menu.save_node": "", "hex.builtin.view.data_processor.name": "Processa Dati", - "hex.builtin.view.diff.name": "Diffing", - "hex.builtin.view.diff.added": "", - "hex.builtin.view.diff.modified": "", - "hex.builtin.view.diff.provider_a": "", - "hex.builtin.view.diff.provider_b": "", - "hex.builtin.view.diff.removed": "", "hex.builtin.view.find.binary_pattern": "", "hex.builtin.view.find.binary_pattern.alignment": "", "hex.builtin.view.find.context.copy": "", diff --git a/plugins/builtin/romfs/lang/ja_JP.json b/plugins/builtin/romfs/lang/ja_JP.json index c8eceee21..e880b6dea 100644 --- a/plugins/builtin/romfs/lang/ja_JP.json +++ b/plugins/builtin/romfs/lang/ja_JP.json @@ -565,12 +565,6 @@ "hex.builtin.view.data_processor.menu.remove_selection": "選択部分を削除", "hex.builtin.view.data_processor.menu.save_node": "", "hex.builtin.view.data_processor.name": "データプロセッサ", - "hex.builtin.view.diff.name": "比較", - "hex.builtin.view.diff.added": "", - "hex.builtin.view.diff.modified": "", - "hex.builtin.view.diff.provider_a": "", - "hex.builtin.view.diff.provider_b": "", - "hex.builtin.view.diff.removed": "", "hex.builtin.view.find.binary_pattern": "16進数", "hex.builtin.view.find.binary_pattern.alignment": "", "hex.builtin.view.find.context.copy": "値をコピー", diff --git a/plugins/builtin/romfs/lang/ko_KR.json b/plugins/builtin/romfs/lang/ko_KR.json index ad196af41..dad4f28a9 100644 --- a/plugins/builtin/romfs/lang/ko_KR.json +++ b/plugins/builtin/romfs/lang/ko_KR.json @@ -586,12 +586,6 @@ "hex.builtin.view.data_processor.menu.remove_selection": "선택 영역 제거", "hex.builtin.view.data_processor.menu.save_node": "노드 저장", "hex.builtin.view.data_processor.name": "데이터 프로세서", - "hex.builtin.view.diff.name": "파일 비교", - "hex.builtin.view.diff.added": "추가됨", - "hex.builtin.view.diff.modified": "수정됨", - "hex.builtin.view.diff.provider_a": "공급자 A", - "hex.builtin.view.diff.provider_b": "공급자 B", - "hex.builtin.view.diff.removed": "제거됨", "hex.builtin.view.find.binary_pattern": "바이너리 패턴", "hex.builtin.view.find.binary_pattern.alignment": "정렬", "hex.builtin.view.find.context.copy": "값 복사", diff --git a/plugins/builtin/romfs/lang/pt_BR.json b/plugins/builtin/romfs/lang/pt_BR.json index 00aba8814..ad5c9c9dc 100644 --- a/plugins/builtin/romfs/lang/pt_BR.json +++ b/plugins/builtin/romfs/lang/pt_BR.json @@ -565,12 +565,6 @@ "hex.builtin.view.data_processor.menu.remove_selection": "Remover Selecionado", "hex.builtin.view.data_processor.menu.save_node": "", "hex.builtin.view.data_processor.name": "Data Processor", - "hex.builtin.view.diff.name": "Diferenciando", - "hex.builtin.view.diff.added": "", - "hex.builtin.view.diff.modified": "", - "hex.builtin.view.diff.provider_a": "", - "hex.builtin.view.diff.provider_b": "", - "hex.builtin.view.diff.removed": "", "hex.builtin.view.find.binary_pattern": "", "hex.builtin.view.find.binary_pattern.alignment": "", "hex.builtin.view.find.context.copy": "", diff --git a/plugins/builtin/romfs/lang/zh_CN.json b/plugins/builtin/romfs/lang/zh_CN.json index cbff9ea04..75bdaf9d0 100644 --- a/plugins/builtin/romfs/lang/zh_CN.json +++ b/plugins/builtin/romfs/lang/zh_CN.json @@ -579,12 +579,6 @@ "hex.builtin.view.data_processor.menu.remove_selection": "移除已选", "hex.builtin.view.data_processor.menu.save_node": "保存节点", "hex.builtin.view.data_processor.name": "数据处理器", - "hex.builtin.view.diff.name": "差异", - "hex.builtin.view.diff.added": "添加", - "hex.builtin.view.diff.modified": "修改", - "hex.builtin.view.diff.provider_a": "提供者A", - "hex.builtin.view.diff.provider_b": "提供者B", - "hex.builtin.view.diff.removed": "移除", "hex.builtin.view.find.binary_pattern": "二进制模式", "hex.builtin.view.find.binary_pattern.alignment": "对齐", "hex.builtin.view.find.context.copy": "复制值", diff --git a/plugins/builtin/romfs/lang/zh_TW.json b/plugins/builtin/romfs/lang/zh_TW.json index 4d24a0e87..89a8570ac 100644 --- a/plugins/builtin/romfs/lang/zh_TW.json +++ b/plugins/builtin/romfs/lang/zh_TW.json @@ -579,12 +579,6 @@ "hex.builtin.view.data_processor.menu.remove_selection": "移除所選", "hex.builtin.view.data_processor.menu.save_node": "儲存節點", "hex.builtin.view.data_processor.name": "資料處理器", - "hex.builtin.view.diff.name": "差異", - "hex.builtin.view.diff.added": "已新增", - "hex.builtin.view.diff.modified": "已修改", - "hex.builtin.view.diff.provider_a": "提供者 A", - "hex.builtin.view.diff.provider_b": "提供者 B", - "hex.builtin.view.diff.removed": "已移除", "hex.builtin.view.find.binary_pattern": "二進位模式", "hex.builtin.view.find.binary_pattern.alignment": "", "hex.builtin.view.find.context.copy": "複製數值", diff --git a/plugins/builtin/romfs/layouts/default.hexlyt b/plugins/builtin/romfs/layouts/default.hexlyt index 8d789ba9c..40e1b6f42 100644 --- a/plugins/builtin/romfs/layouts/default.hexlyt +++ b/plugins/builtin/romfs/layouts/default.hexlyt @@ -65,7 +65,7 @@ Pos=562,201 Size=900,700 Collapsed=0 -[Window][###hex.builtin.view.diff.name] +[Window][###hex.diffing.view.diff.name] Pos=1233,38 Size=687,1021 Collapsed=0 @@ -149,7 +149,7 @@ hex.builtin.view.command_palette.name=0 hex.builtin.view.constants.name=0 hex.builtin.view.data_inspector.name=1 hex.builtin.view.data_processor.name=0 -hex.builtin.view.diff.name=0 +hex.diffing.view.diff.name=0 hex.disassembler.view.disassembler.name=0 hex.builtin.view.find.name=0 hex.hashes.view.hashes.name=0 diff --git a/plugins/builtin/romfs/layouts/minimal.hexlyt b/plugins/builtin/romfs/layouts/minimal.hexlyt index b0779a81b..d511b9611 100644 --- a/plugins/builtin/romfs/layouts/minimal.hexlyt +++ b/plugins/builtin/romfs/layouts/minimal.hexlyt @@ -65,7 +65,7 @@ Pos=562,201 Size=900,700 Collapsed=0 -[Window][###hex.builtin.view.diff.name] +[Window][###hex.diffing.view.diff.name] Pos=1233,38 Size=687,1021 Collapsed=0 @@ -150,7 +150,7 @@ hex.builtin.view.command_palette.name=0 hex.builtin.view.constants.name=0 hex.builtin.view.data_inspector.name=0 hex.builtin.view.data_processor.name=0 -hex.builtin.view.diff.name=0 +hex.diffing.view.diff.name=0 hex.disassembler.view.disassembler.name=0 hex.builtin.view.find.name=0 hex.hashes.view.hashes.name=0 diff --git a/plugins/builtin/source/content/views.cpp b/plugins/builtin/source/content/views.cpp index f970c6bc2..c6a92abb5 100644 --- a/plugins/builtin/source/content/views.cpp +++ b/plugins/builtin/source/content/views.cpp @@ -12,7 +12,6 @@ #include "content/views/view_data_processor.hpp" #include "content/views/view_constants.hpp" #include "content/views/view_store.hpp" -#include "content/views/view_diff.hpp" #include "content/views/view_provider_settings.hpp" #include "content/views/view_find.hpp" #include "content/views/view_theme_manager.hpp" @@ -38,7 +37,6 @@ namespace hex::plugin::builtin { ContentRegistry::Views::add(); ContentRegistry::Views::add(); ContentRegistry::Views::add(); - ContentRegistry::Views::add(); ContentRegistry::Views::add(); ContentRegistry::Views::add(); ContentRegistry::Views::add(); diff --git a/plugins/builtin/source/plugin_builtin.cpp b/plugins/builtin/source/plugin_builtin.cpp index fd27bc77a..7b1fcd575 100644 --- a/plugins/builtin/source/plugin_builtin.cpp +++ b/plugins/builtin/source/plugin_builtin.cpp @@ -71,7 +71,6 @@ IMHEX_PLUGIN_SUBCOMMANDS() { }; IMHEX_PLUGIN_SETUP("Built-in", "WerWolv", "Default ImHex functionality") { - using namespace hex::plugin::builtin; hex::log::debug("Using romfs: '{}'", romfs::name()); diff --git a/plugins/diffing/CMakeLists.txt b/plugins/diffing/CMakeLists.txt new file mode 100644 index 000000000..a42b88982 --- /dev/null +++ b/plugins/diffing/CMakeLists.txt @@ -0,0 +1,24 @@ +cmake_minimum_required(VERSION 3.16) + +include(ImHexPlugin) + +if (USE_SYSTEM_EDLIB) + find_package(edlib REQUIRED) +else() + add_subdirectory(${THIRD_PARTY_LIBS_FOLDER}/edlib ${CMAKE_CURRENT_BINARY_DIR}/edlib EXCLUDE_FROM_ALL) +endif() + +add_imhex_plugin( + NAME + diffing + SOURCES + source/plugin_diffing.cpp + + source/content/diffing_algorithms.cpp + source/content/views/view_diff.cpp + INCLUDES + include + LIBRARIES + ui + edlib +) \ No newline at end of file diff --git a/plugins/builtin/include/content/views/view_diff.hpp b/plugins/diffing/include/content/views/view_diff.hpp similarity index 77% rename from plugins/builtin/include/content/views/view_diff.hpp rename to plugins/diffing/include/content/views/view_diff.hpp index e8ff4ed99..fa50584a1 100644 --- a/plugins/builtin/include/content/views/view_diff.hpp +++ b/plugins/diffing/include/content/views/view_diff.hpp @@ -10,7 +10,7 @@ #include "ui/hex_editor.hpp" -namespace hex::plugin::builtin { +namespace hex::plugin::diffing { class ViewDiff : public View::Window { public: @@ -23,21 +23,12 @@ namespace hex::plugin::builtin { public: struct Column { ui::HexEditor hexEditor; + ContentRegistry::Diffing::DiffTree diffTree; + int provider = -1; i32 scrollLock = 0; }; - enum class DifferenceType : u8 { - Added, - Removed, - Modified - }; - - struct Diff { - Region region; - DifferenceType type; - }; - private: std::function(u64, const u8*, size_t)> createCompareFunction(size_t otherIndex) const; void analyze(prv::Provider *providerA, prv::Provider *providerB); @@ -45,9 +36,9 @@ namespace hex::plugin::builtin { private: std::array m_columns; - std::vector m_diffs; TaskHolder m_diffTask; std::atomic m_analyzed = false; + ContentRegistry::Diffing::Algorithm *m_algorithm = nullptr; }; } \ No newline at end of file diff --git a/plugins/diffing/romfs/lang/de_DE.json b/plugins/diffing/romfs/lang/de_DE.json new file mode 100644 index 000000000..ac811a635 --- /dev/null +++ b/plugins/diffing/romfs/lang/de_DE.json @@ -0,0 +1,14 @@ +{ + "code": "de-DE", + "language": "German", + "country": "Germany", + "fallback": false, + "translations": { + "hex.diffing.view.diff.name": "Diffing", + "hex.diffing.view.diff.added": "", + "hex.diffing.view.diff.modified": "", + "hex.diffing.view.diff.provider_a": "", + "hex.diffing.view.diff.provider_b": "", + "hex.diffing.view.diff.removed": "" + } +} \ No newline at end of file diff --git a/plugins/diffing/romfs/lang/en_US.json b/plugins/diffing/romfs/lang/en_US.json new file mode 100644 index 000000000..42f472b01 --- /dev/null +++ b/plugins/diffing/romfs/lang/en_US.json @@ -0,0 +1,21 @@ +{ + "code": "en-US", + "country": "United States", + "language": "English", + "translations": { + "hex.diffing.algorithm.simple.name": "Simple byte-by-byte algorithm", + "hex.diffing.algorithm.simple.description": "Naïve O(N) byte-by-byte comparison.\nCan only identify byte modifications and insertions / deletions at the end of the data", + "hex.diffing.algorithm.myers.name": "Myers's bit-vector algorithm", + "hex.diffing.algorithm.myers.description": "Smart O(N*M) diffing algorithm. Can identify modifications, insertions and deletions anywhere in the data", + "hex.diffing.algorithm.myers.settings.window_size": "Window size", + "hex.diffing.view.diff.name": "Diffing", + "hex.diffing.view.diff.added": "Added", + "hex.diffing.view.diff.modified": "Modified", + "hex.diffing.view.diff.provider_a": "Provider A", + "hex.diffing.view.diff.provider_b": "Provider B", + "hex.diffing.view.diff.removed": "Removed", + "hex.diffing.view.diff.algorithm": "Diffing Algorithm", + "hex.diffing.view.diff.settings": "No settings available", + "hex.diffing.view.diff.settings.no_settings": "No settings available" + } +} \ No newline at end of file diff --git a/plugins/diffing/romfs/lang/es_ES.json b/plugins/diffing/romfs/lang/es_ES.json new file mode 100644 index 000000000..d5465fd0b --- /dev/null +++ b/plugins/diffing/romfs/lang/es_ES.json @@ -0,0 +1,14 @@ +{ + "code": "es_ES", + "language": "Spanish", + "country": "Spain", + "fallback": false, + "translations": { + "hex.diffing.view.diff.name": "Análisis de diferencias", + "hex.diffing.view.diff.added": "Añadidas", + "hex.diffing.view.diff.modified": "Modificadas", + "hex.diffing.view.diff.provider_a": "Proveedor A", + "hex.diffing.view.diff.provider_b": "Proveedor B", + "hex.diffing.view.diff.removed": "Eliminados" + } +} \ No newline at end of file diff --git a/plugins/diffing/romfs/lang/it_IT.json b/plugins/diffing/romfs/lang/it_IT.json new file mode 100644 index 000000000..7bf95c1f1 --- /dev/null +++ b/plugins/diffing/romfs/lang/it_IT.json @@ -0,0 +1,14 @@ +{ + "code": "it-IT", + "language": "Italian", + "country": "Italy", + "fallback": false, + "translations": { + "hex.diffing.view.diff.name": "Diffing", + "hex.diffing.view.diff.added": "", + "hex.diffing.view.diff.modified": "", + "hex.diffing.view.diff.provider_a": "", + "hex.diffing.view.diff.provider_b": "", + "hex.diffing.view.diff.removed": "" + } +} \ No newline at end of file diff --git a/plugins/diffing/romfs/lang/ja_JP.json b/plugins/diffing/romfs/lang/ja_JP.json new file mode 100644 index 000000000..2f9a0544c --- /dev/null +++ b/plugins/diffing/romfs/lang/ja_JP.json @@ -0,0 +1,14 @@ +{ + "code": "ja-JP", + "language": "Japanese", + "country": "Japan", + "fallback": false, + "translations": { + "hex.diffing.view.diff.name": "比較", + "hex.diffing.view.diff.added": "", + "hex.diffing.view.diff.modified": "", + "hex.diffing.view.diff.provider_a": "", + "hex.diffing.view.diff.provider_b": "", + "hex.diffing.view.diff.removed": "" + } +} \ No newline at end of file diff --git a/plugins/diffing/romfs/lang/ko_KR.json b/plugins/diffing/romfs/lang/ko_KR.json new file mode 100644 index 000000000..e8ceae469 --- /dev/null +++ b/plugins/diffing/romfs/lang/ko_KR.json @@ -0,0 +1,14 @@ +{ + "code": "ko-KR", + "language": "Korean", + "country": "Korea", + "fallback": false, + "translations": { + "hex.diffing.view.diff.name": "파일 비교", + "hex.diffing.view.diff.added": "추가됨", + "hex.diffing.view.diff.modified": "수정됨", + "hex.diffing.view.diff.provider_a": "공급자 A", + "hex.diffing.view.diff.provider_b": "공급자 B", + "hex.diffing.view.diff.removed": "제거됨" + } +} \ No newline at end of file diff --git a/plugins/diffing/romfs/lang/pt_BR.json b/plugins/diffing/romfs/lang/pt_BR.json new file mode 100644 index 000000000..b192fd096 --- /dev/null +++ b/plugins/diffing/romfs/lang/pt_BR.json @@ -0,0 +1,14 @@ +{ + "code": "pt-BR", + "language": "Portuguese", + "country": "Brazil", + "fallback": false, + "translations": { + "hex.diffing.view.diff.name": "Diferenciando", + "hex.diffing.view.diff.added": "", + "hex.diffing.view.diff.modified": "", + "hex.diffing.view.diff.provider_a": "", + "hex.diffing.view.diff.provider_b": "", + "hex.diffing.view.diff.removed": "" + } +} \ No newline at end of file diff --git a/plugins/diffing/romfs/lang/zh_CN.json b/plugins/diffing/romfs/lang/zh_CN.json new file mode 100644 index 000000000..80c1d6767 --- /dev/null +++ b/plugins/diffing/romfs/lang/zh_CN.json @@ -0,0 +1,14 @@ +{ + "code": "zh-CN", + "language": "Chinese (Simplified)", + "country": "China", + "fallback": false, + "translations": { + "hex.diffing.view.diff.name": "差异", + "hex.diffing.view.diff.added": "添加", + "hex.diffing.view.diff.modified": "修改", + "hex.diffing.view.diff.provider_a": "提供者A", + "hex.diffing.view.diff.provider_b": "提供者B", + "hex.diffing.view.diff.removed": "移除" + } +} \ No newline at end of file diff --git a/plugins/diffing/romfs/lang/zh_TW.json b/plugins/diffing/romfs/lang/zh_TW.json new file mode 100644 index 000000000..872802b76 --- /dev/null +++ b/plugins/diffing/romfs/lang/zh_TW.json @@ -0,0 +1,14 @@ +{ + "code": "zh-TW", + "language": "Chinese (Traditional)", + "country": "Taiwan", + "fallback": false, + "translations": { + "hex.diffing.view.diff.name": "差異", + "hex.diffing.view.diff.added": "已新增", + "hex.diffing.view.diff.modified": "已修改", + "hex.diffing.view.diff.provider_a": "提供者 A", + "hex.diffing.view.diff.provider_b": "提供者 B", + "hex.diffing.view.diff.removed": "已移除" + } +} \ No newline at end of file diff --git a/plugins/diffing/source/content/diffing_algorithms.cpp b/plugins/diffing/source/content/diffing_algorithms.cpp new file mode 100644 index 000000000..278338719 --- /dev/null +++ b/plugins/diffing/source/content/diffing_algorithms.cpp @@ -0,0 +1,187 @@ +#include + +#include +#include + +#include +#include + +#include +#include +#include + +namespace hex::plugin::diffing { + + using namespace ContentRegistry::Diffing; + using namespace wolv::literals; + + class AlgorithmSimple : public Algorithm { + public: + AlgorithmSimple() : Algorithm("hex.diffing.algorithm.simple.name", "hex.diffing.algorithm.simple.description") {} + + [[nodiscard]] std::vector analyze(prv::Provider *providerA, prv::Provider *providerB) const override { + wolv::container::IntervalTree differences; + + // Set up readers for both providers + auto readerA = prv::ProviderReader(providerA); + auto readerB = prv::ProviderReader(providerB); + + auto &task = TaskManager::getCurrentTask(); + + // Iterate over both providers and compare the bytes + for (auto itA = readerA.begin(), itB = readerB.begin(); itA < readerA.end() && itB < readerB.end(); ++itA, ++itB) { + // Stop comparing if the diff task was canceled + if (task.wasInterrupted()) + break; + + // If the bytes are different, find the end of the difference + if (*itA != *itB) { + u64 start = itA.getAddress(); + size_t size = 0; + + while (itA != readerA.end() && itB != readerB.end() && *itA != *itB) { + ++itA; + ++itB; + ++size; + } + + // Add the difference to the list + differences.emplace({ start, (start + size) - 1 }, DifferenceType::Mismatch); + } + + // Update the progress bar + task.update(itA.getAddress()); + } + + auto otherDifferences = differences; + + // If one provider is larger than the other, add the extra bytes to the list + if (providerA->getActualSize() != providerB->getActualSize()) { + auto endA = providerA->getActualSize() + 1; + auto endB = providerB->getActualSize() + 1; + + if (endA > endB) { + differences.emplace({ endB, endA }, DifferenceType::Insertion); + otherDifferences.emplace({ endB, endA }, DifferenceType::Deletion); + } + else { + differences.emplace({ endA, endB }, DifferenceType::Insertion); + otherDifferences.emplace({ endB, endA }, DifferenceType::Insertion); + } + } + + return { differences, otherDifferences }; + } + }; + + class AlgorithmMyers : public Algorithm { + public: + AlgorithmMyers() : Algorithm("hex.diffing.algorithm.myers.name", "hex.diffing.algorithm.myers.description") {} + + [[nodiscard]] std::vector analyze(prv::Provider *providerA, prv::Provider *providerB) const override { + DiffTree differencesA, differencesB; + + EdlibAlignConfig edlibConfig; + edlibConfig.k = -1; + edlibConfig.additionalEqualities = nullptr; + edlibConfig.additionalEqualitiesLength = 0; + edlibConfig.mode = EdlibAlignMode::EDLIB_MODE_NW; + edlibConfig.task = EdlibAlignTask::EDLIB_TASK_PATH; + + const auto windowStart = std::min(providerA->getBaseAddress(), providerB->getBaseAddress()); + const auto windowEnd = std::max(providerA->getBaseAddress() + providerA->getActualSize(), providerB->getBaseAddress() + providerB->getActualSize()); + + auto &task = TaskManager::getCurrentTask(); + + for (u64 address = windowStart; address < windowEnd; address += m_windowSize) { + if (task.wasInterrupted()) + break; + + auto currWindowSizeA = std::min(m_windowSize, providerA->getActualSize() - address); + auto currWindowSizeB = std::min(m_windowSize, providerB->getActualSize() - address); + std::vector dataA(currWindowSizeA), dataB(currWindowSizeB); + + providerA->read(address, dataA.data(), dataA.size()); + providerB->read(address, dataB.data(), dataB.size()); + + EdlibAlignResult result = edlibAlign( + reinterpret_cast(dataA.data()), dataA.size(), + reinterpret_cast(dataB.data()), dataB.size(), + edlibConfig + ); + + auto currentOperation = DifferenceType(0xFF); + Region regionA = {}, regionB = {}; + u64 currentAddressA = 0x00, currentAddressB = 0x00; + + const auto insertDifference = [&] { + switch (currentOperation) { + using enum DifferenceType; + + case Match: + break; + case Mismatch: + differencesA.insert({ regionA.getStartAddress(), regionA.getEndAddress() }, Mismatch); + differencesB.insert({ regionB.getStartAddress(), regionB.getEndAddress() }, Mismatch); + break; + case Insertion: + differencesA.insert({ regionA.getStartAddress(), regionA.getEndAddress() }, Insertion); + differencesB.insert({ regionB.getStartAddress(), regionB.getEndAddress() }, Insertion); + currentAddressB -= regionA.size; + break; + case Deletion: + differencesA.insert({ regionA.getStartAddress(), regionA.getEndAddress() }, Deletion); + differencesB.insert({ regionB.getStartAddress(), regionB.getEndAddress() }, Deletion); + currentAddressA -= regionB.size; + break; + } + }; + + for (const u8 alignmentType : std::span(result.alignment, result.alignmentLength)) { + ON_SCOPE_EXIT { + currentAddressA++; + currentAddressB++; + }; + + if (currentOperation == DifferenceType(alignmentType)) { + regionA.size++; + regionB.size++; + + continue; + } else if (currentOperation != DifferenceType(0xFF)) { + insertDifference(); + + currentOperation = DifferenceType(0xFF); + } + + currentOperation = DifferenceType(alignmentType); + regionA.address = currentAddressA; + regionB.address = currentAddressB; + regionA.size = 1; + regionB.size = 1; + } + + insertDifference(); + + task.update(address); + } + + + return { differencesA, differencesB }; + } + + void drawSettings() override { + static u64 min = 32_kiB, max = 128_kiB; + ImGui::SliderScalar("hex.diffing.algorithm.myers.settings.window_size"_lang, ImGuiDataType_U64, &m_windowSize, &min, &max, "0x%X"); + } + + private: + u64 m_windowSize = 64_kiB; + }; + + void registerDiffingAlgorithms() { + ContentRegistry::Diffing::addAlgorithm(); + ContentRegistry::Diffing::addAlgorithm(); + } + +} diff --git a/plugins/builtin/source/content/views/view_diff.cpp b/plugins/diffing/source/content/views/view_diff.cpp similarity index 59% rename from plugins/builtin/source/content/views/view_diff.cpp rename to plugins/diffing/source/content/views/view_diff.cpp index 8ced1d5be..e86bb7051 100644 --- a/plugins/builtin/source/content/views/view_diff.cpp +++ b/plugins/diffing/source/content/views/view_diff.cpp @@ -4,27 +4,21 @@ #include #include +#include -namespace hex::plugin::builtin { +namespace hex::plugin::diffing { - namespace { - - constexpr u32 getDiffColor(u32 color) { - return (color & 0x00FFFFFF) | 0x40000000; - } - - } - - ViewDiff::ViewDiff() : View::Window("hex.builtin.view.diff.name", ICON_VS_DIFF_SIDEBYSIDE) { + using DifferenceType = ContentRegistry::Diffing::DifferenceType; + ViewDiff::ViewDiff() : View::Window("hex.diffing.view.diff.name", ICON_VS_DIFF_SIDEBYSIDE) { // Clear the selected diff providers when a provider is closed EventProviderClosed::subscribe(this, [this](prv::Provider *) { - for (u8 i = 0; i < 2; i++) { - m_columns[i].provider = -1; - m_columns[i].hexEditor.setSelectionUnchecked(std::nullopt, std::nullopt); + for (auto &column : m_columns) { + column.provider = -1; + column.hexEditor.setSelectionUnchecked(std::nullopt, std::nullopt); + column.diffTree.clear(); } - m_diffs.clear(); }); // Set the background highlight callbacks for the two hex editor columns @@ -39,8 +33,12 @@ namespace hex::plugin::builtin { namespace { bool drawDiffColumn(ViewDiff::Column &column, float height) { + if (height < 0) + return false; + bool scrolled = false; ImGui::PushID(&column); + ON_SCOPE_EXIT { ImGui::PopID(); }; // Draw the hex editor float prevScroll = column.hexEditor.getScrollPosition(); @@ -53,8 +51,6 @@ namespace hex::plugin::builtin { column.scrollLock = 5; } - ImGui::PopID(); - return scrolled; } @@ -94,94 +90,44 @@ namespace hex::plugin::builtin { } - std::function(u64, const u8*, size_t)> ViewDiff::createCompareFunction(size_t otherIndex) const { - // Create a function that will handle highlighting the differences between the two providers - // This is a stupidly simple diffing implementation. It will highlight bytes that are different in yellow - // and if one provider is larger than the other it will highlight the extra bytes in green or red depending on which provider is larger - // TODO: Use an actual binary diffing algorithm that searches for the longest common subsequences - - return [this, otherIndex](u64 address, const u8 *data, size_t) -> std::optional { - const auto &providers = ImHexApi::Provider::getProviders(); - auto otherId = m_columns[otherIndex].provider; - - // Check if the other provider is valid - if (otherId < 0 || size_t(otherId) >= providers.size()) - return std::nullopt; - - auto &otherProvider = providers[otherId]; - - // Handle the case where one provider is larger than the other one - if ((address - otherProvider->getBaseAddress()) > otherProvider->getActualSize()) { - if (otherIndex == 1) - return getDiffColor(ImGuiExt::GetCustomColorU32(ImGuiCustomCol_DiffAdded)); - else - return getDiffColor(ImGuiExt::GetCustomColorU32(ImGuiCustomCol_DiffRemoved)); - } - - // Read the current byte from the other provider - u8 otherByte = 0x00; - otherProvider->read(address, &otherByte, 1); - - // Compare the two bytes, highlight both in yellow if they are different - if (otherByte != *data) - return getDiffColor(ImGuiExt::GetCustomColorU32(ImGuiCustomCol_DiffChanged)); - - // No difference - return std::nullopt; - }; - } - void ViewDiff::analyze(prv::Provider *providerA, prv::Provider *providerB) { auto commonSize = std::min(providerA->getActualSize(), providerB->getActualSize()); - m_diffTask = TaskManager::createTask("Diffing...", commonSize, [this, providerA, providerB](Task &task) { - std::vector differences; - - // Set up readers for both providers - auto readerA = prv::ProviderReader(providerA); - auto readerB = prv::ProviderReader(providerB); - - // Iterate over both providers and compare the bytes - for (auto itA = readerA.begin(), itB = readerB.begin(); itA < readerA.end() && itB < readerB.end(); ++itA, ++itB) { - // Stop comparing if the diff task was canceled - if (task.wasInterrupted()) - break; - - // If the bytes are different, find the end of the difference - if (*itA != *itB) { - u64 start = itA.getAddress(); - size_t end = 0; - - while (itA != readerA.end() && itB != readerB.end() && *itA != *itB) { - ++itA; - ++itB; - ++end; - } - - // Add the difference to the list - differences.push_back(Diff { Region{ start, end }, ViewDiff::DifferenceType::Modified }); - } - - // Update the progress bar - task.update(itA.getAddress()); - } - - // If one provider is larger than the other, add the extra bytes to the list - if (providerA->getActualSize() != providerB->getActualSize()) { - auto endA = providerA->getActualSize() + 1; - auto endB = providerB->getActualSize() + 1; - - if (endA > endB) - differences.push_back(Diff { Region{ endB, endA - endB }, ViewDiff::DifferenceType::Added }); - else - differences.push_back(Diff { Region{ endA, endB - endA }, ViewDiff::DifferenceType::Removed }); - } + m_diffTask = TaskManager::createTask("Diffing...", commonSize, [this, providerA, providerB](Task &) { + auto differences = m_algorithm->analyze(providerA, providerB); // Move the calculated differences over so they can be displayed - m_diffs = std::move(differences); + for (size_t i = 0; i < m_columns.size(); i++) { + auto &column = m_columns[i]; + column.diffTree = std::move(differences[i]); + } m_analyzed = true; }); } + std::function(u64, const u8*, size_t)> ViewDiff::createCompareFunction(size_t otherIndex) const { + const auto currIndex = otherIndex == 0 ? 1 : 0; + return [=, this](u64 address, const u8 *, size_t size) -> std::optional { + if (!m_analyzed) + return std::nullopt; + + const auto matches = m_columns[currIndex].diffTree.overlapping({ address, (address + size) - 1 }); + if (matches.empty()) + return std::nullopt; + + const auto type = matches[0].value; + + if (type == DifferenceType::Mismatch) { + return ImGuiExt::GetCustomColorU32(ImGuiCustomCol_DiffChanged); + } else if (type == DifferenceType::Insertion && currIndex == 0) { + return ImGuiExt::GetCustomColorU32(ImGuiCustomCol_DiffAdded); + } else if (type == DifferenceType::Deletion && currIndex == 1) { + return ImGuiExt::GetCustomColorU32(ImGuiCustomCol_DiffRemoved); + } + + return std::nullopt; + }; + } + void ViewDiff::drawContent() { auto &[a, b] = m_columns; @@ -206,7 +152,7 @@ namespace hex::plugin::builtin { } // Analyze the providers if they are valid and the user selected a new provider - if (!m_analyzed && a.provider != -1 && b.provider != -1 && !m_diffTask.isRunning()) { + if (!m_analyzed && a.provider != -1 && b.provider != -1 && !m_diffTask.isRunning() && m_algorithm != nullptr) { const auto &providers = ImHexApi::Provider::getProviders(); auto providerA = providers[a.provider]; auto providerB = providers[b.provider]; @@ -214,18 +160,29 @@ namespace hex::plugin::builtin { this->analyze(providerA, providerB); } + if (auto &algorithms = ContentRegistry::Diffing::impl::getAlgorithms(); m_algorithm == nullptr && !algorithms.empty()) + m_algorithm = algorithms.front().get(); + const auto height = ImGui::GetContentRegionAvail().y; // Draw the two hex editor columns side by side if (ImGui::BeginTable("##binary_diff", 2, ImGuiTableFlags_None, ImVec2(0, height - 250_scaled))) { - ImGui::TableSetupColumn("hex.builtin.view.diff.provider_a"_lang); - ImGui::TableSetupColumn("hex.builtin.view.diff.provider_b"_lang); + ImGui::TableSetupColumn("hex.diffing.view.diff.provider_a"_lang); + ImGui::TableSetupColumn("hex.diffing.view.diff.provider_b"_lang); ImGui::TableHeadersRow(); + ImVec2 buttonPos; ImGui::BeginDisabled(m_diffTask.isRunning()); { - // Draw first provider selector + // Draw settings button ImGui::TableNextColumn(); + if (ImGuiExt::DimmedIconButton(ICON_VS_SETTINGS_GEAR, ImGui::GetStyleColorVec4(ImGuiCol_Text))) + ImGui::OpenPopup("DiffingAlgorithmSettings"); + buttonPos = ImGui::GetCursorScreenPos(); + + ImGui::SameLine(); + + // Draw first provider selector if (drawProviderSelector(a)) m_analyzed = false; // Draw second provider selector @@ -234,6 +191,41 @@ namespace hex::plugin::builtin { } ImGui::EndDisabled(); + ImGui::SetNextWindowPos(buttonPos); + if (ImGui::BeginPopup("DiffingAlgorithmSettings")) { + ImGuiExt::Header("hex.diffing.view.diff.algorithm"_lang, true); + ImGui::PushItemWidth(300_scaled); + if (ImGui::BeginCombo("##Algorithm", m_algorithm == nullptr ? "" : Lang(m_algorithm->getUnlocalizedName()))) { + for (const auto &algorithm : ContentRegistry::Diffing::impl::getAlgorithms()) { + ImGui::PushID(algorithm.get()); + if (ImGui::Selectable(Lang(algorithm->getUnlocalizedName()))) { + m_algorithm = algorithm.get(); + m_analyzed = false; + } + ImGui::PopID(); + } + ImGui::EndCombo(); + } + ImGui::PopItemWidth(); + + if (m_algorithm != nullptr) { + ImGuiExt::TextFormattedWrapped("{}", Lang(m_algorithm->getUnlocalizedDescription())); + } + + ImGuiExt::Header("hex.diffing.view.diff.settings"_lang); + if (m_algorithm != nullptr) { + auto drawList = ImGui::GetWindowDrawList(); + auto prevIdx = drawList->_VtxCurrentIdx; + m_algorithm->drawSettings(); + auto currIdx = drawList->_VtxCurrentIdx; + + if (prevIdx == currIdx) + ImGuiExt::TextFormatted("hex.diffing.view.diff.settings.no_settings"_lang); + } + + ImGui::EndPopup(); + } + ImGui::TableNextRow(); // Draw first hex editor column @@ -270,55 +262,70 @@ namespace hex::plugin::builtin { // Draw the differences if the providers have been analyzed if (m_analyzed) { ImGuiListClipper clipper; - clipper.Begin(int(m_diffs.size())); - while (clipper.Step()) + auto &diffTreeA = m_columns[0].diffTree; + auto &diffTreeB = m_columns[1].diffTree; + clipper.Begin(int(diffTreeA.size())); + + auto diffIterA = diffTreeA.begin(); + auto diffIterB = diffTreeB.begin(); + while (clipper.Step()) { for (int i = clipper.DisplayStart; i < clipper.DisplayEnd; i++) { ImGui::TableNextRow(); // Prevent the list from trying to access non-existing diffs - if (size_t(i) >= m_diffs.size()) + if (size_t(i) >= diffTreeA.size()) break; ImGui::PushID(i); - const auto &diff = m_diffs[i]; + const auto &[startA, restA] = *diffIterA; + const auto &[endA, typeA] = restA; + + const auto &[startB, restB] = *diffIterB; + const auto &[endB, typeB] = restB; + + std::advance(diffIterA, 1); + std::advance(diffIterB, 1); // Draw a clickable row for each difference that will select the difference in both hex editors // Draw start address ImGui::TableNextColumn(); - if (ImGui::Selectable(hex::format("0x{:02X}", diff.region.getStartAddress()).c_str(), false, ImGuiSelectableFlags_SpanAllColumns)) { - a.hexEditor.setSelection(diff.region); + if (ImGui::Selectable(hex::format("0x{:02X}", startA).c_str(), false, ImGuiSelectableFlags_SpanAllColumns)) { + a.hexEditor.setSelection({ startA, ((endA - startA) + 1) }); a.hexEditor.jumpToSelection(); - b.hexEditor.setSelection(diff.region); + b.hexEditor.setSelection({ startB, ((endB - startB) + 1) }); b.hexEditor.jumpToSelection(); } // Draw end address ImGui::TableNextColumn(); - ImGui::TextUnformatted(hex::format("0x{:02X}", diff.region.getEndAddress()).c_str()); + ImGui::TextUnformatted(hex::format("0x{:02X}", endA).c_str()); // Draw difference type ImGui::TableNextColumn(); - switch (diff.type) { - case DifferenceType::Modified: - ImGuiExt::TextFormattedColored(ImGuiExt::GetCustomColorVec4(ImGuiCustomCol_DiffChanged), "hex.builtin.view.diff.modified"_lang); + switch (typeA) { + case DifferenceType::Mismatch: + ImGuiExt::TextFormattedColored(ImGuiExt::GetCustomColorVec4(ImGuiCustomCol_DiffChanged), "hex.diffing.view.diff.modified"_lang); break; - case DifferenceType::Added: - ImGuiExt::TextFormattedColored(ImGuiExt::GetCustomColorVec4(ImGuiCustomCol_DiffAdded), "hex.builtin.view.diff.added"_lang); + case DifferenceType::Insertion: + ImGuiExt::TextFormattedColored(ImGuiExt::GetCustomColorVec4(ImGuiCustomCol_DiffAdded), "hex.diffing.view.diff.added"_lang); break; - case DifferenceType::Removed: - ImGuiExt::TextFormattedColored(ImGuiExt::GetCustomColorVec4(ImGuiCustomCol_DiffRemoved), "hex.builtin.view.diff.removed"_lang); + case DifferenceType::Deletion: + ImGuiExt::TextFormattedColored(ImGuiExt::GetCustomColorVec4(ImGuiCustomCol_DiffRemoved), "hex.diffing.view.diff.removed"_lang); + break; + default: break; } ImGui::PopID(); } + } } ImGui::EndTable(); } } -} \ No newline at end of file +} diff --git a/plugins/diffing/source/plugin_diffing.cpp b/plugins/diffing/source/plugin_diffing.cpp new file mode 100644 index 000000000..5a190701d --- /dev/null +++ b/plugins/diffing/source/plugin_diffing.cpp @@ -0,0 +1,27 @@ +#include + +#include +#include + +#include + +#include "content/views/view_diff.hpp" + + +namespace hex::plugin::diffing { + + void registerDiffingAlgorithms(); + +} + +using namespace hex; +using namespace hex::plugin::diffing; + +IMHEX_PLUGIN_SETUP("Diffing", "WerWolv", "Support for diffing data") { + hex::log::debug("Using romfs: '{}'", romfs::name()); + + registerDiffingAlgorithms(); + + ContentRegistry::Views::add(); + +} \ No newline at end of file diff --git a/plugins/ui/source/ui/hex_editor.cpp b/plugins/ui/source/ui/hex_editor.cpp index f29cd7f54..533f7ae61 100644 --- a/plugins/ui/source/ui/hex_editor.cpp +++ b/plugins/ui/source/ui/hex_editor.cpp @@ -48,6 +48,7 @@ namespace hex::ui { }; ImGui::PushID(reinterpret_cast(address)); + ON_SCOPE_EXIT { ImGui::PopID(); }; char buffer[2] = { std::isprint(data[0]) ? char(data[0]) : '.', 0x00 }; ImGui::InputText("##editing_input", buffer, 2, TextInputFlags | ImGuiInputTextFlags_CallbackEdit, [](ImGuiInputTextCallbackData *data) -> int { auto &userData = *static_cast(data->UserData); @@ -59,7 +60,6 @@ namespace hex::ui { return 0; }, &userData); - ImGui::PopID(); return userData.editingDone || ImGui::IsKeyPressed(ImGuiKey_Enter) || ImGui::IsKeyPressed(ImGuiKey_Escape); } else { @@ -326,8 +326,8 @@ namespace hex::ui { ImGui::GetWindowScrollbarID(window, axis), axis, &m_scrollPosition.get(), - (std::ceil(innerRect.Max.y - innerRect.Min.y) / CharacterSize.y) - (m_visibleRowCount - 1), - std::nextafterf(numRows, std::numeric_limits::max()), + (std::ceil(innerRect.Max.y - innerRect.Min.y) / CharacterSize.y), + std::nextafterf(numRows + ImGui::GetWindowSize().y / CharacterSize.y, std::numeric_limits::max()), roundingCorners); } @@ -608,6 +608,7 @@ namespace hex::ui { ImGui::PushStyleVar(ImGuiStyleVar_CellPadding, ImVec2(0, 0)); ImGui::PushID(y); + ON_SCOPE_EXIT { ImGui::PopID(); }; if (ImGui::BeginTable("##encoding_cell", encodingData.size(), ImGuiTableFlags_SizingFixedFit | ImGuiTableFlags_NoKeepColumnsVisible)) { ImGui::TableNextRow(); @@ -642,7 +643,6 @@ namespace hex::ui { ImGui::EndTable(); } ImGui::PopStyleVar(); - ImGui::PopID(); } } @@ -711,19 +711,19 @@ namespace hex::ui { } void HexEditor::drawFooter(const ImVec2 &size) { - if (m_provider != nullptr && m_provider->isReadable()) { - const auto pageCount = std::max(1, m_provider->getPageCount()); - constexpr static u32 MinPage = 1; + const auto windowEndPos = ImGui::GetWindowPos() + size - ImGui::GetStyle().WindowPadding; + ImGui::GetWindowDrawList()->AddLine(windowEndPos - ImVec2(0, size.y - 1_scaled), windowEndPos - size + ImVec2(0, 1_scaled), ImGui::GetColorU32(ImGuiCol_Separator), 2.0_scaled); - const auto windowEndPos = ImGui::GetWindowPos() + size - ImGui::GetStyle().WindowPadding; - ImGui::GetWindowDrawList()->AddLine(windowEndPos - ImVec2(0, size.y - 1_scaled), windowEndPos - size + ImVec2(0, 1_scaled), ImGui::GetColorU32(ImGuiCol_Separator), 2.0_scaled); + if (ImGui::BeginChild("##footer", size, false, ImGuiWindowFlags_NoScrollbar | ImGuiWindowFlags_NoScrollWithMouse)) { + if (ImGui::BeginTable("##footer_table", 3, ImGuiTableFlags_SizingFixedFit)) { + ImGui::TableSetupColumn("Left", ImGuiTableColumnFlags_WidthStretch, 0.5f); + ImGui::TableSetupColumn("Center", ImGuiTableColumnFlags_WidthFixed, 20_scaled); + ImGui::TableSetupColumn("Right", ImGuiTableColumnFlags_WidthStretch, 0.5F); + ImGui::TableNextRow(); - if (ImGui::BeginChild("##footer", size, false, ImGuiWindowFlags_NoScrollbar | ImGuiWindowFlags_NoScrollWithMouse)) { - if (ImGui::BeginTable("##footer_table", 3, ImGuiTableFlags_SizingFixedFit)) { - ImGui::TableSetupColumn("Left", ImGuiTableColumnFlags_WidthStretch, 0.5f); - ImGui::TableSetupColumn("Center", ImGuiTableColumnFlags_WidthFixed, 20_scaled); - ImGui::TableSetupColumn("Right", ImGuiTableColumnFlags_WidthStretch, 0.5F); - ImGui::TableNextRow(); + if (m_provider != nullptr && m_provider->isReadable()) { + const auto pageCount = std::max(1, m_provider->getPageCount()); + constexpr static u32 MinPage = 1; // Page slider ImGui::TableNextColumn(); @@ -898,12 +898,12 @@ namespace hex::ui { ImGui::PopItemWidth(); } } - - ImGui::EndTable(); } + + ImGui::EndTable(); } - ImGui::EndChild(); } + ImGui::EndChild(); } void HexEditor::handleSelection(u64 address, u32 bytesPerCell, const u8 *data, bool cellHovered) {