kaitai-io / kaitai_struct

Kaitai Struct: declarative language to generate binary data parsers in C++ / C# / Go / Java / JavaScript / Lua / Nim / Perl / PHP / Python / Ruby
https://kaitai.io
3.96k stars 192 forks source link

switch-on for enum #1043

Open tannewt opened 1 year ago

tannewt commented 1 year ago

USB device and interface descriptors have class, subclass and protocol fields where the meaning of subclass depends on the value of class and the meaning of protocol depends on subclass. It'd be great if you could:

- id: class
  type: u1
  enum: interface_class
- id: subclass
  type: u1
  enum:
    switch-on: class
    cases:
      'interface_class::human_interface_device': hid_subclass

It'd work just like switch-on under type but for enums instead.

Thanks!

GreyCat commented 1 year ago

Can you elaborate a little bit more — e.g. what output do you expect from a compiler in such cases? Looks like all class-dependent subclasses effectively form their own separate types (enum)?

tannewt commented 1 year ago

I'm only using the web ide at the moment so I'm only looking to have the values annotate appropriately there. (Right now I cheated and only used the hid_subclass enum type.)

In code, I'd expect a separate enum type that was unioned for the original value.

tannewt commented 1 year ago

Full ksy I have so far is here: https://gist.github.com/tannewt/4c03dfe354c5d979720c7167730554b3

sample_usb_descriptors.zip

darkdread commented 3 months ago

As a work-around, I tried to switch-on types instead, but I encountered the following issue:

meta:
  id: test_id
  bit-endian: be
seq:
  - id: header
    type: header
    doc: This is header
types:
  header:
    seq:
      - id: cmd_class
        type: u1
        enum: enum_cmd_class
      - id: cmd_id
        size: 1
        type: cmd_id
  cmd_id:
    seq:
      - id: direction
        type: b1be
        enum: enum_direction
      - id: id
        type:
          switch-on: _parent.cmd_class
          cases:
            enum_cmd_class::a: cmd_id_a
            enum_cmd_class::b: cmd_id_b
  cmd_id_a:
    seq:
      - id: id
        type: b7be
        enum: enum_a
  cmd_id_b:
    seq:
      - id: id
        type: b7be
        enum: enum_b
enums:
  enum_direction:
    0: left
    1: right
  enum_cmd_class:
    0: a
    1: b
  enum_a:
    2: a
  enum_b:
    3: b

When ran with javascript, message shows "requested 1 bytes, but only 0 bytes available" cmd_id is 1 byte and both cmd_id.direction and cmd_id.id reads different bits from cmd_id. But currently cmd_id_a and cmd_id_b types which are switched-on from cmd_id.id reads from the next byte.

If the type of a field is a bit-sized integer (bXX), when we use a switch-on type, the underlying matched case uses the next byte in the stream. Can we reuse the same byte?

generalmimon commented 3 months ago

@darkdread:

If the type of a field is a bit-sized integer (bXX), when we use a switch-on type, the underlying matched case uses the next byte in the stream. Can we reuse the same byte?

See https://github.com/kaitai-io/kaitai_struct/issues/1070