diff options
author | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-04-11 08:17:27 +0000 |
---|---|---|
committer | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-04-11 08:17:27 +0000 |
commit | f215e02bf85f68d3a6106c2a1f4f7f063f819064 (patch) | |
tree | 6bb5b92c046312c4e95ac2620b10ddf482d3fa8b /src/VBox/Devices/EFI/Firmware/BaseTools/Source/Python/UPT/Library/ExpressionValidate.py | |
parent | Initial commit. (diff) | |
download | virtualbox-f215e02bf85f68d3a6106c2a1f4f7f063f819064.tar.xz virtualbox-f215e02bf85f68d3a6106c2a1f4f7f063f819064.zip |
Adding upstream version 7.0.14-dfsg.upstream/7.0.14-dfsg
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to 'src/VBox/Devices/EFI/Firmware/BaseTools/Source/Python/UPT/Library/ExpressionValidate.py')
-rwxr-xr-x | src/VBox/Devices/EFI/Firmware/BaseTools/Source/Python/UPT/Library/ExpressionValidate.py | 567 |
1 files changed, 567 insertions, 0 deletions
diff --git a/src/VBox/Devices/EFI/Firmware/BaseTools/Source/Python/UPT/Library/ExpressionValidate.py b/src/VBox/Devices/EFI/Firmware/BaseTools/Source/Python/UPT/Library/ExpressionValidate.py new file mode 100755 index 00000000..ae5f835b --- /dev/null +++ b/src/VBox/Devices/EFI/Firmware/BaseTools/Source/Python/UPT/Library/ExpressionValidate.py @@ -0,0 +1,567 @@ +## @file +# This file is used to check PCD logical expression +# +# Copyright (c) 2011 - 2018, Intel Corporation. All rights reserved.<BR> +# +# SPDX-License-Identifier: BSD-2-Clause-Patent + +''' +ExpressionValidate +''' +from __future__ import print_function + +## +# Import Modules +# +import re +from Logger import StringTable as ST + +## IsValidBareCString +# +# Check if String is comprised by whitespace(0x20), !(0x21), 0x23 - 0x7E +# or '\n', '\t', '\f', '\r', '\b', '\0', '\\' +# +# @param String: string to be checked +# +def IsValidBareCString(String): + EscapeList = ['n', 't', 'f', 'r', 'b', '0', '\\', '"'] + PreChar = '' + LastChar = '' + for Char in String: + LastChar = Char + if PreChar == '\\': + if Char not in EscapeList: + return False + if Char == '\\': + PreChar = '' + continue + else: + IntChar = ord(Char) + if IntChar != 0x20 and IntChar != 0x09 and IntChar != 0x21 \ + and (IntChar < 0x23 or IntChar > 0x7e): + return False + PreChar = Char + + # Last char cannot be \ if PreChar is not \ + if LastChar == '\\' and PreChar == LastChar: + return False + return True + +def _ValidateToken(Token): + Token = Token.strip() + Index = Token.find("\"") + if Index != -1: + return IsValidBareCString(Token[Index+1:-1]) + return True + +## _ExprError +# +# @param Exception: Exception +# +class _ExprError(Exception): + def __init__(self, Error = ''): + Exception.__init__(self) + self.Error = Error + +## _ExprBase +# +class _ExprBase: + HEX_PATTERN = '[\t\s]*0[xX][a-fA-F0-9]+' + INT_PATTERN = '[\t\s]*[0-9]+' + MACRO_PATTERN = '[\t\s]*\$\(([A-Z][_A-Z0-9]*)\)' + PCD_PATTERN = \ + '[\t\s]*[_a-zA-Z][a-zA-Z0-9_]*[\t\s]*\.[\t\s]*[_a-zA-Z][a-zA-Z0-9_]*' + QUOTED_PATTERN = '[\t\s]*L?"[^"]*"' + BOOL_PATTERN = '[\t\s]*(true|True|TRUE|false|False|FALSE)' + def __init__(self, Token): + self.Token = Token + self.Index = 0 + self.Len = len(Token) + + ## SkipWhitespace + # + def SkipWhitespace(self): + for Char in self.Token[self.Index:]: + if Char not in ' \t': + break + self.Index += 1 + + ## IsCurrentOp + # + # @param OpList: option list + # + def IsCurrentOp(self, OpList): + self.SkipWhitespace() + LetterOp = ["EQ", "NE", "GE", "LE", "GT", "LT", "NOT", "and", "AND", + "or", "OR", "XOR"] + OpMap = { + '|' : '|', + '&' : '&', + '!' : '=', + '>' : '=', + '<' : '=' + } + + for Operator in OpList: + if not self.Token[self.Index:].startswith(Operator): + continue + + self.Index += len(Operator) + Char = self.Token[self.Index : self.Index + 1] + + if (Operator in LetterOp and (Char == '_' or Char.isalnum())) \ + or (Operator in OpMap and OpMap[Operator] == Char): + self.Index -= len(Operator) + break + + return True + + return False + +## _LogicalExpressionParser +# +# @param _ExprBase: _ExprBase object +# +class _LogicalExpressionParser(_ExprBase): + # + # STRINGITEM can only be logical field according to spec + # + STRINGITEM = -1 + + # + # Evaluate to True or False + # + LOGICAL = 0 + REALLOGICAL = 2 + + # + # Just arithmetic expression + # + ARITH = 1 + + def __init__(self, Token): + _ExprBase.__init__(self, Token) + self.Parens = 0 + + def _CheckToken(self, MatchList): + for Match in MatchList: + if Match and Match.start() == 0: + if not _ValidateToken( + self.Token[self.Index:self.Index+Match.end()] + ): + return False + + self.Index += Match.end() + if self.Token[self.Index - 1] == '"': + return True + if self.Token[self.Index:self.Index+1] == '_' or \ + self.Token[self.Index:self.Index+1].isalnum(): + self.Index -= Match.end() + return False + + Token = self.Token[self.Index - Match.end():self.Index] + if Token.strip() in ["EQ", "NE", "GE", "LE", "GT", "LT", + "NOT", "and", "AND", "or", "OR", "XOR"]: + self.Index -= Match.end() + return False + + return True + + return False + + def IsAtomicNumVal(self): + # + # Hex number + # + Match1 = re.compile(self.HEX_PATTERN).match(self.Token[self.Index:]) + + # + # Number + # + Match2 = re.compile(self.INT_PATTERN).match(self.Token[self.Index:]) + + # + # Macro + # + Match3 = re.compile(self.MACRO_PATTERN).match(self.Token[self.Index:]) + + # + # PcdName + # + Match4 = re.compile(self.PCD_PATTERN).match(self.Token[self.Index:]) + + return self._CheckToken([Match1, Match2, Match3, Match4]) + + + def IsAtomicItem(self): + # + # Macro + # + Match1 = re.compile(self.MACRO_PATTERN).match(self.Token[self.Index:]) + + # + # PcdName + # + Match2 = re.compile(self.PCD_PATTERN).match(self.Token[self.Index:]) + + # + # Quoted string + # + Match3 = re.compile(self.QUOTED_PATTERN).\ + match(self.Token[self.Index:].replace('\\\\', '//').\ + replace('\\\"', '\\\'')) + + return self._CheckToken([Match1, Match2, Match3]) + + ## A || B + # + def LogicalExpression(self): + Ret = self.SpecNot() + while self.IsCurrentOp(['||', 'OR', 'or', '&&', 'AND', 'and', 'XOR', 'xor', '^']): + if self.Token[self.Index-1] == '|' and self.Parens <= 0: + raise _ExprError(ST.ERR_EXPR_OR % self.Token) + if Ret not in [self.ARITH, self.LOGICAL, self.REALLOGICAL, self.STRINGITEM]: + raise _ExprError(ST.ERR_EXPR_LOGICAL % self.Token) + Ret = self.SpecNot() + if Ret not in [self.ARITH, self.LOGICAL, self.REALLOGICAL, self.STRINGITEM]: + raise _ExprError(ST.ERR_EXPR_LOGICAL % self.Token) + Ret = self.REALLOGICAL + return Ret + + def SpecNot(self): + if self.IsCurrentOp(["NOT", "!", "not"]): + return self.SpecNot() + return self.Rel() + + ## A < B, A > B, A <= B, A >= B + # + def Rel(self): + Ret = self.Expr() + if self.IsCurrentOp(["<=", ">=", ">", "<", "GT", "LT", "GE", "LE", + "==", "EQ", "!=", "NE"]): + if Ret == self.STRINGITEM: + raise _ExprError(ST.ERR_EXPR_LOGICAL % self.Token) + Ret = self.Expr() + if Ret == self.REALLOGICAL: + raise _ExprError(ST.ERR_EXPR_LOGICAL % self.Token) + Ret = self.REALLOGICAL + return Ret + + ## A + B, A - B + # + def Expr(self): + Ret = self.Factor() + while self.IsCurrentOp(["+", "-", "&", "|", "^", "XOR", "xor"]): + if self.Token[self.Index-1] == '|' and self.Parens <= 0: + raise _ExprError(ST.ERR_EXPR_OR) + if Ret == self.STRINGITEM or Ret == self.REALLOGICAL: + raise _ExprError(ST.ERR_EXPR_LOGICAL % self.Token) + Ret = self.Factor() + if Ret == self.STRINGITEM or Ret == self.REALLOGICAL: + raise _ExprError(ST.ERR_EXPR_LOGICAL % self.Token) + Ret = self.ARITH + return Ret + + ## Factor + # + def Factor(self): + if self.IsCurrentOp(["("]): + self.Parens += 1 + Ret = self.LogicalExpression() + if not self.IsCurrentOp([")"]): + raise _ExprError(ST.ERR_EXPR_RIGHT_PAREN % \ + (self.Token, self.Token[self.Index:])) + self.Parens -= 1 + return Ret + + if self.IsAtomicItem(): + if self.Token[self.Index - 1] == '"': + return self.STRINGITEM + return self.LOGICAL + elif self.IsAtomicNumVal(): + return self.ARITH + else: + raise _ExprError(ST.ERR_EXPR_FACTOR % \ + (self.Token[self.Index:], self.Token)) + + ## IsValidLogicalExpression + # + def IsValidLogicalExpression(self): + if self.Len == 0: + return False, ST.ERR_EXPRESS_EMPTY + try: + if self.LogicalExpression() not in [self.ARITH, self.LOGICAL, self.REALLOGICAL, self.STRINGITEM]: + return False, ST.ERR_EXPR_LOGICAL % self.Token + except _ExprError as XExcept: + return False, XExcept.Error + self.SkipWhitespace() + if self.Index != self.Len: + return False, (ST.ERR_EXPR_BOOLEAN % \ + (self.Token[self.Index:], self.Token)) + return True, '' + +## _ValidRangeExpressionParser +# +class _ValidRangeExpressionParser(_ExprBase): + INT_RANGE_PATTERN = '[\t\s]*[0-9]+[\t\s]*-[\t\s]*[0-9]+' + HEX_RANGE_PATTERN = \ + '[\t\s]*0[xX][a-fA-F0-9]+[\t\s]*-[\t\s]*0[xX][a-fA-F0-9]+' + def __init__(self, Token): + _ExprBase.__init__(self, Token) + self.Parens = 0 + self.HEX = 1 + self.INT = 2 + self.IsParenHappen = False + self.IsLogicalOpHappen = False + + ## IsValidRangeExpression + # + def IsValidRangeExpression(self): + if self.Len == 0: + return False, ST.ERR_EXPR_RANGE_EMPTY + try: + if self.RangeExpression() not in [self.HEX, self.INT]: + return False, ST.ERR_EXPR_RANGE % self.Token + except _ExprError as XExcept: + return False, XExcept.Error + + self.SkipWhitespace() + if self.Index != self.Len: + return False, (ST.ERR_EXPR_RANGE % self.Token) + return True, '' + + ## RangeExpression + # + def RangeExpression(self): + Ret = self.Unary() + while self.IsCurrentOp(['OR', 'AND', 'and', 'or']): + self.IsLogicalOpHappen = True + if not self.IsParenHappen: + raise _ExprError(ST.ERR_PAREN_NOT_USED % self.Token) + self.IsParenHappen = False + Ret = self.Unary() + + if self.IsCurrentOp(['XOR']): + Ret = self.Unary() + + return Ret + + ## Unary + # + def Unary(self): + if self.IsCurrentOp(["NOT"]): + return self.Unary() + + return self.ValidRange() + + ## ValidRange + # + def ValidRange(self): + Ret = -1 + if self.IsCurrentOp(["("]): + self.IsLogicalOpHappen = False + self.IsParenHappen = True + self.Parens += 1 + if self.Parens > 1: + raise _ExprError(ST.ERR_EXPR_RANGE_DOUBLE_PAREN_NESTED % self.Token) + Ret = self.RangeExpression() + if not self.IsCurrentOp([")"]): + raise _ExprError(ST.ERR_EXPR_RIGHT_PAREN % self.Token) + self.Parens -= 1 + return Ret + + if self.IsLogicalOpHappen: + raise _ExprError(ST.ERR_PAREN_NOT_USED % self.Token) + + if self.IsCurrentOp(["LT", "GT", "LE", "GE", "EQ", "XOR"]): + IntMatch = \ + re.compile(self.INT_PATTERN).match(self.Token[self.Index:]) + HexMatch = \ + re.compile(self.HEX_PATTERN).match(self.Token[self.Index:]) + if HexMatch and HexMatch.start() == 0: + self.Index += HexMatch.end() + Ret = self.HEX + elif IntMatch and IntMatch.start() == 0: + self.Index += IntMatch.end() + Ret = self.INT + else: + raise _ExprError(ST.ERR_EXPR_RANGE_FACTOR % (self.Token[self.Index:], self.Token)) + else: + IntRangeMatch = re.compile( + self.INT_RANGE_PATTERN).match(self.Token[self.Index:] + ) + HexRangeMatch = re.compile( + self.HEX_RANGE_PATTERN).match(self.Token[self.Index:] + ) + if HexRangeMatch and HexRangeMatch.start() == 0: + self.Index += HexRangeMatch.end() + Ret = self.HEX + elif IntRangeMatch and IntRangeMatch.start() == 0: + self.Index += IntRangeMatch.end() + Ret = self.INT + else: + raise _ExprError(ST.ERR_EXPR_RANGE % self.Token) + + return Ret + +## _ValidListExpressionParser +# +class _ValidListExpressionParser(_ExprBase): + VALID_LIST_PATTERN = '(0[xX][0-9a-fA-F]+|[0-9]+)([\t\s]*,[\t\s]*(0[xX][0-9a-fA-F]+|[0-9]+))*' + def __init__(self, Token): + _ExprBase.__init__(self, Token) + self.NUM = 1 + + def IsValidListExpression(self): + if self.Len == 0: + return False, ST.ERR_EXPR_LIST_EMPTY + try: + if self.ListExpression() not in [self.NUM]: + return False, ST.ERR_EXPR_LIST % self.Token + except _ExprError as XExcept: + return False, XExcept.Error + + self.SkipWhitespace() + if self.Index != self.Len: + return False, (ST.ERR_EXPR_LIST % self.Token) + + return True, '' + + def ListExpression(self): + Ret = -1 + self.SkipWhitespace() + ListMatch = re.compile(self.VALID_LIST_PATTERN).match(self.Token[self.Index:]) + if ListMatch and ListMatch.start() == 0: + self.Index += ListMatch.end() + Ret = self.NUM + else: + raise _ExprError(ST.ERR_EXPR_LIST % self.Token) + + return Ret + +## _StringTestParser +# +class _StringTestParser(_ExprBase): + def __init__(self, Token): + _ExprBase.__init__(self, Token) + + ## IsValidStringTest + # + def IsValidStringTest(self): + if self.Len == 0: + return False, ST.ERR_EXPR_EMPTY + try: + self.StringTest() + except _ExprError as XExcept: + return False, XExcept.Error + return True, '' + + ## StringItem + # + def StringItem(self): + Match1 = re.compile(self.QUOTED_PATTERN)\ + .match(self.Token[self.Index:].replace('\\\\', '//')\ + .replace('\\\"', '\\\'')) + Match2 = re.compile(self.MACRO_PATTERN).match(self.Token[self.Index:]) + Match3 = re.compile(self.PCD_PATTERN).match(self.Token[self.Index:]) + MatchList = [Match1, Match2, Match3] + for Match in MatchList: + if Match and Match.start() == 0: + if not _ValidateToken( + self.Token[self.Index:self.Index+Match.end()] + ): + raise _ExprError(ST.ERR_EXPR_STRING_ITEM % \ + (self.Token, self.Token[self.Index:])) + self.Index += Match.end() + Token = self.Token[self.Index - Match.end():self.Index] + if Token.strip() in ["EQ", "NE"]: + raise _ExprError(ST.ERR_EXPR_STRING_ITEM % \ + (self.Token, self.Token[self.Index:])) + return + else: + raise _ExprError(ST.ERR_EXPR_STRING_ITEM % \ + (self.Token, self.Token[self.Index:])) + + ## StringTest + # + def StringTest(self): + self.StringItem() + if not self.IsCurrentOp(["==", "EQ", "!=", "NE"]): + raise _ExprError(ST.ERR_EXPR_EQUALITY % \ + (self.Token[self.Index:], self.Token)) + self.StringItem() + if self.Index != self.Len: + raise _ExprError(ST.ERR_EXPR_BOOLEAN % \ + (self.Token[self.Index:], self.Token)) + +## +# Check syntax of string test +# +# @param Token: string test token +# +def IsValidStringTest(Token, Flag=False): + # + # Not do the check right now, keep the implementation for future enhancement. + # + if not Flag: + return True, "" + return _StringTestParser(Token).IsValidStringTest() + + +## +# Check syntax of logical expression +# +# @param Token: expression token +# +def IsValidLogicalExpr(Token, Flag=False): + # + # Not do the check right now, keep the implementation for future enhancement. + # + if not Flag: + return True, "" + return _LogicalExpressionParser(Token).IsValidLogicalExpression() + +## +# Check syntax of range expression +# +# @param Token: range expression token +# +def IsValidRangeExpr(Token): + return _ValidRangeExpressionParser(Token).IsValidRangeExpression() + +## +# Check syntax of value list expression token +# +# @param Token: value list expression token +# +def IsValidListExpr(Token): + return _ValidListExpressionParser(Token).IsValidListExpression() + +## +# Check whether the feature flag expression is valid or not +# +# @param Token: feature flag expression +# +def IsValidFeatureFlagExp(Token, Flag=False): + # + # Not do the check right now, keep the implementation for future enhancement. + # + if not Flag: + return True, "", Token + else: + if Token in ['TRUE', 'FALSE', 'true', 'false', 'True', 'False', + '0x1', '0x01', '0x0', '0x00']: + return True, "" + Valid, Cause = IsValidStringTest(Token, Flag) + if not Valid: + Valid, Cause = IsValidLogicalExpr(Token, Flag) + if not Valid: + return False, Cause + return True, "" + +if __name__ == '__main__': +# print IsValidRangeExpr('LT 9') + print(_LogicalExpressionParser('gCrownBayTokenSpaceGuid.PcdPciDevice1BridgeAddressLE0').IsValidLogicalExpression()) + + + |