1## @file
2# This file is used to parse meta files
3#
4# Copyright (c) 2008 - 2018, Intel Corporation. All rights reserved.<BR>
5# SPDX-License-Identifier: BSD-2-Clause-Patent
6#
7
8##
9# Import Modules
10#
11from __future__ import absolute_import
12import Common.LongFilePathOs as os
13import re
14import time
15import copy
16
17import Common.EdkLogger as EdkLogger
18import Common.GlobalData as GlobalData
19import Ecc.EccGlobalData as EccGlobalData
20import Ecc.EccToolError as EccToolError
21
22from CommonDataClass.DataClass import *
23from Common.DataType import *
24from Common.StringUtils import *
25from Common.Misc import GuidStructureStringToGuidString, CheckPcdDatum, PathClass, AnalyzePcdData
26from Common.Expression import *
27from CommonDataClass.Exceptions import *
28
29from Ecc.MetaFileWorkspace.MetaFileTable import MetaFileStorage
30from GenFds.FdfParser import FdfParser
31from Common.LongFilePathSupport import OpenLongFilePath as open
32from Common.LongFilePathSupport import CodecOpenLongFilePath
33
34## A decorator used to parse macro definition
35def ParseMacro(Parser):
36    def MacroParser(self):
37        Match = GlobalData.gMacroDefPattern.match(self._CurrentLine)
38        if not Match:
39            # Not 'DEFINE/EDK_GLOBAL' statement, call decorated method
40            Parser(self)
41            return
42
43        TokenList = GetSplitValueList(self._CurrentLine[Match.end(1):], TAB_EQUAL_SPLIT, 1)
44        # Syntax check
45        if not TokenList[0]:
46            EdkLogger.error('Parser', FORMAT_INVALID, "No macro name given",
47                            ExtraData=self._CurrentLine, File=self.MetaFile, Line=self._LineIndex+1)
48        if len(TokenList) < 2:
49            TokenList.append('')
50
51        Type = Match.group(1)
52        Name, Value = TokenList
53        # Global macros can be only defined via environment variable
54        if Name in GlobalData.gGlobalDefines:
55            EdkLogger.error('Parser', FORMAT_INVALID, "%s can only be defined via environment variable" % Name,
56                            ExtraData=self._CurrentLine, File=self.MetaFile, Line=self._LineIndex+1)
57        # Only upper case letters, digit and '_' are allowed
58        if not GlobalData.gMacroNamePattern.match(Name):
59            EdkLogger.error('Parser', FORMAT_INVALID, "The macro name must be in the pattern [A-Z][A-Z0-9_]*",
60                            ExtraData=self._CurrentLine, File=self.MetaFile, Line=self._LineIndex+1)
61
62        Value = ReplaceMacro(Value, self._Macros)
63        self._ItemType = MODEL_META_DATA_DEFINE
64        # DEFINE defined macros
65        if Type == TAB_DSC_DEFINES_DEFINE:
66            if isinstance(self, DecParser):
67                if MODEL_META_DATA_HEADER in self._SectionType:
68                    self._FileLocalMacros[Name] = Value
69                else:
70                    for Scope in self._Scope:
71                        self._SectionsMacroDict.setdefault((Scope[2], Scope[0], Scope[1]), {})[Name] = Value
72            elif self._SectionType == MODEL_META_DATA_HEADER:
73                self._FileLocalMacros[Name] = Value
74            else:
75                SectionDictKey = self._SectionType, self._Scope[0][0], self._Scope[0][1]
76                if SectionDictKey not in self._SectionsMacroDict:
77                    self._SectionsMacroDict[SectionDictKey] = {}
78                SectionLocalMacros = self._SectionsMacroDict[SectionDictKey]
79                SectionLocalMacros[Name] = Value
80        # EDK_GLOBAL defined macros
81        elif not isinstance(self, DscParser):
82            EdkLogger.error('Parser', FORMAT_INVALID, "EDK_GLOBAL can only be used in .dsc file",
83                            ExtraData=self._CurrentLine, File=self.MetaFile, Line=self._LineIndex+1)
84        elif self._SectionType != MODEL_META_DATA_HEADER:
85            EdkLogger.error('Parser', FORMAT_INVALID, "EDK_GLOBAL can only be used under [Defines] section",
86                            ExtraData=self._CurrentLine, File=self.MetaFile, Line=self._LineIndex+1)
87        elif (Name in self._FileLocalMacros) and (self._FileLocalMacros[Name] != Value):
88            EdkLogger.error('Parser', FORMAT_INVALID, "EDK_GLOBAL defined a macro with the same name and different value as one defined by 'DEFINE'",
89                            ExtraData=self._CurrentLine, File=self.MetaFile, Line=self._LineIndex+1)
90
91        self._ValueList = [Type, Name, Value]
92
93    return MacroParser
94
95## Base class of parser
96#
97#  This class is used for derivation purpose. The specific parser for one kind
98# type file must derive this class and implement some public interfaces.
99#
100#   @param      FilePath        The path of platform description file
101#   @param      FileType        The raw data of DSC file
102#   @param      Table           Database used to retrieve module/package information
103#   @param      Macros          Macros used for replacement in file
104#   @param      Owner           Owner ID (for sub-section parsing)
105#   @param      From            ID from which the data comes (for !INCLUDE directive)
106#
107class MetaFileParser(object):
108    # data type (file content) for specific file type
109    DataType = {}
110
111    # Parser objects used to implement singleton
112    MetaFiles = {}
113
114    ## Factory method
115    #
116    # One file, one parser object. This factory method makes sure that there's
117    # only one object constructed for one meta file.
118    #
119    #   @param  Class           class object of real AutoGen class
120    #                           (InfParser, DecParser or DscParser)
121    #   @param  FilePath        The path of meta file
122    #   @param  *args           The specific class related parameters
123    #   @param  **kwargs        The specific class related dict parameters
124    #
125    def __new__(Class, FilePath, *args, **kwargs):
126        if FilePath in Class.MetaFiles:
127            return Class.MetaFiles[FilePath]
128        else:
129            ParserObject = super(MetaFileParser, Class).__new__(Class)
130            Class.MetaFiles[FilePath] = ParserObject
131            return ParserObject
132
133    ## Constructor of MetaFileParser
134    #
135    #  Initialize object of MetaFileParser
136    #
137    #   @param      FilePath        The path of platform description file
138    #   @param      FileType        The raw data of DSC file
139    #   @param      Table           Database used to retrieve module/package information
140    #   @param      Macros          Macros used for replacement in file
141    #   @param      Owner           Owner ID (for sub-section parsing)
142    #   @param      From            ID from which the data comes (for !INCLUDE directive)
143    #
144    def __init__(self, FilePath, FileType, Table, Owner=-1, From=-1):
145        self._Table = Table
146        self._RawTable = Table
147        self._FileType = FileType
148        self.MetaFile = FilePath
149        self._Defines = {}
150        self._FileLocalMacros = {}
151        self._SectionsMacroDict = {}
152
153        # for recursive parsing
154        self._Owner = [Owner]
155        self._From = From
156
157        # parsr status for parsing
158        self._ValueList = ['', '', '', '', '']
159        self._Scope = []
160        self._LineIndex = 0
161        self._CurrentLine = ''
162        self._SectionType = MODEL_UNKNOWN
163        self._SectionName = ''
164        self._InSubsection = False
165        self._SubsectionType = MODEL_UNKNOWN
166        self._SubsectionName = ''
167        self._ItemType = MODEL_UNKNOWN
168        self._LastItem = -1
169        self._Enabled = 0
170        self._Finished = False
171        self._PostProcessed = False
172        # Different version of meta-file has different way to parse.
173        self._Version = 0
174        # UNI object and extra UNI object
175        self._UniObj = None
176        self._UniExtraObj = None
177
178    ## Store the parsed data in table
179    def _Store(self, *Args):
180        return self._Table.Insert(*Args)
181
182    ## Virtual method for starting parse
183    def Start(self):
184        raise NotImplementedError
185
186    ## Notify a post-process is needed
187    def DoPostProcess(self):
188        self._PostProcessed = False
189
190    ## Set parsing complete flag in both class and table
191    def _Done(self):
192        self._Finished = True
193        ## Do not set end flag when processing included files
194        if self._From == -1:
195            self._Table.SetEndFlag()
196
197    def _PostProcess(self):
198        self._PostProcessed = True
199
200    ## Get the parse complete flag
201    def _GetFinished(self):
202        return self._Finished
203
204    ## Set the complete flag
205    def _SetFinished(self, Value):
206        self._Finished = Value
207
208    ## Use [] style to query data in table, just for readability
209    #
210    #   DataInfo = [data_type, scope1(arch), scope2(platform/moduletype)]
211    #
212    def __getitem__(self, DataInfo):
213        if not isinstance(DataInfo, type(())):
214            DataInfo = (DataInfo,)
215
216        # Parse the file first, if necessary
217        if not self._Finished:
218            if self._RawTable.IsIntegrity():
219                self._Finished = True
220            else:
221                self._Table = self._RawTable
222                self._PostProcessed = False
223                self.Start()
224
225        # No specific ARCH or Platform given, use raw data
226        if self._RawTable and (len(DataInfo) == 1 or DataInfo[1] is None):
227            return self._RawTable.Query(*DataInfo)
228
229        # Do post-process if necessary
230        if not self._PostProcessed:
231            self._PostProcess()
232
233        return self._Table.Query(*DataInfo)
234
235    ## Data parser for the common format in different type of file
236    #
237    #   The common format in the meatfile is like
238    #
239    #       xxx1 | xxx2 | xxx3
240    #
241    @ParseMacro
242    def _CommonParser(self):
243        TokenList = GetSplitValueList(self._CurrentLine, TAB_VALUE_SPLIT)
244        self._ValueList[0:len(TokenList)] = TokenList
245
246    ## Data parser for the format in which there's path
247    #
248    #   Only path can have macro used. So we need to replace them before use.
249    #
250    @ParseMacro
251    def _PathParser(self):
252        TokenList = GetSplitValueList(self._CurrentLine, TAB_VALUE_SPLIT)
253        self._ValueList[0:len(TokenList)] = TokenList
254        # Don't do macro replacement for dsc file at this point
255        if not isinstance(self, DscParser):
256            Macros = self._Macros
257            self._ValueList = [ReplaceMacro(Value, Macros) for Value in self._ValueList]
258
259    ## Skip unsupported data
260    def _Skip(self):
261        if self._SectionName == TAB_USER_EXTENSIONS.upper() and self._CurrentLine.upper().endswith('.UNI'):
262            if EccGlobalData.gConfig.UniCheckHelpInfo == '1' or EccGlobalData.gConfig.UniCheckAll == '1' or EccGlobalData.gConfig.CheckAll == '1':
263                ExtraUni = self._CurrentLine.strip()
264                ExtraUniFile = os.path.join(os.path.dirname(self.MetaFile), ExtraUni)
265                IsModuleUni = self.MetaFile.upper().endswith('.INF')
266                self._UniExtraObj = UniParser(ExtraUniFile, IsExtraUni=True, IsModuleUni=IsModuleUni)
267                self._UniExtraObj.Start()
268        else:
269            EdkLogger.warn("Parser", "Unrecognized content", File=self.MetaFile,
270                            Line=self._LineIndex + 1, ExtraData=self._CurrentLine);
271        self._ValueList[0:1] = [self._CurrentLine]
272
273    ## Section header parser
274    #
275    #   The section header is always in following format:
276    #
277    #       [section_name.arch<.platform|module_type>]
278    #
279    def _SectionHeaderParser(self):
280        self._Scope = []
281        self._SectionName = ''
282        ArchList = set()
283        for Item in GetSplitValueList(self._CurrentLine[1:-1], TAB_COMMA_SPLIT):
284            if Item == '':
285                continue
286            ItemList = GetSplitValueList(Item, TAB_SPLIT)
287            # different section should not mix in one section
288            if self._SectionName != '' and self._SectionName != ItemList[0].upper():
289                EdkLogger.error('Parser', FORMAT_INVALID, "Different section names in the same section",
290                                File=self.MetaFile, Line=self._LineIndex+1, ExtraData=self._CurrentLine)
291            self._SectionName = ItemList[0].upper()
292            if self._SectionName in self.DataType:
293                self._SectionType = self.DataType[self._SectionName]
294            else:
295                self._SectionType = MODEL_UNKNOWN
296                EdkLogger.warn("Parser", "Unrecognized section", File=self.MetaFile,
297                                Line=self._LineIndex+1, ExtraData=self._CurrentLine)
298            # S1 is always Arch
299            if len(ItemList) > 1:
300                S1 = ItemList[1].upper()
301            else:
302                S1 = 'COMMON'
303            ArchList.add(S1)
304            # S2 may be Platform or ModuleType
305            if len(ItemList) > 2:
306                S2 = ItemList[2].upper()
307            else:
308                S2 = 'COMMON'
309            self._Scope.append([S1, S2])
310
311        # 'COMMON' must not be used with specific ARCHs at the same section
312        if 'COMMON' in ArchList and len(ArchList) > 1:
313            EdkLogger.error('Parser', FORMAT_INVALID, "'common' ARCH must not be used with specific ARCHs",
314                            File=self.MetaFile, Line=self._LineIndex+1, ExtraData=self._CurrentLine)
315        # If the section information is needed later, it should be stored in database
316        self._ValueList[0] = self._SectionName
317
318    ## [defines] section parser
319    @ParseMacro
320    def _DefineParser(self):
321        TokenList = GetSplitValueList(self._CurrentLine, TAB_EQUAL_SPLIT, 1)
322        self._ValueList[1:len(TokenList)] = TokenList
323        if not self._ValueList[1]:
324            EdkLogger.error('Parser', FORMAT_INVALID, "No name specified",
325                            ExtraData=self._CurrentLine, File=self.MetaFile, Line=self._LineIndex+1)
326        if not self._ValueList[2]:
327            EdkLogger.error('Parser', FORMAT_INVALID, "No value specified",
328                            ExtraData=self._CurrentLine, File=self.MetaFile, Line=self._LineIndex+1)
329
330        self._ValueList = [ReplaceMacro(Value, self._Macros) for Value in self._ValueList]
331        Name, Value = self._ValueList[1], self._ValueList[2]
332        # Sometimes, we need to make differences between EDK and EDK2 modules
333        if Name == 'INF_VERSION':
334            try:
335                self._Version = int(Value, 0)
336            except:
337                EdkLogger.error('Parser', FORMAT_INVALID, "Invalid version number",
338                                ExtraData=self._CurrentLine, File=self.MetaFile, Line=self._LineIndex+1)
339        elif Name == 'MODULE_UNI_FILE':
340            UniFile = os.path.join(os.path.dirname(self.MetaFile), Value)
341            if os.path.exists(UniFile):
342                self._UniObj = UniParser(UniFile, IsExtraUni=False, IsModuleUni=True)
343                self._UniObj.Start()
344            else:
345                EdkLogger.error('Parser', FILE_NOT_FOUND, "Module UNI file %s is missing." % Value,
346                                ExtraData=self._CurrentLine, File=self.MetaFile, Line=self._LineIndex+1,
347                                RaiseError=False)
348        elif Name == 'PACKAGE_UNI_FILE':
349            UniFile = os.path.join(os.path.dirname(self.MetaFile), Value)
350            if os.path.exists(UniFile):
351                self._UniObj = UniParser(UniFile, IsExtraUni=False, IsModuleUni=False)
352
353        if isinstance(self, InfParser) and self._Version < 0x00010005:
354            # EDK module allows using defines as macros
355            self._FileLocalMacros[Name] = Value
356        self._Defines[Name] = Value
357
358    ## [BuildOptions] section parser
359    @ParseMacro
360    def _BuildOptionParser(self):
361        TokenList = GetSplitValueList(self._CurrentLine, TAB_EQUAL_SPLIT, 1)
362        TokenList2 = GetSplitValueList(TokenList[0], ':', 1)
363        if len(TokenList2) == 2:
364            self._ValueList[0] = TokenList2[0]              # toolchain family
365            self._ValueList[1] = TokenList2[1]              # keys
366        else:
367            self._ValueList[1] = TokenList[0]
368        if len(TokenList) == 2 and not isinstance(self, DscParser): # value
369            self._ValueList[2] = ReplaceMacro(TokenList[1], self._Macros)
370
371        if self._ValueList[1].count('_') != 4:
372            EdkLogger.error(
373                'Parser',
374                FORMAT_INVALID,
375                "'%s' must be in format of <TARGET>_<TOOLCHAIN>_<ARCH>_<TOOL>_FLAGS" % self._ValueList[1],
376                ExtraData=self._CurrentLine,
377                File=self.MetaFile,
378                Line=self._LineIndex+1
379                )
380
381    def _GetMacros(self):
382        Macros = {}
383        Macros.update(self._FileLocalMacros)
384        Macros.update(self._GetApplicableSectionMacro())
385        return Macros
386
387
388    ## Get section Macros that are applicable to current line, which may come from other sections
389    ## that share the same name while scope is wider
390    def _GetApplicableSectionMacro(self):
391        Macros = {}
392        for Scope1, Scope2 in [("COMMON", "COMMON"), ("COMMON", self._Scope[0][1]),
393                               (self._Scope[0][0], "COMMON"), (self._Scope[0][0], self._Scope[0][1])]:
394            if (self._SectionType, Scope1, Scope2) in self._SectionsMacroDict:
395                Macros.update(self._SectionsMacroDict[(self._SectionType, Scope1, Scope2)])
396        return Macros
397
398    _SectionParser  = {}
399    Finished        = property(_GetFinished, _SetFinished)
400    _Macros         = property(_GetMacros)
401
402
403## INF file parser class
404#
405#   @param      FilePath        The path of platform description file
406#   @param      FileType        The raw data of DSC file
407#   @param      Table           Database used to retrieve module/package information
408#   @param      Macros          Macros used for replacement in file
409#
410class InfParser(MetaFileParser):
411    # INF file supported data types (one type per section)
412    DataType = {
413        TAB_UNKNOWN.upper() : MODEL_UNKNOWN,
414        TAB_INF_DEFINES.upper() : MODEL_META_DATA_HEADER,
415        TAB_DSC_DEFINES_DEFINE : MODEL_META_DATA_DEFINE,
416        TAB_BUILD_OPTIONS.upper() : MODEL_META_DATA_BUILD_OPTION,
417        TAB_INCLUDES.upper() : MODEL_EFI_INCLUDE,
418        TAB_LIBRARIES.upper() : MODEL_EFI_LIBRARY_INSTANCE,
419        TAB_LIBRARY_CLASSES.upper() : MODEL_EFI_LIBRARY_CLASS,
420        TAB_PACKAGES.upper() : MODEL_META_DATA_PACKAGE,
421        TAB_NMAKE.upper() : MODEL_META_DATA_NMAKE,
422        TAB_INF_FIXED_PCD.upper() : MODEL_PCD_FIXED_AT_BUILD,
423        TAB_INF_PATCH_PCD.upper() : MODEL_PCD_PATCHABLE_IN_MODULE,
424        TAB_INF_FEATURE_PCD.upper() : MODEL_PCD_FEATURE_FLAG,
425        TAB_INF_PCD_EX.upper() : MODEL_PCD_DYNAMIC_EX,
426        TAB_INF_PCD.upper() : MODEL_PCD_DYNAMIC,
427        TAB_SOURCES.upper() : MODEL_EFI_SOURCE_FILE,
428        TAB_GUIDS.upper() : MODEL_EFI_GUID,
429        TAB_PROTOCOLS.upper() : MODEL_EFI_PROTOCOL,
430        TAB_PPIS.upper() : MODEL_EFI_PPI,
431        TAB_DEPEX.upper() : MODEL_EFI_DEPEX,
432        TAB_BINARIES.upper() : MODEL_EFI_BINARY_FILE,
433        TAB_USER_EXTENSIONS.upper() : MODEL_META_DATA_USER_EXTENSION
434    }
435
436    ## Constructor of InfParser
437    #
438    #  Initialize object of InfParser
439    #
440    #   @param      FilePath        The path of module description file
441    #   @param      FileType        The raw data of DSC file
442    #   @param      Table           Database used to retrieve module/package information
443    #   @param      Macros          Macros used for replacement in file
444    #
445    def __init__(self, FilePath, FileType, Table):
446        # prevent re-initialization
447        if hasattr(self, "_Table"):
448            return
449        MetaFileParser.__init__(self, FilePath, FileType, Table)
450        self.TblFile = EccGlobalData.gDb.TblFile
451        self.FileID = -1
452
453    ## Parser starter
454    def Start(self):
455        NmakeLine = ''
456        Content = ''
457        Usage = ''
458        try:
459            Content = open(str(self.MetaFile), 'r').readlines()
460        except:
461            EdkLogger.error("Parser", FILE_READ_FAILURE, ExtraData=self.MetaFile)
462        #
463        # Insert a record for file
464        #
465        Filename = NormPath(self.MetaFile)
466        FileID = self.TblFile.GetFileId(Filename)
467        if FileID:
468            self.FileID = FileID
469        else:
470            self.FileID = self.TblFile.InsertFile(Filename, MODEL_FILE_INF)
471
472        # parse the file line by line
473        IsFindBlockComment = False
474
475        for Index in range(0, len(Content)):
476            if self._SectionType in [MODEL_EFI_GUID,
477                                     MODEL_EFI_PROTOCOL,
478                                     MODEL_EFI_PPI,
479                                     MODEL_PCD_FIXED_AT_BUILD,
480                                     MODEL_PCD_PATCHABLE_IN_MODULE,
481                                     MODEL_PCD_FEATURE_FLAG,
482                                     MODEL_PCD_DYNAMIC_EX,
483                                     MODEL_PCD_DYNAMIC]:
484                Line = Content[Index].strip()
485                if Line.startswith(TAB_SPECIAL_COMMENT):
486                    Usage += ' ' + Line[Line.find(TAB_SPECIAL_COMMENT):]
487                    continue
488                elif Line.startswith(TAB_COMMENT_SPLIT):
489                    continue
490                elif Line.find(TAB_COMMENT_SPLIT) > 0:
491                    Usage += ' ' + Line[Line.find(TAB_COMMENT_SPLIT):]
492                    Line = Line[:Line.find(TAB_COMMENT_SPLIT)]
493            else:
494            # skip empty, commented, block commented lines
495                Line = CleanString(Content[Index], AllowCppStyleComment=True)
496                Usage = ''
497            NextLine = ''
498            if Index + 1 < len(Content):
499                NextLine = CleanString(Content[Index + 1])
500            if Line == '':
501                continue
502            if Line.find(DataType.TAB_COMMENT_EDK_START) > -1:
503                IsFindBlockComment = True
504                continue
505            if Line.find(DataType.TAB_COMMENT_EDK_END) > -1:
506                IsFindBlockComment = False
507                continue
508            if IsFindBlockComment:
509                continue
510
511            self._LineIndex = Index
512            self._CurrentLine = Line
513
514            # section header
515            if Line[0] == TAB_SECTION_START and Line[-1] == TAB_SECTION_END:
516                self._SectionHeaderParser()
517                # Check invalid sections
518                if self._Version < 0x00010005:
519                    if self._SectionType in [MODEL_META_DATA_BUILD_OPTION,
520                                             MODEL_EFI_LIBRARY_CLASS,
521                                             MODEL_META_DATA_PACKAGE,
522                                             MODEL_PCD_FIXED_AT_BUILD,
523                                             MODEL_PCD_PATCHABLE_IN_MODULE,
524                                             MODEL_PCD_FEATURE_FLAG,
525                                             MODEL_PCD_DYNAMIC_EX,
526                                             MODEL_PCD_DYNAMIC,
527                                             MODEL_EFI_GUID,
528                                             MODEL_EFI_PROTOCOL,
529                                             MODEL_EFI_PPI,
530                                             MODEL_META_DATA_USER_EXTENSION]:
531                        EdkLogger.error('Parser', FORMAT_INVALID,
532                                        "Section [%s] is not allowed in inf file without version" % (self._SectionName),
533                                        ExtraData=self._CurrentLine, File=self.MetaFile, Line=self._LineIndex+1)
534                elif self._SectionType in [MODEL_EFI_INCLUDE,
535                                           MODEL_EFI_LIBRARY_INSTANCE,
536                                           MODEL_META_DATA_NMAKE]:
537                    EdkLogger.error('Parser', FORMAT_INVALID,
538                                    "Section [%s] is not allowed in inf file with version 0x%08x" % (self._SectionName, self._Version),
539                                    ExtraData=self._CurrentLine, File=self.MetaFile, Line=self._LineIndex+1)
540                continue
541            # merge two lines specified by '\' in section NMAKE
542            elif self._SectionType == MODEL_META_DATA_NMAKE:
543                if Line[-1] == '\\':
544                    if NextLine == '':
545                        self._CurrentLine = NmakeLine + Line[0:-1]
546                        NmakeLine = ''
547                    else:
548                        if NextLine[0] == TAB_SECTION_START and NextLine[-1] == TAB_SECTION_END:
549                            self._CurrentLine = NmakeLine + Line[0:-1]
550                            NmakeLine = ''
551                        else:
552                            NmakeLine = NmakeLine + ' ' + Line[0:-1]
553                            continue
554                else:
555                    self._CurrentLine = NmakeLine + Line
556                    NmakeLine = ''
557
558            # section content
559            self._ValueList = ['', '', '']
560            # parse current line, result will be put in self._ValueList
561            self._SectionParser[self._SectionType](self)
562            if self._ValueList is None or self._ItemType == MODEL_META_DATA_DEFINE:
563                self._ItemType = -1
564                continue
565            #
566            # Model, Value1, Value2, Value3, Arch, Platform, BelongsToItem=-1,
567            # LineBegin=-1, ColumnBegin=-1, LineEnd=-1, ColumnEnd=-1, Enabled=-1
568            #
569            self._ValueList[0] = self._ValueList[0].replace('/', '\\')
570            Usage = Usage.strip()
571            for Arch, Platform in self._Scope:
572                self._Store(self._SectionType,
573                            self._ValueList[0],
574                            self._ValueList[1],
575                            self._ValueList[2],
576                            Arch,
577                            Platform,
578                            self._Owner[-1],
579                            self.FileID,
580                            self._LineIndex+1,
581                            -1,
582                            self._LineIndex+1,
583                            -1,
584                            0,
585                            Usage
586                            )
587            Usage = ''
588        if IsFindBlockComment:
589            EdkLogger.error("Parser", FORMAT_INVALID, "Open block comments (starting with /*) are expected to end with */",
590                            File=self.MetaFile)
591        self._Done()
592
593    ## Data parser for the format in which there's path
594    #
595    #   Only path can have macro used. So we need to replace them before use.
596    #
597    def _IncludeParser(self):
598        TokenList = GetSplitValueList(self._CurrentLine, TAB_VALUE_SPLIT)
599        self._ValueList[0:len(TokenList)] = TokenList
600        Macros = self._Macros
601        if Macros:
602            for Index in range(0, len(self._ValueList)):
603                Value = self._ValueList[Index]
604                if not Value:
605                    continue
606
607                self._ValueList[Index] = ReplaceMacro(Value, Macros)
608
609    ## Parse [Sources] section
610    #
611    #   Only path can have macro used. So we need to replace them before use.
612    #
613    @ParseMacro
614    def _SourceFileParser(self):
615        TokenList = GetSplitValueList(self._CurrentLine, TAB_VALUE_SPLIT)
616        self._ValueList[0:len(TokenList)] = TokenList
617        Macros = self._Macros
618        # For Acpi tables, remove macro like ' TABLE_NAME=Sata1'
619        if 'COMPONENT_TYPE' in Macros:
620            if self._Defines['COMPONENT_TYPE'].upper() == 'ACPITABLE':
621                self._ValueList[0] = GetSplitValueList(self._ValueList[0], ' ', 1)[0]
622        if self._Defines['BASE_NAME'] == 'Microcode':
623            pass
624        self._ValueList = [ReplaceMacro(Value, Macros) for Value in self._ValueList]
625
626    ## Parse [Binaries] section
627    #
628    #   Only path can have macro used. So we need to replace them before use.
629    #
630    @ParseMacro
631    def _BinaryFileParser(self):
632        TokenList = GetSplitValueList(self._CurrentLine, TAB_VALUE_SPLIT, 2)
633        if len(TokenList) < 2:
634            EdkLogger.error('Parser', FORMAT_INVALID, "No file type or path specified",
635                            ExtraData=self._CurrentLine + " (<FileType> | <FilePath> [| <Target>])",
636                            File=self.MetaFile, Line=self._LineIndex+1)
637        if not TokenList[0]:
638            EdkLogger.error('Parser', FORMAT_INVALID, "No file type specified",
639                            ExtraData=self._CurrentLine + " (<FileType> | <FilePath> [| <Target>])",
640                            File=self.MetaFile, Line=self._LineIndex+1)
641        if not TokenList[1]:
642            EdkLogger.error('Parser', FORMAT_INVALID, "No file path specified",
643                            ExtraData=self._CurrentLine + " (<FileType> | <FilePath> [| <Target>])",
644                            File=self.MetaFile, Line=self._LineIndex+1)
645        self._ValueList[0:len(TokenList)] = TokenList
646        self._ValueList[1] = ReplaceMacro(self._ValueList[1], self._Macros)
647
648    ## [nmake] section parser (Edk.x style only)
649    def _NmakeParser(self):
650        TokenList = GetSplitValueList(self._CurrentLine, TAB_EQUAL_SPLIT, 1)
651        self._ValueList[0:len(TokenList)] = TokenList
652        # remove macros
653        self._ValueList[1] = ReplaceMacro(self._ValueList[1], self._Macros)
654        # remove self-reference in macro setting
655        #self._ValueList[1] = ReplaceMacro(self._ValueList[1], {self._ValueList[0]:''})
656
657    ## [FixedPcd], [FeaturePcd], [PatchPcd], [Pcd] and [PcdEx] sections parser
658    @ParseMacro
659    def _PcdParser(self):
660        TokenList = GetSplitValueList(self._CurrentLine, TAB_VALUE_SPLIT, 1)
661        ValueList = GetSplitValueList(TokenList[0], TAB_SPLIT)
662        if len(ValueList) != 2:
663            EdkLogger.error('Parser', FORMAT_INVALID, "Illegal token space GUID and PCD name format",
664                            ExtraData=self._CurrentLine + " (<TokenSpaceGuidCName>.<PcdCName>)",
665                            File=self.MetaFile, Line=self._LineIndex+1)
666        self._ValueList[0:1] = ValueList
667        if len(TokenList) > 1:
668            self._ValueList[2] = TokenList[1]
669        if self._ValueList[0] == '' or self._ValueList[1] == '':
670            EdkLogger.error('Parser', FORMAT_INVALID, "No token space GUID or PCD name specified",
671                            ExtraData=self._CurrentLine + " (<TokenSpaceGuidCName>.<PcdCName>)",
672                            File=self.MetaFile, Line=self._LineIndex+1)
673
674        # if value are 'True', 'true', 'TRUE' or 'False', 'false', 'FALSE', replace with integer 1 or 0.
675        if self._ValueList[2] != '':
676            InfPcdValueList = GetSplitValueList(TokenList[1], TAB_VALUE_SPLIT, 1)
677            if InfPcdValueList[0] in ['True', 'true', 'TRUE']:
678                self._ValueList[2] = TokenList[1].replace(InfPcdValueList[0], '1', 1);
679            elif InfPcdValueList[0] in ['False', 'false', 'FALSE']:
680                self._ValueList[2] = TokenList[1].replace(InfPcdValueList[0], '0', 1);
681
682    ## [depex] section parser
683    @ParseMacro
684    def _DepexParser(self):
685        self._ValueList[0:1] = [self._CurrentLine]
686
687    _SectionParser = {
688        MODEL_UNKNOWN                   :   MetaFileParser._Skip,
689        MODEL_META_DATA_HEADER          :   MetaFileParser._DefineParser,
690        MODEL_META_DATA_BUILD_OPTION    :   MetaFileParser._BuildOptionParser,
691        MODEL_EFI_INCLUDE               :   _IncludeParser,                 # for Edk.x modules
692        MODEL_EFI_LIBRARY_INSTANCE      :   MetaFileParser._CommonParser,   # for Edk.x modules
693        MODEL_EFI_LIBRARY_CLASS         :   MetaFileParser._PathParser,
694        MODEL_META_DATA_PACKAGE         :   MetaFileParser._PathParser,
695        MODEL_META_DATA_NMAKE           :   _NmakeParser,                   # for Edk.x modules
696        MODEL_PCD_FIXED_AT_BUILD        :   _PcdParser,
697        MODEL_PCD_PATCHABLE_IN_MODULE   :   _PcdParser,
698        MODEL_PCD_FEATURE_FLAG          :   _PcdParser,
699        MODEL_PCD_DYNAMIC_EX            :   _PcdParser,
700        MODEL_PCD_DYNAMIC               :   _PcdParser,
701        MODEL_EFI_SOURCE_FILE           :   _SourceFileParser,
702        MODEL_EFI_GUID                  :   MetaFileParser._CommonParser,
703        MODEL_EFI_PROTOCOL              :   MetaFileParser._CommonParser,
704        MODEL_EFI_PPI                   :   MetaFileParser._CommonParser,
705        MODEL_EFI_DEPEX                 :   _DepexParser,
706        MODEL_EFI_BINARY_FILE           :   _BinaryFileParser,
707        MODEL_META_DATA_USER_EXTENSION  :   MetaFileParser._Skip,
708    }
709
710## DSC file parser class
711#
712#   @param      FilePath        The path of platform description file
713#   @param      FileType        The raw data of DSC file
714#   @param      Table           Database used to retrieve module/package information
715#   @param      Macros          Macros used for replacement in file
716#   @param      Owner           Owner ID (for sub-section parsing)
717#   @param      From            ID from which the data comes (for !INCLUDE directive)
718#
719class DscParser(MetaFileParser):
720    # DSC file supported data types (one type per section)
721    DataType = {
722        TAB_SKUIDS.upper()                          :   MODEL_EFI_SKU_ID,
723        TAB_LIBRARIES.upper()                       :   MODEL_EFI_LIBRARY_INSTANCE,
724        TAB_LIBRARY_CLASSES.upper()                 :   MODEL_EFI_LIBRARY_CLASS,
725        TAB_BUILD_OPTIONS.upper()                   :   MODEL_META_DATA_BUILD_OPTION,
726        TAB_PCDS_FIXED_AT_BUILD_NULL.upper()        :   MODEL_PCD_FIXED_AT_BUILD,
727        TAB_PCDS_PATCHABLE_IN_MODULE_NULL.upper()   :   MODEL_PCD_PATCHABLE_IN_MODULE,
728        TAB_PCDS_FEATURE_FLAG_NULL.upper()          :   MODEL_PCD_FEATURE_FLAG,
729        TAB_PCDS_DYNAMIC_DEFAULT_NULL.upper()       :   MODEL_PCD_DYNAMIC_DEFAULT,
730        TAB_PCDS_DYNAMIC_HII_NULL.upper()           :   MODEL_PCD_DYNAMIC_HII,
731        TAB_PCDS_DYNAMIC_VPD_NULL.upper()           :   MODEL_PCD_DYNAMIC_VPD,
732        TAB_PCDS_DYNAMIC_EX_DEFAULT_NULL.upper()    :   MODEL_PCD_DYNAMIC_EX_DEFAULT,
733        TAB_PCDS_DYNAMIC_EX_HII_NULL.upper()        :   MODEL_PCD_DYNAMIC_EX_HII,
734        TAB_PCDS_DYNAMIC_EX_VPD_NULL.upper()        :   MODEL_PCD_DYNAMIC_EX_VPD,
735        TAB_COMPONENTS.upper()                      :   MODEL_META_DATA_COMPONENT,
736        TAB_DSC_DEFINES.upper()                     :   MODEL_META_DATA_HEADER,
737        TAB_DSC_DEFINES_DEFINE                      :   MODEL_META_DATA_DEFINE,
738        TAB_DSC_DEFINES_EDKGLOBAL                   :   MODEL_META_DATA_GLOBAL_DEFINE,
739        TAB_INCLUDE.upper()                         :   MODEL_META_DATA_INCLUDE,
740        TAB_IF.upper()                              :   MODEL_META_DATA_CONDITIONAL_STATEMENT_IF,
741        TAB_IF_DEF.upper()                          :   MODEL_META_DATA_CONDITIONAL_STATEMENT_IFDEF,
742        TAB_IF_N_DEF.upper()                        :   MODEL_META_DATA_CONDITIONAL_STATEMENT_IFNDEF,
743        TAB_ELSE_IF.upper()                         :   MODEL_META_DATA_CONDITIONAL_STATEMENT_ELSEIF,
744        TAB_ELSE.upper()                            :   MODEL_META_DATA_CONDITIONAL_STATEMENT_ELSE,
745        TAB_END_IF.upper()                          :   MODEL_META_DATA_CONDITIONAL_STATEMENT_ENDIF,
746        TAB_ERROR.upper()                           :   MODEL_META_DATA_CONDITIONAL_STATEMENT_ERROR,
747    }
748
749    # Valid names in define section
750    DefineKeywords = [
751        "DSC_SPECIFICATION",
752        "PLATFORM_NAME",
753        "PLATFORM_GUID",
754        "PLATFORM_VERSION",
755        "SKUID_IDENTIFIER",
756        "PCD_INFO_GENERATION",
757        "SUPPORTED_ARCHITECTURES",
758        "BUILD_TARGETS",
759        "OUTPUT_DIRECTORY",
760        "FLASH_DEFINITION",
761        "BUILD_NUMBER",
762        "RFC_LANGUAGES",
763        "ISO_LANGUAGES",
764        "TIME_STAMP_FILE",
765        "VPD_TOOL_GUID",
766        "FIX_LOAD_TOP_MEMORY_ADDRESS"
767    ]
768
769    SubSectionDefineKeywords = [
770        "FILE_GUID"
771    ]
772
773    SymbolPattern = ValueExpression.SymbolPattern
774
775    ## Constructor of DscParser
776    #
777    #  Initialize object of DscParser
778    #
779    #   @param      FilePath        The path of platform description file
780    #   @param      FileType        The raw data of DSC file
781    #   @param      Table           Database used to retrieve module/package information
782    #   @param      Macros          Macros used for replacement in file
783    #   @param      Owner           Owner ID (for sub-section parsing)
784    #   @param      From            ID from which the data comes (for !INCLUDE directive)
785    #
786    def __init__(self, FilePath, FileType, Table, Owner=-1, From=-1):
787        # prevent re-initialization
788        if hasattr(self, "_Table"):
789            return
790        MetaFileParser.__init__(self, FilePath, FileType, Table, Owner, From)
791        self._Version = 0x00010005  # Only EDK2 dsc file is supported
792        # to store conditional directive evaluation result
793        self._DirectiveStack = []
794        self._DirectiveEvalStack = []
795        self._Enabled = 1
796
797        # Final valid replacable symbols
798        self._Symbols = {}
799        #
800        #  Map the ID between the original table and new table to track
801        #  the owner item
802        #
803        self._IdMapping = {-1:-1}
804
805        self.TblFile = EccGlobalData.gDb.TblFile
806        self.FileID = -1
807
808    ## Parser starter
809    def Start(self):
810        Content = ''
811        try:
812            Content = open(str(self.MetaFile.Path), 'r').readlines()
813        except:
814            EdkLogger.error("Parser", FILE_READ_FAILURE, ExtraData=self.MetaFile)
815        #
816        # Insert a record for file
817        #
818        Filename = NormPath(self.MetaFile.Path)
819        FileID = self.TblFile.GetFileId(Filename)
820        if FileID:
821            self.FileID = FileID
822        else:
823            self.FileID = self.TblFile.InsertFile(Filename, MODEL_FILE_DSC)
824
825
826        for Index in range(0, len(Content)):
827            Line = CleanString(Content[Index])
828            # skip empty line
829            if Line == '':
830                continue
831
832            self._CurrentLine = Line
833            self._LineIndex = Index
834            if self._InSubsection and self._Owner[-1] == -1:
835                self._Owner.append(self._LastItem)
836
837            # section header
838            if Line[0] == TAB_SECTION_START and Line[-1] == TAB_SECTION_END:
839                self._SectionType = MODEL_META_DATA_SECTION_HEADER
840            # subsection ending
841            elif Line[0] == '}' and self._InSubsection:
842                self._InSubsection = False
843                self._SubsectionType = MODEL_UNKNOWN
844                self._SubsectionName = ''
845                self._Owner[-1] = -1
846                continue
847            # subsection header
848            elif Line[0] == TAB_OPTION_START and Line[-1] == TAB_OPTION_END:
849                self._SubsectionType = MODEL_META_DATA_SUBSECTION_HEADER
850            # directive line
851            elif Line[0] == '!':
852                self._DirectiveParser()
853                continue
854
855            if self._InSubsection:
856                SectionType = self._SubsectionType
857            else:
858                SectionType = self._SectionType
859            self._ItemType = SectionType
860
861            self._ValueList = ['', '', '']
862            self._SectionParser[SectionType](self)
863            if self._ValueList is None:
864                continue
865            #
866            # Model, Value1, Value2, Value3, Arch, ModuleType, BelongsToItem=-1, BelongsToFile=-1,
867            # LineBegin=-1, ColumnBegin=-1, LineEnd=-1, ColumnEnd=-1, Enabled=-1
868            #
869            for Arch, ModuleType in self._Scope:
870                self._LastItem = self._Store(
871                                        self._ItemType,
872                                        self._ValueList[0],
873                                        self._ValueList[1],
874                                        self._ValueList[2],
875                                        Arch,
876                                        ModuleType,
877                                        self._Owner[-1],
878                                        self.FileID,
879                                        self._From,
880                                        self._LineIndex+1,
881                                        -1,
882                                        self._LineIndex+1,
883                                        -1,
884                                        self._Enabled
885                                        )
886
887        if self._DirectiveStack:
888            Type, Line, Text = self._DirectiveStack[-1]
889            EdkLogger.error('Parser', FORMAT_INVALID, "No matching '!endif' found",
890                            ExtraData=Text, File=self.MetaFile, Line=Line)
891        self._Done()
892
893    ## <subsection_header> parser
894    def _SubsectionHeaderParser(self):
895        self._SubsectionName = self._CurrentLine[1:-1].upper()
896        if self._SubsectionName in self.DataType:
897            self._SubsectionType = self.DataType[self._SubsectionName]
898        else:
899            self._SubsectionType = MODEL_UNKNOWN
900            EdkLogger.warn("Parser", "Unrecognized sub-section", File=self.MetaFile,
901                           Line=self._LineIndex+1, ExtraData=self._CurrentLine)
902        self._ValueList[0] = self._SubsectionName
903
904    ## Directive statement parser
905    def _DirectiveParser(self):
906        self._ValueList = ['', '', '']
907        TokenList = GetSplitValueList(self._CurrentLine, ' ', 1)
908        self._ValueList[0:len(TokenList)] = TokenList
909
910        # Syntax check
911        DirectiveName = self._ValueList[0].upper()
912        if DirectiveName not in self.DataType:
913            EdkLogger.error("Parser", FORMAT_INVALID, "Unknown directive [%s]" % DirectiveName,
914                            File=self.MetaFile, Line=self._LineIndex+1)
915        if DirectiveName in ['!IF', '!IFDEF', '!INCLUDE', '!IFNDEF', '!ELSEIF'] and self._ValueList[1] == '':
916            EdkLogger.error("Parser", FORMAT_INVALID, "Missing expression",
917                            File=self.MetaFile, Line=self._LineIndex+1,
918                            ExtraData=self._CurrentLine)
919
920        ItemType = self.DataType[DirectiveName]
921        if ItemType == MODEL_META_DATA_CONDITIONAL_STATEMENT_ENDIF:
922            # Remove all directives between !if and !endif, including themselves
923            while self._DirectiveStack:
924                # Remove any !else or !elseif
925                DirectiveInfo = self._DirectiveStack.pop()
926                if DirectiveInfo[0] in [MODEL_META_DATA_CONDITIONAL_STATEMENT_IF,
927                                        MODEL_META_DATA_CONDITIONAL_STATEMENT_IFDEF,
928                                        MODEL_META_DATA_CONDITIONAL_STATEMENT_IFNDEF]:
929                    break
930            else:
931                EdkLogger.error("Parser", FORMAT_INVALID, "Redundant '!endif'",
932                                File=self.MetaFile, Line=self._LineIndex+1,
933                                ExtraData=self._CurrentLine)
934        elif ItemType != MODEL_META_DATA_INCLUDE:
935            # Break if there's a !else is followed by a !elseif
936            if ItemType == MODEL_META_DATA_CONDITIONAL_STATEMENT_ELSEIF and \
937               self._DirectiveStack and \
938               self._DirectiveStack[-1][0] == MODEL_META_DATA_CONDITIONAL_STATEMENT_ELSE:
939                EdkLogger.error("Parser", FORMAT_INVALID, "'!elseif' after '!else'",
940                                File=self.MetaFile, Line=self._LineIndex+1,
941                                ExtraData=self._CurrentLine)
942            self._DirectiveStack.append((ItemType, self._LineIndex+1, self._CurrentLine))
943        elif self._From > 0:
944            EdkLogger.error('Parser', FORMAT_INVALID,
945                            "No '!include' allowed in included file",
946                            ExtraData=self._CurrentLine, File=self.MetaFile,
947                            Line=self._LineIndex+1)
948
949        #
950        # Model, Value1, Value2, Value3, Arch, ModuleType, BelongsToItem=-1, BelongsToFile=-1,
951        # LineBegin=-1, ColumnBegin=-1, LineEnd=-1, ColumnEnd=-1, Enabled=-1
952        #
953        self._LastItem = self._Store(
954                                ItemType,
955                                self._ValueList[0],
956                                self._ValueList[1],
957                                self._ValueList[2],
958                                'COMMON',
959                                'COMMON',
960                                self._Owner[-1],
961                                self.FileID,
962                                self._From,
963                                self._LineIndex+1,
964                                -1,
965                                self._LineIndex+1,
966                                -1,
967                                0
968                                )
969
970    ## [defines] section parser
971    @ParseMacro
972    def _DefineParser(self):
973        TokenList = GetSplitValueList(self._CurrentLine, TAB_EQUAL_SPLIT, 1)
974        self._ValueList[1:len(TokenList)] = TokenList
975
976        # Syntax check
977        if not self._ValueList[1]:
978            EdkLogger.error('Parser', FORMAT_INVALID, "No name specified",
979                            ExtraData=self._CurrentLine, File=self.MetaFile, Line=self._LineIndex+1)
980        if not self._ValueList[2]:
981            EdkLogger.error('Parser', FORMAT_INVALID, "No value specified",
982                            ExtraData=self._CurrentLine, File=self.MetaFile, Line=self._LineIndex+1)
983        if (not self._ValueList[1] in self.DefineKeywords and
984            (self._InSubsection and self._ValueList[1] not in self.SubSectionDefineKeywords)):
985            EdkLogger.error('Parser', FORMAT_INVALID,
986                            "Unknown keyword found: %s. "
987                            "If this is a macro you must "
988                            "add it as a DEFINE in the DSC" % self._ValueList[1],
989                            ExtraData=self._CurrentLine, File=self.MetaFile, Line=self._LineIndex+1)
990        self._Defines[self._ValueList[1]] = self._ValueList[2]
991        self._ItemType = self.DataType[TAB_DSC_DEFINES.upper()]
992
993    @ParseMacro
994    def _SkuIdParser(self):
995        TokenList = GetSplitValueList(self._CurrentLine, TAB_VALUE_SPLIT)
996        if len(TokenList) != 2:
997            EdkLogger.error('Parser', FORMAT_INVALID, "Correct format is '<Integer>|<UiName>'",
998                            ExtraData=self._CurrentLine, File=self.MetaFile, Line=self._LineIndex+1)
999        self._ValueList[0:len(TokenList)] = TokenList
1000
1001    ## Parse Edk style of library modules
1002    def _LibraryInstanceParser(self):
1003        self._ValueList[0] = self._CurrentLine
1004
1005    ## PCD sections parser
1006    #
1007    #   [PcdsFixedAtBuild]
1008    #   [PcdsPatchableInModule]
1009    #   [PcdsFeatureFlag]
1010    #   [PcdsDynamicEx
1011    #   [PcdsDynamicExDefault]
1012    #   [PcdsDynamicExVpd]
1013    #   [PcdsDynamicExHii]
1014    #   [PcdsDynamic]
1015    #   [PcdsDynamicDefault]
1016    #   [PcdsDynamicVpd]
1017    #   [PcdsDynamicHii]
1018    #
1019    @ParseMacro
1020    def _PcdParser(self):
1021        TokenList = GetSplitValueList(self._CurrentLine, TAB_VALUE_SPLIT, 1)
1022        self._ValueList[0:1] = GetSplitValueList(TokenList[0], TAB_SPLIT)
1023        if len(TokenList) == 2:
1024            self._ValueList[2] = TokenList[1]
1025        if self._ValueList[0] == '' or self._ValueList[1] == '':
1026            EdkLogger.error('Parser', FORMAT_INVALID, "No token space GUID or PCD name specified",
1027                            ExtraData=self._CurrentLine + " (<TokenSpaceGuidCName>.<TokenCName>|<PcdValue>)",
1028                            File=self.MetaFile, Line=self._LineIndex+1)
1029        if self._ValueList[2] == '':
1030            EdkLogger.error('Parser', FORMAT_INVALID, "No PCD value given",
1031                            ExtraData=self._CurrentLine + " (<TokenSpaceGuidCName>.<TokenCName>|<PcdValue>)",
1032                            File=self.MetaFile, Line=self._LineIndex+1)
1033        # if value are 'True', 'true', 'TRUE' or 'False', 'false', 'FALSE', replace with integer 1 or 0.
1034        DscPcdValueList = GetSplitValueList(TokenList[1], TAB_VALUE_SPLIT, 1)
1035        if DscPcdValueList[0] in ['True', 'true', 'TRUE']:
1036            self._ValueList[2] = TokenList[1].replace(DscPcdValueList[0], '1', 1);
1037        elif DscPcdValueList[0] in ['False', 'false', 'FALSE']:
1038            self._ValueList[2] = TokenList[1].replace(DscPcdValueList[0], '0', 1);
1039
1040    ## [components] section parser
1041    @ParseMacro
1042    def _ComponentParser(self):
1043        if self._CurrentLine[-1] == '{':
1044            self._ValueList[0] = self._CurrentLine[0:-1].strip()
1045            self._InSubsection = True
1046        else:
1047            self._ValueList[0] = self._CurrentLine
1048
1049    ## [LibraryClasses] section
1050    @ParseMacro
1051    def _LibraryClassParser(self):
1052        TokenList = GetSplitValueList(self._CurrentLine, TAB_VALUE_SPLIT)
1053        if len(TokenList) < 2:
1054            EdkLogger.error('Parser', FORMAT_INVALID, "No library class or instance specified",
1055                            ExtraData=self._CurrentLine + " (<LibraryClassName>|<LibraryInstancePath>)",
1056                            File=self.MetaFile, Line=self._LineIndex+1)
1057        if TokenList[0] == '':
1058            EdkLogger.error('Parser', FORMAT_INVALID, "No library class specified",
1059                            ExtraData=self._CurrentLine + " (<LibraryClassName>|<LibraryInstancePath>)",
1060                            File=self.MetaFile, Line=self._LineIndex+1)
1061        if TokenList[1] == '':
1062            EdkLogger.error('Parser', FORMAT_INVALID, "No library instance specified",
1063                            ExtraData=self._CurrentLine + " (<LibraryClassName>|<LibraryInstancePath>)",
1064                            File=self.MetaFile, Line=self._LineIndex+1)
1065
1066        self._ValueList[0:len(TokenList)] = TokenList
1067
1068
1069    ## [BuildOptions] section parser
1070    @ParseMacro
1071    def _BuildOptionParser(self):
1072        TokenList = GetSplitValueList(self._CurrentLine, TAB_EQUAL_SPLIT, 1)
1073        TokenList2 = GetSplitValueList(TokenList[0], ':', 1)
1074        if len(TokenList2) == 2:
1075            self._ValueList[0] = TokenList2[0]  # toolchain family
1076            self._ValueList[1] = TokenList2[1]  # keys
1077        else:
1078            self._ValueList[1] = TokenList[0]
1079        if len(TokenList) == 2:                 # value
1080            self._ValueList[2] = TokenList[1]
1081
1082        if self._ValueList[1].count('_') != 4:
1083            EdkLogger.error(
1084                'Parser',
1085                FORMAT_INVALID,
1086                "'%s' must be in format of <TARGET>_<TOOLCHAIN>_<ARCH>_<TOOL>_FLAGS" % self._ValueList[1],
1087                ExtraData=self._CurrentLine,
1088                File=self.MetaFile,
1089                Line=self._LineIndex+1
1090                )
1091
1092    ## Override parent's method since we'll do all macro replacements in parser
1093    def _GetMacros(self):
1094        Macros = dict( [('ARCH', 'IA32'), ('FAMILY', TAB_COMPILER_MSFT), ('TOOL_CHAIN_TAG', 'VS2008x86'), ('TARGET', 'DEBUG')])
1095        Macros.update(self._FileLocalMacros)
1096        Macros.update(self._GetApplicableSectionMacro())
1097        Macros.update(GlobalData.gEdkGlobal)
1098        Macros.update(GlobalData.gPlatformDefines)
1099        Macros.update(GlobalData.gCommandLineDefines)
1100        # PCD cannot be referenced in macro definition
1101        if self._ItemType not in [MODEL_META_DATA_DEFINE, MODEL_META_DATA_GLOBAL_DEFINE]:
1102            Macros.update(self._Symbols)
1103        return Macros
1104
1105    def _PostProcess(self):
1106        Processer = {
1107            MODEL_META_DATA_SECTION_HEADER                  :   self.__ProcessSectionHeader,
1108            MODEL_META_DATA_SUBSECTION_HEADER               :   self.__ProcessSubsectionHeader,
1109            MODEL_META_DATA_HEADER                          :   self.__ProcessDefine,
1110            MODEL_META_DATA_DEFINE                          :   self.__ProcessDefine,
1111            MODEL_META_DATA_GLOBAL_DEFINE                   :   self.__ProcessDefine,
1112            MODEL_META_DATA_INCLUDE                         :   self.__ProcessDirective,
1113            MODEL_META_DATA_CONDITIONAL_STATEMENT_IF        :   self.__ProcessDirective,
1114            MODEL_META_DATA_CONDITIONAL_STATEMENT_ELSE      :   self.__ProcessDirective,
1115            MODEL_META_DATA_CONDITIONAL_STATEMENT_IFDEF     :   self.__ProcessDirective,
1116            MODEL_META_DATA_CONDITIONAL_STATEMENT_IFNDEF    :   self.__ProcessDirective,
1117            MODEL_META_DATA_CONDITIONAL_STATEMENT_ENDIF     :   self.__ProcessDirective,
1118            MODEL_META_DATA_CONDITIONAL_STATEMENT_ELSEIF    :   self.__ProcessDirective,
1119            MODEL_EFI_SKU_ID                                :   self.__ProcessSkuId,
1120            MODEL_EFI_LIBRARY_INSTANCE                      :   self.__ProcessLibraryInstance,
1121            MODEL_EFI_LIBRARY_CLASS                         :   self.__ProcessLibraryClass,
1122            MODEL_PCD_FIXED_AT_BUILD                        :   self.__ProcessPcd,
1123            MODEL_PCD_PATCHABLE_IN_MODULE                   :   self.__ProcessPcd,
1124            MODEL_PCD_FEATURE_FLAG                          :   self.__ProcessPcd,
1125            MODEL_PCD_DYNAMIC_DEFAULT                       :   self.__ProcessPcd,
1126            MODEL_PCD_DYNAMIC_HII                           :   self.__ProcessPcd,
1127            MODEL_PCD_DYNAMIC_VPD                           :   self.__ProcessPcd,
1128            MODEL_PCD_DYNAMIC_EX_DEFAULT                    :   self.__ProcessPcd,
1129            MODEL_PCD_DYNAMIC_EX_HII                        :   self.__ProcessPcd,
1130            MODEL_PCD_DYNAMIC_EX_VPD                        :   self.__ProcessPcd,
1131            MODEL_META_DATA_COMPONENT                       :   self.__ProcessComponent,
1132            MODEL_META_DATA_BUILD_OPTION                    :   self.__ProcessBuildOption,
1133            MODEL_UNKNOWN                                   :   self._Skip,
1134            MODEL_META_DATA_USER_EXTENSION                  :   self._Skip,
1135            MODEL_META_DATA_CONDITIONAL_STATEMENT_ERROR     :   self._Skip,
1136        }
1137
1138        self._RawTable = self._Table
1139        self._Table = MetaFileStorage(self._RawTable.Cur, self.MetaFile, MODEL_FILE_DSC, True)
1140        self._DirectiveStack = []
1141        self._DirectiveEvalStack = []
1142        self._FileWithError = self.MetaFile
1143        self._FileLocalMacros = {}
1144        self._SectionsMacroDict = {}
1145        GlobalData.gPlatformDefines = {}
1146
1147        # Get all macro and PCD which has straitforward value
1148        self.__RetrievePcdValue()
1149        self._Content = self._RawTable.GetAll()
1150        self._ContentIndex = 0
1151        while self._ContentIndex < len(self._Content) :
1152            Id, self._ItemType, V1, V2, V3, S1, S2, Owner, BelongsToFile, self._From, \
1153                LineStart, ColStart, LineEnd, ColEnd, Enabled = self._Content[self._ContentIndex]
1154
1155            if self._From < 0:
1156                self._FileWithError = self.MetaFile
1157
1158            self._ContentIndex += 1
1159
1160            self._Scope = [[S1, S2]]
1161            self._LineIndex = LineStart - 1
1162            self._ValueList = [V1, V2, V3]
1163
1164            try:
1165                Processer[self._ItemType]()
1166            except EvaluationException as Excpt:
1167                #
1168                # Only catch expression evaluation error here. We need to report
1169                # the precise number of line on which the error occurred
1170                #
1171                pass
1172#                 EdkLogger.error('Parser', FORMAT_INVALID, "Invalid expression: %s" % str(Excpt),
1173#                                 File=self._FileWithError, ExtraData=' '.join(self._ValueList),
1174#                                 Line=self._LineIndex+1)
1175            except MacroException as Excpt:
1176                EdkLogger.error('Parser', FORMAT_INVALID, str(Excpt),
1177                                File=self._FileWithError, ExtraData=' '.join(self._ValueList),
1178                                Line=self._LineIndex+1)
1179
1180            if self._ValueList is None:
1181                continue
1182
1183            NewOwner = self._IdMapping.get(Owner, -1)
1184            self._Enabled = int((not self._DirectiveEvalStack) or (False not in self._DirectiveEvalStack))
1185            self._LastItem = self._Store(
1186                                self._ItemType,
1187                                self._ValueList[0],
1188                                self._ValueList[1],
1189                                self._ValueList[2],
1190                                S1,
1191                                S2,
1192                                NewOwner,
1193                                BelongsToFile,
1194                                self._From,
1195                                self._LineIndex+1,
1196                                -1,
1197                                self._LineIndex+1,
1198                                -1,
1199                                self._Enabled
1200                                )
1201            self._IdMapping[Id] = self._LastItem
1202
1203        RecordList = self._Table.GetAll()
1204
1205        self._RawTable.Drop()
1206        self._Table.Drop()
1207        for Record in RecordList:
1208            EccGlobalData.gDb.TblDsc.Insert(Record[1], Record[2], Record[3], Record[4], Record[5], Record[6], Record[7], Record[8], Record[9], Record[10], Record[11], Record[12], Record[13], Record[14])
1209        GlobalData.gPlatformDefines.update(self._FileLocalMacros)
1210        self._PostProcessed = True
1211        self._Content = None
1212
1213    def __ProcessSectionHeader(self):
1214        self._SectionName = self._ValueList[0]
1215        if self._SectionName in self.DataType:
1216            self._SectionType = self.DataType[self._SectionName]
1217        else:
1218            self._SectionType = MODEL_UNKNOWN
1219
1220    def __ProcessSubsectionHeader(self):
1221        self._SubsectionName = self._ValueList[0]
1222        if self._SubsectionName in self.DataType:
1223            self._SubsectionType = self.DataType[self._SubsectionName]
1224        else:
1225            self._SubsectionType = MODEL_UNKNOWN
1226
1227    def __RetrievePcdValue(self):
1228        Records = self._RawTable.Query(MODEL_PCD_FEATURE_FLAG, BelongsToItem=-1.0)
1229        for TokenSpaceGuid, PcdName, Value, Dummy2, Dummy3, ID, Line in Records:
1230            Value, DatumType, MaxDatumSize = AnalyzePcdData(Value)
1231            # Only use PCD whose value is straitforward (no macro and PCD)
1232            if self.SymbolPattern.findall(Value):
1233                continue
1234            Name = TokenSpaceGuid + '.' + PcdName
1235            # Don't use PCD with different values.
1236            if Name in self._Symbols and self._Symbols[Name] != Value:
1237                self._Symbols.pop(Name)
1238                continue
1239            self._Symbols[Name] = Value
1240
1241        Records = self._RawTable.Query(MODEL_PCD_FIXED_AT_BUILD, BelongsToItem=-1.0)
1242        for TokenSpaceGuid, PcdName, Value, Dummy2, Dummy3, ID, Line in Records:
1243            Value, DatumType, MaxDatumSize = AnalyzePcdData(Value)
1244            # Only use PCD whose value is straitforward (no macro and PCD)
1245            if self.SymbolPattern.findall(Value):
1246                continue
1247            Name = TokenSpaceGuid+'.'+PcdName
1248            # Don't use PCD with different values.
1249            if Name in self._Symbols and self._Symbols[Name] != Value:
1250                self._Symbols.pop(Name)
1251                continue
1252            self._Symbols[Name] = Value
1253
1254    def __ProcessDefine(self):
1255        if not self._Enabled:
1256            return
1257
1258        Type, Name, Value = self._ValueList
1259        Value = ReplaceMacro(Value, self._Macros, False)
1260        if self._ItemType == MODEL_META_DATA_DEFINE:
1261            if self._SectionType == MODEL_META_DATA_HEADER:
1262                self._FileLocalMacros[Name] = Value
1263            else:
1264                SectionDictKey = self._SectionType, self._Scope[0][0], self._Scope[0][1]
1265                if SectionDictKey not in self._SectionsMacroDict:
1266                    self._SectionsMacroDict[SectionDictKey] = {}
1267                SectionLocalMacros = self._SectionsMacroDict[SectionDictKey]
1268                SectionLocalMacros[Name] = Value
1269        elif self._ItemType == MODEL_META_DATA_GLOBAL_DEFINE:
1270            GlobalData.gEdkGlobal[Name] = Value
1271
1272        #
1273        # Keyword in [Defines] section can be used as Macros
1274        #
1275        if (self._ItemType == MODEL_META_DATA_HEADER) and (self._SectionType == MODEL_META_DATA_HEADER):
1276            self._FileLocalMacros[Name] = Value
1277
1278        self._ValueList = [Type, Name, Value]
1279
1280    def __ProcessDirective(self):
1281        Result = None
1282        if self._ItemType in [MODEL_META_DATA_CONDITIONAL_STATEMENT_IF,
1283                              MODEL_META_DATA_CONDITIONAL_STATEMENT_ELSEIF]:
1284            Macros = self._Macros
1285            Macros.update(GlobalData.gGlobalDefines)
1286            try:
1287                Result = ValueExpression(self._ValueList[1], Macros)()
1288            except SymbolNotFound as Exc:
1289                EdkLogger.debug(EdkLogger.DEBUG_5, str(Exc), self._ValueList[1])
1290                Result = False
1291            except WrnExpression as Excpt:
1292                #
1293                # Catch expression evaluation warning here. We need to report
1294                # the precise number of line and return the evaluation result
1295                #
1296                EdkLogger.warn('Parser', "Suspicious expression: %s" % str(Excpt),
1297                                File=self._FileWithError, ExtraData=' '.join(self._ValueList),
1298                                Line=self._LineIndex+1)
1299                Result = Excpt.result
1300            except BadExpression as Exc:
1301                EdkLogger.debug(EdkLogger.DEBUG_5, str(Exc), self._ValueList[1])
1302                Result = False
1303
1304        if self._ItemType in [MODEL_META_DATA_CONDITIONAL_STATEMENT_IF,
1305                              MODEL_META_DATA_CONDITIONAL_STATEMENT_IFDEF,
1306                              MODEL_META_DATA_CONDITIONAL_STATEMENT_IFNDEF]:
1307            self._DirectiveStack.append(self._ItemType)
1308            if self._ItemType == MODEL_META_DATA_CONDITIONAL_STATEMENT_IF:
1309                Result = bool(Result)
1310            else:
1311                Macro = self._ValueList[1]
1312                Macro = Macro[2:-1] if (Macro.startswith("$(") and Macro.endswith(")")) else Macro
1313                Result = Macro in self._Macros
1314                if self._ItemType == MODEL_META_DATA_CONDITIONAL_STATEMENT_IFNDEF:
1315                    Result = not Result
1316            self._DirectiveEvalStack.append(Result)
1317        elif self._ItemType == MODEL_META_DATA_CONDITIONAL_STATEMENT_ELSEIF:
1318            self._DirectiveStack.append(self._ItemType)
1319            self._DirectiveEvalStack[-1] = not self._DirectiveEvalStack[-1]
1320            self._DirectiveEvalStack.append(bool(Result))
1321        elif self._ItemType == MODEL_META_DATA_CONDITIONAL_STATEMENT_ELSE:
1322            self._DirectiveStack[-1] = self._ItemType
1323            self._DirectiveEvalStack[-1] = not self._DirectiveEvalStack[-1]
1324        elif self._ItemType == MODEL_META_DATA_CONDITIONAL_STATEMENT_ENDIF:
1325            # Back to the nearest !if/!ifdef/!ifndef
1326            while self._DirectiveStack:
1327                self._DirectiveEvalStack.pop()
1328                Directive = self._DirectiveStack.pop()
1329                if Directive in [MODEL_META_DATA_CONDITIONAL_STATEMENT_IF,
1330                                 MODEL_META_DATA_CONDITIONAL_STATEMENT_IFDEF,
1331                                 MODEL_META_DATA_CONDITIONAL_STATEMENT_ELSE,
1332                                 MODEL_META_DATA_CONDITIONAL_STATEMENT_IFNDEF]:
1333                    break
1334        elif self._ItemType == MODEL_META_DATA_INCLUDE:
1335            # The included file must be relative to workspace or same directory as DSC file
1336            __IncludeMacros = {}
1337            #
1338            # Allow using system environment variables  in path after !include
1339            #
1340            __IncludeMacros['WORKSPACE'] = GlobalData.gGlobalDefines['WORKSPACE']
1341
1342            #
1343            # Allow using MACROs comes from [Defines] section to keep compatible.
1344            #
1345            __IncludeMacros.update(self._Macros)
1346
1347            IncludedFile = NormPath(ReplaceMacro(self._ValueList[1], __IncludeMacros, RaiseError=True))
1348            #
1349            # First search the include file under the same directory as DSC file
1350            #
1351            IncludedFile1 = PathClass(IncludedFile, self.MetaFile.Dir)
1352            ErrorCode, ErrorInfo1 = IncludedFile1.Validate()
1353            if ErrorCode != 0:
1354                #
1355                # Also search file under the WORKSPACE directory
1356                #
1357                IncludedFile1 = PathClass(IncludedFile, GlobalData.gWorkspace)
1358                ErrorCode, ErrorInfo2 = IncludedFile1.Validate()
1359                if ErrorCode != 0:
1360                    EdkLogger.error('parser', ErrorCode, File=self._FileWithError,
1361                                    Line=self._LineIndex+1, ExtraData=ErrorInfo1 + "\n"+ ErrorInfo2)
1362
1363            self._FileWithError = IncludedFile1
1364
1365            IncludedFileTable = MetaFileStorage(self._Table.Cur, IncludedFile1, MODEL_FILE_DSC, True)
1366            Owner = self._Content[self._ContentIndex-1][0]
1367            Parser = DscParser(IncludedFile1, self._FileType, IncludedFileTable,
1368                               Owner=Owner, From=Owner)
1369
1370            # set the parser status with current status
1371            Parser._SectionName = self._SectionName
1372            Parser._SectionType = self._SectionType
1373            Parser._Scope = self._Scope
1374            Parser._Enabled = self._Enabled
1375            # Parse the included file
1376            Parser.Start()
1377
1378            # update current status with sub-parser's status
1379            self._SectionName = Parser._SectionName
1380            self._SectionType = Parser._SectionType
1381            self._Scope       = Parser._Scope
1382            self._Enabled     = Parser._Enabled
1383
1384            # Insert all records in the table for the included file into dsc file table
1385            Records = IncludedFileTable.GetAll()
1386            if Records:
1387                self._Content[self._ContentIndex:self._ContentIndex] = Records
1388                self._Content.pop(self._ContentIndex-1)
1389                self._ValueList = None
1390                self._ContentIndex -= 1
1391
1392    def __ProcessSkuId(self):
1393        self._ValueList = [ReplaceMacro(Value, self._Macros, RaiseError=True)
1394                           for Value in self._ValueList]
1395
1396    def __ProcessLibraryInstance(self):
1397        self._ValueList = [ReplaceMacro(Value, self._Macros) for Value in self._ValueList]
1398
1399    def __ProcessLibraryClass(self):
1400        self._ValueList[1] = ReplaceMacro(self._ValueList[1], self._Macros, RaiseError=True)
1401
1402    def __ProcessPcd(self):
1403        ValueList = GetSplitValueList(self._ValueList[2])
1404        #
1405        # PCD value can be an expression
1406        #
1407        if len(ValueList) > 1 and ValueList[1] == TAB_VOID:
1408            PcdValue = ValueList[0]
1409            try:
1410                ValueList[0] = ValueExpression(PcdValue, self._Macros)(True)
1411            except WrnExpression as Value:
1412                ValueList[0] = Value.result
1413        else:
1414            PcdValue = ValueList[-1]
1415            try:
1416                ValueList[-1] = ValueExpression(PcdValue, self._Macros)(True)
1417            except WrnExpression as Value:
1418                ValueList[-1] = Value.result
1419
1420            if ValueList[-1] == 'True':
1421                ValueList[-1] = '1'
1422            if ValueList[-1] == 'False':
1423                ValueList[-1] = '0'
1424
1425        self._ValueList[2] = '|'.join(ValueList)
1426
1427    def __ProcessComponent(self):
1428        self._ValueList[0] = ReplaceMacro(self._ValueList[0], self._Macros)
1429
1430    def __ProcessBuildOption(self):
1431        self._ValueList = [ReplaceMacro(Value, self._Macros, RaiseError=False)
1432                           for Value in self._ValueList]
1433
1434    _SectionParser = {
1435        MODEL_META_DATA_HEADER                          :   _DefineParser,
1436        MODEL_EFI_SKU_ID                                :   _SkuIdParser,
1437        MODEL_EFI_LIBRARY_INSTANCE                      :   _LibraryInstanceParser,
1438        MODEL_EFI_LIBRARY_CLASS                         :   _LibraryClassParser,
1439        MODEL_PCD_FIXED_AT_BUILD                        :   _PcdParser,
1440        MODEL_PCD_PATCHABLE_IN_MODULE                   :   _PcdParser,
1441        MODEL_PCD_FEATURE_FLAG                          :   _PcdParser,
1442        MODEL_PCD_DYNAMIC_DEFAULT                       :   _PcdParser,
1443        MODEL_PCD_DYNAMIC_HII                           :   _PcdParser,
1444        MODEL_PCD_DYNAMIC_VPD                           :   _PcdParser,
1445        MODEL_PCD_DYNAMIC_EX_DEFAULT                    :   _PcdParser,
1446        MODEL_PCD_DYNAMIC_EX_HII                        :   _PcdParser,
1447        MODEL_PCD_DYNAMIC_EX_VPD                        :   _PcdParser,
1448        MODEL_META_DATA_COMPONENT                       :   _ComponentParser,
1449        MODEL_META_DATA_BUILD_OPTION                    :   _BuildOptionParser,
1450        MODEL_UNKNOWN                                   :   MetaFileParser._Skip,
1451        MODEL_META_DATA_USER_EXTENSION                  :   MetaFileParser._Skip,
1452        MODEL_META_DATA_SECTION_HEADER                  :   MetaFileParser._SectionHeaderParser,
1453        MODEL_META_DATA_SUBSECTION_HEADER               :   _SubsectionHeaderParser,
1454    }
1455
1456    _Macros     = property(_GetMacros)
1457
1458## DEC file parser class
1459#
1460#   @param      FilePath        The path of platform description file
1461#   @param      FileType        The raw data of DSC file
1462#   @param      Table           Database used to retrieve module/package information
1463#   @param      Macros          Macros used for replacement in file
1464#
1465class DecParser(MetaFileParser):
1466    # DEC file supported data types (one type per section)
1467    DataType = {
1468        TAB_DEC_DEFINES.upper()                     :   MODEL_META_DATA_HEADER,
1469        TAB_DSC_DEFINES_DEFINE                      :   MODEL_META_DATA_DEFINE,
1470        TAB_INCLUDES.upper()                        :   MODEL_EFI_INCLUDE,
1471        TAB_LIBRARY_CLASSES.upper()                 :   MODEL_EFI_LIBRARY_CLASS,
1472        TAB_GUIDS.upper()                           :   MODEL_EFI_GUID,
1473        TAB_PPIS.upper()                            :   MODEL_EFI_PPI,
1474        TAB_PROTOCOLS.upper()                       :   MODEL_EFI_PROTOCOL,
1475        TAB_PCDS_FIXED_AT_BUILD_NULL.upper()        :   MODEL_PCD_FIXED_AT_BUILD,
1476        TAB_PCDS_PATCHABLE_IN_MODULE_NULL.upper()   :   MODEL_PCD_PATCHABLE_IN_MODULE,
1477        TAB_PCDS_FEATURE_FLAG_NULL.upper()          :   MODEL_PCD_FEATURE_FLAG,
1478        TAB_PCDS_DYNAMIC_NULL.upper()               :   MODEL_PCD_DYNAMIC,
1479        TAB_PCDS_DYNAMIC_EX_NULL.upper()            :   MODEL_PCD_DYNAMIC_EX,
1480    }
1481
1482    ## Constructor of DecParser
1483    #
1484    #  Initialize object of DecParser
1485    #
1486    #   @param      FilePath        The path of platform description file
1487    #   @param      FileType        The raw data of DSC file
1488    #   @param      Table           Database used to retrieve module/package information
1489    #   @param      Macros          Macros used for replacement in file
1490    #
1491    def __init__(self, FilePath, FileType, Table):
1492        # prevent re-initialization
1493        if hasattr(self, "_Table"):
1494            return
1495        MetaFileParser.__init__(self, FilePath, FileType, Table)
1496        self._Comments = []
1497        self._Version = 0x00010005  # Only EDK2 dec file is supported
1498        self.TblFile = EccGlobalData.gDb.TblFile
1499        self.FileID = -1
1500
1501    ## Parser starter
1502    def Start(self):
1503        Content = ''
1504        try:
1505            Content = open(str(self.MetaFile), 'r').readlines()
1506        except:
1507            EdkLogger.error("Parser", FILE_READ_FAILURE, ExtraData=self.MetaFile)
1508
1509        #
1510        # Insert a record for file
1511        #
1512        Filename = NormPath(self.MetaFile)
1513        FileID = self.TblFile.GetFileId(Filename)
1514        if FileID:
1515            self.FileID = FileID
1516        else:
1517            self.FileID = self.TblFile.InsertFile(Filename, MODEL_FILE_DEC)
1518
1519        for Index in range(0, len(Content)):
1520            Line, Comment = CleanString2(Content[Index])
1521            self._CurrentLine = Line
1522            self._LineIndex = Index
1523
1524            # save comment for later use
1525            if Comment:
1526                self._Comments.append((Comment, self._LineIndex+1))
1527            # skip empty line
1528            if Line == '':
1529                continue
1530
1531            # section header
1532            if Line[0] == TAB_SECTION_START and Line[-1] == TAB_SECTION_END:
1533                self._SectionHeaderParser()
1534                self._Comments = []
1535                continue
1536            elif len(self._SectionType) == 0:
1537                self._Comments = []
1538                continue
1539
1540            # section content
1541            self._ValueList = ['', '', '']
1542            self._SectionParser[self._SectionType[0]](self)
1543            if self._ValueList is None or self._ItemType == MODEL_META_DATA_DEFINE:
1544                self._ItemType = -1
1545                self._Comments = []
1546                continue
1547
1548            #
1549            # Model, Value1, Value2, Value3, Arch, BelongsToItem=-1, LineBegin=-1,
1550            # ColumnBegin=-1, LineEnd=-1, ColumnEnd=-1, FeatureFlag='', Enabled=-1
1551            #
1552            for Arch, ModuleType, Type in self._Scope:
1553                self._LastItem = self._Store(
1554                    Type,
1555                    self._ValueList[0],
1556                    self._ValueList[1],
1557                    self._ValueList[2],
1558                    Arch,
1559                    ModuleType,
1560                    self._Owner[-1],
1561                    self.FileID,
1562                    self._LineIndex+1,
1563                    -1,
1564                    self._LineIndex+1,
1565                    -1,
1566                    0
1567                    )
1568                for Comment, LineNo in self._Comments:
1569                    self._Store(
1570                        MODEL_META_DATA_COMMENT,
1571                        Comment,
1572                        self._ValueList[0],
1573                        self._ValueList[1],
1574                        Arch,
1575                        ModuleType,
1576                        self._LastItem,
1577                        self.FileID,
1578                        LineNo,
1579                        -1,
1580                        LineNo,
1581                        -1,
1582                        0
1583                        )
1584            self._Comments = []
1585        self._Done()
1586
1587    def _GetApplicableSectionMacro(self):
1588        Macros = {}
1589        for S1, S2, SectionType in self._Scope:
1590            for Scope1, Scope2 in [("COMMON", "COMMON"), ("COMMON", S2), (S1, "COMMON"), (S1, S2)]:
1591                if (SectionType, Scope1, Scope2) in self._SectionsMacroDict:
1592                    Macros.update(self._SectionsMacroDict[(SectionType, Scope1, Scope2)])
1593        return Macros
1594
1595    ## Section header parser
1596    #
1597    #   The section header is always in following format:
1598    #
1599    #       [section_name.arch<.platform|module_type>]
1600    #
1601    def _SectionHeaderParser(self):
1602        self._Scope = []
1603        self._SectionName = ''
1604        self._SectionType = []
1605        ArchList = set()
1606        for Item in GetSplitValueList(self._CurrentLine[1:-1], TAB_COMMA_SPLIT):
1607            if Item == '':
1608                continue
1609            ItemList = GetSplitValueList(Item, TAB_SPLIT)
1610
1611            # different types of PCD are permissible in one section
1612            self._SectionName = ItemList[0].upper()
1613            if self._SectionName in self.DataType:
1614                if self.DataType[self._SectionName] not in self._SectionType:
1615                    self._SectionType.append(self.DataType[self._SectionName])
1616            else:
1617                EdkLogger.warn("Parser", "Unrecognized section", File=self.MetaFile,
1618                                Line=self._LineIndex+1, ExtraData=self._CurrentLine)
1619                continue
1620
1621            if MODEL_PCD_FEATURE_FLAG in self._SectionType and len(self._SectionType) > 1:
1622                EdkLogger.error(
1623                            'Parser',
1624                            FORMAT_INVALID,
1625                            "%s must not be in the same section of other types of PCD" % TAB_PCDS_FEATURE_FLAG_NULL,
1626                            File=self.MetaFile,
1627                            Line=self._LineIndex+1,
1628                            ExtraData=self._CurrentLine
1629                            )
1630            # S1 is always Arch
1631            if len(ItemList) > 1:
1632                S1 = ItemList[1].upper()
1633            else:
1634                S1 = 'COMMON'
1635            ArchList.add(S1)
1636            # S2 may be Platform or ModuleType
1637            if len(ItemList) > 2:
1638                S2 = ItemList[2].upper()
1639            else:
1640                S2 = 'COMMON'
1641            if [S1, S2, self.DataType[self._SectionName]] not in self._Scope:
1642                self._Scope.append([S1, S2, self.DataType[self._SectionName]])
1643
1644        # 'COMMON' must not be used with specific ARCHs at the same section
1645        if 'COMMON' in ArchList and len(ArchList) > 1:
1646            EdkLogger.error('Parser', FORMAT_INVALID, "'common' ARCH must not be used with specific ARCHs",
1647                            File=self.MetaFile, Line=self._LineIndex+1, ExtraData=self._CurrentLine)
1648
1649    ## [guids], [ppis] and [protocols] section parser
1650    @ParseMacro
1651    def _GuidParser(self):
1652        TokenList = GetSplitValueList(self._CurrentLine, TAB_EQUAL_SPLIT, 1)
1653        if len(TokenList) < 2:
1654            EdkLogger.error('Parser', FORMAT_INVALID, "No GUID name or value specified",
1655                            ExtraData=self._CurrentLine + " (<CName> = <GuidValueInCFormat>)",
1656                            File=self.MetaFile, Line=self._LineIndex+1)
1657        if TokenList[0] == '':
1658            EdkLogger.error('Parser', FORMAT_INVALID, "No GUID name specified",
1659                            ExtraData=self._CurrentLine + " (<CName> = <GuidValueInCFormat>)",
1660                            File=self.MetaFile, Line=self._LineIndex+1)
1661        if TokenList[1] == '':
1662            EdkLogger.error('Parser', FORMAT_INVALID, "No GUID value specified",
1663                            ExtraData=self._CurrentLine + " (<CName> = <GuidValueInCFormat>)",
1664                            File=self.MetaFile, Line=self._LineIndex+1)
1665        if TokenList[1][0] != '{' or TokenList[1][-1] != '}' or GuidStructureStringToGuidString(TokenList[1]) == '':
1666            EdkLogger.error('Parser', FORMAT_INVALID, "Invalid GUID value format",
1667                            ExtraData=self._CurrentLine + \
1668                                      " (<CName> = <GuidValueInCFormat:{8,4,4,{2,2,2,2,2,2,2,2}}>)",
1669                            File=self.MetaFile, Line=self._LineIndex+1)
1670        self._ValueList[0] = TokenList[0]
1671        #Parse the Guid value format
1672        GuidValueList = TokenList[1].strip(' {}').split(',')
1673        Index = 0
1674        HexList = []
1675        if len(GuidValueList) == 11:
1676            for GuidValue in GuidValueList:
1677                GuidValue = GuidValue.strip()
1678                if GuidValue.startswith('0x') or GuidValue.startswith('0X'):
1679                    HexList.append('0x' + str(GuidValue[2:]))
1680                    Index += 1
1681                    continue
1682                else:
1683                    if GuidValue.startswith('{'):
1684                        GuidValue = GuidValue.lstrip(' {')
1685                        HexList.append('0x' + str(GuidValue[2:]))
1686                        Index += 1
1687            self._ValueList[1] = "{ %s, %s, %s, { %s, %s, %s, %s, %s, %s, %s, %s }}" % (HexList[0], HexList[1], HexList[2], HexList[3], HexList[4], HexList[5], HexList[6], HexList[7], HexList[8], HexList[9], HexList[10])
1688        else:
1689            EdkLogger.error('Parser', FORMAT_INVALID, "Invalid GUID value format",
1690                            ExtraData=self._CurrentLine + \
1691                                      " (<CName> = <GuidValueInCFormat:{8,4,4,{2,2,2,2,2,2,2,2}}>)",
1692                            File=self.MetaFile, Line=self._LineIndex+1)
1693            self._ValueList[0] = ''
1694
1695    ## PCD sections parser
1696    #
1697    #   [PcdsFixedAtBuild]
1698    #   [PcdsPatchableInModule]
1699    #   [PcdsFeatureFlag]
1700    #   [PcdsDynamicEx
1701    #   [PcdsDynamic]
1702    #
1703    @ParseMacro
1704    def _PcdParser(self):
1705        TokenList = GetSplitValueList(self._CurrentLine, TAB_VALUE_SPLIT, 1)
1706        self._ValueList[0:1] = GetSplitValueList(TokenList[0], TAB_SPLIT)
1707        # check PCD information
1708        if self._ValueList[0] == '' or self._ValueList[1] == '':
1709            EdkLogger.error('Parser', FORMAT_INVALID, "No token space GUID or PCD name specified",
1710                            ExtraData=self._CurrentLine + \
1711                                      " (<TokenSpaceGuidCName>.<PcdCName>|<DefaultValue>|<DatumType>|<Token>)",
1712                            File=self.MetaFile, Line=self._LineIndex+1)
1713        # check PCD datum information
1714        if len(TokenList) < 2 or TokenList[1] == '':
1715            EdkLogger.error('Parser', FORMAT_INVALID, "No PCD Datum information given",
1716                            ExtraData=self._CurrentLine + \
1717                                      " (<TokenSpaceGuidCName>.<PcdCName>|<DefaultValue>|<DatumType>|<Token>)",
1718                            File=self.MetaFile, Line=self._LineIndex+1)
1719
1720
1721        ValueRe  = re.compile(r'^\s*L?\".*\|.*\"')
1722        PtrValue = ValueRe.findall(TokenList[1])
1723
1724        # Has VOID* type string, may contain "|" character in the string.
1725        if len(PtrValue) != 0:
1726            ptrValueList = re.sub(ValueRe, '', TokenList[1])
1727            ValueList    = GetSplitValueList(ptrValueList)
1728            ValueList[0] = PtrValue[0]
1729        else:
1730            ValueList = GetSplitValueList(TokenList[1])
1731
1732
1733        # check if there's enough datum information given
1734        if len(ValueList) != 3:
1735            EdkLogger.error('Parser', FORMAT_INVALID, "Invalid PCD Datum information given",
1736                            ExtraData=self._CurrentLine + \
1737                                      " (<TokenSpaceGuidCName>.<PcdCName>|<DefaultValue>|<DatumType>|<Token>)",
1738                            File=self.MetaFile, Line=self._LineIndex+1)
1739        # check default value
1740        if ValueList[0] == '':
1741            EdkLogger.error('Parser', FORMAT_INVALID, "Missing DefaultValue in PCD Datum information",
1742                            ExtraData=self._CurrentLine + \
1743                                      " (<TokenSpaceGuidCName>.<PcdCName>|<DefaultValue>|<DatumType>|<Token>)",
1744                            File=self.MetaFile, Line=self._LineIndex+1)
1745        # check datum type
1746        if ValueList[1] == '':
1747            EdkLogger.error('Parser', FORMAT_INVALID, "Missing DatumType in PCD Datum information",
1748                            ExtraData=self._CurrentLine + \
1749                                      " (<TokenSpaceGuidCName>.<PcdCName>|<DefaultValue>|<DatumType>|<Token>)",
1750                            File=self.MetaFile, Line=self._LineIndex+1)
1751        # check token of the PCD
1752        if ValueList[2] == '':
1753            EdkLogger.error('Parser', FORMAT_INVALID, "Missing Token in PCD Datum information",
1754                            ExtraData=self._CurrentLine + \
1755                                      " (<TokenSpaceGuidCName>.<PcdCName>|<DefaultValue>|<DatumType>|<Token>)",
1756                            File=self.MetaFile, Line=self._LineIndex+1)
1757        # check format of default value against the datum type
1758        IsValid, Cause = CheckPcdDatum(ValueList[1], ValueList[0])
1759        if not IsValid:
1760            EdkLogger.error('Parser', FORMAT_INVALID, Cause, ExtraData=self._CurrentLine,
1761                            File=self.MetaFile, Line=self._LineIndex+1)
1762
1763        if EccGlobalData.gConfig.UniCheckPCDInfo == '1' or EccGlobalData.gConfig.UniCheckAll == '1' or EccGlobalData.gConfig.CheckAll == '1':
1764            # check Description, Prompt information
1765            PatternDesc = re.compile('##\s*([\x21-\x7E\s]*)', re.S)
1766            PatternPrompt = re.compile('#\s+@Prompt\s+([\x21-\x7E\s]*)', re.S)
1767            Description = None
1768            Prompt = None
1769            # check @ValidRange, @ValidList and @Expression format valid
1770            ErrorCodeValid = '0x0 <= %s <= 0xFFFFFFFF'
1771            PatternValidRangeIn = '(NOT)?\s*(\d+\s*-\s*\d+|0[xX][a-fA-F0-9]+\s*-\s*0[xX][a-fA-F0-9]+|LT\s*\d+|LT\s*0[xX][a-fA-F0-9]+|GT\s*\d+|GT\s*0[xX][a-fA-F0-9]+|LE\s*\d+|LE\s*0[xX][a-fA-F0-9]+|GE\s*\d+|GE\s*0[xX][a-fA-F0-9]+|XOR\s*\d+|XOR\s*0[xX][a-fA-F0-9]+|EQ\s*\d+|EQ\s*0[xX][a-fA-F0-9]+)'
1772            PatternValidRng = re.compile('^' + '(NOT)?\s*' + PatternValidRangeIn + '$')
1773            for Comment in self._Comments:
1774                Comm = Comment[0].strip()
1775                if not Comm:
1776                    continue
1777                if not Description:
1778                    Description = PatternDesc.findall(Comm)
1779                if not Prompt:
1780                    Prompt = PatternPrompt.findall(Comm)
1781                if Comm[0] == '#':
1782                    ValidFormt = Comm.lstrip('#')
1783                    ValidFormt = ValidFormt.lstrip()
1784                    if ValidFormt[0:11] == '@ValidRange':
1785                        ValidFormt = ValidFormt[11:]
1786                        ValidFormt = ValidFormt.lstrip()
1787                        try:
1788                            ErrorCode, Expression = ValidFormt.split('|', 1)
1789                        except ValueError:
1790                            ErrorCode = '0x0'
1791                            Expression = ValidFormt
1792                        ErrorCode, Expression = ErrorCode.strip(), Expression.strip()
1793                        try:
1794                            if not eval(ErrorCodeValid % ErrorCode):
1795                                EdkLogger.warn('Parser', '@ValidRange ErrorCode(%s) of PCD %s is not valid UINT32 value.' % (ErrorCode, TokenList[0]))
1796                        except:
1797                            EdkLogger.warn('Parser', '@ValidRange ErrorCode(%s) of PCD %s is not valid UINT32 value.' % (ErrorCode, TokenList[0]))
1798                        if not PatternValidRng.search(Expression):
1799                            EdkLogger.warn('Parser', '@ValidRange Expression(%s) of PCD %s is incorrect format.' % (Expression, TokenList[0]))
1800                    if ValidFormt[0:10] == '@ValidList':
1801                        ValidFormt = ValidFormt[10:]
1802                        ValidFormt = ValidFormt.lstrip()
1803                        try:
1804                            ErrorCode, Expression = ValidFormt.split('|', 1)
1805                        except ValueError:
1806                            ErrorCode = '0x0'
1807                            Expression = ValidFormt
1808                        ErrorCode, Expression = ErrorCode.strip(), Expression.strip()
1809                        try:
1810                            if not eval(ErrorCodeValid % ErrorCode):
1811                                EdkLogger.warn('Parser', '@ValidList ErrorCode(%s) of PCD %s is not valid UINT32 value.' % (ErrorCode, TokenList[0]))
1812                        except:
1813                            EdkLogger.warn('Parser', '@ValidList ErrorCode(%s) of PCD %s is not valid UINT32 value.' % (ErrorCode, TokenList[0]))
1814                        Values = Expression.split(',')
1815                        for Value in Values:
1816                            Value = Value.strip()
1817                            try:
1818                                eval(Value)
1819                            except:
1820                                EdkLogger.warn('Parser', '@ValidList Expression of PCD %s include a invalid value(%s).' % (TokenList[0], Value))
1821                                break
1822                    if ValidFormt[0:11] == '@Expression':
1823                        ValidFormt = ValidFormt[11:]
1824                        ValidFormt = ValidFormt.lstrip()
1825                        try:
1826                            ErrorCode, Expression = ValidFormt.split('|', 1)
1827                        except ValueError:
1828                            ErrorCode = '0x0'
1829                            Expression = ValidFormt
1830                        ErrorCode, Expression = ErrorCode.strip(), Expression.strip()
1831                        try:
1832                            if not eval(ErrorCodeValid % ErrorCode):
1833                                EdkLogger.warn('Parser', '@Expression ErrorCode(%s) of PCD %s is not valid UINT32 value.' % (ErrorCode, TokenList[0]))
1834                        except:
1835                            EdkLogger.warn('Parser', '@Expression ErrorCode(%s) of PCD %s is not valid UINT32 value.' % (ErrorCode, TokenList[0]))
1836                        if not Expression:
1837                            EdkLogger.warn('Parser', '@Expression Expression of PCD %s is incorrect format.' % TokenList[0])
1838            if not Description:
1839                EdkLogger.warn('Parser', 'PCD %s Description information is not provided.' % TokenList[0])
1840            if not Prompt:
1841                EdkLogger.warn('Parser', 'PCD %s Prompt information is not provided.' % TokenList[0])
1842            # check Description, Prompt localization information
1843            if self._UniObj:
1844                self._UniObj.CheckPcdInfo(TokenList[0])
1845
1846        if ValueList[0] in ['True', 'true', 'TRUE']:
1847            ValueList[0] = '1'
1848        elif ValueList[0] in ['False', 'false', 'FALSE']:
1849            ValueList[0] = '0'
1850
1851        self._ValueList[2] = ValueList[0].strip() + '|' + ValueList[1].strip() + '|' + ValueList[2].strip()
1852
1853    _SectionParser = {
1854        MODEL_META_DATA_HEADER          :   MetaFileParser._DefineParser,
1855        MODEL_EFI_INCLUDE               :   MetaFileParser._PathParser,
1856        MODEL_EFI_LIBRARY_CLASS         :   MetaFileParser._PathParser,
1857        MODEL_EFI_GUID                  :   _GuidParser,
1858        MODEL_EFI_PPI                   :   _GuidParser,
1859        MODEL_EFI_PROTOCOL              :   _GuidParser,
1860        MODEL_PCD_FIXED_AT_BUILD        :   _PcdParser,
1861        MODEL_PCD_PATCHABLE_IN_MODULE   :   _PcdParser,
1862        MODEL_PCD_FEATURE_FLAG          :   _PcdParser,
1863        MODEL_PCD_DYNAMIC               :   _PcdParser,
1864        MODEL_PCD_DYNAMIC_EX            :   _PcdParser,
1865        MODEL_UNKNOWN                   :   MetaFileParser._Skip,
1866        MODEL_META_DATA_USER_EXTENSION  :   MetaFileParser._Skip,
1867    }
1868
1869
1870## Fdf
1871#
1872# This class defined the structure used in Fdf object
1873#
1874# @param Filename:      Input value for Ffilename of Fdf file, default is None
1875# @param WorkspaceDir:  Input value for current workspace directory, default is None
1876#
1877class Fdf(object):
1878    def __init__(self, Filename = None, IsToDatabase = False, WorkspaceDir = None, Database = None):
1879        self.WorkspaceDir = WorkspaceDir
1880        self.IsToDatabase = IsToDatabase
1881
1882        self.Cur = Database.Cur
1883        self.TblFile = Database.TblFile
1884        self.TblFdf = Database.TblFdf
1885        self.FileID = -1
1886        self.FileList = {}
1887
1888        #
1889        # Load Fdf file if filename is not None
1890        #
1891        if Filename is not None:
1892            try:
1893                self.LoadFdfFile(Filename)
1894            except Exception:
1895                pass
1896
1897    #
1898    # Insert a FDF file record into database
1899    #
1900    def InsertFile(self, Filename):
1901        FileID = -1
1902        Filename = NormPath(Filename)
1903        if Filename not in self.FileList:
1904            FileID = self.TblFile.InsertFile(Filename, MODEL_FILE_FDF)
1905            self.FileList[Filename] = FileID
1906
1907        return self.FileList[Filename]
1908
1909
1910    ## Load Fdf file
1911    #
1912    # Load the file if it exists
1913    #
1914    # @param Filename:  Input value for filename of Fdf file
1915    #
1916    def LoadFdfFile(self, Filename):
1917        FileList = []
1918        #
1919        # Parse Fdf file
1920        #
1921        Filename = NormPath(Filename)
1922        Fdf = FdfParser(Filename)
1923        Fdf.ParseFile()
1924
1925        #
1926        # Insert inf file and pcd information
1927        #
1928        if self.IsToDatabase:
1929            (Model, Value1, Value2, Value3, Scope1, Scope2, BelongsToItem, BelongsToFile, StartLine, StartColumn, EndLine, EndColumn, Enabled) = \
1930            (0, '', '', '', 'COMMON', 'COMMON', -1, -1, -1, -1, -1, -1, 0)
1931            for Index in range(0, len(Fdf.Profile.PcdDict)):
1932                pass
1933            for Key in Fdf.Profile.PcdDict.keys():
1934                Model = MODEL_PCD
1935                Value1 = Key[1]
1936                Value2 = Key[0]
1937                FileName = Fdf.Profile.PcdFileLineDict[Key][0]
1938                StartLine = Fdf.Profile.PcdFileLineDict[Key][1]
1939                BelongsToFile = self.InsertFile(FileName)
1940                self.TblFdf.Insert(Model, Value1, Value2, Value3, Scope1, Scope2, BelongsToItem, BelongsToFile, StartLine, StartColumn, EndLine, EndColumn, Enabled)
1941            for Index in range(0, len(Fdf.Profile.InfList)):
1942                Model = MODEL_META_DATA_COMPONENT
1943                Value1 = Fdf.Profile.InfList[Index]
1944                Value2 = ''
1945                FileName = Fdf.Profile.InfFileLineList[Index][0]
1946                StartLine = Fdf.Profile.InfFileLineList[Index][1]
1947                BelongsToFile = self.InsertFile(FileName)
1948                self.TblFdf.Insert(Model, Value1, Value2, Value3, Scope1, Scope2, BelongsToItem, BelongsToFile, StartLine, StartColumn, EndLine, EndColumn, Enabled)
1949
1950class UniParser(object):
1951    # IsExtraUni defined the UNI file is Module UNI or extra Module UNI
1952    # IsModuleUni defined the UNI file is Module UNI or Package UNI
1953    def __init__(self, FilePath, IsExtraUni=False, IsModuleUni=True):
1954        self.FilePath = FilePath
1955        self.FileName = os.path.basename(FilePath)
1956        self.IsExtraUni = IsExtraUni
1957        self.IsModuleUni = IsModuleUni
1958        self.FileIn = None
1959        self.Missing = []
1960        self.__read()
1961
1962    def __read(self):
1963        try:
1964            self.FileIn = CodecOpenLongFilePath(self.FilePath, Mode='rb', Encoding='utf_8').read()
1965        except UnicodeError:
1966            self.FileIn = CodecOpenLongFilePath(self.FilePath, Mode='rb', Encoding='utf_16').read()
1967        except UnicodeError:
1968            self.FileIn = CodecOpenLongFilePath(self.FilePath, Mode='rb', Encoding='utf_16_le').read()
1969        except IOError:
1970            self.FileIn = ""
1971
1972    def Start(self):
1973        if self.IsModuleUni:
1974            if self.IsExtraUni:
1975                ModuleName = self.CheckKeyValid('STR_PROPERTIES_MODULE_NAME')
1976                self.PrintLog('STR_PROPERTIES_MODULE_NAME', ModuleName)
1977            else:
1978                ModuleAbstract = self.CheckKeyValid('STR_MODULE_ABSTRACT')
1979                self.PrintLog('STR_MODULE_ABSTRACT', ModuleAbstract)
1980                ModuleDescription = self.CheckKeyValid('STR_MODULE_DESCRIPTION')
1981                self.PrintLog('STR_MODULE_DESCRIPTION', ModuleDescription)
1982        else:
1983            if self.IsExtraUni:
1984                PackageName = self.CheckKeyValid('STR_PROPERTIES_PACKAGE_NAME')
1985                self.PrintLog('STR_PROPERTIES_PACKAGE_NAME', PackageName)
1986            else:
1987                PackageAbstract = self.CheckKeyValid('STR_PACKAGE_ABSTRACT')
1988                self.PrintLog('STR_PACKAGE_ABSTRACT', PackageAbstract)
1989                PackageDescription = self.CheckKeyValid('STR_PACKAGE_DESCRIPTION')
1990                self.PrintLog('STR_PACKAGE_DESCRIPTION', PackageDescription)
1991
1992    def CheckKeyValid(self, Key, Contents=None):
1993        if not Contents:
1994            Contents = self.FileIn
1995        KeyPattern = re.compile('#string\s+%s\s+.*?#language.*?".*?"' % Key, re.S)
1996        if KeyPattern.search(Contents):
1997            return True
1998        return False
1999
2000    def CheckPcdInfo(self, PcdCName):
2001        PromptKey = 'STR_%s_PROMPT' % PcdCName.replace('.', '_')
2002        PcdPrompt = self.CheckKeyValid(PromptKey)
2003        self.PrintLog(PromptKey, PcdPrompt)
2004        HelpKey = 'STR_%s_HELP' % PcdCName.replace('.', '_')
2005        PcdHelp = self.CheckKeyValid(HelpKey)
2006        self.PrintLog(HelpKey, PcdHelp)
2007
2008    def PrintLog(self, Key, Value):
2009        if not Value and Key not in self.Missing:
2010            Msg = '%s is missing in the %s file.' % (Key, self.FileName)
2011            EdkLogger.warn('Parser', Msg)
2012            EccGlobalData.gDb.TblReport.Insert(EccToolError.ERROR_GENERAL_CHECK_UNI_HELP_INFO, OtherMsg=Msg, BelongsToTable='File', BelongsToItem=-2)
2013            self.Missing.append(Key)
2014
2015##
2016#
2017# This acts like the main() function for the script, unless it is 'import'ed into another
2018# script.
2019#
2020if __name__ == '__main__':
2021    pass
2022
2023