]> git.proxmox.com Git - mirror_edk2.git/blob - MdeModulePkg/Universal/SetupBrowserDxe/Expression.c
Invoke EFI_BROWSER_ACTION_RETRIEVE callback when read EfiVarstore question.
[mirror_edk2.git] / MdeModulePkg / Universal / SetupBrowserDxe / Expression.c
1 /** @file
2 Utility functions for expression evaluation.
3
4 Copyright (c) 2007 - 2008, 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
9
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.
12
13 **/
14
15 #include "Setup.h"
16
17 //
18 // Global stack used to evaluate boolean expresions
19 //
20 EFI_HII_VALUE *mOpCodeScopeStack = NULL;
21 EFI_HII_VALUE *mOpCodeScopeStackEnd = NULL;
22 EFI_HII_VALUE *mOpCodeScopeStackPointer = NULL;
23
24 EFI_HII_VALUE *mExpressionEvaluationStack = NULL;
25 EFI_HII_VALUE *mExpressionEvaluationStackEnd = NULL;
26 EFI_HII_VALUE *mExpressionEvaluationStackPointer = NULL;
27
28 //
29 // Unicode collation protocol interface
30 //
31 EFI_UNICODE_COLLATION_PROTOCOL *mUnicodeCollation = NULL;
32
33
34 /**
35 Grow size of the stack.
36
37 This is an internal function.
38
39 @param Stack On input: old stack; On output: new stack
40 @param StackPtr On input: old stack pointer; On output: new stack
41 pointer
42 @param StackEnd On input: old stack end; On output: new stack end
43
44 @retval EFI_SUCCESS Grow stack success.
45 @retval EFI_OUT_OF_RESOURCES No enough memory for stack space.
46
47 **/
48 EFI_STATUS
49 GrowStack (
50 IN OUT EFI_HII_VALUE **Stack,
51 IN OUT EFI_HII_VALUE **StackPtr,
52 IN OUT EFI_HII_VALUE **StackEnd
53 )
54 {
55 UINTN Size;
56 EFI_HII_VALUE *NewStack;
57
58 Size = EXPRESSION_STACK_SIZE_INCREMENT;
59 if (*StackPtr != NULL) {
60 Size = Size + (*StackEnd - *Stack);
61 }
62
63 NewStack = AllocatePool (Size * sizeof (EFI_HII_VALUE));
64 if (NewStack == NULL) {
65 return EFI_OUT_OF_RESOURCES;
66 }
67
68 if (*StackPtr != NULL) {
69 //
70 // Copy from Old Stack to the New Stack
71 //
72 CopyMem (
73 NewStack,
74 *Stack,
75 (*StackEnd - *Stack) * sizeof (EFI_HII_VALUE)
76 );
77
78 //
79 // Free The Old Stack
80 //
81 FreePool (*Stack);
82 }
83
84 //
85 // Make the Stack pointer point to the old data in the new stack
86 //
87 *StackPtr = NewStack + (*StackPtr - *Stack);
88 *Stack = NewStack;
89 *StackEnd = NewStack + Size;
90
91 return EFI_SUCCESS;
92 }
93
94
95 /**
96 Push an element onto the Boolean Stack.
97
98 @param Stack On input: old stack; On output: new stack
99 @param StackPtr On input: old stack pointer; On output: new stack
100 pointer
101 @param StackEnd On input: old stack end; On output: new stack end
102 @param Data Data to push.
103
104 @retval EFI_SUCCESS Push stack success.
105
106 **/
107 EFI_STATUS
108 PushStack (
109 IN OUT EFI_HII_VALUE **Stack,
110 IN OUT EFI_HII_VALUE **StackPtr,
111 IN OUT EFI_HII_VALUE **StackEnd,
112 IN EFI_HII_VALUE *Data
113 )
114 {
115 EFI_STATUS Status;
116
117 //
118 // Check for a stack overflow condition
119 //
120 if (*StackPtr >= *StackEnd) {
121 //
122 // Grow the stack
123 //
124 Status = GrowStack (Stack, StackPtr, StackEnd);
125 if (EFI_ERROR (Status)) {
126 return Status;
127 }
128 }
129
130 //
131 // Push the item onto the stack
132 //
133 CopyMem (*StackPtr, Data, sizeof (EFI_HII_VALUE));
134 *StackPtr = *StackPtr + 1;
135
136 return EFI_SUCCESS;
137 }
138
139
140 /**
141 Pop an element from the stack.
142
143 @param Stack On input: old stack; On output: new stack
144 @param StackPtr On input: old stack pointer; On output: new stack
145 pointer
146 @param StackEnd On input: old stack end; On output: new stack end
147 @param Data Data to pop.
148
149 @retval EFI_SUCCESS The value was popped onto the stack.
150 @retval EFI_ACCESS_DENIED The pop operation underflowed the stack
151
152 **/
153 EFI_STATUS
154 PopStack (
155 IN OUT EFI_HII_VALUE **Stack,
156 IN OUT EFI_HII_VALUE **StackPtr,
157 IN OUT EFI_HII_VALUE **StackEnd,
158 OUT EFI_HII_VALUE *Data
159 )
160 {
161 //
162 // Check for a stack underflow condition
163 //
164 if (*StackPtr == *Stack) {
165 return EFI_ACCESS_DENIED;
166 }
167
168 //
169 // Pop the item off the stack
170 //
171 *StackPtr = *StackPtr - 1;
172 CopyMem (Data, *StackPtr, sizeof (EFI_HII_VALUE));
173 return EFI_SUCCESS;
174 }
175
176
177 /**
178 Reset stack pointer to begin of the stack.
179
180 **/
181 VOID
182 ResetScopeStack (
183 VOID
184 )
185 {
186 mOpCodeScopeStackPointer = mOpCodeScopeStack;
187 }
188
189
190 /**
191 Push an Operand onto the Stack
192
193 @param Operand Operand to push.
194
195 @retval EFI_SUCCESS The value was pushed onto the stack.
196 @retval EFI_OUT_OF_RESOURCES There is not enough system memory to grow the
197 stack.
198
199 **/
200 EFI_STATUS
201 PushScope (
202 IN UINT8 Operand
203 )
204 {
205 EFI_HII_VALUE Data;
206
207 Data.Type = EFI_IFR_TYPE_NUM_SIZE_8;
208 Data.Value.u8 = Operand;
209
210 return PushStack (
211 &mOpCodeScopeStack,
212 &mOpCodeScopeStackPointer,
213 &mOpCodeScopeStackEnd,
214 &Data
215 );
216 }
217
218
219 /**
220 Pop an Operand from the Stack
221
222 @param Operand Operand to pop.
223
224 @retval EFI_SUCCESS The value was pushed onto the stack.
225 @retval EFI_OUT_OF_RESOURCES There is not enough system memory to grow the
226 stack.
227
228 **/
229 EFI_STATUS
230 PopScope (
231 OUT UINT8 *Operand
232 )
233 {
234 EFI_STATUS Status;
235 EFI_HII_VALUE Data;
236
237 Status = PopStack (
238 &mOpCodeScopeStack,
239 &mOpCodeScopeStackPointer,
240 &mOpCodeScopeStackEnd,
241 &Data
242 );
243
244 *Operand = Data.Value.u8;
245
246 return Status;
247 }
248
249
250 /**
251 Reset stack pointer to begin of the stack.
252
253 **/
254 VOID
255 ResetExpressionStack (
256 VOID
257 )
258 {
259 mExpressionEvaluationStackPointer = mExpressionEvaluationStack;
260 }
261
262
263 /**
264 Push an Expression value onto the Stack
265
266 @param Value Expression value to push.
267
268 @retval EFI_SUCCESS The value was pushed onto the stack.
269 @retval EFI_OUT_OF_RESOURCES There is not enough system memory to grow the
270 stack.
271
272 **/
273 EFI_STATUS
274 PushExpression (
275 IN EFI_HII_VALUE *Value
276 )
277 {
278 return PushStack (
279 &mExpressionEvaluationStack,
280 &mExpressionEvaluationStackPointer,
281 &mExpressionEvaluationStackEnd,
282 Value
283 );
284 }
285
286
287 /**
288 Pop an Expression value from the stack.
289
290 @param Value Expression value to pop.
291
292 @retval EFI_SUCCESS The value was popped onto the stack.
293 @retval EFI_ACCESS_DENIED The pop operation underflowed the stack
294
295 **/
296 EFI_STATUS
297 PopExpression (
298 OUT EFI_HII_VALUE *Value
299 )
300 {
301 return PopStack (
302 &mExpressionEvaluationStack,
303 &mExpressionEvaluationStackPointer,
304 &mExpressionEvaluationStackEnd,
305 Value
306 );
307 }
308
309
310 /**
311 Get Form given its FormId.
312
313 @param FormSet The formset which contains this form.
314 @param FormId Id of this form.
315
316 @retval Pointer The form.
317 @retval NULL Specified Form is not found in the formset.
318
319 **/
320 FORM_BROWSER_FORM *
321 IdToForm (
322 IN FORM_BROWSER_FORMSET *FormSet,
323 IN UINT16 FormId
324 )
325 {
326 LIST_ENTRY *Link;
327 FORM_BROWSER_FORM *Form;
328
329 Link = GetFirstNode (&FormSet->FormListHead);
330 while (!IsNull (&FormSet->FormListHead, Link)) {
331 Form = FORM_BROWSER_FORM_FROM_LINK (Link);
332
333 if (Form->FormId == FormId) {
334 return Form;
335 }
336
337 Link = GetNextNode (&FormSet->FormListHead, Link);
338 }
339
340 return NULL;
341 }
342
343
344 /**
345 Search a Question in Form scope using its QuestionId.
346
347 @param Form The form which contains this Question.
348 @param QuestionId Id of this Question.
349
350 @retval Pointer The Question.
351 @retval NULL Specified Question not found in the form.
352
353 **/
354 FORM_BROWSER_STATEMENT *
355 IdToQuestion2 (
356 IN FORM_BROWSER_FORM *Form,
357 IN UINT16 QuestionId
358 )
359 {
360 LIST_ENTRY *Link;
361 FORM_BROWSER_STATEMENT *Question;
362
363 if (QuestionId == 0) {
364 //
365 // The value of zero is reserved
366 //
367 return NULL;
368 }
369
370 Link = GetFirstNode (&Form->StatementListHead);
371 while (!IsNull (&Form->StatementListHead, Link)) {
372 Question = FORM_BROWSER_STATEMENT_FROM_LINK (Link);
373
374 if (Question->QuestionId == QuestionId) {
375 return Question;
376 }
377
378 Link = GetNextNode (&Form->StatementListHead, Link);
379 }
380
381 return NULL;
382 }
383
384
385 /**
386 Search a Question in Formset scope using its QuestionId.
387
388 @param FormSet The formset which contains this form.
389 @param Form The form which contains this Question.
390 @param QuestionId Id of this Question.
391
392 @retval Pointer The Question.
393 @retval NULL Specified Question not found in the form.
394
395 **/
396 FORM_BROWSER_STATEMENT *
397 IdToQuestion (
398 IN FORM_BROWSER_FORMSET *FormSet,
399 IN FORM_BROWSER_FORM *Form,
400 IN UINT16 QuestionId
401 )
402 {
403 LIST_ENTRY *Link;
404 FORM_BROWSER_STATEMENT *Question;
405
406 //
407 // Search in the form scope first
408 //
409 Question = IdToQuestion2 (Form, QuestionId);
410 if (Question != NULL) {
411 return Question;
412 }
413
414 //
415 // Search in the formset scope
416 //
417 Link = GetFirstNode (&FormSet->FormListHead);
418 while (!IsNull (&FormSet->FormListHead, Link)) {
419 Form = FORM_BROWSER_FORM_FROM_LINK (Link);
420
421 Question = IdToQuestion2 (Form, QuestionId);
422 if (Question != NULL) {
423 //
424 // EFI variable storage may be updated by Callback() asynchronous,
425 // to keep synchronous, always reload the Question Value.
426 //
427 if (Question->Storage->Type == EFI_HII_VARSTORE_EFI_VARIABLE) {
428 GetQuestionValue (FormSet, Form, Question, FALSE);
429 }
430
431 return Question;
432 }
433
434 Link = GetNextNode (&FormSet->FormListHead, Link);
435 }
436
437 return NULL;
438 }
439
440
441 /**
442 Get Expression given its RuleId.
443
444 @param Form The form which contains this Expression.
445 @param RuleId Id of this Expression.
446
447 @retval Pointer The Expression.
448 @retval NULL Specified Expression not found in the form.
449
450 **/
451 FORM_EXPRESSION *
452 RuleIdToExpression (
453 IN FORM_BROWSER_FORM *Form,
454 IN UINT8 RuleId
455 )
456 {
457 LIST_ENTRY *Link;
458 FORM_EXPRESSION *Expression;
459
460 Link = GetFirstNode (&Form->ExpressionListHead);
461 while (!IsNull (&Form->ExpressionListHead, Link)) {
462 Expression = FORM_EXPRESSION_FROM_LINK (Link);
463
464 if (Expression->Type == EFI_HII_EXPRESSION_RULE && Expression->RuleId == RuleId) {
465 return Expression;
466 }
467
468 Link = GetNextNode (&Form->ExpressionListHead, Link);
469 }
470
471 return NULL;
472 }
473
474
475 /**
476 Locate the Unicode Collation Protocol interface for later use.
477
478 @retval EFI_SUCCESS Protocol interface initialize success.
479 @retval Other Protocol interface initialize failed.
480
481 **/
482 EFI_STATUS
483 InitializeUnicodeCollationProtocol (
484 VOID
485 )
486 {
487 EFI_STATUS Status;
488
489 if (mUnicodeCollation != NULL) {
490 return EFI_SUCCESS;
491 }
492
493 //
494 // BUGBUG: Proper impelmentation is to locate all Unicode Collation Protocol
495 // instances first and then select one which support English language.
496 // Current implementation just pick the first instance.
497 //
498 Status = gBS->LocateProtocol (
499 &gEfiUnicodeCollation2ProtocolGuid,
500 NULL,
501 (VOID **) &mUnicodeCollation
502 );
503 return Status;
504 }
505
506 /**
507 Convert the input Unicode character to upper.
508
509 @param String Th Unicode character to be converted.
510
511 **/
512 VOID
513 IfrStrToUpper (
514 IN CHAR16 *String
515 )
516 {
517 while (*String != 0) {
518 if ((*String >= 'a') && (*String <= 'z')) {
519 *String = (UINT16) ((*String) & ((UINT16) ~0x20));
520 }
521 String++;
522 }
523 }
524
525
526 /**
527 Evaluate opcode EFI_IFR_TO_STRING.
528
529 @param FormSet Formset which contains this opcode.
530 @param Format String format in EFI_IFR_TO_STRING.
531 @param Result Evaluation result for this opcode.
532
533 @retval EFI_SUCCESS Opcode evaluation success.
534 @retval Other Opcode evaluation failed.
535
536 **/
537 EFI_STATUS
538 IfrToString (
539 IN FORM_BROWSER_FORMSET *FormSet,
540 IN UINT8 Format,
541 OUT EFI_HII_VALUE *Result
542 )
543 {
544 EFI_STATUS Status;
545 EFI_HII_VALUE Value;
546 CHAR16 *String;
547 CHAR16 *PrintFormat;
548 CHAR16 Buffer[MAXIMUM_VALUE_CHARACTERS];
549 UINTN BufferSize;
550
551 Status = PopExpression (&Value);
552 if (EFI_ERROR (Status)) {
553 return Status;
554 }
555
556 switch (Value.Type) {
557 case EFI_IFR_TYPE_NUM_SIZE_8:
558 case EFI_IFR_TYPE_NUM_SIZE_16:
559 case EFI_IFR_TYPE_NUM_SIZE_32:
560 case EFI_IFR_TYPE_NUM_SIZE_64:
561 BufferSize = MAXIMUM_VALUE_CHARACTERS * sizeof (CHAR16);
562 switch (Format) {
563 case EFI_IFR_STRING_UNSIGNED_DEC:
564 case EFI_IFR_STRING_SIGNED_DEC:
565 PrintFormat = L"%ld";
566 break;
567
568 case EFI_IFR_STRING_LOWERCASE_HEX:
569 PrintFormat = L"%lx";
570 break;
571
572 case EFI_IFR_STRING_UPPERCASE_HEX:
573 PrintFormat = L"%lX";
574 break;
575
576 default:
577 return EFI_UNSUPPORTED;
578 }
579 UnicodeSPrint (Buffer, BufferSize, PrintFormat, Value.Value.u64);
580 String = Buffer;
581 break;
582
583 case EFI_IFR_TYPE_STRING:
584 CopyMem (Result, &Value, sizeof (EFI_HII_VALUE));
585 return EFI_SUCCESS;
586
587 case EFI_IFR_TYPE_BOOLEAN:
588 String = (Value.Value.b) ? L"True" : L"False";
589 break;
590
591 default:
592 return EFI_UNSUPPORTED;
593 }
594
595 Result->Type = EFI_IFR_TYPE_STRING;
596 Result->Value.string = NewString (String, FormSet->HiiHandle);
597 return EFI_SUCCESS;
598 }
599
600
601 /**
602 Evaluate opcode EFI_IFR_TO_UINT.
603
604 @param FormSet Formset which contains this opcode.
605 @param Result Evaluation result for this opcode.
606
607 @retval EFI_SUCCESS Opcode evaluation success.
608 @retval Other Opcode evaluation failed.
609
610 **/
611 EFI_STATUS
612 IfrToUint (
613 IN FORM_BROWSER_FORMSET *FormSet,
614 OUT EFI_HII_VALUE *Result
615 )
616 {
617 EFI_STATUS Status;
618 EFI_HII_VALUE Value;
619 CHAR16 *String;
620 CHAR16 *StringPtr;
621
622 Status = PopExpression (&Value);
623 if (EFI_ERROR (Status)) {
624 return Status;
625 }
626
627 if (Value.Type >= EFI_IFR_TYPE_OTHER) {
628 return EFI_UNSUPPORTED;
629 }
630
631 Status = EFI_SUCCESS;
632 if (Value.Type == EFI_IFR_TYPE_STRING) {
633 String = GetToken (Value.Value.string, FormSet->HiiHandle);
634 if (String == NULL) {
635 return EFI_NOT_FOUND;
636 }
637
638 IfrStrToUpper (String);
639 StringPtr = StrStr (String, L"0X");
640 if (StringPtr != NULL) {
641 //
642 // Hex string
643 //
644 Result->Value.u64 = StrHexToUint64 (String);
645 } else {
646 //
647 // decimal string
648 //
649 Result->Value.u64 = StrDecimalToUint64 (String);
650 }
651 FreePool (String);
652 } else {
653 CopyMem (Result, &Value, sizeof (EFI_HII_VALUE));
654 }
655
656 Result->Type = EFI_IFR_TYPE_NUM_SIZE_64;
657 return Status;
658 }
659
660
661 /**
662 Evaluate opcode EFI_IFR_CATENATE.
663
664 @param FormSet Formset which contains this opcode.
665 @param Result Evaluation result for this opcode.
666
667 @retval EFI_SUCCESS Opcode evaluation success.
668 @retval Other Opcode evaluation failed.
669
670 **/
671 EFI_STATUS
672 IfrCatenate (
673 IN FORM_BROWSER_FORMSET *FormSet,
674 OUT EFI_HII_VALUE *Result
675 )
676 {
677 EFI_STATUS Status;
678 EFI_HII_VALUE Value;
679 CHAR16 *String[2];
680 UINTN Index;
681 CHAR16 *StringPtr;
682 UINTN Size;
683
684 //
685 // String[0] - The second string
686 // String[1] - The first string
687 //
688 String[0] = NULL;
689 String[1] = NULL;
690 StringPtr = NULL;
691 Status = EFI_SUCCESS;
692
693 for (Index = 0; Index < 2; Index++) {
694 Status = PopExpression (&Value);
695 if (EFI_ERROR (Status)) {
696 goto Done;
697 }
698
699 if (Value.Type != EFI_IFR_TYPE_STRING) {
700 Status = EFI_UNSUPPORTED;
701 goto Done;
702 }
703
704 String[Index] = GetToken (Value.Value.string, FormSet->HiiHandle);
705 if (String[Index] == NULL) {
706 Status = EFI_NOT_FOUND;
707 goto Done;
708 }
709 }
710
711 Size = StrSize (String[0]);
712 StringPtr= AllocatePool (StrSize (String[1]) + Size);
713 ASSERT (StringPtr != NULL);
714 StrCpy (StringPtr, String[1]);
715 StrCat (StringPtr, String[0]);
716
717 Result->Type = EFI_IFR_TYPE_STRING;
718 Result->Value.string = NewString (StringPtr, FormSet->HiiHandle);
719
720 Done:
721 if (String[0] != NULL) {
722 FreePool (String[0]);
723 }
724 if (String[1] != NULL) {
725 FreePool (String[1]);
726 }
727 if (StringPtr != NULL) {
728 FreePool (StringPtr);
729 }
730
731 return Status;
732 }
733
734
735 /**
736 Evaluate opcode EFI_IFR_MATCH.
737
738 @param FormSet Formset which contains this opcode.
739 @param Result Evaluation result for this opcode.
740
741 @retval EFI_SUCCESS Opcode evaluation success.
742 @retval Other Opcode evaluation failed.
743
744 **/
745 EFI_STATUS
746 IfrMatch (
747 IN FORM_BROWSER_FORMSET *FormSet,
748 OUT EFI_HII_VALUE *Result
749 )
750 {
751 EFI_STATUS Status;
752 EFI_HII_VALUE Value;
753 CHAR16 *String[2];
754 UINTN Index;
755
756 //
757 // String[0] - The string to search
758 // String[1] - pattern
759 //
760 String[0] = NULL;
761 String[1] = NULL;
762 Status = EFI_SUCCESS;
763 for (Index = 0; Index < 2; Index++) {
764 Status = PopExpression (&Value);
765 if (EFI_ERROR (Status)) {
766 goto Done;
767 }
768
769 if (Value.Type != EFI_IFR_TYPE_STRING) {
770 Status = EFI_UNSUPPORTED;
771 goto Done;
772 }
773
774 String[Index] = GetToken (Value.Value.string, FormSet->HiiHandle);
775 if (String [Index] == NULL) {
776 Status = EFI_NOT_FOUND;
777 goto Done;
778 }
779 }
780
781 Result->Type = EFI_IFR_TYPE_BOOLEAN;
782 Result->Value.b = mUnicodeCollation->MetaiMatch (mUnicodeCollation, String[0], String[1]);
783
784 Done:
785 if (String[0] != NULL) {
786 FreePool (String[0]);
787 }
788 if (String[1] != NULL) {
789 FreePool (String[1]);
790 }
791
792 return Status;
793 }
794
795
796 /**
797 Evaluate opcode EFI_IFR_FIND.
798
799 @param FormSet Formset which contains this opcode.
800 @param Format Case sensitive or insensitive.
801 @param Result Evaluation result for this opcode.
802
803 @retval EFI_SUCCESS Opcode evaluation success.
804 @retval Other Opcode evaluation failed.
805
806 **/
807 EFI_STATUS
808 IfrFind (
809 IN FORM_BROWSER_FORMSET *FormSet,
810 IN UINT8 Format,
811 OUT EFI_HII_VALUE *Result
812 )
813 {
814 EFI_STATUS Status;
815 EFI_HII_VALUE Value;
816 CHAR16 *String[2];
817 UINTN Base;
818 CHAR16 *StringPtr;
819 UINTN Index;
820
821 if (Format > EFI_IFR_FF_CASE_INSENSITIVE) {
822 return EFI_UNSUPPORTED;
823 }
824
825 Status = PopExpression (&Value);
826 if (EFI_ERROR (Status)) {
827 return Status;
828 }
829 if (Value.Type > EFI_IFR_TYPE_NUM_SIZE_64) {
830 return EFI_UNSUPPORTED;
831 }
832 Base = (UINTN) Value.Value.u64;
833
834 //
835 // String[0] - sub-string
836 // String[1] - The string to search
837 //
838 String[0] = NULL;
839 String[1] = NULL;
840 for (Index = 0; Index < 2; Index++) {
841 Status = PopExpression (&Value);
842 if (EFI_ERROR (Status)) {
843 goto Done;
844 }
845
846 if (Value.Type != EFI_IFR_TYPE_STRING) {
847 Status = EFI_UNSUPPORTED;
848 goto Done;
849 }
850
851 String[Index] = GetToken (Value.Value.string, FormSet->HiiHandle);
852 if (String[Index] == NULL) {
853 Status = EFI_NOT_FOUND;
854 goto Done;
855 }
856
857 if (Format == EFI_IFR_FF_CASE_INSENSITIVE) {
858 //
859 // Case insensitive, convert both string to upper case
860 //
861 IfrStrToUpper (String[Index]);
862 }
863 }
864
865 Result->Type = EFI_IFR_TYPE_NUM_SIZE_64;
866 if (Base >= StrLen (String[1])) {
867 Result->Value.u64 = 0xFFFFFFFFFFFFFFFFULL;
868 } else {
869 StringPtr = StrStr (String[1] + Base, String[0]);
870 Result->Value.u64 = (StringPtr == NULL) ? 0xFFFFFFFFFFFFFFFFULL : (StringPtr - String[1]);
871 }
872
873 Done:
874 if (String[0] != NULL) {
875 FreePool (String[0]);
876 }
877 if (String[1] != NULL) {
878 FreePool (String[1]);
879 }
880
881 return Status;
882 }
883
884
885 /**
886 Evaluate opcode EFI_IFR_MID.
887
888 @param FormSet Formset which contains this opcode.
889 @param Result Evaluation result for this opcode.
890
891 @retval EFI_SUCCESS Opcode evaluation success.
892 @retval Other Opcode evaluation failed.
893
894 **/
895 EFI_STATUS
896 IfrMid (
897 IN FORM_BROWSER_FORMSET *FormSet,
898 OUT EFI_HII_VALUE *Result
899 )
900 {
901 EFI_STATUS Status;
902 EFI_HII_VALUE Value;
903 CHAR16 *String;
904 UINTN Base;
905 UINTN Length;
906 CHAR16 *SubString;
907
908 Status = PopExpression (&Value);
909 if (EFI_ERROR (Status)) {
910 return Status;
911 }
912 if (Value.Type > EFI_IFR_TYPE_NUM_SIZE_64) {
913 return EFI_UNSUPPORTED;
914 }
915 Length = (UINTN) Value.Value.u64;
916
917 Status = PopExpression (&Value);
918 if (EFI_ERROR (Status)) {
919 return Status;
920 }
921 if (Value.Type > EFI_IFR_TYPE_NUM_SIZE_64) {
922 return EFI_UNSUPPORTED;
923 }
924 Base = (UINTN) Value.Value.u64;
925
926 Status = PopExpression (&Value);
927 if (EFI_ERROR (Status)) {
928 return Status;
929 }
930 if (Value.Type != EFI_IFR_TYPE_STRING) {
931 return EFI_UNSUPPORTED;
932 }
933 String = GetToken (Value.Value.string, FormSet->HiiHandle);
934 if (String == NULL) {
935 return EFI_NOT_FOUND;
936 }
937
938 if (Length == 0 || Base >= StrLen (String)) {
939 SubString = gEmptyString;
940 } else {
941 SubString = String + Base;
942 if ((Base + Length) < StrLen (String)) {
943 SubString[Length] = L'\0';
944 }
945 }
946
947 Result->Type = EFI_IFR_TYPE_STRING;
948 Result->Value.string = NewString (SubString, FormSet->HiiHandle);
949
950 FreePool (String);
951
952 return Status;
953 }
954
955
956 /**
957 Evaluate opcode EFI_IFR_TOKEN.
958
959 @param FormSet Formset which contains this opcode.
960 @param Result Evaluation result for this opcode.
961
962 @retval EFI_SUCCESS Opcode evaluation success.
963 @retval Other Opcode evaluation failed.
964
965 **/
966 EFI_STATUS
967 IfrToken (
968 IN FORM_BROWSER_FORMSET *FormSet,
969 OUT EFI_HII_VALUE *Result
970 )
971 {
972 EFI_STATUS Status;
973 EFI_HII_VALUE Value;
974 CHAR16 *String[2];
975 UINTN Count;
976 CHAR16 *Delimiter;
977 CHAR16 *SubString;
978 CHAR16 *StringPtr;
979 UINTN Index;
980
981 Status = PopExpression (&Value);
982 if (EFI_ERROR (Status)) {
983 return Status;
984 }
985 if (Value.Type > EFI_IFR_TYPE_NUM_SIZE_64) {
986 return EFI_UNSUPPORTED;
987 }
988 Count = (UINTN) Value.Value.u64;
989
990 //
991 // String[0] - Delimiter
992 // String[1] - The string to search
993 //
994 String[0] = NULL;
995 String[1] = NULL;
996 for (Index = 0; Index < 2; Index++) {
997 Status = PopExpression (&Value);
998 if (EFI_ERROR (Status)) {
999 goto Done;
1000 }
1001
1002 if (Value.Type != EFI_IFR_TYPE_STRING) {
1003 Status = EFI_UNSUPPORTED;
1004 goto Done;
1005 }
1006
1007 String[Index] = GetToken (Value.Value.string, FormSet->HiiHandle);
1008 if (String[Index] == NULL) {
1009 Status = EFI_NOT_FOUND;
1010 goto Done;
1011 }
1012 }
1013
1014 Delimiter = String[0];
1015 SubString = String[1];
1016 while (Count > 0) {
1017 SubString = StrStr (SubString, Delimiter);
1018 if (SubString != NULL) {
1019 //
1020 // Skip over the delimiter
1021 //
1022 SubString = SubString + StrLen (Delimiter);
1023 } else {
1024 break;
1025 }
1026 Count--;
1027 }
1028
1029 if (SubString == NULL) {
1030 //
1031 // nth delimited sub-string not found, push an empty string
1032 //
1033 SubString = gEmptyString;
1034 } else {
1035 //
1036 // Put a NULL terminator for nth delimited sub-string
1037 //
1038 StringPtr = StrStr (SubString, Delimiter);
1039 if (StringPtr != NULL) {
1040 *StringPtr = L'\0';
1041 }
1042 }
1043
1044 Result->Type = EFI_IFR_TYPE_STRING;
1045 Result->Value.string = NewString (SubString, FormSet->HiiHandle);
1046
1047 Done:
1048 if (String[0] != NULL) {
1049 FreePool (String[0]);
1050 }
1051 if (String[1] != NULL) {
1052 FreePool (String[1]);
1053 }
1054
1055 return Status;
1056 }
1057
1058
1059 /**
1060 Evaluate opcode EFI_IFR_SPAN.
1061
1062 @param FormSet Formset which contains this opcode.
1063 @param Flags FIRST_MATCHING or FIRST_NON_MATCHING.
1064 @param Result Evaluation result for this opcode.
1065
1066 @retval EFI_SUCCESS Opcode evaluation success.
1067 @retval Other Opcode evaluation failed.
1068
1069 **/
1070 EFI_STATUS
1071 IfrSpan (
1072 IN FORM_BROWSER_FORMSET *FormSet,
1073 IN UINT8 Flags,
1074 OUT EFI_HII_VALUE *Result
1075 )
1076 {
1077 EFI_STATUS Status;
1078 EFI_HII_VALUE Value;
1079 CHAR16 *String[2];
1080 CHAR16 *Charset;
1081 UINTN Base;
1082 UINTN Index;
1083 CHAR16 *StringPtr;
1084 BOOLEAN Found;
1085
1086 Status = PopExpression (&Value);
1087 if (EFI_ERROR (Status)) {
1088 return Status;
1089 }
1090 if (Value.Type > EFI_IFR_TYPE_NUM_SIZE_64) {
1091 return EFI_UNSUPPORTED;
1092 }
1093 Base = (UINTN) Value.Value.u64;
1094
1095 //
1096 // String[0] - Charset
1097 // String[1] - The string to search
1098 //
1099 String[0] = NULL;
1100 String[1] = NULL;
1101 for (Index = 0; Index < 2; Index++) {
1102 Status = PopExpression (&Value);
1103 if (EFI_ERROR (Status)) {
1104 goto Done;
1105 }
1106
1107 if (Value.Type != EFI_IFR_TYPE_STRING) {
1108 Status = EFI_UNSUPPORTED;
1109 goto Done;
1110 }
1111
1112 String[Index] = GetToken (Value.Value.string, FormSet->HiiHandle);
1113 if (String [Index] == NULL) {
1114 Status = EFI_NOT_FOUND;
1115 goto Done;
1116 }
1117 }
1118
1119 if (Base >= StrLen (String[1])) {
1120 Status = EFI_UNSUPPORTED;
1121 goto Done;
1122 }
1123
1124 Found = FALSE;
1125 StringPtr = String[1] + Base;
1126 Charset = String[0];
1127 while (*StringPtr != 0 && !Found) {
1128 Index = 0;
1129 while (Charset[Index] != 0) {
1130 if (*StringPtr >= Charset[Index] && *StringPtr <= Charset[Index + 1]) {
1131 if (Flags == EFI_IFR_FLAGS_FIRST_MATCHING) {
1132 Found = TRUE;
1133 break;
1134 }
1135 } else {
1136 if (Flags == EFI_IFR_FLAGS_FIRST_NON_MATCHING) {
1137 Found = TRUE;
1138 break;
1139 }
1140 }
1141 //
1142 // Skip characters pair representing low-end of a range and high-end of a range
1143 //
1144 Index += 2;
1145 }
1146
1147 if (!Found) {
1148 StringPtr++;
1149 }
1150 }
1151
1152 Result->Type = EFI_IFR_TYPE_NUM_SIZE_64;
1153 Result->Value.u64 = StringPtr - String[1];
1154
1155 Done:
1156 if (String[0] != NULL) {
1157 FreePool (String[0]);
1158 }
1159 if (String[1] != NULL) {
1160 FreePool (String[1]);
1161 }
1162
1163 return Status;
1164 }
1165
1166
1167 /**
1168 Zero extend integer/boolean/date/time to UINT64 for comparing.
1169
1170 @param Value HII Value to be converted.
1171
1172 **/
1173 VOID
1174 ExtendValueToU64 (
1175 IN EFI_HII_VALUE *Value
1176 )
1177 {
1178 UINT64 Temp;
1179
1180 Temp = 0;
1181 switch (Value->Type) {
1182 case EFI_IFR_TYPE_NUM_SIZE_8:
1183 Temp = Value->Value.u8;
1184 break;
1185
1186 case EFI_IFR_TYPE_NUM_SIZE_16:
1187 Temp = Value->Value.u16;
1188 break;
1189
1190 case EFI_IFR_TYPE_NUM_SIZE_32:
1191 Temp = Value->Value.u32;
1192 break;
1193
1194 case EFI_IFR_TYPE_BOOLEAN:
1195 Temp = Value->Value.b;
1196 break;
1197
1198 case EFI_IFR_TYPE_TIME:
1199 Temp = Value->Value.u32 & 0xffffff;
1200 break;
1201
1202 case EFI_IFR_TYPE_DATE:
1203 Temp = Value->Value.u32;
1204 break;
1205
1206 default:
1207 return;
1208 }
1209
1210 Value->Value.u64 = Temp;
1211 }
1212
1213
1214 /**
1215 Compare two Hii value.
1216
1217 @param Value1 Expression value to compare on left-hand.
1218 @param Value2 Expression value to compare on right-hand.
1219 @param HiiHandle Only required for string compare.
1220
1221 @retval EFI_INVALID_PARAMETER Could not perform comparation on two values.
1222 @retval 0 Two operators equeal.
1223 @return Positive value if Value1 is greater than Value2.
1224 @retval Negative value if Value1 is less than Value2.
1225
1226 **/
1227 INTN
1228 CompareHiiValue (
1229 IN EFI_HII_VALUE *Value1,
1230 IN EFI_HII_VALUE *Value2,
1231 IN EFI_HII_HANDLE HiiHandle OPTIONAL
1232 )
1233 {
1234 INTN Result;
1235 INT64 Temp64;
1236 CHAR16 *Str1;
1237 CHAR16 *Str2;
1238
1239 if (Value1->Type >= EFI_IFR_TYPE_OTHER || Value2->Type >= EFI_IFR_TYPE_OTHER ) {
1240 return EFI_INVALID_PARAMETER;
1241 }
1242
1243 if (Value1->Type == EFI_IFR_TYPE_STRING || Value2->Type == EFI_IFR_TYPE_STRING ) {
1244 if (Value1->Type != Value2->Type) {
1245 //
1246 // Both Operator should be type of String
1247 //
1248 return EFI_INVALID_PARAMETER;
1249 }
1250
1251 if (Value1->Value.string == 0 || Value2->Value.string == 0) {
1252 //
1253 // StringId 0 is reserved
1254 //
1255 return EFI_INVALID_PARAMETER;
1256 }
1257
1258 if (Value1->Value.string == Value2->Value.string) {
1259 return 0;
1260 }
1261
1262 Str1 = GetToken (Value1->Value.string, HiiHandle);
1263 if (Str1 == NULL) {
1264 //
1265 // String not found
1266 //
1267 return EFI_INVALID_PARAMETER;
1268 }
1269
1270 Str2 = GetToken (Value2->Value.string, HiiHandle);
1271 if (Str2 == NULL) {
1272 FreePool (Str1);
1273 return EFI_INVALID_PARAMETER;
1274 }
1275
1276 Result = StrCmp (Str1, Str2);
1277
1278 FreePool (Str1);
1279 FreePool (Str2);
1280
1281 return Result;
1282 }
1283
1284 //
1285 // Take remain types(integer, boolean, date/time) as integer
1286 //
1287 Temp64 = (INT64) (Value1->Value.u64 - Value2->Value.u64);
1288 if (Temp64 > 0) {
1289 Result = 1;
1290 } else if (Temp64 < 0) {
1291 Result = -1;
1292 } else {
1293 Result = 0;
1294 }
1295
1296 return Result;
1297 }
1298
1299
1300 /**
1301 Evaluate the result of a HII expression.
1302
1303 If Expression is NULL, then ASSERT.
1304
1305 @param FormSet FormSet associated with this expression.
1306 @param Form Form associated with this expression.
1307 @param Expression Expression to be evaluated.
1308
1309 @retval EFI_SUCCESS The expression evaluated successfuly
1310 @retval EFI_NOT_FOUND The Question which referenced by a QuestionId
1311 could not be found.
1312 @retval EFI_OUT_OF_RESOURCES There is not enough system memory to grow the
1313 stack.
1314 @retval EFI_ACCESS_DENIED The pop operation underflowed the stack
1315 @retval EFI_INVALID_PARAMETER Syntax error with the Expression
1316
1317 **/
1318 EFI_STATUS
1319 EvaluateExpression (
1320 IN FORM_BROWSER_FORMSET *FormSet,
1321 IN FORM_BROWSER_FORM *Form,
1322 IN OUT FORM_EXPRESSION *Expression
1323 )
1324 {
1325 EFI_STATUS Status;
1326 LIST_ENTRY *Link;
1327 EXPRESSION_OPCODE *OpCode;
1328 FORM_BROWSER_STATEMENT *Question;
1329 FORM_BROWSER_STATEMENT *Question2;
1330 UINT16 Index;
1331 EFI_HII_VALUE Data1;
1332 EFI_HII_VALUE Data2;
1333 EFI_HII_VALUE Data3;
1334 FORM_EXPRESSION *RuleExpression;
1335 EFI_HII_VALUE *Value;
1336 INTN Result;
1337 CHAR16 *StrPtr;
1338 UINT32 TempValue;
1339
1340 //
1341 // Always reset the stack before evaluating an Expression
1342 //
1343 ResetExpressionStack ();
1344
1345 ASSERT (Expression != NULL);
1346 Expression->Result.Type = EFI_IFR_TYPE_OTHER;
1347
1348 Link = GetFirstNode (&Expression->OpCodeListHead);
1349 while (!IsNull (&Expression->OpCodeListHead, Link)) {
1350 OpCode = EXPRESSION_OPCODE_FROM_LINK (Link);
1351
1352 Link = GetNextNode (&Expression->OpCodeListHead, Link);
1353
1354 ZeroMem (&Data1, sizeof (EFI_HII_VALUE));
1355 ZeroMem (&Data2, sizeof (EFI_HII_VALUE));
1356 ZeroMem (&Data3, sizeof (EFI_HII_VALUE));
1357
1358 Value = &Data3;
1359 Value->Type = EFI_IFR_TYPE_BOOLEAN;
1360 Status = EFI_SUCCESS;
1361
1362 switch (OpCode->Operand) {
1363 //
1364 // Built-in functions
1365 //
1366 case EFI_IFR_EQ_ID_VAL_OP:
1367 Question = IdToQuestion (FormSet, Form, OpCode->QuestionId);
1368 if (Question == NULL) {
1369 return EFI_NOT_FOUND;
1370 }
1371
1372 Result = CompareHiiValue (&Question->HiiValue, &OpCode->Value, NULL);
1373 if (Result == EFI_INVALID_PARAMETER) {
1374 return EFI_INVALID_PARAMETER;
1375 }
1376 Value->Value.b = (BOOLEAN) ((Result == 0) ? TRUE : FALSE);
1377 break;
1378
1379 case EFI_IFR_EQ_ID_ID_OP:
1380 Question = IdToQuestion (FormSet, Form, OpCode->QuestionId);
1381 if (Question == NULL) {
1382 return EFI_NOT_FOUND;
1383 }
1384
1385 Question2 = IdToQuestion (FormSet, Form, OpCode->QuestionId2);
1386 if (Question2 == NULL) {
1387 return EFI_NOT_FOUND;
1388 }
1389
1390 Result = CompareHiiValue (&Question->HiiValue, &Question2->HiiValue, FormSet->HiiHandle);
1391 if (Result == EFI_INVALID_PARAMETER) {
1392 return EFI_INVALID_PARAMETER;
1393 }
1394 Value->Value.b = (BOOLEAN) ((Result == 0) ? TRUE : FALSE);
1395 break;
1396
1397 case EFI_IFR_EQ_ID_LIST_OP:
1398 Question = IdToQuestion (FormSet, Form, OpCode->QuestionId);
1399 if (Question == NULL) {
1400 return EFI_NOT_FOUND;
1401 }
1402
1403 Value->Value.b = FALSE;
1404 for (Index =0; Index < OpCode->ListLength; Index++) {
1405 if (Question->HiiValue.Value.u16 == OpCode->ValueList[Index]) {
1406 Value->Value.b = TRUE;
1407 break;
1408 }
1409 }
1410 break;
1411
1412 case EFI_IFR_DUP_OP:
1413 Status = PopExpression (Value);
1414 if (EFI_ERROR (Status)) {
1415 return Status;
1416 }
1417
1418 Status = PushExpression (Value);
1419 break;
1420
1421 case EFI_IFR_QUESTION_REF1_OP:
1422 case EFI_IFR_THIS_OP:
1423 Question = IdToQuestion (FormSet, Form, OpCode->QuestionId);
1424 if (Question == NULL) {
1425 return EFI_NOT_FOUND;
1426 }
1427
1428 Value = &Question->HiiValue;
1429 break;
1430
1431 case EFI_IFR_QUESTION_REF3_OP:
1432 if (OpCode->DevicePath == 0) {
1433 //
1434 // EFI_IFR_QUESTION_REF3
1435 // Pop an expression from the expression stack
1436 //
1437 Status = PopExpression (Value);
1438 if (EFI_ERROR (Status)) {
1439 return Status;
1440 }
1441
1442 //
1443 // Validate the expression value
1444 //
1445 if ((Value->Type > EFI_IFR_TYPE_NUM_SIZE_64) || (Value->Value.u64 > 0xffff)) {
1446 return EFI_NOT_FOUND;
1447 }
1448
1449 Question = IdToQuestion (FormSet, Form, Value->Value.u16);
1450 if (Question == NULL) {
1451 return EFI_NOT_FOUND;
1452 }
1453
1454 //
1455 // push the questions' value on to the expression stack
1456 //
1457 Value = &Question->HiiValue;
1458 } else {
1459 //
1460 // BUGBUG: push 0 for EFI_IFR_QUESTION_REF3_2 and EFI_IFR_QUESTION_REF3_3,
1461 // since it is impractical to evaluate the value of a Question in another
1462 // Hii Package list.
1463 //
1464 ZeroMem (Value, sizeof (EFI_HII_VALUE));
1465 }
1466 break;
1467
1468 case EFI_IFR_RULE_REF_OP:
1469 //
1470 // Find expression for this rule
1471 //
1472 RuleExpression = RuleIdToExpression (Form, OpCode->RuleId);
1473 if (RuleExpression == NULL) {
1474 return EFI_NOT_FOUND;
1475 }
1476
1477 //
1478 // Evaluate this rule expression
1479 //
1480 Status = EvaluateExpression (FormSet, Form, RuleExpression);
1481 if (EFI_ERROR (Status)) {
1482 return Status;
1483 }
1484
1485 Value = &RuleExpression->Result;
1486 break;
1487
1488 case EFI_IFR_STRING_REF1_OP:
1489 Value->Type = EFI_IFR_TYPE_STRING;
1490 Value->Value.string = OpCode->Value.Value.string;
1491 break;
1492
1493 //
1494 // Constant
1495 //
1496 case EFI_IFR_TRUE_OP:
1497 case EFI_IFR_FALSE_OP:
1498 case EFI_IFR_ONE_OP:
1499 case EFI_IFR_ONES_OP:
1500 case EFI_IFR_UINT8_OP:
1501 case EFI_IFR_UINT16_OP:
1502 case EFI_IFR_UINT32_OP:
1503 case EFI_IFR_UINT64_OP:
1504 case EFI_IFR_UNDEFINED_OP:
1505 case EFI_IFR_VERSION_OP:
1506 case EFI_IFR_ZERO_OP:
1507 Value = &OpCode->Value;
1508 break;
1509
1510 //
1511 // unary-op
1512 //
1513 case EFI_IFR_LENGTH_OP:
1514 Status = PopExpression (Value);
1515 if (EFI_ERROR (Status)) {
1516 return Status;
1517 }
1518 if (Value->Type != EFI_IFR_TYPE_STRING) {
1519 return EFI_INVALID_PARAMETER;
1520 }
1521
1522 StrPtr = GetToken (Value->Value.string, FormSet->HiiHandle);
1523 if (StrPtr == NULL) {
1524 return EFI_INVALID_PARAMETER;
1525 }
1526
1527 Value->Type = EFI_IFR_TYPE_NUM_SIZE_64;
1528 Value->Value.u64 = StrLen (StrPtr);
1529 FreePool (StrPtr);
1530 break;
1531
1532 case EFI_IFR_NOT_OP:
1533 Status = PopExpression (Value);
1534 if (EFI_ERROR (Status)) {
1535 return Status;
1536 }
1537 if (Value->Type != EFI_IFR_TYPE_BOOLEAN) {
1538 return EFI_INVALID_PARAMETER;
1539 }
1540 Value->Value.b = (BOOLEAN) (!Value->Value.b);
1541 break;
1542
1543 case EFI_IFR_QUESTION_REF2_OP:
1544 //
1545 // Pop an expression from the expression stack
1546 //
1547 Status = PopExpression (Value);
1548 if (EFI_ERROR (Status)) {
1549 return Status;
1550 }
1551
1552 //
1553 // Validate the expression value
1554 //
1555 if ((Value->Type > EFI_IFR_TYPE_NUM_SIZE_64) || (Value->Value.u64 > 0xffff)) {
1556 return EFI_NOT_FOUND;
1557 }
1558
1559 Question = IdToQuestion (FormSet, Form, Value->Value.u16);
1560 if (Question == NULL) {
1561 return EFI_NOT_FOUND;
1562 }
1563
1564 Value = &Question->HiiValue;
1565 break;
1566
1567 case EFI_IFR_STRING_REF2_OP:
1568 //
1569 // Pop an expression from the expression stack
1570 //
1571 Status = PopExpression (Value);
1572 if (EFI_ERROR (Status)) {
1573 return Status;
1574 }
1575
1576 //
1577 // Validate the expression value
1578 //
1579 if ((Value->Type > EFI_IFR_TYPE_NUM_SIZE_64) || (Value->Value.u64 > 0xffff)) {
1580 return EFI_NOT_FOUND;
1581 }
1582
1583 Value->Type = EFI_IFR_TYPE_STRING;
1584 StrPtr = GetToken (Value->Value.u16, FormSet->HiiHandle);
1585 if (StrPtr == NULL) {
1586 //
1587 // If String not exit, push an empty string
1588 //
1589 Value->Value.string = NewString (gEmptyString, FormSet->HiiHandle);
1590 } else {
1591 Index = (UINT16) Value->Value.u64;
1592 Value->Value.string = Index;
1593 FreePool (StrPtr);
1594 }
1595 break;
1596
1597 case EFI_IFR_TO_BOOLEAN_OP:
1598 //
1599 // Pop an expression from the expression stack
1600 //
1601 Status = PopExpression (Value);
1602 if (EFI_ERROR (Status)) {
1603 return Status;
1604 }
1605
1606 //
1607 // Convert an expression to a Boolean
1608 //
1609 if (Value->Type <= EFI_IFR_TYPE_DATE) {
1610 //
1611 // When converting from an unsigned integer, zero will be converted to
1612 // FALSE and any other value will be converted to TRUE.
1613 //
1614 Value->Value.b = (BOOLEAN) ((Value->Value.u64) ? TRUE : FALSE);
1615
1616 Value->Type = EFI_IFR_TYPE_BOOLEAN;
1617 } else if (Value->Type == EFI_IFR_TYPE_STRING) {
1618 //
1619 // When converting from a string, if case-insensitive compare
1620 // with "true" is True, then push True. If a case-insensitive compare
1621 // with "false" is True, then push False.
1622 //
1623 StrPtr = GetToken (Value->Value.string, FormSet->HiiHandle);
1624 if (StrPtr == NULL) {
1625 return EFI_INVALID_PARAMETER;
1626 }
1627
1628 if ((StrCmp (StrPtr, L"true") == 0) || (StrCmp (StrPtr, L"false") == 0)){
1629 Value->Value.b = TRUE;
1630 } else {
1631 Value->Value.b = FALSE;
1632 }
1633 FreePool (StrPtr);
1634 Value->Type = EFI_IFR_TYPE_BOOLEAN;
1635 }
1636 break;
1637
1638 case EFI_IFR_TO_STRING_OP:
1639 Status = IfrToString (FormSet, OpCode->Format, Value);
1640 break;
1641
1642 case EFI_IFR_TO_UINT_OP:
1643 Status = IfrToUint (FormSet, Value);
1644 break;
1645
1646 case EFI_IFR_TO_LOWER_OP:
1647 case EFI_IFR_TO_UPPER_OP:
1648 Status = InitializeUnicodeCollationProtocol ();
1649 if (EFI_ERROR (Status)) {
1650 return Status;
1651 }
1652
1653 Status = PopExpression (Value);
1654 if (EFI_ERROR (Status)) {
1655 return Status;
1656 }
1657
1658 if (Value->Type != EFI_IFR_TYPE_STRING) {
1659 return EFI_UNSUPPORTED;
1660 }
1661
1662 StrPtr = GetToken (Value->Value.string, FormSet->HiiHandle);
1663 if (StrPtr == NULL) {
1664 return EFI_NOT_FOUND;
1665 }
1666
1667 if (OpCode->Operand == EFI_IFR_TO_LOWER_OP) {
1668 mUnicodeCollation->StrLwr (mUnicodeCollation, StrPtr);
1669 } else {
1670 mUnicodeCollation->StrUpr (mUnicodeCollation, StrPtr);
1671 }
1672 Value->Value.string = NewString (StrPtr, FormSet->HiiHandle);
1673 FreePool (StrPtr);
1674 break;
1675
1676 case EFI_IFR_BITWISE_NOT_OP:
1677 //
1678 // Pop an expression from the expression stack
1679 //
1680 Status = PopExpression (Value);
1681 if (EFI_ERROR (Status)) {
1682 return Status;
1683 }
1684 if (Value->Type > EFI_IFR_TYPE_DATE) {
1685 return EFI_INVALID_PARAMETER;
1686 }
1687
1688 Value->Type = EFI_IFR_TYPE_NUM_SIZE_64;
1689 Value->Value.u64 = ~Value->Value.u64;
1690 break;
1691
1692 //
1693 // binary-op
1694 //
1695 case EFI_IFR_ADD_OP:
1696 case EFI_IFR_SUBTRACT_OP:
1697 case EFI_IFR_MULTIPLY_OP:
1698 case EFI_IFR_DIVIDE_OP:
1699 case EFI_IFR_MODULO_OP:
1700 case EFI_IFR_BITWISE_AND_OP:
1701 case EFI_IFR_BITWISE_OR_OP:
1702 case EFI_IFR_SHIFT_LEFT_OP:
1703 case EFI_IFR_SHIFT_RIGHT_OP:
1704 //
1705 // Pop an expression from the expression stack
1706 //
1707 Status = PopExpression (&Data2);
1708 if (EFI_ERROR (Status)) {
1709 return Status;
1710 }
1711 if (Data2.Type > EFI_IFR_TYPE_DATE) {
1712 return EFI_INVALID_PARAMETER;
1713 }
1714
1715 //
1716 // Pop another expression from the expression stack
1717 //
1718 Status = PopExpression (&Data1);
1719 if (EFI_ERROR (Status)) {
1720 return Status;
1721 }
1722 if (Data1.Type > EFI_IFR_TYPE_DATE) {
1723 return EFI_INVALID_PARAMETER;
1724 }
1725
1726 Value->Type = EFI_IFR_TYPE_NUM_SIZE_64;
1727
1728 switch (OpCode->Operand) {
1729 case EFI_IFR_ADD_OP:
1730 Value->Value.u64 = Data1.Value.u64 + Data2.Value.u64;
1731 break;
1732
1733 case EFI_IFR_SUBTRACT_OP:
1734 Value->Value.u64 = Data1.Value.u64 - Data2.Value.u64;
1735 break;
1736
1737 case EFI_IFR_MULTIPLY_OP:
1738 Value->Value.u64 = MultU64x32 (Data1.Value.u64, (UINT32) Data2.Value.u64);
1739 break;
1740
1741 case EFI_IFR_DIVIDE_OP:
1742 Value->Value.u64 = DivU64x32 (Data1.Value.u64, (UINT32) Data2.Value.u64);
1743 break;
1744
1745 case EFI_IFR_MODULO_OP:
1746 DivU64x32Remainder (Data1.Value.u64, (UINT32) Data2.Value.u64, &TempValue);
1747 Value->Value.u64 = TempValue;
1748 break;
1749
1750 case EFI_IFR_BITWISE_AND_OP:
1751 Value->Value.u64 = Data1.Value.u64 & Data2.Value.u64;
1752 break;
1753
1754 case EFI_IFR_BITWISE_OR_OP:
1755 Value->Value.u64 = Data1.Value.u64 | Data2.Value.u64;
1756 break;
1757
1758 case EFI_IFR_SHIFT_LEFT_OP:
1759 Value->Value.u64 = LShiftU64 (Data1.Value.u64, (UINTN) Data2.Value.u64);
1760 break;
1761
1762 case EFI_IFR_SHIFT_RIGHT_OP:
1763 Value->Value.u64 = RShiftU64 (Data1.Value.u64, (UINTN) Data2.Value.u64);
1764 break;
1765
1766 default:
1767 break;
1768 }
1769 break;
1770
1771 case EFI_IFR_AND_OP:
1772 case EFI_IFR_OR_OP:
1773 //
1774 // Two Boolean operator
1775 //
1776 Status = PopExpression (&Data2);
1777 if (EFI_ERROR (Status)) {
1778 return Status;
1779 }
1780 if (Data2.Type != EFI_IFR_TYPE_BOOLEAN) {
1781 return EFI_INVALID_PARAMETER;
1782 }
1783
1784 //
1785 // Pop another expression from the expression stack
1786 //
1787 Status = PopExpression (&Data1);
1788 if (EFI_ERROR (Status)) {
1789 return Status;
1790 }
1791 if (Data1.Type != EFI_IFR_TYPE_BOOLEAN) {
1792 return EFI_INVALID_PARAMETER;
1793 }
1794
1795 if (OpCode->Operand == EFI_IFR_AND_OP) {
1796 Value->Value.b = (BOOLEAN) (Data1.Value.b && Data2.Value.b);
1797 } else {
1798 Value->Value.b = (BOOLEAN) (Data1.Value.b || Data2.Value.b);
1799 }
1800 break;
1801
1802 case EFI_IFR_EQUAL_OP:
1803 case EFI_IFR_NOT_EQUAL_OP:
1804 case EFI_IFR_GREATER_EQUAL_OP:
1805 case EFI_IFR_GREATER_THAN_OP:
1806 case EFI_IFR_LESS_EQUAL_OP:
1807 case EFI_IFR_LESS_THAN_OP:
1808 //
1809 // Compare two integer, string, boolean or date/time
1810 //
1811 Status = PopExpression (&Data2);
1812 if (EFI_ERROR (Status)) {
1813 return Status;
1814 }
1815 if (Data2.Type > EFI_IFR_TYPE_BOOLEAN && Data2.Type != EFI_IFR_TYPE_STRING) {
1816 return EFI_INVALID_PARAMETER;
1817 }
1818
1819 //
1820 // Pop another expression from the expression stack
1821 //
1822 Status = PopExpression (&Data1);
1823 if (EFI_ERROR (Status)) {
1824 return Status;
1825 }
1826
1827 Result = CompareHiiValue (&Data1, &Data2, FormSet->HiiHandle);
1828 if (Result == EFI_INVALID_PARAMETER) {
1829 return EFI_INVALID_PARAMETER;
1830 }
1831
1832 switch (OpCode->Operand) {
1833 case EFI_IFR_EQUAL_OP:
1834 Value->Value.b = (BOOLEAN) ((Result == 0) ? TRUE : FALSE);
1835 break;
1836
1837 case EFI_IFR_NOT_EQUAL_OP:
1838 Value->Value.b = (BOOLEAN) ((Result == 0) ? TRUE : FALSE);
1839 break;
1840
1841 case EFI_IFR_GREATER_EQUAL_OP:
1842 Value->Value.b = (BOOLEAN) ((Result >= 0) ? TRUE : FALSE);
1843 break;
1844
1845 case EFI_IFR_GREATER_THAN_OP:
1846 Value->Value.b = (BOOLEAN) ((Result > 0) ? TRUE : FALSE);
1847 break;
1848
1849 case EFI_IFR_LESS_EQUAL_OP:
1850 Value->Value.b = (BOOLEAN) ((Result <= 0) ? TRUE : FALSE);
1851 break;
1852
1853 case EFI_IFR_LESS_THAN_OP:
1854 Value->Value.b = (BOOLEAN) ((Result < 0) ? TRUE : FALSE);
1855 break;
1856
1857 default:
1858 break;
1859 }
1860 break;
1861
1862 case EFI_IFR_MATCH_OP:
1863 Status = IfrMatch (FormSet, Value);
1864 break;
1865
1866 case EFI_IFR_CATENATE_OP:
1867 Status = IfrCatenate (FormSet, Value);
1868 break;
1869
1870 //
1871 // ternary-op
1872 //
1873 case EFI_IFR_CONDITIONAL_OP:
1874 //
1875 // Pop third expression from the expression stack
1876 //
1877 Status = PopExpression (&Data3);
1878 if (EFI_ERROR (Status)) {
1879 return Status;
1880 }
1881
1882 //
1883 // Pop second expression from the expression stack
1884 //
1885 Status = PopExpression (&Data2);
1886 if (EFI_ERROR (Status)) {
1887 return Status;
1888 }
1889
1890 //
1891 // Pop first expression from the expression stack
1892 //
1893 Status = PopExpression (&Data1);
1894 if (EFI_ERROR (Status)) {
1895 return Status;
1896 }
1897 if (Data1.Type != EFI_IFR_TYPE_BOOLEAN) {
1898 return EFI_INVALID_PARAMETER;
1899 }
1900
1901 if (Data1.Value.b) {
1902 Value = &Data3;
1903 } else {
1904 Value = &Data2;
1905 }
1906 break;
1907
1908 case EFI_IFR_FIND_OP:
1909 Status = IfrFind (FormSet, OpCode->Format, Value);
1910 break;
1911
1912 case EFI_IFR_MID_OP:
1913 Status = IfrMid (FormSet, Value);
1914 break;
1915
1916 case EFI_IFR_TOKEN_OP:
1917 Status = IfrToken (FormSet, Value);
1918 break;
1919
1920 case EFI_IFR_SPAN_OP:
1921 Status = IfrSpan (FormSet, OpCode->Flags, Value);
1922 break;
1923
1924 default:
1925 break;
1926 }
1927 if (EFI_ERROR (Status)) {
1928 return Status;
1929 }
1930
1931 Status = PushExpression (Value);
1932 if (EFI_ERROR (Status)) {
1933 return Status;
1934 }
1935 }
1936
1937 //
1938 // Pop the final result from expression stack
1939 //
1940 Value = &Data1;
1941 Status = PopExpression (Value);
1942 if (EFI_ERROR (Status)) {
1943 return Status;
1944 }
1945
1946 //
1947 // After evaluating an expression, there should be only one value left on the expression stack
1948 //
1949 if (PopExpression (Value) != EFI_ACCESS_DENIED) {
1950 return EFI_INVALID_PARAMETER;
1951 }
1952
1953 CopyMem (&Expression->Result, Value, sizeof (EFI_HII_VALUE));
1954
1955 return EFI_SUCCESS;
1956 }