/** @file Utility functions for expression evaluation. Copyright (c) 2007 - 2018, Intel Corporation. All rights reserved.
SPDX-License-Identifier: BSD-2-Clause-Patent **/ #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; 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; FORM_EXPRESSION **mFormExpressionStack = NULL; FORM_EXPRESSION **mFormExpressionEnd = NULL; FORM_EXPRESSION **mFormExpressionPointer = NULL; FORM_EXPRESSION **mStatementExpressionStack = NULL; FORM_EXPRESSION **mStatementExpressionEnd = NULL; FORM_EXPRESSION **mStatementExpressionPointer = NULL; FORM_EXPRESSION **mOptionExpressionStack = NULL; FORM_EXPRESSION **mOptionExpressionEnd = NULL; FORM_EXPRESSION **mOptionExpressionPointer = NULL; // // Unicode collation protocol interface // EFI_UNICODE_COLLATION_PROTOCOL *mUnicodeCollation = NULL; EFI_USER_MANAGER_PROTOCOL *mUserManager = NULL; /** 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)); if (Data->Type == EFI_IFR_TYPE_BUFFER) { (*StackPtr)->Buffer = AllocateCopyPool(Data->BufferLen, Data->Buffer); ASSERT ((*StackPtr)->Buffer != NULL); } *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; mFormExpressionPointer = mFormExpressionStack; mStatementExpressionPointer = mStatementExpressionStack; mOptionExpressionPointer = mOptionExpressionStack; } /** 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; } /** 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 @param MemberSize The stack member size. @retval EFI_SUCCESS Grow stack success. @retval EFI_OUT_OF_RESOURCES No enough memory for stack space. **/ EFI_STATUS GrowConditionalStack ( IN OUT FORM_EXPRESSION ***Stack, IN OUT FORM_EXPRESSION ***StackPtr, IN OUT FORM_EXPRESSION ***StackEnd, IN UINTN MemberSize ) { UINTN Size; FORM_EXPRESSION **NewStack; Size = EXPRESSION_STACK_SIZE_INCREMENT; if (*StackPtr != NULL) { Size = Size + (*StackEnd - *Stack); } NewStack = AllocatePool (Size * MemberSize); if (NewStack == NULL) { return EFI_OUT_OF_RESOURCES; } if (*StackPtr != NULL) { // // Copy from Old Stack to the New Stack // CopyMem ( NewStack, *Stack, (*StackEnd - *Stack) * MemberSize ); // // 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 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 PushConditionalStack ( IN OUT FORM_EXPRESSION ***Stack, IN OUT FORM_EXPRESSION ***StackPtr, IN OUT FORM_EXPRESSION ***StackEnd, IN FORM_EXPRESSION **Data ) { EFI_STATUS Status; // // Check for a stack overflow condition // if (*StackPtr >= *StackEnd) { // // Grow the stack // Status = GrowConditionalStack (Stack, StackPtr, StackEnd, sizeof (FORM_EXPRESSION *)); if (EFI_ERROR (Status)) { return Status; } } // // Push the item onto the stack // CopyMem (*StackPtr, Data, sizeof (FORM_EXPRESSION *)); *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 PopConditionalStack ( IN FORM_EXPRESSION **Stack, IN OUT FORM_EXPRESSION ***StackPtr, OUT FORM_EXPRESSION **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 (FORM_EXPRESSION *)); return EFI_SUCCESS; } /** Get the expression list count. @param Level Which type this expression belong to. Form, statement or option? @retval >=0 The expression count @retval -1 Input parameter error. **/ INTN GetConditionalExpressionCount ( IN EXPRESS_LEVEL Level ) { switch (Level) { case ExpressForm: return mFormExpressionPointer - mFormExpressionStack; case ExpressStatement: return mStatementExpressionPointer - mStatementExpressionStack; case ExpressOption: return mOptionExpressionPointer - mOptionExpressionStack; default: ASSERT (FALSE); return -1; } } /** Get the expression Buffer pointer. @param Level Which type this expression belong to. Form, statement or option? @retval The start pointer of the expression buffer or NULL. **/ FORM_EXPRESSION ** GetConditionalExpressionList ( IN EXPRESS_LEVEL Level ) { switch (Level) { case ExpressForm: return mFormExpressionStack; case ExpressStatement: return mStatementExpressionStack; case ExpressOption: return mOptionExpressionStack; default: ASSERT (FALSE); return NULL; } } /** Push the expression options onto the Stack. @param Pointer Pointer to the current expression. @param Level Which type this expression belong to. Form, statement or option? @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 PushConditionalExpression ( IN FORM_EXPRESSION *Pointer, IN EXPRESS_LEVEL Level ) { switch (Level) { case ExpressForm: return PushConditionalStack ( &mFormExpressionStack, &mFormExpressionPointer, &mFormExpressionEnd, &Pointer ); case ExpressStatement: return PushConditionalStack ( &mStatementExpressionStack, &mStatementExpressionPointer, &mStatementExpressionEnd, &Pointer ); case ExpressOption: return PushConditionalStack ( &mOptionExpressionStack, &mOptionExpressionPointer, &mOptionExpressionEnd, &Pointer ); default: ASSERT (FALSE); return EFI_INVALID_PARAMETER; } } /** Pop the expression options from the Stack @param Level Which type this expression belong to. Form, statement or option? @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 PopConditionalExpression ( IN EXPRESS_LEVEL Level ) { FORM_EXPRESSION *Pointer; switch (Level) { case ExpressForm: return PopConditionalStack ( mFormExpressionStack, &mFormExpressionPointer, &Pointer ); case ExpressStatement: return PopConditionalStack ( mStatementExpressionStack, &mStatementExpressionPointer, &Pointer ); case ExpressOption: return PopConditionalStack ( mOptionExpressionStack, &mOptionExpressionPointer, &Pointer ); default: ASSERT (FALSE); return EFI_INVALID_PARAMETER; } } /** 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 ( VOID ) { 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; } /** 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 || Form == NULL) { // // 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) { // // EFI variable storage may be updated by Callback() asynchronous, // to keep synchronous, always reload the Question Value. // if (Question->Storage->Type == EFI_HII_VARSTORE_EFI_VARIABLE) { GetQuestionValue (FormSet, Form, Question, GetSetValueWithHiiDriver); } 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. @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; } /** 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++; } } /** Check whether this value type can be transfer to EFI_IFR_TYPE_BUFFER type. EFI_IFR_TYPE_REF, EFI_IFR_TYPE_DATE and EFI_IFR_TYPE_TIME are converted to EFI_IFR_TYPE_BUFFER when do the value compare. @param Value Expression value to compare on. @retval TRUE This value type can be transter to EFI_IFR_TYPE_BUFFER type. @retval FALSE This value type can't be transter to EFI_IFR_TYPE_BUFFER type. **/ BOOLEAN IsTypeInBuffer ( IN EFI_HII_VALUE *Value ) { switch (Value->Type) { case EFI_IFR_TYPE_BUFFER: case EFI_IFR_TYPE_DATE: case EFI_IFR_TYPE_TIME: case EFI_IFR_TYPE_REF: return TRUE; default: return FALSE; } } /** Check whether this value type can be transfer to EFI_IFR_TYPE_UINT64 @param Value Expression value to compare on. @retval TRUE This value type can be transter to EFI_IFR_TYPE_BUFFER type. @retval FALSE This value type can't be transter to EFI_IFR_TYPE_BUFFER type. **/ BOOLEAN IsTypeInUINT64 ( IN EFI_HII_VALUE *Value ) { switch (Value->Type) { case EFI_IFR_TYPE_NUM_SIZE_8: case EFI_IFR_TYPE_NUM_SIZE_16: case EFI_IFR_TYPE_NUM_SIZE_32: case EFI_IFR_TYPE_NUM_SIZE_64: case EFI_IFR_TYPE_BOOLEAN: return TRUE; default: return FALSE; } } /** Return the buffer length for this value. EFI_IFR_TYPE_REF, EFI_IFR_TYPE_DATE and EFI_IFR_TYPE_TIME are converted to EFI_IFR_TYPE_BUFFER when do the value compare. @param Value Expression value to compare on. @retval BufLen Return the buffer length. **/ UINT16 GetLengthForValue ( IN EFI_HII_VALUE *Value ) { switch (Value->Type) { case EFI_IFR_TYPE_BUFFER: return Value->BufferLen; case EFI_IFR_TYPE_DATE: return (UINT16) sizeof (EFI_HII_DATE); case EFI_IFR_TYPE_TIME: return (UINT16) sizeof (EFI_HII_TIME); case EFI_IFR_TYPE_REF: return (UINT16) sizeof (EFI_HII_REF); default: return 0; } } /** Return the buffer pointer for this value. EFI_IFR_TYPE_REF, EFI_IFR_TYPE_DATE and EFI_IFR_TYPE_TIME are converted to EFI_IFR_TYPE_BUFFER when do the value compare. @param Value Expression value to compare on. @retval Buf Return the buffer pointer. **/ UINT8 * GetBufferForValue ( IN EFI_HII_VALUE *Value ) { switch (Value->Type) { case EFI_IFR_TYPE_BUFFER: return Value->Buffer; case EFI_IFR_TYPE_DATE: return (UINT8 *) (&Value->Value.date); case EFI_IFR_TYPE_TIME: return (UINT8 *) (&Value->Value.time); case EFI_IFR_TYPE_REF: return (UINT8 *) (&Value->Value.ref); default: return NULL; } } /** 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]; UINT8 *TmpBuf; UINT8 *SrcBuf; UINTN SrcLen; 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: Result->Type = EFI_IFR_TYPE_UNDEFINED; return EFI_SUCCESS; } 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; case EFI_IFR_TYPE_BUFFER: case EFI_IFR_TYPE_DATE: case EFI_IFR_TYPE_TIME: case EFI_IFR_TYPE_REF: // // + 3 is base on the unicode format, the length may be odd number, // so need 1 byte to align, also need 2 bytes for L'\0'. // if (Value.Type == EFI_IFR_TYPE_BUFFER) { SrcLen = Value.BufferLen; SrcBuf = Value.Buffer; } else { SrcBuf = GetBufferForValue(&Value); SrcLen = GetLengthForValue(&Value); } TmpBuf = AllocateZeroPool (SrcLen + 3); ASSERT (TmpBuf != NULL); if (Format == EFI_IFR_STRING_ASCII) { CopyMem (TmpBuf, SrcBuf, SrcLen); PrintFormat = L"%a"; } else { // Format == EFI_IFR_STRING_UNICODE CopyMem (TmpBuf, SrcBuf, SrcLen * sizeof (CHAR16)); PrintFormat = L"%s"; } UnicodeSPrint (Buffer, sizeof (Buffer), PrintFormat, TmpBuf); String = Buffer; FreePool (TmpBuf); if (Value.Type == EFI_IFR_TYPE_BUFFER) { FreePool (Value.Buffer); } break; default: Result->Type = EFI_IFR_TYPE_UNDEFINED; return EFI_SUCCESS; } 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 && !IsTypeInBuffer(&Value)) { Result->Type = EFI_IFR_TYPE_UNDEFINED; return EFI_SUCCESS; } 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 // Result->Value.u64 = StrHexToUint64 (String); } else { // // decimal string // Result->Value.u64 = StrDecimalToUint64 (String); } FreePool (String); } else if (IsTypeInBuffer(&Value)) { if (GetLengthForValue (&Value) > 8) { if (Value.Type == EFI_IFR_TYPE_BUFFER) { FreePool (Value.Buffer); } Result->Type = EFI_IFR_TYPE_UNDEFINED; return EFI_SUCCESS; } ASSERT (GetBufferForValue (&Value) != NULL); Result->Value.u64 = *(UINT64*) GetBufferForValue (&Value); if (Value.Type == EFI_IFR_TYPE_BUFFER) { FreePool (Value.Buffer); } } 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[2]; CHAR16 *String[2]; UINTN Index; CHAR16 *StringPtr; UINTN Size; UINT16 Length0; UINT16 Length1; UINT8 *TmpBuf; UINTN MaxLen; // // String[0] - The second string // String[1] - The first string // String[0] = NULL; String[1] = NULL; StringPtr = NULL; Status = EFI_SUCCESS; ZeroMem (Value, sizeof (Value)); Status = PopExpression (&Value[0]); if (EFI_ERROR (Status)) { goto Done; } Status = PopExpression (&Value[1]); if (EFI_ERROR (Status)) { goto Done; } for (Index = 0; Index < 2; Index++) { if (Value[Index].Type != EFI_IFR_TYPE_STRING && !IsTypeInBuffer(&Value[Index])) { Result->Type = EFI_IFR_TYPE_UNDEFINED; Status = EFI_SUCCESS; goto Done; } if (Value[Index].Type == EFI_IFR_TYPE_STRING) { String[Index] = GetToken (Value[Index].Value.string, FormSet->HiiHandle); if (String[Index] == NULL) { Status = EFI_NOT_FOUND; goto Done; } } } if (Value[0].Type == EFI_IFR_TYPE_STRING) { Size = StrSize (String[0]); MaxLen = (StrSize (String[1]) + Size) / sizeof (CHAR16); StringPtr= AllocatePool (MaxLen * sizeof (CHAR16)); ASSERT (StringPtr != NULL); StrCpyS (StringPtr, MaxLen, String[1]); StrCatS (StringPtr, MaxLen, String[0]); Result->Type = EFI_IFR_TYPE_STRING; Result->Value.string = NewString (StringPtr, FormSet->HiiHandle); } else { Result->Type = EFI_IFR_TYPE_BUFFER; Length0 = GetLengthForValue(&Value[0]); Length1 = GetLengthForValue(&Value[1]); Result->BufferLen = (UINT16) (Length0 + Length1); Result->Buffer = AllocateZeroPool (Result->BufferLen); ASSERT (Result->Buffer != NULL); TmpBuf = GetBufferForValue(&Value[0]); ASSERT (TmpBuf != NULL); CopyMem (Result->Buffer, TmpBuf, Length0); TmpBuf = GetBufferForValue(&Value[1]); ASSERT (TmpBuf != NULL); CopyMem (&Result->Buffer[Length0], TmpBuf, Length1); } Done: if (Value[0].Buffer != NULL) { FreePool (Value[0].Buffer); } if (Value[1].Buffer != NULL) { FreePool (Value[1].Buffer); } 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[2]; CHAR16 *String[2]; UINTN Index; // // String[0] - The string to search // String[1] - pattern // String[0] = NULL; String[1] = NULL; Status = EFI_SUCCESS; ZeroMem (Value, sizeof (Value)); Status = PopExpression (&Value[0]); if (EFI_ERROR (Status)) { goto Done; } Status = PopExpression (&Value[1]); if (EFI_ERROR (Status)) { goto Done; } for (Index = 0; Index < 2; Index++) { if (Value[Index].Type != EFI_IFR_TYPE_STRING) { Result->Type = EFI_IFR_TYPE_UNDEFINED; Status = EFI_SUCCESS; goto Done; } String[Index] = GetToken (Value[Index].Value.string, FormSet->HiiHandle); if (String [Index] == NULL) { Status = EFI_NOT_FOUND; goto Done; } } Result->Type = EFI_IFR_TYPE_BOOLEAN; Result->Value.b = mUnicodeCollation->MetaiMatch (mUnicodeCollation, 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_MATCH2. @param FormSet Formset which contains this opcode. @param SyntaxType Syntax type for match2. @param Result Evaluation result for this opcode. @retval EFI_SUCCESS Opcode evaluation success. @retval Other Opcode evaluation failed. **/ EFI_STATUS IfrMatch2 ( IN FORM_BROWSER_FORMSET *FormSet, IN EFI_GUID *SyntaxType, OUT EFI_HII_VALUE *Result ) { EFI_STATUS Status; EFI_HII_VALUE Value[2]; CHAR16 *String[2]; UINTN Index; UINTN GuidIndex; EFI_HANDLE *HandleBuffer; UINTN BufferSize; EFI_REGULAR_EXPRESSION_PROTOCOL *RegularExpressionProtocol; UINTN RegExSyntaxTypeListSize; EFI_REGEX_SYNTAX_TYPE *RegExSyntaxTypeList; UINTN CapturesCount; // // String[0] - The string to search // String[1] - pattern // String[0] = NULL; String[1] = NULL; HandleBuffer = NULL; RegExSyntaxTypeList = NULL; Status = EFI_SUCCESS; ZeroMem (Value, sizeof (Value)); Status = PopExpression (&Value[0]); if (EFI_ERROR (Status)) { goto Done; } Status = PopExpression (&Value[1]); if (EFI_ERROR (Status)) { goto Done; } for (Index = 0; Index < 2; Index++) { if (Value[Index].Type != EFI_IFR_TYPE_STRING) { Result->Type = EFI_IFR_TYPE_UNDEFINED; Status = EFI_SUCCESS; goto Done; } String[Index] = GetToken (Value[Index].Value.string, FormSet->HiiHandle); if (String [Index] == NULL) { Status = EFI_NOT_FOUND; goto Done; } } BufferSize = 0; HandleBuffer = NULL; Status = gBS->LocateHandle( ByProtocol, &gEfiRegularExpressionProtocolGuid, NULL, &BufferSize, HandleBuffer); if (Status == EFI_BUFFER_TOO_SMALL) { HandleBuffer = AllocateZeroPool(BufferSize); if (HandleBuffer == NULL) { Status = EFI_OUT_OF_RESOURCES; goto Done; } Status = gBS->LocateHandle( ByProtocol, &gEfiRegularExpressionProtocolGuid, NULL, &BufferSize, HandleBuffer); } if (EFI_ERROR (Status)) { Result->Type = EFI_IFR_TYPE_UNDEFINED; Status = EFI_SUCCESS; goto Done; } ASSERT (HandleBuffer != NULL); for ( Index = 0; Index < BufferSize / sizeof(EFI_HANDLE); Index ++) { Status = gBS->HandleProtocol ( HandleBuffer[Index], &gEfiRegularExpressionProtocolGuid, (VOID**)&RegularExpressionProtocol ); if (EFI_ERROR (Status)) { goto Done; } RegExSyntaxTypeListSize = 0; RegExSyntaxTypeList = NULL; Status = RegularExpressionProtocol->GetInfo ( RegularExpressionProtocol, &RegExSyntaxTypeListSize, RegExSyntaxTypeList ); if (Status == EFI_BUFFER_TOO_SMALL) { RegExSyntaxTypeList = AllocateZeroPool(RegExSyntaxTypeListSize); if (RegExSyntaxTypeList == NULL) { Status = EFI_OUT_OF_RESOURCES; goto Done; } Status = RegularExpressionProtocol->GetInfo ( RegularExpressionProtocol, &RegExSyntaxTypeListSize, RegExSyntaxTypeList ); } else if (EFI_ERROR (Status)) { goto Done; } for (GuidIndex = 0; GuidIndex < RegExSyntaxTypeListSize / sizeof(EFI_GUID); GuidIndex++) { if (CompareGuid (&RegExSyntaxTypeList[GuidIndex], SyntaxType)) { // // Find the match type, return the value. // Result->Type = EFI_IFR_TYPE_BOOLEAN; Status = RegularExpressionProtocol->MatchString ( RegularExpressionProtocol, String[0], String[1], SyntaxType, &Result->Value.b, NULL, &CapturesCount ); goto Done; } } if (RegExSyntaxTypeList != NULL) { FreePool (RegExSyntaxTypeList); } } // // Type specified by SyntaxType is not supported // in any of the EFI_REGULAR_EXPRESSION_PROTOCOL instances. // Result->Type = EFI_IFR_TYPE_UNDEFINED; Status = EFI_SUCCESS; Done: if (String[0] != NULL) { FreePool (String[0]); } if (String[1] != NULL) { FreePool (String[1]); } if (RegExSyntaxTypeList != NULL) { FreePool (RegExSyntaxTypeList); } if (HandleBuffer != NULL) { FreePool (HandleBuffer); } 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[3]; CHAR16 *String[2]; UINTN Base; CHAR16 *StringPtr; UINTN Index; ZeroMem (Value, sizeof (Value)); if (Format > EFI_IFR_FF_CASE_INSENSITIVE) { return EFI_INVALID_PARAMETER; } Status = PopExpression (&Value[0]); if (EFI_ERROR (Status)) { return Status; } Status = PopExpression (&Value[1]); if (EFI_ERROR (Status)) { return Status; } Status = PopExpression (&Value[2]); if (EFI_ERROR (Status)) { return Status; } if (Value[0].Type > EFI_IFR_TYPE_NUM_SIZE_64) { Result->Type = EFI_IFR_TYPE_UNDEFINED; return EFI_SUCCESS; } Base = (UINTN) Value[0].Value.u64; // // String[0] - sub-string // String[1] - The string to search // String[0] = NULL; String[1] = NULL; for (Index = 0; Index < 2; Index++) { if (Value[Index + 1].Type != EFI_IFR_TYPE_STRING) { Result->Type = EFI_IFR_TYPE_UNDEFINED; Status = EFI_SUCCESS; goto Done; } String[Index] = GetToken (Value[Index + 1].Value.string, FormSet->HiiHandle); 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 >= 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: 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[3]; CHAR16 *String; UINTN Base; UINTN Length; CHAR16 *SubString; UINT16 BufferLen; UINT8 *Buffer; ZeroMem (Value, sizeof (Value)); Status = PopExpression (&Value[0]); if (EFI_ERROR (Status)) { return Status; } Status = PopExpression (&Value[1]); if (EFI_ERROR (Status)) { return Status; } Status = PopExpression (&Value[2]); if (EFI_ERROR (Status)) { return Status; } if (Value[0].Type > EFI_IFR_TYPE_NUM_SIZE_64) { Result->Type = EFI_IFR_TYPE_UNDEFINED; return EFI_SUCCESS; } Length = (UINTN) Value[0].Value.u64; if (Value[1].Type > EFI_IFR_TYPE_NUM_SIZE_64) { Result->Type = EFI_IFR_TYPE_UNDEFINED; return EFI_SUCCESS; } Base = (UINTN) Value[1].Value.u64; if (Value[2].Type != EFI_IFR_TYPE_STRING && !IsTypeInBuffer(&Value[2])) { Result->Type = EFI_IFR_TYPE_UNDEFINED; return EFI_SUCCESS; } if (Value[2].Type == EFI_IFR_TYPE_STRING) { String = GetToken (Value[2].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); FreePool (String); } else { BufferLen = GetLengthForValue (&Value[2]); Buffer = GetBufferForValue (&Value[2]); Result->Type = EFI_IFR_TYPE_BUFFER; if (Length == 0 || Base >= BufferLen) { Result->BufferLen = 0; Result->Buffer = NULL; } else { Result->BufferLen = (UINT16)((BufferLen - Base) < Length ? (BufferLen - Base) : Length); Result->Buffer = AllocateZeroPool (Result->BufferLen); ASSERT (Result->Buffer != NULL); CopyMem (Result->Buffer, &Buffer[Base], Result->BufferLen); } if (Value[2].Type == EFI_IFR_TYPE_BUFFER) { FreePool (Value[2].Buffer); } } 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[3]; CHAR16 *String[2]; UINTN Count; CHAR16 *Delimiter; CHAR16 *SubString; CHAR16 *StringPtr; UINTN Index; ZeroMem (Value, sizeof (Value)); Status = PopExpression (&Value[0]); if (EFI_ERROR (Status)) { return Status; } Status = PopExpression (&Value[1]); if (EFI_ERROR (Status)) { return Status; } Status = PopExpression (&Value[2]); if (EFI_ERROR (Status)) { return Status; } if (Value[0].Type > EFI_IFR_TYPE_NUM_SIZE_64) { Result->Type = EFI_IFR_TYPE_UNDEFINED; return EFI_SUCCESS; } Count = (UINTN) Value[0].Value.u64; // // String[0] - Delimiter // String[1] - The string to search // String[0] = NULL; String[1] = NULL; for (Index = 0; Index < 2; Index++) { if (Value[Index + 1].Type != EFI_IFR_TYPE_STRING) { Result->Type = EFI_IFR_TYPE_UNDEFINED; Status = EFI_SUCCESS; goto Done; } String[Index] = GetToken (Value[Index + 1].Value.string, FormSet->HiiHandle); 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 + 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: 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[3]; CHAR16 *String[2]; CHAR16 *Charset; UINTN Base; UINTN Index; CHAR16 *StringPtr; BOOLEAN Found; ZeroMem (Value, sizeof (Value)); Status = PopExpression (&Value[0]); if (EFI_ERROR (Status)) { return Status; } Status = PopExpression (&Value[1]); if (EFI_ERROR (Status)) { return Status; } Status = PopExpression (&Value[2]); if (EFI_ERROR (Status)) { return Status; } if (Value[0].Type > EFI_IFR_TYPE_NUM_SIZE_64) { Result->Type = EFI_IFR_TYPE_UNDEFINED; return EFI_SUCCESS; } Base = (UINTN) Value[0].Value.u64; // // String[0] - Charset // String[1] - The string to search // String[0] = NULL; String[1] = NULL; for (Index = 0; Index < 2; Index++) { if (Value[Index + 1].Type != EFI_IFR_TYPE_STRING) { Result->Type = EFI_IFR_TYPE_UNDEFINED; Status = EFI_SUCCESS; goto Done; } String[Index] = GetToken (Value[Index + 1].Value.string, FormSet->HiiHandle); if (String [Index] == NULL) { Status = EFI_NOT_FOUND; goto Done; } } if (Base >= StrLen (String[1])) { Result->Type = EFI_IFR_TYPE_UNDEFINED; Status = EFI_SUCCESS; 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; } /** Get UINT64 type value. @param Value Input Hii value. @retval UINT64 Return the UINT64 type value. **/ UINT64 HiiValueToUINT64 ( IN EFI_HII_VALUE *Value ) { UINT64 RetVal; RetVal = 0; switch (Value->Type) { case EFI_IFR_TYPE_NUM_SIZE_8: RetVal = Value->Value.u8; break; case EFI_IFR_TYPE_NUM_SIZE_16: RetVal = Value->Value.u16; break; case EFI_IFR_TYPE_NUM_SIZE_32: RetVal = Value->Value.u32; break; case EFI_IFR_TYPE_BOOLEAN: RetVal = Value->Value.b; break; case EFI_IFR_TYPE_DATE: RetVal = *(UINT64*) &Value->Value.date; break; case EFI_IFR_TYPE_TIME: RetVal = (*(UINT64*) &Value->Value.time) & 0xffffff; break; default: RetVal = Value->Value.u64; break; } return RetVal; } /** Compare two Hii value. @param Value1 Expression value to compare on left-hand. @param Value2 Expression value to compare on right-hand. @param Result Return value after compare. retval 0 Two operators equal. return Positive value if Value1 is greater than Value2. retval Negative value if Value1 is less than Value2. @param HiiHandle Only required for string compare. @retval other Could not perform compare on two values. @retval EFI_SUCCESS Compare the value success. **/ EFI_STATUS CompareHiiValue ( IN EFI_HII_VALUE *Value1, IN EFI_HII_VALUE *Value2, OUT INTN *Result, IN EFI_HII_HANDLE HiiHandle OPTIONAL ) { INT64 Temp64; CHAR16 *Str1; CHAR16 *Str2; UINTN Len; UINT8 *Buf1; UINT16 Buf1Len; UINT8 *Buf2; UINT16 Buf2Len; if (Value1->Type == EFI_IFR_TYPE_STRING && Value2->Type == EFI_IFR_TYPE_STRING) { if (Value1->Value.string == 0 || Value2->Value.string == 0) { // // StringId 0 is reserved // return EFI_INVALID_PARAMETER; } if (Value1->Value.string == Value2->Value.string) { *Result = 0; return EFI_SUCCESS; } Str1 = GetToken (Value1->Value.string, HiiHandle); if (Str1 == NULL) { // // String not found // return EFI_NOT_FOUND; } Str2 = GetToken (Value2->Value.string, HiiHandle); if (Str2 == NULL) { FreePool (Str1); return EFI_NOT_FOUND; } *Result = StrCmp (Str1, Str2); FreePool (Str1); FreePool (Str2); return EFI_SUCCESS; } // // Take types(date, time, ref, buffer) as buffer // if (IsTypeInBuffer(Value1) && IsTypeInBuffer(Value2)) { Buf1 = GetBufferForValue(Value1); Buf1Len = GetLengthForValue(Value1); Buf2 = GetBufferForValue(Value2); Buf2Len = GetLengthForValue(Value2); Len = Buf1Len > Buf2Len ? Buf2Len : Buf1Len; *Result = CompareMem (Buf1, Buf2, Len); if ((*Result == 0) && (Buf1Len != Buf2Len)) { // // In this case, means base on samll number buffer, the data is same // So which value has more data, which value is bigger. // *Result = Buf1Len > Buf2Len ? 1 : -1; } return EFI_SUCCESS; } // // Take types(integer, boolean) as integer // if (IsTypeInUINT64(Value1) && IsTypeInUINT64(Value2)) { Temp64 = HiiValueToUINT64(Value1) - HiiValueToUINT64(Value2); if (Temp64 > 0) { *Result = 1; } else if (Temp64 < 0) { *Result = -1; } else { *Result = 0; } return EFI_SUCCESS; } return EFI_UNSUPPORTED; } /** Check if current user has the privilege specified by the permissions GUID. @param[in] Guid A GUID specifying setup access permissions. @retval TRUE Current user has the privilege. @retval FALSE Current user does not have the privilege. **/ BOOLEAN CheckUserPrivilege ( IN EFI_GUID *Guid ) { EFI_STATUS Status; EFI_USER_PROFILE_HANDLE UserProfileHandle; EFI_USER_INFO_HANDLE UserInfoHandle; EFI_USER_INFO *UserInfo; EFI_GUID *UserPermissionsGuid; UINTN UserInfoSize; UINTN AccessControlDataSize; EFI_USER_INFO_ACCESS_CONTROL *AccessControl; UINTN RemainSize; if (mUserManager == NULL) { Status = gBS->LocateProtocol ( &gEfiUserManagerProtocolGuid, NULL, (VOID **) &mUserManager ); if (EFI_ERROR (Status)) { /// /// If the system does not support user management, then it is assumed that /// all users have admin privilege and evaluation of each EFI_IFR_SECURITY /// op-code is always TRUE. /// return TRUE; } } Status = mUserManager->Current (mUserManager, &UserProfileHandle); ASSERT_EFI_ERROR (Status); /// /// Enumerate all user information of the current user profile /// to look for any EFI_USER_INFO_ACCESS_SETUP record. /// for (UserInfoHandle = NULL;;) { Status = mUserManager->GetNextInfo (mUserManager, UserProfileHandle, &UserInfoHandle); if (EFI_ERROR (Status)) { break; } UserInfoSize = 0; Status = mUserManager->GetInfo (mUserManager, UserProfileHandle, UserInfoHandle, NULL, &UserInfoSize); if (Status != EFI_BUFFER_TOO_SMALL) { continue; } UserInfo = (EFI_USER_INFO *) AllocatePool (UserInfoSize); if (UserInfo == NULL) { break; } Status = mUserManager->GetInfo (mUserManager, UserProfileHandle, UserInfoHandle, UserInfo, &UserInfoSize); if (EFI_ERROR (Status) || UserInfo->InfoType != EFI_USER_INFO_ACCESS_POLICY_RECORD || UserInfo->InfoSize <= sizeof (EFI_USER_INFO)) { FreePool (UserInfo); continue; } RemainSize = UserInfo->InfoSize - sizeof (EFI_USER_INFO); AccessControl = (EFI_USER_INFO_ACCESS_CONTROL *)(UserInfo + 1); while (RemainSize >= sizeof (EFI_USER_INFO_ACCESS_CONTROL)) { if (RemainSize < AccessControl->Size || AccessControl->Size < sizeof (EFI_USER_INFO_ACCESS_CONTROL)) { break; } if (AccessControl->Type == EFI_USER_INFO_ACCESS_SETUP) { /// /// Check if current user has the privilege specified by the permissions GUID. /// UserPermissionsGuid = (EFI_GUID *)(AccessControl + 1); AccessControlDataSize = AccessControl->Size - sizeof (EFI_USER_INFO_ACCESS_CONTROL); while (AccessControlDataSize >= sizeof (EFI_GUID)) { if (CompareGuid (Guid, UserPermissionsGuid)) { FreePool (UserInfo); return TRUE; } UserPermissionsGuid++; AccessControlDataSize -= sizeof (EFI_GUID); } } RemainSize -= AccessControl->Size; AccessControl = (EFI_USER_INFO_ACCESS_CONTROL *)((UINT8 *)AccessControl + AccessControl->Size); } FreePool (UserInfo); } return FALSE; } /** Get question value from the predefined formset. @param DevicePath The driver's device path which produece the formset data. @param InputHiiHandle The hii handle associate with the formset data. @param FormSetGuid The formset guid which include the question. @param QuestionId The question id which need to get value from. @param Value The return data about question's value. @retval TRUE Get the question value success. @retval FALSE Get the question value failed. **/ BOOLEAN GetQuestionValueFromForm ( IN EFI_DEVICE_PATH_PROTOCOL *DevicePath, IN EFI_HII_HANDLE InputHiiHandle, IN EFI_GUID *FormSetGuid, IN EFI_QUESTION_ID QuestionId, OUT EFI_HII_VALUE *Value ) { EFI_STATUS Status; EFI_HII_HANDLE HiiHandle; FORM_BROWSER_STATEMENT *Question; FORM_BROWSER_FORMSET *FormSet; FORM_BROWSER_FORM *Form; BOOLEAN GetTheVal; LIST_ENTRY *Link; // // The input parameter DevicePath or InputHiiHandle must have one valid input. // ASSERT ((DevicePath != NULL && InputHiiHandle == NULL) || (DevicePath == NULL && InputHiiHandle != NULL) ); GetTheVal = TRUE; HiiHandle = NULL; Question = NULL; Form = NULL; // // Get HiiHandle. // if (DevicePath != NULL) { HiiHandle = DevicePathToHiiHandle (DevicePath, FormSetGuid); if (HiiHandle == NULL) { return FALSE; } } else { HiiHandle = InputHiiHandle; } ASSERT (HiiHandle != NULL); // // Get the formset data include this question. // FormSet = AllocateZeroPool (sizeof (FORM_BROWSER_FORMSET)); ASSERT (FormSet != NULL); Status = InitializeFormSet(HiiHandle, FormSetGuid, FormSet); if (EFI_ERROR (Status)) { GetTheVal = FALSE; goto Done; } // // Base on the Question Id to get the question info. // Question = IdToQuestion(FormSet, NULL, QuestionId); if (Question == NULL) { GetTheVal = FALSE; goto Done; } // // Search form 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) { break; } Link = GetNextNode (&FormSet->FormListHead, Link); Form = NULL; } ASSERT (Form != NULL); // // Get the question value. // Status = GetQuestionValue(FormSet, Form, Question, GetSetValueWithEditBuffer); if (EFI_ERROR (Status)) { GetTheVal = FALSE; goto Done; } CopyMem (Value, &Question->HiiValue, sizeof (EFI_HII_VALUE)); Done: // // Clean the formset structure and restore the global parameter. // if (FormSet != NULL) { DestroyFormSet (FormSet); } return GetTheVal; } /** 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. @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; CHAR16 *NameValue; UINT32 TempValue; LIST_ENTRY *SubExpressionLink; FORM_EXPRESSION *SubExpression; UINTN StackOffset; UINTN TempLength; CHAR16 TempStr[5]; UINT8 DigitUint8; UINT8 *TempBuffer; EFI_TIME EfiTime; EFI_HII_VALUE QuestionVal; EFI_DEVICE_PATH_PROTOCOL *DevicePath; StrPtr = NULL; // // 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; switch (OpCode->Operand) { // // Built-in functions // case EFI_IFR_EQ_ID_VAL_OP: Question = IdToQuestion (FormSet, Form, OpCode->QuestionId); if (Question == NULL) { Value->Type = EFI_IFR_TYPE_UNDEFINED; break; } Status = CompareHiiValue (&Question->HiiValue, &OpCode->Value, &Result, NULL); if (Status == EFI_UNSUPPORTED) { Status = EFI_SUCCESS; Value->Type = EFI_IFR_TYPE_UNDEFINED; break; } if (EFI_ERROR (Status)) { 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) { Value->Type = EFI_IFR_TYPE_UNDEFINED; break; } Question2 = IdToQuestion (FormSet, Form, OpCode->QuestionId2); if (Question2 == NULL) { Value->Type = EFI_IFR_TYPE_UNDEFINED; break; } Status = CompareHiiValue (&Question->HiiValue, &Question2->HiiValue, &Result, FormSet->HiiHandle); if (Status == EFI_UNSUPPORTED) { Value->Type = EFI_IFR_TYPE_UNDEFINED; Status = EFI_SUCCESS; break; } if (EFI_ERROR (Status)) { 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) { Value->Type = EFI_IFR_TYPE_UNDEFINED; break; } 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; } Value = &Question->HiiValue; break; case EFI_IFR_SECURITY_OP: Value->Value.b = CheckUserPrivilege (&OpCode->Guid); 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_HII_VARSTORE_BUFFER: case EFI_HII_VARSTORE_EFI_VARIABLE_BUFFER: // // Get value from Edit Buffer // Value->Type = OpCode->ValueType; CopyMem (&Value->Value, OpCode->VarStorage->EditBuffer + OpCode->VarStoreInfo.VarOffset, 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, GetSetValueWithEditBuffer); if (!EFI_ERROR (Status)) { ASSERT (StrPtr != NULL); TempLength = StrLen (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) StrHexToUint64 (TempStr); if ((Index & 1) == 0) { TempBuffer [Index/2] = DigitUint8; } else { TempBuffer [Index/2] = (UINT8) ((DigitUint8 << 4) + TempBuffer [Index/2]); } } } } } break; case EFI_HII_VARSTORE_EFI_VARIABLE: // // Get value from variable. // TempLength = OpCode->ValueWidth; Value->Type = OpCode->ValueType; Status = gRT->GetVariable ( OpCode->ValueName, &OpCode->VarStorage->Guid, NULL, &TempLength, &Value->Value ); if (EFI_ERROR (Status)) { Value->Type = EFI_IFR_TYPE_UNDEFINED; Value->Value.u8 = 0; } break; default: // // Not recognize storage. // Status = EFI_UNSUPPORTED; goto Done; } } else { // // For Time/Date Data // if (OpCode->ValueType != EFI_IFR_TYPE_DATE && OpCode->ValueType != EFI_IFR_TYPE_TIME) { // // Only support Data/Time data when storage doesn't exist. // Status = EFI_UNSUPPORTED; goto Done; } Status = gRT->GetTime (&EfiTime, NULL); if (!EFI_ERROR (Status)) { if (OpCode->ValueType == EFI_IFR_TYPE_DATE) { switch (OpCode->VarStoreInfo.VarOffset) { case 0x00: Value->Type = EFI_IFR_TYPE_NUM_SIZE_16; Value->Value.u16 = EfiTime.Year; break; case 0x02: Value->Type = EFI_IFR_TYPE_NUM_SIZE_8; Value->Value.u8 = EfiTime.Month; break; case 0x03: Value->Type = EFI_IFR_TYPE_NUM_SIZE_8; Value->Value.u8 = EfiTime.Day; break; default: // // Invalid Date field. // Status = EFI_INVALID_PARAMETER; goto Done; } } else { switch (OpCode->VarStoreInfo.VarOffset) { case 0x00: Value->Type = EFI_IFR_TYPE_NUM_SIZE_8; Value->Value.u8 = EfiTime.Hour; break; case 0x01: Value->Type = EFI_IFR_TYPE_NUM_SIZE_8; Value->Value.u8 = EfiTime.Minute; break; case 0x02: Value->Type = EFI_IFR_TYPE_NUM_SIZE_8; Value->Value.u8 = EfiTime.Second; break; default: // // Invalid Time field. // Status = EFI_INVALID_PARAMETER; goto Done; } } } } break; case EFI_IFR_QUESTION_REF3_OP: // // 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)) { Value->Type = EFI_IFR_TYPE_UNDEFINED; break; } if (OpCode->DevicePath != 0) { Value->Type = EFI_IFR_TYPE_UNDEFINED; StrPtr = GetToken (OpCode->DevicePath, FormSet->HiiHandle); if (StrPtr != NULL && mPathFromText != NULL) { DevicePath = mPathFromText->ConvertTextToDevicePath(StrPtr); if (DevicePath != NULL && GetQuestionValueFromForm(DevicePath, NULL, &OpCode->Guid, Value->Value.u16, &QuestionVal)) { Value = &QuestionVal; } if (DevicePath != NULL) { FreePool (DevicePath); } } if (StrPtr != NULL) { FreePool (StrPtr); } } else if (IsZeroGuid (&OpCode->Guid)) { if (!GetQuestionValueFromForm(NULL, FormSet->HiiHandle, &OpCode->Guid, Value->Value.u16, &QuestionVal)){ Value->Type = EFI_IFR_TYPE_UNDEFINED; break; } Value = &QuestionVal; } else { Question = IdToQuestion (FormSet, Form, Value->Value.u16); if (Question == NULL) { Value->Type = EFI_IFR_TYPE_UNDEFINED; break; } // // push the questions' value on to the expression stack // Value = &Question->HiiValue; } break; case EFI_IFR_RULE_REF_OP: // // Find expression for this rule // RuleExpression = RuleIdToExpression (Form, OpCode->RuleId); if (RuleExpression == NULL) { Value->Type = EFI_IFR_TYPE_UNDEFINED; break; } // // Evaluate this rule expression // Status = EvaluateExpression (FormSet, Form, RuleExpression); if (EFI_ERROR (Status) || RuleExpression->Result.Type == EFI_IFR_TYPE_UNDEFINED) { Value->Type = EFI_IFR_TYPE_UNDEFINED; break; } 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 && !IsTypeInBuffer (Value)) { Value->Type = EFI_IFR_TYPE_UNDEFINED; break; } if (Value->Type == EFI_IFR_TYPE_STRING) { StrPtr = GetToken (Value->Value.string, FormSet->HiiHandle); if (StrPtr == NULL) { Status = EFI_INVALID_PARAMETER; goto Done; } Value->Type = EFI_IFR_TYPE_NUM_SIZE_64; Value->Value.u64 = StrLen (StrPtr); FreePool (StrPtr); } else { Value->Type = EFI_IFR_TYPE_NUM_SIZE_64; Value->Value.u64 = GetLengthForValue(Value); FreePool (Value->Buffer); } break; case EFI_IFR_NOT_OP: Status = PopExpression (Value); if (EFI_ERROR (Status)) { goto Done; } if (Value->Type != EFI_IFR_TYPE_BOOLEAN) { Value->Type = EFI_IFR_TYPE_UNDEFINED; break; } 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)) { Value->Type = EFI_IFR_TYPE_UNDEFINED; break; } Question = IdToQuestion (FormSet, Form, Value->Value.u16); if (Question == NULL) { Value->Type = EFI_IFR_TYPE_UNDEFINED; break; } 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)) { Value->Type = EFI_IFR_TYPE_UNDEFINED; break; } 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; 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) (HiiValueToUINT64(Value) != 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->HiiHandle); if (StrPtr == NULL) { Status = EFI_INVALID_PARAMETER; goto Done; } IfrStrToUpper (StrPtr); if (StrCmp (StrPtr, L"TRUE") == 0){ Value->Value.b = TRUE; Value->Type = EFI_IFR_TYPE_BOOLEAN; } else if (StrCmp (StrPtr, L"FALSE") == 0) { Value->Value.b = FALSE; Value->Type = EFI_IFR_TYPE_BOOLEAN; } else { Value->Type = EFI_IFR_TYPE_UNDEFINED; } FreePool (StrPtr); } else if (Value->Type == EFI_IFR_TYPE_BUFFER) { // // When converting from a buffer, if the buffer is all zeroes, // then push False. Otherwise push True. // for (Index =0; Index < Value->BufferLen; Index ++) { if (Value->Buffer[Index] != 0) { break; } } if (Index >= Value->BufferLen) { Value->Value.b = FALSE; } else { Value->Value.b = TRUE; } Value->Type = EFI_IFR_TYPE_BOOLEAN; FreePool (Value->Buffer); } 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)) { goto Done; } Status = PopExpression (Value); if (EFI_ERROR (Status)) { goto Done; } if (Value->Type != EFI_IFR_TYPE_STRING) { Value->Type = EFI_IFR_TYPE_UNDEFINED; break; } StrPtr = GetToken (Value->Value.string, FormSet->HiiHandle); if (StrPtr == NULL) { Status = EFI_NOT_FOUND; goto Done; } if (OpCode->Operand == EFI_IFR_TO_LOWER_OP) { mUnicodeCollation->StrLwr (mUnicodeCollation, StrPtr); } else { mUnicodeCollation->StrUpr (mUnicodeCollation, StrPtr); } Value->Value.string = NewString (StrPtr, FormSet->HiiHandle); 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) { Value->Type = EFI_IFR_TYPE_UNDEFINED; break; } Value->Type = EFI_IFR_TYPE_NUM_SIZE_64; Value->Value.u64 = ~ HiiValueToUINT64(Value); 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; // // Set value to var storage buffer // if (OpCode->VarStorage != NULL) { switch (OpCode->VarStorage->Type) { case EFI_HII_VARSTORE_BUFFER: case EFI_HII_VARSTORE_EFI_VARIABLE_BUFFER: CopyMem (OpCode->VarStorage->EditBuffer + OpCode->VarStoreInfo.VarOffset, &Value->Value, OpCode->ValueWidth); Data1.Value.b = TRUE; break; case EFI_HII_VARSTORE_NAME_VALUE: if (OpCode->ValueType != EFI_IFR_TYPE_STRING) { NameValue = AllocateZeroPool ((OpCode->ValueWidth * 2 + 1) * sizeof (CHAR16)); ASSERT (NameValue != NULL); // // Convert Buffer to Hex String // TempBuffer = (UINT8 *) &Value->Value + OpCode->ValueWidth - 1; StrPtr = NameValue; for (Index = 0; Index < OpCode->ValueWidth; Index ++, TempBuffer --) { UnicodeValueToStringS ( StrPtr, (OpCode->ValueWidth * 2 + 1) * sizeof (CHAR16) - ((UINTN)StrPtr - (UINTN)NameValue), PREFIX_ZERO | RADIX_HEX, *TempBuffer, 2 ); StrPtr += StrnLenS (StrPtr, OpCode->ValueWidth * 2 + 1 - ((UINTN)StrPtr - (UINTN)NameValue) / sizeof (CHAR16)); } Status = SetValueByName (OpCode->VarStorage, OpCode->ValueName, NameValue, GetSetValueWithEditBuffer, NULL); FreePool (NameValue); if (!EFI_ERROR (Status)) { Data1.Value.b = TRUE; } } break; case EFI_HII_VARSTORE_EFI_VARIABLE: Status = gRT->SetVariable ( OpCode->ValueName, &OpCode->VarStorage->Guid, OpCode->VarStorage->Attributes, OpCode->ValueWidth, &Value->Value ); if (!EFI_ERROR (Status)) { Data1.Value.b = TRUE; } break; default: // // Not recognize storage. // Status = EFI_UNSUPPORTED; goto Done; } } else { // // For Time/Date Data // if (OpCode->ValueType != EFI_IFR_TYPE_DATE && OpCode->ValueType != EFI_IFR_TYPE_TIME) { // // Only support Data/Time data when storage doesn't exist. // Status = EFI_UNSUPPORTED; goto Done; } Status = gRT->GetTime (&EfiTime, NULL); if (!EFI_ERROR (Status)) { if (OpCode->ValueType == EFI_IFR_TYPE_DATE) { switch (OpCode->VarStoreInfo.VarOffset) { case 0x00: EfiTime.Year = Value->Value.u16; break; case 0x02: EfiTime.Month = Value->Value.u8; break; case 0x03: EfiTime.Day = Value->Value.u8; break; default: // // Invalid Date field. // Status = EFI_INVALID_PARAMETER; goto Done; } } else { switch (OpCode->VarStoreInfo.VarOffset) { case 0x00: EfiTime.Hour = Value->Value.u8; break; case 0x01: EfiTime.Minute = Value->Value.u8; break; case 0x02: EfiTime.Second = Value->Value.u8; break; default: // // Invalid Time field. // Status = EFI_INVALID_PARAMETER; goto Done; } } Status = gRT->SetTime (&EfiTime); if (!EFI_ERROR (Status)) { Data1.Value.b = TRUE; } } } 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; } // // Pop another expression from the expression stack // Status = PopExpression (&Data1); if (EFI_ERROR (Status)) { goto Done; } if (Data2.Type > EFI_IFR_TYPE_DATE) { Value->Type = EFI_IFR_TYPE_UNDEFINED; break; } if (Data1.Type > EFI_IFR_TYPE_DATE) { Value->Type = EFI_IFR_TYPE_UNDEFINED; break; } Value->Type = EFI_IFR_TYPE_NUM_SIZE_64; switch (OpCode->Operand) { case EFI_IFR_ADD_OP: Value->Value.u64 = HiiValueToUINT64(&Data1) + HiiValueToUINT64(&Data2); break; case EFI_IFR_SUBTRACT_OP: Value->Value.u64 = HiiValueToUINT64(&Data1) - HiiValueToUINT64(&Data2); break; case EFI_IFR_MULTIPLY_OP: Value->Value.u64 = MultU64x32 (HiiValueToUINT64(&Data1), (UINT32) HiiValueToUINT64(&Data2)); break; case EFI_IFR_DIVIDE_OP: Value->Value.u64 = DivU64x32 (HiiValueToUINT64(&Data1), (UINT32) HiiValueToUINT64(&Data2)); break; case EFI_IFR_MODULO_OP: DivU64x32Remainder (HiiValueToUINT64(&Data1), (UINT32) HiiValueToUINT64(&Data2), &TempValue); Value->Value.u64 = TempValue; break; case EFI_IFR_BITWISE_AND_OP: Value->Value.u64 = HiiValueToUINT64(&Data1) & HiiValueToUINT64(&Data2); break; case EFI_IFR_BITWISE_OR_OP: Value->Value.u64 = HiiValueToUINT64(&Data1) | HiiValueToUINT64(&Data2); break; case EFI_IFR_SHIFT_LEFT_OP: Value->Value.u64 = LShiftU64 (HiiValueToUINT64(&Data1), (UINTN) HiiValueToUINT64(&Data2)); break; case EFI_IFR_SHIFT_RIGHT_OP: Value->Value.u64 = RShiftU64 (HiiValueToUINT64(&Data1), (UINTN) HiiValueToUINT64(&Data2)); 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; } // // Pop another expression from the expression stack // Status = PopExpression (&Data1); if (EFI_ERROR (Status)) { goto Done; } if (Data2.Type != EFI_IFR_TYPE_BOOLEAN) { Value->Type = EFI_IFR_TYPE_UNDEFINED; break; } if (Data1.Type != EFI_IFR_TYPE_BOOLEAN) { Value->Type = EFI_IFR_TYPE_UNDEFINED; break; } 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; } // // Pop another expression from the expression stack // Status = PopExpression (&Data1); if (EFI_ERROR (Status)) { goto Done; } if (Data2.Type > EFI_IFR_TYPE_BOOLEAN && Data2.Type != EFI_IFR_TYPE_STRING && !IsTypeInBuffer(&Data2)) { Value->Type = EFI_IFR_TYPE_UNDEFINED; break; } if (Data1.Type > EFI_IFR_TYPE_BOOLEAN && Data1.Type != EFI_IFR_TYPE_STRING && !IsTypeInBuffer(&Data1)) { Value->Type = EFI_IFR_TYPE_UNDEFINED; break; } Status = CompareHiiValue (&Data1, &Data2, &Result, FormSet->HiiHandle); if (Data1.Type == EFI_IFR_TYPE_BUFFER) { FreePool (Data1.Buffer); } if (Data2.Type == EFI_IFR_TYPE_BUFFER) { FreePool (Data2.Buffer); } if (Status == EFI_UNSUPPORTED) { Value->Type = EFI_IFR_TYPE_UNDEFINED; Status = EFI_SUCCESS; break; } if (EFI_ERROR (Status)) { 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 = InitializeUnicodeCollationProtocol (); if (EFI_ERROR (Status)) { goto Done; } Status = IfrMatch (FormSet, Value); break; case EFI_IFR_MATCH2_OP: Status = IfrMatch2 (FormSet, &OpCode->Guid, 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) { Value->Type = EFI_IFR_TYPE_UNDEFINED; break; } 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); if (EFI_ERROR (Status)) { goto Done; } // // Compare the expression value with current value // if ((CompareHiiValue (&Data1, &SubExpression->Result, &Result, NULL) == EFI_SUCCESS) && (Result == 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); 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) || Value->Type == EFI_IFR_TYPE_UNDEFINED) { 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; } /** Check whether the result is TRUE or FALSE. For the EFI_HII_VALUE value type is numeric, return TRUE if the value is not 0. @param Result Input the result data. @retval TRUE The result is TRUE. @retval FALSE The result is FALSE. **/ BOOLEAN IsTrue ( IN EFI_HII_VALUE *Result ) { switch (Result->Type) { case EFI_IFR_TYPE_BOOLEAN: return Result->Value.b; case EFI_IFR_TYPE_NUM_SIZE_8: return (BOOLEAN)(Result->Value.u8 != 0); case EFI_IFR_TYPE_NUM_SIZE_16: return (BOOLEAN)(Result->Value.u16 != 0); case EFI_IFR_TYPE_NUM_SIZE_32: return (BOOLEAN)(Result->Value.u32 != 0); case EFI_IFR_TYPE_NUM_SIZE_64: return (BOOLEAN)(Result->Value.u64 != 0); default: return FALSE; } } /** Return the result of the expression list. Check the expression list and return the highest priority express result. Priority: DisableIf > SuppressIf > GrayOutIf > FALSE @param ExpList The input expression list. @param Evaluate Whether need to evaluate the expression first. @param FormSet FormSet associated with this expression. @param Form Form associated with this expression. @retval EXPRESS_RESULT Return the higher priority express result. DisableIf > SuppressIf > GrayOutIf > FALSE **/ EXPRESS_RESULT EvaluateExpressionList ( IN FORM_EXPRESSION_LIST *ExpList, IN BOOLEAN Evaluate, IN FORM_BROWSER_FORMSET *FormSet OPTIONAL, IN FORM_BROWSER_FORM *Form OPTIONAL ) { UINTN Index; EXPRESS_RESULT ReturnVal; EXPRESS_RESULT CompareOne; EFI_STATUS Status; if (ExpList == NULL) { return ExpressFalse; } ASSERT(ExpList->Signature == FORM_EXPRESSION_LIST_SIGNATURE); Index = 0; // // Check whether need to evaluate the expression first. // if (Evaluate) { while (ExpList->Count > Index) { Status = EvaluateExpression (FormSet, Form, ExpList->Expression[Index++]); if (EFI_ERROR (Status)) { return ExpressFalse; } } } // // Run the list of expressions. // ReturnVal = ExpressFalse; for (Index = 0; Index < ExpList->Count; Index++) { if (IsTrue (&ExpList->Expression[Index]->Result)) { switch (ExpList->Expression[Index]->Type) { case EFI_HII_EXPRESSION_SUPPRESS_IF: CompareOne = ExpressSuppress; break; case EFI_HII_EXPRESSION_GRAY_OUT_IF: CompareOne = ExpressGrayOut; break; case EFI_HII_EXPRESSION_DISABLE_IF: CompareOne = ExpressDisable; break; default: return ExpressFalse; } ReturnVal = ReturnVal < CompareOne ? CompareOne : ReturnVal; } } return ReturnVal; }