## @file
# Common routines used by all tools
#
-# Copyright (c) 2007, Intel Corporation
-# All rights reserved. This program and the accompanying materials
+# Copyright (c) 2007 - 2010, 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
import time
import re
import cPickle
+import array
from UserDict import IterableUserDict
from UserList import UserList
from Common import EdkLogger as EdkLogger
from Common import GlobalData as GlobalData
-
+from DataType import *
from BuildToolError import *
+from CommonDataClass.DataClass import *
## Regular expression used to find out place holders in string template
gPlaceholderPattern = re.compile("\$\{([^$()\s]+)\}", re.MULTILINE|re.UNICODE)
guidValueString = GuidValue.lower().replace("{", "").replace("}", "").replace(" ", "")
guidValueList = guidValueString.split(",")
if len(guidValueList) != 11:
- EdkLogger.error(None, None, "Invalid GUID value string %s" % GuidValue)
+ EdkLogger.error(None, FORMAT_INVALID, "Invalid GUID value string [%s]" % GuidValue)
return "%08x_%04x_%04x_%02x%02x_%02x%02x%02x%02x%02x%02x" % (
int(guidValueList[0], 16),
int(guidValueList[1], 16),
except:
EdkLogger.error(None, FILE_OPEN_FAILURE, ExtraData=File)
- CreateDirectory(os.path.dirname(File))
+ DirName = os.path.dirname(File)
+ if not CreateDirectory(DirName):
+ EdkLogger.error(None, FILE_CREATE_FAILURE, "Could not create directory %s" % DirName)
+ else:
+ if DirName == '':
+ DirName = os.getcwd()
+ if not os.access(DirName, os.W_OK):
+ EdkLogger.error(None, PERMISSION_FAILURE, "Do not have write permission on directory %s" % DirName)
+
try:
if GlobalData.gIsWindows:
try:
Fd = open(File, "wb")
Fd.write(Content)
Fd.close()
- except:
- EdkLogger.error(None, FILE_CREATE_FAILURE, ExtraData=File)
+ except IOError, X:
+ EdkLogger.error(None, FILE_CREATE_FAILURE, ExtraData='IOError %s'%X)
return True
# @retval None If path doesn't exist
#
class DirCache:
- _CACHE_ = {}
+ _CACHE_ = set()
+ _UPPER_CACHE_ = {}
def __init__(self, Root):
self._Root = Root
for F in os.listdir(Root):
- self._CACHE_[F.upper()] = F
+ self._CACHE_.add(F)
+ self._UPPER_CACHE_[F.upper()] = F
# =[] operator
def __getitem__(self, Path):
return self._Root
if Path and Path[0] == os.path.sep:
Path = Path[1:]
- Path = Path.upper()
if Path in self._CACHE_:
- return os.path.join(self._Root, self._CACHE_[Path])
+ return os.path.join(self._Root, Path)
+ UpperPath = Path.upper()
+ if UpperPath in self._UPPER_CACHE_:
+ return os.path.join(self._Root, self._UPPER_CACHE_[UpperPath])
IndexList = []
LastSepIndex = -1
SepIndex = Path.find(os.path.sep)
while SepIndex > -1:
- Parent = Path[:SepIndex]
- if Parent not in self._CACHE_:
+ Parent = UpperPath[:SepIndex]
+ if Parent not in self._UPPER_CACHE_:
break
LastSepIndex = SepIndex
SepIndex = Path.find(os.path.sep, LastSepIndex + 1)
os.chdir(self._Root)
SepIndex = LastSepIndex
while SepIndex > -1:
- ParentKey = Path[:SepIndex]
- if ParentKey not in self._CACHE_:
+ Parent = Path[:SepIndex]
+ ParentKey = UpperPath[:SepIndex]
+ if ParentKey not in self._UPPER_CACHE_:
os.chdir(Cwd)
return None
- ParentDir = self._CACHE_[ParentKey]
+ if Parent in self._CACHE_:
+ ParentDir = Parent
+ else:
+ ParentDir = self._UPPER_CACHE_[ParentKey]
for F in os.listdir(ParentDir):
Dir = os.path.join(ParentDir, F)
- self._CACHE_[Dir.upper()] = Dir
+ self._CACHE_.add(Dir)
+ self._UPPER_CACHE_[Dir.upper()] = Dir
SepIndex = Path.find(os.path.sep, SepIndex + 1)
os.chdir(Cwd)
- if Path not in self._CACHE_:
- return None
- return os.path.join(self._Root, self._CACHE_[Path])
+ if Path in self._CACHE_:
+ return os.path.join(self._Root, Path)
+ elif UpperPath in self._UPPER_CACHE_:
+ return os.path.join(self._Root, self._UPPER_CACHE_[UpperPath])
+ return None
## Get all files of a directory
#
return NewFile
def RealPath2(File, Dir='', OverrideDir=''):
- NewFile = GlobalData.gAllFiles[os.path.normpath(os.path.join(Dir, File))]
+ if OverrideDir:
+ NewFile = GlobalData.gAllFiles[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)]
+ if GlobalData.gAllFiles:
+ NewFile = GlobalData.gAllFiles[os.path.normpath(os.path.join(Dir, File))]
+ else:
+ NewFile = os.path.normpath(os.path.join(Dir, File))
if NewFile:
if Dir:
if Dir[-1] == os.path.sep:
else:
return NewFile, ''
- if OverrideDir:
- NewFile = GlobalData.gAllFiles[os.path.normpath(os.path.join(OverrideDir, File))]
- if NewFile:
- return NewFile[len(OverrideDir)+1:], NewFile[0:len(OverrideDir)]
return None, None
## Check if gvien file exists or not
if FileExt.lower() != Ext.lower():
return False, File
- # Replace the R8 macros
+ # Replace the Edk macros
if OverrideDir != '' and OverrideDir != None:
if OverrideDir.find('$(EFI_SOURCE)') > -1:
OverrideDir = OverrideDir.replace('$(EFI_SOURCE)', EfiSource)
Dir = os.getcwd()
Dir = Dir[len(Workspace)+1:]
- # First check if File has R8 definition itself
+ # First check if File has Edk definition itself
if File.find('$(EFI_SOURCE)') > -1 or File.find('$(EDK_SOURCE)') > -1:
NewFile = File.replace('$(EFI_SOURCE)', EfiSource)
NewFile = NewFile.replace('$(EDK_SOURCE)', EdkSource)
#
#
def ValidFile3(AllFiles, File, Workspace='', EfiSource='', EdkSource='', Dir='.', OverrideDir=''):
- # Replace the R8 macros
+ # Replace the Edk macros
if OverrideDir != '' and OverrideDir != None:
if OverrideDir.find('$(EFI_SOURCE)') > -1:
OverrideDir = OverrideDir.replace('$(EFI_SOURCE)', EfiSource)
NewRelaPath = RelaPath
while(True):
- # First check if File has R8 definition itself
+ # First check if File has Edk definition itself
if File.find('$(EFI_SOURCE)') > -1 or File.find('$(EDK_SOURCE)') > -1:
File = File.replace('$(EFI_SOURCE)', EfiSource)
File = File.replace('$(EDK_SOURCE)', EdkSource)
## Constructor
def __init__(self, Template=None):
self.String = ''
+ self.IsBinary = False
self._Template = Template
self._TemplateSectionList = self._Parse(Template)
while Template:
MatchObj = gPlaceholderPattern.search(Template, SearchFrom)
if not MatchObj:
- if MatchEnd < len(Template):
+ if MatchEnd <= len(Template):
TemplateSection = TemplateString.Section(Template[SectionStart:], PlaceHolderList)
TemplateSectionList.append(TemplateSection)
break
for Key in self.data:
self.data[Key].SetSingleMode()
+ def GetKeys(self, KeyIndex=0):
+ assert KeyIndex >= 0
+ if KeyIndex == 0:
+ return set(self.data.keys())
+ else:
+ keys = set()
+ for Key in self.data:
+ keys |= self.data[Key].GetKeys(KeyIndex - 1)
+ return keys
+
## Boolean chain list
#
class Blist(UserList):
Opr.close()
Opw.close()
+## AnalyzeDscPcd
+#
+# Analyze DSC PCD value, since there is no data type info in DSC
+# This fuction is used to match functions (AnalyzePcdData, AnalyzeHiiPcdData, AnalyzeVpdPcdData) used for retrieving PCD value from database
+# 1. Feature flag: TokenSpace.PcdCName|PcdValue
+# 2. Fix and Patch:TokenSpace.PcdCName|PcdValue[|MaxSize]
+# 3. Dynamic default:
+# TokenSpace.PcdCName|PcdValue[|VOID*[|MaxSize]]
+# TokenSpace.PcdCName|PcdValue
+# 4. Dynamic VPD:
+# TokenSpace.PcdCName|VpdOffset[|VpdValue]
+# TokenSpace.PcdCName|VpdOffset[|MaxSize[|VpdValue]]
+# 5. Dynamic HII:
+# TokenSpace.PcdCName|HiiString|VaiableGuid|VariableOffset[|HiiValue]
+# PCD value needs to be located in such kind of string, and the PCD value might be an expression in which
+# there might have "|" operator, also in string value.
+#
+# @param Setting: String contain information described above with "TokenSpace.PcdCName|" stripped
+# @param PcdType: PCD type: feature, fixed, dynamic default VPD HII
+# @param DataType: The datum type of PCD: VOID*, UNIT, BOOL
+# @retval:
+# ValueList: A List contain fields described above
+# IsValid: True if conforming EBNF, otherwise False
+# Index: The index where PcdValue is in ValueList
+#
+def AnalyzeDscPcd(Setting, PcdType, DataType=''):
+ Setting = Setting.strip()
+ # There might be escaped quote in a string: \", \\\"
+ Data = Setting.replace('\\\\', '//').replace('\\\"', '\\\'')
+ # There might be '|' in string and in ( ... | ... ), replace it with '-'
+ NewStr = ''
+ InStr = False
+ Pair = 0
+ for ch in Data:
+ if ch == '"':
+ InStr = not InStr
+ elif ch == '(' and not InStr:
+ Pair += 1
+ elif ch == ')' and not InStr:
+ Pair -= 1
+
+ if (Pair > 0 or InStr) and ch == TAB_VALUE_SPLIT:
+ NewStr += '-'
+ else:
+ NewStr += ch
+ FieldList = []
+ StartPos = 0
+ while True:
+ Pos = NewStr.find(TAB_VALUE_SPLIT, StartPos)
+ if Pos < 0:
+ FieldList.append(Setting[StartPos:].strip())
+ break
+ FieldList.append(Setting[StartPos:Pos].strip())
+ StartPos = Pos + 1
+
+ IsValid = True
+ if PcdType in (MODEL_PCD_FIXED_AT_BUILD, MODEL_PCD_PATCHABLE_IN_MODULE, MODEL_PCD_FEATURE_FLAG):
+ Value = FieldList[0]
+ Size = ''
+ if len(FieldList) > 1:
+ Size = FieldList[1]
+ if DataType == 'VOID*':
+ IsValid = (len(FieldList) <= 2)
+ else:
+ IsValid = (len(FieldList) <= 1)
+ return [Value, '', Size], IsValid, 0
+ elif PcdType in (MODEL_PCD_DYNAMIC_DEFAULT, MODEL_PCD_DYNAMIC_EX_DEFAULT):
+ Value = FieldList[0]
+ Size = Type = ''
+ if len(FieldList) > 1:
+ Type = FieldList[1]
+ if len(FieldList) > 2:
+ Size = FieldList[2]
+ if DataType == 'VOID*':
+ IsValid = (len(FieldList) <= 3)
+ else:
+ IsValid = (len(FieldList) <= 1)
+ return [Value, Type, Size], IsValid, 0
+ elif PcdType in (MODEL_PCD_DYNAMIC_VPD, MODEL_PCD_DYNAMIC_EX_VPD):
+ VpdOffset = FieldList[0]
+ Value = Size = ''
+ if not DataType == 'VOID*':
+ if len(FieldList) > 1:
+ Value = FieldList[1]
+ else:
+ if len(FieldList) > 1:
+ Size = FieldList[1]
+ if len(FieldList) > 2:
+ Value = FieldList[2]
+ if DataType == 'VOID*':
+ IsValid = (len(FieldList) <= 3)
+ else:
+ IsValid = (len(FieldList) <= 2)
+ return [VpdOffset, Size, Value], IsValid, 2
+ elif PcdType in (MODEL_PCD_DYNAMIC_HII, MODEL_PCD_DYNAMIC_EX_HII):
+ HiiString = FieldList[0]
+ Guid = Offset = Value = ''
+ if len(FieldList) > 1:
+ Guid = FieldList[1]
+ if len(FieldList) > 2:
+ Offset = FieldList[2]
+ if len(FieldList) > 3:
+ Value = FieldList[3]
+ IsValid = (3 <= len(FieldList) <= 4)
+ return [HiiString, Guid, Offset, Value], IsValid, 3
+ return [], False, 0
+
+## AnalyzePcdData
+#
+# Analyze the pcd Value, Datum type and TokenNumber.
+# Used to avoid split issue while the value string contain "|" character
+#
+# @param[in] Setting: A String contain value/datum type/token number information;
+#
+# @retval ValueList: A List contain value, datum type and toke number.
+#
+def AnalyzePcdData(Setting):
+ ValueList = ['', '', '']
+
+ ValueRe = re.compile(r'^\s*L?\".*\|.*\"')
+ PtrValue = ValueRe.findall(Setting)
+
+ ValueUpdateFlag = False
+
+ if len(PtrValue) >= 1:
+ Setting = re.sub(ValueRe, '', Setting)
+ ValueUpdateFlag = True
+
+ TokenList = Setting.split(TAB_VALUE_SPLIT)
+ ValueList[0:len(TokenList)] = TokenList
+
+ if ValueUpdateFlag:
+ ValueList[0] = PtrValue[0]
+
+ return ValueList
+
+## AnalyzeHiiPcdData
+#
+# Analyze the pcd Value, variable name, variable Guid and variable offset.
+# Used to avoid split issue while the value string contain "|" character
+#
+# @param[in] Setting: A String contain VariableName, VariableGuid, VariableOffset, DefaultValue information;
+#
+# @retval ValueList: A List contaian VariableName, VariableGuid, VariableOffset, DefaultValue.
+#
+def AnalyzeHiiPcdData(Setting):
+ ValueList = ['', '', '', '']
+
+ ValueRe = re.compile(r'^\s*L?\".*\|.*\"')
+ PtrValue = ValueRe.findall(Setting)
+
+ ValueUpdateFlag = False
+
+ if len(PtrValue) >= 1:
+ Setting = re.sub(ValueRe, '', Setting)
+ ValueUpdateFlag = True
+
+ TokenList = Setting.split(TAB_VALUE_SPLIT)
+ ValueList[0:len(TokenList)] = TokenList
+
+ if ValueUpdateFlag:
+ ValueList[0] = PtrValue[0]
+
+ return ValueList
+
+## AnalyzeVpdPcdData
+#
+# Analyze the vpd pcd VpdOffset, MaxDatumSize and InitialValue.
+# Used to avoid split issue while the value string contain "|" character
+#
+# @param[in] Setting: A String contain VpdOffset/MaxDatumSize/InitialValue information;
+#
+# @retval ValueList: A List contain VpdOffset, MaxDatumSize and InitialValue.
+#
+def AnalyzeVpdPcdData(Setting):
+ ValueList = ['', '', '']
+
+ ValueRe = re.compile(r'\s*L?\".*\|.*\"\s*$')
+ PtrValue = ValueRe.findall(Setting)
+
+ ValueUpdateFlag = False
+
+ if len(PtrValue) >= 1:
+ Setting = re.sub(ValueRe, '', Setting)
+ ValueUpdateFlag = True
+
+ TokenList = Setting.split(TAB_VALUE_SPLIT)
+ ValueList[0:len(TokenList)] = TokenList
+
+ if ValueUpdateFlag:
+ ValueList[2] = PtrValue[0]
+
+ return ValueList
+
## check format of PCD value against its the datum type
#
# For PCD value setting
#
def CheckPcdDatum(Type, Value):
if Type == "VOID*":
- if not ((Value.startswith('L"') or Value.startswith('"') and Value.endswith('"'))
+ ValueRe = re.compile(r'\s*L?\".*\"\s*$')
+ if not (((Value.startswith('L"') or Value.startswith('"')) and Value.endswith('"'))
or (Value.startswith('{') and Value.endswith('}'))
):
return False, "Invalid value [%s] of type [%s]; must be in the form of {...} for array"\
- ", or \"...\" for string, or L\"...\" for unicode string" % (Value, Type)
+ ", or \"...\" for string, or L\"...\" for unicode string" % (Value, Type)
+ elif ValueRe.match(Value):
+ # Check the chars in UnicodeString or CString is printable
+ if Value.startswith("L"):
+ Value = Value[2:-1]
+ else:
+ Value = Value[1:-1]
+ Printset = set(string.printable)
+ Printset.remove(TAB_PRINTCHAR_VT)
+ Printset.add(TAB_PRINTCHAR_BS)
+ Printset.add(TAB_PRINTCHAR_NUL)
+ if not set(Value).issubset(Printset):
+ PrintList = list(Printset)
+ PrintList.sort()
+ return False, "Invalid PCD string value of type [%s]; must be printable chars %s." % (Type, PrintList)
elif Type == 'BOOLEAN':
- if Value not in ['TRUE', 'FALSE']:
- return False, "Invalid value [%s] of type [%s]; must be TRUE or FALSE" % (Value, Type)
- elif type(Value) == type(""):
+ if Value not in ['TRUE', 'True', 'true', '0x1', '0x01', '1', 'FALSE', 'False', 'false', '0x0', '0x00', '0']:
+ return False, "Invalid value [%s] of type [%s]; must be one of TRUE, True, true, 0x1, 0x01, 1"\
+ ", FALSE, False, false, 0x0, 0x00, 0" % (Value, Type)
+ elif Type in [TAB_UINT8, TAB_UINT16, TAB_UINT32, TAB_UINT64]:
try:
Value = long(Value, 0)
except:
return False, "Invalid value [%s] of type [%s];"\
- " must be a hexadecimal, decimal or octal in C language format."\
- % (Value, Type)
+ " must be a hexadecimal, decimal or octal in C language format." % (Value, Type)
+ else:
+ return False, "Invalid type [%s]; must be one of VOID*, BOOLEAN, UINT8, UINT16, UINT32, UINT64." % (Type)
return True, ""
else:
return self.Path == str(Other)
+ ## Override __cmp__ function
+ #
+ # Customize the comparsion operation of two PathClass
+ #
+ # @retval 0 The two PathClass are different
+ # @retval -1 The first PathClass is less than the second PathClass
+ # @retval 1 The first PathClass is Bigger than the second PathClass
+ def __cmp__(self, Other):
+ if type(Other) == type(self):
+ OtherKey = Other.Path
+ else:
+ OtherKey = str(Other)
+
+ SelfKey = self.Path
+ if SelfKey == OtherKey:
+ return 0
+ elif SelfKey > OtherKey:
+ return 1
+ else:
+ return -1
+
## Override __hash__ function
#
# Use Path as key in hash table
self._Key = self.Path.upper() # + self.ToolChainFamily + self.TagName + self.ToolCode + self.Target
return self._Key
+ def _GetTimeStamp(self):
+ return os.stat(self.Path)[8]
+
def Validate(self, Type='', CaseSensitive=True):
if GlobalData.gCaseInsensitive:
CaseSensitive = False
RealFile, RealRoot = RealPath2(self.File, self.Root, self.AlterRoot)
if not RealRoot and not RealFile:
- return FILE_NOT_FOUND, self.File
+ 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 FILE_NOT_FOUND, os.path.join(self.AlterRoot, RealFile)
ErrorCode = 0
ErrorInfo = ''
return ErrorCode, ErrorInfo
Key = property(_GetFileKey)
+ TimeStamp = property(_GetTimeStamp)
+## Parse PE image to get the required PE informaion.
+#
+class PeImageClass():
+ ## Constructor
+ #
+ # @param File FilePath of PeImage
+ #
+ def __init__(self, PeFile):
+ self.FileName = PeFile
+ self.IsValid = False
+ self.Size = 0
+ self.EntryPoint = 0
+ self.SectionAlignment = 0
+ self.SectionHeaderList = []
+ self.ErrorInfo = ''
+ try:
+ PeObject = open(PeFile, 'rb')
+ except:
+ self.ErrorInfo = self.FileName + ' can not be found\n'
+ return
+ # Read DOS header
+ ByteArray = array.array('B')
+ ByteArray.fromfile(PeObject, 0x3E)
+ ByteList = ByteArray.tolist()
+ # DOS signature should be 'MZ'
+ if self._ByteListToStr (ByteList[0x0:0x2]) != 'MZ':
+ self.ErrorInfo = self.FileName + ' has no valid DOS signature MZ'
+ return
+
+ # Read 4 byte PE Signature
+ PeOffset = self._ByteListToInt(ByteList[0x3C:0x3E])
+ PeObject.seek(PeOffset)
+ ByteArray = array.array('B')
+ ByteArray.fromfile(PeObject, 4)
+ # PE signature should be 'PE\0\0'
+ if ByteArray.tostring() != 'PE\0\0':
+ self.ErrorInfo = self.FileName + ' has no valid PE signature PE00'
+ return
+
+ # Read PE file header
+ ByteArray = array.array('B')
+ ByteArray.fromfile(PeObject, 0x14)
+ ByteList = ByteArray.tolist()
+ SecNumber = self._ByteListToInt(ByteList[0x2:0x4])
+ if SecNumber == 0:
+ self.ErrorInfo = self.FileName + ' has no section header'
+ return
+
+ # Read PE optional header
+ OptionalHeaderSize = self._ByteListToInt(ByteArray[0x10:0x12])
+ ByteArray = array.array('B')
+ ByteArray.fromfile(PeObject, OptionalHeaderSize)
+ ByteList = ByteArray.tolist()
+ self.EntryPoint = self._ByteListToInt(ByteList[0x10:0x14])
+ self.SectionAlignment = self._ByteListToInt(ByteList[0x20:0x24])
+ self.Size = self._ByteListToInt(ByteList[0x38:0x3C])
+
+ # Read each Section Header
+ for Index in range(SecNumber):
+ ByteArray = array.array('B')
+ ByteArray.fromfile(PeObject, 0x28)
+ ByteList = ByteArray.tolist()
+ SecName = self._ByteListToStr(ByteList[0:8])
+ SecVirtualSize = self._ByteListToInt(ByteList[8:12])
+ SecRawAddress = self._ByteListToInt(ByteList[20:24])
+ SecVirtualAddress = self._ByteListToInt(ByteList[12:16])
+ self.SectionHeaderList.append((SecName, SecVirtualAddress, SecRawAddress, SecVirtualSize))
+ self.IsValid = True
+ PeObject.close()
+
+ def _ByteListToStr(self, ByteList):
+ String = ''
+ for index in range(len(ByteList)):
+ if ByteList[index] == 0:
+ break
+ String += chr(ByteList[index])
+ return String
+
+ def _ByteListToInt(self, ByteList):
+ Value = 0
+ for index in range(len(ByteList) - 1, -1, -1):
+ Value = (Value << 8) | int(ByteList[index])
+ return Value
+
##
#
# This acts like the main() function for the script, unless it is 'import'ed into another