Changed StrGather behavior to be more R8 like
[people/mcb30/basetools.git] / Source / Python / AutoGen / StrGather.py
1 # Copyright (c) 2007, Intel Corporation\r
2 # All rights reserved. This program and the accompanying materials\r
3 # are licensed and made available under the terms and conditions of the BSD License\r
4 # which accompanies this distribution.  The full text of the license may be found at\r
5 # http://opensource.org/licenses/bsd-license.php\r
6 #\r
7 # THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,\r
8 # WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.\r
9 \r
10 #\r
11 #This file is used to parse a strings file and create or add to a string database file.\r
12 #\r
13 \r
14 ##\r
15 # Import Modules\r
16 #\r
17 import re\r
18 import Common.EdkLogger as EdkLogger\r
19 from Common.BuildToolError import *\r
20 from UniClassObject import *\r
21 \r
22 ##\r
23 # Static definitions\r
24 #\r
25 EFI_HII_SIBT_END = '0x00'\r
26 EFI_HII_SIBT_STRING_SCSU = '0x10'\r
27 EFI_HII_SIBT_STRING_SCSU_FONT = '0x11'\r
28 EFI_HII_SIBT_STRINGS_SCSU = '0x12'\r
29 EFI_HII_SIBT_STRINGS_SCSU_FONT = '0x13'\r
30 EFI_HII_SIBT_STRING_UCS2 = '0x14'\r
31 EFI_HII_SIBT_STRING_UCS2_FONT = '0x15'\r
32 EFI_HII_SIBT_STRINGS_UCS2 = '0x16'\r
33 EFI_HII_SIBT_STRINGS_UCS2_FONT = '0x17'\r
34 EFI_HII_SIBT_DUPLICATE = '0x20'\r
35 EFI_HII_SIBT_SKIP2 = '0x21'\r
36 EFI_HII_SIBT_SKIP1 = '0x22'\r
37 EFI_HII_SIBT_EXT1 = '0x30'\r
38 EFI_HII_SIBT_EXT2 = '0x31'\r
39 EFI_HII_SIBT_EXT4 = '0x32'\r
40 EFI_HII_SIBT_FONT = '0x40'\r
41 \r
42 EFI_HII_PACKAGE_STRINGS = '0x04'\r
43 \r
44 StringPackageType = EFI_HII_PACKAGE_STRINGS\r
45 StringBlockType = EFI_HII_SIBT_STRING_UCS2\r
46 StringSkipType = EFI_HII_SIBT_SKIP2\r
47 \r
48 HexHeader = '0x'\r
49 \r
50 COMMENT = '// '\r
51 DEFINE_STR = '#define'\r
52 COMMENT_DEFINE_STR = COMMENT + DEFINE_STR\r
53 NOT_REFERENCED = 'not referenced'\r
54 COMMENT_NOT_REFERENCED = ' ' + COMMENT + NOT_REFERENCED\r
55 CHAR_ARRAY_DEFIN = 'unsigned char'\r
56 COMMON_FILE_NAME = 'Strings'\r
57 OFFSET = 'offset'\r
58 STRING = 'string'\r
59 TO = 'to'\r
60 STRING_TOKEN = re.compile('STRING_TOKEN *\(([A-Z0-9_]+) *\)', re.MULTILINE | re.UNICODE)\r
61 \r
62 EFI_HII_ARRAY_SIZE_LENGTH = 4\r
63 EFI_HII_PACKAGE_HEADER_LENGTH = 4\r
64 EFI_HII_HDR_SIZE_LENGTH = 4\r
65 EFI_HII_STRING_OFFSET_LENGTH = 4\r
66 EFI_STRING_ID = 1\r
67 EFI_STRING_ID_LENGTH = 2\r
68 EFI_HII_LANGUAGE_WINDOW = 0\r
69 EFI_HII_LANGUAGE_WINDOW_LENGTH = 2\r
70 EFI_HII_LANGUAGE_WINDOW_NUMBER = 16\r
71 EFI_HII_STRING_PACKAGE_HDR_LENGTH = EFI_HII_PACKAGE_HEADER_LENGTH + EFI_HII_HDR_SIZE_LENGTH + EFI_HII_STRING_OFFSET_LENGTH + EFI_HII_LANGUAGE_WINDOW_LENGTH * EFI_HII_LANGUAGE_WINDOW_NUMBER + EFI_STRING_ID_LENGTH\r
72 \r
73 H_C_FILE_HEADER = ['//', \\r
74                    '//  DO NOT EDIT -- auto-generated file', \\r
75                    '//', \\r
76                    '//  This file is generated by the StrGather utility', \\r
77                    '//']\r
78 LANGUAGE_NAME_STRING_NAME = '$LANGUAGE_NAME'\r
79 PRINTABLE_LANGUAGE_NAME_STRING_NAME = '$PRINTABLE_LANGUAGE_NAME'\r
80 \r
81 ## Convert a dec number to a hex string\r
82 #\r
83 # Convert a dec number to a formatted hex string in length digit\r
84 # The digit is set to default 8\r
85 # The hex string starts with "0x"\r
86 # DecToHexStr(1000) is '0x000003E8'\r
87 # DecToHexStr(1000, 6) is '0x0003E8'\r
88 #\r
89 # @param Dec:    The number in dec format\r
90 # @param Digit:  The needed digit of hex string\r
91 #\r
92 # @retval:       The formatted hex string  \r
93 #\r
94 def DecToHexStr(Dec, Digit = 8):\r
95     return eval("'0x%0" + str(Digit) + "X' % int(Dec)")\r
96 \r
97 ## Convert a dec number to a hex list\r
98 #\r
99 # Convert a dec number to a formatted hex list in size digit\r
100 # The digit is set to default 8\r
101 # DecToHexList(1000) is ['0xE8', '0x03', '0x00', '0x00']\r
102 # DecToHexList(1000, 6) is ['0xE8', '0x03', '0x00']\r
103 #\r
104 # @param Dec:    The number in dec format\r
105 # @param Digit:  The needed digit of hex list\r
106 #\r
107 # @retval:       A list for formatted hex string\r
108 #\r
109 def DecToHexList(Dec, Digit = 8):\r
110     Hex = eval("'%0" + str(Digit) + "X' % int(Dec)" )\r
111     List = []\r
112     for Bit in range(Digit - 2, -1, -2):\r
113         List.append(HexHeader + Hex[Bit:Bit + 2])\r
114     return List\r
115 \r
116 ## Convert a acsii string to a hex list\r
117 #\r
118 # Convert a acsii string to a formatted hex list\r
119 # AscToHexList('en-US') is ['0x65', '0x6E', '0x2D', '0x55', '0x53']\r
120 #\r
121 # @param Ascii:  The acsii string\r
122 #\r
123 # @retval:       A list for formatted hex string\r
124 #\r
125 def AscToHexList(Ascii):\r
126     List = []\r
127     for Item in Ascii:\r
128         List.append('0x%2X' % ord(Item))\r
129     \r
130     return List\r
131 \r
132 ## Create header of .h file\r
133 #\r
134 # Create a header of .h file\r
135 #\r
136 # @param BaseName: The basename of strings\r
137 #\r
138 # @retval Str:     A string for .h file header\r
139 #\r
140 def CreateHFileHeader(BaseName):\r
141     Str = ''\r
142     for Item in H_C_FILE_HEADER:\r
143         Str = WriteLine(Str, Item)\r
144     Str = WriteLine(Str, '#ifndef _' + BaseName.upper() + '_STRINGS_DEFINE_H_')\r
145     Str = WriteLine(Str, '#define _' + BaseName.upper() + '_STRINGS_DEFINE_H_')\r
146     return Str\r
147 \r
148 ## Create content of .h file\r
149 #\r
150 # Create content of .h file\r
151 #\r
152 # @param BaseName:       The basename of strings\r
153 # @param UniObjectClass: A UniObjectClass instance \r
154 #\r
155 # @retval Str:           A string of .h file content \r
156 #\r
157 def CreateHFileContent(BaseName, UniObjectClass):\r
158     Str = ''\r
159     ValueStartPtr = 60\r
160     Line = COMMENT_DEFINE_STR + ' ' + LANGUAGE_NAME_STRING_NAME + ' ' * (ValueStartPtr - len(DEFINE_STR + LANGUAGE_NAME_STRING_NAME)) + DecToHexStr(0, 4) + COMMENT_NOT_REFERENCED\r
161     Str = WriteLine(Str, Line)\r
162     Line = COMMENT_DEFINE_STR + ' ' + PRINTABLE_LANGUAGE_NAME_STRING_NAME + ' ' * (ValueStartPtr - len(DEFINE_STR + PRINTABLE_LANGUAGE_NAME_STRING_NAME)) + DecToHexStr(1, 4) + COMMENT_NOT_REFERENCED\r
163     Str = WriteLine(Str, Line)\r
164     for Index in range(2, len(UniObjectClass.OrderedStringList[UniObjectClass.LanguageDef[0][0]])):\r
165         StringItem = UniObjectClass.OrderedStringList[UniObjectClass.LanguageDef[0][0]][Index]\r
166         Name = StringItem.StringName\r
167         Token = StringItem.Token\r
168         Referenced = StringItem.Referenced\r
169         if Name != None:\r
170             Line = ''\r
171             if Referenced == True:\r
172                 Line = DEFINE_STR + ' ' + Name + ' ' * (ValueStartPtr - len(DEFINE_STR + Name)) + DecToHexStr(Token, 4)\r
173             else:\r
174                 Line = COMMENT_DEFINE_STR + ' ' + Name + ' ' * (ValueStartPtr - len(DEFINE_STR + Name)) + DecToHexStr(Token, 4) + COMMENT_NOT_REFERENCED\r
175             Str = WriteLine(Str, Line)\r
176 \r
177     Str =  WriteLine(Str, '')\r
178     Str = WriteLine(Str, 'extern unsigned char ' + BaseName + 'Strings[];')\r
179     return Str\r
180 \r
181 ## Create a complete .h file\r
182 #\r
183 # Create a complet .h file with file header and file content\r
184 #\r
185 # @param BaseName:       The basename of strings\r
186 # @param UniObjectClass: A UniObjectClass instance \r
187 #\r
188 # @retval Str:           A string of complete .h file \r
189 #\r
190 def CreateHFile(BaseName, UniObjectClass):\r
191     HFile = WriteLine('', CreateHFileContent(BaseName, UniObjectClass))\r
192 \r
193     return HFile\r
194 \r
195 ## Create header of .c file\r
196 #\r
197 # Create a header of .c file\r
198 #\r
199 # @retval Str:     A string for .c file header\r
200 #\r
201 def CreateCFileHeader():\r
202     Str = ''\r
203     for Item in H_C_FILE_HEADER:\r
204         Str = WriteLine(Str, Item)\r
205 \r
206     return Str\r
207 \r
208 ## Create a formatted string all items in an array\r
209 #\r
210 # Use ',' to join each item in an array, and break an new line when reaching the width (default is 16)\r
211 #\r
212 # @param Array:      The array need to be formatted\r
213 # @param Width:      The line length, the default value is set to 16\r
214 #\r
215 # @retval ArrayItem: A string for all formatted array items\r
216 #\r
217 def CreateArrayItem(Array, Width = 16):\r
218     MaxLength = Width\r
219     Index = 0\r
220     Line = '  '\r
221     ArrayItem = ''\r
222 \r
223     for Item in Array:\r
224         if Index < MaxLength:\r
225             Line = Line + Item + ',  '\r
226             Index = Index + 1\r
227         else:\r
228             ArrayItem = WriteLine(ArrayItem, Line)\r
229             Line = '  ' + Item +  ',  '\r
230             Index = 1\r
231     ArrayItem = Write(ArrayItem, Line.rstrip())\r
232 \r
233     return ArrayItem\r
234 \r
235 ## CreateCFileStringValue\r
236 #\r
237 # Create a line with string value\r
238 #\r
239 # @param Value:  Value of the string\r
240 #\r
241 # @retval Str:   A formatted string with string value\r
242 #\r
243 \r
244 def CreateCFileStringValue(Value):\r
245     Value = [StringBlockType] + Value\r
246     Str = WriteLine('', CreateArrayItem(Value))\r
247 \r
248     return Str\r
249 \r
250 \r
251 ## Create content of .c file\r
252 #\r
253 # Create content of .c file\r
254 #\r
255 # @param BaseName:       The basename of strings\r
256 # @param UniObjectClass: A UniObjectClass instance \r
257 #\r
258 # @retval Str:           A string of .c file content \r
259 #\r
260 def CreateCFileContent(BaseName, UniObjectClass):\r
261     #\r
262     # Init array length\r
263     #\r
264     TotalLength = EFI_HII_ARRAY_SIZE_LENGTH\r
265     Str = ''\r
266     Offset = 0\r
267     \r
268     #\r
269     # Create lines for each language's strings\r
270     #\r
271     for IndexI in range(len(UniObjectClass.LanguageDef)):\r
272         Language = UniObjectClass.LanguageDef[IndexI][0]\r
273         LangPrintName = UniObjectClass.LanguageDef[IndexI][1]\r
274         \r
275         StrStringValue = ''\r
276         ArrayLength = 0\r
277         NumberOfUseOhterLangDef = 0\r
278         Index = 0\r
279         for IndexJ in range(1, len(UniObjectClass.OrderedStringList[UniObjectClass.LanguageDef[IndexI][0]])):\r
280             Item = UniObjectClass.FindByToken(IndexJ, Language)\r
281             #Item = UniObjectClass.OrderedStringList[UniObjectClass.LanguageDef[IndexI][0]][IndexJ]\r
282         #for Item in UniObjectClass.OrderedStringList[Language]:\r
283             Name = Item.StringName\r
284             Value = Item.StringValueByteList\r
285             Referenced = Item.Referenced\r
286             Token = Item.Token\r
287             Length = Item.Length\r
288             UseOtherLangDef = Item.UseOtherLangDef\r
289             \r
290             if UseOtherLangDef != '' and Referenced:\r
291                 NumberOfUseOhterLangDef = NumberOfUseOhterLangDef + 1\r
292                 Index = Index + 1\r
293             else:\r
294                 if NumberOfUseOhterLangDef > 0:\r
295                     StrStringValue = WriteLine(StrStringValue, CreateArrayItem([StringSkipType, DecToHexStr(NumberOfUseOhterLangDef, 2), EFI_HII_SIBT_END]))\r
296                     NumberOfUseOhterLangDef = 0\r
297                     ArrayLength = ArrayLength + 3\r
298                 if Referenced and Item.Token > 0:\r
299                     Index = Index + 1\r
300                     StrStringValue = WriteLine(StrStringValue, "// %s: %s:%s" % (DecToHexStr(Index, 4), Name, DecToHexStr(Token, 4)))\r
301                     StrStringValue = Write(StrStringValue, CreateCFileStringValue(Value))\r
302                     Offset = Offset + Length\r
303                     ArrayLength = ArrayLength + Item.Length + 1 # 1 is for the length of string type        \r
304 \r
305         #\r
306         # EFI_HII_PACKAGE_HEADER\r
307         #\r
308         Str = WriteLine(Str, '// PACKAGE HEADER\n')\r
309         Offset = EFI_HII_STRING_PACKAGE_HDR_LENGTH + len(Language) + 1\r
310         ArrayLength = Offset + ArrayLength + 1\r
311         TotalLength = TotalLength + ArrayLength\r
312         \r
313         List = DecToHexList(ArrayLength, 6) + \\r
314                [StringPackageType] + \\r
315                DecToHexList(Offset) + \\r
316                DecToHexList(Offset) + \\r
317                DecToHexList(EFI_HII_LANGUAGE_WINDOW, EFI_HII_LANGUAGE_WINDOW_LENGTH * 2) * EFI_HII_LANGUAGE_WINDOW_NUMBER + \\r
318                DecToHexList(EFI_STRING_ID, 4) + \\r
319                AscToHexList(Language) + \\r
320                DecToHexList(0, 2)\r
321         Str = WriteLine(Str, CreateArrayItem(List, 16) + '\n')\r
322         \r
323         #\r
324         # PACKAGE DATA\r
325         #\r
326         Str = WriteLine(Str, '// PACKAGE DATA\n')\r
327         Str = Write(Str, StrStringValue)\r
328         \r
329         #\r
330         # Add an EFI_HII_SIBT_END at last\r
331         #\r
332         Str = WriteLine(Str, '  ' + EFI_HII_SIBT_END + ",")\r
333         \r
334     #\r
335     # Create line for string variable name\r
336     # "unsigned char $(BaseName)Strings[] = {"\r
337     #\r
338     AllStr = WriteLine('', CHAR_ARRAY_DEFIN + ' ' + BaseName + COMMON_FILE_NAME + '[] = {\n' )\r
339     \r
340     #\r
341     # Create whole array length\r
342     #\r
343     AllStr = WriteLine(AllStr, '// STRING ARRAY LENGTH\n')\r
344     AllStr = WriteLine(AllStr, CreateArrayItem(DecToHexList(TotalLength)))\r
345     \r
346     #\r
347     # Join package data\r
348     #\r
349     AllStr = Write(AllStr, Str)\r
350     \r
351     return AllStr\r
352 \r
353 ## Create end of .c file\r
354 #\r
355 # Create end of .c file\r
356 #\r
357 # @retval Str:           A string of .h file end \r
358 #\r
359 def CreateCFileEnd():\r
360     Str = Write('', '};')\r
361     return Str\r
362 \r
363 ## Create a .c file\r
364 #\r
365 # Create a complete .c file\r
366 #\r
367 # @param BaseName:       The basename of strings\r
368 # @param UniObjectClass: A UniObjectClass instance \r
369 #\r
370 # @retval CFile:         A string of complete .c file\r
371 #\r
372 def CreateCFile(BaseName, UniObjectClass):\r
373     CFile = ''\r
374     #CFile = WriteLine(CFile, CreateCFileHeader())\r
375     CFile = WriteLine(CFile, CreateCFileContent(BaseName, UniObjectClass))\r
376     CFile = WriteLine(CFile, CreateCFileEnd())\r
377     return CFile\r
378 \r
379 ## GetFileList\r
380 #\r
381 # Get a list for all files\r
382 #\r
383 # @param IncludeList:  A list of all path to be searched\r
384 # @param SkipList:     A list of all types of file could be skipped \r
385 #\r
386 # @retval FileList:    A list of all files found\r
387 #\r
388 def GetFileList(SourceFileList, IncludeList, SkipList):\r
389     if IncludeList == None:\r
390         EdkLogger.error("UnicodeStringGather", AUTOGEN_ERROR, "Include path for unicode file is not defined")\r
391 \r
392     FileList = []\r
393     if SkipList == None:\r
394         SkipList = []\r
395 \r
396     for File in SourceFileList:\r
397         for Dir in IncludeList:\r
398             if not os.path.exists(Dir):\r
399                 continue\r
400             File = os.path.join(Dir, os.path.normcase(File))\r
401             #\r
402             # Ignore Dir\r
403             #\r
404             if os.path.isfile(File) != True:\r
405                 continue\r
406             #\r
407             # Ignore file listed in skip list\r
408             #\r
409             IsSkip = False\r
410             for Skip in SkipList:\r
411                 if os.path.splitext(File)[1].upper() == Skip.upper():\r
412                     EdkLogger.verbose("Skipped %s for string token uses search" % File)\r
413                     IsSkip = True\r
414                     break\r
415 \r
416             if not IsSkip:\r
417                 FileList.append(File)\r
418             break\r
419 \r
420     return FileList\r
421 \r
422 ## SearchString\r
423 #\r
424 # Search whether all string defined in UniObjectClass are referenced\r
425 # All string used should be set to Referenced\r
426 #\r
427 # @param UniObjectClass:  Input UniObjectClass\r
428 # @param FileList:        Search path list\r
429 #\r
430 # @retval UniObjectClass: UniObjectClass after searched\r
431 #\r
432 def SearchString(UniObjectClass, FileList):\r
433     if FileList == []:\r
434         return UniObjectClass\r
435 \r
436     for File in FileList:\r
437         if os.path.isfile(File):\r
438             Lines = open(File, 'r')\r
439             for Line in Lines:\r
440                 StringTokenList = STRING_TOKEN.findall(Line)\r
441                 for StrName in StringTokenList:\r
442                     EdkLogger.debug(EdkLogger.DEBUG_5, "Found string identifier: " + StrName)\r
443                     UniObjectClass.SetStringReferenced(StrName)\r
444 \r
445     UniObjectClass.ReToken()\r
446 \r
447     return UniObjectClass\r
448 \r
449 ## GetStringFiles\r
450 #\r
451 # This function is used for UEFI2.1 spec\r
452\r
453 #\r
454 def GetStringFiles(UniFilList, SourceFileList, IncludeList, SkipList, BaseName):\r
455     Status = True\r
456     ErrorMessage = ''\r
457 \r
458     if len(UniFilList) > 0:\r
459         Uni = UniFileClassObject(UniFilList)\r
460     else:\r
461         EdkLogger.error("UnicodeStringGather", AUTOGEN_ERROR, 'No unicode files given')\r
462 \r
463     FileList = GetFileList(SourceFileList, IncludeList, SkipList)\r
464 \r
465     Uni = SearchString(Uni, FileList)\r
466 \r
467     HFile = CreateHFile(BaseName, Uni)\r
468     CFile = CreateCFile(BaseName, Uni)\r
469 \r
470     return HFile, CFile\r
471 \r
472 #\r
473 # Write an item\r
474 #\r
475 def Write(Target, Item):\r
476     return Target + Item\r
477 \r
478 #\r
479 # Write an item with a break line\r
480 #\r
481 def WriteLine(Target, Item):\r
482     return Target + Item + '\n'\r
483 \r
484 # This acts like the main() function for the script, unless it is 'import'ed into another\r
485 # script.\r
486 if __name__ == '__main__':\r
487     EdkLogger.info('start')\r
488 \r
489     UniFileList = [\r
490          r'C:\\Edk\\Strings2.uni',\r
491          r'C:\\Edk\\Strings.uni'\r
492     ]\r
493 \r
494     IncludeList = [\r
495         r'C:\\Edk'\r
496     ]\r
497 \r
498     SkipList = ['.inf', '.uni']\r
499     BaseName = 'DriverSample'\r
500     (h, c) = GetStringFiles(UniFileList, IncludeList, SkipList, BaseName)\r
501     hfile = open('unistring.h', 'w')\r
502     cfile = open('unistring.c', 'w')\r
503     hfile.write(h)\r
504     cfile.write(c)\r
505 \r
506     EdkLogger.info('end')\r