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