Skip to content

Instantly share code, notes, and snippets.

@santa4nt
Last active August 29, 2015 14:02
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save santa4nt/a2bb3c1474e9e9f56a9a to your computer and use it in GitHub Desktop.
Save santa4nt/a2bb3c1474e9e9f56a9a to your computer and use it in GitHub Desktop.
Convert a raw byte string into a hex string.
#include <stdio.h>
#include <assert.h>
#include <limits.h>
static const char *hexchars = "0123456789abcdef";
/**
* Convert a string of raw bytes into readable hex string.
*
* Input parameters:
* - bytes - a string of raw bytes
* - inlen - length of input, in bytes
*
* Output parameters:
* - buf - caller-supplied buffer space for output hex string
* - outlen - the valid length of said buffer space, in bytes
*
* Return value: 0 if success, the number of bytes needed in output buffer if not
*/
int bytes2hexstr(const char *bytes, unsigned int inlen,
char *buf, unsigned int outlen)
{
unsigned int i;
char byte;
if (!bytes || !inlen)
{
return 0;
}
// `buf` needs to at least be of length (`inlen` * 2 + 1) since
// each byte translates to two characters in hex string, plus terminating zero
if (!buf || outlen < (inlen * 2 + 1))
{
return inlen * 2 + 1;
}
outlen = 0;
for (i = 0; i < inlen; i++)
{
byte = bytes[i];
buf[outlen++] = hexchars[((byte >> 4) & 0x0f)];
buf[outlen++] = hexchars[(byte & 0x0f)];
}
buf[outlen] = '\0';
return 0;
}
#ifdef USE_BOOST_UT
#define BOOST_TEST_DYN_LINK
#define BOOST_TEST_MODULE bytes2hex_test
#include <boost/test/unit_test.hpp>
BOOST_AUTO_TEST_CASE(bytes2hex_empty_arguments)
{
char outbuf[32];
int res;
res = bytes2hexstr(NULL, 10, outbuf, 32);
BOOST_CHECK_EQUAL(res, 0);
res = bytes2hexstr("abc", 0, outbuf, 32);
BOOST_CHECK_EQUAL(res, 0);
res = bytes2hexstr("abc", 3, NULL, 32);
BOOST_CHECK_EQUAL(res, 7);
res = bytes2hexstr("abc", 3, outbuf, 0);
BOOST_CHECK_EQUAL(res, 7);
}
BOOST_AUTO_TEST_CASE(bytes2hex_string)
{
const char *inbytes = "\x00\x01\xde\xad\xbe\xef";
char outbuf[512];
int res;
res = bytes2hexstr(inbytes, 6, outbuf, 0);
BOOST_CHECK_EQUAL(res, 13);
res = bytes2hexstr(inbytes, 6, outbuf, res);
BOOST_CHECK_EQUAL(res, 0);
BOOST_CHECK_EQUAL(outbuf, "0001deadbeef");
}
BOOST_AUTO_TEST_CASE(bytes2hex_integer)
{
char outbuf[512];
int res;
unsigned int i = UINT_MAX;
const int uint_size_in_bytes = sizeof(unsigned int) / sizeof(char);
union _data
{
unsigned int uint;
char bytes[uint_size_in_bytes];
} data;
data.uint = i;
res = bytes2hexstr((const char *)data.bytes, uint_size_in_bytes, outbuf, 0);
BOOST_CHECK_EQUAL(res, 9);
res = bytes2hexstr((const char *)data.bytes, uint_size_in_bytes, outbuf, res);
BOOST_CHECK_EQUAL(res, 0);
BOOST_CHECK_EQUAL(outbuf, "ffffffff");
}
#else
int main()
{
char *inbytes;
char outbuf[512];
int res;
{
inbytes = (char *) "\x00\x01\xde\xad\xbe\xef";
res = bytes2hexstr(inbytes, 6, outbuf, 0);
assert (res > 0);
res = bytes2hexstr(inbytes, 6, outbuf, res);
printf("%s\n", outbuf);
// output: "0001deadbeef"
}
{
unsigned int i = UINT_MAX;
const int uint_size_in_bytes = sizeof(unsigned int) / sizeof(char);
union _data
{
unsigned int uint;
char bytes[uint_size_in_bytes];
} data;
data.uint = i;
res = bytes2hexstr(data.bytes, uint_size_in_bytes, outbuf, 0);
res = bytes2hexstr(data.bytes, uint_size_in_bytes, outbuf, res);
printf("%s\n", outbuf);
// output: "ffffffff" (unsigned int == DWORD == 32 bit, all 1s)
}
return 0;
}
#endif
CC = gcc
CFLAGS = -Wall -g -x c++
LFLAGS = -lstdc++ -lboost_unit_test_framework
DEFINES = -DUSE_BOOST_UT
OBJDIR = obj
BINDIR = bin
TARGET = bytes2hex
all: $(TARGET)
$(TARGET): $(TARGET).cpp
mkdir -p $(OBJDIR)
$(CC) $(CFLAGS) $(DEFINES) -c $(TARGET).cpp -o $(OBJDIR)/$(TARGET).o
exe: $(TARGET)
mkdir -p $(BINDIR)
$(CC) $(OBJDIR)/$(TARGET).o $(LFLAGS) -o $(BINDIR)/$(TARGET)
run: exe
./$(BINDIR)/$(TARGET)
valg: exe
valgrind --leak-check=full -v ./$(BINDIR)/$(TARGET)
clean:
rm -rf $(BINDIR) $(OBJDIR)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment