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)