-/** @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 = 0xFFFFFFFFFFFFFFFFULL;
- } else {
- StringPtr = StrStr (String[1] + Base, String[0]);
- Result->Value.u64 = (StringPtr == NULL) ? 0xFFFFFFFFFFFFFFFFULL : (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;
-}
+/** @file\r
+Utility functions for expression evaluation.\r
+\r
+Copyright (c) 2007 - 2008, Intel Corporation\r
+All rights reserved. This program and the accompanying materials\r
+are licensed and made available under the terms and conditions of the BSD License\r
+which accompanies this distribution. The full text of the license may be found at\r
+http://opensource.org/licenses/bsd-license.php\r
+\r
+THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,\r
+WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.\r
+\r
+**/\r
+\r
+#include "Ui.h"\r
+#include "Setup.h"\r
+\r
+//\r
+// Global stack used to evaluate boolean expresions\r
+//\r
+EFI_HII_VALUE *mOpCodeScopeStack = NULL;\r
+EFI_HII_VALUE *mOpCodeScopeStackEnd = NULL;\r
+EFI_HII_VALUE *mOpCodeScopeStackPointer = NULL;\r
+\r
+EFI_HII_VALUE *mExpressionEvaluationStack = NULL;\r
+EFI_HII_VALUE *mExpressionEvaluationStackEnd = NULL;\r
+EFI_HII_VALUE *mExpressionEvaluationStackPointer = NULL;\r
+\r
+//\r
+// Unicode collation protocol interface\r
+//\r
+EFI_UNICODE_COLLATION_PROTOCOL *mUnicodeCollation = NULL;\r
+\r
+\r
+/**\r
+ Grow size of the stack.\r
+\r
+ This is an internal function.\r
+\r
+ @param Stack On input: old stack; On output: new stack\r
+ @param StackPtr On input: old stack pointer; On output: new stack\r
+ pointer\r
+ @param StackEnd On input: old stack end; On output: new stack end\r
+\r
+ @retval EFI_SUCCESS Grow stack success.\r
+ @retval EFI_OUT_OF_RESOURCES No enough memory for stack space.\r
+\r
+**/\r
+EFI_STATUS\r
+GrowStack (\r
+ IN OUT EFI_HII_VALUE **Stack,\r
+ IN OUT EFI_HII_VALUE **StackPtr,\r
+ IN OUT EFI_HII_VALUE **StackEnd\r
+ )\r
+{\r
+ UINTN Size;\r
+ EFI_HII_VALUE *NewStack;\r
+\r
+ Size = EXPRESSION_STACK_SIZE_INCREMENT;\r
+ if (*StackPtr != NULL) {\r
+ Size = Size + (*StackEnd - *Stack);\r
+ }\r
+\r
+ NewStack = AllocatePool (Size * sizeof (EFI_HII_VALUE));\r
+ if (NewStack == NULL) {\r
+ return EFI_OUT_OF_RESOURCES;\r
+ }\r
+\r
+ if (*StackPtr != NULL) {\r
+ //\r
+ // Copy from Old Stack to the New Stack\r
+ //\r
+ CopyMem (\r
+ NewStack,\r
+ *Stack,\r
+ (*StackEnd - *Stack) * sizeof (EFI_HII_VALUE)\r
+ );\r
+\r
+ //\r
+ // Free The Old Stack\r
+ //\r
+ gBS->FreePool (*Stack);\r
+ }\r
+\r
+ //\r
+ // Make the Stack pointer point to the old data in the new stack\r
+ //\r
+ *StackPtr = NewStack + (*StackPtr - *Stack);\r
+ *Stack = NewStack;\r
+ *StackEnd = NewStack + Size;\r
+\r
+ return EFI_SUCCESS;\r
+}\r
+\r
+\r
+/**\r
+ Push an element onto the Boolean Stack.\r
+\r
+ @param Stack On input: old stack; On output: new stack\r
+ @param StackPtr On input: old stack pointer; On output: new stack\r
+ pointer\r
+ @param StackEnd On input: old stack end; On output: new stack end\r
+ @param Data Data to push.\r
+\r
+ @retval EFI_SUCCESS Push stack success.\r
+\r
+**/\r
+EFI_STATUS\r
+PushStack (\r
+ IN OUT EFI_HII_VALUE **Stack,\r
+ IN OUT EFI_HII_VALUE **StackPtr,\r
+ IN OUT EFI_HII_VALUE **StackEnd,\r
+ IN EFI_HII_VALUE *Data\r
+ )\r
+{\r
+ EFI_STATUS Status;\r
+\r
+ //\r
+ // Check for a stack overflow condition\r
+ //\r
+ if (*StackPtr >= *StackEnd) {\r
+ //\r
+ // Grow the stack\r
+ //\r
+ Status = GrowStack (Stack, StackPtr, StackEnd);\r
+ if (EFI_ERROR (Status)) {\r
+ return Status;\r
+ }\r
+ }\r
+\r
+ //\r
+ // Push the item onto the stack\r
+ //\r
+ CopyMem (*StackPtr, Data, sizeof (EFI_HII_VALUE));\r
+ *StackPtr = *StackPtr + 1;\r
+\r
+ return EFI_SUCCESS;\r
+}\r
+\r
+\r
+/**\r
+ Pop an element from the stack.\r
+\r
+ @param Stack On input: old stack; On output: new stack\r
+ @param StackPtr On input: old stack pointer; On output: new stack\r
+ pointer\r
+ @param StackEnd On input: old stack end; On output: new stack end\r
+ @param Data Data to pop.\r
+\r
+ @retval EFI_SUCCESS The value was popped onto the stack.\r
+ @retval EFI_ACCESS_DENIED The pop operation underflowed the stack\r
+\r
+**/\r
+EFI_STATUS\r
+PopStack (\r
+ IN OUT EFI_HII_VALUE **Stack,\r
+ IN OUT EFI_HII_VALUE **StackPtr,\r
+ IN OUT EFI_HII_VALUE **StackEnd,\r
+ OUT EFI_HII_VALUE *Data\r
+ )\r
+{\r
+ //\r
+ // Check for a stack underflow condition\r
+ //\r
+ if (*StackPtr == *Stack) {\r
+ return EFI_ACCESS_DENIED;\r
+ }\r
+\r
+ //\r
+ // Pop the item off the stack\r
+ //\r
+ *StackPtr = *StackPtr - 1;\r
+ CopyMem (Data, *StackPtr, sizeof (EFI_HII_VALUE));\r
+ return EFI_SUCCESS;\r
+}\r
+\r
+\r
+/**\r
+ Reset stack pointer to begin of the stack.\r
+\r
+**/\r
+VOID\r
+ResetScopeStack (\r
+ VOID\r
+ )\r
+{\r
+ mOpCodeScopeStackPointer = mOpCodeScopeStack;\r
+}\r
+\r
+\r
+/**\r
+ Push an Operand onto the Stack\r
+\r
+ @param Operand Operand to push.\r
+\r
+ @retval EFI_SUCCESS The value was pushed onto the stack.\r
+ @retval EFI_OUT_OF_RESOURCES There is not enough system memory to grow the\r
+ stack.\r
+\r
+**/\r
+EFI_STATUS\r
+PushScope (\r
+ IN UINT8 Operand\r
+ )\r
+{\r
+ EFI_HII_VALUE Data;\r
+\r
+ Data.Type = EFI_IFR_TYPE_NUM_SIZE_8;\r
+ Data.Value.u8 = Operand;\r
+\r
+ return PushStack (\r
+ &mOpCodeScopeStack,\r
+ &mOpCodeScopeStackPointer,\r
+ &mOpCodeScopeStackEnd,\r
+ &Data\r
+ );\r
+}\r
+\r
+\r
+/**\r
+ Pop an Operand from the Stack\r
+\r
+ @param Operand Operand to pop.\r
+\r
+ @retval EFI_SUCCESS The value was pushed onto the stack.\r
+ @retval EFI_OUT_OF_RESOURCES There is not enough system memory to grow the\r
+ stack.\r
+\r
+**/\r
+EFI_STATUS\r
+PopScope (\r
+ OUT UINT8 *Operand\r
+ )\r
+{\r
+ EFI_STATUS Status;\r
+ EFI_HII_VALUE Data;\r
+\r
+ Status = PopStack (\r
+ &mOpCodeScopeStack,\r
+ &mOpCodeScopeStackPointer,\r
+ &mOpCodeScopeStackEnd,\r
+ &Data\r
+ );\r
+\r
+ *Operand = Data.Value.u8;\r
+\r
+ return Status;\r
+}\r
+\r
+\r
+/**\r
+ Reset stack pointer to begin of the stack.\r
+\r
+**/\r
+VOID\r
+ResetExpressionStack (\r
+ VOID\r
+ )\r
+{\r
+ mExpressionEvaluationStackPointer = mExpressionEvaluationStack;\r
+}\r
+\r
+\r
+/**\r
+ Push an Expression value onto the Stack\r
+\r
+ @param Value Expression value to push.\r
+\r
+ @retval EFI_SUCCESS The value was pushed onto the stack.\r
+ @retval EFI_OUT_OF_RESOURCES There is not enough system memory to grow the\r
+ stack.\r
+\r
+**/\r
+EFI_STATUS\r
+PushExpression (\r
+ IN EFI_HII_VALUE *Value\r
+ )\r
+{\r
+ return PushStack (\r
+ &mExpressionEvaluationStack,\r
+ &mExpressionEvaluationStackPointer,\r
+ &mExpressionEvaluationStackEnd,\r
+ Value\r
+ );\r
+}\r
+\r
+\r
+/**\r
+ Pop an Expression value from the stack.\r
+\r
+ @param Value Expression value to pop.\r
+\r
+ @retval EFI_SUCCESS The value was popped onto the stack.\r
+ @retval EFI_ACCESS_DENIED The pop operation underflowed the stack\r
+\r
+**/\r
+EFI_STATUS\r
+PopExpression (\r
+ OUT EFI_HII_VALUE *Value\r
+ )\r
+{\r
+ return PopStack (\r
+ &mExpressionEvaluationStack,\r
+ &mExpressionEvaluationStackPointer,\r
+ &mExpressionEvaluationStackEnd,\r
+ Value\r
+ );\r
+}\r
+\r
+\r
+/**\r
+ Get Form given its FormId.\r
+\r
+ @param FormSet The formset which contains this form.\r
+ @param FormId Id of this form.\r
+\r
+ @retval Pointer The form.\r
+ @retval NULL Specified Form is not found in the formset.\r
+\r
+**/\r
+FORM_BROWSER_FORM *\r
+IdToForm (\r
+ IN FORM_BROWSER_FORMSET *FormSet,\r
+ IN UINT16 FormId\r
+)\r
+{\r
+ LIST_ENTRY *Link;\r
+ FORM_BROWSER_FORM *Form;\r
+\r
+ Link = GetFirstNode (&FormSet->FormListHead);\r
+ while (!IsNull (&FormSet->FormListHead, Link)) {\r
+ Form = FORM_BROWSER_FORM_FROM_LINK (Link);\r
+\r
+ if (Form->FormId == FormId) {\r
+ return Form;\r
+ }\r
+\r
+ Link = GetNextNode (&FormSet->FormListHead, Link);\r
+ }\r
+\r
+ return NULL;\r
+}\r
+\r
+\r
+/**\r
+ Search a Question in Form scope using its QuestionId.\r
+\r
+ @param Form The form which contains this Question.\r
+ @param QuestionId Id of this Question.\r
+\r
+ @retval Pointer The Question.\r
+ @retval NULL Specified Question not found in the form.\r
+\r
+**/\r
+FORM_BROWSER_STATEMENT *\r
+IdToQuestion2 (\r
+ IN FORM_BROWSER_FORM *Form,\r
+ IN UINT16 QuestionId\r
+ )\r
+{\r
+ LIST_ENTRY *Link;\r
+ FORM_BROWSER_STATEMENT *Question;\r
+\r
+ if (QuestionId == 0) {\r
+ //\r
+ // The value of zero is reserved\r
+ //\r
+ return NULL;\r
+ }\r
+\r
+ Link = GetFirstNode (&Form->StatementListHead);\r
+ while (!IsNull (&Form->StatementListHead, Link)) {\r
+ Question = FORM_BROWSER_STATEMENT_FROM_LINK (Link);\r
+\r
+ if (Question->QuestionId == QuestionId) {\r
+ return Question;\r
+ }\r
+\r
+ Link = GetNextNode (&Form->StatementListHead, Link);\r
+ }\r
+\r
+ return NULL;\r
+}\r
+\r
+\r
+/**\r
+ Search a Question in Formset scope using its QuestionId.\r
+\r
+ @param FormSet The formset which contains this form.\r
+ @param Form The form which contains this Question.\r
+ @param QuestionId Id of this Question.\r
+\r
+ @retval Pointer The Question.\r
+ @retval NULL Specified Question not found in the form.\r
+\r
+**/\r
+FORM_BROWSER_STATEMENT *\r
+IdToQuestion (\r
+ IN FORM_BROWSER_FORMSET *FormSet,\r
+ IN FORM_BROWSER_FORM *Form,\r
+ IN UINT16 QuestionId\r
+ )\r
+{\r
+ LIST_ENTRY *Link;\r
+ FORM_BROWSER_STATEMENT *Question;\r
+\r
+ //\r
+ // Search in the form scope first\r
+ //\r
+ Question = IdToQuestion2 (Form, QuestionId);\r
+ if (Question != NULL) {\r
+ return Question;\r
+ }\r
+\r
+ //\r
+ // Search in the formset scope\r
+ //\r
+ Link = GetFirstNode (&FormSet->FormListHead);\r
+ while (!IsNull (&FormSet->FormListHead, Link)) {\r
+ Form = FORM_BROWSER_FORM_FROM_LINK (Link);\r
+\r
+ Question = IdToQuestion2 (Form, QuestionId);\r
+ if (Question != NULL) {\r
+ //\r
+ // EFI variable storage may be updated by Callback() asynchronous,\r
+ // to keep synchronous, always reload the Question Value.\r
+ //\r
+ if (Question->Storage->Type == EFI_HII_VARSTORE_EFI_VARIABLE) {\r
+ GetQuestionValue (FormSet, Form, Question, FALSE);\r
+ }\r
+\r
+ return Question;\r
+ }\r
+\r
+ Link = GetNextNode (&FormSet->FormListHead, Link);\r
+ }\r
+\r
+ return NULL;\r
+}\r
+\r
+\r
+/**\r
+ Get Expression given its RuleId.\r
+\r
+ @param Form The form which contains this Expression.\r
+ @param RuleId Id of this Expression.\r
+\r
+ @retval Pointer The Expression.\r
+ @retval NULL Specified Expression not found in the form.\r
+\r
+**/\r
+FORM_EXPRESSION *\r
+RuleIdToExpression (\r
+ IN FORM_BROWSER_FORM *Form,\r
+ IN UINT8 RuleId\r
+ )\r
+{\r
+ LIST_ENTRY *Link;\r
+ FORM_EXPRESSION *Expression;\r
+\r
+ Link = GetFirstNode (&Form->ExpressionListHead);\r
+ while (!IsNull (&Form->ExpressionListHead, Link)) {\r
+ Expression = FORM_EXPRESSION_FROM_LINK (Link);\r
+\r
+ if (Expression->Type == EFI_HII_EXPRESSION_RULE && Expression->RuleId == RuleId) {\r
+ return Expression;\r
+ }\r
+\r
+ Link = GetNextNode (&Form->ExpressionListHead, Link);\r
+ }\r
+\r
+ return NULL;\r
+}\r
+\r
+\r
+/**\r
+ Locate the Unicode Collation Protocol interface for later use.\r
+\r
+ @retval EFI_SUCCESS Protocol interface initialize success.\r
+ @retval Other Protocol interface initialize failed.\r
+\r
+**/\r
+EFI_STATUS\r
+InitializeUnicodeCollationProtocol (\r
+ VOID\r
+ )\r
+{\r
+ EFI_STATUS Status;\r
+\r
+ if (mUnicodeCollation != NULL) {\r
+ return EFI_SUCCESS;\r
+ }\r
+\r
+ //\r
+ // BUGBUG: Proper impelmentation is to locate all Unicode Collation Protocol\r
+ // instances first and then select one which support English language.\r
+ // Current implementation just pick the first instance.\r
+ //\r
+ Status = gBS->LocateProtocol (\r
+ &gEfiUnicodeCollation2ProtocolGuid,\r
+ NULL,\r
+ (VOID **) &mUnicodeCollation\r
+ );\r
+ return Status;\r
+}\r
+\r
+/**\r
+ Convert the input Unicode character to upper.\r
+\r
+ @param String Th Unicode character to be converted.\r
+\r
+**/\r
+VOID\r
+IfrStrToUpper (\r
+ CHAR16 *String\r
+ )\r
+{\r
+ while (*String != 0) {\r
+ if ((*String >= 'a') && (*String <= 'z')) {\r
+ *String = (UINT16) ((*String) & ((UINT16) ~0x20));\r
+ }\r
+ String++;\r
+ }\r
+}\r
+\r
+\r
+/**\r
+ Evaluate opcode EFI_IFR_TO_STRING.\r
+\r
+ @param FormSet Formset which contains this opcode.\r
+ @param Format String format in EFI_IFR_TO_STRING.\r
+ @param Result Evaluation result for this opcode.\r
+\r
+ @retval EFI_SUCCESS Opcode evaluation success.\r
+ @retval Other Opcode evaluation failed.\r
+\r
+**/\r
+EFI_STATUS\r
+IfrToString (\r
+ IN FORM_BROWSER_FORMSET *FormSet,\r
+ IN UINT8 Format,\r
+ OUT EFI_HII_VALUE *Result\r
+ )\r
+{\r
+ EFI_STATUS Status;\r
+ EFI_HII_VALUE Value;\r
+ CHAR16 *String;\r
+ CHAR16 *PrintFormat;\r
+ CHAR16 Buffer[MAXIMUM_VALUE_CHARACTERS];\r
+ UINTN BufferSize;\r
+\r
+ Status = PopExpression (&Value);\r
+ if (EFI_ERROR (Status)) {\r
+ return Status;\r
+ }\r
+\r
+ switch (Value.Type) {\r
+ case EFI_IFR_TYPE_NUM_SIZE_8:\r
+ case EFI_IFR_TYPE_NUM_SIZE_16:\r
+ case EFI_IFR_TYPE_NUM_SIZE_32:\r
+ case EFI_IFR_TYPE_NUM_SIZE_64:\r
+ BufferSize = MAXIMUM_VALUE_CHARACTERS * sizeof (CHAR16);\r
+ switch (Format) {\r
+ case EFI_IFR_STRING_UNSIGNED_DEC:\r
+ case EFI_IFR_STRING_SIGNED_DEC:\r
+ PrintFormat = L"%ld";\r
+ break;\r
+\r
+ case EFI_IFR_STRING_LOWERCASE_HEX:\r
+ PrintFormat = L"%lx";\r
+ break;\r
+\r
+ case EFI_IFR_STRING_UPPERCASE_HEX:\r
+ PrintFormat = L"%lX";\r
+ break;\r
+\r
+ default:\r
+ return EFI_UNSUPPORTED;\r
+ }\r
+ UnicodeSPrint (Buffer, BufferSize, PrintFormat, Value.Value.u64);\r
+ String = Buffer;\r
+ break;\r
+\r
+ case EFI_IFR_TYPE_STRING:\r
+ CopyMem (Result, &Value, sizeof (EFI_HII_VALUE));\r
+ return EFI_SUCCESS;\r
+\r
+ case EFI_IFR_TYPE_BOOLEAN:\r
+ String = (Value.Value.b) ? L"True" : L"False";\r
+ break;\r
+\r
+ default:\r
+ return EFI_UNSUPPORTED;\r
+ }\r
+\r
+ Result->Type = EFI_IFR_TYPE_STRING;\r
+ Result->Value.string = NewString (String, FormSet->HiiHandle);\r
+ return EFI_SUCCESS;\r
+}\r
+\r
+\r
+/**\r
+ Evaluate opcode EFI_IFR_TO_UINT.\r
+\r
+ @param FormSet Formset which contains this opcode.\r
+ @param Result Evaluation result for this opcode.\r
+\r
+ @retval EFI_SUCCESS Opcode evaluation success.\r
+ @retval Other Opcode evaluation failed.\r
+\r
+**/\r
+EFI_STATUS\r
+IfrToUint (\r
+ IN FORM_BROWSER_FORMSET *FormSet,\r
+ OUT EFI_HII_VALUE *Result\r
+ )\r
+{\r
+ EFI_STATUS Status;\r
+ EFI_HII_VALUE Value;\r
+ CHAR16 *String;\r
+ CHAR16 *StringPtr;\r
+ UINTN BufferSize;\r
+\r
+ Status = PopExpression (&Value);\r
+ if (EFI_ERROR (Status)) {\r
+ return Status;\r
+ }\r
+\r
+ if (Value.Type >= EFI_IFR_TYPE_OTHER) {\r
+ return EFI_UNSUPPORTED;\r
+ }\r
+\r
+ Status = EFI_SUCCESS;\r
+ if (Value.Type == EFI_IFR_TYPE_STRING) {\r
+ String = GetToken (Value.Value.string, FormSet->HiiHandle);\r
+ if (String == NULL) {\r
+ return EFI_NOT_FOUND;\r
+ }\r
+\r
+ IfrStrToUpper (String);\r
+ StringPtr = StrStr (String, L"0X");\r
+ if (StringPtr != NULL) {\r
+ //\r
+ // Hex string\r
+ //\r
+ BufferSize = sizeof (UINT64);\r
+ Status = HexStringToBuf ((UINT8 *) &Result->Value.u64, &BufferSize, StringPtr + 2, NULL);\r
+ } else {\r
+ //\r
+ // BUGBUG: Need handle decimal string\r
+ //\r
+ }\r
+ gBS->FreePool (String);\r
+ } else {\r
+ CopyMem (Result, &Value, sizeof (EFI_HII_VALUE));\r
+ }\r
+\r
+ Result->Type = EFI_IFR_TYPE_NUM_SIZE_64;\r
+ return Status;\r
+}\r
+\r
+\r
+/**\r
+ Evaluate opcode EFI_IFR_CATENATE.\r
+\r
+ @param FormSet Formset which contains this opcode.\r
+ @param Result Evaluation result for this opcode.\r
+\r
+ @retval EFI_SUCCESS Opcode evaluation success.\r
+ @retval Other Opcode evaluation failed.\r
+\r
+**/\r
+EFI_STATUS\r
+IfrCatenate (\r
+ IN FORM_BROWSER_FORMSET *FormSet,\r
+ OUT EFI_HII_VALUE *Result\r
+ )\r
+{\r
+ EFI_STATUS Status;\r
+ EFI_HII_VALUE Value;\r
+ CHAR16 *String[2];\r
+ UINTN Index;\r
+ CHAR16 *StringPtr;\r
+ UINTN Size;\r
+\r
+ //\r
+ // String[0] - The second string\r
+ // String[1] - The first string\r
+ //\r
+ String[0] = NULL;\r
+ String[1] = NULL;\r
+ StringPtr = NULL;\r
+ Status = EFI_SUCCESS;\r
+\r
+ for (Index = 0; Index < 2; Index++) {\r
+ Status = PopExpression (&Value);\r
+ if (EFI_ERROR (Status)) {\r
+ goto Done;\r
+ }\r
+\r
+ if (Value.Type != EFI_IFR_TYPE_STRING) {\r
+ Status = EFI_UNSUPPORTED;\r
+ goto Done;\r
+ }\r
+\r
+ String[Index] = GetToken (Value.Value.string, FormSet->HiiHandle);\r
+ if (String== NULL) {\r
+ Status = EFI_NOT_FOUND;\r
+ goto Done;\r
+ }\r
+ }\r
+\r
+ Size = StrSize (String[0]);\r
+ StringPtr= AllocatePool (StrSize (String[1]) + Size);\r
+ ASSERT (StringPtr != NULL);\r
+ StrCpy (StringPtr, String[1]);\r
+ StrCat (StringPtr, String[0]);\r
+\r
+ Result->Type = EFI_IFR_TYPE_STRING;\r
+ Result->Value.string = NewString (StringPtr, FormSet->HiiHandle);\r
+\r
+Done:\r
+ if (String[0] != NULL) {\r
+ FreePool (String[0]);\r
+ }\r
+ if (String[1] != NULL) {\r
+ FreePool (String[1]);\r
+ } \r
+ if (StringPtr != NULL) {\r
+ FreePool (StringPtr);\r
+ }\r
+\r
+ return Status;\r
+}\r
+\r
+\r
+/**\r
+ Evaluate opcode EFI_IFR_MATCH.\r
+\r
+ @param FormSet Formset which contains this opcode.\r
+ @param Result Evaluation result for this opcode.\r
+\r
+ @retval EFI_SUCCESS Opcode evaluation success.\r
+ @retval Other Opcode evaluation failed.\r
+\r
+**/\r
+EFI_STATUS\r
+IfrMatch (\r
+ IN FORM_BROWSER_FORMSET *FormSet,\r
+ OUT EFI_HII_VALUE *Result\r
+ )\r
+{\r
+ EFI_STATUS Status;\r
+ EFI_HII_VALUE Value;\r
+ CHAR16 *String[2];\r
+ UINTN Index;\r
+\r
+ //\r
+ // String[0] - The string to search\r
+ // String[1] - pattern\r
+ //\r
+ String[0] = NULL;\r
+ String[1] = NULL;\r
+ Status = EFI_SUCCESS;\r
+ for (Index = 0; Index < 2; Index++) {\r
+ Status = PopExpression (&Value);\r
+ if (EFI_ERROR (Status)) {\r
+ goto Done;\r
+ }\r
+\r
+ if (Value.Type != EFI_IFR_TYPE_STRING) {\r
+ Status = EFI_UNSUPPORTED;\r
+ goto Done;\r
+ }\r
+\r
+ String[Index] = GetToken (Value.Value.string, FormSet->HiiHandle);\r
+ if (String== NULL) {\r
+ Status = EFI_NOT_FOUND;\r
+ goto Done;\r
+ }\r
+ }\r
+\r
+ Result->Type = EFI_IFR_TYPE_BOOLEAN;\r
+ Result->Value.b = mUnicodeCollation->MetaiMatch (mUnicodeCollation, String[0], String[1]);\r
+\r
+Done:\r
+ if (String[0] != NULL) {\r
+ FreePool (String[0]);\r
+ }\r
+ if (String[1] != NULL) {\r
+ FreePool (String[1]);\r
+ } \r
+\r
+ return Status;\r
+}\r
+\r
+\r
+/**\r
+ Evaluate opcode EFI_IFR_FIND.\r
+\r
+ @param FormSet Formset which contains this opcode.\r
+ @param Format Case sensitive or insensitive.\r
+ @param Result Evaluation result for this opcode.\r
+\r
+ @retval EFI_SUCCESS Opcode evaluation success.\r
+ @retval Other Opcode evaluation failed.\r
+\r
+**/\r
+EFI_STATUS\r
+IfrFind (\r
+ IN FORM_BROWSER_FORMSET *FormSet,\r
+ IN UINT8 Format,\r
+ OUT EFI_HII_VALUE *Result\r
+ )\r
+{\r
+ EFI_STATUS Status;\r
+ EFI_HII_VALUE Value;\r
+ CHAR16 *String[2];\r
+ UINTN Base;\r
+ CHAR16 *StringPtr;\r
+ UINTN Index;\r
+\r
+ if (Format > EFI_IFR_FF_CASE_INSENSITIVE) {\r
+ return EFI_UNSUPPORTED;\r
+ }\r
+\r
+ Status = PopExpression (&Value);\r
+ if (EFI_ERROR (Status)) {\r
+ return Status;\r
+ }\r
+ if (Value.Type > EFI_IFR_TYPE_NUM_SIZE_64) {\r
+ return EFI_UNSUPPORTED;\r
+ }\r
+ Base = (UINTN) Value.Value.u64;\r
+\r
+ //\r
+ // String[0] - sub-string\r
+ // String[1] - The string to search\r
+ //\r
+ String[0] = NULL;\r
+ String[1] = NULL;\r
+ for (Index = 0; Index < 2; Index++) {\r
+ Status = PopExpression (&Value);\r
+ if (EFI_ERROR (Status)) {\r
+ goto Done;\r
+ }\r
+\r
+ if (Value.Type != EFI_IFR_TYPE_STRING) {\r
+ Status = EFI_UNSUPPORTED;\r
+ goto Done;\r
+ }\r
+\r
+ String[Index] = GetToken (Value.Value.string, FormSet->HiiHandle);\r
+ if (String== NULL) {\r
+ Status = EFI_NOT_FOUND;\r
+ goto Done;\r
+ }\r
+\r
+ if (Format == EFI_IFR_FF_CASE_INSENSITIVE) {\r
+ //\r
+ // Case insensitive, convert both string to upper case\r
+ //\r
+ IfrStrToUpper (String[Index]);\r
+ }\r
+ }\r
+\r
+ Result->Type = EFI_IFR_TYPE_NUM_SIZE_64;\r
+ if (Base >= StrLen (String[1])) {\r
+ Result->Value.u64 = 0xFFFFFFFFFFFFFFFFULL;\r
+ } else {\r
+ StringPtr = StrStr (String[1] + Base, String[0]);\r
+ Result->Value.u64 = (StringPtr == NULL) ? 0xFFFFFFFFFFFFFFFFULL : (StringPtr - String[1]);\r
+ }\r
+\r
+Done:\r
+ if (String[0] != NULL) {\r
+ FreePool (String[0]);\r
+ }\r
+ if (String[1] != NULL) {\r
+ FreePool (String[1]);\r
+ } \r
+\r
+ return Status;\r
+}\r
+\r
+\r
+/**\r
+ Evaluate opcode EFI_IFR_MID.\r
+\r
+ @param FormSet Formset which contains this opcode.\r
+ @param Result Evaluation result for this opcode.\r
+\r
+ @retval EFI_SUCCESS Opcode evaluation success.\r
+ @retval Other Opcode evaluation failed.\r
+\r
+**/\r
+EFI_STATUS\r
+IfrMid (\r
+ IN FORM_BROWSER_FORMSET *FormSet,\r
+ OUT EFI_HII_VALUE *Result\r
+ )\r
+{\r
+ EFI_STATUS Status;\r
+ EFI_HII_VALUE Value;\r
+ CHAR16 *String;\r
+ UINTN Base;\r
+ UINTN Length;\r
+ CHAR16 *SubString;\r
+\r
+ Status = PopExpression (&Value);\r
+ if (EFI_ERROR (Status)) {\r
+ return Status;\r
+ }\r
+ if (Value.Type > EFI_IFR_TYPE_NUM_SIZE_64) {\r
+ return EFI_UNSUPPORTED;\r
+ }\r
+ Length = (UINTN) Value.Value.u64;\r
+\r
+ Status = PopExpression (&Value);\r
+ if (EFI_ERROR (Status)) {\r
+ return Status;\r
+ }\r
+ if (Value.Type > EFI_IFR_TYPE_NUM_SIZE_64) {\r
+ return EFI_UNSUPPORTED;\r
+ }\r
+ Base = (UINTN) Value.Value.u64;\r
+\r
+ Status = PopExpression (&Value);\r
+ if (EFI_ERROR (Status)) {\r
+ return Status;\r
+ }\r
+ if (Value.Type != EFI_IFR_TYPE_STRING) {\r
+ return EFI_UNSUPPORTED;\r
+ }\r
+ String = GetToken (Value.Value.string, FormSet->HiiHandle);\r
+ if (String == NULL) {\r
+ return EFI_NOT_FOUND;\r
+ }\r
+\r
+ if (Length == 0 || Base >= StrLen (String)) {\r
+ SubString = gEmptyString;\r
+ } else {\r
+ SubString = String + Base;\r
+ if ((Base + Length) < StrLen (String)) {\r
+ SubString[Length] = L'\0';\r
+ }\r
+ }\r
+\r
+ Result->Type = EFI_IFR_TYPE_STRING;\r
+ Result->Value.string = NewString (SubString, FormSet->HiiHandle);\r
+\r
+ gBS->FreePool (String);\r
+\r
+ return Status;\r
+}\r
+\r
+\r
+/**\r
+ Evaluate opcode EFI_IFR_TOKEN.\r
+\r
+ @param FormSet Formset which contains this opcode.\r
+ @param Result Evaluation result for this opcode.\r
+\r
+ @retval EFI_SUCCESS Opcode evaluation success.\r
+ @retval Other Opcode evaluation failed.\r
+\r
+**/\r
+EFI_STATUS\r
+IfrToken (\r
+ IN FORM_BROWSER_FORMSET *FormSet,\r
+ OUT EFI_HII_VALUE *Result\r
+ )\r
+{\r
+ EFI_STATUS Status;\r
+ EFI_HII_VALUE Value;\r
+ CHAR16 *String[2];\r
+ UINTN Count;\r
+ CHAR16 *Delimiter;\r
+ CHAR16 *SubString;\r
+ CHAR16 *StringPtr;\r
+ UINTN Index;\r
+\r
+ Status = PopExpression (&Value);\r
+ if (EFI_ERROR (Status)) {\r
+ return Status;\r
+ }\r
+ if (Value.Type > EFI_IFR_TYPE_NUM_SIZE_64) {\r
+ return EFI_UNSUPPORTED;\r
+ }\r
+ Count = (UINTN) Value.Value.u64;\r
+\r
+ //\r
+ // String[0] - Delimiter\r
+ // String[1] - The string to search\r
+ //\r
+ String[0] = NULL;\r
+ String[1] = NULL;\r
+ for (Index = 0; Index < 2; Index++) {\r
+ Status = PopExpression (&Value);\r
+ if (EFI_ERROR (Status)) {\r
+ goto Done;\r
+ }\r
+\r
+ if (Value.Type != EFI_IFR_TYPE_STRING) {\r
+ Status = EFI_UNSUPPORTED;\r
+ goto Done;\r
+ }\r
+\r
+ String[Index] = GetToken (Value.Value.string, FormSet->HiiHandle);\r
+ if (String== NULL) {\r
+ Status = EFI_NOT_FOUND;\r
+ goto Done;\r
+ }\r
+ }\r
+\r
+ Delimiter = String[0];\r
+ SubString = String[1];\r
+ while (Count > 0) {\r
+ SubString = StrStr (SubString, Delimiter);\r
+ if (SubString != NULL) {\r
+ //\r
+ // Skip over the delimiter\r
+ //\r
+ SubString = SubString + StrLen (Delimiter);\r
+ } else {\r
+ break;\r
+ }\r
+ Count--;\r
+ }\r
+\r
+ if (SubString == NULL) {\r
+ //\r
+ // nth delimited sub-string not found, push an empty string\r
+ //\r
+ SubString = gEmptyString;\r
+ } else {\r
+ //\r
+ // Put a NULL terminator for nth delimited sub-string\r
+ //\r
+ StringPtr = StrStr (SubString, Delimiter);\r
+ if (StringPtr != NULL) {\r
+ *StringPtr = L'\0';\r
+ }\r
+ }\r
+\r
+ Result->Type = EFI_IFR_TYPE_STRING;\r
+ Result->Value.string = NewString (SubString, FormSet->HiiHandle);\r
+\r
+Done:\r
+ if (String[0] != NULL) {\r
+ FreePool (String[0]);\r
+ }\r
+ if (String[1] != NULL) {\r
+ FreePool (String[1]);\r
+ } \r
+\r
+ return Status;\r
+}\r
+\r
+\r
+/**\r
+ Evaluate opcode EFI_IFR_SPAN.\r
+\r
+ @param FormSet Formset which contains this opcode.\r
+ @param Flags FIRST_MATCHING or FIRST_NON_MATCHING.\r
+ @param Result Evaluation result for this opcode.\r
+\r
+ @retval EFI_SUCCESS Opcode evaluation success.\r
+ @retval Other Opcode evaluation failed.\r
+\r
+**/\r
+EFI_STATUS\r
+IfrSpan (\r
+ IN FORM_BROWSER_FORMSET *FormSet,\r
+ IN UINT8 Flags,\r
+ OUT EFI_HII_VALUE *Result\r
+ )\r
+{\r
+ EFI_STATUS Status;\r
+ EFI_HII_VALUE Value;\r
+ CHAR16 *String[2];\r
+ CHAR16 *Charset;\r
+ UINTN Base;\r
+ UINTN Index;\r
+ CHAR16 *StringPtr;\r
+ BOOLEAN Found;\r
+\r
+ Status = PopExpression (&Value);\r
+ if (EFI_ERROR (Status)) {\r
+ return Status;\r
+ }\r
+ if (Value.Type > EFI_IFR_TYPE_NUM_SIZE_64) {\r
+ return EFI_UNSUPPORTED;\r
+ }\r
+ Base = (UINTN) Value.Value.u64;\r
+\r
+ //\r
+ // String[0] - Charset\r
+ // String[1] - The string to search\r
+ //\r
+ String[0] = NULL;\r
+ String[1] = NULL;\r
+ for (Index = 0; Index < 2; Index++) {\r
+ Status = PopExpression (&Value);\r
+ if (EFI_ERROR (Status)) {\r
+ goto Done;\r
+ }\r
+\r
+ if (Value.Type != EFI_IFR_TYPE_STRING) {\r
+ Status = EFI_UNSUPPORTED;\r
+ goto Done;\r
+ }\r
+\r
+ String[Index] = GetToken (Value.Value.string, FormSet->HiiHandle);\r
+ if (String== NULL) {\r
+ Status = EFI_NOT_FOUND;\r
+ goto Done;\r
+ }\r
+ }\r
+\r
+ if (Base >= StrLen (String[1])) {\r
+ Status = EFI_UNSUPPORTED;\r
+ goto Done;\r
+ }\r
+\r
+ Found = FALSE;\r
+ StringPtr = String[1] + Base;\r
+ Charset = String[0];\r
+ while (*StringPtr != 0 && !Found) {\r
+ Index = 0;\r
+ while (Charset[Index] != 0) {\r
+ if (*StringPtr >= Charset[Index] && *StringPtr <= Charset[Index + 1]) {\r
+ if (Flags == EFI_IFR_FLAGS_FIRST_MATCHING) {\r
+ Found = TRUE;\r
+ break;\r
+ }\r
+ } else {\r
+ if (Flags == EFI_IFR_FLAGS_FIRST_NON_MATCHING) {\r
+ Found = TRUE;\r
+ break;\r
+ }\r
+ }\r
+ //\r
+ // Skip characters pair representing low-end of a range and high-end of a range\r
+ //\r
+ Index += 2;\r
+ }\r
+\r
+ if (!Found) {\r
+ StringPtr++;\r
+ }\r
+ }\r
+\r
+ Result->Type = EFI_IFR_TYPE_NUM_SIZE_64;\r
+ Result->Value.u64 = StringPtr - String[1];\r
+\r
+Done:\r
+ if (String[0] != NULL) {\r
+ FreePool (String[0]);\r
+ }\r
+ if (String[1] != NULL) {\r
+ FreePool (String[1]);\r
+ } \r
+\r
+ return Status;\r
+}\r
+\r
+\r
+/**\r
+ Zero extend integer/boolean/date/time to UINT64 for comparing.\r
+\r
+ @param Value HII Value to be converted.\r
+\r
+**/\r
+VOID\r
+ExtendValueToU64 (\r
+ IN EFI_HII_VALUE *Value\r
+ )\r
+{\r
+ UINT64 Temp;\r
+\r
+ Temp = 0;\r
+ switch (Value->Type) {\r
+ case EFI_IFR_TYPE_NUM_SIZE_8:\r
+ Temp = Value->Value.u8;\r
+ break;\r
+\r
+ case EFI_IFR_TYPE_NUM_SIZE_16:\r
+ Temp = Value->Value.u16;\r
+ break;\r
+\r
+ case EFI_IFR_TYPE_NUM_SIZE_32:\r
+ Temp = Value->Value.u32;\r
+ break;\r
+\r
+ case EFI_IFR_TYPE_BOOLEAN:\r
+ Temp = Value->Value.b;\r
+ break;\r
+\r
+ case EFI_IFR_TYPE_TIME:\r
+ Temp = Value->Value.u32 & 0xffffff;\r
+ break;\r
+\r
+ case EFI_IFR_TYPE_DATE:\r
+ Temp = Value->Value.u32;\r
+ break;\r
+\r
+ default:\r
+ return;\r
+ }\r
+\r
+ Value->Value.u64 = Temp;\r
+}\r
+\r
+\r
+/**\r
+ Compare two Hii value.\r
+\r
+ @param Value1 Expression value to compare on left-hand.\r
+ @param Value2 Expression value to compare on right-hand.\r
+ @param HiiHandle Only required for string compare.\r
+\r
+ @retval EFI_INVALID_PARAMETER Could not perform comparation on two values.\r
+ @retval 0 Two operators equeal.\r
+ @return Positive value if Value1 is greater than Value2.\r
+ @retval Negative value if Value1 is less than Value2.\r
+\r
+**/\r
+INTN\r
+CompareHiiValue (\r
+ IN EFI_HII_VALUE *Value1,\r
+ IN EFI_HII_VALUE *Value2,\r
+ IN EFI_HII_HANDLE HiiHandle OPTIONAL\r
+ )\r
+{\r
+ INTN Result;\r
+ INT64 Temp64;\r
+ CHAR16 *Str1;\r
+ CHAR16 *Str2;\r
+\r
+ if (Value1->Type >= EFI_IFR_TYPE_OTHER || Value2->Type >= EFI_IFR_TYPE_OTHER ) {\r
+ return EFI_INVALID_PARAMETER;\r
+ }\r
+\r
+ if (Value1->Type == EFI_IFR_TYPE_STRING || Value2->Type == EFI_IFR_TYPE_STRING ) {\r
+ if (Value1->Type != Value2->Type) {\r
+ //\r
+ // Both Operator should be type of String\r
+ //\r
+ return EFI_INVALID_PARAMETER;\r
+ }\r
+\r
+ if (Value1->Value.string == 0 || Value2->Value.string == 0) {\r
+ //\r
+ // StringId 0 is reserved\r
+ //\r
+ return EFI_INVALID_PARAMETER;\r
+ }\r
+\r
+ if (Value1->Value.string == Value2->Value.string) {\r
+ return 0;\r
+ }\r
+\r
+ Str1 = GetToken (Value1->Value.string, HiiHandle);\r
+ if (Str1 == NULL) {\r
+ //\r
+ // String not found\r
+ //\r
+ return EFI_INVALID_PARAMETER;\r
+ }\r
+\r
+ Str2 = GetToken (Value2->Value.string, HiiHandle);\r
+ if (Str2 == NULL) {\r
+ gBS->FreePool (Str1);\r
+ return EFI_INVALID_PARAMETER;\r
+ }\r
+\r
+ Result = StrCmp (Str1, Str2);\r
+\r
+ gBS->FreePool (Str1);\r
+ gBS->FreePool (Str2);\r
+\r
+ return Result;\r
+ }\r
+\r
+ //\r
+ // Take remain types(integer, boolean, date/time) as integer\r
+ //\r
+ Temp64 = (INT64) (Value1->Value.u64 - Value2->Value.u64);\r
+ if (Temp64 > 0) {\r
+ Result = 1;\r
+ } else if (Temp64 < 0) {\r
+ Result = -1;\r
+ } else {\r
+ Result = 0;\r
+ }\r
+\r
+ return Result;\r
+}\r
+\r
+\r
+/**\r
+ Evaluate the result of a HII expression\r
+\r
+ @param FormSet FormSet associated with this expression.\r
+ @param Form Form associated with this expression.\r
+ @param Expression Expression to be evaluated.\r
+\r
+ @retval EFI_SUCCESS The expression evaluated successfuly\r
+ @retval EFI_NOT_FOUND The Question which referenced by a QuestionId\r
+ could not be found.\r
+ @retval EFI_OUT_OF_RESOURCES There is not enough system memory to grow the\r
+ stack.\r
+ @retval EFI_ACCESS_DENIED The pop operation underflowed the stack\r
+ @retval EFI_INVALID_PARAMETER Syntax error with the Expression\r
+\r
+**/\r
+EFI_STATUS\r
+EvaluateExpression (\r
+ IN FORM_BROWSER_FORMSET *FormSet,\r
+ IN FORM_BROWSER_FORM *Form,\r
+ IN OUT FORM_EXPRESSION *Expression\r
+ )\r
+{\r
+ EFI_STATUS Status;\r
+ LIST_ENTRY *Link;\r
+ EXPRESSION_OPCODE *OpCode;\r
+ FORM_BROWSER_STATEMENT *Question;\r
+ FORM_BROWSER_STATEMENT *Question2;\r
+ UINT16 Index;\r
+ EFI_HII_VALUE Data1;\r
+ EFI_HII_VALUE Data2;\r
+ EFI_HII_VALUE Data3;\r
+ FORM_EXPRESSION *RuleExpression;\r
+ EFI_HII_VALUE *Value;\r
+ INTN Result;\r
+ CHAR16 *StrPtr;\r
+ UINT32 TempValue;\r
+\r
+ //\r
+ // Always reset the stack before evaluating an Expression\r
+ //\r
+ ResetExpressionStack ();\r
+\r
+ Expression->Result.Type = EFI_IFR_TYPE_OTHER;\r
+\r
+ Link = GetFirstNode (&Expression->OpCodeListHead);\r
+ while (!IsNull (&Expression->OpCodeListHead, Link)) {\r
+ OpCode = EXPRESSION_OPCODE_FROM_LINK (Link);\r
+\r
+ Link = GetNextNode (&Expression->OpCodeListHead, Link);\r
+\r
+ ZeroMem (&Data1, sizeof (EFI_HII_VALUE));\r
+ ZeroMem (&Data2, sizeof (EFI_HII_VALUE));\r
+ ZeroMem (&Data3, sizeof (EFI_HII_VALUE));\r
+\r
+ Value = &Data3;\r
+ Value->Type = EFI_IFR_TYPE_BOOLEAN;\r
+ Status = EFI_SUCCESS;\r
+\r
+ switch (OpCode->Operand) {\r
+ //\r
+ // Built-in functions\r
+ //\r
+ case EFI_IFR_EQ_ID_VAL_OP:\r
+ Question = IdToQuestion (FormSet, Form, OpCode->QuestionId);\r
+ if (Question == NULL) {\r
+ return EFI_NOT_FOUND;\r
+ }\r
+\r
+ Result = CompareHiiValue (&Question->HiiValue, &OpCode->Value, NULL);\r
+ if (Result == EFI_INVALID_PARAMETER) {\r
+ return EFI_INVALID_PARAMETER;\r
+ }\r
+ Value->Value.b = (BOOLEAN) ((Result == 0) ? TRUE : FALSE);\r
+ break;\r
+\r
+ case EFI_IFR_EQ_ID_ID_OP:\r
+ Question = IdToQuestion (FormSet, Form, OpCode->QuestionId);\r
+ if (Question == NULL) {\r
+ return EFI_NOT_FOUND;\r
+ }\r
+\r
+ Question2 = IdToQuestion (FormSet, Form, OpCode->QuestionId2);\r
+ if (Question2 == NULL) {\r
+ return EFI_NOT_FOUND;\r
+ }\r
+\r
+ Result = CompareHiiValue (&Question->HiiValue, &Question2->HiiValue, FormSet->HiiHandle);\r
+ if (Result == EFI_INVALID_PARAMETER) {\r
+ return EFI_INVALID_PARAMETER;\r
+ }\r
+ Value->Value.b = (BOOLEAN) ((Result == 0) ? TRUE : FALSE);\r
+ break;\r
+\r
+ case EFI_IFR_EQ_ID_LIST_OP:\r
+ Question = IdToQuestion (FormSet, Form, OpCode->QuestionId);\r
+ if (Question == NULL) {\r
+ return EFI_NOT_FOUND;\r
+ }\r
+\r
+ Value->Value.b = FALSE;\r
+ for (Index =0; Index < OpCode->ListLength; Index++) {\r
+ if (Question->HiiValue.Value.u16 == OpCode->ValueList[Index]) {\r
+ Value->Value.b = TRUE;\r
+ break;\r
+ }\r
+ }\r
+ break;\r
+\r
+ case EFI_IFR_DUP_OP:\r
+ Status = PopExpression (Value);\r
+ if (EFI_ERROR (Status)) {\r
+ return Status;\r
+ }\r
+\r
+ Status = PushExpression (Value);\r
+ break;\r
+\r
+ case EFI_IFR_QUESTION_REF1_OP:\r
+ case EFI_IFR_THIS_OP:\r
+ Question = IdToQuestion (FormSet, Form, OpCode->QuestionId);\r
+ if (Question == NULL) {\r
+ return EFI_NOT_FOUND;\r
+ }\r
+\r
+ Value = &Question->HiiValue;\r
+ break;\r
+\r
+ case EFI_IFR_QUESTION_REF3_OP:\r
+ if (OpCode->DevicePath == 0) {\r
+ //\r
+ // EFI_IFR_QUESTION_REF3\r
+ // Pop an expression from the expression stack\r
+ //\r
+ Status = PopExpression (Value);\r
+ if (EFI_ERROR (Status)) {\r
+ return Status;\r
+ }\r
+\r
+ //\r
+ // Validate the expression value\r
+ //\r
+ if ((Value->Type > EFI_IFR_TYPE_NUM_SIZE_64) || (Value->Value.u64 > 0xffff)) {\r
+ return EFI_NOT_FOUND;\r
+ }\r
+\r
+ Question = IdToQuestion (FormSet, Form, Value->Value.u16);\r
+ if (Question == NULL) {\r
+ return EFI_NOT_FOUND;\r
+ }\r
+\r
+ //\r
+ // push the questions' value on to the expression stack\r
+ //\r
+ Value = &Question->HiiValue;\r
+ } else {\r
+ //\r
+ // BUGBUG: push 0 for EFI_IFR_QUESTION_REF3_2 and EFI_IFR_QUESTION_REF3_3,\r
+ // since it is impractical to evaluate the value of a Question in another\r
+ // Hii Package list.\r
+ //\r
+ ZeroMem (Value, sizeof (EFI_HII_VALUE));\r
+ }\r
+ break;\r
+\r
+ case EFI_IFR_RULE_REF_OP:\r
+ //\r
+ // Find expression for this rule\r
+ //\r
+ RuleExpression = RuleIdToExpression (Form, OpCode->RuleId);\r
+ if (RuleExpression == NULL) {\r
+ return EFI_NOT_FOUND;\r
+ }\r
+\r
+ //\r
+ // Evaluate this rule expression\r
+ //\r
+ Status = EvaluateExpression (FormSet, Form, RuleExpression);\r
+ if (EFI_ERROR (Status)) {\r
+ return Status;\r
+ }\r
+\r
+ Value = &RuleExpression->Result;\r
+ break;\r
+\r
+ case EFI_IFR_STRING_REF1_OP:\r
+ Value->Type = EFI_IFR_TYPE_STRING;\r
+ Value->Value.string = OpCode->Value.Value.string;\r
+ break;\r
+\r
+ //\r
+ // Constant\r
+ //\r
+ case EFI_IFR_TRUE_OP:\r
+ case EFI_IFR_FALSE_OP:\r
+ case EFI_IFR_ONE_OP:\r
+ case EFI_IFR_ONES_OP:\r
+ case EFI_IFR_UINT8_OP:\r
+ case EFI_IFR_UINT16_OP:\r
+ case EFI_IFR_UINT32_OP:\r
+ case EFI_IFR_UINT64_OP:\r
+ case EFI_IFR_UNDEFINED_OP:\r
+ case EFI_IFR_VERSION_OP:\r
+ case EFI_IFR_ZERO_OP:\r
+ Value = &OpCode->Value;\r
+ break;\r
+\r
+ //\r
+ // unary-op\r
+ //\r
+ case EFI_IFR_LENGTH_OP:\r
+ Status = PopExpression (Value);\r
+ if (EFI_ERROR (Status)) {\r
+ return Status;\r
+ }\r
+ if (Value->Type != EFI_IFR_TYPE_STRING) {\r
+ return EFI_INVALID_PARAMETER;\r
+ }\r
+\r
+ StrPtr = GetToken (Value->Value.string, FormSet->HiiHandle);\r
+ if (StrPtr == NULL) {\r
+ return EFI_INVALID_PARAMETER;\r
+ }\r
+\r
+ Value->Type = EFI_IFR_TYPE_NUM_SIZE_64;\r
+ Value->Value.u64 = StrLen (StrPtr);\r
+ gBS->FreePool (StrPtr);\r
+ break;\r
+\r
+ case EFI_IFR_NOT_OP:\r
+ Status = PopExpression (Value);\r
+ if (EFI_ERROR (Status)) {\r
+ return Status;\r
+ }\r
+ if (Value->Type != EFI_IFR_TYPE_BOOLEAN) {\r
+ return EFI_INVALID_PARAMETER;\r
+ }\r
+ Value->Value.b = (BOOLEAN) (!Value->Value.b);\r
+ break;\r
+\r
+ case EFI_IFR_QUESTION_REF2_OP:\r
+ //\r
+ // Pop an expression from the expression stack\r
+ //\r
+ Status = PopExpression (Value);\r
+ if (EFI_ERROR (Status)) {\r
+ return Status;\r
+ }\r
+\r
+ //\r
+ // Validate the expression value\r
+ //\r
+ if ((Value->Type > EFI_IFR_TYPE_NUM_SIZE_64) || (Value->Value.u64 > 0xffff)) {\r
+ return EFI_NOT_FOUND;\r
+ }\r
+\r
+ Question = IdToQuestion (FormSet, Form, Value->Value.u16);\r
+ if (Question == NULL) {\r
+ return EFI_NOT_FOUND;\r
+ }\r
+\r
+ Value = &Question->HiiValue;\r
+ break;\r
+\r
+ case EFI_IFR_STRING_REF2_OP:\r
+ //\r
+ // Pop an expression from the expression stack\r
+ //\r
+ Status = PopExpression (Value);\r
+ if (EFI_ERROR (Status)) {\r
+ return Status;\r
+ }\r
+\r
+ //\r
+ // Validate the expression value\r
+ //\r
+ if ((Value->Type > EFI_IFR_TYPE_NUM_SIZE_64) || (Value->Value.u64 > 0xffff)) {\r
+ return EFI_NOT_FOUND;\r
+ }\r
+\r
+ Value->Type = EFI_IFR_TYPE_STRING;\r
+ StrPtr = GetToken (Value->Value.u16, FormSet->HiiHandle);\r
+ if (StrPtr == NULL) {\r
+ //\r
+ // If String not exit, push an empty string\r
+ //\r
+ Value->Value.string = NewString (gEmptyString, FormSet->HiiHandle);\r
+ } else {\r
+ Index = (UINT16) Value->Value.u64;\r
+ Value->Value.string = Index;\r
+ gBS->FreePool (StrPtr);\r
+ }\r
+ break;\r
+\r
+ case EFI_IFR_TO_BOOLEAN_OP:\r
+ //\r
+ // Pop an expression from the expression stack\r
+ //\r
+ Status = PopExpression (Value);\r
+ if (EFI_ERROR (Status)) {\r
+ return Status;\r
+ }\r
+\r
+ //\r
+ // Convert an expression to a Boolean\r
+ //\r
+ if (Value->Type <= EFI_IFR_TYPE_DATE) {\r
+ //\r
+ // When converting from an unsigned integer, zero will be converted to\r
+ // FALSE and any other value will be converted to TRUE.\r
+ //\r
+ Value->Value.b = (BOOLEAN) ((Value->Value.u64) ? TRUE : FALSE);\r
+\r
+ Value->Type = EFI_IFR_TYPE_BOOLEAN;\r
+ } else if (Value->Type == EFI_IFR_TYPE_STRING) {\r
+ //\r
+ // When converting from a string, if case-insensitive compare\r
+ // with "true" is True, then push True. If a case-insensitive compare\r
+ // with "false" is True, then push False.\r
+ //\r
+ StrPtr = GetToken (Value->Value.string, FormSet->HiiHandle);\r
+ if (StrPtr == NULL) {\r
+ return EFI_INVALID_PARAMETER;\r
+ }\r
+\r
+ if ((StrCmp (StrPtr, L"true") == 0) || (StrCmp (StrPtr, L"false") == 0)){\r
+ Value->Value.b = TRUE;\r
+ } else {\r
+ Value->Value.b = FALSE;\r
+ }\r
+ gBS->FreePool (StrPtr);\r
+ Value->Type = EFI_IFR_TYPE_BOOLEAN;\r
+ }\r
+ break;\r
+\r
+ case EFI_IFR_TO_STRING_OP:\r
+ Status = IfrToString (FormSet, OpCode->Format, Value);\r
+ break;\r
+\r
+ case EFI_IFR_TO_UINT_OP:\r
+ Status = IfrToUint (FormSet, Value);\r
+ break;\r
+\r
+ case EFI_IFR_TO_LOWER_OP:\r
+ case EFI_IFR_TO_UPPER_OP:\r
+ Status = InitializeUnicodeCollationProtocol ();\r
+ if (EFI_ERROR (Status)) {\r
+ return Status;\r
+ }\r
+\r
+ Status = PopExpression (Value);\r
+ if (EFI_ERROR (Status)) {\r
+ return Status;\r
+ }\r
+\r
+ if (Value->Type != EFI_IFR_TYPE_STRING) {\r
+ return EFI_UNSUPPORTED;\r
+ }\r
+\r
+ StrPtr = GetToken (Value->Value.string, FormSet->HiiHandle);\r
+ if (StrPtr == NULL) {\r
+ return EFI_NOT_FOUND;\r
+ }\r
+\r
+ if (OpCode->Operand == EFI_IFR_TO_LOWER_OP) {\r
+ mUnicodeCollation->StrLwr (mUnicodeCollation, StrPtr);\r
+ } else {\r
+ mUnicodeCollation->StrUpr (mUnicodeCollation, StrPtr);\r
+ }\r
+ Value->Value.string = NewString (StrPtr, FormSet->HiiHandle);\r
+ gBS->FreePool (StrPtr);\r
+ break;\r
+\r
+ case EFI_IFR_BITWISE_NOT_OP:\r
+ //\r
+ // Pop an expression from the expression stack\r
+ //\r
+ Status = PopExpression (Value);\r
+ if (EFI_ERROR (Status)) {\r
+ return Status;\r
+ }\r
+ if (Value->Type > EFI_IFR_TYPE_DATE) {\r
+ return EFI_INVALID_PARAMETER;\r
+ }\r
+\r
+ Value->Type = EFI_IFR_TYPE_NUM_SIZE_64;\r
+ Value->Value.u64 = ~Value->Value.u64;\r
+ break;\r
+\r
+ //\r
+ // binary-op\r
+ //\r
+ case EFI_IFR_ADD_OP:\r
+ case EFI_IFR_SUBTRACT_OP:\r
+ case EFI_IFR_MULTIPLY_OP:\r
+ case EFI_IFR_DIVIDE_OP:\r
+ case EFI_IFR_MODULO_OP:\r
+ case EFI_IFR_BITWISE_AND_OP:\r
+ case EFI_IFR_BITWISE_OR_OP:\r
+ case EFI_IFR_SHIFT_LEFT_OP:\r
+ case EFI_IFR_SHIFT_RIGHT_OP:\r
+ //\r
+ // Pop an expression from the expression stack\r
+ //\r
+ Status = PopExpression (&Data2);\r
+ if (EFI_ERROR (Status)) {\r
+ return Status;\r
+ }\r
+ if (Data2.Type > EFI_IFR_TYPE_DATE) {\r
+ return EFI_INVALID_PARAMETER;\r
+ }\r
+\r
+ //\r
+ // Pop another expression from the expression stack\r
+ //\r
+ Status = PopExpression (&Data1);\r
+ if (EFI_ERROR (Status)) {\r
+ return Status;\r
+ }\r
+ if (Data1.Type > EFI_IFR_TYPE_DATE) {\r
+ return EFI_INVALID_PARAMETER;\r
+ }\r
+\r
+ Value->Type = EFI_IFR_TYPE_NUM_SIZE_64;\r
+\r
+ switch (OpCode->Operand) {\r
+ case EFI_IFR_ADD_OP:\r
+ Value->Value.u64 = Data1.Value.u64 + Data2.Value.u64;\r
+ break;\r
+\r
+ case EFI_IFR_SUBTRACT_OP:\r
+ Value->Value.u64 = Data1.Value.u64 - Data2.Value.u64;\r
+ break;\r
+\r
+ case EFI_IFR_MULTIPLY_OP:\r
+ Value->Value.u64 = MultU64x32 (Data1.Value.u64, (UINT32) Data2.Value.u64);\r
+ break;\r
+\r
+ case EFI_IFR_DIVIDE_OP:\r
+ Value->Value.u64 = DivU64x32 (Data1.Value.u64, (UINT32) Data2.Value.u64);\r
+ break;\r
+\r
+ case EFI_IFR_MODULO_OP:\r
+ DivU64x32Remainder (Data1.Value.u64, (UINT32) Data2.Value.u64, &TempValue);\r
+ Value->Value.u64 = TempValue;\r
+ break;\r
+\r
+ case EFI_IFR_BITWISE_AND_OP:\r
+ Value->Value.u64 = Data1.Value.u64 & Data2.Value.u64;\r
+ break;\r
+\r
+ case EFI_IFR_BITWISE_OR_OP:\r
+ Value->Value.u64 = Data1.Value.u64 | Data2.Value.u64;\r
+ break;\r
+\r
+ case EFI_IFR_SHIFT_LEFT_OP:\r
+ Value->Value.u64 = LShiftU64 (Data1.Value.u64, (UINTN) Data2.Value.u64);\r
+ break;\r
+\r
+ case EFI_IFR_SHIFT_RIGHT_OP:\r
+ Value->Value.u64 = RShiftU64 (Data1.Value.u64, (UINTN) Data2.Value.u64);\r
+ break;\r
+\r
+ default:\r
+ break;\r
+ }\r
+ break;\r
+\r
+ case EFI_IFR_AND_OP:\r
+ case EFI_IFR_OR_OP:\r
+ //\r
+ // Two Boolean operator\r
+ //\r
+ Status = PopExpression (&Data2);\r
+ if (EFI_ERROR (Status)) {\r
+ return Status;\r
+ }\r
+ if (Data2.Type != EFI_IFR_TYPE_BOOLEAN) {\r
+ return EFI_INVALID_PARAMETER;\r
+ }\r
+\r
+ //\r
+ // Pop another expression from the expression stack\r
+ //\r
+ Status = PopExpression (&Data1);\r
+ if (EFI_ERROR (Status)) {\r
+ return Status;\r
+ }\r
+ if (Data1.Type != EFI_IFR_TYPE_BOOLEAN) {\r
+ return EFI_INVALID_PARAMETER;\r
+ }\r
+\r
+ if (OpCode->Operand == EFI_IFR_AND_OP) {\r
+ Value->Value.b = (BOOLEAN) (Data1.Value.b && Data2.Value.b);\r
+ } else {\r
+ Value->Value.b = (BOOLEAN) (Data1.Value.b || Data2.Value.b);\r
+ }\r
+ break;\r
+\r
+ case EFI_IFR_EQUAL_OP:\r
+ case EFI_IFR_NOT_EQUAL_OP:\r
+ case EFI_IFR_GREATER_EQUAL_OP:\r
+ case EFI_IFR_GREATER_THAN_OP:\r
+ case EFI_IFR_LESS_EQUAL_OP:\r
+ case EFI_IFR_LESS_THAN_OP:\r
+ //\r
+ // Compare two integer, string, boolean or date/time\r
+ //\r
+ Status = PopExpression (&Data2);\r
+ if (EFI_ERROR (Status)) {\r
+ return Status;\r
+ }\r
+ if (Data2.Type > EFI_IFR_TYPE_BOOLEAN && Data2.Type != EFI_IFR_TYPE_STRING) {\r
+ return EFI_INVALID_PARAMETER;\r
+ }\r
+\r
+ //\r
+ // Pop another expression from the expression stack\r
+ //\r
+ Status = PopExpression (&Data1);\r
+ if (EFI_ERROR (Status)) {\r
+ return Status;\r
+ }\r
+\r
+ Result = CompareHiiValue (&Data1, &Data2, FormSet->HiiHandle);\r
+ if (Result == EFI_INVALID_PARAMETER) {\r
+ return EFI_INVALID_PARAMETER;\r
+ }\r
+\r
+ switch (OpCode->Operand) {\r
+ case EFI_IFR_EQUAL_OP:\r
+ Value->Value.b = (BOOLEAN) ((Result == 0) ? TRUE : FALSE);\r
+ break;\r
+\r
+ case EFI_IFR_NOT_EQUAL_OP:\r
+ Value->Value.b = (BOOLEAN) ((Result == 0) ? TRUE : FALSE);\r
+ break;\r
+\r
+ case EFI_IFR_GREATER_EQUAL_OP:\r
+ Value->Value.b = (BOOLEAN) ((Result >= 0) ? TRUE : FALSE);\r
+ break;\r
+\r
+ case EFI_IFR_GREATER_THAN_OP:\r
+ Value->Value.b = (BOOLEAN) ((Result > 0) ? TRUE : FALSE);\r
+ break;\r
+\r
+ case EFI_IFR_LESS_EQUAL_OP:\r
+ Value->Value.b = (BOOLEAN) ((Result <= 0) ? TRUE : FALSE);\r
+ break;\r
+\r
+ case EFI_IFR_LESS_THAN_OP:\r
+ Value->Value.b = (BOOLEAN) ((Result < 0) ? TRUE : FALSE);\r
+ break;\r
+\r
+ default:\r
+ break;\r
+ }\r
+ break;\r
+\r
+ case EFI_IFR_MATCH_OP:\r
+ Status = IfrMatch (FormSet, Value);\r
+ break;\r
+\r
+ case EFI_IFR_CATENATE_OP:\r
+ Status = IfrCatenate (FormSet, Value);\r
+ break;\r
+\r
+ //\r
+ // ternary-op\r
+ //\r
+ case EFI_IFR_CONDITIONAL_OP:\r
+ //\r
+ // Pop third expression from the expression stack\r
+ //\r
+ Status = PopExpression (&Data3);\r
+ if (EFI_ERROR (Status)) {\r
+ return Status;\r
+ }\r
+\r
+ //\r
+ // Pop second expression from the expression stack\r
+ //\r
+ Status = PopExpression (&Data2);\r
+ if (EFI_ERROR (Status)) {\r
+ return Status;\r
+ }\r
+\r
+ //\r
+ // Pop first expression from the expression stack\r
+ //\r
+ Status = PopExpression (&Data1);\r
+ if (EFI_ERROR (Status)) {\r
+ return Status;\r
+ }\r
+ if (Data1.Type != EFI_IFR_TYPE_BOOLEAN) {\r
+ return EFI_INVALID_PARAMETER;\r
+ }\r
+\r
+ if (Data1.Value.b) {\r
+ Value = &Data3;\r
+ } else {\r
+ Value = &Data2;\r
+ }\r
+ break;\r
+\r
+ case EFI_IFR_FIND_OP:\r
+ Status = IfrFind (FormSet, OpCode->Format, Value);\r
+ break;\r
+\r
+ case EFI_IFR_MID_OP:\r
+ Status = IfrMid (FormSet, Value);\r
+ break;\r
+\r
+ case EFI_IFR_TOKEN_OP:\r
+ Status = IfrToken (FormSet, Value);\r
+ break;\r
+\r
+ case EFI_IFR_SPAN_OP:\r
+ Status = IfrSpan (FormSet, OpCode->Flags, Value);\r
+ break;\r
+\r
+ default:\r
+ break;\r
+ }\r
+ if (EFI_ERROR (Status)) {\r
+ return Status;\r
+ }\r
+\r
+ Status = PushExpression (Value);\r
+ if (EFI_ERROR (Status)) {\r
+ return Status;\r
+ }\r
+ }\r
+\r
+ //\r
+ // Pop the final result from expression stack\r
+ //\r
+ Value = &Data1;\r
+ Status = PopExpression (Value);\r
+ if (EFI_ERROR (Status)) {\r
+ return Status;\r
+ }\r
+\r
+ //\r
+ // After evaluating an expression, there should be only one value left on the expression stack\r
+ //\r
+ if (PopExpression (Value) != EFI_ACCESS_DENIED) {\r
+ return EFI_INVALID_PARAMETER;\r
+ }\r
+\r
+ CopyMem (&Expression->Result, Value, sizeof (EFI_HII_VALUE));\r
+\r
+ return EFI_SUCCESS;\r
+}\r