From f215e02bf85f68d3a6106c2a1f4f7f063f819064 Mon Sep 17 00:00:00 2001 From: Daniel Baumann Date: Thu, 11 Apr 2024 10:17:27 +0200 Subject: Adding upstream version 7.0.14-dfsg. Signed-off-by: Daniel Baumann --- .../Source/Python/UPT/Parser/DecParser.py | 1091 ++++++++++++++++++++ .../Source/Python/UPT/Parser/DecParserMisc.py | 364 +++++++ .../Source/Python/UPT/Parser/InfAsBuiltProcess.py | 283 +++++ .../Python/UPT/Parser/InfBinarySectionParser.py | 226 ++++ .../UPT/Parser/InfBuildOptionSectionParser.py | 212 ++++ .../Python/UPT/Parser/InfDefineSectionParser.py | 191 ++++ .../Python/UPT/Parser/InfDepexSectionParser.py | 98 ++ .../UPT/Parser/InfGuidPpiProtocolSectionParser.py | 368 +++++++ .../Python/UPT/Parser/InfLibrarySectionParser.py | 197 ++++ .../Python/UPT/Parser/InfPackageSectionParser.py | 134 +++ .../Source/Python/UPT/Parser/InfParser.py | 680 ++++++++++++ .../Source/Python/UPT/Parser/InfParserMisc.py | 216 ++++ .../Python/UPT/Parser/InfPcdSectionParser.py | 178 ++++ .../Source/Python/UPT/Parser/InfSectionParser.py | 493 +++++++++ .../Python/UPT/Parser/InfSourceSectionParser.py | 139 +++ .../BaseTools/Source/Python/UPT/Parser/__init__.py | 14 + 16 files changed, 4884 insertions(+) create mode 100755 src/VBox/Devices/EFI/Firmware/BaseTools/Source/Python/UPT/Parser/DecParser.py create mode 100755 src/VBox/Devices/EFI/Firmware/BaseTools/Source/Python/UPT/Parser/DecParserMisc.py create mode 100755 src/VBox/Devices/EFI/Firmware/BaseTools/Source/Python/UPT/Parser/InfAsBuiltProcess.py create mode 100755 src/VBox/Devices/EFI/Firmware/BaseTools/Source/Python/UPT/Parser/InfBinarySectionParser.py create mode 100755 src/VBox/Devices/EFI/Firmware/BaseTools/Source/Python/UPT/Parser/InfBuildOptionSectionParser.py create mode 100755 src/VBox/Devices/EFI/Firmware/BaseTools/Source/Python/UPT/Parser/InfDefineSectionParser.py create mode 100755 src/VBox/Devices/EFI/Firmware/BaseTools/Source/Python/UPT/Parser/InfDepexSectionParser.py create mode 100755 src/VBox/Devices/EFI/Firmware/BaseTools/Source/Python/UPT/Parser/InfGuidPpiProtocolSectionParser.py create mode 100755 src/VBox/Devices/EFI/Firmware/BaseTools/Source/Python/UPT/Parser/InfLibrarySectionParser.py create mode 100755 src/VBox/Devices/EFI/Firmware/BaseTools/Source/Python/UPT/Parser/InfPackageSectionParser.py create mode 100755 src/VBox/Devices/EFI/Firmware/BaseTools/Source/Python/UPT/Parser/InfParser.py create mode 100755 src/VBox/Devices/EFI/Firmware/BaseTools/Source/Python/UPT/Parser/InfParserMisc.py create mode 100755 src/VBox/Devices/EFI/Firmware/BaseTools/Source/Python/UPT/Parser/InfPcdSectionParser.py create mode 100755 src/VBox/Devices/EFI/Firmware/BaseTools/Source/Python/UPT/Parser/InfSectionParser.py create mode 100755 src/VBox/Devices/EFI/Firmware/BaseTools/Source/Python/UPT/Parser/InfSourceSectionParser.py create mode 100644 src/VBox/Devices/EFI/Firmware/BaseTools/Source/Python/UPT/Parser/__init__.py (limited to 'src/VBox/Devices/EFI/Firmware/BaseTools/Source/Python/UPT/Parser') diff --git a/src/VBox/Devices/EFI/Firmware/BaseTools/Source/Python/UPT/Parser/DecParser.py b/src/VBox/Devices/EFI/Firmware/BaseTools/Source/Python/UPT/Parser/DecParser.py new file mode 100755 index 00000000..f6b8545b --- /dev/null +++ b/src/VBox/Devices/EFI/Firmware/BaseTools/Source/Python/UPT/Parser/DecParser.py @@ -0,0 +1,1091 @@ +## @file +# This file is used to parse DEC file. It will consumed by DecParser +# +# Copyright (c) 2011 - 2018, Intel Corporation. All rights reserved.
+# +# SPDX-License-Identifier: BSD-2-Clause-Patent +''' +DecParser +''' +## Import modules +# +import Logger.Log as Logger +from Logger.ToolError import FILE_PARSE_FAILURE +from Logger.ToolError import FILE_OPEN_FAILURE +from Logger import StringTable as ST +from Logger.ToolError import FORMAT_INVALID + +import Library.DataType as DT +from Library.ParserValidate import IsValidToken +from Library.ParserValidate import IsValidPath +from Library.ParserValidate import IsValidCFormatGuid +from Library.ParserValidate import IsValidIdString +from Library.ParserValidate import IsValidUserId +from Library.ParserValidate import IsValidArch +from Library.ParserValidate import IsValidWord +from Library.ParserValidate import IsValidDecVersionVal +from Parser.DecParserMisc import TOOL_NAME +from Parser.DecParserMisc import CleanString +from Parser.DecParserMisc import IsValidPcdDatum +from Parser.DecParserMisc import ParserHelper +from Parser.DecParserMisc import StripRoot +from Parser.DecParserMisc import VERSION_PATTERN +from Parser.DecParserMisc import CVAR_PATTERN +from Parser.DecParserMisc import PCD_TOKEN_PATTERN +from Parser.DecParserMisc import MACRO_PATTERN +from Parser.DecParserMisc import FileContent +from Object.Parser.DecObject import _DecComments +from Object.Parser.DecObject import DecDefineObject +from Object.Parser.DecObject import DecDefineItemObject +from Object.Parser.DecObject import DecIncludeObject +from Object.Parser.DecObject import DecIncludeItemObject +from Object.Parser.DecObject import DecLibraryclassObject +from Object.Parser.DecObject import DecLibraryclassItemObject +from Object.Parser.DecObject import DecGuidObject +from Object.Parser.DecObject import DecPpiObject +from Object.Parser.DecObject import DecProtocolObject +from Object.Parser.DecObject import DecGuidItemObject +from Object.Parser.DecObject import DecUserExtensionObject +from Object.Parser.DecObject import DecUserExtensionItemObject +from Object.Parser.DecObject import DecPcdObject +from Object.Parser.DecObject import DecPcdItemObject +from Library.Misc import GuidStructureStringToGuidString +from Library.Misc import CheckGuidRegFormat +from Library.StringUtils import ReplaceMacro +from Library.StringUtils import GetSplitValueList +from Library.StringUtils import gMACRO_PATTERN +from Library.StringUtils import ConvertSpecialChar +from Library.CommentParsing import ParsePcdErrorCode + +## +# _DecBase class for parsing +# +class _DecBase: + def __init__(self, RawData): + self._RawData = RawData + self._ItemDict = {} + self._LocalMacro = {} + # + # Data parsed by 'self' are saved to this object + # + self.ItemObject = None + + def GetDataObject(self): + return self.ItemObject + + def GetLocalMacro(self): + return self._LocalMacro + + ## BlockStart + # + # Called if a new section starts + # + def BlockStart(self): + self._LocalMacro = {} + + ## _CheckReDefine + # + # @param Key: to be checked if multi-defined + # @param Scope: Format: [[SectionName, Arch], ...]. + # If scope is none, use global scope + # + def _CheckReDefine(self, Key, Scope = None): + if not Scope: + Scope = self._RawData.CurrentScope + return + + SecArch = [] + # + # Copy scope to SecArch, avoid Scope be changed outside + # + SecArch[0:1] = Scope[:] + if Key not in self._ItemDict: + self._ItemDict[Key] = [[SecArch, self._RawData.LineIndex]] + return + + for Value in self._ItemDict[Key]: + for SubValue in Scope: + # + # If current is common section + # + if SubValue[-1] == 'COMMON': + for Other in Value[0]: + # Key in common cannot be redefined in other arches + # [:-1] means stripping arch info + if Other[:-1] == SubValue[:-1]: + self._LoggerError(ST.ERR_DECPARSE_REDEFINE % (Key, Value[1])) + return + continue + CommonScope = [] + CommonScope[0:1] = SubValue + CommonScope[-1] = 'COMMON' + # + # Cannot be redefined if this key already defined in COMMON Or defined in same arch + # + if SubValue in Value[0] or CommonScope in Value[0]: + self._LoggerError(ST.ERR_DECPARSE_REDEFINE % (Key, Value[1])) + return + self._ItemDict[Key].append([SecArch, self._RawData.LineIndex]) + + ## CheckRequiredFields + # Some sections need to check if some fields exist, define section for example + # Derived class can re-implement, top parser will call this function after all parsing done + # + def CheckRequiredFields(self): + if self._RawData: + pass + return True + + ## IsItemRequired + # In DEC spec, sections must have at least one statement except user + # extension. + # For example: "[guids" [] "]" + + # sub class can override this method to indicate if statement is a must. + # + def _IsStatementRequired(self): + if self._RawData: + pass + return False + + def _LoggerError(self, ErrorString): + Logger.Error(TOOL_NAME, FILE_PARSE_FAILURE, File=self._RawData.Filename, + Line = self._RawData.LineIndex, + ExtraData=ErrorString + ST.ERR_DECPARSE_LINE % self._RawData.CurrentLine) + + def _ReplaceMacro(self, String): + if gMACRO_PATTERN.findall(String): + String = ReplaceMacro(String, self._LocalMacro, False, + FileName = self._RawData.Filename, + Line = ['', self._RawData.LineIndex]) + String = ReplaceMacro(String, self._RawData.Macros, False, + FileName = self._RawData.Filename, + Line = ['', self._RawData.LineIndex]) + MacroUsed = gMACRO_PATTERN.findall(String) + if MacroUsed: + Logger.Error(TOOL_NAME, FILE_PARSE_FAILURE, + File=self._RawData.Filename, + Line = self._RawData.LineIndex, + ExtraData = ST.ERR_DECPARSE_MACRO_RESOLVE % (str(MacroUsed), String)) + return String + + def _MacroParser(self, String): + TokenList = GetSplitValueList(String, ' ', 1) + if len(TokenList) < 2 or TokenList[1] == '': + self._LoggerError(ST.ERR_DECPARSE_MACRO_PAIR) + + TokenList = GetSplitValueList(TokenList[1], DT.TAB_EQUAL_SPLIT, 1) + if TokenList[0] == '': + self._LoggerError(ST.ERR_DECPARSE_MACRO_NAME) + elif not IsValidToken(MACRO_PATTERN, TokenList[0]): + self._LoggerError(ST.ERR_DECPARSE_MACRO_NAME_UPPER % TokenList[0]) + + if len(TokenList) == 1: + self._LocalMacro[TokenList[0]] = '' + else: + self._LocalMacro[TokenList[0]] = self._ReplaceMacro(TokenList[1]) + + ## _ParseItem + # + # Parse specified item, this function must be derived by subclass + # + def _ParseItem(self): + if self._RawData: + pass + # + # Should never be called + # + return None + + + ## _TailCommentStrategy + # + # This function can be derived to parse tail comment + # default is it will not consume any lines + # + # @param Comment: Comment of current line + # + def _TailCommentStrategy(self, Comment): + if Comment: + pass + if self._RawData: + pass + return False + + ## _StopCurrentParsing + # + # Called in Parse if current parsing should be stopped when encounter some + # keyword + # Default is section start and end + # + # @param Line: Current line + # + def _StopCurrentParsing(self, Line): + if self._RawData: + pass + return Line[0] == DT.TAB_SECTION_START and Line[-1] == DT.TAB_SECTION_END + + ## _TryBackSlash + # + # Split comment and DEC content, concatenate lines if end of char is '\' + # + # @param ProcessedLine: ProcessedLine line + # @param ProcessedComments: ProcessedComments line + # + def _TryBackSlash(self, ProcessedLine, ProcessedComments): + CatLine = '' + Comment = '' + Line = ProcessedLine + CommentList = ProcessedComments + while not self._RawData.IsEndOfFile(): + if Line == '': + self._LoggerError(ST.ERR_DECPARSE_BACKSLASH_EMPTY) + break + + if Comment: + CommentList.append((Comment, self._RawData.LineIndex)) + if Line[-1] != DT.TAB_SLASH: + CatLine += Line + break + elif len(Line) < 2 or Line[-2] != ' ': + self._LoggerError(ST.ERR_DECPARSE_BACKSLASH) + else: + CatLine += Line[:-1] + Line, Comment = CleanString(self._RawData.GetNextLine()) + # + # Reach end of content + # + if self._RawData.IsEndOfFile(): + if not CatLine: + if ProcessedLine[-1] == DT.TAB_SLASH: + self._LoggerError(ST.ERR_DECPARSE_BACKSLASH_EMPTY) + CatLine = ProcessedLine + else: + if not Line or Line[-1] == DT.TAB_SLASH: + self._LoggerError(ST.ERR_DECPARSE_BACKSLASH_EMPTY) + CatLine += Line + + # + # All MACRO values defined by the DEFINE statements in any section + # (except [Userextensions] sections for Intel) of the INF or DEC file + # must be expanded before processing of the file. + # + __IsReplaceMacro = True + Header = self._RawData.CurrentScope[0] if self._RawData.CurrentScope else None + if Header and len(Header) > 2: + if Header[0].upper() == 'USEREXTENSIONS' and not (Header[1] == 'TianoCore' and Header[2] == '"ExtraFiles"'): + __IsReplaceMacro = False + if __IsReplaceMacro: + self._RawData.CurrentLine = self._ReplaceMacro(CatLine) + else: + self._RawData.CurrentLine = CatLine + + return CatLine, CommentList + + ## Parse + # This is a template method in which other member functions which might + # override by sub class are called. It is responsible for reading file + # line by line, and call other member functions to parse. This function + # should not be re-implement by sub class. + # + def Parse(self): + HeadComments = [] + TailComments = [] + + #====================================================================== + # CurComments may pointer to HeadComments or TailComments + #====================================================================== + CurComments = HeadComments + CurObj = None + ItemNum = 0 + FromBuf = False + + #====================================================================== + # Used to report error information if empty section found + #====================================================================== + Index = self._RawData.LineIndex + LineStr = self._RawData.CurrentLine + while not self._RawData.IsEndOfFile() or self._RawData.NextLine: + if self._RawData.NextLine: + #============================================================== + # Have processed line in buffer + #============================================================== + Line = self._RawData.NextLine + HeadComments.extend(self._RawData.HeadComment) + TailComments.extend(self._RawData.TailComment) + self._RawData.ResetNext() + Comment = '' + FromBuf = True + else: + #============================================================== + # No line in buffer, read next line + #============================================================== + Line, Comment = CleanString(self._RawData.GetNextLine()) + FromBuf = False + if Line: + if not FromBuf and CurObj and TailComments: + #========================================================== + # Set tail comments to previous statement if not empty. + #========================================================== + CurObj.SetTailComment(CurObj.GetTailComment()+TailComments) + + if not FromBuf: + del TailComments[:] + CurComments = TailComments + Comments = [] + if Comment: + Comments = [(Comment, self._RawData.LineIndex)] + + #============================================================== + # Try if last char of line has backslash + #============================================================== + Line, Comments = self._TryBackSlash(Line, Comments) + CurComments.extend(Comments) + + #============================================================== + # Macro found + #============================================================== + if Line.startswith('DEFINE '): + self._MacroParser(Line) + del HeadComments[:] + del TailComments[:] + CurComments = HeadComments + continue + + if self._StopCurrentParsing(Line): + #========================================================== + # This line does not belong to this parse, + # Save it, can be used by next parse + #========================================================== + self._RawData.SetNext(Line, HeadComments, TailComments) + break + + Obj = self._ParseItem() + ItemNum += 1 + if Obj: + Obj.SetHeadComment(Obj.GetHeadComment()+HeadComments) + Obj.SetTailComment(Obj.GetTailComment()+TailComments) + del HeadComments[:] + del TailComments[:] + CurObj = Obj + else: + CurObj = None + else: + if id(CurComments) == id(TailComments): + #========================================================== + # Check if this comment belongs to tail comment + #========================================================== + if not self._TailCommentStrategy(Comment): + CurComments = HeadComments + + if Comment: + CurComments.append(((Comment, self._RawData.LineIndex))) + else: + del CurComments[:] + + if self._IsStatementRequired() and ItemNum == 0: + Logger.Error( + TOOL_NAME, FILE_PARSE_FAILURE, + File=self._RawData.Filename, + Line=Index, + ExtraData=ST.ERR_DECPARSE_STATEMENT_EMPTY % LineStr + ) + +## _DecDefine +# Parse define section +# +class _DecDefine(_DecBase): + def __init__(self, RawData): + _DecBase.__init__(self, RawData) + self.ItemObject = DecDefineObject(RawData.Filename) + self._LocalMacro = self._RawData.Macros + self._DefSecNum = 0 + + # + # Each field has a function to validate + # + self.DefineValidation = { + DT.TAB_DEC_DEFINES_DEC_SPECIFICATION : self._SetDecSpecification, + DT.TAB_DEC_DEFINES_PACKAGE_NAME : self._SetPackageName, + DT.TAB_DEC_DEFINES_PACKAGE_GUID : self._SetPackageGuid, + DT.TAB_DEC_DEFINES_PACKAGE_VERSION : self._SetPackageVersion, + DT.TAB_DEC_DEFINES_PKG_UNI_FILE : self._SetPackageUni, + } + + def BlockStart(self): + self._DefSecNum += 1 + if self._DefSecNum > 1: + self._LoggerError(ST.ERR_DECPARSE_DEFINE_MULTISEC) + + ## CheckRequiredFields + # + # Check required fields: DEC_SPECIFICATION, PACKAGE_NAME + # PACKAGE_GUID, PACKAGE_VERSION + # + def CheckRequiredFields(self): + Ret = False + if self.ItemObject.GetPackageSpecification() == '': + Logger.Error(TOOL_NAME, FILE_PARSE_FAILURE, File=self._RawData.Filename, + ExtraData=ST.ERR_DECPARSE_DEFINE_REQUIRED % DT.TAB_DEC_DEFINES_DEC_SPECIFICATION) + elif self.ItemObject.GetPackageName() == '': + Logger.Error(TOOL_NAME, FILE_PARSE_FAILURE, File=self._RawData.Filename, + ExtraData=ST.ERR_DECPARSE_DEFINE_REQUIRED % DT.TAB_DEC_DEFINES_PACKAGE_NAME) + elif self.ItemObject.GetPackageGuid() == '': + Logger.Error(TOOL_NAME, FILE_PARSE_FAILURE, File=self._RawData.Filename, + ExtraData=ST.ERR_DECPARSE_DEFINE_REQUIRED % DT.TAB_DEC_DEFINES_PACKAGE_GUID) + elif self.ItemObject.GetPackageVersion() == '': + Logger.Error(TOOL_NAME, FILE_PARSE_FAILURE, File=self._RawData.Filename, + ExtraData=ST.ERR_DECPARSE_DEFINE_REQUIRED % DT.TAB_DEC_DEFINES_PACKAGE_VERSION) + else: + Ret = True + return Ret + + def _ParseItem(self): + Line = self._RawData.CurrentLine + TokenList = GetSplitValueList(Line, DT.TAB_EQUAL_SPLIT, 1) + if TokenList[0] == DT.TAB_DEC_DEFINES_PKG_UNI_FILE: + self.DefineValidation[TokenList[0]](TokenList[1]) + elif len(TokenList) < 2: + self._LoggerError(ST.ERR_DECPARSE_DEFINE_FORMAT) + elif TokenList[0] not in self.DefineValidation: + self._LoggerError(ST.ERR_DECPARSE_DEFINE_UNKNOWKEY % TokenList[0]) + else: + self.DefineValidation[TokenList[0]](TokenList[1]) + + DefineItem = DecDefineItemObject() + DefineItem.Key = TokenList[0] + DefineItem.Value = TokenList[1] + self.ItemObject.AddItem(DefineItem, self._RawData.CurrentScope) + return DefineItem + + def _SetDecSpecification(self, Token): + if self.ItemObject.GetPackageSpecification(): + self._LoggerError(ST.ERR_DECPARSE_DEFINE_DEFINED % DT.TAB_DEC_DEFINES_DEC_SPECIFICATION) + if not IsValidToken('0[xX][0-9a-fA-F]{8}', Token): + if not IsValidDecVersionVal(Token): + self._LoggerError(ST.ERR_DECPARSE_DEFINE_SPEC) + self.ItemObject.SetPackageSpecification(Token) + + def _SetPackageName(self, Token): + if self.ItemObject.GetPackageName(): + self._LoggerError(ST.ERR_DECPARSE_DEFINE_DEFINED % DT.TAB_DEC_DEFINES_PACKAGE_NAME) + if not IsValidWord(Token): + self._LoggerError(ST.ERR_DECPARSE_DEFINE_PKGNAME) + self.ItemObject.SetPackageName(Token) + + def _SetPackageGuid(self, Token): + if self.ItemObject.GetPackageGuid(): + self._LoggerError(ST.ERR_DECPARSE_DEFINE_DEFINED % DT.TAB_DEC_DEFINES_PACKAGE_GUID) + if not CheckGuidRegFormat(Token): + self._LoggerError(ST.ERR_DECPARSE_DEFINE_PKGGUID) + self.ItemObject.SetPackageGuid(Token) + + def _SetPackageVersion(self, Token): + if self.ItemObject.GetPackageVersion(): + self._LoggerError(ST.ERR_DECPARSE_DEFINE_DEFINED % DT.TAB_DEC_DEFINES_PACKAGE_VERSION) + if not IsValidToken(VERSION_PATTERN, Token): + self._LoggerError(ST.ERR_DECPARSE_DEFINE_PKGVERSION) + else: + if not DT.TAB_SPLIT in Token: + Token = Token + '.0' + self.ItemObject.SetPackageVersion(Token) + + def _SetPackageUni(self, Token): + if self.ItemObject.GetPackageUniFile(): + self._LoggerError(ST.ERR_DECPARSE_DEFINE_DEFINED % DT.TAB_DEC_DEFINES_PKG_UNI_FILE) + self.ItemObject.SetPackageUniFile(Token) + +## _DecInclude +# +# Parse include section +# +class _DecInclude(_DecBase): + def __init__(self, RawData): + _DecBase.__init__(self, RawData) + self.ItemObject = DecIncludeObject(RawData.Filename) + + def _ParseItem(self): + Line = self._RawData.CurrentLine + + if not IsValidPath(Line, self._RawData.PackagePath): + self._LoggerError(ST.ERR_DECPARSE_INCLUDE % Line) + + Item = DecIncludeItemObject(StripRoot(self._RawData.PackagePath, Line), self._RawData.PackagePath) + self.ItemObject.AddItem(Item, self._RawData.CurrentScope) + return Item + +## _DecLibraryclass +# +# Parse library class section +# +class _DecLibraryclass(_DecBase): + def __init__(self, RawData): + _DecBase.__init__(self, RawData) + self.ItemObject = DecLibraryclassObject(RawData.Filename) + + def _ParseItem(self): + Line = self._RawData.CurrentLine + TokenList = GetSplitValueList(Line, DT.TAB_VALUE_SPLIT) + if len(TokenList) != 2: + self._LoggerError(ST.ERR_DECPARSE_LIBCLASS_SPLIT) + if TokenList[0] == '' or TokenList[1] == '': + self._LoggerError(ST.ERR_DECPARSE_LIBCLASS_EMPTY) + if not IsValidToken('[A-Z][0-9A-Za-z]*', TokenList[0]): + self._LoggerError(ST.ERR_DECPARSE_LIBCLASS_LIB) + + self._CheckReDefine(TokenList[0]) + + Value = TokenList[1] + # + # Must end with .h + # + if not Value.endswith('.h'): + self._LoggerError(ST.ERR_DECPARSE_LIBCLASS_PATH_EXT) + + # + # Path must be existed + # + if not IsValidPath(Value, self._RawData.PackagePath): + self._LoggerError(ST.ERR_DECPARSE_INCLUDE % Value) + + Item = DecLibraryclassItemObject(TokenList[0], StripRoot(self._RawData.PackagePath, Value), + self._RawData.PackagePath) + self.ItemObject.AddItem(Item, self._RawData.CurrentScope) + return Item + +## _DecPcd +# +# Parse PCD section +# +class _DecPcd(_DecBase): + def __init__(self, RawData): + _DecBase.__init__(self, RawData) + self.ItemObject = DecPcdObject(RawData.Filename) + # + # Used to check duplicate token + # Key is token space and token number (integer), value is C name + # + self.TokenMap = {} + + def _ParseItem(self): + Line = self._RawData.CurrentLine + TokenList = Line.split(DT.TAB_VALUE_SPLIT) + if len(TokenList) < 4: + self._LoggerError(ST.ERR_DECPARSE_PCD_SPLIT) + + # + # Token space guid C name + # + PcdName = GetSplitValueList(TokenList[0], DT.TAB_SPLIT) + if len(PcdName) != 2 or PcdName[0] == '' or PcdName[1] == '': + self._LoggerError(ST.ERR_DECPARSE_PCD_NAME) + + Guid = PcdName[0] + if not IsValidToken(CVAR_PATTERN, Guid): + self._LoggerError(ST.ERR_DECPARSE_PCD_CVAR_GUID) + + # + # PCD C name + # + CName = PcdName[1] + if not IsValidToken(CVAR_PATTERN, CName): + self._LoggerError(ST.ERR_DECPARSE_PCD_CVAR_PCDCNAME) + + self._CheckReDefine(Guid + DT.TAB_SPLIT + CName) + + # + # Default value, may be C array, string or number + # + Data = DT.TAB_VALUE_SPLIT.join(TokenList[1:-2]).strip() + + # + # PCD data type + # + DataType = TokenList[-2].strip() + Valid, Cause = IsValidPcdDatum(DataType, Data) + if not Valid: + self._LoggerError(Cause) + PcdType = self._RawData.CurrentScope[0][0] + if PcdType == DT.TAB_PCDS_FEATURE_FLAG_NULL.upper() and DataType != 'BOOLEAN': + self._LoggerError(ST.ERR_DECPARSE_PCD_FEATUREFLAG) + # + # Token value is the last element in list. + # + Token = TokenList[-1].strip() + if not IsValidToken(PCD_TOKEN_PATTERN, Token): + self._LoggerError(ST.ERR_DECPARSE_PCD_TOKEN % Token) + elif not Token.startswith('0x') and not Token.startswith('0X'): + if int(Token) > 4294967295: + self._LoggerError(ST.ERR_DECPARSE_PCD_TOKEN_INT % Token) + Token = '0x%x' % int(Token) + + IntToken = int(Token, 0) + if (Guid, IntToken) in self.TokenMap: + if self.TokenMap[Guid, IntToken] != CName: + self._LoggerError(ST.ERR_DECPARSE_PCD_TOKEN_UNIQUE%(Token)) + else: + self.TokenMap[Guid, IntToken] = CName + + Item = DecPcdItemObject(Guid, CName, Data, DataType, Token) + self.ItemObject.AddItem(Item, self._RawData.CurrentScope) + return Item + +## _DecGuid +# +# Parse GUID, PPI, Protocol section +# +class _DecGuid(_DecBase): + def __init__(self, RawData): + _DecBase.__init__(self, RawData) + self.GuidObj = DecGuidObject(RawData.Filename) + self.PpiObj = DecPpiObject(RawData.Filename) + self.ProtocolObj = DecProtocolObject(RawData.Filename) + self.ObjectDict = \ + { + DT.TAB_GUIDS.upper() : self.GuidObj, + DT.TAB_PPIS.upper() : self.PpiObj, + DT.TAB_PROTOCOLS.upper() : self.ProtocolObj + } + + def GetDataObject(self): + if self._RawData.CurrentScope: + return self.ObjectDict[self._RawData.CurrentScope[0][0]] + return None + + def GetGuidObject(self): + return self.GuidObj + + def GetPpiObject(self): + return self.PpiObj + + def GetProtocolObject(self): + return self.ProtocolObj + + def _ParseItem(self): + Line = self._RawData.CurrentLine + TokenList = GetSplitValueList(Line, DT.TAB_EQUAL_SPLIT, 1) + if len(TokenList) < 2: + self._LoggerError(ST.ERR_DECPARSE_CGUID) + if TokenList[0] == '': + self._LoggerError(ST.ERR_DECPARSE_CGUID_NAME) + if TokenList[1] == '': + self._LoggerError(ST.ERR_DECPARSE_CGUID_GUID) + if not IsValidToken(CVAR_PATTERN, TokenList[0]): + self._LoggerError(ST.ERR_DECPARSE_PCD_CVAR_GUID) + + self._CheckReDefine(TokenList[0]) + + if TokenList[1][0] != '{': + if not CheckGuidRegFormat(TokenList[1]): + self._LoggerError(ST.ERR_DECPARSE_DEFINE_PKGGUID) + GuidString = TokenList[1] + else: + # + # Convert C format GUID to GUID string and Simple error check + # + GuidString = GuidStructureStringToGuidString(TokenList[1]) + if TokenList[1][0] != '{' or TokenList[1][-1] != '}' or GuidString == '': + self._LoggerError(ST.ERR_DECPARSE_CGUID_GUIDFORMAT) + + # + # Check C format GUID + # + if not IsValidCFormatGuid(TokenList[1]): + self._LoggerError(ST.ERR_DECPARSE_CGUID_GUIDFORMAT) + + Item = DecGuidItemObject(TokenList[0], TokenList[1], GuidString) + ItemObject = self.ObjectDict[self._RawData.CurrentScope[0][0]] + ItemObject.AddItem(Item, self._RawData.CurrentScope) + return Item + +## _DecUserExtension +# +# Parse user extension section +# +class _DecUserExtension(_DecBase): + def __init__(self, RawData): + _DecBase.__init__(self, RawData) + self.ItemObject = DecUserExtensionObject(RawData.Filename) + self._Headers = [] + self._CurItems = [] + + def BlockStart(self): + self._CurItems = [] + for Header in self._RawData.CurrentScope: + if Header in self._Headers: + self._LoggerError(ST.ERR_DECPARSE_UE_DUPLICATE) + else: + self._Headers.append(Header) + + for Item in self._CurItems: + if Item.UserId == Header[1] and Item.IdString == Header[2]: + Item.ArchAndModuleType.append(Header[3]) + break + else: + Item = DecUserExtensionItemObject() + Item.UserId = Header[1] + Item.IdString = Header[2] + Item.ArchAndModuleType.append(Header[3]) + self._CurItems.append(Item) + self.ItemObject.AddItem(Item, None) + self._LocalMacro = {} + + def _ParseItem(self): + Line = self._RawData.CurrentLine + Item = None + for Item in self._CurItems: + if Item.UserString: + Item.UserString = '\n'.join([Item.UserString, Line]) + else: + Item.UserString = Line + return Item + +## Dec +# +# Top dec parser +# +class Dec(_DecBase, _DecComments): + def __init__(self, DecFile, Parse = True): + try: + Content = ConvertSpecialChar(open(DecFile, 'r').readlines()) + except BaseException: + Logger.Error(TOOL_NAME, FILE_OPEN_FAILURE, File=DecFile, + ExtraData=ST.ERR_DECPARSE_FILEOPEN % DecFile) + + # + # Pre-parser for Private section + # + self._Private = '' + __IsFoundPrivate = False + NewContent = [] + for Line in Content: + Line = Line.strip() + if Line.startswith(DT.TAB_SECTION_START) and Line.endswith(DT.TAB_PRIVATE + DT.TAB_SECTION_END): + __IsFoundPrivate = True + if Line.startswith(DT.TAB_SECTION_START) and Line.endswith(DT.TAB_SECTION_END)\ + and not Line.endswith(DT.TAB_PRIVATE + DT.TAB_SECTION_END): + __IsFoundPrivate = False + if __IsFoundPrivate: + self._Private += Line + '\r' + if not __IsFoundPrivate: + NewContent.append(Line + '\r') + + RawData = FileContent(DecFile, NewContent) + + _DecComments.__init__(self) + _DecBase.__init__(self, RawData) + + self.BinaryHeadComment = [] + self.PcdErrorCommentDict = {} + + self._Define = _DecDefine(RawData) + self._Include = _DecInclude(RawData) + self._Guid = _DecGuid(RawData) + self._LibClass = _DecLibraryclass(RawData) + self._Pcd = _DecPcd(RawData) + self._UserEx = _DecUserExtension(RawData) + + # + # DEC file supported data types (one type per section) + # + self._SectionParser = { + DT.TAB_DEC_DEFINES.upper() : self._Define, + DT.TAB_INCLUDES.upper() : self._Include, + DT.TAB_LIBRARY_CLASSES.upper() : self._LibClass, + DT.TAB_GUIDS.upper() : self._Guid, + DT.TAB_PPIS.upper() : self._Guid, + DT.TAB_PROTOCOLS.upper() : self._Guid, + DT.TAB_PCDS_FIXED_AT_BUILD_NULL.upper() : self._Pcd, + DT.TAB_PCDS_PATCHABLE_IN_MODULE_NULL.upper() : self._Pcd, + DT.TAB_PCDS_FEATURE_FLAG_NULL.upper() : self._Pcd, + DT.TAB_PCDS_DYNAMIC_NULL.upper() : self._Pcd, + DT.TAB_PCDS_DYNAMIC_EX_NULL.upper() : self._Pcd, + DT.TAB_USER_EXTENSIONS.upper() : self._UserEx + } + + if Parse: + self.ParseDecComment() + self.Parse() + # + # Parsing done, check required fields + # + self.CheckRequiredFields() + + def CheckRequiredFields(self): + for SectionParser in self._SectionParser.values(): + if not SectionParser.CheckRequiredFields(): + return False + return True + + ## + # Parse DEC file + # + def ParseDecComment(self): + IsFileHeader = False + IsBinaryHeader = False + FileHeaderLineIndex = -1 + BinaryHeaderLineIndex = -1 + TokenSpaceGuidCName = '' + + # + # Parse PCD error comment section + # + while not self._RawData.IsEndOfFile(): + self._RawData.CurrentLine = self._RawData.GetNextLine() + if self._RawData.CurrentLine.startswith(DT.TAB_COMMENT_SPLIT) and \ + DT.TAB_SECTION_START in self._RawData.CurrentLine and \ + DT.TAB_SECTION_END in self._RawData.CurrentLine: + self._RawData.CurrentLine = self._RawData.CurrentLine.replace(DT.TAB_COMMENT_SPLIT, '').strip() + + if self._RawData.CurrentLine[0] == DT.TAB_SECTION_START and \ + self._RawData.CurrentLine[-1] == DT.TAB_SECTION_END: + RawSection = self._RawData.CurrentLine[1:-1].strip() + if RawSection.upper().startswith(DT.TAB_PCD_ERROR.upper()+'.'): + TokenSpaceGuidCName = RawSection.split(DT.TAB_PCD_ERROR+'.')[1].strip() + continue + + if TokenSpaceGuidCName and self._RawData.CurrentLine.startswith(DT.TAB_COMMENT_SPLIT): + self._RawData.CurrentLine = self._RawData.CurrentLine.replace(DT.TAB_COMMENT_SPLIT, '').strip() + if self._RawData.CurrentLine != '': + if DT.TAB_VALUE_SPLIT not in self._RawData.CurrentLine: + self._LoggerError(ST.ERR_DECPARSE_PCDERRORMSG_MISS_VALUE_SPLIT) + + PcdErrorNumber, PcdErrorMsg = GetSplitValueList(self._RawData.CurrentLine, DT.TAB_VALUE_SPLIT, 1) + PcdErrorNumber = ParsePcdErrorCode(PcdErrorNumber, self._RawData.Filename, self._RawData.LineIndex) + if not PcdErrorMsg.strip(): + self._LoggerError(ST.ERR_DECPARSE_PCD_MISS_ERRORMSG) + + self.PcdErrorCommentDict[(TokenSpaceGuidCName, PcdErrorNumber)] = PcdErrorMsg.strip() + else: + TokenSpaceGuidCName = '' + + self._RawData.LineIndex = 0 + self._RawData.CurrentLine = '' + self._RawData.NextLine = '' + + while not self._RawData.IsEndOfFile(): + Line, Comment = CleanString(self._RawData.GetNextLine()) + + # + # Header must be pure comment + # + if Line != '': + self._RawData.UndoNextLine() + break + + if Comment and Comment.startswith(DT.TAB_SPECIAL_COMMENT) and Comment.find(DT.TAB_HEADER_COMMENT) > 0 \ + and not Comment[2:Comment.find(DT.TAB_HEADER_COMMENT)].strip(): + IsFileHeader = True + IsBinaryHeader = False + FileHeaderLineIndex = self._RawData.LineIndex + + # + # Get license information before '@file' + # + if not IsFileHeader and not IsBinaryHeader and Comment and Comment.startswith(DT.TAB_COMMENT_SPLIT) and \ + DT.TAB_BINARY_HEADER_COMMENT not in Comment: + self._HeadComment.append((Comment, self._RawData.LineIndex)) + + if Comment and IsFileHeader and \ + not(Comment.startswith(DT.TAB_SPECIAL_COMMENT) \ + and Comment.find(DT.TAB_BINARY_HEADER_COMMENT) > 0): + self._HeadComment.append((Comment, self._RawData.LineIndex)) + # + # Double '#' indicates end of header comments + # + if (not Comment or Comment == DT.TAB_SPECIAL_COMMENT) and IsFileHeader: + IsFileHeader = False + continue + + if Comment and Comment.startswith(DT.TAB_SPECIAL_COMMENT) \ + and Comment.find(DT.TAB_BINARY_HEADER_COMMENT) > 0: + IsBinaryHeader = True + IsFileHeader = False + BinaryHeaderLineIndex = self._RawData.LineIndex + + if Comment and IsBinaryHeader: + self.BinaryHeadComment.append((Comment, self._RawData.LineIndex)) + # + # Double '#' indicates end of header comments + # + if (not Comment or Comment == DT.TAB_SPECIAL_COMMENT) and IsBinaryHeader: + IsBinaryHeader = False + break + + if FileHeaderLineIndex > -1 and not IsFileHeader and not IsBinaryHeader: + break + + if FileHeaderLineIndex > BinaryHeaderLineIndex and FileHeaderLineIndex > -1 and BinaryHeaderLineIndex > -1: + self._LoggerError(ST.ERR_BINARY_HEADER_ORDER) + + if FileHeaderLineIndex == -1: +# self._LoggerError(ST.ERR_NO_SOURCE_HEADER) + Logger.Error(TOOL_NAME, FORMAT_INVALID, + ST.ERR_NO_SOURCE_HEADER, + File=self._RawData.Filename) + return + + def _StopCurrentParsing(self, Line): + return False + + def _ParseItem(self): + self._SectionHeaderParser() + if len(self._RawData.CurrentScope) == 0: + self._LoggerError(ST.ERR_DECPARSE_SECTION_EMPTY) + SectionObj = self._SectionParser[self._RawData.CurrentScope[0][0]] + SectionObj.BlockStart() + SectionObj.Parse() + return SectionObj.GetDataObject() + + def _UserExtentionSectionParser(self): + self._RawData.CurrentScope = [] + ArchList = set() + Section = self._RawData.CurrentLine[1:-1] + Par = ParserHelper(Section, self._RawData.Filename) + while not Par.End(): + # + # User extention + # + Token = Par.GetToken() + if Token.upper() != DT.TAB_USER_EXTENSIONS.upper(): + self._LoggerError(ST.ERR_DECPARSE_SECTION_UE) + UserExtension = Token.upper() + Par.AssertChar(DT.TAB_SPLIT, ST.ERR_DECPARSE_SECTION_UE, self._RawData.LineIndex) + + # + # UserID + # + Token = Par.GetToken() + if not IsValidUserId(Token): + self._LoggerError(ST.ERR_DECPARSE_SECTION_UE_USERID) + UserId = Token + Par.AssertChar(DT.TAB_SPLIT, ST.ERR_DECPARSE_SECTION_UE, self._RawData.LineIndex) + # + # IdString + # + Token = Par.GetToken() + if not IsValidIdString(Token): + self._LoggerError(ST.ERR_DECPARSE_SECTION_UE_IDSTRING) + IdString = Token + Arch = 'COMMON' + if Par.Expect(DT.TAB_SPLIT): + Token = Par.GetToken() + Arch = Token.upper() + if not IsValidArch(Arch): + self._LoggerError(ST.ERR_DECPARSE_ARCH) + ArchList.add(Arch) + if [UserExtension, UserId, IdString, Arch] not in \ + self._RawData.CurrentScope: + self._RawData.CurrentScope.append( + [UserExtension, UserId, IdString, Arch] + ) + if not Par.Expect(DT.TAB_COMMA_SPLIT): + break + elif Par.End(): + self._LoggerError(ST.ERR_DECPARSE_SECTION_COMMA) + Par.AssertEnd(ST.ERR_DECPARSE_SECTION_UE, self._RawData.LineIndex) + if 'COMMON' in ArchList and len(ArchList) > 1: + self._LoggerError(ST.ERR_DECPARSE_SECTION_COMMON) + + ## Section header parser + # + # The section header is always in following format: + # + # [section_name.arch<.platform|module_type>] + # + def _SectionHeaderParser(self): + if self._RawData.CurrentLine[0] != DT.TAB_SECTION_START or self._RawData.CurrentLine[-1] != DT.TAB_SECTION_END: + self._LoggerError(ST.ERR_DECPARSE_SECTION_IDENTIFY) + + RawSection = self._RawData.CurrentLine[1:-1].strip().upper() + # + # Check defines section which is only allowed to occur once and + # no arch can be followed + # + if RawSection.startswith(DT.TAB_DEC_DEFINES.upper()): + if RawSection != DT.TAB_DEC_DEFINES.upper(): + self._LoggerError(ST.ERR_DECPARSE_DEFINE_SECNAME) + # + # Check user extension section + # + if RawSection.startswith(DT.TAB_USER_EXTENSIONS.upper()): + return self._UserExtentionSectionParser() + self._RawData.CurrentScope = [] + SectionNames = [] + ArchList = set() + for Item in GetSplitValueList(RawSection, DT.TAB_COMMA_SPLIT): + if Item == '': + self._LoggerError(ST.ERR_DECPARSE_SECTION_SUBEMPTY % self._RawData.CurrentLine) + + ItemList = GetSplitValueList(Item, DT.TAB_SPLIT) + # + # different types of PCD are permissible in one section + # + SectionName = ItemList[0] + if SectionName not in self._SectionParser: + self._LoggerError(ST.ERR_DECPARSE_SECTION_UNKNOW % SectionName) + if SectionName not in SectionNames: + SectionNames.append(SectionName) + # + # In DEC specification, all section headers have at most two part: + # SectionName.Arch except UserExtension + # + if len(ItemList) > 2: + self._LoggerError(ST.ERR_DECPARSE_SECTION_SUBTOOMANY % Item) + + if DT.TAB_PCDS_FEATURE_FLAG_NULL.upper() in SectionNames and len(SectionNames) > 1: + self._LoggerError(ST.ERR_DECPARSE_SECTION_FEATUREFLAG % DT.TAB_PCDS_FEATURE_FLAG_NULL) + # + # S1 is always Arch + # + if len(ItemList) > 1: + Str1 = ItemList[1] + if not IsValidArch(Str1): + self._LoggerError(ST.ERR_DECPARSE_ARCH) + else: + Str1 = 'COMMON' + ArchList.add(Str1) + + if [SectionName, Str1] not in self._RawData.CurrentScope: + self._RawData.CurrentScope.append([SectionName, Str1]) + # + # 'COMMON' must not be used with specific ARCHs at the same section + # + if 'COMMON' in ArchList and len(ArchList) > 1: + self._LoggerError(ST.ERR_DECPARSE_SECTION_COMMON) + if len(SectionNames) == 0: + self._LoggerError(ST.ERR_DECPARSE_SECTION_SUBEMPTY % self._RawData.CurrentLine) + if len(SectionNames) != 1: + for Sec in SectionNames: + if not Sec.startswith(DT.TAB_PCDS.upper()): + self._LoggerError(ST.ERR_DECPARSE_SECTION_NAME % str(SectionNames)) + + def GetDefineSectionMacro(self): + return self._Define.GetLocalMacro() + def GetDefineSectionObject(self): + return self._Define.GetDataObject() + def GetIncludeSectionObject(self): + return self._Include.GetDataObject() + def GetGuidSectionObject(self): + return self._Guid.GetGuidObject() + def GetProtocolSectionObject(self): + return self._Guid.GetProtocolObject() + def GetPpiSectionObject(self): + return self._Guid.GetPpiObject() + def GetLibraryClassSectionObject(self): + return self._LibClass.GetDataObject() + def GetPcdSectionObject(self): + return self._Pcd.GetDataObject() + def GetUserExtensionSectionObject(self): + return self._UserEx.GetDataObject() + def GetPackageSpecification(self): + return self._Define.GetDataObject().GetPackageSpecification() + def GetPackageName(self): + return self._Define.GetDataObject().GetPackageName() + def GetPackageGuid(self): + return self._Define.GetDataObject().GetPackageGuid() + def GetPackageVersion(self): + return self._Define.GetDataObject().GetPackageVersion() + def GetPackageUniFile(self): + return self._Define.GetDataObject().GetPackageUniFile() + def GetPrivateSections(self): + return self._Private diff --git a/src/VBox/Devices/EFI/Firmware/BaseTools/Source/Python/UPT/Parser/DecParserMisc.py b/src/VBox/Devices/EFI/Firmware/BaseTools/Source/Python/UPT/Parser/DecParserMisc.py new file mode 100755 index 00000000..4731c85c --- /dev/null +++ b/src/VBox/Devices/EFI/Firmware/BaseTools/Source/Python/UPT/Parser/DecParserMisc.py @@ -0,0 +1,364 @@ +## @file +# This file is used to define helper class and function for DEC parser +# +# Copyright (c) 2011 - 2018, Intel Corporation. All rights reserved.
+# +# SPDX-License-Identifier: BSD-2-Clause-Patent + +''' +DecParserMisc +''' + +## Import modules +# +import os +import Logger.Log as Logger +from Logger.ToolError import FILE_PARSE_FAILURE +from Logger import StringTable as ST +from Library.DataType import TAB_COMMENT_SPLIT +from Library.DataType import TAB_COMMENT_EDK1_SPLIT +from Library.ExpressionValidate import IsValidBareCString +from Library.ParserValidate import IsValidCFormatGuid +from Library.ExpressionValidate import IsValidFeatureFlagExp +from Library.ExpressionValidate import IsValidLogicalExpr +from Library.ExpressionValidate import IsValidStringTest +from Library.Misc import CheckGuidRegFormat + +TOOL_NAME = 'DecParser' +VERSION_PATTERN = '[0-9]+(\.[0-9]+)?' +CVAR_PATTERN = '[_a-zA-Z][a-zA-Z0-9_]*' +PCD_TOKEN_PATTERN = '(0[xX]0*[a-fA-F0-9]{1,8})|([0-9]+)' +MACRO_PATTERN = '[A-Z][_A-Z0-9]*' + +## FileContent +# Class to hold DEC file information +# +class FileContent: + def __init__(self, Filename, FileContent2): + self.Filename = Filename + self.PackagePath, self.PackageFile = os.path.split(Filename) + self.LineIndex = 0 + self.CurrentLine = '' + self.NextLine = '' + self.HeadComment = [] + self.TailComment = [] + self.CurrentScope = None + self.Content = FileContent2 + self.Macros = {} + self.FileLines = len(FileContent2) + + def GetNextLine(self): + if self.LineIndex >= self.FileLines: + return '' + Line = self.Content[self.LineIndex] + self.LineIndex += 1 + return Line + + def UndoNextLine(self): + if self.LineIndex > 0: + self.LineIndex -= 1 + + def ResetNext(self): + self.HeadComment = [] + self.TailComment = [] + self.NextLine = '' + + def SetNext(self, Line, HeadComment, TailComment): + self.NextLine = Line + self.HeadComment = HeadComment + self.TailComment = TailComment + + def IsEndOfFile(self): + return self.LineIndex >= self.FileLines + + +## StripRoot +# +# Strip root path +# +# @param Root: Root must be absolute path +# @param Path: Path to be stripped +# +def StripRoot(Root, Path): + OrigPath = Path + Root = os.path.normpath(Root) + Path = os.path.normpath(Path) + if not os.path.isabs(Root): + return OrigPath + if Path.startswith(Root): + Path = Path[len(Root):] + if Path and Path[0] == os.sep: + Path = Path[1:] + return Path + return OrigPath + +## CleanString +# +# Split comments in a string +# Remove spaces +# +# @param Line: The string to be cleaned +# @param CommentCharacter: Comment char, used to ignore comment content, +# default is DataType.TAB_COMMENT_SPLIT +# +def CleanString(Line, CommentCharacter=TAB_COMMENT_SPLIT, \ + AllowCppStyleComment=False): + # + # remove whitespace + # + Line = Line.strip() + # + # Replace EDK1's comment character + # + if AllowCppStyleComment: + Line = Line.replace(TAB_COMMENT_EDK1_SPLIT, CommentCharacter) + # + # separate comments and statements + # + Comment = '' + InQuote = False + for Index in range(0, len(Line)): + if Line[Index] == '"': + InQuote = not InQuote + continue + if Line[Index] == CommentCharacter and not InQuote: + Comment = Line[Index:].strip() + Line = Line[0:Index].strip() + break + + return Line, Comment + + +## IsValidNumValUint8 +# +# Check if Token is NumValUint8: ::= {} {} {} +# +# @param Token: Token to be checked +# +def IsValidNumValUint8(Token): + Valid = True + Cause = "" + TokenValue = None + Token = Token.strip() + if Token.lower().startswith('0x'): + Base = 16 + else: + Base = 10 + try: + TokenValue = int(Token, Base) + except BaseException: + Valid, Cause = IsValidLogicalExpr(Token, True) + if Cause: + pass + if not Valid: + return False + if TokenValue and (TokenValue < 0 or TokenValue > 0xFF): + return False + else: + return True + +## IsValidNList +# +# Check if Value has the format of ["," ]{0,} +# ::= {} {} {} +# +# @param Value: Value to be checked +# +def IsValidNList(Value): + Par = ParserHelper(Value) + if Par.End(): + return False + while not Par.End(): + Token = Par.GetToken(',') + if not IsValidNumValUint8(Token): + return False + if Par.Expect(','): + if Par.End(): + return False + continue + else: + break + return Par.End() + +## IsValidCArray +# +# check Array is valid +# +# @param Array: The input Array +# +def IsValidCArray(Array): + Par = ParserHelper(Array) + if not Par.Expect('{'): + return False + if Par.End(): + return False + while not Par.End(): + Token = Par.GetToken(',}') + # + # ShortNum, UINT8, Expression + # + if not IsValidNumValUint8(Token): + return False + if Par.Expect(','): + if Par.End(): + return False + continue + elif Par.Expect('}'): + # + # End of C array + # + break + else: + return False + return Par.End() + +## IsValidPcdDatum +# +# check PcdDatum is valid +# +# @param Type: The pcd Type +# @param Value: The pcd Value +# +def IsValidPcdDatum(Type, Value): + if not Value: + return False, ST.ERR_DECPARSE_PCD_VALUE_EMPTY + Valid = True + Cause = "" + if Type not in ["UINT8", "UINT16", "UINT32", "UINT64", "VOID*", "BOOLEAN"]: + return False, ST.ERR_DECPARSE_PCD_TYPE + if Type == "VOID*": + if not ((Value.startswith('L"') or Value.startswith('"') and \ + Value.endswith('"')) + or (IsValidCArray(Value)) or (IsValidCFormatGuid(Value)) \ + or (IsValidNList(Value)) or (CheckGuidRegFormat(Value)) + ): + return False, ST.ERR_DECPARSE_PCD_VOID % (Value, Type) + RealString = Value[Value.find('"') + 1 :-1] + if RealString: + if not IsValidBareCString(RealString): + return False, ST.ERR_DECPARSE_PCD_VOID % (Value, Type) + elif Type == 'BOOLEAN': + if Value in ['TRUE', 'FALSE', 'true', 'false', 'True', 'False', + '0x1', '0x01', '1', '0x0', '0x00', '0']: + return True, "" + Valid, Cause = IsValidStringTest(Value, True) + if not Valid: + Valid, Cause = IsValidFeatureFlagExp(Value, True) + if not Valid: + return False, Cause + else: + if Value and (Value[0] == '-' or Value[0] == '+'): + return False, ST.ERR_DECPARSE_PCD_INT_NEGTIVE % (Value, Type) + try: + StrVal = Value + if Value and not Value.startswith('0x') \ + and not Value.startswith('0X'): + Value = Value.lstrip('0') + if not Value: + return True, "" + Value = int(Value, 0) + MAX_VAL_TYPE = {"BOOLEAN": 0x01, 'UINT8': 0xFF, 'UINT16': 0xFFFF, 'UINT32': 0xFFFFFFFF, + 'UINT64': 0xFFFFFFFFFFFFFFFF} + if Value > MAX_VAL_TYPE[Type]: + return False, ST.ERR_DECPARSE_PCD_INT_EXCEED % (StrVal, Type) + except BaseException: + Valid, Cause = IsValidLogicalExpr(Value, True) + if not Valid: + return False, Cause + + return True, "" + +## ParserHelper +# +class ParserHelper: + def __init__(self, String, File=''): + self._String = String + self._StrLen = len(String) + self._Index = 0 + self._File = File + + ## End + # + # End + # + def End(self): + self.__SkipWhitespace() + return self._Index >= self._StrLen + + ## __SkipWhitespace + # + # Skip whitespace + # + def __SkipWhitespace(self): + for Char in self._String[self._Index:]: + if Char not in ' \t': + break + self._Index += 1 + + ## Expect + # + # Expect char in string + # + # @param ExpectChar: char expected in index of string + # + def Expect(self, ExpectChar): + self.__SkipWhitespace() + for Char in self._String[self._Index:]: + if Char != ExpectChar: + return False + else: + self._Index += 1 + return True + # + # Index out of bound of String + # + return False + + ## GetToken + # + # Get token until encounter StopChar, front whitespace is consumed + # + # @param StopChar: Get token until encounter char in StopChar + # @param StkipPair: Only can be ' or ", StopChar in SkipPair are skipped + # + def GetToken(self, StopChar='.,|\t ', SkipPair='"'): + self.__SkipWhitespace() + PreIndex = self._Index + InQuote = False + LastChar = '' + for Char in self._String[self._Index:]: + if Char == SkipPair and LastChar != '\\': + InQuote = not InQuote + if Char in StopChar and not InQuote: + break + self._Index += 1 + if Char == '\\' and LastChar == '\\': + LastChar = '' + else: + LastChar = Char + return self._String[PreIndex:self._Index] + + ## AssertChar + # + # Assert char at current index of string is AssertChar, or will report + # error message + # + # @param AssertChar: AssertChar + # @param ErrorString: ErrorString + # @param ErrorLineNum: ErrorLineNum + # + def AssertChar(self, AssertChar, ErrorString, ErrorLineNum): + if not self.Expect(AssertChar): + Logger.Error(TOOL_NAME, FILE_PARSE_FAILURE, File=self._File, + Line=ErrorLineNum, ExtraData=ErrorString) + + ## AssertEnd + # + # @param ErrorString: ErrorString + # @param ErrorLineNum: ErrorLineNum + # + def AssertEnd(self, ErrorString, ErrorLineNum): + self.__SkipWhitespace() + if self._Index != self._StrLen: + Logger.Error(TOOL_NAME, FILE_PARSE_FAILURE, File=self._File, + Line=ErrorLineNum, ExtraData=ErrorString) diff --git a/src/VBox/Devices/EFI/Firmware/BaseTools/Source/Python/UPT/Parser/InfAsBuiltProcess.py b/src/VBox/Devices/EFI/Firmware/BaseTools/Source/Python/UPT/Parser/InfAsBuiltProcess.py new file mode 100755 index 00000000..0f9e9ad3 --- /dev/null +++ b/src/VBox/Devices/EFI/Firmware/BaseTools/Source/Python/UPT/Parser/InfAsBuiltProcess.py @@ -0,0 +1,283 @@ +## @file +# This file is used to provide method for process AsBuilt INF file. It will consumed by InfParser +# +# Copyright (c) 2011 - 2018, Intel Corporation. All rights reserved.
+# +# SPDX-License-Identifier: BSD-2-Clause-Patent +''' +InfAsBuiltProcess +''' +## Import modules +# + +import os +import re +from Library import GlobalData +import Logger.Log as Logger +from Logger import StringTable as ST +from Logger import ToolError + +from Library.StringUtils import GetSplitValueList +from Library.Misc import GetHelpStringByRemoveHashKey +from Library.Misc import ValidFile +from Library.Misc import ProcessLineExtender +from Library.ParserValidate import IsValidPath +from Library.Parsing import MacroParser +from Parser.InfParserMisc import InfExpandMacro + +from Library import DataType as DT + +## GetLibInstanceInfo +# +# Get the information from Library Instance INF file. +# +# @param string. A string start with # and followed by INF file path +# @param WorkSpace. The WorkSpace directory used to combined with INF file path. +# +# @return GUID, Version +def GetLibInstanceInfo(String, WorkSpace, LineNo, CurrentInfFileName): + + FileGuidString = "" + VerString = "" + + OriginalString = String + String = String.strip() + if not String: + return None, None + # + # Remove "#" characters at the beginning + # + String = GetHelpStringByRemoveHashKey(String) + String = String.strip() + + # + # To deal with library instance specified by GUID and version + # + RegFormatGuidPattern = re.compile("\s*([0-9a-fA-F]){8}-" + "([0-9a-fA-F]){4}-" + "([0-9a-fA-F]){4}-" + "([0-9a-fA-F]){4}-" + "([0-9a-fA-F]){12}\s*") + VersionPattern = re.compile('[\t\s]*\d+(\.\d+)?[\t\s]*') + GuidMatchedObj = RegFormatGuidPattern.search(String) + + if String.upper().startswith('GUID') and GuidMatchedObj and 'Version' in String: + VersionStr = String[String.upper().find('VERSION') + 8:] + VersionMatchedObj = VersionPattern.search(VersionStr) + if VersionMatchedObj: + Guid = GuidMatchedObj.group().strip() + Version = VersionMatchedObj.group().strip() + return Guid, Version + + # + # To deal with library instance specified by file name + # + FileLinesList = GetFileLineContent(String, WorkSpace, LineNo, OriginalString) + + + ReFindFileGuidPattern = re.compile("^\s*FILE_GUID\s*=.*$") + ReFindVerStringPattern = re.compile("^\s*VERSION_STRING\s*=.*$") + + for Line in FileLinesList: + if ReFindFileGuidPattern.match(Line): + FileGuidString = Line + if ReFindVerStringPattern.match(Line): + VerString = Line + + if FileGuidString: + FileGuidString = GetSplitValueList(FileGuidString, '=', 1)[1] + if VerString: + VerString = GetSplitValueList(VerString, '=', 1)[1] + + return FileGuidString, VerString + +## GetPackageListInfo +# +# Get the package information from INF file. +# +# @param string. A string start with # and followed by INF file path +# @param WorkSpace. The WorkSpace directory used to combined with INF file path. +# +# @return GUID, Version +def GetPackageListInfo(FileNameString, WorkSpace, LineNo): + PackageInfoList = [] + DefineSectionMacros = {} + PackageSectionMacros = {} + + FileLinesList = GetFileLineContent(FileNameString, WorkSpace, LineNo, '') + + RePackageHeader = re.compile('^\s*\[Packages.*\].*$') + ReDefineHeader = re.compile('^\s*\[Defines].*$') + + PackageHederFlag = False + DefineHeaderFlag = False + LineNo = -1 + for Line in FileLinesList: + LineNo += 1 + Line = Line.strip() + + if Line.startswith('['): + PackageHederFlag = False + DefineHeaderFlag = False + + if Line.startswith("#"): + continue + + if not Line: + continue + + # + # Found [Packages] section + # + if RePackageHeader.match(Line): + PackageHederFlag = True + continue + + # + # Found [Define] section + # + if ReDefineHeader.match(Line): + DefineHeaderFlag = True + continue + + if DefineHeaderFlag: + # + # Find Macro + # + Name, Value = MacroParser((Line, LineNo), + FileNameString, + DT.MODEL_META_DATA_HEADER, + DefineSectionMacros) + + if Name is not None: + DefineSectionMacros[Name] = Value + continue + + if PackageHederFlag: + + # + # Find Macro + # + Name, Value = MacroParser((Line, LineNo), + FileNameString, + DT.MODEL_META_DATA_PACKAGE, + DefineSectionMacros) + if Name is not None: + PackageSectionMacros[Name] = Value + continue + + # + # Replace with Local section Macro and [Defines] section Macro. + # + Line = InfExpandMacro(Line, (FileNameString, Line, LineNo), DefineSectionMacros, PackageSectionMacros, True) + + Line = GetSplitValueList(Line, "#", 1)[0] + Line = GetSplitValueList(Line, "|", 1)[0] + PackageInfoList.append(Line) + + return PackageInfoList + +def GetFileLineContent(FileName, WorkSpace, LineNo, OriginalString): + + if not LineNo: + LineNo = -1 + + # + # Validate file name exist. + # + FullFileName = os.path.normpath(os.path.realpath(os.path.join(WorkSpace, FileName))) + if not (ValidFile(FullFileName)): + return [] + + # + # Validate file exist/format. + # + if not IsValidPath(FileName, WorkSpace): + return [] + + FileLinesList = [] + + try: + FullFileName = FullFileName.replace('\\', '/') + Inputfile = open(FullFileName, "r") + try: + FileLinesList = Inputfile.readlines() + except BaseException: + Logger.Error("InfParser", ToolError.FILE_READ_FAILURE, ST.ERR_FILE_OPEN_FAILURE, File=FullFileName) + finally: + Inputfile.close() + except BaseException: + Logger.Error("InfParser", + ToolError.FILE_READ_FAILURE, + ST.ERR_FILE_OPEN_FAILURE, + File=FullFileName) + + FileLinesList = ProcessLineExtender(FileLinesList) + + return FileLinesList + +## +# Get all INF files from current workspace +# +# +def GetInfsFromWorkSpace(WorkSpace): + InfFiles = [] + for top, dirs, files in os.walk(WorkSpace): + dirs = dirs # just for pylint + for File in files: + if File.upper().endswith(".INF"): + InfFiles.append(os.path.join(top, File)) + + return InfFiles + +## +# Get GUID and version from library instance file +# +# +def GetGuidVerFormLibInstance(Guid, Version, WorkSpace, CurrentInfFileName): + for InfFile in GetInfsFromWorkSpace(WorkSpace): + try: + if InfFile.strip().upper() == CurrentInfFileName.strip().upper(): + continue + InfFile = InfFile.replace('\\', '/') + if InfFile not in GlobalData.gLIBINSTANCEDICT: + InfFileObj = open(InfFile, "r") + GlobalData.gLIBINSTANCEDICT[InfFile] = InfFileObj + else: + InfFileObj = GlobalData.gLIBINSTANCEDICT[InfFile] + + except BaseException: + Logger.Error("InfParser", + ToolError.FILE_READ_FAILURE, + ST.ERR_FILE_OPEN_FAILURE, + File=InfFile) + try: + FileLinesList = InfFileObj.readlines() + FileLinesList = ProcessLineExtender(FileLinesList) + + ReFindFileGuidPattern = re.compile("^\s*FILE_GUID\s*=.*$") + ReFindVerStringPattern = re.compile("^\s*VERSION_STRING\s*=.*$") + + for Line in FileLinesList: + if ReFindFileGuidPattern.match(Line): + FileGuidString = Line + if ReFindVerStringPattern.match(Line): + VerString = Line + + if FileGuidString: + FileGuidString = GetSplitValueList(FileGuidString, '=', 1)[1] + if VerString: + VerString = GetSplitValueList(VerString, '=', 1)[1] + + if FileGuidString.strip().upper() == Guid.upper() and \ + VerString.strip().upper() == Version.upper(): + return Guid, Version + + except BaseException: + Logger.Error("InfParser", ToolError.FILE_READ_FAILURE, ST.ERR_FILE_OPEN_FAILURE, File=InfFile) + finally: + InfFileObj.close() + + return '', '' + + diff --git a/src/VBox/Devices/EFI/Firmware/BaseTools/Source/Python/UPT/Parser/InfBinarySectionParser.py b/src/VBox/Devices/EFI/Firmware/BaseTools/Source/Python/UPT/Parser/InfBinarySectionParser.py new file mode 100755 index 00000000..b3ee7084 --- /dev/null +++ b/src/VBox/Devices/EFI/Firmware/BaseTools/Source/Python/UPT/Parser/InfBinarySectionParser.py @@ -0,0 +1,226 @@ +## @file +# This file contained the parser for [Binaries] sections in INF file +# +# Copyright (c) 2011 - 2018, Intel Corporation. All rights reserved.
+# +# SPDX-License-Identifier: BSD-2-Clause-Patent +# +''' +InfBinarySectionParser +''' +## +# Import Modules +# + +import Logger.Log as Logger +from Logger import StringTable as ST +from Logger.ToolError import FORMAT_INVALID +from Parser.InfParserMisc import InfExpandMacro +from Library import DataType as DT +from Library.Parsing import MacroParser +from Library.Misc import GetSplitValueList +from Object.Parser.InfCommonObject import InfLineCommentObject +from Object.Parser.InfCommonObject import CurrentLine +from Parser.InfParserMisc import InfParserSectionRoot + +class InfBinarySectionParser(InfParserSectionRoot): + ## InfBinaryParser + # + # + def InfBinaryParser(self, SectionString, InfSectionObject, FileName): + # + # Macro defined in this section + # + SectionMacros = {} + ValueList = [] + # + # For UI (UI, SEC_UI, UNI_UI) binaries + # One and only one UI section can be included + # + UiBinaryList = [] + # + # For Version (VER, SEC_VER, UNI_VER). + # One and only one VER section on be included + # + VerBinaryList = [] + # + # For other common type binaries + # + ComBinaryList = [] + + StillCommentFalg = False + HeaderComments = [] + LineComment = None + + AllSectionContent = '' + # + # Parse section content + # + for Line in SectionString: + BinLineContent = Line[0] + BinLineNo = Line[1] + + if BinLineContent.strip() == '': + continue + + CurrentLineObj = CurrentLine() + CurrentLineObj.FileName = FileName + CurrentLineObj.LineString = BinLineContent + CurrentLineObj.LineNo = BinLineNo + # + # Found Header Comments + # + if BinLineContent.strip().startswith(DT.TAB_COMMENT_SPLIT): + # + # Last line is comments, and this line go on. + # + if StillCommentFalg: + HeaderComments.append(Line) + AllSectionContent += BinLineContent + DT.END_OF_LINE + continue + # + # First time encounter comment + # + else: + # + # Clear original data + # + HeaderComments = [] + HeaderComments.append(Line) + AllSectionContent += BinLineContent + DT.END_OF_LINE + StillCommentFalg = True + continue + else: + StillCommentFalg = False + + if len(HeaderComments) >= 1: + LineComment = InfLineCommentObject() + LineCommentContent = '' + for Item in HeaderComments: + LineCommentContent += Item[0] + DT.END_OF_LINE + LineComment.SetHeaderComments(LineCommentContent) + + # + # Find Tail comment. + # + if BinLineContent.find(DT.TAB_COMMENT_SPLIT) > -1: + TailComments = BinLineContent[BinLineContent.find(DT.TAB_COMMENT_SPLIT):] + BinLineContent = BinLineContent[:BinLineContent.find(DT.TAB_COMMENT_SPLIT)] + if LineComment is None: + LineComment = InfLineCommentObject() + LineComment.SetTailComments(TailComments) + + # + # Find Macro + # + MacroDef = MacroParser((BinLineContent, BinLineNo), + FileName, + DT.MODEL_EFI_BINARY_FILE, + self.FileLocalMacros) + if MacroDef[0] is not None: + SectionMacros[MacroDef[0]] = MacroDef[1] + LineComment = None + HeaderComments = [] + continue + + # + # Replace with Local section Macro and [Defines] section Macro. + # + LineContent = InfExpandMacro(BinLineContent, + (FileName, BinLineContent, BinLineNo), + self.FileLocalMacros, + SectionMacros, True) + + AllSectionContent += LineContent + DT.END_OF_LINE + TokenList = GetSplitValueList(LineContent, DT.TAB_VALUE_SPLIT, 1) + ValueList[0:len(TokenList)] = TokenList + + # + # Should equal to UI/SEC_UI/UNI_UI + # + ValueList[0] = ValueList[0].strip() + if ValueList[0] == DT.BINARY_FILE_TYPE_UNI_UI or \ + ValueList[0] == DT.BINARY_FILE_TYPE_SEC_UI or \ + ValueList[0] == DT.BINARY_FILE_TYPE_UI: + if len(ValueList) == 2: + TokenList = GetSplitValueList(ValueList[1], + DT.TAB_VALUE_SPLIT, + 2) + NewValueList = [] + NewValueList.append(ValueList[0]) + for Item in TokenList: + NewValueList.append(Item) + UiBinaryList.append((NewValueList, + LineComment, + CurrentLineObj)) + # + # Should equal to VER/SEC_VER/UNI_VER + # + elif ValueList[0] == DT.BINARY_FILE_TYPE_UNI_VER or \ + ValueList[0] == DT.BINARY_FILE_TYPE_SEC_VER or \ + ValueList[0] == DT.BINARY_FILE_TYPE_VER: + if len(ValueList) == 2: + TokenList = GetSplitValueList(ValueList[1], + DT.TAB_VALUE_SPLIT, + 2) + NewValueList = [] + NewValueList.append(ValueList[0]) + for Item in TokenList: + NewValueList.append(Item) + VerBinaryList.append((NewValueList, + LineComment, + CurrentLineObj)) + else: + if len(ValueList) == 2: + if ValueList[0].strip() == 'SUBTYPE_GUID': + TokenList = GetSplitValueList(ValueList[1], + DT.TAB_VALUE_SPLIT, + 5) + else: + TokenList = GetSplitValueList(ValueList[1], + DT.TAB_VALUE_SPLIT, + 4) + + NewValueList = [] + NewValueList.append(ValueList[0]) + for Item in TokenList: + NewValueList.append(Item) + ComBinaryList.append((NewValueList, + LineComment, + CurrentLineObj)) + elif len(ValueList) == 1: + NewValueList = [] + NewValueList.append(ValueList[0]) + ComBinaryList.append((NewValueList, + LineComment, + CurrentLineObj)) + + + + + ValueList = [] + LineComment = None + TailComments = '' + HeaderComments = [] + continue + + # + # Current section archs + # + ArchList = [] + for Item in self.LastSectionHeaderContent: + if Item[1] not in ArchList: + ArchList.append(Item[1]) + InfSectionObject.SetSupArchList(Item[1]) + + InfSectionObject.SetAllContent(AllSectionContent) + if not InfSectionObject.SetBinary(UiBinaryList, + VerBinaryList, + ComBinaryList, + ArchList): + Logger.Error('InfParser', + FORMAT_INVALID, + ST.ERR_INF_PARSER_MODULE_SECTION_TYPE_ERROR%("[Binaries]"), + File=FileName, + Line=Item[3]) + diff --git a/src/VBox/Devices/EFI/Firmware/BaseTools/Source/Python/UPT/Parser/InfBuildOptionSectionParser.py b/src/VBox/Devices/EFI/Firmware/BaseTools/Source/Python/UPT/Parser/InfBuildOptionSectionParser.py new file mode 100755 index 00000000..3f74ff0c --- /dev/null +++ b/src/VBox/Devices/EFI/Firmware/BaseTools/Source/Python/UPT/Parser/InfBuildOptionSectionParser.py @@ -0,0 +1,212 @@ +## @file +# This file contained the parser for BuildOption sections in INF file +# +# Copyright (c) 2011 - 2018, Intel Corporation. All rights reserved.
+# +# SPDX-License-Identifier: BSD-2-Clause-Patent +# + +''' +InfBuildOptionSectionParser +''' +## +# Import Modules +# +from Library import DataType as DT +from Library import GlobalData +import Logger.Log as Logger +from Logger import StringTable as ST +from Logger.ToolError import FORMAT_INVALID +from Parser.InfParserMisc import InfExpandMacro +from Library.Misc import GetSplitValueList +from Parser.InfParserMisc import IsAsBuildOptionInfo +from Library.Misc import GetHelpStringByRemoveHashKey +from Library.ParserValidate import IsValidFamily +from Library.ParserValidate import IsValidBuildOptionName +from Parser.InfParserMisc import InfParserSectionRoot + +class InfBuildOptionSectionParser(InfParserSectionRoot): + ## InfBuildOptionParser + # + # + def InfBuildOptionParser(self, SectionString, InfSectionObject, FileName): + + BuildOptionList = [] + SectionContent = '' + + if not GlobalData.gIS_BINARY_INF: + ValueList = [] + LineNo = 0 + + for Line in SectionString: + LineContent = Line[0] + LineNo = Line[1] + TailComments = '' + ReplaceFlag = False + + if LineContent.strip() == '': + SectionContent += LineContent + DT.END_OF_LINE + continue + # + # Found Comment + # + if LineContent.strip().startswith(DT.TAB_COMMENT_SPLIT): + SectionContent += LineContent + DT.END_OF_LINE + continue + + # + # Find Tail comment. + # + if LineContent.find(DT.TAB_COMMENT_SPLIT) > -1: + TailComments = LineContent[LineContent.find(DT.TAB_COMMENT_SPLIT):] + LineContent = LineContent[:LineContent.find(DT.TAB_COMMENT_SPLIT)] + + TokenList = GetSplitValueList(LineContent, DT.TAB_DEQUAL_SPLIT, 1) + if len(TokenList) == 2: + # + # "Replace" type build option + # + TokenList.append('True') + ReplaceFlag = True + else: + TokenList = GetSplitValueList(LineContent, DT.TAB_EQUAL_SPLIT, 1) + # + # "Append" type build option + # + if len(TokenList) == 2: + TokenList.append('False') + else: + Logger.Error('InfParser', + FORMAT_INVALID, + ST.ERR_INF_PARSER_BUILD_OPTION_FORMAT_INVALID, + ExtraData=LineContent, + File=FileName, + Line=LineNo) + + ValueList[0:len(TokenList)] = TokenList + + # + # Replace with [Defines] section Macro + # + ValueList[0] = InfExpandMacro(ValueList[0], (FileName, LineContent, LineNo), + self.FileLocalMacros, None) + ValueList[1] = InfExpandMacro(ValueList[1], (FileName, LineContent, LineNo), + self.FileLocalMacros, None, True) + EqualString = '' + if not ReplaceFlag: + EqualString = ' = ' + else: + EqualString = ' == ' + + SectionContent += ValueList[0] + EqualString + ValueList[1] + TailComments + DT.END_OF_LINE + + Family = GetSplitValueList(ValueList[0], DT.TAB_COLON_SPLIT, 1) + if len(Family) == 2: + if not IsValidFamily(Family[0]): + Logger.Error('InfParser', + FORMAT_INVALID, + ST.ERR_INF_PARSER_BUILD_OPTION_FORMAT_INVALID, + ExtraData=LineContent, + File=FileName, + Line=LineNo) + if not IsValidBuildOptionName(Family[1]): + Logger.Error('InfParser', + FORMAT_INVALID, + ST.ERR_INF_PARSER_BUILD_OPTION_FORMAT_INVALID, + ExtraData=LineContent, + File=FileName, + Line=LineNo) + if len(Family) == 1: + if not IsValidBuildOptionName(Family[0]): + Logger.Error('InfParser', + FORMAT_INVALID, + ST.ERR_INF_PARSER_BUILD_OPTION_FORMAT_INVALID, + ExtraData=LineContent, + File=FileName, + Line=LineNo) + + BuildOptionList.append(ValueList) + ValueList = [] + continue + else: + BuildOptionList = InfAsBuiltBuildOptionParser(SectionString, FileName) + + # + # Current section archs + # + ArchList = [] + LastItem = '' + for Item in self.LastSectionHeaderContent: + LastItem = Item + if not (Item[1] == '' or Item[1] == '') and Item[1] not in ArchList: + ArchList.append(Item[1]) + InfSectionObject.SetSupArchList(Item[1]) + + InfSectionObject.SetAllContent(SectionContent) + if not InfSectionObject.SetBuildOptions(BuildOptionList, ArchList, SectionContent): + Logger.Error('InfParser', + FORMAT_INVALID, + ST.ERR_INF_PARSER_MODULE_SECTION_TYPE_ERROR%("[BuilOptions]"), + File=FileName, + Line=LastItem[3]) + +## InfBuildOptionParser +# +# +def InfAsBuiltBuildOptionParser(SectionString, FileName): + BuildOptionList = [] + # + # AsBuild Binary INF file. + # + AsBuildOptionFlag = False + BuildOptionItem = [] + Count = 0 + for Line in SectionString: + Count += 1 + LineContent = Line[0] + LineNo = Line[1] + + # + # The last line + # + if len(SectionString) == Count: + if LineContent.strip().startswith("##") and AsBuildOptionFlag: + BuildOptionList.append(BuildOptionItem) + BuildOptionList.append([GetHelpStringByRemoveHashKey(LineContent)]) + elif LineContent.strip().startswith("#") and AsBuildOptionFlag: + BuildOptionInfo = GetHelpStringByRemoveHashKey(LineContent) + BuildOptionItem.append(BuildOptionInfo) + BuildOptionList.append(BuildOptionItem) + else: + if len(BuildOptionItem) > 0: + BuildOptionList.append(BuildOptionItem) + + break + + if LineContent.strip() == '': + AsBuildOptionFlag = False + continue + + if LineContent.strip().startswith("##") and AsBuildOptionFlag: + if len(BuildOptionItem) > 0: + BuildOptionList.append(BuildOptionItem) + + BuildOptionItem = [] + + if not LineContent.strip().startswith("#"): + Logger.Error('InfParser', + FORMAT_INVALID, + ST.ERR_BO_CONTATIN_ASBUILD_AND_COMMON, + File=FileName, + Line=LineNo, + ExtraData=LineContent) + + if IsAsBuildOptionInfo(LineContent): + AsBuildOptionFlag = True + continue + + if AsBuildOptionFlag: + BuildOptionInfo = GetHelpStringByRemoveHashKey(LineContent) + BuildOptionItem.append(BuildOptionInfo) + + return BuildOptionList diff --git a/src/VBox/Devices/EFI/Firmware/BaseTools/Source/Python/UPT/Parser/InfDefineSectionParser.py b/src/VBox/Devices/EFI/Firmware/BaseTools/Source/Python/UPT/Parser/InfDefineSectionParser.py new file mode 100755 index 00000000..2117da1c --- /dev/null +++ b/src/VBox/Devices/EFI/Firmware/BaseTools/Source/Python/UPT/Parser/InfDefineSectionParser.py @@ -0,0 +1,191 @@ +## @file +# This file contained the parser for define sections in INF file +# +# Copyright (c) 2011 - 2018, Intel Corporation. All rights reserved.
+# +# SPDX-License-Identifier: BSD-2-Clause-Patent +# + +''' +InfDefineSectionParser +''' +## +# Import Modules +# +import re + +from Library import DataType as DT +from Library import GlobalData +from Library.Parsing import MacroParser +from Library.Misc import GetSplitValueList +from Library.ParserValidate import IsValidArch +from Object.Parser.InfCommonObject import InfLineCommentObject +from Object.Parser.InfDefineObject import InfDefMember +from Parser.InfParserMisc import InfExpandMacro +from Object.Parser.InfMisc import ErrorInInf +from Logger import StringTable as ST +from Parser.InfParserMisc import InfParserSectionRoot + +## __GetValidateArchList +# +# +def GetValidateArchList(LineContent): + + TempArch = '' + ArchList = [] + ValidateAcrhPatten = re.compile(r"^\s*#\s*VALID_ARCHITECTURES\s*=\s*.*$", re.DOTALL) + + if ValidateAcrhPatten.match(LineContent): + TempArch = GetSplitValueList(LineContent, DT.TAB_EQUAL_SPLIT, 1)[1] + + TempArch = GetSplitValueList(TempArch, '(', 1)[0] + + ArchList = re.split('\s+', TempArch) + NewArchList = [] + for Arch in ArchList: + if IsValidArch(Arch): + NewArchList.append(Arch) + + ArchList = NewArchList + + return ArchList + +class InfDefinSectionParser(InfParserSectionRoot): + def InfDefineParser(self, SectionString, InfSectionObject, FileName, SectionComment): + + if SectionComment: + pass + # + # Parser Defines section content and fill self._ContentList dict. + # + StillCommentFalg = False + HeaderComments = [] + SectionContent = '' + ArchList = [] + _ContentList = [] + _ValueList = [] + # + # Add WORKSPACE to global Marco dict. + # + self.FileLocalMacros['WORKSPACE'] = GlobalData.gWORKSPACE + + for Line in SectionString: + LineContent = Line[0] + LineNo = Line[1] + TailComments = '' + LineComment = None + + LineInfo = ['', -1, ''] + LineInfo[0] = FileName + LineInfo[1] = LineNo + LineInfo[2] = LineContent + + if LineContent.strip() == '': + continue + # + # The first time encountered VALIDATE_ARCHITECHERS will be considered as support arch list. + # + if not ArchList: + ArchList = GetValidateArchList(LineContent) + + # + # Parser Comment + # + if LineContent.strip().startswith(DT.TAB_COMMENT_SPLIT): + # + # Last line is comments, and this line go on. + # + if StillCommentFalg: + HeaderComments.append(Line) + SectionContent += LineContent + DT.END_OF_LINE + continue + # + # First time encounter comment + # + else: + # + # Clear original data + # + HeaderComments = [] + HeaderComments.append(Line) + StillCommentFalg = True + SectionContent += LineContent + DT.END_OF_LINE + continue + else: + StillCommentFalg = False + + if len(HeaderComments) >= 1: + LineComment = InfLineCommentObject() + LineCommentContent = '' + for Item in HeaderComments: + LineCommentContent += Item[0] + DT.END_OF_LINE + LineComment.SetHeaderComments(LineCommentContent) + + # + # Find Tail comment. + # + if LineContent.find(DT.TAB_COMMENT_SPLIT) > -1: + TailComments = LineContent[LineContent.find(DT.TAB_COMMENT_SPLIT):] + LineContent = LineContent[:LineContent.find(DT.TAB_COMMENT_SPLIT)] + if LineComment is None: + LineComment = InfLineCommentObject() + LineComment.SetTailComments(TailComments) + + # + # Find Macro + # + Name, Value = MacroParser((LineContent, LineNo), + FileName, + DT.MODEL_META_DATA_HEADER, + self.FileLocalMacros) + if Name is not None: + self.FileLocalMacros[Name] = Value + continue + + # + # Replace with [Defines] section Macro + # + LineContent = InfExpandMacro(LineContent, + (FileName, LineContent, LineNo), + self.FileLocalMacros, + None, True) + + SectionContent += LineContent + DT.END_OF_LINE + + TokenList = GetSplitValueList(LineContent, DT.TAB_EQUAL_SPLIT, 1) + if len(TokenList) < 2: + ErrorInInf(ST.ERR_INF_PARSER_DEFINE_ITEM_NO_VALUE, + LineInfo=LineInfo) + _ValueList[0:len(TokenList)] = TokenList + if not _ValueList[0]: + ErrorInInf(ST.ERR_INF_PARSER_DEFINE_ITEM_NO_NAME, + LineInfo=LineInfo) + if not _ValueList[1]: + ErrorInInf(ST.ERR_INF_PARSER_DEFINE_ITEM_NO_VALUE, + LineInfo=LineInfo) + + Name, Value = _ValueList[0], _ValueList[1] + + InfDefMemberObj = InfDefMember(Name, Value) + if (LineComment is not None): + InfDefMemberObj.Comments.SetHeaderComments(LineComment.GetHeaderComments()) + InfDefMemberObj.Comments.SetTailComments(LineComment.GetTailComments()) + + InfDefMemberObj.CurrentLine.SetFileName(self.FullPath) + InfDefMemberObj.CurrentLine.SetLineString(LineContent) + InfDefMemberObj.CurrentLine.SetLineNo(LineNo) + + _ContentList.append(InfDefMemberObj) + HeaderComments = [] + TailComments = '' + + # + # Current Define section archs + # + if not ArchList: + ArchList = ['COMMON'] + + InfSectionObject.SetAllContent(SectionContent) + + InfSectionObject.SetDefines(_ContentList, Arch=ArchList) + diff --git a/src/VBox/Devices/EFI/Firmware/BaseTools/Source/Python/UPT/Parser/InfDepexSectionParser.py b/src/VBox/Devices/EFI/Firmware/BaseTools/Source/Python/UPT/Parser/InfDepexSectionParser.py new file mode 100755 index 00000000..86634b32 --- /dev/null +++ b/src/VBox/Devices/EFI/Firmware/BaseTools/Source/Python/UPT/Parser/InfDepexSectionParser.py @@ -0,0 +1,98 @@ +## @file +# This file contained the parser for [Depex] sections in INF file +# +# Copyright (c) 2011 - 2018, Intel Corporation. All rights reserved.
+# +# SPDX-License-Identifier: BSD-2-Clause-Patent +# +''' +InfDepexSectionParser +''' +## +# Import Modules +# +import re +import Logger.Log as Logger +from Logger import StringTable as ST +from Logger.ToolError import FORMAT_INVALID +from Parser.InfParserMisc import InfExpandMacro +from Library import DataType as DT +from Library.Misc import GetSplitValueList +from Parser.InfParserMisc import InfParserSectionRoot + +class InfDepexSectionParser(InfParserSectionRoot): + ## InfDepexParser + # + # For now, only separate Depex String and comments. + # Have two types of section header. + # 1. [Depex.Arch.ModuleType, ...] + # 2. [Depex.Arch|FFE, ...] + # + def InfDepexParser(self, SectionString, InfSectionObject, FileName): + DepexContent = [] + DepexComment = [] + ValueList = [] + # + # Parse section content + # + for Line in SectionString: + LineContent = Line[0] + LineNo = Line[1] + + # + # Found comment + # + if LineContent.strip().startswith(DT.TAB_COMMENT_SPLIT): + DepexComment.append((LineContent, LineNo)) + continue + # + # Replace with [Defines] section Macro + # + LineContent = InfExpandMacro(LineContent, + (FileName, LineContent, Line[1]), + self.FileLocalMacros, + None, True) + + CommentCount = LineContent.find(DT.TAB_COMMENT_SPLIT) + + if CommentCount > -1: + DepexComment.append((LineContent[CommentCount:], LineNo)) + LineContent = LineContent[:CommentCount-1] + + + CommentCount = -1 + DepexContent.append((LineContent, LineNo)) + + TokenList = GetSplitValueList(LineContent, DT.TAB_COMMENT_SPLIT) + ValueList[0:len(TokenList)] = TokenList + + # + # Current section archs + # + KeyList = [] + LastItem = '' + for Item in self.LastSectionHeaderContent: + LastItem = Item + if (Item[1], Item[2], Item[3]) not in KeyList: + KeyList.append((Item[1], Item[2], Item[3])) + + NewCommentList = [] + FormatCommentLn = -1 + ReFormatComment = re.compile(r"""#(?:\s*)\[(.*?)\](?:.*)""", re.DOTALL) + for CommentItem in DepexComment: + CommentContent = CommentItem[0] + if ReFormatComment.match(CommentContent) is not None: + FormatCommentLn = CommentItem[1] + 1 + continue + + if CommentItem[1] != FormatCommentLn: + NewCommentList.append(CommentContent) + else: + FormatCommentLn = CommentItem[1] + 1 + + if not InfSectionObject.SetDepex(DepexContent, KeyList = KeyList, CommentList = NewCommentList): + Logger.Error('InfParser', + FORMAT_INVALID, + ST.ERR_INF_PARSER_MODULE_SECTION_TYPE_ERROR%("[Depex]"), + File=FileName, + Line=LastItem[3]) diff --git a/src/VBox/Devices/EFI/Firmware/BaseTools/Source/Python/UPT/Parser/InfGuidPpiProtocolSectionParser.py b/src/VBox/Devices/EFI/Firmware/BaseTools/Source/Python/UPT/Parser/InfGuidPpiProtocolSectionParser.py new file mode 100755 index 00000000..2716f8d7 --- /dev/null +++ b/src/VBox/Devices/EFI/Firmware/BaseTools/Source/Python/UPT/Parser/InfGuidPpiProtocolSectionParser.py @@ -0,0 +1,368 @@ +## @file +# This file contained the parser for [Guids], [Ppis], [Protocols] sections in INF file +# +# Copyright (c) 2011 - 2018, Intel Corporation. All rights reserved.
+# +# SPDX-License-Identifier: BSD-2-Clause-Patent +# +''' +InfGuidPpiProtocolSectionParser +''' +## +# Import Modules +# + +import Logger.Log as Logger +from Logger import StringTable as ST +from Logger.ToolError import FORMAT_INVALID +from Parser.InfParserMisc import InfExpandMacro +from Library import DataType as DT +from Library import GlobalData +from Library.Parsing import MacroParser +from Library.Misc import GetSplitValueList +from Library.ParserValidate import IsValidIdString +from Library.ParserValidate import IsValidUserId +from Library.ParserValidate import IsValidArch +from Parser.InfParserMisc import InfParserSectionRoot + +class InfGuidPpiProtocolSectionParser(InfParserSectionRoot): + ## InfGuidParser + # + # + def InfGuidParser(self, SectionString, InfSectionObject, FileName): + # + # Macro defined in this section + # + SectionMacros = {} + ValueList = [] + GuidList = [] + CommentsList = [] + CurrentLineVar = None + # + # Parse section content + # + for Line in SectionString: + LineContent = Line[0] + LineNo = Line[1] + + if LineContent.strip() == '': + CommentsList = [] + continue + + if LineContent.strip().startswith(DT.TAB_COMMENT_SPLIT): + CommentsList.append(Line) + continue + else: + # + # Encounter a GUID entry + # + if LineContent.find(DT.TAB_COMMENT_SPLIT) > -1: + CommentsList.append(( + LineContent[LineContent.find(DT.TAB_COMMENT_SPLIT):], + LineNo)) + LineContent = \ + LineContent[:LineContent.find(DT.TAB_COMMENT_SPLIT)] + + if LineContent != '': + # + # Find Macro + # + Name, Value = MacroParser((LineContent, LineNo), + FileName, + DT.MODEL_EFI_GUID, + self.FileLocalMacros) + if Name is not None: + SectionMacros[Name] = Value + CommentsList = [] + ValueList = [] + continue + + TokenList = GetSplitValueList(LineContent, DT.TAB_VALUE_SPLIT, 1) + ValueList[0:len(TokenList)] = TokenList + + # + # Replace with Local section Macro and [Defines] section Macro. + # + ValueList = [InfExpandMacro(Value, (FileName, LineContent, LineNo), + self.FileLocalMacros, SectionMacros, True) + for Value in ValueList] + + CurrentLineVar = (LineContent, LineNo, FileName) + + + if len(ValueList) >= 1: + GuidList.append((ValueList, CommentsList, CurrentLineVar)) + CommentsList = [] + ValueList = [] + continue + + # + # Current section archs + # + ArchList = [] + LineIndex = -1 + for Item in self.LastSectionHeaderContent: + LineIndex = Item[3] + if Item[1] not in ArchList: + ArchList.append(Item[1]) + + if not InfSectionObject.SetGuid(GuidList, Arch=ArchList): + Logger.Error('InfParser', + FORMAT_INVALID, + ST.ERR_INF_PARSER_MODULE_SECTION_TYPE_ERROR % ("[Guid]"), + File=FileName, + Line=LineIndex) + + ## InfPpiParser + # + # + def InfPpiParser(self, SectionString, InfSectionObject, FileName): + # + # Macro defined in this section + # + SectionMacros = {} + ValueList = [] + PpiList = [] + CommentsList = [] + CurrentLineVar = None + # + # Parse section content + # + for Line in SectionString: + LineContent = Line[0] + LineNo = Line[1] + + if LineContent.strip() == '': + CommentsList = [] + continue + + if LineContent.strip().startswith(DT.TAB_COMMENT_SPLIT): + CommentsList.append(Line) + continue + else: + # + # Encounter a PPI entry + # + if LineContent.find(DT.TAB_COMMENT_SPLIT) > -1: + CommentsList.append(( + LineContent[LineContent.find(DT.TAB_COMMENT_SPLIT):], + LineNo)) + LineContent = \ + LineContent[:LineContent.find(DT.TAB_COMMENT_SPLIT)] + + if LineContent != '': + # + # Find Macro + # + Name, Value = MacroParser((LineContent, LineNo), + FileName, + DT.MODEL_EFI_PPI, + self.FileLocalMacros) + if Name is not None: + SectionMacros[Name] = Value + ValueList = [] + CommentsList = [] + continue + + TokenList = GetSplitValueList(LineContent, DT.TAB_VALUE_SPLIT, 1) + ValueList[0:len(TokenList)] = TokenList + + # + # Replace with Local section Macro and [Defines] section Macro. + # + ValueList = [InfExpandMacro(Value, (FileName, LineContent, LineNo), self.FileLocalMacros, SectionMacros) + for Value in ValueList] + + CurrentLineVar = (LineContent, LineNo, FileName) + + if len(ValueList) >= 1: + PpiList.append((ValueList, CommentsList, CurrentLineVar)) + ValueList = [] + CommentsList = [] + continue + + # + # Current section archs + # + ArchList = [] + LineIndex = -1 + for Item in self.LastSectionHeaderContent: + LineIndex = Item[3] + if Item[1] not in ArchList: + ArchList.append(Item[1]) + + if not InfSectionObject.SetPpi(PpiList, Arch=ArchList): + Logger.Error('InfParser', + FORMAT_INVALID, + ST.ERR_INF_PARSER_MODULE_SECTION_TYPE_ERROR % ("[Ppis]"), + File=FileName, + Line=LineIndex) + + ## InfUserExtensionParser + # + # + def InfUserExtensionParser(self, SectionString, InfSectionObject, FileName): + + UserExtensionContent = '' + + # + # Parse section content + # + for Line in SectionString: + LineContent = Line[0] + +# Comment the code to support user extension without any statement just the section header in [] +# if LineContent.strip() == '': +# continue + + UserExtensionContent += LineContent + DT.END_OF_LINE + continue + + # + # Current section UserId, IdString + # + IdContentList = [] + LastItem = '' + SectionLineNo = None + for Item in self.LastSectionHeaderContent: + UserId = Item[1] + IdString = Item[2] + Arch = Item[3] + SectionLineNo = Item[4] + if not IsValidArch(Arch): + Logger.Error( + 'InfParser', + FORMAT_INVALID, + ST.ERR_INF_PARSER_DEFINE_FROMAT_INVALID % (Arch), + File=GlobalData.gINF_MODULE_NAME, + Line=SectionLineNo, + ExtraData=None) + + if (UserId, IdString, Arch) not in IdContentList: + # + # To check the UserId and IdString valid or not. + # + if not IsValidUserId(UserId): + Logger.Error('InfParser', + FORMAT_INVALID, + ST.ERR_INF_PARSER_UE_SECTION_USER_ID_ERROR % (Item[1]), + File=GlobalData.gINF_MODULE_NAME, + Line=SectionLineNo, + ExtraData=None) + + if not IsValidIdString(IdString): + Logger.Error('InfParser', + FORMAT_INVALID, + ST.ERR_INF_PARSER_UE_SECTION_ID_STRING_ERROR % (IdString), + File=GlobalData.gINF_MODULE_NAME, Line=SectionLineNo, + ExtraData=None) + IdContentList.append((UserId, IdString, Arch)) + else: + # + # Each UserExtensions section header must have a unique set + # of UserId, IdString and Arch values. + # This means that the same UserId can be used in more than one + # section header, provided the IdString or Arch values are + # different. The same IdString values can be used in more than + # one section header if the UserId or Arch values are + # different. The same UserId and the same IdString can be used + # in a section header if the Arch values are different in each + # of the section headers. + # + Logger.Error('InfParser', + FORMAT_INVALID, + ST.ERR_INF_PARSER_UE_SECTION_DUPLICATE_ERROR % ( + IdString), + File=GlobalData.gINF_MODULE_NAME, + Line=SectionLineNo, + ExtraData=None) + LastItem = Item + + if not InfSectionObject.SetUserExtension(UserExtensionContent, + IdContent=IdContentList, + LineNo=SectionLineNo): + Logger.Error\ + ('InfParser', FORMAT_INVALID, \ + ST.ERR_INF_PARSER_MODULE_SECTION_TYPE_ERROR % ("[UserExtension]"), \ + File=FileName, Line=LastItem[4]) + + def InfProtocolParser(self, SectionString, InfSectionObject, FileName): + # + # Macro defined in this section + # + SectionMacros = {} + ValueList = [] + ProtocolList = [] + CommentsList = [] + CurrentLineVar = None + # + # Parse section content + # + for Line in SectionString: + LineContent = Line[0] + LineNo = Line[1] + + if LineContent.strip() == '': + CommentsList = [] + continue + + if LineContent.strip().startswith(DT.TAB_COMMENT_SPLIT): + CommentsList.append(Line) + continue + else: + # + # Encounter a Protocol entry + # + if LineContent.find(DT.TAB_COMMENT_SPLIT) > -1: + CommentsList.append(( + LineContent[LineContent.find(DT.TAB_COMMENT_SPLIT):], + LineNo)) + LineContent = \ + LineContent[:LineContent.find(DT.TAB_COMMENT_SPLIT)] + + if LineContent != '': + # + # Find Macro + # + Name, Value = MacroParser((LineContent, LineNo), + FileName, + DT.MODEL_EFI_PROTOCOL, + self.FileLocalMacros) + if Name is not None: + SectionMacros[Name] = Value + ValueList = [] + CommentsList = [] + continue + + TokenList = GetSplitValueList(LineContent, DT.TAB_VALUE_SPLIT, 1) + ValueList[0:len(TokenList)] = TokenList + + # + # Replace with Local section Macro and [Defines] section Macro. + # + ValueList = [InfExpandMacro(Value, (FileName, LineContent, LineNo), self.FileLocalMacros, SectionMacros) + for Value in ValueList] + + CurrentLineVar = (LineContent, LineNo, FileName) + + if len(ValueList) >= 1: + ProtocolList.append((ValueList, CommentsList, CurrentLineVar)) + ValueList = [] + CommentsList = [] + continue + + # + # Current section archs + # + ArchList = [] + LineIndex = -1 + for Item in self.LastSectionHeaderContent: + LineIndex = Item[3] + if Item[1] not in ArchList: + ArchList.append(Item[1]) + + if not InfSectionObject.SetProtocol(ProtocolList, Arch=ArchList): + Logger.Error\ + ('InfParser', FORMAT_INVALID, \ + ST.ERR_INF_PARSER_MODULE_SECTION_TYPE_ERROR % ("[Protocol]"), \ + File=FileName, Line=LineIndex) diff --git a/src/VBox/Devices/EFI/Firmware/BaseTools/Source/Python/UPT/Parser/InfLibrarySectionParser.py b/src/VBox/Devices/EFI/Firmware/BaseTools/Source/Python/UPT/Parser/InfLibrarySectionParser.py new file mode 100755 index 00000000..66fae2af --- /dev/null +++ b/src/VBox/Devices/EFI/Firmware/BaseTools/Source/Python/UPT/Parser/InfLibrarySectionParser.py @@ -0,0 +1,197 @@ +## @file +# This file contained the parser for [Libraries] sections in INF file +# +# Copyright (c) 2011 - 2018, Intel Corporation. All rights reserved.
+# +# SPDX-License-Identifier: BSD-2-Clause-Patent +# +''' +InfLibrarySectionParser +''' +## +# Import Modules +# + +import Logger.Log as Logger +from Logger import StringTable as ST +from Logger.ToolError import FORMAT_INVALID +from Parser.InfParserMisc import InfExpandMacro +from Library import DataType as DT +from Library.Parsing import MacroParser +from Library.Misc import GetSplitValueList +from Object.Parser.InfCommonObject import InfLineCommentObject +from Library import GlobalData +from Parser.InfParserMisc import IsLibInstanceInfo +from Parser.InfAsBuiltProcess import GetLibInstanceInfo +from Parser.InfParserMisc import InfParserSectionRoot + +class InfLibrarySectionParser(InfParserSectionRoot): + ## InfLibraryParser + # + # + def InfLibraryParser(self, SectionString, InfSectionObject, FileName): + # + # For Common INF file + # + if not GlobalData.gIS_BINARY_INF: + # + # Macro defined in this section + # + SectionMacros = {} + ValueList = [] + LibraryList = [] + LibStillCommentFalg = False + LibHeaderComments = [] + LibLineComment = None + # + # Parse section content + # + for Line in SectionString: + LibLineContent = Line[0] + LibLineNo = Line[1] + + if LibLineContent.strip() == '': + continue + + # + # Found Header Comments + # + if LibLineContent.strip().startswith(DT.TAB_COMMENT_SPLIT): + # + # Last line is comments, and this line go on. + # + if LibStillCommentFalg: + LibHeaderComments.append(Line) + continue + # + # First time encounter comment + # + else: + # + # Clear original data + # + LibHeaderComments = [] + LibHeaderComments.append(Line) + LibStillCommentFalg = True + continue + else: + LibStillCommentFalg = False + + if len(LibHeaderComments) >= 1: + LibLineComment = InfLineCommentObject() + LineCommentContent = '' + for Item in LibHeaderComments: + LineCommentContent += Item[0] + DT.END_OF_LINE + LibLineComment.SetHeaderComments(LineCommentContent) + + # + # Find Tail comment. + # + if LibLineContent.find(DT.TAB_COMMENT_SPLIT) > -1: + LibTailComments = LibLineContent[LibLineContent.find(DT.TAB_COMMENT_SPLIT):] + LibLineContent = LibLineContent[:LibLineContent.find(DT.TAB_COMMENT_SPLIT)] + if LibLineComment is None: + LibLineComment = InfLineCommentObject() + LibLineComment.SetTailComments(LibTailComments) + + # + # Find Macro + # + Name, Value = MacroParser((LibLineContent, LibLineNo), + FileName, + DT.MODEL_EFI_LIBRARY_CLASS, + self.FileLocalMacros) + if Name is not None: + SectionMacros[Name] = Value + LibLineComment = None + LibHeaderComments = [] + continue + + TokenList = GetSplitValueList(LibLineContent, DT.TAB_VALUE_SPLIT, 1) + ValueList[0:len(TokenList)] = TokenList + + # + # Replace with Local section Macro and [Defines] section Macro. + # + ValueList = [InfExpandMacro(Value, (FileName, LibLineContent, LibLineNo), + self.FileLocalMacros, SectionMacros, True) + for Value in ValueList] + + LibraryList.append((ValueList, LibLineComment, + (LibLineContent, LibLineNo, FileName))) + ValueList = [] + LibLineComment = None + LibTailComments = '' + LibHeaderComments = [] + + continue + + # + # Current section archs + # + KeyList = [] + for Item in self.LastSectionHeaderContent: + if (Item[1], Item[2]) not in KeyList: + KeyList.append((Item[1], Item[2])) + + if not InfSectionObject.SetLibraryClasses(LibraryList, KeyList=KeyList): + Logger.Error('InfParser', + FORMAT_INVALID, + ST.ERR_INF_PARSER_MODULE_SECTION_TYPE_ERROR % ("[Library]"), + File=FileName, + Line=Item[3]) + # + # For Binary INF + # + else: + self.InfAsBuiltLibraryParser(SectionString, InfSectionObject, FileName) + + def InfAsBuiltLibraryParser(self, SectionString, InfSectionObject, FileName): + LibraryList = [] + LibInsFlag = False + for Line in SectionString: + LineContent = Line[0] + LineNo = Line[1] + + if LineContent.strip() == '': + LibInsFlag = False + continue + + if not LineContent.strip().startswith("#"): + Logger.Error('InfParser', + FORMAT_INVALID, + ST.ERR_LIB_CONTATIN_ASBUILD_AND_COMMON, + File=FileName, + Line=LineNo, + ExtraData=LineContent) + + if IsLibInstanceInfo(LineContent): + LibInsFlag = True + continue + + if LibInsFlag: + LibGuid, LibVer = GetLibInstanceInfo(LineContent, GlobalData.gWORKSPACE, LineNo, FileName) + # + # If the VERSION_STRING is missing from the INF file, tool should default to "0". + # + if LibVer == '': + LibVer = '0' + if LibGuid != '': + if (LibGuid, LibVer) not in LibraryList: + LibraryList.append((LibGuid, LibVer)) + + # + # Current section archs + # + KeyList = [] + Item = ['', '', ''] + for Item in self.LastSectionHeaderContent: + if (Item[1], Item[2]) not in KeyList: + KeyList.append((Item[1], Item[2])) + + if not InfSectionObject.SetLibraryClasses(LibraryList, KeyList=KeyList): + Logger.Error('InfParser', + FORMAT_INVALID, + ST.ERR_INF_PARSER_MODULE_SECTION_TYPE_ERROR % ("[Library]"), + File=FileName, + Line=Item[3]) diff --git a/src/VBox/Devices/EFI/Firmware/BaseTools/Source/Python/UPT/Parser/InfPackageSectionParser.py b/src/VBox/Devices/EFI/Firmware/BaseTools/Source/Python/UPT/Parser/InfPackageSectionParser.py new file mode 100755 index 00000000..bb6777e8 --- /dev/null +++ b/src/VBox/Devices/EFI/Firmware/BaseTools/Source/Python/UPT/Parser/InfPackageSectionParser.py @@ -0,0 +1,134 @@ +## @file +# This file contained the parser for [Packages] sections in INF file +# +# Copyright (c) 2011 - 2018, Intel Corporation. All rights reserved.
+# +# SPDX-License-Identifier: BSD-2-Clause-Patent +# +''' +InfPackageSectionParser +''' +## +# Import Modules +# + +import Logger.Log as Logger +from Logger import StringTable as ST +from Logger.ToolError import FORMAT_INVALID +from Parser.InfParserMisc import InfExpandMacro +from Library import DataType as DT +from Library.Parsing import MacroParser +from Library.Misc import GetSplitValueList +from Object.Parser.InfCommonObject import InfLineCommentObject +from Parser.InfParserMisc import InfParserSectionRoot + +class InfPackageSectionParser(InfParserSectionRoot): + ## InfPackageParser + # + # + def InfPackageParser(self, SectionString, InfSectionObject, FileName): + # + # Macro defined in this section + # + SectionMacros = {} + ValueList = [] + PackageList = [] + StillCommentFalg = False + HeaderComments = [] + LineComment = None + # + # Parse section content + # + for Line in SectionString: + PkgLineContent = Line[0] + PkgLineNo = Line[1] + + if PkgLineContent.strip() == '': + continue + + # + # Find Header Comments + # + if PkgLineContent.strip().startswith(DT.TAB_COMMENT_SPLIT): + # + # Last line is comments, and this line go on. + # + if StillCommentFalg: + HeaderComments.append(Line) + continue + # + # First time encounter comment + # + else: + # + # Clear original data + # + HeaderComments = [] + HeaderComments.append(Line) + StillCommentFalg = True + continue + else: + StillCommentFalg = False + + if len(HeaderComments) >= 1: + LineComment = InfLineCommentObject() + LineCommentContent = '' + for Item in HeaderComments: + LineCommentContent += Item[0] + DT.END_OF_LINE + LineComment.SetHeaderComments(LineCommentContent) + + # + # Find Tail comment. + # + if PkgLineContent.find(DT.TAB_COMMENT_SPLIT) > -1: + TailComments = PkgLineContent[PkgLineContent.find(DT.TAB_COMMENT_SPLIT):] + PkgLineContent = PkgLineContent[:PkgLineContent.find(DT.TAB_COMMENT_SPLIT)] + if LineComment is None: + LineComment = InfLineCommentObject() + LineComment.SetTailComments(TailComments) + # + # Find Macro + # + Name, Value = MacroParser((PkgLineContent, PkgLineNo), + FileName, + DT.MODEL_META_DATA_PACKAGE, + self.FileLocalMacros) + if Name is not None: + SectionMacros[Name] = Value + LineComment = None + HeaderComments = [] + continue + + TokenList = GetSplitValueList(PkgLineContent, DT.TAB_VALUE_SPLIT, 1) + ValueList[0:len(TokenList)] = TokenList + + # + # Replace with Local section Macro and [Defines] section Macro. + # + ValueList = [InfExpandMacro(Value, (FileName, PkgLineContent, PkgLineNo), + self.FileLocalMacros, SectionMacros, True) + for Value in ValueList] + + PackageList.append((ValueList, LineComment, + (PkgLineContent, PkgLineNo, FileName))) + ValueList = [] + LineComment = None + TailComments = '' + HeaderComments = [] + continue + + # + # Current section archs + # + ArchList = [] + for Item in self.LastSectionHeaderContent: + if Item[1] not in ArchList: + ArchList.append(Item[1]) + + if not InfSectionObject.SetPackages(PackageList, Arch = ArchList): + Logger.Error('InfParser', + FORMAT_INVALID, + ST.ERR_INF_PARSER_MODULE_SECTION_TYPE_ERROR\ + %("[Packages]"), + File=FileName, + Line=Item[3]) diff --git a/src/VBox/Devices/EFI/Firmware/BaseTools/Source/Python/UPT/Parser/InfParser.py b/src/VBox/Devices/EFI/Firmware/BaseTools/Source/Python/UPT/Parser/InfParser.py new file mode 100755 index 00000000..711b5e85 --- /dev/null +++ b/src/VBox/Devices/EFI/Firmware/BaseTools/Source/Python/UPT/Parser/InfParser.py @@ -0,0 +1,680 @@ +## @file +# This file contained the parser for INF file +# +# Copyright (c) 2011 - 2018, Intel Corporation. All rights reserved.
+# +# SPDX-License-Identifier: BSD-2-Clause-Patent +# + +''' +InfParser +''' + +## +# Import Modules +# +import re +import os +from copy import deepcopy + +from Library.StringUtils import GetSplitValueList +from Library.StringUtils import ConvertSpecialChar +from Library.Misc import ProcessLineExtender +from Library.Misc import ProcessEdkComment +from Library.Parsing import NormPath +from Library.ParserValidate import IsValidInfMoudleTypeList +from Library.ParserValidate import IsValidArch +from Library import DataType as DT +from Library import GlobalData + +import Logger.Log as Logger +from Logger import StringTable as ST +from Logger.ToolError import FORMAT_INVALID +from Logger.ToolError import FILE_READ_FAILURE +from Logger.ToolError import PARSER_ERROR + +from Object.Parser.InfCommonObject import InfSectionCommonDef +from Parser.InfSectionParser import InfSectionParser +from Parser.InfParserMisc import gINF_SECTION_DEF +from Parser.InfParserMisc import IsBinaryInf + +## OpenInfFile +# +# +def OpenInfFile(Filename): + FileLinesList = [] + + try: + FInputfile = open(Filename, "r") + try: + FileLinesList = FInputfile.readlines() + except BaseException: + Logger.Error("InfParser", + FILE_READ_FAILURE, + ST.ERR_FILE_OPEN_FAILURE, + File=Filename) + finally: + FInputfile.close() + except BaseException: + Logger.Error("InfParser", + FILE_READ_FAILURE, + ST.ERR_FILE_OPEN_FAILURE, + File=Filename) + + return FileLinesList + +## InfParser +# +# This class defined the structure used in InfParser object +# +# @param InfObject: Inherited from InfSectionParser class +# @param Filename: Input value for Filename of INF file, default is +# None +# @param WorkspaceDir: Input value for current workspace directory, +# default is None +# +class InfParser(InfSectionParser): + + def __init__(self, Filename = None, WorkspaceDir = None): + + # + # Call parent class construct function + # + InfSectionParser.__init__() + + self.WorkspaceDir = WorkspaceDir + self.SupArchList = DT.ARCH_LIST + self.EventList = [] + self.HobList = [] + self.BootModeList = [] + + # + # Load Inf file if filename is not None + # + if Filename is not None: + self.ParseInfFile(Filename) + + ## Parse INF file + # + # Parse the file if it exists + # + # @param Filename: Input value for filename of INF file + # + def ParseInfFile(self, Filename): + + Filename = NormPath(Filename) + (Path, Name) = os.path.split(Filename) + self.FullPath = Filename + self.RelaPath = Path + self.FileName = Name + GlobalData.gINF_MODULE_DIR = Path + GlobalData.gINF_MODULE_NAME = self.FullPath + GlobalData.gIS_BINARY_INF = False + # + # Initialize common data + # + LineNo = 0 + CurrentSection = DT.MODEL_UNKNOWN + SectionLines = [] + + # + # Flags + # + HeaderCommentStart = False + HeaderCommentEnd = False + HeaderStarLineNo = -1 + BinaryHeaderCommentStart = False + BinaryHeaderCommentEnd = False + BinaryHeaderStarLineNo = -1 + + # + # While Section ends. parse whole section contents. + # + NewSectionStartFlag = False + FirstSectionStartFlag = False + + # + # Parse file content + # + CommentBlock = [] + + # + # Variables for Event/Hob/BootMode + # + self.EventList = [] + self.HobList = [] + self.BootModeList = [] + SectionType = '' + + FileLinesList = OpenInfFile (Filename) + + # + # One INF file can only has one [Defines] section. + # + DefineSectionParsedFlag = False + + # + # Convert special characters in lines to space character. + # + FileLinesList = ConvertSpecialChar(FileLinesList) + + # + # Process Line Extender + # + FileLinesList = ProcessLineExtender(FileLinesList) + + # + # Process EdkI INF style comment if found + # + OrigLines = [Line for Line in FileLinesList] + FileLinesList, EdkCommentStartPos = ProcessEdkComment(FileLinesList) + + # + # Judge whether the INF file is Binary INF or not + # + if IsBinaryInf(FileLinesList): + GlobalData.gIS_BINARY_INF = True + + InfSectionCommonDefObj = None + + for Line in FileLinesList: + LineNo = LineNo + 1 + Line = Line.strip() + if (LineNo < len(FileLinesList) - 1): + NextLine = FileLinesList[LineNo].strip() + + # + # blank line + # + if (Line == '' or not Line) and LineNo == len(FileLinesList): + LastSectionFalg = True + + # + # check whether file header comment section started + # + if Line.startswith(DT.TAB_SPECIAL_COMMENT) and \ + (Line.find(DT.TAB_HEADER_COMMENT) > -1) and \ + not HeaderCommentStart and not HeaderCommentEnd: + + CurrentSection = DT.MODEL_META_DATA_FILE_HEADER + # + # Append the first line to section lines. + # + HeaderStarLineNo = LineNo + SectionLines.append((Line, LineNo)) + HeaderCommentStart = True + continue + + # + # Collect Header content. + # + if (Line.startswith(DT.TAB_COMMENT_SPLIT) and CurrentSection == DT.MODEL_META_DATA_FILE_HEADER) and\ + HeaderCommentStart and not Line.startswith(DT.TAB_SPECIAL_COMMENT) and not\ + HeaderCommentEnd and NextLine != '': + SectionLines.append((Line, LineNo)) + continue + # + # Header content end + # + if (Line.startswith(DT.TAB_SPECIAL_COMMENT) or not Line.strip().startswith("#")) and HeaderCommentStart \ + and not HeaderCommentEnd: + HeaderCommentEnd = True + BinaryHeaderCommentStart = False + BinaryHeaderCommentEnd = False + HeaderCommentStart = False + if Line.find(DT.TAB_BINARY_HEADER_COMMENT) > -1: + self.InfHeaderParser(SectionLines, self.InfHeader, self.FileName) + SectionLines = [] + else: + SectionLines.append((Line, LineNo)) + # + # Call Header comment parser. + # + self.InfHeaderParser(SectionLines, self.InfHeader, self.FileName) + SectionLines = [] + continue + + # + # check whether binary header comment section started + # + if Line.startswith(DT.TAB_SPECIAL_COMMENT) and \ + (Line.find(DT.TAB_BINARY_HEADER_COMMENT) > -1) and \ + not BinaryHeaderCommentStart: + SectionLines = [] + CurrentSection = DT.MODEL_META_DATA_FILE_HEADER + # + # Append the first line to section lines. + # + BinaryHeaderStarLineNo = LineNo + SectionLines.append((Line, LineNo)) + BinaryHeaderCommentStart = True + HeaderCommentEnd = True + continue + + # + # check whether there are more than one binary header exist + # + if Line.startswith(DT.TAB_SPECIAL_COMMENT) and BinaryHeaderCommentStart and \ + not BinaryHeaderCommentEnd and (Line.find(DT.TAB_BINARY_HEADER_COMMENT) > -1): + Logger.Error('Parser', + FORMAT_INVALID, + ST.ERR_MULTIPLE_BINARYHEADER_EXIST, + File=Filename) + + # + # Collect Binary Header content. + # + if (Line.startswith(DT.TAB_COMMENT_SPLIT) and CurrentSection == DT.MODEL_META_DATA_FILE_HEADER) and\ + BinaryHeaderCommentStart and not Line.startswith(DT.TAB_SPECIAL_COMMENT) and not\ + BinaryHeaderCommentEnd and NextLine != '': + SectionLines.append((Line, LineNo)) + continue + # + # Binary Header content end + # + if (Line.startswith(DT.TAB_SPECIAL_COMMENT) or not Line.strip().startswith(DT.TAB_COMMENT_SPLIT)) and \ + BinaryHeaderCommentStart and not BinaryHeaderCommentEnd: + SectionLines.append((Line, LineNo)) + BinaryHeaderCommentStart = False + # + # Call Binary Header comment parser. + # + self.InfHeaderParser(SectionLines, self.InfBinaryHeader, self.FileName, True) + SectionLines = [] + BinaryHeaderCommentEnd = True + continue + # + # Find a new section tab + # Or at the last line of INF file, + # need to process the last section. + # + LastSectionFalg = False + if LineNo == len(FileLinesList): + LastSectionFalg = True + + if Line.startswith(DT.TAB_COMMENT_SPLIT) and not Line.startswith(DT.TAB_SPECIAL_COMMENT): + SectionLines.append((Line, LineNo)) + if not LastSectionFalg: + continue + + # + # Encountered a section. start with '[' and end with ']' + # + if (Line.startswith(DT.TAB_SECTION_START) and \ + Line.find(DT.TAB_SECTION_END) > -1) or LastSectionFalg: + + HeaderCommentEnd = True + BinaryHeaderCommentEnd = True + + if not LastSectionFalg: + # + # check to prevent '#' inside section header + # + HeaderContent = Line[1:Line.find(DT.TAB_SECTION_END)] + if HeaderContent.find(DT.TAB_COMMENT_SPLIT) != -1: + Logger.Error("InfParser", + FORMAT_INVALID, + ST.ERR_INF_PARSER_DEFINE_SECTION_HEADER_INVALID, + File=self.FullPath, + Line=LineNo, + ExtraData=Line) + + # + # Keep last time section header content for section parser + # usage. + # + self.LastSectionHeaderContent = deepcopy(self.SectionHeaderContent) + + # + # TailComments in section define. + # + TailComments = '' + CommentIndex = Line.find(DT.TAB_COMMENT_SPLIT) + if CommentIndex > -1: + TailComments = Line[CommentIndex:] + Line = Line[:CommentIndex] + + InfSectionCommonDefObj = InfSectionCommonDef() + if TailComments != '': + InfSectionCommonDefObj.SetTailComments(TailComments) + if CommentBlock != '': + InfSectionCommonDefObj.SetHeaderComments(CommentBlock) + CommentBlock = [] + # + # Call section parser before section header parer to avoid encounter EDKI INF file + # + if CurrentSection == DT.MODEL_META_DATA_DEFINE: + DefineSectionParsedFlag = self._CallSectionParsers(CurrentSection, + DefineSectionParsedFlag, SectionLines, + InfSectionCommonDefObj, LineNo) + # + # Compare the new section name with current + # + self.SectionHeaderParser(Line, self.FileName, LineNo) + + self._CheckSectionHeaders(Line, LineNo) + + SectionType = _ConvertSecNameToType(self.SectionHeaderContent[0][0]) + + if not FirstSectionStartFlag: + CurrentSection = SectionType + FirstSectionStartFlag = True + else: + NewSectionStartFlag = True + else: + SectionLines.append((Line, LineNo)) + continue + + if LastSectionFalg: + SectionLines, CurrentSection = self._ProcessLastSection(SectionLines, Line, LineNo, CurrentSection) + + # + # End of section content collect. + # Parser the section content collected previously. + # + if NewSectionStartFlag or LastSectionFalg: + if CurrentSection != DT.MODEL_META_DATA_DEFINE or \ + (LastSectionFalg and CurrentSection == DT.MODEL_META_DATA_DEFINE): + DefineSectionParsedFlag = self._CallSectionParsers(CurrentSection, + DefineSectionParsedFlag, SectionLines, + InfSectionCommonDefObj, LineNo) + + CurrentSection = SectionType + # + # Clear section lines + # + SectionLines = [] + + if HeaderStarLineNo == -1: + Logger.Error("InfParser", + FORMAT_INVALID, + ST.ERR_NO_SOURCE_HEADER, + File=self.FullPath) + if BinaryHeaderStarLineNo > -1 and HeaderStarLineNo > -1 and HeaderStarLineNo > BinaryHeaderStarLineNo: + Logger.Error("InfParser", + FORMAT_INVALID, + ST.ERR_BINARY_HEADER_ORDER, + File=self.FullPath) + # + # EDKII INF should not have EDKI style comment + # + if EdkCommentStartPos != -1: + Logger.Error("InfParser", + FORMAT_INVALID, + ST.ERR_INF_PARSER_EDKI_COMMENT_IN_EDKII, + File=self.FullPath, + Line=EdkCommentStartPos + 1, + ExtraData=OrigLines[EdkCommentStartPos]) + + # + # extract [Event] [Hob] [BootMode] sections + # + self._ExtractEventHobBootMod(FileLinesList) + + ## _CheckSectionHeaders + # + # + def _CheckSectionHeaders(self, Line, LineNo): + if len(self.SectionHeaderContent) == 0: + Logger.Error("InfParser", + FORMAT_INVALID, + ST.ERR_INF_PARSER_DEFINE_SECTION_HEADER_INVALID, + File=self.FullPath, + Line=LineNo, ExtraData=Line) + else: + for SectionItem in self.SectionHeaderContent: + ArchList = [] + # + # Not cover Depex/UserExtension section header + # check. + # + if SectionItem[0].strip().upper() == DT.TAB_INF_FIXED_PCD.upper() or \ + SectionItem[0].strip().upper() == DT.TAB_INF_PATCH_PCD.upper() or \ + SectionItem[0].strip().upper() == DT.TAB_INF_PCD_EX.upper() or \ + SectionItem[0].strip().upper() == DT.TAB_INF_PCD.upper() or \ + SectionItem[0].strip().upper() == DT.TAB_INF_FEATURE_PCD.upper(): + ArchList = GetSplitValueList(SectionItem[1].strip(), ' ') + else: + ArchList = [SectionItem[1].strip()] + + for Arch in ArchList: + if (not IsValidArch(Arch)) and \ + (SectionItem[0].strip().upper() != DT.TAB_DEPEX.upper()) and \ + (SectionItem[0].strip().upper() != DT.TAB_USER_EXTENSIONS.upper()) and \ + (SectionItem[0].strip().upper() != DT.TAB_COMMON_DEFINES.upper()): + Logger.Error("InfParser", + FORMAT_INVALID, + ST.ERR_INF_PARSER_DEFINE_FROMAT_INVALID%(SectionItem[1]), + File=self.FullPath, + Line=LineNo, ExtraData=Line) + # + # Check if the ModuleType is valid + # + ChkModSectionList = ['LIBRARYCLASSES'] + if (self.SectionHeaderContent[0][0].upper() in ChkModSectionList): + if SectionItem[2].strip().upper(): + MoudleTypeList = GetSplitValueList( + SectionItem[2].strip().upper()) + if (not IsValidInfMoudleTypeList(MoudleTypeList)): + Logger.Error("InfParser", + FORMAT_INVALID, + ST.ERR_INF_PARSER_DEFINE_FROMAT_INVALID%(SectionItem[2]), + File=self.FullPath, Line=LineNo, + ExtraData=Line) + + ## _CallSectionParsers + # + # + def _CallSectionParsers(self, CurrentSection, DefineSectionParsedFlag, + SectionLines, InfSectionCommonDefObj, LineNo): + if CurrentSection == DT.MODEL_META_DATA_DEFINE: + if not DefineSectionParsedFlag: + self.InfDefineParser(SectionLines, + self.InfDefSection, + self.FullPath, + InfSectionCommonDefObj) + DefineSectionParsedFlag = True + else: + Logger.Error("Parser", + PARSER_ERROR, + ST.ERR_INF_PARSER_MULTI_DEFINE_SECTION, + File=self.FullPath, + RaiseError = Logger.IS_RAISE_ERROR) + + elif CurrentSection == DT.MODEL_META_DATA_BUILD_OPTION: + self.InfBuildOptionParser(SectionLines, + self.InfBuildOptionSection, + self.FullPath) + + elif CurrentSection == DT.MODEL_EFI_LIBRARY_CLASS: + self.InfLibraryParser(SectionLines, + self.InfLibraryClassSection, + self.FullPath) + + elif CurrentSection == DT.MODEL_META_DATA_PACKAGE: + self.InfPackageParser(SectionLines, + self.InfPackageSection, + self.FullPath) + # + # [Pcd] Sections, put it together + # + elif CurrentSection == DT.MODEL_PCD_FIXED_AT_BUILD or \ + CurrentSection == DT.MODEL_PCD_PATCHABLE_IN_MODULE or \ + CurrentSection == DT.MODEL_PCD_FEATURE_FLAG or \ + CurrentSection == DT.MODEL_PCD_DYNAMIC_EX or \ + CurrentSection == DT.MODEL_PCD_DYNAMIC: + self.InfPcdParser(SectionLines, + self.InfPcdSection, + self.FullPath) + + elif CurrentSection == DT.MODEL_EFI_SOURCE_FILE: + self.InfSourceParser(SectionLines, + self.InfSourcesSection, + self.FullPath) + + elif CurrentSection == DT.MODEL_META_DATA_USER_EXTENSION: + self.InfUserExtensionParser(SectionLines, + self.InfUserExtensionSection, + self.FullPath) + + elif CurrentSection == DT.MODEL_EFI_PROTOCOL: + self.InfProtocolParser(SectionLines, + self.InfProtocolSection, + self.FullPath) + + elif CurrentSection == DT.MODEL_EFI_PPI: + self.InfPpiParser(SectionLines, + self.InfPpiSection, + self.FullPath) + + elif CurrentSection == DT.MODEL_EFI_GUID: + self.InfGuidParser(SectionLines, + self.InfGuidSection, + self.FullPath) + + elif CurrentSection == DT.MODEL_EFI_DEPEX: + self.InfDepexParser(SectionLines, + self.InfDepexSection, + self.FullPath) + + elif CurrentSection == DT.MODEL_EFI_BINARY_FILE: + self.InfBinaryParser(SectionLines, + self.InfBinariesSection, + self.FullPath) + # + # Unknown section type found, raise error. + # + else: + if len(self.SectionHeaderContent) >= 1: + Logger.Error("Parser", + PARSER_ERROR, + ST.ERR_INF_PARSER_UNKNOWN_SECTION, + File=self.FullPath, Line=LineNo, + RaiseError = Logger.IS_RAISE_ERROR) + else: + Logger.Error("Parser", + PARSER_ERROR, + ST.ERR_INF_PARSER_NO_SECTION_ERROR, + File=self.FullPath, Line=LineNo, + RaiseError = Logger.IS_RAISE_ERROR) + + return DefineSectionParsedFlag + + def _ExtractEventHobBootMod(self, FileLinesList): + SpecialSectionStart = False + CheckLocation = False + GFindSpecialCommentRe = \ + re.compile(r"""#(?:\s*)\[(.*?)\](?:.*)""", re.DOTALL) + GFindNewSectionRe2 = \ + re.compile(r"""#?(\s*)\[(.*?)\](.*)""", re.DOTALL) + LineNum = 0 + Element = [] + for Line in FileLinesList: + Line = Line.strip() + LineNum += 1 + MatchObject = GFindSpecialCommentRe.search(Line) + if MatchObject: + SpecialSectionStart = True + Element = [] + if MatchObject.group(1).upper().startswith("EVENT"): + List = self.EventList + elif MatchObject.group(1).upper().startswith("HOB"): + List = self.HobList + elif MatchObject.group(1).upper().startswith("BOOTMODE"): + List = self.BootModeList + else: + SpecialSectionStart = False + CheckLocation = False + if SpecialSectionStart: + Element.append([Line, LineNum]) + List.append(Element) + else: + # + # if currently in special section, try to detect end of current section + # + MatchObject = GFindNewSectionRe2.search(Line) + if SpecialSectionStart: + if MatchObject: + SpecialSectionStart = False + CheckLocation = False + Element = [] + elif not Line: + SpecialSectionStart = False + CheckLocation = True + Element = [] + else: + if not Line.startswith(DT.TAB_COMMENT_SPLIT): + Logger.Warn("Parser", + ST.WARN_SPECIAL_SECTION_LOCATION_WRONG, + File=self.FullPath, Line=LineNum) + SpecialSectionStart = False + CheckLocation = False + Element = [] + else: + Element.append([Line, LineNum]) + else: + if CheckLocation: + if MatchObject: + CheckLocation = False + elif Line: + Logger.Warn("Parser", + ST.WARN_SPECIAL_SECTION_LOCATION_WRONG, + File=self.FullPath, Line=LineNum) + CheckLocation = False + + if len(self.BootModeList) >= 1: + self.InfSpecialCommentParser(self.BootModeList, + self.InfSpecialCommentSection, + self.FileName, + DT.TYPE_BOOTMODE_SECTION) + + if len(self.EventList) >= 1: + self.InfSpecialCommentParser(self.EventList, + self.InfSpecialCommentSection, + self.FileName, + DT.TYPE_EVENT_SECTION) + + if len(self.HobList) >= 1: + self.InfSpecialCommentParser(self.HobList, + self.InfSpecialCommentSection, + self.FileName, + DT.TYPE_HOB_SECTION) + ## _ProcessLastSection + # + # + def _ProcessLastSection(self, SectionLines, Line, LineNo, CurrentSection): + # + # The last line is a section header. will discard it. + # + if not (Line.startswith(DT.TAB_SECTION_START) and Line.find(DT.TAB_SECTION_END) > -1): + SectionLines.append((Line, LineNo)) + + if len(self.SectionHeaderContent) >= 1: + TemSectionName = self.SectionHeaderContent[0][0].upper() + if TemSectionName.upper() not in gINF_SECTION_DEF.keys(): + Logger.Error("InfParser", + FORMAT_INVALID, + ST.ERR_INF_PARSER_UNKNOWN_SECTION, + File=self.FullPath, + Line=LineNo, + ExtraData=Line, + RaiseError = Logger.IS_RAISE_ERROR + ) + else: + CurrentSection = gINF_SECTION_DEF[TemSectionName] + self.LastSectionHeaderContent = self.SectionHeaderContent + + return SectionLines, CurrentSection + +## _ConvertSecNameToType +# +# +def _ConvertSecNameToType(SectionName): + SectionType = '' + if SectionName.upper() not in gINF_SECTION_DEF.keys(): + SectionType = DT.MODEL_UNKNOWN + else: + SectionType = gINF_SECTION_DEF[SectionName.upper()] + + return SectionType + diff --git a/src/VBox/Devices/EFI/Firmware/BaseTools/Source/Python/UPT/Parser/InfParserMisc.py b/src/VBox/Devices/EFI/Firmware/BaseTools/Source/Python/UPT/Parser/InfParserMisc.py new file mode 100755 index 00000000..0a51ac28 --- /dev/null +++ b/src/VBox/Devices/EFI/Firmware/BaseTools/Source/Python/UPT/Parser/InfParserMisc.py @@ -0,0 +1,216 @@ +## @file +# This file contained the miscellaneous functions for INF parser +# +# Copyright (c) 2011 - 2018, Intel Corporation. All rights reserved.
+# +# SPDX-License-Identifier: BSD-2-Clause-Patent +# + +''' +InfParserMisc +''' + +## +# Import Modules +# +import re + + +from Library import DataType as DT + + +from Library.StringUtils import gMACRO_PATTERN +from Library.StringUtils import ReplaceMacro +from Object.Parser.InfMisc import ErrorInInf +from Logger.StringTable import ERR_MARCO_DEFINITION_MISS_ERROR + +# +# Global variable +# + +# +# Sections can exist in INF file +# +gINF_SECTION_DEF = { + DT.TAB_UNKNOWN.upper() : DT.MODEL_UNKNOWN, + DT.TAB_HEADER.upper() : DT.MODEL_META_DATA_FILE_HEADER, + DT.TAB_INF_DEFINES.upper() : DT.MODEL_META_DATA_DEFINE, + DT.TAB_BUILD_OPTIONS.upper() : DT.MODEL_META_DATA_BUILD_OPTION, + DT.TAB_LIBRARY_CLASSES.upper() : DT.MODEL_EFI_LIBRARY_CLASS, + DT.TAB_PACKAGES.upper() : DT.MODEL_META_DATA_PACKAGE, + DT.TAB_INF_FIXED_PCD.upper() : DT.MODEL_PCD_FIXED_AT_BUILD, + DT.TAB_INF_PATCH_PCD.upper() : DT.MODEL_PCD_PATCHABLE_IN_MODULE, + DT.TAB_INF_FEATURE_PCD.upper() : DT.MODEL_PCD_FEATURE_FLAG, + DT.TAB_INF_PCD_EX.upper() : DT.MODEL_PCD_DYNAMIC_EX, + DT.TAB_INF_PCD.upper() : DT.MODEL_PCD_DYNAMIC, + DT.TAB_SOURCES.upper() : DT.MODEL_EFI_SOURCE_FILE, + DT.TAB_GUIDS.upper() : DT.MODEL_EFI_GUID, + DT.TAB_PROTOCOLS.upper() : DT.MODEL_EFI_PROTOCOL, + DT.TAB_PPIS.upper() : DT.MODEL_EFI_PPI, + DT.TAB_DEPEX.upper() : DT.MODEL_EFI_DEPEX, + DT.TAB_BINARIES.upper() : DT.MODEL_EFI_BINARY_FILE, + DT.TAB_USER_EXTENSIONS.upper() : DT.MODEL_META_DATA_USER_EXTENSION + # + # EDK1 section + # TAB_NMAKE.upper() : MODEL_META_DATA_NMAKE + # + } + +## InfExpandMacro +# +# Expand MACRO definition with MACROs defined in [Defines] section and specific section. +# The MACROs defined in specific section has high priority and will be expanded firstly. +# +# @param LineInfo Contain information of FileName, LineContent, LineNo +# @param GlobalMacros MACROs defined in INF [Defines] section +# @param SectionMacros MACROs defined in INF specific section +# @param Flag If the flag set to True, need to skip macros in a quoted string +# +def InfExpandMacro(Content, LineInfo, GlobalMacros=None, SectionMacros=None, Flag=False): + if GlobalMacros is None: + GlobalMacros = {} + if SectionMacros is None: + SectionMacros = {} + + FileName = LineInfo[0] + LineContent = LineInfo[1] + LineNo = LineInfo[2] + + # Don't expand macros in comments + if LineContent.strip().startswith("#"): + return Content + + NewLineInfo = (FileName, LineNo, LineContent) + + # + # First, replace MARCOs with value defined in specific section + # + Content = ReplaceMacro (Content, + SectionMacros, + False, + (LineContent, LineNo), + FileName, + Flag) + # + # Then replace MARCOs with value defined in [Defines] section + # + Content = ReplaceMacro (Content, + GlobalMacros, + False, + (LineContent, LineNo), + FileName, + Flag) + + MacroUsed = gMACRO_PATTERN.findall(Content) + # + # no macro found in String, stop replacing + # + if len(MacroUsed) == 0: + return Content + else: + for Macro in MacroUsed: + gQuotedMacro = re.compile(".*\".*\$\(%s\).*\".*"%(Macro)) + if not gQuotedMacro.match(Content): + # + # Still have MACROs can't be expanded. + # + ErrorInInf (ERR_MARCO_DEFINITION_MISS_ERROR, + LineInfo=NewLineInfo) + + return Content + + +## IsBinaryInf +# +# Judge whether the INF file is Binary INF or Common INF +# +# @param FileLineList A list contain all INF file content. +# +def IsBinaryInf(FileLineList): + if not FileLineList: + return False + + ReIsSourcesSection = re.compile("^\s*\[Sources.*\]\s.*$", re.IGNORECASE) + ReIsBinarySection = re.compile("^\s*\[Binaries.*\]\s.*$", re.IGNORECASE) + BinarySectionFoundFlag = False + + for Line in FileLineList: + if ReIsSourcesSection.match(Line): + return False + if ReIsBinarySection.match(Line): + BinarySectionFoundFlag = True + + if BinarySectionFoundFlag: + return True + + return False + + +## IsLibInstanceInfo +# +# Judge whether the string contain the information of ## @LIB_INSTANCES. +# +# @param String +# +# @return Flag +# +def IsLibInstanceInfo(String): + ReIsLibInstance = re.compile("^\s*##\s*@LIB_INSTANCES\s*$") + if ReIsLibInstance.match(String): + return True + else: + return False + + +## IsAsBuildOptionInfo +# +# Judge whether the string contain the information of ## @ASBUILD. +# +# @param String +# +# @return Flag +# +def IsAsBuildOptionInfo(String): + ReIsAsBuildInstance = re.compile("^\s*##\s*@AsBuilt\s*$") + if ReIsAsBuildInstance.match(String): + return True + else: + return False + + +class InfParserSectionRoot(object): + def __init__(self): + # + # Macros defined in [Define] section are file scope global + # + self.FileLocalMacros = {} + + # + # Current Section Header content. + # + self.SectionHeaderContent = [] + + # + # Last time Section Header content. + # + self.LastSectionHeaderContent = [] + + self.FullPath = '' + + self.InfDefSection = None + self.InfBuildOptionSection = None + self.InfLibraryClassSection = None + self.InfPackageSection = None + self.InfPcdSection = None + self.InfSourcesSection = None + self.InfUserExtensionSection = None + self.InfProtocolSection = None + self.InfPpiSection = None + self.InfGuidSection = None + self.InfDepexSection = None + self.InfPeiDepexSection = None + self.InfDxeDepexSection = None + self.InfSmmDepexSection = None + self.InfBinariesSection = None + self.InfHeader = None + self.InfSpecialCommentSection = None diff --git a/src/VBox/Devices/EFI/Firmware/BaseTools/Source/Python/UPT/Parser/InfPcdSectionParser.py b/src/VBox/Devices/EFI/Firmware/BaseTools/Source/Python/UPT/Parser/InfPcdSectionParser.py new file mode 100755 index 00000000..e930398d --- /dev/null +++ b/src/VBox/Devices/EFI/Firmware/BaseTools/Source/Python/UPT/Parser/InfPcdSectionParser.py @@ -0,0 +1,178 @@ +## @file +# This file contained the parser for [Pcds] sections in INF file +# +# Copyright (c) 2011 - 2018, Intel Corporation. All rights reserved.
+# +# SPDX-License-Identifier: BSD-2-Clause-Patent +# +''' +InfPcdSectionParser +''' +## +# Import Modules +# + +import Logger.Log as Logger +from Logger import StringTable as ST +from Logger.ToolError import FORMAT_INVALID +from Parser.InfParserMisc import InfExpandMacro +from Library import DataType as DT +from Library.Parsing import MacroParser +from Library.Misc import GetSplitValueList +from Library import GlobalData +from Library.StringUtils import SplitPcdEntry +from Parser.InfParserMisc import InfParserSectionRoot + +class InfPcdSectionParser(InfParserSectionRoot): + ## Section PCD related parser + # + # For 5 types of PCD list below, all use this function. + # 'FixedPcd', 'FeaturePcd', 'PatchPcd', 'Pcd', 'PcdEx' + # + # This is a INF independent parser, the validation in this parser only + # cover + # INF spec scope, will not cross DEC/DSC to check pcd value + # + def InfPcdParser(self, SectionString, InfSectionObject, FileName): + KeysList = [] + PcdList = [] + CommentsList = [] + ValueList = [] + # + # Current section archs + # + LineIndex = -1 + for Item in self.LastSectionHeaderContent: + if (Item[0], Item[1], Item[3]) not in KeysList: + KeysList.append((Item[0], Item[1], Item[3])) + LineIndex = Item[3] + + if (Item[0].upper() == DT.TAB_INF_FIXED_PCD.upper() or \ + Item[0].upper() == DT.TAB_INF_FEATURE_PCD.upper() or \ + Item[0].upper() == DT.TAB_INF_PCD.upper()) and GlobalData.gIS_BINARY_INF: + Logger.Error('InfParser', FORMAT_INVALID, ST.ERR_ASBUILD_PCD_SECTION_TYPE%("\"" + Item[0] + "\""), + File=FileName, Line=LineIndex) + + # + # For Common INF file + # + if not GlobalData.gIS_BINARY_INF: + # + # Macro defined in this section + # + SectionMacros = {} + for Line in SectionString: + PcdLineContent = Line[0] + PcdLineNo = Line[1] + if PcdLineContent.strip() == '': + CommentsList = [] + continue + + if PcdLineContent.strip().startswith(DT.TAB_COMMENT_SPLIT): + CommentsList.append(Line) + continue + else: + # + # Encounter a PCD entry + # + if PcdLineContent.find(DT.TAB_COMMENT_SPLIT) > -1: + CommentsList.append(( + PcdLineContent[PcdLineContent.find(DT.TAB_COMMENT_SPLIT):], + PcdLineNo)) + PcdLineContent = PcdLineContent[:PcdLineContent.find(DT.TAB_COMMENT_SPLIT)] + + if PcdLineContent != '': + # + # Find Macro + # + Name, Value = MacroParser((PcdLineContent, PcdLineNo), + FileName, + DT.MODEL_EFI_PCD, + self.FileLocalMacros) + if Name is not None: + SectionMacros[Name] = Value + ValueList = [] + CommentsList = [] + continue + + PcdEntryReturn = SplitPcdEntry(PcdLineContent) + + if not PcdEntryReturn[1]: + TokenList = [''] + else: + TokenList = PcdEntryReturn[0] + + ValueList[0:len(TokenList)] = TokenList + + # + # Replace with Local section Macro and [Defines] section Macro. + # + ValueList = [InfExpandMacro(Value, (FileName, PcdLineContent, PcdLineNo), + self.FileLocalMacros, SectionMacros, True) + for Value in ValueList] + + if len(ValueList) >= 1: + PcdList.append((ValueList, CommentsList, (PcdLineContent, PcdLineNo, FileName))) + ValueList = [] + CommentsList = [] + continue + # + # For Binary INF file + # + else: + for Line in SectionString: + LineContent = Line[0].strip() + LineNo = Line[1] + + if LineContent == '': + CommentsList = [] + continue + + if LineContent.startswith(DT.TAB_COMMENT_SPLIT): + CommentsList.append(LineContent) + continue + # + # Have comments at tail. + # + CommentIndex = LineContent.find(DT.TAB_COMMENT_SPLIT) + if CommentIndex > -1: + CommentsList.append(LineContent[CommentIndex+1:]) + LineContent = LineContent[:CommentIndex] + + TokenList = GetSplitValueList(LineContent, DT.TAB_VALUE_SPLIT) + # + # PatchablePcd + # TokenSpace.CName | Value | Offset + # + if KeysList[0][0].upper() == DT.TAB_INF_PATCH_PCD.upper(): + if len(TokenList) != 3: + Logger.Error('InfParser', + FORMAT_INVALID, + ST.ERR_ASBUILD_PATCHPCD_FORMAT_INVALID, + File=FileName, + Line=LineNo, + ExtraData=LineContent) + # + elif KeysList[0][0].upper() == DT.TAB_INF_PCD_EX.upper(): + if len(TokenList) != 1: + Logger.Error('InfParser', + FORMAT_INVALID, + ST.ERR_ASBUILD_PCDEX_FORMAT_INVALID, + File=FileName, + Line=LineNo, + ExtraData=LineContent) + ValueList[0:len(TokenList)] = TokenList + if len(ValueList) >= 1: + PcdList.append((ValueList, CommentsList, (LineContent, LineNo, FileName))) + ValueList = [] + CommentsList = [] + continue + + if not InfSectionObject.SetPcds(PcdList, KeysList = KeysList, + PackageInfo = self.InfPackageSection.GetPackages()): + Logger.Error('InfParser', + FORMAT_INVALID, + ST.ERR_INF_PARSER_MODULE_SECTION_TYPE_ERROR%("[PCD]"), + File=FileName, + Line=LineIndex) + diff --git a/src/VBox/Devices/EFI/Firmware/BaseTools/Source/Python/UPT/Parser/InfSectionParser.py b/src/VBox/Devices/EFI/Firmware/BaseTools/Source/Python/UPT/Parser/InfSectionParser.py new file mode 100755 index 00000000..9a0cd714 --- /dev/null +++ b/src/VBox/Devices/EFI/Firmware/BaseTools/Source/Python/UPT/Parser/InfSectionParser.py @@ -0,0 +1,493 @@ +## @file +# This file contained the parser for sections in INF file +# +# Copyright (c) 2011 - 2018, Intel Corporation. All rights reserved.
+# +# SPDX-License-Identifier: BSD-2-Clause-Patent +# + +''' +InfSectionParser +''' +## +# Import Modules +# +from copy import deepcopy +import re + +from Library.StringUtils import GetSplitValueList +from Library.CommentParsing import ParseHeaderCommentSection +from Library.CommentParsing import ParseComment + +from Library import DataType as DT + +import Logger.Log as Logger +from Logger import StringTable as ST +from Logger.ToolError import FORMAT_INVALID + +from Object.Parser.InfDefineObject import InfDefObject +from Object.Parser.InfBuildOptionObject import InfBuildOptionsObject +from Object.Parser.InfLibraryClassesObject import InfLibraryClassObject +from Object.Parser.InfPackagesObject import InfPackageObject +from Object.Parser.InfPcdObject import InfPcdObject +from Object.Parser.InfSoucesObject import InfSourcesObject +from Object.Parser.InfUserExtensionObject import InfUserExtensionObject +from Object.Parser.InfProtocolObject import InfProtocolObject +from Object.Parser.InfPpiObject import InfPpiObject +from Object.Parser.InfGuidObject import InfGuidObject +from Object.Parser.InfDepexObject import InfDepexObject +from Object.Parser.InfBinaryObject import InfBinariesObject +from Object.Parser.InfHeaderObject import InfHeaderObject +from Object.Parser.InfMisc import InfSpecialCommentObject +from Object.Parser.InfMisc import InfHobObject +from Object.Parser.InfMisc import InfBootModeObject +from Object.Parser.InfMisc import InfEventObject +from Parser.InfParserMisc import gINF_SECTION_DEF +from Parser.InfDefineSectionParser import InfDefinSectionParser +from Parser.InfBuildOptionSectionParser import InfBuildOptionSectionParser +from Parser.InfSourceSectionParser import InfSourceSectionParser +from Parser.InfLibrarySectionParser import InfLibrarySectionParser +from Parser.InfPackageSectionParser import InfPackageSectionParser +from Parser.InfGuidPpiProtocolSectionParser import InfGuidPpiProtocolSectionParser +from Parser.InfBinarySectionParser import InfBinarySectionParser +from Parser.InfPcdSectionParser import InfPcdSectionParser +from Parser.InfDepexSectionParser import InfDepexSectionParser + +## GetSpecialStr2 +# +# GetSpecialStr2 +# +def GetSpecialStr2(ItemList, FileName, LineNo, SectionString): + Str2 = '' + # + # S2 may be Platform or ModuleType + # + if len(ItemList) == 3: + # + # Except [LibraryClass], [Depex] + # section can has more than 2 items in section header string, + # others should report error. + # + if not (ItemList[0].upper() == DT.TAB_LIBRARY_CLASSES.upper() or \ + ItemList[0].upper() == DT.TAB_DEPEX.upper() or \ + ItemList[0].upper() == DT.TAB_USER_EXTENSIONS.upper()): + if ItemList[2] != '': + Logger.Error('Parser', + FORMAT_INVALID, + ST.ERR_INF_PARSER_SOURCE_SECTION_SECTIONNAME_INVALID % (SectionString), + File=FileName, + Line=LineNo, + ExtraData=SectionString) + Str2 = ItemList[2] + elif len(ItemList) == 4: + # + # Except [UserExtension] + # section can has 4 items in section header string, + # others should report error. + # + if not ItemList[0].upper() == DT.TAB_USER_EXTENSIONS.upper() or ItemList[0].upper() == DT.TAB_DEPEX.upper(): + if ItemList[3] != '': + Logger.Error('Parser', FORMAT_INVALID, ST.ERR_INF_PARSER_SOURCE_SECTION_SECTIONNAME_INVALID \ + % (SectionString), File=FileName, Line=LineNo, ExtraData=SectionString) + + if not ItemList[0].upper() == DT.TAB_USER_EXTENSIONS.upper(): + Str2 = ItemList[2] + ' | ' + ItemList[3] + else: + Str2 = ItemList[2] + + elif len(ItemList) > 4: + Logger.Error('Parser', FORMAT_INVALID, ST.ERR_INF_PARSER_SOURCE_SECTION_SECTIONNAME_INVALID \ + % (SectionString), File=FileName, Line=LineNo, ExtraData=SectionString) + + return Str2 + +## ProcessUseExtHeader +# +# +def ProcessUseExtHeader(ItemList): + NewItemList = [] + AppendContent = '' + CompleteFlag = False + for Item in ItemList: + if Item.startswith('\"') and not Item.endswith('\"'): + AppendContent = Item + CompleteFlag = True + elif Item.endswith('\"') and not Item.startswith('\"'): + # + # Should not have an userId or IdString not starts with " before but ends with ". + # + if not CompleteFlag: + return False, [] + AppendContent = AppendContent + "." + Item + NewItemList.append(AppendContent) + CompleteFlag = False + AppendContent = '' + elif Item.endswith('\"') and Item.startswith('\"'): + # + # Common item, not need to combine the information + # + NewItemList.append(Item) + else: + if not CompleteFlag: + NewItemList.append(Item) + else: + AppendContent = AppendContent + "." + Item + + if len(NewItemList) > 4: + return False, [] + + return True, NewItemList + +## GetArch +# +# GetArch +# +def GetArch(ItemList, ArchList, FileName, LineNo, SectionString): + # + # S1 is always Arch + # + if len(ItemList) > 1: + Arch = ItemList[1] + else: + Arch = 'COMMON' + ArchList.add(Arch) + + # + # 'COMMON' must not be used with specific ARCHs at the same section + # + if 'COMMON' in ArchList and len(ArchList) > 1: + Logger.Error('Parser', + FORMAT_INVALID, + ST.ERR_INF_PARSER_SECTION_ARCH_CONFLICT, + File=FileName, + Line=LineNo, + ExtraData=SectionString) + + return Arch, ArchList + +## InfSectionParser +# +# Inherit from object +# +class InfSectionParser(InfDefinSectionParser, + InfBuildOptionSectionParser, + InfSourceSectionParser, + InfLibrarySectionParser, + InfPackageSectionParser, + InfGuidPpiProtocolSectionParser, + InfBinarySectionParser, + InfPcdSectionParser, + InfDepexSectionParser): + # + # Parser objects used to implement singleton + # + MetaFiles = {} + + ## Factory method + # + # One file, one parser object. This factory method makes sure that there's + # only one object constructed for one meta file. + # + # @param Class class object of real AutoGen class + # (InfParser, DecParser or DscParser) + # @param FilePath The path of meta file + # + def __new__(cls, FilePath, *args, **kwargs): + if args: + pass + if kwargs: + pass + if FilePath in cls.MetaFiles: + return cls.MetaFiles[FilePath] + else: + ParserObject = super(InfSectionParser, cls).__new__(cls) + cls.MetaFiles[FilePath] = ParserObject + return ParserObject + + def __init__(self): + InfDefinSectionParser.__init__(self) + InfBuildOptionSectionParser.__init__(self) + InfSourceSectionParser.__init__(self) + InfLibrarySectionParser.__init__(self) + InfPackageSectionParser.__init__(self) + InfGuidPpiProtocolSectionParser.__init__(self) + InfBinarySectionParser.__init__(self) + InfPcdSectionParser.__init__(self) + InfDepexSectionParser.__init__(self) + # + # Initialize all objects that an INF file will generated. + # + self.InfDefSection = InfDefObject() + self.InfBuildOptionSection = InfBuildOptionsObject() + self.InfLibraryClassSection = InfLibraryClassObject() + self.InfPackageSection = InfPackageObject() + self.InfPcdSection = InfPcdObject(list(self.MetaFiles.keys())[0]) + self.InfSourcesSection = InfSourcesObject() + self.InfUserExtensionSection = InfUserExtensionObject() + self.InfProtocolSection = InfProtocolObject() + self.InfPpiSection = InfPpiObject() + self.InfGuidSection = InfGuidObject() + self.InfDepexSection = InfDepexObject() + self.InfPeiDepexSection = InfDepexObject() + self.InfDxeDepexSection = InfDepexObject() + self.InfSmmDepexSection = InfDepexObject() + self.InfBinariesSection = InfBinariesObject() + self.InfHeader = InfHeaderObject() + self.InfBinaryHeader = InfHeaderObject() + self.InfSpecialCommentSection = InfSpecialCommentObject() + + # + # A List for store define section content. + # + self._PcdNameList = [] + self._SectionName = '' + self._SectionType = 0 + self.RelaPath = '' + self.FileName = '' + + # + # File Header content parser + # + def InfHeaderParser(self, Content, InfHeaderObject2, FileName, IsBinaryHeader = False): + if IsBinaryHeader: + (Abstract, Description, Copyright, License) = ParseHeaderCommentSection(Content, FileName, True) + if not Abstract or not Description or not Copyright or not License: + Logger.Error('Parser', + FORMAT_INVALID, + ST.ERR_INVALID_BINARYHEADER_FORMAT, + File=FileName) + else: + (Abstract, Description, Copyright, License) = ParseHeaderCommentSection(Content, FileName) + # + # Not process file name now, for later usage. + # + if self.FileName: + pass + + # + # Insert Abstract, Description, CopyRight, License into header object + # + InfHeaderObject2.SetAbstract(Abstract) + InfHeaderObject2.SetDescription(Description) + InfHeaderObject2.SetCopyright(Copyright) + InfHeaderObject2.SetLicense(License) + + + + + ## Section header parser + # + # The section header is always in following format: + # + # [section_name.arch<.platform|module_type>] + # + # @param String A string contained the content need to be parsed. + # + def SectionHeaderParser(self, SectionString, FileName, LineNo): + _Scope = [] + _SectionName = '' + ArchList = set() + _ValueList = [] + _PcdNameList = [DT.TAB_INF_FIXED_PCD.upper(), + DT.TAB_INF_FEATURE_PCD.upper(), + DT.TAB_INF_PATCH_PCD.upper(), + DT.TAB_INF_PCD.upper(), + DT.TAB_INF_PCD_EX.upper() + ] + SectionString = SectionString.strip() + for Item in GetSplitValueList(SectionString[1:-1], DT.TAB_COMMA_SPLIT): + if Item == '': + Logger.Error('Parser', + FORMAT_INVALID, + ST.ERR_INF_PARSER_MODULE_SECTION_TYPE_ERROR % (""), + File=FileName, + Line=LineNo, + ExtraData=SectionString) + ItemList = GetSplitValueList(Item, DT.TAB_SPLIT) + # + # different section should not mix in one section + # Allow different PCD type sections mixed together + # + if _SectionName.upper() not in _PcdNameList: + if _SectionName != '' and _SectionName.upper() != ItemList[0].upper(): + Logger.Error('Parser', + FORMAT_INVALID, + ST.ERR_INF_PARSER_SECTION_NAME_DUPLICATE, + File=FileName, + Line=LineNo, + ExtraData=SectionString) + elif _PcdNameList[1] in [_SectionName.upper(), ItemList[0].upper()] and \ + (_SectionName.upper()!= ItemList[0].upper()): + Logger.Error('Parser', + FORMAT_INVALID, + ST.ERR_INF_PARSER_MODULE_SECTION_TYPE_ERROR % (""), + File=FileName, + Line=LineNo, + ExtraData=SectionString) + + _SectionName = ItemList[0] + if _SectionName.upper() in gINF_SECTION_DEF: + self._SectionType = gINF_SECTION_DEF[_SectionName.upper()] + else: + self._SectionType = DT.MODEL_UNKNOWN + Logger.Error("Parser", + FORMAT_INVALID, + ST.ERR_INF_PARSER_UNKNOWN_SECTION, + File=FileName, + Line=LineNo, + ExtraData=SectionString) + + # + # Get Arch + # + Str1, ArchList = GetArch(ItemList, ArchList, FileName, LineNo, SectionString) + + # + # For [Defines] section, do special check. + # + if ItemList[0].upper() == DT.TAB_COMMON_DEFINES.upper(): + if len(ItemList) != 1: + Logger.Error('Parser', + FORMAT_INVALID, + ST.ERR_INF_PARSER_DEFINE_FROMAT_INVALID % (SectionString), + File=FileName, Line=LineNo, ExtraData=SectionString) + + # + # For [UserExtension] section, do special check. + # + if ItemList[0].upper() == DT.TAB_USER_EXTENSIONS.upper(): + + RetValue = ProcessUseExtHeader(ItemList) + + if not RetValue[0]: + Logger.Error('Parser', + FORMAT_INVALID, + ST.ERR_INF_PARSER_DEFINE_FROMAT_INVALID % (SectionString), + File=FileName, Line=LineNo, ExtraData=SectionString) + else: + ItemList = RetValue[1] + + if len(ItemList) == 3: + ItemList.append('COMMON') + + Str1 = ItemList[1] + + # + # For Library classes, need to check module type. + # + if ItemList[0].upper() == DT.TAB_LIBRARY_CLASSES.upper() and len(ItemList) == 3: + if ItemList[2] != '': + ModuleTypeList = GetSplitValueList(ItemList[2], DT.TAB_VALUE_SPLIT) + for Item in ModuleTypeList: + if Item.strip() not in DT.MODULE_LIST: + Logger.Error('Parser', + FORMAT_INVALID, + ST.ERR_INF_PARSER_DEFINE_MODULETYPE_INVALID % (Item), + File=FileName, + Line=LineNo, + ExtraData=SectionString) + # + # GetSpecialStr2 + # + Str2 = GetSpecialStr2(ItemList, FileName, LineNo, SectionString) + + _Scope.append([Str1, Str2]) + + _NewValueList = [] + _AppendFlag = True + if _SectionName.upper() in _PcdNameList: + for ValueItem in _ValueList: + if _SectionName.upper() == ValueItem[0].upper() and Str1.upper() not in ValueItem[1].split(): + ValueItem[1] = ValueItem[1] + " " + Str1 + _AppendFlag = False + elif _SectionName.upper() == ValueItem[0].upper() and Str1.upper() in ValueItem[1].split(): + _AppendFlag = False + + _NewValueList.append(ValueItem) + + _ValueList = _NewValueList + + if _AppendFlag: + if not ItemList[0].upper() == DT.TAB_USER_EXTENSIONS.upper(): + _ValueList.append([_SectionName, Str1, Str2, LineNo]) + else: + if len(ItemList) == 4: + _ValueList.append([_SectionName, Str1, Str2, ItemList[3], LineNo]) + + self.SectionHeaderContent = deepcopy(_ValueList) + + ## GenSpecialSectionList + # + # @param SpecialSectionList: a list of list, of which item's format + # (Comment, LineNum) + # @param ContainerFile: Input value for filename of Inf file + # + def InfSpecialCommentParser (self, SpecialSectionList, InfSectionObject, ContainerFile, SectionType): + ReFindSpecialCommentRe = re.compile(r"""#(?:\s*)\[(.*?)\](?:.*)""", re.DOTALL) + ReFindHobArchRe = re.compile(r"""[Hh][Oo][Bb]\.([^,]*)""", re.DOTALL) + if self.FileName: + pass + SpecialObjectList = [] + ArchList = [] + if SectionType == DT.TYPE_EVENT_SECTION: + TokenDict = DT.EVENT_TOKENS + elif SectionType == DT.TYPE_HOB_SECTION: + TokenDict = DT.HOB_TOKENS + else: + TokenDict = DT.BOOTMODE_TOKENS + + for List in SpecialSectionList: + # + # Hob has Arch attribute, need to be handled specially here + # + if SectionType == DT.TYPE_HOB_SECTION: + + MatchObject = ReFindSpecialCommentRe.search(List[0][0]) + HobSectionStr = MatchObject.group(1) + ArchList = [] + for Match in ReFindHobArchRe.finditer(HobSectionStr): + Arch = Match.groups(1)[0].upper() + ArchList.append(Arch) + CommentSoFar = '' + for Index in range(1, len(List)): + Result = ParseComment(List[Index], DT.ALL_USAGE_TOKENS, TokenDict, [], False) + Usage = Result[0] + Type = Result[1] + HelpText = Result[3] + + if Usage == DT.ITEM_UNDEFINED and Type == DT.ITEM_UNDEFINED: + if HelpText is None: + HelpText = '' + if not HelpText.endswith('\n'): + HelpText += '\n' + CommentSoFar += HelpText + else: + if HelpText: + CommentSoFar += HelpText + if SectionType == DT.TYPE_EVENT_SECTION: + SpecialObject = InfEventObject() + SpecialObject.SetEventType(Type) + SpecialObject.SetUsage(Usage) + SpecialObject.SetHelpString(CommentSoFar) + elif SectionType == DT.TYPE_HOB_SECTION: + SpecialObject = InfHobObject() + SpecialObject.SetHobType(Type) + SpecialObject.SetUsage(Usage) + SpecialObject.SetHelpString(CommentSoFar) + if len(ArchList) >= 1: + SpecialObject.SetSupArchList(ArchList) + else: + SpecialObject = InfBootModeObject() + SpecialObject.SetSupportedBootModes(Type) + SpecialObject.SetUsage(Usage) + SpecialObject.SetHelpString(CommentSoFar) + + SpecialObjectList.append(SpecialObject) + CommentSoFar = '' + if not InfSectionObject.SetSpecialComments(SpecialObjectList, + SectionType): + Logger.Error('InfParser', + FORMAT_INVALID, + ST.ERR_INF_PARSER_MODULE_SECTION_TYPE_ERROR % (SectionType), + ContainerFile + ) diff --git a/src/VBox/Devices/EFI/Firmware/BaseTools/Source/Python/UPT/Parser/InfSourceSectionParser.py b/src/VBox/Devices/EFI/Firmware/BaseTools/Source/Python/UPT/Parser/InfSourceSectionParser.py new file mode 100755 index 00000000..ac61177a --- /dev/null +++ b/src/VBox/Devices/EFI/Firmware/BaseTools/Source/Python/UPT/Parser/InfSourceSectionParser.py @@ -0,0 +1,139 @@ +## @file +# This file contained the parser for [Sources] sections in INF file +# +# Copyright (c) 2011 - 2018, Intel Corporation. All rights reserved.
+# +# SPDX-License-Identifier: BSD-2-Clause-Patent +# +''' +InfSourceSectionParser +''' +## +# Import Modules +# + +import Logger.Log as Logger +from Logger import StringTable as ST +from Logger.ToolError import FORMAT_INVALID +from Parser.InfParserMisc import InfExpandMacro +from Library import DataType as DT +from Library.Parsing import MacroParser +from Library.Misc import GetSplitValueList +from Object.Parser.InfCommonObject import InfLineCommentObject +from Parser.InfParserMisc import InfParserSectionRoot + +class InfSourceSectionParser(InfParserSectionRoot): + ## InfSourceParser + # + # + def InfSourceParser(self, SectionString, InfSectionObject, FileName): + SectionMacros = {} + ValueList = [] + SourceList = [] + StillCommentFalg = False + HeaderComments = [] + LineComment = None + SectionContent = '' + for Line in SectionString: + SrcLineContent = Line[0] + SrcLineNo = Line[1] + + if SrcLineContent.strip() == '': + continue + + # + # Found Header Comments + # + if SrcLineContent.strip().startswith(DT.TAB_COMMENT_SPLIT): + # + # Last line is comments, and this line go on. + # + if StillCommentFalg: + HeaderComments.append(Line) + SectionContent += SrcLineContent + DT.END_OF_LINE + continue + # + # First time encounter comment + # + else: + # + # Clear original data + # + HeaderComments = [] + HeaderComments.append(Line) + StillCommentFalg = True + SectionContent += SrcLineContent + DT.END_OF_LINE + continue + else: + StillCommentFalg = False + + if len(HeaderComments) >= 1: + LineComment = InfLineCommentObject() + LineCommentContent = '' + for Item in HeaderComments: + LineCommentContent += Item[0] + DT.END_OF_LINE + LineComment.SetHeaderComments(LineCommentContent) + + # + # Find Tail comment. + # + if SrcLineContent.find(DT.TAB_COMMENT_SPLIT) > -1: + TailComments = SrcLineContent[SrcLineContent.find(DT.TAB_COMMENT_SPLIT):] + SrcLineContent = SrcLineContent[:SrcLineContent.find(DT.TAB_COMMENT_SPLIT)] + if LineComment is None: + LineComment = InfLineCommentObject() + LineComment.SetTailComments(TailComments) + + # + # Find Macro + # + Name, Value = MacroParser((SrcLineContent, SrcLineNo), + FileName, + DT.MODEL_EFI_SOURCE_FILE, + self.FileLocalMacros) + if Name is not None: + SectionMacros[Name] = Value + LineComment = None + HeaderComments = [] + continue + + # + # Replace with Local section Macro and [Defines] section Macro. + # + SrcLineContent = InfExpandMacro(SrcLineContent, + (FileName, SrcLineContent, SrcLineNo), + self.FileLocalMacros, + SectionMacros) + + TokenList = GetSplitValueList(SrcLineContent, DT.TAB_VALUE_SPLIT, 4) + ValueList[0:len(TokenList)] = TokenList + + # + # Store section content string after MACRO replaced. + # + SectionContent += SrcLineContent + DT.END_OF_LINE + + SourceList.append((ValueList, LineComment, + (SrcLineContent, SrcLineNo, FileName))) + ValueList = [] + LineComment = None + TailComments = '' + HeaderComments = [] + continue + + # + # Current section archs + # + ArchList = [] + for Item in self.LastSectionHeaderContent: + if Item[1] not in ArchList: + ArchList.append(Item[1]) + InfSectionObject.SetSupArchList(Item[1]) + + InfSectionObject.SetAllContent(SectionContent) + if not InfSectionObject.SetSources(SourceList, Arch = ArchList): + Logger.Error('InfParser', + FORMAT_INVALID, + ST.ERR_INF_PARSER_MODULE_SECTION_TYPE_ERROR % ("[Sources]"), + File=FileName, + Line=Item[3]) diff --git a/src/VBox/Devices/EFI/Firmware/BaseTools/Source/Python/UPT/Parser/__init__.py b/src/VBox/Devices/EFI/Firmware/BaseTools/Source/Python/UPT/Parser/__init__.py new file mode 100644 index 00000000..d6922c14 --- /dev/null +++ b/src/VBox/Devices/EFI/Firmware/BaseTools/Source/Python/UPT/Parser/__init__.py @@ -0,0 +1,14 @@ +## @file +# Python 'Parser' package initialization file. +# +# This file is required to make Python interpreter treat the directory +# as containing package. +# +# Copyright (c) 2011 - 2018, Intel Corporation. All rights reserved.
+# +# SPDX-License-Identifier: BSD-2-Clause-Patent +# + +''' +Parser +''' -- cgit v1.2.3