Search code examples
kaitai-struct

Call external code to determine number of times to repeat expression


I have a sequence that has an 'id' with a repeat expression that I need to repeat an unknown number times, and I'm not sure if this is currently supported.

data_channels:
  seq:
    - id: fast_data
      type: u2
      repeat: expr
      repeat-expr: ???

What I would like to be able to do is call an external method that calculates the correct number of repetitions, and returns that number to kaitai. Like:

data_channels:
  seq:
    - id: fast_data
      type: u2
      repeat: expr
      repeat-expr: CalulateRepetitions

However, even with "ks-opaque-types: true" in the meta data, I get an error that "CalculateRepetitions" cannot be accessed.

The number of repetitions depends on a number of things that just aren't accessible from kaitai, so an external method is a perfect solution.

Thanks in advance for any suggestions.


Solution

  • If you know number of repetitions prior to type invocation, you can declare that as a type parameter and pass it from your application:

    data_channels:
      params:
        - id: num_items
          type: u4
      seq:
        - id: fast_data
          type: u2
          repeat: expr
          repeat-expr: num_items
    

    If you don't know that before parsing, you can still use this trick to bridge into opaque type and back, i.e.:

    meta:
      id: your_main_type
      ksc-opaque-types: true
    seq:
      - id: something
        type: u1
      # at this point we don't know number of repetitions yet
      - id: data_channels
        type: opaque_data_channels_wrapper
    

    After that, implement OpaqueDataChannelsWrapper class in your app. If there, it could be something like that:

    class OpaqueDataChannelsWrapper {
      public OpaqueDataChannelsWrapper(KaitaiStream io) {
        // do something here to determine number of repetitions
    
        // dive back into KaitaiStruct parsing with that information
        DataChannels realDataChannels = new DataChannels(io, numRepetitions);
      }
    }