Thursday, November 9, 2006

Put a hex on that dump

This is actually a snippet I posted to my forum last year, but seeing as my forum is a horrible place to read, I'll re-post it here. Why my forum is horrible? Well it's spam infested, for one. And I'm currently all too busy to move my site to the new colo, which has a brand new ASP.NET site + community server waiting. Ok, that wasn't entirely true -- the site isn't completed yet (... busy and all that). Anyhoo, here's the real content:

std::string hexdump(void* x, unsigned long len, unsigned int w)
{
std::ostringstream osDump;
std::ostringstream osNums;
std::ostringstream osChars;
std::string szPrevNums;
bool bRepeated = false;
unsigned long i;

for(i = 0; i <= len; i++)
{
if(i < len)
{
char c = (char)*((char*)x + i);
unsigned int n = (unsigned int)*((unsigned char*)x + i);
osNums << std::setbase(16) << std::setw(2) << std::setfill('0') << n << " ";
if(((i % w) != w - 1) && ((i % w) % 8 == 7))
osNums << "- ";
osChars << (iscntrl(c) ? '.' : c);
}

if(osNums.str().compare(szPrevNums) == 0)
{
bRepeated = true;
osNums.str("");
osChars.str("");
if(i == len - 1)
osDump << "*" << std::endl;
continue;
}

if(((i % w) == w - 1) || ((i == len) && (osNums.str().size() > 0)))
{
if(bRepeated)
{
osDump << "*" << std::endl;
bRepeated = false;
}
osDump << std::setbase(16) << std::setw(8) << std::setfill('0') << (i - (i % w)) << " "
<< std::setfill(' ') << std::setiosflags(std::ios_base::left)
<< std::setw(3 * w + ((w / 8) - 1) * 2) << osNums.str()
<< " |" << osChars.str() << std::resetiosflags(std::ios_base::left) << "|" << std::endl;
szPrevNums = osNums.str();
osNums.str("");
osChars.str("");
}
}

osDump << std::setbase(16) << std::setw(8) << std::setfill('0') << (i-1) << std::endl;

return osDump.str();
}

x is the base memory location for the dump.
len is the number of bytes to dump.
w is the number of bytes to display per line.

Before you go ahead and cry "code smell", let me pull out the example output:

00000000  00 01 02 03 04 05 06 07 - 08 09 0a 0b 0c 0d 0e 0f  |................|
00000010 10 11 12 13 14 15 16 17 - 18 19 1a 1b 1c 1d 1e 1f |................|
00000020 20 21 22 23 24 25 26 27 - 28 29 2a 2b 2c 2d 2e 2f | !"#$%&'()*+,-./|
00000030 30 31 32 33 34 35 36 37 - 38 39 3a 3b 3c 3d 3e 3f |0123456789:;<=>?|
00000040 40 41 42 43 44 45 46 47 - 48 49 4a 4b 4c 4d 4e 4f |@ABCDEFGHIJKLMNO|
00000050 50 51 52 53 54 55 56 57 - 58 59 5a 5b 5c 5d 5e 5f |PQRSTUVWXYZ[\]^_|
00000060 60 61 62 63 64 65 66 67 - 68 69 6a 6b 6c 6d 6e 6f |`abcdefghijklmno|
00000070 70 71 72 73 74 75 76 77 - 78 79 7a 7b 7c 7d 7e 7f |pqrstuvwxyz{|}~.|
00000080 80 81 82 83 84 85 86 87 - 88 89 8a 8b 8c 8d 8e 8f |ÇüéâäàåçêëèïîìÄÅ|
00000090 90 91 92 93 94 95 96 97 - 98 99 9a 9b 9c 9d 9e 9f |ÉæÆôöòûùÿÖÜø£Ø×ƒ|
000000a0 a0 a1 a2 a3 a4 a5 a6 a7 - a8 a9 aa ab ac ad ae af |áíóúñѪº¿®¬½¼¡«»|
000000b0 b0 b1 b2 b3 b4 b5 b6 b7 - b8 b9 ba bb bc bd be bf |¦¦¦¦¦ÁÂÀ©¦¦++¢¥+|
000000c0 c0 c1 c2 c3 c4 c5 c6 c7 - c8 c9 ca cb cc cd ce cf |+--+-+ãÃ++--¦-+¤|
000000d0 d0 d1 d2 d3 d4 d5 d6 d7 - d8 d9 da db dc dd de df |ðÐÊËÈiÍÎÏ++¦_¦Ì¯|
000000e0 e0 e1 e2 e3 e4 e5 e6 e7 - e8 e9 ea eb ec ed ee ef |ÓßÔÒõÕµþÞÚÛÙýݯ´|
000000f0 f0 f1 f2 f3 f4 f5 f6 f7 - f8 f9 fa fb fc fd fe ff |­±=¾¶§÷¸°¨·¹³²¦ |
00000100 61 61 61 61 61 61 61 61 - 61 61 61 61 61 61 61 61 |aaaaaaaaaaaaaaaa|
*
00000120 61 61 61 61 61 61 62 62 - 62 62 62 62 62 62 62 62 |aaaaaabbbbbbbbbb|
00000130

The output looks a tad borked here, but it really does output quite nice to the console. Either way, there it is. I might tidy the whole thing up at some point, but up until now it's made up a not-very-critical piece of my codebase, and is as such not eligible for the same prudent treatment as the rest of it. Feel free to give me a heads up if you happen to spot anything out of the ordinary, or have any good additions in mind. Remember, though: never write code this factored, magic number infested and generally messy. It'll eat your brain. Read my "Message Only Window" article at CodeGuru for a bunch of pointers on good practices for writing code.

Btw, see http://einaros.livejournal.com/#einaros2530 for real-world use of the function.

0 comments: