def get_desc(self, desc_key, attr_name=None): '''Returns the value in the object's descriptor under the key "desc_key". If attr_name is not None, the descriptor being searched for "desc_key" will instead be the attribute "attr_name".''' desc = object.__getattribute__(self, "desc") # if we are getting something in the descriptor # of one of this Block's attributes, then we # need to set desc to the attributes descriptor if attr_name is not None: if isinstance(attr_name, int): desc = desc['SUB_STRUCT'] elif attr_name in desc: desc = desc[attr_name] else: try: desc = desc[desc['NAME_MAP'][attr_name]] except Exception: raise DescKeyError(("Could not locate '%s' in " + "the descriptor of '%s'.") % (attr_name, desc.get('NAME'))) # Try to return the descriptor value under the key "desc_key" if desc_key in desc: return desc[desc_key] try: return desc[desc['NAME_MAP'][desc_key]] except KeyError: if attr_name is not None: raise DescKeyError(("Could not locate '%s' in the " + "sub-descriptor '%s' in the descriptor " + "of '%s'") % (desc_key, attr_name, desc.get('NAME'))) else: raise DescKeyError(("Could not locate '%s' in the " + "descriptor of '%s'.") % (desc_key, desc.get('NAME')))
def set_size(self, new_value=None, attr_index=None, **context): ''' Sets the size of the 'attr_index' element in this Block to 'new_value' using the SIZE entry in self.desc[attr_index]. If the attribute itself has a descriptor, uses its descriptor instead of the one in self.desc[attr_index] If 'new_value' isnt supplied, calculates it using the sizecalc method of the 'TYPE' entry in the descriptor. If the SIZE entry is a string, the size will be set using self.set_neighbor and providing the SIZE entry as the nodepath. If the SIZE entry is a function, the size will be set by doing: size_setter(attr_index=attr_index, new_value=new_value, parent=self, node=node, **context) where size_setter is the function under the descriptors SIZE key, new_value is the calculated or provided value to set the size to, context is a dictionary of the remaining supplied keyword arguments, node is the attribute whose size is being set, and attr_index is the provided attr_index argument. If attr_index is an int, sets the size of self[attr_index]. If attr_index is a str, sets the size of self.__getattr__(attr_index). If attr_index is None, this method will do nothing. This is because WhileBlocks are designed to express data which doesnt store a size. Raises DescEditError if the descriptor 'SIZE' entry is an int and the value the size is being set to is greater than what is currently in the descriptor. Raises DescKeyError if 'SIZE' doesnt exist in the descriptor. Raises TypeError if the 'SIZE' entry isnt an int, string, or function. ''' self_desc = object.__getattribute__(self, 'desc') if isinstance(attr_index, str): attr_index = self_desc['NAME_MAP'][attr_index] elif not isinstance(attr_index, int): # cant set size of WhileArrays return node = self[attr_index] # try to get the size directly from the node try: desc = node.desc size = self_desc['SIZE'] error_num = 0 except Exception: # if that fails, try to get it from the desc of the parent desc = self_desc[attr_index] try: size = desc['SIZE'] error_num = 0 except Exception: # its parent cant tell us the size, raise this error error_num = 1 if 'TYPE' in desc and not desc['TYPE'].is_var_size: # the size is not variable so it cant be set # without changing the type. raise this error error_num = 2 if error_num: f_type = desc['TYPE'] if error_num == 1: raise DescKeyError("Could not locate size for " + "attribute '%s' in block '%s'." % (desc.get('NAME', UNNAMED), self_desc.get('NAME', UNNAMED))) raise DescKeyError(("Can not set size for attribute " + "'%s' in block '%s'.\n'%s' has a " + "fixed size of '%s'.\nTo change its " + "size you must change its FieldType.") % (desc.get('NAME', attr_index), self_desc.get('NAME', UNNAMED), f_type, f_type.size)) if isinstance(size, int): # Because literal descriptor sizes are supposed to be static # (unless you're changing the structure), we don't even try to # change the size if the new size is less than the current one. if new_value is None and newsize <= size: return raise DescEditError("Changing a size statically defined in a " + "descriptor is not supported through " + "set_size. Make a new descriptor instead.") # if a new size wasnt provided then it needs to be calculated if new_value is not None: newsize = new_value else: newsize = desc['TYPE'].sizecalc(node, parent=self, attr_index=attr_index, **context) if isinstance(size, str): # set size by traversing the tag structure # along the path specified by the string self.set_neighbor(size, newsize, node) elif hasattr(size, "__call__"): # set size by calling the provided function size(attr_index=attr_index, new_value=newsize, parent=self, node=node, **context) else: raise TypeError(("Size specified in '%s' is not a valid type." + "Expected int, str, or function. Got %s.\n") % (desc.get('NAME', attr_index), type(size)) + "Cannot determine how to set the size.")
def set_size(self, new_value=None, attr_index=None, **context): ''' Sets the size of this Block to 'new_value' using the SIZE entry in the descriptor. If 'attr_index' is not None, uses the descriptor of the attribute 'attr_index'. If the attribute has a descriptor, uses its descriptor instead of the one in self.desc[attr_index] If new_value isnt supplied, uses the value returned by the sizecalc method of the TYPE entry in the descriptor. If attr_index is None, calculates the size of this Block, otherwise calculates the size of the specified attribute. If the SIZE entry is a string, the size will be set with: self.set_neighbor(nodepath, new_value, node) where 'node' is this Block(or its attribute if attr_index is not None), and nodepath is the value in the descriptor under 'SIZE'. If the SIZE entry is a function, If attr_index is an int, sets the size of self[attr_index]. If attr_index is a str, sets the size of self.__getattr__(attr_index). Raises a DescEditError if the descriptor 'SIZE' entry is an int FINISH WRITING THIS DOCSTRING Size units are dependent on the data type being measured. Variables and structs will be measured in bytes and arrays and containers will be measured in entries. The descriptor may specify size in terms of already parsed fields. ''' self_desc = object.__getattribute__(self, 'desc') if isinstance(attr_index, int): node = self[attr_index] # try to get the size directly from the node or the parent try: desc = node.desc except AttributeError: desc = self_desc[attr_index] size = desc.get('SIZE') elif isinstance(attr_index, str): node = self.__getattr__(attr_index) error_num = 0 # try to get the size directly from the node try: desc = node.desc size = desc['SIZE'] except Exception: # if that fails, try to get it from the desc of the parent try: desc = self_desc[self_desc['NAME_MAP'][attr_index]] except Exception: desc = self_desc[attr_index] try: size = desc['SIZE'] except Exception: # its parent cant tell us the size, raise this error error_num = 1 if 'TYPE' in desc and not desc['TYPE'].is_var_size: # the size is not variable so it cant be set # without changing the type. raise this error error_num = 2 if error_num: attr_name = desc.get('NAME', UNNAMED) if isinstance(attr_index, (int, str)): attr_name = attr_index if error_num == 1: raise DescKeyError( "Could not determine size for attribute " + "'%s' in block '%s'." % (attr_name, self_desc['NAME'])) elif error_num == 2: raise DescKeyError( ("Can not set size for attribute '%s' in block '%s'." + "\n'%s' has a fixed size of '%s'.\nTo change the " + "size of '%s' you must change its FieldType.") % (attr_name, self_desc['NAME'], desc['TYPE'], desc['TYPE'].size, attr_name)) else: node = self desc = self_desc size = desc.get('SIZE') # raise exception if the size is None if size is None: attr_name = desc.get('NAME', UNNAMED) if isinstance(attr_index, (int, str)): attr_name = attr_index raise DescKeyError("'SIZE' does not exist in '%s'." % attr_name) # if a new size wasnt provided then it needs to be calculated if new_value is not None: newsize = new_value elif hasattr(node, 'parent'): newsize = desc['TYPE'].sizecalc(parent=node.parent, node=node, attr_index=attr_index, **context) else: newsize = desc['TYPE'].sizecalc(parent=self, node=node, attr_index=attr_index, **context) if isinstance(size, int): # Because literal descriptor sizes are supposed to be static # (unless you're changing the structure), we don't even try to # change the size if the new size is less than the current one. if new_value is None and newsize <= size: return raise DescEditError("Changing a size statically defined in a " + "descriptor is not supported through " + "set_size. Make a new descriptor instead.") elif isinstance(size, str): # set size by traversing the tag structure # along the path specified by the string self.set_neighbor(size, newsize, node) return elif hasattr(size, '__call__'): # set size by calling the provided function if hasattr(node, 'parent'): size(attr_index=attr_index, new_value=newsize, parent=node.parent, node=node, **context) else: size(attr_index=attr_index, new_value=newsize, parent=self, node=node, **context) return self_name = self_desc['NAME'] if isinstance(attr_index, (int, str)): self_name = attr_index raise TypeError(("size specified in '%s' is not a valid type." + "\nExpected int, str, or function. Got %s.\n") % (self_name, type(size)))