Подтвердить что ты не робот

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

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

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

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

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

4b9b3361

Ответ 1

Вы можете попытаться использовать Boost.Spirit (v2), который недавно получил двоичные инструменты анализа, endianness-aware native и mixed парсеры

// 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 использоваться для анализа данных потока байтов?

Ответ 2

Инициатива 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 (они предоставляют реализацию эталонного компилятора), и, voila, у вас есть парсер на любом поддерживаемом языке программирования, например, в С++:

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-исполняемый файл.

Ответ 3

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

В проекте было несколько авторов и периоды стагнации, но с 2017 года он, кажется, более активен снова.

Ответ 4

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

Ответ 6

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

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

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


В случае, если вы не знакомы с синтаксическими анализаторами вручную, канонический вопрос SO - Обучение написанию компилятора. Учебник Crenshawв PDF) является быстро читается.

Ответ 7

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