1 ## @file ParserValidate.py
2 # Functions for parser validation
4 # Copyright (c) 2011 - 2014, Intel Corporation. All rights reserved.<BR>
6 # This program and the accompanying materials are licensed and made available
7 # under the terms and conditions of the BSD License which accompanies this
8 # distribution. The full text of the license may be found at
9 # http://opensource.org/licenses/bsd-license.php
11 # THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
12 # WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
23 from Library
.DataType
import MODULE_LIST
24 from Library
.DataType
import COMPONENT_TYPE_LIST
25 from Library
.DataType
import PCD_USAGE_TYPE_LIST_OF_MODULE
26 from Library
.DataType
import TAB_SPACE_SPLIT
27 from Library
.String
import GetSplitValueList
28 from Library
.ExpressionValidate
import IsValidBareCString
29 from Library
.ExpressionValidate
import IsValidFeatureFlagExp
30 from Common
.MultipleWorkspace
import MultipleWorkspace
as mws
32 ## __HexDigit() method
34 # Whether char input is a Hex data bit
36 # @param TempChar: The char to test
38 def __HexDigit(TempChar
):
39 if (TempChar
>= 'a' and TempChar
<= 'f') or \
40 (TempChar
>= 'A' and TempChar
<= 'F') \
41 or (TempChar
>= '0' and TempChar
<= '9'):
46 ## IsValidHex() method
48 # Whether char input is a Hex data.
50 # @param TempChar: The char to test
52 def IsValidHex(HexStr
):
53 if not HexStr
.upper().startswith("0X"):
55 CharList
= [c
for c
in HexStr
[2:] if not __HexDigit(c
)]
56 if len(CharList
) == 0:
61 ## Judge the input string is valid bool type or not.
63 # <TRUE> ::= {"TRUE"} {"true"} {"True"} {"0x1"} {"0x01"}
64 # <FALSE> ::= {"FALSE"} {"false"} {"False"} {"0x0"} {"0x00"}
65 # <BoolType> ::= {<TRUE>} {<FALSE>}
67 # @param BoolString: A string contained the value need to be judged.
69 def IsValidBoolType(BoolString
):
73 if BoolString
== 'TRUE' or \
74 BoolString
== 'True' or \
75 BoolString
== 'true' or \
76 BoolString
== '0x1' or \
82 elif BoolString
== 'FALSE' or \
83 BoolString
== 'False' or \
84 BoolString
== 'false' or \
85 BoolString
== '0x0' or \
94 ## Is Valid Module Type List or not
96 # @param ModuleTypeList: A list contain ModuleType strings need to be
99 def IsValidInfMoudleTypeList(ModuleTypeList
):
100 for ModuleType
in ModuleTypeList
:
101 return IsValidInfMoudleType(ModuleType
)
103 ## Is Valid Module Type or not
105 # @param ModuleType: A string contain ModuleType need to be judged.
107 def IsValidInfMoudleType(ModuleType
):
108 if ModuleType
in MODULE_LIST
:
113 ## Is Valid Component Type or not
115 # @param ComponentType: A string contain ComponentType need to be judged.
117 def IsValidInfComponentType(ComponentType
):
118 if ComponentType
.upper() in COMPONENT_TYPE_LIST
:
124 ## Is valid Tool Family or not
126 # @param ToolFamily: A string contain Tool Family need to be judged.
127 # Famlily := [A-Z]([a-zA-Z0-9])*
129 def IsValidToolFamily(ToolFamily
):
130 ReIsValieFamily
= re
.compile(r
"^[A-Z]+[A-Za-z0-9]{0,}$", re
.DOTALL
)
131 if ReIsValieFamily
.match(ToolFamily
) == None:
135 ## Is valid Tool TagName or not
137 # The TagName sample is MYTOOLS and VS2005.
139 # @param TagName: A string contain Tool TagName need to be judged.
141 def IsValidToolTagName(TagName
):
142 if TagName
.strip() == '':
144 if TagName
.strip() == '*':
146 if not IsValidWord(TagName
):
150 ## Is valid arch or not
152 # @param Arch The arch string need to be validated
153 # <OA> ::= (a-zA-Z)(A-Za-z0-9){0,}
154 # <arch> ::= {"IA32"} {"X64"} {"IPF"} {"EBC"} {<OA>}
156 # @param Arch: Input arch
158 def IsValidArch(Arch
):
161 ReIsValieArch
= re
.compile(r
"^[a-zA-Z]+[a-zA-Z0-9]{0,}$", re
.DOTALL
)
162 if ReIsValieArch
.match(Arch
) == None:
166 ## Is valid family or not
168 # <Family> ::= {"MSFT"} {"GCC"} {"INTEL"} {<Usr>} {"*"}
169 # <Usr> ::= [A-Z][A-Za-z0-9]{0,}
171 # @param family: The family string need to be validated
173 def IsValidFamily(Family
):
174 Family
= Family
.strip()
181 ReIsValidFamily
= re
.compile(r
"^[A-Z]+[A-Za-z0-9]{0,}$", re
.DOTALL
)
182 if ReIsValidFamily
.match(Family
) == None:
186 ## Is valid build option name or not
188 # @param BuildOptionName: The BuildOptionName string need to be validated
190 def IsValidBuildOptionName(BuildOptionName
):
191 if not BuildOptionName
:
194 ToolOptionList
= GetSplitValueList(BuildOptionName
, '_', 4)
196 if len(ToolOptionList
) != 5:
199 ReIsValidBuildOption1
= re
.compile(r
"^\s*(\*)|([A-Z][a-zA-Z0-9]*)$")
200 ReIsValidBuildOption2
= re
.compile(r
"^\s*(\*)|([a-zA-Z][a-zA-Z0-9]*)$")
202 if ReIsValidBuildOption1
.match(ToolOptionList
[0]) == None:
205 if ReIsValidBuildOption1
.match(ToolOptionList
[1]) == None:
208 if ReIsValidBuildOption2
.match(ToolOptionList
[2]) == None:
211 if ToolOptionList
[3] == "*" and ToolOptionList
[4] not in ['FAMILY', 'DLL', 'DPATH']:
218 # Check if pattern string matches total token
220 # @param ReString: regular string
221 # @param Token: Token to be matched
223 def IsValidToken(ReString
, Token
):
224 Match
= re
.compile(ReString
).match(Token
)
225 return Match
and Match
.start() == 0 and Match
.end() == len(Token
)
229 # Check if path exist
231 # @param Path: Absolute path or relative path to be checked
232 # @param Root: Root path
234 def IsValidPath(Path
, Root
):
236 OrigPath
= Path
.replace('\\', '/')
238 Path
= os
.path
.normpath(Path
).replace('\\', '/')
239 Root
= os
.path
.normpath(Root
).replace('\\', '/')
240 FullPath
= mws
.join(Root
, Path
)
242 if not os
.path
.exists(FullPath
):
246 # If Path is absolute path.
247 # It should be in Root.
249 if os
.path
.isabs(Path
):
250 if not Path
.startswith(Root
):
255 # Check illegal character
257 for Rel
in ['/', './', '../']:
258 if OrigPath
.startswith(Rel
):
260 for Rel
in ['//', '/./', '/../']:
263 for Rel
in ['/.', '/..', '/']:
264 if OrigPath
.endswith(Rel
):
267 Path
= Path
.rstrip('/')
270 # Check relative path
272 for Word
in Path
.split('/'):
273 if not IsValidWord(Word
):
278 ## IsValidInstallPath
280 # Check if an install path valid or not.
282 # Absolute path or path starts with '.' or path contains '..' are invalid.
284 # @param Path: path to be checked
286 def IsValidInstallPath(Path
):
287 if platform
.platform().find("Windows") >= 0:
288 if os
.path
.isabs(Path
):
293 if os
.path
.isabs(Path
):
295 if Path
.startswith('.'):
298 if Path
.find('..') != -1:
304 ## IsValidCFormatGuid
306 # Check if GUID format has the from of {8,4,4,{2,2,2,2,2,2,2,2}}
308 # @param Guid: Guid to be checked
310 def IsValidCFormatGuid(Guid
):
312 # Valid: { 0xf0b11735, 0x87a0, 0x4193, {0xb2, 0x66, 0x53, 0x8c, 0x38,
313 # 0xaf, 0x48, 0xce }}
314 # Invalid: { 0xf0b11735, 0x87a0, 0x4193, {0xb2, 0x66, 0x53, 0x8c, 0x38,
315 # 0xaf, 0x48, 0xce }} 0x123
316 # Invalid: { 0xf0b1 1735, 0x87a0, 0x4193, {0xb2, 0x66, 0x53, 0x8c, 0x38,
317 # 0xaf, 0x48, 0xce }}
319 List
= ['{', 10, ',', 6, ',', 6, ',{', 4, ',', 4, ',', 4,
320 ',', 4, ',', 4, ',', 4, ',', 4, ',', 4, '}}']
325 if Char
not in '{},\t ':
331 # Index may out of bound
333 if not SepValue
or SepValue
!= List
[Index
]:
338 if not Value
.startswith('0x') and not Value
.startswith('0X'):
342 # Index may out of bound
344 if type(List
[Index
]) != type(1) or \
345 len(Value
) > List
[Index
] or len(Value
) < 3:
349 # Check if string can be converted to integer
350 # Throw exception if not
353 except BaseException
:
355 # Exception caught means invalid format
363 return SepValue
== '}}' and Value
== ''
367 # Check whether the PCD type is valid
369 # @param PcdTypeString: The PcdType string need to be checked.
371 def IsValidPcdType(PcdTypeString
):
372 if PcdTypeString
.upper() in PCD_USAGE_TYPE_LIST_OF_MODULE
:
379 # Check whether the word is valid.
380 # <Word> ::= (a-zA-Z0-9_)(a-zA-Z0-9_-){0,} Alphanumeric characters with
382 # dash "-" and/or underscore "_" characters. No whitespace
383 # characters are permitted.
385 # @param Word: The word string need to be checked.
387 def IsValidWord(Word
):
391 # The first char should be alpha, _ or Digit.
393 if not Word
[0].isalnum() and \
394 not Word
[0] == '_' and \
395 not Word
[0].isdigit():
399 for Char
in Word
[1:]:
400 if (not Char
.isalpha()) and \
401 (not Char
.isdigit()) and \
406 if Char
== '.' and LastChar
== '.':
415 # Check whether the SimpleWord is valid.
416 # <SimpleWord> ::= (a-zA-Z0-9)(a-zA-Z0-9_-){0,}
417 # A word that cannot contain a period character.
419 # @param Word: The word string need to be checked.
421 def IsValidSimpleWord(Word
):
422 ReIsValidSimpleWord
= \
423 re
.compile(r
"^[0-9A-Za-z][0-9A-Za-z\-_]*$", re
.DOTALL
)
428 if not ReIsValidSimpleWord
.match(Word
):
435 # Check whether the decimal version is valid.
436 # <DecVersion> ::= (0-9){1,} ["." (0-9){1,}]
438 # @param Word: The word string need to be checked.
440 def IsValidDecVersion(Word
):
441 if Word
.find('.') > -1:
442 ReIsValidDecVersion
= re
.compile(r
"[0-9]+\.?[0-9]+$")
444 ReIsValidDecVersion
= re
.compile(r
"[0-9]+$")
445 if ReIsValidDecVersion
.match(Word
) == None:
451 # Check whether the hex version is valid.
452 # <HexVersion> ::= "0x" <Major> <Minor>
453 # <Major> ::= <HexDigit>{4}
454 # <Minor> ::= <HexDigit>{4}
456 # @param Word: The word string need to be checked.
458 def IsValidHexVersion(Word
):
459 ReIsValidHexVersion
= re
.compile(r
"[0][xX][0-9A-Fa-f]{8}$", re
.DOTALL
)
460 if ReIsValidHexVersion
.match(Word
) == None:
465 ## IsValidBuildNumber
467 # Check whether the BUILD_NUMBER is valid.
468 # ["BUILD_NUMBER" "=" <Integer>{1,4} <EOL>]
470 # @param Word: The BUILD_NUMBER string need to be checked.
472 def IsValidBuildNumber(Word
):
473 ReIsValieBuildNumber
= re
.compile(r
"[0-9]{1,4}$", re
.DOTALL
)
474 if ReIsValieBuildNumber
.match(Word
) == None:
481 # Check whether the Depex is valid.
483 # @param Word: The Depex string need to be checked.
485 def IsValidDepex(Word
):
486 Index
= Word
.upper().find("PUSH")
488 return IsValidCFormatGuid(Word
[Index
+4:].strip())
490 ReIsValidCName
= re
.compile(r
"^[A-Za-z_][0-9A-Za-z_\s\.]*$", re
.DOTALL
)
491 if ReIsValidCName
.match(Word
) == None:
496 ## IsValidNormalizedString
499 # <NormalizedString> ::= <DblQuote> [{<Word>} {<Space>}]{1,} <DblQuote>
502 # @param String: string to be checked
504 def IsValidNormalizedString(String
):
512 StringList
= GetSplitValueList(String
, TAB_SPACE_SPLIT
)
514 for Item
in StringList
:
517 if not IsValidWord(Item
):
524 # Check whether the IdString is valid.
526 # @param IdString: The IdString need to be checked.
528 def IsValidIdString(String
):
529 if IsValidSimpleWord(String
.strip()):
532 if String
.strip().startswith('"') and \
533 String
.strip().endswith('"'):
534 String
= String
[1:-1]
535 if String
.strip() == "":
537 if IsValidNormalizedString(String
):
542 ## IsValidVersionString
544 # Check whether the VersionString is valid.
545 # <AsciiString> ::= [ [<WhiteSpace>]{0,} [<AsciiChars>]{0,} ] {0,}
546 # <WhiteSpace> ::= {<Tab>} {<Space>}
549 # <AsciiChars> ::= (0x21 - 0x7E)
551 # @param VersionString: The VersionString need to be checked.
553 def IsValidVersionString(VersionString
):
554 VersionString
= VersionString
.strip()
555 for Char
in VersionString
:
556 if not (Char
>= 0x21 and Char
<= 0x7E):
563 # Check whether the PcdValue is valid.
565 # @param VersionString: The PcdValue need to be checked.
567 def IsValidPcdValue(PcdValue
):
568 for Char
in PcdValue
:
569 if Char
== '\n' or Char
== '\t' or Char
== '\f':
575 if IsValidFeatureFlagExp(PcdValue
, True)[0]:
579 # <Number> ::= {<Integer>} {<HexNumber>}
580 # <Integer> ::= {(0-9)} {(1-9)(0-9){1,}}
581 # <HexNumber> ::= "0x" <HexDigit>{1,}
582 # <HexDigit> ::= (a-fA-F0-9)
584 if IsValidHex(PcdValue
):
587 ReIsValidIntegerSingle
= re
.compile(r
"^\s*[0-9]\s*$", re
.DOTALL
)
588 if ReIsValidIntegerSingle
.match(PcdValue
) != None:
591 ReIsValidIntegerMulti
= re
.compile(r
"^\s*[1-9][0-9]+\s*$", re
.DOTALL
)
592 if ReIsValidIntegerMulti
.match(PcdValue
) != None:
596 # <StringVal> ::= {<StringType>} {<Array>} {"$(" <MACRO> ")"}
597 # <StringType> ::= {<UnicodeString>} {<CString>}
599 ReIsValidStringType
= re
.compile(r
"^\s*[\"L
].*[\"]\s
*$
")
600 if ReIsValidStringType.match(PcdValue):
602 if PcdValue.strip().startswith('L\"'):
603 StringValue = PcdValue.strip().lstrip('L\"').rstrip('\"')
604 if IsValidBareCString(StringValue):
606 elif PcdValue.strip().startswith('\"'):
607 StringValue = PcdValue.strip().lstrip('\"').rstrip('\"')
608 if IsValidBareCString(StringValue):
614 # <Array> ::= {<CArray>} {<NList>} {<CFormatGUID>}
615 # <CArray> ::= "{" [<NList>] <CArray>{0,} "}"
616 # <NList> ::= <HexByte> ["," <HexByte>]{0,}
617 # <HexDigit> ::= (a-fA-F0-9)
618 # <HexByte> ::= "0x
" <HexDigit>{1,2}
620 if IsValidCFormatGuid(PcdValue):
623 ReIsValidByteHex = re.compile(r"^\s
*0x
[0-9a
-fA
-F
]{1,2}\s
*$
", re.DOTALL)
624 if PcdValue.strip().startswith('{') and PcdValue.strip().endswith('}') :
625 StringValue = PcdValue.strip().lstrip('{').rstrip('}')
626 ValueList = StringValue.split(',')
628 for ValueItem in ValueList:
629 if not ReIsValidByteHex.match(ValueItem.strip()):
639 ValueList = PcdValue.split(',')
640 for ValueItem in ValueList:
641 if not ReIsValidByteHex.match(ValueItem.strip()):
649 ## IsValidCVariableName
651 # Check whether the PcdValue is valid.
653 # @param VersionString: The PcdValue need to be checked.
655 def IsValidCVariableName(CName):
656 ReIsValidCName = re.compile(r"^
[A
-Za
-z_
][0-9A
-Za
-z_
]*$
", re.DOTALL)
657 if ReIsValidCName.match(CName) == None:
664 # <Identifier> ::= <NonDigit> <Chars>{0,}
665 # <Chars> ::= (a-zA-Z0-9_)
666 # <NonDigit> ::= (a-zA-Z_)
668 # @param Ident: identifier to be checked
670 def IsValidIdentifier(Ident):
671 ReIdent = re.compile(r"^
[A
-Za
-z_
][0-9A
-Za
-z_
]*$
", re.DOTALL)
672 if ReIdent.match(Ident) == None:
677 ## IsValidDecVersionVal
679 # {(0-9){1,} "." (0-99)}
681 # @param Ver: version to be checked
683 def IsValidDecVersionVal(Ver):
684 ReVersion = re.compile(r"[0-9]+(\
.[0-9]{1,2})$
")
686 if ReVersion.match(Ver) == None:
694 # (A-Z)(a-zA-Z0-9){0,} and could not be "NULL
"
696 def IsValidLibName(LibName):
697 if LibName == 'NULL':
699 ReLibName = re.compile("^
[A
-Z
]+[a
-zA
-Z0
-9]*$
")
700 if not ReLibName.match(LibName):
707 # <UserId> ::= (a-zA-Z)(a-zA-Z0-9_.){0,}
708 # Words that contain period "." must be encapsulated in double quotation marks.
710 def IsValidUserId(UserId):
711 UserId = UserId.strip()
713 if UserId.startswith('"') and UserId.endswith('"'):
715 UserId = UserId[1:-1]
716 if not UserId or not UserId[0].isalpha():
718 for Char in UserId[1:]:
719 if not Char.isalnum() and not Char in '_.':
721 if Char == '.' and not Quoted:
726 # Check if a UTF16-LE file has a BOM header
728 def CheckUTF16FileHeader(File):
729 FileIn = open(File, 'rb').read(2)
730 if FileIn != '\xff\xfe':