Signed-off-by: Eric Dong <eric.dong@intel.com> Reviewed-by: Liming Gao <liming.gao@intel.com> git-svn-id: https://edk2.svn.sourceforge.net/svnroot/edk2/trunk/edk2@13711 6f19259b-4bc3-4df7-8a09-765794883524
		
			
				
	
	
		
			1076 lines
		
	
	
		
			32 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
			
		
		
	
	
			1076 lines
		
	
	
		
			32 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
| /** @file
 | |
| Implementation for handling the User Interface option processing.
 | |
| 
 | |
| 
 | |
| Copyright (c) 2004 - 2012, 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 "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;
 | |
|   INTN             Result;
 | |
| 
 | |
|   Link = GetFirstNode (&Question->OptionListHead);
 | |
|   while (!IsNull (&Question->OptionListHead, Link)) {
 | |
|     Option = QUESTION_OPTION_FROM_LINK (Link);
 | |
| 
 | |
|     if ((CompareHiiValue (&Option->Value, OptionValue, &Result, NULL) == EFI_SUCCESS) && (Result == 0)) {
 | |
|       //
 | |
|       // Check the suppressif condition, only a valid option can be return.
 | |
|       //
 | |
|       if ((Option->SuppressExpression == NULL) ||
 | |
|           ((EvaluateExpressionList(Option->SuppressExpression, FALSE, NULL, NULL) == ExpressFalse))) {
 | |
|         return Option;
 | |
|       }
 | |
|     }
 | |
| 
 | |
|     Link = GetNextNode (&Question->OptionListHead, Link);
 | |
|   }
 | |
| 
 | |
|   return NULL;
 | |
| }
 | |
| 
 | |
| 
 | |
| /**
 | |
|   Return 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.
 | |
| 
 | |
|   @retval Value                  The data to be returned
 | |
| 
 | |
| **/
 | |
| UINT64
 | |
| GetArrayData (
 | |
|   IN VOID                     *Array,
 | |
|   IN UINT8                    Type,
 | |
|   IN UINTN                    Index
 | |
|   )
 | |
| {
 | |
|   UINT64 Data;
 | |
| 
 | |
|   ASSERT (Array != NULL);
 | |
| 
 | |
|   Data = 0;
 | |
|   switch (Type) {
 | |
|   case EFI_IFR_TYPE_NUM_SIZE_8:
 | |
|     Data = (UINT64) *(((UINT8 *) Array) + Index);
 | |
|     break;
 | |
| 
 | |
|   case EFI_IFR_TYPE_NUM_SIZE_16:
 | |
|     Data = (UINT64) *(((UINT16 *) Array) + Index);
 | |
|     break;
 | |
| 
 | |
|   case EFI_IFR_TYPE_NUM_SIZE_32:
 | |
|     Data = (UINT64) *(((UINT32 *) Array) + Index);
 | |
|     break;
 | |
| 
 | |
|   case EFI_IFR_TYPE_NUM_SIZE_64:
 | |
|     Data = (UINT64) *(((UINT64 *) Array) + Index);
 | |
|     break;
 | |
| 
 | |
|   default:
 | |
|     break;
 | |
|   }
 | |
| 
 | |
|   return Data;
 | |
| }
 | |
| 
 | |
| 
 | |
| /**
 | |
|   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;
 | |
|   }
 | |
| }
 | |
| 
 | |
| /**
 | |
|   Check whether this value already in the array, if yes, return the index.
 | |
| 
 | |
|   @param  Array                  The data array.
 | |
|   @param  Type                   Type of the data in this array.
 | |
|   @param  Value                  The value to be find.
 | |
|   @param  Index                  The index in the array which has same value with Value.
 | |
|   
 | |
|   @retval   TRUE Found the value in the array.
 | |
|   @retval   FALSE Not found the value.
 | |
| 
 | |
| **/
 | |
| BOOLEAN 
 | |
| FindArrayData (
 | |
|   IN VOID                     *Array,
 | |
|   IN UINT8                    Type,
 | |
|   IN UINT64                   Value,
 | |
|   OUT UINTN                   *Index OPTIONAL
 | |
|   )
 | |
| {
 | |
|   UINTN  Count;
 | |
|   UINT64 TmpValue;
 | |
|   
 | |
|   ASSERT (Array != NULL);
 | |
| 
 | |
|   Count    = 0;
 | |
|   TmpValue = 0;
 | |
| 
 | |
|   while ((TmpValue = GetArrayData (Array, Type, Count)) != 0) {
 | |
|     if (Value == TmpValue) {
 | |
|       if (Index != NULL) {
 | |
|         *Index = Count;
 | |
|       }
 | |
|       return TRUE;
 | |
|     }
 | |
| 
 | |
|     Count ++;
 | |
|   }
 | |
| 
 | |
|   return FALSE;
 | |
| }
 | |
| 
 | |
| /**
 | |
|   Print Question Value according to it's storage width and display attributes.
 | |
| 
 | |
|   @param  Question               The Question to be printed.
 | |
|   @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_IFR_TYPE_VALUE              IfrTypeValue;
 | |
| 
 | |
|   ConfigAccess = Selection->FormSet->ConfigAccess;
 | |
|   if (ConfigAccess == NULL) {
 | |
|     return EFI_UNSUPPORTED;
 | |
|   }
 | |
| 
 | |
|   //
 | |
|   // Prepare password string in HII database
 | |
|   //
 | |
|   if (String != NULL) {
 | |
|     IfrTypeValue.string = NewString (String, Selection->FormSet->HiiHandle);
 | |
|   } else {
 | |
|     IfrTypeValue.string = 0;
 | |
|   }
 | |
| 
 | |
|   //
 | |
|   // Send password to Configuration Driver for validation
 | |
|   //
 | |
|   Status = ConfigAccess->Callback (
 | |
|                            ConfigAccess,
 | |
|                            EFI_BROWSER_ACTION_CHANGING,
 | |
|                            MenuOption->ThisTag->QuestionId,
 | |
|                            MenuOption->ThisTag->HiiValue.Type,
 | |
|                            &IfrTypeValue,
 | |
|                            &ActionRequest
 | |
|                            );
 | |
| 
 | |
|   //
 | |
|   // Remove password string from HII database
 | |
|   //
 | |
|   if (String != NULL) {
 | |
|     DeleteString (IfrTypeValue.string, Selection->FormSet->HiiHandle);
 | |
|   }
 | |
| 
 | |
|   return Status;
 | |
| }
 | |
| 
 | |
| 
 | |
| /**
 | |
|   Display error message for invalid password.
 | |
| 
 | |
| **/
 | |
| 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;
 | |
|   UINT16                          Maximum;
 | |
|   QUESTION_OPTION                 *Option;
 | |
|   UINTN                           Index2;
 | |
|   UINT8                           *ValueArray;
 | |
|   UINT8                           ValueType;
 | |
|   EFI_STRING_ID                   StringId;
 | |
| 
 | |
|   Status        = EFI_SUCCESS;
 | |
| 
 | |
|   StringPtr     = NULL;
 | |
|   Character[1]  = L'\0';
 | |
|   *OptionString = NULL;
 | |
|   StringId      = 0;
 | |
| 
 | |
|   ZeroMem (FormattedNumber, 21 * sizeof (CHAR16));
 | |
|   BufferSize = (gOptionBlockWidth + 1) * 2 * gScreenDimensions.BottomRow;
 | |
| 
 | |
|   Question = MenuOption->ThisTag;
 | |
|   QuestionValue = &Question->HiiValue;
 | |
|   Maximum = (UINT16) Question->Maximum;
 | |
| 
 | |
|   ValueArray = Question->BufferValue;
 | |
|   ValueType = Question->ValueType;
 | |
| 
 | |
