mirror of https://github.com/acidanthera/audk.git
922 lines
27 KiB
Python
922 lines
27 KiB
Python
## @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
|
|
|
|
## 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
|