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