python-suitcase
python-suitcase copied to clipboard
DispatchTarget does not support FieldArray
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
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]