2010-02-06 115 views
18

所以,我得到这些数据。从网络套接字,或从一个文件。我正在拼凑代码来解释数据。读取一些字节,检查一些标志,一些字节表示后面有多少数据。阅读那么多的数据,冲洗,重复。给我一个二进制解析器。二进制数据解析器

这个任务使我想起了解析源代码的很多事情。我对lex/yacc和antlr很满意,但他们不能胜任这项工作。你不能指定位和原始字节作为标记(也许你可以,但我不知道怎么做),并且你不能哄骗它们“读取两个字节,把它们变成一个无符号的16位整数,称之为n,然后读取n字节。“。然后再次,当协议/数据格式的规范是以系统的方式定义的时候(不是全部都是),应该有一个系统的方法来读取根据协议格式化的数据。对?

有一个工具可以做到这一点。

回答

7

您可以尝试采用Boost.Spirit(V2),最近得到了binary parsing tools,字节序感知nativemixedparsers

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

更新:我发现类似的问题,其中乔尔·古斯曼证实了他的答案可用性二进制解析器:Can Boost Spirit be used to parse byte stream data?

+0

看起来很有希望。谢谢! – doppelfish

1

在ASN.1上阅读。如果您可以用它的术语来描述二进制数据,那么您可以使用各种可用的套件。不是因为心灵的隐隐。

0

肯定没有什么能够阻止你编写一个递归体面的解析器,比如说,对于二进制数据来说,就像你手工操作文本解析器一样。如果你需要阅读的格式不太复杂,这是一个合理的方法来进行。

当然,如果你的格式是非常简单你可以看看Reading binary file defined by a struct以及类似的问题。

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


在你不熟悉的手工编码的解析器的情况下,规范的SO问题是Learning to write a compilerCrenshaw tutorial(和in PDF)是一个快速阅读。

+0

那么,我*本质上就是这样写一个解析器。手工就是这样。但我是否是第一个这样做的人? – doppelfish

2

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

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

+1

最近看起来有人拿起维修。他们也有[新文档](http://construct.readthedocs.org/en/latest/)。 – dowski

0

另请参阅google协议缓冲区。

+1

这实在是一个评论,而不是对问题的回答。请使用“添加评论”为作者留下反馈。 – Thor

9

Kaitai Struct主动近来出现正好解决了这一任务:以产生从规范二进制解析器。您可以在一个基于JSON的YAML /格式一样,任意数据结构的序列化提供了一个方案:

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可以被解析。