Назови меня двоичным парсером. Парсер для двоичных данных
Итак, я получаю эти данные. Из сетевого сокета или из файла. Я собираю код, который будет интерпретировать данные. Прочитайте несколько байтов, проверьте некоторые флаги, и некоторые байты показывают, сколько данных следует. Прочитайте столько данных, промойте, повторите.
Эта задача очень напоминает мне синтаксический анализ исходного кода. Я удобен с 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. Если вы можете описать двоичные данные в их терминах, вы можете использовать различные доступные наборы. Не для слабонервных.
Конечно, ничто не мешает вам написать рекурсивный приличный синтаксический анализатор, скажем, для двоичных данных так же, как вы бы работали вручную с текстовым анализатором. Если формат, который вам нужно прочитать, не слишком сложен, это разумный способ продолжить.
Конечно, если вы форматируете очень просто, вы можете взглянуть на Чтение двоичного файла, определяемого структурой и похожим вопросом.
Я не знаю ни одного генератора парсера для нетекстового ввода, хотя это также возможно.
В случае, если вы не знакомы с синтаксическими анализаторами кода вручную, канонический вопрос SO - это научиться писать компилятор. Учебное пособие по Креншоу (и в формате PDF) быстро читается.
Существует инструмент, называемый binpac, который делает именно это.
http://www.icsi.berkeley.edu/pubs/networking/binpacIMC06.pdf