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