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/Expression.c | |
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/Expression.c')
-rw-r--r-- | MdeModulePkg/Universal/SetupBrowserDxe/Expression.c | 1938 |
1 files changed, 1938 insertions, 0 deletions
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; +} |