Each hexadecimal digit goes into exactly 4 binary digits: A 16 = 1010 2 .
Therefore, it is easy to write code that turns an arbitrarily large hex-string into a “01” line — for each hex-digit, add the corresponding bits to the result:
#include <string> #include "hex2bin_table.h" /// hex: "A" -> "1010", else: "\n" -> "\n" std::string hex2bin(const std::string& hex) { std::string bits; for (unsigned char hex_digit : hex) bits += hex2bin_table[hex_digit]; return bits; }
To avoid multiple allocations when the bits
grow, strings can be added before the loop: bits.reserve(4 * hex.size())
. But you should measure your performance to see what effect this has on your case.
Example:
#include <iostream> int main() { std::string hex = "CAFEBABE\n8BADF00D\nDEADBEEF\nD15EA5E"; std::cout << hex2bin(hex) << std::endl; }
Result
11001010111111101011101010111110 10001011101011011111000000001101 11011110101011011011111011101111 1101000101011110101001011110
To check, you can turn the bits into hexadecimal digits, for example, on Python:
>>> 0b11001010111111101011101010111110 .to_bytes(4, 'big').hex() 'cafebabe'
hex2bin_table
is the table hex -> bin, in which for each hex digit there is a corresponding bit string:
const char* const hex2bin_table[] = { "\x00", "\x01", "\x02", "\x03", "\x04", "\x05", "\x06", "\x07", ... "\x28", "\x29", "\x2A", "\x2B", "\x2C", "\x2D", "\x2E", "\x2F", "0000", "0001", "0010", "0011", "0100", "0101", "0110", "0111", "1000", "1001", "\x3A", "\x3B", "\x3C", "\x3D", "\x3E", "\x3F", ... };
The line position is determined by the ASCII code for the corresponding hex number: 'A' == 65
, therefore hex2bin_table['A'] == hex2bin_table[65] == "1010"
. Bytes that do not correspond to hexadecimal ASCII digits represent themselves as C lines: hex2bin_table[0x2e] == "\x2e"
.
The table can be generated automatically, for example on Python:
#!/usr/bin/env python from string import hexdigits print('const char* const hex2bin_table[] = {') for char in map(chr, range(0x100)): if char in hexdigits: # interpret as hex-digit and print as bits print('"{:04b}",'.format(int(char, 16))) else: # as itself print(r'"\x{:02X}",'.format(ord(char))) print('};')
or instead of a table, you can use the function with a simple switch(hex_digit)
branch .
char *
) string of zeros and ones? - avp