#pragma once #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #if defined(OS_MACOS) #include #elif defined(OS_LINUX) #include #endif #include #include namespace hex { #if !defined(HEX_MODULE_EXPORT) namespace prv { class Provider; } #endif template [[nodiscard]] std::vector> sampleChannels(const std::vector &data, size_t count, size_t channels) { if (channels == 0) return {}; size_t signalLength = std::max(1.0, double(data.size()) / channels); size_t stride = std::max(1.0, double(signalLength) / count); std::vector> result; result.resize(channels); for (size_t i = 0; i < channels; i++) { result[i].reserve(count); } result.reserve(count); for (size_t i = 0; i < data.size(); i += stride) { for (size_t j = 0; j < channels; j++) { result[j].push_back(data[i + j]); } } return result; } template [[nodiscard]] std::vector sampleData(const std::vector &data, size_t count) { size_t stride = std::max(1.0, double(data.size()) / count); std::vector result; result.reserve(count); for (size_t i = 0; i < data.size(); i += stride) { result.push_back(data[i]); } return result; } template [[nodiscard]] std::vector operator|(const std::vector &lhs, const std::vector &rhs) { std::vector result; std::copy(lhs.begin(), lhs.end(), std::back_inserter(result)); std::copy(rhs.begin(), rhs.end(), std::back_inserter(result)); return result; } [[nodiscard]] std::string to_string(u128 value); [[nodiscard]] std::string to_string(i128 value); [[nodiscard]] std::string toLower(std::string string); [[nodiscard]] std::string toUpper(std::string string); [[nodiscard]] std::vector parseHexString(std::string string); [[nodiscard]] std::optional parseBinaryString(const std::string &string); [[nodiscard]] std::string toByteString(u64 bytes); [[nodiscard]] std::string makePrintable(u8 c); void startProgram(const std::vector &command); int executeCommand(const std::string &command); std::optional executeCommandWithOutput(const std::string &command); void openWebpage(std::string url); extern "C" void registerFont(const char *fontName, const char *fontPath); const std::map& getFonts(); [[nodiscard]] std::string encodeByteString(const std::vector &bytes); [[nodiscard]] std::vector decodeByteString(const std::string &string); [[nodiscard]] std::wstring utf8ToUtf16(const std::string& utf8); [[nodiscard]] std::string utf16ToUtf8(const std::wstring& utf16); [[nodiscard]] constexpr u64 extract(u8 from, u8 to, const auto &value) { if (from < to) std::swap(from, to); using ValueType = std::remove_cvref_t; ValueType mask = (std::numeric_limits::max() >> (((sizeof(value) * 8) - 1) - (from - to))) << to; return u64((value & mask) >> to); } [[nodiscard]] inline u64 extract(u32 from, u32 to, const std::vector &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::max() >> (64 - (from + 1))); return (value & mask) >> to; } [[nodiscard]] constexpr i128 signExtend(size_t numBits, i128 value) { i128 mask = 1ULL << (numBits - 1); return (value ^ mask) - mask; } template [[nodiscard]] constexpr 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; } [[nodiscard]] constexpr size_t strnlen(const char *s, size_t n) { size_t i = 0; while (i < n && s[i] != '\x00') i++; return i; } template 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 using SizeType = typename SizeTypeImpl::Type; template [[nodiscard]] constexpr T changeEndianness(const T &value, size_t size, std::endian endian) { if (endian == std::endian::native) return value; size = std::min(size, sizeof(T)); std::array data = { 0 }; std::memcpy(&data[0], &value, size); for (uint32_t i = 0; i < size / 2; i++) { std::swap(data[i], data[size - 1 - i]); } T result = { }; std::memcpy(&result, &data[0], size); return result; } template [[nodiscard]] constexpr T changeEndianness(const T &value, std::endian endian) { return changeEndianness(value, sizeof(value), endian); } [[nodiscard]] constexpr u128 bitmask(u8 bits) { return u128(-1) >> (128 - bits); } template [[nodiscard]] constexpr T bit_width(T x) noexcept { return std::numeric_limits::digits - std::countl_zero(x); } template [[nodiscard]] constexpr T bit_ceil(T x) noexcept { if (x <= 1u) return T(1); return T(1) << bit_width(T(x - 1)); } template [[nodiscard]] 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 void moveToVector(std::vector &buffer, T &&first, Args &&...rest) { buffer.push_back(std::move(first)); if constexpr (sizeof...(rest) > 0) moveToVector(buffer, std::move(rest)...); } template [[nodiscard]] std::vector moveToVector(T &&first, Args &&...rest) { std::vector result; moveToVector(result, T(std::move(first)), std::move(rest)...); return result; } [[nodiscard]] std::string toEngineeringString(double value); [[nodiscard]] inline std::vector parseByteString(const std::string &string) { auto byteString = std::string(string); std::erase(byteString, ' '); if ((byteString.length() % 2) != 0) return {}; std::vector result; for (u32 i = 0; i < byteString.length(); i += 2) { if (!std::isxdigit(byteString[i]) || !std::isxdigit(byteString[i + 1])) return {}; auto value = wolv::util::from_chars(byteString.substr(i, 2), 16); if (!value.has_value()) return {}; result.push_back(*value); } return result; } [[nodiscard]] std::string toBinaryString(std::unsigned_integral auto number) { if (number == 0) return "0"; std::string result; for (i16 bit = hex::bit_width(number) - 1; bit >= 0; bit -= 1) result += (number & (0b1LLU << bit)) == 0 ? '0' : '1'; return result; } template [[nodiscard]] constexpr float customFloatToFloat32(u32 value) { static_assert(ExponentBits <= 8, "ExponentBits must be less than 8"); static_assert(ExponentBits + MantissaBits + 1 <= 32, "Format doesn't fit into a 32-bit float"); const u32 sign = value >> (ExponentBits + MantissaBits); const u32 exponent = (value >> MantissaBits) & ((1u << ExponentBits) - 1); u32 mantissa = value & ((1u << MantissaBits) - 1); // Calculate the bias for the input format and IEEE-754 float32 i32 inputBias = (1 << (ExponentBits - 1)) - 1; i32 float32Bias = 127; u32 result = 0; if (exponent == 0) { if (mantissa == 0) { // Zero result = sign << 31; } else { // Subnormal int shift = 0; while ((mantissa & (1u << MantissaBits)) == 0) { mantissa <<= 1; shift++; } mantissa &= ((1u << MantissaBits) - 1); // clear implicit bit int adjustedExp = float32Bias - inputBias - shift + 1; result = (sign << 31) | (adjustedExp << 23) | (mantissa << (23 - MantissaBits)); } } else if (exponent == ((1u << ExponentBits) - 1)) { // Inf or NaN result = (sign << 31) | (0xFF << 23) | (mantissa << (23 - MantissaBits)); } else { // Normalized number int adjustedExp = exponent - inputBias + float32Bias; result = (sign << 31) | (adjustedExp << 23) | (mantissa << (23 - MantissaBits)); } float floatResult; std::memcpy(&floatResult, &result, sizeof(float)); return floatResult; } [[nodiscard]] constexpr float float16ToFloat32(u16 float16) { return customFloatToFloat32<5, 10>(float16); } [[nodiscard]] inline bool equalsIgnoreCase(std::string_view left, std::string_view right) { return std::equal(left.begin(), left.end(), right.begin(), right.end(), [](char a, char b) { return tolower(a) == tolower(b); }); } [[nodiscard]] inline bool containsIgnoreCase(std::string_view a, std::string_view 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 [[nodiscard]] T get_or(const std::variant &variant, T alt) { const T *value = std::get_if(&variant); if (value == nullptr) return alt; else return *value; } template [[nodiscard]] T alignTo(T value, T alignment) { T remainder = value % alignment; return remainder != 0 ? value + (alignment - remainder) : value; } [[nodiscard]] std::optional hexCharToValue(char c); [[nodiscard]] bool isProcessElevated(); [[nodiscard]] std::optional getEnvironmentVariable(const std::string &env); [[nodiscard]] std::string limitStringLength(const std::string &string, size_t maxLength, bool fromBothEnds = true); [[nodiscard]] std::optional getInitialFilePath(); [[nodiscard]] std::string generateHexView(u64 offset, u64 size, prv::Provider *provider); [[nodiscard]] std::string generateHexView(u64 offset, const std::vector &data); [[nodiscard]] std::string formatSystemError(i32 error); /** * Gets the shared library handle for a given pointer * @param symbol Pointer to any function or variable in the shared library * @return The module handle * @warning Important! Calling this function on functions defined in other modules will return the handle of the current module! * This is because you're not actually passing a pointer to the function in the other module but rather a pointer to a thunk * that is defined in the current module. */ [[nodiscard]] void* getContainingModule(void* symbol); [[nodiscard]] std::optional blendColors(const std::optional &a, const std::optional &b); std::optional parseTime(std::string_view format, const std::string &timeString); std::optional getOSLanguage(); void showErrorMessageBox(const std::string &message); void showToastMessage(const std::string &title, const std::string &message); }