Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

PoC for the issue #980 #1449

Draft
wants to merge 1 commit into
base: master
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
14 changes: 13 additions & 1 deletion plugins/builtin/include/content/views/view_find.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -42,7 +42,8 @@ namespace hex::plugin::builtin {
Sequence,
Regex,
BinaryPattern,
Value
Value,
Approximate
} mode = Mode::Strings;

enum class StringType : int { ASCII = 0, UTF16LE = 1, UTF16BE = 2, ASCII_UTF16LE = 3, ASCII_UTF16BE = 4 };
Expand Down Expand Up @@ -93,6 +94,16 @@ namespace hex::plugin::builtin {
} type = Type::U8;
} value;

struct Approximate {
std::endian endian = std::endian::native;
bool aligned = true;
bool ignore_zeroes = true;
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Use camelCase


enum class Type {
F32 = 0, F64 = 1
} type = Type::F32;
} approximate;

} m_searchSettings, m_decodeSettings;

using OccurrenceTree = wolv::container::IntervalTree<Occurrence>;
Expand All @@ -111,6 +122,7 @@ namespace hex::plugin::builtin {
static std::vector<Occurrence> searchRegex(Task &task, prv::Provider *provider, Region searchRegion, const SearchSettings::Regex &settings);
static std::vector<Occurrence> searchBinaryPattern(Task &task, prv::Provider *provider, Region searchRegion, const SearchSettings::BinaryPattern &settings);
static std::vector<Occurrence> searchValue(Task &task, prv::Provider *provider, Region searchRegion, const SearchSettings::Value &settings);
static std::vector<Occurrence> searchApproximate(Task &task, prv::Provider *provider, Region searchRegion, const SearchSettings::Approximate &settings);

void drawContextMenu(Occurrence &target, const std::string &value);

Expand Down
3 changes: 3 additions & 0 deletions plugins/builtin/romfs/lang/en_US.json
Original file line number Diff line number Diff line change
Expand Up @@ -853,6 +853,9 @@
"hex.builtin.view.find.value.max": "Maximum Value",
"hex.builtin.view.find.value.min": "Minimum Value",
"hex.builtin.view.find.value.range": "Ranged Search",
"hex.builtin.view.find.approximate": "Almost integers",
"hex.builtin.view.find.approximate.aligned": "Aligned",
"hex.builtin.view.find.approximate.ignore_zeroes": "Skip zeroes",
"hex.builtin.view.hashes.function": "Hash function",
"hex.builtin.view.hashes.hash": "Hash",
"hex.builtin.view.hashes.hover_info": "Hover over the Hex Editor selection and hold down SHIFT to view the hashes of that region.",
Expand Down
107 changes: 107 additions & 0 deletions plugins/builtin/source/content/views/view_find.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -437,6 +437,62 @@ namespace hex::plugin::builtin {
return results;
}

std::vector<ViewFind::Occurrence> ViewFind::searchApproximate(Task &task, prv::Provider *provider, Region searchRegion, const SearchSettings::Approximate &settings) {
std::vector<Occurrence> results;

auto reader = prv::ProviderReader(provider);
reader.seek(searchRegion.getStartAddress());
reader.setEndAddress(searchRegion.getEndAddress());

using FloatingType = ViewFind::SearchSettings::Approximate::Type;
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

FloatingPointType


const size_t size = settings.type == FloatingType::F32 ? sizeof(float) : sizeof(double);
const auto advance = settings.aligned ? size : 1;

std::variant<float, double> floating_var;
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Use a more descriptive name for this. What does the variable do?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I've adapted the code for the Numeric search as we may want to add more floating types here. Please note that you used a return value of parseNumericValueInput (the middle one, min), which I thought was a dirty trick to acquire an instance of std::variant. So I made my own here.

if (settings.type == FloatingType::F32) {
floating_var = 0.F;
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

0.0F
I'd probably also be explicit here and use float(0) and double(0) to make sure the right alternative is being set in the variant

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The literal suffix "f" (or "F" which Clang-tidy wanted me to use) is used to turn doubles into floats. It's what forces std::variant to accept the desired type.

Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I know the suffix makes it a float but explicitly writing out the type is better in my opinion

} else {
floating_var = 0.0;
}

for (u64 address = searchRegion.getStartAddress(); address <= searchRegion.getEndAddress() - size + 1; address += advance) {
task.update(address);

auto result = std::visit([&]<typename T>(T) {
using DecayedType = std::remove_cvref_t<std::decay_t<T>>;

DecayedType value = 0;
reader.read(address, reinterpret_cast<u8*>(&value), size);
value = hex::changeEndianess(value, size, settings.endian);

if (settings.ignore_zeroes && value == T(0)) {
return false;
}

return std::floor(value) == value;
}, floating_var);

if (result) {
Occurrence::DecodeType decodeType = [&]{
switch (settings.type) {
using enum Occurrence::DecodeType;

case FloatingType::F32:
return Float;
case FloatingType::F64:
return Double;
default:
return Binary;
}
}();

results.push_back(Occurrence { Region { address, size }, decodeType, settings.endian, false });
}
}
return results;
}

void ViewFind::runSearch() {
Region searchRegion = this->m_searchSettings.region;

Expand Down Expand Up @@ -472,6 +528,9 @@ namespace hex::plugin::builtin {
case Value:
this->m_foundOccurrences.get(provider) = searchValue(task, provider, searchRegion, settings.value);
break;
case Approximate:
this->m_foundOccurrences.get(provider) = searchApproximate(task, provider, searchRegion, settings.approximate);
break;
}

this->m_sortedOccurrences.get(provider) = this->m_foundOccurrences.get(provider);
Expand All @@ -494,6 +553,7 @@ namespace hex::plugin::builtin {
using enum SearchSettings::Mode;

case Value:
case Approximate:
case Strings:
{
switch (occurrence.decodeType) {
Expand Down Expand Up @@ -800,6 +860,53 @@ namespace hex::plugin::builtin {

ImGui::EndTabItem();
}
if (ImGui::BeginTabItem("hex.builtin.view.find.approximate"_lang)) {
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Does it make sense to separate this out to a separate search tool instead of merging it into the numeric find tool?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

image
How would it fit here? I'm not trying to say it's impossible, just show me your PoC.

Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I didn't compile it yet but if it's just a few extra options, they could be hidden unless a floating point type is selected.
I'm fine with having it as a separate tool too but functionality-wise it would fit in the Numeric search tool

auto &settings = this->m_searchSettings.approximate;

mode = SearchSettings::Mode::Approximate;

this->m_settingsValid = true;

const std::array<std::string, 2> InputTypes = {
"hex.builtin.common.type.f32"_lang,
"hex.builtin.common.type.f64"_lang
};

if (ImGui::BeginCombo("hex.builtin.common.type"_lang, InputTypes[std::to_underlying(settings.type)].c_str())) {
for (size_t i = 0; i < InputTypes.size(); i++) {
auto type = static_cast<SearchSettings::Approximate::Type>(i);

if (ImGui::Selectable(InputTypes[i].c_str(), type == settings.type)) {
settings.type = type;
}
}
ImGui::EndCombo();
}

{
int selection = [&] {
switch (settings.endian) {
default:
case std::endian::little: return 0;
case std::endian::big: return 1;
}
}();

std::array options = { "hex.builtin.common.little"_lang, "hex.builtin.common.big"_lang };
if (ImGui::SliderInt("hex.builtin.common.endian"_lang, &selection, 0, options.size() - 1, options[selection], ImGuiSliderFlags_NoInput)) {
switch (selection) {
default:
case 0: settings.endian = std::endian::little; break;
case 1: settings.endian = std::endian::big; break;
}
}
}

ImGui::Checkbox("hex.builtin.view.find.approximate.aligned"_lang, &settings.aligned);
ImGui::Checkbox("hex.builtin.view.find.approximate.ignore_zeroes"_lang, &settings.ignore_zeroes);

ImGui::EndTabItem();
}

ImGui::EndTabBar();
}
Expand Down