#pragma once #include #include #include #include namespace browns { template std::string format_digest(const std::array& dig) { std::string ret; ret.resize(N * 2); for (std::size_t pos = 0; pos < N; ++pos) { std::byte b = dig[pos]; char& c1 = ret[pos * 2]; char& c2 = ret[pos * 2 + 1]; const char tab[17] = "0123456789abcdef"; auto high = (static_cast(b) & 0xf0) >> 4; auto low = (static_cast(b) & 0x0f); c1 = tab[high]; c2 = tab[low]; } return ret; } template 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(c + ('a' - 'A')); } std::byte nib{0}; if (c >= '0' && c <= '9') { nib = std::byte(c - '0'); } else if (c >= 'a' && c <= 'f') { nib = std::byte(c - 'a'); } else { invalid(); } return nib; }; // 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