/** @file  IfrParse.c

 Parser for IFR binary encoding.

 Copyright (c) 2011 - 2018, Intel Corporation. All rights reserved.<BR>

 This program and the accompanying materials are licensed and made available under
 the terms and conditions of the BSD License which accompanies this distribution.
 The full text of the license may be found at
 http://opensource.org/licenses/bsd-license.php

 THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
 WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.

**/

#include "IfrParse.h"

#ifndef EDKII_IFR_BIT_VARSTORE_GUID
#define EDKII_IFR_BIT_VARSTORE_GUID \
  {0x82DDD68B, 0x9163, 0x4187, {0x9B, 0x27, 0x20, 0xA8, 0xFD, 0x60 ,0xA7, 0x1D}}
#endif

#ifndef EDKII_IFR_NUMERIC_SIZE_BIT
#define EDKII_IFR_NUMERIC_SIZE_BIT  0x3F
#endif

UINT16           mStatementIndex;
UINT16           mExpressionOpCodeIndex;

BOOLEAN          mInScopeSubtitle;
BOOLEAN          mInScopeSuppress;
BOOLEAN          mInScopeGrayOut;
BOOLEAN          mInScopeDisable;
FORM_EXPRESSION  *mSuppressExpression;
FORM_EXPRESSION  *mGrayOutExpression;
FORM_EXPRESSION  *mDisableExpression;

extern MULTI_PLATFORM_PARAMETERS   mMultiPlatformParam;
extern LIST_ENTRY                  mVarListEntry;
extern LIST_ENTRY                  mFormSetListEntry;
extern UINT32                      mFormSetOrderParse;

#define FORM_SET_GUID_PREFIX    "Form Set GUID: "
#define EFI_GUID_FORMAT         "%08x-%04x-%04x-%02x%02x-%02x%02x%02x%02x%02x%02x"

UINT32 mMaxCount = 0x100000;
UINT32 mCount = 0;
CHAR8  *mStringBuffer = NULL;
static EFI_GUID gEdkiiIfrBitVarGuid = EDKII_IFR_BIT_VARSTORE_GUID;

/**
  Produces a Null-terminated ASCII string in mStringBuffer based on a Null-terminated
  ASCII format string and variable argument list.
   
  @param  FormatString    A null-terminated ASCII format string.
  @param  ...             The variable argument list whose contents are accessed based on the 
                          format string specified by FormatString.
**/
VOID
StringPrint (
  CHAR8 *FormatString, 
  ...
)
{
  va_list Marker;
  INT32   Count;
  
  va_start (Marker, FormatString);
  Count = vsprintf (mStringBuffer + mCount, FormatString, Marker);
  mCount = mCount + Count;
  va_end (Marker);
  if (mCount + 0x400 > mMaxCount) {
    mStringBuffer[mCount] = '\0';
    fwrite (mStringBuffer, sizeof (CHAR8), mCount, stdout);
    mCount = 0;
  }
}

/**
  Print the information of questions.

  @param  FormSet     The pointer to the formset.
  @param  FormSet     The pointer to the form.
  @param  Question    The pointer to the question.
  @param  PrintOrNot  Decide whether print or not.

  @return NULL.

**/
STATIC
VOID
PrintQuestion (
  IN  FORM_BROWSER_FORMSET    *FormSet,
  IN  FORM_BROWSER_FORM       *Form,
  IN  FORM_BROWSER_STATEMENT  *Question,
  IN  BOOLEAN                  PrintOrNot
  );

/**
  Writes a Unicode string specified by iStringToken and iLanguage to the script file (converted to ASCII).
   
  @param  Package        A pointer to the Unicode string.

  @return NULL

**/
STATIC
VOID
LogUnicodeString (
  IN     CHAR16              *pcString
  )
{
  UINTN  Index;
  
  if (pcString == NULL) {
    return;
  }
  //
  // replace the 0x0D to 0x20, because if the pcString has 0D 0A, then after print it,
  // different editor may have different format
  //
  for (Index = 0; pcString[Index] != 0; Index++) {
    if (pcString[Index] == 0x0D) {
       pcString[Index] = 0x20;
    }
  
    StringPrint("%c", pcString[Index] & 0x00FF);
  }
}

/**
  Writes a UQIL Unicode string specified by iStringToken to the script file as an array of 16-bit integers in ASCII.
   
  @param  Package        A pointer to the Unicode string.

  @return NULL

**/
STATIC
VOID
LogUqi (
  IN     CHAR16              *pcString
  )
{
  UINT16         Index;
  //
  //  Find the UNICODE string length (in CHAR16)
  //
  for (Index = 0; pcString[Index] != 0; Index++);
  //
  //  Write each word as a hex integer
  //
  for (Index = 0; pcString[Index] != 0; Index++) {
    StringPrint("%04X ", pcString[Index]);
  }
}    

/**
  Get the question value with bit field from the buffer.

  @param  Question        The question refer to bit field.
  @param  Buffer          The buffer which the question value get from.
  @param  Value           Retun the value.

**/
VOID
GetBitsQuestionValue(
  IN  FORM_BROWSER_STATEMENT *Question,
  IN  UINT8                  *Buffer,
  OUT UINT32                 *Value
  )
{
  UINT32        PreBits;
  UINT32        Mask;

  PreBits = Question->BitVarOffset - Question->VarStoreInfo.VarOffset * 8;
  Mask = (1<< Question->BitStorageWidth) -1;

  *Value = *(UINT32*)Buffer;
  (*Value) >>= PreBits;
  (*Value) &= Mask;
}

/**
  Set the question value with bit field to the buffer.

  @param  Question        The question refer to bit field.
  @param  Buffer          The buffer which the question value set to.
  @param  Value           The value need to set.

**/
VOID
SetBitsQuestionValue (
  IN     FORM_BROWSER_STATEMENT *Question,
  IN OUT UINT8                  *Buffer,
  IN     UINT32                 Value
  )
{
  UINT32        PreBits;
  UINT32        Mask;
  UINT32        TmpValue;

  PreBits = Question->BitVarOffset - Question->VarStoreInfo.VarOffset * 8;
  Value <<= PreBits;
  Mask = (1<< Question->BitStorageWidth) -1;
  Mask <<= PreBits;

  TmpValue = *(UINT32*)(Buffer);
  TmpValue = (TmpValue & (~Mask)) | Value;
  CopyMem ((UINT32*)Buffer, &TmpValue, sizeof (UINT32));
}

/**
  Print the current value of the specified question.

  @param  Question       The pointer to question   
  
  @return EFI_SUCCESS
**/
STATIC
EFI_STATUS
LogIfrValue (
  IN  FORM_BROWSER_FORMSET     *FormSet,
  IN  FORM_BROWSER_STATEMENT   *Question
  )
{
  EFI_STATUS          Status;
  FORMSET_STORAGE     *VarList;
  UINT8               *VarBuffer;
  UINT32              Value;

  VarBuffer    = NULL;

  Status = SearchVarStorage (
             Question, 
             NULL, 
             Question->VarStoreInfo.VarOffset,
             FormSet->StorageListHead,
             (CHAR8 **)&VarBuffer, 
             &VarList
             );
  
  if (EFI_ERROR (Status)) {
    StringPrint("\nCouldn't read current variable data.");
    return EFI_ABORTED;
  } 
  //
  //  Log the Value
  //
  if (
    (Question->VarStoreInfo.VarOffset > VarList->Size)   \
    && (VarList->Type == EFI_IFR_VARSTORE_OP)
    ) {
    StringPrint("0000 // Offset larger than Variable Size -- FAILURE");
  } else if (
    (Question->VarStoreInfo.VarOffset > VarList->Size) \
    && (VarList->Type == EFI_IFR_VARSTORE_EFI_OP)       \
    && VarList->NewEfiVarstore
    ) {
    StringPrint("0000 // Offset larger than Variable Size -- FAILURE");
  }  else if (
    (Question->StorageWidth > VarList->Size)           \
    && (VarList->Type == EFI_IFR_VARSTORE_EFI_OP)      \
    && !VarList->NewEfiVarstore
    ) {
    StringPrint("0000 // Offset larger than Variable Size -- FAILURE");
  } else {
    if (Question->QuestionReferToBitField) {
      GetBitsQuestionValue (Question, VarBuffer, &Value);
      VarBuffer = (UINT8*)(&Value);
    }
    switch (Question->StorageWidth) {
    
    case sizeof (UINT8):
      StringPrint("%02X", (*(UINT8 *)VarBuffer) & 0xFF);
      break;
      
    case sizeof (UINT16):
      StringPrint("%04X", (*(UINT16 *)VarBuffer) & 0xFFFF);
      break;
  
    case sizeof (UINT32):
      StringPrint("%08X", (*(UINT32 *)VarBuffer) & 0xFFFFFFFF);
      break;
  
    case sizeof (UINT64):
      StringPrint("%016llX", *((UINT64 *)VarBuffer));
      break;
  
    default:
      StringPrint("0000 // Width > 16 is not supported -- FAILURE");
      break;
    }
  }
  return EFI_SUCCESS;
}    

/**
  Print the current value of the STRING question.

  @param  Question       The pointer to question   

  @return EFI_SUCCESS
**/
STATIC
EFI_STATUS
LogIfrValueStr (
  IN  FORM_BROWSER_FORMSET     *FormSet,
  IN  FORM_BROWSER_STATEMENT   *Question
  )
{
  EFI_STATUS          Status;
  FORMSET_STORAGE     *VarList;
  UINT8               *VarBuffer;

  VarBuffer = NULL;
  Status = SearchVarStorage (
             Question, 
             NULL, 
             Question->VarStoreInfo.VarOffset,
             FormSet->StorageListHead,
             (CHAR8 **)&VarBuffer, 
             &VarList
             );

  if (EFI_ERROR (Status)) {
    StringPrint("\nCouldn't read current variable data.");
    return EFI_ABORTED;
  } 

  //
  //  Log the Value
  //
  if (
    (Question->VarStoreInfo.VarOffset > VarList->Size)   \
    && (VarList->Type == EFI_IFR_VARSTORE_OP)
    ) {
    StringPrint("0000 // Offset larger than Variable Size -- FAILURE");
  } else if (
    (Question->VarStoreInfo.VarOffset > VarList->Size) \
    && (VarList->Type == EFI_IFR_VARSTORE_EFI_OP)       \
    && VarList->NewEfiVarstore
    ) {
    StringPrint("0000 // Offset larger than Variable Size -- FAILURE");
  }  else if (
    (Question->StorageWidth > VarList->Size)           \
    && (VarList->Type == EFI_IFR_VARSTORE_EFI_OP)      \
    && !VarList->NewEfiVarstore
    ) {
    StringPrint("0000 // Offset larger than Variable Size -- FAILURE");
  } else {
      StringPrint("\"");
      LogUnicodeString((CHAR16 *)VarBuffer);
      StringPrint("\"");
  }
  return EFI_SUCCESS;
}

/**
  Print the current values of an Ordered List question.

  @param  Question       The pointer to question  
  @param  MaxEntries       The max number of options  
  @param  VarList          The dual pointer to the Node of VarList 
  
  @return EFI_SUCCESS
**/
STATIC
EFI_STATUS
LogIfrValueList (
  IN  FORM_BROWSER_FORMSET     *FormSet,
  IN  FORM_BROWSER_STATEMENT   *Question
  )
{
  EFI_STATUS          Status;
  FORMSET_STORAGE     *VarList;
  UINT8               CurrentEntry;
  UINT8               *VarBuffer;
  
  CurrentEntry = 0;
  VarBuffer    = NULL;

  Status = SearchVarStorage (
             Question, 
             NULL, 
             Question->VarStoreInfo.VarOffset,  
             FormSet->StorageListHead,
             (CHAR8 **)&VarBuffer, 
             &VarList
             );
             
  if (EFI_ERROR (Status)) {
    StringPrint("\nCouldn't read current variable data.");
    return EFI_ABORTED;
  } 
  //
  // Log the value
  //
  if (
    ((Question->VarStoreInfo.VarOffset +  Question->MaxContainers) > VarList->Size)   \
    && (VarList->Type == EFI_IFR_VARSTORE_OP)
    ) {
    StringPrint("0000 // Offset larger than Variable Size -- FAILURE");
  } else if (
    (Question->MaxContainers > VarList->Size) \
    && (VarList->Type == EFI_IFR_VARSTORE_EFI_OP)
    ) {
    StringPrint("0000 // Offset larger than Variable Size -- FAILURE");
  } else {
    for (CurrentEntry = 0; CurrentEntry < Question->MaxContainers; CurrentEntry++) {
    
      switch (Question->StorageWidth/Question->MaxContainers){

      case 1:
        StringPrint("%02X ", VarBuffer[CurrentEntry]);
        break;
        
      case 2:
        StringPrint("%04X ", *((UINT16 *)VarBuffer + CurrentEntry));
        break;

      case 4:
        StringPrint("%08X ", *((UINT32 *)VarBuffer + CurrentEntry));
        break;

      case 8:
        StringPrint("%016llX ", *((UINT64 *)VarBuffer + CurrentEntry));
        break;

      default:
        StringPrint("%02X ", VarBuffer[CurrentEntry]);
      }
    }
  }
  return EFI_SUCCESS;
}    

/**
  Compare two Uqi parameters

  @param UqiParm1       The pointer to the first Uqi parameter.
  @param UqiParm2       The pointer to the second Uqi parameter.

  @retval TRUE          If these two Uqi parameters are the same, return TRUE;
  @return FALSE         Otherwise, return FALSE;
**/
BOOLEAN
CompareUqiHeader (
  IN  CONST UQI_HEADER  *UqiParm1,
  IN  CONST UQI_HEADER  *UqiParm2
  )
{
  INT32    Index;

  if (UqiParm1->HexNum != UqiParm2->HexNum) {
    return FALSE;
  }

  for (Index = UqiParm1->HexNum - 1; Index >= 0; Index--) {
    if (UqiParm1->Data[Index] != UqiParm2->Data[Index]) {
      return FALSE;
    }
  }

  return TRUE;
}


/**
  Check whether existed a same variable in the LIST_ENTRY.

  @param  CurVarList        A pointer to a variable node.

  @return Pointer          If existed the same variable, return the pointer to the Node.
  @return NULL              Otherwise, return FALSE

**/
STATIC
FORMSET_STORAGE *
NotSameVariableInVarList (
  IN  LIST_ENTRY         *VariableListEntry,
  IN  FORMSET_STORAGE    *StorageNode
  )
{
  FORMSET_STORAGE    *CurNode;
  LIST_ENTRY         *Link;
  LIST_ENTRY         *StorageListHead;

  StorageListHead       =  VariableListEntry;
  CurNode               = NULL;

  //
  // Find Storage for this Question
  //
  Link = GetFirstNode (StorageListHead);
  while (!IsNull (StorageListHead, Link)) {
    CurNode = FORMSET_STORAGE_FROM_LINK (Link);

    if (!CompareGuid (&StorageNode->Guid, &CurNode->Guid)   \
      && (CurNode->Name != NULL)                            \
      && (StorageNode->Name != NULL)                        \
      && !FceStrCmp (StorageNode->Name, CurNode->Name)         \
      && (StorageNode - CurNode != 0) 
      ) {
      //
      // If not multi-plaform support mode, take VarStore as the EfiVarStore. So If there are
      // two variables with same guid same name, but different type, we will take as the same
      // in general mode
      //
      if (mMultiPlatformParam.MultiPlatformOrNot && (CurNode->Type == StorageNode->Type)) {
        //
        // If matched, get the address of EFI_IFR_VARSTORE data.
        //
        return CurNode;
        break;
      } else if (!mMultiPlatformParam.MultiPlatformOrNot) {
        return CurNode;
        break;
      }
    }
    Link = GetNextNode (StorageListHead, Link);
  }
  return NULL;
}

/**
  Get the variable Guid and Name by the variableId and FormSetOrder. 

  @param  FormSet        The pointer to the formset.
  @param  FormSet        The pointer to the form.
  @param  ListEntry      The pointer to the LIST_ENTRY.
  
  @return EFI_SUCCESS
  @return EFI_NOT_FOUND  If not find the the variable, or the variable doesn't belong to EfiVarStore or VarStore. 
**/
STATIC
EFI_STATUS
GetGuidNameByVariableId (
  IN       FORM_BROWSER_FORMSET    *FormSet,
  IN  OUT  FORM_BROWSER_STATEMENT  *Question,
  IN       LIST_ENTRY              *ListEntry
  )
{
  FORMSET_STORAGE    *CurNode;
  LIST_ENTRY         *Link;
  LIST_ENTRY         *StorageListHead;
  EFI_STATUS         Status;
  CHAR16             *EfiVariableName;

  StorageListHead       = ListEntry;
  CurNode               = NULL;
  Status                = EFI_SUCCESS;
  EfiVariableName       = NULL;

  Link = GetFirstNode (StorageListHead);
  while (!IsNull (StorageListHead, Link)) {
    CurNode = FORMSET_STORAGE_FROM_LINK (Link);

    if ((FormSet->FormSetOrder == CurNode->FormSetOrder) \
      && (Question->VarStoreId == CurNode->VarStoreId)
      ) {
      //
      // Copy type to question to avoid the case that EfiVarStore and VarStore have the same Guid and name.
      //
      Question->Type           = CurNode->Type;
      Question->NewEfiVarstore = CurNode->NewEfiVarstore;
      Question->Attributes     = CurNode->Attributes;
      
      if (CurNode->Type == EFI_IFR_VARSTORE_EFI_OP) {
        CopyMem (&Question->Guid, &CurNode->Guid, sizeof (EFI_GUID));
        //
        // If the first time to access the old EfiVarStore, need to sync the variable name
        //
        if (!CurNode->NewEfiVarstore) {
          if (CurNode->Buffer == NULL) {
            CurNode->Buffer = malloc (Question->StorageWidth);
          }
          if (CurNode->Name == NULL) {
            Status  = FindDefaultName (
                      &(FormSet->EnUsStringList),
                      FormSet->UnicodeBinary, 
                      Question->VarStoreInfo.VarName, 
                      EN_US, 
                      &EfiVariableName
                     );
            if (EFI_ERROR(Status)) {
              return Status;
            }
            CurNode->Name = EfiVariableName;
          }
          if (CurNode->Size == 0) {
            CurNode->Size = Question->StorageWidth;
          }
        }
        //
        // Check whether the Efivariable variable name is valid.
        //
         if ((CurNode->Name == NULL) || (FceStrLen (CurNode->Name) == 0)) {
          StringPrint ("Error. The variable name of question is NULL. Its UQI is: ");
          StringPrint("Q %04X ", Question->Uqi.HexNum);
          LogUqi (Question->Uqi.Data);
          StringPrint ("\n");
          return EFI_ABORTED;
        }
        if (Question->VariableName == NULL) {
          Question->VariableName = (CHAR16 *) malloc (2 * (FceStrLen ((CONST CHAR16 *)CurNode->Name) + 1));
          if (Question->VariableName == NULL) {
           return EFI_ABORTED;
          }
        }
        StrCpy (Question->VariableName, CurNode->Name);
        
        return EFI_SUCCESS;
        
      } else if (CurNode->Type == EFI_IFR_VARSTORE_OP) {
        CopyMem (&Question->Guid, &CurNode->Guid, sizeof (EFI_GUID));
        if (Question->VariableName == NULL) {
          Question->VariableName = (CHAR16 *) malloc (2 * (FceStrLen ((CONST CHAR16 *)CurNode->Name) + 1));
          if (Question->VariableName == NULL) {
           return EFI_ABORTED;
          }
        }
        //
        // Check whether the variable variable name is valid.
        //
         if ((CurNode->Name == NULL) || (FceStrLen (CurNode->Name) == 0)) {
          StringPrint ("Error. The variable name of question is NULL. UQI:");
          StringPrint("Q %04X ", Question->Uqi.HexNum);
          LogUqi (Question->Uqi.Data);
          StringPrint ("\n");
          return EFI_ABORTED;
        }
        StrCpy (Question->VariableName, CurNode->Name);
        return EFI_SUCCESS;
      }
    }
    Link = GetNextNode (StorageListHead, Link);
  }
  return EFI_NOT_FOUND;
}

