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