|   switch (Question->Operand) {
 | |
|   case EFI_IFR_ORDERED_LIST_OP:
 | |
|     //
 | |
|     // Check whether there are Options of this OrderedList
 | |
|     //
 | |
|     if (IsListEmpty (&Question->OptionListHead)) {
 | |
|       break;
 | |
|     }
 | |
|     //
 | |
|     // Initialize Option value array
 | |
|     //
 | |
|     if (GetArrayData (ValueArray, ValueType, 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 = ValueType;
 | |
|       HiiValue.Value.u64 = 0;
 | |
|       for (Index = 0; Index < Question->MaxContainers; Index++) {
 | |
|         HiiValue.Value.u64 = GetArrayData (ValueArray, ValueType, Index);
 | |
|         if (HiiValue.Value.u64 == 0) {
 | |
|           //
 | |
|           // Values for the options in ordered lists should never be a 0
 | |
|           //
 | |
|           break;
 | |
|         }
 | |
| 
 | |
|         OneOfOption = ValueToOption (Question, &HiiValue);
 | |
|         if (OneOfOption == NULL) {
 | |
|           //
 | |
|           // Show error message
 | |
|           //
 | |
|           do {
 | |
|             CreateDialog (4, TRUE, 0, NULL, &Key, gEmptyString, gOptionMismatch, gPressEnter, gEmptyString);
 | |
|           } while (Key.UnicodeChar != CHAR_CARRIAGE_RETURN);
 | |
| 
 | |
|           //
 | |
|           // The initial value of the orderedlist is invalid, force to be valid value
 | |
|           //
 | |
|           Link = GetFirstNode (&Question->OptionListHead);
 | |
|           Index2 = 0;
 | |
|           while (!IsNull (&Question->OptionListHead, Link) && Index2 < Question->MaxContainers) {
 | |
|             Option = QUESTION_OPTION_FROM_LINK (Link);
 | |
|             Link = GetNextNode (&Question->OptionListHead, Link);
 | |
|             if ((Option->SuppressExpression != NULL) &&
 | |
|                 ((EvaluateExpressionList(Option->SuppressExpression, FALSE, NULL, NULL) == ExpressSuppress))) {
 | |
|               continue;
 | |
|             }
 | |
|             SetArrayData (ValueArray, ValueType, Index2, Option->Value.Value.u64);
 | |
|             Index2++;
 | |
|           }
 | |
|           SetArrayData (ValueArray, ValueType, Index2, 0);
 | |
| 
 | |
|           Status = SetQuestionValue (Selection->FormSet, Selection->Form, Question, GetSetValueWithEditBuffer);
 | |
|           UpdateStatusBar (Selection, NV_UPDATE_REQUIRED, Question->QuestionFlags, TRUE);
 | |
| 
 | |
|           FreePool (*OptionString);
 | |
|           *OptionString = NULL;
 | |
|           return EFI_NOT_FOUND;
 | |
|         }
 | |
| 
 | |
|         Character[0] = LEFT_ONEOF_DELIMITER;
 | |
|         NewStrCat (OptionString[0], Character);
 | |
|         StringPtr = GetToken (OneOfOption->Text, Selection->Handle);
 | |
|         ASSERT (StringPtr != NULL);
 | |
|         NewStrCat (OptionString[0], StringPtr);
 | |
|         Character[0] = RIGHT_ONEOF_DELIMITER;
 | |
|         NewStrCat (OptionString[0], Character);
 | |
|         Character[0] = CHAR_CARRIAGE_RETURN;
 | |
|         NewStrCat (OptionString[0], Character);
 | |
|         FreePool (StringPtr);
 | |
|       }
 | |
| 
 | |
|       //
 | |
|       // Search the other options, try to find the one not in the container.
 | |
|       //
 | |
|       Link = GetFirstNode (&Question->OptionListHead);
 | |
|       while (!IsNull (&Question->OptionListHead, Link)) {
 | |
|         OneOfOption = QUESTION_OPTION_FROM_LINK (Link);
 | |
|         Link = GetNextNode (&Question->OptionListHead, Link);
 | |
|         if ((OneOfOption->SuppressExpression != NULL) &&
 | |
|             ((EvaluateExpressionList(OneOfOption->SuppressExpression, FALSE, NULL, NULL) == ExpressSuppress))) {
 | |
|           continue;
 | |
|         }
 | |
| 
 | |
|         if (FindArrayData (ValueArray, ValueType, OneOfOption->Value.Value.u64, NULL)) {
 | |
|           continue;
 | |
|         }
 | |
| 
 | |
|         SetArrayData (ValueArray, ValueType, Index++, OneOfOption->Value.Value.u64);
 | |
| 
 | |
|         Character[0] = LEFT_ONEOF_DELIMITER;
 | |
|         NewStrCat (OptionString[0], Character);
 | |
|         StringPtr = GetToken (OneOfOption->Text, Selection->Handle);
 | |
|         ASSERT (StringPtr != NULL);
 | |
|         NewStrCat (OptionString[0], StringPtr);
 | |
|         Character[0] = RIGHT_ONEOF_DELIMITER;
 | |
|         NewStrCat (OptionString[0], Character);
 | |
|         Character[0] = CHAR_CARRIAGE_RETURN;
 | |
|         NewStrCat (OptionString[0], Character);
 | |
|         FreePool (StringPtr);
 | |
|       }
 | |
|     }
 | |
|     break;
 | |
| 
 | |
|   case EFI_IFR_ONE_OF_OP:
 | |
|     //
 | |
|     // Check whether there are Options of this OneOf
 | |
|     //
 | |
|     if (IsListEmpty (&Question->OptionListHead)) {
 | |
|       break;
 | |
|     }
 | |
|     if (Selected) {
 | |
|       //
 | |
|       // Go ask for input
 | |
|       //
 | |
|       Status = GetSelectionInputPopUp (Selection, MenuOption);
 | |
|     } else {
 | |
|       *OptionString = AllocateZeroPool (BufferSize);
 | |
|       ASSERT (*OptionString);
 | |
| 
 | |
|       OneOfOption = ValueToOption (Question, QuestionValue);
 | |
|       if (OneOfOption == NULL) {
 | |
|         //
 | |
|         // Show error message
 | |
|         //
 | |
|         do {
 | |
|           CreateDialog (4, TRUE, 0, NULL, &Key, gEmptyString, gOptionMismatch, gPressEnter, gEmptyString);
 | |
|         } while (Key.UnicodeChar != CHAR_CARRIAGE_RETURN);
 | |
| 
 | |
|         //
 | |
|         // Force the Question value to be valid
 | |
|         //
 | |
|         Link = GetFirstNode (&Question->OptionListHead);
 | |
|         while (!IsNull (&Question->OptionListHead, Link)) {
 | |
|           Option = QUESTION_OPTION_FROM_LINK (Link);
 | |
| 
 | |
|           if ((Option->SuppressExpression == NULL) ||
 | |
|               (EvaluateExpressionList(Option->SuppressExpression, FALSE, NULL, NULL) == ExpressFalse)) {
 | |
|             CopyMem (QuestionValue, &Option->Value, sizeof (EFI_HII_VALUE));
 | |
|             SetQuestionValue (Selection->FormSet, Selection->Form, Question, GetSetValueWithEditBuffer);
 | |
|             UpdateStatusBar (Selection, NV_UPDATE_REQUIRED, Question->QuestionFlags, TRUE);
 | |
|             break;
 | |
|           }
 | |
| 
 | |
|           Link = GetNextNode (&Question->OptionListHead, Link);
 | |
|         }
 | |
| 
 | |
|         FreePool (*OptionString);
 | |
|         *OptionString = NULL;
 | |
|         return EFI_NOT_FOUND;
 | |
|       }
 | |
| 
 | |
|       Character[0] = LEFT_ONEOF_DELIMITER;
 | |
|       NewStrCat (OptionString[0], Character);
 | |
|       StringPtr = GetToken (OneOfOption->Text, Selection->Handle);
 | |
|       ASSERT (StringPtr != NULL);
 | |
|       NewStrCat (OptionString[0], StringPtr);
 | |
|       Character[0] = RIGHT_ONEOF_DELIMITER;
 | |
|       NewStrCat (OptionString[0], Character);
 | |
| 
 | |
|       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);
 | |
|         FreePool (*OptionString);
 | |
|         *OptionString = NULL;
 | |
|         return Status;
 | |
|       }
 | |
| 
 | |
|       //
 | |
|       // Save Question value
 | |
|       //
 | |
|       Status = SetQuestionValue (Selection->FormSet, Selection->Form, Question, GetSetValueWithEditBuffer);
 | |
|       UpdateStatusBar (Selection, 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"%04d", 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);
 | |
|       CopyMem(StringPtr, Question->BufferValue, Maximum * sizeof (CHAR16));
 | |
| 
 | |
|       Status = ReadString (MenuOption, gPromptForData, StringPtr);
 | |
|       if (!EFI_ERROR (Status)) {
 | |
|         HiiSetString(Selection->FormSet->HiiHandle, Question->HiiValue.Value.string, StringPtr, NULL);
 | |
|         Status = ValidateQuestion(Selection->FormSet, Selection->Form, Question, EFI_HII_EXPRESSION_INCONSISTENT_IF);
 | |
|         if (EFI_ERROR (Status)) {
 | |
|           HiiSetString(Selection->FormSet->HiiHandle, Question->HiiValue.Value.string, (CHAR16*)Question->BufferValue, NULL);
 | |
|         } else {
 | |
|           CopyMem (Question->BufferValue, StringPtr, Maximum * sizeof (CHAR16));
 | |
|           SetQuestionValue (Selection->FormSet, Selection->Form, Question, GetSetValueWithEditBuffer);
 | |
| 
 | |
|           UpdateStatusBar (Selection, NV_UPDATE_REQUIRED, Question->QuestionFlags, TRUE);
 | |
|         }
 | |
|       }
 | |
| 
 | |
|       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)  != 0) {
 | |
|         //
 | |
|         // Use a NULL password to test whether old password is required
 | |
|         //
 | |
|         *StringPtr = 0;
 | |
|         Status = PasswordCallback (Selection, MenuOption, StringPtr);
 | |
|         if (Status == EFI_NOT_AVAILABLE_YET || Status == EFI_UNSUPPORTED) {
 | |
|           //
 | |
|           // Callback is not supported, or
 | |
|           // Callback request to terminate password input
 | |
|           //
 | |
|           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)) {
 | |
|             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;
 | |
|             }
 | |
