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

发布于 2024-09-05 13:29:14 字数 716 浏览 5 评论 0原文

所以我想解析一个二进制文件并从中提取一些数据。我面临的问题是我需要将 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_t 和ExternalType=char。不幸的是这不能编译。 所以问题是:如何将 char 流转换为 uint8_t 流?

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?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(2

找个人就嫁了吧 2024-09-12 13:29:14

我不知道你是否仍然遇到这个问题,但如果你仍然遇到这个问题,你能否详细说明一下你到底想要实现什么目标。问题是内部 char 和 unsigned char 是相同的。它们只是坐在某个地方的 8 位。无需转换。

唯一的区别在于编译器在您使用它们时如何解释它们。这意味着您应该能够通过在使用时使用 static_cast 来解决大多数问题。

顺便提一下,std::cout 将输出一个与 char 相同的无符号字符。如果你想要数值,你必须将其转换两次:

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

std:cout << int( asd );

我可以看到这样做的不便,并且可能 boost::iostreams 有某种方法可以为你做到这一点,但我从未使用过 boost::iostreams 并查看了答案就在这里,没有多少人可以帮助你。如果一切都失败了,只需重新解释数据即可。无论如何,如果转换意味着复制全部内容,那将是一个坏主意。

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.

匿名的好友 2024-09-12 13:29:14

您可以编写处理 uint8_t 和 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;

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;
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文