使用boost::iostreams逐字节解析二进制文件

3

我想解析一个二进制文件并从中提取一些数据。这个问题的难点在于我需要将一串char转换为一串unsigned char。 阅读Boost文档,看起来boost::iostreams::code_converter应该是解决方案,所以我尝试了以下代码:

typedef unsigned char uint8_t;
typedef boost::iostreams::stream<boost::iostreams::code_converter<
   boost::iostreams::basic_array_source<uint8_t>, 
   std::codecvt<uint8_t, char, std::mbstate_t> > > array_stream;

array_stream s; //initialized properly in the code
unsigned char asd;
s >> asd;
std::cout << asd << std::endl;

这个想法是指定一个 codecvt,其中 InternalType=uint8_tExternalType=char。不幸的是,这无法编译。

所以问题是:如何将一串 char 转换成一串 uint8_t

2个回答

2
我不知道您是否仍然有这个问题,但如果有,您能否详细说明您想要实现的目标。事实上,char和unsigned char在内部是相同的。它们只是8位数据存储在某个地方。不需要进行转换。
唯一的区别在于编译器在使用它们时如何解释它们。这意味着您应该能够通过在使用时使用static_cast来解决大多数问题。
顺便说一下,std::cout将输出与char相同的unsigned char。如果您想要数字值,您需要进行两次强制转换:
array_stream  s;   //initialized properly in the code
unsigned char asd;
s >> asd;

std:cout << int( asd );

我能理解这种情况的不便,可能boost::iostreams有一些方法可以帮助你解决问题,但我从未使用过boost::iostreams,而且看到这里回答的数量不多,很难得到帮助。如果其他方法都失败了,只需重新解释数据即可。无论如何,如果转换意味着全部复制,那么进行转换将是一个坏主意。


所以我猜原始问题的更大的背景是,我想给boost::spirit一个无符号字符流来解析。因此,在每次尝试从流中读取某些内容时在代码中放置static_casts是不可行的(并非我的代码正在进行所有读取)。最终,我通过放弃boost::iostreams并仅使用基于迭代器的解析器来解决了这个问题。 - Zsol

1

您可以编写自定义设备来处理uint8_t等数据类型。以下是一个示例:

template <typename Container>
class raw_back_insert_device
{
public:
    typedef char char_type;
    typedef typename Container::value_type raw_char_type;
    typedef boost::iostreams::sink_tag category;

    raw_back_insert_device(Container& container)
      : container_(container)
    {
    }

    std::streamsize write(char const* s, std::streamsize n)
    {
        auto start = reinterpret_cast<raw_char_type const*>(s);
        container_.insert(container_.end(), start, start + n);
        return n;
    }

private:
    Container& container_;
};

template <typename Container>
raw_back_insert_device<Container> raw_back_inserter(Container& cnt)
{
    return raw_back_insert_device<Container>(cnt);
}

class raw_array_source : public boost::iostreams::array_source
{
public:
    template <typename Char>
    raw_array_source(Char const* begin, Char const* end)
      : boost::iostreams::array_source(
          reinterpret_cast<char const*>(begin),
          reinterpret_cast<char const*>(end))
    {
    }

    template <typename Char>
    raw_array_source(Char const* begin, size_t size)
      : boost::iostreams::array_source(
          reinterpret_cast<char const*>(begin),
          size)
    {
    }

    template <typename Container>
    raw_array_source(Container& container)
      : raw_array_source(container.data(), container.size())
    {
    }

    std::streamsize read(char* s, std::streamsize n)
    {
        auto i = input_sequence();
        auto min = std::min(i.second - i.first, n);
        std::copy(i.first, i.first + min, s);
        return min;
    }
};

template <typename Container>
raw_array_source raw_container_source(Container& container)
{
    return raw_array_source(container);
}

你的代码将如下所示:

typedef unsigned char uint8_t;
typedef boost::iostreams::stream<
    boost::iostreams::code_converter<
        raw_array_source,
        std::codecvt<uint8_t, char, std::mbstate_t>
    >
> array_stream;

array_stream s; //initialized properly in the code
unsigned char asd;
s >> asd;
std::cout << asd << std::endl;

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接