/**
  Get the UniString by the offset.

  @param  UniPackge         A pointer to the beginning of Null-terminated Unicode string Array.
  @param  CurUniPackge      A pointer to the current position of Null-terminated Unicode string Array.
  @param  VarDefaultNameId  The string ID.
  @param  CurOrDefaultLang  Use the current language or the default language.
  @param  VarDefaultName    return the name string.

  @return EFI_SUCCESS
  @return EFI_INVALID_PARAMETER
  @return EFI_NOT_FOUND 
**/
STATIC
EFI_STATUS
GetStringByOffset (
  IN     UINT8               *UniPackge,
  IN     UINT8               *CurUniPackge,
  IN     UINT16              VarDefaultNameId,
  IN     BOOLEAN             CurOrDefaultLang,
  IN OUT CHAR16              **VarDefaultName
  ) 
{
  UINT8                          *HiiStringHeader;
  UINT32                         Offset;
  UINT32                         Count;
  UINT32                         Index;
  EFI_HII_STRING_BLOCK           *Block;
  VOID                           *ThisBlock;

  assert ((UniPackge != NULL) && (CurUniPackge != NULL));

  HiiStringHeader  = NULL;
  Offset           = 1;
  Count            = 0;
  Block            = NULL;
  ThisBlock        = NULL;
  
  if (VarDefaultNameId == 0) {
    return EFI_INVALID_PARAMETER;
  }  
  if (CurOrDefaultLang) {
    HiiStringHeader = CurUniPackge;
  } else {
    HiiStringHeader  = UniPackge + 4;
  }

  Block = (EFI_HII_STRING_BLOCK *)((UINT8*)HiiStringHeader + ((EFI_HII_STRING_PACKAGE_HDR *)HiiStringHeader)->HdrSize);
  //
  // Search the matched String in specificated language package by the Offset
  //
  while( Block->BlockType != EFI_HII_SIBT_END ) {
    switch (Block->BlockType) {
    case EFI_HII_SIBT_STRING_SCSU:
      ThisBlock = (VOID *)Block;
      for (Index = 0 ; ((EFI_HII_SIBT_STRING_SCSU_BLOCK *)ThisBlock)->StringText[Index] != 0 ; Index++) ;
      Block = (EFI_HII_STRING_BLOCK *)&((EFI_HII_SIBT_STRING_SCSU_BLOCK *)ThisBlock)->StringText[Index + 1];
      break;
      
    case EFI_HII_SIBT_STRING_SCSU_FONT:
      ThisBlock = (VOID *)Block;
      for (Index = 0 ; ((EFI_HII_SIBT_STRING_SCSU_FONT_BLOCK *)ThisBlock)->StringText[Index] != 0 ; Index++) ;
      Block = (EFI_HII_STRING_BLOCK *)(((EFI_HII_SIBT_STRING_SCSU_FONT_BLOCK *)ThisBlock) + 1);
      break;
      
    case EFI_HII_SIBT_STRINGS_SCSU:
      ThisBlock = (VOID *)Block;
      for( Count= ((EFI_HII_SIBT_STRINGS_SCSU_BLOCK *)ThisBlock)->StringCount, Index = 0 ; Count; Count--, Index++ ) {
        for ( ; ((EFI_HII_SIBT_STRINGS_SCSU_BLOCK *)ThisBlock)->StringText[Index] != 0 ; Index++) ;
      }
      Block = (EFI_HII_STRING_BLOCK *)&((EFI_HII_SIBT_STRINGS_SCSU_BLOCK *)ThisBlock)->StringText[Index];
      break;
      
    case EFI_HII_SIBT_STRINGS_SCSU_FONT:
      ThisBlock = (VOID *)Block;
      for( Count = ((EFI_HII_SIBT_STRINGS_SCSU_FONT_BLOCK *)ThisBlock)->StringCount, Index = 0 ; Count; Count--, Index++ ) ;
      Block = (EFI_HII_STRING_BLOCK *) & ((EFI_HII_SIBT_STRINGS_SCSU_FONT_BLOCK *)ThisBlock)->StringText[Index];
      break;

    case EFI_HII_SIBT_STRING_UCS2:
      ThisBlock = (VOID *)Block;
      if (Offset == VarDefaultNameId)  {
      *VarDefaultName = malloc ((FceStrLen ((CHAR16 *) ((EFI_HII_SIBT_STRING_UCS2_BLOCK *)ThisBlock)->StringText) + 1) * sizeof (CHAR16));
      if (*VarDefaultName == NULL) {
        printf ("Fail to allocate memory");
        return EFI_OUT_OF_RESOURCES;
      }
      memset (
        *VarDefaultName, 
        0, 
        (FceStrLen ((CHAR16 *) ((EFI_HII_SIBT_STRING_UCS2_BLOCK *)ThisBlock)->StringText) + 1) * sizeof (CHAR16)
      );
      StrCpy (
        *VarDefaultName, 
        (CHAR16 *) ((EFI_HII_SIBT_STRING_UCS2_BLOCK *) ThisBlock)->StringText
      );
      return EFI_SUCCESS;
    }
      
      for (Index = 0 ; ((EFI_HII_SIBT_STRING_UCS2_BLOCK *)ThisBlock)->StringText[Index] != 0 ; Index++) ;
      Block = (EFI_HII_STRING_BLOCK *) & ((EFI_HII_SIBT_STRING_UCS2_BLOCK *) ThisBlock)->StringText[Index + 1];
      Offset += 1;
      break;
      
    case EFI_HII_SIBT_STRING_UCS2_FONT:
      ThisBlock = (VOID *)Block;
      for (Index = 0 ; ((EFI_HII_SIBT_STRING_UCS2_FONT_BLOCK *) ThisBlock)->StringText[Index] != 0 ; Index++) ;
      Block = (EFI_HII_STRING_BLOCK *)& ((EFI_HII_SIBT_STRING_UCS2_FONT_BLOCK *) ThisBlock)->StringText[Index + 1];
      break;
      
    case EFI_HII_SIBT_STRINGS_UCS2:
      ThisBlock = (VOID *)Block;
      for( Count = ((EFI_HII_SIBT_STRINGS_UCS2_BLOCK *)ThisBlock)->StringCount, Index = 0 ; Count; Count--, Index++ ) {
        for ( ; ((EFI_HII_SIBT_STRINGS_UCS2_BLOCK *) ThisBlock)->StringText[Index] != 0 ; Index++) ;
      }
      Block = (EFI_HII_STRING_BLOCK *) & ((EFI_HII_SIBT_STRINGS_UCS2_BLOCK *) ThisBlock)->StringText[Index];
      break;
      
    case EFI_HII_SIBT_STRINGS_UCS2_FONT:
      ThisBlock = (VOID *)Block;
      for( Count= ((EFI_HII_SIBT_STRINGS_UCS2_FONT_BLOCK *) ThisBlock)->StringCount, Index = 0 ; Count ; Count--, Index++ ) {
        for ( ; ((EFI_HII_SIBT_STRINGS_UCS2_FONT_BLOCK *) ThisBlock)->StringText[Index] != 0 ; Index++) ;
      }
      Block = (EFI_HII_STRING_BLOCK *) & ((EFI_HII_SIBT_STRINGS_UCS2_FONT_BLOCK *)ThisBlock)->StringText[Index];
      break;
      
     case EFI_HII_SIBT_DUPLICATE:
       ThisBlock = (VOID *)Block;
       Block = (EFI_HII_STRING_BLOCK *)((EFI_HII_SIBT_DUPLICATE_BLOCK *) ThisBlock + 1);
       break;
       
     case EFI_HII_SIBT_SKIP2:
       ThisBlock = (VOID *)Block;
       Offset += ((EFI_HII_SIBT_SKIP2_BLOCK *) ThisBlock)->SkipCount;
       Block = (EFI_HII_STRING_BLOCK *)( (EFI_HII_SIBT_SKIP2_BLOCK *) ThisBlock + 1);
       break;
       
     case EFI_HII_SIBT_SKIP1:
       ThisBlock = (VOID *)Block;
       Offset += ((EFI_HII_SIBT_SKIP1_BLOCK *) ThisBlock)->SkipCount;
       Block = (EFI_HII_STRING_BLOCK *)((EFI_HII_SIBT_SKIP1_BLOCK *)ThisBlock + 1);
       break;
       
     case EFI_HII_SIBT_EXT1:
       ThisBlock = (VOID *)Block;
       Block = (EFI_HII_STRING_BLOCK *)((UINT8*)ThisBlock + ((EFI_HII_SIBT_EXT1_BLOCK *) ThisBlock)->Length);
       break;
       
     case EFI_HII_SIBT_EXT2:
       ThisBlock = (VOID *)Block;
       Block = (EFI_HII_STRING_BLOCK *)((UINT8*)ThisBlock + ((EFI_HII_SIBT_EXT2_BLOCK *) ThisBlock)->Length);
       break;
       
     case EFI_HII_SIBT_EXT4:
       ThisBlock = (VOID *)Block;
       Block = (EFI_HII_STRING_BLOCK *)((UINT8*)ThisBlock + ((EFI_HII_SIBT_EXT4_BLOCK *)ThisBlock)->Length);
       break;
       
     case EFI_HII_SIBT_FONT:
       ThisBlock = (VOID *)Block;
       for (Index = 0 ; ((EFI_HII_SIBT_FONT_BLOCK *) ThisBlock)->FontName[Index] != 0 ; Index++) ;
       Block = (EFI_HII_STRING_BLOCK *)& ((EFI_HII_SIBT_FONT_BLOCK *) ThisBlock)->FontName[Index + 1];
       break;

     default:
       StringPrint("Unhandled type = 0x%x\n", Block->BlockType);
     }
   }

  return EFI_NOT_FOUND;
}

/**
  Parse the UniString to get the string information.
  
  @param  CachedStringList  A pointer to cached string list
  @param  UniPackge         A pointer to a Null-terminated Unicode string Array.
  @param  VarDefaultNameId  The string ID.
  @param  Language          The language, en-US UQI or eng.
  @param  VarDefaultName    return the name string.

  @return EFI_SUCCESS       If get the name string successfully
  @return EFI_NOT_FOUND       An error occurred.
  @return EFI_INVALID_PARAMETER
 
**/
EFI_STATUS
FindDefaultName (
  IN     FORMSET_STRING_LIST *CachedStringList,
  IN     UINT8               *UniPackge,
  IN     UINT16              VarDefaultNameId,
  IN     LANGUAGE            Language,
  IN OUT CHAR16              **VarDefaultName
  )
{
  CHAR8          *UniPackgeEnd;
  CHAR8          *UniBin;
  CHAR8          LangStr[10];
  BOOLEAN        IsFound;
  EFI_STATUS     Status;
  EFI_STRING_ID  Index; 
  STRING_INFO    *TempBuffer;

  UniBin     = NULL;
  IsFound    = FALSE;
  Status     = EFI_NOT_FOUND;
    
  UniBin       = (CHAR8 *) UniPackge + 4;
  UniPackgeEnd = (CHAR8 *) UniPackge + *(UINT32 *)UniPackge;

  //
  //Handle with the invalid usage "STRING_TOKEN(0)"
  //
  if (VarDefaultNameId == 0) {
    *VarDefaultName = L"";
    return EFI_SUCCESS;
  }
  
  if (CachedStringList != NULL) {
    for (Index = 0; Index < CachedStringList->CachedIdNum; Index ++) {
      if (VarDefaultNameId == CachedStringList->StringInfoList[Index].StringId) {
        *VarDefaultName = CachedStringList->StringInfoList[Index].String;
        return EFI_SUCCESS;
      }
    }
  }

  switch (Language) {

  case UQI:
    strcpy (LangStr, "uqi");
    break;
    
  case EN_US:
    strcpy (LangStr, "en-US");
    break;
    
  case ENG:
    strcpy (LangStr, "eng");
    break;
    
  default:
    strcpy (LangStr, "en-US");
    break;
  }
  IsFound    = FALSE;

  if (((EFI_HII_PACKAGE_HEADER *)UniBin)->Type == EFI_HII_PACKAGE_STRINGS) {
    //
    // Search the specified language package
    //
    while ((UniBin < UniPackgeEnd) && ((EFI_HII_PACKAGE_HEADER *)UniBin)->Type == EFI_HII_PACKAGE_STRINGS) {
      if (strcmp (((EFI_HII_STRING_PACKAGE_HDR *)UniBin)->Language, LangStr) == 0) {
        IsFound = TRUE;
        break;
      }
      UniBin += ((EFI_HII_STRING_PACKAGE_HDR *)UniBin)->Header.Length;
    }
    //
    //If not find the string ID, use the en eng or en-US instead.
    //
    if (!IsFound) {
      UniBin     = (CHAR8 *) UniPackge + 4;

      while ((UniBin < UniPackgeEnd) && ((EFI_HII_PACKAGE_HEADER *)UniBin)->Type == EFI_HII_PACKAGE_STRINGS) {
        if ((strcmp (((EFI_HII_STRING_PACKAGE_HDR *)UniBin)->Language, "en") == 0)    \
          || (strcmp (((EFI_HII_STRING_PACKAGE_HDR *)UniBin)->Language, "en-US") == 0) \
          || (strcmp (((EFI_HII_STRING_PACKAGE_HDR *)UniBin)->Language, "eng") == 0)   \
          ) {
          IsFound = TRUE;
          break;
        }
        UniBin += ((EFI_HII_STRING_PACKAGE_HDR *)UniBin)->Header.Length;
      }
    }
     //
     //If not still find the string ID, use the first one instead.
     //
     Status = GetStringByOffset (
                UniPackge, 
                (UINT8 *)UniBin, 
                VarDefaultNameId, 
                IsFound, 
                VarDefaultName
                );
     if (!EFI_ERROR (Status)) {
       goto Done;
     }
    //
    //If not find the specified string in UQI package, we use the en en-us eng or uqi insteadly
    //
    IsFound    = FALSE;
    UniBin     = (CHAR8 *) UniPackge + 4;

    while ((UniBin < UniPackgeEnd) && ((EFI_HII_PACKAGE_HEADER *)UniBin)->Type == EFI_HII_PACKAGE_STRINGS) {
      if (strcmp (((EFI_HII_STRING_PACKAGE_HDR *)UniBin)->Language, "en") == 0) {
        IsFound = TRUE;
        break;
      }
      UniBin += ((EFI_HII_STRING_PACKAGE_HDR *)UniBin)->Header.Length;
    }
    Status = GetStringByOffset (
              UniPackge, 
              (UINT8 *)UniBin, 
              VarDefaultNameId, 
              IsFound, 
              VarDefaultName
              );
    if (!EFI_ERROR (Status)) {
      goto Done;
    }

    IsFound    = FALSE;
    UniBin     = (CHAR8 *) UniPackge + 4;

    while ((UniBin < UniPackgeEnd) && ((EFI_HII_PACKAGE_HEADER *)UniBin)->Type == EFI_HII_PACKAGE_STRINGS) {
      if (strcmp (((EFI_HII_STRING_PACKAGE_HDR *)UniBin)->Language, "en-US") == 0) {
        IsFound = TRUE;
        break;
      }
      UniBin += ((EFI_HII_STRING_PACKAGE_HDR *)UniBin)->Header.Length;
    }
    Status = GetStringByOffset (
              UniPackge, 
              (UINT8 *)UniBin, 
              VarDefaultNameId, 
              IsFound, 
              VarDefaultName
              );
    if (!EFI_ERROR (Status)) {
      goto Done;
    }

    IsFound    = FALSE;
    UniBin     = (CHAR8 *) UniPackge + 4;

    while ((UniBin < UniPackgeEnd) && ((EFI_HII_PACKAGE_HEADER *)UniBin)->Type == EFI_HII_PACKAGE_STRINGS) {
      if (strcmp (((EFI_HII_STRING_PACKAGE_HDR *)UniBin)->Language, "eng") == 0) {
        IsFound = TRUE;
        break;
      }
      UniBin += ((EFI_HII_STRING_PACKAGE_HDR *)UniBin)->Header.Length;
    }
    Status = GetStringByOffset (
              UniPackge, 
              (UINT8 *)UniBin, 
              VarDefaultNameId, 
              IsFound, 
              VarDefaultName
              );
    if (!EFI_ERROR (Status)) {
      goto Done;
    }

    IsFound    = FALSE;
    UniBin     = (CHAR8 *) UniPackge + 4;

    while ((UniBin < UniPackgeEnd) && ((EFI_HII_PACKAGE_HEADER *)UniBin)->Type == EFI_HII_PACKAGE_STRINGS) {
      if (strcmp (((EFI_HII_STRING_PACKAGE_HDR *)UniBin)->Language, "uqi") == 0) {
        IsFound = TRUE;
        break;
      }
      UniBin += ((EFI_HII_STRING_PACKAGE_HDR *)UniBin)->Header.Length;
    }
    Status = GetStringByOffset (
              UniPackge, 
              (UINT8 *)UniBin, 
              VarDefaultNameId, 
              IsFound, 
              VarDefaultName
              );
    if (!EFI_ERROR (Status)) {
      goto Done;
    }
  }

Done:
  if (EFI_ERROR (Status)) {
    *VarDefaultName = NULL;
    return EFI_NOT_FOUND;
  }
  
  if (CachedStringList != NULL) {
    if (CachedStringList->CachedIdNum >= CachedStringList->MaxIdNum) {
      TempBuffer = calloc (sizeof (STRING_INFO), CachedStringList->MaxIdNum + STRING_NUMBER);
      if (TempBuffer == NULL) {
        printf ("Fail to allocate memory! \n");
        free (*VarDefaultName);
        *VarDefaultName = NULL;
        return EFI_OUT_OF_RESOURCES;
      }
      CopyMem (TempBuffer, CachedStringList->StringInfoList, sizeof (STRING_INFO) * CachedStringList->MaxIdNum);
      FreePool (CachedStringList->StringInfoList);
      CachedStringList->StringInfoList = TempBuffer;
      CachedStringList->MaxIdNum = CachedStringList->MaxIdNum + STRING_NUMBER;
    }
    CachedStringList->StringInfoList[CachedStringList->CachedIdNum].StringId = VarDefaultNameId;
    CachedStringList->StringInfoList[CachedStringList->CachedIdNum].String   = *VarDefaultName;
    CachedStringList->CachedIdNum ++;
  }
  return EFI_SUCCESS;
}

/**
  Search the variable list according to the variable Guid and name, and return the pointer
  of that Node. 

  @param  HiiObjList       The pointer to the Question
  @param  VarName          The EFI variable name need to be updated to VarList
  @param  Offset           The offset of the variable
  @param  StorageListHead  The pointer to the LIST_ENTRY of Storage
  @param  Vaue             The value in that value offset of the variable
  @param  VarList          The dual pointer of Varlist
  
  @return EFI_SUCCESS
  @return EFI_NOT_FOUND
**/
EFI_STATUS
SearchVarStorage (
  IN     FORM_BROWSER_STATEMENT   *Question,
  IN     CHAR16*                  VarName,
  IN     UINT32                   Offset, 
  IN     LIST_ENTRY               *StorageListHead,
  IN OUT CHAR8                    **Value,
  IN OUT FORMSET_STORAGE          **VarList
  )
{
  FORMSET_STORAGE   *CurNode;
  LIST_ENTRY        *Link;
  BOOLEAN           FindOrNot;

  CurNode         = NULL;
  FindOrNot       = FALSE;
  *VarList        = NULL;
  //
  // Find Storage for this Question
  //
  Link = GetFirstNode (StorageListHead);
  while (!IsNull (StorageListHead, Link)) {
    CurNode = FORMSET_STORAGE_FROM_LINK (Link);
    //
    // Deal with the old EfiVarstore before UEFI2.31
    //
    if (!CompareGuid (&Question->Guid, &CurNode->Guid)          \
      && (CurNode->Type == EFI_IFR_VARSTORE_EFI_OP)             \
      && !CurNode->NewEfiVarstore                               \
      && (Question->VariableName != NULL)                       \
      && (CurNode->Name != NULL)                                \
      && !FceStrCmp(Question->VariableName, CurNode->Name)
      ) {
      //
      // If not multi-plaform support mode, take VarStore as the EfiVarStore. So If there are
      // two variables with same guid same name, but different type, we will take as the same
      // in general mode
      //
      if (mMultiPlatformParam.MultiPlatformOrNot && (CurNode->Type == Question->Type)) {
        //
        // check whether exist a old EFI_IFR_VARSTORE_EFI or not.
        //
        *Value = (CHAR8 *)CurNode->Buffer;
        *VarList = CurNode;
        FindOrNot  = TRUE;
        break;
      } else if (!mMultiPlatformParam.MultiPlatformOrNot) {
        //
        // check whether exist a old EFI_IFR_VARSTORE_EFI or not.
        //
        *Value = (CHAR8 *)CurNode->Buffer;
        *VarList = CurNode;
        FindOrNot  = TRUE;
        break;
      }
    }

    if (!CompareGuid (&Question->Guid, &CurNode->Guid)           \
      && (CurNode->Name != NULL)                                   \
      && (Question->VariableName != NULL)                          \
      && !FceStrCmp(Question->VariableName, CurNode->Name)
      ) {
      //
      // If not multi-plaform support mode, take VarStore as the EfiVarStore. So If there are
      // two variables with same guid same name, but different type, we will take as the same
      // in general mode
      //
      if (mMultiPlatformParam.MultiPlatformOrNot && (CurNode->Type == Question->Type)) {
        //
        // If matched, get the address of EFI_IFR_VARSTORE data.
        //
        *Value     = (CHAR8 *)(CurNode->Buffer + Offset);
        *VarList   = CurNode;
        FindOrNot  = TRUE;
        break;
      } else if (!mMultiPlatformParam.MultiPlatformOrNot) {
        //
        // If matched, get the address of EFI_IFR_VARSTORE data.
        //
        *Value     = (CHAR8 *)(CurNode->Buffer + Offset);
        *VarList   = CurNode;
        FindOrNot  = TRUE;
        break;
      }
    }
    Link = GetNextNode (StorageListHead, Link);
  }
  if (!FindOrNot) {
    return EFI_NOT_FOUND;
  }
  return EFI_SUCCESS;
}

/**
  Get the string based on the StringId and HII Package List Handle.

  @param  Token                  The String's ID.
  @param  HiiHandle              The package list in the HII database to search for
                                 the specified string.

  @return The output string.

**/
CHAR16 *
GetToken (
  IN  EFI_STRING_ID                Token,
  IN  UINT8                        *UniPackge
  )
{
  CHAR16      *VarDefaultName;
  EFI_STATUS  Status;

  Status = EFI_SUCCESS;

  if (UniPackge == NULL) {
    return NULL;
  }
  
  Status  = FindDefaultName (
              NULL,
              UniPackge, 
              Token, 
              EN_US, 
              &VarDefaultName
              );
  if (EFI_ERROR (Status)) {
    return NULL;
  }

  return VarDefaultName;
}

/**
  Initialize Statement header members.

  @param  OpCodeData             Pointer of the raw OpCode data.
  @param  FormSet                Pointer of the current FormSe.
  @param  Form                   Pointer of the current Form.

  @return The Statement.

**/
FORM_BROWSER_STATEMENT *
CreateStatement (
  IN UINT8                        *OpCodeData,
  IN OUT FORM_BROWSER_FORMSET     *FormSet,
  IN OUT FORM_BROWSER_FORM        *Form
  )
{
  FORM_BROWSER_STATEMENT    *Statement;
  EFI_IFR_STATEMENT_HEADER  *StatementHdr;

  if (Form == NULL) {
    //
    // We are currently not in a Form Scope, so just skip this Statement
    //
    return NULL;
  }

  Statement = &FormSet->StatementBuffer[mStatementIndex];
  mStatementIndex++;

  InitializeListHead (&Statement->DefaultListHead);
  InitializeListHead (&Statement->OptionListHead);
  InitializeListHead (&Statement->InconsistentListHead);
  InitializeListHead (&Statement->NoSubmitListHead);
  InitializeListHead (&Statement->WarningListHead);

  Statement->Signature = FORM_BROWSER_STATEMENT_SIGNATURE;

  Statement->Operand = ((EFI_IFR_OP_HEADER *) OpCodeData)->OpCode;
  Statement->QuestionReferToBitField = FALSE;

  StatementHdr = (EFI_IFR_STATEMENT_HEADER *) (OpCodeData + sizeof (EFI_IFR_OP_HEADER));
  CopyMem (&Statement->Prompt, &StatementHdr->Prompt, sizeof (EFI_STRING_ID));
  CopyMem (&Statement->Help, &StatementHdr->Help, sizeof (EFI_STRING_ID));

  if (mInScopeSuppress) {
    Statement->SuppressExpression = mSuppressExpression;
  }

  if (mInScopeGrayOut) {
    Statement->GrayOutExpression = mGrayOutExpression;
  }


  if (mInScopeDisable) {
    Statement->DisableExpression = mDisableExpression;
  }

  Statement->InSubtitle = mInScopeSubtitle;

  //
  // Insert this Statement into current Form
  //
  InsertTailList (&Form->StatementListHead, &Statement->Link);

  return Statement;
}

