2019-09-03 11:58:42 +02:00
|
|
|
/** @file
|
|
|
|
Implementation for handling the User Interface option processing.
|
|
|
|
|
|
|
|
|
|
|
|
Copyright (c) 2004 - 2018, 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) {
|
2020-04-23 11:08:10 +02:00
|
|
|
FreePool(Str1);
|
2019-09-03 11:58:42 +02:00
|
|
|
return EFI_NOT_FOUND;
|
|
|
|
}
|
|
|
|
|
|
|
|
*Result = StrCmp (Str1, Str2);
|
|
|
|
|
2020-04-23 11:08:10 +02:00
|
|
|
FreePool(Str1);
|
|
|
|
FreePool(Str2);
|
2019-09-03 11:58:42 +02:00
|
|
|
|
|
|
|
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;
|
|
|
|
|
2020-04-28 12:49:24 +02:00
|
|
|
StringPtr = AllocateZeroPool((Maximum + 1) * sizeof (CHAR16));
|
2019-09-03 11:58:42 +02:00
|
|
|
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);
|
|
|
|
}
|
2020-04-23 11:08:10 +02:00
|
|
|
FreePool(StringPtr);
|
2019-09-03 11:58:42 +02:00
|
|
|
return EFI_SUCCESS;
|
|
|
|
}
|
|
|
|
|
2020-04-23 11:08:10 +02:00
|
|
|
if (EFI_ERROR(Status)) {
|
2019-09-03 11:58:42 +02:00
|
|
|
//
|
|
|
|
// Old password exist, ask user for the old password
|
|
|
|
//
|
|
|
|
Status = ReadString (MenuOption, gPromptForPassword, StringPtr);
|
2020-04-23 11:08:10 +02:00
|
|
|
if (EFI_ERROR(Status)) {
|
|
|
|
FreePool(StringPtr);
|
2019-09-03 11:58:42 +02:00
|
|
|
return Status;
|
|
|
|
}
|
|
|
|
|
|
|
|
//
|
|
|
|
// Check user input old password
|
|
|
|
//
|
|
|
|
Status = Question->PasswordCheck (gFormData, Question, StringPtr);
|
2020-04-23 11:08:10 +02:00
|
|
|
if (EFI_ERROR(Status)) {
|
2019-09-03 11:58:42 +02:00
|
|
|
if (Status == EFI_NOT_READY) {
|
|
|
|
//
|
|
|
|
// Typed in old password incorrect
|
|
|
|
//
|
|
|
|
PasswordInvalid ();
|
|
|
|
} else {
|
|
|
|
Status = EFI_SUCCESS;
|
|
|
|
}
|
|
|
|
|
2020-04-23 11:08:10 +02:00
|
|
|
FreePool(StringPtr);
|
2019-09-03 11:58:42 +02:00
|
|
|
return Status;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
//
|
|
|
|
// Ask for new password
|
|
|
|
//
|
|
|
|
ZeroMem (StringPtr, (Maximum + 1) * sizeof (CHAR16));
|
|
|
|
Status = ReadString (MenuOption, gPromptForNewPassword, StringPtr);
|
2020-04-23 11:08:10 +02:00
|
|
|
if (EFI_ERROR(Status)) {
|
2019-09-03 11:58:42 +02:00
|
|
|
//
|
|
|
|
// Reset state machine for password
|
|
|
|
//
|
|
|
|
Question->PasswordCheck (gFormData, Question, NULL);
|
2020-04-23 11:08:10 +02:00
|
|
|
FreePool(StringPtr);
|
2019-09-03 11:58:42 +02:00
|
|
|
return Status;
|
|
|
|
}
|
|
|
|
|
|
|
|
//
|
|
|
|
// Confirm new password
|
|
|
|
//
|
2020-04-28 12:49:24 +02:00
|
|
|
TempString = AllocateZeroPool((Maximum + 1) * sizeof (CHAR16));
|
2019-09-03 11:58:42 +02:00
|
|
|
ASSERT (TempString);
|
|
|
|
Status = ReadString (MenuOption, gConfirmPassword, TempString);
|
2020-04-23 11:08:10 +02:00
|
|
|
if (EFI_ERROR(Status)) {
|
2019-09-03 11:58:42 +02:00
|
|
|
//
|
|
|
|
// Reset state machine for password
|
|
|
|
//
|
|
|
|
Question->PasswordCheck (gFormData, Question, NULL);
|
2020-04-23 11:08:10 +02:00
|
|
|
FreePool(StringPtr);
|
|
|
|
FreePool(TempString);
|
2019-09-03 11:58:42 +02:00
|
|
|
return Status;
|
|
|
|
}
|
|
|
|
|
|
|
|
//
|
|
|
|
// Compare two typed-in new passwords
|
|
|
|
//
|
|
|
|
if (StrCmp (StringPtr, TempString) == 0) {
|
2020-04-27 17:16:43 +02:00
|
|
|
gUserInput->InputValue.Buffer = AllocateCopyPool(Question->CurrentValue.BufferLen, StringPtr);
|
2019-09-03 11:58:42 +02:00
|
|
|
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));
|
2020-04-23 11:08:10 +02:00
|
|
|
FreePool(TempString);
|
|
|
|
FreePool(StringPtr);
|
2019-09-03 11:58:42 +02:00
|
|
|
|
|
|
|
return Status;
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
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);
|
2020-04-28 12:49:24 +02:00
|
|
|
*OptionString = AllocateZeroPool(MaxLen * sizeof (CHAR16));
|
2019-09-03 11:58:42 +02:00
|
|
|
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) {
|
|
|
|
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;
|
2020-04-28 12:49:24 +02:00
|
|
|
ValueArray = AllocateZeroPool(Question->CurrentValue.BufferLen);
|
2019-09-03 11:58:42 +02:00
|
|
|
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);
|
|
|
|
|
2020-04-23 11:08:10 +02:00
|
|
|
FreePool(*OptionString);
|
2019-09-03 11:58:42 +02:00
|
|
|
*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);
|
2020-04-23 11:08:10 +02:00
|
|
|
FreePool(StringPtr);
|
2019-09-03 11:58:42 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
//
|
|
|
|
// 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;
|
|
|
|
}
|
|
|
|
|
|
|
|
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);
|
2020-04-23 11:08:10 +02:00
|
|
|
FreePool(StringPtr);
|
2019-09-03 11:58:42 +02:00
|
|
|
|
|
|
|
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;
|
2020-04-27 17:16:43 +02:00
|
|
|
ValueArray = AllocateCopyPool(Question->CurrentValue.BufferLen, Question->CurrentValue.Buffer);
|
2019-09-03 11:58:42 +02:00
|
|
|
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) {
|
2020-04-23 11:08:10 +02:00
|
|
|
FreePool(*OptionString);
|
2019-09-03 11:58:42 +02:00
|
|
|
*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);
|
2020-04-28 12:49:24 +02:00
|
|
|
*OptionString = AllocateZeroPool(BufferSize);
|
2019-09-03 11:58:42 +02:00
|
|
|
ASSERT (*OptionString);
|
|
|
|
|
|
|
|
OneOfOption = ValueToOption (Question, QuestionValue);
|
|
|
|
if (OneOfOption == NULL) {
|
|
|
|
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;
|
2020-04-23 11:08:10 +02:00
|
|
|
FreePool(*OptionString);
|
2019-09-03 11:58:42 +02:00
|
|
|
*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);
|
|
|
|
|
2020-04-23 11:08:10 +02:00
|
|
|
FreePool(StringPtr);
|
2019-09-03 11:58:42 +02:00
|
|
|
}
|
|
|
|
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 {
|
2020-04-28 12:49:24 +02:00
|
|
|
*OptionString = AllocateZeroPool(BufferSize);
|
2019-09-03 11:58:42 +02:00
|
|
|
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 {
|
2020-04-28 12:49:24 +02:00
|
|
|
*OptionString = AllocateZeroPool(BufferSize);
|
2019-09-03 11:58:42 +02:00
|
|
|
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 {
|
2020-04-28 12:49:24 +02:00
|
|
|
*OptionString = AllocateZeroPool(BufferSize);
|
2019-09-03 11:58:42 +02:00
|
|
|
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 {
|
2020-04-28 12:49:24 +02:00
|
|
|
*OptionString = AllocateZeroPool(BufferSize);
|
2019-09-03 11:58:42 +02:00
|
|
|
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) {
|
2020-04-28 12:49:24 +02:00
|
|
|
StringPtr = AllocateZeroPool(Question->CurrentValue.BufferLen + sizeof (CHAR16));
|
2019-09-03 11:58:42 +02:00
|
|
|
ASSERT (StringPtr);
|
|
|
|
CopyMem(StringPtr, Question->CurrentValue.Buffer, Question->CurrentValue.BufferLen);
|
|
|
|
|
|
|
|
Status = ReadString (MenuOption, gPromptForData, StringPtr);
|
2020-04-23 11:08:10 +02:00
|
|
|
if (EFI_ERROR(Status)) {
|
|
|
|
FreePool(StringPtr);
|
2019-09-03 11:58:42 +02:00
|
|
|
return Status;
|
|
|
|
}
|
|
|
|
|
2020-04-27 17:16:43 +02:00
|
|
|
gUserInput->InputValue.Buffer = AllocateCopyPool(Question->CurrentValue.BufferLen, StringPtr);
|
2019-09-03 11:58:42 +02:00
|
|
|
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);
|
2020-04-23 11:08:10 +02:00
|
|
|
FreePool(StringPtr);
|
2019-09-03 11:58:42 +02:00
|
|
|
return EFI_SUCCESS;
|
|
|
|
} else {
|
2020-04-28 12:49:24 +02:00
|
|
|
*OptionString = AllocateZeroPool(BufferSize);
|
2019-09-03 11:58:42 +02:00
|
|
|
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 ++;
|
2020-04-23 11:08:10 +02:00
|
|
|
FreePool(OutputString);
|
2019-09-03 11:58:42 +02:00
|
|
|
}
|
|
|
|
*EachLineWidth = MaxStringLen;
|
|
|
|
|
2020-04-28 12:49:24 +02:00
|
|
|
*FormattedString = AllocateZeroPool(TotalRowNum * MaxStringLen * sizeof (CHAR16));
|
2019-09-03 11:58:42 +02:00
|
|
|
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 ++;
|
2020-04-23 11:08:10 +02:00
|
|
|
FreePool(OutputString);
|
2019-09-03 11:58:42 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
return TotalRowNum;
|
|
|
|
}
|