| 
 | |
|             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)) {
 | |
|             FreePool (StringPtr);
 | |
|             return Status;
 | |
|           }
 | |
| 
 | |
|           TempString = AllocateCopyPool ((Maximum + 1) * sizeof (CHAR16), Question->BufferValue);
 | |
|           ASSERT (TempString != NULL);
 | |
| 
 | |
|           TempString[Maximum] = L'\0';
 | |
| 
 | |
|           if (StrCmp (StringPtr, TempString) != 0) {
 | |
|             //
 | |
|             // Typed in old password incorrect
 | |
|             //
 | |
|             PasswordInvalid ();
 | |
| 
 | |
|             FreePool (StringPtr);
 | |
|             FreePool (TempString);
 | |
|             return Status;
 | |
|           }
 | |
| 
 | |
|           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) != 0) {
 | |
|           PasswordCallback (Selection, MenuOption, NULL);
 | |
|         }
 | |
| 
 | |
|         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) != 0) {
 | |
|           PasswordCallback (Selection, MenuOption, NULL);
 | |
|         }
 | |
| 
 | |
|         FreePool (StringPtr);
 | |
|         FreePool (TempString);
 | |
|         return Status;
 | |
|       }
 | |
| 
 | |
|       //
 | |
|       // Compare two typed-in new passwords
 | |
