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