mirror of
https://github.com/WerWolv/ImHex.git
synced 2026-03-27 23:37:05 -05:00
feat: Allow integer literals to be used in binary patterns
This commit is contained in:
@@ -42,6 +42,7 @@ set(LIBIMHEX_SOURCES
|
||||
source/helpers/keys.cpp
|
||||
source/helpers/udp_server.cpp
|
||||
source/helpers/scaling.cpp
|
||||
source/helpers/binary_pattern.cpp
|
||||
|
||||
source/test/tests.cpp
|
||||
|
||||
|
||||
@@ -10,92 +10,19 @@ namespace hex {
|
||||
|
||||
class BinaryPattern {
|
||||
public:
|
||||
BinaryPattern() = default;
|
||||
explicit BinaryPattern(const std::string &pattern);
|
||||
|
||||
[[nodiscard]] bool isValid() const;
|
||||
[[nodiscard]] u64 getSize() const;
|
||||
|
||||
[[nodiscard]] bool matches(const std::vector<u8> &bytes) const;
|
||||
[[nodiscard]] bool matchesByte(u8 byte, u32 offset) const;
|
||||
|
||||
struct Pattern {
|
||||
u8 mask, value;
|
||||
};
|
||||
|
||||
BinaryPattern() = default;
|
||||
explicit BinaryPattern(const std::string &pattern) : m_patterns(parseBinaryPatternString(pattern)) { }
|
||||
|
||||
[[nodiscard]] bool isValid() const { return !m_patterns.empty(); }
|
||||
|
||||
[[nodiscard]] bool matches(const std::vector<u8> &bytes) const {
|
||||
if (bytes.size() < m_patterns.size())
|
||||
return false;
|
||||
|
||||
for (u32 i = 0; i < m_patterns.size(); i++) {
|
||||
if (!this->matchesByte(bytes[i], i))
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
[[nodiscard]] bool matchesByte(u8 byte, u32 offset) const {
|
||||
const auto &pattern = m_patterns[offset];
|
||||
|
||||
return (byte & pattern.mask) == pattern.value;
|
||||
}
|
||||
|
||||
[[nodiscard]] u64 getSize() const {
|
||||
return m_patterns.size();
|
||||
}
|
||||
|
||||
private:
|
||||
static std::vector<Pattern> parseBinaryPatternString(std::string string) {
|
||||
std::vector<Pattern> result;
|
||||
|
||||
if (string.length() < 2)
|
||||
return { };
|
||||
|
||||
bool inString = false;
|
||||
while (string.length() > 0) {
|
||||
Pattern pattern = { 0, 0 };
|
||||
if (string.starts_with("\"")) {
|
||||
inString = !inString;
|
||||
string = string.substr(1);
|
||||
continue;
|
||||
} else if (inString) {
|
||||
pattern = { 0xFF, u8(string.front()) };
|
||||
string = string.substr(1);
|
||||
} else if (string.starts_with("??")) {
|
||||
pattern = { 0x00, 0x00 };
|
||||
string = string.substr(2);
|
||||
} else if ((std::isxdigit(string.front()) || string.front() == '?') && string.length() >= 2) {
|
||||
const auto hex = string.substr(0, 2);
|
||||
|
||||
for (const auto &c : hex) {
|
||||
pattern.mask <<= 4;
|
||||
pattern.value <<= 4;
|
||||
|
||||
if (std::isxdigit(c)) {
|
||||
pattern.mask |= 0x0F;
|
||||
|
||||
if (auto hexValue = hex::hexCharToValue(c); hexValue.has_value())
|
||||
pattern.value |= hexValue.value();
|
||||
else
|
||||
return { };
|
||||
} else if (c != '?') {
|
||||
return { };
|
||||
}
|
||||
}
|
||||
|
||||
string = string.substr(2);
|
||||
} else if (std::isspace(string.front())) {
|
||||
string = string.substr(1);
|
||||
continue;
|
||||
} else {
|
||||
return { };
|
||||
}
|
||||
|
||||
result.push_back(pattern);
|
||||
}
|
||||
|
||||
if (inString)
|
||||
return { };
|
||||
|
||||
return result;
|
||||
}
|
||||
private:
|
||||
std::vector<Pattern> m_patterns;
|
||||
};
|
||||
|
||||
173
lib/libimhex/source/helpers/binary_pattern.cpp
Normal file
173
lib/libimhex/source/helpers/binary_pattern.cpp
Normal file
@@ -0,0 +1,173 @@
|
||||
#include <hex/helpers/binary_pattern.hpp>
|
||||
|
||||
namespace hex {
|
||||
|
||||
namespace {
|
||||
|
||||
void skipWhitespace(std::string_view &string) {
|
||||
while (string.length() > 0) {
|
||||
if (!std::isspace(string.front()))
|
||||
break;
|
||||
string = string.substr(1);
|
||||
}
|
||||
}
|
||||
|
||||
std::vector<BinaryPattern::Pattern> parseValueExpression(std::string_view &string) {
|
||||
string = string.substr(1);
|
||||
|
||||
// Parse bit size number
|
||||
u64 bitSize = 0;
|
||||
std::endian endian = std::endian::little;
|
||||
while (!string.empty() && std::isdigit(string.front())) {
|
||||
bitSize *= 10;
|
||||
bitSize += string.front() - '0';
|
||||
|
||||
string = string.substr(1);
|
||||
skipWhitespace(string);
|
||||
}
|
||||
|
||||
if (string.starts_with("le")) {
|
||||
endian = std::endian::little;
|
||||
string = string.substr(2);
|
||||
} else if (string.starts_with("be")) {
|
||||
endian = std::endian::big;
|
||||
string = string.substr(2);
|
||||
}
|
||||
|
||||
if (bitSize > 64 || bitSize % 8 != 0)
|
||||
return { };
|
||||
|
||||
if (string.empty() || string.front() != '(')
|
||||
return { };
|
||||
|
||||
string = string.substr(1);
|
||||
|
||||
i128 value = 0x00;
|
||||
bool negative = false;
|
||||
for (u32 i = 0; !string.empty(); i++) {
|
||||
const char c = string.front();
|
||||
|
||||
if (c == ')') break;
|
||||
if (i == 0 && c == '-')
|
||||
negative = true;
|
||||
else if (i == 0 && c == '+')
|
||||
continue;
|
||||
else if (std::isdigit(c))
|
||||
value = value * 10 + (c - '0');
|
||||
else
|
||||
return {};
|
||||
|
||||
string = string.substr(1);
|
||||
}
|
||||
|
||||
if (negative)
|
||||
value = -value;
|
||||
|
||||
if (string.empty() || string.front() != ')')
|
||||
return { };
|
||||
|
||||
string = string.substr(1);
|
||||
|
||||
u128 resultValue = changeEndianness(value, bitSize / 8, endian);
|
||||
std::vector<BinaryPattern::Pattern> result;
|
||||
for (u32 bit = 0; bit < bitSize; bit += 8) {
|
||||
result.emplace_back(
|
||||
0xFF,
|
||||
u8((resultValue >> bit) & hex::bitmask(8))
|
||||
);
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
std::vector<BinaryPattern::Pattern> parseBinaryPatternString(std::string_view string) {
|
||||
std::vector<BinaryPattern::Pattern> result;
|
||||
|
||||
if (string.length() < 2)
|
||||
return { };
|
||||
|
||||
bool inString = false;
|
||||
while (string.length() > 0) {
|
||||
BinaryPattern::Pattern pattern = { 0, 0 };
|
||||
|
||||
if (string.starts_with("\"")) {
|
||||
inString = !inString;
|
||||
string = string.substr(1);
|
||||
continue;
|
||||
} else if (inString) {
|
||||
pattern = { 0xFF, u8(string.front()) };
|
||||
string = string.substr(1);
|
||||
} else if (string.starts_with("u") || string.starts_with("s")) {
|
||||
auto newPatterns = parseValueExpression(string);
|
||||
if (newPatterns.empty())
|
||||
return {};
|
||||
std::ranges::move(newPatterns, std::back_inserter(result));
|
||||
continue;
|
||||
} else if (string.starts_with("??")) {
|
||||
pattern = { 0x00, 0x00 };
|
||||
string = string.substr(2);
|
||||
} else if ((std::isxdigit(string.front()) || string.front() == '?') && string.length() >= 2) {
|
||||
const auto hex = string.substr(0, 2);
|
||||
|
||||
for (const auto &c : hex) {
|
||||
pattern.mask <<= 4;
|
||||
pattern.value <<= 4;
|
||||
|
||||
if (std::isxdigit(c)) {
|
||||
pattern.mask |= 0x0F;
|
||||
|
||||
if (auto hexValue = hex::hexCharToValue(c); hexValue.has_value())
|
||||
pattern.value |= hexValue.value();
|
||||
else
|
||||
return { };
|
||||
} else if (c != '?') {
|
||||
return { };
|
||||
}
|
||||
}
|
||||
|
||||
string = string.substr(2);
|
||||
} else if (std::isspace(string.front())) {
|
||||
string = string.substr(1);
|
||||
continue;
|
||||
} else {
|
||||
return { };
|
||||
}
|
||||
|
||||
result.push_back(pattern);
|
||||
}
|
||||
|
||||
if (inString)
|
||||
return { };
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
BinaryPattern::BinaryPattern(const std::string &pattern) : m_patterns(parseBinaryPatternString(pattern)) { }
|
||||
|
||||
bool BinaryPattern::isValid() const { return !m_patterns.empty(); }
|
||||
|
||||
bool BinaryPattern::matches(const std::vector<u8> &bytes) const {
|
||||
if (bytes.size() < m_patterns.size())
|
||||
return false;
|
||||
|
||||
for (u32 i = 0; i < m_patterns.size(); i++) {
|
||||
if (!this->matchesByte(bytes[i], i))
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool BinaryPattern::matchesByte(u8 byte, u32 offset) const {
|
||||
const auto &pattern = m_patterns[offset];
|
||||
|
||||
return (byte & pattern.mask) == pattern.value;
|
||||
}
|
||||
|
||||
u64 BinaryPattern::getSize() const {
|
||||
return m_patterns.size();
|
||||
}
|
||||
|
||||
}
|
||||
@@ -962,12 +962,13 @@ namespace hex::plugin::builtin {
|
||||
|
||||
mode = SearchSettings::Mode::BinaryPattern;
|
||||
|
||||
ImGuiExt::InputTextIconHint("hex.builtin.view.find.binary_pattern"_lang, ICON_VS_SYMBOL_NAMESPACE, "AA BB ?? ?D \"XYZ\"", settings.input);
|
||||
if (ImGuiExt::InputTextIconHint("hex.builtin.view.find.binary_pattern"_lang, ICON_VS_SYMBOL_NAMESPACE, "AA BB ?? ?D \"XYZ\" u32be(1234)", settings.input)) {
|
||||
settings.pattern = hex::BinaryPattern(settings.input);
|
||||
}
|
||||
|
||||
constexpr static u32 min = 1, max = 0x1000;
|
||||
ImGui::SliderScalar("hex.builtin.view.find.binary_pattern.alignment"_lang, ImGuiDataType_U32, &settings.alignment, &min, &max);
|
||||
|
||||
settings.pattern = hex::BinaryPattern(settings.input);
|
||||
m_settingsValid = settings.pattern.isValid() && settings.alignment > 0;
|
||||
|
||||
ImGui::EndTabItem();
|
||||
|
||||
Reference in New Issue
Block a user