|       //
 | |
|       if (StrCmp (StringPtr, TempString) == 0) {
 | |
|         //
 | |
|         // Prepare the  Question->HiiValue.Value.string for ValidateQuestion use.
 | |
|         //
 | |
|         if((Question->QuestionFlags & EFI_IFR_FLAG_CALLBACK) != 0) {
 | |
|           StringId = Question->HiiValue.Value.string;
 | |
|           Question->HiiValue.Value.string = NewString (StringPtr, Selection->FormSet->HiiHandle);
 | |
|         } else {
 | |
|           HiiSetString(Selection->FormSet->HiiHandle, Question->HiiValue.Value.string, StringPtr, NULL);
 | |
|         }
 | |
|         
 | |
|         Status = ValidateQuestion(Selection->FormSet, Selection->Form, Question, EFI_HII_EXPRESSION_INCONSISTENT_IF);
 | |
| 
 | |
|         //
 | |
|         //  Researve the Question->HiiValue.Value.string.
 | |
|         //
 | |
|         if((Question->QuestionFlags & EFI_IFR_FLAG_CALLBACK) != 0) {
 | |
|           DeleteString(Question->HiiValue.Value.string, Selection->FormSet->HiiHandle);
 | |
|           Question->HiiValue.Value.string = StringId;
 | |
|         }   
 | |
|         
 | |
|         if (EFI_ERROR (Status)) {
 | |
|           //
 | |
|           // Reset state machine for interactive password
 | |
|           //
 | |
|           if ((Question->QuestionFlags & EFI_IFR_FLAG_CALLBACK) != 0) {
 | |
|             PasswordCallback (Selection, MenuOption, NULL);
 | |
|           } else {
 | |
|             //
 | |
|             // Researve the Question->HiiValue.Value.string.
 | |
|             //
 | |
|             HiiSetString(Selection->FormSet->HiiHandle, Question->HiiValue.Value.string, (CHAR16*)Question->BufferValue, NULL);            
 | |
|           }
 | |
|         } else {
 | |
|           //
 | |
|           // Two password match, send it to Configuration Driver
 | |
|           //
 | |
|           if ((Question->QuestionFlags & EFI_IFR_FLAG_CALLBACK) != 0) {
 | |
|             PasswordCallback (Selection, MenuOption, StringPtr);
 | |
|           } else {
 | |
|             CopyMem (Question->BufferValue, StringPtr, Maximum * sizeof (CHAR16));
 | |
|             SetQuestionValue (Selection->FormSet, Selection->Form, Question, GetSetValueWithHiiDriver);
 | |
|           }
 | |
|         }
 | |
|       } else {
 | |
|         //
 | |
|         // Reset state machine for interactive password
 | |
|         //
 | |
|         if ((Question->QuestionFlags & EFI_IFR_FLAG_CALLBACK) != 0) {
 | |
|           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);
 | |
|       }
 | |
