]> git.proxmox.com Git - mirror_edk2.git/blob - MdeModulePkg/Universal/SetupBrowserDxe/Expression.c
Remove SafeFreePool from MemoryAllocationLib as this API's name is misleading. Its...
[mirror_edk2.git] / MdeModulePkg / Universal / SetupBrowserDxe / Expression.c
1 /** @file
2 Utility functions for expression evaluation.
3
4 Copyright (c) 2007, Intel Corporation
5 All rights reserved. This program and the accompanying materials
6 are licensed and made available under the terms and conditions of the BSD License
7 which accompanies this distribution. The full text of the license may be found at
8 http://opensource.org/licenses/bsd-license.php
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 gBS->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 return Question;
425 }
426
427 Link = GetNextNode (&FormSet->FormListHead, Link);
428 }
429
430 return NULL;
431 }
432
433
434 /**
435 Get Expression given its RuleId.
436
437 @param Form The form which contains this Expression.
438 @param RuleId Id of this Expression.
439
440 @retval Pointer The Expression.
441 @retval NULL Specified Expression not found in the form.
442
443 **/
444 FORM_EXPRESSION *
445 RuleIdToExpression (
446 IN FORM_BROWSER_FORM *Form,
447 IN UINT8 RuleId
448 )
449 {
450 LIST_ENTRY *Link;
451 FORM_EXPRESSION *Expression;
452
453 Link = GetFirstNode (&Form->ExpressionListHead);
454 while (!IsNull (&Form->ExpressionListHead, Link)) {
455 Expression = FORM_EXPRESSION_FROM_LINK (Link);
456
457 if (Expression->Type == EFI_HII_EXPRESSION_RULE && Expression->RuleId == RuleId) {
458 return Expression;
459 }
460
461 Link = GetNextNode (&Form->ExpressionListHead, Link);
462 }
463
464 return NULL;
465 }
466
467
468 /**
469 Locate the Unicode Collation Protocol interface for later use.
470
471 @retval EFI_SUCCESS Protocol interface initialize success.
472 @retval Other Protocol interface initialize failed.
473
474 **/
475 EFI_STATUS
476 InitializeUnicodeCollationProtocol (
477 VOID
478 )
479 {
480 EFI_STATUS Status;
481
482 if (mUnicodeCollation != NULL) {
483 return EFI_SUCCESS;
484 }
485
486 //
487 // BUGBUG: Proper impelmentation is to locate all Unicode Collation Protocol
488 // instances first and then select one which support English language.
489 // Current implementation just pick the first instance.
490 //
491 Status = gBS->LocateProtocol (
492 &gEfiUnicodeCollation2ProtocolGuid,
493 NULL,
494 (VOID **) &mUnicodeCollation
495 );
496 return Status;
497 }
498
499 /**
500 Convert the input Unicode character to upper.
501
502 @param String Th Unicode character to be converted.
503
504 **/
505 VOID
506 IfrStrToUpper (
507 CHAR16 *String
508 )
509 {
510 while (*String != 0) {
511 if ((*String >= 'a') && (*String <= 'z')) {
512 *String = (UINT16) ((*String) & ((UINT16) ~0x20));
513 }
514 String++;
515 }
516 }
517
518
519 /**
520 Evaluate opcode EFI_IFR_TO_STRING.
521
522 @param FormSet Formset which contains this opcode.
523 @param Format String format in EFI_IFR_TO_STRING.
524 @param Result Evaluation result for this opcode.
525
526 @retval EFI_SUCCESS Opcode evaluation success.
527 @retval Other Opcode evaluation failed.
528
529 **/
530 EFI_STATUS
531 IfrToString (
532 IN FORM_BROWSER_FORMSET *FormSet,
533 IN UINT8 Format,
534 OUT EFI_HII_VALUE *Result
535 )
536 {
537 EFI_STATUS Status;
538 EFI_HII_VALUE Value;
539 CHAR16 *String;
540 CHAR16 *PrintFormat;
541 CHAR16 Buffer[MAXIMUM_VALUE_CHARACTERS];
542 UINTN BufferSize;
543
544 Status = PopExpression (&Value);
545 if (EFI_ERROR (Status)) {
546 return Status;
547 }
548
549 switch (Value.Type) {
550 case EFI_IFR_TYPE_NUM_SIZE_8:
551 case EFI_IFR_TYPE_NUM_SIZE_16:
552 case EFI_IFR_TYPE_NUM_SIZE_32:
553 case EFI_IFR_TYPE_NUM_SIZE_64:
554 BufferSize = MAXIMUM_VALUE_CHARACTERS * sizeof (CHAR16);
555 switch (Format) {
556 case EFI_IFR_STRING_UNSIGNED_DEC:
557 case EFI_IFR_STRING_SIGNED_DEC:
558 PrintFormat = L"%ld";
559 break;
560
561 case EFI_IFR_STRING_LOWERCASE_HEX:
562 PrintFormat = L"%lx";
563 break;
564
565 case EFI_IFR_STRING_UPPERCASE_HEX:
566 PrintFormat = L"%lX";
567 break;
568
569 default:
570 return EFI_UNSUPPORTED;
571 }
572 UnicodeSPrint (Buffer, BufferSize, PrintFormat, Value.Value.u64);
573 String = Buffer;
574 break;
575
576 case EFI_IFR_TYPE_STRING:
577 CopyMem (Result, &Value, sizeof (EFI_HII_VALUE));
578 return EFI_SUCCESS;
579
580 case EFI_IFR_TYPE_BOOLEAN:
581 String = (Value.Value.b) ? L"True" : L"False";
582 break;
583
584 default:
585 return EFI_UNSUPPORTED;
586 }
587
588 Result->Type = EFI_IFR_TYPE_STRING;
589 Result->Value.string = NewString (String, FormSet->HiiHandle);
590 return EFI_SUCCESS;
591 }
592
593
594 /**
595 Evaluate opcode EFI_IFR_TO_UINT.
596
597 @param FormSet Formset which contains this opcode.
598 @param Result Evaluation result for this opcode.
599
600 @retval EFI_SUCCESS Opcode evaluation success.
601 @retval Other Opcode evaluation failed.
602
603 **/
604 EFI_STATUS
605 IfrToUint (
606 IN FORM_BROWSER_FORMSET *FormSet,
607 OUT EFI_HII_VALUE *Result
608 )
609 {
610 EFI_STATUS Status;
611 EFI_HII_VALUE Value;
612 CHAR16 *String;
613 CHAR16 *StringPtr;
614 UINTN BufferSize;
615
616 Status = PopExpression (&Value);
617 if (EFI_ERROR (Status)) {
618 return Status;
619 }
620
621 if (Value.Type >= EFI_IFR_TYPE_OTHER) {
622 return EFI_UNSUPPORTED;
623 }
624
625 Status = EFI_SUCCESS;
626 if (Value.Type == EFI_IFR_TYPE_STRING) {
627 String = GetToken (Value.Value.string, FormSet->HiiHandle);
628 if (String == NULL) {
629 return EFI_NOT_FOUND;
630 }
631
632 IfrStrToUpper (String);
633 StringPtr = StrStr (String, L"0X");
634 if (StringPtr != NULL) {
635 //
636 // Hex string
637 //
638 BufferSize = sizeof (UINT64);
639 Status = HexStringToBuf ((UINT8 *) &Result->Value.u64, &BufferSize, StringPtr + 2, NULL);
640 } else {
641 //
642 // BUGBUG: Need handle decimal string
643 //
644 }
645 gBS->FreePool (String);
646 } else {
647 CopyMem (Result, &Value, sizeof (EFI_HII_VALUE));
648 }
649
650 Result->Type = EFI_IFR_TYPE_NUM_SIZE_64;
651 return Status;
652 }
653
654
655 /**
656 Evaluate opcode EFI_IFR_CATENATE.
657
658 @param FormSet Formset which contains this opcode.
659 @param Result Evaluation result for this opcode.
660
661 @retval EFI_SUCCESS Opcode evaluation success.
662 @retval Other Opcode evaluation failed.
663
664 **/
665 EFI_STATUS
666 IfrCatenate (
667 IN FORM_BROWSER_FORMSET *FormSet,
668 OUT EFI_HII_VALUE *Result
669 )
670 {
671 EFI_STATUS Status;
672 EFI_HII_VALUE Value;
673 CHAR16 *String[2];
674 UINTN Index;
675 CHAR16 *StringPtr;
676 UINTN Size;
677
678 //
679 // String[0] - The second string
680 // String[1] - The first string
681 //
682 String[0] = NULL;
683 String[1] = NULL;
684 StringPtr = NULL;
685 Status = EFI_SUCCESS;
686
687 for (Index = 0; Index < 2; Index++) {
688 Status = PopExpression (&Value);
689 if (EFI_ERROR (Status)) {
690 goto Done;
691 }
692
693 if (Value.Type != EFI_IFR_TYPE_STRING) {
694 Status = EFI_UNSUPPORTED;
695 goto Done;
696 }
697
698 String[Index] = GetToken (Value.Value.string, FormSet->HiiHandle);
699 if (String== NULL) {
700 Status = EFI_NOT_FOUND;
701 goto Done;
702 }
703 }
704
705 Size = StrSize (String[0]);
706 StringPtr= AllocatePool (StrSize (String[1]) + Size);
707 ASSERT (StringPtr != NULL);
708 StrCpy (StringPtr, String[1]);
709 StrCat (StringPtr, String[0]);
710
711 Result->Type = EFI_IFR_TYPE_STRING;
712 Result->Value.string = NewString (StringPtr, FormSet->HiiHandle);
713
714 Done:
715 if (String[0] != NULL) {
716 FreePool (String[0]);
717 }
718 if (String[1] != NULL) {
719 FreePool (String[1]);
720 }
721 if (StringPtr != NULL) {
722 FreePool (StringPtr);
723 }
724
725 return Status;
726 }
727
728
729 /**
730 Evaluate opcode EFI_IFR_MATCH.
731
732 @param FormSet Formset which contains this opcode.
733 @param Result Evaluation result for this opcode.
734
735 @retval EFI_SUCCESS Opcode evaluation success.
736 @retval Other Opcode evaluation failed.
737
738 **/
739 EFI_STATUS
740 IfrMatch (
741 IN FORM_BROWSER_FORMSET *FormSet,
742 OUT EFI_HII_VALUE *Result
743 )
744 {
745 EFI_STATUS Status;
746 EFI_HII_VALUE Value;
747 CHAR16 *String[2];
748 UINTN Index;
749
750 //
751 // String[0] - The string to search
752 // String[1] - pattern
753 //
754 String[0] = NULL;
755 String[1] = NULL;
756 Status = EFI_SUCCESS;
757 for (Index = 0; Index < 2; Index++) {
758 Status = PopExpression (&Value);
759 if (EFI_ERROR (Status)) {
760 goto Done;
761 }
762
763 if (Value.Type != EFI_IFR_TYPE_STRING) {
764 Status = EFI_UNSUPPORTED;
765 goto Done;
766 }
767
768 String[Index] = GetToken (Value.Value.string, FormSet->HiiHandle);
769 if (String== NULL) {
770 Status = EFI_NOT_FOUND;
771 goto Done;
772 }
773 }
774
775 Result->Type = EFI_IFR_TYPE_BOOLEAN;
776 Result->Value.b = mUnicodeCollation->MetaiMatch (mUnicodeCollation, String[0], String[1]);
777
778 Done:
779 if (String[0] != NULL) {
780 FreePool (String[0]);
781 }
782 if (String[1] != NULL) {
783 FreePool (String[1]);
784 }
785
786 return Status;
787 }
788
789
790 /**
791 Evaluate opcode EFI_IFR_FIND.
792
793 @param FormSet Formset which contains this opcode.
794 @param Format Case sensitive or insensitive.
795 @param Result Evaluation result for this opcode.
796
797 @retval EFI_SUCCESS Opcode evaluation success.
798 @retval Other Opcode evaluation failed.
799
800 **/
801 EFI_STATUS
802 IfrFind (
803 IN FORM_BROWSER_FORMSET *FormSet,
804 IN UINT8 Format,
805 OUT EFI_HII_VALUE *Result
806 )
807 {
808 EFI_STATUS Status;
809 EFI_HII_VALUE Value;
810 CHAR16 *String[2];
811 UINTN Base;
812 CHAR16 *StringPtr;
813 UINTN Index;
814
815 if (Format > EFI_IFR_FF_CASE_INSENSITIVE) {
816 return EFI_UNSUPPORTED;
817 }
818
819 Status = PopExpression (&Value);
820 if (EFI_ERROR (Status)) {
821 return Status;
822 }
823 if (Value.Type > EFI_IFR_TYPE_NUM_SIZE_64) {
824 return EFI_UNSUPPORTED;
825 }
826 Base = (UINTN) Value.Value.u64;
827
828 //
829 // String[0] - sub-string
830 // String[1] - The string to search
831 //
832 String[0] = NULL;
833 String[1] = NULL;
834 for (Index = 0; Index < 2; Index++) {
835 Status = PopExpression (&Value);
836 if (EFI_ERROR (Status)) {
837 goto Done;
838 }
839
840 if (Value.Type != EFI_IFR_TYPE_STRING) {
841 Status = EFI_UNSUPPORTED;
842 goto Done;
843 }
844
845 String[Index] = GetToken (Value.Value.string, FormSet->HiiHandle);
846 if (String== NULL) {
847 Status = EFI_NOT_FOUND;
848 goto Done;
849 }
850
851 if (Format == EFI_IFR_FF_CASE_INSENSITIVE) {
852 //
853 // Case insensitive, convert both string to upper case
854 //
855 IfrStrToUpper (String[Index]);
856 }
857 }
858
859 Result->Type = EFI_IFR_TYPE_NUM_SIZE_64;
860 if (Base >= StrLen (String[1])) {
861 Result->Value.u64 = 0xFFFFFFFFFFFFFFFFULL;
862 } else {
863 StringPtr = StrStr (String[1] + Base, String[0]);
864 Result->Value.u64 = (StringPtr == NULL) ? 0xFFFFFFFFFFFFFFFFULL : (StringPtr - String[1]);
865 }
866
867 Done:
868 if (String[0] != NULL) {
869 FreePool (String[0]);
870 }
871 if (String[1] != NULL) {
872 FreePool (String[1]);
873 }
874
875 return Status;
876 }
877
878
879 /**
880 Evaluate opcode EFI_IFR_MID.
881
882 @param FormSet Formset which contains this opcode.
883 @param Result Evaluation result for this opcode.
884
885 @retval EFI_SUCCESS Opcode evaluation success.
886 @retval Other Opcode evaluation failed.
887
888 **/
889 EFI_STATUS
890 IfrMid (
891 IN FORM_BROWSER_FORMSET *FormSet,
892 OUT EFI_HII_VALUE *Result
893 )
894 {
895 EFI_STATUS Status;
896 EFI_HII_VALUE Value;
897 CHAR16 *String;
898 UINTN Base;
899 UINTN Length;
900 CHAR16 *SubString;
901
902 Status = PopExpression (&Value);
903 if (EFI_ERROR (Status)) {
904 return Status;
905 }
906 if (Value.Type > EFI_IFR_TYPE_NUM_SIZE_64) {
907 return EFI_UNSUPPORTED;
908 }
909 Length = (UINTN) Value.Value.u64;
910
911 Status = PopExpression (&Value);
912 if (EFI_ERROR (Status)) {
913 return Status;
914 }
915 if (Value.Type > EFI_IFR_TYPE_NUM_SIZE_64) {
916 return EFI_UNSUPPORTED;
917 }
918 Base = (UINTN) Value.Value.u64;
919
920 Status = PopExpression (&Value);
921 if (EFI_ERROR (Status)) {
922 return Status;
923 }
924 if (Value.Type != EFI_IFR_TYPE_STRING) {
925 return EFI_UNSUPPORTED;
926 }
927 String = GetToken (Value.Value.string, FormSet->HiiHandle);
928 if (String == NULL) {
929 return EFI_NOT_FOUND;
930 }
931
932 if (Length == 0 || Base >= StrLen (String)) {
933 SubString = gEmptyString;
934 } else {
935 SubString = String + Base;
936 if ((Base + Length) < StrLen (String)) {
937 SubString[Length] = L'\0';
938 }
939 }
940
941 Result->Type = EFI_IFR_TYPE_STRING;
942 Result->Value.string = NewString (SubString, FormSet->HiiHandle);
943
944 gBS->FreePool (String);
945
946 return Status;
947 }
948
949
950 /**
951 Evaluate opcode EFI_IFR_TOKEN.
952
953 @param FormSet Formset which contains this opcode.
954 @param Result Evaluation result for this opcode.
955
956 @retval EFI_SUCCESS Opcode evaluation success.
957 @retval Other Opcode evaluation failed.
958
959 **/
960 EFI_STATUS
961 IfrToken (
962 IN FORM_BROWSER_FORMSET *FormSet,
963 OUT EFI_HII_VALUE *Result
964 )
965 {
966 EFI_STATUS Status;
967 EFI_HII_VALUE Value;
968 CHAR16 *String[2];
969 UINTN Count;
970 CHAR16 *Delimiter;
971 CHAR16 *SubString;
972 CHAR16 *StringPtr;
973 UINTN Index;
974
975 Status = PopExpression (&Value);
976 if (EFI_ERROR (Status)) {
977 return Status;
978 }
979 if (Value.Type > EFI_IFR_TYPE_NUM_SIZE_64) {
980 return EFI_UNSUPPORTED;
981 }
982 Count = (UINTN) Value.Value.u64;
983
984 //
985 // String[0] - Delimiter
986 // String[1] - The string to search
987 //
988 String[0] = NULL;
989 String[1] = NULL;
990 for (Index = 0; Index < 2; Index++) {
991 Status = PopExpression (&Value);
992 if (EFI_ERROR (Status)) {
993 goto Done;
994 }
995
996 if (Value.Type != EFI_IFR_TYPE_STRING) {
997 Status = EFI_UNSUPPORTED;
998 goto Done;
999 }
1000
1001 String[Index] = GetToken (Value.Value.string, FormSet->HiiHandle);
1002 if (String== NULL) {
1003 Status = EFI_NOT_FOUND;
1004 goto Done;
1005 }
1006 }
1007
1008 Delimiter = String[0];
1009 SubString = String[1];
1010 while (Count > 0) {
1011 SubString = StrStr (SubString, Delimiter);
1012 if (SubString != NULL) {
1013 //
1014 // Skip over the delimiter
1015 //
1016 SubString = SubString + StrLen (Delimiter);
1017 } else {
1018 break;
1019 }
1020 Count--;
1021 }
1022
1023 if (SubString == NULL) {
1024 //
1025 // nth delimited sub-string not found, push an empty string
1026 //
1027 SubString = gEmptyString;
1028 } else {
1029 //
1030 // Put a NULL terminator for nth delimited sub-string
1031 //
1032 StringPtr = StrStr (SubString, Delimiter);
1033 if (StringPtr != NULL) {
1034 *StringPtr = L'\0';
1035 }
1036 }
1037
1038 Result->Type = EFI_IFR_TYPE_STRING;
1039 Result->Value.string = NewString (SubString, FormSet->HiiHandle);
1040
1041 Done:
1042 if (String[0] != NULL) {
1043 FreePool (String[0]);
1044 }
1045 if (String[1] != NULL) {
1046 FreePool (String[1]);
1047 }
1048
1049 return Status;
1050 }
1051
1052
1053 /**
1054 Evaluate opcode EFI_IFR_SPAN.
1055
1056 @param FormSet Formset which contains this opcode.
1057 @param Flags FIRST_MATCHING or FIRST_NON_MATCHING.
1058 @param Result Evaluation result for this opcode.
1059
1060 @retval EFI_SUCCESS Opcode evaluation success.
1061 @retval Other Opcode evaluation failed.
1062
1063 **/
1064 EFI_STATUS
1065 IfrSpan (
1066 IN FORM_BROWSER_FORMSET *FormSet,
1067 IN UINT8 Flags,
1068 OUT EFI_HII_VALUE *Result
1069 )
1070 {
1071 EFI_STATUS Status;
1072 EFI_HII_VALUE Value;
1073 CHAR16 *String[2];
1074 CHAR16 *Charset;
1075 UINTN Base;
1076 UINTN Index;
1077 CHAR16 *StringPtr;
1078 BOOLEAN Found;
1079
1080 Status = PopExpression (&Value);
1081 if (EFI_ERROR (Status)) {
1082 return Status;
1083 }
1084 if (Value.Type > EFI_IFR_TYPE_NUM_SIZE_64) {
1085 return EFI_UNSUPPORTED;
1086 }
1087 Base = (UINTN) Value.Value.u64;
1088
1089 //
1090 // String[0] - Charset
1091 // String[1] - The string to search
1092 //
1093 String[0] = NULL;
1094 String[1] = NULL;
1095 for (Index = 0; Index < 2; Index++) {
1096 Status = PopExpression (&Value);
1097 if (EFI_ERROR (Status)) {
1098 goto Done;
1099 }
1100
1101 if (Value.Type != EFI_IFR_TYPE_STRING) {
1102 Status = EFI_UNSUPPORTED;
1103 goto Done;
1104 }
1105
1106 String[Index] = GetToken (Value.Value.string, FormSet->HiiHandle);
1107 if (String== NULL) {
1108 Status = EFI_NOT_FOUND;
1109 goto Done;
1110 }
1111 }
1112
1113 if (Base >= StrLen (String[1])) {
1114 Status = EFI_UNSUPPORTED;
1115 goto Done;
1116 }
1117
1118 Found = FALSE;
1119 StringPtr = String[1] + Base;
1120 Charset = String[0];
1121 while (*StringPtr != 0 && !Found) {
1122 Index = 0;
1123 while (Charset[Index] != 0) {
1124 if (*StringPtr >= Charset[Index] && *StringPtr <= Charset[Index + 1]) {
1125 if (Flags == EFI_IFR_FLAGS_FIRST_MATCHING) {
1126 Found = TRUE;
1127 break;
1128 }
1129 } else {
1130 if (Flags == EFI_IFR_FLAGS_FIRST_NON_MATCHING) {
1131 Found = TRUE;
1132 break;
1133 }
1134 }
1135 //
1136 // Skip characters pair representing low-end of a range and high-end of a range
1137 //
1138 Index += 2;
1139 }
1140
1141 if (!Found) {
1142 StringPtr++;
1143 }
1144 }
1145
1146 Result->Type = EFI_IFR_TYPE_NUM_SIZE_64;
1147 Result->Value.u64 = StringPtr - String[1];
1148
1149 Done:
1150 if (String[0] != NULL) {
1151 FreePool (String[0]);
1152 }
1153 if (String[1] != NULL) {
1154 FreePool (String[1]);
1155 }
1156
1157 return Status;
1158 }
1159
1160
1161 /**
1162 Zero extend integer/boolean/date/time to UINT64 for comparing.
1163
1164 @param Value HII Value to be converted.
1165
1166 **/
1167 VOID
1168 ExtendValueToU64 (
1169 IN EFI_HII_VALUE *Value
1170 )
1171 {
1172 UINT64 Temp;
1173
1174 Temp = 0;
1175 switch (Value->Type) {
1176 case EFI_IFR_TYPE_NUM_SIZE_8:
1177 Temp = Value->Value.u8;
1178 break;
1179
1180 case EFI_IFR_TYPE_NUM_SIZE_16:
1181 Temp = Value->Value.u16;
1182 break;
1183
1184 case EFI_IFR_TYPE_NUM_SIZE_32:
1185 Temp = Value->Value.u32;
1186 break;
1187
1188 case EFI_IFR_TYPE_BOOLEAN:
1189 Temp = Value->Value.b;
1190 break;
1191
1192 case EFI_IFR_TYPE_TIME:
1193 Temp = Value->Value.u32 & 0xffffff;
1194 break;
1195
1196 case EFI_IFR_TYPE_DATE:
1197 Temp = Value->Value.u32;
1198 break;
1199
1200 default:
1201 return;
1202 }
1203
1204 Value->Value.u64 = Temp;
1205 }
1206
1207
1208 /**
1209 Compare two Hii value.
1210
1211 @param Value1 Expression value to compare on left-hand.
1212 @param Value2 Expression value to compare on right-hand.
1213 @param HiiHandle Only required for string compare.
1214
1215 @retval EFI_INVALID_PARAMETER Could not perform comparation on two values.
1216 @retval 0 Two operators equeal.
1217 @return Positive value if Value1 is greater than Value2.
1218 @retval Negative value if Value1 is less than Value2.
1219
1220 **/
1221 INTN
1222 CompareHiiValue (
1223 IN EFI_HII_VALUE *Value1,
1224 IN EFI_HII_VALUE *Value2,
1225 IN EFI_HII_HANDLE HiiHandle OPTIONAL
1226 )
1227 {
1228 INTN Result;
1229 INT64 Temp64;
1230 CHAR16 *Str1;
1231 CHAR16 *Str2;
1232
1233 if (Value1->Type >= EFI_IFR_TYPE_OTHER || Value2->Type >= EFI_IFR_TYPE_OTHER ) {
1234 return EFI_INVALID_PARAMETER;
1235 }
1236
1237 if (Value1->Type == EFI_IFR_TYPE_STRING || Value2->Type == EFI_IFR_TYPE_STRING ) {
1238 if (Value1->Type != Value2->Type) {
1239 //
1240 // Both Operator should be type of String
1241 //
1242 return EFI_INVALID_PARAMETER;
1243 }
1244
1245 if (Value1->Value.string == 0 || Value2->Value.string == 0) {
1246 //
1247 // StringId 0 is reserved
1248 //
1249 return EFI_INVALID_PARAMETER;
1250 }
1251
1252 if (Value1->Value.string == Value2->Value.string) {
1253 return 0;
1254 }
1255
1256 Str1 = GetToken (Value1->Value.string, HiiHandle);
1257 if (Str1 == NULL) {
1258 //
1259 // String not found
1260 //
1261 return EFI_INVALID_PARAMETER;
1262 }
1263
1264 Str2 = GetToken (Value2->Value.string, HiiHandle);
1265 if (Str2 == NULL) {
1266 gBS->FreePool (Str1);
1267 return EFI_INVALID_PARAMETER;
1268 }
1269
1270 Result = StrCmp (Str1, Str2);
1271
1272 gBS->FreePool (Str1);
1273 gBS->FreePool (Str2);
1274
1275 return Result;
1276 }
1277
1278 //
1279 // Take remain types(integer, boolean, date/time) as integer
1280 //
1281 Temp64 = (INT64) (Value1->Value.u64 - Value2->Value.u64);
1282 if (Temp64 > 0) {
1283 Result = 1;
1284 } else if (Temp64 < 0) {
1285 Result = -1;
1286 } else {
1287 Result = 0;
1288 }
1289
1290 return Result;
1291 }
1292
1293
1294 /**
1295 Evaluate the result of a HII expression
1296
1297 @param FormSet FormSet associated with this expression.
1298 @param Form Form associated with this expression.
1299 @param Expression Expression to be evaluated.
1300
1301 @retval EFI_SUCCESS The expression evaluated successfuly
1302 @retval EFI_NOT_FOUND The Question which referenced by a QuestionId
1303 could not be found.
1304 @retval EFI_OUT_OF_RESOURCES There is not enough system memory to grow the
1305 stack.
1306 @retval EFI_ACCESS_DENIED The pop operation underflowed the stack
1307 @retval EFI_INVALID_PARAMETER Syntax error with the Expression
1308
1309 **/
1310 EFI_STATUS
1311 EvaluateExpression (
1312 IN FORM_BROWSER_FORMSET *FormSet,
1313 IN FORM_BROWSER_FORM *Form,
1314 IN OUT FORM_EXPRESSION *Expression
1315 )
1316 {
1317 EFI_STATUS Status;
1318 LIST_ENTRY *Link;
1319 EXPRESSION_OPCODE *OpCode;
1320 FORM_BROWSER_STATEMENT *Question;
1321 FORM_BROWSER_STATEMENT *Question2;
1322 UINT16 Index;
1323 EFI_HII_VALUE Data1;
1324 EFI_HII_VALUE Data2;
1325 EFI_HII_VALUE Data3;
1326 FORM_EXPRESSION *RuleExpression;
1327 EFI_HII_VALUE *Value;
1328 INTN Result;
1329 CHAR16 *StrPtr;
1330 UINT32 TempValue;
1331
1332 //
1333 // Always reset the stack before evaluating an Expression
1334 //
1335 ResetExpressionStack ();
1336
1337 Expression->Result.Type = EFI_IFR_TYPE_OTHER;
1338
1339 Link = GetFirstNode (&Expression->OpCodeListHead);
1340 while (!IsNull (&Expression->OpCodeListHead, Link)) {
1341 OpCode = EXPRESSION_OPCODE_FROM_LINK (Link);
1342
1343 Link = GetNextNode (&Expression->OpCodeListHead, Link);
1344
1345 ZeroMem (&Data1, sizeof (EFI_HII_VALUE));
1346 ZeroMem (&Data2, sizeof (EFI_HII_VALUE));
1347 ZeroMem (&Data3, sizeof (EFI_HII_VALUE));
1348
1349 Value = &Data3;
1350 Value->Type = EFI_IFR_TYPE_BOOLEAN;
1351 Status = EFI_SUCCESS;
1352
1353 switch (OpCode->Operand) {
1354 //
1355 // Built-in functions
1356 //
1357 case EFI_IFR_EQ_ID_VAL_OP:
1358 Question = IdToQuestion (FormSet, Form, OpCode->QuestionId);
1359 if (Question == NULL) {
1360 return EFI_NOT_FOUND;
1361 }
1362
1363 Result = CompareHiiValue (&Question->HiiValue, &OpCode->Value, NULL);
1364 if (Result == EFI_INVALID_PARAMETER) {
1365 return EFI_INVALID_PARAMETER;
1366 }
1367 Value->Value.b = (BOOLEAN) ((Result == 0) ? TRUE : FALSE);
1368 break;
1369
1370 case EFI_IFR_EQ_ID_ID_OP:
1371 Question = IdToQuestion (FormSet, Form, OpCode->QuestionId);
1372 if (Question == NULL) {
1373 return EFI_NOT_FOUND;
1374 }
1375
1376 Question2 = IdToQuestion (FormSet, Form, OpCode->QuestionId2);
1377 if (Question2 == NULL) {
1378 return EFI_NOT_FOUND;
1379 }
1380
1381 Result = CompareHiiValue (&Question->HiiValue, &Question2->HiiValue, FormSet->HiiHandle);
1382 if (Result == EFI_INVALID_PARAMETER) {
1383 return EFI_INVALID_PARAMETER;
1384 }
1385 Value->Value.b = (BOOLEAN) ((Result == 0) ? TRUE : FALSE);
1386 break;
1387
1388 case EFI_IFR_EQ_ID_LIST_OP:
1389 Question = IdToQuestion (FormSet, Form, OpCode->QuestionId);
1390 if (Question == NULL) {
1391 return EFI_NOT_FOUND;
1392 }
1393
1394 Value->Value.b = FALSE;
1395 for (Index =0; Index < OpCode->ListLength; Index++) {
1396 if (Question->HiiValue.Value.u16 == OpCode->ValueList[Index]) {
1397 Value->Value.b = TRUE;
1398 break;
1399 }
1400 }
1401 break;
1402
1403 case EFI_IFR_DUP_OP:
1404 Status = PopExpression (Value);
1405 if (EFI_ERROR (Status)) {
1406 return Status;
1407 }
1408
1409 Status = PushExpression (Value);
1410 break;
1411
1412 case EFI_IFR_QUESTION_REF1_OP:
1413 case EFI_IFR_THIS_OP:
1414 Question = IdToQuestion (FormSet, Form, OpCode->QuestionId);
1415 if (Question == NULL) {
1416 return EFI_NOT_FOUND;
1417 }
1418
1419 Value = &Question->HiiValue;
1420 break;
1421
1422 case EFI_IFR_QUESTION_REF3_OP:
1423 if (OpCode->DevicePath == 0) {
1424 //
1425 // EFI_IFR_QUESTION_REF3
1426 // Pop an expression from the expression stack
1427 //
1428 Status = PopExpression (Value);
1429 if (EFI_ERROR (Status)) {
1430 return Status;
1431 }
1432
1433 //
1434 // Validate the expression value
1435 //
1436 if ((Value->Type > EFI_IFR_TYPE_NUM_SIZE_64) || (Value->Value.u64 > 0xffff)) {
1437 return EFI_NOT_FOUND;
1438 }
1439
1440 Question = IdToQuestion (FormSet, Form, Value->Value.u16);
1441 if (Question == NULL) {
1442 return EFI_NOT_FOUND;
1443 }
1444
1445 //
1446 // push the questions' value on to the expression stack
1447 //
1448 Value = &Question->HiiValue;
1449 } else {
1450 //
1451 // BUGBUG: push 0 for EFI_IFR_QUESTION_REF3_2 and EFI_IFR_QUESTION_REF3_3,
1452 // since it is impractical to evaluate the value of a Question in another
1453 // Hii Package list.
1454 //
1455 ZeroMem (Value, sizeof (EFI_HII_VALUE));
1456 }
1457 break;
1458
1459 case EFI_IFR_RULE_REF_OP:
1460 //
1461 // Find expression for this rule
1462 //
1463 RuleExpression = RuleIdToExpression (Form, OpCode->RuleId);
1464 if (RuleExpression == NULL) {
1465 return EFI_NOT_FOUND;
1466 }
1467
1468 //
1469 // Evaluate this rule expression
1470 //
1471 Status = EvaluateExpression (FormSet, Form, RuleExpression);
1472 if (EFI_ERROR (Status)) {
1473 return Status;
1474 }
1475
1476 Value = &RuleExpression->Result;
1477 break;
1478
1479 case EFI_IFR_STRING_REF1_OP:
1480 Value->Type = EFI_IFR_TYPE_STRING;
1481 Value->Value.string = OpCode->Value.Value.string;
1482 break;
1483
1484 //
1485 // Constant
1486 //
1487 case EFI_IFR_TRUE_OP:
1488 case EFI_IFR_FALSE_OP:
1489 case EFI_IFR_ONE_OP:
1490 case EFI_IFR_ONES_OP:
1491 case EFI_IFR_UINT8_OP:
1492 case EFI_IFR_UINT16_OP:
1493 case EFI_IFR_UINT32_OP:
1494 case EFI_IFR_UINT64_OP:
1495 case EFI_IFR_UNDEFINED_OP:
1496 case EFI_IFR_VERSION_OP:
1497 case EFI_IFR_ZERO_OP:
1498 Value = &OpCode->Value;
1499 break;
1500
1501 //
1502 // unary-op
1503 //
1504 case EFI_IFR_LENGTH_OP:
1505 Status = PopExpression (Value);
1506 if (EFI_ERROR (Status)) {
1507 return Status;
1508 }
1509 if (Value->Type != EFI_IFR_TYPE_STRING) {
1510 return EFI_INVALID_PARAMETER;
1511 }
1512
1513 StrPtr = GetToken (Value->Value.string, FormSet->HiiHandle);
1514 if (StrPtr == NULL) {
1515 return EFI_INVALID_PARAMETER;
1516 }
1517
1518 Value->Type = EFI_IFR_TYPE_NUM_SIZE_64;
1519 Value->Value.u64 = StrLen (StrPtr);
1520 gBS->FreePool (StrPtr);
1521 break;
1522
1523 case EFI_IFR_NOT_OP:
1524 Status = PopExpression (Value);
1525 if (EFI_ERROR (Status)) {
1526 return Status;
1527 }
1528 if (Value->Type != EFI_IFR_TYPE_BOOLEAN) {
1529 return EFI_INVALID_PARAMETER;
1530 }
1531 Value->Value.b = (BOOLEAN) (!Value->Value.b);
1532 break;
1533
1534 case EFI_IFR_QUESTION_REF2_OP:
1535 //
1536 // Pop an expression from the expression stack
1537 //
1538 Status = PopExpression (Value);
1539 if (EFI_ERROR (Status)) {
1540 return Status;
1541 }
1542
1543 //
1544 // Validate the expression value
1545 //
1546 if ((Value->Type > EFI_IFR_TYPE_NUM_SIZE_64) || (Value->Value.u64 > 0xffff)) {
1547 return EFI_NOT_FOUND;
1548 }
1549
1550 Question = IdToQuestion (FormSet, Form, Value->Value.u16);
1551 if (Question == NULL) {
1552 return EFI_NOT_FOUND;
1553 }
1554
1555 Value = &Question->HiiValue;
1556 break;
1557
1558 case EFI_IFR_STRING_REF2_OP:
1559 //
1560 // Pop an expression from the expression stack
1561 //
1562 Status = PopExpression (Value);
1563 if (EFI_ERROR (Status)) {
1564 return Status;
1565 }
1566
1567 //
1568 // Validate the expression value
1569 //
1570 if ((Value->Type > EFI_IFR_TYPE_NUM_SIZE_64) || (Value->Value.u64 > 0xffff)) {
1571 return EFI_NOT_FOUND;
1572 }
1573
1574 Value->Type = EFI_IFR_TYPE_STRING;
1575 StrPtr = GetToken (Value->Value.u16, FormSet->HiiHandle);
1576 if (StrPtr == NULL) {
1577 //
1578 // If String not exit, push an empty string
1579 //
1580 Value->Value.string = NewString (gEmptyString, FormSet->HiiHandle);
1581 } else {
1582 Index = (UINT16) Value->Value.u64;
1583 Value->Value.string = Index;
1584 gBS->FreePool (StrPtr);
1585 }
1586 break;
1587
1588 case EFI_IFR_TO_BOOLEAN_OP:
1589 //
1590 // Pop an expression from the expression stack
1591 //
1592 Status = PopExpression (Value);
1593 if (EFI_ERROR (Status)) {
1594 return Status;
1595 }
1596
1597 //
1598 // Convert an expression to a Boolean
1599 //
1600 if (Value->Type <= EFI_IFR_TYPE_DATE) {
1601 //
1602 // When converting from an unsigned integer, zero will be converted to
1603 // FALSE and any other value will be converted to TRUE.
1604 //
1605 Value->Value.b = (BOOLEAN) ((Value->Value.u64) ? TRUE : FALSE);
1606
1607 Value->Type = EFI_IFR_TYPE_BOOLEAN;
1608 } else if (Value->Type == EFI_IFR_TYPE_STRING) {
1609 //
1610 // When converting from a string, if case-insensitive compare
1611 // with "true" is True, then push True. If a case-insensitive compare
1612 // with "false" is True, then push False.
1613 //
1614 StrPtr = GetToken (Value->Value.string, FormSet->HiiHandle);
1615 if (StrPtr == NULL) {
1616 return EFI_INVALID_PARAMETER;
1617 }
1618
1619 if ((StrCmp (StrPtr, L"true") == 0) || (StrCmp (StrPtr, L"false") == 0)){
1620 Value->Value.b = TRUE;
1621 } else {
1622 Value->Value.b = FALSE;
1623 }
1624 gBS->FreePool (StrPtr);
1625 Value->Type = EFI_IFR_TYPE_BOOLEAN;
1626 }
1627 break;
1628
1629 case EFI_IFR_TO_STRING_OP:
1630 Status = IfrToString (FormSet, OpCode->Format, Value);
1631 break;
1632
1633 case EFI_IFR_TO_UINT_OP:
1634 Status = IfrToUint (FormSet, Value);
1635 break;
1636
1637 case EFI_IFR_TO_LOWER_OP:
1638 case EFI_IFR_TO_UPPER_OP:
1639 Status = InitializeUnicodeCollationProtocol ();
1640 if (EFI_ERROR (Status)) {
1641 return Status;
1642 }
1643
1644 Status = PopExpression (Value);
1645 if (EFI_ERROR (Status)) {
1646 return Status;
1647 }
1648
1649 if (Value->Type != EFI_IFR_TYPE_STRING) {
1650 return EFI_UNSUPPORTED;
1651 }
1652
1653 StrPtr = GetToken (Value->Value.string, FormSet->HiiHandle);
1654 if (StrPtr == NULL) {
1655 return EFI_NOT_FOUND;
1656 }
1657
1658 if (OpCode->Operand == EFI_IFR_TO_LOWER_OP) {
1659 mUnicodeCollation->StrLwr (mUnicodeCollation, StrPtr);
1660 } else {
1661 mUnicodeCollation->StrUpr (mUnicodeCollation, StrPtr);
1662 }
1663 Value->Value.string = NewString (StrPtr, FormSet->HiiHandle);
1664 gBS->FreePool (StrPtr);
1665 break;
1666
1667 case EFI_IFR_BITWISE_NOT_OP:
1668 //
1669 // Pop an expression from the expression stack
1670 //
1671 Status = PopExpression (Value);
1672 if (EFI_ERROR (Status)) {
1673 return Status;
1674 }
1675 if (Value->Type > EFI_IFR_TYPE_DATE) {
1676 return EFI_INVALID_PARAMETER;
1677 }
1678
1679 Value->Type = EFI_IFR_TYPE_NUM_SIZE_64;
1680 Value->Value.u64 = ~Value->Value.u64;
1681 break;
1682
1683 //
1684 // binary-op
1685 //
1686 case EFI_IFR_ADD_OP:
1687 case EFI_IFR_SUBTRACT_OP:
1688 case EFI_IFR_MULTIPLY_OP:
1689 case EFI_IFR_DIVIDE_OP:
1690 case EFI_IFR_MODULO_OP:
1691 case EFI_IFR_BITWISE_AND_OP:
1692 case EFI_IFR_BITWISE_OR_OP:
1693 case EFI_IFR_SHIFT_LEFT_OP:
1694 case EFI_IFR_SHIFT_RIGHT_OP:
1695 //
1696 // Pop an expression from the expression stack
1697 //
1698 Status = PopExpression (&Data2);
1699 if (EFI_ERROR (Status)) {
1700 return Status;
1701 }
1702 if (Data2.Type > EFI_IFR_TYPE_DATE) {
1703 return EFI_INVALID_PARAMETER;
1704 }
1705
1706 //
1707 // Pop another expression from the expression stack
1708 //
1709 Status = PopExpression (&Data1);
1710 if (EFI_ERROR (Status)) {
1711 return Status;
1712 }
1713 if (Data1.Type > EFI_IFR_TYPE_DATE) {
1714 return EFI_INVALID_PARAMETER;
1715 }
1716
1717 Value->Type = EFI_IFR_TYPE_NUM_SIZE_64;
1718
1719 switch (OpCode->Operand) {
1720 case EFI_IFR_ADD_OP:
1721 Value->Value.u64 = Data1.Value.u64 + Data2.Value.u64;
1722 break;
1723
1724 case EFI_IFR_SUBTRACT_OP:
1725 Value->Value.u64 = Data1.Value.u64 - Data2.Value.u64;
1726 break;
1727
1728 case EFI_IFR_MULTIPLY_OP:
1729 Value->Value.u64 = MultU64x32 (Data1.Value.u64, (UINT32) Data2.Value.u64);
1730 break;
1731
1732 case EFI_IFR_DIVIDE_OP:
1733 Value->Value.u64 = DivU64x32 (Data1.Value.u64, (UINT32) Data2.Value.u64);
1734 break;
1735
1736 case EFI_IFR_MODULO_OP:
1737 DivU64x32Remainder (Data1.Value.u64, (UINT32) Data2.Value.u64, &TempValue);
1738 Value->Value.u64 = TempValue;
1739 break;
1740
1741 case EFI_IFR_BITWISE_AND_OP:
1742 Value->Value.u64 = Data1.Value.u64 & Data2.Value.u64;
1743 break;
1744
1745 case EFI_IFR_BITWISE_OR_OP:
1746 Value->Value.u64 = Data1.Value.u64 | Data2.Value.u64;
1747 break;
1748
1749 case EFI_IFR_SHIFT_LEFT_OP:
1750 Value->Value.u64 = LShiftU64 (Data1.Value.u64, (UINTN) Data2.Value.u64);
1751 break;
1752
1753 case EFI_IFR_SHIFT_RIGHT_OP:
1754 Value->Value.u64 = RShiftU64 (Data1.Value.u64, (UINTN) Data2.Value.u64);
1755 break;
1756
1757 default:
1758 break;
1759 }
1760 break;
1761
1762 case EFI_IFR_AND_OP:
1763 case EFI_IFR_OR_OP:
1764 //
1765 // Two Boolean operator
1766 //
1767 Status = PopExpression (&Data2);
1768 if (EFI_ERROR (Status)) {
1769 return Status;
1770 }
1771 if (Data2.Type != EFI_IFR_TYPE_BOOLEAN) {
1772 return EFI_INVALID_PARAMETER;
1773 }
1774
1775 //
1776 // Pop another expression from the expression stack
1777 //
1778 Status = PopExpression (&Data1);
1779 if (EFI_ERROR (Status)) {
1780 return Status;
1781 }
1782 if (Data1.Type != EFI_IFR_TYPE_BOOLEAN) {
1783 return EFI_INVALID_PARAMETER;
1784 }
1785
1786 if (OpCode->Operand == EFI_IFR_AND_OP) {
1787 Value->Value.b = (BOOLEAN) (Data1.Value.b && Data2.Value.b);
1788 } else {
1789 Value->Value.b = (BOOLEAN) (Data1.Value.b || Data2.Value.b);
1790 }
1791 break;
1792
1793 case EFI_IFR_EQUAL_OP:
1794 case EFI_IFR_NOT_EQUAL_OP:
1795 case EFI_IFR_GREATER_EQUAL_OP:
1796 case EFI_IFR_GREATER_THAN_OP:
1797 case EFI_IFR_LESS_EQUAL_OP:
1798 case EFI_IFR_LESS_THAN_OP:
1799 //
1800 // Compare two integer, string, boolean or date/time
1801 //
1802 Status = PopExpression (&Data2);
1803 if (EFI_ERROR (Status)) {
1804 return Status;
1805 }
1806 if (Data2.Type > EFI_IFR_TYPE_BOOLEAN && Data2.Type != EFI_IFR_TYPE_STRING) {
1807 return EFI_INVALID_PARAMETER;
1808 }
1809
1810 //
1811 // Pop another expression from the expression stack
1812 //
1813 Status = PopExpression (&Data1);
1814 if (EFI_ERROR (Status)) {
1815 return Status;
1816 }
1817
1818 Result = CompareHiiValue (&Data1, &Data2, FormSet->HiiHandle);
1819 if (Result == EFI_INVALID_PARAMETER) {
1820 return EFI_INVALID_PARAMETER;
1821 }
1822
1823 switch (OpCode->Operand) {
1824 case EFI_IFR_EQUAL_OP:
1825 Value->Value.b = (BOOLEAN) ((Result == 0) ? TRUE : FALSE);
1826 break;
1827
1828 case EFI_IFR_NOT_EQUAL_OP:
1829 Value->Value.b = (BOOLEAN) ((Result == 0) ? TRUE : FALSE);
1830 break;
1831
1832 case EFI_IFR_GREATER_EQUAL_OP:
1833 Value->Value.b = (BOOLEAN) ((Result >= 0) ? TRUE : FALSE);
1834 break;
1835
1836 case EFI_IFR_GREATER_THAN_OP:
1837 Value->Value.b = (BOOLEAN) ((Result > 0) ? TRUE : FALSE);
1838 break;
1839
1840 case EFI_IFR_LESS_EQUAL_OP:
1841 Value->Value.b = (BOOLEAN) ((Result <= 0) ? TRUE : FALSE);
1842 break;
1843
1844 case EFI_IFR_LESS_THAN_OP:
1845 Value->Value.b = (BOOLEAN) ((Result < 0) ? TRUE : FALSE);
1846 break;
1847
1848 default:
1849 break;
1850 }
1851 break;
1852
1853 case EFI_IFR_MATCH_OP:
1854 Status = IfrMatch (FormSet, Value);
1855 break;
1856
1857 case EFI_IFR_CATENATE_OP:
1858 Status = IfrCatenate (FormSet, Value);
1859 break;
1860
1861 //
1862 // ternary-op
1863 //
1864 case EFI_IFR_CONDITIONAL_OP:
1865 //
1866 // Pop third expression from the expression stack
1867 //
1868 Status = PopExpression (&Data3);
1869 if (EFI_ERROR (Status)) {
1870 return Status;
1871 }
1872
1873 //
1874 // Pop second expression from the expression stack
1875 //
1876 Status = PopExpression (&Data2);
1877 if (EFI_ERROR (Status)) {
1878 return Status;
1879 }
1880
1881 //
1882 // Pop first expression from the expression stack
1883 //
1884 Status = PopExpression (&Data1);
1885 if (EFI_ERROR (Status)) {
1886 return Status;
1887 }
1888 if (Data1.Type != EFI_IFR_TYPE_BOOLEAN) {
1889 return EFI_INVALID_PARAMETER;
1890 }
1891
1892 if (Data1.Value.b) {
1893 Value = &Data3;
1894 } else {
1895 Value = &Data2;
1896 }
1897 break;
1898
1899 case EFI_IFR_FIND_OP:
1900 Status = IfrFind (FormSet, OpCode->Format, Value);
1901 break;
1902
1903 case EFI_IFR_MID_OP:
1904 Status = IfrMid (FormSet, Value);
1905 break;
1906
1907 case EFI_IFR_TOKEN_OP:
1908 Status = IfrToken (FormSet, Value);
1909 break;
1910
1911 case EFI_IFR_SPAN_OP:
1912 Status = IfrSpan (FormSet, OpCode->Flags, Value);
1913 break;
1914
1915 default:
1916 break;
1917 }
1918 if (EFI_ERROR (Status)) {
1919 return Status;
1920 }
1921
1922 Status = PushExpression (Value);
1923 if (EFI_ERROR (Status)) {
1924 return Status;
1925 }
1926 }
1927
1928 //
1929 // Pop the final result from expression stack
1930 //
1931 Value = &Data1;
1932 Status = PopExpression (Value);
1933 if (EFI_ERROR (Status)) {
1934 return Status;
1935 }
1936
1937 //
1938 // After evaluating an expression, there should be only one value left on the expression stack
1939 //
1940 if (PopExpression (Value) != EFI_ACCESS_DENIED) {
1941 return EFI_INVALID_PARAMETER;
1942 }
1943
1944 CopyMem (&Expression->Result, Value, sizeof (EFI_HII_VALUE));
1945
1946 return EFI_SUCCESS;
1947 }