python-suitcase icon indicating copy to clipboard operation
python-suitcase copied to clipboard

DispatchTarget does not support FieldArray

Open martinpelikan opened this issue 8 years ago • 1 comments
trafficstars

Among other things, the protocol I'm working with includes a type and length in its metadata. The payload is a list of substructures that will be of the type specified. Here's a stripped down version of what I'm talking about.

class BinaryProtocol(Structure):
    # METADATA
    a = UBInt32()
    b = SBInt16()
    c = DispatchField(SBInt8())
    e = LengthField(SBInt16())

    # DATA
    data = DispatchTarget(None, c, {
        3: FieldArray(TypeThreeStruct),
        4: FieldArray(TypeFourStruct),
    })

It looks like the current implementation does not allow you to combine these two behaviours, you can either have a non-variable structure repeated, or a single structure of a variable type. The error raised when attempting the above is shown below:

/home/mpelikan/.local/lib/python3.6/site-packages/suitcase/structure.py in unpack(self, data, trailing)
    339 
    340     def unpack(self, data, trailing=False):
--> 341         return self._packer.unpack(data, trailing)
    342 
    343     def pack(self):

/home/mpelikan/.local/lib/python3.6/site-packages/suitcase/structure.py in unpack(self, data, trailing)
     62     def unpack(self, data, trailing=False):
     63         stream = BytesIO(data)
---> 64         self.unpack_stream(stream)
     65         stream.tell()
     66         if trailing:

/home/mpelikan/.local/lib/python3.6/site-packages/suitcase/structure.py in unpack_stream(self, stream)
    162 
    163             greedy_data_chunk = inverted_stream.read()[::-1]
--> 164             greedy_field.unpack(greedy_data_chunk)
    165 
    166         if crc_fields:

/home/mpelikan/.local/lib/python3.6/site-packages/suitcase/fields.py in unpack(self, data, **kwargs)
    404             raise SuitcaseParseError("Input data contains type byte not"
    405                                      " contained in mapping")
--> 406         message_instance = target_msg_type()
    407         self.setval(message_instance)
    408         self._value.unpack(data)

TypeError: 'FieldPlaceholder' object is not callable

martinpelikan avatar Mar 15 '17 00:03 martinpelikan

Looks like one workaround is to wrap the FieldArray in a Structure, then use that as the DispatchTarget. This comes at the cost of an additional .subfield access. Using the example above:

class TypeThreeStruct(Structure):
    data = FieldArray(ActualTypeThreeStruct)

class BinaryProtocol(Structure):
    # METADATA
    a = UBInt32()
    b = SBInt16()
    c = DispatchField(SBInt8())
    e = LengthField(SBInt16())

    # DATA
    data = DispatchTarget(None, c, {
        3: TypeThreeStruct,
    })

Then you could do:

thing = BinaryProtocol()
thing.unpack(b'...')
thing.data.data[index_of_interest]

martinpelikan avatar Mar 16 '17 00:03 martinpelikan