]> git.proxmox.com Git - mirror_edk2.git/blob - MdeModulePkg/Universal/SetupBrowserDxe/Expression.c
Clean up SetupBrowserDxe for Doxygen comments requirement.
[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 SafeFreePool (String[0]);
716 SafeFreePool (String[1]);
717 SafeFreePool (StringPtr);
718
719 return Status;
720 }
721
722
723 /**
724 Evaluate opcode EFI_IFR_MATCH.
725
726 @param FormSet Formset which contains this opcode.
727 @param Result Evaluation result for this opcode.
728
729 @retval EFI_SUCCESS Opcode evaluation success.
730 @retval Other Opcode evaluation failed.
731
732 **/
733 EFI_STATUS
734 IfrMatch (
735 IN FORM_BROWSER_FORMSET *FormSet,
736 OUT EFI_HII_VALUE *Result
737 )
738 {
739 EFI_STATUS Status;
740 EFI_HII_VALUE Value;
741 CHAR16 *String[2];
742 UINTN Index;
743
744 //
745 // String[0] - The string to search
746 // String[1] - pattern
747 //
748 String[0] = NULL;
749 String[1] = NULL;
750 Status = EFI_SUCCESS;
751 for (Index = 0; Index < 2; Index++) {
752 Status = PopExpression (&Value);
753 if (EFI_ERROR (Status)) {
754 goto Done;
755 }
756
757 if (Value.Type != EFI_IFR_TYPE_STRING) {
758 Status = EFI_UNSUPPORTED;
759 goto Done;
760 }
761
762 String[Index] = GetToken (Value.Value.string, FormSet->HiiHandle);
763 if (String== NULL) {
764 Status = EFI_NOT_FOUND;
765 goto Done;
766 }
767 }
768
769 Result->Type = EFI_IFR_TYPE_BOOLEAN;
770 Result->Value.b = mUnicodeCollation->MetaiMatch (mUnicodeCollation, String[0], String[1]);
771
772 Done:
773 SafeFreePool (String[0]);
774 SafeFreePool (String[1]);
775
776 return Status;
777 }
778
779
780 /**
781 Evaluate opcode EFI_IFR_FIND.
782
783 @param FormSet Formset which contains this opcode.
784 @param Format Case sensitive or insensitive.
785 @param Result Evaluation result for this opcode.
786
787 @retval EFI_SUCCESS Opcode evaluation success.
788 @retval Other Opcode evaluation failed.
789
790 **/
791 EFI_STATUS
792 IfrFind (
793 IN FORM_BROWSER_FORMSET *FormSet,
794 IN UINT8 Format,
795 OUT EFI_HII_VALUE *Result
796 )
797 {
798 EFI_STATUS Status;
799 EFI_HII_VALUE Value;
800 CHAR16 *String[2];
801 UINTN Base;
802 CHAR16 *StringPtr;
803 UINTN Index;
804
805 if (Format > EFI_IFR_FF_CASE_INSENSITIVE) {
806 return EFI_UNSUPPORTED;
807 }
808
809 Status = PopExpression (&Value);
810 if (EFI_ERROR (Status)) {
811 return Status;
812 }
813 if (Value.Type > EFI_IFR_TYPE_NUM_SIZE_64) {
814 return EFI_UNSUPPORTED;
815 }
816 Base = (UINTN) Value.Value.u64;
817
818 //
819 // String[0] - sub-string
820 // String[1] - The string to search
821 //
822 String[0] = NULL;
823 String[1] = NULL;
824 for (Index = 0; Index < 2; Index++) {
825 Status = PopExpression (&Value);
826 if (EFI_ERROR (Status)) {
827 goto Done;
828 }
829
830 if (Value.Type != EFI_IFR_TYPE_STRING) {
831 Status = EFI_UNSUPPORTED;
832 goto Done;
833 }
834
835 String[Index] = GetToken (Value.Value.string, FormSet->HiiHandle);
836 if (String== NULL) {
837 Status = EFI_NOT_FOUND;
838 goto Done;
839 }
840
841 if (Format == EFI_IFR_FF_CASE_INSENSITIVE) {
842 //
843 // Case insensitive, convert both string to upper case
844 //
845 IfrStrToUpper (String[Index]);
846 }
847 }
848
849 Result->Type = EFI_IFR_TYPE_NUM_SIZE_64;
850 if (Base >= StrLen (String[1])) {
851 Result->Value.u64 = 0xFFFFFFFFFFFFFFFFULL;
852 } else {
853 StringPtr = StrStr (String[1] + Base, String[0]);
854 Result->Value.u64 = (StringPtr == NULL) ? 0xFFFFFFFFFFFFFFFFULL : (StringPtr - String[1]);
855 }
856
857 Done:
858 SafeFreePool (String[0]);
859 SafeFreePool (String[1]);
860
861 return Status;
862 }
863
864
865 /**
866 Evaluate opcode EFI_IFR_MID.
867
868 @param FormSet Formset which contains this opcode.
869 @param Result Evaluation result for this opcode.
870
871 @retval EFI_SUCCESS Opcode evaluation success.
872 @retval Other Opcode evaluation failed.
873
874 **/
875 EFI_STATUS
876 IfrMid (
877 IN FORM_BROWSER_FORMSET *FormSet,
878 OUT EFI_HII_VALUE *Result
879 )
880 {
881 EFI_STATUS Status;
882 EFI_HII_VALUE Value;
883 CHAR16 *String;
884 UINTN Base;
885 UINTN Length;
886 CHAR16 *SubString;
887
888 Status = PopExpression (&Value);
889 if (EFI_ERROR (Status)) {
890 return Status;
891 }
892 if (Value.Type > EFI_IFR_TYPE_NUM_SIZE_64) {
893 return EFI_UNSUPPORTED;
894 }
895 Length = (UINTN) Value.Value.u64;
896
897 Status = PopExpression (&Value);
898 if (EFI_ERROR (Status)) {
899 return Status;
900 }
901 if (Value.Type > EFI_IFR_TYPE_NUM_SIZE_64) {
902 return EFI_UNSUPPORTED;
903 }
904 Base = (UINTN) Value.Value.u64;
905
906 Status = PopExpression (&Value);
907 if (EFI_ERROR (Status)) {
908 return Status;
909 }
910 if (Value.Type != EFI_IFR_TYPE_STRING) {
911 return EFI_UNSUPPORTED;
912 }
913 String = GetToken (Value.Value.string, FormSet->HiiHandle);
914 if (String == NULL) {
915 return EFI_NOT_FOUND;
916 }
917
918 if (Length == 0 || Base >= StrLen (String)) {
919 SubString = gEmptyString;
920 } else {
921 SubString = String + Base;
922 if ((Base + Length) < StrLen (String)) {
923 SubString[Length] = L'\0';
924 }
925 }
926
927 Result->Type = EFI_IFR_TYPE_STRING;
928 Result->Value.string = NewString (SubString, FormSet->HiiHandle);
929
930 gBS->FreePool (String);
931
932 return Status;
933 }
934
935
936 /**
937 Evaluate opcode EFI_IFR_TOKEN.
938
939 @param FormSet Formset which contains this opcode.
940 @param Result Evaluation result for this opcode.
941
942 @retval EFI_SUCCESS Opcode evaluation success.
943 @retval Other Opcode evaluation failed.
944
945 **/
946 EFI_STATUS
947 IfrToken (
948 IN FORM_BROWSER_FORMSET *FormSet,
949 OUT EFI_HII_VALUE *Result
950 )
951 {
952 EFI_STATUS Status;
953 EFI_HII_VALUE Value;
954 CHAR16 *String[2];
955 UINTN Count;
956 CHAR16 *Delimiter;
957 CHAR16 *SubString;
958 CHAR16 *StringPtr;
959 UINTN Index;
960
961 Status = PopExpression (&Value);
962 if (EFI_ERROR (Status)) {
963 return Status;
964 }
965 if (Value.Type > EFI_IFR_TYPE_NUM_SIZE_64) {
966 return EFI_UNSUPPORTED;
967 }
968 Count = (UINTN) Value.Value.u64;
969
970 //
971 // String[0] - Delimiter
972 // String[1] - The string to search
973 //
974 String[0] = NULL;
975 String[1] = NULL;
976 for (Index = 0; Index < 2; Index++) {
977 Status = PopExpression (&Value);
978 if (EFI_ERROR (Status)) {
979 goto Done;
980 }
981
982 if (Value.Type != EFI_IFR_TYPE_STRING) {
983 Status = EFI_UNSUPPORTED;
984 goto Done;
985 }
986
987 String[Index] = GetToken (Value.Value.string, FormSet->HiiHandle);
988 if (String== NULL) {
989 Status = EFI_NOT_FOUND;
990 goto Done;
991 }
992 }
993
994 Delimiter = String[0];
995 SubString = String[1];
996 while (Count > 0) {
997 SubString = StrStr (SubString, Delimiter);
998 if (SubString != NULL) {
999 //
1000 // Skip over the delimiter
1001 //
1002 SubString = SubString + StrLen (Delimiter);
1003 } else {
1004 break;
1005 }
1006 Count--;
1007 }
1008
1009 if (SubString == NULL) {
1010 //
1011 // nth delimited sub-string not found, push an empty string
1012 //
1013 SubString = gEmptyString;
1014 } else {
1015 //
1016 // Put a NULL terminator for nth delimited sub-string
1017 //
1018 StringPtr = StrStr (SubString, Delimiter);
1019 if (StringPtr != NULL) {
1020 *StringPtr = L'\0';
1021 }
1022 }
1023
1024 Result->Type = EFI_IFR_TYPE_STRING;
1025 Result->Value.string = NewString (SubString, FormSet->HiiHandle);
1026
1027 Done:
1028 SafeFreePool (String[0]);
1029 SafeFreePool (String[1]);
1030
1031 return Status;
1032 }
1033
1034
1035 /**
1036 Evaluate opcode EFI_IFR_SPAN.
1037
1038 @param FormSet Formset which contains this opcode.
1039 @param Flags FIRST_MATCHING or FIRST_NON_MATCHING.
1040 @param Result Evaluation result for this opcode.
1041
1042 @retval EFI_SUCCESS Opcode evaluation success.
1043 @retval Other Opcode evaluation failed.
1044
1045 **/
1046 EFI_STATUS
1047 IfrSpan (
1048 IN FORM_BROWSER_FORMSET *FormSet,
1049 IN UINT8 Flags,
1050 OUT EFI_HII_VALUE *Result
1051 )
1052 {
1053 EFI_STATUS Status;
1054 EFI_HII_VALUE Value;
1055 CHAR16 *String[2];
1056 CHAR16 *Charset;
1057 UINTN Base;
1058 UINTN Index;
1059 CHAR16 *StringPtr;
1060 BOOLEAN Found;
1061
1062 Status = PopExpression (&Value);
1063 if (EFI_ERROR (Status)) {
1064 return Status;
1065 }
1066 if (Value.Type > EFI_IFR_TYPE_NUM_SIZE_64) {
1067 return EFI_UNSUPPORTED;
1068 }
1069 Base = (UINTN) Value.Value.u64;
1070
1071 //
1072 // String[0] - Charset
1073 // String[1] - The string to search
1074 //
1075 String[0] = NULL;
1076 String[1] = NULL;
1077 for (Index = 0; Index < 2; Index++) {
1078 Status = PopExpression (&Value);
1079 if (EFI_ERROR (Status)) {
1080 goto Done;
1081 }
1082
1083 if (Value.Type != EFI_IFR_TYPE_STRING) {
1084 Status = EFI_UNSUPPORTED;
1085 goto Done;
1086 }
1087
1088 String[Index] = GetToken (Value.Value.string, FormSet->HiiHandle);
1089 if (String== NULL) {
1090 Status = EFI_NOT_FOUND;
1091 goto Done;
1092 }
1093 }
1094
1095 if (Base >= StrLen (String[1])) {
1096 Status = EFI_UNSUPPORTED;
1097 goto Done;
1098 }
1099
1100 Found = FALSE;
1101 StringPtr = String[1] + Base;
1102 Charset = String[0];
1103 while (*StringPtr != 0 && !Found) {
1104 Index = 0;
1105 while (Charset[Index] != 0) {
1106 if (*StringPtr >= Charset[Index] && *StringPtr <= Charset[Index + 1]) {
1107 if (Flags == EFI_IFR_FLAGS_FIRST_MATCHING) {
1108 Found = TRUE;
1109 break;
1110 }
1111 } else {
1112 if (Flags == EFI_IFR_FLAGS_FIRST_NON_MATCHING) {
1113 Found = TRUE;
1114 break;
1115 }
1116 }
1117 //
1118 // Skip characters pair representing low-end of a range and high-end of a range
1119 //
1120 Index += 2;
1121 }
1122
1123 if (!Found) {
1124 StringPtr++;
1125 }
1126 }
1127
1128 Result->Type = EFI_IFR_TYPE_NUM_SIZE_64;
1129 Result->Value.u64 = StringPtr - String[1];
1130
1131 Done:
1132 SafeFreePool (String[0]);
1133 SafeFreePool (String[1]);
1134
1135 return Status;
1136 }
1137
1138
1139 /**
1140 Zero extend integer/boolean/date/time to UINT64 for comparing.
1141
1142 @param Value HII Value to be converted.
1143
1144 **/
1145 VOID
1146 ExtendValueToU64 (
1147 IN EFI_HII_VALUE *Value
1148 )
1149 {
1150 UINT64 Temp;
1151
1152 Temp = 0;
1153 switch (Value->Type) {
1154 case EFI_IFR_TYPE_NUM_SIZE_8:
1155 Temp = Value->Value.u8;
1156 break;
1157
1158 case EFI_IFR_TYPE_NUM_SIZE_16:
1159 Temp = Value->Value.u16;
1160 break;
1161
1162 case EFI_IFR_TYPE_NUM_SIZE_32:
1163 Temp = Value->Value.u32;
1164 break;
1165
1166 case EFI_IFR_TYPE_BOOLEAN:
1167 Temp = Value->Value.b;
1168 break;
1169
1170 case EFI_IFR_TYPE_TIME:
1171 Temp = Value->Value.u32 & 0xffffff;
1172 break;
1173
1174 case EFI_IFR_TYPE_DATE:
1175 Temp = Value->Value.u32;
1176 break;
1177
1178 default:
1179 return;
1180 }
1181
1182 Value->Value.u64 = Temp;
1183 }
1184
1185
1186 /**
1187 Compare two Hii value.
1188
1189 @param Value1 Expression value to compare on left-hand.
1190 @param Value2 Expression value to compare on right-hand.
1191 @param HiiHandle Only required for string compare.
1192
1193 @retval EFI_INVALID_PARAMETER Could not perform comparation on two values.
1194 @retval 0 Two operators equeal.
1195 @return Positive value if Value1 is greater than Value2.
1196 @retval Negative value if Value1 is less than Value2.
1197
1198 **/
1199 INTN
1200 CompareHiiValue (
1201 IN EFI_HII_VALUE *Value1,
1202 IN EFI_HII_VALUE *Value2,
1203 IN EFI_HII_HANDLE HiiHandle OPTIONAL
1204 )
1205 {
1206 INTN Result;
1207 INT64 Temp64;
1208 CHAR16 *Str1;
1209 CHAR16 *Str2;
1210
1211 if (Value1->Type >= EFI_IFR_TYPE_OTHER || Value2->Type >= EFI_IFR_TYPE_OTHER ) {
1212 return EFI_INVALID_PARAMETER;
1213 }
1214
1215 if (Value1->Type == EFI_IFR_TYPE_STRING || Value2->Type == EFI_IFR_TYPE_STRING ) {
1216 if (Value1->Type != Value2->Type) {
1217 //
1218 // Both Operator should be type of String
1219 //
1220 return EFI_INVALID_PARAMETER;
1221 }
1222
1223 if (Value1->Value.string == 0 || Value2->Value.string == 0) {
1224 //
1225 // StringId 0 is reserved
1226 //
1227 return EFI_INVALID_PARAMETER;
1228 }
1229
1230 if (Value1->Value.string == Value2->Value.string) {
1231 return 0;
1232 }
1233
1234 Str1 = GetToken (Value1->Value.string, HiiHandle);
1235 if (Str1 == NULL) {
1236 //
1237 // String not found
1238 //
1239 return EFI_INVALID_PARAMETER;
1240 }
1241
1242 Str2 = GetToken (Value2->Value.string, HiiHandle);
1243 if (Str2 == NULL) {
1244 gBS->FreePool (Str1);
1245 return EFI_INVALID_PARAMETER;
1246 }
1247
1248 Result = StrCmp (Str1, Str2);
1249
1250 gBS->FreePool (Str1);
1251 gBS->FreePool (Str2);
1252
1253 return Result;
1254 }
1255
1256 //
1257 // Take remain types(integer, boolean, date/time) as integer
1258 //
1259 Temp64 = (INT64) (Value1->Value.u64 - Value2->Value.u64);
1260 if (Temp64 > 0) {
1261 Result = 1;
1262 } else if (Temp64 < 0) {
1263 Result = -1;
1264 } else {
1265 Result = 0;
1266 }
1267
1268 return Result;
1269 }
1270
1271
1272 /**
1273 Evaluate the result of a HII expression
1274
1275 @param FormSet FormSet associated with this expression.
1276 @param Form Form associated with this expression.
1277 @param Expression Expression to be evaluated.
1278
1279 @retval EFI_SUCCESS The expression evaluated successfuly
1280 @retval EFI_NOT_FOUND The Question which referenced by a QuestionId
1281 could not be found.
1282 @retval EFI_OUT_OF_RESOURCES There is not enough system memory to grow the
1283 stack.
1284 @retval EFI_ACCESS_DENIED The pop operation underflowed the stack
1285 @retval EFI_INVALID_PARAMETER Syntax error with the Expression
1286
1287 **/
1288 EFI_STATUS
1289 EvaluateExpression (
1290 IN FORM_BROWSER_FORMSET *FormSet,
1291 IN FORM_BROWSER_FORM *Form,
1292 IN OUT FORM_EXPRESSION *Expression
1293 )
1294 {
1295 EFI_STATUS Status;
1296 LIST_ENTRY *Link;
1297 EXPRESSION_OPCODE *OpCode;
1298 FORM_BROWSER_STATEMENT *Question;
1299 FORM_BROWSER_STATEMENT *Question2;
1300 UINT16 Index;
1301 EFI_HII_VALUE Data1;
1302 EFI_HII_VALUE Data2;
1303 EFI_HII_VALUE Data3;
1304 FORM_EXPRESSION *RuleExpression;
1305 EFI_HII_VALUE *Value;
1306 INTN Result;
1307 CHAR16 *StrPtr;
1308 UINT32 TempValue;
1309
1310 //
1311 // Always reset the stack before evaluating an Expression
1312 //
1313 ResetExpressionStack ();
1314
1315 Expression->Result.Type = EFI_IFR_TYPE_OTHER;
1316
1317 Link = GetFirstNode (&Expression->OpCodeListHead);
1318 while (!IsNull (&Expression->OpCodeListHead, Link)) {
1319 OpCode = EXPRESSION_OPCODE_FROM_LINK (Link);
1320
1321 Link = GetNextNode (&Expression->OpCodeListHead, Link);
1322
1323 ZeroMem (&Data1, sizeof (EFI_HII_VALUE));
1324 ZeroMem (&Data2, sizeof (EFI_HII_VALUE));
1325 ZeroMem (&Data3, sizeof (EFI_HII_VALUE));
1326
1327 Value = &Data3;
1328 Value->Type = EFI_IFR_TYPE_BOOLEAN;
1329 Status = EFI_SUCCESS;
1330
1331 switch (OpCode->Operand) {
1332 //
1333 // Built-in functions
1334 //
1335 case EFI_IFR_EQ_ID_VAL_OP:
1336 Question = IdToQuestion (FormSet, Form, OpCode->QuestionId);
1337 if (Question == NULL) {
1338 return EFI_NOT_FOUND;
1339 }
1340
1341 Result = CompareHiiValue (&Question->HiiValue, &OpCode->Value, NULL);
1342 if (Result == EFI_INVALID_PARAMETER) {
1343 return EFI_INVALID_PARAMETER;
1344 }
1345 Value->Value.b = (BOOLEAN) ((Result == 0) ? TRUE : FALSE);
1346 break;
1347
1348 case EFI_IFR_EQ_ID_ID_OP:
1349 Question = IdToQuestion (FormSet, Form, OpCode->QuestionId);
1350 if (Question == NULL) {
1351 return EFI_NOT_FOUND;
1352 }
1353
1354 Question2 = IdToQuestion (FormSet, Form, OpCode->QuestionId2);
1355 if (Question2 == NULL) {
1356 return EFI_NOT_FOUND;
1357 }
1358
1359 Result = CompareHiiValue (&Question->HiiValue, &Question2->HiiValue, FormSet->HiiHandle);
1360 if (Result == EFI_INVALID_PARAMETER) {
1361 return EFI_INVALID_PARAMETER;
1362 }
1363 Value->Value.b = (BOOLEAN) ((Result == 0) ? TRUE : FALSE);
1364 break;
1365
1366 case EFI_IFR_EQ_ID_LIST_OP:
1367 Question = IdToQuestion (FormSet, Form, OpCode->QuestionId);
1368 if (Question == NULL) {
1369 return EFI_NOT_FOUND;
1370 }
1371
1372 Value->Value.b = FALSE;
1373 for (Index =0; Index < OpCode->ListLength; Index++) {
1374 if (Question->HiiValue.Value.u16 == OpCode->ValueList[Index]) {
1375 Value->Value.b = TRUE;
1376 break;
1377 }
1378 }
1379 break;
1380
1381 case EFI_IFR_DUP_OP:
1382 Status = PopExpression (Value);
1383 if (EFI_ERROR (Status)) {
1384 return Status;
1385 }
1386
1387 Status = PushExpression (Value);
1388 break;
1389
1390 case EFI_IFR_QUESTION_REF1_OP:
1391 case EFI_IFR_THIS_OP:
1392 Question = IdToQuestion (FormSet, Form, OpCode->QuestionId);
1393 if (Question == NULL) {
1394 return EFI_NOT_FOUND;
1395 }
1396
1397 Value = &Question->HiiValue;
1398 break;
1399
1400 case EFI_IFR_QUESTION_REF3_OP:
1401 if (OpCode->DevicePath == 0) {
1402 //
1403 // EFI_IFR_QUESTION_REF3
1404 // Pop an expression from the expression stack
1405 //
1406 Status = PopExpression (Value);
1407 if (EFI_ERROR (Status)) {
1408 return Status;
1409 }
1410
1411 //
1412 // Validate the expression value
1413 //
1414 if ((Value->Type > EFI_IFR_TYPE_NUM_SIZE_64) || (Value->Value.u64 > 0xffff)) {
1415 return EFI_NOT_FOUND;
1416 }
1417
1418 Question = IdToQuestion (FormSet, Form, Value->Value.u16);
1419 if (Question == NULL) {
1420 return EFI_NOT_FOUND;
1421 }
1422
1423 //
1424 // push the questions' value on to the expression stack
1425 //
1426 Value = &Question->HiiValue;
1427 } else {
1428 //
1429 // BUGBUG: push 0 for EFI_IFR_QUESTION_REF3_2 and EFI_IFR_QUESTION_REF3_3,
1430 // since it is impractical to evaluate the value of a Question in another
1431 // Hii Package list.
1432 //
1433 ZeroMem (Value, sizeof (EFI_HII_VALUE));
1434 }
1435 break;
1436
1437 case EFI_IFR_RULE_REF_OP:
1438 //
1439 // Find expression for this rule
1440 //
1441 RuleExpression = RuleIdToExpression (Form, OpCode->RuleId);
1442 if (RuleExpression == NULL) {
1443 return EFI_NOT_FOUND;
1444 }
1445
1446 //
1447 // Evaluate this rule expression
1448 //
1449 Status = EvaluateExpression (FormSet, Form, RuleExpression);
1450 if (EFI_ERROR (Status)) {
1451 return Status;
1452 }
1453
1454 Value = &RuleExpression->Result;
1455 break;
1456
1457 case EFI_IFR_STRING_REF1_OP:
1458 Value->Type = EFI_IFR_TYPE_STRING;
1459 Value->Value.string = OpCode->Value.Value.string;
1460 break;
1461
1462 //
1463 // Constant
1464 //
1465 case EFI_IFR_TRUE_OP:
1466 case EFI_IFR_FALSE_OP:
1467 case EFI_IFR_ONE_OP:
1468 case EFI_IFR_ONES_OP:
1469 case EFI_IFR_UINT8_OP:
1470 case EFI_IFR_UINT16_OP:
1471 case EFI_IFR_UINT32_OP:
1472 case EFI_IFR_UINT64_OP:
1473 case EFI_IFR_UNDEFINED_OP:
1474 case EFI_IFR_VERSION_OP:
1475 case EFI_IFR_ZERO_OP:
1476 Value = &OpCode->Value;
1477 break;
1478
1479 //
1480 // unary-op
1481 //
1482 case EFI_IFR_LENGTH_OP:
1483 Status = PopExpression (Value);
1484 if (EFI_ERROR (Status)) {
1485 return Status;
1486 }
1487 if (Value->Type != EFI_IFR_TYPE_STRING) {
1488 return EFI_INVALID_PARAMETER;
1489 }
1490
1491 StrPtr = GetToken (Value->Value.string, FormSet->HiiHandle);
1492 if (StrPtr == NULL) {
1493 return EFI_INVALID_PARAMETER;
1494 }
1495
1496 Value->Type = EFI_IFR_TYPE_NUM_SIZE_64;
1497 Value->Value.u64 = StrLen (StrPtr);
1498 gBS->FreePool (StrPtr);
1499 break;
1500
1501 case EFI_IFR_NOT_OP:
1502 Status = PopExpression (Value);
1503 if (EFI_ERROR (Status)) {
1504 return Status;
1505 }
1506 if (Value->Type != EFI_IFR_TYPE_BOOLEAN) {
1507 return EFI_INVALID_PARAMETER;
1508 }
1509 Value->Value.b = (BOOLEAN) (!Value->Value.b);
1510 break;
1511
1512 case EFI_IFR_QUESTION_REF2_OP:
1513 //
1514 // Pop an expression from the expression stack
1515 //
1516 Status = PopExpression (Value);
1517 if (EFI_ERROR (Status)) {
1518 return Status;
1519 }
1520
1521 //
1522 // Validate the expression value
1523 //
1524 if ((Value->Type > EFI_IFR_TYPE_NUM_SIZE_64) || (Value->Value.u64 > 0xffff)) {
1525 return EFI_NOT_FOUND;
1526 }
1527
1528 Question = IdToQuestion (FormSet, Form, Value->Value.u16);
1529 if (Question == NULL) {
1530 return EFI_NOT_FOUND;
1531 }
1532
1533 Value = &Question->HiiValue;
1534 break;
1535
1536 case EFI_IFR_STRING_REF2_OP:
1537 //
1538 // Pop an expression from the expression stack
1539 //
1540 Status = PopExpression (Value);
1541 if (EFI_ERROR (Status)) {
1542 return Status;
1543 }
1544
1545 //
1546 // Validate the expression value
1547 //
1548 if ((Value->Type > EFI_IFR_TYPE_NUM_SIZE_64) || (Value->Value.u64 > 0xffff)) {
1549 return EFI_NOT_FOUND;
1550 }
1551
1552 Value->Type = EFI_IFR_TYPE_STRING;
1553 StrPtr = GetToken (Value->Value.u16, FormSet->HiiHandle);
1554 if (StrPtr == NULL) {
1555 //
1556 // If String not exit, push an empty string
1557 //
1558 Value->Value.string = NewString (gEmptyString, FormSet->HiiHandle);
1559 } else {
1560 Index = (UINT16) Value->Value.u64;
1561 Value->Value.string = Index;
1562 gBS->FreePool (StrPtr);
1563 }
1564 break;
1565
1566 case EFI_IFR_TO_BOOLEAN_OP:
1567 //
1568 // Pop an expression from the expression stack
1569 //
1570 Status = PopExpression (Value);
1571 if (EFI_ERROR (Status)) {
1572 return Status;
1573 }
1574
1575 //
1576 // Convert an expression to a Boolean
1577 //
1578 if (Value->Type <= EFI_IFR_TYPE_DATE) {
1579 //
1580 // When converting from an unsigned integer, zero will be converted to
1581 // FALSE and any other value will be converted to TRUE.
1582 //
1583 Value->Value.b = (BOOLEAN) ((Value->Value.u64) ? TRUE : FALSE);
1584
1585 Value->Type = EFI_IFR_TYPE_BOOLEAN;
1586 } else if (Value->Type == EFI_IFR_TYPE_STRING) {
1587 //
1588 // When converting from a string, if case-insensitive compare
1589 // with "true" is True, then push True. If a case-insensitive compare
1590 // with "false" is True, then push False.
1591 //
1592 StrPtr = GetToken (Value->Value.string, FormSet->HiiHandle);
1593 if (StrPtr == NULL) {
1594 return EFI_INVALID_PARAMETER;
1595 }
1596
1597 if ((StrCmp (StrPtr, L"true") == 0) || (StrCmp (StrPtr, L"false") == 0)){
1598 Value->Value.b = TRUE;
1599 } else {
1600 Value->Value.b = FALSE;
1601 }
1602 gBS->FreePool (StrPtr);
1603 Value->Type = EFI_IFR_TYPE_BOOLEAN;
1604 }
1605 break;
1606
1607 case EFI_IFR_TO_STRING_OP:
1608 Status = IfrToString (FormSet, OpCode->Format, Value);
1609 break;
1610
1611 case EFI_IFR_TO_UINT_OP:
1612 Status = IfrToUint (FormSet, Value);
1613 break;
1614
1615 case EFI_IFR_TO_LOWER_OP:
1616 case EFI_IFR_TO_UPPER_OP:
1617 Status = InitializeUnicodeCollationProtocol ();
1618 if (EFI_ERROR (Status)) {
1619 return Status;
1620 }
1621
1622 Status = PopExpression (Value);
1623 if (EFI_ERROR (Status)) {
1624 return Status;
1625 }
1626
1627 if (Value->Type != EFI_IFR_TYPE_STRING) {
1628 return EFI_UNSUPPORTED;
1629 }
1630
1631 StrPtr = GetToken (Value->Value.string, FormSet->HiiHandle);
1632 if (StrPtr == NULL) {
1633 return EFI_NOT_FOUND;
1634 }
1635
1636 if (OpCode->Operand == EFI_IFR_TO_LOWER_OP) {
1637 mUnicodeCollation->StrLwr (mUnicodeCollation, StrPtr);
1638 } else {
1639 mUnicodeCollation->StrUpr (mUnicodeCollation, StrPtr);
1640 }
1641 Value->Value.string = NewString (StrPtr, FormSet->HiiHandle);
1642 gBS->FreePool (StrPtr);
1643 break;
1644
1645 case EFI_IFR_BITWISE_NOT_OP:
1646 //
1647 // Pop an expression from the expression stack
1648 //
1649 Status = PopExpression (Value);
1650 if (EFI_ERROR (Status)) {
1651 return Status;
1652 }
1653 if (Value->Type > EFI_IFR_TYPE_DATE) {
1654 return EFI_INVALID_PARAMETER;
1655 }
1656
1657 Value->Type = EFI_IFR_TYPE_NUM_SIZE_64;
1658 Value->Value.u64 = ~Value->Value.u64;
1659 break;
1660
1661 //
1662 // binary-op
1663 //
1664 case EFI_IFR_ADD_OP:
1665 case EFI_IFR_SUBTRACT_OP:
1666 case EFI_IFR_MULTIPLY_OP:
1667 case EFI_IFR_DIVIDE_OP:
1668 case EFI_IFR_MODULO_OP:
1669 case EFI_IFR_BITWISE_AND_OP:
1670 case EFI_IFR_BITWISE_OR_OP:
1671 case EFI_IFR_SHIFT_LEFT_OP:
1672 case EFI_IFR_SHIFT_RIGHT_OP:
1673 //
1674 // Pop an expression from the expression stack
1675 //
1676 Status = PopExpression (&Data2);
1677 if (EFI_ERROR (Status)) {
1678 return Status;
1679 }
1680 if (Data2.Type > EFI_IFR_TYPE_DATE) {
1681 return EFI_INVALID_PARAMETER;
1682 }
1683
1684 //
1685 // Pop another expression from the expression stack
1686 //
1687 Status = PopExpression (&Data1);
1688 if (EFI_ERROR (Status)) {
1689 return Status;
1690 }
1691 if (Data1.Type > EFI_IFR_TYPE_DATE) {
1692 return EFI_INVALID_PARAMETER;
1693 }
1694
1695 Value->Type = EFI_IFR_TYPE_NUM_SIZE_64;
1696
1697 switch (OpCode->Operand) {
1698 case EFI_IFR_ADD_OP:
1699 Value->Value.u64 = Data1.Value.u64 + Data2.Value.u64;
1700 break;
1701
1702 case EFI_IFR_SUBTRACT_OP:
1703 Value->Value.u64 = Data1.Value.u64 - Data2.Value.u64;
1704 break;
1705
1706 case EFI_IFR_MULTIPLY_OP:
1707 Value->Value.u64 = MultU64x32 (Data1.Value.u64, (UINT32) Data2.Value.u64);
1708 break;
1709
1710 case EFI_IFR_DIVIDE_OP:
1711 Value->Value.u64 = DivU64x32 (Data1.Value.u64, (UINT32) Data2.Value.u64);
1712 break;
1713
1714 case EFI_IFR_MODULO_OP:
1715 DivU64x32Remainder (Data1.Value.u64, (UINT32) Data2.Value.u64, &TempValue);
1716 Value->Value.u64 = TempValue;
1717 break;
1718
1719 case EFI_IFR_BITWISE_AND_OP:
1720 Value->Value.u64 = Data1.Value.u64 & Data2.Value.u64;
1721 break;
1722
1723 case EFI_IFR_BITWISE_OR_OP:
1724 Value->Value.u64 = Data1.Value.u64 | Data2.Value.u64;
1725 break;
1726
1727 case EFI_IFR_SHIFT_LEFT_OP:
1728 Value->Value.u64 = LShiftU64 (Data1.Value.u64, (UINTN) Data2.Value.u64);
1729 break;
1730
1731 case EFI_IFR_SHIFT_RIGHT_OP:
1732 Value->Value.u64 = RShiftU64 (Data1.Value.u64, (UINTN) Data2.Value.u64);
1733 break;
1734
1735 default:
1736 break;
1737 }
1738 break;
1739
1740 case EFI_IFR_AND_OP:
1741 case EFI_IFR_OR_OP:
1742 //
1743 // Two Boolean operator
1744 //
1745 Status = PopExpression (&Data2);
1746 if (EFI_ERROR (Status)) {
1747 return Status;
1748 }
1749 if (Data2.Type != EFI_IFR_TYPE_BOOLEAN) {
1750 return EFI_INVALID_PARAMETER;
1751 }
1752
1753 //
1754 // Pop another expression from the expression stack
1755 //
1756 Status = PopExpression (&Data1);
1757 if (EFI_ERROR (Status)) {
1758 return Status;
1759 }
1760 if (Data1.Type != EFI_IFR_TYPE_BOOLEAN) {
1761 return EFI_INVALID_PARAMETER;
1762 }
1763
1764 if (OpCode->Operand == EFI_IFR_AND_OP) {
1765 Value->Value.b = (BOOLEAN) (Data1.Value.b && Data2.Value.b);
1766 } else {
1767 Value->Value.b = (BOOLEAN) (Data1.Value.b || Data2.Value.b);
1768 }
1769 break;
1770
1771 case EFI_IFR_EQUAL_OP:
1772 case EFI_IFR_NOT_EQUAL_OP:
1773 case EFI_IFR_GREATER_EQUAL_OP:
1774 case EFI_IFR_GREATER_THAN_OP:
1775 case EFI_IFR_LESS_EQUAL_OP:
1776 case EFI_IFR_LESS_THAN_OP:
1777 //
1778 // Compare two integer, string, boolean or date/time
1779 //
1780 Status = PopExpression (&Data2);
1781 if (EFI_ERROR (Status)) {
1782 return Status;
1783 }
1784 if (Data2.Type > EFI_IFR_TYPE_BOOLEAN && Data2.Type != EFI_IFR_TYPE_STRING) {
1785 return EFI_INVALID_PARAMETER;
1786 }
1787
1788 //
1789 // Pop another expression from the expression stack
1790 //
1791 Status = PopExpression (&Data1);
1792 if (EFI_ERROR (Status)) {
1793 return Status;
1794 }
1795
1796 Result = CompareHiiValue (&Data1, &Data2, FormSet->HiiHandle);
1797 if (Result == EFI_INVALID_PARAMETER) {
1798 return EFI_INVALID_PARAMETER;
1799 }
1800
1801 switch (OpCode->Operand) {
1802 case EFI_IFR_EQUAL_OP:
1803 Value->Value.b = (BOOLEAN) ((Result == 0) ? TRUE : FALSE);
1804 break;
1805
1806 case EFI_IFR_NOT_EQUAL_OP:
1807 Value->Value.b = (BOOLEAN) ((Result == 0) ? TRUE : FALSE);
1808 break;
1809
1810 case EFI_IFR_GREATER_EQUAL_OP:
1811 Value->Value.b = (BOOLEAN) ((Result >= 0) ? TRUE : FALSE);
1812 break;
1813
1814 case EFI_IFR_GREATER_THAN_OP:
1815 Value->Value.b = (BOOLEAN) ((Result > 0) ? TRUE : FALSE);
1816 break;
1817
1818 case EFI_IFR_LESS_EQUAL_OP:
1819 Value->Value.b = (BOOLEAN) ((Result <= 0) ? TRUE : FALSE);
1820 break;
1821
1822 case EFI_IFR_LESS_THAN_OP:
1823 Value->Value.b = (BOOLEAN) ((Result < 0) ? TRUE : FALSE);
1824 break;
1825
1826 default:
1827 break;
1828 }
1829 break;
1830
1831 case EFI_IFR_MATCH_OP:
1832 Status = IfrMatch (FormSet, Value);
1833 break;
1834
1835 case EFI_IFR_CATENATE_OP:
1836 Status = IfrCatenate (FormSet, Value);
1837 break;
1838
1839 //
1840 // ternary-op
1841 //
1842 case EFI_IFR_CONDITIONAL_OP:
1843 //
1844 // Pop third expression from the expression stack
1845 //
1846 Status = PopExpression (&Data3);
1847 if (EFI_ERROR (Status)) {
1848 return Status;
1849 }
1850
1851 //
1852 // Pop second expression from the expression stack
1853 //
1854 Status = PopExpression (&Data2);
1855 if (EFI_ERROR (Status)) {
1856 return Status;
1857 }
1858
1859 //
1860 // Pop first expression from the expression stack
1861 //
1862 Status = PopExpression (&Data1);
1863 if (EFI_ERROR (Status)) {
1864 return Status;
1865 }
1866 if (Data1.Type != EFI_IFR_TYPE_BOOLEAN) {
1867 return EFI_INVALID_PARAMETER;
1868 }
1869
1870 if (Data1.Value.b) {
1871 Value = &Data3;
1872 } else {
1873 Value = &Data2;
1874 }
1875 break;
1876
1877 case EFI_IFR_FIND_OP:
1878 Status = IfrFind (FormSet, OpCode->Format, Value);
1879 break;
1880
1881 case EFI_IFR_MID_OP:
1882 Status = IfrMid (FormSet, Value);
1883 break;
1884
1885 case EFI_IFR_TOKEN_OP:
1886 Status = IfrToken (FormSet, Value);
1887 break;
1888
1889 case EFI_IFR_SPAN_OP:
1890 Status = IfrSpan (FormSet, OpCode->Flags, Value);
1891 break;
1892
1893 default:
1894 break;
1895 }
1896 if (EFI_ERROR (Status)) {
1897 return Status;
1898 }
1899
1900 Status = PushExpression (Value);
1901 if (EFI_ERROR (Status)) {
1902 return Status;
1903 }
1904 }
1905
1906 //
1907 // Pop the final result from expression stack
1908 //
1909 Value = &Data1;
1910 Status = PopExpression (Value);
1911 if (EFI_ERROR (Status)) {
1912 return Status;
1913 }
1914
1915 //
1916 // After evaluating an expression, there should be only one value left on the expression stack
1917 //
1918 if (PopExpression (Value) != EFI_ACCESS_DENIED) {
1919 return EFI_INVALID_PARAMETER;
1920 }
1921
1922 CopyMem (&Expression->Result, Value, sizeof (EFI_HII_VALUE));
1923
1924 return EFI_SUCCESS;
1925 }