2 # Common routines used by all tools
4 # Copyright (c) 2011 - 2014, 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
.String
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__
54 ## Convert GUID string in xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx style to C
57 # @param Guid: The GUID string
59 def GuidStringToGuidStructureString(Guid
):
60 GuidList
= Guid
.split('-')
62 for Index
in range(0, 3, 1):
63 Result
= Result
+ '0x' + GuidList
[Index
] + ', '
64 Result
= Result
+ '{0x' + GuidList
[3][0:2] + ', 0x' + GuidList
[3][2:4]
65 for Index
in range(0, 12, 2):
66 Result
= Result
+ ', 0x' + GuidList
[4][Index
:Index
+ 2]
70 ## Check whether GUID string is of format xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx
72 # @param GuidValue: The GUID value
74 def CheckGuidRegFormat(GuidValue
):
75 ## Regular expression used to find out register format of GUID
77 RegFormatGuidPattern
= re
.compile("^\s*([0-9a-fA-F]){8}-"
81 "([0-9a-fA-F]){12}\s*$")
83 if RegFormatGuidPattern
.match(GuidValue
):
89 ## Convert GUID string in C structure style to
90 # xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx
92 # @param GuidValue: The GUID value in C structure format
94 def GuidStructureStringToGuidString(GuidValue
):
95 GuidValueString
= GuidValue
.lower().replace("{", "").replace("}", "").\
96 replace(" ", "").replace(";", "")
97 GuidValueList
= GuidValueString
.split(",")
98 if len(GuidValueList
) != 11:
101 return "%08x-%04x-%04x-%02x%02x-%02x%02x%02x%02x%02x%02x" % (
102 int(GuidValueList
[0], 16),
103 int(GuidValueList
[1], 16),
104 int(GuidValueList
[2], 16),
105 int(GuidValueList
[3], 16),
106 int(GuidValueList
[4], 16),
107 int(GuidValueList
[5], 16),
108 int(GuidValueList
[6], 16),
109 int(GuidValueList
[7], 16),
110 int(GuidValueList
[8], 16),
111 int(GuidValueList
[9], 16),
112 int(GuidValueList
[10], 16)
114 except BaseException
:
117 ## Create directories
119 # @param Directory: The directory name
121 def CreateDirectory(Directory
):
122 if Directory
== None or Directory
.strip() == "":
125 if not access(Directory
, F_OK
):
127 except BaseException
:
131 ## Remove directories, including files and sub-directories in it
133 # @param Directory: The directory name
135 def RemoveDirectory(Directory
, Recursively
=False):
136 if Directory
== None or Directory
.strip() == "" or not \
137 os
.path
.exists(Directory
):
140 CurrentDirectory
= getcwd()
142 for File
in listdir("."):
143 if os
.path
.isdir(File
):
144 RemoveDirectory(File
, Recursively
)
147 chdir(CurrentDirectory
)
150 ## Store content in file
152 # This method is used to save file only when its content is changed. This is
153 # quite useful for "make" system to decide what will be re-built and what
156 # @param File: The path of file
157 # @param Content: The new content of the file
158 # @param IsBinaryFile: The flag indicating if the file is binary file
161 def SaveFileOnChange(File
, Content
, IsBinaryFile
=True):
163 Content
= Content
.replace("\n", linesep
)
165 if os
.path
.exists(File
):
167 if Content
== __FileHookOpen__(File
, "rb").read():
169 except BaseException
:
170 Logger
.Error(None, ToolError
.FILE_OPEN_FAILURE
, ExtraData
=File
)
172 CreateDirectory(os
.path
.dirname(File
))
174 FileFd
= __FileHookOpen__(File
, "wb")
175 FileFd
.write(Content
)
177 except BaseException
:
178 Logger
.Error(None, ToolError
.FILE_CREATE_FAILURE
, ExtraData
=File
)
182 ## Get all files of a directory
184 # @param Root: Root dir
185 # @param SkipList : The files need be skipped
187 def GetFiles(Root
, SkipList
=None, FullPath
=True):
188 OriPath
= os
.path
.normpath(Root
)
190 for Root
, Dirs
, Files
in walk(Root
):
192 for Item
in SkipList
:
198 if Dir
.startswith('.'):
202 if File
.startswith('.'):
204 File
= os
.path
.normpath(os
.path
.join(Root
, File
))
206 File
= File
[len(OriPath
) + 1:]
207 FileList
.append(File
)
211 ## Get all non-metadata files of a directory
213 # @param Root: Root Dir
214 # @param SkipList : List of path need be skipped
215 # @param FullPath: True if the returned file should be full path
216 # @param PrefixPath: the path that need to be added to the files found
217 # @return: the list of files found
219 def GetNonMetaDataFiles(Root
, SkipList
, FullPath
, PrefixPath
):
220 FileList
= GetFiles(Root
, SkipList
, FullPath
)
222 for File
in FileList
:
223 ExtName
= os
.path
.splitext(File
)[1]
225 # skip '.dec', '.inf', '.dsc', '.fdf' files
227 if ExtName
.lower() not in ['.dec', '.inf', '.dsc', '.fdf']:
228 NewFileList
.append(os
.path
.normpath(os
.path
.join(PrefixPath
, File
)))
232 ## Check if given file exists or not
234 # @param File: File name or path to be checked
235 # @param Dir: The directory the file is relative to
237 def ValidFile(File
, Ext
=None):
238 File
= File
.replace('\\', '/')
240 FileExt
= os
.path
.splitext(File
)[1]
241 if FileExt
.lower() != Ext
.lower():
243 if not os
.path
.exists(File
):
249 # @param File: File name or path to be checked
250 # @param Dir: The directory the file is relative to
251 # @param OverrideDir: The override directory
253 def RealPath(File
, Dir
='', OverrideDir
=''):
254 NewFile
= os
.path
.normpath(os
.path
.join(Dir
, File
))
255 NewFile
= GlobalData
.gALL_FILES
[NewFile
]
256 if not NewFile
and OverrideDir
:
257 NewFile
= os
.path
.normpath(os
.path
.join(OverrideDir
, File
))
258 NewFile
= GlobalData
.gALL_FILES
[NewFile
]
263 # @param File: File name or path to be checked
264 # @param Dir: The directory the file is relative to
265 # @param OverrideDir: The override directory
267 def RealPath2(File
, Dir
='', OverrideDir
=''):
269 NewFile
= GlobalData
.gALL_FILES
[os
.path
.normpath(os
.path
.join\
270 (OverrideDir
, File
))]
272 if OverrideDir
[-1] == os
.path
.sep
:
273 return NewFile
[len(OverrideDir
):], NewFile
[0:len(OverrideDir
)]
275 return NewFile
[len(OverrideDir
) + 1:], \
276 NewFile
[0:len(OverrideDir
)]
278 NewFile
= GlobalData
.gALL_FILES
[os
.path
.normpath(os
.path
.join(Dir
, File
))]
281 if Dir
[-1] == os
.path
.sep
:
282 return NewFile
[len(Dir
):], NewFile
[0:len(Dir
)]
284 return NewFile
[len(Dir
) + 1:], NewFile
[0:len(Dir
)]
290 ## A dict which can access its keys and/or values orderly
292 # The class implements a new kind of dict which its keys or values can be
293 # accessed in the order they are added into the dict. It guarantees the order
294 # by making use of an internal list to keep a copy of keys.
296 class Sdict(IterableUserDict
):
300 IterableUserDict
.__init
__(self
)
305 def __setitem__(self
, Key
, Value
):
306 if Key
not in self
._key
_list
:
307 self
._key
_list
.append(Key
)
308 IterableUserDict
.__setitem
__(self
, Key
, Value
)
312 def __delitem__(self
, Key
):
313 self
._key
_list
.remove(Key
)
314 IterableUserDict
.__delitem
__(self
, Key
)
316 ## used in "for k in dict" loop to ensure the correct order
319 return self
.iterkeys()
324 return len(self
._key
_list
)
328 def __contains__(self
, Key
):
329 return Key
in self
._key
_list
333 def index(self
, Key
):
334 return self
._key
_list
.index(Key
)
338 def insert(self
, Key
, Newkey
, Newvalue
, Order
):
339 Index
= self
._key
_list
.index(Key
)
340 if Order
== 'BEFORE':
341 self
._key
_list
.insert(Index
, Newkey
)
342 IterableUserDict
.__setitem
__(self
, Newkey
, Newvalue
)
343 elif Order
== 'AFTER':
344 self
._key
_list
.insert(Index
+ 1, Newkey
)
345 IterableUserDict
.__setitem
__(self
, Newkey
, Newvalue
)
349 def append(self
, Sdict2
):
351 if Key
not in self
._key
_list
:
352 self
._key
_list
.append(Key
)
353 IterableUserDict
.__setitem
__(self
, Key
, Sdict2
[Key
])
356 def has_key(self
, Key
):
357 return Key
in self
._key
_list
363 IterableUserDict
.clear(self
)
365 ## Return a copy of keys
369 for Key
in self
._key
_list
:
373 ## Return a copy of values
377 for Key
in self
._key
_list
:
378 Values
.append(self
[Key
])
381 ## Return a copy of (key, value) list
385 for Key
in self
._key
_list
:
386 Items
.append((Key
, self
[Key
]))
392 return iter(self
.items())
394 ## Keys interation support
397 return iter(self
.keys())
399 ## Values interation support
401 def itervalues(self
):
402 return iter(self
.values())
404 ## Return value related to a key, and remove the (key, value) from the dict
406 def pop(self
, Key
, *Dv
):
408 if Key
in self
._key
_list
:
410 self
.__delitem
__(Key
)
415 ## Return (key, value) pair, and remove the (key, value) from the dict
418 Key
= self
._key
_list
[-1]
420 self
.__delitem
__(Key
)
424 def update(self
, Dict
=None, **Kwargs
):
426 for Key1
, Val1
in Dict
.items():
429 for Key1
, Val1
in Kwargs
.items():
434 # @param PathList: PathList
436 def CommonPath(PathList
):
437 Path1
= min(PathList
).split(os
.path
.sep
)
438 Path2
= max(PathList
).split(os
.path
.sep
)
439 for Index
in xrange(min(len(Path1
), len(Path2
))):
440 if Path1
[Index
] != Path2
[Index
]:
441 return os
.path
.sep
.join(Path1
[:Index
])
442 return os
.path
.sep
.join(Path1
)
446 class PathClass(object):
447 def __init__(self
, File
='', Root
='', AlterRoot
='', Type
='', IsBinary
=False,
448 Arch
='COMMON', ToolChainFamily
='', Target
='', TagName
='', \
451 self
.File
= str(File
)
452 if os
.path
.isabs(self
.File
):
456 self
.Root
= str(Root
)
457 self
.AlterRoot
= str(AlterRoot
)
460 # Remove any '.' and '..' in path
463 self
.Path
= os
.path
.normpath(os
.path
.join(self
.Root
, self
.File
))
464 self
.Root
= os
.path
.normpath(CommonPath([self
.Root
, self
.Path
]))
466 # eliminate the side-effect of 'C:'
468 if self
.Root
[-1] == ':':
469 self
.Root
+= os
.path
.sep
471 # file path should not start with path separator
473 if self
.Root
[-1] == os
.path
.sep
:
474 self
.File
= self
.Path
[len(self
.Root
):]
476 self
.File
= self
.Path
[len(self
.Root
) + 1:]
478 self
.Path
= os
.path
.normpath(self
.File
)
480 self
.SubDir
, self
.Name
= os
.path
.split(self
.File
)
481 self
.BaseName
, self
.Ext
= os
.path
.splitext(self
.Name
)
485 self
.Dir
= os
.path
.join(self
.Root
, self
.SubDir
)
489 self
.Dir
= self
.SubDir
494 self
.Type
= self
.Ext
.lower()
496 self
.IsBinary
= IsBinary
498 self
.TagName
= TagName
499 self
.ToolCode
= ToolCode
500 self
.ToolChainFamily
= ToolChainFamily
504 ## Convert the object of this class to a string
506 # Convert member Path of the class to a string
511 ## Override __eq__ function
513 # Check whether PathClass are the same
515 def __eq__(self
, Other
):
516 if type(Other
) == type(self
):
517 return self
.Path
== Other
.Path
519 return self
.Path
== str(Other
)
521 ## Override __hash__ function
523 # Use Path as key in hash table
526 return hash(self
.Path
)
530 def _GetFileKey(self
):
531 if self
._Key
== None:
532 self
._Key
= self
.Path
.upper()
536 def Validate(self
, Type
='', CaseSensitive
=True):
537 if GlobalData
.gCASE_INSENSITIVE
:
538 CaseSensitive
= False
539 if Type
and Type
.lower() != self
.Type
:
540 return ToolError
.FILE_TYPE_MISMATCH
, '%s (expect %s but got %s)' % \
541 (self
.File
, Type
, self
.Type
)
543 RealFile
, RealRoot
= RealPath2(self
.File
, self
.Root
, self
.AlterRoot
)
544 if not RealRoot
and not RealFile
:
547 RealFile
= os
.path
.join(self
.AlterRoot
, self
.File
)
549 RealFile
= os
.path
.join(self
.Root
, self
.File
)
550 return ToolError
.FILE_NOT_FOUND
, os
.path
.join(self
.AlterRoot
, RealFile
)
554 if RealRoot
!= self
.Root
or RealFile
!= self
.File
:
555 if CaseSensitive
and (RealFile
!= self
.File
or \
556 (RealRoot
!= self
.Root
and RealRoot
!= \
558 ErrorCode
= ToolError
.FILE_CASE_MISMATCH
559 ErrorInfo
= self
.File
+ '\n\t' + RealFile
+ \
562 self
.SubDir
, self
.Name
= os
.path
.split(RealFile
)
563 self
.BaseName
, self
.Ext
= os
.path
.splitext(self
.Name
)
565 self
.Dir
= os
.path
.join(RealRoot
, self
.SubDir
)
570 self
.Path
= os
.path
.join(RealRoot
, RealFile
)
571 return ErrorCode
, ErrorInfo
573 Key
= property(_GetFileKey
)
575 ## Get current workspace
577 # get WORKSPACE from environment variable if present,if not use current working directory as WORKSPACE
583 if "WORKSPACE" in environ
:
584 WorkspaceDir
= os
.path
.normpath(environ
["WORKSPACE"])
585 if not os
.path
.exists(WorkspaceDir
):
587 ToolError
.UPT_ENVIRON_MISSING_ERROR
,
588 ST
.ERR_WORKSPACE_NOTEXIST
,
589 ExtraData
="%s" % WorkspaceDir
)
591 WorkspaceDir
= os
.getcwd()
593 if WorkspaceDir
[-1] == ':':
594 WorkspaceDir
+= os
.sep
599 # use full path and workspace to get relative path
600 # the destination of this function is mainly to resolve the root path issue(like c: or c:\)
602 # @param Fullpath: a string of fullpath
603 # @param Workspace: a string of workspace
605 def GetRelativePath(Fullpath
, Workspace
):
608 if Workspace
.endswith(os
.sep
):
609 RelativePath
= Fullpath
[Fullpath
.upper().find(Workspace
.upper())+len(Workspace
):]
611 RelativePath
= Fullpath
[Fullpath
.upper().find(Workspace
.upper())+len(Workspace
)+1:]
615 ## Check whether all module types are in list
617 # check whether all module types (SUP_MODULE_LIST) are in list
619 # @param ModuleList: a list of ModuleType
621 def IsAllModuleList(ModuleList
):
622 NewModuleList
= [Module
.upper() for Module
in ModuleList
]
623 for Module
in SUP_MODULE_LIST
:
624 if Module
not in NewModuleList
:
629 ## Dictionary that use comment(GenericComment, TailComment) as value,
630 # if a new comment which key already in the dic is inserted, then the
631 # comment will be merged.
632 # Key is (Statement, SupArch), when TailComment is added, it will ident
633 # according to Statement
635 class MergeCommentDict(dict):
638 def __setitem__(self
, Key
, CommentVal
):
639 GenericComment
, TailComment
= CommentVal
641 OrigVal1
, OrigVal2
= dict.__getitem
__(self
, Key
)
643 dict.__setitem
__(self
, Key
, (OrigVal1
+ GenericComment
, OrigVal2 \
644 + len(Statement
) * ' ' + TailComment
))
646 dict.__setitem
__(self
, Key
, (GenericComment
, TailComment
))
650 def __getitem__(self
, Key
):
651 return dict.__getitem
__(self
, Key
)
654 ## GenDummyHelpTextObj
656 # @retval HelpTxt: Generated dummy help text object
658 def GenDummyHelpTextObj():
659 HelpTxt
= TextObject()
660 HelpTxt
.SetLang(TAB_LANGUAGE_EN_US
)
661 HelpTxt
.SetString(' ')
664 ## ConvertVersionToDecimal, the minor version should be within 0 - 99
665 # <HexVersion> ::= "0x" <Major> <Minor>
666 # <Major> ::= (a-fA-F0-9){4}
667 # <Minor> ::= (a-fA-F0-9){4}
668 # <DecVersion> ::= (0-65535) ["." (0-99)]
670 # @param StringIn: The string contains version defined in INF file.
671 # It can be Decimal or Hex
673 def ConvertVersionToDecimal(StringIn
):
674 if IsValidHexVersion(StringIn
):
675 Value
= int(StringIn
, 16)
677 Minor
= Value
& 0xFFFF
678 MinorStr
= str(Minor
)
679 if len(MinorStr
) == 1:
680 MinorStr
= '0' + MinorStr
681 return str(Major
) + '.' + MinorStr
683 if StringIn
.find(TAB_SPLIT
) != -1:
686 return StringIn
+ '.0'
689 # when StringIn is '', return it directly
693 ## GetHelpStringByRemoveHashKey
695 # Remove hash key at the header of string and return the remain.
697 # @param String: The string need to be processed.
699 def GetHelpStringByRemoveHashKey(String
):
701 PattenRemoveHashKey
= re
.compile(r
"^[#+\s]+", re
.DOTALL
)
702 String
= String
.strip()
706 LineList
= GetSplitValueList(String
, END_OF_LINE
)
707 for Line
in LineList
:
708 ValueList
= PattenRemoveHashKey
.split(Line
)
709 if len(ValueList
) == 1:
710 ReturnString
+= ValueList
[0] + END_OF_LINE
712 ReturnString
+= ValueList
[1] + END_OF_LINE
714 if ReturnString
.endswith('\n') and not ReturnString
.endswith('\n\n') and ReturnString
!= '\n':
715 ReturnString
= ReturnString
[:-1]
719 ## ConvPathFromAbsToRel
721 # Get relative file path from absolute path.
723 # @param Path: The string contain file absolute path.
724 # @param Root: The string contain the parent path of Path in.
727 def ConvPathFromAbsToRel(Path
, Root
):
728 Path
= os
.path
.normpath(Path
)
729 Root
= os
.path
.normpath(Root
)
730 FullPath
= os
.path
.normpath(os
.path
.join(Root
, Path
))
733 # If Path is absolute path.
734 # It should be in Root.
736 if os
.path
.isabs(Path
):
737 return FullPath
[FullPath
.find(Root
) + len(Root
) + 1:]
744 # Convert special characters to '_', '\' to '/'
745 # return converted path: Test!1.inf -> Test_1.inf
747 # @param Path: Path to be converted
749 def ConvertPath(Path
):
751 for Char
in Path
.strip():
752 if Char
.isalnum() or Char
in '.-_/':
753 RetPath
= RetPath
+ Char
755 RetPath
= RetPath
+ '/'
757 RetPath
= RetPath
+ '_'
762 # during install, convert the Spec string extract from UPD into INF allowable definition,
763 # the difference is period is allowed in the former (not the first letter) but not in the latter.
764 # return converted Spec string
766 # @param SpecStr: SpecStr to be converted
768 def ConvertSpec(SpecStr
):
771 if Char
.isalnum() or Char
== '_':
772 RetStr
= RetStr
+ Char
774 RetStr
= RetStr
+ '_'
781 # Judge two lists are identical(contain same item).
782 # The rule is elements in List A are in List B and elements in List B are in List A.
784 # @param ListA, ListB Lists need to be judged.
786 # @return True ListA and ListB are identical
787 # @return False ListA and ListB are different with each other
789 def IsEqualList(ListA
, ListB
):
794 if not ItemA
in ListB
:
798 if not ItemB
in ListA
:
805 # Convert item in ArchList if the start character is lower case.
806 # In UDP spec, Arch is only allowed as: [A-Z]([a-zA-Z0-9])*
808 # @param ArchList The ArchList need to be converted.
810 # @return NewList The ArchList been converted.
812 def ConvertArchList(ArchList
):
817 if type(ArchList
) == list:
818 for Arch
in ArchList
:
820 NewArchList
.append(Arch
)
821 elif type(ArchList
) == str:
822 ArchList
= ArchList
.upper()
823 NewArchList
.append(ArchList
)
827 ## ProcessLineExtender
829 # Process the LineExtender of Line in LineList.
830 # If one line ends with a line extender, then it will be combined together with next line.
832 # @param LineList The LineList need to be processed.
834 # @return NewList The ArchList been processed.
836 def ProcessLineExtender(LineList
):
839 while Count
< len(LineList
):
840 if LineList
[Count
].strip().endswith("\\") and Count
+ 1 < len(LineList
):
841 NewList
.append(LineList
[Count
].strip()[:-2] + LineList
[Count
+ 1])
844 NewList
.append(LineList
[Count
])
852 # Process EDK style comment in LineList: c style /* */ comment or cpp style // comment
855 # @param LineList The LineList need to be processed.
857 # @return LineList The LineList been processed.
858 # @return FirstPos Where Edk comment is first found, -1 if not found
860 def ProcessEdkComment(LineList
):
861 FindEdkBlockComment
= False
867 while(Count
< len(LineList
)):
868 Line
= LineList
[Count
].strip()
869 if Line
.startswith("/*"):
871 # handling c style comment
874 while Count
< len(LineList
):
875 Line
= LineList
[Count
].strip()
876 if Line
.endswith("*/"):
877 if (Count
== StartPos
) and Line
.strip() == '/*/':
881 FindEdkBlockComment
= True
885 if FindEdkBlockComment
:
888 for Index
in xrange(StartPos
, EndPos
+1):
890 FindEdkBlockComment
= False
891 elif Line
.find("//") != -1 and not Line
.startswith("#"):
893 # handling cpp style comment
895 LineList
[Count
] = Line
.replace("//", '#')
901 return LineList
, FirstPos
903 ## GetLibInstanceInfo
905 # Get the information from Library Instance INF file.
907 # @param string. A string start with # and followed by INF file path
908 # @param WorkSpace. The WorkSpace directory used to combined with INF file path.
910 # @return GUID, Version
911 def GetLibInstanceInfo(String
, WorkSpace
, LineNo
):
916 OrignalString
= String
917 String
= String
.strip()
921 # Remove "#" characters at the beginning
923 String
= GetHelpStringByRemoveHashKey(String
)
924 String
= String
.strip()
927 # Validate file name exist.
929 FullFileName
= os
.path
.normpath(os
.path
.realpath(os
.path
.join(WorkSpace
, String
)))
930 if not (ValidFile(FullFileName
)):
931 Logger
.Error("InfParser",
932 ToolError
.FORMAT_INVALID
,
933 ST
.ERR_FILELIST_EXIST
% (String
),
934 File
=GlobalData
.gINF_MODULE_NAME
,
936 ExtraData
=OrignalString
)
939 # Validate file exist/format.
941 if IsValidPath(String
, WorkSpace
):
942 IsValidFileFlag
= True
944 Logger
.Error("InfParser",
945 ToolError
.FORMAT_INVALID
,
946 ST
.ERR_INF_PARSER_FILE_NOT_EXIST_OR_NAME_INVALID
% (String
),
947 File
=GlobalData
.gINF_MODULE_NAME
,
949 ExtraData
=OrignalString
)
955 FInputfile
= open(FullFileName
, "rb", 0)
957 FileLinesList
= FInputfile
.readlines()
958 except BaseException
:
959 Logger
.Error("InfParser",
960 ToolError
.FILE_READ_FAILURE
,
961 ST
.ERR_FILE_OPEN_FAILURE
,
965 except BaseException
:
966 Logger
.Error("InfParser",
967 ToolError
.FILE_READ_FAILURE
,
968 ST
.ERR_FILE_OPEN_FAILURE
,
971 ReFileGuidPattern
= re
.compile("^\s*FILE_GUID\s*=.*$")
972 ReVerStringPattern
= re
.compile("^\s*VERSION_STRING\s*=.*$")
974 FileLinesList
= ProcessLineExtender(FileLinesList
)
976 for Line
in FileLinesList
:
977 if ReFileGuidPattern
.match(Line
):
978 FileGuidString
= Line
979 if ReVerStringPattern
.match(Line
):
983 FileGuidString
= GetSplitValueList(FileGuidString
, '=', 1)[1]
985 VerString
= GetSplitValueList(VerString
, '=', 1)[1]
987 return FileGuidString
, VerString
991 # Generate the local value for INF and DEC file. If Lang attribute not present, then use this value.
992 # If present, and there is no element without the Lang attribute, and one of the elements has the rfc1766 code is
993 # "en-x-tianocore", or "en-US" if "en-x-tianocore" was not found, or "en" if "en-US" was not found, or startswith 'en'
994 # if 'en' was not found, then use this value.
995 # If multiple entries of a tag exist which have the same language code, use the last entry.
997 # @param ValueList A list need to be processed.
998 # @param UseFirstValue: True to use the first value, False to use the last value
1000 # @return LocalValue
1001 def GetLocalValue(ValueList
, UseFirstValue
=False):
1007 for (Key
, Value
) in ValueList
:
1008 if Key
== TAB_LANGUAGE_EN_X
:
1014 if Key
== TAB_LANGUAGE_EN_US
:
1020 if Key
== TAB_LANGUAGE_EN
:
1026 if Key
.startswith(TAB_LANGUAGE_EN
):
1053 ## GetCharIndexOutStr
1055 # Get comment character index outside a string
1057 # @param Line: The string to be checked
1058 # @param CommentCharacter: Comment char, used to ignore comment content
1062 def GetCharIndexOutStr(CommentCharacter
, Line
):
1069 # Check whether comment character is in a string
1072 for Index
in range(0, len(Line
)):
1073 if Line
[Index
] == '"':
1074 InString
= not InString
1075 elif Line
[Index
] == CommentCharacter
and InString
:
1077 elif Line
[Index
] == CommentCharacter
and (Index
+1) < len(Line
) and Line
[Index
+1] == CommentCharacter \
1082 ## ValidateUNIFilePath
1084 # Check the UNI file path
1086 # @param FilePath: The UNI file path
1088 def ValidateUNIFilePath(Path
):
1089 Suffix
= Path
[Path
.rfind(TAB_SPLIT
):]
1092 # Check if the suffix is one of the '.uni', '.UNI', '.Uni'
1094 if Suffix
not in TAB_UNI_FILE_SUFFIXS
:
1095 Logger
.Error("Unicode File Parser",
1096 ToolError
.FORMAT_INVALID
,
1097 Message
=ST
.ERR_UNI_FILE_SUFFIX_WRONG
,
1101 # Check if '..' in the file name(without suffixe)
1103 if (TAB_SPLIT
+ TAB_SPLIT
) in Path
:
1104 Logger
.Error("Unicode File Parser",
1105 ToolError
.FORMAT_INVALID
,
1106 Message
=ST
.ERR_UNI_FILE_NAME_INVALID
,
1110 # Check if the file name is valid according to the DEC and INF specification
1112 Pattern
= '[a-zA-Z0-9_][a-zA-Z0-9_\-\.]*'
1113 FileName
= Path
.replace(Suffix
, '')
1114 InvalidCh
= re
.sub(Pattern
, '', FileName
)
1116 Logger
.Error("Unicode File Parser",
1117 ToolError
.FORMAT_INVALID
,
1118 Message
=ST
.ERR_INF_PARSER_FILE_NOT_EXIST_OR_NAME_INVALID
,