1## @file
2# This file is used to provide method for process AsBuilt INF file. It will consumed by InfParser
3#
4# Copyright (c) 2011 - 2018, Intel Corporation. All rights reserved.<BR>
5#
6# SPDX-License-Identifier: BSD-2-Clause-Patent
7'''
8InfAsBuiltProcess
9'''
10## Import modules
11#
12
13import os
14import re
15from Library import GlobalData
16import Logger.Log as Logger
17from Logger import StringTable as ST
18from Logger import ToolError
19
20from Library.StringUtils import GetSplitValueList
21from Library.Misc import GetHelpStringByRemoveHashKey
22from Library.Misc import ValidFile
23from Library.Misc import ProcessLineExtender
24from Library.ParserValidate import IsValidPath
25from Library.Parsing import MacroParser
26from Parser.InfParserMisc import InfExpandMacro
27
28from Library import DataType as DT
29
30## GetLibInstanceInfo
31#
32# Get the information from Library Instance INF file.
33#
34# @param string.  A string start with # and followed by INF file path
35# @param WorkSpace. The WorkSpace directory used to combined with INF file path.
36#
37# @return GUID, Version
38def GetLibInstanceInfo(String, WorkSpace, LineNo, CurrentInfFileName):
39
40    FileGuidString = ""
41    VerString = ""
42
43    OriginalString = String
44    String = String.strip()
45    if not String:
46        return None, None
47    #
48    # Remove "#" characters at the beginning
49    #
50    String = GetHelpStringByRemoveHashKey(String)
51    String = String.strip()
52
53    #
54    # To deal with library instance specified by GUID and version
55    #
56    RegFormatGuidPattern = re.compile("\s*([0-9a-fA-F]){8}-"
57                                       "([0-9a-fA-F]){4}-"
58                                       "([0-9a-fA-F]){4}-"
59                                       "([0-9a-fA-F]){4}-"
60                                       "([0-9a-fA-F]){12}\s*")
61    VersionPattern = re.compile('[\t\s]*\d+(\.\d+)?[\t\s]*')
62    GuidMatchedObj = RegFormatGuidPattern.search(String)
63
64    if String.upper().startswith('GUID') and GuidMatchedObj and 'Version' in String:
65        VersionStr = String[String.upper().find('VERSION') + 8:]
66        VersionMatchedObj = VersionPattern.search(VersionStr)
67        if VersionMatchedObj:
68            Guid = GuidMatchedObj.group().strip()
69            Version = VersionMatchedObj.group().strip()
70            return Guid, Version
71
72    #
73    # To deal with library instance specified by file name
74    #
75    FileLinesList = GetFileLineContent(String, WorkSpace, LineNo, OriginalString)
76
77
78    ReFindFileGuidPattern = re.compile("^\s*FILE_GUID\s*=.*$")
79    ReFindVerStringPattern = re.compile("^\s*VERSION_STRING\s*=.*$")
80
81    for Line in FileLinesList:
82        if ReFindFileGuidPattern.match(Line):
83            FileGuidString = Line
84        if ReFindVerStringPattern.match(Line):
85            VerString = Line
86
87    if FileGuidString:
88        FileGuidString = GetSplitValueList(FileGuidString, '=', 1)[1]
89    if VerString:
90        VerString = GetSplitValueList(VerString, '=', 1)[1]
91
92    return FileGuidString, VerString
93
94## GetPackageListInfo
95#
96# Get the package information from INF file.
97#
98# @param string.  A string start with # and followed by INF file path
99# @param WorkSpace. The WorkSpace directory used to combined with INF file path.
100#
101# @return GUID, Version
102def GetPackageListInfo(FileNameString, WorkSpace, LineNo):
103    PackageInfoList = []
104    DefineSectionMacros = {}
105    PackageSectionMacros = {}
106
107    FileLinesList = GetFileLineContent(FileNameString, WorkSpace, LineNo, '')
108
109    RePackageHeader = re.compile('^\s*\[Packages.*\].*$')
110    ReDefineHeader = re.compile('^\s*\[Defines].*$')
111
112    PackageHederFlag = False
113    DefineHeaderFlag = False
114    LineNo = -1
115    for Line in FileLinesList:
116        LineNo += 1
117        Line = Line.strip()
118
119        if Line.startswith('['):
120            PackageHederFlag = False
121            DefineHeaderFlag = False
122
123        if Line.startswith("#"):
124            continue
125
126        if not Line:
127            continue
128
129        #
130        # Found [Packages] section
131        #
132        if RePackageHeader.match(Line):
133            PackageHederFlag = True
134            continue
135
136        #
137        # Found [Define] section
138        #
139        if ReDefineHeader.match(Line):
140            DefineHeaderFlag = True
141            continue
142
143        if DefineHeaderFlag:
144            #
145            # Find Macro
146            #
147            Name, Value = MacroParser((Line, LineNo),
148                                      FileNameString,
149                                      DT.MODEL_META_DATA_HEADER,
150                                      DefineSectionMacros)
151
152            if Name is not None:
153                DefineSectionMacros[Name] = Value
154                continue
155
156        if PackageHederFlag:
157
158            #
159            # Find Macro
160            #
161            Name, Value = MacroParser((Line, LineNo),
162                                      FileNameString,
163                                      DT.MODEL_META_DATA_PACKAGE,
164                                      DefineSectionMacros)
165            if Name is not None:
166                PackageSectionMacros[Name] = Value
167                continue
168
169            #
170            # Replace with Local section Macro and [Defines] section Macro.
171            #
172            Line = InfExpandMacro(Line, (FileNameString, Line, LineNo), DefineSectionMacros, PackageSectionMacros, True)
173
174            Line = GetSplitValueList(Line, "#", 1)[0]
175            Line = GetSplitValueList(Line, "|", 1)[0]
176            PackageInfoList.append(Line)
177
178    return PackageInfoList
179
180def GetFileLineContent(FileName, WorkSpace, LineNo, OriginalString):
181
182    if not LineNo:
183        LineNo = -1
184
185    #
186    # Validate file name exist.
187    #
188    FullFileName = os.path.normpath(os.path.realpath(os.path.join(WorkSpace, FileName)))
189    if not (ValidFile(FullFileName)):
190        return []
191
192    #
193    # Validate file exist/format.
194    #
195    if not IsValidPath(FileName, WorkSpace):
196        return []
197
198    FileLinesList = []
199
200    try:
201        FullFileName = FullFileName.replace('\\', '/')
202        Inputfile = open(FullFileName, "r")
203        try:
204            FileLinesList = Inputfile.readlines()
205        except BaseException:
206            Logger.Error("InfParser", ToolError.FILE_READ_FAILURE, ST.ERR_FILE_OPEN_FAILURE, File=FullFileName)
207        finally:
208            Inputfile.close()
209    except BaseException:
210        Logger.Error("InfParser",
211                     ToolError.FILE_READ_FAILURE,
212                     ST.ERR_FILE_OPEN_FAILURE,
213                     File=FullFileName)
214
215    FileLinesList = ProcessLineExtender(FileLinesList)
216
217    return FileLinesList
218
219##
220# Get all INF files from current workspace
221#
222#
223def GetInfsFromWorkSpace(WorkSpace):
224    InfFiles = []
225    for top, dirs, files in os.walk(WorkSpace):
226        dirs = dirs # just for pylint
227        for File in files:
228            if File.upper().endswith(".INF"):
229                InfFiles.append(os.path.join(top, File))
230
231    return InfFiles
232
233##
234# Get GUID and version from library instance file
235#
236#
237def GetGuidVerFormLibInstance(Guid, Version, WorkSpace, CurrentInfFileName):
238    for InfFile in GetInfsFromWorkSpace(WorkSpace):
239        try:
240            if InfFile.strip().upper() == CurrentInfFileName.strip().upper():
241                continue
242            InfFile = InfFile.replace('\\', '/')
243            if InfFile not in GlobalData.gLIBINSTANCEDICT:
244                InfFileObj = open(InfFile, "r")
245                GlobalData.gLIBINSTANCEDICT[InfFile] = InfFileObj
246            else:
247                InfFileObj = GlobalData.gLIBINSTANCEDICT[InfFile]
248
249        except BaseException:
250            Logger.Error("InfParser",
251                         ToolError.FILE_READ_FAILURE,
252                         ST.ERR_FILE_OPEN_FAILURE,
253                         File=InfFile)
254        try:
255            FileLinesList = InfFileObj.readlines()
256            FileLinesList = ProcessLineExtender(FileLinesList)
257
258            ReFindFileGuidPattern = re.compile("^\s*FILE_GUID\s*=.*$")
259            ReFindVerStringPattern = re.compile("^\s*VERSION_STRING\s*=.*$")
260
261            for Line in FileLinesList:
262                if ReFindFileGuidPattern.match(Line):
263                    FileGuidString = Line
264                if ReFindVerStringPattern.match(Line):
265                    VerString = Line
266
267            if FileGuidString:
268                FileGuidString = GetSplitValueList(FileGuidString, '=', 1)[1]
269            if VerString:
270                VerString = GetSplitValueList(VerString, '=', 1)[1]
271
272            if FileGuidString.strip().upper() == Guid.upper() and \
273                VerString.strip().upper() == Version.upper():
274                return Guid, Version
275
276        except BaseException:
277            Logger.Error("InfParser", ToolError.FILE_READ_FAILURE, ST.ERR_FILE_OPEN_FAILURE, File=InfFile)
278        finally:
279            InfFileObj.close()
280
281    return '', ''
282
283
284