diff --git a/include/helpers/event.hpp b/include/helpers/event.hpp index ca17c68d8..b6d016eba 100644 --- a/include/helpers/event.hpp +++ b/include/helpers/event.hpp @@ -23,7 +23,7 @@ namespace hex { }; struct EventHandler { - void *sender; + void *owner; Events eventType; std::function callback; }; @@ -37,17 +37,17 @@ namespace hex { handler.callback(userData); } - void subscribe(Events eventType, void *sender, std::function callback) { + void subscribe(Events eventType, void *owner, std::function callback) { for (auto &handler : this->m_eventHandlers) - if (eventType == handler.eventType && sender == handler.sender) + if (eventType == handler.eventType && owner == handler.owner) return; - this->m_eventHandlers.push_back(EventHandler { sender, eventType, callback }); + this->m_eventHandlers.push_back(EventHandler { owner, eventType, callback }); } void unsubscribe(Events eventType, void *sender) { std::erase_if(this->m_eventHandlers, [&eventType, &sender](EventHandler handler) { - return eventType == handler.eventType && sender == handler.sender; + return eventType == handler.eventType && sender == handler.owner; }); } diff --git a/include/views/view_data_inspector.hpp b/include/views/view_data_inspector.hpp index ea9c8e37e..5526f7ef4 100644 --- a/include/views/view_data_inspector.hpp +++ b/include/views/view_data_inspector.hpp @@ -41,6 +41,14 @@ namespace hex { GUID guid; }; + struct CachedData { + CachedData(std::string name, std::string value, size_t size) : name(name), value(value), size(size) { } + + std::string name; + std::string value; + size_t size; + }; + class ViewDataInspector : public View { public: explicit ViewDataInspector(prv::Provider* &dataProvider); @@ -57,7 +65,7 @@ namespace hex { PreviewData m_previewData = { 0 }; size_t m_validBytes = 0; - std::vector> m_cachedData; + std::vector m_cachedData; }; } \ No newline at end of file diff --git a/libs/ImGui/include/imgui_memory_editor.h b/libs/ImGui/include/imgui_memory_editor.h index 4cfa73648..1cc0a7d3c 100644 --- a/libs/ImGui/include/imgui_memory_editor.h +++ b/libs/ImGui/include/imgui_memory_editor.h @@ -93,8 +93,10 @@ struct MemoryEditor // [Internal State] bool ContentsWidthChanged; size_t DataPreviewAddr; - size_t DataEditingAddr; + size_t DataPreviewAddrOld; size_t DataPreviewAddrEnd; + size_t DataPreviewAddrEndOld; + size_t DataEditingAddr; bool DataEditingTakeFocus; char DataInputBuf[32]; char AddrInputBuf[32]; @@ -187,6 +189,14 @@ struct MemoryEditor if (ImGui::Begin(title, p_open, ImGuiWindowFlags_NoScrollbar | ImGuiWindowFlags_NoCollapse)) { + if (DataPreviewAddr != DataPreviewAddrOld || DataPreviewAddrEnd != DataPreviewAddrEndOld) { + hex::Region selectionRegion = { std::min(DataPreviewAddr, DataPreviewAddrEnd), std::max(DataPreviewAddr, DataPreviewAddrEnd) - std::min(DataPreviewAddr, DataPreviewAddrEnd) }; + hex::View::postEvent(hex::Events::RegionSelected, &selectionRegion); + } + + DataPreviewAddrOld = DataPreviewAddr; + DataPreviewAddrEndOld = DataPreviewAddrEnd; + DrawContents(mem_data, mem_size, base_display_addr); if (ContentsWidthChanged) { @@ -436,17 +446,9 @@ struct MemoryEditor DataPreviewAddr = addr; DataPreviewAddrEnd = addr; - - hex::Region selectionRegion { addr, 1 }; - hex::View::postEvent(hex::Events::RegionSelected, &selectionRegion); } if (ImGui::IsItemHovered() && ((ImGui::IsMouseClicked(0) && ImGui::GetIO().KeyShift) || ImGui::IsMouseDragging(0))) { DataPreviewAddrEnd = addr; - - size_t dataPreviewStart = std::min(DataPreviewAddr, DataPreviewAddrEnd); - - hex::Region selectionRegion { std::min(DataPreviewAddr, DataPreviewAddrEnd), std::max(DataPreviewAddr, DataPreviewAddrEnd) - std::min(DataPreviewAddr, DataPreviewAddrEnd) + 1 }; - hex::View::postEvent(hex::Events::RegionSelected, &selectionRegion); } } } diff --git a/source/views/view_data_inspector.cpp b/source/views/view_data_inspector.cpp index 8b41313a8..6e3387418 100644 --- a/source/views/view_data_inspector.cpp +++ b/source/views/view_data_inspector.cpp @@ -13,6 +13,16 @@ namespace hex { View::subscribeEvent(Events::RegionSelected, [this](const void* userData){ Region region = *static_cast(userData); + if (this->m_dataProvider == nullptr) { + this->m_validBytes = 0; + return; + } + + if (region.address == (size_t)-1) { + this->m_validBytes = 0; + return; + } + this->m_validBytes = std::min(u64(this->m_dataProvider->getSize() - region.address), u64(sizeof(PreviewData))); std::memset(&this->m_previewData, 0x00, sizeof(PreviewData)); this->m_dataProvider->read(region.address, &this->m_previewData, this->m_validBytes); @@ -35,20 +45,20 @@ namespace hex { std::string binary; for (u8 i = 0; i < 8; i++) binary += ((this->m_previewData.unsigned8 << i) & 0x80) == 0 ? '0' : '1'; - this->m_cachedData.emplace_back("Binary (8 bit)", binary); + this->m_cachedData.emplace_back("Binary (8 bit)", binary, sizeof(u8)); } - this->m_cachedData.emplace_back("uint8_t", hex::format("%u", hex::changeEndianess(this->m_previewData.unsigned8, this->m_endianess))); - this->m_cachedData.emplace_back("int8_t", hex::format("%d", hex::changeEndianess(this->m_previewData.signed8, this->m_endianess))); - this->m_cachedData.emplace_back("uint16_t", hex::format("%u", hex::changeEndianess(this->m_previewData.unsigned16, this->m_endianess))); - this->m_cachedData.emplace_back("int16_t", hex::format("%d", hex::changeEndianess(this->m_previewData.signed16, this->m_endianess))); - this->m_cachedData.emplace_back("uint32_t", hex::format("%lu", hex::changeEndianess(this->m_previewData.unsigned32, this->m_endianess))); - this->m_cachedData.emplace_back("int32_t", hex::format("%ld", hex::changeEndianess(this->m_previewData.signed32, this->m_endianess))); - this->m_cachedData.emplace_back("uint64_t", hex::format("%llu", hex::changeEndianess(this->m_previewData.unsigned64, this->m_endianess))); - this->m_cachedData.emplace_back("int64_t", hex::format("%lld", hex::changeEndianess(this->m_previewData.signed64, this->m_endianess))); + this->m_cachedData.emplace_back("uint8_t", hex::format("%u", hex::changeEndianess(this->m_previewData.unsigned8, this->m_endianess)), sizeof(u8)); + this->m_cachedData.emplace_back("int8_t", hex::format("%d", hex::changeEndianess(this->m_previewData.signed8, this->m_endianess)), sizeof(s8)); + this->m_cachedData.emplace_back("uint16_t", hex::format("%u", hex::changeEndianess(this->m_previewData.unsigned16, this->m_endianess)), sizeof(u16)); + this->m_cachedData.emplace_back("int16_t", hex::format("%d", hex::changeEndianess(this->m_previewData.signed16, this->m_endianess)), sizeof(s16)); + this->m_cachedData.emplace_back("uint32_t", hex::format("%lu", hex::changeEndianess(this->m_previewData.unsigned32, this->m_endianess)), sizeof(u32)); + this->m_cachedData.emplace_back("int32_t", hex::format("%ld", hex::changeEndianess(this->m_previewData.signed32, this->m_endianess)), sizeof(s32)); + this->m_cachedData.emplace_back("uint64_t", hex::format("%llu", hex::changeEndianess(this->m_previewData.unsigned64, this->m_endianess)), sizeof(u64)); + this->m_cachedData.emplace_back("int64_t", hex::format("%lld", hex::changeEndianess(this->m_previewData.signed64, this->m_endianess)), sizeof(s64)); - this->m_cachedData.emplace_back("ASCII Character", hex::format("'%s'", makePrintable(this->m_previewData.ansiChar).c_str())); - this->m_cachedData.emplace_back("Wide Character", hex::format("'%lc'", this->m_previewData.wideChar == 0 ? '\x01' : hex::changeEndianess(this->m_previewData.wideChar, this->m_endianess))); + this->m_cachedData.emplace_back("ASCII Character", hex::format("'%s'", makePrintable(this->m_previewData.ansiChar).c_str()), sizeof(char)); + this->m_cachedData.emplace_back("Wide Character", hex::format("'%lc'", this->m_previewData.wideChar == 0 ? '\x01' : hex::changeEndianess(this->m_previewData.wideChar, this->m_endianess)), sizeof(wchar_t)); { char buffer[5] = { 0 }; char codepointString[5] = { 0 }; @@ -58,11 +68,11 @@ namespace hex { u8 codepointSize = ImTextCharFromUtf8(&codepoint, buffer, buffer + 4); std::memcpy(codepointString, &codepoint, std::min(codepointSize, u8(4))); - this->m_cachedData.emplace_back("UTF-8 code point", hex::format("'%s' (U+%04lx)", codepoint == 0xFFFD ? "Invalid" : codepointString, codepoint)); + this->m_cachedData.emplace_back("UTF-8 code point", hex::format("'%s' (U+%04lx)", codepoint == 0xFFFD ? "Invalid" : codepointString, codepoint), sizeof(char8_t)); } - this->m_cachedData.emplace_back("float (32 bit)", hex::format("%e", hex::changeEndianess(this->m_previewData.float32, this->m_endianess))); - this->m_cachedData.emplace_back("double (64 bit)", hex::format("%e", hex::changeEndianess(this->m_previewData.float64, this->m_endianess))); + this->m_cachedData.emplace_back("float (32 bit)", hex::format("%e", hex::changeEndianess(this->m_previewData.float32, this->m_endianess)), sizeof(float)); + this->m_cachedData.emplace_back("double (64 bit)", hex::format("%e", hex::changeEndianess(this->m_previewData.float64, this->m_endianess)), sizeof(double)); #if defined(_WIN64) { @@ -70,9 +80,9 @@ namespace hex { std::tm * ptm = _localtime32(&endianAdjustedTime); char buffer[32]; if (ptm != nullptr && std::strftime(buffer, 32, "%a, %d.%m.%Y %H:%M:%S", ptm)) - this->m_cachedData.emplace_back("__time32_t", buffer); + this->m_cachedData.emplace_back("__time32_t", buffer, sizeof(__time32_t)); else - this->m_cachedData.emplace_back("__time32_t", "Invalid"); + this->m_cachedData.emplace_back("__time32_t", "Invalid", sizeof(__time32_t)); } { @@ -80,9 +90,9 @@ namespace hex { std::tm * ptm = _localtime64(&endianAdjustedTime); char buffer[64]; if (ptm != nullptr && std::strftime(buffer, 64, "%a, %d.%m.%Y %H:%M:%S", ptm) != 0) - this->m_cachedData.emplace_back("__time64_t", buffer); + this->m_cachedData.emplace_back("__time64_t", buffer, sizeof(__time64_t)); else - this->m_cachedData.emplace_back("__time64_t", "Invalid"); + this->m_cachedData.emplace_back("__time64_t", "Invalid", sizeof(__time64_t)); } #else { @@ -90,9 +100,9 @@ namespace hex { std::tm * ptm = localtime(&endianAdjustedTime); char buffer[64]; if (ptm != nullptr && std::strftime(buffer, 64, "%a, %d.%m.%Y %H:%M:%S", ptm) != 0) - this->m_cachedData.emplace_back("time_t", buffer); + this->m_cachedData.emplace_back("time_t", buffer, sizeof(time_t)); else - this->m_cachedData.emplace_back("time_t", "Invalid"); + this->m_cachedData.emplace_back("time_t", "Invalid", sizeof(time_t)); } #endif @@ -102,7 +112,8 @@ namespace hex { hex::changeEndianess(this->m_previewData.guid.data2, this->m_endianess), hex::changeEndianess(this->m_previewData.guid.data3, this->m_endianess), this->m_previewData.guid.data4[0], this->m_previewData.guid.data4[1], this->m_previewData.guid.data4[2], this->m_previewData.guid.data4[3], - this->m_previewData.guid.data4[4], this->m_previewData.guid.data4[5], this->m_previewData.guid.data4[6], this->m_previewData.guid.data4[7])); + this->m_previewData.guid.data4[4], this->m_previewData.guid.data4[5], this->m_previewData.guid.data4[6], this->m_previewData.guid.data4[7]), + sizeof(GUID)); } @@ -115,7 +126,9 @@ namespace hex { ImGui::TableHeadersRow(); - for (const auto &[name, value] : this->m_cachedData) { + for (const auto &[name, value, size] : this->m_cachedData) { + if (this->m_validBytes < size) continue; + ImGui::TableNextRow(); ImGui::TableNextColumn(); ImGui::TextUnformatted(name.c_str()); @@ -123,7 +136,7 @@ namespace hex { ImGui::TextUnformatted(value.c_str()); } - { + if (this->m_validBytes >= 4) { ImGui::TableNextRow(); ImGui::TableNextColumn(); ImGui::TextUnformatted("RGBA Color");