1## @file
2# This file is used to parse DEC file. It will consumed by DecParser
3#
4# Copyright (c) 2011 - 2016, Intel Corporation. All rights reserved.<BR>
5#
6# This program and the accompanying materials are licensed and made available
7# under the terms and conditions of the BSD License which accompanies this
8# distribution. The full text of the license may be found at
9# http://opensource.org/licenses/bsd-license.php
10#
11# THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
12# WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
13'''
14DecParser
15'''
16## Import modules
17#
18import Logger.Log as Logger
19from Logger.ToolError import FILE_PARSE_FAILURE
20from Logger.ToolError import FILE_OPEN_FAILURE
21from Logger import StringTable as ST
22from Logger.ToolError import FORMAT_INVALID
23
24import Library.DataType as DT
25from Library.ParserValidate import IsValidToken
26from Library.ParserValidate import IsValidPath
27from Library.ParserValidate import IsValidCFormatGuid
28from Library.ParserValidate import IsValidIdString
29from Library.ParserValidate import IsValidUserId
30from Library.ParserValidate import IsValidArch
31from Library.ParserValidate import IsValidWord
32from Library.ParserValidate import IsValidDecVersionVal
33from Parser.DecParserMisc import TOOL_NAME
34from Parser.DecParserMisc import CleanString
35from Parser.DecParserMisc import IsValidPcdDatum
36from Parser.DecParserMisc import ParserHelper
37from Parser.DecParserMisc import StripRoot
38from Parser.DecParserMisc import VERSION_PATTERN
39from Parser.DecParserMisc import CVAR_PATTERN
40from Parser.DecParserMisc import PCD_TOKEN_PATTERN
41from Parser.DecParserMisc import MACRO_PATTERN
42from Parser.DecParserMisc import FileContent
43from Object.Parser.DecObject import _DecComments
44from Object.Parser.DecObject import DecDefineObject
45from Object.Parser.DecObject import DecDefineItemObject
46from Object.Parser.DecObject import DecIncludeObject
47from Object.Parser.DecObject import DecIncludeItemObject
48from Object.Parser.DecObject import DecLibraryclassObject
49from Object.Parser.DecObject import DecLibraryclassItemObject
50from Object.Parser.DecObject import DecGuidObject
51from Object.Parser.DecObject import DecPpiObject
52from Object.Parser.DecObject import DecProtocolObject
53from Object.Parser.DecObject import DecGuidItemObject
54from Object.Parser.DecObject import DecUserExtensionObject
55from Object.Parser.DecObject import DecUserExtensionItemObject
56from Object.Parser.DecObject import DecPcdObject
57from Object.Parser.DecObject import DecPcdItemObject
58from Library.Misc import GuidStructureStringToGuidString
59from Library.Misc import CheckGuidRegFormat
60from Library.String import ReplaceMacro
61from Library.String import GetSplitValueList
62from Library.String import gMACRO_PATTERN
63from Library.String import ConvertSpecialChar
64from Library.CommentParsing import ParsePcdErrorCode
65
66##
67# _DecBase class for parsing
68#
69class _DecBase:
70    def __init__(self, RawData):
71        self._RawData = RawData
72        self._ItemDict = {}
73        self._LocalMacro = {}
74        #
75        # Data parsed by 'self' are saved to this object
76        #
77        self.ItemObject = None
78
79    def GetDataObject(self):
80        return self.ItemObject
81
82    def GetLocalMacro(self):
83        return self._LocalMacro
84
85    ## BlockStart
86    #
87    # Called if a new section starts
88    #
89    def BlockStart(self):
90        self._LocalMacro = {}
91
92    ## _CheckReDefine
93    #
94    # @param Key: to be checked if multi-defined
95    # @param Scope: Format: [[SectionName, Arch], ...].
96    #               If scope is none, use global scope
97    #
98    def _CheckReDefine(self, Key, Scope = None):
99        if not Scope:
100            Scope = self._RawData.CurrentScope
101            return
102
103        SecArch = []
104        #
105        # Copy scope to SecArch, avoid Scope be changed outside
106        #
107        SecArch[0:1] = Scope[:]
108        if Key not in self._ItemDict:
109            self._ItemDict[Key] = [[SecArch, self._RawData.LineIndex]]
110            return
111
112        for Value in self._ItemDict[Key]:
113            for SubValue in Scope:
114                #
115                # If current is common section
116                #
117                if SubValue[-1] == 'COMMON':
118                    for Other in Value[0]:
119                        # Key in common cannot be redefined in other arches
120                        # [:-1] means stripping arch info
121                        if Other[:-1] == SubValue[:-1]:
122                            self._LoggerError(ST.ERR_DECPARSE_REDEFINE % (Key, Value[1]))
123                            return
124                    continue
125                CommonScope = []
126                CommonScope[0:1] = SubValue
127                CommonScope[-1] = 'COMMON'
128                #
129                # Cannot be redefined if this key already defined in COMMON Or defined in same arch
130                #
131                if SubValue in Value[0] or CommonScope in Value[0]:
132                    self._LoggerError(ST.ERR_DECPARSE_REDEFINE % (Key, Value[1]))
133                    return
134        self._ItemDict[Key].append([SecArch, self._RawData.LineIndex])
135
136    ## CheckRequiredFields
137    # Some sections need to check if some fields exist, define section for example
138    # Derived class can re-implement, top parser will call this function after all parsing done
139    #
140    def CheckRequiredFields(self):
141        if self._RawData:
142            pass
143        return True
144
145    ## IsItemRequired
146    # In DEC spec, sections must have at least one statement except user
147    # extension.
148    # For example: "[guids" [<attribs>] "]" <EOL> <statements>+
149    # sub class can override this method to indicate if statement is a must.
150    #
151    def _IsStatementRequired(self):
152        if self._RawData:
153            pass
154        return False
155
156    def _LoggerError(self, ErrorString):
157        Logger.Error(TOOL_NAME, FILE_PARSE_FAILURE, File=self._RawData.Filename,
158                     Line = self._RawData.LineIndex,
159                     ExtraData=ErrorString + ST.ERR_DECPARSE_LINE % self._RawData.CurrentLine)
160
161    def _ReplaceMacro(self, String):
162        if gMACRO_PATTERN.findall(String):
163            String = ReplaceMacro(String, self._LocalMacro, False,
164                                  FileName = self._RawData.Filename,
165                                  Line = ['', self._RawData.LineIndex])
166            String = ReplaceMacro(String, self._RawData.Macros, False,
167                                  FileName = self._RawData.Filename,
168                                  Line = ['', self._RawData.LineIndex])
169            MacroUsed = gMACRO_PATTERN.findall(String)
170            if MacroUsed:
171                Logger.Error(TOOL_NAME, FILE_PARSE_FAILURE,
172                             File=self._RawData.Filename,
173                             Line = self._RawData.LineIndex,
174                             ExtraData = ST.ERR_DECPARSE_MACRO_RESOLVE % (str(MacroUsed), String))
175        return String
176
177    def _MacroParser(self, String):
178        TokenList = GetSplitValueList(String, ' ', 1)
179        if len(TokenList) < 2 or TokenList[1] == '':
180            self._LoggerError(ST.ERR_DECPARSE_MACRO_PAIR)
181
182        TokenList = GetSplitValueList(TokenList[1], DT.TAB_EQUAL_SPLIT, 1)
183        if TokenList[0] == '':
184            self._LoggerError(ST.ERR_DECPARSE_MACRO_NAME)
185        elif not IsValidToken(MACRO_PATTERN, TokenList[0]):
186            self._LoggerError(ST.ERR_DECPARSE_MACRO_NAME_UPPER % TokenList[0])
187
188        if len(TokenList) == 1:
189            self._LocalMacro[TokenList[0]] = ''
190        else:
191            self._LocalMacro[TokenList[0]] = self._ReplaceMacro(TokenList[1])
192
193    ## _ParseItem
194    #
195    # Parse specified item, this function must be derived by subclass
196    #
197    def _ParseItem(self):
198        if self._RawData:
199            pass
200        #
201        # Should never be called
202        #
203        return None
204
205
206    ## _TailCommentStrategy
207    #
208    # This function can be derived to parse tail comment
209    # default is it will not consume any lines
210    #
211    # @param Comment: Comment of current line
212    #
213    def _TailCommentStrategy(self, Comment):
214        if Comment:
215            pass
216        if self._RawData:
217            pass
218        return False
219
220    ## _StopCurrentParsing
221    #
222    # Called in Parse if current parsing should be stopped when encounter some
223    # keyword
224    # Default is section start and end
225    #
226    # @param Line: Current line
227    #
228    def _StopCurrentParsing(self, Line):
229        if self._RawData:
230            pass
231        return Line[0] == DT.TAB_SECTION_START and Line[-1] == DT.TAB_SECTION_END
232
233    ## _TryBackSlash
234    #
235    # Split comment and DEC content, concatenate lines if end of char is '\'
236    #
237    # @param ProcessedLine: ProcessedLine line
238    # @param ProcessedComments: ProcessedComments line
239    #
240    def _TryBackSlash(self, ProcessedLine, ProcessedComments):
241        CatLine = ''
242        Comment = ''
243        Line = ProcessedLine
244        CommentList = ProcessedComments
245        while not self._RawData.IsEndOfFile():
246            if Line == '':
247                self._LoggerError(ST.ERR_DECPARSE_BACKSLASH_EMPTY)
248                break
249
250            if Comment:
251                CommentList.append((Comment, self._RawData.LineIndex))
252            if Line[-1] != DT.TAB_SLASH:
253                CatLine += Line
254                break
255            elif len(Line) < 2 or Line[-2] != ' ':
256                self._LoggerError(ST.ERR_DECPARSE_BACKSLASH)
257            else:
258                CatLine += Line[:-1]
259                Line, Comment = CleanString(self._RawData.GetNextLine())
260        #
261        # Reach end of content
262        #
263        if self._RawData.IsEndOfFile():
264            if not CatLine:
265                if ProcessedLine[-1] == DT.TAB_SLASH:
266                    self._LoggerError(ST.ERR_DECPARSE_BACKSLASH_EMPTY)
267                CatLine = ProcessedLine
268            else:
269                if not Line or Line[-1] == DT.TAB_SLASH:
270                    self._LoggerError(ST.ERR_DECPARSE_BACKSLASH_EMPTY)
271                CatLine += Line
272
273        #
274        # All MACRO values defined by the DEFINE statements in any section
275        # (except [Userextensions] sections for Intel) of the INF or DEC file
276        # must be expanded before processing of the file.
277        #
278        __IsReplaceMacro = True
279        Header = self._RawData.CurrentScope[0] if self._RawData.CurrentScope else None
280        if Header and len(Header) > 2:
281            if Header[0].upper() == 'USEREXTENSIONS' and not (Header[1] == 'TianoCore' and Header[2] == '"ExtraFiles"'):
282                __IsReplaceMacro = False
283        if __IsReplaceMacro:
284            self._RawData.CurrentLine = self._ReplaceMacro(CatLine)
285        else:
286            self._RawData.CurrentLine = CatLine
287
288        return CatLine, CommentList
289
290    ## Parse
291    # This is a template method in which other member functions which might
292    # override by sub class are called. It is responsible for reading file
293    # line by line, and call other member functions to parse. This function
294    # should not be re-implement by sub class.
295    #
296    def Parse(self):
297        HeadComments = []
298        TailComments = []
299
300        #======================================================================
301        # CurComments may pointer to HeadComments or TailComments
302        #======================================================================
303        CurComments = HeadComments
304        CurObj = None
305        ItemNum = 0
306        FromBuf = False
307
308        #======================================================================
309        # Used to report error information if empty section found
310        #======================================================================
311        Index = self._RawData.LineIndex
312        LineStr = self._RawData.CurrentLine
313        while not self._RawData.IsEndOfFile() or self._RawData.NextLine:
314            if self._RawData.NextLine:
315                #==============================================================
316                # Have processed line in buffer
317                #==============================================================
318                Line = self._RawData.NextLine
319                HeadComments.extend(self._RawData.HeadComment)
320                TailComments.extend(self._RawData.TailComment)
321                self._RawData.ResetNext()
322                Comment = ''
323                FromBuf = True
324            else:
325                #==============================================================
326                # No line in buffer, read next line
327                #==============================================================
328                Line, Comment = CleanString(self._RawData.GetNextLine())
329                FromBuf = False
330            if Line:
331                if not FromBuf and CurObj and TailComments:
332                    #==========================================================
333                    # Set tail comments to previous statement if not empty.
334                    #==========================================================
335                    CurObj.SetTailComment(CurObj.GetTailComment()+TailComments)
336
337                if not FromBuf:
338                    del TailComments[:]
339                CurComments = TailComments
340                Comments = []
341                if Comment:
342                    Comments = [(Comment, self._RawData.LineIndex)]
343
344                #==============================================================
345                # Try if last char of line has backslash
346                #==============================================================
347                Line, Comments = self._TryBackSlash(Line, Comments)
348                CurComments.extend(Comments)
349
350                #==============================================================
351                # Macro found
352                #==============================================================
353                if Line.startswith('DEFINE '):
354                    self._MacroParser(Line)
355                    del HeadComments[:]
356                    del TailComments[:]
357                    CurComments = HeadComments
358                    continue
359
360                if self._StopCurrentParsing(Line):
361                    #==========================================================
362                    # This line does not belong to this parse,
363                    # Save it, can be used by next parse
364                    #==========================================================
365                    self._RawData.SetNext(Line, HeadComments, TailComments)
366                    break
367
368                Obj = self._ParseItem()
369                ItemNum += 1
370                if Obj:
371                    Obj.SetHeadComment(Obj.GetHeadComment()+HeadComments)
372                    Obj.SetTailComment(Obj.GetTailComment()+TailComments)
373                    del HeadComments[:]
374                    del TailComments[:]
375                    CurObj = Obj
376                else:
377                    CurObj = None
378            else:
379                if id(CurComments) == id(TailComments):
380                    #==========================================================
381                    # Check if this comment belongs to tail comment
382                    #==========================================================
383                    if not self._TailCommentStrategy(Comment):
384                        CurComments = HeadComments
385
386                if Comment:
387                    CurComments.append(((Comment, self._RawData.LineIndex)))
388                else:
389                    del CurComments[:]
390
391        if self._IsStatementRequired() and ItemNum == 0:
392            Logger.Error(
393                    TOOL_NAME, FILE_PARSE_FAILURE,
394                    File=self._RawData.Filename,
395                    Line=Index,
396                    ExtraData=ST.ERR_DECPARSE_STATEMENT_EMPTY % LineStr
397            )
398
399## _DecDefine
400# Parse define section
401#
402class _DecDefine(_DecBase):
403    def __init__(self, RawData):
404        _DecBase.__init__(self, RawData)
405        self.ItemObject = DecDefineObject(RawData.Filename)
406        self._LocalMacro = self._RawData.Macros
407        self._DefSecNum = 0
408
409        #
410        # Each field has a function to validate
411        #
412        self.DefineValidation = {
413            DT.TAB_DEC_DEFINES_DEC_SPECIFICATION   :   self._SetDecSpecification,
414            DT.TAB_DEC_DEFINES_PACKAGE_NAME        :   self._SetPackageName,
415            DT.TAB_DEC_DEFINES_PACKAGE_GUID        :   self._SetPackageGuid,
416            DT.TAB_DEC_DEFINES_PACKAGE_VERSION     :   self._SetPackageVersion,
417            DT.TAB_DEC_DEFINES_PKG_UNI_FILE        :   self._SetPackageUni,
418        }
419
420    def BlockStart(self):
421        self._DefSecNum += 1
422        if self._DefSecNum > 1:
423            self._LoggerError(ST.ERR_DECPARSE_DEFINE_MULTISEC)
424
425    ## CheckRequiredFields
426    #
427    # Check required fields: DEC_SPECIFICATION, PACKAGE_NAME
428    #                        PACKAGE_GUID, PACKAGE_VERSION
429    #
430    def CheckRequiredFields(self):
431        Ret = False
432        if self.ItemObject.GetPackageSpecification() == '':
433            Logger.Error(TOOL_NAME, FILE_PARSE_FAILURE, File=self._RawData.Filename,
434                         ExtraData=ST.ERR_DECPARSE_DEFINE_REQUIRED % DT.TAB_DEC_DEFINES_DEC_SPECIFICATION)
435        elif self.ItemObject.GetPackageName() == '':
436            Logger.Error(TOOL_NAME, FILE_PARSE_FAILURE, File=self._RawData.Filename,
437                         ExtraData=ST.ERR_DECPARSE_DEFINE_REQUIRED % DT.TAB_DEC_DEFINES_PACKAGE_NAME)
438        elif self.ItemObject.GetPackageGuid() == '':
439            Logger.Error(TOOL_NAME, FILE_PARSE_FAILURE, File=self._RawData.Filename,
440                         ExtraData=ST.ERR_DECPARSE_DEFINE_REQUIRED % DT.TAB_DEC_DEFINES_PACKAGE_GUID)
441        elif self.ItemObject.GetPackageVersion() == '':
442            Logger.Error(TOOL_NAME, FILE_PARSE_FAILURE, File=self._RawData.Filename,
443                         ExtraData=ST.ERR_DECPARSE_DEFINE_REQUIRED % DT.TAB_DEC_DEFINES_PACKAGE_VERSION)
444        else:
445            Ret = True
446        return Ret
447
448    def _ParseItem(self):
449        Line = self._RawData.CurrentLine
450        TokenList = GetSplitValueList(Line, DT.TAB_EQUAL_SPLIT, 1)
451        if TokenList[0] == DT.TAB_DEC_DEFINES_PKG_UNI_FILE:
452            self.DefineValidation[TokenList[0]](TokenList[1])
453        elif len(TokenList) < 2:
454            self._LoggerError(ST.ERR_DECPARSE_DEFINE_FORMAT)
455        elif TokenList[0] not in self.DefineValidation:
456            self._LoggerError(ST.ERR_DECPARSE_DEFINE_UNKNOWKEY % TokenList[0])
457        else:
458            self.DefineValidation[TokenList[0]](TokenList[1])
459
460        DefineItem = DecDefineItemObject()
461        DefineItem.Key   = TokenList[0]
462        DefineItem.Value = TokenList[1]
463        self.ItemObject.AddItem(DefineItem, self._RawData.CurrentScope)
464        return DefineItem
465
466    def _SetDecSpecification(self, Token):
467        if self.ItemObject.GetPackageSpecification():
468            self._LoggerError(ST.ERR_DECPARSE_DEFINE_DEFINED % DT.TAB_DEC_DEFINES_DEC_SPECIFICATION)
469        if not IsValidToken('0[xX][0-9a-fA-F]{8}', Token):
470            if not IsValidDecVersionVal(Token):
471                self._LoggerError(ST.ERR_DECPARSE_DEFINE_SPEC)
472        self.ItemObject.SetPackageSpecification(Token)
473
474    def _SetPackageName(self, Token):
475        if self.ItemObject.GetPackageName():
476            self._LoggerError(ST.ERR_DECPARSE_DEFINE_DEFINED % DT.TAB_DEC_DEFINES_PACKAGE_NAME)
477        if not IsValidWord(Token):
478            self._LoggerError(ST.ERR_DECPARSE_DEFINE_PKGNAME)
479        self.ItemObject.SetPackageName(Token)
480
481    def _SetPackageGuid(self, Token):
482        if self.ItemObject.GetPackageGuid():
483            self._LoggerError(ST.ERR_DECPARSE_DEFINE_DEFINED % DT.TAB_DEC_DEFINES_PACKAGE_GUID)
484        if not CheckGuidRegFormat(Token):
485            self._LoggerError(ST.ERR_DECPARSE_DEFINE_PKGGUID)
486        self.ItemObject.SetPackageGuid(Token)
487
488    def _SetPackageVersion(self, Token):
489        if self.ItemObject.GetPackageVersion():
490            self._LoggerError(ST.ERR_DECPARSE_DEFINE_DEFINED % DT.TAB_DEC_DEFINES_PACKAGE_VERSION)
491        if not IsValidToken(VERSION_PATTERN, Token):
492            self._LoggerError(ST.ERR_DECPARSE_DEFINE_PKGVERSION)
493        else:
494            if not DT.TAB_SPLIT in Token:
495                Token = Token + '.0'
496            self.ItemObject.SetPackageVersion(Token)
497
498    def _SetPackageUni(self, Token):
499        if self.ItemObject.GetPackageUniFile():
500            self._LoggerError(ST.ERR_DECPARSE_DEFINE_DEFINED % DT.TAB_DEC_DEFINES_PKG_UNI_FILE)
501        self.ItemObject.SetPackageUniFile(Token)
502
503## _DecInclude
504#
505# Parse include section
506#
507class _DecInclude(_DecBase):
508    def __init__(self, RawData):
509        _DecBase.__init__(self, RawData)
510        self.ItemObject = DecIncludeObject(RawData.Filename)
511
512    def _ParseItem(self):
513        Line = self._RawData.CurrentLine
514
515        if not IsValidPath(Line, self._RawData.PackagePath):
516            self._LoggerError(ST.ERR_DECPARSE_INCLUDE % Line)
517
518        Item = DecIncludeItemObject(StripRoot(self._RawData.PackagePath, Line), self._RawData.PackagePath)
519        self.ItemObject.AddItem(Item, self._RawData.CurrentScope)
520        return Item
521
522## _DecLibraryclass
523#
524# Parse library class section
525#
526class _DecLibraryclass(_DecBase):
527    def __init__(self, RawData):
528        _DecBase.__init__(self, RawData)
529        self.ItemObject = DecLibraryclassObject(RawData.Filename)
530
531    def _ParseItem(self):
532        Line = self._RawData.CurrentLine
533        TokenList = GetSplitValueList(Line, DT.TAB_VALUE_SPLIT)
534        if len(TokenList) != 2:
535            self._LoggerError(ST.ERR_DECPARSE_LIBCLASS_SPLIT)
536        if TokenList[0] == '' or TokenList[1] == '':
537            self._LoggerError(ST.ERR_DECPARSE_LIBCLASS_EMPTY)
538        if not IsValidToken('[A-Z][0-9A-Za-z]*', TokenList[0]):
539            self._LoggerError(ST.ERR_DECPARSE_LIBCLASS_LIB)
540
541        self._CheckReDefine(TokenList[0])
542
543        Value = TokenList[1]
544        #
545        # Must end with .h
546        #
547        if not Value.endswith('.h'):
548            self._LoggerError(ST.ERR_DECPARSE_LIBCLASS_PATH_EXT)
549
550        #
551        # Path must be existed
552        #
553        if not IsValidPath(Value, self._RawData.PackagePath):
554            self._LoggerError(ST.ERR_DECPARSE_INCLUDE % Value)
555
556        Item = DecLibraryclassItemObject(TokenList[0], StripRoot(self._RawData.PackagePath, Value),
557                                         self._RawData.PackagePath)
558        self.ItemObject.AddItem(Item, self._RawData.CurrentScope)
559        return Item
560
561## _DecPcd
562#
563# Parse PCD section
564#
565class _DecPcd(_DecBase):
566    def __init__(self, RawData):
567        _DecBase.__init__(self, RawData)
568        self.ItemObject = DecPcdObject(RawData.Filename)
569        #
570        # Used to check duplicate token
571        # Key is token space and token number (integer), value is C name
572        #
573        self.TokenMap = {}
574
575    def _ParseItem(self):
576        Line = self._RawData.CurrentLine
577        TokenList = Line.split(DT.TAB_VALUE_SPLIT)
578        if len(TokenList) < 4:
579            self._LoggerError(ST.ERR_DECPARSE_PCD_SPLIT)
580
581        #
582        # Token space guid C name
583        #
584        PcdName = GetSplitValueList(TokenList[0], DT.TAB_SPLIT)
585        if len(PcdName) != 2 or PcdName[0] == '' or PcdName[1] == '':
586            self._LoggerError(ST.ERR_DECPARSE_PCD_NAME)
587
588        Guid = PcdName[0]
589        if not IsValidToken(CVAR_PATTERN, Guid):
590            self._LoggerError(ST.ERR_DECPARSE_PCD_CVAR_GUID)
591
592        #
593        # PCD C name
594        #
595        CName = PcdName[1]
596        if not IsValidToken(CVAR_PATTERN, CName):
597            self._LoggerError(ST.ERR_DECPARSE_PCD_CVAR_PCDCNAME)
598
599        self._CheckReDefine(Guid + DT.TAB_SPLIT + CName)
600
601        #
602        # Default value, may be C array, string or number
603        #
604        Data = DT.TAB_VALUE_SPLIT.join(TokenList[1:-2]).strip()
605
606        #
607        # PCD data type
608        #
609        DataType = TokenList[-2].strip()
610        Valid, Cause = IsValidPcdDatum(DataType, Data)
611        if not Valid:
612            self._LoggerError(Cause)
613        PcdType = self._RawData.CurrentScope[0][0]
614        if PcdType == DT.TAB_PCDS_FEATURE_FLAG_NULL.upper() and DataType != 'BOOLEAN':
615            self._LoggerError(ST.ERR_DECPARSE_PCD_FEATUREFLAG)
616        #
617        # Token value is the last element in list.
618        #
619        Token = TokenList[-1].strip()
620        if not IsValidToken(PCD_TOKEN_PATTERN, Token):
621            self._LoggerError(ST.ERR_DECPARSE_PCD_TOKEN % Token)
622        elif not Token.startswith('0x') and not Token.startswith('0X'):
623            if long(Token) > 4294967295:
624                self._LoggerError(ST.ERR_DECPARSE_PCD_TOKEN_INT % Token)
625            Token = hex(long(Token))[:-1]
626
627        IntToken = long(Token, 0)
628        if (Guid, IntToken) in self.TokenMap:
629            if self.TokenMap[Guid, IntToken] != CName:
630                self._LoggerError(ST.ERR_DECPARSE_PCD_TOKEN_UNIQUE%(Token))
631        else:
632            self.TokenMap[Guid, IntToken] = CName
633
634        Item = DecPcdItemObject(Guid, CName, Data, DataType, Token)
635        self.ItemObject.AddItem(Item, self._RawData.CurrentScope)
636        return Item
637
638## _DecGuid
639#
640# Parse GUID, PPI, Protocol section
641#
642class _DecGuid(_DecBase):
643    def __init__(self, RawData):
644        _DecBase.__init__(self, RawData)
645        self.GuidObj = DecGuidObject(RawData.Filename)
646        self.PpiObj = DecPpiObject(RawData.Filename)
647        self.ProtocolObj = DecProtocolObject(RawData.Filename)
648        self.ObjectDict = \
649        {
650            DT.TAB_GUIDS.upper()     :   self.GuidObj,
651            DT.TAB_PPIS.upper()      :   self.PpiObj,
652            DT.TAB_PROTOCOLS.upper() :   self.ProtocolObj
653        }
654
655    def GetDataObject(self):
656        if self._RawData.CurrentScope:
657            return self.ObjectDict[self._RawData.CurrentScope[0][0]]
658        return None
659
660    def GetGuidObject(self):
661        return self.GuidObj
662
663    def GetPpiObject(self):
664        return self.PpiObj
665
666    def GetProtocolObject(self):
667        return self.ProtocolObj
668
669    def _ParseItem(self):
670        Line = self._RawData.CurrentLine
671        TokenList = GetSplitValueList(Line, DT.TAB_EQUAL_SPLIT, 1)
672        if len(TokenList) < 2:
673            self._LoggerError(ST.ERR_DECPARSE_CGUID)
674        if TokenList[0] == '':
675            self._LoggerError(ST.ERR_DECPARSE_CGUID_NAME)
676        if TokenList[1] == '':
677            self._LoggerError(ST.ERR_DECPARSE_CGUID_GUID)
678        if not IsValidToken(CVAR_PATTERN, TokenList[0]):
679            self._LoggerError(ST.ERR_DECPARSE_PCD_CVAR_GUID)
680
681        self._CheckReDefine(TokenList[0])
682
683        if TokenList[1][0] != '{':
684            if not CheckGuidRegFormat(TokenList[1]):
685                self._LoggerError(ST.ERR_DECPARSE_DEFINE_PKGGUID)
686            GuidString = TokenList[1]
687        else:
688            #
689            # Convert C format GUID to GUID string and Simple error check
690            #
691            GuidString = GuidStructureStringToGuidString(TokenList[1])
692            if TokenList[1][0] != '{' or TokenList[1][-1] != '}' or GuidString == '':
693                self._LoggerError(ST.ERR_DECPARSE_CGUID_GUIDFORMAT)
694
695            #
696            # Check C format GUID
697            #
698            if not IsValidCFormatGuid(TokenList[1]):
699                self._LoggerError(ST.ERR_DECPARSE_CGUID_GUIDFORMAT)
700
701        Item = DecGuidItemObject(TokenList[0], TokenList[1], GuidString)
702        ItemObject = self.ObjectDict[self._RawData.CurrentScope[0][0]]
703        ItemObject.AddItem(Item, self._RawData.CurrentScope)
704        return Item
705
706## _DecUserExtension
707#
708# Parse user extention section
709#
710class _DecUserExtension(_DecBase):
711    def __init__(self, RawData):
712        _DecBase.__init__(self, RawData)
713        self.ItemObject = DecUserExtensionObject(RawData.Filename)
714        self._Headers = []
715        self._CurItems = []
716
717    def BlockStart(self):
718        self._CurItems = []
719        for Header in self._RawData.CurrentScope:
720            if Header in self._Headers:
721                self._LoggerError(ST.ERR_DECPARSE_UE_DUPLICATE)
722            else:
723                self._Headers.append(Header)
724
725            for Item in self._CurItems:
726                if Item.UserId == Header[1] and Item.IdString == Header[2]:
727                    Item.ArchAndModuleType.append(Header[3])
728                    break
729            else:
730                Item = DecUserExtensionItemObject()
731                Item.UserId = Header[1]
732                Item.IdString = Header[2]
733                Item.ArchAndModuleType.append(Header[3])
734                self._CurItems.append(Item)
735                self.ItemObject.AddItem(Item, None)
736        self._LocalMacro = {}
737
738    def _ParseItem(self):
739        Line = self._RawData.CurrentLine
740        Item = None
741        for Item in self._CurItems:
742            if Item.UserString:
743                Item.UserString = '\n'.join([Item.UserString, Line])
744            else:
745                Item.UserString = Line
746        return Item
747
748## Dec
749#
750# Top dec parser
751#
752class Dec(_DecBase, _DecComments):
753    def __init__(self, DecFile, Parse = True):
754        try:
755            Content = ConvertSpecialChar(open(DecFile, 'rb').readlines())
756        except BaseException:
757            Logger.Error(TOOL_NAME, FILE_OPEN_FAILURE, File=DecFile,
758                         ExtraData=ST.ERR_DECPARSE_FILEOPEN % DecFile)
759
760        #
761        # Pre-parser for Private section
762        #
763        self._Private = ''
764        __IsFoundPrivate = False
765        NewContent = []
766        for Line in Content:
767            Line = Line.strip()
768            if Line.startswith(DT.TAB_SECTION_START) and Line.endswith(DT.TAB_PRIVATE + DT.TAB_SECTION_END):
769                __IsFoundPrivate = True
770            if Line.startswith(DT.TAB_SECTION_START) and Line.endswith(DT.TAB_SECTION_END)\
771               and not Line.endswith(DT.TAB_PRIVATE + DT.TAB_SECTION_END):
772                __IsFoundPrivate = False
773            if __IsFoundPrivate:
774                self._Private += Line + '\r'
775            if not __IsFoundPrivate:
776                NewContent.append(Line + '\r')
777
778        RawData = FileContent(DecFile, NewContent)
779
780        _DecComments.__init__(self)
781        _DecBase.__init__(self, RawData)
782
783        self.BinaryHeadComment = []
784        self.PcdErrorCommentDict = {}
785
786        self._Define    = _DecDefine(RawData)
787        self._Include   = _DecInclude(RawData)
788        self._Guid      = _DecGuid(RawData)
789        self._LibClass  = _DecLibraryclass(RawData)
790        self._Pcd       = _DecPcd(RawData)
791        self._UserEx    = _DecUserExtension(RawData)
792
793        #
794        # DEC file supported data types (one type per section)
795        #
796        self._SectionParser = {
797            DT.TAB_DEC_DEFINES.upper()                     :   self._Define,
798            DT.TAB_INCLUDES.upper()                        :   self._Include,
799            DT.TAB_LIBRARY_CLASSES.upper()                 :   self._LibClass,
800            DT.TAB_GUIDS.upper()                           :   self._Guid,
801            DT.TAB_PPIS.upper()                            :   self._Guid,
802            DT.TAB_PROTOCOLS.upper()                       :   self._Guid,
803            DT.TAB_PCDS_FIXED_AT_BUILD_NULL.upper()        :   self._Pcd,
804            DT.TAB_PCDS_PATCHABLE_IN_MODULE_NULL.upper()   :   self._Pcd,
805            DT.TAB_PCDS_FEATURE_FLAG_NULL.upper()          :   self._Pcd,
806            DT.TAB_PCDS_DYNAMIC_NULL.upper()               :   self._Pcd,
807            DT.TAB_PCDS_DYNAMIC_EX_NULL.upper()            :   self._Pcd,
808            DT.TAB_USER_EXTENSIONS.upper()                 :   self._UserEx
809        }
810
811        if Parse:
812            self.ParseDecComment()
813            self.Parse()
814            #
815            # Parsing done, check required fields
816            #
817            self.CheckRequiredFields()
818
819    def CheckRequiredFields(self):
820        for SectionParser in self._SectionParser.values():
821            if not SectionParser.CheckRequiredFields():
822                return False
823        return True
824
825    ##
826    # Parse DEC file
827    #
828    def ParseDecComment(self):
829        IsFileHeader = False
830        IsBinaryHeader = False
831        FileHeaderLineIndex = -1
832        BinaryHeaderLineIndex = -1
833        TokenSpaceGuidCName = ''
834
835        #
836        # Parse PCD error comment section
837        #
838        while not self._RawData.IsEndOfFile():
839            self._RawData.CurrentLine = self._RawData.GetNextLine()
840            if self._RawData.CurrentLine.startswith(DT.TAB_COMMENT_SPLIT) and \
841                DT.TAB_SECTION_START in self._RawData.CurrentLine and \
842                DT.TAB_SECTION_END in self._RawData.CurrentLine:
843                self._RawData.CurrentLine = self._RawData.CurrentLine.replace(DT.TAB_COMMENT_SPLIT, '').strip()
844
845                if self._RawData.CurrentLine[0] == DT.TAB_SECTION_START and \
846                    self._RawData.CurrentLine[-1] == DT.TAB_SECTION_END:
847                    RawSection = self._RawData.CurrentLine[1:-1].strip()
848                    if RawSection.upper().startswith(DT.TAB_PCD_ERROR.upper()+'.'):
849                        TokenSpaceGuidCName = RawSection.split(DT.TAB_PCD_ERROR+'.')[1].strip()
850                        continue
851
852            if TokenSpaceGuidCName and self._RawData.CurrentLine.startswith(DT.TAB_COMMENT_SPLIT):
853                self._RawData.CurrentLine = self._RawData.CurrentLine.replace(DT.TAB_COMMENT_SPLIT, '').strip()
854                if self._RawData.CurrentLine != '':
855                    if DT.TAB_VALUE_SPLIT not in self._RawData.CurrentLine:
856                        self._LoggerError(ST.ERR_DECPARSE_PCDERRORMSG_MISS_VALUE_SPLIT)
857
858                    PcdErrorNumber, PcdErrorMsg = GetSplitValueList(self._RawData.CurrentLine, DT.TAB_VALUE_SPLIT, 1)
859                    PcdErrorNumber = ParsePcdErrorCode(PcdErrorNumber, self._RawData.Filename, self._RawData.LineIndex)
860                    if not PcdErrorMsg.strip():
861                        self._LoggerError(ST.ERR_DECPARSE_PCD_MISS_ERRORMSG)
862
863                    self.PcdErrorCommentDict[(TokenSpaceGuidCName, PcdErrorNumber)] = PcdErrorMsg.strip()
864            else:
865                TokenSpaceGuidCName = ''
866
867        self._RawData.LineIndex = 0
868        self._RawData.CurrentLine = ''
869        self._RawData.NextLine = ''
870
871        while not self._RawData.IsEndOfFile():
872            Line, Comment = CleanString(self._RawData.GetNextLine())
873
874            #
875            # Header must be pure comment
876            #
877            if Line != '':
878                self._RawData.UndoNextLine()
879                break
880
881            if Comment and Comment.startswith(DT.TAB_SPECIAL_COMMENT) and Comment.find(DT.TAB_HEADER_COMMENT) > 0 \
882                and not Comment[2:Comment.find(DT.TAB_HEADER_COMMENT)].strip():
883                IsFileHeader = True
884                IsBinaryHeader = False
885                FileHeaderLineIndex = self._RawData.LineIndex
886
887            #
888            # Get license information before '@file'
889            #
890            if not IsFileHeader and not IsBinaryHeader and Comment and Comment.startswith(DT.TAB_COMMENT_SPLIT) and \
891            DT.TAB_BINARY_HEADER_COMMENT not in Comment:
892                self._HeadComment.append((Comment, self._RawData.LineIndex))
893
894            if Comment and IsFileHeader and \
895            not(Comment.startswith(DT.TAB_SPECIAL_COMMENT) \
896            and Comment.find(DT.TAB_BINARY_HEADER_COMMENT) > 0):
897                self._HeadComment.append((Comment, self._RawData.LineIndex))
898            #
899            # Double '#' indicates end of header comments
900            #
901            if (not Comment or Comment == DT.TAB_SPECIAL_COMMENT) and IsFileHeader:
902                IsFileHeader = False
903                continue
904
905            if Comment and Comment.startswith(DT.TAB_SPECIAL_COMMENT) \
906            and Comment.find(DT.TAB_BINARY_HEADER_COMMENT) > 0:
907                IsBinaryHeader = True
908                IsFileHeader = False
909                BinaryHeaderLineIndex = self._RawData.LineIndex
910
911            if Comment and IsBinaryHeader:
912                self.BinaryHeadComment.append((Comment, self._RawData.LineIndex))
913            #
914            # Double '#' indicates end of header comments
915            #
916            if (not Comment or Comment == DT.TAB_SPECIAL_COMMENT) and IsBinaryHeader:
917                IsBinaryHeader = False
918                break
919
920            if FileHeaderLineIndex > -1 and not IsFileHeader and not IsBinaryHeader:
921                break
922
923        if FileHeaderLineIndex > BinaryHeaderLineIndex and FileHeaderLineIndex > -1 and BinaryHeaderLineIndex > -1:
924            self._LoggerError(ST.ERR_BINARY_HEADER_ORDER)
925
926        if FileHeaderLineIndex == -1:
927#            self._LoggerError(ST.ERR_NO_SOURCE_HEADER)
928            Logger.Error(TOOL_NAME, FORMAT_INVALID,
929                         ST.ERR_NO_SOURCE_HEADER,
930                         File=self._RawData.Filename)
931        return
932
933    def _StopCurrentParsing(self, Line):
934        return False
935
936    def _ParseItem(self):
937        self._SectionHeaderParser()
938        if len(self._RawData.CurrentScope) == 0:
939            self._LoggerError(ST.ERR_DECPARSE_SECTION_EMPTY)
940        SectionObj = self._SectionParser[self._RawData.CurrentScope[0][0]]
941        SectionObj.BlockStart()
942        SectionObj.Parse()
943        return SectionObj.GetDataObject()
944
945    def _UserExtentionSectionParser(self):
946        self._RawData.CurrentScope = []
947        ArchList = set()
948        Section = self._RawData.CurrentLine[1:-1]
949        Par = ParserHelper(Section, self._RawData.Filename)
950        while not Par.End():
951            #
952            # User extention
953            #
954            Token = Par.GetToken()
955            if Token.upper() != DT.TAB_USER_EXTENSIONS.upper():
956                self._LoggerError(ST.ERR_DECPARSE_SECTION_UE)
957            UserExtension = Token.upper()
958            Par.AssertChar(DT.TAB_SPLIT, ST.ERR_DECPARSE_SECTION_UE, self._RawData.LineIndex)
959
960            #
961            # UserID
962            #
963            Token = Par.GetToken()
964            if not IsValidUserId(Token):
965                self._LoggerError(ST.ERR_DECPARSE_SECTION_UE_USERID)
966            UserId = Token
967            Par.AssertChar(DT.TAB_SPLIT, ST.ERR_DECPARSE_SECTION_UE, self._RawData.LineIndex)
968            #
969            # IdString
970            #
971            Token = Par.GetToken()
972            if not IsValidIdString(Token):
973                self._LoggerError(ST.ERR_DECPARSE_SECTION_UE_IDSTRING)
974            IdString = Token
975            Arch = 'COMMON'
976            if Par.Expect(DT.TAB_SPLIT):
977                Token = Par.GetToken()
978                Arch = Token.upper()
979                if not IsValidArch(Arch):
980                    self._LoggerError(ST.ERR_DECPARSE_ARCH)
981            ArchList.add(Arch)
982            if [UserExtension, UserId, IdString, Arch] not in \
983                self._RawData.CurrentScope:
984                self._RawData.CurrentScope.append(
985                    [UserExtension, UserId, IdString, Arch]
986                )
987            if not Par.Expect(DT.TAB_COMMA_SPLIT):
988                break
989            elif Par.End():
990                self._LoggerError(ST.ERR_DECPARSE_SECTION_COMMA)
991        Par.AssertEnd(ST.ERR_DECPARSE_SECTION_UE, self._RawData.LineIndex)
992        if 'COMMON' in ArchList and len(ArchList) > 1:
993            self._LoggerError(ST.ERR_DECPARSE_SECTION_COMMON)
994
995    ## Section header parser
996    #
997    # The section header is always in following format:
998    #
999    # [section_name.arch<.platform|module_type>]
1000    #
1001    def _SectionHeaderParser(self):
1002        if self._RawData.CurrentLine[0] != DT.TAB_SECTION_START or self._RawData.CurrentLine[-1] != DT.TAB_SECTION_END:
1003            self._LoggerError(ST.ERR_DECPARSE_SECTION_IDENTIFY)
1004
1005        RawSection = self._RawData.CurrentLine[1:-1].strip().upper()
1006        #
1007        # Check defines section which is only allowed to occur once and
1008        # no arch can be followed
1009        #
1010        if RawSection.startswith(DT.TAB_DEC_DEFINES.upper()):
1011            if RawSection != DT.TAB_DEC_DEFINES.upper():
1012                self._LoggerError(ST.ERR_DECPARSE_DEFINE_SECNAME)
1013        #
1014        # Check user extension section
1015        #
1016        if RawSection.startswith(DT.TAB_USER_EXTENSIONS.upper()):
1017            return self._UserExtentionSectionParser()
1018        self._RawData.CurrentScope = []
1019        SectionNames = []
1020        ArchList = set()
1021        for Item in GetSplitValueList(RawSection, DT.TAB_COMMA_SPLIT):
1022            if Item == '':
1023                self._LoggerError(ST.ERR_DECPARSE_SECTION_SUBEMPTY % self._RawData.CurrentLine)
1024
1025            ItemList = GetSplitValueList(Item, DT.TAB_SPLIT)
1026            #
1027            # different types of PCD are permissible in one section
1028            #
1029            SectionName = ItemList[0]
1030            if SectionName not in self._SectionParser:
1031                self._LoggerError(ST.ERR_DECPARSE_SECTION_UNKNOW % SectionName)
1032            if SectionName not in SectionNames:
1033                SectionNames.append(SectionName)
1034            #
1035            # In DEC specification, all section headers have at most two part:
1036            # SectionName.Arch except UserExtention
1037            #
1038            if len(ItemList) > 2:
1039                self._LoggerError(ST.ERR_DECPARSE_SECTION_SUBTOOMANY % Item)
1040
1041            if DT.TAB_PCDS_FEATURE_FLAG_NULL.upper() in SectionNames and len(SectionNames) > 1:
1042                self._LoggerError(ST.ERR_DECPARSE_SECTION_FEATUREFLAG % DT.TAB_PCDS_FEATURE_FLAG_NULL)
1043            #
1044            # S1 is always Arch
1045            #
1046            if len(ItemList) > 1:
1047                Str1 = ItemList[1]
1048                if not IsValidArch(Str1):
1049                    self._LoggerError(ST.ERR_DECPARSE_ARCH)
1050            else:
1051                Str1 = 'COMMON'
1052            ArchList.add(Str1)
1053
1054            if [SectionName, Str1] not in self._RawData.CurrentScope:
1055                self._RawData.CurrentScope.append([SectionName, Str1])
1056        #
1057        # 'COMMON' must not be used with specific ARCHs at the same section
1058        #
1059        if 'COMMON' in ArchList and len(ArchList) > 1:
1060            self._LoggerError(ST.ERR_DECPARSE_SECTION_COMMON)
1061        if len(SectionNames) == 0:
1062            self._LoggerError(ST.ERR_DECPARSE_SECTION_SUBEMPTY % self._RawData.CurrentLine)
1063        if len(SectionNames) != 1:
1064            for Sec in SectionNames:
1065                if not Sec.startswith(DT.TAB_PCDS.upper()):
1066                    self._LoggerError(ST.ERR_DECPARSE_SECTION_NAME % str(SectionNames))
1067
1068    def GetDefineSectionMacro(self):
1069        return self._Define.GetLocalMacro()
1070    def GetDefineSectionObject(self):
1071        return self._Define.GetDataObject()
1072    def GetIncludeSectionObject(self):
1073        return self._Include.GetDataObject()
1074    def GetGuidSectionObject(self):
1075        return self._Guid.GetGuidObject()
1076    def GetProtocolSectionObject(self):
1077        return self._Guid.GetProtocolObject()
1078    def GetPpiSectionObject(self):
1079        return self._Guid.GetPpiObject()
1080    def GetLibraryClassSectionObject(self):
1081        return self._LibClass.GetDataObject()
1082    def GetPcdSectionObject(self):
1083        return self._Pcd.GetDataObject()
1084    def GetUserExtensionSectionObject(self):
1085        return self._UserEx.GetDataObject()
1086    def GetPackageSpecification(self):
1087        return self._Define.GetDataObject().GetPackageSpecification()
1088    def GetPackageName(self):
1089        return self._Define.GetDataObject().GetPackageName()
1090    def GetPackageGuid(self):
1091        return self._Define.GetDataObject().GetPackageGuid()
1092    def GetPackageVersion(self):
1093        return self._Define.GetDataObject().GetPackageVersion()
1094    def GetPackageUniFile(self):
1095        return self._Define.GetDataObject().GetPackageUniFile()
1096    def GetPrivateSections(self):
1097        return self._Private
1098