src/internal/module_name.hpp
| Line | Branch | Exec | Source |
|---|---|---|---|
| 1 | #ifndef DETOURMODKIT_INTERNAL_MODULE_NAME_HPP | ||
| 2 | #define DETOURMODKIT_INTERNAL_MODULE_NAME_HPP | ||
| 3 | |||
| 4 | /** | ||
| 5 | * @file module_name.hpp | ||
| 6 | * @brief Shared bounded UTF-8 -> UTF-16 widening for module-name lookups. | ||
| 7 | */ | ||
| 8 | |||
| 9 | #include <windows.h> | ||
| 10 | |||
| 11 | #include <climits> | ||
| 12 | #include <cstddef> | ||
| 13 | #include <new> | ||
| 14 | #include <string> | ||
| 15 | #include <string_view> | ||
| 16 | |||
| 17 | namespace DetourModKit | ||
| 18 | { | ||
| 19 | namespace detail | ||
| 20 | { | ||
| 21 | /** | ||
| 22 | * @brief Reports whether a module-name byte count fits the Win32 conversion API. | ||
| 23 | * @param length The byte count to test. | ||
| 24 | * @return True when @p length can be represented by the converter's signed count. | ||
| 25 | */ | ||
| 26 | 163 | [[nodiscard]] constexpr bool module_name_length_fits_win32(std::size_t length) noexcept | |
| 27 | { | ||
| 28 | 163 | return length <= static_cast<std::size_t>(INT_MAX); | |
| 29 | } | ||
| 30 | |||
| 31 | /** | ||
| 32 | * @brief Widens a pointer/count UTF-8 module name after validating its Win32 length. | ||
| 33 | * @details The length check precedes construction of a view and every access through @p data. Embedded NUL and | ||
| 34 | * malformed UTF-8 are rejected because GetModuleHandleW would otherwise observe a different name. | ||
| 35 | * @param data The first name byte; may be null only when @p length is zero or oversized. | ||
| 36 | * @param length The number of name bytes. | ||
| 37 | * @return The UTF-16 name, or an empty string when validation, conversion, or allocation fails. | ||
| 38 | * @pre When @p length is nonzero and at most INT_MAX, @p data addresses @p length readable bytes. | ||
| 39 | */ | ||
| 40 | 164 | [[nodiscard]] inline std::wstring widen_module_name_bytes(const char *data, std::size_t length) noexcept | |
| 41 | { | ||
| 42 |
7/8✓ Branch 2 → 3 taken 163 times.
✓ Branch 2 → 6 taken 1 time.
✓ Branch 4 → 5 taken 162 times.
✓ Branch 4 → 6 taken 1 time.
✗ Branch 5 → 6 not taken.
✓ Branch 5 → 7 taken 162 times.
✓ Branch 8 → 9 taken 2 times.
✓ Branch 8 → 10 taken 162 times.
|
164 | if (length == 0 || !module_name_length_fits_win32(length) || data == nullptr) |
| 43 | { | ||
| 44 | 2 | return std::wstring{}; | |
| 45 | } | ||
| 46 | |||
| 47 | 162 | const std::string_view name{data, length}; | |
| 48 |
2/2✓ Branch 12 → 13 taken 3 times.
✓ Branch 12 → 14 taken 159 times.
|
162 | if (name.find('\0') != std::string_view::npos) |
| 49 | { | ||
| 50 | 3 | return std::wstring{}; | |
| 51 | } | ||
| 52 | |||
| 53 | 159 | const int input_length = static_cast<int>(length); | |
| 54 | const int wide_length = | ||
| 55 | 159 | ::MultiByteToWideChar(CP_UTF8, MB_ERR_INVALID_CHARS, data, input_length, nullptr, 0); | |
| 56 |
2/2✓ Branch 15 → 16 taken 1 time.
✓ Branch 15 → 17 taken 158 times.
|
159 | if (wide_length <= 0) |
| 57 | { | ||
| 58 | 1 | return std::wstring{}; | |
| 59 | } | ||
| 60 | try | ||
| 61 | { | ||
| 62 |
2/2✓ Branch 19 → 20 taken 157 times.
✓ Branch 19 → 30 taken 1 time.
|
159 | std::wstring wide_name(static_cast<std::size_t>(wide_length), L'\0'); |
| 63 |
1/2✓ Branch 22 → 23 taken 157 times.
✗ Branch 22 → 33 not taken.
|
157 | const int converted = ::MultiByteToWideChar( |
| 64 | CP_UTF8, | ||
| 65 | MB_ERR_INVALID_CHARS, | ||
| 66 | data, | ||
| 67 | input_length, | ||
| 68 | wide_name.data(), | ||
| 69 | wide_length | ||
| 70 | ); | ||
| 71 |
1/2✗ Branch 23 → 24 not taken.
✓ Branch 23 → 25 taken 157 times.
|
157 | if (converted != wide_length) |
| 72 | { | ||
| 73 | ✗ | return std::wstring{}; | |
| 74 | } | ||
| 75 | 157 | return wide_name; | |
| 76 | 157 | } | |
| 77 |
1/2✗ Branch 36 → 37 not taken.
✓ Branch 36 → 38 taken 1 time.
|
1 | catch (const std::bad_alloc &) |
| 78 | { | ||
| 79 | 1 | return std::wstring{}; | |
| 80 | 1 | } | |
| 81 | } | ||
| 82 | |||
| 83 | /** | ||
| 84 | * @brief Widens a UTF-8 module name to the UTF-16 the Win32 module APIs expect. | ||
| 85 | * @details Reads exactly @c name.size() bytes, so a non-NUL-terminated view is safe. | ||
| 86 | * @param name The bounded UTF-8 module name. | ||
| 87 | * @return The UTF-16 name, or an empty string when validation, conversion, or allocation fails. | ||
| 88 | */ | ||
| 89 | 163 | [[nodiscard]] inline std::wstring widen_module_name(std::string_view name) noexcept | |
| 90 | { | ||
| 91 | 163 | return widen_module_name_bytes(name.data(), name.size()); | |
| 92 | } | ||
| 93 | } // namespace detail | ||
| 94 | } // namespace DetourModKit | ||
| 95 | |||
| 96 | #endif // DETOURMODKIT_INTERNAL_MODULE_NAME_HPP | ||
| 97 |