Я задаюсь вопросом, как преобразовать шестнадцатеричную строку в человекочитаемую строку (если бы это имеет какой-либо смысл), это было бы моим первым реальным обнаружением с шестнадцатеричными значениями, таким образом, я все еще узнаю о них и как управлять ими.
У меня есть программа, которая читает в данных из файла, который содержит необработанные пакетные данные (шестнадцатеричное число), и я должен проанализировать эту информацию, таким образом, это человекочитаемо.
Пример того, что я должен сделать, является чем-то вроде этого, что сайт делает http://home2.paulschou.net/tools/xlate/, где можно вставить шестнадцатеричное число и иметь преобразованный в текст.
Способ получения строки, содержащей шестнадцатеричное представление заданного числа на языке C++, заключается в использовании модификатора hex
для потоков, как в данном примере:
const int i = 0xdeadbeef;
cout << "0x" << hex << i << endl; // prints "0xdeadbeef"
Вы можете использовать тот же модификатор для потоков строк в случае, если вам необходимо шестнадцатеричное представление в строковой переменной:
const int i = 0xdeadc0de;
ostringstream stream;
stream << "0x" << hex << i;
const string s = stream.str(); // s now contains "0xdeadc0de"
UPDATE:
Если входные данные даются в виде строки, содержащей шестнадцатеричное представление символов строки, то для корректного отображения необходимо знать кодировку входной строки. В простейшем случае строка представляет собой нечто вроде ASCII, который сопоставляет один байт с одним символом. Так в заданном вводе "414243" каждые два символа ("41", "42", "43") отображаются в ASCII значение (65, 66, 67), которое отображается в символ ("A", "B", "C").
Вот как это сделать на C++:
const string hexData = "414243";
assert( hexData.size() % 2 == 0 );
ostringstream asciiStream;
istringstream hexDataStream( hexData );
vector<char> buf( 3 ); // two chars for the hex char, one for trailing zero
while ( hexDataStream.good() ) {
hexDataStream.get( &buf[0], buf.size() );
if ( hexDataStream.good() ) {
asciiStream << static_cast<char>( std::strtol( &buf[0], 0, 16 ) );
}
}
const string asciiData = asciiStream.str(); // asciiData == "ABC"
Использование std::strtol
из
делает это простым; если вы настаиваете на использовании шаблонного класса для этого, используйте std::stringstream для преобразования одиночных подстрок (например, "41") в десятичные значения (65).
Гекс - это способ отображения двоичных данных. Это не "сырые данные", как вы говорите. Если исходные данные, которые у вас есть, содержат строку, вы должны быть в состоянии увидеть строку (возможно, среди прочего мусора), когда вы выводите ее на экран.
Вот цикл для вывода ASCII-символов в блоке данных. Чтобы получить что-то ещё, Вам придётся иметь дело с его форматом.
char *binary_data[ BUFFER_SIZE ];
size_t len = BUFFER_SIZE;
len = get_a_packet( data, len ); // or however you get data
for ( char *text_ptr = binary_data; text_ptr != binary_data + len; ++ text_ptr ) {
if ( * text_ptr <= '~' && * text_ptr >= ' ' ) { // if it's ascii
cerr << * text_ptr; // print it out
}
}
cerr << endl;
Взято из библиотеки C++ String Toolkit Library (StrTk), должно быть достаточно следующего. Обратите внимание, что out должно указывать на кусок памяти вдвое меньше размера как std::distance(begin,end), и что значения в диапазоне [begin,end] должны быть 0-9A-F или 0-9a-f
inline bool convert_hex_to_bin(const unsigned char* begin,
const unsigned char* end,
unsigned char* out)
{
if (std::distance(begin,end) % 2)
return false;
static const std::size_t symbol_count = 256;
static const unsigned char hex_to_bin[symbol_count] = {
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // 0x00 - 0x07
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // 0x08 - 0x0F
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // 0x10 - 0x17
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // 0x18 - 0x1F
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // 0x20 - 0x27
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // 0x28 - 0x2F
0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, // 0x30 - 0x37
0x08, 0x09, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // 0x38 - 0x3F
0x00, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F, 0x00, // 0x40 - 0x47
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // 0x48 - 0x4F
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // 0x50 - 0x57
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // 0x58 - 0x5F
0x00, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F, 0x00, // 0x60 - 0x67
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // 0x68 - 0x6F
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // 0x70 - 0x77
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // 0x78 - 0x7F
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // 0x80 - 0x87
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // 0x88 - 0x8F
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // 0x90 - 0x97
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // 0x98 - 0x9F
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // 0xA0 - 0xA7
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // 0xA8 - 0xAF
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // 0xB0 - 0xB7
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // 0xB8 - 0xBF
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // 0xC0 - 0xC7
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // 0xC8 - 0xCF
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // 0xD0 - 0xD7
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // 0xD8 - 0xDF
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // 0xE0 - 0xE7
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // 0xE8 - 0xEF
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // 0xF0 - 0xF7
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 // 0xF8 - 0xFF
};
const unsigned char* itr = begin;
while (end != itr)
{
(*out) = static_cast<unsigned char>(hex_to_bin[*(itr++)] << 4);
(*out) |= static_cast<unsigned char>(hex_to_bin[*(itr++)] );
++out;
}
return true;
}