1## @file 2# This file is used to collect all defined strings in multiple uni files 3# 4# 5# Copyright (c) 2014 Hewlett-Packard Development Company, L.P.<BR> 6# 7# Copyright (c) 2007 - 2015, Intel Corporation. All rights reserved.<BR> 8# This program and the accompanying materials 9# are licensed and made available under the terms and conditions of the BSD License 10# which accompanies this distribution. The full text of the license may be found at 11# http://opensource.org/licenses/bsd-license.php 12# 13# THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, 14# WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. 15 16## 17# Import Modules 18# 19import Common.LongFilePathOs as os, codecs, re 20import distutils.util 21import Common.EdkLogger as EdkLogger 22import StringIO 23from Common.BuildToolError import * 24from Common.String import GetLineNo 25from Common.Misc import PathClass 26from Common.LongFilePathSupport import LongFilePath 27## 28# Static definitions 29# 30UNICODE_WIDE_CHAR = u'\\wide' 31UNICODE_NARROW_CHAR = u'\\narrow' 32UNICODE_NON_BREAKING_CHAR = u'\\nbr' 33UNICODE_UNICODE_CR = '\r' 34UNICODE_UNICODE_LF = '\n' 35 36NARROW_CHAR = u'\uFFF0' 37WIDE_CHAR = u'\uFFF1' 38NON_BREAKING_CHAR = u'\uFFF2' 39CR = u'\u000D' 40LF = u'\u000A' 41NULL = u'\u0000' 42TAB = u'\t' 43BACK_SLASH_PLACEHOLDER = u'\u0006' 44 45gIncludePattern = re.compile("^#include +[\"<]+([^\"< >]+)[>\"]+$", re.MULTILINE | re.UNICODE) 46 47## Convert a python unicode string to a normal string 48# 49# Convert a python unicode string to a normal string 50# UniToStr(u'I am a string') is 'I am a string' 51# 52# @param Uni: The python unicode string 53# 54# @retval: The formatted normal string 55# 56def UniToStr(Uni): 57 return repr(Uni)[2:-1] 58 59## Convert a unicode string to a Hex list 60# 61# Convert a unicode string to a Hex list 62# UniToHexList('ABC') is ['0x41', '0x00', '0x42', '0x00', '0x43', '0x00'] 63# 64# @param Uni: The python unicode string 65# 66# @retval List: The formatted hex list 67# 68def UniToHexList(Uni): 69 List = [] 70 for Item in Uni: 71 Temp = '%04X' % ord(Item) 72 List.append('0x' + Temp[2:4]) 73 List.append('0x' + Temp[0:2]) 74 return List 75 76LangConvTable = {'eng':'en', 'fra':'fr', \ 77 'aar':'aa', 'abk':'ab', 'ave':'ae', 'afr':'af', 'aka':'ak', 'amh':'am', \ 78 'arg':'an', 'ara':'ar', 'asm':'as', 'ava':'av', 'aym':'ay', 'aze':'az', \ 79 'bak':'ba', 'bel':'be', 'bul':'bg', 'bih':'bh', 'bis':'bi', 'bam':'bm', \ 80 'ben':'bn', 'bod':'bo', 'bre':'br', 'bos':'bs', 'cat':'ca', 'che':'ce', \ 81 'cha':'ch', 'cos':'co', 'cre':'cr', 'ces':'cs', 'chu':'cu', 'chv':'cv', \ 82 'cym':'cy', 'dan':'da', 'deu':'de', 'div':'dv', 'dzo':'dz', 'ewe':'ee', \ 83 'ell':'el', 'epo':'eo', 'spa':'es', 'est':'et', 'eus':'eu', 'fas':'fa', \ 84 'ful':'ff', 'fin':'fi', 'fij':'fj', 'fao':'fo', 'fry':'fy', 'gle':'ga', \ 85 'gla':'gd', 'glg':'gl', 'grn':'gn', 'guj':'gu', 'glv':'gv', 'hau':'ha', \ 86 'heb':'he', 'hin':'hi', 'hmo':'ho', 'hrv':'hr', 'hat':'ht', 'hun':'hu', \ 87 'hye':'hy', 'her':'hz', 'ina':'ia', 'ind':'id', 'ile':'ie', 'ibo':'ig', \ 88 'iii':'ii', 'ipk':'ik', 'ido':'io', 'isl':'is', 'ita':'it', 'iku':'iu', \ 89 'jpn':'ja', 'jav':'jv', 'kat':'ka', 'kon':'kg', 'kik':'ki', 'kua':'kj', \ 90 'kaz':'kk', 'kal':'kl', 'khm':'km', 'kan':'kn', 'kor':'ko', 'kau':'kr', \ 91 'kas':'ks', 'kur':'ku', 'kom':'kv', 'cor':'kw', 'kir':'ky', 'lat':'la', \ 92 'ltz':'lb', 'lug':'lg', 'lim':'li', 'lin':'ln', 'lao':'lo', 'lit':'lt', \ 93 'lub':'lu', 'lav':'lv', 'mlg':'mg', 'mah':'mh', 'mri':'mi', 'mkd':'mk', \ 94 'mal':'ml', 'mon':'mn', 'mar':'mr', 'msa':'ms', 'mlt':'mt', 'mya':'my', \ 95 'nau':'na', 'nob':'nb', 'nde':'nd', 'nep':'ne', 'ndo':'ng', 'nld':'nl', \ 96 'nno':'nn', 'nor':'no', 'nbl':'nr', 'nav':'nv', 'nya':'ny', 'oci':'oc', \ 97 'oji':'oj', 'orm':'om', 'ori':'or', 'oss':'os', 'pan':'pa', 'pli':'pi', \ 98 'pol':'pl', 'pus':'ps', 'por':'pt', 'que':'qu', 'roh':'rm', 'run':'rn', \ 99 'ron':'ro', 'rus':'ru', 'kin':'rw', 'san':'sa', 'srd':'sc', 'snd':'sd', \ 100 'sme':'se', 'sag':'sg', 'sin':'si', 'slk':'sk', 'slv':'sl', 'smo':'sm', \ 101 'sna':'sn', 'som':'so', 'sqi':'sq', 'srp':'sr', 'ssw':'ss', 'sot':'st', \ 102 'sun':'su', 'swe':'sv', 'swa':'sw', 'tam':'ta', 'tel':'te', 'tgk':'tg', \ 103 'tha':'th', 'tir':'ti', 'tuk':'tk', 'tgl':'tl', 'tsn':'tn', 'ton':'to', \ 104 'tur':'tr', 'tso':'ts', 'tat':'tt', 'twi':'tw', 'tah':'ty', 'uig':'ug', \ 105 'ukr':'uk', 'urd':'ur', 'uzb':'uz', 'ven':'ve', 'vie':'vi', 'vol':'vo', \ 106 'wln':'wa', 'wol':'wo', 'xho':'xh', 'yid':'yi', 'yor':'yo', 'zha':'za', \ 107 'zho':'zh', 'zul':'zu'} 108 109## GetLanguageCode 110# 111# Check the language code read from .UNI file and convert ISO 639-2 codes to RFC 4646 codes if appropriate 112# ISO 639-2 language codes supported in compatiblity mode 113# RFC 4646 language codes supported in native mode 114# 115# @param LangName: Language codes read from .UNI file 116# 117# @retval LangName: Valid lanugage code in RFC 4646 format or None 118# 119def GetLanguageCode(LangName, IsCompatibleMode, File): 120 global LangConvTable 121 122 length = len(LangName) 123 if IsCompatibleMode: 124 if length == 3 and LangName.isalpha(): 125 TempLangName = LangConvTable.get(LangName.lower()) 126 if TempLangName != None: 127 return TempLangName 128 return LangName 129 else: 130 EdkLogger.error("Unicode File Parser", FORMAT_INVALID, "Invalid ISO 639-2 language code : %s" % LangName, File) 131 132 if (LangName[0] == 'X' or LangName[0] == 'x') and LangName[1] == '-': 133 return LangName 134 if length == 2: 135 if LangName.isalpha(): 136 return LangName 137 elif length == 3: 138 if LangName.isalpha() and LangConvTable.get(LangName.lower()) == None: 139 return LangName 140 elif length == 5: 141 if LangName[0:2].isalpha() and LangName[2] == '-': 142 return LangName 143 elif length >= 6: 144 if LangName[0:2].isalpha() and LangName[2] == '-': 145 return LangName 146 if LangName[0:3].isalpha() and LangConvTable.get(LangName.lower()) == None and LangName[3] == '-': 147 return LangName 148 149 EdkLogger.error("Unicode File Parser", FORMAT_INVALID, "Invalid RFC 4646 language code : %s" % LangName, File) 150 151## Ucs2Codec 152# 153# This is only a partial codec implementation. It only supports 154# encoding, and is primarily used to check that all the characters are 155# valid for UCS-2. 156# 157class Ucs2Codec(codecs.Codec): 158 def __init__(self): 159 self.__utf16 = codecs.lookup('utf-16') 160 161 def encode(self, input, errors='strict'): 162 for Char in input: 163 CodePoint = ord(Char) 164 if CodePoint >= 0xd800 and CodePoint <= 0xdfff: 165 raise ValueError("Code Point is in range reserved for " + 166 "UTF-16 surrogate pairs") 167 elif CodePoint > 0xffff: 168 raise ValueError("Code Point too large to encode in UCS-2") 169 return self.__utf16.encode(input) 170 171TheUcs2Codec = Ucs2Codec() 172def Ucs2Search(name): 173 if name == 'ucs-2': 174 return codecs.CodecInfo( 175 name=name, 176 encode=TheUcs2Codec.encode, 177 decode=TheUcs2Codec.decode) 178 else: 179 return None 180codecs.register(Ucs2Search) 181 182## StringDefClassObject 183# 184# A structure for language definition 185# 186class StringDefClassObject(object): 187 def __init__(self, Name = None, Value = None, Referenced = False, Token = None, UseOtherLangDef = ''): 188 self.StringName = '' 189 self.StringNameByteList = [] 190 self.StringValue = '' 191 self.StringValueByteList = '' 192 self.Token = 0 193 self.Referenced = Referenced 194 self.UseOtherLangDef = UseOtherLangDef 195 self.Length = 0 196 197 if Name != None: 198 self.StringName = Name 199 self.StringNameByteList = UniToHexList(Name) 200 if Value != None: 201 self.StringValue = Value + u'\x00' # Add a NULL at string tail 202 self.StringValueByteList = UniToHexList(self.StringValue) 203 self.Length = len(self.StringValueByteList) 204 if Token != None: 205 self.Token = Token 206 207 def __str__(self): 208 return repr(self.StringName) + ' ' + \ 209 repr(self.Token) + ' ' + \ 210 repr(self.Referenced) + ' ' + \ 211 repr(self.StringValue) + ' ' + \ 212 repr(self.UseOtherLangDef) 213 214 def UpdateValue(self, Value = None): 215 if Value != None: 216 self.StringValue = Value + u'\x00' # Add a NULL at string tail 217 self.StringValueByteList = UniToHexList(self.StringValue) 218 self.Length = len(self.StringValueByteList) 219 220## UniFileClassObject 221# 222# A structure for .uni file definition 223# 224class UniFileClassObject(object): 225 def __init__(self, FileList = [], IsCompatibleMode = False, IncludePathList = []): 226 self.FileList = FileList 227 self.Token = 2 228 self.LanguageDef = [] #[ [u'LanguageIdentifier', u'PrintableName'], ... ] 229 self.OrderedStringList = {} #{ u'LanguageIdentifier' : [StringDefClassObject] } 230 self.OrderedStringDict = {} #{ u'LanguageIdentifier' : {StringName:(IndexInList)} } 231 self.OrderedStringListByToken = {} #{ u'LanguageIdentifier' : {Token: StringDefClassObject} } 232 self.IsCompatibleMode = IsCompatibleMode 233 self.IncludePathList = IncludePathList 234 if len(self.FileList) > 0: 235 self.LoadUniFiles(FileList) 236 237 # 238 # Get Language definition 239 # 240 def GetLangDef(self, File, Line): 241 Lang = distutils.util.split_quoted((Line.split(u"//")[0])) 242 if len(Lang) != 3: 243 try: 244 FileIn = self.OpenUniFile(LongFilePath(File.Path)) 245 except UnicodeError, X: 246 EdkLogger.error("build", FILE_READ_FAILURE, "File read failure: %s" % str(X), ExtraData=File); 247 except: 248 EdkLogger.error("build", FILE_OPEN_FAILURE, ExtraData=File); 249 LineNo = GetLineNo(FileIn, Line, False) 250 EdkLogger.error("Unicode File Parser", PARSER_ERROR, "Wrong language definition", 251 ExtraData="""%s\n\t*Correct format is like '#langdef en-US "English"'""" % Line, File=File, Line=LineNo) 252 else: 253 LangName = GetLanguageCode(Lang[1], self.IsCompatibleMode, self.File) 254 LangPrintName = Lang[2] 255 256 IsLangInDef = False 257 for Item in self.LanguageDef: 258 if Item[0] == LangName: 259 IsLangInDef = True 260 break; 261 262 if not IsLangInDef: 263 self.LanguageDef.append([LangName, LangPrintName]) 264 265 # 266 # Add language string 267 # 268 self.AddStringToList(u'$LANGUAGE_NAME', LangName, LangName, 0, True, Index=0) 269 self.AddStringToList(u'$PRINTABLE_LANGUAGE_NAME', LangName, LangPrintName, 1, True, Index=1) 270 271 if not IsLangInDef: 272 # 273 # The found STRING tokens will be added into new language string list 274 # so that the unique STRING identifier is reserved for all languages in the package list. 275 # 276 FirstLangName = self.LanguageDef[0][0] 277 if LangName != FirstLangName: 278 for Index in range (2, len (self.OrderedStringList[FirstLangName])): 279 Item = self.OrderedStringList[FirstLangName][Index] 280 if Item.UseOtherLangDef != '': 281 OtherLang = Item.UseOtherLangDef 282 else: 283 OtherLang = FirstLangName 284 self.OrderedStringList[LangName].append (StringDefClassObject(Item.StringName, '', Item.Referenced, Item.Token, OtherLang)) 285 self.OrderedStringDict[LangName][Item.StringName] = len(self.OrderedStringList[LangName]) - 1 286 return True 287 288 def OpenUniFile(self, FileName): 289 # 290 # Read file 291 # 292 try: 293 UniFile = open(FileName, mode='rb') 294 FileIn = UniFile.read() 295 UniFile.close() 296 except: 297 EdkLogger.Error("build", FILE_OPEN_FAILURE, ExtraData=File) 298 299 # 300 # Detect Byte Order Mark at beginning of file. Default to UTF-8 301 # 302 Encoding = 'utf-8' 303 if (FileIn.startswith(codecs.BOM_UTF16_BE) or 304 FileIn.startswith(codecs.BOM_UTF16_LE)): 305 Encoding = 'utf-16' 306 307 self.VerifyUcs2Data(FileIn, FileName, Encoding) 308 309 UniFile = StringIO.StringIO(FileIn) 310 Info = codecs.lookup(Encoding) 311 (Reader, Writer) = (Info.streamreader, Info.streamwriter) 312 return codecs.StreamReaderWriter(UniFile, Reader, Writer) 313 314 def VerifyUcs2Data(self, FileIn, FileName, Encoding): 315 Ucs2Info = codecs.lookup('ucs-2') 316 # 317 # Convert to unicode 318 # 319 try: 320 FileDecoded = codecs.decode(FileIn, Encoding) 321 Ucs2Info.encode(FileDecoded) 322 except: 323 UniFile = StringIO.StringIO(FileIn) 324 Info = codecs.lookup(Encoding) 325 (Reader, Writer) = (Info.streamreader, Info.streamwriter) 326 File = codecs.StreamReaderWriter(UniFile, Reader, Writer) 327 LineNumber = 0 328 ErrMsg = lambda Encoding, LineNumber: \ 329 '%s contains invalid %s characters on line %d.' % \ 330 (FileName, Encoding, LineNumber) 331 while True: 332 LineNumber = LineNumber + 1 333 try: 334 Line = File.readline() 335 if Line == '': 336 EdkLogger.error('Unicode File Parser', PARSER_ERROR, 337 ErrMsg(Encoding, LineNumber)) 338 Ucs2Info.encode(Line) 339 except: 340 EdkLogger.error('Unicode File Parser', PARSER_ERROR, 341 ErrMsg('UCS-2', LineNumber)) 342 343 # 344 # Get String name and value 345 # 346 def GetStringObject(self, Item): 347 Language = '' 348 Value = '' 349 350 Name = Item.split()[1] 351 # Check the string name is the upper character 352 if Name != '': 353 MatchString = re.match('[A-Z0-9_]+', Name, re.UNICODE) 354 if MatchString == None or MatchString.end(0) != len(Name): 355 EdkLogger.error('Unicode File Parser', FORMAT_INVALID, 'The string token name %s defined in UNI file %s contains the invalid lower case character.' % (Name, self.File)) 356 LanguageList = Item.split(u'#language ') 357 for IndexI in range(len(LanguageList)): 358 if IndexI == 0: 359 continue 360 else: 361 Language = LanguageList[IndexI].split()[0] 362 Value = LanguageList[IndexI][LanguageList[IndexI].find(u'\"') + len(u'\"') : LanguageList[IndexI].rfind(u'\"')] #.replace(u'\r\n', u'') 363 Language = GetLanguageCode(Language, self.IsCompatibleMode, self.File) 364 self.AddStringToList(Name, Language, Value) 365 366 # 367 # Get include file list and load them 368 # 369 def GetIncludeFile(self, Item, Dir): 370 FileName = Item[Item.find(u'#include ') + len(u'#include ') :Item.find(u' ', len(u'#include '))][1:-1] 371 self.LoadUniFile(FileName) 372 373 def StripComments(self, Line): 374 Comment = u'//' 375 CommentPos = Line.find(Comment) 376 while CommentPos >= 0: 377 # if there are non matched quotes before the comment header 378 # then we are in the middle of a string 379 # but we need to ignore the escaped quotes and backslashes. 380 if ((Line.count(u'"', 0, CommentPos) - Line.count(u'\\"', 0, CommentPos)) & 1) == 1: 381 CommentPos = Line.find (Comment, CommentPos + 1) 382 else: 383 return Line[:CommentPos].strip() 384 return Line.strip() 385 386 387 # 388 # Pre-process before parse .uni file 389 # 390 def PreProcess(self, File): 391 if not os.path.exists(File.Path) or not os.path.isfile(File.Path): 392 EdkLogger.error("Unicode File Parser", FILE_NOT_FOUND, ExtraData=File.Path) 393 394 try: 395 FileIn = self.OpenUniFile(LongFilePath(File.Path)) 396 except UnicodeError, X: 397 EdkLogger.error("build", FILE_READ_FAILURE, "File read failure: %s" % str(X), ExtraData=File.Path); 398 except: 399 EdkLogger.error("build", FILE_OPEN_FAILURE, ExtraData=File.Path); 400 401 Lines = [] 402 # 403 # Use unique identifier 404 # 405 for Line in FileIn: 406 Line = Line.strip() 407 Line = Line.replace(u'\\\\', BACK_SLASH_PLACEHOLDER) 408 Line = self.StripComments(Line) 409 410 # 411 # Ignore empty line 412 # 413 if len(Line) == 0: 414 continue 415 416 417 Line = Line.replace(u'/langdef', u'#langdef') 418 Line = Line.replace(u'/string', u'#string') 419 Line = Line.replace(u'/language', u'#language') 420 Line = Line.replace(u'/include', u'#include') 421 422 Line = Line.replace(UNICODE_WIDE_CHAR, WIDE_CHAR) 423 Line = Line.replace(UNICODE_NARROW_CHAR, NARROW_CHAR) 424 Line = Line.replace(UNICODE_NON_BREAKING_CHAR, NON_BREAKING_CHAR) 425 426 Line = Line.replace(u'\\r\\n', CR + LF) 427 Line = Line.replace(u'\\n', CR + LF) 428 Line = Line.replace(u'\\r', CR) 429 Line = Line.replace(u'\\t', u' ') 430 Line = Line.replace(u'\t', u' ') 431 Line = Line.replace(u'\\"', u'"') 432 Line = Line.replace(u"\\'", u"'") 433 Line = Line.replace(BACK_SLASH_PLACEHOLDER, u'\\') 434 435# if Line.find(u'\\x'): 436# hex = Line[Line.find(u'\\x') + 2 : Line.find(u'\\x') + 6] 437# hex = "u'\\u" + hex + "'" 438 439 IncList = gIncludePattern.findall(Line) 440 if len(IncList) == 1: 441 for Dir in [File.Dir] + self.IncludePathList: 442 IncFile = PathClass(str(IncList[0]), Dir) 443 if os.path.isfile(IncFile.Path): 444 Lines.extend(self.PreProcess(IncFile)) 445 break 446 else: 447 EdkLogger.error("Unicode File Parser", FILE_NOT_FOUND, Message="Cannot find include file", ExtraData=str(IncList[0])) 448 continue 449 450 Lines.append(Line) 451 452 return Lines 453 454 # 455 # Load a .uni file 456 # 457 def LoadUniFile(self, File = None): 458 if File == None: 459 EdkLogger.error("Unicode File Parser", PARSER_ERROR, 'No unicode file is given') 460 self.File = File 461 # 462 # Process special char in file 463 # 464 Lines = self.PreProcess(File) 465 466 # 467 # Get Unicode Information 468 # 469 for IndexI in range(len(Lines)): 470 Line = Lines[IndexI] 471 if (IndexI + 1) < len(Lines): 472 SecondLine = Lines[IndexI + 1] 473 if (IndexI + 2) < len(Lines): 474 ThirdLine = Lines[IndexI + 2] 475 476 # 477 # Get Language def information 478 # 479 if Line.find(u'#langdef ') >= 0: 480 self.GetLangDef(File, Line) 481 continue 482 483 Name = '' 484 Language = '' 485 Value = '' 486 # 487 # Get string def information format 1 as below 488 # 489 # #string MY_STRING_1 490 # #language eng 491 # My first English string line 1 492 # My first English string line 2 493 # #string MY_STRING_1 494 # #language spa 495 # Mi segunda secuencia 1 496 # Mi segunda secuencia 2 497 # 498 if Line.find(u'#string ') >= 0 and Line.find(u'#language ') < 0 and \ 499 SecondLine.find(u'#string ') < 0 and SecondLine.find(u'#language ') >= 0 and \ 500 ThirdLine.find(u'#string ') < 0 and ThirdLine.find(u'#language ') < 0: 501 Name = Line[Line.find(u'#string ') + len(u'#string ') : ].strip(' ') 502 Language = SecondLine[SecondLine.find(u'#language ') + len(u'#language ') : ].strip(' ') 503 for IndexJ in range(IndexI + 2, len(Lines)): 504 if Lines[IndexJ].find(u'#string ') < 0 and Lines[IndexJ].find(u'#language ') < 0: 505 Value = Value + Lines[IndexJ] 506 else: 507 IndexI = IndexJ 508 break 509 # Value = Value.replace(u'\r\n', u'') 510 Language = GetLanguageCode(Language, self.IsCompatibleMode, self.File) 511 # Check the string name is the upper character 512 if not self.IsCompatibleMode and Name != '': 513 MatchString = re.match('[A-Z0-9_]+', Name, re.UNICODE) 514 if MatchString == None or MatchString.end(0) != len(Name): 515 EdkLogger.error('Unicode File Parser', FORMAT_INVALID, 'The string token name %s defined in UNI file %s contains the invalid lower case character.' % (Name, self.File)) 516 self.AddStringToList(Name, Language, Value) 517 continue 518 519 # 520 # Get string def information format 2 as below 521 # 522 # #string MY_STRING_1 #language eng "My first English string line 1" 523 # "My first English string line 2" 524 # #language spa "Mi segunda secuencia 1" 525 # "Mi segunda secuencia 2" 526 # #string MY_STRING_2 #language eng "My first English string line 1" 527 # "My first English string line 2" 528 # #string MY_STRING_2 #language spa "Mi segunda secuencia 1" 529 # "Mi segunda secuencia 2" 530 # 531 if Line.find(u'#string ') >= 0 and Line.find(u'#language ') >= 0: 532 StringItem = Line 533 for IndexJ in range(IndexI + 1, len(Lines)): 534 if Lines[IndexJ].find(u'#string ') >= 0 and Lines[IndexJ].find(u'#language ') >= 0: 535 IndexI = IndexJ 536 break 537 elif Lines[IndexJ].find(u'#string ') < 0 and Lines[IndexJ].find(u'#language ') >= 0: 538 StringItem = StringItem + Lines[IndexJ] 539 elif Lines[IndexJ].count(u'\"') >= 2: 540 StringItem = StringItem[ : StringItem.rfind(u'\"')] + Lines[IndexJ][Lines[IndexJ].find(u'\"') + len(u'\"') : ] 541 self.GetStringObject(StringItem) 542 continue 543 544 # 545 # Load multiple .uni files 546 # 547 def LoadUniFiles(self, FileList): 548 if len(FileList) > 0: 549 for File in FileList: 550 self.LoadUniFile(File) 551 552 # 553 # Add a string to list 554 # 555 def AddStringToList(self, Name, Language, Value, Token = None, Referenced = False, UseOtherLangDef = '', Index = -1): 556 for LangNameItem in self.LanguageDef: 557 if Language == LangNameItem[0]: 558 break 559 else: 560 EdkLogger.error('Unicode File Parser', FORMAT_NOT_SUPPORTED, "The language '%s' for %s is not defined in Unicode file %s." \ 561 % (Language, Name, self.File)) 562 563 if Language not in self.OrderedStringList: 564 self.OrderedStringList[Language] = [] 565 self.OrderedStringDict[Language] = {} 566 567 IsAdded = True 568 if Name in self.OrderedStringDict[Language]: 569 IsAdded = False 570 if Value != None: 571 ItemIndexInList = self.OrderedStringDict[Language][Name] 572 Item = self.OrderedStringList[Language][ItemIndexInList] 573 Item.UpdateValue(Value) 574 Item.UseOtherLangDef = '' 575 576 if IsAdded: 577 Token = len(self.OrderedStringList[Language]) 578 if Index == -1: 579 self.OrderedStringList[Language].append(StringDefClassObject(Name, Value, Referenced, Token, UseOtherLangDef)) 580 self.OrderedStringDict[Language][Name] = Token 581 for LangName in self.LanguageDef: 582 # 583 # New STRING token will be added into all language string lists. 584 # so that the unique STRING identifier is reserved for all languages in the package list. 585 # 586 if LangName[0] != Language: 587 if UseOtherLangDef != '': 588 OtherLangDef = UseOtherLangDef 589 else: 590 OtherLangDef = Language 591 self.OrderedStringList[LangName[0]].append(StringDefClassObject(Name, '', Referenced, Token, OtherLangDef)) 592 self.OrderedStringDict[LangName[0]][Name] = len(self.OrderedStringList[LangName[0]]) - 1 593 else: 594 self.OrderedStringList[Language].insert(Index, StringDefClassObject(Name, Value, Referenced, Token, UseOtherLangDef)) 595 self.OrderedStringDict[Language][Name] = Index 596 597 # 598 # Set the string as referenced 599 # 600 def SetStringReferenced(self, Name): 601 # 602 # String stoken are added in the same order in all language string lists. 603 # So, only update the status of string stoken in first language string list. 604 # 605 Lang = self.LanguageDef[0][0] 606 if Name in self.OrderedStringDict[Lang]: 607 ItemIndexInList = self.OrderedStringDict[Lang][Name] 608 Item = self.OrderedStringList[Lang][ItemIndexInList] 609 Item.Referenced = True 610 611 # 612 # Search the string in language definition by Name 613 # 614 def FindStringValue(self, Name, Lang): 615 if Name in self.OrderedStringDict[Lang]: 616 ItemIndexInList = self.OrderedStringDict[Lang][Name] 617 return self.OrderedStringList[Lang][ItemIndexInList] 618 619 return None 620 621 # 622 # Search the string in language definition by Token 623 # 624 def FindByToken(self, Token, Lang): 625 for Item in self.OrderedStringList[Lang]: 626 if Item.Token == Token: 627 return Item 628 629 return None 630 631 # 632 # Re-order strings and re-generate tokens 633 # 634 def ReToken(self): 635 # 636 # Retoken all language strings according to the status of string stoken in the first language string. 637 # 638 FirstLangName = self.LanguageDef[0][0] 639 640 # Convert the OrderedStringList to be OrderedStringListByToken in order to faciliate future search by token 641 for LangNameItem in self.LanguageDef: 642 self.OrderedStringListByToken[LangNameItem[0]] = {} 643 644 # 645 # Use small token for all referred string stoken. 646 # 647 RefToken = 0 648 for Index in range (0, len (self.OrderedStringList[FirstLangName])): 649 FirstLangItem = self.OrderedStringList[FirstLangName][Index] 650 if FirstLangItem.Referenced == True: 651 for LangNameItem in self.LanguageDef: 652 LangName = LangNameItem[0] 653 OtherLangItem = self.OrderedStringList[LangName][Index] 654 OtherLangItem.Referenced = True 655 OtherLangItem.Token = RefToken 656 self.OrderedStringListByToken[LangName][OtherLangItem.Token] = OtherLangItem 657 RefToken = RefToken + 1 658 659 # 660 # Use big token for all unreferred string stoken. 661 # 662 UnRefToken = 0 663 for Index in range (0, len (self.OrderedStringList[FirstLangName])): 664 FirstLangItem = self.OrderedStringList[FirstLangName][Index] 665 if FirstLangItem.Referenced == False: 666 for LangNameItem in self.LanguageDef: 667 LangName = LangNameItem[0] 668 OtherLangItem = self.OrderedStringList[LangName][Index] 669 OtherLangItem.Token = RefToken + UnRefToken 670 self.OrderedStringListByToken[LangName][OtherLangItem.Token] = OtherLangItem 671 UnRefToken = UnRefToken + 1 672 673 # 674 # Show the instance itself 675 # 676 def ShowMe(self): 677 print self.LanguageDef 678 #print self.OrderedStringList 679 for Item in self.OrderedStringList: 680 print Item 681 for Member in self.OrderedStringList[Item]: 682 print str(Member) 683 684# This acts like the main() function for the script, unless it is 'import'ed into another 685# script. 686if __name__ == '__main__': 687 EdkLogger.Initialize() 688 EdkLogger.SetLevel(EdkLogger.DEBUG_0) 689 a = UniFileClassObject([PathClass("C:\\Edk\\Strings.uni"), PathClass("C:\\Edk\\Strings2.uni")]) 690 a.ReToken() 691 a.ShowMe() 692