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