开发者

Using boost::iostreams to parse a binary file byte by byte

So I would like to parse a binary file and extract some data from it. The problem I am facing with this is that I need to convert a stream of chars to a stream of unsigned chars. Reading the boost documentation, it seems that boost::iostreams::code_converter should be the solution for this, so I tried this:

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;
开发者_运维百科

The idea was to specify a codecvt with InternalType=uint8_t and ExternalType=char. Unfortunately this does not compile. So the question is: how do I convert a stream of chars to a stream of uint8_ts?


I don't know if you you still have this problem, but if you do, could you elaborate a little bit on what exactly you are trying to achieve. The thing is internally char and unsigned char are the same. They are just 8 bits sitting somewhere. No conversion is needed.

The only difference is in how the compiler interprets them when you use them. This means you should be able to solve most problems by using a static_cast at the time of usage.

For your information by the way, std::cout will output a unsigned char identical to a char. If you want the numerical value you have to cast it twice:

array_stream  s;   //initialized properly in the code
unsigned char asd;
s >> asd;

std:cout << int( asd );

I can see the inconvenience in this and possibly boost::iostreams has some way to do that for you, but I have never used boost::iostreams and looking at the number of answers here, not many can help you. If all else fails, just reinterpret the data. In any case converting it would be a bad idea if that meant copying it all.


You could write custom devices that handle uint8_t & friends. Here is an example:

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);
}

Your could would then look as follows:

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;
0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