## @file # Common routines used by all tools # # Copyright (c) 2011 - 2019, Intel Corporation. All rights reserved.
# # SPDX-License-Identifier: BSD-2-Clause-Patent # ''' Misc ''' ## # Import Modules # import os.path from os import access from os import F_OK from os import makedirs from os import getcwd from os import chdir from os import listdir from os import remove from os import rmdir from os import linesep from os import walk from os import environ import re from collections import OrderedDict as Sdict import Logger.Log as Logger from Logger import StringTable as ST from Logger import ToolError from Library import GlobalData from Library.DataType import SUP_MODULE_LIST from Library.DataType import END_OF_LINE from Library.DataType import TAB_SPLIT from Library.DataType import TAB_LANGUAGE_EN_US from Library.DataType import TAB_LANGUAGE_EN from Library.DataType import TAB_LANGUAGE_EN_X from Library.DataType import TAB_UNI_FILE_SUFFIXS from Library.StringUtils import GetSplitValueList from Library.ParserValidate import IsValidHexVersion from Library.ParserValidate import IsValidPath from Object.POM.CommonObject import TextObject from Core.FileHook import __FileHookOpen__ from Common.MultipleWorkspace import MultipleWorkspace as mws ## Convert GUID string in xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx style to C # structure style # # @param Guid: The GUID string # def GuidStringToGuidStructureString(Guid): GuidList = Guid.split('-') Result = '{' for Index in range(0, 3, 1): Result = Result + '0x' + GuidList[Index] + ', ' Result = Result + '{0x' + GuidList[3][0:2] + ', 0x' + GuidList[3][2:4] for Index in range(0, 12, 2): Result = Result + ', 0x' + GuidList[4][Index:Index + 2] Result += '}}' return Result ## Check whether GUID string is of format xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx # # @param GuidValue: The GUID value # def CheckGuidRegFormat(GuidValue): ## Regular expression used to find out register format of GUID # RegFormatGuidPattern = re.compile("^\s*([0-9a-fA-F]){8}-" "([0-9a-fA-F]){4}-" "([0-9a-fA-F]){4}-" "([0-9a-fA-F]){4}-" "([0-9a-fA-F]){12}\s*$") if RegFormatGuidPattern.match(GuidValue): return True else: return False ## Convert GUID string in C structure style to # xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx # # @param GuidValue: The GUID value in C structure format # def GuidStructureStringToGuidString(GuidValue): GuidValueString = GuidValue.lower().replace("{", "").replace("}", "").\ replace(" ", "").replace(";", "") GuidValueList = GuidValueString.split(",") if len(GuidValueList) != 11: return '' try: return "%08x-%04x-%04x-%02x%02x-%02x%02x%02x%02x%02x%02x" % ( int(GuidValueList[0], 16), int(GuidValueList[1], 16), int(GuidValueList[2], 16), int(GuidValueList[3], 16), int(GuidValueList[4], 16), int(GuidValueList[5], 16), int(GuidValueList[6], 16), int(GuidValueList[7], 16), int(GuidValueList[8], 16), int(GuidValueList[9], 16), int(GuidValueList[10], 16) ) except BaseException: return '' ## Create directories # # @param Directory: The directory name # def CreateDirectory(Directory): if Directory is None or Directory.strip() == "": return True try: if not access(Directory, F_OK): makedirs(Directory) except BaseException: return False return True ## Remove directories, including files and sub-directories in it # # @param Directory: The directory name # def RemoveDirectory(Directory, Recursively=False): if Directory is None or Directory.strip() == "" or not \ os.path.exists(Directory): return if Recursively: CurrentDirectory = getcwd() chdir(Directory) for File in listdir("."): if os.path.isdir(File): RemoveDirectory(File, Recursively) else: remove(File) chdir(CurrentDirectory) rmdir(Directory) ## Store content in file # # This method is used to save file only when its content is changed. This is # quite useful for "make" system to decide what will be re-built and what # won't. # # @param File: The path of file # @param Content: The new content of the file # @param IsBinaryFile: The flag indicating if the file is binary file # or not # def SaveFileOnChange(File, Content, IsBinaryFile=True): if os.path.exists(File): if IsBinaryFile: try: if Content == __FileHookOpen__(File, "rb").read(): return False except BaseException: Logger.Error(None, ToolError.FILE_OPEN_FAILURE, ExtraData=File) else: try: if Content == __FileHookOpen__(File, "r").read(): return False except BaseException: Logger.Error(None, ToolError.FILE_OPEN_FAILURE, ExtraData=File) CreateDirectory(os.path.dirname(File)) if IsBinaryFile: try: FileFd = __FileHookOpen__(File, "wb") FileFd.write(Content) FileFd.close() except BaseException: Logger.Error(None, ToolError.FILE_CREATE_FAILURE, ExtraData=File) else: try: FileFd = __FileHookOpen__(File, "w") FileFd.write(Content) FileFd.close() except BaseException: Logger.Error(None, ToolError.FILE_CREATE_FAILURE, ExtraData=File) return True ## Get all files of a directory # # @param Root: Root dir # @param SkipList : The files need be skipped # def GetFiles(Root, SkipList=None, FullPath=True): OriPath = os.path.normpath(Root) FileList = [] for Root, Dirs, Files in walk(Root): if SkipList: for Item in SkipList: if Item in Dirs: Dirs.remove(Item) if Item in Files: Files.remove(Item) for Dir in Dirs: if Dir.startswith('.'): Dirs.remove(Dir) for File in Files: if File.startswith('.'): continue File = os.path.normpath(os.path.join(Root, File)) if not FullPath: File = File[len(OriPath) + 1:] FileList.append(File) return FileList ## Get all non-metadata files of a directory # # @param Root: Root Dir # @param SkipList : List of path need be skipped # @param FullPath: True if the returned file should be full path # @param PrefixPath: the path that need to be added to the files found # @return: the list of files found # def GetNonMetaDataFiles(Root, SkipList, FullPath, PrefixPath): FileList = GetFiles(Root, SkipList, FullPath) NewFileList = [] for File in FileList: ExtName = os.path.splitext(File)[1] # # skip '.dec', '.inf', '.dsc', '.fdf' files # if ExtName.lower() not in ['.dec', '.inf', '.dsc', '.fdf']: NewFileList.append(os.path.normpath(os.path.join(PrefixPath, File))) return NewFileList ## Check if given file exists or not # # @param File: File name or path to be checked # @param Dir: The directory the file is relative to # def ValidFile(File, Ext=None): File = File.replace('\\', '/') if Ext is not None: FileExt = os.path.splitext(File)[1] if FileExt.lower() != Ext.lower(): return False if not os.path.exists(File): return False return True ## RealPath # # @param File: File name or path to be checked # @param Dir: The directory the file is relative to # @param OverrideDir: The override directory # def RealPath(File, Dir='', OverrideDir=''): NewFile = os.path.normpath(os.path.join(Dir, File)) NewFile = GlobalData.gALL_FILES[NewFile] if not NewFile and OverrideDir: NewFile = os.path.normpath(os.path.join(OverrideDir, File)) NewFile = GlobalData.gALL_FILES[NewFile] return NewFile ## RealPath2 # # @param File: File name or path to be checked # @param Dir: The directory the file is relative to # @param OverrideDir: The override directory # def RealPath2(File, Dir='', OverrideDir=''): if OverrideDir: NewFile = GlobalData.gALL_FILES[os.path.normpath(os.path.join\ (OverrideDir, File))] if NewFile: if OverrideDir[-1] == os.path.sep: return NewFile[len(OverrideDir):], NewFile[0:len(OverrideDir)] else: return NewFile[len(OverrideDir) + 1:], \ NewFile[0:len(OverrideDir)] NewFile = GlobalData.gALL_FILES[os.path.normpath(os.path.join(Dir, File))] if NewFile: if Dir: if Dir[-1] == os.path.sep: return NewFile[len(Dir):], NewFile[0:len(Dir)] else: return NewFile[len(Dir) + 1:], NewFile[0:len(Dir)] else: return NewFile, '' return None, None ## CommonPath # # @param PathList: PathList # def CommonPath(PathList): Path1 = min(PathList).split(os.path.sep) Path2 = max(PathList).split(os.path.sep) for Index in range(min(len(Path1), len(Path2))): if Path1[Index] != Path2[Index]: return os.path.sep.join(Path1[:Index]) return os.path.sep.join(Path1) ## PathClass # class PathClass(object): def __init__(self, File='', Root='', AlterRoot='', Type='', IsBinary=False, Arch='COMMON', ToolChainFamily='', Target='', TagName='', \ ToolCode=''): self.Arch = Arch self.File = str(File) if os.path.isabs(self.File): self.Root = '' self.AlterRoot = '' else: self.Root = str(Root) self.AlterRoot = str(AlterRoot) # # Remove any '.' and '..' in path # if self.Root: self.Path = os.path.normpath(os.path.join(self.Root, self.File)) self.Root = os.path.normpath(CommonPath([self.Root, self.Path])) # # eliminate the side-effect of 'C:' # if self.Root[-1] == ':': self.Root += os.path.sep # # file path should not start with path separator # if self.Root[-1] == os.path.sep: self.File = self.Path[len(self.Root):] else: self.File = self.Path[len(self.Root) + 1:] else: self.Path = os.path.normpath(self.File) self.SubDir, self.Name = os.path.split(self.File) self.BaseName, self.Ext = os.path.splitext(self.Name) if self.Root: if self.SubDir: self.Dir = os.path.join(self.Root, self.SubDir) else: self.Dir = self.Root else: self.Dir = self.SubDir if IsBinary: self.Type = Type else: self.Type = self.Ext.lower() self.IsBinary = IsBinary self.Target = Target self.TagName = TagName self.ToolCode = ToolCode self.ToolChainFamily = ToolChainFamily self._Key = None ## Convert the object of this class to a string # # Convert member Path of the class to a string # def __str__(self): return self.Path ## Override __eq__ function # # Check whether PathClass are the same # def __eq__(self, Other): if isinstance(Other, type(self)): return self.Path == Other.Path else: return self.Path == str(Other) ## Override __hash__ function # # Use Path as key in hash table # def __hash__(self): return hash(self.Path) ## _GetFileKey # def _GetFileKey(self): if self._Key is None: self._Key = self.Path.upper() return self._Key ## Validate # def Validate(self, Type='', CaseSensitive=True): if GlobalData.gCASE_INSENSITIVE: CaseSensitive = False if Type and Type.lower() != self.Type: return ToolError.FILE_TYPE_MISMATCH, '%s (expect %s but got %s)' % \ (self.File, Type, self.Type) RealFile, RealRoot = RealPath2(self.File, self.Root, self.AlterRoot) if not RealRoot and not RealFile: RealFile = self.File if self.AlterRoot: RealFile = os.path.join(self.AlterRoot, self.File) elif self.Root: RealFile = os.path.join(self.Root, self.File) return ToolError.FILE_NOT_FOUND, os.path.join(self.AlterRoot, RealFile) ErrorCode = 0 ErrorInfo = '' if RealRoot != self.Root or RealFile != self.File: if CaseSensitive and (RealFile != self.File or \ (RealRoot != self.Root and RealRoot != \ self.AlterRoot)): ErrorCode = ToolError.FILE_CASE_MISMATCH ErrorInfo = self.File + '\n\t' + RealFile + \ " [in file system]" self.SubDir, self.Name = os.path.split(RealFile) self.BaseName, self.Ext = os.path.splitext(self.Name) if self.SubDir: self.Dir = os.path.join(RealRoot, self.SubDir) else: self.Dir = RealRoot self.File = RealFile self.Root = RealRoot self.Path = os.path.join(RealRoot, RealFile) return ErrorCode, ErrorInfo Key = property(_GetFileKey) ## Get current workspace # # get WORKSPACE from environment variable if present,if not use current working directory as WORKSPACE # def GetWorkspace(): # # check WORKSPACE # if "WORKSPACE" in environ: WorkspaceDir = os.path.normpath(environ["WORKSPACE"]) if not os.path.exists(WorkspaceDir): Logger.Error("UPT", ToolError.UPT_ENVIRON_MISSING_ERROR, ST.ERR_WORKSPACE_NOTEXIST, ExtraData="%s" % WorkspaceDir) else: WorkspaceDir = os.getcwd() if WorkspaceDir[-1] == ':': WorkspaceDir += os.sep PackagesPath = os.environ.get("PACKAGES_PATH") mws.setWs(WorkspaceDir, PackagesPath) return WorkspaceDir, mws.PACKAGES_PATH ## Get relative path # # use full path and workspace to get relative path # the destination of this function is mainly to resolve the root path issue(like c: or c:\) # # @param Fullpath: a string of fullpath # @param Workspace: a string of workspace # def GetRelativePath(Fullpath, Workspace): RelativePath = '' if Workspace.endswith(os.sep): RelativePath = Fullpath[Fullpath.upper().find(Workspace.upper())+len(Workspace):] else: RelativePath = Fullpath[Fullpath.upper().find(Workspace.upper())+len(Workspace)+1:] return RelativePath ## Check whether all module types are in list # # check whether all module types (SUP_MODULE_LIST) are in list # # @param ModuleList: a list of ModuleType # def IsAllModuleList(ModuleList): NewModuleList = [Module.upper() for Module in ModuleList] for Module in SUP_MODULE_LIST: if Module not in NewModuleList: return False else: return True ## Dictionary that use comment(GenericComment, TailComment) as value, # if a new comment which key already in the dic is inserted, then the # comment will be merged. # Key is (Statement, SupArch), when TailComment is added, it will ident # according to Statement # class MergeCommentDict(dict): ## []= operator # def __setitem__(self, Key, CommentVal): GenericComment, TailComment = CommentVal if Key in self: OrigVal1, OrigVal2 = dict.__getitem__(self, Key) Statement = Key[0] dict.__setitem__(self, Key, (OrigVal1 + GenericComment, OrigVal2 \ + len(Statement) * ' ' + TailComment)) else: dict.__setitem__(self, Key, (GenericComment, TailComment)) ## =[] operator # def __getitem__(self, Key): return dict.__getitem__(self, Key) ## GenDummyHelpTextObj # # @retval HelpTxt: Generated dummy help text object # def GenDummyHelpTextObj(): HelpTxt = TextObject() HelpTxt.SetLang(TAB_LANGUAGE_EN_US) HelpTxt.SetString(' ') return HelpTxt ## ConvertVersionToDecimal, the minor version should be within 0 - 99 # ::= "0x" # ::= (a-fA-F0-9){4} # ::= (a-fA-F0-9){4} # ::= (0-65535) ["." (0-99)] # # @param StringIn: The string contains version defined in INF file. # It can be Decimal or Hex # def ConvertVersionToDecimal(StringIn): if IsValidHexVersion(StringIn): Value = int(StringIn, 16) Major = Value >> 16 Minor = Value & 0xFFFF MinorStr = str(Minor) if len(MinorStr) == 1: MinorStr = '0' + MinorStr return str(Major) + '.' + MinorStr else: if StringIn.find(TAB_SPLIT) != -1: return StringIn elif StringIn: return StringIn + '.0' else: # # when StringIn is '', return it directly # return StringIn ## GetHelpStringByRemoveHashKey # # Remove hash key at the header of string and return the remain. # # @param String: The string need to be processed. # def GetHelpStringByRemoveHashKey(String): ReturnString = '' PattenRemoveHashKey = re.compile(r"^[#+\s]+", re.DOTALL) String = String.strip() if String == '': return String LineList = GetSplitValueList(String, END_OF_LINE) for Line in LineList: ValueList = PattenRemoveHashKey.split(Line) if len(ValueList) == 1: ReturnString += ValueList[0] + END_OF_LINE else: ReturnString += ValueList[1] + END_OF_LINE if ReturnString.endswith('\n') and not ReturnString.endswith('\n\n') and ReturnString != '\n': ReturnString = ReturnString[:-1] return ReturnString ## ConvPathFromAbsToRel # # Get relative file path from absolute path. # # @param Path: The string contain file absolute path. # @param Root: The string contain the parent path of Path in. # # def ConvPathFromAbsToRel(Path, Root): Path = os.path.normpath(Path) Root = os.path.normpath(Root) FullPath = os.path.normpath(os.path.join(Root, Path)) # # If Path is absolute path. # It should be in Root. # if os.path.isabs(Path): return FullPath[FullPath.find(Root) + len(Root) + 1:] else: return Path ## ConvertPath # # Convert special characters to '_', '\' to '/' # return converted path: Test!1.inf -> Test_1.inf # # @param Path: Path to be converted # def ConvertPath(Path): RetPath = '' for Char in Path.strip(): if Char.isalnum() or Char in '.-_/': RetPath = RetPath + Char elif Char == '\\': RetPath = RetPath + '/' else: RetPath = RetPath + '_' return RetPath ## ConvertSpec # # during install, convert the Spec string extract from UPD into INF allowable definition, # the difference is period is allowed in the former (not the first letter) but not in the latter. # return converted Spec string # # @param SpecStr: SpecStr to be converted # def ConvertSpec(SpecStr): RetStr = '' for Char in SpecStr: if Char.isalnum() or Char == '_': RetStr = RetStr + Char else: RetStr = RetStr + '_' return RetStr ## IsEqualList # # Judge two lists are identical(contain same item). # The rule is elements in List A are in List B and elements in List B are in List A. # # @param ListA, ListB Lists need to be judged. # # @return True ListA and ListB are identical # @return False ListA and ListB are different with each other # def IsEqualList(ListA, ListB): if ListA == ListB: return True for ItemA in ListA: if not ItemA in ListB: return False for ItemB in ListB: if not ItemB in ListA: return False return True ## ConvertArchList # # Convert item in ArchList if the start character is lower case. # In UDP spec, Arch is only allowed as: [A-Z]([a-zA-Z0-9])* # # @param ArchList The ArchList need to be converted. # # @return NewList The ArchList been converted. # def ConvertArchList(ArchList): NewArchList = [] if not ArchList: return NewArchList if isinstance(ArchList, list): for Arch in ArchList: Arch = Arch.upper() NewArchList.append(Arch) elif isinstance(ArchList, str): ArchList = ArchList.upper() NewArchList.append(ArchList) return NewArchList ## ProcessLineExtender # # Process the LineExtender of Line in LineList. # If one line ends with a line extender, then it will be combined together with next line. # # @param LineList The LineList need to be processed. # # @return NewList The ArchList been processed. # def ProcessLineExtender(LineList): NewList = [] Count = 0 while Count < len(LineList): if LineList[Count].strip().endswith("\\") and Count + 1 < len(LineList): NewList.append(LineList[Count].strip()[:-2] + LineList[Count + 1]) Count = Count + 1 else: NewList.append(LineList[Count]) Count = Count + 1 return NewList ## ProcessEdkComment # # Process EDK style comment in LineList: c style /* */ comment or cpp style // comment # # # @param LineList The LineList need to be processed. # # @return LineList The LineList been processed. # @return FirstPos Where Edk comment is first found, -1 if not found # def ProcessEdkComment(LineList): FindEdkBlockComment = False Count = 0 StartPos = -1 EndPos = -1 FirstPos = -1 while(Count < len(LineList)): Line = LineList[Count].strip() if Line.startswith("/*"): # # handling c style comment # StartPos = Count while Count < len(LineList): Line = LineList[Count].strip() if Line.endswith("*/"): if (Count == StartPos) and Line.strip() == '/*/': Count = Count + 1 continue EndPos = Count FindEdkBlockComment = True break Count = Count + 1 if FindEdkBlockComment: if FirstPos == -1: FirstPos = StartPos for Index in range(StartPos, EndPos+1): LineList[Index] = '' FindEdkBlockComment = False elif Line.find("//") != -1 and not Line.startswith("#"): # # handling cpp style comment # LineList[Count] = Line.replace("//", '#') if FirstPos == -1: FirstPos = Count Count = Count + 1 return LineList, FirstPos ## GetLibInstanceInfo # # Get the information from Library Instance INF file. # # @param string. A string start with # and followed by INF file path # @param WorkSpace. The WorkSpace directory used to combined with INF file path. # # @return GUID, Version def GetLibInstanceInfo(String, WorkSpace, LineNo): FileGuidString = "" VerString = "" OriginalString = String String = String.strip() if not String: return None, None # # Remove "#" characters at the beginning # String = GetHelpStringByRemoveHashKey(String) String = String.strip() # # Validate file name exist. # FullFileName = os.path.normpath(os.path.realpath(os.path.join(WorkSpace, String))) if not (ValidFile(FullFileName)): Logger.Error("InfParser", ToolError.FORMAT_INVALID, ST.ERR_FILELIST_EXIST % (String), File=GlobalData.gINF_MODULE_NAME, Line=LineNo, ExtraData=OriginalString) # # Validate file exist/format. # if IsValidPath(String, WorkSpace): IsValidFileFlag = True else: Logger.Error("InfParser", ToolError.FORMAT_INVALID, ST.ERR_INF_PARSER_FILE_NOT_EXIST_OR_NAME_INVALID % (String), File=GlobalData.gINF_MODULE_NAME, Line=LineNo, ExtraData=OriginalString) return False if IsValidFileFlag: FileLinesList = [] try: FInputfile = open(FullFileName, "r") try: FileLinesList = FInputfile.readlines() except BaseException: Logger.Error("InfParser", ToolError.FILE_READ_FAILURE, ST.ERR_FILE_OPEN_FAILURE, File=FullFileName) finally: FInputfile.close() except BaseException: Logger.Error("InfParser", ToolError.FILE_READ_FAILURE, ST.ERR_FILE_OPEN_FAILURE, File=FullFileName) ReFileGuidPattern = re.compile("^\s*FILE_GUID\s*=.*$") ReVerStringPattern = re.compile("^\s*VERSION_STRING\s*=.*$") FileLinesList = ProcessLineExtender(FileLinesList) for Line in FileLinesList: if ReFileGuidPattern.match(Line): FileGuidString = Line if ReVerStringPattern.match(Line): VerString = Line if FileGuidString: FileGuidString = GetSplitValueList(FileGuidString, '=', 1)[1] if VerString: VerString = GetSplitValueList(VerString, '=', 1)[1] return FileGuidString, VerString ## GetLocalValue # # Generate the local value for INF and DEC file. If Lang attribute not present, then use this value. # If present, and there is no element without the Lang attribute, and one of the elements has the rfc1766 code is # "en-x-tianocore", or "en-US" if "en-x-tianocore" was not found, or "en" if "en-US" was not found, or startswith 'en' # if 'en' was not found, then use this value. # If multiple entries of a tag exist which have the same language code, use the last entry. # # @param ValueList A list need to be processed. # @param UseFirstValue: True to use the first value, False to use the last value # # @return LocalValue def GetLocalValue(ValueList, UseFirstValue=False): Value1 = '' Value2 = '' Value3 = '' Value4 = '' Value5 = '' for (Key, Value) in ValueList: if Key == TAB_LANGUAGE_EN_X: if UseFirstValue: if not Value1: Value1 = Value else: Value1 = Value if Key == TAB_LANGUAGE_EN_US: if UseFirstValue: if not Value2: Value2 = Value else: Value2 = Value if Key == TAB_LANGUAGE_EN: if UseFirstValue: if not Value3: Value3 = Value else: Value3 = Value if Key.startswith(TAB_LANGUAGE_EN): if UseFirstValue: if not Value4: Value4 = Value else: Value4 = Value if Key == '': if UseFirstValue: if not Value5: Value5 = Value else: Value5 = Value if Value1: return Value1 if Value2: return Value2 if Value3: return Value3 if Value4: return Value4 if Value5: return Value5 return '' ## GetCharIndexOutStr # # Get comment character index outside a string # # @param Line: The string to be checked # @param CommentCharacter: Comment char, used to ignore comment content # # @retval Index # def GetCharIndexOutStr(CommentCharacter, Line): # # remove whitespace # Line = Line.strip() # # Check whether comment character is in a string # InString = False for Index in range(0, len(Line)): if Line[Index] == '"': InString = not InString elif Line[Index] == CommentCharacter and InString : pass elif Line[Index] == CommentCharacter and (Index +1) < len(Line) and Line[Index+1] == CommentCharacter \ and not InString : return Index return -1 ## ValidateUNIFilePath # # Check the UNI file path # # @param FilePath: The UNI file path # def ValidateUNIFilePath(Path): Suffix = Path[Path.rfind(TAB_SPLIT):] # # Check if the suffix is one of the '.uni', '.UNI', '.Uni' # if Suffix not in TAB_UNI_FILE_SUFFIXS: Logger.Error("Unicode File Parser", ToolError.FORMAT_INVALID, Message=ST.ERR_UNI_FILE_SUFFIX_WRONG, ExtraData=Path) # # Check if '..' in the file name(without suffix) # if (TAB_SPLIT + TAB_SPLIT) in Path: Logger.Error("Unicode File Parser", ToolError.FORMAT_INVALID, Message=ST.ERR_UNI_FILE_NAME_INVALID, ExtraData=Path) # # Check if the file name is valid according to the DEC and INF specification # Pattern = '[a-zA-Z0-9_][a-zA-Z0-9_\-\.]*' FileName = Path.replace(Suffix, '') InvalidCh = re.sub(Pattern, '', FileName) if InvalidCh: Logger.Error("Unicode File Parser", ToolError.FORMAT_INVALID, Message=ST.ERR_INF_PARSER_FILE_NOT_EXIST_OR_NAME_INVALID, ExtraData=Path)