diff options
author | qwang12 <qwang12@6f19259b-4bc3-4df7-8a09-765794883524> | 2008-01-21 14:39:56 +0000 |
---|---|---|
committer | qwang12 <qwang12@6f19259b-4bc3-4df7-8a09-765794883524> | 2008-01-21 14:39:56 +0000 |
commit | 93e3992d1ea50fb30c48f498d257d4e66252dd9b (patch) | |
tree | b76adcd31d2017cd76317f21be967ad3cb05305e /MdeModulePkg/Universal/SetupBrowserDxe | |
parent | f79314fa8f44a79e862d2877e5a9b1a3a9f96791 (diff) | |
download | edk2-platforms-93e3992d1ea50fb30c48f498d257d4e66252dd9b.tar.xz |
UEFI HII: Merge UEFI HII support changes from branch.
git-svn-id: https://edk2.svn.sourceforge.net/svnroot/edk2/trunk/edk2@4599 6f19259b-4bc3-4df7-8a09-765794883524
Diffstat (limited to 'MdeModulePkg/Universal/SetupBrowserDxe')
17 files changed, 13922 insertions, 0 deletions
diff --git a/MdeModulePkg/Universal/SetupBrowserDxe/Colors.h b/MdeModulePkg/Universal/SetupBrowserDxe/Colors.h new file mode 100644 index 0000000000..1b355ec5b6 --- /dev/null +++ b/MdeModulePkg/Universal/SetupBrowserDxe/Colors.h @@ -0,0 +1,55 @@ +/** @file + +Copyright (c) 2004, Intel Corporation +All rights reserved. This program and the accompanying materials +are licensed and made available under the terms and conditions of the BSD License +which accompanies this distribution. The full text of the license may be found at +http://opensource.org/licenses/bsd-license.php + +THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, +WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. + +Module Name: + + Colors.h + +Abstract: + + +Revision History + + +**/ + +#ifndef _COLORS_H +#define _COLORS_H + +// +// Screen Color Settings +// +#define PICKLIST_HIGHLIGHT_TEXT EFI_WHITE +#define PICKLIST_HIGHLIGHT_BACKGROUND EFI_BACKGROUND_CYAN +#define TITLE_TEXT EFI_WHITE +#define TITLE_BACKGROUND EFI_BACKGROUND_BLUE +#define KEYHELP_TEXT EFI_LIGHTGRAY +#define KEYHELP_BACKGROUND EFI_BACKGROUND_BLACK +#define SUBTITLE_TEXT EFI_BLUE +#define SUBTITLE_BACKGROUND EFI_BACKGROUND_LIGHTGRAY +#define BANNER_TEXT EFI_BLUE +#define BANNER_BACKGROUND EFI_BACKGROUND_LIGHTGRAY +#define FIELD_TEXT EFI_BLACK +#define FIELD_TEXT_GRAYED EFI_DARKGRAY +#define FIELD_BACKGROUND EFI_BACKGROUND_LIGHTGRAY +#define FIELD_TEXT_HIGHLIGHT EFI_LIGHTGRAY +#define FIELD_BACKGROUND_HIGHLIGHT EFI_BACKGROUND_BLACK +#define POPUP_TEXT EFI_LIGHTGRAY +#define POPUP_BACKGROUND EFI_BACKGROUND_BLUE +#define POPUP_INVERSE_TEXT EFI_LIGHTGRAY +#define POPUP_INVERSE_BACKGROUND EFI_BACKGROUND_BLACK +#define HELP_TEXT EFI_BLUE +#define ERROR_TEXT EFI_RED | EFI_BRIGHT +#define INFO_TEXT EFI_YELLOW | EFI_BRIGHT +#define ARROW_TEXT EFI_RED | EFI_BRIGHT +#define ARROW_BACKGROUND EFI_BACKGROUND_LIGHTGRAY + +#endif diff --git a/MdeModulePkg/Universal/SetupBrowserDxe/Expression.c b/MdeModulePkg/Universal/SetupBrowserDxe/Expression.c new file mode 100644 index 0000000000..adeada2b29 --- /dev/null +++ b/MdeModulePkg/Universal/SetupBrowserDxe/Expression.c @@ -0,0 +1,1938 @@ +/** @file + +Copyright (c) 2007, Intel Corporation +All rights reserved. This program and the accompanying materials +are licensed and made available under the terms and conditions of the BSD License +which accompanies this distribution. The full text of the license may be found at +http://opensource.org/licenses/bsd-license.php + +THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, +WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. + +Module Name: + + Expression.c + +Abstract: + + Expression evaluation. + + +**/ + +#include "Ui.h" +#include "Setup.h" + +// +// Global stack used to evaluate boolean expresions +// +EFI_HII_VALUE *mOpCodeScopeStack = NULL; +EFI_HII_VALUE *mOpCodeScopeStackEnd = NULL; +EFI_HII_VALUE *mOpCodeScopeStackPointer = NULL; + +EFI_HII_VALUE *mExpressionEvaluationStack = NULL; +EFI_HII_VALUE *mExpressionEvaluationStackEnd = NULL; +EFI_HII_VALUE *mExpressionEvaluationStackPointer = NULL; + +// +// Unicode collation protocol interface +// +EFI_UNICODE_COLLATION_PROTOCOL *mUnicodeCollation = NULL; + + +/** + Grow size of the stack + + @param Stack On input: old stack; On output: new stack + @param StackPtr On input: old stack pointer; On output: new stack + pointer + @param StackPtr On input: old stack end; On output: new stack end + + @retval EFI_SUCCESS Grow stack success. + @retval EFI_OUT_OF_RESOURCES No enough memory for stack space. + +**/ +STATIC +EFI_STATUS +GrowStack ( + IN OUT EFI_HII_VALUE **Stack, + IN OUT EFI_HII_VALUE **StackPtr, + IN OUT EFI_HII_VALUE **StackEnd + ) +{ + UINTN Size; + EFI_HII_VALUE *NewStack; + + Size = EXPRESSION_STACK_SIZE_INCREMENT; + if (*StackPtr != NULL) { + Size = Size + (*StackEnd - *Stack); + } + + NewStack = AllocatePool (Size * sizeof (EFI_HII_VALUE)); + if (NewStack == NULL) { + return EFI_OUT_OF_RESOURCES; + } + + if (*StackPtr != NULL) { + // + // Copy from Old Stack to the New Stack + // + CopyMem ( + NewStack, + *Stack, + (*StackEnd - *Stack) * sizeof (EFI_HII_VALUE) + ); + + // + // Free The Old Stack + // + gBS->FreePool (*Stack); + } + + // + // Make the Stack pointer point to the old data in the new stack + // + *StackPtr = NewStack + (*StackPtr - *Stack); + *Stack = NewStack; + *StackEnd = NewStack + Size; + + return EFI_SUCCESS; +} + + +/** + Push an element onto the Boolean Stack + + @param Stack On input: old stack; On output: new stack + @param StackPtr On input: old stack pointer; On output: new stack + pointer + @param StackPtr On input: old stack end; On output: new stack end + @param Data Data to push. + + @retval EFI_SUCCESS Push stack success. + +**/ +EFI_STATUS +PushStack ( + IN OUT EFI_HII_VALUE **Stack, + IN OUT EFI_HII_VALUE **StackPtr, + IN OUT EFI_HII_VALUE **StackEnd, + IN EFI_HII_VALUE *Data + ) +{ + EFI_STATUS Status; + + // + // Check for a stack overflow condition + // + if (*StackPtr >= *StackEnd) { + // + // Grow the stack + // + Status = GrowStack (Stack, StackPtr, StackEnd); + if (EFI_ERROR (Status)) { + return Status; + } + } + + // + // Push the item onto the stack + // + CopyMem (*StackPtr, Data, sizeof (EFI_HII_VALUE)); + *StackPtr = *StackPtr + 1; + + return EFI_SUCCESS; +} + + +/** + Pop an element from the stack. + + @param Stack On input: old stack; On output: new stack + @param StackPtr On input: old stack pointer; On output: new stack + pointer + @param StackPtr On input: old stack end; On output: new stack end + @param Data Data to pop. + + @retval EFI_SUCCESS The value was popped onto the stack. + @retval EFI_ACCESS_DENIED The pop operation underflowed the stack + +**/ +EFI_STATUS +PopStack ( + IN OUT EFI_HII_VALUE **Stack, + IN OUT EFI_HII_VALUE **StackPtr, + IN OUT EFI_HII_VALUE **StackEnd, + OUT EFI_HII_VALUE *Data + ) +{ + // + // Check for a stack underflow condition + // + if (*StackPtr == *Stack) { + return EFI_ACCESS_DENIED; + } + + // + // Pop the item off the stack + // + *StackPtr = *StackPtr - 1; + CopyMem (Data, *StackPtr, sizeof (EFI_HII_VALUE)); + return EFI_SUCCESS; +} + + +/** + Reset stack pointer to begin of the stack. + + None. + + @return None. + +**/ +VOID +ResetScopeStack ( + VOID + ) +{ + mOpCodeScopeStackPointer = mOpCodeScopeStack; +} + + +/** + Push an Operand onto the Stack + + @param Operand Operand to push. + + @retval EFI_SUCCESS The value was pushed onto the stack. + @retval EFI_OUT_OF_RESOURCES There is not enough system memory to grow the + stack. + +**/ +EFI_STATUS +PushScope ( + IN UINT8 Operand + ) +{ + EFI_HII_VALUE Data; + + Data.Type = EFI_IFR_TYPE_NUM_SIZE_8; + Data.Value.u8 = Operand; + + return PushStack ( + &mOpCodeScopeStack, + &mOpCodeScopeStackPointer, + &mOpCodeScopeStackEnd, + &Data + ); +} + + +/** + Pop an Operand from the Stack + + @param Operand Operand to pop. + + @retval EFI_SUCCESS The value was pushed onto the stack. + @retval EFI_OUT_OF_RESOURCES There is not enough system memory to grow the + stack. + +**/ +EFI_STATUS +PopScope ( + OUT UINT8 *Operand + ) +{ + EFI_STATUS Status; + EFI_HII_VALUE Data; + + Status = PopStack ( + &mOpCodeScopeStack, + &mOpCodeScopeStackPointer, + &mOpCodeScopeStackEnd, + &Data + ); + + *Operand = Data.Value.u8; + + return Status; +} + + +/** + Reset stack pointer to begin of the stack. + + None. + + @return None. + +**/ +VOID +ResetExpressionStack ( + VOID + ) +{ + mExpressionEvaluationStackPointer = mExpressionEvaluationStack; +} + + +/** + Push an Expression value onto the Stack + + @param Value Expression value to push. + + @retval EFI_SUCCESS The value was pushed onto the stack. + @retval EFI_OUT_OF_RESOURCES There is not enough system memory to grow the + stack. + +**/ +EFI_STATUS +PushExpression ( + IN EFI_HII_VALUE *Value + ) +{ + return PushStack ( + &mExpressionEvaluationStack, + &mExpressionEvaluationStackPointer, + &mExpressionEvaluationStackEnd, + Value + ); +} + + +/** + Pop an Expression value from the stack. + + @param Value Expression value to pop. + + @retval EFI_SUCCESS The value was popped onto the stack. + @retval EFI_ACCESS_DENIED The pop operation underflowed the stack + +**/ +EFI_STATUS +PopExpression ( + OUT EFI_HII_VALUE *Value + ) +{ + return PopStack ( + &mExpressionEvaluationStack, + &mExpressionEvaluationStackPointer, + &mExpressionEvaluationStackEnd, + Value + ); +} + + +/** + Get Form given its FormId. + + @param FormSet The formset which contains this form. + @param FormId Id of this form. + + @retval Pointer The form. + @retval NULL Specified Form is not found in the formset. + +**/ +FORM_BROWSER_FORM * +IdToForm ( + IN FORM_BROWSER_FORMSET *FormSet, + IN UINT16 FormId +) +{ + LIST_ENTRY *Link; + FORM_BROWSER_FORM *Form; + + Link = GetFirstNode (&FormSet->FormListHead); + while (!IsNull (&FormSet->FormListHead, Link)) { + Form = FORM_BROWSER_FORM_FROM_LINK (Link); + + if (Form->FormId == FormId) { + return Form; + } + + Link = GetNextNode (&FormSet->FormListHead, Link); + } + + return NULL; +} + + +/** + Search a Question in Form scope using its QuestionId. + + @param Form The form which contains this Question. + @param QuestionId Id of this Question. + + @retval Pointer The Question. + @retval NULL Specified Question not found in the form. + +**/ +FORM_BROWSER_STATEMENT * +IdToQuestion2 ( + IN FORM_BROWSER_FORM *Form, + IN UINT16 QuestionId + ) +{ + LIST_ENTRY *Link; + FORM_BROWSER_STATEMENT *Question; + + if (QuestionId == 0) { + // + // The value of zero is reserved + // + return NULL; + } + + Link = GetFirstNode (&Form->StatementListHead); + while (!IsNull (&Form->StatementListHead, Link)) { + Question = FORM_BROWSER_STATEMENT_FROM_LINK (Link); + + if (Question->QuestionId == QuestionId) { + return Question; + } + + Link = GetNextNode (&Form->StatementListHead, Link); + } + + return NULL; +} + + +/** + Search a Question in Formset scope using its QuestionId. + + @param FormSet The formset which contains this form. + @param Form The form which contains this Question. + @param QuestionId Id of this Question. + + @retval Pointer The Question. + @retval NULL Specified Question not found in the form. + +**/ +FORM_BROWSER_STATEMENT * +IdToQuestion ( + IN FORM_BROWSER_FORMSET *FormSet, + IN FORM_BROWSER_FORM *Form, + IN UINT16 QuestionId + ) +{ + LIST_ENTRY *Link; + FORM_BROWSER_STATEMENT *Question; + + // + // Search in the form scope first + // + Question = IdToQuestion2 (Form, QuestionId); + if (Question != NULL) { + return Question; + } + + // + // Search in the formset scope + // + Link = GetFirstNode (&FormSet->FormListHead); + while (!IsNull (&FormSet->FormListHead, Link)) { + Form = FORM_BROWSER_FORM_FROM_LINK (Link); + + Question = IdToQuestion2 (Form, QuestionId); + if (Question != NULL) { + return Question; + } + + Link = GetNextNode (&FormSet->FormListHead, Link); + } + + return NULL; +} + + +/** + Get Expression given its RuleId. + + @param Form The form which contains this Expression. + @param RuleId Id of this Expression. + + @retval Pointer The Expression. + @retval NULL Specified Expression not found in the form. + +**/ +FORM_EXPRESSION * +RuleIdToExpression ( + IN FORM_BROWSER_FORM *Form, + IN UINT8 RuleId + ) +{ + LIST_ENTRY *Link; + FORM_EXPRESSION *Expression; + + Link = GetFirstNode (&Form->ExpressionListHead); + while (!IsNull (&Form->ExpressionListHead, Link)) { + Expression = FORM_EXPRESSION_FROM_LINK (Link); + + if (Expression->Type == EFI_HII_EXPRESSION_RULE && Expression->RuleId == RuleId) { + return Expression; + } + + Link = GetNextNode (&Form->ExpressionListHead, Link); + } + + return NULL; +} + + +/** + Locate the Unicode Collation Protocol interface for later use. + + None. + + @retval EFI_SUCCESS Protocol interface initialize success. + @retval Other Protocol interface initialize failed. + +**/ +EFI_STATUS +InitializeUnicodeCollationProtocol ( + VOID + ) +{ + EFI_STATUS Status; + + if (mUnicodeCollation != NULL) { + return EFI_SUCCESS; + } + + // + // BUGBUG: Proper impelmentation is to locate all Unicode Collation Protocol + // instances first and then select one which support English language. + // Current implementation just pick the first instance. + // + Status = gBS->LocateProtocol ( + &gEfiUnicodeCollation2ProtocolGuid, + NULL, + (VOID **) &mUnicodeCollation + ); + return Status; +} + +VOID +IfrStrToUpper ( + CHAR16 *String + ) +{ + while (*String != 0) { + if ((*String >= 'a') && (*String <= 'z')) { + *String = (UINT16) ((*String) & ((UINT16) ~0x20)); + } + String++; + } +} + + +/** + Evaluate opcode EFI_IFR_TO_STRING. + + @param FormSet Formset which contains this opcode. + @param Format String format in EFI_IFR_TO_STRING. + @param Result Evaluation result for this opcode. + + @retval EFI_SUCCESS Opcode evaluation success. + @retval Other Opcode evaluation failed. + +**/ +EFI_STATUS +IfrToString ( + IN FORM_BROWSER_FORMSET *FormSet, + IN UINT8 Format, + OUT EFI_HII_VALUE *Result + ) +{ + EFI_STATUS Status; + EFI_HII_VALUE Value; + CHAR16 *String; + CHAR16 *PrintFormat; + CHAR16 Buffer[MAXIMUM_VALUE_CHARACTERS]; + UINTN BufferSize; + + Status = PopExpression (&Value); + if (EFI_ERROR (Status)) { + return Status; + } + + 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: + BufferSize = MAXIMUM_VALUE_CHARACTERS * sizeof (CHAR16); + switch (Format) { + case EFI_IFR_STRING_UNSIGNED_DEC: + case EFI_IFR_STRING_SIGNED_DEC: + PrintFormat = L"%ld"; + break; + + case EFI_IFR_STRING_LOWERCASE_HEX: + PrintFormat = L"%lx"; + break; + + case EFI_IFR_STRING_UPPERCASE_HEX: + PrintFormat = L"%lX"; + break; + + default: + return EFI_UNSUPPORTED; + } + UnicodeSPrint (Buffer, BufferSize, PrintFormat, Value.Value.u64); + String = Buffer; + break; + + case EFI_IFR_TYPE_STRING: + CopyMem (Result, &Value, sizeof (EFI_HII_VALUE)); + return EFI_SUCCESS; + + case EFI_IFR_TYPE_BOOLEAN: + String = (Value.Value.b) ? L"True" : L"False"; + break; + + default: + return EFI_UNSUPPORTED; + } + + Result->Type = EFI_IFR_TYPE_STRING; + Result->Value.string = NewString (String, FormSet->HiiHandle); + return EFI_SUCCESS; +} + + +/** + Evaluate opcode EFI_IFR_TO_UINT. + + @param FormSet Formset which contains this opcode. + @param Result Evaluation result for this opcode. + + @retval EFI_SUCCESS Opcode evaluation success. + @retval Other Opcode evaluation failed. + +**/ +EFI_STATUS +IfrToUint ( + IN FORM_BROWSER_FORMSET *FormSet, + OUT EFI_HII_VALUE *Result + ) +{ + EFI_STATUS Status; + EFI_HII_VALUE Value; + CHAR16 *String; + CHAR16 *StringPtr; + UINTN BufferSize; + + Status = PopExpression (&Value); + if (EFI_ERROR (Status)) { + return Status; + } + + if (Value.Type >= EFI_IFR_TYPE_OTHER) { + return EFI_UNSUPPORTED; + } + + Status = EFI_SUCCESS; + if (Value.Type == EFI_IFR_TYPE_STRING) { + String = GetToken (Value.Value.string, FormSet->HiiHandle); + if (String == NULL) { + return EFI_NOT_FOUND; + } + + IfrStrToUpper (String); + StringPtr = StrStr (String, L"0X"); + if (StringPtr != NULL) { + // + // Hex string + // + BufferSize = sizeof (UINT64); + Status = R8_HexStringToBuf ((UINT8 *) &Result->Value.u64, &BufferSize, StringPtr + 2, NULL); + } else { + // + // BUGBUG: Need handle decimal string + // + } + gBS->FreePool (String); + } else { + CopyMem (Result, &Value, sizeof (EFI_HII_VALUE)); + } + + Result->Type = EFI_IFR_TYPE_NUM_SIZE_64; + return Status; +} + + +/** + Evaluate opcode EFI_IFR_CATENATE. + + @param FormSet Formset which contains this opcode. + @param Result Evaluation result for this opcode. + + @retval EFI_SUCCESS Opcode evaluation success. + @retval Other Opcode evaluation failed. + +**/ +EFI_STATUS +IfrCatenate ( + IN FORM_BROWSER_FORMSET *FormSet, + OUT EFI_HII_VALUE *Result + ) +{ + EFI_STATUS Status; + EFI_HII_VALUE Value; + CHAR16 *String[2]; + UINTN Index; + CHAR16 *StringPtr; + UINTN Size; + + // + // String[0] - The second string + // String[1] - The first string + // + String[0] = NULL; + String[1] = NULL; + StringPtr = NULL; + Status = EFI_SUCCESS; + + for (Index = 0; Index < 2; Index++) { + Status = PopExpression (&Value); + if (EFI_ERROR (Status)) { + goto Done; + } + + if (Value.Type != EFI_IFR_TYPE_STRING) { + Status = EFI_UNSUPPORTED; + goto Done; + } + + String[Index] = GetToken (Value.Value.string, FormSet->HiiHandle); + if (String== NULL) { + Status = EFI_NOT_FOUND; + goto Done; + } + } + + Size = StrSize (String[0]); + StringPtr= AllocatePool (StrSize (String[1]) + Size); + ASSERT (StringPtr != NULL); + StrCpy (StringPtr, String[1]); + StrCat (StringPtr, String[0]); + + Result->Type = EFI_IFR_TYPE_STRING; + Result->Value.string = NewString (StringPtr, FormSet->HiiHandle); + +Done: + SafeFreePool (String[0]); + SafeFreePool (String[1]); + SafeFreePool (StringPtr); + + return Status; +} + + +/** + Evaluate opcode EFI_IFR_MATCH. + + @param FormSet Formset which contains this opcode. + @param Result Evaluation result for this opcode. + + @retval EFI_SUCCESS Opcode evaluation success. + @retval Other Opcode evaluation failed. + +**/ +EFI_STATUS +IfrMatch ( + IN FORM_BROWSER_FORMSET *FormSet, + OUT EFI_HII_VALUE *Result + ) +{ + EFI_STATUS Status; + EFI_HII_VALUE Value; + CHAR16 *String[2]; + UINTN Index; + + // + // String[0] - The string to search + // String[1] - pattern + // + String[0] = NULL; + String[1] = NULL; + Status = EFI_SUCCESS; + for (Index = 0; Index < 2; Index++) { + Status = PopExpression (&Value); + if (EFI_ERROR (Status)) { + goto Done; + } + + if (Value.Type != EFI_IFR_TYPE_STRING) { + Status = EFI_UNSUPPORTED; + goto Done; + } + + String[Index] = GetToken (Value.Value.string, FormSet->HiiHandle); + if (String== NULL) { + Status = EFI_NOT_FOUND; + goto Done; + } + } + + Result->Type = EFI_IFR_TYPE_BOOLEAN; + Result->Value.b = mUnicodeCollation->MetaiMatch (mUnicodeCollation, String[0], String[1]); + +Done: + SafeFreePool (String[0]); + SafeFreePool (String[1]); + + return Status; +} + + +/** + Evaluate opcode EFI_IFR_FIND. + + @param FormSet Formset which contains this opcode. + @param Format Case sensitive or insensitive. + @param Result Evaluation result for this opcode. + + @retval EFI_SUCCESS Opcode evaluation success. + @retval Other Opcode evaluation failed. + +**/ +EFI_STATUS +IfrFind ( + IN FORM_BROWSER_FORMSET *FormSet, + IN UINT8 Format, + OUT EFI_HII_VALUE *Result + ) +{ + EFI_STATUS Status; + EFI_HII_VALUE Value; + CHAR16 *String[2]; + UINTN Base; + CHAR16 *StringPtr; + UINTN Index; + + if (Format > EFI_IFR_FF_CASE_INSENSITIVE) { + return EFI_UNSUPPORTED; + } + + Status = PopExpression (&Value); + if (EFI_ERROR (Status)) { + return Status; + } + if (Value.Type > EFI_IFR_TYPE_NUM_SIZE_64) { + return EFI_UNSUPPORTED; + } + Base = (UINTN) Value.Value.u64; + + // + // String[0] - sub-string + // String[1] - The string to search + // + String[0] = NULL; + String[1] = NULL; + for (Index = 0; Index < 2; Index++) { + Status = PopExpression (&Value); + if (EFI_ERROR (Status)) { + goto Done; + } + + if (Value.Type != EFI_IFR_TYPE_STRING) { + Status = EFI_UNSUPPORTED; + goto Done; + } + + String[Index] = GetToken (Value.Value.string, FormSet->HiiHandle); + if (String== NULL) { + Status = EFI_NOT_FOUND; + goto Done; + } + + if (Format == EFI_IFR_FF_CASE_INSENSITIVE) { + // + // Case insensitive, convert both string to upper case + // + IfrStrToUpper (String[Index]); + } + } + + Result->Type = EFI_IFR_TYPE_NUM_SIZE_64; + if (Base >= StrLen (String[1])) { + Result->Value.u64 = 0xFFFFFFFFFFFFFFFF; + } else { + StringPtr = StrStr (String[1] + Base, String[0]); + Result->Value.u64 = (StringPtr == NULL) ? 0xFFFFFFFFFFFFFFFF : (StringPtr - String[1]); + } + +Done: + SafeFreePool (String[0]); + SafeFreePool (String[1]); + + return Status; +} + + +/** + Evaluate opcode EFI_IFR_MID. + + @param FormSet Formset which contains this opcode. + @param Result Evaluation result for this opcode. + + @retval EFI_SUCCESS Opcode evaluation success. + @retval Other Opcode evaluation failed. + +**/ +EFI_STATUS +IfrMid ( + IN FORM_BROWSER_FORMSET *FormSet, + OUT EFI_HII_VALUE *Result + ) +{ + EFI_STATUS Status; + EFI_HII_VALUE Value; + CHAR16 *String; + UINTN Base; + UINTN Length; + CHAR16 *SubString; + + Status = PopExpression (&Value); + if (EFI_ERROR (Status)) { + return Status; + } + if (Value.Type > EFI_IFR_TYPE_NUM_SIZE_64) { + return EFI_UNSUPPORTED; + } + Length = (UINTN) Value.Value.u64; + + Status = PopExpression (&Value); + if (EFI_ERROR (Status)) { + return Status; + } + if (Value.Type > EFI_IFR_TYPE_NUM_SIZE_64) { + return EFI_UNSUPPORTED; + } + Base = (UINTN) Value.Value.u64; + + Status = PopExpression (&Value); + if (EFI_ERROR (Status)) { + return Status; + } + if (Value.Type != EFI_IFR_TYPE_STRING) { + return EFI_UNSUPPORTED; + } + String = GetToken (Value.Value.string, FormSet->HiiHandle); + if (String == NULL) { + return EFI_NOT_FOUND; + } + + if (Length == 0 || Base >= StrLen (String)) { + SubString = gEmptyString; + } else { + SubString = String + Base; + if ((Base + Length) < StrLen (String)) { + SubString[Length] = L'\0'; + } + } + + Result->Type = EFI_IFR_TYPE_STRING; + Result->Value.string = NewString (SubString, FormSet->HiiHandle); + + gBS->FreePool (String); + + return Status; +} + + +/** + Evaluate opcode EFI_IFR_TOKEN. + + @param FormSet Formset which contains this opcode. + @param Result Evaluation result for this opcode. + + @retval EFI_SUCCESS Opcode evaluation success. + @retval Other Opcode evaluation failed. + +**/ +EFI_STATUS +IfrToken ( + IN FORM_BROWSER_FORMSET *FormSet, + OUT EFI_HII_VALUE *Result + ) +{ + EFI_STATUS Status; + EFI_HII_VALUE Value; + CHAR16 *String[2]; + UINTN Count; + CHAR16 *Delimiter; + CHAR16 *SubString; + CHAR16 *StringPtr; + UINTN Index; + + Status = PopExpression (&Value); + if (EFI_ERROR (Status)) { + return Status; + } + if (Value.Type > EFI_IFR_TYPE_NUM_SIZE_64) { + return EFI_UNSUPPORTED; + } + Count = (UINTN) Value.Value.u64; + + // + // String[0] - Delimiter + // String[1] - The string to search + // + String[0] = NULL; + String[1] = NULL; + for (Index = 0; Index < 2; Index++) { + Status = PopExpression (&Value); + if (EFI_ERROR (Status)) { + goto Done; + } + + if (Value.Type != EFI_IFR_TYPE_STRING) { + Status = EFI_UNSUPPORTED; + goto Done; + } + + String[Index] = GetToken (Value.Value.string, FormSet->HiiHandle); + if (String== NULL) { + Status = EFI_NOT_FOUND; + goto Done; + } + } + + Delimiter = String[0]; + SubString = String[1]; + while (Count > 0) { + SubString = StrStr (SubString, Delimiter); + if (SubString != NULL) { + // + // Skip over the delimiter + // + SubString = SubString + StrLen (Delimiter); + } else { + break; + } + Count--; + } + + if (SubString == NULL) { + // + // nth delimited sub-string not found, push an empty string + // + SubString = gEmptyString; + } else { + // + // Put a NULL terminator for nth delimited sub-string + // + StringPtr = StrStr (SubString, Delimiter); + if (StringPtr != NULL) { + *StringPtr = L'\0'; + } + } + + Result->Type = EFI_IFR_TYPE_STRING; + Result->Value.string = NewString (SubString, FormSet->HiiHandle); + +Done: + SafeFreePool (String[0]); + SafeFreePool (String[1]); + + return Status; +} + + +/** + Evaluate opcode EFI_IFR_SPAN. + + @param FormSet Formset which contains this opcode. + @param Flags FIRST_MATCHING or FIRST_NON_MATCHING. + @param Result Evaluation result for this opcode. + + @retval EFI_SUCCESS Opcode evaluation success. + @retval Other Opcode evaluation failed. + +**/ +EFI_STATUS +IfrSpan ( + IN FORM_BROWSER_FORMSET *FormSet, + IN UINT8 Flags, + OUT EFI_HII_VALUE *Result + ) +{ + EFI_STATUS Status; + EFI_HII_VALUE Value; + CHAR16 *String[2]; + CHAR16 *Charset; + UINTN Base; + UINTN Index; + CHAR16 *StringPtr; + BOOLEAN Found; + + Status = PopExpression (&Value); + if (EFI_ERROR (Status)) { + return Status; + } + if (Value.Type > EFI_IFR_TYPE_NUM_SIZE_64) { + return EFI_UNSUPPORTED; + } + Base = (UINTN) Value.Value.u64; + + // + // String[0] - Charset + // String[1] - The string to search + // + String[0] = NULL; + String[1] = NULL; + for (Index = 0; Index < 2; Index++) { + Status = PopExpression (&Value); + if (EFI_ERROR (Status)) { + goto Done; + } + + if (Value.Type != EFI_IFR_TYPE_STRING) { + Status = EFI_UNSUPPORTED; + goto Done; + } + + String[Index] = GetToken (Value.Value.string, FormSet->HiiHandle); + if (String== NULL) { + Status = EFI_NOT_FOUND; + goto Done; + } + } + + if (Base >= StrLen (String[1])) { + Status = EFI_UNSUPPORTED; + goto Done; + } + + Found = FALSE; + StringPtr = String[1] + Base; + Charset = String[0]; + while (*StringPtr != 0 && !Found) { + Index = 0; + while (Charset[Index] != 0) { + if (*StringPtr >= Charset[Index] && *StringPtr <= Charset[Index + 1]) { + if (Flags == EFI_IFR_FLAGS_FIRST_MATCHING) { + Found = TRUE; + break; + } + } else { + if (Flags == EFI_IFR_FLAGS_FIRST_NON_MATCHING) { + Found = TRUE; + break; + } + } + // + // Skip characters pair representing low-end of a range and high-end of a range + // + Index += 2; + } + + if (!Found) { + StringPtr++; + } + } + + Result->Type = EFI_IFR_TYPE_NUM_SIZE_64; + Result->Value.u64 = StringPtr - String[1]; + +Done: + SafeFreePool (String[0]); + SafeFreePool (String[1]); + + return Status; +} + + +/** + Zero extend integer/boolean/date/time to UINT64 for comparing. + + @param Value HII Value to be converted. + + @return None. + +**/ +VOID +ExtendValueToU64 ( + IN EFI_HII_VALUE *Value + ) +{ + UINT64 Temp; + + Temp = 0; + switch (Value->Type) { + case EFI_IFR_TYPE_NUM_SIZE_8: + Temp = Value->Value.u8; + break; + + case EFI_IFR_TYPE_NUM_SIZE_16: + Temp = Value->Value.u16; + break; + + case EFI_IFR_TYPE_NUM_SIZE_32: + Temp = Value->Value.u32; + break; + + case EFI_IFR_TYPE_BOOLEAN: + Temp = Value->Value.b; + break; + + case EFI_IFR_TYPE_TIME: + Temp = Value->Value.u32 & 0xffffff; + break; + + case EFI_IFR_TYPE_DATE: + Temp = Value->Value.u32; + break; + + default: + return; + } + + Value->Value.u64 = Temp; +} + + +/** + Compare two Hii value. + + @param Value1 Expression value to compare on left-hand + @param Value2 Expression value to compare on right-hand + @param HiiHandle Only required for string compare + + @retval EFI_INVALID_PARAMETER Could not perform comparation on two values + @retval 0 Two operators equeal + @retval 0 Value1 is greater than Value2 + @retval 0 Value1 is less than Value2 + +**/ +INTN +CompareHiiValue ( + IN EFI_HII_VALUE *Value1, + IN EFI_HII_VALUE *Value2, + IN EFI_HII_HANDLE HiiHandle OPTIONAL + ) +{ + INTN Result; + INT64 Temp64; + CHAR16 *Str1; + CHAR16 *Str2; + + if (Value1->Type >= EFI_IFR_TYPE_OTHER || Value2->Type >= EFI_IFR_TYPE_OTHER ) { + return EFI_INVALID_PARAMETER; + } + + if (Value1->Type == EFI_IFR_TYPE_STRING || Value2->Type == EFI_IFR_TYPE_STRING ) { + if (Value1->Type != Value2->Type) { + // + // Both Operator should be type of String + // + return EFI_INVALID_PARAMETER; + } + + if (Value1->Value.string == 0 || Value2->Value.string == 0) { + // + // StringId 0 is reserved + // + return EFI_INVALID_PARAMETER; + } + + if (Value1->Value.string == Value2->Value.string) { + return 0; + } + + Str1 = GetToken (Value1->Value.string, HiiHandle); + if (Str1 == NULL) { + // + // String not found + // + return EFI_INVALID_PARAMETER; + } + + Str2 = GetToken (Value2->Value.string, HiiHandle); + if (Str2 == NULL) { + gBS->FreePool (Str1); + return EFI_INVALID_PARAMETER; + } + + Result = StrCmp (Str1, Str2); + + gBS->FreePool (Str1); + gBS->FreePool (Str2); + + return Result; + } + + // + // Take remain types(integer, boolean, date/time) as integer + // + Temp64 = (INT64) (Value1->Value.u64 - Value2->Value.u64); + if (Temp64 > 0) { + Result = 1; + } else if (Temp64 < 0) { + Result = -1; + } else { + Result = 0; + } + + return Result; +} + + +/** + Evaluate the result of a HII expression + + @param FormSet FormSet associated with this expression. + @param Form Form associated with this expression. + @param Expression Expression to be evaluated. + + @retval EFI_SUCCESS The expression evaluated successfuly + @retval EFI_NOT_FOUND The Question which referenced by a QuestionId + could not be found. + @retval EFI_OUT_OF_RESOURCES There is not enough system memory to grow the + stack. + @retval EFI_ACCESS_DENIED The pop operation underflowed the stack + @retval EFI_INVALID_PARAMETER Syntax error with the Expression + +**/ +EFI_STATUS +EvaluateExpression ( + IN FORM_BROWSER_FORMSET *FormSet, + IN FORM_BROWSER_FORM *Form, + IN OUT FORM_EXPRESSION *Expression + ) +{ + EFI_STATUS Status; + LIST_ENTRY *Link; + EXPRESSION_OPCODE *OpCode; + FORM_BROWSER_STATEMENT *Question; + FORM_BROWSER_STATEMENT *Question2; + UINT16 Index; + EFI_HII_VALUE Data1; + EFI_HII_VALUE Data2; + EFI_HII_VALUE Data3; + FORM_EXPRESSION *RuleExpression; + EFI_HII_VALUE *Value; + INTN Result; + CHAR16 *StrPtr; + UINT32 TempValue; + + // + // Always reset the stack before evaluating an Expression + // + ResetExpressionStack (); + + Expression->Result.Type = EFI_IFR_TYPE_OTHER; + + Link = GetFirstNode (&Expression->OpCodeListHead); + while (!IsNull (&Expression->OpCodeListHead, Link)) { + OpCode = EXPRESSION_OPCODE_FROM_LINK (Link); + + Link = GetNextNode (&Expression->OpCodeListHead, Link); + + ZeroMem (&Data1, sizeof (EFI_HII_VALUE)); + ZeroMem (&Data2, sizeof (EFI_HII_VALUE)); + ZeroMem (&Data3, sizeof (EFI_HII_VALUE)); + + Value = &Data3; + Value->Type = EFI_IFR_TYPE_BOOLEAN; + Status = EFI_SUCCESS; + + switch (OpCode->Operand) { + // + // Built-in functions + // + case EFI_IFR_EQ_ID_VAL_OP: + Question = IdToQuestion (FormSet, Form, OpCode->QuestionId); + if (Question == NULL) { + return EFI_NOT_FOUND; + } + + Result = CompareHiiValue (&Question->HiiValue, &OpCode->Value, NULL); + if (Result == EFI_INVALID_PARAMETER) { + return EFI_INVALID_PARAMETER; + } + Value->Value.b = (BOOLEAN) ((Result == 0) ? TRUE : FALSE); + break; + + case EFI_IFR_EQ_ID_ID_OP: + Question = IdToQuestion (FormSet, Form, OpCode->QuestionId); + if (Question == NULL) { + return EFI_NOT_FOUND; + } + + Question2 = IdToQuestion (FormSet, Form, OpCode->QuestionId2); + if (Question2 == NULL) { + return EFI_NOT_FOUND; + } + + Result = CompareHiiValue (&Question->HiiValue, &Question2->HiiValue, FormSet->HiiHandle); + if (Result == EFI_INVALID_PARAMETER) { + return EFI_INVALID_PARAMETER; + } + Value->Value.b = (BOOLEAN) ((Result == 0) ? TRUE : FALSE); + break; + + case EFI_IFR_EQ_ID_LIST_OP: + Question = IdToQuestion (FormSet, Form, OpCode->QuestionId); + if (Question == NULL) { + return EFI_NOT_FOUND; + } + + Value->Value.b = FALSE; + for (Index =0; Index < OpCode->ListLength; Index++) { + if (Question->HiiValue.Value.u16 == OpCode->ValueList[Index]) { + Value->Value.b = TRUE; + break; + } + } + break; + + case EFI_IFR_DUP_OP: + Status = PopExpression (Value); + if (EFI_ERROR (Status)) { + return Status; + } + + Status = PushExpression (Value); + break; + + case EFI_IFR_QUESTION_REF1_OP: + case EFI_IFR_THIS_OP: + Question = IdToQuestion (FormSet, Form, OpCode->QuestionId); + if (Question == NULL) { + return EFI_NOT_FOUND; + } + + Value = &Question->HiiValue; + break; + + case EFI_IFR_QUESTION_REF3_OP: + if (OpCode->DevicePath == 0) { + // + // EFI_IFR_QUESTION_REF3 + // Pop an expression from the expression stack + // + Status = PopExpression (Value); + if (EFI_ERROR (Status)) { + return Status; + } + + // + // Validate the expression value + // + if ((Value->Type > EFI_IFR_TYPE_NUM_SIZE_64) || (Value->Value.u64 > 0xffff)) { + return EFI_NOT_FOUND; + } + + Question = IdToQuestion (FormSet, Form, Value->Value.u16); + if (Question == NULL) { + return EFI_NOT_FOUND; + } + + // + // push the questions' value on to the expression stack + // + Value = &Question->HiiValue; + } else { + // + // BUGBUG: push 0 for EFI_IFR_QUESTION_REF3_2 and EFI_IFR_QUESTION_REF3_3, + // since it is impractical to evaluate the value of a Question in another + // Hii Package list. + // + ZeroMem (Value, sizeof (EFI_HII_VALUE)); + } + break; + + case EFI_IFR_RULE_REF_OP: + // + // Find expression for this rule + // + RuleExpression = RuleIdToExpression (Form, OpCode->RuleId); + if (RuleExpression == NULL) { + return EFI_NOT_FOUND; + } + + // + // Evaluate this rule expression + // + Status = EvaluateExpression (FormSet, Form, RuleExpression); + if (EFI_ERROR (Status)) { + return Status; + } + + Value = &RuleExpression->Result; + break; + + case EFI_IFR_STRING_REF1_OP: + Value->Type = EFI_IFR_TYPE_STRING; + Value->Value.string = OpCode->Value.Value.string; + break; + + // + // Constant + // + case EFI_IFR_TRUE_OP: + case EFI_IFR_FALSE_OP: + case EFI_IFR_ONE_OP: + case EFI_IFR_ONES_OP: + case EFI_IFR_UINT8_OP: + case EFI_IFR_UINT16_OP: + case EFI_IFR_UINT32_OP: + case EFI_IFR_UINT64_OP: + case EFI_IFR_UNDEFINED_OP: + case EFI_IFR_VERSION_OP: + case EFI_IFR_ZERO_OP: + Value = &OpCode->Value; + break; + + // + // unary-op + // + case EFI_IFR_LENGTH_OP: + Status = PopExpression (Value); + if (EFI_ERROR (Status)) { + return Status; + } + if (Value->Type != EFI_IFR_TYPE_STRING) { + return EFI_INVALID_PARAMETER; + } + + StrPtr = GetToken (Value->Value.string, FormSet->HiiHandle); + if (StrPtr == NULL) { + return EFI_INVALID_PARAMETER; + } + + Value->Type = EFI_IFR_TYPE_NUM_SIZE_64; + Value->Value.u64 = StrLen (StrPtr); + gBS->FreePool (StrPtr); + break; + + case EFI_IFR_NOT_OP: + Status = PopExpression (Value); + if (EFI_ERROR (Status)) { + return Status; + } + if (Value->Type != EFI_IFR_TYPE_BOOLEAN) { + return EFI_INVALID_PARAMETER; + } + Value->Value.b = (BOOLEAN) (!Value->Value.b); + break; + + case EFI_IFR_QUESTION_REF2_OP: + // + // Pop an expression from the expression stack + // + Status = PopExpression (Value); + if (EFI_ERROR (Status)) { + return Status; + } + + // + // Validate the expression value + // + if ((Value->Type > EFI_IFR_TYPE_NUM_SIZE_64) || (Value->Value.u64 > 0xffff)) { + return EFI_NOT_FOUND; + } + + Question = IdToQuestion (FormSet, Form, Value->Value.u16); + if (Question == NULL) { + return EFI_NOT_FOUND; + } + + Value = &Question->HiiValue; + break; + + case EFI_IFR_STRING_REF2_OP: + // + // Pop an expression from the expression stack + // + Status = PopExpression (Value); + if (EFI_ERROR (Status)) { + return Status; + } + + // + // Validate the expression value + // + if ((Value->Type > EFI_IFR_TYPE_NUM_SIZE_64) || (Value->Value.u64 > 0xffff)) { + return EFI_NOT_FOUND; + } + + Value->Type = EFI_IFR_TYPE_STRING; + StrPtr = GetToken (Value->Value.u16, FormSet->HiiHandle); + if (StrPtr == NULL) { + // + // If String not exit, push an empty string + // + Value->Value.string = NewString (gEmptyString, FormSet->HiiHandle); + } else { + Index = (UINT16) Value->Value.u64; + Value->Value.string = Index; + gBS->FreePool (StrPtr); + } + break; + + case EFI_IFR_TO_BOOLEAN_OP: + // + // Pop an expression from the expression stack + // + Status = PopExpression (Value); + if (EFI_ERROR (Status)) { + return Status; + } + + // + // Convert an expression to a Boolean + // + if (Value->Type <= EFI_IFR_TYPE_DATE) { + // + // When converting from an unsigned integer, zero will be converted to + // FALSE and any other value will be converted to TRUE. + // + Value->Value.b = (BOOLEAN) ((Value->Value.u64) ? TRUE : FALSE); + + Value->Type = EFI_IFR_TYPE_BOOLEAN; + } else if (Value->Type == EFI_IFR_TYPE_STRING) { + // + // When converting from a string, if case-insensitive compare + // with "true" is True, then push True. If a case-insensitive compare + // with "false" is True, then push False. + // + StrPtr = GetToken (Value->Value.string, FormSet->HiiHandle); + if (StrPtr == NULL) { + return EFI_INVALID_PARAMETER; + } + + if ((StrCmp (StrPtr, L"true") == 0) || (StrCmp (StrPtr, L"false") == 0)){ + Value->Value.b = TRUE; + } else { + Value->Value.b = FALSE; + } + gBS->FreePool (StrPtr); + Value->Type = EFI_IFR_TYPE_BOOLEAN; + } + break; + + case EFI_IFR_TO_STRING_OP: + Status = IfrToString (FormSet, OpCode->Format, Value); + break; + + case EFI_IFR_TO_UINT_OP: + Status = IfrToUint (FormSet, Value); + break; + + case EFI_IFR_TO_LOWER_OP: + case EFI_IFR_TO_UPPER_OP: + Status = InitializeUnicodeCollationProtocol (); + if (EFI_ERROR (Status)) { + return Status; + } + + Status = PopExpression (Value); + if (EFI_ERROR (Status)) { + return Status; + } + + if (Value->Type != EFI_IFR_TYPE_STRING) { + return EFI_UNSUPPORTED; + } + + StrPtr = GetToken (Value->Value.string, FormSet->HiiHandle); + if (StrPtr == NULL) { + return EFI_NOT_FOUND; + } + + if (OpCode->Operand == EFI_IFR_TO_LOWER_OP) { + mUnicodeCollation->StrLwr (mUnicodeCollation, StrPtr); + } else { + mUnicodeCollation->StrUpr (mUnicodeCollation, StrPtr); + } + Value->Value.string = NewString (StrPtr, FormSet->HiiHandle); + gBS->FreePool (StrPtr); + break; + + case EFI_IFR_BITWISE_NOT_OP: + // + // Pop an expression from the expression stack + // + Status = PopExpression (Value); + if (EFI_ERROR (Status)) { + return Status; + } + if (Value->Type > EFI_IFR_TYPE_DATE) { + return EFI_INVALID_PARAMETER; + } + + Value->Type = EFI_IFR_TYPE_NUM_SIZE_64; + Value->Value.u64 = ~Value->Value.u64; + break; + + // + // binary-op + // + case EFI_IFR_ADD_OP: + case EFI_IFR_SUBTRACT_OP: + case EFI_IFR_MULTIPLY_OP: + case EFI_IFR_DIVIDE_OP: + case EFI_IFR_MODULO_OP: + case EFI_IFR_BITWISE_AND_OP: + case EFI_IFR_BITWISE_OR_OP: + case EFI_IFR_SHIFT_LEFT_OP: + case EFI_IFR_SHIFT_RIGHT_OP: + // + // Pop an expression from the expression stack + // + Status = PopExpression (&Data2); + if (EFI_ERROR (Status)) { + return Status; + } + if (Data2.Type > EFI_IFR_TYPE_DATE) { + return EFI_INVALID_PARAMETER; + } + + // + // Pop another expression from the expression stack + // + Status = PopExpression (&Data1); + if (EFI_ERROR (Status)) { + return Status; + } + if (Data1.Type > EFI_IFR_TYPE_DATE) { + return EFI_INVALID_PARAMETER; + } + + Value->Type = EFI_IFR_TYPE_NUM_SIZE_64; + + switch (OpCode->Operand) { + case EFI_IFR_ADD_OP: + Value->Value.u64 = Data1.Value.u64 + Data2.Value.u64; + break; + + case EFI_IFR_SUBTRACT_OP: + Value->Value.u64 = Data1.Value.u64 - Data2.Value.u64; + break; + + case EFI_IFR_MULTIPLY_OP: + Value->Value.u64 = MultU64x32 (Data1.Value.u64, (UINT32) Data2.Value.u64); + break; + + case EFI_IFR_DIVIDE_OP: + Value->Value.u64 = DivU64x32 (Data1.Value.u64, (UINT32) Data2.Value.u64); + break; + + case EFI_IFR_MODULO_OP: + DivU64x32Remainder (Data1.Value.u64, (UINT32) Data2.Value.u64, &TempValue); + Value->Value.u64 = TempValue; + break; + + case EFI_IFR_BITWISE_AND_OP: + Value->Value.u64 = Data1.Value.u64 & Data2.Value.u64; + break; + + case EFI_IFR_BITWISE_OR_OP: + Value->Value.u64 = Data1.Value.u64 | Data2.Value.u64; + break; + + case EFI_IFR_SHIFT_LEFT_OP: + Value->Value.u64 = LShiftU64 (Data1.Value.u64, (UINTN) Data2.Value.u64); + break; + + case EFI_IFR_SHIFT_RIGHT_OP: + Value->Value.u64 = RShiftU64 (Data1.Value.u64, (UINTN) Data2.Value.u64); + break; + + default: + break; + } + break; + + case EFI_IFR_AND_OP: + case EFI_IFR_OR_OP: + // + // Two Boolean operator + // + Status = PopExpression (&Data2); + if (EFI_ERROR (Status)) { + return Status; + } + if (Data2.Type != EFI_IFR_TYPE_BOOLEAN) { + return EFI_INVALID_PARAMETER; + } + + // + // Pop another expression from the expression stack + // + Status = PopExpression (&Data1); + if (EFI_ERROR (Status)) { + return Status; + } + if (Data1.Type != EFI_IFR_TYPE_BOOLEAN) { + return EFI_INVALID_PARAMETER; + } + + if (OpCode->Operand == EFI_IFR_AND_OP) { + Value->Value.b = (BOOLEAN) (Data1.Value.b && Data2.Value.b); + } else { + Value->Value.b = (BOOLEAN) (Data1.Value.b || Data2.Value.b); + } + break; + + case EFI_IFR_EQUAL_OP: + case EFI_IFR_NOT_EQUAL_OP: + case EFI_IFR_GREATER_EQUAL_OP: + case EFI_IFR_GREATER_THAN_OP: + case EFI_IFR_LESS_EQUAL_OP: + case EFI_IFR_LESS_THAN_OP: + // + // Compare two integer, string, boolean or date/time + // + Status = PopExpression (&Data2); + if (EFI_ERROR (Status)) { + return Status; + } + if (Data2.Type > EFI_IFR_TYPE_BOOLEAN && Data2.Type != EFI_IFR_TYPE_STRING) { + return EFI_INVALID_PARAMETER; + } + + // + // Pop another expression from the expression stack + // + Status = PopExpression (&Data1); + if (EFI_ERROR (Status)) { + return Status; + } + + Result = CompareHiiValue (&Data1, &Data2, FormSet->HiiHandle); + if (Result == EFI_INVALID_PARAMETER) { + return EFI_INVALID_PARAMETER; + } + + switch (OpCode->Operand) { + case EFI_IFR_EQUAL_OP: + Value->Value.b = (BOOLEAN) ((Result == 0) ? TRUE : FALSE); + break; + + case EFI_IFR_NOT_EQUAL_OP: + Value->Value.b = (BOOLEAN) ((Result == 0) ? TRUE : FALSE); + break; + + case EFI_IFR_GREATER_EQUAL_OP: + Value->Value.b = (BOOLEAN) ((Result >= 0) ? TRUE : FALSE); + break; + + case EFI_IFR_GREATER_THAN_OP: + Value->Value.b = (BOOLEAN) ((Result > 0) ? TRUE : FALSE); + break; + + case EFI_IFR_LESS_EQUAL_OP: + Value->Value.b = (BOOLEAN) ((Result <= 0) ? TRUE : FALSE); + break; + + case EFI_IFR_LESS_THAN_OP: + Value->Value.b = (BOOLEAN) ((Result < 0) ? TRUE : FALSE); + break; + + default: + break; + } + break; + + case EFI_IFR_MATCH_OP: + Status = IfrMatch (FormSet, Value); + break; + + case EFI_IFR_CATENATE_OP: + Status = IfrCatenate (FormSet, Value); + break; + + // + // ternary-op + // + case EFI_IFR_CONDITIONAL_OP: + // + // Pop third expression from the expression stack + // + Status = PopExpression (&Data3); + if (EFI_ERROR (Status)) { + return Status; + } + + // + // Pop second expression from the expression stack + // + Status = PopExpression (&Data2); + if (EFI_ERROR (Status)) { + return Status; + } + + // + // Pop first expression from the expression stack + // + Status = PopExpression (&Data1); + if (EFI_ERROR (Status)) { + return Status; + } + if (Data1.Type != EFI_IFR_TYPE_BOOLEAN) { + return EFI_INVALID_PARAMETER; + } + + if (Data1.Value.b) { + Value = &Data3; + } else { + Value = &Data2; + } + break; + + case EFI_IFR_FIND_OP: + Status = IfrFind (FormSet, OpCode->Format, Value); + break; + + case EFI_IFR_MID_OP: + Status = IfrMid (FormSet, Value); + break; + + case EFI_IFR_TOKEN_OP: + Status = IfrToken (FormSet, Value); + break; + + case EFI_IFR_SPAN_OP: + Status = IfrSpan (FormSet, OpCode->Flags, Value); + break; + + default: + break; + } + if (EFI_ERROR (Status)) { + return Status; + } + + Status = PushExpression (Value); + if (EFI_ERROR (Status)) { + return Status; + } + } + + // + // Pop the final result from expression stack + // + Value = &Data1; + Status = PopExpression (Value); + if (EFI_ERROR (Status)) { + return Status; + } + + // + // After evaluating an expression, there should be only one value left on the expression stack + // + if (PopExpression (Value) != EFI_ACCESS_DENIED) { + return EFI_INVALID_PARAMETER; + } + + CopyMem (&Expression->Result, Value, sizeof (EFI_HII_VALUE)); + + return EFI_SUCCESS; +} diff --git a/MdeModulePkg/Universal/SetupBrowserDxe/IfrParse.c b/MdeModulePkg/Universal/SetupBrowserDxe/IfrParse.c new file mode 100644 index 0000000000..4b68047156 --- /dev/null +++ b/MdeModulePkg/Universal/SetupBrowserDxe/IfrParse.c @@ -0,0 +1,1640 @@ +/** @file +Copyright (c) 2007, Intel Corporation +All rights reserved. This program and the accompanying materials +are licensed and made available under the terms and conditions of the BSD License +which accompanies this distribution. The full text of the license may be found at +http://opensource.org/licenses/bsd-license.php + +THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, +WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. + +Module Name: + + IfrParse.c + +Abstract: + + Parser for IFR binary encoding. + + +**/ + +#include "Setup.h" +#include "Ui.h" +//@MT:#include "EfiPrintLib.h" + +UINT16 mStatementIndex; +UINT16 mExpressionOpCodeIndex; + +BOOLEAN mInScopeSubtitle; +BOOLEAN mInScopeSuppress; +BOOLEAN mInScopeGrayOut; +FORM_EXPRESSION *mSuppressExpression; +FORM_EXPRESSION *mGrayOutExpression; + +EFI_GUID gTianoHiiIfrGuid = EFI_IFR_TIANO_GUID; + + +/** + Initialize Statement header members. + + @param OpCodeData Pointer of the raw OpCode data. + @param FormSet Pointer of the current FormSe. + @param Form Pointer of the current Form. + + @return The Statement. + +**/ +FORM_BROWSER_STATEMENT * +CreateStatement ( + IN UINT8 *OpCodeData, + IN OUT FORM_BROWSER_FORMSET *FormSet, + IN OUT FORM_BROWSER_FORM *Form + ) +{ + FORM_BROWSER_STATEMENT *Statement; + EFI_IFR_STATEMENT_HEADER *StatementHdr; + + if (Form == NULL) { + // + // We are currently not in a Form Scope, so just skip this Statement + // + return NULL; + } + + Statement = &FormSet->StatementBuffer[mStatementIndex]; + mStatementIndex++; + + InitializeListHead (&Statement->DefaultListHead); + InitializeListHead (&Statement->OptionListHead); + InitializeListHead (&Statement->InconsistentListHead); + InitializeListHead (&Statement->NoSubmitListHead); + + Statement->Signature = FORM_BROWSER_STATEMENT_SIGNATURE; + + Statement->Operand = ((EFI_IFR_OP_HEADER *) OpCodeData)->OpCode; + + StatementHdr = (EFI_IFR_STATEMENT_HEADER *) (OpCodeData + sizeof (EFI_IFR_OP_HEADER)); + CopyMem (&Statement->Prompt, &StatementHdr->Prompt, sizeof (EFI_STRING_ID)); + CopyMem (&Statement->Help, &StatementHdr->Help, sizeof (EFI_STRING_ID)); + + if (mInScopeSuppress) { + Statement->SuppressExpression = mSuppressExpression; + } + + if (mInScopeGrayOut) { + Statement->GrayOutExpression = mGrayOutExpression; + } + + Statement->InSubtitle = mInScopeSubtitle; + + // + // Insert this Statement into current Form + // + InsertTailList (&Form->StatementListHead, &Statement->Link); + + return Statement; +} + + +/** + Initialize Question's members. + + @param OpCodeData Pointer of the raw OpCode data. + @param FormSet Pointer of the current FormSet. + @param Form Pointer of the current Form. + + @return The Question. + +**/ +FORM_BROWSER_STATEMENT * +CreateQuestion ( + IN UINT8 *OpCodeData, + IN OUT FORM_BROWSER_FORMSET *FormSet, + IN OUT FORM_BROWSER_FORM *Form + ) +{ + FORM_BROWSER_STATEMENT *Statement; + EFI_IFR_QUESTION_HEADER *QuestionHdr; + LIST_ENTRY *Link; + FORMSET_STORAGE *Storage; + NAME_VALUE_NODE *NameValueNode; + + Statement = CreateStatement (OpCodeData, FormSet, Form); + if (Statement == NULL) { + return NULL; + } + + QuestionHdr = (EFI_IFR_QUESTION_HEADER *) (OpCodeData + sizeof (EFI_IFR_OP_HEADER)); + CopyMem (&Statement->QuestionId, &QuestionHdr->QuestionId, sizeof (EFI_QUESTION_ID)); + CopyMem (&Statement->VarStoreId, &QuestionHdr->VarStoreId, sizeof (EFI_VARSTORE_ID)); + CopyMem (&Statement->VarStoreInfo.VarOffset, &QuestionHdr->VarStoreInfo.VarOffset, sizeof (UINT16)); + + Statement->QuestionFlags = QuestionHdr->Flags; + + if (Statement->VarStoreId == 0) { + // + // VarStoreId of zero indicates no variable storage + // + return Statement; + } + + // + // Find Storage for this Question + // + Link = GetFirstNode (&FormSet->StorageListHead); + while (!IsNull (&FormSet->StorageListHead, Link)) { + Storage = FORMSET_STORAGE_FROM_LINK (Link); + + if (Storage->VarStoreId == Statement->VarStoreId) { + Statement->Storage = Storage; + break; + } + + Link = GetNextNode (&FormSet->StorageListHead, Link); + } + ASSERT (Statement->Storage != NULL); + + // + // Initialilze varname for Name/Value or EFI Variable + // + if ((Statement->Storage->Type == EFI_HII_VARSTORE_NAME_VALUE) || + (Statement->Storage->Type == EFI_HII_VARSTORE_EFI_VARIABLE)) { + Statement->VariableName = GetToken (Statement->VarStoreInfo.VarName, FormSet->HiiHandle); + ASSERT (Statement->VariableName != NULL); + + if (Statement->Storage->Type == EFI_HII_VARSTORE_NAME_VALUE) { + // + // Insert to Name/Value varstore list + // + NameValueNode = AllocateZeroPool (sizeof (NAME_VALUE_NODE)); + ASSERT (NameValueNode != NULL); + NameValueNode->Signature = NAME_VALUE_NODE_SIGNATURE; + NameValueNode->Name = AllocateCopyPool (StrSize (Statement->VariableName), Statement->VariableName); + ASSERT (NameValueNode->Name != NULL); + NameValueNode->Value = AllocateZeroPool (0x10); + ASSERT (NameValueNode->Value != NULL); + NameValueNode->EditValue = AllocateZeroPool (0x10); + ASSERT (NameValueNode->EditValue != NULL); + + InsertTailList (&Statement->Storage->NameValueListHead, &NameValueNode->Link); + } + } + + return Statement; +} + + +/** + Allocate a FORM_EXPRESSION node. + + @param Form The Form associated with this Expression + + @return Pointer to a FORM_EXPRESSION data structure. + +**/ +FORM_EXPRESSION * +CreateExpression ( + IN OUT FORM_BROWSER_FORM *Form + ) +{ + FORM_EXPRESSION *Expression; + + Expression = AllocateZeroPool (sizeof (FORM_EXPRESSION)); + Expression->Signature = FORM_EXPRESSION_SIGNATURE; + InitializeListHead (&Expression->OpCodeListHead); + + return Expression; +} + + +/** + Allocate a FORMSET_STORAGE data structure and insert to FormSet Storage List. + + @param FormSet Pointer of the current FormSet + + @return Pointer to a FORMSET_STORAGE data structure. + +**/ +FORMSET_STORAGE * +CreateStorage ( + IN FORM_BROWSER_FORMSET *FormSet + ) +{ + FORMSET_STORAGE *Storage; + + Storage = AllocateZeroPool (sizeof (FORMSET_STORAGE)); + Storage->Signature = FORMSET_STORAGE_SIGNATURE; + InitializeListHead (&Storage->NameValueListHead); + InsertTailList (&FormSet->StorageListHead, &Storage->Link); + + return Storage; +} + + +/** + Create ConfigHdr string for a storage. + + @param FormSet Pointer of the current FormSet + @param Storage Pointer of the storage + + @retval EFI_SUCCESS Initialize ConfigHdr success + +**/ +EFI_STATUS +InitializeConfigHdr ( + IN FORM_BROWSER_FORMSET *FormSet, + IN OUT FORMSET_STORAGE *Storage + ) +{ + EFI_STATUS Status; + UINTN StrBufferLen; + CHAR16 *Name; + + if (Storage->Type == EFI_HII_VARSTORE_BUFFER) { + Name = Storage->Name; + } else { + Name = NULL; + } + + StrBufferLen = 0; + Status = ConstructConfigHdr ( + Storage->ConfigHdr, + &StrBufferLen, + &Storage->Guid, + Name, + FormSet->DriverHandle + ); + if (Status == EFI_BUFFER_TOO_SMALL) { + Storage->ConfigHdr = AllocateZeroPool (StrBufferLen); + Status = ConstructConfigHdr ( + Storage->ConfigHdr, + &StrBufferLen, + &Storage->Guid, + Name, + FormSet->DriverHandle + ); + } + + if (EFI_ERROR (Status)) { + return Status; + } + + Storage->ConfigRequest = AllocateCopyPool (StrBufferLen, Storage->ConfigHdr); + Storage->SpareStrLen = 0; + + return EFI_SUCCESS; +} + + +/** + Initialize Request Element of a Question. <RequestElement> ::= '&'<BlockName> | '&'<Label> + + @param FormSet Pointer of the current FormSet. + @param Question The Question to be initialized. + + @retval EFI_SUCCESS Function success. + @retval EFI_INVALID_PARAMETER No storage associated with the Question. + +**/ +EFI_STATUS +InitializeRequestElement ( + IN OUT FORM_BROWSER_FORMSET *FormSet, + IN OUT FORM_BROWSER_STATEMENT *Question + ) +{ + FORMSET_STORAGE *Storage; + UINTN StrLen; + UINTN StringSize; + CHAR16 *NewStr; + CHAR16 RequestElement[30]; + + Storage = Question->Storage; + if (Storage == NULL) { + return EFI_INVALID_PARAMETER; + } + + if (Storage->Type == EFI_HII_VARSTORE_EFI_VARIABLE) { + // + // <ConfigRequest> is unnecessary for EFI variable storage, + // GetVariable()/SetVariable() will be used to retrieve/save values + // + return EFI_SUCCESS; + } + + // + // Prepare <RequestElement> + // + if (Storage->Type == EFI_HII_VARSTORE_BUFFER) { + StrLen = UnicodeSPrint ( + RequestElement, + 30 * sizeof (CHAR16), + L"&OFFSET=%x&WIDTH=%x", + Question->VarStoreInfo.VarOffset, + Question->StorageWidth + ); + Question->BlockName = AllocateCopyPool ((StrLen + 1) * sizeof (CHAR16), RequestElement); + } else { + StrLen = UnicodeSPrint (RequestElement, 30 * sizeof (CHAR16), L"&%s", Question->VariableName); + } + + if ((Question->Operand == EFI_IFR_PASSWORD_OP) && (Question->QuestionFlags & EFI_IFR_FLAG_CALLBACK)) { + // + // Password with CALLBACK flag is stored in encoded format, + // so don't need to append it to <ConfigRequest>\ + // + return EFI_SUCCESS; + } + + // + // Append <RequestElement> to <ConfigRequest> + // + if (StrLen > Storage->SpareStrLen) { + // + // Old String buffer is not sufficient for RequestElement, allocate a new one + // + StringSize = (Storage->ConfigRequest != NULL) ? StrSize (Storage->ConfigRequest) : 0; + NewStr = AllocateZeroPool (StringSize + CONFIG_REQUEST_STRING_INCREMENTAL * sizeof (CHAR16)); + if (Storage->ConfigRequest != NULL) { + CopyMem (NewStr, Storage->ConfigRequest, StringSize); + gBS->FreePool (Storage->ConfigRequest); + } + Storage->ConfigRequest = NewStr; + Storage->SpareStrLen = CONFIG_REQUEST_STRING_INCREMENTAL; + } + + StrCat (Storage->ConfigRequest, RequestElement); + Storage->ElementCount++; + Storage->SpareStrLen -= StrLen; + + return EFI_SUCCESS; +} + + +/** + Free resources of a Expression + + @param FormSet Pointer of the Expression + + @return None. + +**/ +VOID +DestroyExpression ( + IN FORM_EXPRESSION *Expression + ) +{ + LIST_ENTRY *Link; + EXPRESSION_OPCODE *OpCode; + + while (!IsListEmpty (&Expression->OpCodeListHead)) { + Link = GetFirstNode (&Expression->OpCodeListHead); + OpCode = EXPRESSION_OPCODE_FROM_LINK (Link); + RemoveEntryList (&OpCode->Link); + + SafeFreePool (OpCode->ValueList); + } + + // + // Free this Expression + // + gBS->FreePool (Expression); +} + + +/** + Free resources of a storage + + @param Storage Pointer of the storage + + @return None. + +**/ +VOID +DestroyStorage ( + IN FORMSET_STORAGE *Storage + ) +{ + LIST_ENTRY *Link; + NAME_VALUE_NODE *NameValueNode; + + if (Storage == NULL) { + return; + } + + SafeFreePool (Storage->Name); + SafeFreePool (Storage->Buffer); + SafeFreePool (Storage->EditBuffer); + + while (!IsListEmpty (&Storage->NameValueListHead)) { + Link = GetFirstNode (&Storage->NameValueListHead); + NameValueNode = NAME_VALUE_NODE_FROM_LINK (Link); + RemoveEntryList (&NameValueNode->Link); + + SafeFreePool (NameValueNode->Name); + SafeFreePool (NameValueNode->Value); + SafeFreePool (NameValueNode->EditValue); + SafeFreePool (NameValueNode); + } + + SafeFreePool (Storage->ConfigHdr); + SafeFreePool (Storage->ConfigRequest); + + gBS->FreePool (Storage); +} + + +/** + Free resources of a Statement + + @param Statement Pointer of the Statement + + @return None. + +**/ +VOID +DestroyStatement ( + IN OUT FORM_BROWSER_STATEMENT *Statement + ) +{ + LIST_ENTRY *Link; + QUESTION_DEFAULT *Default; + QUESTION_OPTION *Option; + FORM_EXPRESSION *Expression; + + // + // Free Default value List + // + while (!IsListEmpty (&Statement->DefaultListHead)) { + Link = GetFirstNode (&Statement->DefaultListHead); + Default = QUESTION_DEFAULT_FROM_LINK (Link); + RemoveEntryList (&Default->Link); + + gBS->FreePool (Default); + } + + // + // Free Options List + // + while (!IsListEmpty (&Statement->OptionListHead)) { + Link = GetFirstNode (&Statement->OptionListHead); + Option = QUESTION_OPTION_FROM_LINK (Link); + RemoveEntryList (&Option->Link); + + gBS->FreePool (Option); + } + + // + // Free Inconsistent List + // + while (!IsListEmpty (&Statement->InconsistentListHead)) { + Link = GetFirstNode (&Statement->InconsistentListHead); + Expression = FORM_EXPRESSION_FROM_LINK (Link); + RemoveEntryList (&Expression->Link); + + DestroyExpression (Expression); + } + + // + // Free NoSubmit List + // + while (!IsListEmpty (&Statement->NoSubmitListHead)) { + Link = GetFirstNode (&Statement->NoSubmitListHead); + Expression = FORM_EXPRESSION_FROM_LINK (Link); + RemoveEntryList (&Expression->Link); + + DestroyExpression (Expression); + } + + SafeFreePool (Statement->VariableName); + SafeFreePool (Statement->BlockName); +} + + +/** + Free resources of a Form + + @param Form Pointer of the Form + + @return None. + +**/ +VOID +DestroyForm ( + IN OUT FORM_BROWSER_FORM *Form + ) +{ + LIST_ENTRY *Link; + FORM_EXPRESSION *Expression; + FORM_BROWSER_STATEMENT *Statement; + + // + // Free Form Expressions + // + while (!IsListEmpty (&Form->ExpressionListHead)) { + Link = GetFirstNode (&Form->ExpressionListHead); + Expression = FORM_EXPRESSION_FROM_LINK (Link); + RemoveEntryList (&Expression->Link); + + DestroyExpression (Expression); + } + + // + // Free Statements/Questions + // + while (!IsListEmpty (&Form->StatementListHead)) { + Link = GetFirstNode (&Form->StatementListHead); + Statement = FORM_BROWSER_STATEMENT_FROM_LINK (Link); + RemoveEntryList (&Statement->Link); + + DestroyStatement (Statement); + } + + // + // Free this Form + // + gBS->FreePool (Form); +} + + +/** + Free resources allocated for a FormSet + + @param FormSet Pointer of the FormSet + + @return None. + +**/ +VOID +DestroyFormSet ( + IN OUT FORM_BROWSER_FORMSET *FormSet + ) +{ + LIST_ENTRY *Link; + FORMSET_STORAGE *Storage; + FORMSET_DEFAULTSTORE *DefaultStore; + FORM_BROWSER_FORM *Form; + + // + // Free IFR binary buffer + // + SafeFreePool (FormSet->IfrBinaryData); + + // + // Free FormSet Storage + // + if (FormSet->StorageListHead.ForwardLink != NULL) { + while (!IsListEmpty (&FormSet->StorageListHead)) { + Link = GetFirstNode (&FormSet->StorageListHead); + Storage = FORMSET_STORAGE_FROM_LINK (Link); + RemoveEntryList (&Storage->Link); + + DestroyStorage (Storage); + } + } + + // + // Free FormSet Default Store + // + if (FormSet->DefaultStoreListHead.ForwardLink != NULL) { + while (!IsListEmpty (&FormSet->DefaultStoreListHead)) { + Link = GetFirstNode (&FormSet->DefaultStoreListHead); + DefaultStore = FORMSET_DEFAULTSTORE_FROM_LINK (Link); + RemoveEntryList (&DefaultStore->Link); + + gBS->FreePool (DefaultStore); + } + } + + // + // Free Forms + // + if (FormSet->FormListHead.ForwardLink != NULL) { + while (!IsListEmpty (&FormSet->FormListHead)) { + Link = GetFirstNode (&FormSet->FormListHead); + Form = FORM_BROWSER_FORM_FROM_LINK (Link); + RemoveEntryList (&Form->Link); + + DestroyForm (Form); + } + } + + SafeFreePool (FormSet->StatementBuffer); + SafeFreePool (FormSet->ExpressionBuffer); + + SafeFreePool (FormSet); +} + + +/** + Tell whether this Operand is an Expression OpCode or not + + @param Operand Operand of an IFR OpCode. + + @retval TRUE This is an Expression OpCode. + @retval FALSE Not an Expression OpCode. + +**/ +BOOLEAN +IsExpressionOpCode ( + IN UINT8 Operand + ) +{ + if (((Operand >= EFI_IFR_EQ_ID_VAL_OP) && (Operand <= EFI_IFR_NOT_OP)) || + ((Operand >= EFI_IFR_MATCH_OP) && (Operand <= EFI_IFR_SPAN_OP)) || + (Operand == EFI_IFR_CATENATE_OP) + ) { + return TRUE; + } else { + return FALSE; + } +} + + +/** + Calculate number of Statemens(Questions) and Expression OpCodes. + + @param FormSet The FormSet to be counted. + @param NumberOfStatement Number of Statemens(Questions) + @param NumberOfExpression Number of Expression OpCodes + + @return None. + +**/ +VOID +CountOpCodes ( + IN FORM_BROWSER_FORMSET *FormSet, + IN OUT UINT16 *NumberOfStatement, + IN OUT UINT16 *NumberOfExpression + ) +{ + UINT16 StatementCount; + UINT16 ExpressionCount; + UINT8 *OpCodeData; + UINTN Offset; + UINTN OpCodeLen; + + Offset = 0; + StatementCount = 0; + ExpressionCount = 0; + + while (Offset < FormSet->IfrBinaryLength) { + OpCodeData = FormSet->IfrBinaryData + Offset; + OpCodeLen = ((EFI_IFR_OP_HEADER *) OpCodeData)->Length; + Offset += OpCodeLen; + + if (IsExpressionOpCode (((EFI_IFR_OP_HEADER *) OpCodeData)->OpCode)) { + ExpressionCount++; + } else { + StatementCount++; + } + } + + *NumberOfStatement = StatementCount; + *NumberOfExpression = ExpressionCount; +} + + +/** + Parse opcodes in the formset IFR binary. + + @param FormSet Pointer of the FormSet data structure. + + @retval EFI_SUCCESS Opcode parse success. + @retval Other Opcode parse fail. + +**/ +EFI_STATUS +ParseOpCodes ( + IN FORM_BROWSER_FORMSET *FormSet + ) +{ + EFI_STATUS Status; + UINT16 Index; + FORM_BROWSER_FORM *CurrentForm; + FORM_BROWSER_STATEMENT *CurrentStatement; + EXPRESSION_OPCODE *ExpressionOpCode; + FORM_EXPRESSION *CurrentExpression; + UINT8 Operand; + UINT8 Scope; + UINTN OpCodeOffset; + UINTN OpCodeLength; + UINT8 *OpCodeData; + UINT8 ScopeOpCode; + FORMSET_STORAGE *Storage; + FORMSET_DEFAULTSTORE *DefaultStore; + QUESTION_DEFAULT *CurrentDefault; + QUESTION_OPTION *CurrentOption; + CHAR8 *AsciiString; + UINT16 NumberOfStatement; + UINT16 NumberOfExpression; + EFI_IMAGE_ID *ImageId; + BOOLEAN SuppressForOption; + BOOLEAN InScopeOptionSuppress; + FORM_EXPRESSION *OptionSuppressExpression; + BOOLEAN InScopeDisable; + UINT16 DepthOfDisable; + BOOLEAN OpCodeDisabled; + BOOLEAN SingleOpCodeExpression; + BOOLEAN InScopeDefault; + EFI_HII_VALUE *Value; + + mInScopeSubtitle = FALSE; + SuppressForOption = FALSE; + mInScopeSuppress = FALSE; + InScopeOptionSuppress = FALSE; + mInScopeGrayOut = FALSE; + InScopeDisable = FALSE; + DepthOfDisable = 0; + OpCodeDisabled = FALSE; + SingleOpCodeExpression = FALSE; + InScopeDefault = FALSE; + CurrentExpression = NULL; + CurrentDefault = NULL; + CurrentOption = NULL; + OptionSuppressExpression = NULL; + + // + // Get the number of Statements and Expressions + // + CountOpCodes (FormSet, &NumberOfStatement, &NumberOfExpression); + + mStatementIndex = 0; + FormSet->StatementBuffer = AllocateZeroPool (NumberOfStatement * sizeof (FORM_BROWSER_STATEMENT)); + if (FormSet->StatementBuffer == NULL) { + return EFI_OUT_OF_RESOURCES; + } + + mExpressionOpCodeIndex = 0; + FormSet->ExpressionBuffer = AllocateZeroPool (NumberOfExpression * sizeof (EXPRESSION_OPCODE)); + if (FormSet->ExpressionBuffer == NULL) { + return EFI_OUT_OF_RESOURCES; + } + + InitializeListHead (&FormSet->StorageListHead); + InitializeListHead (&FormSet->DefaultStoreListHead); + InitializeListHead (&FormSet->FormListHead); + + CurrentForm = NULL; + CurrentStatement = NULL; + + ResetScopeStack (); + + OpCodeOffset = 0; + while (OpCodeOffset < FormSet->IfrBinaryLength) { + OpCodeData = FormSet->IfrBinaryData + OpCodeOffset; + + OpCodeLength = ((EFI_IFR_OP_HEADER *) OpCodeData)->Length; + OpCodeOffset += OpCodeLength; + Operand = ((EFI_IFR_OP_HEADER *) OpCodeData)->OpCode; + Scope = ((EFI_IFR_OP_HEADER *) OpCodeData)->Scope; + + // + // If scope bit set, push onto scope stack + // + if (Scope) { + PushScope (Operand); + } + + if (OpCodeDisabled) { + // + // DisableIf Expression is evaluated to be TRUE, try to find its end. + // Here only cares the EFI_IFR_DISABLE_IF and EFI_IFR_END + // + if (Operand == EFI_IFR_DISABLE_IF_OP) { + DepthOfDisable++; + } else if (Operand == EFI_IFR_END_OP) { + Status = PopScope (&ScopeOpCode); + if (EFI_ERROR (Status)) { + return Status; + } + + if (ScopeOpCode == EFI_IFR_DISABLE_IF_OP) { + if (DepthOfDisable == 0) { + InScopeDisable = FALSE; + OpCodeDisabled = FALSE; + } else { + DepthOfDisable--; + } + } + } + continue; + } + + if (IsExpressionOpCode (Operand)) { + ExpressionOpCode = &FormSet->ExpressionBuffer[mExpressionOpCodeIndex]; + mExpressionOpCodeIndex++; + + ExpressionOpCode->Signature = EXPRESSION_OPCODE_SIGNATURE; + ExpressionOpCode->Operand = Operand; + Value = &ExpressionOpCode->Value; + + switch (Operand) { + case EFI_IFR_EQ_ID_VAL_OP: + CopyMem (&ExpressionOpCode->QuestionId, &((EFI_IFR_EQ_ID_VAL *) OpCodeData)->QuestionId, sizeof (EFI_QUESTION_ID)); + + Value->Type = EFI_IFR_TYPE_NUM_SIZE_16; + CopyMem (&Value->Value.u16, &((EFI_IFR_EQ_ID_VAL *) OpCodeData)->Value, sizeof (UINT16)); + break; + + case EFI_IFR_EQ_ID_ID_OP: + CopyMem (&ExpressionOpCode->QuestionId, &((EFI_IFR_EQ_ID_ID *) OpCodeData)->QuestionId1, sizeof (EFI_QUESTION_ID)); + CopyMem (&ExpressionOpCode->QuestionId2, &((EFI_IFR_EQ_ID_ID *) OpCodeData)->QuestionId2, sizeof (EFI_QUESTION_ID)); + break; + + case EFI_IFR_EQ_ID_LIST_OP: + CopyMem (&ExpressionOpCode->QuestionId, &((EFI_IFR_EQ_ID_LIST *) OpCodeData)->QuestionId, sizeof (EFI_QUESTION_ID)); + CopyMem (&ExpressionOpCode->ListLength, &((EFI_IFR_EQ_ID_LIST *) OpCodeData)->ListLength, sizeof (UINT16)); + ExpressionOpCode->ValueList = AllocateCopyPool (ExpressionOpCode->ListLength * sizeof (UINT16), &((EFI_IFR_EQ_ID_LIST *) OpCodeData)->ValueList); + break; + + case EFI_IFR_TO_STRING_OP: + case EFI_IFR_FIND_OP: + ExpressionOpCode->Format = (( EFI_IFR_TO_STRING *) OpCodeData)->Format; + break; + + case EFI_IFR_STRING_REF1_OP: + Value->Type = EFI_IFR_TYPE_STRING; + CopyMem (&Value->Value.string, &(( EFI_IFR_STRING_REF1 *) OpCodeData)->StringId, sizeof (EFI_STRING_ID)); + break; + + case EFI_IFR_RULE_REF_OP: + ExpressionOpCode->RuleId = (( EFI_IFR_RULE_REF *) OpCodeData)->RuleId; + break; + + case EFI_IFR_SPAN_OP: + ExpressionOpCode->Flags = (( EFI_IFR_SPAN *) OpCodeData)->Flags; + break; + + case EFI_IFR_THIS_OP: + ExpressionOpCode->QuestionId = CurrentStatement->QuestionId; + break; + + case EFI_IFR_QUESTION_REF1_OP: + CopyMem (&ExpressionOpCode->QuestionId, &((EFI_IFR_EQ_ID_LIST *) OpCodeData)->QuestionId, sizeof (EFI_QUESTION_ID)); + break; + + case EFI_IFR_QUESTION_REF3_OP: + if (OpCodeLength >= sizeof (EFI_IFR_QUESTION_REF3_2)) { + CopyMem (&ExpressionOpCode->DevicePath, &(( EFI_IFR_QUESTION_REF3_2 *) OpCodeData)->DevicePath, sizeof (EFI_STRING_ID)); + + if (OpCodeLength >= sizeof (EFI_IFR_QUESTION_REF3_3)) { + CopyMem (&ExpressionOpCode->Guid, &(( EFI_IFR_QUESTION_REF3_3 *) OpCodeData)->Guid, sizeof (EFI_GUID)); + } + } + break; + + // + // constant + // + case EFI_IFR_TRUE_OP: + Value->Type = EFI_IFR_TYPE_BOOLEAN; + Value->Value.b = TRUE; + break; + + case EFI_IFR_FALSE_OP: + Value->Type = EFI_IFR_TYPE_BOOLEAN; + Value->Value.b = FALSE; + break; + + case EFI_IFR_ONE_OP: + Value->Type = EFI_IFR_TYPE_NUM_SIZE_8; + Value->Value.u8 = 1; + break; + + case EFI_IFR_ZERO_OP: + Value->Type = EFI_IFR_TYPE_NUM_SIZE_8; + Value->Value.u8 = 0; + break; + + case EFI_IFR_ONES_OP: + Value->Type = EFI_IFR_TYPE_NUM_SIZE_64; + Value->Value.u64 = 0xffffffffffffffff; + break; + + case EFI_IFR_UINT8_OP: + Value->Type = EFI_IFR_TYPE_NUM_SIZE_8; + Value->Value.u8 = (( EFI_IFR_UINT8 *) OpCodeData)->Value; + break; + + case EFI_IFR_UINT16_OP: + Value->Type = EFI_IFR_TYPE_NUM_SIZE_16; + CopyMem (&Value->Value.u16, &(( EFI_IFR_UINT16 *) OpCodeData)->Value, sizeof (UINT16)); + break; + + case EFI_IFR_UINT32_OP: + Value->Type = EFI_IFR_TYPE_NUM_SIZE_32; + CopyMem (&Value->Value.u32, &(( EFI_IFR_UINT32 *) OpCodeData)->Value, sizeof (UINT32)); + break; + + case EFI_IFR_UINT64_OP: + Value->Type = EFI_IFR_TYPE_NUM_SIZE_64; + CopyMem (&Value->Value.u64, &(( EFI_IFR_UINT64 *) OpCodeData)->Value, sizeof (UINT64)); + break; + + case EFI_IFR_UNDEFINED_OP: + Value->Type = EFI_IFR_TYPE_OTHER; + break; + + case EFI_IFR_VERSION_OP: + Value->Type = EFI_IFR_TYPE_NUM_SIZE_16; + Value->Value.u16 = EFI_IFR_SPECIFICATION_VERSION; + break; + + default: + break; + } + + InsertTailList (&CurrentExpression->OpCodeListHead, &ExpressionOpCode->Link); + + if (SingleOpCodeExpression) { + // + // There are two cases to indicate the end of an Expression: + // for single OpCode expression: one Expression OpCode + // for expression consists of more than one OpCode: EFI_IFR_END + // + SingleOpCodeExpression = FALSE; + + if (InScopeDisable) { + // + // Evaluate DisableIf expression + // + Status = EvaluateExpression (FormSet, CurrentForm, CurrentExpression); + if (EFI_ERROR (Status)) { + return Status; + } + if (CurrentExpression->Result.Type != EFI_IFR_TYPE_BOOLEAN) { + return EFI_INVALID_PARAMETER; + } + + OpCodeDisabled = CurrentExpression->Result.Value.b; + } + + CurrentExpression = NULL; + } + + continue; + } + + // + // Parse the Opcode + // + switch (Operand) { + + case EFI_IFR_FORM_SET_OP: + // + // check the formset GUID + // + if (CompareMem (&FormSet->Guid, &((EFI_IFR_FORM_SET *) OpCodeData)->Guid, sizeof (EFI_GUID)) != 0) { + return EFI_INVALID_PARAMETER; + } + + CopyMem (&FormSet->FormSetTitle, &((EFI_IFR_FORM_SET *) OpCodeData)->FormSetTitle, sizeof (EFI_STRING_ID)); + CopyMem (&FormSet->Help, &((EFI_IFR_FORM_SET *) OpCodeData)->Help, sizeof (EFI_STRING_ID)); + break; + + case EFI_IFR_FORM_OP: + // + // Create a new Form for this FormSet + // + CurrentForm = AllocateZeroPool (sizeof (FORM_BROWSER_FORM)); + CurrentForm->Signature = FORM_BROWSER_FORM_SIGNATURE; + InitializeListHead (&CurrentForm->ExpressionListHead); + InitializeListHead (&CurrentForm->StatementListHead); + + CopyMem (&CurrentForm->FormId, &((EFI_IFR_FORM *) OpCodeData)->FormId, sizeof (UINT16)); + CopyMem (&CurrentForm->FormTitle, &((EFI_IFR_FORM *) OpCodeData)->FormTitle, sizeof (EFI_STRING_ID)); + + // + // Insert into Form list of this FormSet + // + InsertTailList (&FormSet->FormListHead, &CurrentForm->Link); + break; + + // + // Storage + // + case EFI_IFR_VARSTORE_OP: + // + // Create a buffer Storage for this FormSet + // + Storage = CreateStorage (FormSet); + Storage->Type = EFI_HII_VARSTORE_BUFFER; + + CopyMem (&Storage->VarStoreId, &((EFI_IFR_VARSTORE *) OpCodeData)->VarStoreId, sizeof (EFI_VARSTORE_ID)); + CopyMem (&Storage->Guid, &((EFI_IFR_VARSTORE *) OpCodeData)->Guid, sizeof (EFI_GUID)); + CopyMem (&Storage->Size, &((EFI_IFR_VARSTORE *) OpCodeData)->Size, sizeof (UINT16)); + + Storage->Buffer = AllocateZeroPool (Storage->Size); + Storage->EditBuffer = AllocateZeroPool (Storage->Size); + + AsciiString = (CHAR8 *) ((EFI_IFR_VARSTORE *) OpCodeData)->Name; + Storage->Name = AllocateZeroPool (AsciiStrSize (AsciiString) * 2); + ASSERT (Storage->Name != NULL); + for (Index = 0; AsciiString[Index] != 0; Index++) { + Storage->Name[Index] = (CHAR16) AsciiString[Index]; + } + + // + // Initialize <ConfigHdr> + // + InitializeConfigHdr (FormSet, Storage); + break; + + case EFI_IFR_VARSTORE_NAME_VALUE_OP: + // + // Create a name/value Storage for this FormSet + // + Storage = CreateStorage (FormSet); + Storage->Type = EFI_HII_VARSTORE_NAME_VALUE; + + CopyMem (&Storage->VarStoreId, &((EFI_IFR_VARSTORE_NAME_VALUE *) OpCodeData)->VarStoreId, sizeof (EFI_VARSTORE_ID)); + CopyMem (&Storage->Guid, &((EFI_IFR_VARSTORE_NAME_VALUE *) OpCodeData)->Guid, sizeof (EFI_GUID)); + + // + // Initialize <ConfigHdr> + // + InitializeConfigHdr (FormSet, Storage); + break; + + case EFI_IFR_VARSTORE_EFI_OP: + // + // Create a EFI variable Storage for this FormSet + // + Storage = CreateStorage (FormSet); + Storage->Type = EFI_HII_VARSTORE_EFI_VARIABLE; + + CopyMem (&Storage->VarStoreId, &((EFI_IFR_VARSTORE_EFI *) OpCodeData)->VarStoreId, sizeof (EFI_VARSTORE_ID)); + CopyMem (&Storage->Guid, &((EFI_IFR_VARSTORE_EFI *) OpCodeData)->Guid, sizeof (EFI_GUID)); + CopyMem (&Storage->Attributes, &((EFI_IFR_VARSTORE_EFI *) OpCodeData)->Attributes, sizeof (UINT32)); + break; + + // + // DefaultStore + // + case EFI_IFR_DEFAULTSTORE_OP: + DefaultStore = AllocateZeroPool (sizeof (FORMSET_DEFAULTSTORE)); + DefaultStore->Signature = FORMSET_DEFAULTSTORE_SIGNATURE; + + CopyMem (&DefaultStore->DefaultId, &((EFI_IFR_DEFAULTSTORE *) OpCodeData)->DefaultId, sizeof (UINT16)); + CopyMem (&DefaultStore->DefaultName, &((EFI_IFR_DEFAULTSTORE *) OpCodeData)->DefaultName, sizeof (EFI_STRING_ID)); + + // + // Insert to DefaultStore list of this Formset + // + InsertTailList (&FormSet->DefaultStoreListHead, &DefaultStore->Link); + break; + + // + // Statements + // + case EFI_IFR_SUBTITLE_OP: + CurrentStatement = CreateStatement (OpCodeData, FormSet, CurrentForm); + CurrentStatement->Flags = ((EFI_IFR_SUBTITLE *) OpCodeData)->Flags; + + if (Scope) { + mInScopeSubtitle = TRUE; + } + break; + + case EFI_IFR_TEXT_OP: + CurrentStatement = CreateStatement (OpCodeData, FormSet, CurrentForm); + + CopyMem (&CurrentStatement->TextTwo, &((EFI_IFR_TEXT *) OpCodeData)->TextTwo, sizeof (EFI_STRING_ID)); + break; + + // + // Questions + // + case EFI_IFR_ACTION_OP: + CurrentStatement = CreateQuestion (OpCodeData, FormSet, CurrentForm); + + if (OpCodeLength == sizeof (EFI_IFR_ACTION_1)) { + // + // No QuestionConfig present, so no configuration string will be processed + // + CurrentStatement->QuestionConfig = 0; + } else { + CopyMem (&CurrentStatement->QuestionConfig, &((EFI_IFR_ACTION *) OpCodeData)->QuestionConfig, sizeof (EFI_STRING_ID)); + } + break; + + case EFI_IFR_RESET_BUTTON_OP: + CurrentStatement = CreateQuestion (OpCodeData, FormSet, CurrentForm); + + CopyMem (&CurrentStatement->DefaultId, &((EFI_IFR_RESET_BUTTON *) OpCodeData)->DefaultId, sizeof (EFI_DEFAULT_ID)); + break; + + case EFI_IFR_REF_OP: + CurrentStatement = CreateQuestion (OpCodeData, FormSet, CurrentForm); + + CopyMem (&CurrentStatement->RefFormId, &((EFI_IFR_REF *) OpCodeData)->FormId, sizeof (EFI_FORM_ID)); + if (OpCodeLength >= sizeof (EFI_IFR_REF2)) { + CopyMem (&CurrentStatement->RefQuestionId, &((EFI_IFR_REF2 *) OpCodeData)->QuestionId, sizeof (EFI_QUESTION_ID)); + + if (OpCodeLength >= sizeof (EFI_IFR_REF3)) { + CopyMem (&CurrentStatement->RefFormSetId, &((EFI_IFR_REF3 *) OpCodeData)->FormSetId, sizeof (EFI_GUID)); + + if (OpCodeLength >= sizeof (EFI_IFR_REF4)) { + CopyMem (&CurrentStatement->RefDevicePath, &((EFI_IFR_REF4 *) OpCodeData)->DevicePath, sizeof (EFI_STRING_ID)); + } + } + } + break; + + case EFI_IFR_ONE_OF_OP: + case EFI_IFR_NUMERIC_OP: + CurrentStatement = CreateQuestion (OpCodeData, FormSet, CurrentForm); + + CurrentStatement->Flags = ((EFI_IFR_ONE_OF *) OpCodeData)->Flags; + Value = &CurrentStatement->HiiValue; + + switch (CurrentStatement->Flags & EFI_IFR_NUMERIC_SIZE) { + case EFI_IFR_NUMERIC_SIZE_1: + CurrentStatement->Minimum = ((EFI_IFR_NUMERIC *) OpCodeData)->data.u8.MinValue; + CurrentStatement->Maximum = ((EFI_IFR_NUMERIC *) OpCodeData)->data.u8.MaxValue; + CurrentStatement->Step = ((EFI_IFR_NUMERIC *) OpCodeData)->data.u8.Step; + CurrentStatement->StorageWidth = sizeof (UINT8); + Value->Type = EFI_IFR_TYPE_NUM_SIZE_8; + break; + + case EFI_IFR_NUMERIC_SIZE_2: + CopyMem (&CurrentStatement->Minimum, &((EFI_IFR_NUMERIC *) OpCodeData)->data.u16.MinValue, sizeof (UINT16)); + CopyMem (&CurrentStatement->Maximum, &((EFI_IFR_NUMERIC *) OpCodeData)->data.u16.MaxValue, sizeof (UINT16)); + CopyMem (&CurrentStatement->Step, &((EFI_IFR_NUMERIC *) OpCodeData)->data.u16.Step, sizeof (UINT16)); + CurrentStatement->StorageWidth = sizeof (UINT16); + Value->Type = EFI_IFR_TYPE_NUM_SIZE_16; + break; + + case EFI_IFR_NUMERIC_SIZE_4: + CopyMem (&CurrentStatement->Minimum, &((EFI_IFR_NUMERIC *) OpCodeData)->data.u32.MinValue, sizeof (UINT32)); + CopyMem (&CurrentStatement->Maximum, &((EFI_IFR_NUMERIC *) OpCodeData)->data.u32.MaxValue, sizeof (UINT32)); + CopyMem (&CurrentStatement->Step, &((EFI_IFR_NUMERIC *) OpCodeData)->data.u32.Step, sizeof (UINT32)); + CurrentStatement->StorageWidth = sizeof (UINT32); + Value->Type = EFI_IFR_TYPE_NUM_SIZE_32; + break; + + case EFI_IFR_NUMERIC_SIZE_8: + CopyMem (&CurrentStatement->Minimum, &((EFI_IFR_NUMERIC *) OpCodeData)->data.u64.MinValue, sizeof (UINT64)); + CopyMem (&CurrentStatement->Maximum, &((EFI_IFR_NUMERIC *) OpCodeData)->data.u64.MaxValue, sizeof (UINT64)); + CopyMem (&CurrentStatement->Step, &((EFI_IFR_NUMERIC *) OpCodeData)->data.u64.Step, sizeof (UINT64)); + CurrentStatement->StorageWidth = sizeof (UINT64); + Value->Type = EFI_IFR_TYPE_NUM_SIZE_64; + break; + + default: + break; + } + + InitializeRequestElement (FormSet, CurrentStatement); + + if ((Operand == EFI_IFR_ONE_OF_OP) && Scope) { + SuppressForOption = TRUE; + } + break; + + case EFI_IFR_ORDERED_LIST_OP: + CurrentStatement = CreateQuestion (OpCodeData, FormSet, CurrentForm); + + CurrentStatement->Flags = ((EFI_IFR_ORDERED_LIST *) OpCodeData)->Flags; + CurrentStatement->MaxContainers = ((EFI_IFR_ORDERED_LIST *) OpCodeData)->MaxContainers; + CurrentStatement->StorageWidth = (UINT16)(CurrentStatement->MaxContainers * sizeof (UINT8)); + InitializeRequestElement (FormSet, CurrentStatement); + + // + // No buffer type is defined in EFI_IFR_TYPE_VALUE, so a Configuration Driver + // has to use FormBrowser2.Callback() to retrieve the uncommited data for + // an interactive orderedlist (i.e. with EFI_IFR_FLAG_CALLBACK flag set). + // + CurrentStatement->HiiValue.Type = EFI_IFR_TYPE_OTHER; + CurrentStatement->BufferValue = AllocateZeroPool (CurrentStatement->StorageWidth); + + if (Scope) { + SuppressForOption = TRUE; + } + break; + + case EFI_IFR_CHECKBOX_OP: + CurrentStatement = CreateQuestion (OpCodeData, FormSet, CurrentForm); + + CurrentStatement->Flags = ((EFI_IFR_CHECKBOX *) OpCodeData)->Flags; + CurrentStatement->StorageWidth = sizeof (BOOLEAN); + CurrentStatement->HiiValue.Type = EFI_IFR_TYPE_BOOLEAN; + + InitializeRequestElement (FormSet, CurrentStatement); + break; + + case EFI_IFR_STRING_OP: + CurrentStatement = CreateQuestion (OpCodeData, FormSet, CurrentForm); + + // + // MinSize is the minimum number of characters that can be accepted for this opcode, + // MaxSize is the maximum number of characters that can be accepted for this opcode. + // The characters are stored as Unicode, so the storage width should multiply 2. + // + CurrentStatement->Minimum = ((EFI_IFR_STRING *) OpCodeData)->MinSize; + CurrentStatement->Maximum = ((EFI_IFR_STRING *) OpCodeData)->MaxSize; + CurrentStatement->StorageWidth = (UINT16)((UINTN) CurrentStatement->Maximum * sizeof (UINT16)); + CurrentStatement->Flags = ((EFI_IFR_STRING *) OpCodeData)->Flags; + + CurrentStatement->HiiValue.Type = EFI_IFR_TYPE_STRING; + CurrentStatement->BufferValue = AllocateZeroPool (CurrentStatement->StorageWidth); + + InitializeRequestElement (FormSet, CurrentStatement); + break; + + case EFI_IFR_PASSWORD_OP: + CurrentStatement = CreateQuestion (OpCodeData, FormSet, CurrentForm); + + // + // MinSize is the minimum number of characters that can be accepted for this opcode, + // MaxSize is the maximum number of characters that can be accepted for this opcode. + // The characters are stored as Unicode, so the storage width should multiply 2. + // + CopyMem (&CurrentStatement->Minimum, &((EFI_IFR_PASSWORD *) OpCodeData)->MinSize, sizeof (UINT16)); + CopyMem (&CurrentStatement->Maximum, &((EFI_IFR_PASSWORD *) OpCodeData)->MaxSize, sizeof (UINT16)); + CurrentStatement->StorageWidth = (UINT16)((UINTN) CurrentStatement->Maximum * sizeof (UINT16)); + + CurrentStatement->HiiValue.Type = EFI_IFR_TYPE_STRING; + CurrentStatement->BufferValue = AllocateZeroPool (CurrentStatement->StorageWidth); + + InitializeRequestElement (FormSet, CurrentStatement); + break; + + case EFI_IFR_DATE_OP: + CurrentStatement = CreateQuestion (OpCodeData, FormSet, CurrentForm); + + CurrentStatement->Flags = ((EFI_IFR_DATE *) OpCodeData)->Flags; + CurrentStatement->HiiValue.Type = EFI_IFR_TYPE_DATE; + + if ((CurrentStatement->Flags & EFI_QF_DATE_STORAGE) == QF_DATE_STORAGE_NORMAL) { + CurrentStatement->StorageWidth = sizeof (EFI_HII_DATE); + + InitializeRequestElement (FormSet, CurrentStatement); + } else { + // + // Don't assign storage for RTC type of date/time + // + CurrentStatement->Storage = NULL; + CurrentStatement->StorageWidth = 0; + } + break; + + case EFI_IFR_TIME_OP: + CurrentStatement = CreateQuestion (OpCodeData, FormSet, CurrentForm); + + CurrentStatement->Flags = ((EFI_IFR_TIME *) OpCodeData)->Flags; + CurrentStatement->HiiValue.Type = EFI_IFR_TYPE_TIME; + + if ((CurrentStatement->Flags & QF_TIME_STORAGE) == QF_TIME_STORAGE_NORMAL) { + CurrentStatement->StorageWidth = sizeof (EFI_IFR_TIME); + + InitializeRequestElement (FormSet, CurrentStatement); + } else { + // + // Don't assign storage for RTC type of date/time + // + CurrentStatement->Storage = NULL; + CurrentStatement->StorageWidth = 0; + } + break; + + // + // Default + // + case EFI_IFR_DEFAULT_OP: + // + // EFI_IFR_DEFAULT appear in scope of a Question, + // It creates a default value for the current question. + // A Question may have more than one Default value which have different default types. + // + CurrentDefault = AllocateZeroPool (sizeof (QUESTION_DEFAULT)); + CurrentDefault->Signature = QUESTION_DEFAULT_SIGNATURE; + + CurrentDefault->Value.Type = ((EFI_IFR_DEFAULT *) OpCodeData)->Type; + CopyMem (&CurrentDefault->DefaultId, &((EFI_IFR_DEFAULT *) OpCodeData)->DefaultId, sizeof (UINT16)); + CopyMem (&CurrentDefault->Value.Value, &((EFI_IFR_DEFAULT *) OpCodeData)->Value, sizeof (EFI_IFR_TYPE_VALUE)); + ExtendValueToU64 (&CurrentDefault->Value); + + // + // Insert to Default Value list of current Question + // + InsertTailList (&CurrentStatement->DefaultListHead, &CurrentDefault->Link); + + if (Scope) { + InScopeDefault = TRUE; + } + break; + + // + // Option + // + case EFI_IFR_ONE_OF_OPTION_OP: + // + // EFI_IFR_ONE_OF_OPTION appear in scope of a Question. + // It create a selection for use in current Question. + // + CurrentOption = AllocateZeroPool (sizeof (QUESTION_OPTION)); + CurrentOption->Signature = QUESTION_OPTION_SIGNATURE; + + CurrentOption->Flags = ((EFI_IFR_ONE_OF_OPTION *) OpCodeData)->Flags; + CurrentOption->Value.Type = ((EFI_IFR_ONE_OF_OPTION *) OpCodeData)->Type; + CopyMem (&CurrentOption->Text, &((EFI_IFR_ONE_OF_OPTION *) OpCodeData)->Option, sizeof (EFI_STRING_ID)); + CopyMem (&CurrentOption->Value.Value, &((EFI_IFR_ONE_OF_OPTION *) OpCodeData)->Value, sizeof (EFI_IFR_TYPE_VALUE)); + ExtendValueToU64 (&CurrentOption->Value); + + if (InScopeOptionSuppress) { + CurrentOption->SuppressExpression = OptionSuppressExpression; + } + + // + // Insert to Option list of current Question + // + InsertTailList (&CurrentStatement->OptionListHead, &CurrentOption->Link); + break; + + // + // Conditional + // + case EFI_IFR_NO_SUBMIT_IF_OP: + case EFI_IFR_INCONSISTENT_IF_OP: + // + // Create an Expression node + // + CurrentExpression = CreateExpression (CurrentForm); + CopyMem (&CurrentExpression->Error, &((EFI_IFR_INCONSISTENT_IF *) OpCodeData)->Error, sizeof (EFI_STRING_ID)); + + if (Operand == EFI_IFR_NO_SUBMIT_IF_OP) { + CurrentExpression->Type = EFI_HII_EXPRESSION_NO_SUBMIT_IF; + InsertTailList (&CurrentStatement->NoSubmitListHead, &CurrentExpression->Link); + } else { + CurrentExpression->Type = EFI_HII_EXPRESSION_INCONSISTENT_IF; + InsertTailList (&CurrentStatement->InconsistentListHead, &CurrentExpression->Link); + } + break; + + case EFI_IFR_SUPPRESS_IF_OP: + // + // Question and Option will appear in scope of this OpCode + // + CurrentExpression = CreateExpression (CurrentForm); + CurrentExpression->Type = EFI_HII_EXPRESSION_SUPPRESS_IF; + InsertTailList (&CurrentForm->ExpressionListHead, &CurrentExpression->Link); + + if (SuppressForOption) { + InScopeOptionSuppress = TRUE; + OptionSuppressExpression = CurrentExpression; + } else { + mInScopeSuppress = TRUE; + mSuppressExpression = CurrentExpression; + } + break; + + case EFI_IFR_GRAY_OUT_IF_OP: + // + // Questions will appear in scope of this OpCode + // + CurrentExpression = CreateExpression (CurrentForm); + CurrentExpression->Type = EFI_HII_EXPRESSION_GRAY_OUT_IF; + InsertTailList (&CurrentForm->ExpressionListHead, &CurrentExpression->Link); + + mInScopeGrayOut = TRUE; + mGrayOutExpression = CurrentExpression; + break; + + case EFI_IFR_DISABLE_IF_OP: + // + // The DisableIf expression should only rely on constant, so it could be + // evaluated at initialization and it will not be queued + // + CurrentExpression = AllocateZeroPool (sizeof (FORM_EXPRESSION)); + CurrentExpression->Signature = FORM_EXPRESSION_SIGNATURE; + CurrentExpression->Type = EFI_HII_EXPRESSION_DISABLE_IF; + InitializeListHead (&CurrentExpression->OpCodeListHead); + + InScopeDisable = TRUE; + OpCodeDisabled = FALSE; + + // + // Take a look at next OpCode to see whether current expression consists + // of single OpCode + // + if (((EFI_IFR_OP_HEADER *) (OpCodeData + OpCodeLength))->Scope == 0) { + SingleOpCodeExpression = TRUE; + } + break; + + // + // Expression + // + case EFI_IFR_VALUE_OP: + CurrentExpression = CreateExpression (CurrentForm); + CurrentExpression->Type = EFI_HII_EXPRESSION_VALUE; + InsertTailList (&CurrentForm->ExpressionListHead, &CurrentExpression->Link); + + if (InScopeDefault) { + // + // Used for default (EFI_IFR_DEFAULT) + // + CurrentDefault->ValueExpression = CurrentExpression; + } else { + // + // If used for a question, then the question will be read-only + // + CurrentStatement->ValueExpression = CurrentExpression; + } + break; + + case EFI_IFR_RULE_OP: + CurrentExpression = CreateExpression (CurrentForm); + CurrentExpression->Type = EFI_HII_EXPRESSION_RULE; + + CurrentExpression->RuleId = ((EFI_IFR_RULE *) OpCodeData)->RuleId; + InsertTailList (&CurrentForm->ExpressionListHead, &CurrentExpression->Link); + break; + + // + // Image + // + case EFI_IFR_IMAGE_OP: + // + // Get ScopeOpcode from top of stack + // + PopScope (&ScopeOpCode); + PushScope (ScopeOpCode); + + switch (ScopeOpCode) { + case EFI_IFR_FORM_SET_OP: + ImageId = &FormSet->ImageId; + break; + + case EFI_IFR_FORM_OP: + ImageId = &CurrentForm->ImageId; + break; + + case EFI_IFR_ONE_OF_OPTION_OP: + ImageId = &CurrentOption->ImageId; + break; + + default: + ImageId = &CurrentStatement->ImageId; + break; + } + + CopyMem (ImageId, &((EFI_IFR_IMAGE *) OpCodeData)->Id, sizeof (EFI_IMAGE_ID)); + break; + + // + // Refresh + // + case EFI_IFR_REFRESH_OP: + CurrentStatement->RefreshInterval = ((EFI_IFR_REFRESH *) OpCodeData)->RefreshInterval; + break; + + // + // Vendor specific + // + case EFI_IFR_GUID_OP: + if (CompareGuid (&gTianoHiiIfrGuid, (EFI_GUID *)(OpCodeData + sizeof (EFI_IFR_OP_HEADER)))) { + // + // Tiano specific GUIDed opcodes + // + switch (((EFI_IFR_GUID_LABEL *) OpCodeData)->ExtendOpCode) { + case EFI_IFR_EXTEND_OP_LABEL: + // + // just ignore label + // + break; + + case EFI_IFR_EXTEND_OP_BANNER: + if (FormSet->SubClass == EFI_FRONT_PAGE_SUBCLASS) { + CopyMem ( + &BannerData->Banner[((EFI_IFR_GUID_BANNER *) OpCodeData)->LineNumber][ + ((EFI_IFR_GUID_BANNER *) OpCodeData)->Alignment], + &((EFI_IFR_GUID_BANNER *) OpCodeData)->Title, + sizeof (EFI_STRING_ID) + ); + } + break; + + case EFI_IFR_EXTEND_OP_CLASS: + CopyMem (&FormSet->Class, &((EFI_IFR_GUID_CLASS *) OpCodeData)->Class, sizeof (UINT16)); + break; + + case EFI_IFR_EXTEND_OP_SUBCLASS: + CopyMem (&FormSet->SubClass, &((EFI_IFR_GUID_SUBCLASS *) OpCodeData)->SubClass, sizeof (UINT16)); + break; + + default: + break; + } + } + break; + + // + // Scope End + // + case EFI_IFR_END_OP: + Status = PopScope (&ScopeOpCode); + if (EFI_ERROR (Status)) { + ResetScopeStack (); + return Status; + } + + switch (ScopeOpCode) { + case EFI_IFR_FORM_SET_OP: + // + // End of FormSet, update FormSet IFR binary length + // to stop parsing substantial OpCodes + // + FormSet->IfrBinaryLength = OpCodeOffset; + break; + + case EFI_IFR_FORM_OP: + // + // End of Form + // + CurrentForm = NULL; + break; + + case EFI_IFR_ONE_OF_OPTION_OP: + // + // End of Option + // + CurrentOption = NULL; + break; + + case EFI_IFR_SUBTITLE_OP: + mInScopeSubtitle = FALSE; + break; + + case EFI_IFR_NO_SUBMIT_IF_OP: + case EFI_IFR_INCONSISTENT_IF_OP: + // + // Ignore end of EFI_IFR_NO_SUBMIT_IF and EFI_IFR_INCONSISTENT_IF + // + break; + + case EFI_IFR_SUPPRESS_IF_OP: + if (SuppressForOption) { + InScopeOptionSuppress = FALSE; + } else { + mInScopeSuppress = FALSE; + } + break; + + case EFI_IFR_GRAY_OUT_IF_OP: + mInScopeGrayOut = FALSE; + break; + + case EFI_IFR_DISABLE_IF_OP: + InScopeDisable = FALSE; + OpCodeDisabled = FALSE; + break; + + case EFI_IFR_ONE_OF_OP: + case EFI_IFR_ORDERED_LIST_OP: + SuppressForOption = FALSE; + break; + + case EFI_IFR_DEFAULT_OP: + InScopeDefault = FALSE; + break; + + default: + if (IsExpressionOpCode (ScopeOpCode)) { + if (InScopeDisable) { + // + // Evaluate DisableIf expression + // + Status = EvaluateExpression (FormSet, CurrentForm, CurrentExpression); + if (EFI_ERROR (Status)) { + return Status; + } + if (CurrentExpression->Result.Type != EFI_IFR_TYPE_BOOLEAN) { + return EFI_INVALID_PARAMETER; + } + + OpCodeDisabled = CurrentExpression->Result.Value.b; + // + // DisableIf Expression is only used once and not quequed, free it + // + DestroyExpression (CurrentExpression); + } + + // + // End of current Expression + // + CurrentExpression = NULL; + } + break; + } + break; + + default: + break; + } + } + + return EFI_SUCCESS; +} diff --git a/MdeModulePkg/Universal/SetupBrowserDxe/InputHandler.c b/MdeModulePkg/Universal/SetupBrowserDxe/InputHandler.c new file mode 100644 index 0000000000..5257f32b66 --- /dev/null +++ b/MdeModulePkg/Universal/SetupBrowserDxe/InputHandler.c @@ -0,0 +1,1146 @@ +/** @file + +Copyright (c) 2004 - 2007, Intel Corporation +All rights reserved. This program and the accompanying materials +are licensed and made available under the terms and conditions of the BSD License +which accompanies this distribution. The full text of the license may be found at +http://opensource.org/licenses/bsd-license.php + +THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, +WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. + +Module Name: + + InputHandler.c + +Abstract: + + Implementation for handling user input from the User Interface + +Revision History + + +**/ + +#include "Ui.h" +#include "Setup.h" + + +/** + Get string or password input from user. + + @param MenuOption Pointer to the current input menu. + @param Prompt The prompt string shown on popup window. + @param StringPtr Destination for use input string. + + @retval EFI_SUCCESS If string input is read successfully + @retval EFI_DEVICE_ERROR If operation fails + +**/ +EFI_STATUS +ReadString ( + IN UI_MENU_OPTION *MenuOption, + IN CHAR16 *Prompt, + OUT CHAR16 *StringPtr + ) +{ + EFI_STATUS Status; + EFI_INPUT_KEY Key; + CHAR16 NullCharacter; + UINTN ScreenSize; + CHAR16 Space[2]; + CHAR16 KeyPad[2]; + CHAR16 *TempString; + CHAR16 *BufferedString; + UINTN Index; + UINTN Count; + UINTN Start; + UINTN Top; + UINTN DimensionsWidth; + UINTN DimensionsHeight; + BOOLEAN CursorVisible; + UINTN Minimum; + UINTN Maximum; + FORM_BROWSER_STATEMENT *Question; + BOOLEAN IsPassword; + + DimensionsWidth = gScreenDimensions.RightColumn - gScreenDimensions.LeftColumn; + DimensionsHeight = gScreenDimensions.BottomRow - gScreenDimensions.TopRow; + + NullCharacter = CHAR_NULL; + ScreenSize = GetStringWidth (Prompt) / sizeof (CHAR16); + Space[0] = L' '; + Space[1] = CHAR_NULL; + + Question = MenuOption->ThisTag; + Minimum = (UINTN) Question->Minimum; + Maximum = (UINTN) Question->Maximum; + + if (Question->Operand == EFI_IFR_PASSWORD_OP) { + IsPassword = TRUE; + } else { + IsPassword = FALSE; + } + + TempString = AllocateZeroPool ((Maximum + 1)* sizeof (CHAR16)); + ASSERT (TempString); + + if (ScreenSize < (Maximum + 1)) { + ScreenSize = Maximum + 1; + } + + if ((ScreenSize + 2) > DimensionsWidth) { + ScreenSize = DimensionsWidth - 2; + } + + BufferedString = AllocateZeroPool (ScreenSize * 2); + ASSERT (BufferedString); + + Start = (DimensionsWidth - ScreenSize - 2) / 2 + gScreenDimensions.LeftColumn + 1; + Top = ((DimensionsHeight - 6) / 2) + gScreenDimensions.TopRow - 1; + + // + // Display prompt for string + // + CreatePopUp (ScreenSize, 4, &NullCharacter, Prompt, Space, &NullCharacter); + + gST->ConOut->SetAttribute (gST->ConOut, EFI_TEXT_ATTR (EFI_BLACK, EFI_LIGHTGRAY)); + + CursorVisible = gST->ConOut->Mode->CursorVisible; + gST->ConOut->EnableCursor (gST->ConOut, TRUE); + + do { + Status = WaitForKeyStroke (&Key); + ASSERT_EFI_ERROR (Status); + + gST->ConOut->SetAttribute (gST->ConOut, EFI_TEXT_ATTR (EFI_BLACK, EFI_LIGHTGRAY)); + switch (Key.UnicodeChar) { + case CHAR_NULL: + switch (Key.ScanCode) { + case SCAN_LEFT: + break; + + case SCAN_RIGHT: + break; + + case SCAN_ESC: + gBS->FreePool (TempString); + gBS->FreePool (BufferedString); + gST->ConOut->SetAttribute (gST->ConOut, EFI_TEXT_ATTR (EFI_LIGHTGRAY, EFI_BLACK)); + gST->ConOut->EnableCursor (gST->ConOut, CursorVisible); + return EFI_DEVICE_ERROR; + + default: + break; + } + + break; + + case CHAR_CARRIAGE_RETURN: + if (GetStringWidth (StringPtr) >= ((Minimum + 1) * sizeof (CHAR16))) { + + gBS->FreePool (TempString); + gBS->FreePool (BufferedString); + gST->ConOut->SetAttribute (gST->ConOut, EFI_TEXT_ATTR (EFI_LIGHTGRAY, EFI_BLACK)); + gST->ConOut->EnableCursor (gST->ConOut, CursorVisible); + return EFI_SUCCESS; + } else { + // + // Simply create a popup to tell the user that they had typed in too few characters. + // To save code space, we can then treat this as an error and return back to the menu. + // + do { + CreateDialog (4, TRUE, 0, NULL, &Key, &NullCharacter, gMiniString, gPressEnter, &NullCharacter); + } while (Key.UnicodeChar != CHAR_CARRIAGE_RETURN); + + gBS->FreePool (TempString); + gBS->FreePool (BufferedString); + gST->ConOut->SetAttribute (gST->ConOut, EFI_TEXT_ATTR (EFI_LIGHTGRAY, EFI_BLACK)); + gST->ConOut->EnableCursor (gST->ConOut, CursorVisible); + return EFI_DEVICE_ERROR; + } + + break; + + case CHAR_BACKSPACE: + if (StringPtr[0] != CHAR_NULL) { + for (Index = 0; StringPtr[Index] != CHAR_NULL; Index++) { + TempString[Index] = StringPtr[Index]; + } + // + // Effectively truncate string by 1 character + // + TempString[Index - 1] = CHAR_NULL; + StrCpy (StringPtr, TempString); + } + + default: + // + // If it is the beginning of the string, don't worry about checking maximum limits + // + if ((StringPtr[0] == CHAR_NULL) && (Key.UnicodeChar != CHAR_BACKSPACE)) { + StrnCpy (StringPtr, &Key.UnicodeChar, 1); + StrnCpy (TempString, &Key.UnicodeChar, 1); + } else if ((GetStringWidth (StringPtr) < ((Maximum + 1) * sizeof (CHAR16))) && (Key.UnicodeChar != CHAR_BACKSPACE)) { + KeyPad[0] = Key.UnicodeChar; + KeyPad[1] = CHAR_NULL; + StrCat (StringPtr, KeyPad); + StrCat (TempString, KeyPad); + } + + // + // If the width of the input string is now larger than the screen, we nee to + // adjust the index to start printing portions of the string + // + SetUnicodeMem (BufferedString, ScreenSize - 1, L' '); + PrintStringAt (Start + 1, Top + 3, BufferedString); + + if ((GetStringWidth (StringPtr) / 2) > (DimensionsWidth - 2)) { + Index = (GetStringWidth (StringPtr) / 2) - DimensionsWidth + 2; + } else { + Index = 0; + } + + if (IsPassword) { + gST->ConOut->SetCursorPosition (gST->ConOut, Start + 1, Top + 3); + } + + for (Count = 0; Index + 1 < GetStringWidth (StringPtr) / 2; Index++, Count++) { + BufferedString[Count] = StringPtr[Index]; + + if (IsPassword) { + PrintChar (L'*'); + } + } + + if (!IsPassword) { + PrintStringAt (Start + 1, Top + 3, BufferedString); + } + break; + } + + gST->ConOut->SetAttribute (gST->ConOut, EFI_TEXT_ATTR (EFI_LIGHTGRAY, EFI_BLACK)); + gST->ConOut->SetCursorPosition (gST->ConOut, Start + GetStringWidth (StringPtr) / 2, Top + 3); + } while (TRUE); + +} + + +/** + This routine reads a numeric value from the user input. + + @param Selection Pointer to current selection. + @param MenuOption Pointer to the current input menu. + + @retval EFI_SUCCESS If numerical input is read successfully + @retval EFI_DEVICE_ERROR If operation fails + +**/ +EFI_STATUS +GetNumericInput ( + IN UI_MENU_SELECTION *Selection, + IN UI_MENU_OPTION *MenuOption + ) +{ + EFI_STATUS Status; + UINTN Column; + UINTN Row; + CHAR16 InputText[23]; + CHAR16 FormattedNumber[22]; + UINT64 PreviousNumber[20]; + UINTN Count; + UINTN Loop; + BOOLEAN ManualInput; + BOOLEAN HexInput; + BOOLEAN DateOrTime; + UINTN InputWidth; + UINT64 EditValue; + UINT64 Step; + UINT64 Minimum; + UINT64 Maximum; + UINTN EraseLen; + UINT8 Digital; + EFI_INPUT_KEY Key; + EFI_HII_VALUE *QuestionValue; + FORM_BROWSER_FORM *Form; + FORM_BROWSER_FORMSET *FormSet; + FORM_BROWSER_STATEMENT *Question; + + Column = MenuOption->OptCol; + Row = MenuOption->Row; + PreviousNumber[0] = 0; + Count = 0; + InputWidth = 0; + Digital = 0; + + FormSet = Selection->FormSet; + Form = Selection->Form; + Question = MenuOption->ThisTag; + QuestionValue = &Question->HiiValue; + Step = Question->Step; + Minimum = Question->Minimum; + Maximum = Question->Maximum; + + if ((Question->Operand == EFI_IFR_DATE_OP) || (Question->Operand == EFI_IFR_TIME_OP)) { + DateOrTime = TRUE; + } else { + DateOrTime = FALSE; + } + + // + // Prepare Value to be edit + // + EraseLen = 0; + EditValue = 0; + if (Question->Operand == EFI_IFR_DATE_OP) { + Step = 1; + Minimum = 1; + + switch (MenuOption->Sequence) { + case 0: + Maximum = 12; + EraseLen = 4; + EditValue = QuestionValue->Value.date.Month; + break; + + case 1: + Maximum = 31; + EraseLen = 3; + EditValue = QuestionValue->Value.date.Day; + break; + + case 2: + Maximum = 0xffff; + EraseLen = 5; + EditValue = QuestionValue->Value.date.Year; + break; + + default: + break; + } + } else if (Question->Operand == EFI_IFR_TIME_OP) { + Step = 1; + Minimum = 0; + + switch (MenuOption->Sequence) { + case 0: + Maximum = 23; + EraseLen = 4; + EditValue = QuestionValue->Value.time.Hour; + break; + + case 1: + Maximum = 59; + EraseLen = 3; + EditValue = QuestionValue->Value.time.Minute; + break; + + case 2: + Maximum = 59; + EraseLen = 3; + EditValue = QuestionValue->Value.time.Second; + break; + + default: + break; + } + } else { + // + // Numeric + // + EraseLen = gOptionBlockWidth; + EditValue = QuestionValue->Value.u64; + if (Maximum == 0) { + Maximum = (UINT64) -1; + } + } + + if (Step == 0) { + ManualInput = TRUE; + } else { + ManualInput = FALSE; + } + + if ((Question->Operand == EFI_IFR_NUMERIC_OP) && + ((Question->Flags & EFI_IFR_DISPLAY) == EFI_IFR_DISPLAY_UINT_HEX)) { + HexInput = TRUE; + } else { + HexInput = FALSE; + } + + if (ManualInput) { + if (HexInput) { + InputWidth = Question->StorageWidth * 2; + } else { + switch (Question->StorageWidth) { + case 1: + InputWidth = 3; + break; + + case 2: + InputWidth = 5; + break; + + case 4: + InputWidth = 10; + break; + + case 8: + InputWidth = 20; + break; + + default: + InputWidth = 0; + break; + } + } + + InputText[0] = LEFT_NUMERIC_DELIMITER; + SetUnicodeMem (InputText + 1, InputWidth, L' '); + InputText[InputWidth + 1] = RIGHT_NUMERIC_DELIMITER; + InputText[InputWidth + 2] = L'\0'; + + PrintAt (Column, Row, InputText); + Column++; + } + + // + // First time we enter this handler, we need to check to see if + // we were passed an increment or decrement directive + // + do { + Key.UnicodeChar = CHAR_NULL; + if (gDirection != 0) { + Key.ScanCode = gDirection; + gDirection = 0; + goto TheKey2; + } + + Status = WaitForKeyStroke (&Key); + +TheKey2: + switch (Key.UnicodeChar) { + + case '+': + case '-': + if (Key.UnicodeChar == '+') { + Key.ScanCode = SCAN_RIGHT; + } else { + Key.ScanCode = SCAN_LEFT; + } + Key.UnicodeChar = CHAR_NULL; + goto TheKey2; + + case CHAR_NULL: + switch (Key.ScanCode) { + case SCAN_LEFT: + case SCAN_RIGHT: + if (DateOrTime) { + // + // By setting this value, we will return back to the caller. + // We need to do this since an auto-refresh will destroy the adjustment + // based on what the real-time-clock is showing. So we always commit + // upon changing the value. + // + gDirection = SCAN_DOWN; + } + + if (!ManualInput) { + if (Key.ScanCode == SCAN_LEFT) { + if (EditValue > Step) { + EditValue = EditValue - Step; + } else { + EditValue = Minimum; + } + } else if (Key.ScanCode == SCAN_RIGHT) { + EditValue = EditValue + Step; + if (EditValue > Maximum) { + EditValue = Maximum; + } + } + + ZeroMem (FormattedNumber, 21 * sizeof (CHAR16)); + if (Question->Operand == EFI_IFR_DATE_OP) { + if (MenuOption->Sequence == 2) { + // + // Year + // + UnicodeSPrint (FormattedNumber, 21 * sizeof (CHAR16), L"%04d", EditValue); + } else { + // + // Month/Day + // + UnicodeSPrint (FormattedNumber, 21 * sizeof (CHAR16), L"%02d", EditValue); + } + + if (MenuOption->Sequence == 0) { + FormattedNumber[EraseLen - 2] = DATE_SEPARATOR; + } else if (MenuOption->Sequence == 1) { + FormattedNumber[EraseLen - 1] = DATE_SEPARATOR; + } + } else if (Question->Operand == EFI_IFR_TIME_OP) { + UnicodeSPrint (FormattedNumber, 21 * sizeof (CHAR16), L"%02d", EditValue); + + if (MenuOption->Sequence == 0) { + FormattedNumber[EraseLen - 2] = TIME_SEPARATOR; + } else if (MenuOption->Sequence == 1) { + FormattedNumber[EraseLen - 1] = TIME_SEPARATOR; + } + } else { + QuestionValue->Value.u64 = EditValue; + PrintFormattedNumber (Question, FormattedNumber, 21 * sizeof (CHAR16)); + } + + gST->ConOut->SetAttribute (gST->ConOut, FIELD_TEXT | FIELD_BACKGROUND); + for (Loop = 0; Loop < EraseLen; Loop++) { + PrintAt (MenuOption->OptCol + Loop, MenuOption->Row, L" "); + } + gST->ConOut->SetAttribute (gST->ConOut, FIELD_TEXT_HIGHLIGHT | FIELD_BACKGROUND_HIGHLIGHT); + + if (MenuOption->Sequence == 0) { + PrintCharAt (MenuOption->OptCol, Row, LEFT_NUMERIC_DELIMITER); + Column = MenuOption->OptCol + 1; + } + + PrintStringAt (Column, Row, FormattedNumber); + + if (!DateOrTime || MenuOption->Sequence == 2) { + PrintChar (RIGHT_NUMERIC_DELIMITER); + } + } + break; + + case SCAN_UP: + case SCAN_DOWN: + goto EnterCarriageReturn; + + case SCAN_ESC: + return EFI_DEVICE_ERROR; + + default: + break; + } + + break; + +EnterCarriageReturn: + + case CHAR_CARRIAGE_RETURN: + // + // Store Edit value back to Question + // + if (Question->Operand == EFI_IFR_DATE_OP) { + switch (MenuOption->Sequence) { + case 0: + QuestionValue->Value.date.Month = (UINT8) EditValue; + break; + + case 1: + QuestionValue->Value.date.Day = (UINT8) EditValue; + break; + + case 2: + QuestionValue->Value.date.Year = (UINT16) EditValue; + break; + + default: + break; + } + } else if (Question->Operand == EFI_IFR_TIME_OP) { + switch (MenuOption->Sequence) { + case 0: + QuestionValue->Value.time.Hour = (UINT8) EditValue; + break; + + case 1: + QuestionValue->Value.time.Minute = (UINT8) EditValue; + break; + + case 2: + QuestionValue->Value.time.Second = (UINT8) EditValue; + break; + + default: + break; + } + } else { + // + // Numeric + // + QuestionValue->Value.u64 = EditValue; + } + + // + // Check to see if the Value is something reasonable against consistency limitations. + // If not, let's kick the error specified. + // + Status = ValidateQuestion (FormSet, Form, Question, EFI_HII_EXPRESSION_INCONSISTENT_IF); + if (EFI_ERROR (Status)) { + // + // Input value is not valid, restore Question Value + // + GetQuestionValue (FormSet, Form, Question, TRUE); + } else { + SetQuestionValue (FormSet, Form, Question, TRUE); + if (!DateOrTime || (Question->Storage != NULL)) { + // + // NV flag is unnecessary for RTC type of Date/Time + // + UpdateStatusBar (NV_UPDATE_REQUIRED, Question->QuestionFlags, TRUE); + } + } + + return Status; + break; + + case CHAR_BACKSPACE: + if (ManualInput) { + if (Count == 0) { + break; + } + // + // Remove a character + // + EditValue = PreviousNumber[Count - 1]; + UpdateStatusBar (INPUT_ERROR, Question->QuestionFlags, FALSE); + Count--; + Column--; + PrintAt (Column, Row, L" "); + } + break; + + default: + if (ManualInput) { + if (HexInput) { + if (!R8_IsHexDigit (&Digital, Key.UnicodeChar)) { + UpdateStatusBar (INPUT_ERROR, Question->QuestionFlags, TRUE); + break; + } + } else { + if (Key.UnicodeChar > L'9' || Key.UnicodeChar < L'0') { + UpdateStatusBar (INPUT_ERROR, Question->QuestionFlags, TRUE); + break; + } + } + + // + // If Count exceed input width, there is no way more is valid + // + if (Count >= InputWidth) { + break; + } + // + // Someone typed something valid! + // + if (Count != 0) { + if (HexInput) { + EditValue = LShiftU64 (EditValue, 4) + Digital; + } else { + EditValue = MultU64x32 (EditValue, 10) + (Key.UnicodeChar - L'0'); + } + } else { + if (HexInput) { + EditValue = Digital; + } else { + EditValue = Key.UnicodeChar - L'0'; + } + } + + if (EditValue > Maximum) { + UpdateStatusBar (INPUT_ERROR, Question->QuestionFlags, TRUE); + EditValue = PreviousNumber[Count]; + break; + } else { + UpdateStatusBar (INPUT_ERROR, Question->QuestionFlags, FALSE); + } + + Count++; + PreviousNumber[Count] = EditValue; + + PrintCharAt (Column, Row, Key.UnicodeChar); + Column++; + } + break; + } + } while (TRUE); + +} + + +/** + Get selection for OneOf and OrderedList (Left/Right will be ignored). + + @param Selection Pointer to current selection. + @param MenuOption Pointer to the current input menu. + + @retval EFI_SUCCESS If Option input is processed successfully + @retval EFI_DEVICE_ERROR If operation fails + +**/ +EFI_STATUS +GetSelectionInputPopUp ( + IN UI_MENU_SELECTION *Selection, + IN UI_MENU_OPTION *MenuOption + ) +{ + EFI_STATUS Status; + EFI_INPUT_KEY Key; + UINTN Index; + CHAR16 *StringPtr; + CHAR16 *TempStringPtr; + UINTN Index2; + UINTN TopOptionIndex; + UINTN HighlightOptionIndex; + UINTN Start; + UINTN End; + UINTN Top; + UINTN Bottom; + UINTN PopUpMenuLines; + UINTN MenuLinesInView; + UINTN PopUpWidth; + CHAR16 Character; + INT32 SavedAttribute; + BOOLEAN ShowDownArrow; + BOOLEAN ShowUpArrow; + UINTN DimensionsWidth; + LIST_ENTRY *Link; + BOOLEAN OrderedList; + UINT8 *ValueArray; + EFI_HII_VALUE HiiValue; + EFI_HII_VALUE *HiiValueArray; + UINTN OptionCount; + QUESTION_OPTION *OneOfOption; + QUESTION_OPTION *CurrentOption; + FORM_BROWSER_STATEMENT *Question; + + DimensionsWidth = gScreenDimensions.RightColumn - gScreenDimensions.LeftColumn; + + ValueArray = NULL; + CurrentOption = NULL; + ShowDownArrow = FALSE; + ShowUpArrow = FALSE; + + StringPtr = AllocateZeroPool ((gOptionBlockWidth + 1) * 2); + ASSERT (StringPtr); + + Question = MenuOption->ThisTag; + if (Question->Operand == EFI_IFR_ORDERED_LIST_OP) { + ValueArray = Question->BufferValue; + OrderedList = TRUE; + } else { + OrderedList = FALSE; + } + + // + // Calculate Option count + // + if (OrderedList) { + for (Index = 0; Index < Question->MaxContainers; Index++) { + if (ValueArray[Index] == 0) { + break; + } + } + + OptionCount = Index; + } else { + OptionCount = 0; + Link = GetFirstNode (&Question->OptionListHead); + while (!IsNull (&Question->OptionListHead, Link)) { + OneOfOption = QUESTION_OPTION_FROM_LINK (Link); + + OptionCount++; + + Link = GetNextNode (&Question->OptionListHead, Link); + } + } + + // + // Prepare HiiValue array + // + HiiValueArray = AllocateZeroPool (OptionCount * sizeof (EFI_HII_VALUE)); + ASSERT (HiiValueArray != NULL); + Link = GetFirstNode (&Question->OptionListHead); + for (Index = 0; Index < OptionCount; Index++) { + if (OrderedList) { + HiiValueArray[Index].Type = EFI_IFR_TYPE_NUM_SIZE_8; + HiiValueArray[Index].Value.u8 = ValueArray[Index]; + } else { + OneOfOption = QUESTION_OPTION_FROM_LINK (Link); + CopyMem (&HiiValueArray[Index], &OneOfOption->Value, sizeof (EFI_HII_VALUE)); + Link = GetNextNode (&Question->OptionListHead, Link); + } + } + + // + // Move Suppressed Option to list tail + // + PopUpMenuLines = 0; + for (Index = 0; Index < OptionCount; Index++) { + OneOfOption = ValueToOption (Question, &HiiValueArray[OptionCount - Index - 1]); + if (OneOfOption == NULL) { + return EFI_NOT_FOUND; + } + + RemoveEntryList (&OneOfOption->Link); + + if ((OneOfOption->SuppressExpression != NULL) && + (OneOfOption->SuppressExpression->Result.Value.b)) { + // + // This option is suppressed, insert to tail + // + InsertTailList (&Question->OptionListHead, &OneOfOption->Link); + } else { + // + // Insert to head + // + InsertHeadList (&Question->OptionListHead, &OneOfOption->Link); + + PopUpMenuLines++; + } + } + + // + // Get the number of one of options present and its size + // + PopUpWidth = 0; + HighlightOptionIndex = 0; + Link = GetFirstNode (&Question->OptionListHead); + for (Index = 0; Index < PopUpMenuLines; Index++) { + OneOfOption = QUESTION_OPTION_FROM_LINK (Link); + + StringPtr = GetToken (OneOfOption->Text, MenuOption->Handle); + if (StrLen (StringPtr) > PopUpWidth) { + PopUpWidth = StrLen (StringPtr); + } + gBS->FreePool (StringPtr); + + if (!OrderedList && CompareHiiValue (&Question->HiiValue, &OneOfOption->Value, NULL) == 0) { + // + // Find current selected Option for OneOf + // + HighlightOptionIndex = Index; + } + + Link = GetNextNode (&Question->OptionListHead, Link); + } + + // + // Perform popup menu initialization. + // + PopUpWidth = PopUpWidth + POPUP_PAD_SPACE_COUNT; + + SavedAttribute = gST->ConOut->Mode->Attribute; + gST->ConOut->SetAttribute (gST->ConOut, POPUP_TEXT | POPUP_BACKGROUND); + + if ((PopUpWidth + POPUP_FRAME_WIDTH) > DimensionsWidth) { + PopUpWidth = DimensionsWidth - POPUP_FRAME_WIDTH; + } + + Start = (DimensionsWidth - PopUpWidth - POPUP_FRAME_WIDTH) / 2 + gScreenDimensions.LeftColumn; + End = Start + PopUpWidth + POPUP_FRAME_WIDTH; + Top = gScreenDimensions.TopRow + NONE_FRONT_PAGE_HEADER_HEIGHT; + Bottom = gScreenDimensions.BottomRow - STATUS_BAR_HEIGHT - FOOTER_HEIGHT - 1; + + MenuLinesInView = Bottom - Top - 1; + if (MenuLinesInView >= PopUpMenuLines) { + Top = Top + (MenuLinesInView - PopUpMenuLines) / 2; + Bottom = Top + PopUpMenuLines + 1; + } else { + ShowDownArrow = TRUE; + } + + if (HighlightOptionIndex > (MenuLinesInView - 1)) { + TopOptionIndex = HighlightOptionIndex - MenuLinesInView + 1; + } else { + TopOptionIndex = 0; + } + + do { + // + // Clear that portion of the screen + // + ClearLines (Start, End, Top, Bottom, POPUP_TEXT | POPUP_BACKGROUND); + + // + // Draw "One of" pop-up menu + // + Character = BOXDRAW_DOWN_RIGHT; + PrintCharAt (Start, Top, Character); + for (Index = Start; Index + 2 < End; Index++) { + if ((ShowUpArrow) && ((Index + 1) == (Start + End) / 2)) { + Character = GEOMETRICSHAPE_UP_TRIANGLE; + } else { + Character = BOXDRAW_HORIZONTAL; + } + + PrintChar (Character); + } + + Character = BOXDRAW_DOWN_LEFT; + PrintChar (Character); + Character = BOXDRAW_VERTICAL; + for (Index = Top + 1; Index < Bottom; Index++) { + PrintCharAt (Start, Index, Character); + PrintCharAt (End - 1, Index, Character); + } + + // + // Move to top Option + // + Link = GetFirstNode (&Question->OptionListHead); + for (Index = 0; Index < TopOptionIndex; Index++) { + Link = GetNextNode (&Question->OptionListHead, Link); + } + + // + // Display the One of options + // + Index2 = Top + 1; + for (Index = TopOptionIndex; (Index < PopUpMenuLines) && (Index2 < Bottom); Index++) { + OneOfOption = QUESTION_OPTION_FROM_LINK (Link); + Link = GetNextNode (&Question->OptionListHead, Link); + + StringPtr = GetToken (OneOfOption->Text, MenuOption->Handle); + // + // If the string occupies multiple lines, truncate it to fit in one line, + // and append a "..." for indication. + // + if (StrLen (StringPtr) > (PopUpWidth - 1)) { + TempStringPtr = AllocateZeroPool (sizeof (CHAR16) * (PopUpWidth - 1)); + ASSERT ( TempStringPtr != NULL ); + CopyMem (TempStringPtr, StringPtr, (sizeof (CHAR16) * (PopUpWidth - 5))); + gBS->FreePool (StringPtr); + StringPtr = TempStringPtr; + StrCat (StringPtr, L"..."); + } + + if (Index == HighlightOptionIndex) { + // + // Highlight the selected one + // + CurrentOption = OneOfOption; + + gST->ConOut->SetAttribute (gST->ConOut, PICKLIST_HIGHLIGHT_TEXT | PICKLIST_HIGHLIGHT_BACKGROUND); + PrintStringAt (Start + 2, Index2, StringPtr); + gST->ConOut->SetAttribute (gST->ConOut, POPUP_TEXT | POPUP_BACKGROUND); + } else { + gST->ConOut->SetAttribute (gST->ConOut, POPUP_TEXT | POPUP_BACKGROUND); + PrintStringAt (Start + 2, Index2, StringPtr); + } + + Index2++; + gBS->FreePool (StringPtr); + } + + Character = BOXDRAW_UP_RIGHT; + PrintCharAt (Start, Bottom, Character); + for (Index = Start; Index + 2 < End; Index++) { + if ((ShowDownArrow) && ((Index + 1) == (Start + End) / 2)) { + Character = GEOMETRICSHAPE_DOWN_TRIANGLE; + } else { + Character = BOXDRAW_HORIZONTAL; + } + + PrintChar (Character); + } + + Character = BOXDRAW_UP_LEFT; + PrintChar (Character); + + // + // Get User selection + // + Key.UnicodeChar = CHAR_NULL; + if ((gDirection == SCAN_UP) || (gDirection == SCAN_DOWN)) { + Key.ScanCode = gDirection; + gDirection = 0; + goto TheKey; + } + + Status = WaitForKeyStroke (&Key); + +TheKey: + switch (Key.UnicodeChar) { + case '+': + if (OrderedList) { + if ((TopOptionIndex > 0) && (TopOptionIndex == HighlightOptionIndex)) { + // + // Highlight reaches the top of the popup window, scroll one menu item. + // + TopOptionIndex--; + ShowDownArrow = TRUE; + } + + if (TopOptionIndex == 0) { + ShowUpArrow = FALSE; + } + + if (HighlightOptionIndex > 0) { + HighlightOptionIndex--; + + SwapListEntries (CurrentOption->Link.BackLink, &CurrentOption->Link); + } + } + break; + + case '-': + // + // If an ordered list op-code, we will allow for a popup of +/- keys + // to create an ordered list of items + // + if (OrderedList) { + if (((TopOptionIndex + MenuLinesInView) < PopUpMenuLines) && + (HighlightOptionIndex == (TopOptionIndex + MenuLinesInView - 1))) { + // + // Highlight reaches the bottom of the popup window, scroll one menu item. + // + TopOptionIndex++; + ShowUpArrow = TRUE; + } + + if ((TopOptionIndex + MenuLinesInView) == PopUpMenuLines) { + ShowDownArrow = FALSE; + } + + if (HighlightOptionIndex < (PopUpMenuLines - 1)) { + HighlightOptionIndex++; + + SwapListEntries (&CurrentOption->Link, CurrentOption->Link.ForwardLink); + } + } + break; + + case CHAR_NULL: + switch (Key.ScanCode) { + case SCAN_UP: + case SCAN_DOWN: + if (Key.ScanCode == SCAN_UP) { + if ((TopOptionIndex > 0) && (TopOptionIndex == HighlightOptionIndex)) { + // + // Highlight reaches the top of the popup window, scroll one menu item. + // + TopOptionIndex--; + ShowDownArrow = TRUE; + } + + if (TopOptionIndex == 0) { + ShowUpArrow = FALSE; + } + + if (HighlightOptionIndex > 0) { + HighlightOptionIndex--; + } + } else { + if (((TopOptionIndex + MenuLinesInView) < PopUpMenuLines) && + (HighlightOptionIndex == (TopOptionIndex + MenuLinesInView - 1))) { + // + // Highlight reaches the bottom of the popup window, scroll one menu item. + // + TopOptionIndex++; + ShowUpArrow = TRUE; + } + + if ((TopOptionIndex + MenuLinesInView) == PopUpMenuLines) { + ShowDownArrow = FALSE; + } + + if (HighlightOptionIndex < (PopUpMenuLines - 1)) { + HighlightOptionIndex++; + } + } + break; + + case SCAN_ESC: + gST->ConOut->SetAttribute (gST->ConOut, SavedAttribute); + + // + // Restore link list order for orderedlist + // + if (OrderedList) { + HiiValue.Type = EFI_IFR_TYPE_NUM_SIZE_8; + HiiValue.Value.u64 = 0; + for (Index = 0; Index < Question->MaxContainers; Index++) { + HiiValue.Value.u8 = ValueArray[Index]; + if (HiiValue.Value.u8) { + break; + } + + OneOfOption = ValueToOption (Question, &HiiValue); + if (OneOfOption == NULL) { + return EFI_NOT_FOUND; + } + + RemoveEntryList (&OneOfOption->Link); + InsertTailList (&Question->OptionListHead, &OneOfOption->Link); + } + } + + gBS->FreePool (HiiValueArray); + return EFI_DEVICE_ERROR; + + default: + break; + } + + break; + + case CHAR_CARRIAGE_RETURN: + // + // return the current selection + // + if (OrderedList) { + Index = 0; + Link = GetFirstNode (&Question->OptionListHead); + while (!IsNull (&Question->OptionListHead, Link)) { + OneOfOption = QUESTION_OPTION_FROM_LINK (Link); + + Question->BufferValue[Index] = OneOfOption->Value.Value.u8; + + Index++; + if (Index > Question->MaxContainers) { + break; + } + + Link = GetNextNode (&Question->OptionListHead, Link); + } + } else { + CopyMem (&Question->HiiValue, &CurrentOption->Value, sizeof (EFI_HII_VALUE)); + } + + gST->ConOut->SetAttribute (gST->ConOut, SavedAttribute); + gBS->FreePool (HiiValueArray); + + Status = ValidateQuestion (Selection->FormSet, Selection->Form, Question, EFI_HII_EXPRESSION_INCONSISTENT_IF); + if (EFI_ERROR (Status)) { + // + // Input value is not valid, restore Question Value + // + GetQuestionValue (Selection->FormSet, Selection->Form, Question, TRUE); + } else { + SetQuestionValue (Selection->FormSet, Selection->Form, Question, TRUE); + UpdateStatusBar (NV_UPDATE_REQUIRED, Question->QuestionFlags, TRUE); + } + + return Status; + + default: + break; + } + } while (TRUE); + +} + +EFI_STATUS +WaitForKeyStroke ( + OUT EFI_INPUT_KEY *Key + ) +{ + EFI_STATUS Status; + + do { + UiWaitForSingleEvent (gST->ConIn->WaitForKey, 0, 0); + Status = gST->ConIn->ReadKeyStroke (gST->ConIn, Key); + } while (EFI_ERROR(Status)); + + return Status; +} diff --git a/MdeModulePkg/Universal/SetupBrowserDxe/Presentation.c b/MdeModulePkg/Universal/SetupBrowserDxe/Presentation.c new file mode 100644 index 0000000000..631f6413b8 --- /dev/null +++ b/MdeModulePkg/Universal/SetupBrowserDxe/Presentation.c @@ -0,0 +1,928 @@ +/** @file +Copyright (c) 2004 - 2007, Intel Corporation +All rights reserved. This program and the accompanying materials +are licensed and made available under the terms and conditions of the BSD License +which accompanies this distribution. The full text of the license may be found at +http://opensource.org/licenses/bsd-license.php + +THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, +WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. + +Module Name: + Presentation.c + +Abstract: + + Some presentation routines. + + +**/ + +#include "Setup.h" +#include "Ui.h" + +BOOLEAN mHiiPackageListUpdated; +UI_MENU_SELECTION *gCurrentSelection; + + +/** + Clear retangle with specified text attribute. + + @param LeftColumn Left column of retangle. + @param RightColumn Right column of retangle. + @param TopRow Start row of retangle. + @param BottomRow End row of retangle. + @param TextAttribute The character foreground and background. + + @return None. + +**/ +VOID +ClearLines ( + UINTN LeftColumn, + UINTN RightColumn, + UINTN TopRow, + UINTN BottomRow, + UINTN TextAttribute + ) +{ + CHAR16 *Buffer; + UINTN Row; + + // + // For now, allocate an arbitrarily long buffer + // + Buffer = AllocateZeroPool (0x10000); + ASSERT (Buffer != NULL); + + // + // Set foreground and background as defined + // + gST->ConOut->SetAttribute (gST->ConOut, TextAttribute); + + // + // Much faster to buffer the long string instead of print it a character at a time + // + SetUnicodeMem (Buffer, RightColumn - LeftColumn, L' '); + + // + // Clear the desired area with the appropriate foreground/background + // + for (Row = TopRow; Row <= BottomRow; Row++) { + PrintStringAt (LeftColumn, Row, Buffer); + } + + gST->ConOut->SetCursorPosition (gST->ConOut, LeftColumn, TopRow); + + gBS->FreePool (Buffer); + return ; +} + +VOID +NewStrCat ( + CHAR16 *Destination, + 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++; + + StrCpy (Destination + Length, Source); +} + +UINTN +GetStringWidth ( + CHAR16 *String + ) +{ + UINTN Index; + UINTN Count; + UINTN IncrementValue; + + Index = 0; + Count = 0; + IncrementValue = 1; + + do { + // + // Advance to the null-terminator or to the first width directive + // + for (; + (String[Index] != NARROW_CHAR) && (String[Index] != WIDE_CHAR) && (String[Index] != 0); + Index++, Count = Count + IncrementValue + ) + ; + + // + // We hit the null-terminator, we now have a count + // + if (String[Index] == 0) { + break; + } + // + // We encountered a narrow directive - strip it from the size calculation since it doesn't get printed + // and also set the flag that determines what we increment by.(if narrow, increment by 1, if wide increment by 2) + // + if (String[Index] == NARROW_CHAR) { + // + // Skip to the next character + // + Index++; + IncrementValue = 1; + } else { + // + // Skip to the next character + // + Index++; + IncrementValue = 2; + } + } while (String[Index] != 0); + + // + // Increment by one to include the null-terminator in the size + // + Count++; + + return Count * sizeof (CHAR16); +} + +VOID +DisplayPageFrame ( + VOID + ) +{ + UINTN Index; + UINT8 Line; + UINT8 Alignment; + CHAR16 Character; + CHAR16 *Buffer; + CHAR16 *StrFrontPageBanner; + UINTN Row; + EFI_SCREEN_DESCRIPTOR LocalScreen; + + ZeroMem (&LocalScreen, sizeof (EFI_SCREEN_DESCRIPTOR)); + gST->ConOut->QueryMode (gST->ConOut, gST->ConOut->Mode->Mode, &LocalScreen.RightColumn, &LocalScreen.BottomRow); + ClearLines (0, LocalScreen.RightColumn, 0, LocalScreen.BottomRow, KEYHELP_BACKGROUND); + + CopyMem (&LocalScreen, &gScreenDimensions, sizeof (EFI_SCREEN_DESCRIPTOR)); + + // + // For now, allocate an arbitrarily long buffer + // + Buffer = AllocateZeroPool (0x10000); + ASSERT (Buffer != NULL); + + Character = BOXDRAW_HORIZONTAL; + + for (Index = 0; Index + 2 < (LocalScreen.RightColumn - LocalScreen.LeftColumn); Index++) { + Buffer[Index] = Character; + } + + if (gClassOfVfr == EFI_FRONT_PAGE_SUBCLASS) { + // + // ClearLines(0, LocalScreen.RightColumn, 0, BANNER_HEIGHT-1, BANNER_TEXT | BANNER_BACKGROUND); + // + ClearLines ( + LocalScreen.LeftColumn, + LocalScreen.RightColumn, + LocalScreen.TopRow, + FRONT_PAGE_HEADER_HEIGHT - 1 + LocalScreen.TopRow, + BANNER_TEXT | BANNER_BACKGROUND + ); + // + // for (Line = 0; Line < BANNER_HEIGHT; Line++) { + // + for (Line = (UINT8) LocalScreen.TopRow; Line < BANNER_HEIGHT + (UINT8) LocalScreen.TopRow; Line++) { + // + // for (Alignment = 0; Alignment < BANNER_COLUMNS; Alignment++) { + // + for (Alignment = (UINT8) LocalScreen.LeftColumn; + Alignment < BANNER_COLUMNS + (UINT8) LocalScreen.LeftColumn; + Alignment++ + ) { + if (BannerData->Banner[Line - (UINT8) LocalScreen.TopRow][Alignment - (UINT8) LocalScreen.LeftColumn] != 0x0000) { + StrFrontPageBanner = GetToken ( + BannerData->Banner[Line - (UINT8) LocalScreen.TopRow][Alignment - (UINT8) LocalScreen.LeftColumn], + FrontPageHandle + ); + } else { + continue; + } + + switch (Alignment - LocalScreen.LeftColumn) { + case 0: + // + // Handle left column + // + PrintStringAt (LocalScreen.LeftColumn, Line, StrFrontPageBanner); + break; + + case 1: + // + // Handle center column + // + PrintStringAt ( + LocalScreen.LeftColumn + (LocalScreen.RightColumn - LocalScreen.LeftColumn) / 3, + Line, + StrFrontPageBanner + ); + break; + + case 2: + // + // Handle right column + // + PrintStringAt ( + LocalScreen.LeftColumn + (LocalScreen.RightColumn - LocalScreen.LeftColumn) * 2 / 3, + Line, + StrFrontPageBanner + ); + break; + } + + gBS->FreePool (StrFrontPageBanner); + } + } + } + + ClearLines ( + LocalScreen.LeftColumn, + LocalScreen.RightColumn, + LocalScreen.BottomRow - STATUS_BAR_HEIGHT - FOOTER_HEIGHT, + LocalScreen.BottomRow - STATUS_BAR_HEIGHT - 1, + KEYHELP_TEXT | KEYHELP_BACKGROUND + ); + + if (gClassOfVfr != EFI_FRONT_PAGE_SUBCLASS) { + ClearLines ( + LocalScreen.LeftColumn, + LocalScreen.RightColumn, + LocalScreen.TopRow, + LocalScreen.TopRow + NONE_FRONT_PAGE_HEADER_HEIGHT - 1, + TITLE_TEXT | TITLE_BACKGROUND + ); + // + // Print Top border line + // +------------------------------------------------------------------------------+ + // ? ? + // +------------------------------------------------------------------------------+ + // + Character = BOXDRAW_DOWN_RIGHT; + + PrintChar (Character); + PrintString (Buffer); + + Character = BOXDRAW_DOWN_LEFT; + PrintChar (Character); + + Character = BOXDRAW_VERTICAL; + for (Row = LocalScreen.TopRow + 1; Row <= LocalScreen.TopRow + NONE_FRONT_PAGE_HEADER_HEIGHT - 2; Row++) { + PrintCharAt (LocalScreen.LeftColumn, Row, Character); + PrintCharAt (LocalScreen.RightColumn - 1, Row, Character); + } + + Character = BOXDRAW_UP_RIGHT; + PrintCharAt (LocalScreen.LeftColumn, LocalScreen.TopRow + NONE_FRONT_PAGE_HEADER_HEIGHT - 1, Character); + PrintString (Buffer); + + Character = BOXDRAW_UP_LEFT; + PrintChar (Character); + + if (gClassOfVfr == EFI_SETUP_APPLICATION_SUBCLASS) { + // + // Print Bottom border line + // +------------------------------------------------------------------------------+ + // ? ? + // +------------------------------------------------------------------------------+ + // + Character = BOXDRAW_DOWN_RIGHT; + PrintCharAt (LocalScreen.LeftColumn, LocalScreen.BottomRow - STATUS_BAR_HEIGHT - FOOTER_HEIGHT, Character); + + PrintString (Buffer); + + Character = BOXDRAW_DOWN_LEFT; + PrintChar (Character); + Character = BOXDRAW_VERTICAL; + for (Row = LocalScreen.BottomRow - STATUS_BAR_HEIGHT - FOOTER_HEIGHT + 1; + Row <= LocalScreen.BottomRow - STATUS_BAR_HEIGHT - 2; + Row++ + ) { + PrintCharAt (LocalScreen.LeftColumn, Row, Character); + PrintCharAt (LocalScreen.RightColumn - 1, Row, Character); + } + + Character = BOXDRAW_UP_RIGHT; + PrintCharAt (LocalScreen.LeftColumn, LocalScreen.BottomRow - STATUS_BAR_HEIGHT - 1, Character); + + PrintString (Buffer); + + Character = BOXDRAW_UP_LEFT; + PrintChar (Character); + } + } + + gBS->FreePool (Buffer); + +} + + +/** + Evaluate all expressions in a Form. + + @param FormSet FormSet this Form belongs to. + @param Form The Form. + + @retval EFI_SUCCESS The expression evaluated successfuly + +**/ +EFI_STATUS +EvaluateFormExpressions ( + IN FORM_BROWSER_FORMSET *FormSet, + IN FORM_BROWSER_FORM *Form + ) +{ + EFI_STATUS Status; + LIST_ENTRY *Link; + FORM_EXPRESSION *Expression; + + Link = GetFirstNode (&Form->ExpressionListHead); + while (!IsNull (&Form->ExpressionListHead, Link)) { + Expression = FORM_EXPRESSION_FROM_LINK (Link); + Link = GetNextNode (&Form->ExpressionListHead, Link); + + if (Expression->Type == EFI_HII_EXPRESSION_INCONSISTENT_IF || + Expression->Type == EFI_HII_EXPRESSION_NO_SUBMIT_IF) { + // + // Postpone Form validation to Question editing or Form submiting + // + continue; + } + + Status = EvaluateExpression (FormSet, Form, Expression); + if (EFI_ERROR (Status)) { + return Status; + } + } + + return EFI_SUCCESS; +} + +/* ++------------------------------------------------------------------------------+ +?F2=Previous Page Setup Page ? ++------------------------------------------------------------------------------+ + + + + + + + + + + + + + + + + + ++------------------------------------------------------------------------------+ +?F1=Scroll Help F9=Reset to Defaults F10=Save and Exit ? +| ^"=Move Highlight <Spacebar> Toggles Checkbox Esc=Discard Changes | ++------------------------------------------------------------------------------+ +*/ +EFI_STATUS +DisplayForm ( + IN OUT UI_MENU_SELECTION *Selection + ) +{ + CHAR16 *StringPtr; + UINT16 MenuItemCount; + EFI_HII_HANDLE Handle; + BOOLEAN Suppress; + EFI_SCREEN_DESCRIPTOR LocalScreen; + UINT16 Width; + UINTN ArrayEntry; + CHAR16 *OutputString; + LIST_ENTRY *Link; + FORM_BROWSER_STATEMENT *Statement; + UINT16 NumberOfLines; + EFI_STATUS Status; + + Handle = Selection->Handle; + MenuItemCount = 0; + ArrayEntry = 0; + OutputString = NULL; + + UiInitMenu (); + + CopyMem (&LocalScreen, &gScreenDimensions, sizeof (EFI_SCREEN_DESCRIPTOR)); + + StringPtr = GetToken (Selection->FormSet->FormSetTitle, Handle); + + if (gClassOfVfr != EFI_FRONT_PAGE_SUBCLASS) { + gST->ConOut->SetAttribute (gST->ConOut, TITLE_TEXT | TITLE_BACKGROUND); + PrintStringAt ( + (LocalScreen.RightColumn + LocalScreen.LeftColumn - GetStringWidth (StringPtr) / 2) / 2, + LocalScreen.TopRow + 1, + StringPtr + ); + } + + if (gClassOfVfr == EFI_SETUP_APPLICATION_SUBCLASS) { + gST->ConOut->SetAttribute (gST->ConOut, KEYHELP_TEXT | KEYHELP_BACKGROUND); + + // + // Display the infrastructure strings + // + if (!IsListEmpty (&gMenuList)) { + PrintStringAt (LocalScreen.LeftColumn + 2, LocalScreen.TopRow + 1, gFunctionTwoString); + } + + PrintStringAt (LocalScreen.LeftColumn + 2, LocalScreen.BottomRow - 4, gFunctionOneString); + PrintStringAt ( + LocalScreen.LeftColumn + (LocalScreen.RightColumn - LocalScreen.LeftColumn) / 3, + LocalScreen.BottomRow - 4, + gFunctionNineString + ); + PrintStringAt ( + LocalScreen.LeftColumn + (LocalScreen.RightColumn - LocalScreen.LeftColumn) * 2 / 3, + LocalScreen.BottomRow - 4, + gFunctionTenString + ); + PrintAt (LocalScreen.LeftColumn + 2, LocalScreen.BottomRow - 3, L"%c%c%s", ARROW_UP, ARROW_DOWN, gMoveHighlight); + PrintStringAt ( + LocalScreen.LeftColumn + (LocalScreen.RightColumn - LocalScreen.LeftColumn) / 3, + LocalScreen.BottomRow - 3, + gEscapeString + ); + } + // + // Remove Buffer allocated for StringPtr after it has been used. + // + gBS->FreePool (StringPtr); + + // + // Evaluate all the Expressions in this Form + // + Status = EvaluateFormExpressions (Selection->FormSet, Selection->Form); + if (EFI_ERROR (Status)) { + return Status; + } + + Link = GetFirstNode (&Selection->Form->StatementListHead); + while (!IsNull (&Selection->Form->StatementListHead, Link)) { + Statement = FORM_BROWSER_STATEMENT_FROM_LINK (Link); + + if (Statement->SuppressExpression != NULL) { + Suppress = Statement->SuppressExpression->Result.Value.b; + } else { + Suppress = FALSE; + } + + if (!Suppress) { + StringPtr = GetToken (Statement->Prompt, Handle); + + Width = GetWidth (Statement, Handle); + + NumberOfLines = 1; + ArrayEntry = 0; + for (; GetLineByWidth (StringPtr, Width, &ArrayEntry, &OutputString) != 0x0000;) { + // + // If there is more string to process print on the next row and increment the Skip value + // + if (StrLen (&StringPtr[ArrayEntry])) { + NumberOfLines++; + } + + gBS->FreePool (OutputString); + } + + // + // We are NOT!! removing this StringPtr buffer via FreePool since it is being used in the menuoptions, we will do + // it in UiFreeMenu. + // + UiAddMenuOption (StringPtr, Selection->Handle, Statement, NumberOfLines, MenuItemCount); + MenuItemCount++; + } + + Link = GetNextNode (&Selection->Form->StatementListHead, Link); + } + + Status = UiDisplayMenu (Selection); + + UiFreeMenu (); + + return Status; +} + +VOID +InitializeBrowserStrings ( + VOID + ) +{ + gFunctionOneString = GetToken (STRING_TOKEN (FUNCTION_ONE_STRING), gHiiHandle); + gFunctionTwoString = GetToken (STRING_TOKEN (FUNCTION_TWO_STRING), gHiiHandle); + gFunctionNineString = GetToken (STRING_TOKEN (FUNCTION_NINE_STRING), gHiiHandle); + gFunctionTenString = GetToken (STRING_TOKEN (FUNCTION_TEN_STRING), gHiiHandle); + gEnterString = GetToken (STRING_TOKEN (ENTER_STRING), gHiiHandle); + gEnterCommitString = GetToken (STRING_TOKEN (ENTER_COMMIT_STRING), gHiiHandle); + gEscapeString = GetToken (STRING_TOKEN (ESCAPE_STRING), gHiiHandle); + gSaveFailed = GetToken (STRING_TOKEN (SAVE_FAILED), gHiiHandle); + gMoveHighlight = GetToken (STRING_TOKEN (MOVE_HIGHLIGHT), gHiiHandle); + gMakeSelection = GetToken (STRING_TOKEN (MAKE_SELECTION), gHiiHandle); + gDecNumericInput = GetToken (STRING_TOKEN (DEC_NUMERIC_INPUT), gHiiHandle); + gHexNumericInput = GetToken (STRING_TOKEN (HEX_NUMERIC_INPUT), gHiiHandle); + gToggleCheckBox = GetToken (STRING_TOKEN (TOGGLE_CHECK_BOX), gHiiHandle); + gPromptForData = GetToken (STRING_TOKEN (PROMPT_FOR_DATA), gHiiHandle); + gPromptForPassword = GetToken (STRING_TOKEN (PROMPT_FOR_PASSWORD), gHiiHandle); + gPromptForNewPassword = GetToken (STRING_TOKEN (PROMPT_FOR_NEW_PASSWORD), gHiiHandle); + gConfirmPassword = GetToken (STRING_TOKEN (CONFIRM_PASSWORD), gHiiHandle); + gConfirmError = GetToken (STRING_TOKEN (CONFIRM_ERROR), gHiiHandle); + gPassowordInvalid = GetToken (STRING_TOKEN (PASSWORD_INVALID), gHiiHandle); + gPressEnter = GetToken (STRING_TOKEN (PRESS_ENTER), gHiiHandle); + gEmptyString = GetToken (STRING_TOKEN (EMPTY_STRING), gHiiHandle); + gAreYouSure = GetToken (STRING_TOKEN (ARE_YOU_SURE), gHiiHandle); + gYesResponse = GetToken (STRING_TOKEN (ARE_YOU_SURE_YES), gHiiHandle); + gNoResponse = GetToken (STRING_TOKEN (ARE_YOU_SURE_NO), gHiiHandle); + gMiniString = GetToken (STRING_TOKEN (MINI_STRING), gHiiHandle); + gPlusString = GetToken (STRING_TOKEN (PLUS_STRING), gHiiHandle); + gMinusString = GetToken (STRING_TOKEN (MINUS_STRING), gHiiHandle); + gAdjustNumber = GetToken (STRING_TOKEN (ADJUST_NUMBER), gHiiHandle); + return ; +} + +VOID +FreeBrowserStrings ( + VOID + ) +{ + SafeFreePool (gFunctionOneString); + SafeFreePool (gFunctionTwoString); + SafeFreePool (gFunctionNineString); + SafeFreePool (gFunctionTenString); + SafeFreePool (gEnterString); + SafeFreePool (gEnterCommitString); + SafeFreePool (gEscapeString); + SafeFreePool (gMoveHighlight); + SafeFreePool (gMakeSelection); + SafeFreePool (gDecNumericInput); + SafeFreePool (gHexNumericInput); + SafeFreePool (gToggleCheckBox); + SafeFreePool (gPromptForData); + SafeFreePool (gPromptForPassword); + SafeFreePool (gPromptForNewPassword); + SafeFreePool (gConfirmPassword); + SafeFreePool (gPassowordInvalid); + SafeFreePool (gConfirmError); + SafeFreePool (gPressEnter); + SafeFreePool (gEmptyString); + SafeFreePool (gAreYouSure); + SafeFreePool (gYesResponse); + SafeFreePool (gNoResponse); + SafeFreePool (gMiniString); + SafeFreePool (gPlusString); + SafeFreePool (gMinusString); + SafeFreePool (gAdjustNumber); + return ; +} + + +/** + Update key's help imformation + + @param MenuOption The Menu option + @param Selected Whether or not a tag be selected + + @return None + +**/ +VOID +UpdateKeyHelp ( + IN UI_MENU_OPTION *MenuOption, + IN BOOLEAN Selected + ) +{ + UINTN SecCol; + UINTN ThdCol; + UINTN LeftColumnOfHelp; + UINTN RightColumnOfHelp; + UINTN TopRowOfHelp; + UINTN BottomRowOfHelp; + UINTN StartColumnOfHelp; + EFI_SCREEN_DESCRIPTOR LocalScreen; + FORM_BROWSER_STATEMENT *Statement; + + CopyMem (&LocalScreen, &gScreenDimensions, sizeof (EFI_SCREEN_DESCRIPTOR)); + + SecCol = LocalScreen.LeftColumn + (LocalScreen.RightColumn - LocalScreen.LeftColumn) / 3; + ThdCol = LocalScreen.LeftColumn + (LocalScreen.RightColumn - LocalScreen.LeftColumn) * 2 / 3; + + StartColumnOfHelp = LocalScreen.LeftColumn + 2; + LeftColumnOfHelp = LocalScreen.LeftColumn + 1; + RightColumnOfHelp = LocalScreen.RightColumn - 2; + TopRowOfHelp = LocalScreen.BottomRow - 4; + BottomRowOfHelp = LocalScreen.BottomRow - 3; + + if (gClassOfVfr == EFI_GENERAL_APPLICATION_SUBCLASS) { + return ; + } + + gST->ConOut->SetAttribute (gST->ConOut, KEYHELP_TEXT | KEYHELP_BACKGROUND); + + Statement = MenuOption->ThisTag; + switch (Statement->Operand) { + case EFI_IFR_ORDERED_LIST_OP: + case EFI_IFR_ONE_OF_OP: + case EFI_IFR_NUMERIC_OP: + case EFI_IFR_TIME_OP: + case EFI_IFR_DATE_OP: + ClearLines (LeftColumnOfHelp, RightColumnOfHelp, TopRowOfHelp, BottomRowOfHelp, KEYHELP_TEXT | KEYHELP_BACKGROUND); + + if (!Selected) { + if (gClassOfVfr == EFI_SETUP_APPLICATION_SUBCLASS) { + PrintStringAt (StartColumnOfHelp, TopRowOfHelp, gFunctionOneString); + PrintStringAt (SecCol, TopRowOfHelp, gFunctionNineString); + PrintStringAt (ThdCol, TopRowOfHelp, gFunctionTenString); + PrintStringAt (ThdCol, BottomRowOfHelp, gEscapeString); + } + + if ((Statement->Operand == EFI_IFR_DATE_OP) || + (Statement->Operand == EFI_IFR_TIME_OP) || + (Statement->Operand == EFI_IFR_NUMERIC_OP && Statement->Step != 0)) { + PrintAt ( + StartColumnOfHelp, + BottomRowOfHelp, + L"%c%c%c%c%s", + ARROW_UP, + ARROW_DOWN, + ARROW_RIGHT, + ARROW_LEFT, + gMoveHighlight + ); + PrintStringAt (SecCol, BottomRowOfHelp, gAdjustNumber); + } else { + PrintAt (StartColumnOfHelp, BottomRowOfHelp, L"%c%c%s", ARROW_UP, ARROW_DOWN, gMoveHighlight); + PrintStringAt (SecCol, BottomRowOfHelp, gEnterString); + } + } else { + PrintStringAt (SecCol, BottomRowOfHelp, gEnterCommitString); + + // + // If it is a selected numeric with manual input, display different message + // + if ((Statement->Operand == EFI_IFR_NUMERIC_OP) && (Statement->Step == 0)) { + PrintStringAt ( + SecCol, + TopRowOfHelp, + (Statement->Flags & EFI_IFR_DISPLAY_UINT_HEX) ? gHexNumericInput : gDecNumericInput + ); + } else if (Statement->Operand != EFI_IFR_ORDERED_LIST_OP) { + PrintAt (StartColumnOfHelp, BottomRowOfHelp, L"%c%c%s", ARROW_UP, ARROW_DOWN, gMoveHighlight); + } + + if (Statement->Operand == EFI_IFR_ORDERED_LIST_OP) { + PrintStringAt (StartColumnOfHelp, TopRowOfHelp, gPlusString); + PrintStringAt (ThdCol, TopRowOfHelp, gMinusString); + } + + PrintStringAt (ThdCol, BottomRowOfHelp, gEscapeString); + } + break; + + case EFI_IFR_CHECKBOX_OP: + ClearLines (LeftColumnOfHelp, RightColumnOfHelp, TopRowOfHelp, BottomRowOfHelp, KEYHELP_TEXT | KEYHELP_BACKGROUND); + + if (gClassOfVfr == EFI_SETUP_APPLICATION_SUBCLASS) { + PrintStringAt (StartColumnOfHelp, TopRowOfHelp, gFunctionOneString); + PrintStringAt (SecCol, TopRowOfHelp, gFunctionNineString); + PrintStringAt (ThdCol, TopRowOfHelp, gFunctionTenString); + PrintStringAt (ThdCol, BottomRowOfHelp, gEscapeString); + } + + PrintAt (StartColumnOfHelp, BottomRowOfHelp, L"%c%c%s", ARROW_UP, ARROW_DOWN, gMoveHighlight); + PrintStringAt (SecCol, BottomRowOfHelp, gToggleCheckBox); + break; + + case EFI_IFR_REF_OP: + case EFI_IFR_PASSWORD_OP: + case EFI_IFR_STRING_OP: + case EFI_IFR_TEXT_OP: + case EFI_IFR_ACTION_OP: + case EFI_IFR_RESET_BUTTON_OP: + ClearLines (LeftColumnOfHelp, RightColumnOfHelp, TopRowOfHelp, BottomRowOfHelp, KEYHELP_TEXT | KEYHELP_BACKGROUND); + + if (!Selected) { + if (gClassOfVfr == EFI_SETUP_APPLICATION_SUBCLASS) { + PrintStringAt (StartColumnOfHelp, TopRowOfHelp, gFunctionOneString); + PrintStringAt (SecCol, TopRowOfHelp, gFunctionNineString); + PrintStringAt (ThdCol, TopRowOfHelp, gFunctionTenString); + PrintStringAt (ThdCol, BottomRowOfHelp, gEscapeString); + } + + PrintAt (StartColumnOfHelp, BottomRowOfHelp, L"%c%c%s", ARROW_UP, ARROW_DOWN, gMoveHighlight); + if (Statement->Operand != EFI_IFR_TEXT_OP) { + PrintStringAt (SecCol, BottomRowOfHelp, gEnterString); + } + } else { + if (Statement->Operand != EFI_IFR_REF_OP) { + PrintStringAt ( + (LocalScreen.RightColumn - GetStringWidth (gEnterCommitString) / 2) / 2, + BottomRowOfHelp, + gEnterCommitString + ); + PrintStringAt (ThdCol, BottomRowOfHelp, gEscapeString); + } + } + break; + + default: + break; + } +} + +EFI_STATUS +FormUpdateNotify ( + IN UINT8 PackageType, + IN CONST EFI_GUID *PackageGuid, + IN CONST EFI_HII_PACKAGE_HEADER *Package, + IN EFI_HII_HANDLE Handle, + IN EFI_HII_DATABASE_NOTIFY_TYPE NotifyType + ) +{ + mHiiPackageListUpdated = TRUE; + + return EFI_SUCCESS; +} + +EFI_STATUS +SetupBrowser ( + IN OUT UI_MENU_SELECTION *Selection + ) +{ + EFI_STATUS Status; + LIST_ENTRY *Link; + EFI_BROWSER_ACTION_REQUEST ActionRequest; + EFI_HANDLE NotifyHandle; + EFI_HII_VALUE *HiiValue; + FORM_BROWSER_STATEMENT *Statement; + EFI_HII_CONFIG_ACCESS_PROTOCOL *ConfigAccess; + + gMenuRefreshHead = NULL; + gResetRequired = FALSE; + gNvUpdateRequired = FALSE; + + UiInitMenuList (); + + // + // Register notify for Form package update + // + Status = mHiiDatabase->RegisterPackageNotify ( + mHiiDatabase, + EFI_HII_PACKAGE_FORM, + NULL, + FormUpdateNotify, + EFI_HII_DATABASE_NOTIFY_REMOVE_PACK, + &NotifyHandle + ); + if (EFI_ERROR (Status)) { + return Status; + } + + do { + // + // Displays the Header and Footer borders + // + DisplayPageFrame (); + + // + // Initialize Selection->Form + // + if (Selection->FormId == 0) { + // + // Zero FormId indicates display the first Form in a FormSet + // + Link = GetFirstNode (&Selection->FormSet->FormListHead); + + Selection->Form = FORM_BROWSER_FORM_FROM_LINK (Link); + Selection->FormId = Selection->Form->FormId; + } else { + Selection->Form = IdToForm (Selection->FormSet, Selection->FormId); + } + + // + // Load Questions' Value for display + // + Status = LoadFormConfig (Selection->FormSet, Selection->Form); + if (EFI_ERROR (Status)) { + return Status; + } + + // + // Display form + // + Status = DisplayForm (Selection); + if (EFI_ERROR (Status)) { + return Status; + } + + // + // Check Selected Statement (if press ESC, Selection->Statement will be NULL) + // + Statement = Selection->Statement; + if (Statement != NULL) { + if (Statement->QuestionFlags & EFI_IFR_FLAG_RESET_REQUIRED) { + gResetRequired = TRUE; + } + + // + // Reset FormPackage update flag + // + mHiiPackageListUpdated = FALSE; + + if (Statement->QuestionFlags & EFI_IFR_FLAG_CALLBACK && Statement->Operand != EFI_IFR_PASSWORD_OP) { + ActionRequest = EFI_BROWSER_ACTION_REQUEST_NONE; + + HiiValue = &Statement->HiiValue; + if (HiiValue->Type == EFI_IFR_TYPE_STRING) { + // + // Create String in HII database for Configuration Driver to retrieve + // + HiiValue->Value.string = NewString ((CHAR16 *) Statement->BufferValue, Selection->FormSet->HiiHandle); + } + + ConfigAccess = Selection->FormSet->ConfigAccess; + if (ConfigAccess == NULL) { + return EFI_UNSUPPORTED; + } + Status = ConfigAccess->Callback ( + ConfigAccess, + EFI_BROWSER_ACTION_CHANGING, + Statement->QuestionId, + HiiValue->Type, + &HiiValue->Value, + &ActionRequest + ); + + if (HiiValue->Type == EFI_IFR_TYPE_STRING) { + // + // Clean the String in HII Database + // + DeleteString (HiiValue->Value.string, Selection->FormSet->HiiHandle); + } + + if (!EFI_ERROR (Status)) { + switch (ActionRequest) { + case EFI_BROWSER_ACTION_REQUEST_RESET: + gResetRequired = TRUE; + break; + + case EFI_BROWSER_ACTION_REQUEST_SUBMIT: + SubmitForm (Selection->FormSet, Selection->Form); + break; + + case EFI_BROWSER_ACTION_REQUEST_EXIT: + Selection->Action = UI_ACTION_EXIT; + gNvUpdateRequired = FALSE; + break; + + default: + break; + } + } + } + + // + // Check whether Form Package has been updated during Callback + // + if (mHiiPackageListUpdated && (Selection->Action == UI_ACTION_REFRESH_FORM)) { + // + // Force to reparse IFR binary of target Formset + // + Selection->Action = UI_ACTION_REFRESH_FORMSET; + } + } + } while (Selection->Action == UI_ACTION_REFRESH_FORM); + + // + // Unregister notify for Form package update + // + Status = mHiiDatabase->UnregisterPackageNotify ( + mHiiDatabase, + NotifyHandle + ); + return Status; +} diff --git a/MdeModulePkg/Universal/SetupBrowserDxe/Print.c b/MdeModulePkg/Universal/SetupBrowserDxe/Print.c new file mode 100644 index 0000000000..6cc50c3ad5 --- /dev/null +++ b/MdeModulePkg/Universal/SetupBrowserDxe/Print.c @@ -0,0 +1,331 @@ +/** @file + +Copyright (c) 2004 - 2007, Intel Corporation +All rights reserved. This program and the accompanying materials +are licensed and made available under the terms and conditions of the BSD License +which accompanies this distribution. The full text of the license may be found at +http://opensource.org/licenses/bsd-license.php + +THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, +WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. + +Module Name: + + Print.c + +Abstract: + + Basic Ascii AvSPrintf() function named VSPrint(). VSPrint() enables very + simple implemenation of SPrint() and Print() to support debug. + + You can not Print more than EFI_DRIVER_LIB_MAX_PRINT_BUFFER characters at a + time. This makes the implementation very simple. + + VSPrint, Print, SPrint format specification has the follwoing form + + %type + + type: + 'S','s' - argument is an Unicode string + 'c' - argument is an ascii character + '%' - Print a % + + +**/ + +//@MT:#include "Tiano.h" +//@MT:#include "EfiDriverLib.h" +//@MT:#include "EfiPrintLib.h" +//@MT:#include "EfiStdArg.h" +//@MT:#include "TianoHii.h" +#include "Setup.h" + +UINTN +ValueToString ( + IN OUT CHAR16 *Buffer, + IN BOOLEAN Flags, + IN INT64 Value + ); + +UINTN +PrintInternal ( + IN UINTN Column, + IN UINTN Row, + IN EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL *Out, + IN CHAR16 *fmt, + IN VA_LIST args + ) +// +// Display string worker for: Print, PrintAt, IPrint, IPrintAt +// +{ + CHAR16 *Buffer; + CHAR16 *BackupBuffer; + UINTN Index; + UINTN PreviousIndex; + + // + // For now, allocate an arbitrarily long buffer + // + Buffer = AllocateZeroPool (0x10000); + BackupBuffer = AllocateZeroPool (0x10000); + ASSERT (Buffer); + ASSERT (BackupBuffer); + + if (Column != (UINTN) -1) { + Out->SetCursorPosition (Out, Column, Row); + } + + UnicodeVSPrint (Buffer, 0x10000, fmt, args); + + Out->Mode->Attribute = Out->Mode->Attribute & 0x7f; + + Out->SetAttribute (Out, Out->Mode->Attribute); + + Index = 0; + PreviousIndex = 0; + + do { + for (; (Buffer[Index] != NARROW_CHAR) && (Buffer[Index] != WIDE_CHAR) && (Buffer[Index] != 0); Index++) { + BackupBuffer[Index] = Buffer[Index]; + } + + if (Buffer[Index] == 0) { + break; + } + // + // Null-terminate the temporary string + // + BackupBuffer[Index] = 0; + + // + // Print this out, we are about to switch widths + // + Out->OutputString (Out, &BackupBuffer[PreviousIndex]); + + // + // Preserve the current index + 1, since this is where we will start printing from next + // + PreviousIndex = Index + 1; + + // + // We are at a narrow or wide character directive. Set attributes and strip it and print it + // + if (Buffer[Index] == NARROW_CHAR) { + // + // Preserve bits 0 - 6 and zero out the rest + // + Out->Mode->Attribute = Out->Mode->Attribute & 0x7f; + Out->SetAttribute (Out, Out->Mode->Attribute); + } else { + // + // Must be wide, set bit 7 ON + // + Out->Mode->Attribute = Out->Mode->Attribute | EFI_WIDE_ATTRIBUTE; + Out->SetAttribute (Out, Out->Mode->Attribute); + } + + Index++; + + } while (Buffer[Index] != 0); + + // + // We hit the end of the string - print it + // + Out->OutputString (Out, &BackupBuffer[PreviousIndex]); + + gBS->FreePool (Buffer); + gBS->FreePool (BackupBuffer); + return EFI_SUCCESS; +} + + +/** + Prints a formatted unicode string to the default console + + @param fmt Format string + + @return Length of string printed to the console + +**/ +UINTN +ConsolePrint ( + IN CHAR16 *fmt, + ... + ) +{ + VA_LIST args; + + VA_START (args, fmt); + return PrintInternal ((UINTN) -1, (UINTN) -1, gST->ConOut, fmt, args); +} + + +/** + Prints a unicode string to the default console, + using L"%s" format. + + @param String String pointer. + + @return Length of string printed to the console + +**/ +UINTN +PrintString ( + CHAR16 *String + ) +{ + return ConsolePrint (L"%s", String); +} + + +/** + Prints a chracter to the default console, + using L"%c" format. + + @param Character Character to print. + + @return Length of string printed to the console. + +**/ +UINTN +PrintChar ( + CHAR16 Character + ) +{ + return ConsolePrint (L"%c", Character); +} + + +/** + Prints a formatted unicode string to the default console, at + the supplied cursor position + + @param Row The cursor position to print the string at + @param fmt Format string + + @return Length of string printed to the console + +**/ +UINTN +PrintAt ( + IN UINTN Column, + IN UINTN Row, + IN CHAR16 *fmt, + ... + ) +{ + VA_LIST args; + + VA_START (args, fmt); + return PrintInternal (Column, Row, gST->ConOut, fmt, args); +} + + +/** + Prints a unicode string to the default console, at + the supplied cursor position, using L"%s" format. + + @param Row The cursor position to print the string at + @param String String pointer. + + @return Length of string printed to the console + +**/ +UINTN +PrintStringAt ( + IN UINTN Column, + IN UINTN Row, + CHAR16 *String + ) +{ + return PrintAt (Column, Row, L"%s", String); +} + + +/** + Prints a chracter to the default console, at + the supplied cursor position, using L"%c" format. + + @param Row The cursor position to print the string at + @param Character Character to print. + + @return Length of string printed to the console. + +**/ +UINTN +PrintCharAt ( + IN UINTN Column, + IN UINTN Row, + CHAR16 Character + ) +{ + return PrintAt (Column, Row, L"%c", Character); +} + + +/** + VSPrint worker function that prints a Value as a decimal number in Buffer + + @param Buffer Location to place ascii decimal number string of Value. + @param Value Decimal value to convert to a string in Buffer. + @param Flags Flags to use in printing decimal string, see file header for + details. + + @return Number of characters printed. + +**/ +UINTN +ValueToString ( + IN OUT CHAR16 *Buffer, + IN BOOLEAN Flags, + IN INT64 Value + ) +{ + CHAR16 TempBuffer[30]; + CHAR16 *TempStr; + CHAR16 *BufferPtr; + UINTN Count; + UINTN NumberCount; + UINT32 Remainder; + BOOLEAN Negative; + + Negative = FALSE; + TempStr = TempBuffer; + BufferPtr = Buffer; + Count = 0; + NumberCount = 0; + + if (Value < 0) { + Negative = TRUE; + Value = -Value; + } + + do { + Value = (INT64) DivU64x32Remainder ((UINT64) Value, 10, &Remainder); + *(TempStr++) = (CHAR16) (Remainder + '0'); + Count++; + NumberCount++; + if ((Flags & COMMA_TYPE) == COMMA_TYPE) { + if (NumberCount % 3 == 0 && Value != 0) { + *(TempStr++) = ','; + Count++; + } + } + } while (Value != 0); + + if (Negative) { + *(BufferPtr++) = '-'; + Count++; + } + + // + // Reverse temp string into Buffer. + // + while (TempStr != TempBuffer) { + *(BufferPtr++) = *(--TempStr); + } + + *BufferPtr = 0; + return Count; +} diff --git a/MdeModulePkg/Universal/SetupBrowserDxe/Print.h b/MdeModulePkg/Universal/SetupBrowserDxe/Print.h new file mode 100644 index 0000000000..c473a26cfa --- /dev/null +++ b/MdeModulePkg/Universal/SetupBrowserDxe/Print.h @@ -0,0 +1,38 @@ +/** @file + +Copyright (c) 2004, Intel Corporation +All rights reserved. This program and the accompanying materials +are licensed and made available under the terms and conditions of the BSD License +which accompanies this distribution. The full text of the license may be found at +http://opensource.org/licenses/bsd-license.php + +THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, +WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. + +Module Name: + + Print.h + +Abstract: + + Private data for Print.c + + +**/ + +#ifndef _PRINT_H_ +#define _PRINT_H_ + +#define LEFT_JUSTIFY 0x01 +#define PREFIX_SIGN 0x02 +#define PREFIX_BLANK 0x04 +#define COMMA_TYPE 0x08 +#define LONG_TYPE 0x10 +#define PREFIX_ZERO 0x20 + +// +// Largest number of characters that can be printed out. +// +#define EFI_DRIVER_LIB_MAX_PRINT_BUFFER (80 * 4) + +#endif diff --git a/MdeModulePkg/Universal/SetupBrowserDxe/ProcessOptions.c b/MdeModulePkg/Universal/SetupBrowserDxe/ProcessOptions.c new file mode 100644 index 0000000000..ac9eeda777 --- /dev/null +++ b/MdeModulePkg/Universal/SetupBrowserDxe/ProcessOptions.c @@ -0,0 +1,986 @@ +/** @file + +Copyright (c) 2004 - 2007, Intel Corporation +All rights reserved. This program and the accompanying materials +are licensed and made available under the terms and conditions of the BSD License +which accompanies this distribution. The full text of the license may be found at +http://opensource.org/licenses/bsd-license.php + +THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, +WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. + +Module Name: + + ProcessOptions.c + +Abstract: + + Implementation for handling the User Interface option processing. + +Revision History + + +**/ + +#include "Ui.h" +#include "Setup.h" + + +/** + Process Question Config. + + @param Selection The UI menu selection. + @param Question The Question to be peocessed. + + @retval EFI_SUCCESS Question Config process success. + @retval Other Question Config process fail. + +**/ +EFI_STATUS +ProcessQuestionConfig ( + IN UI_MENU_SELECTION *Selection, + IN FORM_BROWSER_STATEMENT *Question + ) +{ + EFI_STATUS Status; + CHAR16 *ConfigResp; + CHAR16 *Progress; + EFI_HII_CONFIG_ACCESS_PROTOCOL *ConfigAccess; + + if (Question->QuestionConfig == 0) { + return EFI_SUCCESS; + } + + // + // Get <ConfigResp> + // + ConfigResp = GetToken (Question->QuestionConfig, Selection->FormSet->HiiHandle); + if (ConfigResp == NULL) { + return EFI_NOT_FOUND; + } + + // + // Send config to Configuration Driver + // + ConfigAccess = Selection->FormSet->ConfigAccess; + if (ConfigAccess == NULL) { + return EFI_UNSUPPORTED; + } + Status = ConfigAccess->RouteConfig ( + ConfigAccess, + ConfigResp, + &Progress + ); + + return Status; +} + + +/** + Search an Option of a Question by its value. + + @param Question The Question + @param OptionValue Value for Option to be searched. + + @retval Pointer Pointer to the found Option. + @retval NULL Option not found. + +**/ +QUESTION_OPTION * +ValueToOption ( + IN FORM_BROWSER_STATEMENT *Question, + IN EFI_HII_VALUE *OptionValue + ) +{ + LIST_ENTRY *Link; + QUESTION_OPTION *Option; + + Link = GetFirstNode (&Question->OptionListHead); + while (!IsNull (&Question->OptionListHead, Link)) { + Option = QUESTION_OPTION_FROM_LINK (Link); + + if (CompareHiiValue (&Option->Value, OptionValue, NULL) == 0) { + return Option; + } + + Link = GetNextNode (&Question->OptionListHead, Link); + } + + return NULL; +} + + +/** + Print Question Value according to it's storage width and display attributes. + + @param Event The event to wait for + @param FormattedNumber Buffer for output string. + @param BufferSize The FormattedNumber buffer size in bytes. + + @retval EFI_SUCCESS Print success. + @retval EFI_BUFFER_TOO_SMALL Buffer size is not enough for formatted number. + +**/ +EFI_STATUS +PrintFormattedNumber ( + IN FORM_BROWSER_STATEMENT *Question, + IN OUT CHAR16 *FormattedNumber, + IN UINTN BufferSize + ) +{ + INT64 Value; + CHAR16 *Format; + EFI_HII_VALUE *QuestionValue; + + if (BufferSize < (21 * sizeof (CHAR16))) { + return EFI_BUFFER_TOO_SMALL; + } + + QuestionValue = &Question->HiiValue; + + Value = (INT64) QuestionValue->Value.u64; + switch (Question->Flags & EFI_IFR_DISPLAY) { + case EFI_IFR_DISPLAY_INT_DEC: + switch (QuestionValue->Type) { + case EFI_IFR_NUMERIC_SIZE_1: + Value = (INT64) ((INT8) QuestionValue->Value.u8); + break; + + case EFI_IFR_NUMERIC_SIZE_2: + Value = (INT64) ((INT16) QuestionValue->Value.u16); + break; + + case EFI_IFR_NUMERIC_SIZE_4: + Value = (INT64) ((INT32) QuestionValue->Value.u32); + break; + + case EFI_IFR_NUMERIC_SIZE_8: + default: + break; + } + + if (Value < 0) { + Value = -Value; + Format = L"-%ld"; + } else { + Format = L"%ld"; + } + break; + + case EFI_IFR_DISPLAY_UINT_DEC: + Format = L"%ld"; + break; + + case EFI_IFR_DISPLAY_UINT_HEX: + Format = L"%lx"; + break; + + default: + return EFI_UNSUPPORTED; + break; + } + + UnicodeSPrint (FormattedNumber, BufferSize, Format, Value); + + return EFI_SUCCESS; +} + + +/** + Password may be stored as encrypted by Configuration Driver. When change a + password, user will be challenged with old password. To validate user input old + password, we will send the clear text to Configuration Driver via Callback(). + Configuration driver is responsible to check the passed in password and return + the validation result. If validation pass, state machine in password Callback() + will transit from BROWSER_STATE_VALIDATE_PASSWORD to BROWSER_STATE_SET_PASSWORD. + After user type in new password twice, Callback() will be invoked to send the + new password to Configuration Driver. + + @param Selection Pointer to UI_MENU_SELECTION. + @param MenuOption The MenuOption for this password Question. + @param String The clear text of password. + + @retval EFI_NOT_AVAILABLE_YET Callback() request to terminate password input. + @return In state of BROWSER_STATE_VALIDATE_PASSWORD: + @retval EFI_SUCCESS Password correct, Browser will prompt for new + password. + @retval EFI_NOT_READY Password incorrect, Browser will show error + message. + @retval Other Browser will do nothing. + @return In state of BROWSER_STATE_SET_PASSWORD: + @retval EFI_SUCCESS Set password success. + @retval Other Set password failed. + +**/ +EFI_STATUS +PasswordCallback ( + IN UI_MENU_SELECTION *Selection, + IN UI_MENU_OPTION *MenuOption, + IN CHAR16 *String + ) +{ + EFI_STATUS Status; + EFI_HII_CONFIG_ACCESS_PROTOCOL *ConfigAccess; + EFI_BROWSER_ACTION_REQUEST ActionRequest; + EFI_HII_VALUE *QuestionValue; + + QuestionValue = &MenuOption->ThisTag->HiiValue; + ConfigAccess = Selection->FormSet->ConfigAccess; + if (ConfigAccess == NULL) { + return EFI_UNSUPPORTED; + } + + // + // Prepare password string in HII database + // + if (String != NULL) { + QuestionValue->Value.string = NewString (String, Selection->FormSet->HiiHandle); + } else { + QuestionValue->Value.string = 0; + } + + // + // Send password to Configuration Driver for validation + // + Status = ConfigAccess->Callback ( + ConfigAccess, + EFI_BROWSER_ACTION_CHANGING, + MenuOption->ThisTag->QuestionId, + QuestionValue->Type, + &QuestionValue->Value, + &ActionRequest + ); + + // + // Remove password string from HII database + // + if (String != NULL) { + DeleteString (QuestionValue->Value.string, Selection->FormSet->HiiHandle); + } + + return Status; +} + + +/** + Display error message for invalid password. + + None. + + @return None. + +**/ +VOID +PasswordInvalid ( + VOID + ) +{ + EFI_INPUT_KEY Key; + + // + // Invalid password, prompt error message + // + do { + CreateDialog (4, TRUE, 0, NULL, &Key, gEmptyString, gPassowordInvalid, gPressEnter, gEmptyString); + } while (Key.UnicodeChar != CHAR_CARRIAGE_RETURN); +} + + +/** + Process a Question's Option (whether selected or un-selected). + + @param Selection Pointer to UI_MENU_SELECTION. + @param MenuOption The MenuOption for this Question. + @param Selected TRUE: if Question is selected. + @param OptionString Pointer of the Option String to be displayed. + + @retval EFI_SUCCESS Question Option process success. + @retval Other Question Option process fail. + +**/ +EFI_STATUS +ProcessOptions ( + IN UI_MENU_SELECTION *Selection, + IN UI_MENU_OPTION *MenuOption, + IN BOOLEAN Selected, + OUT CHAR16 **OptionString + ) +{ + EFI_STATUS Status; + CHAR16 *StringPtr; + CHAR16 *TempString; + UINTN Index; + FORM_BROWSER_STATEMENT *Question; + CHAR16 FormattedNumber[21]; + UINT16 Number; + CHAR16 Character[2]; + EFI_INPUT_KEY Key; + UINTN BufferSize; + QUESTION_OPTION *OneOfOption; + LIST_ENTRY *Link; + EFI_HII_VALUE HiiValue; + EFI_HII_VALUE *QuestionValue; + BOOLEAN Suppress; + UINT16 Maximum; + + Status = EFI_SUCCESS; + + StringPtr = NULL; + Character[1] = L'\0'; + *OptionString = NULL; + + ZeroMem (FormattedNumber, 21 * sizeof (CHAR16)); + BufferSize = (gOptionBlockWidth + 1) * 2 * gScreenDimensions.BottomRow; + + Question = MenuOption->ThisTag; + QuestionValue = &Question->HiiValue; + Maximum = (UINT16) Question->Maximum; + + switch (Question->Operand) { + case EFI_IFR_ORDERED_LIST_OP: + // + // Initialize Option value array + // + if (Question->BufferValue[0] == 0) { + GetQuestionDefault (Selection->FormSet, Selection->Form, Question, 0); + } + + if (Selected) { + // + // Go ask for input + // + Status = GetSelectionInputPopUp (Selection, MenuOption); + } else { + // + // We now know how many strings we will have, so we can allocate the + // space required for the array or strings. + // + *OptionString = AllocateZeroPool (Question->MaxContainers * BufferSize); + ASSERT (*OptionString); + + HiiValue.Type = EFI_IFR_TYPE_NUM_SIZE_8; + HiiValue.Value.u64 = 0; + for (Index = 0; Index < Question->MaxContainers; Index++) { + HiiValue.Value.u8 = Question->BufferValue[Index]; + if (HiiValue.Value.u8 == 0) { + // + // Values for the options in ordered lists should never be a 0 + // + break; + } + + OneOfOption = ValueToOption (Question, &HiiValue); + if (OneOfOption == NULL) { + gBS->FreePool (*OptionString); + return EFI_NOT_FOUND; + } + + Suppress = FALSE; + if ((OneOfOption->SuppressExpression != NULL) && + (OneOfOption->SuppressExpression->Result.Value.b)) { + // + // This option is suppressed + // + Suppress = TRUE; + } + + if (!Suppress) { + Character[0] = LEFT_ONEOF_DELIMITER; + NewStrCat (OptionString[0], Character); + StringPtr = GetToken (OneOfOption->Text, Selection->Handle); + NewStrCat (OptionString[0], StringPtr); + Character[0] = RIGHT_ONEOF_DELIMITER; + NewStrCat (OptionString[0], Character); + Character[0] = CHAR_CARRIAGE_RETURN; + NewStrCat (OptionString[0], Character); + + gBS->FreePool (StringPtr); + } + } + } + break; + + case EFI_IFR_ONE_OF_OP: + if (Selected) { + // + // Go ask for input + // + Status = GetSelectionInputPopUp (Selection, MenuOption); + } else { + *OptionString = AllocateZeroPool (BufferSize); + ASSERT (*OptionString); + + OneOfOption = ValueToOption (Question, QuestionValue); + if (OneOfOption == NULL) { + gBS->FreePool (*OptionString); + return EFI_NOT_FOUND; + } + + if ((OneOfOption->SuppressExpression != NULL) && + (OneOfOption->SuppressExpression->Result.Value.b)) { + // + // This option is suppressed + // + Suppress = TRUE; + } else { + Suppress = FALSE; + } + + if (Suppress) { + // + // Current selected option happen to be suppressed, + // enforce to select on a non-suppressed option + // + Link = GetFirstNode (&Question->OptionListHead); + while (!IsNull (&Question->OptionListHead, Link)) { + OneOfOption = QUESTION_OPTION_FROM_LINK (Link); + + if ((OneOfOption->SuppressExpression == NULL) || + !OneOfOption->SuppressExpression->Result.Value.b) { + Suppress = FALSE; + CopyMem (QuestionValue, &OneOfOption->Value, sizeof (EFI_HII_VALUE)); + SetQuestionValue (Selection->FormSet, Selection->Form, Question, TRUE); + break; + } + + Link = GetNextNode (&Question->OptionListHead, Link); + } + } + + if (!Suppress) { + Character[0] = LEFT_ONEOF_DELIMITER; + NewStrCat (OptionString[0], Character); + StringPtr = GetToken (OneOfOption->Text, Selection->Handle); + NewStrCat (OptionString[0], StringPtr); + Character[0] = RIGHT_ONEOF_DELIMITER; + NewStrCat (OptionString[0], Character); + + gBS->FreePool (StringPtr); + } + } + break; + + case EFI_IFR_CHECKBOX_OP: + *OptionString = AllocateZeroPool (BufferSize); + ASSERT (*OptionString); + + *OptionString[0] = LEFT_CHECKBOX_DELIMITER; + + if (Selected) { + // + // Since this is a BOOLEAN operation, flip it upon selection + // + QuestionValue->Value.b = (BOOLEAN) (QuestionValue->Value.b ? FALSE : TRUE); + + // + // Perform inconsistent check + // + Status = ValidateQuestion (Selection->FormSet, Selection->Form, Question, EFI_HII_EXPRESSION_INCONSISTENT_IF); + if (EFI_ERROR (Status)) { + // + // Inconsistent check fail, restore Question Value + // + QuestionValue->Value.b = (BOOLEAN) (QuestionValue->Value.b ? FALSE : TRUE); + gBS->FreePool (*OptionString); + return Status; + } + + // + // Save Question value + // + Status = SetQuestionValue (Selection->FormSet, Selection->Form, Question, TRUE); + UpdateStatusBar (NV_UPDATE_REQUIRED, Question->QuestionFlags, TRUE); + } + + if (QuestionValue->Value.b) { + *(OptionString[0] + 1) = CHECK_ON; + } else { + *(OptionString[0] + 1) = CHECK_OFF; + } + *(OptionString[0] + 2) = RIGHT_CHECKBOX_DELIMITER; + break; + + case EFI_IFR_NUMERIC_OP: + if (Selected) { + // + // Go ask for input + // + Status = GetNumericInput (Selection, MenuOption); + } else { + *OptionString = AllocateZeroPool (BufferSize); + ASSERT (*OptionString); + + *OptionString[0] = LEFT_NUMERIC_DELIMITER; + + // + // Formatted print + // + PrintFormattedNumber (Question, FormattedNumber, 21 * sizeof (CHAR16)); + Number = (UINT16) GetStringWidth (FormattedNumber); + CopyMem (OptionString[0] + 1, FormattedNumber, Number); + + *(OptionString[0] + Number / 2) = RIGHT_NUMERIC_DELIMITER; + } + break; + + case EFI_IFR_DATE_OP: + if (Selected) { + // + // This is similar to numerics + // + Status = GetNumericInput (Selection, MenuOption); + } else { + *OptionString = AllocateZeroPool (BufferSize); + ASSERT (*OptionString); + + switch (MenuOption->Sequence) { + case 0: + *OptionString[0] = LEFT_NUMERIC_DELIMITER; + UnicodeSPrint (OptionString[0] + 1, 21 * sizeof (CHAR16), L"%02d", QuestionValue->Value.date.Month); + *(OptionString[0] + 3) = DATE_SEPARATOR; + break; + + case 1: + SetUnicodeMem (OptionString[0], 4, L' '); + UnicodeSPrint (OptionString[0] + 4, 21 * sizeof (CHAR16), L"%02d", QuestionValue->Value.date.Day); + *(OptionString[0] + 6) = DATE_SEPARATOR; + break; + + case 2: + SetUnicodeMem (OptionString[0], 7, L' '); + UnicodeSPrint (OptionString[0] + 7, 21 * sizeof (CHAR16), L"%4d", QuestionValue->Value.date.Year); + *(OptionString[0] + 11) = RIGHT_NUMERIC_DELIMITER; + break; + } + } + break; + + case EFI_IFR_TIME_OP: + if (Selected) { + // + // This is similar to numerics + // + Status = GetNumericInput (Selection, MenuOption); + } else { + *OptionString = AllocateZeroPool (BufferSize); + ASSERT (*OptionString); + + switch (MenuOption->Sequence) { + case 0: + *OptionString[0] = LEFT_NUMERIC_DELIMITER; + UnicodeSPrint (OptionString[0] + 1, 21 * sizeof (CHAR16), L"%02d", QuestionValue->Value.time.Hour); + *(OptionString[0] + 3) = TIME_SEPARATOR; + break; + + case 1: + SetUnicodeMem (OptionString[0], 4, L' '); + UnicodeSPrint (OptionString[0] + 4, 21 * sizeof (CHAR16), L"%02d", QuestionValue->Value.time.Minute); + *(OptionString[0] + 6) = TIME_SEPARATOR; + break; + + case 2: + SetUnicodeMem (OptionString[0], 7, L' '); + UnicodeSPrint (OptionString[0] + 7, 21 * sizeof (CHAR16), L"%02d", QuestionValue->Value.time.Second); + *(OptionString[0] + 9) = RIGHT_NUMERIC_DELIMITER; + break; + } + } + break; + + case EFI_IFR_STRING_OP: + if (Selected) { + StringPtr = AllocateZeroPool ((Maximum + 1) * sizeof (CHAR16)); + ASSERT (StringPtr); + + Status = ReadString (MenuOption, gPromptForData, StringPtr); + if (!EFI_ERROR (Status)) { + CopyMem (Question->BufferValue, StringPtr, Maximum * sizeof (CHAR16)); + SetQuestionValue (Selection->FormSet, Selection->Form, Question, TRUE); + + UpdateStatusBar (NV_UPDATE_REQUIRED, Question->QuestionFlags, TRUE); + } + + gBS->FreePool (StringPtr); + } else { + *OptionString = AllocateZeroPool (BufferSize); + ASSERT (*OptionString); + + if (((CHAR16 *) Question->BufferValue)[0] == 0x0000) { + *(OptionString[0]) = '_'; + } else { + if ((Maximum * sizeof (CHAR16)) < BufferSize) { + BufferSize = Maximum * sizeof (CHAR16); + } + CopyMem (OptionString[0], (CHAR16 *) Question->BufferValue, BufferSize); + } + } + break; + + case EFI_IFR_PASSWORD_OP: + if (Selected) { + StringPtr = AllocateZeroPool ((Maximum + 1) * sizeof (CHAR16)); + ASSERT (StringPtr); + + // + // For interactive passwords, old password is validated by callback + // + if (Question->QuestionFlags & EFI_IFR_FLAG_CALLBACK) { + // + // Use a NULL password to test whether old password is required + // + *StringPtr = 0; + Status = PasswordCallback (Selection, MenuOption, StringPtr); + if (Status == EFI_NOT_AVAILABLE_YET) { + // + // Callback request to terminate password input + // + gBS->FreePool (StringPtr); + return EFI_SUCCESS; + } + + if (EFI_ERROR (Status)) { + // + // Old password exist, ask user for the old password + // + Status = ReadString (MenuOption, gPromptForPassword, StringPtr); + if (EFI_ERROR (Status)) { + gBS->FreePool (StringPtr); + return Status; + } + + // + // Check user input old password + // + Status = PasswordCallback (Selection, MenuOption, StringPtr); + if (EFI_ERROR (Status)) { + if (Status == EFI_NOT_READY) { + // + // Typed in old password incorrect + // + PasswordInvalid (); + } else { + Status = EFI_SUCCESS; + } + + gBS->FreePool (StringPtr); + return Status; + } + } + } else { + // + // For non-interactive password, validate old password in local + // + if (*((CHAR16 *) Question->BufferValue) != 0) { + // + // There is something there! Prompt for password + // + Status = ReadString (MenuOption, gPromptForPassword, StringPtr); + if (EFI_ERROR (Status)) { + gBS->FreePool (StringPtr); + return Status; + } + + TempString = AllocateCopyPool ((Maximum + 1) * sizeof (CHAR16), Question->BufferValue); + TempString[Maximum] = L'\0'; + + if (StrCmp (StringPtr, TempString) != 0) { + // + // Typed in old password incorrect + // + PasswordInvalid (); + + gBS->FreePool (StringPtr); + gBS->FreePool (TempString); + return Status; + } + + gBS->FreePool (TempString); + } + } + + // + // Ask for new password + // + ZeroMem (StringPtr, (Maximum + 1) * sizeof (CHAR16)); + Status = ReadString (MenuOption, gPromptForNewPassword, StringPtr); + if (EFI_ERROR (Status)) { + // + // Reset state machine for interactive password + // + if (Question->QuestionFlags & EFI_IFR_FLAG_CALLBACK) { + PasswordCallback (Selection, MenuOption, NULL); + } + + gBS->FreePool (StringPtr); + return Status; + } + + // + // Confirm new password + // + TempString = AllocateZeroPool ((Maximum + 1) * sizeof (CHAR16)); + ASSERT (TempString); + Status = ReadString (MenuOption, gConfirmPassword, TempString); + if (EFI_ERROR (Status)) { + // + // Reset state machine for interactive password + // + if (Question->QuestionFlags & EFI_IFR_FLAG_CALLBACK) { + PasswordCallback (Selection, MenuOption, NULL); + } + + gBS->FreePool (StringPtr); + gBS->FreePool (TempString); + return Status; + } + + // + // Compare two typed-in new passwords + // + if (StrCmp (StringPtr, TempString) == 0) { + // + // Two password match, send it to Configuration Driver + // + if (Question->QuestionFlags & EFI_IFR_FLAG_CALLBACK) { + PasswordCallback (Selection, MenuOption, StringPtr); + } else { + CopyMem (Question->BufferValue, StringPtr, Maximum * sizeof (CHAR16)); + SetQuestionValue (Selection->FormSet, Selection->Form, Question, FALSE); + } + } else { + // + // Reset state machine for interactive password + // + if (Question->QuestionFlags & EFI_IFR_FLAG_CALLBACK) { + PasswordCallback (Selection, MenuOption, NULL); + } + + // + // Two password mismatch, prompt error message + // + do { + CreateDialog (4, TRUE, 0, NULL, &Key, gEmptyString, gConfirmError, gPressEnter, gEmptyString); + } while (Key.UnicodeChar != CHAR_CARRIAGE_RETURN); + } + + gBS->FreePool (TempString); + gBS->FreePool (StringPtr); + } + break; + + default: + break; + } + + return Status; +} + + +/** + Process the help string: Split StringPtr to several lines of strings stored in + FormattedString and the glyph width of each line cannot exceed gHelpBlockWidth. + + @param StringPtr The entire help string. + @param MenuOption The MenuOption for this Question. + @param RowCount TRUE: if Question is selected. + @param OptionString Pointer of the Option String to be displayed. + + @return None. + +**/ +VOID +ProcessHelpString ( + IN CHAR16 *StringPtr, + OUT CHAR16 **FormattedString, + IN UINTN RowCount + ) +{ + CONST UINTN BlockWidth = (UINTN) gHelpBlockWidth - 1; + UINTN AllocateSize; + // + // [PrevCurrIndex, CurrIndex) forms a range of a screen-line + // + UINTN CurrIndex; + UINTN PrevCurrIndex; + UINTN LineCount; + UINTN VirtualLineCount; + // + // GlyphOffset stores glyph width of current screen-line + // + UINTN GlyphOffset; + // + // GlyphWidth equals to 2 if we meet width directive + // + UINTN GlyphWidth; + // + // during scanning, we remember the position of last space character + // in case that if next word cannot put in current line, we could restore back to the position + // of last space character + // while we should also remmeber the glyph width of the last space character for restoring + // + UINTN LastSpaceIndex; + UINTN LastSpaceGlyphWidth; + // + // every time we begin to form a new screen-line, we should remember glyph width of single character + // of last line + // + UINTN LineStartGlyphWidth; + UINTN *IndexArray; + UINTN *OldIndexArray; + + // + // every three elements of IndexArray form a screen-line of string:[ IndexArray[i*3], IndexArray[i*3+1] ) + // IndexArray[i*3+2] stores the initial glyph width of single character. to save this is because we want + // to bring the width directive of the last line to current screen-line. + // e.g.: "\wideabcde ... fghi", if "fghi" also has width directive but is splitted to the next screen-line + // different from that of "\wideabcde", we should remember the width directive. + // + AllocateSize = 0x20; + IndexArray = AllocatePool (AllocateSize * sizeof (UINTN) * 3); + + if (*FormattedString != NULL) { + gBS->FreePool (*FormattedString); + *FormattedString = NULL; + } + + for (PrevCurrIndex = 0, CurrIndex = 0, LineCount = 0, LastSpaceIndex = 0, + IndexArray[0] = 0, GlyphWidth = 1, GlyphOffset = 0, LastSpaceGlyphWidth = 1, LineStartGlyphWidth = 1; + (StringPtr[CurrIndex] != CHAR_NULL); + CurrIndex ++) { + + if (LineCount == AllocateSize) { + AllocateSize += 0x10; + OldIndexArray = IndexArray; + IndexArray = AllocatePool (AllocateSize * sizeof (UINTN) * 3); + CopyMem (IndexArray, OldIndexArray, LineCount * sizeof (UINTN) * 3); + gBS->FreePool (OldIndexArray); + } + switch (StringPtr[CurrIndex]) { + + case NARROW_CHAR: + case WIDE_CHAR: + GlyphWidth = ((StringPtr[CurrIndex] == WIDE_CHAR) ? 2 : 1); + if (CurrIndex == 0) { + LineStartGlyphWidth = GlyphWidth; + } + break; + + // + // char is '\n' + // "\r\n" isn't handled here, handled by case CHAR_CARRIAGE_RETURN + // + case CHAR_LINEFEED: + // + // Store a range of string as a line + // + IndexArray[LineCount*3] = PrevCurrIndex; + IndexArray[LineCount*3+1] = CurrIndex; + IndexArray[LineCount*3+2] = LineStartGlyphWidth; + LineCount ++; + // + // Reset offset and save begin position of line + // + GlyphOffset = 0; + LineStartGlyphWidth = GlyphWidth; + PrevCurrIndex = CurrIndex + 1; + break; + + // + // char is '\r' + // "\r\n" and "\r" both are handled here + // + case CHAR_CARRIAGE_RETURN: + if (StringPtr[CurrIndex + 1] == CHAR_LINEFEED) { + // + // next char is '\n' + // + IndexArray[LineCount*3] = PrevCurrIndex; + IndexArray[LineCount*3+1] = CurrIndex; + IndexArray[LineCount*3+2] = LineStartGlyphWidth; + LineCount ++; + CurrIndex ++; + } + GlyphOffset = 0; + LineStartGlyphWidth = GlyphWidth; + PrevCurrIndex = CurrIndex + 1; + break; + + // + // char is space or other char + // + default: + GlyphOffset += GlyphWidth; + if (GlyphOffset >= BlockWidth) { + if (LastSpaceIndex > PrevCurrIndex) { + // + // LastSpaceIndex points to space inside current screen-line, + // restore to LastSpaceIndex + // (Otherwise the word is too long to fit one screen-line, just cut it) + // + CurrIndex = LastSpaceIndex; + GlyphWidth = LastSpaceGlyphWidth; + } else if (GlyphOffset > BlockWidth) { + // + // the word is too long to fit one screen-line and we don't get the chance + // of GlyphOffset == BlockWidth because GlyphWidth = 2 + // + CurrIndex --; + } + + IndexArray[LineCount*3] = PrevCurrIndex; + IndexArray[LineCount*3+1] = CurrIndex + 1; + IndexArray[LineCount*3+2] = LineStartGlyphWidth; + LineStartGlyphWidth = GlyphWidth; + LineCount ++; + // + // Reset offset and save begin position of line + // + GlyphOffset = 0; + PrevCurrIndex = CurrIndex + 1; + } + + // + // LastSpaceIndex: remember position of last space + // + if (StringPtr[CurrIndex] == CHAR_SPACE) { + LastSpaceIndex = CurrIndex; + LastSpaceGlyphWidth = GlyphWidth; + } + break; + } + } + + if (GlyphOffset > 0) { + IndexArray[LineCount*3] = PrevCurrIndex; + IndexArray[LineCount*3+1] = CurrIndex; + IndexArray[LineCount*3+2] = GlyphWidth; + LineCount ++; + } + + if (LineCount == 0) { + // + // in case we meet null string + // + IndexArray[0] = 0; + IndexArray[1] = 1; + // + // we assume null string's glyph width is 1 + // + IndexArray[1] = 1; + LineCount ++; + } + + VirtualLineCount = RowCount * (LineCount / RowCount + (LineCount % RowCount > 0)); + *FormattedString = AllocateZeroPool (VirtualLineCount * (BlockWidth + 1) * sizeof (CHAR16) * 2); + + for (CurrIndex = 0; CurrIndex < LineCount; CurrIndex ++) { + *(*FormattedString + CurrIndex * 2 * (BlockWidth + 1)) = (CHAR16) ((IndexArray[CurrIndex*3+2] == 2) ? WIDE_CHAR : NARROW_CHAR); + StrnCpy ( + *FormattedString + CurrIndex * 2 * (BlockWidth + 1) + 1, + StringPtr + IndexArray[CurrIndex*3], + IndexArray[CurrIndex*3+1]-IndexArray[CurrIndex*3] + ); + } + + gBS->FreePool (IndexArray); +} diff --git a/MdeModulePkg/Universal/SetupBrowserDxe/R8Lib.c b/MdeModulePkg/Universal/SetupBrowserDxe/R8Lib.c new file mode 100644 index 0000000000..1ffeb1bb9d --- /dev/null +++ b/MdeModulePkg/Universal/SetupBrowserDxe/R8Lib.c @@ -0,0 +1,243 @@ +/**@file + Copyright (c) 2007, Intel Corporation + + All rights reserved. This program and the accompanying materials + are licensed and made available under the terms and conditions of the BSD License + which accompanies this distribution. The full text of the license may be found at + http://opensource.org/licenses/bsd-license.php + + THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, + WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. + + +**/ + +#include "Setup.h" + +CHAR16 +NibbleToHexChar ( + IN UINT8 Nibble + ) +/*++ + + Routine Description: + Converts the low nibble of a byte to hex unicode character. + + Arguments: + Nibble - lower nibble of a byte. + + Returns: + Hex unicode character. + +--*/ +{ + Nibble &= 0x0F; + if (Nibble <= 0x9) { + return (CHAR16)(Nibble + L'0'); + } + + return (CHAR16)(Nibble - 0xA + L'A'); +} + + + +/** + Converts binary buffer to Unicode string. + At a minimum, any blob of data could be represented as a hex string. + + @param Str Pointer to the string. + @param HexStringBufferLength Length in bytes of buffer to hold the hex string. + Includes tailing '\0' character. If routine return + with EFI_SUCCESS, containing length of hex string + buffer. If routine return with + EFI_BUFFER_TOO_SMALL, containg length of hex + string buffer desired. + @param Buf Buffer to be converted from. + @param Len Length in bytes of the buffer to be converted. + + @retval EFI_SUCCESS Routine success. + @retval EFI_BUFFER_TOO_SMALL The hex string buffer is too small. + +**/ +EFI_STATUS +R8_BufToHexString ( + IN OUT CHAR16 *Str, + IN OUT UINTN *HexStringBufferLength, + IN UINT8 *Buf, + IN UINTN Len + ) +{ + // + // Porting Guide: + // This library interface is simply obsolete. + // Include the source code to user code. + // + UINTN Idx; + UINT8 Byte; + UINTN StrLen; + + // + // Make sure string is either passed or allocate enough. + // It takes 2 Unicode characters (4 bytes) to represent 1 byte of the binary buffer. + // Plus the Unicode termination character. + // + StrLen = Len * 2; + if (StrLen > ((*HexStringBufferLength) - 1)) { + *HexStringBufferLength = StrLen + 1; + return EFI_BUFFER_TOO_SMALL; + } + + *HexStringBufferLength = StrLen + 1; + // + // Ends the string. + // + Str[StrLen] = L'\0'; + + for (Idx = 0; Idx < Len; Idx++) { + + Byte = Buf[Idx]; + Str[StrLen - 1 - Idx * 2] = NibbleToHexChar (Byte); + Str[StrLen - 2 - Idx * 2] = NibbleToHexChar ((UINT8)(Byte >> 4)); + } + + return EFI_SUCCESS; +} + + + + +/** + Converts Unicode string to binary buffer. + The conversion may be partial. + The first character in the string that is not hex digit stops the conversion. + At a minimum, any blob of data could be represented as a hex string. + + @param Buf Pointer to buffer that receives the data. + @param Len Length in bytes of the buffer to hold converted + data. If routine return with EFI_SUCCESS, + containing length of converted data. If routine + return with EFI_BUFFER_TOO_SMALL, containg length + of buffer desired. + @param Str String to be converted from. + @param ConvertedStrLen Length of the Hex String consumed. + + @retval EFI_SUCCESS Routine Success. + @retval EFI_BUFFER_TOO_SMALL The buffer is too small to hold converted data. + +**/ +EFI_STATUS +R8_HexStringToBuf ( + IN OUT UINT8 *Buf, + IN OUT UINTN *Len, + IN CHAR16 *Str, + OUT UINTN *ConvertedStrLen OPTIONAL + ) +{ + // + // Porting Guide: + // This library interface is simply obsolete. + // Include the source code to user code. + // + + UINTN HexCnt; + UINTN Idx; + UINTN BufferLength; + UINT8 Digit; + UINT8 Byte; + + // + // Find out how many hex characters the string has. + // + for (Idx = 0, HexCnt = 0; R8_IsHexDigit (&Digit, Str[Idx]); Idx++, HexCnt++); + + if (HexCnt == 0) { + *Len = 0; + return EFI_SUCCESS; + } + // + // Two Unicode characters make up 1 buffer byte. Round up. + // + BufferLength = (HexCnt + 1) / 2; + + // + // Test if buffer is passed enough. + // + if (BufferLength > (*Len)) { + *Len = BufferLength; + return EFI_BUFFER_TOO_SMALL; + } + + *Len = BufferLength; + + for (Idx = 0; Idx < HexCnt; Idx++) { + + R8_IsHexDigit (&Digit, Str[HexCnt - 1 - Idx]); + + // + // For odd charaters, write the lower nibble for each buffer byte, + // and for even characters, the upper nibble. + // + if ((Idx & 1) == 0) { + Byte = Digit; + } else { + Byte = Buf[Idx / 2]; + Byte &= 0x0F; + Byte = (UINT8) (Byte | Digit << 4); + } + + Buf[Idx / 2] = Byte; + } + + if (ConvertedStrLen != NULL) { + *ConvertedStrLen = HexCnt; + } + + return EFI_SUCCESS; +} + + + + +/** + Determines if a Unicode character is a hexadecimal digit. + The test is case insensitive. + + @param Digit Pointer to byte that receives the value of the hex + character. + @param Char Unicode character to test. + + @retval TRUE If the character is a hexadecimal digit. + @retval FALSE Otherwise. + +**/ +BOOLEAN +R8_IsHexDigit ( + OUT UINT8 *Digit, + IN CHAR16 Char + ) +{ + // + // Porting Guide: + // This library interface is simply obsolete. + // Include the source code to user code. + // + + if ((Char >= L'0') && (Char <= L'9')) { + *Digit = (UINT8) (Char - L'0'); + return TRUE; + } + + if ((Char >= L'A') && (Char <= L'F')) { + *Digit = (UINT8) (Char - L'A' + 0x0A); + return TRUE; + } + + if ((Char >= L'a') && (Char <= L'f')) { + *Digit = (UINT8) (Char - L'a' + 0x0A); + return TRUE; + } + + return FALSE; +} + + diff --git a/MdeModulePkg/Universal/SetupBrowserDxe/R8Lib.h b/MdeModulePkg/Universal/SetupBrowserDxe/R8Lib.h new file mode 100644 index 0000000000..a0903196e6 --- /dev/null +++ b/MdeModulePkg/Universal/SetupBrowserDxe/R8Lib.h @@ -0,0 +1,97 @@ +/**@file + Copyright (c) 2007, Intel Corporation + + All rights reserved. This program and the accompanying materials + are licensed and made available under the terms and conditions of the BSD License + which accompanies this distribution. The full text of the license may be found at + http://opensource.org/licenses/bsd-license.php + + THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, + WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. + + +**/ + + + +/** + Converts binary buffer to Unicode string. + At a minimum, any blob of data could be represented as a hex string. + + @param Str Pointer to the string. + @param HexStringBufferLength Length in bytes of buffer to hold the hex string. + Includes tailing '\0' character. If routine return + with EFI_SUCCESS, containing length of hex string + buffer. If routine return with + EFI_BUFFER_TOO_SMALL, containg length of hex + string buffer desired. + @param Buf Buffer to be converted from. + @param Len Length in bytes of the buffer to be converted. + + @retval EFI_SUCCESS Routine success. + @retval EFI_BUFFER_TOO_SMALL The hex string buffer is too small. + +**/ +EFI_STATUS +R8_BufToHexString ( + IN OUT CHAR16 *Str, + IN OUT UINTN *HexStringBufferLength, + IN UINT8 *Buf, + IN UINTN Len + ) +; + + + + +/** + Converts Unicode string to binary buffer. + The conversion may be partial. + The first character in the string that is not hex digit stops the conversion. + At a minimum, any blob of data could be represented as a hex string. + + @param Buf Pointer to buffer that receives the data. + @param Len Length in bytes of the buffer to hold converted + data. If routine return with EFI_SUCCESS, + containing length of converted data. If routine + return with EFI_BUFFER_TOO_SMALL, containg length + of buffer desired. + @param Str String to be converted from. + @param ConvertedStrLen Length of the Hex String consumed. + + @retval EFI_SUCCESS Routine Success. + @retval EFI_BUFFER_TOO_SMALL The buffer is too small to hold converted data. + +**/ +EFI_STATUS +R8_HexStringToBuf ( + IN OUT UINT8 *Buf, + IN OUT UINTN *Len, + IN CHAR16 *Str, + OUT UINTN *ConvertedStrLen OPTIONAL + ) +; + + + + +/** + Determines if a Unicode character is a hexadecimal digit. + The test is case insensitive. + + @param Digit Pointer to byte that receives the value of the hex + character. + @param Char Unicode character to test. + + @retval TRUE If the character is a hexadecimal digit. + @retval FALSE Otherwise. + +**/ +BOOLEAN +R8_IsHexDigit ( + OUT UINT8 *Digit, + IN CHAR16 Char + ) +; + + diff --git a/MdeModulePkg/Universal/SetupBrowserDxe/Setup.c b/MdeModulePkg/Universal/SetupBrowserDxe/Setup.c new file mode 100644 index 0000000000..d14dac0373 --- /dev/null +++ b/MdeModulePkg/Universal/SetupBrowserDxe/Setup.c @@ -0,0 +1,2286 @@ +/** @file +Copyright (c) 2007, Intel Corporation +All rights reserved. This program and the accompanying materials +are licensed and made available under the terms and conditions of the BSD License +which accompanies this distribution. The full text of the license may be found at +http://opensource.org/licenses/bsd-license.php + +THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, +WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. + +Module Name: + + Setup.c + +Abstract: + + Entry and initialization module for the browser. + + +**/ + +#include "Setup.h" +#include "Ui.h" + + +SETUP_DRIVER_PRIVATE_DATA mPrivateData = { + SETUP_DRIVER_SIGNATURE, + NULL, + { + SendForm, + BrowserCallback + }, + { + UnicodeVSPrint + } +}; + +EFI_HII_DATABASE_PROTOCOL *mHiiDatabase; +EFI_HII_STRING_PROTOCOL *mHiiString; +EFI_HII_CONFIG_ROUTING_PROTOCOL *mHiiConfigRouting; + +BANNER_DATA *BannerData; +EFI_HII_HANDLE FrontPageHandle; +UINTN gClassOfVfr; +UINTN gFunctionKeySetting; +BOOLEAN gResetRequired; +BOOLEAN gNvUpdateRequired; +EFI_HII_HANDLE gHiiHandle; +BOOLEAN gFirstIn; +UINT16 gDirection; +EFI_SCREEN_DESCRIPTOR gScreenDimensions; +BOOLEAN gUpArrow; +BOOLEAN gDownArrow; + +// +// Browser Global Strings +// +CHAR16 *gFunctionOneString; +CHAR16 *gFunctionTwoString; +CHAR16 *gFunctionNineString; +CHAR16 *gFunctionTenString; +CHAR16 *gEnterString; +CHAR16 *gEnterCommitString; +CHAR16 *gEscapeString; +CHAR16 *gSaveFailed; +CHAR16 *gMoveHighlight; +CHAR16 *gMakeSelection; +CHAR16 *gDecNumericInput; +CHAR16 *gHexNumericInput; +CHAR16 *gToggleCheckBox; +CHAR16 *gPromptForData; +CHAR16 *gPromptForPassword; +CHAR16 *gPromptForNewPassword; +CHAR16 *gConfirmPassword; +CHAR16 *gConfirmError; +CHAR16 *gPassowordInvalid; +CHAR16 *gPressEnter; +CHAR16 *gEmptyString; +CHAR16 *gAreYouSure; +CHAR16 *gYesResponse; +CHAR16 *gNoResponse; +CHAR16 *gMiniString; +CHAR16 *gPlusString; +CHAR16 *gMinusString; +CHAR16 *gAdjustNumber; + +CHAR16 gPromptBlockWidth; +CHAR16 gOptionBlockWidth; +CHAR16 gHelpBlockWidth; + +EFI_GUID gZeroGuid = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}; +EFI_GUID gSetupBrowserGuid = { + 0xab368524, 0xb60c, 0x495b, 0xa0, 0x9, 0x12, 0xe8, 0x5b, 0x1a, 0xea, 0x32 +}; + +FUNCTIION_KEY_SETTING gFunctionKeySettingTable[] = { + // + // Boot Manager + // + { + { + 0x847bc3fe, + 0xb974, + 0x446d, + 0x94, + 0x49, + 0x5a, + 0xd5, + 0x41, + 0x2e, + 0x99, + 0x3b + }, + NONE_FUNCTION_KEY_SETTING + }, + // + // Device Manager + // + { + { + 0x3ebfa8e6, + 0x511d, + 0x4b5b, + 0xa9, + 0x5f, + 0xfb, + 0x38, + 0x26, + 0xf, + 0x1c, + 0x27 + }, + NONE_FUNCTION_KEY_SETTING + }, + // + // BMM FormSet. + // + { + { + 0x642237c7, + 0x35d4, + 0x472d, + 0x83, + 0x65, + 0x12, + 0xe0, + 0xcc, + 0xf2, + 0x7a, + 0x22 + }, + NONE_FUNCTION_KEY_SETTING + }, + // + // BMM File Explorer FormSet. + // + { + { + 0x1f2d63e1, + 0xfebd, + 0x4dc7, + 0x9c, + 0xc5, + 0xba, + 0x2b, + 0x1c, + 0xef, + 0x9c, + 0x5b + }, + NONE_FUNCTION_KEY_SETTING + }, +}; + +//@MT: EFI_DRIVER_ENTRY_POINT (InitializeSetup) + +EFI_STATUS +EFIAPI +SendForm ( + IN CONST EFI_FORM_BROWSER2_PROTOCOL *This, + IN EFI_HII_HANDLE *Handles, + IN UINTN HandleCount, + IN EFI_GUID *FormSetGuid, OPTIONAL + IN UINT16 FormId, OPTIONAL + IN CONST EFI_SCREEN_DESCRIPTOR *ScreenDimensions, OPTIONAL + OUT EFI_BROWSER_ACTION_REQUEST *ActionRequest OPTIONAL + ) +/*++ + +Routine Description: + This is the routine which an external caller uses to direct the browser + where to obtain it's information. + +Arguments: + This - The Form Browser protocol instanse. + Handles - A pointer to an array of Handles. If HandleCount > 1 we + display a list of the formsets for the handles specified. + HandleCount - The number of Handles specified in Handle. + FormSetGuid - This field points to the EFI_GUID which must match the Guid + field in the EFI_IFR_FORM_SET op-code for the specified + forms-based package. If FormSetGuid is NULL, then this + function will display the first found forms package. + FormId - This field specifies which EFI_IFR_FORM to render as the first + displayable page. If this field has a value of 0x0000, then + the forms browser will render the specified forms in their encoded order. + ScreenDimenions - This allows the browser to be called so that it occupies a + portion of the physical screen instead of dynamically determining the screen dimensions. + ActionRequest - Points to the action recommended by the form. + +Returns: + EFI_SUCCESS - The function completed successfully. + EFI_INVALID_PARAMETER - One of the parameters has an invalid value. + EFI_NOT_FOUND - No valid forms could be found to display. + +--*/ +{ + EFI_STATUS Status; + UI_MENU_SELECTION *Selection; + UINTN Index; + FORM_BROWSER_FORMSET *FormSet; + + Status = EFI_SUCCESS; + ZeroMem (&gScreenDimensions, sizeof (EFI_SCREEN_DESCRIPTOR)); + + // + // Seed the dimensions in the global + // + gST->ConOut->QueryMode ( + gST->ConOut, + gST->ConOut->Mode->Mode, + &gScreenDimensions.RightColumn, + &gScreenDimensions.BottomRow + ); + + if (ScreenDimensions != NULL) { + // + // Check local dimension vs. global dimension. + // + if ((gScreenDimensions.RightColumn < ScreenDimensions->RightColumn) || + (gScreenDimensions.BottomRow < ScreenDimensions->BottomRow) + ) { + return EFI_INVALID_PARAMETER; + } else { + // + // Local dimension validation. + // + if ((ScreenDimensions->RightColumn > ScreenDimensions->LeftColumn) && + (ScreenDimensions->BottomRow > ScreenDimensions->TopRow) && + ((ScreenDimensions->RightColumn - ScreenDimensions->LeftColumn) > 2) && + ( + (ScreenDimensions->BottomRow - ScreenDimensions->TopRow) > STATUS_BAR_HEIGHT + + SCROLL_ARROW_HEIGHT * + 2 + + FRONT_PAGE_HEADER_HEIGHT + + FOOTER_HEIGHT + + 1 + ) + ) { + CopyMem (&gScreenDimensions, (VOID *) ScreenDimensions, sizeof (EFI_SCREEN_DESCRIPTOR)); + } else { + return EFI_INVALID_PARAMETER; + } + } + } + + gOptionBlockWidth = (CHAR16) ((gScreenDimensions.RightColumn - gScreenDimensions.LeftColumn) / 3); + gHelpBlockWidth = gOptionBlockWidth; + gPromptBlockWidth = gOptionBlockWidth; + + // + // Initialize the strings for the browser, upon exit of the browser, the strings will be freed + // + InitializeBrowserStrings (); + + gFunctionKeySetting = DEFAULT_FUNCTION_KEY_SETTING; + gClassOfVfr = EFI_SETUP_APPLICATION_SUBCLASS; + + // + // Ensure we are in Text mode + // + if (gFirstIn) { + gFirstIn = FALSE; + gST->ConOut->SetAttribute (gST->ConOut, EFI_TEXT_ATTR (EFI_LIGHTGRAY, EFI_BLACK)); + DisableQuietBoot (); + } + + for (Index = 0; Index < HandleCount; Index++) { + Selection = AllocateZeroPool (sizeof (UI_MENU_SELECTION)); + ASSERT (Selection != NULL); + + Selection->Handle = Handles[Index]; + if (FormSetGuid != NULL) { + CopyMem (&Selection->FormSetGuid, FormSetGuid, sizeof (EFI_GUID)); + Selection->FormId = FormId; + } + + do { + FormSet = AllocateZeroPool (sizeof (FORM_BROWSER_FORMSET)); + ASSERT (FormSet != NULL); + + // + // Initialize internal data structures of FormSet + // + Status = InitializeFormSet (Selection->Handle, &Selection->FormSetGuid, FormSet); + if (EFI_ERROR (Status)) { + DestroyFormSet (FormSet); + break; + } + Selection->FormSet = FormSet; + + // + // Initialize current settings of Questions in this FormSet + // + Status = InitializeCurrentSetting (FormSet); + if (EFI_ERROR (Status)) { + DestroyFormSet (FormSet); + break; + } + + // + // Display this formset + // + gCurrentSelection = Selection; + + Status = SetupBrowser (Selection); + + gCurrentSelection = NULL; + DestroyFormSet (FormSet); + + if (EFI_ERROR (Status)) { + break; + } + + } while (Selection->Action == UI_ACTION_REFRESH_FORMSET); + + gBS->FreePool (Selection); + } + + if (ActionRequest != NULL) { + *ActionRequest = EFI_BROWSER_ACTION_REQUEST_NONE; + if (gResetRequired) { + *ActionRequest = EFI_BROWSER_ACTION_REQUEST_RESET; + } + } + + FreeBrowserStrings (); + + gST->ConOut->SetAttribute (gST->ConOut, EFI_TEXT_ATTR (EFI_LIGHTGRAY, EFI_BLACK)); + gST->ConOut->ClearScreen (gST->ConOut); + + return Status; +} + + +/** + This function is called by a callback handler to retrieve uncommitted state + data from the browser. + + @param This A pointer to the EFI_FORM_BROWSER2_PROTOCOL + instance. + @param ResultsDataSize A pointer to the size of the buffer associated + with ResultsData. + @param ResultsData A string returned from an IFR browser or + equivalent. The results string will have no + routing information in them. + @param RetrieveData A BOOLEAN field which allows an agent to retrieve + (if RetrieveData = TRUE) data from the uncommitted + browser state information or set (if RetrieveData + = FALSE) data in the uncommitted browser state + information. + @param VariableGuid An optional field to indicate the target variable + GUID name to use. + @param VariableName An optional field to indicate the target + human-readable variable name. + + @retval EFI_SUCCESS The results have been distributed or are awaiting + distribution. + @retval EFI_BUFFER_TOO_SMALL The ResultsDataSize specified was too small to + contain the results data. + +**/ +EFI_STATUS +EFIAPI +BrowserCallback ( + IN CONST EFI_FORM_BROWSER2_PROTOCOL *This, + IN OUT UINTN *ResultsDataSize, + IN OUT EFI_STRING ResultsData, + IN BOOLEAN RetrieveData, + IN CONST EFI_GUID *VariableGuid, OPTIONAL + IN CONST CHAR16 *VariableName OPTIONAL + ) +{ + EFI_STATUS Status; + LIST_ENTRY *Link; + FORMSET_STORAGE *Storage; + FORM_BROWSER_FORMSET *FormSet; + BOOLEAN Found; + CHAR16 *ConfigResp; + CHAR16 *StrPtr; + UINTN BufferSize; + UINTN TmpSize; + + if (ResultsDataSize == NULL || ResultsData == NULL) { + return EFI_INVALID_PARAMETER; + } + + if (gCurrentSelection == NULL) { + return EFI_NOT_READY; + } + + Storage = NULL; + ConfigResp = NULL; + FormSet = gCurrentSelection->FormSet; + + // + // Find target storage + // + Link = GetFirstNode (&FormSet->StorageListHead); + if (IsNull (&FormSet->StorageListHead, Link)) { + return EFI_UNSUPPORTED; + } + + if (VariableGuid != NULL) { + // + // Try to find target storage + // + Found = FALSE; + while (!IsNull (&FormSet->StorageListHead, Link)) { + Storage = FORMSET_STORAGE_FROM_LINK (Link); + Link = GetNextNode (&FormSet->StorageListHead, Link); + + if (CompareGuid (&Storage->Guid, (EFI_GUID *) VariableGuid)) { + if (Storage->Type == EFI_HII_VARSTORE_BUFFER) { + // + // Buffer storage require both GUID and Name + // + if (VariableName == NULL) { + return EFI_NOT_FOUND; + } + + if (StrCmp (Storage->Name, (CHAR16 *) VariableName) != 0) { + continue; + } + } + Found = TRUE; + break; + } + } + + if (!Found) { + return EFI_NOT_FOUND; + } + } else { + // + // GUID/Name is not specified, take the first storage in FormSet + // + Storage = FORMSET_STORAGE_FROM_LINK (Link); + } + + if (RetrieveData) { + // + // Skip if there is no RequestElement + // + if (Storage->ElementCount == 0) { + return EFI_SUCCESS; + } + + // + // Generate <ConfigResp> + // + Status = StorageToConfigResp (Storage, &ConfigResp); + if (EFI_ERROR (Status)) { + return Status; + } + + // + // Skip <ConfigHdr> and '&' to point to <ConfigBody> + // + StrPtr = ConfigResp + StrLen (Storage->ConfigHdr) + 1; + + BufferSize = StrSize (StrPtr); + if (*ResultsDataSize < BufferSize) { + *ResultsDataSize = BufferSize; + + gBS->FreePool (ConfigResp); + return EFI_BUFFER_TOO_SMALL; + } + + *ResultsDataSize = BufferSize; + CopyMem (ResultsData, StrPtr, BufferSize); + + gBS->FreePool (ConfigResp); + } else { + // + // Prepare <ConfigResp> + // + TmpSize = StrLen (ResultsData); + BufferSize = (TmpSize + StrLen (Storage->ConfigHdr) + 2) * sizeof (CHAR16); + ConfigResp = AllocateZeroPool (BufferSize); + ASSERT (ConfigResp != NULL); + + StrCpy (ConfigResp, Storage->ConfigHdr); + StrCat (ConfigResp, L"&"); + StrCat (ConfigResp, ResultsData); + + // + // Update Browser uncommited data + // + Status = ConfigRespToStorage (Storage, ConfigResp); + if (EFI_ERROR (Status)) { + return Status; + } + } + + return EFI_SUCCESS; +} + + +/** + Initialize Setup + + @param entry EFI_IMAGE_ENTRY_POINT) + + @retval EFI_SUCCESS Setup loaded. + @retval other Setup Error + +**/ +EFI_STATUS +EFIAPI +InitializeSetup ( + IN EFI_HANDLE ImageHandle, + IN EFI_SYSTEM_TABLE *SystemTable + ) +{ + EFI_STATUS Status; + EFI_HANDLE HiiDriverHandle; + EFI_HII_PACKAGE_LIST_HEADER *PackageList; + + //@MT: EfiInitializeDriverLib (ImageHandle, SystemTable); + + // + // Locate required Hii relative protocols + // + Status = gBS->LocateProtocol ( + &gEfiHiiDatabaseProtocolGuid, + NULL, + (VOID **) &mHiiDatabase + ); + ASSERT_EFI_ERROR (Status); + + Status = gBS->LocateProtocol ( + &gEfiHiiStringProtocolGuid, + NULL, + (VOID **) &mHiiString + ); + ASSERT_EFI_ERROR (Status); + + Status = gBS->LocateProtocol ( + &gEfiHiiConfigRoutingProtocolGuid, + NULL, + (VOID **) &mHiiConfigRouting + ); + ASSERT_EFI_ERROR (Status); + + // + // Publish our HII data + // + Status = HiiLibCreateHiiDriverHandle (&HiiDriverHandle); + ASSERT_EFI_ERROR (Status); + + PackageList = PreparePackageList (1, &gSetupBrowserGuid, SetupBrowserStrings); + ASSERT (PackageList != NULL); + Status = mHiiDatabase->NewPackageList ( + mHiiDatabase, + PackageList, + HiiDriverHandle, + &gHiiHandle + ); + ASSERT_EFI_ERROR (Status); + + // + // Initialize Driver private data + // + gFirstIn = TRUE; + BannerData = AllocateZeroPool (sizeof (BANNER_DATA)); + ASSERT (BannerData != NULL); + + // + // Install FormBrowser2 protocol + // + mPrivateData.Handle = NULL; + Status = gBS->InstallProtocolInterface ( + &mPrivateData.Handle, + &gEfiFormBrowser2ProtocolGuid, + EFI_NATIVE_INTERFACE, + &mPrivateData.FormBrowser2 + ); + ASSERT_EFI_ERROR (Status); + + // + // Install Print protocol + // + Status = gBS->InstallProtocolInterface ( + &mPrivateData.Handle, + &gEfiPrintProtocolGuid, + EFI_NATIVE_INTERFACE, + &mPrivateData.Print + ); + + return Status; +} + + +/** + Create a new string in HII Package List. + + @param String The String to be added + @param HiiHandle The package list in the HII database to insert the + specified string. + + @return The output string. + +**/ +EFI_STRING_ID +NewString ( + IN CHAR16 *String, + IN EFI_HII_HANDLE HiiHandle + ) +{ + EFI_STRING_ID StringId; + EFI_STATUS Status; + + StringId = 0; + Status = IfrLibNewString (HiiHandle, &StringId, String); + ASSERT_EFI_ERROR (Status); + + return StringId; +} + + +/** + Delete a string from HII Package List. + + @param StringId Id of the string in HII database. + @param HiiHandle The HII package list handle. + + @retval EFI_SUCCESS The string was deleted successfully. + +**/ +EFI_STATUS +DeleteString ( + IN EFI_STRING_ID StringId, + IN EFI_HII_HANDLE HiiHandle + ) +{ + CHAR16 NullChar; + + NullChar = CHAR_NULL; + return IfrLibSetString (HiiHandle, StringId, &NullChar); +} + + +/** + Get the string based on the StringId and HII Package List Handle. + + @param Token The String's ID. + @param HiiHandle The package list in the HII database to search for + the specified string. + + @return The output string. + +**/ +CHAR16 * +GetToken ( + IN EFI_STRING_ID Token, + IN EFI_HII_HANDLE HiiHandle + ) +{ + EFI_STATUS Status; + CHAR16 *String; + UINTN BufferLength; + + // + // Set default string size assumption at no more than 256 bytes + // + BufferLength = 0x100; + String = AllocateZeroPool (BufferLength); + ASSERT (String != NULL); + + Status = IfrLibGetString (HiiHandle, Token, String, &BufferLength); + + if (Status == EFI_BUFFER_TOO_SMALL) { + gBS->FreePool (String); + String = AllocateZeroPool (BufferLength); + ASSERT (String != NULL); + + Status = IfrLibGetString (HiiHandle, Token, String, &BufferLength); + } + ASSERT_EFI_ERROR (Status); + + return String; +} + + +/** + Allocate new memory and then copy the Unicode string Source to Destination. + + @param Dest Location to copy string + @param Src String to copy + + @return NONE + +**/ +VOID +NewStringCpy ( + IN OUT CHAR16 **Dest, + IN CHAR16 *Src + ) +{ + SafeFreePool (*Dest); + *Dest = AllocateCopyPool (StrSize (Src), Src); + ASSERT (*Dest != NULL); +} + + +/** + Allocate new memory and concatinate Source on the end of Destination. + + @param Dest String to added to the end of. + @param Src String to concatinate. + + @return NONE + +**/ +VOID +NewStringCat ( + IN OUT CHAR16 **Dest, + IN CHAR16 *Src + ) +{ + CHAR16 *NewString; + UINTN TmpSize; + + if (*Dest == NULL) { + NewStringCpy (Dest, Src); + return; + } + + TmpSize = StrSize (*Dest); + NewString = AllocateZeroPool (TmpSize + StrSize (Src) - 1); + ASSERT (NewString != NULL); + + StrCpy (NewString, *Dest); + StrCat (NewString, Src); + + gBS->FreePool (*Dest); + *Dest = NewString; +} + + +/** + Synchronize Storage's Edit copy to Shadow copy. + + @param Storage The Storage to be synchronized. + + @return NONE + +**/ +VOID +SynchronizeStorage ( + IN FORMSET_STORAGE *Storage + ) +{ + LIST_ENTRY *Link; + NAME_VALUE_NODE *Node; + + switch (Storage->Type) { + case EFI_HII_VARSTORE_BUFFER: + CopyMem (Storage->Buffer, Storage->EditBuffer, Storage->Size); + break; + + case EFI_HII_VARSTORE_NAME_VALUE: + Link = GetFirstNode (&Storage->NameValueListHead); + while (!IsNull (&Storage->NameValueListHead, Link)) { + Node = NAME_VALUE_NODE_FROM_LINK (Link); + + NewStringCpy (&Node->Value, Node->EditValue); + + Link = GetNextNode (&Storage->NameValueListHead, Link); + } + break; + + case EFI_HII_VARSTORE_EFI_VARIABLE: + default: + break; + } +} + + +/** + Get Value for given Name from a NameValue Storage. + + @param Storage The NameValue Storage. + @param Name The Name. + @param Value The retured Value. + + @retval EFI_SUCCESS Value found for given Name. + @retval EFI_NOT_FOUND No such Name found in NameValue storage. + +**/ +EFI_STATUS +GetValueByName ( + IN FORMSET_STORAGE *Storage, + IN CHAR16 *Name, + IN OUT CHAR16 **Value + ) +{ + LIST_ENTRY *Link; + NAME_VALUE_NODE *Node; + + *Value = NULL; + + Link = GetFirstNode (&Storage->NameValueListHead); + while (!IsNull (&Storage->NameValueListHead, Link)) { + Node = NAME_VALUE_NODE_FROM_LINK (Link); + + if (StrCmp (Name, Node->Name) == 0) { + NewStringCpy (Value, Node->EditValue); + return EFI_SUCCESS; + } + + Link = GetNextNode (&Storage->NameValueListHead, Link); + } + + return EFI_NOT_FOUND; +} + + +/** + Set Value of given Name in a NameValue Storage. + + @param Storage The NameValue Storage. + @param Name The Name. + @param Value The Value to set. + + @retval EFI_SUCCESS Value found for given Name. + @retval EFI_NOT_FOUND No such Name found in NameValue storage. + +**/ +EFI_STATUS +SetValueByName ( + IN FORMSET_STORAGE *Storage, + IN CHAR16 *Name, + IN CHAR16 *Value + ) +{ + LIST_ENTRY *Link; + NAME_VALUE_NODE *Node; + + Link = GetFirstNode (&Storage->NameValueListHead); + while (!IsNull (&Storage->NameValueListHead, Link)) { + Node = NAME_VALUE_NODE_FROM_LINK (Link); + + if (StrCmp (Name, Node->Name) == 0) { + SafeFreePool (Node->EditValue); + Node->EditValue = AllocateCopyPool (StrSize (Value), Value); + ASSERT (Node->EditValue != NULL); + return EFI_SUCCESS; + } + + Link = GetNextNode (&Storage->NameValueListHead, Link); + } + + return EFI_NOT_FOUND; +} + + +/** + Convert setting of Buffer Storage or NameValue Storage to <ConfigResp>. + + @param Storage The Storage to be conveted. + @param ConfigResp The returned <ConfigResp>. + + @retval EFI_SUCCESS Convert success. + @retval EFI_INVALID_PARAMETER Incorrect storage type. + +**/ +EFI_STATUS +StorageToConfigResp ( + IN FORMSET_STORAGE *Storage, + IN CHAR16 **ConfigResp + ) +{ + EFI_STATUS Status; + EFI_STRING Progress; + LIST_ENTRY *Link; + NAME_VALUE_NODE *Node; + + Status = EFI_SUCCESS; + + switch (Storage->Type) { + case EFI_HII_VARSTORE_BUFFER: + Status = mHiiConfigRouting->BlockToConfig ( + mHiiConfigRouting, + Storage->ConfigRequest, + Storage->EditBuffer, + Storage->Size, + ConfigResp, + &Progress + ); + break; + + case EFI_HII_VARSTORE_NAME_VALUE: + *ConfigResp = NULL; + NewStringCat (ConfigResp, Storage->ConfigHdr); + + Link = GetFirstNode (&Storage->NameValueListHead); + while (!IsNull (&Storage->NameValueListHead, Link)) { + Node = NAME_VALUE_NODE_FROM_LINK (Link); + + NewStringCat (ConfigResp, L"&"); + NewStringCat (ConfigResp, Node->Name); + NewStringCat (ConfigResp, L"="); + NewStringCat (ConfigResp, Node->EditValue); + + Link = GetNextNode (&Storage->NameValueListHead, Link); + } + break; + + case EFI_HII_VARSTORE_EFI_VARIABLE: + default: + Status = EFI_INVALID_PARAMETER; + break; + } + + return Status; +} + + +/** + Convert <ConfigResp> to settings in Buffer Storage or NameValue Storage. + + @param Storage The Storage to receive the settings. + @param ConfigResp The <ConfigResp> to be converted. + + @retval EFI_SUCCESS Convert success. + @retval EFI_INVALID_PARAMETER Incorrect storage type. + +**/ +EFI_STATUS +ConfigRespToStorage ( + IN FORMSET_STORAGE *Storage, + IN CHAR16 *ConfigResp + ) +{ + EFI_STATUS Status; + EFI_STRING Progress; + UINTN BufferSize; + CHAR16 *StrPtr; + CHAR16 *Name; + CHAR16 *Value; + + Status = EFI_SUCCESS; + + switch (Storage->Type) { + case EFI_HII_VARSTORE_BUFFER: + BufferSize = Storage->Size; + Status = mHiiConfigRouting->ConfigToBlock ( + mHiiConfigRouting, + ConfigResp, + Storage->EditBuffer, + &BufferSize, + &Progress + ); + break; + + case EFI_HII_VARSTORE_NAME_VALUE: + StrPtr = StrStr (ConfigResp, L"&"); + while (StrPtr != NULL) { + // + // Skip '&' + // + StrPtr = StrPtr + 1; + Name = StrPtr; + StrPtr = StrStr (StrPtr, L"="); + if (StrPtr == NULL) { + break; + } + *StrPtr = 0; + + // + // Skip '=' + // + StrPtr = StrPtr + 1; + Value = StrPtr; + StrPtr = StrStr (StrPtr, L"&"); + if (StrPtr != NULL) { + *StrPtr = 0; + } + SetValueByName (Storage, Name, Value); + } + break; + + case EFI_HII_VARSTORE_EFI_VARIABLE: + default: + Status = EFI_INVALID_PARAMETER; + break; + } + + return Status; +} + + +/** + Get Question's current Value. + + @param FormSet FormSet data structure. + @param Form Form data structure. + @param Question Question to be initialized. + @param Cached TRUE: get from Edit copy FALSE: get from original + Storage + + @retval EFI_SUCCESS The function completed successfully. + +**/ +EFI_STATUS +GetQuestionValue ( + IN FORM_BROWSER_FORMSET *FormSet, + IN FORM_BROWSER_FORM *Form, + IN OUT FORM_BROWSER_STATEMENT *Question, + IN BOOLEAN Cached + ) +{ + EFI_STATUS Status; + BOOLEAN Enabled; + BOOLEAN Pending; + UINT8 *Dst; + UINTN StorageWidth; + EFI_TIME EfiTime; + FORMSET_STORAGE *Storage; + EFI_IFR_TYPE_VALUE *QuestionValue; + CHAR16 *ConfigRequest; + CHAR16 *Progress; + CHAR16 *Result; + CHAR16 *Value; + UINTN Length; + BOOLEAN IsBufferStorage; + BOOLEAN IsString; + + Status = EFI_SUCCESS; + + // + // Statement don't have storage, skip them + // + if (Question->QuestionId == 0) { + return Status; + } + + // + // Question value is provided by an Expression, evaluate it + // + if (Question->ValueExpression != NULL) { + Status = EvaluateExpression (FormSet, Form, Question->ValueExpression); + if (!EFI_ERROR (Status)) { + CopyMem (&Question->HiiValue, &Question->ValueExpression->Result, sizeof (EFI_HII_VALUE)); + } + return Status; + } + + // + // Question value is provided by RTC + // + Storage = Question->Storage; + QuestionValue = &Question->HiiValue.Value; + if (Storage == NULL) { + // + // It's a Question without storage, or RTC date/time + // + if (Question->Operand == EFI_IFR_DATE_OP || Question->Operand == EFI_IFR_TIME_OP) { + // + // Date and time define the same Flags bit + // + switch (Question->Flags & EFI_QF_DATE_STORAGE) { + case QF_DATE_STORAGE_TIME: + Status = gRT->GetTime (&EfiTime, NULL); + break; + + case QF_DATE_STORAGE_WAKEUP: + Status = gRT->GetWakeupTime (&Enabled, &Pending, &EfiTime); + break; + + case QF_DATE_STORAGE_NORMAL: + default: + // + // For date/time without storage + // + return EFI_SUCCESS; + } + + if (EFI_ERROR (Status)) { + return Status; + } + + if (Question->Operand == EFI_IFR_DATE_OP) { + QuestionValue->date.Year = EfiTime.Year; + QuestionValue->date.Month = EfiTime.Month; + QuestionValue->date.Day = EfiTime.Day; + } else { + QuestionValue->time.Hour = EfiTime.Hour; + QuestionValue->time.Minute = EfiTime.Minute; + QuestionValue->time.Second = EfiTime.Second; + } + } + + return EFI_SUCCESS; + } + + // + // Question value is provided by EFI variable + // + StorageWidth = Question->StorageWidth; + if (Storage->Type == EFI_HII_VARSTORE_EFI_VARIABLE) { + if (Question->BufferValue != NULL) { + Dst = Question->BufferValue; + } else { + Dst = (UINT8 *) QuestionValue; + } + + Status = gRT->GetVariable ( + Question->VariableName, + &Storage->Guid, + NULL, + &StorageWidth, + Dst + ); + // + // Always return success, even this EFI variable doesn't exist + // + return EFI_SUCCESS; + } + + // + // Question Value is provided by Buffer Storage or NameValue Storage + // + if (Question->BufferValue != NULL) { + // + // This Question is password or orderedlist + // + Dst = Question->BufferValue; + } else { + // + // Other type of Questions + // + Dst = (UINT8 *) &Question->HiiValue.Value; + } + + IsBufferStorage = (BOOLEAN) ((Storage->Type == EFI_HII_VARSTORE_BUFFER) ? TRUE : FALSE); + IsString = (BOOLEAN) ((Question->HiiValue.Type == EFI_IFR_TYPE_STRING) ? TRUE : FALSE); + if (Cached) { + if (IsBufferStorage) { + // + // Copy from storage Edit buffer + // + CopyMem (Dst, Storage->EditBuffer + Question->VarStoreInfo.VarOffset, StorageWidth); + } else { + Status = GetValueByName (Storage, Question->VariableName, &Value); + if (EFI_ERROR (Status)) { + return Status; + } + + if (IsString) { + StrCpy ((CHAR16 *) Dst, Value); + } else { + Status = R8_HexStringToBuf (Dst, &StorageWidth, Value, NULL); + } + + gBS->FreePool (Value); + } + } else { + // + // Request current settings from Configuration Driver + // + if (FormSet->ConfigAccess == NULL) { + return EFI_NOT_FOUND; + } + + // + // <ConfigRequest> ::= <ConfigHdr> + <BlockName> || + // <ConfigHdr> + "&" + <VariableName> + // + if (IsBufferStorage) { + Length = StrLen (Storage->ConfigHdr); + Length += StrLen (Question->BlockName); + } else { + Length = StrLen (Storage->ConfigHdr); + Length += StrLen (Question->VariableName) + 1; + } + ConfigRequest = AllocateZeroPool ((Length + 1) * sizeof (CHAR16)); + ASSERT (ConfigRequest != NULL); + + StrCpy (ConfigRequest, Storage->ConfigHdr); + if (IsBufferStorage) { + StrCat (ConfigRequest, Question->BlockName); + } else { + StrCat (ConfigRequest, L"&"); + StrCat (ConfigRequest, Question->VariableName); + } + + Status = FormSet->ConfigAccess->ExtractConfig ( + FormSet->ConfigAccess, + ConfigRequest, + &Progress, + &Result + ); + if (EFI_ERROR (Status)) { + return Status; + } + + // + // Skip <ConfigRequest> + // + Value = Result + Length; + if (IsBufferStorage) { + // + // Skip "&VALUE" + // + Value = Value + 6; + } + if (*Value != '=') { + gBS->FreePool (Result); + return EFI_NOT_FOUND; + } + // + // Skip '=', point to value + // + Value = Value + 1; + if (!IsBufferStorage && IsString) { + StrCpy ((CHAR16 *) Dst, Value); + } else { + Status = R8_HexStringToBuf (Dst, &StorageWidth, Value, NULL); + if (EFI_ERROR (Status)) { + gBS->FreePool (Result); + return Status; + } + } + + // + // Synchronize Edit Buffer + // + if (IsBufferStorage) { + CopyMem (Storage->EditBuffer + Question->VarStoreInfo.VarOffset, Dst, StorageWidth); + } else { + SetValueByName (Storage, Question->VariableName, Value); + } + gBS->FreePool (Result); + } + + return Status; +} + + +/** + Save Question Value to edit copy(cached) or Storage(uncached). + + @param FormSet FormSet data structure. + @param Form Form data structure. + @param Question Pointer to the Question. + @param Cached TRUE: set to Edit copy FALSE: set to original + Storage + + @retval EFI_SUCCESS The function completed successfully. + +**/ +EFI_STATUS +SetQuestionValue ( + IN FORM_BROWSER_FORMSET *FormSet, + IN FORM_BROWSER_FORM *Form, + IN OUT FORM_BROWSER_STATEMENT *Question, + IN BOOLEAN Cached + ) +{ + EFI_STATUS Status; + BOOLEAN Enabled; + BOOLEAN Pending; + UINT8 *Src; + EFI_TIME EfiTime; + UINTN BufferLen; + UINTN StorageWidth; + FORMSET_STORAGE *Storage; + EFI_IFR_TYPE_VALUE *QuestionValue; + CHAR16 *ConfigResp; + CHAR16 *Progress; + CHAR16 *Value; + UINTN Length; + BOOLEAN IsBufferStorage; + BOOLEAN IsString; + + Status = EFI_SUCCESS; + + // + // Statement don't have storage, skip them + // + if (Question->QuestionId == 0) { + return Status; + } + + // + // If Question value is provided by an Expression, then it is read only + // + if (Question->ValueExpression != NULL) { + return Status; + } + + // + // Question value is provided by RTC + // + Storage = Question->Storage; + QuestionValue = &Question->HiiValue.Value; + if (Storage == NULL) { + // + // It's a Question without storage, or RTC date/time + // + if (Question->Operand == EFI_IFR_DATE_OP || Question->Operand == EFI_IFR_TIME_OP) { + // + // Date and time define the same Flags bit + // + switch (Question->Flags & EFI_QF_DATE_STORAGE) { + case QF_DATE_STORAGE_TIME: + Status = gRT->GetTime (&EfiTime, NULL); + break; + + case QF_DATE_STORAGE_WAKEUP: + Status = gRT->GetWakeupTime (&Enabled, &Pending, &EfiTime); + break; + + case QF_DATE_STORAGE_NORMAL: + default: + // + // For date/time without storage + // + return EFI_SUCCESS; + } + + if (EFI_ERROR (Status)) { + return Status; + } + + if (Question->Operand == EFI_IFR_DATE_OP) { + EfiTime.Year = QuestionValue->date.Year; + EfiTime.Month = QuestionValue->date.Month; + EfiTime.Day = QuestionValue->date.Day; + } else { + EfiTime.Hour = QuestionValue->time.Hour; + EfiTime.Minute = QuestionValue->time.Minute; + EfiTime.Second = QuestionValue->time.Second; + } + + if ((Question->Flags & EFI_QF_DATE_STORAGE) == QF_DATE_STORAGE_TIME) { + Status = gRT->SetTime (&EfiTime); + } else { + Status = gRT->SetWakeupTime (TRUE, &EfiTime); + } + } + + return Status; + } + + // + // Question value is provided by EFI variable + // + StorageWidth = Question->StorageWidth; + if (Storage->Type == EFI_HII_VARSTORE_EFI_VARIABLE) { + if (Question->BufferValue != NULL) { + Src = Question->BufferValue; + } else { + Src = (UINT8 *) QuestionValue; + } + + Status = gRT->SetVariable ( + Question->VariableName, + &Storage->Guid, + Storage->Attributes, + StorageWidth, + Src + ); + return Status; + } + + // + // Question Value is provided by Buffer Storage or NameValue Storage + // + if (Question->BufferValue != NULL) { + Src = Question->BufferValue; + } else { + Src = (UINT8 *) &Question->HiiValue.Value; + } + + IsBufferStorage = (BOOLEAN) ((Storage->Type == EFI_HII_VARSTORE_BUFFER) ? TRUE : FALSE); + IsString = (BOOLEAN) ((Question->HiiValue.Type == EFI_IFR_TYPE_STRING) ? TRUE : FALSE); + if (IsBufferStorage) { + // + // Copy to storage edit buffer + // + CopyMem (Storage->EditBuffer + Question->VarStoreInfo.VarOffset, Src, StorageWidth); + } else { + if (IsString) { + Value = NULL; + NewStringCpy (&Value, (CHAR16 *) Src); + } else { + BufferLen = (StorageWidth * 2 + 1) * sizeof (CHAR16); + Value = AllocateZeroPool (BufferLen); + ASSERT (Value != NULL); + R8_BufToHexString (Value, &BufferLen, Src, StorageWidth); + } + + Status = SetValueByName (Storage, Question->VariableName, Value); + gBS->FreePool (Value); + } + + if (!Cached) { + // + // <ConfigResp> ::= <ConfigHdr> + <BlockName> + "&VALUE=" + "<HexCh>StorageWidth * 2" || + // <ConfigHdr> + "&" + <VariableName> + "=" + "<HexCh>StorageWidth * 2" + // + if (IsBufferStorage) { + Length = StrLen (Question->BlockName) + 7; + } else { + Length = StrLen (Question->VariableName) + 2; + } + if (!IsBufferStorage && IsString) { + Length += StrLen ((CHAR16 *) Src); + } else { + Length += (StorageWidth * 2); + } + ConfigResp = AllocateZeroPool ((StrLen (Storage->ConfigHdr) + Length + 1) * sizeof (CHAR16)); + ASSERT (ConfigResp != NULL); + + StrCpy (ConfigResp, Storage->ConfigHdr); + if (IsBufferStorage) { + StrCat (ConfigResp, Question->BlockName); + StrCat (ConfigResp, L"&VALUE="); + } else { + StrCat (ConfigResp, L"&"); + StrCat (ConfigResp, Question->VariableName); + StrCat (ConfigResp, L"="); + } + + Value = ConfigResp + StrLen (ConfigResp); + if (!IsBufferStorage && IsString) { + StrCpy (Value, (CHAR16 *) Src); + } else { + BufferLen = (StorageWidth * 2 + 1) * sizeof (CHAR16); + R8_BufToHexString (Value, &BufferLen, Src, StorageWidth); + } + + // + // Submit Question Value to Configuration Driver + // + if (FormSet->ConfigAccess != NULL) { + Status = FormSet->ConfigAccess->RouteConfig ( + FormSet->ConfigAccess, + ConfigResp, + &Progress + ); + if (EFI_ERROR (Status)) { + gBS->FreePool (ConfigResp); + return Status; + } + } + gBS->FreePool (ConfigResp); + + // + // Synchronize shadow Buffer + // + SynchronizeStorage (Storage); + } + + return Status; +} + + +/** + Perform inconsistent check for a Form. + + @param FormSet FormSet data structure. + @param Form Form data structure. + @param Question The Question to be validated. + @param Type Validation type: InConsistent or NoSubmit + + @retval EFI_SUCCESS Form validation pass. + @retval other Form validation failed. + +**/ +EFI_STATUS +ValidateQuestion ( + IN FORM_BROWSER_FORMSET *FormSet, + IN FORM_BROWSER_FORM *Form, + IN FORM_BROWSER_STATEMENT *Question, + IN UINTN Type + ) +{ + EFI_STATUS Status; + LIST_ENTRY *Link; + LIST_ENTRY *ListHead; + EFI_STRING PopUp; + EFI_INPUT_KEY Key; + FORM_EXPRESSION *Expression; + + if (Type == EFI_HII_EXPRESSION_INCONSISTENT_IF) { + ListHead = &Question->InconsistentListHead; + } else if (Type == EFI_HII_EXPRESSION_NO_SUBMIT_IF) { + ListHead = &Question->NoSubmitListHead; + } else { + return EFI_UNSUPPORTED; + } + + Link = GetFirstNode (ListHead); + while (!IsNull (ListHead, Link)) { + Expression = FORM_EXPRESSION_FROM_LINK (Link); + + // + // Evaluate the expression + // + Status = EvaluateExpression (FormSet, Form, Expression); + if (EFI_ERROR (Status)) { + return Status; + } + + if (Expression->Result.Value.b) { + // + // Condition meet, show up error message + // + if (Expression->Error != 0) { + PopUp = GetToken (Expression->Error, FormSet->HiiHandle); + do { + CreateDialog (4, TRUE, 0, NULL, &Key, gEmptyString, PopUp, gPressEnter, gEmptyString); + } while (Key.UnicodeChar != CHAR_CARRIAGE_RETURN); + gBS->FreePool (PopUp); + } + + return EFI_NOT_READY; + } + + Link = GetNextNode (ListHead, Link); + } + + return EFI_SUCCESS; +} + + +/** + Perform NoSubmit check for a Form. + + @param FormSet FormSet data structure. + @param Form Form data structure. + + @retval EFI_SUCCESS Form validation pass. + @retval other Form validation failed. + +**/ +EFI_STATUS +NoSubmitCheck ( + IN FORM_BROWSER_FORMSET *FormSet, + IN FORM_BROWSER_FORM *Form + ) +{ + EFI_STATUS Status; + LIST_ENTRY *Link; + FORM_BROWSER_STATEMENT *Question; + + Link = GetFirstNode (&Form->StatementListHead); + while (!IsNull (&Form->StatementListHead, Link)) { + Question = FORM_BROWSER_STATEMENT_FROM_LINK (Link); + + Status = ValidateQuestion (FormSet, Form, Question, EFI_HII_EXPRESSION_NO_SUBMIT_IF); + if (EFI_ERROR (Status)) { + return Status; + } + + Link = GetNextNode (&Form->StatementListHead, Link); + } + + return EFI_SUCCESS; +} + + +/** + Submit a Form. + + @param FormSet FormSet data structure. + @param Form Form data structure. + + @retval EFI_SUCCESS The function completed successfully. + +**/ +EFI_STATUS +SubmitForm ( + IN FORM_BROWSER_FORMSET *FormSet, + IN FORM_BROWSER_FORM *Form + ) +{ + EFI_STATUS Status; + LIST_ENTRY *Link; + EFI_STRING ConfigResp; + EFI_STRING Progress; + FORMSET_STORAGE *Storage; + + // + // Validate the Form by NoSubmit check + // + Status = NoSubmitCheck (FormSet, Form); + if (EFI_ERROR (Status)) { + return Status; + } + + // + // Submit Buffer storage or Name/Value storage + // + Link = GetFirstNode (&FormSet->StorageListHead); + while (!IsNull (&FormSet->StorageListHead, Link)) { + Storage = FORMSET_STORAGE_FROM_LINK (Link); + Link = GetNextNode (&FormSet->StorageListHead, Link); + + if (Storage->Type == EFI_HII_VARSTORE_EFI_VARIABLE) { + continue; + } + + // + // Skip if there is no RequestElement + // + if (Storage->ElementCount == 0) { + continue; + } + + // + // Prepare <ConfigResp> + // + Status = StorageToConfigResp (Storage, &ConfigResp); + if (EFI_ERROR (Status)) { + return Status; + } + + // + // Send <ConfigResp> to Configuration Driver + // + if (FormSet->ConfigAccess != NULL) { + Status = FormSet->ConfigAccess->RouteConfig ( + FormSet->ConfigAccess, + ConfigResp, + &Progress + ); + if (EFI_ERROR (Status)) { + gBS->FreePool (ConfigResp); + return Status; + } + } + gBS->FreePool (ConfigResp); + + // + // Config success, update storage shadow Buffer + // + SynchronizeStorage (Storage); + } + + gNvUpdateRequired = FALSE; + + return EFI_SUCCESS; +} + + +/** + Reset Question to its default value. + + @param FormSet FormSet data structure. + @param DefaultId The Class of the default. + + @retval EFI_SUCCESS Question is reset to default value. + +**/ +EFI_STATUS +GetQuestionDefault ( + IN FORM_BROWSER_FORMSET *FormSet, + IN FORM_BROWSER_FORM *Form, + IN FORM_BROWSER_STATEMENT *Question, + IN UINT16 DefaultId + ) +{ + EFI_STATUS Status; + LIST_ENTRY *Link; + QUESTION_DEFAULT *Default; + QUESTION_OPTION *Option; + EFI_HII_VALUE *HiiValue; + UINT8 Index; + + Status = EFI_SUCCESS; + + // + // Statement don't have storage, skip them + // + if (Question->QuestionId == 0) { + return Status; + } + + // + // There are three ways to specify default value for a Question: + // 1, use nested EFI_IFR_DEFAULT (highest priority) + // 2, set flags of EFI_ONE_OF_OPTION (provide Standard and Manufacturing default) + // 3, set flags of EFI_IFR_CHECKBOX (provide Standard and Manufacturing default) (lowest priority) + // + HiiValue = &Question->HiiValue; + + // + // EFI_IFR_DEFAULT has highest priority + // + if (!IsListEmpty (&Question->DefaultListHead)) { + Link = GetFirstNode (&Question->DefaultListHead); + while (!IsNull (&Question->DefaultListHead, Link)) { + Default = QUESTION_DEFAULT_FROM_LINK (Link); + + if (Default->DefaultId == DefaultId) { + if (Default->ValueExpression != NULL) { + // + // Default is provided by an Expression, evaluate it + // + Status = EvaluateExpression (FormSet, Form, Default->ValueExpression); + if (EFI_ERROR (Status)) { + return Status; + } + + CopyMem (HiiValue, &Default->ValueExpression->Result, sizeof (EFI_HII_VALUE)); + } else { + // + // Default value is embedded in EFI_IFR_DEFAULT + // + CopyMem (HiiValue, &Default->Value, sizeof (EFI_HII_VALUE)); + } + + return EFI_SUCCESS; + } + + Link = GetNextNode (&Question->DefaultListHead, Link); + } + } + + // + // EFI_ONE_OF_OPTION + // + if ((Question->Operand == EFI_IFR_ONE_OF_OP) && !IsListEmpty (&Question->OptionListHead)) { + if (DefaultId <= EFI_HII_DEFAULT_CLASS_MANUFACTURING) { + // + // OneOfOption could only provide Standard and Manufacturing default + // + Link = GetFirstNode (&Question->OptionListHead); + while (!IsNull (&Question->OptionListHead, Link)) { + Option = QUESTION_OPTION_FROM_LINK (Link); + + if (((DefaultId == EFI_HII_DEFAULT_CLASS_STANDARD) && (Option->Flags & EFI_IFR_OPTION_DEFAULT)) || + ((DefaultId == EFI_HII_DEFAULT_CLASS_MANUFACTURING) && (Option->Flags & EFI_IFR_OPTION_DEFAULT_MFG)) + ) { + CopyMem (HiiValue, &Option->Value, sizeof (EFI_HII_VALUE)); + + return EFI_SUCCESS; + } + + Link = GetNextNode (&Question->OptionListHead, Link); + } + } + } + + // + // EFI_IFR_CHECKBOX - lowest priority + // + if (Question->Operand == EFI_IFR_CHECKBOX_OP) { + if (DefaultId <= EFI_HII_DEFAULT_CLASS_MANUFACTURING) { + // + // Checkbox could only provide Standard and Manufacturing default + // + if (((DefaultId == EFI_HII_DEFAULT_CLASS_STANDARD) && (Question->Flags & EFI_IFR_CHECKBOX_DEFAULT)) || + ((DefaultId == EFI_HII_DEFAULT_CLASS_MANUFACTURING) && (Question->Flags & EFI_IFR_CHECKBOX_DEFAULT_MFG)) + ) { + HiiValue->Value.b = TRUE; + } else { + HiiValue->Value.b = FALSE; + } + + return EFI_SUCCESS; + } + } + + // + // For Questions without default + // + switch (Question->Operand) { + case EFI_IFR_NUMERIC_OP: + // + // Take minimal value as numeric's default value + // + HiiValue->Value.u64 = Question->Minimum; + break; + + case EFI_IFR_ONE_OF_OP: + // + // Take first oneof option as oneof's default value + // + Link = GetFirstNode (&Question->OptionListHead); + if (!IsNull (&Question->OptionListHead, Link)) { + Option = QUESTION_OPTION_FROM_LINK (Link); + CopyMem (HiiValue, &Option->Value, sizeof (EFI_HII_VALUE)); + } + break; + + case EFI_IFR_ORDERED_LIST_OP: + // + // Take option sequence in IFR as ordered list's default value + // + Index = 0; + Link = GetFirstNode (&Question->OptionListHead); + while (!IsNull (&Question->OptionListHead, Link)) { + Option = QUESTION_OPTION_FROM_LINK (Link); + + Question->BufferValue[Index] = Option->Value.Value.u8; + + Index++; + if (Index >= Question->MaxContainers) { + break; + } + + Link = GetNextNode (&Question->OptionListHead, Link); + } + break; + + default: + Status = EFI_NOT_FOUND; + break; + } + + return Status; +} + + +/** + Reset Questions in a Form to their default value. + + @param FormSet FormSet data structure. + @param Form The Form which to be reset. + @param DefaultId The Class of the default. + + @retval EFI_SUCCESS The function completed successfully. + +**/ +EFI_STATUS +ExtractFormDefault ( + IN FORM_BROWSER_FORMSET *FormSet, + IN FORM_BROWSER_FORM *Form, + IN UINT16 DefaultId + ) +{ + EFI_STATUS Status; + LIST_ENTRY *Link; + FORM_BROWSER_STATEMENT *Question; + + Link = GetFirstNode (&Form->StatementListHead); + while (!IsNull (&Form->StatementListHead, Link)) { + Question = FORM_BROWSER_STATEMENT_FROM_LINK (Link); + Link = GetNextNode (&Form->StatementListHead, Link); + + // + // Reset Question to its default value + // + Status = GetQuestionDefault (FormSet, Form, Question, DefaultId); + if (EFI_ERROR (Status)) { + continue; + } + + // + // Synchronize Buffer storage's Edit buffer + // + if ((Question->Storage != NULL) && + (Question->Storage->Type != EFI_HII_VARSTORE_EFI_VARIABLE)) { + SetQuestionValue (FormSet, Form, Question, TRUE); + } + } + + return EFI_SUCCESS; +} + + +/** + Initialize Question's Edit copy from Storage. + + @param FormSet FormSet data structure. + @param Form Form data structure. + + @retval EFI_SUCCESS The function completed successfully. + +**/ +EFI_STATUS +LoadFormConfig ( + IN FORM_BROWSER_FORMSET *FormSet, + IN FORM_BROWSER_FORM *Form + ) +{ + EFI_STATUS Status; + LIST_ENTRY *Link; + FORM_BROWSER_STATEMENT *Question; + + Link = GetFirstNode (&Form->StatementListHead); + while (!IsNull (&Form->StatementListHead, Link)) { + Question = FORM_BROWSER_STATEMENT_FROM_LINK (Link); + + // + // Initialize local copy of Value for each Question + // + Status = GetQuestionValue (FormSet, Form, Question, TRUE); + if (EFI_ERROR (Status)) { + return Status; + } + + Link = GetNextNode (&Form->StatementListHead, Link); + } + + return EFI_SUCCESS; +} + + +/** + Fill storage's edit copy with settings requested from Configuration Driver. + + @param FormSet FormSet data structure. + @param Storage Buffer Storage. + + @retval EFI_SUCCESS The function completed successfully. + +**/ +EFI_STATUS +LoadStorage ( + IN FORM_BROWSER_FORMSET *FormSet, + IN FORMSET_STORAGE *Storage + ) +{ + EFI_STATUS Status; + EFI_STRING Progress; + EFI_STRING Result; + CHAR16 *StrPtr; + + if (Storage->Type == EFI_HII_VARSTORE_EFI_VARIABLE) { + return EFI_SUCCESS; + } + + if (FormSet->ConfigAccess == NULL) { + return EFI_NOT_FOUND; + } + + if (Storage->ElementCount == 0) { + // + // Skip if there is no RequestElement + // + return EFI_SUCCESS; + } + + // + // Request current settings from Configuration Driver + // + Status = FormSet->ConfigAccess->ExtractConfig ( + FormSet->ConfigAccess, + Storage->ConfigRequest, + &Progress, + &Result + ); + if (EFI_ERROR (Status)) { + return Status; + } + + // + // Convert Result from <ConfigAltResp> to <ConfigResp> + // + StrPtr = StrStr (Result, L"ALTCFG"); + if (StrPtr != NULL) { + *StrPtr = L'\0'; + } + + Status = ConfigRespToStorage (Storage, Result); + gBS->FreePool (Result); + return Status; +} + + +/** + Get current setting of Questions. + + @param FormSet FormSet data structure. + + @retval EFI_SUCCESS The function completed successfully. + +**/ +EFI_STATUS +InitializeCurrentSetting ( + IN OUT FORM_BROWSER_FORMSET *FormSet + ) +{ + LIST_ENTRY *Link; + FORMSET_STORAGE *Storage; + FORM_BROWSER_FORM *Form; + EFI_STATUS Status; + + // + // Extract default from IFR binary + // + Link = GetFirstNode (&FormSet->FormListHead); + while (!IsNull (&FormSet->FormListHead, Link)) { + Form = FORM_BROWSER_FORM_FROM_LINK (Link); + + Status = ExtractFormDefault (FormSet, Form, EFI_HII_DEFAULT_CLASS_STANDARD); + + Link = GetNextNode (&FormSet->FormListHead, Link); + } + + // + // Request current settings from Configuration Driver + // + Link = GetFirstNode (&FormSet->StorageListHead); + while (!IsNull (&FormSet->StorageListHead, Link)) { + Storage = FORMSET_STORAGE_FROM_LINK (Link); + + Status = LoadStorage (FormSet, Storage); + + // + // Now Edit Buffer is filled with default values(lower priority) and current + // settings(higher priority), sychronize it to shadow Buffer + // + if (!EFI_ERROR (Status)) { + SynchronizeStorage (Storage); + } + + Link = GetNextNode (&FormSet->StorageListHead, Link); + } + + return EFI_SUCCESS; +} + + +/** + Fetch the Ifr binary data of a FormSet. + + @param Handle PackageList Handle + @param FormSetGuid GUID of a formset. If not specified (NULL or zero + GUID), take the first FormSet found in package + list. + @param BinaryLength The length of the FormSet IFR binary. + @param BinaryData The buffer designed to receive the FormSet. + + @retval EFI_SUCCESS Buffer filled with the requested FormSet. + BufferLength was updated. + @retval EFI_INVALID_PARAMETER The handle is unknown. + @retval EFI_NOT_FOUND A form or FormSet on the requested handle cannot + be found with the requested FormId. + +**/ +EFI_STATUS +GetIfrBinaryData ( + IN EFI_HII_HANDLE Handle, + IN OUT EFI_GUID *FormSetGuid, + OUT UINTN *BinaryLength, + OUT UINT8 **BinaryData + ) +{ + EFI_STATUS Status; + EFI_HII_PACKAGE_LIST_HEADER *HiiPackageList; + UINTN BufferSize; + UINT8 *Package; + UINT8 *OpCodeData; + UINT32 Offset; + UINT32 Offset2; + BOOLEAN ReturnDefault; + UINT32 PackageListLength; + EFI_HII_PACKAGE_HEADER PackageHeader; + + OpCodeData = NULL; + Package = NULL; + ZeroMem (&PackageHeader, sizeof (EFI_HII_PACKAGE_HEADER));; + + // + // if FormSetGuid is NULL or zero GUID, return first FormSet in the package list + // + if (FormSetGuid == NULL || CompareGuid (FormSetGuid, &gZeroGuid)) { + ReturnDefault = TRUE; + } else { + ReturnDefault = FALSE; + } + + // + // Get HII PackageList + // + BufferSize = 0; + HiiPackageList = NULL; + Status = mHiiDatabase->ExportPackageLists (mHiiDatabase, Handle, &BufferSize, HiiPackageList); + if (Status == EFI_BUFFER_TOO_SMALL) { + HiiPackageList = AllocatePool (BufferSize); + ASSERT (HiiPackageList != NULL); + + Status = mHiiDatabase->ExportPackageLists (mHiiDatabase, Handle, &BufferSize, HiiPackageList); + } + if (EFI_ERROR (Status)) { + return Status; + } + + // + // Get Form package from this HII package List + // + Offset = sizeof (EFI_HII_PACKAGE_LIST_HEADER); + Offset2 = 0; + CopyMem (&PackageListLength, &HiiPackageList->PackageLength, sizeof (UINT32)); + + while (Offset < PackageListLength) { + Package = ((UINT8 *) HiiPackageList) + Offset; + CopyMem (&PackageHeader, Package, sizeof (EFI_HII_PACKAGE_HEADER)); + + if (PackageHeader.Type == EFI_HII_PACKAGE_FORM) { + // + // Search FormSet in this Form Package + // + Offset2 = sizeof (EFI_HII_PACKAGE_HEADER); + while (Offset2 < PackageHeader.Length) { + OpCodeData = Package + Offset2; + + if (((EFI_IFR_OP_HEADER *) OpCodeData)->OpCode == EFI_IFR_FORM_SET_OP) { + // + // Check whether return default FormSet + // + if (ReturnDefault) { + break; + } + + // + // FormSet GUID is specified, check it + // + if (CompareGuid (FormSetGuid, (EFI_GUID *)(OpCodeData + sizeof (EFI_IFR_OP_HEADER)))) { + break; + } + } + + Offset2 += ((EFI_IFR_OP_HEADER *) OpCodeData)->Length; + } + + if (Offset2 < PackageHeader.Length) { + // + // Target formset found + // + break; + } + } + + Offset += PackageHeader.Length; + } + + if (Offset >= PackageListLength) { + // + // Form package not found in this Package List + // + gBS->FreePool (HiiPackageList); + return EFI_NOT_FOUND; + } + + if (ReturnDefault && FormSetGuid != NULL) { + // + // Return the default FormSet GUID + // + CopyMem (FormSetGuid, &((EFI_IFR_FORM_SET *) OpCodeData)->Guid, sizeof (EFI_GUID)); + } + + // + // To determine the length of a whole FormSet IFR binary, one have to parse all the Opcodes + // in this FormSet; So, here just simply copy the data from start of a FormSet to the end + // of the Form Package. + // + *BinaryLength = PackageHeader.Length - Offset2; + *BinaryData = AllocateCopyPool (*BinaryLength, OpCodeData); + + gBS->FreePool (HiiPackageList); + + if (*BinaryData == NULL) { + return EFI_OUT_OF_RESOURCES; + } + + return EFI_SUCCESS; +} + + +/** + Initialize the internal data structure of a FormSet. + + @param Handle PackageList Handle + @param FormSetGuid GUID of a formset. If not specified (NULL or zero + GUID), take the first FormSet found in package + list. + @param FormSet FormSet data structure. + + @retval EFI_SUCCESS The function completed successfully. + @retval EFI_NOT_FOUND The specified FormSet could not be found. + +**/ +EFI_STATUS +InitializeFormSet ( + IN EFI_HII_HANDLE Handle, + IN OUT EFI_GUID *FormSetGuid, + OUT FORM_BROWSER_FORMSET *FormSet + ) +{ + EFI_STATUS Status; + EFI_HANDLE DriverHandle; + UINT16 Index; + + Status = GetIfrBinaryData (Handle, FormSetGuid, &FormSet->IfrBinaryLength, &FormSet->IfrBinaryData); + if (EFI_ERROR (Status)) { + return Status; + } + + FormSet->HiiHandle = Handle; + CopyMem (&FormSet->Guid, FormSetGuid, sizeof (EFI_GUID)); + + // + // Retrieve ConfigAccess Protocol associated with this HiiPackageList + // + Status = mHiiDatabase->GetPackageListHandle (mHiiDatabase, Handle, &DriverHandle); + if (EFI_ERROR (Status)) { + return Status; + } + FormSet->DriverHandle = DriverHandle; + Status = gBS->HandleProtocol ( + DriverHandle, + &gEfiHiiConfigAccessProtocolGuid, + (VOID **) &FormSet->ConfigAccess + ); + if (EFI_ERROR (Status)) { + // + // Configuration Driver don't attach ConfigAccess protocol to its HII package + // list, then there will be no configuration action required + // + FormSet->ConfigAccess = NULL; + } + + // + // Parse the IFR binary OpCodes + // + Status = ParseOpCodes (FormSet); + if (EFI_ERROR (Status)) { + return Status; + } + + gClassOfVfr = FormSet->SubClass; + if (gClassOfVfr == EFI_FRONT_PAGE_SUBCLASS) { + FrontPageHandle = FormSet->HiiHandle; + } + + // + // Match GUID to find out the function key setting. If match fail, use the default setting. + // + for (Index = 0; Index < sizeof (gFunctionKeySettingTable) / sizeof (FUNCTIION_KEY_SETTING); Index++) { + if (CompareGuid (&FormSet->Guid, &(gFunctionKeySettingTable[Index].FormSetGuid))) { + // + // Update the function key setting. + // + gFunctionKeySetting = gFunctionKeySettingTable[Index].KeySetting; + // + // Function key prompt can not be displayed if the function key has been disabled. + // + if ((gFunctionKeySetting & FUNCTION_ONE) != FUNCTION_ONE) { + gFunctionOneString = GetToken (STRING_TOKEN (EMPTY_STRING), gHiiHandle); + } + + if ((gFunctionKeySetting & FUNCTION_TWO) != FUNCTION_TWO) { + gFunctionTwoString = GetToken (STRING_TOKEN (EMPTY_STRING), gHiiHandle); + } + + if ((gFunctionKeySetting & FUNCTION_NINE) != FUNCTION_NINE) { + gFunctionNineString = GetToken (STRING_TOKEN (EMPTY_STRING), gHiiHandle); + } + + if ((gFunctionKeySetting & FUNCTION_TEN) != FUNCTION_TEN) { + gFunctionTenString = GetToken (STRING_TOKEN (EMPTY_STRING), gHiiHandle); + } + } + } + + return Status; +} diff --git a/MdeModulePkg/Universal/SetupBrowserDxe/Setup.h b/MdeModulePkg/Universal/SetupBrowserDxe/Setup.h new file mode 100644 index 0000000000..3ade4dac57 --- /dev/null +++ b/MdeModulePkg/Universal/SetupBrowserDxe/Setup.h @@ -0,0 +1,760 @@ +/** @file + +Copyright (c) 2007, Intel Corporation +All rights reserved. This program and the accompanying materials +are licensed and made available under the terms and conditions of the BSD License +which accompanies this distribution. The full text of the license may be found at +http://opensource.org/licenses/bsd-license.php + +THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, +WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. + +Module Name: + + Setup.h + +Abstract: + + +Revision History + + +**/ + +#ifndef _SETUP_H +#define _SETUP_H + + +#include <PiDxe.h> + +#include <Protocol/Print.h> +#include <Protocol/SimpleTextOut.h> +#include <Protocol/SimpleTextIn.h> +#include <Protocol/FormBrowser2.h> +#include <Protocol/DevicePath.h> +#include <Protocol/UnicodeCollation.h> +#include <Protocol/HiiConfigAccess.h> +#include <Protocol/HiiConfigRouting.h> +#include <Protocol/HiiDatabase.h> +#include <Protocol/HiiString.h> + +#include <MdeModuleHii.h> + +#include <Library/GraphicsLib.h> +#include <Library/PrintLib.h> +#include <Library/DebugLib.h> +#include <Library/BaseMemoryLib.h> +#include <Library/UefiRuntimeServicesTableLib.h> +#include <Library/UefiDriverEntryPoint.h> +#include <Library/UefiBootServicesTableLib.h> +#include <Library/BaseLib.h> +#include <Library/MemoryAllocationLib.h> +#include <Library/IfrSupportLib.h> +#include <Library/HiiLib.h> + +#include "R8Lib.h" + +#include "Colors.h" + +//@MT:#include EFI_PROTOCOL_DEFINITION (HiiDatabase) +//@MT:#include EFI_PROTOCOL_DEFINITION (HiiString) +//@MT:#include EFI_PROTOCOL_DEFINITION (HiiConfigRouting) +//@MT:#include EFI_PROTOCOL_DEFINITION (HiiConfigAccess) +//@MT:#include EFI_PROTOCOL_DEFINITION (FormBrowser2) + +//@MT:#include EFI_GUID_DEFINITION (GlobalVariable) +//@MT:#include EFI_PROTOCOL_DEFINITION (DevicePath) +//@MT:#include EFI_PROTOCOL_DEFINITION (SimpleTextOut) +//@MT:#include EFI_PROTOCOL_DEFINITION (SimpleTextIn) +//@MT:#include EFI_PROTOCOL_DEFINITION (Print) +//@MT:#include EFI_PROTOCOL_DEFINITION (UnicodeCollation) + +// +// This is the generated header file which includes whatever needs to be exported (strings + IFR) +// + +extern UINT8 SetupBrowserStrings[]; + +// +// Screen definitions +// +#define BANNER_HEIGHT 6 +#define BANNER_COLUMNS 3 + +#define FRONT_PAGE_HEADER_HEIGHT 6 +#define NONE_FRONT_PAGE_HEADER_HEIGHT 3 +#define LEFT_SKIPPED_COLUMNS 4 +#define FOOTER_HEIGHT 4 +#define STATUS_BAR_HEIGHT 1 +#define SCROLL_ARROW_HEIGHT 1 +#define POPUP_PAD_SPACE_COUNT 5 +#define POPUP_FRAME_WIDTH 2 + +// +// Definition for function key setting +// +#define NONE_FUNCTION_KEY_SETTING 0 +#define DEFAULT_FUNCTION_KEY_SETTING (FUNCTION_ONE | FUNCTION_TWO | FUNCTION_NINE | FUNCTION_TEN) + +#define FUNCTION_ONE (1 << 0) +#define FUNCTION_TWO (1 << 1) +#define FUNCTION_NINE (1 << 2) +#define FUNCTION_TEN (1 << 3) + +typedef struct { + EFI_GUID FormSetGuid; + UINTN KeySetting; +} FUNCTIION_KEY_SETTING; + +// +// Character definitions +// +#define CHAR_SPACE 0x0020 +#define UPPER_LOWER_CASE_OFFSET 0x20 + +// +// Time definitions +// +#define ONE_SECOND 10000000 + +// +// Display definitions +// +#define LEFT_HYPER_DELIMITER L'<' +#define RIGHT_HYPER_DELIMITER L'>' + +#define LEFT_ONEOF_DELIMITER L'<' +#define RIGHT_ONEOF_DELIMITER L'>' + +#define LEFT_NUMERIC_DELIMITER L'[' +#define RIGHT_NUMERIC_DELIMITER L']' + +#define LEFT_CHECKBOX_DELIMITER L'[' +#define RIGHT_CHECKBOX_DELIMITER L']' + +#define CHECK_ON L'X' +#define CHECK_OFF L' ' + +#define TIME_SEPARATOR L':' +#define DATE_SEPARATOR L'/' + +#define YES_ANSWER L'Y' +#define NO_ANSWER L'N' + +// +// This is the Input Error Message +// +#define INPUT_ERROR 1 + +// +// This is the NV RAM update required Message +// +#define NV_UPDATE_REQUIRED 2 + +// +// Refresh the Status Bar with flags +// +#define REFRESH_STATUS_BAR 0xff + +// +// Incremental string lenght of ConfigRequest +// +#define CONFIG_REQUEST_STRING_INCREMENTAL 1024 + +// +// HII value compare result +// +#define HII_VALUE_UNDEFINED 0 +#define HII_VALUE_EQUAL 1 +#define HII_VALUE_LESS_THAN 2 +#define HII_VALUE_GREATER_THAN 3 + +// +// Incremental size of stack for expression +// +#define EXPRESSION_STACK_SIZE_INCREMENT 0x100 + + +#define EFI_SPECIFICATION_ERRATA_VERSION 0 + +#define EFI_IFR_SPECIFICATION_VERSION \ + ((((EFI_SPECIFICATION_VERSION) >> 8) & 0xff00) | \ + (((EFI_SPECIFICATION_VERSION) & 0xf) << 4) | \ + ((EFI_SPECIFICATION_ERRATA_VERSION) & 0xf)) + +#define SETUP_DRIVER_SIGNATURE EFI_SIGNATURE_32 ('F', 'B', 'D', 'V') +typedef struct { + UINT32 Signature; + + EFI_HANDLE Handle; + + // + // Produced protocol + // + EFI_FORM_BROWSER2_PROTOCOL FormBrowser2; + EFI_PRINT_PROTOCOL Print; + +} SETUP_DRIVER_PRIVATE_DATA; + +typedef struct { + EFI_STRING_ID Banner[BANNER_HEIGHT][BANNER_COLUMNS]; +} BANNER_DATA; + +// +// IFR relative definition +// +#define EFI_HII_EXPRESSION_INCONSISTENT_IF 0 +#define EFI_HII_EXPRESSION_NO_SUBMIT_IF 1 +#define EFI_HII_EXPRESSION_GRAY_OUT_IF 2 +#define EFI_HII_EXPRESSION_SUPPRESS_IF 3 +#define EFI_HII_EXPRESSION_DISABLE_IF 4 +#define EFI_HII_EXPRESSION_VALUE 5 +#define EFI_HII_EXPRESSION_RULE 6 + +#define EFI_HII_VARSTORE_BUFFER 0 +#define EFI_HII_VARSTORE_NAME_VALUE 1 +#define EFI_HII_VARSTORE_EFI_VARIABLE 2 + +#define FORM_INCONSISTENT_VALIDATION 0 +#define FORM_NO_SUBMIT_VALIDATION 1 + +typedef struct { + UINT8 Type; + EFI_IFR_TYPE_VALUE Value; +} EFI_HII_VALUE; + +#define NAME_VALUE_NODE_SIGNATURE EFI_SIGNATURE_32 ('N', 'V', 'S', 'T') + +typedef struct { + UINTN Signature; + LIST_ENTRY Link; + CHAR16 *Name; + CHAR16 *Value; + CHAR16 *EditValue; +} NAME_VALUE_NODE; + +#define NAME_VALUE_NODE_FROM_LINK(a) CR (a, NAME_VALUE_NODE, Link, NAME_VALUE_NODE_SIGNATURE) + +#define FORMSET_STORAGE_SIGNATURE EFI_SIGNATURE_32 ('F', 'S', 'T', 'G') + +typedef struct { + UINTN Signature; + LIST_ENTRY Link; + + UINT8 Type; // Storage type + + UINT16 VarStoreId; + EFI_GUID Guid; + + CHAR16 *Name; // For EFI_IFR_VARSTORE + UINT16 Size; + UINT8 *Buffer; + UINT8 *EditBuffer; // Edit copy for Buffer Storage + + LIST_ENTRY NameValueListHead; // List of NAME_VALUE_NODE + + UINT32 Attributes; // For EFI_IFR_VARSTORE_EFI: EFI Variable attribute + + CHAR16 *ConfigHdr; // <ConfigHdr> + CHAR16 *ConfigRequest; // <ConfigRequest> = <ConfigHdr> + <RequestElement> + UINTN ElementCount; // Number of <RequestElement> in the <ConfigRequest> + UINTN SpareStrLen; // Spare length of ConfigRequest string buffer +} FORMSET_STORAGE; + +#define FORMSET_STORAGE_FROM_LINK(a) CR (a, FORMSET_STORAGE, Link, FORMSET_STORAGE_SIGNATURE) + +#define EXPRESSION_OPCODE_SIGNATURE EFI_SIGNATURE_32 ('E', 'X', 'O', 'P') + +typedef struct { + UINTN Signature; + LIST_ENTRY Link; + + UINT8 Operand; + + UINT8 Format; // For EFI_IFR_TO_STRING, EFI_IFR_FIND + UINT8 Flags; // For EFI_IFR_SPAN + UINT8 RuleId; // For EFI_IFR_RULE_REF + + EFI_HII_VALUE Value; // For EFI_IFR_EQ_ID_VAL, EFI_IFR_UINT64, EFI_IFR_UINT32, EFI_IFR_UINT16, EFI_IFR_UINT8, EFI_IFR_STRING_REF1 + + EFI_QUESTION_ID QuestionId; // For EFI_IFR_EQ_ID_ID, EFI_IFR_EQ_ID_LIST, EFI_IFR_QUESTION_REF1 + EFI_QUESTION_ID QuestionId2; + + UINT16 ListLength; // For EFI_IFR_EQ_ID_LIST + UINT16 *ValueList; + + EFI_STRING_ID DevicePath; // For EFI_IFR_QUESTION_REF3_2, EFI_IFR_QUESTION_REF3_3 + EFI_GUID Guid; +} EXPRESSION_OPCODE; + +#define EXPRESSION_OPCODE_FROM_LINK(a) CR (a, EXPRESSION_OPCODE, Link, EXPRESSION_OPCODE_SIGNATURE) + +#define FORM_EXPRESSION_SIGNATURE EFI_SIGNATURE_32 ('F', 'E', 'X', 'P') + +typedef struct { + UINTN Signature; + LIST_ENTRY Link; + + UINT8 Type; // Type for this expression + + UINT8 RuleId; // For EFI_IFR_RULE only + EFI_STRING_ID Error; // For EFI_IFR_NO_SUBMIT_IF, EFI_IFR_INCONSISTENT_IF only + + EFI_HII_VALUE Result; // Expression evaluation result + + LIST_ENTRY OpCodeListHead; // OpCodes consist of this expression (EXPRESSION_OPCODE) +} FORM_EXPRESSION; + +#define FORM_EXPRESSION_FROM_LINK(a) CR (a, FORM_EXPRESSION, Link, FORM_EXPRESSION_SIGNATURE) + +#define QUESTION_DEFAULT_SIGNATURE EFI_SIGNATURE_32 ('Q', 'D', 'F', 'T') + +typedef struct { + UINTN Signature; + LIST_ENTRY Link; + + UINT16 DefaultId; + EFI_HII_VALUE Value; // Default value + + FORM_EXPRESSION *ValueExpression; // Not-NULL indicates default value is provided by EFI_IFR_VALUE +} QUESTION_DEFAULT; + +#define QUESTION_DEFAULT_FROM_LINK(a) CR (a, QUESTION_DEFAULT, Link, QUESTION_DEFAULT_SIGNATURE) + +#define QUESTION_OPTION_SIGNATURE EFI_SIGNATURE_32 ('Q', 'O', 'P', 'T') + +typedef struct { + UINTN Signature; + LIST_ENTRY Link; + + EFI_STRING_ID Text; + UINT8 Flags; + EFI_HII_VALUE Value; + EFI_IMAGE_ID ImageId; + + FORM_EXPRESSION *SuppressExpression; // Non-NULL indicates nested inside of SuppressIf +} QUESTION_OPTION; + +#define QUESTION_OPTION_FROM_LINK(a) CR (a, QUESTION_OPTION, Link, QUESTION_OPTION_SIGNATURE) + +#define FORM_BROWSER_STATEMENT_SIGNATURE EFI_SIGNATURE_32 ('F', 'S', 'T', 'A') +typedef struct { + UINTN Signature; + LIST_ENTRY Link; + + UINT8 Operand; // The operand (first byte) of this Statement or Question + + // + // Statement Header + // + EFI_STRING_ID Prompt; + EFI_STRING_ID Help; + EFI_STRING_ID TextTwo; // For EFI_IFR_TEXT + + // + // Question Header + // + EFI_QUESTION_ID QuestionId; // The value of zero is reserved + EFI_VARSTORE_ID VarStoreId; // A value of zero indicates no variable storage + FORMSET_STORAGE *Storage; + union { + EFI_STRING_ID VarName; + UINT16 VarOffset; + } VarStoreInfo; + UINT16 StorageWidth; + UINT8 QuestionFlags; + CHAR16 *VariableName; // Name/Value or EFI Variable name + CHAR16 *BlockName; // Buffer storage block name: "OFFSET=...WIDTH=..." + + EFI_HII_VALUE HiiValue; // Edit copy for checkbox, numberic, oneof + UINT8 *BufferValue; // Edit copy for string, password, orderedlist + + // + // OpCode specific members + // + UINT8 Flags; // for EFI_IFR_CHECKBOX, EFI_IFR_DATE, EFI_IFR_NUMERIC, EFI_IFR_ONE_OF, + // EFI_IFR_ORDERED_LIST, EFI_IFR_STRING,EFI_IFR_SUBTITLE,EFI_IFR_TIME, EFI_IFR_BANNER + UINT8 MaxContainers; // for EFI_IFR_ORDERED_LIST + + UINT16 BannerLineNumber; // for EFI_IFR_BANNER, 1-based line number + EFI_STRING_ID QuestionConfig; // for EFI_IFR_ACTION, if 0 then no configuration string will be processed + + UINT64 Minimum; // for EFI_IFR_ONE_OF/EFI_IFR_NUMERIC, it's Min/Max value + UINT64 Maximum; // for EFI_IFR_STRING/EFI_IFR_PASSWORD, it's Min/Max length + UINT64 Step; + + EFI_DEFAULT_ID DefaultId; // for EFI_IFR_RESET_BUTTON + EFI_FORM_ID RefFormId; // for EFI_IFR_REF + EFI_QUESTION_ID RefQuestionId; // for EFI_IFR_REF2 + EFI_GUID RefFormSetId; // for EFI_IFR_REF3 + EFI_STRING_ID RefDevicePath; // for EFI_IFR_REF4 + + // + // Get from IFR parsing + // + FORM_EXPRESSION *ValueExpression; // nested EFI_IFR_VALUE, provide Question value and indicate Question is ReadOnly + LIST_ENTRY DefaultListHead; // nested EFI_IFR_DEFAULT list (QUESTION_DEFAULT), provide default values + LIST_ENTRY OptionListHead; // nested EFI_IFR_ONE_OF_OPTION list (QUESTION_OPTION) + + EFI_IMAGE_ID ImageId; // nested EFI_IFR_IMAGE + UINT8 RefreshInterval; // nested EFI_IFR_REFRESH, refresh interval(in seconds) for Question value, 0 means no refresh + BOOLEAN InSubtitle; // nesting inside of EFI_IFR_SUBTITLE + + LIST_ENTRY InconsistentListHead;// nested inconsistent expression list (FORM_EXPRESSION) + LIST_ENTRY NoSubmitListHead; // nested nosubmit expression list (FORM_EXPRESSION) + FORM_EXPRESSION *GrayOutExpression; // nesting inside of GrayOutIf + FORM_EXPRESSION *SuppressExpression; // nesting inside of SuppressIf + +} FORM_BROWSER_STATEMENT; + +#define FORM_BROWSER_STATEMENT_FROM_LINK(a) CR (a, FORM_BROWSER_STATEMENT, Link, FORM_BROWSER_STATEMENT_SIGNATURE) + +#define FORM_BROWSER_FORM_SIGNATURE EFI_SIGNATURE_32 ('F', 'F', 'R', 'M') + +typedef struct { + UINTN Signature; + LIST_ENTRY Link; + + UINT16 FormId; + EFI_STRING_ID FormTitle; + + EFI_IMAGE_ID ImageId; + + LIST_ENTRY ExpressionListHead; // List of Expressions (FORM_EXPRESSION) + LIST_ENTRY StatementListHead; // List of Statements and Questions (FORM_BROWSER_STATEMENT) +} FORM_BROWSER_FORM; + +#define FORM_BROWSER_FORM_FROM_LINK(a) CR (a, FORM_BROWSER_FORM, Link, FORM_BROWSER_FORM_SIGNATURE) + +#define FORMSET_DEFAULTSTORE_SIGNATURE EFI_SIGNATURE_32 ('F', 'D', 'F', 'S') + +typedef struct { + UINTN Signature; + LIST_ENTRY Link; + + UINT16 DefaultId; + EFI_STRING_ID DefaultName; +} FORMSET_DEFAULTSTORE; + +#define FORMSET_DEFAULTSTORE_FROM_LINK(a) CR (a, FORMSET_DEFAULTSTORE, Link, FORMSET_DEFAULTSTORE_SIGNATURE) + +typedef struct { + EFI_HII_HANDLE HiiHandle; + EFI_HANDLE DriverHandle; + EFI_HII_CONFIG_ACCESS_PROTOCOL *ConfigAccess; + EFI_DEVICE_PATH_PROTOCOL *DevicePath; + + UINTN IfrBinaryLength; + UINT8 *IfrBinaryData; + + EFI_GUID Guid; + EFI_STRING_ID FormSetTitle; + EFI_STRING_ID Help; + UINT16 Class; + UINT16 SubClass; + EFI_IMAGE_ID ImageId; + + FORM_BROWSER_STATEMENT *StatementBuffer; // Buffer for all Statements and Questions + EXPRESSION_OPCODE *ExpressionBuffer; // Buffer for all Expression OpCode + + LIST_ENTRY StorageListHead; // Storage list (FORMSET_STORAGE) + LIST_ENTRY DefaultStoreListHead; // DefaultStore list (FORMSET_DEFAULTSTORE) + LIST_ENTRY FormListHead; // Form list (FORM_BROWSER_FORM) +} FORM_BROWSER_FORMSET; + + +extern EFI_HII_DATABASE_PROTOCOL *mHiiDatabase; +extern EFI_HII_STRING_PROTOCOL *mHiiString; +extern EFI_HII_CONFIG_ROUTING_PROTOCOL *mHiiConfigRouting; + +extern BANNER_DATA *BannerData; +extern EFI_HII_HANDLE FrontPageHandle; +extern UINTN gClassOfVfr; +extern UINTN gFunctionKeySetting; +extern BOOLEAN gResetRequired; +extern BOOLEAN gNvUpdateRequired; +extern EFI_HII_HANDLE gHiiHandle; +extern BOOLEAN gFirstIn; +extern UINT16 gDirection; +extern EFI_SCREEN_DESCRIPTOR gScreenDimensions; +extern BOOLEAN gUpArrow; +extern BOOLEAN gDownArrow; + +// +// Browser Global Strings +// +extern CHAR16 *gFunctionOneString; +extern CHAR16 *gFunctionTwoString; +extern CHAR16 *gFunctionNineString; +extern CHAR16 *gFunctionTenString; +extern CHAR16 *gEnterString; +extern CHAR16 *gEnterCommitString; +extern CHAR16 *gEscapeString; +extern CHAR16 *gSaveFailed; +extern CHAR16 *gMoveHighlight; +extern CHAR16 *gMakeSelection; +extern CHAR16 *gDecNumericInput; +extern CHAR16 *gHexNumericInput; +extern CHAR16 *gToggleCheckBox; +extern CHAR16 *gPromptForData; +extern CHAR16 *gPromptForPassword; +extern CHAR16 *gPromptForNewPassword; +extern CHAR16 *gConfirmPassword; +extern CHAR16 *gConfirmError; +extern CHAR16 *gPassowordInvalid; +extern CHAR16 *gPressEnter; +extern CHAR16 *gEmptyString; +extern CHAR16 *gAreYouSure; +extern CHAR16 *gYesResponse; +extern CHAR16 *gNoResponse; +extern CHAR16 *gMiniString; +extern CHAR16 *gPlusString; +extern CHAR16 *gMinusString; +extern CHAR16 *gAdjustNumber; + +extern CHAR16 gPromptBlockWidth; +extern CHAR16 gOptionBlockWidth; +extern CHAR16 gHelpBlockWidth; + +extern EFI_GUID gZeroGuid; +extern EFI_GUID gTianoHiiIfrGuid; + +// +// Global Procedure Defines +// +VOID +InitializeBrowserStrings ( + VOID + ) +; + +UINTN +_Print ( + IN CHAR16 *fmt, + ... + ) +; + +UINTN +PrintString ( + CHAR16 *String + ) +; + +UINTN +PrintChar ( + CHAR16 Character + ) +; + +UINTN +PrintAt ( + IN UINTN Column, + IN UINTN Row, + IN CHAR16 *fmt, + ... + ) +; + +UINTN +PrintStringAt ( + IN UINTN Column, + IN UINTN Row, + CHAR16 *String + ) +; + +UINTN +PrintCharAt ( + IN UINTN Column, + IN UINTN Row, + CHAR16 Character + ) +; + +EFI_STATUS +ParseOpCodes ( + IN FORM_BROWSER_FORMSET *FormSet + ) +; + +VOID +DestroyFormSet ( + IN OUT FORM_BROWSER_FORMSET *FormSet + ) +; + +VOID +DisplayPageFrame ( + VOID + ) +; + +EFI_STRING_ID +NewString ( + IN CHAR16 *String, + IN EFI_HII_HANDLE HiiHandle + ) +; + +EFI_STATUS +DeleteString ( + IN EFI_STRING_ID StringId, + IN EFI_HII_HANDLE HiiHandle + ) +; +CHAR16 * +GetToken ( + IN EFI_STRING_ID Token, + IN EFI_HII_HANDLE HiiHandle + ) +; + +VOID +CreateSharedPopUp ( + IN UINTN RequestedWidth, + IN UINTN NumberOfLines, + IN CHAR16 **ArrayOfStrings + ) +; + +EFI_STATUS +CreateDialog ( + IN UINTN NumberOfLines, + IN BOOLEAN HotKey, + IN UINTN MaximumStringSize, + OUT CHAR16 *StringBuffer, + OUT EFI_INPUT_KEY *KeyValue, + IN CHAR16 *String, + ... + ) +; + +EFI_STATUS +GetQuestionValue ( + IN FORM_BROWSER_FORMSET *FormSet, + IN FORM_BROWSER_FORM *Form, + IN OUT FORM_BROWSER_STATEMENT *Question, + IN BOOLEAN Cached + ) +; + +EFI_STATUS +SetQuestionValue ( + IN FORM_BROWSER_FORMSET *FormSet, + IN FORM_BROWSER_FORM *Form, + IN OUT FORM_BROWSER_STATEMENT *Question, + IN BOOLEAN Cached + ) +; + +EFI_STATUS +ValidateQuestion ( + IN FORM_BROWSER_FORMSET *FormSet, + IN FORM_BROWSER_FORM *Form, + IN FORM_BROWSER_STATEMENT *Question, + IN UINTN Type + ) +; + +EFI_STATUS +SubmitForm ( + IN FORM_BROWSER_FORMSET *FormSet, + IN FORM_BROWSER_FORM *Form + ) +; + +EFI_STATUS +GetQuestionDefault ( + IN FORM_BROWSER_FORMSET *FormSet, + IN FORM_BROWSER_FORM *Form, + IN FORM_BROWSER_STATEMENT *Question, + IN UINT16 DefaultId + ) +; + +EFI_STATUS +InitializeCurrentSetting ( + IN OUT FORM_BROWSER_FORMSET *FormSet + ) +; + +EFI_STATUS +InitializeFormSet ( + IN EFI_HII_HANDLE Handle, + IN OUT EFI_GUID *FormSetGuid, + OUT FORM_BROWSER_FORMSET *FormSet + ) +; + +EFI_STATUS +ExtractFormDefault ( + IN FORM_BROWSER_FORMSET *FormSet, + IN FORM_BROWSER_FORM *Form, + IN UINT16 DefaultId + ) +; + +EFI_STATUS +LoadFormConfig ( + IN FORM_BROWSER_FORMSET *FormSet, + IN FORM_BROWSER_FORM *Form + ) +; + +EFI_STATUS +StorageToConfigResp ( + IN FORMSET_STORAGE *Storage, + IN CHAR16 **ConfigResp + ) +; + +EFI_STATUS +ConfigRespToStorage ( + IN FORMSET_STORAGE *Storage, + IN CHAR16 *ConfigResp + ) +; + +EFI_STATUS +LoadStorage ( + IN FORM_BROWSER_FORMSET *FormSet, + IN FORMSET_STORAGE *Storage + ) +; + +EFI_STATUS +GetIfrBinaryData ( + IN EFI_HII_HANDLE Handle, + IN OUT EFI_GUID *FormSetGuid, + OUT UINTN *BinaryLength, + OUT UINT8 **BinaryData + ) +; + +EFI_STATUS +EFIAPI +SendForm ( + IN CONST EFI_FORM_BROWSER2_PROTOCOL *This, + IN EFI_HII_HANDLE *Handles, + IN UINTN HandleCount, + IN EFI_GUID *FormSetGuid, OPTIONAL + IN UINT16 FormId, OPTIONAL + IN CONST EFI_SCREEN_DESCRIPTOR *ScreenDimensions, OPTIONAL + OUT EFI_BROWSER_ACTION_REQUEST *ActionRequest OPTIONAL + ) +; + +EFI_STATUS +EFIAPI +BrowserCallback ( + IN CONST EFI_FORM_BROWSER2_PROTOCOL *This, + IN OUT UINTN *ResultsDataSize, + IN OUT EFI_STRING ResultsData, + IN BOOLEAN RetrieveData, + IN CONST EFI_GUID *VariableGuid, OPTIONAL + IN CONST CHAR16 *VariableName OPTIONAL + ) +; + +#endif diff --git a/MdeModulePkg/Universal/SetupBrowserDxe/SetupBrowser.msa b/MdeModulePkg/Universal/SetupBrowserDxe/SetupBrowser.msa new file mode 100644 index 0000000000..57774992fe --- /dev/null +++ b/MdeModulePkg/Universal/SetupBrowserDxe/SetupBrowser.msa @@ -0,0 +1,84 @@ +<ModuleSurfaceArea xmlns="http://www.TianoCore.org/2006/Edk2.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
+ <MsaHeader>
+ <ModuleName>SetupBrowser</ModuleName>
+ <ModuleType>DXE_DRIVER</ModuleType>
+ <GuidValue>EBf342FE-B1D3-4EF8-957C-8048606FF671</GuidValue>
+ <Version>1.0</Version>
+ <Abstract>Component name for module SetupBrowser</Abstract>
+ <Description>FIX ME!</Description>
+ <Copyright>Copyright (c) 2007, Intel Corporation. All rights reserved.</Copyright>
+ <License>All rights reserved. This program and the accompanying materials + are licensed and made available under the terms and conditions of the BSD License + which accompanies this distribution. The full text of the license may be found at + http://opensource.org/licenses/bsd-license.php + + THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, + WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.</License>
+ <Specification>FRAMEWORK_BUILD_PACKAGING_SPECIFICATION 0x00000052</Specification>
+ </MsaHeader>
+ <ModuleDefinitions>
+ <SupportedArchitectures>IA32 X64 IPF EBC</SupportedArchitectures>
+ <BinaryModule>false</BinaryModule>
+ <OutputFileBasename>SetupBrowser</OutputFileBasename>
+ </ModuleDefinitions>
+ <LibraryClassDefinitions>
+ <LibraryClass Usage="ALWAYS_CONSUMED">
+ <Keyword>PrintLib</Keyword>
+ </LibraryClass>
+ <LibraryClass Usage="ALWAYS_CONSUMED">
+ <Keyword>DebugLib</Keyword>
+ </LibraryClass>
+ <LibraryClass Usage="ALWAYS_CONSUMED">
+ <Keyword>BaseMemoryLib</Keyword>
+ </LibraryClass>
+ <LibraryClass Usage="ALWAYS_CONSUMED">
+ <Keyword>UefiRuntimeServicesTableLib</Keyword>
+ </LibraryClass>
+ <LibraryClass Usage="ALWAYS_CONSUMED">
+ <Keyword>UefiDriverEntryPoint</Keyword>
+ </LibraryClass>
+ <LibraryClass Usage="ALWAYS_CONSUMED">
+ <Keyword>UefiBootServicesTableLib</Keyword>
+ </LibraryClass>
+ <LibraryClass Usage="ALWAYS_CONSUMED">
+ <Keyword>BaseLib</Keyword>
+ </LibraryClass>
+ <LibraryClass Usage="ALWAYS_CONSUMED">
+ <Keyword>MemoryAllocationLib</Keyword>
+ </LibraryClass>
+ </LibraryClassDefinitions>
+ <SourceFiles>
+ <Filename>R8Lib.h</Filename>
+ <Filename>Print.h</Filename>
+ <Filename>Setup.c</Filename>
+ <Filename>Setup.h</Filename>
+ <Filename>Ui.h</Filename>
+ <Filename>Print.c</Filename>
+ <Filename>SetupBrowser.dxs</Filename>
+ <Filename>R8Lib.c</Filename>
+ <Filename>ProcessOptions.c</Filename>
+ <Filename>InputHandler.c</Filename>
+ <Filename>Ui.c</Filename>
+ <Filename>IfrParse.c</Filename>
+ <Filename>Expression.c</Filename>
+ <Filename>Colors.h</Filename>
+ <Filename>Presentation.c</Filename>
+ <Filename>SetupBrowserStr.uni</Filename>
+ </SourceFiles>
+ <PackageDependencies>
+ <Package PackageGuid="5e0e9358-46b6-4ae2-8218-4ab8b9bbdcec"/>
+ <Package PackageGuid="68169ab0-d41b-4009-9060-292c253ac43d"/>
+ </PackageDependencies>
+ <Protocols>
+ <Protocol Usage="ALWAYS_CONSUMED">
+ <ProtocolCName>gEfiPrintProtocolGuid</ProtocolCName>
+ </Protocol>
+ </Protocols>
+ <Externs>
+ <Specification>EFI_SPECIFICATION_VERSION 0x00020000</Specification>
+ <Specification>EDK_RELEASE_VERSION 0x00020000</Specification>
+ <Extern>
+ <ModuleEntryPoint>InitializeSetup</ModuleEntryPoint>
+ </Extern>
+ </Externs>
+</ModuleSurfaceArea>
\ No newline at end of file diff --git a/MdeModulePkg/Universal/SetupBrowserDxe/SetupBrowserDxe.inf b/MdeModulePkg/Universal/SetupBrowserDxe/SetupBrowserDxe.inf new file mode 100644 index 0000000000..807076e8ad --- /dev/null +++ b/MdeModulePkg/Universal/SetupBrowserDxe/SetupBrowserDxe.inf @@ -0,0 +1,82 @@ +#/** @file
+# Component name for module SetupBrowser
+#
+# FIX ME!
+# Copyright (c) 2007, Intel Corporation. All rights reserved.
+#
+# All rights reserved. This program and the accompanying materials
+# are licensed and made available under the terms and conditions of the BSD License
+# which accompanies this distribution. The full text of the license may be found at
+# http://opensource.org/licenses/bsd-license.php
+#
+# THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+# WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+#
+#
+#**/
+
+[Defines]
+ INF_VERSION = 0x00010005
+ BASE_NAME = SetupBrowser
+ FILE_GUID = EBf342FE-B1D3-4EF8-957C-8048606FF671
+ MODULE_TYPE = DXE_DRIVER
+ VERSION_STRING = 1.0
+ EDK_RELEASE_VERSION = 0x00020000
+ EFI_SPECIFICATION_VERSION = 0x0002000A
+
+ ENTRY_POINT = InitializeSetup
+
+#
+# The following information is for reference only and not required by the build tools.
+#
+# VALID_ARCHITECTURES = IA32 X64 IPF EBC
+#
+
+[Sources.common]
+ SetupBrowserStr.uni
+ Setup.c
+ Setup.h
+ IfrParse.c
+ Expression.c
+ InputHandler.c
+ Print.c
+ Print.h
+ Presentation.c
+ ProcessOptions.c
+ Ui.c
+ Ui.h
+ R8Lib.c
+ R8Lib.h
+ Colors.h
+
+
+[Packages]
+ MdePkg/MdePkg.dec
+ MdeModulePkg/MdeModulePkg.dec
+
+
+[LibraryClasses]
+ MemoryAllocationLib
+ BaseLib
+ UefiBootServicesTableLib
+ UefiDriverEntryPoint
+ UefiRuntimeServicesTableLib
+ BaseMemoryLib
+ DebugLib
+ PrintLib
+ GraphicsLib
+ IfrSupportLib
+ HiiLib
+
+[Protocols]
+ gEfiPrintProtocolGuid # PROTOCOL ALWAYS_CONSUMED
+ gEfiHiiConfigAccessProtocolGuid
+ gEfiHiiStringProtocolGuid
+ gEfiFormBrowser2ProtocolGuid
+ gEfiHiiConfigRoutingProtocolGuid
+ gEfiHiiDatabaseProtocolGuid
+ gEfiUnicodeCollation2ProtocolGuid
+
+[Depex]
+ gEfiHiiDatabaseProtocolGuid AND gEfiHiiConfigRoutingProtocolGuid
+
diff --git a/MdeModulePkg/Universal/SetupBrowserDxe/SetupBrowserStr.uni b/MdeModulePkg/Universal/SetupBrowserDxe/SetupBrowserStr.uni Binary files differnew file mode 100644 index 0000000000..5b5e282d84 --- /dev/null +++ b/MdeModulePkg/Universal/SetupBrowserDxe/SetupBrowserStr.uni diff --git a/MdeModulePkg/Universal/SetupBrowserDxe/Ui.c b/MdeModulePkg/Universal/SetupBrowserDxe/Ui.c new file mode 100644 index 0000000000..34ec5260de --- /dev/null +++ b/MdeModulePkg/Universal/SetupBrowserDxe/Ui.c @@ -0,0 +1,2830 @@ +/** @file + +Copyright (c) 2004 - 2007, Intel Corporation +All rights reserved. This program and the accompanying materials +are licensed and made available under the terms and conditions of the BSD License +which accompanies this distribution. The full text of the license may be found at +http://opensource.org/licenses/bsd-license.php + +THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, +WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. + +Module Name: + + Ui.c + +Abstract: + + Implementation for UI. + +Revision History + + +**/ + +#include "Ui.h" +#include "Setup.h" + +LIST_ENTRY Menu; +LIST_ENTRY gMenuList; +MENU_REFRESH_ENTRY *gMenuRefreshHead; + +// +// Search table for UiDisplayMenu() +// +SCAN_CODE_TO_SCREEN_OPERATION gScanCodeToOperation[] = { + SCAN_UP, + UiUp, + SCAN_DOWN, + UiDown, + SCAN_PAGE_UP, + UiPageUp, + SCAN_PAGE_DOWN, + UiPageDown, + SCAN_ESC, + UiReset, + SCAN_F2, + UiPrevious, + SCAN_LEFT, + UiLeft, + SCAN_RIGHT, + UiRight, + SCAN_F9, + UiDefault, + SCAN_F10, + UiSave +}; + +SCREEN_OPERATION_T0_CONTROL_FLAG gScreenOperationToControlFlag[] = { + UiNoOperation, + CfUiNoOperation, + UiDefault, + CfUiDefault, + UiSelect, + CfUiSelect, + UiUp, + CfUiUp, + UiDown, + CfUiDown, + UiLeft, + CfUiLeft, + UiRight, + CfUiRight, + UiReset, + CfUiReset, + UiSave, + CfUiSave, + UiPrevious, + CfUiPrevious, + UiPageUp, + CfUiPageUp, + UiPageDown, + CfUiPageDown +}; + + +/** + Set Buffer to Value for Size bytes. + + @param Buffer Memory to set. + @param Size Number of bytes to set + @param Value Value of the set operation. + + @return None + +**/ +VOID +SetUnicodeMem ( + IN VOID *Buffer, + IN UINTN Size, + IN CHAR16 Value + ) +{ + CHAR16 *Ptr; + + Ptr = Buffer; + while (Size--) { + *(Ptr++) = Value; + } +} + + +/** + Initialize Menu option list. + + None. + + @return None. + +**/ +VOID +UiInitMenu ( + VOID + ) +{ + InitializeListHead (&Menu); +} + + +/** + Initialize Menu option list. + + None. + + @return None. + +**/ +VOID +UiInitMenuList ( + VOID + ) +{ + InitializeListHead (&gMenuList); +} + + +/** + Remove a Menu in list, and return FormId/QuestionId for previous Menu. + + @param Selection Menu selection. + + @return None. + +**/ +VOID +UiRemoveMenuListEntry ( + IN OUT UI_MENU_SELECTION *Selection + ) +{ + UI_MENU_LIST *UiMenuList; + + if (!IsListEmpty (&gMenuList)) { + UiMenuList = CR (gMenuList.ForwardLink, UI_MENU_LIST, MenuLink, UI_MENU_LIST_SIGNATURE); + + Selection->FormId = UiMenuList->FormId; + Selection->QuestionId = UiMenuList->QuestionId; + RemoveEntryList (&UiMenuList->MenuLink); + gBS->FreePool (UiMenuList); + } +} + + +/** + Free Menu option linked list. + + None. + + @return None. + +**/ +VOID +UiFreeMenuList ( + VOID + ) +{ + UI_MENU_LIST *UiMenuList; + + while (!IsListEmpty (&gMenuList)) { + UiMenuList = CR (gMenuList.ForwardLink, UI_MENU_LIST, MenuLink, UI_MENU_LIST_SIGNATURE); + RemoveEntryList (&UiMenuList->MenuLink); + gBS->FreePool (UiMenuList); + } +} + + +/** + Add one menu entry to the linked lst + + @param Selection Menu selection. + + @return None. + +**/ +VOID +UiAddMenuListEntry ( + IN UI_MENU_SELECTION *Selection + ) +{ + UI_MENU_LIST *UiMenuList; + + UiMenuList = AllocateZeroPool (sizeof (UI_MENU_LIST)); + ASSERT (UiMenuList != NULL); + + UiMenuList->Signature = UI_MENU_LIST_SIGNATURE; + UiMenuList->FormId = Selection->FormId; + UiMenuList->QuestionId = Selection->QuestionId; + + InsertHeadList (&gMenuList, &UiMenuList->MenuLink); +} + + +/** + Free Menu option linked list. + + None. + + @return None. + +**/ +VOID +UiFreeMenu ( + VOID + ) +{ + UI_MENU_OPTION *MenuOption; + + while (!IsListEmpty (&Menu)) { + MenuOption = MENU_OPTION_FROM_LINK (Menu.ForwardLink); + RemoveEntryList (&MenuOption->Link); + + // + // We allocated space for this description when we did a GetToken, free it here + // + if (MenuOption->Skip != 0) { + // + // For date/time, MenuOption->Description is shared by three Menu Options + // Data format : [01/02/2004] [11:22:33] + // Line number : 0 0 1 0 0 1 + // + gBS->FreePool (MenuOption->Description); + } + gBS->FreePool (MenuOption); + } +} + + +/** + Free Menu option linked list. + + None. + + @return None. + +**/ +VOID +UiFreeRefreshList ( + VOID + ) +{ + MENU_REFRESH_ENTRY *OldMenuRefreshEntry; + + while (gMenuRefreshHead != NULL) { + OldMenuRefreshEntry = gMenuRefreshHead->Next; + gBS->FreePool (gMenuRefreshHead); + gMenuRefreshHead = OldMenuRefreshEntry; + } + + gMenuRefreshHead = NULL; +} + + + +/** + Refresh screen. + + None. + + @return None. + +**/ +VOID +RefreshForm ( + VOID + ) +{ + CHAR16 *OptionString; + MENU_REFRESH_ENTRY *MenuRefreshEntry; + UINTN Index; + UINTN Loop; + EFI_STATUS Status; + UI_MENU_SELECTION *Selection; + FORM_BROWSER_STATEMENT *Question; + + OptionString = NULL; + + if (gMenuRefreshHead != NULL) { + + MenuRefreshEntry = gMenuRefreshHead; + + do { + gST->ConOut->SetAttribute (gST->ConOut, MenuRefreshEntry->CurrentAttribute); + + Selection = MenuRefreshEntry->Selection; + Question = MenuRefreshEntry->MenuOption->ThisTag; + + // + // Don't update Question being edited + // + if (Question != MenuRefreshEntry->Selection->Statement) { + + Status = GetQuestionValue (Selection->FormSet, Selection->Form, Question, FALSE); + if (EFI_ERROR (Status)) { + return; + } + + ProcessOptions (Selection, MenuRefreshEntry->MenuOption, FALSE, &OptionString); + + if (OptionString != NULL) { + // + // If leading spaces on OptionString - remove the spaces + // + for (Index = 0; OptionString[Index] == L' '; Index++) + ; + + for (Loop = 0; OptionString[Index] != CHAR_NULL; Index++) { + OptionString[Loop] = OptionString[Index]; + Loop++; + } + + OptionString[Loop] = CHAR_NULL; + + PrintStringAt (MenuRefreshEntry->CurrentColumn, MenuRefreshEntry->CurrentRow, OptionString); + gBS->FreePool (OptionString); + } + } + + MenuRefreshEntry = MenuRefreshEntry->Next; + + } while (MenuRefreshEntry != NULL); + } +} + + +/** + Wait for a given event to fire, or for an optional timeout to expire. + + @param Event The event to wait for + @param Timeout An optional timeout value in 100 ns units. + @param RefreshInterval Menu refresh interval (in seconds). + + @retval EFI_SUCCESS Event fired before Timeout expired. + @retval EFI_TIME_OUT Timout expired before Event fired. + +**/ +EFI_STATUS +UiWaitForSingleEvent ( + IN EFI_EVENT Event, + IN UINT64 Timeout, OPTIONAL + IN UINT8 RefreshInterval OPTIONAL + ) +{ + EFI_STATUS Status; + UINTN Index; + EFI_EVENT TimerEvent; + EFI_EVENT WaitList[2]; + + if (Timeout) { + // + // Create a timer event + // + Status = gBS->CreateEvent (EVT_TIMER, 0, NULL, NULL, &TimerEvent); + if (!EFI_ERROR (Status)) { + // + // Set the timer event + // + gBS->SetTimer ( + TimerEvent, + TimerRelative, + Timeout + ); + + // + // Wait for the original event or the timer + // + WaitList[0] = Event; + WaitList[1] = TimerEvent; + Status = gBS->WaitForEvent (2, WaitList, &Index); + gBS->CloseEvent (TimerEvent); + + // + // If the timer expired, change the return to timed out + // + if (!EFI_ERROR (Status) && Index == 1) { + Status = EFI_TIMEOUT; + } + } + } else { + // + // Update screen every second + // + if (RefreshInterval == 0) { + Timeout = ONE_SECOND; + } else { + Timeout = RefreshInterval * ONE_SECOND; + } + + do { + Status = gBS->CreateEvent (EVT_TIMER, 0, NULL, NULL, &TimerEvent); + + // + // Set the timer event + // + gBS->SetTimer ( + TimerEvent, + TimerRelative, + Timeout + ); + + // + // Wait for the original event or the timer + // + WaitList[0] = Event; + WaitList[1] = TimerEvent; + Status = gBS->WaitForEvent (2, WaitList, &Index); + + // + // If the timer expired, update anything that needs a refresh and keep waiting + // + if (!EFI_ERROR (Status) && Index == 1) { + Status = EFI_TIMEOUT; + if (RefreshInterval != 0) { + RefreshForm (); + } + } + + gBS->CloseEvent (TimerEvent); + } while (Status == EFI_TIMEOUT); + } + + return Status; +} + + +/** + Add one menu option by specified description and context. + + @param String String description for this option. + @param Handle Hii handle for the package list. + @param Statement Statement of this Menu Option. + @param NumberOfLines Display lines for this Menu Option. + @param MenuItemCount The index for this Option in the Menu. + + @return None. + +**/ +VOID +UiAddMenuOption ( + IN CHAR16 *String, + IN EFI_HII_HANDLE Handle, + IN FORM_BROWSER_STATEMENT *Statement, + IN UINT16 NumberOfLines, + IN UINT16 MenuItemCount + ) +{ + UI_MENU_OPTION *MenuOption; + UINTN Index; + UINTN Count; + + Count = 1; + + if (Statement->Operand == EFI_IFR_DATE_OP || Statement->Operand == EFI_IFR_TIME_OP) { + // + // Add three MenuOptions for Date/Time + // Data format : [01/02/2004] [11:22:33] + // Line number : 0 0 1 0 0 1 + // + NumberOfLines = 0; + Count = 3; + + if (Statement->Storage == NULL) { + // + // For RTC type of date/time, set default refresh interval to be 1 second + // + if (Statement->RefreshInterval == 0) { + Statement->RefreshInterval = 1; + } + } + } + + for (Index = 0; Index < Count; Index++) { + MenuOption = AllocateZeroPool (sizeof (UI_MENU_OPTION)); + ASSERT (MenuOption); + + MenuOption->Signature = UI_MENU_OPTION_SIGNATURE; + MenuOption->Description = String; + MenuOption->Handle = Handle; + MenuOption->ThisTag = Statement; + MenuOption->EntryNumber = MenuItemCount; + + if (Index == 2) { + // + // Override LineNumber for the MenuOption in Date/Time sequence + // + MenuOption->Skip = 1; + } else { + MenuOption->Skip = NumberOfLines; + } + MenuOption->Sequence = Index; + + if (Statement->GrayOutExpression != NULL) { + MenuOption->GrayOut = Statement->GrayOutExpression->Result.Value.b; + } + + if ((Statement->ValueExpression != NULL) || + (Statement->QuestionFlags & EFI_IFR_FLAG_READ_ONLY)) { + MenuOption->ReadOnly = TRUE; + } + + InsertTailList (&Menu, &MenuOption->Link); + } +} + + +/** + Routine used to abstract a generic dialog interface and return the selected key or string + + @param NumberOfLines The number of lines for the dialog box + @param HotKey Defines whether a single character is parsed + (TRUE) and returned in KeyValue or a string is + returned in StringBuffer. Two special characters + are considered when entering a string, a SCAN_ESC + and an CHAR_CARRIAGE_RETURN. SCAN_ESC terminates + string input and returns + @param MaximumStringSize The maximum size in bytes of a typed in string + (each character is a CHAR16) and the minimum + string returned is two bytes + @param StringBuffer The passed in pointer to the buffer which will + hold the typed in string if HotKey is FALSE + @param KeyValue The EFI_KEY value returned if HotKey is TRUE.. + @param String Pointer to the first string in the list + @param ... A series of (quantity == NumberOfLines) text + strings which will be used to construct the dialog + box + + @retval EFI_SUCCESS Displayed dialog and received user interaction + @retval EFI_INVALID_PARAMETER One of the parameters was invalid (e.g. + (StringBuffer == NULL) && (HotKey == FALSE)) + @retval EFI_DEVICE_ERROR User typed in an ESC character to exit the routine + +**/ +EFI_STATUS +CreateDialog ( + IN UINTN NumberOfLines, + IN BOOLEAN HotKey, + IN UINTN MaximumStringSize, + OUT CHAR16 *StringBuffer, + OUT EFI_INPUT_KEY *KeyValue, + IN CHAR16 *String, + ... + ) +{ + VA_LIST Marker; + UINTN Count; + EFI_INPUT_KEY Key; + UINTN LargestString; + CHAR16 *TempString; + CHAR16 *BufferedString; + CHAR16 *StackString; + CHAR16 KeyPad[2]; + UINTN Start; + UINTN Top; + UINTN Index; + EFI_STATUS Status; + BOOLEAN SelectionComplete; + UINTN InputOffset; + UINTN CurrentAttribute; + UINTN DimensionsWidth; + UINTN DimensionsHeight; + + DimensionsWidth = gScreenDimensions.RightColumn - gScreenDimensions.LeftColumn; + DimensionsHeight = gScreenDimensions.BottomRow - gScreenDimensions.TopRow; + + SelectionComplete = FALSE; + InputOffset = 0; + TempString = AllocateZeroPool (MaximumStringSize * 2); + BufferedString = AllocateZeroPool (MaximumStringSize * 2); + CurrentAttribute = gST->ConOut->Mode->Attribute; + + ASSERT (TempString); + ASSERT (BufferedString); + + VA_START (Marker, String); + + // + // Zero the outgoing buffer + // + ZeroMem (StringBuffer, MaximumStringSize); + + if (HotKey) { + if (KeyValue == NULL) { + return EFI_INVALID_PARAMETER; + } + } else { + if (StringBuffer == NULL) { + return EFI_INVALID_PARAMETER; + } + } + // + // Disable cursor + // + gST->ConOut->EnableCursor (gST->ConOut, FALSE); + + LargestString = (GetStringWidth (String) / 2); + + if (*String == L' ') { + InputOffset = 1; + } + // + // Determine the largest string in the dialog box + // Notice we are starting with 1 since String is the first string + // + for (Count = 1; Count < NumberOfLines; Count++) { + StackString = VA_ARG (Marker, CHAR16 *); + + if (StackString[0] == L' ') { + InputOffset = Count + 1; + } + + if ((GetStringWidth (StackString) / 2) > LargestString) { + // + // Size of the string visually and subtract the width by one for the null-terminator + // + LargestString = (GetStringWidth (StackString) / 2); + } + } + + Start = (DimensionsWidth - LargestString - 2) / 2 + gScreenDimensions.LeftColumn + 1; + Top = ((DimensionsHeight - NumberOfLines - 2) / 2) + gScreenDimensions.TopRow - 1; + + Count = 0; + + // + // Display the Popup + // + CreateSharedPopUp (LargestString, NumberOfLines, &String); + + // + // Take the first key typed and report it back? + // + if (HotKey) { + Status = WaitForKeyStroke (&Key); + ASSERT_EFI_ERROR (Status); + CopyMem (KeyValue, &Key, sizeof (EFI_INPUT_KEY)); + + } else { + do { + Status = WaitForKeyStroke (&Key); + + switch (Key.UnicodeChar) { + case CHAR_NULL: + switch (Key.ScanCode) { + case SCAN_ESC: + gBS->FreePool (TempString); + gBS->FreePool (BufferedString); + gST->ConOut->SetAttribute (gST->ConOut, CurrentAttribute); + gST->ConOut->EnableCursor (gST->ConOut, TRUE); + return EFI_DEVICE_ERROR; + + default: + break; + } + + break; + + case CHAR_CARRIAGE_RETURN: + SelectionComplete = TRUE; + gBS->FreePool (TempString); + gBS->FreePool (BufferedString); + gST->ConOut->SetAttribute (gST->ConOut, CurrentAttribute); + gST->ConOut->EnableCursor (gST->ConOut, TRUE); + return EFI_SUCCESS; + break; + + case CHAR_BACKSPACE: + if (StringBuffer[0] != CHAR_NULL) { + for (Index = 0; StringBuffer[Index] != CHAR_NULL; Index++) { + TempString[Index] = StringBuffer[Index]; + } + // + // Effectively truncate string by 1 character + // + TempString[Index - 1] = CHAR_NULL; + StrCpy (StringBuffer, TempString); + } + + default: + // + // If it is the beginning of the string, don't worry about checking maximum limits + // + if ((StringBuffer[0] == CHAR_NULL) && (Key.UnicodeChar != CHAR_BACKSPACE)) { + StrnCpy (StringBuffer, &Key.UnicodeChar, 1); + StrnCpy (TempString, &Key.UnicodeChar, 1); + } else if ((GetStringWidth (StringBuffer) < MaximumStringSize) && (Key.UnicodeChar != CHAR_BACKSPACE)) { + KeyPad[0] = Key.UnicodeChar; + KeyPad[1] = CHAR_NULL; + StrCat (StringBuffer, KeyPad); + StrCat (TempString, KeyPad); + } + // + // If the width of the input string is now larger than the screen, we nee to + // adjust the index to start printing portions of the string + // + SetUnicodeMem (BufferedString, LargestString, L' '); + + PrintStringAt (Start + 1, Top + InputOffset, BufferedString); + + if ((GetStringWidth (StringBuffer) / 2) > (DimensionsWidth - 2)) { + Index = (GetStringWidth (StringBuffer) / 2) - DimensionsWidth + 2; + } else { + Index = 0; + } + + for (Count = 0; Index + 1 < GetStringWidth (StringBuffer) / 2; Index++, Count++) { + BufferedString[Count] = StringBuffer[Index]; + } + + PrintStringAt (Start + 1, Top + InputOffset, BufferedString); + break; + } + } while (!SelectionComplete); + } + + gST->ConOut->SetAttribute (gST->ConOut, CurrentAttribute); + gST->ConOut->EnableCursor (gST->ConOut, TRUE); + return EFI_SUCCESS; +} + +VOID +CreateSharedPopUp ( + IN UINTN RequestedWidth, + IN UINTN NumberOfLines, + IN CHAR16 **ArrayOfStrings + ) +{ + UINTN Index; + UINTN Count; + CHAR16 Character; + UINTN Start; + UINTN End; + UINTN Top; + UINTN Bottom; + CHAR16 *String; + UINTN DimensionsWidth; + UINTN DimensionsHeight; + + DimensionsWidth = gScreenDimensions.RightColumn - gScreenDimensions.LeftColumn; + DimensionsHeight = gScreenDimensions.BottomRow - gScreenDimensions.TopRow; + + Count = 0; + + gST->ConOut->SetAttribute (gST->ConOut, POPUP_TEXT | POPUP_BACKGROUND); + + 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 + gScreenDimensions.LeftColumn + 1; + End = Start + RequestedWidth + 1; + + Top = ((DimensionsHeight - NumberOfLines - 2) / 2) + gScreenDimensions.TopRow - 1; + Bottom = Top + NumberOfLines + 2; + + Character = BOXDRAW_DOWN_RIGHT; + PrintCharAt (Start, Top, Character); + Character = BOXDRAW_HORIZONTAL; + for (Index = Start; Index + 2 < End; Index++) { + PrintChar (Character); + } + + Character = BOXDRAW_DOWN_LEFT; + PrintChar (Character); + Character = BOXDRAW_VERTICAL; + for (Index = Top; Index + 2 < Bottom; Index++) { + String = ArrayOfStrings[Count]; + Count++; + + // + // 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, POPUP_TEXT | POPUP_BACKGROUND); + } + + // + // 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, POPUP_INVERSE_TEXT | POPUP_INVERSE_BACKGROUND); + } + + // + // Passing in a NULL results in a blank space + // + if (String[0] == CHAR_NULL) { + ClearLines (Start, End, Index + 1, Index + 1, POPUP_TEXT | POPUP_BACKGROUND); + } + + PrintStringAt ( + ((DimensionsWidth - GetStringWidth (String) / 2) / 2) + gScreenDimensions.LeftColumn + 1, + Index + 1, + String + ); + gST->ConOut->SetAttribute (gST->ConOut, POPUP_TEXT | POPUP_BACKGROUND); + 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++) { + PrintChar (Character); + } + + Character = BOXDRAW_UP_LEFT; + PrintChar (Character); +} + +VOID +CreatePopUp ( + IN UINTN RequestedWidth, + IN UINTN NumberOfLines, + IN CHAR16 *ArrayOfStrings, + ... + ) +{ + CreateSharedPopUp (RequestedWidth, NumberOfLines, &ArrayOfStrings); +} + + +/** + Update status bar on the bottom of menu. + + @param MessageType The type of message to be shown. + @param Flags The flags in Question header. + @param State Set or clear. + + @return None. + +**/ +VOID +UpdateStatusBar ( + IN UINTN MessageType, + IN UINT8 Flags, + IN BOOLEAN State + ) +{ + UINTN Index; + STATIC BOOLEAN InputError; + CHAR16 *NvUpdateMessage; + CHAR16 *InputErrorMessage; + + NvUpdateMessage = GetToken (STRING_TOKEN (NV_UPDATE_MESSAGE), gHiiHandle); + InputErrorMessage = GetToken (STRING_TOKEN (INPUT_ERROR_MESSAGE), gHiiHandle); + + switch (MessageType) { + case INPUT_ERROR: + if (State) { + gST->ConOut->SetAttribute (gST->ConOut, ERROR_TEXT); + PrintStringAt ( + gScreenDimensions.LeftColumn + gPromptBlockWidth, + gScreenDimensions.BottomRow - 1, + InputErrorMessage + ); + InputError = TRUE; + } else { + gST->ConOut->SetAttribute (gST->ConOut, FIELD_TEXT_HIGHLIGHT); + for (Index = 0; Index < (GetStringWidth (InputErrorMessage) - 2) / 2; Index++) { + PrintAt (gScreenDimensions.LeftColumn + gPromptBlockWidth + Index, gScreenDimensions.BottomRow - 1, L" "); + } + + InputError = FALSE; + } + break; + + case NV_UPDATE_REQUIRED: + if (gClassOfVfr != EFI_FRONT_PAGE_SUBCLASS) { + if (State) { + gST->ConOut->SetAttribute (gST->ConOut, INFO_TEXT); + PrintStringAt ( + gScreenDimensions.LeftColumn + gPromptBlockWidth + gOptionBlockWidth, + gScreenDimensions.BottomRow - 1, + NvUpdateMessage + ); + gResetRequired = (BOOLEAN) (gResetRequired | ((Flags & EFI_IFR_FLAG_RESET_REQUIRED) == EFI_IFR_FLAG_RESET_REQUIRED)); + + gNvUpdateRequired = TRUE; + } else { + gST->ConOut->SetAttribute (gST->ConOut, FIELD_TEXT_HIGHLIGHT); + for (Index = 0; Index < (GetStringWidth (NvUpdateMessage) - 2) / 2; Index++) { + PrintAt ( + (gScreenDimensions.LeftColumn + gPromptBlockWidth + gOptionBlockWidth + Index), + gScreenDimensions.BottomRow - 1, + L" " + ); + } + + gNvUpdateRequired = FALSE; + } + } + break; + + case REFRESH_STATUS_BAR: + if (InputError) { + UpdateStatusBar (INPUT_ERROR, Flags, TRUE); + } + + if (gNvUpdateRequired) { + UpdateStatusBar (NV_UPDATE_REQUIRED, Flags, TRUE); + } + break; + + default: + break; + } + + gBS->FreePool (InputErrorMessage); + gBS->FreePool (NvUpdateMessage); + return ; +} + + +/** + Get the supported width for a particular op-code + + @param Statement The FORM_BROWSER_STATEMENT structure passed in. + @param Handle The handle in the HII database being used + + @return Returns the number of CHAR16 characters that is support. + +**/ +UINT16 +GetWidth ( + IN FORM_BROWSER_STATEMENT *Statement, + IN EFI_HII_HANDLE Handle + ) +{ + CHAR16 *String; + UINTN Size; + UINT16 Width; + + Size = 0; + + // + // See if the second text parameter is really NULL + // + if ((Statement->Operand == EFI_IFR_TEXT_OP) && (Statement->TextTwo != 0)) { + String = GetToken (Statement->TextTwo, Handle); + Size = StrLen (String); + gBS->FreePool (String); + } + + if ((Statement->Operand == EFI_IFR_SUBTITLE_OP) || + (Statement->Operand == EFI_IFR_REF_OP) || + (Statement->Operand == EFI_IFR_PASSWORD_OP) || + (Statement->Operand == EFI_IFR_ACTION_OP) || + (Statement->Operand == EFI_IFR_RESET_BUTTON_OP) || + // + // Allow a wide display if text op-code and no secondary text op-code + // + ((Statement->Operand == EFI_IFR_TEXT_OP) && (Size == 0)) + ) { + Width = (UINT16) (gPromptBlockWidth + gOptionBlockWidth); + } else { + Width = (UINT16) gPromptBlockWidth; + } + + if (Statement->InSubtitle) { + Width -= SUBTITLE_INDENT; + } + + return Width; +} + + +/** + Will copy LineWidth amount of a string in the OutputString buffer and return the + number of CHAR16 characters that were copied into the OutputString buffer. + + @param InputString String description for this option. + @param LineWidth Width of the desired string to extract in CHAR16 + characters + @param Index Where in InputString to start the copy process + @param OutputString Buffer to copy the string into + + @return Returns the number of CHAR16 characters that were copied into the OutputString buffer. + +**/ +UINT16 +GetLineByWidth ( + IN CHAR16 *InputString, + IN UINT16 LineWidth, + IN OUT UINTN *Index, + OUT CHAR16 **OutputString + ) +{ + static BOOLEAN Finished; + UINT16 Count; + UINT16 Count2; + + if (Finished) { + Finished = FALSE; + return (UINT16) 0; + } + + Count = LineWidth; + Count2 = 0; + + *OutputString = AllocateZeroPool (((UINTN) (LineWidth + 1) * 2)); + + // + // Ensure we have got a valid buffer + // + if (*OutputString != NULL) { + + // + //NARROW_CHAR can not be printed in screen, so if a line only contain the two CHARs: 'NARROW_CHAR + CHAR_CARRIAGE_RETURN' , it is a empty line in Screen. + //To avoid displaying this empty line in screen, just skip the two CHARs here. + // + if ((InputString[*Index] == NARROW_CHAR) && (InputString[*Index + 1] == CHAR_CARRIAGE_RETURN)) { + *Index = *Index + 2; + } + + // + // Fast-forward the string and see if there is a carriage-return in the string + // + for (; (InputString[*Index + Count2] != CHAR_CARRIAGE_RETURN) && (Count2 != LineWidth); Count2++) + ; + + // + // Copy the desired LineWidth of data to the output buffer. + // Also make sure that we don't copy more than the string. + // Also make sure that if there are linefeeds, we account for them. + // + if ((StrSize (&InputString[*Index]) <= ((UINTN) (LineWidth + 1) * 2)) && + (StrSize (&InputString[*Index]) <= ((UINTN) (Count2 + 1) * 2)) + ) { + // + // Convert to CHAR16 value and show that we are done with this operation + // + LineWidth = (UINT16) ((StrSize (&InputString[*Index]) - 2) / 2); + if (LineWidth != 0) { + Finished = TRUE; + } + } else { + if (Count2 == LineWidth) { + // + // Rewind the string from the maximum size until we see a space to break the line + // + for (; (InputString[*Index + LineWidth] != CHAR_SPACE) && (LineWidth != 0); LineWidth--) + ; + if (LineWidth == 0) { + LineWidth = Count; + } + } else { + LineWidth = Count2; + } + } + + CopyMem (*OutputString, &InputString[*Index], LineWidth * 2); + + // + // If currently pointing to a space, increment the index to the first non-space character + // + for (; + (InputString[*Index + LineWidth] == CHAR_SPACE) || (InputString[*Index + LineWidth] == CHAR_CARRIAGE_RETURN); + (*Index)++ + ) + ; + *Index = (UINT16) (*Index + LineWidth); + return LineWidth; + } else { + return (UINT16) 0; + } +} + + +/** + Update display lines for a Menu Option. + + @param MenuOption The MenuOption to be checked. + + @retval TRUE This Menu Option is selectable. + @retval FALSE This Menu Option could not be selected. + +**/ +VOID +UpdateOptionSkipLines ( + IN UI_MENU_SELECTION *Selection, + IN UI_MENU_OPTION *MenuOption, + IN CHAR16 **OptionalString, + IN UINTN SkipValue + ) +{ + UINTN Index; + UINT16 Width; + UINTN Row; + UINTN OriginalRow; + CHAR16 *OutputString; + CHAR16 *OptionString; + + Row = 0; + OptionString = *OptionalString; + OutputString = NULL; + + ProcessOptions (Selection, MenuOption, FALSE, &OptionString); + + if (OptionString != NULL) { + Width = (UINT16) gOptionBlockWidth; + + OriginalRow = Row; + + for (Index = 0; GetLineByWidth (OptionString, Width, &Index, &OutputString) != 0x0000;) { + // + // If there is more string to process print on the next row and increment the Skip value + // + if (StrLen (&OptionString[Index])) { + if (SkipValue == 0) { + Row++; + // + // Since the Number of lines for this menu entry may or may not be reflected accurately + // since the prompt might be 1 lines and option might be many, and vice versa, we need to do + // some testing to ensure we are keeping this in-sync. + // + // If the difference in rows is greater than or equal to the skip value, increase the skip value + // + if ((Row - OriginalRow) >= MenuOption->Skip) { + MenuOption->Skip++; + } + } + } + + gBS->FreePool (OutputString); + if (SkipValue != 0) { + SkipValue--; + } + } + + Row = OriginalRow; + } + + *OptionalString = OptionString; +} + + +/** + Check whether this Menu Option could be highlighted. + + @param MenuOption The MenuOption to be checked. + + @retval TRUE This Menu Option is selectable. + @retval FALSE This Menu Option could not be selected. + +**/ +STATIC +BOOLEAN +IsSelectable ( + UI_MENU_OPTION *MenuOption + ) +{ + if ((MenuOption->ThisTag->Operand == EFI_IFR_SUBTITLE_OP) || + MenuOption->GrayOut || MenuOption->ReadOnly) { + return FALSE; + } else { + return TRUE; + } +} + + +/** + Determine if the menu is the last menu that can be selected. + + @param Direction the scroll direction. False is down. True is up. + + @return FALSE -- the menu isn't the last menu that can be selected. + @return TRUE -- the menu is the last menu that can be selected. + +**/ +STATIC +BOOLEAN +ValueIsScroll ( + IN BOOLEAN Direction, + IN LIST_ENTRY *CurrentPos + ) +{ + LIST_ENTRY *Temp; + UI_MENU_OPTION *MenuOption; + + Temp = Direction ? CurrentPos->BackLink : CurrentPos->ForwardLink; + + if (Temp == &Menu) { + return TRUE; + } + + for (; Temp != &Menu; Temp = Direction ? Temp->BackLink : Temp->ForwardLink) { + MenuOption = MENU_OPTION_FROM_LINK (Temp); + if (IsSelectable (MenuOption)) { + return FALSE; + } + } + + return TRUE; +} + + +/** + Move to next selectable statement. + + @param GoUp The navigation direction. TRUE: up, FALSE: down. + @param CurrentPosition Current position. + + @return The row distance from current MenuOption to next selectable MenuOption. + +**/ +STATIC +INTN +MoveToNextStatement ( + IN BOOLEAN GoUp, + IN OUT LIST_ENTRY **CurrentPosition + ) +{ + INTN Distance; + LIST_ENTRY *Pos; + BOOLEAN HitEnd; + UI_MENU_OPTION *NextMenuOption; + + Distance = 0; + Pos = *CurrentPosition; + HitEnd = FALSE; + + while (TRUE) { + NextMenuOption = MENU_OPTION_FROM_LINK (Pos); + if (IsSelectable (NextMenuOption)) { + break; + } + if ((GoUp ? Pos->BackLink : Pos->ForwardLink) == &Menu) { + HitEnd = TRUE; + break; + } + Distance += NextMenuOption->Skip; + Pos = (GoUp ? Pos->BackLink : Pos->ForwardLink); + } + + if (HitEnd) { + // + // If we hit end there is still no statement can be focused, + // we go backwards to find the statement can be focused. + // + Distance = 0; + Pos = *CurrentPosition; + + while (TRUE) { + NextMenuOption = MENU_OPTION_FROM_LINK (Pos); + if (IsSelectable (NextMenuOption)) { + break; + } + if ((!GoUp ? Pos->BackLink : Pos->ForwardLink) == &Menu) { + ASSERT (FALSE); + break; + } + Distance -= NextMenuOption->Skip; + Pos = (!GoUp ? Pos->BackLink : Pos->ForwardLink); + } + } + + *CurrentPosition = &NextMenuOption->Link; + return Distance; +} + + +/** + Adjust Data and Time position accordingly. + Data format : [01/02/2004] [11:22:33] + Line number : 0 0 1 0 0 1 + + @param DirectionUp the up or down direction. False is down. True is + up. + @param CurrentPosition Current position. On return: Point to the last + Option (Year or Second) if up; Point to the first + Option (Month or Hour) if down. + + @return Return line number to pad. It is possible that we stand on a zero-advance + @return data or time opcode, so pad one line when we judge if we are going to scroll outside. + +**/ +STATIC +UINTN +AdjustDateAndTimePosition ( + IN BOOLEAN DirectionUp, + IN OUT LIST_ENTRY **CurrentPosition + ) +{ + UINTN Count; + LIST_ENTRY *NewPosition; + UI_MENU_OPTION *MenuOption; + UINTN PadLineNumber; + + PadLineNumber = 0; + NewPosition = *CurrentPosition; + MenuOption = MENU_OPTION_FROM_LINK (NewPosition); + + if ((MenuOption->ThisTag->Operand == EFI_IFR_DATE_OP) || + (MenuOption->ThisTag->Operand == EFI_IFR_TIME_OP)) { + // + // Calculate the distance from current position to the last Date/Time MenuOption + // + Count = 0; + while (MenuOption->Skip == 0) { + Count++; + NewPosition = NewPosition->ForwardLink; + MenuOption = MENU_OPTION_FROM_LINK (NewPosition); + PadLineNumber = 1; + } + + NewPosition = *CurrentPosition; + if (DirectionUp) { + // + // Since the behavior of hitting the up arrow on a Date/Time MenuOption is intended + // to be one that back to the previous set of MenuOptions, we need to advance to the first + // Date/Time MenuOption and leave the remaining logic in CfUiUp intact so the appropriate + // checking can be done. + // + while (Count++ < 2) { + NewPosition = NewPosition->BackLink; + } + } else { + // + // Since the behavior of hitting the down arrow on a Date/Time MenuOption is intended + // to be one that progresses to the next set of MenuOptions, we need to advance to the last + // Date/Time MenuOption and leave the remaining logic in CfUiDown intact so the appropriate + // checking can be done. + // + while (Count-- > 0) { + NewPosition = NewPosition->ForwardLink; + } + } + + *CurrentPosition = NewPosition; + } + + return PadLineNumber; +} + + +/** + Display menu and wait for user to select one menu option, then return it. + If AutoBoot is enabled, then if user doesn't select any option, + after period of time, it will automatically return the first menu option. + + + @return Return the pointer of the menu which selected, + @return otherwise return NULL. + +**/ +EFI_STATUS +UiDisplayMenu ( + IN OUT UI_MENU_SELECTION *Selection + ) +{ + INTN SkipValue; + INTN Difference; + INTN OldSkipValue; + UINTN DistanceValue; + UINTN Row; + UINTN Col; + UINTN Temp; + UINTN Temp2; + UINTN TopRow; + UINTN BottomRow; + UINTN OriginalRow; + UINTN Index; + UINT32 Count; + UINT16 Width; + CHAR16 *StringPtr; + CHAR16 *OptionString; + CHAR16 *OutputString; + CHAR16 *FormattedString; + CHAR16 YesResponse; + CHAR16 NoResponse; + BOOLEAN NewLine; + BOOLEAN Repaint; + BOOLEAN SavedValue; + EFI_STATUS Status; + EFI_INPUT_KEY Key; + LIST_ENTRY *Link; + LIST_ENTRY *NewPos; + LIST_ENTRY *TopOfScreen; + LIST_ENTRY *SavedListEntry; + UI_MENU_OPTION *MenuOption; + UI_MENU_OPTION *NextMenuOption; + UI_MENU_OPTION *SavedMenuOption; + UI_MENU_OPTION *PreviousMenuOption; + UI_CONTROL_FLAG ControlFlag; + EFI_SCREEN_DESCRIPTOR LocalScreen; + MENU_REFRESH_ENTRY *MenuRefreshEntry; + UI_SCREEN_OPERATION ScreenOperation; + UINT8 MinRefreshInterval; + UINTN BufferSize; + UINT16 DefaultId; + EFI_DEVICE_PATH_PROTOCOL *DevicePath; + FORM_BROWSER_STATEMENT *Statement; + + CopyMem (&LocalScreen, &gScreenDimensions, sizeof (EFI_SCREEN_DESCRIPTOR)); + + Status = EFI_SUCCESS; + FormattedString = NULL; + OptionString = NULL; + ScreenOperation = UiNoOperation; + NewLine = TRUE; + MinRefreshInterval = 0; + DefaultId = 0; + + OutputString = NULL; + gUpArrow = FALSE; + gDownArrow = FALSE; + SkipValue = 0; + OldSkipValue = 0; + MenuRefreshEntry = gMenuRefreshHead; + + NextMenuOption = NULL; + PreviousMenuOption = NULL; + SavedMenuOption = NULL; + + ZeroMem (&Key, sizeof (EFI_INPUT_KEY)); + + if (gClassOfVfr == EFI_FRONT_PAGE_SUBCLASS) { + TopRow = LocalScreen.TopRow + FRONT_PAGE_HEADER_HEIGHT + SCROLL_ARROW_HEIGHT; + Row = LocalScreen.TopRow + FRONT_PAGE_HEADER_HEIGHT + SCROLL_ARROW_HEIGHT; + } else { + TopRow = LocalScreen.TopRow + NONE_FRONT_PAGE_HEADER_HEIGHT + SCROLL_ARROW_HEIGHT; + Row = LocalScreen.TopRow + NONE_FRONT_PAGE_HEADER_HEIGHT + SCROLL_ARROW_HEIGHT; + } + + Col = LocalScreen.LeftColumn; + BottomRow = LocalScreen.BottomRow - STATUS_BAR_HEIGHT - FOOTER_HEIGHT - SCROLL_ARROW_HEIGHT - 1; + + Selection->TopRow = TopRow; + Selection->BottomRow = BottomRow; + Selection->PromptCol = Col; + Selection->OptionCol = gPromptBlockWidth + 1 + LocalScreen.LeftColumn; + Selection->Statement = NULL; + + TopOfScreen = Menu.ForwardLink; + Repaint = TRUE; + MenuOption = NULL; + + // + // Get user's selection + // + NewPos = Menu.ForwardLink; + + gST->ConOut->EnableCursor (gST->ConOut, FALSE); + UpdateStatusBar (REFRESH_STATUS_BAR, (UINT8) 0, TRUE); + + ControlFlag = CfInitialization; + Selection->Action = UI_ACTION_NONE; + while (TRUE) { + switch (ControlFlag) { + case CfInitialization: + if (IsListEmpty (&Menu)) { + ControlFlag = CfReadKey; + } else { + ControlFlag = CfCheckSelection; + } + break; + + case CfCheckSelection: + if (Selection->Action != UI_ACTION_NONE) { + ControlFlag = CfExit; + } else { + ControlFlag = CfRepaint; + } + break; + + case CfRepaint: + ControlFlag = CfRefreshHighLight; + + if (Repaint) { + // + // Display menu + // + gDownArrow = FALSE; + gUpArrow = FALSE; + Row = TopRow; + + Temp = SkipValue; + Temp2 = SkipValue; + + ClearLines ( + LocalScreen.LeftColumn, + LocalScreen.RightColumn, + TopRow - SCROLL_ARROW_HEIGHT, + BottomRow + SCROLL_ARROW_HEIGHT, + FIELD_TEXT | FIELD_BACKGROUND + ); + + UiFreeRefreshList (); + MinRefreshInterval = 0; + + for (Link = TopOfScreen; Link != &Menu; Link = Link->ForwardLink) { + MenuOption = MENU_OPTION_FROM_LINK (Link); + MenuOption->Row = Row; + MenuOption->Col = Col; + MenuOption->OptCol = gPromptBlockWidth + 1 + LocalScreen.LeftColumn; + + Statement = MenuOption->ThisTag; + if (Statement->InSubtitle) { + MenuOption->Col += SUBTITLE_INDENT; + } + + if (MenuOption->GrayOut) { + gST->ConOut->SetAttribute (gST->ConOut, FIELD_TEXT_GRAYED | FIELD_BACKGROUND); + } else { + if (Statement->Operand == EFI_IFR_SUBTITLE_OP) { + gST->ConOut->SetAttribute (gST->ConOut, SUBTITLE_TEXT | FIELD_BACKGROUND); + } + } + + Width = GetWidth (Statement, MenuOption->Handle); + OriginalRow = Row; + + for (Index = 0; GetLineByWidth (MenuOption->Description, Width, &Index, &OutputString) != 0x0000;) { + if ((Temp == 0) && (Row <= BottomRow)) { + PrintStringAt (MenuOption->Col, Row, OutputString); + } + // + // If there is more string to process print on the next row and increment the Skip value + // + if (StrLen (&MenuOption->Description[Index])) { + if (Temp == 0) { + Row++; + } + } + + gBS->FreePool (OutputString); + if (Temp != 0) { + Temp--; + } + } + + Temp = 0; + Row = OriginalRow; + + gST->ConOut->SetAttribute (gST->ConOut, FIELD_TEXT | FIELD_BACKGROUND); + ProcessOptions (Selection, MenuOption, FALSE, &OptionString); + + if (OptionString != NULL) { + if (Statement->Operand == EFI_IFR_DATE_OP || Statement->Operand == EFI_IFR_TIME_OP) { + // + // If leading spaces on OptionString - remove the spaces + // + for (Index = 0; OptionString[Index] == L' '; Index++) { + MenuOption->OptCol++; + } + + for (Count = 0; OptionString[Index] != CHAR_NULL; Index++) { + OptionString[Count] = OptionString[Index]; + Count++; + } + + OptionString[Count] = CHAR_NULL; + } + + // + // If Question request refresh, register the op-code + // + if (Statement->RefreshInterval != 0) { + // + // Menu will be refreshed at minimal interval of all Questions + // which have refresh request + // + if (MinRefreshInterval == 0 || Statement->RefreshInterval < MinRefreshInterval) { + MinRefreshInterval = Statement->RefreshInterval; + } + + if (gMenuRefreshHead == NULL) { + MenuRefreshEntry = AllocateZeroPool (sizeof (MENU_REFRESH_ENTRY)); + ASSERT (MenuRefreshEntry != NULL); + MenuRefreshEntry->MenuOption = MenuOption; + MenuRefreshEntry->Selection = Selection; + MenuRefreshEntry->CurrentColumn = MenuOption->OptCol; + MenuRefreshEntry->CurrentRow = MenuOption->Row; + MenuRefreshEntry->CurrentAttribute = FIELD_TEXT | FIELD_BACKGROUND; + gMenuRefreshHead = MenuRefreshEntry; + } else { + // + // Advance to the last entry + // + for (MenuRefreshEntry = gMenuRefreshHead; + MenuRefreshEntry->Next != NULL; + MenuRefreshEntry = MenuRefreshEntry->Next + ) + ; + MenuRefreshEntry->Next = AllocateZeroPool (sizeof (MENU_REFRESH_ENTRY)); + ASSERT (MenuRefreshEntry->Next != NULL); + MenuRefreshEntry = MenuRefreshEntry->Next; + MenuRefreshEntry->MenuOption = MenuOption; + MenuRefreshEntry->Selection = Selection; + MenuRefreshEntry->CurrentColumn = MenuOption->OptCol; + MenuRefreshEntry->CurrentRow = MenuOption->Row; + MenuRefreshEntry->CurrentAttribute = FIELD_TEXT | FIELD_BACKGROUND; + } + } + + Width = (UINT16) gOptionBlockWidth; + OriginalRow = Row; + + for (Index = 0; GetLineByWidth (OptionString, Width, &Index, &OutputString) != 0x0000;) { + if ((Temp2 == 0) && (Row <= BottomRow)) { + PrintStringAt (MenuOption->OptCol, Row, OutputString); + } + // + // If there is more string to process print on the next row and increment the Skip value + // + if (StrLen (&OptionString[Index])) { + if (Temp2 == 0) { + Row++; + // + // Since the Number of lines for this menu entry may or may not be reflected accurately + // since the prompt might be 1 lines and option might be many, and vice versa, we need to do + // some testing to ensure we are keeping this in-sync. + // + // If the difference in rows is greater than or equal to the skip value, increase the skip value + // + if ((Row - OriginalRow) >= MenuOption->Skip) { + MenuOption->Skip++; + } + } + } + + gBS->FreePool (OutputString); + if (Temp2 != 0) { + Temp2--; + } + } + + Temp2 = 0; + Row = OriginalRow; + + gBS->FreePool (OptionString); + } + // + // If this is a text op with secondary text information + // + if ((Statement->Operand == EFI_IFR_TEXT_OP) && (Statement->TextTwo != 0)) { + StringPtr = GetToken (Statement->TextTwo, MenuOption->Handle); + + Width = (UINT16) gOptionBlockWidth; + OriginalRow = Row; + + for (Index = 0; GetLineByWidth (StringPtr, Width, &Index, &OutputString) != 0x0000;) { + if ((Temp == 0) && (Row <= BottomRow)) { + PrintStringAt (MenuOption->OptCol, Row, OutputString); + } + // + // If there is more string to process print on the next row and increment the Skip value + // + if (StrLen (&StringPtr[Index])) { + if (Temp2 == 0) { + Row++; + // + // Since the Number of lines for this menu entry may or may not be reflected accurately + // since the prompt might be 1 lines and option might be many, and vice versa, we need to do + // some testing to ensure we are keeping this in-sync. + // + // If the difference in rows is greater than or equal to the skip value, increase the skip value + // + if ((Row - OriginalRow) >= MenuOption->Skip) { + MenuOption->Skip++; + } + } + } + + gBS->FreePool (OutputString); + if (Temp2 != 0) { + Temp2--; + } + } + + Row = OriginalRow; + gBS->FreePool (StringPtr); + } + + // + // Need to handle the bottom of the display + // + if (MenuOption->Skip > 1) { + Row += MenuOption->Skip - SkipValue; + SkipValue = 0; + } else { + Row += MenuOption->Skip; + } + + if (Row > BottomRow) { + if (!ValueIsScroll (FALSE, Link)) { + gDownArrow = TRUE; + } + + Row = BottomRow + 1; + break; + } + } + + if (!ValueIsScroll (TRUE, TopOfScreen)) { + gUpArrow = TRUE; + } + + if (gUpArrow) { + gST->ConOut->SetAttribute (gST->ConOut, ARROW_TEXT | ARROW_BACKGROUND); + PrintAt ( + LocalScreen.LeftColumn + gPromptBlockWidth + gOptionBlockWidth + 1, + TopRow - SCROLL_ARROW_HEIGHT, + L"%c", + ARROW_UP + ); + gST->ConOut->SetAttribute (gST->ConOut, FIELD_TEXT | FIELD_BACKGROUND); + } + + if (gDownArrow) { + gST->ConOut->SetAttribute (gST->ConOut, ARROW_TEXT | ARROW_BACKGROUND); + PrintAt ( + LocalScreen.LeftColumn + gPromptBlockWidth + gOptionBlockWidth + 1, + BottomRow + SCROLL_ARROW_HEIGHT, + L"%c", + ARROW_DOWN + ); + gST->ConOut->SetAttribute (gST->ConOut, FIELD_TEXT | FIELD_BACKGROUND); + } + + MenuOption = NULL; + } + break; + + case CfRefreshHighLight: + // + // MenuOption: Last menu option that need to remove hilight + // MenuOption is set to NULL in Repaint + // NewPos: Current menu option that need to hilight + // + ControlFlag = CfUpdateHelpString; + + // + // Repaint flag is normally reset when finish processing CfUpdateHelpString. Temporarily + // reset Repaint flag because we may break halfway and skip CfUpdateHelpString processing. + // + SavedValue = Repaint; + Repaint = FALSE; + + if (Selection->QuestionId != 0) { + NewPos = Menu.ForwardLink; + SavedMenuOption = MENU_OPTION_FROM_LINK (NewPos); + + while (SavedMenuOption->ThisTag->QuestionId != Selection->QuestionId && NewPos->ForwardLink != &Menu) { + NewPos = NewPos->ForwardLink; + SavedMenuOption = MENU_OPTION_FROM_LINK (NewPos); + } + if (SavedMenuOption->ThisTag->QuestionId == Selection->QuestionId) { + // + // Target Question found, find its MenuOption + // + Link = TopOfScreen; + + for (Index = TopRow; Index <= BottomRow && Link != NewPos;) { + SavedMenuOption = MENU_OPTION_FROM_LINK (Link); + Index += SavedMenuOption->Skip; + Link = Link->ForwardLink; + } + + if (Link != NewPos || Index > BottomRow) { + // + // NewPos is not in the current page, simply scroll page so that NewPos is in the end of the page + // + Link = NewPos; + for (Index = TopRow; Index <= BottomRow; ) { + Link = Link->BackLink; + SavedMenuOption = MENU_OPTION_FROM_LINK (Link); + Index += SavedMenuOption->Skip; + } + TopOfScreen = Link->ForwardLink; + + Repaint = TRUE; + NewLine = TRUE; + ControlFlag = CfRepaint; + break; + } + } else { + // + // Target Question not found, highlight the default menu option + // + NewPos = TopOfScreen; + } + + Selection->QuestionId = 0; + } + + if (NewPos != NULL && (MenuOption == NULL || NewPos != &MenuOption->Link)) { + if (MenuOption != NULL) { + // + // Remove highlight on last Menu Option + // + gST->ConOut->SetCursorPosition (gST->ConOut, MenuOption->Col, MenuOption->Row); + ProcessOptions (Selection, MenuOption, FALSE, &OptionString); + gST->ConOut->SetAttribute (gST->ConOut, FIELD_TEXT | FIELD_BACKGROUND); + if (OptionString != NULL) { + if ((MenuOption->ThisTag->Operand == EFI_IFR_DATE_OP) || + (MenuOption->ThisTag->Operand == EFI_IFR_TIME_OP) + ) { + // + // If leading spaces on OptionString - remove the spaces + // + for (Index = 0; OptionString[Index] == L' '; Index++) + ; + + for (Count = 0; OptionString[Index] != CHAR_NULL; Index++) { + OptionString[Count] = OptionString[Index]; + Count++; + } + + OptionString[Count] = CHAR_NULL; + } + + Width = (UINT16) gOptionBlockWidth; + OriginalRow = MenuOption->Row; + + for (Index = 0; GetLineByWidth (OptionString, Width, &Index, &OutputString) != 0x0000;) { + if (MenuOption->Row >= TopRow && MenuOption->Row <= BottomRow) { + PrintStringAt (MenuOption->OptCol, MenuOption->Row, OutputString); + } + // + // If there is more string to process print on the next row and increment the Skip value + // + if (StrLen (&OptionString[Index])) { + MenuOption->Row++; + } + + gBS->FreePool (OutputString); + } + + MenuOption->Row = OriginalRow; + + gBS->FreePool (OptionString); + } else { + if (NewLine) { + if (MenuOption->GrayOut) { + gST->ConOut->SetAttribute (gST->ConOut, FIELD_TEXT_GRAYED | FIELD_BACKGROUND); + } else if (MenuOption->ThisTag->Operand == EFI_IFR_SUBTITLE_OP) { + gST->ConOut->SetAttribute (gST->ConOut, SUBTITLE_TEXT | FIELD_BACKGROUND); + } + + OriginalRow = MenuOption->Row; + Width = GetWidth (MenuOption->ThisTag, MenuOption->Handle); + + for (Index = 0; GetLineByWidth (MenuOption->Description, Width, &Index, &OutputString) != 0x0000;) { + if (MenuOption->Row >= TopRow && MenuOption->Row <= BottomRow) { + PrintStringAt (MenuOption->Col, MenuOption->Row, OutputString); + } + // + // If there is more string to process print on the next row and increment the Skip value + // + if (StrLen (&MenuOption->Description[Index])) { + MenuOption->Row++; + } + + gBS->FreePool (OutputString); + } + + MenuOption->Row = OriginalRow; + gST->ConOut->SetAttribute (gST->ConOut, FIELD_TEXT | FIELD_BACKGROUND); + } + } + } + + // + // This is only possible if we entered this page and the first menu option is + // a "non-menu" item. In that case, force it UiDown + // + MenuOption = MENU_OPTION_FROM_LINK (NewPos); + if (!IsSelectable (MenuOption)) { + ASSERT (ScreenOperation == UiNoOperation); + ScreenOperation = UiDown; + ControlFlag = CfScreenOperation; + break; + } + + // + // This is the current selected statement + // + Statement = MenuOption->ThisTag; + Selection->Statement = Statement; + + // + // Set reverse attribute + // + gST->ConOut->SetAttribute (gST->ConOut, FIELD_TEXT_HIGHLIGHT | FIELD_BACKGROUND_HIGHLIGHT); + gST->ConOut->SetCursorPosition (gST->ConOut, MenuOption->Col, MenuOption->Row); + + // + // Assuming that we have a refresh linked-list created, lets annotate the + // appropriate entry that we are highlighting with its new attribute. Just prior to this + // lets reset all of the entries' attribute so we do not get multiple highlights in he refresh + // + if (gMenuRefreshHead != NULL) { + for (MenuRefreshEntry = gMenuRefreshHead; MenuRefreshEntry != NULL; MenuRefreshEntry = MenuRefreshEntry->Next) { + MenuRefreshEntry->CurrentAttribute = FIELD_TEXT | FIELD_BACKGROUND; + if (MenuRefreshEntry->MenuOption == MenuOption) { + MenuRefreshEntry->CurrentAttribute = FIELD_TEXT_HIGHLIGHT | FIELD_BACKGROUND_HIGHLIGHT; + } + } + } + + ProcessOptions (Selection, MenuOption, FALSE, &OptionString); + if (OptionString != NULL) { + if (Statement->Operand == EFI_IFR_DATE_OP || Statement->Operand == EFI_IFR_TIME_OP) { + // + // If leading spaces on OptionString - remove the spaces + // + for (Index = 0; OptionString[Index] == L' '; Index++) + ; + + for (Count = 0; OptionString[Index] != CHAR_NULL; Index++) { + OptionString[Count] = OptionString[Index]; + Count++; + } + + OptionString[Count] = CHAR_NULL; + } + Width = (UINT16) gOptionBlockWidth; + + OriginalRow = MenuOption->Row; + + for (Index = 0; GetLineByWidth (OptionString, Width, &Index, &OutputString) != 0x0000;) { + if (MenuOption->Row >= TopRow && MenuOption->Row <= BottomRow) { + PrintStringAt (MenuOption->OptCol, MenuOption->Row, OutputString); + } + // + // If there is more string to process print on the next row and increment the Skip value + // + if (StrLen (&OptionString[Index])) { + MenuOption->Row++; + } + + gBS->FreePool (OutputString); + } + + MenuOption->Row = OriginalRow; + + gBS->FreePool (OptionString); + } else { + if (NewLine) { + OriginalRow = MenuOption->Row; + + Width = GetWidth (Statement, MenuOption->Handle); + + for (Index = 0; GetLineByWidth (MenuOption->Description, Width, &Index, &OutputString) != 0x0000;) { + if (MenuOption->Row >= TopRow && MenuOption->Row <= BottomRow) { + PrintStringAt (MenuOption->Col, MenuOption->Row, OutputString); + } + // + // If there is more string to process print on the next row and increment the Skip value + // + if (StrLen (&MenuOption->Description[Index])) { + MenuOption->Row++; + } + + gBS->FreePool (OutputString); + } + + MenuOption->Row = OriginalRow; + + } + } + + if (((NewPos->ForwardLink != &Menu) && (ScreenOperation == UiDown)) || + ((NewPos->BackLink != &Menu) && (ScreenOperation == UiUp)) || + (ScreenOperation == UiNoOperation) + ) { + UpdateKeyHelp (MenuOption, FALSE); + } + // + // Clear reverse attribute + // + gST->ConOut->SetAttribute (gST->ConOut, FIELD_TEXT | FIELD_BACKGROUND); + } + // + // Repaint flag will be used when process CfUpdateHelpString, so restore its value + // if we didn't break halfway when process CfRefreshHighLight. + // + Repaint = SavedValue; + break; + + case CfUpdateHelpString: + ControlFlag = CfPrepareToReadKey; + + if ((Repaint || NewLine) && (gClassOfVfr != EFI_GENERAL_APPLICATION_SUBCLASS)) { + // + // Don't print anything if it is a NULL help token + // + if (MenuOption->ThisTag->Help == 0) { + StringPtr = L"\0"; + } else { + StringPtr = GetToken (MenuOption->ThisTag->Help, MenuOption->Handle); + } + + ProcessHelpString (StringPtr, &FormattedString, BottomRow - TopRow); + + gST->ConOut->SetAttribute (gST->ConOut, HELP_TEXT | FIELD_BACKGROUND); + + for (Index = 0; Index < BottomRow - TopRow; Index++) { + // + // Pad String with spaces to simulate a clearing of the previous line + // + for (; GetStringWidth (&FormattedString[Index * gHelpBlockWidth * 2]) / 2 < gHelpBlockWidth;) { + StrCat (&FormattedString[Index * gHelpBlockWidth * 2], L" "); + } + + PrintStringAt ( + LocalScreen.RightColumn - gHelpBlockWidth, + Index + TopRow, + &FormattedString[Index * gHelpBlockWidth * 2] + ); + } + } + // + // Reset this flag every time we finish using it. + // + Repaint = FALSE; + NewLine = FALSE; + break; + + case CfPrepareToReadKey: + ControlFlag = CfReadKey; + ScreenOperation = UiNoOperation; + break; + + case CfReadKey: + ControlFlag = CfScreenOperation; + + // + // Wait for user's selection + // + do { + Status = UiWaitForSingleEvent (gST->ConIn->WaitForKey, 0, MinRefreshInterval); + } while (Status == EFI_TIMEOUT); + + if (Status == EFI_TIMEOUT) { + Key.UnicodeChar = CHAR_CARRIAGE_RETURN; + } else { + Status = gST->ConIn->ReadKeyStroke (gST->ConIn, &Key); + // + // if we encounter error, continue to read another key in. + // + if (EFI_ERROR (Status)) { + ControlFlag = CfReadKey; + continue; + } + } + + if (IsListEmpty (&Menu) && Key.UnicodeChar != CHAR_NULL) { + // + // If the screen has no menu items, and the user didn't select UiPrevious, or UiReset + // + break; + } + + switch (Key.UnicodeChar) { + case CHAR_CARRIAGE_RETURN: + ScreenOperation = UiSelect; + gDirection = 0; + break; + + // + // We will push the adjustment of these numeric values directly to the input handler + // NOTE: we won't handle manual input numeric + // + case '+': + case '-': + Statement = MenuOption->ThisTag; + if ((Statement->Operand == EFI_IFR_DATE_OP) + || (Statement->Operand == EFI_IFR_TIME_OP) + || ((Statement->Operand == EFI_IFR_NUMERIC_OP) && (Statement->Step != 0)) + ){ + if (Key.UnicodeChar == '+') { + gDirection = SCAN_RIGHT; + } else { + gDirection = SCAN_LEFT; + } + Status = ProcessOptions (Selection, MenuOption, TRUE, &OptionString); + SafeFreePool (OptionString); + } + break; + + case '^': + ScreenOperation = UiUp; + break; + + case 'V': + case 'v': + ScreenOperation = UiDown; + break; + + case ' ': + if (gClassOfVfr != EFI_FRONT_PAGE_SUBCLASS) { + if (MenuOption->ThisTag->Operand == EFI_IFR_CHECKBOX_OP && !MenuOption->GrayOut) { + ScreenOperation = UiSelect; + } + } + break; + + case CHAR_NULL: + if (((Key.ScanCode == SCAN_F1) && ((gFunctionKeySetting & FUNCTION_ONE) != FUNCTION_ONE)) || + ((Key.ScanCode == SCAN_F2) && ((gFunctionKeySetting & FUNCTION_TWO) != FUNCTION_TWO)) || + ((Key.ScanCode == SCAN_F9) && ((gFunctionKeySetting & FUNCTION_NINE) != FUNCTION_NINE)) || + ((Key.ScanCode == SCAN_F10) && ((gFunctionKeySetting & FUNCTION_TEN) != FUNCTION_TEN)) + ) { + // + // If the function key has been disabled, just ignore the key. + // + } else { + for (Index = 0; Index < sizeof (gScanCodeToOperation) / sizeof (gScanCodeToOperation[0]); Index++) { + if (Key.ScanCode == gScanCodeToOperation[Index].ScanCode) { + if (Key.ScanCode == SCAN_F9) { + // + // Reset to standard default + // + DefaultId = EFI_HII_DEFAULT_CLASS_STANDARD; + } + ScreenOperation = gScanCodeToOperation[Index].ScreenOperation; + break; + } + } + } + break; + } + break; + + case CfScreenOperation: + if (ScreenOperation != UiPrevious && ScreenOperation != UiReset) { + // + // If the screen has no menu items, and the user didn't select UiPrevious, or UiReset + // ignore the selection and go back to reading keys. + // + if (IsListEmpty (&Menu)) { + ControlFlag = CfReadKey; + break; + } + // + // if there is nothing logical to place a cursor on, just move on to wait for a key. + // + for (Link = Menu.ForwardLink; Link != &Menu; Link = Link->ForwardLink) { + NextMenuOption = MENU_OPTION_FROM_LINK (Link); + if (IsSelectable (NextMenuOption)) { + break; + } + } + + if (Link == &Menu) { + ControlFlag = CfPrepareToReadKey; + break; + } + } else if (ScreenOperation == UiReset) { + // + // Press ESC to exit FormSet + // + Selection->Action = UI_ACTION_EXIT; + Selection->Statement = NULL; + } + + for (Index = 0; + Index < sizeof (gScreenOperationToControlFlag) / sizeof (gScreenOperationToControlFlag[0]); + Index++ + ) { + if (ScreenOperation == gScreenOperationToControlFlag[Index].ScreenOperation) { + ControlFlag = gScreenOperationToControlFlag[Index].ControlFlag; + break; + } + } + break; + + case CfUiPrevious: + ControlFlag = CfCheckSelection; + + if (IsListEmpty (&gMenuList)) { + Selection->Action = UI_ACTION_NONE; + if (IsListEmpty (&Menu)) { + ControlFlag = CfReadKey; + } + break; + } + + // + // Remove the Cached page entry + // + UiRemoveMenuListEntry (Selection); + + Selection->Action = UI_ACTION_REFRESH_FORM; + Selection->Statement = NULL; + break; + + case CfUiSelect: + ControlFlag = CfCheckSelection; + + Statement = MenuOption->ThisTag; + if ((Statement->Operand == EFI_IFR_TEXT_OP) || + (Statement->Operand == EFI_IFR_DATE_OP) || + (Statement->Operand == EFI_IFR_TIME_OP) || + (Statement->Operand == EFI_IFR_NUMERIC_OP && Statement->Step != 0)) { + break; + } + + // + // Keep highlight on current MenuOption + // + Selection->QuestionId = Statement->QuestionId; + + switch (Statement->Operand) { + case EFI_IFR_REF_OP: + if (Statement->RefDevicePath != 0) { + // + // Goto another Hii Package list + // + ControlFlag = CfUiReset; + Selection->Action = UI_ACTION_REFRESH_FORMSET; + + StringPtr = GetToken (Statement->RefDevicePath, Selection->FormSet->HiiHandle); + if (StringPtr == NULL) { + // + // No device path string not found, exit + // + Selection->Action = UI_ACTION_EXIT; + Selection->Statement = NULL; + break; + } + BufferSize = StrLen (StringPtr) / 4; + DevicePath = AllocatePool (BufferSize); + + HexStringToBuffer ((UINT8 *) DevicePath, &BufferSize, StringPtr); + Selection->Handle = DevicePathToHiiHandle (mHiiDatabase, DevicePath); + if (Selection->Handle == NULL) { + // + // If target Hii Handle not found, exit + // + Selection->Action = UI_ACTION_EXIT; + Selection->Statement = NULL; + break; + } + + gBS->FreePool (StringPtr); + gBS->FreePool (DevicePath); + + CopyMem (&Selection->FormSetGuid, &Statement->RefFormSetId, sizeof (EFI_GUID)); + Selection->FormId = Statement->RefFormId; + Selection->QuestionId = Statement->RefQuestionId; + } else if (!CompareGuid (&Statement->RefFormSetId, &gZeroGuid)) { + // + // Goto another Formset, check for uncommitted data + // + ControlFlag = CfUiReset; + Selection->Action = UI_ACTION_REFRESH_FORMSET; + + CopyMem (&Selection->FormSetGuid, &Statement->RefFormSetId, sizeof (EFI_GUID)); + Selection->FormId = Statement->RefFormId; + Selection->QuestionId = Statement->RefQuestionId; + } else if (Statement->RefFormId != 0) { + // + // Goto another form inside this formset, + // + Selection->Action = UI_ACTION_REFRESH_FORM; + + // + // Link current form so that we can always go back when someone hits the UiPrevious + // + UiAddMenuListEntry (Selection); + + Selection->FormId = Statement->RefFormId; + Selection->QuestionId = Statement->RefQuestionId; + } else if (Statement->RefQuestionId != 0) { + // + // Goto another Question + // + Selection->QuestionId = Statement->RefQuestionId; + + if ((Statement->QuestionFlags & EFI_IFR_FLAG_CALLBACK)) { + Selection->Action = UI_ACTION_REFRESH_FORM; + } else { + Repaint = TRUE; + NewLine = TRUE; + break; + } + } + break; + + case EFI_IFR_ACTION_OP: + // + // Process the Config string <ConfigResp> + // + Status = ProcessQuestionConfig (Selection, Statement); + + if (EFI_ERROR (Status)) { + break; + } + + // + // The action button may change some Question value, so refresh the form + // + Selection->Action = UI_ACTION_REFRESH_FORM; + break; + + case EFI_IFR_RESET_BUTTON_OP: + // + // Reset Question to default value specified by DefaultId + // + ControlFlag = CfUiDefault; + DefaultId = Statement->DefaultId; + break; + + default: + // + // Editable Questions: oneof, ordered list, checkbox, numeric, string, password + // + UpdateKeyHelp (MenuOption, TRUE); + Status = ProcessOptions (Selection, MenuOption, TRUE, &OptionString); + + if (EFI_ERROR (Status)) { + Repaint = TRUE; + NewLine = TRUE; + break; + } + + if (OptionString != NULL) { + PrintStringAt (LocalScreen.LeftColumn + gPromptBlockWidth + 1, MenuOption->Row, OptionString); + gBS->FreePool (OptionString); + } + + Selection->Action = UI_ACTION_REFRESH_FORM; + break; + } + break; + + case CfUiReset: + // + // We are going to leave current FormSet, so check uncommited data in this FormSet + // + ControlFlag = CfCheckSelection; + + if (gClassOfVfr == EFI_FRONT_PAGE_SUBCLASS) { + // + // There is no parent menu for FrontPage + // + Selection->Action = UI_ACTION_NONE; + Selection->Statement = MenuOption->ThisTag; + break; + } + + // + // If NV flag is up, prompt user + // + if (gNvUpdateRequired) { + Status = gST->ConIn->ReadKeyStroke (gST->ConIn, &Key); + + YesResponse = gYesResponse[0]; + NoResponse = gNoResponse[0]; + + do { + CreateDialog (3, TRUE, 0, NULL, &Key, gEmptyString, gAreYouSure, gEmptyString); + } while + ( + (Key.ScanCode != SCAN_ESC) && + ((Key.UnicodeChar | UPPER_LOWER_CASE_OFFSET) != (NoResponse | UPPER_LOWER_CASE_OFFSET)) && + ((Key.UnicodeChar | UPPER_LOWER_CASE_OFFSET) != (YesResponse | UPPER_LOWER_CASE_OFFSET)) + ); + + // + // If the user hits the YesResponse key + // + if ((Key.UnicodeChar | UPPER_LOWER_CASE_OFFSET) == (YesResponse | UPPER_LOWER_CASE_OFFSET)) { + } else { + Repaint = TRUE; + NewLine = TRUE; + + Selection->Action = UI_ACTION_NONE; + break; + } + } + + gST->ConOut->SetAttribute (gST->ConOut, EFI_TEXT_ATTR (EFI_LIGHTGRAY, EFI_BLACK)); + gST->ConOut->EnableCursor (gST->ConOut, TRUE); + + UiFreeMenuList (); + gST->ConOut->ClearScreen (gST->ConOut); + return EFI_SUCCESS; + + case CfUiLeft: + ControlFlag = CfCheckSelection; + if ((MenuOption->ThisTag->Operand == EFI_IFR_DATE_OP) || (MenuOption->ThisTag->Operand == EFI_IFR_TIME_OP)) { + if (MenuOption->Sequence != 0) { + // + // In the middle or tail of the Date/Time op-code set, go left. + // + NewPos = NewPos->BackLink; + } + } + break; + + case CfUiRight: + ControlFlag = CfCheckSelection; + if ((MenuOption->ThisTag->Operand == EFI_IFR_DATE_OP) || (MenuOption->ThisTag->Operand == EFI_IFR_TIME_OP)) { + if (MenuOption->Sequence != 2) { + // + // In the middle or tail of the Date/Time op-code set, go left. + // + NewPos = NewPos->ForwardLink; + } + } + break; + + case CfUiUp: + ControlFlag = CfCheckSelection; + + SavedListEntry = TopOfScreen; + + if (NewPos->BackLink != &Menu) { + NewLine = TRUE; + // + // Adjust Date/Time position before we advance forward. + // + AdjustDateAndTimePosition (TRUE, &NewPos); + + // + // Caution that we have already rewind to the top, don't go backward in this situation. + // + if (NewPos->BackLink != &Menu) { + NewPos = NewPos->BackLink; + } + + PreviousMenuOption = MENU_OPTION_FROM_LINK (NewPos); + DistanceValue = PreviousMenuOption->Skip; + + // + // Since the behavior of hitting the up arrow on a Date/Time op-code is intended + // to be one that back to the previous set of op-codes, we need to advance to the sencond + // Date/Time op-code and leave the remaining logic in UiDown intact so the appropriate + // checking can be done. + // + DistanceValue += AdjustDateAndTimePosition (TRUE, &NewPos); + + // + // Check the previous menu entry to see if it was a zero-length advance. If it was, + // don't worry about a redraw. + // + if ((INTN) MenuOption->Row - (INTN) DistanceValue < (INTN) TopRow) { + Repaint = TRUE; + TopOfScreen = NewPos; + } + + Difference = MoveToNextStatement (TRUE, &NewPos); + if ((INTN) MenuOption->Row - (INTN) DistanceValue < (INTN) TopRow) { + if (Difference > 0) { + // + // Previous focus MenuOption is above the TopOfScreen, so we need to scroll + // + TopOfScreen = NewPos; + Repaint = TRUE; + } + } + if (Difference < 0) { + // + // We want to goto previous MenuOption, but finally we go down. + // it means that we hit the begining MenuOption that can be focused + // so we simply scroll to the top + // + if (SavedListEntry != Menu.ForwardLink) { + TopOfScreen = Menu.ForwardLink; + Repaint = TRUE; + } + } + + // + // If we encounter a Date/Time op-code set, rewind to the first op-code of the set. + // + AdjustDateAndTimePosition (TRUE, &TopOfScreen); + + UpdateStatusBar (INPUT_ERROR, MenuOption->ThisTag->QuestionFlags, FALSE); + } else { + SavedMenuOption = MenuOption; + MenuOption = MENU_OPTION_FROM_LINK (NewPos); + if (!IsSelectable (MenuOption)) { + // + // If we are at the end of the list and sitting on a text op, we need to more forward + // + ScreenOperation = UiDown; + ControlFlag = CfScreenOperation; + break; + } + + MenuOption = SavedMenuOption; + } + break; + + case CfUiPageUp: + ControlFlag = CfCheckSelection; + + if (NewPos->BackLink == &Menu) { + NewLine = FALSE; + Repaint = FALSE; + break; + } + + NewLine = TRUE; + Repaint = TRUE; + Link = TopOfScreen; + PreviousMenuOption = MENU_OPTION_FROM_LINK (Link); + Index = BottomRow; + while ((Index >= TopRow) && (Link->BackLink != &Menu)) { + Index = Index - PreviousMenuOption->Skip; + Link = Link->BackLink; + PreviousMenuOption = MENU_OPTION_FROM_LINK (Link); + } + + TopOfScreen = Link; + Difference = MoveToNextStatement (TRUE, &Link); + if (Difference > 0) { + // + // The focus MenuOption is above the TopOfScreen + // + TopOfScreen = Link; + } else if (Difference < 0) { + // + // This happens when there is no MenuOption can be focused from + // Current MenuOption to the first MenuOption + // + TopOfScreen = Menu.ForwardLink; + } + Index += Difference; + if (Index < TopRow) { + MenuOption = NULL; + } + + if (NewPos == Link) { + Repaint = FALSE; + NewLine = FALSE; + } else { + NewPos = Link; + } + + // + // If we encounter a Date/Time op-code set, rewind to the first op-code of the set. + // Don't do this when we are already in the first page. + // + AdjustDateAndTimePosition (TRUE, &TopOfScreen); + AdjustDateAndTimePosition (TRUE, &NewPos); + break; + + case CfUiPageDown: + ControlFlag = CfCheckSelection; + + if (NewPos->ForwardLink == &Menu) { + NewLine = FALSE; + Repaint = FALSE; + break; + } + + NewLine = TRUE; + Repaint = TRUE; + Link = TopOfScreen; + NextMenuOption = MENU_OPTION_FROM_LINK (Link); + Index = TopRow; + while ((Index <= BottomRow) && (Link->ForwardLink != &Menu)) { + Index = Index + NextMenuOption->Skip; + Link = Link->ForwardLink; + NextMenuOption = MENU_OPTION_FROM_LINK (Link); + } + + Index += MoveToNextStatement (FALSE, &Link); + if (Index > BottomRow) { + // + // There are more MenuOption needing scrolling + // + TopOfScreen = Link; + MenuOption = NULL; + } + if (NewPos == Link && Index <= BottomRow) { + // + // Finally we know that NewPos is the last MenuOption can be focused. + // + NewLine = FALSE; + Repaint = FALSE; + } else { + NewPos = Link; + } + + // + // If we encounter a Date/Time op-code set, rewind to the first op-code of the set. + // Don't do this when we are already in the last page. + // + AdjustDateAndTimePosition (TRUE, &TopOfScreen); + AdjustDateAndTimePosition (TRUE, &NewPos); + break; + + case CfUiDown: + ControlFlag = CfCheckSelection; + // + // Since the behavior of hitting the down arrow on a Date/Time op-code is intended + // to be one that progresses to the next set of op-codes, we need to advance to the last + // Date/Time op-code and leave the remaining logic in UiDown intact so the appropriate + // checking can be done. The only other logic we need to introduce is that if a Date/Time + // op-code is the last entry in the menu, we need to rewind back to the first op-code of + // the Date/Time op-code. + // + SavedListEntry = NewPos; + DistanceValue = AdjustDateAndTimePosition (FALSE, &NewPos); + + if (NewPos->ForwardLink != &Menu) { + MenuOption = MENU_OPTION_FROM_LINK (NewPos); + NewLine = TRUE; + NewPos = NewPos->ForwardLink; + NextMenuOption = MENU_OPTION_FROM_LINK (NewPos); + + DistanceValue += NextMenuOption->Skip; + DistanceValue += MoveToNextStatement (FALSE, &NewPos); + // + // An option might be multi-line, so we need to reflect that data in the overall skip value + // + UpdateOptionSkipLines (Selection, NextMenuOption, &OptionString, SkipValue); + + Temp = MenuOption->Row + MenuOption->Skip + DistanceValue - 1; + if ((MenuOption->Row + MenuOption->Skip == BottomRow + 1) && + (NextMenuOption->ThisTag->Operand == EFI_IFR_DATE_OP || + NextMenuOption->ThisTag->Operand == EFI_IFR_TIME_OP) + ) { + Temp ++; + } + + // + // If we are going to scroll, update TopOfScreen + // + if (Temp > BottomRow) { + do { + // + // Is the current top of screen a zero-advance op-code? + // If so, keep moving forward till we hit a >0 advance op-code + // + SavedMenuOption = MENU_OPTION_FROM_LINK (TopOfScreen); + + // + // If bottom op-code is more than one line or top op-code is more than one line + // + if ((DistanceValue > 1) || (MenuOption->Skip > 1)) { + // + // Is the bottom op-code greater than or equal in size to the top op-code? + // + if ((Temp - BottomRow) >= (SavedMenuOption->Skip - OldSkipValue)) { + // + // Skip the top op-code + // + TopOfScreen = TopOfScreen->ForwardLink; + Difference = (Temp - BottomRow) - (SavedMenuOption->Skip - OldSkipValue); + + OldSkipValue = Difference; + + SavedMenuOption = MENU_OPTION_FROM_LINK (TopOfScreen); + + // + // If we have a remainder, skip that many more op-codes until we drain the remainder + // + for (; + Difference >= (INTN) SavedMenuOption->Skip; + Difference = Difference - (INTN) SavedMenuOption->Skip + ) { + // + // Since the Difference is greater than or equal to this op-code's skip value, skip it + // + TopOfScreen = TopOfScreen->ForwardLink; + SavedMenuOption = MENU_OPTION_FROM_LINK (TopOfScreen); + if (Difference < (INTN) SavedMenuOption->Skip) { + Difference = SavedMenuOption->Skip - Difference - 1; + break; + } else { + if (Difference == (INTN) SavedMenuOption->Skip) { + TopOfScreen = TopOfScreen->ForwardLink; + SavedMenuOption = MENU_OPTION_FROM_LINK (TopOfScreen); + Difference = SavedMenuOption->Skip - Difference; + break; + } + } + } + // + // Since we will act on this op-code in the next routine, and increment the + // SkipValue, set the skips to one less than what is required. + // + SkipValue = Difference - 1; + + } else { + // + // Since we will act on this op-code in the next routine, and increment the + // SkipValue, set the skips to one less than what is required. + // + SkipValue = OldSkipValue + (Temp - BottomRow) - 1; + } + } else { + if ((OldSkipValue + 1) == (INTN) SavedMenuOption->Skip) { + TopOfScreen = TopOfScreen->ForwardLink; + break; + } else { + SkipValue = OldSkipValue; + } + } + // + // If the op-code at the top of the screen is more than one line, let's not skip it yet + // Let's set a skip flag to smoothly scroll the top of the screen. + // + if (SavedMenuOption->Skip > 1) { + if (SavedMenuOption == NextMenuOption) { + SkipValue = 0; + } else { + SkipValue++; + } + } else { + SkipValue = 0; + TopOfScreen = TopOfScreen->ForwardLink; + } + } while (SavedMenuOption->Skip == 0); + + Repaint = TRUE; + OldSkipValue = SkipValue; + } + + MenuOption = MENU_OPTION_FROM_LINK (SavedListEntry); + + UpdateStatusBar (INPUT_ERROR, MenuOption->ThisTag->QuestionFlags, FALSE); + + } else { + SavedMenuOption = MenuOption; + MenuOption = MENU_OPTION_FROM_LINK (NewPos); + if (!IsSelectable (MenuOption)) { + // + // If we are at the end of the list and sitting on a text op, we need to more forward + // + ScreenOperation = UiUp; + ControlFlag = CfScreenOperation; + break; + } + + MenuOption = SavedMenuOption; + // + // If we are at the end of the list and sitting on a Date/Time op, rewind to the head. + // + AdjustDateAndTimePosition (TRUE, &NewPos); + } + break; + + case CfUiSave: + ControlFlag = CfCheckSelection; + + // + // Submit the form + // + Status = SubmitForm (Selection->FormSet, Selection->Form); + + if (!EFI_ERROR (Status)) { + UpdateStatusBar (INPUT_ERROR, MenuOption->ThisTag->QuestionFlags, FALSE); + UpdateStatusBar (NV_UPDATE_REQUIRED, MenuOption->ThisTag->QuestionFlags, FALSE); + } else { + do { + CreateDialog (4, TRUE, 0, NULL, &Key, gEmptyString, gSaveFailed, gPressEnter, gEmptyString); + } while (Key.UnicodeChar != CHAR_CARRIAGE_RETURN); + + Repaint = TRUE; + NewLine = TRUE; + } + break; + + case CfUiDefault: + ControlFlag = CfCheckSelection; + + Status = ExtractFormDefault (Selection->FormSet, Selection->Form, DefaultId); + + if (!EFI_ERROR (Status)) { + Selection->Action = UI_ACTION_REFRESH_FORM; + + // + // Show NV update flag on status bar + // + gNvUpdateRequired = TRUE; + } + break; + + case CfUiNoOperation: + ControlFlag = CfCheckSelection; + break; + + case CfExit: + UiFreeRefreshList (); + + gST->ConOut->SetAttribute (gST->ConOut, EFI_TEXT_ATTR (EFI_LIGHTGRAY, EFI_BLACK)); + gST->ConOut->SetCursorPosition (gST->ConOut, 0, Row + 4); + gST->ConOut->EnableCursor (gST->ConOut, TRUE); + gST->ConOut->OutputString (gST->ConOut, L"\n"); + + return EFI_SUCCESS; + + default: + break; + } + } +} diff --git a/MdeModulePkg/Universal/SetupBrowserDxe/Ui.h b/MdeModulePkg/Universal/SetupBrowserDxe/Ui.h new file mode 100644 index 0000000000..a5b7076be6 --- /dev/null +++ b/MdeModulePkg/Universal/SetupBrowserDxe/Ui.h @@ -0,0 +1,478 @@ +/** @file + +Copyright (c) 2004 - 2007, Intel Corporation +All rights reserved. This program and the accompanying materials +are licensed and made available under the terms and conditions of the BSD License +which accompanies this distribution. The full text of the license may be found at +http://opensource.org/licenses/bsd-license.php + +THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, +WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. + +Module Name: + + Ui.h + +Abstract: + + Head file UI + +Revision History + + +**/ + +#ifndef _UI_H +#define _UI_H + +//@MT:#include "Tiano.h" +//@MT:#include "EfiDriverLib.h" +#include "Setup.h" +//@MT:#include "GraphicsLib.h" +//@MT:#include "EfiPrintLib.h" + +// +// Globals +// +#define REGULAR_NUMERIC 0 +#define TIME_NUMERIC 1 +#define DATE_NUMERIC 2 + +#define SUBTITLE_INDENT 2 + +typedef enum { + UiNoOperation, + UiDefault, + UiSelect, + UiUp, + UiDown, + UiLeft, + UiRight, + UiReset, + UiSave, + UiPrevious, + UiPageUp, + UiPageDown, + UiMaxOperation +} UI_SCREEN_OPERATION; + +typedef enum { + CfInitialization, + CfCheckSelection, + CfRepaint, + CfRefreshHighLight, + CfUpdateHelpString, + CfPrepareToReadKey, + CfReadKey, + CfScreenOperation, + CfUiPrevious, + CfUiSelect, + CfUiReset, + CfUiLeft, + CfUiRight, + CfUiUp, + CfUiPageUp, + CfUiPageDown, + CfUiDown, + CfUiSave, + CfUiDefault, + CfUiNoOperation, + CfExit, + CfMaxControlFlag +} UI_CONTROL_FLAG; + +#define UI_ACTION_NONE 0 +#define UI_ACTION_REFRESH_FORM 1 +#define UI_ACTION_REFRESH_FORMSET 2 +#define UI_ACTION_EXIT 3 + +typedef struct { + EFI_HII_HANDLE Handle; + + // + // Target formset/form/Question information + // + EFI_GUID FormSetGuid; + UINT16 FormId; + UINT16 QuestionId; + + UINTN TopRow; + UINTN BottomRow; + UINTN PromptCol; + UINTN OptionCol; + UINTN CurrentRow; + + // + // Ation for Browser to taken: + // UI_ACTION_NONE - navigation inside a form + // UI_ACTION_REFRESH_FORM - re-evaluate expressions and repaint form + // UI_ACTION_REFRESH_FORMSET - re-parse formset IFR binary + // + UINTN Action; + + // + // Current selected fomset/form/Question + // + FORM_BROWSER_FORMSET *FormSet; + FORM_BROWSER_FORM *Form; + FORM_BROWSER_STATEMENT *Statement; +} UI_MENU_SELECTION; + +#define UI_MENU_OPTION_SIGNATURE EFI_SIGNATURE_32 ('u', 'i', 'm', 'm') +#define UI_MENU_LIST_SIGNATURE EFI_SIGNATURE_32 ('u', 'i', 'm', 'l') + +typedef struct { + UINTN Signature; + LIST_ENTRY Link; + + EFI_HII_HANDLE Handle; + FORM_BROWSER_STATEMENT *ThisTag; + UINT16 EntryNumber; + + UINTN Row; + UINTN Col; + UINTN OptCol; + CHAR16 *Description; + UINTN Skip; // Number of lines + + // + // Display item sequence for date/time + // Date: Month/Day/Year + // Sequence: 0 1 2 + // + // Time: Hour : Minute : Second + // Sequence: 0 1 2 + // + // + UINTN Sequence; + + BOOLEAN GrayOut; + BOOLEAN ReadOnly; +} UI_MENU_OPTION; + +#define MENU_OPTION_FROM_LINK(a) CR (a, UI_MENU_OPTION, Link, UI_MENU_OPTION_SIGNATURE) + +typedef struct { + UINTN Signature; + LIST_ENTRY MenuLink; + + UINT16 FormId; + UINT16 QuestionId; +} UI_MENU_LIST; + +typedef struct _MENU_REFRESH_ENTRY { + struct _MENU_REFRESH_ENTRY *Next; + UI_MENU_OPTION *MenuOption; // Describes the entry needing an update + UI_MENU_SELECTION *Selection; + UINTN CurrentColumn; + UINTN CurrentRow; + UINTN CurrentAttribute; +} MENU_REFRESH_ENTRY; + +typedef struct { + UINT16 ScanCode; + UI_SCREEN_OPERATION ScreenOperation; +} SCAN_CODE_TO_SCREEN_OPERATION; + +typedef struct { + UI_SCREEN_OPERATION ScreenOperation; + UI_CONTROL_FLAG ControlFlag; +} SCREEN_OPERATION_T0_CONTROL_FLAG; + + +extern LIST_ENTRY gMenuList; +extern MENU_REFRESH_ENTRY *gMenuRefreshHead; +extern UI_MENU_SELECTION *gCurrentSelection; + +// +// Global Functions +// +VOID +UiInitMenu ( + VOID + ) +; + +VOID +UiInitMenuList ( + VOID + ) +; + +VOID +UiRemoveMenuListEntry ( + OUT UI_MENU_SELECTION *Selection + ) +; + +VOID +UiFreeMenuList ( + VOID + ) +; + +VOID +UiAddMenuListEntry ( + IN UI_MENU_SELECTION *Selection + ) +; + +VOID +UiFreeMenu ( + VOID + ) +; + +VOID +UiAddMenuOption ( + IN CHAR16 *String, + IN EFI_HII_HANDLE Handle, + IN FORM_BROWSER_STATEMENT *Statement, + IN UINT16 NumberOfLines, + IN UINT16 MenuItemCount + ) +; + +EFI_STATUS +UiDisplayMenu ( + IN OUT UI_MENU_SELECTION *Selection + ) +; + +VOID +FreeBrowserStrings ( + VOID + ) +; + +EFI_STATUS +SetupBrowser ( + IN OUT UI_MENU_SELECTION *Selection + ) +; + +VOID +ValueToString ( + IN CHAR16 *Buffer, + IN BOOLEAN Comma, + IN INT64 v + ) +; + +EFI_STATUS +UiIntToString ( + IN UINTN num, + IN OUT CHAR16 *str, + IN UINT16 size + ) +; + +VOID +SetUnicodeMem ( + IN VOID *Buffer, + IN UINTN Size, + IN CHAR16 Value + ) +; + +EFI_STATUS +UiWaitForSingleEvent ( + IN EFI_EVENT Event, + IN UINT64 Timeout, OPTIONAL + IN UINT8 RefreshInterval OPTIONAL + ) +; + +VOID +CreatePopUp ( + IN UINTN ScreenWidth, + IN UINTN NumberOfLines, + IN CHAR16 *ArrayOfStrings, + ... + ) +; + +EFI_STATUS +ReadString ( + IN UI_MENU_OPTION *MenuOption, + IN CHAR16 *Prompt, + OUT CHAR16 *StringPtr + ) +; + +EFI_STATUS +GetSelectionInputPopUp ( + IN UI_MENU_SELECTION *Selection, + IN UI_MENU_OPTION *MenuOption + ) +; + +EFI_STATUS +GetNumericInput ( + IN UI_MENU_SELECTION *Selection, + IN UI_MENU_OPTION *MenuOption + ) +; + +VOID +UpdateStatusBar ( + IN UINTN MessageType, + IN UINT8 Flags, + IN BOOLEAN State + ) +; + +EFI_STATUS +ProcessQuestionConfig ( + IN UI_MENU_SELECTION *Selection, + IN FORM_BROWSER_STATEMENT *Question + ) +; + +EFI_STATUS +PrintFormattedNumber ( + IN FORM_BROWSER_STATEMENT *Question, + IN OUT CHAR16 *FormattedNumber, + IN UINTN BufferSize + ) +; + +QUESTION_OPTION * +ValueToOption ( + IN FORM_BROWSER_STATEMENT *Question, + IN EFI_HII_VALUE *OptionValue + ) +; + +EFI_STATUS +ProcessOptions ( + IN UI_MENU_SELECTION *Selection, + IN UI_MENU_OPTION *MenuOption, + IN BOOLEAN Selected, + OUT CHAR16 **OptionString + ) +; + +VOID +ProcessHelpString ( + IN CHAR16 *StringPtr, + OUT CHAR16 **FormattedString, + IN UINTN RowCount + ) +; + +VOID +UpdateKeyHelp ( + IN UI_MENU_OPTION *MenuOption, + IN BOOLEAN Selected + ) +; + +VOID +ClearLines ( + UINTN LeftColumn, + UINTN RightColumn, + UINTN TopRow, + UINTN BottomRow, + UINTN TextAttribute + ) +; + +UINTN +GetStringWidth ( + CHAR16 *String + ) +; + +UINT16 +GetLineByWidth ( + IN CHAR16 *InputString, + IN UINT16 LineWidth, + IN OUT UINTN *Index, + OUT CHAR16 **OutputString + ) +; + +UINT16 +GetWidth ( + IN FORM_BROWSER_STATEMENT *Statement, + IN EFI_HII_HANDLE Handle + ) +; + +VOID +NewStrCat ( + CHAR16 *Destination, + CHAR16 *Source + ) +; + +EFI_STATUS +WaitForKeyStroke ( + OUT EFI_INPUT_KEY *Key + ) +; + +VOID +ResetScopeStack ( + VOID + ) +; + +EFI_STATUS +PushScope ( + IN UINT8 Operand + ) +; + +EFI_STATUS +PopScope ( + OUT UINT8 *Operand + ) +; + +FORM_BROWSER_FORM * +IdToForm ( + IN FORM_BROWSER_FORMSET *FormSet, + IN UINT16 FormId +) +; + +FORM_BROWSER_STATEMENT * +IdToQuestion ( + IN FORM_BROWSER_FORMSET *FormSet, + IN FORM_BROWSER_FORM *Form, + IN UINT16 QuestionId + ) +; + +FORM_EXPRESSION * +IdToExpression ( + IN FORM_BROWSER_FORM *Form, + IN UINT8 RuleId + ) +; + +VOID +ExtendValueToU64 ( + IN EFI_HII_VALUE *Value + ) +; + +INTN +CompareHiiValue ( + IN EFI_HII_VALUE *Value1, + IN EFI_HII_VALUE *Value2, + IN EFI_HII_HANDLE HiiHandle OPTIONAL + ) +; + +EFI_STATUS +EvaluateExpression ( + IN FORM_BROWSER_FORMSET *FormSet, + IN FORM_BROWSER_FORM *Form, + IN OUT FORM_EXPRESSION *Expression + ) +; + +#endif // _UI_H |