X-Git-Url: https://git.proxmox.com/?p=mirror_edk2.git;a=blobdiff_plain;f=BaseTools%2FSource%2FPython%2FCommon%2FMisc.py;h=d082c58befda5b46aa3f40113c96f1566ded60fd;hp=fd948c727a4f9b7a09360529f38533d3243f8654;hb=66b845ae06f1e48c693158ee0b8b4f610d5ada4a;hpb=26067e30c48da27df41252444fce66a6418a613b diff --git a/BaseTools/Source/Python/Common/Misc.py b/BaseTools/Source/Python/Common/Misc.py index fd948c727a..d082c58bef 100644 --- a/BaseTools/Source/Python/Common/Misc.py +++ b/BaseTools/Source/Python/Common/Misc.py @@ -1,44 +1,43 @@ ## @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 # from __future__ import absolute_import -import Common.LongFilePathOs as os + import sys import string 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) @@ -49,8 +48,7 @@ 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) -## Dictionary used to store file time stamp for quick re-access -gFileTimeStampCache = {} # {file path : file time stamp} +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]} @@ -283,6 +281,7 @@ def ProcessDuplicatedInf(Path, BaseName, Workspace): # RtPath.Path = TempFullPath RtPath.BaseName = BaseName + RtPath.OriginalPath = Path # # If file exists, compare contents # @@ -360,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: @@ -452,15 +453,22 @@ def RemoveDirectory(Directory, Recursively=False): # @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): @@ -471,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 as 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 is not 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 as e: - EdkLogger.verbose("Failed to load [%s]\n\t%s" % (File, str(e))) - Data = None - finally: - if Fd is not None: - Fd.close() - return Data - ## Retrieve and cache the real path name in file system # # @param Root The root directory of path relative to @@ -606,32 +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 - ## Get GUID value from given packages # # @param CName The CName of the GUID @@ -643,50 +592,13 @@ def RealPath2(File, Dir='', OverrideDir=''): # 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 = [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 = [x for x in P.Protocols if x not in P._PrivateProtocols] - 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 = [x for x in P.Ppis if x not in P._PrivatePpis] - if CName in PpiKeys: - return P.Ppis[CName] return None ## A string template class @@ -782,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) @@ -792,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 # @@ -840,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 # @@ -865,10 +780,10 @@ 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 @@ -878,9 +793,9 @@ class Progressor: 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 is not None: @@ -891,9 +806,9 @@ class Progressor: 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 @@ -926,165 +841,6 @@ class Progressor: 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 is not 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 # @@ -1092,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_ @@ -1224,24 +980,9 @@ class tdict: keys |= self.data[Key].GetKeys(KeyIndex - 1) return keys -def IsFieldValueAnArray (Value): - Value = Value.strip() - if Value.startswith(TAB_GUID) and Value.endswith(')'): - return True - if Value.startswith('L"') and Value.endswith('"') and len(list(Value[2:-1])) > 1: - return True - if Value[0] == '"' and Value[-1] == '"' and len(list(Value[1:-1])) > 1: - return True - if Value[0] == '{' and Value[-1] == '}': - return True - if Value.startswith("L'") and Value.endswith("'") and len(list(Value[2:-1])) > 1: - return True - if Value[0] == "'" and Value[-1] == "'" and len(list(Value[1:-1])) > 1: - return True - return False - def AnalyzePcdExpression(Setting): - Setting = Setting.strip() + 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 '-' @@ -1274,32 +1015,37 @@ 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): - 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)) - Size = len(out.split()) - out = ','.join(out.split()) - return '{' + out + '}', Size - def ParseFieldValue (Value): + 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 + return Value, (Value.bit_length() + 7) // 8 if not isinstance(Value, type('')): raise BadExpression('Type %s is %s' %(Value, type(Value))) Value = Value.strip() @@ -1327,13 +1073,16 @@ def ParseFieldValue (Value): Value = Value.split('(', 1)[1][:-1].strip() if Value[0] == '{' and Value[-1] == '}': TmpValue = GuidStructureStringToGuidString(Value) - if len(TmpValue) == 0: + 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() + "'" + 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) @@ -1414,15 +1163,18 @@ def ParseFieldValue (Value): 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': @@ -1432,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) 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 @@ -1442,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. # @@ -1458,42 +1210,20 @@ 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] - 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: @@ -1501,7 +1231,12 @@ def AnalyzeDscPcd(Setting, PcdType, DataType=''): 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 = '' @@ -1525,6 +1260,7 @@ def AnalyzeDscPcd(Setting, PcdType, DataType=''): 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: @@ -1535,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 @@ -1598,8 +1333,14 @@ def CheckPcdDatum(Type, Value): 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) @@ -1608,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=''): @@ -1733,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 # @@ -1753,23 +1425,17 @@ class PathClass(object): # @retval True The two PathClass are the same # def __eq__(self, Other): - if isinstance(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 isinstance(Other, type(self)): - OtherKey = Other.Path - else: - OtherKey = str(Other) + OtherKey = str(Other) SelfKey = self.Path if SelfKey == OtherKey: @@ -1788,15 +1454,41 @@ class PathClass(object): def __hash__(self): return hash(self.Path) - def _GetFileKey(self): - if self._Key is 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: @@ -1832,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 @@ -1870,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 @@ -1944,8 +1633,8 @@ class DefaultStore(): for sid, name in self.DefaultStores.values(): if sid == minid: return name -class SkuClass(): +class SkuClass(): DEFAULT = 0 SINGLE = 1 MULTIPLE =2 @@ -1962,17 +1651,17 @@ class SkuClass(): 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('|') @@ -1991,7 +1680,7 @@ 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) @@ -2005,11 +1694,11 @@ class SkuClass(): 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): if sku == "DEFAULT": @@ -2039,61 +1728,45 @@ 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): - return PackGUID(Guid.split('-')) ## Get the integer value from string like "14U" or integer like 2 # @@ -2102,7 +1775,7 @@ def PackRegistryFormatGuid(Guid): # @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"): @@ -2155,11 +1828,26 @@ def PackByteFormatGUID(Guid): Guid[10], ) -## +## DeepCopy dict/OrderedDict recusively +# +# @param ori_dict a nested dict or ordereddict # -# This acts like the main() function for the script, unless it is 'import'ed into another -# script. +# @retval new dict or orderdict # -if __name__ == '__main__': - pass +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)