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