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