1 #include "views/view_strings.hpp" 2 3 #include <hex/providers/provider.hpp> 4 #include <hex/helpers/utils.hpp> 5 6 #include <cstring> 7 8 #include <llvm/Demangle/Demangle.h> 9 10 using namespace std::literals::string_literals; 11 12 namespace hex { 13 ViewStrings()14 ViewStrings::ViewStrings() : View("hex.view.strings.title"_lang) { 15 View::subscribeEvent(Events::DataChanged, [this](auto){ 16 this->m_foundStrings.clear(); 17 }); 18 19 this->m_filter.resize(0xFFFF, 0x00); 20 } 21 ~ViewStrings()22 ViewStrings::~ViewStrings() { 23 View::unsubscribeEvent(Events::DataChanged); 24 } 25 26 createStringContextMenu(const FoundString & foundString)27 void ViewStrings::createStringContextMenu(const FoundString &foundString) { 28 if (ImGui::TableGetColumnFlags(2) == ImGuiTableColumnFlags_IsHovered && ImGui::IsMouseReleased(1) && ImGui::IsItemHovered()) { 29 ImGui::OpenPopup("StringContextMenu"); 30 this->m_selectedString = foundString.string; 31 } 32 if (ImGui::BeginPopup("StringContextMenu")) { 33 if (ImGui::MenuItem("hex.view.strings.copy"_lang)) { 34 ImGui::SetClipboardText(this->m_selectedString.c_str()); 35 } 36 ImGui::Separator(); 37 if (ImGui::MenuItem("hex.view.strings.demangle"_lang)) { 38 this->m_demangledName = llvm::demangle(this->m_selectedString); 39 if (!this->m_demangledName.empty()) 40 View::doLater([]{ ImGui::OpenPopup("hex.view.strings.demangle.title"_lang); }); 41 } 42 ImGui::EndPopup(); 43 } 44 } 45 46 drawContent()47 void ViewStrings::drawContent() { 48 auto provider = SharedData::currentProvider; 49 50 if (this->m_shouldInvalidate) { 51 this->m_shouldInvalidate = false; 52 53 this->m_foundStrings.clear(); 54 55 std::vector<u8> buffer(1024, 0x00); 56 u32 foundCharacters = 0; 57 58 for (u64 offset = 0; offset < provider->getSize(); offset += buffer.size()) { 59 size_t readSize = std::min(u64(buffer.size()), provider->getSize() - offset); 60 provider->read(offset, buffer.data(), readSize); 61 62 for (u32 i = 0; i < readSize; i++) { 63 if (buffer[i] >= 0x20 && buffer[i] <= 0x7E) 64 foundCharacters++; 65 else { 66 if (foundCharacters >= this->m_minimumLength) { 67 FoundString foundString; 68 69 foundString.offset = offset + i - foundCharacters; 70 foundString.size = foundCharacters; 71 foundString.string.reserve(foundCharacters); 72 foundString.string.resize(foundCharacters); 73 provider->read(foundString.offset, foundString.string.data(), foundCharacters); 74 75 this->m_foundStrings.push_back(foundString); 76 } 77 78 foundCharacters = 0; 79 } 80 } 81 } 82 } 83 84 85 if (ImGui::Begin("Strings", &this->getWindowOpenState(), ImGuiWindowFlags_NoCollapse)) { 86 if (provider != nullptr && provider->isReadable()) { 87 if (ImGui::InputInt("hex.view.strings.min_length"_lang, &this->m_minimumLength, 1, 0)) 88 this->m_shouldInvalidate = true; 89 90 ImGui::InputText("hex.view.strings.filter"_lang, this->m_filter.data(), this->m_filter.size()); 91 if (ImGui::Button("hex.view.strings.extract"_lang)) 92 this->m_shouldInvalidate = true; 93 94 ImGui::Separator(); 95 ImGui::NewLine(); 96 97 if (ImGui::BeginTable("##strings", 3, 98 ImGuiTableFlags_Borders | ImGuiTableFlags_Resizable | ImGuiTableFlags_Sortable | 99 ImGuiTableFlags_Reorderable | ImGuiTableFlags_RowBg | ImGuiTableFlags_ScrollY)) { 100 ImGui::TableSetupScrollFreeze(0, 1); 101 ImGui::TableSetupColumn("hex.view.strings.offset"_lang, 0, -1, ImGui::GetID("offset")); 102 ImGui::TableSetupColumn("hex.view.strings.size"_lang, 0, -1, ImGui::GetID("size")); 103 ImGui::TableSetupColumn("hex.view.strings.string"_lang, 0, -1, ImGui::GetID("string")); 104 105 auto sortSpecs = ImGui::TableGetSortSpecs(); 106 107 if (sortSpecs->SpecsDirty) { 108 std::sort(this->m_foundStrings.begin(), this->m_foundStrings.end(), 109 [&sortSpecs](FoundString &left, FoundString &right) -> bool { 110 if (sortSpecs->Specs->ColumnUserID == ImGui::GetID("offset")) { 111 if (sortSpecs->Specs->SortDirection == ImGuiSortDirection_Ascending) 112 return left.offset > right.offset; 113 else 114 return left.offset < right.offset; 115 } else if (sortSpecs->Specs->ColumnUserID == ImGui::GetID("size")) { 116 if (sortSpecs->Specs->SortDirection == ImGuiSortDirection_Ascending) 117 return left.size > right.size; 118 else 119 return left.size < right.size; 120 } else if (sortSpecs->Specs->ColumnUserID == ImGui::GetID("string")) { 121 if (sortSpecs->Specs->SortDirection == ImGuiSortDirection_Ascending) 122 return left.string > right.string; 123 else 124 return left.string < right.string; 125 } 126 127 return false; 128 }); 129 130 sortSpecs->SpecsDirty = false; 131 } 132 133 ImGui::TableHeadersRow(); 134 135 ImGuiListClipper clipper; 136 clipper.Begin(this->m_foundStrings.size()); 137 138 while (clipper.Step()) { 139 for (u64 i = clipper.DisplayStart; i < clipper.DisplayEnd; i++) { 140 auto &foundString = this->m_foundStrings[i]; 141 142 if (strlen(this->m_filter.data()) != 0 && 143 foundString.string.find(this->m_filter.data()) == std::string::npos) 144 continue; 145 146 ImGui::TableNextRow(); 147 ImGui::TableNextColumn(); 148 if (ImGui::Selectable(("##StringLine"s + std::to_string(i)).c_str(), false, ImGuiSelectableFlags_SpanAllColumns)) { 149 Region selectRegion = { foundString.offset, foundString.size }; 150 View::postEvent(Events::SelectionChangeRequest, selectRegion); 151 } 152 ImGui::PushID(i + 1); 153 createStringContextMenu(foundString); 154 ImGui::PopID(); 155 ImGui::SameLine(); 156 ImGui::Text("0x%08lx : 0x%08lx", foundString.offset, foundString.offset + foundString.size); 157 ImGui::TableNextColumn(); 158 ImGui::Text("0x%04lx", foundString.size); 159 ImGui::TableNextColumn(); 160 ImGui::Text("%s", foundString.string.c_str()); 161 } 162 } 163 clipper.End(); 164 165 ImGui::EndTable(); 166 } 167 } 168 } 169 ImGui::End(); 170 171 if (ImGui::BeginPopup("hex.view.strings.demangle.title"_lang)) { 172 if (ImGui::BeginChild("##scrolling", ImVec2(500, 150))) { 173 ImGui::TextUnformatted("hex.view.strings.demangle.title"_lang); 174 ImGui::Separator(); 175 ImGui::TextWrapped("%s", this->m_demangledName.c_str()); 176 ImGui::EndChild(); 177 ImGui::NewLine(); 178 if (ImGui::Button("hex.view.strings.demangle.copy"_lang)) 179 ImGui::SetClipboardText(this->m_demangledName.c_str()); 180 } 181 ImGui::EndPopup(); 182 } 183 } 184 drawMenu()185 void ViewStrings::drawMenu() { 186 187 } 188 189 }