You are viewing an old version of the ionflux.org website! Please visit the new version
here.
Hexadecimal Output (C++)
I often want to take a look at data which has been generated by some code I have
written, but which is not readable very well by humans. In the worst case, it
may even contain characters which are not printable at all. For these
situations, I have written some nice little functions which display arbitrary
byte data in hexadecimal notation, much like in a hexadecimal editor. It is also
possible to view the hexadecimal representation side by side with the readable
characters.
Byte to Hexadecimal String Converter
This snippet does the simple task of converting a string of bytes to a string of
hexadecimal numbers.
#include <string>
#include <sstream>
#include <iomanip>
std::string make_hex(const std::string& inputData)
{
std::ostringstream buffer;
buffer << std::uppercase << std::right << std::setfill('0') << std::hex;
for (unsigned int i = 0; i < inputData.size(); i++)
buffer << std::setw(2) << int(static_cast<unsigned char>(inputData[i]));
return buffer.str();
}
Make Readable Text
Some characters can be considered readable, even in a soup of random bytes. This
piece of code replaces those characters which are not considered readable by a
replacement. The other characters are appended unchanged. If UTF-8 encoding is
available (see the code snippets in the previous section on how to do this), the
version below will display much more characters. They may not all be readable,
but they do look interesting. ;-)
#include <string>
#include <sstream>
std::string make_readable(const std::string& inputData,
const std::string& replacement = ".")
{
std::ostringstream buffer;
unsigned char currentChar;
for (unsigned int i = 0; i < inputData.size(); i++)
{
currentChar = static_cast<unsigned char>(inputData[i]);
if (((currentChar >= 32) && (currentChar <= 126))
|| (currentChar >= 160))
buffer << inputData[i];
else
buffer << replacement;
}
return buffer.str();
}
// This requires the uint_to_utf8() function from the previous section.
std::string make_readable(const std::string& inputData,
const std::string& replacement = ".")
{
std::ostringstream buffer;
unsigned int currentChar;
for (unsigned int i = 0; i < inputData.size(); i++)
{
currentChar = static_cast<unsigned int>(
static_cast<unsigned char>(inputData[i]));
if ((currentChar >= 32) && (currentChar <= 126))
buffer << inputData[i];
else
if (currentChar >= 127)
buffer << uint_to_utf8(currentChar);
else
buffer << replacement;
}
return buffer.str();
}
Make Nice Hexadecimal Output
Now we are ready to do some really nice things with the hexadecimal string and
the readable representation of the data. The following function creates a column
layout with arranges the bytes properly beside the readable characters. The
version below fills in some defaults and puts everything together for a hex view
which is really simple to use at any time when data needs to be inspected
closely.
#include <string>
#include <sstream>
std::string make_nice_hex(const std::string& hex, const std::string& readable,
int bytesPerLine, int groupBytes)
{
std::ostringstream buffer;
std::string paddedHex(hex);
std::string paddedReadable(readable);
if ((paddedHex.size() % 2) != 0)
paddedHex.append(" ");
while (((paddedHex.size() / 2) % bytesPerLine) != 0)
paddedHex.append(" ");
unsigned int bytes = paddedHex.size() / 2;
while (paddedReadable.size() < bytes)
paddedReadable.append(" ");
int readablePos = 0;
for (unsigned int i = 0; i < bytes; i++)
{
buffer << paddedHex.substr(2 * i, 2) << " ";
if ((((i + 1) % groupBytes) == 0) && (((i + 1) % bytesPerLine) != 0))
buffer << " ";
if (((i + 1) % bytesPerLine) == 0)
{
buffer << " " << paddedReadable.substr(readablePos, bytesPerLine) << "n";
readablePos += bytesPerLine;
}
}
return buffer.str();
}
std::string make_nice_hex(const std::string& data, int bytesPerLine = 20,
int groupBytes = 10)
{
return make_nice_hex(make_hex(data), make_readable(data, "."),
bytesPerLine, groupBytes);
}