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    SubSectionDefineKeywords = [
787        "FILE_GUID"
788    ]
789
790    SymbolPattern = ValueExpression.SymbolPattern
791
792    ## Constructor of DscParser
793    #
794    #  Initialize object of DscParser
795    #
796    #   @param      FilePath        The path of platform description file
797    #   @param      FileType        The raw data of DSC file
798    #   @param      Table           Database used to retrieve module/package information
799    #   @param      Macros          Macros used for replacement in file
800    #   @param      Owner           Owner ID (for sub-section parsing)
801    #   @param      From            ID from which the data comes (for !INCLUDE directive)
802    #
803    def __init__(self, FilePath, FileType, Table, Owner=-1, From=-1):
804        # prevent re-initialization
805        if hasattr(self, "_Table"):
806            return
807        MetaFileParser.__init__(self, FilePath, FileType, Table, Owner, From)
808        self._Version = 0x00010005  # Only EDK2 dsc file is supported
809        # to store conditional directive evaluation result
810        self._DirectiveStack = []
811        self._DirectiveEvalStack = []
812        self._Enabled = 1
813
814        # Final valid replacable symbols
815        self._Symbols = {}
816        #
817        #  Map the ID between the original table and new table to track
818        #  the owner item
819        #
820        self._IdMapping = {-1:-1}
821
822        self.TblFile = EccGlobalData.gDb.TblFile
823        self.FileID = -1
824
825    ## Parser starter
826    def Start(self):
827        Content = ''
828        try:
829            Content = open(str(self.MetaFile.Path), 'r').readlines()
830        except:
831            EdkLogger.error("Parser", FILE_READ_FAILURE, ExtraData=self.MetaFile)
832        #
833        # Insert a record for file
834        #
835        Filename = NormPath(self.MetaFile.Path)
836        FileID = self.TblFile.GetFileId(Filename)
837        if FileID:
838            self.FileID = FileID
839        else:
840            self.FileID = self.TblFile.InsertFile(Filename, MODEL_FILE_DSC)
841
842
843        for Index in range(0, len(Content)):
844            Line = CleanString(Content[Index])
845            # skip empty line
846            if Line == '':
847                continue
848
849            self._CurrentLine = Line
850            self._LineIndex = Index
851            if self._InSubsection and self._Owner[-1] == -1:
852                self._Owner.append(self._LastItem)
853
854            # section header
855            if Line[0] == TAB_SECTION_START and Line[-1] == TAB_SECTION_END:
856                self._SectionType = MODEL_META_DATA_SECTION_HEADER
857            # subsection ending
858            elif Line[0] == '}' and self._InSubsection:
859                self._InSubsection = False
860                self._SubsectionType = MODEL_UNKNOWN
861                self._SubsectionName = ''
862                self._Owner[-1] = -1
863                continue
864            # subsection header
865            elif Line[0] == TAB_OPTION_START and Line[-1] == TAB_OPTION_END:
866                self._SubsectionType = MODEL_META_DATA_SUBSECTION_HEADER
867            # directive line
868            elif Line[0] == '!':
869                self._DirectiveParser()
870                continue
871
872            if self._InSubsection:
873                SectionType = self._SubsectionType
874            else:
875                SectionType = self._SectionType
876            self._ItemType = SectionType
877
878            self._ValueList = ['', '', '']
879            self._SectionParser[SectionType](self)
880            if self._ValueList == None:
881                continue
882            #
883            # Model, Value1, Value2, Value3, Arch, ModuleType, BelongsToItem=-1, BelongsToFile=-1,
884            # LineBegin=-1, ColumnBegin=-1, LineEnd=-1, ColumnEnd=-1, Enabled=-1
885            #
886            for Arch, ModuleType in self._Scope:
887                self._LastItem = self._Store(
888                                        self._ItemType,
889                                        self._ValueList[0],
890                                        self._ValueList[1],
891                                        self._ValueList[2],
892                                        Arch,
893                                        ModuleType,
894                                        self._Owner[-1],
895                                        self.FileID,
896                                        self._From,
897                                        self._LineIndex+1,
898                                        -1,
899                                        self._LineIndex+1,
900                                        -1,
901                                        self._Enabled
902                                        )
903
904        if self._DirectiveStack:
905            Type, Line, Text = self._DirectiveStack[-1]
906            EdkLogger.error('Parser', FORMAT_INVALID, "No matching '!endif' found",
907                            ExtraData=Text, File=self.MetaFile, Line=Line)
908        self._Done()
909
910    ## <subsection_header> parser
911    def _SubsectionHeaderParser(self):
912        self._SubsectionName = self._CurrentLine[1:-1].upper()
913        if self._SubsectionName in self.DataType:
914            self._SubsectionType = self.DataType[self._SubsectionName]
915        else:
916            self._SubsectionType = MODEL_UNKNOWN
917            EdkLogger.warn("Parser", "Unrecognized sub-section", File=self.MetaFile,
918                           Line=self._LineIndex+1, ExtraData=self._CurrentLine)
919        self._ValueList[0] = self._SubsectionName
920
921    ## Directive statement parser
922    def _DirectiveParser(self):
923        self._ValueList = ['','','']
924        TokenList = GetSplitValueList(self._CurrentLine, ' ', 1)
925        self._ValueList[0:len(TokenList)] = TokenList
926
927        # Syntax check
928        DirectiveName = self._ValueList[0].upper()
929        if DirectiveName not in self.DataType:
930            EdkLogger.error("Parser", FORMAT_INVALID, "Unknown directive [%s]" % DirectiveName,
931                            File=self.MetaFile, Line=self._LineIndex+1)
932        if DirectiveName in ['!IF', '!IFDEF', '!INCLUDE', '!IFNDEF', '!ELSEIF'] and self._ValueList[1] == '':
933            EdkLogger.error("Parser", FORMAT_INVALID, "Missing expression",
934                            File=self.MetaFile, Line=self._LineIndex+1,
935                            ExtraData=self._CurrentLine)
936
937        ItemType = self.DataType[DirectiveName]
938        if ItemType == MODEL_META_DATA_CONDITIONAL_STATEMENT_ENDIF:
939            # Remove all directives between !if and !endif, including themselves
940            while self._DirectiveStack:
941                # Remove any !else or !elseif
942                DirectiveInfo = self._DirectiveStack.pop()
943                if DirectiveInfo[0] in [MODEL_META_DATA_CONDITIONAL_STATEMENT_IF,
944                                        MODEL_META_DATA_CONDITIONAL_STATEMENT_IFDEF,
945                                        MODEL_META_DATA_CONDITIONAL_STATEMENT_IFNDEF]:
946                    break
947            else:
948                EdkLogger.error("Parser", FORMAT_INVALID, "Redundant '!endif'",
949                                File=self.MetaFile, Line=self._LineIndex+1,
950                                ExtraData=self._CurrentLine)
951        elif ItemType != MODEL_META_DATA_INCLUDE:
952            # Break if there's a !else is followed by a !elseif
953            if ItemType == MODEL_META_DATA_CONDITIONAL_STATEMENT_ELSEIF and \
954               self._DirectiveStack and \
955               self._DirectiveStack[-1][0] == MODEL_META_DATA_CONDITIONAL_STATEMENT_ELSE:
956                EdkLogger.error("Parser", FORMAT_INVALID, "'!elseif' after '!else'",
957                                File=self.MetaFile, Line=self._LineIndex+1,
958                                ExtraData=self._CurrentLine)
959            self._DirectiveStack.append((ItemType, self._LineIndex+1, self._CurrentLine))
960        elif self._From > 0:
961            EdkLogger.error('Parser', FORMAT_INVALID,
962                            "No '!include' allowed in included file",
963                            ExtraData=self._CurrentLine, File=self.MetaFile,
964                            Line=self._LineIndex+1)
965
966        #
967        # Model, Value1, Value2, Value3, Arch, ModuleType, BelongsToItem=-1, BelongsToFile=-1,
968        # LineBegin=-1, ColumnBegin=-1, LineEnd=-1, ColumnEnd=-1, Enabled=-1
969        #
970        self._LastItem = self._Store(
971                                ItemType,
972                                self._ValueList[0],
973                                self._ValueList[1],
974                                self._ValueList[2],
975                                'COMMON',
976                                'COMMON',
977                                self._Owner[-1],
978                                self.FileID,
979                                self._From,
980                                self._LineIndex+1,
981                                -1,
982                                self._LineIndex+1,
983                                -1,
984                                0
985                                )
986
987    ## [defines] section parser
988    @ParseMacro
989    def _DefineParser(self):
990        TokenList = GetSplitValueList(self._CurrentLine, TAB_EQUAL_SPLIT, 1)
991        self._ValueList[1:len(TokenList)] = TokenList
992
993        # Syntax check
994        if not self._ValueList[1]:
995            EdkLogger.error('Parser', FORMAT_INVALID, "No name specified",
996                            ExtraData=self._CurrentLine, File=self.MetaFile, Line=self._LineIndex+1)
997        if not self._ValueList[2]:
998            EdkLogger.error('Parser', FORMAT_INVALID, "No value specified",
999                            ExtraData=self._CurrentLine, File=self.MetaFile, Line=self._LineIndex+1)
1000        if (not self._ValueList[1] in self.DefineKeywords and
1001            (self._InSubsection and self._ValueList[1] not in self.SubSectionDefineKeywords)):
1002            EdkLogger.error('Parser', FORMAT_INVALID,
1003                            "Unknown keyword found: %s. "
1004                            "If this is a macro you must "
1005                            "add it as a DEFINE in the DSC" % self._ValueList[1],
1006                            ExtraData=self._CurrentLine, File=self.MetaFile, Line=self._LineIndex+1)
1007        self._Defines[self._ValueList[1]] = self._ValueList[2]
1008        self._ItemType = self.DataType[TAB_DSC_DEFINES.upper()]
1009
1010    @ParseMacro
1011    def _SkuIdParser(self):
1012        TokenList = GetSplitValueList(self._CurrentLine, TAB_VALUE_SPLIT)
1013        if len(TokenList) != 2:
1014            EdkLogger.error('Parser', FORMAT_INVALID, "Correct format is '<Integer>|<UiName>'",
1015                            ExtraData=self._CurrentLine, File=self.MetaFile, Line=self._LineIndex+1)
1016        self._ValueList[0:len(TokenList)] = TokenList
1017
1018    ## Parse Edk style of library modules
1019    def _LibraryInstanceParser(self):
1020        self._ValueList[0] = self._CurrentLine
1021
1022    ## PCD sections parser
1023    #
1024    #   [PcdsFixedAtBuild]
1025    #   [PcdsPatchableInModule]
1026    #   [PcdsFeatureFlag]
1027    #   [PcdsDynamicEx
1028    #   [PcdsDynamicExDefault]
1029    #   [PcdsDynamicExVpd]
1030    #   [PcdsDynamicExHii]
1031    #   [PcdsDynamic]
1032    #   [PcdsDynamicDefault]
1033    #   [PcdsDynamicVpd]
1034    #   [PcdsDynamicHii]
1035    #
1036    @ParseMacro
1037    def _PcdParser(self):
1038        TokenList = GetSplitValueList(self._CurrentLine, TAB_VALUE_SPLIT, 1)
1039        self._ValueList[0:1] = GetSplitValueList(TokenList[0], TAB_SPLIT)
1040        if len(TokenList) == 2:
1041            self._ValueList[2] = TokenList[1]
1042        if self._ValueList[0] == '' or self._ValueList[1] == '':
1043            EdkLogger.error('Parser', FORMAT_INVALID, "No token space GUID or PCD name specified",
1044                            ExtraData=self._CurrentLine + " (<TokenSpaceGuidCName>.<TokenCName>|<PcdValue>)",
1045                            File=self.MetaFile, Line=self._LineIndex+1)
1046        if self._ValueList[2] == '':
1047            EdkLogger.error('Parser', FORMAT_INVALID, "No PCD value given",
1048                            ExtraData=self._CurrentLine + " (<TokenSpaceGuidCName>.<TokenCName>|<PcdValue>)",
1049                            File=self.MetaFile, Line=self._LineIndex+1)
1050        # if value are 'True', 'true', 'TRUE' or 'False', 'false', 'FALSE', replace with integer 1 or 0.
1051        DscPcdValueList = GetSplitValueList(TokenList[1], TAB_VALUE_SPLIT, 1)
1052        if DscPcdValueList[0] in ['True', 'true', 'TRUE']:
1053            self._ValueList[2] = TokenList[1].replace(DscPcdValueList[0], '1', 1);
1054        elif DscPcdValueList[0] in ['False', 'false', 'FALSE']:
1055            self._ValueList[2] = TokenList[1].replace(DscPcdValueList[0], '0', 1);
1056
1057    ## [components] section parser
1058    @ParseMacro
1059    def _ComponentParser(self):
1060        if self._CurrentLine[-1] == '{':
1061            self._ValueList[0] = self._CurrentLine[0:-1].strip()
1062            self._InSubsection = True
1063        else:
1064            self._ValueList[0] = self._CurrentLine
1065
1066    ## [LibraryClasses] section
1067    @ParseMacro
1068    def _LibraryClassParser(self):
1069        TokenList = GetSplitValueList(self._CurrentLine, TAB_VALUE_SPLIT)
1070        if len(TokenList) < 2:
1071            EdkLogger.error('Parser', FORMAT_INVALID, "No library class or instance specified",
1072                            ExtraData=self._CurrentLine + " (<LibraryClassName>|<LibraryInstancePath>)",
1073                            File=self.MetaFile, Line=self._LineIndex+1)
1074        if TokenList[0] == '':
1075            EdkLogger.error('Parser', FORMAT_INVALID, "No library class specified",
1076                            ExtraData=self._CurrentLine + " (<LibraryClassName>|<LibraryInstancePath>)",
1077                            File=self.MetaFile, Line=self._LineIndex+1)
1078        if TokenList[1] == '':
1079            EdkLogger.error('Parser', FORMAT_INVALID, "No library instance specified",
1080                            ExtraData=self._CurrentLine + " (<LibraryClassName>|<LibraryInstancePath>)",
1081                            File=self.MetaFile, Line=self._LineIndex+1)
1082
1083        self._ValueList[0:len(TokenList)] = TokenList
1084
1085    def _CompponentSourceOverridePathParser(self):
1086        self._ValueList[0] = self._CurrentLine
1087
1088    ## [BuildOptions] section parser
1089    @ParseMacro
1090    def _BuildOptionParser(self):
1091        TokenList = GetSplitValueList(self._CurrentLine, TAB_EQUAL_SPLIT, 1)
1092        TokenList2 = GetSplitValueList(TokenList[0], ':', 1)
1093        if len(TokenList2) == 2:
1094            self._ValueList[0] = TokenList2[0]  # toolchain family
1095            self._ValueList[1] = TokenList2[1]  # keys
1096        else:
1097            self._ValueList[1] = TokenList[0]
1098        if len(TokenList) == 2:                 # value
1099            self._ValueList[2] = TokenList[1]
1100
1101        if self._ValueList[1].count('_') != 4:
1102            EdkLogger.error(
1103                'Parser',
1104                FORMAT_INVALID,
1105                "'%s' must be in format of <TARGET>_<TOOLCHAIN>_<ARCH>_<TOOL>_FLAGS" % self._ValueList[1],
1106                ExtraData=self._CurrentLine,
1107                File=self.MetaFile,
1108                Line=self._LineIndex+1
1109                )
1110
1111    ## Override parent's method since we'll do all macro replacements in parser
1112    def _GetMacros(self):
1113        Macros = dict( [('ARCH','IA32'), ('FAMILY','MSFT'),('TOOL_CHAIN_TAG','VS2008x86'),('TARGET','DEBUG')])
1114        Macros.update(self._FileLocalMacros)
1115        Macros.update(self._GetApplicableSectionMacro())
1116        Macros.update(GlobalData.gEdkGlobal)
1117        Macros.update(GlobalData.gPlatformDefines)
1118        Macros.update(GlobalData.gCommandLineDefines)
1119        # PCD cannot be referenced in macro definition
1120        if self._ItemType not in [MODEL_META_DATA_DEFINE, MODEL_META_DATA_GLOBAL_DEFINE]:
1121            Macros.update(self._Symbols)
1122        return Macros
1123
1124    def _PostProcess(self):
1125        Processer = {
1126            MODEL_META_DATA_SECTION_HEADER                  :   self.__ProcessSectionHeader,
1127            MODEL_META_DATA_SUBSECTION_HEADER               :   self.__ProcessSubsectionHeader,
1128            MODEL_META_DATA_HEADER                          :   self.__ProcessDefine,
1129            MODEL_META_DATA_DEFINE                          :   self.__ProcessDefine,
1130            MODEL_META_DATA_GLOBAL_DEFINE                   :   self.__ProcessDefine,
1131            MODEL_META_DATA_INCLUDE                         :   self.__ProcessDirective,
1132            MODEL_META_DATA_CONDITIONAL_STATEMENT_IF        :   self.__ProcessDirective,
1133            MODEL_META_DATA_CONDITIONAL_STATEMENT_ELSE      :   self.__ProcessDirective,
1134            MODEL_META_DATA_CONDITIONAL_STATEMENT_IFDEF     :   self.__ProcessDirective,
1135            MODEL_META_DATA_CONDITIONAL_STATEMENT_IFNDEF    :   self.__ProcessDirective,
1136            MODEL_META_DATA_CONDITIONAL_STATEMENT_ENDIF     :   self.__ProcessDirective,
1137            MODEL_META_DATA_CONDITIONAL_STATEMENT_ELSEIF    :   self.__ProcessDirective,
1138            MODEL_EFI_SKU_ID                                :   self.__ProcessSkuId,
1139            MODEL_EFI_LIBRARY_INSTANCE                      :   self.__ProcessLibraryInstance,
1140            MODEL_EFI_LIBRARY_CLASS                         :   self.__ProcessLibraryClass,
1141            MODEL_PCD_FIXED_AT_BUILD                        :   self.__ProcessPcd,
1142            MODEL_PCD_PATCHABLE_IN_MODULE                   :   self.__ProcessPcd,
1143            MODEL_PCD_FEATURE_FLAG                          :   self.__ProcessPcd,
1144            MODEL_PCD_DYNAMIC_DEFAULT                       :   self.__ProcessPcd,
1145            MODEL_PCD_DYNAMIC_HII                           :   self.__ProcessPcd,
1146            MODEL_PCD_DYNAMIC_VPD                           :   self.__ProcessPcd,
1147            MODEL_PCD_DYNAMIC_EX_DEFAULT                    :   self.__ProcessPcd,
1148            MODEL_PCD_DYNAMIC_EX_HII                        :   self.__ProcessPcd,
1149            MODEL_PCD_DYNAMIC_EX_VPD                        :   self.__ProcessPcd,
1150            MODEL_META_DATA_COMPONENT                       :   self.__ProcessComponent,
1151            MODEL_META_DATA_COMPONENT_SOURCE_OVERRIDE_PATH  :   self.__ProcessSourceOverridePath,
1152            MODEL_META_DATA_BUILD_OPTION                    :   self.__ProcessBuildOption,
1153            MODEL_UNKNOWN                                   :   self._Skip,
1154            MODEL_META_DATA_USER_EXTENSION                  :   self._Skip,
1155            MODEL_META_DATA_CONDITIONAL_STATEMENT_ERROR     :   self._Skip,
1156        }
1157
1158        self._RawTable = self._Table
1159        self._Table = MetaFileStorage(self._RawTable.Cur, self.MetaFile, MODEL_FILE_DSC, True)
1160        self._DirectiveStack = []
1161        self._DirectiveEvalStack = []
1162        self._FileWithError = self.MetaFile
1163        self._FileLocalMacros = {}
1164        self._SectionsMacroDict = {}
1165        GlobalData.gPlatformDefines = {}
1166
1167        # Get all macro and PCD which has straitforward value
1168        self.__RetrievePcdValue()
1169        self._Content = self._RawTable.GetAll()
1170        self._ContentIndex = 0
1171        while self._ContentIndex < len(self._Content) :
1172            Id, self._ItemType, V1, V2, V3, S1, S2, Owner, BelongsToFile, self._From, \
1173                LineStart, ColStart, LineEnd, ColEnd, Enabled = self._Content[self._ContentIndex]
1174
1175            if self._From < 0:
1176                self._FileWithError = self.MetaFile
1177
1178            self._ContentIndex += 1
1179
1180            self._Scope = [[S1, S2]]
1181            self._LineIndex = LineStart - 1
1182            self._ValueList = [V1, V2, V3]
1183
1184            try:
1185                Processer[self._ItemType]()
1186            except EvaluationException, Excpt:
1187                #
1188                # Only catch expression evaluation error here. We need to report
1189                # the precise number of line on which the error occurred
1190                #
1191                pass
1192#                 EdkLogger.error('Parser', FORMAT_INVALID, "Invalid expression: %s" % str(Excpt),
1193#                                 File=self._FileWithError, ExtraData=' '.join(self._ValueList),
1194#                                 Line=self._LineIndex+1)
1195            except MacroException, Excpt:
1196                EdkLogger.error('Parser', FORMAT_INVALID, str(Excpt),
1197                                File=self._FileWithError, ExtraData=' '.join(self._ValueList),
1198                                Line=self._LineIndex+1)
1199
1200            if self._ValueList == None:
1201                continue
1202
1203            NewOwner = self._IdMapping.get(Owner, -1)
1204            self._Enabled = int((not self._DirectiveEvalStack) or (False not in self._DirectiveEvalStack))
1205            self._LastItem = self._Store(
1206                                self._ItemType,
1207                                self._ValueList[0],
1208                                self._ValueList[1],
1209                                self._ValueList[2],
1210                                S1,
1211                                S2,
1212                                NewOwner,
1213                                BelongsToFile,
1214                                self._From,
1215                                self._LineIndex+1,
1216                                -1,
1217                                self._LineIndex+1,
1218                                -1,
1219                                self._Enabled
1220                                )
1221            self._IdMapping[Id] = self._LastItem
1222
1223        RecordList = self._Table.GetAll()
1224
1225        self._RawTable.Drop()
1226        self._Table.Drop()
1227        for Record in RecordList:
1228            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])
1229        GlobalData.gPlatformDefines.update(self._FileLocalMacros)
1230        self._PostProcessed = True
1231        self._Content = None
1232
1233    def __ProcessSectionHeader(self):
1234        self._SectionName = self._ValueList[0]
1235        if self._SectionName in self.DataType:
1236            self._SectionType = self.DataType[self._SectionName]
1237        else:
1238            self._SectionType = MODEL_UNKNOWN
1239
1240    def __ProcessSubsectionHeader(self):
1241        self._SubsectionName = self._ValueList[0]
1242        if self._SubsectionName in self.DataType:
1243            self._SubsectionType = self.DataType[self._SubsectionName]
1244        else:
1245            self._SubsectionType = MODEL_UNKNOWN
1246
1247    def __RetrievePcdValue(self):
1248        Records = self._RawTable.Query(MODEL_PCD_FEATURE_FLAG, BelongsToItem=-1.0)
1249        for TokenSpaceGuid,PcdName,Value,Dummy2,Dummy3,ID,Line in Records:
1250            Value, DatumType, MaxDatumSize = AnalyzePcdData(Value)
1251            # Only use PCD whose value is straitforward (no macro and PCD)
1252            if self.SymbolPattern.findall(Value):
1253                continue
1254            Name = TokenSpaceGuid + '.' + PcdName
1255            # Don't use PCD with different values.
1256            if Name in self._Symbols and self._Symbols[Name] != Value:
1257                self._Symbols.pop(Name)
1258                continue
1259            self._Symbols[Name] = Value
1260
1261        Records = self._RawTable.Query(MODEL_PCD_FIXED_AT_BUILD, BelongsToItem=-1.0)
1262        for TokenSpaceGuid,PcdName,Value,Dummy2,Dummy3,ID,Line in Records:
1263            Value, DatumType, MaxDatumSize = AnalyzePcdData(Value)
1264            # Only use PCD whose value is straitforward (no macro and PCD)
1265            if self.SymbolPattern.findall(Value):
1266                continue
1267            Name = TokenSpaceGuid+'.'+PcdName
1268            # Don't use PCD with different values.
1269            if Name in self._Symbols and self._Symbols[Name] != Value:
1270                self._Symbols.pop(Name)
1271                continue
1272            self._Symbols[Name] = Value
1273
1274    def __ProcessDefine(self):
1275        if not self._Enabled:
1276            return
1277
1278        Type, Name, Value = self._ValueList
1279        Value = ReplaceMacro(Value, self._Macros, False)
1280        if self._ItemType == MODEL_META_DATA_DEFINE:
1281            if self._SectionType == MODEL_META_DATA_HEADER:
1282                self._FileLocalMacros[Name] = Value
1283            else:
1284                SectionDictKey = self._SectionType, self._Scope[0][0], self._Scope[0][1]
1285                if SectionDictKey not in self._SectionsMacroDict:
1286                    self._SectionsMacroDict[SectionDictKey] = {}
1287                SectionLocalMacros = self._SectionsMacroDict[SectionDictKey]
1288                SectionLocalMacros[Name] = Value
1289        elif self._ItemType == MODEL_META_DATA_GLOBAL_DEFINE:
1290            GlobalData.gEdkGlobal[Name] = Value
1291
1292        #
1293        # Keyword in [Defines] section can be used as Macros
1294        #
1295        if (self._ItemType == MODEL_META_DATA_HEADER) and (self._SectionType == MODEL_META_DATA_HEADER):
1296            self._FileLocalMacros[Name] = Value
1297
1298        self._ValueList = [Type, Name, Value]
1299
1300    def __ProcessDirective(self):
1301        Result = None
1302        if self._ItemType in [MODEL_META_DATA_CONDITIONAL_STATEMENT_IF,
1303                              MODEL_META_DATA_CONDITIONAL_STATEMENT_ELSEIF]:
1304            Macros = self._Macros
1305            Macros.update(GlobalData.gGlobalDefines)
1306            try:
1307                Result = ValueExpression(self._ValueList[1], Macros)()
1308            except SymbolNotFound, Exc:
1309                EdkLogger.debug(EdkLogger.DEBUG_5, str(Exc), self._ValueList[1])
1310                Result = False
1311            except WrnExpression, Excpt:
1312                #
1313                # Catch expression evaluation warning here. We need to report
1314                # the precise number of line and return the evaluation result
1315                #
1316                EdkLogger.warn('Parser', "Suspicious expression: %s" % str(Excpt),
1317                                File=self._FileWithError, ExtraData=' '.join(self._ValueList),
1318                                Line=self._LineIndex+1)
1319                Result = Excpt.result
1320            except BadExpression, Exc:
1321                EdkLogger.debug(EdkLogger.DEBUG_5, str(Exc), self._ValueList[1])
1322                Result = False
1323
1324        if self._ItemType in [MODEL_META_DATA_CONDITIONAL_STATEMENT_IF,
1325                              MODEL_META_DATA_CONDITIONAL_STATEMENT_IFDEF,
1326                              MODEL_META_DATA_CONDITIONAL_STATEMENT_IFNDEF]:
1327            self._DirectiveStack.append(self._ItemType)
1328            if self._ItemType == MODEL_META_DATA_CONDITIONAL_STATEMENT_IF:
1329                Result = bool(Result)
1330            else:
1331                Macro = self._ValueList[1]
1332                Macro = Macro[2:-1] if (Macro.startswith("$(") and Macro.endswith(")")) else Macro
1333                Result = Macro in self._Macros
1334                if self._ItemType == MODEL_META_DATA_CONDITIONAL_STATEMENT_IFNDEF:
1335                    Result = not Result
1336            self._DirectiveEvalStack.append(Result)
1337        elif self._ItemType == MODEL_META_DATA_CONDITIONAL_STATEMENT_ELSEIF:
1338            self._DirectiveStack.append(self._ItemType)
1339            self._DirectiveEvalStack[-1] = not self._DirectiveEvalStack[-1]
1340            self._DirectiveEvalStack.append(bool(Result))
1341        elif self._ItemType == MODEL_META_DATA_CONDITIONAL_STATEMENT_ELSE:
1342            self._DirectiveStack[-1] = self._ItemType
1343            self._DirectiveEvalStack[-1] = not self._DirectiveEvalStack[-1]
1344        elif self._ItemType == MODEL_META_DATA_CONDITIONAL_STATEMENT_ENDIF:
1345            # Back to the nearest !if/!ifdef/!ifndef
1346            while self._DirectiveStack:
1347                self._DirectiveEvalStack.pop()
1348                Directive = self._DirectiveStack.pop()
1349                if Directive in [MODEL_META_DATA_CONDITIONAL_STATEMENT_IF,
1350                                 MODEL_META_DATA_CONDITIONAL_STATEMENT_IFDEF,
1351                                 MODEL_META_DATA_CONDITIONAL_STATEMENT_ELSE,
1352                                 MODEL_META_DATA_CONDITIONAL_STATEMENT_IFNDEF]:
1353                    break
1354        elif self._ItemType == MODEL_META_DATA_INCLUDE:
1355            # The included file must be relative to workspace or same directory as DSC file
1356            __IncludeMacros = {}
1357            #
1358            # Allow using system environment variables  in path after !include
1359            #
1360            __IncludeMacros['WORKSPACE'] = GlobalData.gGlobalDefines['WORKSPACE']
1361            if "ECP_SOURCE" in GlobalData.gGlobalDefines.keys():
1362                __IncludeMacros['ECP_SOURCE'] = GlobalData.gGlobalDefines['ECP_SOURCE']
1363            #
1364            # During GenFds phase call DSC parser, will go into this branch.
1365            #
1366            elif "ECP_SOURCE" in GlobalData.gCommandLineDefines.keys():
1367                __IncludeMacros['ECP_SOURCE'] = GlobalData.gCommandLineDefines['ECP_SOURCE']
1368
1369            __IncludeMacros['EFI_SOURCE'] = GlobalData.gGlobalDefines['EFI_SOURCE']
1370            __IncludeMacros['EDK_SOURCE'] = GlobalData.gGlobalDefines['EDK_SOURCE']
1371            #
1372            # Allow using MACROs comes from [Defines] section to keep compatible.
1373            #
1374            __IncludeMacros.update(self._Macros)
1375
1376            IncludedFile = NormPath(ReplaceMacro(self._ValueList[1], __IncludeMacros, RaiseError=True))
1377            #
1378            # First search the include file under the same directory as DSC file
1379            #
1380            IncludedFile1 = PathClass(IncludedFile, self.MetaFile.Dir)
1381            ErrorCode, ErrorInfo1 = IncludedFile1.Validate()
1382            if ErrorCode != 0:
1383                #
1384                # Also search file under the WORKSPACE directory
1385                #
1386                IncludedFile1 = PathClass(IncludedFile, GlobalData.gWorkspace)
1387                ErrorCode, ErrorInfo2 = IncludedFile1.Validate()
1388                if ErrorCode != 0:
1389                    EdkLogger.error('parser', ErrorCode, File=self._FileWithError,
1390                                    Line=self._LineIndex+1, ExtraData=ErrorInfo1 + "\n"+ ErrorInfo2)
1391
1392            self._FileWithError = IncludedFile1
1393
1394            IncludedFileTable = MetaFileStorage(self._Table.Cur, IncludedFile1, MODEL_FILE_DSC, True)
1395            Owner = self._Content[self._ContentIndex-1][0]
1396            Parser = DscParser(IncludedFile1, self._FileType, IncludedFileTable,
1397                               Owner=Owner, From=Owner)
1398
1399            # set the parser status with current status
1400            Parser._SectionName = self._SectionName
1401            Parser._SectionType = self._SectionType
1402            Parser._Scope = self._Scope
1403            Parser._Enabled = self._Enabled
1404            # Parse the included file
1405            Parser.Start()
1406
1407            # update current status with sub-parser's status
1408            self._SectionName = Parser._SectionName
1409            self._SectionType = Parser._SectionType
1410            self._Scope       = Parser._Scope
1411            self._Enabled     = Parser._Enabled
1412
1413            # Insert all records in the table for the included file into dsc file table
1414            Records = IncludedFileTable.GetAll()
1415            if Records:
1416                self._Content[self._ContentIndex:self._ContentIndex] = Records
1417                self._Content.pop(self._ContentIndex-1)
1418                self._ValueList = None
1419                self._ContentIndex -= 1
1420
1421    def __ProcessSkuId(self):
1422        self._ValueList = [ReplaceMacro(Value, self._Macros, RaiseError=True)
1423                           for Value in self._ValueList]
1424
1425    def __ProcessLibraryInstance(self):
1426        self._ValueList = [ReplaceMacro(Value, self._Macros) for Value in self._ValueList]
1427
1428    def __ProcessLibraryClass(self):
1429        self._ValueList[1] = ReplaceMacro(self._ValueList[1], self._Macros, RaiseError=True)
1430
1431    def __ProcessPcd(self):
1432        ValueList = GetSplitValueList(self._ValueList[2])
1433        #
1434        # PCD value can be an expression
1435        #
1436        if len(ValueList) > 1 and ValueList[1] == 'VOID*':
1437            PcdValue = ValueList[0]
1438            try:
1439                ValueList[0] = ValueExpression(PcdValue, self._Macros)(True)
1440            except WrnExpression, Value:
1441                ValueList[0] = Value.result
1442        else:
1443            PcdValue = ValueList[-1]
1444            try:
1445                ValueList[-1] = ValueExpression(PcdValue, self._Macros)(True)
1446            except WrnExpression, Value:
1447                ValueList[-1] = Value.result
1448
1449            if ValueList[-1] == 'True':
1450                ValueList[-1] = '1'
1451            if ValueList[-1] == 'False':
1452                ValueList[-1] = '0'
1453
1454        self._ValueList[2] = '|'.join(ValueList)
1455
1456    def __ProcessComponent(self):
1457        self._ValueList[0] = ReplaceMacro(self._ValueList[0], self._Macros)
1458
1459    def __ProcessSourceOverridePath(self):
1460        self._ValueList[0] = ReplaceMacro(self._ValueList[0], self._Macros)
1461
1462    def __ProcessBuildOption(self):
1463        self._ValueList = [ReplaceMacro(Value, self._Macros, RaiseError=False)
1464                           for Value in self._ValueList]
1465
1466    _SectionParser = {
1467        MODEL_META_DATA_HEADER                          :   _DefineParser,
1468        MODEL_EFI_SKU_ID                                :   _SkuIdParser,
1469        MODEL_EFI_LIBRARY_INSTANCE                      :   _LibraryInstanceParser,
1470        MODEL_EFI_LIBRARY_CLASS                         :   _LibraryClassParser,
1471        MODEL_PCD_FIXED_AT_BUILD                        :   _PcdParser,
1472        MODEL_PCD_PATCHABLE_IN_MODULE                   :   _PcdParser,
1473        MODEL_PCD_FEATURE_FLAG                          :   _PcdParser,
1474        MODEL_PCD_DYNAMIC_DEFAULT                       :   _PcdParser,
1475        MODEL_PCD_DYNAMIC_HII                           :   _PcdParser,
1476        MODEL_PCD_DYNAMIC_VPD                           :   _PcdParser,
1477        MODEL_PCD_DYNAMIC_EX_DEFAULT                    :   _PcdParser,
1478        MODEL_PCD_DYNAMIC_EX_HII                        :   _PcdParser,
1479        MODEL_PCD_DYNAMIC_EX_VPD                        :   _PcdParser,
1480        MODEL_META_DATA_COMPONENT                       :   _ComponentParser,
1481        MODEL_META_DATA_COMPONENT_SOURCE_OVERRIDE_PATH  :   _CompponentSourceOverridePathParser,
1482        MODEL_META_DATA_BUILD_OPTION                    :   _BuildOptionParser,
1483        MODEL_UNKNOWN                                   :   MetaFileParser._Skip,
1484        MODEL_META_DATA_USER_EXTENSION                  :   MetaFileParser._Skip,
1485        MODEL_META_DATA_SECTION_HEADER                  :   MetaFileParser._SectionHeaderParser,
1486        MODEL_META_DATA_SUBSECTION_HEADER               :   _SubsectionHeaderParser,
1487    }
1488
1489    _Macros     = property(_GetMacros)
1490
1491## DEC file parser class
1492#
1493#   @param      FilePath        The path of platform description file
1494#   @param      FileType        The raw data of DSC file
1495#   @param      Table           Database used to retrieve module/package information
1496#   @param      Macros          Macros used for replacement in file
1497#
1498class DecParser(MetaFileParser):
1499    # DEC file supported data types (one type per section)
1500    DataType = {
1501        TAB_DEC_DEFINES.upper()                     :   MODEL_META_DATA_HEADER,
1502        TAB_DSC_DEFINES_DEFINE                      :   MODEL_META_DATA_DEFINE,
1503        TAB_INCLUDES.upper()                        :   MODEL_EFI_INCLUDE,
1504        TAB_LIBRARY_CLASSES.upper()                 :   MODEL_EFI_LIBRARY_CLASS,
1505        TAB_GUIDS.upper()                           :   MODEL_EFI_GUID,
1506        TAB_PPIS.upper()                            :   MODEL_EFI_PPI,
1507        TAB_PROTOCOLS.upper()                       :   MODEL_EFI_PROTOCOL,
1508        TAB_PCDS_FIXED_AT_BUILD_NULL.upper()        :   MODEL_PCD_FIXED_AT_BUILD,
1509        TAB_PCDS_PATCHABLE_IN_MODULE_NULL.upper()   :   MODEL_PCD_PATCHABLE_IN_MODULE,
1510        TAB_PCDS_FEATURE_FLAG_NULL.upper()          :   MODEL_PCD_FEATURE_FLAG,
1511        TAB_PCDS_DYNAMIC_NULL.upper()               :   MODEL_PCD_DYNAMIC,
1512        TAB_PCDS_DYNAMIC_EX_NULL.upper()            :   MODEL_PCD_DYNAMIC_EX,
1513    }
1514
1515    ## Constructor of DecParser
1516    #
1517    #  Initialize object of DecParser
1518    #
1519    #   @param      FilePath        The path of platform description file
1520    #   @param      FileType        The raw data of DSC file
1521    #   @param      Table           Database used to retrieve module/package information
1522    #   @param      Macros          Macros used for replacement in file
1523    #
1524    def __init__(self, FilePath, FileType, Table):
1525        # prevent re-initialization
1526        if hasattr(self, "_Table"):
1527            return
1528        MetaFileParser.__init__(self, FilePath, FileType, Table)
1529        self._Comments = []
1530        self._Version = 0x00010005  # Only EDK2 dec file is supported
1531        self.TblFile = EccGlobalData.gDb.TblFile
1532        self.FileID = -1
1533
1534    ## Parser starter
1535    def Start(self):
1536        Content = ''
1537        try:
1538            Content = open(str(self.MetaFile), 'r').readlines()
1539        except:
1540            EdkLogger.error("Parser", FILE_READ_FAILURE, ExtraData=self.MetaFile)
1541
1542        #
1543        # Insert a record for file
1544        #
1545        Filename = NormPath(self.MetaFile)
1546        FileID = self.TblFile.GetFileId(Filename)
1547        if FileID:
1548            self.FileID = FileID
1549        else:
1550            self.FileID = self.TblFile.InsertFile(Filename, MODEL_FILE_DEC)
1551
1552        for Index in range(0, len(Content)):
1553            Line, Comment = CleanString2(Content[Index])
1554            self._CurrentLine = Line
1555            self._LineIndex = Index
1556
1557            # save comment for later use
1558            if Comment:
1559                self._Comments.append((Comment, self._LineIndex+1))
1560            # skip empty line
1561            if Line == '':
1562                continue
1563
1564            # section header
1565            if Line[0] == TAB_SECTION_START and Line[-1] == TAB_SECTION_END:
1566                self._SectionHeaderParser()
1567                self._Comments = []
1568                continue
1569            elif len(self._SectionType) == 0:
1570                self._Comments = []
1571                continue
1572
1573            # section content
1574            self._ValueList = ['','','']
1575            self._SectionParser[self._SectionType[0]](self)
1576            if self._ValueList == None or self._ItemType == MODEL_META_DATA_DEFINE:
1577                self._ItemType = -1
1578                self._Comments = []
1579                continue
1580
1581            #
1582            # Model, Value1, Value2, Value3, Arch, BelongsToItem=-1, LineBegin=-1,
1583            # ColumnBegin=-1, LineEnd=-1, ColumnEnd=-1, FeatureFlag='', Enabled=-1
1584            #
1585            for Arch, ModuleType, Type in self._Scope:
1586                self._LastItem = self._Store(
1587                    Type,
1588                    self._ValueList[0],
1589                    self._ValueList[1],
1590                    self._ValueList[2],
1591                    Arch,
1592                    ModuleType,
1593                    self._Owner[-1],
1594                    self.FileID,
1595                    self._LineIndex+1,
1596                    -1,
1597                    self._LineIndex+1,
1598                    -1,
1599                    0
1600                    )
1601                for Comment, LineNo in self._Comments:
1602                    self._Store(
1603                        MODEL_META_DATA_COMMENT,
1604                        Comment,
1605                        self._ValueList[0],
1606                        self._ValueList[1],
1607                        Arch,
1608                        ModuleType,
1609                        self._LastItem,
1610                        self.FileID,
1611                        LineNo,
1612                        -1,
1613                        LineNo,
1614                        -1,
1615                        0
1616                        )
1617            self._Comments = []
1618        self._Done()
1619
1620    def _GetApplicableSectionMacro(self):
1621        Macros = {}
1622        for S1, S2, SectionType in self._Scope:
1623            for Scope1, Scope2 in [("COMMON", "COMMON"), ("COMMON", S2), (S1, "COMMON"), (S1, S2)]:
1624                if (SectionType, Scope1, Scope2) in self._SectionsMacroDict:
1625                    Macros.update(self._SectionsMacroDict[(SectionType, Scope1, Scope2)])
1626        return Macros
1627
1628    ## Section header parser
1629    #
1630    #   The section header is always in following format:
1631    #
1632    #       [section_name.arch<.platform|module_type>]
1633    #
1634    def _SectionHeaderParser(self):
1635        self._Scope = []
1636        self._SectionName = ''
1637        self._SectionType = []
1638        ArchList = set()
1639        for Item in GetSplitValueList(self._CurrentLine[1:-1], TAB_COMMA_SPLIT):
1640            if Item == '':
1641                continue
1642            ItemList = GetSplitValueList(Item, TAB_SPLIT)
1643
1644            # different types of PCD are permissible in one section
1645            self._SectionName = ItemList[0].upper()
1646            if self._SectionName in self.DataType:
1647                if self.DataType[self._SectionName] not in self._SectionType:
1648                    self._SectionType.append(self.DataType[self._SectionName])
1649            else:
1650                EdkLogger.warn("Parser", "Unrecognized section", File=self.MetaFile,
1651                                Line=self._LineIndex+1, ExtraData=self._CurrentLine)
1652                continue
1653
1654            if MODEL_PCD_FEATURE_FLAG in self._SectionType and len(self._SectionType) > 1:
1655                EdkLogger.error(
1656                            'Parser',
1657                            FORMAT_INVALID,
1658                            "%s must not be in the same section of other types of PCD" % TAB_PCDS_FEATURE_FLAG_NULL,
1659                            File=self.MetaFile,
1660                            Line=self._LineIndex+1,
1661                            ExtraData=self._CurrentLine
1662                            )
1663            # S1 is always Arch
1664            if len(ItemList) > 1:
1665                S1 = ItemList[1].upper()
1666            else:
1667                S1 = 'COMMON'
1668            ArchList.add(S1)
1669            # S2 may be Platform or ModuleType
1670            if len(ItemList) > 2:
1671                S2 = ItemList[2].upper()
1672            else:
1673                S2 = 'COMMON'
1674            if [S1, S2, self.DataType[self._SectionName]] not in self._Scope:
1675                self._Scope.append([S1, S2, self.DataType[self._SectionName]])
1676
1677        # 'COMMON' must not be used with specific ARCHs at the same section
1678        if 'COMMON' in ArchList and len(ArchList) > 1:
1679            EdkLogger.error('Parser', FORMAT_INVALID, "'common' ARCH must not be used with specific ARCHs",
1680                            File=self.MetaFile, Line=self._LineIndex+1, ExtraData=self._CurrentLine)
1681
1682    ## [guids], [ppis] and [protocols] section parser
1683    @ParseMacro
1684    def _GuidParser(self):
1685        TokenList = GetSplitValueList(self._CurrentLine, TAB_EQUAL_SPLIT, 1)
1686        if len(TokenList) < 2:
1687            EdkLogger.error('Parser', FORMAT_INVALID, "No GUID name or value specified",
1688                            ExtraData=self._CurrentLine + " (<CName> = <GuidValueInCFormat>)",
1689                            File=self.MetaFile, Line=self._LineIndex+1)
1690        if TokenList[0] == '':
1691            EdkLogger.error('Parser', FORMAT_INVALID, "No GUID name specified",
1692                            ExtraData=self._CurrentLine + " (<CName> = <GuidValueInCFormat>)",
1693                            File=self.MetaFile, Line=self._LineIndex+1)
1694        if TokenList[1] == '':
1695            EdkLogger.error('Parser', FORMAT_INVALID, "No GUID value specified",
1696                            ExtraData=self._CurrentLine + " (<CName> = <GuidValueInCFormat>)",
1697                            File=self.MetaFile, Line=self._LineIndex+1)
1698        if TokenList[1][0] != '{' or TokenList[1][-1] != '}' or GuidStructureStringToGuidString(TokenList[1]) == '':
1699            EdkLogger.error('Parser', FORMAT_INVALID, "Invalid GUID value format",
1700                            ExtraData=self._CurrentLine + \
1701                                      " (<CName> = <GuidValueInCFormat:{8,4,4,{2,2,2,2,2,2,2,2}}>)",
1702                            File=self.MetaFile, Line=self._LineIndex+1)
1703        self._ValueList[0] = TokenList[0]
1704        #Parse the Guid value format
1705        GuidValueList = TokenList[1].strip(' {}').split(',')
1706        Index = 0
1707        HexList = []
1708        if len(GuidValueList) == 11:
1709            for GuidValue in GuidValueList:
1710                GuidValue = GuidValue.strip()
1711                if GuidValue.startswith('0x') or GuidValue.startswith('0X'):
1712                    HexList.append('0x' + str(GuidValue[2:]))
1713                    Index += 1
1714                    continue
1715                else:
1716                    if GuidValue.startswith('{'):
1717                        GuidValue = GuidValue.lstrip(' {')
1718                        HexList.append('0x' + str(GuidValue[2:]))
1719                        Index += 1
1720            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])
1721        else:
1722            EdkLogger.error('Parser', FORMAT_INVALID, "Invalid GUID value format",
1723                            ExtraData=self._CurrentLine + \
1724                                      " (<CName> = <GuidValueInCFormat:{8,4,4,{2,2,2,2,2,2,2,2}}>)",
1725                            File=self.MetaFile, Line=self._LineIndex+1)
1726            self._ValueList[0] = ''
1727
1728    ## PCD sections parser
1729    #
1730    #   [PcdsFixedAtBuild]
1731    #   [PcdsPatchableInModule]
1732    #   [PcdsFeatureFlag]
1733    #   [PcdsDynamicEx
1734    #   [PcdsDynamic]
1735    #
1736    @ParseMacro
1737    def _PcdParser(self):
1738        TokenList = GetSplitValueList(self._CurrentLine, TAB_VALUE_SPLIT, 1)
1739        self._ValueList[0:1] = GetSplitValueList(TokenList[0], TAB_SPLIT)
1740        # check PCD information
1741        if self._ValueList[0] == '' or self._ValueList[1] == '':
1742            EdkLogger.error('Parser', FORMAT_INVALID, "No token space GUID or PCD name specified",
1743                            ExtraData=self._CurrentLine + \
1744                                      " (<TokenSpaceGuidCName>.<PcdCName>|<DefaultValue>|<DatumType>|<Token>)",
1745                            File=self.MetaFile, Line=self._LineIndex+1)
1746        # check PCD datum information
1747        if len(TokenList) < 2 or TokenList[1] == '':
1748            EdkLogger.error('Parser', FORMAT_INVALID, "No PCD Datum information given",
1749                            ExtraData=self._CurrentLine + \
1750                                      " (<TokenSpaceGuidCName>.<PcdCName>|<DefaultValue>|<DatumType>|<Token>)",
1751                            File=self.MetaFile, Line=self._LineIndex+1)
1752
1753
1754        ValueRe  = re.compile(r'^\s*L?\".*\|.*\"')
1755        PtrValue = ValueRe.findall(TokenList[1])
1756
1757        # Has VOID* type string, may contain "|" character in the string.
1758        if len(PtrValue) != 0:
1759            ptrValueList = re.sub(ValueRe, '', TokenList[1])
1760            ValueList    = GetSplitValueList(ptrValueList)
1761            ValueList[0] = PtrValue[0]
1762        else:
1763            ValueList = GetSplitValueList(TokenList[1])
1764
1765
1766        # check if there's enough datum information given
1767        if len(ValueList) != 3:
1768            EdkLogger.error('Parser', FORMAT_INVALID, "Invalid PCD Datum information given",
1769                            ExtraData=self._CurrentLine + \
1770                                      " (<TokenSpaceGuidCName>.<PcdCName>|<DefaultValue>|<DatumType>|<Token>)",
1771                            File=self.MetaFile, Line=self._LineIndex+1)
1772        # check default value
1773        if ValueList[0] == '':
1774            EdkLogger.error('Parser', FORMAT_INVALID, "Missing DefaultValue in PCD Datum information",
1775                            ExtraData=self._CurrentLine + \
1776                                      " (<TokenSpaceGuidCName>.<PcdCName>|<DefaultValue>|<DatumType>|<Token>)",
1777                            File=self.MetaFile, Line=self._LineIndex+1)
1778        # check datum type
1779        if ValueList[1] == '':
1780            EdkLogger.error('Parser', FORMAT_INVALID, "Missing DatumType in PCD Datum information",
1781                            ExtraData=self._CurrentLine + \
1782                                      " (<TokenSpaceGuidCName>.<PcdCName>|<DefaultValue>|<DatumType>|<Token>)",
1783                            File=self.MetaFile, Line=self._LineIndex+1)
1784        # check token of the PCD
1785        if ValueList[2] == '':
1786            EdkLogger.error('Parser', FORMAT_INVALID, "Missing Token in PCD Datum information",
1787                            ExtraData=self._CurrentLine + \
1788                                      " (<TokenSpaceGuidCName>.<PcdCName>|<DefaultValue>|<DatumType>|<Token>)",
1789                            File=self.MetaFile, Line=self._LineIndex+1)
1790        # check format of default value against the datum type
1791        IsValid, Cause = CheckPcdDatum(ValueList[1], ValueList[0])
1792        if not IsValid:
1793            EdkLogger.error('Parser', FORMAT_INVALID, Cause, ExtraData=self._CurrentLine,
1794                            File=self.MetaFile, Line=self._LineIndex+1)
1795
1796        if EccGlobalData.gConfig.UniCheckPCDInfo == '1' or EccGlobalData.gConfig.UniCheckAll == '1' or EccGlobalData.gConfig.CheckAll == '1':
1797            # check Description, Prompt information
1798            PatternDesc = re.compile('##\s*([\x21-\x7E\s]*)', re.S)
1799            PatternPrompt = re.compile('#\s+@Prompt\s+([\x21-\x7E\s]*)', re.S)
1800            Description = None
1801            Prompt = None
1802            # check @ValidRange, @ValidList and @Expression format valid
1803            ErrorCodeValid = '0x0 <= %s <= 0xFFFFFFFF'
1804            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]+)'
1805            PatternValidRng = re.compile('^' + '(NOT)?\s*' + PatternValidRangeIn + '$')
1806            for Comment in self._Comments:
1807                Comm = Comment[0].strip()
1808                if not Comm:
1809                    continue
1810                if not Description:
1811                    Description = PatternDesc.findall(Comm)
1812                if not Prompt:
1813                    Prompt = PatternPrompt.findall(Comm)
1814                if Comm[0] == '#':
1815                    ValidFormt = Comm.lstrip('#')
1816                    ValidFormt = ValidFormt.lstrip()
1817                    if ValidFormt[0:11] == '@ValidRange':
1818                        ValidFormt = ValidFormt[11:]
1819                        ValidFormt = ValidFormt.lstrip()
1820                        try:
1821                            ErrorCode, Expression = ValidFormt.split('|', 1)
1822                        except ValueError:
1823                            ErrorCode = '0x0'
1824                            Expression = ValidFormt
1825                        ErrorCode, Expression = ErrorCode.strip(), Expression.strip()
1826                        try:
1827                            if not eval(ErrorCodeValid % ErrorCode):
1828                                EdkLogger.warn('Parser', '@ValidRange ErrorCode(%s) of PCD %s is not valid UINT32 value.' % (ErrorCode, TokenList[0]))
1829                        except:
1830                            EdkLogger.warn('Parser', '@ValidRange ErrorCode(%s) of PCD %s is not valid UINT32 value.' % (ErrorCode, TokenList[0]))
1831                        if not PatternValidRng.search(Expression):
1832                            EdkLogger.warn('Parser', '@ValidRange Expression(%s) of PCD %s is incorrect format.' % (Expression, TokenList[0]))
1833                    if ValidFormt[0:10] == '@ValidList':
1834                        ValidFormt = ValidFormt[10:]
1835                        ValidFormt = ValidFormt.lstrip()
1836                        try:
1837                            ErrorCode, Expression = ValidFormt.split('|', 1)
1838                        except ValueError:
1839                            ErrorCode = '0x0'
1840                            Expression = ValidFormt
1841                        ErrorCode, Expression = ErrorCode.strip(), Expression.strip()
1842                        try:
1843                            if not eval(ErrorCodeValid % ErrorCode):
1844                                EdkLogger.warn('Parser', '@ValidList ErrorCode(%s) of PCD %s is not valid UINT32 value.' % (ErrorCode, TokenList[0]))
1845                        except:
1846                            EdkLogger.warn('Parser', '@ValidList ErrorCode(%s) of PCD %s is not valid UINT32 value.' % (ErrorCode, TokenList[0]))
1847                        Values = Expression.split(',')
1848                        for Value in Values:
1849                            Value = Value.strip()
1850                            try:
1851                                eval(Value)
1852                            except:
1853                                EdkLogger.warn('Parser', '@ValidList Expression of PCD %s include a invalid value(%s).' % (TokenList[0], Value))
1854                                break
1855                    if ValidFormt[0:11] == '@Expression':
1856                        ValidFormt = ValidFormt[11:]
1857                        ValidFormt = ValidFormt.lstrip()
1858                        try:
1859                            ErrorCode, Expression = ValidFormt.split('|', 1)
1860                        except ValueError:
1861                            ErrorCode = '0x0'
1862                            Expression = ValidFormt
1863                        ErrorCode, Expression = ErrorCode.strip(), Expression.strip()
1864                        try:
1865                            if not eval(ErrorCodeValid % ErrorCode):
1866                                EdkLogger.warn('Parser', '@Expression ErrorCode(%s) of PCD %s is not valid UINT32 value.' % (ErrorCode, TokenList[0]))
1867                        except:
1868                            EdkLogger.warn('Parser', '@Expression ErrorCode(%s) of PCD %s is not valid UINT32 value.' % (ErrorCode, TokenList[0]))
1869                        if not Expression:
1870                            EdkLogger.warn('Parser', '@Expression Expression of PCD %s is incorrect format.' % TokenList[0])
1871            if not Description:
1872                EdkLogger.warn('Parser', 'PCD %s Description information is not provided.' % TokenList[0])
1873            if not Prompt:
1874                EdkLogger.warn('Parser', 'PCD %s Prompt information is not provided.' % TokenList[0])
1875            # check Description, Prompt localization information
1876            if self._UniObj:
1877                self._UniObj.CheckPcdInfo(TokenList[0])
1878
1879        if ValueList[0] in ['True', 'true', 'TRUE']:
1880            ValueList[0] = '1'
1881        elif ValueList[0] in ['False', 'false', 'FALSE']:
1882            ValueList[0] = '0'
1883
1884        self._ValueList[2] = ValueList[0].strip() + '|' + ValueList[1].strip() + '|' + ValueList[2].strip()
1885
1886    _SectionParser = {
1887        MODEL_META_DATA_HEADER          :   MetaFileParser._DefineParser,
1888        MODEL_EFI_INCLUDE               :   MetaFileParser._PathParser,
1889        MODEL_EFI_LIBRARY_CLASS         :   MetaFileParser._PathParser,
1890        MODEL_EFI_GUID                  :   _GuidParser,
1891        MODEL_EFI_PPI                   :   _GuidParser,
1892        MODEL_EFI_PROTOCOL              :   _GuidParser,
1893        MODEL_PCD_FIXED_AT_BUILD        :   _PcdParser,
1894        MODEL_PCD_PATCHABLE_IN_MODULE   :   _PcdParser,
1895        MODEL_PCD_FEATURE_FLAG          :   _PcdParser,
1896        MODEL_PCD_DYNAMIC               :   _PcdParser,
1897        MODEL_PCD_DYNAMIC_EX            :   _PcdParser,
1898        MODEL_UNKNOWN                   :   MetaFileParser._Skip,
1899        MODEL_META_DATA_USER_EXTENSION  :   MetaFileParser._Skip,
1900    }
1901
1902
1903## FdfObject
1904#
1905# This class defined basic Fdf object which is used by inheriting
1906#
1907# @param object:       Inherited from object class
1908#
1909class FdfObject(object):
1910    def __init__(self):
1911        object.__init__()
1912
1913## Fdf
1914#
1915# This class defined the structure used in Fdf object
1916#
1917# @param FdfObject:     Inherited from FdfObject class
1918# @param Filename:      Input value for Ffilename of Fdf file, default is None
1919# @param WorkspaceDir:  Input value for current workspace directory, default is None
1920#
1921class Fdf(FdfObject):
1922    def __init__(self, Filename = None, IsToDatabase = False, WorkspaceDir = None, Database = None):
1923        self.WorkspaceDir = WorkspaceDir
1924        self.IsToDatabase = IsToDatabase
1925
1926        self.Cur = Database.Cur
1927        self.TblFile = Database.TblFile
1928        self.TblFdf = Database.TblFdf
1929        self.FileID = -1
1930        self.FileList = {}
1931
1932        #
1933        # Load Fdf file if filename is not None
1934        #
1935        if Filename != None:
1936            try:
1937                self.LoadFdfFile(Filename)
1938            except Exception:
1939                pass
1940
1941    #
1942    # Insert a FDF file record into database
1943    #
1944    def InsertFile(self, Filename):
1945        FileID = -1
1946        Filename = NormPath(Filename)
1947        if Filename not in self.FileList:
1948            FileID = self.TblFile.InsertFile(Filename, MODEL_FILE_FDF)
1949            self.FileList[Filename] = FileID
1950
1951        return self.FileList[Filename]
1952
1953
1954    ## Load Fdf file
1955    #
1956    # Load the file if it exists
1957    #
1958    # @param Filename:  Input value for filename of Fdf file
1959    #
1960    def LoadFdfFile(self, Filename):
1961        FileList = []
1962        #
1963        # Parse Fdf file
1964        #
1965        Filename = NormPath(Filename)
1966        Fdf = FdfParser(Filename)
1967        Fdf.ParseFile()
1968
1969        #
1970        # Insert inf file and pcd information
1971        #
1972        if self.IsToDatabase:
1973            (Model, Value1, Value2, Value3, Scope1, Scope2, BelongsToItem, BelongsToFile, StartLine, StartColumn, EndLine, EndColumn, Enabled) = \
1974            (0, '', '', '', 'COMMON', 'COMMON', -1, -1, -1, -1, -1, -1, 0)
1975            for Index in range(0, len(Fdf.Profile.PcdDict)):
1976                pass
1977            for Key in Fdf.Profile.PcdDict.keys():
1978                Model = MODEL_PCD
1979                Value1 = Key[1]
1980                Value2 = Key[0]
1981                FileName = Fdf.Profile.PcdFileLineDict[Key][0]
1982                StartLine = Fdf.Profile.PcdFileLineDict[Key][1]
1983                BelongsToFile = self.InsertFile(FileName)
1984                self.TblFdf.Insert(Model, Value1, Value2, Value3, Scope1, Scope2, BelongsToItem, BelongsToFile, StartLine, StartColumn, EndLine, EndColumn, Enabled)
1985            for Index in range(0, len(Fdf.Profile.InfList)):
1986                Model = MODEL_META_DATA_COMPONENT
1987                Value1 = Fdf.Profile.InfList[Index]
1988                Value2 = ''
1989                FileName = Fdf.Profile.InfFileLineList[Index][0]
1990                StartLine = Fdf.Profile.InfFileLineList[Index][1]
1991                BelongsToFile = self.InsertFile(FileName)
1992                self.TblFdf.Insert(Model, Value1, Value2, Value3, Scope1, Scope2, BelongsToItem, BelongsToFile, StartLine, StartColumn, EndLine, EndColumn, Enabled)
1993
1994class UniParser(object):
1995    # IsExtraUni defined the UNI file is Module UNI or extra Module UNI
1996    # IsModuleUni defined the UNI file is Module UNI or Package UNI
1997    def __init__(self, FilePath, IsExtraUni=False, IsModuleUni=True):
1998        self.FilePath = FilePath
1999        self.FileName = os.path.basename(FilePath)
2000        self.IsExtraUni = IsExtraUni
2001        self.IsModuleUni = IsModuleUni
2002        self.FileIn = None
2003        self.Missing = []
2004        self.__read()
2005
2006    def __read(self):
2007        try:
2008            self.FileIn = CodecOpenLongFilePath(self.FilePath, Mode='rb', Encoding='utf_8').read()
2009        except UnicodeError:
2010            self.FileIn = CodecOpenLongFilePath(self.FilePath, Mode='rb', Encoding='utf_16').read()
2011        except UnicodeError:
2012            self.FileIn = CodecOpenLongFilePath(self.FilePath, Mode='rb', Encoding='utf_16_le').read()
2013        except IOError:
2014            self.FileIn = ""
2015
2016    def Start(self):
2017        if self.IsModuleUni:
2018            if self.IsExtraUni:
2019                ModuleName = self.CheckKeyValid('STR_PROPERTIES_MODULE_NAME')
2020                self.PrintLog('STR_PROPERTIES_MODULE_NAME', ModuleName)
2021            else:
2022                ModuleAbstract = self.CheckKeyValid('STR_MODULE_ABSTRACT')
2023                self.PrintLog('STR_MODULE_ABSTRACT', ModuleAbstract)
2024                ModuleDescription = self.CheckKeyValid('STR_MODULE_DESCRIPTION')
2025                self.PrintLog('STR_MODULE_DESCRIPTION', ModuleDescription)
2026        else:
2027            if self.IsExtraUni:
2028                PackageName = self.CheckKeyValid('STR_PROPERTIES_PACKAGE_NAME')
2029                self.PrintLog('STR_PROPERTIES_PACKAGE_NAME', PackageName)
2030            else:
2031                PackageAbstract = self.CheckKeyValid('STR_PACKAGE_ABSTRACT')
2032                self.PrintLog('STR_PACKAGE_ABSTRACT', PackageAbstract)
2033                PackageDescription = self.CheckKeyValid('STR_PACKAGE_DESCRIPTION')
2034                self.PrintLog('STR_PACKAGE_DESCRIPTION', PackageDescription)
2035
2036    def CheckKeyValid(self, Key, Contents=None):
2037        if not Contents:
2038            Contents = self.FileIn
2039        KeyPattern = re.compile('#string\s+%s\s+.*?#language.*?".*?"' % Key, re.S)
2040        if KeyPattern.search(Contents):
2041            return True
2042        return False
2043
2044    def CheckPcdInfo(self, PcdCName):
2045        PromptKey = 'STR_%s_PROMPT' % PcdCName.replace('.', '_')
2046        PcdPrompt = self.CheckKeyValid(PromptKey)
2047        self.PrintLog(PromptKey, PcdPrompt)
2048        HelpKey = 'STR_%s_HELP' % PcdCName.replace('.', '_')
2049        PcdHelp = self.CheckKeyValid(HelpKey)
2050        self.PrintLog(HelpKey, PcdHelp)
2051
2052    def PrintLog(self, Key, Value):
2053        if not Value and Key not in self.Missing:
2054            Msg = '%s is missing in the %s file.' % (Key, self.FileName)
2055            EdkLogger.warn('Parser', Msg)
2056            EccGlobalData.gDb.TblReport.Insert(EccToolError.ERROR_GENERAL_CHECK_UNI_HELP_INFO, OtherMsg=Msg, BelongsToTable='File', BelongsToItem=-2)
2057            self.Missing.append(Key)
2058
2059##
2060#
2061# This acts like the main() function for the script, unless it is 'import'ed into another
2062# script.
2063#
2064if __name__ == '__main__':
2065    pass
2066
2067