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

时间:2010-06-12 08:59:48

标签: c++ boost binaryfiles

所以我想解析一个二进制文件并从中提取一些数据。我面临的问题是我需要将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;

我们的想法是使用codecvtInternalType=uint8_t指定ExternalType=char。不幸的是,这不编译。 问题是:如何将char的流转换为uint8_t的流?

2 个答案:

答案 0 :(得分: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 );

我可以看到这方面带来的不便,可能还有提升:: iostreams有一些方法可以帮到你,但是我从来没有使用过boost :: iostreams,看看这里的答案数量,没有多少可以帮到你。如果所有其他方法都失败了,只需重新解释数据即可。在任何情况下转换它都是一个坏主意,如果这意味着复制它。

答案 1 :(得分:1)

您可以编写处理uint8_t&amp;的自定义设备。朋友。这是一个例子:

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;