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