讨论码流的十六进制打印串(Linux hexdump的结果)和原始码流之间的转换。
背景
在谈谈异或加密中提到一个函数dumphex,用于把码流打印出来,作为调试之用。
比如一个字符串 “Hello, world!”经过dumphex,输出是: “48656C6C6F2C20776F726C6421”。——当然,仅在非字符形式的码流才有使用价值。不过为了描述问题方便,这里就用字符串示例了。
某些情况下,需要把后者再转回去。这里就讨论这个小函数。
原型
为了讨论方便,我们称”48656C6C6F2C20776F726C6421”形式的字符串为hexstring,显然满足条件:
- 这个字符串长度为偶数;
- 其中的每个字符都是0-9a-fA-F,即isxdigit()测试为true.
给出如下的函数原型:
bool hexstring2hex(const std::string &hexstring, unsigned char *buffer);
其中,
- hexstring[in]: 待转换的字符串,如”48656C6C6F2C20776F726C6421”
- buffer[out]: 转换之后的结果,由caller负责分配存储空间,长度至少是hexstring长度的一半。
- @return bool: 对于合法的hexstring,返回true,且buffer存储转换之后的结果。反之,返回false,buffer不做任何改变。
示例代码
下面是示例代码:
#include <assert.h>
#include <string>
#include <iostream>
typedef struct tagTwoChars {
unsigned char first;
unsigned char second;
}TwoChars;
static unsigned char hex_table[] = {
'0', '1', '2', '3', '4', '5', '6', '7',
'8', '9', 'A', 'B', 'C', 'D', 'E', 'F'};
static TwoChars hex2char(unsigned char data)
{
TwoChars twoChars;
twoChars.first = hex_table[(data & 0xF0) >> 4];
twoChars.second = hex_table[data & 0x0F];
return twoChars;
}
std::string hex2string(const unsigned char *data, int len)
{
std::string str;
TwoChars twoChars;
for (int i = 0; i < len; i++) {
twoChars = hex2char(data[i]);
str += twoChars.first;
str += twoChars.second;
}
return str;
}
static unsigned char char2hex(unsigned char c)
{
if (c >= '0' && c <= '9') return c - '0';
if (c >= 'a' && c <= 'f') return c - 'a' + 10;
// A to F
return c - 'A' + 10;
}
static unsigned char chars2hex(unsigned char high, unsigned char low)
{
unsigned char _high = char2hex(high);
unsigned char _low = char2hex(low);
unsigned char result = _high << 4 | _low;
return result;
}
bool hexstring2hex(const std::string &hexstring, unsigned char *buffer)
{
int len = hexstring.length();
if (len == 0) return true; // Oh, you may return false.
if (len % 2 != 0) return false;
int i;
for (i = 0; i < len; i++) {
if (!isxdigit(hexstring[i])) return false;
}
len = len / 2;
for (i = 0; i < len; i++) {
buffer[i] = chars2hex(hexstring[2 * i], hexstring[2 * i + 1]);
}
return true;
}
int main()
{
std::string s("Hello, world!");
std::string sHex = hex2string((unsigned char*)s.c_str(), s.length());
std::cout << "hex string:" << sHex << std::endl; // 48656C6C6F2C20776F726C6421
unsigned char buffer[16] = {0};
assert(hexstring2hex(sHex, buffer));
std::cout << "hex:" << buffer << std::endl; // Hello, world!
return 0;
}
可重用代码
一切妥当之后,就打包到Utility形式的class中, 假定为 class CHexStringUtils.
头文件(HexStringUtils.h)
#pragma once
#include <string>
class CHexStringUtils
{
public:
static std::string hex2string(const unsigned char *data, int len);
static bool hexstring2hex(const std::string &hexstring, unsigned char *buffer);
};
实现文件(HexStringUtils.cpp)
#include "HexStringUtils.h"
typedef struct tagTwoChars {
unsigned char first;
unsigned char second;
}TwoChars;
static unsigned char hex_table[] = {
'0', '1', '2', '3', '4', '5', '6', '7',
'8', '9', 'A', 'B', 'C', 'D', 'E', 'F'};
static TwoChars hex2char(unsigned char data)
{
TwoChars twoChars;
twoChars.first = hex_table[(data & 0xF0) >> 4];
twoChars.second = hex_table[data & 0x0F];
return twoChars;
}
std::string CHexStringUtils::hex2string(const unsigned char *data, int len)
{
std::string str;
TwoChars twoChars;
for (int i = 0; i < len; i++) {
twoChars = hex2char(data[i]);
str += twoChars.first;
str += twoChars.second;
}
return str;
}
static unsigned char char2hex(unsigned char c)
{
if (c >= '0' && c <= '9') return c - '0';
if (c >= 'a' && c <= 'f') return c - 'a' + 10;
// A to F
return c - 'A' + 10;
}
static unsigned char chars2hex(unsigned char high, unsigned char low)
{
unsigned char _high = char2hex(high);
unsigned char _low = char2hex(low);
unsigned char result = _high << 4 | _low;
return result;
}
bool CHexStringUtils::hexstring2hex(const std::string &hexstring, unsigned char *buffer)
{
int len = hexstring.length();
if (len == 0) return true; // Oh, you may return false.
if (len % 2 != 0) return false;
int i;
for (i = 0; i < len; i++) {
if (!isxdigit(hexstring[i])) return false;
}
len = len / 2;
for (i = 0; i < len; i++) {
buffer[i] = chars2hex(hexstring[2 * i], hexstring[2 * i + 1]);
}
return true;
}
测试代码
#include <cassert>
#include <iostream>
#include "HexStringUtils.h"
int main()
{
std::string s("Hello, world!");
std::string sHex = CHexStringUtils::hex2string((unsigned char*)s.c_str(), s.length());
std::cout << "hex string:" << sHex << std::endl; // 48656C6C6F2C20776F726C6421
unsigned char buffer[16] = {0};
assert(CHexStringUtils::hexstring2hex(sHex, buffer));
std::cout << "hex:" << buffer << std::endl; // Hello, world!
return 0;
}