diff options
| author | kx <kx@radix.pro> | 2024-06-04 06:43:08 +0300 |
|---|---|---|
| committer | kx <kx@radix.pro> | 2024-06-04 06:43:08 +0300 |
| commit | 7e2ccccace24636f29ddc210b94606abd4c7e42b (patch) | |
| tree | 545d43ea12671048956cafeb12303e84d601e571 /BaseTools/Source/Python/UPT/Library | |
| parent | 27b044605cd5f6b33a3d231576003850b3fe305b (diff) | |
| download | edk2-trunk.tar.xz | |
Renormalized end-of-lines from master@27b044605cd5f6b33a3d231576003850b3fe305btrunk
Diffstat (limited to 'BaseTools/Source/Python/UPT/Library')
| -rw-r--r-- | BaseTools/Source/Python/UPT/Library/CommentGenerating.py | 476 | ||||
| -rw-r--r-- | BaseTools/Source/Python/UPT/Library/CommentParsing.py | 1186 | ||||
| -rw-r--r-- | BaseTools/Source/Python/UPT/Library/DataType.py | 1940 | ||||
| -rw-r--r-- | BaseTools/Source/Python/UPT/Library/ExpressionValidate.py | 1134 | ||||
| -rw-r--r-- | BaseTools/Source/Python/UPT/Library/GlobalData.py | 220 | ||||
| -rw-r--r-- | BaseTools/Source/Python/UPT/Library/Misc.py | 1978 | ||||
| -rw-r--r-- | BaseTools/Source/Python/UPT/Library/ParserValidate.py | 1454 | ||||
| -rw-r--r-- | BaseTools/Source/Python/UPT/Library/Parsing.py | 2030 | ||||
| -rw-r--r-- | BaseTools/Source/Python/UPT/Library/StringUtils.py | 1964 | ||||
| -rw-r--r-- | BaseTools/Source/Python/UPT/Library/UniClassObject.py | 2148 | ||||
| -rw-r--r-- | BaseTools/Source/Python/UPT/Library/Xml/XmlRoutines.py | 446 | ||||
| -rw-r--r-- | BaseTools/Source/Python/UPT/Library/Xml/__init__.py | 28 | ||||
| -rw-r--r-- | BaseTools/Source/Python/UPT/Library/__init__.py | 28 |
13 files changed, 7516 insertions, 7516 deletions
diff --git a/BaseTools/Source/Python/UPT/Library/CommentGenerating.py b/BaseTools/Source/Python/UPT/Library/CommentGenerating.py index bded508f56..0994cb69db 100644 --- a/BaseTools/Source/Python/UPT/Library/CommentGenerating.py +++ b/BaseTools/Source/Python/UPT/Library/CommentGenerating.py @@ -1,238 +1,238 @@ -## @file
-# This file is used to define comment generating interface
-#
-# Copyright (c) 2011 - 2018, Intel Corporation. All rights reserved.<BR>
-#
-# SPDX-License-Identifier: BSD-2-Clause-Patent
-#
-
-'''
-CommentGenerating
-'''
-
-##
-# Import Modules
-#
-from Library.StringUtils import GetSplitValueList
-from Library.DataType import TAB_SPACE_SPLIT
-from Library.DataType import TAB_INF_GUIDTYPE_VAR
-from Library.DataType import USAGE_ITEM_NOTIFY
-from Library.DataType import ITEM_UNDEFINED
-from Library.DataType import TAB_HEADER_COMMENT
-from Library.DataType import TAB_BINARY_HEADER_COMMENT
-from Library.DataType import TAB_COMMENT_SPLIT
-from Library.DataType import TAB_SPECIAL_COMMENT
-from Library.DataType import END_OF_LINE
-from Library.DataType import TAB_COMMENT_EDK1_SPLIT
-from Library.DataType import TAB_COMMENT_EDK1_START
-from Library.DataType import TAB_COMMENT_EDK1_END
-from Library.DataType import TAB_STAR
-from Library.DataType import TAB_PCD_PROMPT
-from Library.UniClassObject import ConvertSpecialUnicodes
-from Library.Misc import GetLocalValue
-## GenTailCommentLines
-#
-# @param TailCommentLines: the tail comment lines that need to be generated
-# @param LeadingSpaceNum: the number of leading space needed for non-first
-# line tail comment
-#
-def GenTailCommentLines (TailCommentLines, LeadingSpaceNum = 0):
- TailCommentLines = TailCommentLines.rstrip(END_OF_LINE)
- CommentStr = TAB_SPACE_SPLIT*2 + TAB_SPECIAL_COMMENT + TAB_SPACE_SPLIT + \
- (END_OF_LINE + LeadingSpaceNum * TAB_SPACE_SPLIT + TAB_SPACE_SPLIT*2 + TAB_SPECIAL_COMMENT + \
- TAB_SPACE_SPLIT).join(GetSplitValueList(TailCommentLines, END_OF_LINE))
-
- return CommentStr
-
-## GenGenericComment
-#
-# @param CommentLines: Generic comment Text, maybe Multiple Lines
-#
-def GenGenericComment (CommentLines):
- if not CommentLines:
- return ''
- CommentLines = CommentLines.rstrip(END_OF_LINE)
- CommentStr = TAB_SPECIAL_COMMENT + TAB_SPACE_SPLIT + (END_OF_LINE + TAB_COMMENT_SPLIT + TAB_SPACE_SPLIT).join\
- (GetSplitValueList(CommentLines, END_OF_LINE)) + END_OF_LINE
- return CommentStr
-
-## GenGenericCommentF
-#
-# similar to GenGenericComment but will remove <EOL> at end of comment once,
-# and for line with only <EOL>, '#\n' will be generated instead of '# \n'
-#
-# @param CommentLines: Generic comment Text, maybe Multiple Lines
-# @return CommentStr: Generated comment line
-#
-def GenGenericCommentF (CommentLines, NumOfPound=1, IsPrompt=False, IsInfLibraryClass=False):
- if not CommentLines:
- return ''
- #
- # if comment end with '\n', then remove it to prevent one extra line
- # generate later on
- #
- if CommentLines.endswith(END_OF_LINE):
- CommentLines = CommentLines[:-1]
- CommentStr = ''
- if IsPrompt:
- CommentStr += TAB_COMMENT_SPLIT * NumOfPound + TAB_SPACE_SPLIT + TAB_PCD_PROMPT + TAB_SPACE_SPLIT + \
- CommentLines.replace(END_OF_LINE, '') + END_OF_LINE
- else:
- CommentLineList = GetSplitValueList(CommentLines, END_OF_LINE)
- FindLibraryClass = False
- for Line in CommentLineList:
- # If this comment is for @libraryclass and it has multiple lines
- # make sure the second lines align to the first line after @libraryclass as below
- #
- # ## @libraryclass XYZ FIRST_LINE
- # ## ABC SECOND_LINE
- #
- if IsInfLibraryClass and Line.find(u'@libraryclass ') > -1:
- FindLibraryClass = True
- if Line == '':
- CommentStr += TAB_COMMENT_SPLIT * NumOfPound + END_OF_LINE
- else:
- if FindLibraryClass and Line.find(u'@libraryclass ') > -1:
- CommentStr += TAB_COMMENT_SPLIT * NumOfPound + TAB_SPACE_SPLIT + Line + END_OF_LINE
- elif FindLibraryClass:
- CommentStr += TAB_COMMENT_SPLIT * NumOfPound + TAB_SPACE_SPLIT * 16 + Line + END_OF_LINE
- else:
- CommentStr += TAB_COMMENT_SPLIT * NumOfPound + TAB_SPACE_SPLIT + Line + END_OF_LINE
-
- return CommentStr
-
-
-## GenHeaderCommentSection
-#
-# Generate Header comment sections
-#
-# @param Abstract One line of abstract
-# @param Description multiple lines of Description
-# @param Copyright possible multiple copyright lines
-# @param License possible multiple license lines
-#
-def GenHeaderCommentSection(Abstract, Description, Copyright, License, IsBinaryHeader=False, \
- CommChar=TAB_COMMENT_SPLIT):
- Content = ''
-
- #
- # Convert special character to (c), (r) and (tm).
- #
- Abstract = ConvertSpecialUnicodes(Abstract)
- Description = ConvertSpecialUnicodes(Description)
- if IsBinaryHeader:
- Content += CommChar * 2 + TAB_SPACE_SPLIT + TAB_BINARY_HEADER_COMMENT + '\r\n'
- elif CommChar == TAB_COMMENT_EDK1_SPLIT:
- Content += CommChar + TAB_SPACE_SPLIT + TAB_COMMENT_EDK1_START + TAB_STAR + TAB_SPACE_SPLIT +\
- TAB_HEADER_COMMENT + '\r\n'
- else:
- Content += CommChar * 2 + TAB_SPACE_SPLIT + TAB_HEADER_COMMENT + '\r\n'
- if Abstract:
- Abstract = Abstract.rstrip('\r\n')
- Content += CommChar + TAB_SPACE_SPLIT + ('\r\n' + CommChar + TAB_SPACE_SPLIT).join(GetSplitValueList\
- (Abstract, '\n'))
- Content += '\r\n' + CommChar + '\r\n'
- else:
- Content += CommChar + '\r\n'
-
- if Description:
- Description = Description.rstrip('\r\n')
- Content += CommChar + TAB_SPACE_SPLIT + ('\r\n' + CommChar + TAB_SPACE_SPLIT).join(GetSplitValueList\
- (Description, '\n'))
- Content += '\r\n' + CommChar + '\r\n'
-
- #
- # There is no '#\n' line to separate multiple copyright lines in code base
- #
- if Copyright:
- Copyright = Copyright.rstrip('\r\n')
- Content += CommChar + TAB_SPACE_SPLIT + ('\r\n' + CommChar + TAB_SPACE_SPLIT).join\
- (GetSplitValueList(Copyright, '\n'))
- Content += '\r\n' + CommChar + '\r\n'
-
- if License:
- License = License.rstrip('\r\n')
- Content += CommChar + TAB_SPACE_SPLIT + ('\r\n' + CommChar + TAB_SPACE_SPLIT).join(GetSplitValueList\
- (License, '\n'))
- Content += '\r\n' + CommChar + '\r\n'
-
- if CommChar == TAB_COMMENT_EDK1_SPLIT:
- Content += CommChar + TAB_SPACE_SPLIT + TAB_STAR + TAB_COMMENT_EDK1_END + '\r\n'
- else:
- Content += CommChar * 2 + '\r\n'
-
- return Content
-
-
-## GenInfPcdTailComment
-# Generate Pcd tail comment for Inf, this would be one line comment
-#
-# @param Usage: Usage type
-# @param TailCommentText: Comment text for tail comment
-#
-def GenInfPcdTailComment (Usage, TailCommentText):
- if (Usage == ITEM_UNDEFINED) and (not TailCommentText):
- return ''
-
- CommentLine = TAB_SPACE_SPLIT.join([Usage, TailCommentText])
- return GenTailCommentLines(CommentLine)
-
-## GenInfProtocolPPITailComment
-# Generate Protocol/PPI tail comment for Inf
-#
-# @param Usage: Usage type
-# @param TailCommentText: Comment text for tail comment
-#
-def GenInfProtocolPPITailComment (Usage, Notify, TailCommentText):
- if (not Notify) and (Usage == ITEM_UNDEFINED) and (not TailCommentText):
- return ''
-
- if Notify:
- CommentLine = USAGE_ITEM_NOTIFY + " ## "
- else:
- CommentLine = ''
-
- CommentLine += TAB_SPACE_SPLIT.join([Usage, TailCommentText])
- return GenTailCommentLines(CommentLine)
-
-## GenInfGuidTailComment
-# Generate Guid tail comment for Inf
-#
-# @param Usage: Usage type
-# @param TailCommentText: Comment text for tail comment
-#
-def GenInfGuidTailComment (Usage, GuidTypeList, VariableName, TailCommentText):
- GuidType = GuidTypeList[0]
- if (Usage == ITEM_UNDEFINED) and (GuidType == ITEM_UNDEFINED) and \
- (not TailCommentText):
- return ''
-
- FirstLine = Usage + " ## " + GuidType
- if GuidType == TAB_INF_GUIDTYPE_VAR:
- FirstLine += ":" + VariableName
-
- CommentLine = TAB_SPACE_SPLIT.join([FirstLine, TailCommentText])
- return GenTailCommentLines(CommentLine)
-
-## GenDecGuidTailComment
-#
-# @param SupModuleList: Supported module type list
-#
-def GenDecTailComment (SupModuleList):
- CommentLine = TAB_SPACE_SPLIT.join(SupModuleList)
- return GenTailCommentLines(CommentLine)
-
-
-## _GetHelpStr
-# get HelpString from a list of HelpTextObject, the priority refer to
-# related HLD
-#
-# @param HelpTextObjList: List of HelpTextObject
-#
-# @return HelpStr: the help text string found, '' means no help text found
-#
-def _GetHelpStr(HelpTextObjList):
- ValueList = []
- for HelpObj in HelpTextObjList:
- ValueList.append((HelpObj.GetLang(), HelpObj.GetString()))
- return GetLocalValue(ValueList, True)
+## @file +# This file is used to define comment generating interface +# +# Copyright (c) 2011 - 2018, Intel Corporation. All rights reserved.<BR> +# +# SPDX-License-Identifier: BSD-2-Clause-Patent +# + +''' +CommentGenerating +''' + +## +# Import Modules +# +from Library.StringUtils import GetSplitValueList +from Library.DataType import TAB_SPACE_SPLIT +from Library.DataType import TAB_INF_GUIDTYPE_VAR +from Library.DataType import USAGE_ITEM_NOTIFY +from Library.DataType import ITEM_UNDEFINED +from Library.DataType import TAB_HEADER_COMMENT +from Library.DataType import TAB_BINARY_HEADER_COMMENT +from Library.DataType import TAB_COMMENT_SPLIT +from Library.DataType import TAB_SPECIAL_COMMENT +from Library.DataType import END_OF_LINE +from Library.DataType import TAB_COMMENT_EDK1_SPLIT +from Library.DataType import TAB_COMMENT_EDK1_START +from Library.DataType import TAB_COMMENT_EDK1_END +from Library.DataType import TAB_STAR +from Library.DataType import TAB_PCD_PROMPT +from Library.UniClassObject import ConvertSpecialUnicodes +from Library.Misc import GetLocalValue +## GenTailCommentLines +# +# @param TailCommentLines: the tail comment lines that need to be generated +# @param LeadingSpaceNum: the number of leading space needed for non-first +# line tail comment +# +def GenTailCommentLines (TailCommentLines, LeadingSpaceNum = 0): + TailCommentLines = TailCommentLines.rstrip(END_OF_LINE) + CommentStr = TAB_SPACE_SPLIT*2 + TAB_SPECIAL_COMMENT + TAB_SPACE_SPLIT + \ + (END_OF_LINE + LeadingSpaceNum * TAB_SPACE_SPLIT + TAB_SPACE_SPLIT*2 + TAB_SPECIAL_COMMENT + \ + TAB_SPACE_SPLIT).join(GetSplitValueList(TailCommentLines, END_OF_LINE)) + + return CommentStr + +## GenGenericComment +# +# @param CommentLines: Generic comment Text, maybe Multiple Lines +# +def GenGenericComment (CommentLines): + if not CommentLines: + return '' + CommentLines = CommentLines.rstrip(END_OF_LINE) + CommentStr = TAB_SPECIAL_COMMENT + TAB_SPACE_SPLIT + (END_OF_LINE + TAB_COMMENT_SPLIT + TAB_SPACE_SPLIT).join\ + (GetSplitValueList(CommentLines, END_OF_LINE)) + END_OF_LINE + return CommentStr + +## GenGenericCommentF +# +# similar to GenGenericComment but will remove <EOL> at end of comment once, +# and for line with only <EOL>, '#\n' will be generated instead of '# \n' +# +# @param CommentLines: Generic comment Text, maybe Multiple Lines +# @return CommentStr: Generated comment line +# +def GenGenericCommentF (CommentLines, NumOfPound=1, IsPrompt=False, IsInfLibraryClass=False): + if not CommentLines: + return '' + # + # if comment end with '\n', then remove it to prevent one extra line + # generate later on + # + if CommentLines.endswith(END_OF_LINE): + CommentLines = CommentLines[:-1] + CommentStr = '' + if IsPrompt: + CommentStr += TAB_COMMENT_SPLIT * NumOfPound + TAB_SPACE_SPLIT + TAB_PCD_PROMPT + TAB_SPACE_SPLIT + \ + CommentLines.replace(END_OF_LINE, '') + END_OF_LINE + else: + CommentLineList = GetSplitValueList(CommentLines, END_OF_LINE) + FindLibraryClass = False + for Line in CommentLineList: + # If this comment is for @libraryclass and it has multiple lines + # make sure the second lines align to the first line after @libraryclass as below + # + # ## @libraryclass XYZ FIRST_LINE + # ## ABC SECOND_LINE + # + if IsInfLibraryClass and Line.find(u'@libraryclass ') > -1: + FindLibraryClass = True + if Line == '': + CommentStr += TAB_COMMENT_SPLIT * NumOfPound + END_OF_LINE + else: + if FindLibraryClass and Line.find(u'@libraryclass ') > -1: + CommentStr += TAB_COMMENT_SPLIT * NumOfPound + TAB_SPACE_SPLIT + Line + END_OF_LINE + elif FindLibraryClass: + CommentStr += TAB_COMMENT_SPLIT * NumOfPound + TAB_SPACE_SPLIT * 16 + Line + END_OF_LINE + else: + CommentStr += TAB_COMMENT_SPLIT * NumOfPound + TAB_SPACE_SPLIT + Line + END_OF_LINE + + return CommentStr + + +## GenHeaderCommentSection +# +# Generate Header comment sections +# +# @param Abstract One line of abstract +# @param Description multiple lines of Description +# @param Copyright possible multiple copyright lines +# @param License possible multiple license lines +# +def GenHeaderCommentSection(Abstract, Description, Copyright, License, IsBinaryHeader=False, \ + CommChar=TAB_COMMENT_SPLIT): + Content = '' + + # + # Convert special character to (c), (r) and (tm). + # + Abstract = ConvertSpecialUnicodes(Abstract) + Description = ConvertSpecialUnicodes(Description) + if IsBinaryHeader: + Content += CommChar * 2 + TAB_SPACE_SPLIT + TAB_BINARY_HEADER_COMMENT + '\r\n' + elif CommChar == TAB_COMMENT_EDK1_SPLIT: + Content += CommChar + TAB_SPACE_SPLIT + TAB_COMMENT_EDK1_START + TAB_STAR + TAB_SPACE_SPLIT +\ + TAB_HEADER_COMMENT + '\r\n' + else: + Content += CommChar * 2 + TAB_SPACE_SPLIT + TAB_HEADER_COMMENT + '\r\n' + if Abstract: + Abstract = Abstract.rstrip('\r\n') + Content += CommChar + TAB_SPACE_SPLIT + ('\r\n' + CommChar + TAB_SPACE_SPLIT).join(GetSplitValueList\ + (Abstract, '\n')) + Content += '\r\n' + CommChar + '\r\n' + else: + Content += CommChar + '\r\n' + + if Description: + Description = Description.rstrip('\r\n') + Content += CommChar + TAB_SPACE_SPLIT + ('\r\n' + CommChar + TAB_SPACE_SPLIT).join(GetSplitValueList\ + (Description, '\n')) + Content += '\r\n' + CommChar + '\r\n' + + # + # There is no '#\n' line to separate multiple copyright lines in code base + # + if Copyright: + Copyright = Copyright.rstrip('\r\n') + Content += CommChar + TAB_SPACE_SPLIT + ('\r\n' + CommChar + TAB_SPACE_SPLIT).join\ + (GetSplitValueList(Copyright, '\n')) + Content += '\r\n' + CommChar + '\r\n' + + if License: + License = License.rstrip('\r\n') + Content += CommChar + TAB_SPACE_SPLIT + ('\r\n' + CommChar + TAB_SPACE_SPLIT).join(GetSplitValueList\ + (License, '\n')) + Content += '\r\n' + CommChar + '\r\n' + + if CommChar == TAB_COMMENT_EDK1_SPLIT: + Content += CommChar + TAB_SPACE_SPLIT + TAB_STAR + TAB_COMMENT_EDK1_END + '\r\n' + else: + Content += CommChar * 2 + '\r\n' + + return Content + + +## GenInfPcdTailComment +# Generate Pcd tail comment for Inf, this would be one line comment +# +# @param Usage: Usage type +# @param TailCommentText: Comment text for tail comment +# +def GenInfPcdTailComment (Usage, TailCommentText): + if (Usage == ITEM_UNDEFINED) and (not TailCommentText): + return '' + + CommentLine = TAB_SPACE_SPLIT.join([Usage, TailCommentText]) + return GenTailCommentLines(CommentLine) + +## GenInfProtocolPPITailComment +# Generate Protocol/PPI tail comment for Inf +# +# @param Usage: Usage type +# @param TailCommentText: Comment text for tail comment +# +def GenInfProtocolPPITailComment (Usage, Notify, TailCommentText): + if (not Notify) and (Usage == ITEM_UNDEFINED) and (not TailCommentText): + return '' + + if Notify: + CommentLine = USAGE_ITEM_NOTIFY + " ## " + else: + CommentLine = '' + + CommentLine += TAB_SPACE_SPLIT.join([Usage, TailCommentText]) + return GenTailCommentLines(CommentLine) + +## GenInfGuidTailComment +# Generate Guid tail comment for Inf +# +# @param Usage: Usage type +# @param TailCommentText: Comment text for tail comment +# +def GenInfGuidTailComment (Usage, GuidTypeList, VariableName, TailCommentText): + GuidType = GuidTypeList[0] + if (Usage == ITEM_UNDEFINED) and (GuidType == ITEM_UNDEFINED) and \ + (not TailCommentText): + return '' + + FirstLine = Usage + " ## " + GuidType + if GuidType == TAB_INF_GUIDTYPE_VAR: + FirstLine += ":" + VariableName + + CommentLine = TAB_SPACE_SPLIT.join([FirstLine, TailCommentText]) + return GenTailCommentLines(CommentLine) + +## GenDecGuidTailComment +# +# @param SupModuleList: Supported module type list +# +def GenDecTailComment (SupModuleList): + CommentLine = TAB_SPACE_SPLIT.join(SupModuleList) + return GenTailCommentLines(CommentLine) + + +## _GetHelpStr +# get HelpString from a list of HelpTextObject, the priority refer to +# related HLD +# +# @param HelpTextObjList: List of HelpTextObject +# +# @return HelpStr: the help text string found, '' means no help text found +# +def _GetHelpStr(HelpTextObjList): + ValueList = [] + for HelpObj in HelpTextObjList: + ValueList.append((HelpObj.GetLang(), HelpObj.GetString())) + return GetLocalValue(ValueList, True) diff --git a/BaseTools/Source/Python/UPT/Library/CommentParsing.py b/BaseTools/Source/Python/UPT/Library/CommentParsing.py index 7ba9830d34..3f45035882 100644 --- a/BaseTools/Source/Python/UPT/Library/CommentParsing.py +++ b/BaseTools/Source/Python/UPT/Library/CommentParsing.py @@ -1,593 +1,593 @@ -## @file
-# This file is used to define comment parsing interface
-#
-# Copyright (c) 2011 - 2018, Intel Corporation. All rights reserved.<BR>
-#
-# SPDX-License-Identifier: BSD-2-Clause-Patent
-#
-
-'''
-CommentParsing
-'''
-
-##
-# Import Modules
-#
-import re
-
-from Library.StringUtils import GetSplitValueList
-from Library.StringUtils import CleanString2
-from Library.DataType import HEADER_COMMENT_NOT_STARTED
-from Library.DataType import TAB_COMMENT_SPLIT
-from Library.DataType import HEADER_COMMENT_LICENSE
-from Library.DataType import HEADER_COMMENT_ABSTRACT
-from Library.DataType import HEADER_COMMENT_COPYRIGHT
-from Library.DataType import HEADER_COMMENT_DESCRIPTION
-from Library.DataType import TAB_SPACE_SPLIT
-from Library.DataType import TAB_COMMA_SPLIT
-from Library.DataType import SUP_MODULE_LIST
-from Library.DataType import TAB_VALUE_SPLIT
-from Library.DataType import TAB_PCD_VALIDRANGE
-from Library.DataType import TAB_PCD_VALIDLIST
-from Library.DataType import TAB_PCD_EXPRESSION
-from Library.DataType import TAB_PCD_PROMPT
-from Library.DataType import TAB_CAPHEX_START
-from Library.DataType import TAB_HEX_START
-from Library.DataType import PCD_ERR_CODE_MAX_SIZE
-from Library.ExpressionValidate import IsValidRangeExpr
-from Library.ExpressionValidate import IsValidListExpr
-from Library.ExpressionValidate import IsValidLogicalExpr
-from Object.POM.CommonObject import TextObject
-from Object.POM.CommonObject import PcdErrorObject
-import Logger.Log as Logger
-from Logger.ToolError import FORMAT_INVALID
-from Logger.ToolError import FORMAT_NOT_SUPPORTED
-from Logger import StringTable as ST
-
-## ParseHeaderCommentSection
-#
-# Parse Header comment section lines, extract Abstract, Description, Copyright
-# , License lines
-#
-# @param CommentList: List of (Comment, LineNumber)
-# @param FileName: FileName of the comment
-#
-def ParseHeaderCommentSection(CommentList, FileName = None, IsBinaryHeader = False):
- Abstract = ''
- Description = ''
- Copyright = ''
- License = ''
- EndOfLine = "\n"
- if IsBinaryHeader:
- STR_HEADER_COMMENT_START = "@BinaryHeader"
- else:
- STR_HEADER_COMMENT_START = "@file"
- HeaderCommentStage = HEADER_COMMENT_NOT_STARTED
-
- #
- # first find the last copyright line
- #
- Last = 0
- for Index in range(len(CommentList)-1, 0, -1):
- Line = CommentList[Index][0]
- if _IsCopyrightLine(Line):
- Last = Index
- break
-
- for Item in CommentList:
- Line = Item[0]
- LineNo = Item[1]
-
- if not Line.startswith(TAB_COMMENT_SPLIT) and Line:
- Logger.Error("\nUPT", FORMAT_INVALID, ST.ERR_INVALID_COMMENT_FORMAT, FileName, Item[1])
- Comment = CleanString2(Line)[1]
- Comment = Comment.strip()
- #
- # if there are blank lines between License or Description, keep them as they would be
- # indication of different block; or in the position that Abstract should be, also keep it
- # as it indicates that no abstract
- #
- if not Comment and HeaderCommentStage not in [HEADER_COMMENT_LICENSE, \
- HEADER_COMMENT_DESCRIPTION, HEADER_COMMENT_ABSTRACT]:
- continue
-
- if HeaderCommentStage == HEADER_COMMENT_NOT_STARTED:
- if Comment.startswith(STR_HEADER_COMMENT_START):
- HeaderCommentStage = HEADER_COMMENT_ABSTRACT
- else:
- License += Comment + EndOfLine
- else:
- if HeaderCommentStage == HEADER_COMMENT_ABSTRACT:
- #
- # in case there is no abstract and description
- #
- if not Comment:
- HeaderCommentStage = HEADER_COMMENT_DESCRIPTION
- elif _IsCopyrightLine(Comment):
- Result, ErrMsg = _ValidateCopyright(Comment)
- ValidateCopyright(Result, ST.WRN_INVALID_COPYRIGHT, FileName, LineNo, ErrMsg)
- Copyright += Comment + EndOfLine
- HeaderCommentStage = HEADER_COMMENT_COPYRIGHT
- else:
- Abstract += Comment + EndOfLine
- HeaderCommentStage = HEADER_COMMENT_DESCRIPTION
- elif HeaderCommentStage == HEADER_COMMENT_DESCRIPTION:
- #
- # in case there is no description
- #
- if _IsCopyrightLine(Comment):
- Result, ErrMsg = _ValidateCopyright(Comment)
- ValidateCopyright(Result, ST.WRN_INVALID_COPYRIGHT, FileName, LineNo, ErrMsg)
- Copyright += Comment + EndOfLine
- HeaderCommentStage = HEADER_COMMENT_COPYRIGHT
- else:
- Description += Comment + EndOfLine
- elif HeaderCommentStage == HEADER_COMMENT_COPYRIGHT:
- if _IsCopyrightLine(Comment):
- Result, ErrMsg = _ValidateCopyright(Comment)
- ValidateCopyright(Result, ST.WRN_INVALID_COPYRIGHT, FileName, LineNo, ErrMsg)
- Copyright += Comment + EndOfLine
- else:
- #
- # Contents after copyright line are license, those non-copyright lines in between
- # copyright line will be discarded
- #
- if LineNo > Last:
- if License:
- License += EndOfLine
- License += Comment + EndOfLine
- HeaderCommentStage = HEADER_COMMENT_LICENSE
- else:
- if not Comment and not License:
- continue
- License += Comment + EndOfLine
-
- return Abstract.strip(), Description.strip(), Copyright.strip(), License.strip()
-
-## _IsCopyrightLine
-# check whether current line is copyright line, the criteria is whether there is case insensitive keyword "Copyright"
-# followed by zero or more white space characters followed by a "(" character
-#
-# @param LineContent: the line need to be checked
-# @return: True if current line is copyright line, False else
-#
-def _IsCopyrightLine (LineContent):
- LineContent = LineContent.upper()
- Result = False
-
- ReIsCopyrightRe = re.compile(r"""(^|\s)COPYRIGHT *\(""", re.DOTALL)
- if ReIsCopyrightRe.search(LineContent):
- Result = True
-
- return Result
-
-## ParseGenericComment
-#
-# @param GenericComment: Generic comment list, element of
-# (CommentLine, LineNum)
-# @param ContainerFile: Input value for filename of Dec file
-#
-def ParseGenericComment (GenericComment, ContainerFile=None, SkipTag=None):
- if ContainerFile:
- pass
- HelpTxt = None
- HelpStr = ''
-
- for Item in GenericComment:
- CommentLine = Item[0]
- Comment = CleanString2(CommentLine)[1]
- if SkipTag is not None and Comment.startswith(SkipTag):
- Comment = Comment.replace(SkipTag, '', 1)
- HelpStr += Comment + '\n'
-
- if HelpStr:
- HelpTxt = TextObject()
- if HelpStr.endswith('\n') and not HelpStr.endswith('\n\n') and HelpStr != '\n':
- HelpStr = HelpStr[:-1]
- HelpTxt.SetString(HelpStr)
-
- return HelpTxt
-
-## ParsePcdErrorCode
-#
-# @param Value: original ErrorCode value
-# @param ContainerFile: Input value for filename of Dec file
-# @param LineNum: Line Num
-#
-def ParsePcdErrorCode (Value = None, ContainerFile = None, LineNum = None):
- try:
- if Value.strip().startswith((TAB_HEX_START, TAB_CAPHEX_START)):
- Base = 16
- else:
- Base = 10
- ErrorCode = int(Value, Base)
- if ErrorCode > PCD_ERR_CODE_MAX_SIZE or ErrorCode < 0:
- Logger.Error('Parser',
- FORMAT_NOT_SUPPORTED,
- "The format %s of ErrorCode is not valid, should be UNIT32 type or long type" % Value,
- File = ContainerFile,
- Line = LineNum)
- ErrorCode = '0x%x' % ErrorCode
- return ErrorCode
- except ValueError as XStr:
- if XStr:
- pass
- Logger.Error('Parser',
- FORMAT_NOT_SUPPORTED,
- "The format %s of ErrorCode is not valid, should be UNIT32 type or long type" % Value,
- File = ContainerFile,
- Line = LineNum)
-
-## ParseDecPcdGenericComment
-#
-# @param GenericComment: Generic comment list, element of (CommentLine,
-# LineNum)
-# @param ContainerFile: Input value for filename of Dec file
-#
-def ParseDecPcdGenericComment (GenericComment, ContainerFile, TokenSpaceGuidCName, CName, MacroReplaceDict):
- HelpStr = ''
- PromptStr = ''
- PcdErr = None
- PcdErrList = []
- ValidValueNum = 0
- ValidRangeNum = 0
- ExpressionNum = 0
-
- for (CommentLine, LineNum) in GenericComment:
- Comment = CleanString2(CommentLine)[1]
- #
- # To replace Macro
- #
- MACRO_PATTERN = '[\t\s]*\$\([A-Z][_A-Z0-9]*\)'
- MatchedStrs = re.findall(MACRO_PATTERN, Comment)
- for MatchedStr in MatchedStrs:
- if MatchedStr:
- Macro = MatchedStr.strip().lstrip('$(').rstrip(')').strip()
- if Macro in MacroReplaceDict:
- Comment = Comment.replace(MatchedStr, MacroReplaceDict[Macro])
- if Comment.startswith(TAB_PCD_VALIDRANGE):
- if ValidValueNum > 0 or ExpressionNum > 0:
- Logger.Error('Parser',
- FORMAT_NOT_SUPPORTED,
- ST.WRN_MULTI_PCD_RANGES,
- File = ContainerFile,
- Line = LineNum)
- else:
- PcdErr = PcdErrorObject()
- PcdErr.SetTokenSpaceGuidCName(TokenSpaceGuidCName)
- PcdErr.SetCName(CName)
- PcdErr.SetFileLine(Comment)
- PcdErr.SetLineNum(LineNum)
- ValidRangeNum += 1
- ValidRange = Comment.replace(TAB_PCD_VALIDRANGE, "", 1).strip()
- Valid, Cause = _CheckRangeExpression(ValidRange)
- if Valid:
- ValueList = ValidRange.split(TAB_VALUE_SPLIT)
- if len(ValueList) > 1:
- PcdErr.SetValidValueRange((TAB_VALUE_SPLIT.join(ValueList[1:])).strip())
- PcdErr.SetErrorNumber(ParsePcdErrorCode(ValueList[0], ContainerFile, LineNum))
- else:
- PcdErr.SetValidValueRange(ValidRange)
- PcdErrList.append(PcdErr)
- else:
- Logger.Error("Parser",
- FORMAT_NOT_SUPPORTED,
- Cause,
- ContainerFile,
- LineNum)
- elif Comment.startswith(TAB_PCD_VALIDLIST):
- if ValidRangeNum > 0 or ExpressionNum > 0:
- Logger.Error('Parser',
- FORMAT_NOT_SUPPORTED,
- ST.WRN_MULTI_PCD_RANGES,
- File = ContainerFile,
- Line = LineNum)
- elif ValidValueNum > 0:
- Logger.Error('Parser',
- FORMAT_NOT_SUPPORTED,
- ST.WRN_MULTI_PCD_VALIDVALUE,
- File = ContainerFile,
- Line = LineNum)
- else:
- PcdErr = PcdErrorObject()
- PcdErr.SetTokenSpaceGuidCName(TokenSpaceGuidCName)
- PcdErr.SetCName(CName)
- PcdErr.SetFileLine(Comment)
- PcdErr.SetLineNum(LineNum)
- ValidValueNum += 1
- ValidValueExpr = Comment.replace(TAB_PCD_VALIDLIST, "", 1).strip()
- Valid, Cause = _CheckListExpression(ValidValueExpr)
- if Valid:
- ValidValue = Comment.replace(TAB_PCD_VALIDLIST, "", 1).replace(TAB_COMMA_SPLIT, TAB_SPACE_SPLIT)
- ValueList = ValidValue.split(TAB_VALUE_SPLIT)
- if len(ValueList) > 1:
- PcdErr.SetValidValue((TAB_VALUE_SPLIT.join(ValueList[1:])).strip())
- PcdErr.SetErrorNumber(ParsePcdErrorCode(ValueList[0], ContainerFile, LineNum))
- else:
- PcdErr.SetValidValue(ValidValue)
- PcdErrList.append(PcdErr)
- else:
- Logger.Error("Parser",
- FORMAT_NOT_SUPPORTED,
- Cause,
- ContainerFile,
- LineNum)
- elif Comment.startswith(TAB_PCD_EXPRESSION):
- if ValidRangeNum > 0 or ValidValueNum > 0:
- Logger.Error('Parser',
- FORMAT_NOT_SUPPORTED,
- ST.WRN_MULTI_PCD_RANGES,
- File = ContainerFile,
- Line = LineNum)
- else:
- PcdErr = PcdErrorObject()
- PcdErr.SetTokenSpaceGuidCName(TokenSpaceGuidCName)
- PcdErr.SetCName(CName)
- PcdErr.SetFileLine(Comment)
- PcdErr.SetLineNum(LineNum)
- ExpressionNum += 1
- Expression = Comment.replace(TAB_PCD_EXPRESSION, "", 1).strip()
- Valid, Cause = _CheckExpression(Expression)
- if Valid:
- ValueList = Expression.split(TAB_VALUE_SPLIT)
- if len(ValueList) > 1:
- PcdErr.SetExpression((TAB_VALUE_SPLIT.join(ValueList[1:])).strip())
- PcdErr.SetErrorNumber(ParsePcdErrorCode(ValueList[0], ContainerFile, LineNum))
- else:
- PcdErr.SetExpression(Expression)
- PcdErrList.append(PcdErr)
- else:
- Logger.Error("Parser",
- FORMAT_NOT_SUPPORTED,
- Cause,
- ContainerFile,
- LineNum)
- elif Comment.startswith(TAB_PCD_PROMPT):
- if PromptStr:
- Logger.Error('Parser',
- FORMAT_NOT_SUPPORTED,
- ST.WRN_MULTI_PCD_PROMPT,
- File = ContainerFile,
- Line = LineNum)
- PromptStr = Comment.replace(TAB_PCD_PROMPT, "", 1).strip()
- else:
- if Comment:
- HelpStr += Comment + '\n'
-
- #
- # remove the last EOL if the comment is of format 'FOO\n'
- #
- if HelpStr.endswith('\n'):
- if HelpStr != '\n' and not HelpStr.endswith('\n\n'):
- HelpStr = HelpStr[:-1]
-
- return HelpStr, PcdErrList, PromptStr
-
-## ParseDecPcdTailComment
-#
-# @param TailCommentList: Tail comment list of Pcd, item of format (Comment, LineNum)
-# @param ContainerFile: Input value for filename of Dec file
-# @retVal SupModuleList: The supported module type list detected
-# @retVal HelpStr: The generic help text string detected
-#
-def ParseDecPcdTailComment (TailCommentList, ContainerFile):
- assert(len(TailCommentList) == 1)
- TailComment = TailCommentList[0][0]
- LineNum = TailCommentList[0][1]
-
- Comment = TailComment.lstrip(" #")
-
- ReFindFirstWordRe = re.compile(r"""^([^ #]*)""", re.DOTALL)
-
- #
- # get first word and compare with SUP_MODULE_LIST
- #
- MatchObject = ReFindFirstWordRe.match(Comment)
- if not (MatchObject and MatchObject.group(1) in SUP_MODULE_LIST):
- return None, Comment
-
- #
- # parse line, it must have supported module type specified
- #
- if Comment.find(TAB_COMMENT_SPLIT) == -1:
- Comment += TAB_COMMENT_SPLIT
- SupMode, HelpStr = GetSplitValueList(Comment, TAB_COMMENT_SPLIT, 1)
- SupModuleList = []
- for Mod in GetSplitValueList(SupMode, TAB_SPACE_SPLIT):
- if not Mod:
- continue
- elif Mod not in SUP_MODULE_LIST:
- Logger.Error("UPT",
- FORMAT_INVALID,
- ST.WRN_INVALID_MODULE_TYPE%Mod,
- ContainerFile,
- LineNum)
- else:
- SupModuleList.append(Mod)
-
- return SupModuleList, HelpStr
-
-## _CheckListExpression
-#
-# @param Expression: Pcd value list expression
-#
-def _CheckListExpression(Expression):
- ListExpr = ''
- if TAB_VALUE_SPLIT in Expression:
- ListExpr = Expression[Expression.find(TAB_VALUE_SPLIT)+1:]
- else:
- ListExpr = Expression
-
- return IsValidListExpr(ListExpr)
-
-## _CheckExpression
-#
-# @param Expression: Pcd value expression
-#
-def _CheckExpression(Expression):
- Expr = ''
- if TAB_VALUE_SPLIT in Expression:
- Expr = Expression[Expression.find(TAB_VALUE_SPLIT)+1:]
- else:
- Expr = Expression
- return IsValidLogicalExpr(Expr, True)
-
-## _CheckRangeExpression
-#
-# @param Expression: Pcd range expression
-#
-def _CheckRangeExpression(Expression):
- RangeExpr = ''
- if TAB_VALUE_SPLIT in Expression:
- RangeExpr = Expression[Expression.find(TAB_VALUE_SPLIT)+1:]
- else:
- RangeExpr = Expression
-
- return IsValidRangeExpr(RangeExpr)
-
-## ValidateCopyright
-#
-#
-#
-def ValidateCopyright(Result, ErrType, FileName, LineNo, ErrMsg):
- if not Result:
- Logger.Warn("\nUPT", ErrType, FileName, LineNo, ErrMsg)
-
-## _ValidateCopyright
-#
-# @param Line: Line that contains copyright information, # stripped
-#
-# @retval Result: True if line is conformed to Spec format, False else
-# @retval ErrMsg: the detailed error description
-#
-def _ValidateCopyright(Line):
- if Line:
- pass
- Result = True
- ErrMsg = ''
-
- return Result, ErrMsg
-
-def GenerateTokenList (Comment):
- #
- # Tokenize Comment using '#' and ' ' as token separators
- #
- ReplacedComment = None
- while Comment != ReplacedComment:
- ReplacedComment = Comment
- Comment = Comment.replace('##', '#').replace(' ', ' ').replace(' ', '#').strip('# ')
- return Comment.split('#')
-
-
-#
-# Comment - Comment to parse
-# TypeTokens - A dictionary of type token synonyms
-# RemoveTokens - A list of tokens to remove from help text
-# ParseVariable - True for parsing [Guids]. Otherwise False
-#
-def ParseComment (Comment, UsageTokens, TypeTokens, RemoveTokens, ParseVariable):
- #
- # Initialize return values
- #
- Usage = None
- Type = None
- String = None
-
- Comment = Comment[0]
-
- NumTokens = 2
- if ParseVariable:
- #
- # Remove white space around first instance of ':' from Comment if 'Variable'
- # is in front of ':' and Variable is the 1st or 2nd token in Comment.
- #
- List = Comment.split(':', 1)
- if len(List) > 1:
- SubList = GenerateTokenList (List[0].strip())
- if len(SubList) in [1, 2] and SubList[-1] == 'Variable':
- if List[1].strip().find('L"') == 0:
- Comment = List[0].strip() + ':' + List[1].strip()
-
- #
- # Remove first instance of L"<VariableName> from Comment and put into String
- # if and only if L"<VariableName>" is the 1st token, the 2nd token. Or
- # L"<VariableName>" is the third token immediately following 'Variable:'.
- #
- End = -1
- Start = Comment.find('Variable:L"')
- if Start >= 0:
- String = Comment[Start + 9:]
- End = String[2:].find('"')
- else:
- Start = Comment.find('L"')
- if Start >= 0:
- String = Comment[Start:]
- End = String[2:].find('"')
- if End >= 0:
- SubList = GenerateTokenList (Comment[:Start])
- if len(SubList) < 2:
- Comment = Comment[:Start] + String[End + 3:]
- String = String[:End + 3]
- Type = 'Variable'
- NumTokens = 1
-
- #
- # Initialize HelpText to Comment.
- # Content will be remove from HelpText as matching tokens are found
- #
- HelpText = Comment
-
- #
- # Tokenize Comment using '#' and ' ' as token separators
- #
- List = GenerateTokenList (Comment)
-
- #
- # Search first two tokens for Usage and Type and remove any matching tokens
- # from HelpText
- #
- for Token in List[0:NumTokens]:
- if Usage is None and Token in UsageTokens:
- Usage = UsageTokens[Token]
- HelpText = HelpText.replace(Token, '')
- if Usage is not None or not ParseVariable:
- for Token in List[0:NumTokens]:
- if Type is None and Token in TypeTokens:
- Type = TypeTokens[Token]
- HelpText = HelpText.replace(Token, '')
- if Usage is not None:
- for Token in List[0:NumTokens]:
- if Token in RemoveTokens:
- HelpText = HelpText.replace(Token, '')
-
- #
- # If no Usage token is present and set Usage to UNDEFINED
- #
- if Usage is None:
- Usage = 'UNDEFINED'
-
- #
- # If no Type token is present and set Type to UNDEFINED
- #
- if Type is None:
- Type = 'UNDEFINED'
-
- #
- # If Type is not 'Variable:', then set String to None
- #
- if Type != 'Variable':
- String = None
-
- #
- # Strip ' ' and '#' from the beginning of HelpText
- # If HelpText is an empty string after all parsing is
- # complete then set HelpText to None
- #
- HelpText = HelpText.lstrip('# ')
- if HelpText == '':
- HelpText = None
-
- #
- # Return parsing results
- #
- return Usage, Type, String, HelpText
+## @file +# This file is used to define comment parsing interface +# +# Copyright (c) 2011 - 2018, Intel Corporation. All rights reserved.<BR> +# +# SPDX-License-Identifier: BSD-2-Clause-Patent +# + +''' +CommentParsing +''' + +## +# Import Modules +# +import re + +from Library.StringUtils import GetSplitValueList +from Library.StringUtils import CleanString2 +from Library.DataType import HEADER_COMMENT_NOT_STARTED +from Library.DataType import TAB_COMMENT_SPLIT +from Library.DataType import HEADER_COMMENT_LICENSE +from Library.DataType import HEADER_COMMENT_ABSTRACT +from Library.DataType import HEADER_COMMENT_COPYRIGHT +from Library.DataType import HEADER_COMMENT_DESCRIPTION +from Library.DataType import TAB_SPACE_SPLIT +from Library.DataType import TAB_COMMA_SPLIT +from Library.DataType import SUP_MODULE_LIST +from Library.DataType import TAB_VALUE_SPLIT +from Library.DataType import TAB_PCD_VALIDRANGE +from Library.DataType import TAB_PCD_VALIDLIST +from Library.DataType import TAB_PCD_EXPRESSION +from Library.DataType import TAB_PCD_PROMPT +from Library.DataType import TAB_CAPHEX_START +from Library.DataType import TAB_HEX_START +from Library.DataType import PCD_ERR_CODE_MAX_SIZE +from Library.ExpressionValidate import IsValidRangeExpr +from Library.ExpressionValidate import IsValidListExpr +from Library.ExpressionValidate import IsValidLogicalExpr +from Object.POM.CommonObject import TextObject +from Object.POM.CommonObject import PcdErrorObject +import Logger.Log as Logger +from Logger.ToolError import FORMAT_INVALID +from Logger.ToolError import FORMAT_NOT_SUPPORTED +from Logger import StringTable as ST + +## ParseHeaderCommentSection +# +# Parse Header comment section lines, extract Abstract, Description, Copyright +# , License lines +# +# @param CommentList: List of (Comment, LineNumber) +# @param FileName: FileName of the comment +# +def ParseHeaderCommentSection(CommentList, FileName = None, IsBinaryHeader = False): + Abstract = '' + Description = '' + Copyright = '' + License = '' + EndOfLine = "\n" + if IsBinaryHeader: + STR_HEADER_COMMENT_START = "@BinaryHeader" + else: + STR_HEADER_COMMENT_START = "@file" + HeaderCommentStage = HEADER_COMMENT_NOT_STARTED + + # + # first find the last copyright line + # + Last = 0 + for Index in range(len(CommentList)-1, 0, -1): + Line = CommentList[Index][0] + if _IsCopyrightLine(Line): + Last = Index + break + + for Item in CommentList: + Line = Item[0] + LineNo = Item[1] + + if not Line.startswith(TAB_COMMENT_SPLIT) and Line: + Logger.Error("\nUPT", FORMAT_INVALID, ST.ERR_INVALID_COMMENT_FORMAT, FileName, Item[1]) + Comment = CleanString2(Line)[1] + Comment = Comment.strip() + # + # if there are blank lines between License or Description, keep them as they would be + # indication of different block; or in the position that Abstract should be, also keep it + # as it indicates that no abstract + # + if not Comment and HeaderCommentStage not in [HEADER_COMMENT_LICENSE, \ + HEADER_COMMENT_DESCRIPTION, HEADER_COMMENT_ABSTRACT]: + continue + + if HeaderCommentStage == HEADER_COMMENT_NOT_STARTED: + if Comment.startswith(STR_HEADER_COMMENT_START): + HeaderCommentStage = HEADER_COMMENT_ABSTRACT + else: + License += Comment + EndOfLine + else: + if HeaderCommentStage == HEADER_COMMENT_ABSTRACT: + # + # in case there is no abstract and description + # + if not Comment: + HeaderCommentStage = HEADER_COMMENT_DESCRIPTION + elif _IsCopyrightLine(Comment): + Result, ErrMsg = _ValidateCopyright(Comment) + ValidateCopyright(Result, ST.WRN_INVALID_COPYRIGHT, FileName, LineNo, ErrMsg) + Copyright += Comment + EndOfLine + HeaderCommentStage = HEADER_COMMENT_COPYRIGHT + else: + Abstract += Comment + EndOfLine + HeaderCommentStage = HEADER_COMMENT_DESCRIPTION + elif HeaderCommentStage == HEADER_COMMENT_DESCRIPTION: + # + # in case there is no description + # + if _IsCopyrightLine(Comment): + Result, ErrMsg = _ValidateCopyright(Comment) + ValidateCopyright(Result, ST.WRN_INVALID_COPYRIGHT, FileName, LineNo, ErrMsg) + Copyright += Comment + EndOfLine + HeaderCommentStage = HEADER_COMMENT_COPYRIGHT + else: + Description += Comment + EndOfLine + elif HeaderCommentStage == HEADER_COMMENT_COPYRIGHT: + if _IsCopyrightLine(Comment): + Result, ErrMsg = _ValidateCopyright(Comment) + ValidateCopyright(Result, ST.WRN_INVALID_COPYRIGHT, FileName, LineNo, ErrMsg) + Copyright += Comment + EndOfLine + else: + # + # Contents after copyright line are license, those non-copyright lines in between + # copyright line will be discarded + # + if LineNo > Last: + if License: + License += EndOfLine + License += Comment + EndOfLine + HeaderCommentStage = HEADER_COMMENT_LICENSE + else: + if not Comment and not License: + continue + License += Comment + EndOfLine + + return Abstract.strip(), Description.strip(), Copyright.strip(), License.strip() + +## _IsCopyrightLine +# check whether current line is copyright line, the criteria is whether there is case insensitive keyword "Copyright" +# followed by zero or more white space characters followed by a "(" character +# +# @param LineContent: the line need to be checked +# @return: True if current line is copyright line, False else +# +def _IsCopyrightLine (LineContent): + LineContent = LineContent.upper() + Result = False + + ReIsCopyrightRe = re.compile(r"""(^|\s)COPYRIGHT *\(""", re.DOTALL) + if ReIsCopyrightRe.search(LineContent): + Result = True + + return Result + +## ParseGenericComment +# +# @param GenericComment: Generic comment list, element of +# (CommentLine, LineNum) +# @param ContainerFile: Input value for filename of Dec file +# +def ParseGenericComment (GenericComment, ContainerFile=None, SkipTag=None): + if ContainerFile: + pass + HelpTxt = None + HelpStr = '' + + for Item in GenericComment: + CommentLine = Item[0] + Comment = CleanString2(CommentLine)[1] + if SkipTag is not None and Comment.startswith(SkipTag): + Comment = Comment.replace(SkipTag, '', 1) + HelpStr += Comment + '\n' + + if HelpStr: + HelpTxt = TextObject() + if HelpStr.endswith('\n') and not HelpStr.endswith('\n\n') and HelpStr != '\n': + HelpStr = HelpStr[:-1] + HelpTxt.SetString(HelpStr) + + return HelpTxt + +## ParsePcdErrorCode +# +# @param Value: original ErrorCode value +# @param ContainerFile: Input value for filename of Dec file +# @param LineNum: Line Num +# +def ParsePcdErrorCode (Value = None, ContainerFile = None, LineNum = None): + try: + if Value.strip().startswith((TAB_HEX_START, TAB_CAPHEX_START)): + Base = 16 + else: + Base = 10 + ErrorCode = int(Value, Base) + if ErrorCode > PCD_ERR_CODE_MAX_SIZE or ErrorCode < 0: + Logger.Error('Parser', + FORMAT_NOT_SUPPORTED, + "The format %s of ErrorCode is not valid, should be UNIT32 type or long type" % Value, + File = ContainerFile, + Line = LineNum) + ErrorCode = '0x%x' % ErrorCode + return ErrorCode + except ValueError as XStr: + if XStr: + pass + Logger.Error('Parser', + FORMAT_NOT_SUPPORTED, + "The format %s of ErrorCode is not valid, should be UNIT32 type or long type" % Value, + File = ContainerFile, + Line = LineNum) + +## ParseDecPcdGenericComment +# +# @param GenericComment: Generic comment list, element of (CommentLine, +# LineNum) +# @param ContainerFile: Input value for filename of Dec file +# +def ParseDecPcdGenericComment (GenericComment, ContainerFile, TokenSpaceGuidCName, CName, MacroReplaceDict): + HelpStr = '' + PromptStr = '' + PcdErr = None + PcdErrList = [] + ValidValueNum = 0 + ValidRangeNum = 0 + ExpressionNum = 0 + + for (CommentLine, LineNum) in GenericComment: + Comment = CleanString2(CommentLine)[1] + # + # To replace Macro + # + MACRO_PATTERN = '[\t\s]*\$\([A-Z][_A-Z0-9]*\)' + MatchedStrs = re.findall(MACRO_PATTERN, Comment) + for MatchedStr in MatchedStrs: + if MatchedStr: + Macro = MatchedStr.strip().lstrip('$(').rstrip(')').strip() + if Macro in MacroReplaceDict: + Comment = Comment.replace(MatchedStr, MacroReplaceDict[Macro]) + if Comment.startswith(TAB_PCD_VALIDRANGE): + if ValidValueNum > 0 or ExpressionNum > 0: + Logger.Error('Parser', + FORMAT_NOT_SUPPORTED, + ST.WRN_MULTI_PCD_RANGES, + File = ContainerFile, + Line = LineNum) + else: + PcdErr = PcdErrorObject() + PcdErr.SetTokenSpaceGuidCName(TokenSpaceGuidCName) + PcdErr.SetCName(CName) + PcdErr.SetFileLine(Comment) + PcdErr.SetLineNum(LineNum) + ValidRangeNum += 1 + ValidRange = Comment.replace(TAB_PCD_VALIDRANGE, "", 1).strip() + Valid, Cause = _CheckRangeExpression(ValidRange) + if Valid: + ValueList = ValidRange.split(TAB_VALUE_SPLIT) + if len(ValueList) > 1: + PcdErr.SetValidValueRange((TAB_VALUE_SPLIT.join(ValueList[1:])).strip()) + PcdErr.SetErrorNumber(ParsePcdErrorCode(ValueList[0], ContainerFile, LineNum)) + else: + PcdErr.SetValidValueRange(ValidRange) + PcdErrList.append(PcdErr) + else: + Logger.Error("Parser", + FORMAT_NOT_SUPPORTED, + Cause, + ContainerFile, + LineNum) + elif Comment.startswith(TAB_PCD_VALIDLIST): + if ValidRangeNum > 0 or ExpressionNum > 0: + Logger.Error('Parser', + FORMAT_NOT_SUPPORTED, + ST.WRN_MULTI_PCD_RANGES, + File = ContainerFile, + Line = LineNum) + elif ValidValueNum > 0: + Logger.Error('Parser', + FORMAT_NOT_SUPPORTED, + ST.WRN_MULTI_PCD_VALIDVALUE, + File = ContainerFile, + Line = LineNum) + else: + PcdErr = PcdErrorObject() + PcdErr.SetTokenSpaceGuidCName(TokenSpaceGuidCName) + PcdErr.SetCName(CName) + PcdErr.SetFileLine(Comment) + PcdErr.SetLineNum(LineNum) + ValidValueNum += 1 + ValidValueExpr = Comment.replace(TAB_PCD_VALIDLIST, "", 1).strip() + Valid, Cause = _CheckListExpression(ValidValueExpr) + if Valid: + ValidValue = Comment.replace(TAB_PCD_VALIDLIST, "", 1).replace(TAB_COMMA_SPLIT, TAB_SPACE_SPLIT) + ValueList = ValidValue.split(TAB_VALUE_SPLIT) + if len(ValueList) > 1: + PcdErr.SetValidValue((TAB_VALUE_SPLIT.join(ValueList[1:])).strip()) + PcdErr.SetErrorNumber(ParsePcdErrorCode(ValueList[0], ContainerFile, LineNum)) + else: + PcdErr.SetValidValue(ValidValue) + PcdErrList.append(PcdErr) + else: + Logger.Error("Parser", + FORMAT_NOT_SUPPORTED, + Cause, + ContainerFile, + LineNum) + elif Comment.startswith(TAB_PCD_EXPRESSION): + if ValidRangeNum > 0 or ValidValueNum > 0: + Logger.Error('Parser', + FORMAT_NOT_SUPPORTED, + ST.WRN_MULTI_PCD_RANGES, + File = ContainerFile, + Line = LineNum) + else: + PcdErr = PcdErrorObject() + PcdErr.SetTokenSpaceGuidCName(TokenSpaceGuidCName) + PcdErr.SetCName(CName) + PcdErr.SetFileLine(Comment) + PcdErr.SetLineNum(LineNum) + ExpressionNum += 1 + Expression = Comment.replace(TAB_PCD_EXPRESSION, "", 1).strip() + Valid, Cause = _CheckExpression(Expression) + if Valid: + ValueList = Expression.split(TAB_VALUE_SPLIT) + if len(ValueList) > 1: + PcdErr.SetExpression((TAB_VALUE_SPLIT.join(ValueList[1:])).strip()) + PcdErr.SetErrorNumber(ParsePcdErrorCode(ValueList[0], ContainerFile, LineNum)) + else: + PcdErr.SetExpression(Expression) + PcdErrList.append(PcdErr) + else: + Logger.Error("Parser", + FORMAT_NOT_SUPPORTED, + Cause, + ContainerFile, + LineNum) + elif Comment.startswith(TAB_PCD_PROMPT): + if PromptStr: + Logger.Error('Parser', + FORMAT_NOT_SUPPORTED, + ST.WRN_MULTI_PCD_PROMPT, + File = ContainerFile, + Line = LineNum) + PromptStr = Comment.replace(TAB_PCD_PROMPT, "", 1).strip() + else: + if Comment: + HelpStr += Comment + '\n' + + # + # remove the last EOL if the comment is of format 'FOO\n' + # + if HelpStr.endswith('\n'): + if HelpStr != '\n' and not HelpStr.endswith('\n\n'): + HelpStr = HelpStr[:-1] + + return HelpStr, PcdErrList, PromptStr + +## ParseDecPcdTailComment +# +# @param TailCommentList: Tail comment list of Pcd, item of format (Comment, LineNum) +# @param ContainerFile: Input value for filename of Dec file +# @retVal SupModuleList: The supported module type list detected +# @retVal HelpStr: The generic help text string detected +# +def ParseDecPcdTailComment (TailCommentList, ContainerFile): + assert(len(TailCommentList) == 1) + TailComment = TailCommentList[0][0] + LineNum = TailCommentList[0][1] + + Comment = TailComment.lstrip(" #") + + ReFindFirstWordRe = re.compile(r"""^([^ #]*)""", re.DOTALL) + + # + # get first word and compare with SUP_MODULE_LIST + # + MatchObject = ReFindFirstWordRe.match(Comment) + if not (MatchObject and MatchObject.group(1) in SUP_MODULE_LIST): + return None, Comment + + # + # parse line, it must have supported module type specified + # + if Comment.find(TAB_COMMENT_SPLIT) == -1: + Comment += TAB_COMMENT_SPLIT + SupMode, HelpStr = GetSplitValueList(Comment, TAB_COMMENT_SPLIT, 1) + SupModuleList = [] + for Mod in GetSplitValueList(SupMode, TAB_SPACE_SPLIT): + if not Mod: + continue + elif Mod not in SUP_MODULE_LIST: + Logger.Error("UPT", + FORMAT_INVALID, + ST.WRN_INVALID_MODULE_TYPE%Mod, + ContainerFile, + LineNum) + else: + SupModuleList.append(Mod) + + return SupModuleList, HelpStr + +## _CheckListExpression +# +# @param Expression: Pcd value list expression +# +def _CheckListExpression(Expression): + ListExpr = '' + if TAB_VALUE_SPLIT in Expression: + ListExpr = Expression[Expression.find(TAB_VALUE_SPLIT)+1:] + else: + ListExpr = Expression + + return IsValidListExpr(ListExpr) + +## _CheckExpression +# +# @param Expression: Pcd value expression +# +def _CheckExpression(Expression): + Expr = '' + if TAB_VALUE_SPLIT in Expression: + Expr = Expression[Expression.find(TAB_VALUE_SPLIT)+1:] + else: + Expr = Expression + return IsValidLogicalExpr(Expr, True) + +## _CheckRangeExpression +# +# @param Expression: Pcd range expression +# +def _CheckRangeExpression(Expression): + RangeExpr = '' + if TAB_VALUE_SPLIT in Expression: + RangeExpr = Expression[Expression.find(TAB_VALUE_SPLIT)+1:] + else: + RangeExpr = Expression + + return IsValidRangeExpr(RangeExpr) + +## ValidateCopyright +# +# +# +def ValidateCopyright(Result, ErrType, FileName, LineNo, ErrMsg): + if not Result: + Logger.Warn("\nUPT", ErrType, FileName, LineNo, ErrMsg) + +## _ValidateCopyright +# +# @param Line: Line that contains copyright information, # stripped +# +# @retval Result: True if line is conformed to Spec format, False else +# @retval ErrMsg: the detailed error description +# +def _ValidateCopyright(Line): + if Line: + pass + Result = True + ErrMsg = '' + + return Result, ErrMsg + +def GenerateTokenList (Comment): + # + # Tokenize Comment using '#' and ' ' as token separators + # + ReplacedComment = None + while Comment != ReplacedComment: + ReplacedComment = Comment + Comment = Comment.replace('##', '#').replace(' ', ' ').replace(' ', '#').strip('# ') + return Comment.split('#') + + +# +# Comment - Comment to parse +# TypeTokens - A dictionary of type token synonyms +# RemoveTokens - A list of tokens to remove from help text +# ParseVariable - True for parsing [Guids]. Otherwise False +# +def ParseComment (Comment, UsageTokens, TypeTokens, RemoveTokens, ParseVariable): + # + # Initialize return values + # + Usage = None + Type = None + String = None + + Comment = Comment[0] + + NumTokens = 2 + if ParseVariable: + # + # Remove white space around first instance of ':' from Comment if 'Variable' + # is in front of ':' and Variable is the 1st or 2nd token in Comment. + # + List = Comment.split(':', 1) + if len(List) > 1: + SubList = GenerateTokenList (List[0].strip()) + if len(SubList) in [1, 2] and SubList[-1] == 'Variable': + if List[1].strip().find('L"') == 0: + Comment = List[0].strip() + ':' + List[1].strip() + + # + # Remove first instance of L"<VariableName> from Comment and put into String + # if and only if L"<VariableName>" is the 1st token, the 2nd token. Or + # L"<VariableName>" is the third token immediately following 'Variable:'. + # + End = -1 + Start = Comment.find('Variable:L"') + if Start >= 0: + String = Comment[Start + 9:] + End = String[2:].find('"') + else: + Start = Comment.find('L"') + if Start >= 0: + String = Comment[Start:] + End = String[2:].find('"') + if End >= 0: + SubList = GenerateTokenList (Comment[:Start]) + if len(SubList) < 2: + Comment = Comment[:Start] + String[End + 3:] + String = String[:End + 3] + Type = 'Variable' + NumTokens = 1 + + # + # Initialize HelpText to Comment. + # Content will be remove from HelpText as matching tokens are found + # + HelpText = Comment + + # + # Tokenize Comment using '#' and ' ' as token separators + # + List = GenerateTokenList (Comment) + + # + # Search first two tokens for Usage and Type and remove any matching tokens + # from HelpText + # + for Token in List[0:NumTokens]: + if Usage is None and Token in UsageTokens: + Usage = UsageTokens[Token] + HelpText = HelpText.replace(Token, '') + if Usage is not None or not ParseVariable: + for Token in List[0:NumTokens]: + if Type is None and Token in TypeTokens: + Type = TypeTokens[Token] + HelpText = HelpText.replace(Token, '') + if Usage is not None: + for Token in List[0:NumTokens]: + if Token in RemoveTokens: + HelpText = HelpText.replace(Token, '') + + # + # If no Usage token is present and set Usage to UNDEFINED + # + if Usage is None: + Usage = 'UNDEFINED' + + # + # If no Type token is present and set Type to UNDEFINED + # + if Type is None: + Type = 'UNDEFINED' + + # + # If Type is not 'Variable:', then set String to None + # + if Type != 'Variable': + String = None + + # + # Strip ' ' and '#' from the beginning of HelpText + # If HelpText is an empty string after all parsing is + # complete then set HelpText to None + # + HelpText = HelpText.lstrip('# ') + if HelpText == '': + HelpText = None + + # + # Return parsing results + # + return Usage, Type, String, HelpText diff --git a/BaseTools/Source/Python/UPT/Library/DataType.py b/BaseTools/Source/Python/UPT/Library/DataType.py index 0e47f35670..1b43de2c54 100644 --- a/BaseTools/Source/Python/UPT/Library/DataType.py +++ b/BaseTools/Source/Python/UPT/Library/DataType.py @@ -1,970 +1,970 @@ -## @file
-# This file is used to define class for data type structure
-#
-# Copyright (c) 2011 - 2018, Intel Corporation. All rights reserved.<BR>
-# Portions Copyright (c) 2022, Loongson Technology Corporation Limited. All rights reserved.
-#
-# SPDX-License-Identifier: BSD-2-Clause-Patent
-
-'''
-DataType
-'''
-
-##
-# Module List Items
-#
-MODULE_LIST = ["BASE",
- "SEC",
- "PEI_CORE",
- "PEIM",
- "DXE_CORE",
- "DXE_DRIVER",
- "SMM_CORE",
- "DXE_RUNTIME_DRIVER",
- "DXE_SAL_DRIVER",
- "DXE_SMM_DRIVER",
- "UEFI_DRIVER",
- "UEFI_APPLICATION",
- "USER_DEFINED"]
-
-VALID_DEPEX_MODULE_TYPE_LIST = ["PEIM",
- "DXE_DRIVER",
- "DXE_SMM_DRIVER",
- "DXE_RUNTIME_DRIVER",
- "DXE_SAL_DRIVER",
- "UEFI_DRIVER",
- ]
-##
-# Usage List Items
-#
-USAGE_LIST = ["CONSUMES",
- "SOMETIMES_CONSUMES",
- "PRODUCES",
- "SOMETIMES_PRODUCES"]
-
-TAB_LANGUAGE_EN_US = 'en-US'
-TAB_LANGUAGE_ENG = 'eng'
-TAB_LANGUAGE_EN = 'en'
-TAB_LANGUAGE_EN_X = 'en-x-tianocore'
-
-USAGE_ITEM_PRODUCES = 'PRODUCES'
-USAGE_ITEM_SOMETIMES_PRODUCES = 'SOMETIMES_PRODUCES'
-USAGE_ITEM_CONSUMES = 'CONSUMES'
-USAGE_ITEM_SOMETIMES_CONSUMES = 'SOMETIMES_CONSUMES'
-USAGE_ITEM_TO_START = 'TO_START'
-USAGE_ITEM_BY_START = 'BY_START'
-USAGE_ITEM_NOTIFY = 'NOTIFY'
-USAGE_ITEM_UNDEFINED = 'UNDEFINED'
-
-USAGE_CONSUMES_LIST = [USAGE_ITEM_CONSUMES,
- 'CONSUMED',
- 'ALWAYS_CONSUMED',
- 'ALWAYS_CONSUMES'
- ]
-
-USAGE_PRODUCES_LIST = [USAGE_ITEM_PRODUCES,
- 'PRODUCED',
- 'ALWAYS_PRODUCED',
- 'ALWAYS_PRODUCES'
- ]
-
-USAGE_SOMETIMES_PRODUCES_LIST = [USAGE_ITEM_SOMETIMES_PRODUCES,
- 'SOMETIMES_PRODUCED'
- ]
-
-USAGE_SOMETIMES_CONSUMES_LIST = [USAGE_ITEM_SOMETIMES_CONSUMES,
- 'SOMETIMES_CONSUMED'
- ]
-
-ITEM_UNDEFINED = 'UNDEFINED'
-
-TAB_PCD_VALIDRANGE = '@ValidRange'
-TAB_PCD_VALIDLIST = '@ValidList'
-TAB_PCD_EXPRESSION = '@Expression'
-TAB_PCD_PROMPT = '@Prompt'
-TAB_STR_TOKENCNAME = 'STR'
-TAB_STR_TOKENPROMPT = 'PROMPT'
-TAB_STR_TOKENHELP = 'HELP'
-TAB_STR_TOKENERR = 'ERR'
-
-#
-# Dictionary of usage tokens and their synonyms
-#
-ALL_USAGE_TOKENS = {
- "PRODUCES" : "PRODUCES",
- "PRODUCED" : "PRODUCES",
- "ALWAYS_PRODUCES" : "PRODUCES",
- "ALWAYS_PRODUCED" : "PRODUCES",
- "SOMETIMES_PRODUCES" : "SOMETIMES_PRODUCES",
- "SOMETIMES_PRODUCED" : "SOMETIMES_PRODUCES",
- "CONSUMES" : "CONSUMES",
- "CONSUMED" : "CONSUMES",
- "ALWAYS_CONSUMES" : "CONSUMES",
- "ALWAYS_CONSUMED" : "CONSUMES",
- "SOMETIMES_CONSUMES" : "SOMETIMES_CONSUMES",
- "SOMETIMES_CONSUMED" : "SOMETIMES_CONSUMES",
- "SOMETIME_CONSUMES" : "SOMETIMES_CONSUMES",
- "UNDEFINED" : "UNDEFINED"
- }
-
-PROTOCOL_USAGE_TOKENS = {
- "TO_START" : "TO_START",
- "BY_START" : "BY_START"
- }
-
-PROTOCOL_USAGE_TOKENS.update (ALL_USAGE_TOKENS)
-
-#
-# Dictionary of GUID type tokens
-#
-GUID_TYPE_TOKENS = {
- "Event" : "Event",
- "File" : "File",
- "FV" : "FV",
- "GUID" : "GUID",
- "Guid" : "GUID",
- "HII" : "HII",
- "HOB" : "HOB",
- "Hob" : "HOB",
- "Hob:" : "HOB",
- "SystemTable" : "SystemTable",
- "TokenSpaceGuid" : "TokenSpaceGuid",
- "UNDEFINED" : "UNDEFINED"
- }
-
-#
-# Dictionary of Protocol Notify tokens and their synonyms
-#
-PROTOCOL_NOTIFY_TOKENS = {
- "NOTIFY" : "NOTIFY",
- "PROTOCOL_NOTIFY" : "NOTIFY",
- "UNDEFINED" : "UNDEFINED"
- }
-
-#
-# Dictionary of PPI Notify tokens and their synonyms
-#
-PPI_NOTIFY_TOKENS = {
- "NOTIFY" : "NOTIFY",
- "PPI_NOTIFY" : "NOTIFY",
- "UNDEFINED" : "UNDEFINED"
- }
-
-EVENT_TOKENS = {
- "EVENT_TYPE_PERIODIC_TIMER" : "EVENT_TYPE_PERIODIC_TIMER",
- "EVENT_TYPE_RELATIVE_TIMER" : "EVENT_TYPE_RELATIVE_TIMER",
- "UNDEFINED" : "UNDEFINED"
- }
-
-BOOTMODE_TOKENS = {
- "FULL" : "FULL",
- "MINIMAL" : "MINIMAL",
- "NO_CHANGE" : "NO_CHANGE",
- "DIAGNOSTICS" : "DIAGNOSTICS",
- "DEFAULT" : "DEFAULT",
- "S2_RESUME" : "S2_RESUME",
- "S3_RESUME" : "S3_RESUME",
- "S4_RESUME" : "S4_RESUME",
- "S5_RESUME" : "S5_RESUME",
- "FLASH_UPDATE" : "FLASH_UPDATE",
- "RECOVERY_FULL" : "RECOVERY_FULL",
- "RECOVERY_MINIMAL" : "RECOVERY_MINIMAL",
- "RECOVERY_NO_CHANGE" : "RECOVERY_NO_CHANGE",
- "RECOVERY_DIAGNOSTICS" : "RECOVERY_DIAGNOSTICS",
- "RECOVERY_DEFAULT" : "RECOVERY_DEFAULT",
- "RECOVERY_S2_RESUME" : "RECOVERY_S2_RESUME",
- "RECOVERY_S3_RESUME" : "RECOVERY_S3_RESUME",
- "RECOVERY_S4_RESUME" : "RECOVERY_S4_RESUME",
- "RECOVERY_S5_RESUME" : "RECOVERY_S5_RESUME",
- "RECOVERY_FLASH_UPDATE" : "RECOVERY_FLASH_UPDATE",
- "UNDEFINED" : "UNDEFINED"
- }
-
-HOB_TOKENS = {
- "PHIT" : "PHIT",
- "MEMORY_ALLOCATION" : "MEMORY_ALLOCATION",
- "LOAD_PEIM" : "LOAD_PEIM",
- "RESOURCE_DESCRIPTOR" : "RESOURCE_DESCRIPTOR",
- "FIRMWARE_VOLUME" : "FIRMWARE_VOLUME",
- "UNDEFINED" : "UNDEFINED"
- }
-
-##
-# Usage List Items for Protocol
-#
-PROTOCOL_USAGE_LIST = USAGE_LIST + ["TO_START", "BY_START"]
-
-##
-# End of Line
-# Use this but not os.linesep for os.linesep has bug in it.
-#
-END_OF_LINE = '\n'
-
-##
-# Arch List Items
-#
-ARCH_LIST = ["IA32",
- "X64",
- "IPF",
- "EBC",
- "COMMON"]
-##
-# PCD driver type list items
-#
-PCD_DRIVER_TYPE_LIST = ["PEI_PCD_DRIVER", "DXE_PCD_DRIVER"]
-
-##
-# Boot Mode List Items
-#
-BOOT_MODE_LIST = ["FULL",
- "MINIMAL",
- "NO_CHANGE",
- "DIAGNOSTICS",
- "DEFAULT",
- "S2_RESUME",
- "S3_RESUME",
- "S4_RESUME",
- "S5_RESUME",
- "FLASH_UPDATE",
- "RECOVERY_FULL",
- "RECOVERY_MINIMAL",
- "RECOVERY_NO_CHANGE",
- "RECOVERY_DIAGNOSTICS",
- "RECOVERY_DEFAULT",
- "RECOVERY_S2_RESUME",
- "RECOVERY_S3_RESUME",
- "RECOVERY_S4_RESUME",
- "RECOVERY_S5_RESUME",
- "RECOVERY_FLASH_UPDATE"]
-
-##
-# Event Type List Items
-#
-EVENT_TYPE_LIST = ["EVENT_TYPE_PERIODIC_TIMER",
- "EVENT_TYPE_RELATIVE_TIMER"]
-
-##
-# Hob Type List Items
-#
-HOB_TYPE_LIST = ["PHIT",
- "MEMORY_ALLOCATION",
- "RESOURCE_DESCRIPTOR",
- "FIRMWARE_VOLUME",
- "LOAD_PEIM"]
-
-##
-# GUID_TYPE_LIST
-#
-GUID_TYPE_LIST = ["Event", "File", "FV", "GUID", "HII", "HOB",
- "SystemTable", "TokenSpaceGuid", "Variable"]
-##
-# PCD Usage Type List of Package
-#
-PCD_USAGE_TYPE_LIST_OF_PACKAGE = ["FeatureFlag", "PatchableInModule",
- "FixedAtBuild", "Dynamic", "DynamicEx"]
-
-##
-# PCD Usage Type List of Module
-#
-PCD_USAGE_TYPE_LIST_OF_MODULE = ["FEATUREPCD", "PATCHPCD", "FIXEDPCD", "PCD", "PCDEX"]
-##
-# PCD Usage Type List of UPT
-#
-PCD_USAGE_TYPE_LIST_OF_UPT = PCD_USAGE_TYPE_LIST_OF_MODULE
-
-##
-# Binary File Type List
-#
-BINARY_FILE_TYPE_LIST = ["PE32", "PIC", "TE", "DXE_DEPEX", "VER", "UI", "COMPAT16", "FV", "BIN", "RAW",
- "ACPI", "ASL",
- "PEI_DEPEX",
- "SMM_DEPEX",
- "SUBTYPE_GUID",
- "DISPOSABLE"
- ]
-BINARY_FILE_TYPE_LIST_IN_UDP = \
- ["GUID", "FREEFORM",
- "UEFI_IMAGE", "PE32", "PIC",
- "PEI_DEPEX",
- "DXE_DEPEX",
- "SMM_DEPEX",
- "FV", "TE",
- "BIN", "VER", "UI"
- ]
-
-SUBTYPE_GUID_BINARY_FILE_TYPE = "FREEFORM"
-##
-# Possible values for COMPONENT_TYPE, and their descriptions, are listed in
-# the table,
-# "Component (module) Types." For each component, the BASE_NAME and
-# COMPONENT_TYPE
-# are required. The COMPONENT_TYPE definition is case sensitive.
-#
-COMPONENT_TYPE_LIST = [
- "APPLICATION",
- "ACPITABLE",
- "APRIORI",
- "BINARY",
- "BS_DRIVER",
- "CONFIG",
- "FILE",
- "FVIMAGEFILE",
- "LIBRARY",
- "LOGO",
- "LEGACY16",
- "MICROCODE",
- "PE32_PEIM",
- "PEI_CORE",
- "RAWFILE",
- "RT_DRIVER",
- "SAL_RT_DRIVER",
- "SECURITY_CORE",
- "COMBINED_PEIM_DRIVER",
- "PIC_PEIM",
- "RELOCATABLE_PEIM"
- ]
-
-##
-# Common Definitions
-#
-TAB_SPLIT = '.'
-TAB_COMMENT_EDK1_START = '/*'
-TAB_COMMENT_EDK1_END = '*/'
-TAB_COMMENT_EDK1_SPLIT = '//'
-TAB_COMMENT_SPLIT = '#'
-TAB_EQUAL_SPLIT = '='
-TAB_DEQUAL_SPLIT = '=='
-TAB_VALUE_SPLIT = '|'
-TAB_COMMA_SPLIT = ','
-TAB_HORIZON_LINE_SPLIT = '-'
-TAB_SPACE_SPLIT = ' '
-TAB_UNDERLINE_SPLIT = '_'
-TAB_SEMI_COLON_SPLIT = ';'
-TAB_COLON_SPLIT = ':'
-TAB_SECTION_START = '['
-TAB_SECTION_END = ']'
-TAB_OPTION_START = '<'
-TAB_OPTION_END = '>'
-TAB_SLASH = '\\'
-TAB_BACK_SLASH = '/'
-TAB_SPECIAL_COMMENT = '##'
-TAB_HEADER_COMMENT = '@file'
-TAB_BINARY_HEADER_COMMENT = '@BinaryHeader'
-TAB_STAR = '*'
-TAB_ENCODING_UTF16LE = 'utf_16_le'
-TAB_CAPHEX_START = '0X'
-TAB_HEX_START = '0x'
-TAB_PCD_ERROR = 'Error'
-TAB_PCD_ERROR_SECTION_COMMENT = 'Error message section'
-TAB_UNI_FILE_SUFFIXS = ['.uni', '.UNI', '.Uni']
-
-TAB_EDK_SOURCE = '$(EDK_SOURCE)'
-TAB_EFI_SOURCE = '$(EFI_SOURCE)'
-TAB_WORKSPACE = '$(WORKSPACE)'
-
-TAB_ARCH_NULL = ''
-TAB_ARCH_COMMON = 'COMMON'
-TAB_ARCH_IA32 = 'IA32'
-TAB_ARCH_X64 = 'X64'
-TAB_ARCH_IPF = 'IPF'
-TAB_ARCH_ARM = 'ARM'
-TAB_ARCH_LOONGARCH64 = 'LOONGARCH64'
-TAB_ARCH_EBC = 'EBC'
-
-ARCH_LIST = \
-[TAB_ARCH_IA32, TAB_ARCH_X64, TAB_ARCH_IPF, TAB_ARCH_ARM, TAB_ARCH_LOONGARCH64, TAB_ARCH_EBC]
-
-SUP_MODULE_BASE = 'BASE'
-SUP_MODULE_SEC = 'SEC'
-SUP_MODULE_PEI_CORE = 'PEI_CORE'
-SUP_MODULE_PEIM = 'PEIM'
-SUP_MODULE_DXE_CORE = 'DXE_CORE'
-SUP_MODULE_DXE_DRIVER = 'DXE_DRIVER'
-SUP_MODULE_DXE_RUNTIME_DRIVER = 'DXE_RUNTIME_DRIVER'
-SUP_MODULE_DXE_SAL_DRIVER = 'DXE_SAL_DRIVER'
-SUP_MODULE_DXE_SMM_DRIVER = 'DXE_SMM_DRIVER'
-SUP_MODULE_UEFI_DRIVER = 'UEFI_DRIVER'
-SUP_MODULE_UEFI_APPLICATION = 'UEFI_APPLICATION'
-SUP_MODULE_USER_DEFINED = 'USER_DEFINED'
-SUP_MODULE_SMM_CORE = 'SMM_CORE'
-
-SUP_MODULE_LIST = \
-[SUP_MODULE_BASE, SUP_MODULE_SEC, SUP_MODULE_PEI_CORE, SUP_MODULE_PEIM, \
-SUP_MODULE_DXE_CORE, SUP_MODULE_DXE_DRIVER, \
- SUP_MODULE_DXE_RUNTIME_DRIVER, SUP_MODULE_DXE_SAL_DRIVER, \
- SUP_MODULE_DXE_SMM_DRIVER, SUP_MODULE_UEFI_DRIVER, \
- SUP_MODULE_UEFI_APPLICATION, SUP_MODULE_USER_DEFINED, \
- SUP_MODULE_SMM_CORE]
-SUP_MODULE_LIST_STRING = TAB_VALUE_SPLIT.join(l for l in SUP_MODULE_LIST)
-
-EDK_COMPONENT_TYPE_LIBRARY = 'LIBRARY'
-EDK_COMPONENT_TYPE_SECUARITY_CORE = 'SECUARITY_CORE'
-EDK_COMPONENT_TYPE_PEI_CORE = 'PEI_CORE'
-EDK_COMPONENT_TYPE_COMBINED_PEIM_DRIVER = 'COMBINED_PEIM_DRIVER'
-EDK_COMPONENT_TYPE_PIC_PEIM = 'PIC_PEIM'
-EDK_COMPONENT_TYPE_RELOCATABLE_PEIM = 'RELOCATABLE_PEIM'
-EDK_COMPONENT_TYPE_BS_DRIVER = 'BS_DRIVER'
-EDK_COMPONENT_TYPE_RT_DRIVER = 'RT_DRIVER'
-EDK_COMPONENT_TYPE_SAL_RT_DRIVER = 'SAL_RT_DRIVER'
-EDK_COMPONENT_TYPE_APPLICATION = 'APPLICATION'
-EDK_NAME = 'EDK'
-EDKII_NAME = 'EDKII'
-
-BINARY_FILE_TYPE_FW = 'FW'
-BINARY_FILE_TYPE_GUID = 'GUID'
-BINARY_FILE_TYPE_PREEFORM = 'PREEFORM'
-BINARY_FILE_TYPE_UEFI_APP = 'UEFI_APP'
-BINARY_FILE_TYPE_UNI_UI = 'UNI_UI'
-BINARY_FILE_TYPE_SEC_UI = 'SEC_UI'
-BINARY_FILE_TYPE_UNI_VER = 'UNI_VER'
-BINARY_FILE_TYPE_SEC_VER = 'SEC_VER'
-BINARY_FILE_TYPE_LIB = 'LIB'
-BINARY_FILE_TYPE_PE32 = 'PE32'
-BINARY_FILE_TYPE_PIC = 'PIC'
-BINARY_FILE_TYPE_PEI_DEPEX = 'PEI_DEPEX'
-BINARY_FILE_TYPE_DXE_DEPEX = 'DXE_DEPEX'
-BINARY_FILE_TYPE_SMM_DEPEX = 'SMM_DEPEX'
-BINARY_FILE_TYPE_TE = 'TE'
-BINARY_FILE_TYPE_VER = 'VER'
-BINARY_FILE_TYPE_UI = 'UI'
-BINARY_FILE_TYPE_BIN = 'BIN'
-BINARY_FILE_TYPE_FV = 'FV'
-BINARY_FILE_TYPE_UI_LIST = [BINARY_FILE_TYPE_UNI_UI,
- BINARY_FILE_TYPE_SEC_UI,
- BINARY_FILE_TYPE_UI
- ]
-BINARY_FILE_TYPE_VER_LIST = [BINARY_FILE_TYPE_UNI_VER,
- BINARY_FILE_TYPE_SEC_VER,
- BINARY_FILE_TYPE_VER
- ]
-
-DEPEX_SECTION_LIST = ['<PEI_DEPEX>',
- '<DXE_DEPEX>',
- '<SMM_DEPEX>'
- ]
-
-PLATFORM_COMPONENT_TYPE_LIBRARY = 'LIBRARY'
-PLATFORM_COMPONENT_TYPE_LIBRARY_CLASS = 'LIBRARY_CLASS'
-PLATFORM_COMPONENT_TYPE_MODULE = 'MODULE'
-
-TAB_LIBRARIES = 'Libraries'
-
-TAB_SOURCE = 'Source'
-TAB_SOURCES = 'Sources'
-TAB_SOURCES_COMMON = TAB_SOURCES + TAB_SPLIT + TAB_ARCH_COMMON
-TAB_SOURCES_IA32 = TAB_SOURCES + TAB_SPLIT + TAB_ARCH_IA32
-TAB_SOURCES_X64 = TAB_SOURCES + TAB_SPLIT + TAB_ARCH_X64
-TAB_SOURCES_IPF = TAB_SOURCES + TAB_SPLIT + TAB_ARCH_IPF
-TAB_SOURCES_ARM = TAB_SOURCES + TAB_SPLIT + TAB_ARCH_ARM
-TAB_SOURCES_LOONGARCH64 = TAB_SOURCES + TAB_SPLIT + TAB_ARCH_LOONGARCH64
-TAB_SOURCES_EBC = TAB_SOURCES + TAB_SPLIT + TAB_ARCH_EBC
-
-TAB_BINARIES = 'Binaries'
-TAB_BINARIES_COMMON = TAB_BINARIES + TAB_SPLIT + TAB_ARCH_COMMON
-TAB_BINARIES_IA32 = TAB_BINARIES + TAB_SPLIT + TAB_ARCH_IA32
-TAB_BINARIES_X64 = TAB_BINARIES + TAB_SPLIT + TAB_ARCH_X64
-TAB_BINARIES_IPF = TAB_BINARIES + TAB_SPLIT + TAB_ARCH_IPF
-TAB_BINARIES_ARM = TAB_BINARIES + TAB_SPLIT + TAB_ARCH_ARM
-TAB_BINARIES_LOONGARCH64 = TAB_BINARIES + TAB_SPLIT + TAB_ARCH_LOONGARCH64
-TAB_BINARIES_EBC = TAB_BINARIES + TAB_SPLIT + TAB_ARCH_EBC
-
-TAB_INCLUDES = 'Includes'
-TAB_INCLUDES_COMMON = TAB_INCLUDES + TAB_SPLIT + TAB_ARCH_COMMON
-TAB_INCLUDES_IA32 = TAB_INCLUDES + TAB_SPLIT + TAB_ARCH_IA32
-TAB_INCLUDES_X64 = TAB_INCLUDES + TAB_SPLIT + TAB_ARCH_X64
-TAB_INCLUDES_IPF = TAB_INCLUDES + TAB_SPLIT + TAB_ARCH_IPF
-TAB_INCLUDES_ARM = TAB_INCLUDES + TAB_SPLIT + TAB_ARCH_ARM
-TAB_INCLUDES_LOONGARCH64 = TAB_INCLUDES + TAB_SPLIT + TAB_ARCH_LOONGARCH64
-TAB_INCLUDES_EBC = TAB_INCLUDES + TAB_SPLIT + TAB_ARCH_EBC
-
-TAB_GUIDS = 'Guids'
-TAB_GUIDS_COMMON = TAB_GUIDS + TAB_SPLIT + TAB_ARCH_COMMON
-TAB_GUIDS_IA32 = TAB_GUIDS + TAB_SPLIT + TAB_ARCH_IA32
-TAB_GUIDS_X64 = TAB_GUIDS + TAB_SPLIT + TAB_ARCH_X64
-TAB_GUIDS_IPF = TAB_GUIDS + TAB_SPLIT + TAB_ARCH_IPF
-TAB_GUIDS_ARM = TAB_GUIDS + TAB_SPLIT + TAB_ARCH_ARM
-TAB_GUIDS_LOONGARCH64 = TAB_GUIDS + TAB_SPLIT + TAB_ARCH_LOONGARCH64
-TAB_GUIDS_EBC = TAB_GUIDS + TAB_SPLIT + TAB_ARCH_EBC
-
-TAB_PROTOCOLS = 'Protocols'
-TAB_PROTOCOLS_COMMON = TAB_PROTOCOLS + TAB_SPLIT + TAB_ARCH_COMMON
-TAB_PROTOCOLS_IA32 = TAB_PROTOCOLS + TAB_SPLIT + TAB_ARCH_IA32
-TAB_PROTOCOLS_X64 = TAB_PROTOCOLS + TAB_SPLIT + TAB_ARCH_X64
-TAB_PROTOCOLS_IPF = TAB_PROTOCOLS + TAB_SPLIT + TAB_ARCH_IPF
-TAB_PROTOCOLS_ARM = TAB_PROTOCOLS + TAB_SPLIT + TAB_ARCH_ARM
-TAB_PROTOCOLS_LOONGARCH64 = TAB_PROTOCOLS + TAB_SPLIT + TAB_ARCH_LOONGARCH64
-TAB_PROTOCOLS_EBC = TAB_PROTOCOLS + TAB_SPLIT + TAB_ARCH_EBC
-
-TAB_PPIS = 'Ppis'
-TAB_PPIS_COMMON = TAB_PPIS + TAB_SPLIT + TAB_ARCH_COMMON
-TAB_PPIS_IA32 = TAB_PPIS + TAB_SPLIT + TAB_ARCH_IA32
-TAB_PPIS_X64 = TAB_PPIS + TAB_SPLIT + TAB_ARCH_X64
-TAB_PPIS_IPF = TAB_PPIS + TAB_SPLIT + TAB_ARCH_IPF
-TAB_PPIS_ARM = TAB_PPIS + TAB_SPLIT + TAB_ARCH_ARM
-TAB_PPIS_LOONGARCH64 = TAB_PPIS + TAB_SPLIT + TAB_ARCH_LOONGARCH64
-TAB_PPIS_EBC = TAB_PPIS + TAB_SPLIT + TAB_ARCH_EBC
-
-TAB_LIBRARY_CLASSES = 'LibraryClasses'
-TAB_LIBRARY_CLASSES_COMMON = TAB_LIBRARY_CLASSES + TAB_SPLIT + TAB_ARCH_COMMON
-TAB_LIBRARY_CLASSES_IA32 = TAB_LIBRARY_CLASSES + TAB_SPLIT + TAB_ARCH_IA32
-TAB_LIBRARY_CLASSES_X64 = TAB_LIBRARY_CLASSES + TAB_SPLIT + TAB_ARCH_X64
-TAB_LIBRARY_CLASSES_IPF = TAB_LIBRARY_CLASSES + TAB_SPLIT + TAB_ARCH_IPF
-TAB_LIBRARY_CLASSES_ARM = TAB_LIBRARY_CLASSES + TAB_SPLIT + TAB_ARCH_ARM
-TAB_LIBRARY_CLASSES_LOONGARCH64 = TAB_LIBRARY_CLASSES + TAB_SPLIT + TAB_ARCH_LOONGARCH64
-TAB_LIBRARY_CLASSES_EBC = TAB_LIBRARY_CLASSES + TAB_SPLIT + TAB_ARCH_EBC
-
-TAB_PACKAGES = 'Packages'
-TAB_PACKAGES_COMMON = TAB_PACKAGES + TAB_SPLIT + TAB_ARCH_COMMON
-TAB_PACKAGES_IA32 = TAB_PACKAGES + TAB_SPLIT + TAB_ARCH_IA32
-TAB_PACKAGES_X64 = TAB_PACKAGES + TAB_SPLIT + TAB_ARCH_X64
-TAB_PACKAGES_IPF = TAB_PACKAGES + TAB_SPLIT + TAB_ARCH_IPF
-TAB_PACKAGES_ARM = TAB_PACKAGES + TAB_SPLIT + TAB_ARCH_ARM
-TAB_PACKAGES_LOONGARCH64 = TAB_PACKAGES + TAB_SPLIT + TAB_ARCH_LOONGARCH64
-TAB_PACKAGES_EBC = TAB_PACKAGES + TAB_SPLIT + TAB_ARCH_EBC
-
-TAB_PCDS = 'Pcds'
-TAB_PCDS_FIXED_AT_BUILD = 'FixedAtBuild'
-TAB_PCDS_PATCHABLE_IN_MODULE = 'PatchableInModule'
-TAB_PCDS_FEATURE_FLAG = 'FeatureFlag'
-TAB_PCDS_DYNAMIC_EX = 'DynamicEx'
-TAB_PCDS_DYNAMIC_EX_DEFAULT = 'DynamicExDefault'
-TAB_PCDS_DYNAMIC_EX_VPD = 'DynamicExVpd'
-TAB_PCDS_DYNAMIC_EX_HII = 'DynamicExHii'
-TAB_PCDS_DYNAMIC = 'Dynamic'
-TAB_PCDS_DYNAMIC_DEFAULT = 'DynamicDefault'
-TAB_PCDS_DYNAMIC_VPD = 'DynamicVpd'
-TAB_PCDS_DYNAMIC_HII = 'DynamicHii'
-
-TAB_PTR_TYPE_PCD = 'VOID*'
-
-PCD_DYNAMIC_TYPE_LIST = [TAB_PCDS_DYNAMIC, TAB_PCDS_DYNAMIC_DEFAULT, \
- TAB_PCDS_DYNAMIC_VPD, TAB_PCDS_DYNAMIC_HII]
-PCD_DYNAMIC_EX_TYPE_LIST = [TAB_PCDS_DYNAMIC_EX, TAB_PCDS_DYNAMIC_EX_DEFAULT, \
- TAB_PCDS_DYNAMIC_EX_VPD, TAB_PCDS_DYNAMIC_EX_HII]
-
-## Dynamic-ex PCD types
-#
-gDYNAMIC_EX_PCD = [TAB_PCDS_DYNAMIC_EX, TAB_PCDS_DYNAMIC_EX_DEFAULT, \
- TAB_PCDS_DYNAMIC_EX_VPD, TAB_PCDS_DYNAMIC_EX_HII]
-
-TAB_PCDS_FIXED_AT_BUILD_NULL = TAB_PCDS + TAB_PCDS_FIXED_AT_BUILD
-TAB_PCDS_FIXED_AT_BUILD_COMMON = TAB_PCDS + TAB_PCDS_FIXED_AT_BUILD + \
-TAB_SPLIT + TAB_ARCH_COMMON
-TAB_PCDS_FIXED_AT_BUILD_IA32 = TAB_PCDS + TAB_PCDS_FIXED_AT_BUILD + \
-TAB_SPLIT + TAB_ARCH_IA32
-TAB_PCDS_FIXED_AT_BUILD_X64 = TAB_PCDS + TAB_PCDS_FIXED_AT_BUILD + \
-TAB_SPLIT + TAB_ARCH_X64
-TAB_PCDS_FIXED_AT_BUILD_IPF = TAB_PCDS + TAB_PCDS_FIXED_AT_BUILD + \
-TAB_SPLIT + TAB_ARCH_IPF
-TAB_PCDS_FIXED_AT_BUILD_ARM = TAB_PCDS + TAB_PCDS_FIXED_AT_BUILD + \
-TAB_SPLIT + TAB_ARCH_ARM
-TAB_PCDS_FIXED_AT_BUILD_LOONGARCH64 = TAB_PCDS + TAB_PCDS_FIXED_AT_BUILD + \
-TAB_SPLIT + TAB_ARCH_LOONGARCH64
-TAB_PCDS_FIXED_AT_BUILD_EBC = TAB_PCDS + TAB_PCDS_FIXED_AT_BUILD + \
-TAB_SPLIT + TAB_ARCH_EBC
-
-TAB_PCDS_PATCHABLE_IN_MODULE_NULL = TAB_PCDS + TAB_PCDS_PATCHABLE_IN_MODULE
-TAB_PCDS_PATCHABLE_IN_MODULE_COMMON = TAB_PCDS + TAB_PCDS_PATCHABLE_IN_MODULE \
-+ TAB_SPLIT + TAB_ARCH_COMMON
-TAB_PCDS_PATCHABLE_IN_MODULE_IA32 = TAB_PCDS + TAB_PCDS_PATCHABLE_IN_MODULE + \
-TAB_SPLIT + TAB_ARCH_IA32
-TAB_PCDS_PATCHABLE_IN_MODULE_X64 = TAB_PCDS + TAB_PCDS_PATCHABLE_IN_MODULE + \
-TAB_SPLIT + TAB_ARCH_X64
-TAB_PCDS_PATCHABLE_IN_MODULE_IPF = TAB_PCDS + TAB_PCDS_PATCHABLE_IN_MODULE + \
-TAB_SPLIT + TAB_ARCH_IPF
-TAB_PCDS_PATCHABLE_IN_MODULE_ARM = TAB_PCDS + TAB_PCDS_PATCHABLE_IN_MODULE + \
-TAB_SPLIT + TAB_ARCH_ARM
-TAB_PCDS_PATCHABLE_IN_MODULE_LOONGARCH64 = TAB_PCDS + TAB_PCDS_PATCHABLE_IN_MODULE + \
-TAB_SPLIT + TAB_ARCH_LOONGARCH64
-TAB_PCDS_PATCHABLE_IN_MODULE_EBC = TAB_PCDS + TAB_PCDS_PATCHABLE_IN_MODULE + \
-TAB_SPLIT + TAB_ARCH_EBC
-
-TAB_PCDS_FEATURE_FLAG_NULL = TAB_PCDS + TAB_PCDS_FEATURE_FLAG
-TAB_PCDS_FEATURE_FLAG_COMMON = TAB_PCDS + TAB_PCDS_FEATURE_FLAG + TAB_SPLIT \
-+ TAB_ARCH_COMMON
-TAB_PCDS_FEATURE_FLAG_IA32 = TAB_PCDS + TAB_PCDS_FEATURE_FLAG + TAB_SPLIT + \
-TAB_ARCH_IA32
-TAB_PCDS_FEATURE_FLAG_X64 = TAB_PCDS + TAB_PCDS_FEATURE_FLAG + TAB_SPLIT + \
-TAB_ARCH_X64
-TAB_PCDS_FEATURE_FLAG_IPF = TAB_PCDS + TAB_PCDS_FEATURE_FLAG + TAB_SPLIT + \
-TAB_ARCH_IPF
-TAB_PCDS_FEATURE_FLAG_ARM = TAB_PCDS + TAB_PCDS_FEATURE_FLAG + TAB_SPLIT + \
-TAB_ARCH_ARM
-TAB_PCDS_FEATURE_FLAG_LOONGARCH64 = TAB_PCDS + TAB_PCDS_FEATURE_FLAG + TAB_SPLIT + \
-TAB_ARCH_LOONGARCH64
-TAB_PCDS_FEATURE_FLAG_EBC = TAB_PCDS + TAB_PCDS_FEATURE_FLAG + TAB_SPLIT + \
-TAB_ARCH_EBC
-
-TAB_PCDS_DYNAMIC_EX_NULL = TAB_PCDS + TAB_PCDS_DYNAMIC_EX
-TAB_PCDS_DYNAMIC_EX_DEFAULT_NULL = TAB_PCDS + TAB_PCDS_DYNAMIC_EX_DEFAULT
-TAB_PCDS_DYNAMIC_EX_HII_NULL = TAB_PCDS + TAB_PCDS_DYNAMIC_EX_HII
-TAB_PCDS_DYNAMIC_EX_VPD_NULL = TAB_PCDS + TAB_PCDS_DYNAMIC_EX_VPD
-TAB_PCDS_DYNAMIC_EX_COMMON = TAB_PCDS + TAB_PCDS_DYNAMIC_EX + TAB_SPLIT + \
-TAB_ARCH_COMMON
-TAB_PCDS_DYNAMIC_EX_IA32 = TAB_PCDS + TAB_PCDS_DYNAMIC_EX + TAB_SPLIT + \
-TAB_ARCH_IA32
-TAB_PCDS_DYNAMIC_EX_X64 = TAB_PCDS + TAB_PCDS_DYNAMIC_EX + TAB_SPLIT + \
-TAB_ARCH_X64
-TAB_PCDS_DYNAMIC_EX_IPF = TAB_PCDS + TAB_PCDS_DYNAMIC_EX + TAB_SPLIT + \
-TAB_ARCH_IPF
-TAB_PCDS_DYNAMIC_EX_ARM = TAB_PCDS + TAB_PCDS_DYNAMIC_EX + TAB_SPLIT + \
-TAB_ARCH_ARM
-TAB_PCDS_DYNAMIC_EX_LOONGARCH64 = TAB_PCDS + TAB_PCDS_DYNAMIC_EX + TAB_SPLIT + \
-TAB_ARCH_LOONGARCH64
-TAB_PCDS_DYNAMIC_EX_EBC = TAB_PCDS + TAB_PCDS_DYNAMIC_EX + TAB_SPLIT + \
-TAB_ARCH_EBC
-
-TAB_PCDS_DYNAMIC_NULL = TAB_PCDS + TAB_PCDS_DYNAMIC
-TAB_PCDS_DYNAMIC_DEFAULT_NULL = TAB_PCDS + TAB_PCDS_DYNAMIC_DEFAULT
-TAB_PCDS_DYNAMIC_HII_NULL = TAB_PCDS + TAB_PCDS_DYNAMIC_HII
-TAB_PCDS_DYNAMIC_VPD_NULL = TAB_PCDS + TAB_PCDS_DYNAMIC_VPD
-TAB_PCDS_DYNAMIC_COMMON = TAB_PCDS + TAB_PCDS_DYNAMIC + TAB_SPLIT + \
-TAB_ARCH_COMMON
-TAB_PCDS_DYNAMIC_IA32 = TAB_PCDS + TAB_PCDS_DYNAMIC + TAB_SPLIT + TAB_ARCH_IA32
-TAB_PCDS_DYNAMIC_X64 = TAB_PCDS + TAB_PCDS_DYNAMIC + TAB_SPLIT + TAB_ARCH_X64
-TAB_PCDS_DYNAMIC_IPF = TAB_PCDS + TAB_PCDS_DYNAMIC + TAB_SPLIT + TAB_ARCH_IPF
-TAB_PCDS_DYNAMIC_ARM = TAB_PCDS + TAB_PCDS_DYNAMIC + TAB_SPLIT + TAB_ARCH_ARM
-TAB_PCDS_DYNAMIC_LOONGARCH64 = TAB_PCDS + TAB_PCDS_DYNAMIC + TAB_SPLIT + TAB_ARCH_LOONGARCH64
-TAB_PCDS_DYNAMIC_EBC = TAB_PCDS + TAB_PCDS_DYNAMIC + TAB_SPLIT + TAB_ARCH_EBC
-
-TAB_PCD_DYNAMIC_TYPE_LIST = [TAB_PCDS_DYNAMIC_DEFAULT_NULL, \
- TAB_PCDS_DYNAMIC_VPD_NULL, \
- TAB_PCDS_DYNAMIC_HII_NULL]
-TAB_PCD_DYNAMIC_EX_TYPE_LIST = [TAB_PCDS_DYNAMIC_EX_DEFAULT_NULL, \
- TAB_PCDS_DYNAMIC_EX_VPD_NULL, \
- TAB_PCDS_DYNAMIC_EX_HII_NULL]
-
-TAB_PCDS_PATCHABLE_LOAD_FIX_ADDRESS_PEI_PAGE_SIZE = \
-'PcdLoadFixAddressPeiCodePageNumber'
-TAB_PCDS_PATCHABLE_LOAD_FIX_ADDRESS_PEI_PAGE_SIZE_DATA_TYPE = 'UINT32'
-TAB_PCDS_PATCHABLE_LOAD_FIX_ADDRESS_DXE_PAGE_SIZE = \
-'PcdLoadFixAddressBootTimeCodePageNumber'
-TAB_PCDS_PATCHABLE_LOAD_FIX_ADDRESS_DXE_PAGE_SIZE_DATA_TYPE = 'UINT32'
-TAB_PCDS_PATCHABLE_LOAD_FIX_ADDRESS_RUNTIME_PAGE_SIZE = \
-'PcdLoadFixAddressRuntimeCodePageNumber'
-TAB_PCDS_PATCHABLE_LOAD_FIX_ADDRESS_RUNTIME_PAGE_SIZE_DATA_TYPE = 'UINT32'
-TAB_PCDS_PATCHABLE_LOAD_FIX_ADDRESS_SMM_PAGE_SIZE = \
-'PcdLoadFixAddressSmmCodePageNumber'
-TAB_PCDS_PATCHABLE_LOAD_FIX_ADDRESS_SMM_PAGE_SIZE_DATA_TYPE = 'UINT32'
-TAB_PCDS_PATCHABLE_LOAD_FIX_ADDRESS_LIST = \
-[TAB_PCDS_PATCHABLE_LOAD_FIX_ADDRESS_PEI_PAGE_SIZE, \
-TAB_PCDS_PATCHABLE_LOAD_FIX_ADDRESS_DXE_PAGE_SIZE, \
-TAB_PCDS_PATCHABLE_LOAD_FIX_ADDRESS_RUNTIME_PAGE_SIZE, \
-TAB_PCDS_PATCHABLE_LOAD_FIX_ADDRESS_SMM_PAGE_SIZE]
-PCD_SECTION_LIST = [TAB_PCDS_FIXED_AT_BUILD_NULL.upper(), \
- TAB_PCDS_PATCHABLE_IN_MODULE_NULL.upper(), \
- TAB_PCDS_FEATURE_FLAG_NULL.upper(), \
- TAB_PCDS_DYNAMIC_EX_NULL.upper(), \
- TAB_PCDS_DYNAMIC_NULL.upper()]
-INF_PCD_SECTION_LIST = ["FixedPcd".upper(), "FeaturePcd".upper(), \
- "PatchPcd".upper(), "Pcd".upper(), "PcdEx".upper()]
-
-TAB_DEPEX = 'Depex'
-TAB_DEPEX_COMMON = TAB_DEPEX + TAB_SPLIT + TAB_ARCH_COMMON
-TAB_DEPEX_IA32 = TAB_DEPEX + TAB_SPLIT + TAB_ARCH_IA32
-TAB_DEPEX_X64 = TAB_DEPEX + TAB_SPLIT + TAB_ARCH_X64
-TAB_DEPEX_IPF = TAB_DEPEX + TAB_SPLIT + TAB_ARCH_IPF
-TAB_DEPEX_ARM = TAB_DEPEX + TAB_SPLIT + TAB_ARCH_ARM
-TAB_DEPEX_LOONGARCH64 = TAB_DEPEX + TAB_SPLIT + TAB_ARCH_LOONGARCH64
-TAB_DEPEX_EBC = TAB_DEPEX + TAB_SPLIT + TAB_ARCH_EBC
-
-TAB_SKUIDS = 'SkuIds'
-
-TAB_LIBRARIES = 'Libraries'
-TAB_LIBRARIES_COMMON = TAB_LIBRARIES + TAB_SPLIT + TAB_ARCH_COMMON
-TAB_LIBRARIES_IA32 = TAB_LIBRARIES + TAB_SPLIT + TAB_ARCH_IA32
-TAB_LIBRARIES_X64 = TAB_LIBRARIES + TAB_SPLIT + TAB_ARCH_X64
-TAB_LIBRARIES_IPF = TAB_LIBRARIES + TAB_SPLIT + TAB_ARCH_IPF
-TAB_LIBRARIES_ARM = TAB_LIBRARIES + TAB_SPLIT + TAB_ARCH_ARM
-TAB_LIBRARIES_LOONGARCH64 = TAB_LIBRARIES + TAB_SPLIT + TAB_ARCH_LOONGARCH64
-TAB_LIBRARIES_EBC = TAB_LIBRARIES + TAB_SPLIT + TAB_ARCH_EBC
-
-TAB_COMPONENTS = 'Components'
-TAB_COMPONENTS_COMMON = TAB_COMPONENTS + TAB_SPLIT + TAB_ARCH_COMMON
-TAB_COMPONENTS_IA32 = TAB_COMPONENTS + TAB_SPLIT + TAB_ARCH_IA32
-TAB_COMPONENTS_X64 = TAB_COMPONENTS + TAB_SPLIT + TAB_ARCH_X64
-TAB_COMPONENTS_IPF = TAB_COMPONENTS + TAB_SPLIT + TAB_ARCH_IPF
-TAB_COMPONENTS_ARM = TAB_COMPONENTS + TAB_SPLIT + TAB_ARCH_ARM
-TAB_COMPONENTS_LOONGARCH64 = TAB_COMPONENTS + TAB_SPLIT + TAB_ARCH_LOONGARCH64
-TAB_COMPONENTS_EBC = TAB_COMPONENTS + TAB_SPLIT + TAB_ARCH_EBC
-
-TAB_BUILD_OPTIONS = 'BuildOptions'
-
-TAB_DEFINE = 'DEFINE'
-TAB_NMAKE = 'Nmake'
-TAB_USER_EXTENSIONS = 'UserExtensions'
-TAB_INCLUDE = '!include'
-TAB_PRIVATE = 'Private'
-TAB_INTEL = 'Intel'
-
-#
-# Common Define
-#
-TAB_COMMON_DEFINES = 'Defines'
-
-#
-# Inf Definitions
-#
-TAB_INF_DEFINES = TAB_COMMON_DEFINES
-TAB_INF_DEFINES_INF_VERSION = 'INF_VERSION'
-TAB_INF_DEFINES_BASE_NAME = 'BASE_NAME'
-TAB_INF_DEFINES_FILE_GUID = 'FILE_GUID'
-TAB_INF_DEFINES_MODULE_TYPE = 'MODULE_TYPE'
-TAB_INF_DEFINES_EFI_SPECIFICATION_VERSION = 'EFI_SPECIFICATION_VERSION'
-TAB_INF_DEFINES_UEFI_SPECIFICATION_VERSION = 'UEFI_SPECIFICATION_VERSION'
-TAB_INF_DEFINES_PI_SPECIFICATION_VERSION = 'PI_SPECIFICATION_VERSION'
-TAB_INF_DEFINES_EDK_RELEASE_VERSION = 'EDK_RELEASE_VERSION'
-TAB_INF_DEFINES_MODULE_UNI_FILE = 'MODULE_UNI_FILE'
-TAB_INF_DEFINES_BINARY_MODULE = 'BINARY_MODULE'
-TAB_INF_DEFINES_LIBRARY_CLASS = 'LIBRARY_CLASS'
-TAB_INF_DEFINES_COMPONENT_TYPE = 'COMPONENT_TYPE'
-TAB_INF_DEFINES_MAKEFILE_NAME = 'MAKEFILE_NAME'
-TAB_INF_DEFINES_BUILD_NUMBER = 'BUILD_NUMBER'
-TAB_INF_DEFINES_BUILD_TYPE = 'BUILD_TYPE'
-TAB_INF_DEFINES_FFS_EXT = 'FFS_EXT'
-TAB_INF_DEFINES_FV_EXT = 'FV_EXT'
-TAB_INF_DEFINES_SOURCE_FV = 'SOURCE_FV'
-TAB_INF_DEFINES_PACKAGE = 'PACKAGE'
-TAB_INF_DEFINES_VERSION_NUMBER = 'VERSION_NUMBER'
-TAB_INF_DEFINES_VERSION = 'VERSION'
-TAB_INF_DEFINES_VERSION_STRING = 'VERSION_STRING'
-TAB_INF_DEFINES_PCD_IS_DRIVER = 'PCD_IS_DRIVER'
-TAB_INF_DEFINES_TIANO_EDK1_FLASHMAP_H = 'TIANO_EDK1_FLASHMAP_H'
-TAB_INF_DEFINES_ENTRY_POINT = 'ENTRY_POINT'
-TAB_INF_DEFINES_UNLOAD_IMAGE = 'UNLOAD_IMAGE'
-TAB_INF_DEFINES_CONSTRUCTOR = 'CONSTRUCTOR'
-TAB_INF_DEFINES_DESTRUCTOR = 'DESTRUCTOR'
-TAB_INF_DEFINES_PCI_VENDOR_ID = 'PCI_VENDOR_ID'
-TAB_INF_DEFINES_PCI_DEVICE_ID = 'PCI_DEVICE_ID'
-TAB_INF_DEFINES_PCI_CLASS_CODE = 'PCI_CLASS_CODE'
-TAB_INF_DEFINES_PCI_REVISION = 'PCI_REVISION'
-TAB_INF_DEFINES_PCI_COMPRESS = 'PCI_COMPRESS'
-TAB_INF_DEFINES_DEFINE = 'DEFINE'
-TAB_INF_DEFINES_SPEC = 'SPEC'
-TAB_INF_DEFINES_UEFI_HII_RESOURCE_SECTION = 'UEFI_HII_RESOURCE_SECTION'
-TAB_INF_DEFINES_CUSTOM_MAKEFILE = 'CUSTOM_MAKEFILE'
-TAB_INF_DEFINES_MACRO = '__MACROS__'
-TAB_INF_DEFINES_SHADOW = 'SHADOW'
-TAB_INF_DEFINES_DPX_SOURCE = 'DPX_SOURCE'
-TAB_INF_FIXED_PCD = 'FixedPcd'
-TAB_INF_FEATURE_PCD = 'FeaturePcd'
-TAB_INF_PATCH_PCD = 'PatchPcd'
-TAB_INF_PCD = 'Pcd'
-TAB_INF_PCD_EX = 'PcdEx'
-TAB_INF_GUIDTYPE_VAR = 'Variable'
-TAB_INF_ABSTRACT = 'STR_MODULE_ABSTRACT'
-TAB_INF_DESCRIPTION = 'STR_MODULE_DESCRIPTION'
-TAB_INF_LICENSE = 'STR_MODULE_LICENSE'
-TAB_INF_BINARY_ABSTRACT = 'STR_MODULE_BINARY_ABSTRACT'
-TAB_INF_BINARY_DESCRIPTION = 'STR_MODULE_BINARY_DESCRIPTION'
-TAB_INF_BINARY_LICENSE = 'STR_MODULE_BINARY_LICENSE'
-#
-# Dec Definitions
-#
-TAB_DEC_DEFINES = TAB_COMMON_DEFINES
-TAB_DEC_DEFINES_DEC_SPECIFICATION = 'DEC_SPECIFICATION'
-TAB_DEC_DEFINES_PACKAGE_NAME = 'PACKAGE_NAME'
-TAB_DEC_DEFINES_PACKAGE_GUID = 'PACKAGE_GUID'
-TAB_DEC_DEFINES_PACKAGE_VERSION = 'PACKAGE_VERSION'
-TAB_DEC_DEFINES_PKG_UNI_FILE = 'PACKAGE_UNI_FILE'
-TAB_DEC_PACKAGE_ABSTRACT = 'STR_PACKAGE_ABSTRACT'
-TAB_DEC_PACKAGE_DESCRIPTION = 'STR_PACKAGE_DESCRIPTION'
-TAB_DEC_PACKAGE_LICENSE = 'STR_PACKAGE_LICENSE'
-TAB_DEC_BINARY_ABSTRACT = 'STR_PACKAGE_BINARY_ABSTRACT'
-TAB_DEC_BINARY_DESCRIPTION = 'STR_PACKAGE_BINARY_DESCRIPTION'
-TAB_DEC_BINARY_LICENSE = 'STR_PACKAGE_ASBUILT_LICENSE'
-#
-# Dsc Definitions
-#
-TAB_DSC_DEFINES = TAB_COMMON_DEFINES
-TAB_DSC_DEFINES_PLATFORM_NAME = 'PLATFORM_NAME'
-TAB_DSC_DEFINES_PLATFORM_GUID = 'PLATFORM_GUID'
-TAB_DSC_DEFINES_PLATFORM_VERSION = 'PLATFORM_VERSION'
-TAB_DSC_DEFINES_DSC_SPECIFICATION = 'DSC_SPECIFICATION'
-TAB_DSC_DEFINES_OUTPUT_DIRECTORY = 'OUTPUT_DIRECTORY'
-TAB_DSC_DEFINES_SUPPORTED_ARCHITECTURES = 'SUPPORTED_ARCHITECTURES'
-TAB_DSC_DEFINES_BUILD_TARGETS = 'BUILD_TARGETS'
-TAB_DSC_DEFINES_SKUID_IDENTIFIER = 'SKUID_IDENTIFIER'
-TAB_DSC_DEFINES_FLASH_DEFINITION = 'FLASH_DEFINITION'
-TAB_DSC_DEFINES_BUILD_NUMBER = 'BUILD_NUMBER'
-TAB_DSC_DEFINES_MAKEFILE_NAME = 'MAKEFILE_NAME'
-TAB_DSC_DEFINES_BS_BASE_ADDRESS = 'BsBaseAddress'
-TAB_DSC_DEFINES_RT_BASE_ADDRESS = 'RtBaseAddress'
-TAB_DSC_DEFINES_DEFINE = 'DEFINE'
-TAB_FIX_LOAD_TOP_MEMORY_ADDRESS = 'FIX_LOAD_TOP_MEMORY_ADDRESS'
-
-#
-# TargetTxt Definitions
-#
-TAB_TAT_DEFINES_ACTIVE_PLATFORM = 'ACTIVE_PLATFORM'
-TAB_TAT_DEFINES_ACTIVE_MODULE = 'ACTIVE_MODULE'
-TAB_TAT_DEFINES_TOOL_CHAIN_CONF = 'TOOL_CHAIN_CONF'
-TAB_TAT_DEFINES_MULTIPLE_THREAD = 'MULTIPLE_THREAD'
-TAB_TAT_DEFINES_MAX_CONCURRENT_THREAD_NUMBER = 'MAX_CONCURRENT_THREAD_NUMBER'
-TAB_TAT_DEFINES_TARGET = 'TARGET'
-TAB_TAT_DEFINES_TOOL_CHAIN_TAG = 'TOOL_CHAIN_TAG'
-TAB_TAT_DEFINES_TARGET_ARCH = 'TARGET_ARCH'
-TAB_TAT_DEFINES_BUILD_RULE_CONF = "BUILD_RULE_CONF"
-
-#
-# ToolDef Definitions
-#
-TAB_TOD_DEFINES_TARGET = 'TARGET'
-TAB_TOD_DEFINES_TOOL_CHAIN_TAG = 'TOOL_CHAIN_TAG'
-TAB_TOD_DEFINES_TARGET_ARCH = 'TARGET_ARCH'
-TAB_TOD_DEFINES_COMMAND_TYPE = 'COMMAND_TYPE'
-TAB_TOD_DEFINES_FAMILY = 'FAMILY'
-TAB_TOD_DEFINES_BUILDRULEFAMILY = 'BUILDRULEFAMILY'
-
-#
-# Conditional Statements
-#
-TAB_IF = '!if'
-TAB_END_IF = '!endif'
-TAB_ELSE_IF = '!elseif'
-TAB_ELSE = '!else'
-TAB_IF_DEF = '!ifdef'
-TAB_IF_N_DEF = '!ifndef'
-TAB_IF_EXIST = '!if exist'
-
-#
-# Unknown section
-#
-TAB_UNKNOWN = 'UNKNOWN'
-
-#
-# Header section (virtual section for abstract, description, copyright,
-# license)
-#
-TAB_HEADER = 'Header'
-TAB_HEADER_ABSTRACT = 'Abstract'
-TAB_HEADER_DESCRIPTION = 'Description'
-TAB_HEADER_COPYRIGHT = 'Copyright'
-TAB_HEADER_LICENSE = 'License'
-TAB_BINARY_HEADER_IDENTIFIER = 'BinaryHeader'
-TAB_BINARY_HEADER_USERID = 'TianoCore'
-
-#
-# Build database path
-#
-DATABASE_PATH = ":memory:"
-#
-# used by ECC
-#
-MODIFIER_LIST = ['IN', 'OUT', 'OPTIONAL', 'UNALIGNED', 'EFI_RUNTIMESERVICE', \
- 'EFI_BOOTSERVICE', 'EFIAPI']
-#
-# Dependency Expression
-#
-DEPEX_SUPPORTED_OPCODE = ["BEFORE", "AFTER", "PUSH", "AND", "OR", "NOT", \
- "END", "SOR", "TRUE", "FALSE", '(', ')']
-
-TAB_STATIC_LIBRARY = "STATIC-LIBRARY-FILE"
-TAB_DYNAMIC_LIBRARY = "DYNAMIC-LIBRARY-FILE"
-TAB_FRAMEWORK_IMAGE = "EFI-IMAGE-FILE"
-TAB_C_CODE_FILE = "C-CODE-FILE"
-TAB_C_HEADER_FILE = "C-HEADER-FILE"
-TAB_UNICODE_FILE = "UNICODE-TEXT-FILE"
-TAB_DEPENDENCY_EXPRESSION_FILE = "DEPENDENCY-EXPRESSION-FILE"
-TAB_UNKNOWN_FILE = "UNKNOWN-TYPE-FILE"
-TAB_DEFAULT_BINARY_FILE = "_BINARY_FILE_"
-#
-# used to indicate the state of processing header comment section of dec,
-# inf files
-#
-HEADER_COMMENT_NOT_STARTED = -1
-HEADER_COMMENT_STARTED = 0
-HEADER_COMMENT_FILE = 1
-HEADER_COMMENT_ABSTRACT = 2
-HEADER_COMMENT_DESCRIPTION = 3
-HEADER_COMMENT_COPYRIGHT = 4
-HEADER_COMMENT_LICENSE = 5
-HEADER_COMMENT_END = 6
-
-#
-# Static values for data models
-#
-MODEL_UNKNOWN = 0
-
-MODEL_FILE_C = 1001
-MODEL_FILE_H = 1002
-MODEL_FILE_ASM = 1003
-MODEL_FILE_INF = 1011
-MODEL_FILE_DEC = 1012
-MODEL_FILE_DSC = 1013
-MODEL_FILE_FDF = 1014
-MODEL_FILE_INC = 1015
-MODEL_FILE_CIF = 1016
-
-MODEL_IDENTIFIER_FILE_HEADER = 2001
-MODEL_IDENTIFIER_FUNCTION_HEADER = 2002
-MODEL_IDENTIFIER_COMMENT = 2003
-MODEL_IDENTIFIER_PARAMETER = 2004
-MODEL_IDENTIFIER_STRUCTURE = 2005
-MODEL_IDENTIFIER_VARIABLE = 2006
-MODEL_IDENTIFIER_INCLUDE = 2007
-MODEL_IDENTIFIER_PREDICATE_EXPRESSION = 2008
-MODEL_IDENTIFIER_ENUMERATE = 2009
-MODEL_IDENTIFIER_PCD = 2010
-MODEL_IDENTIFIER_UNION = 2011
-MODEL_IDENTIFIER_MACRO_IFDEF = 2012
-MODEL_IDENTIFIER_MACRO_IFNDEF = 2013
-MODEL_IDENTIFIER_MACRO_DEFINE = 2014
-MODEL_IDENTIFIER_MACRO_ENDIF = 2015
-MODEL_IDENTIFIER_MACRO_PROGMA = 2016
-MODEL_IDENTIFIER_FUNCTION_CALLING = 2018
-MODEL_IDENTIFIER_TYPEDEF = 2017
-MODEL_IDENTIFIER_FUNCTION_DECLARATION = 2019
-MODEL_IDENTIFIER_ASSIGNMENT_EXPRESSION = 2020
-
-MODEL_EFI_PROTOCOL = 3001
-MODEL_EFI_PPI = 3002
-MODEL_EFI_GUID = 3003
-MODEL_EFI_LIBRARY_CLASS = 3004
-MODEL_EFI_LIBRARY_INSTANCE = 3005
-MODEL_EFI_PCD = 3006
-MODEL_EFI_SOURCE_FILE = 3007
-MODEL_EFI_BINARY_FILE = 3008
-MODEL_EFI_SKU_ID = 3009
-MODEL_EFI_INCLUDE = 3010
-MODEL_EFI_DEPEX = 3011
-
-MODEL_PCD = 4000
-MODEL_PCD_FIXED_AT_BUILD = 4001
-MODEL_PCD_PATCHABLE_IN_MODULE = 4002
-MODEL_PCD_FEATURE_FLAG = 4003
-MODEL_PCD_DYNAMIC_EX = 4004
-MODEL_PCD_DYNAMIC_EX_DEFAULT = 4005
-MODEL_PCD_DYNAMIC_EX_VPD = 4006
-MODEL_PCD_DYNAMIC_EX_HII = 4007
-MODEL_PCD_DYNAMIC = 4008
-MODEL_PCD_DYNAMIC_DEFAULT = 4009
-MODEL_PCD_DYNAMIC_VPD = 4010
-MODEL_PCD_DYNAMIC_HII = 4011
-
-MODEL_META_DATA_FILE_HEADER = 5000
-MODEL_META_DATA_HEADER = 5001
-MODEL_META_DATA_INCLUDE = 5002
-MODEL_META_DATA_DEFINE = 5003
-MODEL_META_DATA_CONDITIONAL_STATEMENT_IF = 5004
-MODEL_META_DATA_CONDITIONAL_STATEMENT_ELSE = 5005
-MODEL_META_DATA_CONDITIONAL_STATEMENT_IFDEF = 5006
-MODEL_META_DATA_CONDITIONAL_STATEMENT_IFNDEF = 5007
-MODEL_META_DATA_BUILD_OPTION = 5008
-MODEL_META_DATA_COMPONENT = 5009
-MODEL_META_DATA_USER_EXTENSION = 5010
-MODEL_META_DATA_PACKAGE = 5011
-MODEL_META_DATA_NMAKE = 5012
-MODEL_META_DATA_CONDITIONAL_STATEMENT_ELSEIF = 50013
-MODEL_META_DATA_CONDITIONAL_STATEMENT_ENDIF = 5014
-
-TOOL_FAMILY_LIST = ["MSFT",
- "INTEL",
- "GCC",
- ]
-
-TYPE_HOB_SECTION = 'HOB'
-TYPE_EVENT_SECTION = 'EVENT'
-TYPE_BOOTMODE_SECTION = 'BOOTMODE'
-
-PCD_ERR_CODE_MAX_SIZE = 4294967295
+## @file +# This file is used to define class for data type structure +# +# Copyright (c) 2011 - 2018, Intel Corporation. All rights reserved.<BR> +# Portions Copyright (c) 2022, Loongson Technology Corporation Limited. All rights reserved. +# +# SPDX-License-Identifier: BSD-2-Clause-Patent + +''' +DataType +''' + +## +# Module List Items +# +MODULE_LIST = ["BASE", + "SEC", + "PEI_CORE", + "PEIM", + "DXE_CORE", + "DXE_DRIVER", + "SMM_CORE", + "DXE_RUNTIME_DRIVER", + "DXE_SAL_DRIVER", + "DXE_SMM_DRIVER", + "UEFI_DRIVER", + "UEFI_APPLICATION", + "USER_DEFINED"] + +VALID_DEPEX_MODULE_TYPE_LIST = ["PEIM", + "DXE_DRIVER", + "DXE_SMM_DRIVER", + "DXE_RUNTIME_DRIVER", + "DXE_SAL_DRIVER", + "UEFI_DRIVER", + ] +## +# Usage List Items +# +USAGE_LIST = ["CONSUMES", + "SOMETIMES_CONSUMES", + "PRODUCES", + "SOMETIMES_PRODUCES"] + +TAB_LANGUAGE_EN_US = 'en-US' +TAB_LANGUAGE_ENG = 'eng' +TAB_LANGUAGE_EN = 'en' +TAB_LANGUAGE_EN_X = 'en-x-tianocore' + +USAGE_ITEM_PRODUCES = 'PRODUCES' +USAGE_ITEM_SOMETIMES_PRODUCES = 'SOMETIMES_PRODUCES' +USAGE_ITEM_CONSUMES = 'CONSUMES' +USAGE_ITEM_SOMETIMES_CONSUMES = 'SOMETIMES_CONSUMES' +USAGE_ITEM_TO_START = 'TO_START' +USAGE_ITEM_BY_START = 'BY_START' +USAGE_ITEM_NOTIFY = 'NOTIFY' +USAGE_ITEM_UNDEFINED = 'UNDEFINED' + +USAGE_CONSUMES_LIST = [USAGE_ITEM_CONSUMES, + 'CONSUMED', + 'ALWAYS_CONSUMED', + 'ALWAYS_CONSUMES' + ] + +USAGE_PRODUCES_LIST = [USAGE_ITEM_PRODUCES, + 'PRODUCED', + 'ALWAYS_PRODUCED', + 'ALWAYS_PRODUCES' + ] + +USAGE_SOMETIMES_PRODUCES_LIST = [USAGE_ITEM_SOMETIMES_PRODUCES, + 'SOMETIMES_PRODUCED' + ] + +USAGE_SOMETIMES_CONSUMES_LIST = [USAGE_ITEM_SOMETIMES_CONSUMES, + 'SOMETIMES_CONSUMED' + ] + +ITEM_UNDEFINED = 'UNDEFINED' + +TAB_PCD_VALIDRANGE = '@ValidRange' +TAB_PCD_VALIDLIST = '@ValidList' +TAB_PCD_EXPRESSION = '@Expression' +TAB_PCD_PROMPT = '@Prompt' +TAB_STR_TOKENCNAME = 'STR' +TAB_STR_TOKENPROMPT = 'PROMPT' +TAB_STR_TOKENHELP = 'HELP' +TAB_STR_TOKENERR = 'ERR' + +# +# Dictionary of usage tokens and their synonyms +# +ALL_USAGE_TOKENS = { + "PRODUCES" : "PRODUCES", + "PRODUCED" : "PRODUCES", + "ALWAYS_PRODUCES" : "PRODUCES", + "ALWAYS_PRODUCED" : "PRODUCES", + "SOMETIMES_PRODUCES" : "SOMETIMES_PRODUCES", + "SOMETIMES_PRODUCED" : "SOMETIMES_PRODUCES", + "CONSUMES" : "CONSUMES", + "CONSUMED" : "CONSUMES", + "ALWAYS_CONSUMES" : "CONSUMES", + "ALWAYS_CONSUMED" : "CONSUMES", + "SOMETIMES_CONSUMES" : "SOMETIMES_CONSUMES", + "SOMETIMES_CONSUMED" : "SOMETIMES_CONSUMES", + "SOMETIME_CONSUMES" : "SOMETIMES_CONSUMES", + "UNDEFINED" : "UNDEFINED" + } + +PROTOCOL_USAGE_TOKENS = { + "TO_START" : "TO_START", + "BY_START" : "BY_START" + } + +PROTOCOL_USAGE_TOKENS.update (ALL_USAGE_TOKENS) + +# +# Dictionary of GUID type tokens +# +GUID_TYPE_TOKENS = { + "Event" : "Event", + "File" : "File", + "FV" : "FV", + "GUID" : "GUID", + "Guid" : "GUID", + "HII" : "HII", + "HOB" : "HOB", + "Hob" : "HOB", + "Hob:" : "HOB", + "SystemTable" : "SystemTable", + "TokenSpaceGuid" : "TokenSpaceGuid", + "UNDEFINED" : "UNDEFINED" + } + +# +# Dictionary of Protocol Notify tokens and their synonyms +# +PROTOCOL_NOTIFY_TOKENS = { + "NOTIFY" : "NOTIFY", + "PROTOCOL_NOTIFY" : "NOTIFY", + "UNDEFINED" : "UNDEFINED" + } + +# +# Dictionary of PPI Notify tokens and their synonyms +# +PPI_NOTIFY_TOKENS = { + "NOTIFY" : "NOTIFY", + "PPI_NOTIFY" : "NOTIFY", + "UNDEFINED" : "UNDEFINED" + } + +EVENT_TOKENS = { + "EVENT_TYPE_PERIODIC_TIMER" : "EVENT_TYPE_PERIODIC_TIMER", + "EVENT_TYPE_RELATIVE_TIMER" : "EVENT_TYPE_RELATIVE_TIMER", + "UNDEFINED" : "UNDEFINED" + } + +BOOTMODE_TOKENS = { + "FULL" : "FULL", + "MINIMAL" : "MINIMAL", + "NO_CHANGE" : "NO_CHANGE", + "DIAGNOSTICS" : "DIAGNOSTICS", + "DEFAULT" : "DEFAULT", + "S2_RESUME" : "S2_RESUME", + "S3_RESUME" : "S3_RESUME", + "S4_RESUME" : "S4_RESUME", + "S5_RESUME" : "S5_RESUME", + "FLASH_UPDATE" : "FLASH_UPDATE", + "RECOVERY_FULL" : "RECOVERY_FULL", + "RECOVERY_MINIMAL" : "RECOVERY_MINIMAL", + "RECOVERY_NO_CHANGE" : "RECOVERY_NO_CHANGE", + "RECOVERY_DIAGNOSTICS" : "RECOVERY_DIAGNOSTICS", + "RECOVERY_DEFAULT" : "RECOVERY_DEFAULT", + "RECOVERY_S2_RESUME" : "RECOVERY_S2_RESUME", + "RECOVERY_S3_RESUME" : "RECOVERY_S3_RESUME", + "RECOVERY_S4_RESUME" : "RECOVERY_S4_RESUME", + "RECOVERY_S5_RESUME" : "RECOVERY_S5_RESUME", + "RECOVERY_FLASH_UPDATE" : "RECOVERY_FLASH_UPDATE", + "UNDEFINED" : "UNDEFINED" + } + +HOB_TOKENS = { + "PHIT" : "PHIT", + "MEMORY_ALLOCATION" : "MEMORY_ALLOCATION", + "LOAD_PEIM" : "LOAD_PEIM", + "RESOURCE_DESCRIPTOR" : "RESOURCE_DESCRIPTOR", + "FIRMWARE_VOLUME" : "FIRMWARE_VOLUME", + "UNDEFINED" : "UNDEFINED" + } + +## +# Usage List Items for Protocol +# +PROTOCOL_USAGE_LIST = USAGE_LIST + ["TO_START", "BY_START"] + +## +# End of Line +# Use this but not os.linesep for os.linesep has bug in it. +# +END_OF_LINE = '\n' + +## +# Arch List Items +# +ARCH_LIST = ["IA32", + "X64", + "IPF", + "EBC", + "COMMON"] +## +# PCD driver type list items +# +PCD_DRIVER_TYPE_LIST = ["PEI_PCD_DRIVER", "DXE_PCD_DRIVER"] + +## +# Boot Mode List Items +# +BOOT_MODE_LIST = ["FULL", + "MINIMAL", + "NO_CHANGE", + "DIAGNOSTICS", + "DEFAULT", + "S2_RESUME", + "S3_RESUME", + "S4_RESUME", + "S5_RESUME", + "FLASH_UPDATE", + "RECOVERY_FULL", + "RECOVERY_MINIMAL", + "RECOVERY_NO_CHANGE", + "RECOVERY_DIAGNOSTICS", + "RECOVERY_DEFAULT", + "RECOVERY_S2_RESUME", + "RECOVERY_S3_RESUME", + "RECOVERY_S4_RESUME", + "RECOVERY_S5_RESUME", + "RECOVERY_FLASH_UPDATE"] + +## +# Event Type List Items +# +EVENT_TYPE_LIST = ["EVENT_TYPE_PERIODIC_TIMER", + "EVENT_TYPE_RELATIVE_TIMER"] + +## +# Hob Type List Items +# +HOB_TYPE_LIST = ["PHIT", + "MEMORY_ALLOCATION", + "RESOURCE_DESCRIPTOR", + "FIRMWARE_VOLUME", + "LOAD_PEIM"] + +## +# GUID_TYPE_LIST +# +GUID_TYPE_LIST = ["Event", "File", "FV", "GUID", "HII", "HOB", + "SystemTable", "TokenSpaceGuid", "Variable"] +## +# PCD Usage Type List of Package +# +PCD_USAGE_TYPE_LIST_OF_PACKAGE = ["FeatureFlag", "PatchableInModule", + "FixedAtBuild", "Dynamic", "DynamicEx"] + +## +# PCD Usage Type List of Module +# +PCD_USAGE_TYPE_LIST_OF_MODULE = ["FEATUREPCD", "PATCHPCD", "FIXEDPCD", "PCD", "PCDEX"] +## +# PCD Usage Type List of UPT +# +PCD_USAGE_TYPE_LIST_OF_UPT = PCD_USAGE_TYPE_LIST_OF_MODULE + +## +# Binary File Type List +# +BINARY_FILE_TYPE_LIST = ["PE32", "PIC", "TE", "DXE_DEPEX", "VER", "UI", "COMPAT16", "FV", "BIN", "RAW", + "ACPI", "ASL", + "PEI_DEPEX", + "SMM_DEPEX", + "SUBTYPE_GUID", + "DISPOSABLE" + ] +BINARY_FILE_TYPE_LIST_IN_UDP = \ + ["GUID", "FREEFORM", + "UEFI_IMAGE", "PE32", "PIC", + "PEI_DEPEX", + "DXE_DEPEX", + "SMM_DEPEX", + "FV", "TE", + "BIN", "VER", "UI" + ] + +SUBTYPE_GUID_BINARY_FILE_TYPE = "FREEFORM" +## +# Possible values for COMPONENT_TYPE, and their descriptions, are listed in +# the table, +# "Component (module) Types." For each component, the BASE_NAME and +# COMPONENT_TYPE +# are required. The COMPONENT_TYPE definition is case sensitive. +# +COMPONENT_TYPE_LIST = [ + "APPLICATION", + "ACPITABLE", + "APRIORI", + "BINARY", + "BS_DRIVER", + "CONFIG", + "FILE", + "FVIMAGEFILE", + "LIBRARY", + "LOGO", + "LEGACY16", + "MICROCODE", + "PE32_PEIM", + "PEI_CORE", + "RAWFILE", + "RT_DRIVER", + "SAL_RT_DRIVER", + "SECURITY_CORE", + "COMBINED_PEIM_DRIVER", + "PIC_PEIM", + "RELOCATABLE_PEIM" + ] + +## +# Common Definitions +# +TAB_SPLIT = '.' +TAB_COMMENT_EDK1_START = '/*' +TAB_COMMENT_EDK1_END = '*/' +TAB_COMMENT_EDK1_SPLIT = '//' +TAB_COMMENT_SPLIT = '#' +TAB_EQUAL_SPLIT = '=' +TAB_DEQUAL_SPLIT = '==' +TAB_VALUE_SPLIT = '|' +TAB_COMMA_SPLIT = ',' +TAB_HORIZON_LINE_SPLIT = '-' +TAB_SPACE_SPLIT = ' ' +TAB_UNDERLINE_SPLIT = '_' +TAB_SEMI_COLON_SPLIT = ';' +TAB_COLON_SPLIT = ':' +TAB_SECTION_START = '[' +TAB_SECTION_END = ']' +TAB_OPTION_START = '<' +TAB_OPTION_END = '>' +TAB_SLASH = '\\' +TAB_BACK_SLASH = '/' +TAB_SPECIAL_COMMENT = '##' +TAB_HEADER_COMMENT = '@file' +TAB_BINARY_HEADER_COMMENT = '@BinaryHeader' +TAB_STAR = '*' +TAB_ENCODING_UTF16LE = 'utf_16_le' +TAB_CAPHEX_START = '0X' +TAB_HEX_START = '0x' +TAB_PCD_ERROR = 'Error' +TAB_PCD_ERROR_SECTION_COMMENT = 'Error message section' +TAB_UNI_FILE_SUFFIXS = ['.uni', '.UNI', '.Uni'] + +TAB_EDK_SOURCE = '$(EDK_SOURCE)' +TAB_EFI_SOURCE = '$(EFI_SOURCE)' +TAB_WORKSPACE = '$(WORKSPACE)' + +TAB_ARCH_NULL = '' +TAB_ARCH_COMMON = 'COMMON' +TAB_ARCH_IA32 = 'IA32' +TAB_ARCH_X64 = 'X64' +TAB_ARCH_IPF = 'IPF' +TAB_ARCH_ARM = 'ARM' +TAB_ARCH_LOONGARCH64 = 'LOONGARCH64' +TAB_ARCH_EBC = 'EBC' + +ARCH_LIST = \ +[TAB_ARCH_IA32, TAB_ARCH_X64, TAB_ARCH_IPF, TAB_ARCH_ARM, TAB_ARCH_LOONGARCH64, TAB_ARCH_EBC] + +SUP_MODULE_BASE = 'BASE' +SUP_MODULE_SEC = 'SEC' +SUP_MODULE_PEI_CORE = 'PEI_CORE' +SUP_MODULE_PEIM = 'PEIM' +SUP_MODULE_DXE_CORE = 'DXE_CORE' +SUP_MODULE_DXE_DRIVER = 'DXE_DRIVER' +SUP_MODULE_DXE_RUNTIME_DRIVER = 'DXE_RUNTIME_DRIVER' +SUP_MODULE_DXE_SAL_DRIVER = 'DXE_SAL_DRIVER' +SUP_MODULE_DXE_SMM_DRIVER = 'DXE_SMM_DRIVER' +SUP_MODULE_UEFI_DRIVER = 'UEFI_DRIVER' +SUP_MODULE_UEFI_APPLICATION = 'UEFI_APPLICATION' +SUP_MODULE_USER_DEFINED = 'USER_DEFINED' +SUP_MODULE_SMM_CORE = 'SMM_CORE' + +SUP_MODULE_LIST = \ +[SUP_MODULE_BASE, SUP_MODULE_SEC, SUP_MODULE_PEI_CORE, SUP_MODULE_PEIM, \ +SUP_MODULE_DXE_CORE, SUP_MODULE_DXE_DRIVER, \ + SUP_MODULE_DXE_RUNTIME_DRIVER, SUP_MODULE_DXE_SAL_DRIVER, \ + SUP_MODULE_DXE_SMM_DRIVER, SUP_MODULE_UEFI_DRIVER, \ + SUP_MODULE_UEFI_APPLICATION, SUP_MODULE_USER_DEFINED, \ + SUP_MODULE_SMM_CORE] +SUP_MODULE_LIST_STRING = TAB_VALUE_SPLIT.join(l for l in SUP_MODULE_LIST) + +EDK_COMPONENT_TYPE_LIBRARY = 'LIBRARY' +EDK_COMPONENT_TYPE_SECUARITY_CORE = 'SECUARITY_CORE' +EDK_COMPONENT_TYPE_PEI_CORE = 'PEI_CORE' +EDK_COMPONENT_TYPE_COMBINED_PEIM_DRIVER = 'COMBINED_PEIM_DRIVER' +EDK_COMPONENT_TYPE_PIC_PEIM = 'PIC_PEIM' +EDK_COMPONENT_TYPE_RELOCATABLE_PEIM = 'RELOCATABLE_PEIM' +EDK_COMPONENT_TYPE_BS_DRIVER = 'BS_DRIVER' +EDK_COMPONENT_TYPE_RT_DRIVER = 'RT_DRIVER' +EDK_COMPONENT_TYPE_SAL_RT_DRIVER = 'SAL_RT_DRIVER' +EDK_COMPONENT_TYPE_APPLICATION = 'APPLICATION' +EDK_NAME = 'EDK' +EDKII_NAME = 'EDKII' + +BINARY_FILE_TYPE_FW = 'FW' +BINARY_FILE_TYPE_GUID = 'GUID' +BINARY_FILE_TYPE_PREEFORM = 'PREEFORM' +BINARY_FILE_TYPE_UEFI_APP = 'UEFI_APP' +BINARY_FILE_TYPE_UNI_UI = 'UNI_UI' +BINARY_FILE_TYPE_SEC_UI = 'SEC_UI' +BINARY_FILE_TYPE_UNI_VER = 'UNI_VER' +BINARY_FILE_TYPE_SEC_VER = 'SEC_VER' +BINARY_FILE_TYPE_LIB = 'LIB' +BINARY_FILE_TYPE_PE32 = 'PE32' +BINARY_FILE_TYPE_PIC = 'PIC' +BINARY_FILE_TYPE_PEI_DEPEX = 'PEI_DEPEX' +BINARY_FILE_TYPE_DXE_DEPEX = 'DXE_DEPEX' +BINARY_FILE_TYPE_SMM_DEPEX = 'SMM_DEPEX' +BINARY_FILE_TYPE_TE = 'TE' +BINARY_FILE_TYPE_VER = 'VER' +BINARY_FILE_TYPE_UI = 'UI' +BINARY_FILE_TYPE_BIN = 'BIN' +BINARY_FILE_TYPE_FV = 'FV' +BINARY_FILE_TYPE_UI_LIST = [BINARY_FILE_TYPE_UNI_UI, + BINARY_FILE_TYPE_SEC_UI, + BINARY_FILE_TYPE_UI + ] +BINARY_FILE_TYPE_VER_LIST = [BINARY_FILE_TYPE_UNI_VER, + BINARY_FILE_TYPE_SEC_VER, + BINARY_FILE_TYPE_VER + ] + +DEPEX_SECTION_LIST = ['<PEI_DEPEX>', + '<DXE_DEPEX>', + '<SMM_DEPEX>' + ] + +PLATFORM_COMPONENT_TYPE_LIBRARY = 'LIBRARY' +PLATFORM_COMPONENT_TYPE_LIBRARY_CLASS = 'LIBRARY_CLASS' +PLATFORM_COMPONENT_TYPE_MODULE = 'MODULE' + +TAB_LIBRARIES = 'Libraries' + +TAB_SOURCE = 'Source' +TAB_SOURCES = 'Sources' +TAB_SOURCES_COMMON = TAB_SOURCES + TAB_SPLIT + TAB_ARCH_COMMON +TAB_SOURCES_IA32 = TAB_SOURCES + TAB_SPLIT + TAB_ARCH_IA32 +TAB_SOURCES_X64 = TAB_SOURCES + TAB_SPLIT + TAB_ARCH_X64 +TAB_SOURCES_IPF = TAB_SOURCES + TAB_SPLIT + TAB_ARCH_IPF +TAB_SOURCES_ARM = TAB_SOURCES + TAB_SPLIT + TAB_ARCH_ARM +TAB_SOURCES_LOONGARCH64 = TAB_SOURCES + TAB_SPLIT + TAB_ARCH_LOONGARCH64 +TAB_SOURCES_EBC = TAB_SOURCES + TAB_SPLIT + TAB_ARCH_EBC + +TAB_BINARIES = 'Binaries' +TAB_BINARIES_COMMON = TAB_BINARIES + TAB_SPLIT + TAB_ARCH_COMMON +TAB_BINARIES_IA32 = TAB_BINARIES + TAB_SPLIT + TAB_ARCH_IA32 +TAB_BINARIES_X64 = TAB_BINARIES + TAB_SPLIT + TAB_ARCH_X64 +TAB_BINARIES_IPF = TAB_BINARIES + TAB_SPLIT + TAB_ARCH_IPF +TAB_BINARIES_ARM = TAB_BINARIES + TAB_SPLIT + TAB_ARCH_ARM +TAB_BINARIES_LOONGARCH64 = TAB_BINARIES + TAB_SPLIT + TAB_ARCH_LOONGARCH64 +TAB_BINARIES_EBC = TAB_BINARIES + TAB_SPLIT + TAB_ARCH_EBC + +TAB_INCLUDES = 'Includes' +TAB_INCLUDES_COMMON = TAB_INCLUDES + TAB_SPLIT + TAB_ARCH_COMMON +TAB_INCLUDES_IA32 = TAB_INCLUDES + TAB_SPLIT + TAB_ARCH_IA32 +TAB_INCLUDES_X64 = TAB_INCLUDES + TAB_SPLIT + TAB_ARCH_X64 +TAB_INCLUDES_IPF = TAB_INCLUDES + TAB_SPLIT + TAB_ARCH_IPF +TAB_INCLUDES_ARM = TAB_INCLUDES + TAB_SPLIT + TAB_ARCH_ARM +TAB_INCLUDES_LOONGARCH64 = TAB_INCLUDES + TAB_SPLIT + TAB_ARCH_LOONGARCH64 +TAB_INCLUDES_EBC = TAB_INCLUDES + TAB_SPLIT + TAB_ARCH_EBC + +TAB_GUIDS = 'Guids' +TAB_GUIDS_COMMON = TAB_GUIDS + TAB_SPLIT + TAB_ARCH_COMMON +TAB_GUIDS_IA32 = TAB_GUIDS + TAB_SPLIT + TAB_ARCH_IA32 +TAB_GUIDS_X64 = TAB_GUIDS + TAB_SPLIT + TAB_ARCH_X64 +TAB_GUIDS_IPF = TAB_GUIDS + TAB_SPLIT + TAB_ARCH_IPF +TAB_GUIDS_ARM = TAB_GUIDS + TAB_SPLIT + TAB_ARCH_ARM +TAB_GUIDS_LOONGARCH64 = TAB_GUIDS + TAB_SPLIT + TAB_ARCH_LOONGARCH64 +TAB_GUIDS_EBC = TAB_GUIDS + TAB_SPLIT + TAB_ARCH_EBC + +TAB_PROTOCOLS = 'Protocols' +TAB_PROTOCOLS_COMMON = TAB_PROTOCOLS + TAB_SPLIT + TAB_ARCH_COMMON +TAB_PROTOCOLS_IA32 = TAB_PROTOCOLS + TAB_SPLIT + TAB_ARCH_IA32 +TAB_PROTOCOLS_X64 = TAB_PROTOCOLS + TAB_SPLIT + TAB_ARCH_X64 +TAB_PROTOCOLS_IPF = TAB_PROTOCOLS + TAB_SPLIT + TAB_ARCH_IPF +TAB_PROTOCOLS_ARM = TAB_PROTOCOLS + TAB_SPLIT + TAB_ARCH_ARM +TAB_PROTOCOLS_LOONGARCH64 = TAB_PROTOCOLS + TAB_SPLIT + TAB_ARCH_LOONGARCH64 +TAB_PROTOCOLS_EBC = TAB_PROTOCOLS + TAB_SPLIT + TAB_ARCH_EBC + +TAB_PPIS = 'Ppis' +TAB_PPIS_COMMON = TAB_PPIS + TAB_SPLIT + TAB_ARCH_COMMON +TAB_PPIS_IA32 = TAB_PPIS + TAB_SPLIT + TAB_ARCH_IA32 +TAB_PPIS_X64 = TAB_PPIS + TAB_SPLIT + TAB_ARCH_X64 +TAB_PPIS_IPF = TAB_PPIS + TAB_SPLIT + TAB_ARCH_IPF +TAB_PPIS_ARM = TAB_PPIS + TAB_SPLIT + TAB_ARCH_ARM +TAB_PPIS_LOONGARCH64 = TAB_PPIS + TAB_SPLIT + TAB_ARCH_LOONGARCH64 +TAB_PPIS_EBC = TAB_PPIS + TAB_SPLIT + TAB_ARCH_EBC + +TAB_LIBRARY_CLASSES = 'LibraryClasses' +TAB_LIBRARY_CLASSES_COMMON = TAB_LIBRARY_CLASSES + TAB_SPLIT + TAB_ARCH_COMMON +TAB_LIBRARY_CLASSES_IA32 = TAB_LIBRARY_CLASSES + TAB_SPLIT + TAB_ARCH_IA32 +TAB_LIBRARY_CLASSES_X64 = TAB_LIBRARY_CLASSES + TAB_SPLIT + TAB_ARCH_X64 +TAB_LIBRARY_CLASSES_IPF = TAB_LIBRARY_CLASSES + TAB_SPLIT + TAB_ARCH_IPF +TAB_LIBRARY_CLASSES_ARM = TAB_LIBRARY_CLASSES + TAB_SPLIT + TAB_ARCH_ARM +TAB_LIBRARY_CLASSES_LOONGARCH64 = TAB_LIBRARY_CLASSES + TAB_SPLIT + TAB_ARCH_LOONGARCH64 +TAB_LIBRARY_CLASSES_EBC = TAB_LIBRARY_CLASSES + TAB_SPLIT + TAB_ARCH_EBC + +TAB_PACKAGES = 'Packages' +TAB_PACKAGES_COMMON = TAB_PACKAGES + TAB_SPLIT + TAB_ARCH_COMMON +TAB_PACKAGES_IA32 = TAB_PACKAGES + TAB_SPLIT + TAB_ARCH_IA32 +TAB_PACKAGES_X64 = TAB_PACKAGES + TAB_SPLIT + TAB_ARCH_X64 +TAB_PACKAGES_IPF = TAB_PACKAGES + TAB_SPLIT + TAB_ARCH_IPF +TAB_PACKAGES_ARM = TAB_PACKAGES + TAB_SPLIT + TAB_ARCH_ARM +TAB_PACKAGES_LOONGARCH64 = TAB_PACKAGES + TAB_SPLIT + TAB_ARCH_LOONGARCH64 +TAB_PACKAGES_EBC = TAB_PACKAGES + TAB_SPLIT + TAB_ARCH_EBC + +TAB_PCDS = 'Pcds' +TAB_PCDS_FIXED_AT_BUILD = 'FixedAtBuild' +TAB_PCDS_PATCHABLE_IN_MODULE = 'PatchableInModule' +TAB_PCDS_FEATURE_FLAG = 'FeatureFlag' +TAB_PCDS_DYNAMIC_EX = 'DynamicEx' +TAB_PCDS_DYNAMIC_EX_DEFAULT = 'DynamicExDefault' +TAB_PCDS_DYNAMIC_EX_VPD = 'DynamicExVpd' +TAB_PCDS_DYNAMIC_EX_HII = 'DynamicExHii' +TAB_PCDS_DYNAMIC = 'Dynamic' +TAB_PCDS_DYNAMIC_DEFAULT = 'DynamicDefault' +TAB_PCDS_DYNAMIC_VPD = 'DynamicVpd' +TAB_PCDS_DYNAMIC_HII = 'DynamicHii' + +TAB_PTR_TYPE_PCD = 'VOID*' + +PCD_DYNAMIC_TYPE_LIST = [TAB_PCDS_DYNAMIC, TAB_PCDS_DYNAMIC_DEFAULT, \ + TAB_PCDS_DYNAMIC_VPD, TAB_PCDS_DYNAMIC_HII] +PCD_DYNAMIC_EX_TYPE_LIST = [TAB_PCDS_DYNAMIC_EX, TAB_PCDS_DYNAMIC_EX_DEFAULT, \ + TAB_PCDS_DYNAMIC_EX_VPD, TAB_PCDS_DYNAMIC_EX_HII] + +## Dynamic-ex PCD types +# +gDYNAMIC_EX_PCD = [TAB_PCDS_DYNAMIC_EX, TAB_PCDS_DYNAMIC_EX_DEFAULT, \ + TAB_PCDS_DYNAMIC_EX_VPD, TAB_PCDS_DYNAMIC_EX_HII] + +TAB_PCDS_FIXED_AT_BUILD_NULL = TAB_PCDS + TAB_PCDS_FIXED_AT_BUILD +TAB_PCDS_FIXED_AT_BUILD_COMMON = TAB_PCDS + TAB_PCDS_FIXED_AT_BUILD + \ +TAB_SPLIT + TAB_ARCH_COMMON +TAB_PCDS_FIXED_AT_BUILD_IA32 = TAB_PCDS + TAB_PCDS_FIXED_AT_BUILD + \ +TAB_SPLIT + TAB_ARCH_IA32 +TAB_PCDS_FIXED_AT_BUILD_X64 = TAB_PCDS + TAB_PCDS_FIXED_AT_BUILD + \ +TAB_SPLIT + TAB_ARCH_X64 +TAB_PCDS_FIXED_AT_BUILD_IPF = TAB_PCDS + TAB_PCDS_FIXED_AT_BUILD + \ +TAB_SPLIT + TAB_ARCH_IPF +TAB_PCDS_FIXED_AT_BUILD_ARM = TAB_PCDS + TAB_PCDS_FIXED_AT_BUILD + \ +TAB_SPLIT + TAB_ARCH_ARM +TAB_PCDS_FIXED_AT_BUILD_LOONGARCH64 = TAB_PCDS + TAB_PCDS_FIXED_AT_BUILD + \ +TAB_SPLIT + TAB_ARCH_LOONGARCH64 +TAB_PCDS_FIXED_AT_BUILD_EBC = TAB_PCDS + TAB_PCDS_FIXED_AT_BUILD + \ +TAB_SPLIT + TAB_ARCH_EBC + +TAB_PCDS_PATCHABLE_IN_MODULE_NULL = TAB_PCDS + TAB_PCDS_PATCHABLE_IN_MODULE +TAB_PCDS_PATCHABLE_IN_MODULE_COMMON = TAB_PCDS + TAB_PCDS_PATCHABLE_IN_MODULE \ ++ TAB_SPLIT + TAB_ARCH_COMMON +TAB_PCDS_PATCHABLE_IN_MODULE_IA32 = TAB_PCDS + TAB_PCDS_PATCHABLE_IN_MODULE + \ +TAB_SPLIT + TAB_ARCH_IA32 +TAB_PCDS_PATCHABLE_IN_MODULE_X64 = TAB_PCDS + TAB_PCDS_PATCHABLE_IN_MODULE + \ +TAB_SPLIT + TAB_ARCH_X64 +TAB_PCDS_PATCHABLE_IN_MODULE_IPF = TAB_PCDS + TAB_PCDS_PATCHABLE_IN_MODULE + \ +TAB_SPLIT + TAB_ARCH_IPF +TAB_PCDS_PATCHABLE_IN_MODULE_ARM = TAB_PCDS + TAB_PCDS_PATCHABLE_IN_MODULE + \ +TAB_SPLIT + TAB_ARCH_ARM +TAB_PCDS_PATCHABLE_IN_MODULE_LOONGARCH64 = TAB_PCDS + TAB_PCDS_PATCHABLE_IN_MODULE + \ +TAB_SPLIT + TAB_ARCH_LOONGARCH64 +TAB_PCDS_PATCHABLE_IN_MODULE_EBC = TAB_PCDS + TAB_PCDS_PATCHABLE_IN_MODULE + \ +TAB_SPLIT + TAB_ARCH_EBC + +TAB_PCDS_FEATURE_FLAG_NULL = TAB_PCDS + TAB_PCDS_FEATURE_FLAG +TAB_PCDS_FEATURE_FLAG_COMMON = TAB_PCDS + TAB_PCDS_FEATURE_FLAG + TAB_SPLIT \ ++ TAB_ARCH_COMMON +TAB_PCDS_FEATURE_FLAG_IA32 = TAB_PCDS + TAB_PCDS_FEATURE_FLAG + TAB_SPLIT + \ +TAB_ARCH_IA32 +TAB_PCDS_FEATURE_FLAG_X64 = TAB_PCDS + TAB_PCDS_FEATURE_FLAG + TAB_SPLIT + \ +TAB_ARCH_X64 +TAB_PCDS_FEATURE_FLAG_IPF = TAB_PCDS + TAB_PCDS_FEATURE_FLAG + TAB_SPLIT + \ +TAB_ARCH_IPF +TAB_PCDS_FEATURE_FLAG_ARM = TAB_PCDS + TAB_PCDS_FEATURE_FLAG + TAB_SPLIT + \ +TAB_ARCH_ARM +TAB_PCDS_FEATURE_FLAG_LOONGARCH64 = TAB_PCDS + TAB_PCDS_FEATURE_FLAG + TAB_SPLIT + \ +TAB_ARCH_LOONGARCH64 +TAB_PCDS_FEATURE_FLAG_EBC = TAB_PCDS + TAB_PCDS_FEATURE_FLAG + TAB_SPLIT + \ +TAB_ARCH_EBC + +TAB_PCDS_DYNAMIC_EX_NULL = TAB_PCDS + TAB_PCDS_DYNAMIC_EX +TAB_PCDS_DYNAMIC_EX_DEFAULT_NULL = TAB_PCDS + TAB_PCDS_DYNAMIC_EX_DEFAULT +TAB_PCDS_DYNAMIC_EX_HII_NULL = TAB_PCDS + TAB_PCDS_DYNAMIC_EX_HII +TAB_PCDS_DYNAMIC_EX_VPD_NULL = TAB_PCDS + TAB_PCDS_DYNAMIC_EX_VPD +TAB_PCDS_DYNAMIC_EX_COMMON = TAB_PCDS + TAB_PCDS_DYNAMIC_EX + TAB_SPLIT + \ +TAB_ARCH_COMMON +TAB_PCDS_DYNAMIC_EX_IA32 = TAB_PCDS + TAB_PCDS_DYNAMIC_EX + TAB_SPLIT + \ +TAB_ARCH_IA32 +TAB_PCDS_DYNAMIC_EX_X64 = TAB_PCDS + TAB_PCDS_DYNAMIC_EX + TAB_SPLIT + \ +TAB_ARCH_X64 +TAB_PCDS_DYNAMIC_EX_IPF = TAB_PCDS + TAB_PCDS_DYNAMIC_EX + TAB_SPLIT + \ +TAB_ARCH_IPF +TAB_PCDS_DYNAMIC_EX_ARM = TAB_PCDS + TAB_PCDS_DYNAMIC_EX + TAB_SPLIT + \ +TAB_ARCH_ARM +TAB_PCDS_DYNAMIC_EX_LOONGARCH64 = TAB_PCDS + TAB_PCDS_DYNAMIC_EX + TAB_SPLIT + \ +TAB_ARCH_LOONGARCH64 +TAB_PCDS_DYNAMIC_EX_EBC = TAB_PCDS + TAB_PCDS_DYNAMIC_EX + TAB_SPLIT + \ +TAB_ARCH_EBC + +TAB_PCDS_DYNAMIC_NULL = TAB_PCDS + TAB_PCDS_DYNAMIC +TAB_PCDS_DYNAMIC_DEFAULT_NULL = TAB_PCDS + TAB_PCDS_DYNAMIC_DEFAULT +TAB_PCDS_DYNAMIC_HII_NULL = TAB_PCDS + TAB_PCDS_DYNAMIC_HII +TAB_PCDS_DYNAMIC_VPD_NULL = TAB_PCDS + TAB_PCDS_DYNAMIC_VPD +TAB_PCDS_DYNAMIC_COMMON = TAB_PCDS + TAB_PCDS_DYNAMIC + TAB_SPLIT + \ +TAB_ARCH_COMMON +TAB_PCDS_DYNAMIC_IA32 = TAB_PCDS + TAB_PCDS_DYNAMIC + TAB_SPLIT + TAB_ARCH_IA32 +TAB_PCDS_DYNAMIC_X64 = TAB_PCDS + TAB_PCDS_DYNAMIC + TAB_SPLIT + TAB_ARCH_X64 +TAB_PCDS_DYNAMIC_IPF = TAB_PCDS + TAB_PCDS_DYNAMIC + TAB_SPLIT + TAB_ARCH_IPF +TAB_PCDS_DYNAMIC_ARM = TAB_PCDS + TAB_PCDS_DYNAMIC + TAB_SPLIT + TAB_ARCH_ARM +TAB_PCDS_DYNAMIC_LOONGARCH64 = TAB_PCDS + TAB_PCDS_DYNAMIC + TAB_SPLIT + TAB_ARCH_LOONGARCH64 +TAB_PCDS_DYNAMIC_EBC = TAB_PCDS + TAB_PCDS_DYNAMIC + TAB_SPLIT + TAB_ARCH_EBC + +TAB_PCD_DYNAMIC_TYPE_LIST = [TAB_PCDS_DYNAMIC_DEFAULT_NULL, \ + TAB_PCDS_DYNAMIC_VPD_NULL, \ + TAB_PCDS_DYNAMIC_HII_NULL] +TAB_PCD_DYNAMIC_EX_TYPE_LIST = [TAB_PCDS_DYNAMIC_EX_DEFAULT_NULL, \ + TAB_PCDS_DYNAMIC_EX_VPD_NULL, \ + TAB_PCDS_DYNAMIC_EX_HII_NULL] + +TAB_PCDS_PATCHABLE_LOAD_FIX_ADDRESS_PEI_PAGE_SIZE = \ +'PcdLoadFixAddressPeiCodePageNumber' +TAB_PCDS_PATCHABLE_LOAD_FIX_ADDRESS_PEI_PAGE_SIZE_DATA_TYPE = 'UINT32' +TAB_PCDS_PATCHABLE_LOAD_FIX_ADDRESS_DXE_PAGE_SIZE = \ +'PcdLoadFixAddressBootTimeCodePageNumber' +TAB_PCDS_PATCHABLE_LOAD_FIX_ADDRESS_DXE_PAGE_SIZE_DATA_TYPE = 'UINT32' +TAB_PCDS_PATCHABLE_LOAD_FIX_ADDRESS_RUNTIME_PAGE_SIZE = \ +'PcdLoadFixAddressRuntimeCodePageNumber' +TAB_PCDS_PATCHABLE_LOAD_FIX_ADDRESS_RUNTIME_PAGE_SIZE_DATA_TYPE = 'UINT32' +TAB_PCDS_PATCHABLE_LOAD_FIX_ADDRESS_SMM_PAGE_SIZE = \ +'PcdLoadFixAddressSmmCodePageNumber' +TAB_PCDS_PATCHABLE_LOAD_FIX_ADDRESS_SMM_PAGE_SIZE_DATA_TYPE = 'UINT32' +TAB_PCDS_PATCHABLE_LOAD_FIX_ADDRESS_LIST = \ +[TAB_PCDS_PATCHABLE_LOAD_FIX_ADDRESS_PEI_PAGE_SIZE, \ +TAB_PCDS_PATCHABLE_LOAD_FIX_ADDRESS_DXE_PAGE_SIZE, \ +TAB_PCDS_PATCHABLE_LOAD_FIX_ADDRESS_RUNTIME_PAGE_SIZE, \ +TAB_PCDS_PATCHABLE_LOAD_FIX_ADDRESS_SMM_PAGE_SIZE] +PCD_SECTION_LIST = [TAB_PCDS_FIXED_AT_BUILD_NULL.upper(), \ + TAB_PCDS_PATCHABLE_IN_MODULE_NULL.upper(), \ + TAB_PCDS_FEATURE_FLAG_NULL.upper(), \ + TAB_PCDS_DYNAMIC_EX_NULL.upper(), \ + TAB_PCDS_DYNAMIC_NULL.upper()] +INF_PCD_SECTION_LIST = ["FixedPcd".upper(), "FeaturePcd".upper(), \ + "PatchPcd".upper(), "Pcd".upper(), "PcdEx".upper()] + +TAB_DEPEX = 'Depex' +TAB_DEPEX_COMMON = TAB_DEPEX + TAB_SPLIT + TAB_ARCH_COMMON +TAB_DEPEX_IA32 = TAB_DEPEX + TAB_SPLIT + TAB_ARCH_IA32 +TAB_DEPEX_X64 = TAB_DEPEX + TAB_SPLIT + TAB_ARCH_X64 +TAB_DEPEX_IPF = TAB_DEPEX + TAB_SPLIT + TAB_ARCH_IPF +TAB_DEPEX_ARM = TAB_DEPEX + TAB_SPLIT + TAB_ARCH_ARM +TAB_DEPEX_LOONGARCH64 = TAB_DEPEX + TAB_SPLIT + TAB_ARCH_LOONGARCH64 +TAB_DEPEX_EBC = TAB_DEPEX + TAB_SPLIT + TAB_ARCH_EBC + +TAB_SKUIDS = 'SkuIds' + +TAB_LIBRARIES = 'Libraries' +TAB_LIBRARIES_COMMON = TAB_LIBRARIES + TAB_SPLIT + TAB_ARCH_COMMON +TAB_LIBRARIES_IA32 = TAB_LIBRARIES + TAB_SPLIT + TAB_ARCH_IA32 +TAB_LIBRARIES_X64 = TAB_LIBRARIES + TAB_SPLIT + TAB_ARCH_X64 +TAB_LIBRARIES_IPF = TAB_LIBRARIES + TAB_SPLIT + TAB_ARCH_IPF +TAB_LIBRARIES_ARM = TAB_LIBRARIES + TAB_SPLIT + TAB_ARCH_ARM +TAB_LIBRARIES_LOONGARCH64 = TAB_LIBRARIES + TAB_SPLIT + TAB_ARCH_LOONGARCH64 +TAB_LIBRARIES_EBC = TAB_LIBRARIES + TAB_SPLIT + TAB_ARCH_EBC + +TAB_COMPONENTS = 'Components' +TAB_COMPONENTS_COMMON = TAB_COMPONENTS + TAB_SPLIT + TAB_ARCH_COMMON +TAB_COMPONENTS_IA32 = TAB_COMPONENTS + TAB_SPLIT + TAB_ARCH_IA32 +TAB_COMPONENTS_X64 = TAB_COMPONENTS + TAB_SPLIT + TAB_ARCH_X64 +TAB_COMPONENTS_IPF = TAB_COMPONENTS + TAB_SPLIT + TAB_ARCH_IPF +TAB_COMPONENTS_ARM = TAB_COMPONENTS + TAB_SPLIT + TAB_ARCH_ARM +TAB_COMPONENTS_LOONGARCH64 = TAB_COMPONENTS + TAB_SPLIT + TAB_ARCH_LOONGARCH64 +TAB_COMPONENTS_EBC = TAB_COMPONENTS + TAB_SPLIT + TAB_ARCH_EBC + +TAB_BUILD_OPTIONS = 'BuildOptions' + +TAB_DEFINE = 'DEFINE' +TAB_NMAKE = 'Nmake' +TAB_USER_EXTENSIONS = 'UserExtensions' +TAB_INCLUDE = '!include' +TAB_PRIVATE = 'Private' +TAB_INTEL = 'Intel' + +# +# Common Define +# +TAB_COMMON_DEFINES = 'Defines' + +# +# Inf Definitions +# +TAB_INF_DEFINES = TAB_COMMON_DEFINES +TAB_INF_DEFINES_INF_VERSION = 'INF_VERSION' +TAB_INF_DEFINES_BASE_NAME = 'BASE_NAME' +TAB_INF_DEFINES_FILE_GUID = 'FILE_GUID' +TAB_INF_DEFINES_MODULE_TYPE = 'MODULE_TYPE' +TAB_INF_DEFINES_EFI_SPECIFICATION_VERSION = 'EFI_SPECIFICATION_VERSION' +TAB_INF_DEFINES_UEFI_SPECIFICATION_VERSION = 'UEFI_SPECIFICATION_VERSION' +TAB_INF_DEFINES_PI_SPECIFICATION_VERSION = 'PI_SPECIFICATION_VERSION' +TAB_INF_DEFINES_EDK_RELEASE_VERSION = 'EDK_RELEASE_VERSION' +TAB_INF_DEFINES_MODULE_UNI_FILE = 'MODULE_UNI_FILE' +TAB_INF_DEFINES_BINARY_MODULE = 'BINARY_MODULE' +TAB_INF_DEFINES_LIBRARY_CLASS = 'LIBRARY_CLASS' +TAB_INF_DEFINES_COMPONENT_TYPE = 'COMPONENT_TYPE' +TAB_INF_DEFINES_MAKEFILE_NAME = 'MAKEFILE_NAME' +TAB_INF_DEFINES_BUILD_NUMBER = 'BUILD_NUMBER' +TAB_INF_DEFINES_BUILD_TYPE = 'BUILD_TYPE' +TAB_INF_DEFINES_FFS_EXT = 'FFS_EXT' +TAB_INF_DEFINES_FV_EXT = 'FV_EXT' +TAB_INF_DEFINES_SOURCE_FV = 'SOURCE_FV' +TAB_INF_DEFINES_PACKAGE = 'PACKAGE' +TAB_INF_DEFINES_VERSION_NUMBER = 'VERSION_NUMBER' +TAB_INF_DEFINES_VERSION = 'VERSION' +TAB_INF_DEFINES_VERSION_STRING = 'VERSION_STRING' +TAB_INF_DEFINES_PCD_IS_DRIVER = 'PCD_IS_DRIVER' +TAB_INF_DEFINES_TIANO_EDK1_FLASHMAP_H = 'TIANO_EDK1_FLASHMAP_H' +TAB_INF_DEFINES_ENTRY_POINT = 'ENTRY_POINT' +TAB_INF_DEFINES_UNLOAD_IMAGE = 'UNLOAD_IMAGE' +TAB_INF_DEFINES_CONSTRUCTOR = 'CONSTRUCTOR' +TAB_INF_DEFINES_DESTRUCTOR = 'DESTRUCTOR' +TAB_INF_DEFINES_PCI_VENDOR_ID = 'PCI_VENDOR_ID' +TAB_INF_DEFINES_PCI_DEVICE_ID = 'PCI_DEVICE_ID' +TAB_INF_DEFINES_PCI_CLASS_CODE = 'PCI_CLASS_CODE' +TAB_INF_DEFINES_PCI_REVISION = 'PCI_REVISION' +TAB_INF_DEFINES_PCI_COMPRESS = 'PCI_COMPRESS' +TAB_INF_DEFINES_DEFINE = 'DEFINE' +TAB_INF_DEFINES_SPEC = 'SPEC' +TAB_INF_DEFINES_UEFI_HII_RESOURCE_SECTION = 'UEFI_HII_RESOURCE_SECTION' +TAB_INF_DEFINES_CUSTOM_MAKEFILE = 'CUSTOM_MAKEFILE' +TAB_INF_DEFINES_MACRO = '__MACROS__' +TAB_INF_DEFINES_SHADOW = 'SHADOW' +TAB_INF_DEFINES_DPX_SOURCE = 'DPX_SOURCE' +TAB_INF_FIXED_PCD = 'FixedPcd' +TAB_INF_FEATURE_PCD = 'FeaturePcd' +TAB_INF_PATCH_PCD = 'PatchPcd' +TAB_INF_PCD = 'Pcd' +TAB_INF_PCD_EX = 'PcdEx' +TAB_INF_GUIDTYPE_VAR = 'Variable' +TAB_INF_ABSTRACT = 'STR_MODULE_ABSTRACT' +TAB_INF_DESCRIPTION = 'STR_MODULE_DESCRIPTION' +TAB_INF_LICENSE = 'STR_MODULE_LICENSE' +TAB_INF_BINARY_ABSTRACT = 'STR_MODULE_BINARY_ABSTRACT' +TAB_INF_BINARY_DESCRIPTION = 'STR_MODULE_BINARY_DESCRIPTION' +TAB_INF_BINARY_LICENSE = 'STR_MODULE_BINARY_LICENSE' +# +# Dec Definitions +# +TAB_DEC_DEFINES = TAB_COMMON_DEFINES +TAB_DEC_DEFINES_DEC_SPECIFICATION = 'DEC_SPECIFICATION' +TAB_DEC_DEFINES_PACKAGE_NAME = 'PACKAGE_NAME' +TAB_DEC_DEFINES_PACKAGE_GUID = 'PACKAGE_GUID' +TAB_DEC_DEFINES_PACKAGE_VERSION = 'PACKAGE_VERSION' +TAB_DEC_DEFINES_PKG_UNI_FILE = 'PACKAGE_UNI_FILE' +TAB_DEC_PACKAGE_ABSTRACT = 'STR_PACKAGE_ABSTRACT' +TAB_DEC_PACKAGE_DESCRIPTION = 'STR_PACKAGE_DESCRIPTION' +TAB_DEC_PACKAGE_LICENSE = 'STR_PACKAGE_LICENSE' +TAB_DEC_BINARY_ABSTRACT = 'STR_PACKAGE_BINARY_ABSTRACT' +TAB_DEC_BINARY_DESCRIPTION = 'STR_PACKAGE_BINARY_DESCRIPTION' +TAB_DEC_BINARY_LICENSE = 'STR_PACKAGE_ASBUILT_LICENSE' +# +# Dsc Definitions +# +TAB_DSC_DEFINES = TAB_COMMON_DEFINES +TAB_DSC_DEFINES_PLATFORM_NAME = 'PLATFORM_NAME' +TAB_DSC_DEFINES_PLATFORM_GUID = 'PLATFORM_GUID' +TAB_DSC_DEFINES_PLATFORM_VERSION = 'PLATFORM_VERSION' +TAB_DSC_DEFINES_DSC_SPECIFICATION = 'DSC_SPECIFICATION' +TAB_DSC_DEFINES_OUTPUT_DIRECTORY = 'OUTPUT_DIRECTORY' +TAB_DSC_DEFINES_SUPPORTED_ARCHITECTURES = 'SUPPORTED_ARCHITECTURES' +TAB_DSC_DEFINES_BUILD_TARGETS = 'BUILD_TARGETS' +TAB_DSC_DEFINES_SKUID_IDENTIFIER = 'SKUID_IDENTIFIER' +TAB_DSC_DEFINES_FLASH_DEFINITION = 'FLASH_DEFINITION' +TAB_DSC_DEFINES_BUILD_NUMBER = 'BUILD_NUMBER' +TAB_DSC_DEFINES_MAKEFILE_NAME = 'MAKEFILE_NAME' +TAB_DSC_DEFINES_BS_BASE_ADDRESS = 'BsBaseAddress' +TAB_DSC_DEFINES_RT_BASE_ADDRESS = 'RtBaseAddress' +TAB_DSC_DEFINES_DEFINE = 'DEFINE' +TAB_FIX_LOAD_TOP_MEMORY_ADDRESS = 'FIX_LOAD_TOP_MEMORY_ADDRESS' + +# +# TargetTxt Definitions +# +TAB_TAT_DEFINES_ACTIVE_PLATFORM = 'ACTIVE_PLATFORM' +TAB_TAT_DEFINES_ACTIVE_MODULE = 'ACTIVE_MODULE' +TAB_TAT_DEFINES_TOOL_CHAIN_CONF = 'TOOL_CHAIN_CONF' +TAB_TAT_DEFINES_MULTIPLE_THREAD = 'MULTIPLE_THREAD' +TAB_TAT_DEFINES_MAX_CONCURRENT_THREAD_NUMBER = 'MAX_CONCURRENT_THREAD_NUMBER' +TAB_TAT_DEFINES_TARGET = 'TARGET' +TAB_TAT_DEFINES_TOOL_CHAIN_TAG = 'TOOL_CHAIN_TAG' +TAB_TAT_DEFINES_TARGET_ARCH = 'TARGET_ARCH' +TAB_TAT_DEFINES_BUILD_RULE_CONF = "BUILD_RULE_CONF" + +# +# ToolDef Definitions +# +TAB_TOD_DEFINES_TARGET = 'TARGET' +TAB_TOD_DEFINES_TOOL_CHAIN_TAG = 'TOOL_CHAIN_TAG' +TAB_TOD_DEFINES_TARGET_ARCH = 'TARGET_ARCH' +TAB_TOD_DEFINES_COMMAND_TYPE = 'COMMAND_TYPE' +TAB_TOD_DEFINES_FAMILY = 'FAMILY' +TAB_TOD_DEFINES_BUILDRULEFAMILY = 'BUILDRULEFAMILY' + +# +# Conditional Statements +# +TAB_IF = '!if' +TAB_END_IF = '!endif' +TAB_ELSE_IF = '!elseif' +TAB_ELSE = '!else' +TAB_IF_DEF = '!ifdef' +TAB_IF_N_DEF = '!ifndef' +TAB_IF_EXIST = '!if exist' + +# +# Unknown section +# +TAB_UNKNOWN = 'UNKNOWN' + +# +# Header section (virtual section for abstract, description, copyright, +# license) +# +TAB_HEADER = 'Header' +TAB_HEADER_ABSTRACT = 'Abstract' +TAB_HEADER_DESCRIPTION = 'Description' +TAB_HEADER_COPYRIGHT = 'Copyright' +TAB_HEADER_LICENSE = 'License' +TAB_BINARY_HEADER_IDENTIFIER = 'BinaryHeader' +TAB_BINARY_HEADER_USERID = 'TianoCore' + +# +# Build database path +# +DATABASE_PATH = ":memory:" +# +# used by ECC +# +MODIFIER_LIST = ['IN', 'OUT', 'OPTIONAL', 'UNALIGNED', 'EFI_RUNTIMESERVICE', \ + 'EFI_BOOTSERVICE', 'EFIAPI'] +# +# Dependency Expression +# +DEPEX_SUPPORTED_OPCODE = ["BEFORE", "AFTER", "PUSH", "AND", "OR", "NOT", \ + "END", "SOR", "TRUE", "FALSE", '(', ')'] + +TAB_STATIC_LIBRARY = "STATIC-LIBRARY-FILE" +TAB_DYNAMIC_LIBRARY = "DYNAMIC-LIBRARY-FILE" +TAB_FRAMEWORK_IMAGE = "EFI-IMAGE-FILE" +TAB_C_CODE_FILE = "C-CODE-FILE" +TAB_C_HEADER_FILE = "C-HEADER-FILE" +TAB_UNICODE_FILE = "UNICODE-TEXT-FILE" +TAB_DEPENDENCY_EXPRESSION_FILE = "DEPENDENCY-EXPRESSION-FILE" +TAB_UNKNOWN_FILE = "UNKNOWN-TYPE-FILE" +TAB_DEFAULT_BINARY_FILE = "_BINARY_FILE_" +# +# used to indicate the state of processing header comment section of dec, +# inf files +# +HEADER_COMMENT_NOT_STARTED = -1 +HEADER_COMMENT_STARTED = 0 +HEADER_COMMENT_FILE = 1 +HEADER_COMMENT_ABSTRACT = 2 +HEADER_COMMENT_DESCRIPTION = 3 +HEADER_COMMENT_COPYRIGHT = 4 +HEADER_COMMENT_LICENSE = 5 +HEADER_COMMENT_END = 6 + +# +# Static values for data models +# +MODEL_UNKNOWN = 0 + +MODEL_FILE_C = 1001 +MODEL_FILE_H = 1002 +MODEL_FILE_ASM = 1003 +MODEL_FILE_INF = 1011 +MODEL_FILE_DEC = 1012 +MODEL_FILE_DSC = 1013 +MODEL_FILE_FDF = 1014 +MODEL_FILE_INC = 1015 +MODEL_FILE_CIF = 1016 + +MODEL_IDENTIFIER_FILE_HEADER = 2001 +MODEL_IDENTIFIER_FUNCTION_HEADER = 2002 +MODEL_IDENTIFIER_COMMENT = 2003 +MODEL_IDENTIFIER_PARAMETER = 2004 +MODEL_IDENTIFIER_STRUCTURE = 2005 +MODEL_IDENTIFIER_VARIABLE = 2006 +MODEL_IDENTIFIER_INCLUDE = 2007 +MODEL_IDENTIFIER_PREDICATE_EXPRESSION = 2008 +MODEL_IDENTIFIER_ENUMERATE = 2009 +MODEL_IDENTIFIER_PCD = 2010 +MODEL_IDENTIFIER_UNION = 2011 +MODEL_IDENTIFIER_MACRO_IFDEF = 2012 +MODEL_IDENTIFIER_MACRO_IFNDEF = 2013 +MODEL_IDENTIFIER_MACRO_DEFINE = 2014 +MODEL_IDENTIFIER_MACRO_ENDIF = 2015 +MODEL_IDENTIFIER_MACRO_PROGMA = 2016 +MODEL_IDENTIFIER_FUNCTION_CALLING = 2018 +MODEL_IDENTIFIER_TYPEDEF = 2017 +MODEL_IDENTIFIER_FUNCTION_DECLARATION = 2019 +MODEL_IDENTIFIER_ASSIGNMENT_EXPRESSION = 2020 + +MODEL_EFI_PROTOCOL = 3001 +MODEL_EFI_PPI = 3002 +MODEL_EFI_GUID = 3003 +MODEL_EFI_LIBRARY_CLASS = 3004 +MODEL_EFI_LIBRARY_INSTANCE = 3005 +MODEL_EFI_PCD = 3006 +MODEL_EFI_SOURCE_FILE = 3007 +MODEL_EFI_BINARY_FILE = 3008 +MODEL_EFI_SKU_ID = 3009 +MODEL_EFI_INCLUDE = 3010 +MODEL_EFI_DEPEX = 3011 + +MODEL_PCD = 4000 +MODEL_PCD_FIXED_AT_BUILD = 4001 +MODEL_PCD_PATCHABLE_IN_MODULE = 4002 +MODEL_PCD_FEATURE_FLAG = 4003 +MODEL_PCD_DYNAMIC_EX = 4004 +MODEL_PCD_DYNAMIC_EX_DEFAULT = 4005 +MODEL_PCD_DYNAMIC_EX_VPD = 4006 +MODEL_PCD_DYNAMIC_EX_HII = 4007 +MODEL_PCD_DYNAMIC = 4008 +MODEL_PCD_DYNAMIC_DEFAULT = 4009 +MODEL_PCD_DYNAMIC_VPD = 4010 +MODEL_PCD_DYNAMIC_HII = 4011 + +MODEL_META_DATA_FILE_HEADER = 5000 +MODEL_META_DATA_HEADER = 5001 +MODEL_META_DATA_INCLUDE = 5002 +MODEL_META_DATA_DEFINE = 5003 +MODEL_META_DATA_CONDITIONAL_STATEMENT_IF = 5004 +MODEL_META_DATA_CONDITIONAL_STATEMENT_ELSE = 5005 +MODEL_META_DATA_CONDITIONAL_STATEMENT_IFDEF = 5006 +MODEL_META_DATA_CONDITIONAL_STATEMENT_IFNDEF = 5007 +MODEL_META_DATA_BUILD_OPTION = 5008 +MODEL_META_DATA_COMPONENT = 5009 +MODEL_META_DATA_USER_EXTENSION = 5010 +MODEL_META_DATA_PACKAGE = 5011 +MODEL_META_DATA_NMAKE = 5012 +MODEL_META_DATA_CONDITIONAL_STATEMENT_ELSEIF = 50013 +MODEL_META_DATA_CONDITIONAL_STATEMENT_ENDIF = 5014 + +TOOL_FAMILY_LIST = ["MSFT", + "INTEL", + "GCC", + ] + +TYPE_HOB_SECTION = 'HOB' +TYPE_EVENT_SECTION = 'EVENT' +TYPE_BOOTMODE_SECTION = 'BOOTMODE' + +PCD_ERR_CODE_MAX_SIZE = 4294967295 diff --git a/BaseTools/Source/Python/UPT/Library/ExpressionValidate.py b/BaseTools/Source/Python/UPT/Library/ExpressionValidate.py index 7718ca12e5..ae5f835bae 100644 --- a/BaseTools/Source/Python/UPT/Library/ExpressionValidate.py +++ b/BaseTools/Source/Python/UPT/Library/ExpressionValidate.py @@ -1,567 +1,567 @@ -## @file
-# This file is used to check PCD logical expression
-#
-# Copyright (c) 2011 - 2018, Intel Corporation. All rights reserved.<BR>
-#
-# SPDX-License-Identifier: BSD-2-Clause-Patent
-
-'''
-ExpressionValidate
-'''
-from __future__ import print_function
-
-##
-# Import Modules
-#
-import re
-from Logger import StringTable as ST
-
-## IsValidBareCString
-#
-# Check if String is comprised by whitespace(0x20), !(0x21), 0x23 - 0x7E
-# or '\n', '\t', '\f', '\r', '\b', '\0', '\\'
-#
-# @param String: string to be checked
-#
-def IsValidBareCString(String):
- EscapeList = ['n', 't', 'f', 'r', 'b', '0', '\\', '"']
- PreChar = ''
- LastChar = ''
- for Char in String:
- LastChar = Char
- if PreChar == '\\':
- if Char not in EscapeList:
- return False
- if Char == '\\':
- PreChar = ''
- continue
- else:
- IntChar = ord(Char)
- if IntChar != 0x20 and IntChar != 0x09 and IntChar != 0x21 \
- and (IntChar < 0x23 or IntChar > 0x7e):
- return False
- PreChar = Char
-
- # Last char cannot be \ if PreChar is not \
- if LastChar == '\\' and PreChar == LastChar:
- return False
- return True
-
-def _ValidateToken(Token):
- Token = Token.strip()
- Index = Token.find("\"")
- if Index != -1:
- return IsValidBareCString(Token[Index+1:-1])
- return True
-
-## _ExprError
-#
-# @param Exception: Exception
-#
-class _ExprError(Exception):
- def __init__(self, Error = ''):
- Exception.__init__(self)
- self.Error = Error
-
-## _ExprBase
-#
-class _ExprBase:
- HEX_PATTERN = '[\t\s]*0[xX][a-fA-F0-9]+'
- INT_PATTERN = '[\t\s]*[0-9]+'
- MACRO_PATTERN = '[\t\s]*\$\(([A-Z][_A-Z0-9]*)\)'
- PCD_PATTERN = \
- '[\t\s]*[_a-zA-Z][a-zA-Z0-9_]*[\t\s]*\.[\t\s]*[_a-zA-Z][a-zA-Z0-9_]*'
- QUOTED_PATTERN = '[\t\s]*L?"[^"]*"'
- BOOL_PATTERN = '[\t\s]*(true|True|TRUE|false|False|FALSE)'
- def __init__(self, Token):
- self.Token = Token
- self.Index = 0
- self.Len = len(Token)
-
- ## SkipWhitespace
- #
- def SkipWhitespace(self):
- for Char in self.Token[self.Index:]:
- if Char not in ' \t':
- break
- self.Index += 1
-
- ## IsCurrentOp
- #
- # @param OpList: option list
- #
- def IsCurrentOp(self, OpList):
- self.SkipWhitespace()
- LetterOp = ["EQ", "NE", "GE", "LE", "GT", "LT", "NOT", "and", "AND",
- "or", "OR", "XOR"]
- OpMap = {
- '|' : '|',
- '&' : '&',
- '!' : '=',
- '>' : '=',
- '<' : '='
- }
-
- for Operator in OpList:
- if not self.Token[self.Index:].startswith(Operator):
- continue
-
- self.Index += len(Operator)
- Char = self.Token[self.Index : self.Index + 1]
-
- if (Operator in LetterOp and (Char == '_' or Char.isalnum())) \
- or (Operator in OpMap and OpMap[Operator] == Char):
- self.Index -= len(Operator)
- break
-
- return True
-
- return False
-
-## _LogicalExpressionParser
-#
-# @param _ExprBase: _ExprBase object
-#
-class _LogicalExpressionParser(_ExprBase):
- #
- # STRINGITEM can only be logical field according to spec
- #
- STRINGITEM = -1
-
- #
- # Evaluate to True or False
- #
- LOGICAL = 0
- REALLOGICAL = 2
-
- #
- # Just arithmetic expression
- #
- ARITH = 1
-
- def __init__(self, Token):
- _ExprBase.__init__(self, Token)
- self.Parens = 0
-
- def _CheckToken(self, MatchList):
- for Match in MatchList:
- if Match and Match.start() == 0:
- if not _ValidateToken(
- self.Token[self.Index:self.Index+Match.end()]
- ):
- return False
-
- self.Index += Match.end()
- if self.Token[self.Index - 1] == '"':
- return True
- if self.Token[self.Index:self.Index+1] == '_' or \
- self.Token[self.Index:self.Index+1].isalnum():
- self.Index -= Match.end()
- return False
-
- Token = self.Token[self.Index - Match.end():self.Index]
- if Token.strip() in ["EQ", "NE", "GE", "LE", "GT", "LT",
- "NOT", "and", "AND", "or", "OR", "XOR"]:
- self.Index -= Match.end()
- return False
-
- return True
-
- return False
-
- def IsAtomicNumVal(self):
- #
- # Hex number
- #
- Match1 = re.compile(self.HEX_PATTERN).match(self.Token[self.Index:])
-
- #
- # Number
- #
- Match2 = re.compile(self.INT_PATTERN).match(self.Token[self.Index:])
-
- #
- # Macro
- #
- Match3 = re.compile(self.MACRO_PATTERN).match(self.Token[self.Index:])
-
- #
- # PcdName
- #
- Match4 = re.compile(self.PCD_PATTERN).match(self.Token[self.Index:])
-
- return self._CheckToken([Match1, Match2, Match3, Match4])
-
-
- def IsAtomicItem(self):
- #
- # Macro
- #
- Match1 = re.compile(self.MACRO_PATTERN).match(self.Token[self.Index:])
-
- #
- # PcdName
- #
- Match2 = re.compile(self.PCD_PATTERN).match(self.Token[self.Index:])
-
- #
- # Quoted string
- #
- Match3 = re.compile(self.QUOTED_PATTERN).\
- match(self.Token[self.Index:].replace('\\\\', '//').\
- replace('\\\"', '\\\''))
-
- return self._CheckToken([Match1, Match2, Match3])
-
- ## A || B
- #
- def LogicalExpression(self):
- Ret = self.SpecNot()
- while self.IsCurrentOp(['||', 'OR', 'or', '&&', 'AND', 'and', 'XOR', 'xor', '^']):
- if self.Token[self.Index-1] == '|' and self.Parens <= 0:
- raise _ExprError(ST.ERR_EXPR_OR % self.Token)
- if Ret not in [self.ARITH, self.LOGICAL, self.REALLOGICAL, self.STRINGITEM]:
- raise _ExprError(ST.ERR_EXPR_LOGICAL % self.Token)
- Ret = self.SpecNot()
- if Ret not in [self.ARITH, self.LOGICAL, self.REALLOGICAL, self.STRINGITEM]:
- raise _ExprError(ST.ERR_EXPR_LOGICAL % self.Token)
- Ret = self.REALLOGICAL
- return Ret
-
- def SpecNot(self):
- if self.IsCurrentOp(["NOT", "!", "not"]):
- return self.SpecNot()
- return self.Rel()
-
- ## A < B, A > B, A <= B, A >= B
- #
- def Rel(self):
- Ret = self.Expr()
- if self.IsCurrentOp(["<=", ">=", ">", "<", "GT", "LT", "GE", "LE",
- "==", "EQ", "!=", "NE"]):
- if Ret == self.STRINGITEM:
- raise _ExprError(ST.ERR_EXPR_LOGICAL % self.Token)
- Ret = self.Expr()
- if Ret == self.REALLOGICAL:
- raise _ExprError(ST.ERR_EXPR_LOGICAL % self.Token)
- Ret = self.REALLOGICAL
- return Ret
-
- ## A + B, A - B
- #
- def Expr(self):
- Ret = self.Factor()
- while self.IsCurrentOp(["+", "-", "&", "|", "^", "XOR", "xor"]):
- if self.Token[self.Index-1] == '|' and self.Parens <= 0:
- raise _ExprError(ST.ERR_EXPR_OR)
- if Ret == self.STRINGITEM or Ret == self.REALLOGICAL:
- raise _ExprError(ST.ERR_EXPR_LOGICAL % self.Token)
- Ret = self.Factor()
- if Ret == self.STRINGITEM or Ret == self.REALLOGICAL:
- raise _ExprError(ST.ERR_EXPR_LOGICAL % self.Token)
- Ret = self.ARITH
- return Ret
-
- ## Factor
- #
- def Factor(self):
- if self.IsCurrentOp(["("]):
- self.Parens += 1
- Ret = self.LogicalExpression()
- if not self.IsCurrentOp([")"]):
- raise _ExprError(ST.ERR_EXPR_RIGHT_PAREN % \
- (self.Token, self.Token[self.Index:]))
- self.Parens -= 1
- return Ret
-
- if self.IsAtomicItem():
- if self.Token[self.Index - 1] == '"':
- return self.STRINGITEM
- return self.LOGICAL
- elif self.IsAtomicNumVal():
- return self.ARITH
- else:
- raise _ExprError(ST.ERR_EXPR_FACTOR % \
- (self.Token[self.Index:], self.Token))
-
- ## IsValidLogicalExpression
- #
- def IsValidLogicalExpression(self):
- if self.Len == 0:
- return False, ST.ERR_EXPRESS_EMPTY
- try:
- if self.LogicalExpression() not in [self.ARITH, self.LOGICAL, self.REALLOGICAL, self.STRINGITEM]:
- return False, ST.ERR_EXPR_LOGICAL % self.Token
- except _ExprError as XExcept:
- return False, XExcept.Error
- self.SkipWhitespace()
- if self.Index != self.Len:
- return False, (ST.ERR_EXPR_BOOLEAN % \
- (self.Token[self.Index:], self.Token))
- return True, ''
-
-## _ValidRangeExpressionParser
-#
-class _ValidRangeExpressionParser(_ExprBase):
- INT_RANGE_PATTERN = '[\t\s]*[0-9]+[\t\s]*-[\t\s]*[0-9]+'
- HEX_RANGE_PATTERN = \
- '[\t\s]*0[xX][a-fA-F0-9]+[\t\s]*-[\t\s]*0[xX][a-fA-F0-9]+'
- def __init__(self, Token):
- _ExprBase.__init__(self, Token)
- self.Parens = 0
- self.HEX = 1
- self.INT = 2
- self.IsParenHappen = False
- self.IsLogicalOpHappen = False
-
- ## IsValidRangeExpression
- #
- def IsValidRangeExpression(self):
- if self.Len == 0:
- return False, ST.ERR_EXPR_RANGE_EMPTY
- try:
- if self.RangeExpression() not in [self.HEX, self.INT]:
- return False, ST.ERR_EXPR_RANGE % self.Token
- except _ExprError as XExcept:
- return False, XExcept.Error
-
- self.SkipWhitespace()
- if self.Index != self.Len:
- return False, (ST.ERR_EXPR_RANGE % self.Token)
- return True, ''
-
- ## RangeExpression
- #
- def RangeExpression(self):
- Ret = self.Unary()
- while self.IsCurrentOp(['OR', 'AND', 'and', 'or']):
- self.IsLogicalOpHappen = True
- if not self.IsParenHappen:
- raise _ExprError(ST.ERR_PAREN_NOT_USED % self.Token)
- self.IsParenHappen = False
- Ret = self.Unary()
-
- if self.IsCurrentOp(['XOR']):
- Ret = self.Unary()
-
- return Ret
-
- ## Unary
- #
- def Unary(self):
- if self.IsCurrentOp(["NOT"]):
- return self.Unary()
-
- return self.ValidRange()
-
- ## ValidRange
- #
- def ValidRange(self):
- Ret = -1
- if self.IsCurrentOp(["("]):
- self.IsLogicalOpHappen = False
- self.IsParenHappen = True
- self.Parens += 1
- if self.Parens > 1:
- raise _ExprError(ST.ERR_EXPR_RANGE_DOUBLE_PAREN_NESTED % self.Token)
- Ret = self.RangeExpression()
- if not self.IsCurrentOp([")"]):
- raise _ExprError(ST.ERR_EXPR_RIGHT_PAREN % self.Token)
- self.Parens -= 1
- return Ret
-
- if self.IsLogicalOpHappen:
- raise _ExprError(ST.ERR_PAREN_NOT_USED % self.Token)
-
- if self.IsCurrentOp(["LT", "GT", "LE", "GE", "EQ", "XOR"]):
- IntMatch = \
- re.compile(self.INT_PATTERN).match(self.Token[self.Index:])
- HexMatch = \
- re.compile(self.HEX_PATTERN).match(self.Token[self.Index:])
- if HexMatch and HexMatch.start() == 0:
- self.Index += HexMatch.end()
- Ret = self.HEX
- elif IntMatch and IntMatch.start() == 0:
- self.Index += IntMatch.end()
- Ret = self.INT
- else:
- raise _ExprError(ST.ERR_EXPR_RANGE_FACTOR % (self.Token[self.Index:], self.Token))
- else:
- IntRangeMatch = re.compile(
- self.INT_RANGE_PATTERN).match(self.Token[self.Index:]
- )
- HexRangeMatch = re.compile(
- self.HEX_RANGE_PATTERN).match(self.Token[self.Index:]
- )
- if HexRangeMatch and HexRangeMatch.start() == 0:
- self.Index += HexRangeMatch.end()
- Ret = self.HEX
- elif IntRangeMatch and IntRangeMatch.start() == 0:
- self.Index += IntRangeMatch.end()
- Ret = self.INT
- else:
- raise _ExprError(ST.ERR_EXPR_RANGE % self.Token)
-
- return Ret
-
-## _ValidListExpressionParser
-#
-class _ValidListExpressionParser(_ExprBase):
- VALID_LIST_PATTERN = '(0[xX][0-9a-fA-F]+|[0-9]+)([\t\s]*,[\t\s]*(0[xX][0-9a-fA-F]+|[0-9]+))*'
- def __init__(self, Token):
- _ExprBase.__init__(self, Token)
- self.NUM = 1
-
- def IsValidListExpression(self):
- if self.Len == 0:
- return False, ST.ERR_EXPR_LIST_EMPTY
- try:
- if self.ListExpression() not in [self.NUM]:
- return False, ST.ERR_EXPR_LIST % self.Token
- except _ExprError as XExcept:
- return False, XExcept.Error
-
- self.SkipWhitespace()
- if self.Index != self.Len:
- return False, (ST.ERR_EXPR_LIST % self.Token)
-
- return True, ''
-
- def ListExpression(self):
- Ret = -1
- self.SkipWhitespace()
- ListMatch = re.compile(self.VALID_LIST_PATTERN).match(self.Token[self.Index:])
- if ListMatch and ListMatch.start() == 0:
- self.Index += ListMatch.end()
- Ret = self.NUM
- else:
- raise _ExprError(ST.ERR_EXPR_LIST % self.Token)
-
- return Ret
-
-## _StringTestParser
-#
-class _StringTestParser(_ExprBase):
- def __init__(self, Token):
- _ExprBase.__init__(self, Token)
-
- ## IsValidStringTest
- #
- def IsValidStringTest(self):
- if self.Len == 0:
- return False, ST.ERR_EXPR_EMPTY
- try:
- self.StringTest()
- except _ExprError as XExcept:
- return False, XExcept.Error
- return True, ''
-
- ## StringItem
- #
- def StringItem(self):
- Match1 = re.compile(self.QUOTED_PATTERN)\
- .match(self.Token[self.Index:].replace('\\\\', '//')\
- .replace('\\\"', '\\\''))
- Match2 = re.compile(self.MACRO_PATTERN).match(self.Token[self.Index:])
- Match3 = re.compile(self.PCD_PATTERN).match(self.Token[self.Index:])
- MatchList = [Match1, Match2, Match3]
- for Match in MatchList:
- if Match and Match.start() == 0:
- if not _ValidateToken(
- self.Token[self.Index:self.Index+Match.end()]
- ):
- raise _ExprError(ST.ERR_EXPR_STRING_ITEM % \
- (self.Token, self.Token[self.Index:]))
- self.Index += Match.end()
- Token = self.Token[self.Index - Match.end():self.Index]
- if Token.strip() in ["EQ", "NE"]:
- raise _ExprError(ST.ERR_EXPR_STRING_ITEM % \
- (self.Token, self.Token[self.Index:]))
- return
- else:
- raise _ExprError(ST.ERR_EXPR_STRING_ITEM % \
- (self.Token, self.Token[self.Index:]))
-
- ## StringTest
- #
- def StringTest(self):
- self.StringItem()
- if not self.IsCurrentOp(["==", "EQ", "!=", "NE"]):
- raise _ExprError(ST.ERR_EXPR_EQUALITY % \
- (self.Token[self.Index:], self.Token))
- self.StringItem()
- if self.Index != self.Len:
- raise _ExprError(ST.ERR_EXPR_BOOLEAN % \
- (self.Token[self.Index:], self.Token))
-
-##
-# Check syntax of string test
-#
-# @param Token: string test token
-#
-def IsValidStringTest(Token, Flag=False):
- #
- # Not do the check right now, keep the implementation for future enhancement.
- #
- if not Flag:
- return True, ""
- return _StringTestParser(Token).IsValidStringTest()
-
-
-##
-# Check syntax of logical expression
-#
-# @param Token: expression token
-#
-def IsValidLogicalExpr(Token, Flag=False):
- #
- # Not do the check right now, keep the implementation for future enhancement.
- #
- if not Flag:
- return True, ""
- return _LogicalExpressionParser(Token).IsValidLogicalExpression()
-
-##
-# Check syntax of range expression
-#
-# @param Token: range expression token
-#
-def IsValidRangeExpr(Token):
- return _ValidRangeExpressionParser(Token).IsValidRangeExpression()
-
-##
-# Check syntax of value list expression token
-#
-# @param Token: value list expression token
-#
-def IsValidListExpr(Token):
- return _ValidListExpressionParser(Token).IsValidListExpression()
-
-##
-# Check whether the feature flag expression is valid or not
-#
-# @param Token: feature flag expression
-#
-def IsValidFeatureFlagExp(Token, Flag=False):
- #
- # Not do the check right now, keep the implementation for future enhancement.
- #
- if not Flag:
- return True, "", Token
- else:
- if Token in ['TRUE', 'FALSE', 'true', 'false', 'True', 'False',
- '0x1', '0x01', '0x0', '0x00']:
- return True, ""
- Valid, Cause = IsValidStringTest(Token, Flag)
- if not Valid:
- Valid, Cause = IsValidLogicalExpr(Token, Flag)
- if not Valid:
- return False, Cause
- return True, ""
-
-if __name__ == '__main__':
-# print IsValidRangeExpr('LT 9')
- print(_LogicalExpressionParser('gCrownBayTokenSpaceGuid.PcdPciDevice1BridgeAddressLE0').IsValidLogicalExpression())
-
-
-
+## @file +# This file is used to check PCD logical expression +# +# Copyright (c) 2011 - 2018, Intel Corporation. All rights reserved.<BR> +# +# SPDX-License-Identifier: BSD-2-Clause-Patent + +''' +ExpressionValidate +''' +from __future__ import print_function + +## +# Import Modules +# +import re +from Logger import StringTable as ST + +## IsValidBareCString +# +# Check if String is comprised by whitespace(0x20), !(0x21), 0x23 - 0x7E +# or '\n', '\t', '\f', '\r', '\b', '\0', '\\' +# +# @param String: string to be checked +# +def IsValidBareCString(String): + EscapeList = ['n', 't', 'f', 'r', 'b', '0', '\\', '"'] + PreChar = '' + LastChar = '' + for Char in String: + LastChar = Char + if PreChar == '\\': + if Char not in EscapeList: + return False + if Char == '\\': + PreChar = '' + continue + else: + IntChar = ord(Char) + if IntChar != 0x20 and IntChar != 0x09 and IntChar != 0x21 \ + and (IntChar < 0x23 or IntChar > 0x7e): + return False + PreChar = Char + + # Last char cannot be \ if PreChar is not \ + if LastChar == '\\' and PreChar == LastChar: + return False + return True + +def _ValidateToken(Token): + Token = Token.strip() + Index = Token.find("\"") + if Index != -1: + return IsValidBareCString(Token[Index+1:-1]) + return True + +## _ExprError +# +# @param Exception: Exception +# +class _ExprError(Exception): + def __init__(self, Error = ''): + Exception.__init__(self) + self.Error = Error + +## _ExprBase +# +class _ExprBase: + HEX_PATTERN = '[\t\s]*0[xX][a-fA-F0-9]+' + INT_PATTERN = '[\t\s]*[0-9]+' + MACRO_PATTERN = '[\t\s]*\$\(([A-Z][_A-Z0-9]*)\)' + PCD_PATTERN = \ + '[\t\s]*[_a-zA-Z][a-zA-Z0-9_]*[\t\s]*\.[\t\s]*[_a-zA-Z][a-zA-Z0-9_]*' + QUOTED_PATTERN = '[\t\s]*L?"[^"]*"' + BOOL_PATTERN = '[\t\s]*(true|True|TRUE|false|False|FALSE)' + def __init__(self, Token): + self.Token = Token + self.Index = 0 + self.Len = len(Token) + + ## SkipWhitespace + # + def SkipWhitespace(self): + for Char in self.Token[self.Index:]: + if Char not in ' \t': + break + self.Index += 1 + + ## IsCurrentOp + # + # @param OpList: option list + # + def IsCurrentOp(self, OpList): + self.SkipWhitespace() + LetterOp = ["EQ", "NE", "GE", "LE", "GT", "LT", "NOT", "and", "AND", + "or", "OR", "XOR"] + OpMap = { + '|' : '|', + '&' : '&', + '!' : '=', + '>' : '=', + '<' : '=' + } + + for Operator in OpList: + if not self.Token[self.Index:].startswith(Operator): + continue + + self.Index += len(Operator) + Char = self.Token[self.Index : self.Index + 1] + + if (Operator in LetterOp and (Char == '_' or Char.isalnum())) \ + or (Operator in OpMap and OpMap[Operator] == Char): + self.Index -= len(Operator) + break + + return True + + return False + +## _LogicalExpressionParser +# +# @param _ExprBase: _ExprBase object +# +class _LogicalExpressionParser(_ExprBase): + # + # STRINGITEM can only be logical field according to spec + # + STRINGITEM = -1 + + # + # Evaluate to True or False + # + LOGICAL = 0 + REALLOGICAL = 2 + + # + # Just arithmetic expression + # + ARITH = 1 + + def __init__(self, Token): + _ExprBase.__init__(self, Token) + self.Parens = 0 + + def _CheckToken(self, MatchList): + for Match in MatchList: + if Match and Match.start() == 0: + if not _ValidateToken( + self.Token[self.Index:self.Index+Match.end()] + ): + return False + + self.Index += Match.end() + if self.Token[self.Index - 1] == '"': + return True + if self.Token[self.Index:self.Index+1] == '_' or \ + self.Token[self.Index:self.Index+1].isalnum(): + self.Index -= Match.end() + return False + + Token = self.Token[self.Index - Match.end():self.Index] + if Token.strip() in ["EQ", "NE", "GE", "LE", "GT", "LT", + "NOT", "and", "AND", "or", "OR", "XOR"]: + self.Index -= Match.end() + return False + + return True + + return False + + def IsAtomicNumVal(self): + # + # Hex number + # + Match1 = re.compile(self.HEX_PATTERN).match(self.Token[self.Index:]) + + # + # Number + # + Match2 = re.compile(self.INT_PATTERN).match(self.Token[self.Index:]) + + # + # Macro + # + Match3 = re.compile(self.MACRO_PATTERN).match(self.Token[self.Index:]) + + # + # PcdName + # + Match4 = re.compile(self.PCD_PATTERN).match(self.Token[self.Index:]) + + return self._CheckToken([Match1, Match2, Match3, Match4]) + + + def IsAtomicItem(self): + # + # Macro + # + Match1 = re.compile(self.MACRO_PATTERN).match(self.Token[self.Index:]) + + # + # PcdName + # + Match2 = re.compile(self.PCD_PATTERN).match(self.Token[self.Index:]) + + # + # Quoted string + # + Match3 = re.compile(self.QUOTED_PATTERN).\ + match(self.Token[self.Index:].replace('\\\\', '//').\ + replace('\\\"', '\\\'')) + + return self._CheckToken([Match1, Match2, Match3]) + + ## A || B + # + def LogicalExpression(self): + Ret = self.SpecNot() + while self.IsCurrentOp(['||', 'OR', 'or', '&&', 'AND', 'and', 'XOR', 'xor', '^']): + if self.Token[self.Index-1] == '|' and self.Parens <= 0: + raise _ExprError(ST.ERR_EXPR_OR % self.Token) + if Ret not in [self.ARITH, self.LOGICAL, self.REALLOGICAL, self.STRINGITEM]: + raise _ExprError(ST.ERR_EXPR_LOGICAL % self.Token) + Ret = self.SpecNot() + if Ret not in [self.ARITH, self.LOGICAL, self.REALLOGICAL, self.STRINGITEM]: + raise _ExprError(ST.ERR_EXPR_LOGICAL % self.Token) + Ret = self.REALLOGICAL + return Ret + + def SpecNot(self): + if self.IsCurrentOp(["NOT", "!", "not"]): + return self.SpecNot() + return self.Rel() + + ## A < B, A > B, A <= B, A >= B + # + def Rel(self): + Ret = self.Expr() + if self.IsCurrentOp(["<=", ">=", ">", "<", "GT", "LT", "GE", "LE", + "==", "EQ", "!=", "NE"]): + if Ret == self.STRINGITEM: + raise _ExprError(ST.ERR_EXPR_LOGICAL % self.Token) + Ret = self.Expr() + if Ret == self.REALLOGICAL: + raise _ExprError(ST.ERR_EXPR_LOGICAL % self.Token) + Ret = self.REALLOGICAL + return Ret + + ## A + B, A - B + # + def Expr(self): + Ret = self.Factor() + while self.IsCurrentOp(["+", "-", "&", "|", "^", "XOR", "xor"]): + if self.Token[self.Index-1] == '|' and self.Parens <= 0: + raise _ExprError(ST.ERR_EXPR_OR) + if Ret == self.STRINGITEM or Ret == self.REALLOGICAL: + raise _ExprError(ST.ERR_EXPR_LOGICAL % self.Token) + Ret = self.Factor() + if Ret == self.STRINGITEM or Ret == self.REALLOGICAL: + raise _ExprError(ST.ERR_EXPR_LOGICAL % self.Token) + Ret = self.ARITH + return Ret + + ## Factor + # + def Factor(self): + if self.IsCurrentOp(["("]): + self.Parens += 1 + Ret = self.LogicalExpression() + if not self.IsCurrentOp([")"]): + raise _ExprError(ST.ERR_EXPR_RIGHT_PAREN % \ + (self.Token, self.Token[self.Index:])) + self.Parens -= 1 + return Ret + + if self.IsAtomicItem(): + if self.Token[self.Index - 1] == '"': + return self.STRINGITEM + return self.LOGICAL + elif self.IsAtomicNumVal(): + return self.ARITH + else: + raise _ExprError(ST.ERR_EXPR_FACTOR % \ + (self.Token[self.Index:], self.Token)) + + ## IsValidLogicalExpression + # + def IsValidLogicalExpression(self): + if self.Len == 0: + return False, ST.ERR_EXPRESS_EMPTY + try: + if self.LogicalExpression() not in [self.ARITH, self.LOGICAL, self.REALLOGICAL, self.STRINGITEM]: + return False, ST.ERR_EXPR_LOGICAL % self.Token + except _ExprError as XExcept: + return False, XExcept.Error + self.SkipWhitespace() + if self.Index != self.Len: + return False, (ST.ERR_EXPR_BOOLEAN % \ + (self.Token[self.Index:], self.Token)) + return True, '' + +## _ValidRangeExpressionParser +# +class _ValidRangeExpressionParser(_ExprBase): + INT_RANGE_PATTERN = '[\t\s]*[0-9]+[\t\s]*-[\t\s]*[0-9]+' + HEX_RANGE_PATTERN = \ + '[\t\s]*0[xX][a-fA-F0-9]+[\t\s]*-[\t\s]*0[xX][a-fA-F0-9]+' + def __init__(self, Token): + _ExprBase.__init__(self, Token) + self.Parens = 0 + self.HEX = 1 + self.INT = 2 + self.IsParenHappen = False + self.IsLogicalOpHappen = False + + ## IsValidRangeExpression + # + def IsValidRangeExpression(self): + if self.Len == 0: + return False, ST.ERR_EXPR_RANGE_EMPTY + try: + if self.RangeExpression() not in [self.HEX, self.INT]: + return False, ST.ERR_EXPR_RANGE % self.Token + except _ExprError as XExcept: + return False, XExcept.Error + + self.SkipWhitespace() + if self.Index != self.Len: + return False, (ST.ERR_EXPR_RANGE % self.Token) + return True, '' + + ## RangeExpression + # + def RangeExpression(self): + Ret = self.Unary() + while self.IsCurrentOp(['OR', 'AND', 'and', 'or']): + self.IsLogicalOpHappen = True + if not self.IsParenHappen: + raise _ExprError(ST.ERR_PAREN_NOT_USED % self.Token) + self.IsParenHappen = False + Ret = self.Unary() + + if self.IsCurrentOp(['XOR']): + Ret = self.Unary() + + return Ret + + ## Unary + # + def Unary(self): + if self.IsCurrentOp(["NOT"]): + return self.Unary() + + return self.ValidRange() + + ## ValidRange + # + def ValidRange(self): + Ret = -1 + if self.IsCurrentOp(["("]): + self.IsLogicalOpHappen = False + self.IsParenHappen = True + self.Parens += 1 + if self.Parens > 1: + raise _ExprError(ST.ERR_EXPR_RANGE_DOUBLE_PAREN_NESTED % self.Token) + Ret = self.RangeExpression() + if not self.IsCurrentOp([")"]): + raise _ExprError(ST.ERR_EXPR_RIGHT_PAREN % self.Token) + self.Parens -= 1 + return Ret + + if self.IsLogicalOpHappen: + raise _ExprError(ST.ERR_PAREN_NOT_USED % self.Token) + + if self.IsCurrentOp(["LT", "GT", "LE", "GE", "EQ", "XOR"]): + IntMatch = \ + re.compile(self.INT_PATTERN).match(self.Token[self.Index:]) + HexMatch = \ + re.compile(self.HEX_PATTERN).match(self.Token[self.Index:]) + if HexMatch and HexMatch.start() == 0: + self.Index += HexMatch.end() + Ret = self.HEX + elif IntMatch and IntMatch.start() == 0: + self.Index += IntMatch.end() + Ret = self.INT + else: + raise _ExprError(ST.ERR_EXPR_RANGE_FACTOR % (self.Token[self.Index:], self.Token)) + else: + IntRangeMatch = re.compile( + self.INT_RANGE_PATTERN).match(self.Token[self.Index:] + ) + HexRangeMatch = re.compile( + self.HEX_RANGE_PATTERN).match(self.Token[self.Index:] + ) + if HexRangeMatch and HexRangeMatch.start() == 0: + self.Index += HexRangeMatch.end() + Ret = self.HEX + elif IntRangeMatch and IntRangeMatch.start() == 0: + self.Index += IntRangeMatch.end() + Ret = self.INT + else: + raise _ExprError(ST.ERR_EXPR_RANGE % self.Token) + + return Ret + +## _ValidListExpressionParser +# +class _ValidListExpressionParser(_ExprBase): + VALID_LIST_PATTERN = '(0[xX][0-9a-fA-F]+|[0-9]+)([\t\s]*,[\t\s]*(0[xX][0-9a-fA-F]+|[0-9]+))*' + def __init__(self, Token): + _ExprBase.__init__(self, Token) + self.NUM = 1 + + def IsValidListExpression(self): + if self.Len == 0: + return False, ST.ERR_EXPR_LIST_EMPTY + try: + if self.ListExpression() not in [self.NUM]: + return False, ST.ERR_EXPR_LIST % self.Token + except _ExprError as XExcept: + return False, XExcept.Error + + self.SkipWhitespace() + if self.Index != self.Len: + return False, (ST.ERR_EXPR_LIST % self.Token) + + return True, '' + + def ListExpression(self): + Ret = -1 + self.SkipWhitespace() + ListMatch = re.compile(self.VALID_LIST_PATTERN).match(self.Token[self.Index:]) + if ListMatch and ListMatch.start() == 0: + self.Index += ListMatch.end() + Ret = self.NUM + else: + raise _ExprError(ST.ERR_EXPR_LIST % self.Token) + + return Ret + +## _StringTestParser +# +class _StringTestParser(_ExprBase): + def __init__(self, Token): + _ExprBase.__init__(self, Token) + + ## IsValidStringTest + # + def IsValidStringTest(self): + if self.Len == 0: + return False, ST.ERR_EXPR_EMPTY + try: + self.StringTest() + except _ExprError as XExcept: + return False, XExcept.Error + return True, '' + + ## StringItem + # + def StringItem(self): + Match1 = re.compile(self.QUOTED_PATTERN)\ + .match(self.Token[self.Index:].replace('\\\\', '//')\ + .replace('\\\"', '\\\'')) + Match2 = re.compile(self.MACRO_PATTERN).match(self.Token[self.Index:]) + Match3 = re.compile(self.PCD_PATTERN).match(self.Token[self.Index:]) + MatchList = [Match1, Match2, Match3] + for Match in MatchList: + if Match and Match.start() == 0: + if not _ValidateToken( + self.Token[self.Index:self.Index+Match.end()] + ): + raise _ExprError(ST.ERR_EXPR_STRING_ITEM % \ + (self.Token, self.Token[self.Index:])) + self.Index += Match.end() + Token = self.Token[self.Index - Match.end():self.Index] + if Token.strip() in ["EQ", "NE"]: + raise _ExprError(ST.ERR_EXPR_STRING_ITEM % \ + (self.Token, self.Token[self.Index:])) + return + else: + raise _ExprError(ST.ERR_EXPR_STRING_ITEM % \ + (self.Token, self.Token[self.Index:])) + + ## StringTest + # + def StringTest(self): + self.StringItem() + if not self.IsCurrentOp(["==", "EQ", "!=", "NE"]): + raise _ExprError(ST.ERR_EXPR_EQUALITY % \ + (self.Token[self.Index:], self.Token)) + self.StringItem() + if self.Index != self.Len: + raise _ExprError(ST.ERR_EXPR_BOOLEAN % \ + (self.Token[self.Index:], self.Token)) + +## +# Check syntax of string test +# +# @param Token: string test token +# +def IsValidStringTest(Token, Flag=False): + # + # Not do the check right now, keep the implementation for future enhancement. + # + if not Flag: + return True, "" + return _StringTestParser(Token).IsValidStringTest() + + +## +# Check syntax of logical expression +# +# @param Token: expression token +# +def IsValidLogicalExpr(Token, Flag=False): + # + # Not do the check right now, keep the implementation for future enhancement. + # + if not Flag: + return True, "" + return _LogicalExpressionParser(Token).IsValidLogicalExpression() + +## +# Check syntax of range expression +# +# @param Token: range expression token +# +def IsValidRangeExpr(Token): + return _ValidRangeExpressionParser(Token).IsValidRangeExpression() + +## +# Check syntax of value list expression token +# +# @param Token: value list expression token +# +def IsValidListExpr(Token): + return _ValidListExpressionParser(Token).IsValidListExpression() + +## +# Check whether the feature flag expression is valid or not +# +# @param Token: feature flag expression +# +def IsValidFeatureFlagExp(Token, Flag=False): + # + # Not do the check right now, keep the implementation for future enhancement. + # + if not Flag: + return True, "", Token + else: + if Token in ['TRUE', 'FALSE', 'true', 'false', 'True', 'False', + '0x1', '0x01', '0x0', '0x00']: + return True, "" + Valid, Cause = IsValidStringTest(Token, Flag) + if not Valid: + Valid, Cause = IsValidLogicalExpr(Token, Flag) + if not Valid: + return False, Cause + return True, "" + +if __name__ == '__main__': +# print IsValidRangeExpr('LT 9') + print(_LogicalExpressionParser('gCrownBayTokenSpaceGuid.PcdPciDevice1BridgeAddressLE0').IsValidLogicalExpression()) + + + diff --git a/BaseTools/Source/Python/UPT/Library/GlobalData.py b/BaseTools/Source/Python/UPT/Library/GlobalData.py index 8e88fb1e3f..984294c96f 100644 --- a/BaseTools/Source/Python/UPT/Library/GlobalData.py +++ b/BaseTools/Source/Python/UPT/Library/GlobalData.py @@ -1,110 +1,110 @@ -## @file
-# This file is used to define common static strings and global data used by UPT
-#
-# Copyright (c) 2011 - 2018, Intel Corporation. All rights reserved.<BR>
-#
-# SPDX-License-Identifier: BSD-2-Clause-Patent
-
-'''
-GlobalData
-'''
-
-#
-# The workspace directory
-#
-gWORKSPACE = '.'
-gPACKAGE_PATH = None
-
-#
-# INF module directory
-#
-gINF_MODULE_DIR = "."
-gINF_MODULE_NAME = ''
-
-#
-# the directory to holds upt related files
-#
-gUPT_DIR = r"Conf/upt/"
-
-#
-# Log file for invalid meta-data files during force removing
-#
-gINVALID_MODULE_FILE = gUPT_DIR + r"Invalid_Modules.log"
-
-#
-# File name for content zip file in the distribution
-#
-gCONTENT_FILE = "dist.content"
-
-#
-# File name for XML file in the distribution
-#
-gDESC_FILE = 'dist.pkg'
-
-#
-# Case Insensitive flag
-#
-gCASE_INSENSITIVE = ''
-
-#
-# All Files dictionary
-#
-gALL_FILES = {}
-
-#
-# Database instance
-#
-gDB = None
-
-#
-# list for files that are found in module level but not in INF files,
-# items are (File, ModulePath), all these should be relative to $(WORKSPACE)
-#
-gMISS_FILE_IN_MODLIST = []
-
-#
-# Global Current Line
-#
-gINF_CURRENT_LINE = None
-
-#
-# Global pkg list
-#
-gWSPKG_LIST = []
-
-#
-# Flag used to take WARN as ERROR.
-# By default, only ERROR message will break the tools execution.
-#
-gWARNING_AS_ERROR = False
-
-#
-# Used to specify the temp directory to hold the unpacked distribution files
-#
-gUNPACK_DIR = []
-
-#
-# Flag used to mark whether the INF file is Binary INF or not.
-#
-gIS_BINARY_INF = False
-
-#
-# Used by FileHook module.
-#
-gRECOVERMGR = None
-
-#
-# Used by PCD parser
-#
-gPackageDict = {}
-
-#
-# Used by Library instance parser
-# {FilePath: FileObj}
-#
-gLIBINSTANCEDICT = {}
-
-#
-# Store the list of DIST
-#
-gTO_BE_INSTALLED_DIST_LIST = []
+## @file +# This file is used to define common static strings and global data used by UPT +# +# Copyright (c) 2011 - 2018, Intel Corporation. All rights reserved.<BR> +# +# SPDX-License-Identifier: BSD-2-Clause-Patent + +''' +GlobalData +''' + +# +# The workspace directory +# +gWORKSPACE = '.' +gPACKAGE_PATH = None + +# +# INF module directory +# +gINF_MODULE_DIR = "." +gINF_MODULE_NAME = '' + +# +# the directory to holds upt related files +# +gUPT_DIR = r"Conf/upt/" + +# +# Log file for invalid meta-data files during force removing +# +gINVALID_MODULE_FILE = gUPT_DIR + r"Invalid_Modules.log" + +# +# File name for content zip file in the distribution +# +gCONTENT_FILE = "dist.content" + +# +# File name for XML file in the distribution +# +gDESC_FILE = 'dist.pkg' + +# +# Case Insensitive flag +# +gCASE_INSENSITIVE = '' + +# +# All Files dictionary +# +gALL_FILES = {} + +# +# Database instance +# +gDB = None + +# +# list for files that are found in module level but not in INF files, +# items are (File, ModulePath), all these should be relative to $(WORKSPACE) +# +gMISS_FILE_IN_MODLIST = [] + +# +# Global Current Line +# +gINF_CURRENT_LINE = None + +# +# Global pkg list +# +gWSPKG_LIST = [] + +# +# Flag used to take WARN as ERROR. +# By default, only ERROR message will break the tools execution. +# +gWARNING_AS_ERROR = False + +# +# Used to specify the temp directory to hold the unpacked distribution files +# +gUNPACK_DIR = [] + +# +# Flag used to mark whether the INF file is Binary INF or not. +# +gIS_BINARY_INF = False + +# +# Used by FileHook module. +# +gRECOVERMGR = None + +# +# Used by PCD parser +# +gPackageDict = {} + +# +# Used by Library instance parser +# {FilePath: FileObj} +# +gLIBINSTANCEDICT = {} + +# +# Store the list of DIST +# +gTO_BE_INSTALLED_DIST_LIST = [] diff --git a/BaseTools/Source/Python/UPT/Library/Misc.py b/BaseTools/Source/Python/UPT/Library/Misc.py index 77ba3584e0..da62c9a7c0 100644 --- a/BaseTools/Source/Python/UPT/Library/Misc.py +++ b/BaseTools/Source/Python/UPT/Library/Misc.py @@ -1,989 +1,989 @@ -## @file
-# Common routines used by all tools
-#
-# Copyright (c) 2011 - 2019, Intel Corporation. All rights reserved.<BR>
-#
-# SPDX-License-Identifier: BSD-2-Clause-Patent
-#
-
-'''
-Misc
-'''
-
-##
-# Import Modules
-#
-import os.path
-from os import access
-from os import F_OK
-from os import makedirs
-from os import getcwd
-from os import chdir
-from os import listdir
-from os import remove
-from os import rmdir
-from os import linesep
-from os import walk
-from os import environ
-import re
-from collections import OrderedDict as Sdict
-
-import Logger.Log as Logger
-from Logger import StringTable as ST
-from Logger import ToolError
-from Library import GlobalData
-from Library.DataType import SUP_MODULE_LIST
-from Library.DataType import END_OF_LINE
-from Library.DataType import TAB_SPLIT
-from Library.DataType import TAB_LANGUAGE_EN_US
-from Library.DataType import TAB_LANGUAGE_EN
-from Library.DataType import TAB_LANGUAGE_EN_X
-from Library.DataType import TAB_UNI_FILE_SUFFIXS
-from Library.StringUtils import GetSplitValueList
-from Library.ParserValidate import IsValidHexVersion
-from Library.ParserValidate import IsValidPath
-from Object.POM.CommonObject import TextObject
-from Core.FileHook import __FileHookOpen__
-from Common.MultipleWorkspace import MultipleWorkspace as mws
-
-## Convert GUID string in xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx style to C
-# structure style
-#
-# @param Guid: The GUID string
-#
-def GuidStringToGuidStructureString(Guid):
- GuidList = Guid.split('-')
- Result = '{'
- for Index in range(0, 3, 1):
- Result = Result + '0x' + GuidList[Index] + ', '
- Result = Result + '{0x' + GuidList[3][0:2] + ', 0x' + GuidList[3][2:4]
- for Index in range(0, 12, 2):
- Result = Result + ', 0x' + GuidList[4][Index:Index + 2]
- Result += '}}'
- return Result
-
-## Check whether GUID string is of format xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx
-#
-# @param GuidValue: The GUID value
-#
-def CheckGuidRegFormat(GuidValue):
- ## Regular expression used to find out register format of GUID
- #
- 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*$")
-
- if RegFormatGuidPattern.match(GuidValue):
- return True
- else:
- return False
-
-
-## Convert GUID string in C structure style to
-# xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx
-#
-# @param GuidValue: The GUID value in C structure format
-#
-def GuidStructureStringToGuidString(GuidValue):
- GuidValueString = GuidValue.lower().replace("{", "").replace("}", "").\
- replace(" ", "").replace(";", "")
- GuidValueList = GuidValueString.split(",")
- if len(GuidValueList) != 11:
- return ''
- try:
- return "%08x-%04x-%04x-%02x%02x-%02x%02x%02x%02x%02x%02x" % (
- int(GuidValueList[0], 16),
- int(GuidValueList[1], 16),
- int(GuidValueList[2], 16),
- int(GuidValueList[3], 16),
- int(GuidValueList[4], 16),
- int(GuidValueList[5], 16),
- int(GuidValueList[6], 16),
- int(GuidValueList[7], 16),
- int(GuidValueList[8], 16),
- int(GuidValueList[9], 16),
- int(GuidValueList[10], 16)
- )
- except BaseException:
- return ''
-
-## Create directories
-#
-# @param Directory: The directory name
-#
-def CreateDirectory(Directory):
- if Directory is None or Directory.strip() == "":
- return True
- try:
- if not access(Directory, F_OK):
- makedirs(Directory)
- except BaseException:
- return False
- return True
-
-## Remove directories, including files and sub-directories in it
-#
-# @param Directory: The directory name
-#
-def RemoveDirectory(Directory, Recursively=False):
- if Directory is None or Directory.strip() == "" or not \
- os.path.exists(Directory):
- return
- if Recursively:
- CurrentDirectory = getcwd()
- chdir(Directory)
- for File in listdir("."):
- if os.path.isdir(File):
- RemoveDirectory(File, Recursively)
- else:
- remove(File)
- chdir(CurrentDirectory)
- rmdir(Directory)
-
-## Store content in file
-#
-# This method is used to save file only when its content is changed. This is
-# quite useful for "make" system to decide what will be re-built and what
-# won't.
-#
-# @param File: The path of file
-# @param Content: The new content of the file
-# @param IsBinaryFile: The flag indicating if the file is binary file
-# or not
-#
-def SaveFileOnChange(File, Content, IsBinaryFile=True):
- if os.path.exists(File):
- if IsBinaryFile:
- try:
- if Content == __FileHookOpen__(File, "rb").read():
- return False
- except BaseException:
- Logger.Error(None, ToolError.FILE_OPEN_FAILURE, ExtraData=File)
- else:
- try:
- if Content == __FileHookOpen__(File, "r").read():
- return False
- except BaseException:
- Logger.Error(None, ToolError.FILE_OPEN_FAILURE, ExtraData=File)
-
- CreateDirectory(os.path.dirname(File))
- if IsBinaryFile:
- try:
- FileFd = __FileHookOpen__(File, "wb")
- FileFd.write(Content)
- FileFd.close()
- except BaseException:
- Logger.Error(None, ToolError.FILE_CREATE_FAILURE, ExtraData=File)
- else:
- try:
- FileFd = __FileHookOpen__(File, "w")
- FileFd.write(Content)
- FileFd.close()
- except BaseException:
- Logger.Error(None, ToolError.FILE_CREATE_FAILURE, ExtraData=File)
-
- return True
-
-## Get all files of a directory
-#
-# @param Root: Root dir
-# @param SkipList : The files need be skipped
-#
-def GetFiles(Root, SkipList=None, FullPath=True):
- OriPath = os.path.normpath(Root)
- FileList = []
- for Root, Dirs, Files in walk(Root):
- if SkipList:
- for Item in SkipList:
- if Item in Dirs:
- Dirs.remove(Item)
- if Item in Files:
- Files.remove(Item)
- for Dir in Dirs:
- if Dir.startswith('.'):
- Dirs.remove(Dir)
-
- for File in Files:
- if File.startswith('.'):
- continue
- File = os.path.normpath(os.path.join(Root, File))
- if not FullPath:
- File = File[len(OriPath) + 1:]
- FileList.append(File)
-
- return FileList
-
-## Get all non-metadata files of a directory
-#
-# @param Root: Root Dir
-# @param SkipList : List of path need be skipped
-# @param FullPath: True if the returned file should be full path
-# @param PrefixPath: the path that need to be added to the files found
-# @return: the list of files found
-#
-def GetNonMetaDataFiles(Root, SkipList, FullPath, PrefixPath):
- FileList = GetFiles(Root, SkipList, FullPath)
- NewFileList = []
- for File in FileList:
- ExtName = os.path.splitext(File)[1]
- #
- # skip '.dec', '.inf', '.dsc', '.fdf' files
- #
- if ExtName.lower() not in ['.dec', '.inf', '.dsc', '.fdf']:
- NewFileList.append(os.path.normpath(os.path.join(PrefixPath, File)))
-
- return NewFileList
-
-## Check if given file exists or not
-#
-# @param File: File name or path to be checked
-# @param Dir: The directory the file is relative to
-#
-def ValidFile(File, Ext=None):
- File = File.replace('\\', '/')
- if Ext is not None:
- FileExt = os.path.splitext(File)[1]
- if FileExt.lower() != Ext.lower():
- return False
- if not os.path.exists(File):
- return False
- return True
-
-## RealPath
-#
-# @param File: File name or path to be checked
-# @param Dir: The directory the file is relative to
-# @param OverrideDir: The override directory
-#
-def RealPath(File, Dir='', OverrideDir=''):
- NewFile = os.path.normpath(os.path.join(Dir, File))
- NewFile = GlobalData.gALL_FILES[NewFile]
- if not NewFile and OverrideDir:
- NewFile = os.path.normpath(os.path.join(OverrideDir, File))
- NewFile = GlobalData.gALL_FILES[NewFile]
- return NewFile
-
-## RealPath2
-#
-# @param File: File name or path to be checked
-# @param Dir: The directory the file is relative to
-# @param OverrideDir: The override directory
-#
-def RealPath2(File, Dir='', OverrideDir=''):
- if OverrideDir:
- NewFile = GlobalData.gALL_FILES[os.path.normpath(os.path.join\
- (OverrideDir, File))]
- if NewFile:
- if OverrideDir[-1] == os.path.sep:
- return NewFile[len(OverrideDir):], NewFile[0:len(OverrideDir)]
- else:
- return NewFile[len(OverrideDir) + 1:], \
- NewFile[0:len(OverrideDir)]
-
- NewFile = GlobalData.gALL_FILES[os.path.normpath(os.path.join(Dir, File))]
- if NewFile:
- if Dir:
- if Dir[-1] == os.path.sep:
- return NewFile[len(Dir):], NewFile[0:len(Dir)]
- else:
- return NewFile[len(Dir) + 1:], NewFile[0:len(Dir)]
- else:
- return NewFile, ''
-
- return None, None
-
-## CommonPath
-#
-# @param PathList: PathList
-#
-def CommonPath(PathList):
- Path1 = min(PathList).split(os.path.sep)
- Path2 = max(PathList).split(os.path.sep)
- for Index in range(min(len(Path1), len(Path2))):
- if Path1[Index] != Path2[Index]:
- return os.path.sep.join(Path1[:Index])
- return os.path.sep.join(Path1)
-
-## PathClass
-#
-class PathClass(object):
- def __init__(self, File='', Root='', AlterRoot='', Type='', IsBinary=False,
- Arch='COMMON', ToolChainFamily='', Target='', TagName='', \
- ToolCode=''):
- self.Arch = Arch
- self.File = str(File)
- if os.path.isabs(self.File):
- self.Root = ''
- self.AlterRoot = ''
- else:
- self.Root = str(Root)
- self.AlterRoot = str(AlterRoot)
-
- #
- # Remove any '.' and '..' in path
- #
- if self.Root:
- self.Path = os.path.normpath(os.path.join(self.Root, self.File))
- self.Root = os.path.normpath(CommonPath([self.Root, self.Path]))
- #
- # eliminate the side-effect of 'C:'
- #
- if self.Root[-1] == ':':
- self.Root += os.path.sep
- #
- # file path should not start with path separator
- #
- if self.Root[-1] == os.path.sep:
- self.File = self.Path[len(self.Root):]
- else:
- self.File = self.Path[len(self.Root) + 1:]
- else:
- self.Path = os.path.normpath(self.File)
-
- self.SubDir, self.Name = os.path.split(self.File)
- self.BaseName, self.Ext = os.path.splitext(self.Name)
-
- if self.Root:
- if self.SubDir:
- self.Dir = os.path.join(self.Root, self.SubDir)
- else:
- self.Dir = self.Root
- else:
- self.Dir = self.SubDir
-
- if IsBinary:
- self.Type = Type
- else:
- self.Type = self.Ext.lower()
-
- self.IsBinary = IsBinary
- self.Target = Target
- self.TagName = TagName
- self.ToolCode = ToolCode
- self.ToolChainFamily = ToolChainFamily
-
- self._Key = None
-
- ## Convert the object of this class to a string
- #
- # Convert member Path of the class to a string
- #
- def __str__(self):
- return self.Path
-
- ## Override __eq__ function
- #
- # Check whether PathClass are the same
- #
- def __eq__(self, Other):
- if isinstance(Other, type(self)):
- return self.Path == Other.Path
- else:
- return self.Path == str(Other)
-
- ## Override __hash__ function
- #
- # Use Path as key in hash table
- #
- def __hash__(self):
- return hash(self.Path)
-
- ## _GetFileKey
- #
- def _GetFileKey(self):
- if self._Key is None:
- self._Key = self.Path.upper()
- return self._Key
- ## Validate
- #
- def Validate(self, Type='', CaseSensitive=True):
- if GlobalData.gCASE_INSENSITIVE:
- CaseSensitive = False
- if Type and Type.lower() != self.Type:
- return ToolError.FILE_TYPE_MISMATCH, '%s (expect %s but got %s)' % \
- (self.File, Type, self.Type)
-
- RealFile, RealRoot = RealPath2(self.File, self.Root, self.AlterRoot)
- if not RealRoot and not RealFile:
- RealFile = self.File
- if self.AlterRoot:
- RealFile = os.path.join(self.AlterRoot, self.File)
- elif self.Root:
- RealFile = os.path.join(self.Root, self.File)
- return ToolError.FILE_NOT_FOUND, os.path.join(self.AlterRoot, RealFile)
-
- ErrorCode = 0
- ErrorInfo = ''
- if RealRoot != self.Root or RealFile != self.File:
- if CaseSensitive and (RealFile != self.File or \
- (RealRoot != self.Root and RealRoot != \
- self.AlterRoot)):
- ErrorCode = ToolError.FILE_CASE_MISMATCH
- ErrorInfo = self.File + '\n\t' + RealFile + \
- " [in file system]"
-
- self.SubDir, self.Name = os.path.split(RealFile)
- self.BaseName, self.Ext = os.path.splitext(self.Name)
- if self.SubDir:
- self.Dir = os.path.join(RealRoot, self.SubDir)
- else:
- self.Dir = RealRoot
- self.File = RealFile
- self.Root = RealRoot
- self.Path = os.path.join(RealRoot, RealFile)
- return ErrorCode, ErrorInfo
-
- Key = property(_GetFileKey)
-
-## Get current workspace
-#
-# get WORKSPACE from environment variable if present,if not use current working directory as WORKSPACE
-#
-def GetWorkspace():
- #
- # check WORKSPACE
- #
- if "WORKSPACE" in environ:
- WorkspaceDir = os.path.normpath(environ["WORKSPACE"])
- if not os.path.exists(WorkspaceDir):
- Logger.Error("UPT",
- ToolError.UPT_ENVIRON_MISSING_ERROR,
- ST.ERR_WORKSPACE_NOTEXIST,
- ExtraData="%s" % WorkspaceDir)
- else:
- WorkspaceDir = os.getcwd()
-
- if WorkspaceDir[-1] == ':':
- WorkspaceDir += os.sep
-
- PackagesPath = os.environ.get("PACKAGES_PATH")
- mws.setWs(WorkspaceDir, PackagesPath)
-
- return WorkspaceDir, mws.PACKAGES_PATH
-
-## Get relative path
-#
-# use full path and workspace to get relative path
-# the destination of this function is mainly to resolve the root path issue(like c: or c:\)
-#
-# @param Fullpath: a string of fullpath
-# @param Workspace: a string of workspace
-#
-def GetRelativePath(Fullpath, Workspace):
-
- RelativePath = ''
- if Workspace.endswith(os.sep):
- RelativePath = Fullpath[Fullpath.upper().find(Workspace.upper())+len(Workspace):]
- else:
- RelativePath = Fullpath[Fullpath.upper().find(Workspace.upper())+len(Workspace)+1:]
-
- return RelativePath
-
-## Check whether all module types are in list
-#
-# check whether all module types (SUP_MODULE_LIST) are in list
-#
-# @param ModuleList: a list of ModuleType
-#
-def IsAllModuleList(ModuleList):
- NewModuleList = [Module.upper() for Module in ModuleList]
- for Module in SUP_MODULE_LIST:
- if Module not in NewModuleList:
- return False
- else:
- return True
-
-## Dictionary that use comment(GenericComment, TailComment) as value,
-# if a new comment which key already in the dic is inserted, then the
-# comment will be merged.
-# Key is (Statement, SupArch), when TailComment is added, it will ident
-# according to Statement
-#
-class MergeCommentDict(dict):
- ## []= operator
- #
- def __setitem__(self, Key, CommentVal):
- GenericComment, TailComment = CommentVal
- if Key in self:
- OrigVal1, OrigVal2 = dict.__getitem__(self, Key)
- Statement = Key[0]
- dict.__setitem__(self, Key, (OrigVal1 + GenericComment, OrigVal2 \
- + len(Statement) * ' ' + TailComment))
- else:
- dict.__setitem__(self, Key, (GenericComment, TailComment))
-
- ## =[] operator
- #
- def __getitem__(self, Key):
- return dict.__getitem__(self, Key)
-
-
-## GenDummyHelpTextObj
-#
-# @retval HelpTxt: Generated dummy help text object
-#
-def GenDummyHelpTextObj():
- HelpTxt = TextObject()
- HelpTxt.SetLang(TAB_LANGUAGE_EN_US)
- HelpTxt.SetString(' ')
- return HelpTxt
-
-## ConvertVersionToDecimal, the minor version should be within 0 - 99
-# <HexVersion> ::= "0x" <Major> <Minor>
-# <Major> ::= (a-fA-F0-9){4}
-# <Minor> ::= (a-fA-F0-9){4}
-# <DecVersion> ::= (0-65535) ["." (0-99)]
-#
-# @param StringIn: The string contains version defined in INF file.
-# It can be Decimal or Hex
-#
-def ConvertVersionToDecimal(StringIn):
- if IsValidHexVersion(StringIn):
- Value = int(StringIn, 16)
- Major = Value >> 16
- Minor = Value & 0xFFFF
- MinorStr = str(Minor)
- if len(MinorStr) == 1:
- MinorStr = '0' + MinorStr
- return str(Major) + '.' + MinorStr
- else:
- if StringIn.find(TAB_SPLIT) != -1:
- return StringIn
- elif StringIn:
- return StringIn + '.0'
- else:
- #
- # when StringIn is '', return it directly
- #
- return StringIn
-
-## GetHelpStringByRemoveHashKey
-#
-# Remove hash key at the header of string and return the remain.
-#
-# @param String: The string need to be processed.
-#
-def GetHelpStringByRemoveHashKey(String):
- ReturnString = ''
- PattenRemoveHashKey = re.compile(r"^[#+\s]+", re.DOTALL)
- String = String.strip()
- if String == '':
- return String
-
- LineList = GetSplitValueList(String, END_OF_LINE)
- for Line in LineList:
- ValueList = PattenRemoveHashKey.split(Line)
- if len(ValueList) == 1:
- ReturnString += ValueList[0] + END_OF_LINE
- else:
- ReturnString += ValueList[1] + END_OF_LINE
-
- if ReturnString.endswith('\n') and not ReturnString.endswith('\n\n') and ReturnString != '\n':
- ReturnString = ReturnString[:-1]
-
- return ReturnString
-
-## ConvPathFromAbsToRel
-#
-# Get relative file path from absolute path.
-#
-# @param Path: The string contain file absolute path.
-# @param Root: The string contain the parent path of Path in.
-#
-#
-def ConvPathFromAbsToRel(Path, Root):
- Path = os.path.normpath(Path)
- Root = os.path.normpath(Root)
- FullPath = os.path.normpath(os.path.join(Root, Path))
-
- #
- # If Path is absolute path.
- # It should be in Root.
- #
- if os.path.isabs(Path):
- return FullPath[FullPath.find(Root) + len(Root) + 1:]
-
- else:
- return Path
-
-## ConvertPath
-#
-# Convert special characters to '_', '\' to '/'
-# return converted path: Test!1.inf -> Test_1.inf
-#
-# @param Path: Path to be converted
-#
-def ConvertPath(Path):
- RetPath = ''
- for Char in Path.strip():
- if Char.isalnum() or Char in '.-_/':
- RetPath = RetPath + Char
- elif Char == '\\':
- RetPath = RetPath + '/'
- else:
- RetPath = RetPath + '_'
- return RetPath
-
-## ConvertSpec
-#
-# during install, convert the Spec string extract from UPD into INF allowable definition,
-# the difference is period is allowed in the former (not the first letter) but not in the latter.
-# return converted Spec string
-#
-# @param SpecStr: SpecStr to be converted
-#
-def ConvertSpec(SpecStr):
- RetStr = ''
- for Char in SpecStr:
- if Char.isalnum() or Char == '_':
- RetStr = RetStr + Char
- else:
- RetStr = RetStr + '_'
-
- return RetStr
-
-
-## IsEqualList
-#
-# Judge two lists are identical(contain same item).
-# The rule is elements in List A are in List B and elements in List B are in List A.
-#
-# @param ListA, ListB Lists need to be judged.
-#
-# @return True ListA and ListB are identical
-# @return False ListA and ListB are different with each other
-#
-def IsEqualList(ListA, ListB):
- if ListA == ListB:
- return True
-
- for ItemA in ListA:
- if not ItemA in ListB:
- return False
-
- for ItemB in ListB:
- if not ItemB in ListA:
- return False
-
- return True
-
-## ConvertArchList
-#
-# Convert item in ArchList if the start character is lower case.
-# In UDP spec, Arch is only allowed as: [A-Z]([a-zA-Z0-9])*
-#
-# @param ArchList The ArchList need to be converted.
-#
-# @return NewList The ArchList been converted.
-#
-def ConvertArchList(ArchList):
- NewArchList = []
- if not ArchList:
- return NewArchList
-
- if isinstance(ArchList, list):
- for Arch in ArchList:
- Arch = Arch.upper()
- NewArchList.append(Arch)
- elif isinstance(ArchList, str):
- ArchList = ArchList.upper()
- NewArchList.append(ArchList)
-
- return NewArchList
-
-## ProcessLineExtender
-#
-# Process the LineExtender of Line in LineList.
-# If one line ends with a line extender, then it will be combined together with next line.
-#
-# @param LineList The LineList need to be processed.
-#
-# @return NewList The ArchList been processed.
-#
-def ProcessLineExtender(LineList):
- NewList = []
- Count = 0
- while Count < len(LineList):
- if LineList[Count].strip().endswith("\\") and Count + 1 < len(LineList):
- NewList.append(LineList[Count].strip()[:-2] + LineList[Count + 1])
- Count = Count + 1
- else:
- NewList.append(LineList[Count])
-
- Count = Count + 1
-
- return NewList
-
-## ProcessEdkComment
-#
-# Process EDK style comment in LineList: c style /* */ comment or cpp style // comment
-#
-#
-# @param LineList The LineList need to be processed.
-#
-# @return LineList The LineList been processed.
-# @return FirstPos Where Edk comment is first found, -1 if not found
-#
-def ProcessEdkComment(LineList):
- FindEdkBlockComment = False
- Count = 0
- StartPos = -1
- EndPos = -1
- FirstPos = -1
-
- while(Count < len(LineList)):
- Line = LineList[Count].strip()
- if Line.startswith("/*"):
- #
- # handling c style comment
- #
- StartPos = Count
- while Count < len(LineList):
- Line = LineList[Count].strip()
- if Line.endswith("*/"):
- if (Count == StartPos) and Line.strip() == '/*/':
- Count = Count + 1
- continue
- EndPos = Count
- FindEdkBlockComment = True
- break
- Count = Count + 1
-
- if FindEdkBlockComment:
- if FirstPos == -1:
- FirstPos = StartPos
- for Index in range(StartPos, EndPos+1):
- LineList[Index] = ''
- FindEdkBlockComment = False
- elif Line.find("//") != -1 and not Line.startswith("#"):
- #
- # handling cpp style comment
- #
- LineList[Count] = Line.replace("//", '#')
- if FirstPos == -1:
- FirstPos = Count
-
- Count = Count + 1
-
- return LineList, FirstPos
-
-## 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):
-
- FileGuidString = ""
- VerString = ""
-
- OriginalString = String
- String = String.strip()
- if not String:
- return None, None
- #
- # Remove "#" characters at the beginning
- #
- String = GetHelpStringByRemoveHashKey(String)
- String = String.strip()
-
- #
- # Validate file name exist.
- #
- FullFileName = os.path.normpath(os.path.realpath(os.path.join(WorkSpace, String)))
- if not (ValidFile(FullFileName)):
- Logger.Error("InfParser",
- ToolError.FORMAT_INVALID,
- ST.ERR_FILELIST_EXIST % (String),
- File=GlobalData.gINF_MODULE_NAME,
- Line=LineNo,
- ExtraData=OriginalString)
-
- #
- # Validate file exist/format.
- #
- if IsValidPath(String, WorkSpace):
- IsValidFileFlag = True
- else:
- Logger.Error("InfParser",
- ToolError.FORMAT_INVALID,
- ST.ERR_INF_PARSER_FILE_NOT_EXIST_OR_NAME_INVALID % (String),
- File=GlobalData.gINF_MODULE_NAME,
- Line=LineNo,
- ExtraData=OriginalString)
- return False
- if IsValidFileFlag:
- FileLinesList = []
-
- try:
- FInputfile = open(FullFileName, "r")
- try:
- FileLinesList = FInputfile.readlines()
- except BaseException:
- Logger.Error("InfParser",
- ToolError.FILE_READ_FAILURE,
- ST.ERR_FILE_OPEN_FAILURE,
- File=FullFileName)
- finally:
- FInputfile.close()
- except BaseException:
- Logger.Error("InfParser",
- ToolError.FILE_READ_FAILURE,
- ST.ERR_FILE_OPEN_FAILURE,
- File=FullFileName)
-
- ReFileGuidPattern = re.compile("^\s*FILE_GUID\s*=.*$")
- ReVerStringPattern = re.compile("^\s*VERSION_STRING\s*=.*$")
-
- FileLinesList = ProcessLineExtender(FileLinesList)
-
- for Line in FileLinesList:
- if ReFileGuidPattern.match(Line):
- FileGuidString = Line
- if ReVerStringPattern.match(Line):
- VerString = Line
-
- if FileGuidString:
- FileGuidString = GetSplitValueList(FileGuidString, '=', 1)[1]
- if VerString:
- VerString = GetSplitValueList(VerString, '=', 1)[1]
-
- return FileGuidString, VerString
-
-## GetLocalValue
-#
-# Generate the local value for INF and DEC file. If Lang attribute not present, then use this value.
-# If present, and there is no element without the Lang attribute, and one of the elements has the rfc1766 code is
-# "en-x-tianocore", or "en-US" if "en-x-tianocore" was not found, or "en" if "en-US" was not found, or startswith 'en'
-# if 'en' was not found, then use this value.
-# If multiple entries of a tag exist which have the same language code, use the last entry.
-#
-# @param ValueList A list need to be processed.
-# @param UseFirstValue: True to use the first value, False to use the last value
-#
-# @return LocalValue
-def GetLocalValue(ValueList, UseFirstValue=False):
- Value1 = ''
- Value2 = ''
- Value3 = ''
- Value4 = ''
- Value5 = ''
- for (Key, Value) in ValueList:
- if Key == TAB_LANGUAGE_EN_X:
- if UseFirstValue:
- if not Value1:
- Value1 = Value
- else:
- Value1 = Value
- if Key == TAB_LANGUAGE_EN_US:
- if UseFirstValue:
- if not Value2:
- Value2 = Value
- else:
- Value2 = Value
- if Key == TAB_LANGUAGE_EN:
- if UseFirstValue:
- if not Value3:
- Value3 = Value
- else:
- Value3 = Value
- if Key.startswith(TAB_LANGUAGE_EN):
- if UseFirstValue:
- if not Value4:
- Value4 = Value
- else:
- Value4 = Value
- if Key == '':
- if UseFirstValue:
- if not Value5:
- Value5 = Value
- else:
- Value5 = Value
-
- if Value1:
- return Value1
- if Value2:
- return Value2
- if Value3:
- return Value3
- if Value4:
- return Value4
- if Value5:
- return Value5
-
- return ''
-
-
-## GetCharIndexOutStr
-#
-# Get comment character index outside a string
-#
-# @param Line: The string to be checked
-# @param CommentCharacter: Comment char, used to ignore comment content
-#
-# @retval Index
-#
-def GetCharIndexOutStr(CommentCharacter, Line):
- #
- # remove whitespace
- #
- Line = Line.strip()
-
- #
- # Check whether comment character is in a string
- #
- InString = False
- for Index in range(0, len(Line)):
- if Line[Index] == '"':
- InString = not InString
- elif Line[Index] == CommentCharacter and InString :
- pass
- elif Line[Index] == CommentCharacter and (Index +1) < len(Line) and Line[Index+1] == CommentCharacter \
- and not InString :
- return Index
- return -1
-
-## ValidateUNIFilePath
-#
-# Check the UNI file path
-#
-# @param FilePath: The UNI file path
-#
-def ValidateUNIFilePath(Path):
- Suffix = Path[Path.rfind(TAB_SPLIT):]
-
- #
- # Check if the suffix is one of the '.uni', '.UNI', '.Uni'
- #
- if Suffix not in TAB_UNI_FILE_SUFFIXS:
- Logger.Error("Unicode File Parser",
- ToolError.FORMAT_INVALID,
- Message=ST.ERR_UNI_FILE_SUFFIX_WRONG,
- ExtraData=Path)
-
- #
- # Check if '..' in the file name(without suffix)
- #
- if (TAB_SPLIT + TAB_SPLIT) in Path:
- Logger.Error("Unicode File Parser",
- ToolError.FORMAT_INVALID,
- Message=ST.ERR_UNI_FILE_NAME_INVALID,
- ExtraData=Path)
-
- #
- # Check if the file name is valid according to the DEC and INF specification
- #
- Pattern = '[a-zA-Z0-9_][a-zA-Z0-9_\-\.]*'
- FileName = Path.replace(Suffix, '')
- InvalidCh = re.sub(Pattern, '', FileName)
- if InvalidCh:
- Logger.Error("Unicode File Parser",
- ToolError.FORMAT_INVALID,
- Message=ST.ERR_INF_PARSER_FILE_NOT_EXIST_OR_NAME_INVALID,
- ExtraData=Path)
-
+## @file +# Common routines used by all tools +# +# Copyright (c) 2011 - 2019, Intel Corporation. All rights reserved.<BR> +# +# SPDX-License-Identifier: BSD-2-Clause-Patent +# + +''' +Misc +''' + +## +# Import Modules +# +import os.path +from os import access +from os import F_OK +from os import makedirs +from os import getcwd +from os import chdir +from os import listdir +from os import remove +from os import rmdir +from os import linesep +from os import walk +from os import environ +import re +from collections import OrderedDict as Sdict + +import Logger.Log as Logger +from Logger import StringTable as ST +from Logger import ToolError +from Library import GlobalData +from Library.DataType import SUP_MODULE_LIST +from Library.DataType import END_OF_LINE +from Library.DataType import TAB_SPLIT +from Library.DataType import TAB_LANGUAGE_EN_US +from Library.DataType import TAB_LANGUAGE_EN +from Library.DataType import TAB_LANGUAGE_EN_X +from Library.DataType import TAB_UNI_FILE_SUFFIXS +from Library.StringUtils import GetSplitValueList +from Library.ParserValidate import IsValidHexVersion +from Library.ParserValidate import IsValidPath +from Object.POM.CommonObject import TextObject +from Core.FileHook import __FileHookOpen__ +from Common.MultipleWorkspace import MultipleWorkspace as mws + +## Convert GUID string in xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx style to C +# structure style +# +# @param Guid: The GUID string +# +def GuidStringToGuidStructureString(Guid): + GuidList = Guid.split('-') + Result = '{' + for Index in range(0, 3, 1): + Result = Result + '0x' + GuidList[Index] + ', ' + Result = Result + '{0x' + GuidList[3][0:2] + ', 0x' + GuidList[3][2:4] + for Index in range(0, 12, 2): + Result = Result + ', 0x' + GuidList[4][Index:Index + 2] + Result += '}}' + return Result + +## Check whether GUID string is of format xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx +# +# @param GuidValue: The GUID value +# +def CheckGuidRegFormat(GuidValue): + ## Regular expression used to find out register format of GUID + # + 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*$") + + if RegFormatGuidPattern.match(GuidValue): + return True + else: + return False + + +## Convert GUID string in C structure style to +# xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx +# +# @param GuidValue: The GUID value in C structure format +# +def GuidStructureStringToGuidString(GuidValue): + GuidValueString = GuidValue.lower().replace("{", "").replace("}", "").\ + replace(" ", "").replace(";", "") + GuidValueList = GuidValueString.split(",") + if len(GuidValueList) != 11: + return '' + try: + return "%08x-%04x-%04x-%02x%02x-%02x%02x%02x%02x%02x%02x" % ( + int(GuidValueList[0], 16), + int(GuidValueList[1], 16), + int(GuidValueList[2], 16), + int(GuidValueList[3], 16), + int(GuidValueList[4], 16), + int(GuidValueList[5], 16), + int(GuidValueList[6], 16), + int(GuidValueList[7], 16), + int(GuidValueList[8], 16), + int(GuidValueList[9], 16), + int(GuidValueList[10], 16) + ) + except BaseException: + return '' + +## Create directories +# +# @param Directory: The directory name +# +def CreateDirectory(Directory): + if Directory is None or Directory.strip() == "": + return True + try: + if not access(Directory, F_OK): + makedirs(Directory) + except BaseException: + return False + return True + +## Remove directories, including files and sub-directories in it +# +# @param Directory: The directory name +# +def RemoveDirectory(Directory, Recursively=False): + if Directory is None or Directory.strip() == "" or not \ + os.path.exists(Directory): + return + if Recursively: + CurrentDirectory = getcwd() + chdir(Directory) + for File in listdir("."): + if os.path.isdir(File): + RemoveDirectory(File, Recursively) + else: + remove(File) + chdir(CurrentDirectory) + rmdir(Directory) + +## Store content in file +# +# This method is used to save file only when its content is changed. This is +# quite useful for "make" system to decide what will be re-built and what +# won't. +# +# @param File: The path of file +# @param Content: The new content of the file +# @param IsBinaryFile: The flag indicating if the file is binary file +# or not +# +def SaveFileOnChange(File, Content, IsBinaryFile=True): + if os.path.exists(File): + if IsBinaryFile: + try: + if Content == __FileHookOpen__(File, "rb").read(): + return False + except BaseException: + Logger.Error(None, ToolError.FILE_OPEN_FAILURE, ExtraData=File) + else: + try: + if Content == __FileHookOpen__(File, "r").read(): + return False + except BaseException: + Logger.Error(None, ToolError.FILE_OPEN_FAILURE, ExtraData=File) + + CreateDirectory(os.path.dirname(File)) + if IsBinaryFile: + try: + FileFd = __FileHookOpen__(File, "wb") + FileFd.write(Content) + FileFd.close() + except BaseException: + Logger.Error(None, ToolError.FILE_CREATE_FAILURE, ExtraData=File) + else: + try: + FileFd = __FileHookOpen__(File, "w") + FileFd.write(Content) + FileFd.close() + except BaseException: + Logger.Error(None, ToolError.FILE_CREATE_FAILURE, ExtraData=File) + + return True + +## Get all files of a directory +# +# @param Root: Root dir +# @param SkipList : The files need be skipped +# +def GetFiles(Root, SkipList=None, FullPath=True): + OriPath = os.path.normpath(Root) + FileList = [] + for Root, Dirs, Files in walk(Root): + if SkipList: + for Item in SkipList: + if Item in Dirs: + Dirs.remove(Item) + if Item in Files: + Files.remove(Item) + for Dir in Dirs: + if Dir.startswith('.'): + Dirs.remove(Dir) + + for File in Files: + if File.startswith('.'): + continue + File = os.path.normpath(os.path.join(Root, File)) + if not FullPath: + File = File[len(OriPath) + 1:] + FileList.append(File) + + return FileList + +## Get all non-metadata files of a directory +# +# @param Root: Root Dir +# @param SkipList : List of path need be skipped +# @param FullPath: True if the returned file should be full path +# @param PrefixPath: the path that need to be added to the files found +# @return: the list of files found +# +def GetNonMetaDataFiles(Root, SkipList, FullPath, PrefixPath): + FileList = GetFiles(Root, SkipList, FullPath) + NewFileList = [] + for File in FileList: + ExtName = os.path.splitext(File)[1] + # + # skip '.dec', '.inf', '.dsc', '.fdf' files + # + if ExtName.lower() not in ['.dec', '.inf', '.dsc', '.fdf']: + NewFileList.append(os.path.normpath(os.path.join(PrefixPath, File))) + + return NewFileList + +## Check if given file exists or not +# +# @param File: File name or path to be checked +# @param Dir: The directory the file is relative to +# +def ValidFile(File, Ext=None): + File = File.replace('\\', '/') + if Ext is not None: + FileExt = os.path.splitext(File)[1] + if FileExt.lower() != Ext.lower(): + return False + if not os.path.exists(File): + return False + return True + +## RealPath +# +# @param File: File name or path to be checked +# @param Dir: The directory the file is relative to +# @param OverrideDir: The override directory +# +def RealPath(File, Dir='', OverrideDir=''): + NewFile = os.path.normpath(os.path.join(Dir, File)) + NewFile = GlobalData.gALL_FILES[NewFile] + if not NewFile and OverrideDir: + NewFile = os.path.normpath(os.path.join(OverrideDir, File)) + NewFile = GlobalData.gALL_FILES[NewFile] + return NewFile + +## RealPath2 +# +# @param File: File name or path to be checked +# @param Dir: The directory the file is relative to +# @param OverrideDir: The override directory +# +def RealPath2(File, Dir='', OverrideDir=''): + if OverrideDir: + NewFile = GlobalData.gALL_FILES[os.path.normpath(os.path.join\ + (OverrideDir, File))] + if NewFile: + if OverrideDir[-1] == os.path.sep: + return NewFile[len(OverrideDir):], NewFile[0:len(OverrideDir)] + else: + return NewFile[len(OverrideDir) + 1:], \ + NewFile[0:len(OverrideDir)] + + NewFile = GlobalData.gALL_FILES[os.path.normpath(os.path.join(Dir, File))] + if NewFile: + if Dir: + if Dir[-1] == os.path.sep: + return NewFile[len(Dir):], NewFile[0:len(Dir)] + else: + return NewFile[len(Dir) + 1:], NewFile[0:len(Dir)] + else: + return NewFile, '' + + return None, None + +## CommonPath +# +# @param PathList: PathList +# +def CommonPath(PathList): + Path1 = min(PathList).split(os.path.sep) + Path2 = max(PathList).split(os.path.sep) + for Index in range(min(len(Path1), len(Path2))): + if Path1[Index] != Path2[Index]: + return os.path.sep.join(Path1[:Index]) + return os.path.sep.join(Path1) + +## PathClass +# +class PathClass(object): + def __init__(self, File='', Root='', AlterRoot='', Type='', IsBinary=False, + Arch='COMMON', ToolChainFamily='', Target='', TagName='', \ + ToolCode=''): + self.Arch = Arch + self.File = str(File) + if os.path.isabs(self.File): + self.Root = '' + self.AlterRoot = '' + else: + self.Root = str(Root) + self.AlterRoot = str(AlterRoot) + + # + # Remove any '.' and '..' in path + # + if self.Root: + self.Path = os.path.normpath(os.path.join(self.Root, self.File)) + self.Root = os.path.normpath(CommonPath([self.Root, self.Path])) + # + # eliminate the side-effect of 'C:' + # + if self.Root[-1] == ':': + self.Root += os.path.sep + # + # file path should not start with path separator + # + if self.Root[-1] == os.path.sep: + self.File = self.Path[len(self.Root):] + else: + self.File = self.Path[len(self.Root) + 1:] + else: + self.Path = os.path.normpath(self.File) + + self.SubDir, self.Name = os.path.split(self.File) + self.BaseName, self.Ext = os.path.splitext(self.Name) + + if self.Root: + if self.SubDir: + self.Dir = os.path.join(self.Root, self.SubDir) + else: + self.Dir = self.Root + else: + self.Dir = self.SubDir + + if IsBinary: + self.Type = Type + else: + self.Type = self.Ext.lower() + + self.IsBinary = IsBinary + self.Target = Target + self.TagName = TagName + self.ToolCode = ToolCode + self.ToolChainFamily = ToolChainFamily + + self._Key = None + + ## Convert the object of this class to a string + # + # Convert member Path of the class to a string + # + def __str__(self): + return self.Path + + ## Override __eq__ function + # + # Check whether PathClass are the same + # + def __eq__(self, Other): + if isinstance(Other, type(self)): + return self.Path == Other.Path + else: + return self.Path == str(Other) + + ## Override __hash__ function + # + # Use Path as key in hash table + # + def __hash__(self): + return hash(self.Path) + + ## _GetFileKey + # + def _GetFileKey(self): + if self._Key is None: + self._Key = self.Path.upper() + return self._Key + ## Validate + # + def Validate(self, Type='', CaseSensitive=True): + if GlobalData.gCASE_INSENSITIVE: + CaseSensitive = False + if Type and Type.lower() != self.Type: + return ToolError.FILE_TYPE_MISMATCH, '%s (expect %s but got %s)' % \ + (self.File, Type, self.Type) + + RealFile, RealRoot = RealPath2(self.File, self.Root, self.AlterRoot) + if not RealRoot and not RealFile: + RealFile = self.File + if self.AlterRoot: + RealFile = os.path.join(self.AlterRoot, self.File) + elif self.Root: + RealFile = os.path.join(self.Root, self.File) + return ToolError.FILE_NOT_FOUND, os.path.join(self.AlterRoot, RealFile) + + ErrorCode = 0 + ErrorInfo = '' + if RealRoot != self.Root or RealFile != self.File: + if CaseSensitive and (RealFile != self.File or \ + (RealRoot != self.Root and RealRoot != \ + self.AlterRoot)): + ErrorCode = ToolError.FILE_CASE_MISMATCH + ErrorInfo = self.File + '\n\t' + RealFile + \ + " [in file system]" + + self.SubDir, self.Name = os.path.split(RealFile) + self.BaseName, self.Ext = os.path.splitext(self.Name) + if self.SubDir: + self.Dir = os.path.join(RealRoot, self.SubDir) + else: + self.Dir = RealRoot + self.File = RealFile + self.Root = RealRoot + self.Path = os.path.join(RealRoot, RealFile) + return ErrorCode, ErrorInfo + + Key = property(_GetFileKey) + +## Get current workspace +# +# get WORKSPACE from environment variable if present,if not use current working directory as WORKSPACE +# +def GetWorkspace(): + # + # check WORKSPACE + # + if "WORKSPACE" in environ: + WorkspaceDir = os.path.normpath(environ["WORKSPACE"]) + if not os.path.exists(WorkspaceDir): + Logger.Error("UPT", + ToolError.UPT_ENVIRON_MISSING_ERROR, + ST.ERR_WORKSPACE_NOTEXIST, + ExtraData="%s" % WorkspaceDir) + else: + WorkspaceDir = os.getcwd() + + if WorkspaceDir[-1] == ':': + WorkspaceDir += os.sep + + PackagesPath = os.environ.get("PACKAGES_PATH") + mws.setWs(WorkspaceDir, PackagesPath) + + return WorkspaceDir, mws.PACKAGES_PATH + +## Get relative path +# +# use full path and workspace to get relative path +# the destination of this function is mainly to resolve the root path issue(like c: or c:\) +# +# @param Fullpath: a string of fullpath +# @param Workspace: a string of workspace +# +def GetRelativePath(Fullpath, Workspace): + + RelativePath = '' + if Workspace.endswith(os.sep): + RelativePath = Fullpath[Fullpath.upper().find(Workspace.upper())+len(Workspace):] + else: + RelativePath = Fullpath[Fullpath.upper().find(Workspace.upper())+len(Workspace)+1:] + + return RelativePath + +## Check whether all module types are in list +# +# check whether all module types (SUP_MODULE_LIST) are in list +# +# @param ModuleList: a list of ModuleType +# +def IsAllModuleList(ModuleList): + NewModuleList = [Module.upper() for Module in ModuleList] + for Module in SUP_MODULE_LIST: + if Module not in NewModuleList: + return False + else: + return True + +## Dictionary that use comment(GenericComment, TailComment) as value, +# if a new comment which key already in the dic is inserted, then the +# comment will be merged. +# Key is (Statement, SupArch), when TailComment is added, it will ident +# according to Statement +# +class MergeCommentDict(dict): + ## []= operator + # + def __setitem__(self, Key, CommentVal): + GenericComment, TailComment = CommentVal + if Key in self: + OrigVal1, OrigVal2 = dict.__getitem__(self, Key) + Statement = Key[0] + dict.__setitem__(self, Key, (OrigVal1 + GenericComment, OrigVal2 \ + + len(Statement) * ' ' + TailComment)) + else: + dict.__setitem__(self, Key, (GenericComment, TailComment)) + + ## =[] operator + # + def __getitem__(self, Key): + return dict.__getitem__(self, Key) + + +## GenDummyHelpTextObj +# +# @retval HelpTxt: Generated dummy help text object +# +def GenDummyHelpTextObj(): + HelpTxt = TextObject() + HelpTxt.SetLang(TAB_LANGUAGE_EN_US) + HelpTxt.SetString(' ') + return HelpTxt + +## ConvertVersionToDecimal, the minor version should be within 0 - 99 +# <HexVersion> ::= "0x" <Major> <Minor> +# <Major> ::= (a-fA-F0-9){4} +# <Minor> ::= (a-fA-F0-9){4} +# <DecVersion> ::= (0-65535) ["." (0-99)] +# +# @param StringIn: The string contains version defined in INF file. +# It can be Decimal or Hex +# +def ConvertVersionToDecimal(StringIn): + if IsValidHexVersion(StringIn): + Value = int(StringIn, 16) + Major = Value >> 16 + Minor = Value & 0xFFFF + MinorStr = str(Minor) + if len(MinorStr) == 1: + MinorStr = '0' + MinorStr + return str(Major) + '.' + MinorStr + else: + if StringIn.find(TAB_SPLIT) != -1: + return StringIn + elif StringIn: + return StringIn + '.0' + else: + # + # when StringIn is '', return it directly + # + return StringIn + +## GetHelpStringByRemoveHashKey +# +# Remove hash key at the header of string and return the remain. +# +# @param String: The string need to be processed. +# +def GetHelpStringByRemoveHashKey(String): + ReturnString = '' + PattenRemoveHashKey = re.compile(r"^[#+\s]+", re.DOTALL) + String = String.strip() + if String == '': + return String + + LineList = GetSplitValueList(String, END_OF_LINE) + for Line in LineList: + ValueList = PattenRemoveHashKey.split(Line) + if len(ValueList) == 1: + ReturnString += ValueList[0] + END_OF_LINE + else: + ReturnString += ValueList[1] + END_OF_LINE + + if ReturnString.endswith('\n') and not ReturnString.endswith('\n\n') and ReturnString != '\n': + ReturnString = ReturnString[:-1] + + return ReturnString + +## ConvPathFromAbsToRel +# +# Get relative file path from absolute path. +# +# @param Path: The string contain file absolute path. +# @param Root: The string contain the parent path of Path in. +# +# +def ConvPathFromAbsToRel(Path, Root): + Path = os.path.normpath(Path) + Root = os.path.normpath(Root) + FullPath = os.path.normpath(os.path.join(Root, Path)) + + # + # If Path is absolute path. + # It should be in Root. + # + if os.path.isabs(Path): + return FullPath[FullPath.find(Root) + len(Root) + 1:] + + else: + return Path + +## ConvertPath +# +# Convert special characters to '_', '\' to '/' +# return converted path: Test!1.inf -> Test_1.inf +# +# @param Path: Path to be converted +# +def ConvertPath(Path): + RetPath = '' + for Char in Path.strip(): + if Char.isalnum() or Char in '.-_/': + RetPath = RetPath + Char + elif Char == '\\': + RetPath = RetPath + '/' + else: + RetPath = RetPath + '_' + return RetPath + +## ConvertSpec +# +# during install, convert the Spec string extract from UPD into INF allowable definition, +# the difference is period is allowed in the former (not the first letter) but not in the latter. +# return converted Spec string +# +# @param SpecStr: SpecStr to be converted +# +def ConvertSpec(SpecStr): + RetStr = '' + for Char in SpecStr: + if Char.isalnum() or Char == '_': + RetStr = RetStr + Char + else: + RetStr = RetStr + '_' + + return RetStr + + +## IsEqualList +# +# Judge two lists are identical(contain same item). +# The rule is elements in List A are in List B and elements in List B are in List A. +# +# @param ListA, ListB Lists need to be judged. +# +# @return True ListA and ListB are identical +# @return False ListA and ListB are different with each other +# +def IsEqualList(ListA, ListB): + if ListA == ListB: + return True + + for ItemA in ListA: + if not ItemA in ListB: + return False + + for ItemB in ListB: + if not ItemB in ListA: + return False + + return True + +## ConvertArchList +# +# Convert item in ArchList if the start character is lower case. +# In UDP spec, Arch is only allowed as: [A-Z]([a-zA-Z0-9])* +# +# @param ArchList The ArchList need to be converted. +# +# @return NewList The ArchList been converted. +# +def ConvertArchList(ArchList): + NewArchList = [] + if not ArchList: + return NewArchList + + if isinstance(ArchList, list): + for Arch in ArchList: + Arch = Arch.upper() + NewArchList.append(Arch) + elif isinstance(ArchList, str): + ArchList = ArchList.upper() + NewArchList.append(ArchList) + + return NewArchList + +## ProcessLineExtender +# +# Process the LineExtender of Line in LineList. +# If one line ends with a line extender, then it will be combined together with next line. +# +# @param LineList The LineList need to be processed. +# +# @return NewList The ArchList been processed. +# +def ProcessLineExtender(LineList): + NewList = [] + Count = 0 + while Count < len(LineList): + if LineList[Count].strip().endswith("\\") and Count + 1 < len(LineList): + NewList.append(LineList[Count].strip()[:-2] + LineList[Count + 1]) + Count = Count + 1 + else: + NewList.append(LineList[Count]) + + Count = Count + 1 + + return NewList + +## ProcessEdkComment +# +# Process EDK style comment in LineList: c style /* */ comment or cpp style // comment +# +# +# @param LineList The LineList need to be processed. +# +# @return LineList The LineList been processed. +# @return FirstPos Where Edk comment is first found, -1 if not found +# +def ProcessEdkComment(LineList): + FindEdkBlockComment = False + Count = 0 + StartPos = -1 + EndPos = -1 + FirstPos = -1 + + while(Count < len(LineList)): + Line = LineList[Count].strip() + if Line.startswith("/*"): + # + # handling c style comment + # + StartPos = Count + while Count < len(LineList): + Line = LineList[Count].strip() + if Line.endswith("*/"): + if (Count == StartPos) and Line.strip() == '/*/': + Count = Count + 1 + continue + EndPos = Count + FindEdkBlockComment = True + break + Count = Count + 1 + + if FindEdkBlockComment: + if FirstPos == -1: + FirstPos = StartPos + for Index in range(StartPos, EndPos+1): + LineList[Index] = '' + FindEdkBlockComment = False + elif Line.find("//") != -1 and not Line.startswith("#"): + # + # handling cpp style comment + # + LineList[Count] = Line.replace("//", '#') + if FirstPos == -1: + FirstPos = Count + + Count = Count + 1 + + return LineList, FirstPos + +## 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): + + FileGuidString = "" + VerString = "" + + OriginalString = String + String = String.strip() + if not String: + return None, None + # + # Remove "#" characters at the beginning + # + String = GetHelpStringByRemoveHashKey(String) + String = String.strip() + + # + # Validate file name exist. + # + FullFileName = os.path.normpath(os.path.realpath(os.path.join(WorkSpace, String))) + if not (ValidFile(FullFileName)): + Logger.Error("InfParser", + ToolError.FORMAT_INVALID, + ST.ERR_FILELIST_EXIST % (String), + File=GlobalData.gINF_MODULE_NAME, + Line=LineNo, + ExtraData=OriginalString) + + # + # Validate file exist/format. + # + if IsValidPath(String, WorkSpace): + IsValidFileFlag = True + else: + Logger.Error("InfParser", + ToolError.FORMAT_INVALID, + ST.ERR_INF_PARSER_FILE_NOT_EXIST_OR_NAME_INVALID % (String), + File=GlobalData.gINF_MODULE_NAME, + Line=LineNo, + ExtraData=OriginalString) + return False + if IsValidFileFlag: + FileLinesList = [] + + try: + FInputfile = open(FullFileName, "r") + try: + FileLinesList = FInputfile.readlines() + except BaseException: + Logger.Error("InfParser", + ToolError.FILE_READ_FAILURE, + ST.ERR_FILE_OPEN_FAILURE, + File=FullFileName) + finally: + FInputfile.close() + except BaseException: + Logger.Error("InfParser", + ToolError.FILE_READ_FAILURE, + ST.ERR_FILE_OPEN_FAILURE, + File=FullFileName) + + ReFileGuidPattern = re.compile("^\s*FILE_GUID\s*=.*$") + ReVerStringPattern = re.compile("^\s*VERSION_STRING\s*=.*$") + + FileLinesList = ProcessLineExtender(FileLinesList) + + for Line in FileLinesList: + if ReFileGuidPattern.match(Line): + FileGuidString = Line + if ReVerStringPattern.match(Line): + VerString = Line + + if FileGuidString: + FileGuidString = GetSplitValueList(FileGuidString, '=', 1)[1] + if VerString: + VerString = GetSplitValueList(VerString, '=', 1)[1] + + return FileGuidString, VerString + +## GetLocalValue +# +# Generate the local value for INF and DEC file. If Lang attribute not present, then use this value. +# If present, and there is no element without the Lang attribute, and one of the elements has the rfc1766 code is +# "en-x-tianocore", or "en-US" if "en-x-tianocore" was not found, or "en" if "en-US" was not found, or startswith 'en' +# if 'en' was not found, then use this value. +# If multiple entries of a tag exist which have the same language code, use the last entry. +# +# @param ValueList A list need to be processed. +# @param UseFirstValue: True to use the first value, False to use the last value +# +# @return LocalValue +def GetLocalValue(ValueList, UseFirstValue=False): + Value1 = '' + Value2 = '' + Value3 = '' + Value4 = '' + Value5 = '' + for (Key, Value) in ValueList: + if Key == TAB_LANGUAGE_EN_X: + if UseFirstValue: + if not Value1: + Value1 = Value + else: + Value1 = Value + if Key == TAB_LANGUAGE_EN_US: + if UseFirstValue: + if not Value2: + Value2 = Value + else: + Value2 = Value + if Key == TAB_LANGUAGE_EN: + if UseFirstValue: + if not Value3: + Value3 = Value + else: + Value3 = Value + if Key.startswith(TAB_LANGUAGE_EN): + if UseFirstValue: + if not Value4: + Value4 = Value + else: + Value4 = Value + if Key == '': + if UseFirstValue: + if not Value5: + Value5 = Value + else: + Value5 = Value + + if Value1: + return Value1 + if Value2: + return Value2 + if Value3: + return Value3 + if Value4: + return Value4 + if Value5: + return Value5 + + return '' + + +## GetCharIndexOutStr +# +# Get comment character index outside a string +# +# @param Line: The string to be checked +# @param CommentCharacter: Comment char, used to ignore comment content +# +# @retval Index +# +def GetCharIndexOutStr(CommentCharacter, Line): + # + # remove whitespace + # + Line = Line.strip() + + # + # Check whether comment character is in a string + # + InString = False + for Index in range(0, len(Line)): + if Line[Index] == '"': + InString = not InString + elif Line[Index] == CommentCharacter and InString : + pass + elif Line[Index] == CommentCharacter and (Index +1) < len(Line) and Line[Index+1] == CommentCharacter \ + and not InString : + return Index + return -1 + +## ValidateUNIFilePath +# +# Check the UNI file path +# +# @param FilePath: The UNI file path +# +def ValidateUNIFilePath(Path): + Suffix = Path[Path.rfind(TAB_SPLIT):] + + # + # Check if the suffix is one of the '.uni', '.UNI', '.Uni' + # + if Suffix not in TAB_UNI_FILE_SUFFIXS: + Logger.Error("Unicode File Parser", + ToolError.FORMAT_INVALID, + Message=ST.ERR_UNI_FILE_SUFFIX_WRONG, + ExtraData=Path) + + # + # Check if '..' in the file name(without suffix) + # + if (TAB_SPLIT + TAB_SPLIT) in Path: + Logger.Error("Unicode File Parser", + ToolError.FORMAT_INVALID, + Message=ST.ERR_UNI_FILE_NAME_INVALID, + ExtraData=Path) + + # + # Check if the file name is valid according to the DEC and INF specification + # + Pattern = '[a-zA-Z0-9_][a-zA-Z0-9_\-\.]*' + FileName = Path.replace(Suffix, '') + InvalidCh = re.sub(Pattern, '', FileName) + if InvalidCh: + Logger.Error("Unicode File Parser", + ToolError.FORMAT_INVALID, + Message=ST.ERR_INF_PARSER_FILE_NOT_EXIST_OR_NAME_INVALID, + ExtraData=Path) + diff --git a/BaseTools/Source/Python/UPT/Library/ParserValidate.py b/BaseTools/Source/Python/UPT/Library/ParserValidate.py index 62f406141c..233405832e 100644 --- a/BaseTools/Source/Python/UPT/Library/ParserValidate.py +++ b/BaseTools/Source/Python/UPT/Library/ParserValidate.py @@ -1,727 +1,727 @@ -## @file ParserValidate.py
-# Functions for parser validation
-#
-# Copyright (c) 2011 - 2018, Intel Corporation. All rights reserved.<BR>
-#
-# SPDX-License-Identifier: BSD-2-Clause-Patent
-#
-
-'''
-ParserValidate
-'''
-
-import os.path
-import re
-import platform
-
-from Library.DataType import MODULE_LIST
-from Library.DataType import COMPONENT_TYPE_LIST
-from Library.DataType import PCD_USAGE_TYPE_LIST_OF_MODULE
-from Library.DataType import TAB_SPACE_SPLIT
-from Library.StringUtils import GetSplitValueList
-from Library.ExpressionValidate import IsValidBareCString
-from Library.ExpressionValidate import IsValidFeatureFlagExp
-from Common.MultipleWorkspace import MultipleWorkspace as mws
-
-## __HexDigit() method
-#
-# Whether char input is a Hex data bit
-#
-# @param TempChar: The char to test
-#
-def __HexDigit(TempChar):
- if (TempChar >= 'a' and TempChar <= 'f') or \
- (TempChar >= 'A' and TempChar <= 'F') \
- or (TempChar >= '0' and TempChar <= '9'):
- return True
- else:
- return False
-
-## IsValidHex() method
-#
-# Whether char input is a Hex data.
-#
-# @param TempChar: The char to test
-#
-def IsValidHex(HexStr):
- if not HexStr.upper().startswith("0X"):
- return False
- CharList = [c for c in HexStr[2:] if not __HexDigit(c)]
- if len(CharList) == 0:
- return True
- else:
- return False
-
-## Judge the input string is valid bool type or not.
-#
-# <TRUE> ::= {"TRUE"} {"true"} {"True"} {"0x1"} {"0x01"}
-# <FALSE> ::= {"FALSE"} {"false"} {"False"} {"0x0"} {"0x00"}
-# <BoolType> ::= {<TRUE>} {<FALSE>}
-#
-# @param BoolString: A string contained the value need to be judged.
-#
-def IsValidBoolType(BoolString):
- #
- # Valid True
- #
- if BoolString == 'TRUE' or \
- BoolString == 'True' or \
- BoolString == 'true' or \
- BoolString == '0x1' or \
- BoolString == '0x01':
- return True
- #
- # Valid False
- #
- elif BoolString == 'FALSE' or \
- BoolString == 'False' or \
- BoolString == 'false' or \
- BoolString == '0x0' or \
- BoolString == '0x00':
- return True
- #
- # Invalid bool type
- #
- else:
- return False
-
-## Is Valid Module Type List or not
-#
-# @param ModuleTypeList: A list contain ModuleType strings need to be
-# judged.
-#
-def IsValidInfMoudleTypeList(ModuleTypeList):
- for ModuleType in ModuleTypeList:
- return IsValidInfMoudleType(ModuleType)
-
-## Is Valid Module Type or not
-#
-# @param ModuleType: A string contain ModuleType need to be judged.
-#
-def IsValidInfMoudleType(ModuleType):
- if ModuleType in MODULE_LIST:
- return True
- else:
- return False
-
-## Is Valid Component Type or not
-#
-# @param ComponentType: A string contain ComponentType need to be judged.
-#
-def IsValidInfComponentType(ComponentType):
- if ComponentType.upper() in COMPONENT_TYPE_LIST:
- return True
- else:
- return False
-
-
-## Is valid Tool Family or not
-#
-# @param ToolFamily: A string contain Tool Family need to be judged.
-# Family := [A-Z]([a-zA-Z0-9])*
-#
-def IsValidToolFamily(ToolFamily):
- ReIsValidFamily = re.compile(r"^[A-Z]+[A-Za-z0-9]{0,}$", re.DOTALL)
- if ReIsValidFamily.match(ToolFamily) is None:
- return False
- return True
-
-## Is valid Tool TagName or not
-#
-# The TagName sample is MYTOOLS and VS2005.
-#
-# @param TagName: A string contain Tool TagName need to be judged.
-#
-def IsValidToolTagName(TagName):
- if TagName.strip() == '':
- return True
- if TagName.strip() == '*':
- return True
- if not IsValidWord(TagName):
- return False
- return True
-
-## Is valid arch or not
-#
-# @param Arch The arch string need to be validated
-# <OA> ::= (a-zA-Z)(A-Za-z0-9){0,}
-# <arch> ::= {"IA32"} {"X64"} {"IPF"} {"EBC"} {<OA>}
-# {"common"}
-# @param Arch: Input arch
-#
-def IsValidArch(Arch):
- if Arch == 'common':
- return True
- ReIsValidArch = re.compile(r"^[a-zA-Z]+[a-zA-Z0-9]{0,}$", re.DOTALL)
- if ReIsValidArch.match(Arch) is None:
- return False
- return True
-
-## Is valid family or not
-#
-# <Family> ::= {"MSFT"} {"GCC"} {"INTEL"} {<Usr>} {"*"}
-# <Usr> ::= [A-Z][A-Za-z0-9]{0,}
-#
-# @param family: The family string need to be validated
-#
-def IsValidFamily(Family):
- Family = Family.strip()
- if Family == '*':
- return True
-
- if Family == '':
- return True
-
- ReIsValidFamily = re.compile(r"^[A-Z]+[A-Za-z0-9]{0,}$", re.DOTALL)
- if ReIsValidFamily.match(Family) is None:
- return False
- return True
-
-## Is valid build option name or not
-#
-# @param BuildOptionName: The BuildOptionName string need to be validated
-#
-def IsValidBuildOptionName(BuildOptionName):
- if not BuildOptionName:
- return False
-
- ToolOptionList = GetSplitValueList(BuildOptionName, '_', 4)
-
- if len(ToolOptionList) != 5:
- return False
-
- ReIsValidBuildOption1 = re.compile(r"^\s*(\*)|([A-Z][a-zA-Z0-9]*)$")
- ReIsValidBuildOption2 = re.compile(r"^\s*(\*)|([a-zA-Z][a-zA-Z0-9]*)$")
-
- if ReIsValidBuildOption1.match(ToolOptionList[0]) is None:
- return False
-
- if ReIsValidBuildOption1.match(ToolOptionList[1]) is None:
- return False
-
- if ReIsValidBuildOption2.match(ToolOptionList[2]) is None:
- return False
-
- if ToolOptionList[3] == "*" and ToolOptionList[4] not in ['FAMILY', 'DLL', 'DPATH']:
- return False
-
- return True
-
-## IsValidToken
-#
-# Check if pattern string matches total token
-#
-# @param ReString: regular string
-# @param Token: Token to be matched
-#
-def IsValidToken(ReString, Token):
- Match = re.compile(ReString).match(Token)
- return Match and Match.start() == 0 and Match.end() == len(Token)
-
-## IsValidPath
-#
-# Check if path exist
-#
-# @param Path: Absolute path or relative path to be checked
-# @param Root: Root path
-#
-def IsValidPath(Path, Root):
- Path = Path.strip()
- OrigPath = Path.replace('\\', '/')
-
- Path = os.path.normpath(Path).replace('\\', '/')
- Root = os.path.normpath(Root).replace('\\', '/')
- FullPath = mws.join(Root, Path)
-
- if not os.path.exists(FullPath):
- return False
-
- #
- # If Path is absolute path.
- # It should be in Root.
- #
- if os.path.isabs(Path):
- if not Path.startswith(Root):
- return False
- return True
-
- #
- # Check illegal character
- #
- for Rel in ['/', './', '../']:
- if OrigPath.startswith(Rel):
- return False
- for Rel in ['//', '/./', '/../']:
- if Rel in OrigPath:
- return False
- for Rel in ['/.', '/..', '/']:
- if OrigPath.endswith(Rel):
- return False
-
- Path = Path.rstrip('/')
-
- #
- # Check relative path
- #
- for Word in Path.split('/'):
- if not IsValidWord(Word):
- return False
-
- return True
-
-## IsValidInstallPath
-#
-# Check if an install path valid or not.
-#
-# Absolute path or path starts with '.' or path contains '..' are invalid.
-#
-# @param Path: path to be checked
-#
-def IsValidInstallPath(Path):
- if platform.platform().find("Windows") >= 0:
- if os.path.isabs(Path):
- return False
- else:
- if Path[1:2] == ':':
- return False
- if os.path.isabs(Path):
- return False
- if Path.startswith('.'):
- return False
-
- if Path.find('..') != -1:
- return False
-
- return True
-
-
-## IsValidCFormatGuid
-#
-# Check if GUID format has the from of {8,4,4,{2,2,2,2,2,2,2,2}}
-#
-# @param Guid: Guid to be checked
-#
-def IsValidCFormatGuid(Guid):
- #
- # Valid: { 0xf0b11735, 0x87a0, 0x4193, {0xb2, 0x66, 0x53, 0x8c, 0x38,
- # 0xaf, 0x48, 0xce }}
- # Invalid: { 0xf0b11735, 0x87a0, 0x4193, {0xb2, 0x66, 0x53, 0x8c, 0x38,
- # 0xaf, 0x48, 0xce }} 0x123
- # Invalid: { 0xf0b1 1735, 0x87a0, 0x4193, {0xb2, 0x66, 0x53, 0x8c, 0x38,
- # 0xaf, 0x48, 0xce }}
- #
- List = ['{', 10, ',', 6, ',', 6, ',{', 4, ',', 4, ',', 4,
- ',', 4, ',', 4, ',', 4, ',', 4, ',', 4, '}}']
- Index = 0
- Value = ''
- SepValue = ''
- for Char in Guid:
- if Char not in '{},\t ':
- Value += Char
- continue
- if Value:
- try:
- #
- # Index may out of bound
- #
- if not SepValue or SepValue != List[Index]:
- return False
- Index += 1
- SepValue = ''
-
- if not Value.startswith('0x') and not Value.startswith('0X'):
- return False
-
- #
- # Index may out of bound
- #
- if not isinstance(List[Index], type(1)) or \
- len(Value) > List[Index] or len(Value) < 3:
- return False
-
- #
- # Check if string can be converted to integer
- # Throw exception if not
- #
- int(Value, 16)
- except BaseException:
- #
- # Exception caught means invalid format
- #
- return False
- Value = ''
- Index += 1
- if Char in '{},':
- SepValue += Char
-
- return SepValue == '}}' and Value == ''
-
-## IsValidPcdType
-#
-# Check whether the PCD type is valid
-#
-# @param PcdTypeString: The PcdType string need to be checked.
-#
-def IsValidPcdType(PcdTypeString):
- if PcdTypeString.upper() in PCD_USAGE_TYPE_LIST_OF_MODULE:
- return True
- else:
- return False
-
-## IsValidWord
-#
-# Check whether the word is valid.
-# <Word> ::= (a-zA-Z0-9_)(a-zA-Z0-9_-){0,} Alphanumeric characters with
-# optional
-# dash "-" and/or underscore "_" characters. No whitespace
-# characters are permitted.
-#
-# @param Word: The word string need to be checked.
-#
-def IsValidWord(Word):
- if not Word:
- return False
- #
- # The first char should be alpha, _ or Digit.
- #
- if not Word[0].isalnum() and \
- not Word[0] == '_' and \
- not Word[0].isdigit():
- return False
-
- LastChar = ''
- for Char in Word[1:]:
- if (not Char.isalpha()) and \
- (not Char.isdigit()) and \
- Char != '-' and \
- Char != '_' and \
- Char != '.':
- return False
- if Char == '.' and LastChar == '.':
- return False
- LastChar = Char
-
- return True
-
-
-## IsValidSimpleWord
-#
-# Check whether the SimpleWord is valid.
-# <SimpleWord> ::= (a-zA-Z0-9)(a-zA-Z0-9_-){0,}
-# A word that cannot contain a period character.
-#
-# @param Word: The word string need to be checked.
-#
-def IsValidSimpleWord(Word):
- ReIsValidSimpleWord = \
- re.compile(r"^[0-9A-Za-z][0-9A-Za-z\-_]*$", re.DOTALL)
- Word = Word.strip()
- if not Word:
- return False
-
- if not ReIsValidSimpleWord.match(Word):
- return False
-
- return True
-
-## IsValidDecVersion
-#
-# Check whether the decimal version is valid.
-# <DecVersion> ::= (0-9){1,} ["." (0-9){1,}]
-#
-# @param Word: The word string need to be checked.
-#
-def IsValidDecVersion(Word):
- if Word.find('.') > -1:
- ReIsValidDecVersion = re.compile(r"[0-9]+\.?[0-9]+$")
- else:
- ReIsValidDecVersion = re.compile(r"[0-9]+$")
- if ReIsValidDecVersion.match(Word) is None:
- return False
- return True
-
-## IsValidHexVersion
-#
-# Check whether the hex version is valid.
-# <HexVersion> ::= "0x" <Major> <Minor>
-# <Major> ::= <HexDigit>{4}
-# <Minor> ::= <HexDigit>{4}
-#
-# @param Word: The word string need to be checked.
-#
-def IsValidHexVersion(Word):
- ReIsValidHexVersion = re.compile(r"[0][xX][0-9A-Fa-f]{8}$", re.DOTALL)
- if ReIsValidHexVersion.match(Word) is None:
- return False
-
- return True
-
-## IsValidBuildNumber
-#
-# Check whether the BUILD_NUMBER is valid.
-# ["BUILD_NUMBER" "=" <Integer>{1,4} <EOL>]
-#
-# @param Word: The BUILD_NUMBER string need to be checked.
-#
-def IsValidBuildNumber(Word):
- ReIsValieBuildNumber = re.compile(r"[0-9]{1,4}$", re.DOTALL)
- if ReIsValieBuildNumber.match(Word) is None:
- return False
-
- return True
-
-## IsValidDepex
-#
-# Check whether the Depex is valid.
-#
-# @param Word: The Depex string need to be checked.
-#
-def IsValidDepex(Word):
- Index = Word.upper().find("PUSH")
- if Index > -1:
- return IsValidCFormatGuid(Word[Index+4:].strip())
-
- ReIsValidCName = re.compile(r"^[A-Za-z_][0-9A-Za-z_\s\.]*$", re.DOTALL)
- if ReIsValidCName.match(Word) is None:
- return False
-
- return True
-
-## IsValidNormalizedString
-#
-# Check
-# <NormalizedString> ::= <DblQuote> [{<Word>} {<Space>}]{1,} <DblQuote>
-# <Space> ::= 0x20
-#
-# @param String: string to be checked
-#
-def IsValidNormalizedString(String):
- if String == '':
- return True
-
- for Char in String:
- if Char == '\t':
- return False
-
- StringList = GetSplitValueList(String, TAB_SPACE_SPLIT)
-
- for Item in StringList:
- if not Item:
- continue
- if not IsValidWord(Item):
- return False
-
- return True
-
-## IsValidIdString
-#
-# Check whether the IdString is valid.
-#
-# @param IdString: The IdString need to be checked.
-#
-def IsValidIdString(String):
- if IsValidSimpleWord(String.strip()):
- return True
-
- if String.strip().startswith('"') and \
- String.strip().endswith('"'):
- String = String[1:-1]
- if String.strip() == "":
- return True
- if IsValidNormalizedString(String):
- return True
-
- return False
-
-## IsValidVersionString
-#
-# Check whether the VersionString is valid.
-# <AsciiString> ::= [ [<WhiteSpace>]{0,} [<AsciiChars>]{0,} ] {0,}
-# <WhiteSpace> ::= {<Tab>} {<Space>}
-# <Tab> ::= 0x09
-# <Space> ::= 0x20
-# <AsciiChars> ::= (0x21 - 0x7E)
-#
-# @param VersionString: The VersionString need to be checked.
-#
-def IsValidVersionString(VersionString):
- VersionString = VersionString.strip()
- for Char in VersionString:
- if not (Char >= 0x21 and Char <= 0x7E):
- return False
-
- return True
-
-## IsValidPcdValue
-#
-# Check whether the PcdValue is valid.
-#
-# @param VersionString: The PcdValue need to be checked.
-#
-def IsValidPcdValue(PcdValue):
- for Char in PcdValue:
- if Char == '\n' or Char == '\t' or Char == '\f':
- return False
-
- #
- # <Boolean>
- #
- if IsValidFeatureFlagExp(PcdValue, True)[0]:
- return True
-
- #
- # <Number> ::= {<Integer>} {<HexNumber>}
- # <Integer> ::= {(0-9)} {(1-9)(0-9){1,}}
- # <HexNumber> ::= "0x" <HexDigit>{1,}
- # <HexDigit> ::= (a-fA-F0-9)
- #
- if IsValidHex(PcdValue):
- return True
-
- ReIsValidIntegerSingle = re.compile(r"^\s*[0-9]\s*$", re.DOTALL)
- if ReIsValidIntegerSingle.match(PcdValue) is not None:
- return True
-
- ReIsValidIntegerMulti = re.compile(r"^\s*[1-9][0-9]+\s*$", re.DOTALL)
- if ReIsValidIntegerMulti.match(PcdValue) is not None:
- return True
-
- #
- # <StringVal> ::= {<StringType>} {<Array>} {"$(" <MACRO> ")"}
- # <StringType> ::= {<UnicodeString>} {<CString>}
- #
- ReIsValidStringType = re.compile(r"^\s*[\"L].*[\"]\s*$")
- if ReIsValidStringType.match(PcdValue):
- IsTrue = False
- if PcdValue.strip().startswith('L\"'):
- StringValue = PcdValue.strip().lstrip('L\"').rstrip('\"')
- if IsValidBareCString(StringValue):
- IsTrue = True
- elif PcdValue.strip().startswith('\"'):
- StringValue = PcdValue.strip().lstrip('\"').rstrip('\"')
- if IsValidBareCString(StringValue):
- IsTrue = True
- if IsTrue:
- return IsTrue
-
- #
- # <Array> ::= {<CArray>} {<NList>} {<CFormatGUID>}
- # <CArray> ::= "{" [<NList>] <CArray>{0,} "}"
- # <NList> ::= <HexByte> ["," <HexByte>]{0,}
- # <HexDigit> ::= (a-fA-F0-9)
- # <HexByte> ::= "0x" <HexDigit>{1,2}
- #
- if IsValidCFormatGuid(PcdValue):
- return True
-
- ReIsValidByteHex = re.compile(r"^\s*0x[0-9a-fA-F]{1,2}\s*$", re.DOTALL)
- if PcdValue.strip().startswith('{') and PcdValue.strip().endswith('}') :
- StringValue = PcdValue.strip().lstrip('{').rstrip('}')
- ValueList = StringValue.split(',')
- AllValidFlag = True
- for ValueItem in ValueList:
- if not ReIsValidByteHex.match(ValueItem.strip()):
- AllValidFlag = False
-
- if AllValidFlag:
- return True
-
- #
- # NList
- #
- AllValidFlag = True
- ValueList = PcdValue.split(',')
- for ValueItem in ValueList:
- if not ReIsValidByteHex.match(ValueItem.strip()):
- AllValidFlag = False
-
- if AllValidFlag:
- return True
-
- return False
-
-## IsValidCVariableName
-#
-# Check whether the PcdValue is valid.
-#
-# @param VersionString: The PcdValue need to be checked.
-#
-def IsValidCVariableName(CName):
- ReIsValidCName = re.compile(r"^[A-Za-z_][0-9A-Za-z_]*$", re.DOTALL)
- if ReIsValidCName.match(CName) is None:
- return False
-
- return True
-
-## IsValidIdentifier
-#
-# <Identifier> ::= <NonDigit> <Chars>{0,}
-# <Chars> ::= (a-zA-Z0-9_)
-# <NonDigit> ::= (a-zA-Z_)
-#
-# @param Ident: identifier to be checked
-#
-def IsValidIdentifier(Ident):
- ReIdent = re.compile(r"^[A-Za-z_][0-9A-Za-z_]*$", re.DOTALL)
- if ReIdent.match(Ident) is None:
- return False
-
- return True
-
-## IsValidDecVersionVal
-#
-# {(0-9){1,} "." (0-99)}
-#
-# @param Ver: version to be checked
-#
-def IsValidDecVersionVal(Ver):
- ReVersion = re.compile(r"[0-9]+(\.[0-9]{1,2})$")
-
- if ReVersion.match(Ver) is None:
- return False
-
- return True
-
-
-## IsValidLibName
-#
-# (A-Z)(a-zA-Z0-9){0,} and could not be "NULL"
-#
-def IsValidLibName(LibName):
- if LibName == 'NULL':
- return False
- ReLibName = re.compile("^[A-Z]+[a-zA-Z0-9]*$")
- if not ReLibName.match(LibName):
- return False
-
- return True
-
-# IsValidUserId
-#
-# <UserId> ::= (a-zA-Z)(a-zA-Z0-9_.){0,}
-# Words that contain period "." must be encapsulated in double quotation marks.
-#
-def IsValidUserId(UserId):
- UserId = UserId.strip()
- Quoted = False
- if UserId.startswith('"') and UserId.endswith('"'):
- Quoted = True
- UserId = UserId[1:-1]
- if not UserId or not UserId[0].isalpha():
- return False
- for Char in UserId[1:]:
- if not Char.isalnum() and not Char in '_.':
- return False
- if Char == '.' and not Quoted:
- return False
- return True
-
-#
-# Check if a UTF16-LE file has a BOM header
-#
-def CheckUTF16FileHeader(File):
- FileIn = open(File, 'rb').read(2)
- if FileIn != b'\xff\xfe':
- return False
-
- return True
+## @file ParserValidate.py +# Functions for parser validation +# +# Copyright (c) 2011 - 2018, Intel Corporation. All rights reserved.<BR> +# +# SPDX-License-Identifier: BSD-2-Clause-Patent +# + +''' +ParserValidate +''' + +import os.path +import re +import platform + +from Library.DataType import MODULE_LIST +from Library.DataType import COMPONENT_TYPE_LIST +from Library.DataType import PCD_USAGE_TYPE_LIST_OF_MODULE +from Library.DataType import TAB_SPACE_SPLIT +from Library.StringUtils import GetSplitValueList +from Library.ExpressionValidate import IsValidBareCString +from Library.ExpressionValidate import IsValidFeatureFlagExp +from Common.MultipleWorkspace import MultipleWorkspace as mws + +## __HexDigit() method +# +# Whether char input is a Hex data bit +# +# @param TempChar: The char to test +# +def __HexDigit(TempChar): + if (TempChar >= 'a' and TempChar <= 'f') or \ + (TempChar >= 'A' and TempChar <= 'F') \ + or (TempChar >= '0' and TempChar <= '9'): + return True + else: + return False + +## IsValidHex() method +# +# Whether char input is a Hex data. +# +# @param TempChar: The char to test +# +def IsValidHex(HexStr): + if not HexStr.upper().startswith("0X"): + return False + CharList = [c for c in HexStr[2:] if not __HexDigit(c)] + if len(CharList) == 0: + return True + else: + return False + +## Judge the input string is valid bool type or not. +# +# <TRUE> ::= {"TRUE"} {"true"} {"True"} {"0x1"} {"0x01"} +# <FALSE> ::= {"FALSE"} {"false"} {"False"} {"0x0"} {"0x00"} +# <BoolType> ::= {<TRUE>} {<FALSE>} +# +# @param BoolString: A string contained the value need to be judged. +# +def IsValidBoolType(BoolString): + # + # Valid True + # + if BoolString == 'TRUE' or \ + BoolString == 'True' or \ + BoolString == 'true' or \ + BoolString == '0x1' or \ + BoolString == '0x01': + return True + # + # Valid False + # + elif BoolString == 'FALSE' or \ + BoolString == 'False' or \ + BoolString == 'false' or \ + BoolString == '0x0' or \ + BoolString == '0x00': + return True + # + # Invalid bool type + # + else: + return False + +## Is Valid Module Type List or not +# +# @param ModuleTypeList: A list contain ModuleType strings need to be +# judged. +# +def IsValidInfMoudleTypeList(ModuleTypeList): + for ModuleType in ModuleTypeList: + return IsValidInfMoudleType(ModuleType) + +## Is Valid Module Type or not +# +# @param ModuleType: A string contain ModuleType need to be judged. +# +def IsValidInfMoudleType(ModuleType): + if ModuleType in MODULE_LIST: + return True + else: + return False + +## Is Valid Component Type or not +# +# @param ComponentType: A string contain ComponentType need to be judged. +# +def IsValidInfComponentType(ComponentType): + if ComponentType.upper() in COMPONENT_TYPE_LIST: + return True + else: + return False + + +## Is valid Tool Family or not +# +# @param ToolFamily: A string contain Tool Family need to be judged. +# Family := [A-Z]([a-zA-Z0-9])* +# +def IsValidToolFamily(ToolFamily): + ReIsValidFamily = re.compile(r"^[A-Z]+[A-Za-z0-9]{0,}$", re.DOTALL) + if ReIsValidFamily.match(ToolFamily) is None: + return False + return True + +## Is valid Tool TagName or not +# +# The TagName sample is MYTOOLS and VS2005. +# +# @param TagName: A string contain Tool TagName need to be judged. +# +def IsValidToolTagName(TagName): + if TagName.strip() == '': + return True + if TagName.strip() == '*': + return True + if not IsValidWord(TagName): + return False + return True + +## Is valid arch or not +# +# @param Arch The arch string need to be validated +# <OA> ::= (a-zA-Z)(A-Za-z0-9){0,} +# <arch> ::= {"IA32"} {"X64"} {"IPF"} {"EBC"} {<OA>} +# {"common"} +# @param Arch: Input arch +# +def IsValidArch(Arch): + if Arch == 'common': + return True + ReIsValidArch = re.compile(r"^[a-zA-Z]+[a-zA-Z0-9]{0,}$", re.DOTALL) + if ReIsValidArch.match(Arch) is None: + return False + return True + +## Is valid family or not +# +# <Family> ::= {"MSFT"} {"GCC"} {"INTEL"} {<Usr>} {"*"} +# <Usr> ::= [A-Z][A-Za-z0-9]{0,} +# +# @param family: The family string need to be validated +# +def IsValidFamily(Family): + Family = Family.strip() + if Family == '*': + return True + + if Family == '': + return True + + ReIsValidFamily = re.compile(r"^[A-Z]+[A-Za-z0-9]{0,}$", re.DOTALL) + if ReIsValidFamily.match(Family) is None: + return False + return True + +## Is valid build option name or not +# +# @param BuildOptionName: The BuildOptionName string need to be validated +# +def IsValidBuildOptionName(BuildOptionName): + if not BuildOptionName: + return False + + ToolOptionList = GetSplitValueList(BuildOptionName, '_', 4) + + if len(ToolOptionList) != 5: + return False + + ReIsValidBuildOption1 = re.compile(r"^\s*(\*)|([A-Z][a-zA-Z0-9]*)$") + ReIsValidBuildOption2 = re.compile(r"^\s*(\*)|([a-zA-Z][a-zA-Z0-9]*)$") + + if ReIsValidBuildOption1.match(ToolOptionList[0]) is None: + return False + + if ReIsValidBuildOption1.match(ToolOptionList[1]) is None: + return False + + if ReIsValidBuildOption2.match(ToolOptionList[2]) is None: + return False + + if ToolOptionList[3] == "*" and ToolOptionList[4] not in ['FAMILY', 'DLL', 'DPATH']: + return False + + return True + +## IsValidToken +# +# Check if pattern string matches total token +# +# @param ReString: regular string +# @param Token: Token to be matched +# +def IsValidToken(ReString, Token): + Match = re.compile(ReString).match(Token) + return Match and Match.start() == 0 and Match.end() == len(Token) + +## IsValidPath +# +# Check if path exist +# +# @param Path: Absolute path or relative path to be checked +# @param Root: Root path +# +def IsValidPath(Path, Root): + Path = Path.strip() + OrigPath = Path.replace('\\', '/') + + Path = os.path.normpath(Path).replace('\\', '/') + Root = os.path.normpath(Root).replace('\\', '/') + FullPath = mws.join(Root, Path) + + if not os.path.exists(FullPath): + return False + + # + # If Path is absolute path. + # It should be in Root. + # + if os.path.isabs(Path): + if not Path.startswith(Root): + return False + return True + + # + # Check illegal character + # + for Rel in ['/', './', '../']: + if OrigPath.startswith(Rel): + return False + for Rel in ['//', '/./', '/../']: + if Rel in OrigPath: + return False + for Rel in ['/.', '/..', '/']: + if OrigPath.endswith(Rel): + return False + + Path = Path.rstrip('/') + + # + # Check relative path + # + for Word in Path.split('/'): + if not IsValidWord(Word): + return False + + return True + +## IsValidInstallPath +# +# Check if an install path valid or not. +# +# Absolute path or path starts with '.' or path contains '..' are invalid. +# +# @param Path: path to be checked +# +def IsValidInstallPath(Path): + if platform.platform().find("Windows") >= 0: + if os.path.isabs(Path): + return False + else: + if Path[1:2] == ':': + return False + if os.path.isabs(Path): + return False + if Path.startswith('.'): + return False + + if Path.find('..') != -1: + return False + + return True + + +## IsValidCFormatGuid +# +# Check if GUID format has the from of {8,4,4,{2,2,2,2,2,2,2,2}} +# +# @param Guid: Guid to be checked +# +def IsValidCFormatGuid(Guid): + # + # Valid: { 0xf0b11735, 0x87a0, 0x4193, {0xb2, 0x66, 0x53, 0x8c, 0x38, + # 0xaf, 0x48, 0xce }} + # Invalid: { 0xf0b11735, 0x87a0, 0x4193, {0xb2, 0x66, 0x53, 0x8c, 0x38, + # 0xaf, 0x48, 0xce }} 0x123 + # Invalid: { 0xf0b1 1735, 0x87a0, 0x4193, {0xb2, 0x66, 0x53, 0x8c, 0x38, + # 0xaf, 0x48, 0xce }} + # + List = ['{', 10, ',', 6, ',', 6, ',{', 4, ',', 4, ',', 4, + ',', 4, ',', 4, ',', 4, ',', 4, ',', 4, '}}'] + Index = 0 + Value = '' + SepValue = '' + for Char in Guid: + if Char not in '{},\t ': + Value += Char + continue + if Value: + try: + # + # Index may out of bound + # + if not SepValue or SepValue != List[Index]: + return False + Index += 1 + SepValue = '' + + if not Value.startswith('0x') and not Value.startswith('0X'): + return False + + # + # Index may out of bound + # + if not isinstance(List[Index], type(1)) or \ + len(Value) > List[Index] or len(Value) < 3: + return False + + # + # Check if string can be converted to integer + # Throw exception if not + # + int(Value, 16) + except BaseException: + # + # Exception caught means invalid format + # + return False + Value = '' + Index += 1 + if Char in '{},': + SepValue += Char + + return SepValue == '}}' and Value == '' + +## IsValidPcdType +# +# Check whether the PCD type is valid +# +# @param PcdTypeString: The PcdType string need to be checked. +# +def IsValidPcdType(PcdTypeString): + if PcdTypeString.upper() in PCD_USAGE_TYPE_LIST_OF_MODULE: + return True + else: + return False + +## IsValidWord +# +# Check whether the word is valid. +# <Word> ::= (a-zA-Z0-9_)(a-zA-Z0-9_-){0,} Alphanumeric characters with +# optional +# dash "-" and/or underscore "_" characters. No whitespace +# characters are permitted. +# +# @param Word: The word string need to be checked. +# +def IsValidWord(Word): + if not Word: + return False + # + # The first char should be alpha, _ or Digit. + # + if not Word[0].isalnum() and \ + not Word[0] == '_' and \ + not Word[0].isdigit(): + return False + + LastChar = '' + for Char in Word[1:]: + if (not Char.isalpha()) and \ + (not Char.isdigit()) and \ + Char != '-' and \ + Char != '_' and \ + Char != '.': + return False + if Char == '.' and LastChar == '.': + return False + LastChar = Char + + return True + + +## IsValidSimpleWord +# +# Check whether the SimpleWord is valid. +# <SimpleWord> ::= (a-zA-Z0-9)(a-zA-Z0-9_-){0,} +# A word that cannot contain a period character. +# +# @param Word: The word string need to be checked. +# +def IsValidSimpleWord(Word): + ReIsValidSimpleWord = \ + re.compile(r"^[0-9A-Za-z][0-9A-Za-z\-_]*$", re.DOTALL) + Word = Word.strip() + if not Word: + return False + + if not ReIsValidSimpleWord.match(Word): + return False + + return True + +## IsValidDecVersion +# +# Check whether the decimal version is valid. +# <DecVersion> ::= (0-9){1,} ["." (0-9){1,}] +# +# @param Word: The word string need to be checked. +# +def IsValidDecVersion(Word): + if Word.find('.') > -1: + ReIsValidDecVersion = re.compile(r"[0-9]+\.?[0-9]+$") + else: + ReIsValidDecVersion = re.compile(r"[0-9]+$") + if ReIsValidDecVersion.match(Word) is None: + return False + return True + +## IsValidHexVersion +# +# Check whether the hex version is valid. +# <HexVersion> ::= "0x" <Major> <Minor> +# <Major> ::= <HexDigit>{4} +# <Minor> ::= <HexDigit>{4} +# +# @param Word: The word string need to be checked. +# +def IsValidHexVersion(Word): + ReIsValidHexVersion = re.compile(r"[0][xX][0-9A-Fa-f]{8}$", re.DOTALL) + if ReIsValidHexVersion.match(Word) is None: + return False + + return True + +## IsValidBuildNumber +# +# Check whether the BUILD_NUMBER is valid. +# ["BUILD_NUMBER" "=" <Integer>{1,4} <EOL>] +# +# @param Word: The BUILD_NUMBER string need to be checked. +# +def IsValidBuildNumber(Word): + ReIsValieBuildNumber = re.compile(r"[0-9]{1,4}$", re.DOTALL) + if ReIsValieBuildNumber.match(Word) is None: + return False + + return True + +## IsValidDepex +# +# Check whether the Depex is valid. +# +# @param Word: The Depex string need to be checked. +# +def IsValidDepex(Word): + Index = Word.upper().find("PUSH") + if Index > -1: + return IsValidCFormatGuid(Word[Index+4:].strip()) + + ReIsValidCName = re.compile(r"^[A-Za-z_][0-9A-Za-z_\s\.]*$", re.DOTALL) + if ReIsValidCName.match(Word) is None: + return False + + return True + +## IsValidNormalizedString +# +# Check +# <NormalizedString> ::= <DblQuote> [{<Word>} {<Space>}]{1,} <DblQuote> +# <Space> ::= 0x20 +# +# @param String: string to be checked +# +def IsValidNormalizedString(String): + if String == '': + return True + + for Char in String: + if Char == '\t': + return False + + StringList = GetSplitValueList(String, TAB_SPACE_SPLIT) + + for Item in StringList: + if not Item: + continue + if not IsValidWord(Item): + return False + + return True + +## IsValidIdString +# +# Check whether the IdString is valid. +# +# @param IdString: The IdString need to be checked. +# +def IsValidIdString(String): + if IsValidSimpleWord(String.strip()): + return True + + if String.strip().startswith('"') and \ + String.strip().endswith('"'): + String = String[1:-1] + if String.strip() == "": + return True + if IsValidNormalizedString(String): + return True + + return False + +## IsValidVersionString +# +# Check whether the VersionString is valid. +# <AsciiString> ::= [ [<WhiteSpace>]{0,} [<AsciiChars>]{0,} ] {0,} +# <WhiteSpace> ::= {<Tab>} {<Space>} +# <Tab> ::= 0x09 +# <Space> ::= 0x20 +# <AsciiChars> ::= (0x21 - 0x7E) +# +# @param VersionString: The VersionString need to be checked. +# +def IsValidVersionString(VersionString): + VersionString = VersionString.strip() + for Char in VersionString: + if not (Char >= 0x21 and Char <= 0x7E): + return False + + return True + +## IsValidPcdValue +# +# Check whether the PcdValue is valid. +# +# @param VersionString: The PcdValue need to be checked. +# +def IsValidPcdValue(PcdValue): + for Char in PcdValue: + if Char == '\n' or Char == '\t' or Char == '\f': + return False + + # + # <Boolean> + # + if IsValidFeatureFlagExp(PcdValue, True)[0]: + return True + + # + # <Number> ::= {<Integer>} {<HexNumber>} + # <Integer> ::= {(0-9)} {(1-9)(0-9){1,}} + # <HexNumber> ::= "0x" <HexDigit>{1,} + # <HexDigit> ::= (a-fA-F0-9) + # + if IsValidHex(PcdValue): + return True + + ReIsValidIntegerSingle = re.compile(r"^\s*[0-9]\s*$", re.DOTALL) + if ReIsValidIntegerSingle.match(PcdValue) is not None: + return True + + ReIsValidIntegerMulti = re.compile(r"^\s*[1-9][0-9]+\s*$", re.DOTALL) + if ReIsValidIntegerMulti.match(PcdValue) is not None: + return True + + # + # <StringVal> ::= {<StringType>} {<Array>} {"$(" <MACRO> ")"} + # <StringType> ::= {<UnicodeString>} {<CString>} + # + ReIsValidStringType = re.compile(r"^\s*[\"L].*[\"]\s*$") + if ReIsValidStringType.match(PcdValue): + IsTrue = False + if PcdValue.strip().startswith('L\"'): + StringValue = PcdValue.strip().lstrip('L\"').rstrip('\"') + if IsValidBareCString(StringValue): + IsTrue = True + elif PcdValue.strip().startswith('\"'): + StringValue = PcdValue.strip().lstrip('\"').rstrip('\"') + if IsValidBareCString(StringValue): + IsTrue = True + if IsTrue: + return IsTrue + + # + # <Array> ::= {<CArray>} {<NList>} {<CFormatGUID>} + # <CArray> ::= "{" [<NList>] <CArray>{0,} "}" + # <NList> ::= <HexByte> ["," <HexByte>]{0,} + # <HexDigit> ::= (a-fA-F0-9) + # <HexByte> ::= "0x" <HexDigit>{1,2} + # + if IsValidCFormatGuid(PcdValue): + return True + + ReIsValidByteHex = re.compile(r"^\s*0x[0-9a-fA-F]{1,2}\s*$", re.DOTALL) + if PcdValue.strip().startswith('{') and PcdValue.strip().endswith('}') : + StringValue = PcdValue.strip().lstrip('{').rstrip('}') + ValueList = StringValue.split(',') + AllValidFlag = True + for ValueItem in ValueList: + if not ReIsValidByteHex.match(ValueItem.strip()): + AllValidFlag = False + + if AllValidFlag: + return True + + # + # NList + # + AllValidFlag = True + ValueList = PcdValue.split(',') + for ValueItem in ValueList: + if not ReIsValidByteHex.match(ValueItem.strip()): + AllValidFlag = False + + if AllValidFlag: + return True + + return False + +## IsValidCVariableName +# +# Check whether the PcdValue is valid. +# +# @param VersionString: The PcdValue need to be checked. +# +def IsValidCVariableName(CName): + ReIsValidCName = re.compile(r"^[A-Za-z_][0-9A-Za-z_]*$", re.DOTALL) + if ReIsValidCName.match(CName) is None: + return False + + return True + +## IsValidIdentifier +# +# <Identifier> ::= <NonDigit> <Chars>{0,} +# <Chars> ::= (a-zA-Z0-9_) +# <NonDigit> ::= (a-zA-Z_) +# +# @param Ident: identifier to be checked +# +def IsValidIdentifier(Ident): + ReIdent = re.compile(r"^[A-Za-z_][0-9A-Za-z_]*$", re.DOTALL) + if ReIdent.match(Ident) is None: + return False + + return True + +## IsValidDecVersionVal +# +# {(0-9){1,} "." (0-99)} +# +# @param Ver: version to be checked +# +def IsValidDecVersionVal(Ver): + ReVersion = re.compile(r"[0-9]+(\.[0-9]{1,2})$") + + if ReVersion.match(Ver) is None: + return False + + return True + + +## IsValidLibName +# +# (A-Z)(a-zA-Z0-9){0,} and could not be "NULL" +# +def IsValidLibName(LibName): + if LibName == 'NULL': + return False + ReLibName = re.compile("^[A-Z]+[a-zA-Z0-9]*$") + if not ReLibName.match(LibName): + return False + + return True + +# IsValidUserId +# +# <UserId> ::= (a-zA-Z)(a-zA-Z0-9_.){0,} +# Words that contain period "." must be encapsulated in double quotation marks. +# +def IsValidUserId(UserId): + UserId = UserId.strip() + Quoted = False + if UserId.startswith('"') and UserId.endswith('"'): + Quoted = True + UserId = UserId[1:-1] + if not UserId or not UserId[0].isalpha(): + return False + for Char in UserId[1:]: + if not Char.isalnum() and not Char in '_.': + return False + if Char == '.' and not Quoted: + return False + return True + +# +# Check if a UTF16-LE file has a BOM header +# +def CheckUTF16FileHeader(File): + FileIn = open(File, 'rb').read(2) + if FileIn != b'\xff\xfe': + return False + + return True diff --git a/BaseTools/Source/Python/UPT/Library/Parsing.py b/BaseTools/Source/Python/UPT/Library/Parsing.py index 6fb133745e..802f81e65c 100644 --- a/BaseTools/Source/Python/UPT/Library/Parsing.py +++ b/BaseTools/Source/Python/UPT/Library/Parsing.py @@ -1,1015 +1,1015 @@ -## @file
-# This file is used to define common parsing related functions used in parsing
-# INF/DEC/DSC process
-#
-# Copyright (c) 2011 - 2018, Intel Corporation. All rights reserved.<BR>
-#
-# SPDX-License-Identifier: BSD-2-Clause-Patent
-#
-
-'''
-Parsing
-'''
-from __future__ import absolute_import
-
-##
-# Import Modules
-#
-import os.path
-import re
-
-from Library.StringUtils import RaiseParserError
-from Library.StringUtils import GetSplitValueList
-from Library.StringUtils import CheckFileType
-from Library.StringUtils import CheckFileExist
-from Library.StringUtils import CleanString
-from Library.StringUtils import NormPath
-
-from Logger.ToolError import FILE_NOT_FOUND
-from Logger.ToolError import FatalError
-from Logger.ToolError import FORMAT_INVALID
-
-from Library import DataType
-
-from Library.Misc import GuidStructureStringToGuidString
-from Library.Misc import CheckGuidRegFormat
-from Logger import StringTable as ST
-import Logger.Log as Logger
-
-from Parser.DecParser import Dec
-from . import GlobalData
-
-gPKG_INFO_DICT = {}
-
-## GetBuildOption
-#
-# Parse a string with format "[<Family>:]<ToolFlag>=Flag"
-# Return (Family, ToolFlag, Flag)
-#
-# @param String: String with BuildOption statement
-# @param File: The file which defines build option, used in error report
-#
-def GetBuildOption(String, File, LineNo= -1):
- (Family, ToolChain, Flag) = ('', '', '')
- if String.find(DataType.TAB_EQUAL_SPLIT) < 0:
- RaiseParserError(String, 'BuildOptions', File, \
- '[<Family>:]<ToolFlag>=Flag', LineNo)
- else:
- List = GetSplitValueList(String, DataType.TAB_EQUAL_SPLIT, MaxSplit=1)
- if List[0].find(':') > -1:
- Family = List[0][ : List[0].find(':')].strip()
- ToolChain = List[0][List[0].find(':') + 1 : ].strip()
- else:
- ToolChain = List[0].strip()
- Flag = List[1].strip()
- return (Family, ToolChain, Flag)
-
-## Get Library Class
-#
-# Get Library of Dsc as <LibraryClassKeyWord>|<LibraryInstance>
-#
-# @param Item: String as <LibraryClassKeyWord>|<LibraryInstance>
-# @param ContainerFile: The file which describes the library class, used for
-# error report
-#
-def GetLibraryClass(Item, ContainerFile, WorkspaceDir, LineNo= -1):
- List = GetSplitValueList(Item[0])
- SupMod = DataType.SUP_MODULE_LIST_STRING
- if len(List) != 2:
- RaiseParserError(Item[0], 'LibraryClasses', ContainerFile, \
- '<LibraryClassKeyWord>|<LibraryInstance>')
- else:
- CheckFileType(List[1], '.Inf', ContainerFile, \
- 'library class instance', Item[0], LineNo)
- CheckFileExist(WorkspaceDir, List[1], ContainerFile, \
- 'LibraryClasses', Item[0], LineNo)
- if Item[1] != '':
- SupMod = Item[1]
-
- return (List[0], List[1], SupMod)
-
-## Get Library Class
-#
-# Get Library of Dsc as <LibraryClassKeyWord>[|<LibraryInstance>]
-# [|<TokenSpaceGuidCName>.<PcdCName>]
-#
-# @param Item: String as <LibraryClassKeyWord>|<LibraryInstance>
-# @param ContainerFile: The file which describes the library class, used for
-# error report
-#
-def GetLibraryClassOfInf(Item, ContainerFile, WorkspaceDir, LineNo= -1):
- ItemList = GetSplitValueList((Item[0] + DataType.TAB_VALUE_SPLIT * 2))
- SupMod = DataType.SUP_MODULE_LIST_STRING
-
- if len(ItemList) > 5:
- RaiseParserError\
- (Item[0], 'LibraryClasses', ContainerFile, \
- '<LibraryClassKeyWord>[|<LibraryInstance>]\
- [|<TokenSpaceGuidCName>.<PcdCName>]')
- else:
- CheckFileType(ItemList[1], '.Inf', ContainerFile, 'LibraryClasses', \
- Item[0], LineNo)
- CheckFileExist(WorkspaceDir, ItemList[1], ContainerFile, \
- 'LibraryClasses', Item[0], LineNo)
- if ItemList[2] != '':
- CheckPcdTokenInfo(ItemList[2], 'LibraryClasses', \
- ContainerFile, LineNo)
- if Item[1] != '':
- SupMod = Item[1]
-
- return (ItemList[0], ItemList[1], ItemList[2], SupMod)
-
-## CheckPcdTokenInfo
-#
-# Check if PcdTokenInfo is following <TokenSpaceGuidCName>.<PcdCName>
-#
-# @param TokenInfoString: String to be checked
-# @param Section: Used for error report
-# @param File: Used for error report
-#
-def CheckPcdTokenInfo(TokenInfoString, Section, File, LineNo= -1):
- Format = '<TokenSpaceGuidCName>.<PcdCName>'
- if TokenInfoString != '' and TokenInfoString is not None:
- TokenInfoList = GetSplitValueList(TokenInfoString, DataType.TAB_SPLIT)
- if len(TokenInfoList) == 2:
- return True
-
- RaiseParserError(TokenInfoString, Section, File, Format, LineNo)
-
-## Get Pcd
-#
-# Get Pcd of Dsc as <PcdTokenSpaceGuidCName>.<TokenCName>|<Value>
-# [|<Type>|<MaximumDatumSize>]
-#
-# @param Item: String as <PcdTokenSpaceGuidCName>.<TokenCName>|
-# <Value>[|<Type>|<MaximumDatumSize>]
-# @param ContainerFile: The file which describes the pcd, used for error
-# report
-
-#
-def GetPcd(Item, Type, ContainerFile, LineNo= -1):
- TokenGuid, TokenName, Value, MaximumDatumSize, Token = '', '', '', '', ''
- List = GetSplitValueList(Item + DataType.TAB_VALUE_SPLIT * 2)
-
- if len(List) < 4 or len(List) > 6:
- RaiseParserError(Item, 'Pcds' + Type, ContainerFile, \
- '<PcdTokenSpaceGuidCName>.<TokenCName>|<Value>\
- [|<Type>|<MaximumDatumSize>]', LineNo)
- else:
- Value = List[1]
- MaximumDatumSize = List[2]
- Token = List[3]
-
- if CheckPcdTokenInfo(List[0], 'Pcds' + Type, ContainerFile, LineNo):
- (TokenGuid, TokenName) = GetSplitValueList(List[0], DataType.TAB_SPLIT)
-
- return (TokenName, TokenGuid, Value, MaximumDatumSize, Token, Type)
-
-## Get FeatureFlagPcd
-#
-# Get FeatureFlagPcd of Dsc as <PcdTokenSpaceGuidCName>.<TokenCName>|TRUE/FALSE
-#
-# @param Item: String as <PcdTokenSpaceGuidCName>
-# .<TokenCName>|TRUE/FALSE
-# @param ContainerFile: The file which describes the pcd, used for error
-# report
-#
-def GetFeatureFlagPcd(Item, Type, ContainerFile, LineNo= -1):
- TokenGuid, TokenName, Value = '', '', ''
- List = GetSplitValueList(Item)
- if len(List) != 2:
- RaiseParserError(Item, 'Pcds' + Type, ContainerFile, \
- '<PcdTokenSpaceGuidCName>.<TokenCName>|TRUE/FALSE', \
- LineNo)
- else:
- Value = List[1]
- if CheckPcdTokenInfo(List[0], 'Pcds' + Type, ContainerFile, LineNo):
- (TokenGuid, TokenName) = GetSplitValueList(List[0], DataType.TAB_SPLIT)
-
- return (TokenName, TokenGuid, Value, Type)
-
-## Get DynamicDefaultPcd
-#
-# Get DynamicDefaultPcd of Dsc as <PcdTokenSpaceGuidCName>.<TokenCName>
-# |<Value>[|<DatumTyp>[|<MaxDatumSize>]]
-#
-# @param Item: String as <PcdTokenSpaceGuidCName>.<TokenCName>|
-# TRUE/FALSE
-# @param ContainerFile: The file which describes the pcd, used for error
-# report
-#
-def GetDynamicDefaultPcd(Item, Type, ContainerFile, LineNo= -1):
- TokenGuid, TokenName, Value, DatumTyp, MaxDatumSize = '', '', '', '', ''
- List = GetSplitValueList(Item + DataType.TAB_VALUE_SPLIT * 2)
- if len(List) < 4 or len(List) > 8:
- RaiseParserError(Item, 'Pcds' + Type, ContainerFile, \
- '<PcdTokenSpaceGuidCName>.<TokenCName>|<Value>\
- [|<DatumTyp>[|<MaxDatumSize>]]', LineNo)
- else:
- Value = List[1]
- DatumTyp = List[2]
- MaxDatumSize = List[3]
- if CheckPcdTokenInfo(List[0], 'Pcds' + Type, ContainerFile, LineNo):
- (TokenGuid, TokenName) = GetSplitValueList(List[0], DataType.TAB_SPLIT)
-
- return (TokenName, TokenGuid, Value, DatumTyp, MaxDatumSize, Type)
-
-## Get DynamicHiiPcd
-#
-# Get DynamicHiiPcd of Dsc as <PcdTokenSpaceGuidCName>.<TokenCName>|<String>|
-# <VariableGuidCName>|<VariableOffset>[|<DefaultValue>[|<MaximumDatumSize>]]
-#
-# @param Item: String as <PcdTokenSpaceGuidCName>.<TokenCName>|
-# TRUE/FALSE
-# @param ContainerFile: The file which describes the pcd, used for error
-# report
-#
-def GetDynamicHiiPcd(Item, Type, ContainerFile, LineNo= -1):
- TokenGuid, TokenName, List1, List2, List3, List4, List5 = \
- '', '', '', '', '', '', ''
- List = GetSplitValueList(Item + DataType.TAB_VALUE_SPLIT * 2)
- if len(List) < 6 or len(List) > 8:
- RaiseParserError(Item, 'Pcds' + Type, ContainerFile, \
- '<PcdTokenSpaceGuidCName>.<TokenCName>|<String>|\
- <VariableGuidCName>|<VariableOffset>[|<DefaultValue>\
- [|<MaximumDatumSize>]]', LineNo)
- else:
- List1, List2, List3, List4, List5 = \
- List[1], List[2], List[3], List[4], List[5]
- if CheckPcdTokenInfo(List[0], 'Pcds' + Type, ContainerFile, LineNo):
- (TokenGuid, TokenName) = GetSplitValueList(List[0], DataType.TAB_SPLIT)
-
- return (TokenName, TokenGuid, List1, List2, List3, List4, List5, Type)
-
-## Get DynamicVpdPcd
-#
-# Get DynamicVpdPcd of Dsc as <PcdTokenSpaceGuidCName>.<TokenCName>|
-# <VpdOffset>[|<MaximumDatumSize>]
-#
-# @param Item: String as <PcdTokenSpaceGuidCName>.<TokenCName>
-# |TRUE/FALSE
-# @param ContainerFile: The file which describes the pcd, used for error
-# report
-#
-def GetDynamicVpdPcd(Item, Type, ContainerFile, LineNo= -1):
- TokenGuid, TokenName, List1, List2 = '', '', '', ''
- List = GetSplitValueList(Item + DataType.TAB_VALUE_SPLIT)
- if len(List) < 3 or len(List) > 4:
- RaiseParserError(Item, 'Pcds' + Type, ContainerFile, \
- '<PcdTokenSpaceGuidCName>.<TokenCName>|<VpdOffset>\
- [|<MaximumDatumSize>]', LineNo)
- else:
- List1, List2 = List[1], List[2]
- if CheckPcdTokenInfo(List[0], 'Pcds' + Type, ContainerFile, LineNo):
- (TokenGuid, TokenName) = GetSplitValueList(List[0], DataType.TAB_SPLIT)
-
- return (TokenName, TokenGuid, List1, List2, Type)
-
-## GetComponent
-#
-# Parse block of the components defined in dsc file
-# Set KeyValues as [ ['component name', [lib1, lib2, lib3],
-# [bo1, bo2, bo3], [pcd1, pcd2, pcd3]], ...]
-#
-# @param Lines: The content to be parsed
-# @param KeyValues: To store data after parsing
-#
-def GetComponent(Lines, KeyValues):
- (FindBlock, FindLibraryClass, FindBuildOption, FindPcdsFeatureFlag, \
- FindPcdsPatchableInModule, FindPcdsFixedAtBuild, FindPcdsDynamic, \
- FindPcdsDynamicEx) = (False, False, False, False, False, False, False, \
- False)
- ListItem = None
- LibraryClassItem = []
- BuildOption = []
- Pcd = []
-
- for Line in Lines:
- Line = Line[0]
- #
- # Ignore !include statement
- #
- if Line.upper().find(DataType.TAB_INCLUDE.upper() + ' ') > -1 or \
- Line.upper().find(DataType.TAB_DEFINE + ' ') > -1:
- continue
-
- if FindBlock == False:
- ListItem = Line
- #
- # find '{' at line tail
- #
- if Line.endswith('{'):
- FindBlock = True
- ListItem = CleanString(Line.rsplit('{', 1)[0], \
- DataType.TAB_COMMENT_SPLIT)
-
- #
- # Parse a block content
- #
- if FindBlock:
- if Line.find('<LibraryClasses>') != -1:
- (FindLibraryClass, FindBuildOption, FindPcdsFeatureFlag, \
- FindPcdsPatchableInModule, FindPcdsFixedAtBuild, \
- FindPcdsDynamic, FindPcdsDynamicEx) = \
- (True, False, False, False, False, False, False)
- continue
- if Line.find('<BuildOptions>') != -1:
- (FindLibraryClass, FindBuildOption, FindPcdsFeatureFlag, \
- FindPcdsPatchableInModule, FindPcdsFixedAtBuild, \
- FindPcdsDynamic, FindPcdsDynamicEx) = \
- (False, True, False, False, False, False, False)
- continue
- if Line.find('<PcdsFeatureFlag>') != -1:
- (FindLibraryClass, FindBuildOption, FindPcdsFeatureFlag, \
- FindPcdsPatchableInModule, FindPcdsFixedAtBuild, \
- FindPcdsDynamic, FindPcdsDynamicEx) = \
- (False, False, True, False, False, False, False)
- continue
- if Line.find('<PcdsPatchableInModule>') != -1:
- (FindLibraryClass, FindBuildOption, FindPcdsFeatureFlag, \
- FindPcdsPatchableInModule, FindPcdsFixedAtBuild, \
- FindPcdsDynamic, FindPcdsDynamicEx) = \
- (False, False, False, True, False, False, False)
- continue
- if Line.find('<PcdsFixedAtBuild>') != -1:
- (FindLibraryClass, FindBuildOption, FindPcdsFeatureFlag, \
- FindPcdsPatchableInModule, FindPcdsFixedAtBuild, \
- FindPcdsDynamic, FindPcdsDynamicEx) = \
- (False, False, False, False, True, False, False)
- continue
- if Line.find('<PcdsDynamic>') != -1:
- (FindLibraryClass, FindBuildOption, FindPcdsFeatureFlag, \
- FindPcdsPatchableInModule, FindPcdsFixedAtBuild, \
- FindPcdsDynamic, FindPcdsDynamicEx) = \
- (False, False, False, False, False, True, False)
- continue
- if Line.find('<PcdsDynamicEx>') != -1:
- (FindLibraryClass, FindBuildOption, FindPcdsFeatureFlag, \
- FindPcdsPatchableInModule, FindPcdsFixedAtBuild, \
- FindPcdsDynamic, FindPcdsDynamicEx) = \
- (False, False, False, False, False, False, True)
- continue
- if Line.endswith('}'):
- #
- # find '}' at line tail
- #
- KeyValues.append([ListItem, LibraryClassItem, \
- BuildOption, Pcd])
- (FindBlock, FindLibraryClass, FindBuildOption, \
- FindPcdsFeatureFlag, FindPcdsPatchableInModule, \
- FindPcdsFixedAtBuild, FindPcdsDynamic, FindPcdsDynamicEx) = \
- (False, False, False, False, False, False, False, False)
- LibraryClassItem, BuildOption, Pcd = [], [], []
- continue
-
- if FindBlock:
- if FindLibraryClass:
- LibraryClassItem.append(Line)
- elif FindBuildOption:
- BuildOption.append(Line)
- elif FindPcdsFeatureFlag:
- Pcd.append((DataType.TAB_PCDS_FEATURE_FLAG_NULL, Line))
- elif FindPcdsPatchableInModule:
- Pcd.append((DataType.TAB_PCDS_PATCHABLE_IN_MODULE_NULL, Line))
- elif FindPcdsFixedAtBuild:
- Pcd.append((DataType.TAB_PCDS_FIXED_AT_BUILD_NULL, Line))
- elif FindPcdsDynamic:
- Pcd.append((DataType.TAB_PCDS_DYNAMIC_DEFAULT_NULL, Line))
- elif FindPcdsDynamicEx:
- Pcd.append((DataType.TAB_PCDS_DYNAMIC_EX_DEFAULT_NULL, Line))
- else:
- KeyValues.append([ListItem, [], [], []])
-
- return True
-
-## GetExec
-#
-# Parse a string with format "InfFilename [EXEC = ExecFilename]"
-# Return (InfFilename, ExecFilename)
-#
-# @param String: String with EXEC statement
-#
-def GetExec(String):
- InfFilename = ''
- ExecFilename = ''
- if String.find('EXEC') > -1:
- InfFilename = String[ : String.find('EXEC')].strip()
- ExecFilename = String[String.find('EXEC') + len('EXEC') : ].strip()
- else:
- InfFilename = String.strip()
-
- return (InfFilename, ExecFilename)
-
-## GetComponents
-#
-# Parse block of the components defined in dsc file
-# Set KeyValues as [ ['component name', [lib1, lib2, lib3], [bo1, bo2, bo3],
-# [pcd1, pcd2, pcd3]], ...]
-#
-# @param Lines: The content to be parsed
-# @param Key: Reserved
-# @param KeyValues: To store data after parsing
-# @param CommentCharacter: Comment char, used to ignore comment content
-#
-# @retval True Get component successfully
-#
-def GetComponents(Lines, KeyValues, CommentCharacter):
- if Lines.find(DataType.TAB_SECTION_END) > -1:
- Lines = Lines.split(DataType.TAB_SECTION_END, 1)[1]
- (FindBlock, FindLibraryClass, FindBuildOption, FindPcdsFeatureFlag, \
- FindPcdsPatchableInModule, FindPcdsFixedAtBuild, FindPcdsDynamic, \
- FindPcdsDynamicEx) = \
- (False, False, False, False, False, False, False, False)
- ListItem = None
- LibraryClassItem = []
- BuildOption = []
- Pcd = []
-
- LineList = Lines.split('\n')
- for Line in LineList:
- Line = CleanString(Line, CommentCharacter)
- if Line is None or Line == '':
- continue
-
- if FindBlock == False:
- ListItem = Line
- #
- # find '{' at line tail
- #
- if Line.endswith('{'):
- FindBlock = True
- ListItem = CleanString(Line.rsplit('{', 1)[0], CommentCharacter)
-
- #
- # Parse a block content
- #
- if FindBlock:
- if Line.find('<LibraryClasses>') != -1:
- (FindLibraryClass, FindBuildOption, FindPcdsFeatureFlag, \
- FindPcdsPatchableInModule, FindPcdsFixedAtBuild, \
- FindPcdsDynamic, FindPcdsDynamicEx) = \
- (True, False, False, False, False, False, False)
- continue
- if Line.find('<BuildOptions>') != -1:
- (FindLibraryClass, FindBuildOption, FindPcdsFeatureFlag, \
- FindPcdsPatchableInModule, FindPcdsFixedAtBuild, \
- FindPcdsDynamic, FindPcdsDynamicEx) = \
- (False, True, False, False, False, False, False)
- continue
- if Line.find('<PcdsFeatureFlag>') != -1:
- (FindLibraryClass, FindBuildOption, FindPcdsFeatureFlag, \
- FindPcdsPatchableInModule, FindPcdsFixedAtBuild, \
- FindPcdsDynamic, FindPcdsDynamicEx) = \
- (False, False, True, False, False, False, False)
- continue
- if Line.find('<PcdsPatchableInModule>') != -1:
- (FindLibraryClass, FindBuildOption, FindPcdsFeatureFlag, \
- FindPcdsPatchableInModule, FindPcdsFixedAtBuild, \
- FindPcdsDynamic, FindPcdsDynamicEx) = \
- (False, False, False, True, False, False, False)
- continue
- if Line.find('<PcdsFixedAtBuild>') != -1:
- (FindLibraryClass, FindBuildOption, FindPcdsFeatureFlag, \
- FindPcdsPatchableInModule, FindPcdsFixedAtBuild, \
- FindPcdsDynamic, FindPcdsDynamicEx) = \
- (False, False, False, False, True, False, False)
- continue
- if Line.find('<PcdsDynamic>') != -1:
- (FindLibraryClass, FindBuildOption, FindPcdsFeatureFlag, \
- FindPcdsPatchableInModule, FindPcdsFixedAtBuild, \
- FindPcdsDynamic, FindPcdsDynamicEx) = \
- (False, False, False, False, False, True, False)
- continue
- if Line.find('<PcdsDynamicEx>') != -1:
- (FindLibraryClass, FindBuildOption, FindPcdsFeatureFlag, \
- FindPcdsPatchableInModule, FindPcdsFixedAtBuild, \
- FindPcdsDynamic, FindPcdsDynamicEx) = \
- (False, False, False, False, False, False, True)
- continue
- if Line.endswith('}'):
- #
- # find '}' at line tail
- #
- KeyValues.append([ListItem, LibraryClassItem, BuildOption, \
- Pcd])
- (FindBlock, FindLibraryClass, FindBuildOption, \
- FindPcdsFeatureFlag, FindPcdsPatchableInModule, \
- FindPcdsFixedAtBuild, FindPcdsDynamic, FindPcdsDynamicEx) = \
- (False, False, False, False, False, False, False, False)
- LibraryClassItem, BuildOption, Pcd = [], [], []
- continue
-
- if FindBlock:
- if FindLibraryClass:
- LibraryClassItem.append(Line)
- elif FindBuildOption:
- BuildOption.append(Line)
- elif FindPcdsFeatureFlag:
- Pcd.append((DataType.TAB_PCDS_FEATURE_FLAG, Line))
- elif FindPcdsPatchableInModule:
- Pcd.append((DataType.TAB_PCDS_PATCHABLE_IN_MODULE, Line))
- elif FindPcdsFixedAtBuild:
- Pcd.append((DataType.TAB_PCDS_FIXED_AT_BUILD, Line))
- elif FindPcdsDynamic:
- Pcd.append((DataType.TAB_PCDS_DYNAMIC, Line))
- elif FindPcdsDynamicEx:
- Pcd.append((DataType.TAB_PCDS_DYNAMIC_EX, Line))
- else:
- KeyValues.append([ListItem, [], [], []])
-
- return True
-
-## Get Source
-#
-# Get Source of Inf as <Filename>[|<Family>[|<TagName>[|<ToolCode>
-# [|<PcdFeatureFlag>]]]]
-#
-# @param Item: String as <Filename>[|<Family>[|<TagName>[|<ToolCode>
-# [|<PcdFeatureFlag>]]]]
-# @param ContainerFile: The file which describes the library class, used
-# for error report
-#
-def GetSource(Item, ContainerFile, FileRelativePath, LineNo= -1):
- ItemNew = Item + DataType.TAB_VALUE_SPLIT * 4
- List = GetSplitValueList(ItemNew)
- if len(List) < 5 or len(List) > 9:
- RaiseParserError(Item, 'Sources', ContainerFile, \
- '<Filename>[|<Family>[|<TagName>[|<ToolCode>\
- [|<PcdFeatureFlag>]]]]', LineNo)
- List[0] = NormPath(List[0])
- CheckFileExist(FileRelativePath, List[0], ContainerFile, 'Sources', \
- Item, LineNo)
- if List[4] != '':
- CheckPcdTokenInfo(List[4], 'Sources', ContainerFile, LineNo)
-
- return (List[0], List[1], List[2], List[3], List[4])
-
-## Get Binary
-#
-# Get Binary of Inf as <Filename>[|<Family>[|<TagName>[|<ToolCode>
-# [|<PcdFeatureFlag>]]]]
-#
-# @param Item: String as <Filename>[|<Family>[|<TagName>
-# [|<ToolCode>[|<PcdFeatureFlag>]]]]
-# @param ContainerFile: The file which describes the library class,
-# used for error report
-#
-def GetBinary(Item, ContainerFile, LineNo= -1):
- ItemNew = Item + DataType.TAB_VALUE_SPLIT
- List = GetSplitValueList(ItemNew)
- if len(List) < 3 or len(List) > 5:
- RaiseParserError(Item, 'Binaries', ContainerFile, \
- "<FileType>|<Filename>[|<Target>\
- [|<TokenSpaceGuidCName>.<PcdCName>]]", LineNo)
-
- if len(List) >= 4:
- if List[3] != '':
- CheckPcdTokenInfo(List[3], 'Binaries', ContainerFile, LineNo)
- return (List[0], List[1], List[2], List[3])
- elif len(List) == 3:
- return (List[0], List[1], List[2], '')
-
-## Get Guids/Protocols/Ppis
-#
-# Get Guids/Protocols/Ppis of Inf as <GuidCName>[|<PcdFeatureFlag>]
-#
-# @param Item: String as <GuidCName>[|<PcdFeatureFlag>]
-# @param Type: Type of parsing string
-# @param ContainerFile: The file which describes the library class,
-# used for error report
-#
-def GetGuidsProtocolsPpisOfInf(Item):
- ItemNew = Item + DataType.TAB_VALUE_SPLIT
- List = GetSplitValueList(ItemNew)
- return (List[0], List[1])
-
-## Get Guids/Protocols/Ppis
-#
-# Get Guids/Protocols/Ppis of Dec as <GuidCName>=<GuidValue>
-#
-# @param Item: String as <GuidCName>=<GuidValue>
-# @param Type: Type of parsing string
-# @param ContainerFile: The file which describes the library class,
-# used for error report
-#
-def GetGuidsProtocolsPpisOfDec(Item, Type, ContainerFile, LineNo= -1):
- List = GetSplitValueList(Item, DataType.TAB_EQUAL_SPLIT)
- if len(List) != 2:
- RaiseParserError(Item, Type, ContainerFile, '<CName>=<GuidValue>', \
- LineNo)
- #
- #convert C-Format Guid to Register Format
- #
- if List[1][0] == '{' and List[1][-1] == '}':
- RegisterFormatGuid = GuidStructureStringToGuidString(List[1])
- if RegisterFormatGuid == '':
- RaiseParserError(Item, Type, ContainerFile, \
- 'CFormat or RegisterFormat', LineNo)
- else:
- if CheckGuidRegFormat(List[1]):
- RegisterFormatGuid = List[1]
- else:
- RaiseParserError(Item, Type, ContainerFile, \
- 'CFormat or RegisterFormat', LineNo)
-
- return (List[0], RegisterFormatGuid)
-
-## GetPackage
-#
-# Get Package of Inf as <PackagePath>[|<PcdFeatureFlag>]
-#
-# @param Item: String as <PackagePath>[|<PcdFeatureFlag>]
-# @param Type: Type of parsing string
-# @param ContainerFile: The file which describes the library class,
-# used for error report
-#
-def GetPackage(Item, ContainerFile, FileRelativePath, LineNo= -1):
- ItemNew = Item + DataType.TAB_VALUE_SPLIT
- List = GetSplitValueList(ItemNew)
- CheckFileType(List[0], '.Dec', ContainerFile, 'package', List[0], LineNo)
- CheckFileExist(FileRelativePath, List[0], ContainerFile, 'Packages', \
- List[0], LineNo)
- if List[1] != '':
- CheckPcdTokenInfo(List[1], 'Packages', ContainerFile, LineNo)
-
- return (List[0], List[1])
-
-## Get Pcd Values of Inf
-#
-# Get Pcd of Inf as <TokenSpaceGuidCName>.<PcdCName>[|<Value>]
-#
-# @param Item: The string describes pcd
-# @param Type: The type of Pcd
-# @param File: The file which describes the pcd, used for error report
-#
-def GetPcdOfInf(Item, Type, File, LineNo):
- Format = '<TokenSpaceGuidCName>.<PcdCName>[|<Value>]'
- TokenGuid, TokenName, Value, InfType = '', '', '', ''
-
- if Type == DataType.TAB_PCDS_FIXED_AT_BUILD:
- InfType = DataType.TAB_INF_FIXED_PCD
- elif Type == DataType.TAB_PCDS_PATCHABLE_IN_MODULE:
- InfType = DataType.TAB_INF_PATCH_PCD
- elif Type == DataType.TAB_PCDS_FEATURE_FLAG:
- InfType = DataType.TAB_INF_FEATURE_PCD
- elif Type == DataType.TAB_PCDS_DYNAMIC_EX:
- InfType = DataType.TAB_INF_PCD_EX
- elif Type == DataType.TAB_PCDS_DYNAMIC:
- InfType = DataType.TAB_INF_PCD
- List = GetSplitValueList(Item, DataType.TAB_VALUE_SPLIT, 1)
- TokenInfo = GetSplitValueList(List[0], DataType.TAB_SPLIT)
- if len(TokenInfo) != 2:
- RaiseParserError(Item, InfType, File, Format, LineNo)
- else:
- TokenGuid = TokenInfo[0]
- TokenName = TokenInfo[1]
-
- if len(List) > 1:
- Value = List[1]
- else:
- Value = None
- return (TokenGuid, TokenName, Value, InfType)
-
-
-## Get Pcd Values of Dec
-#
-# Get Pcd of Dec as <TokenSpcCName>.<TokenCName>|<Value>|<DatumType>|<Token>
-# @param Item: Pcd item
-# @param Type: Pcd type
-# @param File: Dec file
-# @param LineNo: Line number
-#
-def GetPcdOfDec(Item, Type, File, LineNo= -1):
- Format = '<TokenSpaceGuidCName>.<PcdCName>|<Value>|<DatumType>|<Token>'
- TokenGuid, TokenName, Value, DatumType, Token = '', '', '', '', ''
- List = GetSplitValueList(Item)
- if len(List) != 4:
- RaiseParserError(Item, 'Pcds' + Type, File, Format, LineNo)
- else:
- Value = List[1]
- DatumType = List[2]
- Token = List[3]
- TokenInfo = GetSplitValueList(List[0], DataType.TAB_SPLIT)
- if len(TokenInfo) != 2:
- RaiseParserError(Item, 'Pcds' + Type, File, Format, LineNo)
- else:
- TokenGuid = TokenInfo[0]
- TokenName = TokenInfo[1]
-
- return (TokenGuid, TokenName, Value, DatumType, Token, Type)
-
-## Parse DEFINE statement
-#
-# Get DEFINE macros
-#
-# @param LineValue: A DEFINE line value
-# @param StartLine: A DEFINE start line
-# @param Table: A table
-# @param FileID: File ID
-# @param Filename: File name
-# @param SectionName: DEFINE section name
-# @param SectionModel: DEFINE section model
-# @param Arch: DEFINE arch
-#
-def ParseDefine(LineValue, StartLine, Table, FileID, SectionName, \
- SectionModel, Arch):
- Logger.Debug(Logger.DEBUG_2, ST.MSG_DEFINE_STATEMENT_FOUND % (LineValue, \
- SectionName))
- Define = \
- GetSplitValueList(CleanString\
- (LineValue[LineValue.upper().\
- find(DataType.TAB_DEFINE.upper() + ' ') + \
- len(DataType.TAB_DEFINE + ' ') : ]), \
- DataType.TAB_EQUAL_SPLIT, 1)
- Table.Insert(DataType.MODEL_META_DATA_DEFINE, Define[0], Define[1], '', \
- '', '', Arch, SectionModel, FileID, StartLine, -1, \
- StartLine, -1, 0)
-
-## InsertSectionItems
-#
-# Insert item data of a section to a dict
-#
-# @param Model: A model
-# @param CurrentSection: Current section
-# @param SectionItemList: Section item list
-# @param ArchList: Arch list
-# @param ThirdList: Third list
-# @param RecordSet: Record set
-#
-def InsertSectionItems(Model, SectionItemList, ArchList, \
- ThirdList, RecordSet):
- #
- # Insert each item data of a section
- #
- for Index in range(0, len(ArchList)):
- Arch = ArchList[Index]
- Third = ThirdList[Index]
- if Arch == '':
- Arch = DataType.TAB_ARCH_COMMON
-
- Records = RecordSet[Model]
- for SectionItem in SectionItemList:
- LineValue, StartLine, Comment = SectionItem[0], \
- SectionItem[1], SectionItem[2]
-
- Logger.Debug(4, ST.MSG_PARSING % LineValue)
- #
- # And then parse DEFINE statement
- #
- if LineValue.upper().find(DataType.TAB_DEFINE.upper() + ' ') > -1:
- continue
- #
- # At last parse other sections
- #
- IdNum = -1
- Records.append([LineValue, Arch, StartLine, IdNum, Third, Comment])
-
- if RecordSet != {}:
- RecordSet[Model] = Records
-
-## GenMetaDatSectionItem
-#
-# @param Key: A key
-# @param Value: A value
-# @param List: A list
-#
-def GenMetaDatSectionItem(Key, Value, List):
- if Key not in List:
- List[Key] = [Value]
- else:
- List[Key].append(Value)
-
-## GetPkgInfoFromDec
-#
-# get package name, guid, version info from dec files
-#
-# @param Path: File path
-#
-def GetPkgInfoFromDec(Path):
- PkgName = None
- PkgGuid = None
- PkgVersion = None
-
- Path = Path.replace('\\', '/')
-
- if not os.path.exists(Path):
- Logger.Error("\nUPT", FILE_NOT_FOUND, File=Path)
-
- if Path in gPKG_INFO_DICT:
- return gPKG_INFO_DICT[Path]
-
- try:
- DecParser = None
- if Path not in GlobalData.gPackageDict:
- DecParser = Dec(Path)
- GlobalData.gPackageDict[Path] = DecParser
- else:
- DecParser = GlobalData.gPackageDict[Path]
-
- PkgName = DecParser.GetPackageName()
- PkgGuid = DecParser.GetPackageGuid()
- PkgVersion = DecParser.GetPackageVersion()
- gPKG_INFO_DICT[Path] = (PkgName, PkgGuid, PkgVersion)
- return PkgName, PkgGuid, PkgVersion
- except FatalError:
- return None, None, None
-
-
-## GetWorkspacePackage
-#
-# Get a list of workspace package information.
-#
-def GetWorkspacePackage():
- DecFileList = []
- WorkspaceDir = GlobalData.gWORKSPACE
- PackageDir = GlobalData.gPACKAGE_PATH
- for PkgRoot in [WorkspaceDir] + PackageDir:
- for Root, Dirs, Files in os.walk(PkgRoot):
- if 'CVS' in Dirs:
- Dirs.remove('CVS')
- if '.svn' in Dirs:
- Dirs.remove('.svn')
- for Dir in Dirs:
- if Dir.startswith('.'):
- Dirs.remove(Dir)
- for FileSp in Files:
- if FileSp.startswith('.'):
- continue
- Ext = os.path.splitext(FileSp)[1]
- if Ext.lower() in ['.dec']:
- DecFileList.append\
- (os.path.normpath(os.path.join(Root, FileSp)))
- #
- # abstract package guid, version info from DecFile List
- #
- PkgList = []
- for DecFile in DecFileList:
- (PkgName, PkgGuid, PkgVersion) = GetPkgInfoFromDec(DecFile)
- if PkgName and PkgGuid and PkgVersion:
- PkgList.append((PkgName, PkgGuid, PkgVersion, DecFile))
-
- return PkgList
-
-## GetWorkspaceModule
-#
-# Get a list of workspace modules.
-#
-def GetWorkspaceModule():
- InfFileList = []
- WorkspaceDir = GlobalData.gWORKSPACE
- for Root, Dirs, Files in os.walk(WorkspaceDir):
- if 'CVS' in Dirs:
- Dirs.remove('CVS')
- if '.svn' in Dirs:
- Dirs.remove('.svn')
- if 'Build' in Dirs:
- Dirs.remove('Build')
- for Dir in Dirs:
- if Dir.startswith('.'):
- Dirs.remove(Dir)
- for FileSp in Files:
- if FileSp.startswith('.'):
- continue
- Ext = os.path.splitext(FileSp)[1]
- if Ext.lower() in ['.inf']:
- InfFileList.append\
- (os.path.normpath(os.path.join(Root, FileSp)))
-
- return InfFileList
-
-## MacroParser used to parse macro definition
-#
-# @param Line: The content contain linestring and line number
-# @param FileName: The meta-file file name
-# @param SectionType: Section for the Line belong to
-# @param FileLocalMacros: A list contain Macro defined in [Defines] section.
-#
-def MacroParser(Line, FileName, SectionType, FileLocalMacros):
- MacroDefPattern = re.compile("^(DEFINE)[ \t]+")
- LineContent = Line[0]
- LineNo = Line[1]
- Match = MacroDefPattern.match(LineContent)
- if not Match:
- #
- # Not 'DEFINE/EDK_GLOBAL' statement, call decorated method
- #
- return None, None
-
- TokenList = GetSplitValueList(LineContent[Match.end(1):], \
- DataType.TAB_EQUAL_SPLIT, 1)
- #
- # Syntax check
- #
- if not TokenList[0]:
- Logger.Error('Parser', FORMAT_INVALID, ST.ERR_MACRONAME_NOGIVEN,
- ExtraData=LineContent, File=FileName, Line=LineNo)
- if len(TokenList) < 2:
- Logger.Error('Parser', FORMAT_INVALID, ST.ERR_MACROVALUE_NOGIVEN,
- ExtraData=LineContent, File=FileName, Line=LineNo)
-
- Name, Value = TokenList
-
- #
- # DEFINE defined macros
- #
- if SectionType == DataType.MODEL_META_DATA_HEADER:
- FileLocalMacros[Name] = Value
-
- ReIsValidMacroName = re.compile(r"^[A-Z][A-Z0-9_]*$", re.DOTALL)
- if ReIsValidMacroName.match(Name) is None:
- Logger.Error('Parser',
- FORMAT_INVALID,
- ST.ERR_MACRONAME_INVALID % (Name),
- ExtraData=LineContent,
- File=FileName,
- Line=LineNo)
-
- # Validate MACRO Value
- #
- # <MacroDefinition> ::= [<Comments>]{0,}
- # "DEFINE" <MACRO> "=" [{<PATH>} {<VALUE>}] <EOL>
- # <Value> ::= {<NumVal>} {<Boolean>} {<AsciiString>} {<GUID>}
- # {<CString>} {<UnicodeString>} {<CArray>}
- #
- # The definition of <NumVal>, <PATH>, <Boolean>, <GUID>, <CString>,
- # <UnicodeString>, <CArray> are subset of <AsciiString>.
- #
- ReIsValidMacroValue = re.compile(r"^[\x20-\x7e]*$", re.DOTALL)
- if ReIsValidMacroValue.match(Value) is None:
- Logger.Error('Parser',
- FORMAT_INVALID,
- ST.ERR_MACROVALUE_INVALID % (Value),
- ExtraData=LineContent,
- File=FileName,
- Line=LineNo)
-
- return Name, Value
-
-## GenSection
-#
-# generate section contents
-#
-# @param SectionName: indicate the name of the section, details refer to
-# INF, DEC specs
-# @param SectionDict: section statement dict, key is SectionAttrs(arch,
-# moduletype or platform may exist as needed) list
-# separated by space,
-# value is statement
-#
-def GenSection(SectionName, SectionDict, SplitArch=True, NeedBlankLine=False):
- Content = ''
- for SectionAttrs in SectionDict:
- StatementList = SectionDict[SectionAttrs]
- if SectionAttrs and SectionName != 'Defines' and SectionAttrs.strip().upper() != DataType.TAB_ARCH_COMMON:
- if SplitArch:
- ArchList = GetSplitValueList(SectionAttrs, DataType.TAB_SPACE_SPLIT)
- else:
- if SectionName != 'UserExtensions':
- ArchList = GetSplitValueList(SectionAttrs, DataType.TAB_COMMENT_SPLIT)
- else:
- ArchList = [SectionAttrs]
- for Index in range(0, len(ArchList)):
- ArchList[Index] = ConvertArchForInstall(ArchList[Index])
- Section = '[' + SectionName + '.' + (', ' + SectionName + '.').join(ArchList) + ']'
- else:
- Section = '[' + SectionName + ']'
- Content += '\n' + Section + '\n'
- if StatementList is not None:
- for Statement in StatementList:
- LineList = Statement.split('\n')
- NewStatement = ""
- for Line in LineList:
- # ignore blank comment
- if not Line.replace("#", '').strip() and SectionName not in ('Defines', 'Hob', 'Event', 'BootMode'):
- continue
- # add two space before non-comments line except the comments in Defines section
- if Line.strip().startswith('#') and SectionName == 'Defines':
- NewStatement += "%s\n" % Line
- continue
- NewStatement += " %s\n" % Line
- if NeedBlankLine:
- Content += NewStatement + '\n'
- else:
- Content += NewStatement
-
- if NeedBlankLine:
- Content = Content[:-1]
- if not Content.replace('\\n', '').strip():
- return ''
- return Content
-
-## ConvertArchForInstall
-# if Arch.upper() is in "IA32", "X64", "IPF", and "EBC", it must be upper case. "common" must be lower case.
-# Anything else, the case must be preserved
-#
-# @param Arch: the arch string that need to be converted, it should be stripped before pass in
-# @return: the arch string that get converted
-#
-def ConvertArchForInstall(Arch):
- if Arch.upper() in [DataType.TAB_ARCH_IA32, DataType.TAB_ARCH_X64,
- DataType.TAB_ARCH_IPF, DataType.TAB_ARCH_EBC]:
- Arch = Arch.upper()
- elif Arch.upper() == DataType.TAB_ARCH_COMMON:
- Arch = Arch.lower()
-
- return Arch
+## @file +# This file is used to define common parsing related functions used in parsing +# INF/DEC/DSC process +# +# Copyright (c) 2011 - 2018, Intel Corporation. All rights reserved.<BR> +# +# SPDX-License-Identifier: BSD-2-Clause-Patent +# + +''' +Parsing +''' +from __future__ import absolute_import + +## +# Import Modules +# +import os.path +import re + +from Library.StringUtils import RaiseParserError +from Library.StringUtils import GetSplitValueList +from Library.StringUtils import CheckFileType +from Library.StringUtils import CheckFileExist +from Library.StringUtils import CleanString +from Library.StringUtils import NormPath + +from Logger.ToolError import FILE_NOT_FOUND +from Logger.ToolError import FatalError +from Logger.ToolError import FORMAT_INVALID + +from Library import DataType + +from Library.Misc import GuidStructureStringToGuidString +from Library.Misc import CheckGuidRegFormat +from Logger import StringTable as ST +import Logger.Log as Logger + +from Parser.DecParser import Dec +from . import GlobalData + +gPKG_INFO_DICT = {} + +## GetBuildOption +# +# Parse a string with format "[<Family>:]<ToolFlag>=Flag" +# Return (Family, ToolFlag, Flag) +# +# @param String: String with BuildOption statement +# @param File: The file which defines build option, used in error report +# +def GetBuildOption(String, File, LineNo= -1): + (Family, ToolChain, Flag) = ('', '', '') + if String.find(DataType.TAB_EQUAL_SPLIT) < 0: + RaiseParserError(String, 'BuildOptions', File, \ + '[<Family>:]<ToolFlag>=Flag', LineNo) + else: + List = GetSplitValueList(String, DataType.TAB_EQUAL_SPLIT, MaxSplit=1) + if List[0].find(':') > -1: + Family = List[0][ : List[0].find(':')].strip() + ToolChain = List[0][List[0].find(':') + 1 : ].strip() + else: + ToolChain = List[0].strip() + Flag = List[1].strip() + return (Family, ToolChain, Flag) + +## Get Library Class +# +# Get Library of Dsc as <LibraryClassKeyWord>|<LibraryInstance> +# +# @param Item: String as <LibraryClassKeyWord>|<LibraryInstance> +# @param ContainerFile: The file which describes the library class, used for +# error report +# +def GetLibraryClass(Item, ContainerFile, WorkspaceDir, LineNo= -1): + List = GetSplitValueList(Item[0]) + SupMod = DataType.SUP_MODULE_LIST_STRING + if len(List) != 2: + RaiseParserError(Item[0], 'LibraryClasses', ContainerFile, \ + '<LibraryClassKeyWord>|<LibraryInstance>') + else: + CheckFileType(List[1], '.Inf', ContainerFile, \ + 'library class instance', Item[0], LineNo) + CheckFileExist(WorkspaceDir, List[1], ContainerFile, \ + 'LibraryClasses', Item[0], LineNo) + if Item[1] != '': + SupMod = Item[1] + + return (List[0], List[1], SupMod) + +## Get Library Class +# +# Get Library of Dsc as <LibraryClassKeyWord>[|<LibraryInstance>] +# [|<TokenSpaceGuidCName>.<PcdCName>] +# +# @param Item: String as <LibraryClassKeyWord>|<LibraryInstance> +# @param ContainerFile: The file which describes the library class, used for +# error report +# +def GetLibraryClassOfInf(Item, ContainerFile, WorkspaceDir, LineNo= -1): + ItemList = GetSplitValueList((Item[0] + DataType.TAB_VALUE_SPLIT * 2)) + SupMod = DataType.SUP_MODULE_LIST_STRING + + if len(ItemList) > 5: + RaiseParserError\ + (Item[0], 'LibraryClasses', ContainerFile, \ + '<LibraryClassKeyWord>[|<LibraryInstance>]\ + [|<TokenSpaceGuidCName>.<PcdCName>]') + else: + CheckFileType(ItemList[1], '.Inf', ContainerFile, 'LibraryClasses', \ + Item[0], LineNo) + CheckFileExist(WorkspaceDir, ItemList[1], ContainerFile, \ + 'LibraryClasses', Item[0], LineNo) + if ItemList[2] != '': + CheckPcdTokenInfo(ItemList[2], 'LibraryClasses', \ + ContainerFile, LineNo) + if Item[1] != '': + SupMod = Item[1] + + return (ItemList[0], ItemList[1], ItemList[2], SupMod) + +## CheckPcdTokenInfo +# +# Check if PcdTokenInfo is following <TokenSpaceGuidCName>.<PcdCName> +# +# @param TokenInfoString: String to be checked +# @param Section: Used for error report +# @param File: Used for error report +# +def CheckPcdTokenInfo(TokenInfoString, Section, File, LineNo= -1): + Format = '<TokenSpaceGuidCName>.<PcdCName>' + if TokenInfoString != '' and TokenInfoString is not None: + TokenInfoList = GetSplitValueList(TokenInfoString, DataType.TAB_SPLIT) + if len(TokenInfoList) == 2: + return True + + RaiseParserError(TokenInfoString, Section, File, Format, LineNo) + +## Get Pcd +# +# Get Pcd of Dsc as <PcdTokenSpaceGuidCName>.<TokenCName>|<Value> +# [|<Type>|<MaximumDatumSize>] +# +# @param Item: String as <PcdTokenSpaceGuidCName>.<TokenCName>| +# <Value>[|<Type>|<MaximumDatumSize>] +# @param ContainerFile: The file which describes the pcd, used for error +# report + +# +def GetPcd(Item, Type, ContainerFile, LineNo= -1): + TokenGuid, TokenName, Value, MaximumDatumSize, Token = '', '', '', '', '' + List = GetSplitValueList(Item + DataType.TAB_VALUE_SPLIT * 2) + + if len(List) < 4 or len(List) > 6: + RaiseParserError(Item, 'Pcds' + Type, ContainerFile, \ + '<PcdTokenSpaceGuidCName>.<TokenCName>|<Value>\ + [|<Type>|<MaximumDatumSize>]', LineNo) + else: + Value = List[1] + MaximumDatumSize = List[2] + Token = List[3] + + if CheckPcdTokenInfo(List[0], 'Pcds' + Type, ContainerFile, LineNo): + (TokenGuid, TokenName) = GetSplitValueList(List[0], DataType.TAB_SPLIT) + + return (TokenName, TokenGuid, Value, MaximumDatumSize, Token, Type) + +## Get FeatureFlagPcd +# +# Get FeatureFlagPcd of Dsc as <PcdTokenSpaceGuidCName>.<TokenCName>|TRUE/FALSE +# +# @param Item: String as <PcdTokenSpaceGuidCName> +# .<TokenCName>|TRUE/FALSE +# @param ContainerFile: The file which describes the pcd, used for error +# report +# +def GetFeatureFlagPcd(Item, Type, ContainerFile, LineNo= -1): + TokenGuid, TokenName, Value = '', '', '' + List = GetSplitValueList(Item) + if len(List) != 2: + RaiseParserError(Item, 'Pcds' + Type, ContainerFile, \ + '<PcdTokenSpaceGuidCName>.<TokenCName>|TRUE/FALSE', \ + LineNo) + else: + Value = List[1] + if CheckPcdTokenInfo(List[0], 'Pcds' + Type, ContainerFile, LineNo): + (TokenGuid, TokenName) = GetSplitValueList(List[0], DataType.TAB_SPLIT) + + return (TokenName, TokenGuid, Value, Type) + +## Get DynamicDefaultPcd +# +# Get DynamicDefaultPcd of Dsc as <PcdTokenSpaceGuidCName>.<TokenCName> +# |<Value>[|<DatumTyp>[|<MaxDatumSize>]] +# +# @param Item: String as <PcdTokenSpaceGuidCName>.<TokenCName>| +# TRUE/FALSE +# @param ContainerFile: The file which describes the pcd, used for error +# report +# +def GetDynamicDefaultPcd(Item, Type, ContainerFile, LineNo= -1): + TokenGuid, TokenName, Value, DatumTyp, MaxDatumSize = '', '', '', '', '' + List = GetSplitValueList(Item + DataType.TAB_VALUE_SPLIT * 2) + if len(List) < 4 or len(List) > 8: + RaiseParserError(Item, 'Pcds' + Type, ContainerFile, \ + '<PcdTokenSpaceGuidCName>.<TokenCName>|<Value>\ + [|<DatumTyp>[|<MaxDatumSize>]]', LineNo) + else: + Value = List[1] + DatumTyp = List[2] + MaxDatumSize = List[3] + if CheckPcdTokenInfo(List[0], 'Pcds' + Type, ContainerFile, LineNo): + (TokenGuid, TokenName) = GetSplitValueList(List[0], DataType.TAB_SPLIT) + + return (TokenName, TokenGuid, Value, DatumTyp, MaxDatumSize, Type) + +## Get DynamicHiiPcd +# +# Get DynamicHiiPcd of Dsc as <PcdTokenSpaceGuidCName>.<TokenCName>|<String>| +# <VariableGuidCName>|<VariableOffset>[|<DefaultValue>[|<MaximumDatumSize>]] +# +# @param Item: String as <PcdTokenSpaceGuidCName>.<TokenCName>| +# TRUE/FALSE +# @param ContainerFile: The file which describes the pcd, used for error +# report +# +def GetDynamicHiiPcd(Item, Type, ContainerFile, LineNo= -1): + TokenGuid, TokenName, List1, List2, List3, List4, List5 = \ + '', '', '', '', '', '', '' + List = GetSplitValueList(Item + DataType.TAB_VALUE_SPLIT * 2) + if len(List) < 6 or len(List) > 8: + RaiseParserError(Item, 'Pcds' + Type, ContainerFile, \ + '<PcdTokenSpaceGuidCName>.<TokenCName>|<String>|\ + <VariableGuidCName>|<VariableOffset>[|<DefaultValue>\ + [|<MaximumDatumSize>]]', LineNo) + else: + List1, List2, List3, List4, List5 = \ + List[1], List[2], List[3], List[4], List[5] + if CheckPcdTokenInfo(List[0], 'Pcds' + Type, ContainerFile, LineNo): + (TokenGuid, TokenName) = GetSplitValueList(List[0], DataType.TAB_SPLIT) + + return (TokenName, TokenGuid, List1, List2, List3, List4, List5, Type) + +## Get DynamicVpdPcd +# +# Get DynamicVpdPcd of Dsc as <PcdTokenSpaceGuidCName>.<TokenCName>| +# <VpdOffset>[|<MaximumDatumSize>] +# +# @param Item: String as <PcdTokenSpaceGuidCName>.<TokenCName> +# |TRUE/FALSE +# @param ContainerFile: The file which describes the pcd, used for error +# report +# +def GetDynamicVpdPcd(Item, Type, ContainerFile, LineNo= -1): + TokenGuid, TokenName, List1, List2 = '', '', '', '' + List = GetSplitValueList(Item + DataType.TAB_VALUE_SPLIT) + if len(List) < 3 or len(List) > 4: + RaiseParserError(Item, 'Pcds' + Type, ContainerFile, \ + '<PcdTokenSpaceGuidCName>.<TokenCName>|<VpdOffset>\ + [|<MaximumDatumSize>]', LineNo) + else: + List1, List2 = List[1], List[2] + if CheckPcdTokenInfo(List[0], 'Pcds' + Type, ContainerFile, LineNo): + (TokenGuid, TokenName) = GetSplitValueList(List[0], DataType.TAB_SPLIT) + + return (TokenName, TokenGuid, List1, List2, Type) + +## GetComponent +# +# Parse block of the components defined in dsc file +# Set KeyValues as [ ['component name', [lib1, lib2, lib3], +# [bo1, bo2, bo3], [pcd1, pcd2, pcd3]], ...] +# +# @param Lines: The content to be parsed +# @param KeyValues: To store data after parsing +# +def GetComponent(Lines, KeyValues): + (FindBlock, FindLibraryClass, FindBuildOption, FindPcdsFeatureFlag, \ + FindPcdsPatchableInModule, FindPcdsFixedAtBuild, FindPcdsDynamic, \ + FindPcdsDynamicEx) = (False, False, False, False, False, False, False, \ + False) + ListItem = None + LibraryClassItem = [] + BuildOption = [] + Pcd = [] + + for Line in Lines: + Line = Line[0] + # + # Ignore !include statement + # + if Line.upper().find(DataType.TAB_INCLUDE.upper() + ' ') > -1 or \ + Line.upper().find(DataType.TAB_DEFINE + ' ') > -1: + continue + + if FindBlock == False: + ListItem = Line + # + # find '{' at line tail + # + if Line.endswith('{'): + FindBlock = True + ListItem = CleanString(Line.rsplit('{', 1)[0], \ + DataType.TAB_COMMENT_SPLIT) + + # + # Parse a block content + # + if FindBlock: + if Line.find('<LibraryClasses>') != -1: + (FindLibraryClass, FindBuildOption, FindPcdsFeatureFlag, \ + FindPcdsPatchableInModule, FindPcdsFixedAtBuild, \ + FindPcdsDynamic, FindPcdsDynamicEx) = \ + (True, False, False, False, False, False, False) + continue + if Line.find('<BuildOptions>') != -1: + (FindLibraryClass, FindBuildOption, FindPcdsFeatureFlag, \ + FindPcdsPatchableInModule, FindPcdsFixedAtBuild, \ + FindPcdsDynamic, FindPcdsDynamicEx) = \ + (False, True, False, False, False, False, False) + continue + if Line.find('<PcdsFeatureFlag>') != -1: + (FindLibraryClass, FindBuildOption, FindPcdsFeatureFlag, \ + FindPcdsPatchableInModule, FindPcdsFixedAtBuild, \ + FindPcdsDynamic, FindPcdsDynamicEx) = \ + (False, False, True, False, False, False, False) + continue + if Line.find('<PcdsPatchableInModule>') != -1: + (FindLibraryClass, FindBuildOption, FindPcdsFeatureFlag, \ + FindPcdsPatchableInModule, FindPcdsFixedAtBuild, \ + FindPcdsDynamic, FindPcdsDynamicEx) = \ + (False, False, False, True, False, False, False) + continue + if Line.find('<PcdsFixedAtBuild>') != -1: + (FindLibraryClass, FindBuildOption, FindPcdsFeatureFlag, \ + FindPcdsPatchableInModule, FindPcdsFixedAtBuild, \ + FindPcdsDynamic, FindPcdsDynamicEx) = \ + (False, False, False, False, True, False, False) + continue + if Line.find('<PcdsDynamic>') != -1: + (FindLibraryClass, FindBuildOption, FindPcdsFeatureFlag, \ + FindPcdsPatchableInModule, FindPcdsFixedAtBuild, \ + FindPcdsDynamic, FindPcdsDynamicEx) = \ + (False, False, False, False, False, True, False) + continue + if Line.find('<PcdsDynamicEx>') != -1: + (FindLibraryClass, FindBuildOption, FindPcdsFeatureFlag, \ + FindPcdsPatchableInModule, FindPcdsFixedAtBuild, \ + FindPcdsDynamic, FindPcdsDynamicEx) = \ + (False, False, False, False, False, False, True) + continue + if Line.endswith('}'): + # + # find '}' at line tail + # + KeyValues.append([ListItem, LibraryClassItem, \ + BuildOption, Pcd]) + (FindBlock, FindLibraryClass, FindBuildOption, \ + FindPcdsFeatureFlag, FindPcdsPatchableInModule, \ + FindPcdsFixedAtBuild, FindPcdsDynamic, FindPcdsDynamicEx) = \ + (False, False, False, False, False, False, False, False) + LibraryClassItem, BuildOption, Pcd = [], [], [] + continue + + if FindBlock: + if FindLibraryClass: + LibraryClassItem.append(Line) + elif FindBuildOption: + BuildOption.append(Line) + elif FindPcdsFeatureFlag: + Pcd.append((DataType.TAB_PCDS_FEATURE_FLAG_NULL, Line)) + elif FindPcdsPatchableInModule: + Pcd.append((DataType.TAB_PCDS_PATCHABLE_IN_MODULE_NULL, Line)) + elif FindPcdsFixedAtBuild: + Pcd.append((DataType.TAB_PCDS_FIXED_AT_BUILD_NULL, Line)) + elif FindPcdsDynamic: + Pcd.append((DataType.TAB_PCDS_DYNAMIC_DEFAULT_NULL, Line)) + elif FindPcdsDynamicEx: + Pcd.append((DataType.TAB_PCDS_DYNAMIC_EX_DEFAULT_NULL, Line)) + else: + KeyValues.append([ListItem, [], [], []]) + + return True + +## GetExec +# +# Parse a string with format "InfFilename [EXEC = ExecFilename]" +# Return (InfFilename, ExecFilename) +# +# @param String: String with EXEC statement +# +def GetExec(String): + InfFilename = '' + ExecFilename = '' + if String.find('EXEC') > -1: + InfFilename = String[ : String.find('EXEC')].strip() + ExecFilename = String[String.find('EXEC') + len('EXEC') : ].strip() + else: + InfFilename = String.strip() + + return (InfFilename, ExecFilename) + +## GetComponents +# +# Parse block of the components defined in dsc file +# Set KeyValues as [ ['component name', [lib1, lib2, lib3], [bo1, bo2, bo3], +# [pcd1, pcd2, pcd3]], ...] +# +# @param Lines: The content to be parsed +# @param Key: Reserved +# @param KeyValues: To store data after parsing +# @param CommentCharacter: Comment char, used to ignore comment content +# +# @retval True Get component successfully +# +def GetComponents(Lines, KeyValues, CommentCharacter): + if Lines.find(DataType.TAB_SECTION_END) > -1: + Lines = Lines.split(DataType.TAB_SECTION_END, 1)[1] + (FindBlock, FindLibraryClass, FindBuildOption, FindPcdsFeatureFlag, \ + FindPcdsPatchableInModule, FindPcdsFixedAtBuild, FindPcdsDynamic, \ + FindPcdsDynamicEx) = \ + (False, False, False, False, False, False, False, False) + ListItem = None + LibraryClassItem = [] + BuildOption = [] + Pcd = [] + + LineList = Lines.split('\n') + for Line in LineList: + Line = CleanString(Line, CommentCharacter) + if Line is None or Line == '': + continue + + if FindBlock == False: + ListItem = Line + # + # find '{' at line tail + # + if Line.endswith('{'): + FindBlock = True + ListItem = CleanString(Line.rsplit('{', 1)[0], CommentCharacter) + + # + # Parse a block content + # + if FindBlock: + if Line.find('<LibraryClasses>') != -1: + (FindLibraryClass, FindBuildOption, FindPcdsFeatureFlag, \ + FindPcdsPatchableInModule, FindPcdsFixedAtBuild, \ + FindPcdsDynamic, FindPcdsDynamicEx) = \ + (True, False, False, False, False, False, False) + continue + if Line.find('<BuildOptions>') != -1: + (FindLibraryClass, FindBuildOption, FindPcdsFeatureFlag, \ + FindPcdsPatchableInModule, FindPcdsFixedAtBuild, \ + FindPcdsDynamic, FindPcdsDynamicEx) = \ + (False, True, False, False, False, False, False) + continue + if Line.find('<PcdsFeatureFlag>') != -1: + (FindLibraryClass, FindBuildOption, FindPcdsFeatureFlag, \ + FindPcdsPatchableInModule, FindPcdsFixedAtBuild, \ + FindPcdsDynamic, FindPcdsDynamicEx) = \ + (False, False, True, False, False, False, False) + continue + if Line.find('<PcdsPatchableInModule>') != -1: + (FindLibraryClass, FindBuildOption, FindPcdsFeatureFlag, \ + FindPcdsPatchableInModule, FindPcdsFixedAtBuild, \ + FindPcdsDynamic, FindPcdsDynamicEx) = \ + (False, False, False, True, False, False, False) + continue + if Line.find('<PcdsFixedAtBuild>') != -1: + (FindLibraryClass, FindBuildOption, FindPcdsFeatureFlag, \ + FindPcdsPatchableInModule, FindPcdsFixedAtBuild, \ + FindPcdsDynamic, FindPcdsDynamicEx) = \ + (False, False, False, False, True, False, False) + continue + if Line.find('<PcdsDynamic>') != -1: + (FindLibraryClass, FindBuildOption, FindPcdsFeatureFlag, \ + FindPcdsPatchableInModule, FindPcdsFixedAtBuild, \ + FindPcdsDynamic, FindPcdsDynamicEx) = \ + (False, False, False, False, False, True, False) + continue + if Line.find('<PcdsDynamicEx>') != -1: + (FindLibraryClass, FindBuildOption, FindPcdsFeatureFlag, \ + FindPcdsPatchableInModule, FindPcdsFixedAtBuild, \ + FindPcdsDynamic, FindPcdsDynamicEx) = \ + (False, False, False, False, False, False, True) + continue + if Line.endswith('}'): + # + # find '}' at line tail + # + KeyValues.append([ListItem, LibraryClassItem, BuildOption, \ + Pcd]) + (FindBlock, FindLibraryClass, FindBuildOption, \ + FindPcdsFeatureFlag, FindPcdsPatchableInModule, \ + FindPcdsFixedAtBuild, FindPcdsDynamic, FindPcdsDynamicEx) = \ + (False, False, False, False, False, False, False, False) + LibraryClassItem, BuildOption, Pcd = [], [], [] + continue + + if FindBlock: + if FindLibraryClass: + LibraryClassItem.append(Line) + elif FindBuildOption: + BuildOption.append(Line) + elif FindPcdsFeatureFlag: + Pcd.append((DataType.TAB_PCDS_FEATURE_FLAG, Line)) + elif FindPcdsPatchableInModule: + Pcd.append((DataType.TAB_PCDS_PATCHABLE_IN_MODULE, Line)) + elif FindPcdsFixedAtBuild: + Pcd.append((DataType.TAB_PCDS_FIXED_AT_BUILD, Line)) + elif FindPcdsDynamic: + Pcd.append((DataType.TAB_PCDS_DYNAMIC, Line)) + elif FindPcdsDynamicEx: + Pcd.append((DataType.TAB_PCDS_DYNAMIC_EX, Line)) + else: + KeyValues.append([ListItem, [], [], []]) + + return True + +## Get Source +# +# Get Source of Inf as <Filename>[|<Family>[|<TagName>[|<ToolCode> +# [|<PcdFeatureFlag>]]]] +# +# @param Item: String as <Filename>[|<Family>[|<TagName>[|<ToolCode> +# [|<PcdFeatureFlag>]]]] +# @param ContainerFile: The file which describes the library class, used +# for error report +# +def GetSource(Item, ContainerFile, FileRelativePath, LineNo= -1): + ItemNew = Item + DataType.TAB_VALUE_SPLIT * 4 + List = GetSplitValueList(ItemNew) + if len(List) < 5 or len(List) > 9: + RaiseParserError(Item, 'Sources', ContainerFile, \ + '<Filename>[|<Family>[|<TagName>[|<ToolCode>\ + [|<PcdFeatureFlag>]]]]', LineNo) + List[0] = NormPath(List[0]) + CheckFileExist(FileRelativePath, List[0], ContainerFile, 'Sources', \ + Item, LineNo) + if List[4] != '': + CheckPcdTokenInfo(List[4], 'Sources', ContainerFile, LineNo) + + return (List[0], List[1], List[2], List[3], List[4]) + +## Get Binary +# +# Get Binary of Inf as <Filename>[|<Family>[|<TagName>[|<ToolCode> +# [|<PcdFeatureFlag>]]]] +# +# @param Item: String as <Filename>[|<Family>[|<TagName> +# [|<ToolCode>[|<PcdFeatureFlag>]]]] +# @param ContainerFile: The file which describes the library class, +# used for error report +# +def GetBinary(Item, ContainerFile, LineNo= -1): + ItemNew = Item + DataType.TAB_VALUE_SPLIT + List = GetSplitValueList(ItemNew) + if len(List) < 3 or len(List) > 5: + RaiseParserError(Item, 'Binaries', ContainerFile, \ + "<FileType>|<Filename>[|<Target>\ + [|<TokenSpaceGuidCName>.<PcdCName>]]", LineNo) + + if len(List) >= 4: + if List[3] != '': + CheckPcdTokenInfo(List[3], 'Binaries', ContainerFile, LineNo) + return (List[0], List[1], List[2], List[3]) + elif len(List) == 3: + return (List[0], List[1], List[2], '') + +## Get Guids/Protocols/Ppis +# +# Get Guids/Protocols/Ppis of Inf as <GuidCName>[|<PcdFeatureFlag>] +# +# @param Item: String as <GuidCName>[|<PcdFeatureFlag>] +# @param Type: Type of parsing string +# @param ContainerFile: The file which describes the library class, +# used for error report +# +def GetGuidsProtocolsPpisOfInf(Item): + ItemNew = Item + DataType.TAB_VALUE_SPLIT + List = GetSplitValueList(ItemNew) + return (List[0], List[1]) + +## Get Guids/Protocols/Ppis +# +# Get Guids/Protocols/Ppis of Dec as <GuidCName>=<GuidValue> +# +# @param Item: String as <GuidCName>=<GuidValue> +# @param Type: Type of parsing string +# @param ContainerFile: The file which describes the library class, +# used for error report +# +def GetGuidsProtocolsPpisOfDec(Item, Type, ContainerFile, LineNo= -1): + List = GetSplitValueList(Item, DataType.TAB_EQUAL_SPLIT) + if len(List) != 2: + RaiseParserError(Item, Type, ContainerFile, '<CName>=<GuidValue>', \ + LineNo) + # + #convert C-Format Guid to Register Format + # + if List[1][0] == '{' and List[1][-1] == '}': + RegisterFormatGuid = GuidStructureStringToGuidString(List[1]) + if RegisterFormatGuid == '': + RaiseParserError(Item, Type, ContainerFile, \ + 'CFormat or RegisterFormat', LineNo) + else: + if CheckGuidRegFormat(List[1]): + RegisterFormatGuid = List[1] + else: + RaiseParserError(Item, Type, ContainerFile, \ + 'CFormat or RegisterFormat', LineNo) + + return (List[0], RegisterFormatGuid) + +## GetPackage +# +# Get Package of Inf as <PackagePath>[|<PcdFeatureFlag>] +# +# @param Item: String as <PackagePath>[|<PcdFeatureFlag>] +# @param Type: Type of parsing string +# @param ContainerFile: The file which describes the library class, +# used for error report +# +def GetPackage(Item, ContainerFile, FileRelativePath, LineNo= -1): + ItemNew = Item + DataType.TAB_VALUE_SPLIT + List = GetSplitValueList(ItemNew) + CheckFileType(List[0], '.Dec', ContainerFile, 'package', List[0], LineNo) + CheckFileExist(FileRelativePath, List[0], ContainerFile, 'Packages', \ + List[0], LineNo) + if List[1] != '': + CheckPcdTokenInfo(List[1], 'Packages', ContainerFile, LineNo) + + return (List[0], List[1]) + +## Get Pcd Values of Inf +# +# Get Pcd of Inf as <TokenSpaceGuidCName>.<PcdCName>[|<Value>] +# +# @param Item: The string describes pcd +# @param Type: The type of Pcd +# @param File: The file which describes the pcd, used for error report +# +def GetPcdOfInf(Item, Type, File, LineNo): + Format = '<TokenSpaceGuidCName>.<PcdCName>[|<Value>]' + TokenGuid, TokenName, Value, InfType = '', '', '', '' + + if Type == DataType.TAB_PCDS_FIXED_AT_BUILD: + InfType = DataType.TAB_INF_FIXED_PCD + elif Type == DataType.TAB_PCDS_PATCHABLE_IN_MODULE: + InfType = DataType.TAB_INF_PATCH_PCD + elif Type == DataType.TAB_PCDS_FEATURE_FLAG: + InfType = DataType.TAB_INF_FEATURE_PCD + elif Type == DataType.TAB_PCDS_DYNAMIC_EX: + InfType = DataType.TAB_INF_PCD_EX + elif Type == DataType.TAB_PCDS_DYNAMIC: + InfType = DataType.TAB_INF_PCD + List = GetSplitValueList(Item, DataType.TAB_VALUE_SPLIT, 1) + TokenInfo = GetSplitValueList(List[0], DataType.TAB_SPLIT) + if len(TokenInfo) != 2: + RaiseParserError(Item, InfType, File, Format, LineNo) + else: + TokenGuid = TokenInfo[0] + TokenName = TokenInfo[1] + + if len(List) > 1: + Value = List[1] + else: + Value = None + return (TokenGuid, TokenName, Value, InfType) + + +## Get Pcd Values of Dec +# +# Get Pcd of Dec as <TokenSpcCName>.<TokenCName>|<Value>|<DatumType>|<Token> +# @param Item: Pcd item +# @param Type: Pcd type +# @param File: Dec file +# @param LineNo: Line number +# +def GetPcdOfDec(Item, Type, File, LineNo= -1): + Format = '<TokenSpaceGuidCName>.<PcdCName>|<Value>|<DatumType>|<Token>' + TokenGuid, TokenName, Value, DatumType, Token = '', '', '', '', '' + List = GetSplitValueList(Item) + if len(List) != 4: + RaiseParserError(Item, 'Pcds' + Type, File, Format, LineNo) + else: + Value = List[1] + DatumType = List[2] + Token = List[3] + TokenInfo = GetSplitValueList(List[0], DataType.TAB_SPLIT) + if len(TokenInfo) != 2: + RaiseParserError(Item, 'Pcds' + Type, File, Format, LineNo) + else: + TokenGuid = TokenInfo[0] + TokenName = TokenInfo[1] + + return (TokenGuid, TokenName, Value, DatumType, Token, Type) + +## Parse DEFINE statement +# +# Get DEFINE macros +# +# @param LineValue: A DEFINE line value +# @param StartLine: A DEFINE start line +# @param Table: A table +# @param FileID: File ID +# @param Filename: File name +# @param SectionName: DEFINE section name +# @param SectionModel: DEFINE section model +# @param Arch: DEFINE arch +# +def ParseDefine(LineValue, StartLine, Table, FileID, SectionName, \ + SectionModel, Arch): + Logger.Debug(Logger.DEBUG_2, ST.MSG_DEFINE_STATEMENT_FOUND % (LineValue, \ + SectionName)) + Define = \ + GetSplitValueList(CleanString\ + (LineValue[LineValue.upper().\ + find(DataType.TAB_DEFINE.upper() + ' ') + \ + len(DataType.TAB_DEFINE + ' ') : ]), \ + DataType.TAB_EQUAL_SPLIT, 1) + Table.Insert(DataType.MODEL_META_DATA_DEFINE, Define[0], Define[1], '', \ + '', '', Arch, SectionModel, FileID, StartLine, -1, \ + StartLine, -1, 0) + +## InsertSectionItems +# +# Insert item data of a section to a dict +# +# @param Model: A model +# @param CurrentSection: Current section +# @param SectionItemList: Section item list +# @param ArchList: Arch list +# @param ThirdList: Third list +# @param RecordSet: Record set +# +def InsertSectionItems(Model, SectionItemList, ArchList, \ + ThirdList, RecordSet): + # + # Insert each item data of a section + # + for Index in range(0, len(ArchList)): + Arch = ArchList[Index] + Third = ThirdList[Index] + if Arch == '': + Arch = DataType.TAB_ARCH_COMMON + + Records = RecordSet[Model] + for SectionItem in SectionItemList: + LineValue, StartLine, Comment = SectionItem[0], \ + SectionItem[1], SectionItem[2] + + Logger.Debug(4, ST.MSG_PARSING % LineValue) + # + # And then parse DEFINE statement + # + if LineValue.upper().find(DataType.TAB_DEFINE.upper() + ' ') > -1: + continue + # + # At last parse other sections + # + IdNum = -1 + Records.append([LineValue, Arch, StartLine, IdNum, Third, Comment]) + + if RecordSet != {}: + RecordSet[Model] = Records + +## GenMetaDatSectionItem +# +# @param Key: A key +# @param Value: A value +# @param List: A list +# +def GenMetaDatSectionItem(Key, Value, List): + if Key not in List: + List[Key] = [Value] + else: + List[Key].append(Value) + +## GetPkgInfoFromDec +# +# get package name, guid, version info from dec files +# +# @param Path: File path +# +def GetPkgInfoFromDec(Path): + PkgName = None + PkgGuid = None + PkgVersion = None + + Path = Path.replace('\\', '/') + + if not os.path.exists(Path): + Logger.Error("\nUPT", FILE_NOT_FOUND, File=Path) + + if Path in gPKG_INFO_DICT: + return gPKG_INFO_DICT[Path] + + try: + DecParser = None + if Path not in GlobalData.gPackageDict: + DecParser = Dec(Path) + GlobalData.gPackageDict[Path] = DecParser + else: + DecParser = GlobalData.gPackageDict[Path] + + PkgName = DecParser.GetPackageName() + PkgGuid = DecParser.GetPackageGuid() + PkgVersion = DecParser.GetPackageVersion() + gPKG_INFO_DICT[Path] = (PkgName, PkgGuid, PkgVersion) + return PkgName, PkgGuid, PkgVersion + except FatalError: + return None, None, None + + +## GetWorkspacePackage +# +# Get a list of workspace package information. +# +def GetWorkspacePackage(): + DecFileList = [] + WorkspaceDir = GlobalData.gWORKSPACE + PackageDir = GlobalData.gPACKAGE_PATH + for PkgRoot in [WorkspaceDir] + PackageDir: + for Root, Dirs, Files in os.walk(PkgRoot): + if 'CVS' in Dirs: + Dirs.remove('CVS') + if '.svn' in Dirs: + Dirs.remove('.svn') + for Dir in Dirs: + if Dir.startswith('.'): + Dirs.remove(Dir) + for FileSp in Files: + if FileSp.startswith('.'): + continue + Ext = os.path.splitext(FileSp)[1] + if Ext.lower() in ['.dec']: + DecFileList.append\ + (os.path.normpath(os.path.join(Root, FileSp))) + # + # abstract package guid, version info from DecFile List + # + PkgList = [] + for DecFile in DecFileList: + (PkgName, PkgGuid, PkgVersion) = GetPkgInfoFromDec(DecFile) + if PkgName and PkgGuid and PkgVersion: + PkgList.append((PkgName, PkgGuid, PkgVersion, DecFile)) + + return PkgList + +## GetWorkspaceModule +# +# Get a list of workspace modules. +# +def GetWorkspaceModule(): + InfFileList = [] + WorkspaceDir = GlobalData.gWORKSPACE + for Root, Dirs, Files in os.walk(WorkspaceDir): + if 'CVS' in Dirs: + Dirs.remove('CVS') + if '.svn' in Dirs: + Dirs.remove('.svn') + if 'Build' in Dirs: + Dirs.remove('Build') + for Dir in Dirs: + if Dir.startswith('.'): + Dirs.remove(Dir) + for FileSp in Files: + if FileSp.startswith('.'): + continue + Ext = os.path.splitext(FileSp)[1] + if Ext.lower() in ['.inf']: + InfFileList.append\ + (os.path.normpath(os.path.join(Root, FileSp))) + + return InfFileList + +## MacroParser used to parse macro definition +# +# @param Line: The content contain linestring and line number +# @param FileName: The meta-file file name +# @param SectionType: Section for the Line belong to +# @param FileLocalMacros: A list contain Macro defined in [Defines] section. +# +def MacroParser(Line, FileName, SectionType, FileLocalMacros): + MacroDefPattern = re.compile("^(DEFINE)[ \t]+") + LineContent = Line[0] + LineNo = Line[1] + Match = MacroDefPattern.match(LineContent) + if not Match: + # + # Not 'DEFINE/EDK_GLOBAL' statement, call decorated method + # + return None, None + + TokenList = GetSplitValueList(LineContent[Match.end(1):], \ + DataType.TAB_EQUAL_SPLIT, 1) + # + # Syntax check + # + if not TokenList[0]: + Logger.Error('Parser', FORMAT_INVALID, ST.ERR_MACRONAME_NOGIVEN, + ExtraData=LineContent, File=FileName, Line=LineNo) + if len(TokenList) < 2: + Logger.Error('Parser', FORMAT_INVALID, ST.ERR_MACROVALUE_NOGIVEN, + ExtraData=LineContent, File=FileName, Line=LineNo) + + Name, Value = TokenList + + # + # DEFINE defined macros + # + if SectionType == DataType.MODEL_META_DATA_HEADER: + FileLocalMacros[Name] = Value + + ReIsValidMacroName = re.compile(r"^[A-Z][A-Z0-9_]*$", re.DOTALL) + if ReIsValidMacroName.match(Name) is None: + Logger.Error('Parser', + FORMAT_INVALID, + ST.ERR_MACRONAME_INVALID % (Name), + ExtraData=LineContent, + File=FileName, + Line=LineNo) + + # Validate MACRO Value + # + # <MacroDefinition> ::= [<Comments>]{0,} + # "DEFINE" <MACRO> "=" [{<PATH>} {<VALUE>}] <EOL> + # <Value> ::= {<NumVal>} {<Boolean>} {<AsciiString>} {<GUID>} + # {<CString>} {<UnicodeString>} {<CArray>} + # + # The definition of <NumVal>, <PATH>, <Boolean>, <GUID>, <CString>, + # <UnicodeString>, <CArray> are subset of <AsciiString>. + # + ReIsValidMacroValue = re.compile(r"^[\x20-\x7e]*$", re.DOTALL) + if ReIsValidMacroValue.match(Value) is None: + Logger.Error('Parser', + FORMAT_INVALID, + ST.ERR_MACROVALUE_INVALID % (Value), + ExtraData=LineContent, + File=FileName, + Line=LineNo) + + return Name, Value + +## GenSection +# +# generate section contents +# +# @param SectionName: indicate the name of the section, details refer to +# INF, DEC specs +# @param SectionDict: section statement dict, key is SectionAttrs(arch, +# moduletype or platform may exist as needed) list +# separated by space, +# value is statement +# +def GenSection(SectionName, SectionDict, SplitArch=True, NeedBlankLine=False): + Content = '' + for SectionAttrs in SectionDict: + StatementList = SectionDict[SectionAttrs] + if SectionAttrs and SectionName != 'Defines' and SectionAttrs.strip().upper() != DataType.TAB_ARCH_COMMON: + if SplitArch: + ArchList = GetSplitValueList(SectionAttrs, DataType.TAB_SPACE_SPLIT) + else: + if SectionName != 'UserExtensions': + ArchList = GetSplitValueList(SectionAttrs, DataType.TAB_COMMENT_SPLIT) + else: + ArchList = [SectionAttrs] + for Index in range(0, len(ArchList)): + ArchList[Index] = ConvertArchForInstall(ArchList[Index]) + Section = '[' + SectionName + '.' + (', ' + SectionName + '.').join(ArchList) + ']' + else: + Section = '[' + SectionName + ']' + Content += '\n' + Section + '\n' + if StatementList is not None: + for Statement in StatementList: + LineList = Statement.split('\n') + NewStatement = "" + for Line in LineList: + # ignore blank comment + if not Line.replace("#", '').strip() and SectionName not in ('Defines', 'Hob', 'Event', 'BootMode'): + continue + # add two space before non-comments line except the comments in Defines section + if Line.strip().startswith('#') and SectionName == 'Defines': + NewStatement += "%s\n" % Line + continue + NewStatement += " %s\n" % Line + if NeedBlankLine: + Content += NewStatement + '\n' + else: + Content += NewStatement + + if NeedBlankLine: + Content = Content[:-1] + if not Content.replace('\\n', '').strip(): + return '' + return Content + +## ConvertArchForInstall +# if Arch.upper() is in "IA32", "X64", "IPF", and "EBC", it must be upper case. "common" must be lower case. +# Anything else, the case must be preserved +# +# @param Arch: the arch string that need to be converted, it should be stripped before pass in +# @return: the arch string that get converted +# +def ConvertArchForInstall(Arch): + if Arch.upper() in [DataType.TAB_ARCH_IA32, DataType.TAB_ARCH_X64, + DataType.TAB_ARCH_IPF, DataType.TAB_ARCH_EBC]: + Arch = Arch.upper() + elif Arch.upper() == DataType.TAB_ARCH_COMMON: + Arch = Arch.lower() + + return Arch diff --git a/BaseTools/Source/Python/UPT/Library/StringUtils.py b/BaseTools/Source/Python/UPT/Library/StringUtils.py index fbc5177caf..b3c742c208 100644 --- a/BaseTools/Source/Python/UPT/Library/StringUtils.py +++ b/BaseTools/Source/Python/UPT/Library/StringUtils.py @@ -1,982 +1,982 @@ -## @file
-# This file is used to define common string related functions used in parsing
-# process
-#
-# Copyright (c) 2011 - 2018, Intel Corporation. All rights reserved.<BR>
-#
-# SPDX-License-Identifier: BSD-2-Clause-Patent
-#
-'''
-StringUtils
-'''
-##
-# Import Modules
-#
-import re
-import os.path
-import Logger.Log as Logger
-import Library.DataType as DataType
-from Logger.ToolError import FORMAT_INVALID
-from Logger.ToolError import PARSER_ERROR
-from Logger import StringTable as ST
-
-#
-# Regular expression for matching macro used in DSC/DEC/INF file inclusion
-#
-gMACRO_PATTERN = re.compile("\$\(([_A-Z][_A-Z0-9]*)\)", re.UNICODE)
-
-## GetSplitValueList
-#
-# Get a value list from a string with multiple values split with SplitTag
-# The default SplitTag is DataType.TAB_VALUE_SPLIT
-# 'AAA|BBB|CCC' -> ['AAA', 'BBB', 'CCC']
-#
-# @param String: The input string to be splitted
-# @param SplitTag: The split key, default is DataType.TAB_VALUE_SPLIT
-# @param MaxSplit: The max number of split values, default is -1
-#
-#
-def GetSplitValueList(String, SplitTag=DataType.TAB_VALUE_SPLIT, MaxSplit= -1):
- return list(map(lambda l: l.strip(), String.split(SplitTag, MaxSplit)))
-
-## MergeArches
-#
-# Find a key's all arches in dict, add the new arch to the list
-# If not exist any arch, set the arch directly
-#
-# @param Dict: The input value for Dict
-# @param Key: The input value for Key
-# @param Arch: The Arch to be added or merged
-#
-def MergeArches(Dict, Key, Arch):
- if Key in Dict.keys():
- Dict[Key].append(Arch)
- else:
- Dict[Key] = Arch.split()
-
-## GenDefines
-#
-# Parse a string with format "DEFINE <VarName> = <PATH>"
-# Generate a map Defines[VarName] = PATH
-# Return False if invalid format
-#
-# @param String: String with DEFINE statement
-# @param Arch: Supported Arch
-# @param Defines: DEFINE statement to be parsed
-#
-def GenDefines(String, Arch, Defines):
- if String.find(DataType.TAB_DEFINE + ' ') > -1:
- List = String.replace(DataType.TAB_DEFINE + ' ', '').\
- split(DataType.TAB_EQUAL_SPLIT)
- if len(List) == 2:
- Defines[(CleanString(List[0]), Arch)] = CleanString(List[1])
- return 0
- else:
- return -1
- return 1
-
-## GetLibraryClassesWithModuleType
-#
-# Get Library Class definition when no module type defined
-#
-# @param Lines: The content to be parsed
-# @param Key: Reserved
-# @param KeyValues: To store data after parsing
-# @param CommentCharacter: Comment char, used to ignore comment content
-#
-def GetLibraryClassesWithModuleType(Lines, Key, KeyValues, CommentCharacter):
- NewKey = SplitModuleType(Key)
- Lines = Lines.split(DataType.TAB_SECTION_END, 1)[1]
- LineList = Lines.splitlines()
- for Line in LineList:
- Line = CleanString(Line, CommentCharacter)
- if Line != '' and Line[0] != CommentCharacter:
- KeyValues.append([CleanString(Line, CommentCharacter), NewKey[1]])
-
- return True
-
-## GetDynamics
-#
-# Get Dynamic Pcds
-#
-# @param Lines: The content to be parsed
-# @param Key: Reserved
-# @param KeyValues: To store data after parsing
-# @param CommentCharacter: Comment char, used to ignore comment content
-#
-def GetDynamics(Lines, Key, KeyValues, CommentCharacter):
- #
- # Get SkuId Name List
- #
- SkuIdNameList = SplitModuleType(Key)
-
- Lines = Lines.split(DataType.TAB_SECTION_END, 1)[1]
- LineList = Lines.splitlines()
- for Line in LineList:
- Line = CleanString(Line, CommentCharacter)
- if Line != '' and Line[0] != CommentCharacter:
- KeyValues.append([CleanString(Line, CommentCharacter), SkuIdNameList[1]])
-
- return True
-
-## SplitModuleType
-#
-# Split ModuleType out of section defien to get key
-# [LibraryClass.Arch.ModuleType|ModuleType|ModuleType] -> [
-# 'LibraryClass.Arch', ['ModuleType', 'ModuleType', 'ModuleType'] ]
-#
-# @param Key: String to be parsed
-#
-def SplitModuleType(Key):
- KeyList = Key.split(DataType.TAB_SPLIT)
- #
- # Fill in for arch
- #
- KeyList.append('')
- #
- # Fill in for moduletype
- #
- KeyList.append('')
- ReturnValue = []
- KeyValue = KeyList[0]
- if KeyList[1] != '':
- KeyValue = KeyValue + DataType.TAB_SPLIT + KeyList[1]
- ReturnValue.append(KeyValue)
- ReturnValue.append(GetSplitValueList(KeyList[2]))
-
- return ReturnValue
-
-## Replace macro in string
-#
-# This method replace macros used in given string. The macros are given in a
-# dictionary.
-#
-# @param String String to be processed
-# @param MacroDefinitions The macro definitions in the form of dictionary
-# @param SelfReplacement To decide whether replace un-defined macro to ''
-# @param Line: The content contain line string and line number
-# @param FileName: The meta-file file name
-#
-def ReplaceMacro(String, MacroDefinitions=None, SelfReplacement=False, Line=None, FileName=None, Flag=False):
- LastString = String
- if MacroDefinitions is None:
- MacroDefinitions = {}
- while MacroDefinitions:
- QuotedStringList = []
- HaveQuotedMacroFlag = False
- if not Flag:
- MacroUsed = gMACRO_PATTERN.findall(String)
- else:
- ReQuotedString = re.compile('\"')
- QuotedStringList = ReQuotedString.split(String)
- if len(QuotedStringList) >= 3:
- HaveQuotedMacroFlag = True
- Count = 0
- MacroString = ""
- for QuotedStringItem in QuotedStringList:
- Count += 1
- if Count % 2 != 0:
- MacroString += QuotedStringItem
-
- if Count == len(QuotedStringList) and Count % 2 == 0:
- MacroString += QuotedStringItem
-
- MacroUsed = gMACRO_PATTERN.findall(MacroString)
- #
- # no macro found in String, stop replacing
- #
- if len(MacroUsed) == 0:
- break
- for Macro in MacroUsed:
- if Macro not in MacroDefinitions:
- if SelfReplacement:
- String = String.replace("$(%s)" % Macro, '')
- Logger.Debug(5, "Delete undefined MACROs in file %s line %d: %s!" % (FileName, Line[1], Line[0]))
- continue
- if not HaveQuotedMacroFlag:
- String = String.replace("$(%s)" % Macro, MacroDefinitions[Macro])
- else:
- Count = 0
- for QuotedStringItem in QuotedStringList:
- Count += 1
- if Count % 2 != 0:
- QuotedStringList[Count - 1] = QuotedStringList[Count - 1].replace("$(%s)" % Macro,
- MacroDefinitions[Macro])
- elif Count == len(QuotedStringList) and Count % 2 == 0:
- QuotedStringList[Count - 1] = QuotedStringList[Count - 1].replace("$(%s)" % Macro,
- MacroDefinitions[Macro])
-
- RetString = ''
- if HaveQuotedMacroFlag:
- Count = 0
- for QuotedStringItem in QuotedStringList:
- Count += 1
- if Count != len(QuotedStringList):
- RetString += QuotedStringList[Count - 1] + "\""
- else:
- RetString += QuotedStringList[Count - 1]
-
- String = RetString
-
- #
- # in case there's macro not defined
- #
- if String == LastString:
- break
- LastString = String
-
- return String
-
-## NormPath
-#
-# Create a normal path
-# And replace DEFINE in the path
-#
-# @param Path: The input value for Path to be converted
-# @param Defines: A set for DEFINE statement
-#
-def NormPath(Path, Defines=None):
- IsRelativePath = False
- if Defines is None:
- Defines = {}
- if Path:
- if Path[0] == '.':
- IsRelativePath = True
- #
- # Replace with Define
- #
- if Defines:
- Path = ReplaceMacro(Path, Defines)
- #
- # To local path format
- #
- Path = os.path.normpath(Path)
-
- if IsRelativePath and Path[0] != '.':
- Path = os.path.join('.', Path)
- return Path
-
-## CleanString
-#
-# Remove 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=DataType.TAB_COMMENT_SPLIT, AllowCppStyleComment=False):
- #
- # remove whitespace
- #
- Line = Line.strip()
- #
- # Replace EDK1's comment character
- #
- if AllowCppStyleComment:
- Line = Line.replace(DataType.TAB_COMMENT_EDK1_SPLIT, CommentCharacter)
- #
- # remove comments, but we should escape comment character in string
- #
- InString = False
- for Index in range(0, len(Line)):
- if Line[Index] == '"':
- InString = not InString
- elif Line[Index] == CommentCharacter and not InString:
- Line = Line[0: Index]
- break
- #
- # remove whitespace again
- #
- Line = Line.strip()
-
- return Line
-
-## CleanString2
-#
-# 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 CleanString2(Line, CommentCharacter=DataType.TAB_COMMENT_SPLIT, AllowCppStyleComment=False):
- #
- # remove whitespace
- #
- Line = Line.strip()
- #
- # Replace EDK1's comment character
- #
- if AllowCppStyleComment:
- Line = Line.replace(DataType.TAB_COMMENT_EDK1_SPLIT, CommentCharacter)
- #
- # separate comments and statements
- #
- LineParts = Line.split(CommentCharacter, 1)
- #
- # remove whitespace again
- #
- Line = LineParts[0].strip()
- if len(LineParts) > 1:
- Comment = LineParts[1].strip()
- #
- # Remove prefixed and trailing comment characters
- #
- Start = 0
- End = len(Comment)
- while Start < End and Comment.startswith(CommentCharacter, Start, End):
- Start += 1
- while End >= 0 and Comment.endswith(CommentCharacter, Start, End):
- End -= 1
- Comment = Comment[Start:End]
- Comment = Comment.strip()
- else:
- Comment = ''
-
- return Line, Comment
-
-## GetMultipleValuesOfKeyFromLines
-#
-# Parse multiple strings to clean comment and spaces
-# The result is saved to KeyValues
-#
-# @param Lines: The content to be parsed
-# @param Key: Reserved
-# @param KeyValues: To store data after parsing
-# @param CommentCharacter: Comment char, used to ignore comment content
-#
-def GetMultipleValuesOfKeyFromLines(Lines, Key, KeyValues, CommentCharacter):
- if Key:
- pass
- if KeyValues:
- pass
- Lines = Lines.split(DataType.TAB_SECTION_END, 1)[1]
- LineList = Lines.split('\n')
- for Line in LineList:
- Line = CleanString(Line, CommentCharacter)
- if Line != '' and Line[0] != CommentCharacter:
- KeyValues += [Line]
- return True
-
-## GetDefineValue
-#
-# Parse a DEFINE statement to get defined value
-# DEFINE Key Value
-#
-# @param String: The content to be parsed
-# @param Key: The key of DEFINE statement
-# @param CommentCharacter: Comment char, used to ignore comment content
-#
-def GetDefineValue(String, Key, CommentCharacter):
- if CommentCharacter:
- pass
- String = CleanString(String)
- return String[String.find(Key + ' ') + len(Key + ' ') : ]
-
-## GetSingleValueOfKeyFromLines
-#
-# Parse multiple strings as below to get value of each definition line
-# Key1 = Value1
-# Key2 = Value2
-# The result is saved to Dictionary
-#
-# @param Lines: The content to be parsed
-# @param Dictionary: To store data after parsing
-# @param CommentCharacter: Comment char, be used to ignore comment content
-# @param KeySplitCharacter: Key split char, between key name and key value.
-# Key1 = Value1, '=' is the key split char
-# @param ValueSplitFlag: Value split flag, be used to decide if has
-# multiple values
-# @param ValueSplitCharacter: Value split char, be used to split multiple
-# values. Key1 = Value1|Value2, '|' is the value
-# split char
-#
-def GetSingleValueOfKeyFromLines(Lines, Dictionary, CommentCharacter, KeySplitCharacter, \
- ValueSplitFlag, ValueSplitCharacter):
- Lines = Lines.split('\n')
- Keys = []
- Value = ''
- DefineValues = ['']
- SpecValues = ['']
-
- for Line in Lines:
- #
- # Handle DEFINE and SPEC
- #
- if Line.find(DataType.TAB_INF_DEFINES_DEFINE + ' ') > -1:
- if '' in DefineValues:
- DefineValues.remove('')
- DefineValues.append(GetDefineValue(Line, DataType.TAB_INF_DEFINES_DEFINE, CommentCharacter))
- continue
- if Line.find(DataType.TAB_INF_DEFINES_SPEC + ' ') > -1:
- if '' in SpecValues:
- SpecValues.remove('')
- SpecValues.append(GetDefineValue(Line, DataType.TAB_INF_DEFINES_SPEC, CommentCharacter))
- continue
-
- #
- # Handle Others
- #
- LineList = Line.split(KeySplitCharacter, 1)
- if len(LineList) >= 2:
- Key = LineList[0].split()
- if len(Key) == 1 and Key[0][0] != CommentCharacter:
- #
- # Remove comments and white spaces
- #
- LineList[1] = CleanString(LineList[1], CommentCharacter)
- if ValueSplitFlag:
- Value = list(map(lambda x: x.strip(), LineList[1].split(ValueSplitCharacter)))
- else:
- Value = CleanString(LineList[1], CommentCharacter).splitlines()
-
- if Key[0] in Dictionary:
- if Key[0] not in Keys:
- Dictionary[Key[0]] = Value
- Keys.append(Key[0])
- else:
- Dictionary[Key[0]].extend(Value)
- else:
- Dictionary[DataType.TAB_INF_DEFINES_MACRO][Key[0]] = Value[0]
-
- if DefineValues == []:
- DefineValues = ['']
- if SpecValues == []:
- SpecValues = ['']
- Dictionary[DataType.TAB_INF_DEFINES_DEFINE] = DefineValues
- Dictionary[DataType.TAB_INF_DEFINES_SPEC] = SpecValues
-
- return True
-
-## The content to be parsed
-#
-# Do pre-check for a file before it is parsed
-# Check $()
-# Check []
-#
-# @param FileName: Used for error report
-# @param FileContent: File content to be parsed
-# @param SupSectionTag: Used for error report
-#
-def PreCheck(FileName, FileContent, SupSectionTag):
- if SupSectionTag:
- pass
- LineNo = 0
- IsFailed = False
- NewFileContent = ''
- for Line in FileContent.splitlines():
- LineNo = LineNo + 1
- #
- # Clean current line
- #
- Line = CleanString(Line)
- #
- # Remove commented line
- #
- if Line.find(DataType.TAB_COMMA_SPLIT) == 0:
- Line = ''
- #
- # Check $()
- #
- if Line.find('$') > -1:
- if Line.find('$(') < 0 or Line.find(')') < 0:
- Logger.Error("Parser", FORMAT_INVALID, Line=LineNo, File=FileName, RaiseError=Logger.IS_RAISE_ERROR)
- #
- # Check []
- #
- if Line.find('[') > -1 or Line.find(']') > -1:
- #
- # Only get one '[' or one ']'
- #
- if not (Line.find('[') > -1 and Line.find(']') > -1):
- Logger.Error("Parser", FORMAT_INVALID, Line=LineNo, File=FileName, RaiseError=Logger.IS_RAISE_ERROR)
- #
- # Regenerate FileContent
- #
- NewFileContent = NewFileContent + Line + '\r\n'
-
- if IsFailed:
- Logger.Error("Parser", FORMAT_INVALID, Line=LineNo, File=FileName, RaiseError=Logger.IS_RAISE_ERROR)
-
- return NewFileContent
-
-## CheckFileType
-#
-# Check if the Filename is including ExtName
-# Return True if it exists
-# Raise a error message if it not exists
-#
-# @param CheckFilename: Name of the file to be checked
-# @param ExtName: Ext name of the file to be checked
-# @param ContainerFilename: The container file which describes the file to be
-# checked, used for error report
-# @param SectionName: Used for error report
-# @param Line: The line in container file which defines the file
-# to be checked
-#
-def CheckFileType(CheckFilename, ExtName, ContainerFilename, SectionName, Line, LineNo= -1):
- if CheckFilename != '' and CheckFilename is not None:
- (Root, Ext) = os.path.splitext(CheckFilename)
- if Ext.upper() != ExtName.upper() and Root:
- ContainerFile = open(ContainerFilename, 'r').read()
- if LineNo == -1:
- LineNo = GetLineNo(ContainerFile, Line)
- ErrorMsg = ST.ERR_SECTIONNAME_INVALID % (SectionName, CheckFilename, ExtName)
- Logger.Error("Parser", PARSER_ERROR, ErrorMsg, Line=LineNo, \
- File=ContainerFilename, RaiseError=Logger.IS_RAISE_ERROR)
-
- return True
-
-## CheckFileExist
-#
-# Check if the file exists
-# Return True if it exists
-# Raise a error message if it not exists
-#
-# @param CheckFilename: Name of the file to be checked
-# @param WorkspaceDir: Current workspace dir
-# @param ContainerFilename: The container file which describes the file to
-# be checked, used for error report
-# @param SectionName: Used for error report
-# @param Line: The line in container file which defines the
-# file to be checked
-#
-def CheckFileExist(WorkspaceDir, CheckFilename, ContainerFilename, SectionName, Line, LineNo= -1):
- CheckFile = ''
- if CheckFilename != '' and CheckFilename is not None:
- CheckFile = WorkspaceFile(WorkspaceDir, CheckFilename)
- if not os.path.isfile(CheckFile):
- ContainerFile = open(ContainerFilename, 'r').read()
- if LineNo == -1:
- LineNo = GetLineNo(ContainerFile, Line)
- ErrorMsg = ST.ERR_CHECKFILE_NOTFOUND % (CheckFile, SectionName)
- Logger.Error("Parser", PARSER_ERROR, ErrorMsg,
- File=ContainerFilename, Line=LineNo, RaiseError=Logger.IS_RAISE_ERROR)
- return CheckFile
-
-## GetLineNo
-#
-# Find the index of a line in a file
-#
-# @param FileContent: Search scope
-# @param Line: Search key
-#
-def GetLineNo(FileContent, Line, IsIgnoreComment=True):
- LineList = FileContent.splitlines()
- for Index in range(len(LineList)):
- if LineList[Index].find(Line) > -1:
- #
- # Ignore statement in comment
- #
- if IsIgnoreComment:
- if LineList[Index].strip()[0] == DataType.TAB_COMMENT_SPLIT:
- continue
- return Index + 1
-
- return -1
-
-## RaiseParserError
-#
-# Raise a parser error
-#
-# @param Line: String which has error
-# @param Section: Used for error report
-# @param File: File which has the string
-# @param Format: Correct format
-#
-def RaiseParserError(Line, Section, File, Format='', LineNo= -1):
- if LineNo == -1:
- LineNo = GetLineNo(open(os.path.normpath(File), 'r').read(), Line)
- ErrorMsg = ST.ERR_INVALID_NOTFOUND % (Line, Section)
- if Format != '':
- Format = "Correct format is " + Format
- Logger.Error("Parser", PARSER_ERROR, ErrorMsg, File=File, Line=LineNo, \
- ExtraData=Format, RaiseError=Logger.IS_RAISE_ERROR)
-
-## WorkspaceFile
-#
-# Return a full path with workspace dir
-#
-# @param WorkspaceDir: Workspace dir
-# @param Filename: Relative file name
-#
-def WorkspaceFile(WorkspaceDir, Filename):
- return os.path.join(NormPath(WorkspaceDir), NormPath(Filename))
-
-## Split string
-#
-# Remove '"' which startswith and endswith string
-#
-# @param String: The string need to be split
-#
-def SplitString(String):
- if String.startswith('\"'):
- String = String[1:]
- if String.endswith('\"'):
- String = String[:-1]
- return String
-
-## Convert To Sql String
-#
-# Replace "'" with "''" in each item of StringList
-#
-# @param StringList: A list for strings to be converted
-#
-def ConvertToSqlString(StringList):
- return list(map(lambda s: s.replace("'", "''"), StringList))
-
-## Convert To Sql String
-#
-# Replace "'" with "''" in the String
-#
-# @param String: A String to be converted
-#
-def ConvertToSqlString2(String):
- return String.replace("'", "''")
-
-## GetStringOfList
-#
-# Get String of a List
-#
-# @param Lines: string list
-# @param Split: split character
-#
-def GetStringOfList(List, Split=' '):
- if not isinstance(List, type([])):
- return List
- Str = ''
- for Item in List:
- Str = Str + Item + Split
- return Str.strip()
-
-## Get HelpTextList
-#
-# Get HelpTextList from HelpTextClassList
-#
-# @param HelpTextClassList: Help Text Class List
-#
-def GetHelpTextList(HelpTextClassList):
- List = []
- if HelpTextClassList:
- for HelpText in HelpTextClassList:
- if HelpText.String.endswith('\n'):
- HelpText.String = HelpText.String[0: len(HelpText.String) - len('\n')]
- List.extend(HelpText.String.split('\n'))
- return List
-
-## Get String Array Length
-#
-# Get String Array Length
-#
-# @param String: the source string
-#
-def StringArrayLength(String):
- if String.startswith('L"'):
- return (len(String) - 3 + 1) * 2
- elif String.startswith('"'):
- return (len(String) - 2 + 1)
- else:
- return len(String.split()) + 1
-
-## RemoveDupOption
-#
-# Remove Dup Option
-#
-# @param OptionString: the option string
-# @param Which: Which flag
-# @param Against: Against flag
-#
-def RemoveDupOption(OptionString, Which="/I", Against=None):
- OptionList = OptionString.split()
- ValueList = []
- if Against:
- ValueList += Against
- for Index in range(len(OptionList)):
- Opt = OptionList[Index]
- if not Opt.startswith(Which):
- continue
- if len(Opt) > len(Which):
- Val = Opt[len(Which):]
- else:
- Val = ""
- if Val in ValueList:
- OptionList[Index] = ""
- else:
- ValueList.append(Val)
- return " ".join(OptionList)
-
-## Check if the string is HexDgit
-#
-# Return true if all characters in the string are digits and there is at
-# least one character
-# or valid Hexs (started with 0x, following by hexdigit letters)
-# , false otherwise.
-# @param string: input string
-#
-def IsHexDigit(Str):
- try:
- int(Str, 10)
- return True
- except ValueError:
- if len(Str) > 2 and Str.upper().startswith('0X'):
- try:
- int(Str, 16)
- return True
- except ValueError:
- return False
- return False
-
-## Check if the string is HexDgit and its integer value within limit of UINT32
-#
-# Return true if all characters in the string are digits and there is at
-# least one character
-# or valid Hexs (started with 0x, following by hexdigit letters)
-# , false otherwise.
-# @param string: input string
-#
-def IsHexDigitUINT32(Str):
- try:
- Value = int(Str, 10)
- if (Value <= 0xFFFFFFFF) and (Value >= 0):
- return True
- except ValueError:
- if len(Str) > 2 and Str.upper().startswith('0X'):
- try:
- Value = int(Str, 16)
- if (Value <= 0xFFFFFFFF) and (Value >= 0):
- return True
- except ValueError:
- return False
- return False
-
-## CleanSpecialChar
-#
-# The ASCII text files of type INF, DEC, INI are edited by developers,
-# and may contain characters that cannot be directly translated to strings that
-# are conformant with the UDP XML Schema. Any characters in this category
-# (0x00-0x08, TAB [0x09], 0x0B, 0x0C, 0x0E-0x1F, 0x80-0xFF)
-# must be converted to a space character[0x20] as part of the parsing process.
-#
-def ConvertSpecialChar(Lines):
- RetLines = []
- for line in Lines:
- ReMatchSpecialChar = re.compile(r"[\x00-\x08]|\x09|\x0b|\x0c|[\x0e-\x1f]|[\x7f-\xff]")
- RetLines.append(ReMatchSpecialChar.sub(' ', line))
-
- return RetLines
-
-## __GetTokenList
-#
-# Assume Str is a valid feature flag expression.
-# Return a list which contains tokens: alpha numeric token and other token
-# Whitespace are not stripped
-#
-def __GetTokenList(Str):
- InQuote = False
- Token = ''
- TokenOP = ''
- PreChar = ''
- List = []
- for Char in Str:
- if InQuote:
- Token += Char
- if Char == '"' and PreChar != '\\':
- InQuote = not InQuote
- List.append(Token)
- Token = ''
- continue
- if Char == '"':
- if Token and Token != 'L':
- List.append(Token)
- Token = ''
- if TokenOP:
- List.append(TokenOP)
- TokenOP = ''
- InQuote = not InQuote
- Token += Char
- continue
-
- if not (Char.isalnum() or Char in '_'):
- TokenOP += Char
- if Token:
- List.append(Token)
- Token = ''
- else:
- Token += Char
- if TokenOP:
- List.append(TokenOP)
- TokenOP = ''
-
- if PreChar == '\\' and Char == '\\':
- PreChar = ''
- else:
- PreChar = Char
- if Token:
- List.append(Token)
- if TokenOP:
- List.append(TokenOP)
- return List
-
-## ConvertNEToNOTEQ
-#
-# Convert NE operator to NOT EQ
-# For example: 1 NE 2 -> 1 NOT EQ 2
-#
-# @param Expr: Feature flag expression to be converted
-#
-def ConvertNEToNOTEQ(Expr):
- List = __GetTokenList(Expr)
- for Index in range(len(List)):
- if List[Index] == 'NE':
- List[Index] = 'NOT EQ'
- return ''.join(List)
-
-## ConvertNOTEQToNE
-#
-# Convert NOT EQ operator to NE
-# For example: 1 NOT NE 2 -> 1 NE 2
-#
-# @param Expr: Feature flag expression to be converted
-#
-def ConvertNOTEQToNE(Expr):
- List = __GetTokenList(Expr)
- HasNOT = False
- RetList = []
- for Token in List:
- if HasNOT and Token == 'EQ':
- # At least, 'NOT' is in the list
- while not RetList[-1].strip():
- RetList.pop()
- RetList[-1] = 'NE'
- HasNOT = False
- continue
- if Token == 'NOT':
- HasNOT = True
- elif Token.strip():
- HasNOT = False
- RetList.append(Token)
-
- return ''.join(RetList)
-
-## SplitPcdEntry
-#
-# Split an PCD entry string to Token.CName and PCD value and FFE.
-# NOTE: PCD Value and FFE can contain "|" in its expression. And in INF specification, have below rule.
-# When using the characters "|" or "||" in an expression, the expression must be encapsulated in
-# open "(" and close ")" parenthesis.
-#
-# @param String An PCD entry string need to be split.
-#
-# @return List [PcdTokenCName, Value, FFE]
-#
-def SplitPcdEntry(String):
- if not String:
- return ['', '', ''], False
-
- PcdTokenCName = ''
- PcdValue = ''
- PcdFeatureFlagExp = ''
-
- ValueList = GetSplitValueList(String, "|", 1)
-
- #
- # Only contain TokenCName
- #
- if len(ValueList) == 1:
- return [ValueList[0]], True
-
- NewValueList = []
-
- if len(ValueList) == 2:
- PcdTokenCName = ValueList[0]
-
- InQuote = False
- InParenthesis = False
- StrItem = ''
- for StrCh in ValueList[1]:
- if StrCh == '"':
- InQuote = not InQuote
- elif StrCh == '(' or StrCh == ')':
- InParenthesis = not InParenthesis
-
- if StrCh == '|':
- if not InQuote or not InParenthesis:
- NewValueList.append(StrItem.strip())
- StrItem = ' '
- continue
-
- StrItem += StrCh
-
- NewValueList.append(StrItem.strip())
-
- if len(NewValueList) == 1:
- PcdValue = NewValueList[0]
- return [PcdTokenCName, PcdValue], True
- elif len(NewValueList) == 2:
- PcdValue = NewValueList[0]
- PcdFeatureFlagExp = NewValueList[1]
- return [PcdTokenCName, PcdValue, PcdFeatureFlagExp], True
- else:
- return ['', '', ''], False
-
- return ['', '', ''], False
-
-## Check if two arches matched?
-#
-# @param Arch1
-# @param Arch2
-#
-def IsMatchArch(Arch1, Arch2):
- if 'COMMON' in Arch1 or 'COMMON' in Arch2:
- return True
- try:
- if isinstance(Arch1, list) and isinstance(Arch2, list):
- for Item1 in Arch1:
- for Item2 in Arch2:
- if Item1 == Item2:
- return True
-
- elif isinstance(Arch1, list):
- return Arch2 in Arch1
-
- elif isinstance(Arch2, list):
- return Arch1 in Arch2
-
- else:
- if Arch1 == Arch2:
- return True
- except:
- return False
-
-# Search all files in FilePath to find the FileName with the largest index
-# Return the FileName with index +1 under the FilePath
-#
-def GetUniFileName(FilePath, FileName):
- Files = []
- try:
- Files = os.listdir(FilePath)
- except:
- pass
-
- LargestIndex = -1
- IndexNotFound = True
- for File in Files:
- if File.upper().startswith(FileName.upper()) and File.upper().endswith('.UNI'):
- Index = File.upper().replace(FileName.upper(), '').replace('.UNI', '')
- if Index:
- try:
- Index = int(Index)
- except Exception:
- Index = -1
- else:
- IndexNotFound = False
- Index = 0
- if Index > LargestIndex:
- LargestIndex = Index + 1
-
- if LargestIndex > -1 and not IndexNotFound:
- return os.path.normpath(os.path.join(FilePath, FileName + str(LargestIndex) + '.uni'))
- else:
- return os.path.normpath(os.path.join(FilePath, FileName + '.uni'))
+## @file +# This file is used to define common string related functions used in parsing +# process +# +# Copyright (c) 2011 - 2018, Intel Corporation. All rights reserved.<BR> +# +# SPDX-License-Identifier: BSD-2-Clause-Patent +# +''' +StringUtils +''' +## +# Import Modules +# +import re +import os.path +import Logger.Log as Logger +import Library.DataType as DataType +from Logger.ToolError import FORMAT_INVALID +from Logger.ToolError import PARSER_ERROR +from Logger import StringTable as ST + +# +# Regular expression for matching macro used in DSC/DEC/INF file inclusion +# +gMACRO_PATTERN = re.compile("\$\(([_A-Z][_A-Z0-9]*)\)", re.UNICODE) + +## GetSplitValueList +# +# Get a value list from a string with multiple values split with SplitTag +# The default SplitTag is DataType.TAB_VALUE_SPLIT +# 'AAA|BBB|CCC' -> ['AAA', 'BBB', 'CCC'] +# +# @param String: The input string to be splitted +# @param SplitTag: The split key, default is DataType.TAB_VALUE_SPLIT +# @param MaxSplit: The max number of split values, default is -1 +# +# +def GetSplitValueList(String, SplitTag=DataType.TAB_VALUE_SPLIT, MaxSplit= -1): + return list(map(lambda l: l.strip(), String.split(SplitTag, MaxSplit))) + +## MergeArches +# +# Find a key's all arches in dict, add the new arch to the list +# If not exist any arch, set the arch directly +# +# @param Dict: The input value for Dict +# @param Key: The input value for Key +# @param Arch: The Arch to be added or merged +# +def MergeArches(Dict, Key, Arch): + if Key in Dict.keys(): + Dict[Key].append(Arch) + else: + Dict[Key] = Arch.split() + +## GenDefines +# +# Parse a string with format "DEFINE <VarName> = <PATH>" +# Generate a map Defines[VarName] = PATH +# Return False if invalid format +# +# @param String: String with DEFINE statement +# @param Arch: Supported Arch +# @param Defines: DEFINE statement to be parsed +# +def GenDefines(String, Arch, Defines): + if String.find(DataType.TAB_DEFINE + ' ') > -1: + List = String.replace(DataType.TAB_DEFINE + ' ', '').\ + split(DataType.TAB_EQUAL_SPLIT) + if len(List) == 2: + Defines[(CleanString(List[0]), Arch)] = CleanString(List[1]) + return 0 + else: + return -1 + return 1 + +## GetLibraryClassesWithModuleType +# +# Get Library Class definition when no module type defined +# +# @param Lines: The content to be parsed +# @param Key: Reserved +# @param KeyValues: To store data after parsing +# @param CommentCharacter: Comment char, used to ignore comment content +# +def GetLibraryClassesWithModuleType(Lines, Key, KeyValues, CommentCharacter): + NewKey = SplitModuleType(Key) + Lines = Lines.split(DataType.TAB_SECTION_END, 1)[1] + LineList = Lines.splitlines() + for Line in LineList: + Line = CleanString(Line, CommentCharacter) + if Line != '' and Line[0] != CommentCharacter: + KeyValues.append([CleanString(Line, CommentCharacter), NewKey[1]]) + + return True + +## GetDynamics +# +# Get Dynamic Pcds +# +# @param Lines: The content to be parsed +# @param Key: Reserved +# @param KeyValues: To store data after parsing +# @param CommentCharacter: Comment char, used to ignore comment content +# +def GetDynamics(Lines, Key, KeyValues, CommentCharacter): + # + # Get SkuId Name List + # + SkuIdNameList = SplitModuleType(Key) + + Lines = Lines.split(DataType.TAB_SECTION_END, 1)[1] + LineList = Lines.splitlines() + for Line in LineList: + Line = CleanString(Line, CommentCharacter) + if Line != '' and Line[0] != CommentCharacter: + KeyValues.append([CleanString(Line, CommentCharacter), SkuIdNameList[1]]) + + return True + +## SplitModuleType +# +# Split ModuleType out of section defien to get key +# [LibraryClass.Arch.ModuleType|ModuleType|ModuleType] -> [ +# 'LibraryClass.Arch', ['ModuleType', 'ModuleType', 'ModuleType'] ] +# +# @param Key: String to be parsed +# +def SplitModuleType(Key): + KeyList = Key.split(DataType.TAB_SPLIT) + # + # Fill in for arch + # + KeyList.append('') + # + # Fill in for moduletype + # + KeyList.append('') + ReturnValue = [] + KeyValue = KeyList[0] + if KeyList[1] != '': + KeyValue = KeyValue + DataType.TAB_SPLIT + KeyList[1] + ReturnValue.append(KeyValue) + ReturnValue.append(GetSplitValueList(KeyList[2])) + + return ReturnValue + +## Replace macro in string +# +# This method replace macros used in given string. The macros are given in a +# dictionary. +# +# @param String String to be processed +# @param MacroDefinitions The macro definitions in the form of dictionary +# @param SelfReplacement To decide whether replace un-defined macro to '' +# @param Line: The content contain line string and line number +# @param FileName: The meta-file file name +# +def ReplaceMacro(String, MacroDefinitions=None, SelfReplacement=False, Line=None, FileName=None, Flag=False): + LastString = String + if MacroDefinitions is None: + MacroDefinitions = {} + while MacroDefinitions: + QuotedStringList = [] + HaveQuotedMacroFlag = False + if not Flag: + MacroUsed = gMACRO_PATTERN.findall(String) + else: + ReQuotedString = re.compile('\"') + QuotedStringList = ReQuotedString.split(String) + if len(QuotedStringList) >= 3: + HaveQuotedMacroFlag = True + Count = 0 + MacroString = "" + for QuotedStringItem in QuotedStringList: + Count += 1 + if Count % 2 != 0: + MacroString += QuotedStringItem + + if Count == len(QuotedStringList) and Count % 2 == 0: + MacroString += QuotedStringItem + + MacroUsed = gMACRO_PATTERN.findall(MacroString) + # + # no macro found in String, stop replacing + # + if len(MacroUsed) == 0: + break + for Macro in MacroUsed: + if Macro not in MacroDefinitions: + if SelfReplacement: + String = String.replace("$(%s)" % Macro, '') + Logger.Debug(5, "Delete undefined MACROs in file %s line %d: %s!" % (FileName, Line[1], Line[0])) + continue + if not HaveQuotedMacroFlag: + String = String.replace("$(%s)" % Macro, MacroDefinitions[Macro]) + else: + Count = 0 + for QuotedStringItem in QuotedStringList: + Count += 1 + if Count % 2 != 0: + QuotedStringList[Count - 1] = QuotedStringList[Count - 1].replace("$(%s)" % Macro, + MacroDefinitions[Macro]) + elif Count == len(QuotedStringList) and Count % 2 == 0: + QuotedStringList[Count - 1] = QuotedStringList[Count - 1].replace("$(%s)" % Macro, + MacroDefinitions[Macro]) + + RetString = '' + if HaveQuotedMacroFlag: + Count = 0 + for QuotedStringItem in QuotedStringList: + Count += 1 + if Count != len(QuotedStringList): + RetString += QuotedStringList[Count - 1] + "\"" + else: + RetString += QuotedStringList[Count - 1] + + String = RetString + + # + # in case there's macro not defined + # + if String == LastString: + break + LastString = String + + return String + +## NormPath +# +# Create a normal path +# And replace DEFINE in the path +# +# @param Path: The input value for Path to be converted +# @param Defines: A set for DEFINE statement +# +def NormPath(Path, Defines=None): + IsRelativePath = False + if Defines is None: + Defines = {} + if Path: + if Path[0] == '.': + IsRelativePath = True + # + # Replace with Define + # + if Defines: + Path = ReplaceMacro(Path, Defines) + # + # To local path format + # + Path = os.path.normpath(Path) + + if IsRelativePath and Path[0] != '.': + Path = os.path.join('.', Path) + return Path + +## CleanString +# +# Remove 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=DataType.TAB_COMMENT_SPLIT, AllowCppStyleComment=False): + # + # remove whitespace + # + Line = Line.strip() + # + # Replace EDK1's comment character + # + if AllowCppStyleComment: + Line = Line.replace(DataType.TAB_COMMENT_EDK1_SPLIT, CommentCharacter) + # + # remove comments, but we should escape comment character in string + # + InString = False + for Index in range(0, len(Line)): + if Line[Index] == '"': + InString = not InString + elif Line[Index] == CommentCharacter and not InString: + Line = Line[0: Index] + break + # + # remove whitespace again + # + Line = Line.strip() + + return Line + +## CleanString2 +# +# 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 CleanString2(Line, CommentCharacter=DataType.TAB_COMMENT_SPLIT, AllowCppStyleComment=False): + # + # remove whitespace + # + Line = Line.strip() + # + # Replace EDK1's comment character + # + if AllowCppStyleComment: + Line = Line.replace(DataType.TAB_COMMENT_EDK1_SPLIT, CommentCharacter) + # + # separate comments and statements + # + LineParts = Line.split(CommentCharacter, 1) + # + # remove whitespace again + # + Line = LineParts[0].strip() + if len(LineParts) > 1: + Comment = LineParts[1].strip() + # + # Remove prefixed and trailing comment characters + # + Start = 0 + End = len(Comment) + while Start < End and Comment.startswith(CommentCharacter, Start, End): + Start += 1 + while End >= 0 and Comment.endswith(CommentCharacter, Start, End): + End -= 1 + Comment = Comment[Start:End] + Comment = Comment.strip() + else: + Comment = '' + + return Line, Comment + +## GetMultipleValuesOfKeyFromLines +# +# Parse multiple strings to clean comment and spaces +# The result is saved to KeyValues +# +# @param Lines: The content to be parsed +# @param Key: Reserved +# @param KeyValues: To store data after parsing +# @param CommentCharacter: Comment char, used to ignore comment content +# +def GetMultipleValuesOfKeyFromLines(Lines, Key, KeyValues, CommentCharacter): + if Key: + pass + if KeyValues: + pass + Lines = Lines.split(DataType.TAB_SECTION_END, 1)[1] + LineList = Lines.split('\n') + for Line in LineList: + Line = CleanString(Line, CommentCharacter) + if Line != '' and Line[0] != CommentCharacter: + KeyValues += [Line] + return True + +## GetDefineValue +# +# Parse a DEFINE statement to get defined value +# DEFINE Key Value +# +# @param String: The content to be parsed +# @param Key: The key of DEFINE statement +# @param CommentCharacter: Comment char, used to ignore comment content +# +def GetDefineValue(String, Key, CommentCharacter): + if CommentCharacter: + pass + String = CleanString(String) + return String[String.find(Key + ' ') + len(Key + ' ') : ] + +## GetSingleValueOfKeyFromLines +# +# Parse multiple strings as below to get value of each definition line +# Key1 = Value1 +# Key2 = Value2 +# The result is saved to Dictionary +# +# @param Lines: The content to be parsed +# @param Dictionary: To store data after parsing +# @param CommentCharacter: Comment char, be used to ignore comment content +# @param KeySplitCharacter: Key split char, between key name and key value. +# Key1 = Value1, '=' is the key split char +# @param ValueSplitFlag: Value split flag, be used to decide if has +# multiple values +# @param ValueSplitCharacter: Value split char, be used to split multiple +# values. Key1 = Value1|Value2, '|' is the value +# split char +# +def GetSingleValueOfKeyFromLines(Lines, Dictionary, CommentCharacter, KeySplitCharacter, \ + ValueSplitFlag, ValueSplitCharacter): + Lines = Lines.split('\n') + Keys = [] + Value = '' + DefineValues = [''] + SpecValues = [''] + + for Line in Lines: + # + # Handle DEFINE and SPEC + # + if Line.find(DataType.TAB_INF_DEFINES_DEFINE + ' ') > -1: + if '' in DefineValues: + DefineValues.remove('') + DefineValues.append(GetDefineValue(Line, DataType.TAB_INF_DEFINES_DEFINE, CommentCharacter)) + continue + if Line.find(DataType.TAB_INF_DEFINES_SPEC + ' ') > -1: + if '' in SpecValues: + SpecValues.remove('') + SpecValues.append(GetDefineValue(Line, DataType.TAB_INF_DEFINES_SPEC, CommentCharacter)) + continue + + # + # Handle Others + # + LineList = Line.split(KeySplitCharacter, 1) + if len(LineList) >= 2: + Key = LineList[0].split() + if len(Key) == 1 and Key[0][0] != CommentCharacter: + # + # Remove comments and white spaces + # + LineList[1] = CleanString(LineList[1], CommentCharacter) + if ValueSplitFlag: + Value = list(map(lambda x: x.strip(), LineList[1].split(ValueSplitCharacter))) + else: + Value = CleanString(LineList[1], CommentCharacter).splitlines() + + if Key[0] in Dictionary: + if Key[0] not in Keys: + Dictionary[Key[0]] = Value + Keys.append(Key[0]) + else: + Dictionary[Key[0]].extend(Value) + else: + Dictionary[DataType.TAB_INF_DEFINES_MACRO][Key[0]] = Value[0] + + if DefineValues == []: + DefineValues = [''] + if SpecValues == []: + SpecValues = [''] + Dictionary[DataType.TAB_INF_DEFINES_DEFINE] = DefineValues + Dictionary[DataType.TAB_INF_DEFINES_SPEC] = SpecValues + + return True + +## The content to be parsed +# +# Do pre-check for a file before it is parsed +# Check $() +# Check [] +# +# @param FileName: Used for error report +# @param FileContent: File content to be parsed +# @param SupSectionTag: Used for error report +# +def PreCheck(FileName, FileContent, SupSectionTag): + if SupSectionTag: + pass + LineNo = 0 + IsFailed = False + NewFileContent = '' + for Line in FileContent.splitlines(): + LineNo = LineNo + 1 + # + # Clean current line + # + Line = CleanString(Line) + # + # Remove commented line + # + if Line.find(DataType.TAB_COMMA_SPLIT) == 0: + Line = '' + # + # Check $() + # + if Line.find('$') > -1: + if Line.find('$(') < 0 or Line.find(')') < 0: + Logger.Error("Parser", FORMAT_INVALID, Line=LineNo, File=FileName, RaiseError=Logger.IS_RAISE_ERROR) + # + # Check [] + # + if Line.find('[') > -1 or Line.find(']') > -1: + # + # Only get one '[' or one ']' + # + if not (Line.find('[') > -1 and Line.find(']') > -1): + Logger.Error("Parser", FORMAT_INVALID, Line=LineNo, File=FileName, RaiseError=Logger.IS_RAISE_ERROR) + # + # Regenerate FileContent + # + NewFileContent = NewFileContent + Line + '\r\n' + + if IsFailed: + Logger.Error("Parser", FORMAT_INVALID, Line=LineNo, File=FileName, RaiseError=Logger.IS_RAISE_ERROR) + + return NewFileContent + +## CheckFileType +# +# Check if the Filename is including ExtName +# Return True if it exists +# Raise a error message if it not exists +# +# @param CheckFilename: Name of the file to be checked +# @param ExtName: Ext name of the file to be checked +# @param ContainerFilename: The container file which describes the file to be +# checked, used for error report +# @param SectionName: Used for error report +# @param Line: The line in container file which defines the file +# to be checked +# +def CheckFileType(CheckFilename, ExtName, ContainerFilename, SectionName, Line, LineNo= -1): + if CheckFilename != '' and CheckFilename is not None: + (Root, Ext) = os.path.splitext(CheckFilename) + if Ext.upper() != ExtName.upper() and Root: + ContainerFile = open(ContainerFilename, 'r').read() + if LineNo == -1: + LineNo = GetLineNo(ContainerFile, Line) + ErrorMsg = ST.ERR_SECTIONNAME_INVALID % (SectionName, CheckFilename, ExtName) + Logger.Error("Parser", PARSER_ERROR, ErrorMsg, Line=LineNo, \ + File=ContainerFilename, RaiseError=Logger.IS_RAISE_ERROR) + + return True + +## CheckFileExist +# +# Check if the file exists +# Return True if it exists +# Raise a error message if it not exists +# +# @param CheckFilename: Name of the file to be checked +# @param WorkspaceDir: Current workspace dir +# @param ContainerFilename: The container file which describes the file to +# be checked, used for error report +# @param SectionName: Used for error report +# @param Line: The line in container file which defines the +# file to be checked +# +def CheckFileExist(WorkspaceDir, CheckFilename, ContainerFilename, SectionName, Line, LineNo= -1): + CheckFile = '' + if CheckFilename != '' and CheckFilename is not None: + CheckFile = WorkspaceFile(WorkspaceDir, CheckFilename) + if not os.path.isfile(CheckFile): + ContainerFile = open(ContainerFilename, 'r').read() + if LineNo == -1: + LineNo = GetLineNo(ContainerFile, Line) + ErrorMsg = ST.ERR_CHECKFILE_NOTFOUND % (CheckFile, SectionName) + Logger.Error("Parser", PARSER_ERROR, ErrorMsg, + File=ContainerFilename, Line=LineNo, RaiseError=Logger.IS_RAISE_ERROR) + return CheckFile + +## GetLineNo +# +# Find the index of a line in a file +# +# @param FileContent: Search scope +# @param Line: Search key +# +def GetLineNo(FileContent, Line, IsIgnoreComment=True): + LineList = FileContent.splitlines() + for Index in range(len(LineList)): + if LineList[Index].find(Line) > -1: + # + # Ignore statement in comment + # + if IsIgnoreComment: + if LineList[Index].strip()[0] == DataType.TAB_COMMENT_SPLIT: + continue + return Index + 1 + + return -1 + +## RaiseParserError +# +# Raise a parser error +# +# @param Line: String which has error +# @param Section: Used for error report +# @param File: File which has the string +# @param Format: Correct format +# +def RaiseParserError(Line, Section, File, Format='', LineNo= -1): + if LineNo == -1: + LineNo = GetLineNo(open(os.path.normpath(File), 'r').read(), Line) + ErrorMsg = ST.ERR_INVALID_NOTFOUND % (Line, Section) + if Format != '': + Format = "Correct format is " + Format + Logger.Error("Parser", PARSER_ERROR, ErrorMsg, File=File, Line=LineNo, \ + ExtraData=Format, RaiseError=Logger.IS_RAISE_ERROR) + +## WorkspaceFile +# +# Return a full path with workspace dir +# +# @param WorkspaceDir: Workspace dir +# @param Filename: Relative file name +# +def WorkspaceFile(WorkspaceDir, Filename): + return os.path.join(NormPath(WorkspaceDir), NormPath(Filename)) + +## Split string +# +# Remove '"' which startswith and endswith string +# +# @param String: The string need to be split +# +def SplitString(String): + if String.startswith('\"'): + String = String[1:] + if String.endswith('\"'): + String = String[:-1] + return String + +## Convert To Sql String +# +# Replace "'" with "''" in each item of StringList +# +# @param StringList: A list for strings to be converted +# +def ConvertToSqlString(StringList): + return list(map(lambda s: s.replace("'", "''"), StringList)) + +## Convert To Sql String +# +# Replace "'" with "''" in the String +# +# @param String: A String to be converted +# +def ConvertToSqlString2(String): + return String.replace("'", "''") + +## GetStringOfList +# +# Get String of a List +# +# @param Lines: string list +# @param Split: split character +# +def GetStringOfList(List, Split=' '): + if not isinstance(List, type([])): + return List + Str = '' + for Item in List: + Str = Str + Item + Split + return Str.strip() + +## Get HelpTextList +# +# Get HelpTextList from HelpTextClassList +# +# @param HelpTextClassList: Help Text Class List +# +def GetHelpTextList(HelpTextClassList): + List = [] + if HelpTextClassList: + for HelpText in HelpTextClassList: + if HelpText.String.endswith('\n'): + HelpText.String = HelpText.String[0: len(HelpText.String) - len('\n')] + List.extend(HelpText.String.split('\n')) + return List + +## Get String Array Length +# +# Get String Array Length +# +# @param String: the source string +# +def StringArrayLength(String): + if String.startswith('L"'): + return (len(String) - 3 + 1) * 2 + elif String.startswith('"'): + return (len(String) - 2 + 1) + else: + return len(String.split()) + 1 + +## RemoveDupOption +# +# Remove Dup Option +# +# @param OptionString: the option string +# @param Which: Which flag +# @param Against: Against flag +# +def RemoveDupOption(OptionString, Which="/I", Against=None): + OptionList = OptionString.split() + ValueList = [] + if Against: + ValueList += Against + for Index in range(len(OptionList)): + Opt = OptionList[Index] + if not Opt.startswith(Which): + continue + if len(Opt) > len(Which): + Val = Opt[len(Which):] + else: + Val = "" + if Val in ValueList: + OptionList[Index] = "" + else: + ValueList.append(Val) + return " ".join(OptionList) + +## Check if the string is HexDgit +# +# Return true if all characters in the string are digits and there is at +# least one character +# or valid Hexs (started with 0x, following by hexdigit letters) +# , false otherwise. +# @param string: input string +# +def IsHexDigit(Str): + try: + int(Str, 10) + return True + except ValueError: + if len(Str) > 2 and Str.upper().startswith('0X'): + try: + int(Str, 16) + return True + except ValueError: + return False + return False + +## Check if the string is HexDgit and its integer value within limit of UINT32 +# +# Return true if all characters in the string are digits and there is at +# least one character +# or valid Hexs (started with 0x, following by hexdigit letters) +# , false otherwise. +# @param string: input string +# +def IsHexDigitUINT32(Str): + try: + Value = int(Str, 10) + if (Value <= 0xFFFFFFFF) and (Value >= 0): + return True + except ValueError: + if len(Str) > 2 and Str.upper().startswith('0X'): + try: + Value = int(Str, 16) + if (Value <= 0xFFFFFFFF) and (Value >= 0): + return True + except ValueError: + return False + return False + +## CleanSpecialChar +# +# The ASCII text files of type INF, DEC, INI are edited by developers, +# and may contain characters that cannot be directly translated to strings that +# are conformant with the UDP XML Schema. Any characters in this category +# (0x00-0x08, TAB [0x09], 0x0B, 0x0C, 0x0E-0x1F, 0x80-0xFF) +# must be converted to a space character[0x20] as part of the parsing process. +# +def ConvertSpecialChar(Lines): + RetLines = [] + for line in Lines: + ReMatchSpecialChar = re.compile(r"[\x00-\x08]|\x09|\x0b|\x0c|[\x0e-\x1f]|[\x7f-\xff]") + RetLines.append(ReMatchSpecialChar.sub(' ', line)) + + return RetLines + +## __GetTokenList +# +# Assume Str is a valid feature flag expression. +# Return a list which contains tokens: alpha numeric token and other token +# Whitespace are not stripped +# +def __GetTokenList(Str): + InQuote = False + Token = '' + TokenOP = '' + PreChar = '' + List = [] + for Char in Str: + if InQuote: + Token += Char + if Char == '"' and PreChar != '\\': + InQuote = not InQuote + List.append(Token) + Token = '' + continue + if Char == '"': + if Token and Token != 'L': + List.append(Token) + Token = '' + if TokenOP: + List.append(TokenOP) + TokenOP = '' + InQuote = not InQuote + Token += Char + continue + + if not (Char.isalnum() or Char in '_'): + TokenOP += Char + if Token: + List.append(Token) + Token = '' + else: + Token += Char + if TokenOP: + List.append(TokenOP) + TokenOP = '' + + if PreChar == '\\' and Char == '\\': + PreChar = '' + else: + PreChar = Char + if Token: + List.append(Token) + if TokenOP: + List.append(TokenOP) + return List + +## ConvertNEToNOTEQ +# +# Convert NE operator to NOT EQ +# For example: 1 NE 2 -> 1 NOT EQ 2 +# +# @param Expr: Feature flag expression to be converted +# +def ConvertNEToNOTEQ(Expr): + List = __GetTokenList(Expr) + for Index in range(len(List)): + if List[Index] == 'NE': + List[Index] = 'NOT EQ' + return ''.join(List) + +## ConvertNOTEQToNE +# +# Convert NOT EQ operator to NE +# For example: 1 NOT NE 2 -> 1 NE 2 +# +# @param Expr: Feature flag expression to be converted +# +def ConvertNOTEQToNE(Expr): + List = __GetTokenList(Expr) + HasNOT = False + RetList = [] + for Token in List: + if HasNOT and Token == 'EQ': + # At least, 'NOT' is in the list + while not RetList[-1].strip(): + RetList.pop() + RetList[-1] = 'NE' + HasNOT = False + continue + if Token == 'NOT': + HasNOT = True + elif Token.strip(): + HasNOT = False + RetList.append(Token) + + return ''.join(RetList) + +## SplitPcdEntry +# +# Split an PCD entry string to Token.CName and PCD value and FFE. +# NOTE: PCD Value and FFE can contain "|" in its expression. And in INF specification, have below rule. +# When using the characters "|" or "||" in an expression, the expression must be encapsulated in +# open "(" and close ")" parenthesis. +# +# @param String An PCD entry string need to be split. +# +# @return List [PcdTokenCName, Value, FFE] +# +def SplitPcdEntry(String): + if not String: + return ['', '', ''], False + + PcdTokenCName = '' + PcdValue = '' + PcdFeatureFlagExp = '' + + ValueList = GetSplitValueList(String, "|", 1) + + # + # Only contain TokenCName + # + if len(ValueList) == 1: + return [ValueList[0]], True + + NewValueList = [] + + if len(ValueList) == 2: + PcdTokenCName = ValueList[0] + + InQuote = False + InParenthesis = False + StrItem = '' + for StrCh in ValueList[1]: + if StrCh == '"': + InQuote = not InQuote + elif StrCh == '(' or StrCh == ')': + InParenthesis = not InParenthesis + + if StrCh == '|': + if not InQuote or not InParenthesis: + NewValueList.append(StrItem.strip()) + StrItem = ' ' + continue + + StrItem += StrCh + + NewValueList.append(StrItem.strip()) + + if len(NewValueList) == 1: + PcdValue = NewValueList[0] + return [PcdTokenCName, PcdValue], True + elif len(NewValueList) == 2: + PcdValue = NewValueList[0] + PcdFeatureFlagExp = NewValueList[1] + return [PcdTokenCName, PcdValue, PcdFeatureFlagExp], True + else: + return ['', '', ''], False + + return ['', '', ''], False + +## Check if two arches matched? +# +# @param Arch1 +# @param Arch2 +# +def IsMatchArch(Arch1, Arch2): + if 'COMMON' in Arch1 or 'COMMON' in Arch2: + return True + try: + if isinstance(Arch1, list) and isinstance(Arch2, list): + for Item1 in Arch1: + for Item2 in Arch2: + if Item1 == Item2: + return True + + elif isinstance(Arch1, list): + return Arch2 in Arch1 + + elif isinstance(Arch2, list): + return Arch1 in Arch2 + + else: + if Arch1 == Arch2: + return True + except: + return False + +# Search all files in FilePath to find the FileName with the largest index +# Return the FileName with index +1 under the FilePath +# +def GetUniFileName(FilePath, FileName): + Files = [] + try: + Files = os.listdir(FilePath) + except: + pass + + LargestIndex = -1 + IndexNotFound = True + for File in Files: + if File.upper().startswith(FileName.upper()) and File.upper().endswith('.UNI'): + Index = File.upper().replace(FileName.upper(), '').replace('.UNI', '') + if Index: + try: + Index = int(Index) + except Exception: + Index = -1 + else: + IndexNotFound = False + Index = 0 + if Index > LargestIndex: + LargestIndex = Index + 1 + + if LargestIndex > -1 and not IndexNotFound: + return os.path.normpath(os.path.join(FilePath, FileName + str(LargestIndex) + '.uni')) + else: + return os.path.normpath(os.path.join(FilePath, FileName + '.uni')) diff --git a/BaseTools/Source/Python/UPT/Library/UniClassObject.py b/BaseTools/Source/Python/UPT/Library/UniClassObject.py index 8c44dc2252..dcf8a81ccf 100644 --- a/BaseTools/Source/Python/UPT/Library/UniClassObject.py +++ b/BaseTools/Source/Python/UPT/Library/UniClassObject.py @@ -1,1074 +1,1074 @@ -## @file
-# Collect all defined strings in multiple uni files.
-#
-# Copyright (c) 2014 - 2019, Intel Corporation. All rights reserved.<BR>
-#
-# SPDX-License-Identifier: BSD-2-Clause-Patent
-#
-"""
-Collect all defined strings in multiple uni files
-"""
-from __future__ import print_function
-
-##
-# Import Modules
-#
-import os, codecs, re
-import shlex
-from Logger import ToolError
-from Logger import Log as EdkLogger
-from Logger import StringTable as ST
-from Library.StringUtils import GetLineNo
-from Library.Misc import PathClass
-from Library.Misc import GetCharIndexOutStr
-from Library import DataType as DT
-from Library.ParserValidate import CheckUTF16FileHeader
-
-##
-# Static definitions
-#
-UNICODE_WIDE_CHAR = u'\\wide'
-UNICODE_NARROW_CHAR = u'\\narrow'
-UNICODE_NON_BREAKING_CHAR = u'\\nbr'
-UNICODE_UNICODE_CR = '\r'
-UNICODE_UNICODE_LF = '\n'
-
-NARROW_CHAR = u'\uFFF0'
-WIDE_CHAR = u'\uFFF1'
-NON_BREAKING_CHAR = u'\uFFF2'
-CR = u'\u000D'
-LF = u'\u000A'
-NULL = u'\u0000'
-TAB = u'\t'
-BACK_SPLASH = u'\\'
-
-gLANG_CONV_TABLE = {'eng':'en', 'fra':'fr', \
- 'aar':'aa', 'abk':'ab', 'ave':'ae', 'afr':'af', 'aka':'ak', 'amh':'am', \
- 'arg':'an', 'ara':'ar', 'asm':'as', 'ava':'av', 'aym':'ay', 'aze':'az', \
- 'bak':'ba', 'bel':'be', 'bul':'bg', 'bih':'bh', 'bis':'bi', 'bam':'bm', \
- 'ben':'bn', 'bod':'bo', 'bre':'br', 'bos':'bs', 'cat':'ca', 'che':'ce', \
- 'cha':'ch', 'cos':'co', 'cre':'cr', 'ces':'cs', 'chu':'cu', 'chv':'cv', \
- 'cym':'cy', 'dan':'da', 'deu':'de', 'div':'dv', 'dzo':'dz', 'ewe':'ee', \
- 'ell':'el', 'epo':'eo', 'spa':'es', 'est':'et', 'eus':'eu', 'fas':'fa', \
- 'ful':'ff', 'fin':'fi', 'fij':'fj', 'fao':'fo', 'fry':'fy', 'gle':'ga', \
- 'gla':'gd', 'glg':'gl', 'grn':'gn', 'guj':'gu', 'glv':'gv', 'hau':'ha', \
- 'heb':'he', 'hin':'hi', 'hmo':'ho', 'hrv':'hr', 'hat':'ht', 'hun':'hu', \
- 'hye':'hy', 'her':'hz', 'ina':'ia', 'ind':'id', 'ile':'ie', 'ibo':'ig', \
- 'iii':'ii', 'ipk':'ik', 'ido':'io', 'isl':'is', 'ita':'it', 'iku':'iu', \
- 'jpn':'ja', 'jav':'jv', 'kat':'ka', 'kon':'kg', 'kik':'ki', 'kua':'kj', \
- 'kaz':'kk', 'kal':'kl', 'khm':'km', 'kan':'kn', 'kor':'ko', 'kau':'kr', \
- 'kas':'ks', 'kur':'ku', 'kom':'kv', 'cor':'kw', 'kir':'ky', 'lat':'la', \
- 'ltz':'lb', 'lug':'lg', 'lim':'li', 'lin':'ln', 'lao':'lo', 'lit':'lt', \
- 'lub':'lu', 'lav':'lv', 'mlg':'mg', 'mah':'mh', 'mri':'mi', 'mkd':'mk', \
- 'mal':'ml', 'mon':'mn', 'mar':'mr', 'msa':'ms', 'mlt':'mt', 'mya':'my', \
- 'nau':'na', 'nob':'nb', 'nde':'nd', 'nep':'ne', 'ndo':'ng', 'nld':'nl', \
- 'nno':'nn', 'nor':'no', 'nbl':'nr', 'nav':'nv', 'nya':'ny', 'oci':'oc', \
- 'oji':'oj', 'orm':'om', 'ori':'or', 'oss':'os', 'pan':'pa', 'pli':'pi', \
- 'pol':'pl', 'pus':'ps', 'por':'pt', 'que':'qu', 'roh':'rm', 'run':'rn', \
- 'ron':'ro', 'rus':'ru', 'kin':'rw', 'san':'sa', 'srd':'sc', 'snd':'sd', \
- 'sme':'se', 'sag':'sg', 'sin':'si', 'slk':'sk', 'slv':'sl', 'smo':'sm', \
- 'sna':'sn', 'som':'so', 'sqi':'sq', 'srp':'sr', 'ssw':'ss', 'sot':'st', \
- 'sun':'su', 'swe':'sv', 'swa':'sw', 'tam':'ta', 'tel':'te', 'tgk':'tg', \
- 'tha':'th', 'tir':'ti', 'tuk':'tk', 'tgl':'tl', 'tsn':'tn', 'ton':'to', \
- 'tur':'tr', 'tso':'ts', 'tat':'tt', 'twi':'tw', 'tah':'ty', 'uig':'ug', \
- 'ukr':'uk', 'urd':'ur', 'uzb':'uz', 'ven':'ve', 'vie':'vi', 'vol':'vo', \
- 'wln':'wa', 'wol':'wo', 'xho':'xh', 'yid':'yi', 'yor':'yo', 'zha':'za', \
- 'zho':'zh', 'zul':'zu'}
-
-## Convert a python unicode string to a normal string
-#
-# Convert a python unicode string to a normal string
-# UniToStr(u'I am a string') is 'I am a string'
-#
-# @param Uni: The python unicode string
-#
-# @retval: The formatted normal string
-#
-def UniToStr(Uni):
- return repr(Uni)[2:-1]
-
-## Convert a unicode string to a Hex list
-#
-# Convert a unicode string to a Hex list
-# UniToHexList('ABC') is ['0x41', '0x00', '0x42', '0x00', '0x43', '0x00']
-#
-# @param Uni: The python unicode string
-#
-# @retval List: The formatted hex list
-#
-def UniToHexList(Uni):
- List = []
- for Item in Uni:
- Temp = '%04X' % ord(Item)
- List.append('0x' + Temp[2:4])
- List.append('0x' + Temp[0:2])
- return List
-
-## Convert special unicode characters
-#
-# Convert special characters to (c), (r) and (tm).
-#
-# @param Uni: The python unicode string
-#
-# @retval NewUni: The converted unicode string
-#
-def ConvertSpecialUnicodes(Uni):
- OldUni = NewUni = Uni
- NewUni = NewUni.replace(u'\u00A9', '(c)')
- NewUni = NewUni.replace(u'\u00AE', '(r)')
- NewUni = NewUni.replace(u'\u2122', '(tm)')
- if OldUni == NewUni:
- NewUni = OldUni
- return NewUni
-
-## GetLanguageCode1766
-#
-# Check the language code read from .UNI file and convert RFC 4646 codes to RFC 1766 codes
-# RFC 1766 language codes supported in compatibility mode
-# RFC 4646 language codes supported in native mode
-#
-# @param LangName: Language codes read from .UNI file
-#
-# @retval LangName: Valid language code in RFC 1766 format or None
-#
-def GetLanguageCode1766(LangName, File=None):
- return LangName
-
- length = len(LangName)
- if length == 2:
- if LangName.isalpha():
- for Key in gLANG_CONV_TABLE.keys():
- if gLANG_CONV_TABLE.get(Key) == LangName.lower():
- return Key
- elif length == 3:
- if LangName.isalpha() and gLANG_CONV_TABLE.get(LangName.lower()):
- return LangName
- else:
- EdkLogger.Error("Unicode File Parser",
- ToolError.FORMAT_INVALID,
- "Invalid RFC 1766 language code : %s" % LangName,
- File)
- elif length == 5:
- if LangName[0:2].isalpha() and LangName[2] == '-':
- for Key in gLANG_CONV_TABLE.keys():
- if gLANG_CONV_TABLE.get(Key) == LangName[0:2].lower():
- return Key
- elif length >= 6:
- if LangName[0:2].isalpha() and LangName[2] == '-':
- for Key in gLANG_CONV_TABLE.keys():
- if gLANG_CONV_TABLE.get(Key) == LangName[0:2].lower():
- return Key
- if LangName[0:3].isalpha() and gLANG_CONV_TABLE.get(LangName.lower()) is None and LangName[3] == '-':
- for Key in gLANG_CONV_TABLE.keys():
- if Key == LangName[0:3].lower():
- return Key
-
- EdkLogger.Error("Unicode File Parser",
- ToolError.FORMAT_INVALID,
- "Invalid RFC 4646 language code : %s" % LangName,
- File)
-
-## GetLanguageCode
-#
-# Check the language code read from .UNI file and convert RFC 1766 codes to RFC 4646 codes if appropriate
-# RFC 1766 language codes supported in compatibility mode
-# RFC 4646 language codes supported in native mode
-#
-# @param LangName: Language codes read from .UNI file
-#
-# @retval LangName: Valid lanugage code in RFC 4646 format or None
-#
-def GetLanguageCode(LangName, IsCompatibleMode, File):
- length = len(LangName)
- if IsCompatibleMode:
- if length == 3 and LangName.isalpha():
- TempLangName = gLANG_CONV_TABLE.get(LangName.lower())
- if TempLangName is not None:
- return TempLangName
- return LangName
- else:
- EdkLogger.Error("Unicode File Parser",
- ToolError.FORMAT_INVALID,
- "Invalid RFC 1766 language code : %s" % LangName,
- File)
- if (LangName[0] == 'X' or LangName[0] == 'x') and LangName[1] == '-':
- return LangName
- if length == 2:
- if LangName.isalpha():
- return LangName
- elif length == 3:
- if LangName.isalpha() and gLANG_CONV_TABLE.get(LangName.lower()) is None:
- return LangName
- elif length == 5:
- if LangName[0:2].isalpha() and LangName[2] == '-':
- return LangName
- elif length >= 6:
- if LangName[0:2].isalpha() and LangName[2] == '-':
- return LangName
- if LangName[0:3].isalpha() and gLANG_CONV_TABLE.get(LangName.lower()) is None and LangName[3] == '-':
- return LangName
-
- EdkLogger.Error("Unicode File Parser",
- ToolError.FORMAT_INVALID,
- "Invalid RFC 4646 language code : %s" % LangName,
- File)
-
-## FormatUniEntry
-#
-# Formatted the entry in Uni file.
-#
-# @param StrTokenName StrTokenName.
-# @param TokenValueList A list need to be processed.
-# @param ContainerFile ContainerFile.
-#
-# @return formatted entry
-def FormatUniEntry(StrTokenName, TokenValueList, ContainerFile):
- SubContent = ''
- PreFormatLength = 40
- if len(StrTokenName) > PreFormatLength:
- PreFormatLength = len(StrTokenName) + 1
- for (Lang, Value) in TokenValueList:
- if not Value or Lang == DT.TAB_LANGUAGE_EN_X:
- continue
- if Lang == '':
- Lang = DT.TAB_LANGUAGE_EN_US
- if Lang == 'eng':
- Lang = DT.TAB_LANGUAGE_EN_US
- elif len(Lang.split('-')[0]) == 3:
- Lang = GetLanguageCode(Lang.split('-')[0], True, ContainerFile)
- else:
- Lang = GetLanguageCode(Lang, False, ContainerFile)
- ValueList = Value.split('\n')
- SubValueContent = ''
- for SubValue in ValueList:
- if SubValue.strip():
- SubValueContent += \
- ' ' * (PreFormatLength + len('#language en-US ')) + '\"%s\\n\"' % SubValue.strip() + '\r\n'
- SubValueContent = SubValueContent[(PreFormatLength + len('#language en-US ')):SubValueContent.rfind('\\n')] \
- + '\"' + '\r\n'
- SubContent += ' '*PreFormatLength + '#language %-5s ' % Lang + SubValueContent
- if SubContent:
- SubContent = StrTokenName + ' '*(PreFormatLength - len(StrTokenName)) + SubContent[PreFormatLength:]
- return SubContent
-
-
-## StringDefClassObject
-#
-# A structure for language definition
-#
-class StringDefClassObject(object):
- def __init__(self, Name = None, Value = None, Referenced = False, Token = None, UseOtherLangDef = ''):
- self.StringName = ''
- self.StringNameByteList = []
- self.StringValue = ''
- self.StringValueByteList = ''
- self.Token = 0
- self.Referenced = Referenced
- self.UseOtherLangDef = UseOtherLangDef
- self.Length = 0
-
- if Name is not None:
- self.StringName = Name
- self.StringNameByteList = UniToHexList(Name)
- if Value is not None:
- self.StringValue = Value
- self.StringValueByteList = UniToHexList(self.StringValue)
- self.Length = len(self.StringValueByteList)
- if Token is not None:
- self.Token = Token
-
- def __str__(self):
- return repr(self.StringName) + ' ' + \
- repr(self.Token) + ' ' + \
- repr(self.Referenced) + ' ' + \
- repr(self.StringValue) + ' ' + \
- repr(self.UseOtherLangDef)
-
- def UpdateValue(self, Value = None):
- if Value is not None:
- if self.StringValue:
- self.StringValue = self.StringValue + '\r\n' + Value
- else:
- self.StringValue = Value
- self.StringValueByteList = UniToHexList(self.StringValue)
- self.Length = len(self.StringValueByteList)
-
-## UniFileClassObject
-#
-# A structure for .uni file definition
-#
-class UniFileClassObject(object):
- def __init__(self, FileList = None, IsCompatibleMode = False, IncludePathList = None):
- self.FileList = FileList
- self.File = None
- self.IncFileList = FileList
- self.UniFileHeader = ''
- self.Token = 2
- self.LanguageDef = [] #[ [u'LanguageIdentifier', u'PrintableName'], ... ]
- self.OrderedStringList = {} #{ u'LanguageIdentifier' : [StringDefClassObject] }
- self.OrderedStringDict = {} #{ u'LanguageIdentifier' : {StringName:(IndexInList)} }
- self.OrderedStringListByToken = {} #{ u'LanguageIdentifier' : {Token: StringDefClassObject} }
- self.IsCompatibleMode = IsCompatibleMode
- if not IncludePathList:
- self.IncludePathList = []
- else:
- self.IncludePathList = IncludePathList
- if len(self.FileList) > 0:
- self.LoadUniFiles(FileList)
-
- #
- # Get Language definition
- #
- def GetLangDef(self, File, Line):
- Lang = shlex.split(Line.split(u"//")[0])
- if len(Lang) != 3:
- try:
- FileIn = codecs.open(File.Path, mode='rb', encoding='utf_8').readlines()
- except UnicodeError as Xstr:
- FileIn = codecs.open(File.Path, mode='rb', encoding='utf_16').readlines()
- except UnicodeError as Xstr:
- FileIn = codecs.open(File.Path, mode='rb', encoding='utf_16_le').readlines()
- except:
- EdkLogger.Error("Unicode File Parser",
- ToolError.FILE_OPEN_FAILURE,
- "File read failure: %s" % str(Xstr),
- ExtraData=File)
- LineNo = GetLineNo(FileIn, Line, False)
- EdkLogger.Error("Unicode File Parser",
- ToolError.PARSER_ERROR,
- "Wrong language definition",
- ExtraData="""%s\n\t*Correct format is like '#langdef en-US "English"'""" % Line,
- File = File, Line = LineNo)
- else:
- LangName = GetLanguageCode(Lang[1], self.IsCompatibleMode, self.File)
- LangPrintName = Lang[2]
-
- IsLangInDef = False
- for Item in self.LanguageDef:
- if Item[0] == LangName:
- IsLangInDef = True
- break
-
- if not IsLangInDef:
- self.LanguageDef.append([LangName, LangPrintName])
-
- #
- # Add language string
- #
- self.AddStringToList(u'$LANGUAGE_NAME', LangName, LangName, 0, True, Index=0)
- self.AddStringToList(u'$PRINTABLE_LANGUAGE_NAME', LangName, LangPrintName, 1, True, Index=1)
-
- if not IsLangInDef:
- #
- # The found STRING tokens will be added into new language string list
- # so that the unique STRING identifier is reserved for all languages in the package list.
- #
- FirstLangName = self.LanguageDef[0][0]
- if LangName != FirstLangName:
- for Index in range (2, len (self.OrderedStringList[FirstLangName])):
- Item = self.OrderedStringList[FirstLangName][Index]
- if Item.UseOtherLangDef != '':
- OtherLang = Item.UseOtherLangDef
- else:
- OtherLang = FirstLangName
- self.OrderedStringList[LangName].append (StringDefClassObject(Item.StringName,
- '',
- Item.Referenced,
- Item.Token,
- OtherLang))
- self.OrderedStringDict[LangName][Item.StringName] = len(self.OrderedStringList[LangName]) - 1
- return True
-
- #
- # Get String name and value
- #
- def GetStringObject(self, Item):
- Language = ''
- Value = ''
-
- Name = Item.split()[1]
- # Check the string name is the upper character
- if Name != '':
- MatchString = re.match('[A-Z0-9_]+', Name, re.UNICODE)
- if MatchString is None or MatchString.end(0) != len(Name):
- EdkLogger.Error("Unicode File Parser",
- ToolError.FORMAT_INVALID,
- 'The string token name %s in UNI file %s must be upper case character.' %(Name, self.File))
- LanguageList = Item.split(u'#language ')
- for IndexI in range(len(LanguageList)):
- if IndexI == 0:
- continue
- else:
- Language = LanguageList[IndexI].split()[0]
- #.replace(u'\r\n', u'')
- Value = \
- LanguageList[IndexI][LanguageList[IndexI].find(u'\"') + len(u'\"') : LanguageList[IndexI].rfind(u'\"')]
- Language = GetLanguageCode(Language, self.IsCompatibleMode, self.File)
- self.AddStringToList(Name, Language, Value)
-
- #
- # Get include file list and load them
- #
- def GetIncludeFile(self, Item, Dir = None):
- if Dir:
- pass
- FileName = Item[Item.find(u'!include ') + len(u'!include ') :Item.find(u' ', len(u'!include '))][1:-1]
- self.LoadUniFile(FileName)
-
- #
- # Pre-process before parse .uni file
- #
- def PreProcess(self, File, IsIncludeFile=False):
- if not os.path.exists(File.Path) or not os.path.isfile(File.Path):
- EdkLogger.Error("Unicode File Parser",
- ToolError.FILE_NOT_FOUND,
- ExtraData=File.Path)
-
- #
- # Check file header of the Uni file
- #
-# if not CheckUTF16FileHeader(File.Path):
-# EdkLogger.Error("Unicode File Parser", ToolError.FORMAT_INVALID,
-# ExtraData='The file %s is either invalid UTF-16LE or it is missing the BOM.' % File.Path)
-
- try:
- FileIn = codecs.open(File.Path, mode='rb', encoding='utf_8').readlines()
- except UnicodeError as Xstr:
- FileIn = codecs.open(File.Path, mode='rb', encoding='utf_16').readlines()
- except UnicodeError:
- FileIn = codecs.open(File.Path, mode='rb', encoding='utf_16_le').readlines()
- except:
- EdkLogger.Error("Unicode File Parser", ToolError.FILE_OPEN_FAILURE, ExtraData=File.Path)
-
-
- #
- # get the file header
- #
- Lines = []
- HeaderStart = False
- HeaderEnd = False
- if not self.UniFileHeader:
- FirstGenHeader = True
- else:
- FirstGenHeader = False
- for Line in FileIn:
- Line = Line.strip()
- if Line == u'':
- continue
- if Line.startswith(DT.TAB_COMMENT_EDK1_SPLIT) and (Line.find(DT.TAB_HEADER_COMMENT) > -1) \
- and not HeaderEnd and not HeaderStart:
- HeaderStart = True
- if not Line.startswith(DT.TAB_COMMENT_EDK1_SPLIT) and HeaderStart and not HeaderEnd:
- HeaderEnd = True
- if Line.startswith(DT.TAB_COMMENT_EDK1_SPLIT) and HeaderStart and not HeaderEnd and FirstGenHeader:
- self.UniFileHeader += Line + '\r\n'
- continue
-
- #
- # Use unique identifier
- #
- FindFlag = -1
- LineCount = 0
- MultiLineFeedExits = False
- #
- # 0: initial value
- # 1: single String entry exist
- # 2: line feed exist under the some single String entry
- #
- StringEntryExistsFlag = 0
- for Line in FileIn:
- Line = FileIn[LineCount]
- LineCount += 1
- Line = Line.strip()
- #
- # Ignore comment line and empty line
- #
- if Line == u'' or Line.startswith(u'//'):
- #
- # Change the single line String entry flag status
- #
- if StringEntryExistsFlag == 1:
- StringEntryExistsFlag = 2
- #
- # If the '#string' line and the '#language' line are not in the same line,
- # there should be only one line feed character between them
- #
- if MultiLineFeedExits:
- EdkLogger.Error("Unicode File Parser", ToolError.FORMAT_INVALID, ExtraData=File.Path)
- continue
-
- MultiLineFeedExits = False
- #
- # Process comment embedded in string define lines
- #
- FindFlag = Line.find(u'//')
- if FindFlag != -1 and Line.find(u'//') < Line.find(u'"'):
- Line = Line.replace(Line[FindFlag:], u' ')
- if FileIn[LineCount].strip().startswith('#language'):
- Line = Line + FileIn[LineCount]
- FileIn[LineCount-1] = Line
- FileIn[LineCount] = '\r\n'
- LineCount -= 1
- for Index in range (LineCount + 1, len (FileIn) - 1):
- if (Index == len(FileIn) -1):
- FileIn[Index] = '\r\n'
- else:
- FileIn[Index] = FileIn[Index + 1]
- continue
- CommIndex = GetCharIndexOutStr(u'/', Line)
- if CommIndex > -1:
- if (len(Line) - 1) > CommIndex:
- if Line[CommIndex+1] == u'/':
- Line = Line[:CommIndex].strip()
- else:
- EdkLogger.Error("Unicode File Parser", ToolError.FORMAT_INVALID, ExtraData=File.Path)
- else:
- EdkLogger.Error("Unicode File Parser", ToolError.FORMAT_INVALID, ExtraData=File.Path)
-
- Line = Line.replace(UNICODE_WIDE_CHAR, WIDE_CHAR)
- Line = Line.replace(UNICODE_NARROW_CHAR, NARROW_CHAR)
- Line = Line.replace(UNICODE_NON_BREAKING_CHAR, NON_BREAKING_CHAR)
-
- Line = Line.replace(u'\\\\', u'\u0006')
- Line = Line.replace(u'\\r\\n', CR + LF)
- Line = Line.replace(u'\\n', CR + LF)
- Line = Line.replace(u'\\r', CR)
- Line = Line.replace(u'\\t', u'\t')
- Line = Line.replace(u'''\"''', u'''"''')
- Line = Line.replace(u'\t', u' ')
- Line = Line.replace(u'\u0006', u'\\')
-
- #
- # Check if single line has correct '"'
- #
- if Line.startswith(u'#string') and Line.find(u'#language') > -1 and Line.find('"') > Line.find(u'#language'):
- if not Line.endswith('"'):
- EdkLogger.Error("Unicode File Parser", ToolError.FORMAT_INVALID,
- ExtraData='''The line %s misses '"' at the end of it in file %s'''
- % (LineCount, File.Path))
-
- #
- # Between Name entry and Language entry can not contain line feed
- #
- if Line.startswith(u'#string') and Line.find(u'#language') == -1:
- MultiLineFeedExits = True
-
- if Line.startswith(u'#string') and Line.find(u'#language') > 0 and Line.find(u'"') < 0:
- MultiLineFeedExits = True
-
- #
- # Between Language entry and String entry can not contain line feed
- #
- if Line.startswith(u'#language') and len(Line.split()) == 2:
- MultiLineFeedExits = True
-
- #
- # Check the situation that there only has one '"' for the language entry
- #
- if Line.startswith(u'#string') and Line.find(u'#language') > 0 and Line.count(u'"') == 1:
- EdkLogger.Error("Unicode File Parser", ToolError.FORMAT_INVALID,
- ExtraData='''The line %s misses '"' at the end of it in file %s'''
- % (LineCount, File.Path))
-
- #
- # Check the situation that there has more than 2 '"' for the language entry
- #
- if Line.startswith(u'#string') and Line.find(u'#language') > 0 and Line.replace(u'\\"', '').count(u'"') > 2:
- EdkLogger.Error("Unicode File Parser", ToolError.FORMAT_INVALID,
- ExtraData='''The line %s has more than 2 '"' for language entry in file %s'''
- % (LineCount, File.Path))
-
- #
- # Between two String entry, can not contain line feed
- #
- if Line.startswith(u'"'):
- if StringEntryExistsFlag == 2:
- EdkLogger.Error("Unicode File Parser", ToolError.FORMAT_INVALID,
- Message=ST.ERR_UNIPARSE_LINEFEED_UP_EXIST % Line, ExtraData=File.Path)
-
- StringEntryExistsFlag = 1
- if not Line.endswith('"'):
- EdkLogger.Error("Unicode File Parser", ToolError.FORMAT_INVALID,
- ExtraData='''The line %s misses '"' at the end of it in file %s'''
- % (LineCount, File.Path))
-
- #
- # Check the situation that there has more than 2 '"' for the language entry
- #
- if Line.strip() and Line.replace(u'\\"', '').count(u'"') > 2:
- EdkLogger.Error("Unicode File Parser", ToolError.FORMAT_INVALID,
- ExtraData='''The line %s has more than 2 '"' for language entry in file %s'''
- % (LineCount, File.Path))
-
- elif Line.startswith(u'#language'):
- if StringEntryExistsFlag == 2:
- EdkLogger.Error("Unicode File Parser", ToolError.FORMAT_INVALID,
- Message=ST.ERR_UNI_MISS_STRING_ENTRY % Line, ExtraData=File.Path)
- StringEntryExistsFlag = 0
- else:
- StringEntryExistsFlag = 0
-
- Lines.append(Line)
-
- #
- # Convert string def format as below
- #
- # #string MY_STRING_1
- # #language eng
- # "My first English string line 1"
- # "My first English string line 2"
- # #string MY_STRING_1
- # #language spa
- # "Mi segunda secuencia 1"
- # "Mi segunda secuencia 2"
- #
-
- if not IsIncludeFile and not Lines:
- EdkLogger.Error("Unicode File Parser", ToolError.FORMAT_INVALID, \
- Message=ST.ERR_UNIPARSE_NO_SECTION_EXIST, \
- ExtraData=File.Path)
-
- NewLines = []
- StrName = u''
- ExistStrNameList = []
- for Line in Lines:
- if StrName and not StrName.split()[1].startswith(DT.TAB_STR_TOKENCNAME + DT.TAB_UNDERLINE_SPLIT):
- EdkLogger.Error("Unicode File Parser", ToolError.FORMAT_INVALID, \
- Message=ST.ERR_UNIPARSE_STRNAME_FORMAT_ERROR % StrName.split()[1], \
- ExtraData=File.Path)
-
- if StrName and len(StrName.split()[1].split(DT.TAB_UNDERLINE_SPLIT)) == 4:
- StringTokenList = StrName.split()[1].split(DT.TAB_UNDERLINE_SPLIT)
- if (StringTokenList[3].upper() in [DT.TAB_STR_TOKENPROMPT, DT.TAB_STR_TOKENHELP] and \
- StringTokenList[3] not in [DT.TAB_STR_TOKENPROMPT, DT.TAB_STR_TOKENHELP]) or \
- (StringTokenList[2].upper() == DT.TAB_STR_TOKENERR and StringTokenList[2] != DT.TAB_STR_TOKENERR):
- EdkLogger.Error("Unicode File Parser", ToolError.FORMAT_INVALID, \
- Message=ST.ERR_UNIPARSE_STRTOKEN_FORMAT_ERROR % StrName.split()[1], \
- ExtraData=File.Path)
-
- if Line.count(u'#language') > 1:
- EdkLogger.Error("Unicode File Parser", ToolError.FORMAT_INVALID, \
- Message=ST.ERR_UNIPARSE_SEP_LANGENTRY_LINE % Line, \
- ExtraData=File.Path)
-
- if Line.startswith(u'//'):
- continue
- elif Line.startswith(u'#langdef'):
- if len(Line.split()) == 2:
- NewLines.append(Line)
- continue
- elif len(Line.split()) > 2 and Line.find(u'"') > 0:
- NewLines.append(Line[:Line.find(u'"')].strip())
- NewLines.append(Line[Line.find(u'"'):])
- else:
- EdkLogger.Error("Unicode File Parser", ToolError.FORMAT_INVALID, ExtraData=File.Path)
- elif Line.startswith(u'#string'):
- if len(Line.split()) == 2:
- StrName = Line
- if StrName:
- if StrName.split()[1] not in ExistStrNameList:
- ExistStrNameList.append(StrName.split()[1].strip())
- elif StrName.split()[1] in [DT.TAB_INF_ABSTRACT, DT.TAB_INF_DESCRIPTION, \
- DT.TAB_INF_BINARY_ABSTRACT, DT.TAB_INF_BINARY_DESCRIPTION, \
- DT.TAB_DEC_PACKAGE_ABSTRACT, DT.TAB_DEC_PACKAGE_DESCRIPTION, \
- DT.TAB_DEC_BINARY_ABSTRACT, DT.TAB_DEC_BINARY_DESCRIPTION]:
- EdkLogger.Error("Unicode File Parser", ToolError.FORMAT_INVALID, \
- Message=ST.ERR_UNIPARSE_MULTI_ENTRY_EXIST % StrName.split()[1], \
- ExtraData=File.Path)
- continue
- elif len(Line.split()) == 4 and Line.find(u'#language') > 0:
- if Line[Line.find(u'#language')-1] != ' ' or \
- Line[Line.find(u'#language')+len(u'#language')] != u' ':
- EdkLogger.Error("Unicode File Parser", ToolError.FORMAT_INVALID, ExtraData=File.Path)
-
- if Line.find(u'"') > 0:
- EdkLogger.Error("Unicode File Parser", ToolError.FORMAT_INVALID, ExtraData=File.Path)
-
- StrName = Line.split()[0] + u' ' + Line.split()[1]
- if StrName:
- if StrName.split()[1] not in ExistStrNameList:
- ExistStrNameList.append(StrName.split()[1].strip())
- elif StrName.split()[1] in [DT.TAB_INF_ABSTRACT, DT.TAB_INF_DESCRIPTION, \
- DT.TAB_INF_BINARY_ABSTRACT, DT.TAB_INF_BINARY_DESCRIPTION, \
- DT.TAB_DEC_PACKAGE_ABSTRACT, DT.TAB_DEC_PACKAGE_DESCRIPTION, \
- DT.TAB_DEC_BINARY_ABSTRACT, DT.TAB_DEC_BINARY_DESCRIPTION]:
- EdkLogger.Error("Unicode File Parser", ToolError.FORMAT_INVALID, \
- Message=ST.ERR_UNIPARSE_MULTI_ENTRY_EXIST % StrName.split()[1], \
- ExtraData=File.Path)
- if IsIncludeFile:
- if StrName not in NewLines:
- NewLines.append((Line[:Line.find(u'#language')]).strip())
- else:
- NewLines.append((Line[:Line.find(u'#language')]).strip())
- NewLines.append((Line[Line.find(u'#language'):]).strip())
- elif len(Line.split()) > 4 and Line.find(u'#language') > 0 and Line.find(u'"') > 0:
- if Line[Line.find(u'#language')-1] != u' ' or \
- Line[Line.find(u'#language')+len(u'#language')] != u' ':
- EdkLogger.Error("Unicode File Parser", ToolError.FORMAT_INVALID, ExtraData=File.Path)
-
- if Line[Line.find(u'"')-1] != u' ':
- EdkLogger.Error("Unicode File Parser", ToolError.FORMAT_INVALID, ExtraData=File.Path)
-
- StrName = Line.split()[0] + u' ' + Line.split()[1]
- if StrName:
- if StrName.split()[1] not in ExistStrNameList:
- ExistStrNameList.append(StrName.split()[1].strip())
- elif StrName.split()[1] in [DT.TAB_INF_ABSTRACT, DT.TAB_INF_DESCRIPTION, \
- DT.TAB_INF_BINARY_ABSTRACT, DT.TAB_INF_BINARY_DESCRIPTION, \
- DT.TAB_DEC_PACKAGE_ABSTRACT, DT.TAB_DEC_PACKAGE_DESCRIPTION, \
- DT.TAB_DEC_BINARY_ABSTRACT, DT.TAB_DEC_BINARY_DESCRIPTION]:
- EdkLogger.Error("Unicode File Parser", ToolError.FORMAT_INVALID, \
- Message=ST.ERR_UNIPARSE_MULTI_ENTRY_EXIST % StrName.split()[1], \
- ExtraData=File.Path)
- if IsIncludeFile:
- if StrName not in NewLines:
- NewLines.append((Line[:Line.find(u'#language')]).strip())
- else:
- NewLines.append((Line[:Line.find(u'#language')]).strip())
- NewLines.append((Line[Line.find(u'#language'):Line.find(u'"')]).strip())
- NewLines.append((Line[Line.find(u'"'):]).strip())
- else:
- EdkLogger.Error("Unicode File Parser", ToolError.FORMAT_INVALID, ExtraData=File.Path)
- elif Line.startswith(u'#language'):
- if len(Line.split()) == 2:
- if IsIncludeFile:
- if StrName not in NewLines:
- NewLines.append(StrName)
- else:
- NewLines.append(StrName)
- NewLines.append(Line)
- elif len(Line.split()) > 2 and Line.find(u'"') > 0:
- if IsIncludeFile:
- if StrName not in NewLines:
- NewLines.append(StrName)
- else:
- NewLines.append(StrName)
- NewLines.append((Line[:Line.find(u'"')]).strip())
- NewLines.append((Line[Line.find(u'"'):]).strip())
- else:
- EdkLogger.Error("Unicode File Parser", ToolError.FORMAT_INVALID, ExtraData=File.Path)
- elif Line.startswith(u'"'):
- if u'#string' in Line or u'#language' in Line:
- EdkLogger.Error("Unicode File Parser", ToolError.FORMAT_INVALID, ExtraData=File.Path)
- NewLines.append(Line)
- else:
- print(Line)
- EdkLogger.Error("Unicode File Parser", ToolError.FORMAT_INVALID, ExtraData=File.Path)
-
- if StrName and not StrName.split()[1].startswith(u'STR_'):
- EdkLogger.Error("Unicode File Parser", ToolError.FORMAT_INVALID, \
- Message=ST.ERR_UNIPARSE_STRNAME_FORMAT_ERROR % StrName.split()[1], \
- ExtraData=File.Path)
-
- if StrName and not NewLines:
- EdkLogger.Error("Unicode File Parser", ToolError.FORMAT_INVALID, \
- Message=ST.ERR_UNI_MISS_LANGENTRY % StrName, \
- ExtraData=File.Path)
-
- #
- # Check Abstract, Description, BinaryAbstract and BinaryDescription order,
- # should be Abstract, Description, BinaryAbstract, BinaryDescription
- AbstractPosition = -1
- DescriptionPosition = -1
- BinaryAbstractPosition = -1
- BinaryDescriptionPosition = -1
- for StrName in ExistStrNameList:
- if DT.TAB_HEADER_ABSTRACT.upper() in StrName:
- if 'BINARY' in StrName:
- BinaryAbstractPosition = ExistStrNameList.index(StrName)
- else:
- AbstractPosition = ExistStrNameList.index(StrName)
- if DT.TAB_HEADER_DESCRIPTION.upper() in StrName:
- if 'BINARY' in StrName:
- BinaryDescriptionPosition = ExistStrNameList.index(StrName)
- else:
- DescriptionPosition = ExistStrNameList.index(StrName)
-
- OrderList = sorted([AbstractPosition, DescriptionPosition])
- BinaryOrderList = sorted([BinaryAbstractPosition, BinaryDescriptionPosition])
- Min = OrderList[0]
- Max = OrderList[1]
- BinaryMin = BinaryOrderList[0]
- BinaryMax = BinaryOrderList[1]
- if BinaryDescriptionPosition > -1:
- if not(BinaryDescriptionPosition == BinaryMax and BinaryAbstractPosition == BinaryMin and \
- BinaryMax > Max):
- EdkLogger.Error("Unicode File Parser", ToolError.FORMAT_INVALID, \
- Message=ST.ERR_UNIPARSE_ENTRY_ORDER_WRONG, \
- ExtraData=File.Path)
- elif BinaryAbstractPosition > -1:
- if not(BinaryAbstractPosition > Max):
- EdkLogger.Error("Unicode File Parser", ToolError.FORMAT_INVALID, \
- Message=ST.ERR_UNIPARSE_ENTRY_ORDER_WRONG, \
- ExtraData=File.Path)
-
- if DescriptionPosition > -1:
- if not(DescriptionPosition == Max and AbstractPosition == Min and \
- DescriptionPosition > AbstractPosition):
- EdkLogger.Error("Unicode File Parser", ToolError.FORMAT_INVALID, \
- Message=ST.ERR_UNIPARSE_ENTRY_ORDER_WRONG, \
- ExtraData=File.Path)
-
- if not self.UniFileHeader:
- EdkLogger.Error("Unicode File Parser", ToolError.FORMAT_INVALID,
- Message = ST.ERR_NO_SOURCE_HEADER,
- ExtraData=File.Path)
-
- return NewLines
-
- #
- # Load a .uni file
- #
- def LoadUniFile(self, File = None):
- if File is None:
- EdkLogger.Error("Unicode File Parser",
- ToolError.PARSER_ERROR,
- Message='No unicode file is given',
- ExtraData=File.Path)
-
- self.File = File
-
- #
- # Process special char in file
- #
- Lines = self.PreProcess(File)
-
- #
- # Get Unicode Information
- #
- for IndexI in range(len(Lines)):
- Line = Lines[IndexI]
- if (IndexI + 1) < len(Lines):
- SecondLine = Lines[IndexI + 1]
- if (IndexI + 2) < len(Lines):
- ThirdLine = Lines[IndexI + 2]
-
- #
- # Get Language def information
- #
- if Line.find(u'#langdef ') >= 0:
- self.GetLangDef(File, Line + u' ' + SecondLine)
- continue
-
- Name = ''
- Language = ''
- Value = ''
- CombineToken = False
- #
- # Get string def information format as below
- #
- # #string MY_STRING_1
- # #language eng
- # "My first English string line 1"
- # "My first English string line 2"
- # #string MY_STRING_1
- # #language spa
- # "Mi segunda secuencia 1"
- # "Mi segunda secuencia 2"
- #
- if Line.find(u'#string ') >= 0 and Line.find(u'#language ') < 0 and \
- SecondLine.find(u'#string ') < 0 and SecondLine.find(u'#language ') >= 0 and \
- ThirdLine.find(u'#string ') < 0 and ThirdLine.find(u'#language ') < 0:
- if Line.find('"') > 0 or SecondLine.find('"') > 0:
- EdkLogger.Error("Unicode File Parser", ToolError.FORMAT_INVALID,
- Message=ST.ERR_UNIPARSE_DBLQUOTE_UNMATCHED,
- ExtraData=File.Path)
-
- Name = Line[Line.find(u'#string ') + len(u'#string ') : ].strip(' ')
- Language = SecondLine[SecondLine.find(u'#language ') + len(u'#language ') : ].strip(' ')
- for IndexJ in range(IndexI + 2, len(Lines)):
- if Lines[IndexJ].find(u'#string ') < 0 and Lines[IndexJ].find(u'#language ') < 0 and \
- Lines[IndexJ].strip().startswith(u'"') and Lines[IndexJ].strip().endswith(u'"'):
- if Lines[IndexJ][-2] == ' ':
- CombineToken = True
- if CombineToken:
- if Lines[IndexJ].strip()[1:-1].strip():
- Value = Value + Lines[IndexJ].strip()[1:-1].rstrip() + ' '
- else:
- Value = Value + Lines[IndexJ].strip()[1:-1]
- CombineToken = False
- else:
- Value = Value + Lines[IndexJ].strip()[1:-1] + '\r\n'
- else:
- IndexI = IndexJ
- break
- if Value.endswith('\r\n'):
- Value = Value[: Value.rfind('\r\n')]
- Language = GetLanguageCode(Language, self.IsCompatibleMode, self.File)
- self.AddStringToList(Name, Language, Value)
- continue
-
- #
- # Load multiple .uni files
- #
- def LoadUniFiles(self, FileList):
- if len(FileList) > 0:
- for File in FileList:
- FilePath = File.Path.strip()
- if FilePath.endswith('.uni') or FilePath.endswith('.UNI') or FilePath.endswith('.Uni'):
- self.LoadUniFile(File)
-
- #
- # Add a string to list
- #
- def AddStringToList(self, Name, Language, Value, Token = 0, Referenced = False, UseOtherLangDef = '', Index = -1):
- for LangNameItem in self.LanguageDef:
- if Language == LangNameItem[0]:
- break
-
- if Language not in self.OrderedStringList:
- self.OrderedStringList[Language] = []
- self.OrderedStringDict[Language] = {}
-
- IsAdded = True
- if Name in self.OrderedStringDict[Language]:
- IsAdded = False
- if Value is not None:
- ItemIndexInList = self.OrderedStringDict[Language][Name]
- Item = self.OrderedStringList[Language][ItemIndexInList]
- Item.UpdateValue(Value)
- Item.UseOtherLangDef = ''
-
- if IsAdded:
- Token = len(self.OrderedStringList[Language])
- if Index == -1:
- self.OrderedStringList[Language].append(StringDefClassObject(Name,
- Value,
- Referenced,
- Token,
- UseOtherLangDef))
- self.OrderedStringDict[Language][Name] = Token
- for LangName in self.LanguageDef:
- #
- # New STRING token will be added into all language string lists.
- # so that the unique STRING identifier is reserved for all languages in the package list.
- #
- if LangName[0] != Language:
- if UseOtherLangDef != '':
- OtherLangDef = UseOtherLangDef
- else:
- OtherLangDef = Language
- self.OrderedStringList[LangName[0]].append(StringDefClassObject(Name,
- '',
- Referenced,
- Token,
- OtherLangDef))
- self.OrderedStringDict[LangName[0]][Name] = len(self.OrderedStringList[LangName[0]]) - 1
- else:
- self.OrderedStringList[Language].insert(Index, StringDefClassObject(Name,
- Value,
- Referenced,
- Token,
- UseOtherLangDef))
- self.OrderedStringDict[Language][Name] = Index
-
- #
- # Set the string as referenced
- #
- def SetStringReferenced(self, Name):
- #
- # String stoken are added in the same order in all language string lists.
- # So, only update the status of string stoken in first language string list.
- #
- Lang = self.LanguageDef[0][0]
- if Name in self.OrderedStringDict[Lang]:
- ItemIndexInList = self.OrderedStringDict[Lang][Name]
- Item = self.OrderedStringList[Lang][ItemIndexInList]
- Item.Referenced = True
-
- #
- # Search the string in language definition by Name
- #
- def FindStringValue(self, Name, Lang):
- if Name in self.OrderedStringDict[Lang]:
- ItemIndexInList = self.OrderedStringDict[Lang][Name]
- return self.OrderedStringList[Lang][ItemIndexInList]
-
- return None
-
- #
- # Search the string in language definition by Token
- #
- def FindByToken(self, Token, Lang):
- for Item in self.OrderedStringList[Lang]:
- if Item.Token == Token:
- return Item
-
- return None
-
- #
- # Re-order strings and re-generate tokens
- #
- def ReToken(self):
- if len(self.LanguageDef) == 0:
- return None
- #
- # Retoken all language strings according to the status of string stoken in the first language string.
- #
- FirstLangName = self.LanguageDef[0][0]
-
- # Convert the OrderedStringList to be OrderedStringListByToken in order to faciliate future search by token
- for LangNameItem in self.LanguageDef:
- self.OrderedStringListByToken[LangNameItem[0]] = {}
-
- #
- # Use small token for all referred string stoken.
- #
- RefToken = 0
- for Index in range (0, len (self.OrderedStringList[FirstLangName])):
- FirstLangItem = self.OrderedStringList[FirstLangName][Index]
- if FirstLangItem.Referenced == True:
- for LangNameItem in self.LanguageDef:
- LangName = LangNameItem[0]
- OtherLangItem = self.OrderedStringList[LangName][Index]
- OtherLangItem.Referenced = True
- OtherLangItem.Token = RefToken
- self.OrderedStringListByToken[LangName][OtherLangItem.Token] = OtherLangItem
- RefToken = RefToken + 1
-
- #
- # Use big token for all unreferred string stoken.
- #
- UnRefToken = 0
- for Index in range (0, len (self.OrderedStringList[FirstLangName])):
- FirstLangItem = self.OrderedStringList[FirstLangName][Index]
- if FirstLangItem.Referenced == False:
- for LangNameItem in self.LanguageDef:
- LangName = LangNameItem[0]
- OtherLangItem = self.OrderedStringList[LangName][Index]
- OtherLangItem.Token = RefToken + UnRefToken
- self.OrderedStringListByToken[LangName][OtherLangItem.Token] = OtherLangItem
- UnRefToken = UnRefToken + 1
-
- #
- # Show the instance itself
- #
- def ShowMe(self):
- print(self.LanguageDef)
- #print self.OrderedStringList
- for Item in self.OrderedStringList:
- print(Item)
- for Member in self.OrderedStringList[Item]:
- print(str(Member))
-
- #
- # Read content from '!include' UNI file
- #
- def ReadIncludeUNIfile(self, FilaPath):
- if self.File:
- pass
-
- if not os.path.exists(FilaPath) or not os.path.isfile(FilaPath):
- EdkLogger.Error("Unicode File Parser",
- ToolError.FILE_NOT_FOUND,
- ExtraData=FilaPath)
- try:
- FileIn = codecs.open(FilaPath, mode='rb', encoding='utf_8').readlines()
- except UnicodeError as Xstr:
- FileIn = codecs.open(FilaPath, mode='rb', encoding='utf_16').readlines()
- except UnicodeError:
- FileIn = codecs.open(FilaPath, mode='rb', encoding='utf_16_le').readlines()
- except:
- EdkLogger.Error("Unicode File Parser", ToolError.FILE_OPEN_FAILURE, ExtraData=FilaPath)
- return FileIn
-
+## @file +# Collect all defined strings in multiple uni files. +# +# Copyright (c) 2014 - 2019, Intel Corporation. All rights reserved.<BR> +# +# SPDX-License-Identifier: BSD-2-Clause-Patent +# +""" +Collect all defined strings in multiple uni files +""" +from __future__ import print_function + +## +# Import Modules +# +import os, codecs, re +import shlex +from Logger import ToolError +from Logger import Log as EdkLogger +from Logger import StringTable as ST +from Library.StringUtils import GetLineNo +from Library.Misc import PathClass +from Library.Misc import GetCharIndexOutStr +from Library import DataType as DT +from Library.ParserValidate import CheckUTF16FileHeader + +## +# Static definitions +# +UNICODE_WIDE_CHAR = u'\\wide' +UNICODE_NARROW_CHAR = u'\\narrow' +UNICODE_NON_BREAKING_CHAR = u'\\nbr' +UNICODE_UNICODE_CR = '\r' +UNICODE_UNICODE_LF = '\n' + +NARROW_CHAR = u'\uFFF0' +WIDE_CHAR = u'\uFFF1' +NON_BREAKING_CHAR = u'\uFFF2' +CR = u'\u000D' +LF = u'\u000A' +NULL = u'\u0000' +TAB = u'\t' +BACK_SPLASH = u'\\' + +gLANG_CONV_TABLE = {'eng':'en', 'fra':'fr', \ + 'aar':'aa', 'abk':'ab', 'ave':'ae', 'afr':'af', 'aka':'ak', 'amh':'am', \ + 'arg':'an', 'ara':'ar', 'asm':'as', 'ava':'av', 'aym':'ay', 'aze':'az', \ + 'bak':'ba', 'bel':'be', 'bul':'bg', 'bih':'bh', 'bis':'bi', 'bam':'bm', \ + 'ben':'bn', 'bod':'bo', 'bre':'br', 'bos':'bs', 'cat':'ca', 'che':'ce', \ + 'cha':'ch', 'cos':'co', 'cre':'cr', 'ces':'cs', 'chu':'cu', 'chv':'cv', \ + 'cym':'cy', 'dan':'da', 'deu':'de', 'div':'dv', 'dzo':'dz', 'ewe':'ee', \ + 'ell':'el', 'epo':'eo', 'spa':'es', 'est':'et', 'eus':'eu', 'fas':'fa', \ + 'ful':'ff', 'fin':'fi', 'fij':'fj', 'fao':'fo', 'fry':'fy', 'gle':'ga', \ + 'gla':'gd', 'glg':'gl', 'grn':'gn', 'guj':'gu', 'glv':'gv', 'hau':'ha', \ + 'heb':'he', 'hin':'hi', 'hmo':'ho', 'hrv':'hr', 'hat':'ht', 'hun':'hu', \ + 'hye':'hy', 'her':'hz', 'ina':'ia', 'ind':'id', 'ile':'ie', 'ibo':'ig', \ + 'iii':'ii', 'ipk':'ik', 'ido':'io', 'isl':'is', 'ita':'it', 'iku':'iu', \ + 'jpn':'ja', 'jav':'jv', 'kat':'ka', 'kon':'kg', 'kik':'ki', 'kua':'kj', \ + 'kaz':'kk', 'kal':'kl', 'khm':'km', 'kan':'kn', 'kor':'ko', 'kau':'kr', \ + 'kas':'ks', 'kur':'ku', 'kom':'kv', 'cor':'kw', 'kir':'ky', 'lat':'la', \ + 'ltz':'lb', 'lug':'lg', 'lim':'li', 'lin':'ln', 'lao':'lo', 'lit':'lt', \ + 'lub':'lu', 'lav':'lv', 'mlg':'mg', 'mah':'mh', 'mri':'mi', 'mkd':'mk', \ + 'mal':'ml', 'mon':'mn', 'mar':'mr', 'msa':'ms', 'mlt':'mt', 'mya':'my', \ + 'nau':'na', 'nob':'nb', 'nde':'nd', 'nep':'ne', 'ndo':'ng', 'nld':'nl', \ + 'nno':'nn', 'nor':'no', 'nbl':'nr', 'nav':'nv', 'nya':'ny', 'oci':'oc', \ + 'oji':'oj', 'orm':'om', 'ori':'or', 'oss':'os', 'pan':'pa', 'pli':'pi', \ + 'pol':'pl', 'pus':'ps', 'por':'pt', 'que':'qu', 'roh':'rm', 'run':'rn', \ + 'ron':'ro', 'rus':'ru', 'kin':'rw', 'san':'sa', 'srd':'sc', 'snd':'sd', \ + 'sme':'se', 'sag':'sg', 'sin':'si', 'slk':'sk', 'slv':'sl', 'smo':'sm', \ + 'sna':'sn', 'som':'so', 'sqi':'sq', 'srp':'sr', 'ssw':'ss', 'sot':'st', \ + 'sun':'su', 'swe':'sv', 'swa':'sw', 'tam':'ta', 'tel':'te', 'tgk':'tg', \ + 'tha':'th', 'tir':'ti', 'tuk':'tk', 'tgl':'tl', 'tsn':'tn', 'ton':'to', \ + 'tur':'tr', 'tso':'ts', 'tat':'tt', 'twi':'tw', 'tah':'ty', 'uig':'ug', \ + 'ukr':'uk', 'urd':'ur', 'uzb':'uz', 'ven':'ve', 'vie':'vi', 'vol':'vo', \ + 'wln':'wa', 'wol':'wo', 'xho':'xh', 'yid':'yi', 'yor':'yo', 'zha':'za', \ + 'zho':'zh', 'zul':'zu'} + +## Convert a python unicode string to a normal string +# +# Convert a python unicode string to a normal string +# UniToStr(u'I am a string') is 'I am a string' +# +# @param Uni: The python unicode string +# +# @retval: The formatted normal string +# +def UniToStr(Uni): + return repr(Uni)[2:-1] + +## Convert a unicode string to a Hex list +# +# Convert a unicode string to a Hex list +# UniToHexList('ABC') is ['0x41', '0x00', '0x42', '0x00', '0x43', '0x00'] +# +# @param Uni: The python unicode string +# +# @retval List: The formatted hex list +# +def UniToHexList(Uni): + List = [] + for Item in Uni: + Temp = '%04X' % ord(Item) + List.append('0x' + Temp[2:4]) + List.append('0x' + Temp[0:2]) + return List + +## Convert special unicode characters +# +# Convert special characters to (c), (r) and (tm). +# +# @param Uni: The python unicode string +# +# @retval NewUni: The converted unicode string +# +def ConvertSpecialUnicodes(Uni): + OldUni = NewUni = Uni + NewUni = NewUni.replace(u'\u00A9', '(c)') + NewUni = NewUni.replace(u'\u00AE', '(r)') + NewUni = NewUni.replace(u'\u2122', '(tm)') + if OldUni == NewUni: + NewUni = OldUni + return NewUni + +## GetLanguageCode1766 +# +# Check the language code read from .UNI file and convert RFC 4646 codes to RFC 1766 codes +# RFC 1766 language codes supported in compatibility mode +# RFC 4646 language codes supported in native mode +# +# @param LangName: Language codes read from .UNI file +# +# @retval LangName: Valid language code in RFC 1766 format or None +# +def GetLanguageCode1766(LangName, File=None): + return LangName + + length = len(LangName) + if length == 2: + if LangName.isalpha(): + for Key in gLANG_CONV_TABLE.keys(): + if gLANG_CONV_TABLE.get(Key) == LangName.lower(): + return Key + elif length == 3: + if LangName.isalpha() and gLANG_CONV_TABLE.get(LangName.lower()): + return LangName + else: + EdkLogger.Error("Unicode File Parser", + ToolError.FORMAT_INVALID, + "Invalid RFC 1766 language code : %s" % LangName, + File) + elif length == 5: + if LangName[0:2].isalpha() and LangName[2] == '-': + for Key in gLANG_CONV_TABLE.keys(): + if gLANG_CONV_TABLE.get(Key) == LangName[0:2].lower(): + return Key + elif length >= 6: + if LangName[0:2].isalpha() and LangName[2] == '-': + for Key in gLANG_CONV_TABLE.keys(): + if gLANG_CONV_TABLE.get(Key) == LangName[0:2].lower(): + return Key + if LangName[0:3].isalpha() and gLANG_CONV_TABLE.get(LangName.lower()) is None and LangName[3] == '-': + for Key in gLANG_CONV_TABLE.keys(): + if Key == LangName[0:3].lower(): + return Key + + EdkLogger.Error("Unicode File Parser", + ToolError.FORMAT_INVALID, + "Invalid RFC 4646 language code : %s" % LangName, + File) + +## GetLanguageCode +# +# Check the language code read from .UNI file and convert RFC 1766 codes to RFC 4646 codes if appropriate +# RFC 1766 language codes supported in compatibility mode +# RFC 4646 language codes supported in native mode +# +# @param LangName: Language codes read from .UNI file +# +# @retval LangName: Valid lanugage code in RFC 4646 format or None +# +def GetLanguageCode(LangName, IsCompatibleMode, File): + length = len(LangName) + if IsCompatibleMode: + if length == 3 and LangName.isalpha(): + TempLangName = gLANG_CONV_TABLE.get(LangName.lower()) + if TempLangName is not None: + return TempLangName + return LangName + else: + EdkLogger.Error("Unicode File Parser", + ToolError.FORMAT_INVALID, + "Invalid RFC 1766 language code : %s" % LangName, + File) + if (LangName[0] == 'X' or LangName[0] == 'x') and LangName[1] == '-': + return LangName + if length == 2: + if LangName.isalpha(): + return LangName + elif length == 3: + if LangName.isalpha() and gLANG_CONV_TABLE.get(LangName.lower()) is None: + return LangName + elif length == 5: + if LangName[0:2].isalpha() and LangName[2] == '-': + return LangName + elif length >= 6: + if LangName[0:2].isalpha() and LangName[2] == '-': + return LangName + if LangName[0:3].isalpha() and gLANG_CONV_TABLE.get(LangName.lower()) is None and LangName[3] == '-': + return LangName + + EdkLogger.Error("Unicode File Parser", + ToolError.FORMAT_INVALID, + "Invalid RFC 4646 language code : %s" % LangName, + File) + +## FormatUniEntry +# +# Formatted the entry in Uni file. +# +# @param StrTokenName StrTokenName. +# @param TokenValueList A list need to be processed. +# @param ContainerFile ContainerFile. +# +# @return formatted entry +def FormatUniEntry(StrTokenName, TokenValueList, ContainerFile): + SubContent = '' + PreFormatLength = 40 + if len(StrTokenName) > PreFormatLength: + PreFormatLength = len(StrTokenName) + 1 + for (Lang, Value) in TokenValueList: + if not Value or Lang == DT.TAB_LANGUAGE_EN_X: + continue + if Lang == '': + Lang = DT.TAB_LANGUAGE_EN_US + if Lang == 'eng': + Lang = DT.TAB_LANGUAGE_EN_US + elif len(Lang.split('-')[0]) == 3: + Lang = GetLanguageCode(Lang.split('-')[0], True, ContainerFile) + else: + Lang = GetLanguageCode(Lang, False, ContainerFile) + ValueList = Value.split('\n') + SubValueContent = '' + for SubValue in ValueList: + if SubValue.strip(): + SubValueContent += \ + ' ' * (PreFormatLength + len('#language en-US ')) + '\"%s\\n\"' % SubValue.strip() + '\r\n' + SubValueContent = SubValueContent[(PreFormatLength + len('#language en-US ')):SubValueContent.rfind('\\n')] \ + + '\"' + '\r\n' + SubContent += ' '*PreFormatLength + '#language %-5s ' % Lang + SubValueContent + if SubContent: + SubContent = StrTokenName + ' '*(PreFormatLength - len(StrTokenName)) + SubContent[PreFormatLength:] + return SubContent + + +## StringDefClassObject +# +# A structure for language definition +# +class StringDefClassObject(object): + def __init__(self, Name = None, Value = None, Referenced = False, Token = None, UseOtherLangDef = ''): + self.StringName = '' + self.StringNameByteList = [] + self.StringValue = '' + self.StringValueByteList = '' + self.Token = 0 + self.Referenced = Referenced + self.UseOtherLangDef = UseOtherLangDef + self.Length = 0 + + if Name is not None: + self.StringName = Name + self.StringNameByteList = UniToHexList(Name) + if Value is not None: + self.StringValue = Value + self.StringValueByteList = UniToHexList(self.StringValue) + self.Length = len(self.StringValueByteList) + if Token is not None: + self.Token = Token + + def __str__(self): + return repr(self.StringName) + ' ' + \ + repr(self.Token) + ' ' + \ + repr(self.Referenced) + ' ' + \ + repr(self.StringValue) + ' ' + \ + repr(self.UseOtherLangDef) + + def UpdateValue(self, Value = None): + if Value is not None: + if self.StringValue: + self.StringValue = self.StringValue + '\r\n' + Value + else: + self.StringValue = Value + self.StringValueByteList = UniToHexList(self.StringValue) + self.Length = len(self.StringValueByteList) + +## UniFileClassObject +# +# A structure for .uni file definition +# +class UniFileClassObject(object): + def __init__(self, FileList = None, IsCompatibleMode = False, IncludePathList = None): + self.FileList = FileList + self.File = None + self.IncFileList = FileList + self.UniFileHeader = '' + self.Token = 2 + self.LanguageDef = [] #[ [u'LanguageIdentifier', u'PrintableName'], ... ] + self.OrderedStringList = {} #{ u'LanguageIdentifier' : [StringDefClassObject] } + self.OrderedStringDict = {} #{ u'LanguageIdentifier' : {StringName:(IndexInList)} } + self.OrderedStringListByToken = {} #{ u'LanguageIdentifier' : {Token: StringDefClassObject} } + self.IsCompatibleMode = IsCompatibleMode + if not IncludePathList: + self.IncludePathList = [] + else: + self.IncludePathList = IncludePathList + if len(self.FileList) > 0: + self.LoadUniFiles(FileList) + + # + # Get Language definition + # + def GetLangDef(self, File, Line): + Lang = shlex.split(Line.split(u"//")[0]) + if len(Lang) != 3: + try: + FileIn = codecs.open(File.Path, mode='rb', encoding='utf_8').readlines() + except UnicodeError as Xstr: + FileIn = codecs.open(File.Path, mode='rb', encoding='utf_16').readlines() + except UnicodeError as Xstr: + FileIn = codecs.open(File.Path, mode='rb', encoding='utf_16_le').readlines() + except: + EdkLogger.Error("Unicode File Parser", + ToolError.FILE_OPEN_FAILURE, + "File read failure: %s" % str(Xstr), + ExtraData=File) + LineNo = GetLineNo(FileIn, Line, False) + EdkLogger.Error("Unicode File Parser", + ToolError.PARSER_ERROR, + "Wrong language definition", + ExtraData="""%s\n\t*Correct format is like '#langdef en-US "English"'""" % Line, + File = File, Line = LineNo) + else: + LangName = GetLanguageCode(Lang[1], self.IsCompatibleMode, self.File) + LangPrintName = Lang[2] + + IsLangInDef = False + for Item in self.LanguageDef: + if Item[0] == LangName: + IsLangInDef = True + break + + if not IsLangInDef: + self.LanguageDef.append([LangName, LangPrintName]) + + # + # Add language string + # + self.AddStringToList(u'$LANGUAGE_NAME', LangName, LangName, 0, True, Index=0) + self.AddStringToList(u'$PRINTABLE_LANGUAGE_NAME', LangName, LangPrintName, 1, True, Index=1) + + if not IsLangInDef: + # + # The found STRING tokens will be added into new language string list + # so that the unique STRING identifier is reserved for all languages in the package list. + # + FirstLangName = self.LanguageDef[0][0] + if LangName != FirstLangName: + for Index in range (2, len (self.OrderedStringList[FirstLangName])): + Item = self.OrderedStringList[FirstLangName][Index] + if Item.UseOtherLangDef != '': + OtherLang = Item.UseOtherLangDef + else: + OtherLang = FirstLangName + self.OrderedStringList[LangName].append (StringDefClassObject(Item.StringName, + '', + Item.Referenced, + Item.Token, + OtherLang)) + self.OrderedStringDict[LangName][Item.StringName] = len(self.OrderedStringList[LangName]) - 1 + return True + + # + # Get String name and value + # + def GetStringObject(self, Item): + Language = '' + Value = '' + + Name = Item.split()[1] + # Check the string name is the upper character + if Name != '': + MatchString = re.match('[A-Z0-9_]+', Name, re.UNICODE) + if MatchString is None or MatchString.end(0) != len(Name): + EdkLogger.Error("Unicode File Parser", + ToolError.FORMAT_INVALID, + 'The string token name %s in UNI file %s must be upper case character.' %(Name, self.File)) + LanguageList = Item.split(u'#language ') + for IndexI in range(len(LanguageList)): + if IndexI == 0: + continue + else: + Language = LanguageList[IndexI].split()[0] + #.replace(u'\r\n', u'') + Value = \ + LanguageList[IndexI][LanguageList[IndexI].find(u'\"') + len(u'\"') : LanguageList[IndexI].rfind(u'\"')] + Language = GetLanguageCode(Language, self.IsCompatibleMode, self.File) + self.AddStringToList(Name, Language, Value) + + # + # Get include file list and load them + # + def GetIncludeFile(self, Item, Dir = None): + if Dir: + pass + FileName = Item[Item.find(u'!include ') + len(u'!include ') :Item.find(u' ', len(u'!include '))][1:-1] + self.LoadUniFile(FileName) + + # + # Pre-process before parse .uni file + # + def PreProcess(self, File, IsIncludeFile=False): + if not os.path.exists(File.Path) or not os.path.isfile(File.Path): + EdkLogger.Error("Unicode File Parser", + ToolError.FILE_NOT_FOUND, + ExtraData=File.Path) + + # + # Check file header of the Uni file + # +# if not CheckUTF16FileHeader(File.Path): +# EdkLogger.Error("Unicode File Parser", ToolError.FORMAT_INVALID, +# ExtraData='The file %s is either invalid UTF-16LE or it is missing the BOM.' % File.Path) + + try: + FileIn = codecs.open(File.Path, mode='rb', encoding='utf_8').readlines() + except UnicodeError as Xstr: + FileIn = codecs.open(File.Path, mode='rb', encoding='utf_16').readlines() + except UnicodeError: + FileIn = codecs.open(File.Path, mode='rb', encoding='utf_16_le').readlines() + except: + EdkLogger.Error("Unicode File Parser", ToolError.FILE_OPEN_FAILURE, ExtraData=File.Path) + + + # + # get the file header + # + Lines = [] + HeaderStart = False + HeaderEnd = False + if not self.UniFileHeader: + FirstGenHeader = True + else: + FirstGenHeader = False + for Line in FileIn: + Line = Line.strip() + if Line == u'': + continue + if Line.startswith(DT.TAB_COMMENT_EDK1_SPLIT) and (Line.find(DT.TAB_HEADER_COMMENT) > -1) \ + and not HeaderEnd and not HeaderStart: + HeaderStart = True + if not Line.startswith(DT.TAB_COMMENT_EDK1_SPLIT) and HeaderStart and not HeaderEnd: + HeaderEnd = True + if Line.startswith(DT.TAB_COMMENT_EDK1_SPLIT) and HeaderStart and not HeaderEnd and FirstGenHeader: + self.UniFileHeader += Line + '\r\n' + continue + + # + # Use unique identifier + # + FindFlag = -1 + LineCount = 0 + MultiLineFeedExits = False + # + # 0: initial value + # 1: single String entry exist + # 2: line feed exist under the some single String entry + # + StringEntryExistsFlag = 0 + for Line in FileIn: + Line = FileIn[LineCount] + LineCount += 1 + Line = Line.strip() + # + # Ignore comment line and empty line + # + if Line == u'' or Line.startswith(u'//'): + # + # Change the single line String entry flag status + # + if StringEntryExistsFlag == 1: + StringEntryExistsFlag = 2 + # + # If the '#string' line and the '#language' line are not in the same line, + # there should be only one line feed character between them + # + if MultiLineFeedExits: + EdkLogger.Error("Unicode File Parser", ToolError.FORMAT_INVALID, ExtraData=File.Path) + continue + + MultiLineFeedExits = False + # + # Process comment embedded in string define lines + # + FindFlag = Line.find(u'//') + if FindFlag != -1 and Line.find(u'//') < Line.find(u'"'): + Line = Line.replace(Line[FindFlag:], u' ') + if FileIn[LineCount].strip().startswith('#language'): + Line = Line + FileIn[LineCount] + FileIn[LineCount-1] = Line + FileIn[LineCount] = '\r\n' + LineCount -= 1 + for Index in range (LineCount + 1, len (FileIn) - 1): + if (Index == len(FileIn) -1): + FileIn[Index] = '\r\n' + else: + FileIn[Index] = FileIn[Index + 1] + continue + CommIndex = GetCharIndexOutStr(u'/', Line) + if CommIndex > -1: + if (len(Line) - 1) > CommIndex: + if Line[CommIndex+1] == u'/': + Line = Line[:CommIndex].strip() + else: + EdkLogger.Error("Unicode File Parser", ToolError.FORMAT_INVALID, ExtraData=File.Path) + else: + EdkLogger.Error("Unicode File Parser", ToolError.FORMAT_INVALID, ExtraData=File.Path) + + Line = Line.replace(UNICODE_WIDE_CHAR, WIDE_CHAR) + Line = Line.replace(UNICODE_NARROW_CHAR, NARROW_CHAR) + Line = Line.replace(UNICODE_NON_BREAKING_CHAR, NON_BREAKING_CHAR) + + Line = Line.replace(u'\\\\', u'\u0006') + Line = Line.replace(u'\\r\\n', CR + LF) + Line = Line.replace(u'\\n', CR + LF) + Line = Line.replace(u'\\r', CR) + Line = Line.replace(u'\\t', u'\t') + Line = Line.replace(u'''\"''', u'''"''') + Line = Line.replace(u'\t', u' ') + Line = Line.replace(u'\u0006', u'\\') + + # + # Check if single line has correct '"' + # + if Line.startswith(u'#string') and Line.find(u'#language') > -1 and Line.find('"') > Line.find(u'#language'): + if not Line.endswith('"'): + EdkLogger.Error("Unicode File Parser", ToolError.FORMAT_INVALID, + ExtraData='''The line %s misses '"' at the end of it in file %s''' + % (LineCount, File.Path)) + + # + # Between Name entry and Language entry can not contain line feed + # + if Line.startswith(u'#string') and Line.find(u'#language') == -1: + MultiLineFeedExits = True + + if Line.startswith(u'#string') and Line.find(u'#language') > 0 and Line.find(u'"') < 0: + MultiLineFeedExits = True + + # + # Between Language entry and String entry can not contain line feed + # + if Line.startswith(u'#language') and len(Line.split()) == 2: + MultiLineFeedExits = True + + # + # Check the situation that there only has one '"' for the language entry + # + if Line.startswith(u'#string') and Line.find(u'#language') > 0 and Line.count(u'"') == 1: + EdkLogger.Error("Unicode File Parser", ToolError.FORMAT_INVALID, + ExtraData='''The line %s misses '"' at the end of it in file %s''' + % (LineCount, File.Path)) + + # + # Check the situation that there has more than 2 '"' for the language entry + # + if Line.startswith(u'#string') and Line.find(u'#language') > 0 and Line.replace(u'\\"', '').count(u'"') > 2: + EdkLogger.Error("Unicode File Parser", ToolError.FORMAT_INVALID, + ExtraData='''The line %s has more than 2 '"' for language entry in file %s''' + % (LineCount, File.Path)) + + # + # Between two String entry, can not contain line feed + # + if Line.startswith(u'"'): + if StringEntryExistsFlag == 2: + EdkLogger.Error("Unicode File Parser", ToolError.FORMAT_INVALID, + Message=ST.ERR_UNIPARSE_LINEFEED_UP_EXIST % Line, ExtraData=File.Path) + + StringEntryExistsFlag = 1 + if not Line.endswith('"'): + EdkLogger.Error("Unicode File Parser", ToolError.FORMAT_INVALID, + ExtraData='''The line %s misses '"' at the end of it in file %s''' + % (LineCount, File.Path)) + + # + # Check the situation that there has more than 2 '"' for the language entry + # + if Line.strip() and Line.replace(u'\\"', '').count(u'"') > 2: + EdkLogger.Error("Unicode File Parser", ToolError.FORMAT_INVALID, + ExtraData='''The line %s has more than 2 '"' for language entry in file %s''' + % (LineCount, File.Path)) + + elif Line.startswith(u'#language'): + if StringEntryExistsFlag == 2: + EdkLogger.Error("Unicode File Parser", ToolError.FORMAT_INVALID, + Message=ST.ERR_UNI_MISS_STRING_ENTRY % Line, ExtraData=File.Path) + StringEntryExistsFlag = 0 + else: + StringEntryExistsFlag = 0 + + Lines.append(Line) + + # + # Convert string def format as below + # + # #string MY_STRING_1 + # #language eng + # "My first English string line 1" + # "My first English string line 2" + # #string MY_STRING_1 + # #language spa + # "Mi segunda secuencia 1" + # "Mi segunda secuencia 2" + # + + if not IsIncludeFile and not Lines: + EdkLogger.Error("Unicode File Parser", ToolError.FORMAT_INVALID, \ + Message=ST.ERR_UNIPARSE_NO_SECTION_EXIST, \ + ExtraData=File.Path) + + NewLines = [] + StrName = u'' + ExistStrNameList = [] + for Line in Lines: + if StrName and not StrName.split()[1].startswith(DT.TAB_STR_TOKENCNAME + DT.TAB_UNDERLINE_SPLIT): + EdkLogger.Error("Unicode File Parser", ToolError.FORMAT_INVALID, \ + Message=ST.ERR_UNIPARSE_STRNAME_FORMAT_ERROR % StrName.split()[1], \ + ExtraData=File.Path) + + if StrName and len(StrName.split()[1].split(DT.TAB_UNDERLINE_SPLIT)) == 4: + StringTokenList = StrName.split()[1].split(DT.TAB_UNDERLINE_SPLIT) + if (StringTokenList[3].upper() in [DT.TAB_STR_TOKENPROMPT, DT.TAB_STR_TOKENHELP] and \ + StringTokenList[3] not in [DT.TAB_STR_TOKENPROMPT, DT.TAB_STR_TOKENHELP]) or \ + (StringTokenList[2].upper() == DT.TAB_STR_TOKENERR and StringTokenList[2] != DT.TAB_STR_TOKENERR): + EdkLogger.Error("Unicode File Parser", ToolError.FORMAT_INVALID, \ + Message=ST.ERR_UNIPARSE_STRTOKEN_FORMAT_ERROR % StrName.split()[1], \ + ExtraData=File.Path) + + if Line.count(u'#language') > 1: + EdkLogger.Error("Unicode File Parser", ToolError.FORMAT_INVALID, \ + Message=ST.ERR_UNIPARSE_SEP_LANGENTRY_LINE % Line, \ + ExtraData=File.Path) + + if Line.startswith(u'//'): + continue + elif Line.startswith(u'#langdef'): + if len(Line.split()) == 2: + NewLines.append(Line) + continue + elif len(Line.split()) > 2 and Line.find(u'"') > 0: + NewLines.append(Line[:Line.find(u'"')].strip()) + NewLines.append(Line[Line.find(u'"'):]) + else: + EdkLogger.Error("Unicode File Parser", ToolError.FORMAT_INVALID, ExtraData=File.Path) + elif Line.startswith(u'#string'): + if len(Line.split()) == 2: + StrName = Line + if StrName: + if StrName.split()[1] not in ExistStrNameList: + ExistStrNameList.append(StrName.split()[1].strip()) + elif StrName.split()[1] in [DT.TAB_INF_ABSTRACT, DT.TAB_INF_DESCRIPTION, \ + DT.TAB_INF_BINARY_ABSTRACT, DT.TAB_INF_BINARY_DESCRIPTION, \ + DT.TAB_DEC_PACKAGE_ABSTRACT, DT.TAB_DEC_PACKAGE_DESCRIPTION, \ + DT.TAB_DEC_BINARY_ABSTRACT, DT.TAB_DEC_BINARY_DESCRIPTION]: + EdkLogger.Error("Unicode File Parser", ToolError.FORMAT_INVALID, \ + Message=ST.ERR_UNIPARSE_MULTI_ENTRY_EXIST % StrName.split()[1], \ + ExtraData=File.Path) + continue + elif len(Line.split()) == 4 and Line.find(u'#language') > 0: + if Line[Line.find(u'#language')-1] != ' ' or \ + Line[Line.find(u'#language')+len(u'#language')] != u' ': + EdkLogger.Error("Unicode File Parser", ToolError.FORMAT_INVALID, ExtraData=File.Path) + + if Line.find(u'"') > 0: + EdkLogger.Error("Unicode File Parser", ToolError.FORMAT_INVALID, ExtraData=File.Path) + + StrName = Line.split()[0] + u' ' + Line.split()[1] + if StrName: + if StrName.split()[1] not in ExistStrNameList: + ExistStrNameList.append(StrName.split()[1].strip()) + elif StrName.split()[1] in [DT.TAB_INF_ABSTRACT, DT.TAB_INF_DESCRIPTION, \ + DT.TAB_INF_BINARY_ABSTRACT, DT.TAB_INF_BINARY_DESCRIPTION, \ + DT.TAB_DEC_PACKAGE_ABSTRACT, DT.TAB_DEC_PACKAGE_DESCRIPTION, \ + DT.TAB_DEC_BINARY_ABSTRACT, DT.TAB_DEC_BINARY_DESCRIPTION]: + EdkLogger.Error("Unicode File Parser", ToolError.FORMAT_INVALID, \ + Message=ST.ERR_UNIPARSE_MULTI_ENTRY_EXIST % StrName.split()[1], \ + ExtraData=File.Path) + if IsIncludeFile: + if StrName not in NewLines: + NewLines.append((Line[:Line.find(u'#language')]).strip()) + else: + NewLines.append((Line[:Line.find(u'#language')]).strip()) + NewLines.append((Line[Line.find(u'#language'):]).strip()) + elif len(Line.split()) > 4 and Line.find(u'#language') > 0 and Line.find(u'"') > 0: + if Line[Line.find(u'#language')-1] != u' ' or \ + Line[Line.find(u'#language')+len(u'#language')] != u' ': + EdkLogger.Error("Unicode File Parser", ToolError.FORMAT_INVALID, ExtraData=File.Path) + + if Line[Line.find(u'"')-1] != u' ': + EdkLogger.Error("Unicode File Parser", ToolError.FORMAT_INVALID, ExtraData=File.Path) + + StrName = Line.split()[0] + u' ' + Line.split()[1] + if StrName: + if StrName.split()[1] not in ExistStrNameList: + ExistStrNameList.append(StrName.split()[1].strip()) + elif StrName.split()[1] in [DT.TAB_INF_ABSTRACT, DT.TAB_INF_DESCRIPTION, \ + DT.TAB_INF_BINARY_ABSTRACT, DT.TAB_INF_BINARY_DESCRIPTION, \ + DT.TAB_DEC_PACKAGE_ABSTRACT, DT.TAB_DEC_PACKAGE_DESCRIPTION, \ + DT.TAB_DEC_BINARY_ABSTRACT, DT.TAB_DEC_BINARY_DESCRIPTION]: + EdkLogger.Error("Unicode File Parser", ToolError.FORMAT_INVALID, \ + Message=ST.ERR_UNIPARSE_MULTI_ENTRY_EXIST % StrName.split()[1], \ + ExtraData=File.Path) + if IsIncludeFile: + if StrName not in NewLines: + NewLines.append((Line[:Line.find(u'#language')]).strip()) + else: + NewLines.append((Line[:Line.find(u'#language')]).strip()) + NewLines.append((Line[Line.find(u'#language'):Line.find(u'"')]).strip()) + NewLines.append((Line[Line.find(u'"'):]).strip()) + else: + EdkLogger.Error("Unicode File Parser", ToolError.FORMAT_INVALID, ExtraData=File.Path) + elif Line.startswith(u'#language'): + if len(Line.split()) == 2: + if IsIncludeFile: + if StrName not in NewLines: + NewLines.append(StrName) + else: + NewLines.append(StrName) + NewLines.append(Line) + elif len(Line.split()) > 2 and Line.find(u'"') > 0: + if IsIncludeFile: + if StrName not in NewLines: + NewLines.append(StrName) + else: + NewLines.append(StrName) + NewLines.append((Line[:Line.find(u'"')]).strip()) + NewLines.append((Line[Line.find(u'"'):]).strip()) + else: + EdkLogger.Error("Unicode File Parser", ToolError.FORMAT_INVALID, ExtraData=File.Path) + elif Line.startswith(u'"'): + if u'#string' in Line or u'#language' in Line: + EdkLogger.Error("Unicode File Parser", ToolError.FORMAT_INVALID, ExtraData=File.Path) + NewLines.append(Line) + else: + print(Line) + EdkLogger.Error("Unicode File Parser", ToolError.FORMAT_INVALID, ExtraData=File.Path) + + if StrName and not StrName.split()[1].startswith(u'STR_'): + EdkLogger.Error("Unicode File Parser", ToolError.FORMAT_INVALID, \ + Message=ST.ERR_UNIPARSE_STRNAME_FORMAT_ERROR % StrName.split()[1], \ + ExtraData=File.Path) + + if StrName and not NewLines: + EdkLogger.Error("Unicode File Parser", ToolError.FORMAT_INVALID, \ + Message=ST.ERR_UNI_MISS_LANGENTRY % StrName, \ + ExtraData=File.Path) + + # + # Check Abstract, Description, BinaryAbstract and BinaryDescription order, + # should be Abstract, Description, BinaryAbstract, BinaryDescription + AbstractPosition = -1 + DescriptionPosition = -1 + BinaryAbstractPosition = -1 + BinaryDescriptionPosition = -1 + for StrName in ExistStrNameList: + if DT.TAB_HEADER_ABSTRACT.upper() in StrName: + if 'BINARY' in StrName: + BinaryAbstractPosition = ExistStrNameList.index(StrName) + else: + AbstractPosition = ExistStrNameList.index(StrName) + if DT.TAB_HEADER_DESCRIPTION.upper() in StrName: + if 'BINARY' in StrName: + BinaryDescriptionPosition = ExistStrNameList.index(StrName) + else: + DescriptionPosition = ExistStrNameList.index(StrName) + + OrderList = sorted([AbstractPosition, DescriptionPosition]) + BinaryOrderList = sorted([BinaryAbstractPosition, BinaryDescriptionPosition]) + Min = OrderList[0] + Max = OrderList[1] + BinaryMin = BinaryOrderList[0] + BinaryMax = BinaryOrderList[1] + if BinaryDescriptionPosition > -1: + if not(BinaryDescriptionPosition == BinaryMax and BinaryAbstractPosition == BinaryMin and \ + BinaryMax > Max): + EdkLogger.Error("Unicode File Parser", ToolError.FORMAT_INVALID, \ + Message=ST.ERR_UNIPARSE_ENTRY_ORDER_WRONG, \ + ExtraData=File.Path) + elif BinaryAbstractPosition > -1: + if not(BinaryAbstractPosition > Max): + EdkLogger.Error("Unicode File Parser", ToolError.FORMAT_INVALID, \ + Message=ST.ERR_UNIPARSE_ENTRY_ORDER_WRONG, \ + ExtraData=File.Path) + + if DescriptionPosition > -1: + if not(DescriptionPosition == Max and AbstractPosition == Min and \ + DescriptionPosition > AbstractPosition): + EdkLogger.Error("Unicode File Parser", ToolError.FORMAT_INVALID, \ + Message=ST.ERR_UNIPARSE_ENTRY_ORDER_WRONG, \ + ExtraData=File.Path) + + if not self.UniFileHeader: + EdkLogger.Error("Unicode File Parser", ToolError.FORMAT_INVALID, + Message = ST.ERR_NO_SOURCE_HEADER, + ExtraData=File.Path) + + return NewLines + + # + # Load a .uni file + # + def LoadUniFile(self, File = None): + if File is None: + EdkLogger.Error("Unicode File Parser", + ToolError.PARSER_ERROR, + Message='No unicode file is given', + ExtraData=File.Path) + + self.File = File + + # + # Process special char in file + # + Lines = self.PreProcess(File) + + # + # Get Unicode Information + # + for IndexI in range(len(Lines)): + Line = Lines[IndexI] + if (IndexI + 1) < len(Lines): + SecondLine = Lines[IndexI + 1] + if (IndexI + 2) < len(Lines): + ThirdLine = Lines[IndexI + 2] + + # + # Get Language def information + # + if Line.find(u'#langdef ') >= 0: + self.GetLangDef(File, Line + u' ' + SecondLine) + continue + + Name = '' + Language = '' + Value = '' + CombineToken = False + # + # Get string def information format as below + # + # #string MY_STRING_1 + # #language eng + # "My first English string line 1" + # "My first English string line 2" + # #string MY_STRING_1 + # #language spa + # "Mi segunda secuencia 1" + # "Mi segunda secuencia 2" + # + if Line.find(u'#string ') >= 0 and Line.find(u'#language ') < 0 and \ + SecondLine.find(u'#string ') < 0 and SecondLine.find(u'#language ') >= 0 and \ + ThirdLine.find(u'#string ') < 0 and ThirdLine.find(u'#language ') < 0: + if Line.find('"') > 0 or SecondLine.find('"') > 0: + EdkLogger.Error("Unicode File Parser", ToolError.FORMAT_INVALID, + Message=ST.ERR_UNIPARSE_DBLQUOTE_UNMATCHED, + ExtraData=File.Path) + + Name = Line[Line.find(u'#string ') + len(u'#string ') : ].strip(' ') + Language = SecondLine[SecondLine.find(u'#language ') + len(u'#language ') : ].strip(' ') + for IndexJ in range(IndexI + 2, len(Lines)): + if Lines[IndexJ].find(u'#string ') < 0 and Lines[IndexJ].find(u'#language ') < 0 and \ + Lines[IndexJ].strip().startswith(u'"') and Lines[IndexJ].strip().endswith(u'"'): + if Lines[IndexJ][-2] == ' ': + CombineToken = True + if CombineToken: + if Lines[IndexJ].strip()[1:-1].strip(): + Value = Value + Lines[IndexJ].strip()[1:-1].rstrip() + ' ' + else: + Value = Value + Lines[IndexJ].strip()[1:-1] + CombineToken = False + else: + Value = Value + Lines[IndexJ].strip()[1:-1] + '\r\n' + else: + IndexI = IndexJ + break + if Value.endswith('\r\n'): + Value = Value[: Value.rfind('\r\n')] + Language = GetLanguageCode(Language, self.IsCompatibleMode, self.File) + self.AddStringToList(Name, Language, Value) + continue + + # + # Load multiple .uni files + # + def LoadUniFiles(self, FileList): + if len(FileList) > 0: + for File in FileList: + FilePath = File.Path.strip() + if FilePath.endswith('.uni') or FilePath.endswith('.UNI') or FilePath.endswith('.Uni'): + self.LoadUniFile(File) + + # + # Add a string to list + # + def AddStringToList(self, Name, Language, Value, Token = 0, Referenced = False, UseOtherLangDef = '', Index = -1): + for LangNameItem in self.LanguageDef: + if Language == LangNameItem[0]: + break + + if Language not in self.OrderedStringList: + self.OrderedStringList[Language] = [] + self.OrderedStringDict[Language] = {} + + IsAdded = True + if Name in self.OrderedStringDict[Language]: + IsAdded = False + if Value is not None: + ItemIndexInList = self.OrderedStringDict[Language][Name] + Item = self.OrderedStringList[Language][ItemIndexInList] + Item.UpdateValue(Value) + Item.UseOtherLangDef = '' + + if IsAdded: + Token = len(self.OrderedStringList[Language]) + if Index == -1: + self.OrderedStringList[Language].append(StringDefClassObject(Name, + Value, + Referenced, + Token, + UseOtherLangDef)) + self.OrderedStringDict[Language][Name] = Token + for LangName in self.LanguageDef: + # + # New STRING token will be added into all language string lists. + # so that the unique STRING identifier is reserved for all languages in the package list. + # + if LangName[0] != Language: + if UseOtherLangDef != '': + OtherLangDef = UseOtherLangDef + else: + OtherLangDef = Language + self.OrderedStringList[LangName[0]].append(StringDefClassObject(Name, + '', + Referenced, + Token, + OtherLangDef)) + self.OrderedStringDict[LangName[0]][Name] = len(self.OrderedStringList[LangName[0]]) - 1 + else: + self.OrderedStringList[Language].insert(Index, StringDefClassObject(Name, + Value, + Referenced, + Token, + UseOtherLangDef)) + self.OrderedStringDict[Language][Name] = Index + + # + # Set the string as referenced + # + def SetStringReferenced(self, Name): + # + # String stoken are added in the same order in all language string lists. + # So, only update the status of string stoken in first language string list. + # + Lang = self.LanguageDef[0][0] + if Name in self.OrderedStringDict[Lang]: + ItemIndexInList = self.OrderedStringDict[Lang][Name] + Item = self.OrderedStringList[Lang][ItemIndexInList] + Item.Referenced = True + + # + # Search the string in language definition by Name + # + def FindStringValue(self, Name, Lang): + if Name in self.OrderedStringDict[Lang]: + ItemIndexInList = self.OrderedStringDict[Lang][Name] + return self.OrderedStringList[Lang][ItemIndexInList] + + return None + + # + # Search the string in language definition by Token + # + def FindByToken(self, Token, Lang): + for Item in self.OrderedStringList[Lang]: + if Item.Token == Token: + return Item + + return None + + # + # Re-order strings and re-generate tokens + # + def ReToken(self): + if len(self.LanguageDef) == 0: + return None + # + # Retoken all language strings according to the status of string stoken in the first language string. + # + FirstLangName = self.LanguageDef[0][0] + + # Convert the OrderedStringList to be OrderedStringListByToken in order to faciliate future search by token + for LangNameItem in self.LanguageDef: + self.OrderedStringListByToken[LangNameItem[0]] = {} + + # + # Use small token for all referred string stoken. + # + RefToken = 0 + for Index in range (0, len (self.OrderedStringList[FirstLangName])): + FirstLangItem = self.OrderedStringList[FirstLangName][Index] + if FirstLangItem.Referenced == True: + for LangNameItem in self.LanguageDef: + LangName = LangNameItem[0] + OtherLangItem = self.OrderedStringList[LangName][Index] + OtherLangItem.Referenced = True + OtherLangItem.Token = RefToken + self.OrderedStringListByToken[LangName][OtherLangItem.Token] = OtherLangItem + RefToken = RefToken + 1 + + # + # Use big token for all unreferred string stoken. + # + UnRefToken = 0 + for Index in range (0, len (self.OrderedStringList[FirstLangName])): + FirstLangItem = self.OrderedStringList[FirstLangName][Index] + if FirstLangItem.Referenced == False: + for LangNameItem in self.LanguageDef: + LangName = LangNameItem[0] + OtherLangItem = self.OrderedStringList[LangName][Index] + OtherLangItem.Token = RefToken + UnRefToken + self.OrderedStringListByToken[LangName][OtherLangItem.Token] = OtherLangItem + UnRefToken = UnRefToken + 1 + + # + # Show the instance itself + # + def ShowMe(self): + print(self.LanguageDef) + #print self.OrderedStringList + for Item in self.OrderedStringList: + print(Item) + for Member in self.OrderedStringList[Item]: + print(str(Member)) + + # + # Read content from '!include' UNI file + # + def ReadIncludeUNIfile(self, FilaPath): + if self.File: + pass + + if not os.path.exists(FilaPath) or not os.path.isfile(FilaPath): + EdkLogger.Error("Unicode File Parser", + ToolError.FILE_NOT_FOUND, + ExtraData=FilaPath) + try: + FileIn = codecs.open(FilaPath, mode='rb', encoding='utf_8').readlines() + except UnicodeError as Xstr: + FileIn = codecs.open(FilaPath, mode='rb', encoding='utf_16').readlines() + except UnicodeError: + FileIn = codecs.open(FilaPath, mode='rb', encoding='utf_16_le').readlines() + except: + EdkLogger.Error("Unicode File Parser", ToolError.FILE_OPEN_FAILURE, ExtraData=FilaPath) + return FileIn + diff --git a/BaseTools/Source/Python/UPT/Library/Xml/XmlRoutines.py b/BaseTools/Source/Python/UPT/Library/Xml/XmlRoutines.py index 94e97fa45c..8ef315aded 100644 --- a/BaseTools/Source/Python/UPT/Library/Xml/XmlRoutines.py +++ b/BaseTools/Source/Python/UPT/Library/Xml/XmlRoutines.py @@ -1,223 +1,223 @@ -## @file
-# This is an XML API that uses a syntax similar to XPath, but it is written in
-# standard python so that no extra python packages are required to use it.
-#
-# Copyright (c) 2011 - 2018, Intel Corporation. All rights reserved.<BR>
-#
-# SPDX-License-Identifier: BSD-2-Clause-Patent
-#
-
-'''
-XmlRoutines
-'''
-
-##
-# Import Modules
-#
-import xml.dom.minidom
-import re
-import codecs
-from Logger.ToolError import PARSER_ERROR
-import Logger.Log as Logger
-
-## Create a element of XML
-#
-# @param Name
-# @param String
-# @param NodeList
-# @param AttributeList
-#
-def CreateXmlElement(Name, String, NodeList, AttributeList):
- Doc = xml.dom.minidom.Document()
- Element = Doc.createElement(Name)
- if String != '' and String is not None:
- Element.appendChild(Doc.createTextNode(String))
-
- for Item in NodeList:
- if isinstance(Item, type([])):
- Key = Item[0]
- Value = Item[1]
- if Key != '' and Key is not None and Value != '' and Value is not None:
- Node = Doc.createElement(Key)
- Node.appendChild(Doc.createTextNode(Value))
- Element.appendChild(Node)
- else:
- Element.appendChild(Item)
- for Item in AttributeList:
- Key = Item[0]
- Value = Item[1]
- if Key != '' and Key is not None and Value != '' and Value is not None:
- Element.setAttribute(Key, Value)
-
- return Element
-
-## Get a list of XML nodes using XPath style syntax.
-#
-# Return a list of XML DOM nodes from the root Dom specified by XPath String.
-# If the input Dom or String is not valid, then an empty list is returned.
-#
-# @param Dom The root XML DOM node.
-# @param String A XPath style path.
-#
-def XmlList(Dom, String):
- if String is None or String == "" or Dom is None or Dom == "":
- return []
- if Dom.nodeType == Dom.DOCUMENT_NODE:
- Dom = Dom.documentElement
- if String[0] == "/":
- String = String[1:]
- TagList = String.split('/')
- Nodes = [Dom]
- Index = 0
- End = len(TagList) - 1
- while Index <= End:
- ChildNodes = []
- for Node in Nodes:
- if Node.nodeType == Node.ELEMENT_NODE and Node.tagName == \
- TagList[Index]:
- if Index < End:
- ChildNodes.extend(Node.childNodes)
- else:
- ChildNodes.append(Node)
- Nodes = ChildNodes
- ChildNodes = []
- Index += 1
-
- return Nodes
-
-
-## Get a single XML node using XPath style syntax.
-#
-# Return a single XML DOM node from the root Dom specified by XPath String.
-# If the input Dom or String is not valid, then an empty string is returned.
-#
-# @param Dom The root XML DOM node.
-# @param String A XPath style path.
-#
-def XmlNode(Dom, String):
- if String is None or String == "" or Dom is None or Dom == "":
- return None
- if Dom.nodeType == Dom.DOCUMENT_NODE:
- Dom = Dom.documentElement
- if String[0] == "/":
- String = String[1:]
- TagList = String.split('/')
- Index = 0
- End = len(TagList) - 1
- ChildNodes = [Dom]
- while Index <= End:
- for Node in ChildNodes:
- if Node.nodeType == Node.ELEMENT_NODE and \
- Node.tagName == TagList[Index]:
- if Index < End:
- ChildNodes = Node.childNodes
- else:
- return Node
- break
- Index += 1
- return None
-
-
-## Get a single XML element using XPath style syntax.
-#
-# Return a single XML element from the root Dom specified by XPath String.
-# If the input Dom or String is not valid, then an empty string is returned.
-#
-# @param Dom The root XML DOM object.
-# @param Strin A XPath style path.
-#
-def XmlElement(Dom, String):
- try:
- return XmlNode(Dom, String).firstChild.data.strip()
- except BaseException:
- return ""
-
-## Get a single XML element using XPath style syntax.
-#
-# Similar with XmlElement, but do not strip all the leading and tailing space
-# and newline, instead just remove the newline and spaces introduced by
-# toprettyxml()
-#
-# @param Dom The root XML DOM object.
-# @param Strin A XPath style path.
-#
-def XmlElement2(Dom, String):
- try:
- HelpStr = XmlNode(Dom, String).firstChild.data
- gRemovePrettyRe = re.compile(r"""(?:(\n *) )(.*)\1""", re.DOTALL)
- HelpStr = re.sub(gRemovePrettyRe, r"\2", HelpStr)
- return HelpStr
- except BaseException:
- return ""
-
-
-## Get a single XML element of the current node.
-#
-# Return a single XML element specified by the current root Dom.
-# If the input Dom is not valid, then an empty string is returned.
-#
-# @param Dom The root XML DOM object.
-#
-def XmlElementData(Dom):
- try:
- return Dom.firstChild.data.strip()
- except BaseException:
- return ""
-
-
-## Get a list of XML elements using XPath style syntax.
-#
-# Return a list of XML elements from the root Dom specified by XPath String.
-# If the input Dom or String is not valid, then an empty list is returned.
-#
-# @param Dom The root XML DOM object.
-# @param String A XPath style path.
-#
-def XmlElementList(Dom, String):
- return list(map(XmlElementData, XmlList(Dom, String)))
-
-
-## Get the XML attribute of the current node.
-#
-# Return a single XML attribute named Attribute from the current root Dom.
-# If the input Dom or Attribute is not valid, then an empty string is returned.
-#
-# @param Dom The root XML DOM object.
-# @param Attribute The name of Attribute.
-#
-def XmlAttribute(Dom, Attribute):
- try:
- return Dom.getAttribute(Attribute)
- except BaseException:
- return ''
-
-
-## Get the XML node name of the current node.
-#
-# Return a single XML node name from the current root Dom.
-# If the input Dom is not valid, then an empty string is returned.
-#
-# @param Dom The root XML DOM object.
-#
-def XmlNodeName(Dom):
- try:
- return Dom.nodeName.strip()
- except BaseException:
- return ''
-
-## Parse an XML file.
-#
-# Parse the input XML file named FileName and return a XML DOM it stands for.
-# If the input File is not a valid XML file, then an empty string is returned.
-#
-# @param FileName The XML file name.
-#
-def XmlParseFile(FileName):
- try:
- XmlFile = codecs.open(FileName, 'rb')
- Dom = xml.dom.minidom.parse(XmlFile)
- XmlFile.close()
- return Dom
- except BaseException as XExcept:
- XmlFile.close()
- Logger.Error('\nUPT', PARSER_ERROR, XExcept, File=FileName, RaiseError=True)
+## @file +# This is an XML API that uses a syntax similar to XPath, but it is written in +# standard python so that no extra python packages are required to use it. +# +# Copyright (c) 2011 - 2018, Intel Corporation. All rights reserved.<BR> +# +# SPDX-License-Identifier: BSD-2-Clause-Patent +# + +''' +XmlRoutines +''' + +## +# Import Modules +# +import xml.dom.minidom +import re +import codecs +from Logger.ToolError import PARSER_ERROR +import Logger.Log as Logger + +## Create a element of XML +# +# @param Name +# @param String +# @param NodeList +# @param AttributeList +# +def CreateXmlElement(Name, String, NodeList, AttributeList): + Doc = xml.dom.minidom.Document() + Element = Doc.createElement(Name) + if String != '' and String is not None: + Element.appendChild(Doc.createTextNode(String)) + + for Item in NodeList: + if isinstance(Item, type([])): + Key = Item[0] + Value = Item[1] + if Key != '' and Key is not None and Value != '' and Value is not None: + Node = Doc.createElement(Key) + Node.appendChild(Doc.createTextNode(Value)) + Element.appendChild(Node) + else: + Element.appendChild(Item) + for Item in AttributeList: + Key = Item[0] + Value = Item[1] + if Key != '' and Key is not None and Value != '' and Value is not None: + Element.setAttribute(Key, Value) + + return Element + +## Get a list of XML nodes using XPath style syntax. +# +# Return a list of XML DOM nodes from the root Dom specified by XPath String. +# If the input Dom or String is not valid, then an empty list is returned. +# +# @param Dom The root XML DOM node. +# @param String A XPath style path. +# +def XmlList(Dom, String): + if String is None or String == "" or Dom is None or Dom == "": + return [] + if Dom.nodeType == Dom.DOCUMENT_NODE: + Dom = Dom.documentElement + if String[0] == "/": + String = String[1:] + TagList = String.split('/') + Nodes = [Dom] + Index = 0 + End = len(TagList) - 1 + while Index <= End: + ChildNodes = [] + for Node in Nodes: + if Node.nodeType == Node.ELEMENT_NODE and Node.tagName == \ + TagList[Index]: + if Index < End: + ChildNodes.extend(Node.childNodes) + else: + ChildNodes.append(Node) + Nodes = ChildNodes + ChildNodes = [] + Index += 1 + + return Nodes + + +## Get a single XML node using XPath style syntax. +# +# Return a single XML DOM node from the root Dom specified by XPath String. +# If the input Dom or String is not valid, then an empty string is returned. +# +# @param Dom The root XML DOM node. +# @param String A XPath style path. +# +def XmlNode(Dom, String): + if String is None or String == "" or Dom is None or Dom == "": + return None + if Dom.nodeType == Dom.DOCUMENT_NODE: + Dom = Dom.documentElement + if String[0] == "/": + String = String[1:] + TagList = String.split('/') + Index = 0 + End = len(TagList) - 1 + ChildNodes = [Dom] + while Index <= End: + for Node in ChildNodes: + if Node.nodeType == Node.ELEMENT_NODE and \ + Node.tagName == TagList[Index]: + if Index < End: + ChildNodes = Node.childNodes + else: + return Node + break + Index += 1 + return None + + +## Get a single XML element using XPath style syntax. +# +# Return a single XML element from the root Dom specified by XPath String. +# If the input Dom or String is not valid, then an empty string is returned. +# +# @param Dom The root XML DOM object. +# @param Strin A XPath style path. +# +def XmlElement(Dom, String): + try: + return XmlNode(Dom, String).firstChild.data.strip() + except BaseException: + return "" + +## Get a single XML element using XPath style syntax. +# +# Similar with XmlElement, but do not strip all the leading and tailing space +# and newline, instead just remove the newline and spaces introduced by +# toprettyxml() +# +# @param Dom The root XML DOM object. +# @param Strin A XPath style path. +# +def XmlElement2(Dom, String): + try: + HelpStr = XmlNode(Dom, String).firstChild.data + gRemovePrettyRe = re.compile(r"""(?:(\n *) )(.*)\1""", re.DOTALL) + HelpStr = re.sub(gRemovePrettyRe, r"\2", HelpStr) + return HelpStr + except BaseException: + return "" + + +## Get a single XML element of the current node. +# +# Return a single XML element specified by the current root Dom. +# If the input Dom is not valid, then an empty string is returned. +# +# @param Dom The root XML DOM object. +# +def XmlElementData(Dom): + try: + return Dom.firstChild.data.strip() + except BaseException: + return "" + + +## Get a list of XML elements using XPath style syntax. +# +# Return a list of XML elements from the root Dom specified by XPath String. +# If the input Dom or String is not valid, then an empty list is returned. +# +# @param Dom The root XML DOM object. +# @param String A XPath style path. +# +def XmlElementList(Dom, String): + return list(map(XmlElementData, XmlList(Dom, String))) + + +## Get the XML attribute of the current node. +# +# Return a single XML attribute named Attribute from the current root Dom. +# If the input Dom or Attribute is not valid, then an empty string is returned. +# +# @param Dom The root XML DOM object. +# @param Attribute The name of Attribute. +# +def XmlAttribute(Dom, Attribute): + try: + return Dom.getAttribute(Attribute) + except BaseException: + return '' + + +## Get the XML node name of the current node. +# +# Return a single XML node name from the current root Dom. +# If the input Dom is not valid, then an empty string is returned. +# +# @param Dom The root XML DOM object. +# +def XmlNodeName(Dom): + try: + return Dom.nodeName.strip() + except BaseException: + return '' + +## Parse an XML file. +# +# Parse the input XML file named FileName and return a XML DOM it stands for. +# If the input File is not a valid XML file, then an empty string is returned. +# +# @param FileName The XML file name. +# +def XmlParseFile(FileName): + try: + XmlFile = codecs.open(FileName, 'rb') + Dom = xml.dom.minidom.parse(XmlFile) + XmlFile.close() + return Dom + except BaseException as XExcept: + XmlFile.close() + Logger.Error('\nUPT', PARSER_ERROR, XExcept, File=FileName, RaiseError=True) diff --git a/BaseTools/Source/Python/UPT/Library/Xml/__init__.py b/BaseTools/Source/Python/UPT/Library/Xml/__init__.py index 172e498451..a800a6195f 100644 --- a/BaseTools/Source/Python/UPT/Library/Xml/__init__.py +++ b/BaseTools/Source/Python/UPT/Library/Xml/__init__.py @@ -1,14 +1,14 @@ -## @file
-# Python 'Library' 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.<BR>
-#
-# SPDX-License-Identifier: BSD-2-Clause-Patent
-#
-
-'''
-Xml
-'''
+## @file +# Python 'Library' 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.<BR> +# +# SPDX-License-Identifier: BSD-2-Clause-Patent +# + +''' +Xml +''' diff --git a/BaseTools/Source/Python/UPT/Library/__init__.py b/BaseTools/Source/Python/UPT/Library/__init__.py index 07b5b75dd5..fa602a2ddf 100644 --- a/BaseTools/Source/Python/UPT/Library/__init__.py +++ b/BaseTools/Source/Python/UPT/Library/__init__.py @@ -1,14 +1,14 @@ -## @file
-# Python 'Library' 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.<BR>
-#
-# SPDX-License-Identifier: BSD-2-Clause-Patent
-#
-
-'''
-Library
-'''
+## @file +# Python 'Library' 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.<BR> +# +# SPDX-License-Identifier: BSD-2-Clause-Patent +# + +''' +Library +''' |
