2 # Common routines used by all tools
4 # Copyright (c) 2011 - 2018, Intel Corporation. All rights reserved.<BR>
6 # This program and the accompanying materials are licensed and made available
7 # under the terms and conditions of the BSD License which accompanies this
8 # distribution. The full text of the license may be found at
9 # http://opensource.org/licenses/bsd-license.php
11 # THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
12 # WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
25 from os
import makedirs
28 from os
import listdir
31 from os
import linesep
33 from os
import environ
35 from collections
import UserDict
as IterableUserDict
37 import Logger
.Log
as Logger
38 from Logger
import StringTable
as ST
39 from Logger
import ToolError
40 from Library
import GlobalData
41 from Library
.DataType
import SUP_MODULE_LIST
42 from Library
.DataType
import END_OF_LINE
43 from Library
.DataType
import TAB_SPLIT
44 from Library
.DataType
import TAB_LANGUAGE_EN_US
45 from Library
.DataType
import TAB_LANGUAGE_EN
46 from Library
.DataType
import TAB_LANGUAGE_EN_X
47 from Library
.DataType
import TAB_UNI_FILE_SUFFIXS
48 from Library
.StringUtils
import GetSplitValueList
49 from Library
.ParserValidate
import IsValidHexVersion
50 from Library
.ParserValidate
import IsValidPath
51 from Object
.POM
.CommonObject
import TextObject
52 from Core
.FileHook
import __FileHookOpen__
53 from Common
.MultipleWorkspace
import MultipleWorkspace
as mws
55 ## Convert GUID string in xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx style to C
58 # @param Guid: The GUID string
60 def GuidStringToGuidStructureString(Guid
):
61 GuidList
= Guid
.split('-')
63 for Index
in range(0, 3, 1):
64 Result
= Result
+ '0x' + GuidList
[Index
] + ', '
65 Result
= Result
+ '{0x' + GuidList
[3][0:2] + ', 0x' + GuidList
[3][2:4]
66 for Index
in range(0, 12, 2):
67 Result
= Result
+ ', 0x' + GuidList
[4][Index
:Index
+ 2]
71 ## Check whether GUID string is of format xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx
73 # @param GuidValue: The GUID value
75 def CheckGuidRegFormat(GuidValue
):
76 ## Regular expression used to find out register format of GUID
78 RegFormatGuidPattern
= re
.compile("^\s*([0-9a-fA-F]){8}-"
82 "([0-9a-fA-F]){12}\s*$")
84 if RegFormatGuidPattern
.match(GuidValue
):
90 ## Convert GUID string in C structure style to
91 # xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx
93 # @param GuidValue: The GUID value in C structure format
95 def GuidStructureStringToGuidString(GuidValue
):
96 GuidValueString
= GuidValue
.lower().replace("{", "").replace("}", "").\
97 replace(" ", "").replace(";", "")
98 GuidValueList
= GuidValueString
.split(",")
99 if len(GuidValueList
) != 11:
102 return "%08x-%04x-%04x-%02x%02x-%02x%02x%02x%02x%02x%02x" % (
103 int(GuidValueList
[0], 16),
104 int(GuidValueList
[1], 16),
105 int(GuidValueList
[2], 16),
106 int(GuidValueList
[3], 16),
107 int(GuidValueList
[4], 16),
108 int(GuidValueList
[5], 16),
109 int(GuidValueList
[6], 16),
110 int(GuidValueList
[7], 16),
111 int(GuidValueList
[8], 16),
112 int(GuidValueList
[9], 16),
113 int(GuidValueList
[10], 16)
115 except BaseException
:
118 ## Create directories
120 # @param Directory: The directory name
122 def CreateDirectory(Directory
):
123 if Directory
is None or Directory
.strip() == "":
126 if not access(Directory
, F_OK
):
128 except BaseException
:
132 ## Remove directories, including files and sub-directories in it
134 # @param Directory: The directory name
136 def RemoveDirectory(Directory
, Recursively
=False):
137 if Directory
is None or Directory
.strip() == "" or not \
138 os
.path
.exists(Directory
):
141 CurrentDirectory
= getcwd()
143 for File
in listdir("."):
144 if os
.path
.isdir(File
):
145 RemoveDirectory(File
, Recursively
)
148 chdir(CurrentDirectory
)
151 ## Store content in file
153 # This method is used to save file only when its content is changed. This is
154 # quite useful for "make" system to decide what will be re-built and what
157 # @param File: The path of file
158 # @param Content: The new content of the file
159 # @param IsBinaryFile: The flag indicating if the file is binary file
162 def SaveFileOnChange(File
, Content
, IsBinaryFile
=True):
163 if os
.path
.exists(File
):
165 if isinstance(Content
, bytes
):
166 if Content
== __FileHookOpen__(File
, "rb").read():
169 if Content
== __FileHookOpen__(File
, "r").read():
171 except BaseException
:
172 Logger
.Error(None, ToolError
.FILE_OPEN_FAILURE
, ExtraData
=File
)
174 CreateDirectory(os
.path
.dirname(File
))
176 if isinstance(Content
, bytes
):
177 FileFd
= __FileHookOpen__(File
, "wb")
179 FileFd
= __FileHookOpen__(File
, "w")
180 FileFd
.write(Content
)
182 except BaseException
:
183 Logger
.Error(None, ToolError
.FILE_CREATE_FAILURE
, ExtraData
=File
)
187 ## Get all files of a directory
189 # @param Root: Root dir
190 # @param SkipList : The files need be skipped
192 def GetFiles(Root
, SkipList
=None, FullPath
=True):
193 OriPath
= os
.path
.normpath(Root
)
195 for Root
, Dirs
, Files
in walk(Root
):
197 for Item
in SkipList
:
203 if Dir
.startswith('.'):
207 if File
.startswith('.'):
209 File
= os
.path
.normpath(os
.path
.join(Root
, File
))
211 File
= File
[len(OriPath
) + 1:]
212 FileList
.append(File
)
216 ## Get all non-metadata files of a directory
218 # @param Root: Root Dir
219 # @param SkipList : List of path need be skipped
220 # @param FullPath: True if the returned file should be full path
221 # @param PrefixPath: the path that need to be added to the files found
222 # @return: the list of files found
224 def GetNonMetaDataFiles(Root
, SkipList
, FullPath
, PrefixPath
):
225 FileList
= GetFiles(Root
, SkipList
, FullPath
)
227 for File
in FileList
:
228 ExtName
= os
.path
.splitext(File
)[1]
230 # skip '.dec', '.inf', '.dsc', '.fdf' files
232 if ExtName
.lower() not in ['.dec', '.inf', '.dsc', '.fdf']:
233 NewFileList
.append(os
.path
.normpath(os
.path
.join(PrefixPath
, File
)))
237 ## Check if given file exists or not
239 # @param File: File name or path to be checked
240 # @param Dir: The directory the file is relative to
242 def ValidFile(File
, Ext
=None):
243 File
= File
.replace('\\', '/')
245 FileExt
= os
.path
.splitext(File
)[1]
246 if FileExt
.lower() != Ext
.lower():
248 if not os
.path
.exists(File
):
254 # @param File: File name or path to be checked
255 # @param Dir: The directory the file is relative to
256 # @param OverrideDir: The override directory
258 def RealPath(File
, Dir
='', OverrideDir
=''):
259 NewFile
= os
.path
.normpath(os
.path
.join(Dir
, File
))
260 NewFile
= GlobalData
.gALL_FILES
[NewFile
]
261 if not NewFile
and OverrideDir
:
262 NewFile
= os
.path
.normpath(os
.path
.join(OverrideDir
, File
))
263 NewFile
= GlobalData
.gALL_FILES
[NewFile
]
268 # @param File: File name or path to be checked
269 # @param Dir: The directory the file is relative to
270 # @param OverrideDir: The override directory
272 def RealPath2(File
, Dir
='', OverrideDir
=''):
274 NewFile
= GlobalData
.gALL_FILES
[os
.path
.normpath(os
.path
.join\
275 (OverrideDir
, File
))]
277 if OverrideDir
[-1] == os
.path
.sep
:
278 return NewFile
[len(OverrideDir
):], NewFile
[0:len(OverrideDir
)]
280 return NewFile
[len(OverrideDir
) + 1:], \
281 NewFile
[0:len(OverrideDir
)]
283 NewFile
= GlobalData
.gALL_FILES
[os
.path
.normpath(os
.path
.join(Dir
, File
))]
286 if Dir
[-1] == os
.path
.sep
:
287 return NewFile
[len(Dir
):], NewFile
[0:len(Dir
)]
289 return NewFile
[len(Dir
) + 1:], NewFile
[0:len(Dir
)]
295 ## A dict which can access its keys and/or values orderly
297 # The class implements a new kind of dict which its keys or values can be
298 # accessed in the order they are added into the dict. It guarantees the order
299 # by making use of an internal list to keep a copy of keys.
301 class Sdict(IterableUserDict
):
305 IterableUserDict
.__init
__(self
)
310 def __setitem__(self
, Key
, Value
):
311 if Key
not in self
._key
_list
:
312 self
._key
_list
.append(Key
)
313 IterableUserDict
.__setitem
__(self
, Key
, Value
)
317 def __delitem__(self
, Key
):
318 self
._key
_list
.remove(Key
)
319 IterableUserDict
.__delitem
__(self
, Key
)
321 ## used in "for k in dict" loop to ensure the correct order
324 return self
.iterkeys()
329 return len(self
._key
_list
)
333 def __contains__(self
, Key
):
334 return Key
in self
._key
_list
338 def index(self
, Key
):
339 return self
._key
_list
.index(Key
)
343 def insert(self
, Key
, Newkey
, Newvalue
, Order
):
344 Index
= self
._key
_list
.index(Key
)
345 if Order
== 'BEFORE':
346 self
._key
_list
.insert(Index
, Newkey
)
347 IterableUserDict
.__setitem
__(self
, Newkey
, Newvalue
)
348 elif Order
== 'AFTER':
349 self
._key
_list
.insert(Index
+ 1, Newkey
)
350 IterableUserDict
.__setitem
__(self
, Newkey
, Newvalue
)
354 def append(self
, Sdict2
):
356 if Key
not in self
._key
_list
:
357 self
._key
_list
.append(Key
)
358 IterableUserDict
.__setitem
__(self
, Key
, Sdict2
[Key
])
361 def has_key(self
, Key
):
362 return Key
in self
._key
_list
368 IterableUserDict
.clear(self
)
370 ## Return a copy of keys
374 for Key
in self
._key
_list
:
378 ## Return a copy of values
382 for Key
in self
._key
_list
:
383 Values
.append(self
[Key
])
386 ## Return a copy of (key, value) list
390 for Key
in self
._key
_list
:
391 Items
.append((Key
, self
[Key
]))
397 return iter(self
.items())
399 ## Keys interation support
402 return iter(self
.keys())
404 ## Values interation support
406 def itervalues(self
):
407 return iter(self
.values())
409 ## Return value related to a key, and remove the (key, value) from the dict
411 def pop(self
, Key
, *Dv
):
413 if Key
in self
._key
_list
:
415 self
.__delitem
__(Key
)
420 ## Return (key, value) pair, and remove the (key, value) from the dict
423 Key
= self
._key
_list
[-1]
425 self
.__delitem
__(Key
)
429 def update(self
, Dict
=None, **Kwargs
):
431 for Key1
, Val1
in Dict
.items():
434 for Key1
, Val1
in Kwargs
.items():
439 # @param PathList: PathList
441 def CommonPath(PathList
):
442 Path1
= min(PathList
).split(os
.path
.sep
)
443 Path2
= max(PathList
).split(os
.path
.sep
)
444 for Index
in range(min(len(Path1
), len(Path2
))):
445 if Path1
[Index
] != Path2
[Index
]:
446 return os
.path
.sep
.join(Path1
[:Index
])
447 return os
.path
.sep
.join(Path1
)
451 class PathClass(object):
452 def __init__(self
, File
='', Root
='', AlterRoot
='', Type
='', IsBinary
=False,
453 Arch
='COMMON', ToolChainFamily
='', Target
='', TagName
='', \
456 self
.File
= str(File
)
457 if os
.path
.isabs(self
.File
):
461 self
.Root
= str(Root
)
462 self
.AlterRoot
= str(AlterRoot
)
465 # Remove any '.' and '..' in path
468 self
.Path
= os
.path
.normpath(os
.path
.join(self
.Root
, self
.File
))
469 self
.Root
= os
.path
.normpath(CommonPath([self
.Root
, self
.Path
]))
471 # eliminate the side-effect of 'C:'
473 if self
.Root
[-1] == ':':
474 self
.Root
+= os
.path
.sep
476 # file path should not start with path separator
478 if self
.Root
[-1] == os
.path
.sep
:
479 self
.File
= self
.Path
[len(self
.Root
):]
481 self
.File
= self
.Path
[len(self
.Root
) + 1:]
483 self
.Path
= os
.path
.normpath(self
.File
)
485 self
.SubDir
, self
.Name
= os
.path
.split(self
.File
)
486 self
.BaseName
, self
.Ext
= os
.path
.splitext(self
.Name
)
490 self
.Dir
= os
.path
.join(self
.Root
, self
.SubDir
)
494 self
.Dir
= self
.SubDir
499 self
.Type
= self
.Ext
.lower()
501 self
.IsBinary
= IsBinary
503 self
.TagName
= TagName
504 self
.ToolCode
= ToolCode
505 self
.ToolChainFamily
= ToolChainFamily
509 ## Convert the object of this class to a string
511 # Convert member Path of the class to a string
516 ## Override __eq__ function
518 # Check whether PathClass are the same
520 def __eq__(self
, Other
):
521 if isinstance(Other
, type(self
)):
522 return self
.Path
== Other
.Path
524 return self
.Path
== str(Other
)
526 ## Override __hash__ function
528 # Use Path as key in hash table
531 return hash(self
.Path
)
535 def _GetFileKey(self
):
536 if self
._Key
is None:
537 self
._Key
= self
.Path
.upper()
541 def Validate(self
, Type
='', CaseSensitive
=True):
542 if GlobalData
.gCASE_INSENSITIVE
:
543 CaseSensitive
= False
544 if Type
and Type
.lower() != self
.Type
:
545 return ToolError
.FILE_TYPE_MISMATCH
, '%s (expect %s but got %s)' % \
546 (self
.File
, Type
, self
.Type
)
548 RealFile
, RealRoot
= RealPath2(self
.File
, self
.Root
, self
.AlterRoot
)
549 if not RealRoot
and not RealFile
:
552 RealFile
= os
.path
.join(self
.AlterRoot
, self
.File
)
554 RealFile
= os
.path
.join(self
.Root
, self
.File
)
555 return ToolError
.FILE_NOT_FOUND
, os
.path
.join(self
.AlterRoot
, RealFile
)
559 if RealRoot
!= self
.Root
or RealFile
!= self
.File
:
560 if CaseSensitive
and (RealFile
!= self
.File
or \
561 (RealRoot
!= self
.Root
and RealRoot
!= \
563 ErrorCode
= ToolError
.FILE_CASE_MISMATCH
564 ErrorInfo
= self
.File
+ '\n\t' + RealFile
+ \
567 self
.SubDir
, self
.Name
= os
.path
.split(RealFile
)
568 self
.BaseName
, self
.Ext
= os
.path
.splitext(self
.Name
)
570 self
.Dir
= os
.path
.join(RealRoot
, self
.SubDir
)
575 self
.Path
= os
.path
.join(RealRoot
, RealFile
)
576 return ErrorCode
, ErrorInfo
578 Key
= property(_GetFileKey
)
580 ## Get current workspace
582 # get WORKSPACE from environment variable if present,if not use current working directory as WORKSPACE
588 if "WORKSPACE" in environ
:
589 WorkspaceDir
= os
.path
.normpath(environ
["WORKSPACE"])
590 if not os
.path
.exists(WorkspaceDir
):
592 ToolError
.UPT_ENVIRON_MISSING_ERROR
,
593 ST
.ERR_WORKSPACE_NOTEXIST
,
594 ExtraData
="%s" % WorkspaceDir
)
596 WorkspaceDir
= os
.getcwd()
598 if WorkspaceDir
[-1] == ':':
599 WorkspaceDir
+= os
.sep
601 PackagesPath
= os
.environ
.get("PACKAGES_PATH")
602 mws
.setWs(WorkspaceDir
, PackagesPath
)
604 return WorkspaceDir
, mws
.PACKAGES_PATH
608 # use full path and workspace to get relative path
609 # the destination of this function is mainly to resolve the root path issue(like c: or c:\)
611 # @param Fullpath: a string of fullpath
612 # @param Workspace: a string of workspace
614 def GetRelativePath(Fullpath
, Workspace
):
617 if Workspace
.endswith(os
.sep
):
618 RelativePath
= Fullpath
[Fullpath
.upper().find(Workspace
.upper())+len(Workspace
):]
620 RelativePath
= Fullpath
[Fullpath
.upper().find(Workspace
.upper())+len(Workspace
)+1:]
624 ## Check whether all module types are in list
626 # check whether all module types (SUP_MODULE_LIST) are in list
628 # @param ModuleList: a list of ModuleType
630 def IsAllModuleList(ModuleList
):
631 NewModuleList
= [Module
.upper() for Module
in ModuleList
]
632 for Module
in SUP_MODULE_LIST
:
633 if Module
not in NewModuleList
:
638 ## Dictionary that use comment(GenericComment, TailComment) as value,
639 # if a new comment which key already in the dic is inserted, then the
640 # comment will be merged.
641 # Key is (Statement, SupArch), when TailComment is added, it will ident
642 # according to Statement
644 class MergeCommentDict(dict):
647 def __setitem__(self
, Key
, CommentVal
):
648 GenericComment
, TailComment
= CommentVal
650 OrigVal1
, OrigVal2
= dict.__getitem
__(self
, Key
)
652 dict.__setitem
__(self
, Key
, (OrigVal1
+ GenericComment
, OrigVal2 \
653 + len(Statement
) * ' ' + TailComment
))
655 dict.__setitem
__(self
, Key
, (GenericComment
, TailComment
))
659 def __getitem__(self
, Key
):
660 return dict.__getitem
__(self
, Key
)
663 ## GenDummyHelpTextObj
665 # @retval HelpTxt: Generated dummy help text object
667 def GenDummyHelpTextObj():
668 HelpTxt
= TextObject()
669 HelpTxt
.SetLang(TAB_LANGUAGE_EN_US
)
670 HelpTxt
.SetString(' ')
673 ## ConvertVersionToDecimal, the minor version should be within 0 - 99
674 # <HexVersion> ::= "0x" <Major> <Minor>
675 # <Major> ::= (a-fA-F0-9){4}
676 # <Minor> ::= (a-fA-F0-9){4}
677 # <DecVersion> ::= (0-65535) ["." (0-99)]
679 # @param StringIn: The string contains version defined in INF file.
680 # It can be Decimal or Hex
682 def ConvertVersionToDecimal(StringIn
):
683 if IsValidHexVersion(StringIn
):
684 Value
= int(StringIn
, 16)
686 Minor
= Value
& 0xFFFF
687 MinorStr
= str(Minor
)
688 if len(MinorStr
) == 1:
689 MinorStr
= '0' + MinorStr
690 return str(Major
) + '.' + MinorStr
692 if StringIn
.find(TAB_SPLIT
) != -1:
695 return StringIn
+ '.0'
698 # when StringIn is '', return it directly
702 ## GetHelpStringByRemoveHashKey
704 # Remove hash key at the header of string and return the remain.
706 # @param String: The string need to be processed.
708 def GetHelpStringByRemoveHashKey(String
):
710 PattenRemoveHashKey
= re
.compile(r
"^[#+\s]+", re
.DOTALL
)
711 String
= String
.strip()
715 LineList
= GetSplitValueList(String
, END_OF_LINE
)
716 for Line
in LineList
:
717 ValueList
= PattenRemoveHashKey
.split(Line
)
718 if len(ValueList
) == 1:
719 ReturnString
+= ValueList
[0] + END_OF_LINE
721 ReturnString
+= ValueList
[1] + END_OF_LINE
723 if ReturnString
.endswith('\n') and not ReturnString
.endswith('\n\n') and ReturnString
!= '\n':
724 ReturnString
= ReturnString
[:-1]
728 ## ConvPathFromAbsToRel
730 # Get relative file path from absolute path.
732 # @param Path: The string contain file absolute path.
733 # @param Root: The string contain the parent path of Path in.
736 def ConvPathFromAbsToRel(Path
, Root
):
737 Path
= os
.path
.normpath(Path
)
738 Root
= os
.path
.normpath(Root
)
739 FullPath
= os
.path
.normpath(os
.path
.join(Root
, Path
))
742 # If Path is absolute path.
743 # It should be in Root.
745 if os
.path
.isabs(Path
):
746 return FullPath
[FullPath
.find(Root
) + len(Root
) + 1:]
753 # Convert special characters to '_', '\' to '/'
754 # return converted path: Test!1.inf -> Test_1.inf
756 # @param Path: Path to be converted
758 def ConvertPath(Path
):
760 for Char
in Path
.strip():
761 if Char
.isalnum() or Char
in '.-_/':
762 RetPath
= RetPath
+ Char
764 RetPath
= RetPath
+ '/'
766 RetPath
= RetPath
+ '_'
771 # during install, convert the Spec string extract from UPD into INF allowable definition,
772 # the difference is period is allowed in the former (not the first letter) but not in the latter.
773 # return converted Spec string
775 # @param SpecStr: SpecStr to be converted
777 def ConvertSpec(SpecStr
):
780 if Char
.isalnum() or Char
== '_':
781 RetStr
= RetStr
+ Char
783 RetStr
= RetStr
+ '_'
790 # Judge two lists are identical(contain same item).
791 # The rule is elements in List A are in List B and elements in List B are in List A.
793 # @param ListA, ListB Lists need to be judged.
795 # @return True ListA and ListB are identical
796 # @return False ListA and ListB are different with each other
798 def IsEqualList(ListA
, ListB
):
803 if not ItemA
in ListB
:
807 if not ItemB
in ListA
:
814 # Convert item in ArchList if the start character is lower case.
815 # In UDP spec, Arch is only allowed as: [A-Z]([a-zA-Z0-9])*
817 # @param ArchList The ArchList need to be converted.
819 # @return NewList The ArchList been converted.
821 def ConvertArchList(ArchList
):
826 if isinstance(ArchList
, list):
827 for Arch
in ArchList
:
829 NewArchList
.append(Arch
)
830 elif isinstance(ArchList
, str):
831 ArchList
= ArchList
.upper()
832 NewArchList
.append(ArchList
)
836 ## ProcessLineExtender
838 # Process the LineExtender of Line in LineList.
839 # If one line ends with a line extender, then it will be combined together with next line.
841 # @param LineList The LineList need to be processed.
843 # @return NewList The ArchList been processed.
845 def ProcessLineExtender(LineList
):
848 while Count
< len(LineList
):
849 if LineList
[Count
].strip().endswith("\\") and Count
+ 1 < len(LineList
):
850 NewList
.append(LineList
[Count
].strip()[:-2] + LineList
[Count
+ 1])
853 NewList
.append(LineList
[Count
])
861 # Process EDK style comment in LineList: c style /* */ comment or cpp style // comment
864 # @param LineList The LineList need to be processed.
866 # @return LineList The LineList been processed.
867 # @return FirstPos Where Edk comment is first found, -1 if not found
869 def ProcessEdkComment(LineList
):
870 FindEdkBlockComment
= False
876 while(Count
< len(LineList
)):
877 Line
= LineList
[Count
].strip()
878 if Line
.startswith("/*"):
880 # handling c style comment
883 while Count
< len(LineList
):
884 Line
= LineList
[Count
].strip()
885 if Line
.endswith("*/"):
886 if (Count
== StartPos
) and Line
.strip() == '/*/':
890 FindEdkBlockComment
= True
894 if FindEdkBlockComment
:
897 for Index
in range(StartPos
, EndPos
+1):
899 FindEdkBlockComment
= False
900 elif Line
.find("//") != -1 and not Line
.startswith("#"):
902 # handling cpp style comment
904 LineList
[Count
] = Line
.replace("//", '#')
910 return LineList
, FirstPos
912 ## GetLibInstanceInfo
914 # Get the information from Library Instance INF file.
916 # @param string. A string start with # and followed by INF file path
917 # @param WorkSpace. The WorkSpace directory used to combined with INF file path.
919 # @return GUID, Version
920 def GetLibInstanceInfo(String
, WorkSpace
, LineNo
):
925 OrignalString
= String
926 String
= String
.strip()
930 # Remove "#" characters at the beginning
932 String
= GetHelpStringByRemoveHashKey(String
)
933 String
= String
.strip()
936 # Validate file name exist.
938 FullFileName
= os
.path
.normpath(os
.path
.realpath(os
.path
.join(WorkSpace
, String
)))
939 if not (ValidFile(FullFileName
)):
940 Logger
.Error("InfParser",
941 ToolError
.FORMAT_INVALID
,
942 ST
.ERR_FILELIST_EXIST
% (String
),
943 File
=GlobalData
.gINF_MODULE_NAME
,
945 ExtraData
=OrignalString
)
948 # Validate file exist/format.
950 if IsValidPath(String
, WorkSpace
):
951 IsValidFileFlag
= True
953 Logger
.Error("InfParser",
954 ToolError
.FORMAT_INVALID
,
955 ST
.ERR_INF_PARSER_FILE_NOT_EXIST_OR_NAME_INVALID
% (String
),
956 File
=GlobalData
.gINF_MODULE_NAME
,
958 ExtraData
=OrignalString
)
964 FInputfile
= open(FullFileName
, "r")
966 FileLinesList
= FInputfile
.readlines()
967 except BaseException
:
968 Logger
.Error("InfParser",
969 ToolError
.FILE_READ_FAILURE
,
970 ST
.ERR_FILE_OPEN_FAILURE
,
974 except BaseException
:
975 Logger
.Error("InfParser",
976 ToolError
.FILE_READ_FAILURE
,
977 ST
.ERR_FILE_OPEN_FAILURE
,
980 ReFileGuidPattern
= re
.compile("^\s*FILE_GUID\s*=.*$")
981 ReVerStringPattern
= re
.compile("^\s*VERSION_STRING\s*=.*$")
983 FileLinesList
= ProcessLineExtender(FileLinesList
)
985 for Line
in FileLinesList
:
986 if ReFileGuidPattern
.match(Line
):
987 FileGuidString
= Line
988 if ReVerStringPattern
.match(Line
):
992 FileGuidString
= GetSplitValueList(FileGuidString
, '=', 1)[1]
994 VerString
= GetSplitValueList(VerString
, '=', 1)[1]
996 return FileGuidString
, VerString
1000 # Generate the local value for INF and DEC file. If Lang attribute not present, then use this value.
1001 # If present, and there is no element without the Lang attribute, and one of the elements has the rfc1766 code is
1002 # "en-x-tianocore", or "en-US" if "en-x-tianocore" was not found, or "en" if "en-US" was not found, or startswith 'en'
1003 # if 'en' was not found, then use this value.
1004 # If multiple entries of a tag exist which have the same language code, use the last entry.
1006 # @param ValueList A list need to be processed.
1007 # @param UseFirstValue: True to use the first value, False to use the last value
1009 # @return LocalValue
1010 def GetLocalValue(ValueList
, UseFirstValue
=False):
1016 for (Key
, Value
) in ValueList
:
1017 if Key
== TAB_LANGUAGE_EN_X
:
1023 if Key
== TAB_LANGUAGE_EN_US
:
1029 if Key
== TAB_LANGUAGE_EN
:
1035 if Key
.startswith(TAB_LANGUAGE_EN
):
1062 ## GetCharIndexOutStr
1064 # Get comment character index outside a string
1066 # @param Line: The string to be checked
1067 # @param CommentCharacter: Comment char, used to ignore comment content
1071 def GetCharIndexOutStr(CommentCharacter
, Line
):
1078 # Check whether comment character is in a string
1081 for Index
in range(0, len(Line
)):
1082 if Line
[Index
] == '"':
1083 InString
= not InString
1084 elif Line
[Index
] == CommentCharacter
and InString
:
1086 elif Line
[Index
] == CommentCharacter
and (Index
+1) < len(Line
) and Line
[Index
+1] == CommentCharacter \
1091 ## ValidateUNIFilePath
1093 # Check the UNI file path
1095 # @param FilePath: The UNI file path
1097 def ValidateUNIFilePath(Path
):
1098 Suffix
= Path
[Path
.rfind(TAB_SPLIT
):]
1101 # Check if the suffix is one of the '.uni', '.UNI', '.Uni'
1103 if Suffix
not in TAB_UNI_FILE_SUFFIXS
:
1104 Logger
.Error("Unicode File Parser",
1105 ToolError
.FORMAT_INVALID
,
1106 Message
=ST
.ERR_UNI_FILE_SUFFIX_WRONG
,
1110 # Check if '..' in the file name(without suffixe)
1112 if (TAB_SPLIT
+ TAB_SPLIT
) in Path
:
1113 Logger
.Error("Unicode File Parser",
1114 ToolError
.FORMAT_INVALID
,
1115 Message
=ST
.ERR_UNI_FILE_NAME_INVALID
,
1119 # Check if the file name is valid according to the DEC and INF specification
1121 Pattern
= '[a-zA-Z0-9_][a-zA-Z0-9_\-\.]*'
1122 FileName
= Path
.replace(Suffix
, '')
1123 InvalidCh
= re
.sub(Pattern
, '', FileName
)
1125 Logger
.Error("Unicode File Parser",
1126 ToolError
.FORMAT_INVALID
,
1127 Message
=ST
.ERR_INF_PARSER_FILE_NOT_EXIST_OR_NAME_INVALID
,