Пример #1
0
def _ComputeIds(root, predetermined_tids):
    """Returns a dict of textual id -> numeric id for all nodes in root.

  IDs are mostly assigned sequentially, but will vary based on:
    * first_id node attribute (from first_ids_file)
    * hash of textual id (if not first_id is defined)
    * offset node attribute
    * whether the textual id matches a system id
    * whether the node generates its own ID via GetId()

  Args:
    predetermined_tids: Dict of textual id -> numeric id to use in return dict.
  """
    from grit.node import empty, include, misc, structure

    ids = {}  # Maps numeric id to textual id
    tids = {}  # Maps textual id to numeric id
    id_reasons = {
    }  # Maps numeric id to text id and a human-readable explanation
    group = None
    last_id = None
    predetermined_ids = {
        value: key
        for key, value in predetermined_tids.items()
    }

    for item in root:
        if isinstance(item, empty.GroupingNode):
            # Note: this won't work if any GroupingNode can be contained inside
            # another.
            group = item
            last_id = None
            continue

        assert not item.GetTextualIds() or isinstance(
            item, (include.IncludeNode, message.MessageNode,
                   misc.IdentifierNode, structure.StructureNode))

        # Resources that use the RES protocol don't need
        # any numerical ids generated, so we skip them altogether.
        # This is accomplished by setting the flag 'generateid' to false
        # in the GRD file.
        if item.attrs.get('generateid', 'true') == 'false':
            continue

        for tid in item.GetTextualIds():
            if util.SYSTEM_IDENTIFIERS.match(tid):
                # Don't emit a new ID for predefined IDs
                continue

            if tid in tids:
                continue

            if predetermined_tids and tid in predetermined_tids:
                id = predetermined_tids[tid]
                reason = "from predetermined_tids map"

            # Some identifier nodes can provide their own id,
            # and we use that id in the generated header in that case.
            elif hasattr(item, 'GetId') and item.GetId():
                id = long(item.GetId())
                reason = 'returned by GetId() method'

            elif ('offset' in item.attrs and group
                  and group.attrs.get('first_id', '') != ''):
                offset_text = item.attrs['offset']
                parent_text = group.attrs['first_id']

                try:
                    offset_id = long(offset_text)
                except ValueError:
                    offset_id = tids[offset_text]

                try:
                    parent_id = long(parent_text)
                except ValueError:
                    parent_id = tids[parent_text]

                id = parent_id + offset_id
                reason = 'first_id %d + offset %d' % (parent_id, offset_id)

            # We try to allocate IDs sequentially for blocks of items that might
            # be related, for instance strings in a stringtable (as their IDs might be
            # used e.g. as IDs for some radio buttons, in which case the IDs must
            # be sequential).
            #
            # We do this by having the first item in a section store its computed ID
            # (computed from a fingerprint) in its parent object.  Subsequent children
            # of the same parent will then try to get IDs that sequentially follow
            # the currently stored ID (on the parent) and increment it.
            elif last_id is None:
                # First check if the starting ID is explicitly specified by the parent.
                if group and group.attrs.get('first_id', '') != '':
                    id = long(group.attrs['first_id'])
                    reason = "from parent's first_id attribute"
                else:
                    # Automatically generate the ID based on the first clique from the
                    # first child of the first child node of our parent (i.e. when we
                    # first get to this location in the code).

                    # According to
                    # http://msdn.microsoft.com/en-us/library/t2zechd4(VS.71).aspx
                    # the safe usable range for resource IDs in Windows is from decimal
                    # 101 to 0x7FFF.

                    id = FP.UnsignedFingerPrint(tid)
                    id = id % (0x7FFF - 101) + 101
                    reason = 'chosen by random fingerprint -- use first_id to override'

                last_id = id
            else:
                id = last_id = last_id + 1
                reason = 'sequentially assigned'

            reason = "%s (%s)" % (tid, reason)
            # Don't fail when 'offset' is specified, as the base and the 0th
            # offset will have the same ID.
            if id in id_reasons and not 'offset' in item.attrs:
                raise exception.IdRangeOverlap(
                    'ID %d was assigned to both %s and %s.' %
                    (id, id_reasons[id], reason))

            if id < 101:
                print(
                    'WARNING: Numeric resource IDs should be greater than 100 to\n'
                    'avoid conflicts with system-defined resource IDs.')

            if tid not in predetermined_tids and id in predetermined_ids:
                raise exception.IdRangeOverlap(
                    'ID %d overlaps between %s and %s' %
                    (id, tid, predetermined_ids[tid]))

            ids[id] = tid
            tids[tid] = id
            id_reasons[id] = reason

    return tids
