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