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