195640e3a20adea634b4df4ccf8c93f411184c438joi@chromium.org#!/usr/bin/env python 295640e3a20adea634b4df4ccf8c93f411184c438joi@chromium.org# Copyright (c) 2012 The Chromium Authors. All rights reserved. 301b3bc768461bd303bff39f8cd1663682254e407joi@chromium.org# Use of this source code is governed by a BSD-style license that can be 401b3bc768461bd303bff39f8cd1663682254e407joi@chromium.org# found in the LICENSE file. 501b3bc768461bd303bff39f8cd1663682254e407joi@chromium.org 601b3bc768461bd303bff39f8cd1663682254e407joi@chromium.org'''Item formatters for RC headers. 701b3bc768461bd303bff39f8cd1663682254e407joi@chromium.org''' 801b3bc768461bd303bff39f8cd1663682254e407joi@chromium.org 901b3bc768461bd303bff39f8cd1663682254e407joi@chromium.orgfrom grit import exception 1001b3bc768461bd303bff39f8cd1663682254e407joi@chromium.orgfrom grit import util 1101b3bc768461bd303bff39f8cd1663682254e407joi@chromium.orgfrom grit.extern import FP 1201b3bc768461bd303bff39f8cd1663682254e407joi@chromium.org 1301b3bc768461bd303bff39f8cd1663682254e407joi@chromium.org 14ccda47032903a6550dac2921f88c51b4da55aa36benrg@chromium.orgdef Format(root, lang='en', output_dir='.'): 15ccda47032903a6550dac2921f88c51b4da55aa36benrg@chromium.org yield '''\ 1601b3bc768461bd303bff39f8cd1663682254e407joi@chromium.org// This file is automatically generated by GRIT. Do not edit. 1701b3bc768461bd303bff39f8cd1663682254e407joi@chromium.org 1801b3bc768461bd303bff39f8cd1663682254e407joi@chromium.org#pragma once 19d4edc6c61f2135b39318e34f9b342b673133e6ccbenrg@chromium.org''' 20ccda47032903a6550dac2921f88c51b4da55aa36benrg@chromium.org # Check for emit nodes under the rc_header. If any emit node 21ccda47032903a6550dac2921f88c51b4da55aa36benrg@chromium.org # is present, we assume it means the GRD file wants to override 22ccda47032903a6550dac2921f88c51b4da55aa36benrg@chromium.org # the default header, with no includes. 23ccda47032903a6550dac2921f88c51b4da55aa36benrg@chromium.org default_includes = ['#include <atlres.h>', ''] 24ccda47032903a6550dac2921f88c51b4da55aa36benrg@chromium.org emit_lines = [] 25ccda47032903a6550dac2921f88c51b4da55aa36benrg@chromium.org for output_node in root.GetOutputFiles(): 26ccda47032903a6550dac2921f88c51b4da55aa36benrg@chromium.org if output_node.GetType() == 'rc_header': 27ccda47032903a6550dac2921f88c51b4da55aa36benrg@chromium.org for child in output_node.children: 28ccda47032903a6550dac2921f88c51b4da55aa36benrg@chromium.org if child.name == 'emit' and child.attrs['emit_type'] == 'prepend': 29ccda47032903a6550dac2921f88c51b4da55aa36benrg@chromium.org emit_lines.append(child.GetCdata()) 30ccda47032903a6550dac2921f88c51b4da55aa36benrg@chromium.org for line in emit_lines or default_includes: 31ccda47032903a6550dac2921f88c51b4da55aa36benrg@chromium.org yield line + '\n' 32ccda47032903a6550dac2921f88c51b4da55aa36benrg@chromium.org 33db2e077842c311c22eb33a13cc9eb9fadb7def5ajoi@chromium.org for line in FormatDefines(root, root.ShouldOutputAllResourceDefines(), 34db2e077842c311c22eb33a13cc9eb9fadb7def5ajoi@chromium.org root.GetRcHeaderFormat()): 35ccda47032903a6550dac2921f88c51b4da55aa36benrg@chromium.org yield line 36ccda47032903a6550dac2921f88c51b4da55aa36benrg@chromium.org 37ccda47032903a6550dac2921f88c51b4da55aa36benrg@chromium.org 38db2e077842c311c22eb33a13cc9eb9fadb7def5ajoi@chromium.orgdef FormatDefines(root, output_all_resource_defines=True, 39db2e077842c311c22eb33a13cc9eb9fadb7def5ajoi@chromium.org rc_header_format=None): 40ccda47032903a6550dac2921f88c51b4da55aa36benrg@chromium.org '''Yields #define SYMBOL 1234 lines. 41ccda47032903a6550dac2921f88c51b4da55aa36benrg@chromium.org 42ccda47032903a6550dac2921f88c51b4da55aa36benrg@chromium.org Args: 43ccda47032903a6550dac2921f88c51b4da55aa36benrg@chromium.org root: A GritNode. 44ccda47032903a6550dac2921f88c51b4da55aa36benrg@chromium.org output_all_resource_defines: If False, output only the symbols used in the 45ccda47032903a6550dac2921f88c51b4da55aa36benrg@chromium.org current output configuration. 46ccda47032903a6550dac2921f88c51b4da55aa36benrg@chromium.org ''' 47ccda47032903a6550dac2921f88c51b4da55aa36benrg@chromium.org from grit.node import message 48ccda47032903a6550dac2921f88c51b4da55aa36benrg@chromium.org tids = GetIds(root) 49ccda47032903a6550dac2921f88c51b4da55aa36benrg@chromium.org 50ccda47032903a6550dac2921f88c51b4da55aa36benrg@chromium.org if output_all_resource_defines: 51ccda47032903a6550dac2921f88c51b4da55aa36benrg@chromium.org items = root.Preorder() 52ccda47032903a6550dac2921f88c51b4da55aa36benrg@chromium.org else: 53ccda47032903a6550dac2921f88c51b4da55aa36benrg@chromium.org items = root.ActiveDescendants() 54ccda47032903a6550dac2921f88c51b4da55aa36benrg@chromium.org 55db2e077842c311c22eb33a13cc9eb9fadb7def5ajoi@chromium.org if not rc_header_format: 5677646803647fbfac846a54cc4e42cc265a320d6fjoi@chromium.org rc_header_format = "#define {textual_id} {numeric_id}" 5777646803647fbfac846a54cc4e42cc265a320d6fjoi@chromium.org rc_header_format += "\n" 58ccda47032903a6550dac2921f88c51b4da55aa36benrg@chromium.org seen = set() 59ccda47032903a6550dac2921f88c51b4da55aa36benrg@chromium.org for item in items: 60ccda47032903a6550dac2921f88c51b4da55aa36benrg@chromium.org if not isinstance(item, message.MessageNode): 61ccda47032903a6550dac2921f88c51b4da55aa36benrg@chromium.org with item: 62ccda47032903a6550dac2921f88c51b4da55aa36benrg@chromium.org for tid in item.GetTextualIds(): 63ccda47032903a6550dac2921f88c51b4da55aa36benrg@chromium.org if tid in tids and tid not in seen: 64ccda47032903a6550dac2921f88c51b4da55aa36benrg@chromium.org seen.add(tid) 65db2e077842c311c22eb33a13cc9eb9fadb7def5ajoi@chromium.org yield rc_header_format.format(textual_id=tid,numeric_id=tids[tid]) 66db2e077842c311c22eb33a13cc9eb9fadb7def5ajoi@chromium.org 67ccda47032903a6550dac2921f88c51b4da55aa36benrg@chromium.org # Temporarily mimic old behavior: MessageNodes were only output if active, 68ccda47032903a6550dac2921f88c51b4da55aa36benrg@chromium.org # even with output_all_resource_defines set. TODO(benrg): Remove this after 69ccda47032903a6550dac2921f88c51b4da55aa36benrg@chromium.org # fixing problems in the Chrome tree. 70ccda47032903a6550dac2921f88c51b4da55aa36benrg@chromium.org for item in root.ActiveDescendants(): 71ccda47032903a6550dac2921f88c51b4da55aa36benrg@chromium.org if isinstance(item, message.MessageNode): 72ccda47032903a6550dac2921f88c51b4da55aa36benrg@chromium.org with item: 73ccda47032903a6550dac2921f88c51b4da55aa36benrg@chromium.org for tid in item.GetTextualIds(): 74ccda47032903a6550dac2921f88c51b4da55aa36benrg@chromium.org if tid in tids and tid not in seen: 75ccda47032903a6550dac2921f88c51b4da55aa36benrg@chromium.org seen.add(tid) 76db2e077842c311c22eb33a13cc9eb9fadb7def5ajoi@chromium.org yield rc_header_format.format(textual_id=tid,numeric_id=tids[tid]) 77ccda47032903a6550dac2921f88c51b4da55aa36benrg@chromium.org 78ccda47032903a6550dac2921f88c51b4da55aa36benrg@chromium.org 79ccda47032903a6550dac2921f88c51b4da55aa36benrg@chromium.org_cached_ids = {} 80ccda47032903a6550dac2921f88c51b4da55aa36benrg@chromium.org 81ccda47032903a6550dac2921f88c51b4da55aa36benrg@chromium.org 82ccda47032903a6550dac2921f88c51b4da55aa36benrg@chromium.orgdef GetIds(root): 83ccda47032903a6550dac2921f88c51b4da55aa36benrg@chromium.org '''Return a dictionary mapping textual ids to numeric ids for the given tree. 84ccda47032903a6550dac2921f88c51b4da55aa36benrg@chromium.org 85ccda47032903a6550dac2921f88c51b4da55aa36benrg@chromium.org Args: 86ccda47032903a6550dac2921f88c51b4da55aa36benrg@chromium.org root: A GritNode. 87ccda47032903a6550dac2921f88c51b4da55aa36benrg@chromium.org ''' 88ccda47032903a6550dac2921f88c51b4da55aa36benrg@chromium.org # TODO(benrg): Since other formatters use this, it might make sense to move it 89ccda47032903a6550dac2921f88c51b4da55aa36benrg@chromium.org # and _ComputeIds to GritNode and store the cached ids as an attribute. On the 90ccda47032903a6550dac2921f88c51b4da55aa36benrg@chromium.org # other hand, GritNode has too much random stuff already. 91ccda47032903a6550dac2921f88c51b4da55aa36benrg@chromium.org if root not in _cached_ids: 92ccda47032903a6550dac2921f88c51b4da55aa36benrg@chromium.org _cached_ids[root] = _ComputeIds(root) 93ccda47032903a6550dac2921f88c51b4da55aa36benrg@chromium.org return _cached_ids[root] 94ccda47032903a6550dac2921f88c51b4da55aa36benrg@chromium.org 95ccda47032903a6550dac2921f88c51b4da55aa36benrg@chromium.org 96ccda47032903a6550dac2921f88c51b4da55aa36benrg@chromium.orgdef _ComputeIds(root): 97ccda47032903a6550dac2921f88c51b4da55aa36benrg@chromium.org from grit.node import empty, include, message, misc, structure 98ccda47032903a6550dac2921f88c51b4da55aa36benrg@chromium.org 99ccda47032903a6550dac2921f88c51b4da55aa36benrg@chromium.org ids = {} # Maps numeric id to textual id 100ccda47032903a6550dac2921f88c51b4da55aa36benrg@chromium.org tids = {} # Maps textual id to numeric id 101ccda47032903a6550dac2921f88c51b4da55aa36benrg@chromium.org id_reasons = {} # Maps numeric id to text id and a human-readable explanation 102ccda47032903a6550dac2921f88c51b4da55aa36benrg@chromium.org group = None 103ccda47032903a6550dac2921f88c51b4da55aa36benrg@chromium.org last_id = None 104ccda47032903a6550dac2921f88c51b4da55aa36benrg@chromium.org 105ccda47032903a6550dac2921f88c51b4da55aa36benrg@chromium.org for item in root: 106ccda47032903a6550dac2921f88c51b4da55aa36benrg@chromium.org if isinstance(item, empty.GroupingNode): 107ccda47032903a6550dac2921f88c51b4da55aa36benrg@chromium.org # Note: this won't work if any GroupingNode can be contained inside 108ccda47032903a6550dac2921f88c51b4da55aa36benrg@chromium.org # another. 109ccda47032903a6550dac2921f88c51b4da55aa36benrg@chromium.org group = item 110ccda47032903a6550dac2921f88c51b4da55aa36benrg@chromium.org last_id = None 111ccda47032903a6550dac2921f88c51b4da55aa36benrg@chromium.org continue 112ccda47032903a6550dac2921f88c51b4da55aa36benrg@chromium.org 113ccda47032903a6550dac2921f88c51b4da55aa36benrg@chromium.org assert not item.GetTextualIds() or isinstance(item, 114ccda47032903a6550dac2921f88c51b4da55aa36benrg@chromium.org (include.IncludeNode, message.MessageNode, 115ccda47032903a6550dac2921f88c51b4da55aa36benrg@chromium.org misc.IdentifierNode, structure.StructureNode)) 11601b3bc768461bd303bff39f8cd1663682254e407joi@chromium.org 11701b3bc768461bd303bff39f8cd1663682254e407joi@chromium.org # Resources that use the RES protocol don't need 11801b3bc768461bd303bff39f8cd1663682254e407joi@chromium.org # any numerical ids generated, so we skip them altogether. 11901b3bc768461bd303bff39f8cd1663682254e407joi@chromium.org # This is accomplished by setting the flag 'generateid' to false 12001b3bc768461bd303bff39f8cd1663682254e407joi@chromium.org # in the GRD file. 121ccda47032903a6550dac2921f88c51b4da55aa36benrg@chromium.org if item.attrs.get('generateid', 'true') == 'false': 122ccda47032903a6550dac2921f88c51b4da55aa36benrg@chromium.org continue 123ccda47032903a6550dac2921f88c51b4da55aa36benrg@chromium.org 124ccda47032903a6550dac2921f88c51b4da55aa36benrg@chromium.org for tid in item.GetTextualIds(): 12501b3bc768461bd303bff39f8cd1663682254e407joi@chromium.org if util.SYSTEM_IDENTIFIERS.match(tid): 12601b3bc768461bd303bff39f8cd1663682254e407joi@chromium.org # Don't emit a new ID for predefined IDs 12701b3bc768461bd303bff39f8cd1663682254e407joi@chromium.org continue 12801b3bc768461bd303bff39f8cd1663682254e407joi@chromium.org 129ccda47032903a6550dac2921f88c51b4da55aa36benrg@chromium.org if tid in tids: 130ccda47032903a6550dac2921f88c51b4da55aa36benrg@chromium.org continue 131ccda47032903a6550dac2921f88c51b4da55aa36benrg@chromium.org 13201b3bc768461bd303bff39f8cd1663682254e407joi@chromium.org # Some identifier nodes can provide their own id, 13301b3bc768461bd303bff39f8cd1663682254e407joi@chromium.org # and we use that id in the generated header in that case. 13401b3bc768461bd303bff39f8cd1663682254e407joi@chromium.org if hasattr(item, 'GetId') and item.GetId(): 13501b3bc768461bd303bff39f8cd1663682254e407joi@chromium.org id = long(item.GetId()) 136ccda47032903a6550dac2921f88c51b4da55aa36benrg@chromium.org reason = 'returned by GetId() method' 13701b3bc768461bd303bff39f8cd1663682254e407joi@chromium.org 138ccda47032903a6550dac2921f88c51b4da55aa36benrg@chromium.org elif ('offset' in item.attrs and group and 139ccda47032903a6550dac2921f88c51b4da55aa36benrg@chromium.org group.attrs.get('first_id', '') != ''): 14001b3bc768461bd303bff39f8cd1663682254e407joi@chromium.org offset_text = item.attrs['offset'] 141ccda47032903a6550dac2921f88c51b4da55aa36benrg@chromium.org parent_text = group.attrs['first_id'] 14201b3bc768461bd303bff39f8cd1663682254e407joi@chromium.org 14301b3bc768461bd303bff39f8cd1663682254e407joi@chromium.org try: 14401b3bc768461bd303bff39f8cd1663682254e407joi@chromium.org offset_id = long(offset_text) 14501b3bc768461bd303bff39f8cd1663682254e407joi@chromium.org except ValueError: 146ccda47032903a6550dac2921f88c51b4da55aa36benrg@chromium.org offset_id = tids[offset_text] 14701b3bc768461bd303bff39f8cd1663682254e407joi@chromium.org 14801b3bc768461bd303bff39f8cd1663682254e407joi@chromium.org try: 14901b3bc768461bd303bff39f8cd1663682254e407joi@chromium.org parent_id = long(parent_text) 15001b3bc768461bd303bff39f8cd1663682254e407joi@chromium.org except ValueError: 151ccda47032903a6550dac2921f88c51b4da55aa36benrg@chromium.org parent_id = tids[parent_text] 15201b3bc768461bd303bff39f8cd1663682254e407joi@chromium.org 15301b3bc768461bd303bff39f8cd1663682254e407joi@chromium.org id = parent_id + offset_id 154ccda47032903a6550dac2921f88c51b4da55aa36benrg@chromium.org reason = 'first_id %d + offset %d' % (parent_id, offset_id) 15501b3bc768461bd303bff39f8cd1663682254e407joi@chromium.org 15601b3bc768461bd303bff39f8cd1663682254e407joi@chromium.org # We try to allocate IDs sequentially for blocks of items that might 15701b3bc768461bd303bff39f8cd1663682254e407joi@chromium.org # be related, for instance strings in a stringtable (as their IDs might be 15801b3bc768461bd303bff39f8cd1663682254e407joi@chromium.org # used e.g. as IDs for some radio buttons, in which case the IDs must 15901b3bc768461bd303bff39f8cd1663682254e407joi@chromium.org # be sequential). 16001b3bc768461bd303bff39f8cd1663682254e407joi@chromium.org # 16101b3bc768461bd303bff39f8cd1663682254e407joi@chromium.org # We do this by having the first item in a section store its computed ID 16201b3bc768461bd303bff39f8cd1663682254e407joi@chromium.org # (computed from a fingerprint) in its parent object. Subsequent children 16301b3bc768461bd303bff39f8cd1663682254e407joi@chromium.org # of the same parent will then try to get IDs that sequentially follow 16401b3bc768461bd303bff39f8cd1663682254e407joi@chromium.org # the currently stored ID (on the parent) and increment it. 165ccda47032903a6550dac2921f88c51b4da55aa36benrg@chromium.org elif last_id is None: 16601b3bc768461bd303bff39f8cd1663682254e407joi@chromium.org # First check if the starting ID is explicitly specified by the parent. 167ccda47032903a6550dac2921f88c51b4da55aa36benrg@chromium.org if group and group.attrs.get('first_id', '') != '': 168ccda47032903a6550dac2921f88c51b4da55aa36benrg@chromium.org id = long(group.attrs['first_id']) 169ccda47032903a6550dac2921f88c51b4da55aa36benrg@chromium.org reason = "from parent's first_id attribute" 17001b3bc768461bd303bff39f8cd1663682254e407joi@chromium.org else: 17101b3bc768461bd303bff39f8cd1663682254e407joi@chromium.org # Automatically generate the ID based on the first clique from the 17201b3bc768461bd303bff39f8cd1663682254e407joi@chromium.org # first child of the first child node of our parent (i.e. when we 17301b3bc768461bd303bff39f8cd1663682254e407joi@chromium.org # first get to this location in the code). 17401b3bc768461bd303bff39f8cd1663682254e407joi@chromium.org 17501b3bc768461bd303bff39f8cd1663682254e407joi@chromium.org # According to 17601b3bc768461bd303bff39f8cd1663682254e407joi@chromium.org # http://msdn.microsoft.com/en-us/library/t2zechd4(VS.71).aspx 17701b3bc768461bd303bff39f8cd1663682254e407joi@chromium.org # the safe usable range for resource IDs in Windows is from decimal 17801b3bc768461bd303bff39f8cd1663682254e407joi@chromium.org # 101 to 0x7FFF. 17901b3bc768461bd303bff39f8cd1663682254e407joi@chromium.org 18001b3bc768461bd303bff39f8cd1663682254e407joi@chromium.org id = FP.UnsignedFingerPrint(tid) 181ccda47032903a6550dac2921f88c51b4da55aa36benrg@chromium.org id = id % (0x7FFF - 101) + 101 182ccda47032903a6550dac2921f88c51b4da55aa36benrg@chromium.org reason = 'chosen by random fingerprint -- use first_id to override' 18301b3bc768461bd303bff39f8cd1663682254e407joi@chromium.org 184ccda47032903a6550dac2921f88c51b4da55aa36benrg@chromium.org last_id = id 18501b3bc768461bd303bff39f8cd1663682254e407joi@chromium.org else: 186ccda47032903a6550dac2921f88c51b4da55aa36benrg@chromium.org id = last_id = last_id + 1 187ccda47032903a6550dac2921f88c51b4da55aa36benrg@chromium.org reason = 'sequentially assigned' 188ccda47032903a6550dac2921f88c51b4da55aa36benrg@chromium.org 189ccda47032903a6550dac2921f88c51b4da55aa36benrg@chromium.org reason = "%s (%s)" % (tid, reason) 190528c23465b5b57bd81eab467504be053be6f1be0joi@chromium.org # Don't fail when 'offset' is specified, as the base and the 0th 191528c23465b5b57bd81eab467504be053be6f1be0joi@chromium.org # offset will have the same ID. 192528c23465b5b57bd81eab467504be053be6f1be0joi@chromium.org if id in id_reasons and not 'offset' in item.attrs: 193ccda47032903a6550dac2921f88c51b4da55aa36benrg@chromium.org raise exception.IdRangeOverlap('ID %d was assigned to both %s and %s.' 194ccda47032903a6550dac2921f88c51b4da55aa36benrg@chromium.org % (id, id_reasons[id], reason)) 195ccda47032903a6550dac2921f88c51b4da55aa36benrg@chromium.org 196ccda47032903a6550dac2921f88c51b4da55aa36benrg@chromium.org if id < 101: 197ccda47032903a6550dac2921f88c51b4da55aa36benrg@chromium.org print ('WARNING: Numeric resource IDs should be greater than 100 to\n' 198ccda47032903a6550dac2921f88c51b4da55aa36benrg@chromium.org 'avoid conflicts with system-defined resource IDs.') 199ccda47032903a6550dac2921f88c51b4da55aa36benrg@chromium.org 200ccda47032903a6550dac2921f88c51b4da55aa36benrg@chromium.org ids[id] = tid 201ccda47032903a6550dac2921f88c51b4da55aa36benrg@chromium.org tids[tid] = id 202ccda47032903a6550dac2921f88c51b4da55aa36benrg@chromium.org id_reasons[id] = reason 20301b3bc768461bd303bff39f8cd1663682254e407joi@chromium.org 204ccda47032903a6550dac2921f88c51b4da55aa36benrg@chromium.org return tids 205