1
0
mirror of synced 2024-12-04 20:17:57 +01:00
ImHex/plugins/libimhex/include/hex/helpers/utils.hpp

260 lines
7.6 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>
2020-12-27 14:12:53 +01:00
#include <array>
2021-01-07 01:58:56 +01:00
#include <cstring>
2020-12-27 14:12:53 +01:00
#include <functional>
#include <memory>
#include <optional>
#include <string>
2021-01-02 20:49:55 +01:00
#include <type_traits>
2020-12-27 14:12:53 +01:00
#include <vector>
2021-08-28 00:45:59 +02:00
#include <nfd.hpp>
2021-08-29 22:15:18 +02:00
#if defined(OS_MACOS)
#define off64_t off_t
2020-12-27 15:54:12 +01:00
#define fopen64 fopen
#define fseeko64 fseek
#define ftello64 ftell
#endif
#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__)
2020-12-27 14:12:53 +01:00
namespace hex {
std::string to_string(u128 value);
std::string to_string(s128 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
[[nodiscard]] constexpr inline u64 extract(u8 from, u8 to, const hex::unsigned_integral auto &value) {
using ValueType = std::remove_cvref_t<decltype(value)>;
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
template<class... Ts> struct overloaded : Ts... { using Ts::operator()...; };
template<class... Ts> overloaded(Ts...) -> overloaded<Ts...>;
2020-12-27 14:12:53 +01:00
template<typename T>
constexpr T changeEndianess(T value, std::endian endian) {
if (endian == std::endian::native)
return value;
if constexpr (sizeof(T) == 1)
return value;
else if constexpr (sizeof(T) == 2)
return __builtin_bswap16(value);
else if constexpr (sizeof(T) == 4)
return __builtin_bswap32(value);
else if constexpr (sizeof(T) == 8)
return __builtin_bswap64(value);
2021-01-21 22:55:04 +01:00
else if constexpr (sizeof(T) == 16)
return T(__builtin_bswap64(value & 0xFFFF'FFFF'FFFF'FFFF)) << 64 | __builtin_bswap64(value >> 64);
2020-12-27 14:12:53 +01:00
else
2021-01-21 22:55:04 +01:00
static_assert(always_false<T>::value, "Invalid type provided!");
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;
if (size == 1)
return value;
else if (size == 2)
return __builtin_bswap16(value);
else if (size == 4)
return __builtin_bswap32(value);
else if (size == 8)
return __builtin_bswap64(value);
2021-01-21 22:55:04 +01:00
else if (size == 16)
return u128(__builtin_bswap64(u128(value) & 0xFFFF'FFFF'FFFF'FFFF)) << 64 | __builtin_bswap64(u128(value) >> 64);
2020-12-27 14:12:53 +01:00
else
throw std::invalid_argument("Invalid value size!");
}
template< class T >
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));
}
std::vector<std::string> splitString(std::string_view string, std::string_view delimiter);
std::string combineStrings(const std::vector<std::string> &strings, std::string_view delimiter = "");
std::string toEngineeringString(double value);
2020-12-27 14:12:53 +01:00
std::vector<u8> readFile(std::string_view path);
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(std::string_view 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 (s16 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) {
return !std::isspace(ch);
}));
}
inline void trimRight(std::string &s) {
s.erase(std::find_if(s.rbegin(), s.rend(), [](unsigned char ch) {
return !std::isspace(ch);
}).base(), s.end());
}
inline void trim(std::string &s) {
trimLeft(s);
trimRight(s);
}
sys/build: Properly support per-system metadata file paths (#181) * sys: Move away from metadata paths next to executable in the application Build system doesn't properly install / pack stuff yet * build: Updated README to contain better install instructions * sys: Search for imhex resource files in ~/Application Support * sys: MAX_PATH -> PATH_MAX * sys: Seach for imhex resource files in Application Support using NSFileManager (#180) * sys: Allow for multiple file search paths Also use install prefix instead of just /usr on Linux * build: Fixed IMHEX_INSTALL_PREFIX macro definition * build: Fix duplicate switch entry on Linux * docs: Updated readme to properly reflect new paths and dependencies * sys: Install files in their proper paths on linux (#183) * Install files in their proper paths on linux * Only create user directories * Follow the XDG specification on linux XDG specification specifies how to find config and data directories on linux systems. Specifically, it says this: - Data should be written to $XDG_DATA_HOME - Config should be written to $XDG_CONFIG_HOME - Data should be read from $XDG_DATA_HOME:$XDG_DATA_DIRS - Config should be read from $XDG_CONFIG_HOME:$XDG_CONFIG_DIRS The default values are this: - XDG_DATA_HOME: $HOME/.local/share - XDG_CONFIG_HOME: $HOME/.config - XDG_DATA_DIRS: /usr/share:/usr/local/share - XDG_CONFIG_DIRS: /etc/xdg Platforms with non-standard filesystems (like NixOS) will correctly set up those environment variables, allowing softwares to work unmodified. In order to make integration as simple as possible, we use a simple header-only dependency called XDGPP which does all the hard work for us to find the default directories. * Look for plugins in all Plugin Paths If the plugin folder was missing from one of the PluginPaths, we would immediately stop loading plugins. We now keep looking even if one of the path is missing. Co-authored-by: Nichole Mattera <me@nicholemattera.com> Co-authored-by: Robin Lambertz <unfiltered@roblab.la>
2021-03-01 08:56:49 +01:00
enum class ImHexPath {
Patterns,
PatternsInclude,
Magic,
Python,
Plugins,
Yara,
Config,
2021-06-26 01:18:33 +02:00
Resources,
Constants
sys/build: Properly support per-system metadata file paths (#181) * sys: Move away from metadata paths next to executable in the application Build system doesn't properly install / pack stuff yet * build: Updated README to contain better install instructions * sys: Search for imhex resource files in ~/Application Support * sys: MAX_PATH -> PATH_MAX * sys: Seach for imhex resource files in Application Support using NSFileManager (#180) * sys: Allow for multiple file search paths Also use install prefix instead of just /usr on Linux * build: Fixed IMHEX_INSTALL_PREFIX macro definition * build: Fix duplicate switch entry on Linux * docs: Updated readme to properly reflect new paths and dependencies * sys: Install files in their proper paths on linux (#183) * Install files in their proper paths on linux * Only create user directories * Follow the XDG specification on linux XDG specification specifies how to find config and data directories on linux systems. Specifically, it says this: - Data should be written to $XDG_DATA_HOME - Config should be written to $XDG_CONFIG_HOME - Data should be read from $XDG_DATA_HOME:$XDG_DATA_DIRS - Config should be read from $XDG_CONFIG_HOME:$XDG_CONFIG_DIRS The default values are this: - XDG_DATA_HOME: $HOME/.local/share - XDG_CONFIG_HOME: $HOME/.config - XDG_DATA_DIRS: /usr/share:/usr/local/share - XDG_CONFIG_DIRS: /etc/xdg Platforms with non-standard filesystems (like NixOS) will correctly set up those environment variables, allowing softwares to work unmodified. In order to make integration as simple as possible, we use a simple header-only dependency called XDGPP which does all the hard work for us to find the default directories. * Look for plugins in all Plugin Paths If the plugin folder was missing from one of the PluginPaths, we would immediately stop loading plugins. We now keep looking even if one of the path is missing. Co-authored-by: Nichole Mattera <me@nicholemattera.com> Co-authored-by: Robin Lambertz <unfiltered@roblab.la>
2021-03-01 08:56:49 +01:00
};
std::vector<std::string> getPath(ImHexPath path);
2021-08-28 00:45:59 +02:00
enum class DialogMode {
Open,
Save,
Folder
};
void openFileBrowser(std::string_view title, DialogMode mode, const std::vector<nfdfilteritem_t> &validExtensions, const std::function<void(std::string)> &callback);
float float16ToFloat32(u16 float16);
2021-08-28 00:45:59 +02:00
namespace scope_guard {
#define SCOPE_GUARD ::hex::scope_guard::ScopeGuardOnExit() + [&]()
#define ON_SCOPE_EXIT auto ANONYMOUS_VARIABLE(SCOPE_EXIT_) = SCOPE_GUARD
template<class F>
class ScopeGuard {
private:
F m_func;
bool m_active;
public:
constexpr ScopeGuard(F func) : m_func(std::move(func)), m_active(true) { }
~ScopeGuard() { if (this->m_active) { this->m_func(); } }
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;
};
enum class ScopeGuardOnExit { };
template <typename F>
constexpr ScopeGuard<F> operator+(ScopeGuardOnExit, F&& f) {
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 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:
constexpr FirstTimeExecute(F func) { func(); }
FirstTimeExecute& operator=(FirstTimeExecute &&) = delete;
};
enum class FirstTimeExecutor { };
template <typename F>
constexpr FirstTimeExecute<F> operator+(FirstTimeExecutor, F&& f) {
return FirstTimeExecute<F>(std::forward<F>(f));
}
}
namespace final_cleanup {
#define FINAL_CLEANUP static auto ANONYMOUS_VARIABLE(ON_EXIT_) = ::hex::final_cleanup::FinalCleanupExecutor() + [&]()
template<class F>
class FinalCleanupExecute {
F m_func;
public:
constexpr FinalCleanupExecute(F func) : m_func(func) { }
constexpr ~FinalCleanupExecute() { this->m_func(); }
FinalCleanupExecute& operator=(FinalCleanupExecute &&) = delete;
};
enum class FinalCleanupExecutor { };
template <typename F>
constexpr FinalCleanupExecute<F> operator+(FinalCleanupExecutor, F&& f) {
return FinalCleanupExecute<F>(std::forward<F>(f));
}
2021-03-31 22:54:43 +02:00
}
}