/**
  Initialize Question's members.

  @param  OpCodeData             Pointer of the raw OpCode data.
  @param  FormSet                Pointer of the current FormSet.
  @param  Form                   Pointer of the current Form.

  @return The Question.

**/
FORM_BROWSER_STATEMENT *
CreateQuestion (
  IN UINT8                        *OpCodeData,
  IN OUT FORM_BROWSER_FORMSET     *FormSet,
  IN OUT FORM_BROWSER_FORM        *Form
  )
{
  FORM_BROWSER_STATEMENT   *Statement;
  EFI_IFR_QUESTION_HEADER  *QuestionHdr;
  LIST_ENTRY               *Link;
  FORMSET_STORAGE          *Storage;
  NAME_VALUE_NODE          *NameValueNode;

  Statement = CreateStatement (OpCodeData, FormSet, Form);
  if (Statement == NULL) {
    return NULL;
  }

  QuestionHdr = (EFI_IFR_QUESTION_HEADER *) (OpCodeData + sizeof (EFI_IFR_OP_HEADER));
  CopyMem (&Statement->QuestionId, &QuestionHdr->QuestionId, sizeof (EFI_QUESTION_ID));
  CopyMem (&Statement->VarStoreId, &QuestionHdr->VarStoreId, sizeof (EFI_VARSTORE_ID));
  CopyMem (&Statement->VarStoreInfo.VarOffset, &QuestionHdr->VarStoreInfo.VarOffset, sizeof (UINT16));
  
  Statement->QuestionFlags = QuestionHdr->Flags;

  Statement->FormSetOrder = mFormSetOrderParse;

  if (Statement->VarStoreId == 0) {
    //
    // VarStoreId of zero indicates no variable storage
    //
    return Statement;
  }

  //
  // Find Storage for this Question
  //
  Link = GetFirstNode (FormSet->StorageListHead);
  while (!IsNull (FormSet->StorageListHead, Link)) {
    Storage = FORMSET_STORAGE_FROM_LINK (Link);

    if ((Storage->VarStoreId == Statement->VarStoreId) 
      && (Storage->FormSetOrder == Statement->FormSetOrder)) {
      Statement->Storage = Storage;
      break;
    }

    Link = GetNextNode (FormSet->StorageListHead, Link);
  }
  ASSERT (Statement->Storage != NULL);

  if (Statement->Storage->Type == EFI_HII_VARSTORE_NAME_VALUE) {
    Statement->VariableName = GetToken (Statement->VarStoreInfo.VarName, FormSet->UnicodeBinary);
    ASSERT (Statement->VariableName != NULL);
    //
    // Insert to Name/Value varstore list
    //
    NameValueNode = AllocateZeroPool (sizeof (NAME_VALUE_NODE));
    ASSERT (NameValueNode != NULL);
    NameValueNode->Signature = NAME_VALUE_NODE_SIGNATURE;
    NameValueNode->Name = FceAllocateCopyPool (FceStrSize (Statement->VariableName), Statement->VariableName);
    ASSERT (NameValueNode->Name != NULL);
    NameValueNode->Value = AllocateZeroPool (0x10);
    ASSERT (NameValueNode->Value != NULL);
    NameValueNode->EditValue = AllocateZeroPool (0x10);
    ASSERT (NameValueNode->EditValue != NULL);

    InsertTailList (&Statement->Storage->NameValueListHead, &NameValueNode->Link);
  }

  return Statement;
}


/**
  Allocate a FORM_EXPRESSION node.

  @param  Form                   The Form associated with this Expression

  @return Pointer to a FORM_EXPRESSION data structure.

**/
FORM_EXPRESSION *
CreateExpression (
  IN OUT FORM_BROWSER_FORM        *Form
  )
{
  FORM_EXPRESSION  *Expression;

  Expression = AllocateZeroPool (sizeof (FORM_EXPRESSION));
  ASSERT (Expression != NULL);
  Expression->Signature = FORM_EXPRESSION_SIGNATURE;
  InitializeListHead (&Expression->OpCodeListHead);

  return Expression;
}


/**
  Allocate a FORMSET_STORAGE data structure and insert to FormSet Storage List.

  @param  FormSet                Pointer of the current FormSet

  @return Pointer to a FORMSET_STORAGE data structure.

**/
FORMSET_STORAGE *
CreateStorage (
  IN FORM_BROWSER_FORMSET  *FormSet
  )
{
  FORMSET_STORAGE  *Storage;

  Storage = AllocateZeroPool (sizeof (FORMSET_STORAGE));
  ASSERT (Storage != NULL);
  Storage->Signature = FORMSET_STORAGE_SIGNATURE;
  InitializeListHead (&Storage->NameValueListHead);
  InsertTailList (FormSet->StorageListHead, &Storage->Link);

  return Storage;
}

/**
  Free resources of a Expression.

  @param  FormSet                Pointer of the Expression

**/
VOID
DestroyExpression (
  IN FORM_EXPRESSION   *Expression
  )
{
  LIST_ENTRY         *Link;
  EXPRESSION_OPCODE  *OpCode;
  LIST_ENTRY         *SubExpressionLink;
  FORM_EXPRESSION    *SubExpression;

  while (!IsListEmpty (&Expression->OpCodeListHead)) {
    Link = GetFirstNode (&Expression->OpCodeListHead);
    OpCode = EXPRESSION_OPCODE_FROM_LINK (Link);
    RemoveEntryList (&OpCode->Link);

    if (OpCode->ValueList != NULL) {
      FreePool (OpCode->ValueList);
    }

    if (OpCode->ValueName != NULL) {
      FreePool (OpCode->ValueName);
    }

    if (OpCode->MapExpressionList.ForwardLink != NULL) {
      while (!IsListEmpty (&OpCode->MapExpressionList)) {
        SubExpressionLink = GetFirstNode(&OpCode->MapExpressionList);
        SubExpression     = FORM_EXPRESSION_FROM_LINK (SubExpressionLink);
        RemoveEntryList(&SubExpression->Link);
        DestroyExpression (SubExpression);
      }
    }
  }

  //
  // Free this Expression
  //
  FreePool (Expression);
}


/**
  Free resources of a storage.

  @param  Storage                Pointer of the storage

**/
VOID
DestroyStorage (
  IN FORMSET_STORAGE   *Storage
  )
{
  LIST_ENTRY         *Link;
  NAME_VALUE_NODE    *NameValueNode;

  if (Storage == NULL) {
    return;
  }

  if (Storage->Name != NULL) {
    FreePool (Storage->Name);
  }
  if (Storage->Buffer != NULL) {
    FreePool (Storage->Buffer);
  }

  while (!IsListEmpty (&Storage->NameValueListHead)) {
    Link = GetFirstNode (&Storage->NameValueListHead);
    NameValueNode = NAME_VALUE_NODE_FROM_LINK (Link);
    RemoveEntryList (&NameValueNode->Link);

    if (NameValueNode->Name != NULL) {
      FreePool (NameValueNode->Name);
    }
    if (NameValueNode->Value != NULL) {
      FreePool (NameValueNode->Value);
    }
    if (NameValueNode->EditValue != NULL) {
      FreePool (NameValueNode->EditValue);
    }
    FreePool (NameValueNode);
  }

  FreePool (Storage);
  Storage = NULL;
}

/**
  Free resources allocated for all Storage in an LIST_ENTRY.

  @param  FormSet                Pointer of the FormSet

**/
VOID
DestroyAllStorage (
  IN LIST_ENTRY    *StorageEntryListHead
  ) 
{
  LIST_ENTRY              *Link;
  FORMSET_STORAGE         *Storage;
  //
  // Parse Fromset one by one
  //     
  if (StorageEntryListHead->ForwardLink != NULL) {
    while (!IsListEmpty (StorageEntryListHead)) {
      Link = GetFirstNode (StorageEntryListHead);
      Storage = FORMSET_STORAGE_FROM_LINK (Link);
      RemoveEntryList (&Storage->Link);

      DestroyStorage (Storage);
    }
  }
  StorageEntryListHead = NULL;
}

/**
  Free resources of a Statement.

  @param  FormSet                Pointer of the FormSet
  @param  Statement              Pointer of the Statement

**/
VOID
DestroyStatement (
  IN     FORM_BROWSER_FORMSET    *FormSet,
  IN OUT FORM_BROWSER_STATEMENT  *Statement
  )
{
  LIST_ENTRY        *Link;
  QUESTION_DEFAULT  *Default;
  QUESTION_OPTION   *Option;
  FORM_EXPRESSION   *Expression;

  //
  // Free Default value List
  //
  while (!IsListEmpty (&Statement->DefaultListHead)) {
    Link = GetFirstNode (&Statement->DefaultListHead);
    Default = QUESTION_DEFAULT_FROM_LINK (Link);
    RemoveEntryList (&Default->Link);

    if (Default->Value.Buffer != NULL) {
      FreePool(Default->Value.Buffer);
    }
    FreePool (Default);
  }

  //
  // Free Options List
  //
  while (!IsListEmpty (&Statement->OptionListHead)) {
    Link = GetFirstNode (&Statement->OptionListHead);
    Option = QUESTION_OPTION_FROM_LINK (Link);
    RemoveEntryList (&Option->Link);

    FreePool (Option);
  }

  //
  // Free Inconsistent List
  //
  while (!IsListEmpty (&Statement->InconsistentListHead)) {
    Link = GetFirstNode (&Statement->InconsistentListHead);
    Expression = FORM_EXPRESSION_FROM_LINK (Link);
    RemoveEntryList (&Expression->Link);

    DestroyExpression (Expression);
  }

  //
  // Free NoSubmit List
  //
  while (!IsListEmpty (&Statement->NoSubmitListHead)) {
    Link = GetFirstNode (&Statement->NoSubmitListHead);
    Expression = FORM_EXPRESSION_FROM_LINK (Link);
    RemoveEntryList (&Expression->Link);

    DestroyExpression (Expression);
  }

  //
  // Free WarningIf List
  //
  while (!IsListEmpty (&Statement->WarningListHead)) {
    Link = GetFirstNode (&Statement->WarningListHead);
    Expression = FORM_EXPRESSION_FROM_LINK (Link);
    RemoveEntryList (&Expression->Link);

    DestroyExpression (Expression);
  }
  if (Statement->VariableName != NULL) {
    FreePool (Statement->VariableName);
  }
  if (Statement->BufferValue != NULL) {
    FreePool (Statement->BufferValue);
  }
}

/**
  Free resources of a Form.

  @param  FormSet                Pointer of the FormSet
  @param  Form                   Pointer of the Form.

**/
VOID
DestroyForm (
  IN     FORM_BROWSER_FORMSET  *FormSet,
  IN OUT FORM_BROWSER_FORM     *Form
  )
{
  LIST_ENTRY              *Link;
  FORM_EXPRESSION         *Expression;
  FORM_BROWSER_STATEMENT  *Statement;

  //
  // Free Form Expressions
  //
  while (!IsListEmpty (&Form->ExpressionListHead)) {
    Link = GetFirstNode (&Form->ExpressionListHead);
    Expression = FORM_EXPRESSION_FROM_LINK (Link);
    RemoveEntryList (&Expression->Link);

    DestroyExpression (Expression);
  }

  //
  // Free Statements/Questions
  //
  while (!IsListEmpty (&Form->StatementListHead)) {
    Link = GetFirstNode (&Form->StatementListHead);
    Statement = FORM_BROWSER_STATEMENT_FROM_LINK (Link);
    RemoveEntryList (&Statement->Link);

    DestroyStatement (FormSet, Statement);
  }

  //
  // Free this Form
  //
  FreePool (Form);
}


/**
  Free resources allocated for a FormSet.

  @param  FormSet                Pointer of the FormSet

**/
VOID
DestroyFormSet (
  IN FORM_BROWSER_FORMSET  *FormSet
  )
{
  LIST_ENTRY            *Link;
  FORMSET_DEFAULTSTORE  *DefaultStore;
  FORM_EXPRESSION       *Expression;
  FORM_BROWSER_FORM     *Form;
  UINT16                Index;

  //
  // Free FormSet Default Store
  //
  if (FormSet->DefaultStoreListHead.ForwardLink != NULL) {
    while (!IsListEmpty (&FormSet->DefaultStoreListHead)) {
      Link = GetFirstNode (&FormSet->DefaultStoreListHead);
      DefaultStore = FORMSET_DEFAULTSTORE_FROM_LINK (Link);
      RemoveEntryList (&DefaultStore->Link);

      FreePool (DefaultStore);
    }
  }

  //
  // Free Formset Expressions
  //
  while (!IsListEmpty (&FormSet->ExpressionListHead)) {
    Link = GetFirstNode (&FormSet->ExpressionListHead);
    Expression = FORM_EXPRESSION_FROM_LINK (Link);
    RemoveEntryList (&Expression->Link);

    DestroyExpression (Expression);
  }

  //
  // Free Forms
  //
  if (FormSet->FormListHead.ForwardLink != NULL) {
    while (!IsListEmpty (&FormSet->FormListHead)) {
      Link = GetFirstNode (&FormSet->FormListHead);
      Form = FORM_BROWSER_FORM_FROM_LINK (Link);
      RemoveEntryList (&Form->Link);

      DestroyForm (FormSet, Form);
    }
  }

  if (FormSet->StatementBuffer != NULL) {
    FreePool (FormSet->StatementBuffer);
  }
  if (FormSet->ExpressionBuffer != NULL) {
    FreePool (FormSet->ExpressionBuffer);
  }
  if (FormSet->EnUsStringList.StringInfoList != NULL) {
    for (Index = 0; Index < FormSet->EnUsStringList.CachedIdNum; Index ++) {
      FreePool (FormSet->EnUsStringList.StringInfoList[Index].String);
    }
    FreePool (FormSet->EnUsStringList.StringInfoList);
  }
  if (FormSet->UqiStringList.StringInfoList != NULL) {
    for (Index = 0; Index < FormSet->UqiStringList.CachedIdNum; Index ++) {
      FreePool (FormSet->UqiStringList.StringInfoList[Index].String);
    }
    FreePool (FormSet->UqiStringList.StringInfoList);
  }

  FreePool (FormSet);
}

/**
  Free resources allocated for all FormSet in an LIST_ENTRY.

  @param  FormSet                Pointer of the FormSet

**/
VOID
DestroyAllFormSet (
  IN LIST_ENTRY    *FormSetEntryListHead
  ) 
{
  LIST_ENTRY              *Link;
  FORM_BROWSER_FORMSET    *FormSet;
  //
  // Parse Fromset one by one
  //     
  if (FormSetEntryListHead->ForwardLink != NULL) {
    while (!IsListEmpty (FormSetEntryListHead)) {
      Link = GetFirstNode (FormSetEntryListHead);
      FormSet = FORM_BROWSER_FORMSET_FROM_LINK (Link);
      RemoveEntryList (&FormSet->Link);
      DestroyFormSet (FormSet);
    }
  }
}

/**
  Tell whether this Operand is an Expression OpCode or not

  @param  Operand                Operand of an IFR OpCode.

  @retval TRUE                   This is an Expression OpCode.
  @retval FALSE                  Not an Expression OpCode.

**/
BOOLEAN
IsExpressionOpCode (
  IN UINT8              Operand
  )
{
  if (((Operand >= EFI_IFR_EQ_ID_VAL_OP) && (Operand <= EFI_IFR_NOT_OP)) ||
      ((Operand >= EFI_IFR_MATCH_OP) && (Operand <= EFI_IFR_SET_OP))  ||
      ((Operand >= EFI_IFR_EQUAL_OP) && (Operand <= EFI_IFR_SPAN_OP)) ||
      (Operand == EFI_IFR_CATENATE_OP) ||
      (Operand == EFI_IFR_TO_LOWER_OP) ||
      (Operand == EFI_IFR_TO_UPPER_OP) ||
      (Operand == EFI_IFR_MAP_OP)      ||
      (Operand == EFI_IFR_VERSION_OP)  ||
      (Operand == EFI_IFR_SECURITY_OP)) {
    return TRUE;
  } else {
    return FALSE;
  }
}


/**
  Calculate number of Statemens(Questions) and Expression OpCodes.

  @param  FormSet                The FormSet to be counted.
  @param  NumberOfStatement      Number of Statemens(Questions)
  @param  NumberOfExpression     Number of Expression OpCodes

**/
VOID
CountOpCodes (
  IN  FORM_BROWSER_FORMSET  *FormSet,
  IN OUT  UINT16            *NumberOfStatement,
  IN OUT  UINT16            *NumberOfExpression
  )
{
  UINT16  StatementCount;
  UINT16  ExpressionCount;
  UINT8   *OpCodeData;
  UINTN   Offset;
  UINTN   OpCodeLen;

  Offset = 0;
  StatementCount = 0;
  ExpressionCount = 0;

  while (Offset < FormSet->IfrBinaryLength) {
    OpCodeData = FormSet->IfrBinaryData + Offset;
    OpCodeLen = ((EFI_IFR_OP_HEADER *) OpCodeData)->Length;
    Offset += OpCodeLen;

    if (IsExpressionOpCode (((EFI_IFR_OP_HEADER *) OpCodeData)->OpCode)) {
      ExpressionCount++;
    } else {
      StatementCount++;
    }
  }

  *NumberOfStatement = StatementCount;
  *NumberOfExpression = ExpressionCount;
}



