text: ## @file
  # process GUIDed section generation
  #
  #  Copyright (c) 2007 - 2018, Intel Corporation. All rights reserved.<BR>
  #  Copyright (c) 2018, Hewlett Packard Enterprise Development, L.P.<BR>
  #
  #  SPDX-License-Identifier: BSD-2-Clause-Patent
  #
  
  ##
  # Import Modules
  #
  from __future__ import absolute_import
  from . import Section
  import subprocess
  from .Ffs import SectionSuffix
  import edk2basetools.Common.LongFilePathOs as os
  from .GenFdsGlobalVariable import GenFdsGlobalVariable
  from .GenFdsGlobalVariable import FindExtendTool
  from edk2basetools.CommonDataClass.FdfClass import GuidSectionClassObject
  import sys
  from edk2basetools.Common import EdkLogger
  from edk2basetools.Common.BuildToolError import *
  from .FvImageSection import FvImageSection
  from edk2basetools.Common.LongFilePathSupport import OpenLongFilePath as open
  from edk2basetools.Common.DataType import *
  
  ## generate GUIDed section
  #
  #
  class GuidSection(GuidSectionClassObject) :
  
      ## The constructor
      #
      #   @param  self        The object pointer
      #
      def __init__(self):
          GuidSectionClassObject.__init__(self)
  
      ## GenSection() method
      #
      #   Generate GUIDed section
      #
      #   @param  self        The object pointer
      #   @param  OutputPath  Where to place output file
      #   @param  ModuleName  Which module this section belongs to
      #   @param  SecNum      Index of section
      #   @param  KeyStringList  Filter for inputs of section generation
      #   @param  FfsInf      FfsInfStatement object that contains this section data
      #   @param  Dict        dictionary contains macro and its value
      #   @retval tuple       (Generated file name, section alignment)
      #
      def GenSection(self, OutputPath, ModuleName, SecNum, KeyStringList, FfsInf=None, Dict=None, IsMakefile=False):
          #
          # Generate all section
          #
          self.KeyStringList = KeyStringList
          self.CurrentArchList = GenFdsGlobalVariable.ArchList
          if FfsInf is not None:
              self.Alignment = FfsInf.__ExtendMacro__(self.Alignment)
              self.NameGuid = FfsInf.__ExtendMacro__(self.NameGuid)
              self.SectionType = FfsInf.__ExtendMacro__(self.SectionType)
              self.CurrentArchList = [FfsInf.CurrentArch]
  
          SectFile = tuple()
          SectAlign = []
          Index = 0
          MaxAlign = None
          if Dict is None:
              Dict = {}
          if self.FvAddr != []:
              FvAddrIsSet = True
          else:
              FvAddrIsSet = False
  
          if self.ProcessRequired in ("TRUE", "1"):
              if self.FvAddr != []:
                  #no use FvAddr when the image is processed.
                  self.FvAddr = []
              if self.FvParentAddr is not None:
                  #no use Parent Addr when the image is processed.
                  self.FvParentAddr = None
  
          for Sect in self.SectionList:
              Index = Index + 1
              SecIndex = '%s.%d' % (SecNum, Index)
              # set base address for inside FvImage
              if isinstance(Sect, FvImageSection):
                  if self.FvAddr != []:
                      Sect.FvAddr = self.FvAddr.pop(0)
                  self.IncludeFvSection = True
              elif isinstance(Sect, GuidSection):
                  Sect.FvAddr = self.FvAddr
                  Sect.FvParentAddr = self.FvParentAddr
              ReturnSectList, align = Sect.GenSection(OutputPath, ModuleName, SecIndex, KeyStringList, FfsInf, Dict, IsMakefile=IsMakefile)
              if isinstance(Sect, GuidSection):
                  if Sect.IncludeFvSection:
                      self.IncludeFvSection = Sect.IncludeFvSection
  
              if align is not None:
                  if MaxAlign is None:
                      MaxAlign = align
                  if GenFdsGlobalVariable.GetAlignment (align) > GenFdsGlobalVariable.GetAlignment (MaxAlign):
                      MaxAlign = align
              if ReturnSectList != []:
                  if align is None:
                      align = "1"
                  for file in ReturnSectList:
                      SectFile += (file,)
                      SectAlign.append(align)
  
          if MaxAlign is not None:
              if self.Alignment is None:
                  self.Alignment = MaxAlign
              else:
                  if GenFdsGlobalVariable.GetAlignment (MaxAlign) > GenFdsGlobalVariable.GetAlignment (self.Alignment):
                      self.Alignment = MaxAlign
  
          OutputFile = OutputPath + \
                       os.sep + \
                       ModuleName + \
                       SUP_MODULE_SEC + \
                       SecNum + \
                       SectionSuffix['GUIDED']
          OutputFile = os.path.normpath(OutputFile)
  
          ExternalTool = None
          ExternalOption = None
          if self.NameGuid is not None:
              ExternalTool, ExternalOption = FindExtendTool(self.KeyStringList, self.CurrentArchList, self.NameGuid)
  
          #
          # If not have GUID , call default
          # GENCRC32 section
          #
          if self.NameGuid is None :
              GenFdsGlobalVariable.VerboseLogger("Use GenSection function Generate CRC32 Section")
              GenFdsGlobalVariable.GenerateSection(OutputFile, SectFile, Section.Section.SectionType[self.SectionType], InputAlign=SectAlign, IsMakefile=IsMakefile)
              OutputFileList = []
              OutputFileList.append(OutputFile)
              return OutputFileList, self.Alignment
          #or GUID not in External Tool List
          elif ExternalTool is None:
              EdkLogger.error("GenFds", GENFDS_ERROR, "No tool found with GUID %s" % self.NameGuid)
          else:
              DummyFile = OutputFile + ".dummy"
              #
              # Call GenSection with DUMMY section type.
              #
              GenFdsGlobalVariable.GenerateSection(DummyFile, SectFile, InputAlign=SectAlign, IsMakefile=IsMakefile)
              #
              # Use external tool process the Output
              #
              TempFile = OutputPath + \
                         os.sep + \
                         ModuleName + \
                         SUP_MODULE_SEC + \
                         SecNum + \
                         '.tmp'
              TempFile = os.path.normpath(TempFile)
              #
              # Remove temp file if its time stamp is older than dummy file
              # Just in case the external tool fails at this time but succeeded before
              # Error should be reported if the external tool does not generate a new output based on new input
              #
              if os.path.exists(TempFile) and os.path.exists(DummyFile) and os.path.getmtime(TempFile) < os.path.getmtime(DummyFile):
                  os.remove(TempFile)
  
              FirstCall = False
              CmdOption = '-e'
              if ExternalOption is not None:
                  CmdOption = CmdOption + ' ' + ExternalOption
              if not GenFdsGlobalVariable.EnableGenfdsMultiThread:
                  if self.ProcessRequired not in ("TRUE", "1") and self.IncludeFvSection and not FvAddrIsSet and self.FvParentAddr is not None:
                      #FirstCall is only set for the encapsulated flash FV image without process required attribute.
                      FirstCall = True
                  #
                  # Call external tool
                  #
                  ReturnValue = [1]
                  if FirstCall:
                      #first try to call the guided tool with -z option and CmdOption for the no process required guided tool.
                      GenFdsGlobalVariable.GuidTool(TempFile, [DummyFile], ExternalTool, '-z' + ' ' + CmdOption, ReturnValue)
  
                  #
                  # when no call or first call failed, ReturnValue are not 1.
                  # Call the guided tool with CmdOption
                  #
                  if ReturnValue[0] != 0:
                      FirstCall = False
                      ReturnValue[0] = 0
                      GenFdsGlobalVariable.GuidTool(TempFile, [DummyFile], ExternalTool, CmdOption)
                  #
                  # There is external tool which does not follow standard rule which return nonzero if tool fails
                  # The output file has to be checked
                  #
  
                  if not os.path.exists(TempFile) :
                      EdkLogger.error("GenFds", COMMAND_FAILURE, 'Fail to call %s, no output file was generated' % ExternalTool)
  
                  FileHandleIn = open(DummyFile, 'rb')
                  FileHandleIn.seek(0, 2)
                  InputFileSize = FileHandleIn.tell()
  
                  FileHandleOut = open(TempFile, 'rb')
                  FileHandleOut.seek(0, 2)
                  TempFileSize = FileHandleOut.tell()
  
                  Attribute = []
                  HeaderLength = None
                  if self.ExtraHeaderSize != -1:
                      HeaderLength = str(self.ExtraHeaderSize)
  
                  if self.ProcessRequired == "NONE" and HeaderLength is None:
                      if TempFileSize > InputFileSize:
                          FileHandleIn.seek(0)
                          BufferIn = FileHandleIn.read()
                          FileHandleOut.seek(0)
                          BufferOut = FileHandleOut.read()
                          if BufferIn == BufferOut[TempFileSize - InputFileSize:]:
                              HeaderLength = str(TempFileSize - InputFileSize)
                      #auto sec guided attribute with process required
                      if HeaderLength is None:
                          Attribute.append('PROCESSING_REQUIRED')
  
                  FileHandleIn.close()
                  FileHandleOut.close()
  
                  if FirstCall and 'PROCESSING_REQUIRED' in Attribute:
                      # Guided data by -z option on first call is the process required data. Call the guided tool with the real option.
                      GenFdsGlobalVariable.GuidTool(TempFile, [DummyFile], ExternalTool, CmdOption)
  
                  #
                  # Call Gensection Add Section Header
                  #
                  if self.ProcessRequired in ("TRUE", "1"):
                      if 'PROCESSING_REQUIRED' not in Attribute:
                          Attribute.append('PROCESSING_REQUIRED')
  
                  if self.AuthStatusValid in ("TRUE", "1"):
                      Attribute.append('AUTH_STATUS_VALID')
                  GenFdsGlobalVariable.GenerateSection(OutputFile, [TempFile], Section.Section.SectionType['GUIDED'],
                                                       Guid=self.NameGuid, GuidAttr=Attribute, GuidHdrLen=HeaderLength)
  
              else:
                  #add input file for GenSec get PROCESSING_REQUIRED
                  GenFdsGlobalVariable.GuidTool(TempFile, [DummyFile], ExternalTool, CmdOption, IsMakefile=IsMakefile)
                  Attribute = []
                  HeaderLength = None
                  if self.ExtraHeaderSize != -1:
                      HeaderLength = str(self.ExtraHeaderSize)
                  if self.AuthStatusValid in ("TRUE", "1"):
                      Attribute.append('AUTH_STATUS_VALID')
                  if self.ProcessRequired == "NONE" and HeaderLength is None:
                      GenFdsGlobalVariable.GenerateSection(OutputFile, [TempFile], Section.Section.SectionType['GUIDED'],
                                                           Guid=self.NameGuid, GuidAttr=Attribute,
                                                           GuidHdrLen=HeaderLength, DummyFile=DummyFile, IsMakefile=IsMakefile)
                  else:
                      if self.ProcessRequired in ("TRUE", "1"):
                          if 'PROCESSING_REQUIRED' not in Attribute:
                              Attribute.append('PROCESSING_REQUIRED')
                      GenFdsGlobalVariable.GenerateSection(OutputFile, [TempFile], Section.Section.SectionType['GUIDED'],
                                                           Guid=self.NameGuid, GuidAttr=Attribute,
                                                           GuidHdrLen=HeaderLength, IsMakefile=IsMakefile)
  
              OutputFileList = []
              OutputFileList.append(OutputFile)
              if 'PROCESSING_REQUIRED' in Attribute:
                  # reset guided section alignment to none for the processed required guided data
                  self.Alignment = None
                  self.IncludeFvSection = False
                  self.ProcessRequired = "TRUE"
              if IsMakefile and self.Alignment is not None and self.Alignment.strip() == '0':
                  self.Alignment = '1'
              return OutputFileList, self.Alignment
  
  
  
  