X-Git-Url: https://git.proxmox.com/?p=mirror_edk2.git;a=blobdiff_plain;f=MdeModulePkg%2FUniversal%2FSetupBrowserDxe%2FExpression.c;h=1938ff2f99cdd5bcc533b622b942f132fdbd187f;hp=508a80524a9dfa359f4924b2460541e783649f39;hb=bef778c1fe67ceddc03a3ac34c8cef9157e01c91;hpb=cbf73e503031172207d39cdabe3bf1b56d453997 diff --git a/MdeModulePkg/Universal/SetupBrowserDxe/Expression.c b/MdeModulePkg/Universal/SetupBrowserDxe/Expression.c index 508a80524a..1938ff2f99 100644 --- a/MdeModulePkg/Universal/SetupBrowserDxe/Expression.c +++ b/MdeModulePkg/Universal/SetupBrowserDxe/Expression.c @@ -1,8 +1,8 @@ /** @file Utility functions for expression evaluation. -Copyright (c) 2007 - 2009, Intel Corporation -All rights reserved. This program and the accompanying materials +Copyright (c) 2007 - 2016, Intel Corporation. All rights reserved.
+This program and the accompanying materials are licensed and made available under the terms and conditions of the BSD License which accompanies this distribution. The full text of the license may be found at http://opensource.org/licenses/bsd-license.php @@ -24,6 +24,28 @@ 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 @@ -131,6 +153,11 @@ PushStack ( // 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; @@ -140,10 +167,8 @@ PushStack ( /** Pop an element from the stack. - @param Stack On input: old stack; On output: new stack - @param StackPtr On input: old stack pointer; On output: new stack - pointer - @param StackEnd On input: old stack end; On output: new stack end + @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. @@ -152,16 +177,15 @@ PushStack ( **/ EFI_STATUS PopStack ( - IN OUT EFI_HII_VALUE **Stack, + IN EFI_HII_VALUE *Stack, IN OUT EFI_HII_VALUE **StackPtr, - IN OUT EFI_HII_VALUE **StackEnd, OUT EFI_HII_VALUE *Data ) { // // Check for a stack underflow condition // - if (*StackPtr == *Stack) { + if (*StackPtr == Stack) { return EFI_ACCESS_DENIED; } @@ -174,6 +198,435 @@ PopStack ( } +/** + 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. @@ -235,9 +688,8 @@ PopScope ( EFI_HII_VALUE Data; Status = PopStack ( - &mOpCodeScopeStack, + mOpCodeScopeStack, &mOpCodeScopeStackPointer, - &mOpCodeScopeStackEnd, &Data ); @@ -247,19 +699,6 @@ PopScope ( } -/** - Reset stack pointer to begin of the stack. - -**/ -VOID -ResetExpressionStack ( - VOID - ) -{ - mExpressionEvaluationStackPointer = mExpressionEvaluationStack; -} - - /** Push an Expression value onto the Stack @@ -299,13 +738,40 @@ PopExpression ( ) { return PopStack ( - &mExpressionEvaluationStack, + mExpressionEvaluationStack + mExpressionEvaluationStackOffset, &mExpressionEvaluationStackPointer, - &mExpressionEvaluationStackEnd, 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; +} /** Get Form given its FormId. @@ -321,7 +787,7 @@ FORM_BROWSER_FORM * IdToForm ( IN FORM_BROWSER_FORMSET *FormSet, IN UINT16 FormId -) + ) { LIST_ENTRY *Link; FORM_BROWSER_FORM *Form; @@ -360,7 +826,7 @@ IdToQuestion2 ( LIST_ENTRY *Link; FORM_BROWSER_STATEMENT *Question; - if (QuestionId == 0) { + if (QuestionId == 0 || Form == NULL) { // // The value of zero is reserved // @@ -425,7 +891,7 @@ IdToQuestion ( // to keep synchronous, always reload the Question Value. // if (Question->Storage->Type == EFI_HII_VARSTORE_EFI_VARIABLE) { - GetQuestionValue (FormSet, Form, Question, FALSE); + GetQuestionValue (FormSet, Form, Question, GetSetValueWithHiiDriver); } return Question; @@ -522,6 +988,129 @@ IfrStrToUpper ( } } +/** + 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. @@ -546,6 +1135,9 @@ IfrToString ( CHAR16 *String; CHAR16 *PrintFormat; CHAR16 Buffer[MAXIMUM_VALUE_CHARACTERS]; + UINT8 *TmpBuf; + UINT8 *SrcBuf; + UINTN SrcLen; UINTN BufferSize; Status = PopExpression (&Value); @@ -574,7 +1166,8 @@ IfrToString ( break; default: - return EFI_UNSUPPORTED; + Result->Type = EFI_IFR_TYPE_UNDEFINED; + return EFI_SUCCESS; } UnicodeSPrint (Buffer, BufferSize, PrintFormat, Value.Value.u64); String = Buffer; @@ -587,9 +1180,44 @@ IfrToString ( 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: - return EFI_UNSUPPORTED; + Result->Type = EFI_IFR_TYPE_UNDEFINED; + return EFI_SUCCESS; } Result->Type = EFI_IFR_TYPE_STRING; @@ -624,8 +1252,9 @@ IfrToUint ( return Status; } - if (Value.Type >= EFI_IFR_TYPE_OTHER) { - return EFI_UNSUPPORTED; + if (Value.Type >= EFI_IFR_TYPE_OTHER && !IsTypeInBuffer(&Value)) { + Result->Type = EFI_IFR_TYPE_UNDEFINED; + return EFI_SUCCESS; } Status = EFI_SUCCESS; @@ -649,6 +1278,18 @@ IfrToUint ( 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; + } + Result->Value.u64 = *(UINT64*) GetBufferForValue (&Value); + if (Value.Type == EFI_IFR_TYPE_BUFFER) { + FreePool (Value.Buffer); + } } else { CopyMem (Result, &Value, sizeof (EFI_HII_VALUE)); } @@ -675,11 +1316,15 @@ IfrCatenate ( ) { EFI_STATUS Status; - EFI_HII_VALUE Value; + 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 @@ -689,33 +1334,137 @@ IfrCatenate ( 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++) { - Status = PopExpression (&Value); - if (EFI_ERROR (Status)) { + if (Value[Index].Type != EFI_IFR_TYPE_STRING && !IsTypeInBuffer(&Value[Index])) { + Result->Type = EFI_IFR_TYPE_UNDEFINED; + Status = EFI_SUCCESS; goto Done; } - if (Value.Type != EFI_IFR_TYPE_STRING) { - Status = EFI_UNSUPPORTED; + 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.Value.string, FormSet->HiiHandle); - if (String[Index] == NULL) { + String[Index] = GetToken (Value[Index].Value.string, FormSet->HiiHandle); + if (String [Index] == NULL) { Status = EFI_NOT_FOUND; goto Done; } } - Size = StrSize (String[0]); - StringPtr= AllocatePool (StrSize (String[1]) + Size); - ASSERT (StringPtr != NULL); - StrCpy (StringPtr, String[1]); - StrCat (StringPtr, String[0]); - - Result->Type = EFI_IFR_TYPE_STRING; - Result->Value.string = NewString (StringPtr, FormSet->HiiHandle); + Result->Type = EFI_IFR_TYPE_BOOLEAN; + Result->Value.b = mUnicodeCollation->MetaiMatch (mUnicodeCollation, String[0], String[1]); Done: if (String[0] != NULL) { @@ -724,18 +1473,15 @@ Done: if (String[1] != NULL) { FreePool (String[1]); } - if (StringPtr != NULL) { - FreePool (StringPtr); - } return Status; } - /** - Evaluate opcode EFI_IFR_MATCH. + 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. @@ -743,15 +1489,23 @@ Done: **/ EFI_STATUS -IfrMatch ( +IfrMatch2 ( IN FORM_BROWSER_FORMSET *FormSet, + IN EFI_GUID *SyntaxType, OUT EFI_HII_VALUE *Result ) { - EFI_STATUS Status; - EFI_HII_VALUE Value; - CHAR16 *String[2]; - UINTN Index; + 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 @@ -759,27 +1513,128 @@ IfrMatch ( // 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++) { - Status = PopExpression (&Value); - if (EFI_ERROR (Status)) { + 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; } + } - if (Value.Type != EFI_IFR_TYPE_STRING) { - Status = EFI_UNSUPPORTED; + 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); - String[Index] = GetToken (Value.Value.string, FormSet->HiiHandle); - if (String [Index] == NULL) { - Status = EFI_NOT_FOUND; + } + + 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); + } } - Result->Type = EFI_IFR_TYPE_BOOLEAN; - Result->Value.b = mUnicodeCollation->MetaiMatch (mUnicodeCollation, String[0], String[1]); + // + // 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) { @@ -788,11 +1643,15 @@ Done: if (String[1] != NULL) { FreePool (String[1]); } - + if (RegExSyntaxTypeList != NULL) { + FreePool (RegExSyntaxTypeList); + } + if (HandleBuffer != NULL) { + FreePool (HandleBuffer); + } return Status; } - /** Evaluate opcode EFI_IFR_FIND. @@ -812,24 +1671,38 @@ IfrFind ( ) { EFI_STATUS Status; - EFI_HII_VALUE Value; + 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_UNSUPPORTED; + return EFI_INVALID_PARAMETER; } - Status = PopExpression (&Value); + Status = PopExpression (&Value[0]); + if (EFI_ERROR (Status)) { + return Status; + } + + Status = PopExpression (&Value[1]); if (EFI_ERROR (Status)) { return Status; } - if (Value.Type > EFI_IFR_TYPE_NUM_SIZE_64) { - return EFI_UNSUPPORTED; + + 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.Value.u64; + Base = (UINTN) Value[0].Value.u64; // // String[0] - sub-string @@ -838,17 +1711,13 @@ IfrFind ( 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; + if (Value[Index + 1].Type != EFI_IFR_TYPE_STRING) { + Result->Type = EFI_IFR_TYPE_UNDEFINED; + Status = EFI_SUCCESS; goto Done; } - String[Index] = GetToken (Value.Value.string, FormSet->HiiHandle); + String[Index] = GetToken (Value[Index + 1].Value.string, FormSet->HiiHandle); if (String[Index] == NULL) { Status = EFI_NOT_FOUND; goto Done; @@ -899,56 +1768,86 @@ IfrMid ( ) { EFI_STATUS Status; - EFI_HII_VALUE Value; + EFI_HII_VALUE Value[3]; CHAR16 *String; UINTN Base; UINTN Length; CHAR16 *SubString; + UINT16 BufferLen; + UINT8 *Buffer; - Status = PopExpression (&Value); + ZeroMem (Value, sizeof (Value)); + + Status = PopExpression (&Value[0]); 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); + Status = PopExpression (&Value[1]); 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); + 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; } - if (Value.Type != EFI_IFR_TYPE_STRING) { - return EFI_UNSUPPORTED; + 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; } - String = GetToken (Value.Value.string, FormSet->HiiHandle); - if (String == NULL) { - return EFI_NOT_FOUND; + 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'; + 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); + Result->Type = EFI_IFR_TYPE_STRING; + Result->Value.string = NewString (SubString, FormSet->HiiHandle); + + FreePool (String); + } else { + BufferLen = GetLengthForValue (&Value[2]); + Buffer = GetBufferForValue (&Value[2]); - FreePool (String); + 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; } @@ -970,7 +1869,7 @@ IfrToken ( ) { EFI_STATUS Status; - EFI_HII_VALUE Value; + EFI_HII_VALUE Value[3]; CHAR16 *String[2]; UINTN Count; CHAR16 *Delimiter; @@ -978,14 +1877,28 @@ IfrToken ( CHAR16 *StringPtr; UINTN Index; - Status = PopExpression (&Value); + ZeroMem (Value, sizeof (Value)); + + Status = PopExpression (&Value[0]); + if (EFI_ERROR (Status)) { + return Status; + } + + Status = PopExpression (&Value[1]); if (EFI_ERROR (Status)) { return Status; } - if (Value.Type > EFI_IFR_TYPE_NUM_SIZE_64) { - return EFI_UNSUPPORTED; + + 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.Value.u64; + Count = (UINTN) Value[0].Value.u64; // // String[0] - Delimiter @@ -994,17 +1907,13 @@ IfrToken ( 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; + if (Value[Index + 1].Type != EFI_IFR_TYPE_STRING) { + Result->Type = EFI_IFR_TYPE_UNDEFINED; + Status = EFI_SUCCESS; goto Done; } - String[Index] = GetToken (Value.Value.string, FormSet->HiiHandle); + String[Index] = GetToken (Value[Index + 1].Value.string, FormSet->HiiHandle); if (String[Index] == NULL) { Status = EFI_NOT_FOUND; goto Done; @@ -1075,7 +1984,7 @@ IfrSpan ( ) { EFI_STATUS Status; - EFI_HII_VALUE Value; + EFI_HII_VALUE Value[3]; CHAR16 *String[2]; CHAR16 *Charset; UINTN Base; @@ -1083,14 +1992,28 @@ IfrSpan ( CHAR16 *StringPtr; BOOLEAN Found; - Status = PopExpression (&Value); + ZeroMem (Value, sizeof (Value)); + + Status = PopExpression (&Value[0]); + if (EFI_ERROR (Status)) { + return Status; + } + + Status = PopExpression (&Value[1]); if (EFI_ERROR (Status)) { return Status; } - if (Value.Type > EFI_IFR_TYPE_NUM_SIZE_64) { - return EFI_UNSUPPORTED; + + 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.Value.u64; + Base = (UINTN) Value[0].Value.u64; // // String[0] - Charset @@ -1099,17 +2022,13 @@ IfrSpan ( 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; + if (Value[Index + 1].Type != EFI_IFR_TYPE_STRING) { + Result->Type = EFI_IFR_TYPE_UNDEFINED; + Status = EFI_SUCCESS; goto Done; } - String[Index] = GetToken (Value.Value.string, FormSet->HiiHandle); + String[Index] = GetToken (Value[Index + 1].Value.string, FormSet->HiiHandle); if (String [Index] == NULL) { Status = EFI_NOT_FOUND; goto Done; @@ -1117,7 +2036,8 @@ IfrSpan ( } if (Base >= StrLen (String[1])) { - Status = EFI_UNSUPPORTED; + Result->Type = EFI_IFR_TYPE_UNDEFINED; + Status = EFI_SUCCESS; goto Done; } @@ -1210,44 +2130,89 @@ ExtendValueToU64 ( 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 EFI_INVALID_PARAMETER Could not perform comparation on two values. - @retval 0 Two operators equeal. - @return Positive value if Value1 is greater than Value2. - @retval Negative value if Value1 is less than Value2. + @retval other Could not perform compare on two values. + @retval EFI_SUCCESS Compare the value success. **/ -INTN +EFI_STATUS CompareHiiValue ( IN EFI_HII_VALUE *Value1, IN EFI_HII_VALUE *Value2, + OUT INTN *Result, IN EFI_HII_HANDLE HiiHandle OPTIONAL ) { - INTN Result; INT64 Temp64; CHAR16 *Str1; CHAR16 *Str2; + UINTN Len; + UINT8 *Buf1; + UINT16 Buf1Len; + UINT8 *Buf2; + UINT16 Buf2Len; - 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->Type == EFI_IFR_TYPE_STRING && Value2->Type == EFI_IFR_TYPE_STRING) { if (Value1->Value.string == 0 || Value2->Value.string == 0) { // // StringId 0 is reserved @@ -1256,7 +2221,8 @@ CompareHiiValue ( } if (Value1->Value.string == Value2->Value.string) { - return 0; + *Result = 0; + return EFI_SUCCESS; } Str1 = GetToken (Value1->Value.string, HiiHandle); @@ -1264,36 +2230,61 @@ CompareHiiValue ( // // String not found // - return EFI_INVALID_PARAMETER; + return EFI_NOT_FOUND; } Str2 = GetToken (Value2->Value.string, HiiHandle); if (Str2 == NULL) { FreePool (Str1); - return EFI_INVALID_PARAMETER; + return EFI_NOT_FOUND; } - Result = StrCmp (Str1, Str2); + *Result = StrCmp (Str1, Str2); FreePool (Str1); FreePool (Str2); - return Result; + return EFI_SUCCESS; } // - // Take remain types(integer, boolean, date/time) as integer + // Take types(date, time, ref, buffer) as buffer // - Temp64 = (INT64) (Value1->Value.u64 - Value2->Value.u64); - if (Temp64 > 0) { - Result = 1; - } else if (Temp64 < 0) { - Result = -1; - } else { - Result = 0; + 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 Result; + return EFI_UNSUPPORTED; } /** @@ -1371,7 +2362,7 @@ CheckUserPrivilege ( 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)) { + if (RemainSize < AccessControl->Size || AccessControl->Size < sizeof (EFI_USER_INFO_ACCESS_CONTROL)) { break; } if (AccessControl->Type == EFI_USER_INFO_ACCESS_SETUP) { @@ -1396,7 +2387,119 @@ CheckUserPrivilege ( FreePool (UserInfo); } - return FALSE; + 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; } /** @@ -1437,12 +2540,25 @@ EvaluateExpression ( 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; // - // Always reset the stack before evaluating an Expression + // Save current stack offset. // - ResetExpressionStack (); + StackOffset = SaveExpressionEvaluationStackOffset (); ASSERT (Expression != NULL); Expression->Result.Type = EFI_IFR_TYPE_OTHER; @@ -1468,12 +2584,19 @@ EvaluateExpression ( case EFI_IFR_EQ_ID_VAL_OP: Question = IdToQuestion (FormSet, Form, OpCode->QuestionId); if (Question == NULL) { - return EFI_NOT_FOUND; + 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; } - Result = CompareHiiValue (&Question->HiiValue, &OpCode->Value, NULL); - if (Result == EFI_INVALID_PARAMETER) { - return EFI_INVALID_PARAMETER; + if (EFI_ERROR (Status)) { + goto Done; } Value->Value.b = (BOOLEAN) ((Result == 0) ? TRUE : FALSE); break; @@ -1481,25 +2604,33 @@ EvaluateExpression ( case EFI_IFR_EQ_ID_ID_OP: Question = IdToQuestion (FormSet, Form, OpCode->QuestionId); if (Question == NULL) { - return EFI_NOT_FOUND; + Value->Type = EFI_IFR_TYPE_UNDEFINED; + break; } Question2 = IdToQuestion (FormSet, Form, OpCode->QuestionId2); if (Question2 == NULL) { - return EFI_NOT_FOUND; + Value->Type = EFI_IFR_TYPE_UNDEFINED; + break; } - Result = CompareHiiValue (&Question->HiiValue, &Question2->HiiValue, FormSet->HiiHandle); - if (Result == EFI_INVALID_PARAMETER) { - return EFI_INVALID_PARAMETER; + 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_LIST_OP: + case EFI_IFR_EQ_ID_VAL_LIST_OP: Question = IdToQuestion (FormSet, Form, OpCode->QuestionId); if (Question == NULL) { - return EFI_NOT_FOUND; + Value->Type = EFI_IFR_TYPE_UNDEFINED; + break; } Value->Value.b = FALSE; @@ -1514,7 +2645,7 @@ EvaluateExpression ( case EFI_IFR_DUP_OP: Status = PopExpression (Value); if (EFI_ERROR (Status)) { - return Status; + goto Done; } Status = PushExpression (Value); @@ -1524,7 +2655,8 @@ EvaluateExpression ( case EFI_IFR_THIS_OP: Question = IdToQuestion (FormSet, Form, OpCode->QuestionId); if (Question == NULL) { - return EFI_NOT_FOUND; + Status = EFI_NOT_FOUND; + goto Done; } Value = &Question->HiiValue; @@ -1534,40 +2666,186 @@ EvaluateExpression ( Value->Value.b = CheckUserPrivilege (&OpCode->Guid); break; - case EFI_IFR_QUESTION_REF3_OP: - if (OpCode->DevicePath == 0) { + 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 { // - // EFI_IFR_QUESTION_REF3 - // Pop an expression from the expression stack + // For Time/Date Data // - Status = PopExpression (Value); - if (EFI_ERROR (Status)) { - return Status; + 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; + } + } } + } - // - // Validate the expression value - // - if ((Value->Type > EFI_IFR_TYPE_NUM_SIZE_64) || (Value->Value.u64 > 0xffff)) { - return EFI_NOT_FOUND; + 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 (CompareGuid (&OpCode->Guid, &gZeroGuid) != 0) { + 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) { - return EFI_NOT_FOUND; + Value->Type = EFI_IFR_TYPE_UNDEFINED; + break; } // // 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; @@ -1577,15 +2855,17 @@ EvaluateExpression ( // RuleExpression = RuleIdToExpression (Form, OpCode->RuleId); if (RuleExpression == NULL) { - return EFI_NOT_FOUND; + Value->Type = EFI_IFR_TYPE_UNDEFINED; + break; } // // Evaluate this rule expression // Status = EvaluateExpression (FormSet, Form, RuleExpression); - if (EFI_ERROR (Status)) { - return Status; + if (EFI_ERROR (Status) || RuleExpression->Result.Type == EFI_IFR_TYPE_UNDEFINED) { + Value->Type = EFI_IFR_TYPE_UNDEFINED; + break; } Value = &RuleExpression->Result; @@ -1619,29 +2899,38 @@ EvaluateExpression ( case EFI_IFR_LENGTH_OP: Status = PopExpression (Value); if (EFI_ERROR (Status)) { - return Status; + goto Done; } - if (Value->Type != EFI_IFR_TYPE_STRING) { - return EFI_INVALID_PARAMETER; + if (Value->Type != EFI_IFR_TYPE_STRING && !IsTypeInBuffer (Value)) { + Value->Type = EFI_IFR_TYPE_UNDEFINED; + break; } - StrPtr = GetToken (Value->Value.string, FormSet->HiiHandle); - if (StrPtr == NULL) { - return EFI_INVALID_PARAMETER; - } + 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); + 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)) { - return Status; + goto Done; } if (Value->Type != EFI_IFR_TYPE_BOOLEAN) { - return EFI_INVALID_PARAMETER; + Value->Type = EFI_IFR_TYPE_UNDEFINED; + break; } Value->Value.b = (BOOLEAN) (!Value->Value.b); break; @@ -1652,19 +2941,21 @@ EvaluateExpression ( // Status = PopExpression (Value); if (EFI_ERROR (Status)) { - return Status; + goto Done; } // // Validate the expression value // if ((Value->Type > EFI_IFR_TYPE_NUM_SIZE_64) || (Value->Value.u64 > 0xffff)) { - return EFI_NOT_FOUND; + Value->Type = EFI_IFR_TYPE_UNDEFINED; + break; } Question = IdToQuestion (FormSet, Form, Value->Value.u16); if (Question == NULL) { - return EFI_NOT_FOUND; + Value->Type = EFI_IFR_TYPE_UNDEFINED; + break; } Value = &Question->HiiValue; @@ -1676,14 +2967,15 @@ EvaluateExpression ( // Status = PopExpression (Value); if (EFI_ERROR (Status)) { - return Status; + goto Done; } // // Validate the expression value // if ((Value->Type > EFI_IFR_TYPE_NUM_SIZE_64) || (Value->Value.u64 > 0xffff)) { - return EFI_NOT_FOUND; + Value->Type = EFI_IFR_TYPE_UNDEFINED; + break; } Value->Type = EFI_IFR_TYPE_STRING; @@ -1706,7 +2998,7 @@ EvaluateExpression ( // Status = PopExpression (Value); if (EFI_ERROR (Status)) { - return Status; + goto Done; } // @@ -1717,27 +3009,50 @@ EvaluateExpression ( // When converting from an unsigned integer, zero will be converted to // FALSE and any other value will be converted to TRUE. // - Value->Value.b = (BOOLEAN) ((Value->Value.u64) ? TRUE : FALSE); + Value->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. + // with "false" is True, then push False. Otherwise, push Undefined. // StrPtr = GetToken (Value->Value.string, FormSet->HiiHandle); if (StrPtr == NULL) { - return EFI_INVALID_PARAMETER; + Status = EFI_INVALID_PARAMETER; + goto Done; } - - if ((StrCmp (StrPtr, L"true") == 0) || (StrCmp (StrPtr, L"false") == 0)){ + + IfrStrToUpper (StrPtr); + if (StrCmp (StrPtr, L"TRUE") == 0){ Value->Value.b = TRUE; - } else { + 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; @@ -1753,21 +3068,23 @@ EvaluateExpression ( case EFI_IFR_TO_UPPER_OP: Status = InitializeUnicodeCollationProtocol (); if (EFI_ERROR (Status)) { - return Status; + goto Done; } Status = PopExpression (Value); if (EFI_ERROR (Status)) { - return Status; + goto Done; } if (Value->Type != EFI_IFR_TYPE_STRING) { - return EFI_UNSUPPORTED; + Value->Type = EFI_IFR_TYPE_UNDEFINED; + break; } StrPtr = GetToken (Value->Value.string, FormSet->HiiHandle); if (StrPtr == NULL) { - return EFI_NOT_FOUND; + Status = EFI_NOT_FOUND; + goto Done; } if (OpCode->Operand == EFI_IFR_TO_LOWER_OP) { @@ -1785,14 +3102,132 @@ EvaluateExpression ( // Status = PopExpression (Value); if (EFI_ERROR (Status)) { - return Status; + goto Done; } if (Value->Type > EFI_IFR_TYPE_DATE) { - return EFI_INVALID_PARAMETER; + Value->Type = EFI_IFR_TYPE_UNDEFINED; + break; } Value->Type = EFI_IFR_TYPE_NUM_SIZE_64; - Value->Value.u64 = ~Value->Value.u64; + 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 --) { + StrPtr += UnicodeValueToString (StrPtr, PREFIX_ZERO | RADIX_HEX, *TempBuffer, 2); + } + 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; // @@ -1812,10 +3247,7 @@ EvaluateExpression ( // Status = PopExpression (&Data2); if (EFI_ERROR (Status)) { - return Status; - } - if (Data2.Type > EFI_IFR_TYPE_DATE) { - return EFI_INVALID_PARAMETER; + goto Done; } // @@ -1823,50 +3255,58 @@ EvaluateExpression ( // Status = PopExpression (&Data1); if (EFI_ERROR (Status)) { - return Status; + goto Done; } + + if (Data2.Type > EFI_IFR_TYPE_DATE) { + Value->Type = EFI_IFR_TYPE_UNDEFINED; + break; + } + + if (Data1.Type > EFI_IFR_TYPE_DATE) { - return EFI_INVALID_PARAMETER; + 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 = Data1.Value.u64 + Data2.Value.u64; + Value->Value.u64 = HiiValueToUINT64(&Data1) + HiiValueToUINT64(&Data2); break; case EFI_IFR_SUBTRACT_OP: - Value->Value.u64 = Data1.Value.u64 - Data2.Value.u64; + Value->Value.u64 = HiiValueToUINT64(&Data1) - HiiValueToUINT64(&Data2); break; case EFI_IFR_MULTIPLY_OP: - Value->Value.u64 = MultU64x32 (Data1.Value.u64, (UINT32) Data2.Value.u64); + Value->Value.u64 = MultU64x32 (HiiValueToUINT64(&Data1), (UINT32) HiiValueToUINT64(&Data2)); break; case EFI_IFR_DIVIDE_OP: - Value->Value.u64 = DivU64x32 (Data1.Value.u64, (UINT32) Data2.Value.u64); + Value->Value.u64 = DivU64x32 (HiiValueToUINT64(&Data1), (UINT32) HiiValueToUINT64(&Data2)); break; case EFI_IFR_MODULO_OP: - DivU64x32Remainder (Data1.Value.u64, (UINT32) Data2.Value.u64, &TempValue); + DivU64x32Remainder (HiiValueToUINT64(&Data1), (UINT32) HiiValueToUINT64(&Data2), &TempValue); Value->Value.u64 = TempValue; break; case EFI_IFR_BITWISE_AND_OP: - Value->Value.u64 = Data1.Value.u64 & Data2.Value.u64; + Value->Value.u64 = HiiValueToUINT64(&Data1) & HiiValueToUINT64(&Data2); break; case EFI_IFR_BITWISE_OR_OP: - Value->Value.u64 = Data1.Value.u64 | Data2.Value.u64; + Value->Value.u64 = HiiValueToUINT64(&Data1) | HiiValueToUINT64(&Data2); break; case EFI_IFR_SHIFT_LEFT_OP: - Value->Value.u64 = LShiftU64 (Data1.Value.u64, (UINTN) Data2.Value.u64); + Value->Value.u64 = LShiftU64 (HiiValueToUINT64(&Data1), (UINTN) HiiValueToUINT64(&Data2)); break; case EFI_IFR_SHIFT_RIGHT_OP: - Value->Value.u64 = RShiftU64 (Data1.Value.u64, (UINTN) Data2.Value.u64); + Value->Value.u64 = RShiftU64 (HiiValueToUINT64(&Data1), (UINTN) HiiValueToUINT64(&Data2)); break; default: @@ -1881,10 +3321,7 @@ EvaluateExpression ( // Status = PopExpression (&Data2); if (EFI_ERROR (Status)) { - return Status; - } - if (Data2.Type != EFI_IFR_TYPE_BOOLEAN) { - return EFI_INVALID_PARAMETER; + goto Done; } // @@ -1892,10 +3329,17 @@ EvaluateExpression ( // Status = PopExpression (&Data1); if (EFI_ERROR (Status)) { - return Status; + goto Done; + } + + if (Data2.Type != EFI_IFR_TYPE_BOOLEAN) { + Value->Type = EFI_IFR_TYPE_UNDEFINED; + break; } + if (Data1.Type != EFI_IFR_TYPE_BOOLEAN) { - return EFI_INVALID_PARAMETER; + Value->Type = EFI_IFR_TYPE_UNDEFINED; + break; } if (OpCode->Operand == EFI_IFR_AND_OP) { @@ -1916,10 +3360,7 @@ EvaluateExpression ( // Status = PopExpression (&Data2); if (EFI_ERROR (Status)) { - return Status; - } - if (Data2.Type > EFI_IFR_TYPE_BOOLEAN && Data2.Type != EFI_IFR_TYPE_STRING) { - return EFI_INVALID_PARAMETER; + goto Done; } // @@ -1927,12 +3368,39 @@ EvaluateExpression ( // Status = PopExpression (&Data1); if (EFI_ERROR (Status)) { - return 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; } - Result = CompareHiiValue (&Data1, &Data2, FormSet->HiiHandle); - if (Result == EFI_INVALID_PARAMETER) { - return EFI_INVALID_PARAMETER; + if (EFI_ERROR (Status)) { + goto Done; } switch (OpCode->Operand) { @@ -1941,7 +3409,7 @@ EvaluateExpression ( break; case EFI_IFR_NOT_EQUAL_OP: - Value->Value.b = (BOOLEAN) ((Result == 0) ? TRUE : FALSE); + Value->Value.b = (BOOLEAN) ((Result != 0) ? TRUE : FALSE); break; case EFI_IFR_GREATER_EQUAL_OP: @@ -1966,9 +3434,18 @@ EvaluateExpression ( 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; @@ -1982,7 +3459,7 @@ EvaluateExpression ( // Status = PopExpression (&Data3); if (EFI_ERROR (Status)) { - return Status; + goto Done; } // @@ -1990,7 +3467,7 @@ EvaluateExpression ( // Status = PopExpression (&Data2); if (EFI_ERROR (Status)) { - return Status; + goto Done; } // @@ -1998,10 +3475,11 @@ EvaluateExpression ( // Status = PopExpression (&Data1); if (EFI_ERROR (Status)) { - return Status; + goto Done; } if (Data1.Type != EFI_IFR_TYPE_BOOLEAN) { - return EFI_INVALID_PARAMETER; + Value->Type = EFI_IFR_TYPE_UNDEFINED; + break; } if (Data1.Value.b) { @@ -2027,16 +3505,87 @@ EvaluateExpression ( 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)) { - return Status; + if (EFI_ERROR (Status) || Value->Type == EFI_IFR_TYPE_UNDEFINED) { + goto Done; } Status = PushExpression (Value); if (EFI_ERROR (Status)) { - return Status; + goto Done; } } @@ -2046,17 +3595,135 @@ EvaluateExpression ( Value = &Data1; Status = PopExpression (Value); if (EFI_ERROR (Status)) { - return Status; + goto Done; } // // After evaluating an expression, there should be only one value left on the expression stack // if (PopExpression (Value) != EFI_ACCESS_DENIED) { - return EFI_INVALID_PARAMETER; + Status = EFI_INVALID_PARAMETER; } - CopyMem (&Expression->Result, Value, sizeof (EFI_HII_VALUE)); +Done: + RestoreExpressionEvaluationStackOffset (StackOffset); + if (!EFI_ERROR (Status)) { + CopyMem (&Expression->Result, Value, sizeof (EFI_HII_VALUE)); + } - return EFI_SUCCESS; + 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; }