1
0
mirror of synced 2024-12-14 00:32:52 +01:00
ImHex/lib/libimhex/include/hex/helpers/utils.hpp

417 lines
12 KiB
C++
Raw Normal View History

2020-12-27 14:12:53 +01:00
#pragma once
#include <hex.hpp>
2021-08-29 22:15:18 +02:00
#include <hex/helpers/concepts.hpp>
#include <hex/helpers/fs.hpp>
#include <hex/helpers/intrinsics.hpp>
2021-08-29 22:15:18 +02:00
2020-12-27 14:12:53 +01:00
#include <array>
#include <bit>
2021-01-07 01:58:56 +01:00
#include <cstring>
#include <cctype>
2020-12-27 14:12:53 +01:00
#include <functional>
2021-09-16 22:23:51 +02:00
#include <limits>
2020-12-27 14:12:53 +01:00
#include <memory>
#include <optional>
#include <string>
2021-01-02 20:49:55 +01:00
#include <type_traits>
#include <variant>
2020-12-27 14:12:53 +01:00
#include <vector>
#define TOKEN_CONCAT_IMPL(x, y) x##y
#define TOKEN_CONCAT(x, y) TOKEN_CONCAT_IMPL(x, y)
2021-03-31 22:54:43 +02:00
#define ANONYMOUS_VARIABLE(prefix) TOKEN_CONCAT(prefix, __COUNTER__)
struct ImVec2;
2020-12-27 14:12:53 +01:00
namespace hex {
long double operator""_scaled(long double value);
long double operator""_scaled(unsigned long long value);
ImVec2 scaled(const ImVec2 &vector);
std::string to_string(u128 value);
std::string to_string(i128 value);
2021-01-21 14:53:44 +01:00
std::string toByteString(u64 bytes);
std::string makePrintable(u8 c);
2021-01-21 14:53:44 +01:00
void runCommand(const std::string &command);
void openWebpage(std::string url);
2021-01-21 14:53:44 +01:00
std::string encodeByteString(const std::vector<u8> &bytes);
std::vector<u8> decodeByteString(const std::string &string);
[[nodiscard]] constexpr inline u64 extract(u8 from, u8 to, const hex::unsigned_integral auto &value) {
if (from < to) std::swap(from, to);
using ValueType = std::remove_cvref_t<decltype(value)>;
2022-02-01 22:09:44 +01:00
ValueType mask = (std::numeric_limits<ValueType>::max() >> (((sizeof(value) * 8) - 1) - (from - to))) << to;
2020-12-27 14:12:53 +01:00
return (value & mask) >> to;
}
2021-04-14 09:03:41 +02:00
[[nodiscard]] inline u64 extract(u32 from, u32 to, const std::vector<u8> &bytes) {
u8 index = 0;
while (from > 32 && to > 32) {
from -= 8;
to -= 8;
index++;
}
u64 value = 0;
std::memcpy(&value, &bytes[index], std::min(sizeof(value), bytes.size() - index));
u64 mask = (std::numeric_limits<u64>::max() >> (64 - (from + 1)));
return (value & mask) >> to;
}
constexpr inline i128 signExtend(size_t numBits, i128 value) {
i128 mask = 1U << (numBits - 1);
return (value ^ mask) - mask;
}
template<hex::integral T>
constexpr inline T swapBitOrder(size_t numBits, T value) {
T result = 0x00;
for (size_t bit = 0; bit < numBits; bit++) {
result <<= 1;
result |= (value & (1 << bit)) != 0;
}
return result;
}
template<class... Ts>
struct overloaded : Ts... { using Ts::operator()...; };
template<class... Ts>
overloaded(Ts...) -> overloaded<Ts...>;
template<size_t Size>
struct SizeTypeImpl { };
template<>
struct SizeTypeImpl<1> { using Type = u8; };
template<>
struct SizeTypeImpl<2> { using Type = u16; };
template<>
struct SizeTypeImpl<4> { using Type = u32; };
template<>
struct SizeTypeImpl<8> { using Type = u64; };
template<>
struct SizeTypeImpl<16> { using Type = u128; };
template<size_t Size>
using SizeType = typename SizeTypeImpl<Size>::Type;
2020-12-27 14:12:53 +01:00
template<typename T>
constexpr T changeEndianess(const T &value, std::endian endian) {
2020-12-27 14:12:53 +01:00
if (endian == std::endian::native)
return value;
constexpr auto Size = sizeof(T);
SizeType<Size> unswapped;
std::memcpy(&unswapped, &value, Size);
SizeType<Size> swapped;
if constexpr (!std::has_single_bit(Size) || Size > 16)
static_assert(always_false<T>::value, "Invalid type provided!");
switch (Size) {
2022-02-01 22:09:44 +01:00
case 1:
swapped = unswapped;
break;
case 2:
swapped = __builtin_bswap16(unswapped);
break;
case 4:
swapped = __builtin_bswap32(unswapped);
break;
case 8:
swapped = __builtin_bswap64(unswapped);
break;
case 16:
swapped = (u128(__builtin_bswap64(unswapped & 0xFFFF'FFFF'FFFF'FFFF)) << 64) | __builtin_bswap64(u128(unswapped) >> 64);
break;
default:
hex::unreachable();
}
T result;
std::memcpy(&result, &swapped, Size);
return result;
2020-12-27 14:12:53 +01:00
}
[[nodiscard]] constexpr u128 bitmask(u8 bits) {
return u128(-1) >> (128 - bits);
}
2020-12-27 14:12:53 +01:00
template<typename T>
constexpr T changeEndianess(T value, size_t size, std::endian endian) {
if (endian == std::endian::native)
return value;
u128 unswapped = 0;
std::memcpy(&unswapped, &value, size);
u128 swapped;
switch (size) {
2022-02-01 22:09:44 +01:00
case 1:
swapped = unswapped;
break;
case 2:
swapped = __builtin_bswap16(unswapped);
break;
case 4:
swapped = __builtin_bswap32(unswapped);
break;
case 8:
swapped = __builtin_bswap64(unswapped);
break;
case 16:
swapped = (u128(__builtin_bswap64(unswapped & 0xFFFF'FFFF'FFFF'FFFF)) << 64) | __builtin_bswap64(u128(unswapped) >> 64);
break;
default:
hex::unreachable();
}
2021-10-20 10:35:26 +02:00
T result = 0;
std::memcpy(&result, &swapped, size);
return result;
2020-12-27 14:12:53 +01:00
}
template<class T>
2020-12-27 14:12:53 +01:00
constexpr T bit_width(T x) noexcept {
return std::numeric_limits<T>::digits - std::countl_zero(x);
}
template<typename T>
constexpr T bit_ceil(T x) noexcept {
if (x <= 1u)
return T(1);
return T(1) << bit_width(T(x - 1));
}
ui/ux: Rewrite of the entire hex editor view to make it more flexible (#512) * ui/ux: Initial recreation of the hex editor view * ui/ux: Added back support for editing cells * ux: Make scrolling and selecting bytes feel nice again * ui/ux: Improved byte selecting, added footer * sys: Make math evaluator more generic to support integer only calculations * patterns: Moved value formatting into pattern language * ui/ux: Added Goto and Search popups, improved selection * ui: Added better tooltips for bookmarks and patterns * sys: Use worse hex search algorithm on macOS Sadly it still doesn't support `std::boyer_moore_horsepool_searcher` * ui: Added back missing events, menu items and shortcuts * fix: Bookmark highlighting being rendered off by one * fix: Various macOS build errors * fix: size_t is not u64 on macos * fix: std::fmod and std::pow not working with integer types on macos * fix: Missing semicolons * sys: Added proper integer pow function * ui: Added back support for custom encodings * fix: Editor not jumping to selection when selection gets changed * ui: Turn Hexii setting into a data visualizer * sys: Added back remaining shortcuts * sys: Remove old hex editor files * sys: Moved more legacy things away from the hex editor view, updated localization * fix: Hex editor scrolling behaving weirdly and inconsistently * sys: Cleaned up Hex editor code * sys: Added selection color setting, localized all new settings * fix: Search feature not working correctly * ui: Replace custom ImGui::Disabled function with native ImGui ones * ui: Fix bookmark tooltip rendering issues * fix: Another size_t not being 64 bit issue on MacOS
2022-05-27 20:42:07 +02:00
template<hex::integral T, hex::integral U>
auto powi(T base, U exp) {
using ResultType = decltype(T{} * U{});
if (exp < 0)
return ResultType(0);
ResultType result = 1;
while (exp != 0) {
if ((exp & 0b1) == 0b1)
result *= base;
exp >>= 1;
base *= base;
}
return result;
}
template<typename T, typename... Args>
void moveToVector(std::vector<T> &buffer, T &&first, Args &&...rest) {
buffer.push_back(std::move(first));
if constexpr (sizeof...(rest) > 0)
moveToVector(buffer, std::move(rest)...);
}
template<typename T, typename... Args>
std::vector<T> moveToVector(T &&first, Args &&...rest) {
std::vector<T> result;
moveToVector(result, T(std::move(first)), std::move(rest)...);
return result;
}
std::vector<std::string> splitString(const std::string &string, const std::string &delimiter);
std::string combineStrings(const std::vector<std::string> &strings, const std::string &delimiter = "");
std::string toEngineeringString(double value);
template<typename T>
std::vector<u8> toBytes(T value) {
std::vector<u8> bytes(sizeof(T));
std::memcpy(bytes.data(), &value, sizeof(T));
return bytes;
}
inline std::vector<u8> parseByteString(const std::string &string) {
auto byteString = std::string(string);
byteString.erase(std::remove(byteString.begin(), byteString.end(), ' '), byteString.end());
if ((byteString.length() % 2) != 0) return {};
std::vector<u8> result;
for (u32 i = 0; i < byteString.length(); i += 2) {
if (!std::isxdigit(byteString[i]) || !std::isxdigit(byteString[i + 1]))
return {};
result.push_back(std::strtoul(byteString.substr(i, 2).c_str(), nullptr, 16));
}
return result;
}
inline std::string toBinaryString(hex::unsigned_integral auto number) {
2021-02-07 22:57:34 +01:00
if (number == 0) return "0";
std::string result;
for (i16 bit = hex::bit_width(number) - 1; bit >= 0; bit--)
2021-02-07 22:57:34 +01:00
result += (number & (0b1 << bit)) == 0 ? '0' : '1';
return result;
}
inline void trimLeft(std::string &s) {
s.erase(s.begin(), std::find_if(s.begin(), s.end(), [](unsigned char ch) {
2022-02-01 22:09:44 +01:00
return !std::isspace(ch) && ch >= 0x20;
}));
}
inline void trimRight(std::string &s) {
s.erase(std::find_if(s.rbegin(), s.rend(), [](unsigned char ch) {
2022-02-01 22:09:44 +01:00
return !std::isspace(ch) && ch >= 0x20;
}).base(),
s.end());
}
inline void trim(std::string &s) {
trimLeft(s);
trimRight(s);
}
float float16ToFloat32(u16 float16);
inline bool equalsIgnoreCase(const std::string &left, const std::string &right) {
return std::equal(left.begin(), left.end(), right.begin(), right.end(), [](char a, char b) {
return tolower(a) == tolower(b);
});
}
inline bool containsIgnoreCase(const std::string &a, const std::string &b) {
auto iter = std::search(a.begin(), a.end(), b.begin(), b.end(), [](char ch1, char ch2) {
return std::toupper(ch1) == std::toupper(ch2);
});
return iter != a.end();
}
template<typename T, typename... VariantTypes>
T get_or(const std::variant<VariantTypes...> &variant, T alt) {
const T *value = std::get_if<T>(&variant);
if (value == nullptr)
return alt;
else
return *value;
}
ui/ux: Rewrite of the entire hex editor view to make it more flexible (#512) * ui/ux: Initial recreation of the hex editor view * ui/ux: Added back support for editing cells * ux: Make scrolling and selecting bytes feel nice again * ui/ux: Improved byte selecting, added footer * sys: Make math evaluator more generic to support integer only calculations * patterns: Moved value formatting into pattern language * ui/ux: Added Goto and Search popups, improved selection * ui: Added better tooltips for bookmarks and patterns * sys: Use worse hex search algorithm on macOS Sadly it still doesn't support `std::boyer_moore_horsepool_searcher` * ui: Added back missing events, menu items and shortcuts * fix: Bookmark highlighting being rendered off by one * fix: Various macOS build errors * fix: size_t is not u64 on macos * fix: std::fmod and std::pow not working with integer types on macos * fix: Missing semicolons * sys: Added proper integer pow function * ui: Added back support for custom encodings * fix: Editor not jumping to selection when selection gets changed * ui: Turn Hexii setting into a data visualizer * sys: Added back remaining shortcuts * sys: Remove old hex editor files * sys: Moved more legacy things away from the hex editor view, updated localization * fix: Hex editor scrolling behaving weirdly and inconsistently * sys: Cleaned up Hex editor code * sys: Added selection color setting, localized all new settings * fix: Search feature not working correctly * ui: Replace custom ImGui::Disabled function with native ImGui ones * ui: Fix bookmark tooltip rendering issues * fix: Another size_t not being 64 bit issue on MacOS
2022-05-27 20:42:07 +02:00
template<hex::integral T>
T alignTo(T value, T alignment) {
T remainder = value % alignment;
return remainder != 0 ? value + (alignment - remainder) : value;
}
bool isProcessElevated();
std::optional<std::string> getEnvironmentVariable(const std::string &env);
2021-08-28 00:45:59 +02:00
namespace scope_guard {
#define SCOPE_GUARD ::hex::scope_guard::ScopeGuardOnExit() + [&]()
#define ON_SCOPE_EXIT [[maybe_unused]] auto ANONYMOUS_VARIABLE(SCOPE_EXIT_) = SCOPE_GUARD
2021-08-28 00:45:59 +02:00
template<class F>
class ScopeGuard {
private:
F m_func;
bool m_active;
2021-08-28 00:45:59 +02:00
public:
explicit constexpr ScopeGuard(F func) : m_func(std::move(func)), m_active(true) { }
~ScopeGuard() {
if (this->m_active) { this->m_func(); }
}
2021-08-28 00:45:59 +02:00
void release() { this->m_active = false; }
ScopeGuard(ScopeGuard &&other) noexcept : m_func(std::move(other.m_func)), m_active(other.m_active) {
other.cancel();
}
ScopeGuard &operator=(ScopeGuard &&) = delete;
2021-08-28 00:45:59 +02:00
};
enum class ScopeGuardOnExit
{
};
2021-08-28 00:45:59 +02:00
template<typename F>
constexpr ScopeGuard<F> operator+(ScopeGuardOnExit, F &&f) {
2021-08-28 00:45:59 +02:00
return ScopeGuard<F>(std::forward<F>(f));
2020-12-27 14:12:53 +01:00
}
2021-08-28 00:45:59 +02:00
}
namespace first_time_exec {
#define FIRST_TIME [[maybe_unused]] static auto ANONYMOUS_VARIABLE(FIRST_TIME_) = ::hex::first_time_exec::FirstTimeExecutor() + [&]()
2020-12-27 14:12:53 +01:00
2021-08-28 00:45:59 +02:00
template<class F>
class FirstTimeExecute {
public:
explicit constexpr FirstTimeExecute(F func) { func(); }
2021-08-28 00:45:59 +02:00
FirstTimeExecute &operator=(FirstTimeExecute &&) = delete;
2021-08-28 00:45:59 +02:00
};
enum class FirstTimeExecutor
{
};
2021-08-28 00:45:59 +02:00
template<typename F>
constexpr FirstTimeExecute<F> operator+(FirstTimeExecutor, F &&f) {
2021-08-28 00:45:59 +02:00
return FirstTimeExecute<F>(std::forward<F>(f));
}
}
namespace final_cleanup {
#define FINAL_CLEANUP [[maybe_unused]] static auto ANONYMOUS_VARIABLE(ON_EXIT_) = ::hex::final_cleanup::FinalCleanupExecutor() + [&]()
2021-08-28 00:45:59 +02:00
template<class F>
class FinalCleanupExecute {
F m_func;
2021-08-28 00:45:59 +02:00
public:
explicit constexpr FinalCleanupExecute(F func) : m_func(func) { }
2021-08-28 00:45:59 +02:00
constexpr ~FinalCleanupExecute() { this->m_func(); }
FinalCleanupExecute &operator=(FinalCleanupExecute &&) = delete;
2021-08-28 00:45:59 +02:00
};
enum class FinalCleanupExecutor
{
};
2021-08-28 00:45:59 +02:00
template<typename F>
constexpr FinalCleanupExecute<F> operator+(FinalCleanupExecutor, F &&f) {
2021-08-28 00:45:59 +02:00
return FinalCleanupExecute<F>(std::forward<F>(f));
}
2021-03-31 22:54:43 +02:00
}
}