diff options
author | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-04-11 08:17:27 +0000 |
---|---|---|
committer | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-04-11 08:17:27 +0000 |
commit | f215e02bf85f68d3a6106c2a1f4f7f063f819064 (patch) | |
tree | 6bb5b92c046312c4e95ac2620b10ddf482d3fa8b /src/VBox/Devices/EFI/Firmware/BaseTools/Source/Python/UPT/Parser/DecParser.py | |
parent | Initial commit. (diff) | |
download | virtualbox-f215e02bf85f68d3a6106c2a1f4f7f063f819064.tar.xz virtualbox-f215e02bf85f68d3a6106c2a1f4f7f063f819064.zip |
Adding upstream version 7.0.14-dfsg.upstream/7.0.14-dfsg
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to '')
-rwxr-xr-x | src/VBox/Devices/EFI/Firmware/BaseTools/Source/Python/UPT/Parser/DecParser.py | 1091 |
1 files changed, 1091 insertions, 0 deletions
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.<BR> +# +# 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" [<attribs>] "]" <EOL> <statements>+ + # 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 |