|
|
@@ -3,6 +3,7 @@ |
|
|
|
#include <array> |
|
|
|
#include <cstddef> |
|
|
|
#include <string> |
|
|
|
#include <string_view> |
|
|
|
|
|
|
|
namespace browns { |
|
|
|
|
|
|
@@ -23,4 +24,48 @@ std::string format_digest(const std::array<std::byte, N>& dig) { |
|
|
|
return ret; |
|
|
|
} |
|
|
|
|
|
|
|
template <typename Digest> |
|
|
|
Digest parse_digest(std::string_view str) { |
|
|
|
Digest ret; |
|
|
|
std::byte* out_ptr = ret.data(); |
|
|
|
std::byte* const out_end = out_ptr + ret.size(); |
|
|
|
auto str_ptr = str.begin(); |
|
|
|
const auto str_end = str.end(); |
|
|
|
|
|
|
|
auto invalid = [&] { // |
|
|
|
throw std::runtime_error("Invalid hash digest string: " + std::string(str)); |
|
|
|
}; |
|
|
|
|
|
|
|
auto nibble = [&](char c) -> std::byte { |
|
|
|
if (c >= 'A' && c <= 'F') { |
|
|
|
c = static_cast<char>(c + ('a' - 'A')); |
|
|
|
} |
|
|
|
if (c >= '0' && c <= '9') { |
|
|
|
return std::byte(c - '0'); |
|
|
|
} |
|
|
|
if (c >= 'a' && c <= 'f') { |
|
|
|
return std::byte(c - 'a'); |
|
|
|
} |
|
|
|
invalid(); |
|
|
|
std::terminate(); |
|
|
|
}; |
|
|
|
|
|
|
|
// We must have an even number of chars to form full octets |
|
|
|
if (str.size() % 2) { |
|
|
|
invalid(); |
|
|
|
} |
|
|
|
|
|
|
|
while (str_ptr != str_end && out_ptr != out_end) { |
|
|
|
std::byte high = nibble(*str_ptr++); |
|
|
|
std::byte low = nibble(*str_ptr++); |
|
|
|
std::byte octet = (high << 4) | low; |
|
|
|
*out_ptr++ = octet; |
|
|
|
} |
|
|
|
|
|
|
|
if (str_ptr != str_end || out_ptr != out_end) { |
|
|
|
invalid(); |
|
|
|
} |
|
|
|
return ret; |
|
|
|
} |
|
|
|
|
|
|
|
} // namespace browns |