[edk2-devel] [Patch v3 3/3] BaseTools: Add a tool FMMT

Liming Gao liming.gao at intel.com
Mon Jul 1 11:27:31 UTC 2019


From: Shenglei Zhang <shenglei.zhang at intel.com>

FMMT is a tool to enable removal, addition and replacement of
FFS files in FD image binaries.
https://bugzilla.tianocore.org/show_bug.cgi?id=1847

Cc: Bob Feng <bob.c.feng at intel.com>
Cc: Liming Gao <liming.gao at intel.com>
Signed-off-by: Shenglei Zhang <shenglei.zhang at intel.com>
Reviewed-by: Bob Feng <bob.c.feng at intel.com>
---
 BaseTools/Source/C/FMMT/FirmwareModuleManagement.c | 2559 ++++++++++
 BaseTools/Source/C/FMMT/FmmtLib.c                  | 5051 ++++++++++++++++++++
 BaseTools/Source/C/FMMT/Rebase.c                   |  846 ++++
 BaseTools/BinWrappers/PosixLike/FMMT               |   29 +
 BaseTools/Source/C/FMMT/FirmwareModuleManagement.h |  479 ++
 BaseTools/Source/C/FMMT/FmmtConf.ini               |    6 +
 BaseTools/Source/C/FMMT/GNUmakefile                |   16 +
 BaseTools/Source/C/FMMT/Makefile                   |   17 +
 BaseTools/Source/C/FMMT/Rebase.h                   |   31 +
 BaseTools/Source/C/GNUmakefile                     |    1 +
 BaseTools/Source/C/Makefile                        |    1 +
 11 files changed, 9036 insertions(+)
 create mode 100644 BaseTools/Source/C/FMMT/FirmwareModuleManagement.c
 create mode 100644 BaseTools/Source/C/FMMT/FmmtLib.c
 create mode 100644 BaseTools/Source/C/FMMT/Rebase.c
 create mode 100755 BaseTools/BinWrappers/PosixLike/FMMT
 create mode 100644 BaseTools/Source/C/FMMT/FirmwareModuleManagement.h
 create mode 100644 BaseTools/Source/C/FMMT/FmmtConf.ini
 create mode 100644 BaseTools/Source/C/FMMT/GNUmakefile
 create mode 100644 BaseTools/Source/C/FMMT/Makefile
 create mode 100644 BaseTools/Source/C/FMMT/Rebase.h

diff --git a/BaseTools/Source/C/FMMT/FirmwareModuleManagement.c b/BaseTools/Source/C/FMMT/FirmwareModuleManagement.c
new file mode 100644
index 0000000000..63ae3c45a4
--- /dev/null
+++ b/BaseTools/Source/C/FMMT/FirmwareModuleManagement.c
@@ -0,0 +1,2559 @@
+/** @file
+
+ FMMT main routine.
+
+Copyright (c) 2019, Intel Corporation. All rights reserved.<BR>
+SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#include "FirmwareModuleManagement.h"
+#include "Rebase.h"
+#include <stdlib.h>
+#include <wchar.h>
+
+CHAR8*      mGuidToolDefinition     = "FmmtConf.ini";
+extern EFI_FIRMWARE_VOLUME_HEADER  *mFvHeader;
+extern UINT32                      mFvLength;
+
+//
+// Store GUIDed Section guid->tool mapping
+//
+EFI_HANDLE mParsedGuidedSectionTools = NULL;
+#define EFI_FFS_VOLUME_TOP_FILE_GUID \
+{ \
+  0x1BA0062E, 0xC779, 0x4582, { 0x85, 0x66, 0x33, 0x6A, 0xE8, 0xF7, 0x8F, 0x09 } \
+}
+#define FSP_FFS_INFORMATION_FILE_GUID \
+{ 0x912740be, 0x2284, 0x4734, { 0xb9, 0x71, 0x84, 0xb0, 0x27, 0x35, 0x3f, 0x0c }};
+
+static EFI_GUID mVTFGuid = EFI_FFS_VOLUME_TOP_FILE_GUID;
+static EFI_GUID mFSPGuid = FSP_FFS_INFORMATION_FILE_GUID;
+
+
+/**
+
+Routine Description:
+
+  The Usage of FMMT tool.
+
+Arguments:
+
+  None
+
+Returns:
+
+  None
+
+**/
+VOID
+Usage (
+  VOID
+  )
+{
+  //
+  // Summary usage
+  //
+  fprintf (stdout, "Usage: %s [options] \n\n", UTILITY_SHORT_NAME);
+
+  //
+  // Copyright declaration
+  //
+  fprintf (stdout, "Copyright (c) 2011 - 2018, Intel Corporation. All rights reserved.\n\n");
+
+  //
+  // Details Option
+  //
+  fprintf (stdout, "Options:\n");
+
+  //
+  // Command Line for View
+  //
+  fprintf (stdout, "  -v <input-binary-file>\n\
+            View each FV and the named files within each FV.\n");
+
+  //
+  // Command Line for Delete entire FV
+  //
+  fprintf (stdout, "  -d <input-binary-file> <FV-id> <output-binary-file>\n\
+            Delete the entire FV in an FD binary\n");
+
+  //
+  // Command Line for Delete file from FV
+  //
+  fprintf (stdout, "  -d <input-binary-file> <FV-id> <File-Name> [<FV-id> <File-Name> ...] <output-binary-file>\n\
+            Delete a file (or files) from the firmware volume in an FD binary\n");
+
+  //
+  // Command Line for Add
+  //
+  fprintf (stdout, "  -a <input-binary-file> <FV-id> <NewFilePath> [<FV-id> <NewFilePath> ...] <output-binary-file>\n\
+            Add a file (or files) to the firmware volume in an FD binary\n");
+
+  //
+  // Command Line for Replace
+  //
+  fprintf (stdout, "  -r <input-binary-file> <FV-id> <File-Name> <NewFilePath> [<FV-id> <File-Name> <NewFilePath> ...] <output-binary-file>\n\
+            The replace command combines the functionality of remove and add into a single operation.\n");
+
+  fprintf (stdout, "\nNote:\n");
+  fprintf (stdout, "  <FV-id> is the sequence of the firmware volume included in the FD image, it both support the sequentially format like FV0, FV1 and the FV's file guid value format.\n");
+  return;
+}
+
+
+BOOLEAN
+IsVtf(EFI_FFS_FILE_HEADER2* ffs) {
+  if (!memcmp(&ffs->Name, &mVTFGuid, sizeof (EFI_GUID))) {
+    return TRUE;
+  } else {
+    return FALSE;
+  }
+}
+
+BOOLEAN
+IsFsp(EFI_FFS_FILE_HEADER2* ffs) {
+  if (!memcmp(&ffs->Name, &mFSPGuid, sizeof (EFI_GUID))) {
+    return TRUE;
+  } else {
+    return FALSE;
+  }
+}
+
+static
+EFI_STATUS
+GetBaseAddrFromVtf(FIRMWARE_DEVICE *FdData, CHAR8 *FvId, UINT64 *BaseAddr) {
+  EFI_STATUS Status;
+  FV_INFORMATION *CurrentFv;
+  FV_INFORMATION *FvInFd;
+
+  Status = LibLocateFvViaFvId(FdData, FvId, &FvInFd);
+  if (EFI_ERROR(Status)) {
+    return Status;
+  }
+
+  //
+  // Get bottom FV
+  //
+  CurrentFv = FdData->Fv;
+  while (CurrentFv->FvNext) {
+    CurrentFv = CurrentFv->FvNext;
+  }
+  if (CurrentFv->FfsNumbers > 0 && IsVtf(&CurrentFv->FfsHeader[CurrentFv->FfsNumbers])) {
+    //
+    // Found VTF at the top of FV
+    // Assume 4G address
+    //
+    *BaseAddr = 0x100000000 - (FdData->Size - FvInFd->ImageAddress);
+    return EFI_SUCCESS;
+  }
+  return EFI_NOT_FOUND;
+}
+
+static
+EFI_STATUS
+GetBaseAddrFromFsp(FIRMWARE_DEVICE *FdData, CONST UINT8* FdBuffer, CHAR8 *FvId, UINT64 *BaseAddr)
+{
+  EFI_STATUS Status;
+  FV_INFORMATION *FvInFd;
+  FV_INFORMATION *CurrentFv;
+  FV_INFORMATION *FspFv;
+  UINT32 Offset;
+  UINT64 ImageSize;
+  UINT64 Size;
+  EFI_FFS_FILE_HEADER2 *CurrentFile;
+  BOOLEAN FspFound;
+
+  Status = LibLocateFvViaFvId(FdData, FvId, &FvInFd);
+  if (EFI_ERROR(Status)) {
+    return Status;
+  }
+
+  ImageSize = 0;
+  Size = 0;
+  FspFound = FALSE;
+  FspFv = NULL;
+  CurrentFv = FdData->Fv;
+  while (CurrentFv) {
+    if (CurrentFv->FfsNumbers > 0 && IsFsp(&CurrentFv->FfsHeader[0])) {
+      Offset = CurrentFv->ImageAddress + CurrentFv->FfsAttuibutes[0].Offset;
+      CurrentFile = (EFI_FFS_FILE_HEADER2 *)(FdBuffer + Offset);
+      //
+      // Skip FFS header
+      //
+      Offset += GetFfsHeaderLength((EFI_FFS_FILE_HEADER *)CurrentFile);
+      //
+      // Stip section header
+      //
+      Offset += GetSectionHeaderLength((EFI_COMMON_SECTION_HEADER *)(FdBuffer + Offset));
+      //
+      // We have raw FSP here, and 24 is the image size
+      //
+      ImageSize = *((UINT32 *)(FdBuffer + Offset + 24));
+      //
+      // 28 is the base address
+      //
+      *BaseAddr = *((UINT32 *)(FdBuffer + Offset + 28));
+      FspFound = TRUE;
+      FspFv = CurrentFv;
+    }
+    if (CurrentFv == FvInFd){
+      break;
+    }
+    CurrentFv = CurrentFv->FvNext;
+  }
+  if (!FspFound) {
+    return EFI_NOT_FOUND;
+  }
+  //
+  // Check if FSP binary contains this FV
+  //
+  while (FspFv != NULL) {
+    Size += FspFv->FvHeader->FvLength;
+    if (FspFv == FvInFd) {
+      break;
+    }
+    FspFv = FspFv->FvNext;
+  }
+  if (Size <= ImageSize) {
+    return EFI_SUCCESS;
+  }
+
+  return EFI_NOT_FOUND;
+}
+
+static
+VOID
+AddPadFile(EFI_FIRMWARE_VOLUME_HEADER *Fv, EFI_FFS_FILE_HEADER2 *PadFile, UINT32 PadFileSize) {
+  UINT32 hdrSize;
+
+  if (Fv->Attributes & EFI_FVB2_ERASE_POLARITY) {
+    memset(PadFile, -1, PadFileSize);
+  }
+  else {
+    memset(PadFile, 0, PadFileSize);
+  }
+  PadFile->Type = EFI_FV_FILETYPE_FFS_PAD;
+  PadFile->Attributes = 0;
+
+  //
+  // Write pad file size (calculated size minus next file header size)
+  //
+  if (PadFileSize >= MAX_FFS_SIZE) {
+    memset(PadFile->Size, 0, sizeof(UINT8)* 3);
+    ((EFI_FFS_FILE_HEADER2 *)PadFile)->ExtendedSize = PadFileSize;
+    PadFile->Attributes |= FFS_ATTRIB_LARGE_FILE;
+    hdrSize = sizeof(EFI_FFS_FILE_HEADER2);
+  }
+  else {
+    PadFile->Size[0] = (UINT8)(PadFileSize & 0xFF);
+    PadFile->Size[1] = (UINT8)((PadFileSize >> 8) & 0xFF);
+    PadFile->Size[2] = (UINT8)((PadFileSize >> 16) & 0xFF);
+    hdrSize = sizeof(EFI_FFS_FILE_HEADER);
+  }
+
+  //
+  // Fill in checksums and state, they must be 0 for checksumming.
+  //
+  PadFile->IntegrityCheck.Checksum.Header = 0;
+  PadFile->IntegrityCheck.Checksum.File = 0;
+  PadFile->State = 0;
+  PadFile->IntegrityCheck.Checksum.Header = CalculateChecksum8((UINT8 *)PadFile, hdrSize);
+  PadFile->IntegrityCheck.Checksum.File = FFS_FIXED_CHECKSUM;
+
+  PadFile->State = EFI_FILE_HEADER_CONSTRUCTION | EFI_FILE_HEADER_VALID | EFI_FILE_DATA_VALID;
+  if (Fv->Attributes & EFI_FVB2_ERASE_POLARITY) {
+    PadFile->State = (UINT8)~(PadFile->State);
+  }
+}
+
+static
+UINT8* ReadFileToBuffer(CONST CHAR8 *FdName, UINT32 *FdSize) {
+  FILE* file;
+
+  UINT8 *FdBuffer = NULL;
+
+  file = fopen(FdName, "rb");
+  if (file == NULL)
+    return NULL;
+
+  fseek(file, 0, SEEK_SET);
+  fseek(file, 0, SEEK_END);
+  *FdSize = ftell(file);
+  fseek(file, 0, SEEK_SET);
+
+  FdBuffer = malloc(*FdSize);
+  if (FdBuffer == NULL) {
+    goto FAIL;
+  }
+  if (fread(FdBuffer, 1, *FdSize, file) != *FdSize) {
+    goto FAIL;
+  }
+  fclose(file);
+  return FdBuffer;
+FAIL:
+  free(FdBuffer);
+  fclose(file);
+  return NULL;
+}
+
+static UINT32 CalcuFfsSize(EFI_FIRMWARE_VOLUME_HEADER* Fv, CONST EFI_FFS_FILE_HEADER2 *Ffs) {
+  EFI_FFS_FILE_HEADER2        *NextFile;
+  UINTN FfsSize;
+  UINTN FvSize;
+  UINTN Offset;
+
+  FfsSize = GetFfsFileLength((EFI_FFS_FILE_HEADER *)Ffs);
+  FfsSize += (UINT8 *)ALIGN_POINTER(((UINT8 *)Ffs + FfsSize), 8) - ((UINT8 *)Ffs + FfsSize);
+  FvBufGetSize(Fv, &FvSize);
+  Offset = (UINT8 *)Ffs - (UINT8 *)Fv;
+  if (Offset + FfsSize < FvSize) {
+    NextFile = (EFI_FFS_FILE_HEADER2 *)((UINT8 *)Ffs + FfsSize);
+    if (NextFile->Type == EFI_FV_FILETYPE_FFS_PAD) {
+      FfsSize += GetFfsFileLength((EFI_FFS_FILE_HEADER *)NextFile);
+    }
+  }
+  return FfsSize;
+}
+
+static
+EFI_STATUS
+ReadFfsAlignment(
+IN EFI_FFS_FILE_HEADER    *FfsFile,
+IN OUT UINT32             *Alignment
+)
+{
+  //
+  // Verify input parameters.
+  //
+  if (FfsFile == NULL || Alignment == NULL) {
+    return EFI_INVALID_PARAMETER;
+  }
+
+  switch ((FfsFile->Attributes >> 3) & 0x07) {
+
+  case 0:
+    //
+    // 1 byte alignment
+    //
+    *Alignment = 0;
+    break;
+
+  case 1:
+    //
+    // 16 byte alignment
+    //
+    *Alignment = 4;
+    break;
+
+  case 2:
+    //
+    // 128 byte alignment
+    //
+    *Alignment = 7;
+    break;
+
+  case 3:
+    //
+    // 512 byte alignment
+    //
+    *Alignment = 9;
+    break;
+
+  case 4:
+    //
+    // 1K byte alignment
+    //
+    *Alignment = 10;
+    break;
+
+  case 5:
+    //
+    // 4K byte alignment
+    //
+    *Alignment = 12;
+    break;
+
+  case 6:
+    //
+    // 32K byte alignment
+    //
+    *Alignment = 15;
+    break;
+
+  case 7:
+    //
+    // 64K byte alignment
+    //
+    *Alignment = 16;
+    break;
+
+  default:
+    break;
+  }
+
+  return EFI_SUCCESS;
+}
+
+static
+BOOLEAN
+ReplaceFfs(EFI_FIRMWARE_VOLUME_HEADER* Fv, EFI_FFS_FILE_HEADER2 *InputFfs, EFI_FFS_FILE_HEADER2 *OldFfs) {
+  UINT32 FfsSize;
+  UINT32 NewFileSize;
+  UINT32 Offset;
+  UINT32 Align;
+  UINT32 HdrSize;
+  UINT32 PadSize;
+  EFI_FFS_FILE_HEADER2 *Pad;
+
+  Align = 0;
+  PadSize = 0;
+  Pad = NULL;
+  ReadFfsAlignment((EFI_FFS_FILE_HEADER *)InputFfs, &Align);
+  Align = 1 << Align;
+  HdrSize = GetFfsHeaderLength((EFI_FFS_FILE_HEADER *)InputFfs);
+
+  FfsSize = CalcuFfsSize(Fv, OldFfs);
+  //
+  // Align data
+  //
+  if ((((UINT8 *)OldFfs - (UINT8 *)Fv) + HdrSize) % Align != 0) {
+    PadSize = ((UINT8 *)OldFfs - (UINT8 *)Fv) + sizeof (EFI_FFS_FILE_HEADER)+HdrSize;
+    while (PadSize % Align != 0) {
+      PadSize++;
+    }
+    PadSize -= HdrSize;
+    PadSize -= ((UINT8 *)OldFfs - (UINT8 *)Fv);
+    if (FfsSize < PadSize) {
+      return FALSE;
+    }
+    FfsSize -= PadSize;
+    Pad = OldFfs;
+    OldFfs = (EFI_FFS_FILE_HEADER2 *)((UINT8 *)OldFfs + PadSize);
+  }
+
+  NewFileSize = GetFfsFileLength((EFI_FFS_FILE_HEADER *)InputFfs);
+  Offset = (UINT8 *)ALIGN_POINTER(((UINT8 *)OldFfs + NewFileSize), 8) - ((UINT8 *)OldFfs + NewFileSize);
+  if (FfsSize >= NewFileSize && FfsSize - NewFileSize <= 7) {
+    memcpy(OldFfs, (UINT8 *)InputFfs, NewFileSize);
+    if (Fv->Attributes & EFI_FVB2_ERASE_POLARITY) {
+      memset((UINT8 *)OldFfs + NewFileSize, -1, FfsSize - NewFileSize);
+    }
+    else {
+      memset((UINT8 *)OldFfs + NewFileSize, 0, FfsSize - NewFileSize);
+    }
+  }
+  else if (FfsSize >= NewFileSize + sizeof(EFI_FFS_FILE_HEADER) + Offset) {
+    memcpy(OldFfs, (UINT8 *)InputFfs, NewFileSize);
+    AddPadFile(
+      Fv,
+      (EFI_FFS_FILE_HEADER2 *)((UINT8 *)OldFfs + NewFileSize + Offset),
+      FfsSize - NewFileSize - Offset
+      );
+  }
+  else {
+    return FALSE;
+  }
+  if (Fv->Attributes & EFI_FVB2_ERASE_POLARITY) {
+    OldFfs->State = (UINT8)~(InputFfs->State);
+  }
+  if (PadSize != 0) {
+    AddPadFile(Fv, Pad, PadSize);
+  }
+  return TRUE;
+}
+
+static
+
+EFI_STATUS
+AddFfs(UINT8 *FdBuffer, UINT32 ImageAddress, EFI_FIRMWARE_VOLUME_HEADER* Fv, EFI_FFS_FILE_HEADER2 *InputFfs, UINT32 *OffsetAdded) {
+  UINTN FreeOffset;
+  UINTN Offset;
+  UINTN FfsSize;
+  EFI_STATUS Status;
+  EFI_FFS_FILE_HEADER2 *CurrentFile;
+  EFI_FFS_FILE_HEADER FreeHeader;
+
+  if (Fv->Attributes & EFI_FVB2_ERASE_POLARITY) {
+    memset(&FreeHeader, -1, sizeof(EFI_FFS_FILE_HEADER));
+  }
+  else {
+    memset(&FreeHeader, 0, sizeof(EFI_FFS_FILE_HEADER));
+  }
+
+  FfsSize = GetFfsFileLength((EFI_FFS_FILE_HEADER *)InputFfs);
+
+  Offset = 0;
+  CurrentFile = NULL;
+  FreeOffset = 0;
+  do {
+    if (FreeOffset == 0 && memcmp(FdBuffer + ImageAddress + (UINTN)ALIGN_POINTER(Offset, 8), &FreeHeader, sizeof(EFI_FFS_FILE_HEADER)) == 0) {
+      //
+      // Offset of free FV space found
+      //
+      FreeOffset = (UINTN)ALIGN_POINTER(Offset, 8);
+    }
+    Status = FvBufFindNextFile(FdBuffer + ImageAddress, &Offset, (VOID **)&CurrentFile);
+    if (Status == EFI_NOT_FOUND) {
+      CurrentFile = NULL;
+      break;
+    }
+    else if (EFI_ERROR(Status)) {
+      return Status;
+    }
+
+    if (CurrentFile != NULL && CurrentFile->Type == EFI_FV_FILETYPE_FFS_PAD &&
+      ReplaceFfs(Fv, InputFfs, CurrentFile)) {
+      *OffsetAdded = (UINT8 *)CurrentFile - (FdBuffer + ImageAddress);
+      return EFI_SUCCESS;
+    }
+  } while (CurrentFile != NULL);
+
+  if (FreeOffset != 0) {
+    if (Fv->FvLength - FreeOffset < FfsSize) {
+      return EFI_ABORTED;
+    }
+    if (Fv->Attributes & EFI_FVB2_ERASE_POLARITY) {
+      InputFfs->State = (UINT8)~(InputFfs->State);
+    }
+    memcpy(FdBuffer + ImageAddress + FreeOffset, InputFfs, FfsSize);
+    *OffsetAdded = FreeOffset;
+    return EFI_SUCCESS;
+  }
+
+  return EFI_NOT_FOUND;
+}
+
+static
+EFI_STATUS
+FindPreviousFile(VOID *Fv, VOID *CurrentFile, VOID **PreFile) {
+  EFI_STATUS Status;
+  VOID *File = NULL;
+  UINTN Offset = 0;
+
+  do {
+    *PreFile = File;
+    Status = FvBufFindNextFile(Fv, &Offset, &File);
+    if (Status == EFI_NOT_FOUND) {
+      CurrentFile = NULL;
+      break;
+    }
+    else if (EFI_ERROR(Status)) {
+      return Status;
+    }
+    if (File == CurrentFile) {
+      return EFI_SUCCESS;
+    }
+  } while (CurrentFile != NULL);
+  *PreFile = NULL;
+  return Status;
+}
+
+static
+BOOLEAN
+NeedNewPath(FV_INFORMATION *FvInFd, CHAR8 *FvId, UINT32 FileIndex, BOOLEAN IsAdd) {
+  UINT32 Index;
+
+  Index = 0;
+
+  if (strcmp(FvId, FvInFd->FvName) != 0) {
+    return FALSE;
+  }
+  if (IsAdd) {
+    return TRUE;
+  }
+  if (FvInFd->FfsAttuibutes[FileIndex].FvLevel != 1) {
+    return FALSE;
+  }
+
+  for (Index = 0; Index <= FvInFd->FfsNumbers; Index++) {
+    if (FvInFd->FfsAttuibutes[Index].FvLevel != 1) {
+      continue;
+    }
+    switch (FvInFd->FfsHeader[Index].Type) {
+    case EFI_FV_FILETYPE_PEI_CORE:
+    case EFI_FV_FILETYPE_PEIM:
+    case EFI_FV_FILETYPE_SECURITY_CORE:
+      return TRUE;
+    }
+  }
+  return FALSE;
+}
+
+static UINT32 FindFile(FV_INFORMATION *FvInFd, UINT8 FvLevel, CHAR8 *File, UINT32 *MatchIndex) {
+  UINT32 Index = 0;
+  CHAR16 *UIName;
+  CHAR16 *FfsUIName;
+  UINT32 FileNumber = 0;
+
+  UIName = (CHAR16 *)malloc(_MAX_PATH);
+  if (NULL == UIName) {
+    return 0;
+  }
+  FfsUIName = (CHAR16 *)malloc(_MAX_PATH);
+  if (NULL == FfsUIName) {
+    free(UIName);
+    return 0;
+  }
+  LibAscii2Unicode(File, UIName);
+  for (Index = 0; Index <= FvInFd->FfsNumbers; Index++) {
+    //
+    // Compare the New File Name with UI Name of FFS
+    // NOTE: The UI Name is Unicode, but the New File Name is Ascii.
+    //
+    memcpy(FfsUIName, (CHAR16 *)(FvInFd->FfsAttuibutes[Index].UiName), _MAX_PATH);
+
+    if (FvInFd->FfsAttuibutes[Index].UiNameSize > 0 && memcmp(UIName, FfsUIName, FvInFd->FfsAttuibutes[Index].UiNameSize) == 0) {
+      FileNumber += 1;
+      *MatchIndex = Index;
+      if (FileNumber > 1) {
+        break;
+      }
+    }
+
+  }
+  free(UIName);
+  free(FfsUIName);
+
+  return FileNumber;
+}
+
+/**
+  Search the config file from the path list.
+
+  Split the path from env PATH, and then search the cofig
+  file from these paths. The priority is from left to
+  right of PATH string. When met the first Config file, it
+  will break and return the pointer to the full file name.
+
+  @param  PathList         the pointer to the path list.
+  @param  FileName         the pointer to the file name.
+
+  @retval The pointer to the file name.
+  @return NULL       An error occurred.
+**/
+CHAR8 *
+SearchConfigFromPathList (
+  IN  CHAR8  *PathList,
+  IN  CHAR8  *FileName
+)
+{
+  CHAR8  *CurDir;
+  CHAR8  *FileNamePath;
+
+  CurDir       = NULL;
+  FileNamePath = NULL;
+
+#ifndef __GNUC__
+  CurDir = strtok (PathList,";");
+#else
+  CurDir = strtok (PathList,":");
+#endif
+  while (CurDir != NULL) {
+    FileNamePath  = (char *)calloc(
+                     strlen (CurDir) + strlen (OS_SEP_STR) +strlen (FileName) + 1,
+                     sizeof(char)
+                     );
+    if (FileNamePath == NULL) {
+      return NULL;
+    }
+    sprintf(FileNamePath, "%s%c%s", CurDir, OS_SEP, FileName);
+    if (access (FileNamePath, 0) != -1) {
+      return FileNamePath;
+    }
+#ifndef __GNUC__
+    CurDir = strtok(NULL, ";");
+#else
+    CurDir = strtok(NULL, ":");
+#endif
+    free (FileNamePath);
+    FileNamePath = NULL;
+  }
+  return NULL;
+}
+
+UINT32 lenList(FILENode* head){
+    FILENode *p = head;
+    UINT32 sum=0;
+    if(head==NULL) return 0;
+    while(p!=NULL){
+        sum+=1;
+        p=p->Next;
+    }
+    return sum;
+}
+
+void sortList(FILENode* head){
+    UINT32 len = lenList(head);
+    FILENode *p = head;
+    UINT32 i;
+    UINT32 j;
+    if(len==0) return;
+    for(i=1; i<len; ++i){
+        p = head;
+        for(j=0; j<len-i; j++){
+            if(p->SubLevel < p->Next->SubLevel){
+                CHAR8 *FileName = p->FileName;
+                UINT8 tmp = p->SubLevel;
+                p->SubLevel = p->Next->SubLevel;
+                p->Next->SubLevel = tmp;
+                p->FileName = p->Next->FileName;
+                p->Next->FileName = FileName;
+            }
+            p=p->Next;
+        }
+    }
+}
+
+BOOLEAN
+ParseSection (
+  IN  EFI_FFS_FILE_HEADER2  *InputFfs
+)
+{
+  BOOLEAN             UISectionFlag;
+  UINT32              SectionLength;
+  UINT32              ParsedLength;
+  UINT32              FfsFileSize;
+  UINT8               *Ptr;
+  EFI_SECTION_TYPE    Type;
+
+  UISectionFlag       = FALSE;
+  Ptr                 = NULL;
+  SectionLength       = 0;
+  ParsedLength        = GetFfsHeaderLength((EFI_FFS_FILE_HEADER *)InputFfs);
+  FfsFileSize         = GetFfsFileLength((EFI_FFS_FILE_HEADER *)InputFfs);
+
+  while (ParsedLength < FfsFileSize) {
+    Ptr           = (UINT8 *)InputFfs + ParsedLength;
+    SectionLength = GetLength (((EFI_COMMON_SECTION_HEADER *) Ptr)->Size);
+    Type          = ((EFI_COMMON_SECTION_HEADER *) Ptr)->Type;
+
+    //
+    // This is sort of an odd check, but is necessary because FFS files are
+    // padded to a QWORD boundary, meaning there is potentially a whole section
+    // header worth of 0xFF bytes.
+    //
+    if ((SectionLength == 0xffffff) && (Type == 0xff)) {
+      ParsedLength += 4;
+      continue;
+    }
+    if (Type == EFI_SECTION_USER_INTERFACE) {
+      UISectionFlag = TRUE;
+      break;
+    }
+    ParsedLength += SectionLength;
+    //
+    // We make then next section begin on a 4-byte boundary
+    //
+    ParsedLength = GetOccupiedSize (ParsedLength, 4);
+  }
+  return UISectionFlag;
+
+}
+
+
+/**
+
+  Show the FD image layout information. Only display the modules with UI name.
+
+  @param[in]   FdInName    Input FD binary/image file name;
+  @param[in]   FvName      The FV ID in the FD file;
+  @param[in]   ViewFlag    Is this call for view or other operate(add/del/replace)
+  @param[in]   FdData      The Fd data structure store the FD information.
+
+  @retval      EFI_SUCCESS
+  @retval      EFI_INVALID_PARAMETER
+  @retval      EFI_ABORTED
+
+**/
+EFI_STATUS
+FmmtImageView (
+  IN     CHAR8*           FdInName,
+  IN     CHAR8*           FvName,
+  IN     BOOLEAN          ViewFlag,
+  IN     FIRMWARE_DEVICE  **FdData
+)
+{
+  EFI_STATUS                  Status;
+  EFI_STATUS                  ErrorStatus;
+  FIRMWARE_DEVICE             *LocalFdData;
+  FV_INFORMATION              *CurrentFv;
+  FILE                        *InputFile;
+  UINT32                      FvSize;
+  UINTN                       BytesRead;
+  EFI_FIRMWARE_VOLUME_HEADER  *FvImage;
+  UINT32                      FfsCount;
+  UINT8                       FvCount;
+  CHAR8                       *TemDir;
+
+  LocalFdData    = NULL;
+  CurrentFv      = NULL;
+  FvImage        = NULL;
+  TemDir         = NULL;
+  FvSize         = 0;
+  BytesRead      = 0;
+  FfsCount       = 0;
+  FvCount        = 0;
+  ErrorStatus    = EFI_SUCCESS;
+
+  //
+  // Check the FD file name/path.
+  //
+  if (FdInName == NULL) {
+    Error("FMMT", 0, 1001, "Invalid parameter! Please specify <input-binary-file>", FdInName);
+    Usage();
+    return EFI_INVALID_PARAMETER;
+  }
+
+  //
+  // Open the file containing the FV
+  //
+  InputFile = fopen (FdInName, "rb");
+  if (InputFile == NULL) {
+    Error (NULL, 0, 0001, "Error opening the input file", FdInName);
+    return EFI_INVALID_PARAMETER;
+  }
+
+  Status = LibFindFvInFd (InputFile, &LocalFdData);
+
+  if (EFI_ERROR(Status)) {
+    Error("FMMT", 0, 1001, "Error while search FV in FD", "");
+    fclose (InputFile);
+    return EFI_ABORTED;
+  }
+
+  CurrentFv = LocalFdData->Fv;
+
+
+  do {
+
+    memset (CurrentFv->FvName, '\0', _MAX_PATH);
+
+    if (FvCount == 0) {
+      sprintf (CurrentFv->FvName, "FV%d", FvCount);
+    } else {
+      sprintf (CurrentFv->FvName, "FV%d", FvCount);
+    }
+
+    //
+    // Determine size of FV
+    //
+    if (fseek (InputFile, CurrentFv->ImageAddress, SEEK_SET) != 0) {
+      Error (NULL, 0, 0003, "error parsing FV image", "%s FD file is invalid", InputFile);
+      fclose (InputFile);
+      ErrorStatus = EFI_ABORTED;
+      goto Done;
+    }
+
+    Status = LibGetFvSize(InputFile, &FvSize);
+    if (EFI_ERROR (Status)) {
+      Error (NULL, 0, 0003, "error parsing FV image", "%s Header is invalid", InputFile);
+      fclose (InputFile);
+      ErrorStatus = EFI_ABORTED;
+      goto Done;
+    }
+
+    //
+    // Seek to the start of the image, then read the entire FV to the buffer
+    //
+    fseek (InputFile, CurrentFv->ImageAddress, SEEK_SET);
+
+
+    FvImage = (EFI_FIRMWARE_VOLUME_HEADER *) malloc (FvSize);
+
+    if (FvImage == NULL) {
+      Error (NULL, 0, 4001, "Resource: Memory can't be allocated", NULL);
+      fclose (InputFile);
+      ErrorStatus = EFI_ABORTED;
+      goto Done;
+    }
+
+    BytesRead = fread (FvImage, 1, FvSize, InputFile);
+    if ((unsigned int) BytesRead != FvSize) {
+      Error ("FMMT", 0, 0004, "error reading FvImage from", FdInName);
+      free (FvImage);
+      fclose (InputFile);
+      ErrorStatus = EFI_ABORTED;
+      goto Done;
+    }
+
+    //
+    // Collect FV information each by each.
+    //
+    Status = LibGetFvInfo (FvImage, CurrentFv, FvName, 0, &CurrentFv->EncapData, &FfsCount, &FvCount, ViewFlag, FALSE);
+    if (FvImage != NULL) {
+      free (FvImage);
+      FvImage = NULL;
+    }
+    if (EFI_ERROR (Status)) {
+      Error ("FMMT", 0, 0004, "error while get information from FV %s", FvName);
+      ErrorStatus = Status;
+      //
+      // If the FV to be parsed error is the same with the input FV in add, replace and delete
+      // operation, abort the program directly.
+      //
+      if ((FvName != NULL) && ((CurrentFv->FvName) != NULL) && !strcmp(CurrentFv->FvName, FvName)) {
+        fclose (InputFile);
+        ErrorStatus = EFI_ABORTED;
+        goto Done;
+      }
+    }
+
+
+    FfsCount = 0;
+
+    CurrentFv = CurrentFv->FvNext;
+
+  } while (CurrentFv != NULL);
+
+  fclose (InputFile);
+
+  if (ViewFlag) {
+
+    TemDir = getcwd (NULL, _MAX_PATH);
+    if (strlen (TemDir) + strlen(OS_SEP_STR) + strlen (TEMP_DIR_NAME) > _MAX_PATH - 1) {
+      Error("FMMT", 0, 1001, "The directory is too long.", "");
+      ErrorStatus = EFI_ABORTED;
+      goto Done;
+    }
+    strncat (TemDir, OS_SEP_STR, _MAX_PATH - strlen(TemDir) - 1);
+    strncat (TemDir, TEMP_DIR_NAME, _MAX_PATH - strlen(TemDir) - 1);
+
+    mkdir(TemDir, S_IRWXU | S_IRWXG | S_IRWXO);
+
+    Status = LibRmDir (TemDir);
+
+    if (EFI_ERROR (Status)) {
+      Error ("FMMT", 0, 0004, "error while encapsulate FD Image", "remove directory failed!");
+      ErrorStatus = Status;
+    }
+  }
+Done:
+  if (!ViewFlag) {
+    *FdData = LocalFdData;
+  } else {
+    LibFmmtFreeFd( LocalFdData);
+  }
+  return ErrorStatus;
+}
+
+/**
+  Add FFS file into a specify FV.
+
+  @param[in]   FdInName     Input FD binary/image file name;
+  @param[in]   FileList     The FV ID and FFS file Data;
+  @param[in]   count        The length of FileList;
+  @param[in]   FdOutName    Name of output FD binary/image file.
+
+  @retval      EFI_SUCCESS
+  @retval      EFI_INVALID_PARAMETER
+  @retval      EFI_ABORTED
+
+**/
+EFI_STATUS
+FmmtImageAdd(
+  IN     CHAR8*    FdInName,
+  IN     Data      *FileList,
+  IN     int       count,
+  IN     CHAR8*    FdOutName
+)
+{
+  EFI_STATUS                  Status;
+  FIRMWARE_DEVICE             *FdData;
+  FV_INFORMATION              *FvInFd;
+  FILE*                       NewFdFile;
+  FILE*                       NewFvFile;
+  UINT64                      NewFvLength;
+  VOID*                       Buffer;
+  CHAR8                       *TemDir;
+  UINT8                       FvNumInFd;
+  UINT8                       FvNumInFdCounter;
+  UINT8                       NewAddedFfsLevel;
+  FFS_INFORMATION             *OutputFileName;
+  UINT32                      Index;
+  UINT32                      EndId;
+  UINT8                       *FdBuffer;
+  EFI_FIRMWARE_VOLUME_HEADER  *Fv;
+  UINT32                      FdSize;
+  EFI_FFS_FILE_HEADER2        *InputFfs;
+  UINT32                      NewFileSize;
+  UINT64                      BaseAddr;
+  UINT32                      OffsetAdded;
+  int                         i;
+  int                         j;
+  Data                        *tmp;
+  CHAR8*                      FvId;
+  CHAR8*                      NewFile;
+  FILENode                    *NewFileNode;
+  BOOLEAN                     HasUISection;
+  HasUISection                = FALSE;
+  Index                       = 0;
+  EndId                       = 0;
+  NewFvLength                 = 0;
+  FvNumInFd                   = 0;
+  FvNumInFdCounter            = 0;
+  NewAddedFfsLevel            = 0;
+  FdData                      = NULL;
+  FvInFd                      = NULL;
+  NewFdFile                   = NULL;
+  NewFvFile                   = NULL;
+  Buffer                      = NULL;
+  TemDir                      = NULL;
+  OutputFileName              = NULL;
+  FvId                        = NULL;
+  NewFile                     = NULL;
+
+  FdBuffer                    = NULL;
+  InputFfs                    = NULL;
+  BaseAddr                    = 0;
+  OffsetAdded                 = 0;
+  FdSize                      = 0;
+
+    for (i = 0; i < count; i ++){
+        tmp = FileList + i;
+        FvId = tmp->FvId;
+        FdData = tmp->FdData;
+        if (FdData == NULL) {
+            Status = FmmtImageView (FdInName, FvId, FALSE, &FdData);
+            if (EFI_ERROR (Status) && Status != EFI_UNSUPPORTED) {
+                Error ("FMMT", 0, 0004, "error while parsing FD Image", "Gathering FD information failed!");
+                return Status;
+            }
+            if (FdData == NULL) {
+                Error ("FMMT", 0, 0004, "error while parsing FD Image", "");
+                return EFI_ABORTED;
+            }
+
+            Status = LibLocateFvViaFvId (FdData, FvId, &FvInFd);
+            if (EFI_ERROR (Status)) {
+                Error ("FMMT", 0, 0005, "error while locate FV in FD", "");
+                return Status;
+            }
+            (FileList + i) -> FdData = FdData;
+            (FileList + i) -> FvInFd = FvInFd;
+            (FileList + i) -> FvLevel = FvInFd -> FvLevel;
+        }
+    }
+
+  for (i = 0; i < count; i++) {
+      for (j = i + 1; j < count; j++){
+        if (((FileList + i)->FvId == NULL) || ((FileList + j)->FvId == NULL)) {
+          continue;
+        }
+        if (strcmp((FileList + j)->FvId, (FileList + i)->FvInFd->FvName) == 0){
+          NewFileNode = (FileList + j)->NewFile;
+          while (NewFileNode ->Next != NULL) {
+            NewFileNode = NewFileNode->Next;
+          }
+          NewFileNode->Next = (FileList + i)->NewFile;
+          (FileList + i)->FvId = NULL;
+            }
+    }
+    }
+
+    for (i = 0; i < count; i ++){
+        if ((FileList + i)->FvId == NULL) {
+            continue;
+        }
+        sortList ((FileList + i)-> NewFile);
+    }
+
+    TemDir = getcwd(NULL, _MAX_PATH);
+    if (strlen (TemDir) + strlen(OS_SEP_STR) + strlen (TEMP_DIR_NAME) > _MAX_PATH - 1) {
+      Error("FMMT", 0, 1001, "The directory is too long.", "");
+      return EFI_ABORTED;
+    }
+    strncat (TemDir, OS_SEP_STR, _MAX_PATH - strlen(TemDir) - 1);
+    strncat (TemDir, TEMP_DIR_NAME, _MAX_PATH - strlen(TemDir) - 1);
+
+    if (FdBuffer == NULL) {
+        FdBuffer = ReadFileToBuffer(FdInName, &FdSize);
+        if (FdBuffer == NULL) {
+            Error("FMMT", 0, 0004, "error while adding file", "cannot read input file.");
+            return EFI_ABORTED;
+        }
+    }
+
+    for (i = 0; i < count; i ++){
+        tmp = FileList + i;
+        FvId = tmp->FvId;
+    if (FvId == NULL) {
+            continue;
+        }
+        FdData = tmp->FdData;
+        FvInFd = tmp->FvInFd;
+        NewFileNode =tmp->NewFile;
+
+        NewFile = NewFileNode->FileName;
+        InputFfs = (EFI_FFS_FILE_HEADER2 *)ReadFileToBuffer(NewFile, &NewFileSize);
+        if (InputFfs == NULL) {
+            Error("FMMT", 0, 0004, "error while adding file", "cannot read input file.");
+            Status = EFI_ABORTED;
+            goto FAILED;
+        }
+        HasUISection = FALSE;
+        HasUISection = ParseSection(InputFfs);
+        if (!HasUISection) {
+            printf ("WARNING: The newly add file must have a user interface (UI) section, otherwise it cannot be deleted or replaced. \n");
+        }
+        if (NeedNewPath(FvInFd, FvId, 0, TRUE)) {
+            do {
+                NewFile = NewFileNode->FileName;
+                //
+                // TODO: currently only root FV is handled
+                //
+                InputFfs = (EFI_FFS_FILE_HEADER2 *)ReadFileToBuffer(NewFile, &NewFileSize);
+                if (InputFfs == NULL) {
+                    Error("FMMT", 0, 0004, "error while adding file", "cannot read input file.");
+                    Status =  EFI_ABORTED;
+                    goto FAILED;
+                }
+
+                Fv = (EFI_FIRMWARE_VOLUME_HEADER *)(FdBuffer + FvInFd->ImageAddress);
+
+                Status = AddFfs(FdBuffer, FvInFd->ImageAddress, Fv, InputFfs, &OffsetAdded);
+                if (EFI_ERROR(Status)) {
+                    Error("FMMT", 0, 0003, "error while adding file", "Not enough space to add FFS");
+                    goto FAILED;
+                }
+                //
+                // Calculate base address of Current FV
+                //
+                if (InputFfs->Type == EFI_FV_FILETYPE_PEIM || InputFfs->Type == EFI_FV_FILETYPE_FIRMWARE_VOLUME_IMAGE) {
+                    Status = GetBaseAddrFromFsp(FdData, FdBuffer, FvId, &BaseAddr);
+                    if (!EFI_ERROR(Status)) {
+                        mFvHeader = FvInFd->FvHeader;
+                        mFvLength = (UINT32)FvInFd->FvHeader->FvLength;
+                        RebaseFfs(BaseAddr, NewFile, (EFI_FFS_FILE_HEADER *)(FdBuffer + FvInFd->ImageAddress + OffsetAdded), OffsetAdded);
+                    }
+                    else {
+                        Status = GetBaseAddrFromVtf(FdData, FvId, &BaseAddr);
+                        if (!EFI_ERROR(Status)) {
+                            mFvHeader = FvInFd->FvHeader;
+                            mFvLength = (UINT32)FvInFd->FvHeader->FvLength;
+                            RebaseFfs(BaseAddr, NewFile, (EFI_FFS_FILE_HEADER *)(FdBuffer + FvInFd->ImageAddress + OffsetAdded), OffsetAdded);
+                        }
+                    }
+                }
+                NewFileNode = NewFileNode->Next;
+                free (InputFfs);
+                InputFfs = NULL;
+            } while (NewFileNode != NULL);
+        } else {
+            do {
+                NewFile = NewFileNode->FileName;
+                if (strlen (NewFile) > _MAX_PATH - 1) {
+                  Error ("FMMT", 0, 2000, "error while adding file", "New file name is too long!");
+                  Status = EFI_ABORTED;
+                  goto FAILED;
+                }
+                FvNumInFd = ((UINT8)atoi(FvId + 2) - (UINT8)atoi(FvInFd->FvName + 2));
+                if (FvInFd->FfsNumbers == 0) {
+                    NewAddedFfsLevel = FvInFd->FfsAttuibutes[0].Level;
+                }
+                for (Index = 0; Index <= FvInFd->FfsNumbers; Index++) {
+                    if (FvInFd->FfsAttuibutes[Index].IsFvStart == 1) {
+                        FvNumInFdCounter++;
+                    }
+                    if ( FvNumInFdCounter == FvNumInFd && FvInFd->FfsAttuibutes[Index].IsFvEnd == 1) {
+                        NewAddedFfsLevel = FvInFd->FfsAttuibutes[Index].Level;
+                        EndId = Index+1;
+                        break;
+                    }
+                    if (FvInFd->FfsAttuibutes[Index].IsFvEnd == 1) {
+                        FvNumInFdCounter--;
+                        if (FvNumInFdCounter == 0) {
+                            FvNumInFd--;
+                        }
+                    }
+                }
+
+                //
+                // Add the new file into FV.
+                //
+                FvInFd->FfsNumbers += 1;
+                for (Index = FvInFd->FfsNumbers; Index > EndId; Index--) {
+                    FvInFd->FfsAttuibutes[Index] = FvInFd->FfsAttuibutes[Index - 1];
+                }
+                strncpy(FvInFd->FfsAttuibutes[EndId].FfsName, NewFile, _MAX_PATH - 1);
+                FvInFd->FfsAttuibutes[EndId].FfsName[_MAX_PATH - 1] = 0;
+                FvInFd->FfsAttuibutes[EndId].Level = NewAddedFfsLevel;
+                memset (&FvInFd->FfsAttuibutes[EndId].GuidName, '\0', sizeof(EFI_GUID));
+                if (EndId > 0) {
+                    FvInFd->FfsAttuibutes[EndId].FvLevel = FvInFd->FfsAttuibutes[EndId - 1].FvLevel;
+                    FvInFd->FfsAttuibutes[EndId - 1].IsFvEnd = 0;
+                }
+                FvInFd->FfsAttuibutes[EndId].IsFvEnd = 1;
+                FvInFd->FfsAttuibutes[EndId].IsFvStart = 0;
+                NewFileNode = NewFileNode->Next;
+            } while (NewFileNode != NULL);
+
+            mkdir(TemDir, S_IRWXU | S_IRWXG | S_IRWXO);
+
+            Status = LibEncapNewFvFile (FvInFd, TemDir, NULL, 0, &OutputFileName);
+            if (EFI_ERROR (Status)) {
+                Error ("FMMT", 0, 0004, "error while encapsulate FD Image", "Make new FV file failed!");
+                goto FAILED;
+            }
+
+            NewFvFile = fopen (OutputFileName->FFSName, "rb+");
+            if (NewFvFile == NULL) {
+                Error ("FMMT", 0, 0003, "error Open FV file", "cannot Create a new FD file.");
+                Status =  EFI_ABORTED;
+                goto FAILED;
+            }
+
+            fseek(NewFvFile,0,SEEK_SET);
+            fseek(NewFvFile,0,SEEK_END);
+
+            NewFvLength = ftell(NewFvFile);
+            fseek(NewFvFile,0,SEEK_SET);
+            Buffer = malloc ((size_t)NewFvLength);
+            if (Buffer == NULL)  {
+                Status =  EFI_ABORTED;
+                fclose(NewFvFile);
+                goto FAILED;
+            }
+
+            if (fread (Buffer, 1, (size_t) NewFvLength, NewFvFile) != (size_t) NewFvLength) {
+                Error ("FMMT", 0, 0003, "error reading FV file %s", OutputFileName->FFSName);
+                free (Buffer);
+                Status =  EFI_ABORTED;
+                fclose(NewFvFile);
+                goto FAILED;
+            }
+
+            if (NewFvLength <= FvInFd->FvHeader->FvLength) {
+                memcpy(FdBuffer+FvInFd->ImageAddress,Buffer,(size_t) NewFvLength);
+            } else {
+                Error ("FMMT", 0, 0004, "error writing FD file", "The add ffs file is too large.");
+            }
+            fclose(NewFvFile);
+            free(Buffer);
+        }
+    }
+
+    Status = LibRmDir(TemDir);
+    if (EFI_ERROR(Status)) {
+        Error("FMMT", 0, 0004, "error while encapsulate FD Image", "remove directory failed!");
+        goto FAILED;
+    }
+
+    NewFdFile = fopen(FdOutName, "wb");
+    if (NewFdFile == NULL) {
+        Error("FMMT", 0, 0004, "error while encapsulate FD Image", "Cannot open target FD file!");
+        Status = EFI_ABORTED;
+        goto FAILED;
+    }
+
+    fwrite(FdBuffer, 1, FdSize, NewFdFile);
+    fclose(NewFdFile);
+    free(FdBuffer);
+    free(InputFfs);
+    printf ("Create New FD file successfully. \n\nDone! \n");
+    return EFI_SUCCESS;
+
+  FAILED:
+    if (FdBuffer != NULL) {
+      free(FdBuffer);
+    }
+    if (InputFfs != NULL) {
+      free(InputFfs);
+    }
+    return Status;
+}
+
+/**
+Delete a root FV from FD.
+
+ at param[in]   FdInName     Input FD binary/image file name;
+ at param[in]   FvName       FV name;
+ at param[in]   FdOutName    Name of output fd file.
+
+ at retval      EFI_SUCCESS
+ at retval      EFI_INVALID_PARAMETER
+ at retval      EFI_ABORTED
+
+**/
+EFI_STATUS
+FmmtImageDeleteFv(
+  IN     CHAR8*  FdInName,
+  IN     CHAR8*  FvName,
+  IN     CHAR8*  FdOutName
+)
+{
+  EFI_STATUS Status;
+  FV_INFORMATION *FvInFd;
+  FILE *NewFdFile;
+  CHAR8 *TemDir;
+
+  UINT8 *FdBuffer = NULL;
+  UINT8 *FdBak = NULL;
+  UINT32 FdSize = 0;
+
+  FIRMWARE_DEVICE *FdData = NULL;
+
+  TemDir = getcwd(NULL, _MAX_PATH);
+  if (strlen (TemDir) + strlen(OS_SEP_STR) + strlen (TEMP_DIR_NAME) > _MAX_PATH - 1) {
+    Error("FMMT", 0, 1001,  "The directory is too long.", "");
+    return EFI_ABORTED;
+  }
+  strncat (TemDir, OS_SEP_STR, _MAX_PATH - strlen(TemDir) - 1);
+  strncat (TemDir, TEMP_DIR_NAME, _MAX_PATH - strlen(TemDir) - 1);
+
+  Status = FmmtImageView(FdInName, NULL, FALSE, &FdData);
+  if (EFI_ERROR(Status) && Status != EFI_UNSUPPORTED) {
+    Error("FMMT", 0, 0004, "error while parsing FD Image", "Gathering FD information failed!");
+    goto END;
+  }
+  if (FdData == NULL) {
+    Error("FMMT", 0, 0004, "error while parsing FD Image", "");
+    Status = EFI_ABORTED;
+    goto END;
+  }
+
+  FvInFd = FdData->Fv;
+  while (FvInFd) {
+    if (FvInFd->FvUiName && strcmp(FvInFd->FvUiName, FvName) == 0) {
+      break;
+    }
+    FvInFd = FvInFd->FvNext;
+  }
+  if (!FvInFd) {
+    Error("FMMT", 0, 0004, "error while deleting root FV", "Cannot find this FV!");
+    Status = EFI_ABORTED;
+    goto END;
+  }
+  FdBuffer = ReadFileToBuffer(FdInName, &FdSize);
+  FdBak = FdBuffer;
+  if (FdBuffer == NULL) {
+    Error("FMMT", 0, 0004, "error while deleting root FV", "Cannot read FD file!");
+    Status = EFI_ABORTED;
+    goto END;
+  }
+
+  if (FvInFd->ImageAddress == 0) {
+    FdBuffer = FdBuffer + FvInFd->FvHeader->FvLength;
+    FdSize -= (UINT32)FvInFd->FvHeader->FvLength;
+  } else {
+    if (FvInFd->FvHeader->Attributes & EFI_FVB2_ERASE_POLARITY) {
+      memset(FdBuffer + FvInFd->ImageAddress, -1, (size_t)FvInFd->FvHeader->FvLength);
+    }
+    else {
+      memset(FdBuffer + FvInFd->ImageAddress, 0, (size_t)FvInFd->FvHeader->FvLength);
+    }
+  }
+
+  NewFdFile = fopen(FdOutName, "wb");
+  if (NewFdFile == NULL) {
+    Error("FMMT", 0, 0004, "error while deleting root FV", "Cannot open target FD file!");
+    Status = EFI_ABORTED;
+    goto END;
+  }
+  fwrite(FdBuffer, 1, FdSize, NewFdFile);
+  fclose(NewFdFile);
+
+  Status = LibRmDir(TemDir);
+
+  if (EFI_ERROR(Status)) {
+    Error("FMMT", 0, 0004, "error while deleting root FV", "remove directory failed!");
+    goto END;
+  }
+
+  printf("Create New FD file successfully. \n\nDone! \n");
+END:
+  LibFmmtFreeFd(FdData);
+  free(FdBak);
+  return Status;
+}
+
+/**
+  Delete an FFS file from a specify FV.
+
+  @param[in]   FdInName     Input FD binary/image file name;
+  @param[in]   FileList     The FV ID and FFS file Data;
+  @param[in]   count        The length of FileList;
+  @param[in]   FdOutName    Name of output fd file.
+
+  @retval      EFI_SUCCESS
+  @retval      EFI_INVALID_PARAMETER
+  @retval      EFI_ABORTED
+
+**/
+EFI_STATUS
+FmmtImageDelete (
+  IN     CHAR8*    FdInName,
+  IN     Data      *FileList,
+  IN     int       count,
+  IN     CHAR8*    FdOutName
+)
+{
+  EFI_STATUS                  Status;
+  FIRMWARE_DEVICE             *FdData;
+  FV_INFORMATION              *FvInFd;
+  UINT32                      Index;
+  UINT32                      FfsFoundFlag;
+  FFS_INFORMATION             *OutputFileName;
+  FILE*                       NewFdFile;
+  FILE*                       NewFvFile;
+  UINT64                      NewFvLength;
+  VOID*                       Buffer;
+  CHAR8                       *TemDir;
+  UINT8                       FvNumInFd;
+  UINT32                      Offset;
+  UINT8                       *FdBuffer;
+  EFI_FFS_FILE_HEADER2        *CurrentFile;
+  EFI_FFS_FILE_HEADER2        *PreFile;
+  Data                        *tmp;
+  CHAR8*                      FvId;
+  CHAR8*                      DelFile;
+  FILENode                    *OldFileNode;
+  int                         i;
+  UINT32                      FfsSize;
+  UINT32                      FdSize;
+  int                         j;
+
+  FdSize                      = 0;
+  Index                       = 0;
+  NewFvLength                 = 0;
+  FfsFoundFlag                = 0;
+  FdData                      = NULL;
+  FvInFd                      = NULL;
+  OutputFileName              = NULL;
+  NewFdFile                   = NULL;
+  NewFvFile                   = NULL;
+  Buffer                      = NULL;
+  TemDir                      = NULL;
+  FvNumInFd                   = 0;
+  Offset                      = 0;
+  FdBuffer                    = NULL;
+
+    for (i = 0; i < count; i ++){
+        tmp = FileList + i;
+        FvId = tmp->FvId;
+        FdData = tmp->FdData;
+        if (FdData == NULL) {
+            Status = FmmtImageView (FdInName, FvId, FALSE, &FdData);
+            if (EFI_ERROR (Status) && Status != EFI_UNSUPPORTED) {
+                Error ("FMMT", 0, 0004, "error while parsing FD Image", "Gathering FD information failed!");
+                return Status;
+            }
+            if (FdData == NULL) {
+                Error ("FMMT", 0, 0004, "error while parsing FD Image", "");
+                return EFI_ABORTED;
+            }
+
+            Status = LibLocateFvViaFvId (FdData, FvId, &FvInFd);
+            if (EFI_ERROR (Status)) {
+                Error ("FMMT", 0, 0005, "error while locate FV in FD", "");
+                return Status;
+            }
+            (FileList + i) -> FdData = FdData;
+            (FileList + i) -> FvInFd = FvInFd;
+            (FileList + i) -> FvLevel = FvInFd -> FvLevel;
+        }
+        FvNumInFd = ((UINT8)atoi(FvId + 2) - (UINT8)atoi(FvInFd->FvName + 2)) + 1;
+        OldFileNode = tmp-> OldFile;
+        do {
+            DelFile = OldFileNode->FileName;
+            if (FvInFd == NULL) {
+              break;
+            }
+            FfsFoundFlag = FindFile(FvInFd, FvNumInFd, DelFile, &Index);
+            if (FfsFoundFlag) {
+                if (FfsFoundFlag > 1) {
+                    printf("Duplicated file found in this FV, file name: %s\n", DelFile);
+                    return EFI_ABORTED;
+                }
+            } else {
+                printf ("Could not found the FFS file from FD!, file name: %s\n", DelFile);
+                return EFI_ABORTED;
+            }
+            OldFileNode -> SubLevel = FvInFd -> FfsAttuibutes[Index].Level;
+            OldFileNode = OldFileNode->Next;
+        } while (OldFileNode != NULL);
+    }
+
+    for (i = 0; i < count; i++) {
+        for (j = i + 1; j < count; j++)
+        {
+            if (((FileList + i)->FvId == NULL) || ((FileList + j)->FvId == NULL)) {
+                continue;
+            }
+            if (strcmp((FileList + j)->FvId, (FileList + i)->FvInFd->FvName) == 0){
+                OldFileNode = (FileList + j)->OldFile;
+                while (OldFileNode ->Next != NULL) {
+                    OldFileNode = OldFileNode->Next;
+                }
+                OldFileNode->Next = (FileList + i)->OldFile;
+                (FileList + i)->FvId = NULL;
+            }
+            }
+    }
+
+    for (i = 0; i < count; i ++){
+        if ((FileList + i)->FvId == NULL) {
+            continue;
+        }
+        sortList ((FileList + i)-> OldFile);
+    }
+
+    TemDir = getcwd(NULL, _MAX_PATH);
+    if (strlen (TemDir) + strlen(OS_SEP_STR) + strlen (TEMP_DIR_NAME) > _MAX_PATH - 1) {
+      Error("FMMT", 0, 1001, "The directory is too long.", "");
+      return EFI_ABORTED;
+    }
+    strncat (TemDir, OS_SEP_STR, _MAX_PATH - strlen(TemDir) - 1);
+    strncat (TemDir, TEMP_DIR_NAME, _MAX_PATH - strlen(TemDir) - 1);
+
+    if (FdBuffer == NULL) {
+        FdBuffer = ReadFileToBuffer(FdInName, &FdSize);
+        if (FdBuffer == NULL) {
+            Error("FMMT", 0, 0004, "error while deleting file", "cannot read input file.");
+            return EFI_ABORTED;
+        }
+    }
+
+    for (i = 0; i < count; i ++){
+        tmp = FileList + i;
+        FvId = tmp->FvId;
+        if (FvId == NULL) {
+            continue;
+        }
+        FdData = tmp->FdData;
+        FvInFd = tmp->FvInFd;
+        FvNumInFd = ((UINT8)atoi(FvId + 2) - (UINT8)atoi(FvInFd->FvName + 2)) + 1;
+        OldFileNode = tmp->OldFile;
+        DelFile = OldFileNode -> FileName;
+        FfsFoundFlag = FindFile(FvInFd, FvNumInFd, DelFile, &Index);
+        if (FfsFoundFlag && NeedNewPath(FvInFd, FvId, Index, FALSE)) {
+            do {
+                DelFile = OldFileNode -> FileName;
+                FfsFoundFlag = FindFile(FvInFd, FvNumInFd, DelFile, &Index);
+                //
+                // TODO: currently only root FV is handled
+                //
+                Offset = FvInFd->ImageAddress + FvInFd->FfsAttuibutes[Index].Offset;
+                if (FdBuffer != NULL) {
+                  CurrentFile = (EFI_FFS_FILE_HEADER2 *)(FdBuffer + Offset);
+
+                  FfsSize = CalcuFfsSize((EFI_FIRMWARE_VOLUME_HEADER *)(FdBuffer + FvInFd->ImageAddress), CurrentFile);
+
+                  FindPreviousFile((EFI_FIRMWARE_VOLUME_HEADER *)(FdBuffer + FvInFd->ImageAddress), CurrentFile, (VOID **) &PreFile);
+                  if (PreFile != NULL && PreFile->Type == EFI_FV_FILETYPE_FFS_PAD) {
+                    FfsSize += (UINT8 *)CurrentFile - (UINT8 *)PreFile;
+                    CurrentFile = PreFile;
+                  }
+                  AddPadFile((EFI_FIRMWARE_VOLUME_HEADER *)(FdBuffer + FvInFd->ImageAddress), CurrentFile, FfsSize);
+                }
+                OldFileNode = OldFileNode -> Next;
+            } while (OldFileNode != NULL);
+        } else {
+            do {
+                DelFile = OldFileNode -> FileName;
+                FfsFoundFlag = FindFile(FvInFd, FvNumInFd, DelFile, &Index);
+
+                if (FfsFoundFlag) {
+                    //
+                    // Delete this FFS file from Current FV structure.
+                    //
+                    Status = LibFmmtDeleteFile (FvInFd->FfsAttuibutes[Index].FfsName);
+                    if (EFI_ERROR (Status)) {
+                        Error ("FMMT", 0, 0004, "error while encapsulate FD Image", "Delete the specified file failed!");
+                        Error ("FMMT", 0, 0004, "Cannot find the file need to delete", "Please check the name of the file you want to delete!");
+                        goto FAILED;
+                    }
+
+                    memset(FvInFd->FfsAttuibutes[Index].FfsName, '\0', _MAX_PATH);
+                    FvInFd->FfsAttuibutes[Index].Level   = 0xFF;
+
+                    //
+                    // Since we can avoid to add NULL ffs file, at this time we don't need to decrease the FFS number.
+                    // If decrease operation executed, we should adjust the ffs list. It will bring in more complex.
+                    //
+                    //FvInFd->FfsNumbers                    -= 1;
+                    memset(FvInFd->FfsAttuibutes[Index].UiName, '\0', _MAX_PATH);
+                   if (FvInFd->FfsAttuibutes[Index].FvLevel > 1) {
+                       for (j = Index - 1; j >= 0; j--) {
+                           if (FvInFd->FfsAttuibutes[j].FvLevel == FvInFd->FfsAttuibutes[Index].FvLevel - 1) {
+                               break;
+                           }
+                       }
+                      if (Index+1 <= FvInFd->FfsNumbers) {
+                          if (FvInFd->FfsAttuibutes[Index+1].FvLevel == FvInFd->FfsAttuibutes[Index].FvLevel + 1) {
+                             for (j = Index+1; j <= (signed)FvInFd->FfsNumbers; j++) {
+                                if (FvInFd->FfsAttuibutes[j].FvLevel > FvInFd->FfsAttuibutes[Index].FvLevel) {
+                                   Status = LibFmmtDeleteFile(FvInFd->FfsAttuibutes[j].FfsName);
+                                   if (EFI_ERROR(Status)) {
+                                       Error("FMMT", 0, 0004, "error while encapsulate FD Image", "Delete the specified file failed!");
+                                       return Status;
+                                   }
+                                   memset(FvInFd->FfsAttuibutes[j].FfsName, '\0', _MAX_PATH);
+                                   FvInFd->FfsAttuibutes[j].Level = 0xFF;
+                                }
+                             }
+                          }
+                      }
+                   }
+                } else {
+                    printf ("Could not found the FFS file from FD!, file name: %s\n", DelFile);
+                    Status =  EFI_ABORTED;
+                    goto FAILED;
+                }
+                OldFileNode = OldFileNode -> Next;
+
+            }while (OldFileNode != NULL);
+
+            mkdir(TemDir, S_IRWXU | S_IRWXG | S_IRWXO);
+
+            Status = LibEncapNewFvFile (FvInFd, TemDir, NULL, 0, &OutputFileName);
+            if (EFI_ERROR (Status)) {
+                Error ("FMMT", 0, 0004, "error while encapsulate FD Image", "Make new FV file failed!");
+                goto FAILED;
+            }
+
+            NewFvFile = fopen (OutputFileName->FFSName, "rb+");
+            if (NewFvFile == NULL) {
+                Error ("FMMT", 0, 0003, "error Open FV file", "cannot Create a new FD file.");
+                Status =  EFI_ABORTED;
+                goto FAILED;
+            }
+
+            fseek(NewFvFile,0,SEEK_SET);
+            fseek(NewFvFile,0,SEEK_END);
+
+            NewFvLength = ftell(NewFvFile);
+            fseek(NewFvFile,0,SEEK_SET);
+            Buffer = malloc ((size_t)NewFvLength);
+            if (Buffer == NULL)  {
+              fclose(NewFvFile);
+              Status =  EFI_ABORTED;
+              goto FAILED;
+            }
+
+            if (fread (Buffer, 1, (size_t) NewFvLength, NewFvFile) != (size_t) NewFvLength) {
+                Error ("FMMT", 0, 0003, "error reading FV file %s", OutputFileName->FFSName);
+                fclose(NewFvFile);
+                free(Buffer);
+                Status =  EFI_ABORTED;
+                goto FAILED;
+            }
+            memcpy(FdBuffer+FvInFd->ImageAddress,Buffer,(size_t) NewFvLength);
+            free(Buffer);
+            fclose(NewFvFile);
+        }
+    }
+
+    Status = LibRmDir(TemDir);
+    if (EFI_ERROR(Status)) {
+        Error("FMMT", 0, 0004, "error while encapsulate FD Image", "remove directory failed!");
+        goto FAILED;
+    }
+
+    NewFdFile = fopen(FdOutName, "wb");
+    if (NewFdFile == NULL) {
+      Error("FMMT", 0, 0004, "error while encapsulate FD Image", "Cannot open target FD file!");
+      Status = EFI_ABORTED;
+      goto FAILED;
+    }
+
+    fwrite(FdBuffer, 1, FdSize, NewFdFile);
+    fclose(NewFdFile);
+    free(FdBuffer);
+    printf("Create New FD file successfully. \n\nDone! \n");
+    return EFI_SUCCESS;
+
+  FAILED:
+    free(FdBuffer);
+    return Status;
+}
+
+/**
+  Replace the exist FFS file with new one from a specify FV.
+
+  @param[in]   FdInName     Input FD binary/image file name;
+  @param[in]   FileList     The FV ID and FFS file Data;
+  @param[in]   count        The length of FileList;
+  @param[in]   FdOutName    Name of output fd file.
+
+  @retval      EFI_SUCCESS
+  @retval      EFI_INVALID_PARAMETER
+  @retval      EFI_ABORTED
+
+**/
+EFI_STATUS
+FmmtImageReplace (
+  IN     CHAR8*    FdInName,
+  IN     Data      *FileList,
+  IN     int       count,
+  IN     CHAR8*    FdOutName
+)
+{
+  EFI_STATUS                  Status;
+  FIRMWARE_DEVICE             *FdData;
+  FV_INFORMATION              *FvInFd;
+  UINT32                      Index;
+  UINT32                      FfsFoundFlag;
+  FFS_INFORMATION             *OutputFileName;
+  FILE*                       NewFdFile;
+  FILE*                       NewFvFile;
+  UINT64                      NewFvLength;
+  VOID*                       Buffer;
+  CHAR8                       *TemDir;
+  UINT32                      Offset;
+  UINT8                       *FdBuffer;
+  UINT8                       FvNumInFd;
+  EFI_FFS_FILE_HEADER2        *CurrentFile;
+  EFI_FIRMWARE_VOLUME_HEADER  *Fv;
+  UINT32                      FdSize;
+  EFI_FFS_FILE_HEADER2        *InputFfs;
+  UINT32                      NewFileSize;
+  UINT32                      PadFileSize;
+  UINT64                      BaseAddr;
+  UINT32                      OffsetAdded;
+  Data                        *tmp;
+  CHAR8*                      FvId;
+  CHAR8*                      OldFile;
+  CHAR8*                      NewFile;
+  int                         i;
+  int                         j;
+  FILENode                    *OldFileNode;
+  FILENode                    *NewFileNode;
+  BOOLEAN                     HasUISection;
+  HasUISection                = FALSE;
+  Index                       = 0;
+  NewFvLength                 = 0;
+  FfsFoundFlag                = 0;
+  FdData                      = NULL;
+  FvInFd                      = NULL;
+  OutputFileName              = NULL;
+  NewFdFile                   = NULL;
+  NewFvFile                   = NULL;
+  Buffer                      = NULL;
+  TemDir                      = NULL;
+  Offset                      = 0;
+  FdBuffer                    = NULL;
+  InputFfs                    = NULL;
+  BaseAddr                    = 0;
+  OffsetAdded                 = 0;
+  FdSize                      = 0;
+
+    for (i = 0; i < count; i ++){
+        tmp = FileList + i;
+        FvId = tmp->FvId;
+        FdData = tmp->FdData;
+        if (FdData == NULL){
+            Status = FmmtImageView(FdInName, FvId, FALSE, &FdData);
+            if (EFI_ERROR(Status) && Status != EFI_UNSUPPORTED) {
+                Error("FMMT", 0, 0004, "error while parsing FD Image", "Gathering information failed!");
+                return Status;
+            }
+
+            if (FdData == NULL) {
+                Error("FMMT", 0, 0004, "error while parsing FD Image", "");
+                return EFI_ABORTED;
+            }
+
+            Status = LibLocateFvViaFvId(FdData, FvId, &FvInFd);
+            if (EFI_ERROR(Status)) {
+                Error("FMMT", 0, 0005, "error while locate FV in FD", "");
+                return Status;
+            }
+            (FileList + i) -> FdData = FdData;
+            (FileList + i) -> FvInFd = FvInFd;
+            (FileList + i) -> FvLevel = FvInFd -> FvLevel;
+        }
+        FvNumInFd = ((UINT8)atoi(FvId + 2) - (UINT8)atoi(FvInFd->FvName + 2)) + 1;
+        OldFileNode = tmp-> OldFile;
+        NewFileNode = tmp-> NewFile;
+        do {
+            OldFile = OldFileNode -> FileName;
+            NewFile = NewFileNode -> FileName;
+            if (FvInFd == NULL) {
+              break;
+            }
+            FfsFoundFlag = FindFile(FvInFd, FvNumInFd, OldFile, &Index);
+
+            if (FfsFoundFlag) {
+                if (FfsFoundFlag > 1) {
+                    printf("Duplicated file found in this FV, file name: %s\n", OldFile);
+                    return EFI_ABORTED;
+                }
+                //
+                // Replace this FFS file with the new one.
+                // strcpy (FvInFd->FfsAttuibutes[Index].FfsName, NewFile);
+            } else {
+                printf ("Could not found the FFS file need to be replaced from FD! file name: %s\n", OldFile);
+                return EFI_ABORTED;
+            }
+            OldFileNode -> SubLevel = FvInFd -> FfsAttuibutes[Index].Level;
+            NewFileNode -> SubLevel = FvInFd -> FfsAttuibutes[Index].Level;
+            OldFileNode = OldFileNode->Next;
+            NewFileNode = NewFileNode->Next;
+        } while (OldFileNode != NULL && NewFileNode != NULL);
+    }
+
+    for (i = 0; i < count; i++) {
+        for (j = i + 1; j < count; j++)
+        {
+            if (((FileList + i)->FvId == NULL) || ((FileList + j)->FvId == NULL)) {
+                continue;
+            }
+            if (strcmp((FileList + j)->FvId, (FileList + i)->FvInFd->FvName) == 0){
+                OldFileNode = (FileList + j)->OldFile;
+                NewFileNode = (FileList + j)->NewFile;
+                while (OldFileNode->Next != NULL && NewFileNode->Next != NULL) {
+                    OldFileNode = OldFileNode->Next;
+                    NewFileNode = NewFileNode->Next;
+                }
+                OldFileNode->Next = (FileList + i)->OldFile;
+                NewFileNode->Next = (FileList + i)->NewFile;
+                (FileList + i)->FvId = NULL;
+            }
+        }
+    }
+
+    for (i = 0; i < count; i ++){
+        if ((FileList + i)->FvId == NULL) {
+            continue;
+        }
+        sortList ((FileList + i)-> OldFile);
+        sortList ((FileList + i)-> NewFile);
+    }
+    TemDir = getcwd (NULL, _MAX_PATH);
+    if (strlen (TemDir) + strlen(OS_SEP_STR) + strlen (TEMP_DIR_NAME) > _MAX_PATH - 1) {
+      Error("FMMT", 0, 1001,  "The directory  is too long.", "");
+      return EFI_ABORTED;
+    }
+    strncat (TemDir, OS_SEP_STR, _MAX_PATH - strlen(TemDir) - 1);
+    strncat (TemDir, TEMP_DIR_NAME, _MAX_PATH - strlen(TemDir) - 1);
+    mkdir(TemDir, S_IRWXU | S_IRWXG | S_IRWXO);
+    if (FdBuffer == NULL) {
+        FdBuffer = ReadFileToBuffer(FdInName, &FdSize);
+        if (FdBuffer == NULL) {
+          Error("FMMT", 0, 0004, "error while replacing file", "cannot read input file.");
+          return EFI_ABORTED;
+        }
+    }
+
+    for (i = 0; i < count; i ++){
+        tmp = FileList + i;
+        FvId = tmp->FvId;
+        if (FvId == NULL) {
+            continue;
+        }
+        FdData = tmp->FdData;
+        FvInFd = tmp->FvInFd;
+        FvNumInFd = ((UINT8)atoi(FvId + 2) - (UINT8)atoi(FvInFd->FvName + 2)) + 1;
+        OldFileNode = tmp-> OldFile;
+        OldFile = OldFileNode -> FileName;
+        NewFileNode = tmp-> NewFile;
+        FfsFoundFlag = FindFile(FvInFd, FvNumInFd, OldFile, &Index);
+
+        NewFile = NewFileNode->FileName;
+        InputFfs = (EFI_FFS_FILE_HEADER2 *)ReadFileToBuffer(NewFile, &NewFileSize);
+        if (InputFfs == NULL) {
+            Error("FMMT", 0, 0004, "error while replacing file", "cannot read input file.");
+            free (FdBuffer);
+            return EFI_ABORTED;
+        }
+        HasUISection = FALSE;
+        HasUISection = ParseSection(InputFfs);
+        if (!HasUISection) {
+            printf ("WARNING: The newly replace file must have a user interface (UI) section, otherwise it cannot be deleted or replaced. \n");
+        }
+        if (FfsFoundFlag && NeedNewPath(FvInFd, FvId, Index, FALSE)) {
+            do {
+                OldFile = OldFileNode -> FileName;
+                NewFile = NewFileNode -> FileName;
+                FfsFoundFlag = FindFile(FvInFd, FvNumInFd, OldFile, &Index);
+                //
+                // TODO: currently only root FV is handled
+                //
+                InputFfs = (EFI_FFS_FILE_HEADER2 *)ReadFileToBuffer(NewFile, &NewFileSize);
+                if (InputFfs == NULL) {
+                    Error("FMMT", 0, 0004, "error while replacing file", "cannot read input file.");
+                    free (FdBuffer);
+                    return EFI_ABORTED;
+                }
+
+                Offset = FvInFd->ImageAddress + FvInFd->FfsAttuibutes[Index].Offset;
+                Fv = (EFI_FIRMWARE_VOLUME_HEADER *)(FdBuffer + FvInFd->ImageAddress);
+                OffsetAdded = FvInFd->FfsAttuibutes[Index].Offset;
+
+                if (!ReplaceFfs(Fv, InputFfs, (EFI_FFS_FILE_HEADER2 *)(FdBuffer + Offset))) {
+                  Status = AddFfs(FdBuffer, FvInFd->ImageAddress, Fv, InputFfs, &OffsetAdded);
+                  if (EFI_ERROR(Status)) {
+                    Error("FMMT", 0, 0003, "error while replacing file", "cannot add ffs");
+                    goto END;
+                  }
+                  //
+                  // Set original FFS to PAD file
+                 //
+                  CurrentFile = (EFI_FFS_FILE_HEADER2 *)(FdBuffer + FvInFd->ImageAddress + FvInFd->FfsAttuibutes[Index].Offset);
+                  PadFileSize = CalcuFfsSize(Fv, CurrentFile);
+                  AddPadFile(Fv, CurrentFile, PadFileSize);
+                }
+
+                //
+                // Calculate base address of Current FV
+                //
+                if (InputFfs->Type == EFI_FV_FILETYPE_PEIM || InputFfs->Type == EFI_FV_FILETYPE_FIRMWARE_VOLUME_IMAGE) {
+                  Status = GetBaseAddrFromFsp(FdData, FdBuffer, FvId, &BaseAddr);
+                  if (!EFI_ERROR(Status)) {
+                    mFvHeader = FvInFd->FvHeader;
+                    mFvLength = (UINT32)FvInFd->FvHeader->FvLength;
+                    RebaseFfs(BaseAddr, NewFile, (EFI_FFS_FILE_HEADER *)(FdBuffer + FvInFd->ImageAddress + OffsetAdded), OffsetAdded);
+                  }
+                  else {
+                    Status = GetBaseAddrFromVtf(FdData, FvId, &BaseAddr);
+                    if (!EFI_ERROR(Status)) {
+                      mFvHeader = FvInFd->FvHeader;
+                      mFvLength = (UINT32)FvInFd->FvHeader->FvLength;
+                      RebaseFfs(BaseAddr, NewFile, (EFI_FFS_FILE_HEADER *)(FdBuffer + FvInFd->ImageAddress + OffsetAdded), OffsetAdded);
+                    }
+                  }
+                }
+                OldFileNode = OldFileNode -> Next;
+                NewFileNode = NewFileNode -> Next;
+                free (InputFfs);
+                InputFfs = NULL;
+            } while (OldFileNode != NULL && NewFileNode!= NULL);
+        } else {
+            do {
+                OldFile = OldFileNode->FileName;
+                NewFile = NewFileNode->FileName;
+                FfsFoundFlag = FindFile(FvInFd, FvNumInFd, OldFile, &Index);
+                //
+                // Replace this FFS file with the new one.
+                //
+                if (strlen (NewFile) > _MAX_PATH - 1) {
+                  Error ("FMMT", 0, 2000, "error while replacing file", "New file name is too long!");
+                  free (FdBuffer);
+                  return EFI_ABORTED;
+                }
+                strncpy(FvInFd->FfsAttuibutes[Index].FfsName, NewFile, _MAX_PATH - 1);
+                FvInFd->FfsAttuibutes[Index].FfsName[_MAX_PATH - 1] = 0;
+                OldFileNode = OldFileNode->Next;
+                NewFileNode = NewFileNode->Next;
+            } while (OldFileNode != NULL && NewFileNode != NULL);
+            Status = LibEncapNewFvFile (FvInFd, TemDir, NULL, 0, &OutputFileName);
+            if (EFI_ERROR (Status)) {
+                Error ("FMMT", 0, 0004, "error while encapsulate FD Image", "Make new FV file failed!");
+                free (FdBuffer);
+                return Status;
+            }
+
+            NewFvFile = fopen (OutputFileName->FFSName, "rb+");
+            if (NewFvFile == NULL) {
+                Error ("FMMT", 0, 0003, "error Open FV file", "cannot Create a new FD file.");
+                free (FdBuffer);
+                return EFI_ABORTED;
+            }
+
+            fseek(NewFvFile,0,SEEK_SET);
+            fseek(NewFvFile,0,SEEK_END);
+
+            NewFvLength = ftell(NewFvFile);
+            fseek(NewFvFile,0,SEEK_SET);
+            Buffer = malloc ((size_t)NewFvLength);
+            if (Buffer == NULL)  {
+                fclose(NewFvFile);
+                free (FdBuffer);
+                return EFI_ABORTED;
+            }
+
+            if (fread (Buffer, 1, (size_t) NewFvLength, NewFvFile) != (size_t) NewFvLength) {
+                Error ("FMMT", 0, 0003, "error reading FV file %s", OutputFileName->FFSName);
+                free(Buffer);
+                free (FdBuffer);
+                fclose(NewFvFile);
+                return EFI_ABORTED;
+            }
+            if (NewFvLength <= FvInFd->FvHeader->FvLength) {
+                memcpy(FdBuffer+FvInFd->ImageAddress,Buffer,(size_t) NewFvLength);
+            }else {
+                Error ("FMMT", 0, 0004, "error writing FD file", "The replace ffs file is too large.");
+            }
+            free(Buffer);
+            fclose(NewFvFile);
+        }
+    }
+
+    Status = LibRmDir(TemDir);
+    if (EFI_ERROR(Status)) {
+      Error("FMMT", 0, 0004, "error while encapsulate FD Image", "remove directory failed!");
+    }
+
+    NewFdFile = fopen(FdOutName, "wb");
+    if (NewFdFile == NULL) {
+      Error("FMMT", 0, 0004, "error while replacing file", "Cannot open target FD file!");
+      Status = EFI_ABORTED;
+      goto END;
+    }
+    fwrite(FdBuffer, 1, FdSize, NewFdFile);
+    fclose(NewFdFile);
+    free(FdBuffer);
+    printf("Create New FD file successfully. \n\nDone! \n");
+    return EFI_SUCCESS;
+
+  END:
+    if (FdBuffer != NULL) {
+      free(FdBuffer);
+    }
+    if (InputFfs != NULL) {
+      free(InputFfs);
+    }
+    return EFI_ABORTED;
+}
+
+/**
+
+The main entry of FMMT.
+
+ at param  argc   The number of input parameters.
+ at param  *argv[]  The array pointer to the parameters.
+
+ at retval  0     The application exited normally.
+ at retval  1     An error occurred.
+
+**/
+int main(
+  int      Argc,
+  char     *Argv[]
+)
+{
+  EFI_STATUS                    Status;
+  CHAR8                         *TemDir;
+  FILE                          *CheckFileExist;
+  CHAR8                         *InFilePath;
+  CHAR8                         FullGuidToolDefinition[_MAX_PATH];
+  CHAR8                         *FileName;
+  UINTN                         FileNameIndex;
+  CHAR8                         *PathList;
+  UINTN                         EnvLen;
+  CHAR8                         *NewPathList;
+  Data                          *FileData;
+  int                           index;
+  int                           count;
+  int                           exist;
+  int                           j;
+  FILENode                      *p;
+  FILENode                      *q;
+
+  p                             = NULL;
+  q                             = NULL;
+  TemDir                        = NULL;
+  CheckFileExist                = NULL;
+  PathList                      = NULL;
+  NewPathList                   = NULL;
+  EnvLen                        = 0;
+  count                         = 0;
+  exist                         = -1;
+
+  TemDir = getcwd (NULL, _MAX_PATH);
+  if (strlen (TemDir) + strlen(OS_SEP_STR) + strlen (TEMP_DIR_NAME) > _MAX_PATH - 1) {
+    Error("FMMT", 0, 1001,  "The directory is too long.", "");
+    return 1;
+  }
+  strncat (TemDir, OS_SEP_STR, _MAX_PATH - strlen(TemDir) - 1);
+  strncat (TemDir, TEMP_DIR_NAME, _MAX_PATH - strlen(TemDir) - 1);
+
+  //
+  // Print utility header
+  //
+  printf ("Intel(R) %s. Version %d.%d, %s. %s.\n",
+    UTILITY_NAME,
+    UTILITY_MAJOR_VERSION,
+    UTILITY_MINOR_VERSION,
+    __DATE__,
+    __BUILD_VERSION
+    );
+
+  //
+  // Should have more than 1 arguments.
+  //
+  if (Argc <= 1) {
+    Usage();
+    return 1;
+  }
+
+  //
+  // Workaroud: the first call to this function
+  //            returns a file name ends with dot
+  //
+#ifndef __GNUC__
+  tmpnam (NULL);
+#else
+  CHAR8 tmp[] = "/tmp/fileXXXXXX";
+  UINTN Fdtmp;
+  Fdtmp = mkstemp(tmp);
+  close(Fdtmp);
+#endif
+
+  //
+  // Save, skip filename arg
+  //
+  FileName = Argv[0];
+  Argc--;
+  Argv++;
+
+  //
+  // Get the same path with the application itself
+  //
+  if (strlen (FileName) > _MAX_PATH - 1) {
+    Error ("FMMT", 0, 2000, "Parameter: The input filename is too long", NULL);
+    return 1;
+  }
+  strncpy (FullGuidToolDefinition, FileName, _MAX_PATH - 1);
+  FullGuidToolDefinition[_MAX_PATH - 1] = 0;
+  FileNameIndex = strlen (FullGuidToolDefinition);
+  while (FileNameIndex != 0) {
+    FileNameIndex --;
+    if (FullGuidToolDefinition[FileNameIndex] == OS_SEP) {
+    FullGuidToolDefinition[FileNameIndex] = 0;
+      break;
+    }
+  }
+  //
+  // Build the path list for Config file scan. The priority is below.
+  // 1. Scan the current path
+  // 2. Scan the same path with the application itself
+  // 3. Scan the current %PATH% of OS environment
+  // 4. Use the build-in default configuration
+  //
+  PathList = getenv("PATH");
+  if (PathList == NULL) {
+    Error (NULL, 0, 1001, "Option: Environment variable 'PATH' does not exist", NULL);
+    return 1;
+  }
+  EnvLen = strlen(PathList);
+  NewPathList  = (char *)calloc(
+                     strlen (".")
+                     + strlen (";")
+                     + strlen (FullGuidToolDefinition)
+                     + strlen (";")
+                     + EnvLen
+                     + 1,
+                     sizeof(char)
+                  );
+  if (NewPathList == NULL) {
+    Error (NULL, 0, 4001, "Resource: Memory can't be allocated", NULL);
+    PathList = NULL;
+    free (PathList);
+    return 1;
+  }
+#ifndef __GNUC__
+  sprintf (NewPathList, "%s;%s;%s", ".", FullGuidToolDefinition, PathList);
+#else
+  sprintf (NewPathList, "%s:%s:%s", ".", FullGuidToolDefinition, PathList);
+#endif
+  PathList = NULL;
+  free (PathList);
+
+  //
+  // Load Guid Tools definition
+  //
+  InFilePath = SearchConfigFromPathList(NewPathList, mGuidToolDefinition);
+  free (NewPathList);
+  if (InFilePath != NULL) {
+    printf ("\nThe Guid Tool Definition comes from the '%s'. \n", InFilePath);
+    mParsedGuidedSectionTools = ParseGuidedSectionToolsFile (InFilePath);
+    free (InFilePath);
+  } else {
+    //
+    // Use the pre-defined standard guided tools.
+    //
+  printf ("\nThe Guid Tool Definition comes from the build-in default configuration. \n");
+    mParsedGuidedSectionTools = LibPreDefinedGuidedTools ();
+  }
+
+  if ((strcmp(Argv[0], "-v") == 0) || (strcmp(Argv[0], "-V") == 0)) {
+    //
+    // View the FD binary image information.
+    //
+    if (Argc <= 1) {
+      Error("FMMT", 0, 1001, "Invalid parameter, Please make sure the parameter is correct.", "");
+      Usage ();
+      return 1;
+    }
+
+    //
+    // Open the file containing the FV to check whether it exist or not
+    //
+    CheckFileExist = fopen (Argv[1], "rb");
+    if (CheckFileExist == NULL) {
+      Error ("FMMT", 0, 0001, "Error opening the input binary file, Please make sure the <input-binary-file> exist!", Argv[1]);
+      return 1;
+    }
+    fclose(CheckFileExist);
+
+    Status = FmmtImageView(Argv[1], NULL, TRUE, NULL);
+
+    if (EFI_ERROR (Status)) {
+      Error("FMMT", 0, 1001,  "Error while view the FD image file.", "");
+      LibRmDir (TemDir);
+      return 1;
+    }
+
+  } else if ((strcmp(Argv[0], "-d") == 0) || (strcmp(Argv[0], "-D") == 0)) {
+    //
+    // Delete some named FFS file from FD binary image.
+    //
+    if (!((Argc == 4) || ((Argc - 3) % 2 == 0))) {
+      Error("FMMT", 0, 1001,  "Invalid parameter, Please make sure the parameter is correct.", "");
+      Usage ();
+      return 1;
+    }
+
+    //
+    // Open the file containing the FV to check whether it exist or not
+    //
+    CheckFileExist = fopen (Argv[1], "rb");
+    if (CheckFileExist == NULL) {
+      Error ("FMMT", 0, 0001, "Error opening the input binary file, Please make sure the <input-binary-file> exist!", Argv[1]);
+      return 1;
+    }
+    fclose(CheckFileExist);
+
+    if ((Argc - 3) % 2 == 0) {
+        FileData = malloc(sizeof (Data) * (Argc - 3)/2);
+        if (FileData == NULL) {
+          Error ("FMMT", 0, 4001, "Resource: Memory can't be allocated", NULL);
+          return 1;
+        }
+        for(index = 0; index < (Argc - 3)/2; index ++) {
+            p = malloc(sizeof (FILENode));
+            if (p == NULL) {
+              Error ("FMMT", 0, 4001, "Resource: Memory can't be allocated", NULL);
+              free (FileData);
+              return 1;
+            }
+            p -> FileName = Argv[3 + index * 2];
+            p -> SubLevel = 0;
+            exist = -1;
+            for (j = 0; j < count; j ++) {
+                if ((strcmp(Argv[2 + index * 2], (FileData + j) -> FvId) == 0)) {
+                    exist = j;
+                    break;
+                }
+            }
+            if (exist >= 0) {
+                p -> Next = (FileData + j) -> OldFile;
+                (FileData + j) -> OldFile = p;
+            } else {
+                (FileData + count) -> NewFile = NULL;
+                (FileData + count) -> FdData = NULL;
+                (FileData + count) -> FvLevel = 0;
+                (FileData + count) -> FvInFd = NULL;
+                (FileData + count) -> FvId = Argv[2 + index * 2];;
+                (FileData + count) -> OldFile = p;
+                p -> Next = NULL;
+                count ++;
+            }
+        }
+
+        if (count <= 0) {
+            Error("FMMT", 0, 0004, "error while parsing FD Image", "Gathering information failed!");
+        }
+        for (index = 0; index < count; index ++) {
+            for (j = index + 1; j < count; j ++) {
+                if ((strcmp((FileData + index)->FvId, (FileData + j)->FvId) < 0)) {
+                    CHAR8 *tmp = (FileData + index)->FvId;
+                    FILENode *t = (FileData + index)->OldFile;
+                    (FileData + index)->FvId = (FileData + j)->FvId;
+                    (FileData + index)-> OldFile = (FileData + j)->OldFile;
+                    (FileData + j)-> OldFile = t;
+                    (FileData + j)-> FvId = tmp;
+                }
+            }
+        }
+
+        //
+        // Delete some FFS file
+        //
+        Status = FmmtImageDelete(Argv[1], FileData, count, Argv[Argc-1]);
+        for (index = 0; index < count; index ++) {
+          if ((FileData + index) ->NewFile != NULL) {
+            free ((FileData + index)->NewFile);
+            (FileData + index)->NewFile = NULL;
+          }
+          if ((FileData + index)->OldFile != NULL) {
+            free ((FileData + index)->OldFile);
+            (FileData + index)->OldFile = NULL;
+          }
+        }
+        for (index = 0; index < count; index ++) {
+          if ((FileData + index)->FdData != NULL) {
+            LibFmmtFreeFd ((FileData + index)->FdData);
+          }
+        }
+        free (FileData);
+        if (EFI_ERROR (Status)) {
+            Error("FMMT", 0, 1001,  "Error while delete some named ffs file from the FD image file.", "");
+            LibRmDir (TemDir);
+            return 1;
+        }
+    } else {
+        //
+        // Delete FV
+        //
+        Status = FmmtImageDeleteFv(Argv[1], Argv[2], Argv[3]);
+        if (EFI_ERROR (Status)) {
+            Error("FMMT", 0, 1001,  "Error while delete the entire FV from the FD image file.", "");
+            LibRmDir (TemDir);
+            return 1;
+        }
+    }
+
+  } else if ((strcmp(Argv[0], "-a") == 0) || (strcmp(Argv[0], "-A") == 0)) {
+    //
+    // Add some named FFS file into FD binary image.
+    //
+    if ((Argc - 3 ) % 2 != 0) {
+      Error("FMMT", 0, 1001,  "Invalid parameter, Please make sure the parameter is correct.", "");
+      Usage ();
+      return 1;
+    }
+
+    //
+    // Open the file containing the FV to check whether it exist or not
+    //
+    CheckFileExist = fopen (Argv[1], "rb");
+    if (CheckFileExist == NULL) {
+      Error ("FMMT", 0, 0001, "Error opening the input binary file, Please make sure the <input-binary-file> exist!", Argv[1]);
+      return 1;
+    }
+    fclose(CheckFileExist);
+
+    //
+    // Check whether the new added file exist or not.
+    //
+    for (index = 1; index < (Argc - 1) / 2; index ++) {
+        CheckFileExist = fopen(Argv[2 * index + 1], "rb");
+        if (CheckFileExist == NULL) {
+            Error("FMMT", 0, 0001, "Could not open the new FFS file, Please make sure the new FFS file exist.", Argv[2 * index + 1]);
+            return 1;
+        }
+        fclose(CheckFileExist);
+    }
+
+    FileData = malloc(sizeof (Data) * (Argc - 3)/2);
+    if (FileData == NULL) {
+      Error ("FMMT", 0, 4001, "Resource: Memory can't be allocated", NULL);
+      return 1;
+    }
+    for(index = 0; index < (Argc - 3)/2; index ++) {
+        p = malloc(sizeof (FILENode));
+        if (p == NULL) {
+          Error ("FMMT", 0, 4001, "Resource: Memory can't be allocated", NULL);
+          free (FileData);
+          return 1;
+        }
+        p -> FileName = Argv[3 + index * 2];
+        p -> SubLevel = 0;
+        exist = -1;
+        for (j = 0; j < count; j ++) {
+            if ((strcmp(Argv[2 + index * 2], (FileData + j) -> FvId) == 0)) {
+                exist = j;
+                break;
+            }
+        }
+        if (exist >= 0) {
+            p -> Next = (FileData + j) -> NewFile;
+            (FileData + j) -> NewFile = p;
+        } else {
+            (FileData + count) -> OldFile = NULL;
+            (FileData + count) -> FdData = NULL;
+            (FileData + count) -> FvLevel = 0;
+            (FileData + count) -> FvInFd = NULL;
+            (FileData + count) -> FvId = Argv[2 + index * 2];
+            (FileData + count) -> NewFile = p;
+            p -> Next = NULL;
+            count ++;
+        }
+    }
+
+    if (count <= 0) {
+        Error("FMMT", 0, 0004, "error while parsing FD Image", "Gathering information failed!");
+    }
+
+  for (index = 0; index < count; index ++) {
+    for (j = index + 1; j < count; j ++) {
+      if ((strcmp((FileData + index)->FvId, (FileData + j)->FvId) < 0)) {
+        CHAR8 *tmp = (FileData + index)->FvId;
+        FILENode *temp = (FileData + index)->NewFile;
+        (FileData + index)->FvId = (FileData + j)->FvId;
+        (FileData + index)-> NewFile = (FileData + j)->NewFile;
+        (FileData + j)-> NewFile = temp;
+        (FileData + j)-> FvId = tmp;
+      }
+    }
+  }
+
+    Status = FmmtImageAdd(Argv[1], FileData, count, Argv[Argc-1]);
+    for (index = 0; index < count; index ++) {
+      if ((FileData + index)->NewFile != NULL) {
+        free ((FileData + index)->NewFile);
+        (FileData + index)->NewFile = NULL;
+      }
+      if ((FileData + index)->OldFile != NULL) {
+        free ((FileData + index)->OldFile);
+        (FileData + index)->OldFile = NULL;
+      }
+    }
+    for (index = 0; index < count; index ++) {
+      if ((FileData + index)->FdData != NULL) {
+        LibFmmtFreeFd ((FileData + index)->FdData);
+      }
+    }
+    free (FileData);
+
+    if (EFI_ERROR (Status)) {
+      Error("FMMT", 0, 1001,  "Error while add some named ffs file into the FD image file.", "");
+      LibRmDir (TemDir);
+      return 1;
+    }
+
+  } else if ((strcmp(Argv[0], "-r") == 0) || (strcmp(Argv[0], "-R") == 0)) {
+    //
+    // Replace some named FFS file in the FD binary.
+    //
+    if ((Argc - 3) % 3 != 0) {
+      Error("FMMT", 0, 1001,  "Invalid parameter, Please make sure the parameter is correct.", "");
+      Usage();
+      return 1;
+    }
+
+    //
+    // Open the file containing the FV to check whether it exist or not
+    //
+    CheckFileExist = fopen (Argv[1], "rb");
+    if (CheckFileExist == NULL) {
+      Error ("FMMT", 0, 0001, "Error opening the input binary file, Please make sure the <input-binary-file> exist!", Argv[1]);
+      return 1;
+    }
+    fclose(CheckFileExist);
+
+    //
+    // Check whether the new FFS file exist or not.
+    //
+    for (index = 1; index < Argc/3; index ++) {
+        CheckFileExist = fopen(Argv[3 * index + 1], "rb");
+        if (CheckFileExist == NULL) {
+            Error ("FMMT", 0, 0001, "Could not open the new FFS file, Please make sure the new FFS file exist.", Argv[3 * index + 1]);
+            return 1;
+       }
+       fclose(CheckFileExist);
+    }
+
+    FileData = malloc(sizeof (Data) * (Argc - 3)/3);
+    if (FileData == NULL) {
+      Error ("FMMT", 0, 4001, "Resource: Memory can't be allocated", NULL);
+      return 1;
+    }
+    for(index = 0; index < (Argc - 3)/3; index ++) {
+        p = malloc(sizeof (FILENode)); //p for old file
+        if (p == NULL) {
+          Error ("FMMT", 0, 4001, "Resource: Memory can't be allocated", NULL);
+          free (FileData);
+          return 1;
+        }
+        q = malloc(sizeof (FILENode)); //q for new file
+        if (q == NULL) {
+          Error ("FMMT", 0, 4001, "Resource: Memory can't be allocated", NULL);
+          free (FileData);
+          free (p);
+          return 1;
+        }
+        p -> FileName = Argv[3 + index * 3];
+        q -> FileName = Argv[4 + index * 3];
+        p -> SubLevel = 0;
+        q -> SubLevel = 0;
+        exist = -1;
+        for (j = 0; j < count; j ++) {
+            if ((strcmp(Argv[2 + index * 3], (FileData + j) -> FvId) == 0)) {
+                exist = j;
+                break;
+            }
+        }
+        if (exist >= 0) {
+            p -> Next = (FileData + j) -> OldFile;
+            (FileData + j) -> OldFile = p;
+            q -> Next = (FileData + j) -> NewFile;
+            (FileData + j) -> NewFile = q;
+        } else {
+            (FileData + count) -> FdData = NULL;
+            (FileData + count) -> FvLevel = 0;
+            (FileData + count) -> FvInFd = NULL;
+            (FileData + count) -> FvId = Argv[2 + index * 3];;
+            (FileData + count) -> OldFile = p;
+            (FileData + count) -> NewFile = q;
+            p -> Next = NULL;
+            q -> Next = NULL;
+            count ++;
+        }
+    }
+
+    if (count <= 0) {
+        Error("FMMT", 0, 0004, "error while parsing FD Image", "Gathering information failed!");
+    }
+    for (index = 0; index < count; index ++) {
+        for (j = index + 1; j < count; j ++) {
+            if ((strcmp((FileData + index)->FvId, (FileData + j)->FvId) < 0)) {
+                CHAR8 *tmp = (FileData + index)->FvId;
+                FILENode *Old = (FileData + index)->OldFile;
+                FILENode *New = (FileData + index)->NewFile;
+                (FileData + index)->FvId = (FileData + j)->FvId;
+                (FileData + index)->OldFile = (FileData + j)->OldFile;
+                (FileData + index)->NewFile = (FileData + j)->NewFile;
+                (FileData + j)->OldFile = Old;
+                (FileData + j)->NewFile = New;
+                (FileData + j)->FvId = tmp;
+            }
+        }
+    }
+
+    Status = FmmtImageReplace(Argv[1], FileData, count, Argv[Argc-1]);
+    for (index = 0; index < count; index ++) {
+      if ((FileData + index)->NewFile != NULL) {
+        free ((FileData + index)->NewFile);
+        (FileData + index)->NewFile = NULL;
+      }
+      if ((FileData + index)->OldFile != NULL) {
+        free ((FileData + index)->OldFile);
+        (FileData + index)->OldFile = NULL;
+      }
+    }
+    for (index = 0; index < count; index ++) {
+      if ((FileData + index)->FdData != NULL) {
+        LibFmmtFreeFd ((FileData + index)->FdData);
+      }
+    }
+    free (FileData);
+    if (EFI_ERROR (Status)) {
+      Error("FMMT", 0, 1001,  "Error while replace the named ffs file in the FD image file with the new ffs file.", "");
+      LibRmDir (TemDir);
+      return 1;
+    }
+
+  } else if ((strcmp(Argv[0], "-h") == 0) || (strcmp(Argv[0], "--help") == 0) ||
+             (strcmp(Argv[0], "-?") == 0) || (strcmp(Argv[0], "/?") == 0)) {
+    //
+    // print help information to user.
+    //
+    Usage();
+
+  } else {
+    //
+    // Invalid parameter.
+    //
+    printf("\n");
+    Error("FMMT", 0, 1001,  "Invalid parameter", Argv[0]);
+    Usage();
+    return 1;
+  }
+
+  return 0;
+}
+
diff --git a/BaseTools/Source/C/FMMT/FmmtLib.c b/BaseTools/Source/C/FMMT/FmmtLib.c
new file mode 100644
index 0000000000..f87042114b
--- /dev/null
+++ b/BaseTools/Source/C/FMMT/FmmtLib.c
@@ -0,0 +1,5051 @@
+/** @file
+
+ Library to parse and generate FV image.
+
+ Copyright (c)  2019, Intel Corporation. All rights reserved.<BR>
+ SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#include "FirmwareModuleManagement.h"
+
+#define EFI_TEST_FFS_ATTRIBUTES_BIT(FvbAttributes, TestAttributes, Bit) \
+    ( \
+      (BOOLEAN) ( \
+          (FvbAttributes & EFI_FVB2_ERASE_POLARITY) ? (((~TestAttributes) & Bit) == Bit) : ((TestAttributes & Bit) == Bit) \
+        ) \
+    )
+
+CHAR8      mFirmwareFileSystem2Guid[16] = {0x78, 0xE5, 0x8C, 0x8C, 0x3D, 0x8A, 0x1C, 0x4F, 0x99, 0x35, 0x89, 0x61, 0x85, 0xC3, 0x2D, 0xD3};
+
+CHAR8      mFirmwareFileSystem3Guid[16] = {0x7A, 0xC0, 0x73, 0x54, 0xCB, 0x3D, 0xCA, 0x4D, 0xBD, 0x6F, 0x1E, 0x96, 0x89, 0xE7, 0x34, 0x9A };
+
+EFI_GUID   mEfiCrc32GuidedSectionExtractionProtocolGuid = EFI_CRC32_GUIDED_SECTION_EXTRACTION_PROTOCOL_GUID;
+extern     CHAR8*      mGuidToolDefinition;
+
+static CHAR8 *mSectionTypeName[] = {
+  NULL,                                 // 0x00 - reserved
+  "EFI_SECTION_COMPRESSION",            // 0x01
+  "EFI_SECTION_GUID_DEFINED",           // 0x02
+  NULL,                                 // 0x03 - reserved
+  NULL,                                 // 0x04 - reserved
+  NULL,                                 // 0x05 - reserved
+  NULL,                                 // 0x06 - reserved
+  NULL,                                 // 0x07 - reserved
+  NULL,                                 // 0x08 - reserved
+  NULL,                                 // 0x09 - reserved
+  NULL,                                 // 0x0A - reserved
+  NULL,                                 // 0x0B - reserved
+  NULL,                                 // 0x0C - reserved
+  NULL,                                 // 0x0D - reserved
+  NULL,                                 // 0x0E - reserved
+  NULL,                                 // 0x0F - reserved
+  "EFI_SECTION_PE32",                   // 0x10
+  "EFI_SECTION_PIC",                    // 0x11
+  "EFI_SECTION_TE",                     // 0x12
+  "EFI_SECTION_DXE_DEPEX",              // 0x13
+  "EFI_SECTION_VERSION",                // 0x14
+  "EFI_SECTION_USER_INTERFACE",         // 0x15
+  "EFI_SECTION_COMPATIBILITY16",        // 0x16
+  "EFI_SECTION_FIRMWARE_VOLUME_IMAGE",  // 0x17
+  "EFI_SECTION_FREEFORM_SUBTYPE_GUID",  // 0x18
+  "EFI_SECTION_RAW",                    // 0x19
+  NULL,                                 // 0x1A
+  "EFI_SECTION_PEI_DEPEX",              // 0x1B
+  "EFI_SECTION_SMM_DEPEX"               // 0x1C
+};
+
+
+static CHAR8 *mFfsFileType[] = {
+  NULL,                                   // 0x00
+  "EFI_FV_FILETYPE_RAW",                  // 0x01
+  "EFI_FV_FILETYPE_FREEFORM",             // 0x02
+  "EFI_FV_FILETYPE_SECURITY_CORE",        // 0x03
+  "EFI_FV_FILETYPE_PEI_CORE",             // 0x04
+  "EFI_FV_FILETYPE_DXE_CORE",             // 0x05
+  "EFI_FV_FILETYPE_PEIM",                 // 0x06
+  "EFI_FV_FILETYPE_DRIVER",               // 0x07
+  "EFI_FV_FILETYPE_COMBINED_PEIM_DRIVER", // 0x08
+  "EFI_FV_FILETYPE_APPLICATION",          // 0x09
+  "EFI_FV_FILETYPE_SMM",                  // 0x0A
+  "EFI_FV_FILETYPE_FIRMWARE_VOLUME_IMAGE",// 0x0B
+  "EFI_FV_FILETYPE_COMBINED_SMM_DXE",     // 0x0C
+  "EFI_FV_FILETYPE_SMM_CORE"              // 0x0D
+ };
+
+static CHAR8 *mGuidSectionAttr[] = {
+  "NONE",                                 // 0x00
+  "PROCESSING_REQUIRED",                  // 0x01
+  "AUTH_STATUS_VALID"                     // 0x02
+};
+
+static EFI_GUID mFvUiGuid = {
+  0xA67DF1FA, 0x8DE8, 0x4E98, {
+    0xAF, 0x09, 0x4B, 0xDF, 0x2E, 0xFF, 0xBC, 0x7C
+  }
+};
+
+
+/**
+  Generate the unique template filename.
+**/
+CHAR8 *
+GenTempFile (
+ VOID
+ )
+{
+  CHAR8   *TemString;
+  TemString = NULL;
+#ifndef __GNUC__
+  TemString = CloneString (tmpnam (NULL));
+#else
+  CHAR8 tmp[] = "/tmp/fileXXXXXX";
+  UINTN Fdtmp;
+  Fdtmp = mkstemp(tmp);
+  TemString = CloneString(tmp);
+  close(Fdtmp);
+#endif
+  return TemString;
+}
+
+static
+EFI_STATUS
+LibExtractFvUiName(CONST EFI_FIRMWARE_VOLUME_EXT_HEADER *FvExtHeader, CHAR8 **FvUiName)
+{
+  UINT8 *ExtEnd;
+  UINT32 ExtDataSize;
+  EFI_FIRMWARE_VOLUME_EXT_ENTRY *ExtEntry;
+  EFI_FIRMWARE_VOLUME_EXT_ENTRY_GUID_TYPE *GuidEntry;
+
+
+  ExtEnd = (UINT8 *)FvExtHeader + FvExtHeader->ExtHeaderSize;
+  ExtEntry = (EFI_FIRMWARE_VOLUME_EXT_ENTRY *)(FvExtHeader + 1);
+  while ((UINT8 *)ExtEntry < ExtEnd) {
+    //
+    // GUID type EXT
+    //
+    if (ExtEntry->ExtEntryType == 0x0002) {
+      GuidEntry = (EFI_FIRMWARE_VOLUME_EXT_ENTRY_GUID_TYPE *)ExtEntry;
+      if (memcmp(&GuidEntry->FormatType, &mFvUiGuid, sizeof(EFI_GUID)) == 0) {
+        ExtDataSize = ExtEntry->ExtEntrySize - (sizeof(EFI_GUID)+sizeof(*ExtEntry));
+        *FvUiName = malloc(ExtDataSize + 1);
+        if (*FvUiName != NULL) {
+          memcpy(*FvUiName, (UINT8 *)GuidEntry + sizeof(EFI_GUID)+sizeof(*ExtEntry), ExtDataSize);
+          (*FvUiName)[ExtDataSize] = '\0';
+          return EFI_SUCCESS;
+        }
+      }
+    }
+
+    ExtEntry = (EFI_FIRMWARE_VOLUME_EXT_ENTRY *)((UINT8 *)ExtEntry + ExtEntry->ExtEntrySize);
+  }
+  return EFI_NOT_FOUND;
+}
+
+FV_INFORMATION *
+LibInitializeFvStruct (
+  FV_INFORMATION *Fv
+)
+{
+  UINT32     Index;
+
+  if (Fv == NULL) {
+    return NULL;
+  }
+
+  for (Index = 0; Index < MAX_NUMBER_OF_FILES_IN_FV; Index ++) {
+    memset (Fv->FfsAttuibutes[Index].FfsName, '\0', _MAX_PATH);
+    memset (Fv->FfsAttuibutes[Index].UiName, '\0', _MAX_PATH);
+    memset (&Fv->FfsAttuibutes[Index].GuidName, '\0', sizeof(EFI_GUID));
+    Fv->FfsAttuibutes[Index].UiNameSize           = 0;
+    Fv->FfsAttuibutes[Index].IsLeaf               = TRUE;
+    Fv->FfsAttuibutes[Index].Level                = 0xFF;
+    Fv->FfsAttuibutes[Index].TotalSectionNum      = 0;
+    Fv->FfsAttuibutes[Index].Depex                = NULL;
+    Fv->FfsAttuibutes[Index].DepexLen             = 0;
+    Fv->FfsAttuibutes[Index].IsHandle             = FALSE;
+    Fv->FfsAttuibutes[Index].IsFvStart            = FALSE;
+    Fv->FfsAttuibutes[Index].IsFvEnd              = FALSE;
+  }
+
+  Fv->EncapData = NULL;
+  Fv->FvNext = NULL;
+  Fv->ChildFvFFS = NULL;
+  Fv->FvLevel   = 0;
+  Fv->MulFvLevel = 1;
+  strcpy(Fv->AlignmentStr,"8");
+  return Fv;
+}
+
+
+EFI_STATUS
+LibFindFvInFd (
+  IN     FILE             *InputFile,
+  IN OUT FIRMWARE_DEVICE  **FdData
+)
+{
+  FIRMWARE_DEVICE             *LocalFdData;
+  UINT16                      Index;
+  CHAR8                       Ffs2Guid[16];
+  CHAR8                       SignatureCheck[5] = "";
+  CHAR8                       Signature[5] = "_FVH";
+  FV_INFORMATION              *CurrentFv;
+  FV_INFORMATION              *NewFoundFv;
+  BOOLEAN                     FirstMatch;
+  UINT32                      FdSize;
+  UINT16                      FvCount;
+  UINT8                       *FdBuffer;
+  UINT8                       *FdBufferEnd;
+  UINT8                       *FdBufferOri;
+  EFI_FIRMWARE_VOLUME_HEADER  *FvHeader;
+
+  CurrentFv      = NULL;
+  NewFoundFv     = NULL;
+  FdBuffer       = NULL;
+  FdBufferOri    = NULL;
+  FirstMatch     = TRUE;
+  Index          = 0;
+  FdSize         = 0;
+  FvCount        = 0;
+  LocalFdData    = NULL;
+
+  if (InputFile == NULL) {
+    Error ("FMMT", 0, 0001, "Error opening the input file", "");
+    return EFI_ABORTED;
+  }
+
+  //
+  // Find each FVs in the FD
+  //
+
+  fseek(InputFile,0,SEEK_SET);
+  fseek(InputFile,0,SEEK_END);
+
+  FdSize = ftell(InputFile);
+
+  fseek(InputFile,0,SEEK_SET);
+  //
+  // Create an FD structure to store useful information.
+  //
+  LocalFdData     = (FIRMWARE_DEVICE *) malloc (sizeof (FIRMWARE_DEVICE));
+  if (LocalFdData == NULL) {
+    Error ("FMMT", 0, 0002, "Error searching FVs in the input fd", "Allocate memory error");
+    return EFI_OUT_OF_RESOURCES;
+  }
+  LocalFdData->Fv = (FV_INFORMATION *)  malloc (sizeof (FV_INFORMATION));
+  if (LocalFdData->Fv == NULL) {
+    Error ("FMMT", 0, 0002, "Error searching FVs in the input fd", "Allocate memory error");
+    free (LocalFdData);
+    return EFI_OUT_OF_RESOURCES;
+  }
+
+  LibInitializeFvStruct (LocalFdData->Fv);
+
+  //
+  // Readout the FD file data to buffer.
+  //
+  FdBuffer = malloc (FdSize);
+
+  if (FdBuffer == NULL) {
+    Error ("FMMT", 0, 0002, "Error searching FVs in the input fd", "Allocate memory error");
+    free (LocalFdData->Fv);
+    free (LocalFdData);
+    return EFI_OUT_OF_RESOURCES;
+  }
+
+  if (fread (FdBuffer, 1, FdSize, InputFile) != FdSize) {
+    Error ("FMMT", 0, 0002, "Error searching FVs in the input fd", "Read FD file error!");
+    free (LocalFdData->Fv);
+    free (LocalFdData);
+    free (FdBuffer);
+    return EFI_ABORTED;
+  }
+
+  FdBufferOri = FdBuffer;
+  FdBufferEnd = FdBuffer + FdSize;
+
+  while (FdBuffer <= FdBufferEnd - sizeof (EFI_FIRMWARE_VOLUME_HEADER)) {
+    FvHeader = (EFI_FIRMWARE_VOLUME_HEADER *) FdBuffer;
+    //
+    // Copy 4 bytes of fd data to check the _FVH signature
+    //
+    memcpy (SignatureCheck, &FvHeader->Signature, 4);
+
+    if (strncmp(SignatureCheck, Signature, 4) == 0){
+      //
+      // Still need to determine the FileSystemGuid in EFI_FIRMWARE_VOLUME_HEADER equal to
+      // EFI_FIRMWARE_FILE_SYSTEM2_GUID or EFI_FIRMWARE_FILE_SYSTEM3_GUID.
+      // Turn back 28 bytes to find the GUID.
+      //
+      memcpy (Ffs2Guid, &FvHeader->FileSystemGuid, 16);
+
+      //
+      // Compare GUID.
+      //
+      for (Index = 0; Index < 16; Index ++) {
+        if (Ffs2Guid[Index] != mFirmwareFileSystem2Guid[Index]) {
+          break;
+        }
+      }
+    if (Index != 16) {
+      for (Index = 0; Index < 16; Index ++) {
+          if (Ffs2Guid[Index] != mFirmwareFileSystem3Guid[Index]) {
+            break;
+          }
+        }
+    }
+
+      //
+      // Here we found an FV.
+      //
+      if ((Index == 16) && ((FdBuffer + FvHeader->FvLength) <= FdBufferEnd)) {
+        if (FirstMatch) {
+          LocalFdData->Fv->ImageAddress = (UINTN)((UINT8 *)FdBuffer - (UINT8 *)FdBufferOri);
+          CurrentFv                     = LocalFdData->Fv;
+          CurrentFv->FvNext             = NULL;
+          //
+          // Store the FV name by found sequence
+          //
+          sprintf(CurrentFv->FvName, "FV%d", FvCount);
+
+          FirstMatch = FALSE;
+          } else {
+            NewFoundFv = (FV_INFORMATION *) malloc (sizeof (FV_INFORMATION));
+            if (NewFoundFv == NULL) {
+              Error ("FMMT", 0, 0002, "Error searching FVs in the input fd", "Allocate memory error");
+              free (LocalFdData->Fv);
+              free (LocalFdData);
+              free (FdBuffer);
+              return EFI_OUT_OF_RESOURCES;
+            }
+
+            LibInitializeFvStruct (NewFoundFv);
+
+            //
+            // Need to turn back 0x2c bytes
+            //
+            NewFoundFv->ImageAddress = (UINTN)((UINT8 *)FdBuffer - (UINT8 *)FdBufferOri);
+
+            //
+            // Store the FV name by found sequence
+            //
+            sprintf(NewFoundFv->FvName, "FV%d", FvCount);
+
+            //
+            // Value it to NULL for found FV usage.
+            //
+            NewFoundFv->FvNext       = NULL;
+            CurrentFv->FvNext        = NewFoundFv;
+
+            //
+            // Make the CurrentFv point to next FV.
+            //
+            CurrentFv                = CurrentFv->FvNext;
+          }
+
+        FvCount ++;
+        FdBuffer = FdBuffer + FvHeader->FvLength;
+      } else {
+        FdBuffer ++;
+      }
+
+    } else {
+      FdBuffer ++;
+    }
+  }
+
+  LocalFdData->Size = FdSize;
+
+  *FdData = LocalFdData;
+
+  free (FdBufferOri);
+
+  return EFI_SUCCESS;
+}
+
+UINTN
+GetFreeOffset (
+  IN   VOID   *InputFv
+)
+{
+  UINTN FreeOffset;
+  UINTN Offset;
+  EFI_STATUS Status;
+  EFI_FFS_FILE_HEADER2 *CurrentFile;
+
+  Offset = 0;
+  CurrentFile = NULL;
+  FreeOffset = 0;
+  do {
+    FreeOffset = (UINTN)ALIGN_POINTER(Offset, 8);
+    Status = FvBufFindNextFile(InputFv, &Offset, (VOID **)&CurrentFile);
+    if (Status == EFI_NOT_FOUND) {
+      CurrentFile = NULL;
+      break;
+    }
+    else if (EFI_ERROR(Status)) {
+      return Status;
+    }
+  } while (CurrentFile != NULL);
+
+  return FreeOffset;
+}
+
+/*
+  Construct a set of blank chars based on the number.
+
+  @param[in]   Count The number of blank chars.
+
+  @return      A string contained the blank chars.
+
+*/
+CHAR8 *
+LibConstructBlankChar (
+  IN UINT8    Count
+)
+{
+  CHAR8    *RetStr;
+  UINT8    Index;
+
+  Index  = 0;
+  RetStr = NULL;
+
+  RetStr = (CHAR8 *) malloc (Count +1);
+
+  if (RetStr == NULL) {
+    Error (NULL, 0, 4001, "Resource: Memory can't be allocated", NULL);
+    return NULL;
+  }
+
+  memset (RetStr , '\0', Count + 1);
+
+  for (Index=0; Index <= Count -1; Index ++) {
+    RetStr[Index] = ' ';
+  }
+
+  return RetStr;
+
+}
+
+/**
+
+  This function determines the size of the FV and the erase polarity.  The
+  erase polarity is the FALSE value for file state.
+
+
+  @param[in ]   InputFile       The file that contains the FV image.
+  @param[out]   FvSize          The size of the FV.
+  @param[out]   ErasePolarity   The FV erase polarity.
+
+  @return EFI_SUCCESS             Function completed successfully.
+  @return EFI_INVALID_PARAMETER   A required parameter was NULL or is out of range.
+  @return EFI_ABORTED             The function encountered an error.
+
+**/
+EFI_STATUS
+LibReadFvHeader (
+  IN   VOID                       *InputFv,
+  IN   BOOLEAN                    ViewFlag,
+  IN   UINT8                      FvLevel,
+  IN   UINT8                      FvCount,
+  IN   CHAR8                      *FvName
+  )
+{
+  EFI_FIRMWARE_VOLUME_HEADER     *VolumeHeader;
+  CHAR8                          *BlankSpace;
+  CHAR8                          *FvUiName;
+  EFI_FIRMWARE_VOLUME_EXT_HEADER *FvExtHeader;
+
+  BlankSpace = NULL;
+  FvUiName = NULL;
+
+  //
+  // Check input parameters
+  //
+  if (InputFv == NULL) {
+    Error (__FILE__, __LINE__, 0, "FMMT application error", "invalid parameter to function");
+    return EFI_INVALID_PARAMETER;
+  }
+
+  //
+  // Read the header
+  //
+  VolumeHeader = (EFI_FIRMWARE_VOLUME_HEADER *) InputFv;
+
+
+  BlankSpace = LibConstructBlankChar((FvLevel)*2);
+
+  if (BlankSpace == NULL) {
+    Error (NULL, 0, 4001, "Resource: Memory can't be allocated", NULL);
+    return EFI_OUT_OF_RESOURCES;
+  }
+
+
+  if (ViewFlag) {
+    if ((FvLevel -1) == 0) {
+      printf ("\n%s :\n", FvName);
+    } else {
+      printf ("%sChild FV named FV%d of %s\n", BlankSpace, FvCount, FvName);
+    }
+  }
+
+  //
+  // Print FV header information
+  //
+  if (ViewFlag) {
+    printf ("\n%sAttributes:            %X\n", BlankSpace, (unsigned) VolumeHeader->Attributes);
+    printf ("%sTotal Volume Size:     0x%08X\n", BlankSpace, (unsigned) VolumeHeader->FvLength);
+    printf ("%sFree Volume Size:      0x%08X\n", BlankSpace, (unsigned) (VolumeHeader->FvLength - GetFreeOffset(InputFv)));
+  }
+
+  if (ViewFlag && VolumeHeader->ExtHeaderOffset != 0) {
+    FvExtHeader = (EFI_FIRMWARE_VOLUME_EXT_HEADER *)((UINT8 *)VolumeHeader + VolumeHeader->ExtHeaderOffset);
+    printf("%sFvNameGuid:            %08X-%04X-%04X-%02X%02X-%02X%02X%02X%02X%02X%02X\n",
+           BlankSpace,
+           FvExtHeader->FvName.Data1,
+           FvExtHeader->FvName.Data2,
+           FvExtHeader->FvName.Data3,
+           FvExtHeader->FvName.Data4[0],
+           FvExtHeader->FvName.Data4[1],
+           FvExtHeader->FvName.Data4[2],
+           FvExtHeader->FvName.Data4[3],
+           FvExtHeader->FvName.Data4[4],
+           FvExtHeader->FvName.Data4[5],
+           FvExtHeader->FvName.Data4[6],
+           FvExtHeader->FvName.Data4[7]);
+    LibExtractFvUiName(FvExtHeader, &FvUiName);
+    if (FvUiName != NULL && FvLevel == 1) {
+      printf("%sFV UI Name:            %s\n\n", BlankSpace, FvUiName);
+    }
+    free(FvUiName);
+  }
+  free (BlankSpace);
+  return EFI_SUCCESS;
+}
+
+/*
+  Get size info from FV file.
+
+  @param[in]
+  @param[out]
+
+  @retval
+
+*/
+EFI_STATUS
+LibGetFvSize (
+  IN   FILE                       *InputFile,
+  OUT  UINT32                     *FvSize
+  )
+{
+
+  UINTN                          BytesRead;
+  UINT32                         Size;
+  EFI_FV_BLOCK_MAP_ENTRY         BlockMap;
+
+  BytesRead = 0;
+  Size      = 0;
+
+  if (InputFile == NULL || FvSize == NULL) {
+    Error (__FILE__, __LINE__, 0, "FMMT application error", "invalid parameter to function");
+    return EFI_INVALID_PARAMETER;
+  }
+
+  fseek (InputFile, sizeof (EFI_FIRMWARE_VOLUME_HEADER) - sizeof (EFI_FV_BLOCK_MAP_ENTRY), SEEK_CUR);
+  do {
+    fread (&BlockMap, sizeof (EFI_FV_BLOCK_MAP_ENTRY), 1, InputFile);
+    BytesRead += sizeof (EFI_FV_BLOCK_MAP_ENTRY);
+
+    if (BlockMap.NumBlocks != 0) {
+      Size += BlockMap.NumBlocks * BlockMap.Length;
+    }
+  } while (!(BlockMap.NumBlocks == 0 && BlockMap.Length == 0));
+
+
+  *FvSize = Size;
+
+  return EFI_SUCCESS;
+}
+
+/**
+
+  Clears out all files from the Fv buffer in memory
+
+  @param[in]    Fv - Address of the Fv in memory
+
+  @return       EFI_STATUS
+
+**/
+EFI_STATUS
+FvBufGetSize (
+  IN  VOID   *Fv,
+  OUT UINTN  *Size
+  )
+{
+  EFI_FIRMWARE_VOLUME_HEADER *hdr;
+  EFI_FV_BLOCK_MAP_ENTRY     *blk;
+
+  *Size = 0;
+  hdr   = (EFI_FIRMWARE_VOLUME_HEADER*)Fv;
+  blk   = hdr->BlockMap;
+
+  while (blk->Length != 0 || blk->NumBlocks != 0) {
+    *Size = *Size + (blk->Length * blk->NumBlocks);
+    if (*Size >= 0x40000000) {
+    //
+      // If size is greater than 1GB, then assume it is corrupted
+      //
+      return EFI_VOLUME_CORRUPTED;
+    }
+    blk++;
+  }
+
+  if (*Size == 0) {
+    //
+    // If size is 0, then assume the volume is corrupted
+    //
+    return EFI_VOLUME_CORRUPTED;
+  }
+
+  return EFI_SUCCESS;
+}
+
+/*
+  Generate the leaf FFS files.
+
+*/
+EFI_STATUS
+LibGenFfsFile (
+  EFI_FFS_FILE_HEADER2   *CurrentFile,
+  FV_INFORMATION         *CurrentFv,
+  CHAR8                  *FvName,
+  UINT8                  Level,
+  UINT32                 *FfsCount,
+  BOOLEAN                ErasePolarity
+)
+{
+  UINT32                      FfsFileSize;
+  CHAR8                       *FfsFileName;
+  FILE                        *FfsFile;
+  CHAR8                       *TempDir;
+
+
+  FfsFileSize   = 0;
+  FfsFileName   = NULL;
+  FfsFile       = NULL;
+  TempDir       = NULL;
+
+  TempDir = getcwd (NULL, _MAX_PATH);
+  if (strlen (TempDir) + strlen(OS_SEP_STR) + strlen (TEMP_DIR_NAME) > _MAX_PATH - 1) {
+    Error("FMMT", 0, 1001,  "The directory is too long.", "");
+    return EFI_ABORTED;
+  }
+  strncat (TempDir, OS_SEP_STR, _MAX_PATH - strlen(TempDir) - 1);
+  strncat (TempDir, TEMP_DIR_NAME, _MAX_PATH - strlen(TempDir) - 1);
+
+  mkdir(TempDir, S_IRWXU | S_IRWXG | S_IRWXO);
+
+  FfsFileName = (CHAR8 *) malloc (_MAX_PATH);
+  if (FfsFileName == NULL) {
+    Error (NULL, 0, 4001, "Resource: Memory can't be allocated", NULL);
+    return EFI_ABORTED;
+  }
+  memset (FfsFileName, '\0', _MAX_PATH);
+  FfsFileSize = GetFfsFileLength ((EFI_FFS_FILE_HEADER *) CurrentFile);
+  sprintf (
+    (CHAR8 *)FfsFileName,
+    "%s%cNum%d-%08X-%04X-%04X-%02X%02X-%02X%02X%02X%02X%02X%02X-Level%d",
+    TempDir,
+    OS_SEP,
+    *FfsCount,
+    (unsigned) CurrentFile->Name.Data1,
+    CurrentFile->Name.Data2,
+    CurrentFile->Name.Data3,
+    CurrentFile->Name.Data4[0],
+    CurrentFile->Name.Data4[1],
+    CurrentFile->Name.Data4[2],
+    CurrentFile->Name.Data4[3],
+    CurrentFile->Name.Data4[4],
+    CurrentFile->Name.Data4[5],
+    CurrentFile->Name.Data4[6],
+    CurrentFile->Name.Data4[7],
+    Level
+  );
+
+  memcpy (CurrentFv->FfsAttuibutes[*FfsCount].FfsName, FfsFileName, strlen(FfsFileName));
+  memcpy (&CurrentFv->FfsAttuibutes[*FfsCount].GuidName, &CurrentFile->Name, sizeof(EFI_GUID));
+  //
+  // Update current FFS files file state.
+  //
+  if (ErasePolarity) {
+    CurrentFile->State = (UINT8)~(CurrentFile->State);
+  }
+
+  FfsFile = fopen (FfsFileName, "wb+");
+  if (FfsFile == NULL) {
+    Error ("FMMT", 0, 0003, "error writing FFS file", "cannot Create a new ffs file.");
+    free(FfsFileName);
+    return EFI_ABORTED;
+  }
+
+  if (fwrite (CurrentFile, 1, FfsFileSize, FfsFile) != FfsFileSize) {
+     Error ("FMMT", 0, 0004, "error writing FFS file", "cannot Create a new ffs file.");
+     fclose(FfsFile);
+     free(FfsFileName);
+     return EFI_ABORTED;
+  }
+
+  fclose(FfsFile);
+  free(FfsFileName);
+  FfsFileName = NULL;
+
+  CurrentFv->FfsNumbers  = *FfsCount;
+
+  *FfsCount += 1;
+
+  if (ErasePolarity) {
+    CurrentFile->State = (UINT8)~(CurrentFile->State);
+  }
+
+  return EFI_SUCCESS;
+}
+
+VOID
+Unicode2AsciiString (
+  IN  CHAR16 *Source,
+  OUT CHAR8  *Destination
+  )
+  /*++
+
+  Routine Description:
+
+  Convert a null-terminated unicode string to a null-terminated ascii string.
+
+  Arguments:
+
+    Source      - The pointer to the null-terminated input unicode string.
+    Destination - The pointer to the null-terminated output ascii string.
+
+  Returns:
+
+    N/A
+
+  --*/
+{
+  while (*Source != '\0') {
+    *(Destination++) = (CHAR8) *(Source++);
+  }
+  //
+  // End the ascii with a NULL.
+  //
+  *Destination = '\0';
+}
+
+
+/**
+
+  Parses EFI Sections, if the view flag turn on, then will collect FFS section information
+  and extract FFS files.
+
+  @param[in]      SectionBuffer - Buffer containing the section to parse.
+  @param[in]      BufferLength  - Length of SectionBuffer
+  @param[in, out] CurrentFv
+  @param[in]      FvName
+  @param[in]      CurrentFile
+  @param[in]      Level
+  @param[in, out] FfsCount
+  @param[in]      ViewFlag
+  @param[in]      ErasePolarity
+
+  @retval       EFI_SECTION_ERROR - Problem with section parsing.
+                      (a) compression errors
+                      (b) unrecognized section
+  @retval       EFI_UNSUPPORTED - Do not know how to parse the section.
+  @retval       EFI_SUCCESS - Section successfully parsed.
+  @retval       EFI_OUT_OF_RESOURCES - Memory allocation failed.
+
+--*/
+EFI_STATUS
+LibParseSection (
+  UINT8                  *SectionBuffer,
+  UINT32                 BufferLength,
+  FV_INFORMATION         *CurrentFv,
+  CHAR8                  *FvName,
+  EFI_FFS_FILE_HEADER2   *CurrentFile,
+  UINT8                  Level,
+  ENCAP_INFO_DATA        **CurrentFvEncapData,
+  UINT8                  FfsLevel,
+  UINT32                 *FfsCount,
+  UINT8                  *FvCount,
+  BOOLEAN                ViewFlag,
+  BOOLEAN                ErasePolarity,
+  BOOLEAN                *IsFfsGenerated
+  )
+{
+  UINT32              ParsedLength;
+  UINT8               *Ptr;
+  UINT32              SectionLength;
+  UINT32              UiSectionLength;
+  EFI_SECTION_TYPE    Type;
+  EFI_STATUS          Status;
+  CHAR8               *ExtractionTool;
+  CHAR8               *ToolInputFile;
+  CHAR8               *ToolOutputFile;
+  CHAR8               *SystemCommandFormatString;
+  CHAR8               *SystemCommand;
+  UINT8               *ToolOutputBuffer;
+  UINT32              ToolOutputLength;
+  CHAR16              *UIName;
+  UINT32              UINameSize;
+  BOOLEAN             HasDepexSection;
+  UINT32              NumberOfSections;
+  ENCAP_INFO_DATA     *LocalEncapData;
+  ENCAP_INFO_DATA     *LocalEncapDataTemp;
+  CHAR8               *BlankChar;
+  UINT8               *UncompressedBuffer;
+  UINT32              UncompressedLength;
+  UINT8               *CompressedBuffer;
+  UINT32              CompressedLength;
+  UINT8               CompressionType;
+  DECOMPRESS_FUNCTION DecompressFunction;
+  GETINFO_FUNCTION    GetInfoFunction;
+  UINT32              DstSize;
+  UINT32              ScratchSize;
+  UINT8               *ScratchBuffer;
+  BOOLEAN             EncapDataNeedUpdata;
+  CHAR8               *TempDir;
+  CHAR8               *ToolInputFileFullName;
+  CHAR8               *ToolOutputFileFullName;
+  UINT8               LargeHeaderOffset;
+  UINT16              GuidAttr;
+  UINT16              DataOffset;
+  CHAR8               *UIFileName;
+  CHAR8               *ToolInputFileName;
+  CHAR8               *ToolOutputFileName;
+
+  DataOffset                 = 0;
+  GuidAttr                   = 0;
+  ParsedLength               = 0;
+  ToolOutputLength           = 0;
+  UINameSize                 = 0;
+  NumberOfSections           = 0;
+  UncompressedLength         = 0;
+  CompressedLength           = 0;
+  CompressionType            = 0;
+  DstSize                    = 0;
+  ScratchSize                = 0;
+  Ptr                        = NULL;
+  ExtractionTool             = NULL;
+  ToolInputFile              = NULL;
+  ToolOutputFile             = NULL;
+  SystemCommand              = NULL;
+  SystemCommandFormatString  = NULL;
+  ToolOutputBuffer           = NULL;
+  UIName                     = NULL;
+  LocalEncapData             = NULL;
+  LocalEncapDataTemp         = NULL;
+  BlankChar                  = NULL;
+  UncompressedBuffer         = NULL;
+  CompressedBuffer           = NULL;
+  ScratchBuffer              = NULL;
+  TempDir                    = NULL;
+  ToolInputFileFullName      = NULL;
+  ToolOutputFileFullName     = NULL;
+  ToolInputFileName          = NULL;
+  ToolOutputFileFullName     = NULL;
+  HasDepexSection            = FALSE;
+  EncapDataNeedUpdata        = TRUE;
+  LargeHeaderOffset          = 0;
+
+
+  while (ParsedLength < BufferLength) {
+    Ptr           = SectionBuffer + ParsedLength;
+
+    SectionLength = GetLength (((EFI_COMMON_SECTION_HEADER *) Ptr)->Size);
+    Type          = ((EFI_COMMON_SECTION_HEADER *) Ptr)->Type;
+
+    //
+    // This is sort of an odd check, but is necessary because FFS files are
+    // padded to a QWORD boundary, meaning there is potentially a whole section
+    // header worth of 0xFF bytes.
+    //
+    if (SectionLength == 0xffffff && Type == 0xff) {
+      ParsedLength += 4;
+      continue;
+    }
+  //
+  //If Size is 0xFFFFFF then ExtendedSize contains the size of the section.
+  //
+    if (SectionLength == 0xffffff) {
+    SectionLength     = ((EFI_COMMON_SECTION_HEADER2 *) Ptr)->ExtendedSize;
+    LargeHeaderOffset = sizeof (EFI_COMMON_SECTION_HEADER2) - sizeof (EFI_COMMON_SECTION_HEADER);
+  }
+
+    switch (Type) {
+
+    case EFI_SECTION_FIRMWARE_VOLUME_IMAGE:
+
+      EncapDataNeedUpdata = TRUE;
+
+      Level ++;
+      NumberOfSections ++;
+
+      CurrentFv->FfsAttuibutes[*FfsCount].IsLeaf = FALSE;
+      CurrentFv->FfsAttuibutes[*FfsCount].IsFvStart = TRUE;
+      //
+      // Put in encapsulate data information.
+      //
+      LocalEncapData = *CurrentFvEncapData;
+      if (LocalEncapData->NextNode != NULL) {
+        LocalEncapData = LocalEncapData->NextNode;
+        while (LocalEncapData->RightNode != NULL) {
+          LocalEncapData = LocalEncapData->RightNode;
+        }
+      }
+
+      if (EncapDataNeedUpdata) {
+        //
+        // Put in this is an FFS with FV section
+        //
+
+        //
+        // Construct the new ENCAP_DATA
+        //
+        LocalEncapData->NextNode = (ENCAP_INFO_DATA *) malloc (sizeof (ENCAP_INFO_DATA));
+
+        if (LocalEncapData->NextNode == NULL) {
+          Error (NULL, 0, 4001, "Resource: Memory can't be allocated", NULL);
+          return EFI_ABORTED;
+        }
+
+        LocalEncapData        = LocalEncapData->NextNode;
+
+        LocalEncapData->Level = Level;
+        LocalEncapData->Type  = FMMT_ENCAP_TREE_FV_SECTION;
+
+        //
+        // We don't need additional data for encapsulate this FFS but type.
+        //
+        LocalEncapData->Data        = NULL;
+        LocalEncapData->FvExtHeader = NULL;
+        LocalEncapData->NextNode    = NULL;
+    LocalEncapData->RightNode = NULL;
+        LocalEncapData->Depex = NULL;
+        LocalEncapData->DepexLen = 0;
+        LocalEncapData->UiNameSize = 0;
+        LocalEncapData->FvId  = *FvCount;
+      }
+
+     //
+     //save parent level FFS file's GUID name
+     //
+     LocalEncapDataTemp = CurrentFv->EncapData;
+     while (LocalEncapDataTemp->NextNode != NULL) {
+         if (LocalEncapDataTemp->Level == FfsLevel) {
+           while (LocalEncapDataTemp->RightNode != NULL) {
+             LocalEncapDataTemp = LocalEncapDataTemp->RightNode;
+           }
+             if (LocalEncapDataTemp != NULL && LocalEncapDataTemp->FvExtHeader == NULL) {
+                 LocalEncapDataTemp->FvExtHeader = (EFI_FIRMWARE_VOLUME_EXT_HEADER *)malloc(sizeof(EFI_FIRMWARE_VOLUME_EXT_HEADER));
+                 if (LocalEncapDataTemp->FvExtHeader == NULL) {
+                     Error(NULL, 0, 4001, "Resource: Memory can't be allocated", NULL);
+                     return EFI_ABORTED;
+                 }
+
+                 if (*FfsCount >= 1) {
+                    if ((memcmp(&CurrentFv->FfsAttuibutes[*FfsCount - 1].GuidName, &(LocalEncapDataTemp->FvExtHeader->FvName), sizeof(EFI_GUID)) == 0)) {
+                        memcpy(LocalEncapDataTemp->UiName, CurrentFv->FfsAttuibutes[*FfsCount - 1].UiName, _MAX_PATH);
+                        LocalEncapDataTemp->UiNameSize = CurrentFv->FfsAttuibutes[*FfsCount - 1].UiNameSize;
+                        LocalEncapDataTemp->DepexLen = CurrentFv->FfsAttuibutes[*FfsCount - 1].DepexLen;
+                        LocalEncapDataTemp->Depex = malloc (LocalEncapDataTemp->DepexLen);
+                        if (LocalEncapDataTemp->Depex == NULL) {
+                            Error(NULL, 0, 4001, "Resource: Memory can't be allocated", NULL);
+                            return EFI_ABORTED;
+                        }
+                        memcpy(LocalEncapDataTemp->Depex, CurrentFv->FfsAttuibutes[*FfsCount - 1].Depex, LocalEncapDataTemp->DepexLen);
+                    }
+                 }
+             }
+             break;
+         }
+         LocalEncapDataTemp = LocalEncapDataTemp->NextNode;
+     }
+
+      Status = LibGetFvInfo ((UINT8*)((EFI_FIRMWARE_VOLUME_IMAGE_SECTION*)Ptr + 1) + LargeHeaderOffset, CurrentFv, FvName, Level, &LocalEncapData, FfsCount, FvCount, ViewFlag, TRUE);
+      if (EFI_ERROR (Status)) {
+        Error ("FMMT", 0, 0003, "printing of FV section contents failed", NULL);
+        return EFI_SECTION_ERROR;
+      }
+      if (*FfsCount >= 1) {
+        CurrentFv->FfsAttuibutes[*FfsCount -1].IsFvEnd = TRUE;
+      }
+      break;
+
+    case EFI_SECTION_COMPRESSION:
+      Level ++;
+      NumberOfSections ++;
+
+      EncapDataNeedUpdata = TRUE;
+      //
+      // Put in encapsulate data information.
+      //
+      LocalEncapData = *CurrentFvEncapData;
+      if (LocalEncapData->NextNode != NULL) {
+        EncapDataNeedUpdata = FALSE;
+        while (LocalEncapData->RightNode != NULL) {
+          LocalEncapData = LocalEncapData->RightNode;
+        }
+      }
+
+      if (EncapDataNeedUpdata) {
+        //
+        // Put in this is an FFS with FV section
+        //
+
+        //
+        // Construct the new ENCAP_DATA
+        //
+        LocalEncapData->NextNode = (ENCAP_INFO_DATA *) malloc (sizeof (ENCAP_INFO_DATA));
+
+        if (LocalEncapData->NextNode == NULL) {
+          Error (NULL, 0, 4001, "Resource: Memory can't be allocated", NULL);
+          return EFI_ABORTED;
+          }
+
+        LocalEncapData        = LocalEncapData->NextNode;
+
+        LocalEncapData->Level = Level;
+        LocalEncapData->Type  = FMMT_ENCAP_TREE_COMPRESS_SECTION;
+
+        //
+        // Store the compress type
+        //
+        LocalEncapData->Data     = malloc (sizeof (UINT8));
+
+        if (LocalEncapData->Data == NULL) {
+          Error ("FMMT", 0, 0003, "Allocate memory failed", NULL);
+          return EFI_OUT_OF_RESOURCES;
+        }
+
+        *(UINT8 *)LocalEncapData->Data     = ((EFI_COMPRESSION_SECTION *) (Ptr + LargeHeaderOffset))->CompressionType;
+        LocalEncapData->FvExtHeader = NULL;
+        LocalEncapData->NextNode = NULL;
+    LocalEncapData->RightNode = NULL;
+      } else {
+        LocalEncapData->RightNode = (ENCAP_INFO_DATA *) malloc (sizeof (ENCAP_INFO_DATA));
+        if (LocalEncapData->RightNode == NULL) {
+          Error (NULL, 0, 4001, "Resource: Memory can't be allocated", NULL);
+          return EFI_ABORTED;
+        }
+        LocalEncapData        = LocalEncapData->RightNode;
+
+        LocalEncapData->Level = Level;
+        LocalEncapData->Type  = FMMT_ENCAP_TREE_COMPRESS_SECTION;
+
+        //
+        // Store the compress type
+        //
+        LocalEncapData->Data     = malloc (sizeof (UINT8));
+
+        if (LocalEncapData->Data == NULL) {
+          Error ("FMMT", 0, 0003, "Allocate memory failed", NULL);
+          return EFI_OUT_OF_RESOURCES;
+        }
+
+        *(UINT8 *)LocalEncapData->Data     = ((EFI_COMPRESSION_SECTION *) (Ptr + LargeHeaderOffset))->CompressionType;
+        LocalEncapData->FvExtHeader = NULL;
+        LocalEncapData->NextNode = NULL;
+        LocalEncapData->RightNode = NULL;
+
+      }
+
+      //
+      // Process compressed section
+      //
+      CurrentFv->FfsAttuibutes[*FfsCount].IsLeaf = FALSE;
+
+      UncompressedBuffer  = NULL;
+      CompressedLength    = SectionLength - sizeof (EFI_COMPRESSION_SECTION) - LargeHeaderOffset;
+      UncompressedLength  = ((EFI_COMPRESSION_SECTION *) (Ptr + LargeHeaderOffset))->UncompressedLength;
+      CompressionType     = ((EFI_COMPRESSION_SECTION *) (Ptr + LargeHeaderOffset))->CompressionType;
+
+      if (CompressionType == EFI_NOT_COMPRESSED) {
+        //printf ("  Compression Type:  EFI_NOT_COMPRESSED\n");
+        if (CompressedLength != UncompressedLength) {
+          Error ("FMMT", 0, 0, "file is not compressed, but the compressed length does not match the uncompressed length", NULL);
+          return EFI_SECTION_ERROR;
+        }
+
+        UncompressedBuffer = Ptr + sizeof (EFI_COMPRESSION_SECTION) + LargeHeaderOffset;
+      } else if (CompressionType == EFI_STANDARD_COMPRESSION) {
+        GetInfoFunction     = EfiGetInfo;
+        DecompressFunction  = EfiDecompress;
+
+        CompressedBuffer  = Ptr + sizeof (EFI_COMPRESSION_SECTION) + LargeHeaderOffset;
+
+        Status            = GetInfoFunction (CompressedBuffer, CompressedLength, &DstSize, &ScratchSize);
+        if (EFI_ERROR (Status)) {
+          Error ("FMMT", 0, 0003, "error getting compression info from compression section", NULL);
+          return EFI_SECTION_ERROR;
+        }
+
+        if (DstSize != UncompressedLength) {
+          Error ("FMMT", 0, 0003, "compression error in the compression section", NULL);
+          return EFI_SECTION_ERROR;
+        }
+
+        ScratchBuffer       = malloc (ScratchSize);
+        if (ScratchBuffer == NULL) {
+          Error ("FMMT", 0, 0003, "Allocate memory failed", NULL);
+          return EFI_OUT_OF_RESOURCES;
+        }
+        UncompressedBuffer  = malloc (UncompressedLength);
+        if (UncompressedBuffer == NULL) {
+          Error ("FMMT", 0, 0003, "Allocate memory failed", NULL);
+          free (ScratchBuffer);
+          return EFI_OUT_OF_RESOURCES;
+        }
+        //
+        // Decompress the section.
+        //
+        Status = DecompressFunction (
+                  CompressedBuffer,
+                  CompressedLength,
+                  UncompressedBuffer,
+                  UncompressedLength,
+                  ScratchBuffer,
+                  ScratchSize
+                  );
+        free (ScratchBuffer);
+        if (EFI_ERROR (Status)) {
+          Error ("FMMT", 0, 0003, "decompress failed", NULL);
+          free (UncompressedBuffer);
+          return EFI_SECTION_ERROR;
+        }
+      } else {
+        Error ("FMMT", 0, 0003, "unrecognized compression type", "type 0x%X", CompressionType);
+        return EFI_SECTION_ERROR;
+      }
+
+      Status = LibParseSection (  UncompressedBuffer,
+                                  UncompressedLength,
+                                  CurrentFv,
+                                  FvName,
+                                  CurrentFile,
+                                  Level,
+                                  &LocalEncapData,
+                                  FfsLevel,
+                                  FfsCount,
+                                  FvCount,
+                                  ViewFlag,
+                                  ErasePolarity,
+                                  IsFfsGenerated);
+
+      if (CompressionType == EFI_STANDARD_COMPRESSION) {
+        //
+        // We need to deallocate Buffer
+        //
+        free (UncompressedBuffer);
+      }
+
+      if (EFI_ERROR (Status)) {
+        Error (NULL, 0, 0003, "failed to parse section", NULL);
+        return EFI_SECTION_ERROR;
+      }
+
+      break;
+
+    case EFI_SECTION_GUID_DEFINED:
+      //
+      // Process GUID defined
+      // looks up the appropriate tool to use for extracting
+      // a GUID defined FV section.
+      //
+      Level ++;
+      NumberOfSections++;
+      EncapDataNeedUpdata = TRUE;
+      //
+      // Put in encapsulate data information.
+      //
+      LocalEncapData = *CurrentFvEncapData;
+      if (LocalEncapData->NextNode != NULL) {
+        EncapDataNeedUpdata = FALSE;
+        while (LocalEncapData->RightNode != NULL) {
+          LocalEncapData = LocalEncapData->RightNode;
+        }
+      }
+      GuidAttr = ((EFI_GUID_DEFINED_SECTION *)(Ptr + LargeHeaderOffset))->Attributes;
+      DataOffset = ((EFI_GUID_DEFINED_SECTION *)(Ptr + LargeHeaderOffset))->DataOffset;
+
+      if ((ViewFlag) && ((GuidAttr & EFI_GUIDED_SECTION_PROCESSING_REQUIRED) == 0)) {
+        ToolOutputBuffer = Ptr + DataOffset;
+        ToolOutputLength = SectionLength - DataOffset;
+        Status = LibParseSection(
+                ToolOutputBuffer,
+                ToolOutputLength,
+                CurrentFv,
+                FvName,
+                CurrentFile,
+                Level,
+                &LocalEncapData,
+                FfsLevel,
+                FfsCount,
+                FvCount,
+                ViewFlag,
+                ErasePolarity,
+                IsFfsGenerated
+                );
+        if (EFI_ERROR(Status)) {
+          Error(NULL, 0, 0003, "parse of decoded GUIDED section failed", NULL);
+          return EFI_SECTION_ERROR;
+        }
+        break;
+      }
+
+      if (EncapDataNeedUpdata)  {
+
+        //
+        // Put in this is an FFS with FV section
+        //
+
+        //
+        // Construct the new ENCAP_DATA
+        //
+        LocalEncapData->NextNode = (ENCAP_INFO_DATA *) malloc (sizeof (ENCAP_INFO_DATA));
+
+        if (LocalEncapData->NextNode == NULL) {
+          Error (NULL, 0, 4001, "Resource: Memory can't be allocated", NULL);
+          return EFI_ABORTED;
+        }
+
+        LocalEncapData        = LocalEncapData->NextNode;
+
+        LocalEncapData->Level = Level;
+        LocalEncapData->Type  = FMMT_ENCAP_TREE_GUIDED_SECTION;
+        LocalEncapData->Depex = NULL;
+        LocalEncapData->DepexLen = 0;
+        LocalEncapData->UiNameSize = 0;
+        //
+        // We don't need additional data for encapsulate this FFS but type.
+        // include DataOffset + Attributes
+        //
+
+        LocalEncapData->Data     = (EFI_GUID *) malloc (sizeof (EFI_GUID) + 4);
+
+        if (LocalEncapData->Data == NULL) {
+          Error (NULL, 0, 4001, "Resource: Memory can't be allocated", NULL);
+          return EFI_ABORTED;
+        }
+
+        //
+        // include guid attribute and dataoffset
+        //
+        memcpy (LocalEncapData->Data, Ptr + LargeHeaderOffset + OFFSET_OF (EFI_GUID_DEFINED_SECTION, SectionDefinitionGuid), sizeof (EFI_GUID) + 4);
+
+        LocalEncapData->FvExtHeader = NULL;
+        LocalEncapData->NextNode = NULL;
+    LocalEncapData->RightNode = NULL;
+      } else {
+        LocalEncapData->RightNode = (ENCAP_INFO_DATA *) malloc (sizeof (ENCAP_INFO_DATA));
+        if (LocalEncapData->RightNode == NULL) {
+          Error (NULL, 0, 4001, "Resource: Memory can't be allocated", NULL);
+          return EFI_ABORTED;
+          }
+        LocalEncapData        = LocalEncapData->RightNode;
+        LocalEncapData->Level = Level;
+        LocalEncapData->Type  = FMMT_ENCAP_TREE_GUIDED_SECTION;
+        LocalEncapData->Depex = NULL;
+        LocalEncapData->DepexLen = 0;
+        LocalEncapData->UiNameSize = 0;
+        //
+        // We don't need additional data for encapsulate this FFS but type.
+        // include DataOffset + Attributes
+        //
+
+        LocalEncapData->Data     = (EFI_GUID *) malloc (sizeof (EFI_GUID) + 4);
+
+        if (LocalEncapData->Data == NULL) {
+          Error (NULL, 0, 4001, "Resource: Memory can't be allocated", NULL);
+          return EFI_ABORTED;
+        }
+
+        //
+        // include guid attribute and dataoffset
+        //
+        memcpy (LocalEncapData->Data, Ptr + LargeHeaderOffset + OFFSET_OF (EFI_GUID_DEFINED_SECTION, SectionDefinitionGuid), sizeof (EFI_GUID) + 4);
+
+        LocalEncapData->FvExtHeader = NULL;
+        LocalEncapData->NextNode = NULL;
+    LocalEncapData->RightNode = NULL;
+      }
+
+      CurrentFv->FfsAttuibutes[*FfsCount].IsLeaf = FALSE;
+
+      ExtractionTool =
+        LookupGuidedSectionToolPath (
+          mParsedGuidedSectionTools,
+          &((EFI_GUID_DEFINED_SECTION *) (Ptr + LargeHeaderOffset))->SectionDefinitionGuid
+          );
+
+      if (ExtractionTool != NULL && ((GuidAttr & EFI_GUIDED_SECTION_PROCESSING_REQUIRED) != 0)) {
+
+        TempDir = getcwd (NULL, _MAX_PATH);
+        if (strlen (TempDir) + strlen(OS_SEP_STR) + strlen (TEMP_DIR_NAME) > _MAX_PATH - 1) {
+          Error("FMMT", 0, 1001, "The directory is too long.", "");
+          free (ExtractionTool);
+          return EFI_SECTION_ERROR;
+        }
+        strncat (TempDir, OS_SEP_STR, _MAX_PATH - strlen(TempDir) - 1);
+        strncat (TempDir, TEMP_DIR_NAME, _MAX_PATH - strlen(TempDir) - 1);
+        mkdir(TempDir, S_IRWXU | S_IRWXG | S_IRWXO);
+        ToolInputFile  = GenTempFile ();
+        if (ToolInputFile == NULL) {
+          Error (NULL, 0, 4001, "Resource: Memory can't be allocated", NULL);
+          free (ExtractionTool);
+          return EFI_OUT_OF_RESOURCES;
+        }
+        ToolOutputFile = GenTempFile ();
+        if (ToolOutputFile == NULL) {
+          free (ToolInputFile);
+          Error (NULL, 0, 4001, "Resource: Memory can't be allocated", NULL);
+          free (ExtractionTool);
+          return EFI_OUT_OF_RESOURCES;
+        }
+        ToolInputFileName = strrchr(ToolInputFile, OS_SEP);
+        if (ToolInputFileName == NULL) {
+          free (ToolInputFile);
+          free (ToolOutputFile);
+          free (ExtractionTool);
+          return EFI_ABORTED;
+        }
+        ToolOutputFileName = strrchr(ToolOutputFile, OS_SEP);
+        if (ToolOutputFileName == NULL) {
+          free (ToolInputFile);
+          free (ToolOutputFile);
+          free (ExtractionTool);
+          return EFI_ABORTED;
+        }
+
+        ToolInputFileFullName   = malloc (strlen("%s%s") + strlen(TempDir) + strlen(ToolInputFileName) + 1);
+        if (ToolInputFileFullName == NULL) {
+          free (ToolInputFile);
+          free (ToolOutputFile);
+          free (ExtractionTool);
+          Error ("FMMT", 0, 0003, "Allocate memory failed", NULL);
+          return EFI_OUT_OF_RESOURCES;
+        }
+        ToolOutputFileFullName  = malloc (strlen("%s%s") + strlen(TempDir) + strlen(ToolOutputFileName) + 1);
+
+        if (ToolOutputFileFullName == NULL) {
+          free (ToolInputFile);
+          free (ToolOutputFile);
+          free (ToolInputFileFullName);
+          free (ExtractionTool);
+          Error (NULL, 0, 4001, "Resource: Memory can't be allocated", NULL);
+          return EFI_OUT_OF_RESOURCES;
+        }
+
+        sprintf (ToolInputFileFullName, "%s%s", TempDir, ToolInputFileName);
+        sprintf (ToolOutputFileFullName, "%s%s", TempDir, ToolOutputFileName);
+
+        //
+        // Construction 'system' command string
+        //
+        SystemCommandFormatString = "%s -d -o \"%s\" \"%s\"";
+        SystemCommand = malloc (
+          strlen (SystemCommandFormatString) +
+          strlen (ExtractionTool) +
+          strlen (ToolInputFileFullName) +
+          strlen (ToolOutputFileFullName) +
+          1
+          );
+        if (SystemCommand == NULL) {
+          free (ToolInputFile);
+          free (ToolOutputFile);
+          free (ToolInputFileFullName);
+          free (ToolOutputFileFullName);
+          free (ExtractionTool);
+          return EFI_ABORTED;
+        }
+        sprintf (
+          SystemCommand,
+          "%s -d -o \"%s\" \"%s\"",
+          ExtractionTool,
+          ToolOutputFileFullName,
+          ToolInputFileFullName
+          );
+        free (ExtractionTool);
+        ExtractionTool = NULL;
+
+        Status = PutFileImage (
+        ToolInputFileFullName,
+        (CHAR8*) Ptr + ((EFI_GUID_DEFINED_SECTION *) (Ptr + LargeHeaderOffset))->DataOffset,
+        SectionLength - ((EFI_GUID_DEFINED_SECTION *) (Ptr + LargeHeaderOffset))->DataOffset
+        );
+
+        if (HasDepexSection) {
+          HasDepexSection = FALSE;
+        }
+
+        if (EFI_ERROR (Status)) {
+          Error ("FMMT", 0, 0004, "unable to decoded GUIDED section", NULL);
+          free (SystemCommand);
+          free (ToolInputFile);
+          free (ToolOutputFile);
+          free (ToolOutputFileFullName);
+          remove (ToolInputFileFullName);
+          free (ToolInputFileFullName);
+          return EFI_SECTION_ERROR;
+        }
+
+        if (system (SystemCommand) != EFI_SUCCESS) {
+          printf("Command failed: %s\n", SystemCommand);
+          free (SystemCommand);
+          free (ToolInputFile);
+          free (ToolOutputFile);
+          free (ToolOutputFileFullName);
+          remove (ToolInputFileFullName);
+          free (ToolInputFileFullName);
+          return EFI_ABORTED;
+        }
+        free (SystemCommand);
+        remove (ToolInputFileFullName);
+        free (ToolInputFile);
+        free (ToolInputFileFullName);
+        ToolInputFile = NULL;
+        ToolInputFileFullName = NULL;
+
+
+        Status = GetFileImage (
+                   ToolOutputFileFullName,
+                   (CHAR8 **)&ToolOutputBuffer,
+                   &ToolOutputLength
+                   );
+        remove (ToolOutputFileFullName);
+        free (ToolOutputFile);
+        free (ToolOutputFileFullName);
+        ToolOutputFile = NULL;
+        ToolOutputFileFullName = NULL;
+
+        if (EFI_ERROR (Status)) {
+          Error ("FMMT", 0, 0004, "unable to read decoded GUIDED section", NULL);
+          return EFI_SECTION_ERROR;
+        }
+
+        Status = LibParseSection (
+                  ToolOutputBuffer,
+                  ToolOutputLength,
+                  CurrentFv,
+                  FvName,
+                  CurrentFile,
+                  Level,
+                  &LocalEncapData,
+                  FfsLevel,
+                  FfsCount,
+                  FvCount,
+                  ViewFlag,
+                  ErasePolarity,
+                  IsFfsGenerated
+                  );
+        if (EFI_ERROR (Status)) {
+          Error (NULL, 0, 0003, "parse of decoded GUIDED section failed", NULL);
+          return EFI_SECTION_ERROR;
+        }
+      } else if ((GuidAttr & EFI_GUIDED_SECTION_PROCESSING_REQUIRED) == 0){
+          Status = LibParseSection (
+            Ptr + ((EFI_GUID_DEFINED_SECTION *) (Ptr + LargeHeaderOffset))->DataOffset,
+            SectionLength - ((EFI_GUID_DEFINED_SECTION *) (Ptr + LargeHeaderOffset))->DataOffset,
+            CurrentFv,
+            FvName,
+            CurrentFile,
+            Level,
+            &LocalEncapData,
+            FfsLevel,
+            FfsCount,
+            FvCount,
+            ViewFlag,
+            ErasePolarity,
+            IsFfsGenerated
+            );
+          if (ExtractionTool != NULL) {
+            free (ExtractionTool);
+            ExtractionTool = NULL;
+          }
+          if (EFI_ERROR (Status)) {
+            Error (NULL, 0, 0003, "parse of decoded GUIDED section failed", NULL);
+            return EFI_SECTION_ERROR;
+          }
+      }else {
+        //
+        // We don't know how to parse it now.
+        //
+        if (ExtractionTool != NULL) {
+          free (ExtractionTool);
+          ExtractionTool = NULL;
+        }
+        Error ("FMMT", 0, 0003, "Error parsing section", \
+                              "EFI_SECTION_GUID_DEFINED cannot be parsed at this time. Tool to decode this section should have been defined in %s file.", mGuidToolDefinition);
+        printf("  Its GUID is: ");
+        PrintGuid(&(((EFI_GUID_DEFINED_SECTION *)(Ptr + LargeHeaderOffset))->SectionDefinitionGuid));
+        return EFI_UNSUPPORTED;
+      }
+      break;
+
+    //
+    //Leaf sections
+    //
+    case EFI_SECTION_RAW:
+      NumberOfSections ++;
+      CurrentFv->FfsAttuibutes[*FfsCount].Level = Level;
+      if (!ViewFlag) {
+        if (!*IsFfsGenerated) {
+          LibGenFfsFile(CurrentFile, CurrentFv, FvName, Level, FfsCount, ErasePolarity);
+          *IsFfsGenerated = TRUE;
+        }
+      }
+
+      break;
+    case EFI_SECTION_PE32:
+      NumberOfSections ++;
+      CurrentFv->FfsAttuibutes[*FfsCount].Level = Level;
+      if (!ViewFlag) {
+        if (!*IsFfsGenerated) {
+          LibGenFfsFile(CurrentFile, CurrentFv, FvName, Level, FfsCount, ErasePolarity);
+          *IsFfsGenerated = TRUE;
+        }
+      }
+
+      break;
+    case EFI_SECTION_PIC:
+      NumberOfSections ++;
+      CurrentFv->FfsAttuibutes[*FfsCount].Level = Level;
+      if (!ViewFlag) {
+        if (!*IsFfsGenerated) {
+          LibGenFfsFile(CurrentFile, CurrentFv, FvName, Level, FfsCount, ErasePolarity);
+          *IsFfsGenerated = TRUE;
+        }
+      }
+
+      break;
+    case EFI_SECTION_TE:
+      NumberOfSections ++;
+      CurrentFv->FfsAttuibutes[*FfsCount].Level = Level;
+      if (!ViewFlag) {
+        if (!*IsFfsGenerated) {
+          LibGenFfsFile(CurrentFile, CurrentFv, FvName, Level, FfsCount, ErasePolarity);
+          *IsFfsGenerated = TRUE;
+        }
+      }
+      break;
+
+    case EFI_SECTION_COMPATIBILITY16:
+      NumberOfSections ++;
+      CurrentFv->FfsAttuibutes[*FfsCount].Level = Level;
+      if (!ViewFlag) {
+        if (!*IsFfsGenerated) {
+          LibGenFfsFile(CurrentFile, CurrentFv, FvName, Level, FfsCount, ErasePolarity);
+          *IsFfsGenerated = TRUE;
+        }
+      }
+      break;
+
+    case EFI_SECTION_FREEFORM_SUBTYPE_GUID:
+      NumberOfSections ++;
+      CurrentFv->FfsAttuibutes[*FfsCount].Level = Level;
+      if (!ViewFlag) {
+        if (!*IsFfsGenerated) {
+          LibGenFfsFile(CurrentFile, CurrentFv, FvName, Level, FfsCount, ErasePolarity);
+          *IsFfsGenerated = TRUE;
+        }
+      }
+      break;
+
+    case EFI_SECTION_VERSION:
+      NumberOfSections ++;
+      CurrentFv->FfsAttuibutes[*FfsCount].Level = Level;
+      break;
+    case EFI_SECTION_PEI_DEPEX:
+      NumberOfSections ++;
+      CurrentFv->FfsAttuibutes[*FfsCount].Level = Level;
+      HasDepexSection = TRUE;
+      CurrentFv->FfsAttuibutes[*FfsCount].Depex = malloc (SectionLength);
+      memcpy(CurrentFv->FfsAttuibutes[*FfsCount].Depex, Ptr, SectionLength);
+      CurrentFv->FfsAttuibutes[*FfsCount].DepexLen = SectionLength;
+      break;
+    case EFI_SECTION_DXE_DEPEX:
+      NumberOfSections ++;
+      CurrentFv->FfsAttuibutes[*FfsCount].Level = Level;
+      HasDepexSection = TRUE;
+      CurrentFv->FfsAttuibutes[*FfsCount].Depex = malloc (SectionLength);
+      memcpy(CurrentFv->FfsAttuibutes[*FfsCount].Depex, Ptr, SectionLength);
+      CurrentFv->FfsAttuibutes[*FfsCount].DepexLen = SectionLength;
+      break;
+    case EFI_SECTION_SMM_DEPEX:
+      NumberOfSections ++;
+      CurrentFv->FfsAttuibutes[*FfsCount].Level = Level;
+      HasDepexSection = TRUE;
+      CurrentFv->FfsAttuibutes[*FfsCount].Depex = malloc (SectionLength);
+      memcpy(CurrentFv->FfsAttuibutes[*FfsCount].Depex, Ptr, SectionLength);
+      CurrentFv->FfsAttuibutes[*FfsCount].DepexLen = SectionLength;
+      break;
+
+    case EFI_SECTION_USER_INTERFACE:
+      NumberOfSections ++;
+      CurrentFv->FfsAttuibutes[*FfsCount].Level = Level;
+
+      UiSectionLength = GetLength (((EFI_USER_INTERFACE_SECTION *) Ptr)->CommonHeader.Size);
+    if (UiSectionLength == 0xffffff) {
+      UiSectionLength   = ((EFI_USER_INTERFACE_SECTION2 *) Ptr)->CommonHeader.ExtendedSize;
+    UINameSize        = UiSectionLength - sizeof(EFI_COMMON_SECTION_HEADER2);
+    } else {
+      UINameSize = UiSectionLength - sizeof(EFI_COMMON_SECTION_HEADER);
+    }
+
+      UIName     = (CHAR16 *) malloc (UINameSize + 2);
+      if (UIName != NULL) {
+        memset (UIName, '\0', UINameSize + 2);
+        if (UiSectionLength >= 0xffffff) {
+          memcpy(UIName, ((EFI_USER_INTERFACE_SECTION2 *) Ptr)->FileNameString, UINameSize);
+        } else {
+          memcpy(UIName, ((EFI_USER_INTERFACE_SECTION *) Ptr)->FileNameString, UINameSize);
+        }
+      } else {
+        Error ("FMMT", 0, 0001, "Memory allocate error!", NULL);
+        return EFI_OUT_OF_RESOURCES;
+      }
+
+      BlankChar = LibConstructBlankChar( CurrentFv->FvLevel * 2);
+      if (BlankChar == NULL) {
+        free(UIName);
+        return EFI_OUT_OF_RESOURCES;
+      }
+
+      if (ViewFlag) {
+        UIFileName = malloc (UINameSize + 2);
+        if (UIFileName == NULL) {
+          Error ("FMMT", 0, 4001, "Memory allocation fail!", NULL);
+          free (UIName);
+          free (BlankChar);
+          return EFI_OUT_OF_RESOURCES;
+        }
+        Unicode2AsciiString (UIName, UIFileName);
+        fprintf(stdout, "%sFile \"%s\"\n", BlankChar, UIFileName);
+        free(UIFileName);
+      }
+      free (BlankChar);
+
+      //
+      // If Ffs file has been generated, then the FfsCount should decrease 1.
+      //
+      if (*IsFfsGenerated) {
+        memcpy (CurrentFv->FfsAttuibutes[*FfsCount -1].UiName, UIName, UINameSize);
+        CurrentFv->FfsAttuibutes[*FfsCount -1].UiNameSize = UINameSize;
+      } else {
+        memcpy (CurrentFv->FfsAttuibutes[*FfsCount].UiName, UIName, UINameSize);
+        CurrentFv->FfsAttuibutes[*FfsCount].UiNameSize = UINameSize;
+      }
+
+      HasDepexSection = FALSE;
+    free(UIName);
+    UINameSize = 0;
+
+      break;
+    default:
+      break;
+    }
+
+    ParsedLength += SectionLength;
+    //
+    // We make then next section begin on a 4-byte boundary
+    //
+    ParsedLength = GetOccupiedSize (ParsedLength, 4);
+  }
+
+  if (ParsedLength < BufferLength) {
+    Error ("FMMT", 0, 0003, "sections do not completely fill the sectioned buffer being parsed", NULL);
+    return EFI_SECTION_ERROR;
+  }
+
+
+  return EFI_SUCCESS;
+}
+
+/**
+
+  Iterates through the files contained within the firmware volume
+
+  @param[in]    Fv  - Address of the Fv in memory
+  @param[in]    Key - Should be 0 to get the first file.  After that, it should be
+                      passed back in without modifying it's contents to retrieve
+                      subsequent files.
+  @param[in]    File- Output file pointer
+                      File == NULL - invalid parameter
+                      otherwise - *File will be update to the location of the file
+
+  @return       EFI_STATUS
+                EFI_NOT_FOUND
+                EFI_VOLUME_CORRUPTED
+
+**/
+EFI_STATUS
+FvBufFindNextFile (
+  IN     VOID      *Fv,
+  IN OUT UINTN     *Key,
+  OUT    VOID      **File
+  )
+{
+  EFI_FIRMWARE_VOLUME_HEADER *hdr;
+  EFI_FFS_FILE_HEADER        *fhdr;
+  EFI_FIRMWARE_VOLUME_EXT_HEADER  *FwVolExtHeader;
+  EFI_FVB_ATTRIBUTES_2       FvbAttributes;
+  UINTN                      fsize;
+  EFI_STATUS                 Status;
+  UINTN                      fvSize;
+
+  hdr = (EFI_FIRMWARE_VOLUME_HEADER*)Fv;
+  fhdr = NULL;
+
+  if (Fv == NULL) {
+    return EFI_INVALID_PARAMETER;
+  }
+
+  Status = FvBufGetSize (Fv, &fvSize);
+  if (EFI_ERROR (Status)) {
+    return Status;
+  }
+
+  if (*Key == 0) {
+    if (hdr->ExtHeaderOffset != 0) {
+      //
+      // Searching for files starts on an 8 byte aligned boundary after the end of the Extended Header if it exists.
+      //
+      FwVolExtHeader = (EFI_FIRMWARE_VOLUME_EXT_HEADER *)((UINT8 *)hdr + hdr->ExtHeaderOffset);
+      *Key = (UINTN)hdr->ExtHeaderOffset + FwVolExtHeader->ExtHeaderSize;
+      *Key = (UINTN)ALIGN_POINTER(*Key, 8);
+    } else {
+      *Key = hdr->HeaderLength;
+    }
+  }
+
+  FvbAttributes = hdr->Attributes;
+
+  for(
+      *Key = (UINTN)ALIGN_POINTER (*Key, 8);
+      (*Key + sizeof (*fhdr)) < fvSize;
+      *Key = (UINTN)ALIGN_POINTER (*Key, 8)
+    ) {
+    fhdr = (EFI_FFS_FILE_HEADER*) ((UINT8*)hdr + *Key);
+    fsize = GetFfsFileLength (fhdr);
+    if (!EFI_TEST_FFS_ATTRIBUTES_BIT(
+          FvbAttributes,
+          fhdr->State,
+          EFI_FILE_HEADER_VALID
+        ) ||
+        EFI_TEST_FFS_ATTRIBUTES_BIT(
+          FvbAttributes,
+          fhdr->State,
+          EFI_FILE_HEADER_INVALID
+        )
+      ) {
+      *Key = *Key + 1;
+      continue;
+    } else if(
+        EFI_TEST_FFS_ATTRIBUTES_BIT(
+          FvbAttributes,
+          fhdr->State,
+          EFI_FILE_MARKED_FOR_UPDATE
+        ) ||
+        EFI_TEST_FFS_ATTRIBUTES_BIT(
+          FvbAttributes,
+          fhdr->State,
+          EFI_FILE_DELETED
+        )
+      ) {
+      *Key = *Key + fsize;
+      continue;
+    } else if (EFI_TEST_FFS_ATTRIBUTES_BIT(
+          FvbAttributes,
+          fhdr->State,
+          EFI_FILE_DATA_VALID
+        )
+      ) {
+      *File = (UINT8*)hdr + *Key;
+      *Key = *Key + fsize;
+      return EFI_SUCCESS;
+    }
+
+    *Key = *Key + 1;
+  }
+
+  return EFI_NOT_FOUND;
+}
+
+/**
+
+  TODO: Add function description
+
+  FvImage       - TODO: add argument description
+  FileHeader    - TODO: add argument description
+  ErasePolarity - TODO: add argument description
+
+  EFI_SUCCESS - TODO: Add description for return value
+  EFI_ABORTED - TODO: Add description for return value
+
+**/
+EFI_STATUS
+LibGetFileInfo (
+  EFI_FIRMWARE_VOLUME_HEADER  *FvImage,
+  EFI_FFS_FILE_HEADER2        *CurrentFile,
+  BOOLEAN                     ErasePolarity,
+  FV_INFORMATION              *CurrentFv,
+  CHAR8                       *FvName,
+  UINT8                       Level,
+  ENCAP_INFO_DATA             **CurrentFvEncapData,
+  UINT32                      *FfsCount,
+  UINT8                       *FvCount,
+  BOOLEAN                     ViewFlag
+  )
+{
+  UINT32              FileLength;
+  UINT8               FileState;
+  UINT8               Checksum;
+  EFI_FFS_FILE_HEADER2 BlankHeader;
+  EFI_STATUS          Status;
+  UINT8               GuidBuffer[PRINTED_GUID_BUFFER_SIZE];
+  ENCAP_INFO_DATA     *LocalEncapData;
+  BOOLEAN             EncapDataNeedUpdateFlag;
+  BOOLEAN             IsGeneratedFfs;
+  UINT32              FfsFileHeaderSize;
+
+  Status = EFI_SUCCESS;
+
+  LocalEncapData  = NULL;
+  EncapDataNeedUpdateFlag = TRUE;
+  IsGeneratedFfs   = FALSE;
+
+  FfsFileHeaderSize = GetFfsHeaderLength  ((EFI_FFS_FILE_HEADER *) CurrentFile);
+  FileLength        = GetFfsFileLength ((EFI_FFS_FILE_HEADER *) CurrentFile);
+
+  //
+  // Check if we have free space
+  //
+  if (ErasePolarity) {
+    memset (&BlankHeader, -1, FfsFileHeaderSize);
+  } else {
+    memset (&BlankHeader, 0, FfsFileHeaderSize);
+  }
+
+  //
+  // Is this FV blank?
+  //
+  if (memcmp (&BlankHeader, CurrentFile, FfsFileHeaderSize) == 0) {
+    return EFI_SUCCESS;
+  }
+
+  //
+  // Print file information.
+  //
+  FileState = GetFileState (ErasePolarity, (EFI_FFS_FILE_HEADER *)CurrentFile);
+  PrintGuidToBuffer (&(CurrentFile->Name), GuidBuffer, PRINTED_GUID_BUFFER_SIZE, FALSE);
+  if (FileState == EFI_FILE_DATA_VALID) {
+    //
+    // Calculate header checksum
+    //
+    Checksum  = CalculateSum8 ((UINT8 *) CurrentFile, FfsFileHeaderSize);
+    Checksum  = (UINT8) (Checksum - CurrentFile->IntegrityCheck.Checksum.File);
+    Checksum  = (UINT8) (Checksum - CurrentFile->State);
+    if (Checksum != 0) {
+      Error ("FMMT", 0, 0003, "error parsing FFS file", "FFS file with Guid %s has invalid header checksum", GuidBuffer);
+      return EFI_ABORTED;
+    }
+
+    if (CurrentFile->Attributes & FFS_ATTRIB_CHECKSUM) {
+      //
+      // Calculate file checksum
+      //
+      Checksum  = CalculateSum8 ((UINT8 *) ((UINTN)CurrentFile + FfsFileHeaderSize), FileLength - FfsFileHeaderSize);
+      Checksum  = Checksum + CurrentFile->IntegrityCheck.Checksum.File;
+      if (Checksum != 0) {
+        Error ("FMMT", 0, 0003, "error parsing FFS file", "FFS file with Guid %s has invalid file checksum", GuidBuffer);
+        return EFI_ABORTED;
+      }
+    } else {
+      if (CurrentFile->IntegrityCheck.Checksum.File != FFS_FIXED_CHECKSUM) {
+        Error ("FMMT", 0, 0003, "error parsing FFS file", "FFS file with Guid %s has invalid header checksum -- not set to fixed value of 0xAA", GuidBuffer);
+        return EFI_ABORTED;
+      }
+    }
+  } else {
+    Error ("FMMT", 0, 0003, "error parsing FFS file", "FFS file with Guid %s has the invalid/unrecognized file state bits", GuidBuffer);
+    return EFI_ABORTED;
+  }
+
+  Level += 1;
+
+  if ((CurrentFile->Type != EFI_FV_FILETYPE_ALL) && (CurrentFile->Type != EFI_FV_FILETYPE_FFS_PAD)) {
+
+    //
+    // Put in encapsulate data information.
+    //
+    LocalEncapData = *CurrentFvEncapData;
+    if (LocalEncapData->NextNode != NULL) {
+      LocalEncapData = LocalEncapData->NextNode;
+      EncapDataNeedUpdateFlag = FALSE;
+      while (LocalEncapData->RightNode != NULL) {
+        LocalEncapData = LocalEncapData->RightNode;
+      }
+    }
+
+    if (EncapDataNeedUpdateFlag) {
+      //
+      // Construct the new ENCAP_DATA
+      //
+      LocalEncapData->NextNode = (ENCAP_INFO_DATA *) malloc (sizeof (ENCAP_INFO_DATA));
+
+      if (LocalEncapData->NextNode == NULL) {
+        Error (NULL, 0, 4001, "Resource: Memory can't be allocated", NULL);
+        return EFI_ABORTED;
+      }
+
+      LocalEncapData        = LocalEncapData->NextNode;
+
+      LocalEncapData->Level = Level;
+      LocalEncapData->Type  = FMMT_ENCAP_TREE_FFS;
+      LocalEncapData->FvExtHeader = NULL;
+      LocalEncapData->Depex = NULL;
+      LocalEncapData->DepexLen = 0;
+      LocalEncapData->UiNameSize = 0;
+      //
+      // Store the header of FFS file.
+      //
+      LocalEncapData->Data     = malloc (FfsFileHeaderSize);
+      if (LocalEncapData->Data == NULL) {
+        Error (NULL, 0, 4001, "Resource: Memory can't be allocated", NULL);
+        return EFI_ABORTED;
+      }
+
+      memcpy (LocalEncapData->Data, CurrentFile, FfsFileHeaderSize);
+      LocalEncapData->FvExtHeader = (EFI_FIRMWARE_VOLUME_EXT_HEADER *)malloc(sizeof(EFI_FIRMWARE_VOLUME_EXT_HEADER));
+      if (LocalEncapData->FvExtHeader == NULL) {
+        Error(NULL, 0, 4001, "Resource: Memory can't be allocated", NULL);
+        return EFI_ABORTED;
+        }
+      LocalEncapData->FvExtHeader->FvName.Data1 = CurrentFile->Name.Data1;
+      LocalEncapData->FvExtHeader->FvName.Data2 = CurrentFile->Name.Data2;
+      LocalEncapData->FvExtHeader->FvName.Data3 = CurrentFile->Name.Data3;
+      LocalEncapData->FvExtHeader->FvName.Data4[0] = CurrentFile->Name.Data4[0];
+      LocalEncapData->FvExtHeader->FvName.Data4[1] = CurrentFile->Name.Data4[1];
+      LocalEncapData->FvExtHeader->FvName.Data4[2] = CurrentFile->Name.Data4[2];
+      LocalEncapData->FvExtHeader->FvName.Data4[3] = CurrentFile->Name.Data4[3];
+      LocalEncapData->FvExtHeader->FvName.Data4[4] = CurrentFile->Name.Data4[4];
+      LocalEncapData->FvExtHeader->FvName.Data4[5] = CurrentFile->Name.Data4[5];
+      LocalEncapData->FvExtHeader->FvName.Data4[6] = CurrentFile->Name.Data4[6];
+      LocalEncapData->FvExtHeader->FvName.Data4[7] = CurrentFile->Name.Data4[7];
+      LocalEncapData->NextNode = NULL;
+    LocalEncapData->RightNode = NULL;
+    }else{
+      //
+      // Construct the new ENCAP_DATA
+      //
+      LocalEncapData->RightNode = (ENCAP_INFO_DATA *) malloc (sizeof (ENCAP_INFO_DATA));
+
+      if (LocalEncapData->RightNode == NULL) {
+        Error (NULL, 0, 4001, "Resource: Memory can't be allocated", NULL);
+        return EFI_ABORTED;
+      }
+
+      LocalEncapData        = LocalEncapData->RightNode;
+
+      LocalEncapData->Level = Level;
+      LocalEncapData->Type  = FMMT_ENCAP_TREE_FFS;
+    LocalEncapData->FvExtHeader = NULL;
+      LocalEncapData->Depex = NULL;
+      LocalEncapData->DepexLen = 0;
+      LocalEncapData->UiNameSize = 0;
+      //
+      // Store the header of FFS file.
+      //
+      LocalEncapData->Data     = malloc (FfsFileHeaderSize);
+      if (LocalEncapData->Data == NULL) {
+        Error (NULL, 0, 4001, "Resource: Memory can't be allocated", NULL);
+        return EFI_ABORTED;
+      }
+
+      memcpy (LocalEncapData->Data, CurrentFile, FfsFileHeaderSize);
+      LocalEncapData->FvExtHeader = (EFI_FIRMWARE_VOLUME_EXT_HEADER *)malloc(sizeof(EFI_FIRMWARE_VOLUME_EXT_HEADER));
+      if (LocalEncapData->FvExtHeader == NULL) {
+        Error(NULL, 0, 4001, "Resource: Memory can't be allocated", NULL);
+        return EFI_ABORTED;
+      }
+      LocalEncapData->FvExtHeader->FvName.Data1 = CurrentFile->Name.Data1;
+      LocalEncapData->FvExtHeader->FvName.Data2 = CurrentFile->Name.Data2;
+      LocalEncapData->FvExtHeader->FvName.Data3 = CurrentFile->Name.Data3;
+      LocalEncapData->FvExtHeader->FvName.Data4[0] = CurrentFile->Name.Data4[0];
+      LocalEncapData->FvExtHeader->FvName.Data4[1] = CurrentFile->Name.Data4[1];
+      LocalEncapData->FvExtHeader->FvName.Data4[2] = CurrentFile->Name.Data4[2];
+      LocalEncapData->FvExtHeader->FvName.Data4[3] = CurrentFile->Name.Data4[3];
+      LocalEncapData->FvExtHeader->FvName.Data4[4] = CurrentFile->Name.Data4[4];
+      LocalEncapData->FvExtHeader->FvName.Data4[5] = CurrentFile->Name.Data4[5];
+      LocalEncapData->FvExtHeader->FvName.Data4[6] = CurrentFile->Name.Data4[6];
+      LocalEncapData->FvExtHeader->FvName.Data4[7] = CurrentFile->Name.Data4[7];
+      LocalEncapData->RightNode = NULL;
+      LocalEncapData->NextNode = NULL;
+    }
+
+   if ( CurrentFile->Type == EFI_FV_FILETYPE_RAW){
+      CurrentFv->FfsAttuibutes[*FfsCount].Level = Level;
+      if (!ViewFlag){
+        LibGenFfsFile(CurrentFile, CurrentFv, FvName, Level, FfsCount, ErasePolarity);
+      }
+    } else if( CurrentFile->Type == EFI_FV_FILETYPE_FFS_PAD){
+      //EFI_FV_FILETYPE_FFS_PAD
+    } else {
+    //
+    // All other files have sections
+    //
+    Status = LibParseSection (
+      (UINT8 *) ((UINTN) CurrentFile + FfsFileHeaderSize),
+      FileLength - FfsFileHeaderSize,
+      CurrentFv,
+      FvName,
+      CurrentFile,
+      Level,
+      &LocalEncapData,
+      Level,
+      FfsCount,
+      FvCount,
+      ViewFlag,
+      ErasePolarity,
+      &IsGeneratedFfs
+      );
+    }
+    if (EFI_ERROR (Status)) {
+      printf ("ERROR: Parsing the FFS file.\n");
+      return Status;
+    }
+  }
+
+
+  return EFI_SUCCESS;
+}
+
+/**
+
+  Get firmware information. Including the FV headers,
+
+  @param[in]    Fv            - Firmware Volume to get information from
+
+  @return       EFI_STATUS
+
+**/
+EFI_STATUS
+LibGetFvInfo (
+  IN     VOID                         *Fv,
+  IN OUT FV_INFORMATION               *CurrentFv,
+  IN     CHAR8                        *FvName,
+  IN     UINT8                        Level,
+  IN     ENCAP_INFO_DATA              **CurrentFvEncapData,
+  IN     UINT32                       *FfsCount,
+  IN OUT UINT8                        *FvCount,
+  IN     BOOLEAN                      ViewFlag,
+  IN     BOOLEAN                      IsChildFv
+  )
+{
+  EFI_STATUS                  Status;
+  UINTN                       NumberOfFiles;
+  BOOLEAN                     ErasePolarity;
+  UINTN                       FvSize;
+  EFI_FFS_FILE_HEADER2        *CurrentFile;
+  UINTN                       Key;
+  ENCAP_INFO_DATA             *LocalEncapData;
+  EFI_FIRMWARE_VOLUME_EXT_HEADER *ExtHdrPtr;
+  EFI_FIRMWARE_VOLUME_HEADER *FvHdr;
+
+  NumberOfFiles  = 0;
+  Key            = 0;
+  LocalEncapData = NULL;
+  CurrentFile    = NULL;
+  FvHdr = (EFI_FIRMWARE_VOLUME_HEADER *)Fv;
+
+
+  Level += 1;
+  *FvCount += 1;
+  CurrentFv->FvLevel += 1;
+
+  Status = FvBufGetSize (Fv, &FvSize);
+
+  ErasePolarity = (((EFI_FIRMWARE_VOLUME_HEADER*)Fv)->Attributes & EFI_FVB2_ERASE_POLARITY) ? TRUE : FALSE;
+
+  Status = LibReadFvHeader (Fv, ViewFlag, CurrentFv->FvLevel, *FvCount - 1, CurrentFv->FvName);
+  if (EFI_ERROR (Status)) {
+    Error (NULL, 0, 0003, "error parsing FV image", "Header is invalid");
+    return EFI_ABORTED;
+  }
+
+  if (!IsChildFv) {
+    //
+    // Write FV header information into CurrentFv struct.
+    //
+    CurrentFv->FvHeader = (EFI_FIRMWARE_VOLUME_HEADER *) malloc (FvHdr->HeaderLength);
+
+    if (CurrentFv->FvHeader == NULL) {
+      Error (NULL, 0, 4001, "Resource: Memory can't be allocated", NULL);
+      return EFI_ABORTED;
+    }
+
+    //
+    // Get the FV Header information
+    //
+    memcpy(CurrentFv->FvHeader, Fv, FvHdr->HeaderLength);
+    CurrentFv->FvExtHeader = NULL;
+    CurrentFv->FvUiName = NULL;
+
+    //
+    // Exist Extend FV header.
+    //
+    if (CurrentFv->FvHeader->ExtHeaderOffset != 0){
+      ExtHdrPtr = (VOID *)((UINTN)Fv + CurrentFv->FvHeader->ExtHeaderOffset);
+      CurrentFv->FvExtHeader = (EFI_FIRMWARE_VOLUME_EXT_HEADER *) malloc (ExtHdrPtr->ExtHeaderSize);
+
+      if (CurrentFv->FvExtHeader == NULL) {
+        Error (NULL, 0, 4001, "Resource: Memory can't be allocated", NULL);
+        return EFI_ABORTED;
+      }
+
+      //
+      // Get the FV extended Header information
+      //
+      memcpy (CurrentFv->FvExtHeader, (VOID *)((UINTN)Fv + CurrentFv->FvHeader->ExtHeaderOffset), ExtHdrPtr->ExtHeaderSize);
+      LibExtractFvUiName(CurrentFv->FvExtHeader, &CurrentFv->FvUiName);
+    }
+  }
+
+  //
+  // Put encapsulate information into structure.
+  //
+  LocalEncapData = *CurrentFvEncapData;
+  if (LocalEncapData == NULL && !IsChildFv) {
+    //
+    // First time in, the root FV
+    //
+    LocalEncapData = (ENCAP_INFO_DATA *) malloc (sizeof (ENCAP_INFO_DATA));
+    CurrentFv->EncapData = LocalEncapData;
+    if (CurrentFv->EncapData == NULL) {
+      Error (NULL, 0, 4001, "Resource: Memory can't be allocated", NULL);
+      return EFI_ABORTED;
+    }
+
+    CurrentFv->EncapData->FvExtHeader = NULL;
+    CurrentFv->EncapData->Depex = NULL;
+    CurrentFv->EncapData->DepexLen = 0;
+    CurrentFv->EncapData->UiNameSize = 0;
+    CurrentFv->EncapData->Level = Level;
+    CurrentFv->EncapData->Type  = FMMT_ENCAP_TREE_FV;
+    CurrentFv->EncapData->Data  = (EFI_FIRMWARE_VOLUME_HEADER *) malloc (sizeof (EFI_FIRMWARE_VOLUME_HEADER));
+    CurrentFv->EncapData->FvId  = *FvCount;
+
+    if (CurrentFv->EncapData->Data == NULL) {
+      Error (NULL, 0, 4001, "Resource: Memory can't be allocated", NULL);
+      return EFI_ABORTED;
+    }
+
+    memcpy (CurrentFv->EncapData->Data, Fv, sizeof (EFI_FIRMWARE_VOLUME_HEADER));
+
+    if (((EFI_FIRMWARE_VOLUME_HEADER *)(CurrentFv->EncapData->Data))->ExtHeaderOffset != 0) {
+      ExtHdrPtr = (VOID *)((UINTN)Fv + ((EFI_FIRMWARE_VOLUME_HEADER *)(CurrentFv->EncapData->Data))->ExtHeaderOffset);
+      CurrentFv->EncapData->FvExtHeader = (EFI_FIRMWARE_VOLUME_EXT_HEADER *) malloc (ExtHdrPtr->ExtHeaderSize);
+
+      if (CurrentFv->EncapData->FvExtHeader == NULL) {
+        Error (NULL, 0, 4001, "Resource: Memory can't be allocated", NULL);
+        return EFI_ABORTED;
+      }
+
+      //
+      // Get the FV extended Header information
+      //
+      memcpy(CurrentFv->EncapData->FvExtHeader, (VOID *)((UINTN)Fv + ((EFI_FIRMWARE_VOLUME_HEADER *)(CurrentFv->EncapData->Data))->ExtHeaderOffset), ExtHdrPtr->ExtHeaderSize);
+    }
+
+    CurrentFv->EncapData->NextNode  = NULL;
+  CurrentFv->EncapData->RightNode  = NULL;
+  } else if (LocalEncapData == NULL) {
+    return EFI_ABORTED;
+  } else if (IsChildFv) {
+
+      LocalEncapData = *CurrentFvEncapData;
+      while (LocalEncapData->NextNode != NULL) {
+        LocalEncapData = LocalEncapData->NextNode;
+      }
+
+      //
+      // Construct the new ENCAP_DATA
+      //
+      LocalEncapData->NextNode = (ENCAP_INFO_DATA *) malloc (sizeof (ENCAP_INFO_DATA));
+
+      if (LocalEncapData->NextNode == NULL) {
+        Error (NULL, 0, 4001, "Resource: Memory can't be allocated", NULL);
+        return EFI_ABORTED;
+      }
+
+      LocalEncapData           = LocalEncapData->NextNode;
+
+      LocalEncapData->Level = Level;
+      LocalEncapData->Type  = FMMT_ENCAP_TREE_FV;
+      LocalEncapData->Data  = (EFI_FIRMWARE_VOLUME_HEADER *) malloc (sizeof (EFI_FIRMWARE_VOLUME_HEADER));
+      LocalEncapData->FvExtHeader = NULL;
+      LocalEncapData->Depex = NULL;
+      LocalEncapData->DepexLen = 0;
+      LocalEncapData->UiNameSize = 0;
+      LocalEncapData->FvId  = *FvCount;
+      if (LocalEncapData->Data == NULL) {
+        Error (NULL, 0, 4001, "Resource: Memory can't be allocated", NULL);
+        return EFI_ABORTED;
+      }
+
+      memcpy (LocalEncapData->Data, Fv, sizeof (EFI_FIRMWARE_VOLUME_HEADER));
+
+      if (((EFI_FIRMWARE_VOLUME_HEADER *)(LocalEncapData->Data))->ExtHeaderOffset != 0) {
+        ExtHdrPtr = (VOID *)((UINTN)Fv + ((EFI_FIRMWARE_VOLUME_HEADER *)(LocalEncapData->Data))->ExtHeaderOffset);
+        LocalEncapData->FvExtHeader = (EFI_FIRMWARE_VOLUME_EXT_HEADER *)malloc(ExtHdrPtr->ExtHeaderSize);
+
+        if (LocalEncapData->FvExtHeader == NULL) {
+          Error (NULL, 0, 4001, "Resource: Memory can't be allocated", NULL);
+          return EFI_ABORTED;
+        }
+
+        //
+        // Get the FV extended Header information
+        //
+        memcpy(LocalEncapData->FvExtHeader, (VOID *)((UINTN)Fv + ((EFI_FIRMWARE_VOLUME_HEADER *)(LocalEncapData->Data))->ExtHeaderOffset), ExtHdrPtr->ExtHeaderSize);
+      }
+
+      LocalEncapData->NextNode  = NULL;
+      LocalEncapData->RightNode  = NULL;
+
+  }
+
+
+  //
+  // Get the first file
+  //
+  Status = FvBufFindNextFile (Fv, &Key, (VOID **) &CurrentFile);
+  if (Status == EFI_NOT_FOUND) {
+    CurrentFile = NULL;
+  } else if (EFI_ERROR (Status)) {
+    Error ("FMMT", 0, 0003, "error parsing FV image", "cannot find the first file in the FV image");
+    return Status;
+  }
+
+  while (CurrentFile != NULL) {
+
+    //
+    // Increment the number of files counter
+    //
+    NumberOfFiles++;
+
+    //
+    // Store FFS file Header information
+    //
+    CurrentFv->FfsHeader[*FfsCount].Attributes       = CurrentFile->Attributes;
+    CurrentFv->FfsHeader[*FfsCount].IntegrityCheck   = CurrentFile->IntegrityCheck;
+    CurrentFv->FfsHeader[*FfsCount].Name             = CurrentFile->Name;
+    CurrentFv->FfsHeader[*FfsCount].Size[0]          = CurrentFile->Size[0];
+    CurrentFv->FfsHeader[*FfsCount].Size[1]          = CurrentFile->Size[1];
+    CurrentFv->FfsHeader[*FfsCount].Size[2]          = CurrentFile->Size[2];
+    CurrentFv->FfsHeader[*FfsCount].State            = CurrentFile->State;
+    CurrentFv->FfsHeader[*FfsCount].Type             = CurrentFile->Type;
+    CurrentFv->FfsHeader[*FfsCount].ExtendedSize     = CurrentFile->ExtendedSize;
+    CurrentFv->FfsAttuibutes[*FfsCount].Offset = Key - GetFfsFileLength ((EFI_FFS_FILE_HEADER *) CurrentFile);
+
+    CurrentFv->FfsAttuibutes[*FfsCount].FvLevel = CurrentFv->FvLevel;
+     if (CurrentFv->FvLevel > CurrentFv->MulFvLevel) {
+      CurrentFv->MulFvLevel = CurrentFv->FvLevel;
+   }
+    //
+    // Display info about this file
+    //
+    Status = LibGetFileInfo (Fv, CurrentFile, ErasePolarity, CurrentFv, FvName, Level, &LocalEncapData, FfsCount, FvCount, ViewFlag);
+    if (EFI_ERROR (Status)) {
+      Error ("FMMT", 0, 0003, "error parsing FV image", "failed to parse a file in the FV");
+      return Status;
+    }
+
+    //
+    // Get the next file
+    //
+    Status = FvBufFindNextFile (Fv, &Key, (VOID **) &CurrentFile);
+    if (Status == EFI_NOT_FOUND) {
+      CurrentFile = NULL;
+    } else if (EFI_ERROR (Status)) {
+      Error ("FMMT", 0, 0003, "error parsing FV image", "cannot find the next file in the FV image");
+      return Status;
+    }
+  }
+
+  if (IsChildFv) {
+      if (CurrentFv->FvLevel > 1) {
+          CurrentFv->FvLevel -= 1;
+      }
+  }
+  return EFI_SUCCESS;
+}
+
+/**
+
+  This function returns the next larger size that meets the alignment
+  requirement specified.
+
+  @param[in]      ActualSize      The size.
+  @param[in]      Alignment       The desired alignment.
+
+  @retval         EFI_SUCCESS     Function completed successfully.
+  @retval         EFI_ABORTED     The function encountered an error.
+
+**/
+UINT32
+GetOccupiedSize (
+  IN UINT32  ActualSize,
+  IN UINT32  Alignment
+  )
+{
+  UINT32  OccupiedSize;
+
+  OccupiedSize = ActualSize;
+  while ((OccupiedSize & (Alignment - 1)) != 0) {
+    OccupiedSize++;
+  }
+
+  return OccupiedSize;
+}
+
+
+
+EFI_STATUS
+LibDeleteAndRenameFfs(
+  IN CHAR8*    DeleteFile,
+  IN CHAR8*    NewFile
+)
+{
+  CHAR8*                 SystemCommand;
+  CHAR8*                 TemDir;
+  SystemCommand             = NULL;
+
+  if (DeleteFile == NULL ||
+      NewFile    == NULL) {
+    return EFI_INVALID_PARAMETER;
+  }
+
+  //
+  // Delete the file of the specified extract FFS file.
+  //
+  SystemCommand = malloc (
+    strlen (DEL_STR) +
+    strlen (DeleteFile)  +
+    1
+    );
+  if (SystemCommand == NULL) {
+    Error (NULL, 0, 4001, "Resource: Memory can't be allocated", NULL);
+    return EFI_ABORTED;
+  }
+
+  sprintf (
+    SystemCommand,
+    DEL_STR,
+    DeleteFile
+    );
+
+  if (system (SystemCommand) != EFI_SUCCESS) {
+    free(SystemCommand);
+    return EFI_ABORTED;
+  }
+  free(SystemCommand);
+
+  TemDir = getcwd (NULL, _MAX_PATH);
+  if (strlen (TemDir) + strlen(OS_SEP_STR) + strlen (TEMP_DIR_NAME) > _MAX_PATH - 1) {
+    Error("FMMT", 0, 1001, "The directory is too long.", "");
+     return EFI_ABORTED;
+  }
+  strncat (TemDir, OS_SEP_STR, _MAX_PATH - strlen(TemDir) - 1);
+  strncat (TemDir, TEMP_DIR_NAME, _MAX_PATH - strlen(TemDir) - 1);
+
+  mkdir(TemDir, S_IRWXU | S_IRWXG | S_IRWXO);
+  //
+  // Create a copy the new file.
+  //
+
+  SystemCommand = malloc (
+    strlen (COPY_STR) +
+    strlen (NewFile)    +
+    strlen (DeleteFile) +
+    1
+    );
+  if (SystemCommand == NULL) {
+    Error (NULL, 0, 4001, "Resource: Memory can't be allocated", NULL);
+    return EFI_ABORTED;
+  }
+
+  sprintf (
+    SystemCommand,
+    COPY_STR,
+    NewFile,
+    DeleteFile
+    );
+
+  if (system (SystemCommand) != EFI_SUCCESS) {
+  free(SystemCommand);
+    return EFI_ABORTED;
+  }
+  free(SystemCommand);
+
+  return EFI_SUCCESS;
+
+}
+
+/**
+  Converts ASCII characters to Unicode.
+  Assumes that the Unicode characters are only these defined in the ASCII set.
+
+  String      - Pointer to string that is written to FILE.
+  UniString   - Pointer to unicode string
+
+  The address to the ASCII string - same as AsciiStr.
+
+**/
+VOID
+LibAscii2Unicode (
+  IN   CHAR8          *String,
+  OUT  CHAR16         *UniString
+  )
+{
+  while (*String != '\0') {
+    *(UniString++) = (CHAR16) *(String++);
+    }
+  //
+  // End the UniString with a NULL.
+  //
+  *UniString = '\0';
+}
+
+
+EFI_STATUS
+LibCreateGuidedSectionOriginalData(
+  IN CHAR8*    FileIn,
+  IN CHAR8*    ToolName,
+  IN CHAR8*    FileOut
+)
+{
+  CHAR8*                 SystemCommandFormatString;
+  CHAR8*                 SystemCommand;
+
+  SystemCommandFormatString = NULL;
+  SystemCommand             = NULL;
+
+  if (FileIn   == NULL ||
+      ToolName == NULL ||
+      FileOut  == NULL) {
+    return EFI_INVALID_PARAMETER;
+  }
+
+  //
+  // Delete the file of the specified extract FFS file.
+  //
+  SystemCommandFormatString = "%s -e \"%s\" -o \"%s\"";
+
+  SystemCommand = malloc (
+    strlen (SystemCommandFormatString) +
+    strlen (FileIn)  +
+    strlen (ToolName)  +
+    strlen (FileOut)  +
+    1
+    );
+  if (SystemCommand == NULL) {
+    Error (NULL, 0, 4001, "Resource: Memory can't be allocated", NULL);
+    return EFI_ABORTED;
+  }
+
+  sprintf (
+    SystemCommand,
+    "%s -e \"%s\" -o \"%s\"",
+    ToolName,
+    FileIn,
+    FileOut
+    );
+
+  if (system (SystemCommand) != EFI_SUCCESS) {
+    printf("Command failed: %s\n", SystemCommand);
+  free(SystemCommand);
+    return EFI_ABORTED;
+  }
+  free(SystemCommand);
+
+  return EFI_SUCCESS;
+}
+
+/**
+
+   This function convert the FV header's attribute to a string. The converted string
+   will be put into an INF file as the input of GenFV.
+
+   @param[in]      Attr       FV header's attribute.
+   @param[out]     InfFile    InfFile contain FV header attribute information.
+
+   @retval         EFI_SUCCESS.
+   @retval         EFI_INVLID_PARAMETER
+   @retval         EFI_OUT_OF_RESOURCES
+
+**/
+EFI_STATUS
+LibFvHeaderAttributeToStr (
+  IN     EFI_FVB_ATTRIBUTES_2     Attr,
+  IN     FILE*                  InfFile
+)
+{
+  CHAR8     *LocalStr;
+
+  LocalStr  = NULL;
+
+  LocalStr = (CHAR8 *) malloc (1024 * 4);
+
+  if (LocalStr == NULL) {
+    printf ("Memory allocate error!\n");
+    return EFI_OUT_OF_RESOURCES;
+  }
+
+  memset (LocalStr, '\0', 1024 * 4);
+
+  if (Attr == 0 || InfFile  == NULL) {
+    free (LocalStr);
+    return EFI_INVALID_PARAMETER;
+  }
+
+  strncat (LocalStr, "[attributes] \n", sizeof("[attributes] \n"));
+
+  if (Attr & EFI_FVB2_READ_DISABLED_CAP) {
+    strncat (LocalStr, "EFI_READ_DISABLED_CAP = TRUE \n", sizeof ("EFI_READ_DISABLED_CAP = TRUE \n"));
+  }
+
+  if (Attr & EFI_FVB2_READ_ENABLED_CAP) {
+    strncat (LocalStr, "EFI_READ_ENABLED_CAP = TRUE \n", sizeof ("EFI_READ_ENABLED_CAP = TRUE \n"));
+  }
+
+  if (Attr & EFI_FVB2_READ_STATUS) {
+    strncat (LocalStr, "EFI_READ_STATUS = TRUE \n", sizeof ("EFI_READ_STATUS = TRUE \n"));
+  }
+
+  if (Attr & EFI_FVB2_WRITE_DISABLED_CAP) {
+    strncat (LocalStr, "EFI_WRITE_DISABLED_CAP = TRUE \n", sizeof ("EFI_WRITE_DISABLED_CAP = TRUE \n"));
+  }
+
+  if (Attr & EFI_FVB2_WRITE_ENABLED_CAP) {
+    strncat (LocalStr, "EFI_WRITE_ENABLED_CAP = TRUE \n", sizeof ("EFI_WRITE_ENABLED_CAP = TRUE \n"));
+  }
+
+  if (Attr & EFI_FVB2_WRITE_STATUS) {
+    strncat (LocalStr, "EFI_WRITE_STATUS = TRUE \n", sizeof ("EFI_WRITE_STATUS = TRUE \n"));
+  }
+
+  if (Attr & EFI_FVB2_LOCK_CAP) {
+    strncat (LocalStr, "EFI_LOCK_CAP = TRUE \n", sizeof ("EFI_LOCK_CAP = TRUE \n"));
+  }
+
+  if (Attr & EFI_FVB2_LOCK_STATUS) {
+    strncat (LocalStr, "EFI_LOCK_STATUS = TRUE \n", sizeof ("EFI_LOCK_STATUS = TRUE \n"));
+  }
+
+  if (Attr & EFI_FVB2_STICKY_WRITE) {
+    strncat (LocalStr, "EFI_STICKY_WRITE = TRUE \n", sizeof ("EFI_STICKY_WRITE = TRUE \n"));
+  }
+
+  if (Attr & EFI_FVB2_MEMORY_MAPPED) {
+    strncat (LocalStr, "EFI_MEMORY_MAPPED = TRUE \n", sizeof ("EFI_MEMORY_MAPPED = TRUE \n"));
+  }
+
+  if (Attr & EFI_FVB2_ERASE_POLARITY) {
+    strncat (LocalStr, "EFI_ERASE_POLARITY = 1 \n", sizeof ("EFI_ERASE_POLARITY = 1 \n"));
+  }
+
+  if (Attr & EFI_FVB2_READ_LOCK_CAP) {
+    strncat (LocalStr, "EFI_READ_LOCK_CAP = TRUE \n", sizeof ("EFI_READ_LOCK_CAP = TRUE \n"));
+  }
+
+  if (Attr & EFI_FVB2_READ_LOCK_STATUS) {
+    strncat (LocalStr, "EFI_READ_LOCK_STATUS = TRUE \n", sizeof ("EFI_READ_LOCK_STATUS = TRUE \n"));
+  }
+
+  if (Attr & EFI_FVB2_WRITE_LOCK_CAP) {
+    strncat (LocalStr, "EFI_WRITE_LOCK_CAP = TRUE \n", sizeof ("EFI_WRITE_LOCK_CAP = TRUE \n"));
+  }
+
+  if (Attr & EFI_FVB2_WRITE_LOCK_STATUS) {
+    strncat (LocalStr, "EFI_WRITE_LOCK_STATUS = TRUE \n", sizeof ("EFI_WRITE_LOCK_STATUS = TRUE \n"));
+  }
+
+  if (Attr & EFI_FVB2_LOCK_STATUS) {
+    strncat (LocalStr, "EFI_READ_LOCK_STATUS = TRUE \n", sizeof ("EFI_READ_LOCK_STATUS = TRUE \n"));
+  }
+
+  //
+  // Alignment
+  //
+  if (Attr & EFI_FVB2_ALIGNMENT_1) {
+    strncat (LocalStr, "EFI_FVB2_ALIGNMENT_1 = TRUE \n", sizeof ("EFI_FVB2_ALIGNMENT_1 = TRUE \n"));
+  } else if (Attr & EFI_FVB2_ALIGNMENT_2) {
+    strncat (LocalStr, "EFI_FVB2_ALIGNMENT_2 = TRUE \n", sizeof ("EFI_FVB2_ALIGNMENT_2 = TRUE \n"));
+  } else if (Attr & EFI_FVB2_ALIGNMENT_4) {
+    strncat (LocalStr, "EFI_FVB2_ALIGNMENT_4 = TRUE \n", sizeof ("EFI_FVB2_ALIGNMENT_4 = TRUE \n"));
+  } else if (Attr & EFI_FVB2_ALIGNMENT_8) {
+    strncat (LocalStr, "EFI_FVB2_ALIGNMENT_8 = TRUE \n", sizeof ("EFI_FVB2_ALIGNMENT_8 = TRUE \n"));
+  } else if (Attr & EFI_FVB2_ALIGNMENT_16) {
+    strncat (LocalStr, "EFI_FVB2_ALIGNMENT_16 = TRUE \n", sizeof ("EFI_FVB2_ALIGNMENT_16 = TRUE \n"));
+  } else if (Attr & EFI_FVB2_ALIGNMENT_32) {
+    strncat (LocalStr, "EFI_FVB2_ALIGNMENT_32 = TRUE \n", sizeof ("EFI_FVB2_ALIGNMENT_32 = TRUE \n"));
+  } else if (Attr & EFI_FVB2_ALIGNMENT_64) {
+    strncat (LocalStr, "EFI_FVB2_ALIGNMENT_64 = TRUE \n", sizeof ("EFI_FVB2_ALIGNMENT_64 = TRUE \n"));
+  } else if (Attr & EFI_FVB2_ALIGNMENT_128) {
+    strncat (LocalStr, "EFI_FVB2_ALIGNMENT_128 = TRUE \n", sizeof ("EFI_FVB2_ALIGNMENT_128 = TRUE \n"));
+  } else if (Attr & EFI_FVB2_ALIGNMENT_256) {
+    strncat (LocalStr, "EFI_FVB2_ALIGNMENT_256 = TRUE \n", sizeof ("EFI_FVB2_ALIGNMENT_256 = TRUE \n"));
+  } else if (Attr & EFI_FVB2_ALIGNMENT_512) {
+    strncat (LocalStr, "EFI_FVB2_ALIGNMENT_512 = TRUE \n", sizeof ("EFI_FVB2_ALIGNMENT_512 = TRUE \n"));
+  } else if (Attr & EFI_FVB2_ALIGNMENT_1K) {
+    strncat (LocalStr, "EFI_FVB2_ALIGNMENT_1K = TRUE \n", sizeof ("EFI_FVB2_ALIGNMENT_1K = TRUE \n"));
+  } else if (Attr & EFI_FVB2_ALIGNMENT_2K) {
+    strncat (LocalStr, "EFI_FVB2_ALIGNMENT_2K = TRUE \n", sizeof ("EFI_FVB2_ALIGNMENT_2K = TRUE \n"));
+  } else if (Attr & EFI_FVB2_ALIGNMENT_4K) {
+    strncat (LocalStr, "EFI_FVB2_ALIGNMENT_4K = TRUE \n", sizeof ("EFI_FVB2_ALIGNMENT_4K = TRUE \n"));
+  } else if (Attr & EFI_FVB2_ALIGNMENT_8K) {
+    strncat (LocalStr, "EFI_FVB2_ALIGNMENT_8K = TRUE \n", sizeof ("EFI_FVB2_ALIGNMENT_8K = TRUE \n"));
+  } else if (Attr & EFI_FVB2_ALIGNMENT_16K) {
+    strncat (LocalStr, "EFI_FVB2_ALIGNMENT_16K = TRUE \n", sizeof ("EFI_FVB2_ALIGNMENT_16K = TRUE \n"));
+  } else if (Attr & EFI_FVB2_ALIGNMENT_32K) {
+    strncat (LocalStr, "EFI_FVB2_ALIGNMENT_32K = TRUE \n", sizeof ("EFI_FVB2_ALIGNMENT_32K = TRUE \n"));
+  } else if (Attr & EFI_FVB2_ALIGNMENT_64K) {
+    strncat (LocalStr, "EFI_FVB2_ALIGNMENT_64K = TRUE \n", sizeof ("EFI_FVB2_ALIGNMENT_64K = TRUE \n"));
+  } else if (Attr & EFI_FVB2_ALIGNMENT_128K) {
+    strncat (LocalStr, "EFI_FVB2_ALIGNMENT_128K = TRUE \n", sizeof ("EFI_FVB2_ALIGNMENT_128K = TRUE \n"));
+  } else if (Attr & EFI_FVB2_ALIGNMENT_256K) {
+    strncat (LocalStr, "EFI_FVB2_ALIGNMENT_256K = TRUE \n", sizeof ("EFI_FVB2_ALIGNMENT_256K = TRUE \n"));
+  } else if (Attr & EFI_FVB2_ALIGNMENT_512K) {
+    strncat (LocalStr, "EFI_FVB2_ALIGNMENT_512K = TRUE \n", sizeof ("EFI_FVB2_ALIGNMENT_512K = TRUE \n"));
+  } else if (Attr & EFI_FVB2_ALIGNMENT_1M) {
+    strncat (LocalStr, "EFI_FVB2_ALIGNMENT_1M = TRUE \n", sizeof ("EFI_FVB2_ALIGNMENT_1M = TRUE \n"));
+  } else if (Attr & EFI_FVB2_ALIGNMENT_2M) {
+    strncat (LocalStr, "EFI_FVB2_ALIGNMENT_2M = TRUE \n", sizeof ("EFI_FVB2_ALIGNMENT_2M = TRUE \n"));
+  } else if (Attr & EFI_FVB2_ALIGNMENT_4M) {
+    strncat (LocalStr, "EFI_FVB2_ALIGNMENT_4M = TRUE \n", sizeof ("EFI_FVB2_ALIGNMENT_4M = TRUE \n"));
+  } else if (Attr & EFI_FVB2_ALIGNMENT_8M) {
+    strncat (LocalStr, "EFI_FVB2_ALIGNMENT_8M = TRUE \n", sizeof ("EFI_FVB2_ALIGNMENT_8M = TRUE \n"));
+  } else if (Attr & EFI_FVB2_ALIGNMENT_16M) {
+    strncat (LocalStr, "EFI_FVB2_ALIGNMENT_16M = TRUE \n", sizeof ("EFI_FVB2_ALIGNMENT_16M = TRUE \n"));
+  } else if (Attr & EFI_FVB2_ALIGNMENT_32M) {
+    strncat (LocalStr, "EFI_FVB2_ALIGNMENT_32M = TRUE \n", sizeof ("EFI_FVB2_ALIGNMENT_32M = TRUE \n"));
+  } else if (Attr & EFI_FVB2_ALIGNMENT_64M) {
+    strncat (LocalStr, "EFI_FVB2_ALIGNMENT_64M = TRUE \n", sizeof ("EFI_FVB2_ALIGNMENT_64M = TRUE \n"));
+  } else if (Attr & EFI_FVB2_ALIGNMENT_128M) {
+    strncat (LocalStr, "EFI_FVB2_ALIGNMENT_128M = TRUE \n", sizeof ("EFI_FVB2_ALIGNMENT_128M = TRUE \n"));
+  } else if (Attr & EFI_FVB2_ALIGNMENT_256M) {
+    strncat (LocalStr, "EFI_FVB2_ALIGNMENT_256M = TRUE \n", sizeof ("EFI_FVB2_ALIGNMENT_256M = TRUE \n"));
+  } else if (Attr & EFI_FVB2_ALIGNMENT_512M) {
+    strncat (LocalStr, "EFI_FVB2_ALIGNMENT_512M = TRUE \n", sizeof ("EFI_FVB2_ALIGNMENT_512M = TRUE \n"));
+  } else if (Attr & EFI_FVB2_ALIGNMENT_1G) {
+    strncat (LocalStr, "EFI_FVB2_ALIGNMENT_1G = TRUE \n", sizeof ("EFI_FVB2_ALIGNMENT_1G = TRUE \n"));
+  } else if (Attr & EFI_FVB2_ALIGNMENT_2G) {
+    strncat (LocalStr, "EFI_FVB2_ALIGNMENT_2G = TRUE \n", sizeof ("EFI_FVB2_ALIGNMENT_2G = TRUE \n"));
+  }
+
+  if (fwrite (LocalStr, 1, (size_t) strlen (LocalStr), InfFile) != (size_t) strlen (LocalStr)) {
+    printf ("Error while writing data to %p file.", (void*)InfFile);
+    free (LocalStr);
+    return EFI_ABORTED;
+  }
+
+  free (LocalStr);
+
+  return EFI_SUCCESS;
+}
+
+
+/**
+   This function fill the FV inf files option field.
+
+   @param[in]      BlockMap       FV header's attribute.
+   @param[out]     InfFile    InfFile contain FV header attribute information.
+
+   @retval         EFI_SUCCESS.
+   @retval         EFI_INVLID_PARAMETER
+
+**/
+EFI_STATUS
+LibFvHeaderOptionToStr (
+  IN     EFI_FIRMWARE_VOLUME_HEADER  *FvHeader,
+  IN     FILE*                   InfFile,
+  IN     BOOLEAN                 IsRootFv
+)
+{
+  CHAR8     *LocalStr;
+  CHAR8     *TempStr;
+  EFI_FV_BLOCK_MAP_ENTRY  *BlockMap;
+
+  LocalStr     = NULL;
+  TempStr      = NULL;
+
+  if (FvHeader == NULL || InfFile  == NULL) {
+    return EFI_INVALID_PARAMETER;
+  }
+
+  //
+  // This section will not over 1024 bytes and each line will never over 128 bytes.
+  //
+  LocalStr    = (CHAR8 *) malloc (1024);
+  TempStr     = (CHAR8 *) malloc (128);
+
+  if (LocalStr    == NULL ||
+     TempStr   == NULL ) {
+      if (LocalStr != NULL) {
+        free (LocalStr);
+      }
+      if (TempStr != NULL) {
+        free (TempStr);
+      }
+    printf ("Memory allocate error! \n");
+    return EFI_OUT_OF_RESOURCES;
+  }
+
+  BlockMap = FvHeader->BlockMap;
+  memset (LocalStr, '\0', 1024);
+  memset (TempStr, '\0', 128);
+
+  strncat (LocalStr, "[options] \n", sizeof("[Options] \n"));
+
+
+  snprintf (TempStr, 128, "EFI_BLOCK_SIZE  = 0x%x \n", BlockMap->Length);
+  strncat (LocalStr, TempStr, strlen(TempStr));
+
+  if (IsRootFv) {
+  snprintf (TempStr, 128, "EFI_NUM_BLOCKS  = 0x%x \n", BlockMap->NumBlocks);
+  strncat (LocalStr, TempStr, strlen(TempStr));
+  }
+
+  if (fwrite (LocalStr, 1, (size_t) strlen (LocalStr), InfFile) != (size_t) strlen (LocalStr)) {
+    printf ("Error while writing data to %p file.", (void*)InfFile);
+    free (LocalStr);
+    free (TempStr);
+    return EFI_ABORTED;
+  }
+
+  free (LocalStr);
+  free (TempStr);
+
+  return EFI_SUCCESS;
+}
+
+/**
+   This function fill the FV inf files option field.
+
+   @param[in]      FfsName    Ffs file path/name.
+   @param[out]     InfFile    InfFile contain FV header attribute information
+   @param[in]      FirstIn    Is the first time call this function? If yes, should create [files] section.
+
+   @retval         EFI_SUCCESS.
+   @retval         EFI_INVLID_PARAMETER
+
+**/
+EFI_STATUS
+LibAddFfsFileToFvInf (
+  IN     CHAR8                   *FfsName,
+  IN     FILE*                   InfFile,
+  IN     BOOLEAN                 FirstIn
+)
+{
+
+  CHAR8     *LocalStr;
+
+  LocalStr     = NULL;
+
+  if (FfsName == NULL || InfFile  == NULL) {
+    return EFI_INVALID_PARAMETER;
+  }
+
+  if (strlen(FfsName) == 0) {
+    return EFI_SUCCESS;
+  }
+
+  LocalStr    = (CHAR8 *) malloc (_MAX_PATH);
+
+  if (LocalStr == NULL) {
+    printf ("Memory allocate error! \n");
+    return EFI_OUT_OF_RESOURCES;
+  }
+
+  memset (LocalStr, '\0', _MAX_PATH);
+
+  if (FirstIn) {
+    sprintf (LocalStr, "[files] \nEFI_FILE_NAME = %s \n", FfsName);
+  } else {
+    sprintf (LocalStr, "EFI_FILE_NAME = %s \n", FfsName);
+  }
+
+  if (fwrite (LocalStr, 1, (size_t) strlen (LocalStr), InfFile) != (size_t) strlen (LocalStr)) {
+    printf ("Error while writing data to %p file.", (void*)InfFile);
+    free (LocalStr);
+    return EFI_ABORTED;
+  }
+
+  free (LocalStr);
+
+  return EFI_SUCCESS;
+}
+
+
+/**
+  Convert EFI file to PE or TE section
+
+  @param[in]   InputFilePath   .efi file, it's optional unless process PE/TE section.
+  @param[in]   Type            PE or TE and UI/Version
+  @param[in]   OutputFilePath  .te or .pe file
+  @param[in]   UiString        String for generate UI section usage, this parameter is optional
+                               unless Type is EFI_SECTION_USER_INTERFACE.
+  @param[in]   VerString       String for generate Version section usage, this parameter is optional
+                               unless Type is EFI_SECTION_VERSION.
+
+  @retval EFI_SUCCESS
+
+**/
+EFI_STATUS
+LibCreateFfsSection (
+  IN FV_INFORMATION   *FvInFd,      OPTIONAL
+  IN CHAR8*     InputFilePath,      OPTIONAL
+  IN CHAR8*     Sections,           OPTIONAL
+  IN UINT8      Type,
+  IN CHAR8*     OutputFilePath,
+  IN CHAR8*     UiString,           OPTIONAL
+  IN CHAR8*     VerString,          OPTIONAL
+  IN CHAR8*     GuidToolGuid,       OPTIONAL
+  IN UINT16     GuidHeaderLength,
+  IN UINT16     GuidAttr,
+  IN CHAR8*     CompressType       OPTIONAL
+  )
+{
+  //EFI_STATUS             Status;
+  CHAR8*                 SystemCommandFormatString;
+  CHAR8*                 SystemCommand;
+  FILE                   *file;
+  UINT8                  Buffer[4];
+  int                    BitNum;
+  int                    Position;
+  UINT32                 AlignmentValue;
+  //
+  // Workaround for static code checkers.
+  // Ensures the size of 'AlignmentStr' can hold all the digits of an
+  // unsigned 32-bit integer plus the size unit character.
+  //
+  char                   AlignmentStr[16];
+
+  SystemCommandFormatString = NULL;
+  SystemCommand             = NULL;
+  strcpy(AlignmentStr,"1");
+  //
+  // Call GenSec tool to generate FFS section.
+  //
+
+  //
+  // -s SectionType.
+  //
+  if (Type != 0) {
+    switch (Type) {
+      //
+      // Process compression section
+      //
+      case EFI_SECTION_COMPRESSION:
+        SystemCommandFormatString = "GenSec -s %s -c %s  \"%s\" -o \"%s\"";
+        SystemCommand = malloc (
+          strlen (SystemCommandFormatString) +
+          strlen (mSectionTypeName[Type]) +
+          strlen (CompressType) +
+          strlen (InputFilePath) +
+          strlen (OutputFilePath) +
+          1
+          );
+        if (SystemCommand == NULL) {
+          Error (NULL, 0, 4001, "Resource: Memory can't be allocated", NULL);
+          return EFI_ABORTED;
+        }
+        sprintf (
+          SystemCommand,
+          "GenSec -s %s -c %s  \"%s\" -o \"%s\"",
+          mSectionTypeName[Type],
+          CompressType,
+          InputFilePath,
+          OutputFilePath
+          );
+
+        if (system (SystemCommand) != EFI_SUCCESS) {
+          free(SystemCommand);
+          return EFI_ABORTED;
+        }
+        free(SystemCommand);
+        break;
+
+      //
+      // Process GUID defined section
+      //
+      case EFI_SECTION_GUID_DEFINED:
+        SystemCommandFormatString = "GenSec -s %s -g %s \"%s\" -o \"%s\" -r %s -r %s -l %d";
+        SystemCommand = malloc (
+          strlen (SystemCommandFormatString) +
+          strlen (mSectionTypeName[Type]) +
+          strlen (GuidToolGuid) +
+          strlen (InputFilePath) +
+          strlen (OutputFilePath) +
+          strlen (mGuidSectionAttr[GuidAttr&0x01]) +
+          strlen (mGuidSectionAttr[GuidAttr&0x02]) +
+          4 +
+          1
+          );
+        if (SystemCommand == NULL) {
+          Error (NULL, 0, 4001, "Resource: Memory can't be allocated", NULL);
+          return EFI_ABORTED;
+        }
+        sprintf (
+          SystemCommand,
+          "GenSec -s %s -g %s \"%s\" -o \"%s\" -r %s -r %s -l %d",
+          mSectionTypeName[Type],
+          GuidToolGuid,
+          InputFilePath,
+          OutputFilePath,
+          mGuidSectionAttr[GuidAttr&0x01],
+          mGuidSectionAttr[GuidAttr&0x02],
+          GuidHeaderLength
+          );
+
+        if (system (SystemCommand) != EFI_SUCCESS) {
+          free(SystemCommand);
+          return EFI_ABORTED;
+        }
+        free(SystemCommand);
+        break;
+
+      case EFI_SECTION_FIRMWARE_VOLUME_IMAGE:
+
+        SystemCommandFormatString = "GenSec -s %s \"%s\" -o \"%s\"";
+        SystemCommand = malloc (
+          strlen (SystemCommandFormatString) +
+          strlen (mSectionTypeName[Type]) +
+          strlen (InputFilePath) +
+          strlen (OutputFilePath) +
+          1
+          );
+        if (SystemCommand == NULL) {
+          Error (NULL, 0, 4001, "Resource: Memory can't be allocated", NULL);
+          return EFI_ABORTED;
+        }
+        sprintf (
+          SystemCommand,
+          "GenSec -s %s \"%s\" -o \"%s\"",
+          mSectionTypeName[Type],
+          InputFilePath,
+          OutputFilePath
+          );
+
+        if (system (SystemCommand) != EFI_SUCCESS) {
+          free(SystemCommand);
+          return EFI_ABORTED;
+        }
+        free(SystemCommand);
+        break;
+
+      default:
+        Error ("FMMT", 0, 0003, "Please specify the section type while call GenSec tool.", NULL);
+        return EFI_UNSUPPORTED;
+    }
+  } else {
+    //
+    // Create Dummy section.
+    //
+    file = fopen(InputFilePath, "rb");
+    if (file == NULL) {
+      Error(NULL, 0, 0001, "Error opening the file", InputFilePath);
+      return EFI_INVALID_PARAMETER;
+    }
+    // The Section Struct, 3 bits for Size, then 1 bit for Type
+    if (fread(Buffer, 1, (size_t)(4), file) != (size_t)(4)) {
+      fclose(file);
+      return EFI_ABORTED;
+    }
+    if (*(Buffer + 3) == EFI_SECTION_FIRMWARE_VOLUME_IMAGE) {
+      // The Section Struct, if size is not 0xFFFF, the length is 4
+      Position = 4;
+      // If Size is 0xFFFFFF then ExtendedSize contains the size of the section
+      if ((*Buffer == 0xFF) && (*(Buffer + 1) == 0xFF) && (*(Buffer + 2) == 0xFF)) {
+        Position = 8;
+      }
+      //Per EFI_FIRMWARE_VOLUME_HEADER struct, 0x2E bit is EFI_FVB_ATTRIBUTES_2 attr
+      fseek(file, 0x2E + Position, SEEK_SET);
+      BitNum = fgetc(file);
+      AlignmentValue = 1 << (BitNum & 0x1F);
+      if (AlignmentValue >= 0x400){
+        if (AlignmentValue >= 0x10000){
+          strcpy(AlignmentStr,"64K");
+        }
+        else{
+          sprintf(AlignmentStr, "%d", AlignmentValue/0x400);
+          strcat(AlignmentStr, "K");
+        }
+      }
+      else{
+        sprintf(AlignmentStr, "%d", AlignmentValue);
+      }
+      strcpy(FvInFd->AlignmentStr, AlignmentStr);
+    }
+    fclose(file);
+    SystemCommandFormatString = "GenSec \"%s\" -o \"%s\" --sectionalign %s";
+    SystemCommand = malloc (
+      strlen (SystemCommandFormatString) +
+      strlen (InputFilePath) +
+      strlen (OutputFilePath) +
+      4 +                                 // Alignment maximum length
+      1
+      );
+    if (SystemCommand == NULL) {
+      Error (NULL, 0, 4001, "Resource: Memory can't be allocated", NULL);
+      return EFI_ABORTED;
+    }
+    sprintf (
+      SystemCommand,
+      "GenSec \"%s\" -o \"%s\" --sectionalign %s",
+      InputFilePath,
+      OutputFilePath,
+      AlignmentStr
+      );
+
+    if (system (SystemCommand) != EFI_SUCCESS) {
+      free(SystemCommand);
+      return EFI_ABORTED;
+    }
+    free(SystemCommand);
+
+  }
+
+  return EFI_SUCCESS;
+}
+
+/**
+  Encapsulate FFSs to FV
+
+  @param[in]   InputFilePath   Section file will be read into this FFS file. This option is required.
+  @param[in]   OutputFilePath  The created PI firmware file name. This option is required.
+  @param[in]   BlockSize       BlockSize is one HEX or DEC format value required by FV image.
+  @param[in]   FileTakeSize
+
+  @retval EFI_SUCCESS
+
+**/
+EFI_STATUS
+LibEncapsulateFfsToFv (
+  IN CHAR8*     InfFilePath,
+  IN CHAR8*     InputFFSs,
+  IN CHAR8*     OutputFilePath,
+  IN CHAR8*     FvGuidName,
+  IN BOOLEAN    IsLargeFile
+  )
+{
+
+  CHAR8*                 SystemCommandFormatString;
+  CHAR8*                 SystemCommand;
+  CHAR8*                 FfsGuid = "8c8ce578-8a3d-4f1c-9935-896185c32dd3";
+
+  if (IsLargeFile == TRUE) {
+    FfsGuid = "5473c07a-3dcb-4dca-bd6f-1e9689e7349a";
+  }
+
+  SystemCommandFormatString = NULL;
+  SystemCommand             = NULL;
+
+  if (OutputFilePath  == NULL ||
+      InfFilePath     == NULL ) {
+    return EFI_INVALID_PARAMETER;
+  }
+
+  if (InfFilePath != NULL) {
+    if (FvGuidName == NULL) {
+      SystemCommandFormatString = "GenFv -i \"%s\" -g %s -o \"%s\"";
+
+      SystemCommand = malloc (
+        strlen (SystemCommandFormatString) +
+        strlen (InfFilePath)   +
+        strlen (FfsGuid) +
+        strlen (OutputFilePath)  +
+        1
+        );
+      if (SystemCommand == NULL) {
+        Error (NULL, 0, 4001, "Resource: Memory can't be allocated", NULL);
+        return EFI_ABORTED;
+      }
+      sprintf (
+        SystemCommand,
+        "GenFv -i \"%s\" -g %s -o \"%s\"",
+        InfFilePath,          // -i
+        FfsGuid,              // -g
+        OutputFilePath        // -o
+        );
+
+      if (system (SystemCommand) != EFI_SUCCESS) {
+        free(SystemCommand);
+        return EFI_ABORTED;
+      }
+
+      free(SystemCommand);
+    } else {
+      //
+      // Have FvGuidName in it.
+      //
+      SystemCommandFormatString = "GenFv -i \"%s\" -g %s -o \"%s\" --FvNameGuid %s";
+
+      SystemCommand = malloc (
+        strlen (SystemCommandFormatString) +
+        strlen (InfFilePath)   +
+        strlen (FfsGuid)  +
+        strlen (OutputFilePath)  +
+        strlen (FvGuidName) +
+        1
+        );
+      if (SystemCommand == NULL) {
+        Error (NULL, 0, 4001, "Resource: Memory can't be allocated", NULL);
+        return EFI_ABORTED;
+      }
+      sprintf (
+        SystemCommand,
+        "GenFv -i \"%s\" -g %s -o \"%s\" --FvNameGuid %s",
+        InfFilePath,          // -i
+        FfsGuid,              // -g
+        OutputFilePath,       // -o
+        FvGuidName            // FvNameGuid
+        );
+
+      if (system (SystemCommand) != EFI_SUCCESS) {
+        free(SystemCommand);
+        return EFI_ABORTED;
+      }
+      free(SystemCommand);
+
+    }
+  }
+
+  return EFI_SUCCESS;
+}
+
+
+/**
+
+  Convert a GUID to a string.
+
+
+  @param[in]   Guid       - Pointer to GUID to print.
+
+
+  @return The string after convert.
+
+**/
+CHAR8 *
+LibFmmtGuidToStr (
+  IN  EFI_GUID  *Guid
+)
+{
+  CHAR8 * Buffer;
+
+  Buffer = NULL;
+
+  if (Guid == NULL) {
+    printf ("The guid is NULL while convert guid to string! \n");
+    return NULL;
+  }
+
+  Buffer = (CHAR8 *) malloc (36 + 1);
+
+  if (Buffer == NULL) {
+    printf ("Error while allocate resource! \n");
+    return NULL;
+  }
+  memset (Buffer, '\0', 36 + 1);
+
+  sprintf (
+      Buffer,
+      "%08x-%04x-%04x-%02x%02x-%02x%02x%02x%02x%02x%02x",
+      Guid->Data1,
+      Guid->Data2,
+      Guid->Data3,
+      Guid->Data4[0],
+      Guid->Data4[1],
+      Guid->Data4[2],
+      Guid->Data4[3],
+      Guid->Data4[4],
+      Guid->Data4[5],
+      Guid->Data4[6],
+      Guid->Data4[7]
+      );
+
+  return Buffer;
+}
+
+
+/**
+  Encapsulate an FFS section file to an FFS file.
+
+  @param[in]   Type            Type is one FV file type defined in PI spec, which is one type of EFI_FV_FILETYPE_RAW, EFI_FV_FILETYPE_FREEFORM,
+                               EFI_FV_FILETYPE_SECURITY_CORE, EFI_FV_FILETYPE_PEIM, EFI_FV_FILETYPE_PEI_CORE, EFI_FV_FILETYPE_DXE_CORE,
+                               EFI_FV_FILETYPE_DRIVER, EFI_FV_FILETYPE_APPLICATION, EFI_FV_FILETYPE_COMBINED_PEIM_DRIVER,
+                               EFI_FV_FILETYPE_FIRMWARE_VOLUME_IMAGE. This option is required.
+  @param[in]   InputFilePath   Section file will be read into this FFS file. This option is required.
+  @param[in]   OutputFilePath  The created PI firmware file name. This option is required.
+  @param[in]   FileGuid        FileGuid is the unique identifier for this FFS file. This option is required.
+  @param[in]   Fixed           Set fixed attribute in FFS file header to indicate that the file may not be moved from its present location.
+  @param[in]   SectionAlign    FileAlign specifies FFS file alignment, which only support the following alignment: 8,16,128,512,1K,4K,32K,64K.
+
+  @retval EFI_SUCCESS
+
+**/
+EFI_STATUS
+LibEncapSectionFileToFFS (
+  IN UINT8      Type,
+  IN CHAR8*     InputFilePath,
+  IN CHAR8*     OutputFilePath,
+  IN EFI_GUID   FileGuid,
+  IN BOOLEAN    Fixed,
+  IN CHAR8*     SectionAlign
+  )
+{
+  CHAR8*                 SystemCommandFormatString;
+  CHAR8*                 SystemCommand;
+  CHAR8*                 GuidStr;
+
+
+  SystemCommandFormatString = NULL;
+  SystemCommand             = NULL;
+  GuidStr                   = NULL;
+
+  GuidStr  = LibFmmtGuidToStr(&FileGuid);
+
+  if (GuidStr == NULL) {
+    return EFI_ABORTED;
+  }
+
+
+  //
+  // -t  Type
+  // -i  InputFilePath
+  // -o  OutPutFilePath
+  // -g  FileGuid
+  // -x  Fixed
+  // -n  SectionAlign
+  //
+
+  if (Fixed) {
+    SystemCommandFormatString = "GenFfs -t %s -i \"%s\" -g %s -x -o \"%s\" -a %s";
+    SystemCommand = malloc (
+      strlen (SystemCommandFormatString) +
+      strlen (mFfsFileType[Type]) +
+      strlen (InputFilePath) +
+      strlen (GuidStr) +
+      strlen (OutputFilePath) +
+      4 +
+      1
+      );
+    if (SystemCommand == NULL) {
+      Error (NULL, 0, 4001, "Resource: Memory can't be allocated", NULL);
+      free (GuidStr);
+      return EFI_ABORTED;
+    }
+    sprintf (
+      SystemCommand,
+      "GenFfs -t %s -i \"%s\" -g %s -x -o \"%s\" -a %s",
+      mFfsFileType[Type],     // -t
+      InputFilePath,          // -i
+      GuidStr,                // -g
+      OutputFilePath,         // -o
+      SectionAlign
+      );
+
+    free (GuidStr);
+    if (system (SystemCommand) != EFI_SUCCESS) {
+      free(SystemCommand);
+      return EFI_ABORTED;
+    }
+    free(SystemCommand);
+  } else {
+    SystemCommandFormatString = "GenFfs -t %s -i \"%s\" -g %s -o \"%s\" -a %s";
+    SystemCommand = malloc (
+      strlen (SystemCommandFormatString) +
+      strlen (mFfsFileType[Type]) +
+      strlen (InputFilePath) +
+      strlen (GuidStr) +
+      strlen (OutputFilePath) +
+      4 +
+      1
+      );
+    if (SystemCommand == NULL) {
+      free (GuidStr);
+      Error (NULL, 0, 4001, "Resource: Memory can't be allocated", NULL);
+      return EFI_ABORTED;
+    }
+    sprintf (
+      SystemCommand,
+      "GenFfs -t %s -i \"%s\" -g %s -o \"%s\" -a %s",
+      mFfsFileType[Type],     // -t
+      InputFilePath,          // -i
+      GuidStr,                // -g
+      OutputFilePath,         // -o
+      SectionAlign
+      );
+
+    free (GuidStr);
+    if (system (SystemCommand) != EFI_SUCCESS) {
+      free(SystemCommand);
+      return EFI_ABORTED;
+    }
+    free(SystemCommand);
+  }
+
+
+  return EFI_SUCCESS;
+}
+
+EFI_STATUS
+LibCreateNewFdCopy(
+  IN CHAR8*    OldFd,
+  IN CHAR8*    NewFd
+)
+{
+
+  FILE*                       NewFdFile;
+  FILE*                       OldFdFile;
+  CHAR8                       *NewFdDir;
+  CHAR8                       *OldFdDir;
+  UINT64                      FdLength;
+  UINT32                      Count;
+  BOOLEAN                     UseNewDirFlag;
+  CHAR8                       *Buffer;
+
+  NewFdFile = NULL;
+  OldFdFile = NULL;
+  NewFdDir  = NULL;
+  OldFdDir  = NULL;
+  Count     = 0;
+  UseNewDirFlag = FALSE;
+
+  if (OldFd == NULL ||
+    NewFd    == NULL) {
+      return EFI_INVALID_PARAMETER;
+  }
+
+
+  NewFdDir = getcwd (NULL, _MAX_PATH);
+
+  Count = strlen(NewFdDir);
+
+  if (strlen(NewFd) > Count) {
+
+    do {
+      if (NewFdDir[Count-1] == NewFd[Count-1]) {
+        Count--;
+      } else {
+        if (strlen(NewFdDir) + strlen (OS_SEP_STR) + strlen (NewFd) > _MAX_PATH -1) {
+          return EFI_ABORTED;
+        }
+        strncat (NewFdDir,OS_SEP_STR, _MAX_PATH - strlen (NewFdDir) -1);
+        strncat (NewFdDir,NewFd, _MAX_PATH - strlen (NewFdDir) -1);
+        UseNewDirFlag = TRUE;
+        break;
+      }
+
+    } while (Count != 1);
+
+  }else {
+    if (strlen(NewFdDir) + strlen (OS_SEP_STR) + strlen (NewFd) > _MAX_PATH -1) {
+      return EFI_ABORTED;
+    }
+    strncat (NewFdDir,OS_SEP_STR, _MAX_PATH - strlen (NewFdDir) -1);
+    strncat (NewFdDir,NewFd, _MAX_PATH - strlen (NewFdDir) -1);
+    UseNewDirFlag = TRUE;
+  }
+
+  if (UseNewDirFlag) {
+    NewFdFile = fopen (NewFdDir, "wb+");
+    if (NewFdFile == NULL) {
+      NewFdFile = fopen (NewFd, "wb+");
+    }
+  } else {
+    NewFdFile = fopen (NewFd, "wb+");
+  }
+  // support network path file
+  if (OldFd[0] == '\\' && OldFd[1] == '\\') {
+    OldFdFile = fopen (OldFd, "rb");
+  } else {
+  UseNewDirFlag = FALSE;
+
+  OldFdDir = getcwd (NULL, _MAX_PATH);
+
+  Count = strlen(OldFdDir);
+
+  if (strlen(OldFd) > Count) {
+
+    do {
+      if (OldFdDir[Count-1] == OldFd[Count-1]) {
+        Count--;
+      } else {
+        if (strlen(OldFdDir) + strlen (OS_SEP_STR) + strlen (OldFd) > _MAX_PATH -1) {
+          if (NewFdFile != NULL) {
+            fclose(NewFdFile);
+          }
+          return EFI_ABORTED;
+        }
+        strncat (OldFdDir,OS_SEP_STR, _MAX_PATH - strlen (OldFdDir) -1);
+        strncat (OldFdDir,OldFd, _MAX_PATH - strlen (OldFdDir) -1);
+        UseNewDirFlag = TRUE;
+        break;
+      }
+
+    } while (Count != 1);
+
+  }else {
+    if (strlen(OldFdDir) + strlen (OS_SEP_STR) + strlen (OldFd) > _MAX_PATH -1) {
+      if (NewFdFile != NULL) {
+        fclose(NewFdFile);
+      }
+      return EFI_ABORTED;
+    }
+    strncat (OldFdDir,OS_SEP_STR, _MAX_PATH - strlen (OldFdDir) -1);
+    strncat (OldFdDir,OldFd, _MAX_PATH - strlen (OldFdDir) -1);
+    UseNewDirFlag = TRUE;
+  }
+
+  if (UseNewDirFlag) {
+    OldFdFile = fopen (OldFdDir, "rb+");
+    if (OldFdFile == NULL) {
+      OldFdFile = fopen (OldFd, "rb+");
+    }
+  } else {
+    OldFdFile = fopen (OldFd, "rb+");
+  }
+  }
+
+  if (NewFdFile == NULL) {
+    Error ("FMMT", 0, 0003, "error Open FD file", "cannot Create a new FD file.");
+    if (OldFdFile != NULL) {
+      fclose (OldFdFile);
+    }
+    return EFI_ABORTED;
+  }
+
+  if (OldFdFile == NULL) {
+    Error ("FMMT", 0, 0003, "error Open FD file", "cannot Create a new FD file.");
+    if (NewFdFile != NULL) {
+      fclose (NewFdFile);
+    }
+    return EFI_ABORTED;
+  }
+
+
+  fseek(OldFdFile,0,SEEK_SET);
+  fseek(OldFdFile,0,SEEK_END);
+
+  FdLength = ftell(OldFdFile);
+
+  fseek(OldFdFile,0,SEEK_SET);
+  fseek(NewFdFile,0,SEEK_SET);
+
+  Buffer = malloc ((size_t)FdLength);
+
+  if (Buffer == NULL)  {
+    fclose(OldFdFile);
+    fclose(NewFdFile);
+    return EFI_ABORTED;
+  }
+
+  if (fread (Buffer, 1, (size_t) FdLength, OldFdFile) != (size_t) FdLength) {
+    Error ("FMMT", 0, 0003, "error reading FD file %s", OldFd);
+    free (Buffer);
+    fclose(OldFdFile);
+    fclose(NewFdFile);
+    return EFI_ABORTED;
+  }
+
+  if (fwrite (Buffer, 1, (size_t) FdLength, NewFdFile) != (size_t) FdLength) {
+    Error ("FMMT", 0, 0004, "error writing FD file", "cannot Create a new FD file.");
+    free (Buffer);
+    fclose(OldFdFile);
+    fclose(NewFdFile);
+    return EFI_ABORTED;
+  }
+  free (Buffer);
+  fclose(OldFdFile);
+  fclose (NewFdFile);
+
+  return EFI_SUCCESS;
+}
+
+
+/**
+  This function will assemble the filename, directory and extend and return the combined string.
+  Like FileName = file1, Dir = c:\temp extend = txt, the output string will be:
+  c:\temp\file1.txt.
+
+  @param[in]
+  @param[in]
+  @param[in]
+
+  @retrun     A string contain all the input information.
+
+**/
+CHAR8 *
+LibFilenameStrExtended (
+  IN CHAR8      *FileName,
+  IN CHAR8      *Dir,
+  IN CHAR8      *Extend
+)
+{
+  CHAR8 *RetStr;
+
+  RetStr = NULL;
+
+  if (FileName == NULL) {
+    return NULL;
+  }
+
+  if (Dir == NULL || Extend == NULL) {
+    return FileName;
+  }
+
+  RetStr = (CHAR8 *) malloc (strlen (FileName) +
+                             strlen (Dir) +
+                             strlen (Extend) +
+                             strlen ("%s%s.%s") +
+                             1);
+  if (RetStr == NULL) {
+    Error (NULL, 0, 4001, "Resource: Memory can't be allocated", NULL);
+    return NULL;
+  }
+
+  memset (RetStr, '\0', (strlen (FileName) + strlen (Dir) + strlen (Extend) + strlen ("%s%s.%s") + 1));
+
+  sprintf (RetStr, "%s%s.%s", Dir, FileName, Extend);
+
+  return RetStr;
+}
+
+/**
+  Delete a directory and files in it.
+
+  @param[in]   DirName   Name of the directory need to be deleted.
+
+  @return EFI_INVALID_PARAMETER
+  @return EFI_SUCCESS
+**/
+EFI_STATUS
+LibRmDir (
+  IN  CHAR8*  DirName
+)
+{
+  CHAR8*                 SystemCommand;
+
+  SystemCommand             = NULL;
+
+
+  if (DirName == NULL) {
+    return EFI_INVALID_PARAMETER;
+  }
+
+  if (access (DirName, 0) == -1){
+    return EFI_SUCCESS;
+  }
+
+  //
+  // Delete a directory and files in it.
+  //
+
+  SystemCommand = malloc (
+    strlen (RMDIR_STR) +
+    strlen (DirName)     +
+    1
+    );
+   if (SystemCommand == NULL) {
+     Error (NULL, 0, 4001, "Resource: Memory can't be allocated", NULL);
+     return EFI_ABORTED;
+   }
+
+  sprintf (
+    SystemCommand,
+    RMDIR_STR,
+    DirName
+    );
+
+  if (system (SystemCommand) != EFI_SUCCESS) {
+    free(SystemCommand);
+    return EFI_ABORTED;
+  }
+  free(SystemCommand);
+
+  return EFI_SUCCESS;
+}
+
+EFI_STATUS
+LibGenExtFile(
+CONST EFI_FIRMWARE_VOLUME_EXT_HEADER *ExtPtr,
+FILE *InfFile
+)
+{
+  CHAR8   *TempDir;
+  FILE    *ExtFile;
+  CHAR8   OutputExtFile[_MAX_PATH];
+  CHAR8   Line[512];
+  size_t  Len;
+
+  TempDir = NULL;
+
+  TempDir = getcwd(NULL, _MAX_PATH);
+  if (strlen (TempDir) + strlen(OS_SEP_STR) + strlen (TEMP_DIR_NAME) > _MAX_PATH - 1) {
+    Error("FMMT", 0, 1001,  "The directory is too long.", "");
+    return EFI_ABORTED;
+  }
+  strncat (TempDir, OS_SEP_STR, _MAX_PATH - strlen (TempDir) -1);
+  strncat (TempDir, TEMP_DIR_NAME, _MAX_PATH - strlen (TempDir) -1);
+
+  mkdir(TempDir, S_IRWXU | S_IRWXG | S_IRWXO);
+
+  sprintf(
+    Line,
+    "%c%08X-%04X-%04X-%02X%02X-%02X%02X%02X%02X%02X%02X%d.ext",
+    OS_SEP,
+    (unsigned)ExtPtr->FvName.Data1,
+    ExtPtr->FvName.Data2,
+    ExtPtr->FvName.Data3,
+    ExtPtr->FvName.Data4[0],
+    ExtPtr->FvName.Data4[1],
+    ExtPtr->FvName.Data4[2],
+    ExtPtr->FvName.Data4[3],
+    ExtPtr->FvName.Data4[4],
+    ExtPtr->FvName.Data4[5],
+    ExtPtr->FvName.Data4[6],
+    ExtPtr->FvName.Data4[7],
+    ExtPtr->ExtHeaderSize
+    );
+  if (strlen (TempDir) + strlen (Line) > _MAX_PATH - 1) {
+    Error("FMMT", 0, 1001,  "The directory is too long.", "");
+    return EFI_ABORTED;
+  }
+  strncpy (OutputExtFile, TempDir, _MAX_PATH - 1);
+  OutputExtFile[_MAX_PATH - 1] = 0;
+  strncat (OutputExtFile, Line, _MAX_PATH - strlen (OutputExtFile) - 1);
+
+
+  ExtFile = fopen(OutputExtFile, "wb+");
+  if (ExtFile == NULL) {
+    return EFI_ABORTED;
+  }
+
+  if (fwrite(ExtPtr, 1, ExtPtr->ExtHeaderSize, ExtFile) != ExtPtr->ExtHeaderSize) {
+    fclose(ExtFile);
+    return EFI_ABORTED;
+  }
+
+  fclose(ExtFile);
+
+  strcpy (Line, "EFI_FV_EXT_HEADER_FILE_NAME = ");
+  if (strlen (Line) + strlen (OutputExtFile) + 1 > sizeof(Line) / sizeof (CHAR8) - 1) {
+    Error("FMMT", 0, 1001,  "The directory is too long.", "");
+    return EFI_ABORTED;
+  }
+  strncat (Line, OutputExtFile, sizeof(Line) / sizeof (CHAR8) - strlen (Line) - 1);
+  strncat (Line, "\n", sizeof(Line) / sizeof (CHAR8) - strlen (Line) - 1);
+  Len = strlen(Line);
+  if (fwrite(Line, 1, Len, InfFile) != Len) {
+    return EFI_ABORTED;
+  }
+
+  return EFI_SUCCESS;
+}
+
+/**
+  Delete a file.
+
+  @param[in]   FileName   Name of the file need to be deleted.
+
+  @return EFI_INVALID_PARAMETER
+  @return EFI_SUCCESS
+**/
+EFI_STATUS
+LibFmmtDeleteFile(
+  IN   CHAR8    *FileName
+)
+{
+  CHAR8*                 SystemCommand;
+  CHAR8                  *TemDir;
+
+  SystemCommand             = NULL;
+  TemDir                    = NULL;
+
+
+  if (FileName == NULL) {
+    return EFI_INVALID_PARAMETER;
+  }
+
+  // if the FileName is not in TemDir, we don't need to delete.
+  TemDir = getcwd (NULL, _MAX_PATH);
+  if (*(TemDir + strlen(TemDir) - 1) == OS_SEP) {
+    *(TemDir + strlen(TemDir) - 1) = '\0';
+  }
+  if (strlen (TemDir) + strlen (OS_SEP_STR) + strlen (TEMP_DIR_NAME) > _MAX_PATH - 1) {
+    Error (NULL, 0, 2000, "Path: The current path is too long.", NULL);
+    return EFI_ABORTED;
+  }
+  strncat (TemDir, OS_SEP_STR, _MAX_PATH - strlen (TemDir) - 1);
+  strncat (TemDir, TEMP_DIR_NAME, _MAX_PATH - strlen (TemDir) - 1);
+  if (strstr(FileName, TemDir) == NULL) {
+    return EFI_SUCCESS;
+  }
+
+  //
+  // Delete a file
+  //
+
+  SystemCommand = malloc (
+    strlen (DEL_STR) +
+    strlen (FileName)     +
+    1
+    );
+   if (SystemCommand == NULL) {
+     Error (NULL, 0, 4001, "Resource: Memory can't be allocated", NULL);
+     return EFI_ABORTED;
+   }
+
+  sprintf (
+    SystemCommand,
+    DEL_STR,
+    FileName
+    );
+
+  if (system (SystemCommand) != EFI_SUCCESS) {
+    free(SystemCommand);
+    return EFI_ABORTED;
+  }
+  free(SystemCommand);
+
+  return EFI_SUCCESS;
+
+}
+
+
+/**
+
+  Free the whole Fd data structure.
+
+  @param[in]  Fd  The pointer point to the Fd data structure.
+
+**/
+VOID
+LibFmmtFreeFd (
+  FIRMWARE_DEVICE *Fd
+  )
+{
+  FV_INFORMATION   *CurrentFv;
+  FV_INFORMATION   *TempFv;
+  ENCAP_INFO_DATA  *EncapData1;
+  ENCAP_INFO_DATA  *EncapData2;
+
+  CurrentFv        = NULL;
+  TempFv           = NULL;
+  EncapData1       = NULL;
+  EncapData2       = NULL;
+
+  if (Fd == NULL) {
+    return;
+  }
+
+  CurrentFv = Fd->Fv;
+
+  do {
+    TempFv = CurrentFv;
+    CurrentFv = CurrentFv->FvNext;
+
+    free (TempFv->FvHeader);
+
+    if (TempFv->FvExtHeader != NULL) {
+      free (TempFv->FvExtHeader);
+    }
+    if (TempFv->FvUiName) {
+      free(TempFv->FvUiName);
+    }
+
+    //
+    // Free encapsulate data;
+    //
+    EncapData1 = TempFv->EncapData;
+
+    while (EncapData1 != NULL) {
+
+      EncapData2 = EncapData1;
+      EncapData1 = EncapData1->NextNode;
+
+      if (EncapData2->Data != NULL) {
+        free (EncapData2->Data);
+      }
+    if (EncapData2->FvExtHeader != NULL) {
+      free(EncapData2->FvExtHeader);
+    }
+      free (EncapData2);
+      EncapData2 = NULL;
+    }
+
+    EncapData1 = NULL;
+
+    free (TempFv);
+    TempFv = NULL;
+
+  } while (CurrentFv != NULL);
+
+  CurrentFv = NULL;
+  free (Fd);
+  Fd = NULL;
+
+  return;
+}
+
+/**
+  Generate the compressed section with specific type.
+  Type could be EFI_STANDARD_COMPRESSION or EFI_NOT_COMPRESSED
+
+  @param[in]  InputFileName    File name of the raw data.
+  @param[in]  OutPutFileName   File name of the sectioned data.
+  @param[in]  CompressionType  The compression type.
+
+  @return  EFI_INVALID_PARAMETER
+  @return  EFI_ABORTED
+  @return  EFI_OUT_OF_RESOURCES
+  @return  EFI_SUCCESS
+
+**/
+EFI_STATUS
+LibGenCompressedSection (
+  CHAR8         *InputFileName,
+  CHAR8         *OutPutFileName,
+  UINT8         CompressionType
+)
+{
+  //FILE                        *UnCompressFile;
+  //FILE                        *CompressedFile;
+  //VOID                        *UnCompressedBuffer;
+  //VOID                        *CompressedBuffer;
+  //UINT32                      UnCompressedSize;
+  //UINT32                      CompressedSize;
+  //CHAR8                       *TempName;
+  //CHAR8                       *TemDir;
+  //EFI_STATUS                  Status;
+
+  //UnCompressFile     = NULL;
+  //CompressedFile     = NULL;
+  //UnCompressedBuffer = NULL;
+  //CompressedBuffer   = NULL;
+  //TempName           = NULL;
+  //TemDir             = NULL;
+  //UnCompressedSize   = 0;
+  //CompressedSize     = 0;
+
+  if ( InputFileName == NULL ||
+       OutPutFileName == NULL) {
+    printf ("Error while generate compressed section!\n");
+    return EFI_INVALID_PARAMETER;
+  }
+
+  if (CompressionType == EFI_STANDARD_COMPRESSION) {
+    /*
+
+    UnCompressFile = fopen (InputFileName, "rb");
+    if (UnCompressFile == NULL) {
+      printf ("Error while open file %s \n", InputFileName);
+      return EFI_ABORTED;
+    }
+
+    TemDir = _getcwd (NULL, _MAX_PATH);
+    sprintf(TemDir, "%s\\%s", TemDir, TEMP_DIR_NAME);
+
+    TempName= LibFilenameStrExtended (strrchr(CloneString (tmpnam (NULL)),'\\'), TemDir, "comp");
+
+    CompressedFile = fopen (TempName, "wb+");
+    if (CompressedFile == NULL) {
+      printf ("Error while open file %s \n", TempName);
+      return EFI_ABORTED;
+    }
+
+    //
+    // Get the original file size;
+    //
+    fseek(UnCompressFile,0,SEEK_SET);
+    fseek(UnCompressFile,0,SEEK_END);
+
+    UnCompressedSize = ftell(UnCompressFile);
+
+    fseek(UnCompressFile,0,SEEK_SET);
+
+    UnCompressedBuffer = malloc (UnCompressedSize);
+
+    if (UnCompressedBuffer == NULL) {
+      printf("Error while allocate memory! \n");
+      return EFI_OUT_OF_RESOURCES;
+    }
+
+    CompressedBuffer = malloc (UnCompressedSize);
+
+    if (CompressedBuffer == NULL) {
+      printf("Error while allocate memory! \n");
+      return EFI_OUT_OF_RESOURCES;
+    }
+
+    if (fread (UnCompressedBuffer, 1, (size_t) UnCompressedSize, UnCompressFile) == (size_t) UnCompressedSize) {
+      CompressedSize = UnCompressedSize;
+
+      Status = EfiCompress ( UnCompressedBuffer,
+                             UnCompressedSize,
+                             CompressedBuffer,
+                             &CompressedSize);
+
+      if (EFI_ERROR(Status)) {
+        printf("Error while do compress operation! \n");
+        return EFI_ABORTED;
+      }
+
+      if (CompressedSize > UnCompressedSize) {
+        printf("Error while do compress operation! \n");
+        return EFI_ABORTED;
+      }
+    } else {
+      printf("Error while reading file %s! \n", InputFileName);
+      return EFI_ABORTED;
+    }
+
+    //
+    // Write the compressed data into output file
+    //
+    if (fwrite (CompressedBuffer, 1, (size_t) CompressedSize, CompressedFile) != (size_t) CompressedSize) {
+      Error ("FMMT", 0, 0004, "error writing %s file", OutPutFileName);
+      fclose(UnCompressFile);
+      fclose (CompressedFile);
+      return EFI_ABORTED;
+    }
+
+    fclose(UnCompressFile);
+    fclose (CompressedFile);
+    */
+
+    //
+    // Call GenSec tool to generate the compressed section.
+    //
+    LibCreateFfsSection(NULL, InputFileName, NULL, EFI_SECTION_COMPRESSION, OutPutFileName, NULL, NULL, NULL, 0, 0, "PI_STD");
+
+  } else if (CompressionType == EFI_NOT_COMPRESSED) {
+
+      LibCreateFfsSection(NULL, InputFileName, NULL, EFI_SECTION_COMPRESSION, OutPutFileName, NULL, NULL, NULL, 0, 0, "PI_NONE");
+
+  } else {
+    printf ("Error while generate compressed section, unknown compression type! \n");
+    return EFI_INVALID_PARAMETER;
+  }
+
+
+  return EFI_SUCCESS;
+}
+
+EFI_STATUS
+LibEncapNewFvFile(
+  IN  FV_INFORMATION   *FvInFd,
+  IN  CHAR8            *TemDir,
+  IN  ENCAP_INFO_DATA  *CurrentEncapData,
+  IN  UINT32           Level_Break,
+  OUT FFS_INFORMATION  **OutputFile
+)
+{
+  EFI_STATUS                  Status;
+  UINT32                      ParentType;
+  UINT8                       ParentLevel;
+  UINT32                      Type;
+  UINT8                       Level;
+  CHAR8                       *InfFileName;
+  FILE                        *InfFile;
+  ENCAP_INFO_DATA             *LocalEncapData;
+  ENCAP_INFO_DATA             *LocalEncapDataTemp;
+  ENCAP_INFO_DATA             *LocalEncapDataNext;
+  BOOLEAN                     FfsFoundFlag;
+  UINT32                      Index;
+  UINT32                      OuterIndex;
+  CHAR8                       *ExtractionTool;
+  BOOLEAN                     IsLastLevelFfs;
+  BOOLEAN                     IsLeafFlagIgnore;
+  BOOLEAN                     FirstInFlag;
+  BOOLEAN                     OutputFileNameListFlag;
+  CHAR8                       *InputFileName;
+  CHAR8                       *OutputFileName;
+  FFS_INFORMATION             *OutputFileNameList;
+  FFS_INFORMATION             *ChildFileNameList;
+  FFS_INFORMATION             *NewFileNameList;
+  CHAR8                       *FvGuidName;
+  UINT16                      GuidAttributes;
+  UINT16                      GuidDataOffset;
+  BOOLEAN                     IsRootFv;
+  BOOLEAN                     IsLargeFile;
+  UINT32                      EncapFvStart;
+  UINT32                      EncapFvIndex;
+  CHAR8                       *TmpFileName;
+  FILE                        *TmpFile;
+  FILE                        *InputFile;
+  FILE                        *OutFile;
+  UINT32                      InputFileSize;
+  UINT32                      OutputFileSize;
+  UINT32                      LargeFileSize;
+  UINT8                       *Buffer = NULL;
+  UINT8                       SectionHeader[4] = { 0x00, 0x00, 0x00, 0x00 };
+  UINT32                      Id;
+  UINT32                      SubFvId;
+  UINT32                      header;
+  UINT8                       AlignN;
+  UINT8                       AlignV[1] = {0xFF};
+  AlignN                      = 0;
+  Id                          = 0;
+  InputFileSize               = 0;
+  EncapFvIndex                = 0;
+  Index                       = 0;
+  OuterIndex                  = 0;
+  ParentType                  = 0;
+  ParentLevel                 = 0;
+  Type                        = 0;
+  Level                       = 0;
+  SubFvId                     = 0;
+  FfsFoundFlag                = FALSE;
+  LocalEncapDataTemp          = NULL;
+  LocalEncapDataNext          = NULL;
+  ExtractionTool              = NULL;
+  InputFileName               = NULL;
+  OutputFileName              = NULL;
+  IsLastLevelFfs              = TRUE;
+  IsLeafFlagIgnore            = FALSE;
+  FirstInFlag                 = TRUE;
+  FvGuidName                  = NULL;
+  OutputFileNameListFlag      = TRUE;
+  IsLargeFile                 = FALSE;
+  OutputFileSize              = 0;
+  LargeFileSize               = 0x1000000;
+
+
+  OutputFileNameList = (FFS_INFORMATION *)malloc(sizeof(FV_INFORMATION));
+  if (OutputFileNameList == NULL) {
+    Error ("FMMT", 0, 0004, "Out of resource, memory allocation failed! \n", "");
+    return EFI_OUT_OF_RESOURCES;
+  }
+  OutputFileNameList->FFSName = NULL;
+  OutputFileNameList->InFvId = 0;
+  OutputFileNameList->IsFFS = FALSE;
+  OutputFileNameList->ParentLevel = 0;
+  OutputFileNameList->Next = NULL;
+  OutputFileNameList->UiNameSize = 0;
+  OutputFileNameList->Depex = NULL;
+  OutputFileNameList->DepexLen = 0;
+  OutputFileNameList->FfsFoundFlag = FALSE;
+
+  ChildFileNameList = (FFS_INFORMATION *)malloc(sizeof(FV_INFORMATION));
+  if (ChildFileNameList == NULL) {
+    Error ("FMMT", 0, 0004, "Out of resource, memory allocation failed! \n", "");
+    return EFI_OUT_OF_RESOURCES;
+  }
+  ChildFileNameList->FFSName = NULL;
+  ChildFileNameList->InFvId = 0;
+  ChildFileNameList->ParentLevel = 0;
+  ChildFileNameList->Next = NULL;
+  ChildFileNameList->IsFFS = FALSE;
+  ChildFileNameList->UiNameSize = 0;
+  ChildFileNameList->Depex = NULL;
+  ChildFileNameList->DepexLen = 0;
+  ChildFileNameList->FfsFoundFlag = FALSE;
+  //
+  // Encapsulate from the lowest FFS file level.
+  //
+    LocalEncapData = CurrentEncapData;
+    if (LocalEncapData == NULL) {
+        LocalEncapData = FvInFd->EncapData;
+    }
+    Level = LocalEncapData->Level;
+    Type = LocalEncapData->Type;
+
+  if (CurrentEncapData == NULL) {
+    LocalEncapData = FvInFd->EncapData;
+    while (LocalEncapData != NULL) {
+      if (LocalEncapData->Type == FMMT_ENCAP_TREE_FFS) {
+        LocalEncapDataTemp = LocalEncapData->RightNode;
+        while (LocalEncapDataTemp != NULL) {
+            LocalEncapDataNext = LocalEncapDataTemp->NextNode;
+            if (LocalEncapDataNext != NULL && LocalEncapDataNext->NextNode != NULL) {
+
+                LibEncapNewFvFile(FvInFd, TemDir, LocalEncapDataTemp, 1, &ChildFileNameList);
+                ChildFileNameList->ParentLevel = LocalEncapDataTemp->Level -1;
+                if (FvInFd->ChildFvFFS == NULL) {
+                    FvInFd->ChildFvFFS = ChildFileNameList;
+                } else {
+                    NewFileNameList = FvInFd->ChildFvFFS;
+                    while (NewFileNameList->Next != NULL) {
+                        NewFileNameList = NewFileNameList->Next;
+                    }
+                    NewFileNameList->Next = ChildFileNameList;
+                }
+            }
+            LocalEncapDataTemp = LocalEncapDataTemp->RightNode;
+        }
+      }
+
+      if (LocalEncapData->Level > Level) {
+        if (LocalEncapData->Type == FMMT_ENCAP_TREE_FFS) {
+            ParentLevel = Level;
+            ParentType  = Type;
+        }
+        Level       = LocalEncapData->Level;
+        Type        = LocalEncapData->Type;
+      }
+      LocalEncapData = LocalEncapData->NextNode;
+    }
+  } else {
+    LocalEncapData = CurrentEncapData;
+    while (LocalEncapData != NULL) {
+        if (LocalEncapData->Level > Level) {
+            if (LocalEncapData->Type == FMMT_ENCAP_TREE_FFS) {
+                ParentLevel = Level;
+                ParentType  = Type;
+            }
+            Level       = LocalEncapData->Level;
+            Type        = LocalEncapData->Type;
+        }
+        LocalEncapData = LocalEncapData->NextNode;
+    }
+  }
+
+  do {
+    switch (ParentType) {
+      case FMMT_ENCAP_TREE_FV:
+        OutputFileNameListFlag = TRUE;
+        EncapFvStart = 0;
+    for(OuterIndex=0;OutputFileNameListFlag;OuterIndex++){
+        //
+        // Generate FV.inf attributes.
+        //
+        InfFileName = LibFilenameStrExtended (strrchr(GenTempFile (),OS_SEP), TemDir, "inf");
+    FirstInFlag = TRUE;
+
+        InfFile = fopen (InfFileName, "wt+");
+
+        if (InfFile == NULL) {
+          Error ("FMMT", 0, 0004, "Could not open inf file %s to store FV information! \n", "");
+          free (OutputFileNameList);
+          free (ChildFileNameList);
+          return EFI_ABORTED;
+        }
+
+        if (CurrentEncapData == NULL) {
+           LocalEncapData = FvInFd->EncapData;
+        } else {
+            LocalEncapData = CurrentEncapData;
+        }
+
+        while (LocalEncapData->NextNode != NULL) {
+          if (LocalEncapData->Level == ParentLevel) {
+             break;
+          }
+          LocalEncapData = LocalEncapData->NextNode;
+        }
+
+        if (((EFI_FIRMWARE_VOLUME_HEADER *)(LocalEncapData->Data))->ExtHeaderOffset != 0) {
+          //
+          // FV GUID Name memory allocation
+          //
+          FvGuidName = (CHAR8 *) malloc (255);
+
+          if (FvGuidName == NULL) {
+            Error ("FMMT", 0, 0004, "Out of resource, memory allocation failed! \n", "");
+            fclose (InfFile);
+            free (OutputFileNameList);
+            free (ChildFileNameList);
+            return EFI_ABORTED;
+          }
+
+          memset(FvGuidName, '\0', 255);
+
+          sprintf(
+            FvGuidName,
+            "%08X-%04X-%04X-%02X%02X-%02X%02X%02X%02X%02X%02X\n",
+            LocalEncapData->FvExtHeader->FvName.Data1,
+            LocalEncapData->FvExtHeader->FvName.Data2,
+            LocalEncapData->FvExtHeader->FvName.Data3,
+            LocalEncapData->FvExtHeader->FvName.Data4[0],
+            LocalEncapData->FvExtHeader->FvName.Data4[1],
+            LocalEncapData->FvExtHeader->FvName.Data4[2],
+            LocalEncapData->FvExtHeader->FvName.Data4[3],
+            LocalEncapData->FvExtHeader->FvName.Data4[4],
+            LocalEncapData->FvExtHeader->FvName.Data4[5],
+            LocalEncapData->FvExtHeader->FvName.Data4[6],
+            LocalEncapData->FvExtHeader->FvName.Data4[7]
+          );
+
+        } else {
+          FvGuidName = NULL;
+        }
+
+
+        if (ParentLevel == 1) {
+          Status = LibFvHeaderOptionToStr((EFI_FIRMWARE_VOLUME_HEADER *)LocalEncapData->Data, InfFile, TRUE);
+        } else {
+          Status = LibFvHeaderOptionToStr((EFI_FIRMWARE_VOLUME_HEADER *)LocalEncapData->Data, InfFile, FALSE);
+        }
+
+
+        if (EFI_ERROR (Status)) {
+          Error ("FMMT", 0, 0004, "error while encapsulate FD Image", "generate FV INF file [Options] section failed.");
+          fclose (InfFile);
+          free (OutputFileNameList);
+          free (ChildFileNameList);
+          return Status;
+        }
+
+        Status = LibFvHeaderAttributeToStr(((EFI_FIRMWARE_VOLUME_HEADER *)LocalEncapData->Data)->Attributes, InfFile);
+
+        if (EFI_ERROR (Status)) {
+          Error ("FMMT", 0, 0004, "error while encapsulate FD Image", "Generate FV header attribute failed");
+          fclose (InfFile);
+          free (OutputFileNameList);
+          free (ChildFileNameList);
+          return Status;
+        }
+        if (LocalEncapData->FvExtHeader != NULL) {
+          Status = LibGenExtFile(LocalEncapData->FvExtHeader, InfFile);
+          if (EFI_ERROR(Status)) {
+            Error("FMMT", 0, 0004, "error while encapsulate FD Image", "Generate FV EXT header failed");
+            fclose (InfFile);
+            free (OutputFileNameList);
+            free (ChildFileNameList);
+            return Status;
+          }
+          FvGuidName = NULL;
+        }
+
+        if (CurrentEncapData != NULL) {
+            for (Index = 0; Index <= FvInFd->FfsNumbers; Index++) {
+                if ((memcmp(&FvInFd->FfsAttuibutes[Index].GuidName, &(CurrentEncapData->FvExtHeader->FvName), sizeof(EFI_GUID)) == 0)) {
+                    SubFvId = Index;
+                    break;
+                }
+            }
+        }
+        //
+        // Found FFSs from Fv structure.
+        //
+        FfsFoundFlag = FALSE;
+        IsRootFv = FALSE;
+        for (Index=0; Index <= FvInFd->FfsNumbers; Index++) {
+            if (OutputFileNameList != NULL && OutputFileNameList->FFSName != NULL && OutputFileNameList->IsFFS == FALSE){
+                break;
+            }
+            if (OutputFileNameList != NULL && OutputFileNameList->FFSName != NULL && OutputFileNameList->IsFFS == TRUE){
+                if (Index == EncapFvIndex) {
+                    if (FirstInFlag) {
+                            Status = LibAddFfsFileToFvInf (OutputFileNameList->FFSName, InfFile, TRUE);
+                            FirstInFlag = FALSE;
+                        } else {
+                            Status = LibAddFfsFileToFvInf (OutputFileNameList->FFSName, InfFile, FALSE);
+                        }
+                        if (EFI_ERROR (Status)) {
+                            Error ("FMMT", 0, 0004, "error while encapsulate FD Image", "Generate FV inf file [files] section failed!");
+                            fclose (InfFile);
+                            free (OutputFileNameList);
+                            free (ChildFileNameList);
+                            return Status;
+                        }
+                }
+            }
+
+            NewFileNameList = FvInFd->ChildFvFFS;
+            while (NewFileNameList != NULL && NewFileNameList -> FFSName != NULL) {
+                if (NewFileNameList -> ParentLevel == ParentLevel && Index == NewFileNameList->InFvId && NewFileNameList->FfsFoundFlag==TRUE) {
+                    if (FirstInFlag) {
+                        Status = LibAddFfsFileToFvInf (NewFileNameList->FFSName, InfFile, TRUE);
+                        FirstInFlag = FALSE;
+                    } else {
+                        Status = LibAddFfsFileToFvInf (NewFileNameList->FFSName, InfFile, FALSE);
+                    }
+                    if (EFI_ERROR (Status)) {
+                        Error ("FMMT", 0, 0004, "error while encapsulate FD Image", "Generate FV inf file [files] section failed!");
+                        fclose (InfFile);
+                        free (OutputFileNameList);
+                        free (ChildFileNameList);
+                        return Status;
+                    }
+                }
+                NewFileNameList = NewFileNameList->Next;
+            }
+
+            if (FvInFd->FfsAttuibutes[Index].IsHandle==TRUE) {
+                continue;
+            }
+            if (SubFvId > 0 && Index < SubFvId) {
+                continue;
+            }
+
+          //
+          // For the last level FFS, the level below FFSs we should not care the IsLeaf Flag.
+          //
+          if (IsLastLevelFfs) {
+            IsLeafFlagIgnore = TRUE;
+            } else {
+              IsLeafFlagIgnore = FvInFd->FfsAttuibutes[Index].IsLeaf;
+            }
+
+          if (FvInFd->FfsAttuibutes[Index].Level >= ParentLevel + 1 && IsLeafFlagIgnore) {
+            if (FirstInFlag) {
+        if (FvInFd->FfsAttuibutes[Index].Level < 0xFF) {
+          FfsFoundFlag = TRUE;
+          Status = LibAddFfsFileToFvInf (FvInFd->FfsAttuibutes[Index].FfsName, InfFile, TRUE);
+          FirstInFlag = FALSE;
+          FvInFd->FfsAttuibutes[Index].IsHandle=TRUE;
+          EncapFvStart = Index;
+        }
+
+              if (EFI_ERROR (Status)) {
+                  Error ("FMMT", 0, 0004, "error while encapsulate FD Image", "Generate FV inf file [files] section failed!");
+                  fclose (InfFile);
+                  free (OutputFileNameList);
+                  free (ChildFileNameList);
+                  return Status;
+              }
+              if (Index == 0) {
+                // Root FV need to include all FFS files.
+                IsRootFv = TRUE;
+              }
+            } else {
+          if (FvInFd->FfsAttuibutes[Index].Level < 0xFF) {
+          FfsFoundFlag = TRUE;
+          Status = LibAddFfsFileToFvInf (FvInFd->FfsAttuibutes[Index].FfsName, InfFile, FALSE);
+          FvInFd->FfsAttuibutes[Index].IsHandle=TRUE;
+        }
+
+                if (EFI_ERROR (Status)) {
+                  Error ("FMMT", 0, 0004, "error while encapsulate FD Image", "Generate FV inf file [files] section failed!");
+                  fclose (InfFile);
+                  free (OutputFileNameList);
+                  free (ChildFileNameList);
+                  return Status;
+                }
+                if (Index == 0) {
+                  // Root FV need to include all FFS files.
+                  IsRootFv = TRUE;
+                }
+              }
+
+
+      //avoid a FV contain too many ffs files
+           if ((!IsRootFv) && (FvInFd->FfsAttuibutes[Index].FvLevel <= FvInFd->MulFvLevel) && (FvInFd->FfsAttuibutes[Index+1].FvLevel <= FvInFd->MulFvLevel) &&
+               (FvInFd->FfsAttuibutes[Index].FvLevel != FvInFd->FfsAttuibutes[Index+1].FvLevel) && (ParentLevel != 1) && (FvInFd->FfsAttuibutes[Index].Level != FvInFd->FfsAttuibutes[Index+1].Level) &&
+               FvInFd->FfsAttuibutes[Index].Level != 0xFF && FvInFd->FfsAttuibutes[Index+1].Level != 0xFF && FvInFd->FfsAttuibutes[Index+1].Level != 0x0){
+        FvInFd->FfsAttuibutes[Index].Level = 0;
+        break;
+      }else{
+        if (FvInFd->FfsAttuibutes[Index].Level != 0xFF){
+          FvInFd->FfsAttuibutes[Index].Level = 0;
+        }
+      }
+
+            }
+          }
+       // The Fv may has multiple level (> 2), when it is in the FvLevel == 2, we set the IsLastLevelFfs Flag
+       if (Index <=FvInFd->FfsNumbers && FvInFd->FfsAttuibutes[Index].FvLevel <= FvInFd->MulFvLevel) {
+           if (FvInFd->FfsAttuibutes[Index].FvLevel == 2) {
+               IsLastLevelFfs = FALSE;
+           }
+       }
+    if (!FfsFoundFlag){
+      OutputFileNameListFlag = FALSE;
+      if (OuterIndex > 0){
+        fclose (InfFile);
+        break;
+      }
+    }
+        //
+        // Create FV
+        //
+        fclose (InfFile);
+
+        EncapFvIndex = EncapFvStart;
+
+        OutputFileName= LibFilenameStrExtended (strrchr(GenTempFile (), OS_SEP), TemDir, "FV");
+
+        Status = LibEncapsulateFfsToFv (InfFileName, NULL, OutputFileName, FvGuidName, IsLargeFile);
+
+        if (EFI_ERROR (Status)) {
+          Error ("FMMT", 0, 0004, "error while encapsulate FD Image", "Generate FV failed!");
+          free (OutputFileNameList);
+          free (ChildFileNameList);
+          return Status;
+        }
+
+    OutputFileNameList->FFSName = (char *)malloc(strlen(OutputFileName)+1);
+    if (OutputFileNameList->FFSName == NULL) {
+      Error ("FMMT", 0, 0004, "Out of resource, memory allocation failed! \n", "");
+      return EFI_OUT_OF_RESOURCES;
+    }
+    memcpy((char *)OutputFileNameList->FFSName, (char *)OutputFileName, strlen(OutputFileName)+1);
+      if (CurrentEncapData != NULL) {
+        OutputFileNameList->InFvId = EncapFvIndex;
+        if (EncapFvIndex > 0) {
+            memcpy(OutputFileNameList->UiName,FvInFd->FfsAttuibutes[EncapFvIndex - 1].UiName, FvInFd->FfsAttuibutes[EncapFvIndex - 1].UiNameSize);
+            OutputFileNameList->UiNameSize = FvInFd->FfsAttuibutes[EncapFvIndex - 1].UiNameSize;
+            OutputFileNameList->Depex = FvInFd->FfsAttuibutes[EncapFvIndex - 1].Depex;
+            OutputFileNameList->DepexLen = FvInFd->FfsAttuibutes[EncapFvIndex - 1].DepexLen;
+            OutputFileNameList->FfsFoundFlag = FfsFoundFlag;
+        }
+      }
+    }
+        break;
+      case FMMT_ENCAP_TREE_FFS:
+
+        while(OutputFileNameList!= NULL && OutputFileNameList->FFSName != NULL){
+          InputFileName  = OutputFileNameList->FFSName;
+          OutputFileName= LibFilenameStrExtended (strrchr(GenTempFile (), OS_SEP), TemDir, "ffs");
+          LocalEncapData = CurrentEncapData;
+          if (LocalEncapData == NULL) {
+            LocalEncapData = FvInFd->EncapData;
+          }
+          while (LocalEncapData->NextNode != NULL) {
+            if (LocalEncapData->Level == ParentLevel) {
+        for(;LocalEncapData->NextNode != NULL;) {
+          if(LocalEncapData->FvExtHeader != NULL) {
+            break;
+          }
+          LocalEncapData = LocalEncapData->NextNode;
+        }
+                break;
+            }
+            LocalEncapData = LocalEncapData->NextNode;
+          }
+
+          if (LocalEncapData->FvExtHeader == NULL) {
+            Error ("FMMT", 0, 0004, "error while encapsulate FD Image", "Generate FFS file failed!");
+            free (OutputFileNameList);
+            free (ChildFileNameList);
+            return EFI_ABORTED;
+          }
+
+          if (OutputFileNameList->UiNameSize > 0) {
+              TmpFileName = LibFilenameStrExtended(strrchr(GenTempFile (), OS_SEP), TemDir, "tmp");
+              TmpFile = fopen(TmpFileName, "wb+");
+              if (TmpFile == NULL) {
+                 Error("FMMT", 0, 0004, "Could not open tmp file %s to store UI section information! \n", "");
+                 free (OutputFileNameList);
+                 free (ChildFileNameList);
+                 return EFI_ABORTED;
+              }
+             header = (OutputFileNameList->UiNameSize+4) | (EFI_SECTION_USER_INTERFACE << 24);
+             Index = 0;
+             while (header) {
+                 SectionHeader[Index] = header % 0x100;
+                 header /= 0x100;
+                 Index ++;
+             }
+             InputFile = fopen(InputFileName, "rb+");
+             if (InputFile == NULL) {
+               Error("FMMT", 0, 0004, "Could not open input file %s! \n", "");
+               fclose(TmpFile);
+               free (OutputFileNameList);
+               free (ChildFileNameList);
+               return EFI_ABORTED;
+             }
+             fseek(InputFile, 0, SEEK_SET);
+             fseek(InputFile, 0, SEEK_END);
+             InputFileSize = ftell(InputFile);
+             fseek(InputFile, 0, SEEK_SET);
+
+             Buffer = malloc(InputFileSize+OutputFileNameList->UiNameSize+4);
+             memcpy(Buffer, (CHAR16 *)SectionHeader, 4);
+             memcpy(Buffer + 4, (CHAR16 *)(OutputFileNameList->UiName), OutputFileNameList->UiNameSize);
+             if (fread(Buffer+4+OutputFileNameList->UiNameSize, 1, InputFileSize, InputFile) != InputFileSize) {
+               Error("FMMT", 0, 0004, "Could not open sec file %s to add UI section information! \n", "");
+               fclose(TmpFile);
+               fclose(InputFile);
+               free(Buffer);
+               free (OutputFileNameList);
+               free (ChildFileNameList);
+               return EFI_ABORTED;
+             }
+             fwrite(Buffer, 1, InputFileSize + OutputFileNameList->UiNameSize + 4, TmpFile);
+             free(Buffer);
+             fclose(TmpFile);
+             fclose(InputFile);
+             InputFileName = TmpFileName;
+          }
+          if (OutputFileNameList->DepexLen > 0) {
+              TmpFileName = LibFilenameStrExtended(strrchr(GenTempFile (), OS_SEP), TemDir, "tmp");
+              TmpFile = fopen(TmpFileName, "wb+");
+              if (TmpFile == NULL) {
+                  Error("FMMT", 0, 0004, "Could not open tmp file %s to store Depex section information! \n", "");
+                  free (OutputFileNameList);
+                  free (ChildFileNameList);
+                  return EFI_ABORTED;
+              }
+              InputFile = fopen(InputFileName, "rb+");
+              if (InputFile == NULL) {
+                Error("FMMT", 0, 0004, "Could not open input file %s! \n", "");
+                fclose(TmpFile);
+                free (OutputFileNameList);
+                free (ChildFileNameList);
+                return EFI_ABORTED;
+              }
+              fseek(InputFile, 0, SEEK_SET);
+              fseek(InputFile, 0, SEEK_END);
+              InputFileSize = ftell(InputFile);
+              fseek(InputFile, 0, SEEK_SET);
+              // make sure the section is 4 byte align
+              if (OutputFileNameList->DepexLen % 4 != 0) {
+                  AlignN = 4 - OutputFileNameList->DepexLen % 4;
+              }
+              Buffer = malloc(InputFileSize + OutputFileNameList->DepexLen + AlignN);
+              memcpy(Buffer, OutputFileNameList->Depex, OutputFileNameList->DepexLen);
+              if (AlignN != 0) {
+                  for (Index = 0; Index < AlignN; Index ++) {
+                      memcpy(Buffer + OutputFileNameList->DepexLen + Index, AlignV, 1);
+                  }
+              }
+              if (fread(Buffer + OutputFileNameList->DepexLen + AlignN, 1, InputFileSize, InputFile) != InputFileSize) {
+                  Error("FMMT", 0, 0004, "Could not open sec file %s to add Depex section information! \n", "");
+                  fclose(TmpFile);
+                  fclose(InputFile);
+                  free(Buffer);
+                  free (OutputFileNameList);
+                  free (ChildFileNameList);
+                  return EFI_ABORTED;
+              }
+              fwrite(Buffer, 1, InputFileSize + OutputFileNameList->DepexLen + AlignN, TmpFile);
+              free(Buffer);
+              fclose(TmpFile);
+              fclose(InputFile);
+              InputFileName = TmpFileName;
+         }
+         for (Id = FvInFd->FfsNumbers; Id <= FvInFd->FfsNumbers; Id--) {
+             if ((memcmp(&FvInFd->FfsAttuibutes[Id].GuidName, &(LocalEncapData->FvExtHeader->FvName), sizeof(EFI_GUID)) == 0)){
+                 if (access(FvInFd->FfsAttuibutes[Id].FfsName, 0) != -1) {
+                     Status = LibFmmtDeleteFile(FvInFd->FfsAttuibutes[Id].FfsName);
+                     if (EFI_ERROR(Status)) {
+                         Error("FMMT", 0, 0004, "error while encapsulate FD Image", "Delete the specified file failed!");
+                         free (OutputFileNameList);
+                         free (ChildFileNameList);
+                         return Status;
+                     }
+                     memset(FvInFd->FfsAttuibutes[Id].FfsName, '\0', _MAX_PATH);
+                     FvInFd->FfsAttuibutes[Id].Level = 0xFF;
+                     break;
+                 }
+             }
+         }
+         if (LocalEncapData->NextNode != NULL) {
+             LocalEncapDataTemp = LocalEncapData->NextNode;
+             if ((LocalEncapDataTemp->Type == FMMT_ENCAP_TREE_GUIDED_SECTION) || (LocalEncapDataTemp->Type == FMMT_ENCAP_TREE_COMPRESS_SECTION)) {
+                 Status = LibEncapSectionFileToFFS(EFI_FV_FILETYPE_FIRMWARE_VOLUME_IMAGE, InputFileName, OutputFileName, LocalEncapData->FvExtHeader->FvName, FALSE, "1");
+             }
+             else{
+                 Status = LibEncapSectionFileToFFS(EFI_FV_FILETYPE_FIRMWARE_VOLUME_IMAGE, InputFileName, OutputFileName, LocalEncapData->FvExtHeader->FvName, FALSE, FvInFd->AlignmentStr);
+             }
+         }
+         else{
+             Status = LibEncapSectionFileToFFS(EFI_FV_FILETYPE_FIRMWARE_VOLUME_IMAGE, InputFileName, OutputFileName, LocalEncapData->FvExtHeader->FvName, FALSE, FvInFd->AlignmentStr);
+         }
+      if (EFI_ERROR (Status)) {
+        Error ("FMMT", 0, 0004, "error while encapsulate FD Image", "Generate FFS file failed!");
+        free (OutputFileNameList);
+        free (ChildFileNameList);
+        return Status;
+      }
+      free(LocalEncapData->FvExtHeader);
+      LocalEncapData->FvExtHeader = NULL;
+      OutputFileNameList->FFSName = (char *)malloc(strlen(OutputFileName)+1);
+      if (OutputFileNameList->FFSName == NULL) {
+          Error ("FMMT", 0, 0004, "Out of resource, memory allocation failed! \n", "");
+          return EFI_OUT_OF_RESOURCES;
+      }
+      memcpy((char *)OutputFileNameList->FFSName, (char *)OutputFileName, strlen(OutputFileName)+1);
+      OutputFileNameList->IsFFS = TRUE;
+      if (OutputFileNameList->Next == NULL){
+          break;
+      }
+      OutputFileNameList = OutputFileNameList->Next;
+    }
+        break;
+      case FMMT_ENCAP_TREE_GUIDED_SECTION:
+      while(OutputFileNameList!= NULL && OutputFileNameList->FFSName != NULL){
+        //
+        // Create the guided section original data, do compress operation.
+        //
+        InputFileName  = OutputFileNameList->FFSName;
+        OutputFileName= LibFilenameStrExtended (strrchr(GenTempFile (), OS_SEP), TemDir, "compressed");
+
+        //
+        // Use the guided section header guid to find out compress application name.
+        //
+        LocalEncapData = CurrentEncapData;
+          if (LocalEncapData == NULL) {
+            LocalEncapData = FvInFd->EncapData;
+        }
+        while (LocalEncapData->NextNode != NULL) {
+          if (LocalEncapData->Level == ParentLevel) {
+            break;
+          }
+          LocalEncapData = LocalEncapData->NextNode;
+        }
+
+        ExtractionTool =
+          LookupGuidedSectionToolPath (
+            mParsedGuidedSectionTools,
+            (EFI_GUID *)LocalEncapData->Data
+            );
+        GuidDataOffset = *(UINT16 *) ((UINT8 *) LocalEncapData->Data + sizeof (EFI_GUID));
+        GuidAttributes = *(UINT16 *) ((UINT8 *) LocalEncapData->Data + sizeof (EFI_GUID) + sizeof (UINT16));
+
+        Status = LibCreateGuidedSectionOriginalData (InputFileName, ExtractionTool, OutputFileName);
+
+        if (EFI_ERROR (Status) || GuidDataOffset < sizeof (EFI_GUID_DEFINED_SECTION)) {
+          Error ("FMMT", 0, 0004, "error while encapsulate FD Image", "Compress guided data failed!");
+          free (OutputFileNameList);
+          free (ChildFileNameList);
+          return Status;
+        }
+
+        GuidDataOffset = GuidDataOffset - sizeof (EFI_GUID_DEFINED_SECTION);
+        InputFileName  = OutputFileName;
+        OutputFileName= LibFilenameStrExtended (strrchr(GenTempFile (), OS_SEP), TemDir, "guided");
+
+        Status = LibCreateFfsSection(NULL, InputFileName, NULL, EFI_SECTION_GUID_DEFINED, OutputFileName, NULL, NULL, LibFmmtGuidToStr((EFI_GUID *)LocalEncapData->Data), GuidDataOffset, GuidAttributes, NULL);
+        OutFile = fopen(OutputFileName, "rb+");
+        if (OutFile == NULL) {
+            Error("FMMT", 0, 0004, "Could not open the file %s! \n", "");
+            free (OutputFileNameList);
+            free (ChildFileNameList);
+            return EFI_ABORTED;
+        }
+        fseek(OutFile, 0, SEEK_SET);
+        fseek(OutFile, 0, SEEK_END);
+        OutputFileSize = ftell(OutFile);
+        fclose(OutFile);
+        if (OutputFileSize > LargeFileSize) {
+            IsLargeFile = TRUE;
+        }
+    OutputFileNameList->FFSName = (char *)malloc(strlen(OutputFileName)+1);
+    if (OutputFileNameList->FFSName == NULL) {
+      Error ("FMMT", 0, 0004, "Out of resource, memory allocation failed! \n", "");
+      return EFI_OUT_OF_RESOURCES;
+    }
+    memcpy((char *)OutputFileNameList->FFSName, (char *)OutputFileName, strlen(OutputFileName)+1);
+
+        if (EFI_ERROR (Status)) {
+          Error ("FMMT", 0, 0004, "error while encapsulate FD Image", "Generate guided section failed!");
+          free (OutputFileNameList);
+          free (ChildFileNameList);
+          return Status;
+        }
+        if (OutputFileNameList->Next == NULL){
+          break;
+       }
+       OutputFileNameList = OutputFileNameList->Next;
+    }
+        break;
+      case FMMT_ENCAP_TREE_COMPRESS_SECTION:
+        while(OutputFileNameList!= NULL && OutputFileNameList->FFSName != NULL){
+          InputFileName  = OutputFileNameList->FFSName;
+
+          OutputFileName= LibFilenameStrExtended (strrchr(GenTempFile (), OS_SEP), TemDir, "comsec");
+          LocalEncapData = CurrentEncapData;
+          if (LocalEncapData == NULL) {
+            LocalEncapData = FvInFd->EncapData;
+          }
+          while (LocalEncapData->NextNode != NULL) {
+            if (LocalEncapData->Level == ParentLevel) {
+              break;
+            }
+            LocalEncapData = LocalEncapData->NextNode;
+          }
+
+          Status = LibGenCompressedSection (InputFileName, OutputFileName, *(UINT8 *)(LocalEncapData->Data));
+      OutputFileNameList->FFSName = (char *)malloc(strlen(OutputFileName)+1);
+      if (OutputFileNameList->FFSName == NULL) {
+        Error ("FMMT", 0, 0004, "Out of resource, memory allocation failed! \n", "");
+        return EFI_OUT_OF_RESOURCES;
+      }
+      memcpy((char *)OutputFileNameList->FFSName, (char *)OutputFileName, strlen(OutputFileName)+1);
+
+          if (EFI_ERROR (Status)) {
+            Error ("FMMT", 0, 0004, "error while encapsulate FD Image", "Generate compressed section failed!");
+            free (OutputFileNameList);
+            free (ChildFileNameList);
+            return Status;
+          }
+          if (OutputFileNameList->Next == NULL){
+            break;
+          }
+          OutputFileNameList = OutputFileNameList->Next;
+        }
+        break;
+      case FMMT_ENCAP_TREE_FV_SECTION:
+        while(OutputFileNameList!= NULL && OutputFileNameList->FFSName != NULL){
+        InputFileName  = OutputFileNameList->FFSName;
+        OutputFileName= LibFilenameStrExtended (strrchr(GenTempFile (), OS_SEP), TemDir, "sec");
+
+        Status = LibCreateFfsSection(NULL, InputFileName, NULL, EFI_SECTION_FIRMWARE_VOLUME_IMAGE, OutputFileName, NULL, NULL, NULL, 0, 0, NULL);
+
+        if (EFI_ERROR (Status)) {
+          Error ("FMMT", 0, 0004, "error while encapsulate FD Image", "Generate FV section failed!");
+          free (OutputFileNameList);
+          free (ChildFileNameList);
+          return Status;
+        }
+
+        InputFileName  = OutputFileName;
+        OutputFileName= LibFilenameStrExtended (strrchr(GenTempFile (), OS_SEP), TemDir, "sec");
+
+        //
+        // Make it alignment.
+        //
+        Status = LibCreateFfsSection(FvInFd, InputFileName, NULL, 0, OutputFileName, NULL, NULL, NULL, 0, 0, NULL);
+        OutFile = fopen(OutputFileName, "rb+");
+        if (OutFile == NULL) {
+            Error("FMMT", 0, 0004, "Could not open the file %s! \n", "");
+            free (OutputFileNameList);
+            free (ChildFileNameList);
+            return EFI_ABORTED;
+        }
+        fseek(OutFile, 0, SEEK_SET);
+        fseek(OutFile, 0, SEEK_END);
+        OutputFileSize = ftell(OutFile);
+        fclose(OutFile);
+        if (OutputFileSize > LargeFileSize) {
+            IsLargeFile = TRUE;
+        }
+
+    OutputFileNameList->FFSName = (char *)malloc(strlen(OutputFileName)+1);
+    if (OutputFileNameList->FFSName == NULL) {
+      Error ("FMMT", 0, 0004, "Out of resource, memory allocation failed! \n", "");
+      return EFI_OUT_OF_RESOURCES;
+    }
+    memcpy((char *)OutputFileNameList->FFSName, (char *)OutputFileName, strlen(OutputFileName)+1);
+
+        if (EFI_ERROR (Status)) {
+          Error ("FMMT", 0, 0004, "error while encapsulate FD Image", "Generate FV section failed!");
+          free (OutputFileNameList);
+          free (ChildFileNameList);
+          return Status;
+        }
+        if (OutputFileNameList->Next == NULL){
+           break;
+        }
+        OutputFileNameList = OutputFileNameList->Next;
+    }
+        break;
+      default:
+        for (Id = FvInFd->FfsNumbers; Id <= FvInFd->FfsNumbers; Id--) {
+            if ((memcmp(&FvInFd->FfsAttuibutes[Id].GuidName, &(CurrentEncapData->FvExtHeader->FvName), sizeof(EFI_GUID)) == 0)){
+                FvInFd->FfsAttuibutes[Id].IsHandle = TRUE;
+                memcpy(OutputFileNameList->UiName, FvInFd->FfsAttuibutes[Id].UiName, FvInFd->FfsAttuibutes[Id].UiNameSize);
+                OutputFileNameList->UiNameSize = FvInFd->FfsAttuibutes[Id].UiNameSize;
+                OutputFileNameList->FFSName = FvInFd->FfsAttuibutes[Id].FfsName;
+                OutputFileNameList->Depex = FvInFd->FfsAttuibutes[Id].Depex;
+                OutputFileNameList->DepexLen = FvInFd->FfsAttuibutes[Id].DepexLen;
+                OutputFileNameList->FfsFoundFlag = TRUE;
+                OutputFileNameList->IsFFS = TRUE;
+                OutputFileNameList->InFvId = Id;
+                *OutputFile = OutputFileNameList;
+                return EFI_SUCCESS;
+            }
+        }
+    }
+
+    if (CurrentEncapData == NULL) {
+       LocalEncapData = FvInFd->EncapData;
+    } else {
+        if (OutputFileNameList != NULL && OutputFileNameList->FFSName != NULL && OutputFileNameList->IsFFS == TRUE) {
+          *OutputFile = OutputFileNameList;
+          return EFI_SUCCESS;
+        }
+        LocalEncapData = CurrentEncapData;
+    }
+    ParentLevel -= 1;
+
+    while (LocalEncapData->NextNode != NULL) {
+      if (LocalEncapData->Level == ParentLevel) {
+       LocalEncapDataTemp = LocalEncapData->NextNode;
+       if ((LocalEncapDataTemp != NULL) && (LocalEncapDataTemp->Level == ParentLevel)) {
+           ParentType = LocalEncapDataTemp->Type;
+           break;
+        }
+        ParentType = LocalEncapData->Type;
+        break;
+      }
+      LocalEncapData = LocalEncapData->NextNode;
+    }
+  } while (ParentLevel != Level_Break);
+
+  *OutputFile = OutputFileNameList;
+  return EFI_SUCCESS;
+
+}
+
+EFI_STATUS
+LibFindFvInEncapData (
+  ENCAP_INFO_DATA *EncapData,
+  UINT8 *Index
+)
+{
+  ENCAP_INFO_DATA *LocalEncapData;
+  LocalEncapData = EncapData;
+  if (LocalEncapData == NULL) {
+    Error("FMMT", 0, 0005, "error while find FV in Encapulate buffer", "Invalid parameters.");
+    return EFI_INVALID_PARAMETER;
+  }
+  while (LocalEncapData != NULL) {
+    if (LocalEncapData->RightNode != NULL) {
+      LibFindFvInEncapData (LocalEncapData->RightNode, Index);
+    }
+    if (LocalEncapData->Type == FMMT_ENCAP_TREE_FV) {
+      (*Index)++;
+    }
+    LocalEncapData = LocalEncapData->NextNode;
+  }
+    return EFI_SUCCESS;
+}
+
+EFI_STATUS
+LibLocateFvViaFvId (
+  IN     FIRMWARE_DEVICE     *FdData,
+  IN     CHAR8               *FvId,
+  IN OUT FV_INFORMATION      **FvInFd
+)
+{
+  UINT8                       FvIndex1;
+  UINT8                       FvIndex2;
+  BOOLEAN                     FvFoundFlag;
+  CHAR8*                      FvGuidName;
+  ENCAP_INFO_DATA             *LocalEncapData;
+  ENCAP_INFO_DATA             *LocalEncapDataRight;
+  ENCAP_INFO_DATA             *LocalEncapDataNext;
+  FvIndex1                    = 0;
+  FvIndex2                    = 0;
+  FvFoundFlag                 = FALSE;
+  FvGuidName                  = NULL;
+  LocalEncapDataNext          = NULL;
+  LocalEncapDataRight         = NULL;
+
+  if (FdData == NULL || FvId == NULL || FvInFd == NULL || FdData->Fv == NULL) {
+    Error ("FMMT", 0, 0005, "error while find FV in FD", "Invalid parameters.");
+    return EFI_INVALID_PARAMETER;
+  }
+
+  *FvInFd = FdData->Fv;
+
+  if (strlen(FvId) < 3) {
+    Error ("FMMT", 0, 0005, "error while find FV in FD", "Invalid FvId, please double check the FvId. You can use view operate to get the FvId information!");
+    return EFI_ABORTED;
+  }
+
+  FvGuidName = (CHAR8 *) malloc (255);
+  if (FvGuidName == NULL) {
+    Error ("FMMT", 0, 0005, "Resource: Memory can't be allocated", NULL);
+    return EFI_ABORTED;
+  }
+  memset(FvGuidName, '\0', 255);
+  LocalEncapData = NULL;
+
+  if (strlen(FvId) == 36) {
+    while (FvInFd != NULL) {
+      if (((*FvInFd)->FvExtHeader) != NULL) {
+        sprintf(
+          FvGuidName,
+          "%08X-%04X-%04X-%02X%02X-%02X%02X%02X%02X%02X%02X",
+          (*FvInFd)->FvExtHeader->FvName.Data1,
+          (*FvInFd)->FvExtHeader->FvName.Data2,
+          (*FvInFd)->FvExtHeader->FvName.Data3,
+          (*FvInFd)->FvExtHeader->FvName.Data4[0],
+          (*FvInFd)->FvExtHeader->FvName.Data4[1],
+          (*FvInFd)->FvExtHeader->FvName.Data4[2],
+          (*FvInFd)->FvExtHeader->FvName.Data4[3],
+          (*FvInFd)->FvExtHeader->FvName.Data4[4],
+          (*FvInFd)->FvExtHeader->FvName.Data4[5],
+          (*FvInFd)->FvExtHeader->FvName.Data4[6],
+          (*FvInFd)->FvExtHeader->FvName.Data4[7]);
+        if (strcmp(FvGuidName, FvId) == 0) {
+          FvId = (*FvInFd)->FvName;
+          break;
+        }
+      }
+      if ((*FvInFd)->MulFvLevel > 1) {
+        LocalEncapData = (*FvInFd) -> EncapData;
+        LocalEncapData = LocalEncapData->NextNode;
+        while (LocalEncapData != NULL) {
+          if (LocalEncapData->RightNode != NULL) {
+            LocalEncapDataRight = LocalEncapData->RightNode;
+            while (LocalEncapDataRight !=NULL) {
+              if (LocalEncapDataRight->NextNode != NULL) {
+                LocalEncapDataNext = LocalEncapDataRight->NextNode;
+                while (LocalEncapDataNext != NULL) {
+                  if (LocalEncapDataNext->Type == FMMT_ENCAP_TREE_FV) {
+                    if (LocalEncapDataNext->FvExtHeader != NULL) {
+                      sprintf(
+                          FvGuidName,
+                          "%08X-%04X-%04X-%02X%02X-%02X%02X%02X%02X%02X%02X",
+                          LocalEncapDataNext->FvExtHeader->FvName.Data1,
+                          LocalEncapDataNext->FvExtHeader->FvName.Data2,
+                          LocalEncapDataNext->FvExtHeader->FvName.Data3,
+                          LocalEncapDataNext->FvExtHeader->FvName.Data4[0],
+                          LocalEncapDataNext->FvExtHeader->FvName.Data4[1],
+                          LocalEncapDataNext->FvExtHeader->FvName.Data4[2],
+                          LocalEncapDataNext->FvExtHeader->FvName.Data4[3],
+                          LocalEncapDataNext->FvExtHeader->FvName.Data4[4],
+                          LocalEncapDataNext->FvExtHeader->FvName.Data4[5],
+                          LocalEncapDataNext->FvExtHeader->FvName.Data4[6],
+                          LocalEncapDataNext->FvExtHeader->FvName.Data4[7]);
+                          if (strcmp(FvGuidName, FvId) == 0)
+                          {
+                            sprintf(FvId, "%s%d", "FV", LocalEncapDataNext->FvId - 1);
+                            break;
+                          }
+
+                    }
+                  }
+                  LocalEncapDataNext = LocalEncapDataNext->NextNode;
+                }
+              }
+              LocalEncapDataRight = LocalEncapDataRight->RightNode;
+            }
+          }
+          if (LocalEncapData->Type == FMMT_ENCAP_TREE_FV) {
+            if (LocalEncapData->FvExtHeader != NULL) {
+              sprintf(
+                FvGuidName,
+                "%08X-%04X-%04X-%02X%02X-%02X%02X%02X%02X%02X%02X",
+                LocalEncapData->FvExtHeader->FvName.Data1,
+                LocalEncapData->FvExtHeader->FvName.Data2,
+                LocalEncapData->FvExtHeader->FvName.Data3,
+                LocalEncapData->FvExtHeader->FvName.Data4[0],
+                LocalEncapData->FvExtHeader->FvName.Data4[1],
+                LocalEncapData->FvExtHeader->FvName.Data4[2],
+                LocalEncapData->FvExtHeader->FvName.Data4[3],
+                LocalEncapData->FvExtHeader->FvName.Data4[4],
+                LocalEncapData->FvExtHeader->FvName.Data4[5],
+                LocalEncapData->FvExtHeader->FvName.Data4[6],
+                LocalEncapData->FvExtHeader->FvName.Data4[7]);
+
+                if (strcmp(FvGuidName, FvId) == 0) {
+                  sprintf(FvId, "%s%d", "FV", LocalEncapData->FvId - 1);
+                  break;
+                }
+            }
+          }
+          LocalEncapData = LocalEncapData->NextNode;
+        }
+      }
+      if ((*FvInFd)->FvNext == 0) {
+        break;
+      }
+      *FvInFd = (*FvInFd)->FvNext;
+    }
+  }
+  *FvInFd = FdData->Fv;
+  FvIndex1 = (UINT8) atoi (FvId + 2);
+
+  while (FvInFd != NULL) {
+    if (((*FvInFd)->FvName) != NULL) {
+      FvIndex2 = (UINT8) atoi ((*FvInFd)->FvName + 2);
+      LocalEncapData = (*FvInFd)->EncapData;
+      LibFindFvInEncapData (LocalEncapData, &FvIndex2);
+
+      if ((FvIndex2 - 1 >= FvIndex1)) {
+        FvFoundFlag = TRUE;
+        break;
+      }
+      if ((*FvInFd)->FvNext == 0) {
+        break;
+      }
+    }
+    *FvInFd = (*FvInFd)->FvNext;
+  }
+  if (FvGuidName != NULL) {
+    free (FvGuidName);
+  }
+  //
+  // The specified FV id has issue, can not find the FV in FD.
+  //
+  if (!FvFoundFlag) {
+    Error ("FMMT", 0, 0005, "error while find FV in FD", "Invalid FvId, please double check the FvId. You can use view operate to get the FvId information!");
+    return EFI_ABORTED;
+  }
+
+  return EFI_SUCCESS;
+
+}
+
+#define BUILD_IN_TOOL_COUNT 4
+
+EFI_HANDLE
+LibPreDefinedGuidedTools (
+  VOID
+)
+{
+  EFI_GUID            Guid;
+  STRING_LIST         *Tool;
+  GUID_SEC_TOOL_ENTRY *FirstGuidTool;
+  GUID_SEC_TOOL_ENTRY *LastGuidTool;
+  GUID_SEC_TOOL_ENTRY *NewGuidTool;
+  UINT8               Index;
+  EFI_STATUS          Status;
+
+  CHAR8 PreDefinedGuidedTool[BUILD_IN_TOOL_COUNT][255] = {
+    "a31280ad-481e-41b6-95e8-127f4c984779 TIANO TianoCompress",
+    "ee4e5898-3914-4259-9d6e-dc7bd79403cf LZMA LzmaCompress",
+    "fc1bcdb0-7d31-49aa-936a-a4600d9dd083 CRC32 GenCrc32",
+    "3d532050-5cda-4fd0-879e-0f7f630d5afb BROTLI BrotliCompress"
+  };
+
+  Tool            = NULL;
+  FirstGuidTool   = NULL;
+  LastGuidTool    = NULL;
+  NewGuidTool     = NULL;
+  Index           = 0;
+
+  for (Index = 0; Index < BUILD_IN_TOOL_COUNT; Index++) {
+    Tool = SplitStringByWhitespace (PreDefinedGuidedTool[Index]);
+    if ((Tool != NULL) &&
+        (Tool->Count == 3)
+       ) {
+      Status = StringToGuid (Tool->Strings[0], &Guid);
+      if (!EFI_ERROR (Status)) {
+        NewGuidTool = malloc (sizeof (GUID_SEC_TOOL_ENTRY));
+        if (NewGuidTool != NULL) {
+          memcpy (&(NewGuidTool->Guid), &Guid, sizeof (Guid));
+          NewGuidTool->Name = CloneString(Tool->Strings[1]);
+          NewGuidTool->Path = CloneString(Tool->Strings[2]);
+          NewGuidTool->Next = NULL;
+        } else {
+          printf ("Error while allocate resource! \n");
+          FreeStringList (Tool);
+          return NULL;
+        }
+        if (FirstGuidTool == NULL) {
+          FirstGuidTool = NewGuidTool;
+        } else {
+          LastGuidTool->Next = NewGuidTool;
+        }
+        LastGuidTool = NewGuidTool;
+      }
+    } else {
+      fprintf (stdout, "Error");
+    }
+    if (Tool != NULL) {
+      FreeStringList (Tool);
+      Tool = NULL;
+    }
+  }
+  return FirstGuidTool;
+}
diff --git a/BaseTools/Source/C/FMMT/Rebase.c b/BaseTools/Source/C/FMMT/Rebase.c
new file mode 100644
index 0000000000..d32217d18c
--- /dev/null
+++ b/BaseTools/Source/C/FMMT/Rebase.c
@@ -0,0 +1,846 @@
+/** @file
+
+ Library to rebase PE image.
+
+Copyright (c) 2019, Intel Corporation. All rights reserved.<BR>
+SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#include "Rebase.h"
+#include <stdio.h>
+#include <stdlib.h>
+#ifdef __GNUC__
+#include <unistd.h>
+#else
+#include <io.h>
+#include <direct.h>
+#endif
+#include <PeCoffLib.h>
+#include <CommonLib.h>
+#include <IndustryStandard/PeImage.h>
+#include <FvLib.h>
+#include "EfiUtilityMsgs.h"
+
+static
+EFI_STATUS
+FfsRebaseImageRead(
+IN     VOID    *FileHandle,
+IN     UINTN   FileOffset,
+IN OUT UINT32  *ReadSize,
+OUT    VOID    *Buffer
+);
+
+EFI_STATUS
+RebaseFfs(
+IN OUT  UINT64                 BaseAddress,
+IN      CHAR8                 *FileName,
+IN OUT  EFI_FFS_FILE_HEADER   *FfsFile,
+IN      UINTN                 XipOffset
+)
+/*++
+
+Routine Description:
+
+This function determines if a file is XIP and should be rebased.  It will
+rebase any PE32 sections found in the file using the base address.
+
+Arguments:
+
+FvInfo            A pointer to FV_INFO struture.
+FileName          Ffs File PathName
+FfsFile           A pointer to Ffs file image.
+XipOffset         The offset address to use for rebasing the XIP file image.
+
+Returns:
+
+EFI_SUCCESS             The image was properly rebased.
+EFI_INVALID_PARAMETER   An input parameter is invalid.
+EFI_ABORTED             An error occurred while rebasing the input file image.
+EFI_OUT_OF_RESOURCES    Could not allocate a required resource.
+EFI_NOT_FOUND           No compressed sections could be found.
+
+--*/
+{
+  EFI_STATUS                            Status;
+  PE_COFF_LOADER_IMAGE_CONTEXT          ImageContext;
+  PE_COFF_LOADER_IMAGE_CONTEXT          OrigImageContext;
+  EFI_PHYSICAL_ADDRESS                  XipBase;
+  EFI_PHYSICAL_ADDRESS                  NewPe32BaseAddress;
+  UINTN                                 Index;
+  EFI_FILE_SECTION_POINTER              CurrentPe32Section;
+  EFI_FFS_FILE_STATE                    SavedState;
+  EFI_IMAGE_OPTIONAL_HEADER_UNION       *ImgHdr;
+  EFI_TE_IMAGE_HEADER                   *TEImageHeader;
+  UINT8                                 *MemoryImagePointer;
+  EFI_IMAGE_SECTION_HEADER              *SectionHeader;
+  CHAR8                                 PeFileName[MAX_LONG_FILE_PATH];
+  CHAR8                                 *Cptr;
+  FILE                                  *PeFile;
+  UINT8                                 *PeFileBuffer;
+  UINT32                                PeFileSize;
+  CHAR8                                 *PdbPointer;
+  UINT32                                FfsHeaderSize;
+  UINT32                                CurSecHdrSize;
+  CHAR8                                 *LongFilePathName;
+
+  Index = 0;
+  MemoryImagePointer = NULL;
+  TEImageHeader = NULL;
+  ImgHdr = NULL;
+  SectionHeader = NULL;
+  Cptr = NULL;
+  PeFile = NULL;
+  PeFileBuffer = NULL;
+
+  //
+  // Don't need to relocate image when BaseAddress is zero and no ForceRebase Flag specified.
+  //
+  if (BaseAddress == 0) {
+    return EFI_SUCCESS;
+  }
+
+  XipBase = BaseAddress + XipOffset;
+
+  //
+  // We only process files potentially containing PE32 sections.
+  //
+  switch (FfsFile->Type) {
+  case EFI_FV_FILETYPE_SECURITY_CORE:
+  case EFI_FV_FILETYPE_PEI_CORE:
+  case EFI_FV_FILETYPE_PEIM:
+  case EFI_FV_FILETYPE_COMBINED_PEIM_DRIVER:
+  case EFI_FV_FILETYPE_DRIVER:
+  case EFI_FV_FILETYPE_DXE_CORE:
+    break;
+  case EFI_FV_FILETYPE_FIRMWARE_VOLUME_IMAGE:
+    //
+    // Rebase the inside FvImage.
+    //
+      GetChildFvFromFfs (BaseAddress, FfsFile, XipOffset);
+
+    //
+    // Search PE/TE section in FV sectin.
+    //
+    break;
+  default:
+    return EFI_SUCCESS;
+  }
+
+  FfsHeaderSize = GetFfsHeaderLength(FfsFile);
+  //
+  // Rebase each PE32 section
+  //
+  Status = EFI_SUCCESS;
+  for (Index = 1;; Index++) {
+    //
+    // Init Value
+    //
+    NewPe32BaseAddress = 0;
+
+    //
+    // Find Pe Image
+    //
+    Status = GetSectionByType(FfsFile, EFI_SECTION_PE32, Index, &CurrentPe32Section);
+    if (EFI_ERROR(Status)) {
+      break;
+    }
+    CurSecHdrSize = GetSectionHeaderLength(CurrentPe32Section.CommonHeader);
+
+    //
+    // Initialize context
+    //
+    memset(&ImageContext, 0, sizeof (ImageContext));
+    ImageContext.Handle = (VOID *)((UINTN)CurrentPe32Section.Pe32Section + CurSecHdrSize);
+    ImageContext.ImageRead = (PE_COFF_LOADER_READ_FILE)FfsRebaseImageRead;
+    Status = PeCoffLoaderGetImageInfo(&ImageContext);
+    if (EFI_ERROR(Status)) {
+      Error(NULL, 0, 3000, "Invalid PeImage", "The input file is %s and the return status is %x", FileName, (int)Status);
+      return Status;
+    }
+
+    //if ((ImageContext.Machine == EFI_IMAGE_MACHINE_ARMT) ||
+    //  (ImageContext.Machine == EFI_IMAGE_MACHINE_AARCH64)) {
+    //  mArm = TRUE;
+    //}
+
+    //
+    // Keep Image Context for PE image in FV
+    //
+    memcpy(&OrigImageContext, &ImageContext, sizeof (ImageContext));
+
+    //
+    // Get File PdbPointer
+    //
+    PdbPointer = PeCoffLoaderGetPdbPointer(ImageContext.Handle);
+    if (PdbPointer == NULL) {
+      PdbPointer = FileName;
+    }
+
+    //
+    // Get PeHeader pointer
+    //
+    ImgHdr = (EFI_IMAGE_OPTIONAL_HEADER_UNION *)((UINTN)CurrentPe32Section.Pe32Section + CurSecHdrSize + ImageContext.PeCoffHeaderOffset);
+
+    //
+    // Calculate the PE32 base address, based on file type
+    //
+    switch (FfsFile->Type) {
+    case EFI_FV_FILETYPE_SECURITY_CORE:
+    case EFI_FV_FILETYPE_PEI_CORE:
+    case EFI_FV_FILETYPE_PEIM:
+    case EFI_FV_FILETYPE_COMBINED_PEIM_DRIVER:
+      //
+      // Check if section-alignment and file-alignment match or not
+      //
+      if ((ImgHdr->Pe32.OptionalHeader.SectionAlignment != ImgHdr->Pe32.OptionalHeader.FileAlignment)) {
+        //
+        // Xip module has the same section alignment and file alignment.
+        //
+        Error(NULL, 0, 3000, "Invalid", "Section-Alignment and File-Alignment do not match : %s.", FileName);
+        return EFI_ABORTED;
+      }
+      //
+      // PeImage has no reloc section. It will try to get reloc data from the original EFI image.
+      //
+      if (ImageContext.RelocationsStripped) {
+        //
+        // Construct the original efi file Name
+        //
+        if (strlen (FileName) > MAX_LONG_FILE_PATH - 1) {
+          Error(NULL, 0, 3000, "Invalid", "The file name for %s is too long.", FileName);
+          return EFI_ABORTED;
+        }
+        strncpy(PeFileName, FileName, MAX_LONG_FILE_PATH - 1);
+        PeFileName[MAX_LONG_FILE_PATH - 1] = 0;
+        Cptr = PeFileName + strlen(PeFileName);
+        while (*Cptr != '.') {
+          Cptr--;
+        }
+        if (*Cptr != '.') {
+          Error(NULL, 0, 3000, "Invalid", "The file %s has no .reloc section.", FileName);
+          return EFI_ABORTED;
+        }
+        else {
+          *(Cptr + 1) = 'e';
+          *(Cptr + 2) = 'f';
+          *(Cptr + 3) = 'i';
+          *(Cptr + 4) = '\0';
+        }
+        LongFilePathName = LongFilePath(PeFileName);
+        if (LongFilePathName == NULL) {
+          Error(NULL, 0, 3000, "Invalid", "Fail to get long file path for file %s.", FileName);
+          return EFI_ABORTED;
+        }
+        PeFile = fopen(LongFilePathName, "rb");
+        if (PeFile == NULL) {
+          Warning(NULL, 0, 0, "Invalid", "The file %s has no .reloc section.", FileName);
+          //Error (NULL, 0, 3000, "Invalid", "The file %s has no .reloc section.", FileName);
+          //return EFI_ABORTED;
+          break;
+        }
+        //
+        // Get the file size
+        //
+        PeFileSize = _filelength(fileno(PeFile));
+        PeFileBuffer = (UINT8 *)malloc(PeFileSize);
+        if (PeFileBuffer == NULL) {
+          Error(NULL, 0, 4001, "Resource", "memory cannot be allocated on rebase of %s", FileName);
+          fclose(PeFile);
+          return EFI_OUT_OF_RESOURCES;
+        }
+        //
+        // Read Pe File
+        //
+        fread(PeFileBuffer, sizeof (UINT8), PeFileSize, PeFile);
+        //
+        // close file
+        //
+        fclose(PeFile);
+        //
+        // Handle pointer to the original efi image.
+        //
+        ImageContext.Handle = PeFileBuffer;
+        Status = PeCoffLoaderGetImageInfo(&ImageContext);
+        if (EFI_ERROR(Status)) {
+          Error(NULL, 0, 3000, "Invalid PeImage", "The input file is %s and the return status is %x", FileName, (int)Status);
+          return Status;
+        }
+        ImageContext.RelocationsStripped = FALSE;
+      }
+
+      NewPe32BaseAddress = XipBase + (UINTN)CurrentPe32Section.Pe32Section + CurSecHdrSize - (UINTN)FfsFile;
+      break;
+
+    case EFI_FV_FILETYPE_DRIVER:
+    case EFI_FV_FILETYPE_DXE_CORE:
+      //
+      // Check if section-alignment and file-alignment match or not
+      //
+      if ((ImgHdr->Pe32.OptionalHeader.SectionAlignment != ImgHdr->Pe32.OptionalHeader.FileAlignment)) {
+        //
+        // Xip module has the same section alignment and file alignment.
+        //
+        Error(NULL, 0, 3000, "Invalid", "Section-Alignment and File-Alignment do not match : %s.", FileName);
+        return EFI_ABORTED;
+      }
+      NewPe32BaseAddress = XipBase + (UINTN)CurrentPe32Section.Pe32Section + CurSecHdrSize - (UINTN)FfsFile;
+      break;
+
+    default:
+      //
+      // Not supported file type
+      //
+      return EFI_SUCCESS;
+    }
+
+    //
+    // Relocation doesn't exist
+    //
+    if (ImageContext.RelocationsStripped) {
+      Warning(NULL, 0, 0, "Invalid", "The file %s has no .reloc section.", FileName);
+      continue;
+    }
+
+    //
+    // Relocation exist and rebase
+    //
+    //
+    // Load and Relocate Image Data
+    //
+    MemoryImagePointer = (UINT8 *)malloc((UINTN)ImageContext.ImageSize + ImageContext.SectionAlignment);
+    if (MemoryImagePointer == NULL) {
+      Error(NULL, 0, 4001, "Resource", "memory cannot be allocated on rebase of %s", FileName);
+      return EFI_OUT_OF_RESOURCES;
+    }
+    memset((VOID *)MemoryImagePointer, 0, (UINTN)ImageContext.ImageSize + ImageContext.SectionAlignment);
+    ImageContext.ImageAddress = ((UINTN)MemoryImagePointer + ImageContext.SectionAlignment - 1) & (~((UINTN)ImageContext.SectionAlignment - 1));
+
+    Status = PeCoffLoaderLoadImage(&ImageContext);
+    if (EFI_ERROR(Status)) {
+      Error(NULL, 0, 3000, "Invalid", "LocateImage() call failed on rebase of %s", FileName);
+      free((VOID *)MemoryImagePointer);
+      return Status;
+    }
+
+    ImageContext.DestinationAddress = NewPe32BaseAddress;
+    Status = PeCoffLoaderRelocateImage(&ImageContext);
+    if (EFI_ERROR(Status)) {
+      Error(NULL, 0, 3000, "Invalid", "RelocateImage() call failed on rebase of %s", FileName);
+      free((VOID *)MemoryImagePointer);
+      return Status;
+    }
+
+    //
+    // Copy Relocated data to raw image file.
+    //
+    SectionHeader = (EFI_IMAGE_SECTION_HEADER *)(
+      (UINTN)ImgHdr +
+      sizeof (UINT32)+
+      sizeof (EFI_IMAGE_FILE_HEADER)+
+      ImgHdr->Pe32.FileHeader.SizeOfOptionalHeader
+      );
+
+    for (Index = 0; Index < ImgHdr->Pe32.FileHeader.NumberOfSections; Index++, SectionHeader++) {
+      CopyMem(
+        (UINT8 *)CurrentPe32Section.Pe32Section + CurSecHdrSize + SectionHeader->PointerToRawData,
+        (VOID*)(UINTN)(ImageContext.ImageAddress + SectionHeader->VirtualAddress),
+        SectionHeader->SizeOfRawData
+        );
+    }
+
+    free((VOID *)MemoryImagePointer);
+    MemoryImagePointer = NULL;
+    if (PeFileBuffer != NULL) {
+      free(PeFileBuffer);
+      PeFileBuffer = NULL;
+    }
+
+    //
+    // Update Image Base Address
+    //
+    if (ImgHdr->Pe32.OptionalHeader.Magic == EFI_IMAGE_NT_OPTIONAL_HDR32_MAGIC) {
+      ImgHdr->Pe32.OptionalHeader.ImageBase = (UINT32)NewPe32BaseAddress;
+    }
+    else if (ImgHdr->Pe32Plus.OptionalHeader.Magic == EFI_IMAGE_NT_OPTIONAL_HDR64_MAGIC) {
+      ImgHdr->Pe32Plus.OptionalHeader.ImageBase = NewPe32BaseAddress;
+    }
+    else {
+      Error(NULL, 0, 3000, "Invalid", "unknown PE magic signature %X in PE32 image %s",
+        ImgHdr->Pe32.OptionalHeader.Magic,
+        FileName
+        );
+      return EFI_ABORTED;
+    }
+
+    //
+    // Now update file checksum
+    //
+    if (FfsFile->Attributes & FFS_ATTRIB_CHECKSUM) {
+      SavedState = FfsFile->State;
+      FfsFile->IntegrityCheck.Checksum.File = 0;
+      FfsFile->State = 0;
+      FfsFile->IntegrityCheck.Checksum.File = CalculateChecksum8(
+        (UINT8 *)((UINT8 *)FfsFile + FfsHeaderSize),
+        GetFfsFileLength(FfsFile) - FfsHeaderSize
+        );
+      FfsFile->State = SavedState;
+    }
+
+  }
+
+  if (FfsFile->Type != EFI_FV_FILETYPE_SECURITY_CORE &&
+    FfsFile->Type != EFI_FV_FILETYPE_PEI_CORE &&
+    FfsFile->Type != EFI_FV_FILETYPE_PEIM &&
+    FfsFile->Type != EFI_FV_FILETYPE_COMBINED_PEIM_DRIVER &&
+    FfsFile->Type != EFI_FV_FILETYPE_FIRMWARE_VOLUME_IMAGE
+    ) {
+    //
+    // Only Peim code may have a TE section
+    //
+    return EFI_SUCCESS;
+  }
+
+  //
+  // Now process TE sections
+  //
+  for (Index = 1;; Index++) {
+    NewPe32BaseAddress = 0;
+
+    //
+    // Find Te Image
+    //
+    Status = GetSectionByType(FfsFile, EFI_SECTION_TE, Index, &CurrentPe32Section);
+    if (EFI_ERROR(Status)) {
+      break;
+    }
+
+    CurSecHdrSize = GetSectionHeaderLength(CurrentPe32Section.CommonHeader);
+
+    //
+    // Calculate the TE base address, the FFS file base plus the offset of the TE section less the size stripped off
+    // by GenTEImage
+    //
+    TEImageHeader = (EFI_TE_IMAGE_HEADER *)((UINT8 *)CurrentPe32Section.Pe32Section + CurSecHdrSize);
+
+    //
+    // Initialize context, load image info.
+    //
+    memset(&ImageContext, 0, sizeof (ImageContext));
+    ImageContext.Handle = (VOID *)TEImageHeader;
+    ImageContext.ImageRead = (PE_COFF_LOADER_READ_FILE)FfsRebaseImageRead;
+    Status = PeCoffLoaderGetImageInfo(&ImageContext);
+    if (EFI_ERROR(Status)) {
+      Error(NULL, 0, 3000, "Invalid TeImage", "The input file is %s and the return status is %x", FileName, (int)Status);
+      return Status;
+    }
+
+    //if ((ImageContext.Machine == EFI_IMAGE_MACHINE_ARMT) ||
+    //  (ImageContext.Machine == EFI_IMAGE_MACHINE_AARCH64)) {
+    //  mArm = TRUE;
+    //}
+
+    //
+    // Keep Image Context for TE image in FV
+    //
+    memcpy(&OrigImageContext, &ImageContext, sizeof (ImageContext));
+
+    //
+    // Get File PdbPointer
+    //
+    PdbPointer = PeCoffLoaderGetPdbPointer(ImageContext.Handle);
+    if (PdbPointer == NULL) {
+      PdbPointer = FileName;
+    }
+    //
+    // Set new rebased address.
+    //
+    NewPe32BaseAddress = XipBase + (UINTN)TEImageHeader + sizeof (EFI_TE_IMAGE_HEADER) \
+      - TEImageHeader->StrippedSize - (UINTN)FfsFile;
+
+    //
+    // if reloc is stripped, try to get the original efi image to get reloc info.
+    //
+    if (ImageContext.RelocationsStripped) {
+      //
+      // Construct the original efi file name
+      //
+      if (strlen (FileName) > MAX_LONG_FILE_PATH - 1) {
+        Error(NULL, 0, 3000, "Invalid", "The file name for %s is too long.", FileName);
+        return EFI_ABORTED;
+      }
+      strncpy(PeFileName, FileName, MAX_LONG_FILE_PATH - 1);
+      PeFileName[MAX_LONG_FILE_PATH - 1] = 0;
+      Cptr = PeFileName + strlen(PeFileName);
+      while (*Cptr != '.') {
+        Cptr--;
+      }
+
+      if (*Cptr != '.') {
+        Error(NULL, 0, 3000, "Invalid", "The file %s has no .reloc section.", FileName);
+        return EFI_ABORTED;
+      }
+      else {
+        *(Cptr + 1) = 'e';
+        *(Cptr + 2) = 'f';
+        *(Cptr + 3) = 'i';
+        *(Cptr + 4) = '\0';
+      }
+
+      LongFilePathName = LongFilePath(PeFileName);
+      if (LongFilePathName == NULL) {
+        Error(NULL, 0, 3000, "Invalid", "Fail to get long file path for file %s.", FileName);
+        return EFI_ABORTED;
+      }
+      PeFile = fopen(LongFilePathName, "rb");
+      if (PeFile == NULL) {
+        Warning(NULL, 0, 0, "Invalid", "The file %s has no .reloc section.", FileName);
+        //Error (NULL, 0, 3000, "Invalid", "The file %s has no .reloc section.", FileName);
+        //return EFI_ABORTED;
+      }
+      else {
+        //
+        // Get the file size
+        //
+        PeFileSize = _filelength(fileno(PeFile));
+        PeFileBuffer = (UINT8 *)malloc(PeFileSize);
+        if (PeFileBuffer == NULL) {
+          Error(NULL, 0, 4001, "Resource", "memory cannot be allocated on rebase of %s", FileName);
+          fclose(PeFile);
+          return EFI_OUT_OF_RESOURCES;
+        }
+        //
+        // Read Pe File
+        //
+        fread(PeFileBuffer, sizeof (UINT8), PeFileSize, PeFile);
+        //
+        // close file
+        //
+        fclose(PeFile);
+        //
+        // Append reloc section into TeImage
+        //
+        ImageContext.Handle = PeFileBuffer;
+        Status = PeCoffLoaderGetImageInfo(&ImageContext);
+        if (EFI_ERROR(Status)) {
+          Error(NULL, 0, 3000, "Invalid TeImage", "The input file is %s and the return status is %x", FileName, (int)Status);
+          return Status;
+        }
+        ImageContext.RelocationsStripped = FALSE;
+      }
+    }
+    //
+    // Relocation doesn't exist
+    //
+    if (ImageContext.RelocationsStripped) {
+      Warning(NULL, 0, 0, "Invalid", "The file %s has no .reloc section.", FileName);
+      continue;
+    }
+
+    //
+    // Relocation exist and rebase
+    //
+    //
+    // Load and Relocate Image Data
+    //
+    MemoryImagePointer = (UINT8 *)malloc((UINTN)ImageContext.ImageSize + ImageContext.SectionAlignment);
+    if (MemoryImagePointer == NULL) {
+      Error(NULL, 0, 4001, "Resource", "memory cannot be allocated on rebase of %s", FileName);
+      return EFI_OUT_OF_RESOURCES;
+    }
+    memset((VOID *)MemoryImagePointer, 0, (UINTN)ImageContext.ImageSize + ImageContext.SectionAlignment);
+    ImageContext.ImageAddress = ((UINTN)MemoryImagePointer + ImageContext.SectionAlignment - 1) & (~((UINTN)ImageContext.SectionAlignment - 1));
+
+    Status = PeCoffLoaderLoadImage(&ImageContext);
+    if (EFI_ERROR(Status)) {
+      Error(NULL, 0, 3000, "Invalid", "LocateImage() call failed on rebase of %s", FileName);
+      free((VOID *)MemoryImagePointer);
+      return Status;
+    }
+    //
+    // Reloacate TeImage
+    //
+    ImageContext.DestinationAddress = NewPe32BaseAddress;
+    Status = PeCoffLoaderRelocateImage(&ImageContext);
+    if (EFI_ERROR(Status)) {
+      Error(NULL, 0, 3000, "Invalid", "RelocateImage() call failed on rebase of TE image %s", FileName);
+      free((VOID *)MemoryImagePointer);
+      return Status;
+    }
+
+    //
+    // Copy the relocated image into raw image file.
+    //
+    SectionHeader = (EFI_IMAGE_SECTION_HEADER *)(TEImageHeader + 1);
+    for (Index = 0; Index < TEImageHeader->NumberOfSections; Index++, SectionHeader++) {
+      if (!ImageContext.IsTeImage) {
+        CopyMem(
+          (UINT8 *)TEImageHeader + sizeof (EFI_TE_IMAGE_HEADER)-TEImageHeader->StrippedSize + SectionHeader->PointerToRawData,
+          (VOID*)(UINTN)(ImageContext.ImageAddress + SectionHeader->VirtualAddress),
+          SectionHeader->SizeOfRawData
+          );
+      }
+      else {
+        CopyMem(
+          (UINT8 *)TEImageHeader + sizeof (EFI_TE_IMAGE_HEADER)-TEImageHeader->StrippedSize + SectionHeader->PointerToRawData,
+          (VOID*)(UINTN)(ImageContext.ImageAddress + sizeof (EFI_TE_IMAGE_HEADER)-TEImageHeader->StrippedSize + SectionHeader->VirtualAddress),
+          SectionHeader->SizeOfRawData
+          );
+      }
+    }
+
+    //
+    // Free the allocated memory resource
+    //
+    free((VOID *)MemoryImagePointer);
+    MemoryImagePointer = NULL;
+    if (PeFileBuffer != NULL) {
+      free(PeFileBuffer);
+      PeFileBuffer = NULL;
+    }
+
+    //
+    // Update Image Base Address
+    //
+    TEImageHeader->ImageBase = NewPe32BaseAddress;
+
+    //
+    // Now update file checksum
+    //
+    if (FfsFile->Attributes & FFS_ATTRIB_CHECKSUM) {
+      SavedState = FfsFile->State;
+      FfsFile->IntegrityCheck.Checksum.File = 0;
+      FfsFile->State = 0;
+      FfsFile->IntegrityCheck.Checksum.File = CalculateChecksum8(
+        (UINT8 *)((UINT8 *)FfsFile + FfsHeaderSize),
+        GetFfsFileLength(FfsFile) - FfsHeaderSize
+        );
+      FfsFile->State = SavedState;
+    }
+  }
+
+  return EFI_SUCCESS;
+}
+
+EFI_STATUS
+FfsRebaseImageRead(
+IN     VOID    *FileHandle,
+IN     UINTN   FileOffset,
+IN OUT UINT32  *ReadSize,
+OUT    VOID    *Buffer
+)
+/*++
+
+Routine Description:
+
+Support routine for the PE/COFF Loader that reads a buffer from a PE/COFF file
+
+Arguments:
+
+FileHandle - The handle to the PE/COFF file
+
+FileOffset - The offset, in bytes, into the file to read
+
+ReadSize   - The number of bytes to read from the file starting at FileOffset
+
+Buffer     - A pointer to the buffer to read the data into.
+
+Returns:
+
+EFI_SUCCESS - ReadSize bytes of data were read into Buffer from the PE/COFF file starting at FileOffset
+
+--*/
+{
+  CHAR8   *Destination8;
+  CHAR8   *Source8;
+  UINT32  Length;
+
+  Destination8 = Buffer;
+  Source8 = (CHAR8 *)((UINTN)FileHandle + FileOffset);
+  Length = *ReadSize;
+  while (Length--) {
+    *(Destination8++) = *(Source8++);
+  }
+
+  return EFI_SUCCESS;
+}
+
+EFI_STATUS
+GetChildFvFromFfs (
+  IN      UINT64                 BaseAddress,
+  IN      EFI_FFS_FILE_HEADER   *FfsFile,
+  IN      UINTN                 XipOffset
+  )
+/*++
+
+Routine Description:
+
+  This function gets all child FvImages in the input FfsFile, and records
+  their base address to the parent image.
+
+Arguments:
+  FvInfo            A pointer to FV_INFO struture.
+  FfsFile           A pointer to Ffs file image that may contain FvImage.
+  XipOffset         The offset address to the parent FvImage base.
+
+Returns:
+
+  EFI_SUCCESS        Base address of child Fv image is recorded.
+--*/
+{
+  EFI_STATUS                          Status;
+  UINTN                               Index;
+  EFI_FILE_SECTION_POINTER            SubFvSection;
+  EFI_FIRMWARE_VOLUME_HEADER          *SubFvImageHeader;
+  EFI_PHYSICAL_ADDRESS                SubFvBaseAddress;
+  EFI_FIRMWARE_VOLUME_HEADER          *OrigFvHeader;
+  UINT32                              OrigFvLength;
+  EFI_PHYSICAL_ADDRESS                OrigFvBaseAddress;
+  EFI_FFS_FILE_HEADER                 *CurrentFile;
+
+  //
+  // Initialize FV library, saving previous values
+  //
+  OrigFvHeader = NULL;
+  GetFvHeader (&OrigFvHeader, &OrigFvLength);
+  OrigFvBaseAddress = BaseAddress;
+  for (Index = 1;; Index++) {
+    //
+    // Find FV section
+    //
+    Status = GetSectionByType (FfsFile, EFI_SECTION_FIRMWARE_VOLUME_IMAGE, Index, &SubFvSection);
+    if (EFI_ERROR (Status)) {
+      break;
+    }
+    SubFvImageHeader = (EFI_FIRMWARE_VOLUME_HEADER *) ((UINT8 *) SubFvSection.FVImageSection + GetSectionHeaderLength(SubFvSection.FVImageSection));
+
+    //
+    // Rebase on Flash
+    //
+    SubFvBaseAddress = OrigFvBaseAddress + (UINTN) SubFvImageHeader - (UINTN) FfsFile + XipOffset;
+    //mFvBaseAddress[mFvBaseAddressNumber ++ ] = SubFvBaseAddress;
+    BaseAddress = SubFvBaseAddress;
+    InitializeFvLib(SubFvImageHeader, (UINT32) SubFvImageHeader->FvLength);
+
+    Status = GetNextFile (NULL, &CurrentFile);
+    if (EFI_ERROR (Status)) {
+      Error (NULL, 0, 0003, "error parsing FV image", "FFS file can't be found");
+      continue;
+    }
+    while (CurrentFile) {
+      RebaseFfs (BaseAddress, "", CurrentFile, (UINTN) CurrentFile - (UINTN) SubFvImageHeader);
+      Status = GetNextFile (CurrentFile, &CurrentFile);
+      if (EFI_ERROR (Status)) {
+        break;
+      }
+    }
+  }
+
+  BaseAddress = OrigFvBaseAddress;
+  if (OrigFvHeader != NULL) {
+    InitializeFvLib(OrigFvHeader, OrigFvLength);
+  }
+
+  return EFI_SUCCESS;
+}
+
+EFI_STATUS
+GetPe32Info (
+  IN UINT8                  *Pe32,
+  OUT UINT32                *EntryPoint,
+  OUT UINT32                *BaseOfCode,
+  OUT UINT16                *MachineType
+  )
+/*++
+
+Routine Description:
+
+  Retrieves the PE32 entry point offset and machine type from PE image or TeImage.
+  See EfiImage.h for machine types.  The entry point offset is from the beginning
+  of the PE32 buffer passed in.
+
+Arguments:
+
+  Pe32          Beginning of the PE32.
+  EntryPoint    Offset from the beginning of the PE32 to the image entry point.
+  BaseOfCode    Base address of code.
+  MachineType   Magic number for the machine type.
+
+Returns:
+
+  EFI_SUCCESS             Function completed successfully.
+  EFI_ABORTED             Error encountered.
+  EFI_INVALID_PARAMETER   A required parameter was NULL.
+  EFI_UNSUPPORTED         The operation is unsupported.
+
+--*/
+{
+  EFI_IMAGE_DOS_HEADER             *DosHeader;
+  EFI_IMAGE_OPTIONAL_HEADER_UNION  *ImgHdr;
+  EFI_TE_IMAGE_HEADER              *TeHeader;
+
+  //
+  // Verify input parameters
+  //
+  if (Pe32 == NULL) {
+    return EFI_INVALID_PARAMETER;
+  }
+
+  //
+  // First check whether it is one TE Image.
+  //
+  TeHeader = (EFI_TE_IMAGE_HEADER *) Pe32;
+  if (TeHeader->Signature == EFI_TE_IMAGE_HEADER_SIGNATURE) {
+    //
+    // By TeImage Header to get output
+    //
+    *EntryPoint   = TeHeader->AddressOfEntryPoint + sizeof (EFI_TE_IMAGE_HEADER) - TeHeader->StrippedSize;
+    *BaseOfCode   = TeHeader->BaseOfCode + sizeof (EFI_TE_IMAGE_HEADER) - TeHeader->StrippedSize;
+    *MachineType  = TeHeader->Machine;
+  } else {
+
+    //
+    // Then check whether
+    // First is the DOS header
+    //
+    DosHeader = (EFI_IMAGE_DOS_HEADER *) Pe32;
+
+    //
+    // Verify DOS header is expected
+    //
+    if (DosHeader->e_magic != EFI_IMAGE_DOS_SIGNATURE) {
+      Error (NULL, 0, 3000, "Invalid", "Unknown magic number in the DOS header, 0x%04X.", DosHeader->e_magic);
+      return EFI_UNSUPPORTED;
+    }
+    //
+    // Immediately following is the NT header.
+    //
+    ImgHdr = (EFI_IMAGE_OPTIONAL_HEADER_UNION *) ((UINTN) Pe32 + DosHeader->e_lfanew);
+
+    //
+    // Verify NT header is expected
+    //
+    if (ImgHdr->Pe32.Signature != EFI_IMAGE_NT_SIGNATURE) {
+      Error (NULL, 0, 3000, "Invalid", "Unrecognized image signature 0x%08X.", (unsigned) ImgHdr->Pe32.Signature);
+      return EFI_UNSUPPORTED;
+    }
+    //
+    // Get output
+    //
+    *EntryPoint   = ImgHdr->Pe32.OptionalHeader.AddressOfEntryPoint;
+    *BaseOfCode   = ImgHdr->Pe32.OptionalHeader.BaseOfCode;
+    *MachineType  = ImgHdr->Pe32.FileHeader.Machine;
+  }
+
+  //
+  // Verify machine type is supported
+  //
+  if ((*MachineType != EFI_IMAGE_MACHINE_IA32) && (*MachineType != EFI_IMAGE_MACHINE_X64) && (*MachineType != EFI_IMAGE_MACHINE_EBC) &&
+      (*MachineType != EFI_IMAGE_MACHINE_ARMT) && (*MachineType != EFI_IMAGE_MACHINE_AARCH64)) {
+    Error (NULL, 0, 3000, "Invalid", "Unrecognized machine type in the PE32 file.");
+    return EFI_UNSUPPORTED;
+  }
+
+  return EFI_SUCCESS;
+}
+
diff --git a/BaseTools/BinWrappers/PosixLike/FMMT b/BaseTools/BinWrappers/PosixLike/FMMT
new file mode 100755
index 0000000000..a244ecc095
--- /dev/null
+++ b/BaseTools/BinWrappers/PosixLike/FMMT
@@ -0,0 +1,29 @@
+#!/usr/bin/env bash
+
+full_cmd=${BASH_SOURCE:-$0} # see http://mywiki.wooledge.org/BashFAQ/028 for a discussion of why $0 is not a good choice here
+dir=$(dirname "$full_cmd")
+cmd=${full_cmd##*/}
+
+if [ -n "$WORKSPACE" ] && [ -e "$WORKSPACE/Conf/BaseToolsCBinaries" ]
+then
+  exec "$WORKSPACE/Conf/BaseToolsCBinaries/$cmd"
+elif [ -n "$WORKSPACE" ] && [ -e "$EDK_TOOLS_PATH/Source/C" ]
+then
+  if [ ! -e "$EDK_TOOLS_PATH/Source/C/bin/$cmd" ]
+  then
+    echo "BaseTools C Tool binary was not found ($cmd)"
+    echo "You may need to run:"
+    echo "  make -C $EDK_TOOLS_PATH/Source/C"
+  else
+    exec "$EDK_TOOLS_PATH/Source/C/bin/$cmd" "$@"
+  fi
+elif [ -e "$dir/../../Source/C/bin/$cmd" ]
+then
+  exec "$dir/../../Source/C/bin/$cmd" "$@"
+else
+  echo "Unable to find the real '$cmd' to run"
+  echo "This message was printed by"
+  echo "  $0"
+  exit 127
+fi
+
diff --git a/BaseTools/Source/C/FMMT/FirmwareModuleManagement.h b/BaseTools/Source/C/FMMT/FirmwareModuleManagement.h
new file mode 100644
index 0000000000..ec8e3eaba0
--- /dev/null
+++ b/BaseTools/Source/C/FMMT/FirmwareModuleManagement.h
@@ -0,0 +1,479 @@
+/** @file
+
+ Structures and functions declaration.
+
+ Copyright (c) 2019, Intel Corporation. All rights reserved.<BR>
+ SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#ifndef    _BIN_FILE_MANAGER_
+#define    _BIN_FILE_MANAGER_
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#ifdef __GNUC__
+#include <unistd.h>
+#else
+#include <io.h>
+#include <direct.h>
+#endif
+#include <FvLib.h>
+#include <Common/UefiBaseTypes.h>
+#include <Common/PiFirmwareVolume.h>
+#include <Common/PiFirmwareFile.h>
+#include <Protocol/GuidedSectionExtraction.h>
+
+#include "CommonLib.h"
+#include "EfiUtilityMsgs.h"
+#include "ParseInf.h"
+#include "ParseGuidedSectionTools.h"
+#include "StringFuncs.h"
+#include "Compress.h"
+#include "Decompress.h"
+
+#ifndef _MAX_PATH
+#define _MAX_PATH 500
+#endif
+
+#if defined(_MSC_VER) && _MSC_VER < 1900
+#define snprintf _snprintf
+#endif
+
+#ifdef __GNUC__
+#define OS_SEP        '/'
+#define OS_SEP_STR    "/"
+#define COPY_STR      "cp \"%s\" \"%s\" > /dev/null"
+#define RMDIR_STR     "rm -r \"%s\" > /dev/null"
+#define DEL_STR       "rm \"%s\" > /dev/null"
+#else
+#define OS_SEP        '\\'
+#define OS_SEP_STR    "\\"
+#define COPY_STR      "copy \"%s\" \"%s\" > NUL"
+#define RMDIR_STR     "rmdir /S /Q \"%s\" > NUL"
+#define DEL_STR       "del \"%s\" > NUL"
+#endif
+
+#define UTILITY_NAME               "Firmware Module Management Tool(FMMT)"
+#define UTILITY_SHORT_NAME         "FMMT"
+#define UTILITY_MAJOR_VERSION      0
+#define UTILITY_MINOR_VERSION      23
+#define MAX_BASENAME_LEN           60  // not good to HardCode, but let's be reasonable
+#define EFI_SECTION_ERROR EFIERR   (100)
+//
+// The maximum number of Pad file guid entries.
+//
+#define MAX_NUMBER_OF_PAD_FILE_GUIDS    1024
+
+//
+// The maximum number of block map entries supported by the library
+//
+#define MAX_NUMBER_OF_FV_BLOCKS         100
+
+
+//
+// The maximum number of sections in an FFS file.
+//
+#define MAX_NUMBER_OF_SECTION_IN_FFS    100
+
+//
+// The maximum number of files in the FV supported by the library
+//
+#define MAX_NUMBER_OF_FILES_IN_FV       1000
+#define MAX_NUMBER_OF_FILES_IN_CAP      1000
+
+
+
+///
+/// If present, this must be the first and only opcode,
+/// EFI_DEP_BEFORE is only used by DXE driver.
+///
+#define EFI_DEP_BEFORE        0x00
+
+///
+/// If present, this must be the first and only opcode,
+/// EFI_DEP_AFTER is only used by DXE driver.
+///
+#define EFI_DEP_AFTER         0x01
+
+#define EFI_DEP_PUSH          0x02
+#define EFI_DEP_AND           0x03
+#define EFI_DEP_OR            0x04
+#define EFI_DEP_NOT           0x05
+#define EFI_DEP_TRUE          0x06
+#define EFI_DEP_FALSE         0x07
+#define EFI_DEP_END           0x08
+
+
+///
+/// If present, this must be the first opcode,
+/// EFI_DEP_SOR is only used by DXE driver.
+///
+#define EFI_DEP_SOR           0x09
+
+//
+// INF file strings
+//
+#define OPTIONS_SECTION_STRING                "[options]"
+#define ATTRIBUTES_SECTION_STRING             "[attributes]"
+#define FILES_SECTION_STRING                  "[files]"
+#define FV_BASE_ADDRESS_STRING                "[FV_BASE_ADDRESS]"
+
+//
+// Options section
+//
+#define EFI_FV_BASE_ADDRESS_STRING        "EFI_BASE_ADDRESS"
+#define EFI_FV_FILE_NAME_STRING           "EFI_FILE_NAME"
+#define EFI_NUM_BLOCKS_STRING             "EFI_NUM_BLOCKS"
+#define EFI_BLOCK_SIZE_STRING             "EFI_BLOCK_SIZE"
+#define EFI_GUID_STRING                   "EFI_GUID"
+#define EFI_FV_FILESYSTEMGUID_STRING      "EFI_FV_GUID"
+#define EFI_FV_NAMEGUID_STRING            "EFI_FVNAME_GUID"
+#define EFI_CAPSULE_GUID_STRING           "EFI_CAPSULE_GUID"
+#define EFI_CAPSULE_HEADER_SIZE_STRING    "EFI_CAPSULE_HEADER_SIZE"
+#define EFI_CAPSULE_FLAGS_STRING          "EFI_CAPSULE_FLAGS"
+#define EFI_CAPSULE_VERSION_STRING        "EFI_CAPSULE_VERSION"
+
+#define EFI_FV_TOTAL_SIZE_STRING    "EFI_FV_TOTAL_SIZE"
+#define EFI_FV_TAKEN_SIZE_STRING    "EFI_FV_TAKEN_SIZE"
+#define EFI_FV_SPACE_SIZE_STRING    "EFI_FV_SPACE_SIZE"
+
+
+typedef UINT32 FMMT_ENCAP_TYPE;
+
+#define MAX_LEVEL_IN_FV_FILE  32
+
+//
+// Types of FMMT_ENCAP_TREENODE_TYPE
+//
+#define FMMT_ENCAP_TREE_FV                    0x1
+#define FMMT_ENCAP_TREE_FFS                   0x2
+#define FMMT_ENCAP_TREE_GUIDED_SECTION        0x3
+#define FMMT_ENCAP_TREE_COMPRESS_SECTION      0x4
+#define FMMT_ENCAP_TREE_FV_SECTION            0x5
+
+extern EFI_HANDLE mParsedGuidedSectionTools;
+
+
+#define TEMP_DIR_NAME  "FmmtTemp"
+
+//
+// Structure to keep a list of GUID-To-BaseNames
+//
+typedef struct _GUID_TO_BASENAME {
+  struct _GUID_TO_BASENAME  *Next;
+  INT8                      Guid[PRINTED_GUID_BUFFER_SIZE];
+  INT8                      BaseName[MAX_BASENAME_LEN];
+} GUID_TO_BASENAME;
+
+
+typedef struct _GUID_SEC_TOOL_ENTRY {
+  EFI_GUID   Guid;
+  CHAR8*     Name;
+  CHAR8*     Path;
+  struct _GUID_SEC_TOOL_ENTRY *Next;
+} GUID_SEC_TOOL_ENTRY;
+
+
+//
+// Private data types
+//
+//
+// Component information
+//
+typedef struct {
+  UINTN Size;
+  CHAR8 ComponentName[_MAX_PATH];
+} COMPONENT_INFO;
+
+typedef struct {
+  CHAR8            FfsName[_MAX_PATH];
+
+  //
+  // UI Name for this FFS file, if has.
+  //
+  CHAR16           UiName[_MAX_PATH];
+   UINT32           UiNameSize;
+  //
+  // Total section number in this FFS.
+  //
+  UINT32           TotalSectionNum;
+
+  //
+  // Describe the position of the FFS file.
+  //
+  UINT8            Level;
+  //
+  // If this FFS has no encapsulate section, this flag will set to True.
+  //
+  BOOLEAN          IsLeaf;
+  //
+  // Section type for each section in FFS.
+  //
+  EFI_SECTION_TYPE SectionType[MAX_NUMBER_OF_SECTION_IN_FFS];
+  //
+  // Offset relative to current FV
+  //
+  UINT32                  Offset;
+  UINT8                   FvLevel;
+  EFI_GUID                GuidName;
+  UINT8                   *Depex;
+  UINT32                  DepexLen;
+  BOOLEAN                 IsHandle;
+  BOOLEAN                 IsFvStart;
+  BOOLEAN                 IsFvEnd;
+}FFS_ATTRIBUTES;
+
+
+typedef struct __ENCAP_INFO_DATA{
+  //
+  // Now Level
+  //
+  UINT8                      Level;
+
+  //
+  // Encapsulate type.
+  //
+  FMMT_ENCAP_TYPE             Type;
+
+  //
+  // Data, if it's FV, should be FV header.
+  //
+  VOID                       *Data;
+
+  //
+  //FvId, match FvId with FvGuidName.
+  //
+  UINT8                       FvId;
+
+  //
+  // if FV ExtHeaderOffset not to zero, should also have FvExtHeader information
+  //
+  EFI_FIRMWARE_VOLUME_EXT_HEADER *FvExtHeader;
+
+  CHAR16           UiName[_MAX_PATH];
+  UINT32           UiNameSize;
+  UINT8            *Depex;
+  UINT32           DepexLen;
+
+  //
+  // Next node.
+  //
+  struct __ENCAP_INFO_DATA   *NextNode;
+
+  //
+  // Right node.
+  //
+  struct __ENCAP_INFO_DATA   *RightNode;
+} ENCAP_INFO_DATA;
+
+typedef struct _FFS_INFOMATION{
+  CHAR8                      *FFSName;
+  UINT32                     InFvId;
+  UINT8                      ParentLevel;
+  BOOLEAN                    IsFFS;
+  CHAR16                     UiName[_MAX_PATH];
+  UINT32                     UiNameSize;
+  UINT8                      *Depex;
+  UINT32                     DepexLen;
+  BOOLEAN                    FfsFoundFlag;
+  struct _FFS_INFOMATION     *Next;
+} FFS_INFORMATION;
+
+//
+// FV and capsule information holder
+//
+typedef struct _FV_INFOMATION{
+  EFI_FIRMWARE_VOLUME_HEADER *FvHeader;
+  EFI_FIRMWARE_VOLUME_EXT_HEADER *FvExtHeader;
+  UINT32                     ImageAddress;
+  UINT32                     FfsNumbers;
+  CHAR8                      FvName[_MAX_PATH];
+  EFI_FV_BLOCK_MAP_ENTRY     FvBlocks[MAX_NUMBER_OF_FV_BLOCKS];
+  FFS_ATTRIBUTES             FfsAttuibutes[MAX_NUMBER_OF_FILES_IN_FV];
+  EFI_FFS_FILE_HEADER2       FfsHeader[MAX_NUMBER_OF_FILES_IN_FV];
+  struct _FV_INFOMATION      *FvNext;
+  ENCAP_INFO_DATA            *EncapData;
+  UINT8                      FvLevel;
+  CHAR8                      *FvUiName;
+  UINT8                      MulFvLevel;
+  CHAR8                      AlignmentStr[16];
+  FFS_INFORMATION            *ChildFvFFS;
+} FV_INFORMATION;
+
+typedef struct _FIRMWARE_DEVICE {
+  ///
+  /// Size of FD file
+  ///
+  UINT32                   Size;
+  FV_INFORMATION           *Fv;
+} FIRMWARE_DEVICE;
+
+typedef struct _FILENode {
+  CHAR8              *FileName;
+  UINT8              SubLevel;
+  struct _FILENode   *Next;
+} FILENode;
+
+typedef struct {
+  CHAR8              *FvId;
+  FILENode           *NewFile;
+  FILENode           *OldFile;
+  FIRMWARE_DEVICE    *FdData;
+  UINT8              FvLevel;
+  FV_INFORMATION     *FvInFd;
+} Data;
+
+EFI_STATUS
+LibFindFvInFd (
+  IN     FILE             *InputFile,
+  IN OUT FIRMWARE_DEVICE  **FdData
+);
+
+/**
+
+  TODO: Add function description
+
+  @param[in]    Fv            - Firmware Volume to get information from
+
+  @return       EFI_STATUS
+
+**/
+EFI_STATUS
+LibGetFvInfo (
+  IN     VOID                         *Fv,
+  IN OUT FV_INFORMATION               *CurrentFv,
+  IN     CHAR8                        *FvName,
+  IN     UINT8                        Level,
+  IN     ENCAP_INFO_DATA              **CurrentFvEncapData,
+  IN     UINT32                       *FfsCount,
+  IN OUT UINT8                        *FvCount,
+  IN     BOOLEAN                      ViewFlag,
+  IN     BOOLEAN                      IsChildFv
+  );
+
+/*
+  Get size info from FV file.
+
+  @param[in]
+  @param[out]
+
+  @retval
+
+*/
+EFI_STATUS
+LibGetFvSize (
+  IN   FILE                       *InputFile,
+  OUT  UINT32                     *FvSize
+  );
+
+ /**
+
+  This function returns the next larger size that meets the alignment
+  requirement specified.
+
+  @param[in]      ActualSize      The size.
+  @param[in]      Alignment       The desired alignment.
+
+  @retval         EFI_SUCCESS     Function completed successfully.
+  @retval         EFI_ABORTED     The function encountered an error.
+
+**/
+UINT32
+GetOccupiedSize (
+  IN UINT32  ActualSize,
+  IN UINT32  Alignment
+  );
+
+/**
+  Converts ASCII characters to Unicode.
+  Assumes that the Unicode characters are only these defined in the ASCII set.
+
+  String      - Pointer to string that is written to FILE.
+  UniString   - Pointer to unicode string
+
+  The address to the ASCII string - same as AsciiStr.
+
+**/
+VOID
+LibAscii2Unicode (
+  IN   CHAR8          *String,
+  OUT  CHAR16         *UniString
+  );
+
+/**
+  Delete a directory and files in it.
+
+  @param[in]   DirName   Name of the directory need to be deleted.
+
+  @return EFI_INVALID_PARAMETER
+  @return EFI_SUCCESS
+**/
+EFI_STATUS
+LibRmDir (
+  IN  CHAR8*  DirName
+  );
+
+/**
+  Delete a file.
+
+  @param[in]   FileName   Name of the file need to be deleted.
+
+  @return EFI_INVALID_PARAMETER
+  @return EFI_SUCCESS
+**/
+EFI_STATUS
+LibFmmtDeleteFile(
+  IN   CHAR8    *FileName
+);
+
+
+/**
+
+  Free the whole Fd data structure.
+
+  @param[in]  Fd  The pointer point to the Fd data structure.
+
+**/
+VOID
+LibFmmtFreeFd (
+  FIRMWARE_DEVICE *Fd
+);
+
+
+EFI_STATUS
+LibEncapNewFvFile(
+  IN  FV_INFORMATION   *FvInFd,
+  IN  CHAR8            *TemDir,
+  IN  ENCAP_INFO_DATA  *CurrentEncapData,
+  IN  UINT32           Level_Break,
+  OUT FFS_INFORMATION  **OutputFile
+);
+
+
+EFI_STATUS
+LibLocateFvViaFvId (
+  IN     FIRMWARE_DEVICE     *FdData,
+  IN     CHAR8               *FvId,
+  IN OUT FV_INFORMATION      **FvInFd
+);
+
+EFI_HANDLE
+LibPreDefinedGuidedTools (
+  VOID
+);
+
+EFI_STATUS
+FvBufGetSize(
+IN  VOID   *Fv,
+OUT UINTN  *Size
+);
+
+EFI_STATUS
+FvBufFindNextFile(
+IN     VOID      *Fv,
+IN OUT UINTN     *Key,
+OUT    VOID      **File
+);
+#endif
diff --git a/BaseTools/Source/C/FMMT/FmmtConf.ini b/BaseTools/Source/C/FMMT/FmmtConf.ini
new file mode 100644
index 0000000000..36135116b3
--- /dev/null
+++ b/BaseTools/Source/C/FMMT/FmmtConf.ini
@@ -0,0 +1,6 @@
+a31280ad-481e-41b6-95e8-127f4c984779 TIANO TianoCompress
+ee4e5898-3914-4259-9d6e-dc7bd79403cf LZMA LzmaCompress
+fc1bcdb0-7d31-49aa-936a-a4600d9dd083 CRC32 GenCrc32
+d42ae6bd-1352-4bfb-909a-ca72a6eae889 LZMAF86 LzmaF86Compress
+3d532050-5cda-4fd0-879e-0f7f630d5afb BROTLI BrotliCompress
+
diff --git a/BaseTools/Source/C/FMMT/GNUmakefile b/BaseTools/Source/C/FMMT/GNUmakefile
new file mode 100644
index 0000000000..81b99f25db
--- /dev/null
+++ b/BaseTools/Source/C/FMMT/GNUmakefile
@@ -0,0 +1,16 @@
+## @file
+# GNU/Linux makefile for 'FMMT' module build.
+#
+# Copyright (c) 2019, Intel Corporation. All rights reserved.<BR>
+# SPDX-License-Identifier: BSD-2-Clause-Patent
+#
+MAKEROOT ?= ..
+
+APPNAME = FMMT
+
+LIBS = -lCommon
+
+OBJECTS = FmmtLib.o Rebase.o FirmwareModuleManagement.o
+
+include $(MAKEROOT)/Makefiles/app.makefile
+
diff --git a/BaseTools/Source/C/FMMT/Makefile b/BaseTools/Source/C/FMMT/Makefile
new file mode 100644
index 0000000000..d6559d65fd
--- /dev/null
+++ b/BaseTools/Source/C/FMMT/Makefile
@@ -0,0 +1,17 @@
+## @file
+# Windows makefile for 'FMMT' module build.
+#
+# Copyright (c) 2019, Intel Corporation. All rights reserved.<BR>
+# SPDX-License-Identifier: BSD-2-Clause-Patent
+#
+
+!INCLUDE ..\Makefiles\ms.common
+
+APPNAME = FMMT
+
+LIBS = $(LIB_PATH)\Common.lib
+
+OBJECTS = FirmwareModuleManagement.obj FmmtLib.obj Rebase.obj
+
+!INCLUDE ..\Makefiles\ms.app
+
diff --git a/BaseTools/Source/C/FMMT/Rebase.h b/BaseTools/Source/C/FMMT/Rebase.h
new file mode 100644
index 0000000000..57604a357f
--- /dev/null
+++ b/BaseTools/Source/C/FMMT/Rebase.h
@@ -0,0 +1,31 @@
+/** @file  Rebase.h
+
+ Library to rebase PE image.
+
+ Copyright (c)  2019, Intel Corporation. All rights reserved.<BR>
+ SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#ifndef _FMMT_REBASE_H
+#define _FMMT_REBASE_H
+
+#include <Common/UefiBaseTypes.h>
+#include <Common/PiFirmwareFile.h>
+
+EFI_STATUS
+RebaseFfs(
+IN OUT  UINT64                 BaseAddress,
+IN      CHAR8                 *FileName,
+IN OUT  EFI_FFS_FILE_HEADER   *FfsFile,
+IN      UINTN                 XipOffset
+);
+
+EFI_STATUS
+GetChildFvFromFfs (
+  IN      UINT64                 BaseAddress,
+  IN      EFI_FFS_FILE_HEADER   *FfsFile,
+  IN      UINTN                 XipOffset
+);
+
+#endif
diff --git a/BaseTools/Source/C/GNUmakefile b/BaseTools/Source/C/GNUmakefile
index 990c6d0a82..b99b5121f5 100644
--- a/BaseTools/Source/C/GNUmakefile
+++ b/BaseTools/Source/C/GNUmakefile
@@ -47,6 +47,7 @@ VFRAUTOGEN = VfrCompile/VfrLexer.h
 APPLICATIONS = \
   BrotliCompress \
   VfrCompile \
+  FMMT \
   BfmLib \
   EfiRom \
   FCE \
diff --git a/BaseTools/Source/C/Makefile b/BaseTools/Source/C/Makefile
index 357e8b9003..4377ec5522 100644
--- a/BaseTools/Source/C/Makefile
+++ b/BaseTools/Source/C/Makefile
@@ -12,6 +12,7 @@ LIBRARIES = Common
 APPLICATIONS = \
   VfrCompile \
   BrotliCompress \
+  FMMT \
   BfmLib \
   EfiRom \
   FCE \
-- 
2.13.0.windows.1


-=-=-=-=-=-=-=-=-=-=-=-
Groups.io Links: You receive all messages sent to this group.

View/Reply Online (#43123): https://edk2.groups.io/g/devel/message/43123
Mute This Topic: https://groups.io/mt/32270353/1813853
Group Owner: devel+owner at edk2.groups.io
Unsubscribe: https://edk2.groups.io/g/devel/unsub  [edk2-devel-archive at redhat.com]
-=-=-=-=-=-=-=-=-=-=-=-




More information about the edk2-devel-archive mailing list