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 UserDict
import 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):
164 Content
= Content
.replace("\n", linesep
)
166 if os
.path
.exists(File
):
168 if Content
== __FileHookOpen__(File
, "rb").read():
170 except BaseException
:
171 Logger
.Error(None, ToolError
.FILE_OPEN_FAILURE
, ExtraData
=File
)
173 CreateDirectory(os
.path
.dirname(File
))
175 FileFd
= __FileHookOpen__(File
, "wb")
176 FileFd
.write(Content
)
178 except BaseException
:
179 Logger
.Error(None, ToolError
.FILE_CREATE_FAILURE
, ExtraData
=File
)
183 ## Get all files of a directory
185 # @param Root: Root dir
186 # @param SkipList : The files need be skipped
188 def GetFiles(Root
, SkipList
=None, FullPath
=True):
189 OriPath
= os
.path
.normpath(Root
)
191 for Root
, Dirs
, Files
in walk(Root
):
193 for Item
in SkipList
:
199 if Dir
.startswith('.'):
203 if File
.startswith('.'):
205 File
= os
.path
.normpath(os
.path
.join(Root
, File
))
207 File
= File
[len(OriPath
) + 1:]
208 FileList
.append(File
)
212 ## Get all non-metadata files of a directory
214 # @param Root: Root Dir
215 # @param SkipList : List of path need be skipped
216 # @param FullPath: True if the returned file should be full path
217 # @param PrefixPath: the path that need to be added to the files found
218 # @return: the list of files found
220 def GetNonMetaDataFiles(Root
, SkipList
, FullPath
, PrefixPath
):
221 FileList
= GetFiles(Root
, SkipList
, FullPath
)
223 for File
in FileList
:
224 ExtName
= os
.path
.splitext(File
)[1]
226 # skip '.dec', '.inf', '.dsc', '.fdf' files
228 if ExtName
.lower() not in ['.dec', '.inf', '.dsc', '.fdf']:
229 NewFileList
.append(os
.path
.normpath(os
.path
.join(PrefixPath
, File
)))
233 ## Check if given file exists or not
235 # @param File: File name or path to be checked
236 # @param Dir: The directory the file is relative to
238 def ValidFile(File
, Ext
=None):
239 File
= File
.replace('\\', '/')
241 FileExt
= os
.path
.splitext(File
)[1]
242 if FileExt
.lower() != Ext
.lower():
244 if not os
.path
.exists(File
):
250 # @param File: File name or path to be checked
251 # @param Dir: The directory the file is relative to
252 # @param OverrideDir: The override directory
254 def RealPath(File
, Dir
='', OverrideDir
=''):
255 NewFile
= os
.path
.normpath(os
.path
.join(Dir
, File
))
256 NewFile
= GlobalData
.gALL_FILES
[NewFile
]
257 if not NewFile
and OverrideDir
:
258 NewFile
= os
.path
.normpath(os
.path
.join(OverrideDir
, File
))
259 NewFile
= GlobalData
.gALL_FILES
[NewFile
]
264 # @param File: File name or path to be checked
265 # @param Dir: The directory the file is relative to
266 # @param OverrideDir: The override directory
268 def RealPath2(File
, Dir
='', OverrideDir
=''):
270 NewFile
= GlobalData
.gALL_FILES
[os
.path
.normpath(os
.path
.join\
271 (OverrideDir
, File
))]
273 if OverrideDir
[-1] == os
.path
.sep
:
274 return NewFile
[len(OverrideDir
):], NewFile
[0:len(OverrideDir
)]
276 return NewFile
[len(OverrideDir
) + 1:], \
277 NewFile
[0:len(OverrideDir
)]
279 NewFile
= GlobalData
.gALL_FILES
[os
.path
.normpath(os
.path
.join(Dir
, File
))]
282 if Dir
[-1] == os
.path
.sep
:
283 return NewFile
[len(Dir
):], NewFile
[0:len(Dir
)]
285 return NewFile
[len(Dir
) + 1:], NewFile
[0:len(Dir
)]
291 ## A dict which can access its keys and/or values orderly
293 # The class implements a new kind of dict which its keys or values can be
294 # accessed in the order they are added into the dict. It guarantees the order
295 # by making use of an internal list to keep a copy of keys.
297 class Sdict(IterableUserDict
):
301 IterableUserDict
.__init
__(self
)
306 def __setitem__(self
, Key
, Value
):
307 if Key
not in self
._key
_list
:
308 self
._key
_list
.append(Key
)
309 IterableUserDict
.__setitem
__(self
, Key
, Value
)
313 def __delitem__(self
, Key
):
314 self
._key
_list
.remove(Key
)
315 IterableUserDict
.__delitem
__(self
, Key
)
317 ## used in "for k in dict" loop to ensure the correct order
320 return self
.iterkeys()
325 return len(self
._key
_list
)
329 def __contains__(self
, Key
):
330 return Key
in self
._key
_list
334 def index(self
, Key
):
335 return self
._key
_list
.index(Key
)
339 def insert(self
, Key
, Newkey
, Newvalue
, Order
):
340 Index
= self
._key
_list
.index(Key
)
341 if Order
== 'BEFORE':
342 self
._key
_list
.insert(Index
, Newkey
)
343 IterableUserDict
.__setitem
__(self
, Newkey
, Newvalue
)
344 elif Order
== 'AFTER':
345 self
._key
_list
.insert(Index
+ 1, Newkey
)
346 IterableUserDict
.__setitem
__(self
, Newkey
, Newvalue
)
350 def append(self
, Sdict2
):
352 if Key
not in self
._key
_list
:
353 self
._key
_list
.append(Key
)
354 IterableUserDict
.__setitem
__(self
, Key
, Sdict2
[Key
])
357 def has_key(self
, Key
):
358 return Key
in self
._key
_list
364 IterableUserDict
.clear(self
)
366 ## Return a copy of keys
370 for Key
in self
._key
_list
:
374 ## Return a copy of values
378 for Key
in self
._key
_list
:
379 Values
.append(self
[Key
])
382 ## Return a copy of (key, value) list
386 for Key
in self
._key
_list
:
387 Items
.append((Key
, self
[Key
]))
393 return iter(self
.items())
395 ## Keys interation support
398 return iter(self
.keys())
400 ## Values interation support
402 def itervalues(self
):
403 return iter(self
.values())
405 ## Return value related to a key, and remove the (key, value) from the dict
407 def pop(self
, Key
, *Dv
):
409 if Key
in self
._key
_list
:
411 self
.__delitem
__(Key
)
416 ## Return (key, value) pair, and remove the (key, value) from the dict
419 Key
= self
._key
_list
[-1]
421 self
.__delitem
__(Key
)
425 def update(self
, Dict
=None, **Kwargs
):
427 for Key1
, Val1
in Dict
.items():
430 for Key1
, Val1
in Kwargs
.items():
435 # @param PathList: PathList
437 def CommonPath(PathList
):
438 Path1
= min(PathList
).split(os
.path
.sep
)
439 Path2
= max(PathList
).split(os
.path
.sep
)
440 for Index
in xrange(min(len(Path1
), len(Path2
))):
441 if Path1
[Index
] != Path2
[Index
]:
442 return os
.path
.sep
.join(Path1
[:Index
])
443 return os
.path
.sep
.join(Path1
)
447 class PathClass(object):
448 def __init__(self
, File
='', Root
='', AlterRoot
='', Type
='', IsBinary
=False,
449 Arch
='COMMON', ToolChainFamily
='', Target
='', TagName
='', \
452 self
.File
= str(File
)
453 if os
.path
.isabs(self
.File
):
457 self
.Root
= str(Root
)
458 self
.AlterRoot
= str(AlterRoot
)
461 # Remove any '.' and '..' in path
464 self
.Path
= os
.path
.normpath(os
.path
.join(self
.Root
, self
.File
))
465 self
.Root
= os
.path
.normpath(CommonPath([self
.Root
, self
.Path
]))
467 # eliminate the side-effect of 'C:'
469 if self
.Root
[-1] == ':':
470 self
.Root
+= os
.path
.sep
472 # file path should not start with path separator
474 if self
.Root
[-1] == os
.path
.sep
:
475 self
.File
= self
.Path
[len(self
.Root
):]
477 self
.File
= self
.Path
[len(self
.Root
) + 1:]
479 self
.Path
= os
.path
.normpath(self
.File
)
481 self
.SubDir
, self
.Name
= os
.path
.split(self
.File
)
482 self
.BaseName
, self
.Ext
= os
.path
.splitext(self
.Name
)
486 self
.Dir
= os
.path
.join(self
.Root
, self
.SubDir
)
490 self
.Dir
= self
.SubDir
495 self
.Type
= self
.Ext
.lower()
497 self
.IsBinary
= IsBinary
499 self
.TagName
= TagName
500 self
.ToolCode
= ToolCode
501 self
.ToolChainFamily
= ToolChainFamily
505 ## Convert the object of this class to a string
507 # Convert member Path of the class to a string
512 ## Override __eq__ function
514 # Check whether PathClass are the same
516 def __eq__(self
, Other
):
517 if type(Other
) == type(self
):
518 return self
.Path
== Other
.Path
520 return self
.Path
== str(Other
)
522 ## Override __hash__ function
524 # Use Path as key in hash table
527 return hash(self
.Path
)
531 def _GetFileKey(self
):
532 if self
._Key
is None:
533 self
._Key
= self
.Path
.upper()
537 def Validate(self
, Type
='', CaseSensitive
=True):
538 if GlobalData
.gCASE_INSENSITIVE
:
539 CaseSensitive
= False
540 if Type
and Type
.lower() != self
.Type
:
541 return ToolError
.FILE_TYPE_MISMATCH
, '%s (expect %s but got %s)' % \
542 (self
.File
, Type
, self
.Type
)
544 RealFile
, RealRoot
= RealPath2(self
.File
, self
.Root
, self
.AlterRoot
)
545 if not RealRoot
and not RealFile
:
548 RealFile
= os
.path
.join(self
.AlterRoot
, self
.File
)
550 RealFile
= os
.path
.join(self
.Root
, self
.File
)
551 return ToolError
.FILE_NOT_FOUND
, os
.path
.join(self
.AlterRoot
, RealFile
)
555 if RealRoot
!= self
.Root
or RealFile
!= self
.File
:
556 if CaseSensitive
and (RealFile
!= self
.File
or \
557 (RealRoot
!= self
.Root
and RealRoot
!= \
559 ErrorCode
= ToolError
.FILE_CASE_MISMATCH
560 ErrorInfo
= self
.File
+ '\n\t' + RealFile
+ \
563 self
.SubDir
, self
.Name
= os
.path
.split(RealFile
)
564 self
.BaseName
, self
.Ext
= os
.path
.splitext(self
.Name
)
566 self
.Dir
= os
.path
.join(RealRoot
, self
.SubDir
)
571 self
.Path
= os
.path
.join(RealRoot
, RealFile
)
572 return ErrorCode
, ErrorInfo
574 Key
= property(_GetFileKey
)
576 ## Get current workspace
578 # get WORKSPACE from environment variable if present,if not use current working directory as WORKSPACE
584 if "WORKSPACE" in environ
:
585 WorkspaceDir
= os
.path
.normpath(environ
["WORKSPACE"])
586 if not os
.path
.exists(WorkspaceDir
):
588 ToolError
.UPT_ENVIRON_MISSING_ERROR
,
589 ST
.ERR_WORKSPACE_NOTEXIST
,
590 ExtraData
="%s" % WorkspaceDir
)
592 WorkspaceDir
= os
.getcwd()
594 if WorkspaceDir
[-1] == ':':
595 WorkspaceDir
+= os
.sep
597 PackagesPath
= os
.environ
.get("PACKAGES_PATH")
598 mws
.setWs(WorkspaceDir
, PackagesPath
)
600 return WorkspaceDir
, mws
.PACKAGES_PATH
604 # use full path and workspace to get relative path
605 # the destination of this function is mainly to resolve the root path issue(like c: or c:\)
607 # @param Fullpath: a string of fullpath
608 # @param Workspace: a string of workspace
610 def GetRelativePath(Fullpath
, Workspace
):
613 if Workspace
.endswith(os
.sep
):
614 RelativePath
= Fullpath
[Fullpath
.upper().find(Workspace
.upper())+len(Workspace
):]
616 RelativePath
= Fullpath
[Fullpath
.upper().find(Workspace
.upper())+len(Workspace
)+1:]
620 ## Check whether all module types are in list
622 # check whether all module types (SUP_MODULE_LIST) are in list
624 # @param ModuleList: a list of ModuleType
626 def IsAllModuleList(ModuleList
):
627 NewModuleList
= [Module
.upper() for Module
in ModuleList
]
628 for Module
in SUP_MODULE_LIST
:
629 if Module
not in NewModuleList
:
634 ## Dictionary that use comment(GenericComment, TailComment) as value,
635 # if a new comment which key already in the dic is inserted, then the
636 # comment will be merged.
637 # Key is (Statement, SupArch), when TailComment is added, it will ident
638 # according to Statement
640 class MergeCommentDict(dict):
643 def __setitem__(self
, Key
, CommentVal
):
644 GenericComment
, TailComment
= CommentVal
646 OrigVal1
, OrigVal2
= dict.__getitem
__(self
, Key
)
648 dict.__setitem
__(self
, Key
, (OrigVal1
+ GenericComment
, OrigVal2 \
649 + len(Statement
) * ' ' + TailComment
))
651 dict.__setitem
__(self
, Key
, (GenericComment
, TailComment
))
655 def __getitem__(self
, Key
):
656 return dict.__getitem
__(self
, Key
)
659 ## GenDummyHelpTextObj
661 # @retval HelpTxt: Generated dummy help text object
663 def GenDummyHelpTextObj():
664 HelpTxt
= TextObject()
665 HelpTxt
.SetLang(TAB_LANGUAGE_EN_US
)
666 HelpTxt
.SetString(' ')
669 ## ConvertVersionToDecimal, the minor version should be within 0 - 99
670 # <HexVersion> ::= "0x" <Major> <Minor>
671 # <Major> ::= (a-fA-F0-9){4}
672 # <Minor> ::= (a-fA-F0-9){4}
673 # <DecVersion> ::= (0-65535) ["." (0-99)]
675 # @param StringIn: The string contains version defined in INF file.
676 # It can be Decimal or Hex
678 def ConvertVersionToDecimal(StringIn
):
679 if IsValidHexVersion(StringIn
):
680 Value
= int(StringIn
, 16)
682 Minor
= Value
& 0xFFFF
683 MinorStr
= str(Minor
)
684 if len(MinorStr
) == 1:
685 MinorStr
= '0' + MinorStr
686 return str(Major
) + '.' + MinorStr
688 if StringIn
.find(TAB_SPLIT
) != -1:
691 return StringIn
+ '.0'
694 # when StringIn is '', return it directly
698 ## GetHelpStringByRemoveHashKey
700 # Remove hash key at the header of string and return the remain.
702 # @param String: The string need to be processed.
704 def GetHelpStringByRemoveHashKey(String
):
706 PattenRemoveHashKey
= re
.compile(r
"^[#+\s]+", re
.DOTALL
)
707 String
= String
.strip()
711 LineList
= GetSplitValueList(String
, END_OF_LINE
)
712 for Line
in LineList
:
713 ValueList
= PattenRemoveHashKey
.split(Line
)
714 if len(ValueList
) == 1:
715 ReturnString
+= ValueList
[0] + END_OF_LINE
717 ReturnString
+= ValueList
[1] + END_OF_LINE
719 if ReturnString
.endswith('\n') and not ReturnString
.endswith('\n\n') and ReturnString
!= '\n':
720 ReturnString
= ReturnString
[:-1]
724 ## ConvPathFromAbsToRel
726 # Get relative file path from absolute path.
728 # @param Path: The string contain file absolute path.
729 # @param Root: The string contain the parent path of Path in.
732 def ConvPathFromAbsToRel(Path
, Root
):
733 Path
= os
.path
.normpath(Path
)
734 Root
= os
.path
.normpath(Root
)
735 FullPath
= os
.path
.normpath(os
.path
.join(Root
, Path
))
738 # If Path is absolute path.
739 # It should be in Root.
741 if os
.path
.isabs(Path
):
742 return FullPath
[FullPath
.find(Root
) + len(Root
) + 1:]
749 # Convert special characters to '_', '\' to '/'
750 # return converted path: Test!1.inf -> Test_1.inf
752 # @param Path: Path to be converted
754 def ConvertPath(Path
):
756 for Char
in Path
.strip():
757 if Char
.isalnum() or Char
in '.-_/':
758 RetPath
= RetPath
+ Char
760 RetPath
= RetPath
+ '/'
762 RetPath
= RetPath
+ '_'
767 # during install, convert the Spec string extract from UPD into INF allowable definition,
768 # the difference is period is allowed in the former (not the first letter) but not in the latter.
769 # return converted Spec string
771 # @param SpecStr: SpecStr to be converted
773 def ConvertSpec(SpecStr
):
776 if Char
.isalnum() or Char
== '_':
777 RetStr
= RetStr
+ Char
779 RetStr
= RetStr
+ '_'
786 # Judge two lists are identical(contain same item).
787 # The rule is elements in List A are in List B and elements in List B are in List A.
789 # @param ListA, ListB Lists need to be judged.
791 # @return True ListA and ListB are identical
792 # @return False ListA and ListB are different with each other
794 def IsEqualList(ListA
, ListB
):
799 if not ItemA
in ListB
:
803 if not ItemB
in ListA
:
810 # Convert item in ArchList if the start character is lower case.
811 # In UDP spec, Arch is only allowed as: [A-Z]([a-zA-Z0-9])*
813 # @param ArchList The ArchList need to be converted.
815 # @return NewList The ArchList been converted.
817 def ConvertArchList(ArchList
):
822 if type(ArchList
) == list:
823 for Arch
in ArchList
:
825 NewArchList
.append(Arch
)
826 elif type(ArchList
) == str:
827 ArchList
= ArchList
.upper()
828 NewArchList
.append(ArchList
)
832 ## ProcessLineExtender
834 # Process the LineExtender of Line in LineList.
835 # If one line ends with a line extender, then it will be combined together with next line.
837 # @param LineList The LineList need to be processed.
839 # @return NewList The ArchList been processed.
841 def ProcessLineExtender(LineList
):
844 while Count
< len(LineList
):
845 if LineList
[Count
].strip().endswith("\\") and Count
+ 1 < len(LineList
):
846 NewList
.append(LineList
[Count
].strip()[:-2] + LineList
[Count
+ 1])
849 NewList
.append(LineList
[Count
])
857 # Process EDK style comment in LineList: c style /* */ comment or cpp style // comment
860 # @param LineList The LineList need to be processed.
862 # @return LineList The LineList been processed.
863 # @return FirstPos Where Edk comment is first found, -1 if not found
865 def ProcessEdkComment(LineList
):
866 FindEdkBlockComment
= False
872 while(Count
< len(LineList
)):
873 Line
= LineList
[Count
].strip()
874 if Line
.startswith("/*"):
876 # handling c style comment
879 while Count
< len(LineList
):
880 Line
= LineList
[Count
].strip()
881 if Line
.endswith("*/"):
882 if (Count
== StartPos
) and Line
.strip() == '/*/':
886 FindEdkBlockComment
= True
890 if FindEdkBlockComment
:
893 for Index
in xrange(StartPos
, EndPos
+1):
895 FindEdkBlockComment
= False
896 elif Line
.find("//") != -1 and not Line
.startswith("#"):
898 # handling cpp style comment
900 LineList
[Count
] = Line
.replace("//", '#')
906 return LineList
, FirstPos
908 ## GetLibInstanceInfo
910 # Get the information from Library Instance INF file.
912 # @param string. A string start with # and followed by INF file path
913 # @param WorkSpace. The WorkSpace directory used to combined with INF file path.
915 # @return GUID, Version
916 def GetLibInstanceInfo(String
, WorkSpace
, LineNo
):
921 OrignalString
= String
922 String
= String
.strip()
926 # Remove "#" characters at the beginning
928 String
= GetHelpStringByRemoveHashKey(String
)
929 String
= String
.strip()
932 # Validate file name exist.
934 FullFileName
= os
.path
.normpath(os
.path
.realpath(os
.path
.join(WorkSpace
, String
)))
935 if not (ValidFile(FullFileName
)):
936 Logger
.Error("InfParser",
937 ToolError
.FORMAT_INVALID
,
938 ST
.ERR_FILELIST_EXIST
% (String
),
939 File
=GlobalData
.gINF_MODULE_NAME
,
941 ExtraData
=OrignalString
)
944 # Validate file exist/format.
946 if IsValidPath(String
, WorkSpace
):
947 IsValidFileFlag
= True
949 Logger
.Error("InfParser",
950 ToolError
.FORMAT_INVALID
,
951 ST
.ERR_INF_PARSER_FILE_NOT_EXIST_OR_NAME_INVALID
% (String
),
952 File
=GlobalData
.gINF_MODULE_NAME
,
954 ExtraData
=OrignalString
)
960 FInputfile
= open(FullFileName
, "rb", 0)
962 FileLinesList
= FInputfile
.readlines()
963 except BaseException
:
964 Logger
.Error("InfParser",
965 ToolError
.FILE_READ_FAILURE
,
966 ST
.ERR_FILE_OPEN_FAILURE
,
970 except BaseException
:
971 Logger
.Error("InfParser",
972 ToolError
.FILE_READ_FAILURE
,
973 ST
.ERR_FILE_OPEN_FAILURE
,
976 ReFileGuidPattern
= re
.compile("^\s*FILE_GUID\s*=.*$")
977 ReVerStringPattern
= re
.compile("^\s*VERSION_STRING\s*=.*$")
979 FileLinesList
= ProcessLineExtender(FileLinesList
)
981 for Line
in FileLinesList
:
982 if ReFileGuidPattern
.match(Line
):
983 FileGuidString
= Line
984 if ReVerStringPattern
.match(Line
):
988 FileGuidString
= GetSplitValueList(FileGuidString
, '=', 1)[1]
990 VerString
= GetSplitValueList(VerString
, '=', 1)[1]
992 return FileGuidString
, VerString
996 # Generate the local value for INF and DEC file. If Lang attribute not present, then use this value.
997 # If present, and there is no element without the Lang attribute, and one of the elements has the rfc1766 code is
998 # "en-x-tianocore", or "en-US" if "en-x-tianocore" was not found, or "en" if "en-US" was not found, or startswith 'en'
999 # if 'en' was not found, then use this value.
1000 # If multiple entries of a tag exist which have the same language code, use the last entry.
1002 # @param ValueList A list need to be processed.
1003 # @param UseFirstValue: True to use the first value, False to use the last value
1005 # @return LocalValue
1006 def GetLocalValue(ValueList
, UseFirstValue
=False):
1012 for (Key
, Value
) in ValueList
:
1013 if Key
== TAB_LANGUAGE_EN_X
:
1019 if Key
== TAB_LANGUAGE_EN_US
:
1025 if Key
== TAB_LANGUAGE_EN
:
1031 if Key
.startswith(TAB_LANGUAGE_EN
):
1058 ## GetCharIndexOutStr
1060 # Get comment character index outside a string
1062 # @param Line: The string to be checked
1063 # @param CommentCharacter: Comment char, used to ignore comment content
1067 def GetCharIndexOutStr(CommentCharacter
, Line
):
1074 # Check whether comment character is in a string
1077 for Index
in range(0, len(Line
)):
1078 if Line
[Index
] == '"':
1079 InString
= not InString
1080 elif Line
[Index
] == CommentCharacter
and InString
:
1082 elif Line
[Index
] == CommentCharacter
and (Index
+1) < len(Line
) and Line
[Index
+1] == CommentCharacter \
1087 ## ValidateUNIFilePath
1089 # Check the UNI file path
1091 # @param FilePath: The UNI file path
1093 def ValidateUNIFilePath(Path
):
1094 Suffix
= Path
[Path
.rfind(TAB_SPLIT
):]
1097 # Check if the suffix is one of the '.uni', '.UNI', '.Uni'
1099 if Suffix
not in TAB_UNI_FILE_SUFFIXS
:
1100 Logger
.Error("Unicode File Parser",
1101 ToolError
.FORMAT_INVALID
,
1102 Message
=ST
.ERR_UNI_FILE_SUFFIX_WRONG
,
1106 # Check if '..' in the file name(without suffixe)
1108 if (TAB_SPLIT
+ TAB_SPLIT
) in Path
:
1109 Logger
.Error("Unicode File Parser",
1110 ToolError
.FORMAT_INVALID
,
1111 Message
=ST
.ERR_UNI_FILE_NAME_INVALID
,
1115 # Check if the file name is valid according to the DEC and INF specification
1117 Pattern
= '[a-zA-Z0-9_][a-zA-Z0-9_\-\.]*'
1118 FileName
= Path
.replace(Suffix
, '')
1119 InvalidCh
= re
.sub(Pattern
, '', FileName
)
1121 Logger
.Error("Unicode File Parser",
1122 ToolError
.FORMAT_INVALID
,
1123 Message
=ST
.ERR_INF_PARSER_FILE_NOT_EXIST_OR_NAME_INVALID
,