]> git.proxmox.com Git - mirror_edk2.git/blame - BaseTools/Source/Python/UPT/Library/Misc.py
This patch is going to:
[mirror_edk2.git] / BaseTools / Source / Python / UPT / Library / Misc.py
CommitLineData
f51461c8
LG
1## @file\r
2# Common routines used by all tools\r
3#\r
421ccda3 4# Copyright (c) 2011 - 2014, Intel Corporation. All rights reserved.<BR>\r
f51461c8
LG
5#\r
6# This program and the accompanying materials are licensed and made available \r
7# under the terms and conditions of the BSD License which accompanies this \r
8# distribution. The full text of the license may be found at \r
9# http://opensource.org/licenses/bsd-license.php\r
10#\r
11# THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,\r
12# WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.\r
13#\r
14\r
15'''\r
16Misc\r
17'''\r
18\r
19##\r
20# Import Modules\r
21#\r
22import os.path\r
23from os import access\r
24from os import F_OK\r
25from os import makedirs\r
26from os import getcwd\r
27from os import chdir\r
28from os import listdir\r
29from os import remove\r
30from os import rmdir\r
31from os import linesep\r
32from os import walk\r
33from os import environ\r
34import re\r
35from UserDict import IterableUserDict\r
36\r
37import Logger.Log as Logger\r
38from Logger import StringTable as ST\r
39from Logger import ToolError\r
40from Library import GlobalData\r
41from Library.DataType import SUP_MODULE_LIST\r
42from Library.DataType import END_OF_LINE\r
43from Library.DataType import TAB_SPLIT\r
421ccda3
HC
44from Library.DataType import TAB_LANGUAGE_EN_US\r
45from Library.DataType import TAB_LANGUAGE_EN\r
46from Library.DataType import TAB_LANGUAGE_EN_X\r
47from Library.DataType import TAB_UNI_FILE_SUFFIXS\r
f51461c8
LG
48from Library.String import GetSplitValueList\r
49from Library.ParserValidate import IsValidHexVersion\r
50from Library.ParserValidate import IsValidPath\r
51from Object.POM.CommonObject import TextObject\r
421ccda3 52from Core.FileHook import __FileHookOpen__\r
f51461c8
LG
53\r
54## Convert GUID string in xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx style to C \r
55# structure style\r
56#\r
57# @param Guid: The GUID string\r
58#\r
59def GuidStringToGuidStructureString(Guid):\r
60 GuidList = Guid.split('-')\r
61 Result = '{'\r
62 for Index in range(0, 3, 1):\r
63 Result = Result + '0x' + GuidList[Index] + ', '\r
64 Result = Result + '{0x' + GuidList[3][0:2] + ', 0x' + GuidList[3][2:4]\r
65 for Index in range(0, 12, 2):\r
66 Result = Result + ', 0x' + GuidList[4][Index:Index + 2]\r
67 Result += '}}'\r
68 return Result\r
69\r
70## Check whether GUID string is of format xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx\r
71#\r
72# @param GuidValue: The GUID value\r
73#\r
74def CheckGuidRegFormat(GuidValue):\r
75 ## Regular expression used to find out register format of GUID\r
76 #\r
77 RegFormatGuidPattern = re.compile("^\s*([0-9a-fA-F]){8}-"\r
78 "([0-9a-fA-F]){4}-"\r
79 "([0-9a-fA-F]){4}-"\r
80 "([0-9a-fA-F]){4}-"\r
81 "([0-9a-fA-F]){12}\s*$")\r
82\r
83 if RegFormatGuidPattern.match(GuidValue):\r
84 return True\r
85 else:\r
86 return False\r
87\r
88\r
89## Convert GUID string in C structure style to \r
90# xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx\r
91#\r
92# @param GuidValue: The GUID value in C structure format\r
93#\r
94def GuidStructureStringToGuidString(GuidValue):\r
95 GuidValueString = GuidValue.lower().replace("{", "").replace("}", "").\\r
96 replace(" ", "").replace(";", "")\r
97 GuidValueList = GuidValueString.split(",")\r
98 if len(GuidValueList) != 11:\r
99 return ''\r
100 try:\r
101 return "%08x-%04x-%04x-%02x%02x-%02x%02x%02x%02x%02x%02x" % (\r
102 int(GuidValueList[0], 16),\r
103 int(GuidValueList[1], 16),\r
104 int(GuidValueList[2], 16),\r
105 int(GuidValueList[3], 16),\r
106 int(GuidValueList[4], 16),\r
107 int(GuidValueList[5], 16),\r
108 int(GuidValueList[6], 16),\r
109 int(GuidValueList[7], 16),\r
110 int(GuidValueList[8], 16),\r
111 int(GuidValueList[9], 16),\r
112 int(GuidValueList[10], 16)\r
113 )\r
114 except BaseException:\r
115 return ''\r
116\r
117## Create directories\r
118#\r
119# @param Directory: The directory name\r
120#\r
121def CreateDirectory(Directory):\r
122 if Directory == None or Directory.strip() == "":\r
123 return True\r
124 try:\r
125 if not access(Directory, F_OK):\r
126 makedirs(Directory)\r
127 except BaseException:\r
128 return False\r
129 return True\r
130\r
131## Remove directories, including files and sub-directories in it\r
132#\r
133# @param Directory: The directory name\r
134#\r
135def RemoveDirectory(Directory, Recursively=False):\r
136 if Directory == None or Directory.strip() == "" or not \\r
137 os.path.exists(Directory):\r
138 return\r
139 if Recursively:\r
140 CurrentDirectory = getcwd()\r
141 chdir(Directory)\r
142 for File in listdir("."):\r
143 if os.path.isdir(File):\r
144 RemoveDirectory(File, Recursively)\r
145 else:\r
146 remove(File)\r
147 chdir(CurrentDirectory)\r
148 rmdir(Directory)\r
149\r
150## Store content in file\r
151#\r
152# This method is used to save file only when its content is changed. This is\r
153# quite useful for "make" system to decide what will be re-built and what \r
154# won't.\r
155#\r
156# @param File: The path of file\r
157# @param Content: The new content of the file\r
158# @param IsBinaryFile: The flag indicating if the file is binary file \r
159# or not\r
160#\r
161def SaveFileOnChange(File, Content, IsBinaryFile=True):\r
162 if not IsBinaryFile:\r
163 Content = Content.replace("\n", linesep)\r
164\r
165 if os.path.exists(File):\r
166 try:\r
421ccda3 167 if Content == __FileHookOpen__(File, "rb").read():\r
f51461c8
LG
168 return False\r
169 except BaseException:\r
170 Logger.Error(None, ToolError.FILE_OPEN_FAILURE, ExtraData=File)\r
171\r
172 CreateDirectory(os.path.dirname(File))\r
173 try:\r
421ccda3 174 FileFd = __FileHookOpen__(File, "wb")\r
f51461c8
LG
175 FileFd.write(Content)\r
176 FileFd.close()\r
177 except BaseException:\r
178 Logger.Error(None, ToolError.FILE_CREATE_FAILURE, ExtraData=File)\r
179\r
180 return True\r
181\r
182## Get all files of a directory\r
183#\r
184# @param Root: Root dir\r
185# @param SkipList : The files need be skipped\r
186#\r
187def GetFiles(Root, SkipList=None, FullPath=True):\r
188 OriPath = os.path.normpath(Root)\r
189 FileList = []\r
190 for Root, Dirs, Files in walk(Root):\r
191 if SkipList:\r
192 for Item in SkipList:\r
193 if Item in Dirs:\r
194 Dirs.remove(Item)\r
421ccda3
HC
195 if Item in Files:\r
196 Files.remove(Item)\r
f51461c8
LG
197 for Dir in Dirs:\r
198 if Dir.startswith('.'):\r
199 Dirs.remove(Dir)\r
200\r
201 for File in Files:\r
202 if File.startswith('.'):\r
203 continue\r
204 File = os.path.normpath(os.path.join(Root, File))\r
205 if not FullPath:\r
206 File = File[len(OriPath) + 1:]\r
207 FileList.append(File)\r
208\r
209 return FileList\r
210\r
211## Get all non-metadata files of a directory\r
212#\r
213# @param Root: Root Dir\r
214# @param SkipList : List of path need be skipped\r
215# @param FullPath: True if the returned file should be full path\r
216# @param PrefixPath: the path that need to be added to the files found\r
217# @return: the list of files found\r
218# \r
219def GetNonMetaDataFiles(Root, SkipList, FullPath, PrefixPath):\r
220 FileList = GetFiles(Root, SkipList, FullPath)\r
221 NewFileList = []\r
222 for File in FileList:\r
223 ExtName = os.path.splitext(File)[1]\r
224 #\r
225 # skip '.dec', '.inf', '.dsc', '.fdf' files\r
226 #\r
227 if ExtName.lower() not in ['.dec', '.inf', '.dsc', '.fdf']:\r
228 NewFileList.append(os.path.normpath(os.path.join(PrefixPath, File)))\r
229\r
230 return NewFileList\r
231\r
232## Check if given file exists or not\r
233#\r
234# @param File: File name or path to be checked\r
235# @param Dir: The directory the file is relative to\r
236#\r
237def ValidFile(File, Ext=None):\r
238 File = File.replace('\\', '/')\r
239 if Ext != None:\r
240 FileExt = os.path.splitext(File)[1]\r
241 if FileExt.lower() != Ext.lower():\r
242 return False\r
243 if not os.path.exists(File):\r
244 return False\r
245 return True\r
246\r
247## RealPath\r
248#\r
249# @param File: File name or path to be checked\r
250# @param Dir: The directory the file is relative to\r
251# @param OverrideDir: The override directory\r
252#\r
253def RealPath(File, Dir='', OverrideDir=''):\r
254 NewFile = os.path.normpath(os.path.join(Dir, File))\r
255 NewFile = GlobalData.gALL_FILES[NewFile]\r
256 if not NewFile and OverrideDir:\r
257 NewFile = os.path.normpath(os.path.join(OverrideDir, File))\r
258 NewFile = GlobalData.gALL_FILES[NewFile]\r
259 return NewFile\r
260\r
261## RealPath2\r
262#\r
263# @param File: File name or path to be checked\r
264# @param Dir: The directory the file is relative to\r
265# @param OverrideDir: The override directory\r
266#\r
267def RealPath2(File, Dir='', OverrideDir=''):\r
268 if OverrideDir:\r
269 NewFile = GlobalData.gALL_FILES[os.path.normpath(os.path.join\\r
270 (OverrideDir, File))]\r
271 if NewFile:\r
272 if OverrideDir[-1] == os.path.sep:\r
273 return NewFile[len(OverrideDir):], NewFile[0:len(OverrideDir)]\r
274 else:\r
275 return NewFile[len(OverrideDir) + 1:], \\r
276 NewFile[0:len(OverrideDir)]\r
277\r
278 NewFile = GlobalData.gALL_FILES[os.path.normpath(os.path.join(Dir, File))]\r
279 if NewFile:\r
280 if Dir:\r
281 if Dir[-1] == os.path.sep:\r
282 return NewFile[len(Dir):], NewFile[0:len(Dir)]\r
283 else:\r
284 return NewFile[len(Dir) + 1:], NewFile[0:len(Dir)]\r
285 else:\r
286 return NewFile, ''\r
287\r
288 return None, None\r
289\r
290## A dict which can access its keys and/or values orderly\r
291#\r
292# The class implements a new kind of dict which its keys or values can be\r
293# accessed in the order they are added into the dict. It guarantees the order\r
294# by making use of an internal list to keep a copy of keys.\r
295#\r
296class Sdict(IterableUserDict):\r
297 ## Constructor\r
298 #\r
299 def __init__(self):\r
300 IterableUserDict.__init__(self)\r
301 self._key_list = []\r
302\r
303 ## [] operator\r
304 #\r
305 def __setitem__(self, Key, Value):\r
306 if Key not in self._key_list:\r
307 self._key_list.append(Key)\r
308 IterableUserDict.__setitem__(self, Key, Value)\r
309\r
310 ## del operator\r
311 #\r
312 def __delitem__(self, Key):\r
313 self._key_list.remove(Key)\r
314 IterableUserDict.__delitem__(self, Key)\r
315\r
316 ## used in "for k in dict" loop to ensure the correct order\r
317 #\r
318 def __iter__(self):\r
319 return self.iterkeys()\r
320\r
321 ## len() support\r
322 #\r
323 def __len__(self):\r
324 return len(self._key_list)\r
325\r
326 ## "in" test support\r
327 #\r
328 def __contains__(self, Key):\r
329 return Key in self._key_list\r
330\r
331 ## indexof support\r
332 #\r
333 def index(self, Key):\r
334 return self._key_list.index(Key)\r
335\r
336 ## insert support\r
337 #\r
338 def insert(self, Key, Newkey, Newvalue, Order):\r
339 Index = self._key_list.index(Key)\r
340 if Order == 'BEFORE':\r
341 self._key_list.insert(Index, Newkey)\r
342 IterableUserDict.__setitem__(self, Newkey, Newvalue)\r
343 elif Order == 'AFTER':\r
344 self._key_list.insert(Index + 1, Newkey)\r
345 IterableUserDict.__setitem__(self, Newkey, Newvalue)\r
346\r
347 ## append support\r
348 #\r
349 def append(self, Sdict2):\r
350 for Key in Sdict2:\r
351 if Key not in self._key_list:\r
352 self._key_list.append(Key)\r
353 IterableUserDict.__setitem__(self, Key, Sdict2[Key])\r
354 ## hash key\r
355 #\r
356 def has_key(self, Key):\r
357 return Key in self._key_list\r
358\r
359 ## Empty the dict\r
360 #\r
361 def clear(self):\r
362 self._key_list = []\r
363 IterableUserDict.clear(self)\r
364\r
365 ## Return a copy of keys\r
366 #\r
367 def keys(self):\r
368 Keys = []\r
369 for Key in self._key_list:\r
370 Keys.append(Key)\r
371 return Keys\r
372\r
373 ## Return a copy of values\r
374 #\r
375 def values(self):\r
376 Values = []\r
377 for Key in self._key_list:\r
378 Values.append(self[Key])\r
379 return Values\r
380\r
381 ## Return a copy of (key, value) list\r
382 #\r
383 def items(self):\r
384 Items = []\r
385 for Key in self._key_list:\r
386 Items.append((Key, self[Key]))\r
387 return Items\r
388\r
389 ## Iteration support\r
390 #\r
391 def iteritems(self):\r
392 return iter(self.items())\r
393\r
394 ## Keys interation support\r
395 #\r
396 def iterkeys(self):\r
397 return iter(self.keys())\r
398\r
399 ## Values interation support\r
400 #\r
401 def itervalues(self):\r
402 return iter(self.values())\r
403\r
404 ## Return value related to a key, and remove the (key, value) from the dict\r
405 #\r
406 def pop(self, Key, *Dv):\r
407 Value = None\r
408 if Key in self._key_list:\r
409 Value = self[Key]\r
410 self.__delitem__(Key)\r
411 elif len(Dv) != 0 :\r
412 Value = Dv[0]\r
413 return Value\r
414\r
415 ## Return (key, value) pair, and remove the (key, value) from the dict\r
416 #\r
417 def popitem(self):\r
418 Key = self._key_list[-1]\r
419 Value = self[Key]\r
420 self.__delitem__(Key)\r
421 return Key, Value\r
422 ## update method\r
423 #\r
424 def update(self, Dict=None, **Kwargs):\r
425 if Dict != None:\r
426 for Key1, Val1 in Dict.items():\r
427 self[Key1] = Val1\r
428 if len(Kwargs):\r
429 for Key1, Val1 in Kwargs.items():\r
430 self[Key1] = Val1\r
431\r
432## CommonPath\r
433#\r
434# @param PathList: PathList\r
435#\r
436def CommonPath(PathList):\r
437 Path1 = min(PathList).split(os.path.sep)\r
438 Path2 = max(PathList).split(os.path.sep)\r
439 for Index in xrange(min(len(Path1), len(Path2))):\r
440 if Path1[Index] != Path2[Index]:\r
441 return os.path.sep.join(Path1[:Index])\r
442 return os.path.sep.join(Path1)\r
443\r
444## PathClass\r
445#\r
446class PathClass(object):\r
447 def __init__(self, File='', Root='', AlterRoot='', Type='', IsBinary=False,\r
448 Arch='COMMON', ToolChainFamily='', Target='', TagName='', \\r
449 ToolCode=''):\r
450 self.Arch = Arch\r
451 self.File = str(File)\r
452 if os.path.isabs(self.File):\r
453 self.Root = ''\r
454 self.AlterRoot = ''\r
455 else:\r
456 self.Root = str(Root)\r
457 self.AlterRoot = str(AlterRoot)\r
458\r
459 #\r
460 # Remove any '.' and '..' in path\r
461 #\r
462 if self.Root:\r
463 self.Path = os.path.normpath(os.path.join(self.Root, self.File))\r
464 self.Root = os.path.normpath(CommonPath([self.Root, self.Path]))\r
465 #\r
466 # eliminate the side-effect of 'C:'\r
467 #\r
468 if self.Root[-1] == ':':\r
469 self.Root += os.path.sep\r
470 #\r
471 # file path should not start with path separator\r
472 #\r
473 if self.Root[-1] == os.path.sep:\r
474 self.File = self.Path[len(self.Root):]\r
475 else:\r
476 self.File = self.Path[len(self.Root) + 1:]\r
477 else:\r
478 self.Path = os.path.normpath(self.File)\r
479\r
480 self.SubDir, self.Name = os.path.split(self.File)\r
481 self.BaseName, self.Ext = os.path.splitext(self.Name)\r
482\r
483 if self.Root:\r
484 if self.SubDir:\r
485 self.Dir = os.path.join(self.Root, self.SubDir)\r
486 else:\r
487 self.Dir = self.Root\r
488 else:\r
489 self.Dir = self.SubDir\r
490\r
491 if IsBinary:\r
492 self.Type = Type\r
493 else:\r
494 self.Type = self.Ext.lower()\r
495\r
496 self.IsBinary = IsBinary\r
497 self.Target = Target\r
498 self.TagName = TagName\r
499 self.ToolCode = ToolCode\r
500 self.ToolChainFamily = ToolChainFamily\r
501\r
502 self._Key = None\r
503\r
504 ## Convert the object of this class to a string\r
505 #\r
506 # Convert member Path of the class to a string\r
507 #\r
508 def __str__(self):\r
509 return self.Path\r
510\r
511 ## Override __eq__ function\r
512 #\r
513 # Check whether PathClass are the same\r
514 #\r
515 def __eq__(self, Other):\r
516 if type(Other) == type(self):\r
517 return self.Path == Other.Path\r
518 else:\r
519 return self.Path == str(Other)\r
520\r
521 ## Override __hash__ function\r
522 #\r
523 # Use Path as key in hash table\r
524 #\r
525 def __hash__(self):\r
526 return hash(self.Path)\r
527\r
528 ## _GetFileKey\r
529 #\r
530 def _GetFileKey(self):\r
531 if self._Key == None:\r
532 self._Key = self.Path.upper()\r
533 return self._Key\r
534 ## Validate\r
535 #\r
536 def Validate(self, Type='', CaseSensitive=True):\r
537 if GlobalData.gCASE_INSENSITIVE:\r
538 CaseSensitive = False\r
539 if Type and Type.lower() != self.Type:\r
540 return ToolError.FILE_TYPE_MISMATCH, '%s (expect %s but got %s)' % \\r
541 (self.File, Type, self.Type)\r
542\r
543 RealFile, RealRoot = RealPath2(self.File, self.Root, self.AlterRoot)\r
544 if not RealRoot and not RealFile:\r
545 RealFile = self.File\r
546 if self.AlterRoot:\r
547 RealFile = os.path.join(self.AlterRoot, self.File)\r
548 elif self.Root:\r
549 RealFile = os.path.join(self.Root, self.File)\r
550 return ToolError.FILE_NOT_FOUND, os.path.join(self.AlterRoot, RealFile)\r
551\r
552 ErrorCode = 0\r
553 ErrorInfo = ''\r
554 if RealRoot != self.Root or RealFile != self.File:\r
555 if CaseSensitive and (RealFile != self.File or \\r
556 (RealRoot != self.Root and RealRoot != \\r
557 self.AlterRoot)):\r
558 ErrorCode = ToolError.FILE_CASE_MISMATCH\r
559 ErrorInfo = self.File + '\n\t' + RealFile + \\r
560 " [in file system]"\r
561\r
562 self.SubDir, self.Name = os.path.split(RealFile)\r
563 self.BaseName, self.Ext = os.path.splitext(self.Name)\r
564 if self.SubDir:\r
565 self.Dir = os.path.join(RealRoot, self.SubDir)\r
566 else:\r
567 self.Dir = RealRoot\r
568 self.File = RealFile\r
569 self.Root = RealRoot\r
570 self.Path = os.path.join(RealRoot, RealFile)\r
571 return ErrorCode, ErrorInfo\r
572\r
573 Key = property(_GetFileKey)\r
574\r
421ccda3 575## Get current workspace\r
f51461c8 576#\r
421ccda3 577# get WORKSPACE from environment variable if present,if not use current working directory as WORKSPACE\r
f51461c8 578#\r
421ccda3 579def GetWorkspace():\r
f51461c8
LG
580 #\r
581 # check WORKSPACE\r
582 #\r
421ccda3
HC
583 if "WORKSPACE" in environ:\r
584 WorkspaceDir = os.path.normpath(environ["WORKSPACE"])\r
585 if not os.path.exists(WorkspaceDir):\r
586 Logger.Error("UPT",\r
587 ToolError.UPT_ENVIRON_MISSING_ERROR,\r
588 ST.ERR_WORKSPACE_NOTEXIST,\r
589 ExtraData="%s" % WorkspaceDir)\r
590 else:\r
591 WorkspaceDir = os.getcwd()\r
f51461c8 592\r
421ccda3
HC
593 if WorkspaceDir[-1] == ':':\r
594 WorkspaceDir += os.sep\r
595 return WorkspaceDir\r
596\r
597## Get relative path\r
598#\r
599# use full path and workspace to get relative path\r
600# the destination of this function is mainly to resolve the root path issue(like c: or c:\) \r
601#\r
602# @param Fullpath: a string of fullpath\r
603# @param Workspace: a string of workspace\r
604#\r
605def GetRelativePath(Fullpath, Workspace):\r
606 \r
607 RelativePath = ''\r
608 if Workspace.endswith(os.sep):\r
609 RelativePath = Fullpath[Fullpath.upper().find(Workspace.upper())+len(Workspace):]\r
610 else:\r
611 RelativePath = Fullpath[Fullpath.upper().find(Workspace.upper())+len(Workspace)+1:]\r
612 \r
613 return RelativePath\r
614 \r
f51461c8
LG
615## Check whether all module types are in list\r
616#\r
617# check whether all module types (SUP_MODULE_LIST) are in list\r
618# \r
619# @param ModuleList: a list of ModuleType\r
620#\r
621def IsAllModuleList(ModuleList):\r
622 NewModuleList = [Module.upper() for Module in ModuleList]\r
623 for Module in SUP_MODULE_LIST:\r
624 if Module not in NewModuleList:\r
625 return False\r
626 else:\r
627 return True\r
628\r
629## Dictionary that use comment(GenericComment, TailComment) as value,\r
630# if a new comment which key already in the dic is inserted, then the \r
631# comment will be merged.\r
632# Key is (Statement, SupArch), when TailComment is added, it will ident \r
633# according to Statement\r
634#\r
635class MergeCommentDict(dict):\r
636 ## []= operator\r
637 #\r
638 def __setitem__(self, Key, CommentVal):\r
639 GenericComment, TailComment = CommentVal\r
640 if Key in self:\r
641 OrigVal1, OrigVal2 = dict.__getitem__(self, Key)\r
642 Statement = Key[0]\r
643 dict.__setitem__(self, Key, (OrigVal1 + GenericComment, OrigVal2 \\r
644 + len(Statement) * ' ' + TailComment))\r
645 else:\r
646 dict.__setitem__(self, Key, (GenericComment, TailComment))\r
647\r
648 ## =[] operator\r
649 #\r
650 def __getitem__(self, Key):\r
651 return dict.__getitem__(self, Key)\r
652\r
653\r
654## GenDummyHelpTextObj\r
655#\r
656# @retval HelpTxt: Generated dummy help text object\r
657#\r
658def GenDummyHelpTextObj():\r
659 HelpTxt = TextObject()\r
421ccda3 660 HelpTxt.SetLang(TAB_LANGUAGE_EN_US)\r
f51461c8
LG
661 HelpTxt.SetString(' ')\r
662 return HelpTxt\r
663\r
664## ConvertVersionToDecimal, the minor version should be within 0 - 99\r
665# <HexVersion> ::= "0x" <Major> <Minor>\r
666# <Major> ::= (a-fA-F0-9){4}\r
667# <Minor> ::= (a-fA-F0-9){4}\r
668# <DecVersion> ::= (0-65535) ["." (0-99)]\r
669# \r
670# @param StringIn: The string contains version defined in INF file.\r
671# It can be Decimal or Hex\r
672#\r
673def ConvertVersionToDecimal(StringIn):\r
674 if IsValidHexVersion(StringIn):\r
675 Value = int(StringIn, 16)\r
676 Major = Value >> 16\r
677 Minor = Value & 0xFFFF\r
678 MinorStr = str(Minor)\r
679 if len(MinorStr) == 1:\r
680 MinorStr = '0' + MinorStr\r
681 return str(Major) + '.' + MinorStr\r
682 else:\r
683 if StringIn.find(TAB_SPLIT) != -1:\r
684 return StringIn\r
685 elif StringIn:\r
686 return StringIn + '.0'\r
687 else:\r
688 #\r
689 # when StringIn is '', return it directly\r
690 #\r
691 return StringIn\r
692\r
693## GetHelpStringByRemoveHashKey\r
694#\r
695# Remove hash key at the header of string and return the remain.\r
696#\r
697# @param String: The string need to be processed.\r
698#\r
699def GetHelpStringByRemoveHashKey(String):\r
700 ReturnString = ''\r
701 PattenRemoveHashKey = re.compile(r"^[#+\s]+", re.DOTALL)\r
702 String = String.strip()\r
703 if String == '':\r
704 return String\r
705\r
706 LineList = GetSplitValueList(String, END_OF_LINE)\r
707 for Line in LineList:\r
708 ValueList = PattenRemoveHashKey.split(Line)\r
709 if len(ValueList) == 1:\r
710 ReturnString += ValueList[0] + END_OF_LINE\r
711 else:\r
712 ReturnString += ValueList[1] + END_OF_LINE\r
713\r
714 if ReturnString.endswith('\n') and not ReturnString.endswith('\n\n') and ReturnString != '\n':\r
715 ReturnString = ReturnString[:-1]\r
716\r
717 return ReturnString\r
718\r
719## ConvPathFromAbsToRel\r
720#\r
721# Get relative file path from absolute path.\r
722#\r
723# @param Path: The string contain file absolute path.\r
724# @param Root: The string contain the parent path of Path in.\r
725#\r
726#\r
727def ConvPathFromAbsToRel(Path, Root):\r
728 Path = os.path.normpath(Path)\r
729 Root = os.path.normpath(Root)\r
730 FullPath = os.path.normpath(os.path.join(Root, Path))\r
731\r
732 #\r
733 # If Path is absolute path.\r
734 # It should be in Root.\r
735 #\r
736 if os.path.isabs(Path):\r
737 return FullPath[FullPath.find(Root) + len(Root) + 1:]\r
738\r
739 else:\r
740 return Path\r
741\r
742## ConvertPath\r
743#\r
744# Convert special characters to '_', '\' to '/'\r
745# return converted path: Test!1.inf -> Test_1.inf\r
746#\r
747# @param Path: Path to be converted\r
748#\r
749def ConvertPath(Path):\r
750 RetPath = ''\r
751 for Char in Path.strip():\r
752 if Char.isalnum() or Char in '.-_/':\r
753 RetPath = RetPath + Char\r
754 elif Char == '\\':\r
755 RetPath = RetPath + '/'\r
756 else:\r
757 RetPath = RetPath + '_'\r
758 return RetPath\r
759\r
760## ConvertSpec\r
761#\r
762# during install, convert the Spec string extract from UPD into INF allowable definition, \r
763# the difference is period is allowed in the former (not the first letter) but not in the latter.\r
764# return converted Spec string\r
765#\r
766# @param SpecStr: SpecStr to be converted\r
767#\r
768def ConvertSpec(SpecStr):\r
769 RetStr = ''\r
770 for Char in SpecStr:\r
771 if Char.isalnum() or Char == '_':\r
772 RetStr = RetStr + Char\r
773 else:\r
774 RetStr = RetStr + '_'\r
775\r
776 return RetStr\r
777\r
778\r
779## IsEqualList\r
780#\r
781# Judge two lists are identical(contain same item).\r
782# The rule is elements in List A are in List B and elements in List B are in List A.\r
783#\r
784# @param ListA, ListB Lists need to be judged.\r
785# \r
786# @return True ListA and ListB are identical\r
787# @return False ListA and ListB are different with each other\r
788#\r
789def IsEqualList(ListA, ListB):\r
790 if ListA == ListB:\r
791 return True\r
792\r
793 for ItemA in ListA:\r
794 if not ItemA in ListB:\r
795 return False\r
796\r
797 for ItemB in ListB:\r
798 if not ItemB in ListA:\r
799 return False\r
800\r
801 return True\r
802\r
803## ConvertArchList\r
804#\r
805# Convert item in ArchList if the start character is lower case.\r
806# In UDP spec, Arch is only allowed as: [A-Z]([a-zA-Z0-9])* \r
807#\r
808# @param ArchList The ArchList need to be converted.\r
809# \r
810# @return NewList The ArchList been converted.\r
811#\r
812def ConvertArchList(ArchList):\r
813 NewArchList = []\r
814 if not ArchList:\r
815 return NewArchList\r
816\r
817 if type(ArchList) == list:\r
818 for Arch in ArchList:\r
819 Arch = Arch.upper()\r
820 NewArchList.append(Arch)\r
821 elif type(ArchList) == str:\r
822 ArchList = ArchList.upper()\r
823 NewArchList.append(ArchList)\r
824\r
825 return NewArchList\r
826\r
827## ProcessLineExtender\r
828#\r
829# Process the LineExtender of Line in LineList.\r
830# If one line ends with a line extender, then it will be combined together with next line.\r
831#\r
832# @param LineList The LineList need to be processed.\r
833# \r
834# @return NewList The ArchList been processed.\r
835#\r
836def ProcessLineExtender(LineList):\r
837 NewList = []\r
838 Count = 0\r
839 while Count < len(LineList):\r
840 if LineList[Count].strip().endswith("\\") and Count + 1 < len(LineList):\r
841 NewList.append(LineList[Count].strip()[:-2] + LineList[Count + 1])\r
842 Count = Count + 1\r
843 else:\r
844 NewList.append(LineList[Count])\r
845\r
846 Count = Count + 1\r
847\r
848 return NewList\r
849\r
850## ProcessEdkComment\r
851#\r
852# Process EDK style comment in LineList: c style /* */ comment or cpp style // comment \r
853#\r
854#\r
855# @param LineList The LineList need to be processed.\r
856# \r
857# @return LineList The LineList been processed.\r
858# @return FirstPos Where Edk comment is first found, -1 if not found\r
859#\r
860def ProcessEdkComment(LineList):\r
861 FindEdkBlockComment = False\r
862 Count = 0\r
863 StartPos = -1\r
864 EndPos = -1\r
865 FirstPos = -1\r
866 \r
867 while(Count < len(LineList)):\r
868 Line = LineList[Count].strip()\r
869 if Line.startswith("/*"):\r
870 #\r
871 # handling c style comment\r
872 #\r
873 StartPos = Count\r
874 while Count < len(LineList):\r
875 Line = LineList[Count].strip()\r
876 if Line.endswith("*/"):\r
877 if (Count == StartPos) and Line.strip() == '/*/':\r
878 Count = Count + 1\r
879 continue\r
880 EndPos = Count\r
881 FindEdkBlockComment = True\r
882 break\r
883 Count = Count + 1\r
884 \r
885 if FindEdkBlockComment:\r
886 if FirstPos == -1:\r
887 FirstPos = StartPos\r
888 for Index in xrange(StartPos, EndPos+1):\r
889 LineList[Index] = ''\r
890 FindEdkBlockComment = False\r
891 elif Line.find("//") != -1 and not Line.startswith("#"):\r
892 #\r
893 # handling cpp style comment\r
894 #\r
895 LineList[Count] = Line.replace("//", '#')\r
896 if FirstPos == -1:\r
897 FirstPos = Count\r
898 \r
899 Count = Count + 1\r
900 \r
901 return LineList, FirstPos\r
902\r
903## GetLibInstanceInfo\r
904#\r
905# Get the information from Library Instance INF file.\r
906#\r
907# @param string. A string start with # and followed by INF file path\r
908# @param WorkSpace. The WorkSpace directory used to combined with INF file path.\r
909#\r
910# @return GUID, Version\r
911def GetLibInstanceInfo(String, WorkSpace, LineNo):\r
912\r
913 FileGuidString = ""\r
914 VerString = ""\r
915\r
916 OrignalString = String\r
917 String = String.strip()\r
918 if not String:\r
919 return None, None\r
920 #\r
921 # Remove "#" characters at the beginning\r
922 #\r
923 String = GetHelpStringByRemoveHashKey(String)\r
924 String = String.strip()\r
925\r
926 #\r
927 # Validate file name exist.\r
928 #\r
929 FullFileName = os.path.normpath(os.path.realpath(os.path.join(WorkSpace, String)))\r
930 if not (ValidFile(FullFileName)):\r
931 Logger.Error("InfParser",\r
932 ToolError.FORMAT_INVALID,\r
933 ST.ERR_FILELIST_EXIST % (String),\r
934 File=GlobalData.gINF_MODULE_NAME,\r
935 Line=LineNo,\r
936 ExtraData=OrignalString)\r
937\r
938 #\r
939 # Validate file exist/format.\r
940 #\r
941 if IsValidPath(String, WorkSpace):\r
942 IsValidFileFlag = True\r
943 else:\r
944 Logger.Error("InfParser",\r
945 ToolError.FORMAT_INVALID,\r
946 ST.ERR_INF_PARSER_FILE_NOT_EXIST_OR_NAME_INVALID % (String),\r
947 File=GlobalData.gINF_MODULE_NAME,\r
948 Line=LineNo,\r
949 ExtraData=OrignalString)\r
950 return False\r
951 if IsValidFileFlag:\r
952 FileLinesList = []\r
953\r
954 try:\r
955 FInputfile = open(FullFileName, "rb", 0)\r
956 try:\r
957 FileLinesList = FInputfile.readlines()\r
958 except BaseException:\r
959 Logger.Error("InfParser",\r
960 ToolError.FILE_READ_FAILURE,\r
961 ST.ERR_FILE_OPEN_FAILURE,\r
962 File=FullFileName)\r
963 finally:\r
964 FInputfile.close()\r
965 except BaseException:\r
966 Logger.Error("InfParser",\r
967 ToolError.FILE_READ_FAILURE,\r
968 ST.ERR_FILE_OPEN_FAILURE,\r
969 File=FullFileName)\r
970\r
971 ReFileGuidPattern = re.compile("^\s*FILE_GUID\s*=.*$")\r
972 ReVerStringPattern = re.compile("^\s*VERSION_STRING\s*=.*$")\r
973\r
974 FileLinesList = ProcessLineExtender(FileLinesList)\r
975\r
976 for Line in FileLinesList:\r
977 if ReFileGuidPattern.match(Line):\r
978 FileGuidString = Line\r
979 if ReVerStringPattern.match(Line):\r
980 VerString = Line\r
981\r
982 if FileGuidString:\r
983 FileGuidString = GetSplitValueList(FileGuidString, '=', 1)[1]\r
984 if VerString:\r
985 VerString = GetSplitValueList(VerString, '=', 1)[1]\r
986\r
987 return FileGuidString, VerString\r
421ccda3
HC
988\r
989## GetLocalValue\r
990#\r
991# Generate the local value for INF and DEC file. If Lang attribute not present, then use this value.\r
992# If present, and there is no element without the Lang attribute, and one of the elements has the rfc1766 code is \r
993# "en-x-tianocore", or "en-US" if "en-x-tianocore" was not found, or "en" if "en-US" was not found, or startswith 'en' \r
994# if 'en' was not found, then use this value.\r
995# If multiple entries of a tag exist which have the same language code, use the last entry.\r
996#\r
997# @param ValueList A list need to be processed.\r
998# @param UseFirstValue: True to use the first value, False to use the last value \r
999#\r
1000# @return LocalValue\r
1001def GetLocalValue(ValueList, UseFirstValue=False):\r
1002 Value1 = ''\r
1003 Value2 = ''\r
1004 Value3 = ''\r
1005 Value4 = ''\r
1006 Value5 = ''\r
1007 for (Key, Value) in ValueList:\r
1008 if Key == TAB_LANGUAGE_EN_X:\r
1009 if UseFirstValue:\r
1010 if not Value1:\r
1011 Value1 = Value\r
1012 else:\r
1013 Value1 = Value\r
1014 if Key == TAB_LANGUAGE_EN_US:\r
1015 if UseFirstValue:\r
1016 if not Value2:\r
1017 Value2 = Value\r
1018 else:\r
1019 Value2 = Value\r
1020 if Key == TAB_LANGUAGE_EN:\r
1021 if UseFirstValue:\r
1022 if not Value3:\r
1023 Value3 = Value\r
1024 else:\r
1025 Value3 = Value\r
1026 if Key.startswith(TAB_LANGUAGE_EN):\r
1027 if UseFirstValue:\r
1028 if not Value4:\r
1029 Value4 = Value\r
1030 else:\r
1031 Value4 = Value\r
1032 if Key == '':\r
1033 if UseFirstValue:\r
1034 if not Value5:\r
1035 Value5 = Value\r
1036 else:\r
1037 Value5 = Value\r
1038 \r
1039 if Value1:\r
1040 return Value1\r
1041 if Value2:\r
1042 return Value2\r
1043 if Value3:\r
1044 return Value3\r
1045 if Value4:\r
1046 return Value4\r
1047 if Value5:\r
1048 return Value5\r
1049 \r
1050 return ''\r
1051\r
1052\r
1053## GetCharIndexOutStr\r
1054#\r
1055# Get comment character index outside a string\r
1056#\r
1057# @param Line: The string to be checked\r
1058# @param CommentCharacter: Comment char, used to ignore comment content\r
1059#\r
1060# @retval Index\r
1061#\r
1062def GetCharIndexOutStr(CommentCharacter, Line):\r
1063 #\r
1064 # remove whitespace\r
1065 #\r
1066 Line = Line.strip()\r
1067\r
1068 #\r
1069 # Check whether comment character is in a string\r
1070 #\r
1071 InString = False\r
1072 for Index in range(0, len(Line)):\r
1073 if Line[Index] == '"':\r
1074 InString = not InString\r
1075 elif Line[Index] == CommentCharacter and InString :\r
1076 pass\r
1077 elif Line[Index] == CommentCharacter and (Index +1) < len(Line) and Line[Index+1] == CommentCharacter \\r
1078 and not InString :\r
1079 return Index\r
1080 return -1\r
1081\r
1082## ValidateUNIFilePath\r
1083#\r
1084# Check the UNI file path\r
1085#\r
1086# @param FilePath: The UNI file path \r
1087#\r
1088def ValidateUNIFilePath(Path):\r
1089 Suffix = Path[Path.rfind(TAB_SPLIT):]\r
1090 \r
1091 #\r
1092 # Check if the suffix is one of the '.uni', '.UNI', '.Uni' \r
1093 #\r
1094 if Suffix not in TAB_UNI_FILE_SUFFIXS:\r
1095 Logger.Error("Unicode File Parser", \r
1096 ToolError.FORMAT_INVALID, \r
1097 Message=ST.ERR_UNI_FILE_SUFFIX_WRONG, \r
1098 ExtraData=Path) \r
1099 \r
1100 #\r
1101 # Check if '..' in the file name(without suffixe)\r
1102 #\r
1103 if (TAB_SPLIT + TAB_SPLIT) in Path:\r
1104 Logger.Error("Unicode File Parser", \r
1105 ToolError.FORMAT_INVALID, \r
1106 Message=ST.ERR_UNI_FILE_NAME_INVALID, \r
1107 ExtraData=Path) \r
1108 \r
1109 #\r
1110 # Check if the file name is valid according to the DEC and INF specification\r
1111 #\r
1112 Pattern = '[a-zA-Z0-9_][a-zA-Z0-9_\-\.]*'\r
1113 FileName = Path.replace(Suffix, '')\r
1114 InvalidCh = re.sub(Pattern, '', FileName)\r
1115 if InvalidCh:\r
1116 Logger.Error("Unicode File Parser", \r
1117 ToolError.FORMAT_INVALID, \r
1118 Message=ST.ERR_INF_PARSER_FILE_NOT_EXIST_OR_NAME_INVALID, \r
1119 ExtraData=Path) \r
1120\r