Использование boost :: iostreams для разбора двоичного файла побайтно - PullRequest
3 голосов
/ 12 июня 2010

Итак, я хотел бы проанализировать двоичный файл и извлечь из него некоторые данные.Проблема, с которой я сталкиваюсь, заключается в том, что мне нужно преобразовать поток char s в поток unsigned char s.Читая документацию по бусту, кажется, что 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 s в поток uint8_t s?

Ответы [ 2 ]

2 голосов
/ 28 июня 2010

Я не знаю, если у вас все еще есть эта проблема, но если у вас есть, не могли бы вы рассказать немного о том, что именно вы пытаетесь достичь.Дело в том, что внутренне символ и символ без знака одинаковы.Они всего лишь 8 бит сидят где-то.Нет преобразования не требуется.

Единственное отличие состоит в том, как компилятор интерпретирует их, когда вы их используете.Это означает, что вы сможете решить большинство проблем, используя static_cast во время использования.

Кстати, std :: cout выведет неподписанный символ, идентичный символу.Если вы хотите получить числовое значение, вы должны привести его дважды:

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

std:cout << int( asd );

Я вижу в этом неудобство и, возможно, boost :: iostreams может как-то это сделать, но я никогда не использовал boost:: iostreams и, глядя на количество ответов здесь, не многие могут вам помочь.Если ничего не помогает, просто переосмыслите данные.В любом случае преобразование было бы плохой идеей, если бы это означало копирование всего этого.

1 голос
/ 07 марта 2012

Вы можете написать пользовательские устройства, которые обрабатывают 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;
...