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'''Support for gathering resources from RC files. 701b3bc768461bd303bff39f8cd1663682254e407joi@chromium.org''' 801b3bc768461bd303bff39f8cd1663682254e407joi@chromium.org 901b3bc768461bd303bff39f8cd1663682254e407joi@chromium.org 1001b3bc768461bd303bff39f8cd1663682254e407joi@chromium.orgimport re 1101b3bc768461bd303bff39f8cd1663682254e407joi@chromium.org 1201b3bc768461bd303bff39f8cd1663682254e407joi@chromium.orgfrom grit import exception 1301fadb72b6e94e6511eaffd1874a8cc095f098a7joi@chromium.orgfrom grit import lazy_re 1401b3bc768461bd303bff39f8cd1663682254e407joi@chromium.orgfrom grit import tclib 1501b3bc768461bd303bff39f8cd1663682254e407joi@chromium.org 1601b3bc768461bd303bff39f8cd1663682254e407joi@chromium.orgfrom grit.gather import regexp 1701b3bc768461bd303bff39f8cd1663682254e407joi@chromium.org 1801b3bc768461bd303bff39f8cd1663682254e407joi@chromium.org 1901b3bc768461bd303bff39f8cd1663682254e407joi@chromium.org# Find portions that need unescaping in resource strings. We need to be 2001b3bc768461bd303bff39f8cd1663682254e407joi@chromium.org# careful that a \\n is matched _first_ as a \\ rather than matching as 2101b3bc768461bd303bff39f8cd1663682254e407joi@chromium.org# a \ followed by a \n. 2201b3bc768461bd303bff39f8cd1663682254e407joi@chromium.org# TODO(joi) Handle ampersands if we decide to change them into <ph> 2301b3bc768461bd303bff39f8cd1663682254e407joi@chromium.org# TODO(joi) May need to handle other control characters than \n 2401fadb72b6e94e6511eaffd1874a8cc095f098a7joi@chromium.org_NEED_UNESCAPE = lazy_re.compile(r'""|\\\\|\\n|\\t') 2501b3bc768461bd303bff39f8cd1663682254e407joi@chromium.org 2601b3bc768461bd303bff39f8cd1663682254e407joi@chromium.org# Find portions that need escaping to encode string as a resource string. 2701fadb72b6e94e6511eaffd1874a8cc095f098a7joi@chromium.org_NEED_ESCAPE = lazy_re.compile(r'"|\n|\t|\\|\ \;') 2801b3bc768461bd303bff39f8cd1663682254e407joi@chromium.org 2901b3bc768461bd303bff39f8cd1663682254e407joi@chromium.org# How to escape certain characters 3001b3bc768461bd303bff39f8cd1663682254e407joi@chromium.org_ESCAPE_CHARS = { 3101b3bc768461bd303bff39f8cd1663682254e407joi@chromium.org '"' : '""', 3201b3bc768461bd303bff39f8cd1663682254e407joi@chromium.org '\n' : '\\n', 3301b3bc768461bd303bff39f8cd1663682254e407joi@chromium.org '\t' : '\\t', 3401b3bc768461bd303bff39f8cd1663682254e407joi@chromium.org '\\' : '\\\\', 3501b3bc768461bd303bff39f8cd1663682254e407joi@chromium.org ' ' : ' ' 3601b3bc768461bd303bff39f8cd1663682254e407joi@chromium.org} 3701b3bc768461bd303bff39f8cd1663682254e407joi@chromium.org 3801b3bc768461bd303bff39f8cd1663682254e407joi@chromium.org# How to unescape certain strings 3901b3bc768461bd303bff39f8cd1663682254e407joi@chromium.org_UNESCAPE_CHARS = dict([[value, key] for key, value in _ESCAPE_CHARS.items()]) 4001b3bc768461bd303bff39f8cd1663682254e407joi@chromium.org 4101b3bc768461bd303bff39f8cd1663682254e407joi@chromium.org 4201b3bc768461bd303bff39f8cd1663682254e407joi@chromium.org 4301b3bc768461bd303bff39f8cd1663682254e407joi@chromium.orgclass Section(regexp.RegexpGatherer): 4401b3bc768461bd303bff39f8cd1663682254e407joi@chromium.org '''A section from a resource file.''' 4501b3bc768461bd303bff39f8cd1663682254e407joi@chromium.org 46b9161407f737461b5db16a29782f8a31d19e602dbenrg@chromium.org @staticmethod 4701b3bc768461bd303bff39f8cd1663682254e407joi@chromium.org def Escape(text): 4801b3bc768461bd303bff39f8cd1663682254e407joi@chromium.org '''Returns a version of 'text' with characters escaped that need to be 4901b3bc768461bd303bff39f8cd1663682254e407joi@chromium.org for inclusion in a resource section.''' 5001b3bc768461bd303bff39f8cd1663682254e407joi@chromium.org def Replace(match): 5101b3bc768461bd303bff39f8cd1663682254e407joi@chromium.org return _ESCAPE_CHARS[match.group()] 5201b3bc768461bd303bff39f8cd1663682254e407joi@chromium.org return _NEED_ESCAPE.sub(Replace, text) 5301b3bc768461bd303bff39f8cd1663682254e407joi@chromium.org 54b9161407f737461b5db16a29782f8a31d19e602dbenrg@chromium.org @staticmethod 5501b3bc768461bd303bff39f8cd1663682254e407joi@chromium.org def UnEscape(text): 5601b3bc768461bd303bff39f8cd1663682254e407joi@chromium.org '''Returns a version of 'text' with escaped characters unescaped.''' 5701b3bc768461bd303bff39f8cd1663682254e407joi@chromium.org def Replace(match): 5801b3bc768461bd303bff39f8cd1663682254e407joi@chromium.org return _UNESCAPE_CHARS[match.group()] 5901b3bc768461bd303bff39f8cd1663682254e407joi@chromium.org return _NEED_UNESCAPE.sub(Replace, text) 6001b3bc768461bd303bff39f8cd1663682254e407joi@chromium.org 6101b3bc768461bd303bff39f8cd1663682254e407joi@chromium.org def _RegExpParse(self, rexp, text_to_parse): 6201b3bc768461bd303bff39f8cd1663682254e407joi@chromium.org '''Overrides _RegExpParse to add shortcut group handling. Otherwise 6301b3bc768461bd303bff39f8cd1663682254e407joi@chromium.org the same. 6401b3bc768461bd303bff39f8cd1663682254e407joi@chromium.org ''' 65b9161407f737461b5db16a29782f8a31d19e602dbenrg@chromium.org super(Section, self)._RegExpParse(rexp, text_to_parse) 6601b3bc768461bd303bff39f8cd1663682254e407joi@chromium.org 67ec8016c73b3b945b6284746230913d88653f35e7benrg@chromium.org if not self.is_skeleton and len(self.GetTextualIds()) > 0: 6801b3bc768461bd303bff39f8cd1663682254e407joi@chromium.org group_name = self.GetTextualIds()[0] 6901b3bc768461bd303bff39f8cd1663682254e407joi@chromium.org for c in self.GetCliques(): 7001b3bc768461bd303bff39f8cd1663682254e407joi@chromium.org c.AddToShortcutGroup(group_name) 7101b3bc768461bd303bff39f8cd1663682254e407joi@chromium.org 72ec8016c73b3b945b6284746230913d88653f35e7benrg@chromium.org def ReadSection(self): 73b9161407f737461b5db16a29782f8a31d19e602dbenrg@chromium.org rc_text = self._LoadInputFile() 7401b3bc768461bd303bff39f8cd1663682254e407joi@chromium.org 7501b3bc768461bd303bff39f8cd1663682254e407joi@chromium.org out = '' 7601b3bc768461bd303bff39f8cd1663682254e407joi@chromium.org begin_count = 0 77ec8016c73b3b945b6284746230913d88653f35e7benrg@chromium.org assert self.extkey 78ec8016c73b3b945b6284746230913d88653f35e7benrg@chromium.org first_line_re = re.compile(r'\s*' + self.extkey + r'\b') 79ec8016c73b3b945b6284746230913d88653f35e7benrg@chromium.org for line in rc_text.splitlines(True): 80ec8016c73b3b945b6284746230913d88653f35e7benrg@chromium.org if out or first_line_re.match(line): 8101b3bc768461bd303bff39f8cd1663682254e407joi@chromium.org out += line 8201b3bc768461bd303bff39f8cd1663682254e407joi@chromium.org 8301b3bc768461bd303bff39f8cd1663682254e407joi@chromium.org # we stop once we reach the END for the outermost block. 8401b3bc768461bd303bff39f8cd1663682254e407joi@chromium.org begin_count_was = begin_count 8501b3bc768461bd303bff39f8cd1663682254e407joi@chromium.org if len(out) > 0 and line.strip() == 'BEGIN': 8601b3bc768461bd303bff39f8cd1663682254e407joi@chromium.org begin_count += 1 8701b3bc768461bd303bff39f8cd1663682254e407joi@chromium.org elif len(out) > 0 and line.strip() == 'END': 8801b3bc768461bd303bff39f8cd1663682254e407joi@chromium.org begin_count -= 1 8901b3bc768461bd303bff39f8cd1663682254e407joi@chromium.org if begin_count_was == 1 and begin_count == 0: 9001b3bc768461bd303bff39f8cd1663682254e407joi@chromium.org break 9101b3bc768461bd303bff39f8cd1663682254e407joi@chromium.org 9201b3bc768461bd303bff39f8cd1663682254e407joi@chromium.org if len(out) == 0: 93ec8016c73b3b945b6284746230913d88653f35e7benrg@chromium.org raise exception.SectionNotFound('%s in file %s' % (self.extkey, self.rc_file)) 9401b3bc768461bd303bff39f8cd1663682254e407joi@chromium.org 95ec8016c73b3b945b6284746230913d88653f35e7benrg@chromium.org self.text_ = out.strip() 9601b3bc768461bd303bff39f8cd1663682254e407joi@chromium.org 9701b3bc768461bd303bff39f8cd1663682254e407joi@chromium.org 9801b3bc768461bd303bff39f8cd1663682254e407joi@chromium.orgclass Dialog(Section): 9901b3bc768461bd303bff39f8cd1663682254e407joi@chromium.org '''A resource section that contains a dialog resource.''' 10001b3bc768461bd303bff39f8cd1663682254e407joi@chromium.org 10101b3bc768461bd303bff39f8cd1663682254e407joi@chromium.org # A typical dialog resource section looks like this: 10201b3bc768461bd303bff39f8cd1663682254e407joi@chromium.org # 10301b3bc768461bd303bff39f8cd1663682254e407joi@chromium.org # IDD_ABOUTBOX DIALOGEX 22, 17, 230, 75 10401b3bc768461bd303bff39f8cd1663682254e407joi@chromium.org # STYLE DS_SETFONT | DS_MODALFRAME | WS_CAPTION | WS_SYSMENU 10501b3bc768461bd303bff39f8cd1663682254e407joi@chromium.org # CAPTION "About" 10601b3bc768461bd303bff39f8cd1663682254e407joi@chromium.org # FONT 8, "System", 0, 0, 0x0 10701b3bc768461bd303bff39f8cd1663682254e407joi@chromium.org # BEGIN 10801b3bc768461bd303bff39f8cd1663682254e407joi@chromium.org # ICON IDI_KLONK,IDC_MYICON,14,9,20,20 10901b3bc768461bd303bff39f8cd1663682254e407joi@chromium.org # LTEXT "klonk Version ""yibbee"" 1.0",IDC_STATIC,49,10,119,8, 11001b3bc768461bd303bff39f8cd1663682254e407joi@chromium.org # SS_NOPREFIX 11101b3bc768461bd303bff39f8cd1663682254e407joi@chromium.org # LTEXT "Copyright (C) 2005",IDC_STATIC,49,20,119,8 11201b3bc768461bd303bff39f8cd1663682254e407joi@chromium.org # DEFPUSHBUTTON "OK",IDOK,195,6,30,11,WS_GROUP 11301b3bc768461bd303bff39f8cd1663682254e407joi@chromium.org # CONTROL "Jack ""Black"" Daniels",IDC_RADIO1,"Button", 11401b3bc768461bd303bff39f8cd1663682254e407joi@chromium.org # BS_AUTORADIOBUTTON,46,51,84,10 11501b3bc768461bd303bff39f8cd1663682254e407joi@chromium.org # END 11601b3bc768461bd303bff39f8cd1663682254e407joi@chromium.org 11701b3bc768461bd303bff39f8cd1663682254e407joi@chromium.org # We are using a sorted set of keys, and we assume that the 11801b3bc768461bd303bff39f8cd1663682254e407joi@chromium.org # group name used for descriptions (type) will come after the "text" 11901b3bc768461bd303bff39f8cd1663682254e407joi@chromium.org # group in alphabetical order. We also assume that there cannot be 12001b3bc768461bd303bff39f8cd1663682254e407joi@chromium.org # more than one description per regular expression match. 12101b3bc768461bd303bff39f8cd1663682254e407joi@chromium.org # If that's not the case some descriptions will be clobbered. 12201fadb72b6e94e6511eaffd1874a8cc095f098a7joi@chromium.org dialog_re_ = lazy_re.compile(''' 12301b3bc768461bd303bff39f8cd1663682254e407joi@chromium.org # The dialog's ID in the first line 12401b3bc768461bd303bff39f8cd1663682254e407joi@chromium.org (?P<id1>[A-Z0-9_]+)\s+DIALOG(EX)? 12501b3bc768461bd303bff39f8cd1663682254e407joi@chromium.org | 12601b3bc768461bd303bff39f8cd1663682254e407joi@chromium.org # The caption of the dialog 12701b3bc768461bd303bff39f8cd1663682254e407joi@chromium.org (?P<type1>CAPTION)\s+"(?P<text1>.*?([^"]|""))"\s 12801b3bc768461bd303bff39f8cd1663682254e407joi@chromium.org | 12901b3bc768461bd303bff39f8cd1663682254e407joi@chromium.org # Lines for controls that have text and an ID 13001b3bc768461bd303bff39f8cd1663682254e407joi@chromium.org \s+(?P<type2>[A-Z]+)\s+"(?P<text2>.*?([^"]|"")?)"\s*,\s*(?P<id2>[A-Z0-9_]+)\s*, 13101b3bc768461bd303bff39f8cd1663682254e407joi@chromium.org | 13201b3bc768461bd303bff39f8cd1663682254e407joi@chromium.org # Lines for controls that have text only 13301b3bc768461bd303bff39f8cd1663682254e407joi@chromium.org \s+(?P<type3>[A-Z]+)\s+"(?P<text3>.*?([^"]|"")?)"\s*, 13401b3bc768461bd303bff39f8cd1663682254e407joi@chromium.org | 13501b3bc768461bd303bff39f8cd1663682254e407joi@chromium.org # Lines for controls that reference other resources 13601b3bc768461bd303bff39f8cd1663682254e407joi@chromium.org \s+[A-Z]+\s+[A-Z0-9_]+\s*,\s*(?P<id3>[A-Z0-9_]*[A-Z][A-Z0-9_]*) 13701b3bc768461bd303bff39f8cd1663682254e407joi@chromium.org | 13801b3bc768461bd303bff39f8cd1663682254e407joi@chromium.org # This matches "NOT SOME_STYLE" so that it gets consumed and doesn't get 13901b3bc768461bd303bff39f8cd1663682254e407joi@chromium.org # matched by the next option (controls that have only an ID and then just 14001b3bc768461bd303bff39f8cd1663682254e407joi@chromium.org # numbers) 14101b3bc768461bd303bff39f8cd1663682254e407joi@chromium.org \s+NOT\s+[A-Z][A-Z0-9_]+ 14201b3bc768461bd303bff39f8cd1663682254e407joi@chromium.org | 14301b3bc768461bd303bff39f8cd1663682254e407joi@chromium.org # Lines for controls that have only an ID and then just numbers 14401b3bc768461bd303bff39f8cd1663682254e407joi@chromium.org \s+[A-Z]+\s+(?P<id4>[A-Z0-9_]*[A-Z][A-Z0-9_]*)\s*, 14501b3bc768461bd303bff39f8cd1663682254e407joi@chromium.org ''', re.MULTILINE | re.VERBOSE) 14601b3bc768461bd303bff39f8cd1663682254e407joi@chromium.org 14701b3bc768461bd303bff39f8cd1663682254e407joi@chromium.org def Parse(self): 14801b3bc768461bd303bff39f8cd1663682254e407joi@chromium.org '''Knows how to parse dialog resource sections.''' 149ec8016c73b3b945b6284746230913d88653f35e7benrg@chromium.org self.ReadSection() 15001b3bc768461bd303bff39f8cd1663682254e407joi@chromium.org self._RegExpParse(self.dialog_re_, self.text_) 15101b3bc768461bd303bff39f8cd1663682254e407joi@chromium.org 15201b3bc768461bd303bff39f8cd1663682254e407joi@chromium.org 15301b3bc768461bd303bff39f8cd1663682254e407joi@chromium.orgclass Menu(Section): 15401b3bc768461bd303bff39f8cd1663682254e407joi@chromium.org '''A resource section that contains a menu resource.''' 15501b3bc768461bd303bff39f8cd1663682254e407joi@chromium.org 15601b3bc768461bd303bff39f8cd1663682254e407joi@chromium.org # A typical menu resource section looks something like this: 15701b3bc768461bd303bff39f8cd1663682254e407joi@chromium.org # 15801b3bc768461bd303bff39f8cd1663682254e407joi@chromium.org # IDC_KLONK MENU 15901b3bc768461bd303bff39f8cd1663682254e407joi@chromium.org # BEGIN 16001b3bc768461bd303bff39f8cd1663682254e407joi@chromium.org # POPUP "&File" 16101b3bc768461bd303bff39f8cd1663682254e407joi@chromium.org # BEGIN 16201b3bc768461bd303bff39f8cd1663682254e407joi@chromium.org # MENUITEM "E&xit", IDM_EXIT 16301b3bc768461bd303bff39f8cd1663682254e407joi@chromium.org # MENUITEM "This be ""Klonk"" me like", ID_FILE_THISBE 16401b3bc768461bd303bff39f8cd1663682254e407joi@chromium.org # POPUP "gonk" 16501b3bc768461bd303bff39f8cd1663682254e407joi@chromium.org # BEGIN 16601b3bc768461bd303bff39f8cd1663682254e407joi@chromium.org # MENUITEM "Klonk && is ""good""", ID_GONK_KLONKIS 16701b3bc768461bd303bff39f8cd1663682254e407joi@chromium.org # END 16801b3bc768461bd303bff39f8cd1663682254e407joi@chromium.org # END 16901b3bc768461bd303bff39f8cd1663682254e407joi@chromium.org # POPUP "&Help" 17001b3bc768461bd303bff39f8cd1663682254e407joi@chromium.org # BEGIN 17101b3bc768461bd303bff39f8cd1663682254e407joi@chromium.org # MENUITEM "&About ...", IDM_ABOUT 17201b3bc768461bd303bff39f8cd1663682254e407joi@chromium.org # END 17301b3bc768461bd303bff39f8cd1663682254e407joi@chromium.org # END 17401b3bc768461bd303bff39f8cd1663682254e407joi@chromium.org 17501b3bc768461bd303bff39f8cd1663682254e407joi@chromium.org # Description used for the messages generated for menus, to explain to 17601b3bc768461bd303bff39f8cd1663682254e407joi@chromium.org # the translators how to handle them. 17701b3bc768461bd303bff39f8cd1663682254e407joi@chromium.org MENU_MESSAGE_DESCRIPTION = ( 17801b3bc768461bd303bff39f8cd1663682254e407joi@chromium.org 'This message represents a menu. Each of the items appears in sequence ' 17901b3bc768461bd303bff39f8cd1663682254e407joi@chromium.org '(some possibly within sub-menus) in the menu. The XX01XX placeholders ' 18001b3bc768461bd303bff39f8cd1663682254e407joi@chromium.org 'serve to separate items. Each item contains an & (ampersand) character ' 18101b3bc768461bd303bff39f8cd1663682254e407joi@chromium.org 'in front of the keystroke that should be used as a shortcut for that item ' 18201b3bc768461bd303bff39f8cd1663682254e407joi@chromium.org 'in the menu. Please make sure that no two items in the same menu share ' 18301b3bc768461bd303bff39f8cd1663682254e407joi@chromium.org 'the same shortcut.' 18401b3bc768461bd303bff39f8cd1663682254e407joi@chromium.org ) 18501b3bc768461bd303bff39f8cd1663682254e407joi@chromium.org 18601b3bc768461bd303bff39f8cd1663682254e407joi@chromium.org # A dandy regexp to suck all the IDs and translateables out of a menu 18701b3bc768461bd303bff39f8cd1663682254e407joi@chromium.org # resource 18801fadb72b6e94e6511eaffd1874a8cc095f098a7joi@chromium.org menu_re_ = lazy_re.compile(''' 18901b3bc768461bd303bff39f8cd1663682254e407joi@chromium.org # Match the MENU ID on the first line 19001b3bc768461bd303bff39f8cd1663682254e407joi@chromium.org ^(?P<id1>[A-Z0-9_]+)\s+MENU 19101b3bc768461bd303bff39f8cd1663682254e407joi@chromium.org | 19201b3bc768461bd303bff39f8cd1663682254e407joi@chromium.org # Match the translateable caption for a popup menu 19301b3bc768461bd303bff39f8cd1663682254e407joi@chromium.org POPUP\s+"(?P<text1>.*?([^"]|""))"\s 19401b3bc768461bd303bff39f8cd1663682254e407joi@chromium.org | 19501b3bc768461bd303bff39f8cd1663682254e407joi@chromium.org # Match the caption & ID of a MENUITEM 19601b3bc768461bd303bff39f8cd1663682254e407joi@chromium.org MENUITEM\s+"(?P<text2>.*?([^"]|""))"\s*,\s*(?P<id2>[A-Z0-9_]+) 19701b3bc768461bd303bff39f8cd1663682254e407joi@chromium.org ''', re.MULTILINE | re.VERBOSE) 19801b3bc768461bd303bff39f8cd1663682254e407joi@chromium.org 19901b3bc768461bd303bff39f8cd1663682254e407joi@chromium.org def Parse(self): 20001b3bc768461bd303bff39f8cd1663682254e407joi@chromium.org '''Knows how to parse menu resource sections. Because it is important that 20101b3bc768461bd303bff39f8cd1663682254e407joi@chromium.org menu shortcuts are unique within the menu, we return each menu as a single 20201b3bc768461bd303bff39f8cd1663682254e407joi@chromium.org message with placeholders to break up the different menu items, rather than 20301b3bc768461bd303bff39f8cd1663682254e407joi@chromium.org return a single message per menu item. we also add an automatic description 20401b3bc768461bd303bff39f8cd1663682254e407joi@chromium.org with instructions for the translators.''' 205ec8016c73b3b945b6284746230913d88653f35e7benrg@chromium.org self.ReadSection() 20601b3bc768461bd303bff39f8cd1663682254e407joi@chromium.org self.single_message_ = tclib.Message(description=self.MENU_MESSAGE_DESCRIPTION) 20701b3bc768461bd303bff39f8cd1663682254e407joi@chromium.org self._RegExpParse(self.menu_re_, self.text_) 20801b3bc768461bd303bff39f8cd1663682254e407joi@chromium.org 20901b3bc768461bd303bff39f8cd1663682254e407joi@chromium.org 21001b3bc768461bd303bff39f8cd1663682254e407joi@chromium.orgclass Version(Section): 21101b3bc768461bd303bff39f8cd1663682254e407joi@chromium.org '''A resource section that contains a VERSIONINFO resource.''' 21201b3bc768461bd303bff39f8cd1663682254e407joi@chromium.org 21301b3bc768461bd303bff39f8cd1663682254e407joi@chromium.org # A typical version info resource can look like this: 21401b3bc768461bd303bff39f8cd1663682254e407joi@chromium.org # 21501b3bc768461bd303bff39f8cd1663682254e407joi@chromium.org # VS_VERSION_INFO VERSIONINFO 21601b3bc768461bd303bff39f8cd1663682254e407joi@chromium.org # FILEVERSION 1,0,0,1 21701b3bc768461bd303bff39f8cd1663682254e407joi@chromium.org # PRODUCTVERSION 1,0,0,1 21801b3bc768461bd303bff39f8cd1663682254e407joi@chromium.org # FILEFLAGSMASK 0x3fL 21901b3bc768461bd303bff39f8cd1663682254e407joi@chromium.org # #ifdef _DEBUG 22001b3bc768461bd303bff39f8cd1663682254e407joi@chromium.org # FILEFLAGS 0x1L 22101b3bc768461bd303bff39f8cd1663682254e407joi@chromium.org # #else 22201b3bc768461bd303bff39f8cd1663682254e407joi@chromium.org # FILEFLAGS 0x0L 22301b3bc768461bd303bff39f8cd1663682254e407joi@chromium.org # #endif 22401b3bc768461bd303bff39f8cd1663682254e407joi@chromium.org # FILEOS 0x4L 22501b3bc768461bd303bff39f8cd1663682254e407joi@chromium.org # FILETYPE 0x2L 22601b3bc768461bd303bff39f8cd1663682254e407joi@chromium.org # FILESUBTYPE 0x0L 22701b3bc768461bd303bff39f8cd1663682254e407joi@chromium.org # BEGIN 22801b3bc768461bd303bff39f8cd1663682254e407joi@chromium.org # BLOCK "StringFileInfo" 22901b3bc768461bd303bff39f8cd1663682254e407joi@chromium.org # BEGIN 23001b3bc768461bd303bff39f8cd1663682254e407joi@chromium.org # BLOCK "040904e4" 23101b3bc768461bd303bff39f8cd1663682254e407joi@chromium.org # BEGIN 23201b3bc768461bd303bff39f8cd1663682254e407joi@chromium.org # VALUE "CompanyName", "TODO: <Company name>" 23301b3bc768461bd303bff39f8cd1663682254e407joi@chromium.org # VALUE "FileDescription", "TODO: <File description>" 23401b3bc768461bd303bff39f8cd1663682254e407joi@chromium.org # VALUE "FileVersion", "1.0.0.1" 23501b3bc768461bd303bff39f8cd1663682254e407joi@chromium.org # VALUE "LegalCopyright", "TODO: (c) <Company name>. All rights reserved." 23601b3bc768461bd303bff39f8cd1663682254e407joi@chromium.org # VALUE "InternalName", "res_format_test.dll" 23701b3bc768461bd303bff39f8cd1663682254e407joi@chromium.org # VALUE "OriginalFilename", "res_format_test.dll" 23801b3bc768461bd303bff39f8cd1663682254e407joi@chromium.org # VALUE "ProductName", "TODO: <Product name>" 23901b3bc768461bd303bff39f8cd1663682254e407joi@chromium.org # VALUE "ProductVersion", "1.0.0.1" 24001b3bc768461bd303bff39f8cd1663682254e407joi@chromium.org # END 24101b3bc768461bd303bff39f8cd1663682254e407joi@chromium.org # END 24201b3bc768461bd303bff39f8cd1663682254e407joi@chromium.org # BLOCK "VarFileInfo" 24301b3bc768461bd303bff39f8cd1663682254e407joi@chromium.org # BEGIN 24401b3bc768461bd303bff39f8cd1663682254e407joi@chromium.org # VALUE "Translation", 0x409, 1252 24501b3bc768461bd303bff39f8cd1663682254e407joi@chromium.org # END 24601b3bc768461bd303bff39f8cd1663682254e407joi@chromium.org # END 24701b3bc768461bd303bff39f8cd1663682254e407joi@chromium.org # 24801b3bc768461bd303bff39f8cd1663682254e407joi@chromium.org # 24901b3bc768461bd303bff39f8cd1663682254e407joi@chromium.org # In addition to the above fields, VALUE fields named "Comments" and 25001b3bc768461bd303bff39f8cd1663682254e407joi@chromium.org # "LegalTrademarks" may also be translateable. 25101b3bc768461bd303bff39f8cd1663682254e407joi@chromium.org 25201fadb72b6e94e6511eaffd1874a8cc095f098a7joi@chromium.org version_re_ = lazy_re.compile(''' 25301b3bc768461bd303bff39f8cd1663682254e407joi@chromium.org # Match the ID on the first line 25401b3bc768461bd303bff39f8cd1663682254e407joi@chromium.org ^(?P<id1>[A-Z0-9_]+)\s+VERSIONINFO 25501b3bc768461bd303bff39f8cd1663682254e407joi@chromium.org | 25601b3bc768461bd303bff39f8cd1663682254e407joi@chromium.org # Match all potentially translateable VALUE sections 25701b3bc768461bd303bff39f8cd1663682254e407joi@chromium.org \s+VALUE\s+" 25801b3bc768461bd303bff39f8cd1663682254e407joi@chromium.org ( 25901b3bc768461bd303bff39f8cd1663682254e407joi@chromium.org CompanyName|FileDescription|LegalCopyright| 26001b3bc768461bd303bff39f8cd1663682254e407joi@chromium.org ProductName|Comments|LegalTrademarks 26101b3bc768461bd303bff39f8cd1663682254e407joi@chromium.org )",\s+"(?P<text1>.*?([^"]|""))"\s 26201b3bc768461bd303bff39f8cd1663682254e407joi@chromium.org ''', re.MULTILINE | re.VERBOSE) 26301b3bc768461bd303bff39f8cd1663682254e407joi@chromium.org 26401b3bc768461bd303bff39f8cd1663682254e407joi@chromium.org def Parse(self): 26501b3bc768461bd303bff39f8cd1663682254e407joi@chromium.org '''Knows how to parse VERSIONINFO resource sections.''' 266ec8016c73b3b945b6284746230913d88653f35e7benrg@chromium.org self.ReadSection() 26701b3bc768461bd303bff39f8cd1663682254e407joi@chromium.org self._RegExpParse(self.version_re_, self.text_) 26801b3bc768461bd303bff39f8cd1663682254e407joi@chromium.org 26901b3bc768461bd303bff39f8cd1663682254e407joi@chromium.org # TODO(joi) May need to override the Translate() method to change the 27001b3bc768461bd303bff39f8cd1663682254e407joi@chromium.org # "Translation" VALUE block to indicate the correct language code. 27101b3bc768461bd303bff39f8cd1663682254e407joi@chromium.org 27201b3bc768461bd303bff39f8cd1663682254e407joi@chromium.org 27301b3bc768461bd303bff39f8cd1663682254e407joi@chromium.orgclass RCData(Section): 27401b3bc768461bd303bff39f8cd1663682254e407joi@chromium.org '''A resource section that contains some data .''' 27501b3bc768461bd303bff39f8cd1663682254e407joi@chromium.org 27601b3bc768461bd303bff39f8cd1663682254e407joi@chromium.org # A typical rcdataresource section looks like this: 27701b3bc768461bd303bff39f8cd1663682254e407joi@chromium.org # 27801b3bc768461bd303bff39f8cd1663682254e407joi@chromium.org # IDR_BLAH RCDATA { 1, 2, 3, 4 } 27901b3bc768461bd303bff39f8cd1663682254e407joi@chromium.org 28001fadb72b6e94e6511eaffd1874a8cc095f098a7joi@chromium.org dialog_re_ = lazy_re.compile(''' 28101b3bc768461bd303bff39f8cd1663682254e407joi@chromium.org ^(?P<id1>[A-Z0-9_]+)\s+RCDATA\s+(DISCARDABLE)?\s+\{.*?\} 28201b3bc768461bd303bff39f8cd1663682254e407joi@chromium.org ''', re.MULTILINE | re.VERBOSE | re.DOTALL) 28301b3bc768461bd303bff39f8cd1663682254e407joi@chromium.org 28401b3bc768461bd303bff39f8cd1663682254e407joi@chromium.org def Parse(self): 285ec8016c73b3b945b6284746230913d88653f35e7benrg@chromium.org '''Implementation for resource types w/braces (not BEGIN/END) 28601b3bc768461bd303bff39f8cd1663682254e407joi@chromium.org ''' 287b9161407f737461b5db16a29782f8a31d19e602dbenrg@chromium.org rc_text = self._LoadInputFile() 28801b3bc768461bd303bff39f8cd1663682254e407joi@chromium.org 28901b3bc768461bd303bff39f8cd1663682254e407joi@chromium.org out = '' 29001b3bc768461bd303bff39f8cd1663682254e407joi@chromium.org begin_count = 0 29101b3bc768461bd303bff39f8cd1663682254e407joi@chromium.org openbrace_count = 0 292ec8016c73b3b945b6284746230913d88653f35e7benrg@chromium.org assert self.extkey 293ec8016c73b3b945b6284746230913d88653f35e7benrg@chromium.org first_line_re = re.compile(r'\s*' + self.extkey + r'\b') 294ec8016c73b3b945b6284746230913d88653f35e7benrg@chromium.org for line in rc_text.splitlines(True): 295ec8016c73b3b945b6284746230913d88653f35e7benrg@chromium.org if out or first_line_re.match(line): 29601b3bc768461bd303bff39f8cd1663682254e407joi@chromium.org out += line 29701b3bc768461bd303bff39f8cd1663682254e407joi@chromium.org 298ec8016c73b3b945b6284746230913d88653f35e7benrg@chromium.org # We stop once the braces balance (could happen in one line). 29901b3bc768461bd303bff39f8cd1663682254e407joi@chromium.org begin_count_was = begin_count 30001b3bc768461bd303bff39f8cd1663682254e407joi@chromium.org if len(out) > 0: 30101b3bc768461bd303bff39f8cd1663682254e407joi@chromium.org openbrace_count += line.count('{') 30201b3bc768461bd303bff39f8cd1663682254e407joi@chromium.org begin_count += line.count('{') 30301b3bc768461bd303bff39f8cd1663682254e407joi@chromium.org begin_count -= line.count('}') 30401b3bc768461bd303bff39f8cd1663682254e407joi@chromium.org if ((begin_count_was == 1 and begin_count == 0) or 30501b3bc768461bd303bff39f8cd1663682254e407joi@chromium.org (openbrace_count > 0 and begin_count == 0)): 30601b3bc768461bd303bff39f8cd1663682254e407joi@chromium.org break 30701b3bc768461bd303bff39f8cd1663682254e407joi@chromium.org 30801b3bc768461bd303bff39f8cd1663682254e407joi@chromium.org if len(out) == 0: 309ec8016c73b3b945b6284746230913d88653f35e7benrg@chromium.org raise exception.SectionNotFound('%s in file %s' % (self.extkey, self.rc_file)) 310ec8016c73b3b945b6284746230913d88653f35e7benrg@chromium.org 311ec8016c73b3b945b6284746230913d88653f35e7benrg@chromium.org self.text_ = out 31201b3bc768461bd303bff39f8cd1663682254e407joi@chromium.org 313ec8016c73b3b945b6284746230913d88653f35e7benrg@chromium.org self._RegExpParse(self.dialog_re_, out) 31401b3bc768461bd303bff39f8cd1663682254e407joi@chromium.org 31501b3bc768461bd303bff39f8cd1663682254e407joi@chromium.org 31601b3bc768461bd303bff39f8cd1663682254e407joi@chromium.orgclass Accelerators(Section): 31701b3bc768461bd303bff39f8cd1663682254e407joi@chromium.org '''An ACCELERATORS table. 31801b3bc768461bd303bff39f8cd1663682254e407joi@chromium.org ''' 31901b3bc768461bd303bff39f8cd1663682254e407joi@chromium.org 32001b3bc768461bd303bff39f8cd1663682254e407joi@chromium.org # A typical ACCELERATORS section looks like this: 32101b3bc768461bd303bff39f8cd1663682254e407joi@chromium.org # 32201b3bc768461bd303bff39f8cd1663682254e407joi@chromium.org # IDR_ACCELERATOR1 ACCELERATORS 32301b3bc768461bd303bff39f8cd1663682254e407joi@chromium.org # BEGIN 32401b3bc768461bd303bff39f8cd1663682254e407joi@chromium.org # "^C", ID_ACCELERATOR32770, ASCII, NOINVERT 32501b3bc768461bd303bff39f8cd1663682254e407joi@chromium.org # "^V", ID_ACCELERATOR32771, ASCII, NOINVERT 32601b3bc768461bd303bff39f8cd1663682254e407joi@chromium.org # VK_INSERT, ID_ACCELERATOR32772, VIRTKEY, CONTROL, NOINVERT 32701b3bc768461bd303bff39f8cd1663682254e407joi@chromium.org # END 32801b3bc768461bd303bff39f8cd1663682254e407joi@chromium.org 32901fadb72b6e94e6511eaffd1874a8cc095f098a7joi@chromium.org accelerators_re_ = lazy_re.compile(''' 33001b3bc768461bd303bff39f8cd1663682254e407joi@chromium.org # Match the ID on the first line 33101b3bc768461bd303bff39f8cd1663682254e407joi@chromium.org ^(?P<id1>[A-Z0-9_]+)\s+ACCELERATORS\s+ 33201b3bc768461bd303bff39f8cd1663682254e407joi@chromium.org | 33301b3bc768461bd303bff39f8cd1663682254e407joi@chromium.org # Match accelerators specified as VK_XXX 33401b3bc768461bd303bff39f8cd1663682254e407joi@chromium.org \s+VK_[A-Z0-9_]+,\s*(?P<id2>[A-Z0-9_]+)\s*, 33501b3bc768461bd303bff39f8cd1663682254e407joi@chromium.org | 33601b3bc768461bd303bff39f8cd1663682254e407joi@chromium.org # Match accelerators specified as e.g. "^C" 33701b3bc768461bd303bff39f8cd1663682254e407joi@chromium.org \s+"[^"]*",\s+(?P<id3>[A-Z0-9_]+)\s*, 33801b3bc768461bd303bff39f8cd1663682254e407joi@chromium.org ''', re.MULTILINE | re.VERBOSE) 33901b3bc768461bd303bff39f8cd1663682254e407joi@chromium.org 34001b3bc768461bd303bff39f8cd1663682254e407joi@chromium.org def Parse(self): 34101b3bc768461bd303bff39f8cd1663682254e407joi@chromium.org '''Knows how to parse ACCELERATORS resource sections.''' 342ec8016c73b3b945b6284746230913d88653f35e7benrg@chromium.org self.ReadSection() 34301b3bc768461bd303bff39f8cd1663682254e407joi@chromium.org self._RegExpParse(self.accelerators_re_, self.text_) 344