/**
  Parse opcodes in the formset IFR binary.

  @param  FormSet                Pointer of the FormSet data structure.

  @retval EFI_SUCCESS            Opcode parse success.
  @retval Other                  Opcode parse fail.

**/
EFI_STATUS
ParseOpCodes (
  IN FORM_BROWSER_FORMSET              *FormSet
  )
{
  EFI_STATUS              Status;
  UINT16                  Index;
  FORM_BROWSER_FORM       *CurrentForm;
  FORM_BROWSER_STATEMENT  *CurrentStatement;
  EXPRESSION_OPCODE       *ExpressionOpCode;
  FORM_EXPRESSION         *CurrentExpression;
  UINT8                   Operand;
  UINT8                   Scope;
  UINTN                   OpCodeOffset;
  UINTN                   OpCodeLength;
  UINT8                   *OpCodeData;
  UINT8                   ScopeOpCode;
  FORMSET_STORAGE         *Storage;
  FORMSET_STORAGE         *TempStorage;
  FORMSET_DEFAULTSTORE    *DefaultStore;
  QUESTION_DEFAULT        *CurrentDefault;
  QUESTION_OPTION         *CurrentOption;
  UINT8                   Width;
  CHAR8                   *AsciiString;
  UINT16                  NumberOfStatement;
  UINT16                  NumberOfExpression;
  BOOLEAN                 SuppressForQuestion;
  BOOLEAN                 SuppressForOption;
  BOOLEAN                 InScopeOptionSuppress;
  FORM_EXPRESSION         *OptionSuppressExpression;
  BOOLEAN                 InScopeFormSuppress;
  FORM_EXPRESSION         *FormSuppressExpression;
  UINT16                  DepthOfDisable;
  BOOLEAN                 OpCodeDisabled;
  BOOLEAN                 SingleOpCodeExpression;
  BOOLEAN                 InScopeDefault;
  EFI_HII_VALUE           *Value;
  UINT8                   MapScopeDepth;
  LIST_ENTRY              *Link;
  FORMSET_STORAGE         *VarStorage;
  LIST_ENTRY              *MapExpressionList;
  EFI_VARSTORE_ID         TempVarstoreId;
  BOOLEAN                 ConstantFlag;
  FORMSET_DEFAULTSTORE    *PreDefaultStore;
  LIST_ENTRY              *DefaultLink;
  BOOLEAN                 HaveInserted;
  BOOLEAN                 BitFieldStorage;
  UINT16                  TotalBits;

  mInScopeSubtitle         = FALSE;
  SuppressForQuestion      = FALSE;
  SuppressForOption        = FALSE;
  InScopeFormSuppress      = FALSE;
  mInScopeSuppress         = FALSE;
  InScopeOptionSuppress    = FALSE;
  mInScopeGrayOut          = FALSE;
  mInScopeDisable          = FALSE;
  DepthOfDisable           = 0;
  OpCodeDisabled           = FALSE;
  SingleOpCodeExpression   = FALSE;
  InScopeDefault           = FALSE;
  CurrentExpression        = NULL;
  CurrentDefault           = NULL;
  CurrentOption            = NULL;
  OptionSuppressExpression = NULL;
  FormSuppressExpression   = NULL;
  MapScopeDepth            = 0;
  Link                     = NULL;
  VarStorage               = NULL;
  MapExpressionList        = NULL;
  TempVarstoreId           = 0;
  ConstantFlag             = TRUE;
  BitFieldStorage          = FALSE;

  //
  // Get the number of Statements and Expressions
  //
  CountOpCodes (FormSet, &NumberOfStatement, &NumberOfExpression);

  mStatementIndex = 0;
  FormSet->StatementBuffer = AllocateZeroPool (NumberOfStatement * sizeof (FORM_BROWSER_STATEMENT));
  if (FormSet->StatementBuffer == NULL) {
    return EFI_OUT_OF_RESOURCES;
  }

  mExpressionOpCodeIndex = 0;
  FormSet->ExpressionBuffer = AllocateZeroPool (NumberOfExpression * sizeof (EXPRESSION_OPCODE));
  if (FormSet->ExpressionBuffer == NULL) {
    return EFI_OUT_OF_RESOURCES;
  }

  FormSet->StorageListHead = &mVarListEntry;
  InitializeListHead (&FormSet->DefaultStoreListHead);
  InitializeListHead (&FormSet->FormListHead);
  InitializeListHead (&FormSet->ExpressionListHead);
  ResetCurrentExpressionStack ();
  ResetMapExpressionListStack ();

  CurrentForm = NULL;
  CurrentStatement = NULL;

  ResetScopeStack ();

  OpCodeOffset = 0;
  while (OpCodeOffset < FormSet->IfrBinaryLength) {
    OpCodeData = FormSet->IfrBinaryData + OpCodeOffset;

    OpCodeLength = ((EFI_IFR_OP_HEADER *) OpCodeData)->Length;
    OpCodeOffset += OpCodeLength;
    Operand = ((EFI_IFR_OP_HEADER *) OpCodeData)->OpCode;
    Scope = ((EFI_IFR_OP_HEADER *) OpCodeData)->Scope;

    //
    // If scope bit set, push onto scope stack
    //
    if (Scope != 0) {
      PushScope (Operand);
    }

    if (OpCodeDisabled) {
      //
      // DisableIf Expression is evaluated to be TRUE, try to find its end.
      // Here only cares the EFI_IFR_DISABLE_IF and EFI_IFR_END
      //
      if (Operand == EFI_IFR_DISABLE_IF_OP) {
        DepthOfDisable++;
      } else if (Operand == EFI_IFR_END_OP) {
        Status = PopScope (&ScopeOpCode);
        if (EFI_ERROR (Status)) {
          return Status;
        }

        if (ScopeOpCode == EFI_IFR_DISABLE_IF_OP) {
          if (DepthOfDisable == 0) {
            mInScopeDisable = FALSE;
            OpCodeDisabled = FALSE;
          } else {
            DepthOfDisable--;
          }
        }
      }
      continue;
    }

    if (IsExpressionOpCode (Operand)) {
      ExpressionOpCode = &FormSet->ExpressionBuffer[mExpressionOpCodeIndex];
      mExpressionOpCodeIndex++;

      ExpressionOpCode->Signature = EXPRESSION_OPCODE_SIGNATURE;
      ExpressionOpCode->Operand = Operand;
      Value = &ExpressionOpCode->Value;

      switch (Operand) {
      case EFI_IFR_EQ_ID_VAL_OP:
        CopyMem (&ExpressionOpCode->QuestionId, &((EFI_IFR_EQ_ID_VAL *) OpCodeData)->QuestionId, sizeof (EFI_QUESTION_ID));

        Value->Type = EFI_IFR_TYPE_NUM_SIZE_16;
        CopyMem (&Value->Value.u16, &((EFI_IFR_EQ_ID_VAL *) OpCodeData)->Value, sizeof (UINT16));
        break;

      case EFI_IFR_EQ_ID_ID_OP:
        CopyMem (&ExpressionOpCode->QuestionId, &((EFI_IFR_EQ_ID_ID *) OpCodeData)->QuestionId1, sizeof (EFI_QUESTION_ID));
        CopyMem (&ExpressionOpCode->QuestionId2, &((EFI_IFR_EQ_ID_ID *) OpCodeData)->QuestionId2, sizeof (EFI_QUESTION_ID));
        break;

      case EFI_IFR_EQ_ID_VAL_LIST_OP:
        CopyMem (&ExpressionOpCode->QuestionId, &((EFI_IFR_EQ_ID_VAL_LIST *) OpCodeData)->QuestionId, sizeof (EFI_QUESTION_ID));
        CopyMem (&ExpressionOpCode->ListLength, &((EFI_IFR_EQ_ID_VAL_LIST *) OpCodeData)->ListLength, sizeof (UINT16));
        ExpressionOpCode->ValueList = FceAllocateCopyPool (ExpressionOpCode->ListLength * sizeof (UINT16), &((EFI_IFR_EQ_ID_VAL_LIST *) OpCodeData)->ValueList);
        break;

      case EFI_IFR_TO_STRING_OP:
      case EFI_IFR_FIND_OP:
        ExpressionOpCode->Format = (( EFI_IFR_TO_STRING *) OpCodeData)->Format;
        break;

      case EFI_IFR_STRING_REF1_OP:
        Value->Type = EFI_IFR_TYPE_STRING;
        CopyMem (&Value->Value.string, &(( EFI_IFR_STRING_REF1 *) OpCodeData)->StringId, sizeof (EFI_STRING_ID));
        break;

      case EFI_IFR_RULE_REF_OP:
        ExpressionOpCode->RuleId = (( EFI_IFR_RULE_REF *) OpCodeData)->RuleId;
        break;

      case EFI_IFR_SPAN_OP:
        ExpressionOpCode->Flags = (( EFI_IFR_SPAN *) OpCodeData)->Flags;
        break;

      case EFI_IFR_THIS_OP:
        ASSERT (CurrentStatement != NULL);
        ExpressionOpCode->QuestionId = CurrentStatement->QuestionId;
        break;

      case EFI_IFR_SECURITY_OP:
        CopyMem (&ExpressionOpCode->Guid, &((EFI_IFR_SECURITY *) OpCodeData)->Permissions, sizeof (EFI_GUID));
        break;

      case EFI_IFR_GET_OP:
      case EFI_IFR_SET_OP:
        CopyMem (&TempVarstoreId, &((EFI_IFR_GET *) OpCodeData)->VarStoreId, sizeof (TempVarstoreId));
        if (TempVarstoreId != 0) {
          if (FormSet->StorageListHead->ForwardLink != NULL) {
            Link = GetFirstNode (FormSet->StorageListHead);
            while (!IsNull (FormSet->StorageListHead, Link)) {
              VarStorage = FORMSET_STORAGE_FROM_LINK (Link);
              if (VarStorage->VarStoreId == ((EFI_IFR_GET *) OpCodeData)->VarStoreId) {
                ExpressionOpCode->VarStorage = VarStorage;
                break;
              }
              Link = GetNextNode (FormSet->StorageListHead, Link);
            }
          }
          if (ExpressionOpCode->VarStorage == NULL) {
            //
            // VarStorage is not found.
            //
            return EFI_INVALID_PARAMETER;
          }
        }
        ExpressionOpCode->ValueType = ((EFI_IFR_GET *) OpCodeData)->VarStoreType;
        switch (ExpressionOpCode->ValueType) {
        case EFI_IFR_TYPE_BOOLEAN:
        case EFI_IFR_TYPE_NUM_SIZE_8: 
          ExpressionOpCode->ValueWidth = 1;
          break;

        case EFI_IFR_TYPE_NUM_SIZE_16:
        case EFI_IFR_TYPE_STRING:
          ExpressionOpCode->ValueWidth = 2;
          break;

        case EFI_IFR_TYPE_NUM_SIZE_32:
          ExpressionOpCode->ValueWidth = 4;
          break;

        case EFI_IFR_TYPE_NUM_SIZE_64:
          ExpressionOpCode->ValueWidth = 8;
          break;

        case EFI_IFR_TYPE_DATE:
          ExpressionOpCode->ValueWidth = (UINT8) sizeof (EFI_IFR_DATE);
          break;

        case EFI_IFR_TYPE_TIME:
          ExpressionOpCode->ValueWidth = (UINT8) sizeof (EFI_IFR_TIME);
          break;

        case EFI_IFR_TYPE_REF:
          ExpressionOpCode->ValueWidth = (UINT8) sizeof (EFI_IFR_REF);
          break;

        case EFI_IFR_TYPE_OTHER:
        case EFI_IFR_TYPE_UNDEFINED:
        case EFI_IFR_TYPE_ACTION:
        case EFI_IFR_TYPE_BUFFER:
        default:
          //
          // Invalid value type for Get/Set opcode.
          //
          return EFI_INVALID_PARAMETER;
        }
        CopyMem (&ExpressionOpCode->VarStoreInfo.VarName,   &((EFI_IFR_GET *) OpCodeData)->VarStoreInfo.VarName,   sizeof (EFI_STRING_ID));
        CopyMem (&ExpressionOpCode->VarStoreInfo.VarOffset, &((EFI_IFR_GET *) OpCodeData)->VarStoreInfo.VarOffset, sizeof (UINT16));
        if ((ExpressionOpCode->VarStorage != NULL) && 
            ((ExpressionOpCode->VarStorage->Type == EFI_HII_VARSTORE_NAME_VALUE)
            || ((ExpressionOpCode->VarStorage->Type == EFI_IFR_VARSTORE_EFI_OP) && !ExpressionOpCode->VarStorage->NewEfiVarstore))
             ) {
          ExpressionOpCode->ValueName = GetToken (ExpressionOpCode->VarStoreInfo.VarName, FormSet->UnicodeBinary);
          if (ExpressionOpCode->ValueName == NULL) {
            //
            // String ID is invalid.
            //
            return EFI_INVALID_PARAMETER;
          }
        }
        break;

      case EFI_IFR_QUESTION_REF1_OP:
        CopyMem (&ExpressionOpCode->QuestionId, &((EFI_IFR_EQ_ID_VAL_LIST *) OpCodeData)->QuestionId, sizeof (EFI_QUESTION_ID));
        break;

      case EFI_IFR_QUESTION_REF3_OP:
        if (OpCodeLength >= sizeof (EFI_IFR_QUESTION_REF3_2)) {
          CopyMem (&ExpressionOpCode->DevicePath, &(( EFI_IFR_QUESTION_REF3_2 *) OpCodeData)->DevicePath, sizeof (EFI_STRING_ID));

          if (OpCodeLength >= sizeof (EFI_IFR_QUESTION_REF3_3)) {
            CopyMem (&ExpressionOpCode->Guid, &(( EFI_IFR_QUESTION_REF3_3 *) OpCodeData)->Guid, sizeof (EFI_GUID));
          }
        }
        break;

      //
      // constant
      //
      case EFI_IFR_TRUE_OP:
        Value->Type = EFI_IFR_TYPE_BOOLEAN;
        Value->Value.b = TRUE;
        break;

      case EFI_IFR_FALSE_OP:
        Value->Type = EFI_IFR_TYPE_BOOLEAN;
        Value->Value.b = FALSE;
        break;

      case EFI_IFR_ONE_OP:
        Value->Type = EFI_IFR_TYPE_NUM_SIZE_8;
        Value->Value.u8 = 1;
        break;

      case EFI_IFR_ZERO_OP:
        Value->Type = EFI_IFR_TYPE_NUM_SIZE_8;
        Value->Value.u8 = 0;
        break;

      case EFI_IFR_ONES_OP:
        Value->Type = EFI_IFR_TYPE_NUM_SIZE_64;
        Value->Value.u64 = 0xffffffffffffffffULL;
        break;

      case EFI_IFR_UINT8_OP:
        Value->Type = EFI_IFR_TYPE_NUM_SIZE_8;
        Value->Value.u8 = (( EFI_IFR_UINT8 *) OpCodeData)->Value;
        break;

      case EFI_IFR_UINT16_OP:
        Value->Type = EFI_IFR_TYPE_NUM_SIZE_16;
        CopyMem (&Value->Value.u16, &(( EFI_IFR_UINT16 *) OpCodeData)->Value, sizeof (UINT16));
        break;

      case EFI_IFR_UINT32_OP:
        Value->Type = EFI_IFR_TYPE_NUM_SIZE_32;
        CopyMem (&Value->Value.u32, &(( EFI_IFR_UINT32 *) OpCodeData)->Value, sizeof (UINT32));
        break;

      case EFI_IFR_UINT64_OP:
        Value->Type = EFI_IFR_TYPE_NUM_SIZE_64;
        CopyMem (&Value->Value.u64, &(( EFI_IFR_UINT64 *) OpCodeData)->Value, sizeof (UINT64));
        break;

      case EFI_IFR_UNDEFINED_OP:
        Value->Type = EFI_IFR_TYPE_UNDEFINED;
        break;

      case EFI_IFR_VERSION_OP:
        Value->Type = EFI_IFR_TYPE_NUM_SIZE_16;
        break;

      default:
        break;
      }
      //
      // Create sub expression nested in MAP opcode
      //
      if ((CurrentExpression == NULL) && (MapScopeDepth > 0)) {
        CurrentExpression = CreateExpression (CurrentForm);
        ASSERT (MapExpressionList != NULL);
        InsertTailList (MapExpressionList, &CurrentExpression->Link);
        if (Scope == 0) {
          SingleOpCodeExpression = TRUE;
        }
      }
      ASSERT (CurrentExpression != NULL);
      InsertTailList (&CurrentExpression->OpCodeListHead, &ExpressionOpCode->Link);
      if (Operand == EFI_IFR_MAP_OP) {
        //
        // Store current Map Expression List.
        //
        if (MapExpressionList != NULL) {
          PushMapExpressionList (MapExpressionList);
        }
        //
        // Initialize new Map Expression List.
        //
        MapExpressionList = &ExpressionOpCode->MapExpressionList;
        InitializeListHead (MapExpressionList);
        //
        // Store current expression.
        //
        PushCurrentExpression (CurrentExpression);
        CurrentExpression = NULL;
        MapScopeDepth ++;
      } else if (SingleOpCodeExpression) {
        //
        // There are two cases to indicate the end of an Expression:
        // for single OpCode expression: one Expression OpCode
        // for expression consists of more than one OpCode: EFI_IFR_END
        //
        SingleOpCodeExpression = FALSE;

        if (mInScopeDisable && (CurrentForm == NULL)) {
          //
          // This is DisableIf expression for Form, it should be a constant expression
          //
          ConstantFlag = TRUE;
          Status = EvaluateExpression (FormSet, CurrentForm, CurrentExpression, &ConstantFlag);
          if (EFI_ERROR (Status)) {
            return Status;
          }

          if (CurrentExpression->Result.Type != EFI_IFR_TYPE_BOOLEAN) {
            return EFI_INVALID_PARAMETER;
          }
          if (!ConstantFlag) {
            StringPrint ("WARNING. The DisableIf expression for Form should be a constant expression.\n");
          }
          OpCodeDisabled = CurrentExpression->Result.Value.b;
        }

        CurrentExpression = NULL;
      }

      continue;
    }

    //
    // Parse the Opcode
    //
    switch (Operand) {

    case EFI_IFR_FORM_SET_OP:

      CopyMem (&FormSet->FormSetTitle, &((EFI_IFR_FORM_SET *) OpCodeData)->FormSetTitle, sizeof (EFI_STRING_ID));
      CopyMem (&FormSet->Help,         &((EFI_IFR_FORM_SET *) OpCodeData)->Help,         sizeof (EFI_STRING_ID));
      CopyMem (&FormSet->Guid,         &((EFI_IFR_FORM_SET *) OpCodeData)->Guid,         sizeof (EFI_GUID));

      if (OpCodeLength > OFFSET_OF (EFI_IFR_FORM_SET, Flags)) {
        //
        // The formset OpCode contains ClassGuid
        //
        FormSet->NumberOfClassGuid = (UINT8) (((EFI_IFR_FORM_SET *) OpCodeData)->Flags & 0x3);
        CopyMem (FormSet->ClassGuid, OpCodeData + sizeof (EFI_IFR_FORM_SET), FormSet->NumberOfClassGuid * sizeof (EFI_GUID));
      }
      FormSet->FormSetOrder = ++mFormSetOrderParse;
      break;

    case EFI_IFR_FORM_OP:
    case EFI_IFR_FORM_MAP_OP:
      //
      // Create a new Form for this FormSet
      //
      CurrentForm = AllocateZeroPool (sizeof (FORM_BROWSER_FORM));
      ASSERT (CurrentForm != NULL);
      CurrentForm->Signature = FORM_BROWSER_FORM_SIGNATURE;
      InitializeListHead (&CurrentForm->ExpressionListHead);
      InitializeListHead (&CurrentForm->StatementListHead);

      CurrentForm->FormType = STANDARD_MAP_FORM_TYPE;
      CopyMem (&CurrentForm->FormId,    &((EFI_IFR_FORM *) OpCodeData)->FormId,    sizeof (UINT16));
      CopyMem (&CurrentForm->FormTitle, &((EFI_IFR_FORM *) OpCodeData)->FormTitle, sizeof (EFI_STRING_ID));

      if (InScopeFormSuppress) {
        //
        // Form is inside of suppressif
        //
        CurrentForm->SuppressExpression = FormSuppressExpression;
      }

      if (Scope != 0) {
        //
        // Enter scope of a Form, suppressif will be used for Question or Option
        //
        SuppressForQuestion = TRUE;
      }

      //
      // Insert into Form list of this FormSet
      //
      InsertTailList (&FormSet->FormListHead, &CurrentForm->Link);
      break;
    //
    // Storage
    //
    case EFI_IFR_VARSTORE_OP:
      //
      // Create a buffer Storage for this FormSet
      //
      
      Storage = CreateStorage (FormSet);
      Storage->Type = EFI_IFR_VARSTORE_OP;

      CopyMem (&Storage->VarStoreId, &((EFI_IFR_VARSTORE *) OpCodeData)->VarStoreId, sizeof (EFI_VARSTORE_ID));
      CopyMem (&Storage->Guid,       &((EFI_IFR_VARSTORE *) OpCodeData)->Guid,       sizeof (EFI_GUID));
      CopyMem (&Storage->Size,       &((EFI_IFR_VARSTORE *) OpCodeData)->Size,       sizeof (UINT16));

      Storage->Buffer = AllocateZeroPool (Storage->Size);

      AsciiString = (CHAR8 *) ((EFI_IFR_VARSTORE *) OpCodeData)->Name;
      Storage->Name = AllocateZeroPool ((strlen (AsciiString) + 1) * 2);
      ASSERT (Storage->Name != NULL);
      for (Index = 0; AsciiString[Index] != 0; Index++) {
        Storage->Name[Index] = (CHAR16) AsciiString[Index];
      }
      Storage->FormSetOrder = mFormSetOrderParse;
      
      //
      // If not existed the same variable in StorageList, insert the new one. Or else, use the old one.
      // If these two variales have the same Guid name but different size, report an error.
      //
      if ((TempStorage = NotSameVariableInVarList (FormSet->StorageListHead, Storage)) != NULL) {
        if (Storage->Size != TempStorage->Size) {
           StringPrint ("Error. Two modules found with VarStore variables with same name %S and GUID %08x-%04x-%04x-%02x%02x-%02x%02x%02x%02x%02x%02x, but with different sizes %d and %d.\n",
           Storage->Name,
           Storage->Guid.Data1,
           Storage->Guid.Data2,
           Storage->Guid.Data3,
           Storage->Guid.Data4[0],
           Storage->Guid.Data4[1],
           Storage->Guid.Data4[2],
           Storage->Guid.Data4[3],
           Storage->Guid.Data4[4],
           Storage->Guid.Data4[5],
           Storage->Guid.Data4[6],
           Storage->Guid.Data4[7],
           Storage->Size,
           TempStorage->Size
           );
          return EFI_ABORTED;
        }
        //
        // Update the VarStoreId for current question to get the variable guid and name information
        //
        TempStorage->VarStoreId   = Storage->VarStoreId;
        TempStorage->FormSetOrder = Storage->FormSetOrder;
        RemoveEntryList (&Storage->Link);
        DestroyStorage(Storage);
      }
      break;

    case EFI_IFR_VARSTORE_NAME_VALUE_OP:
      //
      // Create a name/value Storage for this FormSet
      //
      Storage = CreateStorage (FormSet);
      Storage->Type = EFI_HII_VARSTORE_NAME_VALUE;

      CopyMem (&Storage->VarStoreId, &((EFI_IFR_VARSTORE_NAME_VALUE *) OpCodeData)->VarStoreId, sizeof (EFI_VARSTORE_ID));
      CopyMem (&Storage->Guid,       &((EFI_IFR_VARSTORE_NAME_VALUE *) OpCodeData)->Guid,       sizeof (EFI_GUID));

      Storage->FormSetOrder = mFormSetOrderParse;
      break;

    case EFI_IFR_VARSTORE_EFI_OP:
      //
      // Create a EFI variable Storage for this FormSet
      //
      Storage = CreateStorage (FormSet);
      Storage->Type = EFI_IFR_VARSTORE_EFI_OP;
      CopyMem (&Storage->VarStoreId, &((EFI_IFR_VARSTORE_EFI *) OpCodeData)->VarStoreId, sizeof (EFI_VARSTORE_ID));
      CopyMem (&Storage->Guid,       &((EFI_IFR_VARSTORE_EFI *) OpCodeData)->Guid,       sizeof (EFI_GUID));
      CopyMem (&Storage->Attributes, &((EFI_IFR_VARSTORE_EFI *) OpCodeData)->Attributes, sizeof (UINT32));
      //
      // Check whether the EfiVarStore before UEFI2.31 or not
      //  
      Storage->Size             = sizeof (EFI_IFR_VARSTORE_EFI_OLD);
      if (((EFI_IFR_VARSTORE_EFI *) OpCodeData)->Header.Length == sizeof (EFI_IFR_VARSTORE_EFI_OLD)) {
        Storage->NewEfiVarstore   = FALSE;
        Storage->Size             = 0;
        Storage->Buffer           = NULL;
        Storage->Name             = NULL;
        Storage->Size             = 0;
      } else {
        //
        // EfiVarStore structure for UEFI2.31
        //
        Storage->NewEfiVarstore   = TRUE;
        CopyMem (&Storage->Size, &((EFI_IFR_VARSTORE_EFI *) OpCodeData)->Size, sizeof (UINT16));

        Storage->Buffer = AllocateZeroPool (Storage->Size);
        AsciiString = (CHAR8 *) ((EFI_IFR_VARSTORE_EFI *) OpCodeData)->Name;
        Storage->Name = AllocateZeroPool ((strlen (AsciiString) + 1) * 2);
        ASSERT (Storage->Name != NULL);
        for (Index = 0; AsciiString[Index] != 0; Index++) {
          Storage->Name[Index] = (CHAR16) AsciiString[Index];
        }
      }
      Storage->FormSetOrder = mFormSetOrderParse;
      //
      // If not existed the same variable in StorageList, insert the new one. Or else, use the old one.
      // If these two variales have the same Guid name but different size, report an error.
      //
      if ((TempStorage = NotSameVariableInVarList (FormSet->StorageListHead, Storage)) != NULL) {
        if (Storage->Size != TempStorage->Size) {
          StringPrint ("Error. Two modules found with EfiVarStore variables with same name %S and GUID %08x-%04x-%04x-%02x%02x-%02x%02x%02x%02x%02x%02x, but different sizes %d and %d.\n", 
          Storage->Name,
          Storage->Guid.Data1,
          Storage->Guid.Data2,
          Storage->Guid.Data3,
          Storage->Guid.Data4[0],
          Storage->Guid.Data4[1],
          Storage->Guid.Data4[2],
          Storage->Guid.Data4[3],
          Storage->Guid.Data4[4],
          Storage->Guid.Data4[5],
          Storage->Guid.Data4[6],
          Storage->Guid.Data4[7],
          Storage->Size,
          TempStorage->Size
          );
          return EFI_ABORTED;
        }
        //
        // Update the VarStoreId for current question to get the variable guid and name information
        //
        TempStorage->VarStoreId   = Storage->VarStoreId;
        TempStorage->FormSetOrder = Storage->FormSetOrder;
        RemoveEntryList (&Storage->Link);
        DestroyStorage( Storage);
      }
      break;

    //
    // DefaultStore
    //
    case EFI_IFR_DEFAULTSTORE_OP:
      HaveInserted = FALSE;
      DefaultStore = AllocateZeroPool (sizeof (FORMSET_DEFAULTSTORE));
      ASSERT (DefaultStore != NULL);
      DefaultStore->Signature = FORMSET_DEFAULTSTORE_SIGNATURE;

      CopyMem (&DefaultStore->DefaultId,   &((EFI_IFR_DEFAULTSTORE *) OpCodeData)->DefaultId,   sizeof (UINT16));
      CopyMem (&DefaultStore->DefaultName, &((EFI_IFR_DEFAULTSTORE *) OpCodeData)->DefaultName, sizeof (EFI_STRING_ID));

      //
      // Insert it to the DefaultStore list of this Formset with ascending order.
      //
      if (!IsListEmpty (&FormSet->DefaultStoreListHead)) {
        DefaultLink = GetFirstNode (&FormSet->DefaultStoreListHead);
        while (!IsNull (&FormSet->DefaultStoreListHead, DefaultLink)) {
          PreDefaultStore = FORMSET_DEFAULTSTORE_FROM_LINK(DefaultLink);
          DefaultLink = GetNextNode (&FormSet->DefaultStoreListHead, DefaultLink);
          if (DefaultStore->DefaultId < PreDefaultStore->DefaultId) {
            InsertTailList (&PreDefaultStore->Link, &DefaultStore->Link);
            HaveInserted = TRUE;
            break;
          }
        }
      }
      if (!HaveInserted) {
        InsertTailList (&FormSet->DefaultStoreListHead, &DefaultStore->Link);
      }
      break;

    //
    // Statements
    //
    case EFI_IFR_SUBTITLE_OP:
      CurrentStatement = CreateStatement (OpCodeData, FormSet, CurrentForm);
      ASSERT (CurrentStatement != NULL);

      CurrentStatement->Flags = ((EFI_IFR_SUBTITLE *) OpCodeData)->Flags;

      if (Scope != 0) {
        mInScopeSubtitle = TRUE;
      }
      break;

    case EFI_IFR_TEXT_OP:
      CurrentStatement = CreateStatement (OpCodeData, FormSet, CurrentForm);
      ASSERT (CurrentStatement != NULL);

      CopyMem (&CurrentStatement->TextTwo, &((EFI_IFR_TEXT *) OpCodeData)->TextTwo, sizeof (EFI_STRING_ID));
      break;

    case EFI_IFR_RESET_BUTTON_OP:
      CurrentStatement = CreateStatement (OpCodeData, FormSet, CurrentForm);
      ASSERT (CurrentStatement != NULL);
      CopyMem (&CurrentStatement->DefaultId, &((EFI_IFR_RESET_BUTTON *) OpCodeData)->DefaultId, sizeof (EFI_DEFAULT_ID));
      break;

    //
    // Questions
    //
    case EFI_IFR_ACTION_OP:
      CurrentStatement = CreateQuestion (OpCodeData, FormSet, CurrentForm);
      ASSERT (CurrentStatement != NULL);
      CurrentStatement->HiiValue.Type = EFI_IFR_TYPE_ACTION;
      //
      // No need to deal with the EFI_IFR_ACTION
      //
      break;

    case EFI_IFR_REF_OP:
      CurrentStatement = CreateQuestion (OpCodeData, FormSet, CurrentForm);
      ASSERT (CurrentStatement != NULL);
      Value = &CurrentStatement->HiiValue;
      Value->Type = EFI_IFR_TYPE_REF;
      if (OpCodeLength >= sizeof (EFI_IFR_REF)) {
        CopyMem (&Value->Value.ref.FormId, &((EFI_IFR_REF *) OpCodeData)->FormId, sizeof (EFI_FORM_ID));

        if (OpCodeLength >= sizeof (EFI_IFR_REF2)) {
          CopyMem (&Value->Value.ref.QuestionId, &((EFI_IFR_REF2 *) OpCodeData)->QuestionId, sizeof (EFI_QUESTION_ID));

          if (OpCodeLength >= sizeof (EFI_IFR_REF3)) {
            CopyMem (&Value->Value.ref.FormSetGuid, &((EFI_IFR_REF3 *) OpCodeData)->FormSetId, sizeof (EFI_GUID));

            if (OpCodeLength >= sizeof (EFI_IFR_REF4)) {
              CopyMem (&Value->Value.ref.DevicePath, &((EFI_IFR_REF4 *) OpCodeData)->DevicePath, sizeof (EFI_STRING_ID));
            }
          }
        }
      }
      CurrentStatement->StorageWidth = (UINT16) sizeof (EFI_HII_REF);        
      break;

    case EFI_IFR_ONE_OF_OP:
    case EFI_IFR_NUMERIC_OP:
      CurrentStatement = CreateQuestion (OpCodeData, FormSet, CurrentForm);
      ASSERT(CurrentStatement != NULL);

      CurrentStatement->Flags = ((EFI_IFR_ONE_OF *) OpCodeData)->Flags;
      Value = &CurrentStatement->HiiValue;

      if (BitFieldStorage) {
        //
        // Get the bit var store info (bit/byte offset, bit/byte offset)
        //
        CurrentStatement->QuestionReferToBitField = TRUE;
        CurrentStatement->BitStorageWidth = CurrentStatement->Flags & EDKII_IFR_NUMERIC_SIZE_BIT;
        CurrentStatement->BitVarOffset = CurrentStatement->VarStoreInfo.VarOffset;
        CurrentStatement->VarStoreInfo.VarOffset = CurrentStatement->BitVarOffset / 8;
        TotalBits = CurrentStatement->BitVarOffset % 8 + CurrentStatement->BitStorageWidth;
        CurrentStatement->StorageWidth = (TotalBits % 8 == 0? TotalBits / 8: TotalBits / 8 + 1);
        //
        // Get the Minimum/Maximum/Step value(Note: bit field type has been stored as UINT32 type)
        //
        CurrentStatement->Minimum = ((EFI_IFR_NUMERIC *) OpCodeData)->data.u32.MinValue;
        CurrentStatement->Maximum = ((EFI_IFR_NUMERIC *) OpCodeData)->data.u32.MaxValue;
        CurrentStatement->Step    = ((EFI_IFR_NUMERIC *) OpCodeData)->data.u32.Step;
      } else {
        switch (CurrentStatement->Flags & EFI_IFR_NUMERIC_SIZE) {
        case EFI_IFR_NUMERIC_SIZE_1:
          CurrentStatement->Minimum = ((EFI_IFR_NUMERIC *) OpCodeData)->data.u8.MinValue;
          CurrentStatement->Maximum = ((EFI_IFR_NUMERIC *) OpCodeData)->data.u8.MaxValue;
          CurrentStatement->Step    = ((EFI_IFR_NUMERIC *) OpCodeData)->data.u8.Step;
          CurrentStatement->StorageWidth = (UINT16) sizeof (UINT8);
          Value->Type = EFI_IFR_TYPE_NUM_SIZE_8;
          break;

        case EFI_IFR_NUMERIC_SIZE_2:
          CopyMem (&CurrentStatement->Minimum, &((EFI_IFR_NUMERIC *) OpCodeData)->data.u16.MinValue, sizeof (UINT16));
          CopyMem (&CurrentStatement->Maximum, &((EFI_IFR_NUMERIC *) OpCodeData)->data.u16.MaxValue, sizeof (UINT16));
          CopyMem (&CurrentStatement->Step,    &((EFI_IFR_NUMERIC *) OpCodeData)->data.u16.Step,     sizeof (UINT16));
          CurrentStatement->StorageWidth = (UINT16) sizeof (UINT16);
          Value->Type = EFI_IFR_TYPE_NUM_SIZE_16;
          break;

        case EFI_IFR_NUMERIC_SIZE_4:
          CopyMem (&CurrentStatement->Minimum, &((EFI_IFR_NUMERIC *) OpCodeData)->data.u32.MinValue, sizeof (UINT32));
          CopyMem (&CurrentStatement->Maximum, &((EFI_IFR_NUMERIC *) OpCodeData)->data.u32.MaxValue, sizeof (UINT32));
          CopyMem (&CurrentStatement->Step,    &((EFI_IFR_NUMERIC *) OpCodeData)->data.u32.Step,     sizeof (UINT32));
          CurrentStatement->StorageWidth = (UINT16) sizeof (UINT32);
          Value->Type = EFI_IFR_TYPE_NUM_SIZE_32;
          break;

        case EFI_IFR_NUMERIC_SIZE_8:
          CopyMem (&CurrentStatement->Minimum, &((EFI_IFR_NUMERIC *) OpCodeData)->data.u64.MinValue, sizeof (UINT64));
          CopyMem (&CurrentStatement->Maximum, &((EFI_IFR_NUMERIC *) OpCodeData)->data.u64.MaxValue, sizeof (UINT64));
          CopyMem (&CurrentStatement->Step,    &((EFI_IFR_NUMERIC *) OpCodeData)->data.u64.Step,     sizeof (UINT64));
          CurrentStatement->StorageWidth = (UINT16) sizeof (UINT64);
          Value->Type = EFI_IFR_TYPE_NUM_SIZE_64;
          break;

        default:
          break;
        }
      }
      if ((Operand == EFI_IFR_ONE_OF_OP) && (Scope != 0)) {
        SuppressForOption = TRUE;
      }
      //
      // Get the UQI information
      //
      PrintQuestion(FormSet, CurrentForm, CurrentStatement, FALSE);
      //
      // Exchange the Guid and name information between VarList and Question List
      //
      Status = GetGuidNameByVariableId (FormSet, CurrentStatement, FormSet->StorageListHead);
      //
      // Remove the question which isn't stored by EfiVarStore or VarStore 
      //
      if (EFI_ERROR (Status)) {
        RemoveEntryList (&CurrentStatement->Link);
        DestroyStatement (FormSet, CurrentStatement);
      }
      break;

    case EFI_IFR_ORDERED_LIST_OP:
      CurrentStatement = CreateQuestion (OpCodeData, FormSet, CurrentForm);
      ASSERT(CurrentStatement != NULL);

      CurrentStatement->Flags = ((EFI_IFR_ORDERED_LIST *) OpCodeData)->Flags;
      CurrentStatement->MaxContainers = ((EFI_IFR_ORDERED_LIST *) OpCodeData)->MaxContainers;

      CurrentStatement->HiiValue.Type = EFI_IFR_TYPE_BUFFER;
      CurrentStatement->BufferValue   = NULL;
      if (Scope != 0) {
        SuppressForOption = TRUE;
      }
      //
      // Get the UQI information
      //
      PrintQuestion(FormSet, CurrentForm, CurrentStatement, FALSE);
      //
      // Exchange the Guid and name information between VarList and Question List
      //
      Status = GetGuidNameByVariableId (FormSet, CurrentStatement, FormSet->StorageListHead);
      //
      // Remove the question which isn't stored by EfiVarStore or VarStore 
      //
      if (EFI_ERROR (Status)) {
        RemoveEntryList (&CurrentStatement->Link);
        DestroyStatement (FormSet, CurrentStatement);
      }

      break;

    case EFI_IFR_CHECKBOX_OP:
      CurrentStatement = CreateQuestion (OpCodeData, FormSet, CurrentForm);
      ASSERT(CurrentStatement != NULL);

      CurrentStatement->Flags = ((EFI_IFR_CHECKBOX *) OpCodeData)->Flags;
      CurrentStatement->StorageWidth  = (UINT16) sizeof (BOOLEAN);
      CurrentStatement->HiiValue.Type = EFI_IFR_TYPE_BOOLEAN;

      if (BitFieldStorage) {
        //
        // Get the bit var store info (bit/byte offset, bit/byte width)
        //
        CurrentStatement->QuestionReferToBitField = TRUE;
        CurrentStatement->BitStorageWidth = 1;
        CurrentStatement->BitVarOffset = CurrentStatement->VarStoreInfo.VarOffset;
        CurrentStatement->VarStoreInfo.VarOffset = CurrentStatement->BitVarOffset / 8;
        TotalBits = CurrentStatement->BitVarOffset % 8 + CurrentStatement->BitStorageWidth;
        CurrentStatement->StorageWidth = (TotalBits % 8 == 0? TotalBits / 8: TotalBits / 8 + 1);
      }
      //
      // Get the UQI information
      //
      PrintQuestion(FormSet, CurrentForm, CurrentStatement, FALSE);
      //
      // Exchange the Guid and name information between VarList and Question List
      //
      Status = GetGuidNameByVariableId (FormSet, CurrentStatement, FormSet->StorageListHead);
      //
      // Remove the question which isn't stored by EfiVarStore or VarStore 
      //
      if (EFI_ERROR (Status)) {
        RemoveEntryList (&CurrentStatement->Link);
        DestroyStatement (FormSet, CurrentStatement);
      }

      break;

    case EFI_IFR_STRING_OP:
      CurrentStatement = CreateQuestion (OpCodeData, FormSet, CurrentForm);
      ASSERT (CurrentStatement != NULL);
      //
      // MinSize is the minimum number of characters that can be accepted for this opcode,
      // MaxSize is the maximum number of characters that can be accepted for this opcode.
      // The characters are stored as Unicode, so the storage width should multiply 2.
      //
      CurrentStatement->Minimum = ((EFI_IFR_STRING *) OpCodeData)->MinSize;
      CurrentStatement->Maximum = ((EFI_IFR_STRING *) OpCodeData)->MaxSize;
      CurrentStatement->StorageWidth = (UINT16)((UINTN) CurrentStatement->Maximum * sizeof (CHAR16));
      CurrentStatement->Flags = ((EFI_IFR_STRING *) OpCodeData)->Flags;

      CurrentStatement->HiiValue.Type = EFI_IFR_TYPE_STRING;
      CurrentStatement->BufferValue = AllocateZeroPool (CurrentStatement->StorageWidth + sizeof (CHAR16));
      //
      // Get the UQI information
      //
      PrintQuestion(FormSet, CurrentForm, CurrentStatement, FALSE);
      //
      // Exchange the Guid and name information between VarList and Question List
      //
      Status = GetGuidNameByVariableId (FormSet, CurrentStatement, FormSet->StorageListHead);
      //
      // Remove the question which isn't stored by EfiVarStore or VarStore 
      //
      if (EFI_ERROR (Status)) {
        RemoveEntryList (&CurrentStatement->Link);
        DestroyStatement (FormSet, CurrentStatement);
      }

      break;

    case EFI_IFR_PASSWORD_OP:
      CurrentStatement = CreateQuestion (OpCodeData, FormSet, CurrentForm);
      ASSERT (CurrentStatement != NULL);
      //
      // MinSize is the minimum number of characters that can be accepted for this opcode,
      // MaxSize is the maximum number of characters that can be accepted for this opcode.
      // The characters are stored as Unicode, so the storage width should multiply 2.
      //
      CopyMem (&CurrentStatement->Minimum, &((EFI_IFR_PASSWORD *) OpCodeData)->MinSize, sizeof (UINT16));
      CopyMem (&CurrentStatement->Maximum, &((EFI_IFR_PASSWORD *) OpCodeData)->MaxSize, sizeof (UINT16));
      CurrentStatement->StorageWidth = (UINT16)((UINTN) CurrentStatement->Maximum * sizeof (CHAR16));

      CurrentStatement->HiiValue.Type = EFI_IFR_TYPE_STRING;
      CurrentStatement->BufferValue = AllocateZeroPool ((CurrentStatement->StorageWidth + sizeof (CHAR16)));
      break;

    case EFI_IFR_DATE_OP:
      CurrentStatement = CreateQuestion (OpCodeData, FormSet, CurrentForm);
      ASSERT(CurrentStatement != NULL);

      CurrentStatement->Flags = ((EFI_IFR_DATE *) OpCodeData)->Flags;
      CurrentStatement->HiiValue.Type = EFI_IFR_TYPE_DATE;

      if ((CurrentStatement->Flags & EFI_QF_DATE_STORAGE) == QF_DATE_STORAGE_NORMAL) {
        CurrentStatement->StorageWidth = (UINT16) sizeof (EFI_HII_DATE);
      } else {
        //
        // Don't assign storage for RTC type of date/time
        //
        CurrentStatement->Storage = NULL;
        CurrentStatement->StorageWidth = 0;
      }
      break;

    case EFI_IFR_TIME_OP:
      CurrentStatement = CreateQuestion (OpCodeData, FormSet, CurrentForm);
      ASSERT(CurrentStatement != NULL);

      CurrentStatement->Flags = ((EFI_IFR_TIME *) OpCodeData)->Flags;
      CurrentStatement->HiiValue.Type = EFI_IFR_TYPE_TIME;

      if ((CurrentStatement->Flags & QF_TIME_STORAGE) == QF_TIME_STORAGE_NORMAL) {
        CurrentStatement->StorageWidth = (UINT16) sizeof (EFI_HII_TIME);
      } else {
        //
        // Don't assign storage for RTC type of date/time
        //
        CurrentStatement->Storage = NULL;
        CurrentStatement->StorageWidth = 0;
      }
      break;

    //
    // Default
    //
    case EFI_IFR_DEFAULT_OP:
      //
      // EFI_IFR_DEFAULT appear in scope of a Question,
      // It creates a default value for the current question.
      // A Question may have more than one Default value which have different default types.
      //
      CurrentDefault = AllocateZeroPool (sizeof (QUESTION_DEFAULT));
      ASSERT (CurrentDefault != NULL);
      CurrentDefault->Signature = QUESTION_DEFAULT_SIGNATURE;

      CurrentDefault->Value.Type = ((EFI_IFR_DEFAULT *) OpCodeData)->Type;
      CopyMem (&CurrentDefault->DefaultId, &((EFI_IFR_DEFAULT *) OpCodeData)->DefaultId, sizeof (UINT16));
      if (CurrentDefault->Value.Type == EFI_IFR_TYPE_BUFFER) {
        CurrentDefault->Value.BufferLen = (UINT16)(OpCodeLength - OFFSET_OF(EFI_IFR_DEFAULT, Value));
        CurrentDefault->Value.Buffer = FceAllocateCopyPool(CurrentDefault->Value.BufferLen, &((EFI_IFR_DEFAULT *)OpCodeData)->Value);
        ASSERT(CurrentDefault->Value.Buffer != NULL);
      } else {
        CopyMem(&CurrentDefault->Value.Value, &((EFI_IFR_DEFAULT *)OpCodeData)->Value, OpCodeLength - OFFSET_OF(EFI_IFR_DEFAULT, Value));
        ExtendValueToU64(&CurrentDefault->Value);
      }

      //
      // Insert to Default Value list of current Question
      //
      InsertTailList (&CurrentStatement->DefaultListHead, &CurrentDefault->Link);

      if (Scope != 0) {
        InScopeDefault = TRUE;
      }
      break;

    //
    // Option
    //
    case EFI_IFR_ONE_OF_OPTION_OP:
      ASSERT (CurrentStatement != NULL);
      if (CurrentStatement->Operand == EFI_IFR_ORDERED_LIST_OP &&
        ((((EFI_IFR_ONE_OF_OPTION *)OpCodeData)->Flags & (EFI_IFR_OPTION_DEFAULT | EFI_IFR_OPTION_DEFAULT_MFG)) != 0)) {
        //
        // It's keep the default value for ordered list opcode.
        //
        CurrentDefault = AllocateZeroPool(sizeof (QUESTION_DEFAULT));
        ASSERT(CurrentDefault != NULL);
        CurrentDefault->Signature = QUESTION_DEFAULT_SIGNATURE;

        CurrentDefault->Value.Type = EFI_IFR_TYPE_BUFFER;
        if ((((EFI_IFR_ONE_OF_OPTION *)OpCodeData)->Flags & EFI_IFR_OPTION_DEFAULT) != 0) {
          CurrentDefault->DefaultId = EFI_HII_DEFAULT_CLASS_STANDARD;
        } else {
          CurrentDefault->DefaultId = EFI_HII_DEFAULT_CLASS_MANUFACTURING;
        }

        CurrentDefault->Value.BufferLen = (UINT16)(OpCodeLength - OFFSET_OF(EFI_IFR_ONE_OF_OPTION, Value));
        CurrentDefault->Value.Buffer = FceAllocateCopyPool(CurrentDefault->Value.BufferLen, &((EFI_IFR_ONE_OF_OPTION *)OpCodeData)->Value);
        ASSERT(CurrentDefault->Value.Buffer != NULL);

        //
        // Insert to Default Value list of current Question
        //
        InsertTailList(&CurrentStatement->DefaultListHead, &CurrentDefault->Link);
        break;
      }
      //
      // EFI_IFR_ONE_OF_OPTION appear in scope of a Question.
      // It create a selection for use in current Question.
      //
      CurrentOption = AllocateZeroPool (sizeof (QUESTION_OPTION));
      ASSERT (CurrentOption != NULL);
      CurrentOption->Signature = QUESTION_OPTION_SIGNATURE;

      CurrentOption->Flags = ((EFI_IFR_ONE_OF_OPTION *) OpCodeData)->Flags;
      CurrentOption->Value.Type = ((EFI_IFR_ONE_OF_OPTION *) OpCodeData)->Type;
      CopyMem (&CurrentOption->Text, &((EFI_IFR_ONE_OF_OPTION *) OpCodeData)->Option, sizeof (EFI_STRING_ID));
      CopyMem (&CurrentOption->Value.Value, &((EFI_IFR_ONE_OF_OPTION *) OpCodeData)->Value, OpCodeLength - OFFSET_OF (EFI_IFR_ONE_OF_OPTION, Value));
      ExtendValueToU64 (&CurrentOption->Value);

      if (InScopeOptionSuppress) {
        CurrentOption->SuppressExpression = OptionSuppressExpression;
      }

      //
      // Insert to Option list of current Question
      //
      InsertTailList (&CurrentStatement->OptionListHead, &CurrentOption->Link);

      //
      // Now we know the Storage width of nested Ordered List
      //
      if ((CurrentStatement->Operand == EFI_IFR_ORDERED_LIST_OP) && (CurrentStatement->BufferValue == NULL)) {
        Width = 1;
        switch (CurrentOption->Value.Type) {
        case EFI_IFR_TYPE_NUM_SIZE_8:
          Width = 1;
          break;

        case EFI_IFR_TYPE_NUM_SIZE_16:
          Width = 2;
          break;

        case EFI_IFR_TYPE_NUM_SIZE_32:
          Width = 4;
          break;

        case EFI_IFR_TYPE_NUM_SIZE_64:
          Width = 8;
          break;

        default:
          //
          // Invalid type for Ordered List
          //
          break;
        }

        CurrentStatement->StorageWidth = (UINT16) (CurrentStatement->MaxContainers * Width);
        CurrentStatement->BufferValue = AllocateZeroPool (CurrentStatement->StorageWidth);
        CurrentStatement->ValueType = CurrentOption->Value.Type;
        if (CurrentStatement->HiiValue.Type == EFI_IFR_TYPE_BUFFER) {
          CurrentStatement->HiiValue.Buffer = CurrentStatement->BufferValue;
          CurrentStatement->HiiValue.BufferLen = CurrentStatement->StorageWidth;
        }
      }
      break;

    //
    // Conditional
    //
    case EFI_IFR_NO_SUBMIT_IF_OP:
    case EFI_IFR_INCONSISTENT_IF_OP:
      //
      // Create an Expression node
      //
      CurrentExpression = CreateExpression (CurrentForm);
      CopyMem (&CurrentExpression->Error, &((EFI_IFR_INCONSISTENT_IF *) OpCodeData)->Error, sizeof (EFI_STRING_ID));

      if (Operand == EFI_IFR_NO_SUBMIT_IF_OP) {
        CurrentExpression->Type = EFI_HII_EXPRESSION_NO_SUBMIT_IF;
        InsertTailList (&CurrentStatement->NoSubmitListHead, &CurrentExpression->Link);
      } else {
        CurrentExpression->Type = EFI_HII_EXPRESSION_INCONSISTENT_IF;
        InsertTailList (&CurrentStatement->InconsistentListHead, &CurrentExpression->Link);
      }
      //
      // Take a look at next OpCode to see whether current expression consists
      // of single OpCode
      //
      if (((EFI_IFR_OP_HEADER *) (OpCodeData + OpCodeLength))->Scope == 0) {
        SingleOpCodeExpression = TRUE;
      }
      break;

    case EFI_IFR_WARNING_IF_OP:
      //
      // Create an Expression node
      //
      CurrentExpression = CreateExpression (CurrentForm);
      CopyMem (&CurrentExpression->Error, &((EFI_IFR_WARNING_IF *) OpCodeData)->Warning, sizeof (EFI_STRING_ID));
      CurrentExpression->TimeOut = ((EFI_IFR_WARNING_IF *) OpCodeData)->TimeOut;
      CurrentExpression->Type    = EFI_HII_EXPRESSION_WARNING_IF;
      InsertTailList (&CurrentStatement->WarningListHead, &CurrentExpression->Link);

      //
      // Take a look at next OpCode to see whether current expression consists
      // of single OpCode
      //
      if (((EFI_IFR_OP_HEADER *) (OpCodeData + OpCodeLength))->Scope == 0) {
        SingleOpCodeExpression = TRUE;
      }
      break;

    case EFI_IFR_SUPPRESS_IF_OP:
      //
      // Question and Option will appear in scope of this OpCode
      //
      CurrentExpression = CreateExpression (CurrentForm);
      CurrentExpression->Type = EFI_HII_EXPRESSION_SUPPRESS_IF;

      if (CurrentForm == NULL) {
        InsertTailList (&FormSet->ExpressionListHead, &CurrentExpression->Link);
      } else {
        InsertTailList (&CurrentForm->ExpressionListHead, &CurrentExpression->Link);
      }

      if (SuppressForOption) {
        InScopeOptionSuppress = TRUE;
        OptionSuppressExpression = CurrentExpression;
      } else if (SuppressForQuestion) {
        mInScopeSuppress = TRUE;
        mSuppressExpression = CurrentExpression;
      } else {
        InScopeFormSuppress = TRUE;
        FormSuppressExpression = CurrentExpression;
      }
      //
      // Take a look at next OpCode to see whether current expression consists
      // of single OpCode
      //
      if (((EFI_IFR_OP_HEADER *) (OpCodeData + OpCodeLength))->Scope == 0) {
        SingleOpCodeExpression = TRUE;
      }
      break;

    case EFI_IFR_GRAY_OUT_IF_OP:
      //
      // Questions will appear in scope of this OpCode
      //
      CurrentExpression = CreateExpression (CurrentForm);
      CurrentExpression->Type = EFI_HII_EXPRESSION_GRAY_OUT_IF;
      InsertTailList (&CurrentForm->ExpressionListHead, &CurrentExpression->Link);

      mInScopeGrayOut = TRUE;
      mGrayOutExpression = CurrentExpression;

      //
      // Take a look at next OpCode to see whether current expression consists
      // of single OpCode
      //
      if (((EFI_IFR_OP_HEADER *) (OpCodeData + OpCodeLength))->Scope == 0) {
        SingleOpCodeExpression = TRUE;
      }
      break;

    case EFI_IFR_DISABLE_IF_OP:
      //
      // The DisableIf expression should only rely on constant, so it could be
      // evaluated at initialization and it will not be queued
      //
      CurrentExpression = AllocateZeroPool (sizeof (FORM_EXPRESSION));
      ASSERT (CurrentExpression != NULL);
      CurrentExpression->Signature = FORM_EXPRESSION_SIGNATURE;
      CurrentExpression->Type = EFI_HII_EXPRESSION_DISABLE_IF;
      InitializeListHead (&CurrentExpression->OpCodeListHead);

      if (CurrentForm != NULL) {
        //
        // This is DisableIf for Question, enqueue it to Form expression list
        //
        InsertTailList (&CurrentForm->ExpressionListHead, &CurrentExpression->Link);
      }

      mDisableExpression = CurrentExpression;
      mInScopeDisable    = TRUE;
      OpCodeDisabled     = FALSE;

      //
      // Take a look at next OpCode to see whether current expression consists
      // of single OpCode
      //
      if (((EFI_IFR_OP_HEADER *) (OpCodeData + OpCodeLength))->Scope == 0) {
        SingleOpCodeExpression = TRUE;
      }
      break;

    //
    // Expression
    //
    case EFI_IFR_VALUE_OP:
      CurrentExpression = CreateExpression (CurrentForm);
      CurrentExpression->Type = EFI_HII_EXPRESSION_VALUE;
      InsertTailList (&CurrentForm->ExpressionListHead, &CurrentExpression->Link);

      if (InScopeDefault) {
        //
        // Used for default (EFI_IFR_DEFAULT)
        //
        CurrentDefault->ValueExpression = CurrentExpression;
      } else {
        //
        // If used for a question, then the question will be read-only
        //
        //
        // Make sure CurrentStatement is not NULL.
        // If it is NULL, 1) ParseOpCodes functions may parse the IFR wrongly. Or 2) the IFR
        // file is wrongly generated by tools such as VFR Compiler. There may be a bug in VFR Compiler.
        //
        ASSERT (CurrentStatement != NULL);
        CurrentStatement->ValueExpression = CurrentExpression;
      }

      //
      // Take a look at next OpCode to see whether current expression consists
      // of single OpCode
      //
      if (((EFI_IFR_OP_HEADER *) (OpCodeData + OpCodeLength))->Scope == 0) {
        SingleOpCodeExpression = TRUE;
      }
      break;

    case EFI_IFR_RULE_OP:
      CurrentExpression = CreateExpression (CurrentForm);
      CurrentExpression->Type = EFI_HII_EXPRESSION_RULE;

      CurrentExpression->RuleId = ((EFI_IFR_RULE *) OpCodeData)->RuleId;
      InsertTailList (&CurrentForm->ExpressionListHead, &CurrentExpression->Link);

      //
      // Take a look at next OpCode to see whether current expression consists
      // of single OpCode
      //
      if (((EFI_IFR_OP_HEADER *) (OpCodeData + OpCodeLength))->Scope == 0) {
        SingleOpCodeExpression = TRUE;
      }
      break;

    case EFI_IFR_READ_OP:
      CurrentExpression = CreateExpression (CurrentForm);
      CurrentExpression->Type = EFI_HII_EXPRESSION_READ;
      InsertTailList (&CurrentForm->ExpressionListHead, &CurrentExpression->Link);

      //
      // Make sure CurrentStatement is not NULL.
      // If it is NULL, 1) ParseOpCodes functions may parse the IFR wrongly. Or 2) the IFR
      // file is wrongly generated by tools such as VFR Compiler. There may be a bug in VFR Compiler.
      //
      ASSERT (CurrentStatement != NULL);
      CurrentStatement->ReadExpression = CurrentExpression;

      //
      // Take a look at next OpCode to see whether current expression consists
      // of single OpCode
      //
      if (((EFI_IFR_OP_HEADER *) (OpCodeData + OpCodeLength))->Scope == 0) {
        SingleOpCodeExpression = TRUE;
      }
      break;

    case EFI_IFR_WRITE_OP:
      CurrentExpression = CreateExpression (CurrentForm);
      CurrentExpression->Type = EFI_HII_EXPRESSION_WRITE;
      InsertTailList (&CurrentForm->ExpressionListHead, &CurrentExpression->Link);

      //
      // Make sure CurrentStatement is not NULL.
      // If it is NULL, 1) ParseOpCodes functions may parse the IFR wrongly. Or 2) the IFR
      // file is wrongly generated by tools such as VFR Compiler. There may be a bug in VFR Compiler.
      //
      ASSERT (CurrentStatement != NULL);
      CurrentStatement->WriteExpression = CurrentExpression;

      //
      // Take a look at next OpCode to see whether current expression consists
      // of single OpCode
      //
      if (((EFI_IFR_OP_HEADER *) (OpCodeData + OpCodeLength))->Scope == 0) {
        SingleOpCodeExpression = TRUE;
      }
      break;

    //
    // Image
    //
    case EFI_IFR_IMAGE_OP:
      //
      // Get ScopeOpcode from top of stack
      //
      PopScope (&ScopeOpCode);
      PushScope (ScopeOpCode);

      switch (ScopeOpCode) {
      case EFI_IFR_FORM_SET_OP:
        break;

      case EFI_IFR_FORM_OP:
      case EFI_IFR_FORM_MAP_OP:
        ASSERT (CurrentForm != NULL);
        break;

      case EFI_IFR_ONE_OF_OPTION_OP:
        break;

      default:
        //
        // Make sure CurrentStatement is not NULL.
        // If it is NULL, 1) ParseOpCodes functions may parse the IFR wrongly. Or 2) the IFR
        // file is wrongly generated by tools such as VFR Compiler.
        //
        ASSERT (CurrentStatement != NULL);
        break;
      }
      break;

    //
    // Refresh
    //
    case EFI_IFR_REFRESH_OP:
      break;

    //
    // Refresh guid.
    //
    case EFI_IFR_REFRESH_ID_OP:
      break;

    //
    // Modal tag
    //
    case EFI_IFR_MODAL_TAG_OP:
      break;

    //
    // Vendor specific
    //
    case EFI_IFR_GUID_OP:
      if (CompareGuid ((EFI_GUID *)(OpCodeData + sizeof (EFI_IFR_OP_HEADER)), &gEdkiiIfrBitVarGuid)==0) {
        Scope = 0;
        BitFieldStorage = TRUE;
      }
      break;

    //
    // Scope End
    //
    case EFI_IFR_END_OP:
      BitFieldStorage = FALSE;
      Status = PopScope (&ScopeOpCode);
      if (EFI_ERROR (Status)) {
        ResetScopeStack ();
        return Status;
      }

      switch (ScopeOpCode) {
      case EFI_IFR_FORM_SET_OP:
        //
        // End of FormSet, update FormSet IFR binary length
        // to stop parsing substantial OpCodes
        //
        FormSet->IfrBinaryLength = OpCodeOffset;
        break;

      case EFI_IFR_FORM_OP:
      case EFI_IFR_FORM_MAP_OP:
        //
        // End of Form
        //
        CurrentForm = NULL;
        SuppressForQuestion = FALSE;
        break;

      case EFI_IFR_ONE_OF_OPTION_OP:
        //
        // End of Option
        //
        CurrentOption = NULL;
        break;

      case EFI_IFR_SUBTITLE_OP:
        mInScopeSubtitle = FALSE;
        break;

      case EFI_IFR_NO_SUBMIT_IF_OP:
      case EFI_IFR_INCONSISTENT_IF_OP:
      case EFI_IFR_WARNING_IF_OP:
        //
        // Ignore end of EFI_IFR_NO_SUBMIT_IF and EFI_IFR_INCONSISTENT_IF
        //
        break;

      case EFI_IFR_SUPPRESS_IF_OP:
        if (SuppressForOption) {
          InScopeOptionSuppress = FALSE;
        } else if (SuppressForQuestion) {
          mInScopeSuppress = FALSE;
        } else {
          InScopeFormSuppress = FALSE;
        }
        break;

      case EFI_IFR_GRAY_OUT_IF_OP:
        mInScopeGrayOut = FALSE;
        break;

      case EFI_IFR_DISABLE_IF_OP:
        mInScopeDisable = FALSE;
        OpCodeDisabled  = FALSE;
        break;

      case EFI_IFR_ONE_OF_OP:
      case EFI_IFR_ORDERED_LIST_OP:
        SuppressForOption = FALSE;
        break;

      case EFI_IFR_DEFAULT_OP:
        InScopeDefault = FALSE;
        break;

      case EFI_IFR_MAP_OP:
        //
        // Get current Map Expression List.
        //
        Status = PopMapExpressionList ((VOID **) &MapExpressionList);
        if (Status == EFI_ACCESS_DENIED) {
          MapExpressionList = NULL;
        }
        //
        // Get current expression.
        //
        Status = PopCurrentExpression ((VOID **) &CurrentExpression);
        ASSERT (!EFI_ERROR (Status));
        ASSERT (MapScopeDepth > 0);
        MapScopeDepth --;
        break;

      default:
        if (IsExpressionOpCode (ScopeOpCode)) {
          if (mInScopeDisable && (CurrentForm == NULL)) {
            //
            // This is DisableIf expression for Form, it should be a constant expression
            //
            ASSERT (CurrentExpression != NULL);
            ConstantFlag = TRUE;
            Status = EvaluateExpression (FormSet, CurrentForm, CurrentExpression, &ConstantFlag);
            if (EFI_ERROR (Status)) {
              return Status;
            }
            if (CurrentExpression->Result.Type != EFI_IFR_TYPE_BOOLEAN) {
              return EFI_INVALID_PARAMETER;
            }
            if (!ConstantFlag) {
              StringPrint ("WARNING. The DisableIf expression for Form should be a constant expression.\n");
            }
            OpCodeDisabled = CurrentExpression->Result.Value.b;
            //
            // DisableIf Expression is only used once and not queued, free it
            //
            DestroyExpression (CurrentExpression);
          }

          //
          // End of current Expression
          //
          CurrentExpression = NULL;
        }
        break;
      }
      break;

    default:
      break;
    }
  }

  return EFI_SUCCESS;
}

/**
  Search an Option of a Question by its value.

  @param  Question               The Question
  @param  OptionValue            Value for Option to be searched.

  @retval Pointer                Pointer to the found Option.
  @retval NULL                   Option not found.

**/
QUESTION_OPTION *
ValueToOption (
  IN FORM_BROWSER_FORMSET     *FormSet,
  IN FORM_BROWSER_STATEMENT   *Question,
  IN EFI_HII_VALUE            *OptionValue
  )
{
  LIST_ENTRY       *Link;
  QUESTION_OPTION  *Option;

  Link = GetFirstNode (&Question->OptionListHead);
  while (!IsNull (&Question->OptionListHead, Link)) {
    Option = QUESTION_OPTION_FROM_LINK (Link);

    if (CompareHiiValue (&Option->Value, OptionValue, FormSet) == 0) {
      return Option;
    }

    Link = GetNextNode (&Question->OptionListHead, Link);
  }

  return NULL;
}

/**
  Set value of a data element in an Array by its Index.

  @param  Array                  The data array.
  @param  Type                   Type of the data in this array.
  @param  Index                  Zero based index for data in this array.
  @param  Value                  The value to be set.

**/
VOID
SetArrayData (
  IN VOID                     *Array,
  IN UINT8                    Type,
  IN UINTN                    Index,
  IN UINT64                   Value
  )
{

  ASSERT (Array != NULL);

  switch (Type) {
  case EFI_IFR_TYPE_NUM_SIZE_8:
    *(((UINT8 *) Array) + Index) = (UINT8) Value;
    break;

  case EFI_IFR_TYPE_NUM_SIZE_16:
    *(((UINT16 *) Array) + Index) = (UINT16) Value;
    break;

  case EFI_IFR_TYPE_NUM_SIZE_32:
    *(((UINT32 *) Array) + Index) = (UINT32) Value;
    break;

  case EFI_IFR_TYPE_NUM_SIZE_64:
    *(((UINT64 *) Array) + Index) = (UINT64) Value;
    break;

  default:
    break;
  }
}

/**
  Reset Question of five kinds to its default value.

  @param  FormSet                The form set.
  @param  Form                   The form.
  @param  Question               The question.
  @param  DefaultId              The default Id.
  @param  DefaultId              The platform Id.

  @retval EFI_SUCCESS            Question is reset to default value.

**/
EFI_STATUS
GetQuestionDefault (
  IN FORM_BROWSER_FORMSET             *FormSet,
  IN FORM_BROWSER_FORM                *Form,
  IN FORM_BROWSER_STATEMENT           *Question,
  IN UINT16                           DefaultId,
  IN UINT64                           PlatformId
  )
{
  EFI_STATUS              Status;
  LIST_ENTRY              *Link;
  QUESTION_DEFAULT        *Default;
  QUESTION_OPTION         *Option;
  EFI_HII_VALUE           *HiiValue;
  UINT8                   Index;
  FORMSET_STORAGE         *VarList;
  UINT8                   *VarBuffer;
  BOOLEAN                 ConstantFlag;
  UINT16                  OriginalDefaultId;
  FORMSET_DEFAULTSTORE    *DefaultStore;
  LIST_ENTRY              *DefaultLink;
  CHAR16                  *VarDefaultName;

  VarDefaultName  = NULL;
  Status          = EFI_SUCCESS;
  ConstantFlag    = TRUE;
  OriginalDefaultId  = DefaultId;
  DefaultLink        = GetFirstNode (&FormSet->DefaultStoreListHead);

  //
  // Statement don't have storage, skip them
  //
  if (Question->QuestionId == 0) {
    return EFI_NOT_FOUND;
  }
  //
  // Return if no any kinds of 
  //
  if ((Question->Operand != EFI_IFR_CHECKBOX_OP)
    && (Question->Operand != EFI_IFR_ONE_OF_OP)
    && (Question->Operand != EFI_IFR_ORDERED_LIST_OP)
    && (Question->Operand != EFI_IFR_NUMERIC_OP)
    && (Question->Operand != EFI_IFR_STRING_OP)
    ) {
    return EFI_ABORTED;
  }
  //
  // Search the variable for this question (Compatible with the old EfiVarStore before UEFI2.31)
  //

  //
  //VarStoreInfoDepending on the type of variable store selected, 
  //this contains either a 16-bit Buffer Storage offset (VarOffset) 
  //or a Name/Value or EFI Variable name (VarName).
  //
  Status = SearchVarStorage (
             Question, 
             NULL, 
             Question->VarStoreInfo.VarOffset,
             FormSet->StorageListHead,
             (CHAR8 **)&VarBuffer,
             &VarList
             );
  if (EFI_ERROR(Status)) {
    return Status;
  }
  //
  // There are three ways to specify default value for a Question:
  //  1, use nested EFI_IFR_DEFAULT 
  //  2, set flags of EFI_ONE_OF_OPTION (provide Standard and Manufacturing default)
  //  3, set flags of EFI_IFR_CHECKBOX (provide Standard and Manufacturing default) (lowest priority)
  //
ReGetDefault:
  HiiValue = &Question->HiiValue;
  //
  // EFI_IFR_DEFAULT has highest priority
  //
  if (!IsListEmpty (&Question->DefaultListHead)) {
    Link = GetFirstNode (&Question->DefaultListHead);
    while (!IsNull (&Question->DefaultListHead, Link)) {
      Default = QUESTION_DEFAULT_FROM_LINK (Link);

      if (Default->DefaultId == DefaultId) {
        if (Default->ValueExpression != NULL) {
          //
          // Default is provided by an Expression, evaluate it
          //
          Status = EvaluateExpression (FormSet, Form, Default->ValueExpression, &ConstantFlag);
          if (EFI_ERROR (Status)) {
            return Status;
          }

          if (Default->ValueExpression->Result.Type == EFI_IFR_TYPE_BUFFER) {
            if (Question->StorageWidth > Default->ValueExpression->Result.BufferLen) {
              CopyMem(Question->HiiValue.Buffer, Default->ValueExpression->Result.Buffer, Default->ValueExpression->Result.BufferLen);
              Question->HiiValue.BufferLen = Default->ValueExpression->Result.BufferLen;
            } else {
              CopyMem(Question->HiiValue.Buffer, Default->ValueExpression->Result.Buffer, Question->StorageWidth);
              Question->HiiValue.BufferLen = Question->StorageWidth;
            }
            FreePool(Default->ValueExpression->Result.Buffer);
          }
          HiiValue->Type = Default->ValueExpression->Result.Type;
          CopyMem(&HiiValue->Value, &Default->ValueExpression->Result.Value, sizeof (EFI_IFR_TYPE_VALUE));
        } else {
          //
          // Default value is embedded in EFI_IFR_DEFAULT
          //
          if (Default->Value.Type == EFI_IFR_TYPE_BUFFER) {
            CopyMem(HiiValue->Buffer, Default->Value.Buffer, Default->Value.BufferLen);
          } else {
            CopyMem(HiiValue, &Default->Value, sizeof (EFI_HII_VALUE));
          }
        }
        if (Default->Value.Type == EFI_IFR_TYPE_BUFFER) {
          CopyMem(VarBuffer, HiiValue->Buffer, HiiValue->BufferLen);
        } else if (HiiValue->Type == EFI_IFR_TYPE_STRING){
          Status = FindDefaultName (
                 &(FormSet->EnUsStringList),
                 FormSet->UnicodeBinary,
                 HiiValue->Value.string,
                 EN_US, 
                 &VarDefaultName
                 );
          if (VarDefaultName == NULL) {
            return EFI_NOT_FOUND;
          }
          if (Question->StorageWidth > FceStrSize(VarDefaultName)) {
            ZeroMem (VarBuffer, Question->StorageWidth);
            CopyMem (VarBuffer, VarDefaultName, FceStrSize(VarDefaultName));
          } else {
            CopyMem (VarBuffer, VarDefaultName, Question->StorageWidth);
          }
        } else {
          if (Question->QuestionReferToBitField) {
            SetBitsQuestionValue(Question, VarBuffer, HiiValue->Value.u32);
          } else {
            CopyMem(VarBuffer, &HiiValue->Value.u64, Question->StorageWidth);
          }
        }
        return EFI_SUCCESS;
      }
      if (Default->DefaultId == DefaultId) {
          return EFI_SUCCESS;
       }
      Link = GetNextNode (&Question->DefaultListHead, Link);
    }
  }

  if (HiiValue->Buffer == NULL) {
    ZeroMem (HiiValue, sizeof (EFI_HII_VALUE));
  }

  //
  // EFI_ONE_OF_OPTION
  //
  if ((Question->Operand == EFI_IFR_ONE_OF_OP) && !IsListEmpty (&Question->OptionListHead)) {
    if (DefaultId <= EFI_HII_DEFAULT_CLASS_MANUFACTURING)  {
      //
      // OneOfOption could only provide Standard and Manufacturing default
      //
      Link = GetFirstNode (&Question->OptionListHead);
      while (!IsNull (&Question->OptionListHead, Link)) {
        Option = QUESTION_OPTION_FROM_LINK (Link);

        if (((DefaultId == EFI_HII_DEFAULT_CLASS_STANDARD) && ((Option->Flags & EFI_IFR_OPTION_DEFAULT) != 0)) ||
            ((DefaultId == EFI_HII_DEFAULT_CLASS_MANUFACTURING) && ((Option->Flags & EFI_IFR_OPTION_DEFAULT_MFG) != 0))
           ) {
          CopyMem (HiiValue, &Option->Value, sizeof (EFI_HII_VALUE));
          if (Question->QuestionReferToBitField) {
            SetBitsQuestionValue(Question, VarBuffer, HiiValue->Value.u32);
          } else {
            CopyMem (VarBuffer, &HiiValue->Value.u64, Question->StorageWidth);
          }
          return EFI_SUCCESS;
        }

        Link = GetNextNode (&Question->OptionListHead, Link);
      }
    }
  }

  //
  // EFI_IFR_CHECKBOX - lowest priority
  //
  if (Question->Operand == EFI_IFR_CHECKBOX_OP) {
    if (DefaultId <= EFI_HII_DEFAULT_CLASS_MANUFACTURING)  {
      //
      // Checkbox could only provide Standard and Manufacturing default
      //
      if (((DefaultId == EFI_HII_DEFAULT_CLASS_STANDARD) && ((Question->Flags & EFI_IFR_CHECKBOX_DEFAULT) != 0)) ||
          ((DefaultId == EFI_HII_DEFAULT_CLASS_MANUFACTURING) && ((Question->Flags & EFI_IFR_CHECKBOX_DEFAULT_MFG) != 0))
         ) {
        HiiValue->Value.b = TRUE;
        if (Question->QuestionReferToBitField) {
          SetBitsQuestionValue(Question, VarBuffer, HiiValue->Value.u32);
        } else {
          CopyMem (VarBuffer, &HiiValue->Value.u64, Question->StorageWidth);
        }
        return EFI_SUCCESS;
      }
    }
  }

  //
  // For question without default value for current default Id, we try to re-get the default value form other default id in the DefaultStoreList.
  // If get, will exit the function, if not, will choose next default id in the DefaultStoreList.
  // The default id in DefaultStoreList are in ascending order to make sure choose the smallest default id every time.
  //
  while (!IsNull(&FormSet->DefaultStoreListHead, DefaultLink)) {
    DefaultStore = FORMSET_DEFAULTSTORE_FROM_LINK(DefaultLink);
    DefaultLink = GetNextNode (&FormSet->DefaultStoreListHead,DefaultLink);
    DefaultId = DefaultStore->DefaultId;
    if (DefaultId == OriginalDefaultId) {
      continue;
    }
    goto ReGetDefault;
  }

  //
  // For Questions without default
  //
  Status = EFI_NOT_FOUND;
  switch (Question->Operand) {
  case EFI_IFR_CHECKBOX_OP:
    HiiValue->Value.b = FALSE;
    if (Question->QuestionReferToBitField) {
      SetBitsQuestionValue(Question, VarBuffer, HiiValue->Value.u32);
    } else {
      CopyMem (VarBuffer, &HiiValue->Value.u64, Question->StorageWidth);
    }
    break;

  case EFI_IFR_NUMERIC_OP:
    //
    // Take minimum value as numeric default value
    //
    if ((HiiValue->Value.u64 < Question->Minimum) || (HiiValue->Value.u64 > Question->Maximum)) {
      HiiValue->Value.u64 = Question->Minimum;
      if (Question->QuestionReferToBitField) {
        SetBitsQuestionValue(Question, VarBuffer, HiiValue->Value.u32);
      } else {
        CopyMem (VarBuffer, &HiiValue->Value.u64, Question->StorageWidth);
      }
      return EFI_SUCCESS;
    }
    break;

  case EFI_IFR_ONE_OF_OP:
    //
    // Take first oneof option as oneof's default value
    //
    if (ValueToOption (FormSet, Question, HiiValue) == NULL) {
      Link = GetFirstNode (&Question->OptionListHead);
      if (!IsNull (&Question->OptionListHead, Link)) {
        Option = QUESTION_OPTION_FROM_LINK (Link);
        CopyMem (HiiValue, &Option->Value, sizeof (EFI_HII_VALUE));
        if (Question->QuestionReferToBitField) {
          SetBitsQuestionValue(Question, VarBuffer, HiiValue->Value.u32);
        } else {
          CopyMem (VarBuffer, &HiiValue->Value.u64, Question->StorageWidth);
        }
        return EFI_SUCCESS;
      }
    }
    break;

  case EFI_IFR_ORDERED_LIST_OP:
    //
    // Take option sequence in IFR as ordered list's default value
    //
    Index = 0;
    Link = GetFirstNode (&Question->OptionListHead);
    while (!IsNull (&Question->OptionListHead, Link)) {
      Option = QUESTION_OPTION_FROM_LINK (Link);

      SetArrayData (Question->BufferValue, Question->ValueType, Index, Option->Value.Value.u64);
      SetArrayData (VarBuffer, Question->ValueType, Index, Option->Value.Value.u64);

      Index++;
      if (Index >= Question->MaxContainers) {
        break;
      }

      Link = GetNextNode (&Question->OptionListHead, Link);
    }
    break;

  default:
    break;
  }

  return EFI_SUCCESS;
}

/**
  Set the value to the variable of platformId question.

  @param  PlatformId             The form set.

  @retval EFI_SUCCESS            Set successfully.

**/
EFI_STATUS
AssignThePlatformId (
  IN  UINT64   PlatformId
  )
{
  EFI_STATUS          Status;
  FORMSET_STORAGE     *VarList;
  UINT8               *VarBuffer;

  Status       = EFI_SUCCESS;
  VarBuffer    = NULL;
  //
  // Set the Storage
  //
  Status = SearchVarStorage (
             &mMultiPlatformParam.PlatformIdQuestion, 
             NULL, 
             mMultiPlatformParam.PlatformIdQuestion.VarStoreInfo.VarOffset,
             &mVarListEntry,
             (CHAR8 **)&VarBuffer,
             &VarList
             );
  if (EFI_ERROR(Status)) {
    return Status;
  }
  CopyMem (VarBuffer, &PlatformId, mMultiPlatformParam.PlatformIdWidth);
  //
  // Set the  HIIvalue of this questions
  //
  CopyMem (&mMultiPlatformParam.Question->HiiValue.Value.u64, &PlatformId, mMultiPlatformParam.PlatformIdWidth);
  
  switch (mMultiPlatformParam.PlatformIdWidth) {
    case sizeof (UINT8):
      mMultiPlatformParam.Question->HiiValue.Type = EFI_IFR_TYPE_NUM_SIZE_8;
      break;
      
    case sizeof (UINT16):
      mMultiPlatformParam.Question->HiiValue.Type = EFI_IFR_TYPE_NUM_SIZE_16;
      break;
      
    case sizeof (UINT32):
      mMultiPlatformParam.Question->HiiValue.Type = EFI_IFR_TYPE_NUM_SIZE_32;
      break; 
      
    case sizeof (UINT64):
      mMultiPlatformParam.Question->HiiValue.Type = EFI_IFR_TYPE_NUM_SIZE_64;
      break;     

    default:
      mMultiPlatformParam.Question->HiiValue.Type = EFI_IFR_TYPE_NUM_SIZE_64;
   }  
  return EFI_SUCCESS;
}
/**
  Reset Questions to their default value in a Form, Formset or System.

  @param  FormSet                FormSet data structure.
  @param  Form                   Form data structure.
  @param  DefaultId              The default Id
  @param  PlatformId             The platform Id
  @param  SettingScope           Setting Scope for Default action.

  @retval EFI_SUCCESS            The function completed successfully.
  @retval EFI_UNSUPPORTED        Unsupport SettingScope.

**/
EFI_STATUS
ExtractDefault (
  IN FORM_BROWSER_FORMSET             *FormSet,
  IN FORM_BROWSER_FORM                *Form,
  IN UINT16                           DefaultId,
  IN UINT64                           PlatformId,
  IN BROWSER_SETTING_SCOPE            SettingScope
  )
{
  EFI_STATUS              Status;
  LIST_ENTRY              *FormLink;
  LIST_ENTRY              *Link;
  LIST_ENTRY              *FormSetEntryListHead;
  FORM_BROWSER_STATEMENT  *Question;
  //
  // Check the supported setting level.
  //
  if (SettingScope >= MaxLevel) {
    return EFI_UNSUPPORTED;
  }
  
  if (SettingScope == FormLevel) {
    //
    // Extract Form default
    //
    Link = GetFirstNode (&Form->StatementListHead);
    while (!IsNull (&Form->StatementListHead, Link)) {
      Question = FORM_BROWSER_STATEMENT_FROM_LINK (Link);
      Link = GetNextNode (&Form->StatementListHead, Link);
      //
      // Re-set the platformId before calcuate the platformId of every question to avoid over-written.
      // 
      if (mMultiPlatformParam.MultiPlatformOrNot) {
        Status = AssignThePlatformId (PlatformId);
        if (EFI_ERROR (Status)) {
          StringPrint ("Error. Failed to assign the platformId.\n");
          return Status;
        }
      }
      //
      // Reset Question to its default value, and store the default to variable
      //
      Status = GetQuestionDefault (FormSet, Form, Question, DefaultId, PlatformId);
      if (EFI_ERROR (Status)) {
        continue;
      }
    }
  } else if (SettingScope == FormSetLevel) {
    FormLink = GetFirstNode (&FormSet->FormListHead);
    while (!IsNull (&FormSet->FormListHead, FormLink)) {
      Form = FORM_BROWSER_FORM_FROM_LINK (FormLink);
      ExtractDefault (FormSet, Form, DefaultId, PlatformId, FormLevel);
      FormLink = GetNextNode (&FormSet->FormListHead, FormLink);
    }
  } else if (SettingScope == SystemLevel) {
    //
    // Parse Fromset one by one
    //
    FormSetEntryListHead = &mFormSetListEntry;
    
    FormLink = GetFirstNode (FormSetEntryListHead);
    while (!IsNull (FormSetEntryListHead, FormLink)) {
      FormSet = FORM_BROWSER_FORMSET_FROM_LINK (FormLink);
      ExtractDefault (FormSet, NULL, DefaultId, PlatformId, FormSetLevel);
      FormLink = GetNextNode (FormSetEntryListHead, FormLink);
    }
  }

  return EFI_SUCCESS;
}

/**
  Check whether existed the UQI in Current Unicode String.

  @param  UniPackge         A pointer to a Null-terminated Unicode string Array.

  @return TRUE              If find the uqi, return TRUE
  @return FALSE             Otherwise, return FALSE

**/
STATIC
BOOLEAN
IsUqiOrNot (
  IN  UINT8  *UniPackge
  )
{
  CHAR8          *UniBin;   
  UINTN          UniLength;
  UINTN          Index;
  BOOLEAN        FindIt;
  
  UniBin     = (CHAR8 *) UniPackge + 4;
  Index      = 4;
  FindIt     = FALSE;
  UniLength  = *(UINT32 *) UniPackge;
    
  if (((EFI_HII_PACKAGE_HEADER *)UniBin)->Type == EFI_HII_PACKAGE_STRINGS) {
    //
    // Search the uqi language
    //
    while ((Index < UniLength) && ((EFI_HII_PACKAGE_HEADER *)UniBin)->Type == EFI_HII_PACKAGE_STRINGS){
      if (!strcmp (((EFI_HII_STRING_PACKAGE_HDR *)UniBin)->Language, "uqi")) {
        FindIt = TRUE;
        break;
      }
      Index = Index + ((EFI_HII_STRING_PACKAGE_HDR *)UniBin)->Header.Length;
      UniBin += ((EFI_HII_STRING_PACKAGE_HDR *)UniBin)->Header.Length;
    }
  }
  return FindIt;
}

 /**
  Returns Length of UQI string (in CHAR16) (not including null termination).

  @param  UniPackge         A pointer to a UQI string.

  @return Number            Length of UQIL string (in words) or 0

**/
STATIC
UINT16
GetUqiNum (
  IN     CHAR16        *UniString
  )
{
  UINT16              Number; 
  
  if (UniString == NULL) {
    return 0;
  }
  for (Number = 0; UniString[Number] != 0; Number++) {
    ;
  }
  return Number;
}    

/**
  Print the formset title information.
   
  @param  FormSet    The pointer to the formset.

  @return NULL.

**/
STATIC
VOID
StringPrintormSetTitle (
  IN  FORM_BROWSER_FORMSET  *FormSet
  )
{
  CHAR16      *VarDefaultName;
  EFI_STATUS  Status;
  
  VarDefaultName = NULL;
  
  StringPrint("\n\n// Form Set: ");
        
  Status  = FindDefaultName (
              &(FormSet->EnUsStringList),
              FormSet->UnicodeBinary, 
              FormSet->FormSetTitle, 
              EN_US, 
              &VarDefaultName
             );
  assert (!EFI_ERROR (Status));
  LogUnicodeString (VarDefaultName);
        
  StringPrint("\n// %s",FORM_SET_GUID_PREFIX);
  StringPrint(
    EFI_GUID_FORMAT,
    FormSet->Guid.Data1,   FormSet->Guid.Data2,
    FormSet->Guid.Data3,   FormSet->Guid.Data4[0],
    FormSet->Guid.Data4[1],FormSet->Guid.Data4[2],
    FormSet->Guid.Data4[3],FormSet->Guid.Data4[4],
    FormSet->Guid.Data4[5],FormSet->Guid.Data4[6],
    FormSet->Guid.Data4[7]);
  StringPrint("\n");

  if (&(FormSet->EnUsStringList) == NULL && VarDefaultName != NULL && FormSet->FormSetTitle != 0) {
    free (VarDefaultName);
    VarDefaultName = NULL;
  }
}

/**
  Print the formset title information.
   
  @param  FormSet    The pointer to the formset.
  @param  Question   The pointer to the question of ONE_OF.

  @return NULL.

**/
STATIC
EFI_STATUS
PrintOneOfOptions (
  IN  FORM_BROWSER_FORMSET    *FormSet,
  IN  FORM_BROWSER_STATEMENT  *Question
  )
{
  LIST_ENTRY       *Link;
  QUESTION_OPTION  *Option;
  CHAR16           *VarDefaultName;
  EFI_STATUS       Status;

  Status = EFI_SUCCESS;
  VarDefaultName = NULL;
  
  if ((Question->Operand != EFI_IFR_ONE_OF_OP)
    && (Question->Operand != EFI_IFR_ORDERED_LIST_OP)
    ) {
    return EFI_ABORTED;
  }

  Link = GetFirstNode (&Question->OptionListHead);
  while (!IsNull (&Question->OptionListHead, Link)) { 
    Option = QUESTION_OPTION_FROM_LINK (Link);
    if (Question->QuestionReferToBitField) {
      StringPrint("// %08X = ", Option->Value.Value.u32);
    } else {
      switch(Option->Value.Type) {

        case EFI_IFR_TYPE_NUM_SIZE_8:
          StringPrint("// %02X = ", Option->Value.Value.u8);
          break;

        case EFI_IFR_TYPE_NUM_SIZE_16:
          StringPrint("// %04X = ", Option->Value.Value.u16);
          break;

        case EFI_IFR_TYPE_NUM_SIZE_32:
          StringPrint("// %08X = ", Option->Value.Value.u32);
          break;

        case EFI_IFR_TYPE_NUM_SIZE_64:
          StringPrint("// %016llX = ", Option->Value.Value.u64);
          break;

        case EFI_IFR_TYPE_BOOLEAN:
          StringPrint("// %X = ", Option->Value.Value.b);
          break;

        case EFI_IFR_TYPE_STRING:
          StringPrint("// %X = ", Option->Value.Value.string);
          break;

        default:
          break;
        }
      }
    Status = FindDefaultName (
               &(FormSet->EnUsStringList),
               FormSet->UnicodeBinary, 
               Option->Text, 
               EN_US, 
               &VarDefaultName
               );
    
    LogUnicodeString (VarDefaultName);
    StringPrint("\n");
    if (&(FormSet->EnUsStringList) == NULL && VarDefaultName != NULL && Option->Text != 0) {
      free (VarDefaultName);
      VarDefaultName = NULL;
    }
    Link = GetNextNode (&Question->OptionListHead, Link);
  }
  return Status;
}

/**
  Print the form title information.
   
  @param  FormSet    The pointer to the formset.
  @param  FormSet    The pointer to the form.

  @return NULL.

**/
STATIC
VOID
StringPrintormTitle (
  IN  FORM_BROWSER_FORMSET  *FormSet,
  IN  FORM_BROWSER_FORM     *Form
  )
{
  CHAR16      *VarDefaultName;
  EFI_STATUS  Status;
    
  VarDefaultName = NULL;

  StringPrint("\n// Form: ");
  Status  = FindDefaultName (
              &(FormSet->EnUsStringList),
              FormSet->UnicodeBinary, 
              Form->FormTitle, 
              EN_US, 
              &VarDefaultName
             );
  assert (!EFI_ERROR (Status));

  LogUnicodeString (VarDefaultName);
  StringPrint("\n");

  if (&(FormSet->EnUsStringList) == NULL && VarDefaultName != NULL && Form->FormTitle != 0) {
    free (VarDefaultName);
    VarDefaultName  = NULL;
  }

}

/**
  Print the information of questions.

  @param  FormSet     The pointer to the formset.
  @param  FormSet     The pointer to the form.
  @param  Question    The pointer to the question.
  @param  PrintOrNot  Decide whether print or not.

  @return NULL.

**/
STATIC
VOID
PrintQuestion (
  IN  FORM_BROWSER_FORMSET    *FormSet,
  IN  FORM_BROWSER_FORM       *Form,
  IN  FORM_BROWSER_STATEMENT  *Question,
  IN  BOOLEAN                  PrintOrNot
  )
{
  EFI_STATUS       Status;
  CHAR16           *VarDefaultName;
  UINT16           UqiStringLength;
  BOOLEAN          HaveUQIlanguage;

  Status           = EFI_SUCCESS;
  VarDefaultName   = NULL;
  UqiStringLength  = 0;

  HaveUQIlanguage = IsUqiOrNot (FormSet->UnicodeBinary);
  
  switch (Question->Operand) {
  
  case EFI_IFR_SUBTITLE_OP:
  if (PrintOrNot) {
    Status  = FindDefaultName (
                &(FormSet->EnUsStringList),
                FormSet->UnicodeBinary, 
                Question->Prompt,
                EN_US, 
                &VarDefaultName
                );
    assert (!EFI_ERROR (Status));
    if ((VarDefaultName != NULL) && (FceStrCmp (VarDefaultName, L"") != 0)) {
      StringPrint("// Subtitle: ");
      StringPrint("// ");
      LogUnicodeString (VarDefaultName);
      StringPrint("\n");
    }
  }
    break;
  
  case EFI_IFR_ONE_OF_OP:

    if( HaveUQIlanguage ) {
      Status = FindDefaultName (
                 &(FormSet->UqiStringList),
                 FormSet->UnicodeBinary, 
                 Question->Prompt, 
                 UQI, 
                 &VarDefaultName
                 );
      assert (!EFI_ERROR (Status));
      
      UqiStringLength = GetUqiNum (VarDefaultName);
      if (PrintOrNot) {
        if (UqiStringLength > 0) {
          StringPrint("\nQ %04X ", UqiStringLength);
          LogUqi(VarDefaultName);
        } else {
          StringPrint("\n// [No UQI] ");
        }
      }
    } else {
      Status       = FindDefaultName (
                       &(FormSet->EnUsStringList),
                       FormSet->UnicodeBinary, 
                       Question->Prompt, 
                       EN_US, 
                       &VarDefaultName
                     );
      assert (!EFI_ERROR (Status)); 
      UqiStringLength = GetUqiNum (VarDefaultName);

      if (PrintOrNot) {
        if (UqiStringLength > 0) {
          StringPrint("\nQ %04X ", UqiStringLength);
          LogUqi(VarDefaultName);
        } else {
          StringPrint("\n// [No UQI] ");
        }
      }
    }
    //
    //Record the UQi to the Question
    //
    Question->Uqi.HexNum = UqiStringLength;
    Question->Uqi.Data   = VarDefaultName;
    Question->Uqi.Type   = ONE_OF;
    
    if (PrintOrNot) {
      StringPrint("ONE_OF ");
      
      LogIfrValue ( 
        FormSet,
        Question
        );
      StringPrint(" // ");
      Status       = FindDefaultName (
                       &(FormSet->EnUsStringList),
                       FormSet->UnicodeBinary, 
                       Question->Prompt, 
                       EN_US, 
                       &VarDefaultName
                       );
      assert (!EFI_ERROR (Status));
      LogUnicodeString (VarDefaultName);
      StringPrint("\n");
      //
      // Print ONE_OF_OPTION
      //
      PrintOneOfOptions (FormSet, Question);
    }
    break;
  
  case EFI_IFR_CHECKBOX_OP:

    if( HaveUQIlanguage ) {
      Status = FindDefaultName (
                 &(FormSet->UqiStringList),
                 FormSet->UnicodeBinary, 
                 Question->Prompt, 
                 UQI, 
                 &VarDefaultName
                 );
      assert (!EFI_ERROR (Status));
      
      UqiStringLength = GetUqiNum (VarDefaultName);
      if (PrintOrNot) {
        if (UqiStringLength > 0) {
          StringPrint("\nQ %04X ", UqiStringLength);
          LogUqi(VarDefaultName);
        } else {
          StringPrint("\n// [No UQI] ");
        }
      }
    } else {
      Status = FindDefaultName (
                 &(FormSet->EnUsStringList),
                 FormSet->UnicodeBinary, 
                 Question->Prompt, 
                 EN_US, 
                 &VarDefaultName
                 );
      assert (!EFI_ERROR (Status));
    
      UqiStringLength = GetUqiNum (VarDefaultName);

      if (PrintOrNot) {
        if (UqiStringLength > 0) {
          StringPrint("\nQ %04X ", UqiStringLength);
          LogUqi(VarDefaultName);
        } else {
          StringPrint("\n// [No UQI] ");
        }
      }
    }
    //
    //Record the UQi to the HiiObjList
    //
    Question->Uqi.HexNum = UqiStringLength;
    Question->Uqi.Data   = VarDefaultName;
    Question->Uqi.Type   = CHECKBOX;
    if (PrintOrNot) {
      StringPrint("CHECKBOX ");
      LogIfrValue ( 
        FormSet,
        Question
        );
      StringPrint(" // ");
      Status = FindDefaultName (
                 &(FormSet->EnUsStringList),
                 FormSet->UnicodeBinary, 
                 Question->Prompt,  
                 EN_US, 
                 &VarDefaultName
                 );
      assert (!EFI_ERROR (Status));
      LogUnicodeString (VarDefaultName);
      StringPrint("\n");
      StringPrint("// 0 = Unchecked\n");
      StringPrint("// 1 = Checked\n");
    }
    break;

  case EFI_IFR_STRING_OP:
    if( HaveUQIlanguage ) {
      Status = FindDefaultName (
                 &(FormSet->UqiStringList),
                 FormSet->UnicodeBinary,
                 Question->Prompt,
                 UQI,
                 &VarDefaultName
                 );
      assert (!EFI_ERROR (Status));

      UqiStringLength = GetUqiNum (VarDefaultName);
      if (PrintOrNot) {
        if (UqiStringLength > 0) {
          StringPrint("\nQ %04X ", UqiStringLength);
          LogUqi(VarDefaultName);
        } else {
          StringPrint("\n// [No UQI] ");
        }
      }
    } else {
      Status = FindDefaultName (
                 &(FormSet->EnUsStringList),
                 FormSet->UnicodeBinary,
                 Question->Prompt,
                 EN_US,
                 &VarDefaultName
                 );
      assert (!EFI_ERROR (Status));

      UqiStringLength = GetUqiNum (VarDefaultName);

      if (PrintOrNot) {
        if (UqiStringLength > 0) {
          StringPrint("\nQ %04X ", UqiStringLength);
          LogUqi(VarDefaultName);
        } else {
          StringPrint("\n// [No UQI] ");
        }
      }
    }
    //
    //Record the UQi to the HiiObjList
    //
    Question->Uqi.HexNum = UqiStringLength;
    Question->Uqi.Data   = VarDefaultName;
    Question->Uqi.Type   = STRING;
    if (PrintOrNot) {
      StringPrint("STRING ");
      LogIfrValueStr ( 
        FormSet,
        Question
        );
      StringPrint(" // ");
      Status = FindDefaultName (
                 &(FormSet->EnUsStringList),
                 FormSet->UnicodeBinary,
                 Question->Prompt,
                 EN_US,
                 &VarDefaultName
                 );
      assert (!EFI_ERROR (Status));
      LogUnicodeString (VarDefaultName);
      StringPrint("\n");
    }
    break;

  case EFI_IFR_NUMERIC_OP:

    if( HaveUQIlanguage ) {
      Status = FindDefaultName (
                 &(FormSet->UqiStringList),
                 FormSet->UnicodeBinary, 
                 Question->Prompt,  
                 UQI, 
                 &VarDefaultName
                 );
      assert (!EFI_ERROR (Status));
    
      UqiStringLength = GetUqiNum (VarDefaultName);
      if (PrintOrNot) {
        if (UqiStringLength > 0) {
          StringPrint("\nQ %04X ", UqiStringLength);
          LogUqi(VarDefaultName);
        } else {
          StringPrint("\n// [No UQI] ");
        }
      }
    } else {
      Status = FindDefaultName (
                 &(FormSet->EnUsStringList),
                 FormSet->UnicodeBinary, 
                 Question->Prompt,  
                 EN_US, 
                 &VarDefaultName
                 );
      assert (!EFI_ERROR (Status));
 
      UqiStringLength = GetUqiNum (VarDefaultName);
      if (PrintOrNot) {
        if (UqiStringLength > 0) {
          StringPrint("\nQ %04X ", UqiStringLength);
          LogUqi(VarDefaultName);
        } else {
          StringPrint("\n// [No UQI] ");
        }
      }
    }
    //
    //Record the UQi to the HiiObjList
    //
    Question->Uqi.HexNum = UqiStringLength;
    Question->Uqi.Data   = VarDefaultName;
    Question->Uqi.Type   = NUMERIC;
    if (PrintOrNot) {
      StringPrint("NUMERIC ");
      LogIfrValue ( 
        FormSet,
        Question
      );
      StringPrint(" // ");
      Status = FindDefaultName (
                 &(FormSet->EnUsStringList),
                 FormSet->UnicodeBinary, 
                 Question->Prompt, 
                 EN_US, 
                 &VarDefaultName
                 );
      assert (!EFI_ERROR (Status));
      LogUnicodeString (VarDefaultName);
      StringPrint("\n");

      if (Question->QuestionReferToBitField) {
        StringPrint("// Minimum = %08llX \n", Question->Minimum);
        StringPrint("// Maximum = %08llX \n", Question->Maximum);
        StringPrint("// Step    = %08llX \n", Question->Step);
      } else {
        switch (Question->StorageWidth) {

        case sizeof (UINT8):
          StringPrint("// Minimum = %02llX \n", Question->Minimum);
          StringPrint("// Maximum = %02llX \n", Question->Maximum);
          StringPrint("// Step    = %02llX \n", Question->Step);
          break;

        case sizeof (UINT16):
          StringPrint("// Minimum = %04llX \n", Question->Minimum);
          StringPrint("// Maximum = %04llX \n", Question->Maximum);
          StringPrint("// Step    = %04llX \n", Question->Step);
          break;

        case sizeof (UINT32):
          StringPrint("// Minimum = %08llX \n", Question->Minimum);
          StringPrint("// Maximum = %08llX \n", Question->Maximum);
          StringPrint("// Step    = %08llX \n", Question->Step);
          break;

        case sizeof (UINT64):
          StringPrint("// Minimum = %016llX \n", Question->Minimum);
          StringPrint("// Maximum = %016llX \n", Question->Maximum);
          StringPrint("// Step    = %016llX \n", Question->Step);
          break;

        default:
          StringPrint("0000 // Width > 16 is not supported -- FAILURE");
          break;
        }
      }
    }
    break;

  case EFI_IFR_ORDERED_LIST_OP:

    if( HaveUQIlanguage ) {
      Status = FindDefaultName (
                 &(FormSet->UqiStringList),
                 FormSet->UnicodeBinary, 
                 Question->Prompt, 
                 UQI, 
                 &VarDefaultName
                 );
      assert (!EFI_ERROR (Status));
      UqiStringLength = GetUqiNum (VarDefaultName);
      
      if (PrintOrNot) {
        if (UqiStringLength > 0) {
          StringPrint("\nQ %04X ", UqiStringLength);
          LogUqi(VarDefaultName);
        } else {
          StringPrint("\n// [No UQI] ");
        }
      }
    } else {
      Status = FindDefaultName (
                 &(FormSet->EnUsStringList),
                 FormSet->UnicodeBinary, 
                 Question->Prompt, 
                 EN_US, 
                 &VarDefaultName
                 );
      
      assert (!EFI_ERROR (Status));
    
      UqiStringLength = GetUqiNum (VarDefaultName);
      if (PrintOrNot) {
        if (UqiStringLength > 0) {
          StringPrint("\nQ %04X ", UqiStringLength);
          LogUqi(VarDefaultName);
        } else {
          StringPrint("\n// [No UQI] ");
        }
      }
    }
    //
    //Record the UQi to the HiiObjList
    //
    Question->Uqi.HexNum = UqiStringLength;
    Question->Uqi.Data   = VarDefaultName;
    Question->Uqi.Type   = ORDERED_LIST;

    if (PrintOrNot) {
      StringPrint("ORDERED_LIST %04X ", Question->MaxContainers);
    
      LogIfrValueList ( 
        FormSet,
        Question
        );
      StringPrint(" // ");
      Status = FindDefaultName (
                 &(FormSet->EnUsStringList),
                 FormSet->UnicodeBinary, 
                 Question->Prompt, 
                 EN_US, 
                 &VarDefaultName
                 );
      assert (!EFI_ERROR (Status));
      LogUnicodeString (VarDefaultName);
      StringPrint("\n");
    }
    //
    // Print ONE_OF_OPTION
    //
    PrintOneOfOptions (FormSet, Question);
    break;
    
  default:
    break;
  }

  if (&(FormSet->EnUsStringList) == NULL &&VarDefaultName != NULL && Question->Prompt != 0) {
    free (VarDefaultName);
    VarDefaultName = NULL;
  }

  if (PrintOrNot && Question->Storage) {
    StringPrint("// size = 0x%x", Question->StorageWidth);
    StringPrint("\n// offset = 0x%x", Question->VarStoreInfo.VarOffset);
    StringPrint("\n// name = ");
    LogUnicodeString(Question->VariableName);
    StringPrint("\n// guid = ");
    StringPrint(
      EFI_GUID_FORMAT,
      Question->Guid.Data1,   Question->Guid.Data2,
      Question->Guid.Data3,   Question->Guid.Data4[0],
      Question->Guid.Data4[1],Question->Guid.Data4[2],
      Question->Guid.Data4[3],Question->Guid.Data4[4],
      Question->Guid.Data4[5],Question->Guid.Data4[6],
      Question->Guid.Data4[7]
    );
    StringPrint("\n// attribute = 0x%x", Question->Attributes);
    StringPrint("\n// help = ");
    Status = FindDefaultName (
               &(FormSet->EnUsStringList),
               FormSet->UnicodeBinary, 
               Question->Help,  
               EN_US, 
               &VarDefaultName
               );
    assert (!EFI_ERROR (Status));
    LogUnicodeString (VarDefaultName);
    StringPrint("\n");
    if (&(FormSet->EnUsStringList) == NULL &&VarDefaultName != NULL && Question->Help != 0) {
      free (VarDefaultName);
      VarDefaultName = NULL;
    }
  }

}

/**
  Check whether current Formset or Form is NULL. If no valid questions, return FASLE.
  
  @param  FormSet     The pointer to the formset.
  @param  FormSet     The pointer to the form.
  @param  IsFormSet   FormSet or Form.

  @retval TRUE
  @return FALSE 
**/
BOOLEAN
CheckFormSetOrFormNull (
  IN  FORM_BROWSER_FORMSET    *FormSet,
  IN  FORM_BROWSER_FORM       *Form,
  IN  BOOLEAN                  IsFormSet
  )
{ 
  LIST_ENTRY              *FormLink;
  FORM_BROWSER_STATEMENT  *Question;
  LIST_ENTRY              *QuestionLink;
  
  FormLink     = NULL;
  Question     = NULL;
  QuestionLink = NULL;

  //
  // Parse all forms in formset
  //
  if (IsFormSet) {
    FormLink = GetFirstNode (&FormSet->FormListHead);
    
    while (!IsNull (&FormSet->FormListHead, FormLink)) {
      Form = FORM_BROWSER_FORM_FROM_LINK (FormLink);
      //
      // Parse five kinds of Questions in Form
      //
      QuestionLink = GetFirstNode (&Form->StatementListHead);
    
      while (!IsNull (&Form->StatementListHead, QuestionLink)) {
        Question = FORM_BROWSER_STATEMENT_FROM_LINK (QuestionLink);
        //
        // Parse five kinds of Questions in Form 
        //
        if ((Question->Operand == EFI_IFR_ONE_OF_OP) 
          || (Question->Operand == EFI_IFR_NUMERIC_OP) 
          || (Question->Operand == EFI_IFR_CHECKBOX_OP)
          || (Question->Operand == EFI_IFR_ORDERED_LIST_OP)
          || (Question->Operand == EFI_IFR_STRING_OP)
          ) {
          if (mMultiPlatformParam.MultiPlatformOrNot) {
            //
            // Only compare the valid EFI_IFR_VARSTORE_EFI_OP in multi-platform mode
            //
            if (Question->Type != EFI_IFR_VARSTORE_EFI_OP) {
              QuestionLink = GetNextNode (&Form->StatementListHead, QuestionLink);
              continue;
            }
            if (Question->Type == EFI_IFR_VARSTORE_EFI_OP
              && Question->NewEfiVarstore
              && ((Question->Attributes & EFI_VARIABLE_NON_VOLATILE) == 0)) {
              QuestionLink = GetNextNode (&Form->StatementListHead, QuestionLink);
              continue;
            }
          }
          //
          //If invalid variable type, skip it.
          //
           if ((Question->Type != EFI_IFR_VARSTORE_EFI_OP)
             && (Question->Type != EFI_IFR_VARSTORE_OP)) {
             QuestionLink = GetNextNode (&Form->StatementListHead, QuestionLink);
             continue;
          }
          return TRUE;
        }
        QuestionLink = GetNextNode (&Form->StatementListHead, QuestionLink);
      }
      
      FormLink = GetNextNode (&FormSet->FormListHead, FormLink);
    }
 } else {
   //
   // Parse five kinds of Questions in Form
   //
   QuestionLink = GetFirstNode (&Form->StatementListHead);
    
   while (!IsNull (&Form->StatementListHead, QuestionLink)) {
     Question = FORM_BROWSER_STATEMENT_FROM_LINK (QuestionLink);
     //
     // Parse five kinds of Questions in Form
     //
     if ((Question->Operand == EFI_IFR_ONE_OF_OP) 
       || (Question->Operand == EFI_IFR_NUMERIC_OP) 
       || (Question->Operand == EFI_IFR_CHECKBOX_OP)
       || (Question->Operand == EFI_IFR_ORDERED_LIST_OP)
       || (Question->Operand == EFI_IFR_STRING_OP)
       ) {
       if (mMultiPlatformParam.MultiPlatformOrNot) {
         //
         // Only compare the valid EFI_IFR_VARSTORE_EFI_OP in multi-platform mode
         //
         if (Question->Type != EFI_IFR_VARSTORE_EFI_OP) {
           QuestionLink = GetNextNode (&Form->StatementListHead, QuestionLink);
           continue;
         }
         if ((Question->Type == EFI_IFR_VARSTORE_EFI_OP)
           && Question->NewEfiVarstore
           && ((Question->Attributes & EFI_VARIABLE_NON_VOLATILE) == 0)) {
           QuestionLink = GetNextNode (&Form->StatementListHead, QuestionLink);
           continue;
         }
       }
       //
       //If invalid variable type, skip it.
       //
       if ((Question->Type != EFI_IFR_VARSTORE_EFI_OP)
         && (Question->Type != EFI_IFR_VARSTORE_OP)) {
         QuestionLink = GetNextNode (&Form->StatementListHead, QuestionLink);
         continue;
       }
       return TRUE;
     }
     QuestionLink = GetNextNode (&Form->StatementListHead, QuestionLink);
   }
 }
 return FALSE;
}

/**
  Print all ONE_OF ORDER_LIST NUMERIC STRING and CHECKBOX in all fromsets.

  @param Formset        The pointer to the entry of the fromset list
  @param Formset        The pointer to the entry of the storage list

  @retval EFI_SUCCESS   It was complete successfully
  @return EFI_ABORTED   An error occurred
**/
EFI_STATUS
PrintInfoInAllFormset (
  IN LIST_ENTRY      *FormSetEntryListHead,
  IN LIST_ENTRY      *StorageEntryListHead
  )
{
  EFI_STATUS              Status;
  FORM_BROWSER_FORMSET    *FormSet;
  LIST_ENTRY              *FormSetLink;
  LIST_ENTRY              *FormLink;
  FORM_BROWSER_FORM       *Form;
  FORM_BROWSER_STATEMENT  *Question;
  LIST_ENTRY              *QuestionLink;
  FORMSET_STORAGE         *Storage;
  CHAR8                   *VarBuffer;
  LIST_ENTRY              *TempStorageLink;
  UINT32                  Index;
  BOOLEAN                 Skip;
  BOOLEAN                 ConstantFlag;

  Status          = EFI_SUCCESS;
  FormSet         = NULL;
  FormSetLink     = NULL;
  FormLink        = NULL;
  Form            = NULL;
  Question        = NULL;
  QuestionLink    = NULL;
  Storage         = NULL;
  VarBuffer       = NULL;
  TempStorageLink = NULL;
  Index           = 0;
  Skip            = FALSE;
  ConstantFlag    = TRUE;
  //
  // Print platformId, defaultId and platformIdUqi
  //
  if (mMultiPlatformParam.MultiPlatformOrNot) {
    StringPrint("\n\n// FCEKEY DEFAULT_ID:");
    TempStorageLink = GetFirstNode (StorageEntryListHead);
    Storage = FORMSET_STORAGE_FROM_LINK (TempStorageLink);
    for (Index = 0; Index <= Storage->DefaultPlatformIdNum; Index++) {
      StringPrint (" %4d", Storage->DefaultId[Index]);  
    } 
    StringPrint("\n\n//FCEKEY PLATFORM_ID:");
    for (Index = 0; Index <= Storage->DefaultPlatformIdNum; Index++) {
      StringPrint (" %4lld", Storage->PlatformId[Index]);  
    }
    if (mMultiPlatformParam.Uqi.Data != NULL) {
      StringPrint("\n\n//FCEKEY PLATFORM_UQI:");
      StringPrint(" %04X ", mMultiPlatformParam.Uqi.HexNum);
      LogUqi(mMultiPlatformParam.Uqi.Data);
    }
  }      
  FormSetLink = GetFirstNode (FormSetEntryListHead);
  while (!IsNull (FormSetEntryListHead, FormSetLink)) {
    FormSet = FORM_BROWSER_FORMSET_FROM_LINK (FormSetLink);
    //
    //Assign the new storage list
    //
    FormSet->StorageListHead = StorageEntryListHead;

    if (CheckFormSetOrFormNull (FormSet, NULL, TRUE)) {
      StringPrintormSetTitle (FormSet);
    } else {
      FormSetLink = GetNextNode (FormSetEntryListHead, FormSetLink);
      continue;
    }
    //
    // Parse all forms in formset
    //
    FormLink = GetFirstNode (&FormSet->FormListHead);
      
    while (!IsNull (&FormSet->FormListHead, FormLink)) {
      Form = FORM_BROWSER_FORM_FROM_LINK (FormLink);
      
      if (CheckFormSetOrFormNull (NULL, Form, FALSE)) {
        StringPrintormTitle(FormSet,Form);
      } else {
        FormLink = GetNextNode (&FormSet->FormListHead, FormLink);
        continue;
      }
      //
      // Parse five kinds of Questions in Form
      //
      QuestionLink = GetFirstNode (&Form->StatementListHead);
      
      while (!IsNull (&Form->StatementListHead, QuestionLink)) {
        Question = FORM_BROWSER_STATEMENT_FROM_LINK (QuestionLink);
        //
        // Parse five kinds of Questions in Form
        //
        if ((Question->Operand == EFI_IFR_ONE_OF_OP) 
          || (Question->Operand == EFI_IFR_NUMERIC_OP) 
          || (Question->Operand == EFI_IFR_CHECKBOX_OP)
          || (Question->Operand == EFI_IFR_ORDERED_LIST_OP) 
          || (Question->Operand == EFI_IFR_SUBTITLE_OP)
          || (Question->Operand == EFI_IFR_STRING_OP)
          ) {
          Skip = FALSE;
  
          //
          //Only output the questions stored by EFI_IFR_VARSTORE_EFI_OP.
          //
          if (mMultiPlatformParam.MultiPlatformOrNot 
            && (Question->Operand != EFI_IFR_SUBTITLE_OP)
            ) {
            Status = SearchVarStorage (
                       Question, 
                       NULL, 
                       Question->VarStoreInfo.VarOffset,            
                       StorageEntryListHead,
                       (CHAR8 **)&VarBuffer,
                       &Storage
                     );
               
            if (EFI_ERROR (Status)) {
              Skip = TRUE;
            }
          }
          //
          // If Question is constant expression and "disabledIf True", don't output it.
          //
          ConstantFlag    = TRUE;
          if (!Skip && (Question->DisableExpression != NULL)) {
            Status = EvaluateExpression (FormSet, Form, Question->DisableExpression, &ConstantFlag);
            if (!EFI_ERROR (Status) && Question->DisableExpression->Result.Value.b && ConstantFlag) {
              Skip = TRUE;
            }
          }
          //
          // If Question is constant expression and "disabledIf True", don't output it.
          //
          ConstantFlag    = TRUE;
          if (!Skip && (Question->SuppressExpression != NULL)) {
            Status = EvaluateExpression (FormSet, Form, Question->SuppressExpression, &ConstantFlag);
            if (!EFI_ERROR (Status) && Question->SuppressExpression->Result.Value.b && ConstantFlag) {
              Skip = TRUE;
            }
          }
          
          if (!Skip) {
            PrintQuestion(FormSet, Form, Question, TRUE);
          }
        }
        QuestionLink = GetNextNode (&Form->StatementListHead, QuestionLink);
      }
       
      FormLink = GetNextNode (&FormSet->FormListHead, FormLink);
    }
    FormSetLink = GetNextNode (FormSetEntryListHead, FormSetLink);
  }

  return EFI_SUCCESS;
}

