| /** @file | |
| Implementation for handling the User Interface option processing. | |
| Copyright (c) 2004 - 2020, Intel Corporation. All rights reserved.<BR> | |
| SPDX-License-Identifier: BSD-2-Clause-Patent | |
| **/ | |
| #include "FormDisplay.h" | |
| #define MAX_TIME_OUT_LEN 0x10 | |
| /** | |
| Concatenate a narrow string to another string. | |
| @param Destination The destination string. | |
| @param DestMax The Max length of destination string. | |
| @param Source The source string. The string to be concatenated. | |
| to the end of Destination. | |
| **/ | |
| VOID | |
| NewStrCat ( | |
| IN OUT CHAR16 *Destination, | |
| IN UINTN DestMax, | |
| IN CHAR16 *Source | |
| ) | |
| { | |
| UINTN Length; | |
| for (Length = 0; Destination[Length] != 0; Length++) { | |
| } | |
| // | |
| // We now have the length of the original string | |
| // We can safely assume for now that we are concatenating a narrow value to this string. | |
| // For instance, the string is "XYZ" and cat'ing ">" | |
| // If this assumption changes, we need to make this routine a bit more complex | |
| // | |
| Destination[Length] = NARROW_CHAR; | |
| Length++; | |
| StrCpyS (Destination + Length, DestMax - Length, Source); | |
| } | |
| /** | |
| Get UINT64 type value. | |
| @param Value Input Hii value. | |
| @retval UINT64 Return the UINT64 type value. | |
| **/ | |
| UINT64 | |
| HiiValueToUINT64 ( | |
| IN EFI_HII_VALUE *Value | |
| ) | |
| { | |
| UINT64 RetVal; | |
| RetVal = 0; | |
| switch (Value->Type) { | |
| case EFI_IFR_TYPE_NUM_SIZE_8: | |
| RetVal = Value->Value.u8; | |
| break; | |
| case EFI_IFR_TYPE_NUM_SIZE_16: | |
| RetVal = Value->Value.u16; | |
| break; | |
| case EFI_IFR_TYPE_NUM_SIZE_32: | |
| RetVal = Value->Value.u32; | |
| break; | |
| case EFI_IFR_TYPE_BOOLEAN: | |
| RetVal = Value->Value.b; | |
| break; | |
| case EFI_IFR_TYPE_DATE: | |
| RetVal = *(UINT64 *)&Value->Value.date; | |
| break; | |
| case EFI_IFR_TYPE_TIME: | |
| RetVal = (*(UINT64 *)&Value->Value.time) & 0xffffff; | |
| break; | |
| default: | |
| RetVal = Value->Value.u64; | |
| break; | |
| } | |
| return RetVal; | |
| } | |
| /** | |
| Check whether this value type can be transfer to EFI_IFR_TYPE_BUFFER type. | |
| EFI_IFR_TYPE_REF, EFI_IFR_TYPE_DATE and EFI_IFR_TYPE_TIME are converted to | |
| EFI_IFR_TYPE_BUFFER when do the value compare. | |
| @param Value Expression value to compare on. | |
| @retval TRUE This value type can be transter to EFI_IFR_TYPE_BUFFER type. | |
| @retval FALSE This value type can't be transter to EFI_IFR_TYPE_BUFFER type. | |
| **/ | |
| BOOLEAN | |
| IsTypeInBuffer ( | |
| IN EFI_HII_VALUE *Value | |
| ) | |
| { | |
| switch (Value->Type) { | |
| case EFI_IFR_TYPE_BUFFER: | |
| case EFI_IFR_TYPE_DATE: | |
| case EFI_IFR_TYPE_TIME: | |
| case EFI_IFR_TYPE_REF: | |
| return TRUE; | |
| default: | |
| return FALSE; | |
| } | |
| } | |
| /** | |
| Check whether this value type can be transfer to EFI_IFR_TYPE_UINT64 | |
| @param Value Expression value to compare on. | |
| @retval TRUE This value type can be transter to EFI_IFR_TYPE_BUFFER type. | |
| @retval FALSE This value type can't be transter to EFI_IFR_TYPE_BUFFER type. | |
| **/ | |
| BOOLEAN | |
| IsTypeInUINT64 ( | |
| IN EFI_HII_VALUE *Value | |
| ) | |
| { | |
| switch (Value->Type) { | |
| case EFI_IFR_TYPE_NUM_SIZE_8: | |
| case EFI_IFR_TYPE_NUM_SIZE_16: | |
| case EFI_IFR_TYPE_NUM_SIZE_32: | |
| case EFI_IFR_TYPE_NUM_SIZE_64: | |
| case EFI_IFR_TYPE_BOOLEAN: | |
| return TRUE; | |
| default: | |
| return FALSE; | |
| } | |
| } | |
| /** | |
| Return the buffer length and buffer pointer for this value. | |
| EFI_IFR_TYPE_REF, EFI_IFR_TYPE_DATE and EFI_IFR_TYPE_TIME are converted to | |
| EFI_IFR_TYPE_BUFFER when do the value compare. | |
| @param Value Expression value to compare on. | |
| @param Buf Return the buffer pointer. | |
| @param BufLen Return the buffer length. | |
| **/ | |
| VOID | |
| GetBufAndLenForValue ( | |
| IN EFI_HII_VALUE *Value, | |
| OUT UINT8 **Buf, | |
| OUT UINT16 *BufLen | |
| ) | |
| { | |
| switch (Value->Type) { | |
| case EFI_IFR_TYPE_BUFFER: | |
| *Buf = Value->Buffer; | |
| *BufLen = Value->BufferLen; | |
| break; | |
| case EFI_IFR_TYPE_DATE: | |
| *Buf = (UINT8 *)(&Value->Value.date); | |
| *BufLen = (UINT16)sizeof (EFI_HII_DATE); | |
| break; | |
| case EFI_IFR_TYPE_TIME: | |
| *Buf = (UINT8 *)(&Value->Value.time); | |
| *BufLen = (UINT16)sizeof (EFI_HII_TIME); | |
| break; | |
| case EFI_IFR_TYPE_REF: | |
| *Buf = (UINT8 *)(&Value->Value.ref); | |
| *BufLen = (UINT16)sizeof (EFI_HII_REF); | |
| break; | |
| default: | |
| *Buf = NULL; | |
| *BufLen = 0; | |
| } | |
| } | |
| /** | |
| Compare two Hii value. | |
| @param Value1 Expression value to compare on left-hand. | |
| @param Value2 Expression value to compare on right-hand. | |
| @param Result Return value after compare. | |
| retval 0 Two operators equal. | |
| return Positive value if Value1 is greater than Value2. | |
| retval Negative value if Value1 is less than Value2. | |
| @param HiiHandle Only required for string compare. | |
| @retval other Could not perform compare on two values. | |
| @retval EFI_SUCCESS Compare the value success. | |
| **/ | |
| EFI_STATUS | |
| CompareHiiValue ( | |
| IN EFI_HII_VALUE *Value1, | |
| IN EFI_HII_VALUE *Value2, | |
| OUT INTN *Result, | |
| IN EFI_HII_HANDLE HiiHandle OPTIONAL | |
| ) | |
| { | |
| INT64 Temp64; | |
| CHAR16 *Str1; | |
| CHAR16 *Str2; | |
| UINTN Len; | |
| UINT8 *Buf1; | |
| UINT16 Buf1Len; | |
| UINT8 *Buf2; | |
| UINT16 Buf2Len; | |
| if ((Value1->Type == EFI_IFR_TYPE_STRING) && (Value2->Type == EFI_IFR_TYPE_STRING)) { | |
| if ((Value1->Value.string == 0) || (Value2->Value.string == 0)) { | |
| // | |
| // StringId 0 is reserved | |
| // | |
| return EFI_INVALID_PARAMETER; | |
| } | |
| if (Value1->Value.string == Value2->Value.string) { | |
| *Result = 0; | |
| return EFI_SUCCESS; | |
| } | |
| Str1 = GetToken (Value1->Value.string, HiiHandle); | |
| if (Str1 == NULL) { | |
| // | |
| // String not found | |
| // | |
| return EFI_NOT_FOUND; | |
| } | |
| Str2 = GetToken (Value2->Value.string, HiiHandle); | |
| if (Str2 == NULL) { | |
| FreePool (Str1); | |
| return EFI_NOT_FOUND; | |
| } | |
| *Result = StrCmp (Str1, Str2); | |
| FreePool (Str1); | |
| FreePool (Str2); | |
| return EFI_SUCCESS; | |
| } | |
| // | |
| // Take types(date, time, ref, buffer) as buffer | |
| // | |
| if (IsTypeInBuffer (Value1) && IsTypeInBuffer (Value2)) { | |
| GetBufAndLenForValue (Value1, &Buf1, &Buf1Len); | |
| GetBufAndLenForValue (Value2, &Buf2, &Buf2Len); | |
| Len = Buf1Len > Buf2Len ? Buf2Len : Buf1Len; | |
| *Result = CompareMem (Buf1, Buf2, Len); | |
| if ((*Result == 0) && (Buf1Len != Buf2Len)) { | |
| // | |
| // In this case, means base on samll number buffer, the data is same | |
| // So which value has more data, which value is bigger. | |
| // | |
| *Result = Buf1Len > Buf2Len ? 1 : -1; | |
| } | |
| return EFI_SUCCESS; | |
| } | |
| // | |
| // Take remain types(integer, boolean, date/time) as integer | |
| // | |
| if (IsTypeInUINT64 (Value1) && IsTypeInUINT64 (Value2)) { | |
| Temp64 = HiiValueToUINT64 (Value1) - HiiValueToUINT64 (Value2); | |
| if (Temp64 > 0) { | |
| *Result = 1; | |
| } else if (Temp64 < 0) { | |
| *Result = -1; | |
| } else { | |
| *Result = 0; | |
| } | |
| return EFI_SUCCESS; | |
| } | |
| return EFI_UNSUPPORTED; | |
| } | |
| /** | |
| 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. | |
| **/ | |
| DISPLAY_QUESTION_OPTION * | |
| ValueToOption ( | |
| IN FORM_DISPLAY_ENGINE_STATEMENT *Question, | |
| IN EFI_HII_VALUE *OptionValue | |
| ) | |
| { | |
| LIST_ENTRY *Link; | |
| DISPLAY_QUESTION_OPTION *Option; | |
| INTN Result; | |
| EFI_HII_VALUE Value; | |
| Link = GetFirstNode (&Question->OptionListHead); | |
| while (!IsNull (&Question->OptionListHead, Link)) { | |
| Option = DISPLAY_QUESTION_OPTION_FROM_LINK (Link); | |
| ZeroMem (&Value, sizeof (EFI_HII_VALUE)); | |
| Value.Type = Option->OptionOpCode->Type; | |
| CopyMem (&Value.Value, &Option->OptionOpCode->Value, Option->OptionOpCode->Header.Length - OFFSET_OF (EFI_IFR_ONE_OF_OPTION, Value)); | |
| if ((CompareHiiValue (&Value, OptionValue, &Result, NULL) == EFI_SUCCESS) && (Result == 0)) { | |
| 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; | |
| UINT64 ValueComp; | |
| ASSERT (Array != NULL); | |
| Count = 0; | |
| TmpValue = 0; | |
| switch (Type) { | |
| case EFI_IFR_TYPE_NUM_SIZE_8: | |
| ValueComp = (UINT8)Value; | |
| break; | |
| case EFI_IFR_TYPE_NUM_SIZE_16: | |
| ValueComp = (UINT16)Value; | |
| break; | |
| case EFI_IFR_TYPE_NUM_SIZE_32: | |
| ValueComp = (UINT32)Value; | |
| break; | |
| case EFI_IFR_TYPE_NUM_SIZE_64: | |
| ValueComp = (UINT64)Value; | |
| break; | |
| default: | |
| ValueComp = 0; | |
| break; | |
| } | |
| while ((TmpValue = GetArrayData (Array, Type, Count)) != 0) { | |
| if (ValueComp == 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_DISPLAY_ENGINE_STATEMENT *Question, | |
| IN OUT CHAR16 *FormattedNumber, | |
| IN UINTN BufferSize | |
| ) | |
| { | |
| INT64 Value; | |
| CHAR16 *Format; | |
| EFI_HII_VALUE *QuestionValue; | |
| EFI_IFR_NUMERIC *NumericOp; | |
| if (BufferSize < (21 * sizeof (CHAR16))) { | |
| return EFI_BUFFER_TOO_SMALL; | |
| } | |
| QuestionValue = &Question->CurrentValue; | |
| NumericOp = (EFI_IFR_NUMERIC *)Question->OpCode; | |
| Value = (INT64)QuestionValue->Value.u64; | |
| switch (NumericOp->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; | |
| } | |
| UnicodeSPrint (FormattedNumber, BufferSize, Format, Value); | |
| return EFI_SUCCESS; | |
| } | |
| /** | |
| Draw a pop up windows based on the dimension, number of lines and | |
| strings specified. | |
| @param RequestedWidth The width of the pop-up. | |
| @param NumberOfLines The number of lines. | |
| @param Marker The variable argument list for the list of string to be printed. | |
| **/ | |
| VOID | |
| CreateSharedPopUp ( | |
| IN UINTN RequestedWidth, | |
| IN UINTN NumberOfLines, | |
| IN VA_LIST Marker | |
| ) | |
| { | |
| UINTN Index; | |
| UINTN Count; | |
| CHAR16 Character; | |
| UINTN Start; | |
| UINTN End; | |
| UINTN Top; | |
| UINTN Bottom; | |
| CHAR16 *String; | |
| UINTN DimensionsWidth; | |
| UINTN DimensionsHeight; | |
| DimensionsWidth = gStatementDimensions.RightColumn - gStatementDimensions.LeftColumn; | |
| DimensionsHeight = gStatementDimensions.BottomRow - gStatementDimensions.TopRow; | |
| gST->ConOut->SetAttribute (gST->ConOut, GetPopupColor ()); | |
| if ((RequestedWidth + 2) > DimensionsWidth) { | |
| RequestedWidth = DimensionsWidth - 2; | |
| } | |
| // | |
| // Subtract the PopUp width from total Columns, allow for one space extra on | |
| // each end plus a border. | |
| // | |
| Start = (DimensionsWidth - RequestedWidth - 2) / 2 + gStatementDimensions.LeftColumn + 1; | |
| End = Start + RequestedWidth + 1; | |
| Top = ((DimensionsHeight - NumberOfLines - 2) / 2) + gStatementDimensions.TopRow - 1; | |
| Bottom = Top + NumberOfLines + 2; | |
| Character = BOXDRAW_DOWN_RIGHT; | |
| PrintCharAt (Start, Top, Character); | |
| Character = BOXDRAW_HORIZONTAL; | |
| for (Index = Start; Index + 2 < End; Index++) { | |
| PrintCharAt ((UINTN)-1, (UINTN)-1, Character); | |
| } | |
| Character = BOXDRAW_DOWN_LEFT; | |
| PrintCharAt ((UINTN)-1, (UINTN)-1, Character); | |
| Character = BOXDRAW_VERTICAL; | |
| Count = 0; | |
| for (Index = Top; Index + 2 < Bottom; Index++, Count++) { | |
| String = VA_ARG (Marker, CHAR16 *); | |
| // | |
| // This will clear the background of the line - we never know who might have been | |
| // here before us. This differs from the next clear in that it used the non-reverse | |
| // video for normal printing. | |
| // | |
| if (GetStringWidth (String) / 2 > 1) { | |
| ClearLines (Start, End, Index + 1, Index + 1, GetPopupColor ()); | |
| } | |
| // | |
| // Passing in a space results in the assumption that this is where typing will occur | |
| // | |
| if (String[0] == L' ') { | |
| ClearLines (Start + 1, End - 1, Index + 1, Index + 1, GetPopupInverseColor ()); | |
| } | |
| // | |
| // Passing in a NULL results in a blank space | |
| // | |
| if (String[0] == CHAR_NULL) { | |
| ClearLines (Start, End, Index + 1, Index + 1, GetPopupColor ()); | |
| } | |
| PrintStringAt ( | |
| ((DimensionsWidth - GetStringWidth (String) / 2) / 2) + gStatementDimensions.LeftColumn + 1, | |
| Index + 1, | |
| String | |
| ); | |
| gST->ConOut->SetAttribute (gST->ConOut, GetPopupColor ()); | |
| PrintCharAt (Start, Index + 1, Character); | |
| PrintCharAt (End - 1, Index + 1, Character); | |
| } | |
| Character = BOXDRAW_UP_RIGHT; | |
| PrintCharAt (Start, Bottom - 1, Character); | |
| Character = BOXDRAW_HORIZONTAL; | |
| for (Index = Start; Index + 2 < End; Index++) { | |
| PrintCharAt ((UINTN)-1, (UINTN)-1, Character); | |
| } | |
| Character = BOXDRAW_UP_LEFT; | |
| PrintCharAt ((UINTN)-1, (UINTN)-1, Character); | |
| } | |
| /** | |
| Draw a pop up windows based on the dimension, number of lines and | |
| strings specified. | |
| @param RequestedWidth The width of the pop-up. | |
| @param NumberOfLines The number of lines. | |
| @param ... A series of text strings that displayed in the pop-up. | |
| **/ | |
| VOID | |
| EFIAPI | |
| CreateMultiStringPopUp ( | |
| IN UINTN RequestedWidth, | |
| IN UINTN NumberOfLines, | |
| ... | |
| ) | |
| { | |
| VA_LIST Marker; | |
| VA_START (Marker, NumberOfLines); | |
| CreateSharedPopUp (RequestedWidth, NumberOfLines, Marker); | |
| VA_END (Marker); | |
| } | |
| /** | |
| Process nothing. | |
| @param Event The Event need to be process | |
| @param Context The context of the event. | |
| **/ | |
| VOID | |
| EFIAPI | |
| EmptyEventProcess ( | |
| IN EFI_EVENT Event, | |
| IN VOID *Context | |
| ) | |
| { | |
| } | |
| /** | |
| Process for the refresh interval statement. | |
| @param Event The Event need to be process | |
| @param Context The context of the event. | |
| **/ | |
| VOID | |
| EFIAPI | |
| RefreshTimeOutProcess ( | |
| IN EFI_EVENT Event, | |
| IN VOID *Context | |
| ) | |
| { | |
| WARNING_IF_CONTEXT *EventInfo; | |
| CHAR16 TimeOutString[MAX_TIME_OUT_LEN]; | |
| EventInfo = (WARNING_IF_CONTEXT *)Context; | |
| if (*(EventInfo->TimeOut) == 0) { | |
| gBS->CloseEvent (Event); | |
| gBS->SignalEvent (EventInfo->SyncEvent); | |
| return; | |
| } | |
| UnicodeSPrint (TimeOutString, MAX_TIME_OUT_LEN, L"%d", *(EventInfo->TimeOut)); | |
| CreateDialog (NULL, gEmptyString, EventInfo->ErrorInfo, gPressEnter, gEmptyString, TimeOutString, NULL); | |
| *(EventInfo->TimeOut) -= 1; | |
| } | |
| /** | |
| Display error message for invalid password. | |
| **/ | |
| VOID | |
| PasswordInvalid ( | |
| VOID | |
| ) | |
| { | |
| EFI_INPUT_KEY Key; | |
| // | |
| // Invalid password, prompt error message | |
| // | |
| do { | |
| CreateDialog (&Key, gEmptyString, gPassowordInvalid, gPressEnter, gEmptyString, NULL); | |
| } while (Key.UnicodeChar != CHAR_CARRIAGE_RETURN); | |
| } | |
| /** | |
| Process password op code. | |
| @param MenuOption The menu for current password op code. | |
| @retval EFI_SUCCESS Question Option process success. | |
| @retval Other Question Option process fail. | |
| **/ | |
| EFI_STATUS | |
| PasswordProcess ( | |
| IN UI_MENU_OPTION *MenuOption | |
| ) | |
| { | |
| CHAR16 *StringPtr; | |
| CHAR16 *TempString; | |
| UINTN Maximum; | |
| EFI_STATUS Status; | |
| EFI_IFR_PASSWORD *PasswordInfo; | |
| FORM_DISPLAY_ENGINE_STATEMENT *Question; | |
| EFI_INPUT_KEY Key; | |
| Question = MenuOption->ThisTag; | |
| PasswordInfo = (EFI_IFR_PASSWORD *)Question->OpCode; | |
| Maximum = PasswordInfo->MaxSize; | |
| Status = EFI_SUCCESS; | |
| StringPtr = AllocateZeroPool ((Maximum + 1) * sizeof (CHAR16)); | |
| ASSERT (StringPtr); | |
| // | |
| // Use a NULL password to test whether old password is required | |
| // | |
| *StringPtr = 0; | |
| Status = Question->PasswordCheck (gFormData, Question, StringPtr); | |
| if ((Status == EFI_NOT_AVAILABLE_YET) || (Status == EFI_UNSUPPORTED)) { | |
| // | |
| // Password can't be set now. | |
| // | |
| if (Status == EFI_UNSUPPORTED) { | |
| do { | |
| CreateDialog (&Key, gEmptyString, gPasswordUnsupported, gPressEnter, gEmptyString, NULL); | |
| } while (Key.UnicodeChar != CHAR_CARRIAGE_RETURN); | |
| } | |
| 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)) { | |
| ZeroMem (StringPtr, (Maximum + 1) * sizeof (CHAR16)); | |
| FreePool (StringPtr); | |
| return Status; | |
| } | |
| // | |
| // Check user input old password | |
| // | |
| Status = Question->PasswordCheck (gFormData, Question, StringPtr); | |
| if (EFI_ERROR (Status)) { | |
| if (Status == EFI_NOT_READY) { | |
| // | |
| // Typed in old password incorrect | |
| // | |
| PasswordInvalid (); | |
| } else { | |
| Status = EFI_SUCCESS; | |
| } | |
| ZeroMem (StringPtr, (Maximum + 1) * sizeof (CHAR16)); | |
| FreePool (StringPtr); | |
| return Status; | |
| } | |
| } | |
| // | |
| // Ask for new password | |
| // | |
| ZeroMem (StringPtr, (Maximum + 1) * sizeof (CHAR16)); | |
| Status = ReadString (MenuOption, gPromptForNewPassword, StringPtr); | |
| if (EFI_ERROR (Status)) { | |
| // | |
| // Reset state machine for password | |
| // | |
| Question->PasswordCheck (gFormData, Question, NULL); | |
| ZeroMem (StringPtr, (Maximum + 1) * sizeof (CHAR16)); | |
| 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 password | |
| // | |
| Question->PasswordCheck (gFormData, Question, NULL); | |
| ZeroMem (StringPtr, (Maximum + 1) * sizeof (CHAR16)); | |
| ZeroMem (TempString, (Maximum + 1) * sizeof (CHAR16)); | |
| FreePool (StringPtr); | |
| FreePool (TempString); | |
| return Status; | |
| } | |
| // | |
| // Compare two typed-in new passwords | |
| // | |
| if (StrCmp (StringPtr, TempString) == 0) { | |
| gUserInput->InputValue.Buffer = AllocateCopyPool (Question->CurrentValue.BufferLen, StringPtr); | |
| gUserInput->InputValue.BufferLen = Question->CurrentValue.BufferLen; | |
| gUserInput->InputValue.Type = Question->CurrentValue.Type; | |
| gUserInput->InputValue.Value.string = HiiSetString (gFormData->HiiHandle, gUserInput->InputValue.Value.string, StringPtr, NULL); | |
| Status = EFI_SUCCESS; | |
| } else { | |
| // | |
| // Reset state machine for password | |
| // | |
| Question->PasswordCheck (gFormData, Question, NULL); | |
| // | |
| // Two password mismatch, prompt error message | |
| // | |
| do { | |
| CreateDialog (&Key, gEmptyString, gConfirmError, gPressEnter, gEmptyString, NULL); | |
| } while (Key.UnicodeChar != CHAR_CARRIAGE_RETURN); | |
| Status = EFI_INVALID_PARAMETER; | |
| } | |
| ZeroMem (TempString, (Maximum + 1) * sizeof (CHAR16)); | |
| ZeroMem (StringPtr, (Maximum + 1) * sizeof (CHAR16)); | |
| FreePool (TempString); | |
| FreePool (StringPtr); | |
| return Status; | |
| } | |
| /** | |
| Print some debug message about mismatched menu info. | |
| @param MenuOption The MenuOption for this Question. | |
| **/ | |
| VOID | |
| PrintMismatchMenuInfo ( | |
| IN UI_MENU_OPTION *MenuOption | |
| ) | |
| { | |
| CHAR16 *FormTitleStr; | |
| CHAR16 *FormSetTitleStr; | |
| CHAR16 *OneOfOptionStr; | |
| CHAR16 *QuestionName; | |
| LIST_ENTRY *Link; | |
| FORM_DISPLAY_ENGINE_STATEMENT *Question; | |
| EFI_IFR_ORDERED_LIST *OrderList; | |
| UINT8 Index; | |
| EFI_HII_VALUE HiiValue; | |
| EFI_HII_VALUE *QuestionValue; | |
| DISPLAY_QUESTION_OPTION *Option; | |
| UINT8 *ValueArray; | |
| UINT8 ValueType; | |
| EFI_IFR_FORM_SET *FormsetBuffer; | |
| UINTN FormsetBufferSize; | |
| Question = MenuOption->ThisTag; | |
| if (!EFI_ERROR (HiiGetFormSetFromHiiHandle (gFormData->HiiHandle, &FormsetBuffer, &FormsetBufferSize))) { | |
| FormSetTitleStr = GetToken (FormsetBuffer->FormSetTitle, gFormData->HiiHandle); | |
| FormTitleStr = GetToken (gFormData->FormTitle, gFormData->HiiHandle); | |
| DEBUG ((DEBUG_ERROR, "\n[%a]: Mismatch Formset : Formset Guid = %g, FormSet title = %s\n", gEfiCallerBaseName, &gFormData->FormSetGuid, FormSetTitleStr)); | |
| DEBUG ((DEBUG_ERROR, "[%a]: Mismatch Form : FormId = %d, Form title = %s.\n", gEfiCallerBaseName, gFormData->FormId, FormTitleStr)); | |
| } | |
| if (Question->OpCode->OpCode == EFI_IFR_ORDERED_LIST_OP) { | |
| QuestionName = GetToken (((EFI_IFR_ORDERED_LIST *)MenuOption->ThisTag->OpCode)->Question.Header.Prompt, gFormData->HiiHandle); | |
| Link = GetFirstNode (&Question->OptionListHead); | |
| Option = DISPLAY_QUESTION_OPTION_FROM_LINK (Link); | |
| ValueType = Option->OptionOpCode->Type; | |
| DEBUG ((DEBUG_ERROR, "[%a]: Mismatch Error : OrderedList value in the array doesn't match with option value.\n", gEfiCallerBaseName)); | |
| DEBUG ((DEBUG_ERROR, "[%a]: Mismatch OrderedList: Name = %s.\n", gEfiCallerBaseName, QuestionName)); | |
| DEBUG ((DEBUG_ERROR, "[%a]: Mismatch OrderedList: OrderedList array value :\n", gEfiCallerBaseName)); | |
| OrderList = (EFI_IFR_ORDERED_LIST *)Question->OpCode; | |
| for (Index = 0; Index < OrderList->MaxContainers; Index++) { | |
| ValueArray = Question->CurrentValue.Buffer; | |
| HiiValue.Value.u64 = GetArrayData (ValueArray, ValueType, Index); | |
| DEBUG ((DEBUG_ERROR, " Value[%d] =%ld.\n", Index, HiiValue.Value.u64)); | |
| } | |
| } else if (Question->OpCode->OpCode == EFI_IFR_ONE_OF_OP) { | |
| QuestionName = GetToken (((EFI_IFR_ONE_OF *)MenuOption->ThisTag->OpCode)->Question.Header.Prompt, gFormData->HiiHandle); | |
| QuestionValue = &Question->CurrentValue; | |
| DEBUG ((DEBUG_ERROR, "[%a]: Mismatch Error : OneOf value doesn't match with option value.\n", gEfiCallerBaseName)); | |
| DEBUG ((DEBUG_ERROR, "[%a]: Mismatch OneOf : Name = %s.\n", gEfiCallerBaseName, QuestionName)); | |
| switch (QuestionValue->Type) { | |
| case EFI_IFR_TYPE_NUM_SIZE_64: | |
| DEBUG ((DEBUG_ERROR, "[%a]: Mismatch OneOf : OneOf value = %ld.\n", gEfiCallerBaseName, QuestionValue->Value.u64)); | |
| break; | |
| case EFI_IFR_TYPE_NUM_SIZE_32: | |
| DEBUG ((DEBUG_ERROR, "[%a]: Mismatch OneOf : OneOf value = %d.\n", gEfiCallerBaseName, QuestionValue->Value.u32)); | |
| break; | |
| case EFI_IFR_TYPE_NUM_SIZE_16: | |
| DEBUG ((DEBUG_ERROR, "[%a]: Mismatch OneOf : OneOf value = %d.\n", gEfiCallerBaseName, QuestionValue->Value.u16)); | |
| break; | |
| case EFI_IFR_TYPE_NUM_SIZE_8: | |
| DEBUG ((DEBUG_ERROR, "[%a]: Mismatch OneOf : OneOf value = %d.\n", gEfiCallerBaseName, QuestionValue->Value.u8)); | |
| break; | |
| default: | |
| ASSERT (FALSE); | |
| break; | |
| } | |
| } | |
| Index = 0; | |
| Link = GetFirstNode (&Question->OptionListHead); | |
| while (!IsNull (&Question->OptionListHead, Link)) { | |
| Option = DISPLAY_QUESTION_OPTION_FROM_LINK (Link); | |
| OneOfOptionStr = GetToken (Option->OptionOpCode->Option, gFormData->HiiHandle); | |
| switch (Option->OptionOpCode->Type) { | |
| case EFI_IFR_TYPE_NUM_SIZE_64: | |
| DEBUG ((DEBUG_ERROR, "[%a]: Option %d : Option Value = %ld, Option Name = %s.\n", gEfiCallerBaseName, Index, Option->OptionOpCode->Value.u64, OneOfOptionStr)); | |
| break; | |
| case EFI_IFR_TYPE_NUM_SIZE_32: | |
| DEBUG ((DEBUG_ERROR, "[%a]: Option %d : Option Value = %d, Option Name = %s.\n", gEfiCallerBaseName, Index, Option->OptionOpCode->Value.u32, OneOfOptionStr)); | |
| break; | |
| case EFI_IFR_TYPE_NUM_SIZE_16: | |
| DEBUG ((DEBUG_ERROR, "[%a]: Option %d : Option Value = %d, Option Name = %s.\n", gEfiCallerBaseName, Index, Option->OptionOpCode->Value.u16, OneOfOptionStr)); | |
| break; | |
| case EFI_IFR_TYPE_NUM_SIZE_8: | |
| DEBUG ((DEBUG_ERROR, "[%a]: Option %d : Option Value = %d, Option Name = %s.\n", gEfiCallerBaseName, Index, Option->OptionOpCode->Value.u8, OneOfOptionStr)); | |
| break; | |
| default: | |
| ASSERT (FALSE); | |
| break; | |
| } | |
| Link = GetNextNode (&Question->OptionListHead, Link); | |
| Index++; | |
| } | |
| } | |
| /** | |
| Process a Question's Option (whether selected or un-selected). | |
| @param MenuOption The MenuOption for this Question. | |
| @param Selected TRUE: if Question is selected. | |
| @param OptionString Pointer of the Option String to be displayed. | |
| @param SkipErrorValue Whether need to return when value without option for it. | |
| @retval EFI_SUCCESS Question Option process success. | |
| @retval Other Question Option process fail. | |
| **/ | |
| EFI_STATUS | |
| ProcessOptions ( | |
| IN UI_MENU_OPTION *MenuOption, | |
| IN BOOLEAN Selected, | |
| OUT CHAR16 **OptionString, | |
| IN BOOLEAN SkipErrorValue | |
| ) | |
| { | |
| EFI_STATUS Status; | |
| CHAR16 *StringPtr; | |
| UINTN Index; | |
| FORM_DISPLAY_ENGINE_STATEMENT *Question; | |
| CHAR16 FormattedNumber[21]; | |
| UINT16 Number; | |
| CHAR16 Character[2]; | |
| EFI_INPUT_KEY Key; | |
| UINTN BufferSize; | |
| DISPLAY_QUESTION_OPTION *OneOfOption; | |
| LIST_ENTRY *Link; | |
| EFI_HII_VALUE HiiValue; | |
| EFI_HII_VALUE *QuestionValue; | |
| DISPLAY_QUESTION_OPTION *Option; | |
| UINTN Index2; | |
| UINT8 *ValueArray; | |
| UINT8 ValueType; | |
| EFI_IFR_ORDERED_LIST *OrderList; | |
| BOOLEAN ValueInvalid; | |
| UINTN MaxLen; | |
| Status = EFI_SUCCESS; | |
| StringPtr = NULL; | |
| Character[1] = L'\0'; | |
| *OptionString = NULL; | |
| ValueInvalid = FALSE; | |
| ZeroMem (FormattedNumber, 21 * sizeof (CHAR16)); | |
| BufferSize = (gOptionBlockWidth + 1) * 2 * gStatementDimensions.BottomRow; | |
| Question = MenuOption->ThisTag; | |
| QuestionValue = &Question->CurrentValue; | |
| switch (Question->OpCode->OpCode) { | |
| case EFI_IFR_ORDERED_LIST_OP: | |
| // | |
| // Check whether there are Options of this OrderedList | |
| // | |
| if (IsListEmpty (&Question->OptionListHead)) { | |
| break; | |
| } | |
| OrderList = (EFI_IFR_ORDERED_LIST *)Question->OpCode; | |
| Link = GetFirstNode (&Question->OptionListHead); | |
| OneOfOption = DISPLAY_QUESTION_OPTION_FROM_LINK (Link); | |
| ValueType = OneOfOption->OptionOpCode->Type; | |
| ValueArray = Question->CurrentValue.Buffer; | |
| if (Selected) { | |
| // | |
| // Go ask for input | |
| // | |
| Status = GetSelectionInputPopUp (MenuOption); | |
| } else { | |
| // | |
| // We now know how many strings we will have, so we can allocate the | |
| // space required for the array or strings. | |
| // | |
| MaxLen = OrderList->MaxContainers * BufferSize / sizeof (CHAR16); | |
| *OptionString = AllocateZeroPool (MaxLen * sizeof (CHAR16)); | |
| ASSERT (*OptionString); | |
| HiiValue.Type = ValueType; | |
| HiiValue.Value.u64 = 0; | |
| for (Index = 0; Index < OrderList->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) { | |
| // | |
| // Print debug msg for the mistach menu. | |
| // | |
| PrintMismatchMenuInfo (MenuOption); | |
| if (SkipErrorValue) { | |
| // | |
| // Just try to get the option string, skip the value which not has option. | |
| // | |
| continue; | |
| } | |
| // | |
| // Show error message | |
| // | |
| do { | |
| CreateDialog (&Key, gEmptyString, gOptionMismatch, gPressEnter, gEmptyString, NULL); | |
| } while (Key.UnicodeChar != CHAR_CARRIAGE_RETURN); | |
| // | |
| // The initial value of the orderedlist is invalid, force to be valid value | |
| // Exit current DisplayForm with new value. | |
| // | |
| gUserInput->SelectedStatement = Question; | |
| gMisMatch = TRUE; | |
| ValueArray = AllocateZeroPool (Question->CurrentValue.BufferLen); | |
| ASSERT (ValueArray != NULL); | |
| gUserInput->InputValue.Buffer = ValueArray; | |
| gUserInput->InputValue.BufferLen = Question->CurrentValue.BufferLen; | |
| gUserInput->InputValue.Type = Question->CurrentValue.Type; | |
| Link = GetFirstNode (&Question->OptionListHead); | |
| Index2 = 0; | |
| while (!IsNull (&Question->OptionListHead, Link) && Index2 < OrderList->MaxContainers) { | |
| Option = DISPLAY_QUESTION_OPTION_FROM_LINK (Link); | |
| Link = GetNextNode (&Question->OptionListHead, Link); | |
| SetArrayData (ValueArray, ValueType, Index2, Option->OptionOpCode->Value.u64); | |
| Index2++; | |
| } | |
| SetArrayData (ValueArray, ValueType, Index2, 0); | |
| FreePool (*OptionString); | |
| *OptionString = NULL; | |
| return EFI_NOT_FOUND; | |
| } | |
| Character[0] = LEFT_ONEOF_DELIMITER; | |
| NewStrCat (OptionString[0], MaxLen, Character); | |
| StringPtr = GetToken (OneOfOption->OptionOpCode->Option, gFormData->HiiHandle); | |
| ASSERT (StringPtr != NULL); | |
| NewStrCat (OptionString[0], MaxLen, StringPtr); | |
| Character[0] = RIGHT_ONEOF_DELIMITER; | |
| NewStrCat (OptionString[0], MaxLen, Character); | |
| Character[0] = CHAR_CARRIAGE_RETURN; | |
| NewStrCat (OptionString[0], MaxLen, Character); | |
| FreePool (StringPtr); | |
| } | |
| // | |
| // If valid option more than the max container, skip these options. | |
| // | |
| if (Index >= OrderList->MaxContainers) { | |
| break; | |
| } | |
| // | |
| // Search the other options, try to find the one not in the container. | |
| // | |
| Link = GetFirstNode (&Question->OptionListHead); | |
| while (!IsNull (&Question->OptionListHead, Link)) { | |
| OneOfOption = DISPLAY_QUESTION_OPTION_FROM_LINK (Link); | |
| Link = GetNextNode (&Question->OptionListHead, Link); | |
| if (FindArrayData (ValueArray, ValueType, OneOfOption->OptionOpCode->Value.u64, NULL)) { | |
| continue; | |
| } | |
| // | |
| // Print debug msg for the mistach menu. | |
| // | |
| PrintMismatchMenuInfo (MenuOption); | |
| if (SkipErrorValue) { | |
| // | |
| // Not report error, just get the correct option string info. | |
| // | |
| Character[0] = LEFT_ONEOF_DELIMITER; | |
| NewStrCat (OptionString[0], MaxLen, Character); | |
| StringPtr = GetToken (OneOfOption->OptionOpCode->Option, gFormData->HiiHandle); | |
| ASSERT (StringPtr != NULL); | |
| NewStrCat (OptionString[0], MaxLen, StringPtr); | |
| Character[0] = RIGHT_ONEOF_DELIMITER; | |
| NewStrCat (OptionString[0], MaxLen, Character); | |
| Character[0] = CHAR_CARRIAGE_RETURN; | |
| NewStrCat (OptionString[0], MaxLen, Character); | |
| FreePool (StringPtr); | |
| continue; | |
| } | |
| if (!ValueInvalid) { | |
| ValueInvalid = TRUE; | |
| // | |
| // Show error message | |
| // | |
| do { | |
| CreateDialog (&Key, gEmptyString, gOptionMismatch, gPressEnter, gEmptyString, NULL); | |
| } while (Key.UnicodeChar != CHAR_CARRIAGE_RETURN); | |
| // | |
| // The initial value of the orderedlist is invalid, force to be valid value | |
| // Exit current DisplayForm with new value. | |
| // | |
| gUserInput->SelectedStatement = Question; | |
| gMisMatch = TRUE; | |
| ValueArray = AllocateCopyPool (Question->CurrentValue.BufferLen, Question->CurrentValue.Buffer); | |
| ASSERT (ValueArray != NULL); | |
| gUserInput->InputValue.Buffer = ValueArray; | |
| gUserInput->InputValue.BufferLen = Question->CurrentValue.BufferLen; | |
| gUserInput->InputValue.Type = Question->CurrentValue.Type; | |
| } | |
| SetArrayData (ValueArray, ValueType, Index++, OneOfOption->OptionOpCode->Value.u64); | |
| } | |
| if (ValueInvalid) { | |
| FreePool (*OptionString); | |
| *OptionString = NULL; | |
| return EFI_NOT_FOUND; | |
| } | |
| } | |
| 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 (MenuOption); | |
| } else { | |
| MaxLen = BufferSize / sizeof (CHAR16); | |
| *OptionString = AllocateZeroPool (BufferSize); | |
| ASSERT (*OptionString); | |
| OneOfOption = ValueToOption (Question, QuestionValue); | |
| if (OneOfOption == NULL) { | |
| // | |
| // Print debug msg for the mistach menu. | |
| // | |
| PrintMismatchMenuInfo (MenuOption); | |
| if (SkipErrorValue) { | |
| // | |
| // Not report error, just get the correct option string info. | |
| // | |
| Link = GetFirstNode (&Question->OptionListHead); | |
| OneOfOption = DISPLAY_QUESTION_OPTION_FROM_LINK (Link); | |
| } else { | |
| // | |
| // Show error message | |
| // | |
| do { | |
| CreateDialog (&Key, gEmptyString, gOptionMismatch, gPressEnter, gEmptyString, NULL); | |
| } while (Key.UnicodeChar != CHAR_CARRIAGE_RETURN); | |
| // | |
| // Force the Question value to be valid | |
| // Exit current DisplayForm with new value. | |
| // | |
| Link = GetFirstNode (&Question->OptionListHead); | |
| Option = DISPLAY_QUESTION_OPTION_FROM_LINK (Link); | |
| gUserInput->InputValue.Type = Option->OptionOpCode->Type; | |
| switch (gUserInput->InputValue.Type) { | |
| case EFI_IFR_TYPE_NUM_SIZE_8: | |
| gUserInput->InputValue.Value.u8 = Option->OptionOpCode->Value.u8; | |
| break; | |
| case EFI_IFR_TYPE_NUM_SIZE_16: | |
| CopyMem (&gUserInput->InputValue.Value.u16, &Option->OptionOpCode->Value.u16, sizeof (UINT16)); | |
| break; | |
| case EFI_IFR_TYPE_NUM_SIZE_32: | |
| CopyMem (&gUserInput->InputValue.Value.u32, &Option->OptionOpCode->Value.u32, sizeof (UINT32)); | |
| break; | |
| case EFI_IFR_TYPE_NUM_SIZE_64: | |
| CopyMem (&gUserInput->InputValue.Value.u64, &Option->OptionOpCode->Value.u64, sizeof (UINT64)); | |
| break; | |
| default: | |
| ASSERT (FALSE); | |
| break; | |
| } | |
| gUserInput->SelectedStatement = Question; | |
| gMisMatch = TRUE; | |
| FreePool (*OptionString); | |
| *OptionString = NULL; | |
| return EFI_NOT_FOUND; | |
| } | |
| } | |
| Character[0] = LEFT_ONEOF_DELIMITER; | |
| NewStrCat (OptionString[0], MaxLen, Character); | |
| StringPtr = GetToken (OneOfOption->OptionOpCode->Option, gFormData->HiiHandle); | |
| ASSERT (StringPtr != NULL); | |
| NewStrCat (OptionString[0], MaxLen, StringPtr); | |
| Character[0] = RIGHT_ONEOF_DELIMITER; | |
| NewStrCat (OptionString[0], MaxLen, Character); | |
| FreePool (StringPtr); | |
| } | |
| break; | |
| case EFI_IFR_CHECKBOX_OP: | |
| if (Selected) { | |
| // | |
| // Since this is a BOOLEAN operation, flip it upon selection | |
| // | |
| gUserInput->InputValue.Type = QuestionValue->Type; | |
| gUserInput->InputValue.Value.b = (BOOLEAN)(QuestionValue->Value.b ? FALSE : TRUE); | |
| // | |
| // Perform inconsistent check | |
| // | |
| return EFI_SUCCESS; | |
| } else { | |
| *OptionString = AllocateZeroPool (BufferSize); | |
| ASSERT (*OptionString); | |
| *OptionString[0] = LEFT_CHECKBOX_DELIMITER; | |
| 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 (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 (MenuOption); | |
| } else { | |
| *OptionString = AllocateZeroPool (BufferSize); | |
| ASSERT (*OptionString); | |
| switch (MenuOption->Sequence) { | |
| case 0: | |
| *OptionString[0] = LEFT_NUMERIC_DELIMITER; | |
| if (QuestionValue->Value.date.Month == 0xff) { | |
| UnicodeSPrint (OptionString[0] + 1, 21 * sizeof (CHAR16), L"??"); | |
| } else { | |
| 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' '); | |
| if (QuestionValue->Value.date.Day == 0xff) { | |
| UnicodeSPrint (OptionString[0] + 4, 21 * sizeof (CHAR16), L"??"); | |
| } else { | |
| 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' '); | |
| if (QuestionValue->Value.date.Year == 0xff) { | |
| UnicodeSPrint (OptionString[0] + 7, 21 * sizeof (CHAR16), L"????"); | |
| } else { | |
| 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 (MenuOption); | |
| } else { | |
| *OptionString = AllocateZeroPool (BufferSize); | |
| ASSERT (*OptionString); | |
| switch (MenuOption->Sequence) { | |
| case 0: | |
| *OptionString[0] = LEFT_NUMERIC_DELIMITER; | |
| if (QuestionValue->Value.time.Hour == 0xff) { | |
| UnicodeSPrint (OptionString[0] + 1, 21 * sizeof (CHAR16), L"??"); | |
| } else { | |
| 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' '); | |
| if (QuestionValue->Value.time.Minute == 0xff) { | |
| UnicodeSPrint (OptionString[0] + 4, 21 * sizeof (CHAR16), L"??"); | |
| } else { | |
| 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' '); | |
| if (QuestionValue->Value.time.Second == 0xff) { | |
| UnicodeSPrint (OptionString[0] + 7, 21 * sizeof (CHAR16), L"??"); | |
| } else { | |
| 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 (Question->CurrentValue.BufferLen + sizeof (CHAR16)); | |
| ASSERT (StringPtr); | |
| CopyMem (StringPtr, Question->CurrentValue.Buffer, Question->CurrentValue.BufferLen); | |
| Status = ReadString (MenuOption, gPromptForData, StringPtr); | |
| if (EFI_ERROR (Status)) { | |
| FreePool (StringPtr); | |
| return Status; | |
| } | |
| gUserInput->InputValue.Buffer = AllocateCopyPool (Question->CurrentValue.BufferLen, StringPtr); | |
| gUserInput->InputValue.BufferLen = Question->CurrentValue.BufferLen; | |
| gUserInput->InputValue.Type = Question->CurrentValue.Type; | |
| gUserInput->InputValue.Value.string = HiiSetString (gFormData->HiiHandle, gUserInput->InputValue.Value.string, StringPtr, NULL); | |
| FreePool (StringPtr); | |
| return EFI_SUCCESS; | |
| } else { | |
| *OptionString = AllocateZeroPool (BufferSize); | |
| ASSERT (*OptionString); | |
| if (((CHAR16 *)Question->CurrentValue.Buffer)[0] == 0x0000) { | |
| *(OptionString[0]) = '_'; | |
| } else { | |
| if (Question->CurrentValue.BufferLen < BufferSize) { | |
| BufferSize = Question->CurrentValue.BufferLen; | |
| } | |
| CopyMem (OptionString[0], (CHAR16 *)Question->CurrentValue.Buffer, BufferSize); | |
| } | |
| } | |
| break; | |
| case EFI_IFR_PASSWORD_OP: | |
| if (Selected) { | |
| Status = PasswordProcess (MenuOption); | |
| } | |
| 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; | |
| } |