2 Utility functions for expression evaluation.
4 Copyright (c) 2007 - 2011, Intel Corporation. All rights reserved.<BR>
5 This program and the accompanying materials
6 are licensed and made available under the terms and conditions of the BSD License
7 which accompanies this distribution. The full text of the license may be found at
8 http://opensource.org/licenses/bsd-license.php
10 THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
11 WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
18 // Global stack used to evaluate boolean expresions
20 EFI_HII_VALUE
*mOpCodeScopeStack
= NULL
;
21 EFI_HII_VALUE
*mOpCodeScopeStackEnd
= NULL
;
22 EFI_HII_VALUE
*mOpCodeScopeStackPointer
= NULL
;
24 EFI_HII_VALUE
*mExpressionEvaluationStack
= NULL
;
25 EFI_HII_VALUE
*mExpressionEvaluationStackEnd
= NULL
;
26 EFI_HII_VALUE
*mExpressionEvaluationStackPointer
= NULL
;
27 UINTN mExpressionEvaluationStackOffset
= 0;
29 EFI_HII_VALUE
*mCurrentExpressionStack
= NULL
;
30 EFI_HII_VALUE
*mCurrentExpressionEnd
= NULL
;
31 EFI_HII_VALUE
*mCurrentExpressionPointer
= NULL
;
33 EFI_HII_VALUE
*mMapExpressionListStack
= NULL
;
34 EFI_HII_VALUE
*mMapExpressionListEnd
= NULL
;
35 EFI_HII_VALUE
*mMapExpressionListPointer
= NULL
;
38 // Unicode collation protocol interface
40 EFI_UNICODE_COLLATION_PROTOCOL
*mUnicodeCollation
= NULL
;
41 EFI_USER_MANAGER_PROTOCOL
*mUserManager
= NULL
;
44 Grow size of the stack.
46 This is an internal function.
48 @param Stack On input: old stack; On output: new stack
49 @param StackPtr On input: old stack pointer; On output: new stack
51 @param StackEnd On input: old stack end; On output: new stack end
53 @retval EFI_SUCCESS Grow stack success.
54 @retval EFI_OUT_OF_RESOURCES No enough memory for stack space.
59 IN OUT EFI_HII_VALUE
**Stack
,
60 IN OUT EFI_HII_VALUE
**StackPtr
,
61 IN OUT EFI_HII_VALUE
**StackEnd
65 EFI_HII_VALUE
*NewStack
;
67 Size
= EXPRESSION_STACK_SIZE_INCREMENT
;
68 if (*StackPtr
!= NULL
) {
69 Size
= Size
+ (*StackEnd
- *Stack
);
72 NewStack
= AllocatePool (Size
* sizeof (EFI_HII_VALUE
));
73 if (NewStack
== NULL
) {
74 return EFI_OUT_OF_RESOURCES
;
77 if (*StackPtr
!= NULL
) {
79 // Copy from Old Stack to the New Stack
84 (*StackEnd
- *Stack
) * sizeof (EFI_HII_VALUE
)
94 // Make the Stack pointer point to the old data in the new stack
96 *StackPtr
= NewStack
+ (*StackPtr
- *Stack
);
98 *StackEnd
= NewStack
+ Size
;
105 Push an element onto the Boolean Stack.
107 @param Stack On input: old stack; On output: new stack
108 @param StackPtr On input: old stack pointer; On output: new stack
110 @param StackEnd On input: old stack end; On output: new stack end
111 @param Data Data to push.
113 @retval EFI_SUCCESS Push stack success.
118 IN OUT EFI_HII_VALUE
**Stack
,
119 IN OUT EFI_HII_VALUE
**StackPtr
,
120 IN OUT EFI_HII_VALUE
**StackEnd
,
121 IN EFI_HII_VALUE
*Data
127 // Check for a stack overflow condition
129 if (*StackPtr
>= *StackEnd
) {
133 Status
= GrowStack (Stack
, StackPtr
, StackEnd
);
134 if (EFI_ERROR (Status
)) {
140 // Push the item onto the stack
142 CopyMem (*StackPtr
, Data
, sizeof (EFI_HII_VALUE
));
143 *StackPtr
= *StackPtr
+ 1;
150 Pop an element from the stack.
152 @param Stack On input: old stack
153 @param StackPtr On input: old stack pointer; On output: new stack pointer
154 @param Data Data to pop.
156 @retval EFI_SUCCESS The value was popped onto the stack.
157 @retval EFI_ACCESS_DENIED The pop operation underflowed the stack
162 IN EFI_HII_VALUE
*Stack
,
163 IN OUT EFI_HII_VALUE
**StackPtr
,
164 OUT EFI_HII_VALUE
*Data
168 // Check for a stack underflow condition
170 if (*StackPtr
== Stack
) {
171 return EFI_ACCESS_DENIED
;
175 // Pop the item off the stack
177 *StackPtr
= *StackPtr
- 1;
178 CopyMem (Data
, *StackPtr
, sizeof (EFI_HII_VALUE
));
184 Reset stack pointer to begin of the stack.
188 ResetCurrentExpressionStack (
192 mCurrentExpressionPointer
= mCurrentExpressionStack
;
197 Push current expression onto the Stack
199 @param Pointer Pointer to current expression.
201 @retval EFI_SUCCESS The value was pushed onto the stack.
202 @retval EFI_OUT_OF_RESOURCES There is not enough system memory to grow the stack.
206 PushCurrentExpression (
212 Data
.Type
= EFI_IFR_TYPE_NUM_SIZE_64
;
213 Data
.Value
.u64
= (UINT64
) (UINTN
) Pointer
;
216 &mCurrentExpressionStack
,
217 &mCurrentExpressionPointer
,
218 &mCurrentExpressionEnd
,
225 Pop current expression from the Stack
227 @param Pointer Pointer to current expression to be pop.
229 @retval EFI_SUCCESS The value was pushed onto the stack.
230 @retval EFI_OUT_OF_RESOURCES There is not enough system memory to grow the stack.
234 PopCurrentExpression (
242 mCurrentExpressionStack
,
243 &mCurrentExpressionPointer
,
247 *Pointer
= (VOID
*) (UINTN
) Data
.Value
.u64
;
253 Reset stack pointer to begin of the stack.
257 ResetMapExpressionListStack (
261 mMapExpressionListPointer
= mMapExpressionListStack
;
266 Push the list of map expression onto the Stack
268 @param Pointer Pointer to the list of map expression to be pushed.
270 @retval EFI_SUCCESS The value was pushed onto the stack.
271 @retval EFI_OUT_OF_RESOURCES There is not enough system memory to grow the stack.
275 PushMapExpressionList (
281 Data
.Type
= EFI_IFR_TYPE_NUM_SIZE_64
;
282 Data
.Value
.u64
= (UINT64
) (UINTN
) Pointer
;
285 &mMapExpressionListStack
,
286 &mMapExpressionListPointer
,
287 &mMapExpressionListEnd
,
294 Pop the list of map expression from the Stack
296 @param Pointer Pointer to the list of map expression to be pop.
298 @retval EFI_SUCCESS The value was pushed onto the stack.
299 @retval EFI_OUT_OF_RESOURCES There is not enough system memory to grow the stack.
303 PopMapExpressionList (
311 mMapExpressionListStack
,
312 &mMapExpressionListPointer
,
316 *Pointer
= (VOID
*) (UINTN
) Data
.Value
.u64
;
322 Reset stack pointer to begin of the stack.
330 mOpCodeScopeStackPointer
= mOpCodeScopeStack
;
335 Push an Operand onto the Stack
337 @param Operand Operand to push.
339 @retval EFI_SUCCESS The value was pushed onto the stack.
340 @retval EFI_OUT_OF_RESOURCES There is not enough system memory to grow the
351 Data
.Type
= EFI_IFR_TYPE_NUM_SIZE_8
;
352 Data
.Value
.u8
= Operand
;
356 &mOpCodeScopeStackPointer
,
357 &mOpCodeScopeStackEnd
,
364 Pop an Operand from the Stack
366 @param Operand Operand to pop.
368 @retval EFI_SUCCESS The value was pushed onto the stack.
369 @retval EFI_OUT_OF_RESOURCES There is not enough system memory to grow the
383 &mOpCodeScopeStackPointer
,
387 *Operand
= Data
.Value
.u8
;
394 Push an Expression value onto the Stack
396 @param Value Expression value to push.
398 @retval EFI_SUCCESS The value was pushed onto the stack.
399 @retval EFI_OUT_OF_RESOURCES There is not enough system memory to grow the
405 IN EFI_HII_VALUE
*Value
409 &mExpressionEvaluationStack
,
410 &mExpressionEvaluationStackPointer
,
411 &mExpressionEvaluationStackEnd
,
418 Pop an Expression value from the stack.
420 @param Value Expression value to pop.
422 @retval EFI_SUCCESS The value was popped onto the stack.
423 @retval EFI_ACCESS_DENIED The pop operation underflowed the stack
428 OUT EFI_HII_VALUE
*Value
432 mExpressionEvaluationStack
+ mExpressionEvaluationStackOffset
,
433 &mExpressionEvaluationStackPointer
,
439 Get current stack offset from stack start.
441 @return Stack offset to stack start.
444 SaveExpressionEvaluationStackOffset (
447 UINTN TempStackOffset
;
448 TempStackOffset
= mExpressionEvaluationStackOffset
;
449 mExpressionEvaluationStackOffset
= mExpressionEvaluationStackPointer
- mExpressionEvaluationStack
;
450 return TempStackOffset
;
454 Restore stack offset based on input stack offset
456 @param StackOffset Offset to stack start.
460 RestoreExpressionEvaluationStackOffset (
464 mExpressionEvaluationStackOffset
= StackOffset
;
468 Get Form given its FormId.
470 @param FormSet The formset which contains this form.
471 @param FormId Id of this form.
473 @retval Pointer The form.
474 @retval NULL Specified Form is not found in the formset.
479 IN FORM_BROWSER_FORMSET
*FormSet
,
484 FORM_BROWSER_FORM
*Form
;
486 Link
= GetFirstNode (&FormSet
->FormListHead
);
487 while (!IsNull (&FormSet
->FormListHead
, Link
)) {
488 Form
= FORM_BROWSER_FORM_FROM_LINK (Link
);
490 if (Form
->FormId
== FormId
) {
494 Link
= GetNextNode (&FormSet
->FormListHead
, Link
);
502 Search a Question in Form scope using its QuestionId.
504 @param Form The form which contains this Question.
505 @param QuestionId Id of this Question.
507 @retval Pointer The Question.
508 @retval NULL Specified Question not found in the form.
511 FORM_BROWSER_STATEMENT
*
513 IN FORM_BROWSER_FORM
*Form
,
518 FORM_BROWSER_STATEMENT
*Question
;
520 if (QuestionId
== 0) {
522 // The value of zero is reserved
527 Link
= GetFirstNode (&Form
->StatementListHead
);
528 while (!IsNull (&Form
->StatementListHead
, Link
)) {
529 Question
= FORM_BROWSER_STATEMENT_FROM_LINK (Link
);
531 if (Question
->QuestionId
== QuestionId
) {
535 Link
= GetNextNode (&Form
->StatementListHead
, Link
);
543 Search a Question in Formset scope using its QuestionId.
545 @param FormSet The formset which contains this form.
546 @param Form The form which contains this Question.
547 @param QuestionId Id of this Question.
549 @retval Pointer The Question.
550 @retval NULL Specified Question not found in the form.
553 FORM_BROWSER_STATEMENT
*
555 IN FORM_BROWSER_FORMSET
*FormSet
,
556 IN FORM_BROWSER_FORM
*Form
,
561 FORM_BROWSER_STATEMENT
*Question
;
564 // Search in the form scope first
566 Question
= IdToQuestion2 (Form
, QuestionId
);
567 if (Question
!= NULL
) {
572 // Search in the formset scope
574 Link
= GetFirstNode (&FormSet
->FormListHead
);
575 while (!IsNull (&FormSet
->FormListHead
, Link
)) {
576 Form
= FORM_BROWSER_FORM_FROM_LINK (Link
);
578 Question
= IdToQuestion2 (Form
, QuestionId
);
579 if (Question
!= NULL
) {
581 // EFI variable storage may be updated by Callback() asynchronous,
582 // to keep synchronous, always reload the Question Value.
584 if (Question
->Storage
->Type
== EFI_HII_VARSTORE_EFI_VARIABLE
) {
585 GetQuestionValue (FormSet
, Form
, Question
, FALSE
);
591 Link
= GetNextNode (&FormSet
->FormListHead
, Link
);
599 Get Expression given its RuleId.
601 @param Form The form which contains this Expression.
602 @param RuleId Id of this Expression.
604 @retval Pointer The Expression.
605 @retval NULL Specified Expression not found in the form.
610 IN FORM_BROWSER_FORM
*Form
,
615 FORM_EXPRESSION
*Expression
;
617 Link
= GetFirstNode (&Form
->ExpressionListHead
);
618 while (!IsNull (&Form
->ExpressionListHead
, Link
)) {
619 Expression
= FORM_EXPRESSION_FROM_LINK (Link
);
621 if (Expression
->Type
== EFI_HII_EXPRESSION_RULE
&& Expression
->RuleId
== RuleId
) {
625 Link
= GetNextNode (&Form
->ExpressionListHead
, Link
);
633 Locate the Unicode Collation Protocol interface for later use.
635 @retval EFI_SUCCESS Protocol interface initialize success.
636 @retval Other Protocol interface initialize failed.
640 InitializeUnicodeCollationProtocol (
646 if (mUnicodeCollation
!= NULL
) {
651 // BUGBUG: Proper impelmentation is to locate all Unicode Collation Protocol
652 // instances first and then select one which support English language.
653 // Current implementation just pick the first instance.
655 Status
= gBS
->LocateProtocol (
656 &gEfiUnicodeCollation2ProtocolGuid
,
658 (VOID
**) &mUnicodeCollation
664 Convert the input Unicode character to upper.
666 @param String Th Unicode character to be converted.
674 while (*String
!= 0) {
675 if ((*String
>= 'a') && (*String
<= 'z')) {
676 *String
= (UINT16
) ((*String
) & ((UINT16
) ~0x20));
684 Evaluate opcode EFI_IFR_TO_STRING.
686 @param FormSet Formset which contains this opcode.
687 @param Format String format in EFI_IFR_TO_STRING.
688 @param Result Evaluation result for this opcode.
690 @retval EFI_SUCCESS Opcode evaluation success.
691 @retval Other Opcode evaluation failed.
696 IN FORM_BROWSER_FORMSET
*FormSet
,
698 OUT EFI_HII_VALUE
*Result
705 CHAR16 Buffer
[MAXIMUM_VALUE_CHARACTERS
];
708 Status
= PopExpression (&Value
);
709 if (EFI_ERROR (Status
)) {
713 switch (Value
.Type
) {
714 case EFI_IFR_TYPE_NUM_SIZE_8
:
715 case EFI_IFR_TYPE_NUM_SIZE_16
:
716 case EFI_IFR_TYPE_NUM_SIZE_32
:
717 case EFI_IFR_TYPE_NUM_SIZE_64
:
718 BufferSize
= MAXIMUM_VALUE_CHARACTERS
* sizeof (CHAR16
);
720 case EFI_IFR_STRING_UNSIGNED_DEC
:
721 case EFI_IFR_STRING_SIGNED_DEC
:
722 PrintFormat
= L
"%ld";
725 case EFI_IFR_STRING_LOWERCASE_HEX
:
726 PrintFormat
= L
"%lx";
729 case EFI_IFR_STRING_UPPERCASE_HEX
:
730 PrintFormat
= L
"%lX";
734 return EFI_UNSUPPORTED
;
736 UnicodeSPrint (Buffer
, BufferSize
, PrintFormat
, Value
.Value
.u64
);
740 case EFI_IFR_TYPE_STRING
:
741 CopyMem (Result
, &Value
, sizeof (EFI_HII_VALUE
));
744 case EFI_IFR_TYPE_BOOLEAN
:
745 String
= (Value
.Value
.b
) ? L
"True" : L
"False";
749 return EFI_UNSUPPORTED
;
752 Result
->Type
= EFI_IFR_TYPE_STRING
;
753 Result
->Value
.string
= NewString (String
, FormSet
->HiiHandle
);
759 Evaluate opcode EFI_IFR_TO_UINT.
761 @param FormSet Formset which contains this opcode.
762 @param Result Evaluation result for this opcode.
764 @retval EFI_SUCCESS Opcode evaluation success.
765 @retval Other Opcode evaluation failed.
770 IN FORM_BROWSER_FORMSET
*FormSet
,
771 OUT EFI_HII_VALUE
*Result
779 Status
= PopExpression (&Value
);
780 if (EFI_ERROR (Status
)) {
784 if (Value
.Type
>= EFI_IFR_TYPE_OTHER
) {
785 return EFI_UNSUPPORTED
;
788 Status
= EFI_SUCCESS
;
789 if (Value
.Type
== EFI_IFR_TYPE_STRING
) {
790 String
= GetToken (Value
.Value
.string
, FormSet
->HiiHandle
);
791 if (String
== NULL
) {
792 return EFI_NOT_FOUND
;
795 IfrStrToUpper (String
);
796 StringPtr
= StrStr (String
, L
"0X");
797 if (StringPtr
!= NULL
) {
801 Result
->Value
.u64
= StrHexToUint64 (String
);
806 Result
->Value
.u64
= StrDecimalToUint64 (String
);
810 CopyMem (Result
, &Value
, sizeof (EFI_HII_VALUE
));
813 Result
->Type
= EFI_IFR_TYPE_NUM_SIZE_64
;
819 Evaluate opcode EFI_IFR_CATENATE.
821 @param FormSet Formset which contains this opcode.
822 @param Result Evaluation result for this opcode.
824 @retval EFI_SUCCESS Opcode evaluation success.
825 @retval Other Opcode evaluation failed.
830 IN FORM_BROWSER_FORMSET
*FormSet
,
831 OUT EFI_HII_VALUE
*Result
842 // String[0] - The second string
843 // String[1] - The first string
848 Status
= EFI_SUCCESS
;
850 for (Index
= 0; Index
< 2; Index
++) {
851 Status
= PopExpression (&Value
);
852 if (EFI_ERROR (Status
)) {
856 if (Value
.Type
!= EFI_IFR_TYPE_STRING
) {
857 Status
= EFI_UNSUPPORTED
;
861 String
[Index
] = GetToken (Value
.Value
.string
, FormSet
->HiiHandle
);
862 if (String
[Index
] == NULL
) {
863 Status
= EFI_NOT_FOUND
;
868 Size
= StrSize (String
[0]);
869 StringPtr
= AllocatePool (StrSize (String
[1]) + Size
);
870 ASSERT (StringPtr
!= NULL
);
871 StrCpy (StringPtr
, String
[1]);
872 StrCat (StringPtr
, String
[0]);
874 Result
->Type
= EFI_IFR_TYPE_STRING
;
875 Result
->Value
.string
= NewString (StringPtr
, FormSet
->HiiHandle
);
878 if (String
[0] != NULL
) {
879 FreePool (String
[0]);
881 if (String
[1] != NULL
) {
882 FreePool (String
[1]);
884 if (StringPtr
!= NULL
) {
885 FreePool (StringPtr
);
893 Evaluate opcode EFI_IFR_MATCH.
895 @param FormSet Formset which contains this opcode.
896 @param Result Evaluation result for this opcode.
898 @retval EFI_SUCCESS Opcode evaluation success.
899 @retval Other Opcode evaluation failed.
904 IN FORM_BROWSER_FORMSET
*FormSet
,
905 OUT EFI_HII_VALUE
*Result
914 // String[0] - The string to search
915 // String[1] - pattern
919 Status
= EFI_SUCCESS
;
920 for (Index
= 0; Index
< 2; Index
++) {
921 Status
= PopExpression (&Value
);
922 if (EFI_ERROR (Status
)) {
926 if (Value
.Type
!= EFI_IFR_TYPE_STRING
) {
927 Status
= EFI_UNSUPPORTED
;
931 String
[Index
] = GetToken (Value
.Value
.string
, FormSet
->HiiHandle
);
932 if (String
[Index
] == NULL
) {
933 Status
= EFI_NOT_FOUND
;
938 Result
->Type
= EFI_IFR_TYPE_BOOLEAN
;
939 Result
->Value
.b
= mUnicodeCollation
->MetaiMatch (mUnicodeCollation
, String
[0], String
[1]);
942 if (String
[0] != NULL
) {
943 FreePool (String
[0]);
945 if (String
[1] != NULL
) {
946 FreePool (String
[1]);
954 Evaluate opcode EFI_IFR_FIND.
956 @param FormSet Formset which contains this opcode.
957 @param Format Case sensitive or insensitive.
958 @param Result Evaluation result for this opcode.
960 @retval EFI_SUCCESS Opcode evaluation success.
961 @retval Other Opcode evaluation failed.
966 IN FORM_BROWSER_FORMSET
*FormSet
,
968 OUT EFI_HII_VALUE
*Result
978 if (Format
> EFI_IFR_FF_CASE_INSENSITIVE
) {
979 return EFI_UNSUPPORTED
;
982 Status
= PopExpression (&Value
);
983 if (EFI_ERROR (Status
)) {
986 if (Value
.Type
> EFI_IFR_TYPE_NUM_SIZE_64
) {
987 return EFI_UNSUPPORTED
;
989 Base
= (UINTN
) Value
.Value
.u64
;
992 // String[0] - sub-string
993 // String[1] - The string to search
997 for (Index
= 0; Index
< 2; Index
++) {
998 Status
= PopExpression (&Value
);
999 if (EFI_ERROR (Status
)) {
1003 if (Value
.Type
!= EFI_IFR_TYPE_STRING
) {
1004 Status
= EFI_UNSUPPORTED
;
1008 String
[Index
] = GetToken (Value
.Value
.string
, FormSet
->HiiHandle
);
1009 if (String
[Index
] == NULL
) {
1010 Status
= EFI_NOT_FOUND
;
1014 if (Format
== EFI_IFR_FF_CASE_INSENSITIVE
) {
1016 // Case insensitive, convert both string to upper case
1018 IfrStrToUpper (String
[Index
]);
1022 Result
->Type
= EFI_IFR_TYPE_NUM_SIZE_64
;
1023 if (Base
>= StrLen (String
[1])) {
1024 Result
->Value
.u64
= 0xFFFFFFFFFFFFFFFFULL
;
1026 StringPtr
= StrStr (String
[1] + Base
, String
[0]);
1027 Result
->Value
.u64
= (StringPtr
== NULL
) ? 0xFFFFFFFFFFFFFFFFULL
: (StringPtr
- String
[1]);
1031 if (String
[0] != NULL
) {
1032 FreePool (String
[0]);
1034 if (String
[1] != NULL
) {
1035 FreePool (String
[1]);
1043 Evaluate opcode EFI_IFR_MID.
1045 @param FormSet Formset which contains this opcode.
1046 @param Result Evaluation result for this opcode.
1048 @retval EFI_SUCCESS Opcode evaluation success.
1049 @retval Other Opcode evaluation failed.
1054 IN FORM_BROWSER_FORMSET
*FormSet
,
1055 OUT EFI_HII_VALUE
*Result
1059 EFI_HII_VALUE Value
;
1065 Status
= PopExpression (&Value
);
1066 if (EFI_ERROR (Status
)) {
1069 if (Value
.Type
> EFI_IFR_TYPE_NUM_SIZE_64
) {
1070 return EFI_UNSUPPORTED
;
1072 Length
= (UINTN
) Value
.Value
.u64
;
1074 Status
= PopExpression (&Value
);
1075 if (EFI_ERROR (Status
)) {
1078 if (Value
.Type
> EFI_IFR_TYPE_NUM_SIZE_64
) {
1079 return EFI_UNSUPPORTED
;
1081 Base
= (UINTN
) Value
.Value
.u64
;
1083 Status
= PopExpression (&Value
);
1084 if (EFI_ERROR (Status
)) {
1087 if (Value
.Type
!= EFI_IFR_TYPE_STRING
) {
1088 return EFI_UNSUPPORTED
;
1090 String
= GetToken (Value
.Value
.string
, FormSet
->HiiHandle
);
1091 if (String
== NULL
) {
1092 return EFI_NOT_FOUND
;
1095 if (Length
== 0 || Base
>= StrLen (String
)) {
1096 SubString
= gEmptyString
;
1098 SubString
= String
+ Base
;
1099 if ((Base
+ Length
) < StrLen (String
)) {
1100 SubString
[Length
] = L
'\0';
1104 Result
->Type
= EFI_IFR_TYPE_STRING
;
1105 Result
->Value
.string
= NewString (SubString
, FormSet
->HiiHandle
);
1114 Evaluate opcode EFI_IFR_TOKEN.
1116 @param FormSet Formset which contains this opcode.
1117 @param Result Evaluation result for this opcode.
1119 @retval EFI_SUCCESS Opcode evaluation success.
1120 @retval Other Opcode evaluation failed.
1125 IN FORM_BROWSER_FORMSET
*FormSet
,
1126 OUT EFI_HII_VALUE
*Result
1130 EFI_HII_VALUE Value
;
1138 Status
= PopExpression (&Value
);
1139 if (EFI_ERROR (Status
)) {
1142 if (Value
.Type
> EFI_IFR_TYPE_NUM_SIZE_64
) {
1143 return EFI_UNSUPPORTED
;
1145 Count
= (UINTN
) Value
.Value
.u64
;
1148 // String[0] - Delimiter
1149 // String[1] - The string to search
1153 for (Index
= 0; Index
< 2; Index
++) {
1154 Status
= PopExpression (&Value
);
1155 if (EFI_ERROR (Status
)) {
1159 if (Value
.Type
!= EFI_IFR_TYPE_STRING
) {
1160 Status
= EFI_UNSUPPORTED
;
1164 String
[Index
] = GetToken (Value
.Value
.string
, FormSet
->HiiHandle
);
1165 if (String
[Index
] == NULL
) {
1166 Status
= EFI_NOT_FOUND
;
1171 Delimiter
= String
[0];
1172 SubString
= String
[1];
1174 SubString
= StrStr (SubString
, Delimiter
);
1175 if (SubString
!= NULL
) {
1177 // Skip over the delimiter
1179 SubString
= SubString
+ StrLen (Delimiter
);
1186 if (SubString
== NULL
) {
1188 // nth delimited sub-string not found, push an empty string
1190 SubString
= gEmptyString
;
1193 // Put a NULL terminator for nth delimited sub-string
1195 StringPtr
= StrStr (SubString
, Delimiter
);
1196 if (StringPtr
!= NULL
) {
1201 Result
->Type
= EFI_IFR_TYPE_STRING
;
1202 Result
->Value
.string
= NewString (SubString
, FormSet
->HiiHandle
);
1205 if (String
[0] != NULL
) {
1206 FreePool (String
[0]);
1208 if (String
[1] != NULL
) {
1209 FreePool (String
[1]);
1217 Evaluate opcode EFI_IFR_SPAN.
1219 @param FormSet Formset which contains this opcode.
1220 @param Flags FIRST_MATCHING or FIRST_NON_MATCHING.
1221 @param Result Evaluation result for this opcode.
1223 @retval EFI_SUCCESS Opcode evaluation success.
1224 @retval Other Opcode evaluation failed.
1229 IN FORM_BROWSER_FORMSET
*FormSet
,
1231 OUT EFI_HII_VALUE
*Result
1235 EFI_HII_VALUE Value
;
1243 Status
= PopExpression (&Value
);
1244 if (EFI_ERROR (Status
)) {
1247 if (Value
.Type
> EFI_IFR_TYPE_NUM_SIZE_64
) {
1248 return EFI_UNSUPPORTED
;
1250 Base
= (UINTN
) Value
.Value
.u64
;
1253 // String[0] - Charset
1254 // String[1] - The string to search
1258 for (Index
= 0; Index
< 2; Index
++) {
1259 Status
= PopExpression (&Value
);
1260 if (EFI_ERROR (Status
)) {
1264 if (Value
.Type
!= EFI_IFR_TYPE_STRING
) {
1265 Status
= EFI_UNSUPPORTED
;
1269 String
[Index
] = GetToken (Value
.Value
.string
, FormSet
->HiiHandle
);
1270 if (String
[Index
] == NULL
) {
1271 Status
= EFI_NOT_FOUND
;
1276 if (Base
>= StrLen (String
[1])) {
1277 Status
= EFI_UNSUPPORTED
;
1282 StringPtr
= String
[1] + Base
;
1283 Charset
= String
[0];
1284 while (*StringPtr
!= 0 && !Found
) {
1286 while (Charset
[Index
] != 0) {
1287 if (*StringPtr
>= Charset
[Index
] && *StringPtr
<= Charset
[Index
+ 1]) {
1288 if (Flags
== EFI_IFR_FLAGS_FIRST_MATCHING
) {
1293 if (Flags
== EFI_IFR_FLAGS_FIRST_NON_MATCHING
) {
1299 // Skip characters pair representing low-end of a range and high-end of a range
1309 Result
->Type
= EFI_IFR_TYPE_NUM_SIZE_64
;
1310 Result
->Value
.u64
= StringPtr
- String
[1];
1313 if (String
[0] != NULL
) {
1314 FreePool (String
[0]);
1316 if (String
[1] != NULL
) {
1317 FreePool (String
[1]);
1325 Zero extend integer/boolean/date/time to UINT64 for comparing.
1327 @param Value HII Value to be converted.
1332 IN EFI_HII_VALUE
*Value
1338 switch (Value
->Type
) {
1339 case EFI_IFR_TYPE_NUM_SIZE_8
:
1340 Temp
= Value
->Value
.u8
;
1343 case EFI_IFR_TYPE_NUM_SIZE_16
:
1344 Temp
= Value
->Value
.u16
;
1347 case EFI_IFR_TYPE_NUM_SIZE_32
:
1348 Temp
= Value
->Value
.u32
;
1351 case EFI_IFR_TYPE_BOOLEAN
:
1352 Temp
= Value
->Value
.b
;
1355 case EFI_IFR_TYPE_TIME
:
1356 Temp
= Value
->Value
.u32
& 0xffffff;
1359 case EFI_IFR_TYPE_DATE
:
1360 Temp
= Value
->Value
.u32
;
1367 Value
->Value
.u64
= Temp
;
1372 Compare two Hii value.
1374 @param Value1 Expression value to compare on left-hand.
1375 @param Value2 Expression value to compare on right-hand.
1376 @param HiiHandle Only required for string compare.
1378 @retval EFI_INVALID_PARAMETER Could not perform compare on two values.
1379 @retval 0 Two operators equal.
1380 @return Positive value if Value1 is greater than Value2.
1381 @retval Negative value if Value1 is less than Value2.
1386 IN EFI_HII_VALUE
*Value1
,
1387 IN EFI_HII_VALUE
*Value2
,
1388 IN EFI_HII_HANDLE HiiHandle OPTIONAL
1396 if (Value1
->Type
>= EFI_IFR_TYPE_OTHER
|| Value2
->Type
>= EFI_IFR_TYPE_OTHER
) {
1397 return EFI_INVALID_PARAMETER
;
1400 if (Value1
->Type
== EFI_IFR_TYPE_STRING
|| Value2
->Type
== EFI_IFR_TYPE_STRING
) {
1401 if (Value1
->Type
!= Value2
->Type
) {
1403 // Both Operator should be type of String
1405 return EFI_INVALID_PARAMETER
;
1408 if (Value1
->Value
.string
== 0 || Value2
->Value
.string
== 0) {
1410 // StringId 0 is reserved
1412 return EFI_INVALID_PARAMETER
;
1415 if (Value1
->Value
.string
== Value2
->Value
.string
) {
1419 Str1
= GetToken (Value1
->Value
.string
, HiiHandle
);
1424 return EFI_INVALID_PARAMETER
;
1427 Str2
= GetToken (Value2
->Value
.string
, HiiHandle
);
1430 return EFI_INVALID_PARAMETER
;
1433 Result
= StrCmp (Str1
, Str2
);
1442 // Take remain types(integer, boolean, date/time) as integer
1444 Temp64
= (INT64
) (Value1
->Value
.u64
- Value2
->Value
.u64
);
1447 } else if (Temp64
< 0) {
1457 Check if current user has the privilege specified by the permissions GUID.
1459 @param[in] Guid A GUID specifying setup access permissions.
1461 @retval TRUE Current user has the privilege.
1462 @retval FALSE Current user does not have the privilege.
1465 CheckUserPrivilege (
1470 EFI_USER_PROFILE_HANDLE UserProfileHandle
;
1471 EFI_USER_INFO_HANDLE UserInfoHandle
;
1472 EFI_USER_INFO
*UserInfo
;
1473 EFI_GUID
*UserPermissionsGuid
;
1475 UINTN AccessControlDataSize
;
1476 EFI_USER_INFO_ACCESS_CONTROL
*AccessControl
;
1479 if (mUserManager
== NULL
) {
1480 Status
= gBS
->LocateProtocol (
1481 &gEfiUserManagerProtocolGuid
,
1483 (VOID
**) &mUserManager
1485 if (EFI_ERROR (Status
)) {
1487 /// If the system does not support user management, then it is assumed that
1488 /// all users have admin privilege and evaluation of each EFI_IFR_SECURITY
1489 /// op-code is always TRUE.
1495 Status
= mUserManager
->Current (mUserManager
, &UserProfileHandle
);
1496 ASSERT_EFI_ERROR (Status
);
1499 /// Enumerate all user information of the current user profile
1500 /// to look for any EFI_USER_INFO_ACCESS_SETUP record.
1503 for (UserInfoHandle
= NULL
;;) {
1504 Status
= mUserManager
->GetNextInfo (mUserManager
, UserProfileHandle
, &UserInfoHandle
);
1505 if (EFI_ERROR (Status
)) {
1510 Status
= mUserManager
->GetInfo (mUserManager
, UserProfileHandle
, UserInfoHandle
, NULL
, &UserInfoSize
);
1511 if (Status
!= EFI_BUFFER_TOO_SMALL
) {
1515 UserInfo
= (EFI_USER_INFO
*) AllocatePool (UserInfoSize
);
1516 if (UserInfo
== NULL
) {
1520 Status
= mUserManager
->GetInfo (mUserManager
, UserProfileHandle
, UserInfoHandle
, UserInfo
, &UserInfoSize
);
1521 if (EFI_ERROR (Status
) ||
1522 UserInfo
->InfoType
!= EFI_USER_INFO_ACCESS_POLICY_RECORD
||
1523 UserInfo
->InfoSize
<= sizeof (EFI_USER_INFO
)) {
1524 FreePool (UserInfo
);
1528 RemainSize
= UserInfo
->InfoSize
- sizeof (EFI_USER_INFO
);
1529 AccessControl
= (EFI_USER_INFO_ACCESS_CONTROL
*)(UserInfo
+ 1);
1530 while (RemainSize
>= sizeof (EFI_USER_INFO_ACCESS_CONTROL
)) {
1531 if (RemainSize
< AccessControl
->Size
|| AccessControl
->Size
< sizeof (EFI_USER_INFO_ACCESS_CONTROL
)) {
1534 if (AccessControl
->Type
== EFI_USER_INFO_ACCESS_SETUP
) {
1536 /// Check if current user has the privilege specified by the permissions GUID.
1539 UserPermissionsGuid
= (EFI_GUID
*)(AccessControl
+ 1);
1540 AccessControlDataSize
= AccessControl
->Size
- sizeof (EFI_USER_INFO_ACCESS_CONTROL
);
1541 while (AccessControlDataSize
>= sizeof (EFI_GUID
)) {
1542 if (CompareGuid (Guid
, UserPermissionsGuid
)) {
1543 FreePool (UserInfo
);
1546 UserPermissionsGuid
++;
1547 AccessControlDataSize
-= sizeof (EFI_GUID
);
1550 RemainSize
-= AccessControl
->Size
;
1551 AccessControl
= (EFI_USER_INFO_ACCESS_CONTROL
*)((UINT8
*)AccessControl
+ AccessControl
->Size
);
1554 FreePool (UserInfo
);
1560 Evaluate the result of a HII expression.
1562 If Expression is NULL, then ASSERT.
1564 @param FormSet FormSet associated with this expression.
1565 @param Form Form associated with this expression.
1566 @param Expression Expression to be evaluated.
1568 @retval EFI_SUCCESS The expression evaluated successfuly
1569 @retval EFI_NOT_FOUND The Question which referenced by a QuestionId
1571 @retval EFI_OUT_OF_RESOURCES There is not enough system memory to grow the
1573 @retval EFI_ACCESS_DENIED The pop operation underflowed the stack
1574 @retval EFI_INVALID_PARAMETER Syntax error with the Expression
1578 EvaluateExpression (
1579 IN FORM_BROWSER_FORMSET
*FormSet
,
1580 IN FORM_BROWSER_FORM
*Form
,
1581 IN OUT FORM_EXPRESSION
*Expression
1586 EXPRESSION_OPCODE
*OpCode
;
1587 FORM_BROWSER_STATEMENT
*Question
;
1588 FORM_BROWSER_STATEMENT
*Question2
;
1590 EFI_HII_VALUE Data1
;
1591 EFI_HII_VALUE Data2
;
1592 EFI_HII_VALUE Data3
;
1593 FORM_EXPRESSION
*RuleExpression
;
1594 EFI_HII_VALUE
*Value
;
1599 LIST_ENTRY
*SubExpressionLink
;
1600 FORM_EXPRESSION
*SubExpression
;
1609 // Save current stack offset.
1611 StackOffset
= SaveExpressionEvaluationStackOffset ();
1613 ASSERT (Expression
!= NULL
);
1614 Expression
->Result
.Type
= EFI_IFR_TYPE_OTHER
;
1616 Link
= GetFirstNode (&Expression
->OpCodeListHead
);
1617 while (!IsNull (&Expression
->OpCodeListHead
, Link
)) {
1618 OpCode
= EXPRESSION_OPCODE_FROM_LINK (Link
);
1620 Link
= GetNextNode (&Expression
->OpCodeListHead
, Link
);
1622 ZeroMem (&Data1
, sizeof (EFI_HII_VALUE
));
1623 ZeroMem (&Data2
, sizeof (EFI_HII_VALUE
));
1624 ZeroMem (&Data3
, sizeof (EFI_HII_VALUE
));
1627 Value
->Type
= EFI_IFR_TYPE_BOOLEAN
;
1628 Status
= EFI_SUCCESS
;
1630 switch (OpCode
->Operand
) {
1632 // Built-in functions
1634 case EFI_IFR_EQ_ID_VAL_OP
:
1635 Question
= IdToQuestion (FormSet
, Form
, OpCode
->QuestionId
);
1636 if (Question
== NULL
) {
1637 Status
= EFI_NOT_FOUND
;
1641 Result
= CompareHiiValue (&Question
->HiiValue
, &OpCode
->Value
, NULL
);
1642 if (Result
== EFI_INVALID_PARAMETER
) {
1643 Status
= EFI_INVALID_PARAMETER
;
1646 Value
->Value
.b
= (BOOLEAN
) ((Result
== 0) ? TRUE
: FALSE
);
1649 case EFI_IFR_EQ_ID_ID_OP
:
1650 Question
= IdToQuestion (FormSet
, Form
, OpCode
->QuestionId
);
1651 if (Question
== NULL
) {
1652 Status
= EFI_NOT_FOUND
;
1656 Question2
= IdToQuestion (FormSet
, Form
, OpCode
->QuestionId2
);
1657 if (Question2
== NULL
) {
1658 Status
= EFI_NOT_FOUND
;
1662 Result
= CompareHiiValue (&Question
->HiiValue
, &Question2
->HiiValue
, FormSet
->HiiHandle
);
1663 if (Result
== EFI_INVALID_PARAMETER
) {
1664 Status
= EFI_INVALID_PARAMETER
;
1667 Value
->Value
.b
= (BOOLEAN
) ((Result
== 0) ? TRUE
: FALSE
);
1670 case EFI_IFR_EQ_ID_LIST_OP
:
1671 Question
= IdToQuestion (FormSet
, Form
, OpCode
->QuestionId
);
1672 if (Question
== NULL
) {
1673 Status
= EFI_NOT_FOUND
;
1677 Value
->Value
.b
= FALSE
;
1678 for (Index
=0; Index
< OpCode
->ListLength
; Index
++) {
1679 if (Question
->HiiValue
.Value
.u16
== OpCode
->ValueList
[Index
]) {
1680 Value
->Value
.b
= TRUE
;
1686 case EFI_IFR_DUP_OP
:
1687 Status
= PopExpression (Value
);
1688 if (EFI_ERROR (Status
)) {
1692 Status
= PushExpression (Value
);
1695 case EFI_IFR_QUESTION_REF1_OP
:
1696 case EFI_IFR_THIS_OP
:
1697 Question
= IdToQuestion (FormSet
, Form
, OpCode
->QuestionId
);
1698 if (Question
== NULL
) {
1699 Status
= EFI_NOT_FOUND
;
1703 Value
= &Question
->HiiValue
;
1706 case EFI_IFR_SECURITY_OP
:
1707 Value
->Value
.b
= CheckUserPrivilege (&OpCode
->Guid
);
1710 case EFI_IFR_GET_OP
:
1712 // Get Value from VarStore buffer, EFI VarStore, Name/Value VarStore.
1714 Value
->Type
= EFI_IFR_TYPE_UNDEFINED
;
1715 Value
->Value
.u8
= 0;
1716 if (OpCode
->VarStorage
!= NULL
) {
1717 switch (OpCode
->VarStorage
->Type
) {
1718 case EFI_HII_VARSTORE_BUFFER
:
1719 case EFI_HII_VARSTORE_EFI_VARIABLE_BUFFER
:
1721 // Get value from Edit Buffer
1723 Value
->Type
= OpCode
->ValueType
;
1724 CopyMem (&Value
->Value
, OpCode
->VarStorage
->EditBuffer
+ OpCode
->VarStoreInfo
.VarOffset
, OpCode
->ValueWidth
);
1726 case EFI_HII_VARSTORE_NAME_VALUE
:
1727 if (OpCode
->ValueType
!= EFI_IFR_TYPE_STRING
) {
1729 // Get value from string except for STRING value.
1731 Status
= GetValueByName (OpCode
->VarStorage
, OpCode
->ValueName
, &StrPtr
);
1732 if (!EFI_ERROR (Status
)) {
1733 ASSERT (StrPtr
!= NULL
);
1734 TempLength
= StrLen (StrPtr
);
1735 if (OpCode
->ValueWidth
>= ((TempLength
+ 1) / 2)) {
1736 Value
->Type
= OpCode
->ValueType
;
1737 TempBuffer
= (UINT8
*) &Value
->Value
;
1738 ZeroMem (TempStr
, sizeof (TempStr
));
1739 for (Index
= 0; Index
< TempLength
; Index
++) {
1740 TempStr
[0] = StrPtr
[TempLength
- Index
- 1];
1741 DigitUint8
= (UINT8
) StrHexToUint64 (TempStr
);
1742 if ((Index
& 1) == 0) {
1743 TempBuffer
[Index
/2] = DigitUint8
;
1745 TempBuffer
[Index
/2] = (UINT8
) ((DigitUint8
<< 4) + TempBuffer
[Index
/2]);
1752 case EFI_HII_VARSTORE_EFI_VARIABLE
:
1754 // Get value from variable.
1756 TempLength
= OpCode
->ValueWidth
;
1757 Value
->Type
= OpCode
->ValueType
;
1758 Status
= gRT
->GetVariable (
1760 &OpCode
->VarStorage
->Guid
,
1765 if (EFI_ERROR (Status
)) {
1766 Value
->Type
= EFI_IFR_TYPE_UNDEFINED
;
1767 Value
->Value
.u8
= 0;
1772 // Not recognize storage.
1774 Status
= EFI_UNSUPPORTED
;
1779 // For Time/Date Data
1781 if (OpCode
->ValueType
!= EFI_IFR_TYPE_DATE
&& OpCode
->ValueType
!= EFI_IFR_TYPE_TIME
) {
1783 // Only support Data/Time data when storage doesn't exist.
1785 Status
= EFI_UNSUPPORTED
;
1788 Status
= gRT
->GetTime (&EfiTime
, NULL
);
1789 if (!EFI_ERROR (Status
)) {
1790 if (OpCode
->ValueType
== EFI_IFR_TYPE_DATE
) {
1791 switch (OpCode
->VarStoreInfo
.VarOffset
) {
1793 Value
->Type
= EFI_IFR_TYPE_NUM_SIZE_16
;
1794 Value
->Value
.u16
= EfiTime
.Year
;
1797 Value
->Type
= EFI_IFR_TYPE_NUM_SIZE_8
;
1798 Value
->Value
.u8
= EfiTime
.Month
;
1801 Value
->Type
= EFI_IFR_TYPE_NUM_SIZE_8
;
1802 Value
->Value
.u8
= EfiTime
.Day
;
1806 // Invalid Date field.
1808 Status
= EFI_INVALID_PARAMETER
;
1812 switch (OpCode
->VarStoreInfo
.VarOffset
) {
1814 Value
->Type
= EFI_IFR_TYPE_NUM_SIZE_8
;
1815 Value
->Value
.u8
= EfiTime
.Hour
;
1818 Value
->Type
= EFI_IFR_TYPE_NUM_SIZE_8
;
1819 Value
->Value
.u8
= EfiTime
.Minute
;
1822 Value
->Type
= EFI_IFR_TYPE_NUM_SIZE_8
;
1823 Value
->Value
.u8
= EfiTime
.Second
;
1827 // Invalid Time field.
1829 Status
= EFI_INVALID_PARAMETER
;
1838 case EFI_IFR_QUESTION_REF3_OP
:
1839 if (OpCode
->DevicePath
== 0) {
1841 // EFI_IFR_QUESTION_REF3
1842 // Pop an expression from the expression stack
1844 Status
= PopExpression (Value
);
1845 if (EFI_ERROR (Status
)) {
1850 // Validate the expression value
1852 if ((Value
->Type
> EFI_IFR_TYPE_NUM_SIZE_64
) || (Value
->Value
.u64
> 0xffff)) {
1853 Status
= EFI_NOT_FOUND
;
1857 Question
= IdToQuestion (FormSet
, Form
, Value
->Value
.u16
);
1858 if (Question
== NULL
) {
1859 Status
= EFI_NOT_FOUND
;
1864 // push the questions' value on to the expression stack
1866 Value
= &Question
->HiiValue
;
1869 // BUGBUG: push 0 for EFI_IFR_QUESTION_REF3_2 and EFI_IFR_QUESTION_REF3_3,
1870 // since it is impractical to evaluate the value of a Question in another
1871 // Hii Package list.
1873 ZeroMem (Value
, sizeof (EFI_HII_VALUE
));
1877 case EFI_IFR_RULE_REF_OP
:
1879 // Find expression for this rule
1881 RuleExpression
= RuleIdToExpression (Form
, OpCode
->RuleId
);
1882 if (RuleExpression
== NULL
) {
1883 Status
= EFI_NOT_FOUND
;
1888 // Evaluate this rule expression
1890 Status
= EvaluateExpression (FormSet
, Form
, RuleExpression
);
1891 if (EFI_ERROR (Status
)) {
1895 Value
= &RuleExpression
->Result
;
1898 case EFI_IFR_STRING_REF1_OP
:
1899 Value
->Type
= EFI_IFR_TYPE_STRING
;
1900 Value
->Value
.string
= OpCode
->Value
.Value
.string
;
1906 case EFI_IFR_TRUE_OP
:
1907 case EFI_IFR_FALSE_OP
:
1908 case EFI_IFR_ONE_OP
:
1909 case EFI_IFR_ONES_OP
:
1910 case EFI_IFR_UINT8_OP
:
1911 case EFI_IFR_UINT16_OP
:
1912 case EFI_IFR_UINT32_OP
:
1913 case EFI_IFR_UINT64_OP
:
1914 case EFI_IFR_UNDEFINED_OP
:
1915 case EFI_IFR_VERSION_OP
:
1916 case EFI_IFR_ZERO_OP
:
1917 Value
= &OpCode
->Value
;
1923 case EFI_IFR_LENGTH_OP
:
1924 Status
= PopExpression (Value
);
1925 if (EFI_ERROR (Status
)) {
1928 if (Value
->Type
!= EFI_IFR_TYPE_STRING
) {
1929 Status
= EFI_INVALID_PARAMETER
;
1933 StrPtr
= GetToken (Value
->Value
.string
, FormSet
->HiiHandle
);
1934 if (StrPtr
== NULL
) {
1935 Status
= EFI_INVALID_PARAMETER
;
1939 Value
->Type
= EFI_IFR_TYPE_NUM_SIZE_64
;
1940 Value
->Value
.u64
= StrLen (StrPtr
);
1944 case EFI_IFR_NOT_OP
:
1945 Status
= PopExpression (Value
);
1946 if (EFI_ERROR (Status
)) {
1949 if (Value
->Type
!= EFI_IFR_TYPE_BOOLEAN
) {
1950 Status
= EFI_INVALID_PARAMETER
;
1953 Value
->Value
.b
= (BOOLEAN
) (!Value
->Value
.b
);
1956 case EFI_IFR_QUESTION_REF2_OP
:
1958 // Pop an expression from the expression stack
1960 Status
= PopExpression (Value
);
1961 if (EFI_ERROR (Status
)) {
1966 // Validate the expression value
1968 if ((Value
->Type
> EFI_IFR_TYPE_NUM_SIZE_64
) || (Value
->Value
.u64
> 0xffff)) {
1969 Status
= EFI_NOT_FOUND
;
1973 Question
= IdToQuestion (FormSet
, Form
, Value
->Value
.u16
);
1974 if (Question
== NULL
) {
1975 Status
= EFI_NOT_FOUND
;
1979 Value
= &Question
->HiiValue
;
1982 case EFI_IFR_STRING_REF2_OP
:
1984 // Pop an expression from the expression stack
1986 Status
= PopExpression (Value
);
1987 if (EFI_ERROR (Status
)) {
1992 // Validate the expression value
1994 if ((Value
->Type
> EFI_IFR_TYPE_NUM_SIZE_64
) || (Value
->Value
.u64
> 0xffff)) {
1995 Status
= EFI_NOT_FOUND
;
1999 Value
->Type
= EFI_IFR_TYPE_STRING
;
2000 StrPtr
= GetToken (Value
->Value
.u16
, FormSet
->HiiHandle
);
2001 if (StrPtr
== NULL
) {
2003 // If String not exit, push an empty string
2005 Value
->Value
.string
= NewString (gEmptyString
, FormSet
->HiiHandle
);
2007 Index
= (UINT16
) Value
->Value
.u64
;
2008 Value
->Value
.string
= Index
;
2013 case EFI_IFR_TO_BOOLEAN_OP
:
2015 // Pop an expression from the expression stack
2017 Status
= PopExpression (Value
);
2018 if (EFI_ERROR (Status
)) {
2023 // Convert an expression to a Boolean
2025 if (Value
->Type
<= EFI_IFR_TYPE_DATE
) {
2027 // When converting from an unsigned integer, zero will be converted to
2028 // FALSE and any other value will be converted to TRUE.
2030 Value
->Value
.b
= (BOOLEAN
) (Value
->Value
.u64
!= 0);
2032 Value
->Type
= EFI_IFR_TYPE_BOOLEAN
;
2033 } else if (Value
->Type
== EFI_IFR_TYPE_STRING
) {
2035 // When converting from a string, if case-insensitive compare
2036 // with "true" is True, then push True. If a case-insensitive compare
2037 // with "false" is True, then push False.
2039 StrPtr
= GetToken (Value
->Value
.string
, FormSet
->HiiHandle
);
2040 if (StrPtr
== NULL
) {
2041 Status
= EFI_INVALID_PARAMETER
;
2045 if ((StrCmp (StrPtr
, L
"true") == 0) || (StrCmp (StrPtr
, L
"false") == 0)){
2046 Value
->Value
.b
= TRUE
;
2048 Value
->Value
.b
= FALSE
;
2051 Value
->Type
= EFI_IFR_TYPE_BOOLEAN
;
2055 case EFI_IFR_TO_STRING_OP
:
2056 Status
= IfrToString (FormSet
, OpCode
->Format
, Value
);
2059 case EFI_IFR_TO_UINT_OP
:
2060 Status
= IfrToUint (FormSet
, Value
);
2063 case EFI_IFR_TO_LOWER_OP
:
2064 case EFI_IFR_TO_UPPER_OP
:
2065 Status
= InitializeUnicodeCollationProtocol ();
2066 if (EFI_ERROR (Status
)) {
2070 Status
= PopExpression (Value
);
2071 if (EFI_ERROR (Status
)) {
2075 if (Value
->Type
!= EFI_IFR_TYPE_STRING
) {
2076 Status
= EFI_UNSUPPORTED
;
2080 StrPtr
= GetToken (Value
->Value
.string
, FormSet
->HiiHandle
);
2081 if (StrPtr
== NULL
) {
2082 Status
= EFI_NOT_FOUND
;
2086 if (OpCode
->Operand
== EFI_IFR_TO_LOWER_OP
) {
2087 mUnicodeCollation
->StrLwr (mUnicodeCollation
, StrPtr
);
2089 mUnicodeCollation
->StrUpr (mUnicodeCollation
, StrPtr
);
2091 Value
->Value
.string
= NewString (StrPtr
, FormSet
->HiiHandle
);
2095 case EFI_IFR_BITWISE_NOT_OP
:
2097 // Pop an expression from the expression stack
2099 Status
= PopExpression (Value
);
2100 if (EFI_ERROR (Status
)) {
2103 if (Value
->Type
> EFI_IFR_TYPE_DATE
) {
2104 Status
= EFI_INVALID_PARAMETER
;
2108 Value
->Type
= EFI_IFR_TYPE_NUM_SIZE_64
;
2109 Value
->Value
.u64
= ~Value
->Value
.u64
;
2112 case EFI_IFR_SET_OP
:
2114 // Pop an expression from the expression stack
2116 Status
= PopExpression (Value
);
2117 if (EFI_ERROR (Status
)) {
2120 Data1
.Type
= EFI_IFR_TYPE_BOOLEAN
;
2121 Data1
.Value
.b
= FALSE
;
2123 // Set value to var storage buffer
2125 if (OpCode
->VarStorage
!= NULL
) {
2126 switch (OpCode
->VarStorage
->Type
) {
2127 case EFI_HII_VARSTORE_BUFFER
:
2128 case EFI_HII_VARSTORE_EFI_VARIABLE_BUFFER
:
2129 CopyMem (OpCode
->VarStorage
->EditBuffer
+ OpCode
->VarStoreInfo
.VarOffset
, &Value
->Value
, OpCode
->ValueWidth
);
2130 Data1
.Value
.b
= TRUE
;
2132 case EFI_HII_VARSTORE_NAME_VALUE
:
2133 if (OpCode
->ValueType
!= EFI_IFR_TYPE_STRING
) {
2134 NameValue
= AllocateZeroPool ((OpCode
->ValueWidth
* 2 + 1) * sizeof (CHAR16
));
2135 ASSERT (Value
!= NULL
);
2137 // Convert Buffer to Hex String
2139 TempBuffer
= (UINT8
*) &Value
->Value
+ OpCode
->ValueWidth
- 1;
2141 for (Index
= 0; Index
< OpCode
->ValueWidth
; Index
++, TempBuffer
--) {
2142 StrPtr
+= UnicodeValueToString (StrPtr
, PREFIX_ZERO
| RADIX_HEX
, *TempBuffer
, 2);
2144 Status
= SetValueByName (OpCode
->VarStorage
, OpCode
->ValueName
, NameValue
, TRUE
);
2145 FreePool (NameValue
);
2146 if (!EFI_ERROR (Status
)) {
2147 Data1
.Value
.b
= TRUE
;
2151 case EFI_HII_VARSTORE_EFI_VARIABLE
:
2152 Status
= gRT
->SetVariable (
2154 &OpCode
->VarStorage
->Guid
,
2155 OpCode
->VarStorage
->Attributes
,
2159 if (!EFI_ERROR (Status
)) {
2160 Data1
.Value
.b
= TRUE
;
2165 // Not recognize storage.
2167 Status
= EFI_UNSUPPORTED
;
2173 // For Time/Date Data
2175 if (OpCode
->ValueType
!= EFI_IFR_TYPE_DATE
&& OpCode
->ValueType
!= EFI_IFR_TYPE_TIME
) {
2177 // Only support Data/Time data when storage doesn't exist.
2179 Status
= EFI_UNSUPPORTED
;
2182 Status
= gRT
->GetTime (&EfiTime
, NULL
);
2183 if (!EFI_ERROR (Status
)) {
2184 if (OpCode
->ValueType
== EFI_IFR_TYPE_DATE
) {
2185 switch (OpCode
->VarStoreInfo
.VarOffset
) {
2187 EfiTime
.Year
= Value
->Value
.u16
;
2190 EfiTime
.Month
= Value
->Value
.u8
;
2193 EfiTime
.Day
= Value
->Value
.u8
;
2197 // Invalid Date field.
2199 Status
= EFI_INVALID_PARAMETER
;
2203 switch (OpCode
->VarStoreInfo
.VarOffset
) {
2205 EfiTime
.Hour
= Value
->Value
.u8
;
2208 EfiTime
.Minute
= Value
->Value
.u8
;
2211 EfiTime
.Second
= Value
->Value
.u8
;
2215 // Invalid Time field.
2217 Status
= EFI_INVALID_PARAMETER
;
2221 Status
= gRT
->SetTime (&EfiTime
);
2222 if (!EFI_ERROR (Status
)) {
2223 Data1
.Value
.b
= TRUE
;
2233 case EFI_IFR_ADD_OP
:
2234 case EFI_IFR_SUBTRACT_OP
:
2235 case EFI_IFR_MULTIPLY_OP
:
2236 case EFI_IFR_DIVIDE_OP
:
2237 case EFI_IFR_MODULO_OP
:
2238 case EFI_IFR_BITWISE_AND_OP
:
2239 case EFI_IFR_BITWISE_OR_OP
:
2240 case EFI_IFR_SHIFT_LEFT_OP
:
2241 case EFI_IFR_SHIFT_RIGHT_OP
:
2243 // Pop an expression from the expression stack
2245 Status
= PopExpression (&Data2
);
2246 if (EFI_ERROR (Status
)) {
2249 if (Data2
.Type
> EFI_IFR_TYPE_DATE
) {
2250 Status
= EFI_INVALID_PARAMETER
;
2255 // Pop another expression from the expression stack
2257 Status
= PopExpression (&Data1
);
2258 if (EFI_ERROR (Status
)) {
2261 if (Data1
.Type
> EFI_IFR_TYPE_DATE
) {
2262 Status
= EFI_INVALID_PARAMETER
;
2266 Value
->Type
= EFI_IFR_TYPE_NUM_SIZE_64
;
2268 switch (OpCode
->Operand
) {
2269 case EFI_IFR_ADD_OP
:
2270 Value
->Value
.u64
= Data1
.Value
.u64
+ Data2
.Value
.u64
;
2273 case EFI_IFR_SUBTRACT_OP
:
2274 Value
->Value
.u64
= Data1
.Value
.u64
- Data2
.Value
.u64
;
2277 case EFI_IFR_MULTIPLY_OP
:
2278 Value
->Value
.u64
= MultU64x32 (Data1
.Value
.u64
, (UINT32
) Data2
.Value
.u64
);
2281 case EFI_IFR_DIVIDE_OP
:
2282 Value
->Value
.u64
= DivU64x32 (Data1
.Value
.u64
, (UINT32
) Data2
.Value
.u64
);
2285 case EFI_IFR_MODULO_OP
:
2286 DivU64x32Remainder (Data1
.Value
.u64
, (UINT32
) Data2
.Value
.u64
, &TempValue
);
2287 Value
->Value
.u64
= TempValue
;
2290 case EFI_IFR_BITWISE_AND_OP
:
2291 Value
->Value
.u64
= Data1
.Value
.u64
& Data2
.Value
.u64
;
2294 case EFI_IFR_BITWISE_OR_OP
:
2295 Value
->Value
.u64
= Data1
.Value
.u64
| Data2
.Value
.u64
;
2298 case EFI_IFR_SHIFT_LEFT_OP
:
2299 Value
->Value
.u64
= LShiftU64 (Data1
.Value
.u64
, (UINTN
) Data2
.Value
.u64
);
2302 case EFI_IFR_SHIFT_RIGHT_OP
:
2303 Value
->Value
.u64
= RShiftU64 (Data1
.Value
.u64
, (UINTN
) Data2
.Value
.u64
);
2311 case EFI_IFR_AND_OP
:
2314 // Two Boolean operator
2316 Status
= PopExpression (&Data2
);
2317 if (EFI_ERROR (Status
)) {
2320 if (Data2
.Type
!= EFI_IFR_TYPE_BOOLEAN
) {
2321 Status
= EFI_INVALID_PARAMETER
;
2326 // Pop another expression from the expression stack
2328 Status
= PopExpression (&Data1
);
2329 if (EFI_ERROR (Status
)) {
2332 if (Data1
.Type
!= EFI_IFR_TYPE_BOOLEAN
) {
2333 Status
= EFI_INVALID_PARAMETER
;
2337 if (OpCode
->Operand
== EFI_IFR_AND_OP
) {
2338 Value
->Value
.b
= (BOOLEAN
) (Data1
.Value
.b
&& Data2
.Value
.b
);
2340 Value
->Value
.b
= (BOOLEAN
) (Data1
.Value
.b
|| Data2
.Value
.b
);
2344 case EFI_IFR_EQUAL_OP
:
2345 case EFI_IFR_NOT_EQUAL_OP
:
2346 case EFI_IFR_GREATER_EQUAL_OP
:
2347 case EFI_IFR_GREATER_THAN_OP
:
2348 case EFI_IFR_LESS_EQUAL_OP
:
2349 case EFI_IFR_LESS_THAN_OP
:
2351 // Compare two integer, string, boolean or date/time
2353 Status
= PopExpression (&Data2
);
2354 if (EFI_ERROR (Status
)) {
2357 if (Data2
.Type
> EFI_IFR_TYPE_BOOLEAN
&& Data2
.Type
!= EFI_IFR_TYPE_STRING
) {
2358 Status
= EFI_INVALID_PARAMETER
;
2363 // Pop another expression from the expression stack
2365 Status
= PopExpression (&Data1
);
2366 if (EFI_ERROR (Status
)) {
2370 Result
= CompareHiiValue (&Data1
, &Data2
, FormSet
->HiiHandle
);
2371 if (Result
== EFI_INVALID_PARAMETER
) {
2372 Status
= EFI_INVALID_PARAMETER
;
2376 switch (OpCode
->Operand
) {
2377 case EFI_IFR_EQUAL_OP
:
2378 Value
->Value
.b
= (BOOLEAN
) ((Result
== 0) ? TRUE
: FALSE
);
2381 case EFI_IFR_NOT_EQUAL_OP
:
2382 Value
->Value
.b
= (BOOLEAN
) ((Result
!= 0) ? TRUE
: FALSE
);
2385 case EFI_IFR_GREATER_EQUAL_OP
:
2386 Value
->Value
.b
= (BOOLEAN
) ((Result
>= 0) ? TRUE
: FALSE
);
2389 case EFI_IFR_GREATER_THAN_OP
:
2390 Value
->Value
.b
= (BOOLEAN
) ((Result
> 0) ? TRUE
: FALSE
);
2393 case EFI_IFR_LESS_EQUAL_OP
:
2394 Value
->Value
.b
= (BOOLEAN
) ((Result
<= 0) ? TRUE
: FALSE
);
2397 case EFI_IFR_LESS_THAN_OP
:
2398 Value
->Value
.b
= (BOOLEAN
) ((Result
< 0) ? TRUE
: FALSE
);
2406 case EFI_IFR_MATCH_OP
:
2407 Status
= IfrMatch (FormSet
, Value
);
2410 case EFI_IFR_CATENATE_OP
:
2411 Status
= IfrCatenate (FormSet
, Value
);
2417 case EFI_IFR_CONDITIONAL_OP
:
2419 // Pop third expression from the expression stack
2421 Status
= PopExpression (&Data3
);
2422 if (EFI_ERROR (Status
)) {
2427 // Pop second expression from the expression stack
2429 Status
= PopExpression (&Data2
);
2430 if (EFI_ERROR (Status
)) {
2435 // Pop first expression from the expression stack
2437 Status
= PopExpression (&Data1
);
2438 if (EFI_ERROR (Status
)) {
2441 if (Data1
.Type
!= EFI_IFR_TYPE_BOOLEAN
) {
2442 Status
= EFI_INVALID_PARAMETER
;
2446 if (Data1
.Value
.b
) {
2453 case EFI_IFR_FIND_OP
:
2454 Status
= IfrFind (FormSet
, OpCode
->Format
, Value
);
2457 case EFI_IFR_MID_OP
:
2458 Status
= IfrMid (FormSet
, Value
);
2461 case EFI_IFR_TOKEN_OP
:
2462 Status
= IfrToken (FormSet
, Value
);
2465 case EFI_IFR_SPAN_OP
:
2466 Status
= IfrSpan (FormSet
, OpCode
->Flags
, Value
);
2469 case EFI_IFR_MAP_OP
:
2471 // Pop the check value
2473 Status
= PopExpression (&Data1
);
2474 if (EFI_ERROR (Status
)) {
2478 // Check MapExpression list is valid.
2480 if (OpCode
->MapExpressionList
.ForwardLink
== NULL
) {
2481 Status
= EFI_INVALID_PARAMETER
;
2485 // Go through map expression list.
2487 SubExpressionLink
= GetFirstNode(&OpCode
->MapExpressionList
);
2488 while (!IsNull (&OpCode
->MapExpressionList
, SubExpressionLink
)) {
2489 SubExpression
= FORM_EXPRESSION_FROM_LINK (SubExpressionLink
);
2491 // Evaluate the first expression in this pair.
2493 Status
= EvaluateExpression (FormSet
, Form
, SubExpression
);
2494 if (EFI_ERROR (Status
)) {
2498 // Compare the expression value with current value
2500 if (CompareHiiValue (&Data1
, &SubExpression
->Result
, NULL
) == 0) {
2502 // Try get the map value.
2504 SubExpressionLink
= GetNextNode (&OpCode
->MapExpressionList
, SubExpressionLink
);
2505 if (IsNull (&OpCode
->MapExpressionList
, SubExpressionLink
)) {
2506 Status
= EFI_INVALID_PARAMETER
;
2509 SubExpression
= FORM_EXPRESSION_FROM_LINK (SubExpressionLink
);
2510 Status
= EvaluateExpression (FormSet
, Form
, SubExpression
);
2511 if (EFI_ERROR (Status
)) {
2514 Value
= &SubExpression
->Result
;
2518 // Skip the second expression on this pair.
2520 SubExpressionLink
= GetNextNode (&OpCode
->MapExpressionList
, SubExpressionLink
);
2521 if (IsNull (&OpCode
->MapExpressionList
, SubExpressionLink
)) {
2522 Status
= EFI_INVALID_PARAMETER
;
2526 // Goto the first expression on next pair.
2528 SubExpressionLink
= GetNextNode (&OpCode
->MapExpressionList
, SubExpressionLink
);
2532 // No map value is found.
2534 if (IsNull (&OpCode
->MapExpressionList
, SubExpressionLink
)) {
2535 Value
->Type
= EFI_IFR_TYPE_UNDEFINED
;
2536 Value
->Value
.u8
= 0;
2543 if (EFI_ERROR (Status
)) {
2547 Status
= PushExpression (Value
);
2548 if (EFI_ERROR (Status
)) {
2554 // Pop the final result from expression stack
2557 Status
= PopExpression (Value
);
2558 if (EFI_ERROR (Status
)) {
2563 // After evaluating an expression, there should be only one value left on the expression stack
2565 if (PopExpression (Value
) != EFI_ACCESS_DENIED
) {
2566 Status
= EFI_INVALID_PARAMETER
;
2570 RestoreExpressionEvaluationStackOffset (StackOffset
);
2571 if (!EFI_ERROR (Status
)) {
2572 CopyMem (&Expression
->Result
, Value
, sizeof (EFI_HII_VALUE
));