Назови меня двоичным парсером. Парсер для двоичных данных

Итак, я получаю эти данные. Из сетевого сокета или из файла. Я собираю код, который будет интерпретировать данные. Прочитайте несколько байтов, проверьте некоторые флаги, и некоторые байты показывают, сколько данных следует. Прочитайте столько данных, промойте, повторите.

Эта задача очень напоминает мне синтаксический анализ исходного кода. Я удобен с lex/yacc и antlr, но они не справляются с этой задачей. Вы не можете указать биты и необработанные байты в качестве токенов (ну, может быть, вы могли бы, но я не знаю, как), и вы не можете уговорить их "прочитать два байта, превратить их в 16-разрядное целое число без знака, вызвать его" n, а затем прочитать n байтов. "

С другой стороны, когда спецификация протокола / формата данных определяется систематически (не все из них), должен существовать систематический способ считывания данных, отформатированных в соответствии с протоколом. Правильно?

Должен быть инструмент, который делает это.

8 ответов

Решение

Вы можете попытаться использовать Boost.Spirit (v2), который недавно получил инструменты двоичного разбора, нативные и смешанные парсеры с поддержкой порядка байтов

// This is not a complete and useful example, but just illustration that parsing
// of raw binary to real data components is possible
typedef boost::uint8_t byte_t;
byte_t raw[16] = { 0 };
char const* hex = "01010000005839B4C876BEF33F83C0CA";
my_custom_hex_to_bytes(hex, raw, 16);

// parse raw binary stream bytes to 4 separate words
boost::uint32_t word(0);
byte_t* beg = raw;
boost::spirit::qi::parse(beg, beg + 16, boost::spirit::qi::dword, word))

ОБНОВЛЕНИЕ: я нашел похожий вопрос, где Джоэл де Гузман в своем ответе подтверждает наличие бинарных парсеров: можно ли использовать Boost Spirit для анализа данных потока байтов?

Недавно появилась инициатива Kaitai Struct для решения именно этой задачи: генерировать двоичные парсеры из спецификации. Вы можете предоставить схему для сериализации произвольной структуры данных в формате на основе YAML/JSON, например:

meta:
  id: my_struct
  endian: le
seq:
  - id: some_int
    type: u4
  - id: some_string
    type: str
    encoding: UTF-8
    size: some_int + 4
  - id: another_int
    type: u4

скомпилируйте его, используя ksc (они предоставляют реализацию эталонного компилятора), и, вуаля, у вас есть парсер на любом поддерживаемом языке программирования, например, в C++:

my_struct_t::my_struct_t(kaitai::kstream *p_io, kaitai::kstruct *p_parent, my_struct_t *p_root) : kaitai::kstruct(p_io) {
    m__parent = p_parent;
    m__root = this;
    m_some_int = m__io->read_u4le();
    m_some_string = m__io->read_str_byte_limit((some_int() + 4), "UTF-8");
    m_another_int = m__io->read_u4le();
}

или в Java:

private void _parse() throws IOException {
    this.someInt = this._io.readU4le();
    this.someString = this._io.readStrByteLimit((someInt() + 4), "UTF-8");
    this.anotherInt = this._io.readU4le();
}

После добавления этого в ваш проект, он предоставляет очень интуитивно понятный API-интерфейс, подобный этому (пример на Java, но они поддерживают больше языков):

// given file.dat contains 01 00 00 00|41 42 43 44|07 01 00 00

MyStruct s = MyStruct.fromFile("path/to/file.dat");
s.someString() // => "ABCD"
s.anotherInt() // => 263 = 0x107

Он поддерживает различные порядковые номера, условные структуры, подструктуры и т. Д. И многое другое. Могут быть проанализированы довольно сложные структуры данных, такие как формат файла изображения PNG или исполняемый файл PE.

Парсер Construct, написанный на Python, проделал интересную работу в этой области.

У проекта было несколько авторов и периоды застоя, но по состоянию на 2017 год он снова стал более активным.

https://github.com/lonelybug/ddprotocol/wiki/Getting-Start

надеюсь, что это полезно для вас.

Читайте на ASN.1. Если вы можете описать двоичные данные в их терминах, вы можете использовать различные доступные наборы. Не для слабонервных.

Смотрите также буферы протокола Google.

Конечно, ничто не мешает вам написать рекурсивный приличный синтаксический анализатор, скажем, для двоичных данных так же, как вы бы работали вручную с текстовым анализатором. Если формат, который вам нужно прочитать, не слишком сложен, это разумный способ продолжить.

Конечно, если вы форматируете очень просто, вы можете взглянуть на Чтение двоичного файла, определяемого структурой и похожим вопросом.

Я не знаю ни одного генератора парсера для нетекстового ввода, хотя это также возможно.


В случае, если вы не знакомы с синтаксическими анализаторами кода вручную, канонический вопрос SO - это научиться писать компилятор. Учебное пособие по Креншоув формате PDF) быстро читается.

Существует инструмент, называемый binpac, который делает именно это.

http://www.icsi.berkeley.edu/pubs/networking/binpacIMC06.pdf

Другие вопросы по тегам