Home | History | Annotate | Download | only in Library
      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) == 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) == 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) == 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]) == None:
    203         return False
    204     
    205     if ReIsValidBuildOption1.match(ToolOptionList[1]) == None:
    206         return False
    207     
    208     if ReIsValidBuildOption2.match(ToolOptionList[2]) == 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) == 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) == 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) == 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) == 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) != None:
    589         return True
    590     
    591     ReIsValidIntegerMulti = re.compile(r"^\s*[1-9][0-9]+\s*$", re.DOTALL)   
    592     if ReIsValidIntegerMulti.match(PcdValue) != 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) == 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) == 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) == 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
    734