From b580691871a8c80743d75ea4d6b1896c6ed57e15 Mon Sep 17 00:00:00 2001 From: WerWolv Date: Fri, 12 Aug 2022 15:11:27 +0200 Subject: [PATCH] feat: Added Intel Hex and Motorola SREC provider (#670) * feat: Initial implementation of an Intel Hex provider * fix: Reading of bytes from intel hex files * lang: Added localization for new provider * ui: Only show file name in intel hex provider name * feat: Added Motorola SREC provider --- lib/external/intervaltree/CMakeLists.txt | 9 + lib/external/intervaltree/LICENSE | 19 + lib/external/intervaltree/README.md | 37 ++ .../intervaltree/include/IntervalTree.h | 325 ++++++++++++++++++ lib/external/pattern_language | 2 +- lib/libimhex/CMakeLists.txt | 5 +- .../include/hex/providers/provider.hpp | 3 + lib/libimhex/source/providers/provider.cpp | 8 + main/source/window/win_window.cpp | 17 + plugins/builtin/CMakeLists.txt | 2 + .../content/providers/disk_provider.hpp | 2 +- .../content/providers/file_provider.hpp | 7 +- .../content/providers/gdb_provider.hpp | 2 +- .../content/providers/intel_hex_provider.hpp | 50 +++ .../providers/motorola_srec_provider.hpp | 27 ++ plugins/builtin/source/content/events.cpp | 53 ++- plugins/builtin/source/content/providers.cpp | 4 + .../content/providers/disk_provider.cpp | 4 - .../content/providers/file_provider.cpp | 14 +- .../source/content/providers/gdb_provider.cpp | 5 - .../content/providers/intel_hex_provider.cpp | 235 +++++++++++++ .../providers/motorola_srec_provider.cpp | 216 ++++++++++++ .../content/views/view_provider_settings.cpp | 1 - .../builtin/source/content/welcome_screen.cpp | 4 +- plugins/builtin/source/lang/de_DE.cpp | 25 +- plugins/builtin/source/lang/en_US.cpp | 15 +- plugins/builtin/source/lang/it_IT.cpp | 15 +- plugins/builtin/source/lang/ja_JP.cpp | 15 +- plugins/builtin/source/lang/pt_BR.cpp | 15 +- plugins/builtin/source/lang/zh_CN.cpp | 15 +- plugins/builtin/source/lang/zh_TW.cpp | 15 +- 31 files changed, 1062 insertions(+), 104 deletions(-) create mode 100644 lib/external/intervaltree/CMakeLists.txt create mode 100644 lib/external/intervaltree/LICENSE create mode 100644 lib/external/intervaltree/README.md create mode 100644 lib/external/intervaltree/include/IntervalTree.h create mode 100644 plugins/builtin/include/content/providers/intel_hex_provider.hpp create mode 100644 plugins/builtin/include/content/providers/motorola_srec_provider.hpp create mode 100644 plugins/builtin/source/content/providers/intel_hex_provider.cpp create mode 100644 plugins/builtin/source/content/providers/motorola_srec_provider.cpp diff --git a/lib/external/intervaltree/CMakeLists.txt b/lib/external/intervaltree/CMakeLists.txt new file mode 100644 index 000000000..34c56b077 --- /dev/null +++ b/lib/external/intervaltree/CMakeLists.txt @@ -0,0 +1,9 @@ +cmake_minimum_required(VERSION 3.16) +project(intervaltree) + +set(CMAKE_CXX_STANDARD20) + +add_library(intervaltree INTERFACE) + +target_include_directories(intervaltree INTERFACE include) +target_compile_options(intervaltree INTERFACE "-DUSE_INTERVAL_TREE_NAMESPACE") \ No newline at end of file diff --git a/lib/external/intervaltree/LICENSE b/lib/external/intervaltree/LICENSE new file mode 100644 index 000000000..be6b5b5ac --- /dev/null +++ b/lib/external/intervaltree/LICENSE @@ -0,0 +1,19 @@ +Copyright (c) 2011 Erik Garrison + +Permission is hereby granted, free of charge, to any person obtaining a copy of +this software and associated documentation files (the "Software"), to deal in +the Software without restriction, including without limitation the rights to +use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies +of the Software, and to permit persons to whom the Software is furnished to do +so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. diff --git a/lib/external/intervaltree/README.md b/lib/external/intervaltree/README.md new file mode 100644 index 000000000..ed000d024 --- /dev/null +++ b/lib/external/intervaltree/README.md @@ -0,0 +1,37 @@ +# intervaltree + +## Overview + +An interval tree can be used to efficiently find a set of numeric intervals overlapping or containing another interval. + +This library provides a basic implementation of an interval tree using C++ templates, allowing the insertion of arbitrary types into the tree. + +## Usage + +Add `#include "IntervalTree.h"` to the source files in which you will use the interval tree. + +To make an IntervalTree to contain objects of class T, use: + +```c++ +vector > intervals; +T a, b, c; +intervals.push_back(Interval(2, 10, a)); +intervals.push_back(Interval(3, 4, b)); +intervals.push_back(Interval(20, 100, c)); +IntervalTree tree; +tree = IntervalTree(intervals); +``` + +Now, it's possible to query the tree and obtain a set of intervals which are contained within the start and stop coordinates. + +```c++ +vector > results; +tree.findContained(start, stop, results); +cout << "found " << results.size() << " overlapping intervals" << endl; +``` + +The function IntervalTree::findOverlapping provides a method to find all those intervals which are contained or partially overlap the interval (start, stop). + +### Author: Erik Garrison + +### License: MIT diff --git a/lib/external/intervaltree/include/IntervalTree.h b/lib/external/intervaltree/include/IntervalTree.h new file mode 100644 index 000000000..701e45933 --- /dev/null +++ b/lib/external/intervaltree/include/IntervalTree.h @@ -0,0 +1,325 @@ +#ifndef __INTERVAL_TREE_H +#define __INTERVAL_TREE_H + +#include +#include +#include +#include +#include +#include + +#ifdef USE_INTERVAL_TREE_NAMESPACE +namespace interval_tree { +#endif +template +class Interval { +public: + Scalar start; + Scalar stop; + Value value; + Interval(const Scalar& s, const Scalar& e, const Value& v) + : start(std::min(s, e)) + , stop(std::max(s, e)) + , value(v) + {} +}; + +template +Value intervalStart(const Interval& i) { + return i.start; +} + +template +Value intervalStop(const Interval& i) { + return i.stop; +} + +template +std::ostream& operator<<(std::ostream& out, const Interval& i) { + out << "Interval(" << i.start << ", " << i.stop << "): " << i.value; + return out; +} + +template +class IntervalTree { +public: + typedef Interval interval; + typedef std::vector interval_vector; + + + struct IntervalStartCmp { + bool operator()(const interval& a, const interval& b) { + return a.start < b.start; + } + }; + + struct IntervalStopCmp { + bool operator()(const interval& a, const interval& b) { + return a.stop < b.stop; + } + }; + + IntervalTree() + : left(nullptr) + , right(nullptr) + , center(0) + {} + + ~IntervalTree() = default; + + std::unique_ptr clone() const { + return std::unique_ptr(new IntervalTree(*this)); + } + + IntervalTree(const IntervalTree& other) + : intervals(other.intervals), + left(other.left ? other.left->clone() : nullptr), + right(other.right ? other.right->clone() : nullptr), + center(other.center) + {} + + IntervalTree& operator=(IntervalTree&&) = default; + IntervalTree(IntervalTree&&) = default; + + IntervalTree& operator=(const IntervalTree& other) { + center = other.center; + intervals = other.intervals; + left = other.left ? other.left->clone() : nullptr; + right = other.right ? other.right->clone() : nullptr; + return *this; + } + + IntervalTree( + interval_vector&& ivals, + std::size_t depth = 16, + std::size_t minbucket = 64, + std::size_t maxbucket = 512, + Scalar leftextent = 0, + Scalar rightextent = 0) + : left(nullptr) + , right(nullptr) + { + --depth; + const auto minmaxStop = std::minmax_element(ivals.begin(), ivals.end(), + IntervalStopCmp()); + const auto minmaxStart = std::minmax_element(ivals.begin(), ivals.end(), + IntervalStartCmp()); + if (!ivals.empty()) { + center = (minmaxStart.first->start + minmaxStop.second->stop) / 2; + } + if (leftextent == 0 && rightextent == 0) { + // sort intervals by start + std::sort(ivals.begin(), ivals.end(), IntervalStartCmp()); + } else { + assert(std::is_sorted(ivals.begin(), ivals.end(), IntervalStartCmp())); + } + if (depth == 0 || (ivals.size() < minbucket && ivals.size() < maxbucket)) { + std::sort(ivals.begin(), ivals.end(), IntervalStartCmp()); + intervals = std::move(ivals); + assert(is_valid().first); + return; + } else { + Scalar leftp = 0; + Scalar rightp = 0; + + if (leftextent || rightextent) { + leftp = leftextent; + rightp = rightextent; + } else { + leftp = ivals.front().start; + rightp = std::max_element(ivals.begin(), ivals.end(), + IntervalStopCmp())->stop; + } + + interval_vector lefts; + interval_vector rights; + + for (typename interval_vector::const_iterator i = ivals.begin(); + i != ivals.end(); ++i) { + const interval& interval = *i; + if (interval.stop < center) { + lefts.push_back(interval); + } else if (interval.start > center) { + rights.push_back(interval); + } else { + assert(interval.start <= center); + assert(center <= interval.stop); + intervals.push_back(interval); + } + } + + if (!lefts.empty()) { + left.reset(new IntervalTree(std::move(lefts), + depth, minbucket, maxbucket, + leftp, center)); + } + if (!rights.empty()) { + right.reset(new IntervalTree(std::move(rights), + depth, minbucket, maxbucket, + center, rightp)); + } + } + assert(is_valid().first); + } + + // Call f on all intervals near the range [start, stop]: + template + void visit_near(const Scalar& start, const Scalar& stop, UnaryFunction f) const { + if (!intervals.empty() && ! (stop < intervals.front().start)) { + for (auto & i : intervals) { + f(i); + } + } + if (left && start <= center) { + left->visit_near(start, stop, f); + } + if (right && stop >= center) { + right->visit_near(start, stop, f); + } + } + + // Call f on all intervals crossing pos + template + void visit_overlapping(const Scalar& pos, UnaryFunction f) const { + visit_overlapping(pos, pos, f); + } + + // Call f on all intervals overlapping [start, stop] + template + void visit_overlapping(const Scalar& start, const Scalar& stop, UnaryFunction f) const { + auto filterF = [&](const interval& interval) { + if (interval.stop >= start && interval.start <= stop) { + // Only apply f if overlapping + f(interval); + } + }; + visit_near(start, stop, filterF); + } + + // Call f on all intervals contained within [start, stop] + template + void visit_contained(const Scalar& start, const Scalar& stop, UnaryFunction f) const { + auto filterF = [&](const interval& interval) { + if (start <= interval.start && interval.stop <= stop) { + f(interval); + } + }; + visit_near(start, stop, filterF); + } + + interval_vector findOverlapping(const Scalar& start, const Scalar& stop) const { + interval_vector result; + visit_overlapping(start, stop, + [&](const interval& interval) { + result.emplace_back(interval); + }); + return result; + } + + interval_vector findContained(const Scalar& start, const Scalar& stop) const { + interval_vector result; + visit_contained(start, stop, + [&](const interval& interval) { + result.push_back(interval); + }); + return result; + } + bool empty() const { + if (left && !left->empty()) { + return false; + } + if (!intervals.empty()) { + return false; + } + if (right && !right->empty()) { + return false; + } + return true; + } + + template + void visit_all(UnaryFunction f) const { + if (left) { + left->visit_all(f); + } + std::for_each(intervals.begin(), intervals.end(), f); + if (right) { + right->visit_all(f); + } + } + + std::pair extentBruitForce() const { + struct Extent { + std::pair x = {std::numeric_limits::max(), + std::numeric_limits::min() }; + void operator()(const interval & interval) { + x.first = std::min(x.first, interval.start); + x.second = std::max(x.second, interval.stop); + } + }; + Extent extent; + + visit_all([&](const interval & interval) { extent(interval); }); + return extent.x; + } + + // Check all constraints. + // If first is false, second is invalid. + std::pair> is_valid() const { + const auto minmaxStop = std::minmax_element(intervals.begin(), intervals.end(), + IntervalStopCmp()); + const auto minmaxStart = std::minmax_element(intervals.begin(), intervals.end(), + IntervalStartCmp()); + + std::pair> result = {true, { std::numeric_limits::max(), + std::numeric_limits::min() }}; + if (!intervals.empty()) { + result.second.first = std::min(result.second.first, minmaxStart.first->start); + result.second.second = std::min(result.second.second, minmaxStop.second->stop); + } + if (left) { + auto valid = left->is_valid(); + result.first &= valid.first; + result.second.first = std::min(result.second.first, valid.second.first); + result.second.second = std::min(result.second.second, valid.second.second); + if (!result.first) { return result; } + if (valid.second.second >= center) { + result.first = false; + return result; + } + } + if (right) { + auto valid = right->is_valid(); + result.first &= valid.first; + result.second.first = std::min(result.second.first, valid.second.first); + result.second.second = std::min(result.second.second, valid.second.second); + if (!result.first) { return result; } + if (valid.second.first <= center) { + result.first = false; + return result; + } + } + if (!std::is_sorted(intervals.begin(), intervals.end(), IntervalStartCmp())) { + result.first = false; + } + return result; + } + + void clear() { + left.reset(); + right.reset(); + intervals.clear(); + center = 0; + } + +private: + interval_vector intervals; + std::unique_ptr left; + std::unique_ptr right; + Scalar center; +}; +#ifdef USE_INTERVAL_TREE_NAMESPACE +} +#endif + +#endif diff --git a/lib/external/pattern_language b/lib/external/pattern_language index 15f42da03..7285b76f8 160000 --- a/lib/external/pattern_language +++ b/lib/external/pattern_language @@ -1 +1 @@ -Subproject commit 15f42da03ff501d5e1c66794a508ef9a452236e3 +Subproject commit 7285b76f8284ea1c6e145ac0e664d8f3e5f537b9 diff --git a/lib/libimhex/CMakeLists.txt b/lib/libimhex/CMakeLists.txt index c78d3e2f2..d8b43fb7a 100644 --- a/lib/libimhex/CMakeLists.txt +++ b/lib/libimhex/CMakeLists.txt @@ -18,6 +18,9 @@ set(LIBROMFS_RESOURCE_LOCATION ${IMHEX_BASE_FOLDER}/resources/romfs) add_subdirectory(${CMAKE_CURRENT_SOURCE_DIR}/../external/libromfs ${CMAKE_CURRENT_BINARY_DIR}/external/libromfs EXCLUDE_FROM_ALL) set_target_properties(libromfs PROPERTIES POSITION_INDEPENDENT_CODE ON) +add_subdirectory(${CMAKE_CURRENT_SOURCE_DIR}/../external/intervaltree ${CMAKE_CURRENT_BINARY_DIR}/external/intervaltree EXCLUDE_FROM_ALL) +set_target_properties(intervaltree PROPERTIES POSITION_INDEPENDENT_CODE ON) + set(XDGPP_INCLUDE_DIRS "${CMAKE_CURRENT_SOURCE_DIR}/../external/xdgpp") set(CURL_USE_MBEDTLS ON) set(BUILD_CURL_EXE OFF) @@ -163,4 +166,4 @@ if (APPLE) target_link_libraries(libimhex PUBLIC ${FOUNDATION}) endif () -target_link_libraries(libimhex PUBLIC dl imgui nfd magic ${CAPSTONE_LIBRARIES} LLVMDemangle microtar ${NLOHMANN_JSON_LIBRARIES} ${YARA_LIBRARIES} ${LIBCURL_LIBRARIES} ${MBEDTLS_LIBRARIES} ${FMT_LIBRARIES} ${Python_LIBRARIES} libromfs libpl) +target_link_libraries(libimhex PUBLIC dl imgui nfd magic ${CAPSTONE_LIBRARIES} LLVMDemangle microtar ${NLOHMANN_JSON_LIBRARIES} ${YARA_LIBRARIES} ${LIBCURL_LIBRARIES} ${MBEDTLS_LIBRARIES} ${FMT_LIBRARIES} ${Python_LIBRARIES} libromfs libpl intervaltree) diff --git a/lib/libimhex/include/hex/providers/provider.hpp b/lib/libimhex/include/hex/providers/provider.hpp index f9aa967bf..54cb0d4bb 100644 --- a/lib/libimhex/include/hex/providers/provider.hpp +++ b/lib/libimhex/include/hex/providers/provider.hpp @@ -82,6 +82,9 @@ namespace hex::prv { [[nodiscard]] bool canUndo() const; [[nodiscard]] bool canRedo() const; + [[nodiscard]] virtual bool hasFilePicker() const; + virtual bool handleFilePicker(); + [[nodiscard]] virtual bool hasLoadInterface() const; [[nodiscard]] virtual bool hasInterface() const; virtual void drawLoadInterface(); diff --git a/lib/libimhex/source/providers/provider.cpp b/lib/libimhex/source/providers/provider.cpp index 66b5f67f2..e9f927512 100644 --- a/lib/libimhex/source/providers/provider.cpp +++ b/lib/libimhex/source/providers/provider.cpp @@ -19,6 +19,7 @@ namespace hex::prv { Provider::~Provider() { for (auto &overlay : this->m_overlays) this->deleteOverlay(overlay); + this->close(); } void Provider::read(u64 offset, void *buffer, size_t size, bool overlays) { @@ -227,6 +228,13 @@ namespace hex::prv { return this->m_patchTreeOffset > 0; } + bool Provider::hasFilePicker() const { + return false; + } + + bool Provider::handleFilePicker() { + return false; + } bool Provider::hasLoadInterface() const { return false; diff --git a/main/source/window/win_window.cpp b/main/source/window/win_window.cpp index 343db63f3..da8cf7124 100644 --- a/main/source/window/win_window.cpp +++ b/main/source/window/win_window.cpp @@ -22,6 +22,8 @@ #include #include + #include + #include namespace hex { @@ -263,6 +265,21 @@ namespace hex { ::SetWindowPos(hwnd, nullptr, 0, 0, 0, 0, SWP_NOZORDER | SWP_NOOWNERZORDER | SWP_FRAMECHANGED | SWP_NOSIZE | SWP_NOMOVE); ::SetWindowLong(hwnd, GWL_STYLE, GetWindowLong(hwnd, GWL_STYLE) | WS_OVERLAPPEDWINDOW); } + + // Catch heap corruption + { + ::AddVectoredExceptionHandler(TRUE, [](PEXCEPTION_POINTERS exception) -> LONG { + if ((exception->ExceptionRecord->ExceptionCode & 0xF000'0000) == 0xC000'0000) { + log::fatal("Exception raised: 0x{:08X}", exception->ExceptionRecord->ExceptionCode); + if (exception->ExceptionRecord->ExceptionCode == STATUS_HEAP_CORRUPTION) { + log::fatal("Heap corruption detected!"); + std::raise(SIGABRT); + } + } + + return EXCEPTION_CONTINUE_SEARCH; + }); + } } void Window::beginNativeWindowFrame() { diff --git a/plugins/builtin/CMakeLists.txt b/plugins/builtin/CMakeLists.txt index 35ce7d5f9..a0833c21c 100644 --- a/plugins/builtin/CMakeLists.txt +++ b/plugins/builtin/CMakeLists.txt @@ -28,6 +28,8 @@ add_library(${PROJECT_NAME} SHARED source/content/providers/file_provider.cpp source/content/providers/gdb_provider.cpp source/content/providers/disk_provider.cpp + source/content/providers/intel_hex_provider.cpp + source/content/providers/motorola_srec_provider.cpp source/content/views/view_hex_editor.cpp source/content/views/view_pattern_editor.cpp diff --git a/plugins/builtin/include/content/providers/disk_provider.hpp b/plugins/builtin/include/content/providers/disk_provider.hpp index f2aea16ab..ee08445f7 100644 --- a/plugins/builtin/include/content/providers/disk_provider.hpp +++ b/plugins/builtin/include/content/providers/disk_provider.hpp @@ -15,7 +15,7 @@ namespace hex::plugin::builtin::prv { class DiskProvider : public hex::prv::Provider { public: DiskProvider(); - ~DiskProvider() override; + ~DiskProvider() override = default; [[nodiscard]] bool isAvailable() const override; [[nodiscard]] bool isReadable() const override; diff --git a/plugins/builtin/include/content/providers/file_provider.hpp b/plugins/builtin/include/content/providers/file_provider.hpp index 4df8a289d..322c99c30 100644 --- a/plugins/builtin/include/content/providers/file_provider.hpp +++ b/plugins/builtin/include/content/providers/file_provider.hpp @@ -22,8 +22,8 @@ namespace hex::plugin::builtin::prv { class FileProvider : public hex::prv::Provider { public: - explicit FileProvider(); - ~FileProvider() override; + FileProvider() = default;; + ~FileProvider() override = default;; [[nodiscard]] bool isAvailable() const override; [[nodiscard]] bool isReadable() const override; @@ -49,6 +49,9 @@ namespace hex::plugin::builtin::prv { [[nodiscard]] std::string getName() const override; [[nodiscard]] std::vector> getDataInformation() const override; + bool hasFilePicker() const override { return true; } + bool handleFilePicker() override; + void setPath(const std::fs::path &path); [[nodiscard]] bool open() override; diff --git a/plugins/builtin/include/content/providers/gdb_provider.hpp b/plugins/builtin/include/content/providers/gdb_provider.hpp index abbfce6b7..adce07db8 100644 --- a/plugins/builtin/include/content/providers/gdb_provider.hpp +++ b/plugins/builtin/include/content/providers/gdb_provider.hpp @@ -13,7 +13,7 @@ namespace hex::plugin::builtin::prv { class GDBProvider : public hex::prv::Provider { public: GDBProvider(); - ~GDBProvider() override; + ~GDBProvider() override = default;; [[nodiscard]] bool isAvailable() const override; [[nodiscard]] bool isReadable() const override; diff --git a/plugins/builtin/include/content/providers/intel_hex_provider.hpp b/plugins/builtin/include/content/providers/intel_hex_provider.hpp new file mode 100644 index 000000000..550ef26b6 --- /dev/null +++ b/plugins/builtin/include/content/providers/intel_hex_provider.hpp @@ -0,0 +1,50 @@ +#pragma once + +#include + +#include + +namespace hex::plugin::builtin::prv { + + class IntelHexProvider : public hex::prv::Provider { + public: + IntelHexProvider() = default; + ~IntelHexProvider() override = default; + + [[nodiscard]] bool isAvailable() const override { return this->m_dataValid; } + [[nodiscard]] bool isReadable() const override { return true; } + [[nodiscard]] bool isWritable() const override { return false; } + [[nodiscard]] bool isResizable() const override { return false; } + [[nodiscard]] bool isSavable() const override { return false; } + + void readRaw(u64 offset, void *buffer, size_t size) override; + void writeRaw(u64 offset, const void *buffer, size_t size) override; + [[nodiscard]] size_t getActualSize() const override; + + bool open() override; + void close() override; + + [[nodiscard]] std::string getName() const override; + [[nodiscard]] std::vector> getDataInformation() const override { return { }; } + + void loadSettings(const nlohmann::json &settings) override { hex::unused(settings); } + [[nodiscard]] nlohmann::json storeSettings(nlohmann::json settings) const override { return settings; } + + [[nodiscard]] std::string getTypeName() const override { + return "hex.builtin.provider.intel_hex"; + } + + bool hasFilePicker() const override { return true; } + bool handleFilePicker() override; + + std::pair getRegionValidity(u64 address) const override; + + protected: + bool m_dataValid = false; + size_t m_dataSize = 0x00; + interval_tree::IntervalTree> m_data; + + std::fs::path m_sourceFilePath; + }; + +} \ No newline at end of file diff --git a/plugins/builtin/include/content/providers/motorola_srec_provider.hpp b/plugins/builtin/include/content/providers/motorola_srec_provider.hpp new file mode 100644 index 000000000..db911cdd9 --- /dev/null +++ b/plugins/builtin/include/content/providers/motorola_srec_provider.hpp @@ -0,0 +1,27 @@ +#pragma once + +#include + +namespace hex::plugin::builtin::prv { + + class MotorolaSRECProvider : public IntelHexProvider { + public: + MotorolaSRECProvider() = default; + ~MotorolaSRECProvider() override = default; + + bool open() override; + void close() override; + + [[nodiscard]] std::string getName() const override; + + [[nodiscard]] std::string getTypeName() const override { + return "hex.builtin.provider.motorola_srec"; + } + + bool handleFilePicker() override; + + private: + + }; + +} \ No newline at end of file diff --git a/plugins/builtin/source/content/events.cpp b/plugins/builtin/source/content/events.cpp index 8b8583ad7..b653e417a 100644 --- a/plugins/builtin/source/content/events.cpp +++ b/plugins/builtin/source/content/events.cpp @@ -11,38 +11,13 @@ #include #include -#include "content/providers/file_provider.hpp" #include "provider_extra_data.hpp" namespace hex::plugin::builtin { static void openFile(const std::fs::path &path) { - auto provider = ImHexApi::Provider::createProvider("hex.builtin.provider.file"); - - if (auto fileProvider = dynamic_cast(provider)) { - fileProvider->setPath(path); - if (!fileProvider->open()) { - View::showErrorPopup("hex.builtin.popup.error.open"_lang); - ImHexApi::Provider::remove(provider); - - return; - } - } - - if (!provider->isWritable()) { - View::showErrorPopup("hex.builtin.popup.error.read_only"_lang); - } - - if (!provider->isAvailable()) { - View::showErrorPopup("hex.builtin.popup.error.open"_lang); - ImHexApi::Provider::remove(provider); - - return; - } - + ImHexApi::Provider::createProvider("hex.builtin.provider.file"); EventManager::post(path); - EventManager::post(); - EventManager::post(); } void registerEventHandlers() { @@ -88,9 +63,7 @@ namespace hex::plugin::builtin { EventManager::post(path); }); } else if (name == "Open File") { - fs::openFileBrowser(fs::DialogMode::Open, {}, [](const auto &path) { - EventManager::post(path); - }); + ImHexApi::Provider::createProvider("hex.builtin.provider.file"); } else if (name == "Open Project") { fs::openFileBrowser(fs::DialogMode::Open, { {"Project File", "hexproj"} }, [](const auto &path) { @@ -104,8 +77,28 @@ namespace hex::plugin::builtin { }); EventManager::subscribe([](hex::prv::Provider *provider) { - if (provider->hasLoadInterface()) + if (provider->hasFilePicker()) { + if (!provider->handleFilePicker()) { + ImHexApi::Tasks::doLater([provider] { ImHexApi::Provider::remove(provider); }); + return; + } + if (!provider->open()) { + View::showErrorPopup("hex.builtin.popup.error.open"_lang); + ImHexApi::Tasks::doLater([provider] { ImHexApi::Provider::remove(provider); }); + return; + } + } + else if (provider->hasLoadInterface()) EventManager::post(View::toWindowName("hex.builtin.view.provider_settings.load_popup")); + else { + if (!provider->open() || !provider->isAvailable()) { + View::showErrorPopup("hex.builtin.popup.error.open"_lang); + ImHexApi::Tasks::doLater([provider] { ImHexApi::Provider::remove(provider); }); + } + + if (!provider->isWritable()) + View::showErrorPopup("hex.builtin.popup.error.read_only"_lang); + } }); EventManager::subscribe([](hex::prv::Provider *provider) { diff --git a/plugins/builtin/source/content/providers.cpp b/plugins/builtin/source/content/providers.cpp index 3fe423a02..95efc70ab 100644 --- a/plugins/builtin/source/content/providers.cpp +++ b/plugins/builtin/source/content/providers.cpp @@ -4,6 +4,8 @@ #include "content/providers/file_provider.hpp" #include "content/providers/null_provider.hpp" #include "content/providers/disk_provider.hpp" +#include "content/providers/intel_hex_provider.hpp" +#include "content/providers/motorola_srec_provider.hpp" #include #include @@ -17,6 +19,8 @@ namespace hex::plugin::builtin { ContentRegistry::Provider::add(false); ContentRegistry::Provider::add(); ContentRegistry::Provider::add(); + ContentRegistry::Provider::add(); + ContentRegistry::Provider::add(); ProjectFile::registerHandler({ .basePath = "providers", diff --git a/plugins/builtin/source/content/providers/disk_provider.cpp b/plugins/builtin/source/content/providers/disk_provider.cpp index 299f06a42..6433c29fd 100644 --- a/plugins/builtin/source/content/providers/disk_provider.cpp +++ b/plugins/builtin/source/content/providers/disk_provider.cpp @@ -35,10 +35,6 @@ namespace hex::plugin::builtin::prv { this->reloadDrives(); } - DiskProvider::~DiskProvider() { - this->close(); - } - bool DiskProvider::isAvailable() const { #if defined(OS_WINDOWS) diff --git a/plugins/builtin/source/content/providers/file_provider.cpp b/plugins/builtin/source/content/providers/file_provider.cpp index 3aafffc67..90ef798c0 100644 --- a/plugins/builtin/source/content/providers/file_provider.cpp +++ b/plugins/builtin/source/content/providers/file_provider.cpp @@ -12,14 +12,6 @@ namespace hex::plugin::builtin::prv { - FileProvider::FileProvider() : Provider() { - } - - FileProvider::~FileProvider() { - this->close(); - } - - 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; @@ -196,6 +188,12 @@ namespace hex::plugin::builtin::prv { return result; } + bool FileProvider::handleFilePicker() { + return fs::openFileBrowser(fs::DialogMode::Open, {}, [this](const auto &path) { + this->setPath(path); + }); + } + void FileProvider::setPath(const std::fs::path &path) { this->m_path = path; } diff --git a/plugins/builtin/source/content/providers/gdb_provider.cpp b/plugins/builtin/source/content/providers/gdb_provider.cpp index 6d2c625ff..06ed2e146 100644 --- a/plugins/builtin/source/content/providers/gdb_provider.cpp +++ b/plugins/builtin/source/content/providers/gdb_provider.cpp @@ -121,11 +121,6 @@ namespace hex::plugin::builtin::prv { GDBProvider::GDBProvider() : Provider(), m_size(0xFFFF'FFFF) { } - GDBProvider::~GDBProvider() { - this->close(); - } - - bool GDBProvider::isAvailable() const { return this->m_socket.isConnected(); } diff --git a/plugins/builtin/source/content/providers/intel_hex_provider.cpp b/plugins/builtin/source/content/providers/intel_hex_provider.cpp new file mode 100644 index 000000000..08d1644a2 --- /dev/null +++ b/plugins/builtin/source/content/providers/intel_hex_provider.cpp @@ -0,0 +1,235 @@ +#include "content/providers/intel_hex_provider.hpp" + +#include + +#include +#include +#include +#include +#include + +#include + +namespace hex::plugin::builtin::prv { + + namespace intel_hex { + + u8 parseHexDigit(char c) { + if (c >= '0' && c <= '9') + return c - '0'; + else if (c >= 'A' && c <= 'F') + return c - 'A' + 10; + else if (c >= 'a' && c <= 'f') + return c - 'a' + 10; + else + throw std::runtime_error("Failed to parse hex digit"); + } + + std::map> parseIntelHex(const std::string &string) { + std::map> result; + + u8 checksum = 0x00; + u64 offset = 0x00; + + u8 byteCount = 0x00; + u32 segmentAddress = 0x0000'0000; + u32 extendedLinearAddress = 0x0000'0000; + u16 address = 0x0000; + std::vector data; + + enum class RecordType { + Data = 0x00, + EndOfFile = 0x01, + ExtendedSegmentAddress = 0x02, + StartSegmentAddress = 0x03, + ExtendedLinearAddress = 0x04, + StartLinearAddress = 0x05 + } recordType; + + auto c = [&]() { + while (std::isspace(string[offset]) && offset < string.length()) + offset++; + + if (offset >= string.length()) + throw std::runtime_error("Unexpected end of file"); + + return string[offset++]; + }; + + auto parseValue = [&](u8 byteCount) { + u64 value = 0x00; + for (u8 i = 0; i < byteCount; i++) { + u8 byte = (parseHexDigit(c()) << 4) | parseHexDigit(c()); + value <<= 8; + value |= byte; + + checksum += byte; + } + + + return value; + }; + + bool endOfFile = false; + try { + while (offset < string.length()) { + // Parse start code + if (c() != ':') + return { }; + + checksum = 0x00; + + if (endOfFile) + throw std::runtime_error("Unexpected end of file"); + + // Parse byte count + byteCount = parseValue(1); + + // Parse address + address = parseValue(2); + + // Parse record type + recordType = static_cast(parseValue(1)); + + data.clear(); + for (u32 i = 0; i < byteCount; i++) { + data.push_back(parseValue(1)); + } + + parseValue(1); + if (!data.empty() && checksum != 0x00) + throw std::runtime_error("Checksum mismatch"); + + while (std::isspace(string[offset]) && offset < string.length()) + offset++; + + // Construct region + switch (recordType) { + case RecordType::Data: { + result[extendedLinearAddress | (segmentAddress + address)] = data; + break; + } + case RecordType::EndOfFile: { + endOfFile = true; + break; + } + case RecordType::ExtendedSegmentAddress: { + if (byteCount != 2) + throw std::runtime_error("Unexpected byte count"); + + segmentAddress = (data[0] << 8 | data[1]) * 16; + break; + } + case RecordType::StartSegmentAddress: { + if (byteCount != 4) + throw std::runtime_error("Unexpected byte count"); + + // Can be safely ignored + break; + } + case RecordType::ExtendedLinearAddress: { + if (byteCount != 2) + throw std::runtime_error("Unexpected byte count"); + + extendedLinearAddress = (data[0] << 8 | data[1]) << 16; + break; + } + case RecordType::StartLinearAddress: { + if (byteCount != 4) + throw std::runtime_error("Unexpected byte count"); + + // Can be safely ignored + break; + } + } + } + + } catch (const std::runtime_error &e) { + return { }; + } + + return result; + } + + } + + void IntelHexProvider::readRaw(u64 offset, void *buffer, size_t size) { + auto intervals = this->m_data.findOverlapping(offset, (offset + size) - 1); + + std::memset(buffer, 0x00, size); + auto bytes = reinterpret_cast(buffer); + for (const auto &interval : intervals) { + for (u32 i = std::max(interval.start, offset); i <= interval.stop && (i - offset) < size; i++) { + bytes[i - offset] = interval.value[i - interval.start]; + } + } + } + + void IntelHexProvider::writeRaw(u64 offset, const void *buffer, size_t size) { + hex::unused(offset, buffer, size); + } + + size_t IntelHexProvider::getActualSize() const { + return this->m_dataSize; + } + + bool IntelHexProvider::open() { + auto file = fs::File(this->m_sourceFilePath, fs::File::Mode::Read); + if (!file.isValid()) + return false; + + auto data = intel_hex::parseIntelHex(file.readString()); + if (data.empty()) + return false; + + u64 maxAddress = 0x00; + decltype(this->m_data)::interval_vector intervals; + for (auto &[address, bytes] : data) { + auto endAddress = (address + bytes.size()) - 1; + intervals.emplace_back(address, endAddress, std::move(bytes)); + + if (endAddress > maxAddress) + maxAddress = endAddress; + } + this->m_data = std::move(intervals); + this->m_dataSize = maxAddress + 1; + this->m_dataValid = true; + + return Provider::open(); + } + + void IntelHexProvider::close() { + + Provider::close(); + } + + [[nodiscard]] std::string IntelHexProvider::getName() const { + return hex::format("hex.builtin.provider.intel_hex.name"_lang, this->m_sourceFilePath.filename().string()); + } + + bool IntelHexProvider::handleFilePicker() { + auto picked = fs::openFileBrowser(fs::DialogMode::Open, { { "Intel Hex File", "*" } }, [this](const std::fs::path &path) { + this->m_sourceFilePath = path; + }); + if (!picked) + return false; + if (!fs::isRegularFile(this->m_sourceFilePath)) + return false; + + return true; + } + + std::pair IntelHexProvider::getRegionValidity(u64 address) const { + auto intervals = this->m_data.findOverlapping(address, address); + if (intervals.empty()) + return { Region::Invalid(), false }; + + auto closestInterval = intervals.front(); + for (const auto &interval : intervals) { + if (interval.start < closestInterval.start) + closestInterval = interval; + } + return { Region { closestInterval.start, (closestInterval.stop - closestInterval.start) + 1}, true }; + } + +} diff --git a/plugins/builtin/source/content/providers/motorola_srec_provider.cpp b/plugins/builtin/source/content/providers/motorola_srec_provider.cpp new file mode 100644 index 000000000..4468d687e --- /dev/null +++ b/plugins/builtin/source/content/providers/motorola_srec_provider.cpp @@ -0,0 +1,216 @@ +#include "content/providers/motorola_srec_provider.hpp" + +#include + +#include +#include +#include +#include +#include + +#include + +namespace hex::plugin::builtin::prv { + + namespace motorola_srec { + + u8 parseHexDigit(char c) { + if (c >= '0' && c <= '9') + return c - '0'; + else if (c >= 'A' && c <= 'F') + return c - 'A' + 10; + else if (c >= 'a' && c <= 'f') + return c - 'a' + 10; + else + throw std::runtime_error("Failed to parse hex digit"); + } + + std::map> parseMotorolaSREC(const std::string &string) { + std::map> result; + + u64 offset = 0x00; + u8 checksum = 0x00; + u8 byteCount = 0x00; + u32 address = 0x0000'0000; + std::vector data; + + auto c = [&]() { + while (std::isspace(string[offset]) && offset < string.length()) + offset++; + + if (offset >= string.length()) + throw std::runtime_error("Unexpected end of file"); + + return string[offset++]; + }; + + auto parseValue = [&](u8 byteCount) { + u64 value = 0x00; + for (u8 i = 0; i < byteCount; i++) { + u8 byte = (parseHexDigit(c()) << 4) | parseHexDigit(c()); + value <<= 8; + value |= byte; + + checksum += byte; + } + + return value; + }; + + enum class RecordType { + Header = 0x00, + Data16 = 0x01, + Data24 = 0x02, + Data32 = 0x03, + Reserved = 0x04, + Count16 = 0x05, + Count24 = 0x06, + StartAddress32 = 0x07, + StartAddress24 = 0x08, + StartAddress16 = 0x09, + } recordType; + + bool endOfFile = false; + try { + while (offset < string.length()) { + // Parse record start + if (c() != 'S') + return { }; + + if (endOfFile) + throw std::runtime_error("Unexpected end of file"); + + // Parse record type + { + char typeCharacter = c(); + if (typeCharacter < '0' || typeCharacter > '9') + throw std::runtime_error("Invalid record type"); + recordType = static_cast(typeCharacter - '0'); + } + + checksum = 0x00; + + // Parse byte count + byteCount = parseValue(1); + + // Parse address + switch (recordType) { + case RecordType::Reserved: + break; + case RecordType::Header: + case RecordType::Data16: + case RecordType::Count16: + case RecordType::StartAddress16: + byteCount -= 2; + address = parseValue(2); + break; + case RecordType::Data24: + case RecordType::Count24: + case RecordType::StartAddress24: + byteCount -= 3; + address = parseValue(3); + break; + case RecordType::Data32: + case RecordType::StartAddress32: + byteCount -= 4; + address = parseValue(4); + break; + } + + byteCount -= 1; + + auto readData = [&byteCount, &parseValue]() { + std::vector bytes; + bytes.resize(byteCount); + for (u8 i = 0; i < byteCount; i++) { + bytes[i] = parseValue(1); + } + + return bytes; + }; + + // Parse data + data = readData(); + + // Parse checksum + { + auto value = parseValue(1); + if (((checksum - value) ^ 0xFF) != value) + throw std::runtime_error("Invalid checksum"); + } + + // Construct region + switch (recordType) { + case RecordType::Data16: + case RecordType::Data24: + case RecordType::Data32: + result[address] = data; + break; + case RecordType::Header: + case RecordType::Reserved: + break; + case RecordType::Count16: + case RecordType::Count24: + break; + case RecordType::StartAddress32: + case RecordType::StartAddress24: + case RecordType::StartAddress16: + endOfFile = true; + break; + } + } + } catch (const std::runtime_error &e) { + return { }; + } + + return result; + } + + } + + bool MotorolaSRECProvider::open() { + auto file = fs::File(this->m_sourceFilePath, fs::File::Mode::Read); + if (!file.isValid()) + return false; + + auto data = motorola_srec::parseMotorolaSREC(file.readString()); + if (data.empty()) + return false; + + u64 maxAddress = 0x00; + decltype(this->m_data)::interval_vector intervals; + for (auto &[address, bytes] : data) { + auto endAddress = (address + bytes.size()) - 1; + intervals.emplace_back(address, endAddress, std::move(bytes)); + + if (endAddress > maxAddress) + maxAddress = endAddress; + } + this->m_data = std::move(intervals); + this->m_dataSize = maxAddress + 1; + this->m_dataValid = true; + + return Provider::open(); + } + + void MotorolaSRECProvider::close() { + Provider::close(); + } + + [[nodiscard]] std::string MotorolaSRECProvider::getName() const { + return hex::format("hex.builtin.provider.motorola_srec.name"_lang, this->m_sourceFilePath.filename().string()); + } + + bool MotorolaSRECProvider::handleFilePicker() { + auto picked = fs::openFileBrowser(fs::DialogMode::Open, { { "Motorola SREC File", "*" } }, [this](const std::fs::path &path) { + this->m_sourceFilePath = path; + }); + if (!picked) + return false; + if (!fs::isRegularFile(this->m_sourceFilePath)) + return false; + + return true; + } + +} diff --git a/plugins/builtin/source/content/views/view_provider_settings.cpp b/plugins/builtin/source/content/views/view_provider_settings.cpp index 6f2d1727d..b2b2765c4 100644 --- a/plugins/builtin/source/content/views/view_provider_settings.cpp +++ b/plugins/builtin/source/content/views/view_provider_settings.cpp @@ -28,7 +28,6 @@ namespace hex::plugin::builtin { if (ImGui::BeginPopupModal(View::toWindowName("hex.builtin.view.provider_settings.load_popup").c_str(), nullptr, ImGuiWindowFlags_AlwaysAutoResize)) { auto provider = hex::ImHexApi::Provider::get(); - if (provider != nullptr) { provider->drawLoadInterface(); diff --git a/plugins/builtin/source/content/welcome_screen.cpp b/plugins/builtin/source/content/welcome_screen.cpp index cb248137b..da39e601c 100644 --- a/plugins/builtin/source/content/welcome_screen.cpp +++ b/plugins/builtin/source/content/welcome_screen.cpp @@ -140,9 +140,7 @@ namespace hex::plugin::builtin { for (const auto &unlocalizedProviderName : ContentRegistry::Provider::getEntries()) { if (ImGui::Hyperlink(LangEntry(unlocalizedProviderName))) { - auto *provider = ImHexApi::Provider::createProvider(unlocalizedProviderName); - if (!provider->hasLoadInterface()) - (void)provider->open(); + ImHexApi::Provider::createProvider(unlocalizedProviderName); ImGui::CloseCurrentPopup(); } } diff --git a/plugins/builtin/source/lang/de_DE.cpp b/plugins/builtin/source/lang/de_DE.cpp index 109bc0cb0..64b5eb356 100644 --- a/plugins/builtin/source/lang/de_DE.cpp +++ b/plugins/builtin/source/lang/de_DE.cpp @@ -734,19 +734,18 @@ namespace hex::plugin::builtin { { "hex.builtin.setting.font", "Schriftart" }, { "hex.builtin.setting.font.font_path", "Eigene Schriftart" }, { "hex.builtin.setting.font.font_size", "Schriftgrösse" }, - //{ "hex.builtin.setting.proxy", "Proxy" }, - //{ "hex.builtin.setting.proxy.description", "Proxy will take effect on store, wikipedia or any other plugin immediately." }, - //{ "hex.builtin.setting.proxy.enable", "Enable Proxy" }, - //{ "hex.builtin.setting.proxy.url", "Proxy URL" }, - //{ "hex.builtin.setting.proxy.url.tooltip", "http(s):// or socks5:// (e.g., http://127.0.0.1:1080)" }, - - { "hex.builtin.provider.file.path", "Dateipfad" }, - { "hex.builtin.provider.file.size", "Größe" }, - { "hex.builtin.provider.file.creation", "Erstellungszeit" }, - { "hex.builtin.provider.file.access", "Letzte Zugriffszeit" }, - { "hex.builtin.provider.file.modification", "Letzte Modifikationszeit" }, + { "hex.builtin.setting.proxy", "Proxy" }, + { "hex.builtin.setting.proxy.description", "Proxy wird bei allen Netzwerkverbindungen angewendet." }, + { "hex.builtin.setting.proxy.enable", "Proxy aktivieren" }, + { "hex.builtin.setting.proxy.url", "Proxy URL" }, + { "hex.builtin.setting.proxy.url.tooltip", "http(s):// oder socks5:// (z.B, http://127.0.0.1:1080)" }, { "hex.builtin.provider.file", "Datei Provider" }, + { "hex.builtin.provider.file.path", "Dateipfad" }, + { "hex.builtin.provider.file.size", "Größe" }, + { "hex.builtin.provider.file.creation", "Erstellungszeit" }, + { "hex.builtin.provider.file.access", "Letzte Zugriffszeit" }, + { "hex.builtin.provider.file.modification", "Letzte Modifikationszeit" }, { "hex.builtin.provider.gdb", "GDB Server Provider" }, { "hex.builtin.provider.gdb.name", "GDB Server <{0}:{1}>" }, { "hex.builtin.provider.gdb.server", "Server" }, @@ -757,6 +756,10 @@ namespace hex::plugin::builtin { { "hex.builtin.provider.disk.disk_size", "Datenträgergrösse" }, { "hex.builtin.provider.disk.sector_size", "Sektorgrösse" }, { "hex.builtin.provider.disk.reload", "Neu laden" }, + { "hex.builtin.provider.intel_hex", "Intel Hex Provider" }, + { "hex.builtin.provider.intel_hex.name", "Intel Hex {0}" }, + { "hex.builtin.provider.motorola_srec", "Motorola SREC Provider" }, + { "hex.builtin.provider.motorola_srec.name", "Motorola SREC {0}" }, { "hex.builtin.layouts.default", "Standard" }, diff --git a/plugins/builtin/source/lang/en_US.cpp b/plugins/builtin/source/lang/en_US.cpp index 49223f57f..f9bf7e061 100644 --- a/plugins/builtin/source/lang/en_US.cpp +++ b/plugins/builtin/source/lang/en_US.cpp @@ -744,13 +744,12 @@ namespace hex::plugin::builtin { { "hex.builtin.setting.proxy.url", "Proxy URL" }, { "hex.builtin.setting.proxy.url.tooltip", "http(s):// or socks5:// (e.g., http://127.0.0.1:1080)" }, - { "hex.builtin.provider.file.path", "File path" }, - { "hex.builtin.provider.file.size", "Size" }, - { "hex.builtin.provider.file.creation", "Creation time" }, - { "hex.builtin.provider.file.access", "Last access time" }, - { "hex.builtin.provider.file.modification", "Last modification time" }, - { "hex.builtin.provider.file", "File Provider" }, + { "hex.builtin.provider.file.path", "File path" }, + { "hex.builtin.provider.file.size", "Size" }, + { "hex.builtin.provider.file.creation", "Creation time" }, + { "hex.builtin.provider.file.access", "Last access time" }, + { "hex.builtin.provider.file.modification", "Last modification time" }, { "hex.builtin.provider.gdb", "GDB Server Provider" }, { "hex.builtin.provider.gdb.name", "GDB Server <{0}:{1}>" }, { "hex.builtin.provider.gdb.server", "Server" }, @@ -761,6 +760,10 @@ namespace hex::plugin::builtin { { "hex.builtin.provider.disk.disk_size", "Disk Size" }, { "hex.builtin.provider.disk.sector_size", "Sector Size" }, { "hex.builtin.provider.disk.reload", "Reload" }, + { "hex.builtin.provider.intel_hex", "Intel Hex Provider" }, + { "hex.builtin.provider.intel_hex.name", "Intel Hex {0}" }, + { "hex.builtin.provider.motorola_srec", "Motorola SREC Provider" }, + { "hex.builtin.provider.motorola_srec.name", "Motorola SREC {0}" }, { "hex.builtin.layouts.default", "Default" }, diff --git a/plugins/builtin/source/lang/it_IT.cpp b/plugins/builtin/source/lang/it_IT.cpp index 392604f32..e26723ec9 100644 --- a/plugins/builtin/source/lang/it_IT.cpp +++ b/plugins/builtin/source/lang/it_IT.cpp @@ -748,13 +748,12 @@ namespace hex::plugin::builtin { //{ "hex.builtin.setting.proxy.url", "Proxy URL" }, //{ "hex.builtin.setting.proxy.url.tooltip", "http(s):// or socks5:// (e.g., http://127.0.0.1:1080)" }, - { "hex.builtin.provider.file.path", "Percorso del File" }, - { "hex.builtin.provider.file.size", "Dimensione" }, - { "hex.builtin.provider.file.creation", "Data di creazione" }, - { "hex.builtin.provider.file.access", "Data dell'ultimo accesso" }, - { "hex.builtin.provider.file.modification", "Data dell'ultima modifica" }, - { "hex.builtin.provider.file", "Provider di file" }, + { "hex.builtin.provider.file.path", "Percorso del File" }, + { "hex.builtin.provider.file.size", "Dimensione" }, + { "hex.builtin.provider.file.creation", "Data di creazione" }, + { "hex.builtin.provider.file.access", "Data dell'ultimo accesso" }, + { "hex.builtin.provider.file.modification", "Data dell'ultima modifica" }, { "hex.builtin.provider.gdb", "Server GDB Provider" }, { "hex.builtin.provider.gdb.name", "Server GDB <{0}:{1}>" }, { "hex.builtin.provider.gdb.server", "Server" }, @@ -765,6 +764,10 @@ namespace hex::plugin::builtin { { "hex.builtin.provider.disk.disk_size", "Dimensione disco" }, { "hex.builtin.provider.disk.sector_size", "Dimensione settore" }, { "hex.builtin.provider.disk.reload", "Ricarica" }, + //{ "hex.builtin.provider.intel_hex", "Intel Hex Provider" }, + // { "hex.builtin.provider.intel_hex.name", "Intel Hex {0}" }, + //{ "hex.builtin.provider.motorola_srec", "Motorola SREC Provider" }, + // { "hex.builtin.provider.motorola_srec.name", "Motorola SREC {0}" }, { "hex.builtin.layouts.default", "Default" }, diff --git a/plugins/builtin/source/lang/ja_JP.cpp b/plugins/builtin/source/lang/ja_JP.cpp index cf1ce5ef6..f0b27ec5d 100644 --- a/plugins/builtin/source/lang/ja_JP.cpp +++ b/plugins/builtin/source/lang/ja_JP.cpp @@ -745,13 +745,12 @@ namespace hex::plugin::builtin { { "hex.builtin.setting.proxy.url", "プロキシURL" }, //{ "hex.builtin.setting.proxy.url.tooltip", "http(s):// or socks5:// (e.g., http://127.0.0.1:1080)" }, - { "hex.builtin.provider.file.path", "ファイルパス" }, - { "hex.builtin.provider.file.size", "サイズ" }, - { "hex.builtin.provider.file.creation", "作成時刻" }, - { "hex.builtin.provider.file.access", "最終アクセス時刻" }, - { "hex.builtin.provider.file.modification", "最終編集時刻" }, - { "hex.builtin.provider.file", "ファイルプロバイダ" }, + { "hex.builtin.provider.file.path", "ファイルパス" }, + { "hex.builtin.provider.file.size", "サイズ" }, + { "hex.builtin.provider.file.creation", "作成時刻" }, + { "hex.builtin.provider.file.access", "最終アクセス時刻" }, + { "hex.builtin.provider.file.modification", "最終編集時刻" }, { "hex.builtin.provider.gdb", "GDBサーバープロバイダ" }, { "hex.builtin.provider.gdb.name", "GDBサーバー <{0}:{1}>" }, { "hex.builtin.provider.gdb.server", "サーバー" }, @@ -762,6 +761,10 @@ namespace hex::plugin::builtin { { "hex.builtin.provider.disk.disk_size", "ディスクサイズ" }, { "hex.builtin.provider.disk.sector_size", "セクタサイズ" }, { "hex.builtin.provider.disk.reload", "リロード" }, + //{ "hex.builtin.provider.intel_hex", "Intel Hex Provider" }, + // { "hex.builtin.provider.intel_hex.name", "Intel Hex {0}" }, + //{ "hex.builtin.provider.motorola_srec", "Motorola SREC Provider" }, + // { "hex.builtin.provider.motorola_srec.name", "Motorola SREC {0}" }, { "hex.builtin.layouts.default", "標準" }, diff --git a/plugins/builtin/source/lang/pt_BR.cpp b/plugins/builtin/source/lang/pt_BR.cpp index c4c6c26f5..ba8bf3969 100644 --- a/plugins/builtin/source/lang/pt_BR.cpp +++ b/plugins/builtin/source/lang/pt_BR.cpp @@ -740,13 +740,12 @@ namespace hex::plugin::builtin { //{ "hex.builtin.setting.proxy.url", "Proxy URL" }, //{ "hex.builtin.setting.proxy.url.tooltip", "http(s):// or socks5:// (e.g., http://127.0.0.1:1080)" }, - { "hex.builtin.provider.file.path", "Caminho do Arquivo" }, - { "hex.builtin.provider.file.size", "Tamanho" }, - { "hex.builtin.provider.file.creation", "Data de Criação" }, - { "hex.builtin.provider.file.access", "Ultima vez acessado" }, - { "hex.builtin.provider.file.modification", "Ultima vez modificado" }, - { "hex.builtin.provider.file", "Provedor de arquivo" }, + { "hex.builtin.provider.file.path", "Caminho do Arquivo" }, + { "hex.builtin.provider.file.size", "Tamanho" }, + { "hex.builtin.provider.file.creation", "Data de Criação" }, + { "hex.builtin.provider.file.access", "Ultima vez acessado" }, + { "hex.builtin.provider.file.modification", "Ultima vez modificado" }, { "hex.builtin.provider.gdb", "GDB Server Provider" }, { "hex.builtin.provider.gdb.name", "GDB Server <{0}:{1}>" }, { "hex.builtin.provider.gdb.server", "Servidor" }, @@ -757,6 +756,10 @@ namespace hex::plugin::builtin { { "hex.builtin.provider.disk.disk_size", "Tamanho do Disco" }, { "hex.builtin.provider.disk.sector_size", "Tamanho do Setor" }, { "hex.builtin.provider.disk.reload", "Recarregar" }, + //{ "hex.builtin.provider.intel_hex", "Intel Hex Provider" }, + // { "hex.builtin.provider.intel_hex.name", "Intel Hex {0}" }, + //{ "hex.builtin.provider.motorola_srec", "Motorola SREC Provider" }, + // { "hex.builtin.provider.motorola_srec.name", "Motorola SREC {0}" }, { "hex.builtin.layouts.default", "Default" }, diff --git a/plugins/builtin/source/lang/zh_CN.cpp b/plugins/builtin/source/lang/zh_CN.cpp index e483a889e..3082e2985 100644 --- a/plugins/builtin/source/lang/zh_CN.cpp +++ b/plugins/builtin/source/lang/zh_CN.cpp @@ -745,13 +745,12 @@ namespace hex::plugin::builtin { { "hex.builtin.setting.proxy.url", "代理 URL" }, { "hex.builtin.setting.proxy.url.tooltip", "http(s):// 或 socks5://(如 http://127.0.0.1:1080)" }, - { "hex.builtin.provider.file.path", "路径" }, - { "hex.builtin.provider.file.size", "大小" }, - { "hex.builtin.provider.file.creation", "创建时间" }, - { "hex.builtin.provider.file.access", "最后访问时间" }, - { "hex.builtin.provider.file.modification", "最后更改时间" }, - { "hex.builtin.provider.file", "文件" }, + { "hex.builtin.provider.file.path", "路径" }, + { "hex.builtin.provider.file.size", "大小" }, + { "hex.builtin.provider.file.creation", "创建时间" }, + { "hex.builtin.provider.file.access", "最后访问时间" }, + { "hex.builtin.provider.file.modification", "最后更改时间" }, { "hex.builtin.provider.gdb", "GDB 服务器" }, { "hex.builtin.provider.gdb.name", "GDB 服务器 <{0}:{1}>" }, { "hex.builtin.provider.gdb.server", "服务器" }, @@ -762,6 +761,10 @@ namespace hex::plugin::builtin { { "hex.builtin.provider.disk.disk_size", "磁盘大小" }, { "hex.builtin.provider.disk.sector_size", "扇区大小" }, { "hex.builtin.provider.disk.reload", "刷新" }, + //{ "hex.builtin.provider.intel_hex", "Intel Hex Provider" }, + // { "hex.builtin.provider.intel_hex.name", "Intel Hex {0}" }, + //{ "hex.builtin.provider.motorola_srec", "Motorola SREC Provider" }, + // { "hex.builtin.provider.motorola_srec.name", "Motorola SREC {0}" }, { "hex.builtin.layouts.default", "默认" }, diff --git a/plugins/builtin/source/lang/zh_TW.cpp b/plugins/builtin/source/lang/zh_TW.cpp index 813a9ba41..9adf6e377 100644 --- a/plugins/builtin/source/lang/zh_TW.cpp +++ b/plugins/builtin/source/lang/zh_TW.cpp @@ -741,13 +741,12 @@ namespace hex::plugin::builtin { { "hex.builtin.setting.proxy.url", "Proxy 網址" }, { "hex.builtin.setting.proxy.url.tooltip", "http(s):// 或 socks5:// (例如 http://127.0.0.1:1080)" }, - { "hex.builtin.provider.file.path", "檔案路徑" }, - { "hex.builtin.provider.file.size", "大小" }, - { "hex.builtin.provider.file.creation", "建立時間" }, - { "hex.builtin.provider.file.access", "最後存取時間" }, - { "hex.builtin.provider.file.modification", "最後修改時間" }, - { "hex.builtin.provider.file", "檔案提供者" }, + { "hex.builtin.provider.file.path", "檔案路徑" }, + { "hex.builtin.provider.file.size", "大小" }, + { "hex.builtin.provider.file.creation", "建立時間" }, + { "hex.builtin.provider.file.access", "最後存取時間" }, + { "hex.builtin.provider.file.modification", "最後修改時間" }, { "hex.builtin.provider.gdb", "GDB 伺服器提供者" }, { "hex.builtin.provider.gdb.name", "GDB 伺服器 <{0}:{1}>" }, { "hex.builtin.provider.gdb.server", "伺服器" }, @@ -758,6 +757,10 @@ namespace hex::plugin::builtin { { "hex.builtin.provider.disk.disk_size", "Disk Size" }, { "hex.builtin.provider.disk.sector_size", "Sector Size" }, { "hex.builtin.provider.disk.reload", "Reload" }, + //{ "hex.builtin.provider.intel_hex", "Intel Hex Provider" }, + // { "hex.builtin.provider.intel_hex.name", "Intel Hex {0}" }, + //{ "hex.builtin.provider.motorola_srec", "Motorola SREC Provider" }, + // { "hex.builtin.provider.motorola_srec.name", "Motorola SREC {0}" }, { "hex.builtin.layouts.default", "預設" },