| 
 | |
|       FreePool (TempString);
 | |
|       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  FormattedString        The oupput formatted string.
 | |
|   @param  EachLineWidth          The max string length of each line in the formatted string.
 | |
|   @param  RowCount               TRUE: if Question is selected.
 | |
| 
 | |
| **/
 | |
| UINTN
 | |
| ProcessHelpString (
 | |
|   IN  CHAR16  *StringPtr,
 | |
|   OUT CHAR16  **FormattedString,
 | |
|   OUT UINT16  *EachLineWidth,
 | |
|   IN  UINTN   RowCount
 | |
|   )
 | |
| {
 | |
|   UINTN   Index;
 | |
|   CHAR16  *OutputString;
 | |
|   UINTN   TotalRowNum;
 | |
|   UINTN   CheckedNum;
 | |
|   UINT16  GlyphWidth;
 | |
|   UINT16  LineWidth;
 | |
|   UINT16  MaxStringLen;
 | |
|   UINT16  StringLen;
 | |
| 
 | |
|   TotalRowNum    = 0;
 | |
|   CheckedNum     = 0;
 | |
|   GlyphWidth     = 1;
 | |
|   Index          = 0;
 | |
|   MaxStringLen   = 0;
 | |
|   StringLen      = 0;
 | |
| 
 | |
|   //
 | |
|   // Set default help string width.
 | |
|   //
 | |
|   LineWidth      = (UINT16) (gHelpBlockWidth - 1);
 | |
| 
 | |
|   //
 | |
|   // Get row number of the String.
 | |
|   //
 | |
|   while ((StringLen = GetLineByWidth (StringPtr, LineWidth, &GlyphWidth, &Index, &OutputString)) != 0) {
 | |
|     if (StringLen > MaxStringLen) {
 | |
|       MaxStringLen = StringLen;
 | |
|     }
 | |
| 
 | |
|     TotalRowNum ++;
 | |
|     FreePool (OutputString);
 | |
|   }
 | |
|   *EachLineWidth = MaxStringLen;
 | |
| 
 | |
|   *FormattedString = AllocateZeroPool (TotalRowNum * MaxStringLen * sizeof (CHAR16));
 | |
|   ASSERT (*FormattedString != NULL);
 | |
| 
 | |
|   //
 | |
|   // Generate formatted help string array.
 | |
|   //
 | |
|   GlyphWidth  = 1;
 | |
|   Index       = 0;
 | |
|   while((StringLen = GetLineByWidth (StringPtr, LineWidth, &GlyphWidth, &Index, &OutputString)) != 0) {
 | |
|     CopyMem (*FormattedString + CheckedNum * MaxStringLen, OutputString, StringLen * sizeof (CHAR16));
 | |
|     CheckedNum ++;
 | |
|     FreePool (OutputString);
 | |
|   }
 | |
| 
 | |
|   return TotalRowNum; 
 | |
| }
 |