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