@@ -845,6 +845,8 @@ class FieldArray(BaseField):
845845 the entire contents of the array.
846846 :param length_provider: The field providing a length value binding this
847847 message (if any). Set this field to None to leave unconstrained.
848+ :param num_elements_provider: The field providing the number of elements
849+ in the array. Set this field to None to leave unconstrained.
848850
849851 For example, one can imagine a message listing the zipcodes covered by
850852 a telephone area code. Depending on the population density, the number
@@ -863,7 +865,7 @@ class TelephoneZipcodes(Structure):
863865
864866 """
865867
866- def __init__ (self , substructure , length_provider = None , ** kwargs ):
868+ def __init__ (self , substructure , length_provider = None , num_elements_provider = None , ** kwargs ):
867869 BaseField .__init__ (self , ** kwargs )
868870 self .substructure = substructure
869871 self ._value = list ()
@@ -872,6 +874,12 @@ def __init__(self, substructure, length_provider=None, **kwargs):
872874 self .length_provider .associate_length_consumer (self )
873875 else :
874876 self .length_provider = None
877+ if isinstance (num_elements_provider , FieldPlaceholder ):
878+ self .num_elements_provider = self ._ph2f (num_elements_provider )
879+ self .num_elements_provider .length_value_provider = lambda : len (self ._value )
880+ else :
881+ self .num_elements_provider = None
882+
875883
876884 @property
877885 def bytes_required (self ):
@@ -880,15 +888,22 @@ def bytes_required(self):
880888 else :
881889 return self .length_provider .get_adjusted_length ()
882890
891+ @property
892+ def num_elements (self ):
893+ if self .num_elements_provider is None :
894+ return None
895+ else :
896+ return self .num_elements_provider .get_adjusted_length ()
897+
883898 def pack (self , stream ):
884899 for structure in self ._value :
885900 stream .write (structure .pack ())
886901
887902 def unpack (self , data , ** kwargs ):
888903 length = self .bytes_required
889- if length == 0 or (data == b"" and length is None ):
904+ if length == 0 or (data == b"" and length is None ) or self . num_elements == 0 :
890905 # Array is empty.
891- return
906+ return data
892907
893908 kwargs ['trailing' ] = True
894909 while True :
@@ -897,6 +912,14 @@ def unpack(self, data, **kwargs):
897912 self ._value .append (structure )
898913 if data == b"" :
899914 break
915+ if len (self ._value ) == self .num_elements :
916+ break
917+
918+ if self .num_elements is not None and len (self ._value ) != self .num_elements :
919+ raise SuitcaseParseError ("Expected %s elements but received %d." %
920+ (self .num_elements , len (self ._value )))
921+
922+ return data
900923
901924
902925class BaseFixedByteSequence (BaseField ):
0 commit comments