码流转换

讨论码流的十六进制打印串(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;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值