4

在 Kaitai Struct 中解析截断的日志时,有什么方法可以传递某些字段?因为如果它读取一个字段(类型指定为枚举)但值不在其中,它将引发NullPointer Exception
所以我想问是否有任何方法可以实现这一点,就像default: passpython 库Construct中的属性一样

这是我的ksy文件:

meta:
  id: btsnoop
  endian: be
seq:
  - id: header
    type: header
  - id: packets
    type: packet
    repeat: eos
types:
  header:
    seq:
      - id: iden
        size: 8
      - id: version
        type: u4
      - id: datalink_type
        type: u4
        enum: linktype
  packet:
    seq:
      - id: ori_len
        type: u4
      - id: include_len
        type: u4
      - id: pkt_flags
        type: u4
      - id: cumu_drop
        type: u4
      - id: timestamp
        type: s8
      - id: data
        size: include_len
        type: frame
  frame:
    seq:
      - id: pkt_type
        type: u1
        enum: pkttype
      - id: cmd
        type: cmd
        if: pkt_type == pkttype::cmd_pkt
      - id: acl
        type: acl
        if: pkt_type == pkttype::acl_pkt
      - id: evt
        type: evt
        if: pkt_type == pkttype::evt_pkt  
  cmd:
    seq:
      - id: opcode
        type: u2le
      - id: params_len
        type: u1
      - id: params
        size: params_len
  acl:
    seq:
      - id: handle
        type: u2le
  evt:
    seq:
      - id: status
        type: u1
        enum: status
      - id: total_length
        type: u1
      - id: params
        size-eos: true
enums:  <-- I need to list all possible option in every enum?
  linktype:
    0x03E9: unencapsulated_hci
    0x03EA: hci_uart
    0x03EB: hci_bscp
    0x03EC: hci_serial
  pkttype:
    1: cmd_pkt
    2: acl_pkt
    4: evt_pkt
  status:
    0x0D: complete_D
    0x0E: complete_E
    0xFF: vendor_specific

谢谢您的回复 :)

4

1 回答 1

3

您在这里仍然面临两个问题:)

解析部分/截断/损坏的数据

这里的主要问题是通常 Kaitai Struct 将 .ksy 编译成在类构造函数中进行实际解析的代码。这意味着如果出现问题,繁荣,你根本没有对象。在大多数用例中,这是所需的行为,因为它实际上允许您确保对象已完全初始化。问题通常是EOFException, 当格式想要读取下一个原语时,但流中没有数据了,或者,在一些更复杂的情况下,还有其他东西。

但是,正如您所提到的,在某些用例中,“尽力而为”解析会有所帮助 - 即您可以使用半填充对象。另一个流行的用例是可视化器:在那里显示“尽力而为”也很有帮助,因为最好将用户半解析结果可视化(以帮助定位错误)而不是根本没有结果(并留下用户猜测)。

Kaitai Struct 中有一个简单的解决方案 - 您可以使用--debug选项编译您的类。这样,您将获得一个对象创建和解析分离的类,解析只是对象的另一种方法(void _read())。但是,这意味着您必须手动调用解析方法。例如,如果您的原始代码是:

Btssnoop b = Btssnoop.fromFile("/path/to/file.bin");
System.out.println(b.packets.size());

在你用 编译它之后--debug,你必须做额外的步骤:

Btssnoop b = Btssnoop.fromFile("/path/to/file.bin");
b._read();
System.out.println(b.packets.size());

然后你可以将它包装在一个 try/catch 块中,即使在得到以下内容后实际上也继续处理IOException

Btssnoop b = Btssnoop.fromFile("/path/to/file.bin");
try {
    b._read();
} catch (IOException e) {
    System.out.println("warning: truncated packets");
}
System.out.println(b.packets.size());

不过,有一些问题:

  • --debug截至 v0.3 版,尚不能用于 Java 目标;实际上,它现在甚至不在公共 git 存储库中,但我希望我能尽快推送它。
  • --debug还做了一些额外的事情,比如写下每个属性的位置,这会带来相当苛刻的性能/内存损失。告诉我您是否需要一个开关来编译“单独的构造函数/解析”功能而没有其他--debug功能 - 我可以想到额外的开关来启用它。
  • 如果您需要在传入数据包到达时对其进行连续解析,那么将它们全部存储在内存中并在每次更新时重新解析它们可能不是一个好主意。我们正在为那个考虑基于事件的解析模型,如果你对那个感兴趣,请告诉我。

缺少枚举值和 NPE

当前的 Java 实现将枚举读取转换为类似

this.pet1 = Animal.byId(_io.readU4le());

其中 Animal.byId 被翻译成:

private static final Map<Long, Animal> byId = new HashMap<Long, Animal>(3);
static {
    for (Animal e : Animal.values())
        byId.put(e.id(), e);
}
public static Animal byId(long id) { return byId.get(id); }

当地图中没有找到值时, Java Map 的 getnull按合同返回。您应该能够将该空值与某些东西(即其他枚举值)进行比较,并得到正确的真或假。你能告诉我你究竟在哪里遇到了 NPE 问题,即你的代码、生成的代码和堆栈跟踪吗?

于 2016-07-22T09:03:22.040 回答