text: ## @file
  # This file is used to be the main entrance of EOT tool
  #
  # Copyright (c) 2008 - 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 Modules
  #
  from __future__ import absolute_import
  import Common.LongFilePathOs as os, time, glob
  import Common.EdkLogger as EdkLogger
  import Eot.EotGlobalData as EotGlobalData
  from optparse import OptionParser
  from Common.StringUtils import NormPath
  from Common import BuildToolError
  from Common.Misc import GuidStructureStringToGuidString
  from collections import OrderedDict as sdict
  from Eot.Parser import *
  from Eot.InfParserLite import EdkInfParser
  from Common.StringUtils import GetSplitValueList
  from Eot import c
  from Eot import Database
  from array import array
  from Eot.Report import Report
  from Common.BuildVersion import gBUILD_VERSION
  from Eot.Parser import ConvertGuid
  from Common.LongFilePathSupport import OpenLongFilePath as open
  import struct
  import uuid
  import copy
  import codecs
  from GenFds.AprioriSection import DXE_APRIORI_GUID, PEI_APRIORI_GUID
  
  gGuidStringFormat = "%08X-%04X-%04X-%02X%02X-%02X%02X%02X%02X%02X%02X"
  gIndention = -4
  
  class Image(array):
      _HEADER_ = struct.Struct("")
      _HEADER_SIZE_ = _HEADER_.size
  
      def __new__(cls, *args, **kwargs):
          return array.__new__(cls, 'B')
  
      def __init__(self, ID=None):
          if ID is None:
              self._ID_ = str(uuid.uuid1()).upper()
          else:
              self._ID_ = ID
          self._BUF_ = None
          self._LEN_ = None
          self._OFF_ = None
  
          self._SubImages = sdict() # {offset: Image()}
  
          array.__init__(self)
  
      def __repr__(self):
          return self._ID_
  
      def __len__(self):
          Len = array.__len__(self)
          for Offset in self._SubImages.keys():
              Len += len(self._SubImages[Offset])
          return Len
  
      def _Unpack(self):
          self.extend(self._BUF_[self._OFF_ : self._OFF_ + self._LEN_])
          return len(self)
  
      def _Pack(self, PadByte=0xFF):
          raise NotImplementedError
  
      def frombuffer(self, Buffer, Offset=0, Size=None):
          self._BUF_ = Buffer
          self._OFF_ = Offset
          # we may need the Size information in advance if it's given
          self._LEN_ = Size
          self._LEN_ = self._Unpack()
  
      def empty(self):
          del self[0:]
  
      def GetField(self, FieldStruct, Offset=0):
          return FieldStruct.unpack_from(self, Offset)
  
      def SetField(self, FieldStruct, Offset, *args):
          # check if there's enough space
          Size = FieldStruct.size
          if Size > len(self):
              self.extend([0] * (Size - len(self)))
          FieldStruct.pack_into(self, Offset, *args)
  
      def _SetData(self, Data):
          if len(self) < self._HEADER_SIZE_:
              self.extend([0] * (self._HEADER_SIZE_ - len(self)))
          else:
              del self[self._HEADER_SIZE_:]
          self.extend(Data)
  
      def _GetData(self):
          if len(self) > self._HEADER_SIZE_:
              return self[self._HEADER_SIZE_:]
          return None
  
      Data = property(_GetData, _SetData)
  
  ## CompressedImage() class
  #
  #  A class for Compressed Image
  #
  class CompressedImage(Image):
      # UncompressedLength = 4-byte
      # CompressionType = 1-byte
      _HEADER_ = struct.Struct("1I 1B")
      _HEADER_SIZE_ = _HEADER_.size
  
      _ORIG_SIZE_     = struct.Struct("1I")
      _CMPRS_TYPE_    = struct.Struct("4x 1B")
  
      def __init__(self, CompressedData=None, CompressionType=None, UncompressedLength=None):
          Image.__init__(self)
          if UncompressedLength is not None:
              self.UncompressedLength = UncompressedLength
          if CompressionType is not None:
              self.CompressionType = CompressionType
          if CompressedData is not None:
              self.Data = CompressedData
  
      def __str__(self):
          global gIndention
          S = "algorithm=%s uncompressed=%x" % (self.CompressionType, self.UncompressedLength)
          for Sec in self.Sections:
              S += '\n' + str(Sec)
  
          return S
  
      def _SetOriginalSize(self, Size):
          self.SetField(self._ORIG_SIZE_, 0, Size)
  
      def _GetOriginalSize(self):
          return self.GetField(self._ORIG_SIZE_)[0]
  
      def _SetCompressionType(self, Type):
          self.SetField(self._CMPRS_TYPE_, 0, Type)
  
      def _GetCompressionType(self):
          return self.GetField(self._CMPRS_TYPE_)[0]
  
      def _GetSections(self):
          try:
              TmpData = DeCompress('Efi', self[self._HEADER_SIZE_:])
              DecData = array('B')
              DecData.fromstring(TmpData)
          except:
              TmpData = DeCompress('Framework', self[self._HEADER_SIZE_:])
              DecData = array('B')
              DecData.fromstring(TmpData)
  
          SectionList = []
          Offset = 0
          while Offset < len(DecData):
              Sec = Section()
              try:
                  Sec.frombuffer(DecData, Offset)
                  Offset += Sec.Size
                  # the section is aligned to 4-byte boundary
              except:
                  break
              SectionList.append(Sec)
          return SectionList
  
      UncompressedLength = property(_GetOriginalSize, _SetOriginalSize)
      CompressionType = property(_GetCompressionType, _SetCompressionType)
      Sections = property(_GetSections)
  
  ## Ui() class
  #
  #  A class for Ui
  #
  class Ui(Image):
      _HEADER_ = struct.Struct("")
      _HEADER_SIZE_ = 0
  
      def __init__(self):
          Image.__init__(self)
  
      def __str__(self):
          return self.String
  
      def _Unpack(self):
          # keep header in this Image object
          self.empty()
          self.extend(self._BUF_[self._OFF_ : self._OFF_ + self._LEN_])
          return len(self)
  
      def _GetUiString(self):
          return codecs.utf_16_decode(self[0:-2].tostring())[0]
  
      String = property(_GetUiString)
  
  ## Depex() class
  #
  #  A class for Depex
  #
  class Depex(Image):
      _HEADER_ = struct.Struct("")
      _HEADER_SIZE_ = 0
  
      _GUID_          = struct.Struct("1I2H8B")
      _OPCODE_        = struct.Struct("1B")
  
      _OPCODE_STRING_ = {
          0x00    :   "BEFORE",
          0x01    :   "AFTER",
          0x02    :   "PUSH",
          0x03    :   "AND",
          0x04    :   "OR",
          0x05    :   "NOT",
          0x06    :   "TRUE",
          0x07    :   "FALSE",
          0x08    :   "END",
          0x09    :   "SOR"
      }
  
      _NEXT_ = {
          -1      :   _OPCODE_,   # first one in depex must be an opcdoe
          0x00    :   _GUID_,     #"BEFORE",
          0x01    :   _GUID_,     #"AFTER",
          0x02    :   _GUID_,     #"PUSH",
          0x03    :   _OPCODE_,   #"AND",
          0x04    :   _OPCODE_,   #"OR",
          0x05    :   _OPCODE_,   #"NOT",
          0x06    :   _OPCODE_,   #"TRUE",
          0x07    :   _OPCODE_,   #"FALSE",
          0x08    :   None,       #"END",
          0x09    :   _OPCODE_,   #"SOR"
      }
  
      def __init__(self):
          Image.__init__(self)
          self._ExprList = []
  
      def __str__(self):
          global gIndention
          gIndention += 4
          Indention = ' ' * gIndention
          S = '\n'
          for T in self.Expression:
              if T in self._OPCODE_STRING_:
                  S += Indention + self._OPCODE_STRING_[T]
                  if T not in [0x00, 0x01, 0x02]:
                      S += '\n'
              else:
                  S += ' ' + gGuidStringFormat % T + '\n'
          gIndention -= 4
          return S
  
      def _Unpack(self):
          # keep header in this Image object
          self.empty()
          self.extend(self._BUF_[self._OFF_ : self._OFF_ + self._LEN_])
          return len(self)
  
      def _GetExpression(self):
          if self._ExprList == []:
              Offset = 0
              CurrentData = self._OPCODE_
              while Offset < len(self):
                  Token = CurrentData.unpack_from(self, Offset)
                  Offset += CurrentData.size
                  if len(Token) == 1:
                      Token = Token[0]
                      if Token in self._NEXT_:
                          CurrentData = self._NEXT_[Token]
                      else:
                          CurrentData = self._GUID_
                  else:
                      CurrentData = self._OPCODE_
                  self._ExprList.append(Token)
                  if CurrentData is None:
                      break
          return self._ExprList
  
      Expression = property(_GetExpression)
  
  # # FirmwareVolume() class
  #
  #  A class for Firmware Volume
  #
  class FirmwareVolume(Image):
      # Read FvLength, Attributes, HeaderLength, Checksum
      _HEADER_ = struct.Struct("16x 1I2H8B 1Q 4x 1I 1H 1H")
      _HEADER_SIZE_ = _HEADER_.size
  
      _FfsGuid = "8C8CE578-8A3D-4F1C-9935-896185C32DD3"
  
      _GUID_ = struct.Struct("16x 1I2H8B")
      _LENGTH_ = struct.Struct("16x 16x 1Q")
      _SIG_ = struct.Struct("16x 16x 8x 1I")
      _ATTR_ = struct.Struct("16x 16x 8x 4x 1I")
      _HLEN_ = struct.Struct("16x 16x 8x 4x 4x 1H")
      _CHECKSUM_ = struct.Struct("16x 16x 8x 4x 4x 2x 1H")
  
      def __init__(self, Name=''):
          Image.__init__(self)
          self.Name = Name
          self.FfsDict = sdict()
          self.OrderedFfsDict = sdict()
          self.UnDispatchedFfsDict = sdict()
          self.ProtocolList = sdict()
  
      def CheckArchProtocol(self):
          for Item in EotGlobalData.gArchProtocolGuids:
              if Item.lower() not in EotGlobalData.gProtocolList:
                  return False
          return True
  
      def ParseDepex(self, Depex, Type):
          List = None
          if Type == 'Ppi':
              List = EotGlobalData.gPpiList
          if Type == 'Protocol':
              List = EotGlobalData.gProtocolList
          DepexStack = []
          DepexList = []
          DepexString = ''
          FileDepex = None
          CouldBeLoaded = True
          for Index in range(0, len(Depex.Expression)):
              Item = Depex.Expression[Index]
              if Item == 0x00:
                  Index = Index + 1
                  Guid = gGuidStringFormat % Depex.Expression[Index]
                  if Guid in self.OrderedFfsDict and Depex.Expression[Index + 1] == 0x08:
                      return (True, 'BEFORE %s' % Guid, [Guid, 'BEFORE'])
              elif Item == 0x01:
                  Index = Index + 1
                  Guid = gGuidStringFormat % Depex.Expression[Index]
                  if Guid in self.OrderedFfsDict and Depex.Expression[Index + 1] == 0x08:
                      return (True, 'AFTER %s' % Guid, [Guid, 'AFTER'])
              elif Item == 0x02:
                  Index = Index + 1
                  Guid = gGuidStringFormat % Depex.Expression[Index]
                  if Guid.lower() in List:
                      DepexStack.append(True)
                      DepexList.append(Guid)
                  else:
                      DepexStack.append(False)
                      DepexList.append(Guid)
                  continue
              elif Item == 0x03 or Item == 0x04:
                  DepexStack.append(eval(str(DepexStack.pop()) + ' ' + Depex._OPCODE_STRING_[Item].lower() + ' ' + str(DepexStack.pop())))
                  DepexList.append(str(DepexList.pop()) + ' ' + Depex._OPCODE_STRING_[Item].upper() + ' ' + str(DepexList.pop()))
              elif Item == 0x05:
                  DepexStack.append(eval(Depex._OPCODE_STRING_[Item].lower() + ' ' + str(DepexStack.pop())))
                  DepexList.append(Depex._OPCODE_STRING_[Item].lower() + ' ' + str(DepexList.pop()))
              elif Item == 0x06:
                  DepexStack.append(True)
                  DepexList.append('TRUE')
                  DepexString = DepexString + 'TRUE' + ' '
              elif Item == 0x07:
                  DepexStack.append(False)
                  DepexList.append('False')
                  DepexString = DepexString + 'FALSE' + ' '
              elif Item == 0x08:
                  if Index != len(Depex.Expression) - 1:
                      CouldBeLoaded = False
                  else:
                      CouldBeLoaded = DepexStack.pop()
              else:
                  CouldBeLoaded = False
          if DepexList != []:
              DepexString = DepexList[0].strip()
          return (CouldBeLoaded, DepexString, FileDepex)
  
      def Dispatch(self, Db=None):
          if Db is None:
              return False
          self.UnDispatchedFfsDict = copy.copy(self.FfsDict)
          # Find PeiCore, DexCore, PeiPriori, DxePriori first
          FfsSecCoreGuid = None
          FfsPeiCoreGuid = None
          FfsDxeCoreGuid = None
          FfsPeiPrioriGuid = None
          FfsDxePrioriGuid = None
          for FfsID in self.UnDispatchedFfsDict.keys():
              Ffs = self.UnDispatchedFfsDict[FfsID]
              if Ffs.Type == 0x03:
                  FfsSecCoreGuid = FfsID
                  continue
              if Ffs.Type == 0x04:
                  FfsPeiCoreGuid = FfsID
                  continue
              if Ffs.Type == 0x05:
                  FfsDxeCoreGuid = FfsID
                  continue
              if Ffs.Guid.lower() == PEI_APRIORI_GUID.lower():
                  FfsPeiPrioriGuid = FfsID
                  continue
              if Ffs.Guid.lower() == DXE_APRIORI_GUID.lower():
                  FfsDxePrioriGuid = FfsID
                  continue
  
          # Parse SEC_CORE first
          if FfsSecCoreGuid is not None:
              self.OrderedFfsDict[FfsSecCoreGuid] = self.UnDispatchedFfsDict.pop(FfsSecCoreGuid)
              self.LoadPpi(Db, FfsSecCoreGuid)
  
          # Parse PEI first
          if FfsPeiCoreGuid is not None:
              self.OrderedFfsDict[FfsPeiCoreGuid] = self.UnDispatchedFfsDict.pop(FfsPeiCoreGuid)
              self.LoadPpi(Db, FfsPeiCoreGuid)
              if FfsPeiPrioriGuid is not None:
                  # Load PEIM described in priori file
                  FfsPeiPriori = self.UnDispatchedFfsDict.pop(FfsPeiPrioriGuid)
                  if len(FfsPeiPriori.Sections) == 1:
                      Section = FfsPeiPriori.Sections.popitem()[1]
                      if Section.Type == 0x19:
                          GuidStruct = struct.Struct('1I2H8B')
                          Start = 4
                          while len(Section) > Start:
                              Guid = GuidStruct.unpack_from(Section[Start : Start + 16])
                              GuidString = gGuidStringFormat % Guid
                              Start = Start + 16
                              if GuidString in self.UnDispatchedFfsDict:
                                  self.OrderedFfsDict[GuidString] = self.UnDispatchedFfsDict.pop(GuidString)
                                  self.LoadPpi(Db, GuidString)
  
          self.DisPatchPei(Db)
  
          # Parse DXE then
          if FfsDxeCoreGuid is not None:
              self.OrderedFfsDict[FfsDxeCoreGuid] = self.UnDispatchedFfsDict.pop(FfsDxeCoreGuid)
              self.LoadProtocol(Db, FfsDxeCoreGuid)
              if FfsDxePrioriGuid is not None:
                  # Load PEIM described in priori file
                  FfsDxePriori = self.UnDispatchedFfsDict.pop(FfsDxePrioriGuid)
                  if len(FfsDxePriori.Sections) == 1:
                      Section = FfsDxePriori.Sections.popitem()[1]
                      if Section.Type == 0x19:
                          GuidStruct = struct.Struct('1I2H8B')
                          Start = 4
                          while len(Section) > Start:
                              Guid = GuidStruct.unpack_from(Section[Start : Start + 16])
                              GuidString = gGuidStringFormat % Guid
                              Start = Start + 16
                              if GuidString in self.UnDispatchedFfsDict:
                                  self.OrderedFfsDict[GuidString] = self.UnDispatchedFfsDict.pop(GuidString)
                                  self.LoadProtocol(Db, GuidString)
  
          self.DisPatchDxe(Db)
  
      def LoadProtocol(self, Db, ModuleGuid):
          SqlCommand = """select GuidValue from Report
                          where SourceFileFullPath in
                          (select Value1 from Inf where BelongsToFile =
                          (select BelongsToFile from Inf
                          where Value1 = 'FILE_GUID' and Value2 like '%s' and Model = %s)
                          and Model = %s)
                          and ItemType = 'Protocol' and ItemMode = 'Produced'""" \
                          % (ModuleGuid, 5001, 3007)
          RecordSet = Db.TblReport.Exec(SqlCommand)
          for Record in RecordSet:
              SqlCommand = """select Value2 from Inf where BelongsToFile =
                              (select DISTINCT BelongsToFile from Inf
                              where Value1 =
                              (select SourceFileFullPath from Report
                              where GuidValue like '%s' and ItemMode = 'Callback'))
                              and Value1 = 'FILE_GUID'""" % Record[0]
              CallBackSet = Db.TblReport.Exec(SqlCommand)
              if CallBackSet != []:
                  EotGlobalData.gProtocolList[Record[0].lower()] = ModuleGuid
              else:
                  EotGlobalData.gProtocolList[Record[0].lower()] = ModuleGuid
  
      def LoadPpi(self, Db, ModuleGuid):
          SqlCommand = """select GuidValue from Report
                          where SourceFileFullPath in
                          (select Value1 from Inf where BelongsToFile =
                          (select BelongsToFile from Inf
                          where Value1 = 'FILE_GUID' and Value2 like '%s' and Model = %s)
                          and Model = %s)
                          and ItemType = 'Ppi' and ItemMode = 'Produced'""" \
                          % (ModuleGuid, 5001, 3007)
          RecordSet = Db.TblReport.Exec(SqlCommand)
          for Record in RecordSet:
              EotGlobalData.gPpiList[Record[0].lower()] = ModuleGuid
  
      def DisPatchDxe(self, Db):
          IsInstalled = False
          ScheduleList = sdict()
          for FfsID in self.UnDispatchedFfsDict.keys():
              CouldBeLoaded = False
              DepexString = ''
              FileDepex = None
              Ffs = self.UnDispatchedFfsDict[FfsID]
              if Ffs.Type == 0x07:
                  # Get Depex
                  IsFoundDepex = False
                  for Section in Ffs.Sections.values():
                      # Find Depex
                      if Section.Type == 0x13:
                          IsFoundDepex = True
                          CouldBeLoaded, DepexString, FileDepex = self.ParseDepex(Section._SubImages[4], 'Protocol')
                          break
                      if Section.Type == 0x01:
                          CompressSections = Section._SubImages[4]
                          for CompressSection in CompressSections.Sections:
                              if CompressSection.Type == 0x13:
                                  IsFoundDepex = True
                                  CouldBeLoaded, DepexString, FileDepex = self.ParseDepex(CompressSection._SubImages[4], 'Protocol')
                                  break
                              if CompressSection.Type == 0x02:
                                  NewSections = CompressSection._SubImages[4]
                                  for NewSection in NewSections.Sections:
                                      if NewSection.Type == 0x13:
                                          IsFoundDepex = True
                                          CouldBeLoaded, DepexString, FileDepex = self.ParseDepex(NewSection._SubImages[4], 'Protocol')
                                          break
  
                  # Not find Depex
                  if not IsFoundDepex:
                      CouldBeLoaded = self.CheckArchProtocol()
                      DepexString = ''
                      FileDepex = None
  
                  # Append New Ffs
                  if CouldBeLoaded:
                      IsInstalled = True
                      NewFfs = self.UnDispatchedFfsDict.pop(FfsID)
                      NewFfs.Depex = DepexString
                      if FileDepex is not None:
                          ScheduleList.insert(FileDepex[1], FfsID, NewFfs, FileDepex[0])
                      else:
                          ScheduleList[FfsID] = NewFfs
                  else:
                      self.UnDispatchedFfsDict[FfsID].Depex = DepexString
  
          for FfsID in ScheduleList.keys():
              NewFfs = ScheduleList.pop(FfsID)
              FfsName = 'UnKnown'
              self.OrderedFfsDict[FfsID] = NewFfs
              self.LoadProtocol(Db, FfsID)
  
              SqlCommand = """select Value2 from Inf
                              where BelongsToFile = (select BelongsToFile from Inf where Value1 = 'FILE_GUID' and lower(Value2) = lower('%s') and Model = %s)
                              and Model = %s and Value1='BASE_NAME'""" % (FfsID, 5001, 5001)
              RecordSet = Db.TblReport.Exec(SqlCommand)
              if RecordSet != []:
                  FfsName = RecordSet[0][0]
  
          if IsInstalled:
              self.DisPatchDxe(Db)
  
      def DisPatchPei(self, Db):
          IsInstalled = False
          for FfsID in self.UnDispatchedFfsDict.keys():
              CouldBeLoaded = True
              DepexString = ''
              FileDepex = None
              Ffs = self.UnDispatchedFfsDict[FfsID]
              if Ffs.Type == 0x06 or Ffs.Type == 0x08:
                  # Get Depex
                  for Section in Ffs.Sections.values():
                      if Section.Type == 0x1B:
                          CouldBeLoaded, DepexString, FileDepex = self.ParseDepex(Section._SubImages[4], 'Ppi')
                          break
                      if Section.Type == 0x01:
                          CompressSections = Section._SubImages[4]
                          for CompressSection in CompressSections.Sections:
                              if CompressSection.Type == 0x1B:
                                  CouldBeLoaded, DepexString, FileDepex = self.ParseDepex(CompressSection._SubImages[4], 'Ppi')
                                  break
                              if CompressSection.Type == 0x02:
                                  NewSections = CompressSection._SubImages[4]
                                  for NewSection in NewSections.Sections:
                                      if NewSection.Type == 0x1B:
                                          CouldBeLoaded, DepexString, FileDepex = self.ParseDepex(NewSection._SubImages[4], 'Ppi')
                                          break
  
                  # Append New Ffs
                  if CouldBeLoaded:
                      IsInstalled = True
                      NewFfs = self.UnDispatchedFfsDict.pop(FfsID)
                      NewFfs.Depex = DepexString
                      self.OrderedFfsDict[FfsID] = NewFfs
                      self.LoadPpi(Db, FfsID)
                  else:
                      self.UnDispatchedFfsDict[FfsID].Depex = DepexString
  
          if IsInstalled:
              self.DisPatchPei(Db)
  
  
      def __str__(self):
          global gIndention
          gIndention += 4
          FvInfo = '\n' + ' ' * gIndention
          FvInfo += "[FV:%s] file_system=%s size=%x checksum=%s\n" % (self.Name, self.FileSystemGuid, self.Size, self.Checksum)
          FfsInfo = "\n".join([str(self.FfsDict[FfsId]) for FfsId in self.FfsDict])
          gIndention -= 4
          return FvInfo + FfsInfo
  
      def _Unpack(self):
          Size = self._LENGTH_.unpack_from(self._BUF_, self._OFF_)[0]
          self.empty()
          self.extend(self._BUF_[self._OFF_:self._OFF_ + Size])
  
          # traverse the FFS
          EndOfFv = Size
          FfsStartAddress = self.HeaderSize
          LastFfsObj = None
          while FfsStartAddress < EndOfFv:
              FfsObj = Ffs()
              FfsObj.frombuffer(self, FfsStartAddress)
              FfsId = repr(FfsObj)
              if ((self.Attributes & 0x00000800) != 0 and len(FfsObj) == 0xFFFFFF) \
                  or ((self.Attributes & 0x00000800) == 0 and len(FfsObj) == 0):
                  if LastFfsObj is not None:
                      LastFfsObj.FreeSpace = EndOfFv - LastFfsObj._OFF_ - len(LastFfsObj)
              else:
                  if FfsId in self.FfsDict:
                      EdkLogger.error("FV", 0, "Duplicate GUID in FFS",
                                      ExtraData="\t%s @ %s\n\t%s @ %s" \
                                      % (FfsObj.Guid, FfsObj.Offset,
                                         self.FfsDict[FfsId].Guid, self.FfsDict[FfsId].Offset))
                  self.FfsDict[FfsId] = FfsObj
                  if LastFfsObj is not None:
                      LastFfsObj.FreeSpace = FfsStartAddress - LastFfsObj._OFF_ - len(LastFfsObj)
  
              FfsStartAddress += len(FfsObj)
              #
              # align to next 8-byte aligned address: A = (A + 8 - 1) & (~(8 - 1))
              # The next FFS must be at the latest next 8-byte aligned address
              #
              FfsStartAddress = (FfsStartAddress + 7) & (~7)
              LastFfsObj = FfsObj
  
      def _GetAttributes(self):
          return self.GetField(self._ATTR_, 0)[0]
  
      def _GetSize(self):
          return self.GetField(self._LENGTH_, 0)[0]
  
      def _GetChecksum(self):
          return self.GetField(self._CHECKSUM_, 0)[0]
  
      def _GetHeaderLength(self):
          return self.GetField(self._HLEN_, 0)[0]
  
      def _GetFileSystemGuid(self):
          return gGuidStringFormat % self.GetField(self._GUID_, 0)
  
      Attributes = property(_GetAttributes)
      Size = property(_GetSize)
      Checksum = property(_GetChecksum)
      HeaderSize = property(_GetHeaderLength)
      FileSystemGuid = property(_GetFileSystemGuid)
  
  ## GuidDefinedImage() class
  #
  #  A class for GUID Defined Image
  #
  class GuidDefinedImage(Image):
      _HEADER_ = struct.Struct("1I2H8B 1H 1H")
      _HEADER_SIZE_ = _HEADER_.size
  
      _GUID_          = struct.Struct("1I2H8B")
      _DATA_OFFSET_   = struct.Struct("16x 1H")
      _ATTR_          = struct.Struct("18x 1H")
  
      CRC32_GUID          = "FC1BCDB0-7D31-49AA-936A-A4600D9DD083"
      TIANO_COMPRESS_GUID = 'A31280AD-481E-41B6-95E8-127F4C984779'
      LZMA_COMPRESS_GUID  = 'EE4E5898-3914-4259-9D6E-DC7BD79403CF'
  
      def __init__(self, SectionDefinitionGuid=None, DataOffset=None, Attributes=None, Data=None):
          Image.__init__(self)
          if SectionDefinitionGuid is not None:
              self.SectionDefinitionGuid = SectionDefinitionGuid
          if DataOffset is not None:
              self.DataOffset = DataOffset
          if Attributes is not None:
              self.Attributes = Attributes
          if Data is not None:
              self.Data = Data
  
      def __str__(self):
          S = "guid=%s" % (gGuidStringFormat % self.SectionDefinitionGuid)
          for Sec in self.Sections:
              S += "\n" + str(Sec)
          return S
  
      def _Unpack(self):
          # keep header in this Image object
          self.empty()
          self.extend(self._BUF_[self._OFF_ : self._OFF_ + self._LEN_])
          return len(self)
  
      def _SetAttribute(self, Attribute):
          self.SetField(self._ATTR_, 0, Attribute)
  
      def _GetAttribute(self):
          return self.GetField(self._ATTR_)[0]
  
      def _SetGuid(self, Guid):
          self.SetField(self._GUID_, 0, Guid)
  
      def _GetGuid(self):
          return self.GetField(self._GUID_)
  
      def _SetDataOffset(self, Offset):
          self.SetField(self._DATA_OFFSET_, 0, Offset)
  
      def _GetDataOffset(self):
          return self.GetField(self._DATA_OFFSET_)[0]
  
      def _GetSections(self):
          SectionList = []
          Guid = gGuidStringFormat % self.SectionDefinitionGuid
          if Guid == self.CRC32_GUID:
              # skip the CRC32 value, we don't do CRC32 verification here
              Offset = self.DataOffset - 4
              while Offset < len(self):
                  Sec = Section()
                  try:
                      Sec.frombuffer(self, Offset)
                      Offset += Sec.Size
                      # the section is aligned to 4-byte boundary
                      Offset = (Offset + 3) & (~3)
                  except:
                      break
                  SectionList.append(Sec)
          elif Guid == self.TIANO_COMPRESS_GUID:
              try:
                  # skip the header
                  Offset = self.DataOffset - 4
                  TmpData = DeCompress('Framework', self[self.Offset:])
                  DecData = array('B')
                  DecData.fromstring(TmpData)
                  Offset = 0
                  while Offset < len(DecData):
                      Sec = Section()
                      try:
                          Sec.frombuffer(DecData, Offset)
                          Offset += Sec.Size
                          # the section is aligned to 4-byte boundary
                          Offset = (Offset + 3) & (~3)
                      except:
                          break
                      SectionList.append(Sec)
              except:
                  pass
          elif Guid == self.LZMA_COMPRESS_GUID:
              try:
                  # skip the header
                  Offset = self.DataOffset - 4
  
                  TmpData = DeCompress('Lzma', self[self.Offset:])
                  DecData = array('B')
                  DecData.fromstring(TmpData)
                  Offset = 0
                  while Offset < len(DecData):
                      Sec = Section()
                      try:
                          Sec.frombuffer(DecData, Offset)
                          Offset += Sec.Size
                          # the section is aligned to 4-byte boundary
                          Offset = (Offset + 3) & (~3)
                      except:
                          break
                      SectionList.append(Sec)
              except:
                  pass
  
          return SectionList
  
      Attributes = property(_GetAttribute, _SetAttribute)
      SectionDefinitionGuid = property(_GetGuid, _SetGuid)
      DataOffset = property(_GetDataOffset, _SetDataOffset)
      Sections = property(_GetSections)
  
  ## Section() class
  #
  #  A class for Section
  #
  class Section(Image):
      _TypeName = {
          0x00    :   "<unknown>",
          0x01    :   "COMPRESSION",
          0x02    :   "GUID_DEFINED",
          0x10    :   "PE32",
          0x11    :   "PIC",
          0x12    :   "TE",
          0x13    :   "DXE_DEPEX",
          0x14    :   "VERSION",
          0x15    :   "USER_INTERFACE",
          0x16    :   "COMPATIBILITY16",
          0x17    :   "FIRMWARE_VOLUME_IMAGE",
          0x18    :   "FREEFORM_SUBTYPE_GUID",
          0x19    :   "RAW",
          0x1B    :   "PEI_DEPEX"
      }
  
      _SectionSubImages = {
          0x01    :   CompressedImage,
          0x02    :   GuidDefinedImage,
          0x17    :   FirmwareVolume,
          0x13    :   Depex,
          0x1B    :   Depex,
          0x15    :   Ui
      }
  
      # Size = 3-byte
      # Type = 1-byte
      _HEADER_ = struct.Struct("3B 1B")
      _HEADER_SIZE_ = _HEADER_.size
  
      # SubTypeGuid
      # _FREE_FORM_SUBTYPE_GUID_HEADER_ = struct.Struct("1I2H8B")
      _SIZE_          = struct.Struct("3B")
      _TYPE_          = struct.Struct("3x 1B")
  
      def __init__(self, Type=None, Size=None):
          Image.__init__(self)
          self._Alignment = 1
          if Type is not None:
              self.Type = Type
          if Size is not None:
              self.Size = Size
  
      def __str__(self):
          global gIndention
          gIndention += 4
          SectionInfo = ' ' * gIndention
          if self.Type in self._TypeName:
              SectionInfo += "[SECTION:%s] offset=%x size=%x" % (self._TypeName[self.Type], self._OFF_, self.Size)
          else:
              SectionInfo += "[SECTION:%x<unknown>] offset=%x size=%x " % (self.Type, self._OFF_, self.Size)
          for Offset in self._SubImages.keys():
              SectionInfo += ", " + str(self._SubImages[Offset])
          gIndention -= 4
          return SectionInfo
  
      def _Unpack(self):
          self.empty()
          Type, = self._TYPE_.unpack_from(self._BUF_, self._OFF_)
          Size1, Size2, Size3 = self._SIZE_.unpack_from(self._BUF_, self._OFF_)
          Size = Size1 + (Size2 << 8) + (Size3 << 16)
  
          if Type not in self._SectionSubImages:
              # no need to extract sub-image, keep all in this Image object
              self.extend(self._BUF_[self._OFF_ : self._OFF_ + Size])
          else:
              # keep header in this Image object
              self.extend(self._BUF_[self._OFF_ : self._OFF_ + self._HEADER_SIZE_])
              #
              # use new Image object to represent payload, which may be another kind
              # of image such as PE32
              #
              PayloadOffset = self._HEADER_SIZE_
              PayloadLen = self.Size - self._HEADER_SIZE_
              Payload = self._SectionSubImages[self.Type]()
              Payload.frombuffer(self._BUF_, self._OFF_ + self._HEADER_SIZE_, PayloadLen)
              self._SubImages[PayloadOffset] = Payload
  
          return Size
  
      def _SetSize(self, Size):
          Size1 = Size & 0xFF
          Size2 = (Size & 0xFF00) >> 8
          Size3 = (Size & 0xFF0000) >> 16
          self.SetField(self._SIZE_, 0, Size1, Size2, Size3)
  
      def _GetSize(self):
          Size1, Size2, Size3 = self.GetField(self._SIZE_)
          return Size1 + (Size2 << 8) + (Size3 << 16)
  
      def _SetType(self, Type):
          self.SetField(self._TYPE_, 0, Type)
  
      def _GetType(self):
          return self.GetField(self._TYPE_)[0]
  
      def _GetAlignment(self):
          return self._Alignment
  
      def _SetAlignment(self, Alignment):
          self._Alignment = Alignment
          AlignmentMask = Alignment - 1
          # section alignment is actually for payload, so we need to add header size
          PayloadOffset = self._OFF_ + self._HEADER_SIZE_
          if (PayloadOffset & (~AlignmentMask)) == 0:
              return
          NewOffset = (PayloadOffset + AlignmentMask) & (~AlignmentMask)
          while (NewOffset - PayloadOffset) < self._HEADER_SIZE_:
              NewOffset += self._Alignment
  
      def tofile(self, f):
          self.Size = len(self)
          Image.tofile(self, f)
          for Offset in self._SubImages:
              self._SubImages[Offset].tofile(f)
  
      Type = property(_GetType, _SetType)
      Size = property(_GetSize, _SetSize)
      Alignment = property(_GetAlignment, _SetAlignment)
  
  ## Ffs() class
  #
  #  A class for Ffs Section
  #
  class Ffs(Image):
      _FfsFormat = "24B%(payload_size)sB"
      # skip IntegrityCheck
      _HEADER_ = struct.Struct("1I2H8B 2x 1B 1B 3B 1B")
      _HEADER_SIZE_ = _HEADER_.size
  
      _NAME_      = struct.Struct("1I2H8B")
      _INT_CHECK_ = struct.Struct("16x 1H")
      _TYPE_      = struct.Struct("18x 1B")
      _ATTR_      = struct.Struct("19x 1B")
      _SIZE_      = struct.Struct("20x 3B")
      _STATE_     = struct.Struct("23x 1B")
  
      FFS_ATTRIB_FIXED              = 0x04
      FFS_ATTRIB_DATA_ALIGNMENT     = 0x38
      FFS_ATTRIB_CHECKSUM           = 0x40
  
      _TypeName = {
          0x00    :   "<unknown>",
          0x01    :   "RAW",
          0x02    :   "FREEFORM",
          0x03    :   "SECURITY_CORE",
          0x04    :   "PEI_CORE",
          0x05    :   "DXE_CORE",
          0x06    :   "PEIM",
          0x07    :   "DRIVER",
          0x08    :   "COMBINED_PEIM_DRIVER",
          0x09    :   "APPLICATION",
          0x0A    :   "SMM",
          0x0B    :   "FIRMWARE_VOLUME_IMAGE",
          0x0C    :   "COMBINED_SMM_DXE",
          0x0D    :   "SMM_CORE",
          0x0E    :   "MM_STANDALONE",
          0x0F    :   "MM_CORE_STANDALONE",
          0xc0    :   "OEM_MIN",
          0xdf    :   "OEM_MAX",
          0xe0    :   "DEBUG_MIN",
          0xef    :   "DEBUG_MAX",
          0xf0    :   "FFS_MIN",
          0xff    :   "FFS_MAX",
          0xf0    :   "FFS_PAD",
      }
  
      def __init__(self):
          Image.__init__(self)
          self.FreeSpace = 0
  
          self.Sections = sdict()
          self.Depex = ''
  
          self.__ID__ = None
  
      def __str__(self):
          global gIndention
          gIndention += 4
          Indention = ' ' * gIndention
          FfsInfo = Indention
          FfsInfo +=  "[FFS:%s] offset=%x size=%x guid=%s free_space=%x alignment=%s\n" % \
                      (Ffs._TypeName[self.Type], self._OFF_, self.Size, self.Guid, self.FreeSpace, self.Alignment)
          SectionInfo = '\n'.join([str(self.Sections[Offset]) for Offset in self.Sections.keys()])
          gIndention -= 4
          return FfsInfo + SectionInfo + "\n"
  
      def __len__(self):
          return self.Size
  
      def __repr__(self):
          return self.__ID__
  
      def _Unpack(self):
          Size1, Size2, Size3 = self._SIZE_.unpack_from(self._BUF_, self._OFF_)
          Size = Size1 + (Size2 << 8) + (Size3 << 16)
          self.empty()
          self.extend(self._BUF_[self._OFF_ : self._OFF_ + Size])
  
          # Pad FFS may use the same GUID. We need to avoid it.
          if self.Type == 0xf0:
              self.__ID__ = str(uuid.uuid1()).upper()
          else:
              self.__ID__ = self.Guid
  
          # Traverse the SECTION. RAW and PAD do not have sections
          if self.Type not in [0xf0, 0x01] and Size > 0 and Size < 0xFFFFFF:
              EndOfFfs = Size
              SectionStartAddress = self._HEADER_SIZE_
              while SectionStartAddress < EndOfFfs:
                  SectionObj = Section()
                  SectionObj.frombuffer(self, SectionStartAddress)
                  #f = open(repr(SectionObj), 'wb')
                  #SectionObj.Size = 0
                  #SectionObj.tofile(f)
                  #f.close()
                  self.Sections[SectionStartAddress] = SectionObj
                  SectionStartAddress += len(SectionObj)
                  SectionStartAddress = (SectionStartAddress + 3) & (~3)
  
      def Pack(self):
          pass
  
      def SetFreeSpace(self, Size):
          self.FreeSpace = Size
  
      def _GetGuid(self):
          return gGuidStringFormat % self.Name
  
      def _SetName(self, Value):
          # Guid1, Guid2, Guid3, Guid4, Guid5, Guid6, Guid7, Guid8, Guid9, Guid10, Guid11
          self.SetField(self._NAME_, 0, Value)
  
      def _GetName(self):
          # Guid1, Guid2, Guid3, Guid4, Guid5, Guid6, Guid7, Guid8, Guid9, Guid10, Guid11
          return self.GetField(self._NAME_)
  
      def _SetSize(self, Size):
          Size1 = Size & 0xFF
          Size2 = (Size & 0xFF00) >> 8
          Size3 = (Size & 0xFF0000) >> 16
          self.SetField(self._SIZE_, 0, Size1, Size2, Size3)
  
      def _GetSize(self):
          Size1, Size2, Size3 = self.GetField(self._SIZE_)
          return Size1 + (Size2 << 8) + (Size3 << 16)
  
      def _SetType(self, Type):
          self.SetField(self._TYPE_, 0, Type)
  
      def _GetType(self):
          return self.GetField(self._TYPE_)[0]
  
      def _SetAttributes(self, Value):
          self.SetField(self._ATTR_, 0, Value)
  
      def _GetAttributes(self):
          return self.GetField(self._ATTR_)[0]
  
      def _GetFixed(self):
          if (self.Attributes & self.FFS_ATTRIB_FIXED) != 0:
              return True
          return False
  
      def _GetCheckSum(self):
          if (self.Attributes & self.FFS_ATTRIB_CHECKSUM) != 0:
              return True
          return False
  
      def _GetAlignment(self):
          return (self.Attributes & self.FFS_ATTRIB_DATA_ALIGNMENT) >> 3
  
      def _SetState(self, Value):
          self.SetField(self._STATE_, 0, Value)
  
      def _GetState(self):
          return self.GetField(self._STATE_)[0]
  
      Name = property(_GetName, _SetName)
      Guid = property(_GetGuid)
      Type = property(_GetType, _SetType)
      Size = property(_GetSize, _SetSize)
      Attributes = property(_GetAttributes, _SetAttributes)
      Fixed = property(_GetFixed)
      Checksum = property(_GetCheckSum)
      Alignment = property(_GetAlignment)
      State = property(_GetState, _SetState)
  
  
  ## MultipleFv() class
  #
  #  A class for Multiple FV
  #
  class MultipleFv(FirmwareVolume):
      def __init__(self, FvList):
          FirmwareVolume.__init__(self)
          self.BasicInfo = []
          for FvPath in FvList:
              Fd = None
              FvName = os.path.splitext(os.path.split(FvPath)[1])[0]
              if FvPath.strip():
                  Fd = open(FvPath, 'rb')
              Buf = array('B')
              try:
                  Buf.fromfile(Fd, os.path.getsize(FvPath))
              except EOFError:
                  pass
  
              Fv = FirmwareVolume(FvName)
              Fv.frombuffer(Buf, 0, len(Buf))
  
              self.BasicInfo.append([Fv.Name, Fv.FileSystemGuid, Fv.Size])
              self.FfsDict.append(Fv.FfsDict)
  
  ## Class Eot
  #
  # This class is used to define Eot main entrance
  #
  # @param object:          Inherited from object class
  #
  class Eot(object):
      ## The constructor
      #
      #   @param  self:      The object pointer
      #
      def __init__(self, CommandLineOption=True, IsInit=True, SourceFileList=None, \
                   IncludeDirList=None, DecFileList=None, GuidList=None, LogFile=None,
                   FvFileList="", MapFileList="", Report='Report.html', Dispatch=None):
          # Version and Copyright
          self.VersionNumber = ("0.02" + " " + gBUILD_VERSION)
          self.Version = "%prog Version " + self.VersionNumber
          self.Copyright = "Copyright (c) 2008 - 2018, Intel Corporation  All rights reserved."
          self.Report = Report
  
          self.IsInit = IsInit
          self.SourceFileList = SourceFileList
          self.IncludeDirList = IncludeDirList
          self.DecFileList = DecFileList
          self.GuidList = GuidList
          self.LogFile = LogFile
          self.FvFileList = FvFileList
          self.MapFileList = MapFileList
          self.Dispatch = Dispatch
  
          # Check workspace environment
          if "EFI_SOURCE" not in os.environ:
              if "EDK_SOURCE" not in os.environ:
                  pass
              else:
                  EotGlobalData.gEDK_SOURCE = os.path.normpath(os.getenv("EDK_SOURCE"))
          else:
              EotGlobalData.gEFI_SOURCE = os.path.normpath(os.getenv("EFI_SOURCE"))
              EotGlobalData.gEDK_SOURCE = os.path.join(EotGlobalData.gEFI_SOURCE, 'Edk')
  
          if "WORKSPACE" not in os.environ:
              EdkLogger.error("EOT", BuildToolError.ATTRIBUTE_NOT_AVAILABLE, "Environment variable not found",
                              ExtraData="WORKSPACE")
          else:
              EotGlobalData.gWORKSPACE = os.path.normpath(os.getenv("WORKSPACE"))
  
          EotGlobalData.gMACRO['WORKSPACE'] = EotGlobalData.gWORKSPACE
          EotGlobalData.gMACRO['EFI_SOURCE'] = EotGlobalData.gEFI_SOURCE
          EotGlobalData.gMACRO['EDK_SOURCE'] = EotGlobalData.gEDK_SOURCE
  
          # Parse the options and args
          if CommandLineOption:
              self.ParseOption()
  
          if self.FvFileList:
              for FvFile in GetSplitValueList(self.FvFileList, ' '):
                  FvFile = os.path.normpath(FvFile)
                  if not os.path.isfile(FvFile):
                      EdkLogger.error("Eot", EdkLogger.EOT_ERROR, "Can not find file %s " % FvFile)
                  EotGlobalData.gFV_FILE.append(FvFile)
          else:
              EdkLogger.error("Eot", EdkLogger.EOT_ERROR, "The fv file list of target platform was not specified")
  
          if self.MapFileList:
              for MapFile in GetSplitValueList(self.MapFileList, ' '):
                  MapFile = os.path.normpath(MapFile)
                  if not os.path.isfile(MapFile):
                      EdkLogger.error("Eot", EdkLogger.EOT_ERROR, "Can not find file %s " % MapFile)
                  EotGlobalData.gMAP_FILE.append(MapFile)
  
          # Generate source file list
          self.GenerateSourceFileList(self.SourceFileList, self.IncludeDirList)
  
          # Generate guid list of dec file list
          self.ParseDecFile(self.DecFileList)
  
          # Generate guid list from GUID list file
          self.ParseGuidList(self.GuidList)
  
          # Init Eot database
          EotGlobalData.gDb = Database.Database(Database.DATABASE_PATH)
          EotGlobalData.gDb.InitDatabase(self.IsInit)
  
          # Build ECC database
          self.BuildDatabase()
  
          # Parse Ppi/Protocol
          self.ParseExecutionOrder()
  
          # Merge Identifier tables
          self.GenerateQueryTable()
  
          # Generate report database
          self.GenerateReportDatabase()
  
          # Load Fv Info
          self.LoadFvInfo()
  
          # Load Map Info
          self.LoadMapInfo()
  
          # Generate Report
          self.GenerateReport()
  
          # Convert log file
          self.ConvertLogFile(self.LogFile)
  
          # DONE
          EdkLogger.quiet("EOT FINISHED!")
  
          # Close Database
          EotGlobalData.gDb.Close()
  
      ## ParseDecFile() method
      #
      #  parse DEC file and get all GUID names with GUID values as {GuidName : GuidValue}
      #  The Dict is stored in EotGlobalData.gGuidDict
      #
      #  @param self: The object pointer
      #  @param DecFileList: A list of all DEC files
      #
      def ParseDecFile(self, DecFileList):
          if DecFileList:
              path = os.path.normpath(DecFileList)
              lfr = open(path, 'rb')
              for line in lfr:
                  path = os.path.normpath(os.path.join(EotGlobalData.gWORKSPACE, line.strip()))
                  if os.path.exists(path):
                      dfr = open(path, 'rb')
                      for line in dfr:
                          line = CleanString(line)
                          list = line.split('=')
                          if len(list) == 2:
                              EotGlobalData.gGuidDict[list[0].strip()] = GuidStructureStringToGuidString(list[1].strip())
  
  
      ## ParseGuidList() method
      #
      #  Parse Guid list and get all GUID names with GUID values as {GuidName : GuidValue}
      #  The Dict is stored in EotGlobalData.gGuidDict
      #
      #  @param self: The object pointer
      #  @param GuidList: A list of all GUID and its value
      #
      def ParseGuidList(self, GuidList):
          Path = os.path.join(EotGlobalData.gWORKSPACE, GuidList)
          if os.path.isfile(Path):
              for Line in open(Path):
                  if Line.strip():
                      (GuidName, GuidValue) = Line.split()
                      EotGlobalData.gGuidDict[GuidName] = GuidValue
  
      ## ConvertLogFile() method
      #
      #  Parse a real running log file to get real dispatch order
      #  The result is saved to old file name + '.new'
      #
      #  @param self: The object pointer
      #  @param LogFile: A real running log file name
      #
      def ConvertLogFile(self, LogFile):
          newline = []
          lfr = None
          lfw = None
          if LogFile:
              lfr = open(LogFile, 'rb')
              lfw = open(LogFile + '.new', 'wb')
              for line in lfr:
                  line = line.strip()
                  line = line.replace('.efi', '')
                  index = line.find("Loading PEIM at ")
                  if index > -1:
                      newline.append(line[index + 55 : ])
                      continue
                  index = line.find("Loading driver at ")
                  if index > -1:
                      newline.append(line[index + 57 : ])
                      continue
  
          for line in newline:
              lfw.write(line + '\r\n')
  
          if lfr:
              lfr.close()
          if lfw:
              lfw.close()
  
      ## GenerateSourceFileList() method
      #
      #  Generate a list of all source files
      #  1. Search the file list one by one
      #  2. Store inf file name with source file names under it like
      #  { INF file name: [source file1, source file2, ...]}
      #  3. Search the include list to find all .h files
      #  4. Store source file list to EotGlobalData.gSOURCE_FILES
      #  5. Store INF file list to EotGlobalData.gINF_FILES
      #
      #  @param self: The object pointer
      #  @param SourceFileList: A list of all source files
      #  @param IncludeFileList: A list of all include files
      #
      def GenerateSourceFileList(self, SourceFileList, IncludeFileList):
          EdkLogger.quiet("Generating source files list ... ")
          mSourceFileList = []
          mInfFileList = []
          mDecFileList = []
          mFileList = {}
          mCurrentInfFile = ''
          mCurrentSourceFileList = []
  
          if SourceFileList:
              sfl = open(SourceFileList, 'r')
              for line in sfl:
                  line = os.path.normpath(os.path.join(EotGlobalData.gWORKSPACE, line.strip()))
                  if line[-2:].upper() == '.C' or  line[-2:].upper() == '.H':
                      if line not in mCurrentSourceFileList:
                          mCurrentSourceFileList.append(line)
                          mSourceFileList.append(line)
                          EotGlobalData.gOP_SOURCE_FILES.write('%s\n' % line)
                  if line[-4:].upper() == '.INF':
                      if mCurrentInfFile != '':
                          mFileList[mCurrentInfFile] = mCurrentSourceFileList
                          mCurrentSourceFileList = []
                      mCurrentInfFile = os.path.normpath(os.path.join(EotGlobalData.gWORKSPACE, line))
                      EotGlobalData.gOP_INF.write('%s\n' % mCurrentInfFile)
              if mCurrentInfFile not in mFileList:
                  mFileList[mCurrentInfFile] = mCurrentSourceFileList
  
          # Get all include files from packages
          if IncludeFileList:
              ifl = open(IncludeFileList, 'rb')
              for line in ifl:
                  if not line.strip():
                      continue
                  newline = os.path.normpath(os.path.join(EotGlobalData.gWORKSPACE, line.strip()))
                  for Root, Dirs, Files in os.walk(str(newline)):
                      for File in Files:
                          FullPath = os.path.normpath(os.path.join(Root, File))
                          if FullPath not in mSourceFileList and File[-2:].upper() == '.H':
                              mSourceFileList.append(FullPath)
                              EotGlobalData.gOP_SOURCE_FILES.write('%s\n' % FullPath)
                          if FullPath not in mDecFileList and File.upper().find('.DEC') > -1:
                              mDecFileList.append(FullPath)
  
          EotGlobalData.gSOURCE_FILES = mSourceFileList
          EotGlobalData.gOP_SOURCE_FILES.close()
  
          EotGlobalData.gINF_FILES = mFileList
          EotGlobalData.gOP_INF.close()
  
      ## GenerateReport() method
      #
      #  Generate final HTML report
      #
      #  @param self: The object pointer
      #
      def GenerateReport(self):
          EdkLogger.quiet("Generating report file ... ")
          Rep = Report(self.Report, EotGlobalData.gFV, self.Dispatch)
          Rep.GenerateReport()
  
      ## LoadMapInfo() method
      #
      #  Load map files and parse them
      #
      #  @param self: The object pointer
      #
      def LoadMapInfo(self):
          if EotGlobalData.gMAP_FILE != []:
              EdkLogger.quiet("Parsing Map file ... ")
              EotGlobalData.gMap = ParseMapFile(EotGlobalData.gMAP_FILE)
  
      ## LoadFvInfo() method
      #
      #  Load FV binary files and parse them
      #
      #  @param self: The object pointer
      #
      def LoadFvInfo(self):
          EdkLogger.quiet("Parsing FV file ... ")
          EotGlobalData.gFV = MultipleFv(EotGlobalData.gFV_FILE)
          EotGlobalData.gFV.Dispatch(EotGlobalData.gDb)
  
          for Protocol in EotGlobalData.gProtocolList:
              EotGlobalData.gOP_UN_MATCHED_IN_LIBRARY_CALLING.write('%s\n' %Protocol)
  
      ## GenerateReportDatabase() method
      #
      #  Generate data for the information needed by report
      #  1. Update name, macro and value of all found PPI/PROTOCOL GUID
      #  2. Install hard coded PPI/PROTOCOL
      #
      #  @param self: The object pointer
      #
      def GenerateReportDatabase(self):
          EdkLogger.quiet("Generating the cross-reference table of GUID for Ppi/Protocol ... ")
  
          # Update Protocol/Ppi Guid
          SqlCommand = """select DISTINCT GuidName from Report"""
          RecordSet = EotGlobalData.gDb.TblReport.Exec(SqlCommand)
          for Record in RecordSet:
              GuidName = Record[0]
              GuidMacro = ''
              GuidMacro2 = ''
              GuidValue = ''
  
              # Find guid value defined in Dec file
              if GuidName in EotGlobalData.gGuidDict:
                  GuidValue = EotGlobalData.gGuidDict[GuidName]
                  SqlCommand = """update Report set GuidMacro = '%s', GuidValue = '%s' where GuidName = '%s'""" %(GuidMacro, GuidValue, GuidName)
                  EotGlobalData.gDb.TblReport.Exec(SqlCommand)
                  continue
  
              # Search defined Macros for guid name
              SqlCommand ="""select DISTINCT Value, Modifier from Query where Name like '%s'""" % GuidName
              GuidMacroSet = EotGlobalData.gDb.TblReport.Exec(SqlCommand)
              # Ignore NULL result
              if not GuidMacroSet:
                  continue
              GuidMacro = GuidMacroSet[0][0].strip()
              if not GuidMacro:
                  continue
              # Find Guid value of Guid Macro
              SqlCommand ="""select DISTINCT Value from Query2 where Value like '%%%s%%' and Model = %s""" % (GuidMacro, MODEL_IDENTIFIER_MACRO_DEFINE)
              GuidValueSet = EotGlobalData.gDb.TblReport.Exec(SqlCommand)
              if GuidValueSet != []:
                  GuidValue = GuidValueSet[0][0]
                  GuidValue = GuidValue[GuidValue.find(GuidMacro) + len(GuidMacro) :]
                  GuidValue = GuidValue.lower().replace('\\', '').replace('\r', '').replace('\n', '').replace('l', '').strip()
                  GuidValue = GuidStructureStringToGuidString(GuidValue)
                  SqlCommand = """update Report set GuidMacro = '%s', GuidValue = '%s' where GuidName = '%s'""" %(GuidMacro, GuidValue, GuidName)
                  EotGlobalData.gDb.TblReport.Exec(SqlCommand)
                  continue
  
          # Update Hard Coded Ppi/Protocol
          SqlCommand = """select DISTINCT GuidValue, ItemType from Report where ModuleID = -2 and ItemMode = 'Produced'"""
          RecordSet = EotGlobalData.gDb.TblReport.Exec(SqlCommand)
          for Record in RecordSet:
              if Record[1] == 'Ppi':
                  EotGlobalData.gPpiList[Record[0].lower()] = -2
              if Record[1] == 'Protocol':
                  EotGlobalData.gProtocolList[Record[0].lower()] = -2
  
      ## GenerateQueryTable() method
      #
      #  Generate two tables improve query performance
      #
      #  @param self: The object pointer
      #
      def GenerateQueryTable(self):
          EdkLogger.quiet("Generating temp query table for analysis ... ")
          for Identifier in EotGlobalData.gIdentifierTableList:
              SqlCommand = """insert into Query (Name, Modifier, Value, Model)
                              select Name, Modifier, Value, Model from %s where (Model = %s or Model = %s)""" \
                              % (Identifier[0], MODEL_IDENTIFIER_VARIABLE, MODEL_IDENTIFIER_ASSIGNMENT_EXPRESSION)
              EotGlobalData.gDb.TblReport.Exec(SqlCommand)
              SqlCommand = """insert into Query2 (Name, Modifier, Value, Model)
                              select Name, Modifier, Value, Model from %s where Model = %s""" \
                              % (Identifier[0], MODEL_IDENTIFIER_MACRO_DEFINE)
              EotGlobalData.gDb.TblReport.Exec(SqlCommand)
  
      ## ParseExecutionOrder() method
      #
      #  Get final execution order
      #  1. Search all PPI
      #  2. Search all PROTOCOL
      #
      #  @param self: The object pointer
      #
      def ParseExecutionOrder(self):
          EdkLogger.quiet("Searching Ppi/Protocol ... ")
          for Identifier in EotGlobalData.gIdentifierTableList:
              ModuleID, ModuleName, ModuleGuid, SourceFileID, SourceFileFullPath, ItemName, ItemType, ItemMode, GuidName, GuidMacro, GuidValue, BelongsToFunction, Enabled = \
              -1, '', '', -1, '', '', '', '', '', '', '', '', 0
  
              SourceFileID = Identifier[0].replace('Identifier', '')
              SourceFileFullPath = Identifier[1]
              Identifier = Identifier[0]
  
              # Find Ppis
              ItemMode = 'Produced'
              SqlCommand = """select Value, Name, BelongsToFile, StartLine, EndLine from %s
                              where (Name like '%%%s%%' or Name like '%%%s%%' or Name like '%%%s%%') and Model = %s""" \
                              % (Identifier, '.InstallPpi', '->InstallPpi', 'PeiInstallPpi', MODEL_IDENTIFIER_FUNCTION_CALLING)
              SearchPpi(SqlCommand, Identifier, SourceFileID, SourceFileFullPath, ItemMode)
  
              ItemMode = 'Produced'
              SqlCommand = """select Value, Name, BelongsToFile, StartLine, EndLine from %s
                              where (Name like '%%%s%%' or Name like '%%%s%%') and Model = %s""" \
                              % (Identifier, '.ReInstallPpi', '->ReInstallPpi', MODEL_IDENTIFIER_FUNCTION_CALLING)
              SearchPpi(SqlCommand, Identifier, SourceFileID, SourceFileFullPath, ItemMode, 2)
  
              SearchPpiCallFunction(Identifier, SourceFileID, SourceFileFullPath, ItemMode)
  
              ItemMode = 'Consumed'
              SqlCommand = """select Value, Name, BelongsToFile, StartLine, EndLine from %s
                              where (Name like '%%%s%%' or Name like '%%%s%%') and Model = %s""" \
                              % (Identifier, '.LocatePpi', '->LocatePpi', MODEL_IDENTIFIER_FUNCTION_CALLING)
              SearchPpi(SqlCommand, Identifier, SourceFileID, SourceFileFullPath, ItemMode)
  
              SearchFunctionCalling(Identifier, SourceFileID, SourceFileFullPath, 'Ppi', ItemMode)
  
              ItemMode = 'Callback'
              SqlCommand = """select Value, Name, BelongsToFile, StartLine, EndLine from %s
                              where (Name like '%%%s%%' or Name like '%%%s%%') and Model = %s""" \
                              % (Identifier, '.NotifyPpi', '->NotifyPpi', MODEL_IDENTIFIER_FUNCTION_CALLING)
              SearchPpi(SqlCommand, Identifier, SourceFileID, SourceFileFullPath, ItemMode)
  
              # Find Protocols
              ItemMode = 'Produced'
              SqlCommand = """select Value, Name, BelongsToFile, StartLine, EndLine from %s
                              where (Name like '%%%s%%' or Name like '%%%s%%' or Name like '%%%s%%' or Name like '%%%s%%') and Model = %s""" \
                              % (Identifier, '.InstallProtocolInterface', '.ReInstallProtocolInterface', '->InstallProtocolInterface', '->ReInstallProtocolInterface', MODEL_IDENTIFIER_FUNCTION_CALLING)
              SearchProtocols(SqlCommand, Identifier, SourceFileID, SourceFileFullPath, ItemMode, 1)
  
              SqlCommand = """select Value, Name, BelongsToFile, StartLine, EndLine from %s
                              where (Name like '%%%s%%' or Name like '%%%s%%') and Model = %s""" \
                              % (Identifier, '.InstallMultipleProtocolInterfaces', '->InstallMultipleProtocolInterfaces', MODEL_IDENTIFIER_FUNCTION_CALLING)
              SearchProtocols(SqlCommand, Identifier, SourceFileID, SourceFileFullPath, ItemMode, 2)
  
              SearchFunctionCalling(Identifier, SourceFileID, SourceFileFullPath, 'Protocol', ItemMode)
  
              ItemMode = 'Consumed'
              SqlCommand = """select Value, Name, BelongsToFile, StartLine, EndLine from %s
                              where (Name like '%%%s%%' or Name like '%%%s%%') and Model = %s""" \
                              % (Identifier, '.LocateProtocol', '->LocateProtocol', MODEL_IDENTIFIER_FUNCTION_CALLING)
              SearchProtocols(SqlCommand, Identifier, SourceFileID, SourceFileFullPath, ItemMode, 0)
  
              SqlCommand = """select Value, Name, BelongsToFile, StartLine, EndLine from %s
                              where (Name like '%%%s%%' or Name like '%%%s%%') and Model = %s""" \
                              % (Identifier, '.HandleProtocol', '->HandleProtocol', MODEL_IDENTIFIER_FUNCTION_CALLING)
              SearchProtocols(SqlCommand, Identifier, SourceFileID, SourceFileFullPath, ItemMode, 1)
  
              SearchFunctionCalling(Identifier, SourceFileID, SourceFileFullPath, 'Protocol', ItemMode)
  
              ItemMode = 'Callback'
              SqlCommand = """select Value, Name, BelongsToFile, StartLine, EndLine from %s
                              where (Name like '%%%s%%' or Name like '%%%s%%') and Model = %s""" \
                              % (Identifier, '.RegisterProtocolNotify', '->RegisterProtocolNotify', MODEL_IDENTIFIER_FUNCTION_CALLING)
              SearchProtocols(SqlCommand, Identifier, SourceFileID, SourceFileFullPath, ItemMode, 0)
  
              SearchFunctionCalling(Identifier, SourceFileID, SourceFileFullPath, 'Protocol', ItemMode)
  
          # Hard Code
          EotGlobalData.gDb.TblReport.Insert(-2, '', '', -1, '', '', 'Ppi', 'Produced', 'gEfiSecPlatformInformationPpiGuid', '', '', '', 0)
          EotGlobalData.gDb.TblReport.Insert(-2, '', '', -1, '', '', 'Ppi', 'Produced', 'gEfiNtLoadAsDllPpiGuid', '', '', '', 0)
          EotGlobalData.gDb.TblReport.Insert(-2, '', '', -1, '', '', 'Ppi', 'Produced', 'gNtPeiLoadFileGuid', '', '', '', 0)
          EotGlobalData.gDb.TblReport.Insert(-2, '', '', -1, '', '', 'Ppi', 'Produced', 'gPeiNtAutoScanPpiGuid', '', '', '', 0)
          EotGlobalData.gDb.TblReport.Insert(-2, '', '', -1, '', '', 'Ppi', 'Produced', 'gNtFwhPpiGuid', '', '', '', 0)
          EotGlobalData.gDb.TblReport.Insert(-2, '', '', -1, '', '', 'Ppi', 'Produced', 'gPeiNtThunkPpiGuid', '', '', '', 0)
          EotGlobalData.gDb.TblReport.Insert(-2, '', '', -1, '', '', 'Ppi', 'Produced', 'gPeiPlatformTypePpiGuid', '', '', '', 0)
          EotGlobalData.gDb.TblReport.Insert(-2, '', '', -1, '', '', 'Ppi', 'Produced', 'gPeiFrequencySelectionCpuPpiGuid', '', '', '', 0)
          EotGlobalData.gDb.TblReport.Insert(-2, '', '', -1, '', '', 'Ppi', 'Produced', 'gPeiCachePpiGuid', '', '', '', 0)
  
          EotGlobalData.gDb.Conn.commit()
  
  
      ## BuildDatabase() methoc
      #
      #  Build the database for target
      #
      #  @param self: The object pointer
      #
      def BuildDatabase(self):
          # Clean report table
          EotGlobalData.gDb.TblReport.Drop()
          EotGlobalData.gDb.TblReport.Create()
  
          # Build database
          if self.IsInit:
              self.BuildMetaDataFileDatabase(EotGlobalData.gINF_FILES)
              EdkLogger.quiet("Building database for source code ...")
              c.CreateCCodeDB(EotGlobalData.gSOURCE_FILES)
              EdkLogger.quiet("Building database for source code done!")
  
          EotGlobalData.gIdentifierTableList = GetTableList((MODEL_FILE_C, MODEL_FILE_H), 'Identifier', EotGlobalData.gDb)
  
      ## BuildMetaDataFileDatabase() method
      #
      #  Build the database for meta data files
      #
      #  @param self: The object pointer
      #  @param Inf_Files: A list for all INF files
      #
      def BuildMetaDataFileDatabase(self, Inf_Files):
          EdkLogger.quiet("Building database for meta data files ...")
          for InfFile in Inf_Files:
              if not InfFile:
                  continue
              EdkLogger.quiet("Parsing %s ..."  % str(InfFile))
              EdkInfParser(InfFile, EotGlobalData.gDb, Inf_Files[InfFile], '')
  
          EotGlobalData.gDb.Conn.commit()
          EdkLogger.quiet("Building database for meta data files done!")
  
      ## ParseOption() method
      #
      #  Parse command line options
      #
      #  @param self: The object pointer
      #
      def ParseOption(self):
          (Options, Target) = self.EotOptionParser()
  
          # Set log level
          self.SetLogLevel(Options)
  
          if Options.FvFileList:
              self.FvFileList = Options.FvFileList
  
          if Options.MapFileList:
              self.MapFileList = Options.FvMapFileList
  
          if Options.SourceFileList:
              self.SourceFileList = Options.SourceFileList
  
          if Options.IncludeDirList:
              self.IncludeDirList = Options.IncludeDirList
  
          if Options.DecFileList:
              self.DecFileList = Options.DecFileList
  
          if Options.GuidList:
              self.GuidList = Options.GuidList
  
          if Options.LogFile:
              self.LogFile = Options.LogFile
  
          if Options.keepdatabase:
              self.IsInit = False
  
      ## SetLogLevel() method
      #
      #  Set current log level of the tool based on args
      #
      #  @param self: The object pointer
      #  @param Option: The option list including log level setting
      #
      def SetLogLevel(self, Option):
          if Option.verbose is not None:
              EdkLogger.SetLevel(EdkLogger.VERBOSE)
          elif Option.quiet is not None:
              EdkLogger.SetLevel(EdkLogger.QUIET)
          elif Option.debug is not None:
              EdkLogger.SetLevel(Option.debug + 1)
          else:
              EdkLogger.SetLevel(EdkLogger.INFO)
  
      ## EotOptionParser() method
      #
      #  Using standard Python module optparse to parse command line option of this tool.
      #
      #  @param self: The object pointer
      #
      #  @retval Opt   A optparse.Values object containing the parsed options
      #  @retval Args  Target of build command
      #
      def EotOptionParser(self):
          Parser = OptionParser(description = self.Copyright, version = self.Version, prog = "Eot.exe", usage = "%prog [options]")
          Parser.add_option("-m", "--makefile filename", action="store", type="string", dest='MakeFile',
              help="Specify a makefile for the platform.")
          Parser.add_option("-c", "--dsc filename", action="store", type="string", dest="DscFile",
              help="Specify a dsc file for the platform.")
          Parser.add_option("-f", "--fv filename", action="store", type="string", dest="FvFileList",
              help="Specify fv file list, quoted by \"\".")
          Parser.add_option("-a", "--map filename", action="store", type="string", dest="MapFileList",
              help="Specify map file list, quoted by \"\".")
          Parser.add_option("-s", "--source files", action="store", type="string", dest="SourceFileList",
              help="Specify source file list by a file")
          Parser.add_option("-i", "--include dirs", action="store", type="string", dest="IncludeDirList",
              help="Specify include dir list by a file")
          Parser.add_option("-e", "--dec files", action="store", type="string", dest="DecFileList",
              help="Specify dec file list by a file")
          Parser.add_option("-g", "--guid list", action="store", type="string", dest="GuidList",
              help="Specify guid file list by a file")
          Parser.add_option("-l", "--log filename", action="store", type="string", dest="LogFile",
              help="Specify real execution log file")
  
          Parser.add_option("-k", "--keepdatabase", action="store_true", type=None, help="The existing Eot database will not be cleaned except report information if this option is specified.")
  
          Parser.add_option("-q", "--quiet", action="store_true", type=None, help="Disable all messages except FATAL ERRORS.")
          Parser.add_option("-v", "--verbose", action="store_true", type=None, help="Turn on verbose output with informational messages printed, "\
                                                                                     "including library instances selected, final dependency expression, "\
                                                                                     "and warning messages, etc.")
          Parser.add_option("-d", "--debug", action="store", type="int", help="Enable debug messages at specified level.")
  
          (Opt, Args)=Parser.parse_args()
  
          return (Opt, Args)
  
  ##
  #
  # This acts like the main() function for the script, unless it is 'import'ed into another
  # script.
  #
  if __name__ == '__main__':
      # Initialize log system
      EdkLogger.Initialize()
      EdkLogger.IsRaiseError = False
      EdkLogger.quiet(time.strftime("%H:%M:%S, %b.%d %Y ", time.localtime()) + "[00:00]" + "\n")
  
      StartTime = time.clock()
      Eot = Eot(CommandLineOption=False,
                SourceFileList=r'C:\TestEot\Source.txt',
                GuidList=r'C:\TestEot\Guid.txt',
                FvFileList=r'C:\TestEot\FVRECOVERY.Fv')
      FinishTime = time.clock()
  
      BuildDuration = time.strftime("%M:%S", time.gmtime(int(round(FinishTime - StartTime))))
      EdkLogger.quiet("\n%s [%s]" % (time.strftime("%H:%M:%S, %b.%d %Y", time.localtime()), BuildDuration))
  