2 Utility functions for expression evaluation.
4 Copyright (c) 2007, Intel Corporation
5 All rights reserved. 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.
19 // Global stack used to evaluate boolean expresions
21 EFI_HII_VALUE
*mOpCodeScopeStack
= NULL
;
22 EFI_HII_VALUE
*mOpCodeScopeStackEnd
= NULL
;
23 EFI_HII_VALUE
*mOpCodeScopeStackPointer
= NULL
;
25 EFI_HII_VALUE
*mExpressionEvaluationStack
= NULL
;
26 EFI_HII_VALUE
*mExpressionEvaluationStackEnd
= NULL
;
27 EFI_HII_VALUE
*mExpressionEvaluationStackPointer
= NULL
;
30 // Unicode collation protocol interface
32 EFI_UNICODE_COLLATION_PROTOCOL
*mUnicodeCollation
= NULL
;
36 Grow size of the stack.
38 This is an internal function.
40 @param Stack On input: old stack; On output: new stack
41 @param StackPtr On input: old stack pointer; On output: new stack
43 @param StackEnd On input: old stack end; On output: new stack end
45 @retval EFI_SUCCESS Grow stack success.
46 @retval EFI_OUT_OF_RESOURCES No enough memory for stack space.
51 IN OUT EFI_HII_VALUE
**Stack
,
52 IN OUT EFI_HII_VALUE
**StackPtr
,
53 IN OUT EFI_HII_VALUE
**StackEnd
57 EFI_HII_VALUE
*NewStack
;
59 Size
= EXPRESSION_STACK_SIZE_INCREMENT
;
60 if (*StackPtr
!= NULL
) {
61 Size
= Size
+ (*StackEnd
- *Stack
);
64 NewStack
= AllocatePool (Size
* sizeof (EFI_HII_VALUE
));
65 if (NewStack
== NULL
) {
66 return EFI_OUT_OF_RESOURCES
;
69 if (*StackPtr
!= NULL
) {
71 // Copy from Old Stack to the New Stack
76 (*StackEnd
- *Stack
) * sizeof (EFI_HII_VALUE
)
82 gBS
->FreePool (*Stack
);
86 // Make the Stack pointer point to the old data in the new stack
88 *StackPtr
= NewStack
+ (*StackPtr
- *Stack
);
90 *StackEnd
= NewStack
+ Size
;
97 Push an element onto the Boolean Stack.
99 @param Stack On input: old stack; On output: new stack
100 @param StackPtr On input: old stack pointer; On output: new stack
102 @param StackEnd On input: old stack end; On output: new stack end
103 @param Data Data to push.
105 @retval EFI_SUCCESS Push stack success.
110 IN OUT EFI_HII_VALUE
**Stack
,
111 IN OUT EFI_HII_VALUE
**StackPtr
,
112 IN OUT EFI_HII_VALUE
**StackEnd
,
113 IN EFI_HII_VALUE
*Data
119 // Check for a stack overflow condition
121 if (*StackPtr
>= *StackEnd
) {
125 Status
= GrowStack (Stack
, StackPtr
, StackEnd
);
126 if (EFI_ERROR (Status
)) {
132 // Push the item onto the stack
134 CopyMem (*StackPtr
, Data
, sizeof (EFI_HII_VALUE
));
135 *StackPtr
= *StackPtr
+ 1;
142 Pop an element from the stack.
144 @param Stack On input: old stack; On output: new stack
145 @param StackPtr On input: old stack pointer; On output: new stack
147 @param StackEnd On input: old stack end; On output: new stack end
148 @param Data Data to pop.
150 @retval EFI_SUCCESS The value was popped onto the stack.
151 @retval EFI_ACCESS_DENIED The pop operation underflowed the stack
156 IN OUT EFI_HII_VALUE
**Stack
,
157 IN OUT EFI_HII_VALUE
**StackPtr
,
158 IN OUT EFI_HII_VALUE
**StackEnd
,
159 OUT EFI_HII_VALUE
*Data
163 // Check for a stack underflow condition
165 if (*StackPtr
== *Stack
) {
166 return EFI_ACCESS_DENIED
;
170 // Pop the item off the stack
172 *StackPtr
= *StackPtr
- 1;
173 CopyMem (Data
, *StackPtr
, sizeof (EFI_HII_VALUE
));
179 Reset stack pointer to begin of the stack.
187 mOpCodeScopeStackPointer
= mOpCodeScopeStack
;
192 Push an Operand onto the Stack
194 @param Operand Operand to push.
196 @retval EFI_SUCCESS The value was pushed onto the stack.
197 @retval EFI_OUT_OF_RESOURCES There is not enough system memory to grow the
208 Data
.Type
= EFI_IFR_TYPE_NUM_SIZE_8
;
209 Data
.Value
.u8
= Operand
;
213 &mOpCodeScopeStackPointer
,
214 &mOpCodeScopeStackEnd
,
221 Pop an Operand from the Stack
223 @param Operand Operand to pop.
225 @retval EFI_SUCCESS The value was pushed onto the stack.
226 @retval EFI_OUT_OF_RESOURCES There is not enough system memory to grow the
240 &mOpCodeScopeStackPointer
,
241 &mOpCodeScopeStackEnd
,
245 *Operand
= Data
.Value
.u8
;
252 Reset stack pointer to begin of the stack.
256 ResetExpressionStack (
260 mExpressionEvaluationStackPointer
= mExpressionEvaluationStack
;
265 Push an Expression value onto the Stack
267 @param Value Expression value to push.
269 @retval EFI_SUCCESS The value was pushed onto the stack.
270 @retval EFI_OUT_OF_RESOURCES There is not enough system memory to grow the
276 IN EFI_HII_VALUE
*Value
280 &mExpressionEvaluationStack
,
281 &mExpressionEvaluationStackPointer
,
282 &mExpressionEvaluationStackEnd
,
289 Pop an Expression value from the stack.
291 @param Value Expression value to pop.
293 @retval EFI_SUCCESS The value was popped onto the stack.
294 @retval EFI_ACCESS_DENIED The pop operation underflowed the stack
299 OUT EFI_HII_VALUE
*Value
303 &mExpressionEvaluationStack
,
304 &mExpressionEvaluationStackPointer
,
305 &mExpressionEvaluationStackEnd
,
312 Get Form given its FormId.
314 @param FormSet The formset which contains this form.
315 @param FormId Id of this form.
317 @retval Pointer The form.
318 @retval NULL Specified Form is not found in the formset.
323 IN FORM_BROWSER_FORMSET
*FormSet
,
328 FORM_BROWSER_FORM
*Form
;
330 Link
= GetFirstNode (&FormSet
->FormListHead
);
331 while (!IsNull (&FormSet
->FormListHead
, Link
)) {
332 Form
= FORM_BROWSER_FORM_FROM_LINK (Link
);
334 if (Form
->FormId
== FormId
) {
338 Link
= GetNextNode (&FormSet
->FormListHead
, Link
);
346 Search a Question in Form scope using its QuestionId.
348 @param Form The form which contains this Question.
349 @param QuestionId Id of this Question.
351 @retval Pointer The Question.
352 @retval NULL Specified Question not found in the form.
355 FORM_BROWSER_STATEMENT
*
357 IN FORM_BROWSER_FORM
*Form
,
362 FORM_BROWSER_STATEMENT
*Question
;
364 if (QuestionId
== 0) {
366 // The value of zero is reserved
371 Link
= GetFirstNode (&Form
->StatementListHead
);
372 while (!IsNull (&Form
->StatementListHead
, Link
)) {
373 Question
= FORM_BROWSER_STATEMENT_FROM_LINK (Link
);
375 if (Question
->QuestionId
== QuestionId
) {
379 Link
= GetNextNode (&Form
->StatementListHead
, Link
);
387 Search a Question in Formset scope using its QuestionId.
389 @param FormSet The formset which contains this form.
390 @param Form The form which contains this Question.
391 @param QuestionId Id of this Question.
393 @retval Pointer The Question.
394 @retval NULL Specified Question not found in the form.
397 FORM_BROWSER_STATEMENT
*
399 IN FORM_BROWSER_FORMSET
*FormSet
,
400 IN FORM_BROWSER_FORM
*Form
,
405 FORM_BROWSER_STATEMENT
*Question
;
408 // Search in the form scope first
410 Question
= IdToQuestion2 (Form
, QuestionId
);
411 if (Question
!= NULL
) {
416 // Search in the formset scope
418 Link
= GetFirstNode (&FormSet
->FormListHead
);
419 while (!IsNull (&FormSet
->FormListHead
, Link
)) {
420 Form
= FORM_BROWSER_FORM_FROM_LINK (Link
);
422 Question
= IdToQuestion2 (Form
, QuestionId
);
423 if (Question
!= NULL
) {
427 Link
= GetNextNode (&FormSet
->FormListHead
, Link
);
435 Get Expression given its RuleId.
437 @param Form The form which contains this Expression.
438 @param RuleId Id of this Expression.
440 @retval Pointer The Expression.
441 @retval NULL Specified Expression not found in the form.
446 IN FORM_BROWSER_FORM
*Form
,
451 FORM_EXPRESSION
*Expression
;
453 Link
= GetFirstNode (&Form
->ExpressionListHead
);
454 while (!IsNull (&Form
->ExpressionListHead
, Link
)) {
455 Expression
= FORM_EXPRESSION_FROM_LINK (Link
);
457 if (Expression
->Type
== EFI_HII_EXPRESSION_RULE
&& Expression
->RuleId
== RuleId
) {
461 Link
= GetNextNode (&Form
->ExpressionListHead
, Link
);
469 Locate the Unicode Collation Protocol interface for later use.
471 @retval EFI_SUCCESS Protocol interface initialize success.
472 @retval Other Protocol interface initialize failed.
476 InitializeUnicodeCollationProtocol (
482 if (mUnicodeCollation
!= NULL
) {
487 // BUGBUG: Proper impelmentation is to locate all Unicode Collation Protocol
488 // instances first and then select one which support English language.
489 // Current implementation just pick the first instance.
491 Status
= gBS
->LocateProtocol (
492 &gEfiUnicodeCollation2ProtocolGuid
,
494 (VOID
**) &mUnicodeCollation
500 Convert the input Unicode character to upper.
502 @param String Th Unicode character to be converted.
510 while (*String
!= 0) {
511 if ((*String
>= 'a') && (*String
<= 'z')) {
512 *String
= (UINT16
) ((*String
) & ((UINT16
) ~0x20));
520 Evaluate opcode EFI_IFR_TO_STRING.
522 @param FormSet Formset which contains this opcode.
523 @param Format String format in EFI_IFR_TO_STRING.
524 @param Result Evaluation result for this opcode.
526 @retval EFI_SUCCESS Opcode evaluation success.
527 @retval Other Opcode evaluation failed.
532 IN FORM_BROWSER_FORMSET
*FormSet
,
534 OUT EFI_HII_VALUE
*Result
541 CHAR16 Buffer
[MAXIMUM_VALUE_CHARACTERS
];
544 Status
= PopExpression (&Value
);
545 if (EFI_ERROR (Status
)) {
549 switch (Value
.Type
) {
550 case EFI_IFR_TYPE_NUM_SIZE_8
:
551 case EFI_IFR_TYPE_NUM_SIZE_16
:
552 case EFI_IFR_TYPE_NUM_SIZE_32
:
553 case EFI_IFR_TYPE_NUM_SIZE_64
:
554 BufferSize
= MAXIMUM_VALUE_CHARACTERS
* sizeof (CHAR16
);
556 case EFI_IFR_STRING_UNSIGNED_DEC
:
557 case EFI_IFR_STRING_SIGNED_DEC
:
558 PrintFormat
= L
"%ld";
561 case EFI_IFR_STRING_LOWERCASE_HEX
:
562 PrintFormat
= L
"%lx";
565 case EFI_IFR_STRING_UPPERCASE_HEX
:
566 PrintFormat
= L
"%lX";
570 return EFI_UNSUPPORTED
;
572 UnicodeSPrint (Buffer
, BufferSize
, PrintFormat
, Value
.Value
.u64
);
576 case EFI_IFR_TYPE_STRING
:
577 CopyMem (Result
, &Value
, sizeof (EFI_HII_VALUE
));
580 case EFI_IFR_TYPE_BOOLEAN
:
581 String
= (Value
.Value
.b
) ? L
"True" : L
"False";
585 return EFI_UNSUPPORTED
;
588 Result
->Type
= EFI_IFR_TYPE_STRING
;
589 Result
->Value
.string
= NewString (String
, FormSet
->HiiHandle
);
595 Evaluate opcode EFI_IFR_TO_UINT.
597 @param FormSet Formset which contains this opcode.
598 @param Result Evaluation result for this opcode.
600 @retval EFI_SUCCESS Opcode evaluation success.
601 @retval Other Opcode evaluation failed.
606 IN FORM_BROWSER_FORMSET
*FormSet
,
607 OUT EFI_HII_VALUE
*Result
616 Status
= PopExpression (&Value
);
617 if (EFI_ERROR (Status
)) {
621 if (Value
.Type
>= EFI_IFR_TYPE_OTHER
) {
622 return EFI_UNSUPPORTED
;
625 Status
= EFI_SUCCESS
;
626 if (Value
.Type
== EFI_IFR_TYPE_STRING
) {
627 String
= GetToken (Value
.Value
.string
, FormSet
->HiiHandle
);
628 if (String
== NULL
) {
629 return EFI_NOT_FOUND
;
632 IfrStrToUpper (String
);
633 StringPtr
= StrStr (String
, L
"0X");
634 if (StringPtr
!= NULL
) {
638 BufferSize
= sizeof (UINT64
);
639 Status
= HexStringToBuf ((UINT8
*) &Result
->Value
.u64
, &BufferSize
, StringPtr
+ 2, NULL
);
642 // BUGBUG: Need handle decimal string
645 gBS
->FreePool (String
);
647 CopyMem (Result
, &Value
, sizeof (EFI_HII_VALUE
));
650 Result
->Type
= EFI_IFR_TYPE_NUM_SIZE_64
;
656 Evaluate opcode EFI_IFR_CATENATE.
658 @param FormSet Formset which contains this opcode.
659 @param Result Evaluation result for this opcode.
661 @retval EFI_SUCCESS Opcode evaluation success.
662 @retval Other Opcode evaluation failed.
667 IN FORM_BROWSER_FORMSET
*FormSet
,
668 OUT EFI_HII_VALUE
*Result
679 // String[0] - The second string
680 // String[1] - The first string
685 Status
= EFI_SUCCESS
;
687 for (Index
= 0; Index
< 2; Index
++) {
688 Status
= PopExpression (&Value
);
689 if (EFI_ERROR (Status
)) {
693 if (Value
.Type
!= EFI_IFR_TYPE_STRING
) {
694 Status
= EFI_UNSUPPORTED
;
698 String
[Index
] = GetToken (Value
.Value
.string
, FormSet
->HiiHandle
);
700 Status
= EFI_NOT_FOUND
;
705 Size
= StrSize (String
[0]);
706 StringPtr
= AllocatePool (StrSize (String
[1]) + Size
);
707 ASSERT (StringPtr
!= NULL
);
708 StrCpy (StringPtr
, String
[1]);
709 StrCat (StringPtr
, String
[0]);
711 Result
->Type
= EFI_IFR_TYPE_STRING
;
712 Result
->Value
.string
= NewString (StringPtr
, FormSet
->HiiHandle
);
715 SafeFreePool (String
[0]);
716 SafeFreePool (String
[1]);
717 SafeFreePool (StringPtr
);
724 Evaluate opcode EFI_IFR_MATCH.
726 @param FormSet Formset which contains this opcode.
727 @param Result Evaluation result for this opcode.
729 @retval EFI_SUCCESS Opcode evaluation success.
730 @retval Other Opcode evaluation failed.
735 IN FORM_BROWSER_FORMSET
*FormSet
,
736 OUT EFI_HII_VALUE
*Result
745 // String[0] - The string to search
746 // String[1] - pattern
750 Status
= EFI_SUCCESS
;
751 for (Index
= 0; Index
< 2; Index
++) {
752 Status
= PopExpression (&Value
);
753 if (EFI_ERROR (Status
)) {
757 if (Value
.Type
!= EFI_IFR_TYPE_STRING
) {
758 Status
= EFI_UNSUPPORTED
;
762 String
[Index
] = GetToken (Value
.Value
.string
, FormSet
->HiiHandle
);
764 Status
= EFI_NOT_FOUND
;
769 Result
->Type
= EFI_IFR_TYPE_BOOLEAN
;
770 Result
->Value
.b
= mUnicodeCollation
->MetaiMatch (mUnicodeCollation
, String
[0], String
[1]);
773 SafeFreePool (String
[0]);
774 SafeFreePool (String
[1]);
781 Evaluate opcode EFI_IFR_FIND.
783 @param FormSet Formset which contains this opcode.
784 @param Format Case sensitive or insensitive.
785 @param Result Evaluation result for this opcode.
787 @retval EFI_SUCCESS Opcode evaluation success.
788 @retval Other Opcode evaluation failed.
793 IN FORM_BROWSER_FORMSET
*FormSet
,
795 OUT EFI_HII_VALUE
*Result
805 if (Format
> EFI_IFR_FF_CASE_INSENSITIVE
) {
806 return EFI_UNSUPPORTED
;
809 Status
= PopExpression (&Value
);
810 if (EFI_ERROR (Status
)) {
813 if (Value
.Type
> EFI_IFR_TYPE_NUM_SIZE_64
) {
814 return EFI_UNSUPPORTED
;
816 Base
= (UINTN
) Value
.Value
.u64
;
819 // String[0] - sub-string
820 // String[1] - The string to search
824 for (Index
= 0; Index
< 2; Index
++) {
825 Status
= PopExpression (&Value
);
826 if (EFI_ERROR (Status
)) {
830 if (Value
.Type
!= EFI_IFR_TYPE_STRING
) {
831 Status
= EFI_UNSUPPORTED
;
835 String
[Index
] = GetToken (Value
.Value
.string
, FormSet
->HiiHandle
);
837 Status
= EFI_NOT_FOUND
;
841 if (Format
== EFI_IFR_FF_CASE_INSENSITIVE
) {
843 // Case insensitive, convert both string to upper case
845 IfrStrToUpper (String
[Index
]);
849 Result
->Type
= EFI_IFR_TYPE_NUM_SIZE_64
;
850 if (Base
>= StrLen (String
[1])) {
851 Result
->Value
.u64
= 0xFFFFFFFFFFFFFFFFULL
;
853 StringPtr
= StrStr (String
[1] + Base
, String
[0]);
854 Result
->Value
.u64
= (StringPtr
== NULL
) ? 0xFFFFFFFFFFFFFFFFULL
: (StringPtr
- String
[1]);
858 SafeFreePool (String
[0]);
859 SafeFreePool (String
[1]);
866 Evaluate opcode EFI_IFR_MID.
868 @param FormSet Formset which contains this opcode.
869 @param Result Evaluation result for this opcode.
871 @retval EFI_SUCCESS Opcode evaluation success.
872 @retval Other Opcode evaluation failed.
877 IN FORM_BROWSER_FORMSET
*FormSet
,
878 OUT EFI_HII_VALUE
*Result
888 Status
= PopExpression (&Value
);
889 if (EFI_ERROR (Status
)) {
892 if (Value
.Type
> EFI_IFR_TYPE_NUM_SIZE_64
) {
893 return EFI_UNSUPPORTED
;
895 Length
= (UINTN
) Value
.Value
.u64
;
897 Status
= PopExpression (&Value
);
898 if (EFI_ERROR (Status
)) {
901 if (Value
.Type
> EFI_IFR_TYPE_NUM_SIZE_64
) {
902 return EFI_UNSUPPORTED
;
904 Base
= (UINTN
) Value
.Value
.u64
;
906 Status
= PopExpression (&Value
);
907 if (EFI_ERROR (Status
)) {
910 if (Value
.Type
!= EFI_IFR_TYPE_STRING
) {
911 return EFI_UNSUPPORTED
;
913 String
= GetToken (Value
.Value
.string
, FormSet
->HiiHandle
);
914 if (String
== NULL
) {
915 return EFI_NOT_FOUND
;
918 if (Length
== 0 || Base
>= StrLen (String
)) {
919 SubString
= gEmptyString
;
921 SubString
= String
+ Base
;
922 if ((Base
+ Length
) < StrLen (String
)) {
923 SubString
[Length
] = L
'\0';
927 Result
->Type
= EFI_IFR_TYPE_STRING
;
928 Result
->Value
.string
= NewString (SubString
, FormSet
->HiiHandle
);
930 gBS
->FreePool (String
);
937 Evaluate opcode EFI_IFR_TOKEN.
939 @param FormSet Formset which contains this opcode.
940 @param Result Evaluation result for this opcode.
942 @retval EFI_SUCCESS Opcode evaluation success.
943 @retval Other Opcode evaluation failed.
948 IN FORM_BROWSER_FORMSET
*FormSet
,
949 OUT EFI_HII_VALUE
*Result
961 Status
= PopExpression (&Value
);
962 if (EFI_ERROR (Status
)) {
965 if (Value
.Type
> EFI_IFR_TYPE_NUM_SIZE_64
) {
966 return EFI_UNSUPPORTED
;
968 Count
= (UINTN
) Value
.Value
.u64
;
971 // String[0] - Delimiter
972 // String[1] - The string to search
976 for (Index
= 0; Index
< 2; Index
++) {
977 Status
= PopExpression (&Value
);
978 if (EFI_ERROR (Status
)) {
982 if (Value
.Type
!= EFI_IFR_TYPE_STRING
) {
983 Status
= EFI_UNSUPPORTED
;
987 String
[Index
] = GetToken (Value
.Value
.string
, FormSet
->HiiHandle
);
989 Status
= EFI_NOT_FOUND
;
994 Delimiter
= String
[0];
995 SubString
= String
[1];
997 SubString
= StrStr (SubString
, Delimiter
);
998 if (SubString
!= NULL
) {
1000 // Skip over the delimiter
1002 SubString
= SubString
+ StrLen (Delimiter
);
1009 if (SubString
== NULL
) {
1011 // nth delimited sub-string not found, push an empty string
1013 SubString
= gEmptyString
;
1016 // Put a NULL terminator for nth delimited sub-string
1018 StringPtr
= StrStr (SubString
, Delimiter
);
1019 if (StringPtr
!= NULL
) {
1024 Result
->Type
= EFI_IFR_TYPE_STRING
;
1025 Result
->Value
.string
= NewString (SubString
, FormSet
->HiiHandle
);
1028 SafeFreePool (String
[0]);
1029 SafeFreePool (String
[1]);
1036 Evaluate opcode EFI_IFR_SPAN.
1038 @param FormSet Formset which contains this opcode.
1039 @param Flags FIRST_MATCHING or FIRST_NON_MATCHING.
1040 @param Result Evaluation result for this opcode.
1042 @retval EFI_SUCCESS Opcode evaluation success.
1043 @retval Other Opcode evaluation failed.
1048 IN FORM_BROWSER_FORMSET
*FormSet
,
1050 OUT EFI_HII_VALUE
*Result
1054 EFI_HII_VALUE Value
;
1062 Status
= PopExpression (&Value
);
1063 if (EFI_ERROR (Status
)) {
1066 if (Value
.Type
> EFI_IFR_TYPE_NUM_SIZE_64
) {
1067 return EFI_UNSUPPORTED
;
1069 Base
= (UINTN
) Value
.Value
.u64
;
1072 // String[0] - Charset
1073 // String[1] - The string to search
1077 for (Index
= 0; Index
< 2; Index
++) {
1078 Status
= PopExpression (&Value
);
1079 if (EFI_ERROR (Status
)) {
1083 if (Value
.Type
!= EFI_IFR_TYPE_STRING
) {
1084 Status
= EFI_UNSUPPORTED
;
1088 String
[Index
] = GetToken (Value
.Value
.string
, FormSet
->HiiHandle
);
1089 if (String
== NULL
) {
1090 Status
= EFI_NOT_FOUND
;
1095 if (Base
>= StrLen (String
[1])) {
1096 Status
= EFI_UNSUPPORTED
;
1101 StringPtr
= String
[1] + Base
;
1102 Charset
= String
[0];
1103 while (*StringPtr
!= 0 && !Found
) {
1105 while (Charset
[Index
] != 0) {
1106 if (*StringPtr
>= Charset
[Index
] && *StringPtr
<= Charset
[Index
+ 1]) {
1107 if (Flags
== EFI_IFR_FLAGS_FIRST_MATCHING
) {
1112 if (Flags
== EFI_IFR_FLAGS_FIRST_NON_MATCHING
) {
1118 // Skip characters pair representing low-end of a range and high-end of a range
1128 Result
->Type
= EFI_IFR_TYPE_NUM_SIZE_64
;
1129 Result
->Value
.u64
= StringPtr
- String
[1];
1132 SafeFreePool (String
[0]);
1133 SafeFreePool (String
[1]);
1140 Zero extend integer/boolean/date/time to UINT64 for comparing.
1142 @param Value HII Value to be converted.
1147 IN EFI_HII_VALUE
*Value
1153 switch (Value
->Type
) {
1154 case EFI_IFR_TYPE_NUM_SIZE_8
:
1155 Temp
= Value
->Value
.u8
;
1158 case EFI_IFR_TYPE_NUM_SIZE_16
:
1159 Temp
= Value
->Value
.u16
;
1162 case EFI_IFR_TYPE_NUM_SIZE_32
:
1163 Temp
= Value
->Value
.u32
;
1166 case EFI_IFR_TYPE_BOOLEAN
:
1167 Temp
= Value
->Value
.b
;
1170 case EFI_IFR_TYPE_TIME
:
1171 Temp
= Value
->Value
.u32
& 0xffffff;
1174 case EFI_IFR_TYPE_DATE
:
1175 Temp
= Value
->Value
.u32
;
1182 Value
->Value
.u64
= Temp
;
1187 Compare two Hii value.
1189 @param Value1 Expression value to compare on left-hand.
1190 @param Value2 Expression value to compare on right-hand.
1191 @param HiiHandle Only required for string compare.
1193 @retval EFI_INVALID_PARAMETER Could not perform comparation on two values.
1194 @retval 0 Two operators equeal.
1195 @return Positive value if Value1 is greater than Value2.
1196 @retval Negative value if Value1 is less than Value2.
1201 IN EFI_HII_VALUE
*Value1
,
1202 IN EFI_HII_VALUE
*Value2
,
1203 IN EFI_HII_HANDLE HiiHandle OPTIONAL
1211 if (Value1
->Type
>= EFI_IFR_TYPE_OTHER
|| Value2
->Type
>= EFI_IFR_TYPE_OTHER
) {
1212 return EFI_INVALID_PARAMETER
;
1215 if (Value1
->Type
== EFI_IFR_TYPE_STRING
|| Value2
->Type
== EFI_IFR_TYPE_STRING
) {
1216 if (Value1
->Type
!= Value2
->Type
) {
1218 // Both Operator should be type of String
1220 return EFI_INVALID_PARAMETER
;
1223 if (Value1
->Value
.string
== 0 || Value2
->Value
.string
== 0) {
1225 // StringId 0 is reserved
1227 return EFI_INVALID_PARAMETER
;
1230 if (Value1
->Value
.string
== Value2
->Value
.string
) {
1234 Str1
= GetToken (Value1
->Value
.string
, HiiHandle
);
1239 return EFI_INVALID_PARAMETER
;
1242 Str2
= GetToken (Value2
->Value
.string
, HiiHandle
);
1244 gBS
->FreePool (Str1
);
1245 return EFI_INVALID_PARAMETER
;
1248 Result
= StrCmp (Str1
, Str2
);
1250 gBS
->FreePool (Str1
);
1251 gBS
->FreePool (Str2
);
1257 // Take remain types(integer, boolean, date/time) as integer
1259 Temp64
= (INT64
) (Value1
->Value
.u64
- Value2
->Value
.u64
);
1262 } else if (Temp64
< 0) {
1273 Evaluate the result of a HII expression
1275 @param FormSet FormSet associated with this expression.
1276 @param Form Form associated with this expression.
1277 @param Expression Expression to be evaluated.
1279 @retval EFI_SUCCESS The expression evaluated successfuly
1280 @retval EFI_NOT_FOUND The Question which referenced by a QuestionId
1282 @retval EFI_OUT_OF_RESOURCES There is not enough system memory to grow the
1284 @retval EFI_ACCESS_DENIED The pop operation underflowed the stack
1285 @retval EFI_INVALID_PARAMETER Syntax error with the Expression
1289 EvaluateExpression (
1290 IN FORM_BROWSER_FORMSET
*FormSet
,
1291 IN FORM_BROWSER_FORM
*Form
,
1292 IN OUT FORM_EXPRESSION
*Expression
1297 EXPRESSION_OPCODE
*OpCode
;
1298 FORM_BROWSER_STATEMENT
*Question
;
1299 FORM_BROWSER_STATEMENT
*Question2
;
1301 EFI_HII_VALUE Data1
;
1302 EFI_HII_VALUE Data2
;
1303 EFI_HII_VALUE Data3
;
1304 FORM_EXPRESSION
*RuleExpression
;
1305 EFI_HII_VALUE
*Value
;
1311 // Always reset the stack before evaluating an Expression
1313 ResetExpressionStack ();
1315 Expression
->Result
.Type
= EFI_IFR_TYPE_OTHER
;
1317 Link
= GetFirstNode (&Expression
->OpCodeListHead
);
1318 while (!IsNull (&Expression
->OpCodeListHead
, Link
)) {
1319 OpCode
= EXPRESSION_OPCODE_FROM_LINK (Link
);
1321 Link
= GetNextNode (&Expression
->OpCodeListHead
, Link
);
1323 ZeroMem (&Data1
, sizeof (EFI_HII_VALUE
));
1324 ZeroMem (&Data2
, sizeof (EFI_HII_VALUE
));
1325 ZeroMem (&Data3
, sizeof (EFI_HII_VALUE
));
1328 Value
->Type
= EFI_IFR_TYPE_BOOLEAN
;
1329 Status
= EFI_SUCCESS
;
1331 switch (OpCode
->Operand
) {
1333 // Built-in functions
1335 case EFI_IFR_EQ_ID_VAL_OP
:
1336 Question
= IdToQuestion (FormSet
, Form
, OpCode
->QuestionId
);
1337 if (Question
== NULL
) {
1338 return EFI_NOT_FOUND
;
1341 Result
= CompareHiiValue (&Question
->HiiValue
, &OpCode
->Value
, NULL
);
1342 if (Result
== EFI_INVALID_PARAMETER
) {
1343 return EFI_INVALID_PARAMETER
;
1345 Value
->Value
.b
= (BOOLEAN
) ((Result
== 0) ? TRUE
: FALSE
);
1348 case EFI_IFR_EQ_ID_ID_OP
:
1349 Question
= IdToQuestion (FormSet
, Form
, OpCode
->QuestionId
);
1350 if (Question
== NULL
) {
1351 return EFI_NOT_FOUND
;
1354 Question2
= IdToQuestion (FormSet
, Form
, OpCode
->QuestionId2
);
1355 if (Question2
== NULL
) {
1356 return EFI_NOT_FOUND
;
1359 Result
= CompareHiiValue (&Question
->HiiValue
, &Question2
->HiiValue
, FormSet
->HiiHandle
);
1360 if (Result
== EFI_INVALID_PARAMETER
) {
1361 return EFI_INVALID_PARAMETER
;
1363 Value
->Value
.b
= (BOOLEAN
) ((Result
== 0) ? TRUE
: FALSE
);
1366 case EFI_IFR_EQ_ID_LIST_OP
:
1367 Question
= IdToQuestion (FormSet
, Form
, OpCode
->QuestionId
);
1368 if (Question
== NULL
) {
1369 return EFI_NOT_FOUND
;
1372 Value
->Value
.b
= FALSE
;
1373 for (Index
=0; Index
< OpCode
->ListLength
; Index
++) {
1374 if (Question
->HiiValue
.Value
.u16
== OpCode
->ValueList
[Index
]) {
1375 Value
->Value
.b
= TRUE
;
1381 case EFI_IFR_DUP_OP
:
1382 Status
= PopExpression (Value
);
1383 if (EFI_ERROR (Status
)) {
1387 Status
= PushExpression (Value
);
1390 case EFI_IFR_QUESTION_REF1_OP
:
1391 case EFI_IFR_THIS_OP
:
1392 Question
= IdToQuestion (FormSet
, Form
, OpCode
->QuestionId
);
1393 if (Question
== NULL
) {
1394 return EFI_NOT_FOUND
;
1397 Value
= &Question
->HiiValue
;
1400 case EFI_IFR_QUESTION_REF3_OP
:
1401 if (OpCode
->DevicePath
== 0) {
1403 // EFI_IFR_QUESTION_REF3
1404 // Pop an expression from the expression stack
1406 Status
= PopExpression (Value
);
1407 if (EFI_ERROR (Status
)) {
1412 // Validate the expression value
1414 if ((Value
->Type
> EFI_IFR_TYPE_NUM_SIZE_64
) || (Value
->Value
.u64
> 0xffff)) {
1415 return EFI_NOT_FOUND
;
1418 Question
= IdToQuestion (FormSet
, Form
, Value
->Value
.u16
);
1419 if (Question
== NULL
) {
1420 return EFI_NOT_FOUND
;
1424 // push the questions' value on to the expression stack
1426 Value
= &Question
->HiiValue
;
1429 // BUGBUG: push 0 for EFI_IFR_QUESTION_REF3_2 and EFI_IFR_QUESTION_REF3_3,
1430 // since it is impractical to evaluate the value of a Question in another
1431 // Hii Package list.
1433 ZeroMem (Value
, sizeof (EFI_HII_VALUE
));
1437 case EFI_IFR_RULE_REF_OP
:
1439 // Find expression for this rule
1441 RuleExpression
= RuleIdToExpression (Form
, OpCode
->RuleId
);
1442 if (RuleExpression
== NULL
) {
1443 return EFI_NOT_FOUND
;
1447 // Evaluate this rule expression
1449 Status
= EvaluateExpression (FormSet
, Form
, RuleExpression
);
1450 if (EFI_ERROR (Status
)) {
1454 Value
= &RuleExpression
->Result
;
1457 case EFI_IFR_STRING_REF1_OP
:
1458 Value
->Type
= EFI_IFR_TYPE_STRING
;
1459 Value
->Value
.string
= OpCode
->Value
.Value
.string
;
1465 case EFI_IFR_TRUE_OP
:
1466 case EFI_IFR_FALSE_OP
:
1467 case EFI_IFR_ONE_OP
:
1468 case EFI_IFR_ONES_OP
:
1469 case EFI_IFR_UINT8_OP
:
1470 case EFI_IFR_UINT16_OP
:
1471 case EFI_IFR_UINT32_OP
:
1472 case EFI_IFR_UINT64_OP
:
1473 case EFI_IFR_UNDEFINED_OP
:
1474 case EFI_IFR_VERSION_OP
:
1475 case EFI_IFR_ZERO_OP
:
1476 Value
= &OpCode
->Value
;
1482 case EFI_IFR_LENGTH_OP
:
1483 Status
= PopExpression (Value
);
1484 if (EFI_ERROR (Status
)) {
1487 if (Value
->Type
!= EFI_IFR_TYPE_STRING
) {
1488 return EFI_INVALID_PARAMETER
;
1491 StrPtr
= GetToken (Value
->Value
.string
, FormSet
->HiiHandle
);
1492 if (StrPtr
== NULL
) {
1493 return EFI_INVALID_PARAMETER
;
1496 Value
->Type
= EFI_IFR_TYPE_NUM_SIZE_64
;
1497 Value
->Value
.u64
= StrLen (StrPtr
);
1498 gBS
->FreePool (StrPtr
);
1501 case EFI_IFR_NOT_OP
:
1502 Status
= PopExpression (Value
);
1503 if (EFI_ERROR (Status
)) {
1506 if (Value
->Type
!= EFI_IFR_TYPE_BOOLEAN
) {
1507 return EFI_INVALID_PARAMETER
;
1509 Value
->Value
.b
= (BOOLEAN
) (!Value
->Value
.b
);
1512 case EFI_IFR_QUESTION_REF2_OP
:
1514 // Pop an expression from the expression stack
1516 Status
= PopExpression (Value
);
1517 if (EFI_ERROR (Status
)) {
1522 // Validate the expression value
1524 if ((Value
->Type
> EFI_IFR_TYPE_NUM_SIZE_64
) || (Value
->Value
.u64
> 0xffff)) {
1525 return EFI_NOT_FOUND
;
1528 Question
= IdToQuestion (FormSet
, Form
, Value
->Value
.u16
);
1529 if (Question
== NULL
) {
1530 return EFI_NOT_FOUND
;
1533 Value
= &Question
->HiiValue
;
1536 case EFI_IFR_STRING_REF2_OP
:
1538 // Pop an expression from the expression stack
1540 Status
= PopExpression (Value
);
1541 if (EFI_ERROR (Status
)) {
1546 // Validate the expression value
1548 if ((Value
->Type
> EFI_IFR_TYPE_NUM_SIZE_64
) || (Value
->Value
.u64
> 0xffff)) {
1549 return EFI_NOT_FOUND
;
1552 Value
->Type
= EFI_IFR_TYPE_STRING
;
1553 StrPtr
= GetToken (Value
->Value
.u16
, FormSet
->HiiHandle
);
1554 if (StrPtr
== NULL
) {
1556 // If String not exit, push an empty string
1558 Value
->Value
.string
= NewString (gEmptyString
, FormSet
->HiiHandle
);
1560 Index
= (UINT16
) Value
->Value
.u64
;
1561 Value
->Value
.string
= Index
;
1562 gBS
->FreePool (StrPtr
);
1566 case EFI_IFR_TO_BOOLEAN_OP
:
1568 // Pop an expression from the expression stack
1570 Status
= PopExpression (Value
);
1571 if (EFI_ERROR (Status
)) {
1576 // Convert an expression to a Boolean
1578 if (Value
->Type
<= EFI_IFR_TYPE_DATE
) {
1580 // When converting from an unsigned integer, zero will be converted to
1581 // FALSE and any other value will be converted to TRUE.
1583 Value
->Value
.b
= (BOOLEAN
) ((Value
->Value
.u64
) ? TRUE
: FALSE
);
1585 Value
->Type
= EFI_IFR_TYPE_BOOLEAN
;
1586 } else if (Value
->Type
== EFI_IFR_TYPE_STRING
) {
1588 // When converting from a string, if case-insensitive compare
1589 // with "true" is True, then push True. If a case-insensitive compare
1590 // with "false" is True, then push False.
1592 StrPtr
= GetToken (Value
->Value
.string
, FormSet
->HiiHandle
);
1593 if (StrPtr
== NULL
) {
1594 return EFI_INVALID_PARAMETER
;
1597 if ((StrCmp (StrPtr
, L
"true") == 0) || (StrCmp (StrPtr
, L
"false") == 0)){
1598 Value
->Value
.b
= TRUE
;
1600 Value
->Value
.b
= FALSE
;
1602 gBS
->FreePool (StrPtr
);
1603 Value
->Type
= EFI_IFR_TYPE_BOOLEAN
;
1607 case EFI_IFR_TO_STRING_OP
:
1608 Status
= IfrToString (FormSet
, OpCode
->Format
, Value
);
1611 case EFI_IFR_TO_UINT_OP
:
1612 Status
= IfrToUint (FormSet
, Value
);
1615 case EFI_IFR_TO_LOWER_OP
:
1616 case EFI_IFR_TO_UPPER_OP
:
1617 Status
= InitializeUnicodeCollationProtocol ();
1618 if (EFI_ERROR (Status
)) {
1622 Status
= PopExpression (Value
);
1623 if (EFI_ERROR (Status
)) {
1627 if (Value
->Type
!= EFI_IFR_TYPE_STRING
) {
1628 return EFI_UNSUPPORTED
;
1631 StrPtr
= GetToken (Value
->Value
.string
, FormSet
->HiiHandle
);
1632 if (StrPtr
== NULL
) {
1633 return EFI_NOT_FOUND
;
1636 if (OpCode
->Operand
== EFI_IFR_TO_LOWER_OP
) {
1637 mUnicodeCollation
->StrLwr (mUnicodeCollation
, StrPtr
);
1639 mUnicodeCollation
->StrUpr (mUnicodeCollation
, StrPtr
);
1641 Value
->Value
.string
= NewString (StrPtr
, FormSet
->HiiHandle
);
1642 gBS
->FreePool (StrPtr
);
1645 case EFI_IFR_BITWISE_NOT_OP
:
1647 // Pop an expression from the expression stack
1649 Status
= PopExpression (Value
);
1650 if (EFI_ERROR (Status
)) {
1653 if (Value
->Type
> EFI_IFR_TYPE_DATE
) {
1654 return EFI_INVALID_PARAMETER
;
1657 Value
->Type
= EFI_IFR_TYPE_NUM_SIZE_64
;
1658 Value
->Value
.u64
= ~Value
->Value
.u64
;
1664 case EFI_IFR_ADD_OP
:
1665 case EFI_IFR_SUBTRACT_OP
:
1666 case EFI_IFR_MULTIPLY_OP
:
1667 case EFI_IFR_DIVIDE_OP
:
1668 case EFI_IFR_MODULO_OP
:
1669 case EFI_IFR_BITWISE_AND_OP
:
1670 case EFI_IFR_BITWISE_OR_OP
:
1671 case EFI_IFR_SHIFT_LEFT_OP
:
1672 case EFI_IFR_SHIFT_RIGHT_OP
:
1674 // Pop an expression from the expression stack
1676 Status
= PopExpression (&Data2
);
1677 if (EFI_ERROR (Status
)) {
1680 if (Data2
.Type
> EFI_IFR_TYPE_DATE
) {
1681 return EFI_INVALID_PARAMETER
;
1685 // Pop another expression from the expression stack
1687 Status
= PopExpression (&Data1
);
1688 if (EFI_ERROR (Status
)) {
1691 if (Data1
.Type
> EFI_IFR_TYPE_DATE
) {
1692 return EFI_INVALID_PARAMETER
;
1695 Value
->Type
= EFI_IFR_TYPE_NUM_SIZE_64
;
1697 switch (OpCode
->Operand
) {
1698 case EFI_IFR_ADD_OP
:
1699 Value
->Value
.u64
= Data1
.Value
.u64
+ Data2
.Value
.u64
;
1702 case EFI_IFR_SUBTRACT_OP
:
1703 Value
->Value
.u64
= Data1
.Value
.u64
- Data2
.Value
.u64
;
1706 case EFI_IFR_MULTIPLY_OP
:
1707 Value
->Value
.u64
= MultU64x32 (Data1
.Value
.u64
, (UINT32
) Data2
.Value
.u64
);
1710 case EFI_IFR_DIVIDE_OP
:
1711 Value
->Value
.u64
= DivU64x32 (Data1
.Value
.u64
, (UINT32
) Data2
.Value
.u64
);
1714 case EFI_IFR_MODULO_OP
:
1715 DivU64x32Remainder (Data1
.Value
.u64
, (UINT32
) Data2
.Value
.u64
, &TempValue
);
1716 Value
->Value
.u64
= TempValue
;
1719 case EFI_IFR_BITWISE_AND_OP
:
1720 Value
->Value
.u64
= Data1
.Value
.u64
& Data2
.Value
.u64
;
1723 case EFI_IFR_BITWISE_OR_OP
:
1724 Value
->Value
.u64
= Data1
.Value
.u64
| Data2
.Value
.u64
;
1727 case EFI_IFR_SHIFT_LEFT_OP
:
1728 Value
->Value
.u64
= LShiftU64 (Data1
.Value
.u64
, (UINTN
) Data2
.Value
.u64
);
1731 case EFI_IFR_SHIFT_RIGHT_OP
:
1732 Value
->Value
.u64
= RShiftU64 (Data1
.Value
.u64
, (UINTN
) Data2
.Value
.u64
);
1740 case EFI_IFR_AND_OP
:
1743 // Two Boolean operator
1745 Status
= PopExpression (&Data2
);
1746 if (EFI_ERROR (Status
)) {
1749 if (Data2
.Type
!= EFI_IFR_TYPE_BOOLEAN
) {
1750 return EFI_INVALID_PARAMETER
;
1754 // Pop another expression from the expression stack
1756 Status
= PopExpression (&Data1
);
1757 if (EFI_ERROR (Status
)) {
1760 if (Data1
.Type
!= EFI_IFR_TYPE_BOOLEAN
) {
1761 return EFI_INVALID_PARAMETER
;
1764 if (OpCode
->Operand
== EFI_IFR_AND_OP
) {
1765 Value
->Value
.b
= (BOOLEAN
) (Data1
.Value
.b
&& Data2
.Value
.b
);
1767 Value
->Value
.b
= (BOOLEAN
) (Data1
.Value
.b
|| Data2
.Value
.b
);
1771 case EFI_IFR_EQUAL_OP
:
1772 case EFI_IFR_NOT_EQUAL_OP
:
1773 case EFI_IFR_GREATER_EQUAL_OP
:
1774 case EFI_IFR_GREATER_THAN_OP
:
1775 case EFI_IFR_LESS_EQUAL_OP
:
1776 case EFI_IFR_LESS_THAN_OP
:
1778 // Compare two integer, string, boolean or date/time
1780 Status
= PopExpression (&Data2
);
1781 if (EFI_ERROR (Status
)) {
1784 if (Data2
.Type
> EFI_IFR_TYPE_BOOLEAN
&& Data2
.Type
!= EFI_IFR_TYPE_STRING
) {
1785 return EFI_INVALID_PARAMETER
;
1789 // Pop another expression from the expression stack
1791 Status
= PopExpression (&Data1
);
1792 if (EFI_ERROR (Status
)) {
1796 Result
= CompareHiiValue (&Data1
, &Data2
, FormSet
->HiiHandle
);
1797 if (Result
== EFI_INVALID_PARAMETER
) {
1798 return EFI_INVALID_PARAMETER
;
1801 switch (OpCode
->Operand
) {
1802 case EFI_IFR_EQUAL_OP
:
1803 Value
->Value
.b
= (BOOLEAN
) ((Result
== 0) ? TRUE
: FALSE
);
1806 case EFI_IFR_NOT_EQUAL_OP
:
1807 Value
->Value
.b
= (BOOLEAN
) ((Result
== 0) ? TRUE
: FALSE
);
1810 case EFI_IFR_GREATER_EQUAL_OP
:
1811 Value
->Value
.b
= (BOOLEAN
) ((Result
>= 0) ? TRUE
: FALSE
);
1814 case EFI_IFR_GREATER_THAN_OP
:
1815 Value
->Value
.b
= (BOOLEAN
) ((Result
> 0) ? TRUE
: FALSE
);
1818 case EFI_IFR_LESS_EQUAL_OP
:
1819 Value
->Value
.b
= (BOOLEAN
) ((Result
<= 0) ? TRUE
: FALSE
);
1822 case EFI_IFR_LESS_THAN_OP
:
1823 Value
->Value
.b
= (BOOLEAN
) ((Result
< 0) ? TRUE
: FALSE
);
1831 case EFI_IFR_MATCH_OP
:
1832 Status
= IfrMatch (FormSet
, Value
);
1835 case EFI_IFR_CATENATE_OP
:
1836 Status
= IfrCatenate (FormSet
, Value
);
1842 case EFI_IFR_CONDITIONAL_OP
:
1844 // Pop third expression from the expression stack
1846 Status
= PopExpression (&Data3
);
1847 if (EFI_ERROR (Status
)) {
1852 // Pop second expression from the expression stack
1854 Status
= PopExpression (&Data2
);
1855 if (EFI_ERROR (Status
)) {
1860 // Pop first expression from the expression stack
1862 Status
= PopExpression (&Data1
);
1863 if (EFI_ERROR (Status
)) {
1866 if (Data1
.Type
!= EFI_IFR_TYPE_BOOLEAN
) {
1867 return EFI_INVALID_PARAMETER
;
1870 if (Data1
.Value
.b
) {
1877 case EFI_IFR_FIND_OP
:
1878 Status
= IfrFind (FormSet
, OpCode
->Format
, Value
);
1881 case EFI_IFR_MID_OP
:
1882 Status
= IfrMid (FormSet
, Value
);
1885 case EFI_IFR_TOKEN_OP
:
1886 Status
= IfrToken (FormSet
, Value
);
1889 case EFI_IFR_SPAN_OP
:
1890 Status
= IfrSpan (FormSet
, OpCode
->Flags
, Value
);
1896 if (EFI_ERROR (Status
)) {
1900 Status
= PushExpression (Value
);
1901 if (EFI_ERROR (Status
)) {
1907 // Pop the final result from expression stack
1910 Status
= PopExpression (Value
);
1911 if (EFI_ERROR (Status
)) {
1916 // After evaluating an expression, there should be only one value left on the expression stack
1918 if (PopExpression (Value
) != EFI_ACCESS_DENIED
) {
1919 return EFI_INVALID_PARAMETER
;
1922 CopyMem (&Expression
->Result
, Value
, sizeof (EFI_HII_VALUE
));