Hexdumper for C++ IOStreams

A hex::dumper object which can output hexdumps in several ways, configured by using various stream manipulators. Usage is as simple as:

std::cout << hex::hexstring << hex::dumper(data, size) << std::endl;

or

std::cout << hex::offset(0x12000) << std::hex << hex::dumper(data, size) << std::endl;

I use hexdumps in various ways, sometimes i just need a couple of bytes, without any spaces converted to hex, other times i want to have a full listing with offsets, and ascii, or yet another time i would like to see dwords instead of bytes.

So my hexdumper needs to be configurable in many ways. My idea is to use stream manipulators to configure the hexdump.

Looking at iostreams, there are many ways to configure a stream:

getter setter
os.flags() & os.adjustfield os << std::left os << std::right
os.flags() & os.basefield os << std::hex, os << std::dec, os << std::oct
os.flags() & os.uppercase os << std::uppercase os << std::lowercase
os.width() os << std::setw(n)
os.precision() os << std::setprecision(n)
os.flags() & os.showpoint os << std::showpoint
os.flags() & os.showbase os << std::showbase
os.flags() & os.skipws os << std::skipws
os.fill() os << std::setfill(c)
os.flags() & os.showpos os << std::showpos

And this is a list of properties i would like to configure in my hexdumper:

  • base offset
  • item size ( byte, word, dword, qword )
  • which items to output: offset, hexdata, ascdata
  • separator: space, ':', '-', or nothing.
  • line width
  • stepsize ( do i print everything, or skip through the data in larger jumps )
  • summarize identical lines
  • whether to output hex, octal, decimal or binary
  • wheter to show a base with the data ( 0, 0x, 0b )

Here is the mapping i made from the std stream manipulators to my desired features. The reasoning is as follows: left is where the hexdump usually is, right is where the ascii dump usually is.

manipulator hexdump feature
std::left only hexdump
std::right only ascdump
std::hex hexadecimal data
std::dec decimal data
std::oct octal data
std::setw nr of units per line
std::fill separator
std::uppercase uppercase hexadecimal
std::showpoint show offset
std::showbase show base
std::skipws summarize identical lines
std::setprecision unused
std::showpos unused
sizeof(T) unit type : byte, word, dword, ...
binary data
stepsize
base offset

As you can see there are not enough std manipulators to use comfortably for all hexdumper features.

So, how do i add my own custom manipulators?

There are two kinds of stream manipulators, the first are simple ones, like std::hex. These are functions with the following signature:

template <class _CharT, class _Traits>
std::basic_ostream<_CharT, _Traits>&
MANIPULATOR(std::basic_ostream<_CharT, _Traits>&os)
{
    ...
}

The second are in the form of objects which have a friend operator <<

struct MANIPULATOR {
    MANIPULATOR(...) { ... }
    friend std::ostream& operator<<(std::ostream&os, offset ofs)
    {
        ...
    }
}

Now these manipulators need to remember the change they are making to the stream somewhere. This is where the stream iword function comes in: this allows you to store custom parameters in a stream, and use them later. Each stream has a number of iwords, and pwords associated with the stream, you have to reserve slots in the iword or pword arrays using the xalloc function.

So now we can add our own manipulators

manipulator hexdump feature
hex::bin binary data
hex::step(n) stepsize
hex::offset(n) base offset

The resulting hexdumper can be used as follows:

std::cout << hex::offset(0x12000) << std::hex << hex::dumper(data, size) << std::endl;

or

std::cout << std::fill(0) << std::left << hex::dumper(data, size) << std::endl;

i made some handy manipulators which make this easier to type:

std::cout << hex::hexstring << hex::dumper(data, size) << std::endl;

The resulting library can be found at https://github.com/nlitsme/cpputils/

Comments

Comments powered by Disqus