1 #pragma once
2 
3 #include <array>
4 #include <cstddef>
5 #include <string>
6 #include <vector>
7 
8 static constexpr std::array<char, 16> digitsArray = {
9     '0', '1', '2', '3', '4', '5', '6', '7',
10     '8', '9', 'A', 'B', 'C', 'D', 'E', 'F'};
11 
12 inline std::string intToHexString(uint64_t value, size_t digits)
13 {
14     std::string rc(digits, '0');
15     size_t bitIndex = (digits - 1) * 4;
16     for (size_t digitIndex = 0; digitIndex < digits; digitIndex++)
17     {
18         rc[digitIndex] = digitsArray[(value >> bitIndex) & 0x0f];
19         bitIndex -= 4;
20     }
21     return rc;
22 }
23 
24 inline std::string bytesToHexString(const std::vector<uint8_t>& bytes)
25 {
26     std::string rc(bytes.size() * 2, '0');
27     for (size_t i = 0; i < bytes.size(); ++i)
28     {
29         rc[i * 2] = digitsArray[(bytes[i] & 0xf0) >> 4];
30         rc[i * 2 + 1] = digitsArray[bytes[i] & 0x0f];
31     }
32     return rc;
33 }
34 
35 // Returns nibble.
36 inline uint8_t hexCharToNibble(char ch)
37 {
38     uint8_t rc = 16;
39     if (ch >= '0' && ch <= '9')
40     {
41         rc = static_cast<uint8_t>(ch) - '0';
42     }
43     else if (ch >= 'A' && ch <= 'F')
44     {
45         rc = static_cast<uint8_t>(ch) - 'A' + 10;
46     }
47     else if (ch >= 'a' && ch <= 'f')
48     {
49         rc = static_cast<uint8_t>(ch) - 'a' + 10;
50     }
51 
52     return rc;
53 }
54 
55 // Returns empty vector in case of malformed hex-string.
56 inline std::vector<uint8_t> hexStringToBytes(const std::string& str)
57 {
58     std::vector<uint8_t> rc(str.size() / 2, 0);
59     for (size_t i = 0; i < str.length(); i += 2)
60     {
61         uint8_t hi = hexCharToNibble(str[i]);
62         if (i == str.length() - 1)
63         {
64             return {};
65         }
66         uint8_t lo = hexCharToNibble(str[i + 1]);
67         if (lo == 16 || hi == 16)
68         {
69             return {};
70         }
71 
72         rc[i / 2] = static_cast<uint8_t>(hi << 4) | lo;
73     }
74     return rc;
75 }
76