예제 #1
0
    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')))
예제 #2
0
    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.")
예제 #3
0
    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)))