1## @file
2# This file is used to parse DEC file. It will consumed by DecParser
3#
4# Copyright (c) 2011 - 2014, 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        self._RawData.CurrentLine = self._ReplaceMacro(CatLine)
274        return CatLine, CommentList
275
276    ## Parse
277    # This is a template method in which other member functions which might
278    # override by sub class are called. It is responsible for reading file
279    # line by line, and call other member functions to parse. This function
280    # should not be re-implement by sub class.
281    #
282    def Parse(self):
283        HeadComments = []
284        TailComments = []
285
286        #======================================================================
287        # CurComments may pointer to HeadComments or TailComments
288        #======================================================================
289        CurComments = HeadComments
290        CurObj = None
291        ItemNum = 0
292        FromBuf = False
293
294        #======================================================================
295        # Used to report error information if empty section found
296        #======================================================================
297        Index = self._RawData.LineIndex
298        LineStr = self._RawData.CurrentLine
299        while not self._RawData.IsEndOfFile() or self._RawData.NextLine:
300            if self._RawData.NextLine:
301                #==============================================================
302                # Have processed line in buffer
303                #==============================================================
304                Line = self._RawData.NextLine
305                HeadComments.extend(self._RawData.HeadComment)
306                TailComments.extend(self._RawData.TailComment)
307                self._RawData.ResetNext()
308                Comment = ''
309                FromBuf = True
310            else:
311                #==============================================================
312                # No line in buffer, read next line
313                #==============================================================
314                Line, Comment = CleanString(self._RawData.GetNextLine())
315                FromBuf = False
316            if Line:
317                if not FromBuf and CurObj and TailComments:
318                    #==========================================================
319                    # Set tail comments to previous statement if not empty.
320                    #==========================================================
321                    CurObj.SetTailComment(CurObj.GetTailComment()+TailComments)
322
323                if not FromBuf:
324                    del TailComments[:]
325                CurComments = TailComments
326                Comments = []
327                if Comment:
328                    Comments = [(Comment, self._RawData.LineIndex)]
329
330                #==============================================================
331                # Try if last char of line has backslash
332                #==============================================================
333                Line, Comments = self._TryBackSlash(Line, Comments)
334                CurComments.extend(Comments)
335
336                #==============================================================
337                # Macro found
338                #==============================================================
339                if Line.startswith('DEFINE '):
340                    self._MacroParser(Line)
341                    del HeadComments[:]
342                    del TailComments[:]
343                    CurComments = HeadComments
344                    continue
345
346                if self._StopCurrentParsing(Line):
347                    #==========================================================
348                    # This line does not belong to this parse,
349                    # Save it, can be used by next parse
350                    #==========================================================
351                    self._RawData.SetNext(Line, HeadComments, TailComments)
352                    break
353
354                Obj = self._ParseItem()
355                ItemNum += 1
356                if Obj:
357                    Obj.SetHeadComment(Obj.GetHeadComment()+HeadComments)
358                    Obj.SetTailComment(Obj.GetTailComment()+TailComments)
359                    del HeadComments[:]
360                    del TailComments[:]
361                    CurObj = Obj
362                else:
363                    CurObj = None
364            else:
365                if id(CurComments) == id(TailComments):
366                    #==========================================================
367                    # Check if this comment belongs to tail comment
368                    #==========================================================
369                    if not self._TailCommentStrategy(Comment):
370                        CurComments = HeadComments
371
372                if Comment:
373                    CurComments.append(((Comment, self._RawData.LineIndex)))
374                else:
375                    del CurComments[:]
376
377        if self._IsStatementRequired() and ItemNum == 0:
378            Logger.Error(
379                    TOOL_NAME, FILE_PARSE_FAILURE,
380                    File=self._RawData.Filename,
381                    Line=Index,
382                    ExtraData=ST.ERR_DECPARSE_STATEMENT_EMPTY % LineStr
383            )
384
385## _DecDefine
386# Parse define section
387#
388class _DecDefine(_DecBase):
389    def __init__(self, RawData):
390        _DecBase.__init__(self, RawData)
391        self.ItemObject = DecDefineObject(RawData.Filename)
392        self._LocalMacro = self._RawData.Macros
393        self._DefSecNum = 0
394
395        #
396        # Each field has a function to validate
397        #
398        self.DefineValidation = {
399            DT.TAB_DEC_DEFINES_DEC_SPECIFICATION   :   self._SetDecSpecification,
400            DT.TAB_DEC_DEFINES_PACKAGE_NAME        :   self._SetPackageName,
401            DT.TAB_DEC_DEFINES_PACKAGE_GUID        :   self._SetPackageGuid,
402            DT.TAB_DEC_DEFINES_PACKAGE_VERSION     :   self._SetPackageVersion,
403            DT.TAB_DEC_DEFINES_PKG_UNI_FILE        :   self._SetPackageUni,
404        }
405
406    def BlockStart(self):
407        self._DefSecNum += 1
408        if self._DefSecNum > 1:
409            self._LoggerError(ST.ERR_DECPARSE_DEFINE_MULTISEC)
410
411    ## CheckRequiredFields
412    #
413    # Check required fields: DEC_SPECIFICATION, PACKAGE_NAME
414    #                        PACKAGE_GUID, PACKAGE_VERSION
415    #
416    def CheckRequiredFields(self):
417        Ret = False
418        if self.ItemObject.GetPackageSpecification() == '':
419            Logger.Error(TOOL_NAME, FILE_PARSE_FAILURE, File=self._RawData.Filename,
420                         ExtraData=ST.ERR_DECPARSE_DEFINE_REQUIRED % DT.TAB_DEC_DEFINES_DEC_SPECIFICATION)
421        elif self.ItemObject.GetPackageName() == '':
422            Logger.Error(TOOL_NAME, FILE_PARSE_FAILURE, File=self._RawData.Filename,
423                         ExtraData=ST.ERR_DECPARSE_DEFINE_REQUIRED % DT.TAB_DEC_DEFINES_PACKAGE_NAME)
424        elif self.ItemObject.GetPackageGuid() == '':
425            Logger.Error(TOOL_NAME, FILE_PARSE_FAILURE, File=self._RawData.Filename,
426                         ExtraData=ST.ERR_DECPARSE_DEFINE_REQUIRED % DT.TAB_DEC_DEFINES_PACKAGE_GUID)
427        elif self.ItemObject.GetPackageVersion() == '':
428            Logger.Error(TOOL_NAME, FILE_PARSE_FAILURE, File=self._RawData.Filename,
429                         ExtraData=ST.ERR_DECPARSE_DEFINE_REQUIRED % DT.TAB_DEC_DEFINES_PACKAGE_VERSION)
430        else:
431            Ret = True
432        return Ret
433
434    def _ParseItem(self):
435        Line = self._RawData.CurrentLine
436        TokenList = GetSplitValueList(Line, DT.TAB_EQUAL_SPLIT, 1)
437        if TokenList[0] == DT.TAB_DEC_DEFINES_PKG_UNI_FILE:
438            self.DefineValidation[TokenList[0]](TokenList[1])
439        elif len(TokenList) < 2:
440            self._LoggerError(ST.ERR_DECPARSE_DEFINE_FORMAT)
441        elif TokenList[0] not in self.DefineValidation:
442            self._LoggerError(ST.ERR_DECPARSE_DEFINE_UNKNOWKEY % TokenList[0])
443        else:
444            self.DefineValidation[TokenList[0]](TokenList[1])
445
446        DefineItem = DecDefineItemObject()
447        DefineItem.Key   = TokenList[0]
448        DefineItem.Value = TokenList[1]
449        self.ItemObject.AddItem(DefineItem, self._RawData.CurrentScope)
450        return DefineItem
451
452    def _SetDecSpecification(self, Token):
453        if self.ItemObject.GetPackageSpecification():
454            self._LoggerError(ST.ERR_DECPARSE_DEFINE_DEFINED % DT.TAB_DEC_DEFINES_DEC_SPECIFICATION)
455        if not IsValidToken('0[xX][0-9a-fA-F]{8}', Token):
456            if not IsValidDecVersionVal(Token):
457                self._LoggerError(ST.ERR_DECPARSE_DEFINE_SPEC)
458        self.ItemObject.SetPackageSpecification(Token)
459
460    def _SetPackageName(self, Token):
461        if self.ItemObject.GetPackageName():
462            self._LoggerError(ST.ERR_DECPARSE_DEFINE_DEFINED % DT.TAB_DEC_DEFINES_PACKAGE_NAME)
463        if not IsValidWord(Token):
464            self._LoggerError(ST.ERR_DECPARSE_DEFINE_PKGNAME)
465        self.ItemObject.SetPackageName(Token)
466
467    def _SetPackageGuid(self, Token):
468        if self.ItemObject.GetPackageGuid():
469            self._LoggerError(ST.ERR_DECPARSE_DEFINE_DEFINED % DT.TAB_DEC_DEFINES_PACKAGE_GUID)
470        if not CheckGuidRegFormat(Token):
471            self._LoggerError(ST.ERR_DECPARSE_DEFINE_PKGGUID)
472        self.ItemObject.SetPackageGuid(Token)
473
474    def _SetPackageVersion(self, Token):
475        if self.ItemObject.GetPackageVersion():
476            self._LoggerError(ST.ERR_DECPARSE_DEFINE_DEFINED % DT.TAB_DEC_DEFINES_PACKAGE_VERSION)
477        if not IsValidToken(VERSION_PATTERN, Token):
478            self._LoggerError(ST.ERR_DECPARSE_DEFINE_PKGVERSION)
479        else:
480            if not DT.TAB_SPLIT in Token:
481                Token = Token + '.0'
482            self.ItemObject.SetPackageVersion(Token)
483
484    def _SetPackageUni(self, Token):
485        if self.ItemObject.GetPackageUniFile():
486            self._LoggerError(ST.ERR_DECPARSE_DEFINE_DEFINED % DT.TAB_DEC_DEFINES_PKG_UNI_FILE)
487        self.ItemObject.SetPackageUniFile(Token)
488
489## _DecInclude
490#
491# Parse include section
492#
493class _DecInclude(_DecBase):
494    def __init__(self, RawData):
495        _DecBase.__init__(self, RawData)
496        self.ItemObject = DecIncludeObject(RawData.Filename)
497
498    def _ParseItem(self):
499        Line = self._RawData.CurrentLine
500
501        if not IsValidPath(Line, self._RawData.PackagePath):
502            self._LoggerError(ST.ERR_DECPARSE_INCLUDE % Line)
503
504        Item = DecIncludeItemObject(StripRoot(self._RawData.PackagePath, Line), self._RawData.PackagePath)
505        self.ItemObject.AddItem(Item, self._RawData.CurrentScope)
506        return Item
507
508## _DecLibraryclass
509#
510# Parse library class section
511#
512class _DecLibraryclass(_DecBase):
513    def __init__(self, RawData):
514        _DecBase.__init__(self, RawData)
515        self.ItemObject = DecLibraryclassObject(RawData.Filename)
516
517    def _ParseItem(self):
518        Line = self._RawData.CurrentLine
519        TokenList = GetSplitValueList(Line, DT.TAB_VALUE_SPLIT)
520        if len(TokenList) != 2:
521            self._LoggerError(ST.ERR_DECPARSE_LIBCLASS_SPLIT)
522        if TokenList[0] == '' or TokenList[1] == '':
523            self._LoggerError(ST.ERR_DECPARSE_LIBCLASS_EMPTY)
524        if not IsValidToken('[A-Z][0-9A-Za-z]*', TokenList[0]):
525            self._LoggerError(ST.ERR_DECPARSE_LIBCLASS_LIB)
526
527        self._CheckReDefine(TokenList[0])
528
529        Value = TokenList[1]
530        #
531        # Must end with .h
532        #
533        if not Value.endswith('.h'):
534            self._LoggerError(ST.ERR_DECPARSE_LIBCLASS_PATH_EXT)
535
536        #
537        # Path must be existed
538        #
539        if not IsValidPath(Value, self._RawData.PackagePath):
540            self._LoggerError(ST.ERR_DECPARSE_INCLUDE % Value)
541
542        Item = DecLibraryclassItemObject(TokenList[0], StripRoot(self._RawData.PackagePath, Value),
543                                         self._RawData.PackagePath)
544        self.ItemObject.AddItem(Item, self._RawData.CurrentScope)
545        return Item
546
547## _DecPcd
548#
549# Parse PCD section
550#
551class _DecPcd(_DecBase):
552    def __init__(self, RawData):
553        _DecBase.__init__(self, RawData)
554        self.ItemObject = DecPcdObject(RawData.Filename)
555        #
556        # Used to check duplicate token
557        # Key is token space and token number (integer), value is C name
558        #
559        self.TokenMap = {}
560
561    def _ParseItem(self):
562        Line = self._RawData.CurrentLine
563        TokenList = Line.split(DT.TAB_VALUE_SPLIT)
564        if len(TokenList) < 4:
565            self._LoggerError(ST.ERR_DECPARSE_PCD_SPLIT)
566
567        #
568        # Token space guid C name
569        #
570        PcdName = GetSplitValueList(TokenList[0], DT.TAB_SPLIT)
571        if len(PcdName) != 2 or PcdName[0] == '' or PcdName[1] == '':
572            self._LoggerError(ST.ERR_DECPARSE_PCD_NAME)
573
574        Guid = PcdName[0]
575        if not IsValidToken(CVAR_PATTERN, Guid):
576            self._LoggerError(ST.ERR_DECPARSE_PCD_CVAR_GUID)
577
578        #
579        # PCD C name
580        #
581        CName = PcdName[1]
582        if not IsValidToken(CVAR_PATTERN, CName):
583            self._LoggerError(ST.ERR_DECPARSE_PCD_CVAR_PCDCNAME)
584
585        self._CheckReDefine(Guid + DT.TAB_SPLIT + CName)
586
587        #
588        # Default value, may be C array, string or number
589        #
590        Data = DT.TAB_VALUE_SPLIT.join(TokenList[1:-2]).strip()
591
592        #
593        # PCD data type
594        #
595        DataType = TokenList[-2].strip()
596        Valid, Cause = IsValidPcdDatum(DataType, Data)
597        if not Valid:
598            self._LoggerError(Cause)
599        PcdType = self._RawData.CurrentScope[0][0]
600        if PcdType == DT.TAB_PCDS_FEATURE_FLAG_NULL.upper() and DataType != 'BOOLEAN':
601            self._LoggerError(ST.ERR_DECPARSE_PCD_FEATUREFLAG)
602        #
603        # Token value is the last element in list.
604        #
605        Token = TokenList[-1].strip()
606        if not IsValidToken(PCD_TOKEN_PATTERN, Token):
607            self._LoggerError(ST.ERR_DECPARSE_PCD_TOKEN % Token)
608        elif not Token.startswith('0x') and not Token.startswith('0X'):
609            if long(Token) > 4294967295:
610                self._LoggerError(ST.ERR_DECPARSE_PCD_TOKEN_INT % Token)
611            Token = hex(long(Token))[:-1]
612
613        IntToken = long(Token, 0)
614        if (Guid, IntToken) in self.TokenMap:
615            if self.TokenMap[Guid, IntToken] != CName:
616                self._LoggerError(ST.ERR_DECPARSE_PCD_TOKEN_UNIQUE%(Token))
617        else:
618            self.TokenMap[Guid, IntToken] = CName
619
620        Item = DecPcdItemObject(Guid, CName, Data, DataType, Token)
621        self.ItemObject.AddItem(Item, self._RawData.CurrentScope)
622        return Item
623
624## _DecGuid
625#
626# Parse GUID, PPI, Protocol section
627#
628class _DecGuid(_DecBase):
629    def __init__(self, RawData):
630        _DecBase.__init__(self, RawData)
631        self.GuidObj = DecGuidObject(RawData.Filename)
632        self.PpiObj = DecPpiObject(RawData.Filename)
633        self.ProtocolObj = DecProtocolObject(RawData.Filename)
634        self.ObjectDict = \
635        {
636            DT.TAB_GUIDS.upper()     :   self.GuidObj,
637            DT.TAB_PPIS.upper()      :   self.PpiObj,
638            DT.TAB_PROTOCOLS.upper() :   self.ProtocolObj
639        }
640
641    def GetDataObject(self):
642        if self._RawData.CurrentScope:
643            return self.ObjectDict[self._RawData.CurrentScope[0][0]]
644        return None
645
646    def GetGuidObject(self):
647        return self.GuidObj
648
649    def GetPpiObject(self):
650        return self.PpiObj
651
652    def GetProtocolObject(self):
653        return self.ProtocolObj
654
655    def _ParseItem(self):
656        Line = self._RawData.CurrentLine
657        TokenList = GetSplitValueList(Line, DT.TAB_EQUAL_SPLIT, 1)
658        if len(TokenList) < 2:
659            self._LoggerError(ST.ERR_DECPARSE_CGUID)
660        if TokenList[0] == '':
661            self._LoggerError(ST.ERR_DECPARSE_CGUID_NAME)
662        if TokenList[1] == '':
663            self._LoggerError(ST.ERR_DECPARSE_CGUID_GUID)
664        if not IsValidToken(CVAR_PATTERN, TokenList[0]):
665            self._LoggerError(ST.ERR_DECPARSE_PCD_CVAR_GUID)
666
667        self._CheckReDefine(TokenList[0])
668
669        if TokenList[1][0] != '{':
670            if not CheckGuidRegFormat(TokenList[1]):
671                self._LoggerError(ST.ERR_DECPARSE_DEFINE_PKGGUID)
672            GuidString = TokenList[1]
673        else:
674            #
675            # Convert C format GUID to GUID string and Simple error check
676            #
677            GuidString = GuidStructureStringToGuidString(TokenList[1])
678            if TokenList[1][0] != '{' or TokenList[1][-1] != '}' or GuidString == '':
679                self._LoggerError(ST.ERR_DECPARSE_CGUID_GUIDFORMAT)
680
681            #
682            # Check C format GUID
683            #
684            if not IsValidCFormatGuid(TokenList[1]):
685                self._LoggerError(ST.ERR_DECPARSE_CGUID_GUIDFORMAT)
686
687        Item = DecGuidItemObject(TokenList[0], TokenList[1], GuidString)
688        ItemObject = self.ObjectDict[self._RawData.CurrentScope[0][0]]
689        ItemObject.AddItem(Item, self._RawData.CurrentScope)
690        return Item
691
692## _DecUserExtension
693#
694# Parse user extention section
695#
696class _DecUserExtension(_DecBase):
697    def __init__(self, RawData):
698        _DecBase.__init__(self, RawData)
699        self.ItemObject = DecUserExtensionObject(RawData.Filename)
700        self._Headers = []
701        self._CurItems = []
702
703    def BlockStart(self):
704        self._CurItems = []
705        for Header in self._RawData.CurrentScope:
706            if Header in self._Headers:
707                self._LoggerError(ST.ERR_DECPARSE_UE_DUPLICATE)
708            else:
709                self._Headers.append(Header)
710
711            for Item in self._CurItems:
712                if Item.UserId == Header[1] and Item.IdString == Header[2]:
713                    Item.ArchAndModuleType.append(Header[3])
714                    break
715            else:
716                Item = DecUserExtensionItemObject()
717                Item.UserId = Header[1]
718                Item.IdString = Header[2]
719                Item.ArchAndModuleType.append(Header[3])
720                self._CurItems.append(Item)
721                self.ItemObject.AddItem(Item, None)
722        self._LocalMacro = {}
723
724    def _ParseItem(self):
725        Line = self._RawData.CurrentLine
726        Item = None
727        for Item in self._CurItems:
728            if Item.UserString:
729                Item.UserString = '\n'.join([Item.UserString, Line])
730            else:
731                Item.UserString = Line
732        return Item
733
734## Dec
735#
736# Top dec parser
737#
738class Dec(_DecBase, _DecComments):
739    def __init__(self, DecFile, Parse = True):
740        try:
741            Content = ConvertSpecialChar(open(DecFile, 'rb').readlines())
742        except BaseException:
743            Logger.Error(TOOL_NAME, FILE_OPEN_FAILURE, File=DecFile,
744                         ExtraData=ST.ERR_DECPARSE_FILEOPEN % DecFile)
745        RawData = FileContent(DecFile, Content)
746
747        _DecComments.__init__(self)
748        _DecBase.__init__(self, RawData)
749
750        self.BinaryHeadComment = []
751        self.PcdErrorCommentDict = {}
752
753        self._Define    = _DecDefine(RawData)
754        self._Include   = _DecInclude(RawData)
755        self._Guid      = _DecGuid(RawData)
756        self._LibClass  = _DecLibraryclass(RawData)
757        self._Pcd       = _DecPcd(RawData)
758        self._UserEx    = _DecUserExtension(RawData)
759
760        #
761        # DEC file supported data types (one type per section)
762        #
763        self._SectionParser = {
764            DT.TAB_DEC_DEFINES.upper()                     :   self._Define,
765            DT.TAB_INCLUDES.upper()                        :   self._Include,
766            DT.TAB_LIBRARY_CLASSES.upper()                 :   self._LibClass,
767            DT.TAB_GUIDS.upper()                           :   self._Guid,
768            DT.TAB_PPIS.upper()                            :   self._Guid,
769            DT.TAB_PROTOCOLS.upper()                       :   self._Guid,
770            DT.TAB_PCDS_FIXED_AT_BUILD_NULL.upper()        :   self._Pcd,
771            DT.TAB_PCDS_PATCHABLE_IN_MODULE_NULL.upper()   :   self._Pcd,
772            DT.TAB_PCDS_FEATURE_FLAG_NULL.upper()          :   self._Pcd,
773            DT.TAB_PCDS_DYNAMIC_NULL.upper()               :   self._Pcd,
774            DT.TAB_PCDS_DYNAMIC_EX_NULL.upper()            :   self._Pcd,
775            DT.TAB_USER_EXTENSIONS.upper()                 :   self._UserEx
776        }
777
778        if Parse:
779            self.ParseDecComment()
780            self.Parse()
781            #
782            # Parsing done, check required fields
783            #
784            self.CheckRequiredFields()
785
786    def CheckRequiredFields(self):
787        for SectionParser in self._SectionParser.values():
788            if not SectionParser.CheckRequiredFields():
789                return False
790        return True
791
792    ##
793    # Parse DEC file
794    #
795    def ParseDecComment(self):
796        IsFileHeader = False
797        IsBinaryHeader = False
798        FileHeaderLineIndex = -1
799        BinaryHeaderLineIndex = -1
800        TokenSpaceGuidCName = ''
801
802        #
803        # Parse PCD error comment section
804        #
805        while not self._RawData.IsEndOfFile():
806            self._RawData.CurrentLine = self._RawData.GetNextLine()
807            if self._RawData.CurrentLine.startswith(DT.TAB_COMMENT_SPLIT) and \
808                DT.TAB_SECTION_START in self._RawData.CurrentLine and \
809                DT.TAB_SECTION_END in self._RawData.CurrentLine:
810                self._RawData.CurrentLine = self._RawData.CurrentLine.replace(DT.TAB_COMMENT_SPLIT, '').strip()
811
812                if self._RawData.CurrentLine[0] == DT.TAB_SECTION_START and \
813                    self._RawData.CurrentLine[-1] == DT.TAB_SECTION_END:
814                    RawSection = self._RawData.CurrentLine[1:-1].strip()
815                    if RawSection.upper().startswith(DT.TAB_PCD_ERROR.upper()+'.'):
816                        TokenSpaceGuidCName = RawSection.split(DT.TAB_PCD_ERROR+'.')[1].strip()
817                        continue
818
819            if TokenSpaceGuidCName and self._RawData.CurrentLine.startswith(DT.TAB_COMMENT_SPLIT):
820                self._RawData.CurrentLine = self._RawData.CurrentLine.replace(DT.TAB_COMMENT_SPLIT, '').strip()
821                if self._RawData.CurrentLine != '':
822                    if DT.TAB_VALUE_SPLIT not in self._RawData.CurrentLine:
823                        self._LoggerError(ST.ERR_DECPARSE_PCDERRORMSG_MISS_VALUE_SPLIT)
824
825                    PcdErrorNumber, PcdErrorMsg = GetSplitValueList(self._RawData.CurrentLine, DT.TAB_VALUE_SPLIT, 1)
826                    PcdErrorNumber = ParsePcdErrorCode(PcdErrorNumber, self._RawData.Filename, self._RawData.LineIndex)
827                    if not PcdErrorMsg.strip():
828                        self._LoggerError(ST.ERR_DECPARSE_PCD_MISS_ERRORMSG)
829
830                    self.PcdErrorCommentDict[(TokenSpaceGuidCName, PcdErrorNumber)] = PcdErrorMsg.strip()
831            else:
832                TokenSpaceGuidCName = ''
833
834        self._RawData.LineIndex = 0
835        self._RawData.CurrentLine = ''
836        self._RawData.NextLine = ''
837
838        while not self._RawData.IsEndOfFile():
839            Line, Comment = CleanString(self._RawData.GetNextLine())
840
841            #
842            # Header must be pure comment
843            #
844            if Line != '':
845                self._RawData.UndoNextLine()
846                break
847
848            if Comment and Comment.startswith(DT.TAB_SPECIAL_COMMENT) and Comment.find(DT.TAB_HEADER_COMMENT) > 0 \
849                and not Comment[2:Comment.find(DT.TAB_HEADER_COMMENT)].strip():
850                IsFileHeader = True
851                IsBinaryHeader = False
852                FileHeaderLineIndex = self._RawData.LineIndex
853
854            #
855            # Get license information before '@file'
856            #
857            if not IsFileHeader and not IsBinaryHeader and Comment and Comment.startswith(DT.TAB_COMMENT_SPLIT) and \
858            DT.TAB_BINARY_HEADER_COMMENT not in Comment:
859                self._HeadComment.append((Comment, self._RawData.LineIndex))
860
861            if Comment and IsFileHeader and \
862            not(Comment.startswith(DT.TAB_SPECIAL_COMMENT) \
863            and Comment.find(DT.TAB_BINARY_HEADER_COMMENT) > 0):
864                self._HeadComment.append((Comment, self._RawData.LineIndex))
865            #
866            # Double '#' indicates end of header comments
867            #
868            if (not Comment or Comment == DT.TAB_SPECIAL_COMMENT) and IsFileHeader:
869                IsFileHeader = False
870                continue
871
872            if Comment and Comment.startswith(DT.TAB_SPECIAL_COMMENT) \
873            and Comment.find(DT.TAB_BINARY_HEADER_COMMENT) > 0:
874                IsBinaryHeader = True
875                IsFileHeader = False
876                BinaryHeaderLineIndex = self._RawData.LineIndex
877
878            if Comment and IsBinaryHeader:
879                self.BinaryHeadComment.append((Comment, self._RawData.LineIndex))
880            #
881            # Double '#' indicates end of header comments
882            #
883            if (not Comment or Comment == DT.TAB_SPECIAL_COMMENT) and IsBinaryHeader:
884                IsBinaryHeader = False
885                break
886
887            if FileHeaderLineIndex > -1 and not IsFileHeader and not IsBinaryHeader:
888                break
889
890        if FileHeaderLineIndex > BinaryHeaderLineIndex and FileHeaderLineIndex > -1 and BinaryHeaderLineIndex > -1:
891            self._LoggerError(ST.ERR_BINARY_HEADER_ORDER)
892
893        if FileHeaderLineIndex == -1:
894#            self._LoggerError(ST.ERR_NO_SOURCE_HEADER)
895            Logger.Error(TOOL_NAME, FORMAT_INVALID,
896                         ST.ERR_NO_SOURCE_HEADER,
897                         File=self._RawData.Filename)
898        return
899
900    def _StopCurrentParsing(self, Line):
901        return False
902
903    def _ParseItem(self):
904        self._SectionHeaderParser()
905        if len(self._RawData.CurrentScope) == 0:
906            self._LoggerError(ST.ERR_DECPARSE_SECTION_EMPTY)
907        SectionObj = self._SectionParser[self._RawData.CurrentScope[0][0]]
908        SectionObj.BlockStart()
909        SectionObj.Parse()
910        return SectionObj.GetDataObject()
911
912    def _UserExtentionSectionParser(self):
913        self._RawData.CurrentScope = []
914        ArchList = set()
915        Section = self._RawData.CurrentLine[1:-1]
916        Par = ParserHelper(Section, self._RawData.Filename)
917        while not Par.End():
918            #
919            # User extention
920            #
921            Token = Par.GetToken()
922            if Token.upper() != DT.TAB_USER_EXTENSIONS.upper():
923                self._LoggerError(ST.ERR_DECPARSE_SECTION_UE)
924            UserExtension = Token.upper()
925            Par.AssertChar(DT.TAB_SPLIT, ST.ERR_DECPARSE_SECTION_UE, self._RawData.LineIndex)
926
927            #
928            # UserID
929            #
930            Token = Par.GetToken()
931            if not IsValidUserId(Token):
932                self._LoggerError(ST.ERR_DECPARSE_SECTION_UE_USERID)
933            UserId = Token
934            Par.AssertChar(DT.TAB_SPLIT, ST.ERR_DECPARSE_SECTION_UE, self._RawData.LineIndex)
935            #
936            # IdString
937            #
938            Token = Par.GetToken()
939            if not IsValidIdString(Token):
940                self._LoggerError(ST.ERR_DECPARSE_SECTION_UE_IDSTRING)
941            IdString = Token
942            Arch = 'COMMON'
943            if Par.Expect(DT.TAB_SPLIT):
944                Token = Par.GetToken()
945                Arch = Token.upper()
946                if not IsValidArch(Arch):
947                    self._LoggerError(ST.ERR_DECPARSE_ARCH)
948            ArchList.add(Arch)
949            if [UserExtension, UserId, IdString, Arch] not in \
950                self._RawData.CurrentScope:
951                self._RawData.CurrentScope.append(
952                    [UserExtension, UserId, IdString, Arch]
953                )
954            if not Par.Expect(DT.TAB_COMMA_SPLIT):
955                break
956            elif Par.End():
957                self._LoggerError(ST.ERR_DECPARSE_SECTION_COMMA)
958        Par.AssertEnd(ST.ERR_DECPARSE_SECTION_UE, self._RawData.LineIndex)
959        if 'COMMON' in ArchList and len(ArchList) > 1:
960            self._LoggerError(ST.ERR_DECPARSE_SECTION_COMMON)
961
962    ## Section header parser
963    #
964    # The section header is always in following format:
965    #
966    # [section_name.arch<.platform|module_type>]
967    #
968    def _SectionHeaderParser(self):
969        if self._RawData.CurrentLine[0] != DT.TAB_SECTION_START or self._RawData.CurrentLine[-1] != DT.TAB_SECTION_END:
970            self._LoggerError(ST.ERR_DECPARSE_SECTION_IDENTIFY)
971
972        RawSection = self._RawData.CurrentLine[1:-1].strip().upper()
973        #
974        # Check defines section which is only allowed to occur once and
975        # no arch can be followed
976        #
977        if RawSection.startswith(DT.TAB_DEC_DEFINES.upper()):
978            if RawSection != DT.TAB_DEC_DEFINES.upper():
979                self._LoggerError(ST.ERR_DECPARSE_DEFINE_SECNAME)
980        #
981        # Check user extension section
982        #
983        if RawSection.startswith(DT.TAB_USER_EXTENSIONS.upper()):
984            return self._UserExtentionSectionParser()
985        self._RawData.CurrentScope = []
986        SectionNames = []
987        ArchList = set()
988        for Item in GetSplitValueList(RawSection, DT.TAB_COMMA_SPLIT):
989            if Item == '':
990                self._LoggerError(ST.ERR_DECPARSE_SECTION_SUBEMPTY % self._RawData.CurrentLine)
991
992            ItemList = GetSplitValueList(Item, DT.TAB_SPLIT)
993            #
994            # different types of PCD are permissible in one section
995            #
996            SectionName = ItemList[0]
997            if SectionName not in self._SectionParser:
998                self._LoggerError(ST.ERR_DECPARSE_SECTION_UNKNOW % SectionName)
999            if SectionName not in SectionNames:
1000                SectionNames.append(SectionName)
1001            #
1002            # In DEC specification, all section headers have at most two part:
1003            # SectionName.Arch except UserExtention
1004            #
1005            if len(ItemList) > 2:
1006                self._LoggerError(ST.ERR_DECPARSE_SECTION_SUBTOOMANY % Item)
1007
1008            if DT.TAB_PCDS_FEATURE_FLAG_NULL.upper() in SectionNames and len(SectionNames) > 1:
1009                self._LoggerError(ST.ERR_DECPARSE_SECTION_FEATUREFLAG % DT.TAB_PCDS_FEATURE_FLAG_NULL)
1010            #
1011            # S1 is always Arch
1012            #
1013            if len(ItemList) > 1:
1014                Str1 = ItemList[1]
1015                if not IsValidArch(Str1):
1016                    self._LoggerError(ST.ERR_DECPARSE_ARCH)
1017            else:
1018                Str1 = 'COMMON'
1019            ArchList.add(Str1)
1020
1021            if [SectionName, Str1] not in self._RawData.CurrentScope:
1022                self._RawData.CurrentScope.append([SectionName, Str1])
1023        #
1024        # 'COMMON' must not be used with specific ARCHs at the same section
1025        #
1026        if 'COMMON' in ArchList and len(ArchList) > 1:
1027            self._LoggerError(ST.ERR_DECPARSE_SECTION_COMMON)
1028        if len(SectionNames) == 0:
1029            self._LoggerError(ST.ERR_DECPARSE_SECTION_SUBEMPTY % self._RawData.CurrentLine)
1030        if len(SectionNames) != 1:
1031            for Sec in SectionNames:
1032                if not Sec.startswith(DT.TAB_PCDS.upper()):
1033                    self._LoggerError(ST.ERR_DECPARSE_SECTION_NAME % str(SectionNames))
1034
1035    def GetDefineSectionMacro(self):
1036        return self._Define.GetLocalMacro()
1037    def GetDefineSectionObject(self):
1038        return self._Define.GetDataObject()
1039    def GetIncludeSectionObject(self):
1040        return self._Include.GetDataObject()
1041    def GetGuidSectionObject(self):
1042        return self._Guid.GetGuidObject()
1043    def GetProtocolSectionObject(self):
1044        return self._Guid.GetProtocolObject()
1045    def GetPpiSectionObject(self):
1046        return self._Guid.GetPpiObject()
1047    def GetLibraryClassSectionObject(self):
1048        return self._LibClass.GetDataObject()
1049    def GetPcdSectionObject(self):
1050        return self._Pcd.GetDataObject()
1051    def GetUserExtensionSectionObject(self):
1052        return self._UserEx.GetDataObject()
1053    def GetPackageSpecification(self):
1054        return self._Define.GetDataObject().GetPackageSpecification()
1055    def GetPackageName(self):
1056        return self._Define.GetDataObject().GetPackageName()
1057    def GetPackageGuid(self):
1058        return self._Define.GetDataObject().GetPackageGuid()
1059    def GetPackageVersion(self):
1060        return self._Define.GetDataObject().GetPackageVersion()
1061    def GetPackageUniFile(self):
1062        return self._Define.GetDataObject().GetPackageUniFile()
1063