3 Copyright (c) 2007, Intel Corporation
4 All rights reserved. This program and the accompanying materials
5 are licensed and made available under the terms and conditions of the BSD License
6 which accompanies this distribution. The full text of the license may be found at
7 http://opensource.org/licenses/bsd-license.php
9 THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
10 WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
18 Expression evaluation.
27 // Global stack used to evaluate boolean expresions
29 EFI_HII_VALUE
*mOpCodeScopeStack
= NULL
;
30 EFI_HII_VALUE
*mOpCodeScopeStackEnd
= NULL
;
31 EFI_HII_VALUE
*mOpCodeScopeStackPointer
= NULL
;
33 EFI_HII_VALUE
*mExpressionEvaluationStack
= NULL
;
34 EFI_HII_VALUE
*mExpressionEvaluationStackEnd
= NULL
;
35 EFI_HII_VALUE
*mExpressionEvaluationStackPointer
= NULL
;
38 // Unicode collation protocol interface
40 EFI_UNICODE_COLLATION_PROTOCOL
*mUnicodeCollation
= NULL
;
44 Grow size of the stack
46 @param Stack On input: old stack; On output: new stack
47 @param StackPtr On input: old stack pointer; On output: new stack
49 @param StackPtr On input: old stack end; On output: new stack end
51 @retval EFI_SUCCESS Grow stack success.
52 @retval EFI_OUT_OF_RESOURCES No enough memory for stack space.
58 IN OUT EFI_HII_VALUE
**Stack
,
59 IN OUT EFI_HII_VALUE
**StackPtr
,
60 IN OUT EFI_HII_VALUE
**StackEnd
64 EFI_HII_VALUE
*NewStack
;
66 Size
= EXPRESSION_STACK_SIZE_INCREMENT
;
67 if (*StackPtr
!= NULL
) {
68 Size
= Size
+ (*StackEnd
- *Stack
);
71 NewStack
= AllocatePool (Size
* sizeof (EFI_HII_VALUE
));
72 if (NewStack
== NULL
) {
73 return EFI_OUT_OF_RESOURCES
;
76 if (*StackPtr
!= NULL
) {
78 // Copy from Old Stack to the New Stack
83 (*StackEnd
- *Stack
) * sizeof (EFI_HII_VALUE
)
89 gBS
->FreePool (*Stack
);
93 // Make the Stack pointer point to the old data in the new stack
95 *StackPtr
= NewStack
+ (*StackPtr
- *Stack
);
97 *StackEnd
= NewStack
+ Size
;
104 Push an element onto the Boolean Stack
106 @param Stack On input: old stack; On output: new stack
107 @param StackPtr On input: old stack pointer; On output: new stack
109 @param StackPtr On input: old stack end; On output: new stack end
110 @param Data Data to push.
112 @retval EFI_SUCCESS Push stack success.
117 IN OUT EFI_HII_VALUE
**Stack
,
118 IN OUT EFI_HII_VALUE
**StackPtr
,
119 IN OUT EFI_HII_VALUE
**StackEnd
,
120 IN EFI_HII_VALUE
*Data
126 // Check for a stack overflow condition
128 if (*StackPtr
>= *StackEnd
) {
132 Status
= GrowStack (Stack
, StackPtr
, StackEnd
);
133 if (EFI_ERROR (Status
)) {
139 // Push the item onto the stack
141 CopyMem (*StackPtr
, Data
, sizeof (EFI_HII_VALUE
));
142 *StackPtr
= *StackPtr
+ 1;
149 Pop an element from the stack.
151 @param Stack On input: old stack; On output: new stack
152 @param StackPtr On input: old stack pointer; On output: new stack
154 @param StackPtr On input: old stack end; On output: new stack end
155 @param Data Data to pop.
157 @retval EFI_SUCCESS The value was popped onto the stack.
158 @retval EFI_ACCESS_DENIED The pop operation underflowed the stack
163 IN OUT EFI_HII_VALUE
**Stack
,
164 IN OUT EFI_HII_VALUE
**StackPtr
,
165 IN OUT EFI_HII_VALUE
**StackEnd
,
166 OUT EFI_HII_VALUE
*Data
170 // Check for a stack underflow condition
172 if (*StackPtr
== *Stack
) {
173 return EFI_ACCESS_DENIED
;
177 // Pop the item off the stack
179 *StackPtr
= *StackPtr
- 1;
180 CopyMem (Data
, *StackPtr
, sizeof (EFI_HII_VALUE
));
186 Reset stack pointer to begin of the stack.
198 mOpCodeScopeStackPointer
= mOpCodeScopeStack
;
203 Push an Operand onto the Stack
205 @param Operand Operand to push.
207 @retval EFI_SUCCESS The value was pushed onto the stack.
208 @retval EFI_OUT_OF_RESOURCES There is not enough system memory to grow the
219 Data
.Type
= EFI_IFR_TYPE_NUM_SIZE_8
;
220 Data
.Value
.u8
= Operand
;
224 &mOpCodeScopeStackPointer
,
225 &mOpCodeScopeStackEnd
,
232 Pop an Operand from the Stack
234 @param Operand Operand to pop.
236 @retval EFI_SUCCESS The value was pushed onto the stack.
237 @retval EFI_OUT_OF_RESOURCES There is not enough system memory to grow the
251 &mOpCodeScopeStackPointer
,
252 &mOpCodeScopeStackEnd
,
256 *Operand
= Data
.Value
.u8
;
263 Reset stack pointer to begin of the stack.
271 ResetExpressionStack (
275 mExpressionEvaluationStackPointer
= mExpressionEvaluationStack
;
280 Push an Expression value onto the Stack
282 @param Value Expression value to push.
284 @retval EFI_SUCCESS The value was pushed onto the stack.
285 @retval EFI_OUT_OF_RESOURCES There is not enough system memory to grow the
291 IN EFI_HII_VALUE
*Value
295 &mExpressionEvaluationStack
,
296 &mExpressionEvaluationStackPointer
,
297 &mExpressionEvaluationStackEnd
,
304 Pop an Expression value from the stack.
306 @param Value Expression value to pop.
308 @retval EFI_SUCCESS The value was popped onto the stack.
309 @retval EFI_ACCESS_DENIED The pop operation underflowed the stack
314 OUT EFI_HII_VALUE
*Value
318 &mExpressionEvaluationStack
,
319 &mExpressionEvaluationStackPointer
,
320 &mExpressionEvaluationStackEnd
,
327 Get Form given its FormId.
329 @param FormSet The formset which contains this form.
330 @param FormId Id of this form.
332 @retval Pointer The form.
333 @retval NULL Specified Form is not found in the formset.
338 IN FORM_BROWSER_FORMSET
*FormSet
,
343 FORM_BROWSER_FORM
*Form
;
345 Link
= GetFirstNode (&FormSet
->FormListHead
);
346 while (!IsNull (&FormSet
->FormListHead
, Link
)) {
347 Form
= FORM_BROWSER_FORM_FROM_LINK (Link
);
349 if (Form
->FormId
== FormId
) {
353 Link
= GetNextNode (&FormSet
->FormListHead
, Link
);
361 Search a Question in Form scope using its QuestionId.
363 @param Form The form which contains this Question.
364 @param QuestionId Id of this Question.
366 @retval Pointer The Question.
367 @retval NULL Specified Question not found in the form.
370 FORM_BROWSER_STATEMENT
*
372 IN FORM_BROWSER_FORM
*Form
,
377 FORM_BROWSER_STATEMENT
*Question
;
379 if (QuestionId
== 0) {
381 // The value of zero is reserved
386 Link
= GetFirstNode (&Form
->StatementListHead
);
387 while (!IsNull (&Form
->StatementListHead
, Link
)) {
388 Question
= FORM_BROWSER_STATEMENT_FROM_LINK (Link
);
390 if (Question
->QuestionId
== QuestionId
) {
394 Link
= GetNextNode (&Form
->StatementListHead
, Link
);
402 Search a Question in Formset scope using its QuestionId.
404 @param FormSet The formset which contains this form.
405 @param Form The form which contains this Question.
406 @param QuestionId Id of this Question.
408 @retval Pointer The Question.
409 @retval NULL Specified Question not found in the form.
412 FORM_BROWSER_STATEMENT
*
414 IN FORM_BROWSER_FORMSET
*FormSet
,
415 IN FORM_BROWSER_FORM
*Form
,
420 FORM_BROWSER_STATEMENT
*Question
;
423 // Search in the form scope first
425 Question
= IdToQuestion2 (Form
, QuestionId
);
426 if (Question
!= NULL
) {
431 // Search in the formset scope
433 Link
= GetFirstNode (&FormSet
->FormListHead
);
434 while (!IsNull (&FormSet
->FormListHead
, Link
)) {
435 Form
= FORM_BROWSER_FORM_FROM_LINK (Link
);
437 Question
= IdToQuestion2 (Form
, QuestionId
);
438 if (Question
!= NULL
) {
442 Link
= GetNextNode (&FormSet
->FormListHead
, Link
);
450 Get Expression given its RuleId.
452 @param Form The form which contains this Expression.
453 @param RuleId Id of this Expression.
455 @retval Pointer The Expression.
456 @retval NULL Specified Expression not found in the form.
461 IN FORM_BROWSER_FORM
*Form
,
466 FORM_EXPRESSION
*Expression
;
468 Link
= GetFirstNode (&Form
->ExpressionListHead
);
469 while (!IsNull (&Form
->ExpressionListHead
, Link
)) {
470 Expression
= FORM_EXPRESSION_FROM_LINK (Link
);
472 if (Expression
->Type
== EFI_HII_EXPRESSION_RULE
&& Expression
->RuleId
== RuleId
) {
476 Link
= GetNextNode (&Form
->ExpressionListHead
, Link
);
484 Locate the Unicode Collation Protocol interface for later use.
488 @retval EFI_SUCCESS Protocol interface initialize success.
489 @retval Other Protocol interface initialize failed.
493 InitializeUnicodeCollationProtocol (
499 if (mUnicodeCollation
!= NULL
) {
504 // BUGBUG: Proper impelmentation is to locate all Unicode Collation Protocol
505 // instances first and then select one which support English language.
506 // Current implementation just pick the first instance.
508 Status
= gBS
->LocateProtocol (
509 &gEfiUnicodeCollation2ProtocolGuid
,
511 (VOID
**) &mUnicodeCollation
521 while (*String
!= 0) {
522 if ((*String
>= 'a') && (*String
<= 'z')) {
523 *String
= (UINT16
) ((*String
) & ((UINT16
) ~0x20));
531 Evaluate opcode EFI_IFR_TO_STRING.
533 @param FormSet Formset which contains this opcode.
534 @param Format String format in EFI_IFR_TO_STRING.
535 @param Result Evaluation result for this opcode.
537 @retval EFI_SUCCESS Opcode evaluation success.
538 @retval Other Opcode evaluation failed.
543 IN FORM_BROWSER_FORMSET
*FormSet
,
545 OUT EFI_HII_VALUE
*Result
552 CHAR16 Buffer
[MAXIMUM_VALUE_CHARACTERS
];
555 Status
= PopExpression (&Value
);
556 if (EFI_ERROR (Status
)) {
560 switch (Value
.Type
) {
561 case EFI_IFR_TYPE_NUM_SIZE_8
:
562 case EFI_IFR_TYPE_NUM_SIZE_16
:
563 case EFI_IFR_TYPE_NUM_SIZE_32
:
564 case EFI_IFR_TYPE_NUM_SIZE_64
:
565 BufferSize
= MAXIMUM_VALUE_CHARACTERS
* sizeof (CHAR16
);
567 case EFI_IFR_STRING_UNSIGNED_DEC
:
568 case EFI_IFR_STRING_SIGNED_DEC
:
569 PrintFormat
= L
"%ld";
572 case EFI_IFR_STRING_LOWERCASE_HEX
:
573 PrintFormat
= L
"%lx";
576 case EFI_IFR_STRING_UPPERCASE_HEX
:
577 PrintFormat
= L
"%lX";
581 return EFI_UNSUPPORTED
;
583 UnicodeSPrint (Buffer
, BufferSize
, PrintFormat
, Value
.Value
.u64
);
587 case EFI_IFR_TYPE_STRING
:
588 CopyMem (Result
, &Value
, sizeof (EFI_HII_VALUE
));
591 case EFI_IFR_TYPE_BOOLEAN
:
592 String
= (Value
.Value
.b
) ? L
"True" : L
"False";
596 return EFI_UNSUPPORTED
;
599 Result
->Type
= EFI_IFR_TYPE_STRING
;
600 Result
->Value
.string
= NewString (String
, FormSet
->HiiHandle
);
606 Evaluate opcode EFI_IFR_TO_UINT.
608 @param FormSet Formset which contains this opcode.
609 @param Result Evaluation result for this opcode.
611 @retval EFI_SUCCESS Opcode evaluation success.
612 @retval Other Opcode evaluation failed.
617 IN FORM_BROWSER_FORMSET
*FormSet
,
618 OUT EFI_HII_VALUE
*Result
627 Status
= PopExpression (&Value
);
628 if (EFI_ERROR (Status
)) {
632 if (Value
.Type
>= EFI_IFR_TYPE_OTHER
) {
633 return EFI_UNSUPPORTED
;
636 Status
= EFI_SUCCESS
;
637 if (Value
.Type
== EFI_IFR_TYPE_STRING
) {
638 String
= GetToken (Value
.Value
.string
, FormSet
->HiiHandle
);
639 if (String
== NULL
) {
640 return EFI_NOT_FOUND
;
643 IfrStrToUpper (String
);
644 StringPtr
= StrStr (String
, L
"0X");
645 if (StringPtr
!= NULL
) {
649 BufferSize
= sizeof (UINT64
);
650 Status
= R8_HexStringToBuf ((UINT8
*) &Result
->Value
.u64
, &BufferSize
, StringPtr
+ 2, NULL
);
653 // BUGBUG: Need handle decimal string
656 gBS
->FreePool (String
);
658 CopyMem (Result
, &Value
, sizeof (EFI_HII_VALUE
));
661 Result
->Type
= EFI_IFR_TYPE_NUM_SIZE_64
;
667 Evaluate opcode EFI_IFR_CATENATE.
669 @param FormSet Formset which contains this opcode.
670 @param Result Evaluation result for this opcode.
672 @retval EFI_SUCCESS Opcode evaluation success.
673 @retval Other Opcode evaluation failed.
678 IN FORM_BROWSER_FORMSET
*FormSet
,
679 OUT EFI_HII_VALUE
*Result
690 // String[0] - The second string
691 // String[1] - The first string
696 Status
= EFI_SUCCESS
;
698 for (Index
= 0; Index
< 2; Index
++) {
699 Status
= PopExpression (&Value
);
700 if (EFI_ERROR (Status
)) {
704 if (Value
.Type
!= EFI_IFR_TYPE_STRING
) {
705 Status
= EFI_UNSUPPORTED
;
709 String
[Index
] = GetToken (Value
.Value
.string
, FormSet
->HiiHandle
);
711 Status
= EFI_NOT_FOUND
;
716 Size
= StrSize (String
[0]);
717 StringPtr
= AllocatePool (StrSize (String
[1]) + Size
);
718 ASSERT (StringPtr
!= NULL
);
719 StrCpy (StringPtr
, String
[1]);
720 StrCat (StringPtr
, String
[0]);
722 Result
->Type
= EFI_IFR_TYPE_STRING
;
723 Result
->Value
.string
= NewString (StringPtr
, FormSet
->HiiHandle
);
726 SafeFreePool (String
[0]);
727 SafeFreePool (String
[1]);
728 SafeFreePool (StringPtr
);
735 Evaluate opcode EFI_IFR_MATCH.
737 @param FormSet Formset which contains this opcode.
738 @param Result Evaluation result for this opcode.
740 @retval EFI_SUCCESS Opcode evaluation success.
741 @retval Other Opcode evaluation failed.
746 IN FORM_BROWSER_FORMSET
*FormSet
,
747 OUT EFI_HII_VALUE
*Result
756 // String[0] - The string to search
757 // String[1] - pattern
761 Status
= EFI_SUCCESS
;
762 for (Index
= 0; Index
< 2; Index
++) {
763 Status
= PopExpression (&Value
);
764 if (EFI_ERROR (Status
)) {
768 if (Value
.Type
!= EFI_IFR_TYPE_STRING
) {
769 Status
= EFI_UNSUPPORTED
;
773 String
[Index
] = GetToken (Value
.Value
.string
, FormSet
->HiiHandle
);
775 Status
= EFI_NOT_FOUND
;
780 Result
->Type
= EFI_IFR_TYPE_BOOLEAN
;
781 Result
->Value
.b
= mUnicodeCollation
->MetaiMatch (mUnicodeCollation
, String
[0], String
[1]);
784 SafeFreePool (String
[0]);
785 SafeFreePool (String
[1]);
792 Evaluate opcode EFI_IFR_FIND.
794 @param FormSet Formset which contains this opcode.
795 @param Format Case sensitive or insensitive.
796 @param Result Evaluation result for this opcode.
798 @retval EFI_SUCCESS Opcode evaluation success.
799 @retval Other Opcode evaluation failed.
804 IN FORM_BROWSER_FORMSET
*FormSet
,
806 OUT EFI_HII_VALUE
*Result
816 if (Format
> EFI_IFR_FF_CASE_INSENSITIVE
) {
817 return EFI_UNSUPPORTED
;
820 Status
= PopExpression (&Value
);
821 if (EFI_ERROR (Status
)) {
824 if (Value
.Type
> EFI_IFR_TYPE_NUM_SIZE_64
) {
825 return EFI_UNSUPPORTED
;
827 Base
= (UINTN
) Value
.Value
.u64
;
830 // String[0] - sub-string
831 // String[1] - The string to search
835 for (Index
= 0; Index
< 2; Index
++) {
836 Status
= PopExpression (&Value
);
837 if (EFI_ERROR (Status
)) {
841 if (Value
.Type
!= EFI_IFR_TYPE_STRING
) {
842 Status
= EFI_UNSUPPORTED
;
846 String
[Index
] = GetToken (Value
.Value
.string
, FormSet
->HiiHandle
);
848 Status
= EFI_NOT_FOUND
;
852 if (Format
== EFI_IFR_FF_CASE_INSENSITIVE
) {
854 // Case insensitive, convert both string to upper case
856 IfrStrToUpper (String
[Index
]);
860 Result
->Type
= EFI_IFR_TYPE_NUM_SIZE_64
;
861 if (Base
>= StrLen (String
[1])) {
862 Result
->Value
.u64
= 0xFFFFFFFFFFFFFFFF;
864 StringPtr
= StrStr (String
[1] + Base
, String
[0]);
865 Result
->Value
.u64
= (StringPtr
== NULL
) ? 0xFFFFFFFFFFFFFFFF : (StringPtr
- String
[1]);
869 SafeFreePool (String
[0]);
870 SafeFreePool (String
[1]);
877 Evaluate opcode EFI_IFR_MID.
879 @param FormSet Formset which contains this opcode.
880 @param Result Evaluation result for this opcode.
882 @retval EFI_SUCCESS Opcode evaluation success.
883 @retval Other Opcode evaluation failed.
888 IN FORM_BROWSER_FORMSET
*FormSet
,
889 OUT EFI_HII_VALUE
*Result
899 Status
= PopExpression (&Value
);
900 if (EFI_ERROR (Status
)) {
903 if (Value
.Type
> EFI_IFR_TYPE_NUM_SIZE_64
) {
904 return EFI_UNSUPPORTED
;
906 Length
= (UINTN
) Value
.Value
.u64
;
908 Status
= PopExpression (&Value
);
909 if (EFI_ERROR (Status
)) {
912 if (Value
.Type
> EFI_IFR_TYPE_NUM_SIZE_64
) {
913 return EFI_UNSUPPORTED
;
915 Base
= (UINTN
) Value
.Value
.u64
;
917 Status
= PopExpression (&Value
);
918 if (EFI_ERROR (Status
)) {
921 if (Value
.Type
!= EFI_IFR_TYPE_STRING
) {
922 return EFI_UNSUPPORTED
;
924 String
= GetToken (Value
.Value
.string
, FormSet
->HiiHandle
);
925 if (String
== NULL
) {
926 return EFI_NOT_FOUND
;
929 if (Length
== 0 || Base
>= StrLen (String
)) {
930 SubString
= gEmptyString
;
932 SubString
= String
+ Base
;
933 if ((Base
+ Length
) < StrLen (String
)) {
934 SubString
[Length
] = L
'\0';
938 Result
->Type
= EFI_IFR_TYPE_STRING
;
939 Result
->Value
.string
= NewString (SubString
, FormSet
->HiiHandle
);
941 gBS
->FreePool (String
);
948 Evaluate opcode EFI_IFR_TOKEN.
950 @param FormSet Formset which contains this opcode.
951 @param Result Evaluation result for this opcode.
953 @retval EFI_SUCCESS Opcode evaluation success.
954 @retval Other Opcode evaluation failed.
959 IN FORM_BROWSER_FORMSET
*FormSet
,
960 OUT EFI_HII_VALUE
*Result
972 Status
= PopExpression (&Value
);
973 if (EFI_ERROR (Status
)) {
976 if (Value
.Type
> EFI_IFR_TYPE_NUM_SIZE_64
) {
977 return EFI_UNSUPPORTED
;
979 Count
= (UINTN
) Value
.Value
.u64
;
982 // String[0] - Delimiter
983 // String[1] - The string to search
987 for (Index
= 0; Index
< 2; Index
++) {
988 Status
= PopExpression (&Value
);
989 if (EFI_ERROR (Status
)) {
993 if (Value
.Type
!= EFI_IFR_TYPE_STRING
) {
994 Status
= EFI_UNSUPPORTED
;
998 String
[Index
] = GetToken (Value
.Value
.string
, FormSet
->HiiHandle
);
1000 Status
= EFI_NOT_FOUND
;
1005 Delimiter
= String
[0];
1006 SubString
= String
[1];
1008 SubString
= StrStr (SubString
, Delimiter
);
1009 if (SubString
!= NULL
) {
1011 // Skip over the delimiter
1013 SubString
= SubString
+ StrLen (Delimiter
);
1020 if (SubString
== NULL
) {
1022 // nth delimited sub-string not found, push an empty string
1024 SubString
= gEmptyString
;
1027 // Put a NULL terminator for nth delimited sub-string
1029 StringPtr
= StrStr (SubString
, Delimiter
);
1030 if (StringPtr
!= NULL
) {
1035 Result
->Type
= EFI_IFR_TYPE_STRING
;
1036 Result
->Value
.string
= NewString (SubString
, FormSet
->HiiHandle
);
1039 SafeFreePool (String
[0]);
1040 SafeFreePool (String
[1]);
1047 Evaluate opcode EFI_IFR_SPAN.
1049 @param FormSet Formset which contains this opcode.
1050 @param Flags FIRST_MATCHING or FIRST_NON_MATCHING.
1051 @param Result Evaluation result for this opcode.
1053 @retval EFI_SUCCESS Opcode evaluation success.
1054 @retval Other Opcode evaluation failed.
1059 IN FORM_BROWSER_FORMSET
*FormSet
,
1061 OUT EFI_HII_VALUE
*Result
1065 EFI_HII_VALUE Value
;
1073 Status
= PopExpression (&Value
);
1074 if (EFI_ERROR (Status
)) {
1077 if (Value
.Type
> EFI_IFR_TYPE_NUM_SIZE_64
) {
1078 return EFI_UNSUPPORTED
;
1080 Base
= (UINTN
) Value
.Value
.u64
;
1083 // String[0] - Charset
1084 // String[1] - The string to search
1088 for (Index
= 0; Index
< 2; Index
++) {
1089 Status
= PopExpression (&Value
);
1090 if (EFI_ERROR (Status
)) {
1094 if (Value
.Type
!= EFI_IFR_TYPE_STRING
) {
1095 Status
= EFI_UNSUPPORTED
;
1099 String
[Index
] = GetToken (Value
.Value
.string
, FormSet
->HiiHandle
);
1100 if (String
== NULL
) {
1101 Status
= EFI_NOT_FOUND
;
1106 if (Base
>= StrLen (String
[1])) {
1107 Status
= EFI_UNSUPPORTED
;
1112 StringPtr
= String
[1] + Base
;
1113 Charset
= String
[0];
1114 while (*StringPtr
!= 0 && !Found
) {
1116 while (Charset
[Index
] != 0) {
1117 if (*StringPtr
>= Charset
[Index
] && *StringPtr
<= Charset
[Index
+ 1]) {
1118 if (Flags
== EFI_IFR_FLAGS_FIRST_MATCHING
) {
1123 if (Flags
== EFI_IFR_FLAGS_FIRST_NON_MATCHING
) {
1129 // Skip characters pair representing low-end of a range and high-end of a range
1139 Result
->Type
= EFI_IFR_TYPE_NUM_SIZE_64
;
1140 Result
->Value
.u64
= StringPtr
- String
[1];
1143 SafeFreePool (String
[0]);
1144 SafeFreePool (String
[1]);
1151 Zero extend integer/boolean/date/time to UINT64 for comparing.
1153 @param Value HII Value to be converted.
1160 IN EFI_HII_VALUE
*Value
1166 switch (Value
->Type
) {
1167 case EFI_IFR_TYPE_NUM_SIZE_8
:
1168 Temp
= Value
->Value
.u8
;
1171 case EFI_IFR_TYPE_NUM_SIZE_16
:
1172 Temp
= Value
->Value
.u16
;
1175 case EFI_IFR_TYPE_NUM_SIZE_32
:
1176 Temp
= Value
->Value
.u32
;
1179 case EFI_IFR_TYPE_BOOLEAN
:
1180 Temp
= Value
->Value
.b
;
1183 case EFI_IFR_TYPE_TIME
:
1184 Temp
= Value
->Value
.u32
& 0xffffff;
1187 case EFI_IFR_TYPE_DATE
:
1188 Temp
= Value
->Value
.u32
;
1195 Value
->Value
.u64
= Temp
;
1200 Compare two Hii value.
1202 @param Value1 Expression value to compare on left-hand
1203 @param Value2 Expression value to compare on right-hand
1204 @param HiiHandle Only required for string compare
1206 @retval EFI_INVALID_PARAMETER Could not perform comparation on two values
1207 @retval 0 Two operators equeal
1208 @retval 0 Value1 is greater than Value2
1209 @retval 0 Value1 is less than Value2
1214 IN EFI_HII_VALUE
*Value1
,
1215 IN EFI_HII_VALUE
*Value2
,
1216 IN EFI_HII_HANDLE HiiHandle OPTIONAL
1224 if (Value1
->Type
>= EFI_IFR_TYPE_OTHER
|| Value2
->Type
>= EFI_IFR_TYPE_OTHER
) {
1225 return EFI_INVALID_PARAMETER
;
1228 if (Value1
->Type
== EFI_IFR_TYPE_STRING
|| Value2
->Type
== EFI_IFR_TYPE_STRING
) {
1229 if (Value1
->Type
!= Value2
->Type
) {
1231 // Both Operator should be type of String
1233 return EFI_INVALID_PARAMETER
;
1236 if (Value1
->Value
.string
== 0 || Value2
->Value
.string
== 0) {
1238 // StringId 0 is reserved
1240 return EFI_INVALID_PARAMETER
;
1243 if (Value1
->Value
.string
== Value2
->Value
.string
) {
1247 Str1
= GetToken (Value1
->Value
.string
, HiiHandle
);
1252 return EFI_INVALID_PARAMETER
;
1255 Str2
= GetToken (Value2
->Value
.string
, HiiHandle
);
1257 gBS
->FreePool (Str1
);
1258 return EFI_INVALID_PARAMETER
;
1261 Result
= StrCmp (Str1
, Str2
);
1263 gBS
->FreePool (Str1
);
1264 gBS
->FreePool (Str2
);
1270 // Take remain types(integer, boolean, date/time) as integer
1272 Temp64
= (INT64
) (Value1
->Value
.u64
- Value2
->Value
.u64
);
1275 } else if (Temp64
< 0) {
1286 Evaluate the result of a HII expression
1288 @param FormSet FormSet associated with this expression.
1289 @param Form Form associated with this expression.
1290 @param Expression Expression to be evaluated.
1292 @retval EFI_SUCCESS The expression evaluated successfuly
1293 @retval EFI_NOT_FOUND The Question which referenced by a QuestionId
1295 @retval EFI_OUT_OF_RESOURCES There is not enough system memory to grow the
1297 @retval EFI_ACCESS_DENIED The pop operation underflowed the stack
1298 @retval EFI_INVALID_PARAMETER Syntax error with the Expression
1302 EvaluateExpression (
1303 IN FORM_BROWSER_FORMSET
*FormSet
,
1304 IN FORM_BROWSER_FORM
*Form
,
1305 IN OUT FORM_EXPRESSION
*Expression
1310 EXPRESSION_OPCODE
*OpCode
;
1311 FORM_BROWSER_STATEMENT
*Question
;
1312 FORM_BROWSER_STATEMENT
*Question2
;
1314 EFI_HII_VALUE Data1
;
1315 EFI_HII_VALUE Data2
;
1316 EFI_HII_VALUE Data3
;
1317 FORM_EXPRESSION
*RuleExpression
;
1318 EFI_HII_VALUE
*Value
;
1324 // Always reset the stack before evaluating an Expression
1326 ResetExpressionStack ();
1328 Expression
->Result
.Type
= EFI_IFR_TYPE_OTHER
;
1330 Link
= GetFirstNode (&Expression
->OpCodeListHead
);
1331 while (!IsNull (&Expression
->OpCodeListHead
, Link
)) {
1332 OpCode
= EXPRESSION_OPCODE_FROM_LINK (Link
);
1334 Link
= GetNextNode (&Expression
->OpCodeListHead
, Link
);
1336 ZeroMem (&Data1
, sizeof (EFI_HII_VALUE
));
1337 ZeroMem (&Data2
, sizeof (EFI_HII_VALUE
));
1338 ZeroMem (&Data3
, sizeof (EFI_HII_VALUE
));
1341 Value
->Type
= EFI_IFR_TYPE_BOOLEAN
;
1342 Status
= EFI_SUCCESS
;
1344 switch (OpCode
->Operand
) {
1346 // Built-in functions
1348 case EFI_IFR_EQ_ID_VAL_OP
:
1349 Question
= IdToQuestion (FormSet
, Form
, OpCode
->QuestionId
);
1350 if (Question
== NULL
) {
1351 return EFI_NOT_FOUND
;
1354 Result
= CompareHiiValue (&Question
->HiiValue
, &OpCode
->Value
, NULL
);
1355 if (Result
== EFI_INVALID_PARAMETER
) {
1356 return EFI_INVALID_PARAMETER
;
1358 Value
->Value
.b
= (BOOLEAN
) ((Result
== 0) ? TRUE
: FALSE
);
1361 case EFI_IFR_EQ_ID_ID_OP
:
1362 Question
= IdToQuestion (FormSet
, Form
, OpCode
->QuestionId
);
1363 if (Question
== NULL
) {
1364 return EFI_NOT_FOUND
;
1367 Question2
= IdToQuestion (FormSet
, Form
, OpCode
->QuestionId2
);
1368 if (Question2
== NULL
) {
1369 return EFI_NOT_FOUND
;
1372 Result
= CompareHiiValue (&Question
->HiiValue
, &Question2
->HiiValue
, FormSet
->HiiHandle
);
1373 if (Result
== EFI_INVALID_PARAMETER
) {
1374 return EFI_INVALID_PARAMETER
;
1376 Value
->Value
.b
= (BOOLEAN
) ((Result
== 0) ? TRUE
: FALSE
);
1379 case EFI_IFR_EQ_ID_LIST_OP
:
1380 Question
= IdToQuestion (FormSet
, Form
, OpCode
->QuestionId
);
1381 if (Question
== NULL
) {
1382 return EFI_NOT_FOUND
;
1385 Value
->Value
.b
= FALSE
;
1386 for (Index
=0; Index
< OpCode
->ListLength
; Index
++) {
1387 if (Question
->HiiValue
.Value
.u16
== OpCode
->ValueList
[Index
]) {
1388 Value
->Value
.b
= TRUE
;
1394 case EFI_IFR_DUP_OP
:
1395 Status
= PopExpression (Value
);
1396 if (EFI_ERROR (Status
)) {
1400 Status
= PushExpression (Value
);
1403 case EFI_IFR_QUESTION_REF1_OP
:
1404 case EFI_IFR_THIS_OP
:
1405 Question
= IdToQuestion (FormSet
, Form
, OpCode
->QuestionId
);
1406 if (Question
== NULL
) {
1407 return EFI_NOT_FOUND
;
1410 Value
= &Question
->HiiValue
;
1413 case EFI_IFR_QUESTION_REF3_OP
:
1414 if (OpCode
->DevicePath
== 0) {
1416 // EFI_IFR_QUESTION_REF3
1417 // Pop an expression from the expression stack
1419 Status
= PopExpression (Value
);
1420 if (EFI_ERROR (Status
)) {
1425 // Validate the expression value
1427 if ((Value
->Type
> EFI_IFR_TYPE_NUM_SIZE_64
) || (Value
->Value
.u64
> 0xffff)) {
1428 return EFI_NOT_FOUND
;
1431 Question
= IdToQuestion (FormSet
, Form
, Value
->Value
.u16
);
1432 if (Question
== NULL
) {
1433 return EFI_NOT_FOUND
;
1437 // push the questions' value on to the expression stack
1439 Value
= &Question
->HiiValue
;
1442 // BUGBUG: push 0 for EFI_IFR_QUESTION_REF3_2 and EFI_IFR_QUESTION_REF3_3,
1443 // since it is impractical to evaluate the value of a Question in another
1444 // Hii Package list.
1446 ZeroMem (Value
, sizeof (EFI_HII_VALUE
));
1450 case EFI_IFR_RULE_REF_OP
:
1452 // Find expression for this rule
1454 RuleExpression
= RuleIdToExpression (Form
, OpCode
->RuleId
);
1455 if (RuleExpression
== NULL
) {
1456 return EFI_NOT_FOUND
;
1460 // Evaluate this rule expression
1462 Status
= EvaluateExpression (FormSet
, Form
, RuleExpression
);
1463 if (EFI_ERROR (Status
)) {
1467 Value
= &RuleExpression
->Result
;
1470 case EFI_IFR_STRING_REF1_OP
:
1471 Value
->Type
= EFI_IFR_TYPE_STRING
;
1472 Value
->Value
.string
= OpCode
->Value
.Value
.string
;
1478 case EFI_IFR_TRUE_OP
:
1479 case EFI_IFR_FALSE_OP
:
1480 case EFI_IFR_ONE_OP
:
1481 case EFI_IFR_ONES_OP
:
1482 case EFI_IFR_UINT8_OP
:
1483 case EFI_IFR_UINT16_OP
:
1484 case EFI_IFR_UINT32_OP
:
1485 case EFI_IFR_UINT64_OP
:
1486 case EFI_IFR_UNDEFINED_OP
:
1487 case EFI_IFR_VERSION_OP
:
1488 case EFI_IFR_ZERO_OP
:
1489 Value
= &OpCode
->Value
;
1495 case EFI_IFR_LENGTH_OP
:
1496 Status
= PopExpression (Value
);
1497 if (EFI_ERROR (Status
)) {
1500 if (Value
->Type
!= EFI_IFR_TYPE_STRING
) {
1501 return EFI_INVALID_PARAMETER
;
1504 StrPtr
= GetToken (Value
->Value
.string
, FormSet
->HiiHandle
);
1505 if (StrPtr
== NULL
) {
1506 return EFI_INVALID_PARAMETER
;
1509 Value
->Type
= EFI_IFR_TYPE_NUM_SIZE_64
;
1510 Value
->Value
.u64
= StrLen (StrPtr
);
1511 gBS
->FreePool (StrPtr
);
1514 case EFI_IFR_NOT_OP
:
1515 Status
= PopExpression (Value
);
1516 if (EFI_ERROR (Status
)) {
1519 if (Value
->Type
!= EFI_IFR_TYPE_BOOLEAN
) {
1520 return EFI_INVALID_PARAMETER
;
1522 Value
->Value
.b
= (BOOLEAN
) (!Value
->Value
.b
);
1525 case EFI_IFR_QUESTION_REF2_OP
:
1527 // Pop an expression from the expression stack
1529 Status
= PopExpression (Value
);
1530 if (EFI_ERROR (Status
)) {
1535 // Validate the expression value
1537 if ((Value
->Type
> EFI_IFR_TYPE_NUM_SIZE_64
) || (Value
->Value
.u64
> 0xffff)) {
1538 return EFI_NOT_FOUND
;
1541 Question
= IdToQuestion (FormSet
, Form
, Value
->Value
.u16
);
1542 if (Question
== NULL
) {
1543 return EFI_NOT_FOUND
;
1546 Value
= &Question
->HiiValue
;
1549 case EFI_IFR_STRING_REF2_OP
:
1551 // Pop an expression from the expression stack
1553 Status
= PopExpression (Value
);
1554 if (EFI_ERROR (Status
)) {
1559 // Validate the expression value
1561 if ((Value
->Type
> EFI_IFR_TYPE_NUM_SIZE_64
) || (Value
->Value
.u64
> 0xffff)) {
1562 return EFI_NOT_FOUND
;
1565 Value
->Type
= EFI_IFR_TYPE_STRING
;
1566 StrPtr
= GetToken (Value
->Value
.u16
, FormSet
->HiiHandle
);
1567 if (StrPtr
== NULL
) {
1569 // If String not exit, push an empty string
1571 Value
->Value
.string
= NewString (gEmptyString
, FormSet
->HiiHandle
);
1573 Index
= (UINT16
) Value
->Value
.u64
;
1574 Value
->Value
.string
= Index
;
1575 gBS
->FreePool (StrPtr
);
1579 case EFI_IFR_TO_BOOLEAN_OP
:
1581 // Pop an expression from the expression stack
1583 Status
= PopExpression (Value
);
1584 if (EFI_ERROR (Status
)) {
1589 // Convert an expression to a Boolean
1591 if (Value
->Type
<= EFI_IFR_TYPE_DATE
) {
1593 // When converting from an unsigned integer, zero will be converted to
1594 // FALSE and any other value will be converted to TRUE.
1596 Value
->Value
.b
= (BOOLEAN
) ((Value
->Value
.u64
) ? TRUE
: FALSE
);
1598 Value
->Type
= EFI_IFR_TYPE_BOOLEAN
;
1599 } else if (Value
->Type
== EFI_IFR_TYPE_STRING
) {
1601 // When converting from a string, if case-insensitive compare
1602 // with "true" is True, then push True. If a case-insensitive compare
1603 // with "false" is True, then push False.
1605 StrPtr
= GetToken (Value
->Value
.string
, FormSet
->HiiHandle
);
1606 if (StrPtr
== NULL
) {
1607 return EFI_INVALID_PARAMETER
;
1610 if ((StrCmp (StrPtr
, L
"true") == 0) || (StrCmp (StrPtr
, L
"false") == 0)){
1611 Value
->Value
.b
= TRUE
;
1613 Value
->Value
.b
= FALSE
;
1615 gBS
->FreePool (StrPtr
);
1616 Value
->Type
= EFI_IFR_TYPE_BOOLEAN
;
1620 case EFI_IFR_TO_STRING_OP
:
1621 Status
= IfrToString (FormSet
, OpCode
->Format
, Value
);
1624 case EFI_IFR_TO_UINT_OP
:
1625 Status
= IfrToUint (FormSet
, Value
);
1628 case EFI_IFR_TO_LOWER_OP
:
1629 case EFI_IFR_TO_UPPER_OP
:
1630 Status
= InitializeUnicodeCollationProtocol ();
1631 if (EFI_ERROR (Status
)) {
1635 Status
= PopExpression (Value
);
1636 if (EFI_ERROR (Status
)) {
1640 if (Value
->Type
!= EFI_IFR_TYPE_STRING
) {
1641 return EFI_UNSUPPORTED
;
1644 StrPtr
= GetToken (Value
->Value
.string
, FormSet
->HiiHandle
);
1645 if (StrPtr
== NULL
) {
1646 return EFI_NOT_FOUND
;
1649 if (OpCode
->Operand
== EFI_IFR_TO_LOWER_OP
) {
1650 mUnicodeCollation
->StrLwr (mUnicodeCollation
, StrPtr
);
1652 mUnicodeCollation
->StrUpr (mUnicodeCollation
, StrPtr
);
1654 Value
->Value
.string
= NewString (StrPtr
, FormSet
->HiiHandle
);
1655 gBS
->FreePool (StrPtr
);
1658 case EFI_IFR_BITWISE_NOT_OP
:
1660 // Pop an expression from the expression stack
1662 Status
= PopExpression (Value
);
1663 if (EFI_ERROR (Status
)) {
1666 if (Value
->Type
> EFI_IFR_TYPE_DATE
) {
1667 return EFI_INVALID_PARAMETER
;
1670 Value
->Type
= EFI_IFR_TYPE_NUM_SIZE_64
;
1671 Value
->Value
.u64
= ~Value
->Value
.u64
;
1677 case EFI_IFR_ADD_OP
:
1678 case EFI_IFR_SUBTRACT_OP
:
1679 case EFI_IFR_MULTIPLY_OP
:
1680 case EFI_IFR_DIVIDE_OP
:
1681 case EFI_IFR_MODULO_OP
:
1682 case EFI_IFR_BITWISE_AND_OP
:
1683 case EFI_IFR_BITWISE_OR_OP
:
1684 case EFI_IFR_SHIFT_LEFT_OP
:
1685 case EFI_IFR_SHIFT_RIGHT_OP
:
1687 // Pop an expression from the expression stack
1689 Status
= PopExpression (&Data2
);
1690 if (EFI_ERROR (Status
)) {
1693 if (Data2
.Type
> EFI_IFR_TYPE_DATE
) {
1694 return EFI_INVALID_PARAMETER
;
1698 // Pop another expression from the expression stack
1700 Status
= PopExpression (&Data1
);
1701 if (EFI_ERROR (Status
)) {
1704 if (Data1
.Type
> EFI_IFR_TYPE_DATE
) {
1705 return EFI_INVALID_PARAMETER
;
1708 Value
->Type
= EFI_IFR_TYPE_NUM_SIZE_64
;
1710 switch (OpCode
->Operand
) {
1711 case EFI_IFR_ADD_OP
:
1712 Value
->Value
.u64
= Data1
.Value
.u64
+ Data2
.Value
.u64
;
1715 case EFI_IFR_SUBTRACT_OP
:
1716 Value
->Value
.u64
= Data1
.Value
.u64
- Data2
.Value
.u64
;
1719 case EFI_IFR_MULTIPLY_OP
:
1720 Value
->Value
.u64
= MultU64x32 (Data1
.Value
.u64
, (UINT32
) Data2
.Value
.u64
);
1723 case EFI_IFR_DIVIDE_OP
:
1724 Value
->Value
.u64
= DivU64x32 (Data1
.Value
.u64
, (UINT32
) Data2
.Value
.u64
);
1727 case EFI_IFR_MODULO_OP
:
1728 DivU64x32Remainder (Data1
.Value
.u64
, (UINT32
) Data2
.Value
.u64
, &TempValue
);
1729 Value
->Value
.u64
= TempValue
;
1732 case EFI_IFR_BITWISE_AND_OP
:
1733 Value
->Value
.u64
= Data1
.Value
.u64
& Data2
.Value
.u64
;
1736 case EFI_IFR_BITWISE_OR_OP
:
1737 Value
->Value
.u64
= Data1
.Value
.u64
| Data2
.Value
.u64
;
1740 case EFI_IFR_SHIFT_LEFT_OP
:
1741 Value
->Value
.u64
= LShiftU64 (Data1
.Value
.u64
, (UINTN
) Data2
.Value
.u64
);
1744 case EFI_IFR_SHIFT_RIGHT_OP
:
1745 Value
->Value
.u64
= RShiftU64 (Data1
.Value
.u64
, (UINTN
) Data2
.Value
.u64
);
1753 case EFI_IFR_AND_OP
:
1756 // Two Boolean operator
1758 Status
= PopExpression (&Data2
);
1759 if (EFI_ERROR (Status
)) {
1762 if (Data2
.Type
!= EFI_IFR_TYPE_BOOLEAN
) {
1763 return EFI_INVALID_PARAMETER
;
1767 // Pop another expression from the expression stack
1769 Status
= PopExpression (&Data1
);
1770 if (EFI_ERROR (Status
)) {
1773 if (Data1
.Type
!= EFI_IFR_TYPE_BOOLEAN
) {
1774 return EFI_INVALID_PARAMETER
;
1777 if (OpCode
->Operand
== EFI_IFR_AND_OP
) {
1778 Value
->Value
.b
= (BOOLEAN
) (Data1
.Value
.b
&& Data2
.Value
.b
);
1780 Value
->Value
.b
= (BOOLEAN
) (Data1
.Value
.b
|| Data2
.Value
.b
);
1784 case EFI_IFR_EQUAL_OP
:
1785 case EFI_IFR_NOT_EQUAL_OP
:
1786 case EFI_IFR_GREATER_EQUAL_OP
:
1787 case EFI_IFR_GREATER_THAN_OP
:
1788 case EFI_IFR_LESS_EQUAL_OP
:
1789 case EFI_IFR_LESS_THAN_OP
:
1791 // Compare two integer, string, boolean or date/time
1793 Status
= PopExpression (&Data2
);
1794 if (EFI_ERROR (Status
)) {
1797 if (Data2
.Type
> EFI_IFR_TYPE_BOOLEAN
&& Data2
.Type
!= EFI_IFR_TYPE_STRING
) {
1798 return EFI_INVALID_PARAMETER
;
1802 // Pop another expression from the expression stack
1804 Status
= PopExpression (&Data1
);
1805 if (EFI_ERROR (Status
)) {
1809 Result
= CompareHiiValue (&Data1
, &Data2
, FormSet
->HiiHandle
);
1810 if (Result
== EFI_INVALID_PARAMETER
) {
1811 return EFI_INVALID_PARAMETER
;
1814 switch (OpCode
->Operand
) {
1815 case EFI_IFR_EQUAL_OP
:
1816 Value
->Value
.b
= (BOOLEAN
) ((Result
== 0) ? TRUE
: FALSE
);
1819 case EFI_IFR_NOT_EQUAL_OP
:
1820 Value
->Value
.b
= (BOOLEAN
) ((Result
== 0) ? TRUE
: FALSE
);
1823 case EFI_IFR_GREATER_EQUAL_OP
:
1824 Value
->Value
.b
= (BOOLEAN
) ((Result
>= 0) ? TRUE
: FALSE
);
1827 case EFI_IFR_GREATER_THAN_OP
:
1828 Value
->Value
.b
= (BOOLEAN
) ((Result
> 0) ? TRUE
: FALSE
);
1831 case EFI_IFR_LESS_EQUAL_OP
:
1832 Value
->Value
.b
= (BOOLEAN
) ((Result
<= 0) ? TRUE
: FALSE
);
1835 case EFI_IFR_LESS_THAN_OP
:
1836 Value
->Value
.b
= (BOOLEAN
) ((Result
< 0) ? TRUE
: FALSE
);
1844 case EFI_IFR_MATCH_OP
:
1845 Status
= IfrMatch (FormSet
, Value
);
1848 case EFI_IFR_CATENATE_OP
:
1849 Status
= IfrCatenate (FormSet
, Value
);
1855 case EFI_IFR_CONDITIONAL_OP
:
1857 // Pop third expression from the expression stack
1859 Status
= PopExpression (&Data3
);
1860 if (EFI_ERROR (Status
)) {
1865 // Pop second expression from the expression stack
1867 Status
= PopExpression (&Data2
);
1868 if (EFI_ERROR (Status
)) {
1873 // Pop first expression from the expression stack
1875 Status
= PopExpression (&Data1
);
1876 if (EFI_ERROR (Status
)) {
1879 if (Data1
.Type
!= EFI_IFR_TYPE_BOOLEAN
) {
1880 return EFI_INVALID_PARAMETER
;
1883 if (Data1
.Value
.b
) {
1890 case EFI_IFR_FIND_OP
:
1891 Status
= IfrFind (FormSet
, OpCode
->Format
, Value
);
1894 case EFI_IFR_MID_OP
:
1895 Status
= IfrMid (FormSet
, Value
);
1898 case EFI_IFR_TOKEN_OP
:
1899 Status
= IfrToken (FormSet
, Value
);
1902 case EFI_IFR_SPAN_OP
:
1903 Status
= IfrSpan (FormSet
, OpCode
->Flags
, Value
);
1909 if (EFI_ERROR (Status
)) {
1913 Status
= PushExpression (Value
);
1914 if (EFI_ERROR (Status
)) {
1920 // Pop the final result from expression stack
1923 Status
= PopExpression (Value
);
1924 if (EFI_ERROR (Status
)) {
1929 // After evaluating an expression, there should be only one value left on the expression stack
1931 if (PopExpression (Value
) != EFI_ACCESS_DENIED
) {
1932 return EFI_INVALID_PARAMETER
;
1935 CopyMem (&Expression
->Result
, Value
, sizeof (EFI_HII_VALUE
));