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