【问题标题】:Name me a Binary Parser. A parser for binary data [closed]命名我为二进制解析器。二进制数据的解析器[关闭]
【发布时间】:2010-02-06 21:43:46
【问题描述】:

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

这个任务让我想起了解析源代码。我对 lex/yacc 和 antlr 很满意,但他们无法胜任这项任务。您不能将位和原始字节指定为标记(好吧,也许您可​​以,但我不知道如何),并且您不能将它们哄成“读取两个字节,将它们变成一个无符号的 16 位整数,调用它n,然后读取 n 个字节。”。

再一次,当协议/数据格式的规范以系统的方式定义时(并非全部都是),应该有系统的方式来读取根据协议格式化的数据。正确的?

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

【问题讨论】:

  • 投票重新开放,因为这不是寻求建议,而是更多地了解是否存在某种技术。我发现这个页面非常相关和有用,我不想认为它对那些没有关闭/重新打开权限的人隐藏

标签: parsing binary protocols


【解决方案1】:

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等相当复杂的数据结构。

【讨论】:

    【解决方案2】:

    您可以尝试使用Boost.Spirit (v2),它最近获得了binary parsing tools、字节序感知nativemixed parsers

    // 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 在他的回答中确认了二进制解析器的可用性:Can Boost Spirit be used to parse byte stream data?

    【讨论】:

    • 这看起来很有希望。谢谢!
    【解决方案3】:

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

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

    【讨论】:

    • 最近好像有人维修了。他们也有new docs
    【解决方案4】:

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

    【讨论】:

      【解决方案5】:

      【讨论】:

      • 单独链接不好,请提供总结。
      • 对此感到抱歉。请忘记这个链接,我会以某种方式重构这个工具。
      【解决方案6】:

      当然,没有什么能阻止您编写一个体面的递归解析器,例如,对于二进制数据,就像您手动编写文本解析器一样。如果您需要阅读的格式不是太复杂,这是一个合理的方法。

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

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


      如果您不熟悉手动编码解析器,那么规范的 SO 问题是 Learning to write a compilerCrenshaw tutorial(和in PDF)读起来很快。

      【讨论】:

      • 嗯,我基本上就是这样写解析器的。用手,就是这样。但我是世界上第一个这样做的人吗?
      【解决方案7】:

      另请参阅 google 协议缓冲区。

      【讨论】:

      • 这真的是评论,而不是问题的答案。请使用“添加评论”为作者留下反馈。
      【解决方案8】:

      有一个名为 binpac 的工具可以做到这一点。

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

      【讨论】:

        猜你喜欢
        • 2011-11-23
        • 2014-11-12
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2018-05-20
        • 2023-03-15
        • 2018-12-14
        相关资源
        最近更新 更多