41a30573f6
cpp-template / format (ubuntu-22.04) (push) Successful in 1m5s
cpp-template / format (ubuntu-24.04) (push) Successful in 1m6s
cpp-template / build-test (asan, ubuntu-22.04) (push) Successful in 1m48s
cpp-template / build-test (asan, ubuntu-24.04) (push) Successful in 1m53s
cpp-template / build-test (debug, ubuntu-22.04) (push) Successful in 2m11s
cpp-template / build-test (debug, ubuntu-24.04) (push) Successful in 2m16s
cpp-template / build-test (fuzz, ubuntu-22.04) (push) Successful in 7m55s
cpp-template / build-test (fuzz, ubuntu-24.04) (push) Successful in 8m14s
cpp-template / build-test (release, ubuntu-22.04) (push) Successful in 2m13s
cpp-template / build-test (release, ubuntu-24.04) (push) Successful in 2m11s
cpp-template / clang-tidy (ubuntu-22.04) (push) Successful in 1m53s
cpp-template / clang-tidy (ubuntu-24.04) (push) Successful in 1m59s
cpp-template / install-consumer (ubuntu-22.04) (push) Successful in 1m43s
cpp-template / install-consumer (ubuntu-24.04) (push) Successful in 1m45s
cpp-template / no-network-negative (ubuntu-22.04) (push) Successful in 7m9s
cpp-template / no-network-negative (ubuntu-24.04) (push) Successful in 7m24s
cpp-template / format (ubuntu-20.04) (push) Has been cancelled
cpp-template / build-test (asan, ubuntu-20.04) (push) Has been cancelled
cpp-template / build-test (debug, ubuntu-20.04) (push) Has been cancelled
cpp-template / build-test (fuzz, ubuntu-20.04) (push) Has been cancelled
cpp-template / build-test (release, ubuntu-20.04) (push) Has been cancelled
cpp-template / clang-tidy (ubuntu-20.04) (push) Has been cancelled
cpp-template / install-consumer (ubuntu-20.04) (push) Has been cancelled
cpp-template / no-network-negative (ubuntu-20.04) (push) Has been cancelled
74 lines
2.2 KiB
C++
74 lines
2.2 KiB
C++
#pragma once
|
|
|
|
#include <cstddef>
|
|
#include <cstdint>
|
|
#include <string>
|
|
#include <vector>
|
|
|
|
#include <tl/optional.hpp>
|
|
|
|
// Compile-time lookup table for decoding hex characters to their 0-15 value,
|
|
// or -1 for invalid characters.
|
|
struct HexDecodeTable
|
|
{
|
|
std::int8_t values[256];
|
|
|
|
constexpr HexDecodeTable() : values{}
|
|
{
|
|
for (auto &v : values) {
|
|
v = -1;
|
|
}
|
|
for (char c = '0'; c <= '9'; ++c) {
|
|
values[static_cast<std::size_t>(c)] = static_cast<std::int8_t>(c - '0');
|
|
}
|
|
for (char c = 'a'; c <= 'f'; ++c) {
|
|
values[static_cast<std::size_t>(c)] = static_cast<std::int8_t>(c - 'a' + 10);
|
|
}
|
|
for (char c = 'A'; c <= 'F'; ++c) {
|
|
values[static_cast<std::size_t>(c)] = static_cast<std::int8_t>(c - 'A' + 10);
|
|
}
|
|
}
|
|
};
|
|
|
|
namespace
|
|
{
|
|
const HexDecodeTable kHexDecode;
|
|
} // namespace
|
|
|
|
inline std::string hex_encode(const void *data, std::size_t len)
|
|
{
|
|
const auto *bytes = static_cast<const std::uint8_t *>(data);
|
|
static constexpr char kHexChars[] = "0123456789abcdef";
|
|
std::string result;
|
|
result.reserve(len * 2U);
|
|
for (std::size_t i = 0; i < len; ++i) {
|
|
result.push_back(kHexChars[(bytes[i] >> 4U) & 0x0FU]);
|
|
result.push_back(kHexChars[bytes[i] & 0x0FU]);
|
|
}
|
|
return result;
|
|
}
|
|
|
|
inline std::string hex_encode(const std::string &data) { return hex_encode(data.data(), data.size()); }
|
|
|
|
inline std::string hex_encode(const std::vector<std::uint8_t> &data) { return hex_encode(data.data(), data.size()); }
|
|
|
|
// Returns decoded bytes, or tl::nullopt on invalid input (odd length or
|
|
// non-hex characters).
|
|
inline tl::optional<std::vector<std::uint8_t>> hex_decode(const std::string &hex)
|
|
{
|
|
if (hex.size() % 2U != 0U) {
|
|
return tl::nullopt;
|
|
}
|
|
std::vector<std::uint8_t> result;
|
|
result.reserve(hex.size() / 2U);
|
|
for (std::size_t i = 0; i < hex.size(); i += 2U) {
|
|
auto high = kHexDecode.values[static_cast<std::uint8_t>(hex[i])];
|
|
auto low = kHexDecode.values[static_cast<std::uint8_t>(hex[i + 1U])];
|
|
if (high < 0 || low < 0) {
|
|
return tl::nullopt;
|
|
}
|
|
result.push_back(static_cast<std::uint8_t>((high << 4) | low));
|
|
}
|
|
return result;
|
|
}
|