给我一个Binary Parser。二进制数据的解析器

时间:2010-02-06 21:43:47

标签: parsing binary protocols

所以,我收到了这些数据。从网络套接字,或从文件中。我正在拼凑将解释数据的代码。读取一些字节,检查一些标志,一些字节表示后面有多少数据。读入那么多数据,冲洗,重复。

这个任务让我想起解析源代码。我对lex / yacc和antlr很满意,但他们不能胜任这项任务。你不能将比特和原始字节指定为标记(好吧,也许你可以,但我不知道如何),你不能把它们哄成“读取两个字节,使它们成为无符号的16位整数,称之为 n ,然后读取 n 字节。“。

然后,当以系统方式定义协议/数据格式的规范(并非所有规范都是)时,应该有一种系统的方式来读取根据协议格式化的数据。对?

必须有一个工具才能做到这一点。

8 个答案:

答案 0 :(得分:10)

最近出现了

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 image file formatPE executable

答案 1 :(得分:8)

您可以尝试使用Boost.Spirit(v2),该binary parsing tools(v2)最近得到native,有字节感知mixedparsers Can Boost Spirit be used to parse byte stream data?

// 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))

更新:我发现了类似的问题,Joel de Guzman在答案中证实了二进制解析器的可用性:{{3}}

答案 2 :(得分:2)

用Python编写的Construct解析器在这个领域做了一些有趣的工作。

该项目有许多作者和停滞期,但截至2017年,它似乎再次变得更加活跃。

答案 3 :(得分:1)

阅读ASN.1。如果您可以用其术语描述二进制数据,则可以使用各种可用的工具包。不适合胆小的人。

答案 4 :(得分:1)

答案 5 :(得分:0)

当然,没有什么可以阻止你编写一个递归的正确解析器,比如二进制数据,就像你手工工具文本解析器一样。如果您需要阅读的格式不太复杂,这是一种合理的方式。

当然,如果格式为非常,您可以查看Reading binary file defined by a struct和类似的问题。

我不知道任何用于非文本输入的解析器生成器,尽管这些也是可能的。


如果您不熟悉手动编码解析器,则规范的SO问题为Learning to write a compilerCrenshaw tutorial(和in PDF)是快速阅读。

答案 6 :(得分:0)

另请参阅google协议缓冲区。

答案 7 :(得分:0)

有一个名为binpac的工具就是这样做的。

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