public inbox for devel@edk2.groups.io
 help / color / mirror / Atom feed
From: Yonghong Zhu <yonghong.zhu@intel.com>
To: edk2-devel@lists.01.org
Cc: Star Zeng <star.zeng@intel.com>, Liming Gao <liming.gao@intel.com>
Subject: [Patch] BaseTools: Add PackageDocumentTools into Scripts folder
Date: Thu, 15 Mar 2018 14:45:51 +0800	[thread overview]
Message-ID: <1521096351-17908-1-git-send-email-yonghong.zhu@intel.com> (raw)

This tool is used to generate the document for edk2 packages. The
generated document will be in UDK release. For example, UDK2017
document can be found in:
https://github.com/tianocore/tianocore.github.io/wiki/UDK2017#documentation

Cc: Star Zeng <star.zeng@intel.com>
Cc: Liming Gao <liming.gao@intel.com>
Contributed-under: TianoCore Contribution Agreement 1.1
Signed-off-by: Yonghong Zhu <yonghong.zhu@intel.com>
---
 BaseTools/Scripts/PackageDocumentTools/Readme.md   |   19 +
 BaseTools/Scripts/PackageDocumentTools/__init__.py |   12 +
 .../Scripts/PackageDocumentTools/packagedoc_cli.py |  429 ++++++++
 .../Scripts/PackageDocumentTools/packagedocapp.pyw | 1066 +++++++++++++++++++
 .../plugins/EdkPlugins/__init__.py                 |   12 +
 .../plugins/EdkPlugins/basemodel/__init__.py       |   12 +
 .../plugins/EdkPlugins/basemodel/doxygen.py        |  449 ++++++++
 .../plugins/EdkPlugins/basemodel/efibinary.py      |  611 +++++++++++
 .../plugins/EdkPlugins/basemodel/ini.py            |  480 +++++++++
 .../plugins/EdkPlugins/basemodel/inidocview.py     |   23 +
 .../plugins/EdkPlugins/basemodel/message.py        |   52 +
 .../plugins/EdkPlugins/edk2/__init__.py            |   12 +
 .../plugins/EdkPlugins/edk2/model/__init__.py      |   12 +
 .../plugins/EdkPlugins/edk2/model/baseobject.py    |  934 +++++++++++++++++
 .../plugins/EdkPlugins/edk2/model/dec.py           |  319 ++++++
 .../plugins/EdkPlugins/edk2/model/doxygengen.py    | 1089 +++++++++++++++++++
 .../EdkPlugins/edk2/model/doxygengen_spec.py       | 1092 ++++++++++++++++++++
 .../plugins/EdkPlugins/edk2/model/dsc.py           |  201 ++++
 .../plugins/EdkPlugins/edk2/model/inf.py           |  341 ++++++
 .../PackageDocumentTools/plugins/__init__.py       |   12 +
 20 files changed, 7177 insertions(+)
 create mode 100644 BaseTools/Scripts/PackageDocumentTools/Readme.md
 create mode 100644 BaseTools/Scripts/PackageDocumentTools/__init__.py
 create mode 100644 BaseTools/Scripts/PackageDocumentTools/packagedoc_cli.py
 create mode 100644 BaseTools/Scripts/PackageDocumentTools/packagedocapp.pyw
 create mode 100644 BaseTools/Scripts/PackageDocumentTools/plugins/EdkPlugins/__init__.py
 create mode 100644 BaseTools/Scripts/PackageDocumentTools/plugins/EdkPlugins/basemodel/__init__.py
 create mode 100644 BaseTools/Scripts/PackageDocumentTools/plugins/EdkPlugins/basemodel/doxygen.py
 create mode 100644 BaseTools/Scripts/PackageDocumentTools/plugins/EdkPlugins/basemodel/efibinary.py
 create mode 100644 BaseTools/Scripts/PackageDocumentTools/plugins/EdkPlugins/basemodel/ini.py
 create mode 100644 BaseTools/Scripts/PackageDocumentTools/plugins/EdkPlugins/basemodel/inidocview.py
 create mode 100644 BaseTools/Scripts/PackageDocumentTools/plugins/EdkPlugins/basemodel/message.py
 create mode 100644 BaseTools/Scripts/PackageDocumentTools/plugins/EdkPlugins/edk2/__init__.py
 create mode 100644 BaseTools/Scripts/PackageDocumentTools/plugins/EdkPlugins/edk2/model/__init__.py
 create mode 100644 BaseTools/Scripts/PackageDocumentTools/plugins/EdkPlugins/edk2/model/baseobject.py
 create mode 100644 BaseTools/Scripts/PackageDocumentTools/plugins/EdkPlugins/edk2/model/dec.py
 create mode 100644 BaseTools/Scripts/PackageDocumentTools/plugins/EdkPlugins/edk2/model/doxygengen.py
 create mode 100644 BaseTools/Scripts/PackageDocumentTools/plugins/EdkPlugins/edk2/model/doxygengen_spec.py
 create mode 100644 BaseTools/Scripts/PackageDocumentTools/plugins/EdkPlugins/edk2/model/dsc.py
 create mode 100644 BaseTools/Scripts/PackageDocumentTools/plugins/EdkPlugins/edk2/model/inf.py
 create mode 100644 BaseTools/Scripts/PackageDocumentTools/plugins/__init__.py

