def __init__(self, name, lengthfield, wordsize = 1): ''' Initialize the field with the given *name* and a *lengthfield*. The *lengthfield* must be a numeric field instance. *wordsize* specifies how many bytes a word contains and it can be a numeric value or a unary function that knows where to get the word size, it has a default value of 1. So, the total length in bytes of a :mod:`Data` field is the length field multiplied by the word size. If *wordsize* is a function, it takes the top-level root :mod:`Container` field as a single argument. This way, it is possible to provide a word size that depends on the value of another field. ''' Structure.__init__(self, name) self.__wordsize = wordsize wsizefunc = lambda root: \ lengthfield.value() * param_call(wordsize, root) self.__length = lengthfield self.__data = String("Data", wsizefunc) Structure.append(self, self.__length) Structure.append(self, self.__data)
class Data(Structure): ''' This class lets you store strings of characters (divided by words) and also provides a field to hold its length. It is a :mod:`Structure` with two fields: length and data (internally created with name *Data*). The length is a numeric field and specifies how many words the *Data* field contains. The *Data* field is internally a :class:`String`. ''' def __init__(self, name, lengthfield, wordsize = 1): ''' Initialize the field with the given *name* and a *lengthfield*. The *lengthfield* must be a numeric field instance. *wordsize* specifies how many bytes a word contains and it can be a numeric value or a unary function that knows where to get the word size, it has a default value of 1. So, the total length in bytes of a :mod:`Data` field is the length field multiplied by the word size. If *wordsize* is a function, it takes the top-level root :mod:`Container` field as a single argument. This way, it is possible to provide a word size that depends on the value of another field. ''' Structure.__init__(self, name) self.__wordsize = wordsize wsizefunc = lambda root: \ lengthfield.value() * param_call(wordsize, root) self.__length = lengthfield self.__data = String("Data", wsizefunc) Structure.append(self, self.__length) Structure.append(self, self.__data) def value(self): ''' Returns the value of the *Data* field as a string. ''' return self.__data.value() def set_value(self, value): ''' Sets a new string to the *Data* field. The given string length must be a mutliple of the word size and must fit in the length field (i.e. 300 characters are too long if the length field is :class:`UInt8`, as only 255 characters fit), otherwise a *ValueError* exception will be raised. ''' length = len(value) wordsize = param_call(self.__wordsize, self.root()) if (length % wordsize) == 0: try: self.__length.set_value(length / wordsize) except: raise ValueError("Data length must be lower than length " "field maximum size (%d given)" % length) self.__data.set_value(value) else: raise ValueError("Data length must be a multiple of %d (%d given)" \ % (wordsize, length))