-## @file
-# Common routines used by all tools
-#
-# Copyright (c) 2011, Intel Corporation. All rights reserved.<BR>
-#
-# This program and the accompanying materials are licensed and made available
-# under the terms and conditions of the BSD License which accompanies this
-# distribution. The full text of the license may be found at
-# http://opensource.org/licenses/bsd-license.php
-#
-# THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
-# WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
-#
-
-'''
-Misc
-'''
-
-##
-# Import Modules
-#
-import os.path
-from os import access
-from os import F_OK
-from os import makedirs
-from os import getcwd
-from os import chdir
-from os import listdir
-from os import remove
-from os import rmdir
-from os import linesep
-from os import walk
-from os import environ
-import re
-from UserDict import IterableUserDict
-
-import Logger.Log as Logger
-from Logger import StringTable as ST
-from Logger import ToolError
-from Library import GlobalData
-from Library.DataType import SUP_MODULE_LIST
-from Library.DataType import END_OF_LINE
-from Library.DataType import TAB_SPLIT
-from Library.DataType import LANGUAGE_EN_US
-from Library.String import GetSplitValueList
-from Library.ParserValidate import IsValidHexVersion
-from Library.ParserValidate import IsValidPath
-from Object.POM.CommonObject import TextObject
-
-## Convert GUID string in xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx style to C
-# structure style
-#
-# @param Guid: The GUID string
-#
-def GuidStringToGuidStructureString(Guid):
- GuidList = Guid.split('-')
- Result = '{'
- for Index in range(0, 3, 1):
- Result = Result + '0x' + GuidList[Index] + ', '
- Result = Result + '{0x' + GuidList[3][0:2] + ', 0x' + GuidList[3][2:4]
- for Index in range(0, 12, 2):
- Result = Result + ', 0x' + GuidList[4][Index:Index + 2]
- Result += '}}'
- return Result
-
-## Check whether GUID string is of format xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx
-#
-# @param GuidValue: The GUID value
-#
-def CheckGuidRegFormat(GuidValue):
- ## Regular expression used to find out register format of GUID
- #
- RegFormatGuidPattern = re.compile("^\s*([0-9a-fA-F]){8}-"
- "([0-9a-fA-F]){4}-"
- "([0-9a-fA-F]){4}-"
- "([0-9a-fA-F]){4}-"
- "([0-9a-fA-F]){12}\s*$")
-
- if RegFormatGuidPattern.match(GuidValue):
- return True
- else:
- return False
-
-
-## Convert GUID string in C structure style to
-# xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx
-#
-# @param GuidValue: The GUID value in C structure format
-#
-def GuidStructureStringToGuidString(GuidValue):
- GuidValueString = GuidValue.lower().replace("{", "").replace("}", "").\
- replace(" ", "").replace(";", "")
- GuidValueList = GuidValueString.split(",")
- if len(GuidValueList) != 11:
- return ''
- try:
- return "%08x-%04x-%04x-%02x%02x-%02x%02x%02x%02x%02x%02x" % (
- int(GuidValueList[0], 16),
- int(GuidValueList[1], 16),
- int(GuidValueList[2], 16),
- int(GuidValueList[3], 16),
- int(GuidValueList[4], 16),
- int(GuidValueList[5], 16),
- int(GuidValueList[6], 16),
- int(GuidValueList[7], 16),
- int(GuidValueList[8], 16),
- int(GuidValueList[9], 16),
- int(GuidValueList[10], 16)
- )
- except BaseException:
- return ''
-
-## Create directories
-#
-# @param Directory: The directory name
-#
-def CreateDirectory(Directory):
- if Directory == None or Directory.strip() == "":
- return True
- try:
- if not access(Directory, F_OK):
- makedirs(Directory)
- except BaseException:
- return False
- return True
-
-## Remove directories, including files and sub-directories in it
-#
-# @param Directory: The directory name
-#
-def RemoveDirectory(Directory, Recursively=False):
- if Directory == None or Directory.strip() == "" or not \
- os.path.exists(Directory):
- return
- if Recursively:
- CurrentDirectory = getcwd()
- chdir(Directory)
- for File in listdir("."):
- if os.path.isdir(File):
- RemoveDirectory(File, Recursively)
- else:
- remove(File)
- chdir(CurrentDirectory)
- rmdir(Directory)
-
-## Store content in file
-#
-# This method is used to save file only when its content is changed. This is
-# quite useful for "make" system to decide what will be re-built and what
-# won't.
-#
-# @param File: The path of file
-# @param Content: The new content of the file
-# @param IsBinaryFile: The flag indicating if the file is binary file
-# or not
-#
-def SaveFileOnChange(File, Content, IsBinaryFile=True):
- if not IsBinaryFile:
- Content = Content.replace("\n", linesep)
-
- if os.path.exists(File):
- try:
- if Content == open(File, "rb").read():
- return False
- except BaseException:
- Logger.Error(None, ToolError.FILE_OPEN_FAILURE, ExtraData=File)
-
- CreateDirectory(os.path.dirname(File))
- try:
- FileFd = open(File, "wb")
- FileFd.write(Content)
- FileFd.close()
- except BaseException:
- Logger.Error(None, ToolError.FILE_CREATE_FAILURE, ExtraData=File)
-
- return True
-
-## Get all files of a directory
-#
-# @param Root: Root dir
-# @param SkipList : The files need be skipped
-#
-def GetFiles(Root, SkipList=None, FullPath=True):
- OriPath = os.path.normpath(Root)
- FileList = []
- for Root, Dirs, Files in walk(Root):
- if SkipList:
- for Item in SkipList:
- if Item in Dirs:
- Dirs.remove(Item)
- for Dir in Dirs:
- if Dir.startswith('.'):
- Dirs.remove(Dir)
-
- for File in Files:
- if File.startswith('.'):
- continue
- File = os.path.normpath(os.path.join(Root, File))
- if not FullPath:
- File = File[len(OriPath) + 1:]
- FileList.append(File)
-
- return FileList
-
-## Get all non-metadata files of a directory
-#
-# @param Root: Root Dir
-# @param SkipList : List of path need be skipped
-# @param FullPath: True if the returned file should be full path
-# @param PrefixPath: the path that need to be added to the files found
-# @return: the list of files found
-#
-def GetNonMetaDataFiles(Root, SkipList, FullPath, PrefixPath):
- FileList = GetFiles(Root, SkipList, FullPath)
- NewFileList = []
- for File in FileList:
- ExtName = os.path.splitext(File)[1]
- #
- # skip '.dec', '.inf', '.dsc', '.fdf' files
- #
- if ExtName.lower() not in ['.dec', '.inf', '.dsc', '.fdf']:
- NewFileList.append(os.path.normpath(os.path.join(PrefixPath, File)))
-
- return NewFileList
-
-## Check if given file exists or not
-#
-# @param File: File name or path to be checked
-# @param Dir: The directory the file is relative to
-#
-def ValidFile(File, Ext=None):
- File = File.replace('\\', '/')
- if Ext != None:
- FileExt = os.path.splitext(File)[1]
- if FileExt.lower() != Ext.lower():
- return False
- if not os.path.exists(File):
- return False
- return True
-
-## RealPath
-#
-# @param File: File name or path to be checked
-# @param Dir: The directory the file is relative to
-# @param OverrideDir: The override directory
-#
-def RealPath(File, Dir='', OverrideDir=''):
- NewFile = os.path.normpath(os.path.join(Dir, File))
- NewFile = GlobalData.gALL_FILES[NewFile]
- if not NewFile and OverrideDir:
- NewFile = os.path.normpath(os.path.join(OverrideDir, File))
- NewFile = GlobalData.gALL_FILES[NewFile]
- return NewFile
-
-## RealPath2
-#
-# @param File: File name or path to be checked
-# @param Dir: The directory the file is relative to
-# @param OverrideDir: The override directory
-#
-def RealPath2(File, Dir='', OverrideDir=''):
- if OverrideDir:
- NewFile = GlobalData.gALL_FILES[os.path.normpath(os.path.join\
- (OverrideDir, File))]
- if NewFile:
- if OverrideDir[-1] == os.path.sep:
- return NewFile[len(OverrideDir):], NewFile[0:len(OverrideDir)]
- else:
- return NewFile[len(OverrideDir) + 1:], \
- NewFile[0:len(OverrideDir)]
-
- NewFile = GlobalData.gALL_FILES[os.path.normpath(os.path.join(Dir, File))]
- if NewFile:
- if Dir:
- if Dir[-1] == os.path.sep:
- return NewFile[len(Dir):], NewFile[0:len(Dir)]
- else:
- return NewFile[len(Dir) + 1:], NewFile[0:len(Dir)]
- else:
- return NewFile, ''
-
- return None, None
-
-## A dict which can access its keys and/or values orderly
-#
-# The class implements a new kind of dict which its keys or values can be
-# accessed in the order they are added into the dict. It guarantees the order
-# by making use of an internal list to keep a copy of keys.
-#
-class Sdict(IterableUserDict):
- ## Constructor
- #
- def __init__(self):
- IterableUserDict.__init__(self)
- self._key_list = []
-
- ## [] operator
- #
- def __setitem__(self, Key, Value):
- if Key not in self._key_list:
- self._key_list.append(Key)
- IterableUserDict.__setitem__(self, Key, Value)
-
- ## del operator
- #
- def __delitem__(self, Key):
- self._key_list.remove(Key)
- IterableUserDict.__delitem__(self, Key)
-
- ## used in "for k in dict" loop to ensure the correct order
- #
- def __iter__(self):
- return self.iterkeys()
-
- ## len() support
- #
- def __len__(self):
- return len(self._key_list)
-
- ## "in" test support
- #
- def __contains__(self, Key):
- return Key in self._key_list
-
- ## indexof support
- #
- def index(self, Key):
- return self._key_list.index(Key)
-
- ## insert support
- #
- def insert(self, Key, Newkey, Newvalue, Order):
- Index = self._key_list.index(Key)
- if Order == 'BEFORE':
- self._key_list.insert(Index, Newkey)
- IterableUserDict.__setitem__(self, Newkey, Newvalue)
- elif Order == 'AFTER':
- self._key_list.insert(Index + 1, Newkey)
- IterableUserDict.__setitem__(self, Newkey, Newvalue)
-
- ## append support
- #
- def append(self, Sdict2):
- for Key in Sdict2:
- if Key not in self._key_list:
- self._key_list.append(Key)
- IterableUserDict.__setitem__(self, Key, Sdict2[Key])
- ## hash key
- #
- def has_key(self, Key):
- return Key in self._key_list
-
- ## Empty the dict
- #
- def clear(self):
- self._key_list = []
- IterableUserDict.clear(self)
-
- ## Return a copy of keys
- #
- def keys(self):
- Keys = []
- for Key in self._key_list:
- Keys.append(Key)
- return Keys
-
- ## Return a copy of values
- #
- def values(self):
- Values = []
- for Key in self._key_list:
- Values.append(self[Key])
- return Values
-
- ## Return a copy of (key, value) list
- #
- def items(self):
- Items = []
- for Key in self._key_list:
- Items.append((Key, self[Key]))
- return Items
-
- ## Iteration support
- #
- def iteritems(self):
- return iter(self.items())
-
- ## Keys interation support
- #
- def iterkeys(self):
- return iter(self.keys())
-
- ## Values interation support
- #
- def itervalues(self):
- return iter(self.values())
-
- ## Return value related to a key, and remove the (key, value) from the dict
- #
- def pop(self, Key, *Dv):
- Value = None
- if Key in self._key_list:
- Value = self[Key]
- self.__delitem__(Key)
- elif len(Dv) != 0 :
- Value = Dv[0]
- return Value
-
- ## Return (key, value) pair, and remove the (key, value) from the dict
- #
- def popitem(self):
- Key = self._key_list[-1]
- Value = self[Key]
- self.__delitem__(Key)
- return Key, Value
- ## update method
- #
- def update(self, Dict=None, **Kwargs):
- if Dict != None:
- for Key1, Val1 in Dict.items():
- self[Key1] = Val1
- if len(Kwargs):
- for Key1, Val1 in Kwargs.items():
- self[Key1] = Val1
-
-## CommonPath
-#
-# @param PathList: PathList
-#
-def CommonPath(PathList):
- Path1 = min(PathList).split(os.path.sep)
- Path2 = max(PathList).split(os.path.sep)
- for Index in xrange(min(len(Path1), len(Path2))):
- if Path1[Index] != Path2[Index]:
- return os.path.sep.join(Path1[:Index])
- return os.path.sep.join(Path1)
-
-## PathClass
-#
-class PathClass(object):
- def __init__(self, File='', Root='', AlterRoot='', Type='', IsBinary=False,
- Arch='COMMON', ToolChainFamily='', Target='', TagName='', \
- ToolCode=''):
- self.Arch = Arch
- self.File = str(File)
- if os.path.isabs(self.File):
- self.Root = ''
- self.AlterRoot = ''
- else:
- self.Root = str(Root)
- self.AlterRoot = str(AlterRoot)
-
- #
- # Remove any '.' and '..' in path
- #
- if self.Root:
- self.Path = os.path.normpath(os.path.join(self.Root, self.File))
- self.Root = os.path.normpath(CommonPath([self.Root, self.Path]))
- #
- # eliminate the side-effect of 'C:'
- #
- if self.Root[-1] == ':':
- self.Root += os.path.sep
- #
- # file path should not start with path separator
- #
- if self.Root[-1] == os.path.sep:
- self.File = self.Path[len(self.Root):]
- else:
- self.File = self.Path[len(self.Root) + 1:]
- else:
- self.Path = os.path.normpath(self.File)
-
- self.SubDir, self.Name = os.path.split(self.File)
- self.BaseName, self.Ext = os.path.splitext(self.Name)
-
- if self.Root:
- if self.SubDir:
- self.Dir = os.path.join(self.Root, self.SubDir)
- else:
- self.Dir = self.Root
- else:
- self.Dir = self.SubDir
-
- if IsBinary:
- self.Type = Type
- else:
- self.Type = self.Ext.lower()
-
- self.IsBinary = IsBinary
- self.Target = Target
- self.TagName = TagName
- self.ToolCode = ToolCode
- self.ToolChainFamily = ToolChainFamily
-
- self._Key = None
-
- ## Convert the object of this class to a string
- #
- # Convert member Path of the class to a string
- #
- def __str__(self):
- return self.Path
-
- ## Override __eq__ function
- #
- # Check whether PathClass are the same
- #
- def __eq__(self, Other):
- if type(Other) == type(self):
- return self.Path == Other.Path
- else:
- return self.Path == str(Other)
-
- ## Override __hash__ function
- #
- # Use Path as key in hash table
- #
- def __hash__(self):
- return hash(self.Path)
-
- ## _GetFileKey
- #
- def _GetFileKey(self):
- if self._Key == None:
- self._Key = self.Path.upper()
- return self._Key
- ## Validate
- #
- def Validate(self, Type='', CaseSensitive=True):
- if GlobalData.gCASE_INSENSITIVE:
- CaseSensitive = False
- if Type and Type.lower() != self.Type:
- return ToolError.FILE_TYPE_MISMATCH, '%s (expect %s but got %s)' % \
- (self.File, Type, self.Type)
-
- RealFile, RealRoot = RealPath2(self.File, self.Root, self.AlterRoot)
- if not RealRoot and not RealFile:
- RealFile = self.File
- if self.AlterRoot:
- RealFile = os.path.join(self.AlterRoot, self.File)
- elif self.Root:
- RealFile = os.path.join(self.Root, self.File)
- return ToolError.FILE_NOT_FOUND, os.path.join(self.AlterRoot, RealFile)
-
- ErrorCode = 0
- ErrorInfo = ''
- if RealRoot != self.Root or RealFile != self.File:
- if CaseSensitive and (RealFile != self.File or \
- (RealRoot != self.Root and RealRoot != \
- self.AlterRoot)):
- ErrorCode = ToolError.FILE_CASE_MISMATCH
- ErrorInfo = self.File + '\n\t' + RealFile + \
- " [in file system]"
-
- self.SubDir, self.Name = os.path.split(RealFile)
- self.BaseName, self.Ext = os.path.splitext(self.Name)
- if self.SubDir:
- self.Dir = os.path.join(RealRoot, self.SubDir)
- else:
- self.Dir = RealRoot
- self.File = RealFile
- self.Root = RealRoot
- self.Path = os.path.join(RealRoot, RealFile)
- return ErrorCode, ErrorInfo
-
- Key = property(_GetFileKey)
-
-## Check environment variables
-#
-# Check environment variables that must be set for build. Currently they are
-#
-# WORKSPACE The directory all packages/platforms start from
-# EDK_TOOLS_PATH The directory contains all tools needed by the build
-# PATH $(EDK_TOOLS_PATH)/Bin/<sys> must be set in PATH
-#
-# If any of above environment variable is not set or has error, the build
-# will be broken.
-#
-def CheckEnvVariable():
- #
- # check WORKSPACE
- #
- if "WORKSPACE" not in environ:
- Logger.Error("UPT",
- ToolError.UPT_ENVIRON_MISSING_ERROR,
- ST.ERR_NOT_FOUND_ENVIRONMENT,
- ExtraData="WORKSPACE")
-
- WorkspaceDir = os.path.normpath(environ["WORKSPACE"])
- if not os.path.exists(WorkspaceDir):
- Logger.Error("UPT",
- ToolError.UPT_ENVIRON_MISSING_ERROR,
- ST.ERR_WORKSPACE_NOTEXIST,
- ExtraData="%s" % WorkspaceDir)
- elif ' ' in WorkspaceDir:
- Logger.Error("UPT",
- ToolError.FORMAT_NOT_SUPPORTED,
- ST.ERR_SPACE_NOTALLOWED,
- ExtraData=WorkspaceDir)
-
-## Check whether all module types are in list
-#
-# check whether all module types (SUP_MODULE_LIST) are in list
-#
-# @param ModuleList: a list of ModuleType
-#
-def IsAllModuleList(ModuleList):
- NewModuleList = [Module.upper() for Module in ModuleList]
- for Module in SUP_MODULE_LIST:
- if Module not in NewModuleList:
- return False
- else:
- return True
-
-## Dictionary that use comment(GenericComment, TailComment) as value,
-# if a new comment which key already in the dic is inserted, then the
-# comment will be merged.
-# Key is (Statement, SupArch), when TailComment is added, it will ident
-# according to Statement
-#
-class MergeCommentDict(dict):
- ## []= operator
- #
- def __setitem__(self, Key, CommentVal):
- GenericComment, TailComment = CommentVal
- if Key in self:
- OrigVal1, OrigVal2 = dict.__getitem__(self, Key)
- Statement = Key[0]
- dict.__setitem__(self, Key, (OrigVal1 + GenericComment, OrigVal2 \
- + len(Statement) * ' ' + TailComment))
- else:
- dict.__setitem__(self, Key, (GenericComment, TailComment))
-
- ## =[] operator
- #
- def __getitem__(self, Key):
- return dict.__getitem__(self, Key)
-
-
-## GenDummyHelpTextObj
-#
-# @retval HelpTxt: Generated dummy help text object
-#
-def GenDummyHelpTextObj():
- HelpTxt = TextObject()
- HelpTxt.SetLang(LANGUAGE_EN_US)
- HelpTxt.SetString(' ')
- return HelpTxt
-
-## ConvertVersionToDecimal, the minor version should be within 0 - 99
-# <HexVersion> ::= "0x" <Major> <Minor>
-# <Major> ::= (a-fA-F0-9){4}
-# <Minor> ::= (a-fA-F0-9){4}
-# <DecVersion> ::= (0-65535) ["." (0-99)]
-#
-# @param StringIn: The string contains version defined in INF file.
-# It can be Decimal or Hex
-#
-def ConvertVersionToDecimal(StringIn):
- if IsValidHexVersion(StringIn):
- Value = int(StringIn, 16)
- Major = Value >> 16
- Minor = Value & 0xFFFF
- MinorStr = str(Minor)
- if len(MinorStr) == 1:
- MinorStr = '0' + MinorStr
- return str(Major) + '.' + MinorStr
- else:
- if StringIn.find(TAB_SPLIT) != -1:
- return StringIn
- elif StringIn:
- return StringIn + '.0'
- else:
- #
- # when StringIn is '', return it directly
- #
- return StringIn
-
-## GetHelpStringByRemoveHashKey
-#
-# Remove hash key at the header of string and return the remain.
-#
-# @param String: The string need to be processed.
-#
-def GetHelpStringByRemoveHashKey(String):
- ReturnString = ''
- PattenRemoveHashKey = re.compile(r"^[#+\s]+", re.DOTALL)
- String = String.strip()
- if String == '':
- return String
-
- LineList = GetSplitValueList(String, END_OF_LINE)
- for Line in LineList:
- ValueList = PattenRemoveHashKey.split(Line)
- if len(ValueList) == 1:
- ReturnString += ValueList[0] + END_OF_LINE
- else:
- ReturnString += ValueList[1] + END_OF_LINE
-
- if ReturnString.endswith('\n') and not ReturnString.endswith('\n\n') and ReturnString != '\n':
- ReturnString = ReturnString[:-1]
-
- return ReturnString
-
-## ConvPathFromAbsToRel
-#
-# Get relative file path from absolute path.
-#
-# @param Path: The string contain file absolute path.
-# @param Root: The string contain the parent path of Path in.
-#
-#
-def ConvPathFromAbsToRel(Path, Root):
- Path = os.path.normpath(Path)
- Root = os.path.normpath(Root)
- FullPath = os.path.normpath(os.path.join(Root, Path))
-
- #
- # If Path is absolute path.
- # It should be in Root.
- #
- if os.path.isabs(Path):
- return FullPath[FullPath.find(Root) + len(Root) + 1:]
-
- else:
- return Path
-
-## ConvertPath
-#
-# Convert special characters to '_', '\' to '/'
-# return converted path: Test!1.inf -> Test_1.inf
-#
-# @param Path: Path to be converted
-#
-def ConvertPath(Path):
- RetPath = ''
- for Char in Path.strip():
- if Char.isalnum() or Char in '.-_/':
- RetPath = RetPath + Char
- elif Char == '\\':
- RetPath = RetPath + '/'
- else:
- RetPath = RetPath + '_'
- return RetPath
-
-## ConvertSpec
-#
-# during install, convert the Spec string extract from UPD into INF allowable definition,
-# the difference is period is allowed in the former (not the first letter) but not in the latter.
-# return converted Spec string
-#
-# @param SpecStr: SpecStr to be converted
-#
-def ConvertSpec(SpecStr):
- RetStr = ''
- for Char in SpecStr:
- if Char.isalnum() or Char == '_':
- RetStr = RetStr + Char
- else:
- RetStr = RetStr + '_'
-
- return RetStr
-
-
-## IsEqualList
-#
-# Judge two lists are identical(contain same item).
-# The rule is elements in List A are in List B and elements in List B are in List A.
-#
-# @param ListA, ListB Lists need to be judged.
-#
-# @return True ListA and ListB are identical
-# @return False ListA and ListB are different with each other
-#
-def IsEqualList(ListA, ListB):
- if ListA == ListB:
- return True
-
- for ItemA in ListA:
- if not ItemA in ListB:
- return False
-
- for ItemB in ListB:
- if not ItemB in ListA:
- return False
-
- return True
-
-## ConvertArchList
-#
-# Convert item in ArchList if the start character is lower case.
-# In UDP spec, Arch is only allowed as: [A-Z]([a-zA-Z0-9])*
-#
-# @param ArchList The ArchList need to be converted.
-#
-# @return NewList The ArchList been converted.
-#
-def ConvertArchList(ArchList):
- NewArchList = []
- if not ArchList:
- return NewArchList
-
- if type(ArchList) == list:
- for Arch in ArchList:
- Arch = Arch.upper()
- NewArchList.append(Arch)
- elif type(ArchList) == str:
- ArchList = ArchList.upper()
- NewArchList.append(ArchList)
-
- return NewArchList
-
-## ProcessLineExtender
-#
-# Process the LineExtender of Line in LineList.
-# If one line ends with a line extender, then it will be combined together with next line.
-#
-# @param LineList The LineList need to be processed.
-#
-# @return NewList The ArchList been processed.
-#
-def ProcessLineExtender(LineList):
- NewList = []
- Count = 0
- while Count < len(LineList):
- if LineList[Count].strip().endswith("\\") and Count + 1 < len(LineList):
- NewList.append(LineList[Count].strip()[:-2] + LineList[Count + 1])
- Count = Count + 1
- else:
- NewList.append(LineList[Count])
-
- Count = Count + 1
-
- return NewList
-
-## ProcessEdkComment
-#
-# Process EDK style comment in LineList: c style /* */ comment or cpp style // comment
-#
-#
-# @param LineList The LineList need to be processed.
-#
-# @return LineList The LineList been processed.
-# @return FirstPos Where Edk comment is first found, -1 if not found
-#
-def ProcessEdkComment(LineList):
- FindEdkBlockComment = False
- Count = 0
- StartPos = -1
- EndPos = -1
- FirstPos = -1
-
- while(Count < len(LineList)):
- Line = LineList[Count].strip()
- if Line.startswith("/*"):
- #
- # handling c style comment
- #
- StartPos = Count
- while Count < len(LineList):
- Line = LineList[Count].strip()
- if Line.endswith("*/"):
- if (Count == StartPos) and Line.strip() == '/*/':
- Count = Count + 1
- continue
- EndPos = Count
- FindEdkBlockComment = True
- break
- Count = Count + 1
-
- if FindEdkBlockComment:
- if FirstPos == -1:
- FirstPos = StartPos
- for Index in xrange(StartPos, EndPos+1):
- LineList[Index] = ''
- FindEdkBlockComment = False
- elif Line.find("//") != -1:
- #
- # handling cpp style comment
- #
- LineList[Count] = Line.replace("//", '#')
- if FirstPos == -1:
- FirstPos = Count
-
- Count = Count + 1
-
- return LineList, FirstPos
-
-## GetLibInstanceInfo
-#
-# Get the information from Library Instance INF file.
-#
-# @param string. A string start with # and followed by INF file path
-# @param WorkSpace. The WorkSpace directory used to combined with INF file path.
-#
-# @return GUID, Version
-def GetLibInstanceInfo(String, WorkSpace, LineNo):
-
- FileGuidString = ""
- VerString = ""
-
- OrignalString = String
- String = String.strip()
- if not String:
- return None, None
- #
- # Remove "#" characters at the beginning
- #
- String = GetHelpStringByRemoveHashKey(String)
- String = String.strip()
-
- #
- # Validate file name exist.
- #
- FullFileName = os.path.normpath(os.path.realpath(os.path.join(WorkSpace, String)))
- if not (ValidFile(FullFileName)):
- Logger.Error("InfParser",
- ToolError.FORMAT_INVALID,
- ST.ERR_FILELIST_EXIST % (String),
- File=GlobalData.gINF_MODULE_NAME,
- Line=LineNo,
- ExtraData=OrignalString)
-
- #
- # Validate file exist/format.
- #
- if IsValidPath(String, WorkSpace):
- IsValidFileFlag = True
- else:
- Logger.Error("InfParser",
- ToolError.FORMAT_INVALID,
- ST.ERR_INF_PARSER_FILE_NOT_EXIST_OR_NAME_INVALID % (String),
- File=GlobalData.gINF_MODULE_NAME,
- Line=LineNo,
- ExtraData=OrignalString)
- return False
- if IsValidFileFlag:
- FileLinesList = []
-
- try:
- FInputfile = open(FullFileName, "rb", 0)
- try:
- FileLinesList = FInputfile.readlines()
- except BaseException:
- Logger.Error("InfParser",
- ToolError.FILE_READ_FAILURE,
- ST.ERR_FILE_OPEN_FAILURE,
- File=FullFileName)
- finally:
- FInputfile.close()
- except BaseException:
- Logger.Error("InfParser",
- ToolError.FILE_READ_FAILURE,
- ST.ERR_FILE_OPEN_FAILURE,
- File=FullFileName)
-
- ReFileGuidPattern = re.compile("^\s*FILE_GUID\s*=.*$")
- ReVerStringPattern = re.compile("^\s*VERSION_STRING\s*=.*$")
-
- FileLinesList = ProcessLineExtender(FileLinesList)
-
- for Line in FileLinesList:
- if ReFileGuidPattern.match(Line):
- FileGuidString = Line
- if ReVerStringPattern.match(Line):
- VerString = Line
-
- if FileGuidString:
- FileGuidString = GetSplitValueList(FileGuidString, '=', 1)[1]
- if VerString:
- VerString = GetSplitValueList(VerString, '=', 1)[1]
-
- return FileGuidString, VerString
+## @file\r
+# Common routines used by all tools\r
+#\r
+# Copyright (c) 2011 - 2019, Intel Corporation. All rights reserved.<BR>\r
+#\r
+# SPDX-License-Identifier: BSD-2-Clause-Patent\r
+#\r
+\r
+'''\r
+Misc\r
+'''\r
+\r
+##\r
+# Import Modules\r
+#\r
+import os.path\r
+from os import access\r
+from os import F_OK\r
+from os import makedirs\r
+from os import getcwd\r
+from os import chdir\r
+from os import listdir\r
+from os import remove\r
+from os import rmdir\r
+from os import linesep\r
+from os import walk\r
+from os import environ\r
+import re\r
+from collections import OrderedDict as Sdict\r
+\r
+import Logger.Log as Logger\r
+from Logger import StringTable as ST\r
+from Logger import ToolError\r
+from Library import GlobalData\r
+from Library.DataType import SUP_MODULE_LIST\r
+from Library.DataType import END_OF_LINE\r
+from Library.DataType import TAB_SPLIT\r
+from Library.DataType import TAB_LANGUAGE_EN_US\r
+from Library.DataType import TAB_LANGUAGE_EN\r
+from Library.DataType import TAB_LANGUAGE_EN_X\r
+from Library.DataType import TAB_UNI_FILE_SUFFIXS\r
+from Library.StringUtils import GetSplitValueList\r
+from Library.ParserValidate import IsValidHexVersion\r
+from Library.ParserValidate import IsValidPath\r
+from Object.POM.CommonObject import TextObject\r
+from Core.FileHook import __FileHookOpen__\r
+from Common.MultipleWorkspace import MultipleWorkspace as mws\r
+\r
+## Convert GUID string in xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx style to C\r
+# structure style\r
+#\r
+# @param Guid: The GUID string\r
+#\r
+def GuidStringToGuidStructureString(Guid):\r
+ GuidList = Guid.split('-')\r
+ Result = '{'\r
+ for Index in range(0, 3, 1):\r
+ Result = Result + '0x' + GuidList[Index] + ', '\r
+ Result = Result + '{0x' + GuidList[3][0:2] + ', 0x' + GuidList[3][2:4]\r
+ for Index in range(0, 12, 2):\r
+ Result = Result + ', 0x' + GuidList[4][Index:Index + 2]\r
+ Result += '}}'\r
+ return Result\r
+\r
+## Check whether GUID string is of format xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx\r
+#\r
+# @param GuidValue: The GUID value\r
+#\r
+def CheckGuidRegFormat(GuidValue):\r
+ ## Regular expression used to find out register format of GUID\r
+ #\r
+ RegFormatGuidPattern = re.compile("^\s*([0-9a-fA-F]){8}-"\r
+ "([0-9a-fA-F]){4}-"\r
+ "([0-9a-fA-F]){4}-"\r
+ "([0-9a-fA-F]){4}-"\r
+ "([0-9a-fA-F]){12}\s*$")\r
+\r
+ if RegFormatGuidPattern.match(GuidValue):\r
+ return True\r
+ else:\r
+ return False\r
+\r
+\r
+## Convert GUID string in C structure style to\r
+# xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx\r
+#\r
+# @param GuidValue: The GUID value in C structure format\r
+#\r
+def GuidStructureStringToGuidString(GuidValue):\r
+ GuidValueString = GuidValue.lower().replace("{", "").replace("}", "").\\r
+ replace(" ", "").replace(";", "")\r
+ GuidValueList = GuidValueString.split(",")\r
+ if len(GuidValueList) != 11:\r
+ return ''\r
+ try:\r
+ return "%08x-%04x-%04x-%02x%02x-%02x%02x%02x%02x%02x%02x" % (\r
+ int(GuidValueList[0], 16),\r
+ int(GuidValueList[1], 16),\r
+ int(GuidValueList[2], 16),\r
+ int(GuidValueList[3], 16),\r
+ int(GuidValueList[4], 16),\r
+ int(GuidValueList[5], 16),\r
+ int(GuidValueList[6], 16),\r
+ int(GuidValueList[7], 16),\r
+ int(GuidValueList[8], 16),\r
+ int(GuidValueList[9], 16),\r
+ int(GuidValueList[10], 16)\r
+ )\r
+ except BaseException:\r
+ return ''\r
+\r
+## Create directories\r
+#\r
+# @param Directory: The directory name\r
+#\r
+def CreateDirectory(Directory):\r
+ if Directory is None or Directory.strip() == "":\r
+ return True\r
+ try:\r
+ if not access(Directory, F_OK):\r
+ makedirs(Directory)\r
+ except BaseException:\r
+ return False\r
+ return True\r
+\r
+## Remove directories, including files and sub-directories in it\r
+#\r
+# @param Directory: The directory name\r
+#\r
+def RemoveDirectory(Directory, Recursively=False):\r
+ if Directory is None or Directory.strip() == "" or not \\r
+ os.path.exists(Directory):\r
+ return\r
+ if Recursively:\r
+ CurrentDirectory = getcwd()\r
+ chdir(Directory)\r
+ for File in listdir("."):\r
+ if os.path.isdir(File):\r
+ RemoveDirectory(File, Recursively)\r
+ else:\r
+ remove(File)\r
+ chdir(CurrentDirectory)\r
+ rmdir(Directory)\r
+\r
+## Store content in file\r
+#\r
+# This method is used to save file only when its content is changed. This is\r
+# quite useful for "make" system to decide what will be re-built and what\r
+# won't.\r
+#\r
+# @param File: The path of file\r
+# @param Content: The new content of the file\r
+# @param IsBinaryFile: The flag indicating if the file is binary file\r
+# or not\r
+#\r
+def SaveFileOnChange(File, Content, IsBinaryFile=True):\r
+ if os.path.exists(File):\r
+ if IsBinaryFile:\r
+ try:\r
+ if Content == __FileHookOpen__(File, "rb").read():\r
+ return False\r
+ except BaseException:\r
+ Logger.Error(None, ToolError.FILE_OPEN_FAILURE, ExtraData=File)\r
+ else:\r
+ try:\r
+ if Content == __FileHookOpen__(File, "r").read():\r
+ return False\r
+ except BaseException:\r
+ Logger.Error(None, ToolError.FILE_OPEN_FAILURE, ExtraData=File)\r
+\r
+ CreateDirectory(os.path.dirname(File))\r
+ if IsBinaryFile:\r
+ try:\r
+ FileFd = __FileHookOpen__(File, "wb")\r
+ FileFd.write(Content)\r
+ FileFd.close()\r
+ except BaseException:\r
+ Logger.Error(None, ToolError.FILE_CREATE_FAILURE, ExtraData=File)\r
+ else:\r
+ try:\r
+ FileFd = __FileHookOpen__(File, "w")\r
+ FileFd.write(Content)\r
+ FileFd.close()\r
+ except BaseException:\r
+ Logger.Error(None, ToolError.FILE_CREATE_FAILURE, ExtraData=File)\r
+\r
+ return True\r
+\r
+## Get all files of a directory\r
+#\r
+# @param Root: Root dir\r
+# @param SkipList : The files need be skipped\r
+#\r
+def GetFiles(Root, SkipList=None, FullPath=True):\r
+ OriPath = os.path.normpath(Root)\r
+ FileList = []\r
+ for Root, Dirs, Files in walk(Root):\r
+ if SkipList:\r
+ for Item in SkipList:\r
+ if Item in Dirs:\r
+ Dirs.remove(Item)\r
+ if Item in Files:\r
+ Files.remove(Item)\r
+ for Dir in Dirs:\r
+ if Dir.startswith('.'):\r
+ Dirs.remove(Dir)\r
+\r
+ for File in Files:\r
+ if File.startswith('.'):\r
+ continue\r
+ File = os.path.normpath(os.path.join(Root, File))\r
+ if not FullPath:\r
+ File = File[len(OriPath) + 1:]\r
+ FileList.append(File)\r
+\r
+ return FileList\r
+\r
+## Get all non-metadata files of a directory\r
+#\r
+# @param Root: Root Dir\r
+# @param SkipList : List of path need be skipped\r
+# @param FullPath: True if the returned file should be full path\r
+# @param PrefixPath: the path that need to be added to the files found\r
+# @return: the list of files found\r
+#\r
+def GetNonMetaDataFiles(Root, SkipList, FullPath, PrefixPath):\r
+ FileList = GetFiles(Root, SkipList, FullPath)\r
+ NewFileList = []\r
+ for File in FileList:\r
+ ExtName = os.path.splitext(File)[1]\r
+ #\r
+ # skip '.dec', '.inf', '.dsc', '.fdf' files\r
+ #\r
+ if ExtName.lower() not in ['.dec', '.inf', '.dsc', '.fdf']:\r
+ NewFileList.append(os.path.normpath(os.path.join(PrefixPath, File)))\r
+\r
+ return NewFileList\r
+\r
+## Check if given file exists or not\r
+#\r
+# @param File: File name or path to be checked\r
+# @param Dir: The directory the file is relative to\r
+#\r
+def ValidFile(File, Ext=None):\r
+ File = File.replace('\\', '/')\r
+ if Ext is not None:\r
+ FileExt = os.path.splitext(File)[1]\r
+ if FileExt.lower() != Ext.lower():\r
+ return False\r
+ if not os.path.exists(File):\r
+ return False\r
+ return True\r
+\r
+## RealPath\r
+#\r
+# @param File: File name or path to be checked\r
+# @param Dir: The directory the file is relative to\r
+# @param OverrideDir: The override directory\r
+#\r
+def RealPath(File, Dir='', OverrideDir=''):\r
+ NewFile = os.path.normpath(os.path.join(Dir, File))\r
+ NewFile = GlobalData.gALL_FILES[NewFile]\r
+ if not NewFile and OverrideDir:\r
+ NewFile = os.path.normpath(os.path.join(OverrideDir, File))\r
+ NewFile = GlobalData.gALL_FILES[NewFile]\r
+ return NewFile\r
+\r
+## RealPath2\r
+#\r
+# @param File: File name or path to be checked\r
+# @param Dir: The directory the file is relative to\r
+# @param OverrideDir: The override directory\r
+#\r
+def RealPath2(File, Dir='', OverrideDir=''):\r
+ if OverrideDir:\r
+ NewFile = GlobalData.gALL_FILES[os.path.normpath(os.path.join\\r
+ (OverrideDir, File))]\r
+ if NewFile:\r
+ if OverrideDir[-1] == os.path.sep:\r
+ return NewFile[len(OverrideDir):], NewFile[0:len(OverrideDir)]\r
+ else:\r
+ return NewFile[len(OverrideDir) + 1:], \\r
+ NewFile[0:len(OverrideDir)]\r
+\r
+ NewFile = GlobalData.gALL_FILES[os.path.normpath(os.path.join(Dir, File))]\r
+ if NewFile:\r
+ if Dir:\r
+ if Dir[-1] == os.path.sep:\r
+ return NewFile[len(Dir):], NewFile[0:len(Dir)]\r
+ else:\r
+ return NewFile[len(Dir) + 1:], NewFile[0:len(Dir)]\r
+ else:\r
+ return NewFile, ''\r
+\r
+ return None, None\r
+\r
+## CommonPath\r
+#\r
+# @param PathList: PathList\r
+#\r
+def CommonPath(PathList):\r
+ Path1 = min(PathList).split(os.path.sep)\r
+ Path2 = max(PathList).split(os.path.sep)\r
+ for Index in range(min(len(Path1), len(Path2))):\r
+ if Path1[Index] != Path2[Index]:\r
+ return os.path.sep.join(Path1[:Index])\r
+ return os.path.sep.join(Path1)\r
+\r
+## PathClass\r
+#\r
+class PathClass(object):\r
+ def __init__(self, File='', Root='', AlterRoot='', Type='', IsBinary=False,\r
+ Arch='COMMON', ToolChainFamily='', Target='', TagName='', \\r
+ ToolCode=''):\r
+ self.Arch = Arch\r
+ self.File = str(File)\r
+ if os.path.isabs(self.File):\r
+ self.Root = ''\r
+ self.AlterRoot = ''\r
+ else:\r
+ self.Root = str(Root)\r
+ self.AlterRoot = str(AlterRoot)\r
+\r
+ #\r
+ # Remove any '.' and '..' in path\r
+ #\r
+ if self.Root:\r
+ self.Path = os.path.normpath(os.path.join(self.Root, self.File))\r
+ self.Root = os.path.normpath(CommonPath([self.Root, self.Path]))\r
+ #\r
+ # eliminate the side-effect of 'C:'\r
+ #\r
+ if self.Root[-1] == ':':\r
+ self.Root += os.path.sep\r
+ #\r
+ # file path should not start with path separator\r
+ #\r
+ if self.Root[-1] == os.path.sep:\r
+ self.File = self.Path[len(self.Root):]\r
+ else:\r
+ self.File = self.Path[len(self.Root) + 1:]\r
+ else:\r
+ self.Path = os.path.normpath(self.File)\r
+\r
+ self.SubDir, self.Name = os.path.split(self.File)\r
+ self.BaseName, self.Ext = os.path.splitext(self.Name)\r
+\r
+ if self.Root:\r
+ if self.SubDir:\r
+ self.Dir = os.path.join(self.Root, self.SubDir)\r
+ else:\r
+ self.Dir = self.Root\r
+ else:\r
+ self.Dir = self.SubDir\r
+\r
+ if IsBinary:\r
+ self.Type = Type\r
+ else:\r
+ self.Type = self.Ext.lower()\r
+\r
+ self.IsBinary = IsBinary\r
+ self.Target = Target\r
+ self.TagName = TagName\r
+ self.ToolCode = ToolCode\r
+ self.ToolChainFamily = ToolChainFamily\r
+\r
+ self._Key = None\r
+\r
+ ## Convert the object of this class to a string\r
+ #\r
+ # Convert member Path of the class to a string\r
+ #\r
+ def __str__(self):\r
+ return self.Path\r
+\r
+ ## Override __eq__ function\r
+ #\r
+ # Check whether PathClass are the same\r
+ #\r
+ def __eq__(self, Other):\r
+ if isinstance(Other, type(self)):\r
+ return self.Path == Other.Path\r
+ else:\r
+ return self.Path == str(Other)\r
+\r
+ ## Override __hash__ function\r
+ #\r
+ # Use Path as key in hash table\r
+ #\r
+ def __hash__(self):\r
+ return hash(self.Path)\r
+\r
+ ## _GetFileKey\r
+ #\r
+ def _GetFileKey(self):\r
+ if self._Key is None:\r
+ self._Key = self.Path.upper()\r
+ return self._Key\r
+ ## Validate\r
+ #\r
+ def Validate(self, Type='', CaseSensitive=True):\r
+ if GlobalData.gCASE_INSENSITIVE:\r
+ CaseSensitive = False\r
+ if Type and Type.lower() != self.Type:\r
+ return ToolError.FILE_TYPE_MISMATCH, '%s (expect %s but got %s)' % \\r
+ (self.File, Type, self.Type)\r
+\r
+ RealFile, RealRoot = RealPath2(self.File, self.Root, self.AlterRoot)\r
+ if not RealRoot and not RealFile:\r
+ RealFile = self.File\r
+ if self.AlterRoot:\r
+ RealFile = os.path.join(self.AlterRoot, self.File)\r
+ elif self.Root:\r
+ RealFile = os.path.join(self.Root, self.File)\r
+ return ToolError.FILE_NOT_FOUND, os.path.join(self.AlterRoot, RealFile)\r
+\r
+ ErrorCode = 0\r
+ ErrorInfo = ''\r
+ if RealRoot != self.Root or RealFile != self.File:\r
+ if CaseSensitive and (RealFile != self.File or \\r
+ (RealRoot != self.Root and RealRoot != \\r
+ self.AlterRoot)):\r
+ ErrorCode = ToolError.FILE_CASE_MISMATCH\r
+ ErrorInfo = self.File + '\n\t' + RealFile + \\r
+ " [in file system]"\r
+\r
+ self.SubDir, self.Name = os.path.split(RealFile)\r
+ self.BaseName, self.Ext = os.path.splitext(self.Name)\r
+ if self.SubDir:\r
+ self.Dir = os.path.join(RealRoot, self.SubDir)\r
+ else:\r
+ self.Dir = RealRoot\r
+ self.File = RealFile\r
+ self.Root = RealRoot\r
+ self.Path = os.path.join(RealRoot, RealFile)\r
+ return ErrorCode, ErrorInfo\r
+\r
+ Key = property(_GetFileKey)\r
+\r
+## Get current workspace\r
+#\r
+# get WORKSPACE from environment variable if present,if not use current working directory as WORKSPACE\r
+#\r
+def GetWorkspace():\r
+ #\r
+ # check WORKSPACE\r
+ #\r
+ if "WORKSPACE" in environ:\r
+ WorkspaceDir = os.path.normpath(environ["WORKSPACE"])\r
+ if not os.path.exists(WorkspaceDir):\r
+ Logger.Error("UPT",\r
+ ToolError.UPT_ENVIRON_MISSING_ERROR,\r
+ ST.ERR_WORKSPACE_NOTEXIST,\r
+ ExtraData="%s" % WorkspaceDir)\r
+ else:\r
+ WorkspaceDir = os.getcwd()\r
+\r
+ if WorkspaceDir[-1] == ':':\r
+ WorkspaceDir += os.sep\r
+\r
+ PackagesPath = os.environ.get("PACKAGES_PATH")\r
+ mws.setWs(WorkspaceDir, PackagesPath)\r
+\r
+ return WorkspaceDir, mws.PACKAGES_PATH\r
+\r
+## Get relative path\r
+#\r
+# use full path and workspace to get relative path\r
+# the destination of this function is mainly to resolve the root path issue(like c: or c:\)\r
+#\r
+# @param Fullpath: a string of fullpath\r
+# @param Workspace: a string of workspace\r
+#\r
+def GetRelativePath(Fullpath, Workspace):\r
+\r
+ RelativePath = ''\r
+ if Workspace.endswith(os.sep):\r
+ RelativePath = Fullpath[Fullpath.upper().find(Workspace.upper())+len(Workspace):]\r
+ else:\r
+ RelativePath = Fullpath[Fullpath.upper().find(Workspace.upper())+len(Workspace)+1:]\r
+\r
+ return RelativePath\r
+\r
+## Check whether all module types are in list\r
+#\r
+# check whether all module types (SUP_MODULE_LIST) are in list\r
+#\r
+# @param ModuleList: a list of ModuleType\r
+#\r
+def IsAllModuleList(ModuleList):\r
+ NewModuleList = [Module.upper() for Module in ModuleList]\r
+ for Module in SUP_MODULE_LIST:\r
+ if Module not in NewModuleList:\r
+ return False\r
+ else:\r
+ return True\r
+\r
+## Dictionary that use comment(GenericComment, TailComment) as value,\r
+# if a new comment which key already in the dic is inserted, then the\r
+# comment will be merged.\r
+# Key is (Statement, SupArch), when TailComment is added, it will ident\r
+# according to Statement\r
+#\r
+class MergeCommentDict(dict):\r
+ ## []= operator\r
+ #\r
+ def __setitem__(self, Key, CommentVal):\r
+ GenericComment, TailComment = CommentVal\r
+ if Key in self:\r
+ OrigVal1, OrigVal2 = dict.__getitem__(self, Key)\r
+ Statement = Key[0]\r
+ dict.__setitem__(self, Key, (OrigVal1 + GenericComment, OrigVal2 \\r
+ + len(Statement) * ' ' + TailComment))\r
+ else:\r
+ dict.__setitem__(self, Key, (GenericComment, TailComment))\r
+\r
+ ## =[] operator\r
+ #\r
+ def __getitem__(self, Key):\r
+ return dict.__getitem__(self, Key)\r
+\r
+\r
+## GenDummyHelpTextObj\r
+#\r
+# @retval HelpTxt: Generated dummy help text object\r
+#\r
+def GenDummyHelpTextObj():\r
+ HelpTxt = TextObject()\r
+ HelpTxt.SetLang(TAB_LANGUAGE_EN_US)\r
+ HelpTxt.SetString(' ')\r
+ return HelpTxt\r
+\r
+## ConvertVersionToDecimal, the minor version should be within 0 - 99\r
+# <HexVersion> ::= "0x" <Major> <Minor>\r
+# <Major> ::= (a-fA-F0-9){4}\r
+# <Minor> ::= (a-fA-F0-9){4}\r
+# <DecVersion> ::= (0-65535) ["." (0-99)]\r
+#\r
+# @param StringIn: The string contains version defined in INF file.\r
+# It can be Decimal or Hex\r
+#\r
+def ConvertVersionToDecimal(StringIn):\r
+ if IsValidHexVersion(StringIn):\r
+ Value = int(StringIn, 16)\r
+ Major = Value >> 16\r
+ Minor = Value & 0xFFFF\r
+ MinorStr = str(Minor)\r
+ if len(MinorStr) == 1:\r
+ MinorStr = '0' + MinorStr\r
+ return str(Major) + '.' + MinorStr\r
+ else:\r
+ if StringIn.find(TAB_SPLIT) != -1:\r
+ return StringIn\r
+ elif StringIn:\r
+ return StringIn + '.0'\r
+ else:\r
+ #\r
+ # when StringIn is '', return it directly\r
+ #\r
+ return StringIn\r
+\r
+## GetHelpStringByRemoveHashKey\r
+#\r
+# Remove hash key at the header of string and return the remain.\r
+#\r
+# @param String: The string need to be processed.\r
+#\r
+def GetHelpStringByRemoveHashKey(String):\r
+ ReturnString = ''\r
+ PattenRemoveHashKey = re.compile(r"^[#+\s]+", re.DOTALL)\r
+ String = String.strip()\r
+ if String == '':\r
+ return String\r
+\r
+ LineList = GetSplitValueList(String, END_OF_LINE)\r
+ for Line in LineList:\r
+ ValueList = PattenRemoveHashKey.split(Line)\r
+ if len(ValueList) == 1:\r
+ ReturnString += ValueList[0] + END_OF_LINE\r
+ else:\r
+ ReturnString += ValueList[1] + END_OF_LINE\r
+\r
+ if ReturnString.endswith('\n') and not ReturnString.endswith('\n\n') and ReturnString != '\n':\r
+ ReturnString = ReturnString[:-1]\r
+\r
+ return ReturnString\r
+\r
+## ConvPathFromAbsToRel\r
+#\r
+# Get relative file path from absolute path.\r
+#\r
+# @param Path: The string contain file absolute path.\r
+# @param Root: The string contain the parent path of Path in.\r
+#\r
+#\r
+def ConvPathFromAbsToRel(Path, Root):\r
+ Path = os.path.normpath(Path)\r
+ Root = os.path.normpath(Root)\r
+ FullPath = os.path.normpath(os.path.join(Root, Path))\r
+\r
+ #\r
+ # If Path is absolute path.\r
+ # It should be in Root.\r
+ #\r
+ if os.path.isabs(Path):\r
+ return FullPath[FullPath.find(Root) + len(Root) + 1:]\r
+\r
+ else:\r
+ return Path\r
+\r
+## ConvertPath\r
+#\r
+# Convert special characters to '_', '\' to '/'\r
+# return converted path: Test!1.inf -> Test_1.inf\r
+#\r
+# @param Path: Path to be converted\r
+#\r
+def ConvertPath(Path):\r
+ RetPath = ''\r
+ for Char in Path.strip():\r
+ if Char.isalnum() or Char in '.-_/':\r
+ RetPath = RetPath + Char\r
+ elif Char == '\\':\r
+ RetPath = RetPath + '/'\r
+ else:\r
+ RetPath = RetPath + '_'\r
+ return RetPath\r
+\r
+## ConvertSpec\r
+#\r
+# during install, convert the Spec string extract from UPD into INF allowable definition,\r
+# the difference is period is allowed in the former (not the first letter) but not in the latter.\r
+# return converted Spec string\r
+#\r
+# @param SpecStr: SpecStr to be converted\r
+#\r
+def ConvertSpec(SpecStr):\r
+ RetStr = ''\r
+ for Char in SpecStr:\r
+ if Char.isalnum() or Char == '_':\r
+ RetStr = RetStr + Char\r
+ else:\r
+ RetStr = RetStr + '_'\r
+\r
+ return RetStr\r
+\r
+\r
+## IsEqualList\r
+#\r
+# Judge two lists are identical(contain same item).\r
+# The rule is elements in List A are in List B and elements in List B are in List A.\r
+#\r
+# @param ListA, ListB Lists need to be judged.\r
+#\r
+# @return True ListA and ListB are identical\r
+# @return False ListA and ListB are different with each other\r
+#\r
+def IsEqualList(ListA, ListB):\r
+ if ListA == ListB:\r
+ return True\r
+\r
+ for ItemA in ListA:\r
+ if not ItemA in ListB:\r
+ return False\r
+\r
+ for ItemB in ListB:\r
+ if not ItemB in ListA:\r
+ return False\r
+\r
+ return True\r
+\r
+## ConvertArchList\r
+#\r
+# Convert item in ArchList if the start character is lower case.\r
+# In UDP spec, Arch is only allowed as: [A-Z]([a-zA-Z0-9])*\r
+#\r
+# @param ArchList The ArchList need to be converted.\r
+#\r
+# @return NewList The ArchList been converted.\r
+#\r
+def ConvertArchList(ArchList):\r
+ NewArchList = []\r
+ if not ArchList:\r
+ return NewArchList\r
+\r
+ if isinstance(ArchList, list):\r
+ for Arch in ArchList:\r
+ Arch = Arch.upper()\r
+ NewArchList.append(Arch)\r
+ elif isinstance(ArchList, str):\r
+ ArchList = ArchList.upper()\r
+ NewArchList.append(ArchList)\r
+\r
+ return NewArchList\r
+\r
+## ProcessLineExtender\r
+#\r
+# Process the LineExtender of Line in LineList.\r
+# If one line ends with a line extender, then it will be combined together with next line.\r
+#\r
+# @param LineList The LineList need to be processed.\r
+#\r
+# @return NewList The ArchList been processed.\r
+#\r
+def ProcessLineExtender(LineList):\r
+ NewList = []\r
+ Count = 0\r
+ while Count < len(LineList):\r
+ if LineList[Count].strip().endswith("\\") and Count + 1 < len(LineList):\r
+ NewList.append(LineList[Count].strip()[:-2] + LineList[Count + 1])\r
+ Count = Count + 1\r
+ else:\r
+ NewList.append(LineList[Count])\r
+\r
+ Count = Count + 1\r
+\r
+ return NewList\r
+\r
+## ProcessEdkComment\r
+#\r
+# Process EDK style comment in LineList: c style /* */ comment or cpp style // comment\r
+#\r
+#\r
+# @param LineList The LineList need to be processed.\r
+#\r
+# @return LineList The LineList been processed.\r
+# @return FirstPos Where Edk comment is first found, -1 if not found\r
+#\r
+def ProcessEdkComment(LineList):\r
+ FindEdkBlockComment = False\r
+ Count = 0\r
+ StartPos = -1\r
+ EndPos = -1\r
+ FirstPos = -1\r
+\r
+ while(Count < len(LineList)):\r
+ Line = LineList[Count].strip()\r
+ if Line.startswith("/*"):\r
+ #\r
+ # handling c style comment\r
+ #\r
+ StartPos = Count\r
+ while Count < len(LineList):\r
+ Line = LineList[Count].strip()\r
+ if Line.endswith("*/"):\r
+ if (Count == StartPos) and Line.strip() == '/*/':\r
+ Count = Count + 1\r
+ continue\r
+ EndPos = Count\r
+ FindEdkBlockComment = True\r
+ break\r
+ Count = Count + 1\r
+\r
+ if FindEdkBlockComment:\r
+ if FirstPos == -1:\r
+ FirstPos = StartPos\r
+ for Index in range(StartPos, EndPos+1):\r
+ LineList[Index] = ''\r
+ FindEdkBlockComment = False\r
+ elif Line.find("//") != -1 and not Line.startswith("#"):\r
+ #\r
+ # handling cpp style comment\r
+ #\r
+ LineList[Count] = Line.replace("//", '#')\r
+ if FirstPos == -1:\r
+ FirstPos = Count\r
+\r
+ Count = Count + 1\r
+\r
+ return LineList, FirstPos\r
+\r
+## GetLibInstanceInfo\r
+#\r
+# Get the information from Library Instance INF file.\r
+#\r
+# @param string. A string start with # and followed by INF file path\r
+# @param WorkSpace. The WorkSpace directory used to combined with INF file path.\r
+#\r
+# @return GUID, Version\r
+def GetLibInstanceInfo(String, WorkSpace, LineNo):\r
+\r
+ FileGuidString = ""\r
+ VerString = ""\r
+\r
+ OriginalString = String\r
+ String = String.strip()\r
+ if not String:\r
+ return None, None\r
+ #\r
+ # Remove "#" characters at the beginning\r
+ #\r
+ String = GetHelpStringByRemoveHashKey(String)\r
+ String = String.strip()\r
+\r
+ #\r
+ # Validate file name exist.\r
+ #\r
+ FullFileName = os.path.normpath(os.path.realpath(os.path.join(WorkSpace, String)))\r
+ if not (ValidFile(FullFileName)):\r
+ Logger.Error("InfParser",\r
+ ToolError.FORMAT_INVALID,\r
+ ST.ERR_FILELIST_EXIST % (String),\r
+ File=GlobalData.gINF_MODULE_NAME,\r
+ Line=LineNo,\r
+ ExtraData=OriginalString)\r
+\r
+ #\r
+ # Validate file exist/format.\r
+ #\r
+ if IsValidPath(String, WorkSpace):\r
+ IsValidFileFlag = True\r
+ else:\r
+ Logger.Error("InfParser",\r
+ ToolError.FORMAT_INVALID,\r
+ ST.ERR_INF_PARSER_FILE_NOT_EXIST_OR_NAME_INVALID % (String),\r
+ File=GlobalData.gINF_MODULE_NAME,\r
+ Line=LineNo,\r
+ ExtraData=OriginalString)\r
+ return False\r
+ if IsValidFileFlag:\r
+ FileLinesList = []\r
+\r
+ try:\r
+ FInputfile = open(FullFileName, "r")\r
+ try:\r
+ FileLinesList = FInputfile.readlines()\r
+ except BaseException:\r
+ Logger.Error("InfParser",\r
+ ToolError.FILE_READ_FAILURE,\r
+ ST.ERR_FILE_OPEN_FAILURE,\r
+ File=FullFileName)\r
+ finally:\r
+ FInputfile.close()\r
+ except BaseException:\r
+ Logger.Error("InfParser",\r
+ ToolError.FILE_READ_FAILURE,\r
+ ST.ERR_FILE_OPEN_FAILURE,\r
+ File=FullFileName)\r
+\r
+ ReFileGuidPattern = re.compile("^\s*FILE_GUID\s*=.*$")\r
+ ReVerStringPattern = re.compile("^\s*VERSION_STRING\s*=.*$")\r
+\r
+ FileLinesList = ProcessLineExtender(FileLinesList)\r
+\r
+ for Line in FileLinesList:\r
+ if ReFileGuidPattern.match(Line):\r
+ FileGuidString = Line\r
+ if ReVerStringPattern.match(Line):\r
+ VerString = Line\r
+\r
+ if FileGuidString:\r
+ FileGuidString = GetSplitValueList(FileGuidString, '=', 1)[1]\r
+ if VerString:\r
+ VerString = GetSplitValueList(VerString, '=', 1)[1]\r
+\r
+ return FileGuidString, VerString\r
+\r
+## GetLocalValue\r
+#\r
+# Generate the local value for INF and DEC file. If Lang attribute not present, then use this value.\r
+# If present, and there is no element without the Lang attribute, and one of the elements has the rfc1766 code is\r
+# "en-x-tianocore", or "en-US" if "en-x-tianocore" was not found, or "en" if "en-US" was not found, or startswith 'en'\r
+# if 'en' was not found, then use this value.\r
+# If multiple entries of a tag exist which have the same language code, use the last entry.\r
+#\r
+# @param ValueList A list need to be processed.\r
+# @param UseFirstValue: True to use the first value, False to use the last value\r
+#\r
+# @return LocalValue\r
+def GetLocalValue(ValueList, UseFirstValue=False):\r
+ Value1 = ''\r
+ Value2 = ''\r
+ Value3 = ''\r
+ Value4 = ''\r
+ Value5 = ''\r
+ for (Key, Value) in ValueList:\r
+ if Key == TAB_LANGUAGE_EN_X:\r
+ if UseFirstValue:\r
+ if not Value1:\r
+ Value1 = Value\r
+ else:\r
+ Value1 = Value\r
+ if Key == TAB_LANGUAGE_EN_US:\r
+ if UseFirstValue:\r
+ if not Value2:\r
+ Value2 = Value\r
+ else:\r
+ Value2 = Value\r
+ if Key == TAB_LANGUAGE_EN:\r
+ if UseFirstValue:\r
+ if not Value3:\r
+ Value3 = Value\r
+ else:\r
+ Value3 = Value\r
+ if Key.startswith(TAB_LANGUAGE_EN):\r
+ if UseFirstValue:\r
+ if not Value4:\r
+ Value4 = Value\r
+ else:\r
+ Value4 = Value\r
+ if Key == '':\r
+ if UseFirstValue:\r
+ if not Value5:\r
+ Value5 = Value\r
+ else:\r
+ Value5 = Value\r
+\r
+ if Value1:\r
+ return Value1\r
+ if Value2:\r
+ return Value2\r
+ if Value3:\r
+ return Value3\r
+ if Value4:\r
+ return Value4\r
+ if Value5:\r
+ return Value5\r
+\r
+ return ''\r
+\r
+\r
+## GetCharIndexOutStr\r
+#\r
+# Get comment character index outside a string\r
+#\r
+# @param Line: The string to be checked\r
+# @param CommentCharacter: Comment char, used to ignore comment content\r
+#\r
+# @retval Index\r
+#\r
+def GetCharIndexOutStr(CommentCharacter, Line):\r
+ #\r
+ # remove whitespace\r
+ #\r
+ Line = Line.strip()\r
+\r
+ #\r
+ # Check whether comment character is in a string\r
+ #\r
+ InString = False\r
+ for Index in range(0, len(Line)):\r
+ if Line[Index] == '"':\r
+ InString = not InString\r
+ elif Line[Index] == CommentCharacter and InString :\r
+ pass\r
+ elif Line[Index] == CommentCharacter and (Index +1) < len(Line) and Line[Index+1] == CommentCharacter \\r
+ and not InString :\r
+ return Index\r
+ return -1\r
+\r
+## ValidateUNIFilePath\r
+#\r
+# Check the UNI file path\r
+#\r
+# @param FilePath: The UNI file path\r
+#\r
+def ValidateUNIFilePath(Path):\r
+ Suffix = Path[Path.rfind(TAB_SPLIT):]\r
+\r
+ #\r
+ # Check if the suffix is one of the '.uni', '.UNI', '.Uni'\r
+ #\r
+ if Suffix not in TAB_UNI_FILE_SUFFIXS:\r
+ Logger.Error("Unicode File Parser",\r
+ ToolError.FORMAT_INVALID,\r
+ Message=ST.ERR_UNI_FILE_SUFFIX_WRONG,\r
+ ExtraData=Path)\r
+\r
+ #\r
+ # Check if '..' in the file name(without suffix)\r
+ #\r
+ if (TAB_SPLIT + TAB_SPLIT) in Path:\r
+ Logger.Error("Unicode File Parser",\r
+ ToolError.FORMAT_INVALID,\r
+ Message=ST.ERR_UNI_FILE_NAME_INVALID,\r
+ ExtraData=Path)\r
+\r
+ #\r
+ # Check if the file name is valid according to the DEC and INF specification\r
+ #\r
+ Pattern = '[a-zA-Z0-9_][a-zA-Z0-9_\-\.]*'\r
+ FileName = Path.replace(Suffix, '')\r
+ InvalidCh = re.sub(Pattern, '', FileName)\r
+ if InvalidCh:\r
+ Logger.Error("Unicode File Parser",\r
+ ToolError.FORMAT_INVALID,\r
+ Message=ST.ERR_INF_PARSER_FILE_NOT_EXIST_OR_NAME_INVALID,\r
+ ExtraData=Path)\r
+\r