/** @file Utility functions for expression evaluation. Copyright (c) 2011-2019, Intel Corporation. All rights reserved.
SPDX-License-Identifier: BSD-2-Clause-Patent **/ #include "IfrParse.h" #define gEmptyString L"" // // 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; UINTN mExpressionEvaluationStackOffset = 0; EFI_HII_VALUE *mCurrentExpressionStack = NULL; EFI_HII_VALUE *mCurrentExpressionEnd = NULL; EFI_HII_VALUE *mCurrentExpressionPointer = NULL; EFI_HII_VALUE *mMapExpressionListStack = NULL; EFI_HII_VALUE *mMapExpressionListEnd = NULL; EFI_HII_VALUE *mMapExpressionListPointer = NULL; /** Get Value for given Name from a NameValue Storage. @param Storage The NameValue Storage. @param Name The Name. @param Value The retured Value. @retval EFI_SUCCESS Value found for given Name. @retval EFI_NOT_FOUND No such Name found in NameValue storage. **/ EFI_STATUS GetValueByName ( IN FORMSET_STORAGE *Storage, IN CHAR16 *Name, IN OUT CHAR16 **Value ) { LIST_ENTRY *Link; NAME_VALUE_NODE *Node; *Value = NULL; Link = GetFirstNode (&Storage->NameValueListHead); while (!IsNull (&Storage->NameValueListHead, Link)) { Node = NAME_VALUE_NODE_FROM_LINK (Link); if (FceStrCmp (Name, Node->Name) == 0) { NewStringCpy (Value, Node->EditValue); return EFI_SUCCESS; } Link = GetNextNode (&Storage->NameValueListHead, Link); } return EFI_NOT_FOUND; } /** Grow size of the stack. This is an internal function. @param Stack On input: old stack; On output: new stack @param StackPtr On input: old stack pointer; On output: new stack pointer @param StackEnd 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. **/ 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 // 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 StackEnd 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 @param StackPtr On input: old stack pointer; On output: new stack pointer @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 EFI_HII_VALUE *Stack, IN OUT EFI_HII_VALUE **StackPtr, 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. **/ VOID ResetCurrentExpressionStack ( VOID ) { mCurrentExpressionPointer = mCurrentExpressionStack; } /** Push current expression onto the Stack @param Pointer Pointer to current expression. @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 PushCurrentExpression ( IN VOID *Pointer ) { EFI_HII_VALUE Data; Data.Type = EFI_IFR_TYPE_NUM_SIZE_64; Data.Value.u64 = (UINT64) (UINTN) Pointer; return PushStack ( &mCurrentExpressionStack, &mCurrentExpressionPointer, &mCurrentExpressionEnd, &Data ); } /** Pop current expression from the Stack @param Pointer Pointer to current expression to be 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 PopCurrentExpression ( OUT VOID **Pointer ) { EFI_STATUS Status; EFI_HII_VALUE Data; Status = PopStack ( mCurrentExpressionStack, &mCurrentExpressionPointer, &Data ); *Pointer = (VOID *) (UINTN) Data.Value.u64; return Status; } /** Reset stack pointer to begin of the stack. **/ VOID ResetMapExpressionListStack ( VOID ) { mMapExpressionListPointer = mMapExpressionListStack; } /** Push the list of map expression onto the Stack @param Pointer Pointer to the list of map expression to be pushed. @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 PushMapExpressionList ( IN VOID *Pointer ) { EFI_HII_VALUE Data; Data.Type = EFI_IFR_TYPE_NUM_SIZE_64; Data.Value.u64 = (UINT64) (UINTN) Pointer; return PushStack ( &mMapExpressionListStack, &mMapExpressionListPointer, &mMapExpressionListEnd, &Data ); } /** Pop the list of map expression from the Stack @param Pointer Pointer to the list of map expression to be 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 PopMapExpressionList ( OUT VOID **Pointer ) { EFI_STATUS Status; EFI_HII_VALUE Data; Status = PopStack ( mMapExpressionListStack, &mMapExpressionListPointer, &Data ); *Pointer = (VOID *) (UINTN) Data.Value.u64; return Status; } /** Reset stack pointer to begin of the stack. **/ 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, &Data ); *Operand = Data.Value.u8; return Status; } /** 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 + mExpressionEvaluationStackOffset, &mExpressionEvaluationStackPointer, Value ); } /** Get current stack offset from stack start. @return Stack offset to stack start. **/ UINTN SaveExpressionEvaluationStackOffset ( ) { UINTN TempStackOffset; TempStackOffset = mExpressionEvaluationStackOffset; mExpressionEvaluationStackOffset = mExpressionEvaluationStackPointer - mExpressionEvaluationStack; return TempStackOffset; } /** Restore stack offset based on input stack offset @param StackOffset Offset to stack start. **/ VOID RestoreExpressionEvaluationStackOffset ( UINTN StackOffset ) { mExpressionEvaluationStackOffset = StackOffset; } /** 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; } /** Convert the input Unicode character to upper. @param String Th Unicode character to be converted. **/ VOID IfrStrToUpper ( IN 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 *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); break; case EFI_IFR_TYPE_STRING: CopyMem (Result, &Value, sizeof (EFI_HII_VALUE)); return EFI_SUCCESS; case EFI_IFR_TYPE_BOOLEAN: 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; 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->UnicodeBinary); if (String == NULL) { return EFI_NOT_FOUND; } IfrStrToUpper (String); StringPtr = StrStr (String, L"0X"); if (StringPtr != NULL) { // // Hex string // Result->Value.u64 = FceStrHexToUint64 (String); } else { // // decimal string // Result->Value.u64 = FceStrDecimalToUint64 (String); } 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->UnicodeBinary); if (String[Index] == NULL) { Status = EFI_NOT_FOUND; goto Done; } } Size = FceStrSize (String[0]); StringPtr= AllocatePool (FceStrSize (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: if (String[0] != NULL) { FreePool (String[0]); } if (String[1] != NULL) { FreePool (String[1]); } if (StringPtr != NULL) { FreePool (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->UnicodeBinary); if (String [Index] == NULL) { Status = EFI_NOT_FOUND; goto Done; } } Result->Type = EFI_IFR_TYPE_BOOLEAN; Result->Value.b = MetaiMatch (String[0], String[1]); Done: if (String[0] != NULL) { FreePool (String[0]); } if (String[1] != NULL) { FreePool (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->UnicodeBinary); if (String[Index] == 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 >= FceStrLen (String[1])) { Result->Value.u64 = 0xFFFFFFFFFFFFFFFFULL; } else { StringPtr = StrStr (String[1] + Base, String[0]); Result->Value.u64 = (StringPtr == NULL) ? 0xFFFFFFFFFFFFFFFFULL : (StringPtr - String[1]); } Done: if (String[0] != NULL) { FreePool (String[0]); } if (String[1] != NULL) { FreePool (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->UnicodeBinary); if (String == NULL) { return EFI_NOT_FOUND; } if ((Length == 0) || (Base >= FceStrLen (String))) { SubString = gEmptyString; } else { SubString = String + Base; if ((Base + Length) < FceStrLen (String)) { SubString[Length] = L'\0'; } } Result->Type = EFI_IFR_TYPE_STRING; //Result->Value.string = NewString (SubString, FormSet->HiiHandle); 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->UnicodeBinary); if (String[Index] == 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 + FceStrLen (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: if (String[0] != NULL) { FreePool (String[0]); } if (String[1] != NULL) { FreePool (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->UnicodeBinary); if (String [Index] == NULL) { Status = EFI_NOT_FOUND; goto Done; } } if (Base >= FceStrLen (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: if (String[0] != NULL) { FreePool (String[0]); } if (String[1] != NULL) { FreePool (String[1]); } return Status; } /** Zero extend integer/boolean/date/time to UINT64 for comparing. @param Value HII Value to be converted. **/ 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 FormSet The pointer to the Formset. @retval EFI_INVALID_PARAMETER Could not perform compare on two values. @retval 0 Two operators equal. @return Positive value if Value1 is greater than Value2. @retval Negative value if Value1 is less than Value2. **/ INTN CompareHiiValue ( IN EFI_HII_VALUE *Value1, IN EFI_HII_VALUE *Value2, IN FORM_BROWSER_FORMSET *FormSet ) { 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, FormSet->UnicodeBinary); if (Str1 == NULL) { // // String not found // return EFI_INVALID_PARAMETER; } Str2 = GetToken (Value2->Value.string, FormSet->UnicodeBinary); if (Str2 == NULL) { FreePool (Str1); return EFI_INVALID_PARAMETER; } Result = FceStrCmp (Str1, Str2); FreePool (Str1); 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; } /** Tell whether this Operand is an constant Expression or not @param Operand Operand of an IFR OpCode. @retval TRUE This is an Expression OpCode. @retval FALSE Not an Expression OpCode. **/ BOOLEAN IsConstantExpressionOpCode ( IN UINT8 Operand ) { if ((Operand == EFI_IFR_EQ_ID_VAL_OP) || (Operand == EFI_IFR_EQ_ID_ID_OP) || (Operand == EFI_IFR_EQ_ID_VAL_LIST_OP )|| (Operand == EFI_IFR_QUESTION_REF1_OP) || (Operand == EFI_IFR_QUESTION_REF2_OP) || (Operand == EFI_IFR_QUESTION_REF3_OP) || (Operand == EFI_IFR_THIS_OP ) || (Operand == EFI_IFR_SECURITY_OP) || (Operand == EFI_IFR_GET_OP) || (Operand == EFI_IFR_SET_OP) ) { return FALSE; } else { return TRUE; } } /** Update the HiiValue of question from its variable. @param FormSet FormSet associated with this expression. @param Question The pointer to the Question @return EFI_SUCCESS @return EFI_NOT_FOUND **/ EFI_STATUS UpdateHiiValue ( IN FORM_BROWSER_FORMSET *FormSet, IN FORM_BROWSER_STATEMENT *Question ) { EFI_STATUS Status; FORMSET_STORAGE *VarList; UINT8 *VarBuffer; EFI_HII_VALUE *HiiValue; Status = EFI_SUCCESS; HiiValue = &Question->HiiValue; Status = SearchVarStorage ( Question, NULL, Question->VarStoreInfo.VarOffset, FormSet->StorageListHead, (CHAR8 **)&VarBuffer, &VarList ); if (EFI_ERROR(Status)) { return Status; } if (Question->QuestionReferToBitField) { GetBitsQuestionValue (Question, VarBuffer, &HiiValue->Value.u32); } else { CopyMem (&HiiValue->Value.u64, VarBuffer, Question->StorageWidth); } return Status; } /** Evaluate the result of a HII expression. If Expression is NULL, then ASSERT. @param FormSet FormSet associated with this expression. @param Form Form associated with this expression. @param Expression Expression to be evaluated. @param ConstantExpression The pointer to the flag of constant expression. If constant, will return TRUE. @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, IN OUT BOOLEAN *ConstantExpression ) { 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; LIST_ENTRY *SubExpressionLink; FORM_EXPRESSION *SubExpression; UINTN StackOffset; UINTN TempLength; CHAR16 TempStr[5]; UINT8 DigitUint8; UINT8 *TempBuffer; // // Save current stack offset. // StackOffset = SaveExpressionEvaluationStackOffset (); ASSERT (Expression != NULL); 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; // // Check whether it is a constant expression or not // if (*ConstantExpression) { *ConstantExpression = IsConstantExpressionOpCode (OpCode->Operand); } switch (OpCode->Operand) { // // Built-in functions // case EFI_IFR_EQ_ID_VAL_OP: Question = IdToQuestion (FormSet, Form, OpCode->QuestionId); if (Question == NULL) { Status = EFI_NOT_FOUND; goto Done; } UpdateHiiValue (FormSet, Question); Result = CompareHiiValue (&Question->HiiValue, &OpCode->Value, FormSet); if ((EFI_STATUS)Result == EFI_INVALID_PARAMETER) { Status = EFI_INVALID_PARAMETER; goto Done; } 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) { Status = EFI_NOT_FOUND; goto Done; } Question2 = IdToQuestion (FormSet, Form, OpCode->QuestionId2); if (Question2 == NULL) { Status = EFI_NOT_FOUND; goto Done; } UpdateHiiValue (FormSet, Question); UpdateHiiValue (FormSet, Question2); Result = CompareHiiValue (&Question->HiiValue, &Question2->HiiValue, FormSet); if ((EFI_STATUS)Result == EFI_INVALID_PARAMETER) { Status = EFI_INVALID_PARAMETER; goto Done; } Value->Value.b = (BOOLEAN) ((Result == 0) ? TRUE : FALSE); break; case EFI_IFR_EQ_ID_VAL_LIST_OP: Question = IdToQuestion (FormSet, Form, OpCode->QuestionId); if (Question == NULL) { Status = EFI_NOT_FOUND; goto Done; } UpdateHiiValue (FormSet, Question); 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)) { goto Done; } Status = PushExpression (Value); break; case EFI_IFR_QUESTION_REF1_OP: case EFI_IFR_THIS_OP: Question = IdToQuestion (FormSet, Form, OpCode->QuestionId); if (Question == NULL) { Status = EFI_NOT_FOUND; goto Done; } UpdateHiiValue (FormSet, Question); Value = &Question->HiiValue; break; case EFI_IFR_SECURITY_OP: // // Do nothing, as no need for static scaning // break; case EFI_IFR_GET_OP: // // Get Value from VarStore buffer, EFI VarStore, Name/Value VarStore. // Value->Type = EFI_IFR_TYPE_UNDEFINED; Value->Value.u8 = 0; if (OpCode->VarStorage != NULL) { switch (OpCode->VarStorage->Type) { case EFI_IFR_VARSTORE_OP: // // Get value from Buffer // Value->Type = OpCode->ValueType; CopyMem (&Value->Value, OpCode->VarStorage->Buffer + OpCode->VarStoreInfo.VarOffset, OpCode->ValueWidth); break; case EFI_IFR_VARSTORE_EFI_OP: // // Get value from Buffer // if (OpCode->VarStorage->NewEfiVarstore) { Value->Type = OpCode->ValueType; CopyMem (&Value->Value, OpCode->VarStorage->Buffer + OpCode->VarStoreInfo.VarOffset, OpCode->ValueWidth); } else { CopyMem (&Value->Value, OpCode->VarStorage->Buffer, OpCode->ValueWidth); } break; case EFI_HII_VARSTORE_NAME_VALUE: if (OpCode->ValueType != EFI_IFR_TYPE_STRING) { // // Get value from string except for STRING value. // Status = GetValueByName (OpCode->VarStorage, OpCode->ValueName, &StrPtr); if (!EFI_ERROR (Status)) { ASSERT (StrPtr != NULL); TempLength = FceStrLen (StrPtr); if (OpCode->ValueWidth >= ((TempLength + 1) / 2)) { Value->Type = OpCode->ValueType; TempBuffer = (UINT8 *) &Value->Value; ZeroMem (TempStr, sizeof (TempStr)); for (Index = 0; Index < TempLength; Index ++) { TempStr[0] = StrPtr[TempLength - Index - 1]; DigitUint8 = (UINT8) FceStrHexToUint64 (TempStr); if ((Index & 1) == 0) { TempBuffer [Index/2] = DigitUint8; } else { TempBuffer [Index/2] = (UINT8) ((DigitUint8 << 4) + TempBuffer [Index/2]); } } } free (StrPtr); StrPtr = NULL; } } break; default: // // Not recognize storage. // Status = EFI_UNSUPPORTED; goto Done; } } 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)) { goto Done; } // // Validate the expression value // if ((Value->Type > EFI_IFR_TYPE_NUM_SIZE_64) || (Value->Value.u64 > 0xffff)) { Status = EFI_NOT_FOUND; goto Done; } Question = IdToQuestion (FormSet, Form, Value->Value.u16); if (Question == NULL) { Status = EFI_NOT_FOUND; goto Done; } // // 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) { Status = EFI_NOT_FOUND; goto Done; } // // Evaluate this rule expression // Status = EvaluateExpression (FormSet, Form, RuleExpression, ConstantExpression); if (EFI_ERROR (Status)) { goto Done; } 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)) { goto Done; } if (Value->Type != EFI_IFR_TYPE_STRING) { Status = EFI_INVALID_PARAMETER; goto Done; } StrPtr = GetToken (Value->Value.string, FormSet->UnicodeBinary); if (StrPtr == NULL) { Status = EFI_INVALID_PARAMETER; goto Done; } Value->Type = EFI_IFR_TYPE_NUM_SIZE_64; Value->Value.u64 = FceStrLen (StrPtr); FreePool (StrPtr); break; case EFI_IFR_NOT_OP: Status = PopExpression (Value); if (EFI_ERROR (Status)) { goto Done; } if (Value->Type != EFI_IFR_TYPE_BOOLEAN) { Status = EFI_INVALID_PARAMETER; goto Done; } 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)) { goto Done; } // // Validate the expression value // if ((Value->Type > EFI_IFR_TYPE_NUM_SIZE_64) || (Value->Value.u64 > 0xffff)) { Status = EFI_NOT_FOUND; goto Done; } Question = IdToQuestion (FormSet, Form, Value->Value.u16); if (Question == NULL) { Status = EFI_NOT_FOUND; goto Done; } Value = &Question->HiiValue; break; case EFI_IFR_STRING_REF2_OP: // // Pop an expression from the expression stack // Status = PopExpression (Value); if (EFI_ERROR (Status)) { goto Done; } // // Validate the expression value // if ((Value->Type > EFI_IFR_TYPE_NUM_SIZE_64) || (Value->Value.u64 > 0xffff)) { Status = EFI_NOT_FOUND; goto Done; } Value->Type = EFI_IFR_TYPE_STRING; StrPtr = GetToken (Value->Value.u16, FormSet->UnicodeBinary); 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; FreePool (StrPtr); } break; case EFI_IFR_TO_BOOLEAN_OP: // // Pop an expression from the expression stack // Status = PopExpression (Value); if (EFI_ERROR (Status)) { goto Done; } // // 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 != 0); 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. Otherwise, push Undefined. // StrPtr = GetToken (Value->Value.string, FormSet->UnicodeBinary); if (StrPtr == NULL) { Status = EFI_INVALID_PARAMETER; goto Done; } IfrStrToUpper (StrPtr); if (FceStrCmp (StrPtr, L"TRUE") == 0){ Value->Value.b = TRUE; } else if (FceStrCmp (StrPtr, L"FALSE") == 0) { Value->Value.b = FALSE; } else { Status = EFI_INVALID_PARAMETER; FreePool (StrPtr); goto Done; } 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 = PopExpression (Value); if (EFI_ERROR (Status)) { goto Done; } if (Value->Type != EFI_IFR_TYPE_STRING) { Status = EFI_UNSUPPORTED; goto Done; } StrPtr = GetToken (Value->Value.string, FormSet->UnicodeBinary); if (StrPtr == NULL) { Status = EFI_NOT_FOUND; goto Done; } // // Do nothing here, as these two Opcode are to change or update the String Package // FreePool (StrPtr); break; case EFI_IFR_BITWISE_NOT_OP: // // Pop an expression from the expression stack // Status = PopExpression (Value); if (EFI_ERROR (Status)) { goto Done; } if (Value->Type > EFI_IFR_TYPE_DATE) { Status = EFI_INVALID_PARAMETER; goto Done; } Value->Type = EFI_IFR_TYPE_NUM_SIZE_64; Value->Value.u64 = ~Value->Value.u64; break; case EFI_IFR_SET_OP: // // Pop an expression from the expression stack // Status = PopExpression (Value); if (EFI_ERROR (Status)) { goto Done; } Data1.Type = EFI_IFR_TYPE_BOOLEAN; Data1.Value.b = FALSE; // // Not support SetOpcode for static scaning // if (OpCode->VarStorage != NULL) { switch (OpCode->VarStorage->Type) { case EFI_IFR_VARSTORE_OP: CopyMem (OpCode->VarStorage->Buffer + OpCode->VarStoreInfo.VarOffset, &Value->Value, OpCode->ValueWidth); Data1.Value.b = TRUE; break; case EFI_IFR_VARSTORE_EFI_OP: if (OpCode->VarStorage->NewEfiVarstore) { CopyMem (OpCode->VarStorage->Buffer + OpCode->VarStoreInfo.VarOffset, &Value->Value, OpCode->ValueWidth); Data1.Value.b = TRUE; } else { CopyMem (OpCode->VarStorage->Buffer, &Value->Value, OpCode->ValueWidth); Data1.Value.b = TRUE; } break; case EFI_HII_VARSTORE_NAME_VALUE: break; break; default: // // Not recognize storage. // Status = EFI_UNSUPPORTED; goto Done; break; } Value = &Data1; } 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)) { goto Done; } if (Data2.Type > EFI_IFR_TYPE_DATE) { Status = EFI_INVALID_PARAMETER; goto Done; } // // Pop another expression from the expression stack // Status = PopExpression (&Data1); if (EFI_ERROR (Status)) { goto Done; } if (Data1.Type > EFI_IFR_TYPE_DATE) { Status = EFI_INVALID_PARAMETER; goto Done; } 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)) { goto Done; } if (Data2.Type != EFI_IFR_TYPE_BOOLEAN) { Status = EFI_INVALID_PARAMETER; goto Done; } // // Pop another expression from the expression stack // Status = PopExpression (&Data1); if (EFI_ERROR (Status)) { goto Done; } if (Data1.Type != EFI_IFR_TYPE_BOOLEAN) { Status = EFI_INVALID_PARAMETER; goto Done; } 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)) { goto Done; } if ((Data2.Type > EFI_IFR_TYPE_BOOLEAN) && (Data2.Type != EFI_IFR_TYPE_STRING)) { Status = EFI_INVALID_PARAMETER; goto Done; } // // Pop another expression from the expression stack // Status = PopExpression (&Data1); if (EFI_ERROR (Status)) { goto Done; } Result = CompareHiiValue (&Data1, &Data2, FormSet); if ((EFI_STATUS)Result == EFI_INVALID_PARAMETER) { Status = EFI_INVALID_PARAMETER; goto Done; } 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)) { goto Done; } // // Pop second expression from the expression stack // Status = PopExpression (&Data2); if (EFI_ERROR (Status)) { goto Done; } // // Pop first expression from the expression stack // Status = PopExpression (&Data1); if (EFI_ERROR (Status)) { goto Done; } if (Data1.Type != EFI_IFR_TYPE_BOOLEAN) { Status = EFI_INVALID_PARAMETER; goto Done; } 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; case EFI_IFR_MAP_OP: // // Pop the check value // Status = PopExpression (&Data1); if (EFI_ERROR (Status)) { goto Done; } // // Check MapExpression list is valid. // if (OpCode->MapExpressionList.ForwardLink == NULL) { Status = EFI_INVALID_PARAMETER; goto Done; } // // Go through map expression list. // SubExpressionLink = GetFirstNode(&OpCode->MapExpressionList); while (!IsNull (&OpCode->MapExpressionList, SubExpressionLink)) { SubExpression = FORM_EXPRESSION_FROM_LINK (SubExpressionLink); // // Evaluate the first expression in this pair. // Status = EvaluateExpression (FormSet, Form, SubExpression, ConstantExpression); if (EFI_ERROR (Status)) { goto Done; } // // Compare the expression value with current value // if (CompareHiiValue (&Data1, &SubExpression->Result, FormSet) == 0) { // // Try get the map value. // SubExpressionLink = GetNextNode (&OpCode->MapExpressionList, SubExpressionLink); if (IsNull (&OpCode->MapExpressionList, SubExpressionLink)) { Status = EFI_INVALID_PARAMETER; goto Done; } SubExpression = FORM_EXPRESSION_FROM_LINK (SubExpressionLink); Status = EvaluateExpression (FormSet, Form, SubExpression, ConstantExpression); if (EFI_ERROR (Status)) { goto Done; } Value = &SubExpression->Result; break; } // // Skip the second expression on this pair. // SubExpressionLink = GetNextNode (&OpCode->MapExpressionList, SubExpressionLink); if (IsNull (&OpCode->MapExpressionList, SubExpressionLink)) { Status = EFI_INVALID_PARAMETER; goto Done; } // // Goto the first expression on next pair. // SubExpressionLink = GetNextNode (&OpCode->MapExpressionList, SubExpressionLink); } // // No map value is found. // if (IsNull (&OpCode->MapExpressionList, SubExpressionLink)) { Value->Type = EFI_IFR_TYPE_UNDEFINED; Value->Value.u8 = 0; } break; default: break; } if (EFI_ERROR (Status)) { goto Done; } Status = PushExpression (Value); if (EFI_ERROR (Status)) { goto Done; } } // // Pop the final result from expression stack // Value = &Data1; Status = PopExpression (Value); if (EFI_ERROR (Status)) { goto Done; } // // After evaluating an expression, there should be only one value left on the expression stack // if (PopExpression (Value) != EFI_ACCESS_DENIED) { Status = EFI_INVALID_PARAMETER; } Done: RestoreExpressionEvaluationStackOffset (StackOffset); if (!EFI_ERROR (Status)) { CopyMem (&Expression->Result, Value, sizeof (EFI_HII_VALUE)); } return Status; }