]> git.proxmox.com Git - mirror_edk2.git/blobdiff - BaseTools/Source/Python/Common/Misc.py
Sync BaseTools Branch (version r2271) to EDKII main trunk.
[mirror_edk2.git] / BaseTools / Source / Python / Common / Misc.py
index 2c1041c55b12b7fdc43700ca340d8c359756c664..0540636988a674873d317d518e7bf9acda63ebfb 100644 (file)
@@ -1,8 +1,8 @@
 ## @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
@@ -22,12 +22,13 @@ import threading
 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 *
 
 ## Regular expression used to find out place holders in string template
@@ -251,7 +252,15 @@ def SaveFileOnChange(File, Content, IsBinaryFile=True):
         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:
@@ -266,8 +275,8 @@ def SaveFileOnChange(File, Content, IsBinaryFile=True):
             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
 
@@ -316,12 +325,14 @@ def DataRestore(File):
 #   @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):
@@ -330,16 +341,18 @@ class DirCache:
             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)
@@ -351,22 +364,29 @@ class DirCache:
         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
 #
@@ -683,6 +703,7 @@ class TemplateString(object):
     ## Constructor
     def __init__(self, Template=None):
         self.String = ''
+        self.IsBinary = False
         self._Template = Template
         self._TemplateSectionList = self._Parse(Template)
 
@@ -706,7 +727,7 @@ class TemplateString(object):
         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
@@ -1113,6 +1134,16 @@ class tdict:
             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):
@@ -1143,20 +1174,108 @@ def ParseConsoleLog(Filename):
     Opr.close()
     Opw.close()
 
+## 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 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 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('"'))
+        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)
     elif Type == 'BOOLEAN':
-        if Value not in ['TRUE', 'FALSE']:
-            return False, "Invalid value [%s] of type [%s]; must be TRUE or FALSE" % (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(Value) == type(""):
         try:
             Value = long(Value, 0)
@@ -1299,7 +1418,12 @@ class PathClass(object):
 
         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 = ''
@@ -1321,6 +1445,90 @@ class PathClass(object):
 
     Key = property(_GetFileKey)
 
+## 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