diff --git a/BaseTools/Scripts/PackageDocumentTools/Readme.md b/BaseTools/Scripts/PackageDocumentTools/Readme.md
new file mode 100644
index 0000000..dfc2892
--- /dev/null
+++ b/BaseTools/Scripts/PackageDocumentTools/Readme.md
@@ -0,0 +1,19 @@
+Prerequisite Tools:
+1. Install Python 2.7.3 from https://www.python.org/download/releases/2.7.3/
+2. Install wxPython 2.8.12.1 from https://sourceforge.net/projects/wxpython/files/wxPython/2.8.12.1/
+   generally the libraries will be installed at python's subfolder, for example in windows: c:\python27\Lib\site-packages\
+3. Install DoxyGen 1.8.6 from https://sourceforge.net/projects/doxygen/files/rel-1.8.6/
+4. (Windows only) Install Htmlhelp tool from https://msdn.microsoft.com/en-us/library/windows/desktop/ms669985(v=vs.85).aspx
+
+Limitation:
+1. Current tool doesn't work on latest wxPython and DoxyGen tool. Please use the sepecific version in above.
+
+Run the Tool:
+a) Run with GUI:
+  1. Enter src folder, double click "packagedocapp.pyw" or run command "python packagedocapp.pyw" to open the GUI.
+  2. Make sure all the information in blank are correct.
+  3. Click "Generate Package Document!"
+b) Run with command line:
+  1. Open command line window
+  2. Enter src folder, for example: "cd C:\PackageDocumentTools\src"
+  3. Run "python packagedoc_cli.py --help" for detail command.
diff --git a/BaseTools/Scripts/PackageDocumentTools/__init__.py b/BaseTools/Scripts/PackageDocumentTools/__init__.py
new file mode 100644
index 0000000..3e4ee53
--- /dev/null
+++ b/BaseTools/Scripts/PackageDocumentTools/__init__.py
@@ -0,0 +1,12 @@
+## @file
+#
+# Copyright (c) 2011 - 2018, Intel Corporation. All rights reserved.<BR>
+#
+# This program and the accompanying materials are licensed and made available
+# under the terms and conditions of the BSD License which accompanies this
+# distribution. The full text of the license may be found at
+# http://opensource.org/licenses/bsd-license.php
+#
+# THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+# WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+#
diff --git a/BaseTools/Scripts/PackageDocumentTools/packagedoc_cli.py b/BaseTools/Scripts/PackageDocumentTools/packagedoc_cli.py
new file mode 100644
index 0000000..92ee699
--- /dev/null
+++ b/BaseTools/Scripts/PackageDocumentTools/packagedoc_cli.py
@@ -0,0 +1,429 @@
+## @file
+# This module provide command line entry for generating package document!
+#
+# Copyright (c) 2011 - 2018, Intel Corporation. All rights reserved.<BR>
+#
+# This program and the accompanying materials are licensed and made available
+# under the terms and conditions of the BSD License which accompanies this
+# distribution. The full text of the license may be found at
+# http://opensource.org/licenses/bsd-license.php
+#
+# THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+# WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+#
+
+import os, sys, logging, traceback, subprocess
+from optparse import OptionParser
+
+import plugins.EdkPlugins.edk2.model.baseobject as baseobject
+import plugins.EdkPlugins.edk2.model.doxygengen as doxygengen
+
+gArchMarcoDict = {'ALL'      : 'MDE_CPU_IA32 MDE_CPU_X64 MDE_CPU_EBC MDE_CPU_IPF _MSC_EXTENSIONS __GNUC__ __INTEL_COMPILER',
+                  'IA32_MSFT': 'MDE_CPU_IA32 _MSC_EXTENSIONS',
+                  'IA32_GNU' : 'MDE_CPU_IA32 __GNUC__',
+                  'X64_MSFT' : 'MDE_CPU_X64 _MSC_EXTENSIONS  ASM_PFX= OPTIONAL= ',
+                  'X64_GNU'  : 'MDE_CPU_X64 __GNUC__  ASM_PFX= OPTIONAL= ',
+                  'IPF_MSFT' : 'MDE_CPU_IPF _MSC_EXTENSIONS  ASM_PFX= OPTIONAL= ',
+                  'IPF_GNU'  : 'MDE_CPU_IPF __GNUC__  ASM_PFX= OPTIONAL= ',
+                  'EBC_INTEL': 'MDE_CPU_EBC __INTEL_COMPILER  ASM_PFX= OPTIONAL= '}
+
+def parseCmdArgs():
+    parser = OptionParser(version="Package Document Generation Tools - Version 0.1")
+    parser.add_option('-w', '--workspace', action='store', type='string', dest='WorkspacePath',
+                      help='Specify workspace absolute path. For example: c:\\tianocore')
+    parser.add_option('-p', '--decfile', action='store', dest='PackagePath',
+                      help='Specify the absolute path for package DEC file. For example: c:\\tianocore\\MdePkg\\MdePkg.dec')
+    parser.add_option('-x', '--doxygen', action='store', dest='DoxygenPath',
+                      help='Specify the absolute path of doxygen tools installation. For example: C:\\Program Files\\doxygen\bin\doxygen.exe')
+    parser.add_option('-o', '--output', action='store', dest='OutputPath',
+                      help='Specify the document output path. For example: c:\\docoutput')
+    parser.add_option('-a', '--arch', action='store', dest='Arch', choices=gArchMarcoDict.keys(),
+                      help='Specify the architecture used in preprocess package\'s source. For example: -a IA32_MSFT')
+    parser.add_option('-m', '--mode', action='store', dest='DocumentMode', choices=['CHM', 'HTML'],
+                      help='Specify the document mode from : CHM or HTML')
+    parser.add_option('-i', '--includeonly', action='store_true', dest='IncludeOnly',
+                      help='Only generate document for package\'s public interfaces produced by include folder. ')
+    parser.add_option('-c', '--htmlworkshop', dest='HtmlWorkshopPath',
+                      help='Specify the absolute path for Microsoft HTML Workshop\'s hhc.exe file. For example: C:\\Program Files\\HTML Help Workshop\\hhc.exe')
+    (options, args) = parser.parse_args()
+
+    # validate the options
+    errors = []
+    if options.WorkspacePath == None:
+        errors.append('- Please specify workspace path via option -w!')
+    elif not os.path.exists(options.WorkspacePath):
+        errors.append("- Invalid workspace path %s! The workspace path should be exist in absolute path!" % options.WorkspacePath)
+
+    if options.PackagePath == None:
+        errors.append('- Please specify package DEC file path via option -p!')
+    elif not os.path.exists(options.PackagePath):
+        errors.append("- Invalid package's DEC file path %s! The DEC path should be exist in absolute path!" % options.PackagePath)
+
+    default = "C:\\Program Files\\doxygen\\bin\\doxygen.exe"
+    if options.DoxygenPath == None:
+        if os.path.exists(default):
+            print "Warning: Assume doxygen tool is installed at %s. If not, please specify via -x" % default
+            options.DoxygenPath = default
+        else:
+            errors.append('- Please specify the path of doxygen tool installation via option -x! or install it in default path %s' % default)
+    elif not os.path.exists(options.DoxygenPath):
+        errors.append("- Invalid doxygen tool path %s! The doxygen tool path should be exist in absolute path!" % options.DoxygenPath)
+
+    if options.OutputPath != None:
+        if not os.path.exists(options.OutputPath):
+            # create output
+            try:
+                os.makedirs(options.OutputPath)
+            except:
+                errors.append('- Fail to create the output directory %s' % options.OutputPath)
+    else:
+        if options.PackagePath != None and os.path.exists(options.PackagePath):
+            dirpath = os.path.dirname(options.PackagePath)
+            default = os.path.join (dirpath, "Document")
+            print 'Warning: Assume document output at %s. If not, please specify via option -o' % default
+            options.OutputPath = default
+            if not os.path.exists(default):
+                try:
+                    os.makedirs(default)
+                except:
+                    errors.append('- Fail to create default output directory %s! Please specify document output diretory via option -o' % default)
+        else:
+            errors.append('- Please specify document output path via option -o!')
+
+    if options.Arch == None:
+        options.Arch = 'ALL'
+        print "Warning: Assume arch is \"ALL\". If not, specify via -a"
+
+    if options.DocumentMode == None:
+        options.DocumentMode = "HTML"
+        print "Warning: Assume document mode is \"HTML\". If not, specify via -m"
+
+    if options.IncludeOnly == None:
+        options.IncludeOnly = False
+        print "Warning: Assume generate package document for all package\'s source including publich interfaces and implementation libraries and modules."
+
+    if options.DocumentMode.lower() == 'chm':
+        default = "C:\\Program Files\\HTML Help Workshop\\hhc.exe"
+        if options.HtmlWorkshopPath == None:
+            if os.path.exists(default):
+                print 'Warning: Assume the installation path of Microsoft HTML Workshop is %s. If not, specify via option -c.' % default
+                options.HtmlWorkshopPath = default
+            else:
+                errors.append('- Please specify the installation path of Microsoft HTML Workshop via option -c!')
+        elif not os.path.exists(options.HtmlWorkshopPath):
+            errors.append('- The installation path of Microsoft HTML Workshop %s does not exists. ' % options.HtmlWorkshopPath)
+
+    if len(errors) != 0:
+        print '\n'
+        parser.error('Fail to start due to following reasons: \n%s' %'\n'.join(errors))
+    return (options.WorkspacePath, options.PackagePath, options.DoxygenPath, options.OutputPath,
+            options.Arch, options.DocumentMode, options.IncludeOnly, options.HtmlWorkshopPath)
+
+def createPackageObject(wsPath, pkgPath):
+    try:
+        pkgObj = baseobject.Package(None, wsPath)
+        pkgObj.Load(pkgPath)
+    except:
+        logging.getLogger().error ('Fail to create package object!')
+        return None
+
+    return pkgObj
+
+def callbackLogMessage(msg, level):
+    print msg.strip()
+
+def callbackCreateDoxygenProcess(doxPath, configPath):
+    if sys.platform == 'win32':
+        cmd = '"%s" %s' % (doxPath, configPath)
+    else:
+        cmd = '%s %s' % (doxPath, configPath)
+    print cmd
+    subprocess.call(cmd, shell=True)
+
+
+def DocumentFixup(outPath, arch):
+    # find BASE_LIBRARY_JUMP_BUFFER structure reference page
+
+    print '\n    >>> Start fixup document \n'
+
+    for root, dirs, files in os.walk(outPath):
+        for dir in dirs:
+            if dir.lower() in ['.svn', '_svn', 'cvs']:
+                dirs.remove(dir)
+        for file in files:
+            if not file.lower().endswith('.html'): continue
+            fullpath = os.path.join(outPath, root, file)
+            try:
+                f = open(fullpath, 'r')
+                text = f.read()
+                f.close()
+            except:
+                logging.getLogger().error('\nFail to open file %s\n' % fullpath)
+                continue
+            if arch.lower() == 'all':
+                if text.find('BASE_LIBRARY_JUMP_BUFFER Struct Reference') != -1:
+                    FixPageBASE_LIBRARY_JUMP_BUFFER(fullpath, text)
+                if text.find('MdePkg/Include/Library/BaseLib.h File Reference') != -1:
+                    FixPageBaseLib(fullpath, text)
+                if text.find('IA32_IDT_GATE_DESCRIPTOR Union Reference') != -1:
+                    FixPageIA32_IDT_GATE_DESCRIPTOR(fullpath, text)
+            if text.find('MdePkg/Include/Library/UefiDriverEntryPoint.h File Reference') != -1:
+                FixPageUefiDriverEntryPoint(fullpath, text)
+            if text.find('MdePkg/Include/Library/UefiApplicationEntryPoint.h File Reference') != -1:
+                FixPageUefiApplicationEntryPoint(fullpath, text)
+
+    print '    >>> Finish all document fixing up! \n'
+
+def FixPageBaseLib(path, text):
+    print '    >>> Fixup BaseLib file page at file %s \n' % path
+    lines = text.split('\n')
+    lastBaseJumpIndex = -1
+    lastIdtGateDescriptor = -1
+    for index in range(len(lines) - 1, -1, -1):
+        line = lines[index]
+        if line.strip() == '<td class="memname">#define BASE_LIBRARY_JUMP_BUFFER_ALIGNMENT&nbsp;&nbsp;&nbsp;4          </td>':
+            lines[index] = '<td class="memname">#define BASE_LIBRARY_JUMP_BUFFER_ALIGNMENT&nbsp;&nbsp;&nbsp;4&nbsp;[IA32]    </td>'
+        if line.strip() == '<td class="memname">#define BASE_LIBRARY_JUMP_BUFFER_ALIGNMENT&nbsp;&nbsp;&nbsp;0x10          </td>':
+            lines[index] = '<td class="memname">#define BASE_LIBRARY_JUMP_BUFFER_ALIGNMENT&nbsp;&nbsp;&nbsp;0x10&nbsp;[IPF]   </td>'
+        if line.strip() == '<td class="memname">#define BASE_LIBRARY_JUMP_BUFFER_ALIGNMENT&nbsp;&nbsp;&nbsp;8          </td>':
+            lines[index] = '<td class="memname">#define BASE_LIBRARY_JUMP_BUFFER_ALIGNMENT&nbsp;&nbsp;&nbsp;9&nbsp;[EBC, x64]   </td>'
+        if line.find('BASE_LIBRARY_JUMP_BUFFER_ALIGNMENT</a>&nbsp;&nbsp;&nbsp;4') != -1:
+            lines[index] = lines[index].replace('BASE_LIBRARY_JUMP_BUFFER_ALIGNMENT</a>&nbsp;&nbsp;&nbsp;4',
+                                 'BASE_LIBRARY_JUMP_BUFFER_ALIGNMENT</a>&nbsp;&nbsp;&nbsp;4&nbsp;[IA32]')
+        if line.find('BASE_LIBRARY_JUMP_BUFFER_ALIGNMENT</a>&nbsp;&nbsp;&nbsp;0x10') != -1:
+            lines[index] = lines[index].replace('BASE_LIBRARY_JUMP_BUFFER_ALIGNMENT</a>&nbsp;&nbsp;&nbsp;0x10',
+                                 'BASE_LIBRARY_JUMP_BUFFER_ALIGNMENT</a>&nbsp;&nbsp;&nbsp;0x10&nbsp;[IPF]')
+        if line.find('BASE_LIBRARY_JUMP_BUFFER_ALIGNMENT</a>&nbsp;&nbsp;&nbsp;8') != -1:
+            lines[index] = lines[index].replace('BASE_LIBRARY_JUMP_BUFFER_ALIGNMENT</a>&nbsp;&nbsp;&nbsp;8',
+                                 'BASE_LIBRARY_JUMP_BUFFER_ALIGNMENT</a>&nbsp;&nbsp;&nbsp;8&nbsp;[x64, EBC]')
+        if line.find('>BASE_LIBRARY_JUMP_BUFFER</a>') != -1:
+            if lastBaseJumpIndex != -1:
+                del lines[lastBaseJumpIndex]
+            lastBaseJumpIndex = index
+        if line.find('>IA32_IDT_GATE_DESCRIPTOR</a></td>') != -1:
+            if lastIdtGateDescriptor != -1:
+                del lines[lastIdtGateDescriptor]
+            lastIdtGateDescriptor = index
+    try:
+        f = open(path, 'w')
+        f.write('\n'.join(lines))
+        f.close()
+    except:
+        logging.getLogger().error("     <<< Fail to fixup file %s\n" % path)
+        return
+    print "    <<< Finish to fixup file %s\n" % path
+
+def FixPageIA32_IDT_GATE_DESCRIPTOR(path, text):
+    print '    >>> Fixup structure reference IA32_IDT_GATE_DESCRIPTOR at file %s \n' % path
+    lines = text.split('\n')
+    for index in range(len(lines) - 1, -1, -1):
+        line = lines[index].strip()
+        if line.find('struct {</td>') != -1 and lines[index - 2].find('>Uint64</a></td>') != -1:
+            lines.insert(index, '<tr><td colspan="2"><br><h2>Data Fields For X64</h2></td></tr>')
+        if line.find('struct {</td>') != -1 and lines[index - 1].find('Data Fields') != -1:
+            lines.insert(index, '<tr><td colspan="2"><br><h2>Data Fields For IA32</h2></td></tr>')
+    try:
+        f = open(path, 'w')
+        f.write('\n'.join(lines))
+        f.close()
+    except:
+        logging.getLogger().error("     <<< Fail to fixup file %s\n" % path)
+        return
+    print "    <<< Finish to fixup file %s\n" % path
+
+def FixPageBASE_LIBRARY_JUMP_BUFFER(path, text):
+    print '    >>> Fixup structure reference BASE_LIBRARY_JUMP_BUFFER at file %s \n' % path
+    lines = text.split('\n')
+    bInDetail = True
+    bNeedRemove = False
+    for index in range(len(lines) - 1, -1, -1):
+        line = lines[index]
+        if line.find('Detailed Description') != -1:
+            bInDetail = False
+        if line.startswith('EBC context buffer used by') and lines[index - 1].startswith('x64 context buffer'):
+            lines[index] = "IA32/IPF/X64/" + line
+            bNeedRemove  = True
+        if line.startswith("x64 context buffer") or line.startswith('IPF context buffer used by') or \
+           line.startswith('IA32 context buffer used by'):
+            if bNeedRemove:
+                lines.remove(line)
+        if line.find('>R0</a>') != -1 and not bInDetail:
+            if lines[index - 1] != '<tr><td colspan="2"><br><h2>Data Fields For EBC</h2></td></tr>':
+                lines.insert(index, '<tr><td colspan="2"><br><h2>Data Fields For EBC</h2></td></tr>')
+        if line.find('>Rbx</a>') != -1 and not bInDetail:
+            if lines[index - 1] != '<tr><td colspan="2"><br><h2>Data Fields For X64</h2></td></tr>':
+                lines.insert(index, '<tr><td colspan="2"><br><h2>Data Fields For X64</h2></td></tr>')
+        if line.find('>F2</a>') != -1 and not bInDetail:
+            if lines[index - 1] != '<tr><td colspan="2"><br><h2>Data Fields For IPF</h2></td></tr>':
+                lines.insert(index, '<tr><td colspan="2"><br><h2>Data Fields For IPF</h2></td></tr>')
+        if line.find('>Ebx</a>') != -1 and not bInDetail:
+            if lines[index - 1] != '<tr><td colspan="2"><br><h2>Data Fields For IA32</h2></td></tr>':
+                lines.insert(index, '<tr><td colspan="2"><br><h2>Data Fields For IA32</h2></td></tr>')
+    try:
+        f = open(path, 'w')
+        f.write('\n'.join(lines))
+        f.close()
+    except:
+        logging.getLogger().error("     <<< Fail to fixup file %s" % path)
+        return
+    print "    <<< Finish to fixup file %s\n" % path
+
+def FixPageUefiDriverEntryPoint(path, text):
+    print '    >>> Fixup file reference MdePkg/Include/Library/UefiDriverEntryPoint.h at file %s \n' % path
+    lines = text.split('\n')
+    bInModuleEntry = False
+    bInEfiMain     = False
+    ModuleEntryDlCount  = 0
+    ModuleEntryDelStart = 0
+    ModuleEntryDelEnd   = 0
+    EfiMainDlCount      = 0
+    EfiMainDelStart     = 0
+    EfiMainDelEnd       = 0
+
+    for index in range(len(lines)):
+        line = lines[index].strip()
+        if line.find('EFI_STATUS</a> EFIAPI _ModuleEntryPoint           </td>') != -1:
+            bInModuleEntry = True
+        if line.find('EFI_STATUS</a> EFIAPI EfiMain           </td>') != -1:
+            bInEfiMain = True
+        if line.startswith('<p>References <a'):
+            if bInModuleEntry:
+                ModuleEntryDelEnd = index - 1
+                bInModuleEntry = False
+            elif bInEfiMain:
+                EfiMainDelEnd = index - 1
+                bInEfiMain = False
+        if bInModuleEntry:
+            if line.startswith('</dl>'):
+                ModuleEntryDlCount = ModuleEntryDlCount + 1
+            if ModuleEntryDlCount == 1:
+                ModuleEntryDelStart = index + 1
+        if bInEfiMain:
+            if line.startswith('</dl>'):
+                EfiMainDlCount = EfiMainDlCount + 1
+            if EfiMainDlCount == 1:
+                EfiMainDelStart = index + 1
+
+    if EfiMainDelEnd > EfiMainDelStart:
+        for index in range(EfiMainDelEnd, EfiMainDelStart, -1):
+            del lines[index]
+    if ModuleEntryDelEnd > ModuleEntryDelStart:
+        for index in range(ModuleEntryDelEnd, ModuleEntryDelStart, -1):
+            del lines[index]
+
+    try:
+        f = open(path, 'w')
+        f.write('\n'.join(lines))
+        f.close()
+    except:
+        logging.getLogger().error("     <<< Fail to fixup file %s" % path)
+        return
+    print "    <<< Finish to fixup file %s\n" % path
+
+
+def FixPageUefiApplicationEntryPoint(path, text):
+    print '    >>> Fixup file reference MdePkg/Include/Library/UefiApplicationEntryPoint.h at file %s \n' % path
+    lines = text.split('\n')
+    bInModuleEntry = False
+    bInEfiMain     = False
+    ModuleEntryDlCount  = 0
+    ModuleEntryDelStart = 0
+    ModuleEntryDelEnd   = 0
+    EfiMainDlCount      = 0
+    EfiMainDelStart     = 0
+    EfiMainDelEnd       = 0
+
+    for index in range(len(lines)):
+        line = lines[index].strip()
+        if line.find('EFI_STATUS</a> EFIAPI _ModuleEntryPoint           </td>') != -1:
+            bInModuleEntry = True
+        if line.find('EFI_STATUS</a> EFIAPI EfiMain           </td>') != -1:
+            bInEfiMain = True
+        if line.startswith('<p>References <a'):
+            if bInModuleEntry:
+                ModuleEntryDelEnd = index - 1
+                bInModuleEntry = False
+            elif bInEfiMain:
+                EfiMainDelEnd = index - 1
+                bInEfiMain = False
+        if bInModuleEntry:
+            if line.startswith('</dl>'):
+                ModuleEntryDlCount = ModuleEntryDlCount + 1
+            if ModuleEntryDlCount == 1:
+                ModuleEntryDelStart = index + 1
+        if bInEfiMain:
+            if line.startswith('</dl>'):
+                EfiMainDlCount = EfiMainDlCount + 1
+            if EfiMainDlCount == 1:
+                EfiMainDelStart = index + 1
+
+    if EfiMainDelEnd > EfiMainDelStart:
+        for index in range(EfiMainDelEnd, EfiMainDelStart, -1):
+            del lines[index]
+    if ModuleEntryDelEnd > ModuleEntryDelStart:
+        for index in range(ModuleEntryDelEnd, ModuleEntryDelStart, -1):
+            del lines[index]
+
+    try:
+        f = open(path, 'w')
+        f.write('\n'.join(lines))
+        f.close()
+    except:
+        logging.getLogger().error("     <<< Fail to fixup file %s" % path)
+        return
+    print "    <<< Finish to fixup file %s\n" % path
+
+if __name__ == '__main__':
+    wspath, pkgpath, doxpath, outpath, archtag, docmode, isinc, hwpath = parseCmdArgs()
+
+    # configure logging system
+    logfilepath = os.path.join(outpath, 'log.txt')
+    logging.basicConfig(format='%(levelname)-8s %(message)s', level=logging.DEBUG)
+
+    # create package model object firstly
+    pkgObj = createPackageObject(wspath, pkgpath)
+    if pkgObj == None:
+        sys.exit(-1)
+
+    # create doxygen action model
+    arch    = None
+    tooltag = None
+    if archtag.lower() != 'all':
+        arch = archtag.split('_')[0]
+        tooltag = archtag.split('_')[1]
+    else:
+        arch    = 'all'
+        tooltag = 'all'
+
+    # preprocess package and call doxygen
+    try:
+        action = doxygengen.PackageDocumentAction(doxpath,
+                                                  hwpath,
+                                                  outpath,
+                                                  pkgObj,
+                                                  docmode,
+                                                  callbackLogMessage,
+                                                  arch,
+                                                  tooltag,
+                                                  isinc,
+                                                  True)
+        action.RegisterCallbackDoxygenProcess(callbackCreateDoxygenProcess)
+        action.Generate()
+    except:
+        message = traceback.format_exception(*sys.exc_info())
+        logging.getLogger().error('Fail to create doxygen action! \n%s' % ''.join(message))
+        sys.exit(-1)
+
+    DocumentFixup(outpath, arch)
+
+    # generate CHM is necessary
+    if docmode.lower() == 'chm':
+        indexpath = os.path.join(outpath, 'html', 'index.hhp')
+        if sys.platform == 'win32':
+            cmd = '"%s" %s' % (hwpath, indexpath)
+        else:
+            cmd = '%s %s' % (hwpath, indexpath)
+        subprocess.call(cmd)
+        print '\nFinish to generate package document! Please open %s for review' % os.path.join(outpath, 'html', 'index.chm')
+    else:
+        print '\nFinish to generate package document! Please open %s for review' % os.path.join(outpath, 'html', 'index.html')
diff --git a/BaseTools/Scripts/PackageDocumentTools/packagedocapp.pyw b/BaseTools/Scripts/PackageDocumentTools/packagedocapp.pyw
new file mode 100644
index 0000000..28f6f9b
--- /dev/null
+++ b/BaseTools/Scripts/PackageDocumentTools/packagedocapp.pyw
@@ -0,0 +1,1066 @@
+## @file
+# This file is used to define common string related functions used in parsing
+# process
+#
+# Copyright (c) 2011 - 2018, Intel Corporation. All rights reserved.<BR>
+#
+# This program and the accompanying materials are licensed and made available
+# under the terms and conditions of the BSD License which accompanies this
+# distribution. The full text of the license may be found at
+# http://opensource.org/licenses/bsd-license.php
+#
+# THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+# WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+#
+
+import os, sys, wx, logging
+
+import wx.stc
+import wx.lib.newevent
+import wx.lib.agw.genericmessagedialog as GMD
+import plugins.EdkPlugins.edk2.model.baseobject as baseobject
+import plugins.EdkPlugins.edk2.model.doxygengen as doxygengen
+
+if hasattr(sys, "frozen"):
+    appPath = os.path.abspath(os.path.dirname(sys.executable))
+else:
+    appPath = os.path.abspath(os.path.dirname(__file__))
+
+AppCallBackEvent, EVT_APP_CALLBACK = wx.lib.newevent.NewEvent()
+LogEvent, EVT_LOG = wx.lib.newevent.NewEvent()
+
+class PackageDocApp(wx.App):
+
+    def OnInit(self):
+        logfile = os.path.join(appPath, 'log.txt')
+        logging.basicConfig(format='%(name)-8s %(levelname)-8s %(message)s',
+                            filename=logfile, level=logging.ERROR)
+
+        self.SetAppName('Package Doxygen Generate Application')
+        frame = PackageDocMainFrame(None, "Package Document Generation Application!")
+        self.SetTopWindow(frame)
+
+        frame.Show(True)
+
+        EVT_APP_CALLBACK( self, self.OnAppCallBack)
+        return True
+
+    def GetLogger(self):
+        return logging.getLogger('')
+
+    def ForegroundProcess(self, function, args):
+        wx.PostEvent(self, AppCallBackEvent(callback=function, args=args))
+
+    def OnAppCallBack(self, event):
+        try:
+            event.callback(*event.args)
+        except:
+            self._logger.exception( 'OnAppCallBack<%s.%s>\n' %
+                (event.callback.__module__, event.callback.__name__ ))
+
+class PackageDocMainFrame(wx.Frame):
+    def __init__(self, parent, title):
+        wx.Frame.__init__(self, parent, -1, title, size=(550, 290), style=wx.MINIMIZE_BOX|wx.SYSTEM_MENU|wx.CAPTION|wx.CLOSE_BOX )
+
+        panel = wx.Panel(self)
+        sizer = wx.BoxSizer(wx.VERTICAL)
+
+        subsizer = wx.GridBagSizer(5, 10)
+        subsizer.AddGrowableCol(1)
+        subsizer.Add(wx.StaticText(panel, -1, "Workspace Location : "), (0, 0), flag=wx.ALIGN_CENTER_VERTICAL)
+        self._workspacePathCtrl = wx.ComboBox(panel, -1)
+        list = self.GetConfigure("WorkspacePath")
+        if len(list) != 0:
+            for item in list:
+                self._workspacePathCtrl.Append(item)
+            self._workspacePathCtrl.SetValue(list[len(list) - 1])
+
+        subsizer.Add(self._workspacePathCtrl, (0, 1), flag=wx.ALIGN_CENTER_VERTICAL|wx.EXPAND)
+        self._workspacePathBt = wx.BitmapButton(panel, -1, bitmap=wx.ArtProvider_GetBitmap(wx.ART_FILE_OPEN))
+        subsizer.Add(self._workspacePathBt, (0, 2), flag=wx.ALIGN_CENTER_VERTICAL)
+        wx.EVT_BUTTON(self._workspacePathBt, self._workspacePathBt.GetId(), self.OnBrowsePath)
+
+        subsizer.Add(wx.StaticText(panel, -1, "Package DEC Location : "), (1, 0), flag=wx.ALIGN_CENTER_VERTICAL|wx.EXPAND)
+        self._packagePathCtrl = wx.ComboBox(panel, -1)
+        list = self.GetConfigure("PackagePath")
+        if len(list) != 0:
+            for item in list:
+                self._packagePathCtrl.Append(item)
+            self._packagePathCtrl.SetValue(list[len(list) - 1])
+        subsizer.Add(self._packagePathCtrl, (1, 1), flag=wx.ALIGN_CENTER_VERTICAL|wx.EXPAND)
+        self._packagePathBt = wx.BitmapButton(panel, -1, bitmap=wx.ArtProvider_GetBitmap(wx.ART_FILE_OPEN))
+        subsizer.Add(self._packagePathBt, (1, 2), flag=wx.ALIGN_CENTER_VERTICAL)
+        wx.EVT_BUTTON(self._packagePathBt, self._packagePathBt.GetId(), self.OnBrowsePath)
+
+        subsizer.Add(wx.StaticText(panel, -1, "Doxygen Tool Location : "), (2, 0), flag=wx.ALIGN_CENTER_VERTICAL)
+        self._doxygenPathCtrl = wx.TextCtrl(panel, -1)
+        list = self.GetConfigure('DoxygenPath')
+        if len(list) != 0:
+            self._doxygenPathCtrl.SetValue(list[0])
+        else:
+            if wx.Platform == '__WXMSW__':
+                self._doxygenPathCtrl.SetValue('C:\\Program Files\\Doxygen\\bin\\doxygen.exe')
+            else:
+                self._doxygenPathCtrl.SetValue('/usr/bin/doxygen')
+
+        self._doxygenPathBt = wx.BitmapButton(panel, -1, bitmap=wx.ArtProvider_GetBitmap(wx.ART_FILE_OPEN))
+        subsizer.Add(self._doxygenPathCtrl, (2, 1), flag=wx.ALIGN_CENTER_VERTICAL|wx.EXPAND)
+        subsizer.Add(self._doxygenPathBt, (2, 2), flag=wx.ALIGN_CENTER_VERTICAL)
+        wx.EVT_BUTTON(self._doxygenPathBt, self._doxygenPathBt.GetId(), self.OnBrowsePath)
+
+        subsizer.Add(wx.StaticText(panel, -1, "CHM Tool Location : "), (3, 0), flag=wx.ALIGN_CENTER_VERTICAL)
+        self._chmPathCtrl = wx.TextCtrl(panel, -1)
+        list = self.GetConfigure('CHMPath')
+        if len(list) != 0:
+            self._chmPathCtrl.SetValue(list[0])
+        else:
+            self._chmPathCtrl.SetValue('C:\\Program Files\\HTML Help Workshop\\hhc.exe')
+
+        self._chmPathBt = wx.BitmapButton(panel, -1, bitmap=wx.ArtProvider_GetBitmap(wx.ART_FILE_OPEN))
+        subsizer.Add(self._chmPathCtrl, (3, 1), flag=wx.ALIGN_CENTER_VERTICAL|wx.EXPAND)
+        subsizer.Add(self._chmPathBt, (3, 2), flag=wx.ALIGN_CENTER_VERTICAL)
+        wx.EVT_BUTTON(self._chmPathBt, self._chmPathBt.GetId(), self.OnBrowsePath)
+
+        subsizer.Add(wx.StaticText(panel, -1, "Output Location : "), (4, 0), flag=wx.ALIGN_CENTER_VERTICAL)
+        self._outputPathCtrl = wx.ComboBox(panel, -1)
+        list = self.GetConfigure("OutputPath")
+        if len(list) != 0:
+            for item in list:
+                self._outputPathCtrl.Append(item)
+            self._outputPathCtrl.SetValue(list[len(list) - 1])
+
+        subsizer.Add(self._outputPathCtrl, (4, 1), flag=wx.ALIGN_CENTER_VERTICAL|wx.EXPAND)
+        self._outputPathBt = wx.BitmapButton(panel, -1, bitmap=wx.ArtProvider_GetBitmap(wx.ART_FILE_OPEN))
+        subsizer.Add(self._outputPathBt, (4, 2), flag=wx.ALIGN_CENTER_VERTICAL|wx.EXPAND)
+        wx.EVT_BUTTON(self._outputPathBt, self._outputPathBt.GetId(), self.OnBrowsePath)
+
+        subsizer.Add(wx.StaticText(panel, -1, "Architecture Specified : "), (5, 0), flag=wx.ALIGN_CENTER_VERTICAL)
+        self._archCtrl = wx.ComboBox(panel, -1, value='ALL', choices=['ALL', 'IA32/MSFT', 'IA32/GNU', 'X64/INTEL', 'X64/GNU', 'IPF/MSFT', 'IPF/GNU', 'EBC/INTEL'],
+                                     style=wx.CB_READONLY)
+        self._archCtrl.Bind(wx.EVT_COMBOBOX, self.OnArchtectureSelectChanged)
+        subsizer.Add(self._archCtrl, (5, 1), (1, 2), flag=wx.ALIGN_CENTER_VERTICAL|wx.EXPAND)
+        sizer.Add(subsizer, 0, wx.EXPAND|wx.TOP|wx.BOTTOM|wx.LEFT|wx.RIGHT, 5)
+
+        sizer6 = wx.BoxSizer(wx.HORIZONTAL)
+        self._modesel = wx.RadioBox(panel, -1, 'Generated Document Mode', majorDimension=2, choices=['CHM', 'HTML'], style=wx.RA_SPECIFY_COLS)
+        self._modesel.SetStringSelection('HTML')
+
+        self._includeonlysel = wx.CheckBox(panel, -1, 'Only document public include')
+
+        sizer6.Add(self._modesel, 0 , wx.EXPAND)
+        sizer6.Add(self._includeonlysel, 0, wx.EXPAND|wx.LEFT, 5)
+
+        sizer.Add(sizer6, 0, wx.EXPAND|wx.TOP|wx.LEFT|wx.RIGHT, 5)
+
+        self._generateBt = wx.Button(panel, -1, "Generate Package Document!")
+        self._generateBt.Bind(wx.EVT_BUTTON, self.OnGenerate)
+        sizer.Add(self._generateBt, 0, wx.EXPAND|wx.TOP|wx.LEFT|wx.RIGHT, 5)
+
+        panel.SetSizer(sizer)
+        panel.Layout()
+        panel.SetAutoLayout(True)
+        self.CenterOnScreen()
+
+    def SaveConfigure(self, name, value):
+        if value ==None or len(value) == 0:
+            return
+        config = wx.ConfigBase_Get()
+        oldvalues = config.Read(name, '').split(';')
+        if len(oldvalues) >= 10:
+            oldvalues.remove(oldvalues[0])
+        if value not in oldvalues:
+            oldvalues.append(value)
+        else:
+            oldvalues.remove(value)
+            oldvalues.append(value)
+
+        config.Write(name, ';'.join(oldvalues))
+
+    def GetConfigure(self, name):
+        config = wx.ConfigBase_Get()
+        values = config.Read(name, '').split(';')
+        list = []
+        for item in values:
+            if len(item) != 0:
+                list.append(item)
+        return list
+
+    def OnBrowsePath(self, event):
+        id       = event.GetId()
+        editctrl = None
+        startdir = ''
+        isFile   = False
+        if id == self._packagePathBt.GetId():
+            dlgTitle = "Choose package path:"
+            editctrl = self._packagePathCtrl
+            isFile   = True
+            if os.path.exists(self.GetWorkspace()):
+                startdir = self.GetWorkspace()
+        elif id == self._workspacePathBt.GetId():
+            dlgTitle = "Choose workspace path:"
+            editctrl = self._workspacePathCtrl
+            startdir = editctrl.GetValue()
+        elif id == self._doxygenPathBt.GetId():
+            isFile  = True
+            dlgTitle = "Choose doxygen installation path:"
+            editctrl = self._doxygenPathCtrl
+            startdir = editctrl.GetValue()
+        elif id == self._outputPathBt.GetId():
+            dlgTitle = "Choose document output path:"
+            editctrl = self._outputPathCtrl
+            if os.path.exists(self.GetWorkspace()):
+                startdir = self.GetWorkspace()
+            startdir = editctrl.GetValue()
+        elif id == self._chmPathBt.GetId():
+            isFile = True
+            dlgTitle = "Choose installation path for Microsoft HTML workshop software"
+            editctrl = self._chmPathCtrl
+            startdir = editctrl.GetValue()
+        else:
+            return
+
+        if not isFile:
+            dlg = wx.DirDialog(self, dlgTitle, defaultPath=startdir)
+        else:
+            dlg = wx.FileDialog(self, dlgTitle, defaultDir=startdir)
+
+        if dlg.ShowModal() == wx.ID_OK:
+            editctrl.SetValue(dlg.GetPath())
+        dlg.Destroy()
+
+    def OnArchtectureSelectChanged(self, event):
+        str = ''
+        selarch = self._archCtrl.GetValue()
+        if selarch == 'ALL':
+            str += 'MDE_CPU_IA32 MDE_CPU_X64 MDE_CPU_EBC MDE_CPU_IPF _MSC_EXTENSIONS __GNUC__ __INTEL_COMPILER'
+        elif selarch == 'IA32/MSFT':
+            str += 'MDE_CPU_IA32 _MSC_EXTENSIONS'
+        elif selarch == 'IA32/GNU':
+            str += 'MDE_CPU_IA32 __GNUC__'
+        elif selarch == 'X64/MSFT':
+            str += 'MDE_CPU_X64 _MSC_EXTENSIONS'
+        elif selarch == 'X64/GNU':
+            str += 'MDE_CPU_X64 __GNUC__'
+        elif selarch == 'IPF/MSFT':
+            str += 'MDE_CPU_IPF _MSC_EXTENSIONS'
+        elif selarch == 'IPF/GNU':
+            str += 'MDE_CPU_IPF __GNUC__'
+        elif selarch == 'EBC/INTEL':
+            str += 'MDE_CPU_EBC __INTEL_COMPILER'
+
+        str += ' ASM_PFX= OPTIONAL= '
+
+    def OnMacroText(self, event):
+        str = ''
+        selarch = self._archCtrl.GetValue()
+        if selarch == 'ALL':
+            str += 'MDE_CPU_IA32 MDE_CPU_X64 MDE_CPU_EBC MDE_CPU_IPF _MSC_EXTENSIONS __GNUC__ __INTEL_COMPILER'
+        elif selarch == 'IA32/MSFT':
+            str += 'MDE_CPU_IA32 _MSC_EXTENSIONS'
+        elif selarch == 'IA32/GNU':
+            str += 'MDE_CPU_IA32 __GNUC__'
+        elif selarch == 'X64/MSFT':
+            str += 'MDE_CPU_X64 _MSC_EXTENSIONS'
+        elif selarch == 'X64/GNU':
+            str += 'MDE_CPU_X64 __GNUC__'
+        elif selarch == 'IPF/MSFT':
+            str += 'MDE_CPU_IPF _MSC_EXTENSIONS'
+        elif selarch == 'IPF/GNU':
+            str += 'MDE_CPU_IPF __GNUC__'
+        elif selarch == 'EBC/INTEL':
+            str += 'MDE_CPU_EBC __INTEL_COMPILER'
+
+        str += ' ASM_PFX= OPTIONAL= '
+
+    def OnGenerate(self, event):
+        if not self.CheckInput(): return
+
+        dlg = ProgressDialog(self)
+        dlg.ShowModal()
+        dlg.Destroy()
+
+    def CheckInput(self):
+        pPath = self.GetPackagePath()
+        wPath = self.GetWorkspace()
+        dPath = self.GetDoxygenToolPath()
+        cPath = self.GetChmToolPath()
+        oPath = self.GetOutputPath()
+
+        if len(wPath) == 0 or not os.path.exists(wPath):
+            self._Error("Please input existing workspace path!")
+            return False
+        else:
+            self.SaveConfigure('WorkspacePath', wPath)
+
+        if len(pPath) == 0 or not os.path.exists(pPath) or not pPath.lower().endswith('.dec'):
+            self._Error("Please input existing package file location!")
+            return False
+        elif pPath.lower().find(wPath.lower()) == -1:
+            self._Error("Package patch should starts with workspace path, such as if workspace path is c:\\edk2, package patch could be c:\\edk2\MdePkg")
+            return False
+        else:
+            self.SaveConfigure('PackagePath', pPath)
+
+        if len(dPath) == 0 or not os.path.exists(dPath):
+            self._Error("Can not find doxygen tool from path %s! Please download it from www.stack.nl/~dimitri/doxygen/download.html" % dPath)
+            return False
+        else:
+            self.SaveConfigure('DoxygenPath', dPath)
+
+        if self._modesel.GetStringSelection() == 'CHM':
+            if (len(cPath) == 0 or not os.path.exists(cPath)):
+                self._Error("You select CHM mode to generate document, but can not find software of Microsoft HTML Help Workshop.\nPlease\
+ download it from http://www.microsoft.com/downloads/details.aspx?FamilyID=00535334-c8a6-452f-9aa0-d597d16580cc&displaylang=en\n\
+and install!")
+                return False
+            else:
+                self.SaveConfigure('CHMPath', cPath)
+
+        if len(oPath) == 0:
+            self._Error("You must specific document output path")
+            return False
+        else:
+            self.SaveConfigure('OutputPath', oPath)
+
+            if os.path.exists(oPath):
+                # add checking whether there is old doxygen config file here
+                files = os.listdir(oPath)
+                for file in files:
+                    if os.path.isfile(os.path.join(oPath,file)):
+                        basename, ext = os.path.splitext(file)
+                        if ext.lower() == '.doxygen_config':
+                            dlg = GMD.GenericMessageDialog(self, "Existing doxygen document in output directory will be overwritten\n, Are you sure?",
+                                                           "Info", wx.ICON_WARNING|wx.YES_NO)
+                            if dlg.ShowModal() == wx.ID_YES:
+                                break
+                            else:
+                                return False
+            else:
+                try:
+                    os.makedirs(oPath)
+                except:
+                    self._Error("Fail to create output directory, please select another output directory!")
+                    return False
+
+        return True
+
+    def _Error(self, message):
+        dlg = GMD.GenericMessageDialog(self, message,
+                                       "Error", wx.ICON_ERROR|wx.OK)
+        dlg.ShowModal()
+        dlg.Destroy()
+
+    def GetWorkspace(self):
+        return os.path.normpath(self._workspacePathCtrl.GetValue())
+
+    def GetPackagePath(self):
+        return os.path.normpath(self._packagePathCtrl.GetValue())
+
+    def GetOutputPath(self):
+        return os.path.normpath(self._outputPathCtrl.GetValue())
+
+    def GetDoxygenToolPath(self):
+        return os.path.normpath(self._doxygenPathCtrl.GetValue())
+
+    def GetChmToolPath(self):
+        return os.path.normpath(self._chmPathCtrl.GetValue())
+
+    def GetDocumentMode(self):
+        return self._modesel.GetStringSelection()
+
+    def GetArchitecture(self):
+        value = self._archCtrl.GetValue()
+        return value.split('/')[0]
+
+    def GetToolTag(self):
+        value = self._archCtrl.GetValue()
+        if value == 'ALL':
+            return 'ALL'
+        return value.split('/')[1]
+
+    def GetIsOnlyDocumentInclude(self):
+        return self._includeonlysel.IsChecked()
+
+class ProgressDialog(wx.Dialog):
+    def __init__(self, parent, id=wx.ID_ANY):
+        title = "Generate Document for " + parent.GetPackagePath()
+        wx.Dialog.__init__(self, parent, id, title=title, style=wx.CAPTION, size=(600, 300))
+        self.Freeze()
+        sizer = wx.BoxSizer(wx.VERTICAL)
+        self._textCtrl   = wx.StaticText(self, -1, "Start launching!")
+        self._gaugeCtrl  = wx.Gauge(self, -1, 100, size=(-1, 10))
+        self._resultCtrl = wx.stc.StyledTextCtrl(self, -1)
+        self._closeBt     = wx.Button(self, -1, "Close")
+        self._gotoOuputBt = wx.Button(self, -1, "Goto Output")
+
+        # clear all margin
+        self._resultCtrl.SetMarginWidth(0, 0)
+        self._resultCtrl.SetMarginWidth(1, 0)
+        self._resultCtrl.SetMarginWidth(2, 0)
+
+        sizer.Add(self._textCtrl, 0, wx.EXPAND|wx.LEFT|wx.TOP|wx.RIGHT, 5)
+        sizer.Add(self._gaugeCtrl, 0, wx.EXPAND|wx.LEFT|wx.TOP|wx.RIGHT, 5)
+        sizer.Add(self._resultCtrl, 1, wx.EXPAND|wx.LEFT|wx.TOP|wx.RIGHT, 5)
+        btsizer  = wx.BoxSizer(wx.HORIZONTAL)
+        btsizer.Add(self._gotoOuputBt, 0, wx.ALIGN_CENTER_HORIZONTAL|wx.LEFT|wx.TOP|wx.LEFT|wx.BOTTOM, 5)
+        btsizer.Add(self._closeBt, 0, wx.ALIGN_CENTER_HORIZONTAL|wx.LEFT|wx.TOP|wx.LEFT|wx.BOTTOM, 5)
+        sizer.Add(btsizer, 0, wx.ALIGN_CENTER_HORIZONTAL)
+
+        self.SetSizer(sizer)
+        self.CenterOnScreen()
+        self.Thaw()
+
+        self._logger    = logging.getLogger('')
+        self._loghandle = ResultHandler(self)
+        logging.getLogger('edk').addHandler(self._loghandle)
+        logging.getLogger('').addHandler(self._loghandle)
+        logging.getLogger('app').addHandler(self._loghandle)
+
+        wx.EVT_BUTTON(self._closeBt, self._closeBt.GetId(), self.OnButtonClose)
+        wx.EVT_UPDATE_UI(self, self._closeBt.GetId(), self.OnUpdateCloseButton)
+        wx.EVT_BUTTON(self._gotoOuputBt, self._gotoOuputBt.GetId(), self.OnGotoOutput)
+        EVT_LOG(self, self.OnPostLog)
+
+        self._process     = None
+        self._pid         = None
+        self._input       = None
+        self._output      = None
+        self._error       = None
+        self._inputThread = None
+        self._errorThread = None
+        self._isBusy      = True
+        self._pObj        = None
+
+        wx.CallAfter(self.GenerateAction)
+
+    def OnUpdateCloseButton(self, event):
+        self._closeBt.Enable(not self._isBusy)
+        return True
+
+    def OnButtonClose(self, event):
+        if self._isBusy:
+            self._InfoDialog("Please don't close in progressing...")
+            return
+
+        if self._process != None:
+            self._process.CloseOutput()
+
+        if self._inputThread:
+            self._inputThread.Terminate()
+        if self._errorThread:
+            self._errorThread.Terminate()
+
+        if self._pid != None:
+            wx.Process.Kill(self._pid, wx.SIGKILL, wx.KILL_CHILDREN)
+
+        logging.getLogger('edk').removeHandler(self._loghandle)
+        logging.getLogger('').removeHandler(self._loghandle)
+        logging.getLogger('app').removeHandler(self._loghandle)
+
+        if self._pObj != None:
+            self._pObj.Destroy()
+
+        self.EndModal(0)
+
+    def OnGotoOutput(self, event):
+        output = self.GetParent().GetOutputPath()
+        if os.path.exists(output):
+            if wx.Platform == '__WXMSW__':
+                os.startfile(self.GetParent().GetOutputPath())
+            else:
+                import webbrowser
+                webbrowser.open(self.GetParent().GetOutputPath())
+        else:
+            self._ErrorDialog("Output directory does not exist!")
+
+    def _ErrorDialog(self, message):
+        dlg = GMD.GenericMessageDialog(self, message,
+                                       "Error", wx.ICON_ERROR|wx.OK)
+        dlg.ShowModal()
+        dlg.Destroy()
+
+    def _InfoDialog(self, message):
+        dlg = GMD.GenericMessageDialog(self, message,
+                                       "Info", wx.ICON_INFORMATION|wx.OK)
+        dlg.ShowModal()
+        dlg.Destroy()
+
+    def _LogStep(self, index, message):
+        stepstr = "Step %d: %s" % (index, message)
+        self._textCtrl.SetLabel(stepstr)
+        self.LogMessage(os.linesep + stepstr + os.linesep)
+        self._gaugeCtrl.SetValue(index * 100 / 6 )
+
+    def OnPostLog(self, event):
+        self.LogMessage(event.message)
+
+    def GenerateAction(self):
+        self._LogStep(1, "Create Package Object Model")
+        wsPath = self.GetParent().GetWorkspace()
+        pkPath = self.GetParent().GetPackagePath()[len(wsPath) + 1:]
+
+        try:
+            pObj = baseobject.Package(None, self.GetParent().GetWorkspace())
+            pObj.Load(pkPath)
+        except:
+            self._ErrorDialog("Fail to create package object model! Please check log.txt under this application folder!")
+            self._isBusy = False
+            return
+        self._pObj = pObj
+
+        self.LogMessage(str(pObj.GetPcds()))
+
+        self._LogStep(2, "Preprocess and Generate Doxygen Config File")
+        try:
+            action = doxygengen.PackageDocumentAction(self.GetParent().GetDoxygenToolPath(),
+                                                      self.GetParent().GetChmToolPath(),
+                                                      self.GetParent().GetOutputPath(),
+                                                      pObj,
+                                                      self.GetParent().GetDocumentMode(),
+                                                      self.LogMessage,
+                                                      self.GetParent().GetArchitecture(),
+                                                      self.GetParent().GetToolTag(),
+                                                      self.GetParent().GetIsOnlyDocumentInclude(),
+                                                      True)
+        except:
+            self._ErrorDialog("Fail to preprocess! Please check log.txt under this application folder!")
+            self._isBusy = False
+            return
+
+        action.RegisterCallbackDoxygenProcess(self.CreateDoxygeProcess)
+
+        try:
+            if not action.Generate():
+                self._isBusy = False
+                self.LogMessage("Fail to generate package document! Please check log.txt under this application folder!", 'error')
+        except:
+            import traceback
+            message = traceback.format_exception(*sys.exc_info())
+            logging.getLogger('').error(''.join(message))
+            self._isBusy = False
+            self._ErrorDialog("Fail to generate package document! Please check log.txt under this application folder!")
+
+    def LogMessage(self, message, level='info'):
+        self._resultCtrl.DocumentEnd()
+        self._resultCtrl.SetReadOnly(False)
+        self._resultCtrl.AppendText(message)
+        self._resultCtrl.Home()
+        self._resultCtrl.Home()
+        self._resultCtrl.SetReadOnly(True)
+        if level == 'error':
+            wx.GetApp().GetLogger().error(message)
+
+    def CreateDoxygeProcess(self, doxPath, configFile):
+        self._LogStep(3, "Launch Doxygen Tool and Generate Package Document")
+
+        cmd = '"%s" %s' % (doxPath, configFile)
+        try:
+            self._process = DoxygenProcess()
+            self._process.SetParent(self)
+            self._process.Redirect()
+            self._pid    = wx.Execute(cmd, wx.EXEC_ASYNC, self._process)
+            self._input  = self._process.GetInputStream()
+            self._output = self._process.GetOutputStream()
+            self._error  = self._process.GetErrorStream()
+        except:
+            self._ErrorDialog('Fail to launch doxygen cmd %s! Please check log.txt under this application folder!' % cmd)
+            self._isBusy = False
+            return False
+
+        self._inputThread = MonitorThread(self._input, self.LogMessage)
+        self._errorThread = MonitorThread(self._error, self.LogMessage)
+        self._inputThread.start()
+        self._errorThread.start()
+        return True
+
+    def OnTerminateDoxygenProcess(self):
+        if self._inputThread:
+            self._inputThread.Terminate()
+            self._inputThread = None
+        if self._errorThread:
+            self._errorThread.Terminate()
+            self._errorThread = None
+
+        if self._error:
+            while self._error.CanRead():
+                text = self._error.read()
+                self.LogMessage(text)
+
+        if self._input:
+            while self._input.CanRead():
+                text = self._input.read()
+                self.LogMessage(text)
+        self._process.Detach()
+
+        self._process.CloseOutput()
+        self._process = None
+        self._pid     = None
+
+        self.DocumentFixup()
+
+        if self.GetParent().GetDocumentMode().lower() == 'chm':
+            hhcfile = os.path.join(self.GetParent().GetOutputPath(), 'html', 'index.hhc')
+            hhpfile = os.path.join(self.GetParent().GetOutputPath(), 'html', 'index.hhp')
+            self.FixDecDoxygenFileLink(hhcfile, None)
+            if not self.CreateCHMProcess(self.GetParent().GetChmToolPath(), hhpfile):
+                self._ErrorDialog("Fail to Create %s process for %s" % (self.GetParent().GetChmToolPath(), hhpfile))
+                self._isBusy = False
+        else:
+            self._LogStep(6, "Finished Document Generation!")
+            self._isBusy = False
+            indexpath = os.path.realpath(os.path.join(self.GetParent().GetOutputPath(), 'html', 'index.html'))
+            if wx.Platform == '__WXMSW__':
+                os.startfile(indexpath)
+            else:
+                import webbrowser
+                webbrowser.open(indexpath)
+
+            self._InfoDialog('Success create HTML doxgen document %s' % indexpath)
+
+    def CreateCHMProcess(self, chmPath, hhpfile):
+        self.LogMessage("    >>>>>> Start Microsoft HTML workshop process...Zzz...\n")
+        cmd = '"%s" %s' % (chmPath, hhpfile)
+        try:
+            self._process = CHMProcess()
+            self._process.SetParent(self)
+            self._process.Redirect()
+            self._pid    = wx.Execute(cmd, wx.EXEC_ASYNC, self._process)
+            self._input  = self._process.GetInputStream()
+            self._output = self._process.GetOutputStream()
+            self._error  = self._process.GetErrorStream()
+        except:
+            self.LogMessage('\nFail to launch hhp cmd %s!\n' % cmd)
+            self._isBusy = False
+            return False
+        self._inputThread = MonitorThread(self._input, self.LogMessage)
+        self._errorThread = MonitorThread(self._error, self.LogMessage)
+        self._inputThread.start()
+        self._errorThread.start()
+        return True
+
+    def OnTerminateCHMProcess(self):
+        if self._inputThread:
+            self._inputThread.Terminate()
+            self._inputThread = None
+        if self._errorThread:
+            self._errorThread.Terminate()
+            self._errorThread = None
+
+        if self._error:
+            while self._error.CanRead():
+                text = self._error.read()
+                self.LogMessage(text)
+        if self._input:
+            while self._input.CanRead():
+                text = self._input.read()
+                self.LogMessage(text)
+        self._process.Detach()
+
+        self._process.CloseOutput()
+        self._process = None
+        self._pid     = None
+        self._isBusy  = False
+        indexpath = os.path.realpath(os.path.join(self.GetParent().GetOutputPath(), 'html', 'index.chm'))
+        if os.path.exists(indexpath):
+            if wx.Platform == '__WXMSW__':
+                os.startfile(indexpath)
+            else:
+                import webbrowser
+                webbrowser.open(indexpath)
+
+        self._LogStep(6, "Finished Document Generation!")
+        self.LogMessage('\nSuccess create CHM doxgen document %s\n' % indexpath)
+        self._InfoDialog('Success create CHM doxgen document %s' % indexpath)
+
+    def DocumentFixup(self):
+        # find BASE_LIBRARY_JUMP_BUFFER structure reference page
+        self._LogStep(4, "Fixup Package Document!")
+        self.LogMessage('\n    >>> Start fixup document \n')
+
+        for root, dirs, files in os.walk(os.path.join(self.GetParent().GetOutputPath(), 'html')):
+            for dir in dirs:
+                if dir.lower() in ['.svn', '_svn', 'cvs']:
+                    dirs.remove(dir)
+            for file in files:
+                wx.YieldIfNeeded()
+                if not file.lower().endswith('.html'): continue
+                fullpath = os.path.join(self.GetParent().GetOutputPath(), root, file)
+                try:
+                    f = open(fullpath, 'r')
+                    text = f.read()
+                    f.close()
+                except:
+                    self.LogMessage('\nFail to open file %s\n' % fullpath)
+                    continue
+                if text.find('BASE_LIBRARY_JUMP_BUFFER Struct Reference') != -1 and self.GetParent().GetArchitecture() == 'ALL':
+                    self.FixPageBASE_LIBRARY_JUMP_BUFFER(fullpath, text)
+                if text.find('MdePkg/Include/Library/BaseLib.h File Reference') != -1  and self.GetParent().GetArchitecture() == 'ALL':
+                    self.FixPageBaseLib(fullpath, text)
+                if text.find('IA32_IDT_GATE_DESCRIPTOR Union Reference') != -1  and self.GetParent().GetArchitecture() == 'ALL':
+                    self.FixPageIA32_IDT_GATE_DESCRIPTOR(fullpath, text)
+                if text.find('MdePkg/Include/Library/UefiDriverEntryPoint.h File Reference') != -1:
+                    self.FixPageUefiDriverEntryPoint(fullpath, text)
+                if text.find('MdePkg/Include/Library/UefiApplicationEntryPoint.h File Reference') != -1:
+                    self.FixPageUefiApplicationEntryPoint(fullpath, text)
+                if text.lower().find('.s.dox') != -1 or \
+                   text.lower().find('.asm.dox') != -1 or \
+                   text.lower().find('.uni.dox') != -1:
+                   self.FixDoxFileLink(fullpath, text)
+
+        self.RemoveFileList()
+        self.LogMessage('    >>> Finish all document fixing up! \n')
+
+    def RemoveFileList(self):
+        path_html = os.path.join(self.GetParent().GetOutputPath(), "html", "tree.html")
+        path_chm  = os.path.join(self.GetParent().GetOutputPath(), "html", "index.hhc")
+        if os.path.exists(path_html):
+            self.LogMessage('    >>>Remove FileList item from generated HTML document.\n');
+            lines = []
+            f = open (path_html, "r")
+            lines = f.readlines()
+            f.close()
+            bfound = False
+            for index in xrange(len(lines)):
+                if lines[index].find('<a class="el" href="files.html" target="basefrm">File List</a>') != -1:
+                    lines[index] = "<!-- %s" % lines[index]
+                    bfound = True
+                    continue
+                if bfound:
+                    if lines[index].find('</div>') != -1:
+                        lines[index] = "%s -->" % lines[index]
+                        break
+            if bfound:
+                f = open(path_html, "w")
+                f.write("".join(lines))
+                f.close()
+            else:
+                self.LogMessage ('    !!!Can not found FileList item in HTML document!\n')
+
+        if os.path.exists(path_chm):
+            self.LogMessage("    >>>Warning: Can not remove FileList for CHM files!\n");
+            """
+            self.LogMessage('    >>>Remove FileList item from generated CHM document!\n');
+            lines = []
+            f = open (path_chm, "r")
+            lines = f.readlines()
+            f.close()
+            bfound = False
+            for index in xrange(len(lines)):
+                if not bfound:
+                    if lines[index].find('<param name="Local" value="files.html">') != -1:
+                        lines[index] = '<!-- %s' % lines[index]
+                        bfound = True
+                        continue
+                if bfound:
+                    if lines[index].find('</UL>') != -1:
+                        lines[index] = '%s -->\n' % lines[index].rstrip()
+                        break
+            if bfound:
+                f = open(path_chm, "w")
+                f.write("".join(lines))
+                f.close()
+                import time
+                time.sleep(2)
+            else:
+                self.LogMessage('   !!!Can not found the FileList item in CHM document!')
+            """
+    def FixPageBaseLib(self, path, text):
+        self.LogMessage('    >>> Fixup BaseLib file page at file %s \n' % path)
+        lines = text.split('\n')
+        lastBaseJumpIndex = -1
+        lastIdtGateDescriptor = -1
+        for index in range(len(lines) - 1, -1, -1):
+            line = lines[index]
+            if line.strip() == '<td class="memname">#define BASE_LIBRARY_JUMP_BUFFER_ALIGNMENT&nbsp;&nbsp;&nbsp;4          </td>':
+                lines[index] = '<td class="memname">#define BASE_LIBRARY_JUMP_BUFFER_ALIGNMENT&nbsp;&nbsp;&nbsp;4&nbsp;[IA32]    </td>'
+            if line.strip() == '<td class="memname">#define BASE_LIBRARY_JUMP_BUFFER_ALIGNMENT&nbsp;&nbsp;&nbsp;0x10          </td>':
+                lines[index] = '<td class="memname">#define BASE_LIBRARY_JUMP_BUFFER_ALIGNMENT&nbsp;&nbsp;&nbsp;0x10&nbsp;[IPF]   </td>'
+            if line.strip() == '<td class="memname">#define BASE_LIBRARY_JUMP_BUFFER_ALIGNMENT&nbsp;&nbsp;&nbsp;8          </td>':
+                lines[index] = '<td class="memname">#define BASE_LIBRARY_JUMP_BUFFER_ALIGNMENT&nbsp;&nbsp;&nbsp;9&nbsp;[EBC, x64]   </td>'
+            if line.find('BASE_LIBRARY_JUMP_BUFFER_ALIGNMENT</a>&nbsp;&nbsp;&nbsp;4') != -1:
+                lines[index] = lines[index].replace('BASE_LIBRARY_JUMP_BUFFER_ALIGNMENT</a>&nbsp;&nbsp;&nbsp;4',
+                                     'BASE_LIBRARY_JUMP_BUFFER_ALIGNMENT</a>&nbsp;&nbsp;&nbsp;4&nbsp;[IA32]')
+            if line.find('BASE_LIBRARY_JUMP_BUFFER_ALIGNMENT</a>&nbsp;&nbsp;&nbsp;0x10') != -1:
+                lines[index] = lines[index].replace('BASE_LIBRARY_JUMP_BUFFER_ALIGNMENT</a>&nbsp;&nbsp;&nbsp;0x10',
+                                     'BASE_LIBRARY_JUMP_BUFFER_ALIGNMENT</a>&nbsp;&nbsp;&nbsp;0x10&nbsp;[IPF]')
+            if line.find('BASE_LIBRARY_JUMP_BUFFER_ALIGNMENT</a>&nbsp;&nbsp;&nbsp;8') != -1:
+                lines[index] = lines[index].replace('BASE_LIBRARY_JUMP_BUFFER_ALIGNMENT</a>&nbsp;&nbsp;&nbsp;8',
+                                     'BASE_LIBRARY_JUMP_BUFFER_ALIGNMENT</a>&nbsp;&nbsp;&nbsp;8&nbsp;[x64, EBC]')
+            if line.find('>BASE_LIBRARY_JUMP_BUFFER</a>') != -1:
+                if lastBaseJumpIndex != -1:
+                    del lines[lastBaseJumpIndex]
+                lastBaseJumpIndex = index
+            if line.find('>IA32_IDT_GATE_DESCRIPTOR</a></td>') != -1:
+                if lastIdtGateDescriptor != -1:
+                    del lines[lastIdtGateDescriptor]
+                lastIdtGateDescriptor = index
+        try:
+            f = open(path, 'w')
+            f.write('\n'.join(lines))
+            f.close()
+        except:
+            self._isBusy = False
+            self.LogMessage("     <<< Fail to fixup file %s\n" % path)
+        self.LogMessage("    <<< Finish to fixup file %s\n" % path)
+
+    def FixPageIA32_IDT_GATE_DESCRIPTOR(self, path, text):
+        self.LogMessage('    >>> Fixup structure reference IA32_IDT_GATE_DESCRIPTOR at file %s \n' % path)
+        lines = text.split('\n')
+        for index in range(len(lines) - 1, -1, -1):
+            line = lines[index].strip()
+            if line.find('struct {</td>') != -1 and lines[index - 2].find('>Uint64</a></td>') != -1:
+                lines.insert(index, '<tr><td colspan="2"><br><h2>Data Fields For X64</h2></td></tr>')
+            if line.find('struct {</td>') != -1 and lines[index - 1].find('Data Fields') != -1:
+                lines.insert(index, '<tr><td colspan="2"><br><h2>Data Fields For IA32</h2></td></tr>')
+        try:
+            f = open(path, 'w')
+            f.write('\n'.join(lines))
+            f.close()
+        except:
+            self._isBusy = False
+            self.LogMessage("     <<< Fail to fixup file %s\n" % path)
+        self.LogMessage("    <<< Finish to fixup file %s\n" % path)
+
+    def FixPageBASE_LIBRARY_JUMP_BUFFER(self, path, text):
+        self.LogMessage('    >>> Fixup structure reference BASE_LIBRARY_JUMP_BUFFER at file %s \n' % path)
+        lines = text.split('\n')
+        bInDetail = True
+        bNeedRemove = False
+        for index in range(len(lines) - 1, -1, -1):
+            line = lines[index]
+            if line.find('Detailed Description') != -1:
+                bInDetail = False
+            if line.startswith('EBC context buffer used by') and lines[index - 1].startswith('x64 context buffer'):
+                lines[index] = "IA32/IPF/X64/" + line
+                bNeedRemove  = True
+            if line.startswith("x64 context buffer") or line.startswith('IPF context buffer used by') or \
+               line.startswith('IA32 context buffer used by'):
+                if bNeedRemove:
+                    lines.remove(line)
+            if line.find('>R0</a>') != -1 and not bInDetail:
+                if lines[index - 1] != '<tr><td colspan="2"><br><h2>Data Fields For EBC</h2></td></tr>':
+                    lines.insert(index, '<tr><td colspan="2"><br><h2>Data Fields For EBC</h2></td></tr>')
+            if line.find('>Rbx</a>') != -1 and not bInDetail:
+                if lines[index - 1] != '<tr><td colspan="2"><br><h2>Data Fields For X64</h2></td></tr>':
+                    lines.insert(index, '<tr><td colspan="2"><br><h2>Data Fields For X64</h2></td></tr>')
+            if line.find('>F2</a>') != -1 and not bInDetail:
+                if lines[index - 1] != '<tr><td colspan="2"><br><h2>Data Fields For IPF</h2></td></tr>':
+                    lines.insert(index, '<tr><td colspan="2"><br><h2>Data Fields For IPF</h2></td></tr>')
+            if line.find('>Ebx</a>') != -1 and not bInDetail:
+                if lines[index - 1] != '<tr><td colspan="2"><br><h2>Data Fields For IA32</h2></td></tr>':
+                    lines.insert(index, '<tr><td colspan="2"><br><h2>Data Fields For IA32</h2></td></tr>')
+        try:
+            f = open(path, 'w')
+            f.write('\n'.join(lines))
+            f.close()
+        except:
+            self._isBusy = False
+            self.LogMessage("     <<< Fail to fixup file %s" % path)
+        self.LogMessage("    <<< Finish to fixup file %s\n" % path)
+
+    def FixPageUefiDriverEntryPoint(self, path, text):
+        self.LogMessage('    >>> Fixup file reference MdePkg/Include/Library/UefiDriverEntryPoint.h at file %s \n' % path)
+        lines = text.split('\n')
+        bInModuleEntry = False
+        bInEfiMain     = False
+        ModuleEntryDlCount  = 0
+        ModuleEntryDelStart = 0
+        ModuleEntryDelEnd   = 0
+        EfiMainDlCount      = 0
+        EfiMainDelStart     = 0
+        EfiMainDelEnd       = 0
+
+        for index in range(len(lines)):
+            line = lines[index].strip()
+            if line.find('EFI_STATUS</a> EFIAPI _ModuleEntryPoint           </td>') != -1:
+                bInModuleEntry = True
+            if line.find('EFI_STATUS</a> EFIAPI EfiMain           </td>') != -1:
+                bInEfiMain = True
+            if line.startswith('<p>References <a'):
+                if bInModuleEntry:
+                    ModuleEntryDelEnd = index - 1
+                    bInModuleEntry = False
+                elif bInEfiMain:
+                    EfiMainDelEnd = index - 1
+                    bInEfiMain = False
+            if bInModuleEntry:
+                if line.startswith('</dl>'):
+                    ModuleEntryDlCount = ModuleEntryDlCount + 1
+                if ModuleEntryDlCount == 1:
+                    ModuleEntryDelStart = index + 1
+            if bInEfiMain:
+                if line.startswith('</dl>'):
+                    EfiMainDlCount = EfiMainDlCount + 1
+                if EfiMainDlCount == 1:
+                    EfiMainDelStart = index + 1
+
+        if EfiMainDelEnd > EfiMainDelStart:
+            for index in range(EfiMainDelEnd, EfiMainDelStart, -1):
+                del lines[index]
+        if ModuleEntryDelEnd > ModuleEntryDelStart:
+            for index in range(ModuleEntryDelEnd, ModuleEntryDelStart, -1):
+                del lines[index]
+
+        try:
+            f = open(path, 'w')
+            f.write('\n'.join(lines))
+            f.close()
+        except:
+            self._isBusy = False
+            self.LogMessage("     <<< Fail to fixup file %s" % path)
+        self.LogMessage("    <<< Finish to fixup file %s\n" % path)
+
+    def FixPageUefiApplicationEntryPoint(self, path, text):
+        self.LogMessage('    >>> Fixup file reference MdePkg/Include/Library/UefiApplicationEntryPoint.h at file %s \n' % path)
+        lines = text.split('\n')
+        bInModuleEntry = False
+        bInEfiMain     = False
+        ModuleEntryDlCount  = 0
+        ModuleEntryDelStart = 0
+        ModuleEntryDelEnd   = 0
+        EfiMainDlCount      = 0
+        EfiMainDelStart     = 0
+        EfiMainDelEnd       = 0
+
+        for index in range(len(lines)):
+            line = lines[index].strip()
+            if line.find('EFI_STATUS</a> EFIAPI _ModuleEntryPoint           </td>') != -1:
+                bInModuleEntry = True
+            if line.find('EFI_STATUS</a> EFIAPI EfiMain           </td>') != -1:
+                bInEfiMain = True
+            if line.startswith('<p>References <a'):
+                if bInModuleEntry:
+                    ModuleEntryDelEnd = index - 1
+                    bInModuleEntry = False
+                elif bInEfiMain:
+                    EfiMainDelEnd = index - 1
+                    bInEfiMain = False
+            if bInModuleEntry:
+                if line.startswith('</dl>'):
+                    ModuleEntryDlCount = ModuleEntryDlCount + 1
+                if ModuleEntryDlCount == 1:
+                    ModuleEntryDelStart = index + 1
+            if bInEfiMain:
+                if line.startswith('</dl>'):
+                    EfiMainDlCount = EfiMainDlCount + 1
+                if EfiMainDlCount == 1:
+                    EfiMainDelStart = index + 1
+
+        if EfiMainDelEnd > EfiMainDelStart:
+            for index in range(EfiMainDelEnd, EfiMainDelStart, -1):
+                del lines[index]
+        if ModuleEntryDelEnd > ModuleEntryDelStart:
+            for index in range(ModuleEntryDelEnd, ModuleEntryDelStart, -1):
+                del lines[index]
+
+        try:
+            f = open(path, 'w')
+            f.write('\n'.join(lines))
+            f.close()
+        except:
+            self._isBusy = False
+            self.LogMessage("     <<< Fail to fixup file %s" % path)
+        self.LogMessage("    <<< Finish to fixup file %s\n" % path)
+
+
+    def FixDoxFileLink(self, path, text):
+        self.LogMessage('    >>> Fixup .dox postfix for file %s \n' % path)
+        try:
+            fd = open(path, 'r')
+            text = fd.read()
+            fd.close()
+        except Exception, e:
+            self.LogMessage ("   <<<Fail to open file %s" % path)
+            return
+        text = text.replace ('.s.dox', '.s')
+        text = text.replace ('.S.dox', '.S')
+        text = text.replace ('.asm.dox', '.asm')
+        text = text.replace ('.Asm.dox', '.Asm')
+        text = text.replace ('.uni.dox', '.uni')
+        text = text.replace ('.Uni.dox', '.Uni')
+        try:
+            fd = open(path, 'w')
+            fd.write(text)
+            fd.close()
+        except Exception, e:
+            self.LogMessage ("    <<<Fail to fixup file %s" % path)
+            return
+        self.LogMessage('    >>> Finish to fixup .dox postfix for file %s \n' % path)
+
+    def FixDecDoxygenFileLink(self, path, text):
+        self.LogMessage('    >>> Fixup .decdoxygen postfix for file %s \n' % path)
+        try:
+            fd = open(path, 'r')
+            lines = fd.readlines()
+            fd.close()
+        except Exception, e:
+            self.LogMessage ("   <<<Fail to open file %s" % path)
+            return
+        for line in lines:
+            if line.find('.decdoxygen') != -1:
+                lines.remove(line)
+                break
+        try:
+            fd = open(path, 'w')
+            fd.write("".join(lines))
+            fd.close()
+        except Exception, e:
+            self.LogMessage ("    <<<Fail to fixup file %s" % path)
+            return
+        self.LogMessage('    >>> Finish to fixup .decdoxygen postfix for file %s \n' % path)
+
+import threading
+class MonitorThread(threading.Thread):
+    def __init__(self, pipe, callback):
+        threading.Thread.__init__(self)
+        self._pipe = pipe
+        self._callback = callback
+        self._isCancel = False
+
+    def run(self):
+        while (not self._isCancel):
+            self._pipe.Peek()
+            if self._pipe.LastRead() == 0:
+                break
+            text = self._pipe.read()
+            if len(text.strip()) != 0:
+                wx.GetApp().ForegroundProcess(self._callback, (text,))
+
+    def Terminate(self):
+        self._pipe.flush()
+        self._isCancel = True
+
+class DoxygenProcess(wx.Process):
+    def OnTerminate(self, id, status):
+        self._parent.OnTerminateDoxygenProcess()
+
+    def SetParent(self, parent):
+        self._parent = parent
+
+class CHMProcess(wx.Process):
+    def OnTerminate(self, id, status):
+        self._parent.OnTerminateCHMProcess()
+
+    def SetParent(self, parent):
+        self._parent = parent
+
+class ResultHandler:
+    def __init__(self, parent):
+        self._parent = parent
+        self.level   = 0
+
+    def emit(self, record):
+        self._parent.LogMessage(record)
+
+    def handle(self, record):
+        wx.PostEvent(self._parent, LogEvent(message=record.getMessage()))
+
+    def acquire(self):
+        pass
+
+    def release(self):
+        pass
+
+if __name__ == '__main__':
+    app = PackageDocApp(redirect=False)
+    app.MainLoop()
diff --git a/BaseTools/Scripts/PackageDocumentTools/plugins/EdkPlugins/__init__.py b/BaseTools/Scripts/PackageDocumentTools/plugins/EdkPlugins/__init__.py
new file mode 100644
index 0000000..3e4ee53
--- /dev/null
+++ b/BaseTools/Scripts/PackageDocumentTools/plugins/EdkPlugins/__init__.py
@@ -0,0 +1,12 @@
+## @file
+#
+# Copyright (c) 2011 - 2018, Intel Corporation. All rights reserved.<BR>
+#
+# This program and the accompanying materials are licensed and made available
+# under the terms and conditions of the BSD License which accompanies this
+# distribution. The full text of the license may be found at
+# http://opensource.org/licenses/bsd-license.php
+#
+# THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+# WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+#
diff --git a/BaseTools/Scripts/PackageDocumentTools/plugins/EdkPlugins/basemodel/__init__.py b/BaseTools/Scripts/PackageDocumentTools/plugins/EdkPlugins/basemodel/__init__.py
new file mode 100644
index 0000000..3e4ee53
--- /dev/null
+++ b/BaseTools/Scripts/PackageDocumentTools/plugins/EdkPlugins/basemodel/__init__.py
@@ -0,0 +1,12 @@
+## @file
+#
+# Copyright (c) 2011 - 2018, Intel Corporation. All rights reserved.<BR>
+#
+# This program and the accompanying materials are licensed and made available
+# under the terms and conditions of the BSD License which accompanies this
+# distribution. The full text of the license may be found at
+# http://opensource.org/licenses/bsd-license.php
+#
+# THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+# WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+#
diff --git a/BaseTools/Scripts/PackageDocumentTools/plugins/EdkPlugins/basemodel/doxygen.py b/BaseTools/Scripts/PackageDocumentTools/plugins/EdkPlugins/basemodel/doxygen.py
new file mode 100644
index 0000000..2d0cc9d
--- /dev/null
+++ b/BaseTools/Scripts/PackageDocumentTools/plugins/EdkPlugins/basemodel/doxygen.py
@@ -0,0 +1,449 @@
+## @file
+#
+# Copyright (c) 2011 - 2018, Intel Corporation. All rights reserved.<BR>
+#
+# This program and the accompanying materials are licensed and made available
+# under the terms and conditions of the BSD License which accompanies this
+# distribution. The full text of the license may be found at
+# http://opensource.org/licenses/bsd-license.php
+#
+# THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+# WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+#
+
+import os
+
+from message import *
+
+class BaseDoxygeItem:
+    def __init__(self, name, tag=''):
+        self.mName = name
+        self.mTag  = tag
+        self.mDescription = ''
+        self.mText = []
+
+    def AddDescription(self, desc):
+        self.mDescription = '%s%s' % (self.mDescription, desc)
+
+    def __str__(self):
+        return '\n'.join(self.mText)
+
+    def Generate(self):
+        """This interface need to be override"""
+
+class Section(BaseDoxygeItem):
+    def Generate(self):
+        """This interface need to be override"""
+        if len(self.mTag) != 0:
+            self.mText.append(' \section %s %s' % (self.mName, self.mTag))
+        else:
+            self.mText.append(' \section %s' % self.mName)
+
+        self.mText.append(self.mDescription)
+        return self.mText
+
+class Page(BaseDoxygeItem):
+    def __init__(self, name, tag=None, isSort=True):
+        BaseDoxygeItem.__init__(self, name, tag)
+        self.mSubPages     = []
+        self.mIsMainPage   = False
+        self.mSections     = []
+        self.mIsSort       = isSort
+
+    def GetSubpageCount(self):
+        return len(self.mSubPages)
+
+    def AddPage(self, subpage):
+        self.mSubPages.append(subpage)
+        return subpage
+
+    def AddPages(self, pageArray):
+        if pageArray == None:
+            return
+        for page in pageArray:
+            self.AddPage(page)
+
+    def AddSection(self, section):
+        self.mSections.append(section)
+        self.mSections.sort(cmp=lambda x,y: cmp(x.mName.lower(), y.mName.lower()))
+
+    def Generate(self):
+        if self.mIsMainPage:
+            self.mText.append('/** \mainpage %s' % self.mName)
+            self.mIsSort = False
+        else:
+            self.mText.append('/** \page %s %s' % (self.mTag, self.mName))
+
+        if len(self.mDescription) != 0:
+            self.mText.append(self.mDescription)
+        endIndex = len(self.mText)
+
+        self.mSections.sort()
+        for sect in self.mSections:
+            self.mText += sect.Generate()
+
+        endIndex = len(self.mText)
+
+        if len(self.mSubPages) != 0:
+            self.mText.insert(endIndex, "<p> \section content_index INDEX")
+            endIndex = len(self.mText)
+            self.mText.insert(endIndex, '<ul>')
+            endIndex += 1
+            if self.mIsSort:
+                self.mSubPages.sort(cmp=lambda x,y: cmp(x.mName.lower(), y.mName.lower()))
+            for page in self.mSubPages:
+                self.mText.insert(endIndex, '<li>\subpage %s \"%s\" </li>' % (page.mTag, page.mName))
+                endIndex += 1
+                self.mText += page.Generate()
+            self.mText.insert(endIndex, '</ul>')
+            endIndex += 1
+        self.mText.insert(endIndex, ' **/')
+        return self.mText
+
+class DoxygenFile(Page):
+    def __init__(self, name, file):
+        Page.__init__(self, name)
+        self.mFilename  = file
+        self.mIsMainPage = True
+
+    def GetFilename(self):
+        return self.mFilename.replace('/', '\\')
+
+    def Save(self):
+        str = self.Generate()
+        try:
+            f = open(self.mFilename, 'w')
+            f.write('\n'.join(str))
+            f.close()
+        except IOError, e:
+            ErrorMsg ('Fail to write file %s' % self.mFilename)
+            return False
+
+        return True
+
+doxygenConfigTemplate = """
+DOXYFILE_ENCODING      = UTF-8
+PROJECT_NAME           = %(ProjectName)s
+PROJECT_NUMBER         = %(ProjectVersion)s
+OUTPUT_DIRECTORY       = %(OutputDir)s
+CREATE_SUBDIRS         = YES
+OUTPUT_LANGUAGE        = English
+BRIEF_MEMBER_DESC      = YES
+REPEAT_BRIEF           = YES
+ABBREVIATE_BRIEF       = "The $name class           " \\
+                         "The $name widget           " \\
+                         "The $name file           " \\
+                         is \\
+                         provides \\
+                         specifies \\
+                         contains \\
+                         represents \\
+                         a \\
+                         an \\
+                         the
+ALWAYS_DETAILED_SEC    = NO
+INLINE_INHERITED_MEMB  = NO
+FULL_PATH_NAMES        = YES
+STRIP_FROM_PATH        = %(StripPath)s
+STRIP_FROM_INC_PATH    =
+SHORT_NAMES            = YES
+JAVADOC_AUTOBRIEF      = NO
+QT_AUTOBRIEF           = NO
+MULTILINE_CPP_IS_BRIEF = NO
+DETAILS_AT_TOP         = YES
+INHERIT_DOCS           = YES
+SEPARATE_MEMBER_PAGES  = NO
+TAB_SIZE               = 1
+ALIASES                =
+OPTIMIZE_OUTPUT_FOR_C  = YES
+OPTIMIZE_OUTPUT_JAVA   = NO
+BUILTIN_STL_SUPPORT    = NO
+CPP_CLI_SUPPORT        = NO
+SIP_SUPPORT            = NO
+DISTRIBUTE_GROUP_DOC   = YES
+SUBGROUPING            = YES
+TYPEDEF_HIDES_STRUCT   = NO
+
+EXTRACT_ALL            = YES
+EXTRACT_PRIVATE        = NO
+EXTRACT_STATIC         = NO
+EXTRACT_LOCAL_CLASSES  = NO
+EXTRACT_LOCAL_METHODS  = NO
+EXTRACT_ANON_NSPACES   = NO
+HIDE_UNDOC_MEMBERS     = NO
+HIDE_UNDOC_CLASSES     = NO
+HIDE_FRIEND_COMPOUNDS  = NO
+HIDE_IN_BODY_DOCS      = NO
+INTERNAL_DOCS          = NO
+CASE_SENSE_NAMES       = NO
+HIDE_SCOPE_NAMES       = NO
+SHOW_INCLUDE_FILES     = NO
+INLINE_INFO            = YES
+SORT_MEMBER_DOCS       = YES
+SORT_BRIEF_DOCS        = NO
+SORT_BY_SCOPE_NAME     = YES
+GENERATE_TODOLIST      = YES
+GENERATE_TESTLIST      = YES
+GENERATE_BUGLIST       = YES
+GENERATE_DEPRECATEDLIST= YES
+ENABLED_SECTIONS       =
+MAX_INITIALIZER_LINES  = 30
+SHOW_USED_FILES        = NO
+SHOW_DIRECTORIES       = NO
+FILE_VERSION_FILTER    =
+
+QUIET                  = NO
+WARNINGS               = YES
+WARN_IF_UNDOCUMENTED   = YES
+WARN_IF_DOC_ERROR      = YES
+WARN_NO_PARAMDOC       = YES
+WARN_FORMAT            = "$file:$line: $text           "
+WARN_LOGFILE           = %(WarningFile)s
+
+INPUT                  = %(FileList)s
+INPUT_ENCODING         = UTF-8
+FILE_PATTERNS          = %(Pattern)s
+RECURSIVE              = NO
+EXCLUDE                = *.svn
+EXCLUDE_SYMLINKS       = NO
+EXCLUDE_PATTERNS       = .svn
+EXCLUDE_SYMBOLS        =
+EXAMPLE_PATH           = %(ExamplePath)s
+EXAMPLE_PATTERNS       = *
+EXAMPLE_RECURSIVE      = NO
+IMAGE_PATH             =
+INPUT_FILTER           =
+FILTER_PATTERNS        =
+FILTER_SOURCE_FILES    = NO
+
+SOURCE_BROWSER         = NO
+INLINE_SOURCES         = NO
+STRIP_CODE_COMMENTS    = YES
+REFERENCED_BY_RELATION = YES
+REFERENCES_RELATION    = YES
+REFERENCES_LINK_SOURCE = NO
+USE_HTAGS              = NO
+VERBATIM_HEADERS       = NO
+
+ALPHABETICAL_INDEX     = NO
+COLS_IN_ALPHA_INDEX    = 5
+IGNORE_PREFIX          =
+
+GENERATE_HTML          = YES
+HTML_OUTPUT            = html
+HTML_FILE_EXTENSION    = .html
+HTML_HEADER            =
+HTML_FOOTER            =
+HTML_STYLESHEET        =
+HTML_ALIGN_MEMBERS     = YES
+GENERATE_HTMLHELP      = %(WhetherGenerateHtmlHelp)s
+HTML_DYNAMIC_SECTIONS  = NO
+CHM_FILE               = index.chm
+HHC_LOCATION           =
+GENERATE_CHI           = NO
+BINARY_TOC             = NO
+TOC_EXPAND             = NO
+DISABLE_INDEX          = NO
+ENUM_VALUES_PER_LINE   = 4
+GENERATE_TREEVIEW      = %(WhetherGenerateTreeView)s
+TREEVIEW_WIDTH         = 250
+
+GENERATE_LATEX         = NO
+LATEX_OUTPUT           = latex
+LATEX_CMD_NAME         = latex
+MAKEINDEX_CMD_NAME     = makeindex
+COMPACT_LATEX          = NO
+PAPER_TYPE             = a4wide
+EXTRA_PACKAGES         =
+LATEX_HEADER           =
+PDF_HYPERLINKS         = YES
+USE_PDFLATEX           = YES
+LATEX_BATCHMODE        = NO
+LATEX_HIDE_INDICES     = NO
+
+GENERATE_RTF           = NO
+RTF_OUTPUT             = rtf
+COMPACT_RTF            = NO
+RTF_HYPERLINKS         = NO
+RTF_STYLESHEET_FILE    =
+RTF_EXTENSIONS_FILE    =
+
+GENERATE_MAN           = NO
+MAN_OUTPUT             = man
+MAN_EXTENSION          = .3
+MAN_LINKS              = NO
+
+GENERATE_XML           = NO
+XML_OUTPUT             = xml
+XML_SCHEMA             =
+XML_DTD                =
+XML_PROGRAMLISTING     = YES
+
+GENERATE_AUTOGEN_DEF   = NO
+
+GENERATE_PERLMOD       = NO
+PERLMOD_LATEX          = NO
+PERLMOD_PRETTY         = YES
+PERLMOD_MAKEVAR_PREFIX =
+
+ENABLE_PREPROCESSING   = YES
+MACRO_EXPANSION        = YES
+EXPAND_ONLY_PREDEF     = YES
+SEARCH_INCLUDES        = YES
+INCLUDE_PATH           = %(IncludePath)s
+INCLUDE_FILE_PATTERNS  = *.h
+PREDEFINED             = %(PreDefined)s
+EXPAND_AS_DEFINED      =
+SKIP_FUNCTION_MACROS   = NO
+
+TAGFILES               =
+GENERATE_TAGFILE       =
+ALLEXTERNALS           = NO
+EXTERNAL_GROUPS        = YES
+PERL_PATH              = /usr/bin/perl
+
+CLASS_DIAGRAMS         = NO
+MSCGEN_PATH            =
+HIDE_UNDOC_RELATIONS   = YES
+HAVE_DOT               = NO
+CLASS_GRAPH            = YES
+COLLABORATION_GRAPH    = YES
+GROUP_GRAPHS           = YES
+UML_LOOK               = NO
+TEMPLATE_RELATIONS     = NO
+INCLUDE_GRAPH          = YES
+INCLUDED_BY_GRAPH      = YES
+CALL_GRAPH             = NO
+CALLER_GRAPH           = NO
+GRAPHICAL_HIERARCHY    = YES
+DIRECTORY_GRAPH        = YES
+DOT_IMAGE_FORMAT       = png
+DOT_PATH               =
+DOTFILE_DIRS           =
+DOT_GRAPH_MAX_NODES    = 50
+MAX_DOT_GRAPH_DEPTH    = 1000
+DOT_TRANSPARENT        = YES
+DOT_MULTI_TARGETS      = NO
+GENERATE_LEGEND        = YES
+DOT_CLEANUP            = YES
+
+SEARCHENGINE           = NO
+
+"""
+class DoxygenConfigFile:
+    def __init__(self):
+        self.mProjectName  = ''
+        self.mOutputDir    = ''
+        self.mFileList     = []
+        self.mIncludeList  = []
+        self.mStripPath    = ''
+        self.mExamplePath  = ''
+        self.mPattern      = ['*.c', '*.h',
+                              '*.asm', '*.s', '.nasm', '*.html', '*.dox']
+        self.mMode         = 'HTML'
+        self.mWarningFile  = ''
+        self.mPreDefined   = []
+        self.mProjectVersion = 0.1
+
+    def SetChmMode(self):
+        self.mMode = 'CHM'
+
+    def SetHtmlMode(self):
+        self.mMode = 'HTML'
+
+    def SetProjectName(self, str):
+        self.mProjectName = str
+
+    def SetProjectVersion(self, str):
+        self.mProjectVersion = str
+
+    def SetOutputDir(self, str):
+        self.mOutputDir = str
+
+    def SetStripPath(self, str):
+        self.mStripPath = str
+
+    def SetExamplePath(self, str):
+        self.mExamplePath = str
+
+    def SetWarningFilePath(self, str):
+        self.mWarningFile = str.replace('\\', '/')
+
+    def FileExists(self, path):
+        if path == None:
+            return False
+        if len(path) == 0:
+            return False
+
+        for p in self.mFileList:
+            if path.lower() == p.lower():
+                return True
+
+        return False
+
+    def AddFile(self, path):
+        if path == None:
+            return
+
+        if len(path) == 0:
+            return
+        path = path.replace('\\', '/')
+        if not self.FileExists(path):
+            self.mFileList.append(path)
+
+    def AddIncludePath(self, path):
+        path = path.replace('\\', '/')
+        if path not in self.mIncludeList:
+            self.mIncludeList.append(path)
+
+    def AddPattern(self, pattern):
+        self.mPattern.append(pattern)
+
+    def AddPreDefined(self, macro):
+        self.mPreDefined.append(macro)
+
+    def Generate(self, path):
+        files    = ' \\\n'.join(self.mFileList)
+        includes = ' \\\n'.join(self.mIncludeList)
+        patterns = ' \\\n'.join(self.mPattern)
+        if self.mMode.lower() == 'html':
+            sHtmlHelp = 'NO'
+            sTreeView = 'YES'
+        else:
+            sHtmlHelp = 'YES'
+            sTreeView = 'NO'
+
+        text = doxygenConfigTemplate % {'ProjectName':self.mProjectName,
+                                        'OutputDir':self.mOutputDir,
+                                        'StripPath':self.mStripPath,
+                                        'ExamplePath':self.mExamplePath,
+                                        'FileList':files,
+                                        'Pattern':patterns,
+                                        'WhetherGenerateHtmlHelp':sHtmlHelp,
+                                        'WhetherGenerateTreeView':sTreeView,
+                                        'IncludePath':includes,
+                                        'WarningFile':self.mWarningFile,
+                                        'PreDefined':' '.join(self.mPreDefined),
+                                        'ProjectVersion':self.mProjectVersion}
+        try:
+            f = open(path, 'w')
+            f.write(text)
+            f.close()
+        except IOError, e:
+            ErrorMsg ('Fail to generate doxygen config file %s' % path)
+            return False
+
+        return True
+
+########################################################################
+#                  TEST                   CODE
+########################################################################
+if __name__== '__main__':
+    df = DoxygenFile('Platform Document', 'm:\tree')
+    df.AddPage(Page('Module', 'module'))
+    p = df.AddPage(Page('Library', 'library'))
+    p.AddDescription(desc)
+    p.AddPage(Page('PCD', 'pcds'))
+
+    df.Generate()
+    print df
diff --git a/BaseTools/Scripts/PackageDocumentTools/plugins/EdkPlugins/basemodel/efibinary.py b/BaseTools/Scripts/PackageDocumentTools/plugins/EdkPlugins/basemodel/efibinary.py
new file mode 100644
index 0000000..72beced
--- /dev/null
+++ b/BaseTools/Scripts/PackageDocumentTools/plugins/EdkPlugins/basemodel/efibinary.py
@@ -0,0 +1,611 @@
+## @file
+#
+# Copyright (c) 2011 - 2018, Intel Corporation. All rights reserved.<BR>
+#
+# This program and the accompanying materials are licensed and made available
+# under the terms and conditions of the BSD License which accompanies this
+# distribution. The full text of the license may be found at
+# http://opensource.org/licenses/bsd-license.php
+#
+# THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+# WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+#
+
+import array
+import uuid
+import re
+import os
+import logging
+import core.pe as pe
+
+def GetLogger():
+    return logging.getLogger('EFI Binary File')
+
+class EFIBinaryError(Exception):
+    def __init__(self, message):
+        Exception.__init__(self)
+        self._message = message
+
+    def GetMessage(self):
+        return self._message
+
+class EfiFd(object):
+    EFI_FV_HEADER_SIZE = 0x48
+
+    def __init__(self):
+        self._fvs = []
+
+    def Load(self, fd, size):
+        index = fd.tell()
+        while (index + self.EFI_FV_HEADER_SIZE < size):
+            fv = EfiFv(self)
+            fv.Load(fd)
+            self._fvs.append(fv)
+            index += fv.GetHeader().GetFvLength()
+            index = align(index, 8)
+            fd.seek(index)
+
+    def GetFvs(self):
+        return self._fvs
+
+class EfiFv(object):
+    FILE_SYSTEM_GUID = uuid.UUID('{8c8ce578-8a3d-4f1c-9935-896185c32dd3}')
+
+    def __init__(self, parent=None):
+        self._size         = 0
+        self._filename     = None
+        self._fvheader     = None
+        self._blockentries = []
+        self._ffs          = []
+
+        # following field is for FV in FD
+        self._parent       = parent
+        self._offset       = 0
+        self._raw          = array.array('B')
+
+    def Load(self, fd):
+        self._offset   = fd.tell()
+        self._filename = fd.name
+
+        # get file header
+        self._fvheader = EfiFirmwareVolumeHeader.Read(fd)
+        #self._fvheader.Dump()
+
+        self._size = self._fvheader.GetFvLength()
+
+        if self._fvheader.GetFileSystemGuid() != self.FILE_SYSTEM_GUID:
+            fd.seek(self._offset)
+            self._raw.fromfile(fd, self.GetHeader().GetFvLength())
+            return
+
+        # read block map
+        blockentry = BlockMapEntry.Read(fd)
+        self._blockentries.append(blockentry)
+        while (blockentry.GetNumberBlocks() != 0 and blockentry.GetLength() != 0):
+            self._blockentries.append(blockentry)
+            blockentry = BlockMapEntry.Read(fd)
+
+
+        if self._fvheader.GetSize() + (len(self._blockentries)) * 8 != \
+           self._fvheader.GetHeaderLength():
+            raise EFIBinaryError("Volume Header length not consistent with block map!")
+
+        index = align(fd.tell(), 8)
+        count = 0
+        while ((index + EfiFfs.FFS_HEADER_SIZE) < self._size):
+            ffs = EfiFfs.Read(fd, self)
+            if not isValidGuid(ffs.GetNameGuid()):
+                break
+            self._ffs.append(ffs)
+            count += 1
+            index = align(fd.tell(), 8)
+
+        fd.seek(self._offset)
+        self._raw.fromfile(fd, self.GetHeader().GetFvLength())
+
+    def GetFfs(self):
+        return self._ffs
+
+    def GetHeader(self):
+        return self._fvheader
+
+    def GetBlockEntries(self):
+        return self._blockentries
+
+    def GetHeaderRawData(self):
+        ret = []
+        ret += self._fvheader.GetRawData()
+        for block in self._blockentries:
+            ret += block.GetRawData()
+        return ret
+
+    def GetOffset(self):
+        return 0
+
+    def GetRawData(self):
+        return self._raw.tolist()
+
+class BinaryItem(object):
+    def __init__(self, parent=None):
+        self._size = 0
+        self._arr  = array.array('B')
+        self._parent = parent
+
+    @classmethod
+    def Read(cls, fd, parent=None):
+        item = cls(parent)
+        item.fromfile(fd)
+        return item
+
+    def Load(self, fd):
+        self.fromfile(fd)
+
+    def GetSize(self):
+        """should be implemented by inherited class"""
+
+    def fromfile(self, fd):
+        self._arr.fromfile(fd, self.GetSize())
+
+    def GetParent(self):
+        return self._parent
+
+class EfiFirmwareVolumeHeader(BinaryItem):
+    def GetSize(self):
+        return 56
+
+    def GetSigunature(self):
+        list = self._arr.tolist()
+        sig = ''
+        for x in list[40:44]:
+            sig += chr(x)
+        return sig
+
+    def GetAttribute(self):
+        return list2int(self._arr.tolist()[44:48])
+
+    def GetErasePolarity(self):
+        list = self.GetAttrStrings()
+        if 'EFI_FVB2_ERASE_POLARITY' in list:
+            return True
+        return False
+
+    def GetAttrStrings(self):
+        list = []
+        value = self.GetAttribute()
+        if (value & 0x01) != 0:
+            list.append('EFI_FVB2_READ_DISABLED_CAP')
+        if (value & 0x02) != 0:
+            list.append('EFI_FVB2_READ_ENABLED_CAP')
+        if (value & 0x04) != 0:
+            list.append('EFI_FVB2_READ_STATUS')
+        if (value & 0x08) != 0:
+            list.append('EFI_FVB2_WRITE_DISABLED_CAP')
+        if (value & 0x10) != 0:
+            list.append('EFI_FVB2_WRITE_ENABLED_CAP')
+        if (value & 0x20) != 0:
+            list.append('EFI_FVB2_WRITE_STATUS')
+        if (value & 0x40) != 0:
+            list.append('EFI_FVB2_LOCK_CAP')
+        if (value & 0x80) != 0:
+            list.append('EFI_FVB2_LOCK_STATUS')
+        if (value & 0x200) != 0:
+            list.append('EFI_FVB2_STICKY_WRITE')
+        if (value & 0x400) != 0:
+            list.append('EFI_FVB2_MEMORY_MAPPED')
+        if (value & 0x800) != 0:
+            list.append('EFI_FVB2_ERASE_POLARITY')
+        if (value & 0x1000) != 0:
+            list.append('EFI_FVB2_READ_LOCK_CAP')
+        if (value & 0x00002000) != 0:
+            list.append('EFI_FVB2_READ_LOCK_STATUS')
+        if (value & 0x00004000) != 0:
+            list.append('EFI_FVB2_WRITE_LOCK_CAP')
+        if (value & 0x00008000) != 0:
+            list.append('EFI_FVB2_WRITE_LOCK_STATUS')
+
+        if (value == 0):
+            list.append('EFI_FVB2_ALIGNMENT_1')
+        if (value & 0x001F0000) == 0x00010000:
+            list.append('EFI_FVB2_ALIGNMENT_2')
+        if (value & 0x001F0000) == 0x00020000:
+            list.append('EFI_FVB2_ALIGNMENT_4')
+        if (value & 0x001F0000) == 0x00030000:
+            list.append('EFI_FVB2_ALIGNMENT_8')
+        if (value & 0x001F0000) == 0x00040000:
+            list.append('EFI_FVB2_ALIGNMENT_16')
+        if (value & 0x001F0000) == 0x00050000:
+            list.append('EFI_FVB2_ALIGNMENT_32')
+        if (value & 0x001F0000) == 0x00060000:
+            list.append('EFI_FVB2_ALIGNMENT_64')
+        if (value & 0x001F0000) == 0x00070000:
+            list.append('EFI_FVB2_ALIGNMENT_128')
+        if (value & 0x001F0000) == 0x00080000:
+            list.append('EFI_FVB2_ALIGNMENT_256')
+        if (value & 0x001F0000) == 0x00090000:
+            list.append('EFI_FVB2_ALIGNMENT_512')
+        if (value & 0x001F0000) == 0x000A0000:
+            list.append('EFI_FVB2_ALIGNMENT_1K')
+        if (value & 0x001F0000) == 0x000B0000:
+            list.append('EFI_FVB2_ALIGNMENT_2K')
+        if (value & 0x001F0000) == 0x000C0000:
+            list.append('EFI_FVB2_ALIGNMENT_4K')
+        if (value & 0x001F0000) == 0x000D0000:
+            list.append('EFI_FVB2_ALIGNMENT_8K')
+        if (value & 0x001F0000) == 0x000E0000:
+            list.append('EFI_FVB2_ALIGNMENT_16K')
+        if (value & 0x001F0000) == 0x000F0000:
+            list.append('EFI_FVB2_ALIGNMENT_32K')
+        if (value & 0x001F0000) == 0x00100000:
+            list.append('EFI_FVB2_ALIGNMENT_64K')
+        if (value & 0x001F0000) == 0x00110000:
+            list.append('EFI_FVB2_ALIGNMENT_128K')
+        if (value & 0x001F0000) == 0x00120000:
+            list.append('EFI_FVB2_ALIGNMENT_256K')
+        if (value & 0x001F0000) == 0x00130000:
+            list.append('EFI_FVB2_ALIGNMENT_512K')
+
+        return list
+
+    def GetHeaderLength(self):
+        return list2int(self._arr.tolist()[48:50])
+
+    def Dump(self):
+        print 'Signature: %s' % self.GetSigunature()
+        print 'Attribute: 0x%X' % self.GetAttribute()
+        print 'Header Length: 0x%X' % self.GetHeaderLength()
+        print 'File system Guid: ', self.GetFileSystemGuid()
+        print 'Revision: 0x%X' % self.GetRevision()
+        print 'FvLength: 0x%X' % self.GetFvLength()
+
+    def GetFileSystemGuid(self):
+        list = self._arr.tolist()
+        return list2guid(list[16:32])
+
+    def GetRevision(self):
+        list = self._arr.tolist()
+        return int(list[55])
+
+    def GetFvLength(self):
+        list = self._arr.tolist()
+        return list2int(list[32:40])
+
+    def GetRawData(self):
+        return self._arr.tolist()
+
+class BlockMapEntry(BinaryItem):
+    def GetSize(self):
+        return 8
+
+    def GetNumberBlocks(self):
+        list = self._arr.tolist()
+        return list2int(list[0:4])
+
+    def GetLength(self):
+        list = self._arr.tolist()
+        return list2int(list[4:8])
+
+    def GetRawData(self):
+        return self._arr.tolist()
+
+    def __str__(self):
+        return '[BlockEntry] Number = 0x%X, length=0x%X' % (self.GetNumberBlocks(), self.GetLength())
+
+class EfiFfs(object):
+    FFS_HEADER_SIZE  = 24
+
+    def __init__(self, parent=None):
+        self._header = None
+
+        # following field is for FFS in FV file.
+        self._parent  = parent
+        self._offset  = 0
+        self._sections = []
+
+    def Load(self, fd):
+        self._offset = align(fd.tell(), 8)
+
+        self._header = EfiFfsHeader.Read(fd, self)
+
+        if not isValidGuid(self.GetNameGuid()):
+            return
+
+        index = self._offset
+        fileend = self._offset + self.GetSize()
+        while (index + EfiSection.EFI_SECTION_HEADER_SIZE < fileend):
+            section = EfiSection(self)
+            section.Load(fd)
+            if section.GetSize() == 0 and section.GetHeader().GetType() == 0:
+                break
+            self._sections.append(section)
+            index = fd.tell()
+
+        # rebase file pointer to next ffs file
+        index = self._offset + self._header.GetFfsSize()
+        index = align(index, 8)
+        fd.seek(index)
+
+    def GetOffset(self):
+        return self._offset
+
+    def GetSize(self):
+        return self._header.GetFfsSize()
+
+    @classmethod
+    def Read(cls, fd, parent=None):
+        item = cls(parent)
+        item.Load(fd)
+        return item
+
+    def GetNameGuid(self):
+        return self._header.GetNameGuid()
+
+    def DumpContent(self):
+        list  = self._content.tolist()
+        line  = []
+        count = 0
+        for item in list:
+            if count < 32:
+                line.append('0x%X' % int(item))
+                count += 1
+            else:
+                print ' '.join(line)
+                count = 0
+                line = []
+                line.append('0x%X' % int(item))
+                count += 1
+
+    def GetHeader(self):
+        return self._header
+
+    def GetParent(self):
+        return self._parent
+
+    def GetSections(self):
+        return self._sections
+
+class EfiFfsHeader(BinaryItem):
+    ffs_state_map = {0x01:'EFI_FILE_HEADER_CONSTRUCTION',
+                     0x02:'EFI_FILE_HEADER_VALID',
+                     0x04:'EFI_FILE_DATA_VALID',
+                     0x08:'EFI_FILE_MARKED_FOR_UPDATE',
+                     0x10:'EFI_FILE_DELETED',
+                     0x20:'EFI_FILE_HEADER_INVALID'}
+
+    def GetSize(self):
+        return 24
+
+    def GetNameGuid(self):
+        list = self._arr.tolist()
+        return list2guid(list[0:16])
+
+    def GetType(self):
+        list = self._arr.tolist()
+        return int(list[18])
+
+
+    def GetTypeString(self):
+        value = self.GetType()
+        if value == 0x01:
+            return 'EFI_FV_FILETYPE_RAW'
+        if value == 0x02:
+            return 'EFI_FV_FILETYPE_FREEFORM'
+        if value == 0x03:
+            return 'EFI_FV_FILETYPE_SECURITY_CORE'
+        if value == 0x04:
+            return 'EFI_FV_FILETYPE_PEI_CORE'
+        if value == 0x05:
+            return 'EFI_FV_FILETYPE_DXE_CORE'
+        if value == 0x06:
+            return 'EFI_FV_FILETYPE_PEIM'
+        if value == 0x07:
+            return 'EFI_FV_FILETYPE_DRIVER'
+        if value == 0x08:
+            return 'EFI_FV_FILETYPE_COMBINED_PEIM_DRIVER'
+        if value == 0x09:
+            return 'EFI_FV_FILETYPE_APPLICATION'
+        if value == 0x0B:
+            return 'EFI_FV_FILETYPE_FIRMWARE_VOLUME_IMAGE'
+        if value == 0xc0:
+            return 'EFI_FV_FILETYPE_OEM_MIN'
+        if value == 0xdf:
+            return 'EFI_FV_FILETYPE_OEM_MAX'
+        if value == 0xe0:
+            return 'EFI_FV_FILETYPE_DEBUG_MIN'
+        if value == 0xef:
+            return 'EFI_FV_FILETYPE_DEBUG_MAX'
+        if value == 0xf0:
+            return 'EFI_FV_FILETYPE_FFS_PAD'
+        if value == 0xff:
+            return 'EFI_FV_FILETYPE_FFS_MAX'
+        return 'Unknown FFS Type'
+
+    def GetAttributes(self):
+        list = self._arr.tolist()
+        return int(list[19])
+
+    def GetFfsSize(self):
+        list = self._arr.tolist()
+        return list2int(list[20:23])
+
+    def GetState(self):
+        list = self._arr.tolist()
+        state = int(list[23])
+        polarity = self.GetParent().GetParent().GetHeader().GetErasePolarity()
+        if polarity:
+            state = (~state) & 0xFF
+        HighestBit = 0x80
+        while (HighestBit != 0) and (HighestBit & state) == 0:
+            HighestBit = HighestBit >> 1
+        return HighestBit
+
+    def GetStateString(self):
+        state = self.GetState()
+        if state in self.ffs_state_map.keys():
+            return self.ffs_state_map[state]
+        return 'Unknown Ffs State'
+
+    def Dump(self):
+        print "FFS name: ", self.GetNameGuid()
+        print "FFS type: ", self.GetType()
+        print "FFS attr: 0x%X" % self.GetAttributes()
+        print "FFS size: 0x%X" % self.GetFfsSize()
+        print "FFS state: 0x%X" % self.GetState()
+
+    def GetRawData(self):
+        return self._arr.tolist()
+
+
+class EfiSection(object):
+    EFI_SECTION_HEADER_SIZE = 4
+
+    def __init__(self, parent=None):
+        self._size   = 0
+        self._parent = parent
+        self._offset = 0
+        self._contents = array.array('B')
+
+    def Load(self, fd):
+        self._offset = align(fd.tell(), 4)
+
+        self._header = EfiSectionHeader.Read(fd, self)
+
+        if self._header.GetTypeString() == "EFI_SECTION_PE32":
+             pefile = pe.PEFile(self)
+             pefile.Load(fd, self.GetContentSize())
+
+        fd.seek(self._offset)
+        self._contents.fromfile(fd, self.GetContentSize())
+
+        # rebase file pointer to next section
+        index = self._offset + self.GetSize()
+        index = align(index, 4)
+        fd.seek(index)
+
+    def GetContentSize(self):
+        return self.GetSize() - self.EFI_SECTION_HEADER_SIZE
+
+    def GetContent(self):
+        return self._contents.tolist()
+
+    def GetSize(self):
+        return self._header.GetSectionSize()
+
+    def GetHeader(self):
+        return self._header
+
+    def GetSectionOffset(self):
+        return self._offset + self.EFI_SECTION_HEADER_SIZE
+
+class EfiSectionHeader(BinaryItem):
+    section_type_map = {0x01: 'EFI_SECTION_COMPRESSION',
+                        0x02: 'EFI_SECTION_GUID_DEFINED',
+                        0x10: 'EFI_SECTION_PE32',
+                        0x11: 'EFI_SECTION_PIC',
+                        0x12: 'EFI_SECTION_TE',
+                        0x13: 'EFI_SECTION_DXE_DEPEX',
+                        0x14: 'EFI_SECTION_VERSION',
+                        0x15: 'EFI_SECTION_USER_INTERFACE',
+                        0x16: 'EFI_SECTION_COMPATIBILITY16',
+                        0x17: 'EFI_SECTION_FIRMWARE_VOLUME_IMAGE',
+                        0x18: 'EFI_SECTION_FREEFORM_SUBTYPE_GUID',
+                        0x19: 'EFI_SECTION_RAW',
+                        0x1B: 'EFI_SECTION_PEI_DEPEX'}
+    def GetSize(self):
+        return 4
+
+    def GetSectionSize(self):
+        list = self._arr.tolist()
+        return list2int(list[0:3])
+
+    def GetType(self):
+        list = self._arr.tolist()
+        return int(list[3])
+
+    def GetTypeString(self):
+        type = self.GetType()
+        if type not in self.section_type_map.keys():
+            return 'Unknown Section Type'
+        return self.section_type_map[type]
+
+    def Dump(self):
+        print 'size = 0x%X' % self.GetSectionSize()
+        print 'type = 0x%X' % self.GetType()
+
+
+
+rMapEntry = re.compile('^(\w+)[ \(\w\)]* \(BaseAddress=([0-9a-fA-F]+), EntryPoint=([0-9a-fA-F]+), GUID=([0-9a-fA-F\-]+)')
+class EfiFvMapFile(object):
+    def __init__(self):
+        self._mapentries = {}
+
+    def Load(self, path):
+        if not os.path.exists(path):
+            return False
+
+        try:
+            file = open(path, 'r')
+            lines = file.readlines()
+            file.close()
+        except:
+            return False
+
+        for line in lines:
+            if line[0] != ' ':
+                # new entry
+                ret = rMapEntry.match(line)
+                if ret != None:
+                    name     = ret.groups()[0]
+                    baseaddr = int(ret.groups()[1], 16)
+                    entry    = int(ret.groups()[2], 16)
+                    guidstr  = '{' + ret.groups()[3] + '}'
+                    guid     = uuid.UUID(guidstr)
+                    self._mapentries[guid] = EfiFvMapFileEntry(name, baseaddr, entry, guid)
+        return True
+
+    def GetEntry(self, guid):
+        if guid in self._mapentries.keys():
+            return self._mapentries[guid]
+        return None
+
+class EfiFvMapFileEntry(object):
+    def __init__(self, name, baseaddr, entry, guid):
+        self._name     = name
+        self._baseaddr = baseaddr
+        self._entry    = entry
+        self._guid     = guid
+
+    def GetName(self):
+        return self._name
+
+    def GetBaseAddress(self):
+        return self._baseaddr
+
+    def GetEntryPoint(self):
+        return self._entry
+
+def list2guid(list):
+    val1 = list2int(list[0:4])
+    val2 = list2int(list[4:6])
+    val3 = list2int(list[6:8])
+    val4 = 0
+    for item in list[8:16]:
+        val4 = (val4 << 8) | int(item)
+
+    val  = val1 << 12 * 8 | val2 << 10 * 8 | val3 << 8 * 8 | val4
+    guid = uuid.UUID(int=val)
+    return guid
+
+def list2int(list):
+    val = 0
+    for index in range(len(list) - 1, -1, -1):
+        val = (val << 8) | int(list[index])
+    return val
+
+def align(value, alignment):
+    return (value + ((alignment - value) & (alignment - 1)))
+
+gInvalidGuid = uuid.UUID(int=0xffffffffffffffffffffffffffffffff)
+def isValidGuid(guid):
+    if guid == gInvalidGuid:
+        return False
+    return True
diff --git a/BaseTools/Scripts/PackageDocumentTools/plugins/EdkPlugins/basemodel/ini.py b/BaseTools/Scripts/PackageDocumentTools/plugins/EdkPlugins/basemodel/ini.py
new file mode 100644
index 0000000..515e7a4
--- /dev/null
+++ b/BaseTools/Scripts/PackageDocumentTools/plugins/EdkPlugins/basemodel/ini.py
@@ -0,0 +1,480 @@
+## @file
+#
+# Copyright (c) 2011 - 2018, Intel Corporation. All rights reserved.<BR>
+#
+# This program and the accompanying materials are licensed and made available
+# under the terms and conditions of the BSD License which accompanies this
+# distribution. The full text of the license may be found at
+# http://opensource.org/licenses/bsd-license.php
+#
+# THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+# WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+#
+
+from message import *
+import re
+import os
+
+section_re = re.compile(r'^\[([\w., "]+)\]')
+
+class BaseINIFile(object):
+    _objs = {}
+    def __new__(cls, *args, **kwargs):
+        """Maintain only a single instance of this object
+        @return: instance of this class
+
+        """
+        if len(args) == 0: return object.__new__(cls, *args, **kwargs)
+        filename = args[0]
+        parent   = None
+        if len(args) > 1:
+            parent = args[1]
+
+        key = os.path.normpath(filename)
+        if key not in cls._objs.keys():
+            cls._objs[key] = object.__new__(cls, *args, **kwargs)
+
+        if parent != None:
+            cls._objs[key].AddParent(parent)
+
+        return cls._objs[key]
+
+    def __init__(self, filename=None, parent=None):
+        self._lines    = []
+        self._sections = {}
+        self._filename = filename
+        self._globals  = []
+        self._isModify = True
+
+    def AddParent(self, parent):
+        if parent == None: return
+        if not hasattr(self, "_parents"):
+            self._parents = []
+
+        if parent in self._parents:
+            ErrorMsg("Duplicate parent is found for INI file %s" % self._filename)
+            return
+        self._parents.append(parent)
+
+    def GetFilename(self):
+        return os.path.normpath(self._filename)
+
+    def IsModified(self):
+        return self._isModify
+
+    def Modify(self, modify=True, obj=None):
+        if modify == self._isModify: return
+        self._isModify = modify
+        if modify:
+            for parent in self._parents:
+                parent.Modify(True, self)
+
+    def _ReadLines(self, filename):
+        #
+        # try to open file
+        #
+        if not os.path.exists(filename):
+            return False
+
+        try:
+            handle = open(filename, 'r')
+            self._lines  = handle.readlines()
+            handle.close()
+        except:
+            raise EdkException("Fail to open file %s" % filename)
+
+        return True
+
+    def GetSectionInstance(self, parent, name, isCombined=False):
+        return BaseINISection(parent, name, isCombined)
+
+    def GetSectionByName(self, name):
+        arr = []
+        for key in self._sections.keys():
+            if '.private' in key:
+                continue
+            for item in self._sections[key]:
+                if item.GetBaseName().lower().find(name.lower()) != -1:
+                    arr.append(item)
+        return arr
+
+    def GetSectionObjectsByName(self, name):
+        arr = []
+        sects = self.GetSectionByName(name)
+        for sect in sects:
+            for obj in sect.GetObjects():
+                arr.append(obj)
+        return arr
+
+    def Parse(self):
+        if not self._isModify: return True
+        if not self._ReadLines(self._filename): return False
+
+        sObjs    = []
+        inGlobal = True
+        # process line
+        for index in range(len(self._lines)):
+            templine = self._lines[index].strip()
+            # skip comments
+            if len(templine) == 0: continue
+            if re.match("^\[=*\]", templine) or re.match("^#", templine) or \
+               re.match("\*+/", templine):
+                continue
+
+            m = section_re.match(templine)
+            if m!= None: # found a section
+                inGlobal = False
+                # Finish the latest section first
+                if len(sObjs) != 0:
+                    for sObj in sObjs:
+                        sObj._end = index - 1
+                        if not sObj.Parse():
+                            ErrorMsg("Fail to parse section %s" % sObj.GetBaseName(),
+                                     self._filename,
+                                     sObj._start)
+
+                # start new section
+                sname_arr = m.groups()[0].split(',')
+                sObjs = []
+                for name in sname_arr:
+                    sObj = self.GetSectionInstance(self, name, (len(sname_arr) > 1))
+                    sObj._start = index
+                    sObjs.append(sObj)
+                    if not self._sections.has_key(name.lower()):
+                        self._sections[name.lower()] = [sObj]
+                    else:
+                        self._sections[name.lower()].append(sObj)
+            elif inGlobal:  # not start any section and find global object
+                gObj = BaseINIGlobalObject(self)
+                gObj._start = index
+                gObj.Parse()
+                self._globals.append(gObj)
+
+        # Finish the last section
+        if len(sObjs) != 0:
+            for sObj in sObjs:
+                sObj._end = index
+                if not sObj.Parse():
+                    ErrorMsg("Fail to parse section %s" % sObj.GetBaseName(),
+                             self._filename,
+                             sObj._start)
+
+        self._isModify = False
+        return True
+
+    def Destroy(self, parent):
+
+        # check referenced parent
+        if parent != None:
+            assert parent in self._parents, "when destory ini object, can not found parent reference!"
+            self._parents.remove(parent)
+
+        if len(self._parents) != 0: return
+
+        for sects in self._sections.values():
+            for sect in sects:
+                sect.Destroy()
+
+        # dereference from _objs array
+        assert self.GetFilename() in self._objs.keys(), "When destroy ini object, can not find obj reference!"
+        assert self in self._objs.values(), "When destroy ini object, can not find obj reference!"
+        del self._objs[self.GetFilename()]
+
+        # dereference self
+        self.Clear()
+
+    def GetDefine(self, name):
+        sects = self.GetSectionByName('Defines')
+        for sect in sects:
+            for obj in sect.GetObjects():
+                line = obj.GetLineByOffset(obj._start).split('#')[0].strip()
+                arr = line.split('=')
+                if arr[0].strip().lower() == name.strip().lower():
+                    return arr[1].strip()
+        return None
+
+    def Clear(self):
+        for sects in self._sections.values():
+            for sect in sects:
+                del sect
+        self._sections.clear()
+        for gObj in self._globals:
+            del gObj
+
+        del self._globals[:]
+        del self._lines[:]
+
+    def Reload(self):
+        self.Clear()
+        ret = self.Parse()
+        if ret:
+            self._isModify = False
+        return ret
+
+    def AddNewSection(self, sectName):
+        if sectName.lower() in self._sections.keys():
+            ErrorMsg('Section %s can not be created for conflict with existing section')
+            return None
+
+        sectionObj = self.GetSectionInstance(self, sectName)
+        sectionObj._start = len(self._lines)
+        sectionObj._end   = len(self._lines) + 1
+        self._lines.append('[%s]\n' % sectName)
+        self._lines.append('\n\n')
+        self._sections[sectName.lower()] = sectionObj
+        return sectionObj
+
+    def CopySectionsByName(self, oldDscObj, nameStr):
+        sects = oldDscObj.GetSectionByName(nameStr)
+        for sect in sects:
+            sectObj = self.AddNewSection(sect.GetName())
+            sectObj.Copy(sect)
+
+    def __str__(self):
+        return ''.join(self._lines)
+
+    ## Get file header's comment from basic INI file.
+    #  The file comments has two style:
+    #  1) #/** @file
+    #  2) ## @file
+    #
+    def GetFileHeader(self):
+        desc = []
+        lineArr  = self._lines
+        inHeader = False
+        for num in range(len(self._lines)):
+            line = lineArr[num].strip()
+            if not inHeader and (line.startswith("#/**") or line.startswith("##")) and \
+                line.find("@file") != -1:
+                inHeader = True
+                continue
+            if inHeader and (line.startswith("#**/") or line.startswith('##')):
+                inHeader = False
+                break
+            if inHeader:
+                prefixIndex = line.find('#')
+                if prefixIndex == -1:
+                    desc.append(line)
+                else:
+                    desc.append(line[prefixIndex + 1:])
+        return '<br>\n'.join(desc)
+
+class BaseINISection(object):
+    def __init__(self, parent, name, isCombined=False):
+        self._parent     = parent
+        self._name       = name
+        self._isCombined = isCombined
+        self._start      = 0
+        self._end        = 0
+        self._objs       = []
+
+    def __del__(self):
+        for obj in self._objs:
+            del obj
+        del self._objs[:]
+
+    def GetName(self):
+        return self._name
+
+    def GetObjects(self):
+        return self._objs
+
+    def GetParent(self):
+        return self._parent
+
+    def GetStartLinenumber(self):
+        return self._start
+
+    def GetEndLinenumber(self):
+        return self._end
+
+    def GetLine(self, linenumber):
+        return self._parent._lines[linenumber]
+
+    def GetFilename(self):
+        return self._parent.GetFilename()
+
+    def GetSectionINIObject(self, parent):
+        return BaseINISectionObject(parent)
+
+    def Parse(self):
+        # skip first line in section, it is used by section name
+        visit = self._start + 1
+        iniObj = None
+        while (visit <= self._end):
+            line = self.GetLine(visit).strip()
+            if re.match("^\[=*\]", line) or re.match("^#", line) or len(line) == 0:
+                visit += 1
+                continue
+            line = line.split('#')[0].strip()
+            if iniObj != None:
+                if line.endswith('}'):
+                    iniObj._end = visit - self._start
+                    if not iniObj.Parse():
+                        ErrorMsg("Fail to parse ini object",
+                                 self.GetFilename(),
+                                 iniObj.GetStartLinenumber())
+                    else:
+                        self._objs.append(iniObj)
+                    iniObj = None
+            else:
+                iniObj = self.GetSectionINIObject(self)
+                iniObj._start = visit - self._start
+                if not line.endswith('{'):
+                    iniObj._end = visit - self._start
+                    if not iniObj.Parse():
+                        ErrorMsg("Fail to parse ini object",
+                                 self.GetFilename(),
+                                 iniObj.GetStartLinenumber())
+                    else:
+                        self._objs.append(iniObj)
+                    iniObj = None
+            visit += 1
+        return True
+
+    def Destroy(self):
+        for obj in self._objs:
+            obj.Destroy()
+
+    def GetBaseName(self):
+        return self._name
+
+    def AddLine(self, line):
+        end = self.GetEndLinenumber()
+        self._parent._lines.insert(end, line)
+        self._end += 1
+
+    def Copy(self, sectObj):
+        index = sectObj.GetStartLinenumber() + 1
+        while index < sectObj.GetEndLinenumber():
+            line = sectObj.GetLine(index)
+            if not line.strip().startswith('#'):
+                self.AddLine(line)
+            index += 1
+
+    def AddObject(self, obj):
+        lines = obj.GenerateLines()
+        for line in lines:
+            self.AddLine(line)
+
+    def GetComment(self):
+        comments = []
+        start  = self._start - 1
+        bFound = False
+
+        while (start > 0):
+            line = self.GetLine(start).strip()
+            if len(line) == 0:
+                start -= 1
+                continue
+            if line.startswith('##'):
+                bFound = True
+                index = line.rfind('#')
+                if (index + 1) < len(line):
+                    comments.append(line[index + 1:])
+                break
+            if line.startswith('#'):
+                start -= 1
+                continue
+            break
+        if bFound:
+            end = start + 1
+            while (end < self._start):
+                line = self.GetLine(end).strip()
+                if len(line) == 0: break
+                if not line.startswith('#'): break
+                index = line.rfind('#')
+                if (index + 1) < len(line):
+                    comments.append(line[index + 1:])
+                end += 1
+        return comments
+
+class BaseINIGlobalObject(object):
+    def __init__(self, parent):
+        self._start = 0
+        self._end   = 0
+
+    def Parse(self):
+        return True
+
+    def __str__(self):
+        return parent._lines[self._start]
+
+    def __del__(self):
+        pass
+
+class BaseINISectionObject(object):
+    def __init__(self, parent):
+        self._start  = 0
+        self._end    = 0
+        self._parent = parent
+
+    def __del__(self):
+        self._parent = None
+
+    def GetParent(self):
+        return self._parent
+
+    def GetFilename(self):
+        return self.GetParent().GetFilename()
+
+    def GetPackageName(self):
+        return self.GetFilename()
+
+    def GetFileObj(self):
+        return self.GetParent().GetParent()
+
+    def GetStartLinenumber(self):
+        return self.GetParent()._start + self._start
+
+    def GetLineByOffset(self, offset):
+        sect_start = self._parent.GetStartLinenumber()
+        linenumber = sect_start + offset
+        return self._parent.GetLine(linenumber)
+
+    def GetLinenumberByOffset(self, offset):
+        return offset + self._parent.GetStartLinenumber()
+
+    def Parse(self):
+        return True
+
+    def Destroy(self):
+        pass
+
+    def __str__(self):
+        return self.GetLineByOffset(self._start).strip()
+
+    def GenerateLines(self):
+        return ['default setion object string\n']
+
+    def GetComment(self):
+        comments = []
+        start  = self.GetStartLinenumber() - 1
+        bFound = False
+
+        while (start > 0):
+            line = self.GetParent().GetLine(start).strip()
+            if len(line) == 0:
+                start -= 1
+                continue
+            if line.startswith('##'):
+                bFound = True
+                index = line.rfind('#')
+                if (index + 1) < len(line):
+                    comments.append(line[index + 1:])
+                break
+            if line.startswith('#'):
+                start -= 1
+                continue
+            break
+        if bFound:
+            end = start + 1
+            while (end <= self.GetStartLinenumber() - 1):
+                line = self.GetParent().GetLine(end).strip()
+                if len(line) == 0: break
+                if not line.startswith('#'): break
+                index = line.rfind('#')
+                if (index + 1) < len(line):
+                    comments.append(line[index + 1:])
+                end += 1
+        return comments
diff --git a/BaseTools/Scripts/PackageDocumentTools/plugins/EdkPlugins/basemodel/inidocview.py b/BaseTools/Scripts/PackageDocumentTools/plugins/EdkPlugins/basemodel/inidocview.py
new file mode 100644
index 0000000..f062f09
--- /dev/null
+++ b/BaseTools/Scripts/PackageDocumentTools/plugins/EdkPlugins/basemodel/inidocview.py
@@ -0,0 +1,23 @@
+## @file
+#
+# Copyright (c) 2011 - 2018, Intel Corporation. All rights reserved.<BR>
+#
+# This program and the accompanying materials are licensed and made available
+# under the terms and conditions of the BSD License which accompanies this
+# distribution. The full text of the license may be found at
+# http://opensource.org/licenses/bsd-license.php
+#
+# THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+# WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+#
+
+import core.editor
+
+class INIDoc(core.editor.EditorDocument):
+    def __init__(self):
+        core.editor.EditorDocument.__init__(self)
+        self._iniobj = None
+
+
+class INIView(core.editor.EditorView):
+    pass
diff --git a/BaseTools/Scripts/PackageDocumentTools/plugins/EdkPlugins/basemodel/message.py b/BaseTools/Scripts/PackageDocumentTools/plugins/EdkPlugins/basemodel/message.py
new file mode 100644
index 0000000..5cf2028
--- /dev/null
+++ b/BaseTools/Scripts/PackageDocumentTools/plugins/EdkPlugins/basemodel/message.py
@@ -0,0 +1,52 @@
+## @file
+#
+# Copyright (c) 2011 - 2018, Intel Corporation. All rights reserved.<BR>
+#
+# This program and the accompanying materials are licensed and made available
+# under the terms and conditions of the BSD License which accompanies this
+# distribution. The full text of the license may be found at
+# http://opensource.org/licenses/bsd-license.php
+#
+# THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+# WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+#
+
+def GetEdkLogger():
+    import logging
+    return logging.getLogger('edk')
+
+class EdkException(Exception):
+    def __init__(self, message, fName=None, fNo=None):
+        self._message = message
+        ErrorMsg(message, fName, fNo)
+
+    def GetMessage(self):
+        return '[EDK Failure]: %s' %self._message
+
+def ErrorMsg(mess, fName=None, fNo=None):
+    GetEdkLogger().error(NormalMessage('#ERR#', mess, fName, fNo))
+
+def LogMsg(mess, fName=None, fNo=None):
+    GetEdkLogger().info(NormalMessage('@LOG@', mess, fName, fNo))
+
+def WarnMsg(mess, fName=None, fNo=None):
+    GetEdkLogger().warning(NormalMessage('!WAR!', mess, fName, fNo))
+
+def NormalMessage(type, mess, fName=None, fNo=None):
+    strMsg = type
+
+    if fName != None:
+        strMsg += ' %s' % fName.replace('/', '\\')
+        if fNo != None:
+            strMsg += '(%d):' % fNo
+        else:
+            strMsg += ' :'
+
+    if fName == None and fNo == None:
+        strMsg += ' '
+    strMsg += mess
+
+    return strMsg
+
+
+
diff --git a/BaseTools/Scripts/PackageDocumentTools/plugins/EdkPlugins/edk2/__init__.py b/BaseTools/Scripts/PackageDocumentTools/plugins/EdkPlugins/edk2/__init__.py
new file mode 100644
index 0000000..3e4ee53
--- /dev/null
+++ b/BaseTools/Scripts/PackageDocumentTools/plugins/EdkPlugins/edk2/__init__.py
@@ -0,0 +1,12 @@
+## @file
+#
+# Copyright (c) 2011 - 2018, Intel Corporation. All rights reserved.<BR>
+#
+# This program and the accompanying materials are licensed and made available
+# under the terms and conditions of the BSD License which accompanies this
+# distribution. The full text of the license may be found at
+# http://opensource.org/licenses/bsd-license.php
+#
+# THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+# WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+#
diff --git a/BaseTools/Scripts/PackageDocumentTools/plugins/EdkPlugins/edk2/model/__init__.py b/BaseTools/Scripts/PackageDocumentTools/plugins/EdkPlugins/edk2/model/__init__.py
new file mode 100644
index 0000000..3e4ee53
--- /dev/null
+++ b/BaseTools/Scripts/PackageDocumentTools/plugins/EdkPlugins/edk2/model/__init__.py
@@ -0,0 +1,12 @@
+## @file
+#
+# Copyright (c) 2011 - 2018, Intel Corporation. All rights reserved.<BR>
+#
+# This program and the accompanying materials are licensed and made available
+# under the terms and conditions of the BSD License which accompanies this
+# distribution. The full text of the license may be found at
+# http://opensource.org/licenses/bsd-license.php
+#
+# THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+# WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+#
diff --git a/BaseTools/Scripts/PackageDocumentTools/plugins/EdkPlugins/edk2/model/baseobject.py b/BaseTools/Scripts/PackageDocumentTools/plugins/EdkPlugins/edk2/model/baseobject.py
new file mode 100644
index 0000000..05fa252
--- /dev/null
+++ b/BaseTools/Scripts/PackageDocumentTools/plugins/EdkPlugins/edk2/model/baseobject.py
@@ -0,0 +1,934 @@
+## @file
+#
+# Copyright (c) 2011 - 2018, Intel Corporation. All rights reserved.<BR>
+#
+# This program and the accompanying materials are licensed and made available
+# under the terms and conditions of the BSD License which accompanies this
+# distribution. The full text of the license may be found at
+# http://opensource.org/licenses/bsd-license.php
+#
+# THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+# WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+
+import plugins.EdkPlugins.basemodel.ini as ini
+import plugins.EdkPlugins.edk2.model.dsc as dsc
+import plugins.EdkPlugins.edk2.model.inf as inf
+import plugins.EdkPlugins.edk2.model.dec as dec
+import os
+from plugins.EdkPlugins.basemodel.message import *
+
+class SurfaceObject(object):
+    _objs = {}
+
+    def __new__(cls, *args, **kwargs):
+        """Maintain only a single instance of this object
+        @return: instance of this class
+
+        """
+        obj = object.__new__(cls, *args, **kwargs)
+        if not cls._objs.has_key("None"):
+            cls._objs["None"] = []
+        cls._objs["None"].append(obj)
+
+        return obj
+
+    def __init__(self, parent, workspace):
+        self._parent    = parent
+        self._fileObj   = None
+        self._workspace = workspace
+        self._isModify  = False
+        self._modifiedObjs = []
+
+    def __del__(self):
+        pass
+
+    def Destroy(self):
+        key = self.GetRelativeFilename()
+        self.GetFileObj().Destroy(self)
+        del self._fileObj
+        # dereference self from _objs arrary
+        assert self._objs.has_key(key), "when destory, object is not in obj list"
+        assert self in self._objs[key], "when destory, object is not in obj list"
+        self._objs[key].remove(self)
+        if len(self._objs[key]) == 0:
+            del self._objs[key]
+
+    def GetParent(self):
+        return self._parent
+
+    def GetWorkspace(self):
+        return self._workspace
+
+    def GetFileObjectClass(self):
+        return ini.BaseINIFile
+
+    def GetFilename(self):
+        return self.GetFileObj().GetFilename()
+
+    def GetFileObj(self):
+        return self._fileObj
+
+    def GetRelativeFilename(self):
+        fullPath = self.GetFilename()
+        return fullPath[len(self._workspace) + 1:]
+
+    def Load(self, relativePath):
+        # if has been loaded, directly return
+        if self._fileObj != None: return True
+
+        relativePath = os.path.normpath(relativePath)
+        fullPath = os.path.join(self._workspace, relativePath)
+        fullPath = os.path.normpath(fullPath)
+
+        if not os.path.exists(fullPath):
+            ErrorMsg("file does not exist!", fullPath)
+            return False
+
+        self._fileObj = self.GetFileObjectClass()(fullPath, self)
+
+        if not self._fileObj.Parse():
+            ErrorMsg("Fail to parse file!", fullPath)
+            return False
+
+        # remove self from None list to list with filename as key
+        cls = self.__class__
+        if self not in cls._objs["None"]:
+            ErrorMsg("Sufrace object does not be create into None list")
+        cls._objs["None"].remove(self)
+        if not cls._objs.has_key(relativePath):
+            cls._objs[relativePath] = []
+        cls._objs[relativePath].append(self)
+
+        return True
+
+    def Reload(self, force=False):
+        ret = True
+        # whether require must be update
+        if force:
+            ret = self.GetFileObj().Reload(True)
+        else:
+            if self.IsModified():
+                if self.GetFileObj().IsModified():
+                    ret = self.GetFileObj().Reload()
+        return ret
+
+    def Modify(self, modify=True, modifiedObj=None):
+        if modify:
+            #LogMsg("%s is modified, modified object is %s" % (self.GetFilename(), modifiedObj))
+            if issubclass(modifiedObj.__class__, ini.BaseINIFile) and self._isModify:
+                return
+            self._isModify = modify
+            self.GetParent().Modify(modify, self)
+        else:
+            self._isModify = modify
+
+    def IsModified(self):
+        return self._isModify
+
+    def GetModifiedObjs(self):
+        return self._modifiedObjs
+
+    def FilterObjsByArch(self, objs, arch):
+        arr = []
+        for obj in objs:
+            if obj.GetArch().lower() == 'common':
+                arr.append(obj)
+                continue
+            if obj.GetArch().lower() == arch.lower():
+                arr.append(obj)
+                continue
+        return arr
+
+class Platform(SurfaceObject):
+    def __init__(self, parent, workspace):
+        SurfaceObject.__init__(self, parent, workspace)
+        self._modules    = []
+        self._packages   = []
+
+    def Destroy(self):
+        for module in self._modules:
+            module.Destroy()
+        del self._modules[:]
+
+        del self._packages[:]
+        SurfaceObject.Destroy(self)
+
+    def GetName(self):
+        return self.GetFileObj().GetDefine("PLATFORM_NAME")
+
+    def GetFileObjectClass(self):
+        return dsc.DSCFile
+
+    def GetModuleCount(self):
+        if self.GetFileObj() == None:
+            ErrorMsg("Fail to get module count because DSC file has not been load!")
+
+        return len(self.GetFileObj().GetComponents())
+
+    def GetSupportArchs(self):
+        return self.GetFileObj().GetDefine("SUPPORTED_ARCHITECTURES").strip().split('#')[0].split('|')
+
+    def LoadModules(self, precallback=None, postcallback=None):
+        for obj in self.GetFileObj().GetComponents():
+            mFilename = obj.GetFilename()
+            if precallback != None:
+                precallback(self, mFilename)
+            arch = obj.GetArch()
+            if arch.lower() == 'common':
+                archarr = self.GetSupportArchs()
+            else:
+                archarr = [arch]
+            for arch in archarr:
+                module = Module(self, self.GetWorkspace())
+                if module.Load(mFilename, arch, obj.GetOveridePcds(), obj.GetOverideLibs()):
+                    self._modules.append(module)
+                    if postcallback != None:
+                        postcallback(self, module)
+                else:
+                    del module
+                    ErrorMsg("Fail to load module %s" % mFilename)
+
+    def GetModules(self):
+        return self._modules
+
+    def GetLibraryPath(self, classname, arch, type):
+        objs = self.GetFileObj().GetSectionObjectsByName("libraryclasses")
+
+        for obj in objs:
+            if classname.lower() != obj.GetClass().lower():
+                continue
+            if obj.GetArch().lower() != 'common' and \
+               obj.GetArch().lower() != arch.lower():
+                continue
+
+            if obj.GetModuleType().lower() != 'common' and \
+               obj.GetModuleType().lower() != type.lower():
+                continue
+
+            return obj.GetInstance()
+
+        ErrorMsg("Fail to get library class %s [%s][%s] from platform %s" % (classname, arch, type, self.GetFilename()))
+        return None
+
+    def GetPackage(self, path):
+        package = self.GetParent().GetPackage(path)
+        if package not in self._packages:
+            self._packages.append(package)
+        return package
+
+    def GetPcdBuildObjs(self, name, arch=None):
+        arr = []
+        objs = self.GetFileObj().GetSectionObjectsByName('pcds')
+        for obj in objs:
+            if obj.GetPcdName().lower() == name.lower():
+                arr.append(obj)
+        if arch != None:
+            arr = self.FilterObjsByArch(arr, arch)
+        return arr
+
+    def Reload(self, callback=None):
+        # do not care force paramter for platform object
+        isFileChanged = self.GetFileObj().IsModified()
+        ret = SurfaceObject.Reload(self, False)
+        if not ret: return False
+        if isFileChanged:
+            # destroy all modules and reload them again
+            for obj in self._modules:
+                obj.Destroy()
+            del self._modules[:]
+            del self._packages[:]
+            self.LoadModules(callback)
+        else:
+            for obj in self._modules:
+                callback(self, obj.GetFilename())
+                obj.Reload()
+
+        self.Modify(False)
+        return True
+
+    def Modify(self, modify=True, modifiedObj=None):
+        if modify:
+            #LogMsg("%s is modified, modified object is %s" % (self.GetFilename(), modifiedObj))
+            if issubclass(modifiedObj.__class__, ini.BaseINIFile) and self._isModify:
+                return
+            self._isModify = modify
+            self.GetParent().Modify(modify, self)
+        else:
+            if self.GetFileObj().IsModified():
+                return
+            for obj in self._modules:
+                if obj.IsModified():
+                    return
+
+            self._isModify = modify
+            self.GetParent().Modify(modify, self)
+
+    def GetModuleObject(self, relativePath, arch):
+        path = os.path.normpath(relativePath)
+        for obj in self._modules:
+            if obj.GetRelativeFilename() == path:
+                if arch.lower() == 'common':
+                    return obj
+                if obj.GetArch() == arch:
+                    return obj
+        return None
+
+    def GenerateFullReferenceDsc(self):
+        oldDsc = self.GetFileObj()
+        newDsc = dsc.DSCFile()
+        newDsc.CopySectionsByName(oldDsc, 'defines')
+        newDsc.CopySectionsByName(oldDsc, 'SkuIds')
+
+        #
+        # Dynamic common section should also be copied
+        #
+        newDsc.CopySectionsByName(oldDsc, 'PcdsDynamicDefault')
+        newDsc.CopySectionsByName(oldDsc, 'PcdsDynamicHii')
+        newDsc.CopySectionsByName(oldDsc, 'PcdsDynamicVpd')
+        newDsc.CopySectionsByName(oldDsc, 'PcdsDynamicEx')
+
+        sects = oldDsc.GetSectionByName('Components')
+        for oldSect in sects:
+            newSect = newDsc.AddNewSection(oldSect.GetName())
+            for oldComObj in oldSect.GetObjects():
+                module = self.GetModuleObject(oldComObj.GetFilename(), oldSect.GetArch())
+                if module == None: continue
+
+                newComObj = dsc.DSCComponentObject(newSect)
+                newComObj.SetFilename(oldComObj.GetFilename())
+
+                # add all library instance for override section
+                libdict = module.GetLibraries()
+                for libclass in libdict.keys():
+                    if libdict[libclass] != None:
+                        newComObj.AddOverideLib(libclass, libdict[libclass].GetRelativeFilename().replace('\\', '/'))
+
+                # add all pcds for override section
+                pcddict = module.GetPcds()
+                for pcd in pcddict.values():
+                    buildPcd   = pcd.GetBuildObj()
+                    buildType  = buildPcd.GetPcdType()
+                    buildValue = None
+                    if buildType.lower() == 'pcdsdynamichii' or \
+                       buildType.lower() == 'pcdsdynamicvpd' or \
+                       buildType.lower() == 'pcdsdynamicdefault':
+                        buildType = 'PcdsDynamic'
+                    if buildType != 'PcdsDynamic':
+                        buildValue = buildPcd.GetPcdValue()
+                    newComObj.AddOveridePcd(buildPcd.GetPcdName(),
+                                            buildType,
+                                            buildValue)
+                newSect.AddObject(newComObj)
+        return newDsc
+
+class Module(SurfaceObject):
+    def __init__(self, parent, workspace):
+        SurfaceObject.__init__(self, parent, workspace)
+        self._arch        = 'common'
+        self._parent      = parent
+        self._overidePcds = {}
+        self._overideLibs = {}
+        self._libs        = {}
+        self._pcds        = {}
+        self._ppis        = []
+        self._protocols   = []
+        self._depexs      = []
+        self._guids       = []
+        self._packages    = []
+
+    def Destroy(self):
+        for lib in self._libs.values():
+            if lib != None:
+                lib.Destroy()
+        self._libs.clear()
+
+        for pcd in self._pcds.values():
+            pcd.Destroy()
+        self._pcds.clear()
+
+        for ppi in self._ppis:
+            ppi.DeRef(self)
+        del self._ppis[:]
+
+        for protocol in self._protocols:
+            if protocol != None:
+                protocol.DeRef(self)
+        del self._protocols[:]
+
+        for guid in self._guids:
+            if guid != None:
+                guid.DeRef(self)
+        del self._guids[:]
+
+        del self._packages[:]
+        del self._depexs[:]
+        SurfaceObject.Destroy(self)
+
+    def GetFileObjectClass(self):
+        return inf.INFFile
+
+    def GetLibraries(self):
+        return self._libs
+
+    def Load(self, filename, arch='common', overidePcds=None, overideLibs=None):
+        if not SurfaceObject.Load(self, filename):
+            return False
+
+        self._arch = arch
+        if overidePcds != None:
+            self._overideLibs = overideLibs
+        if overideLibs != None:
+            self._overidePcds = overidePcds
+
+        self._SearchLibraries()
+        self._SearchPackage()
+        self._SearchSurfaceItems()
+        return True
+
+    def GetArch(self):
+        return self._arch
+
+    def GetModuleName(self):
+        return self.GetFileObj().GetDefine("BASE_NAME")
+
+    def GetModuleType(self):
+        return self.GetFileObj().GetDefine("MODULE_TYPE")
+
+    def GetPlatform(self):
+        return self.GetParent()
+
+    def GetModuleObj(self):
+        return self
+
+    def GetPcds(self):
+        pcds = self._pcds.copy()
+        for lib in self._libs.values():
+            if lib == None: continue
+            for name in lib._pcds.keys():
+                pcds[name] = lib._pcds[name]
+        return pcds
+
+    def GetPpis(self):
+        ppis = []
+        ppis += self._ppis
+        for lib in self._libs.values():
+            if lib == None: continue
+            ppis += lib._ppis
+        return ppis
+
+    def GetProtocols(self):
+        pros = []
+        pros = self._protocols
+        for lib in self._libs.values():
+            if lib == None: continue
+            pros += lib._protocols
+        return pros
+
+    def GetGuids(self):
+        guids = []
+        guids += self._guids
+        for lib in self._libs.values():
+            if lib == None: continue
+            guids += lib._guids
+        return guids
+
+    def GetDepexs(self):
+        deps = []
+        deps += self._depexs
+        for lib in self._libs.values():
+            if lib == None: continue
+            deps += lib._depexs
+        return deps
+
+    def IsLibrary(self):
+        return self.GetFileObj().GetDefine("LIBRARY_CLASS") != None
+
+    def GetLibraryInstance(self, classname, arch, type):
+        if classname not in self._libs.keys():
+            # find in overide lib firstly
+            if classname in self._overideLibs.keys():
+                self._libs[classname] = Library(self, self.GetWorkspace())
+                self._libs[classname].Load(self._overideLibs[classname])
+                return self._libs[classname]
+
+            parent = self.GetParent()
+            if issubclass(parent.__class__, Platform):
+                path = parent.GetLibraryPath(classname, arch, type)
+                if path == None:
+                    ErrorMsg('Fail to get library instance for %s' % classname, self.GetFilename())
+                    return None
+                self._libs[classname] = Library(self, self.GetWorkspace())
+                if not self._libs[classname].Load(path, self.GetArch()):
+                    self._libs[classname] = None
+            else:
+                self._libs[classname] = parent.GetLibraryInstance(classname, arch, type)
+        return self._libs[classname]
+
+    def GetSourceObjs(self):
+        return self.GetFileObj().GetSectionObjectsByName('source')
+
+    def _SearchLibraries(self):
+        objs = self.GetFileObj().GetSectionObjectsByName('libraryclasses')
+        arch = self.GetArch()
+        type = self.GetModuleType()
+        for obj in objs:
+            if obj.GetArch().lower() != 'common' and \
+               obj.GetArch().lower() not in self.GetPlatform().GetSupportArchs():
+                continue
+            classname = obj.GetClass()
+            instance = self.GetLibraryInstance(classname, arch, type)
+            if not self.IsLibrary() and instance != None:
+                instance._isInherit = False
+
+            if classname not in self._libs.keys():
+                self._libs[classname] = instance
+
+    def _SearchSurfaceItems(self):
+        # get surface item from self's inf
+        pcds  = []
+        ppis  = []
+        pros  = []
+        deps  = []
+        guids = []
+        if self.GetFileObj() != None:
+            pcds = self.FilterObjsByArch(self.GetFileObj().GetSectionObjectsByName('pcd'),
+                                          self.GetArch())
+            for pcd in pcds:
+                if pcd.GetPcdName() not in self._pcds.keys():
+                    pcdItem = PcdItem(pcd.GetPcdName(), self, pcd)
+                    self._pcds[pcd.GetPcdName()] = ModulePcd(self,
+                                                             pcd.GetPcdName(),
+                                                             pcd,
+                                                             pcdItem)
+
+            ppis += self.FilterObjsByArch(self.GetFileObj().GetSectionObjectsByName('ppis'),
+                                          self.GetArch())
+
+            for ppi in ppis:
+                item = PpiItem(ppi.GetName(), self, ppi)
+                if item not in self._ppis:
+                    self._ppis.append(item)
+
+            pros += self.FilterObjsByArch(self.GetFileObj().GetSectionObjectsByName('protocols'),
+                                          self.GetArch())
+
+            for pro in pros:
+                item = ProtocolItem(pro.GetName(), self, pro)
+                if item not in self._protocols:
+                    self._protocols.append(item)
+
+            deps += self.FilterObjsByArch(self.GetFileObj().GetSectionObjectsByName('depex'),
+                                          self.GetArch())
+            for dep in deps:
+                item = DepexItem(self, dep)
+                self._depexs.append(item)
+
+            guids += self.FilterObjsByArch(self.GetFileObj().GetSectionObjectsByName('guids'),
+                                          self.GetArch())
+            for guid in guids:
+                item = GuidItem(guid.GetName(), self, guid)
+                if item not in self._guids:
+                    self._guids.append(item)
+
+    def _SearchPackage(self):
+        objs = self.GetFileObj().GetSectionObjectsByName('packages')
+        for obj in objs:
+            package = self.GetPlatform().GetPackage(obj.GetPath())
+            if package != None:
+                self._packages.append(package)
+
+    def GetPackages(self):
+        return self._packages
+
+    def GetPcdObjects(self):
+        if self.GetFileObj() == None:
+            return []
+
+        return self.GetFileObj().GetSectionObjectsByName('pcd')
+
+    def GetLibraryClassHeaderFilePath(self):
+        lcname = self.GetFileObj().GetProduceLibraryClass()
+        if lcname == None: return None
+
+        pkgs = self.GetPackages()
+        for package in pkgs:
+            path = package.GetLibraryClassHeaderPathByName(lcname)
+            if path != None:
+                return os.path.realpath(os.path.join(package.GetFileObj().GetPackageRootPath(), path))
+        return None
+
+    def Reload(self, force=False, callback=None):
+        if callback != None:
+            callback(self, "Starting reload...")
+
+        ret = SurfaceObject.Reload(self, force)
+        if not ret: return False
+
+        if not force and not self.IsModified():
+            return True
+
+        for lib in self._libs.values():
+            if lib != None:
+                lib.Destroy()
+        self._libs.clear()
+
+        for pcd in self._pcds.values():
+            pcd.Destroy()
+        self._pcds.clear()
+
+        for ppi in self._ppis:
+            ppi.DeRef(self)
+        del self._ppis[:]
+
+        for protocol in self._protocols:
+            protocol.DeRef(self)
+        del self._protocols[:]
+
+        for guid in self._guids:
+            guid.DeRef(self)
+        del self._guids[:]
+
+        del self._packages[:]
+        del self._depexs[:]
+
+        if callback != None:
+            callback(self, "Searching libraries...")
+        self._SearchLibraries()
+        if callback != None:
+            callback(self, "Searching packages...")
+        self._SearchPackage()
+        if callback != None:
+            callback(self, "Searching surface items...")
+        self._SearchSurfaceItems()
+
+        self.Modify(False)
+        return True
+
+    def Modify(self, modify=True, modifiedObj=None):
+        if modify:
+            #LogMsg("%s is modified, modified object is %s" % (self.GetFilename(), modifiedObj))
+            if issubclass(modifiedObj.__class__, ini.BaseINIFile) and self._isModify:
+                return
+            self._isModify = modify
+            self.GetParent().Modify(modify, self)
+        else:
+            if self.GetFileObj().IsModified():
+                return
+
+            self._isModify = modify
+            self.GetParent().Modify(modify, self)
+
+class Library(Module):
+    def __init__(self, parent, workspace):
+        Module.__init__(self, parent, workspace)
+        self._isInherit = True
+
+    def IsInherit(self):
+        return self._isInherit
+
+    def GetModuleType(self):
+        return self.GetParent().GetModuleType()
+
+    def GetPlatform(self):
+        return self.GetParent().GetParent()
+
+    def GetModuleObj(self):
+        return self.GetParent()
+
+    def GetArch(self):
+        return self.GetParent().GetArch()
+
+    def Destroy(self):
+        self._libs.clear()
+        self._pcds.clear()
+        SurfaceObject.Destroy(self)
+
+class Package(SurfaceObject):
+    def __init__(self, parent, workspace):
+        SurfaceObject.__init__(self, parent, workspace)
+        self._pcds      = {}
+        self._guids     = {}
+        self._protocols = {}
+        self._ppis      = {}
+
+    def GetPcds(self):
+        return self._pcds
+
+    def GetPpis(self):
+        return self._ppis.values()
+
+    def GetProtocols(self):
+        return self._protocols.values()
+
+    def GetGuids(self):
+        return self._guids.values()
+
+    def Destroy(self):
+        for pcd in self._pcds.values():
+            if pcd != None:
+                pcd.Destroy()
+        for guid in self._guids.values():
+            if guid != None:
+                guid.Destroy()
+        for protocol in self._protocols.values():
+            if protocol != None:
+                protocol.Destroy()
+        for ppi in self._ppis.values():
+            if ppi != None:
+                ppi.Destroy()
+        self._pcds.clear()
+        self._guids.clear()
+        self._protocols.clear()
+        self._ppis.clear()
+        self._pcds.clear()
+        SurfaceObject.Destroy(self)
+
+    def Load(self, relativePath):
+        ret = SurfaceObject.Load(self, relativePath)
+        if not ret: return False
+        pcds = self.GetFileObj().GetSectionObjectsByName('pcds')
+        for pcd in pcds:
+            if pcd.GetPcdName() in self._pcds.keys():
+                if self._pcds[pcd.GetPcdName()] != None:
+                    self._pcds[pcd.GetPcdName()].AddDecObj(pcd)
+            else:
+                self._pcds[pcd.GetPcdName()] = PcdItem(pcd.GetPcdName(), self, pcd)
+
+        guids = self.GetFileObj().GetSectionObjectsByName('guids')
+        for guid in guids:
+            if guid.GetName() not in self._guids.keys():
+                self._guids[guid.GetName()] = GuidItem(guid.GetName(), self, guid)
+            else:
+                WarnMsg("Duplicate definition for %s" % guid.GetName())
+
+        ppis = self.GetFileObj().GetSectionObjectsByName('ppis')
+        for ppi in ppis:
+            if ppi.GetName() not in self._ppis.keys():
+                self._ppis[ppi.GetName()] = PpiItem(ppi.GetName(), self, ppi)
+            else:
+                WarnMsg("Duplicate definition for %s" % ppi.GetName())
+
+        protocols = self.GetFileObj().GetSectionObjectsByName('protocols')
+        for protocol in protocols:
+            if protocol.GetName() not in self._protocols.keys():
+                self._protocols[protocol.GetName()] = ProtocolItem(protocol.GetName(), self, protocol)
+            else:
+                WarnMsg("Duplicate definition for %s" % protocol.GetName())
+
+        return True
+
+    def GetFileObjectClass(self):
+        return dec.DECFile
+
+    def GetName(self):
+        return self.GetFileObj().GetDefine("PACKAGE_NAME")
+
+    def GetPcdDefineObjs(self, name=None):
+        arr = []
+        objs = self.GetFileObj().GetSectionObjectsByName('pcds')
+        if name == None: return objs
+
+        for obj in objs:
+            if obj.GetPcdName().lower() == name.lower():
+                arr.append(obj)
+        return arr
+
+    def GetLibraryClassObjs(self):
+        return self.GetFileObj().GetSectionObjectsByName('libraryclasses')
+
+    def Modify(self, modify=True, modifiedObj=None):
+        if modify:
+            self._isModify = modify
+            self.GetParent().Modify(modify, self)
+        else:
+            if self.GetFileObj().IsModified():
+                return
+
+            self._isModify = modify
+            self.GetParent().Modify(modify, self)
+
+    def GetLibraryClassHeaderPathByName(self, clsname):
+        objs = self.GetLibraryClassObjs()
+        for obj in objs:
+            if obj.GetClassName() == clsname:
+                return obj.GetHeaderFile()
+        return None
+
+class DepexItem(object):
+    def __init__(self, parent, infObj):
+        self._parent = parent
+        self._infObj = infObj
+
+    def GetDepexString(self):
+        return str(self._infObj)
+
+    def GetInfObject(self):
+        return self._infObj
+
+class ModulePcd(object):
+    _type_mapping = {'FeaturePcd': 'PcdsFeatureFlag',
+                     'FixedPcd': 'PcdsFixedAtBuild',
+                     'PatchPcd': 'PcdsPatchableInModule'}
+
+    def __init__(self, parent, name, infObj, pcdItem):
+        assert issubclass(parent.__class__, Module), "Module's PCD's parent must be module!"
+        assert pcdItem != None, 'Pcd %s does not in some package!' % name
+
+        self._name          = name
+        self._parent        = parent
+        self._pcdItem       = pcdItem
+        self._infObj        = infObj
+
+    def GetName(self):
+        return self._name
+
+    def GetParent(self):
+        return self._name
+
+    def GetArch(self):
+        return self._parent.GetArch()
+
+    def Destroy(self):
+        self._pcdItem.DeRef(self._parent)
+        self._infObj = None
+
+    def GetBuildObj(self):
+        platformInfos = self._parent.GetPlatform().GetPcdBuildObjs(self._name, self.GetArch())
+        modulePcdType = self._infObj.GetPcdType()
+
+        # if platform do not gives pcd's value, get default value from package
+        if len(platformInfos) == 0:
+            if modulePcdType.lower() == 'pcd':
+                return self._pcdItem.GetDecObject()
+            else:
+                for obj in self._pcdItem.GetDecObjects():
+                    if modulePcdType not in self._type_mapping.keys():
+                        ErrorMsg("Invalid PCD type %s" % modulePcdType)
+                        return None
+
+                    if self._type_mapping[modulePcdType] == obj.GetPcdType():
+                        return obj
+                ErrorMsg ('Module PCD type %s does not in valied range [%s] in package!' % \
+                          (modulePcdType))
+        else:
+            if modulePcdType.lower() == 'pcd':
+                if len(platformInfos) > 1:
+                    WarnMsg("Find more than one value for PCD %s in platform %s" % \
+                            (self._name, self._parent.GetPlatform().GetFilename()))
+                return platformInfos[0]
+            else:
+                for obj in platformInfos:
+                    if modulePcdType not in self._type_mapping.keys():
+                        ErrorMsg("Invalid PCD type %s" % modulePcdType)
+                        return None
+
+                    if self._type_mapping[modulePcdType] == obj.GetPcdType():
+                        return obj
+
+                ErrorMsg('Can not find value for pcd %s in pcd type %s' % \
+                         (self._name, modulePcdType))
+        return None
+
+
+class SurfaceItem(object):
+    _objs = {}
+
+    def __new__(cls, *args, **kwargs):
+        """Maintain only a single instance of this object
+        @return: instance of this class
+
+        """
+        name    = args[0]
+        parent  = args[1]
+        fileObj = args[2]
+        if issubclass(parent.__class__, Package):
+            if name in cls._objs.keys():
+                ErrorMsg("%s item is duplicated defined in packages: %s and %s" %
+                         (name, parent.GetFilename(), cls._objs[name].GetParent().GetFilename()))
+                return None
+            obj = object.__new__(cls, *args, **kwargs)
+            cls._objs[name] = obj
+            return obj
+        elif issubclass(parent.__class__, Module):
+            if name not in cls._objs.keys():
+                ErrorMsg("%s item does not defined in any package! It is used by module %s" % \
+                         (name, parent.GetFilename()))
+                return None
+            return cls._objs[name]
+
+        return None
+
+
+    def __init__(self, name, parent, fileObj):
+        if issubclass(parent.__class__, Package):
+            self._name    = name
+            self._parent  = parent
+            self._decObj  = [fileObj]
+            self._refMods = {}
+        else:
+            self.RefModule(parent, fileObj)
+
+    @classmethod
+    def GetObjectDict(cls):
+        return cls._objs
+
+    def GetParent(self):
+        return self._parent
+
+    def GetReference(self):
+        return self._refMods
+
+    def RefModule(self, mObj, infObj):
+        if mObj in self._refMods.keys():
+            return
+        self._refMods[mObj] = infObj
+
+    def DeRef(self, mObj):
+        if mObj not in self._refMods.keys():
+            WarnMsg("%s is not referenced by module %s" % (self._name, mObj.GetFilename()))
+            return
+        del self._refMods[mObj]
+
+    def Destroy(self):
+        self._refMods.clear()
+        cls = self.__class__
+        del cls._objs[self._name]
+
+    def GetName(self):
+        return self._name
+
+    def GetDecObject(self):
+        return self._decObj[0]
+
+    def GetDecObjects(self):
+        return self._decObj
+
+class PcdItem(SurfaceItem):
+    def AddDecObj(self, fileObj):
+        for decObj in self._decObj:
+            if decObj.GetFilename() != fileObj.GetFilename():
+                ErrorMsg("Pcd %s defined in more than one packages : %s and %s" % \
+                         (self._name, decObj.GetFilename(), fileObj.GetFilename()))
+                return
+            if decObj.GetPcdType() == fileObj.GetPcdType() and \
+               decObj.GetArch().lower() == fileObj.GetArch():
+                ErrorMsg("Pcd %s is duplicated defined in pcd type %s in package %s" % \
+                         (self._name, decObj.GetPcdType(), decObj.GetFilename()))
+                return
+        self._decObj.append(fileObj)
+
+    def GetValidPcdType(self):
+        types = []
+        for obj in self._decObj:
+            if obj.GetPcdType() not in types:
+                types += obj.GetPcdType()
+        return types
+
+class GuidItem(SurfaceItem):
+    pass
+
+class PpiItem(SurfaceItem):
+    pass
+
+class ProtocolItem(SurfaceItem):
+    pass
diff --git a/BaseTools/Scripts/PackageDocumentTools/plugins/EdkPlugins/edk2/model/dec.py b/BaseTools/Scripts/PackageDocumentTools/plugins/EdkPlugins/edk2/model/dec.py
new file mode 100644
index 0000000..3bd0b7b
--- /dev/null
+++ b/BaseTools/Scripts/PackageDocumentTools/plugins/EdkPlugins/edk2/model/dec.py
@@ -0,0 +1,319 @@
+## @file
+#
+# Copyright (c) 2011 - 2018, Intel Corporation. All rights reserved.<BR>
+#
+# This program and the accompanying materials are licensed and made available
+# under the terms and conditions of the BSD License which accompanies this
+# distribution. The full text of the license may be found at
+# http://opensource.org/licenses/bsd-license.php
+#
+# THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+# WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+#
+
+import plugins.EdkPlugins.basemodel.ini as ini
+import re, os
+from plugins.EdkPlugins.basemodel.message import *
+
+class DECFile(ini.BaseINIFile):
+
+    def GetSectionInstance(self, parent, name, isCombined=False):
+        return DECSection(parent, name, isCombined)
+
+    def GetComponents(self):
+        return self.GetSectionByName('Components')
+
+    def GetPackageRootPath(self):
+        return os.path.dirname(self.GetFilename()).strip()
+
+    def GetBaseName(self):
+        return self.GetDefine("PACKAGE_NAME").strip()
+
+    def GetVersion(self):
+        return self.GetDefine("PACKAGE_VERSION").strip()
+
+    def GetSectionObjectsByName(self, name, arch=None):
+        arr = []
+        sects = self.GetSectionByName(name)
+        for sect in sects:
+            # skip unmatched archtecture content
+            if not sect.IsArchMatch(arch):
+                continue
+
+            for obj in sect.GetObjects():
+                arr.append(obj)
+
+        return arr
+
+class DECSection(ini.BaseINISection):
+    def GetSectionINIObject(self, parent):
+        type = self.GetType()
+
+        if type.lower().find('defines') != -1:
+            return DECDefineSectionObject(self)
+        if type.lower().find('includes') != -1:
+            return DECIncludeObject(self)
+        if type.lower().find('pcd') != -1:
+            return DECPcdObject(self)
+        if type.lower() == 'libraryclasses':
+            return DECLibraryClassObject(self)
+        if type.lower() == 'guids':
+            return DECGuidObject(self)
+        if type.lower() == 'ppis':
+            return DECPpiObject(self)
+        if type.lower() == 'protocols':
+            return DECProtocolObject(self)
+
+        return DECSectionObject(self)
+
+    def GetType(self):
+        arr = self._name.split('.')
+        return arr[0].strip()
+
+    def GetArch(self):
+        arr = self._name.split('.')
+        if len(arr) == 1:
+            return 'common'
+        return arr[1]
+
+    def IsArchMatch(self, arch):
+        if arch == None or self.GetArch() == 'common':
+            return True
+
+        if self.GetArch().lower() != arch.lower():
+            return False
+
+        return True
+
+class DECSectionObject(ini.BaseINISectionObject):
+    def GetArch(self):
+        return self.GetParent().GetArch()
+
+class DECDefineSectionObject(DECSectionObject):
+    def __init__(self, parent):
+        DECSectionObject.__init__(self, parent)
+        self._key = None
+        self._value = None
+
+    def Parse(self):
+        assert (self._start == self._end), 'The object in define section must be in single line'
+
+        line = self.GetLineByOffset(self._start).strip()
+
+        line = line.split('#')[0]
+        arr  = line.split('=')
+        if len(arr) != 2:
+            ErrorMsg('Invalid define section object',
+                   self.GetFilename(),
+                   self.GetParent().GetName()
+                   )
+            return False
+
+        self._key   = arr[0].strip()
+        self._value = arr[1].strip()
+
+        return True
+
+    def GetKey(self):
+        return self._key
+
+    def GetValue(self):
+        return self._value
+
+class DECGuidObject(DECSectionObject):
+    _objs = {}
+
+    def __init__(self, parent):
+        DECSectionObject.__init__(self, parent)
+        self._name = None
+
+    def Parse(self):
+        line = self.GetLineByOffset(self._start).strip().split('#')[0]
+        self._name = line.split('=')[0].strip()
+        self._guid = line.split('=')[1].strip()
+        objdict = DECGuidObject._objs
+        if self._name not in objdict.keys():
+            objdict[self._name] = [self]
+        else:
+            objdict[self._name].append(self)
+
+        return True
+
+    def GetName(self):
+        return self._name
+
+    def GetGuid(self):
+        return self._guid
+
+    def Destroy(self):
+        objdict = DECGuidObject._objs
+        objdict[self._name].remove(self)
+        if len(objdict[self._name]) == 0:
+            del objdict[self._name]
+
+    @staticmethod
+    def GetObjectDict():
+        return DECGuidObject._objs
+
+class DECPpiObject(DECSectionObject):
+    _objs = {}
+    def __init__(self, parent):
+        DECSectionObject.__init__(self, parent)
+        self._name = None
+
+    def Parse(self):
+        line = self.GetLineByOffset(self._start).strip().split('#')[0]
+        self._name = line.split('=')[0].strip()
+        self._guid = line.split('=')[1].strip()
+        objdict = DECPpiObject._objs
+        if self._name not in objdict.keys():
+            objdict[self._name] = [self]
+        else:
+            objdict[self._name].append(self)
+
+        return True
+
+    def GetName(self):
+        return self._name
+
+    def GetGuid(self):
+        return self._guid
+
+    def Destroy(self):
+        objdict = DECPpiObject._objs
+        objdict[self._name].remove(self)
+        if len(objdict[self._name]) == 0:
+            del objdict[self._name]
+
+    @staticmethod
+    def GetObjectDict():
+        return DECPpiObject._objs
+
+class DECProtocolObject(DECSectionObject):
+    _objs = {}
+
+    def __init__(self, parent):
+        DECSectionObject.__init__(self, parent)
+        self._name = None
+
+    def Parse(self):
+        line = self.GetLineByOffset(self._start).strip().split('#')[0]
+        self._name = line.split('=')[0].strip()
+        self._guid = line.split('=')[1].strip()
+        objdict = DECProtocolObject._objs
+        if self._name not in objdict.keys():
+            objdict[self._name] = [self]
+        else:
+            objdict[self._name].append(self)
+
+        return True
+
+    def GetName(self):
+        return self._name
+
+    def GetGuid(self):
+        return self._guid
+
+    def Destroy(self):
+        objdict = DECProtocolObject._objs
+        objdict[self._name].remove(self)
+        if len(objdict[self._name]) == 0:
+            del objdict[self._name]
+
+
+    @staticmethod
+    def GetObjectDict():
+        return DECProtocolObject._objs
+
+class DECLibraryClassObject(DECSectionObject):
+    _objs = {}
+
+    def __init__(self, parent):
+        DECSectionObject.__init__(self, parent)
+        self.mClassName = None
+        self.mHeaderFile = None
+
+    def Parse(self):
+        line = self.GetLineByOffset(self._start).strip().split('#')[0]
+        self.mClassName, self.mHeaderFile = line.split('|')
+        objdict = DECLibraryClassObject._objs
+        if self.mClassName not in objdict.keys():
+            objdict[self.mClassName] = [self]
+        else:
+            objdict[self.mClassName].append(self)
+        return True
+
+    def GetClassName(self):
+        return self.mClassName
+
+    def GetName(self):
+        return self.mClassName
+
+    def GetHeaderFile(self):
+        return self.mHeaderFile
+
+    def Destroy(self):
+        objdict = DECLibraryClassObject._objs
+        objdict[self.mClassName].remove(self)
+        if len(objdict[self.mClassName]) == 0:
+            del objdict[self.mClassName]
+
+    @staticmethod
+    def GetObjectDict():
+        return DECLibraryClassObject._objs
+
+class DECIncludeObject(DECSectionObject):
+    def __init__(self, parent):
+        DECSectionObject.__init__(self, parent)
+
+    def GetPath(self):
+        return self.GetLineByOffset(self._start).split('#')[0].strip()
+
+class DECPcdObject(DECSectionObject):
+    _objs = {}
+
+    def __init__(self, parent):
+        DECSectionObject.__init__(self, parent)
+        self.mPcdName           = None
+        self.mPcdDefaultValue   = None
+        self.mPcdDataType       = None
+        self.mPcdToken          = None
+
+    def Parse(self):
+        line = self.GetLineByOffset(self._start).strip().split('#')[0]
+        (self.mPcdName, self.mPcdDefaultValue, self.mPcdDataType, self.mPcdToken) = line.split('|')
+        objdict = DECPcdObject._objs
+        if self.mPcdName not in objdict.keys():
+            objdict[self.mPcdName] = [self]
+        else:
+            objdict[self.mPcdName].append(self)
+
+        return True
+
+    def Destroy(self):
+        objdict = DECPcdObject._objs
+        objdict[self.mPcdName].remove(self)
+        if len(objdict[self.mPcdName]) == 0:
+            del objdict[self.mPcdName]
+
+    def GetPcdType(self):
+        return self.GetParent().GetType()
+
+    def GetPcdName(self):
+        return self.mPcdName
+
+    def GetPcdValue(self):
+        return self.mPcdDefaultValue
+
+    def GetPcdDataType(self):
+        return self.mPcdDataType
+
+    def GetPcdToken(self):
+        return self.mPcdToken
+
+    def GetName(self):
+        return self.GetPcdName().split('.')[1]
+
+    @staticmethod
+    def GetObjectDict():
+        return DECPcdObject._objs
diff --git a/BaseTools/Scripts/PackageDocumentTools/plugins/EdkPlugins/edk2/model/doxygengen.py b/BaseTools/Scripts/PackageDocumentTools/plugins/EdkPlugins/edk2/model/doxygengen.py
new file mode 100644
index 0000000..268ba5c
--- /dev/null
+++ b/BaseTools/Scripts/PackageDocumentTools/plugins/EdkPlugins/edk2/model/doxygengen.py
@@ -0,0 +1,1089 @@
+## @file
+#
+# This file produce action class to generate doxygen document for edk2 codebase.
+# The action classes are shared by GUI and command line tools.
+#
+# Copyright (c) 2011 - 2018, Intel Corporation. All rights reserved.<BR>
+#
+# This program and the accompanying materials are licensed and made available
+# under the terms and conditions of the BSD License which accompanies this
+# distribution. The full text of the license may be found at
+# http://opensource.org/licenses/bsd-license.php
+#
+# THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+# WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+
+"""This file produce action class to generate doxygen document for edk2 codebase.
+   The action classes are shared by GUI and command line tools.
+"""
+import plugins.EdkPlugins.basemodel.doxygen as doxygen
+import os
+try:
+    import wx
+    gInGui = True
+except:
+    gInGui = False
+import re
+import plugins.EdkPlugins.edk2.model.inf as inf
+import plugins.EdkPlugins.edk2.model.dec as dec
+from plugins.EdkPlugins.basemodel.message import *
+
+_ignore_dir = ['.svn', '_svn', 'cvs']
+_inf_key_description_mapping_table = {
+  'INF_VERSION':'Version of INF file specification',
+  #'BASE_NAME':'Module Name',
+  'FILE_GUID':'Module Guid',
+  'MODULE_TYPE': 'Module Type',
+  'VERSION_STRING': 'Module Version',
+  'LIBRARY_CLASS': 'Produced Library Class',
+  'EFI_SPECIFICATION_VERSION': 'UEFI Specification Version',
+  'PI_SPECIFICATION_VERSION': 'PI Specification Version',
+  'ENTRY_POINT': 'Module Entry Point Function',
+  'CONSTRUCTOR': 'Library Constructor Function'
+}
+
+_dec_key_description_mapping_table = {
+  'DEC_SPECIFICATION': 'Version of DEC file specification',
+  'PACKAGE_GUID': 'Package Guid'
+}
+class DoxygenAction:
+    """This is base class for all doxygen action.
+    """
+
+    def __init__(self, doxPath, chmPath, outputPath, projname, mode='html', log=None, verbose=False):
+        """Constructor function.
+        @param  doxPath         the obosolution path of doxygen execute file.
+        @param  outputPath      the obosolution output path.
+        @param  log             log function for output message
+        """
+        self._doxPath       = doxPath
+        self._chmPath       = chmPath
+        self._outputPath    = outputPath
+        self._projname      = projname
+        self._configFile    = None          # doxygen config file is used by doxygen exe file
+        self._indexPageFile = None          # doxygen page file for index page.
+        self._log           = log
+        self._mode          = mode
+        self._verbose       = verbose
+        self._doxygenCallback = None
+        self._chmCallback     = None
+
+    def Log(self, message, level='info'):
+        if self._log != None:
+            self._log(message, level)
+
+    def IsVerbose(self):
+        return self._verbose
+
+    def Generate(self):
+        """Generate interface called by outer directly"""
+        self.Log(">>>>>> Start generate doxygen document for %s... Zzz....\n" % self._projname)
+
+        # create doxygen config file at first
+        self._configFile = doxygen.DoxygenConfigFile()
+        self._configFile.SetOutputDir(self._outputPath)
+
+        self._configFile.SetWarningFilePath(os.path.join(self._outputPath, 'warning.txt'))
+        if self._mode.lower() == 'html':
+            self._configFile.SetHtmlMode()
+        else:
+            self._configFile.SetChmMode()
+
+        self.Log("    >>>>>> Initialize doxygen config file...Zzz...\n")
+        self.InitializeConfigFile()
+
+        self.Log("    >>>>>> Generate doxygen index page file...Zzz...\n")
+        indexPagePath = self.GenerateIndexPage()
+        if indexPagePath == None:
+            self.Log("Fail to generate index page!\n", 'error')
+            return False
+        else:
+            self.Log("Success to create doxygen index page file %s \n" % indexPagePath)
+
+        # Add index page doxygen file to file list.
+        self._configFile.AddFile(indexPagePath)
+
+        # save config file to output path
+        configFilePath = os.path.join(self._outputPath, self._projname + '.doxygen_config')
+        self._configFile.Generate(configFilePath)
+        self.Log("    <<<<<< Success Save doxygen config file to %s...\n" % configFilePath)
+
+        # launch doxygen tool to generate document
+        if self._doxygenCallback != None:
+            self.Log("    >>>>>> Start doxygen process...Zzz...\n")
+            if not self._doxygenCallback(self._doxPath, configFilePath):
+                return False
+        else:
+            self.Log("Fail to create doxygen process!", 'error')
+            return False
+
+        return True
+
+    def InitializeConfigFile(self):
+        """Initialize config setting for doxygen project. It will be invoked after config file
+           object is created. Inherited class should implement it.
+        """
+
+    def GenerateIndexPage(self):
+        """Generate doxygen index page. Inherited class should implement it."""
+        return None
+
+    def RegisterCallbackDoxygenProcess(self, callback):
+        self._doxygenCallback = callback
+
+    def RegisterCallbackCHMProcess(self, callback):
+        self._chmCallback = callback
+
+class PlatformDocumentAction(DoxygenAction):
+    """Generate platform doxygen document, will be implement at future."""
+
+class PackageDocumentAction(DoxygenAction):
+    """Generate package reference document"""
+
+    def __init__(self, doxPath, chmPath, outputPath, pObj, mode='html', log=None, arch=None, tooltag=None,
+                  onlyInclude=False, verbose=False):
+        DoxygenAction.__init__(self, doxPath, chmPath, outputPath, pObj.GetName(), mode, log, verbose)
+        self._pObj   = pObj
+        self._arch   = arch
+        self._tooltag = tooltag
+        self._onlyIncludeDocument = onlyInclude
+
+    def InitializeConfigFile(self):
+        if self._arch == 'IA32':
+            self._configFile.AddPreDefined('MDE_CPU_IA32')
+        elif self._arch == 'X64':
+            self._configFile.AddPreDefined('MDE_CPU_X64')
+        elif self._arch == 'IPF':
+            self._configFile.AddPreDefined('MDE_CPU_IPF')
+        elif self._arch == 'EBC':
+            self._configFile.AddPreDefined('MDE_CPU_EBC')
+        else:
+            self._arch = None
+            self._configFile.AddPreDefined('MDE_CPU_IA32')
+            self._configFile.AddPreDefined('MDE_CPU_X64')
+            self._configFile.AddPreDefined('MDE_CPU_IPF')
+            self._configFile.AddPreDefined('MDE_CPU_EBC')
+            self._configFile.AddPreDefined('MDE_CPU_ARM')
+
+        namestr = self._pObj.GetName()
+        if self._arch != None:
+            namestr += '[%s]' % self._arch
+        if self._tooltag != None:
+            namestr += '[%s]' % self._tooltag
+        self._configFile.SetProjectName(namestr)
+        self._configFile.SetStripPath(self._pObj.GetWorkspace())
+        self._configFile.SetProjectVersion(self._pObj.GetFileObj().GetVersion())
+        self._configFile.AddPattern('*.decdoxygen')
+
+        if self._tooltag.lower() == 'msft':
+            self._configFile.AddPreDefined('_MSC_EXTENSIONS')
+        elif self._tooltag.lower() == 'gnu':
+            self._configFile.AddPreDefined('__GNUC__')
+        elif self._tooltag.lower() == 'intel':
+            self._configFile.AddPreDefined('__INTEL_COMPILER')
+        else:
+            self._tooltag = None
+            self._configFile.AddPreDefined('_MSC_EXTENSIONS')
+            self._configFile.AddPreDefined('__GNUC__')
+            self._configFile.AddPreDefined('__INTEL_COMPILER')
+
+        self._configFile.AddPreDefined('ASM_PFX= ')
+        self._configFile.AddPreDefined('OPTIONAL= ')
+
+    def GenerateIndexPage(self):
+        """Generate doxygen index page. Inherited class should implement it."""
+        fObj   = self._pObj.GetFileObj()
+        pdObj  = doxygen.DoxygenFile('%s Package Document' % self._pObj.GetName(),
+                                     '%s.decdoxygen' % self._pObj.GetFilename())
+        self._configFile.AddFile(pdObj.GetFilename())
+        pdObj.AddDescription(fObj.GetFileHeader())
+
+        defSection = fObj.GetSectionByName('defines')[0]
+        baseSection = doxygen.Section('PackageBasicInformation', 'Package Basic Information')
+        descr = '<TABLE>'
+        for obj in defSection.GetObjects():
+            if obj.GetKey() in _dec_key_description_mapping_table.keys():
+                descr += '<TR>'
+                descr += '<TD><B>%s</B></TD>' % _dec_key_description_mapping_table[obj.GetKey()]
+                descr += '<TD>%s</TD>' % obj.GetValue()
+                descr += '</TR>'
+        descr += '</TABLE><br>'
+        baseSection.AddDescription(descr)
+        pdObj.AddSection(baseSection)
+
+        knownIssueSection = doxygen.Section('Known_Issue_section', 'Known Issue')
+        knownIssueSection.AddDescription('<ul>')
+        knownIssueSection.AddDescription('<li> OPTIONAL macro for function parameter can not be dealed with doxygen, so it disapear in this document! </li>')
+        knownIssueSection.AddDescription('</ul>')
+        pdObj.AddSection(knownIssueSection)
+
+        self.AddAllIncludeFiles(self._pObj, self._configFile)
+        pages = self.GenerateIncludesSubPage(self._pObj, self._configFile)
+        if len(pages) != 0:
+            pdObj.AddPages(pages)
+        pages = self.GenerateLibraryClassesSubPage(self._pObj, self._configFile)
+        if len(pages) != 0:
+            pdObj.AddPages(pages)
+        pages = self.GeneratePcdSubPages(self._pObj, self._configFile)
+        if len(pages) != 0:
+            pdObj.AddPages(pages)
+        pages = self.GenerateGuidSubPages(self._pObj, self._configFile)
+        if len(pages) != 0:
+            pdObj.AddPages(pages)
+        pages = self.GeneratePpiSubPages(self._pObj, self._configFile)
+        if len(pages) != 0:
+            pdObj.AddPages(pages)
+        pages = self.GenerateProtocolSubPages(self._pObj, self._configFile)
+        if len(pages) != 0:
+            pdObj.AddPages(pages)
+        if not self._onlyIncludeDocument:
+            pdObj.AddPages(self.GenerateModulePages(self._pObj, self._configFile))
+
+        pdObj.Save()
+        return pdObj.GetFilename()
+
+    def GenerateIncludesSubPage(self, pObj, configFile):
+        # by default add following path as include path to config file
+        pkpath = pObj.GetFileObj().GetPackageRootPath()
+        configFile.AddIncludePath(os.path.join(pkpath, 'Include'))
+        configFile.AddIncludePath(os.path.join(pkpath, 'Include', 'Library'))
+        configFile.AddIncludePath(os.path.join(pkpath, 'Include', 'Protocol'))
+        configFile.AddIncludePath(os.path.join(pkpath, 'Include', 'Ppi'))
+        configFile.AddIncludePath(os.path.join(pkpath, 'Include', 'Guid'))
+        configFile.AddIncludePath(os.path.join(pkpath, 'Include', 'IndustryStandard'))
+
+        rootArray = []
+        pageRoot = doxygen.Page("Public Includes", "%s_public_includes" % pObj.GetName())
+        objs = pObj.GetFileObj().GetSectionObjectsByName('includes')
+        if len(objs) == 0: return []
+
+        for obj in objs:
+            # Add path to include path
+            path = os.path.join(pObj.GetFileObj().GetPackageRootPath(), obj.GetPath())
+            configFile.AddIncludePath(path)
+
+            # only list common folder's include file
+            if obj.GetArch().lower() != 'common':
+                continue
+
+            bNeedAddIncludePage = False
+            topPage = doxygen.Page(self._ConvertPathToDoxygen(path, pObj), 'public_include_top')
+
+            topPage.AddDescription('<ul>\n')
+            for file in os.listdir(path):
+                if file.lower() in _ignore_dir: continue
+                fullpath = os.path.join(path, file)
+                if os.path.isfile(fullpath):
+                    self.ProcessSourceFileForInclude(fullpath, pObj, configFile)
+                    topPage.AddDescription('<li> \link %s\endlink </li>\n' % self._ConvertPathToDoxygen(fullpath, pObj))
+                else:
+                    if file.lower() in ['library', 'protocol', 'guid', 'ppi', 'ia32', 'x64', 'ipf', 'ebc', 'arm', 'pi', 'uefi', 'aarch64']:
+                        continue
+                    bNeedAddSubPage = False
+                    subpage = doxygen.Page(self._ConvertPathToDoxygen(fullpath, pObj), 'public_include_%s' % file)
+                    subpage.AddDescription('<ul>\n')
+                    for subfile in os.listdir(fullpath):
+                        if subfile.lower() in _ignore_dir: continue
+                        bNeedAddSubPage = True
+                        subfullpath = os.path.join(fullpath, subfile)
+                        self.ProcessSourceFileForInclude(subfullpath, pObj, configFile)
+                        subpage.AddDescription('<li> \link %s \endlink </li>\n' % self._ConvertPathToDoxygen(subfullpath, pObj))
+                    subpage.AddDescription('</ul>\n')
+                    if bNeedAddSubPage:
+                        bNeedAddIncludePage = True
+                        pageRoot.AddPage(subpage)
+            topPage.AddDescription('</ul>\n')
+            if bNeedAddIncludePage:
+                pageRoot.AddPage(topPage)
+
+        if pageRoot.GetSubpageCount() != 0:
+            return [pageRoot]
+        else:
+            return []
+
+    def GenerateLibraryClassesSubPage(self, pObj, configFile):
+        """
+        Generate sub page for library class for package.
+        One DEC file maybe contains many library class sections
+        for different architecture.
+
+        @param  fObj DEC file object.
+        """
+        rootArray = []
+        pageRoot = doxygen.Page("Library Class", "%s_libraryclass" % pObj.GetName())
+        objs = pObj.GetFileObj().GetSectionObjectsByName('libraryclass', self._arch)
+        if len(objs) == 0: return []
+
+        if self._arch != None:
+            for obj in objs:
+                classPage = doxygen.Page(obj.GetClassName(),
+                                         "lc_%s" % obj.GetClassName())
+                comments = obj.GetComment()
+                if len(comments) != 0:
+                    classPage.AddDescription('<br>\n'.join(comments) + '<br>\n')
+                pageRoot.AddPage(classPage)
+                path = os.path.join(pObj.GetFileObj().GetPackageRootPath(), obj.GetHeaderFile())
+                path = path[len(pObj.GetWorkspace()) + 1:]
+                if len(comments) == 0:
+                    classPage.AddDescription('\copydoc %s<p>' % obj.GetHeaderFile())
+                section = doxygen.Section('ref', 'Refer to Header File')
+                section.AddDescription('\link %s\n' % obj.GetHeaderFile())
+                section.AddDescription(' \endlink<p>\n')
+                classPage.AddSection(section)
+                fullPath = os.path.join(pObj.GetFileObj().GetPackageRootPath(), obj.GetHeaderFile())
+                self.ProcessSourceFileForInclude(fullPath, pObj, configFile)
+        else:
+            archPageDict = {}
+            for obj in objs:
+                if obj.GetArch() not in archPageDict.keys():
+                    archPageDict[obj.GetArch()] = doxygen.Page(obj.GetArch(),
+                                                               'lc_%s' % obj.GetArch())
+                    pageRoot.AddPage(archPageDict[obj.GetArch()])
+                subArchRoot = archPageDict[obj.GetArch()]
+                classPage = doxygen.Page(obj.GetClassName(),
+                                         "lc_%s" % obj.GetClassName())
+                comments = obj.GetComment()
+                if len(comments) != 0:
+                    classPage.AddDescription('<br>\n'.join(comments) + '<br>\n')
+                subArchRoot.AddPage(classPage)
+                path = os.path.join(pObj.GetFileObj().GetPackageRootPath(), obj.GetHeaderFile())
+                path = path[len(pObj.GetWorkspace()) + 1:]
+                if len(comments) == 0:
+                    classPage.AddDescription('\copydoc %s<p>' % obj.GetHeaderFile())
+                section = doxygen.Section('ref', 'Refer to Header File')
+                section.AddDescription('\link %s\n' % obj.GetHeaderFile())
+                section.AddDescription(' \endlink<p>\n')
+                classPage.AddSection(section)
+                fullPath = os.path.join(pObj.GetFileObj().GetPackageRootPath(), obj.GetHeaderFile())
+
+                self.ProcessSourceFileForInclude(fullPath, pObj, configFile)
+        rootArray.append(pageRoot)
+        return rootArray
+
+    def ProcessSourceFileForInclude(self, path, pObj, configFile, infObj=None):
+        """
+        @param path        the analysising file full path
+        @param pObj        package object
+        @param configFile  doxygen config file.
+        """
+        if gInGui:
+            wx.Yield()
+        if not os.path.exists(path):
+            ErrorMsg('Source file path %s does not exist!' % path)
+            return
+
+        if configFile.FileExists(path):
+            return
+
+        try:
+            f = open(path, 'r')
+            lines = f.readlines()
+            f.close()
+        except IOError:
+            ErrorMsg('Fail to open file %s' % path)
+            return
+
+        configFile.AddFile(path)
+
+        no = 0
+        for no in xrange(len(lines)):
+            if len(lines[no].strip()) == 0:
+                continue
+            if lines[no].strip()[:2] in ['##', '//', '/*', '*/']:
+                continue
+            index = lines[no].lower().find('include')
+            #mo = IncludePattern.finditer(lines[no].lower())
+            mo = re.match(r"^#\s*include\s+[<\"]([\\/\w.]+)[>\"]$", lines[no].strip().lower())
+            if not mo:
+                continue
+            mo = re.match(r"^[#\w\s]+[<\"]([\\/\w.]+)[>\"]$", lines[no].strip())
+            filePath = mo.groups()[0]
+
+            if filePath == None or len(filePath) == 0:
+                continue
+
+            # find header file in module's path firstly.
+            fullPath = None
+
+            if os.path.exists(os.path.join(os.path.dirname(path), filePath)):
+                # Find the file in current directory
+                fullPath = os.path.join(os.path.dirname(path), filePath).replace('\\', '/')
+            else:
+                # find in depedent package's include path
+                incObjs = pObj.GetFileObj().GetSectionObjectsByName('includes')
+                for incObj in incObjs:
+                    incPath = os.path.join(pObj.GetFileObj().GetPackageRootPath(), incObj.GetPath()).strip()
+                    incPath = os.path.realpath(os.path.join(incPath, filePath))
+                    if os.path.exists(incPath):
+                        fullPath = incPath
+                        break
+                if infObj != None:
+                    pkgInfObjs = infObj.GetSectionObjectsByName('packages')
+                    for obj in  pkgInfObjs:
+                        decObj = dec.DECFile(os.path.join(pObj.GetWorkspace(), obj.GetPath()))
+                        if not decObj:
+                            ErrorMsg ('Fail to create pacakge object for %s' % obj.GetPackageName())
+                            continue
+                        if not decObj.Parse():
+                            ErrorMsg ('Fail to load package object for %s' % obj.GetPackageName())
+                            continue
+                        incObjs = decObj.GetSectionObjectsByName('includes')
+                        for incObj in incObjs:
+                            incPath = os.path.join(decObj.GetPackageRootPath(), incObj.GetPath()).replace('\\', '/')
+                            if os.path.exists(os.path.join(incPath, filePath)):
+                                fullPath = os.path.join(os.path.join(incPath, filePath))
+                                break
+                        if fullPath != None:
+                            break
+
+            if fullPath == None and self.IsVerbose():
+                self.Log('Can not resolve header file %s for file %s in package %s\n' % (filePath, path, pObj.GetFileObj().GetFilename()), 'error')
+                return
+            else:
+                fullPath = fullPath.replace('\\', '/')
+                if self.IsVerbose():
+                    self.Log('Preprocessing: Add include file %s for file %s\n' % (fullPath, path))
+                #LogMsg ('Preprocessing: Add include file %s for file %s' % (fullPath, path))
+                self.ProcessSourceFileForInclude(fullPath, pObj, configFile, infObj)
+
+    def AddAllIncludeFiles(self, pObj, configFile):
+        objs = pObj.GetFileObj().GetSectionObjectsByName('includes')
+        for obj in objs:
+            incPath = os.path.join(pObj.GetFileObj().GetPackageRootPath(), obj.GetPath())
+            for root, dirs, files in os.walk(incPath):
+                for dir in dirs:
+                    if dir.lower() in _ignore_dir:
+                        dirs.remove(dir)
+                for file in files:
+                    path = os.path.normpath(os.path.join(root, file))
+                    configFile.AddFile(path.replace('/', '\\'))
+
+    def GeneratePcdSubPages(self, pObj, configFile):
+        """
+        Generate sub pages for package's PCD definition.
+        @param pObj         package object
+        @param configFile   config file object
+        """
+        rootArray = []
+        objs = pObj.GetFileObj().GetSectionObjectsByName('pcd')
+        if len(objs) == 0:
+            return []
+
+        pcdRootPage = doxygen.Page('PCD', 'pcd_root_page')
+        typeRootPageDict = {}
+        typeArchRootPageDict = {}
+        for obj in objs:
+            if obj.GetPcdType() not in typeRootPageDict.keys():
+                typeRootPageDict[obj.GetPcdType()] = doxygen.Page(obj.GetPcdType(), 'pcd_%s_root_page' % obj.GetPcdType())
+                pcdRootPage.AddPage(typeRootPageDict[obj.GetPcdType()])
+            typeRoot = typeRootPageDict[obj.GetPcdType()]
+            if self._arch != None:
+                pcdPage = doxygen.Page('%s' % obj.GetPcdName(),
+                                        'pcd_%s_%s_%s' % (obj.GetPcdType(), obj.GetArch(), obj.GetPcdName().split('.')[1]))
+                pcdPage.AddDescription('<br>\n'.join(obj.GetComment()) + '<br>\n')
+                section = doxygen.Section('PCDinformation', 'PCD Information')
+                desc  = '<TABLE>'
+                desc += '<TR>'
+                desc += '<TD><CAPTION>Name</CAPTION></TD>'
+                desc += '<TD><CAPTION>Token Space</CAPTION></TD>'
+                desc += '<TD><CAPTION>Token number</CAPTION></TD>'
+                desc += '<TD><CAPTION>Data Type</CAPTION></TD>'
+                desc += '<TD><CAPTION>Default Value</CAPTION></TD>'
+                desc += '</TR>'
+                desc += '<TR>'
+                desc += '<TD><CAPTION>%s</CAPTION></TD>' % obj.GetPcdName().split('.')[1]
+                desc += '<TD><CAPTION>%s</CAPTION></TD>' % obj.GetPcdName().split('.')[0]
+                desc += '<TD><CAPTION>%s</CAPTION></TD>' % obj.GetPcdToken()
+                desc += '<TD><CAPTION>%s</CAPTION></TD>' % obj.GetPcdDataType()
+                desc += '<TD><CAPTION>%s</CAPTION></TD>' % obj.GetPcdValue()
+                desc += '</TR>'
+                desc += '</TABLE>'
+                section.AddDescription(desc)
+                pcdPage.AddSection(section)
+                typeRoot.AddPage(pcdPage)
+            else:
+                keystr = obj.GetPcdType() + obj.GetArch()
+                if keystr not in typeArchRootPageDict.keys():
+                    typeArchRootPage = doxygen.Page(obj.GetArch(), 'pcd_%s_%s_root_page' % (obj.GetPcdType(), obj.GetArch()))
+                    typeArchRootPageDict[keystr] = typeArchRootPage
+                    typeRoot.AddPage(typeArchRootPage)
+                typeArchRoot = typeArchRootPageDict[keystr]
+                pcdPage = doxygen.Page('%s' % obj.GetPcdName(),
+                                        'pcd_%s_%s_%s' % (obj.GetPcdType(), obj.GetArch(), obj.GetPcdName().split('.')[1]))
+                pcdPage.AddDescription('<br>\n'.join(obj.GetComment()) + '<br>\n')
+                section = doxygen.Section('PCDinformation', 'PCD Information')
+                desc  = '<TABLE>'
+                desc += '<TR>'
+                desc += '<TD><CAPTION>Name</CAPTION></TD>'
+                desc += '<TD><CAPTION>Token Space</CAPTION></TD>'
+                desc += '<TD><CAPTION>Token number</CAPTION></TD>'
+                desc += '<TD><CAPTION>Data Type</CAPTION></TD>'
+                desc += '<TD><CAPTION>Default Value</CAPTION></TD>'
+                desc += '</TR>'
+                desc += '<TR>'
+                desc += '<TD><CAPTION>%s</CAPTION></TD>' % obj.GetPcdName().split('.')[1]
+                desc += '<TD><CAPTION>%s</CAPTION></TD>' % obj.GetPcdName().split('.')[0]
+                desc += '<TD><CAPTION>%s</CAPTION></TD>' % obj.GetPcdToken()
+                desc += '<TD><CAPTION>%s</CAPTION></TD>' % obj.GetPcdDataType()
+                desc += '<TD><CAPTION>%s</CAPTION></TD>' % obj.GetPcdValue()
+                desc += '</TR>'
+                desc += '</TABLE>'
+                section.AddDescription(desc)
+                pcdPage.AddSection(section)
+                typeArchRoot.AddPage(pcdPage)
+        return [pcdRootPage]
+
+    def _GenerateGuidSubPage(self, pObj, obj, configFile):
+        guidPage = doxygen.Page('%s' % obj.GetName(),
+                                'guid_%s_%s' % (obj.GetArch(), obj.GetName()))
+        comments = obj.GetComment()
+        if len(comments) != 0:
+            guidPage.AddDescription('<br>'.join(obj.GetComment()) + '<br>')
+        section = doxygen.Section('BasicGuidInfo', 'GUID Information')
+        desc  = '<TABLE>'
+        desc += '<TR>'
+        desc += '<TD><CAPTION>GUID\'s Guid Name</CAPTION></TD><TD><CAPTION>GUID\'s Guid</CAPTION></TD>'
+        desc += '</TR>'
+        desc += '<TR>'
+        desc += '<TD>%s</TD>' % obj.GetName()
+        desc += '<TD>%s</TD>' % obj.GetGuid()
+        desc += '</TR>'
+        desc += '</TABLE>'
+        section.AddDescription(desc)
+        guidPage.AddSection(section)
+        refFile = self.FindHeaderFileForGuid(pObj, obj.GetName(), configFile)
+        if refFile:
+            relPath = refFile[len(pObj.GetWorkspace()) + 1:]
+            if len(comments) == 0:
+                guidPage.AddDescription(' \\copydoc %s <br>' % relPath)
+
+            section = doxygen.Section('ref', 'Refer to Header File')
+            section.AddDescription('\link %s\n' % relPath)
+            section.AddDescription('\endlink\n')
+            self.ProcessSourceFileForInclude(refFile, pObj, configFile)
+            guidPage.AddSection(section)
+        return guidPage
+
+    def GenerateGuidSubPages(self, pObj, configFile):
+        """
+        Generate sub pages for package's GUID definition.
+        @param  pObj            package object
+        @param  configFilf      doxygen config file object
+        """
+        pageRoot = doxygen.Page('GUID', 'guid_root_page')
+        objs = pObj.GetFileObj().GetSectionObjectsByName('guids', self._arch)
+        if len(objs) == 0: return []
+        if self._arch != None:
+            for obj in objs:
+                pageRoot.AddPage(self._GenerateGuidSubPage(pObj, obj, configFile))
+        else:
+            guidArchRootPageDict = {}
+            for obj in objs:
+                if obj.GetArch() not in guidArchRootPageDict.keys():
+                    guidArchRoot = doxygen.Page(obj.GetArch(), 'guid_arch_root_%s' % obj.GetArch())
+                    pageRoot.AddPage(guidArchRoot)
+                    guidArchRootPageDict[obj.GetArch()] = guidArchRoot
+                guidArchRoot = guidArchRootPageDict[obj.GetArch()]
+                guidArchRoot.AddPage(self._GenerateGuidSubPage(pObj, obj, configFile))
+        return [pageRoot]
+
+    def _GeneratePpiSubPage(self, pObj, obj, configFile):
+        guidPage = doxygen.Page(obj.GetName(), 'ppi_page_%s' % obj.GetName())
+        comments = obj.GetComment()
+        if len(comments) != 0:
+            guidPage.AddDescription('<br>'.join(obj.GetComment()) + '<br>')
+        section = doxygen.Section('BasicPpiInfo', 'PPI Information')
+        desc  = '<TABLE>'
+        desc += '<TR>'
+        desc += '<TD><CAPTION>PPI\'s Guid Name</CAPTION></TD><TD><CAPTION>PPI\'s Guid</CAPTION></TD>'
+        desc += '</TR>'
+        desc += '<TR>'
+        desc += '<TD>%s</TD>' % obj.GetName()
+        desc += '<TD>%s</TD>' % obj.GetGuid()
+        desc += '</TR>'
+        desc += '</TABLE>'
+        section.AddDescription(desc)
+        guidPage.AddSection(section)
+        refFile = self.FindHeaderFileForGuid(pObj, obj.GetName(), configFile)
+        if refFile:
+            relPath = refFile[len(pObj.GetWorkspace()) + 1:]
+            if len(comments) == 0:
+                guidPage.AddDescription(' \\copydoc %s <br>' % relPath)
+            section = doxygen.Section('ref', 'Refer to Header File')
+            section.AddDescription('\link %s\n' % relPath)
+            section.AddDescription('\endlink\n')
+            self.ProcessSourceFileForInclude(refFile, pObj, configFile)
+            guidPage.AddSection(section)
+
+        return guidPage
+
+    def GeneratePpiSubPages(self, pObj, configFile):
+        """
+        Generate sub pages for package's GUID definition.
+        @param  pObj            package object
+        @param  configFilf      doxygen config file object
+        """
+        pageRoot = doxygen.Page('PPI', 'ppi_root_page')
+        objs = pObj.GetFileObj().GetSectionObjectsByName('ppis', self._arch)
+        if len(objs) == 0: return []
+        if self._arch != None:
+            for obj in objs:
+                pageRoot.AddPage(self._GeneratePpiSubPage(pObj, obj, configFile))
+        else:
+            guidArchRootPageDict = {}
+            for obj in objs:
+                if obj.GetArch() not in guidArchRootPageDict.keys():
+                    guidArchRoot = doxygen.Page(obj.GetArch(), 'ppi_arch_root_%s' % obj.GetArch())
+                    pageRoot.AddPage(guidArchRoot)
+                    guidArchRootPageDict[obj.GetArch()] = guidArchRoot
+                guidArchRoot = guidArchRootPageDict[obj.GetArch()]
+                guidArchRoot.AddPage(self._GeneratePpiSubPage(pObj, obj, configFile))
+        return [pageRoot]
+
+    def _GenerateProtocolSubPage(self, pObj, obj, configFile):
+        guidPage = doxygen.Page(obj.GetName(), 'protocol_page_%s' % obj.GetName())
+        comments = obj.GetComment()
+        if len(comments) != 0:
+            guidPage.AddDescription('<br>'.join(obj.GetComment()) + '<br>')
+        section = doxygen.Section('BasicProtocolInfo', 'PROTOCOL Information')
+        desc  = '<TABLE>'
+        desc += '<TR>'
+        desc += '<TD><CAPTION>PROTOCOL\'s Guid Name</CAPTION></TD><TD><CAPTION>PROTOCOL\'s Guid</CAPTION></TD>'
+        desc += '</TR>'
+        desc += '<TR>'
+        desc += '<TD>%s</TD>' % obj.GetName()
+        desc += '<TD>%s</TD>' % obj.GetGuid()
+        desc += '</TR>'
+        desc += '</TABLE>'
+        section.AddDescription(desc)
+        guidPage.AddSection(section)
+
+        refFile = self.FindHeaderFileForGuid(pObj, obj.GetName(), configFile)
+        if refFile:
+            relPath = refFile[len(pObj.GetWorkspace()) + 1:]
+            if len(comments) == 0:
+                guidPage.AddDescription(' \\copydoc %s <br>' % relPath)
+            section = doxygen.Section('ref', 'Refer to Header File')
+            section.AddDescription('\link %s\n' % relPath)
+            section.AddDescription('\endlink\n')
+            self.ProcessSourceFileForInclude(refFile, pObj, configFile)
+            guidPage.AddSection(section)
+
+        return guidPage
+
+    def GenerateProtocolSubPages(self, pObj, configFile):
+        """
+        Generate sub pages for package's GUID definition.
+        @param  pObj            package object
+        @param  configFilf      doxygen config file object
+        """
+        pageRoot = doxygen.Page('PROTOCOL', 'protocol_root_page')
+        objs = pObj.GetFileObj().GetSectionObjectsByName('protocols', self._arch)
+        if len(objs) == 0: return []
+        if self._arch != None:
+            for obj in objs:
+                pageRoot.AddPage(self._GenerateProtocolSubPage(pObj, obj, configFile))
+        else:
+            guidArchRootPageDict = {}
+            for obj in objs:
+                if obj.GetArch() not in guidArchRootPageDict.keys():
+                    guidArchRoot = doxygen.Page(obj.GetArch(), 'protocol_arch_root_%s' % obj.GetArch())
+                    pageRoot.AddPage(guidArchRoot)
+                    guidArchRootPageDict[obj.GetArch()] = guidArchRoot
+                guidArchRoot = guidArchRootPageDict[obj.GetArch()]
+                guidArchRoot.AddPage(self._GenerateProtocolSubPage(pObj, obj, configFile))
+        return [pageRoot]
+
+    def FindHeaderFileForGuid(self, pObj, name, configFile):
+        """
+        For declaration header file for GUID/PPI/Protocol.
+
+        @param pObj         package object
+        @param name         guid/ppi/protocol's name
+        @param configFile   config file object
+
+        @return full path of header file and None if not found.
+        """
+        startPath  = pObj.GetFileObj().GetPackageRootPath()
+        incPath    = os.path.join(startPath, 'Include').replace('\\', '/')
+        # if <PackagePath>/include exist, then search header under it.
+        if os.path.exists(incPath):
+            startPath = incPath
+
+        for root, dirs, files in os.walk(startPath):
+            for dir in dirs:
+                if dir.lower() in _ignore_dir:
+                    dirs.remove(dir)
+            for file in files:
+                fPath = os.path.join(root, file)
+                if not IsCHeaderFile(fPath):
+                    continue
+                try:
+                    f = open(fPath, 'r')
+                    lines = f.readlines()
+                    f.close()
+                except IOError:
+                    self.Log('Fail to open file %s\n' % fPath)
+                    continue
+                for line in lines:
+                    if line.find(name) != -1 and \
+                       line.find('extern') != -1:
+                        return fPath.replace('\\', '/')
+        return None
+
+    def GetPackageModuleList(self, pObj):
+        """
+        Get all module's INF path under package's root path
+        @param     pObj  package object
+        @return    arrary of INF full path
+        """
+        mArray = []
+        packPath = pObj.GetFileObj().GetPackageRootPath()
+        if not os.path.exists:
+            return None
+        for root, dirs, files in os.walk(packPath):
+            for dir in dirs:
+                if dir.lower() in _ignore_dir:
+                    dirs.remove(dir)
+            for file in files:
+                if CheckPathPostfix(file, 'inf'):
+                    fPath = os.path.join(root, file).replace('\\', '/')
+                    mArray.append(fPath)
+        return mArray
+
+    def GenerateModulePages(self, pObj, configFile):
+        """
+        Generate sub pages for package's module which is under the package
+        root directory.
+
+        @param  pObj            package object
+        @param  configFilf      doxygen config file object
+        """
+        infList = self.GetPackageModuleList(pObj)
+        rootPages = []
+        libObjs = []
+        modObjs = []
+        for infpath in infList:
+            infObj = inf.INFFile(infpath)
+            #infObj = INFFileObject.INFFile (pObj.GetWorkspacePath(),
+            #                                inf)
+            if not infObj:
+                self.Log('Fail create INF object for %s' % inf)
+                continue
+            if not infObj.Parse():
+                self.Log('Fail to load INF file %s' % inf)
+                continue
+            if infObj.GetProduceLibraryClass() != None:
+                libObjs.append(infObj)
+            else:
+                modObjs.append(infObj)
+
+        if len(libObjs) != 0:
+            libRootPage = doxygen.Page('Libraries', 'lib_root_page')
+            rootPages.append(libRootPage)
+            for libInf in libObjs:
+                libRootPage.AddPage(self.GenerateModulePage(pObj, libInf, configFile, True))
+
+        if len(modObjs) != 0:
+            modRootPage = doxygen.Page('Modules', 'module_root_page')
+            rootPages.append(modRootPage)
+            for modInf in modObjs:
+                modRootPage.AddPage(self.GenerateModulePage(pObj, modInf, configFile, False))
+
+        return rootPages
+
+    def GenerateModulePage(self, pObj, infObj, configFile, isLib):
+        """
+        Generate page for a module/library.
+        @param infObj     INF file object for module/library
+        @param configFile doxygen config file object
+        @param isLib      Whether this module is libary
+
+        @param module doxygen page object
+        """
+        workspace = pObj.GetWorkspace()
+        refDecObjs = []
+        for obj in  infObj.GetSectionObjectsByName('packages'):
+            decObj = dec.DECFile(os.path.join(workspace, obj.GetPath()))
+            if not decObj:
+                ErrorMsg ('Fail to create pacakge object for %s' % obj.GetPackageName())
+                continue
+            if not decObj.Parse():
+                ErrorMsg ('Fail to load package object for %s' % obj.GetPackageName())
+                continue
+            refDecObjs.append(decObj)
+
+        modPage = doxygen.Page('%s' % infObj.GetBaseName(),
+                               'module_%s' % infObj.GetBaseName())
+        modPage.AddDescription(infObj.GetFileHeader())
+
+        basicInfSection = doxygen.Section('BasicModuleInformation', 'Basic Module Information')
+        desc = "<TABLE>"
+        for obj in infObj.GetSectionObjectsByName('defines'):
+            key = obj.GetKey()
+            value = obj.GetValue()
+            if key not in _inf_key_description_mapping_table.keys(): continue
+            if key == 'LIBRARY_CLASS' and value.find('|') != -1:
+                clsname, types = value.split('|')
+                desc += '<TR>'
+                desc += '<TD><B>%s</B></TD>' % _inf_key_description_mapping_table[key]
+                desc += '<TD>%s</TD>' % clsname
+                desc += '</TR>'
+
+                desc += '<TR>'
+                desc += '<TD><B>Supported Module Types</B></TD>'
+                desc += '<TD>%s</TD>' % types
+                desc += '</TR>'
+            else:
+                desc += '<TR>'
+                desc += '<TD><B>%s</B></TD>' % _inf_key_description_mapping_table[key]
+                if key == 'EFI_SPECIFICATION_VERSION' and value == '0x00020000':
+                    value = '2.0'
+                desc += '<TD>%s</TD>' % value
+                desc += '</TR>'
+        desc += '</TABLE>'
+        basicInfSection.AddDescription(desc)
+        modPage.AddSection(basicInfSection)
+
+        # Add protocol section
+        data  = []
+        for obj in infObj.GetSectionObjectsByName('pcd', self._arch):
+            data.append(obj.GetPcdName().strip())
+        if len(data) != 0:
+            s = doxygen.Section('Pcds', 'Pcds')
+            desc = "<TABLE>"
+            desc += '<TR><TD><B>PCD Name</B></TD><TD><B>TokenSpace</B></TD><TD><B>Package</B></TD></TR>'
+            for item in data:
+                desc += '<TR>'
+                desc += '<TD>%s</TD>' % item.split('.')[1]
+                desc += '<TD>%s</TD>' % item.split('.')[0]
+                pkgbasename = self.SearchPcdPackage(item, workspace, refDecObjs)
+                desc += '<TD>%s</TD>' % pkgbasename
+                desc += '</TR>'
+            desc += "</TABLE>"
+            s.AddDescription(desc)
+            modPage.AddSection(s)
+
+        # Add protocol section
+        #sects = infObj.GetSectionByString('protocol')
+        data  = []
+        #for sect in sects:
+        for obj in infObj.GetSectionObjectsByName('protocol', self._arch):
+            data.append(obj.GetName().strip())
+        if len(data) != 0:
+            s = doxygen.Section('Protocols', 'Protocols')
+            desc = "<TABLE>"
+            desc += '<TR><TD><B>Name</B></TD><TD><B>Package</B></TD></TR>'
+            for item in data:
+                desc += '<TR>'
+                desc += '<TD>%s</TD>' % item
+                pkgbasename = self.SearchProtocolPackage(item, workspace, refDecObjs)
+                desc += '<TD>%s</TD>' % pkgbasename
+                desc += '</TR>'
+            desc += "</TABLE>"
+            s.AddDescription(desc)
+            modPage.AddSection(s)
+
+        # Add ppi section
+        #sects = infObj.GetSectionByString('ppi')
+        data  = []
+        #for sect in sects:
+        for obj in infObj.GetSectionObjectsByName('ppi', self._arch):
+            data.append(obj.GetName().strip())
+        if len(data) != 0:
+            s = doxygen.Section('Ppis', 'Ppis')
+            desc = "<TABLE>"
+            desc += '<TR><TD><B>Name</B></TD><TD><B>Package</B></TD></TR>'
+            for item in data:
+                desc += '<TR>'
+                desc += '<TD>%s</TD>' % item
+                pkgbasename = self.SearchPpiPackage(item, workspace, refDecObjs)
+                desc += '<TD>%s</TD>' % pkgbasename
+                desc += '</TR>'
+            desc += "</TABLE>"
+            s.AddDescription(desc)
+            modPage.AddSection(s)
+
+        # Add guid section
+        #sects = infObj.GetSectionByString('guid')
+        data  = []
+        #for sect in sects:
+        for obj in infObj.GetSectionObjectsByName('guid', self._arch):
+            data.append(obj.GetName().strip())
+        if len(data) != 0:
+            s = doxygen.Section('Guids', 'Guids')
+            desc = "<TABLE>"
+            desc += '<TR><TD><B>Name</B></TD><TD><B>Package</B></TD></TR>'
+            for item in data:
+                desc += '<TR>'
+                desc += '<TD>%s</TD>' % item
+                pkgbasename = self.SearchGuidPackage(item, workspace, refDecObjs)
+                desc += '<TD>%s</TD>' % pkgbasename
+                desc += '</TR>'
+            desc += "</TABLE>"
+            s.AddDescription(desc)
+            modPage.AddSection(s)
+
+        section = doxygen.Section('LibraryClasses', 'Library Classes')
+        desc = "<TABLE>"
+        desc += '<TR><TD><B>Name</B></TD><TD><B>Type</B></TD><TD><B>Package</B></TD><TD><B>Header File</B></TD></TR>'
+        if isLib:
+            desc += '<TR>'
+            desc += '<TD>%s</TD>' % infObj.GetProduceLibraryClass()
+            desc += '<TD>Produce</TD>'
+            try:
+                pkgname, hPath = self.SearchLibraryClassHeaderFile(infObj.GetProduceLibraryClass(),
+                                                              workspace,
+                                                              refDecObjs)
+            except:
+                self.Log ('fail to get package header file for lib class %s' % infObj.GetProduceLibraryClass())
+                pkgname = 'NULL'
+                hPath   = 'NULL'
+            desc += '<TD>%s</TD>' % pkgname
+            if hPath != "NULL":
+                desc += '<TD>\link %s \endlink</TD>' % hPath
+            else:
+                desc += '<TD>%s</TD>' % hPath
+            desc += '</TR>'
+        for lcObj in infObj.GetSectionObjectsByName('libraryclasses', self._arch):
+            desc += '<TR>'
+            desc += '<TD>%s</TD>' % lcObj.GetClass()
+            retarr = self.SearchLibraryClassHeaderFile(lcObj.GetClass(),
+                                                       workspace,
+                                                       refDecObjs)
+            if retarr != None:
+                pkgname, hPath = retarr
+            else:
+                self.Log('Fail find the library class %s definition from module %s dependent package!' % (lcObj.GetClass(), infObj.GetFilename()), 'error')
+                pkgname = 'NULL'
+                hPath   = 'NULL'
+            desc += '<TD>Consume</TD>'
+            desc += '<TD>%s</TD>' % pkgname
+            desc += '<TD>\link %s \endlink</TD>' % hPath
+            desc += '</TR>'
+        desc += "</TABLE>"
+        section.AddDescription(desc)
+        modPage.AddSection(section)
+
+        section = doxygen.Section('SourceFiles', 'Source Files')
+        section.AddDescription('<ul>\n')
+        for obj in infObj.GetSourceObjects(self._arch, self._tooltag):
+            sPath = infObj.GetModuleRootPath()
+            sPath = os.path.join(sPath, obj.GetSourcePath()).replace('\\', '/').strip()
+            if sPath.lower().endswith('.uni') or sPath.lower().endswith('.s') or sPath.lower().endswith('.asm') or sPath.lower().endswith('.nasm'):
+                newPath = self.TranslateUniFile(sPath)
+                configFile.AddFile(newPath)
+                newPath = newPath[len(pObj.GetWorkspace()) + 1:]
+                section.AddDescription('<li> \link %s \endlink </li>' %  newPath)
+            else:
+                self.ProcessSourceFileForInclude(sPath, pObj, configFile, infObj)
+                sPath = sPath[len(pObj.GetWorkspace()) + 1:]
+                section.AddDescription('<li>\link %s \endlink </li>' % sPath)
+        section.AddDescription('</ul>\n')
+        modPage.AddSection(section)
+
+        #sects = infObj.GetSectionByString('depex')
+        data  = []
+        #for sect in sects:
+        for obj in infObj.GetSectionObjectsByName('depex'):
+            data.append(str(obj))
+        if len(data) != 0:
+            s = doxygen.Section('DependentSection', 'Module Dependencies')
+            s.AddDescription('<br>'.join(data))
+            modPage.AddSection(s)
+
+        return modPage
+
+    def TranslateUniFile(self, path):
+        newpath = path + '.dox'
+        #import core.textfile as textfile
+        #file = textfile.TextFile(path)
+
+        try:
+            file = open(path, 'rb')
+        except (IOError, OSError), msg:
+            return None
+
+        t = file.read()
+        file.close()
+
+        output = '/** @file \n'
+        #output = '<html><body>'
+        arr = t.split('\r\n')
+        for line in arr:
+            if line.find('@file') != -1:
+                continue
+            if line.find('*/') != -1:
+                continue
+            line = line.strip()
+            if line.strip().startswith('/'):
+                arr = line.split(' ')
+                if len(arr) > 1:
+                    line = ' '.join(arr[1:])
+                else:
+                    continue
+            output += '%s<br>\n' % line
+        output += '**/'
+
+        if os.path.exists(newpath):
+            os.remove(newpath)
+
+        file = open(newpath, "w")
+        file.write(output)
+        file.close()
+        return newpath
+
+    def SearchPcdPackage(self, pcdname, workspace, decObjs):
+        for decObj in  decObjs:
+            for pcd in decObj.GetSectionObjectsByName('pcd'):
+                if pcdname == pcd.GetPcdName():
+                    return decObj.GetBaseName()
+        return None
+
+    def SearchProtocolPackage(self, protname, workspace, decObjs):
+        for decObj in  decObjs:
+            for proto in decObj.GetSectionObjectsByName('protocol'):
+                if protname == proto.GetName():
+                    return decObj.GetBaseName()
+        return None
+
+    def SearchPpiPackage(self, ppiname, workspace, decObjs):
+        for decObj in  decObjs:
+            for ppi in decObj.GetSectionObjectsByName('ppi'):
+                if ppiname == ppi.GetName():
+                    return decObj.GetBaseName()
+        return None
+
+    def SearchGuidPackage(self, guidname, workspace, decObjs):
+        for decObj in  decObjs:
+            for guid in decObj.GetSectionObjectsByName('guid'):
+                if guidname == guid.GetName():
+                    return decObj.GetBaseName()
+        return None
+
+    def SearchLibraryClassHeaderFile(self, className, workspace, decObjs):
+        for decObj in  decObjs:
+            for cls in decObj.GetSectionObjectsByName('libraryclasses'):
+                if cls.GetClassName().strip() == className:
+                    path = cls.GetHeaderFile().strip()
+                    path = os.path.join(decObj.GetPackageRootPath(), path)
+                    path = path[len(workspace) + 1:]
+                    return decObj.GetBaseName(), path.replace('\\', '/')
+
+        return None
+
+    def _ConvertPathToDoxygen(self, path, pObj):
+        pRootPath = pObj.GetWorkspace()
+        path = path[len(pRootPath) + 1:]
+        return path.replace('\\', '/')
+
+def IsCHeaderFile(path):
+    return CheckPathPostfix(path, 'h')
+
+def CheckPathPostfix(path, str):
+    index = path.rfind('.')
+    if index == -1:
+        return False
+    if path[index + 1:].lower() == str.lower():
+        return True
+    return False
diff --git a/BaseTools/Scripts/PackageDocumentTools/plugins/EdkPlugins/edk2/model/doxygengen_spec.py b/BaseTools/Scripts/PackageDocumentTools/plugins/EdkPlugins/edk2/model/doxygengen_spec.py
new file mode 100644
index 0000000..876da13
--- /dev/null
+++ b/BaseTools/Scripts/PackageDocumentTools/plugins/EdkPlugins/edk2/model/doxygengen_spec.py
@@ -0,0 +1,1092 @@
+## @file
+#
+# This file produce action class to generate doxygen document for edk2 codebase.
+# The action classes are shared by GUI and command line tools.
+#
+# Copyright (c) 2011 - 2018, Intel Corporation. All rights reserved.<BR>
+#
+# This program and the accompanying materials are licensed and made available
+# under the terms and conditions of the BSD License which accompanies this
+# distribution. The full text of the license may be found at
+# http://opensource.org/licenses/bsd-license.php
+#
+# THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+# WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+
+import plugins.EdkPlugins.basemodel.doxygen as doxygen
+import os
+try:
+    import wx
+    gInGui = True
+except:
+    gInGui = False
+import re
+import plugins.EdkPlugins.edk2.model.inf as inf
+import plugins.EdkPlugins.edk2.model.dec as dec
+from plugins.EdkPlugins.basemodel.message import *
+
+_ignore_dir = ['.svn', '_svn', 'cvs']
+_inf_key_description_mapping_table = {
+  'INF_VERSION':'Version of INF file specification',
+  #'BASE_NAME':'Module Name',
+  'FILE_GUID':'Module Guid',
+  'MODULE_TYPE': 'Module Type',
+  'VERSION_STRING': 'Module Version',
+  'LIBRARY_CLASS': 'Produced Library Class',
+  'EFI_SPECIFICATION_VERSION': 'UEFI Specification Version',
+  'PI_SPECIFICATION_VERSION': 'PI Specification Version',
+  'ENTRY_POINT': 'Module Entry Point Function',
+  'CONSTRUCTOR': 'Library Constructor Function'
+}
+
+_dec_key_description_mapping_table = {
+  'DEC_SPECIFICATION': 'Version of DEC file specification',
+  'PACKAGE_GUID': 'Package Guid'
+}
+class DoxygenAction:
+    """This is base class for all doxygen action.
+    """
+
+    def __init__(self, doxPath, chmPath, outputPath, projname, mode='html', log=None, verbose=False):
+        """Constructor function.
+        @param  doxPath         the obosolution path of doxygen execute file.
+        @param  outputPath      the obosolution output path.
+        @param  log             log function for output message
+        """
+        self._doxPath       = doxPath
+        self._chmPath       = chmPath
+        self._outputPath    = outputPath
+        self._projname      = projname
+        self._configFile    = None          # doxygen config file is used by doxygen exe file
+        self._indexPageFile = None          # doxygen page file for index page.
+        self._log           = log
+        self._mode          = mode
+        self._verbose       = verbose
+        self._doxygenCallback = None
+        self._chmCallback     = None
+
+    def Log(self, message, level='info'):
+        if self._log != None:
+            self._log(message, level)
+
+    def IsVerbose(self):
+        return self._verbose
+
+    def Generate(self):
+        """Generate interface called by outer directly"""
+        self.Log(">>>>>> Start generate doxygen document for %s... Zzz....\n" % self._projname)
+
+        # create doxygen config file at first
+        self._configFile = doxygen.DoxygenConfigFile()
+        self._configFile.SetOutputDir(self._outputPath)
+
+        self._configFile.SetWarningFilePath(os.path.join(self._outputPath, 'warning.txt'))
+        if self._mode.lower() == 'html':
+            self._configFile.SetHtmlMode()
+        else:
+            self._configFile.SetChmMode()
+
+        self.Log("    >>>>>> Initialize doxygen config file...Zzz...\n")
+        self.InitializeConfigFile()
+
+        self.Log("    >>>>>> Generate doxygen index page file...Zzz...\n")
+        indexPagePath = self.GenerateIndexPage()
+        if indexPagePath == None:
+            self.Log("Fail to generate index page!\n", 'error')
+            return False
+        else:
+            self.Log("Success to create doxygen index page file %s \n" % indexPagePath)
+
+        # Add index page doxygen file to file list.
+        self._configFile.AddFile(indexPagePath)
+
+        # save config file to output path
+        configFilePath = os.path.join(self._outputPath, self._projname + '.doxygen_config')
+        self._configFile.Generate(configFilePath)
+        self.Log("    <<<<<< Success Save doxygen config file to %s...\n" % configFilePath)
+
+        # launch doxygen tool to generate document
+        if self._doxygenCallback != None:
+            self.Log("    >>>>>> Start doxygen process...Zzz...\n")
+            if not self._doxygenCallback(self._doxPath, configFilePath):
+                return False
+        else:
+            self.Log("Fail to create doxygen process!", 'error')
+            return False
+
+        return True
+
+    def InitializeConfigFile(self):
+        """Initialize config setting for doxygen project. It will be invoked after config file
+           object is created. Inherited class should implement it.
+        """
+
+    def GenerateIndexPage(self):
+        """Generate doxygen index page. Inherited class should implement it."""
+        return None
+
+    def RegisterCallbackDoxygenProcess(self, callback):
+        self._doxygenCallback = callback
+
+    def RegisterCallbackCHMProcess(self, callback):
+        self._chmCallback = callback
+
+class PlatformDocumentAction(DoxygenAction):
+    """Generate platform doxygen document, will be implement at future."""
+
+class PackageDocumentAction(DoxygenAction):
+    """Generate package reference document"""
+
+    def __init__(self, doxPath, chmPath, outputPath, pObj, mode='html', log=None, arch=None, tooltag=None,
+                 macros=[], onlyInclude=False, verbose=False):
+        DoxygenAction.__init__(self, doxPath, chmPath, outputPath, pObj.GetName(), mode, log, verbose)
+        self._pObj   = pObj
+        self._arch   = arch
+        self._tooltag = tooltag
+        self._macros = macros
+        self._onlyIncludeDocument = onlyInclude
+
+    def InitializeConfigFile(self):
+        if self._arch == 'IA32':
+            self._configFile.AddPreDefined('MDE_CPU_IA32')
+        elif self._arch == 'X64':
+            self._configFile.AddPreDefined('MDE_CPU_X64')
+        elif self._arch == 'IPF':
+            self._configFile.AddPreDefined('MDE_CPU_IPF')
+        elif self._arch == 'EBC':
+            self._configFile.AddPreDefined('MDE_CPU_EBC')
+        else:
+            self._arch = None
+            self._configFile.AddPreDefined('MDE_CPU_IA32')
+            self._configFile.AddPreDefined('MDE_CPU_X64')
+            self._configFile.AddPreDefined('MDE_CPU_IPF')
+            self._configFile.AddPreDefined('MDE_CPU_EBC')
+            self._configFile.AddPreDefined('MDE_CPU_ARM')
+
+        for macro in self._macros:
+            self._configFile.AddPreDefined(macro)
+
+        namestr = self._pObj.GetName()
+        if self._arch != None:
+            namestr += '[%s]' % self._arch
+        if self._tooltag != None:
+            namestr += '[%s]' % self._tooltag
+        self._configFile.SetProjectName(namestr)
+        self._configFile.SetStripPath(self._pObj.GetWorkspace())
+        self._configFile.SetProjectVersion(self._pObj.GetFileObj().GetVersion())
+        self._configFile.AddPattern('*.decdoxygen')
+
+        if self._tooltag.lower() == 'msft':
+            self._configFile.AddPreDefined('_MSC_EXTENSIONS')
+        elif self._tooltag.lower() == 'gnu':
+            self._configFile.AddPreDefined('__GNUC__')
+        elif self._tooltag.lower() == 'intel':
+            self._configFile.AddPreDefined('__INTEL_COMPILER')
+        else:
+            self._tooltag = None
+            self._configFile.AddPreDefined('_MSC_EXTENSIONS')
+            self._configFile.AddPreDefined('__GNUC__')
+            self._configFile.AddPreDefined('__INTEL_COMPILER')
+
+        self._configFile.AddPreDefined('ASM_PFX= ')
+        self._configFile.AddPreDefined('OPTIONAL= ')
+
+    def GenerateIndexPage(self):
+        """Generate doxygen index page. Inherited class should implement it."""
+        fObj   = self._pObj.GetFileObj()
+        pdObj  = doxygen.DoxygenFile('%s Package Document' % self._pObj.GetName(),
+                                     '%s.decdoxygen' % self._pObj.GetFilename())
+        self._configFile.AddFile(pdObj.GetFilename())
+        pdObj.AddDescription(fObj.GetFileHeader())
+
+        defSection = fObj.GetSectionByName('defines')[0]
+        baseSection = doxygen.Section('PackageBasicInformation', 'Package Basic Information')
+        descr = '<TABLE>'
+        for obj in defSection.GetObjects():
+            if obj.GetKey() in _dec_key_description_mapping_table.keys():
+                descr += '<TR>'
+                descr += '<TD><B>%s</B></TD>' % _dec_key_description_mapping_table[obj.GetKey()]
+                descr += '<TD>%s</TD>' % obj.GetValue()
+                descr += '</TR>'
+        descr += '</TABLE><br>'
+        baseSection.AddDescription(descr)
+        pdObj.AddSection(baseSection)
+
+        knownIssueSection = doxygen.Section('Known_Issue_section', 'Known Issue')
+        knownIssueSection.AddDescription('<ul>')
+        knownIssueSection.AddDescription('<li> OPTIONAL macro for function parameter can not be dealed with doxygen, so it disapear in this document! </li>')
+        knownIssueSection.AddDescription('</ul>')
+        pdObj.AddSection(knownIssueSection)
+
+        self.AddAllIncludeFiles(self._pObj, self._configFile)
+        pages = self.GenerateIncludesSubPage(self._pObj, self._configFile)
+        if len(pages) != 0:
+            pdObj.AddPages(pages)
+        pages = self.GenerateLibraryClassesSubPage(self._pObj, self._configFile)
+        if len(pages) != 0:
+            pdObj.AddPages(pages)
+        pages = self.GeneratePcdSubPages(self._pObj, self._configFile)
+        if len(pages) != 0:
+            pdObj.AddPages(pages)
+        pages = self.GenerateGuidSubPages(self._pObj, self._configFile)
+        if len(pages) != 0:
+            pdObj.AddPages(pages)
+        pages = self.GeneratePpiSubPages(self._pObj, self._configFile)
+        if len(pages) != 0:
+            pdObj.AddPages(pages)
+        pages = self.GenerateProtocolSubPages(self._pObj, self._configFile)
+        if len(pages) != 0:
+            pdObj.AddPages(pages)
+        if not self._onlyIncludeDocument:
+            pdObj.AddPages(self.GenerateModulePages(self._pObj, self._configFile))
+
+        pdObj.Save()
+        return pdObj.GetFilename()
+
+    def GenerateIncludesSubPage(self, pObj, configFile):
+        # by default add following path as include path to config file
+        pkpath = pObj.GetFileObj().GetPackageRootPath()
+        configFile.AddIncludePath(os.path.join(pkpath, 'Include'))
+        configFile.AddIncludePath(os.path.join(pkpath, 'Include', 'Library'))
+        configFile.AddIncludePath(os.path.join(pkpath, 'Include', 'Protocol'))
+        configFile.AddIncludePath(os.path.join(pkpath, 'Include', 'Ppi'))
+        configFile.AddIncludePath(os.path.join(pkpath, 'Include', 'Guid'))
+        configFile.AddIncludePath(os.path.join(pkpath, 'Include', 'IndustryStandard'))
+
+        rootArray = []
+        pageRoot = doxygen.Page("Public Includes", "%s_public_includes" % pObj.GetName())
+        objs = pObj.GetFileObj().GetSectionObjectsByName('includes')
+        if len(objs) == 0: return []
+
+        for obj in objs:
+            # Add path to include path
+            path = os.path.join(pObj.GetFileObj().GetPackageRootPath(), obj.GetPath())
+            configFile.AddIncludePath(path)
+
+            # only list common folder's include file
+            if obj.GetArch().lower() != 'common':
+                continue
+
+            bNeedAddIncludePage = False
+            topPage = doxygen.Page(self._ConvertPathToDoxygen(path, pObj), 'public_include_top')
+
+            topPage.AddDescription('<ul>\n')
+            for file in os.listdir(path):
+                if file.lower() in _ignore_dir: continue
+                fullpath = os.path.join(path, file)
+                if os.path.isfile(fullpath):
+                    self.ProcessSourceFileForInclude(fullpath, pObj, configFile)
+                    topPage.AddDescription('<li> \link %s\endlink </li>\n' % self._ConvertPathToDoxygen(fullpath, pObj))
+                else:
+                    if file.lower() in ['library', 'protocol', 'guid', 'ppi', 'ia32', 'x64', 'ipf', 'ebc', 'arm', 'pi', 'uefi', 'aarch64']:
+                        continue
+                    bNeedAddSubPage = False
+                    subpage = doxygen.Page(self._ConvertPathToDoxygen(fullpath, pObj), 'public_include_%s' % file)
+                    subpage.AddDescription('<ul>\n')
+                    for subfile in os.listdir(fullpath):
+                        if subfile.lower() in _ignore_dir: continue
+                        bNeedAddSubPage = True
+                        subfullpath = os.path.join(fullpath, subfile)
+                        self.ProcessSourceFileForInclude(subfullpath, pObj, configFile)
+                        subpage.AddDescription('<li> \link %s \endlink </li>\n' % self._ConvertPathToDoxygen(subfullpath, pObj))
+                    subpage.AddDescription('</ul>\n')
+                    if bNeedAddSubPage:
+                        bNeedAddIncludePage = True
+                        pageRoot.AddPage(subpage)
+            topPage.AddDescription('</ul>\n')
+            if bNeedAddIncludePage:
+                pageRoot.AddPage(topPage)
+
+        if pageRoot.GetSubpageCount() != 0:
+            return [pageRoot]
+        else:
+            return []
+
+    def GenerateLibraryClassesSubPage(self, pObj, configFile):
+        """
+        Generate sub page for library class for package.
+        One DEC file maybe contains many library class sections
+        for different architecture.
+
+        @param  fObj DEC file object.
+        """
+        rootArray = []
+        pageRoot = doxygen.Page("Library Class", "%s_libraryclass" % pObj.GetName())
+        objs = pObj.GetFileObj().GetSectionObjectsByName('libraryclass', self._arch)
+        if len(objs) == 0: return []
+
+        if self._arch != None:
+            for obj in objs:
+                classPage = doxygen.Page(obj.GetClassName(),
+                                         "lc_%s" % obj.GetClassName())
+                comments = obj.GetComment()
+                if len(comments) != 0:
+                    classPage.AddDescription('<br>\n'.join(comments) + '<br>\n')
+                pageRoot.AddPage(classPage)
+                path = os.path.join(pObj.GetFileObj().GetPackageRootPath(), obj.GetHeaderFile())
+                path = path[len(pObj.GetWorkspace()) + 1:]
+                if len(comments) == 0:
+                    classPage.AddDescription('\copydoc %s<p>' % obj.GetHeaderFile())
+                section = doxygen.Section('ref', 'Refer to Header File')
+                section.AddDescription('\link %s\n' % obj.GetHeaderFile())
+                section.AddDescription(' \endlink<p>\n')
+                classPage.AddSection(section)
+                fullPath = os.path.join(pObj.GetFileObj().GetPackageRootPath(), obj.GetHeaderFile())
+                self.ProcessSourceFileForInclude(fullPath, pObj, configFile)
+        else:
+            archPageDict = {}
+            for obj in objs:
+                if obj.GetArch() not in archPageDict.keys():
+                    archPageDict[obj.GetArch()] = doxygen.Page(obj.GetArch(),
+                                                               'lc_%s' % obj.GetArch())
+                    pageRoot.AddPage(archPageDict[obj.GetArch()])
+                subArchRoot = archPageDict[obj.GetArch()]
+                classPage = doxygen.Page(obj.GetClassName(),
+                                         "lc_%s" % obj.GetClassName())
+                comments = obj.GetComment()
+                if len(comments) != 0:
+                    classPage.AddDescription('<br>\n'.join(comments) + '<br>\n')
+                subArchRoot.AddPage(classPage)
+                path = os.path.join(pObj.GetFileObj().GetPackageRootPath(), obj.GetHeaderFile())
+                path = path[len(pObj.GetWorkspace()) + 1:]
+                if len(comments) == 0:
+                    classPage.AddDescription('\copydoc %s<p>' % obj.GetHeaderFile())
+                section = doxygen.Section('ref', 'Refer to Header File')
+                section.AddDescription('\link %s\n' % obj.GetHeaderFile())
+                section.AddDescription(' \endlink<p>\n')
+                classPage.AddSection(section)
+                fullPath = os.path.join(pObj.GetFileObj().GetPackageRootPath(), obj.GetHeaderFile())
+
+                self.ProcessSourceFileForInclude(fullPath, pObj, configFile)
+        rootArray.append(pageRoot)
+        return rootArray
+
+    def ProcessSourceFileForInclude(self, path, pObj, configFile, infObj=None):
+        """
+        @param path        the analysising file full path
+        @param pObj        package object
+        @param configFile  doxygen config file.
+        """
+
+        if gInGui:
+            wx.Yield()
+        if not os.path.exists(path):
+            ErrorMsg('Source file path %s does not exist!' % path)
+            return
+
+        if configFile.FileExists(path):
+            return
+
+        try:
+            f = open(path, 'r')
+            lines = f.readlines()
+            f.close()
+        except IOError:
+            ErrorMsg('Fail to open file %s' % path)
+            return
+
+        configFile.AddFile(path)
+        return
+        no = 0
+        for no in xrange(len(lines)):
+            if len(lines[no].strip()) == 0:
+                continue
+            if lines[no].strip()[:2] in ['##', '//', '/*', '*/']:
+                continue
+            index = lines[no].lower().find('include')
+            #mo = IncludePattern.finditer(lines[no].lower())
+            mo = re.match(r"^#\s*include\s+[<\"]([\\/\w.]+)[>\"]$", lines[no].strip().lower())
+            if not mo:
+                continue
+            mo = re.match(r"^[#\w\s]+[<\"]([\\/\w.]+)[>\"]$", lines[no].strip())
+            filePath = mo.groups()[0]
+
+            if filePath == None or len(filePath) == 0:
+                continue
+
+            # find header file in module's path firstly.
+            fullPath = None
+
+            if os.path.exists(os.path.join(os.path.dirname(path), filePath)):
+                # Find the file in current directory
+                fullPath = os.path.join(os.path.dirname(path), filePath).replace('\\', '/')
+            else:
+                # find in depedent package's include path
+                incObjs = pObj.GetFileObj().GetSectionObjectsByName('includes')
+                for incObj in incObjs:
+                    incPath = os.path.join(pObj.GetFileObj().GetPackageRootPath(), incObj.GetPath()).strip()
+                    incPath = os.path.realpath(os.path.join(incPath, filePath))
+                    if os.path.exists(incPath):
+                        fullPath = incPath
+                        break
+                if infObj != None:
+                    pkgInfObjs = infObj.GetSectionObjectsByName('packages')
+                    for obj in  pkgInfObjs:
+                        decObj = dec.DECFile(os.path.join(pObj.GetWorkspace(), obj.GetPath()))
+                        if not decObj:
+                            ErrorMsg ('Fail to create pacakge object for %s' % obj.GetPackageName())
+                            continue
+                        if not decObj.Parse():
+                            ErrorMsg ('Fail to load package object for %s' % obj.GetPackageName())
+                            continue
+                        incObjs = decObj.GetSectionObjectsByName('includes')
+                        for incObj in incObjs:
+                            incPath = os.path.join(decObj.GetPackageRootPath(), incObj.GetPath()).replace('\\', '/')
+                            if os.path.exists(os.path.join(incPath, filePath)):
+                                fullPath = os.path.join(os.path.join(incPath, filePath))
+                                break
+                        if fullPath != None:
+                            break
+
+            if fullPath == None and self.IsVerbose():
+                self.Log('Can not resolve header file %s for file %s in package %s\n' % (filePath, path, pObj.GetFileObj().GetFilename()), 'error')
+                return
+            else:
+                fullPath = fullPath.replace('\\', '/')
+                if self.IsVerbose():
+                    self.Log('Preprocessing: Add include file %s for file %s\n' % (fullPath, path))
+                #LogMsg ('Preprocessing: Add include file %s for file %s' % (fullPath, path))
+                self.ProcessSourceFileForInclude(fullPath, pObj, configFile, infObj)
+
+    def AddAllIncludeFiles(self, pObj, configFile):
+        objs = pObj.GetFileObj().GetSectionObjectsByName('includes')
+        for obj in objs:
+            incPath = os.path.join(pObj.GetFileObj().GetPackageRootPath(), obj.GetPath())
+            for root, dirs, files in os.walk(incPath):
+                for dir in dirs:
+                    if dir.lower() in _ignore_dir:
+                        dirs.remove(dir)
+                for file in files:
+                    path = os.path.normpath(os.path.join(root, file))
+                    configFile.AddFile(path.replace('/', '\\'))
+
+    def GeneratePcdSubPages(self, pObj, configFile):
+        """
+        Generate sub pages for package's PCD definition.
+        @param pObj         package object
+        @param configFile   config file object
+        """
+        rootArray = []
+        objs = pObj.GetFileObj().GetSectionObjectsByName('pcd')
+        if len(objs) == 0:
+            return []
+
+        pcdRootPage = doxygen.Page('PCD', 'pcd_root_page')
+        typeRootPageDict = {}
+        typeArchRootPageDict = {}
+        for obj in objs:
+            if obj.GetPcdType() not in typeRootPageDict.keys():
+                typeRootPageDict[obj.GetPcdType()] = doxygen.Page(obj.GetPcdType(), 'pcd_%s_root_page' % obj.GetPcdType())
+                pcdRootPage.AddPage(typeRootPageDict[obj.GetPcdType()])
+            typeRoot = typeRootPageDict[obj.GetPcdType()]
+            if self._arch != None:
+                pcdPage = doxygen.Page('%s' % obj.GetPcdName(),
+                                        'pcd_%s_%s_%s' % (obj.GetPcdType(), obj.GetArch(), obj.GetPcdName().split('.')[1]))
+                pcdPage.AddDescription('<br>\n'.join(obj.GetComment()) + '<br>\n')
+                section = doxygen.Section('PCDinformation', 'PCD Information')
+                desc  = '<TABLE>'
+                desc += '<TR>'
+                desc += '<TD><CAPTION>Name</CAPTION></TD>'
+                desc += '<TD><CAPTION>Token Space</CAPTION></TD>'
+                desc += '<TD><CAPTION>Token number</CAPTION></TD>'
+                desc += '<TD><CAPTION>Data Type</CAPTION></TD>'
+                desc += '<TD><CAPTION>Default Value</CAPTION></TD>'
+                desc += '</TR>'
+                desc += '<TR>'
+                desc += '<TD><CAPTION>%s</CAPTION></TD>' % obj.GetPcdName().split('.')[1]
+                desc += '<TD><CAPTION>%s</CAPTION></TD>' % obj.GetPcdName().split('.')[0]
+                desc += '<TD><CAPTION>%s</CAPTION></TD>' % obj.GetPcdToken()
+                desc += '<TD><CAPTION>%s</CAPTION></TD>' % obj.GetPcdDataType()
+                desc += '<TD><CAPTION>%s</CAPTION></TD>' % obj.GetPcdValue()
+                desc += '</TR>'
+                desc += '</TABLE>'
+                section.AddDescription(desc)
+                pcdPage.AddSection(section)
+                typeRoot.AddPage(pcdPage)
+            else:
+                keystr = obj.GetPcdType() + obj.GetArch()
+                if keystr not in typeArchRootPageDict.keys():
+                    typeArchRootPage = doxygen.Page(obj.GetArch(), 'pcd_%s_%s_root_page' % (obj.GetPcdType(), obj.GetArch()))
+                    typeArchRootPageDict[keystr] = typeArchRootPage
+                    typeRoot.AddPage(typeArchRootPage)
+                typeArchRoot = typeArchRootPageDict[keystr]
+                pcdPage = doxygen.Page('%s' % obj.GetPcdName(),
+                                        'pcd_%s_%s_%s' % (obj.GetPcdType(), obj.GetArch(), obj.GetPcdName().split('.')[1]))
+                pcdPage.AddDescription('<br>\n'.join(obj.GetComment()) + '<br>\n')
+                section = doxygen.Section('PCDinformation', 'PCD Information')
+                desc  = '<TABLE>'
+                desc += '<TR>'
+                desc += '<TD><CAPTION>Name</CAPTION></TD>'
+                desc += '<TD><CAPTION>Token Space</CAPTION></TD>'
+                desc += '<TD><CAPTION>Token number</CAPTION></TD>'
+                desc += '<TD><CAPTION>Data Type</CAPTION></TD>'
+                desc += '<TD><CAPTION>Default Value</CAPTION></TD>'
+                desc += '</TR>'
+                desc += '<TR>'
+                desc += '<TD><CAPTION>%s</CAPTION></TD>' % obj.GetPcdName().split('.')[1]
+                desc += '<TD><CAPTION>%s</CAPTION></TD>' % obj.GetPcdName().split('.')[0]
+                desc += '<TD><CAPTION>%s</CAPTION></TD>' % obj.GetPcdToken()
+                desc += '<TD><CAPTION>%s</CAPTION></TD>' % obj.GetPcdDataType()
+                desc += '<TD><CAPTION>%s</CAPTION></TD>' % obj.GetPcdValue()
+                desc += '</TR>'
+                desc += '</TABLE>'
+                section.AddDescription(desc)
+                pcdPage.AddSection(section)
+                typeArchRoot.AddPage(pcdPage)
+        return [pcdRootPage]
+
+    def _GenerateGuidSubPage(self, pObj, obj, configFile):
+        guidPage = doxygen.Page('%s' % obj.GetName(),
+                                'guid_%s_%s' % (obj.GetArch(), obj.GetName()))
+        comments = obj.GetComment()
+        if len(comments) != 0:
+            guidPage.AddDescription('<br>'.join(obj.GetComment()) + '<br>')
+        section = doxygen.Section('BasicGuidInfo', 'GUID Information')
+        desc  = '<TABLE>'
+        desc += '<TR>'
+        desc += '<TD><CAPTION>GUID\'s Guid Name</CAPTION></TD><TD><CAPTION>GUID\'s Guid</CAPTION></TD>'
+        desc += '</TR>'
+        desc += '<TR>'
+        desc += '<TD>%s</TD>' % obj.GetName()
+        desc += '<TD>%s</TD>' % obj.GetGuid()
+        desc += '</TR>'
+        desc += '</TABLE>'
+        section.AddDescription(desc)
+        guidPage.AddSection(section)
+        refFile = self.FindHeaderFileForGuid(pObj, obj.GetName(), configFile)
+        if refFile:
+            relPath = refFile[len(pObj.GetWorkspace()) + 1:]
+            if len(comments) == 0:
+                guidPage.AddDescription(' \\copydoc %s <br>' % relPath)
+
+            section = doxygen.Section('ref', 'Refer to Header File')
+            section.AddDescription('\link %s\n' % relPath)
+            section.AddDescription('\endlink\n')
+            self.ProcessSourceFileForInclude(refFile, pObj, configFile)
+            guidPage.AddSection(section)
+        return guidPage
+
+    def GenerateGuidSubPages(self, pObj, configFile):
+        """
+        Generate sub pages for package's GUID definition.
+        @param  pObj            package object
+        @param  configFilf      doxygen config file object
+        """
+        pageRoot = doxygen.Page('GUID', 'guid_root_page')
+        objs = pObj.GetFileObj().GetSectionObjectsByName('guids', self._arch)
+        if len(objs) == 0: return []
+        if self._arch != None:
+            for obj in objs:
+                pageRoot.AddPage(self._GenerateGuidSubPage(pObj, obj, configFile))
+        else:
+            guidArchRootPageDict = {}
+            for obj in objs:
+                if obj.GetArch() not in guidArchRootPageDict.keys():
+                    guidArchRoot = doxygen.Page(obj.GetArch(), 'guid_arch_root_%s' % obj.GetArch())
+                    pageRoot.AddPage(guidArchRoot)
+                    guidArchRootPageDict[obj.GetArch()] = guidArchRoot
+                guidArchRoot = guidArchRootPageDict[obj.GetArch()]
+                guidArchRoot.AddPage(self._GenerateGuidSubPage(pObj, obj, configFile))
+        return [pageRoot]
+
+    def _GeneratePpiSubPage(self, pObj, obj, configFile):
+        guidPage = doxygen.Page(obj.GetName(), 'ppi_page_%s' % obj.GetName())
+        comments = obj.GetComment()
+        if len(comments) != 0:
+            guidPage.AddDescription('<br>'.join(obj.GetComment()) + '<br>')
+        section = doxygen.Section('BasicPpiInfo', 'PPI Information')
+        desc  = '<TABLE>'
+        desc += '<TR>'
+        desc += '<TD><CAPTION>PPI\'s Guid Name</CAPTION></TD><TD><CAPTION>PPI\'s Guid</CAPTION></TD>'
+        desc += '</TR>'
+        desc += '<TR>'
+        desc += '<TD>%s</TD>' % obj.GetName()
+        desc += '<TD>%s</TD>' % obj.GetGuid()
+        desc += '</TR>'
+        desc += '</TABLE>'
+        section.AddDescription(desc)
+        guidPage.AddSection(section)
+        refFile = self.FindHeaderFileForGuid(pObj, obj.GetName(), configFile)
+        if refFile:
+            relPath = refFile[len(pObj.GetWorkspace()) + 1:]
+            if len(comments) == 0:
+                guidPage.AddDescription(' \\copydoc %s <br>' % relPath)
+            section = doxygen.Section('ref', 'Refer to Header File')
+            section.AddDescription('\link %s\n' % relPath)
+            section.AddDescription('\endlink\n')
+            self.ProcessSourceFileForInclude(refFile, pObj, configFile)
+            guidPage.AddSection(section)
+
+        return guidPage
+
+    def GeneratePpiSubPages(self, pObj, configFile):
+        """
+        Generate sub pages for package's GUID definition.
+        @param  pObj            package object
+        @param  configFilf      doxygen config file object
+        """
+        pageRoot = doxygen.Page('PPI', 'ppi_root_page')
+        objs = pObj.GetFileObj().GetSectionObjectsByName('ppis', self._arch)
+        if len(objs) == 0: return []
+        if self._arch != None:
+            for obj in objs:
+                pageRoot.AddPage(self._GeneratePpiSubPage(pObj, obj, configFile))
+        else:
+            guidArchRootPageDict = {}
+            for obj in objs:
+                if obj.GetArch() not in guidArchRootPageDict.keys():
+                    guidArchRoot = doxygen.Page(obj.GetArch(), 'ppi_arch_root_%s' % obj.GetArch())
+                    pageRoot.AddPage(guidArchRoot)
+                    guidArchRootPageDict[obj.GetArch()] = guidArchRoot
+                guidArchRoot = guidArchRootPageDict[obj.GetArch()]
+                guidArchRoot.AddPage(self._GeneratePpiSubPage(pObj, obj, configFile))
+        return [pageRoot]
+
+    def _GenerateProtocolSubPage(self, pObj, obj, configFile):
+        guidPage = doxygen.Page(obj.GetName(), 'protocol_page_%s' % obj.GetName())
+        comments = obj.GetComment()
+        if len(comments) != 0:
+            guidPage.AddDescription('<br>'.join(obj.GetComment()) + '<br>')
+        section = doxygen.Section('BasicProtocolInfo', 'PROTOCOL Information')
+        desc  = '<TABLE>'
+        desc += '<TR>'
+        desc += '<TD><CAPTION>PROTOCOL\'s Guid Name</CAPTION></TD><TD><CAPTION>PROTOCOL\'s Guid</CAPTION></TD>'
+        desc += '</TR>'
+        desc += '<TR>'
+        desc += '<TD>%s</TD>' % obj.GetName()
+        desc += '<TD>%s</TD>' % obj.GetGuid()
+        desc += '</TR>'
+        desc += '</TABLE>'
+        section.AddDescription(desc)
+        guidPage.AddSection(section)
+
+        refFile = self.FindHeaderFileForGuid(pObj, obj.GetName(), configFile)
+        if refFile:
+            relPath = refFile[len(pObj.GetWorkspace()) + 1:]
+            if len(comments) == 0:
+                guidPage.AddDescription(' \\copydoc %s <br>' % relPath)
+            section = doxygen.Section('ref', 'Refer to Header File')
+            section.AddDescription('\link %s\n' % relPath)
+            section.AddDescription('\endlink\n')
+            self.ProcessSourceFileForInclude(refFile, pObj, configFile)
+            guidPage.AddSection(section)
+
+        return guidPage
+
+    def GenerateProtocolSubPages(self, pObj, configFile):
+        """
+        Generate sub pages for package's GUID definition.
+        @param  pObj            package object
+        @param  configFilf      doxygen config file object
+        """
+        pageRoot = doxygen.Page('PROTOCOL', 'protocol_root_page')
+        objs = pObj.GetFileObj().GetSectionObjectsByName('protocols', self._arch)
+        if len(objs) == 0: return []
+        if self._arch != None:
+            for obj in objs:
+                pageRoot.AddPage(self._GenerateProtocolSubPage(pObj, obj, configFile))
+        else:
+            guidArchRootPageDict = {}
+            for obj in objs:
+                if obj.GetArch() not in guidArchRootPageDict.keys():
+                    guidArchRoot = doxygen.Page(obj.GetArch(), 'protocol_arch_root_%s' % obj.GetArch())
+                    pageRoot.AddPage(guidArchRoot)
+                    guidArchRootPageDict[obj.GetArch()] = guidArchRoot
+                guidArchRoot = guidArchRootPageDict[obj.GetArch()]
+                guidArchRoot.AddPage(self._GenerateProtocolSubPage(pObj, obj, configFile))
+        return [pageRoot]
+
+    def FindHeaderFileForGuid(self, pObj, name, configFile):
+        """
+        For declaration header file for GUID/PPI/Protocol.
+
+        @param pObj         package object
+        @param name         guid/ppi/protocol's name
+        @param configFile   config file object
+
+        @return full path of header file and None if not found.
+        """
+        startPath  = pObj.GetFileObj().GetPackageRootPath()
+        incPath    = os.path.join(startPath, 'Include').replace('\\', '/')
+        # if <PackagePath>/include exist, then search header under it.
+        if os.path.exists(incPath):
+            startPath = incPath
+
+        for root, dirs, files in os.walk(startPath):
+            for dir in dirs:
+                if dir.lower() in _ignore_dir:
+                    dirs.remove(dir)
+            for file in files:
+                fPath = os.path.join(root, file)
+                if not IsCHeaderFile(fPath):
+                    continue
+                try:
+                    f = open(fPath, 'r')
+                    lines = f.readlines()
+                    f.close()
+                except IOError:
+                    self.Log('Fail to open file %s\n' % fPath)
+                    continue
+                for line in lines:
+                    if line.find(name) != -1 and \
+                       line.find('extern') != -1:
+                        return fPath.replace('\\', '/')
+        return None
+
+    def GetPackageModuleList(self, pObj):
+        """
+        Get all module's INF path under package's root path
+        @param     pObj  package object
+        @return    arrary of INF full path
+        """
+        mArray = []
+        packPath = pObj.GetFileObj().GetPackageRootPath()
+        if not os.path.exists:
+            return None
+        for root, dirs, files in os.walk(packPath):
+            for dir in dirs:
+                if dir.lower() in _ignore_dir:
+                    dirs.remove(dir)
+            for file in files:
+                if CheckPathPostfix(file, 'inf'):
+                    fPath = os.path.join(root, file).replace('\\', '/')
+                    mArray.append(fPath)
+        return mArray
+
+    def GenerateModulePages(self, pObj, configFile):
+        """
+        Generate sub pages for package's module which is under the package
+        root directory.
+
+        @param  pObj            package object
+        @param  configFilf      doxygen config file object
+        """
+        infList = self.GetPackageModuleList(pObj)
+        rootPages = []
+        libObjs = []
+        modObjs = []
+        for infpath in infList:
+            infObj = inf.INFFile(infpath)
+            #infObj = INFFileObject.INFFile (pObj.GetWorkspacePath(),
+            #                                inf)
+            if not infObj:
+                self.Log('Fail create INF object for %s' % inf)
+                continue
+            if not infObj.Parse():
+                self.Log('Fail to load INF file %s' % inf)
+                continue
+            if infObj.GetProduceLibraryClass() != None:
+                libObjs.append(infObj)
+            else:
+                modObjs.append(infObj)
+
+        if len(libObjs) != 0:
+            libRootPage = doxygen.Page('Libraries', 'lib_root_page')
+            rootPages.append(libRootPage)
+            for libInf in libObjs:
+                libRootPage.AddPage(self.GenerateModulePage(pObj, libInf, configFile, True))
+
+        if len(modObjs) != 0:
+            modRootPage = doxygen.Page('Modules', 'module_root_page')
+            rootPages.append(modRootPage)
+            for modInf in modObjs:
+                modRootPage.AddPage(self.GenerateModulePage(pObj, modInf, configFile, False))
+
+        return rootPages
+
+    def GenerateModulePage(self, pObj, infObj, configFile, isLib):
+        """
+        Generate page for a module/library.
+        @param infObj     INF file object for module/library
+        @param configFile doxygen config file object
+        @param isLib      Whether this module is libary
+
+        @param module doxygen page object
+        """
+        workspace = pObj.GetWorkspace()
+        refDecObjs = []
+        for obj in  infObj.GetSectionObjectsByName('packages'):
+            decObj = dec.DECFile(os.path.join(workspace, obj.GetPath()))
+            if not decObj:
+                ErrorMsg ('Fail to create pacakge object for %s' % obj.GetPackageName())
+                continue
+            if not decObj.Parse():
+                ErrorMsg ('Fail to load package object for %s' % obj.GetPackageName())
+                continue
+            refDecObjs.append(decObj)
+
+        modPage = doxygen.Page('%s' % infObj.GetBaseName(),
+                               'module_%s' % infObj.GetBaseName())
+        modPage.AddDescription(infObj.GetFileHeader())
+
+        basicInfSection = doxygen.Section('BasicModuleInformation', 'Basic Module Information')
+        desc = "<TABLE>"
+        for obj in infObj.GetSectionObjectsByName('defines'):
+            key = obj.GetKey()
+            value = obj.GetValue()
+            if key not in _inf_key_description_mapping_table.keys(): continue
+            if key == 'LIBRARY_CLASS' and value.find('|') != -1:
+                clsname, types = value.split('|')
+                desc += '<TR>'
+                desc += '<TD><B>%s</B></TD>' % _inf_key_description_mapping_table[key]
+                desc += '<TD>%s</TD>' % clsname
+                desc += '</TR>'
+
+                desc += '<TR>'
+                desc += '<TD><B>Supported Module Types</B></TD>'
+                desc += '<TD>%s</TD>' % types
+                desc += '</TR>'
+            else:
+                desc += '<TR>'
+                desc += '<TD><B>%s</B></TD>' % _inf_key_description_mapping_table[key]
+                if key == 'EFI_SPECIFICATION_VERSION' and value == '0x00020000':
+                    value = '2.0'
+                desc += '<TD>%s</TD>' % value
+                desc += '</TR>'
+        desc += '</TABLE>'
+        basicInfSection.AddDescription(desc)
+        modPage.AddSection(basicInfSection)
+
+        # Add protocol section
+        data  = []
+        for obj in infObj.GetSectionObjectsByName('pcd', self._arch):
+            data.append(obj.GetPcdName().strip())
+        if len(data) != 0:
+            s = doxygen.Section('Pcds', 'Pcds')
+            desc = "<TABLE>"
+            desc += '<TR><TD><B>PCD Name</B></TD><TD><B>TokenSpace</B></TD><TD><B>Package</B></TD></TR>'
+            for item in data:
+                desc += '<TR>'
+                desc += '<TD>%s</TD>' % item.split('.')[1]
+                desc += '<TD>%s</TD>' % item.split('.')[0]
+                pkgbasename = self.SearchPcdPackage(item, workspace, refDecObjs)
+                desc += '<TD>%s</TD>' % pkgbasename
+                desc += '</TR>'
+            desc += "</TABLE>"
+            s.AddDescription(desc)
+            modPage.AddSection(s)
+
+        # Add protocol section
+        #sects = infObj.GetSectionByString('protocol')
+        data  = []
+        #for sect in sects:
+        for obj in infObj.GetSectionObjectsByName('protocol', self._arch):
+            data.append(obj.GetName().strip())
+        if len(data) != 0:
+            s = doxygen.Section('Protocols', 'Protocols')
+            desc = "<TABLE>"
+            desc += '<TR><TD><B>Name</B></TD><TD><B>Package</B></TD></TR>'
+            for item in data:
+                desc += '<TR>'
+                desc += '<TD>%s</TD>' % item
+                pkgbasename = self.SearchProtocolPackage(item, workspace, refDecObjs)
+                desc += '<TD>%s</TD>' % pkgbasename
+                desc += '</TR>'
+            desc += "</TABLE>"
+            s.AddDescription(desc)
+            modPage.AddSection(s)
+
+        # Add ppi section
+        #sects = infObj.GetSectionByString('ppi')
+        data  = []
+        #for sect in sects:
+        for obj in infObj.GetSectionObjectsByName('ppi', self._arch):
+            data.append(obj.GetName().strip())
+        if len(data) != 0:
+            s = doxygen.Section('Ppis', 'Ppis')
+            desc = "<TABLE>"
+            desc += '<TR><TD><B>Name</B></TD><TD><B>Package</B></TD></TR>'
+            for item in data:
+                desc += '<TR>'
+                desc += '<TD>%s</TD>' % item
+                pkgbasename = self.SearchPpiPackage(item, workspace, refDecObjs)
+                desc += '<TD>%s</TD>' % pkgbasename
+                desc += '</TR>'
+            desc += "</TABLE>"
+            s.AddDescription(desc)
+            modPage.AddSection(s)
+
+        # Add guid section
+        #sects = infObj.GetSectionByString('guid')
+        data  = []
+        #for sect in sects:
+        for obj in infObj.GetSectionObjectsByName('guid', self._arch):
+            data.append(obj.GetName().strip())
+        if len(data) != 0:
+            s = doxygen.Section('Guids', 'Guids')
+            desc = "<TABLE>"
+            desc += '<TR><TD><B>Name</B></TD><TD><B>Package</B></TD></TR>'
+            for item in data:
+                desc += '<TR>'
+                desc += '<TD>%s</TD>' % item
+                pkgbasename = self.SearchGuidPackage(item, workspace, refDecObjs)
+                desc += '<TD>%s</TD>' % pkgbasename
+                desc += '</TR>'
+            desc += "</TABLE>"
+            s.AddDescription(desc)
+            modPage.AddSection(s)
+
+        section = doxygen.Section('LibraryClasses', 'Library Classes')
+        desc = "<TABLE>"
+        desc += '<TR><TD><B>Name</B></TD><TD><B>Type</B></TD><TD><B>Package</B></TD><TD><B>Header File</B></TD></TR>'
+        if isLib:
+            desc += '<TR>'
+            desc += '<TD>%s</TD>' % infObj.GetProduceLibraryClass()
+            desc += '<TD>Produce</TD>'
+            try:
+                pkgname, hPath = self.SearchLibraryClassHeaderFile(infObj.GetProduceLibraryClass(),
+                                                              workspace,
+                                                              refDecObjs)
+            except:
+                self.Log ('fail to get package header file for lib class %s' % infObj.GetProduceLibraryClass())
+                pkgname = 'NULL'
+                hPath   = 'NULL'
+            desc += '<TD>%s</TD>' % pkgname
+            if hPath != "NULL":
+                #desc += '<TD>\link %s \endlink</TD>' % hPath
+                desc += '<TD>%s</TD>' % hPath
+            else:
+                desc += '<TD>%s</TD>' % hPath
+            desc += '</TR>'
+        for lcObj in infObj.GetSectionObjectsByName('libraryclasses', self._arch):
+            desc += '<TR>'
+            desc += '<TD>%s</TD>' % lcObj.GetClass()
+            retarr = self.SearchLibraryClassHeaderFile(lcObj.GetClass(),
+                                                       workspace,
+                                                       refDecObjs)
+            if retarr != None:
+                pkgname, hPath = retarr
+            else:
+                self.Log('Fail find the library class %s definition from module %s dependent package!' % (lcObj.GetClass(), infObj.GetFilename()), 'error')
+                pkgname = 'NULL'
+                hPath   = 'NULL'
+            desc += '<TD>Consume</TD>'
+            desc += '<TD>%s</TD>' % pkgname
+            desc += '<TD>%s</TD>' % hPath
+            desc += '</TR>'
+        desc += "</TABLE>"
+        section.AddDescription(desc)
+        modPage.AddSection(section)
+
+        section = doxygen.Section('SourceFiles', 'Source Files')
+        section.AddDescription('<ul>\n')
+        for obj in infObj.GetSourceObjects(self._arch, self._tooltag):
+            sPath = infObj.GetModuleRootPath()
+            sPath = os.path.join(sPath, obj.GetSourcePath()).replace('\\', '/').strip()
+            if sPath.lower().endswith('.uni') or sPath.lower().endswith('.s') or sPath.lower().endswith('.asm') or sPath.lower().endswith('.nasm'):
+                newPath = self.TranslateUniFile(sPath)
+                configFile.AddFile(newPath)
+                newPath = newPath[len(pObj.GetWorkspace()) + 1:]
+                section.AddDescription('<li> \link %s \endlink </li>' %  newPath)
+            else:
+                self.ProcessSourceFileForInclude(sPath, pObj, configFile, infObj)
+                sPath = sPath[len(pObj.GetWorkspace()) + 1:]
+                section.AddDescription('<li>\link %s \endlink </li>' % sPath)
+        section.AddDescription('</ul>\n')
+        modPage.AddSection(section)
+
+        #sects = infObj.GetSectionByString('depex')
+        data  = []
+        #for sect in sects:
+        for obj in infObj.GetSectionObjectsByName('depex'):
+            data.append(str(obj))
+        if len(data) != 0:
+            s = doxygen.Section('DependentSection', 'Module Dependencies')
+            s.AddDescription('<br>'.join(data))
+            modPage.AddSection(s)
+
+        return modPage
+
+    def TranslateUniFile(self, path):
+        newpath = path + '.dox'
+        #import core.textfile as textfile
+        #file = textfile.TextFile(path)
+
+        try:
+            file = open(path, 'rb')
+        except (IOError, OSError), msg:
+            return None
+
+        t = file.read()
+        file.close()
+
+        output = '/** @file \n'
+        #output = '<html><body>'
+        arr = t.split('\r\n')
+        for line in arr:
+            if line.find('@file') != -1:
+                continue
+            if line.find('*/') != -1:
+                continue
+            line = line.strip()
+            if line.strip().startswith('/'):
+                arr = line.split(' ')
+                if len(arr) > 1:
+                    line = ' '.join(arr[1:])
+                else:
+                    continue
+            output += '%s<br>\n' % line
+        output += '**/'
+
+        if os.path.exists(newpath):
+            os.remove(newpath)
+
+        file = open(newpath, "w")
+        file.write(output)
+        file.close()
+        return newpath
+
+    def SearchPcdPackage(self, pcdname, workspace, decObjs):
+        for decObj in  decObjs:
+            for pcd in decObj.GetSectionObjectsByName('pcd'):
+                if pcdname == pcd.GetPcdName():
+                    return decObj.GetBaseName()
+        return None
+
+    def SearchProtocolPackage(self, protname, workspace, decObjs):
+        for decObj in  decObjs:
+            for proto in decObj.GetSectionObjectsByName('protocol'):
+                if protname == proto.GetName():
+                    return decObj.GetBaseName()
+        return None
+
+    def SearchPpiPackage(self, ppiname, workspace, decObjs):
+        for decObj in  decObjs:
+            for ppi in decObj.GetSectionObjectsByName('ppi'):
+                if ppiname == ppi.GetName():
+                    return decObj.GetBaseName()
+        return None
+
+    def SearchGuidPackage(self, guidname, workspace, decObjs):
+        for decObj in  decObjs:
+            for guid in decObj.GetSectionObjectsByName('guid'):
+                if guidname == guid.GetName():
+                    return decObj.GetBaseName()
+        return None
+
+    def SearchLibraryClassHeaderFile(self, className, workspace, decObjs):
+        for decObj in  decObjs:
+            for cls in decObj.GetSectionObjectsByName('libraryclasses'):
+                if cls.GetClassName().strip() == className:
+                    path = cls.GetHeaderFile().strip()
+                    path = os.path.join(decObj.GetPackageRootPath(), path)
+                    path = path[len(workspace) + 1:]
+                    return decObj.GetBaseName(), path.replace('\\', '/')
+
+        return None
+
+    def _ConvertPathToDoxygen(self, path, pObj):
+        pRootPath = pObj.GetWorkspace()
+        path = path[len(pRootPath) + 1:]
+        return path.replace('\\', '/')
+
+def IsCHeaderFile(path):
+    return CheckPathPostfix(path, 'h')
+
+def CheckPathPostfix(path, str):
+    index = path.rfind('.')
+    if index == -1:
+        return False
+    if path[index + 1:].lower() == str.lower():
+        return True
+    return False
diff --git a/BaseTools/Scripts/PackageDocumentTools/plugins/EdkPlugins/edk2/model/dsc.py b/BaseTools/Scripts/PackageDocumentTools/plugins/EdkPlugins/edk2/model/dsc.py
new file mode 100644
index 0000000..f8ed531
--- /dev/null
+++ b/BaseTools/Scripts/PackageDocumentTools/plugins/EdkPlugins/edk2/model/dsc.py
@@ -0,0 +1,201 @@
+## @file
+#
+# Copyright (c) 2011 - 2018, Intel Corporation. All rights reserved.<BR>
+#
+# This program and the accompanying materials are licensed and made available
+# under the terms and conditions of the BSD License which accompanies this
+# distribution. The full text of the license may be found at
+# http://opensource.org/licenses/bsd-license.php
+#
+# THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+# WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+#
+
+import plugins.EdkPlugins.basemodel.ini as ini
+import re, os
+from plugins.EdkPlugins.basemodel.message import *
+
+class DSCFile(ini.BaseINIFile):
+    def GetSectionInstance(self, parent, name, isCombined=False):
+        return DSCSection(parent, name, isCombined)
+
+    def GetComponents(self):
+        return self.GetSectionObjectsByName('Components')
+
+class DSCSection(ini.BaseINISection):
+    def GetSectionINIObject(self, parent):
+        type = self.GetType()
+
+        if type.lower() == 'components':
+            return DSCComponentObject(self)
+        if type.lower() == 'libraryclasses':
+            return DSCLibraryClassObject(self)
+        if type.lower() == 'defines':
+            return ini.BaseINISectionObject(self)
+        if type.lower() == 'pcdsfeatureflag' or \
+           type.lower() == 'pcdsfixedatbuild' or \
+           type.lower() == 'pcdspatchableinmodule' or\
+           type.lower() == 'pcdsdynamicdefault' or \
+           type.lower() == 'pcdsdynamicex' or \
+           type.lower() == 'pcdsdynamichii' or \
+           type.lower() == 'pcdsdynamicvpd':
+            return DSCPcdObject(self)
+
+        return DSCSectionObject(self)
+
+    def GetType(self):
+        arr = self._name.split('.')
+        return arr[0].strip()
+
+    def GetArch(self):
+        arr = self._name.split('.')
+        if len(arr) == 1:
+            return 'common'
+        return arr[1]
+
+    def GetModuleType(self):
+        arr = self._name.split('.')
+        if len(arr) < 3:
+            return 'common'
+        return arr[2]
+
+class DSCSectionObject(ini.BaseINISectionObject):
+    def GetArch(self):
+        return self.GetParent().GetArch()
+
+class DSCPcdObject(DSCSectionObject):
+
+    def __init__(self, parent):
+        ini.BaseINISectionObject.__init__(self, parent)
+        self._name = None
+
+    def Parse(self):
+        line = self.GetLineByOffset(self._start).strip().split('#')[0]
+        self._name   = line.split('|')[0]
+        self._value  = line.split('|')[1]
+        return True
+
+    def GetPcdName(self):
+        return self._name
+
+    def GetPcdType(self):
+        return self.GetParent().GetType()
+
+    def GetPcdValue(self):
+        return self._value
+
+class DSCLibraryClassObject(DSCSectionObject):
+    def __init__(self, parent):
+        ini.BaseINISectionObject.__init__(self, parent)
+
+    def GetClass(self):
+        line = self.GetLineByOffset(self._start)
+        return line.split('#')[0].split('|')[0].strip()
+
+    def GetInstance(self):
+        line = self.GetLineByOffset(self._start)
+        return line.split('#')[0].split('|')[1].strip()
+
+    def GetArch(self):
+        return self.GetParent().GetArch()
+
+    def GetModuleType(self):
+        return self.GetParent().GetModuleType()
+
+class DSCComponentObject(DSCSectionObject):
+
+    def __init__(self, parent):
+        ini.BaseINISectionObject.__init__(self, parent)
+        self._OveridePcds      = {}
+        self._OverideLibraries = {}
+        self._Filename         = ''
+
+    def __del__(self):
+        self._OverideLibraries.clear()
+        self._OverideLibraries.clear()
+        ini.BaseINISectionObject.__del__(self)
+
+    def AddOverideLib(self, libclass, libinstPath):
+        if libclass not in self._OverideLibraries.keys():
+            self._OverideLibraries[libclass] = libinstPath
+
+    def AddOveridePcd(self, name, type, value=None):
+        if type not in self._OveridePcds.keys():
+            self._OveridePcds[type] = []
+        self._OveridePcds[type].append((name, value))
+
+    def GetOverideLibs(self):
+        return self._OverideLibraries
+
+    def GetArch(self):
+        return self.GetParent().GetArch()
+
+    def GetOveridePcds(self):
+        return self._OveridePcds
+
+    def GetFilename(self):
+        return self.GetLineByOffset(self._start).split('#')[0].split('{')[0].strip()
+
+    def SetFilename(self, fName):
+        self._Filename = fName
+
+    def Parse(self):
+        if (self._start < self._end):
+            #
+            # The first line is inf path and could be ignored
+            # The end line is '}' and could be ignored
+            #
+            curr = self._start + 1
+            end  = self._end - 1
+            OverideName = ''
+            while (curr <= end):
+                line = self.GetLineByOffset(curr).strip()
+                if len(line) > 0 and line[0] != '#':
+                    line = line.split('#')[0].strip()
+                    if line[0] == '<':
+                        OverideName = line[1:len(line)-1]
+                    elif OverideName.lower() == 'libraryclasses':
+                        arr = line.split('|')
+                        self._OverideLibraries[arr[0].strip()] = arr[1].strip()
+                    elif OverideName.lower() == 'pcds':
+                        ErrorMsg('EDES does not support PCD overide',
+                                 self.GetFileName(),
+                                 self.GetParent().GetLinenumberByOffset(curr))
+                curr = curr + 1
+        return True
+
+    def GenerateLines(self):
+        lines = []
+        hasLib = False
+        hasPcd = False
+        if len(self._OverideLibraries) != 0:
+            hasLib = True
+        if len(self._OveridePcds) != 0:
+            hasPcd = True
+
+        if hasLib or hasPcd:
+            lines.append(('  %s {\n' % self._Filename))
+        else:
+            lines.append(('  %s \n' % self._Filename))
+            return lines
+
+        if hasLib:
+            lines.append('    <LibraryClasses>\n')
+            for libKey in self._OverideLibraries.keys():
+                lines.append('      %s|%s\n' % (libKey, self._OverideLibraries[libKey]))
+
+        if hasPcd:
+            for key in self._OveridePcds.keys():
+                lines.append('    <%s>\n' % key)
+
+                for name, value in self._OveridePcds[key]:
+                    if value != None:
+                        lines.append('      %s|%s\n' % (name, value))
+                    else:
+                        lines.append('      %s\n' % name)
+
+        if hasLib or hasPcd:
+            lines.append('  }\n')
+
+        return lines
+
diff --git a/BaseTools/Scripts/PackageDocumentTools/plugins/EdkPlugins/edk2/model/inf.py b/BaseTools/Scripts/PackageDocumentTools/plugins/EdkPlugins/edk2/model/inf.py
new file mode 100644
index 0000000..9d70fbc
--- /dev/null
+++ b/BaseTools/Scripts/PackageDocumentTools/plugins/EdkPlugins/edk2/model/inf.py
@@ -0,0 +1,341 @@
+## @file
+#
+# Copyright (c) 2011 - 2018, Intel Corporation. All rights reserved.<BR>
+#
+# This program and the accompanying materials are licensed and made available
+# under the terms and conditions of the BSD License which accompanies this
+# distribution. The full text of the license may be found at
+# http://opensource.org/licenses/bsd-license.php
+#
+# THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+# WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+#
+
+import plugins.EdkPlugins.basemodel.ini as ini
+import re, os
+from plugins.EdkPlugins.basemodel.message import *
+
+class INFFile(ini.BaseINIFile):
+    _libobjs = {}
+
+    def GetSectionInstance(self, parent, name, isCombined=False):
+        return INFSection(parent, name, isCombined)
+
+    def GetProduceLibraryClass(self):
+        obj = self.GetDefine("LIBRARY_CLASS")
+        if obj == None: return None
+
+        return obj.split('|')[0].strip()
+
+    def GetSectionObjectsByName(self, name, arch=None):
+        arr = []
+        sects = self.GetSectionByName(name)
+        for sect in sects:
+            # skip unmatched archtecture content
+            if not sect.IsArchMatch(arch):
+                continue
+
+            for obj in sect.GetObjects():
+                arr.append(obj)
+
+        return arr
+
+    def GetSourceObjects(self, arch=None, tool=None):
+        arr = []
+        sects = self.GetSectionByName('sources')
+        for sect in sects:
+            # skip unmatched archtecture content
+            if not sect.IsArchMatch(arch):
+                continue
+
+            for obj in sect.GetObjects():
+                if not obj.IsMatchFamily(tool):
+                    continue
+                arr.append(obj)
+
+        return arr
+
+    def Parse(self):
+        if not ini.BaseINIFile.Parse(self):
+            return False
+        classname = self.GetProduceLibraryClass()
+        if classname != None:
+            libobjdict = INFFile._libobjs
+            if libobjdict.has_key(classname):
+                if self not in libobjdict[classname]:
+                    libobjdict[classname].append(self)
+            else:
+                libobjdict[classname] = [self]
+
+        return True
+
+    def GetBaseName(self):
+        return self.GetDefine("BASE_NAME").strip()
+
+    def GetModuleRootPath(self):
+        return os.path.dirname(self.GetFilename())
+
+    def Clear(self):
+        classname = self.GetProduceLibraryClass()
+        if classname != None:
+            libobjdict = INFFile._libobjs
+            libobjdict[classname].remove(self)
+            if len(libobjdict[classname]) == 0:
+                del libobjdict[classname]
+        ini.BaseINIFile.Clear(self)
+
+
+class INFSection(ini.BaseINISection):
+    def GetSectionINIObject(self, parent):
+        type = self.GetType()
+
+        if type.lower() == 'libraryclasses':
+            return INFLibraryClassObject(self)
+        if type.lower() == 'sources':
+            return INFSourceObject(self)
+        if type.lower().find('pcd') != -1:
+            return INFPcdObject(self)
+        if type.lower() == 'packages':
+            return INFDependentPackageObject(self)
+        if type.lower() in ['guids', 'protocols', 'ppis']:
+            return INFGuidObject(self)
+        if type.lower() == 'defines':
+            return INFDefineSectionObject(self)
+        return INFSectionObject(self)
+
+    def GetType(self):
+        arr = self._name.split('.')
+        return arr[0].strip()
+
+    def GetArch(self):
+        arr = self._name.split('.')
+        if len(arr) == 1:
+            return 'common'
+        return arr[1]
+
+    def IsArchMatch(self, arch):
+        if arch == None or self.GetArch() == 'common':
+            return True
+
+        if self.GetArch().lower() != arch.lower():
+            return False
+
+        return True
+
+class INFSectionObject(ini.BaseINISectionObject):
+    def GetArch(self):
+        return self.GetParent().GetArch()
+
+class INFDefineSectionObject(INFSectionObject):
+    def __init__(self, parent):
+        INFSectionObject.__init__(self, parent)
+        self._key = None
+        self._value = None
+
+    def Parse(self):
+        assert (self._start == self._end), 'The object in define section must be in single line'
+
+        line = self.GetLineByOffset(self._start).strip()
+
+        line = line.split('#')[0]
+        arr  = line.split('=')
+        if len(arr) != 2:
+            ErrorMsg('Invalid define section object',
+                   self.GetFilename(),
+                   self._start
+                   )
+            return False
+
+        self._key   = arr[0].strip()
+        self._value = arr[1].strip()
+
+        return True
+
+    def GetKey(self):
+        return self._key
+
+    def GetValue(self):
+        return self._value
+
+class INFLibraryClassObject(INFSectionObject):
+    _objs = {}
+    def __init__(self, parent):
+        INFSectionObject.__init__(self, parent)
+        self._classname = None
+
+    def GetClass(self):
+        return self._classname
+
+    def Parse(self):
+        self._classname = self.GetLineByOffset(self._start).split('#')[0].strip()
+        objdict = INFLibraryClassObject._objs
+        if objdict.has_key(self._classname):
+            objdict[self._classname].append(self)
+        else:
+            objdict[self._classname] = [self]
+        return True
+
+    def Destroy(self):
+        objdict = INFLibraryClassObject._objs
+        objdict[self._classname].remove(self)
+        if len(objdict[self._classname]) == 0:
+            del objdict[self._classname]
+
+    def GetName(self):
+        return self._classname
+
+    @staticmethod
+    def GetObjectDict():
+        return INFLibraryClassObject._objs
+
+class INFDependentPackageObject(INFSectionObject):
+    def GetPath(self):
+        return self.GetLineByOffset(self._start).split('#')[0].strip()
+
+class INFSourceObject(INFSectionObject):
+    _objs = {}
+    def __init__(self, parent):
+        INFSectionObject.__init__(self, parent)
+
+        self.mSourcename  = None
+        self.mToolCode    = None
+        self.mFamily      = None
+        self.mTagName     = None
+        self.mFeaturePcd  = None
+        self.mFilename    = None
+
+    def GetSourcePath(self):
+        return self.mSourcename
+
+    def GetSourceFullPath(self):
+        path = os.path.dirname(self.GetFilename())
+        path = os.path.join(path, self.GetSourcePath())
+        return os.path.normpath(path)
+
+    def GetToolCode(self):
+        return self.mToolCode
+
+    def GetFamily(self):
+        return self.mFamily
+
+    def GetTagName(self):
+        return self.mTagName
+
+    def GetFeaturePcd(self):
+        return self.mFeaturePcd
+
+    def Parse(self):
+        line = self.GetLineByOffset(self._start).strip().split('#')[0]
+
+        arr = line.split('|')
+
+        self.mSourcename = arr[0].strip()
+        if len(arr) >= 2:
+            self.mFamily = arr[1].strip()
+        if len(arr) >= 3:
+            self.mTagName = arr[2].strip()
+        if len(arr) >= 4:
+            self.mToolCode = arr[3].strip()
+        if len(arr) >= 5:
+            self.mFeaturePcd = arr[4].strip()
+
+        self.mFilename = os.path.basename(self.GetSourceFullPath())
+        objdict = INFSourceObject._objs
+        if not objdict.has_key(self.mFilename):
+            objdict[self.mFilename] = [self]
+        else:
+            objdict[self.mFilename].append(self)
+
+        return True
+
+    def GetName(self):
+        return self.mFilename
+
+    def Destroy(self):
+        objdict = INFSourceObject._objs
+        objdict[self.mFilename].remove(self)
+        if len(objdict[self.mFilename]) == 0:
+            del objdict[self.mFilename]
+
+    def IsMatchFamily(self, family):
+        if family == None:
+            return True
+        if self.mFamily != None:
+            if family.strip().lower() == self.mFamily.lower():
+                return True
+            else:
+                return False
+        else:
+            fname = self.GetSourcePath()
+            if fname.endswith('.S') and family.lower() != 'gcc':
+                return False
+            if fname.endswith('.s') and (self.GetArch().lower() != 'ipf' and self.GetArch().lower() != 'common'):
+                return False
+            if fname.lower().endswith('.asm') and (family.lower() != 'msft' and family.lower() != 'intel'):
+                return False
+        return True
+
+    @staticmethod
+    def GetObjectDict():
+        return INFSourceObject._objs
+
+class INFPcdObject(INFSectionObject):
+    _objs = {}
+
+    def __init__(self, parent):
+        INFSectionObject.__init__(self, parent)
+
+        self.mPcdType      = None
+        self.mDefaultValue = None
+        self.mPcdName      = None
+
+    @staticmethod
+    def GetObjectDict():
+        return INFPcdObject._objs
+
+    def Parse(self):
+        line = self.GetLineByOffset(self._start).strip().split('#')[0]
+
+        arr = line.split('|')
+        self.mPcdName       = arr[0].strip()
+
+        if len(arr) >= 2:
+            self.mDefaultValue = arr[1].strip()
+
+        objdict = INFPcdObject._objs
+        if objdict.has_key(self.GetName()):
+            if self not in objdict[self.GetName()]:
+                objdict[self.GetName()].append(self)
+        else:
+            objdict[self.GetName()] = [self]
+        return True
+
+    def GetPcdName(self):
+        return self.mPcdName
+
+    def GetPcdType(self):
+        return self.GetParent().GetType()
+
+    def GetName(self):
+        return self.mPcdName.split('.')[1]
+
+    def Destroy(self):
+        objdict = INFPcdObject._objs
+        objdict[self.GetName()].remove(self)
+        if len(objdict[self.GetName()]) == 0:
+            del objdict[self.GetName()]
+
+class INFGuidObject(INFSectionObject):
+    def __init__(self, parent):
+        INFSectionObject.__init__(self, parent)
+        self._name = None
+
+    def Parse(self):
+        line = self.GetLineByOffset(self._start).strip().split('#')[0].split("|")[0]
+        self._name =  line.strip()
+        return True
+
+    def GetName(self):
+        return self._name
+
+
diff --git a/BaseTools/Scripts/PackageDocumentTools/plugins/__init__.py b/BaseTools/Scripts/PackageDocumentTools/plugins/__init__.py
new file mode 100644
index 0000000..3e4ee53
--- /dev/null
+++ b/BaseTools/Scripts/PackageDocumentTools/plugins/__init__.py
@@ -0,0 +1,12 @@
+## @file
+#
+# Copyright (c) 2011 - 2018, Intel Corporation. All rights reserved.<BR>
+#
+# This program and the accompanying materials are licensed and made available
+# under the terms and conditions of the BSD License which accompanies this
+# distribution. The full text of the license may be found at
+# http://opensource.org/licenses/bsd-license.php
+#
+# THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+# WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+#
-- 
2.6.1.windows.1



             reply	other threads:[~2018-03-15  6:39 UTC|newest]

Thread overview: 2+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2018-03-15  6:45 Yonghong Zhu [this message]
2018-03-19  0:54 ` [Patch] BaseTools: Add PackageDocumentTools into Scripts folder Zeng, Star

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-list from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=1521096351-17908-1-git-send-email-yonghong.zhu@intel.com \
    --to=devel@edk2.groups.io \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox