]> git.proxmox.com Git - mirror_edk2.git/blobdiff - MdeModulePkg/Universal/SetupBrowserDxe/ProcessOptions.c
1. Support inconsistent if opcode used in string/password opcode.
[mirror_edk2.git] / MdeModulePkg / Universal / SetupBrowserDxe / ProcessOptions.c
index ac9eeda777e81c6bb2ead0bbde5c197b974027cd..e654545bf73e84d28c26eb000d495447122c866d 100644 (file)
-/** @file
-
-Copyright (c) 2004 - 2007, Intel Corporation
-All rights reserved. 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.
-
-Module Name:
-
-  ProcessOptions.c
-
-Abstract:
-
-  Implementation for handling the User Interface option processing.
-
-Revision History
-
-
-**/
-
-#include "Ui.h"
-#include "Setup.h"
-
-
-/**
-  Process Question Config.
-
-  @param  Selection              The UI menu selection.
-  @param  Question               The Question to be peocessed.
-
-  @retval EFI_SUCCESS            Question Config process success.
-  @retval Other                  Question Config process fail.
-
-**/
-EFI_STATUS
-ProcessQuestionConfig (
-  IN  UI_MENU_SELECTION       *Selection,
-  IN  FORM_BROWSER_STATEMENT  *Question
-  )
-{
-  EFI_STATUS                      Status;
-  CHAR16                          *ConfigResp;
-  CHAR16                          *Progress;
-  EFI_HII_CONFIG_ACCESS_PROTOCOL  *ConfigAccess;
-
-  if (Question->QuestionConfig == 0) {
-    return EFI_SUCCESS;
-  }
-
-  //
-  // Get <ConfigResp>
-  //
-  ConfigResp = GetToken (Question->QuestionConfig, Selection->FormSet->HiiHandle);
-  if (ConfigResp == NULL) {
-    return EFI_NOT_FOUND;
-  }
-
-  //
-  // Send config to Configuration Driver
-  //
-  ConfigAccess = Selection->FormSet->ConfigAccess;
-  if (ConfigAccess == NULL) {
-    return EFI_UNSUPPORTED;
-  }
-  Status = ConfigAccess->RouteConfig (
-                           ConfigAccess,
-                           ConfigResp,
-                           &Progress
-                           );
-
-  return Status;
-}
-
-
-/**
-  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_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, NULL) == 0) {
-      return Option;
-    }
-
-    Link = GetNextNode (&Question->OptionListHead, Link);
-  }
-
-  return NULL;
-}
-
-
-/**
-  Print Question Value according to it's storage width and display attributes.
-
-  @param  Event                  The event to wait for
-  @param  FormattedNumber        Buffer for output string.
-  @param  BufferSize             The FormattedNumber buffer size in bytes.
-
-  @retval EFI_SUCCESS            Print success.
-  @retval EFI_BUFFER_TOO_SMALL   Buffer size is not enough for formatted number.
-
-**/
-EFI_STATUS
-PrintFormattedNumber (
-  IN FORM_BROWSER_STATEMENT   *Question,
-  IN OUT CHAR16               *FormattedNumber,
-  IN UINTN                    BufferSize
-  )
-{
-  INT64          Value;
-  CHAR16         *Format;
-  EFI_HII_VALUE  *QuestionValue;
-
-  if (BufferSize < (21 * sizeof (CHAR16))) {
-    return EFI_BUFFER_TOO_SMALL;
-  }
-
-  QuestionValue = &Question->HiiValue;
-
-  Value = (INT64) QuestionValue->Value.u64;
-  switch (Question->Flags & EFI_IFR_DISPLAY) {
-  case EFI_IFR_DISPLAY_INT_DEC:
-    switch (QuestionValue->Type) {
-    case EFI_IFR_NUMERIC_SIZE_1:
-      Value = (INT64) ((INT8) QuestionValue->Value.u8);
-      break;
-
-    case EFI_IFR_NUMERIC_SIZE_2:
-      Value = (INT64) ((INT16) QuestionValue->Value.u16);
-      break;
-
-    case EFI_IFR_NUMERIC_SIZE_4:
-      Value = (INT64) ((INT32) QuestionValue->Value.u32);
-      break;
-
-    case EFI_IFR_NUMERIC_SIZE_8:
-    default:
-      break;
-    }
-
-    if (Value < 0) {
-      Value = -Value;
-      Format = L"-%ld";
-    } else {
-      Format = L"%ld";
-    }
-    break;
-
-  case EFI_IFR_DISPLAY_UINT_DEC:
-    Format = L"%ld";
-    break;
-
-  case EFI_IFR_DISPLAY_UINT_HEX:
-    Format = L"%lx";
-    break;
-
-  default:
-    return EFI_UNSUPPORTED;
-    break;
-  }
-
-  UnicodeSPrint (FormattedNumber, BufferSize, Format, Value);
-
-  return EFI_SUCCESS;
-}
-
-
-/**
-  Password may be stored as encrypted by Configuration Driver. When change a
-  password, user will be challenged with old password. To validate user input old
-  password, we will send the clear text to Configuration Driver via Callback().
-  Configuration driver is responsible to check the passed in password and return
-  the validation result. If validation pass, state machine in password Callback()
-  will transit from BROWSER_STATE_VALIDATE_PASSWORD to BROWSER_STATE_SET_PASSWORD.
-  After user type in new password twice, Callback() will be invoked to send the
-  new password to Configuration Driver.
-
-  @param  Selection              Pointer to UI_MENU_SELECTION.
-  @param  MenuOption             The MenuOption for this password Question.
-  @param  String                 The clear text of password.
-
-  @retval EFI_NOT_AVAILABLE_YET  Callback() request to terminate password input.
-  @return In state of BROWSER_STATE_VALIDATE_PASSWORD:
-  @retval EFI_SUCCESS            Password correct, Browser will prompt for new
-                                 password.
-  @retval EFI_NOT_READY          Password incorrect, Browser will show error
-                                 message.
-  @retval Other                  Browser will do nothing.
-  @return In state of BROWSER_STATE_SET_PASSWORD:
-  @retval EFI_SUCCESS            Set password success.
-  @retval Other                  Set password failed.
-
-**/
-EFI_STATUS
-PasswordCallback (
-  IN  UI_MENU_SELECTION           *Selection,
-  IN  UI_MENU_OPTION              *MenuOption,
-  IN  CHAR16                      *String
-  )
-{
-  EFI_STATUS                      Status;
-  EFI_HII_CONFIG_ACCESS_PROTOCOL  *ConfigAccess;
-  EFI_BROWSER_ACTION_REQUEST      ActionRequest;
-  EFI_HII_VALUE                   *QuestionValue;
-
-  QuestionValue = &MenuOption->ThisTag->HiiValue;
-  ConfigAccess = Selection->FormSet->ConfigAccess;
-  if (ConfigAccess == NULL) {
-    return EFI_UNSUPPORTED;
-  }
-
-  //
-  // Prepare password string in HII database
-  //
-  if (String != NULL) {
-    QuestionValue->Value.string = NewString (String, Selection->FormSet->HiiHandle);
-  } else {
-    QuestionValue->Value.string = 0;
-  }
-
-  //
-  // Send password to Configuration Driver for validation
-  //
-  Status = ConfigAccess->Callback (
-                           ConfigAccess,
-                           EFI_BROWSER_ACTION_CHANGING,
-                           MenuOption->ThisTag->QuestionId,
-                           QuestionValue->Type,
-                           &QuestionValue->Value,
-                           &ActionRequest
-                           );
-
-  //
-  // Remove password string from HII database
-  //
-  if (String != NULL) {
-    DeleteString (QuestionValue->Value.string, Selection->FormSet->HiiHandle);
-  }
-
-  return Status;
-}
-
-
-/**
-  Display error message for invalid password.
-
-  None.
-
-  @return None.
-
-**/
-VOID
-PasswordInvalid (
-  VOID
-  )
-{
-  EFI_INPUT_KEY  Key;
-
-  //
-  // Invalid password, prompt error message
-  //
-  do {
-    CreateDialog (4, TRUE, 0, NULL, &Key, gEmptyString, gPassowordInvalid, gPressEnter, gEmptyString);
-  } while (Key.UnicodeChar != CHAR_CARRIAGE_RETURN);
-}
-
-
-/**
-  Process a Question's Option (whether selected or un-selected).
-
-  @param  Selection              Pointer to UI_MENU_SELECTION.
-  @param  MenuOption             The MenuOption for this Question.
-  @param  Selected               TRUE: if Question is selected.
-  @param  OptionString           Pointer of the Option String to be displayed.
-
-  @retval EFI_SUCCESS            Question Option process success.
-  @retval Other                  Question Option process fail.
-
-**/
-EFI_STATUS
-ProcessOptions (
-  IN  UI_MENU_SELECTION           *Selection,
-  IN  UI_MENU_OPTION              *MenuOption,
-  IN  BOOLEAN                     Selected,
-  OUT CHAR16                      **OptionString
-  )
-{
-  EFI_STATUS                      Status;
-  CHAR16                          *StringPtr;
-  CHAR16                          *TempString;
-  UINTN                           Index;
-  FORM_BROWSER_STATEMENT          *Question;
-  CHAR16                          FormattedNumber[21];
-  UINT16                          Number;
-  CHAR16                          Character[2];
-  EFI_INPUT_KEY                   Key;
-  UINTN                           BufferSize;
-  QUESTION_OPTION                 *OneOfOption;
-  LIST_ENTRY                      *Link;
-  EFI_HII_VALUE                   HiiValue;
-  EFI_HII_VALUE                   *QuestionValue;
-  BOOLEAN                         Suppress;
-  UINT16                          Maximum;
-
-  Status        = EFI_SUCCESS;
-
-  StringPtr     = NULL;
-  Character[1]  = L'\0';
-  *OptionString = NULL;
-
-  ZeroMem (FormattedNumber, 21 * sizeof (CHAR16));
-  BufferSize = (gOptionBlockWidth + 1) * 2 * gScreenDimensions.BottomRow;
-
-  Question = MenuOption->ThisTag;
-  QuestionValue = &Question->HiiValue;
-  Maximum = (UINT16) Question->Maximum;
-
-  switch (Question->Operand) {
-  case EFI_IFR_ORDERED_LIST_OP:
-    //
-    // Initialize Option value array
-    //
-    if (Question->BufferValue[0] == 0) {
-      GetQuestionDefault (Selection->FormSet, Selection->Form, Question, 0);
-    }
-
-    if (Selected) {
-      //
-      // Go ask for input
-      //
-      Status = GetSelectionInputPopUp (Selection, MenuOption);
-    } else {
-      //
-      // We now know how many strings we will have, so we can allocate the
-      // space required for the array or strings.
-      //
-      *OptionString = AllocateZeroPool (Question->MaxContainers * BufferSize);
-      ASSERT (*OptionString);
-
-      HiiValue.Type = EFI_IFR_TYPE_NUM_SIZE_8;
-      HiiValue.Value.u64 = 0;
-      for (Index = 0; Index < Question->MaxContainers; Index++) {
-        HiiValue.Value.u8 = Question->BufferValue[Index];
-        if (HiiValue.Value.u8 == 0) {
-          //
-          // Values for the options in ordered lists should never be a 0
-          //
-          break;
-        }
-
-        OneOfOption = ValueToOption (Question, &HiiValue);
-        if (OneOfOption == NULL) {
-          gBS->FreePool (*OptionString);
-          return EFI_NOT_FOUND;
-        }
-
-        Suppress = FALSE;
-        if ((OneOfOption->SuppressExpression != NULL) &&
-            (OneOfOption->SuppressExpression->Result.Value.b)) {
-          //
-          // This option is suppressed
-          //
-          Suppress = TRUE;
-        }
-
-        if (!Suppress) {
-          Character[0] = LEFT_ONEOF_DELIMITER;
-          NewStrCat (OptionString[0], Character);
-          StringPtr = GetToken (OneOfOption->Text, Selection->Handle);
-          NewStrCat (OptionString[0], StringPtr);
-          Character[0] = RIGHT_ONEOF_DELIMITER;
-          NewStrCat (OptionString[0], Character);
-          Character[0] = CHAR_CARRIAGE_RETURN;
-          NewStrCat (OptionString[0], Character);
-
-          gBS->FreePool (StringPtr);
-        }
-      }
-    }
-    break;
-
-  case EFI_IFR_ONE_OF_OP:
-    if (Selected) {
-      //
-      // Go ask for input
-      //
-      Status = GetSelectionInputPopUp (Selection, MenuOption);
-    } else {
-      *OptionString = AllocateZeroPool (BufferSize);
-      ASSERT (*OptionString);
-
-      OneOfOption = ValueToOption (Question, QuestionValue);
-      if (OneOfOption == NULL) {
-        gBS->FreePool (*OptionString);
-        return EFI_NOT_FOUND;
-      }
-
-      if ((OneOfOption->SuppressExpression != NULL) &&
-          (OneOfOption->SuppressExpression->Result.Value.b)) {
-        //
-        // This option is suppressed
-        //
-        Suppress = TRUE;
-      } else {
-        Suppress = FALSE;
-      }
-
-      if (Suppress) {
-        //
-        // Current selected option happen to be suppressed,
-        // enforce to select on a non-suppressed option
-        //
-        Link = GetFirstNode (&Question->OptionListHead);
-        while (!IsNull (&Question->OptionListHead, Link)) {
-          OneOfOption = QUESTION_OPTION_FROM_LINK (Link);
-
-          if ((OneOfOption->SuppressExpression == NULL) ||
-              !OneOfOption->SuppressExpression->Result.Value.b) {
-            Suppress = FALSE;
-            CopyMem (QuestionValue, &OneOfOption->Value, sizeof (EFI_HII_VALUE));
-            SetQuestionValue (Selection->FormSet, Selection->Form, Question, TRUE);
-            break;
-          }
-
-          Link = GetNextNode (&Question->OptionListHead, Link);
-        }
-      }
-
-      if (!Suppress) {
-        Character[0] = LEFT_ONEOF_DELIMITER;
-        NewStrCat (OptionString[0], Character);
-        StringPtr = GetToken (OneOfOption->Text, Selection->Handle);
-        NewStrCat (OptionString[0], StringPtr);
-        Character[0] = RIGHT_ONEOF_DELIMITER;
-        NewStrCat (OptionString[0], Character);
-
-        gBS->FreePool (StringPtr);
-      }
-    }
-    break;
-
-  case EFI_IFR_CHECKBOX_OP:
-    *OptionString = AllocateZeroPool (BufferSize);
-    ASSERT (*OptionString);
-
-    *OptionString[0] = LEFT_CHECKBOX_DELIMITER;
-
-    if (Selected) {
-      //
-      // Since this is a BOOLEAN operation, flip it upon selection
-      //
-      QuestionValue->Value.b = (BOOLEAN) (QuestionValue->Value.b ? FALSE : TRUE);
-
-      //
-      // Perform inconsistent check
-      //
-      Status = ValidateQuestion (Selection->FormSet, Selection->Form, Question, EFI_HII_EXPRESSION_INCONSISTENT_IF);
-      if (EFI_ERROR (Status)) {
-        //
-        // Inconsistent check fail, restore Question Value
-        //
-        QuestionValue->Value.b = (BOOLEAN) (QuestionValue->Value.b ? FALSE : TRUE);
-        gBS->FreePool (*OptionString);
-        return Status;
-      }
-
-      //
-      // Save Question value
-      //
-      Status = SetQuestionValue (Selection->FormSet, Selection->Form, Question, TRUE);
-      UpdateStatusBar (NV_UPDATE_REQUIRED, Question->QuestionFlags, TRUE);
-    }
-
-    if (QuestionValue->Value.b) {
-      *(OptionString[0] + 1) = CHECK_ON;
-    } else {
-      *(OptionString[0] + 1) = CHECK_OFF;
-    }
-    *(OptionString[0] + 2) = RIGHT_CHECKBOX_DELIMITER;
-    break;
-
-  case EFI_IFR_NUMERIC_OP:
-    if (Selected) {
-      //
-      // Go ask for input
-      //
-      Status = GetNumericInput (Selection, MenuOption);
-    } else {
-      *OptionString = AllocateZeroPool (BufferSize);
-      ASSERT (*OptionString);
-
-      *OptionString[0] = LEFT_NUMERIC_DELIMITER;
-
-      //
-      // Formatted print
-      //
-      PrintFormattedNumber (Question, FormattedNumber, 21 * sizeof (CHAR16));
-      Number = (UINT16) GetStringWidth (FormattedNumber);
-      CopyMem (OptionString[0] + 1, FormattedNumber, Number);
-
-      *(OptionString[0] + Number / 2) = RIGHT_NUMERIC_DELIMITER;
-    }
-    break;
-
-  case EFI_IFR_DATE_OP:
-    if (Selected) {
-      //
-      // This is similar to numerics
-      //
-      Status = GetNumericInput (Selection, MenuOption);
-    } else {
-      *OptionString = AllocateZeroPool (BufferSize);
-      ASSERT (*OptionString);
-
-      switch (MenuOption->Sequence) {
-      case 0:
-        *OptionString[0] = LEFT_NUMERIC_DELIMITER;
-        UnicodeSPrint (OptionString[0] + 1, 21 * sizeof (CHAR16), L"%02d", QuestionValue->Value.date.Month);
-        *(OptionString[0] + 3) = DATE_SEPARATOR;
-        break;
-
-      case 1:
-        SetUnicodeMem (OptionString[0], 4, L' ');
-        UnicodeSPrint (OptionString[0] + 4, 21 * sizeof (CHAR16), L"%02d", QuestionValue->Value.date.Day);
-        *(OptionString[0] + 6) = DATE_SEPARATOR;
-        break;
-
-      case 2:
-        SetUnicodeMem (OptionString[0], 7, L' ');
-        UnicodeSPrint (OptionString[0] + 7, 21 * sizeof (CHAR16), L"%4d", QuestionValue->Value.date.Year);
-        *(OptionString[0] + 11) = RIGHT_NUMERIC_DELIMITER;
-        break;
-      }
-    }
-    break;
-
-  case EFI_IFR_TIME_OP:
-    if (Selected) {
-      //
-      // This is similar to numerics
-      //
-      Status = GetNumericInput (Selection, MenuOption);
-    } else {
-      *OptionString = AllocateZeroPool (BufferSize);
-      ASSERT (*OptionString);
-
-      switch (MenuOption->Sequence) {
-      case 0:
-        *OptionString[0] = LEFT_NUMERIC_DELIMITER;
-        UnicodeSPrint (OptionString[0] + 1, 21 * sizeof (CHAR16), L"%02d", QuestionValue->Value.time.Hour);
-        *(OptionString[0] + 3) = TIME_SEPARATOR;
-        break;
-
-      case 1:
-        SetUnicodeMem (OptionString[0], 4, L' ');
-        UnicodeSPrint (OptionString[0] + 4, 21 * sizeof (CHAR16), L"%02d", QuestionValue->Value.time.Minute);
-        *(OptionString[0] + 6) = TIME_SEPARATOR;
-        break;
-
-      case 2:
-        SetUnicodeMem (OptionString[0], 7, L' ');
-        UnicodeSPrint (OptionString[0] + 7, 21 * sizeof (CHAR16), L"%02d", QuestionValue->Value.time.Second);
-        *(OptionString[0] + 9) = RIGHT_NUMERIC_DELIMITER;
-        break;
-      }
-    }
-    break;
-
-  case EFI_IFR_STRING_OP:
-    if (Selected) {
-      StringPtr = AllocateZeroPool ((Maximum + 1) * sizeof (CHAR16));
-      ASSERT (StringPtr);
-
-      Status = ReadString (MenuOption, gPromptForData, StringPtr);
-      if (!EFI_ERROR (Status)) {
-        CopyMem (Question->BufferValue, StringPtr, Maximum * sizeof (CHAR16));
-        SetQuestionValue (Selection->FormSet, Selection->Form, Question, TRUE);
-
-        UpdateStatusBar (NV_UPDATE_REQUIRED, Question->QuestionFlags, TRUE);
-      }
-
-      gBS->FreePool (StringPtr);
-    } else {
-      *OptionString = AllocateZeroPool (BufferSize);
-      ASSERT (*OptionString);
-
-      if (((CHAR16 *) Question->BufferValue)[0] == 0x0000) {
-        *(OptionString[0]) = '_';
-      } else {
-        if ((Maximum * sizeof (CHAR16)) < BufferSize) {
-          BufferSize = Maximum * sizeof (CHAR16);
-        }
-        CopyMem (OptionString[0], (CHAR16 *) Question->BufferValue, BufferSize);
-      }
-    }
-    break;
-
-  case EFI_IFR_PASSWORD_OP:
-    if (Selected) {
-      StringPtr = AllocateZeroPool ((Maximum + 1) * sizeof (CHAR16));
-      ASSERT (StringPtr);
-
-      //
-      // For interactive passwords, old password is validated by callback
-      //
-      if (Question->QuestionFlags & EFI_IFR_FLAG_CALLBACK) {
-        //
-        // Use a NULL password to test whether old password is required
-        //
-        *StringPtr = 0;
-        Status = PasswordCallback (Selection, MenuOption, StringPtr);
-        if (Status == EFI_NOT_AVAILABLE_YET) {
-          //
-          // Callback request to terminate password input
-          //
-          gBS->FreePool (StringPtr);
-          return EFI_SUCCESS;
-        }
-
-        if (EFI_ERROR (Status)) {
-          //
-          // Old password exist, ask user for the old password
-          //
-          Status = ReadString (MenuOption, gPromptForPassword, StringPtr);
-          if (EFI_ERROR (Status)) {
-            gBS->FreePool (StringPtr);
-            return Status;
-          }
-
-          //
-          // Check user input old password
-          //
-          Status = PasswordCallback (Selection, MenuOption, StringPtr);
-          if (EFI_ERROR (Status)) {
-            if (Status == EFI_NOT_READY) {
-              //
-              // Typed in old password incorrect
-              //
-              PasswordInvalid ();
-            } else {
-              Status = EFI_SUCCESS;
-            }
-
-            gBS->FreePool (StringPtr);
-            return Status;
-          }
-        }
-      } else {
-        //
-        // For non-interactive password, validate old password in local
-        //
-        if (*((CHAR16 *) Question->BufferValue) != 0) {
-          //
-          // There is something there!  Prompt for password
-          //
-          Status = ReadString (MenuOption, gPromptForPassword, StringPtr);
-          if (EFI_ERROR (Status)) {
-            gBS->FreePool (StringPtr);
-            return Status;
-          }
-
-          TempString = AllocateCopyPool ((Maximum + 1) * sizeof (CHAR16), Question->BufferValue);
-          TempString[Maximum] = L'\0';
-
-          if (StrCmp (StringPtr, TempString) != 0) {
-            //
-            // Typed in old password incorrect
-            //
-            PasswordInvalid ();
-
-            gBS->FreePool (StringPtr);
-            gBS->FreePool (TempString);
-            return Status;
-          }
-
-          gBS->FreePool (TempString);
-        }
-      }
-
-      //
-      // Ask for new password
-      //
-      ZeroMem (StringPtr, (Maximum + 1) * sizeof (CHAR16));
-      Status = ReadString (MenuOption, gPromptForNewPassword, StringPtr);
-      if (EFI_ERROR (Status)) {
-        //
-        // Reset state machine for interactive password
-        //
-        if (Question->QuestionFlags & EFI_IFR_FLAG_CALLBACK) {
-          PasswordCallback (Selection, MenuOption, NULL);
-        }
-
-        gBS->FreePool (StringPtr);
-        return Status;
-      }
-
-      //
-      // Confirm new password
-      //
-      TempString = AllocateZeroPool ((Maximum + 1) * sizeof (CHAR16));
-      ASSERT (TempString);
-      Status = ReadString (MenuOption, gConfirmPassword, TempString);
-      if (EFI_ERROR (Status)) {
-        //
-        // Reset state machine for interactive password
-        //
-        if (Question->QuestionFlags & EFI_IFR_FLAG_CALLBACK) {
-          PasswordCallback (Selection, MenuOption, NULL);
-        }
-
-        gBS->FreePool (StringPtr);
-        gBS->FreePool (TempString);
-        return Status;
-      }
-
-      //
-      // Compare two typed-in new passwords
-      //
-      if (StrCmp (StringPtr, TempString) == 0) {
-        //
-        // Two password match, send it to Configuration Driver
-        //
-        if (Question->QuestionFlags & EFI_IFR_FLAG_CALLBACK) {
-          PasswordCallback (Selection, MenuOption, StringPtr);
-        } else {
-          CopyMem (Question->BufferValue, StringPtr, Maximum * sizeof (CHAR16));
-          SetQuestionValue (Selection->FormSet, Selection->Form, Question, FALSE);
-        }
-      } else {
-        //
-        // Reset state machine for interactive password
-        //
-        if (Question->QuestionFlags & EFI_IFR_FLAG_CALLBACK) {
-          PasswordCallback (Selection, MenuOption, NULL);
-        }
-
-        //
-        // Two password mismatch, prompt error message
-        //
-        do {
-          CreateDialog (4, TRUE, 0, NULL, &Key, gEmptyString, gConfirmError, gPressEnter, gEmptyString);
-        } while (Key.UnicodeChar != CHAR_CARRIAGE_RETURN);
-      }
-
-      gBS->FreePool (TempString);
-      gBS->FreePool (StringPtr);
-    }
-    break;
-
-  default:
-    break;
-  }
-
-  return Status;
-}
-
-
-/**
-  Process the help string: Split StringPtr to several lines of strings stored in
-  FormattedString and the glyph width of each line cannot exceed gHelpBlockWidth.
-
-  @param  StringPtr              The entire help string.
-  @param  MenuOption             The MenuOption for this Question.
-  @param  RowCount               TRUE: if Question is selected.
-  @param  OptionString           Pointer of the Option String to be displayed.
-
-  @return None.
-
-**/
-VOID
-ProcessHelpString (
-  IN  CHAR16  *StringPtr,
-  OUT CHAR16  **FormattedString,
-  IN  UINTN   RowCount
-  )
-{
-  CONST UINTN BlockWidth = (UINTN) gHelpBlockWidth - 1;
-  UINTN AllocateSize;
-  //
-  // [PrevCurrIndex, CurrIndex) forms a range of a screen-line
-  //
-  UINTN CurrIndex;
-  UINTN PrevCurrIndex;
-  UINTN LineCount;
-  UINTN VirtualLineCount;
-  //
-  // GlyphOffset stores glyph width of current screen-line
-  //
-  UINTN GlyphOffset;
-  //
-  // GlyphWidth equals to 2 if we meet width directive
-  //
-  UINTN GlyphWidth;
-  //
-  // during scanning, we remember the position of last space character
-  // in case that if next word cannot put in current line, we could restore back to the position
-  // of last space character
-  // while we should also remmeber the glyph width of the last space character for restoring
-  //
-  UINTN LastSpaceIndex;
-  UINTN LastSpaceGlyphWidth;
-  //
-  // every time we begin to form a new screen-line, we should remember glyph width of single character
-  // of last line
-  //
-  UINTN LineStartGlyphWidth;
-  UINTN *IndexArray;
-  UINTN *OldIndexArray;
-
-  //
-  // every three elements of IndexArray form a screen-line of string:[ IndexArray[i*3], IndexArray[i*3+1] )
-  // IndexArray[i*3+2] stores the initial glyph width of single character. to save this is because we want
-  // to bring the width directive of the last line to current screen-line.
-  // e.g.: "\wideabcde ... fghi", if "fghi" also has width directive but is splitted to the next screen-line
-  // different from that of "\wideabcde", we should remember the width directive.
-  //
-  AllocateSize  = 0x20;
-  IndexArray    = AllocatePool (AllocateSize * sizeof (UINTN) * 3);
-
-  if (*FormattedString != NULL) {
-    gBS->FreePool (*FormattedString);
-    *FormattedString = NULL;
-  }
-
-  for (PrevCurrIndex = 0, CurrIndex  = 0, LineCount   = 0, LastSpaceIndex = 0,
-       IndexArray[0] = 0, GlyphWidth = 1, GlyphOffset = 0, LastSpaceGlyphWidth = 1, LineStartGlyphWidth = 1;
-       (StringPtr[CurrIndex] != CHAR_NULL);
-       CurrIndex ++) {
-
-    if (LineCount == AllocateSize) {
-      AllocateSize += 0x10;
-      OldIndexArray  = IndexArray;
-      IndexArray = AllocatePool (AllocateSize * sizeof (UINTN) * 3);
-      CopyMem (IndexArray, OldIndexArray, LineCount * sizeof (UINTN) * 3);
-      gBS->FreePool (OldIndexArray);
-    }
-    switch (StringPtr[CurrIndex]) {
-
-      case NARROW_CHAR:
-      case WIDE_CHAR:
-        GlyphWidth = ((StringPtr[CurrIndex] == WIDE_CHAR) ? 2 : 1);
-        if (CurrIndex == 0) {
-          LineStartGlyphWidth = GlyphWidth;
-        }
-        break;
-
-      //
-      // char is '\n'
-      // "\r\n" isn't handled here, handled by case CHAR_CARRIAGE_RETURN
-      //
-      case CHAR_LINEFEED:
-        //
-        // Store a range of string as a line
-        //
-        IndexArray[LineCount*3]   = PrevCurrIndex;
-        IndexArray[LineCount*3+1] = CurrIndex;
-        IndexArray[LineCount*3+2] = LineStartGlyphWidth;
-        LineCount ++;
-        //
-        // Reset offset and save begin position of line
-        //
-        GlyphOffset = 0;
-        LineStartGlyphWidth = GlyphWidth;
-        PrevCurrIndex = CurrIndex + 1;
-        break;
-
-      //
-      // char is '\r'
-      // "\r\n" and "\r" both are handled here
-      //
-      case CHAR_CARRIAGE_RETURN:
-        if (StringPtr[CurrIndex + 1] == CHAR_LINEFEED) {
-          //
-          // next char is '\n'
-          //
-          IndexArray[LineCount*3]   = PrevCurrIndex;
-          IndexArray[LineCount*3+1] = CurrIndex;
-          IndexArray[LineCount*3+2] = LineStartGlyphWidth;
-          LineCount ++;
-          CurrIndex ++;
-        }
-        GlyphOffset = 0;
-        LineStartGlyphWidth = GlyphWidth;
-        PrevCurrIndex = CurrIndex + 1;
-        break;
-
-      //
-      // char is space or other char
-      //
-      default:
-        GlyphOffset     += GlyphWidth;
-        if (GlyphOffset >= BlockWidth) {
-          if (LastSpaceIndex > PrevCurrIndex) {
-            //
-            // LastSpaceIndex points to space inside current screen-line,
-            // restore to LastSpaceIndex
-            // (Otherwise the word is too long to fit one screen-line, just cut it)
-            //
-            CurrIndex  = LastSpaceIndex;
-            GlyphWidth = LastSpaceGlyphWidth;
-          } else if (GlyphOffset > BlockWidth) {
-            //
-            // the word is too long to fit one screen-line and we don't get the chance
-            // of GlyphOffset == BlockWidth because GlyphWidth = 2
-            //
-            CurrIndex --;
-          }
-
-          IndexArray[LineCount*3]   = PrevCurrIndex;
-          IndexArray[LineCount*3+1] = CurrIndex + 1;
-          IndexArray[LineCount*3+2] = LineStartGlyphWidth;
-          LineStartGlyphWidth = GlyphWidth;
-          LineCount ++;
-          //
-          // Reset offset and save begin position of line
-          //
-          GlyphOffset                 = 0;
-          PrevCurrIndex               = CurrIndex + 1;
-        }
-
-        //
-        // LastSpaceIndex: remember position of last space
-        //
-        if (StringPtr[CurrIndex] == CHAR_SPACE) {
-          LastSpaceIndex      = CurrIndex;
-          LastSpaceGlyphWidth = GlyphWidth;
-        }
-        break;
-    }
-  }
-
-  if (GlyphOffset > 0) {
-    IndexArray[LineCount*3]   = PrevCurrIndex;
-    IndexArray[LineCount*3+1] = CurrIndex;
-    IndexArray[LineCount*3+2] = GlyphWidth;
-    LineCount ++;
-  }
-
-  if (LineCount == 0) {
-    //
-    // in case we meet null string
-    //
-    IndexArray[0] = 0;
-    IndexArray[1] = 1;
-    //
-    // we assume null string's glyph width is 1
-    //
-    IndexArray[1] = 1;
-    LineCount ++;
-  }
-
-  VirtualLineCount = RowCount * (LineCount / RowCount + (LineCount % RowCount > 0));
-  *FormattedString = AllocateZeroPool (VirtualLineCount * (BlockWidth + 1) * sizeof (CHAR16) * 2);
-
-  for (CurrIndex = 0; CurrIndex < LineCount; CurrIndex ++) {
-    *(*FormattedString + CurrIndex * 2 * (BlockWidth + 1)) = (CHAR16) ((IndexArray[CurrIndex*3+2] == 2) ? WIDE_CHAR : NARROW_CHAR);
-    StrnCpy (
-      *FormattedString + CurrIndex * 2 * (BlockWidth + 1) + 1,
-      StringPtr + IndexArray[CurrIndex*3],
-      IndexArray[CurrIndex*3+1]-IndexArray[CurrIndex*3]
-      );
-  }
-
-  gBS->FreePool (IndexArray);
-}
+/** @file\r
+Implementation for handling the User Interface option processing.\r
+\r
+\r
+Copyright (c) 2004 - 2010, Intel Corporation. All rights reserved.<BR>\r
+This program and the accompanying materials\r
+are licensed and made available under the terms and conditions of the BSD License\r
+which accompanies this distribution.  The full text of the license may be found at\r
+http://opensource.org/licenses/bsd-license.php\r
+\r
+THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,\r
+WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.\r
+\r
+**/\r
+\r
+#include "Setup.h"\r
+\r
+\r
+/**\r
+  Process Question Config.\r
+\r
+  @param  Selection              The UI menu selection.\r
+  @param  Question               The Question to be peocessed.\r
+\r
+  @retval EFI_SUCCESS            Question Config process success.\r
+  @retval Other                  Question Config process fail.\r
+\r
+**/\r
+EFI_STATUS\r
+ProcessQuestionConfig (\r
+  IN  UI_MENU_SELECTION       *Selection,\r
+  IN  FORM_BROWSER_STATEMENT  *Question\r
+  )\r
+{\r
+  EFI_STATUS                      Status;\r
+  CHAR16                          *ConfigResp;\r
+  CHAR16                          *Progress;\r
+  EFI_HII_CONFIG_ACCESS_PROTOCOL  *ConfigAccess;\r
+\r
+  if (Question->QuestionConfig == 0) {\r
+    return EFI_SUCCESS;\r
+  }\r
+\r
+  //\r
+  // Get <ConfigResp>\r
+  //\r
+  ConfigResp = GetToken (Question->QuestionConfig, Selection->FormSet->HiiHandle);\r
+  if (ConfigResp == NULL) {\r
+    return EFI_NOT_FOUND;\r
+  }\r
+\r
+  //\r
+  // Send config to Configuration Driver\r
+  //\r
+  ConfigAccess = Selection->FormSet->ConfigAccess;\r
+  if (ConfigAccess == NULL) {\r
+    return EFI_UNSUPPORTED;\r
+  }\r
+  Status = ConfigAccess->RouteConfig (\r
+                           ConfigAccess,\r
+                           ConfigResp,\r
+                           &Progress\r
+                           );\r
+\r
+  return Status;\r
+}\r
+\r
+\r
+/**\r
+  Search an Option of a Question by its value.\r
+\r
+  @param  Question               The Question\r
+  @param  OptionValue            Value for Option to be searched.\r
+\r
+  @retval Pointer                Pointer to the found Option.\r
+  @retval NULL                   Option not found.\r
+\r
+**/\r
+QUESTION_OPTION *\r
+ValueToOption (\r
+  IN FORM_BROWSER_STATEMENT   *Question,\r
+  IN EFI_HII_VALUE            *OptionValue\r
+  )\r
+{\r
+  LIST_ENTRY       *Link;\r
+  QUESTION_OPTION  *Option;\r
+\r
+  Link = GetFirstNode (&Question->OptionListHead);\r
+  while (!IsNull (&Question->OptionListHead, Link)) {\r
+    Option = QUESTION_OPTION_FROM_LINK (Link);\r
+\r
+    if (CompareHiiValue (&Option->Value, OptionValue, NULL) == 0) {\r
+      return Option;\r
+    }\r
+\r
+    Link = GetNextNode (&Question->OptionListHead, Link);\r
+  }\r
+\r
+  return NULL;\r
+}\r
+\r
+\r
+/**\r
+  Return data element in an Array by its Index.\r
+\r
+  @param  Array                  The data array.\r
+  @param  Type                   Type of the data in this array.\r
+  @param  Index                  Zero based index for data in this array.\r
+\r
+  @retval Value                  The data to be returned\r
+\r
+**/\r
+UINT64\r
+GetArrayData (\r
+  IN VOID                     *Array,\r
+  IN UINT8                    Type,\r
+  IN UINTN                    Index\r
+  )\r
+{\r
+  UINT64 Data;\r
+\r
+  ASSERT (Array != NULL);\r
+\r
+  Data = 0;\r
+  switch (Type) {\r
+  case EFI_IFR_TYPE_NUM_SIZE_8:\r
+    Data = (UINT64) *(((UINT8 *) Array) + Index);\r
+    break;\r
+\r
+  case EFI_IFR_TYPE_NUM_SIZE_16:\r
+    Data = (UINT64) *(((UINT16 *) Array) + Index);\r
+    break;\r
+\r
+  case EFI_IFR_TYPE_NUM_SIZE_32:\r
+    Data = (UINT64) *(((UINT32 *) Array) + Index);\r
+    break;\r
+\r
+  case EFI_IFR_TYPE_NUM_SIZE_64:\r
+    Data = (UINT64) *(((UINT64 *) Array) + Index);\r
+    break;\r
+\r
+  default:\r
+    break;\r
+  }\r
+\r
+  return Data;\r
+}\r
+\r
+\r
+/**\r
+  Set value of a data element in an Array by its Index.\r
+\r
+  @param  Array                  The data array.\r
+  @param  Type                   Type of the data in this array.\r
+  @param  Index                  Zero based index for data in this array.\r
+  @param  Value                  The value to be set.\r
+\r
+**/\r
+VOID\r
+SetArrayData (\r
+  IN VOID                     *Array,\r
+  IN UINT8                    Type,\r
+  IN UINTN                    Index,\r
+  IN UINT64                   Value\r
+  )\r
+{\r
+\r
+  ASSERT (Array != NULL);\r
+\r
+  switch (Type) {\r
+  case EFI_IFR_TYPE_NUM_SIZE_8:\r
+    *(((UINT8 *) Array) + Index) = (UINT8) Value;\r
+    break;\r
+\r
+  case EFI_IFR_TYPE_NUM_SIZE_16:\r
+    *(((UINT16 *) Array) + Index) = (UINT16) Value;\r
+    break;\r
+\r
+  case EFI_IFR_TYPE_NUM_SIZE_32:\r
+    *(((UINT32 *) Array) + Index) = (UINT32) Value;\r
+    break;\r
+\r
+  case EFI_IFR_TYPE_NUM_SIZE_64:\r
+    *(((UINT64 *) Array) + Index) = (UINT64) Value;\r
+    break;\r
+\r
+  default:\r
+    break;\r
+  }\r
+}\r
+\r
+\r
+/**\r
+  Print Question Value according to it's storage width and display attributes.\r
+\r
+  @param  Question               The Question to be printed.\r
+  @param  FormattedNumber        Buffer for output string.\r
+  @param  BufferSize             The FormattedNumber buffer size in bytes.\r
+\r
+  @retval EFI_SUCCESS            Print success.\r
+  @retval EFI_BUFFER_TOO_SMALL   Buffer size is not enough for formatted number.\r
+\r
+**/\r
+EFI_STATUS\r
+PrintFormattedNumber (\r
+  IN FORM_BROWSER_STATEMENT   *Question,\r
+  IN OUT CHAR16               *FormattedNumber,\r
+  IN UINTN                    BufferSize\r
+  )\r
+{\r
+  INT64          Value;\r
+  CHAR16         *Format;\r
+  EFI_HII_VALUE  *QuestionValue;\r
+\r
+  if (BufferSize < (21 * sizeof (CHAR16))) {\r
+    return EFI_BUFFER_TOO_SMALL;\r
+  }\r
+\r
+  QuestionValue = &Question->HiiValue;\r
+\r
+  Value = (INT64) QuestionValue->Value.u64;\r
+  switch (Question->Flags & EFI_IFR_DISPLAY) {\r
+  case EFI_IFR_DISPLAY_INT_DEC:\r
+    switch (QuestionValue->Type) {\r
+    case EFI_IFR_NUMERIC_SIZE_1:\r
+      Value = (INT64) ((INT8) QuestionValue->Value.u8);\r
+      break;\r
+\r
+    case EFI_IFR_NUMERIC_SIZE_2:\r
+      Value = (INT64) ((INT16) QuestionValue->Value.u16);\r
+      break;\r
+\r
+    case EFI_IFR_NUMERIC_SIZE_4:\r
+      Value = (INT64) ((INT32) QuestionValue->Value.u32);\r
+      break;\r
+\r
+    case EFI_IFR_NUMERIC_SIZE_8:\r
+    default:\r
+      break;\r
+    }\r
+\r
+    if (Value < 0) {\r
+      Value = -Value;\r
+      Format = L"-%ld";\r
+    } else {\r
+      Format = L"%ld";\r
+    }\r
+    break;\r
+\r
+  case EFI_IFR_DISPLAY_UINT_DEC:\r
+    Format = L"%ld";\r
+    break;\r
+\r
+  case EFI_IFR_DISPLAY_UINT_HEX:\r
+    Format = L"%lx";\r
+    break;\r
+\r
+  default:\r
+    return EFI_UNSUPPORTED;\r
+    break;\r
+  }\r
+\r
+  UnicodeSPrint (FormattedNumber, BufferSize, Format, Value);\r
+\r
+  return EFI_SUCCESS;\r
+}\r
+\r
+\r
+/**\r
+  Password may be stored as encrypted by Configuration Driver. When change a\r
+  password, user will be challenged with old password. To validate user input old\r
+  password, we will send the clear text to Configuration Driver via Callback().\r
+  Configuration driver is responsible to check the passed in password and return\r
+  the validation result. If validation pass, state machine in password Callback()\r
+  will transit from BROWSER_STATE_VALIDATE_PASSWORD to BROWSER_STATE_SET_PASSWORD.\r
+  After user type in new password twice, Callback() will be invoked to send the\r
+  new password to Configuration Driver.\r
+\r
+  @param  Selection              Pointer to UI_MENU_SELECTION.\r
+  @param  MenuOption             The MenuOption for this password Question.\r
+  @param  String                 The clear text of password.\r
+\r
+  @retval EFI_NOT_AVAILABLE_YET  Callback() request to terminate password input.\r
+  @return In state of BROWSER_STATE_VALIDATE_PASSWORD:\r
+  @retval EFI_SUCCESS            Password correct, Browser will prompt for new\r
+                                 password.\r
+  @retval EFI_NOT_READY          Password incorrect, Browser will show error\r
+                                 message.\r
+  @retval Other                  Browser will do nothing.\r
+  @return In state of BROWSER_STATE_SET_PASSWORD:\r
+  @retval EFI_SUCCESS            Set password success.\r
+  @retval Other                  Set password failed.\r
+\r
+**/\r
+EFI_STATUS\r
+PasswordCallback (\r
+  IN  UI_MENU_SELECTION           *Selection,\r
+  IN  UI_MENU_OPTION              *MenuOption,\r
+  IN  CHAR16                      *String\r
+  )\r
+{\r
+  EFI_STATUS                      Status;\r
+  EFI_HII_CONFIG_ACCESS_PROTOCOL  *ConfigAccess;\r
+  EFI_BROWSER_ACTION_REQUEST      ActionRequest;\r
+  EFI_IFR_TYPE_VALUE              IfrTypeValue;\r
+\r
+  ConfigAccess = Selection->FormSet->ConfigAccess;\r
+  if (ConfigAccess == NULL) {\r
+    return EFI_UNSUPPORTED;\r
+  }\r
+\r
+  //\r
+  // Prepare password string in HII database\r
+  //\r
+  if (String != NULL) {\r
+    IfrTypeValue.string = NewString (String, Selection->FormSet->HiiHandle);\r
+  } else {\r
+    IfrTypeValue.string = 0;\r
+  }\r
+\r
+  //\r
+  // Send password to Configuration Driver for validation\r
+  //\r
+  Status = ConfigAccess->Callback (\r
+                           ConfigAccess,\r
+                           EFI_BROWSER_ACTION_CHANGING,\r
+                           MenuOption->ThisTag->QuestionId,\r
+                           MenuOption->ThisTag->HiiValue.Type,\r
+                           &IfrTypeValue,\r
+                           &ActionRequest\r
+                           );\r
+\r
+  //\r
+  // Remove password string from HII database\r
+  //\r
+  if (String != NULL) {\r
+    DeleteString (IfrTypeValue.string, Selection->FormSet->HiiHandle);\r
+  }\r
+\r
+  return Status;\r
+}\r
+\r
+\r
+/**\r
+  Display error message for invalid password.\r
+\r
+**/\r
+VOID\r
+PasswordInvalid (\r
+  VOID\r
+  )\r
+{\r
+  EFI_INPUT_KEY  Key;\r
+\r
+  //\r
+  // Invalid password, prompt error message\r
+  //\r
+  do {\r
+    CreateDialog (4, TRUE, 0, NULL, &Key, gEmptyString, gPassowordInvalid, gPressEnter, gEmptyString);\r
+  } while (Key.UnicodeChar != CHAR_CARRIAGE_RETURN);\r
+}\r
+\r
+\r
+/**\r
+  Process a Question's Option (whether selected or un-selected).\r
+\r
+  @param  Selection              Pointer to UI_MENU_SELECTION.\r
+  @param  MenuOption             The MenuOption for this Question.\r
+  @param  Selected               TRUE: if Question is selected.\r
+  @param  OptionString           Pointer of the Option String to be displayed.\r
+\r
+  @retval EFI_SUCCESS            Question Option process success.\r
+  @retval Other                  Question Option process fail.\r
+\r
+**/\r
+EFI_STATUS\r
+ProcessOptions (\r
+  IN  UI_MENU_SELECTION           *Selection,\r
+  IN  UI_MENU_OPTION              *MenuOption,\r
+  IN  BOOLEAN                     Selected,\r
+  OUT CHAR16                      **OptionString\r
+  )\r
+{\r
+  EFI_STATUS                      Status;\r
+  CHAR16                          *StringPtr;\r
+  CHAR16                          *TempString;\r
+  UINTN                           Index;\r
+  FORM_BROWSER_STATEMENT          *Question;\r
+  CHAR16                          FormattedNumber[21];\r
+  UINT16                          Number;\r
+  CHAR16                          Character[2];\r
+  EFI_INPUT_KEY                   Key;\r
+  UINTN                           BufferSize;\r
+  QUESTION_OPTION                 *OneOfOption;\r
+  LIST_ENTRY                      *Link;\r
+  EFI_HII_VALUE                   HiiValue;\r
+  EFI_HII_VALUE                   *QuestionValue;\r
+  BOOLEAN                         Suppress;\r
+  UINT16                          Maximum;\r
+  QUESTION_OPTION                 *Option;\r
+  UINTN                           Index2;\r
+  UINT8                           *ValueArray;\r
+  UINT8                           ValueType;\r
+  EFI_STRING_ID                   StringId;\r
+\r
+  Status        = EFI_SUCCESS;\r
+\r
+  StringPtr     = NULL;\r
+  Character[1]  = L'\0';\r
+  *OptionString = NULL;\r
+  StringId      = 0;\r
+\r
+  ZeroMem (FormattedNumber, 21 * sizeof (CHAR16));\r
+  BufferSize = (gOptionBlockWidth + 1) * 2 * gScreenDimensions.BottomRow;\r
+\r
+  Question = MenuOption->ThisTag;\r
+  QuestionValue = &Question->HiiValue;\r
+  Maximum = (UINT16) Question->Maximum;\r
+\r
+  ValueArray = Question->BufferValue;\r
+  ValueType = Question->ValueType;\r
+\r
+  switch (Question->Operand) {\r
+  case EFI_IFR_ORDERED_LIST_OP:\r
+    //\r
+    // Check whether there are Options of this OrderedList\r
+    //\r
+    if (IsListEmpty (&Question->OptionListHead)) {\r
+      break;\r
+    }\r
+    //\r
+    // Initialize Option value array\r
+    //\r
+    if (GetArrayData (ValueArray, ValueType, 0) == 0) {\r
+      GetQuestionDefault (Selection->FormSet, Selection->Form, Question, 0);\r
+    }\r
+\r
+    if (Selected) {\r
+      //\r
+      // Go ask for input\r
+      //\r
+      Status = GetSelectionInputPopUp (Selection, MenuOption);\r
+    } else {\r
+      //\r
+      // We now know how many strings we will have, so we can allocate the\r
+      // space required for the array or strings.\r
+      //\r
+      *OptionString = AllocateZeroPool (Question->MaxContainers * BufferSize);\r
+      ASSERT (*OptionString);\r
+\r
+      HiiValue.Type = ValueType;\r
+      HiiValue.Value.u64 = 0;\r
+      for (Index = 0; Index < Question->MaxContainers; Index++) {\r
+        HiiValue.Value.u64 = GetArrayData (ValueArray, ValueType, Index);\r
+        if (HiiValue.Value.u64 == 0) {\r
+          //\r
+          // Values for the options in ordered lists should never be a 0\r
+          //\r
+          break;\r
+        }\r
+\r
+        OneOfOption = ValueToOption (Question, &HiiValue);\r
+        if (OneOfOption == NULL) {\r
+          //\r
+          // Show error message\r
+          //\r
+          do {\r
+            CreateDialog (4, TRUE, 0, NULL, &Key, gEmptyString, gOptionMismatch, gPressEnter, gEmptyString);\r
+          } while (Key.UnicodeChar != CHAR_CARRIAGE_RETURN);\r
+\r
+          //\r
+          // The initial value of the orderedlist is invalid, force to be valid value\r
+          //\r
+          Link = GetFirstNode (&Question->OptionListHead);\r
+          Index2 = 0;\r
+          while (!IsNull (&Question->OptionListHead, Link) && Index2 < Question->MaxContainers) {\r
+            Option = QUESTION_OPTION_FROM_LINK (Link);\r
+            SetArrayData (ValueArray, ValueType, Index2, Option->Value.Value.u64);\r
+            Index2++;\r
+            Link = GetNextNode (&Question->OptionListHead, Link);\r
+          }\r
+          SetArrayData (ValueArray, ValueType, Index2, 0);\r
+\r
+          Status = SetQuestionValue (Selection->FormSet, Selection->Form, Question, TRUE);\r
+          UpdateStatusBar (NV_UPDATE_REQUIRED, Question->QuestionFlags, TRUE);\r
+\r
+          FreePool (*OptionString);\r
+          *OptionString = NULL;\r
+          return EFI_NOT_FOUND;\r
+        }\r
+\r
+        Suppress = FALSE;\r
+        if ((OneOfOption->SuppressExpression != NULL) &&\r
+            (OneOfOption->SuppressExpression->Result.Value.b)) {\r
+          //\r
+          // This option is suppressed\r
+          //\r
+          Suppress = TRUE;\r
+        }\r
+\r
+        if (!Suppress) {\r
+          Character[0] = LEFT_ONEOF_DELIMITER;\r
+          NewStrCat (OptionString[0], Character);\r
+          StringPtr = GetToken (OneOfOption->Text, Selection->Handle);\r
+          NewStrCat (OptionString[0], StringPtr);\r
+          Character[0] = RIGHT_ONEOF_DELIMITER;\r
+          NewStrCat (OptionString[0], Character);\r
+          Character[0] = CHAR_CARRIAGE_RETURN;\r
+          NewStrCat (OptionString[0], Character);\r
+\r
+          FreePool (StringPtr);\r
+        }\r
+      }\r
+    }\r
+    break;\r
+\r
+  case EFI_IFR_ONE_OF_OP:\r
+    //\r
+    // Check whether there are Options of this OneOf\r
+    //\r
+    if (IsListEmpty (&Question->OptionListHead)) {\r
+      break;\r
+    }\r
+    if (Selected) {\r
+      //\r
+      // Go ask for input\r
+      //\r
+      Status = GetSelectionInputPopUp (Selection, MenuOption);\r
+    } else {\r
+      *OptionString = AllocateZeroPool (BufferSize);\r
+      ASSERT (*OptionString);\r
+\r
+      OneOfOption = ValueToOption (Question, QuestionValue);\r
+      if (OneOfOption == NULL) {\r
+        //\r
+        // Show error message\r
+        //\r
+        do {\r
+          CreateDialog (4, TRUE, 0, NULL, &Key, gEmptyString, gOptionMismatch, gPressEnter, gEmptyString);\r
+        } while (Key.UnicodeChar != CHAR_CARRIAGE_RETURN);\r
+\r
+        //\r
+        // Force the Question value to be valid\r
+        //\r
+        Link = GetFirstNode (&Question->OptionListHead);\r
+        while (!IsNull (&Question->OptionListHead, Link)) {\r
+          Option = QUESTION_OPTION_FROM_LINK (Link);\r
+\r
+          if ((Option->SuppressExpression == NULL) ||\r
+              !Option->SuppressExpression->Result.Value.b) {\r
+            CopyMem (QuestionValue, &Option->Value, sizeof (EFI_HII_VALUE));\r
+            SetQuestionValue (Selection->FormSet, Selection->Form, Question, TRUE);\r
+            UpdateStatusBar (NV_UPDATE_REQUIRED, Question->QuestionFlags, TRUE);\r
+            break;\r
+          }\r
+\r
+          Link = GetNextNode (&Question->OptionListHead, Link);\r
+        }\r
+\r
+        FreePool (*OptionString);\r
+        *OptionString = NULL;\r
+        return EFI_NOT_FOUND;\r
+      }\r
+\r
+      if ((OneOfOption->SuppressExpression != NULL) &&\r
+          (OneOfOption->SuppressExpression->Result.Value.b)) {\r
+        //\r
+        // This option is suppressed\r
+        //\r
+        Suppress = TRUE;\r
+      } else {\r
+        Suppress = FALSE;\r
+      }\r
+\r
+      if (Suppress) {\r
+        //\r
+        // Current selected option happen to be suppressed,\r
+        // enforce to select on a non-suppressed option\r
+        //\r
+        Link = GetFirstNode (&Question->OptionListHead);\r
+        while (!IsNull (&Question->OptionListHead, Link)) {\r
+          OneOfOption = QUESTION_OPTION_FROM_LINK (Link);\r
+\r
+          if ((OneOfOption->SuppressExpression == NULL) ||\r
+              !OneOfOption->SuppressExpression->Result.Value.b) {\r
+            Suppress = FALSE;\r
+            CopyMem (QuestionValue, &OneOfOption->Value, sizeof (EFI_HII_VALUE));\r
+            SetQuestionValue (Selection->FormSet, Selection->Form, Question, TRUE);\r
+            UpdateStatusBar (NV_UPDATE_REQUIRED, Question->QuestionFlags, TRUE);\r
+            gST->ConOut->SetAttribute (gST->ConOut, FIELD_TEXT | FIELD_BACKGROUND);\r
+            break;\r
+          }\r
+\r
+          Link = GetNextNode (&Question->OptionListHead, Link);\r
+        }\r
+      }\r
+\r
+      if (!Suppress) {\r
+        Character[0] = LEFT_ONEOF_DELIMITER;\r
+        NewStrCat (OptionString[0], Character);\r
+        StringPtr = GetToken (OneOfOption->Text, Selection->Handle);\r
+        NewStrCat (OptionString[0], StringPtr);\r
+        Character[0] = RIGHT_ONEOF_DELIMITER;\r
+        NewStrCat (OptionString[0], Character);\r
+\r
+        FreePool (StringPtr);\r
+      }\r
+    }\r
+    break;\r
+\r
+  case EFI_IFR_CHECKBOX_OP:\r
+    *OptionString = AllocateZeroPool (BufferSize);\r
+    ASSERT (*OptionString);\r
+\r
+    *OptionString[0] = LEFT_CHECKBOX_DELIMITER;\r
+\r
+    if (Selected) {\r
+      //\r
+      // Since this is a BOOLEAN operation, flip it upon selection\r
+      //\r
+      QuestionValue->Value.b = (BOOLEAN) (QuestionValue->Value.b ? FALSE : TRUE);\r
+\r
+      //\r
+      // Perform inconsistent check\r
+      //\r
+      Status = ValidateQuestion (Selection->FormSet, Selection->Form, Question, EFI_HII_EXPRESSION_INCONSISTENT_IF);\r
+      if (EFI_ERROR (Status)) {\r
+        //\r
+        // Inconsistent check fail, restore Question Value\r
+        //\r
+        QuestionValue->Value.b = (BOOLEAN) (QuestionValue->Value.b ? FALSE : TRUE);\r
+        FreePool (*OptionString);\r
+        *OptionString = NULL;\r
+        return Status;\r
+      }\r
+\r
+      //\r
+      // Save Question value\r
+      //\r
+      Status = SetQuestionValue (Selection->FormSet, Selection->Form, Question, TRUE);\r
+      UpdateStatusBar (NV_UPDATE_REQUIRED, Question->QuestionFlags, TRUE);\r
+    }\r
+\r
+    if (QuestionValue->Value.b) {\r
+      *(OptionString[0] + 1) = CHECK_ON;\r
+    } else {\r
+      *(OptionString[0] + 1) = CHECK_OFF;\r
+    }\r
+    *(OptionString[0] + 2) = RIGHT_CHECKBOX_DELIMITER;\r
+    break;\r
+\r
+  case EFI_IFR_NUMERIC_OP:\r
+    if (Selected) {\r
+      //\r
+      // Go ask for input\r
+      //\r
+      Status = GetNumericInput (Selection, MenuOption);\r
+    } else {\r
+      *OptionString = AllocateZeroPool (BufferSize);\r
+      ASSERT (*OptionString);\r
+\r
+      *OptionString[0] = LEFT_NUMERIC_DELIMITER;\r
+\r
+      //\r
+      // Formatted print\r
+      //\r
+      PrintFormattedNumber (Question, FormattedNumber, 21 * sizeof (CHAR16));\r
+      Number = (UINT16) GetStringWidth (FormattedNumber);\r
+      CopyMem (OptionString[0] + 1, FormattedNumber, Number);\r
+\r
+      *(OptionString[0] + Number / 2) = RIGHT_NUMERIC_DELIMITER;\r
+    }\r
+    break;\r
+\r
+  case EFI_IFR_DATE_OP:\r
+    if (Selected) {\r
+      //\r
+      // This is similar to numerics\r
+      //\r
+      Status = GetNumericInput (Selection, MenuOption);\r
+    } else {\r
+      *OptionString = AllocateZeroPool (BufferSize);\r
+      ASSERT (*OptionString);\r
+\r
+      switch (MenuOption->Sequence) {\r
+      case 0:\r
+        *OptionString[0] = LEFT_NUMERIC_DELIMITER;\r
+        UnicodeSPrint (OptionString[0] + 1, 21 * sizeof (CHAR16), L"%02d", QuestionValue->Value.date.Month);\r
+        *(OptionString[0] + 3) = DATE_SEPARATOR;\r
+        break;\r
+\r
+      case 1:\r
+        SetUnicodeMem (OptionString[0], 4, L' ');\r
+        UnicodeSPrint (OptionString[0] + 4, 21 * sizeof (CHAR16), L"%02d", QuestionValue->Value.date.Day);\r
+        *(OptionString[0] + 6) = DATE_SEPARATOR;\r
+        break;\r
+\r
+      case 2:\r
+        SetUnicodeMem (OptionString[0], 7, L' ');\r
+        UnicodeSPrint (OptionString[0] + 7, 21 * sizeof (CHAR16), L"%4d", QuestionValue->Value.date.Year);\r
+        *(OptionString[0] + 11) = RIGHT_NUMERIC_DELIMITER;\r
+        break;\r
+      }\r
+    }\r
+    break;\r
+\r
+  case EFI_IFR_TIME_OP:\r
+    if (Selected) {\r
+      //\r
+      // This is similar to numerics\r
+      //\r
+      Status = GetNumericInput (Selection, MenuOption);\r
+    } else {\r
+      *OptionString = AllocateZeroPool (BufferSize);\r
+      ASSERT (*OptionString);\r
+\r
+      switch (MenuOption->Sequence) {\r
+      case 0:\r
+        *OptionString[0] = LEFT_NUMERIC_DELIMITER;\r
+        UnicodeSPrint (OptionString[0] + 1, 21 * sizeof (CHAR16), L"%02d", QuestionValue->Value.time.Hour);\r
+        *(OptionString[0] + 3) = TIME_SEPARATOR;\r
+        break;\r
+\r
+      case 1:\r
+        SetUnicodeMem (OptionString[0], 4, L' ');\r
+        UnicodeSPrint (OptionString[0] + 4, 21 * sizeof (CHAR16), L"%02d", QuestionValue->Value.time.Minute);\r
+        *(OptionString[0] + 6) = TIME_SEPARATOR;\r
+        break;\r
+\r
+      case 2:\r
+        SetUnicodeMem (OptionString[0], 7, L' ');\r
+        UnicodeSPrint (OptionString[0] + 7, 21 * sizeof (CHAR16), L"%02d", QuestionValue->Value.time.Second);\r
+        *(OptionString[0] + 9) = RIGHT_NUMERIC_DELIMITER;\r
+        break;\r
+      }\r
+    }\r
+    break;\r
+\r
+  case EFI_IFR_STRING_OP:\r
+    if (Selected) {\r
+      StringPtr = AllocateZeroPool ((Maximum + 1) * sizeof (CHAR16));\r
+      ASSERT (StringPtr);\r
+\r
+      Status = ReadString (MenuOption, gPromptForData, StringPtr);\r
+      if (!EFI_ERROR (Status)) {\r
+        HiiSetString(Selection->FormSet->HiiHandle, Question->HiiValue.Value.string, StringPtr, NULL);\r
+        Status = ValidateQuestion(Selection->FormSet, Selection->Form, Question, EFI_HII_EXPRESSION_INCONSISTENT_IF);\r
+        if (EFI_ERROR (Status)) {\r
+          HiiSetString(Selection->FormSet->HiiHandle, Question->HiiValue.Value.string, (CHAR16*)Question->BufferValue, NULL);\r
+        } else {\r
+          CopyMem (Question->BufferValue, StringPtr, Maximum * sizeof (CHAR16));\r
+          SetQuestionValue (Selection->FormSet, Selection->Form, Question, TRUE);\r
+\r
+          UpdateStatusBar (NV_UPDATE_REQUIRED, Question->QuestionFlags, TRUE);\r
+        }\r
+      }\r
+\r
+      FreePool (StringPtr);\r
+    } else {\r
+      *OptionString = AllocateZeroPool (BufferSize);\r
+      ASSERT (*OptionString);\r
+\r
+      if (((CHAR16 *) Question->BufferValue)[0] == 0x0000) {\r
+        *(OptionString[0]) = '_';\r
+      } else {\r
+        if ((Maximum * sizeof (CHAR16)) < BufferSize) {\r
+          BufferSize = Maximum * sizeof (CHAR16);\r
+        }\r
+        CopyMem (OptionString[0], (CHAR16 *) Question->BufferValue, BufferSize);\r
+      }\r
+    }\r
+    break;\r
+\r
+  case EFI_IFR_PASSWORD_OP:\r
+    if (Selected) {\r
+      StringPtr = AllocateZeroPool ((Maximum + 1) * sizeof (CHAR16));\r
+      ASSERT (StringPtr);\r
+\r
+      //\r
+      // For interactive passwords, old password is validated by callback\r
+      //\r
+      if ((Question->QuestionFlags & EFI_IFR_FLAG_CALLBACK)  != 0) {\r
+        //\r
+        // Use a NULL password to test whether old password is required\r
+        //\r
+        *StringPtr = 0;\r
+        Status = PasswordCallback (Selection, MenuOption, StringPtr);\r
+        if (Status == EFI_NOT_AVAILABLE_YET || Status == EFI_UNSUPPORTED) {\r
+          //\r
+          // Callback is not supported, or\r
+          // Callback request to terminate password input\r
+          //\r
+          FreePool (StringPtr);\r
+          return EFI_SUCCESS;\r
+        }\r
+\r
+        if (EFI_ERROR (Status)) {\r
+          //\r
+          // Old password exist, ask user for the old password\r
+          //\r
+          Status = ReadString (MenuOption, gPromptForPassword, StringPtr);\r
+          if (EFI_ERROR (Status)) {\r
+            FreePool (StringPtr);\r
+            return Status;\r
+          }\r
+\r
+          //\r
+          // Check user input old password\r
+          //\r
+          Status = PasswordCallback (Selection, MenuOption, StringPtr);\r
+          if (EFI_ERROR (Status)) {\r
+            if (Status == EFI_NOT_READY) {\r
+              //\r
+              // Typed in old password incorrect\r
+              //\r
+              PasswordInvalid ();\r
+            } else {\r
+              Status = EFI_SUCCESS;\r
+            }\r
+\r
+            FreePool (StringPtr);\r
+            return Status;\r
+          }\r
+        }\r
+      } else {\r
+        //\r
+        // For non-interactive password, validate old password in local\r
+        //\r
+        if (*((CHAR16 *) Question->BufferValue) != 0) {\r
+          //\r
+          // There is something there!  Prompt for password\r
+          //\r
+          Status = ReadString (MenuOption, gPromptForPassword, StringPtr);\r
+          if (EFI_ERROR (Status)) {\r
+            FreePool (StringPtr);\r
+            return Status;\r
+          }\r
+\r
+          TempString = AllocateCopyPool ((Maximum + 1) * sizeof (CHAR16), Question->BufferValue);\r
+          ASSERT (TempString != NULL);\r
+\r
+          TempString[Maximum] = L'\0';\r
+\r
+          if (StrCmp (StringPtr, TempString) != 0) {\r
+            //\r
+            // Typed in old password incorrect\r
+            //\r
+            PasswordInvalid ();\r
+\r
+            FreePool (StringPtr);\r
+            FreePool (TempString);\r
+            return Status;\r
+          }\r
+\r
+          FreePool (TempString);\r
+        }\r
+      }\r
+\r
+      //\r
+      // Ask for new password\r
+      //\r
+      ZeroMem (StringPtr, (Maximum + 1) * sizeof (CHAR16));\r
+      Status = ReadString (MenuOption, gPromptForNewPassword, StringPtr);\r
+      if (EFI_ERROR (Status)) {\r
+        //\r
+        // Reset state machine for interactive password\r
+        //\r
+        if ((Question->QuestionFlags & EFI_IFR_FLAG_CALLBACK) != 0) {\r
+          PasswordCallback (Selection, MenuOption, NULL);\r
+        }\r
+\r
+        FreePool (StringPtr);\r
+        return Status;\r
+      }\r
+\r
+      //\r
+      // Confirm new password\r
+      //\r
+      TempString = AllocateZeroPool ((Maximum + 1) * sizeof (CHAR16));\r
+      ASSERT (TempString);\r
+      Status = ReadString (MenuOption, gConfirmPassword, TempString);\r
+      if (EFI_ERROR (Status)) {\r
+        //\r
+        // Reset state machine for interactive password\r
+        //\r
+        if ((Question->QuestionFlags & EFI_IFR_FLAG_CALLBACK) != 0) {\r
+          PasswordCallback (Selection, MenuOption, NULL);\r
+        }\r
+\r
+        FreePool (StringPtr);\r
+        FreePool (TempString);\r
+        return Status;\r
+      }\r
+\r
+      //\r
+      // Compare two typed-in new passwords\r
+      //\r
+      if (StrCmp (StringPtr, TempString) == 0) {\r
+        //\r
+        // Prepare the  Question->HiiValue.Value.string for ValidateQuestion use.\r
+        //\r
+        if((Question->QuestionFlags & EFI_IFR_FLAG_CALLBACK) != 0) {\r
+          StringId = Question->HiiValue.Value.string;\r
+          Question->HiiValue.Value.string = NewString (StringPtr, Selection->FormSet->HiiHandle);\r
+        } else {\r
+          HiiSetString(Selection->FormSet->HiiHandle, Question->HiiValue.Value.string, StringPtr, NULL);\r
+        }\r
+        \r
+        Status = ValidateQuestion(Selection->FormSet, Selection->Form, Question, EFI_HII_EXPRESSION_INCONSISTENT_IF);\r
+\r
+        //\r
+        //  Researve the Question->HiiValue.Value.string.\r
+        //\r
+        if((Question->QuestionFlags & EFI_IFR_FLAG_CALLBACK) != 0) {\r
+          DeleteString(Question->HiiValue.Value.string, Selection->FormSet->HiiHandle);\r
+          Question->HiiValue.Value.string = StringId;\r
+        }   \r
+        \r
+        if (EFI_ERROR (Status)) {\r
+          //\r
+          // Reset state machine for interactive password\r
+          //\r
+          if ((Question->QuestionFlags & EFI_IFR_FLAG_CALLBACK) != 0) {\r
+            PasswordCallback (Selection, MenuOption, NULL);\r
+          } else {\r
+            //\r
+            // Researve the Question->HiiValue.Value.string.\r
+            //\r
+            HiiSetString(Selection->FormSet->HiiHandle, Question->HiiValue.Value.string, (CHAR16*)Question->BufferValue, NULL);            \r
+          }\r
+        } else {\r
+          //\r
+          // Two password match, send it to Configuration Driver\r
+          //\r
+          if ((Question->QuestionFlags & EFI_IFR_FLAG_CALLBACK) != 0) {\r
+            PasswordCallback (Selection, MenuOption, StringPtr);\r
+          } else {\r
+            CopyMem (Question->BufferValue, StringPtr, Maximum * sizeof (CHAR16));\r
+            SetQuestionValue (Selection->FormSet, Selection->Form, Question, FALSE);\r
+          }\r
+        }\r
+      } else {\r
+        //\r
+        // Reset state machine for interactive password\r
+        //\r
+        if ((Question->QuestionFlags & EFI_IFR_FLAG_CALLBACK) != 0) {\r
+          PasswordCallback (Selection, MenuOption, NULL);\r
+        }\r
+\r
+        //\r
+        // Two password mismatch, prompt error message\r
+        //\r
+        do {\r
+          CreateDialog (4, TRUE, 0, NULL, &Key, gEmptyString, gConfirmError, gPressEnter, gEmptyString);\r
+        } while (Key.UnicodeChar != CHAR_CARRIAGE_RETURN);\r
+      }\r
+\r
+      FreePool (TempString);\r
+      FreePool (StringPtr);\r
+    }\r
+    break;\r
+\r
+  default:\r
+    break;\r
+  }\r
+\r
+  return Status;\r
+}\r
+\r
+\r
+/**\r
+  Process the help string: Split StringPtr to several lines of strings stored in\r
+  FormattedString and the glyph width of each line cannot exceed gHelpBlockWidth.\r
+\r
+  @param  StringPtr              The entire help string.\r
+  @param  FormattedString        The oupput formatted string.\r
+  @param  RowCount               TRUE: if Question is selected.\r
+\r
+**/\r
+VOID\r
+ProcessHelpString (\r
+  IN  CHAR16  *StringPtr,\r
+  OUT CHAR16  **FormattedString,\r
+  IN  UINTN   RowCount\r
+  )\r
+{\r
+  UINTN BlockWidth;\r
+  UINTN AllocateSize;\r
+  //\r
+  // [PrevCurrIndex, CurrIndex) forms a range of a screen-line\r
+  //\r
+  UINTN CurrIndex;\r
+  UINTN PrevCurrIndex;\r
+  UINTN LineCount;\r
+  UINTN VirtualLineCount;\r
+  //\r
+  // GlyphOffset stores glyph width of current screen-line\r
+  //\r
+  UINTN GlyphOffset;\r
+  //\r
+  // GlyphWidth equals to 2 if we meet width directive\r
+  //\r
+  UINTN GlyphWidth;\r
+  //\r
+  // during scanning, we remember the position of last space character\r
+  // in case that if next word cannot put in current line, we could restore back to the position\r
+  // of last space character\r
+  // while we should also remmeber the glyph width of the last space character for restoring\r
+  //\r
+  UINTN LastSpaceIndex;\r
+  UINTN LastSpaceGlyphWidth;\r
+  //\r
+  // every time we begin to form a new screen-line, we should remember glyph width of single character\r
+  // of last line\r
+  //\r
+  UINTN LineStartGlyphWidth;\r
+  UINTN *IndexArray;\r
+  UINTN *OldIndexArray;\r
+\r
+  BlockWidth = (UINTN) gHelpBlockWidth - 1;\r
+\r
+  //\r
+  // every three elements of IndexArray form a screen-line of string:[ IndexArray[i*3], IndexArray[i*3+1] )\r
+  // IndexArray[i*3+2] stores the initial glyph width of single character. to save this is because we want\r
+  // to bring the width directive of the last line to current screen-line.\r
+  // e.g.: "\wideabcde ... fghi", if "fghi" also has width directive but is splitted to the next screen-line\r
+  // different from that of "\wideabcde", we should remember the width directive.\r
+  //\r
+  AllocateSize  = 0x20;\r
+  IndexArray    = AllocatePool (AllocateSize * sizeof (UINTN) * 3);\r
+  ASSERT (IndexArray != NULL);\r
+\r
+  if (*FormattedString != NULL) {\r
+    FreePool (*FormattedString);\r
+    *FormattedString = NULL;\r
+  }\r
+\r
+  for (PrevCurrIndex = 0, CurrIndex  = 0, LineCount   = 0, LastSpaceIndex = 0,\r
+       IndexArray[0] = 0, GlyphWidth = 1, GlyphOffset = 0, LastSpaceGlyphWidth = 1, LineStartGlyphWidth = 1;\r
+       (StringPtr[CurrIndex] != CHAR_NULL);\r
+       CurrIndex ++) {\r
+\r
+    if (LineCount == AllocateSize) {\r
+      AllocateSize += 0x10;\r
+      OldIndexArray  = IndexArray;\r
+      IndexArray = AllocatePool (AllocateSize * sizeof (UINTN) * 3);\r
+      ASSERT (IndexArray != NULL);\r
+\r
+      CopyMem (IndexArray, OldIndexArray, LineCount * sizeof (UINTN) * 3);\r
+      FreePool (OldIndexArray);\r
+    }\r
+    switch (StringPtr[CurrIndex]) {\r
+\r
+      case NARROW_CHAR:\r
+      case WIDE_CHAR:\r
+        GlyphWidth = ((StringPtr[CurrIndex] == WIDE_CHAR) ? 2 : 1);\r
+        if (CurrIndex == 0) {\r
+          LineStartGlyphWidth = GlyphWidth;\r
+        }\r
+        break;\r
+\r
+      //\r
+      // char is '\n'\r
+      // "\r\n" isn't handled here, handled by case CHAR_CARRIAGE_RETURN\r
+      //\r
+      case CHAR_LINEFEED:\r
+        //\r
+        // Store a range of string as a line\r
+        //\r
+        IndexArray[LineCount*3]   = PrevCurrIndex;\r
+        IndexArray[LineCount*3+1] = CurrIndex;\r
+        IndexArray[LineCount*3+2] = LineStartGlyphWidth;\r
+        LineCount ++;\r
+        //\r
+        // Reset offset and save begin position of line\r
+        //\r
+        GlyphOffset = 0;\r
+        LineStartGlyphWidth = GlyphWidth;\r
+        PrevCurrIndex = CurrIndex + 1;\r
+        break;\r
+\r
+      //\r
+      // char is '\r'\r
+      // "\r\n" and "\r" both are handled here\r
+      //\r
+      case CHAR_CARRIAGE_RETURN:\r
+        if (StringPtr[CurrIndex + 1] == CHAR_LINEFEED) {\r
+          //\r
+          // next char is '\n'\r
+          //\r
+          IndexArray[LineCount*3]   = PrevCurrIndex;\r
+          IndexArray[LineCount*3+1] = CurrIndex;\r
+          IndexArray[LineCount*3+2] = LineStartGlyphWidth;\r
+          LineCount ++;\r
+          CurrIndex ++;\r
+        }\r
+        GlyphOffset = 0;\r
+        LineStartGlyphWidth = GlyphWidth;\r
+        PrevCurrIndex = CurrIndex + 1;\r
+        break;\r
+\r
+      //\r
+      // char is space or other char\r
+      //\r
+      default:\r
+        GlyphOffset     += GlyphWidth;\r
+        if (GlyphOffset >= BlockWidth) {\r
+          if (LastSpaceIndex > PrevCurrIndex) {\r
+            //\r
+            // LastSpaceIndex points to space inside current screen-line,\r
+            // restore to LastSpaceIndex\r
+            // (Otherwise the word is too long to fit one screen-line, just cut it)\r
+            //\r
+            CurrIndex  = LastSpaceIndex;\r
+            GlyphWidth = LastSpaceGlyphWidth;\r
+          } else if (GlyphOffset > BlockWidth) {\r
+            //\r
+            // the word is too long to fit one screen-line and we don't get the chance\r
+            // of GlyphOffset == BlockWidth because GlyphWidth = 2\r
+            //\r
+            CurrIndex --;\r
+          }\r
+\r
+          IndexArray[LineCount*3]   = PrevCurrIndex;\r
+          IndexArray[LineCount*3+1] = CurrIndex + 1;\r
+          IndexArray[LineCount*3+2] = LineStartGlyphWidth;\r
+          LineStartGlyphWidth = GlyphWidth;\r
+          LineCount ++;\r
+          //\r
+          // Reset offset and save begin position of line\r
+          //\r
+          GlyphOffset                 = 0;\r
+          PrevCurrIndex               = CurrIndex + 1;\r
+        }\r
+\r
+        //\r
+        // LastSpaceIndex: remember position of last space\r
+        //\r
+        if (StringPtr[CurrIndex] == CHAR_SPACE) {\r
+          LastSpaceIndex      = CurrIndex;\r
+          LastSpaceGlyphWidth = GlyphWidth;\r
+        }\r
+        break;\r
+    }\r
+  }\r
+\r
+  if (GlyphOffset > 0) {\r
+    IndexArray[LineCount*3]   = PrevCurrIndex;\r
+    IndexArray[LineCount*3+1] = CurrIndex;\r
+    IndexArray[LineCount*3+2] = GlyphWidth;\r
+    LineCount ++;\r
+  }\r
+\r
+  if (LineCount == 0) {\r
+    //\r
+    // in case we meet null string\r
+    //\r
+    IndexArray[0] = 0;\r
+    IndexArray[1] = 1;\r
+    //\r
+    // we assume null string's glyph width is 1\r
+    //\r
+    IndexArray[1] = 1;\r
+    LineCount ++;\r
+  }\r
+\r
+  VirtualLineCount = RowCount * (LineCount / RowCount + (LineCount % RowCount > 0));\r
+  *FormattedString = AllocateZeroPool (VirtualLineCount * (BlockWidth + 1) * sizeof (CHAR16) * 2);\r
+  ASSERT (*FormattedString != NULL);\r
+\r
+  for (CurrIndex = 0; CurrIndex < LineCount; CurrIndex ++) {\r
+    *(*FormattedString + CurrIndex * 2 * (BlockWidth + 1)) = (CHAR16) ((IndexArray[CurrIndex*3+2] == 2) ? WIDE_CHAR : NARROW_CHAR);\r
+    StrnCpy (\r
+      *FormattedString + CurrIndex * 2 * (BlockWidth + 1) + 1,\r
+      StringPtr + IndexArray[CurrIndex*3],\r
+      IndexArray[CurrIndex*3+1]-IndexArray[CurrIndex*3]\r
+      );\r
+  }\r
+\r
+  FreePool (IndexArray);\r
+}\r