]> git.proxmox.com Git - mirror_edk2.git/blobdiff - BaseTools/Source/Python/UPT/Parser/DecParser.py
Sync BaseTools Branch (version r2271) to EDKII main trunk.
[mirror_edk2.git] / BaseTools / Source / Python / UPT / Parser / DecParser.py
diff --git a/BaseTools/Source/Python/UPT/Parser/DecParser.py b/BaseTools/Source/Python/UPT/Parser/DecParser.py
new file mode 100644 (file)
index 0000000..823cf71
--- /dev/null
@@ -0,0 +1,989 @@
+## @file\r
+# This file is used to parse DEC file. It will consumed by DecParser\r
+#\r
+# Copyright (c) 2011, Intel Corporation. All rights reserved.<BR>\r
+#\r
+# This program and the accompanying materials are licensed and made available \r
+# under the terms and conditions of the BSD License which accompanies this \r
+# distribution. The full text of the license may be found at \r
+# http://opensource.org/licenses/bsd-license.php\r
+#\r
+# THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,\r
+# WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.\r
+'''\r
+DecParser\r
+'''\r
+## Import modules\r
+#\r
+import Logger.Log as Logger\r
+from Logger.ToolError import FILE_PARSE_FAILURE\r
+from Logger.ToolError import FILE_OPEN_FAILURE\r
+from Logger import StringTable as ST\r
+\r
+import Library.DataType as DT\r
+from Library.ParserValidate import IsValidToken\r
+from Library.ParserValidate import IsValidPath\r
+from Library.ParserValidate import IsValidCFormatGuid\r
+from Library.ParserValidate import IsValidIdString\r
+from Library.ParserValidate import IsValidUserId\r
+from Library.ParserValidate import IsValidArch\r
+from Library.ParserValidate import IsValidWord\r
+from Parser.DecParserMisc import TOOL_NAME\r
+from Parser.DecParserMisc import CleanString\r
+from Parser.DecParserMisc import IsValidPcdDatum\r
+from Parser.DecParserMisc import ParserHelper\r
+from Parser.DecParserMisc import StripRoot\r
+from Parser.DecParserMisc import VERSION_PATTERN\r
+from Parser.DecParserMisc import CVAR_PATTERN\r
+from Parser.DecParserMisc import PCD_TOKEN_PATTERN\r
+from Parser.DecParserMisc import MACRO_PATTERN\r
+from Parser.DecParserMisc import FileContent\r
+from Object.Parser.DecObject import _DecComments\r
+from Object.Parser.DecObject import DecDefineObject\r
+from Object.Parser.DecObject import DecDefineItemObject\r
+from Object.Parser.DecObject import DecIncludeObject\r
+from Object.Parser.DecObject import DecIncludeItemObject\r
+from Object.Parser.DecObject import DecLibraryclassObject\r
+from Object.Parser.DecObject import DecLibraryclassItemObject\r
+from Object.Parser.DecObject import DecGuidObject\r
+from Object.Parser.DecObject import DecPpiObject\r
+from Object.Parser.DecObject import DecProtocolObject\r
+from Object.Parser.DecObject import DecGuidItemObject\r
+from Object.Parser.DecObject import DecUserExtensionObject\r
+from Object.Parser.DecObject import DecUserExtensionItemObject\r
+from Object.Parser.DecObject import DecPcdObject\r
+from Object.Parser.DecObject import DecPcdItemObject\r
+from Library.Misc import GuidStructureStringToGuidString\r
+from Library.Misc import CheckGuidRegFormat\r
+from Library.String import ReplaceMacro\r
+from Library.String import GetSplitValueList\r
+from Library.String import gMACRO_PATTERN\r
+from Library.String import ConvertSpecialChar\r
+\r
+##\r
+# _DecBase class for parsing\r
+#\r
+class _DecBase:\r
+    def __init__(self, RawData):\r
+        self._RawData = RawData\r
+        self._ItemDict = {}\r
+        self._LocalMacro = {}\r
+        #\r
+        # Data parsed by 'self' are saved to this object\r
+        #\r
+        self.ItemObject = None\r
+    \r
+    def GetDataObject(self):\r
+        return self.ItemObject\r
+    \r
+    ## BlockStart\r
+    #\r
+    # Called if a new section starts\r
+    #\r
+    def BlockStart(self):\r
+        self._LocalMacro = {}\r
+    \r
+    ## _CheckReDefine\r
+    #\r
+    # @param Key: to be checked if multi-defined\r
+    # @param Scope: Format: [[SectionName, Arch], ...]. \r
+    #               If scope is none, use global scope\r
+    #\r
+    def _CheckReDefine(self, Key, Scope = None):\r
+        if not Scope:\r
+            Scope = self._RawData.CurrentScope\r
+            return\r
+        \r
+        SecArch = []\r
+        #\r
+        # Copy scope to SecArch, avoid Scope be changed outside\r
+        #\r
+        SecArch[0:1] = Scope[:]\r
+        if Key not in self._ItemDict:\r
+            self._ItemDict[Key] = [[SecArch, self._RawData.LineIndex]]\r
+            return\r
+        \r
+        for Value in self._ItemDict[Key]:\r
+            for SubValue in Scope:\r
+                #\r
+                # If current is common section\r
+                #\r
+                if SubValue[-1] == 'COMMON':\r
+                    for Other in Value[0]:\r
+                        # Key in common cannot be redefined in other arches\r
+                        # [:-1] means stripping arch info\r
+                        if Other[:-1] == SubValue[:-1]:\r
+                            self._LoggerError(ST.ERR_DECPARSE_REDEFINE % (Key, Value[1]))\r
+                            return\r
+                    continue\r
+                CommonScope = []\r
+                CommonScope[0:1] = SubValue\r
+                CommonScope[-1] = 'COMMON'\r
+                #\r
+                # Cannot be redefined if this key already defined in COMMON Or defined in same arch\r
+                #\r
+                if SubValue in Value[0] or CommonScope in Value[0]:\r
+                    self._LoggerError(ST.ERR_DECPARSE_REDEFINE % (Key, Value[1]))\r
+                    return\r
+        self._ItemDict[Key].append([SecArch, self._RawData.LineIndex])\r
+    \r
+    ## CheckRequiredFields\r
+    # Some sections need to check if some fields exist, define section for example\r
+    # Derived class can re-implement, top parser will call this function after all parsing done\r
+    #  \r
+    def CheckRequiredFields(self):\r
+        if self._RawData:\r
+            pass\r
+        return True\r
+    \r
+    ## IsItemRequired\r
+    # In DEC spec, sections must have at least one statement except user \r
+    # extension.\r
+    # For example: "[guids" [<attribs>] "]" <EOL> <statements>+\r
+    # sub class can override this method to indicate if statement is a must.\r
+    #\r
+    def _IsStatementRequired(self):\r
+        if self._RawData:\r
+            pass\r
+        return False\r
+    \r
+    def _LoggerError(self, ErrorString):\r
+        Logger.Error(TOOL_NAME, FILE_PARSE_FAILURE, File=self._RawData.Filename, \r
+                     Line = self._RawData.LineIndex,\r
+                     ExtraData=ErrorString + ST.ERR_DECPARSE_LINE % self._RawData.CurrentLine)\r
+    \r
+    def _ReplaceMacro(self, String):\r
+        if gMACRO_PATTERN.findall(String):\r
+            String = ReplaceMacro(String, self._LocalMacro, False,\r
+                                  FileName = self._RawData.Filename,\r
+                                  Line = ['', self._RawData.LineIndex])\r
+            String = ReplaceMacro(String, self._RawData.Macros, False,\r
+                                  FileName = self._RawData.Filename,\r
+                                  Line = ['', self._RawData.LineIndex])\r
+            MacroUsed = gMACRO_PATTERN.findall(String)\r
+            if MacroUsed:\r
+                Logger.Error(TOOL_NAME, FILE_PARSE_FAILURE,\r
+                             File=self._RawData.Filename, \r
+                             Line = self._RawData.LineIndex,\r
+                             ExtraData = ST.ERR_DECPARSE_MACRO_RESOLVE % (str(MacroUsed), String))\r
+        return String\r
+    \r
+    def _MacroParser(self, String):\r
+        TokenList = GetSplitValueList(String, ' ', 1)\r
+        if len(TokenList) < 2 or TokenList[1] == '':\r
+            self._LoggerError(ST.ERR_DECPARSE_MACRO_PAIR)\r
+\r
+        TokenList = GetSplitValueList(TokenList[1], DT.TAB_EQUAL_SPLIT, 1)\r
+        if TokenList[0] == '':\r
+            self._LoggerError(ST.ERR_DECPARSE_MACRO_NAME)\r
+        elif not IsValidToken(MACRO_PATTERN, TokenList[0]):\r
+            self._LoggerError(ST.ERR_DECPARSE_MACRO_NAME_UPPER % TokenList[0])\r
+        \r
+        if len(TokenList) == 1:\r
+            self._LocalMacro[TokenList[0]] = ''\r
+        else:\r
+            self._LocalMacro[TokenList[0]] = self._ReplaceMacro(TokenList[1])\r
+    \r
+    ## _ParseItem\r
+    #\r
+    # Parse specified item, this function must be derived by subclass\r
+    #\r
+    def _ParseItem(self):\r
+        if self._RawData:\r
+            pass\r
+        #\r
+        # Should never be called\r
+        #\r
+        return None\r
+\r
+    \r
+    ## _TailCommentStrategy\r
+    #\r
+    # This function can be derived to parse tail comment\r
+    # default is it will not consume any lines\r
+    #\r
+    # @param Comment: Comment of current line\r
+    #\r
+    def _TailCommentStrategy(self, Comment):\r
+        if Comment:\r
+            pass\r
+        if self._RawData:\r
+            pass\r
+        return False\r
+    \r
+    ## _StopCurrentParsing\r
+    #\r
+    # Called in Parse if current parsing should be stopped when encounter some\r
+    # keyword\r
+    # Default is section start and end\r
+    #\r
+    # @param Line: Current line\r
+    #\r
+    def _StopCurrentParsing(self, Line):\r
+        if self._RawData:\r
+            pass\r
+        return Line[0] == DT.TAB_SECTION_START and Line[-1] == DT.TAB_SECTION_END\r
+    \r
+    ## _TryBackSlash\r
+    #\r
+    # Split comment and DEC content, concatenate lines if end of char is '\'\r
+    #\r
+    # @param ProcessedLine: ProcessedLine line\r
+    # @param ProcessedComments: ProcessedComments line\r
+    #\r
+    def _TryBackSlash(self, ProcessedLine, ProcessedComments):\r
+        CatLine = ''\r
+        Comment = ''\r
+        Line = ProcessedLine\r
+        CommentList = ProcessedComments\r
+        while not self._RawData.IsEndOfFile():\r
+            if Line == '':\r
+                self._LoggerError(ST.ERR_DECPARSE_BACKSLASH_EMPTY)\r
+                break\r
+            \r
+            if Comment:\r
+                CommentList.append((Comment, self._RawData.LineIndex))\r
+            if Line[-1] != DT.TAB_SLASH:\r
+                CatLine += Line\r
+                break\r
+            elif len(Line) < 2 or Line[-2] != ' ':\r
+                self._LoggerError(ST.ERR_DECPARSE_BACKSLASH)\r
+            else:\r
+                CatLine += Line[:-1]\r
+                Line, Comment = CleanString(self._RawData.GetNextLine())\r
+        #\r
+        # Reach end of content\r
+        #\r
+        if self._RawData.IsEndOfFile():\r
+            if not CatLine:\r
+                if ProcessedLine[-1] == DT.TAB_SLASH:\r
+                    self._LoggerError(ST.ERR_DECPARSE_BACKSLASH_EMPTY)\r
+                CatLine = ProcessedLine\r
+            else:\r
+                if not Line or Line[-1] == DT.TAB_SLASH:\r
+                    self._LoggerError(ST.ERR_DECPARSE_BACKSLASH_EMPTY)\r
+                CatLine += Line\r
+         \r
+        self._RawData.CurrentLine = self._ReplaceMacro(CatLine)\r
+        return CatLine, CommentList\r
+    \r
+    ## Parse\r
+    # This is a template method in which other member functions which might \r
+    # override by sub class are called. It is responsible for reading file \r
+    # line by line, and call other member functions to parse. This function\r
+    # should not be re-implement by sub class.\r
+    #\r
+    def Parse(self):\r
+        HeadComments = []\r
+        TailComments = []\r
+        \r
+        #======================================================================\r
+        # CurComments may pointer to HeadComments or TailComments\r
+        #======================================================================\r
+        CurComments = HeadComments\r
+        CurObj = None\r
+        ItemNum = 0\r
+        FromBuf = False\r
+        \r
+        #======================================================================\r
+        # Used to report error information if empty section found\r
+        #======================================================================\r
+        Index = self._RawData.LineIndex\r
+        LineStr = self._RawData.CurrentLine\r
+        while not self._RawData.IsEndOfFile() or self._RawData.NextLine:\r
+            if self._RawData.NextLine:\r
+                #==============================================================\r
+                # Have processed line in buffer\r
+                #==============================================================\r
+                Line = self._RawData.NextLine\r
+                HeadComments.extend(self._RawData.HeadComment)\r
+                TailComments.extend(self._RawData.TailComment)\r
+                self._RawData.ResetNext()\r
+                Comment = ''\r
+                FromBuf = True\r
+            else:\r
+                #==============================================================\r
+                # No line in buffer, read next line\r
+                #==============================================================\r
+                Line, Comment = CleanString(self._RawData.GetNextLine())\r
+                FromBuf = False\r
+            if Line:\r
+                if not FromBuf and CurObj and TailComments:\r
+                    #==========================================================\r
+                    # Set tail comments to previous statement if not empty.\r
+                    #==========================================================\r
+                    CurObj.SetTailComment(CurObj.GetTailComment()+TailComments)\r
+                \r
+                if not FromBuf:\r
+                    del TailComments[:]\r
+                CurComments = TailComments\r
+                Comments = []\r
+                if Comment:\r
+                    Comments = [(Comment, self._RawData.LineIndex)]\r
+                \r
+                #==============================================================\r
+                # Try if last char of line has backslash\r
+                #==============================================================\r
+                Line, Comments = self._TryBackSlash(Line, Comments)\r
+                CurComments.extend(Comments)\r
+                \r
+                #==============================================================\r
+                # Macro found\r
+                #==============================================================\r
+                if Line.startswith('DEFINE '):\r
+                    self._MacroParser(Line)\r
+                    del HeadComments[:]\r
+                    del TailComments[:]\r
+                    CurComments = HeadComments\r
+                    continue\r
+                \r
+                if self._StopCurrentParsing(Line):\r
+                    #==========================================================\r
+                    # This line does not belong to this parse,\r
+                    # Save it, can be used by next parse\r
+                    #==========================================================\r
+                    self._RawData.SetNext(Line, HeadComments, TailComments)\r
+                    break\r
+                \r
+                Obj = self._ParseItem()\r
+                ItemNum += 1\r
+                if Obj:\r
+                    Obj.SetHeadComment(Obj.GetHeadComment()+HeadComments)\r
+                    Obj.SetTailComment(Obj.GetTailComment()+TailComments)\r
+                    del HeadComments[:]\r
+                    del TailComments[:]\r
+                    CurObj = Obj\r
+                else:\r
+                    CurObj = None\r
+            else:\r
+                if id(CurComments) == id(TailComments):\r
+                    #==========================================================\r
+                    # Check if this comment belongs to tail comment\r
+                    #==========================================================\r
+                    if not self._TailCommentStrategy(Comment):\r
+                        CurComments = HeadComments\r
+\r
+                if Comment:\r
+                    CurComments.append(((Comment, self._RawData.LineIndex)))\r
+                else:\r
+                    del CurComments[:]\r
+        \r
+        if self._IsStatementRequired() and ItemNum == 0:\r
+            Logger.Error(\r
+                    TOOL_NAME, FILE_PARSE_FAILURE,\r
+                    File=self._RawData.Filename,\r
+                    Line=Index,\r
+                    ExtraData=ST.ERR_DECPARSE_STATEMENT_EMPTY % LineStr\r
+            )\r
+\r
+## _DecDefine\r
+# Parse define section\r
+#\r
+class _DecDefine(_DecBase):\r
+    def __init__(self, RawData):\r
+        _DecBase.__init__(self, RawData)\r
+        self.ItemObject = DecDefineObject(RawData.Filename)\r
+        self._LocalMacro = self._RawData.Macros\r
+        self._DefSecNum = 0\r
+        \r
+        #\r
+        # Each field has a function to validate\r
+        #\r
+        self.DefineValidation = {\r
+            DT.TAB_DEC_DEFINES_DEC_SPECIFICATION   :   self._SetDecSpecification,\r
+            DT.TAB_DEC_DEFINES_PACKAGE_NAME        :   self._SetPackageName,\r
+            DT.TAB_DEC_DEFINES_PACKAGE_GUID        :   self._SetPackageGuid,\r
+            DT.TAB_DEC_DEFINES_PACKAGE_VERSION     :   self._SetPackageVersion,\r
+        }\r
+    \r
+    def BlockStart(self):\r
+        self._DefSecNum += 1\r
+        if self._DefSecNum > 1:\r
+            self._LoggerError(ST.ERR_DECPARSE_DEFINE_MULTISEC)\r
+    \r
+    ## CheckRequiredFields\r
+    #\r
+    # Check required fields: DEC_SPECIFICATION, PACKAGE_NAME\r
+    #                        PACKAGE_GUID, PACKAGE_VERSION\r
+    #\r
+    def CheckRequiredFields(self):\r
+        Ret = False\r
+        if self.ItemObject.GetPackageSpecification() == '':\r
+            Logger.Error(TOOL_NAME, FILE_PARSE_FAILURE, File=self._RawData.Filename, \r
+                         ExtraData=ST.ERR_DECPARSE_DEFINE_REQUIRED % DT.TAB_DEC_DEFINES_DEC_SPECIFICATION)\r
+        elif self.ItemObject.GetPackageName() == '':\r
+            Logger.Error(TOOL_NAME, FILE_PARSE_FAILURE, File=self._RawData.Filename, \r
+                         ExtraData=ST.ERR_DECPARSE_DEFINE_REQUIRED % DT.TAB_DEC_DEFINES_PACKAGE_NAME)\r
+        elif self.ItemObject.GetPackageGuid() == '':\r
+            Logger.Error(TOOL_NAME, FILE_PARSE_FAILURE, File=self._RawData.Filename, \r
+                         ExtraData=ST.ERR_DECPARSE_DEFINE_REQUIRED % DT.TAB_DEC_DEFINES_PACKAGE_GUID)\r
+        elif self.ItemObject.GetPackageVersion() == '':\r
+            Logger.Error(TOOL_NAME, FILE_PARSE_FAILURE, File=self._RawData.Filename, \r
+                         ExtraData=ST.ERR_DECPARSE_DEFINE_REQUIRED % DT.TAB_DEC_DEFINES_PACKAGE_VERSION)\r
+        else:\r
+            Ret = True\r
+        return Ret\r
+    \r
+    def _ParseItem(self):\r
+        Line = self._RawData.CurrentLine\r
+        TokenList = GetSplitValueList(Line, DT.TAB_EQUAL_SPLIT, 1)\r
+        if TokenList[0] == DT.TAB_DEC_DEFINES_PKG_UNI_FILE:\r
+            pass\r
+        elif len(TokenList) < 2:\r
+            self._LoggerError(ST.ERR_DECPARSE_DEFINE_FORMAT)\r
+        elif TokenList[0] not in self.DefineValidation:\r
+            self._LoggerError(ST.ERR_DECPARSE_DEFINE_UNKNOWKEY % TokenList[0])\r
+        else:\r
+            self.DefineValidation[TokenList[0]](TokenList[1])\r
+        \r
+        DefineItem = DecDefineItemObject()\r
+        if TokenList[0] != DT.TAB_DEC_DEFINES_PKG_UNI_FILE:\r
+            DefineItem.Key   = TokenList[0]\r
+            DefineItem.Value = TokenList[1]\r
+            self.ItemObject.AddItem(DefineItem, self._RawData.CurrentScope)\r
+        return DefineItem\r
+    \r
+    def _SetDecSpecification(self, Token):\r
+        if self.ItemObject.GetPackageSpecification():\r
+            self._LoggerError(ST.ERR_DECPARSE_DEFINE_DEFINED % DT.TAB_DEC_DEFINES_DEC_SPECIFICATION)\r
+        if not IsValidToken('0[xX][0-9a-fA-F]{8}', Token):\r
+            self._LoggerError(ST.ERR_DECPARSE_DEFINE_SPEC)\r
+        self.ItemObject.SetPackageSpecification(Token)\r
+    \r
+    def _SetPackageName(self, Token):\r
+        if self.ItemObject.GetPackageName():\r
+            self._LoggerError(ST.ERR_DECPARSE_DEFINE_DEFINED % DT.TAB_DEC_DEFINES_PACKAGE_NAME)\r
+        if not IsValidWord(Token):\r
+            self._LoggerError(ST.ERR_DECPARSE_DEFINE_PKGNAME)\r
+        self.ItemObject.SetPackageName(Token)\r
+    \r
+    def _SetPackageGuid(self, Token):\r
+        if self.ItemObject.GetPackageGuid():\r
+            self._LoggerError(ST.ERR_DECPARSE_DEFINE_DEFINED % DT.TAB_DEC_DEFINES_PACKAGE_GUID)\r
+        if not CheckGuidRegFormat(Token):\r
+            self._LoggerError(ST.ERR_DECPARSE_DEFINE_PKGGUID)\r
+        self.ItemObject.SetPackageGuid(Token)\r
+    \r
+    def _SetPackageVersion(self, Token):\r
+        if self.ItemObject.GetPackageVersion():\r
+            self._LoggerError(ST.ERR_DECPARSE_DEFINE_DEFINED % DT.TAB_DEC_DEFINES_PACKAGE_VERSION)\r
+        if not IsValidToken(VERSION_PATTERN, Token):\r
+            self._LoggerError(ST.ERR_DECPARSE_DEFINE_PKGVERSION)\r
+        else:\r
+            if not DT.TAB_SPLIT in Token:\r
+                Token = Token + '.0'\r
+            self.ItemObject._PkgVersion = Token\r
+\r
+## _DecInclude\r
+#\r
+# Parse include section\r
+#\r
+class _DecInclude(_DecBase):\r
+    def __init__(self, RawData):\r
+        _DecBase.__init__(self, RawData)\r
+        self.ItemObject = DecIncludeObject(RawData.Filename)\r
+    \r
+    def _ParseItem(self):\r
+        Line = self._RawData.CurrentLine\r
+        \r
+        if not IsValidPath(Line, self._RawData.PackagePath):\r
+            self._LoggerError(ST.ERR_DECPARSE_INCLUDE % Line) \r
+        \r
+        Item = DecIncludeItemObject(StripRoot(self._RawData.PackagePath, Line), self._RawData.PackagePath)\r
+        self.ItemObject.AddItem(Item, self._RawData.CurrentScope)\r
+        return Item\r
+\r
+## _DecLibraryclass\r
+#\r
+# Parse library class section\r
+#\r
+class _DecLibraryclass(_DecBase):\r
+    def __init__(self, RawData):\r
+        _DecBase.__init__(self, RawData)\r
+        self.ItemObject = DecLibraryclassObject(RawData.Filename)\r
+    \r
+    def _ParseItem(self):\r
+        Line = self._RawData.CurrentLine\r
+        TokenList = GetSplitValueList(Line, DT.TAB_VALUE_SPLIT)\r
+        if len(TokenList) != 2:\r
+            self._LoggerError(ST.ERR_DECPARSE_LIBCLASS_SPLIT) \r
+        if TokenList[0] == '' or TokenList[1] == '':\r
+            self._LoggerError(ST.ERR_DECPARSE_LIBCLASS_EMPTY)\r
+        if not IsValidToken('[A-Z][0-9A-Za-z]*', TokenList[0]):\r
+            self._LoggerError(ST.ERR_DECPARSE_LIBCLASS_LIB)\r
+        \r
+        self._CheckReDefine(TokenList[0])\r
+        \r
+        Value = TokenList[1]\r
+        #\r
+        # Must end with .h\r
+        #\r
+        if not Value.endswith('.h'):\r
+            self._LoggerError(ST.ERR_DECPARSE_LIBCLASS_PATH_EXT)\r
+        \r
+        #\r
+        # Path must be existed\r
+        #\r
+        if not IsValidPath(Value, self._RawData.PackagePath):\r
+            self._LoggerError(ST.ERR_DECPARSE_INCLUDE % Value)\r
+        \r
+        Item = DecLibraryclassItemObject(TokenList[0], StripRoot(self._RawData.PackagePath, Value),\r
+                                         self._RawData.PackagePath)\r
+        self.ItemObject.AddItem(Item, self._RawData.CurrentScope)\r
+        return Item\r
+\r
+## _DecPcd\r
+#\r
+# Parse PCD section\r
+#\r
+class _DecPcd(_DecBase):\r
+    def __init__(self, RawData):\r
+        _DecBase.__init__(self, RawData)\r
+        self.ItemObject = DecPcdObject(RawData.Filename)\r
+        #\r
+        # Used to check duplicate token\r
+        # Key is token space and token number (integer), value is C name\r
+        #\r
+        self.TokenMap = {}\r
+    \r
+    def _ParseItem(self):\r
+        Line = self._RawData.CurrentLine\r
+        TokenList = Line.split(DT.TAB_VALUE_SPLIT)\r
+        if len(TokenList) < 4:\r
+            self._LoggerError(ST.ERR_DECPARSE_PCD_SPLIT)\r
+        \r
+        #\r
+        # Token space guid C name\r
+        #\r
+        PcdName = GetSplitValueList(TokenList[0], DT.TAB_SPLIT)\r
+        if len(PcdName) != 2 or PcdName[0] == '' or PcdName[1] == '':\r
+            self._LoggerError(ST.ERR_DECPARSE_PCD_NAME)\r
+        \r
+        Guid = PcdName[0]\r
+        if not IsValidToken(CVAR_PATTERN, Guid):\r
+            self._LoggerError(ST.ERR_DECPARSE_PCD_CVAR_GUID)\r
+        \r
+        #\r
+        # PCD C name\r
+        #\r
+        CName = PcdName[1]\r
+        if not IsValidToken(CVAR_PATTERN, CName):\r
+            self._LoggerError(ST.ERR_DECPARSE_PCD_CVAR_PCDCNAME)\r
+        \r
+        self._CheckReDefine(Guid + DT.TAB_SPLIT + CName)\r
+        \r
+        #\r
+        # Default value, may be C array, string or number\r
+        #\r
+        Data = DT.TAB_VALUE_SPLIT.join(TokenList[1:-2]).strip()\r
+        \r
+        #\r
+        # PCD data type\r
+        #\r
+        DataType = TokenList[-2].strip()\r
+        Valid, Cause = IsValidPcdDatum(DataType, Data)\r
+        if not Valid:\r
+            self._LoggerError(Cause)\r
+        PcdType = self._RawData.CurrentScope[0][0]\r
+        if PcdType == DT.TAB_PCDS_FEATURE_FLAG_NULL.upper() and DataType != 'BOOLEAN':\r
+            self._LoggerError(ST.ERR_DECPARSE_PCD_FEATUREFLAG)\r
+        #\r
+        # Token value is the last element in list.\r
+        #\r
+        Token = TokenList[-1].strip()\r
+        if not IsValidToken(PCD_TOKEN_PATTERN, Token):\r
+            self._LoggerError(ST.ERR_DECPARSE_PCD_TOKEN % Token)\r
+        elif not Token.startswith('0x') and not Token.startswith('0X'):\r
+            if long(Token) > 4294967295:\r
+                self._LoggerError(ST.ERR_DECPARSE_PCD_TOKEN_INT % Token)\r
+            Token = hex(long(Token))[:-1]\r
+        \r
+        IntToken = long(Token, 0)\r
+        if (Guid, IntToken) in self.TokenMap:\r
+            if self.TokenMap[Guid, IntToken] != CName:\r
+                self._LoggerError(ST.ERR_DECPARSE_PCD_TOKEN_UNIQUE%(Token))\r
+        else:\r
+            self.TokenMap[Guid, IntToken] = CName\r
+        \r
+        Item = DecPcdItemObject(Guid, CName, Data, DataType, Token)\r
+        self.ItemObject.AddItem(Item, self._RawData.CurrentScope)\r
+        return Item\r
+        \r
+## _DecGuid\r
+#\r
+# Parse GUID, PPI, Protocol section\r
+#\r
+class _DecGuid(_DecBase):\r
+    def __init__(self, RawData):\r
+        _DecBase.__init__(self, RawData)\r
+        self.GuidObj = DecGuidObject(RawData.Filename)\r
+        self.PpiObj = DecPpiObject(RawData.Filename)\r
+        self.ProtocolObj = DecProtocolObject(RawData.Filename)\r
+        self.ObjectDict = \\r
+        {\r
+            DT.TAB_GUIDS.upper()     :   self.GuidObj,\r
+            DT.TAB_PPIS.upper()      :   self.PpiObj,\r
+            DT.TAB_PROTOCOLS.upper() :   self.ProtocolObj\r
+        }\r
+    \r
+    def GetDataObject(self):\r
+        if self._RawData.CurrentScope:\r
+            return self.ObjectDict[self._RawData.CurrentScope[0][0]]\r
+        return None\r
+    \r
+    def GetGuidObject(self):\r
+        return self.GuidObj\r
+    \r
+    def GetPpiObject(self):\r
+        return self.PpiObj\r
+    \r
+    def GetProtocolObject(self):\r
+        return self.ProtocolObj\r
+    \r
+    def _ParseItem(self):\r
+        Line = self._RawData.CurrentLine\r
+        TokenList = GetSplitValueList(Line, DT.TAB_EQUAL_SPLIT, 1)\r
+        if len(TokenList) < 2:\r
+            self._LoggerError(ST.ERR_DECPARSE_CGUID)\r
+        if TokenList[0] == '':\r
+            self._LoggerError(ST.ERR_DECPARSE_CGUID_NAME)\r
+        if TokenList[1] == '':\r
+            self._LoggerError(ST.ERR_DECPARSE_CGUID_GUID)\r
+        if not IsValidToken(CVAR_PATTERN, TokenList[0]):\r
+            self._LoggerError(ST.ERR_DECPARSE_PCD_CVAR_GUID)\r
+        \r
+        self._CheckReDefine(TokenList[0])\r
+        \r
+        if TokenList[1][0] != '{':\r
+            if not CheckGuidRegFormat(TokenList[1]):\r
+                self._LoggerError(ST.ERR_DECPARSE_DEFINE_PKGGUID)\r
+            GuidString = TokenList[1]\r
+        else:\r
+            #\r
+            # Convert C format GUID to GUID string and Simple error check\r
+            #\r
+            GuidString = GuidStructureStringToGuidString(TokenList[1])\r
+            if TokenList[1][0] != '{' or TokenList[1][-1] != '}' or GuidString == '':\r
+                self._LoggerError(ST.ERR_DECPARSE_CGUID_GUIDFORMAT)\r
+    \r
+            #\r
+            # Check C format GUID\r
+            #\r
+            if not IsValidCFormatGuid(TokenList[1]):\r
+                self._LoggerError(ST.ERR_DECPARSE_CGUID_GUIDFORMAT)\r
+\r
+        Item = DecGuidItemObject(TokenList[0], TokenList[1], GuidString)\r
+        ItemObject = self.ObjectDict[self._RawData.CurrentScope[0][0]]\r
+        ItemObject.AddItem(Item, self._RawData.CurrentScope)\r
+        return Item\r
+\r
+## _DecUserExtension\r
+#\r
+# Parse user extention section\r
+#\r
+class _DecUserExtension(_DecBase):\r
+    def __init__(self, RawData):\r
+        _DecBase.__init__(self, RawData)\r
+        self.ItemObject = DecUserExtensionObject(RawData.Filename)\r
+        self._Headers = []\r
+        self._CurItems = []\r
+    \r
+    def BlockStart(self):\r
+        self._CurItems = []\r
+        for Header in self._RawData.CurrentScope:\r
+            if Header in self._Headers:\r
+                self._LoggerError(ST.ERR_DECPARSE_UE_DUPLICATE)\r
+            else:\r
+                self._Headers.append(Header)\r
+            \r
+            for Item in self._CurItems:\r
+                if Item.UserId == Header[1] and Item.IdString == Header[2]:\r
+                    Item.ArchAndModuleType.append(Header[3])\r
+                    break\r
+            else:\r
+                Item = DecUserExtensionItemObject()\r
+                Item.UserId = Header[1]\r
+                Item.IdString = Header[2]\r
+                Item.ArchAndModuleType.append(Header[3])\r
+                self._CurItems.append(Item)\r
+                self.ItemObject.AddItem(Item, None)\r
+        self._LocalMacro = {}\r
+    \r
+    def _ParseItem(self):\r
+        Line = self._RawData.CurrentLine\r
+        Item = None\r
+        for Item in self._CurItems:\r
+            if Item.UserString:\r
+                Item.UserString = '\n'.join([Item.UserString, Line])\r
+            else:\r
+                Item.UserString = Line\r
+        return Item\r
+\r
+## Dec\r
+#\r
+# Top dec parser\r
+#\r
+class Dec(_DecBase, _DecComments):    \r
+    def __init__(self, DecFile, Parse = True):        \r
+        try:\r
+            Content   = ConvertSpecialChar(open(DecFile, 'rb').readlines())\r
+        except BaseException:\r
+            Logger.Error(TOOL_NAME, FILE_OPEN_FAILURE, File=DecFile,\r
+                         ExtraData=ST.ERR_DECPARSE_FILEOPEN % DecFile)\r
+        RawData = FileContent(DecFile, Content)\r
+        \r
+        _DecComments.__init__(self)\r
+        _DecBase.__init__(self, RawData)\r
+        \r
+        self._Define    = _DecDefine(RawData)\r
+        self._Include   = _DecInclude(RawData)\r
+        self._Guid      = _DecGuid(RawData)\r
+        self._LibClass  = _DecLibraryclass(RawData)\r
+        self._Pcd       = _DecPcd(RawData)\r
+        self._UserEx    = _DecUserExtension(RawData)\r
+        \r
+        #\r
+        # DEC file supported data types (one type per section)\r
+        #\r
+        self._SectionParser = {\r
+            DT.TAB_DEC_DEFINES.upper()                     :   self._Define,\r
+            DT.TAB_INCLUDES.upper()                        :   self._Include,\r
+            DT.TAB_LIBRARY_CLASSES.upper()                 :   self._LibClass,\r
+            DT.TAB_GUIDS.upper()                           :   self._Guid,\r
+            DT.TAB_PPIS.upper()                            :   self._Guid,\r
+            DT.TAB_PROTOCOLS.upper()                       :   self._Guid,\r
+            DT.TAB_PCDS_FIXED_AT_BUILD_NULL.upper()        :   self._Pcd,\r
+            DT.TAB_PCDS_PATCHABLE_IN_MODULE_NULL.upper()   :   self._Pcd,\r
+            DT.TAB_PCDS_FEATURE_FLAG_NULL.upper()          :   self._Pcd,\r
+            DT.TAB_PCDS_DYNAMIC_NULL.upper()               :   self._Pcd,\r
+            DT.TAB_PCDS_DYNAMIC_EX_NULL.upper()            :   self._Pcd,\r
+            DT.TAB_USER_EXTENSIONS.upper()                 :   self._UserEx\r
+        }\r
+\r
+        if Parse:\r
+            self.ParseDecComment()\r
+            self.Parse()\r
+            #\r
+            # Parsing done, check required fields\r
+            #\r
+            self.CheckRequiredFields()\r
+    \r
+    def CheckRequiredFields(self):\r
+        for SectionParser in self._SectionParser.values():\r
+            if not SectionParser.CheckRequiredFields():\r
+                return False\r
+        return True\r
+    \r
+    ##\r
+    # Parse DEC file\r
+    #\r
+    def ParseDecComment(self):\r
+        while not self._RawData.IsEndOfFile():\r
+            Line, Comment = CleanString(self._RawData.GetNextLine())\r
+            #\r
+            # Header must be pure comment\r
+            #\r
+            if Line != '':\r
+                self._RawData.UndoNextLine()\r
+                break\r
+            \r
+            if Comment:\r
+                self._HeadComment.append((Comment, self._RawData.LineIndex))\r
+            #\r
+            # Double '#' indicates end of header comments\r
+            #\r
+            if not Comment or Comment == DT.TAB_SPECIAL_COMMENT:\r
+                break\r
+        \r
+        return\r
+    \r
+    def _StopCurrentParsing(self, Line):\r
+        return False\r
+    \r
+    def _ParseItem(self):\r
+        self._SectionHeaderParser()\r
+        if len(self._RawData.CurrentScope) == 0:\r
+            self._LoggerError(ST.ERR_DECPARSE_SECTION_EMPTY)\r
+\r
+        SectionObj = self._SectionParser[self._RawData.CurrentScope[0][0]]\r
+\r
+        SectionObj.BlockStart()\r
+        SectionObj.Parse()\r
+        \r
+        return SectionObj.GetDataObject()\r
+\r
+    def _UserExtentionSectionParser(self):\r
+        self._RawData.CurrentScope = []\r
+        ArchList = set()\r
+        Section = self._RawData.CurrentLine[1:-1]\r
+        \r
+        Par = ParserHelper(Section, self._RawData.Filename)\r
+        while not Par.End():\r
+            #\r
+            # User extention\r
+            #\r
+            Token = Par.GetToken()\r
+            if Token.upper() != DT.TAB_USER_EXTENSIONS.upper():\r
+                self._LoggerError(ST.ERR_DECPARSE_SECTION_UE)\r
+            UserExtension = Token.upper()\r
+\r
+            Par.AssertChar(DT.TAB_SPLIT, ST.ERR_DECPARSE_SECTION_UE, self._RawData.LineIndex)\r
+            #\r
+            # UserID\r
+            #\r
+            Token = Par.GetToken()\r
+            if not IsValidUserId(Token):\r
+                self._LoggerError(ST.ERR_DECPARSE_SECTION_UE_USERID)\r
+            UserId = Token\r
+            \r
+            Par.AssertChar(DT.TAB_SPLIT, ST.ERR_DECPARSE_SECTION_UE, self._RawData.LineIndex)\r
+            #\r
+            # IdString\r
+            #\r
+            Token = Par.GetToken()\r
+            if not IsValidIdString(Token):\r
+                self._LoggerError(ST.ERR_DECPARSE_SECTION_UE_IDSTRING)\r
+            IdString = Token\r
+            \r
+            Arch = 'COMMON'\r
+            if Par.Expect(DT.TAB_SPLIT):\r
+                Token = Par.GetToken()\r
+                Arch = Token.upper()\r
+                if not IsValidArch(Arch):\r
+                    self._LoggerError(ST.ERR_DECPARSE_ARCH)\r
+            ArchList.add(Arch)\r
+            \r
+            if [UserExtension, UserId, IdString, Arch] not in \\r
+                self._RawData.CurrentScope:\r
+                self._RawData.CurrentScope.append(\r
+                    [UserExtension, UserId, IdString, Arch]\r
+                )\r
+            \r
+            if not Par.Expect(DT.TAB_COMMA_SPLIT):\r
+                break\r
+            elif Par.End():\r
+                self._LoggerError(ST.ERR_DECPARSE_SECTION_COMMA)\r
+        \r
+        Par.AssertEnd(ST.ERR_DECPARSE_SECTION_UE, self._RawData.LineIndex)\r
+        \r
+        if 'COMMON' in ArchList and len(ArchList) > 1:\r
+            self._LoggerError(ST.ERR_DECPARSE_SECTION_COMMON)\r
\r
+    ## Section header parser\r
+    #\r
+    # The section header is always in following format:\r
+    #\r
+    # [section_name.arch<.platform|module_type>]\r
+    #\r
+    def _SectionHeaderParser(self):\r
+        if self._RawData.CurrentLine[0] != DT.TAB_SECTION_START or self._RawData.CurrentLine[-1] != DT.TAB_SECTION_END:\r
+            self._LoggerError(ST.ERR_DECPARSE_SECTION_IDENTIFY)\r
+        \r
+        RawSection = self._RawData.CurrentLine[1:-1].strip().upper()\r
+        \r
+        #\r
+        # Check defines section which is only allowed to occur once and\r
+        # no arch can be followed\r
+        #\r
+        if RawSection.startswith(DT.TAB_DEC_DEFINES.upper()):\r
+            if RawSection != DT.TAB_DEC_DEFINES.upper():\r
+                self._LoggerError(ST.ERR_DECPARSE_DEFINE_SECNAME)\r
+        \r
+        #\r
+        # Check user extension section\r
+        #\r
+        if RawSection.startswith(DT.TAB_USER_EXTENSIONS.upper()):\r
+            return self._UserExtentionSectionParser()\r
+        \r
+        self._RawData.CurrentScope = []\r
+        SectionNames = []\r
+        ArchList = set()\r
+        for Item in GetSplitValueList(RawSection, DT.TAB_COMMA_SPLIT):\r
+            if Item == '':\r
+                self._LoggerError(ST.ERR_DECPARSE_SECTION_SUBEMPTY % self._RawData.CurrentLine)\r
+\r
+            ItemList = GetSplitValueList(Item, DT.TAB_SPLIT)\r
+\r
+            #\r
+            # different types of PCD are permissible in one section\r
+            #\r
+            SectionName = ItemList[0]\r
+            if SectionName not in self._SectionParser:\r
+                self._LoggerError(ST.ERR_DECPARSE_SECTION_UNKNOW % SectionName)\r
+            \r
+            if SectionName not in SectionNames:\r
+                SectionNames.append(SectionName)\r
+            \r
+            #\r
+            # In DEC specification, all section headers have at most two part:\r
+            # SectionName.Arch except UserExtention\r
+            #\r
+            if len(ItemList) > 2:\r
+                self._LoggerError(ST.ERR_DECPARSE_SECTION_SUBTOOMANY % Item)\r
+\r
+            if DT.TAB_PCDS_FEATURE_FLAG_NULL.upper() in SectionNames and len(SectionNames) > 1:\r
+                self._LoggerError(ST.ERR_DECPARSE_SECTION_FEATUREFLAG % DT.TAB_PCDS_FEATURE_FLAG_NULL) \r
+            #\r
+            # S1 is always Arch\r
+            #\r
+            if len(ItemList) > 1:\r
+                Str1 = ItemList[1]\r
+                if not IsValidArch(Str1):\r
+                    self._LoggerError(ST.ERR_DECPARSE_ARCH)\r
+            else:\r
+                Str1 = 'COMMON'\r
+            ArchList.add(Str1)\r
+\r
+            if [SectionName, Str1] not in self._RawData.CurrentScope:\r
+                self._RawData.CurrentScope.append([SectionName, Str1])\r
+        #\r
+        # 'COMMON' must not be used with specific ARCHs at the same section\r
+        #\r
+        if 'COMMON' in ArchList and len(ArchList) > 1:\r
+            self._LoggerError(ST.ERR_DECPARSE_SECTION_COMMON)\r
+        \r
+        if len(SectionNames) == 0:\r
+            self._LoggerError(ST.ERR_DECPARSE_SECTION_SUBEMPTY % self._RawData.CurrentLine)\r
+        if len(SectionNames) != 1:\r
+            for Sec in SectionNames:\r
+                if not Sec.startswith(DT.TAB_PCDS.upper()):\r
+                    self._LoggerError(ST.ERR_DECPARSE_SECTION_NAME % str(SectionNames))\r
+    \r
+    def GetDefineSectionObject(self):\r
+        return self._Define.GetDataObject()\r
+    \r
+    def GetIncludeSectionObject(self):\r
+        return self._Include.GetDataObject()\r
+    \r
+    def GetGuidSectionObject(self):\r
+        return self._Guid.GetGuidObject()\r
+    \r
+    def GetProtocolSectionObject(self):\r
+        return self._Guid.GetProtocolObject()\r
+    \r
+    def GetPpiSectionObject(self):\r
+        return self._Guid.GetPpiObject()\r
+    \r
+    def GetLibraryClassSectionObject(self):\r
+        return self._LibClass.GetDataObject()\r
+    \r
+    def GetPcdSectionObject(self):\r
+        return self._Pcd.GetDataObject()\r
+    \r
+    def GetUserExtensionSectionObject(self):\r
+        return self._UserEx.GetDataObject()\r
+    \r
+    def GetPackageSpecification(self):\r
+        return self._Define.GetDataObject().GetPackageSpecification()\r
+    \r
+    def GetPackageName(self):\r
+        return self._Define.GetDataObject().GetPackageName()\r
+    \r
+    def GetPackageGuid(self):\r
+        return self._Define.GetDataObject().GetPackageGuid()\r
+    \r
+    def GetPackageVersion(self):\r
+        return self._Define.GetDataObject().GetPackageVersion()\r
+    \r
+    def GetPackageUniFile(self):\r
+        return self._Define.GetDataObject().GetPackageUniFile()\r