]> git.proxmox.com Git - mirror_edk2.git/blob - BaseTools/Source/Python/UPT/Library/ParserValidate.py
Sync BaseTool trunk (version r2474) into EDKII BaseTools.
[mirror_edk2.git] / BaseTools / Source / Python / UPT / Library / ParserValidate.py
1 ## @file ParserValidate.py
2 #
3 # Copyright (c) 2011, Intel Corporation. All rights reserved.<BR>
4 #
5 # This program and the accompanying materials are licensed and made available
6 # under the terms and conditions of the BSD License which accompanies this
7 # distribution. The full text of the license may be found at
8 # http://opensource.org/licenses/bsd-license.php
9 #
10 # THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
11 # WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
12 #
13
14 '''
15 PaserValidate
16 '''
17
18 import os.path
19 import re
20 import platform
21
22 from Library.DataType import MODULE_LIST
23 from Library.DataType import COMPONENT_TYPE_LIST
24 from Library.DataType import PCD_USAGE_TYPE_LIST_OF_MODULE
25 from Library.DataType import TAB_SPACE_SPLIT
26 from Library.String import GetSplitValueList
27 from Library.ExpressionValidate import IsValidBareCString
28 from Library.ExpressionValidate import IsValidFeatureFlagExp
29
30 ## __HexDigit() method
31 #
32 # Whether char input is a Hex data bit
33 #
34 # @param TempChar: The char to test
35 #
36 def __HexDigit(TempChar):
37 if (TempChar >= 'a' and TempChar <= 'f') or \
38 (TempChar >= 'A' and TempChar <= 'F') \
39 or (TempChar >= '0' and TempChar <= '9'):
40 return True
41 else:
42 return False
43
44 ## IsValidHex() method
45 #
46 # Whether char input is a Hex data.
47 #
48 # @param TempChar: The char to test
49 #
50 def IsValidHex(HexStr):
51 if not HexStr.upper().startswith("0X"):
52 return False
53 CharList = [c for c in HexStr[2:] if not __HexDigit(c)]
54 if len(CharList) == 0:
55 return True
56 else:
57 return False
58
59 ## Judge the input string is valid bool type or not.
60 #
61 # <TRUE> ::= {"TRUE"} {"true"} {"True"} {"0x1"} {"0x01"}
62 # <FALSE> ::= {"FALSE"} {"false"} {"False"} {"0x0"} {"0x00"}
63 # <BoolType> ::= {<TRUE>} {<FALSE>}
64 #
65 # @param BoolString: A string contained the value need to be judged.
66 #
67 def IsValidBoolType(BoolString):
68 #
69 # Valid Ture
70 #
71 if BoolString == 'TRUE' or \
72 BoolString == 'True' or \
73 BoolString == 'true' or \
74 BoolString == '0x1' or \
75 BoolString == '0x01':
76 return True
77 #
78 # Valid False
79 #
80 elif BoolString == 'FALSE' or \
81 BoolString == 'False' or \
82 BoolString == 'false' or \
83 BoolString == '0x0' or \
84 BoolString == '0x00':
85 return True
86 #
87 # Invalid bool type
88 #
89 else:
90 return False
91
92 ## Is Valid Module Type List or not
93 #
94 # @param ModuleTypeList: A list contain ModuleType strings need to be
95 # judged.
96 #
97 def IsValidInfMoudleTypeList(ModuleTypeList):
98 for ModuleType in ModuleTypeList:
99 return IsValidInfMoudleType(ModuleType)
100
101 ## Is Valid Module Type or not
102 #
103 # @param ModuleType: A string contain ModuleType need to be judged.
104 #
105 def IsValidInfMoudleType(ModuleType):
106 if ModuleType in MODULE_LIST:
107 return True
108 else:
109 return False
110
111 ## Is Valid Component Type or not
112 #
113 # @param ComponentType: A string contain ComponentType need to be judged.
114 #
115 def IsValidInfComponentType(ComponentType):
116 if ComponentType.upper() in COMPONENT_TYPE_LIST:
117 return True
118 else:
119 return False
120
121
122 ## Is valid Tool Family or not
123 #
124 # @param ToolFamily: A string contain Tool Family need to be judged.
125 # Famlily := [A-Z]([a-zA-Z0-9])*
126 #
127 def IsValidToolFamily(ToolFamily):
128 ReIsValieFamily = re.compile(r"^[A-Z]+[A-Za-z0-9]{0,}$", re.DOTALL)
129 if ReIsValieFamily.match(ToolFamily) == None:
130 return False
131 return True
132
133 ## Is valid Tool TagName or not
134 #
135 # The TagName sample is MYTOOLS and VS2005.
136 #
137 # @param TagName: A string contain Tool TagName need to be judged.
138 #
139 def IsValidToolTagName(TagName):
140 if TagName.strip() == '':
141 return True
142 if TagName.strip() == '*':
143 return True
144 if not IsValidWord(TagName):
145 return False
146 return True
147
148 ## Is valid arch or not
149 #
150 # @param Arch The arch string need to be validated
151 # <OA> ::= (a-zA-Z)(A-Za-z0-9){0,}
152 # <arch> ::= {"IA32"} {"X64"} {"IPF"} {"EBC"} {<OA>}
153 # {"common"}
154 # @param Arch: Input arch
155 #
156 def IsValidArch(Arch):
157 if Arch == 'common':
158 return True
159 ReIsValieArch = re.compile(r"^[a-zA-Z]+[a-zA-Z0-9]{0,}$", re.DOTALL)
160 if ReIsValieArch.match(Arch) == None:
161 return False
162 return True
163
164 ## Is valid family or not
165 #
166 # <Family> ::= {"MSFT"} {"GCC"} {"INTEL"} {<Usr>} {"*"}
167 # <Usr> ::= [A-Z][A-Za-z0-9]{0,}
168 #
169 # @param family: The family string need to be validated
170 #
171 def IsValidFamily(Family):
172 Family = Family.strip()
173 if Family == '*':
174 return True
175
176 if Family == '':
177 return True
178
179 ReIsValidFamily = re.compile(r"^[A-Z]+[A-Za-z0-9]{0,}$", re.DOTALL)
180 if ReIsValidFamily.match(Family) == None:
181 return False
182 return True
183
184 ## Is valid build option name or not
185 #
186 # @param BuildOptionName: The BuildOptionName string need to be validated
187 #
188 def IsValidBuildOptionName(BuildOptionName):
189 if not BuildOptionName:
190 return False
191
192 ToolOptionList = GetSplitValueList(BuildOptionName, '_', 4)
193
194 if len(ToolOptionList) != 5:
195 return False
196
197 ReIsValidBuildOption1 = re.compile(r"^\s*(\*)|([A-Z][a-zA-Z0-9]*)$")
198 ReIsValidBuildOption2 = re.compile(r"^\s*(\*)|([a-zA-Z][a-zA-Z0-9]*)$")
199
200 if ReIsValidBuildOption1.match(ToolOptionList[0]) == None:
201 return False
202
203 if ReIsValidBuildOption1.match(ToolOptionList[1]) == None:
204 return False
205
206 if ReIsValidBuildOption2.match(ToolOptionList[2]) == None:
207 return False
208
209 if ToolOptionList[3] == "*" and ToolOptionList[4] not in ['FAMILY', 'DLL', 'DPATH']:
210 return False
211
212 return True
213
214 ## IsValidToken
215 #
216 # Check if pattern string matches total token
217 #
218 # @param ReString: regular string
219 # @param Token: Token to be matched
220 #
221 def IsValidToken(ReString, Token):
222 Match = re.compile(ReString).match(Token)
223 return Match and Match.start() == 0 and Match.end() == len(Token)
224
225 ## IsValidPath
226 #
227 # Check if path exist
228 #
229 # @param Path: Absolute path or relative path to be checked
230 # @param Root: Root path
231 #
232 def IsValidPath(Path, Root):
233 Path = Path.strip()
234 OrigPath = Path.replace('\\', '/')
235
236 Path = os.path.normpath(Path).replace('\\', '/')
237 Root = os.path.normpath(Root).replace('\\', '/')
238 FullPath = os.path.normpath(os.path.join(Root, Path)).replace('\\', '/')
239
240 if not os.path.exists(FullPath):
241 return False
242
243 #
244 # If Path is absolute path.
245 # It should be in Root.
246 #
247 if os.path.isabs(Path):
248 if not Path.startswith(Root):
249 return False
250 return True
251
252 #
253 # Check illegal character
254 #
255 for Rel in ['/', './', '../']:
256 if OrigPath.startswith(Rel):
257 return False
258 for Rel in ['//', '/./', '/../']:
259 if Rel in OrigPath:
260 return False
261 for Rel in ['/.', '/..', '/']:
262 if OrigPath.endswith(Rel):
263 return False
264
265 Path = Path.rstrip('/')
266
267 #
268 # Check relative path
269 #
270 for Word in Path.split('/'):
271 if not IsValidWord(Word):
272 return False
273
274 return True
275
276 ## IsValidInstallPath
277 #
278 # Check if an install path valid or not.
279 #
280 # Absolute path or path starts with '.' or path contains '..' are invalid.
281 #
282 # @param Path: path to be checked
283 #
284 def IsValidInstallPath(Path):
285 if platform.platform().find("Windows") >= 0:
286 if os.path.isabs(Path):
287 return False
288 else:
289 if Path[1:2] == ':':
290 return False
291 if os.path.isabs(Path):
292 return False
293 if Path.startswith('.'):
294 return False
295
296 if Path.find('..') != -1:
297 return False
298
299 return True
300
301
302 ## IsValidCFormatGuid
303 #
304 # Check if GUID format has the from of {8,4,4,{2,2,2,2,2,2,2,2}}
305 #
306 # @param Guid: Guid to be checked
307 #
308 def IsValidCFormatGuid(Guid):
309 #
310 # Valid: { 0xf0b11735, 0x87a0, 0x4193, {0xb2, 0x66, 0x53, 0x8c, 0x38,
311 # 0xaf, 0x48, 0xce }}
312 # Invalid: { 0xf0b11735, 0x87a0, 0x4193, {0xb2, 0x66, 0x53, 0x8c, 0x38,
313 # 0xaf, 0x48, 0xce }} 0x123
314 # Invalid: { 0xf0b1 1735, 0x87a0, 0x4193, {0xb2, 0x66, 0x53, 0x8c, 0x38,
315 # 0xaf, 0x48, 0xce }}
316 #
317 List = ['{', 10, ',', 6, ',', 6, ',{', 4, ',', 4, ',', 4,
318 ',', 4, ',', 4, ',', 4, ',', 4, ',', 4, '}}']
319 Index = 0
320 Value = ''
321 SepValue = ''
322 for Char in Guid:
323 if Char not in '{},\t ':
324 Value += Char
325 continue
326 if Value:
327 try:
328 #
329 # Index may out of bound
330 #
331 if not SepValue or SepValue != List[Index]:
332 return False
333 Index += 1
334 SepValue = ''
335
336 if not Value.startswith('0x') and not Value.startswith('0X'):
337 return False
338
339 #
340 # Index may out of bound
341 #
342 if type(List[Index]) != type(1) or \
343 len(Value) > List[Index] or len(Value) < 3:
344 return False
345
346 #
347 # Check if string can be converted to integer
348 # Throw exception if not
349 #
350 int(Value, 16)
351 except BaseException:
352 #
353 # Exception caught means invalid format
354 #
355 return False
356 Value = ''
357 Index += 1
358 if Char in '{},':
359 SepValue += Char
360
361 return SepValue == '}}' and Value == ''
362
363 ## IsValidPcdType
364 #
365 # Check whether the PCD type is valid
366 #
367 # @param PcdTypeString: The PcdType string need to be checked.
368 #
369 def IsValidPcdType(PcdTypeString):
370 if PcdTypeString.upper() in PCD_USAGE_TYPE_LIST_OF_MODULE:
371 return True
372 else:
373 return False
374
375 ## IsValidWord
376 #
377 # Check whether the word is valid.
378 # <Word> ::= (a-zA-Z0-9_)(a-zA-Z0-9_-){0,} Alphanumeric characters with
379 # optional
380 # dash "-" and/or underscore "_" characters. No whitespace
381 # characters are permitted.
382 #
383 # @param Word: The word string need to be checked.
384 #
385 def IsValidWord(Word):
386 if not Word:
387 return False
388 #
389 # The first char should be alpha, _ or Digit.
390 #
391 if not Word[0].isalnum() and \
392 not Word[0] == '_' and \
393 not Word[0].isdigit():
394 return False
395
396 LastChar = ''
397 for Char in Word[1:]:
398 if (not Char.isalpha()) and \
399 (not Char.isdigit()) and \
400 Char != '-' and \
401 Char != '_' and \
402 Char != '.':
403 return False
404 if Char == '.' and LastChar == '.':
405 return False
406 LastChar = Char
407
408 return True
409
410
411 ## IsValidSimpleWord
412 #
413 # Check whether the SimpleWord is valid.
414 # <SimpleWord> ::= (a-zA-Z0-9)(a-zA-Z0-9_-){0,}
415 # A word that cannot contain a period character.
416 #
417 # @param Word: The word string need to be checked.
418 #
419 def IsValidSimpleWord(Word):
420 ReIsValidSimpleWord = \
421 re.compile(r"^[0-9A-Za-z][0-9A-Za-z\-_]*$", re.DOTALL)
422 Word = Word.strip()
423 if not Word:
424 return False
425
426 if not ReIsValidSimpleWord.match(Word):
427 return False
428
429 return True
430
431 ## IsValidDecVersion
432 #
433 # Check whether the decimal version is valid.
434 # <DecVersion> ::= (0-9){1,} ["." (0-9){1,}]
435 #
436 # @param Word: The word string need to be checked.
437 #
438 def IsValidDecVersion(Word):
439 if Word.find('.') > -1:
440 ReIsValidDecVersion = re.compile(r"[0-9]+\.?[0-9]+$")
441 else:
442 ReIsValidDecVersion = re.compile(r"[0-9]+$")
443 if ReIsValidDecVersion.match(Word) == None:
444 return False
445 return True
446
447 ## IsValidHexVersion
448 #
449 # Check whether the hex version is valid.
450 # <HexVersion> ::= "0x" <Major> <Minor>
451 # <Major> ::= <HexDigit>{4}
452 # <Minor> ::= <HexDigit>{4}
453 #
454 # @param Word: The word string need to be checked.
455 #
456 def IsValidHexVersion(Word):
457 ReIsValidHexVersion = re.compile(r"[0][xX][0-9A-Fa-f]{8}$", re.DOTALL)
458 if ReIsValidHexVersion.match(Word) == None:
459 return False
460
461 return True
462
463 ## IsValidBuildNumber
464 #
465 # Check whether the BUILD_NUMBER is valid.
466 # ["BUILD_NUMBER" "=" <Integer>{1,4} <EOL>]
467 #
468 # @param Word: The BUILD_NUMBER string need to be checked.
469 #
470 def IsValidBuildNumber(Word):
471 ReIsValieBuildNumber = re.compile(r"[0-9]{1,4}$", re.DOTALL)
472 if ReIsValieBuildNumber.match(Word) == None:
473 return False
474
475 return True
476
477 ## IsValidDepex
478 #
479 # Check whether the Depex is valid.
480 #
481 # @param Word: The Depex string need to be checked.
482 #
483 def IsValidDepex(Word):
484 Index = Word.upper().find("PUSH")
485 if Index > -1:
486 return IsValidCFormatGuid(Word[Index+4:].strip())
487
488 ReIsValidCName = re.compile(r"^[A-Za-z_][0-9A-Za-z_\s\.]*$", re.DOTALL)
489 if ReIsValidCName.match(Word) == None:
490 return False
491
492 return True
493
494 ## IsValidNormalizedString
495 #
496 # Check
497 # <NormalizedString> ::= <DblQuote> [{<Word>} {<Space>}]{1,} <DblQuote>
498 # <Space> ::= 0x20
499 #
500 # @param String: string to be checked
501 #
502 def IsValidNormalizedString(String):
503 if String == '':
504 return True
505
506 for Char in String:
507 if Char == '\t':
508 return False
509
510 StringList = GetSplitValueList(String, TAB_SPACE_SPLIT)
511
512 for Item in StringList:
513 if not Item:
514 continue
515 if not IsValidWord(Item):
516 return False
517
518 return True
519
520 ## IsValidIdString
521 #
522 # Check whether the IdString is valid.
523 #
524 # @param IdString: The IdString need to be checked.
525 #
526 def IsValidIdString(String):
527 if IsValidSimpleWord(String.strip()):
528 return True
529
530 if String.strip().startswith('"') and \
531 String.strip().endswith('"'):
532 String = String[1:-1]
533 if String.strip() == "":
534 return True
535 if IsValidNormalizedString(String):
536 return True
537
538 return False
539
540 ## IsValidVersionString
541 #
542 # Check whether the VersionString is valid.
543 # <AsciiString> ::= [ [<WhiteSpace>]{0,} [<AsciiChars>]{0,} ] {0,}
544 # <WhiteSpace> ::= {<Tab>} {<Space>}
545 # <Tab> ::= 0x09
546 # <Space> ::= 0x20
547 # <AsciiChars> ::= (0x21 - 0x7E)
548 #
549 # @param VersionString: The VersionString need to be checked.
550 #
551 def IsValidVersionString(VersionString):
552 VersionString = VersionString.strip()
553 for Char in VersionString:
554 if not (Char >= 0x21 and Char <= 0x7E):
555 return False
556
557 return True
558
559 ## IsValidPcdValue
560 #
561 # Check whether the PcdValue is valid.
562 #
563 # @param VersionString: The PcdValue need to be checked.
564 #
565 def IsValidPcdValue(PcdValue):
566 for Char in PcdValue:
567 if Char == '\n' or Char == '\t' or Char == '\f':
568 return False
569
570 #
571 # <Boolean>
572 #
573 if IsValidFeatureFlagExp(PcdValue, True)[0]:
574 return True
575
576 #
577 # <Number> ::= {<Integer>} {<HexNumber>}
578 # <Integer> ::= {(0-9)} {(1-9)(0-9){1,}}
579 # <HexNumber> ::= "0x" <HexDigit>{1,}
580 # <HexDigit> ::= (a-fA-F0-9)
581 #
582 if IsValidHex(PcdValue):
583 return True
584
585 ReIsValidIntegerSingle = re.compile(r"^\s*[0-9]\s*$", re.DOTALL)
586 if ReIsValidIntegerSingle.match(PcdValue) != None:
587 return True
588
589 ReIsValidIntegerMulti = re.compile(r"^\s*[1-9][0-9]+\s*$", re.DOTALL)
590 if ReIsValidIntegerMulti.match(PcdValue) != None:
591 return True
592
593
594 #
595 # <StringVal> ::= {<StringType>} {<Array>} {"$(" <MACRO> ")"}
596 # <StringType> ::= {<UnicodeString>} {<CString>}
597 #
598 ReIsValidStringType = re.compile(r"^\s*[\"L].*[\"]\s*$")
599 if ReIsValidStringType.match(PcdValue):
600 IsTrue = False
601 if PcdValue.strip().startswith('L\"'):
602 StringValue = PcdValue.strip().lstrip('L\"').rstrip('\"')
603 if IsValidBareCString(StringValue):
604 IsTrue = True
605 elif PcdValue.strip().startswith('\"'):
606 StringValue = PcdValue.strip().lstrip('\"').rstrip('\"')
607 if IsValidBareCString(StringValue):
608 IsTrue = True
609 if IsTrue:
610 return IsTrue
611
612 #
613 # <Array> ::= {<CArray>} {<NList>} {<CFormatGUID>}
614 # <CArray> ::= "{" [<NList>] <CArray>{0,} "}"
615 # <NList> ::= <HexByte> ["," <HexByte>]{0,}
616 # <HexDigit> ::= (a-fA-F0-9)
617 # <HexByte> ::= "0x" <HexDigit>{1,2}
618 #
619 if IsValidCFormatGuid(PcdValue):
620 return True
621
622 ReIsValidByteHex = re.compile(r"^\s*0x[0-9a-fA-F]{1,2}\s*$", re.DOTALL)
623 if PcdValue.strip().startswith('{') and PcdValue.strip().endswith('}') :
624 StringValue = PcdValue.strip().lstrip('{').rstrip('}')
625 ValueList = StringValue.split(',')
626 AllValidFlag = True
627 for ValueItem in ValueList:
628 if not ReIsValidByteHex.match(ValueItem.strip()):
629 AllValidFlag = False
630
631 if AllValidFlag:
632 return True
633
634 #
635 # NList
636 #
637 AllValidFlag = True
638 ValueList = PcdValue.split(',')
639 for ValueItem in ValueList:
640 if not ReIsValidByteHex.match(ValueItem.strip()):
641 AllValidFlag = False
642
643 if AllValidFlag:
644 return True
645
646 return False
647
648 ## IsValidCVariableName
649 #
650 # Check whether the PcdValue is valid.
651 #
652 # @param VersionString: The PcdValue need to be checked.
653 #
654 def IsValidCVariableName(CName):
655 ReIsValidCName = re.compile(r"^[A-Za-z_][0-9A-Za-z_]*$", re.DOTALL)
656 if ReIsValidCName.match(CName) == None:
657 return False
658
659 return True
660
661 ## IsValidIdentifier
662 #
663 # <Identifier> ::= <NonDigit> <Chars>{0,}
664 # <Chars> ::= (a-zA-Z0-9_)
665 # <NonDigit> ::= (a-zA-Z_)
666 #
667 # @param Ident: identifier to be checked
668 #
669 def IsValidIdentifier(Ident):
670 ReIdent = re.compile(r"^[A-Za-z_][0-9A-Za-z_]*$", re.DOTALL)
671 if ReIdent.match(Ident) == None:
672 return False
673
674 return True
675
676 ## IsValidDecVersionVal
677 #
678 # {(0-9){1,} "." (0-99)}
679 #
680 # @param Ver: version to be checked
681 #
682 def IsValidDecVersionVal(Ver):
683 ReVersion = re.compile(r"[0-9]+(\.[0-9]{1,2})$")
684
685 if ReVersion.match(Ver) == None:
686 return False
687
688 return True
689
690
691 ## IsValidLibName
692 #
693 # (A-Z)(a-zA-Z0-9){0,} and could not be "NULL"
694 #
695 def IsValidLibName(LibName):
696 if LibName == 'NULL':
697 return False
698 ReLibName = re.compile("^[A-Z]+[a-zA-Z0-9]*$")
699 if not ReLibName.match(LibName):
700 return False
701
702 return True
703
704 # IsValidUserId
705 #
706 # <UserId> ::= (a-zA-Z)(a-zA-Z0-9_.){0,}
707 # Words that contain period "." must be encapsulated in double quotation marks.
708 #
709 def IsValidUserId(UserId):
710 UserId = UserId.strip()
711 Quoted = False
712 if UserId.startswith('"') and UserId.endswith('"'):
713 Quoted = True
714 UserId = UserId[1:-1]
715 if not UserId or not UserId[0].isalpha():
716 return False
717 for Char in UserId[1:]:
718 if not Char.isalnum() and not Char in '_.':
719 return False
720 if Char == '.' and not Quoted:
721 return False
722 return True
723