X-Git-Url: https://git.proxmox.com/?a=blobdiff_plain;ds=sidebyside;f=BaseTools%2FSource%2FPython%2FCommon%2FMisc.py;h=d082c58befda5b46aa3f40113c96f1566ded60fd;hb=66b845ae06f1e48c693158ee0b8b4f610d5ada4a;hp=b8c2ce1ddccf9345671f76fcda4af9468ca10eab;hpb=f9bba77495750bb5f9bc5c5864b7c76fece5ec9f;p=mirror_edk2.git diff --git a/BaseTools/Source/Python/Common/Misc.py b/BaseTools/Source/Python/Common/Misc.py index b8c2ce1ddc..d082c58bef 100644 --- a/BaseTools/Source/Python/Common/Misc.py +++ b/BaseTools/Source/Python/Common/Misc.py @@ -1,59 +1,71 @@ ## @file # Common routines used by all tools # -# Copyright (c) 2007 - 2018, Intel Corporation. All rights reserved.
-# 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. +# Copyright (c) 2007 - 2019, Intel Corporation. All rights reserved.
+# SPDX-License-Identifier: BSD-2-Clause-Patent # ## # Import Modules # -import Common.LongFilePathOs as os +from __future__ import absolute_import + import sys import string -import thread import threading import time import re -import cPickle +import pickle import array import shutil +from random import sample from struct import pack -from UserDict import IterableUserDict -from UserList import UserList +import uuid +import subprocess +import tempfile +from collections import OrderedDict +import Common.LongFilePathOs as os from Common import EdkLogger as EdkLogger from Common import GlobalData as GlobalData -from DataType import * -from BuildToolError import * +from Common.DataType import * +from Common.BuildToolError import * from CommonDataClass.DataClass import * -from Parsing import GetSplitValueList +from Common.Parsing import GetSplitValueList from Common.LongFilePathSupport import OpenLongFilePath as open from Common.MultipleWorkspace import MultipleWorkspace as mws -import uuid from CommonDataClass.Exceptions import BadExpression -import subprocess +from Common.caching import cached_property + +ArrayIndex = re.compile("\[\s*[0-9a-fA-FxX]*\s*\]") ## Regular expression used to find out place holders in string template gPlaceholderPattern = re.compile("\$\{([^$()\s]+)\}", re.MULTILINE | re.UNICODE) -## Dictionary used to store file time stamp for quick re-access -gFileTimeStampCache = {} # {file path : file time stamp} +## regular expressions for map file processing +startPatternGeneral = re.compile("^Start[' ']+Length[' ']+Name[' ']+Class") +addressPatternGeneral = re.compile("^Address[' ']+Publics by Value[' ']+Rva\+Base") +valuePatternGcc = re.compile('^([\w_\.]+) +([\da-fA-Fx]+) +([\da-fA-Fx]+)$') +pcdPatternGcc = re.compile('^([\da-fA-Fx]+) +([\da-fA-Fx]+)') +secReGeneral = re.compile('^([\da-fA-F]+):([\da-fA-F]+) +([\da-fA-F]+)[Hh]? +([.\w\$]+) +(\w+)', re.UNICODE) + +StructPattern = re.compile(r'[_a-zA-Z][0-9A-Za-z_]*$') ## Dictionary used to store dependencies of files gDependencyDatabase = {} # arch : {file path : [dependent files list]} +# +# If a module is built more than once with different PCDs or library classes +# a temporary INF file with same content is created, the temporary file is removed +# when build exits. +# +_TempInfs = [] + def GetVariableOffset(mapfilepath, efifilepath, varnames): - """ Parse map file to get variable offset in current EFI file + """ Parse map file to get variable offset in current EFI file @param mapfilepath Map file absolution path @param efifilepath: EFI binary file full path @param varnames iteratable container whose elements are variable names to be searched - + @return List whos elements are tuple with variable name and raw offset """ lines = [] @@ -63,7 +75,7 @@ def GetVariableOffset(mapfilepath, efifilepath, varnames): f.close() except: return None - + if len(lines) == 0: return None firstline = lines[0].strip() if (firstline.startswith("Archive member included ") and @@ -76,7 +88,7 @@ def GetVariableOffset(mapfilepath, efifilepath, varnames): def _parseForXcode(lines, efifilepath, varnames): status = 0 ret = [] - for index, line in enumerate(lines): + for line in lines: line = line.strip() if status == 0 and line == "# Symbols:": status = 1 @@ -84,8 +96,9 @@ def _parseForXcode(lines, efifilepath, varnames): if status == 1 and len(line) != 0: for varname in varnames: if varname in line: + # cannot pregenerate this RegEx since it uses varname from varnames. m = re.match('^([\da-fA-FxX]+)([\s\S]*)([_]*%s)$' % varname, line) - if m != None: + if m is not None: ret.append((varname, m.group(1))) return ret @@ -109,28 +122,28 @@ def _parseForGCC(lines, efifilepath, varnames): # status handler if status == 3: - m = re.match('^([\w_\.]+) +([\da-fA-Fx]+) +([\da-fA-Fx]+)$', line) - if m != None: + m = valuePatternGcc.match(line) + if m is not None: sections.append(m.groups(0)) for varname in varnames: Str = '' m = re.match("^.data.(%s)" % varname, line) - if m != None: + if m is not None: m = re.match(".data.(%s)$" % varname, line) - if m != None: + if m is not None: Str = lines[index + 1] else: Str = line[len(".data.%s" % varname):] if Str: - m = re.match('^([\da-fA-Fx]+) +([\da-fA-Fx]+)', Str.strip()) - if m != None: - varoffset.append((varname, int(m.groups(0)[0], 16) , int(sections[-1][1], 16), sections[-1][0])) + m = pcdPatternGcc.match(Str.strip()) + if m is not None: + varoffset.append((varname, int(m.groups(0)[0], 16), int(sections[-1][1], 16), sections[-1][0])) if not varoffset: return [] # get section information from efi file efisecs = PeImageClass(efifilepath).SectionHeaderList - if efisecs == None or len(efisecs) == 0: + if efisecs is None or len(efisecs) == 0: return [] #redirection redirection = 0 @@ -150,35 +163,35 @@ def _parseGeneral(lines, efifilepath, varnames): status = 0 #0 - beginning of file; 1 - PE section definition; 2 - symbol table secs = [] # key = section name varoffset = [] - secRe = re.compile('^([\da-fA-F]+):([\da-fA-F]+) +([\da-fA-F]+)[Hh]? +([.\w\$]+) +(\w+)', re.UNICODE) symRe = re.compile('^([\da-fA-F]+):([\da-fA-F]+) +([\.:\\\\\w\?@\$]+) +([\da-fA-F]+)', re.UNICODE) for line in lines: line = line.strip() - if re.match("^Start[' ']+Length[' ']+Name[' ']+Class", line): + if startPatternGeneral.match(line): status = 1 continue - if re.match("^Address[' ']+Publics by Value[' ']+Rva\+Base", line): + if addressPatternGeneral.match(line): status = 2 continue - if re.match("^entry point at", line): + if line.startswith("entry point at"): status = 3 - continue + continue if status == 1 and len(line) != 0: - m = secRe.match(line) - assert m != None, "Fail to parse the section in map file , line is %s" % line + m = secReGeneral.match(line) + assert m is not None, "Fail to parse the section in map file , line is %s" % line sec_no, sec_start, sec_length, sec_name, sec_class = m.groups(0) secs.append([int(sec_no, 16), int(sec_start, 16), int(sec_length, 16), sec_name, sec_class]) if status == 2 and len(line) != 0: for varname in varnames: m = symRe.match(line) - assert m != None, "Fail to parse the symbol in map file, line is %s" % line + assert m is not None, "Fail to parse the symbol in map file, line is %s" % line sec_no, sym_offset, sym_name, vir_addr = m.groups(0) sec_no = int(sec_no, 16) sym_offset = int(sym_offset, 16) vir_addr = int(vir_addr, 16) + # cannot pregenerate this RegEx since it uses varname from varnames. m2 = re.match('^[_]*(%s)' % varname, sym_name) - if m2 != None: + if m2 is not None: # fond a binary pcd entry in map file for sec in secs: if sec[0] == sec_no and (sym_offset >= sec[1] and sym_offset < sec[1] + sec[2]): @@ -188,7 +201,7 @@ def _parseGeneral(lines, efifilepath, varnames): # get section information from efi file efisecs = PeImageClass(efifilepath).SectionHeaderList - if efisecs == None or len(efisecs) == 0: + if efisecs is None or len(efisecs) == 0: return [] ret = [] @@ -242,7 +255,7 @@ def ProcessDuplicatedInf(Path, BaseName, Workspace): # # A temporary INF is copied to database path which must have write permission # The temporary will be removed at the end of build - # In case of name conflict, the file name is + # In case of name conflict, the file name is # FILE_GUIDBaseName (0D1B936F-68F3-4589-AFCC-FB8B7AEBC836module.inf) # TempFullPath = os.path.join(DbDir, @@ -253,7 +266,7 @@ def ProcessDuplicatedInf(Path, BaseName, Workspace): # # To build same module more than once, the module path with FILE_GUID overridden has # the file name FILE_GUIDmodule.inf, but the relative path (self.MetaFile.File) is the real path - # in DSC which is used as relative path by C files and other files in INF. + # in DSC which is used as relative path by C files and other files in INF. # A trick was used: all module paths are PathClass instances, after the initialization # of PathClass, the PathClass.Path is overridden by the temporary INF path. # @@ -268,51 +281,26 @@ def ProcessDuplicatedInf(Path, BaseName, Workspace): # RtPath.Path = TempFullPath RtPath.BaseName = BaseName + RtPath.OriginalPath = Path # # If file exists, compare contents # if os.path.exists(TempFullPath): - with open(str(Path), 'rb') as f1: Src = f1.read() - with open(TempFullPath, 'rb') as f2: Dst = f2.read() - if Src == Dst: - return RtPath - GlobalData.gTempInfs.append(TempFullPath) + with open(str(Path), 'rb') as f1, open(TempFullPath, 'rb') as f2: + if f1.read() == f2.read(): + return RtPath + _TempInfs.append(TempFullPath) shutil.copy2(str(Path), TempFullPath) return RtPath -## Remove temporary created INFs whose paths were saved in gTempInfs +## Remove temporary created INFs whose paths were saved in _TempInfs # def ClearDuplicatedInf(): - for File in GlobalData.gTempInfs: + while _TempInfs: + File = _TempInfs.pop() if os.path.exists(File): os.remove(File) -## callback routine for processing variable option -# -# This function can be used to process variable number of option values. The -# typical usage of it is specify architecure list on command line. -# (e.g. -a IA32 X64 IPF) -# -# @param Option Standard callback function parameter -# @param OptionString Standard callback function parameter -# @param Value Standard callback function parameter -# @param Parser Standard callback function parameter -# -# @retval -# -def ProcessVariableArgument(Option, OptionString, Value, Parser): - assert Value is None - Value = [] - RawArgs = Parser.rargs - while RawArgs: - Arg = RawArgs[0] - if (Arg[:2] == "--" and len(Arg) > 2) or \ - (Arg[:1] == "-" and len(Arg) > 1 and Arg[1] != "-"): - break - Value.append(Arg) - del RawArgs[0] - setattr(Parser.values, Option.dest, Value) - ## Convert GUID string in xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx style to C structure style # # @param Guid The GUID string @@ -371,6 +359,8 @@ def GuidStructureByteArrayToGuidString(GuidValue): # @retval string The GUID value in xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx format # def GuidStructureStringToGuidString(GuidValue): + if not GlobalData.gGuidCFormatPattern.match(GuidValue): + return '' guidValueString = GuidValue.lower().replace("{", "").replace("}", "").replace(" ", "").replace(";", "") guidValueList = guidValueString.split(",") if len(guidValueList) != 11: @@ -423,7 +413,7 @@ def GuidStructureStringToGuidValueName(GuidValue): # @param Directory The directory name # def CreateDirectory(Directory): - if Directory == None or Directory.strip() == "": + if Directory is None or Directory.strip() == "": return True try: if not os.access(Directory, os.F_OK): @@ -437,7 +427,7 @@ def CreateDirectory(Directory): # @param Directory The directory name # def RemoveDirectory(Directory, Recursively=False): - if Directory == None or Directory.strip() == "" or not os.path.exists(Directory): + if Directory is None or Directory.strip() == "" or not os.path.exists(Directory): return if Recursively: CurrentDirectory = os.getcwd() @@ -450,32 +440,6 @@ def RemoveDirectory(Directory, Recursively=False): os.chdir(CurrentDirectory) os.rmdir(Directory) -## Check if given file is changed or not -# -# This method is used to check if a file is changed or not between two build -# actions. It makes use a cache to store files timestamp. -# -# @param File The path of file -# -# @retval True If the given file is changed, doesn't exist, or can't be -# found in timestamp cache -# @retval False If the given file is changed -# -def IsChanged(File): - if not os.path.exists(File): - return True - - FileState = os.stat(File) - TimeStamp = FileState[-2] - - if File in gFileTimeStampCache and TimeStamp == gFileTimeStampCache[File]: - FileChanged = False - else: - FileChanged = True - gFileTimeStampCache[File] = TimeStamp - - return FileChanged - ## Store content in file # # This method is used to save file only when its content is changed. This is @@ -489,15 +453,22 @@ def IsChanged(File): # @retval False If the file content is the same # def SaveFileOnChange(File, Content, IsBinaryFile=True): - if not IsBinaryFile: - Content = Content.replace("\n", os.linesep) if os.path.exists(File): - try: - if Content == open(File, "rb").read(): - return False - except: - EdkLogger.error(None, FILE_OPEN_FAILURE, ExtraData=File) + if IsBinaryFile: + try: + with open(File, "rb") as f: + if Content == f.read(): + return False + except: + EdkLogger.error(None, FILE_OPEN_FAILURE, ExtraData=File) + else: + try: + with open(File, "r") as f: + if Content == f.read(): + return False + except: + EdkLogger.error(None, FILE_OPEN_FAILURE, ExtraData=File) DirName = os.path.dirname(File) if not CreateDirectory(DirName): @@ -508,62 +479,29 @@ def SaveFileOnChange(File, Content, IsBinaryFile=True): 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: - from PyUtility import SaveFileToDisk - if not SaveFileToDisk(File, Content): - EdkLogger.error(None, FILE_CREATE_FAILURE, ExtraData=File) - except: - Fd = open(File, "wb") + OpenMode = "w" + if IsBinaryFile: + OpenMode = "wb" + + if GlobalData.gIsWindows and not os.path.exists(File): + # write temp file, then rename the temp file to the real file + # to make sure the file be immediate saved to disk + with tempfile.NamedTemporaryFile(OpenMode, dir=os.path.dirname(File), delete=False) as tf: + tf.write(Content) + tempname = tf.name + try: + os.rename(tempname, File) + except: + EdkLogger.error(None, FILE_CREATE_FAILURE, ExtraData='IOError %s' % X) + else: + try: + with open(File, OpenMode) as Fd: Fd.write(Content) - Fd.close() - else: - Fd = open(File, "wb") - Fd.write(Content) - Fd.close() - except IOError, X: - EdkLogger.error(None, FILE_CREATE_FAILURE, ExtraData='IOError %s' % X) + except IOError as X: + EdkLogger.error(None, FILE_CREATE_FAILURE, ExtraData='IOError %s' % X) return True -## Make a Python object persistent on file system -# -# @param Data The object to be stored in file -# @param File The path of file to store the object -# -def DataDump(Data, File): - Fd = None - try: - Fd = open(File, 'wb') - cPickle.dump(Data, Fd, cPickle.HIGHEST_PROTOCOL) - except: - EdkLogger.error("", FILE_OPEN_FAILURE, ExtraData=File, RaiseError=False) - finally: - if Fd != None: - Fd.close() - -## Restore a Python object from a file -# -# @param File The path of file stored the object -# -# @retval object A python object -# @retval None If failure in file operation -# -def DataRestore(File): - Data = None - Fd = None - try: - Fd = open(File, 'rb') - Data = cPickle.load(Fd) - except Exception, e: - EdkLogger.verbose("Failed to load [%s]\n\t%s" % (File, str(e))) - Data = None - finally: - if Fd != None: - Fd.close() - return Data - ## Retrieve and cache the real path name in file system # # @param Root The root directory of path relative to @@ -635,47 +573,6 @@ class DirCache: return os.path.join(self._Root, self._UPPER_CACHE_[UpperPath]) return None -## Get all files of a directory -# -# @param Root: Root dir -# @param SkipList : The files need be skipped -# -# @retval A list of all files -# -def GetFiles(Root, SkipList=None, FullPath=True): - OriPath = Root - FileList = [] - for Root, Dirs, Files in os.walk(Root): - if SkipList: - for Item in SkipList: - if Item in Dirs: - Dirs.remove(Item) - - for File in Files: - File = os.path.normpath(os.path.join(Root, File)) - if not FullPath: - File = File[len(OriPath) + 1:] - FileList.append(File) - - return FileList - -## Check if gvien file exists or not -# -# @param File File name or path to be checked -# @param Dir The directory the file is relative to -# -# @retval True if file exists -# @retval False if file doesn't exists -# -def ValidFile(File, Ext=None): - if Ext != None: - Dummy, FileExt = os.path.splitext(File) - if FileExt.lower() != Ext.lower(): - return False - if not os.path.exists(File): - return False - return True - def RealPath(File, Dir='', OverrideDir=''): NewFile = os.path.normpath(os.path.join(Dir, File)) NewFile = GlobalData.gAllFiles[NewFile] @@ -684,141 +581,6 @@ def RealPath(File, Dir='', OverrideDir=''): NewFile = GlobalData.gAllFiles[NewFile] return NewFile -def RealPath2(File, Dir='', OverrideDir=''): - NewFile = None - 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))] - if not NewFile: - NewFile = os.path.normpath(os.path.join(Dir, File)) - if not os.path.exists(NewFile): - return None, None - 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 - -## Check if gvien file exists or not -# -# -def ValidFile2(AllFiles, File, Ext=None, Workspace='', EfiSource='', EdkSource='', Dir='.', OverrideDir=''): - NewFile = File - if Ext != None: - Dummy, FileExt = os.path.splitext(File) - if FileExt.lower() != Ext.lower(): - return False, File - - # Replace the Edk macros - if OverrideDir != '' and OverrideDir != None: - if OverrideDir.find('$(EFI_SOURCE)') > -1: - OverrideDir = OverrideDir.replace('$(EFI_SOURCE)', EfiSource) - if OverrideDir.find('$(EDK_SOURCE)') > -1: - OverrideDir = OverrideDir.replace('$(EDK_SOURCE)', EdkSource) - - # Replace the default dir to current dir - if Dir == '.': - Dir = os.getcwd() - Dir = Dir[len(Workspace) + 1:] - - # 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) - NewFile = AllFiles[os.path.normpath(NewFile)] - if NewFile != None: - return True, NewFile - - # Second check the path with override value - if OverrideDir != '' and OverrideDir != None: - NewFile = AllFiles[os.path.normpath(os.path.join(OverrideDir, File))] - if NewFile != None: - return True, NewFile - - # Last check the path with normal definitions - File = os.path.join(Dir, File) - NewFile = AllFiles[os.path.normpath(File)] - if NewFile != None: - return True, NewFile - - return False, File - -## Check if gvien file exists or not -# -# -def ValidFile3(AllFiles, File, Workspace='', EfiSource='', EdkSource='', Dir='.', OverrideDir=''): - # Replace the Edk macros - if OverrideDir != '' and OverrideDir != None: - if OverrideDir.find('$(EFI_SOURCE)') > -1: - OverrideDir = OverrideDir.replace('$(EFI_SOURCE)', EfiSource) - if OverrideDir.find('$(EDK_SOURCE)') > -1: - OverrideDir = OverrideDir.replace('$(EDK_SOURCE)', EdkSource) - - # Replace the default dir to current dir - # Dir is current module dir related to workspace - if Dir == '.': - Dir = os.getcwd() - Dir = Dir[len(Workspace) + 1:] - - NewFile = File - RelaPath = AllFiles[os.path.normpath(Dir)] - NewRelaPath = RelaPath - - while(True): - # 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) - NewFile = AllFiles[os.path.normpath(File)] - if NewFile != None: - NewRelaPath = os.path.dirname(NewFile) - File = os.path.basename(NewFile) - #NewRelaPath = NewFile[:len(NewFile) - len(File.replace("..\\", '').replace("../", '')) - 1] - break - - # Second check the path with override value - if OverrideDir != '' and OverrideDir != None: - NewFile = AllFiles[os.path.normpath(os.path.join(OverrideDir, File))] - if NewFile != None: - #NewRelaPath = os.path.dirname(NewFile) - NewRelaPath = NewFile[:len(NewFile) - len(File.replace("..\\", '').replace("../", '')) - 1] - break - - # Last check the path with normal definitions - NewFile = AllFiles[os.path.normpath(os.path.join(Dir, File))] - if NewFile != None: - break - - # No file found - break - - return NewRelaPath, RelaPath, File - - -def GetRelPath(Path1, Path2): - FileName = os.path.basename(Path2) - L1 = os.path.normpath(Path1).split(os.path.normpath('/')) - L2 = os.path.normpath(Path2).split(os.path.normpath('/')) - for Index in range(0, len(L1)): - if L1[Index] != L2[Index]: - FileName = '../' * (len(L1) - Index) - for Index2 in range(Index, len(L2)): - FileName = os.path.join(FileName, L2[Index2]) - break - return os.path.normpath(FileName) - - ## Get GUID value from given packages # # @param CName The CName of the GUID @@ -830,50 +592,13 @@ def GetRelPath(Path1, Path2): # def GuidValue(CName, PackageList, Inffile = None): for P in PackageList: - GuidKeys = P.Guids.keys() + GuidKeys = list(P.Guids.keys()) if Inffile and P._PrivateGuids: if not Inffile.startswith(P.MetaFile.Dir): - GuidKeys = (dict.fromkeys(x for x in P.Guids if x not in P._PrivateGuids)).keys() + GuidKeys = [x for x in P.Guids if x not in P._PrivateGuids] if CName in GuidKeys: return P.Guids[CName] return None - -## Get Protocol value from given packages -# -# @param CName The CName of the GUID -# @param PackageList List of packages looking-up in -# @param Inffile The driver file -# -# @retval GuidValue if the CName is found in any given package -# @retval None if the CName is not found in all given packages -# -def ProtocolValue(CName, PackageList, Inffile = None): - for P in PackageList: - ProtocolKeys = P.Protocols.keys() - if Inffile and P._PrivateProtocols: - if not Inffile.startswith(P.MetaFile.Dir): - ProtocolKeys = (dict.fromkeys(x for x in P.Protocols if x not in P._PrivateProtocols)).keys() - if CName in ProtocolKeys: - return P.Protocols[CName] - return None - -## Get PPI value from given packages -# -# @param CName The CName of the GUID -# @param PackageList List of packages looking-up in -# @param Inffile The driver file -# -# @retval GuidValue if the CName is found in any given package -# @retval None if the CName is not found in all given packages -# -def PpiValue(CName, PackageList, Inffile = None): - for P in PackageList: - PpiKeys = P.Ppis.keys() - if Inffile and P._PrivatePpis: - if not Inffile.startswith(P.MetaFile.Dir): - PpiKeys = (dict.fromkeys(x for x in P.Ppis if x not in P._PrivatePpis)).keys() - if CName in PpiKeys: - return P.Ppis[CName] return None ## A string template class @@ -969,7 +694,7 @@ class TemplateString(object): ## Constructor def __init__(self, Template=None): - self.String = '' + self.String = [] self.IsBinary = False self._Template = Template self._TemplateSectionList = self._Parse(Template) @@ -979,7 +704,7 @@ class TemplateString(object): # @retval string The string replaced # def __str__(self): - return self.String + return "".join(self.String) ## Split the template string into fragments per the ${BEGIN} and ${END} flags # @@ -1027,9 +752,12 @@ class TemplateString(object): def Append(self, AppendString, Dictionary=None): if Dictionary: SectionList = self._Parse(AppendString) - self.String += "".join([S.Instantiate(Dictionary) for S in SectionList]) + self.String.append( "".join(S.Instantiate(Dictionary) for S in SectionList)) else: - self.String += AppendString + if isinstance(AppendString,list): + self.String.extend(AppendString) + else: + self.String.append(AppendString) ## Replace the string template with dictionary of placeholders # @@ -1038,7 +766,7 @@ class TemplateString(object): # @retval str The string replaced with placeholder values # def Replace(self, Dictionary=None): - return "".join([S.Instantiate(Dictionary) for S in self._TemplateSectionList]) + return "".join(S.Instantiate(Dictionary) for S in self._TemplateSectionList) ## Progress indicator class # @@ -1052,39 +780,39 @@ class Progressor: ## Constructor # - # @param OpenMessage The string printed before progress charaters - # @param CloseMessage The string printed after progress charaters - # @param ProgressChar The charater used to indicate the progress - # @param Interval The interval in seconds between two progress charaters + # @param OpenMessage The string printed before progress characters + # @param CloseMessage The string printed after progress characters + # @param ProgressChar The character used to indicate the progress + # @param Interval The interval in seconds between two progress characters # def __init__(self, OpenMessage="", CloseMessage="", ProgressChar='.', Interval=1.0): self.PromptMessage = OpenMessage self.CodaMessage = CloseMessage self.ProgressChar = ProgressChar self.Interval = Interval - if Progressor._StopFlag == None: + if Progressor._StopFlag is None: Progressor._StopFlag = threading.Event() - ## Start to print progress charater + ## Start to print progress character # - # @param OpenMessage The string printed before progress charaters + # @param OpenMessage The string printed before progress characters # def Start(self, OpenMessage=None): - if OpenMessage != None: + if OpenMessage is not None: self.PromptMessage = OpenMessage Progressor._StopFlag.clear() - if Progressor._ProgressThread == None: + if Progressor._ProgressThread is None: Progressor._ProgressThread = threading.Thread(target=self._ProgressThreadEntry) Progressor._ProgressThread.setDaemon(False) Progressor._ProgressThread.start() - ## Stop printing progress charater + ## Stop printing progress character # - # @param CloseMessage The string printed after progress charaters + # @param CloseMessage The string printed after progress characters # def Stop(self, CloseMessage=None): OriginalCodaMessage = self.CodaMessage - if CloseMessage != None: + if CloseMessage is not None: self.CodaMessage = CloseMessage self.Abort() self.CodaMessage = OriginalCodaMessage @@ -1107,171 +835,12 @@ class Progressor: ## Abort the progress display @staticmethod def Abort(): - if Progressor._StopFlag != None: + if Progressor._StopFlag is not None: Progressor._StopFlag.set() - if Progressor._ProgressThread != None: + if Progressor._ProgressThread is not None: Progressor._ProgressThread.join() Progressor._ProgressThread = 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, sdict): - for key in sdict: - if key not in self._key_list: - self._key_list.append(key) - IterableUserDict.__setitem__(self, key, sdict[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 = kv[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 - - def update(self, dict=None, **kwargs): - if dict != None: - for k, v in dict.items(): - self[k] = v - if len(kwargs): - for k, v in kwargs.items(): - self[k] = v - -## Dictionary with restricted keys -# -class rdict(dict): - ## Constructor - def __init__(self, KeyList): - for Key in KeyList: - dict.__setitem__(self, Key, "") - - ## []= operator - def __setitem__(self, key, value): - if key not in self: - EdkLogger.error("RestrictedDict", ATTRIBUTE_SET_FAILURE, "Key [%s] is not allowed" % key, - ExtraData=", ".join(dict.keys(self))) - dict.__setitem__(self, key, value) - - ## =[] operator - def __getitem__(self, key): - if key not in self: - return "" - return dict.__getitem__(self, key) - - ## del operator - def __delitem__(self, key): - EdkLogger.error("RestrictedDict", ATTRIBUTE_ACCESS_DENIED, ExtraData="del") - - ## Empty the dict - def clear(self): - for Key in self: - self.__setitem__(Key, "") - - ## Return value related to a key, and remove the (key, value) from the dict - def pop(self, key, *dv): - EdkLogger.error("RestrictedDict", ATTRIBUTE_ACCESS_DENIED, ExtraData="pop") - - ## Return (key, value) pair, and remove the (key, value) from the dict - def popitem(self): - EdkLogger.error("RestrictedDict", ATTRIBUTE_ACCESS_DENIED, ExtraData="popitem") ## Dictionary using prioritized list as key # @@ -1279,7 +848,7 @@ class tdict: _ListType = type([]) _TupleType = type(()) _Wildcard = 'COMMON' - _ValidWildcardList = ['COMMON', 'DEFAULT', 'ALL', '*', 'PLATFORM'] + _ValidWildcardList = ['COMMON', 'DEFAULT', 'ALL', TAB_STAR, 'PLATFORM'] def __init__(self, _Single_=False, _Level_=2): self._Level_ = _Level_ @@ -1301,7 +870,7 @@ class tdict: if self._Level_ > 1: RestKeys = [self._Wildcard for i in range(0, self._Level_ - 1)] - if FirstKey == None or str(FirstKey).upper() in self._ValidWildcardList: + if FirstKey is None or str(FirstKey).upper() in self._ValidWildcardList: FirstKey = self._Wildcard if self._Single_: @@ -1316,24 +885,24 @@ class tdict: if FirstKey == self._Wildcard: if FirstKey in self.data: Value = self.data[FirstKey][RestKeys] - if Value == None: + if Value is None: for Key in self.data: Value = self.data[Key][RestKeys] - if Value != None: break + if Value is not None: break else: if FirstKey in self.data: Value = self.data[FirstKey][RestKeys] - if Value == None and self._Wildcard in self.data: + if Value is None and self._Wildcard in self.data: #print "Value=None" Value = self.data[self._Wildcard][RestKeys] else: if FirstKey == self._Wildcard: if FirstKey in self.data: Value = self.data[FirstKey] - if Value == None: + if Value is None: for Key in self.data: Value = self.data[Key] - if Value != None: break + if Value is not None: break else: if FirstKey in self.data: Value = self.data[FirstKey] @@ -1411,53 +980,29 @@ class tdict: keys |= self.data[Key].GetKeys(KeyIndex - 1) return keys -## Boolean chain list -# -class Blist(UserList): - def __init__(self, initlist=None): - UserList.__init__(self, initlist) - def __setitem__(self, i, item): - if item not in [True, False]: - if item == 0: - item = False - else: - item = True - self.data[i] = item - def _GetResult(self): - Value = True - for item in self.data: - Value &= item - return Value - Result = property(_GetResult) - -def ParseConsoleLog(Filename): - Opr = open(os.path.normpath(Filename), 'r') - Opw = open(os.path.normpath(Filename + '.New'), 'w+') - for Line in Opr.readlines(): - if Line.find('.efi') > -1: - Line = Line[Line.rfind(' ') : Line.rfind('.efi')].strip() - Opw.write('%s\n' % Line) - - Opr.close() - Opw.close() - def AnalyzePcdExpression(Setting): - Setting = Setting.strip() - # There might be escaped quote in a string: \", \\\" - Data = Setting.replace('\\\\', '//').replace('\\\"', '\\\'') + RanStr = ''.join(sample(string.ascii_letters + string.digits, 8)) + Setting = Setting.replace('\\\\', RanStr).strip() + # There might be escaped quote in a string: \", \\\" , \', \\\' + Data = Setting # There might be '|' in string and in ( ... | ... ), replace it with '-' NewStr = '' - InStr = False + InSingleQuoteStr = False + InDoubleQuoteStr = False Pair = 0 - for ch in Data: - if ch == '"': - InStr = not InStr - elif ch == '(' and not InStr: + for Index, ch in enumerate(Data): + if ch == '"' and not InSingleQuoteStr: + if Data[Index - 1] != '\\': + InDoubleQuoteStr = not InDoubleQuoteStr + elif ch == "'" and not InDoubleQuoteStr: + if Data[Index - 1] != '\\': + InSingleQuoteStr = not InSingleQuoteStr + elif ch == '(' and not (InSingleQuoteStr or InDoubleQuoteStr): Pair += 1 - elif ch == ')' and not InStr: + elif ch == ')' and not (InSingleQuoteStr or InDoubleQuoteStr): Pair -= 1 - if (Pair > 0 or InStr) and ch == TAB_VALUE_SPLIT: + if (Pair > 0 or InSingleQuoteStr or InDoubleQuoteStr) and ch == TAB_VALUE_SPLIT: NewStr += '-' else: NewStr += ch @@ -1470,92 +1015,87 @@ def AnalyzePcdExpression(Setting): break FieldList.append(Setting[StartPos:Pos].strip()) StartPos = Pos + 1 - + for i, ch in enumerate(FieldList): + if RanStr in ch: + FieldList[i] = ch.replace(RanStr,'\\\\') return FieldList -def ParseDevPathValue (Value): - DevPathList = [ "Path","HardwarePath","Pci","PcCard","MemoryMapped","VenHw","Ctrl","BMC","AcpiPath","Acpi","PciRoot", - "PcieRoot","Floppy","Keyboard","Serial","ParallelPort","AcpiEx","AcpiExp","AcpiAdr","Msg","Ata","Scsi", - "Fibre","FibreEx","I1394","USB","I2O","Infiniband","VenMsg","VenPcAnsi","VenVt100","VenVt100Plus", - "VenUtf8","UartFlowCtrl","SAS","SasEx","NVMe","UFS","SD","eMMC","DebugPort","MAC","IPv4","IPv6","Uart", - "UsbClass","UsbAudio","UsbCDCControl","UsbHID","UsbImage","UsbPrinter","UsbMassStorage","UsbHub", - "UsbCDCData","UsbSmartCard","UsbVideo","UsbDiagnostic","UsbWireless","UsbDeviceFirmwareUpdate", - "UsbIrdaBridge","UsbTestAndMeasurement","UsbWwid","Unit","iSCSI","Vlan","Uri","Bluetooth","Wi-Fi", - "MediaPath","HD","CDROM","VenMedia","Media","Fv","FvFile","Offset","RamDisk","VirtualDisk","VirtualCD", - "PersistentVirtualDisk","PersistentVirtualCD","BbsPath","BBS","Sata" ] - if '\\' in Value: - Value.replace('\\', '/').replace(' ', '') - for Item in Value.split('/'): - Key = Item.strip().split('(')[0] - if Key not in DevPathList: - pass - - Cmd = 'DevicePath ' + '"' + Value + '"' - try: - p = subprocess.Popen(Cmd, stdout=subprocess.PIPE, stderr=subprocess.PIPE, shell=True) - out, err = p.communicate() - except Exception, X: - raise BadExpression("DevicePath: %s" % (str(X)) ) - finally: - subprocess._cleanup() - p.stdout.close() - p.stderr.close() - if err: - raise BadExpression("DevicePath: %s" % str(err)) - Size = len(out.split()) - out = ','.join(out.split()) - return '{' + out + '}', Size - def ParseFieldValue (Value): - if type(Value) == type(0): - return Value, (Value.bit_length() + 7) / 8 - if type(Value) <> type(''): + def ParseDevPathValue (Value): + if '\\' in Value: + Value.replace('\\', '/').replace(' ', '') + + Cmd = 'DevicePath ' + '"' + Value + '"' + try: + p = subprocess.Popen(Cmd, stdout=subprocess.PIPE, stderr=subprocess.PIPE, shell=True) + out, err = p.communicate() + except Exception as X: + raise BadExpression("DevicePath: %s" % (str(X)) ) + finally: + subprocess._cleanup() + p.stdout.close() + p.stderr.close() + if err: + raise BadExpression("DevicePath: %s" % str(err)) + out = out.decode(encoding='utf-8', errors='ignore') + Size = len(out.split()) + out = ','.join(out.split()) + return '{' + out + '}', Size + + if "{CODE(" in Value: + return Value, len(Value.split(",")) + if isinstance(Value, type(0)): + return Value, (Value.bit_length() + 7) // 8 + if not isinstance(Value, type('')): raise BadExpression('Type %s is %s' %(Value, type(Value))) Value = Value.strip() - if Value.startswith('UINT8') and Value.endswith(')'): + if Value.startswith(TAB_UINT8) and Value.endswith(')'): Value, Size = ParseFieldValue(Value.split('(', 1)[1][:-1]) if Size > 1: raise BadExpression('Value (%s) Size larger than %d' %(Value, Size)) return Value, 1 - if Value.startswith('UINT16') and Value.endswith(')'): + if Value.startswith(TAB_UINT16) and Value.endswith(')'): Value, Size = ParseFieldValue(Value.split('(', 1)[1][:-1]) if Size > 2: raise BadExpression('Value (%s) Size larger than %d' %(Value, Size)) return Value, 2 - if Value.startswith('UINT32') and Value.endswith(')'): + if Value.startswith(TAB_UINT32) and Value.endswith(')'): Value, Size = ParseFieldValue(Value.split('(', 1)[1][:-1]) if Size > 4: raise BadExpression('Value (%s) Size larger than %d' %(Value, Size)) return Value, 4 - if Value.startswith('UINT64') and Value.endswith(')'): + if Value.startswith(TAB_UINT64) and Value.endswith(')'): Value, Size = ParseFieldValue(Value.split('(', 1)[1][:-1]) if Size > 8: raise BadExpression('Value (%s) Size larger than %d' % (Value, Size)) return Value, 8 - if Value.startswith('GUID') and Value.endswith(')'): + if Value.startswith(TAB_GUID) and Value.endswith(')'): Value = Value.split('(', 1)[1][:-1].strip() if Value[0] == '{' and Value[-1] == '}': - Value = Value[1:-1].strip() - Value = Value.split('{', 1) - Value = ['%02x' % int(Item, 16) for Item in (Value[0] + Value[1][:-1]).split(',')] - if len(Value[0]) != 8: - Value[0] = '%08X' % int(Value[0], 16) - if len(Value[1]) != 4: - Value[1] = '%04X' % int(Value[1], 16) - if len(Value[2]) != 4: - Value[2] = '%04X' % int(Value[2], 16) - Value = '-'.join(Value[0:3]) + '-' + ''.join(Value[3:5]) + '-' + ''.join(Value[5:11]) + TmpValue = GuidStructureStringToGuidString(Value) + if not TmpValue: + raise BadExpression("Invalid GUID value string %s" % Value) + Value = TmpValue if Value[0] == '"' and Value[-1] == '"': Value = Value[1:-1] try: - Value = "'" + uuid.UUID(Value).get_bytes_le() + "'" - except ValueError, Message: - raise BadExpression('%s' % Message) + Value = str(uuid.UUID(Value).bytes_le) + if Value.startswith("b'"): + Value = Value[2:-1] + Value = "'" + Value + "'" + except ValueError as Message: + raise BadExpression(Message) Value, Size = ParseFieldValue(Value) return Value, 16 if Value.startswith('L"') and Value.endswith('"'): # Unicode String - List = list(Value[2:-1]) + # translate escape character + Value = Value[1:] + try: + Value = eval(Value) + except: + Value = Value[1:-1] + List = list(Value) List.reverse() Value = 0 for Char in List: @@ -1563,7 +1103,12 @@ def ParseFieldValue (Value): return Value, (len(List) + 1) * 2 if Value.startswith('"') and Value.endswith('"'): # ASCII String - List = list(Value[1:-1]) + # translate escape character + try: + Value = eval(Value) + except: + Value = Value[1:-1] + List = list(Value) List.reverse() Value = 0 for Char in List: @@ -1571,7 +1116,13 @@ def ParseFieldValue (Value): return Value, len(List) + 1 if Value.startswith("L'") and Value.endswith("'"): # Unicode Character Constant - List = list(Value[2:-1]) + # translate escape character + Value = Value[1:] + try: + Value = eval(Value) + except: + Value = Value[1:-1] + List = list(Value) if len(List) == 0: raise BadExpression('Length %s is %s' % (Value, len(List))) List.reverse() @@ -1581,7 +1132,12 @@ def ParseFieldValue (Value): return Value, len(List) * 2 if Value.startswith("'") and Value.endswith("'"): # Character constant - List = list(Value[1:-1]) + # translate escape character + try: + Value = eval(Value) + except: + Value = Value[1:-1] + List = list(Value) if len(List) == 0: raise BadExpression('Length %s is %s' % (Value, len(List))) List.reverse() @@ -1603,18 +1159,22 @@ def ParseFieldValue (Value): Value = (Value << 8) | ((ItemValue >> 8 * I) & 0xff) return Value, RetSize if Value.startswith('DEVICE_PATH(') and Value.endswith(')'): - Value = Value.split('"')[1] + Value = Value.replace("DEVICE_PATH(", '').rstrip(')') + Value = Value.strip().strip('"') return ParseDevPathValue(Value) if Value.lower().startswith('0x'): - Value = int(Value, 16) + try: + Value = int(Value, 16) + except: + raise BadExpression("invalid hex value: %s" % Value) if Value == 0: return 0, 1 - return Value, (Value.bit_length() + 7) / 8 + return Value, (Value.bit_length() + 7) // 8 if Value[0].isdigit(): Value = int(Value, 10) if Value == 0: return 0, 1 - return Value, (Value.bit_length() + 7) / 8 + return Value, (Value.bit_length() + 7) // 8 if Value.lower() == 'true': return 1, 1 if Value.lower() == 'false': @@ -1624,9 +1184,9 @@ def ParseFieldValue (Value): ## 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 +# This function is used to match functions (AnalyzePcdData) used for retrieving PCD value from database # 1. Feature flag: TokenSpace.PcdCName|PcdValue -# 2. Fix and Patch:TokenSpace.PcdCName|PcdValue[|MaxSize] +# 2. Fix and Patch:TokenSpace.PcdCName|PcdValue[|VOID*[|MaxSize]] # 3. Dynamic default: # TokenSpace.PcdCName|PcdValue[|VOID*[|MaxSize]] # TokenSpace.PcdCName|PcdValue @@ -1634,7 +1194,7 @@ def ParseFieldValue (Value): # TokenSpace.PcdCName|VpdOffset[|VpdValue] # TokenSpace.PcdCName|VpdOffset[|MaxSize[|VpdValue]] # 5. Dynamic HII: -# TokenSpace.PcdCName|HiiString|VaiableGuid|VariableOffset[|HiiValue] +# TokenSpace.PcdCName|HiiString|VariableGuid|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. # @@ -1650,62 +1210,37 @@ def AnalyzeDscPcd(Setting, PcdType, DataType=''): FieldList = AnalyzePcdExpression(Setting) IsValid = True - if PcdType in (MODEL_PCD_FIXED_AT_BUILD, MODEL_PCD_PATCHABLE_IN_MODULE, MODEL_PCD_FEATURE_FLAG): + if PcdType in (MODEL_PCD_FIXED_AT_BUILD, MODEL_PCD_PATCHABLE_IN_MODULE, MODEL_PCD_DYNAMIC_DEFAULT, MODEL_PCD_DYNAMIC_EX_DEFAULT): Value = FieldList[0] Size = '' - if len(FieldList) > 1: - if FieldList[1].upper().startswith("0X") or FieldList[1].isdigit(): - Size = FieldList[1] - else: - DataType = FieldList[1] - - if len(FieldList) > 2: - Size = FieldList[2] - if DataType == "": - IsValid = (len(FieldList) <= 1) - else: - IsValid = (len(FieldList) <= 3) -# Value, Size = ParseFieldValue(Value) - if Size: - try: - int(Size,16) if Size.upper().startswith("0X") else int(Size) - except: + if len(FieldList) > 1 and FieldList[1]: + DataType = FieldList[1] + if FieldList[1] != TAB_VOID and StructPattern.match(FieldList[1]) is None: IsValid = False - Size = -1 - return [str(Value), '', str(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] - else: - Type = DataType if len(FieldList) > 2: Size = FieldList[2] - else: - if Type == 'VOID*': - if Value.startswith("L"): - Size = str((len(Value)- 3 + 1) * 2) - elif Value.startswith("{"): - Size = str(len(Value.split(","))) - else: - Size = str(len(Value) -2 + 1 ) - if DataType == "": - IsValid = (len(FieldList) <= 1) - else: - IsValid = (len(FieldList) <= 3) + if IsValid: + if DataType == "": + IsValid = (len(FieldList) <= 1) + else: + IsValid = (len(FieldList) <= 3) if Size: try: - int(Size,16) if Size.upper().startswith("0X") else int(Size) + int(Size, 16) if Size.upper().startswith("0X") else int(Size) except: IsValid = False Size = -1 - return [Value, Type, str(Size)], IsValid, 0 + return [str(Value), DataType, str(Size)], IsValid, 0 + elif PcdType == MODEL_PCD_FEATURE_FLAG: + Value = FieldList[0] + Size = '' + IsValid = (len(FieldList) <= 1) + return [Value, DataType, str(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 not DataType == TAB_VOID: if len(FieldList) > 1: Value = FieldList[1] else: @@ -1719,12 +1254,13 @@ def AnalyzeDscPcd(Setting, PcdType, DataType=''): IsValid = (len(FieldList) <= 3) if Size: try: - int(Size,16) if Size.upper().startswith("0X") else int(Size) + int(Size, 16) if Size.upper().startswith("0X") else int(Size) except: IsValid = False Size = -1 return [VpdOffset, str(Size), Value], IsValid, 2 elif PcdType in (MODEL_PCD_DYNAMIC_HII, MODEL_PCD_DYNAMIC_EX_HII): + IsValid = (3 <= len(FieldList) <= 5) HiiString = FieldList[0] Guid = Offset = Value = Attribute = '' if len(FieldList) > 1: @@ -1735,7 +1271,6 @@ def AnalyzeDscPcd(Setting, PcdType, DataType=''): Value = FieldList[3] if len(FieldList) > 4: Attribute = FieldList[4] - IsValid = (3 <= len(FieldList) <= 5) return [HiiString, Guid, Offset, Value, Attribute], IsValid, 3 return [], False, 0 @@ -1745,81 +1280,35 @@ def AnalyzeDscPcd(Setting, PcdType, DataType=''): # 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. +# +# @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 = ['', '', '', ''] - - TokenList = GetSplitValueList(Setting) - ValueList[0:len(TokenList)] = TokenList 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 Type == TAB_VOID: ValueRe = re.compile(r'\s*L?\".*\"\s*$') if not (((Value.startswith('L"') or Value.startswith('"')) and Value.endswith('"')) or (Value.startswith('{') and Value.endswith('}')) or (Value.startswith("L'") or Value.startswith("'") and Value.endswith("'")) @@ -1837,16 +1326,21 @@ def CheckPcdDatum(Type, Value): Printset.add(TAB_PRINTCHAR_BS) Printset.add(TAB_PRINTCHAR_NUL) if not set(Value).issubset(Printset): - PrintList = list(Printset) - PrintList.sort() + PrintList = sorted(Printset) return False, "Invalid PCD string value of type [%s]; must be printable chars %s." % (Type, PrintList) elif Type == 'BOOLEAN': 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]: + if Value.startswith('0') and not Value.lower().startswith('0x') and len(Value) > 1 and Value.lstrip('0'): + Value = Value.lstrip('0') try: - Value = long(Value, 0) + if Value and int(Value, 0) < 0: + return False, "PCD can't be set to negative value[%s] for datum type [%s]" % (Value, Type) + Value = int(Value, 0) + if Value > MAX_VAL_TYPE[Type]: + return False, "Too large PCD value[%s] for datum type [%s]" % (Value, Type) except: return False, "Invalid value [%s] of type [%s];"\ " must be a hexadecimal, decimal or octal in C language format." % (Value, Type) @@ -1855,82 +1349,14 @@ def CheckPcdDatum(Type, Value): return True, "" -## Split command line option string to list -# -# subprocess.Popen needs the args to be a sequence. Otherwise there's problem -# in non-windows platform to launch command -# -def SplitOption(OptionString): - OptionList = [] - LastChar = " " - OptionStart = 0 - QuotationMark = "" - for Index in range(0, len(OptionString)): - CurrentChar = OptionString[Index] - if CurrentChar in ['"', "'"]: - if QuotationMark == CurrentChar: - QuotationMark = "" - elif QuotationMark == "": - QuotationMark = CurrentChar - continue - elif QuotationMark: - continue - - if CurrentChar in ["/", "-"] and LastChar in [" ", "\t", "\r", "\n"]: - if Index > OptionStart: - OptionList.append(OptionString[OptionStart:Index - 1]) - OptionStart = Index - LastChar = CurrentChar - OptionList.append(OptionString[OptionStart:]) - return OptionList - def CommonPath(PathList): P1 = min(PathList).split(os.path.sep) P2 = max(PathList).split(os.path.sep) - for Index in xrange(min(len(P1), len(P2))): + for Index in range(min(len(P1), len(P2))): if P1[Index] != P2[Index]: return os.path.sep.join(P1[:Index]) return os.path.sep.join(P1) -# -# Convert string to C format array -# -def ConvertStringToByteArray(Value): - Value = Value.strip() - if not Value: - return None - if Value[0] == '{': - if not Value.endswith('}'): - return None - Value = Value.replace(' ', '').replace('{', '').replace('}', '') - ValFields = Value.split(',') - try: - for Index in range(len(ValFields)): - ValFields[Index] = str(int(ValFields[Index], 0)) - except ValueError: - return None - Value = '{' + ','.join(ValFields) + '}' - return Value - - Unicode = False - if Value.startswith('L"'): - if not Value.endswith('"'): - return None - Value = Value[1:] - Unicode = True - elif not Value.startswith('"') or not Value.endswith('"'): - return None - - Value = eval(Value) # translate escape character - NewValue = '{' - for Index in range(0,len(Value)): - if Unicode: - NewValue = NewValue + str(ord(Value[Index]) % 0x10000) + ',' - else: - NewValue = NewValue + str(ord(Value[Index]) % 0x100) + ',' - Value = NewValue + '0}' - return Value - class PathClass(object): def __init__(self, File='', Root='', AlterRoot='', Type='', IsBinary=False, Arch='COMMON', ToolChainFamily='', Target='', TagName='', ToolCode=''): @@ -1980,8 +1406,7 @@ class PathClass(object): self.TagName = TagName self.ToolCode = ToolCode self.ToolChainFamily = ToolChainFamily - - self._Key = None + self.OriginalPath = self ## Convert the object of this class to a string # @@ -2000,24 +1425,18 @@ class PathClass(object): # @retval True The two PathClass are the same # def __eq__(self, Other): - if type(Other) == type(self): - return self.Path == Other.Path - else: - return self.Path == str(Other) + return self.Path == str(Other) ## Override __cmp__ function # - # Customize the comparsion operation of two PathClass + # Customize the comparison 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) - + OtherKey = str(Other) + SelfKey = self.Path if SelfKey == OtherKey: return 0 @@ -2035,15 +1454,41 @@ class PathClass(object): def __hash__(self): return hash(self.Path) - def _GetFileKey(self): - if self._Key == None: - self._Key = self.Path.upper() # + self.ToolChainFamily + self.TagName + self.ToolCode + self.Target - return self._Key + @cached_property + def Key(self): + return self.Path.upper() - def _GetTimeStamp(self): + @property + def TimeStamp(self): return os.stat(self.Path)[8] def Validate(self, Type='', CaseSensitive=True): + def RealPath2(File, Dir='', OverrideDir=''): + NewFile = None + 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))] + if not NewFile: + NewFile = os.path.normpath(os.path.join(Dir, File)) + if not os.path.exists(NewFile): + return None, None + 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 + if GlobalData.gCaseInsensitive: CaseSensitive = False if Type and Type.lower() != self.Type: @@ -2079,10 +1524,7 @@ class PathClass(object): self.Path = os.path.join(RealRoot, RealFile) return ErrorCode, ErrorInfo - Key = property(_GetFileKey) - TimeStamp = property(_GetTimeStamp) - -## Parse PE image to get the required PE informaion. +## Parse PE image to get the required PE information. # class PeImageClass(): ## Constructor @@ -2117,7 +1559,7 @@ class PeImageClass(): ByteArray = array.array('B') ByteArray.fromfile(PeObject, 4) # PE signature should be 'PE\0\0' - if ByteArray.tostring() != 'PE\0\0': + if ByteArray.tostring() != b'PE\0\0': self.ErrorInfo = self.FileName + ' has no valid PE signature PE00' return @@ -2155,7 +1597,7 @@ class PeImageClass(): def _ByteListToStr(self, ByteList): String = '' for index in range(len(ByteList)): - if ByteList[index] == 0: + if ByteList[index] == 0: break String += chr(ByteList[index]) return String @@ -2167,65 +1609,65 @@ class PeImageClass(): return Value class DefaultStore(): - def __init__(self,DefaultStores ): + def __init__(self, DefaultStores ): self.DefaultStores = DefaultStores - def DefaultStoreID(self,DefaultStoreName): - for key,value in self.DefaultStores.items(): + def DefaultStoreID(self, DefaultStoreName): + for key, value in self.DefaultStores.items(): if value == DefaultStoreName: return key return None def GetDefaultDefault(self): if not self.DefaultStores or "0" in self.DefaultStores: - return "0",TAB_DEFAULT_STORES_DEFAULT + return "0", TAB_DEFAULT_STORES_DEFAULT else: - minvalue = min([int(value_str) for value_str in self.DefaultStores.keys()]) + minvalue = min(int(value_str) for value_str in self.DefaultStores) return (str(minvalue), self.DefaultStores[str(minvalue)]) - def GetMin(self,DefaultSIdList): + def GetMin(self, DefaultSIdList): if not DefaultSIdList: - return "STANDARD" + return TAB_DEFAULT_STORES_DEFAULT storeidset = {storeid for storeid, storename in self.DefaultStores.values() if storename in DefaultSIdList} if not storeidset: return "" minid = min(storeidset ) - for sid,name in self.DefaultStores.values(): + for sid, name in self.DefaultStores.values(): if sid == minid: return name + class SkuClass(): - DEFAULT = 0 SINGLE = 1 MULTIPLE =2 - + def __init__(self,SkuIdentifier='', SkuIds=None): if SkuIds is None: SkuIds = {} for SkuName in SkuIds: SkuId = SkuIds[SkuName][0] - skuid_num = int(SkuId,16) if SkuId.upper().startswith("0X") else int(SkuId) + skuid_num = int(SkuId, 16) if SkuId.upper().startswith("0X") else int(SkuId) if skuid_num > 0xFFFFFFFFFFFFFFFF: EdkLogger.error("build", PARAMETER_INVALID, ExtraData = "SKU-ID [%s] value %s exceeds the max value of UINT64" % (SkuName, SkuId)) - - self.AvailableSkuIds = sdict() + + self.AvailableSkuIds = OrderedDict() self.SkuIdSet = [] self.SkuIdNumberSet = [] self.SkuData = SkuIds - self.__SkuInherit = {} - self.__SkuIdentifier = SkuIdentifier + self._SkuInherit = {} + self._SkuIdentifier = SkuIdentifier if SkuIdentifier == '' or SkuIdentifier is None: self.SkuIdSet = ['DEFAULT'] self.SkuIdNumberSet = ['0U'] elif SkuIdentifier == 'ALL': - self.SkuIdSet = SkuIds.keys() + self.SkuIdSet = list(SkuIds.keys()) self.SkuIdNumberSet = [num[0].strip() + 'U' for num in SkuIds.values()] else: - r = SkuIdentifier.split('|') + r = SkuIdentifier.split('|') self.SkuIdSet=[(r[k].strip()).upper() for k in range(len(r))] k = None - try: + try: self.SkuIdNumberSet = [SkuIds[k][0].strip() + 'U' for k in self.SkuIdSet] except Exception: EdkLogger.error("build", PARAMETER_INVALID, @@ -2238,28 +1680,32 @@ class SkuClass(): EdkLogger.error("build", PARAMETER_INVALID, ExtraData="SKU-ID [%s] is not supported by the platform. [Valid SKU-ID: %s]" % (each, " | ".join(SkuIds.keys()))) - if self.SkuUsageType != self.SINGLE: + if self.SkuUsageType != SkuClass.SINGLE: self.AvailableSkuIds.update({'DEFAULT':0, 'COMMON':0}) if self.SkuIdSet: GlobalData.gSkuids = (self.SkuIdSet) if 'COMMON' in GlobalData.gSkuids: GlobalData.gSkuids.remove('COMMON') + if self.SkuUsageType == self.SINGLE: + if len(GlobalData.gSkuids) != 1: + if 'DEFAULT' in GlobalData.gSkuids: + GlobalData.gSkuids.remove('DEFAULT') if GlobalData.gSkuids: GlobalData.gSkuids.sort() def GetNextSkuId(self, skuname): - if not self.__SkuInherit: - self.__SkuInherit = {} + if not self._SkuInherit: + self._SkuInherit = {} for item in self.SkuData.values(): - self.__SkuInherit[item[1]]=item[2] if item[2] else "DEFAULT" - return self.__SkuInherit.get(skuname,"DEFAULT") + self._SkuInherit[item[1]]=item[2] if item[2] else "DEFAULT" + return self._SkuInherit.get(skuname, "DEFAULT") - def GetSkuChain(self,sku): + def GetSkuChain(self, sku): if sku == "DEFAULT": return ["DEFAULT"] skulist = [sku] nextsku = sku - while 1: + while True: nextsku = self.GetNextSkuId(nextsku) skulist.append(nextsku) if nextsku == "DEFAULT": @@ -2270,9 +1716,9 @@ class SkuClass(): skuorderset = [] for skuname in self.SkuIdSet: skuorderset.append(self.GetSkuChain(skuname)) - + skuorder = [] - for index in range(max([len(item) for item in skuorderset])): + for index in range(max(len(item) for item in skuorderset)): for subset in skuorderset: if index > len(subset)-1: continue @@ -2282,100 +1728,46 @@ class SkuClass(): return skuorder - def __SkuUsageType(self): - - if self.__SkuIdentifier.upper() == "ALL": + @property + def SkuUsageType(self): + if self._SkuIdentifier.upper() == "ALL": return SkuClass.MULTIPLE if len(self.SkuIdSet) == 1: if self.SkuIdSet[0] == 'DEFAULT': return SkuClass.DEFAULT - else: - return SkuClass.SINGLE - elif len(self.SkuIdSet) == 2: - if 'DEFAULT' in self.SkuIdSet: - return SkuClass.SINGLE - else: - return SkuClass.MULTIPLE - else: - return SkuClass.MULTIPLE - def DumpSkuIdArrary(self): + return SkuClass.SINGLE + if len(self.SkuIdSet) == 2 and 'DEFAULT' in self.SkuIdSet: + return SkuClass.SINGLE + return SkuClass.MULTIPLE - ArrayStrList = [] + def DumpSkuIdArrary(self): if self.SkuUsageType == SkuClass.SINGLE: - ArrayStr = "{0x0}" - else: - for skuname in self.AvailableSkuIds: - if skuname == "COMMON": - continue - while skuname != "DEFAULT": - ArrayStrList.append(hex(int(self.AvailableSkuIds[skuname]))) - skuname = self.GetNextSkuId(skuname) - ArrayStrList.append("0x0") - ArrayStr = "{" + ",".join(ArrayStrList) + "}" - return ArrayStr - def __GetAvailableSkuIds(self): + return "{0x0}" + ArrayStrList = [] + for skuname in self.AvailableSkuIds: + if skuname == "COMMON": + continue + while skuname != "DEFAULT": + ArrayStrList.append(hex(int(self.AvailableSkuIds[skuname]))) + skuname = self.GetNextSkuId(skuname) + ArrayStrList.append("0x0") + return "{{{myList}}}".format(myList=",".join(ArrayStrList)) + + @property + def AvailableSkuIdSet(self): return self.AvailableSkuIds - - def __GetSystemSkuID(self): - if self.__SkuUsageType() == SkuClass.SINGLE: + + @property + def SystemSkuId(self): + if self.SkuUsageType == SkuClass.SINGLE: if len(self.SkuIdSet) == 1: return self.SkuIdSet[0] else: return self.SkuIdSet[0] if self.SkuIdSet[0] != 'DEFAULT' else self.SkuIdSet[1] else: return 'DEFAULT' - def __GetAvailableSkuIdNumber(self): - return self.SkuIdNumberSet - SystemSkuId = property(__GetSystemSkuID) - AvailableSkuIdSet = property(__GetAvailableSkuIds) - SkuUsageType = property(__SkuUsageType) - AvailableSkuIdNumSet = property(__GetAvailableSkuIdNumber) - -# -# Pack a registry format GUID -# -def PackRegistryFormatGuid(Guid): - Guid = Guid.split('-') - return pack('=LHHBBBBBBBB', - int(Guid[0], 16), - int(Guid[1], 16), - int(Guid[2], 16), - int(Guid[3][-4:-2], 16), - int(Guid[3][-2:], 16), - int(Guid[4][-12:-10], 16), - int(Guid[4][-10:-8], 16), - int(Guid[4][-8:-6], 16), - int(Guid[4][-6:-4], 16), - int(Guid[4][-4:-2], 16), - int(Guid[4][-2:], 16) - ) -def BuildOptionPcdValueFormat(TokenSpaceGuidCName, TokenCName, PcdDatumType, Value): - if PcdDatumType not in [TAB_UINT8, TAB_UINT16, TAB_UINT32, TAB_UINT64,'BOOLEAN']: - if Value.startswith('L') or Value.startswith('"'): - if not Value[1]: - EdkLogger.error("build", FORMAT_INVALID, 'For Void* type PCD, when specify the Value in the command line, please use the following format: "string", L"string", H"{...}"') - Value = Value - elif Value.startswith('H'): - if not Value[1]: - EdkLogger.error("build", FORMAT_INVALID, 'For Void* type PCD, when specify the Value in the command line, please use the following format: "string", L"string", H"{...}"') - Value = Value[1:] - else: - if not Value[0]: - EdkLogger.error("build", FORMAT_INVALID, 'For Void* type PCD, when specify the Value in the command line, please use the following format: "string", L"string", H"{...}"') - Value = '"' + Value + '"' - - IsValid, Cause = CheckPcdDatum(PcdDatumType, Value) - if not IsValid: - EdkLogger.error("build", FORMAT_INVALID, Cause, ExtraData="%s.%s" % (TokenSpaceGuidCName, TokenCName)) - if PcdDatumType == 'BOOLEAN': - Value = Value.upper() - if Value == 'TRUE' or Value == '1': - Value = '1' - elif Value == 'FALSE' or Value == '0': - Value = '0' - return Value ## Get the integer value from string like "14U" or integer like 2 # # @param Input The object that may be either a integer value or a string @@ -2383,7 +1775,7 @@ def BuildOptionPcdValueFormat(TokenSpaceGuidCName, TokenCName, PcdDatumType, Val # @retval Value The integer value that the input represents # def GetIntegerValue(Input): - if type(Input) in (int, long): + if not isinstance(Input, str): return Input String = Input if String.endswith("U"): @@ -2400,11 +1792,62 @@ def GetIntegerValue(Input): else: return int(String) -## # -# This acts like the main() function for the script, unless it is 'import'ed into another -# script. +# Pack a GUID (registry format) list into a buffer and return it # -if __name__ == '__main__': - pass +def PackGUID(Guid): + return pack(PACK_PATTERN_GUID, + int(Guid[0], 16), + int(Guid[1], 16), + int(Guid[2], 16), + int(Guid[3][-4:-2], 16), + int(Guid[3][-2:], 16), + int(Guid[4][-12:-10], 16), + int(Guid[4][-10:-8], 16), + int(Guid[4][-8:-6], 16), + int(Guid[4][-6:-4], 16), + int(Guid[4][-4:-2], 16), + int(Guid[4][-2:], 16) + ) + +# +# Pack a GUID (byte) list into a buffer and return it +# +def PackByteFormatGUID(Guid): + return pack(PACK_PATTERN_GUID, + Guid[0], + Guid[1], + Guid[2], + Guid[3], + Guid[4], + Guid[5], + Guid[6], + Guid[7], + Guid[8], + Guid[9], + Guid[10], + ) +## DeepCopy dict/OrderedDict recusively +# +# @param ori_dict a nested dict or ordereddict +# +# @retval new dict or orderdict +# +def CopyDict(ori_dict): + dict_type = ori_dict.__class__ + if dict_type not in (dict,OrderedDict): + return ori_dict + new_dict = dict_type() + for key in ori_dict: + if isinstance(ori_dict[key],(dict,OrderedDict)): + new_dict[key] = CopyDict(ori_dict[key]) + else: + new_dict[key] = ori_dict[key] + return new_dict + +# +# Remove the c/c++ comments: // and /* */ +# +def RemoveCComments(ctext): + return re.sub('//.*?\n|/\*.*?\*/', '\n', ctext, flags=re.S)