]> git.proxmox.com Git - mirror_edk2.git/blobdiff - BaseTools/Source/Python/UPT/Library/Misc.py
Sync BaseTool trunk (version r2649) into EDKII BaseTools.
[mirror_edk2.git] / BaseTools / Source / Python / UPT / Library / Misc.py
index 889b777d190ae0e6c7c90d2a1a5899c06e3c2092..750805e32814a978b7b3fbb62436b44fdb312782 100644 (file)
-## @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 and not Line.startswith("#"):
-            #
-            # 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, Intel Corporation. All rights reserved.<BR>\r
+#\r
+# This program and the accompanying materials are licensed and made available \r
+# under the terms and conditions of the BSD License which accompanies this \r
+# distribution. The full text of the license may be found at \r
+# http://opensource.org/licenses/bsd-license.php\r
+#\r
+# THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,\r
+# WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.\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 UserDict import IterableUserDict\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 LANGUAGE_EN_US\r
+from Library.String import GetSplitValueList\r
+from Library.ParserValidate import IsValidHexVersion\r
+from Library.ParserValidate import IsValidPath\r
+from Object.POM.CommonObject import TextObject\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 == 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 == 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 not IsBinaryFile:\r
+        Content = Content.replace("\n", linesep)\r
+\r
+    if os.path.exists(File):\r
+        try:\r
+            if Content == open(File, "rb").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
+    try:\r
+        FileFd = open(File, "wb")\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
+        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 != 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
+## A dict which can access its keys and/or values orderly\r
+#\r
+#  The class implements a new kind of dict which its keys or values can be\r
+#  accessed in the order they are added into the dict. It guarantees the order\r
+#  by making use of an internal list to keep a copy of keys.\r
+#\r
+class Sdict(IterableUserDict):\r
+    ## Constructor\r
+    #\r
+    def __init__(self):\r
+        IterableUserDict.__init__(self)\r
+        self._key_list = []\r
+\r
+    ## [] operator\r
+    #\r
+    def __setitem__(self, Key, Value):\r
+        if Key not in self._key_list:\r
+            self._key_list.append(Key)\r
+        IterableUserDict.__setitem__(self, Key, Value)\r
+\r
+    ## del operator\r
+    #\r
+    def __delitem__(self, Key):\r
+        self._key_list.remove(Key)\r
+        IterableUserDict.__delitem__(self, Key)\r
+\r
+    ## used in "for k in dict" loop to ensure the correct order\r
+    #\r
+    def __iter__(self):\r
+        return self.iterkeys()\r
+\r
+    ## len() support\r
+    #\r
+    def __len__(self):\r
+        return len(self._key_list)\r
+\r
+    ## "in" test support\r
+    #\r
+    def __contains__(self, Key):\r
+        return Key in self._key_list\r
+\r
+    ## indexof support\r
+    #\r
+    def index(self, Key):\r
+        return self._key_list.index(Key)\r
+\r
+    ## insert support\r
+    #\r
+    def insert(self, Key, Newkey, Newvalue, Order):\r
+        Index = self._key_list.index(Key)\r
+        if Order == 'BEFORE':\r
+            self._key_list.insert(Index, Newkey)\r
+            IterableUserDict.__setitem__(self, Newkey, Newvalue)\r
+        elif Order == 'AFTER':\r
+            self._key_list.insert(Index + 1, Newkey)\r
+            IterableUserDict.__setitem__(self, Newkey, Newvalue)\r
+\r
+    ## append support\r
+    #\r
+    def append(self, Sdict2):\r
+        for Key in Sdict2:\r
+            if Key not in self._key_list:\r
+                self._key_list.append(Key)\r
+            IterableUserDict.__setitem__(self, Key, Sdict2[Key])\r
+    ## hash key\r
+    #\r
+    def has_key(self, Key):\r
+        return Key in self._key_list\r
+\r
+    ## Empty the dict\r
+    #\r
+    def clear(self):\r
+        self._key_list = []\r
+        IterableUserDict.clear(self)\r
+\r
+    ## Return a copy of keys\r
+    #\r
+    def keys(self):\r
+        Keys = []\r
+        for Key in self._key_list:\r
+            Keys.append(Key)\r
+        return Keys\r
+\r
+    ## Return a copy of values\r
+    #\r
+    def values(self):\r
+        Values = []\r
+        for Key in self._key_list:\r
+            Values.append(self[Key])\r
+        return Values\r
+\r
+    ## Return a copy of (key, value) list\r
+    #\r
+    def items(self):\r
+        Items = []\r
+        for Key in self._key_list:\r
+            Items.append((Key, self[Key]))\r
+        return Items\r
+\r
+    ## Iteration support\r
+    #\r
+    def iteritems(self):\r
+        return iter(self.items())\r
+\r
+    ## Keys interation support\r
+    #\r
+    def iterkeys(self):\r
+        return iter(self.keys())\r
+\r
+    ## Values interation support\r
+    #\r
+    def itervalues(self):\r
+        return iter(self.values())\r
+\r
+    ## Return value related to a key, and remove the (key, value) from the dict\r
+    #\r
+    def pop(self, Key, *Dv):\r
+        Value = None\r
+        if Key in self._key_list:\r
+            Value = self[Key]\r
+            self.__delitem__(Key)\r
+        elif len(Dv) != 0 :\r
+            Value = Dv[0]\r
+        return Value\r
+\r
+    ## Return (key, value) pair, and remove the (key, value) from the dict\r
+    #\r
+    def popitem(self):\r
+        Key = self._key_list[-1]\r
+        Value = self[Key]\r
+        self.__delitem__(Key)\r
+        return Key, Value\r
+    ## update method\r
+    #\r
+    def update(self, Dict=None, **Kwargs):\r
+        if Dict != None:\r
+            for Key1, Val1 in Dict.items():\r
+                self[Key1] = Val1\r
+        if len(Kwargs):\r
+            for Key1, Val1 in Kwargs.items():\r
+                self[Key1] = Val1\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 xrange(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 type(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 == 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
+## Check environment variables\r
+#\r
+#  Check environment variables that must be set for build. Currently they are\r
+#\r
+#   WORKSPACE           The directory all packages/platforms start from\r
+#   EDK_TOOLS_PATH      The directory contains all tools needed by the build\r
+#   PATH                $(EDK_TOOLS_PATH)/Bin/<sys> must be set in PATH\r
+#\r
+#   If any of above environment variable is not set or has error, the build\r
+#   will be broken.\r
+#\r
+def CheckEnvVariable():\r
+    #\r
+    # check WORKSPACE\r
+    #\r
+    if "WORKSPACE" not in environ:\r
+        Logger.Error("UPT",\r
+                     ToolError.UPT_ENVIRON_MISSING_ERROR,\r
+                     ST.ERR_NOT_FOUND_ENVIRONMENT,\r
+                     ExtraData="WORKSPACE")\r
+\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
+    elif ' ' in WorkspaceDir:\r
+        Logger.Error("UPT",\r
+                     ToolError.FORMAT_NOT_SUPPORTED,\r
+                     ST.ERR_SPACE_NOTALLOWED,\r
+                     ExtraData=WorkspaceDir)\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(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 type(ArchList) == list:\r
+        for Arch in ArchList:\r
+            Arch = Arch.upper()\r
+            NewArchList.append(Arch)\r
+    elif type(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 xrange(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
+    OrignalString = 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=OrignalString)\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=OrignalString)\r
+        return False\r
+    if IsValidFileFlag:\r
+        FileLinesList = []\r
+\r
+        try:\r
+            FInputfile = open(FullFileName, "rb", 0)\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