Пример #2
0
    def Format(self, item, lang='', output_dir='.'):
        # Resources that use the RES protocol don't need
        # any numerical ids generated, so we skip them altogether.
        # This is accomplished by setting the flag 'generateid' to false
        # in the GRD file.
        if 'generateid' in item.attrs:
            if item.attrs['generateid'] == 'false':
                return ''

        text_ids = item.GetTextualIds()

        # We consider the "parent" of the item to be the GroupingNode containing
        # the item, as its immediate parent may be an <if> node.
        item_parent = item.parent
        import grit.node.empty
        while item_parent and not isinstance(item_parent,
                                             grit.node.empty.GroupingNode):
            item_parent = item_parent.parent

        lines = []
        for tid in text_ids:
            if util.SYSTEM_IDENTIFIERS.match(tid):
                # Don't emit a new ID for predefined IDs
                continue

            # Some identifier nodes can provide their own id,
            # and we use that id in the generated header in that case.
            if hasattr(item, 'GetId') and item.GetId():
                id = long(item.GetId())

            elif ('offset' in item.attrs and item_parent
                  and 'first_id' in item_parent.attrs
                  and item_parent.attrs['first_id'] != ''):
                offset_text = item.attrs['offset']
                parent_text = item_parent.attrs['first_id']

                try:
                    offset_id = long(offset_text)
                except ValueError:
                    offset_id = self.tids_[offset_text]

                try:
                    parent_id = long(parent_text)
                except ValueError:
                    parent_id = self.tids_[parent_text]

                id = parent_id + offset_id

            # We try to allocate IDs sequentially for blocks of items that might
            # be related, for instance strings in a stringtable (as their IDs might be
            # used e.g. as IDs for some radio buttons, in which case the IDs must
            # be sequential).
            #
            # We do this by having the first item in a section store its computed ID
            # (computed from a fingerprint) in its parent object.  Subsequent children
            # of the same parent will then try to get IDs that sequentially follow
            # the currently stored ID (on the parent) and increment it.
            elif not item_parent or not hasattr(item_parent, '_last_id_'):
                # First check if the starting ID is explicitly specified by the parent.
                if (item_parent and 'first_id' in item_parent.attrs
                        and item_parent.attrs['first_id'] != ''):
                    id = long(item_parent.attrs['first_id'])
                    self._VerifyId(
                        id, tid,
                        'Explicitly specified numeric first_id %d conflicts with one of the\n'
                        'ID ranges already used.' % id)
                else:
                    # Automatically generate the ID based on the first clique from the
                    # first child of the first child node of our parent (i.e. when we
                    # first get to this location in the code).

                    # According to
                    # http://msdn.microsoft.com/en-us/library/t2zechd4(VS.71).aspx
                    # the safe usable range for resource IDs in Windows is from decimal
                    # 101 to 0x7FFF.

                    id = FP.UnsignedFingerPrint(tid)
                    id = id % (0x7FFF - 101)
                    id += 101

                    self._VerifyId(
                        id, tid,
                        'Automatic (fingerprint-based) numeric ID for %s (%d) overlapped\n'
                        'with a previously allocated range.' % (tid, id))

                if item_parent:
                    item_parent._last_id_ = id
            else:
                assert hasattr(item_parent, '_last_id_')
                id = item_parent._last_id_ = item_parent._last_id_ + 1
                self._VerifyId(
                    id, tid,
                    'Wanted to make numeric value for ID %s (%d) follow the numeric value of\n'
                    'the previous ID in the .grd file, but it was already used.'
                    % (tid, id))

            if tid not in self.ids_.values():
                self.ids_[id] = tid
                self.tids_[tid] = id
                if (item.GetRoot().ShouldOutputAllResourceDefines()
                        or item.SatisfiesOutputCondition()):
                    lines.append('#define %s %d\n' % (tid, id))
        return ''.join(lines)