]> git.proxmox.com Git - mirror_edk2.git/blob - MdeModulePkg/Universal/SetupBrowserDxe/Expression.c
Enable nest for suppressif/grayoutif/diableif for form/question/option.
[mirror_edk2.git] / MdeModulePkg / Universal / SetupBrowserDxe / Expression.c
1 /** @file
2 Utility functions for expression evaluation.
3
4 Copyright (c) 2007 - 2012, Intel Corporation. All rights reserved.<BR>
5 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 UINTN mExpressionEvaluationStackOffset = 0;
28
29 EFI_HII_VALUE *mCurrentExpressionStack = NULL;
30 EFI_HII_VALUE *mCurrentExpressionEnd = NULL;
31 EFI_HII_VALUE *mCurrentExpressionPointer = NULL;
32
33 EFI_HII_VALUE *mMapExpressionListStack = NULL;
34 EFI_HII_VALUE *mMapExpressionListEnd = NULL;
35 EFI_HII_VALUE *mMapExpressionListPointer = NULL;
36
37 FORM_EXPRESSION **mFormExpressionStack = NULL;
38 FORM_EXPRESSION **mFormExpressionEnd = NULL;
39 FORM_EXPRESSION **mFormExpressionPointer = NULL;
40
41 FORM_EXPRESSION **mStatementExpressionStack = NULL;
42 FORM_EXPRESSION **mStatementExpressionEnd = NULL;
43 FORM_EXPRESSION **mStatementExpressionPointer = NULL;
44
45 FORM_EXPRESSION **mOptionExpressionStack = NULL;
46 FORM_EXPRESSION **mOptionExpressionEnd = NULL;
47 FORM_EXPRESSION **mOptionExpressionPointer = NULL;
48
49
50 //
51 // Unicode collation protocol interface
52 //
53 EFI_UNICODE_COLLATION_PROTOCOL *mUnicodeCollation = NULL;
54 EFI_USER_MANAGER_PROTOCOL *mUserManager = NULL;
55
56 /**
57 Grow size of the stack.
58
59 This is an internal function.
60
61 @param Stack On input: old stack; On output: new stack
62 @param StackPtr On input: old stack pointer; On output: new stack
63 pointer
64 @param StackEnd On input: old stack end; On output: new stack end
65
66 @retval EFI_SUCCESS Grow stack success.
67 @retval EFI_OUT_OF_RESOURCES No enough memory for stack space.
68
69 **/
70 EFI_STATUS
71 GrowStack (
72 IN OUT EFI_HII_VALUE **Stack,
73 IN OUT EFI_HII_VALUE **StackPtr,
74 IN OUT EFI_HII_VALUE **StackEnd
75 )
76 {
77 UINTN Size;
78 EFI_HII_VALUE *NewStack;
79
80 Size = EXPRESSION_STACK_SIZE_INCREMENT;
81 if (*StackPtr != NULL) {
82 Size = Size + (*StackEnd - *Stack);
83 }
84
85 NewStack = AllocatePool (Size * sizeof (EFI_HII_VALUE));
86 if (NewStack == NULL) {
87 return EFI_OUT_OF_RESOURCES;
88 }
89
90 if (*StackPtr != NULL) {
91 //
92 // Copy from Old Stack to the New Stack
93 //
94 CopyMem (
95 NewStack,
96 *Stack,
97 (*StackEnd - *Stack) * sizeof (EFI_HII_VALUE)
98 );
99
100 //
101 // Free The Old Stack
102 //
103 FreePool (*Stack);
104 }
105
106 //
107 // Make the Stack pointer point to the old data in the new stack
108 //
109 *StackPtr = NewStack + (*StackPtr - *Stack);
110 *Stack = NewStack;
111 *StackEnd = NewStack + Size;
112
113 return EFI_SUCCESS;
114 }
115
116
117 /**
118 Push an element onto the Boolean Stack.
119
120 @param Stack On input: old stack; On output: new stack
121 @param StackPtr On input: old stack pointer; On output: new stack
122 pointer
123 @param StackEnd On input: old stack end; On output: new stack end
124 @param Data Data to push.
125
126 @retval EFI_SUCCESS Push stack success.
127
128 **/
129 EFI_STATUS
130 PushStack (
131 IN OUT EFI_HII_VALUE **Stack,
132 IN OUT EFI_HII_VALUE **StackPtr,
133 IN OUT EFI_HII_VALUE **StackEnd,
134 IN EFI_HII_VALUE *Data
135 )
136 {
137 EFI_STATUS Status;
138
139 //
140 // Check for a stack overflow condition
141 //
142 if (*StackPtr >= *StackEnd) {
143 //
144 // Grow the stack
145 //
146 Status = GrowStack (Stack, StackPtr, StackEnd);
147 if (EFI_ERROR (Status)) {
148 return Status;
149 }
150 }
151
152 //
153 // Push the item onto the stack
154 //
155 CopyMem (*StackPtr, Data, sizeof (EFI_HII_VALUE));
156 if (Data->Type == EFI_IFR_TYPE_BUFFER) {
157 (*StackPtr)->Buffer = AllocateCopyPool(Data->BufferLen, Data->Buffer);
158 ASSERT ((*StackPtr)->Buffer != NULL);
159 }
160
161 *StackPtr = *StackPtr + 1;
162
163 return EFI_SUCCESS;
164 }
165
166
167 /**
168 Pop an element from the stack.
169
170 @param Stack On input: old stack
171 @param StackPtr On input: old stack pointer; On output: new stack pointer
172 @param Data Data to pop.
173
174 @retval EFI_SUCCESS The value was popped onto the stack.
175 @retval EFI_ACCESS_DENIED The pop operation underflowed the stack
176
177 **/
178 EFI_STATUS
179 PopStack (
180 IN EFI_HII_VALUE *Stack,
181 IN OUT EFI_HII_VALUE **StackPtr,
182 OUT EFI_HII_VALUE *Data
183 )
184 {
185 //
186 // Check for a stack underflow condition
187 //
188 if (*StackPtr == Stack) {
189 return EFI_ACCESS_DENIED;
190 }
191
192 //
193 // Pop the item off the stack
194 //
195 *StackPtr = *StackPtr - 1;
196 CopyMem (Data, *StackPtr, sizeof (EFI_HII_VALUE));
197 return EFI_SUCCESS;
198 }
199
200
201 /**
202 Reset stack pointer to begin of the stack.
203
204 **/
205 VOID
206 ResetCurrentExpressionStack (
207 VOID
208 )
209 {
210 mCurrentExpressionPointer = mCurrentExpressionStack;
211 mFormExpressionPointer = mFormExpressionStack;
212 mStatementExpressionPointer = mStatementExpressionStack;
213 mOptionExpressionPointer = mOptionExpressionStack;
214 }
215
216
217 /**
218 Push current expression onto the Stack
219
220 @param Pointer Pointer to current expression.
221
222 @retval EFI_SUCCESS The value was pushed onto the stack.
223 @retval EFI_OUT_OF_RESOURCES There is not enough system memory to grow the stack.
224
225 **/
226 EFI_STATUS
227 PushCurrentExpression (
228 IN VOID *Pointer
229 )
230 {
231 EFI_HII_VALUE Data;
232
233 Data.Type = EFI_IFR_TYPE_NUM_SIZE_64;
234 Data.Value.u64 = (UINT64) (UINTN) Pointer;
235
236 return PushStack (
237 &mCurrentExpressionStack,
238 &mCurrentExpressionPointer,
239 &mCurrentExpressionEnd,
240 &Data
241 );
242 }
243
244
245 /**
246 Pop current expression from the Stack
247
248 @param Pointer Pointer to current expression to be pop.
249
250 @retval EFI_SUCCESS The value was pushed onto the stack.
251 @retval EFI_OUT_OF_RESOURCES There is not enough system memory to grow the stack.
252
253 **/
254 EFI_STATUS
255 PopCurrentExpression (
256 OUT VOID **Pointer
257 )
258 {
259 EFI_STATUS Status;
260 EFI_HII_VALUE Data;
261
262 Status = PopStack (
263 mCurrentExpressionStack,
264 &mCurrentExpressionPointer,
265 &Data
266 );
267
268 *Pointer = (VOID *) (UINTN) Data.Value.u64;
269
270 return Status;
271 }
272
273 /**
274 Reset stack pointer to begin of the stack.
275
276 **/
277 VOID
278 ResetMapExpressionListStack (
279 VOID
280 )
281 {
282 mMapExpressionListPointer = mMapExpressionListStack;
283 }
284
285
286 /**
287 Grow size of the stack.
288
289 This is an internal function.
290
291 @param Stack On input: old stack; On output: new stack
292 @param StackPtr On input: old stack pointer; On output: new stack
293 pointer
294 @param StackEnd On input: old stack end; On output: new stack end
295 @param MemberSize The stack member size.
296
297 @retval EFI_SUCCESS Grow stack success.
298 @retval EFI_OUT_OF_RESOURCES No enough memory for stack space.
299
300 **/
301 EFI_STATUS
302 GrowConditionalStack (
303 IN OUT FORM_EXPRESSION ***Stack,
304 IN OUT FORM_EXPRESSION ***StackPtr,
305 IN OUT FORM_EXPRESSION ***StackEnd,
306 IN UINTN MemberSize
307 )
308 {
309 UINTN Size;
310 FORM_EXPRESSION **NewStack;
311
312 Size = EXPRESSION_STACK_SIZE_INCREMENT;
313 if (*StackPtr != NULL) {
314 Size = Size + (*StackEnd - *Stack);
315 }
316
317 NewStack = AllocatePool (Size * MemberSize);
318 if (NewStack == NULL) {
319 return EFI_OUT_OF_RESOURCES;
320 }
321
322 if (*StackPtr != NULL) {
323 //
324 // Copy from Old Stack to the New Stack
325 //
326 CopyMem (
327 NewStack,
328 *Stack,
329 (*StackEnd - *Stack) * MemberSize
330 );
331
332 //
333 // Free The Old Stack
334 //
335 FreePool (*Stack);
336 }
337
338 //
339 // Make the Stack pointer point to the old data in the new stack
340 //
341 *StackPtr = NewStack + (*StackPtr - *Stack);
342 *Stack = NewStack;
343 *StackEnd = NewStack + Size;
344
345 return EFI_SUCCESS;
346 }
347
348 /**
349 Push an element onto the Stack.
350
351 @param Stack On input: old stack; On output: new stack
352 @param StackPtr On input: old stack pointer; On output: new stack
353 pointer
354 @param StackEnd On input: old stack end; On output: new stack end
355 @param Data Data to push.
356
357 @retval EFI_SUCCESS Push stack success.
358
359 **/
360 EFI_STATUS
361 PushConditionalStack (
362 IN OUT FORM_EXPRESSION ***Stack,
363 IN OUT FORM_EXPRESSION ***StackPtr,
364 IN OUT FORM_EXPRESSION ***StackEnd,
365 IN FORM_EXPRESSION **Data
366 )
367 {
368 EFI_STATUS Status;
369
370 //
371 // Check for a stack overflow condition
372 //
373 if (*StackPtr >= *StackEnd) {
374 //
375 // Grow the stack
376 //
377 Status = GrowConditionalStack (Stack, StackPtr, StackEnd, sizeof (FORM_EXPRESSION *));
378 if (EFI_ERROR (Status)) {
379 return Status;
380 }
381 }
382
383 //
384 // Push the item onto the stack
385 //
386 CopyMem (*StackPtr, Data, sizeof (FORM_EXPRESSION *));
387 *StackPtr = *StackPtr + 1;
388
389 return EFI_SUCCESS;
390
391 }
392
393 /**
394 Pop an element from the stack.
395
396 @param Stack On input: old stack
397 @param StackPtr On input: old stack pointer; On output: new stack pointer
398 @param Data Data to pop.
399
400 @retval EFI_SUCCESS The value was popped onto the stack.
401 @retval EFI_ACCESS_DENIED The pop operation underflowed the stack
402
403 **/
404 EFI_STATUS
405 PopConditionalStack (
406 IN FORM_EXPRESSION **Stack,
407 IN OUT FORM_EXPRESSION ***StackPtr,
408 OUT FORM_EXPRESSION **Data
409 )
410 {
411 //
412 // Check for a stack underflow condition
413 //
414 if (*StackPtr == Stack) {
415 return EFI_ACCESS_DENIED;
416 }
417
418 //
419 // Pop the item off the stack
420 //
421 *StackPtr = *StackPtr - 1;
422 CopyMem (Data, *StackPtr, sizeof (FORM_EXPRESSION *));
423 return EFI_SUCCESS;
424
425 }
426
427 /**
428 Get the expression list count.
429
430 @param Level Which type this expression belong to. Form,
431 statement or option?
432
433 @retval >=0 The expression count
434 @retval -1 Input parameter error.
435
436 **/
437 INTN
438 GetConditionalExpressionCount (
439 IN EXPRESS_LEVEL Level
440 )
441 {
442 switch (Level) {
443 case ExpressForm:
444 return mFormExpressionPointer - mFormExpressionStack;
445 case ExpressStatement:
446 return mStatementExpressionPointer - mStatementExpressionStack;
447 case ExpressOption:
448 return mOptionExpressionPointer - mOptionExpressionStack;
449 default:
450 ASSERT (FALSE);
451 return -1;
452 }
453 }
454
455 /**
456 Get the expression Buffer pointer.
457
458 @param Level Which type this expression belong to. Form,
459 statement or option?
460
461 @retval The start pointer of the expression buffer or NULL.
462
463 **/
464 FORM_EXPRESSION **
465 GetConditionalExpressionList (
466 IN EXPRESS_LEVEL Level
467 )
468 {
469 switch (Level) {
470 case ExpressForm:
471 return mFormExpressionStack;
472 case ExpressStatement:
473 return mStatementExpressionStack;
474 case ExpressOption:
475 return mOptionExpressionStack;
476 default:
477 ASSERT (FALSE);
478 return NULL;
479 }
480 }
481
482
483 /**
484 Push the expression options onto the Stack.
485
486 @param Pointer Pointer to the current expression.
487 @param Level Which type this expression belong to. Form,
488 statement or option?
489
490 @retval EFI_SUCCESS The value was pushed onto the stack.
491 @retval EFI_OUT_OF_RESOURCES There is not enough system memory to grow the stack.
492
493 **/
494 EFI_STATUS
495 PushConditionalExpression (
496 IN FORM_EXPRESSION *Pointer,
497 IN EXPRESS_LEVEL Level
498 )
499 {
500 switch (Level) {
501 case ExpressForm:
502 return PushConditionalStack (
503 &mFormExpressionStack,
504 &mFormExpressionPointer,
505 &mFormExpressionEnd,
506 &Pointer
507 );
508 case ExpressStatement:
509 return PushConditionalStack (
510 &mStatementExpressionStack,
511 &mStatementExpressionPointer,
512 &mStatementExpressionEnd,
513 &Pointer
514 );
515 case ExpressOption:
516 return PushConditionalStack (
517 &mOptionExpressionStack,
518 &mOptionExpressionPointer,
519 &mOptionExpressionEnd,
520 &Pointer
521 );
522 default:
523 ASSERT (FALSE);
524 return EFI_INVALID_PARAMETER;
525 }
526 }
527
528 /**
529 Pop the expression options from the Stack
530
531 @param Level Which type this expression belong to. Form,
532 statement or option?
533
534 @retval EFI_SUCCESS The value was pushed onto the stack.
535 @retval EFI_OUT_OF_RESOURCES There is not enough system memory to grow the stack.
536
537 **/
538 EFI_STATUS
539 PopConditionalExpression (
540 IN EXPRESS_LEVEL Level
541 )
542 {
543 FORM_EXPRESSION *Pointer;
544
545 switch (Level) {
546 case ExpressForm:
547 return PopConditionalStack (
548 mFormExpressionStack,
549 &mFormExpressionPointer,
550 &Pointer
551 );
552
553 case ExpressStatement:
554 return PopConditionalStack (
555 mStatementExpressionStack,
556 &mStatementExpressionPointer,
557 &Pointer
558 );
559
560 case ExpressOption:
561 return PopConditionalStack (
562 mOptionExpressionStack,
563 &mOptionExpressionPointer,
564 &Pointer
565 );
566
567 default:
568 ASSERT (FALSE);
569 return EFI_INVALID_PARAMETER;
570 }
571 }
572
573
574 /**
575 Push the list of map expression onto the Stack
576
577 @param Pointer Pointer to the list of map expression to be pushed.
578
579 @retval EFI_SUCCESS The value was pushed onto the stack.
580 @retval EFI_OUT_OF_RESOURCES There is not enough system memory to grow the stack.
581
582 **/
583 EFI_STATUS
584 PushMapExpressionList (
585 IN VOID *Pointer
586 )
587 {
588 EFI_HII_VALUE Data;
589
590 Data.Type = EFI_IFR_TYPE_NUM_SIZE_64;
591 Data.Value.u64 = (UINT64) (UINTN) Pointer;
592
593 return PushStack (
594 &mMapExpressionListStack,
595 &mMapExpressionListPointer,
596 &mMapExpressionListEnd,
597 &Data
598 );
599 }
600
601
602 /**
603 Pop the list of map expression from the Stack
604
605 @param Pointer Pointer to the list of map expression to be pop.
606
607 @retval EFI_SUCCESS The value was pushed onto the stack.
608 @retval EFI_OUT_OF_RESOURCES There is not enough system memory to grow the stack.
609
610 **/
611 EFI_STATUS
612 PopMapExpressionList (
613 OUT VOID **Pointer
614 )
615 {
616 EFI_STATUS Status;
617 EFI_HII_VALUE Data;
618
619 Status = PopStack (
620 mMapExpressionListStack,
621 &mMapExpressionListPointer,
622 &Data
623 );
624
625 *Pointer = (VOID *) (UINTN) Data.Value.u64;
626
627 return Status;
628 }
629
630 /**
631 Reset stack pointer to begin of the stack.
632
633 **/
634 VOID
635 ResetScopeStack (
636 VOID
637 )
638 {
639 mOpCodeScopeStackPointer = mOpCodeScopeStack;
640 }
641
642
643 /**
644 Push an Operand onto the Stack
645
646 @param Operand Operand to push.
647
648 @retval EFI_SUCCESS The value was pushed onto the stack.
649 @retval EFI_OUT_OF_RESOURCES There is not enough system memory to grow the
650 stack.
651
652 **/
653 EFI_STATUS
654 PushScope (
655 IN UINT8 Operand
656 )
657 {
658 EFI_HII_VALUE Data;
659
660 Data.Type = EFI_IFR_TYPE_NUM_SIZE_8;
661 Data.Value.u8 = Operand;
662
663 return PushStack (
664 &mOpCodeScopeStack,
665 &mOpCodeScopeStackPointer,
666 &mOpCodeScopeStackEnd,
667 &Data
668 );
669 }
670
671
672 /**
673 Pop an Operand from the Stack
674
675 @param Operand Operand to pop.
676
677 @retval EFI_SUCCESS The value was pushed onto the stack.
678 @retval EFI_OUT_OF_RESOURCES There is not enough system memory to grow the
679 stack.
680
681 **/
682 EFI_STATUS
683 PopScope (
684 OUT UINT8 *Operand
685 )
686 {
687 EFI_STATUS Status;
688 EFI_HII_VALUE Data;
689
690 Status = PopStack (
691 mOpCodeScopeStack,
692 &mOpCodeScopeStackPointer,
693 &Data
694 );
695
696 *Operand = Data.Value.u8;
697
698 return Status;
699 }
700
701
702 /**
703 Push an Expression value onto the Stack
704
705 @param Value Expression value to push.
706
707 @retval EFI_SUCCESS The value was pushed onto the stack.
708 @retval EFI_OUT_OF_RESOURCES There is not enough system memory to grow the
709 stack.
710
711 **/
712 EFI_STATUS
713 PushExpression (
714 IN EFI_HII_VALUE *Value
715 )
716 {
717 return PushStack (
718 &mExpressionEvaluationStack,
719 &mExpressionEvaluationStackPointer,
720 &mExpressionEvaluationStackEnd,
721 Value
722 );
723 }
724
725
726 /**
727 Pop an Expression value from the stack.
728
729 @param Value Expression value to pop.
730
731 @retval EFI_SUCCESS The value was popped onto the stack.
732 @retval EFI_ACCESS_DENIED The pop operation underflowed the stack
733
734 **/
735 EFI_STATUS
736 PopExpression (
737 OUT EFI_HII_VALUE *Value
738 )
739 {
740 return PopStack (
741 mExpressionEvaluationStack + mExpressionEvaluationStackOffset,
742 &mExpressionEvaluationStackPointer,
743 Value
744 );
745 }
746
747 /**
748 Get current stack offset from stack start.
749
750 @return Stack offset to stack start.
751 **/
752 UINTN
753 SaveExpressionEvaluationStackOffset (
754 )
755 {
756 UINTN TempStackOffset;
757 TempStackOffset = mExpressionEvaluationStackOffset;
758 mExpressionEvaluationStackOffset = mExpressionEvaluationStackPointer - mExpressionEvaluationStack;
759 return TempStackOffset;
760 }
761
762 /**
763 Restore stack offset based on input stack offset
764
765 @param StackOffset Offset to stack start.
766
767 **/
768 VOID
769 RestoreExpressionEvaluationStackOffset (
770 UINTN StackOffset
771 )
772 {
773 mExpressionEvaluationStackOffset = StackOffset;
774 }
775
776 /**
777 Get Form given its FormId.
778
779 @param FormSet The formset which contains this form.
780 @param FormId Id of this form.
781
782 @retval Pointer The form.
783 @retval NULL Specified Form is not found in the formset.
784
785 **/
786 FORM_BROWSER_FORM *
787 IdToForm (
788 IN FORM_BROWSER_FORMSET *FormSet,
789 IN UINT16 FormId
790 )
791 {
792 LIST_ENTRY *Link;
793 FORM_BROWSER_FORM *Form;
794
795 Link = GetFirstNode (&FormSet->FormListHead);
796 while (!IsNull (&FormSet->FormListHead, Link)) {
797 Form = FORM_BROWSER_FORM_FROM_LINK (Link);
798
799 if (Form->FormId == FormId) {
800 return Form;
801 }
802
803 Link = GetNextNode (&FormSet->FormListHead, Link);
804 }
805
806 return NULL;
807 }
808
809
810 /**
811 Search a Question in Form scope using its QuestionId.
812
813 @param Form The form which contains this Question.
814 @param QuestionId Id of this Question.
815
816 @retval Pointer The Question.
817 @retval NULL Specified Question not found in the form.
818
819 **/
820 FORM_BROWSER_STATEMENT *
821 IdToQuestion2 (
822 IN FORM_BROWSER_FORM *Form,
823 IN UINT16 QuestionId
824 )
825 {
826 LIST_ENTRY *Link;
827 FORM_BROWSER_STATEMENT *Question;
828
829 if (QuestionId == 0 || Form == NULL) {
830 //
831 // The value of zero is reserved
832 //
833 return NULL;
834 }
835
836 Link = GetFirstNode (&Form->StatementListHead);
837 while (!IsNull (&Form->StatementListHead, Link)) {
838 Question = FORM_BROWSER_STATEMENT_FROM_LINK (Link);
839
840 if (Question->QuestionId == QuestionId) {
841 return Question;
842 }
843
844 Link = GetNextNode (&Form->StatementListHead, Link);
845 }
846
847 return NULL;
848 }
849
850
851 /**
852 Search a Question in Formset scope using its QuestionId.
853
854 @param FormSet The formset which contains this form.
855 @param Form The form which contains this Question.
856 @param QuestionId Id of this Question.
857
858 @retval Pointer The Question.
859 @retval NULL Specified Question not found in the form.
860
861 **/
862 FORM_BROWSER_STATEMENT *
863 IdToQuestion (
864 IN FORM_BROWSER_FORMSET *FormSet,
865 IN FORM_BROWSER_FORM *Form,
866 IN UINT16 QuestionId
867 )
868 {
869 LIST_ENTRY *Link;
870 FORM_BROWSER_STATEMENT *Question;
871
872 //
873 // Search in the form scope first
874 //
875 Question = IdToQuestion2 (Form, QuestionId);
876 if (Question != NULL) {
877 return Question;
878 }
879
880 //
881 // Search in the formset scope
882 //
883 Link = GetFirstNode (&FormSet->FormListHead);
884 while (!IsNull (&FormSet->FormListHead, Link)) {
885 Form = FORM_BROWSER_FORM_FROM_LINK (Link);
886
887 Question = IdToQuestion2 (Form, QuestionId);
888 if (Question != NULL) {
889 //
890 // EFI variable storage may be updated by Callback() asynchronous,
891 // to keep synchronous, always reload the Question Value.
892 //
893 if (Question->Storage->Type == EFI_HII_VARSTORE_EFI_VARIABLE) {
894 GetQuestionValue (FormSet, Form, Question, FALSE);
895 }
896
897 return Question;
898 }
899
900 Link = GetNextNode (&FormSet->FormListHead, Link);
901 }
902
903 return NULL;
904 }
905
906
907 /**
908 Get Expression given its RuleId.
909
910 @param Form The form which contains this Expression.
911 @param RuleId Id of this Expression.
912
913 @retval Pointer The Expression.
914 @retval NULL Specified Expression not found in the form.
915
916 **/
917 FORM_EXPRESSION *
918 RuleIdToExpression (
919 IN FORM_BROWSER_FORM *Form,
920 IN UINT8 RuleId
921 )
922 {
923 LIST_ENTRY *Link;
924 FORM_EXPRESSION *Expression;
925
926 Link = GetFirstNode (&Form->ExpressionListHead);
927 while (!IsNull (&Form->ExpressionListHead, Link)) {
928 Expression = FORM_EXPRESSION_FROM_LINK (Link);
929
930 if (Expression->Type == EFI_HII_EXPRESSION_RULE && Expression->RuleId == RuleId) {
931 return Expression;
932 }
933
934 Link = GetNextNode (&Form->ExpressionListHead, Link);
935 }
936
937 return NULL;
938 }
939
940
941 /**
942 Locate the Unicode Collation Protocol interface for later use.
943
944 @retval EFI_SUCCESS Protocol interface initialize success.
945 @retval Other Protocol interface initialize failed.
946
947 **/
948 EFI_STATUS
949 InitializeUnicodeCollationProtocol (
950 VOID
951 )
952 {
953 EFI_STATUS Status;
954
955 if (mUnicodeCollation != NULL) {
956 return EFI_SUCCESS;
957 }
958
959 //
960 // BUGBUG: Proper impelmentation is to locate all Unicode Collation Protocol
961 // instances first and then select one which support English language.
962 // Current implementation just pick the first instance.
963 //
964 Status = gBS->LocateProtocol (
965 &gEfiUnicodeCollation2ProtocolGuid,
966 NULL,
967 (VOID **) &mUnicodeCollation
968 );
969 return Status;
970 }
971
972 /**
973 Convert the input Unicode character to upper.
974
975 @param String Th Unicode character to be converted.
976
977 **/
978 VOID
979 IfrStrToUpper (
980 IN CHAR16 *String
981 )
982 {
983 while (*String != 0) {
984 if ((*String >= 'a') && (*String <= 'z')) {
985 *String = (UINT16) ((*String) & ((UINT16) ~0x20));
986 }
987 String++;
988 }
989 }
990
991
992 /**
993 Evaluate opcode EFI_IFR_TO_STRING.
994
995 @param FormSet Formset which contains this opcode.
996 @param Format String format in EFI_IFR_TO_STRING.
997 @param Result Evaluation result for this opcode.
998
999 @retval EFI_SUCCESS Opcode evaluation success.
1000 @retval Other Opcode evaluation failed.
1001
1002 **/
1003 EFI_STATUS
1004 IfrToString (
1005 IN FORM_BROWSER_FORMSET *FormSet,
1006 IN UINT8 Format,
1007 OUT EFI_HII_VALUE *Result
1008 )
1009 {
1010 EFI_STATUS Status;
1011 EFI_HII_VALUE Value;
1012 CHAR16 *String;
1013 CHAR16 *PrintFormat;
1014 CHAR16 Buffer[MAXIMUM_VALUE_CHARACTERS];
1015 UINT8 *TmpBuf;
1016 UINTN BufferSize;
1017
1018 Status = PopExpression (&Value);
1019 if (EFI_ERROR (Status)) {
1020 return Status;
1021 }
1022
1023 switch (Value.Type) {
1024 case EFI_IFR_TYPE_NUM_SIZE_8:
1025 case EFI_IFR_TYPE_NUM_SIZE_16:
1026 case EFI_IFR_TYPE_NUM_SIZE_32:
1027 case EFI_IFR_TYPE_NUM_SIZE_64:
1028 BufferSize = MAXIMUM_VALUE_CHARACTERS * sizeof (CHAR16);
1029 switch (Format) {
1030 case EFI_IFR_STRING_UNSIGNED_DEC:
1031 case EFI_IFR_STRING_SIGNED_DEC:
1032 PrintFormat = L"%ld";
1033 break;
1034
1035 case EFI_IFR_STRING_LOWERCASE_HEX:
1036 PrintFormat = L"%lx";
1037 break;
1038
1039 case EFI_IFR_STRING_UPPERCASE_HEX:
1040 PrintFormat = L"%lX";
1041 break;
1042
1043 default:
1044 return EFI_UNSUPPORTED;
1045 }
1046 UnicodeSPrint (Buffer, BufferSize, PrintFormat, Value.Value.u64);
1047 String = Buffer;
1048 break;
1049
1050 case EFI_IFR_TYPE_STRING:
1051 CopyMem (Result, &Value, sizeof (EFI_HII_VALUE));
1052 return EFI_SUCCESS;
1053
1054 case EFI_IFR_TYPE_BOOLEAN:
1055 String = (Value.Value.b) ? L"True" : L"False";
1056 break;
1057
1058 case EFI_IFR_TYPE_BUFFER:
1059 //
1060 // + 3 is base on the unicode format, the length may be odd number,
1061 // so need 1 byte to align, also need 2 bytes for L'\0'.
1062 //
1063 TmpBuf = AllocateZeroPool (Value.BufferLen + 3);
1064 ASSERT (TmpBuf != NULL);
1065 if (Format == EFI_IFR_STRING_ASCII) {
1066 CopyMem (TmpBuf, Value.Buffer, Value.BufferLen);
1067 PrintFormat = L"%a";
1068 } else {
1069 // Format == EFI_IFR_STRING_UNICODE
1070 CopyMem (TmpBuf, Value.Buffer, Value.BufferLen * sizeof (CHAR16));
1071 PrintFormat = L"%s";
1072 }
1073 UnicodeSPrint (Buffer, MAXIMUM_VALUE_CHARACTERS, PrintFormat, Value.Buffer);
1074 String = Buffer;
1075 FreePool (TmpBuf);
1076 FreePool (Value.Buffer);
1077 break;
1078
1079 default:
1080 return EFI_UNSUPPORTED;
1081 }
1082
1083 Result->Type = EFI_IFR_TYPE_STRING;
1084 Result->Value.string = NewString (String, FormSet->HiiHandle);
1085 return EFI_SUCCESS;
1086 }
1087
1088
1089 /**
1090 Evaluate opcode EFI_IFR_TO_UINT.
1091
1092 @param FormSet Formset which contains this opcode.
1093 @param Result Evaluation result for this opcode.
1094
1095 @retval EFI_SUCCESS Opcode evaluation success.
1096 @retval Other Opcode evaluation failed.
1097
1098 **/
1099 EFI_STATUS
1100 IfrToUint (
1101 IN FORM_BROWSER_FORMSET *FormSet,
1102 OUT EFI_HII_VALUE *Result
1103 )
1104 {
1105 EFI_STATUS Status;
1106 EFI_HII_VALUE Value;
1107 CHAR16 *String;
1108 CHAR16 *StringPtr;
1109
1110 Status = PopExpression (&Value);
1111 if (EFI_ERROR (Status)) {
1112 return Status;
1113 }
1114
1115 if (Value.Type >= EFI_IFR_TYPE_OTHER && Value.Type != EFI_IFR_TYPE_BUFFER) {
1116 return EFI_UNSUPPORTED;
1117 }
1118
1119 Status = EFI_SUCCESS;
1120 if (Value.Type == EFI_IFR_TYPE_STRING) {
1121 String = GetToken (Value.Value.string, FormSet->HiiHandle);
1122 if (String == NULL) {
1123 return EFI_NOT_FOUND;
1124 }
1125
1126 IfrStrToUpper (String);
1127 StringPtr = StrStr (String, L"0X");
1128 if (StringPtr != NULL) {
1129 //
1130 // Hex string
1131 //
1132 Result->Value.u64 = StrHexToUint64 (String);
1133 } else {
1134 //
1135 // decimal string
1136 //
1137 Result->Value.u64 = StrDecimalToUint64 (String);
1138 }
1139 FreePool (String);
1140 } else if (Value.Type == EFI_IFR_TYPE_BUFFER) {
1141 if (Value.BufferLen > 8) {
1142 FreePool (Value.Buffer);
1143 return EFI_UNSUPPORTED;
1144 }
1145 Result->Value.u64 = *(UINT64*) Value.Buffer;
1146 FreePool (Value.Buffer);
1147 } else {
1148 CopyMem (Result, &Value, sizeof (EFI_HII_VALUE));
1149 }
1150
1151 Result->Type = EFI_IFR_TYPE_NUM_SIZE_64;
1152 return Status;
1153 }
1154
1155
1156 /**
1157 Evaluate opcode EFI_IFR_CATENATE.
1158
1159 @param FormSet Formset which contains this opcode.
1160 @param Result Evaluation result for this opcode.
1161
1162 @retval EFI_SUCCESS Opcode evaluation success.
1163 @retval Other Opcode evaluation failed.
1164
1165 **/
1166 EFI_STATUS
1167 IfrCatenate (
1168 IN FORM_BROWSER_FORMSET *FormSet,
1169 OUT EFI_HII_VALUE *Result
1170 )
1171 {
1172 EFI_STATUS Status;
1173 EFI_HII_VALUE Value[2];
1174 CHAR16 *String[2];
1175 UINTN Index;
1176 CHAR16 *StringPtr;
1177 UINTN Size;
1178
1179 //
1180 // String[0] - The second string
1181 // String[1] - The first string
1182 //
1183 String[0] = NULL;
1184 String[1] = NULL;
1185 StringPtr = NULL;
1186 Status = EFI_SUCCESS;
1187 ZeroMem (Value, sizeof (Value));
1188
1189 for (Index = 0; Index < 2; Index++) {
1190 Status = PopExpression (&Value[Index]);
1191 if (EFI_ERROR (Status)) {
1192 goto Done;
1193 }
1194
1195 if (Value[Index].Type != EFI_IFR_TYPE_STRING && Value[Index].Type != EFI_IFR_TYPE_BUFFER) {
1196 Status = EFI_UNSUPPORTED;
1197 goto Done;
1198 }
1199
1200 if (Value[Index].Type == EFI_IFR_TYPE_STRING) {
1201 String[Index] = GetToken (Value[Index].Value.string, FormSet->HiiHandle);
1202 if (String[Index] == NULL) {
1203 Status = EFI_NOT_FOUND;
1204 goto Done;
1205 }
1206 }
1207 }
1208
1209 if (Value[0].Type == EFI_IFR_TYPE_STRING) {
1210 Size = StrSize (String[0]);
1211 StringPtr= AllocatePool (StrSize (String[1]) + Size);
1212 ASSERT (StringPtr != NULL);
1213 StrCpy (StringPtr, String[1]);
1214 StrCat (StringPtr, String[0]);
1215
1216 Result->Type = EFI_IFR_TYPE_STRING;
1217 Result->Value.string = NewString (StringPtr, FormSet->HiiHandle);
1218 } else {
1219 Result->Type = EFI_IFR_TYPE_BUFFER;
1220 Result->BufferLen = (UINT16) (Value[0].BufferLen + Value[1].BufferLen);
1221
1222 Result->Buffer = AllocateZeroPool (Result->BufferLen);
1223 ASSERT (Result->Buffer != NULL);
1224
1225 CopyMem (Result->Buffer, Value[0].Buffer, Value[0].BufferLen);
1226 CopyMem (&Result->Buffer[Value[0].BufferLen], Value[1].Buffer, Value[1].BufferLen);
1227 }
1228 Done:
1229 if (Value[0].Buffer != NULL) {
1230 FreePool (Value[0].Buffer);
1231 }
1232 if (Value[1].Buffer != NULL) {
1233 FreePool (Value[1].Buffer);
1234 }
1235 if (String[0] != NULL) {
1236 FreePool (String[0]);
1237 }
1238 if (String[1] != NULL) {
1239 FreePool (String[1]);
1240 }
1241 if (StringPtr != NULL) {
1242 FreePool (StringPtr);
1243 }
1244
1245 return Status;
1246 }
1247
1248
1249 /**
1250 Evaluate opcode EFI_IFR_MATCH.
1251
1252 @param FormSet Formset which contains this opcode.
1253 @param Result Evaluation result for this opcode.
1254
1255 @retval EFI_SUCCESS Opcode evaluation success.
1256 @retval Other Opcode evaluation failed.
1257
1258 **/
1259 EFI_STATUS
1260 IfrMatch (
1261 IN FORM_BROWSER_FORMSET *FormSet,
1262 OUT EFI_HII_VALUE *Result
1263 )
1264 {
1265 EFI_STATUS Status;
1266 EFI_HII_VALUE Value;
1267 CHAR16 *String[2];
1268 UINTN Index;
1269
1270 //
1271 // String[0] - The string to search
1272 // String[1] - pattern
1273 //
1274 String[0] = NULL;
1275 String[1] = NULL;
1276 Status = EFI_SUCCESS;
1277 for (Index = 0; Index < 2; Index++) {
1278 Status = PopExpression (&Value);
1279 if (EFI_ERROR (Status)) {
1280 goto Done;
1281 }
1282
1283 if (Value.Type != EFI_IFR_TYPE_STRING) {
1284 Status = EFI_UNSUPPORTED;
1285 goto Done;
1286 }
1287
1288 String[Index] = GetToken (Value.Value.string, FormSet->HiiHandle);
1289 if (String [Index] == NULL) {
1290 Status = EFI_NOT_FOUND;
1291 goto Done;
1292 }
1293 }
1294
1295 Result->Type = EFI_IFR_TYPE_BOOLEAN;
1296 Result->Value.b = mUnicodeCollation->MetaiMatch (mUnicodeCollation, String[0], String[1]);
1297
1298 Done:
1299 if (String[0] != NULL) {
1300 FreePool (String[0]);
1301 }
1302 if (String[1] != NULL) {
1303 FreePool (String[1]);
1304 }
1305
1306 return Status;
1307 }
1308
1309
1310 /**
1311 Evaluate opcode EFI_IFR_FIND.
1312
1313 @param FormSet Formset which contains this opcode.
1314 @param Format Case sensitive or insensitive.
1315 @param Result Evaluation result for this opcode.
1316
1317 @retval EFI_SUCCESS Opcode evaluation success.
1318 @retval Other Opcode evaluation failed.
1319
1320 **/
1321 EFI_STATUS
1322 IfrFind (
1323 IN FORM_BROWSER_FORMSET *FormSet,
1324 IN UINT8 Format,
1325 OUT EFI_HII_VALUE *Result
1326 )
1327 {
1328 EFI_STATUS Status;
1329 EFI_HII_VALUE Value;
1330 CHAR16 *String[2];
1331 UINTN Base;
1332 CHAR16 *StringPtr;
1333 UINTN Index;
1334
1335 if (Format > EFI_IFR_FF_CASE_INSENSITIVE) {
1336 return EFI_UNSUPPORTED;
1337 }
1338
1339 Status = PopExpression (&Value);
1340 if (EFI_ERROR (Status)) {
1341 return Status;
1342 }
1343 if (Value.Type > EFI_IFR_TYPE_NUM_SIZE_64) {
1344 return EFI_UNSUPPORTED;
1345 }
1346 Base = (UINTN) Value.Value.u64;
1347
1348 //
1349 // String[0] - sub-string
1350 // String[1] - The string to search
1351 //
1352 String[0] = NULL;
1353 String[1] = NULL;
1354 for (Index = 0; Index < 2; Index++) {
1355 Status = PopExpression (&Value);
1356 if (EFI_ERROR (Status)) {
1357 goto Done;
1358 }
1359
1360 if (Value.Type != EFI_IFR_TYPE_STRING) {
1361 Status = EFI_UNSUPPORTED;
1362 goto Done;
1363 }
1364
1365 String[Index] = GetToken (Value.Value.string, FormSet->HiiHandle);
1366 if (String[Index] == NULL) {
1367 Status = EFI_NOT_FOUND;
1368 goto Done;
1369 }
1370
1371 if (Format == EFI_IFR_FF_CASE_INSENSITIVE) {
1372 //
1373 // Case insensitive, convert both string to upper case
1374 //
1375 IfrStrToUpper (String[Index]);
1376 }
1377 }
1378
1379 Result->Type = EFI_IFR_TYPE_NUM_SIZE_64;
1380 if (Base >= StrLen (String[1])) {
1381 Result->Value.u64 = 0xFFFFFFFFFFFFFFFFULL;
1382 } else {
1383 StringPtr = StrStr (String[1] + Base, String[0]);
1384 Result->Value.u64 = (StringPtr == NULL) ? 0xFFFFFFFFFFFFFFFFULL : (StringPtr - String[1]);
1385 }
1386
1387 Done:
1388 if (String[0] != NULL) {
1389 FreePool (String[0]);
1390 }
1391 if (String[1] != NULL) {
1392 FreePool (String[1]);
1393 }
1394
1395 return Status;
1396 }
1397
1398
1399 /**
1400 Evaluate opcode EFI_IFR_MID.
1401
1402 @param FormSet Formset which contains this opcode.
1403 @param Result Evaluation result for this opcode.
1404
1405 @retval EFI_SUCCESS Opcode evaluation success.
1406 @retval Other Opcode evaluation failed.
1407
1408 **/
1409 EFI_STATUS
1410 IfrMid (
1411 IN FORM_BROWSER_FORMSET *FormSet,
1412 OUT EFI_HII_VALUE *Result
1413 )
1414 {
1415 EFI_STATUS Status;
1416 EFI_HII_VALUE Value;
1417 CHAR16 *String;
1418 UINTN Base;
1419 UINTN Length;
1420 CHAR16 *SubString;
1421 UINT8 *Buffer;
1422 UINT16 BufferLen;
1423
1424 Status = PopExpression (&Value);
1425 if (EFI_ERROR (Status)) {
1426 return Status;
1427 }
1428 if (Value.Type > EFI_IFR_TYPE_NUM_SIZE_64) {
1429 return EFI_UNSUPPORTED;
1430 }
1431 Length = (UINTN) Value.Value.u64;
1432
1433 Status = PopExpression (&Value);
1434 if (EFI_ERROR (Status)) {
1435 return Status;
1436 }
1437 if (Value.Type > EFI_IFR_TYPE_NUM_SIZE_64) {
1438 return EFI_UNSUPPORTED;
1439 }
1440 Base = (UINTN) Value.Value.u64;
1441
1442 Status = PopExpression (&Value);
1443 if (EFI_ERROR (Status)) {
1444 return Status;
1445 }
1446 if (Value.Type != EFI_IFR_TYPE_STRING && Value.Type != EFI_IFR_TYPE_BUFFER) {
1447 return EFI_UNSUPPORTED;
1448 }
1449 if (Value.Type == EFI_IFR_TYPE_STRING) {
1450 String = GetToken (Value.Value.string, FormSet->HiiHandle);
1451 if (String == NULL) {
1452 return EFI_NOT_FOUND;
1453 }
1454
1455 if (Length == 0 || Base >= StrLen (String)) {
1456 SubString = gEmptyString;
1457 } else {
1458 SubString = String + Base;
1459 if ((Base + Length) < StrLen (String)) {
1460 SubString[Length] = L'\0';
1461 }
1462 }
1463
1464 Result->Type = EFI_IFR_TYPE_STRING;
1465 Result->Value.string = NewString (SubString, FormSet->HiiHandle);
1466
1467 FreePool (String);
1468 } else {
1469 Buffer = Value.Buffer;
1470 BufferLen = Value.BufferLen;
1471
1472 Result->Type = EFI_IFR_TYPE_BUFFER;
1473 if (Length == 0 || Base >= BufferLen) {
1474 Result->BufferLen = 0;
1475 Result->Buffer = NULL;
1476 } else {
1477 Result->BufferLen = (UINT16)((BufferLen - Base) < Length ? (BufferLen - Base) : Length);
1478 Result->Buffer = AllocateZeroPool (Result->BufferLen);
1479 ASSERT (Result->Buffer != NULL);
1480 CopyMem (Result->Buffer, &Value.Buffer[Base], Result->BufferLen);
1481 }
1482
1483 FreePool (Value.Buffer);
1484 }
1485
1486 return Status;
1487 }
1488
1489
1490 /**
1491 Evaluate opcode EFI_IFR_TOKEN.
1492
1493 @param FormSet Formset which contains this opcode.
1494 @param Result Evaluation result for this opcode.
1495
1496 @retval EFI_SUCCESS Opcode evaluation success.
1497 @retval Other Opcode evaluation failed.
1498
1499 **/
1500 EFI_STATUS
1501 IfrToken (
1502 IN FORM_BROWSER_FORMSET *FormSet,
1503 OUT EFI_HII_VALUE *Result
1504 )
1505 {
1506 EFI_STATUS Status;
1507 EFI_HII_VALUE Value;
1508 CHAR16 *String[2];
1509 UINTN Count;
1510 CHAR16 *Delimiter;
1511 CHAR16 *SubString;
1512 CHAR16 *StringPtr;
1513 UINTN Index;
1514
1515 Status = PopExpression (&Value);
1516 if (EFI_ERROR (Status)) {
1517 return Status;
1518 }
1519 if (Value.Type > EFI_IFR_TYPE_NUM_SIZE_64) {
1520 return EFI_UNSUPPORTED;
1521 }
1522 Count = (UINTN) Value.Value.u64;
1523
1524 //
1525 // String[0] - Delimiter
1526 // String[1] - The string to search
1527 //
1528 String[0] = NULL;
1529 String[1] = NULL;
1530 for (Index = 0; Index < 2; Index++) {
1531 Status = PopExpression (&Value);
1532 if (EFI_ERROR (Status)) {
1533 goto Done;
1534 }
1535
1536 if (Value.Type != EFI_IFR_TYPE_STRING) {
1537 Status = EFI_UNSUPPORTED;
1538 goto Done;
1539 }
1540
1541 String[Index] = GetToken (Value.Value.string, FormSet->HiiHandle);
1542 if (String[Index] == NULL) {
1543 Status = EFI_NOT_FOUND;
1544 goto Done;
1545 }
1546 }
1547
1548 Delimiter = String[0];
1549 SubString = String[1];
1550 while (Count > 0) {
1551 SubString = StrStr (SubString, Delimiter);
1552 if (SubString != NULL) {
1553 //
1554 // Skip over the delimiter
1555 //
1556 SubString = SubString + StrLen (Delimiter);
1557 } else {
1558 break;
1559 }
1560 Count--;
1561 }
1562
1563 if (SubString == NULL) {
1564 //
1565 // nth delimited sub-string not found, push an empty string
1566 //
1567 SubString = gEmptyString;
1568 } else {
1569 //
1570 // Put a NULL terminator for nth delimited sub-string
1571 //
1572 StringPtr = StrStr (SubString, Delimiter);
1573 if (StringPtr != NULL) {
1574 *StringPtr = L'\0';
1575 }
1576 }
1577
1578 Result->Type = EFI_IFR_TYPE_STRING;
1579 Result->Value.string = NewString (SubString, FormSet->HiiHandle);
1580
1581 Done:
1582 if (String[0] != NULL) {
1583 FreePool (String[0]);
1584 }
1585 if (String[1] != NULL) {
1586 FreePool (String[1]);
1587 }
1588
1589 return Status;
1590 }
1591
1592
1593 /**
1594 Evaluate opcode EFI_IFR_SPAN.
1595
1596 @param FormSet Formset which contains this opcode.
1597 @param Flags FIRST_MATCHING or FIRST_NON_MATCHING.
1598 @param Result Evaluation result for this opcode.
1599
1600 @retval EFI_SUCCESS Opcode evaluation success.
1601 @retval Other Opcode evaluation failed.
1602
1603 **/
1604 EFI_STATUS
1605 IfrSpan (
1606 IN FORM_BROWSER_FORMSET *FormSet,
1607 IN UINT8 Flags,
1608 OUT EFI_HII_VALUE *Result
1609 )
1610 {
1611 EFI_STATUS Status;
1612 EFI_HII_VALUE Value;
1613 CHAR16 *String[2];
1614 CHAR16 *Charset;
1615 UINTN Base;
1616 UINTN Index;
1617 CHAR16 *StringPtr;
1618 BOOLEAN Found;
1619
1620 Status = PopExpression (&Value);
1621 if (EFI_ERROR (Status)) {
1622 return Status;
1623 }
1624 if (Value.Type > EFI_IFR_TYPE_NUM_SIZE_64) {
1625 return EFI_UNSUPPORTED;
1626 }
1627 Base = (UINTN) Value.Value.u64;
1628
1629 //
1630 // String[0] - Charset
1631 // String[1] - The string to search
1632 //
1633 String[0] = NULL;
1634 String[1] = NULL;
1635 for (Index = 0; Index < 2; Index++) {
1636 Status = PopExpression (&Value);
1637 if (EFI_ERROR (Status)) {
1638 goto Done;
1639 }
1640
1641 if (Value.Type != EFI_IFR_TYPE_STRING) {
1642 Status = EFI_UNSUPPORTED;
1643 goto Done;
1644 }
1645
1646 String[Index] = GetToken (Value.Value.string, FormSet->HiiHandle);
1647 if (String [Index] == NULL) {
1648 Status = EFI_NOT_FOUND;
1649 goto Done;
1650 }
1651 }
1652
1653 if (Base >= StrLen (String[1])) {
1654 Status = EFI_UNSUPPORTED;
1655 goto Done;
1656 }
1657
1658 Found = FALSE;
1659 StringPtr = String[1] + Base;
1660 Charset = String[0];
1661 while (*StringPtr != 0 && !Found) {
1662 Index = 0;
1663 while (Charset[Index] != 0) {
1664 if (*StringPtr >= Charset[Index] && *StringPtr <= Charset[Index + 1]) {
1665 if (Flags == EFI_IFR_FLAGS_FIRST_MATCHING) {
1666 Found = TRUE;
1667 break;
1668 }
1669 } else {
1670 if (Flags == EFI_IFR_FLAGS_FIRST_NON_MATCHING) {
1671 Found = TRUE;
1672 break;
1673 }
1674 }
1675 //
1676 // Skip characters pair representing low-end of a range and high-end of a range
1677 //
1678 Index += 2;
1679 }
1680
1681 if (!Found) {
1682 StringPtr++;
1683 }
1684 }
1685
1686 Result->Type = EFI_IFR_TYPE_NUM_SIZE_64;
1687 Result->Value.u64 = StringPtr - String[1];
1688
1689 Done:
1690 if (String[0] != NULL) {
1691 FreePool (String[0]);
1692 }
1693 if (String[1] != NULL) {
1694 FreePool (String[1]);
1695 }
1696
1697 return Status;
1698 }
1699
1700
1701 /**
1702 Zero extend integer/boolean/date/time to UINT64 for comparing.
1703
1704 @param Value HII Value to be converted.
1705
1706 **/
1707 VOID
1708 ExtendValueToU64 (
1709 IN EFI_HII_VALUE *Value
1710 )
1711 {
1712 UINT64 Temp;
1713
1714 Temp = 0;
1715 switch (Value->Type) {
1716 case EFI_IFR_TYPE_NUM_SIZE_8:
1717 Temp = Value->Value.u8;
1718 break;
1719
1720 case EFI_IFR_TYPE_NUM_SIZE_16:
1721 Temp = Value->Value.u16;
1722 break;
1723
1724 case EFI_IFR_TYPE_NUM_SIZE_32:
1725 Temp = Value->Value.u32;
1726 break;
1727
1728 case EFI_IFR_TYPE_BOOLEAN:
1729 Temp = Value->Value.b;
1730 break;
1731
1732 case EFI_IFR_TYPE_TIME:
1733 Temp = Value->Value.u32 & 0xffffff;
1734 break;
1735
1736 case EFI_IFR_TYPE_DATE:
1737 Temp = Value->Value.u32;
1738 break;
1739
1740 default:
1741 return;
1742 }
1743
1744 Value->Value.u64 = Temp;
1745 }
1746
1747
1748 /**
1749 Compare two Hii value.
1750
1751 @param Value1 Expression value to compare on left-hand.
1752 @param Value2 Expression value to compare on right-hand.
1753 @param HiiHandle Only required for string compare.
1754
1755 @retval EFI_INVALID_PARAMETER Could not perform compare on two values.
1756 @retval 0 Two operators equal.
1757 @return Positive value if Value1 is greater than Value2.
1758 @retval Negative value if Value1 is less than Value2.
1759
1760 **/
1761 INTN
1762 CompareHiiValue (
1763 IN EFI_HII_VALUE *Value1,
1764 IN EFI_HII_VALUE *Value2,
1765 IN EFI_HII_HANDLE HiiHandle OPTIONAL
1766 )
1767 {
1768 INTN Result;
1769 INT64 Temp64;
1770 CHAR16 *Str1;
1771 CHAR16 *Str2;
1772 UINTN Len;
1773
1774 if (Value1->Type >= EFI_IFR_TYPE_OTHER || Value2->Type >= EFI_IFR_TYPE_OTHER ) {
1775 if (Value1->Type != EFI_IFR_TYPE_BUFFER && Value2->Type != EFI_IFR_TYPE_BUFFER) {
1776 return EFI_INVALID_PARAMETER;
1777 }
1778 }
1779
1780 if (Value1->Type == EFI_IFR_TYPE_STRING || Value2->Type == EFI_IFR_TYPE_STRING ) {
1781 if (Value1->Type != Value2->Type) {
1782 //
1783 // Both Operator should be type of String
1784 //
1785 return EFI_INVALID_PARAMETER;
1786 }
1787
1788 if (Value1->Value.string == 0 || Value2->Value.string == 0) {
1789 //
1790 // StringId 0 is reserved
1791 //
1792 return EFI_INVALID_PARAMETER;
1793 }
1794
1795 if (Value1->Value.string == Value2->Value.string) {
1796 return 0;
1797 }
1798
1799 Str1 = GetToken (Value1->Value.string, HiiHandle);
1800 if (Str1 == NULL) {
1801 //
1802 // String not found
1803 //
1804 return EFI_INVALID_PARAMETER;
1805 }
1806
1807 Str2 = GetToken (Value2->Value.string, HiiHandle);
1808 if (Str2 == NULL) {
1809 FreePool (Str1);
1810 return EFI_INVALID_PARAMETER;
1811 }
1812
1813 Result = StrCmp (Str1, Str2);
1814
1815 FreePool (Str1);
1816 FreePool (Str2);
1817
1818 return Result;
1819 }
1820
1821 if (Value1->Type == EFI_IFR_TYPE_BUFFER || Value2->Type == EFI_IFR_TYPE_BUFFER ) {
1822 if (Value1->Type != Value2->Type) {
1823 //
1824 // Both Operator should be type of Buffer.
1825 //
1826 return EFI_INVALID_PARAMETER;
1827 }
1828 Len = Value1->BufferLen > Value2->BufferLen ? Value2->BufferLen : Value1->BufferLen;
1829 Result = CompareMem (Value1->Buffer, Value2->Buffer, Len);
1830 if ((Result == 0) && (Value1->BufferLen != Value2->BufferLen))
1831 {
1832 //
1833 // In this case, means base on samll number buffer, the data is same
1834 // So which value has more data, which value is bigger.
1835 //
1836 Result = Value1->BufferLen > Value2->BufferLen ? 1 : -1;
1837 }
1838 return Result;
1839 }
1840
1841 //
1842 // Take remain types(integer, boolean, date/time) as integer
1843 //
1844 Temp64 = (INT64) (Value1->Value.u64 - Value2->Value.u64);
1845 if (Temp64 > 0) {
1846 Result = 1;
1847 } else if (Temp64 < 0) {
1848 Result = -1;
1849 } else {
1850 Result = 0;
1851 }
1852
1853 return Result;
1854 }
1855
1856 /**
1857 Check if current user has the privilege specified by the permissions GUID.
1858
1859 @param[in] Guid A GUID specifying setup access permissions.
1860
1861 @retval TRUE Current user has the privilege.
1862 @retval FALSE Current user does not have the privilege.
1863 **/
1864 BOOLEAN
1865 CheckUserPrivilege (
1866 IN EFI_GUID *Guid
1867 )
1868 {
1869 EFI_STATUS Status;
1870 EFI_USER_PROFILE_HANDLE UserProfileHandle;
1871 EFI_USER_INFO_HANDLE UserInfoHandle;
1872 EFI_USER_INFO *UserInfo;
1873 EFI_GUID *UserPermissionsGuid;
1874 UINTN UserInfoSize;
1875 UINTN AccessControlDataSize;
1876 EFI_USER_INFO_ACCESS_CONTROL *AccessControl;
1877 UINTN RemainSize;
1878
1879 if (mUserManager == NULL) {
1880 Status = gBS->LocateProtocol (
1881 &gEfiUserManagerProtocolGuid,
1882 NULL,
1883 (VOID **) &mUserManager
1884 );
1885 if (EFI_ERROR (Status)) {
1886 ///
1887 /// If the system does not support user management, then it is assumed that
1888 /// all users have admin privilege and evaluation of each EFI_IFR_SECURITY
1889 /// op-code is always TRUE.
1890 ///
1891 return TRUE;
1892 }
1893 }
1894
1895 Status = mUserManager->Current (mUserManager, &UserProfileHandle);
1896 ASSERT_EFI_ERROR (Status);
1897
1898 ///
1899 /// Enumerate all user information of the current user profile
1900 /// to look for any EFI_USER_INFO_ACCESS_SETUP record.
1901 ///
1902
1903 for (UserInfoHandle = NULL;;) {
1904 Status = mUserManager->GetNextInfo (mUserManager, UserProfileHandle, &UserInfoHandle);
1905 if (EFI_ERROR (Status)) {
1906 break;
1907 }
1908
1909 UserInfoSize = 0;
1910 Status = mUserManager->GetInfo (mUserManager, UserProfileHandle, UserInfoHandle, NULL, &UserInfoSize);
1911 if (Status != EFI_BUFFER_TOO_SMALL) {
1912 continue;
1913 }
1914
1915 UserInfo = (EFI_USER_INFO *) AllocatePool (UserInfoSize);
1916 if (UserInfo == NULL) {
1917 break;
1918 }
1919
1920 Status = mUserManager->GetInfo (mUserManager, UserProfileHandle, UserInfoHandle, UserInfo, &UserInfoSize);
1921 if (EFI_ERROR (Status) ||
1922 UserInfo->InfoType != EFI_USER_INFO_ACCESS_POLICY_RECORD ||
1923 UserInfo->InfoSize <= sizeof (EFI_USER_INFO)) {
1924 FreePool (UserInfo);
1925 continue;
1926 }
1927
1928 RemainSize = UserInfo->InfoSize - sizeof (EFI_USER_INFO);
1929 AccessControl = (EFI_USER_INFO_ACCESS_CONTROL *)(UserInfo + 1);
1930 while (RemainSize >= sizeof (EFI_USER_INFO_ACCESS_CONTROL)) {
1931 if (RemainSize < AccessControl->Size || AccessControl->Size < sizeof (EFI_USER_INFO_ACCESS_CONTROL)) {
1932 break;
1933 }
1934 if (AccessControl->Type == EFI_USER_INFO_ACCESS_SETUP) {
1935 ///
1936 /// Check if current user has the privilege specified by the permissions GUID.
1937 ///
1938
1939 UserPermissionsGuid = (EFI_GUID *)(AccessControl + 1);
1940 AccessControlDataSize = AccessControl->Size - sizeof (EFI_USER_INFO_ACCESS_CONTROL);
1941 while (AccessControlDataSize >= sizeof (EFI_GUID)) {
1942 if (CompareGuid (Guid, UserPermissionsGuid)) {
1943 FreePool (UserInfo);
1944 return TRUE;
1945 }
1946 UserPermissionsGuid++;
1947 AccessControlDataSize -= sizeof (EFI_GUID);
1948 }
1949 }
1950 RemainSize -= AccessControl->Size;
1951 AccessControl = (EFI_USER_INFO_ACCESS_CONTROL *)((UINT8 *)AccessControl + AccessControl->Size);
1952 }
1953
1954 FreePool (UserInfo);
1955 }
1956 return FALSE;
1957 }
1958
1959 /**
1960 Get question value from the predefined formset.
1961
1962 @param DevicePath The driver's device path which produece the formset data.
1963 @param InputHiiHandle The hii handle associate with the formset data.
1964 @param FormSetGuid The formset guid which include the question.
1965 @param QuestionId The question id which need to get value from.
1966 @param Value The return data about question's value.
1967
1968 @retval TRUE Get the question value success.
1969 @retval FALSE Get the question value failed.
1970 **/
1971 BOOLEAN
1972 GetQuestionValueFromForm (
1973 IN EFI_DEVICE_PATH_PROTOCOL *DevicePath,
1974 IN EFI_HII_HANDLE InputHiiHandle,
1975 IN EFI_GUID *FormSetGuid,
1976 IN EFI_QUESTION_ID QuestionId,
1977 OUT EFI_HII_VALUE *Value
1978 )
1979 {
1980 EFI_STATUS Status;
1981 EFI_HANDLE DriverHandle;
1982 EFI_HANDLE Handle;
1983 EFI_HII_HANDLE *HiiHandles;
1984 EFI_HII_HANDLE HiiHandle;
1985 UINTN Index;
1986 FORM_BROWSER_STATEMENT *Question;
1987 FORM_BROWSER_FORMSET *FormSet;
1988 FORM_BROWSER_FORM *Form;
1989 BOOLEAN GetTheVal;
1990 LIST_ENTRY *Link;
1991
1992 //
1993 // The input parameter DevicePath or InputHiiHandle must have one valid input.
1994 //
1995 ASSERT ((DevicePath != NULL && InputHiiHandle == NULL) ||
1996 (DevicePath == NULL && InputHiiHandle != NULL) );
1997
1998 GetTheVal = TRUE;
1999 DriverHandle = NULL;
2000 HiiHandle = NULL;
2001 Question = NULL;
2002 Form = NULL;
2003
2004 //
2005 // Get HiiHandle.
2006 //
2007 if (DevicePath != NULL) {
2008 //
2009 // 1. Get Driver handle.
2010 //
2011 Status = gBS->LocateDevicePath (
2012 &gEfiDevicePathProtocolGuid,
2013 &DevicePath,
2014 &DriverHandle
2015 );
2016 if (EFI_ERROR (Status) || (DriverHandle == NULL)) {
2017 return FALSE;
2018 }
2019
2020 //
2021 // 2. Get Hii handle
2022 //
2023 HiiHandles = HiiGetHiiHandles (NULL);
2024 if (HiiHandles == NULL) {
2025 return FALSE;
2026 }
2027
2028 for (Index = 0; HiiHandles[Index] != NULL; Index++) {
2029 Status = mHiiDatabase->GetPackageListHandle (
2030 mHiiDatabase,
2031 HiiHandles[Index],
2032 &Handle
2033 );
2034 if (!EFI_ERROR (Status) && (Handle == DriverHandle)) {
2035 HiiHandle = HiiHandles[Index];
2036 break;
2037 }
2038 }
2039 FreePool (HiiHandles);
2040 } else {
2041 HiiHandle = InputHiiHandle;
2042 }
2043 ASSERT (HiiHandle != NULL);
2044
2045 //
2046 // Get the formset data include this question.
2047 //
2048 FormSet = AllocateZeroPool (sizeof (FORM_BROWSER_FORMSET));
2049 ASSERT (FormSet != NULL);
2050 Status = InitializeFormSet(HiiHandle, FormSetGuid, FormSet, FALSE);
2051 if (EFI_ERROR (Status)) {
2052 GetTheVal = FALSE;
2053 goto Done;
2054 }
2055
2056 //
2057 // Base on the Question Id to get the question info.
2058 //
2059 Question = IdToQuestion(FormSet, NULL, QuestionId);
2060 if (Question == NULL) {
2061 GetTheVal = FALSE;
2062 goto Done;
2063 }
2064
2065 //
2066 // Search form in the formset scope
2067 //
2068 Link = GetFirstNode (&FormSet->FormListHead);
2069 while (!IsNull (&FormSet->FormListHead, Link)) {
2070 Form = FORM_BROWSER_FORM_FROM_LINK (Link);
2071
2072 Question = IdToQuestion2 (Form, QuestionId);
2073 if (Question != NULL) {
2074 break;
2075 }
2076
2077 Link = GetNextNode (&FormSet->FormListHead, Link);
2078 Form = NULL;
2079 }
2080 ASSERT (Form != NULL);
2081
2082 //
2083 // Get the question value.
2084 //
2085 Status = GetQuestionValue(FormSet, Form, Question, FALSE);
2086 if (EFI_ERROR (Status)) {
2087 GetTheVal = FALSE;
2088 goto Done;
2089 }
2090
2091 CopyMem (Value, &Question->HiiValue, sizeof (EFI_HII_VALUE));
2092
2093 Done:
2094 //
2095 // Clean the formset structure and restore the global parameter.
2096 //
2097 if (FormSet != NULL) {
2098 DestroyFormSet (FormSet);
2099 }
2100
2101 return GetTheVal;
2102 }
2103
2104 /**
2105 Evaluate the result of a HII expression.
2106
2107 If Expression is NULL, then ASSERT.
2108
2109 @param FormSet FormSet associated with this expression.
2110 @param Form Form associated with this expression.
2111 @param Expression Expression to be evaluated.
2112
2113 @retval EFI_SUCCESS The expression evaluated successfuly
2114 @retval EFI_NOT_FOUND The Question which referenced by a QuestionId
2115 could not be found.
2116 @retval EFI_OUT_OF_RESOURCES There is not enough system memory to grow the
2117 stack.
2118 @retval EFI_ACCESS_DENIED The pop operation underflowed the stack
2119 @retval EFI_INVALID_PARAMETER Syntax error with the Expression
2120
2121 **/
2122 EFI_STATUS
2123 EvaluateExpression (
2124 IN FORM_BROWSER_FORMSET *FormSet,
2125 IN FORM_BROWSER_FORM *Form,
2126 IN OUT FORM_EXPRESSION *Expression
2127 )
2128 {
2129 EFI_STATUS Status;
2130 LIST_ENTRY *Link;
2131 EXPRESSION_OPCODE *OpCode;
2132 FORM_BROWSER_STATEMENT *Question;
2133 FORM_BROWSER_STATEMENT *Question2;
2134 UINT16 Index;
2135 EFI_HII_VALUE Data1;
2136 EFI_HII_VALUE Data2;
2137 EFI_HII_VALUE Data3;
2138 FORM_EXPRESSION *RuleExpression;
2139 EFI_HII_VALUE *Value;
2140 INTN Result;
2141 CHAR16 *StrPtr;
2142 CHAR16 *NameValue;
2143 UINT32 TempValue;
2144 LIST_ENTRY *SubExpressionLink;
2145 FORM_EXPRESSION *SubExpression;
2146 UINTN StackOffset;
2147 UINTN TempLength;
2148 CHAR16 TempStr[5];
2149 UINT8 DigitUint8;
2150 UINT8 *TempBuffer;
2151 EFI_TIME EfiTime;
2152 EFI_HII_VALUE QuestionVal;
2153
2154 //
2155 // Save current stack offset.
2156 //
2157 StackOffset = SaveExpressionEvaluationStackOffset ();
2158
2159 ASSERT (Expression != NULL);
2160 Expression->Result.Type = EFI_IFR_TYPE_OTHER;
2161
2162 Link = GetFirstNode (&Expression->OpCodeListHead);
2163 while (!IsNull (&Expression->OpCodeListHead, Link)) {
2164 OpCode = EXPRESSION_OPCODE_FROM_LINK (Link);
2165
2166 Link = GetNextNode (&Expression->OpCodeListHead, Link);
2167
2168 ZeroMem (&Data1, sizeof (EFI_HII_VALUE));
2169 ZeroMem (&Data2, sizeof (EFI_HII_VALUE));
2170 ZeroMem (&Data3, sizeof (EFI_HII_VALUE));
2171
2172 Value = &Data3;
2173 Value->Type = EFI_IFR_TYPE_BOOLEAN;
2174 Status = EFI_SUCCESS;
2175
2176 switch (OpCode->Operand) {
2177 //
2178 // Built-in functions
2179 //
2180 case EFI_IFR_EQ_ID_VAL_OP:
2181 Question = IdToQuestion (FormSet, Form, OpCode->QuestionId);
2182 if (Question == NULL) {
2183 Status = EFI_NOT_FOUND;
2184 goto Done;
2185 }
2186
2187 Result = CompareHiiValue (&Question->HiiValue, &OpCode->Value, NULL);
2188 if (Result == EFI_INVALID_PARAMETER) {
2189 Status = EFI_INVALID_PARAMETER;
2190 goto Done;
2191 }
2192 Value->Value.b = (BOOLEAN) ((Result == 0) ? TRUE : FALSE);
2193 break;
2194
2195 case EFI_IFR_EQ_ID_ID_OP:
2196 Question = IdToQuestion (FormSet, Form, OpCode->QuestionId);
2197 if (Question == NULL) {
2198 Status = EFI_NOT_FOUND;
2199 goto Done;
2200 }
2201
2202 Question2 = IdToQuestion (FormSet, Form, OpCode->QuestionId2);
2203 if (Question2 == NULL) {
2204 Status = EFI_NOT_FOUND;
2205 goto Done;
2206 }
2207
2208 Result = CompareHiiValue (&Question->HiiValue, &Question2->HiiValue, FormSet->HiiHandle);
2209 if (Result == EFI_INVALID_PARAMETER) {
2210 Status = EFI_INVALID_PARAMETER;
2211 goto Done;
2212 }
2213 Value->Value.b = (BOOLEAN) ((Result == 0) ? TRUE : FALSE);
2214 break;
2215
2216 case EFI_IFR_EQ_ID_VAL_LIST_OP:
2217 Question = IdToQuestion (FormSet, Form, OpCode->QuestionId);
2218 if (Question == NULL) {
2219 Status = EFI_NOT_FOUND;
2220 goto Done;
2221 }
2222
2223 Value->Value.b = FALSE;
2224 for (Index =0; Index < OpCode->ListLength; Index++) {
2225 if (Question->HiiValue.Value.u16 == OpCode->ValueList[Index]) {
2226 Value->Value.b = TRUE;
2227 break;
2228 }
2229 }
2230 break;
2231
2232 case EFI_IFR_DUP_OP:
2233 Status = PopExpression (Value);
2234 if (EFI_ERROR (Status)) {
2235 goto Done;
2236 }
2237
2238 Status = PushExpression (Value);
2239 break;
2240
2241 case EFI_IFR_QUESTION_REF1_OP:
2242 case EFI_IFR_THIS_OP:
2243 Question = IdToQuestion (FormSet, Form, OpCode->QuestionId);
2244 if (Question == NULL) {
2245 Status = EFI_NOT_FOUND;
2246 goto Done;
2247 }
2248
2249 Value = &Question->HiiValue;
2250 break;
2251
2252 case EFI_IFR_SECURITY_OP:
2253 Value->Value.b = CheckUserPrivilege (&OpCode->Guid);
2254 break;
2255
2256 case EFI_IFR_GET_OP:
2257 //
2258 // Get Value from VarStore buffer, EFI VarStore, Name/Value VarStore.
2259 //
2260 Value->Type = EFI_IFR_TYPE_UNDEFINED;
2261 Value->Value.u8 = 0;
2262 if (OpCode->VarStorage != NULL) {
2263 switch (OpCode->VarStorage->Type) {
2264 case EFI_HII_VARSTORE_BUFFER:
2265 case EFI_HII_VARSTORE_EFI_VARIABLE_BUFFER:
2266 //
2267 // Get value from Edit Buffer
2268 //
2269 Value->Type = OpCode->ValueType;
2270 CopyMem (&Value->Value, OpCode->VarStorage->EditBuffer + OpCode->VarStoreInfo.VarOffset, OpCode->ValueWidth);
2271 break;
2272 case EFI_HII_VARSTORE_NAME_VALUE:
2273 if (OpCode->ValueType != EFI_IFR_TYPE_STRING) {
2274 //
2275 // Get value from string except for STRING value.
2276 //
2277 Status = GetValueByName (OpCode->VarStorage, OpCode->ValueName, &StrPtr);
2278 if (!EFI_ERROR (Status)) {
2279 ASSERT (StrPtr != NULL);
2280 TempLength = StrLen (StrPtr);
2281 if (OpCode->ValueWidth >= ((TempLength + 1) / 2)) {
2282 Value->Type = OpCode->ValueType;
2283 TempBuffer = (UINT8 *) &Value->Value;
2284 ZeroMem (TempStr, sizeof (TempStr));
2285 for (Index = 0; Index < TempLength; Index ++) {
2286 TempStr[0] = StrPtr[TempLength - Index - 1];
2287 DigitUint8 = (UINT8) StrHexToUint64 (TempStr);
2288 if ((Index & 1) == 0) {
2289 TempBuffer [Index/2] = DigitUint8;
2290 } else {
2291 TempBuffer [Index/2] = (UINT8) ((DigitUint8 << 4) + TempBuffer [Index/2]);
2292 }
2293 }
2294 }
2295 }
2296 }
2297 break;
2298 case EFI_HII_VARSTORE_EFI_VARIABLE:
2299 //
2300 // Get value from variable.
2301 //
2302 TempLength = OpCode->ValueWidth;
2303 Value->Type = OpCode->ValueType;
2304 Status = gRT->GetVariable (
2305 OpCode->ValueName,
2306 &OpCode->VarStorage->Guid,
2307 NULL,
2308 &TempLength,
2309 &Value->Value
2310 );
2311 if (EFI_ERROR (Status)) {
2312 Value->Type = EFI_IFR_TYPE_UNDEFINED;
2313 Value->Value.u8 = 0;
2314 }
2315 break;
2316 default:
2317 //
2318 // Not recognize storage.
2319 //
2320 Status = EFI_UNSUPPORTED;
2321 goto Done;
2322 }
2323 } else {
2324 //
2325 // For Time/Date Data
2326 //
2327 if (OpCode->ValueType != EFI_IFR_TYPE_DATE && OpCode->ValueType != EFI_IFR_TYPE_TIME) {
2328 //
2329 // Only support Data/Time data when storage doesn't exist.
2330 //
2331 Status = EFI_UNSUPPORTED;
2332 goto Done;
2333 }
2334 Status = gRT->GetTime (&EfiTime, NULL);
2335 if (!EFI_ERROR (Status)) {
2336 if (OpCode->ValueType == EFI_IFR_TYPE_DATE) {
2337 switch (OpCode->VarStoreInfo.VarOffset) {
2338 case 0x00:
2339 Value->Type = EFI_IFR_TYPE_NUM_SIZE_16;
2340 Value->Value.u16 = EfiTime.Year;
2341 break;
2342 case 0x02:
2343 Value->Type = EFI_IFR_TYPE_NUM_SIZE_8;
2344 Value->Value.u8 = EfiTime.Month;
2345 break;
2346 case 0x03:
2347 Value->Type = EFI_IFR_TYPE_NUM_SIZE_8;
2348 Value->Value.u8 = EfiTime.Day;
2349 break;
2350 default:
2351 //
2352 // Invalid Date field.
2353 //
2354 Status = EFI_INVALID_PARAMETER;
2355 goto Done;
2356 }
2357 } else {
2358 switch (OpCode->VarStoreInfo.VarOffset) {
2359 case 0x00:
2360 Value->Type = EFI_IFR_TYPE_NUM_SIZE_8;
2361 Value->Value.u8 = EfiTime.Hour;
2362 break;
2363 case 0x01:
2364 Value->Type = EFI_IFR_TYPE_NUM_SIZE_8;
2365 Value->Value.u8 = EfiTime.Minute;
2366 break;
2367 case 0x02:
2368 Value->Type = EFI_IFR_TYPE_NUM_SIZE_8;
2369 Value->Value.u8 = EfiTime.Second;
2370 break;
2371 default:
2372 //
2373 // Invalid Time field.
2374 //
2375 Status = EFI_INVALID_PARAMETER;
2376 goto Done;
2377 }
2378 }
2379 }
2380 }
2381
2382 break;
2383
2384 case EFI_IFR_QUESTION_REF3_OP:
2385 //
2386 // EFI_IFR_QUESTION_REF3
2387 // Pop an expression from the expression stack
2388 //
2389 Status = PopExpression (Value);
2390 if (EFI_ERROR (Status)) {
2391 goto Done;
2392 }
2393
2394 //
2395 // Validate the expression value
2396 //
2397 if ((Value->Type > EFI_IFR_TYPE_NUM_SIZE_64) || (Value->Value.u64 > 0xffff)) {
2398 Status = EFI_NOT_FOUND;
2399 goto Done;
2400 }
2401
2402 if (OpCode->DevicePath != 0) {
2403 StrPtr = GetToken (OpCode->DevicePath, FormSet->HiiHandle);
2404 if (StrPtr == NULL) {
2405 Status = EFI_NOT_FOUND;
2406 goto Done;
2407 }
2408
2409 if (!GetQuestionValueFromForm((EFI_DEVICE_PATH_PROTOCOL*)StrPtr, NULL, &OpCode->Guid, Value->Value.u16, &QuestionVal)){
2410 Status = EFI_NOT_FOUND;
2411 goto Done;
2412 }
2413 Value = &QuestionVal;
2414 } else if (CompareGuid (&OpCode->Guid, &gZeroGuid) != 0) {
2415 if (!GetQuestionValueFromForm(NULL, FormSet->HiiHandle, &OpCode->Guid, Value->Value.u16, &QuestionVal)){
2416 Status = EFI_NOT_FOUND;
2417 goto Done;
2418 }
2419 Value = &QuestionVal;
2420 } else {
2421 Question = IdToQuestion (FormSet, Form, Value->Value.u16);
2422 if (Question == NULL) {
2423 Status = EFI_NOT_FOUND;
2424 goto Done;
2425 }
2426
2427 //
2428 // push the questions' value on to the expression stack
2429 //
2430 Value = &Question->HiiValue;
2431 }
2432 break;
2433
2434 case EFI_IFR_RULE_REF_OP:
2435 //
2436 // Find expression for this rule
2437 //
2438 RuleExpression = RuleIdToExpression (Form, OpCode->RuleId);
2439 if (RuleExpression == NULL) {
2440 Status = EFI_NOT_FOUND;
2441 goto Done;
2442 }
2443
2444 //
2445 // Evaluate this rule expression
2446 //
2447 Status = EvaluateExpression (FormSet, Form, RuleExpression);
2448 if (EFI_ERROR (Status)) {
2449 goto Done;
2450 }
2451
2452 Value = &RuleExpression->Result;
2453 break;
2454
2455 case EFI_IFR_STRING_REF1_OP:
2456 Value->Type = EFI_IFR_TYPE_STRING;
2457 Value->Value.string = OpCode->Value.Value.string;
2458 break;
2459
2460 //
2461 // Constant
2462 //
2463 case EFI_IFR_TRUE_OP:
2464 case EFI_IFR_FALSE_OP:
2465 case EFI_IFR_ONE_OP:
2466 case EFI_IFR_ONES_OP:
2467 case EFI_IFR_UINT8_OP:
2468 case EFI_IFR_UINT16_OP:
2469 case EFI_IFR_UINT32_OP:
2470 case EFI_IFR_UINT64_OP:
2471 case EFI_IFR_UNDEFINED_OP:
2472 case EFI_IFR_VERSION_OP:
2473 case EFI_IFR_ZERO_OP:
2474 Value = &OpCode->Value;
2475 break;
2476
2477 //
2478 // unary-op
2479 //
2480 case EFI_IFR_LENGTH_OP:
2481 Status = PopExpression (Value);
2482 if (EFI_ERROR (Status)) {
2483 goto Done;
2484 }
2485 if (Value->Type != EFI_IFR_TYPE_STRING && Value->Type != EFI_IFR_TYPE_BUFFER) {
2486 Status = EFI_INVALID_PARAMETER;
2487 goto Done;
2488 }
2489
2490 if (Value->Type == EFI_IFR_TYPE_STRING) {
2491 StrPtr = GetToken (Value->Value.string, FormSet->HiiHandle);
2492 if (StrPtr == NULL) {
2493 Status = EFI_INVALID_PARAMETER;
2494 goto Done;
2495 }
2496
2497 Value->Type = EFI_IFR_TYPE_NUM_SIZE_64;
2498 Value->Value.u64 = StrLen (StrPtr);
2499 FreePool (StrPtr);
2500 } else {
2501 Value->Type = EFI_IFR_TYPE_NUM_SIZE_64;
2502 Value->Value.u64 = Value->BufferLen;
2503 FreePool (Value->Buffer);
2504 }
2505 break;
2506
2507 case EFI_IFR_NOT_OP:
2508 Status = PopExpression (Value);
2509 if (EFI_ERROR (Status)) {
2510 goto Done;
2511 }
2512 if (Value->Type != EFI_IFR_TYPE_BOOLEAN) {
2513 Status = EFI_INVALID_PARAMETER;
2514 goto Done;
2515 }
2516 Value->Value.b = (BOOLEAN) (!Value->Value.b);
2517 break;
2518
2519 case EFI_IFR_QUESTION_REF2_OP:
2520 //
2521 // Pop an expression from the expression stack
2522 //
2523 Status = PopExpression (Value);
2524 if (EFI_ERROR (Status)) {
2525 goto Done;
2526 }
2527
2528 //
2529 // Validate the expression value
2530 //
2531 if ((Value->Type > EFI_IFR_TYPE_NUM_SIZE_64) || (Value->Value.u64 > 0xffff)) {
2532 Status = EFI_NOT_FOUND;
2533 goto Done;
2534 }
2535
2536 Question = IdToQuestion (FormSet, Form, Value->Value.u16);
2537 if (Question == NULL) {
2538 Status = EFI_NOT_FOUND;
2539 goto Done;
2540 }
2541
2542 Value = &Question->HiiValue;
2543 break;
2544
2545 case EFI_IFR_STRING_REF2_OP:
2546 //
2547 // Pop an expression from the expression stack
2548 //
2549 Status = PopExpression (Value);
2550 if (EFI_ERROR (Status)) {
2551 goto Done;
2552 }
2553
2554 //
2555 // Validate the expression value
2556 //
2557 if ((Value->Type > EFI_IFR_TYPE_NUM_SIZE_64) || (Value->Value.u64 > 0xffff)) {
2558 Status = EFI_NOT_FOUND;
2559 goto Done;
2560 }
2561
2562 Value->Type = EFI_IFR_TYPE_STRING;
2563 StrPtr = GetToken (Value->Value.u16, FormSet->HiiHandle);
2564 if (StrPtr == NULL) {
2565 //
2566 // If String not exit, push an empty string
2567 //
2568 Value->Value.string = NewString (gEmptyString, FormSet->HiiHandle);
2569 } else {
2570 Index = (UINT16) Value->Value.u64;
2571 Value->Value.string = Index;
2572 FreePool (StrPtr);
2573 }
2574 break;
2575
2576 case EFI_IFR_TO_BOOLEAN_OP:
2577 //
2578 // Pop an expression from the expression stack
2579 //
2580 Status = PopExpression (Value);
2581 if (EFI_ERROR (Status)) {
2582 goto Done;
2583 }
2584
2585 //
2586 // Convert an expression to a Boolean
2587 //
2588 if (Value->Type <= EFI_IFR_TYPE_DATE) {
2589 //
2590 // When converting from an unsigned integer, zero will be converted to
2591 // FALSE and any other value will be converted to TRUE.
2592 //
2593 Value->Value.b = (BOOLEAN) (Value->Value.u64 != 0);
2594
2595 Value->Type = EFI_IFR_TYPE_BOOLEAN;
2596 } else if (Value->Type == EFI_IFR_TYPE_STRING) {
2597 //
2598 // When converting from a string, if case-insensitive compare
2599 // with "true" is True, then push True. If a case-insensitive compare
2600 // with "false" is True, then push False. Otherwise, push Undefined.
2601 //
2602 StrPtr = GetToken (Value->Value.string, FormSet->HiiHandle);
2603 if (StrPtr == NULL) {
2604 Status = EFI_INVALID_PARAMETER;
2605 goto Done;
2606 }
2607
2608 IfrStrToUpper (StrPtr);
2609 if (StrCmp (StrPtr, L"TRUE") == 0){
2610 Value->Value.b = TRUE;
2611 } else if (StrCmp (StrPtr, L"FALSE") == 0) {
2612 Value->Value.b = FALSE;
2613 } else {
2614 Status = EFI_INVALID_PARAMETER;
2615 FreePool (StrPtr);
2616 goto Done;
2617 }
2618 FreePool (StrPtr);
2619 Value->Type = EFI_IFR_TYPE_BOOLEAN;
2620 } else if (Value->Type == EFI_IFR_TYPE_BUFFER) {
2621 //
2622 // When converting from a buffer, if the buffer is all zeroes,
2623 // then push False. Otherwise push True.
2624 //
2625 for (Index =0; Index < Value->BufferLen; Index ++) {
2626 if (Value->Buffer[Index] != 0) {
2627 break;
2628 }
2629 }
2630
2631 if (Index >= Value->BufferLen) {
2632 Value->Value.b = FALSE;
2633 } else {
2634 Value->Value.b = TRUE;
2635 }
2636 Value->Type = EFI_IFR_TYPE_BOOLEAN;
2637 FreePool (Value->Buffer);
2638 }
2639 break;
2640
2641 case EFI_IFR_TO_STRING_OP:
2642 Status = IfrToString (FormSet, OpCode->Format, Value);
2643 break;
2644
2645 case EFI_IFR_TO_UINT_OP:
2646 Status = IfrToUint (FormSet, Value);
2647 break;
2648
2649 case EFI_IFR_TO_LOWER_OP:
2650 case EFI_IFR_TO_UPPER_OP:
2651 Status = InitializeUnicodeCollationProtocol ();
2652 if (EFI_ERROR (Status)) {
2653 goto Done;
2654 }
2655
2656 Status = PopExpression (Value);
2657 if (EFI_ERROR (Status)) {
2658 goto Done;
2659 }
2660
2661 if (Value->Type != EFI_IFR_TYPE_STRING) {
2662 Status = EFI_UNSUPPORTED;
2663 goto Done;
2664 }
2665
2666 StrPtr = GetToken (Value->Value.string, FormSet->HiiHandle);
2667 if (StrPtr == NULL) {
2668 Status = EFI_NOT_FOUND;
2669 goto Done;
2670 }
2671
2672 if (OpCode->Operand == EFI_IFR_TO_LOWER_OP) {
2673 mUnicodeCollation->StrLwr (mUnicodeCollation, StrPtr);
2674 } else {
2675 mUnicodeCollation->StrUpr (mUnicodeCollation, StrPtr);
2676 }
2677 Value->Value.string = NewString (StrPtr, FormSet->HiiHandle);
2678 FreePool (StrPtr);
2679 break;
2680
2681 case EFI_IFR_BITWISE_NOT_OP:
2682 //
2683 // Pop an expression from the expression stack
2684 //
2685 Status = PopExpression (Value);
2686 if (EFI_ERROR (Status)) {
2687 goto Done;
2688 }
2689 if (Value->Type > EFI_IFR_TYPE_DATE) {
2690 Status = EFI_INVALID_PARAMETER;
2691 goto Done;
2692 }
2693
2694 Value->Type = EFI_IFR_TYPE_NUM_SIZE_64;
2695 Value->Value.u64 = ~Value->Value.u64;
2696 break;
2697
2698 case EFI_IFR_SET_OP:
2699 //
2700 // Pop an expression from the expression stack
2701 //
2702 Status = PopExpression (Value);
2703 if (EFI_ERROR (Status)) {
2704 goto Done;
2705 }
2706 Data1.Type = EFI_IFR_TYPE_BOOLEAN;
2707 Data1.Value.b = FALSE;
2708 //
2709 // Set value to var storage buffer
2710 //
2711 if (OpCode->VarStorage != NULL) {
2712 switch (OpCode->VarStorage->Type) {
2713 case EFI_HII_VARSTORE_BUFFER:
2714 case EFI_HII_VARSTORE_EFI_VARIABLE_BUFFER:
2715 CopyMem (OpCode->VarStorage->EditBuffer + OpCode->VarStoreInfo.VarOffset, &Value->Value, OpCode->ValueWidth);
2716 Data1.Value.b = TRUE;
2717 break;
2718 case EFI_HII_VARSTORE_NAME_VALUE:
2719 if (OpCode->ValueType != EFI_IFR_TYPE_STRING) {
2720 NameValue = AllocateZeroPool ((OpCode->ValueWidth * 2 + 1) * sizeof (CHAR16));
2721 ASSERT (Value != NULL);
2722 //
2723 // Convert Buffer to Hex String
2724 //
2725 TempBuffer = (UINT8 *) &Value->Value + OpCode->ValueWidth - 1;
2726 StrPtr = NameValue;
2727 for (Index = 0; Index < OpCode->ValueWidth; Index ++, TempBuffer --) {
2728 StrPtr += UnicodeValueToString (StrPtr, PREFIX_ZERO | RADIX_HEX, *TempBuffer, 2);
2729 }
2730 Status = SetValueByName (OpCode->VarStorage, OpCode->ValueName, NameValue, TRUE);
2731 FreePool (NameValue);
2732 if (!EFI_ERROR (Status)) {
2733 Data1.Value.b = TRUE;
2734 }
2735 }
2736 break;
2737 case EFI_HII_VARSTORE_EFI_VARIABLE:
2738 Status = gRT->SetVariable (
2739 OpCode->ValueName,
2740 &OpCode->VarStorage->Guid,
2741 OpCode->VarStorage->Attributes,
2742 OpCode->ValueWidth,
2743 &Value->Value
2744 );
2745 if (!EFI_ERROR (Status)) {
2746 Data1.Value.b = TRUE;
2747 }
2748 break;
2749 default:
2750 //
2751 // Not recognize storage.
2752 //
2753 Status = EFI_UNSUPPORTED;
2754 goto Done;
2755 break;
2756 }
2757 } else {
2758 //
2759 // For Time/Date Data
2760 //
2761 if (OpCode->ValueType != EFI_IFR_TYPE_DATE && OpCode->ValueType != EFI_IFR_TYPE_TIME) {
2762 //
2763 // Only support Data/Time data when storage doesn't exist.
2764 //
2765 Status = EFI_UNSUPPORTED;
2766 goto Done;
2767 }
2768 Status = gRT->GetTime (&EfiTime, NULL);
2769 if (!EFI_ERROR (Status)) {
2770 if (OpCode->ValueType == EFI_IFR_TYPE_DATE) {
2771 switch (OpCode->VarStoreInfo.VarOffset) {
2772 case 0x00:
2773 EfiTime.Year = Value->Value.u16;
2774 break;
2775 case 0x02:
2776 EfiTime.Month = Value->Value.u8;
2777 break;
2778 case 0x03:
2779 EfiTime.Day = Value->Value.u8;
2780 break;
2781 default:
2782 //
2783 // Invalid Date field.
2784 //
2785 Status = EFI_INVALID_PARAMETER;
2786 goto Done;
2787 }
2788 } else {
2789 switch (OpCode->VarStoreInfo.VarOffset) {
2790 case 0x00:
2791 EfiTime.Hour = Value->Value.u8;
2792 break;
2793 case 0x01:
2794 EfiTime.Minute = Value->Value.u8;
2795 break;
2796 case 0x02:
2797 EfiTime.Second = Value->Value.u8;
2798 break;
2799 default:
2800 //
2801 // Invalid Time field.
2802 //
2803 Status = EFI_INVALID_PARAMETER;
2804 goto Done;
2805 }
2806 }
2807 Status = gRT->SetTime (&EfiTime);
2808 if (!EFI_ERROR (Status)) {
2809 Data1.Value.b = TRUE;
2810 }
2811 }
2812 }
2813 Value = &Data1;
2814 break;
2815
2816 //
2817 // binary-op
2818 //
2819 case EFI_IFR_ADD_OP:
2820 case EFI_IFR_SUBTRACT_OP:
2821 case EFI_IFR_MULTIPLY_OP:
2822 case EFI_IFR_DIVIDE_OP:
2823 case EFI_IFR_MODULO_OP:
2824 case EFI_IFR_BITWISE_AND_OP:
2825 case EFI_IFR_BITWISE_OR_OP:
2826 case EFI_IFR_SHIFT_LEFT_OP:
2827 case EFI_IFR_SHIFT_RIGHT_OP:
2828 //
2829 // Pop an expression from the expression stack
2830 //
2831 Status = PopExpression (&Data2);
2832 if (EFI_ERROR (Status)) {
2833 goto Done;
2834 }
2835 if (Data2.Type > EFI_IFR_TYPE_DATE) {
2836 Status = EFI_INVALID_PARAMETER;
2837 goto Done;
2838 }
2839
2840 //
2841 // Pop another expression from the expression stack
2842 //
2843 Status = PopExpression (&Data1);
2844 if (EFI_ERROR (Status)) {
2845 goto Done;
2846 }
2847 if (Data1.Type > EFI_IFR_TYPE_DATE) {
2848 Status = EFI_INVALID_PARAMETER;
2849 goto Done;
2850 }
2851
2852 Value->Type = EFI_IFR_TYPE_NUM_SIZE_64;
2853
2854 switch (OpCode->Operand) {
2855 case EFI_IFR_ADD_OP:
2856 Value->Value.u64 = Data1.Value.u64 + Data2.Value.u64;
2857 break;
2858
2859 case EFI_IFR_SUBTRACT_OP:
2860 Value->Value.u64 = Data1.Value.u64 - Data2.Value.u64;
2861 break;
2862
2863 case EFI_IFR_MULTIPLY_OP:
2864 Value->Value.u64 = MultU64x32 (Data1.Value.u64, (UINT32) Data2.Value.u64);
2865 break;
2866
2867 case EFI_IFR_DIVIDE_OP:
2868 Value->Value.u64 = DivU64x32 (Data1.Value.u64, (UINT32) Data2.Value.u64);
2869 break;
2870
2871 case EFI_IFR_MODULO_OP:
2872 DivU64x32Remainder (Data1.Value.u64, (UINT32) Data2.Value.u64, &TempValue);
2873 Value->Value.u64 = TempValue;
2874 break;
2875
2876 case EFI_IFR_BITWISE_AND_OP:
2877 Value->Value.u64 = Data1.Value.u64 & Data2.Value.u64;
2878 break;
2879
2880 case EFI_IFR_BITWISE_OR_OP:
2881 Value->Value.u64 = Data1.Value.u64 | Data2.Value.u64;
2882 break;
2883
2884 case EFI_IFR_SHIFT_LEFT_OP:
2885 Value->Value.u64 = LShiftU64 (Data1.Value.u64, (UINTN) Data2.Value.u64);
2886 break;
2887
2888 case EFI_IFR_SHIFT_RIGHT_OP:
2889 Value->Value.u64 = RShiftU64 (Data1.Value.u64, (UINTN) Data2.Value.u64);
2890 break;
2891
2892 default:
2893 break;
2894 }
2895 break;
2896
2897 case EFI_IFR_AND_OP:
2898 case EFI_IFR_OR_OP:
2899 //
2900 // Two Boolean operator
2901 //
2902 Status = PopExpression (&Data2);
2903 if (EFI_ERROR (Status)) {
2904 goto Done;
2905 }
2906 if (Data2.Type != EFI_IFR_TYPE_BOOLEAN) {
2907 Status = EFI_INVALID_PARAMETER;
2908 goto Done;
2909 }
2910
2911 //
2912 // Pop another expression from the expression stack
2913 //
2914 Status = PopExpression (&Data1);
2915 if (EFI_ERROR (Status)) {
2916 goto Done;
2917 }
2918 if (Data1.Type != EFI_IFR_TYPE_BOOLEAN) {
2919 Status = EFI_INVALID_PARAMETER;
2920 goto Done;
2921 }
2922
2923 if (OpCode->Operand == EFI_IFR_AND_OP) {
2924 Value->Value.b = (BOOLEAN) (Data1.Value.b && Data2.Value.b);
2925 } else {
2926 Value->Value.b = (BOOLEAN) (Data1.Value.b || Data2.Value.b);
2927 }
2928 break;
2929
2930 case EFI_IFR_EQUAL_OP:
2931 case EFI_IFR_NOT_EQUAL_OP:
2932 case EFI_IFR_GREATER_EQUAL_OP:
2933 case EFI_IFR_GREATER_THAN_OP:
2934 case EFI_IFR_LESS_EQUAL_OP:
2935 case EFI_IFR_LESS_THAN_OP:
2936 //
2937 // Compare two integer, string, boolean or date/time
2938 //
2939 Status = PopExpression (&Data2);
2940 if (EFI_ERROR (Status)) {
2941 goto Done;
2942 }
2943 if (Data2.Type > EFI_IFR_TYPE_BOOLEAN &&
2944 Data2.Type != EFI_IFR_TYPE_STRING &&
2945 Data2.Type != EFI_IFR_TYPE_BUFFER) {
2946 Status = EFI_INVALID_PARAMETER;
2947 goto Done;
2948 }
2949
2950 //
2951 // Pop another expression from the expression stack
2952 //
2953 Status = PopExpression (&Data1);
2954 if (EFI_ERROR (Status)) {
2955 goto Done;
2956 }
2957
2958 Result = CompareHiiValue (&Data1, &Data2, FormSet->HiiHandle);
2959 if (Data1.Type == EFI_IFR_TYPE_BUFFER) {
2960 FreePool (Data1.Buffer);
2961 FreePool (Data2.Buffer);
2962 }
2963
2964 if (Result == EFI_INVALID_PARAMETER) {
2965 Status = EFI_INVALID_PARAMETER;
2966 goto Done;
2967 }
2968
2969 switch (OpCode->Operand) {
2970 case EFI_IFR_EQUAL_OP:
2971 Value->Value.b = (BOOLEAN) ((Result == 0) ? TRUE : FALSE);
2972 break;
2973
2974 case EFI_IFR_NOT_EQUAL_OP:
2975 Value->Value.b = (BOOLEAN) ((Result != 0) ? TRUE : FALSE);
2976 break;
2977
2978 case EFI_IFR_GREATER_EQUAL_OP:
2979 Value->Value.b = (BOOLEAN) ((Result >= 0) ? TRUE : FALSE);
2980 break;
2981
2982 case EFI_IFR_GREATER_THAN_OP:
2983 Value->Value.b = (BOOLEAN) ((Result > 0) ? TRUE : FALSE);
2984 break;
2985
2986 case EFI_IFR_LESS_EQUAL_OP:
2987 Value->Value.b = (BOOLEAN) ((Result <= 0) ? TRUE : FALSE);
2988 break;
2989
2990 case EFI_IFR_LESS_THAN_OP:
2991 Value->Value.b = (BOOLEAN) ((Result < 0) ? TRUE : FALSE);
2992 break;
2993
2994 default:
2995 break;
2996 }
2997 break;
2998
2999 case EFI_IFR_MATCH_OP:
3000 Status = InitializeUnicodeCollationProtocol ();
3001 if (EFI_ERROR (Status)) {
3002 goto Done;
3003 }
3004
3005 Status = IfrMatch (FormSet, Value);
3006 break;
3007
3008 case EFI_IFR_CATENATE_OP:
3009 Status = IfrCatenate (FormSet, Value);
3010 break;
3011
3012 //
3013 // ternary-op
3014 //
3015 case EFI_IFR_CONDITIONAL_OP:
3016 //
3017 // Pop third expression from the expression stack
3018 //
3019 Status = PopExpression (&Data3);
3020 if (EFI_ERROR (Status)) {
3021 goto Done;
3022 }
3023
3024 //
3025 // Pop second expression from the expression stack
3026 //
3027 Status = PopExpression (&Data2);
3028 if (EFI_ERROR (Status)) {
3029 goto Done;
3030 }
3031
3032 //
3033 // Pop first expression from the expression stack
3034 //
3035 Status = PopExpression (&Data1);
3036 if (EFI_ERROR (Status)) {
3037 goto Done;
3038 }
3039 if (Data1.Type != EFI_IFR_TYPE_BOOLEAN) {
3040 Status = EFI_INVALID_PARAMETER;
3041 goto Done;
3042 }
3043
3044 if (Data1.Value.b) {
3045 Value = &Data3;
3046 } else {
3047 Value = &Data2;
3048 }
3049 break;
3050
3051 case EFI_IFR_FIND_OP:
3052 Status = IfrFind (FormSet, OpCode->Format, Value);
3053 break;
3054
3055 case EFI_IFR_MID_OP:
3056 Status = IfrMid (FormSet, Value);
3057 break;
3058
3059 case EFI_IFR_TOKEN_OP:
3060 Status = IfrToken (FormSet, Value);
3061 break;
3062
3063 case EFI_IFR_SPAN_OP:
3064 Status = IfrSpan (FormSet, OpCode->Flags, Value);
3065 break;
3066
3067 case EFI_IFR_MAP_OP:
3068 //
3069 // Pop the check value
3070 //
3071 Status = PopExpression (&Data1);
3072 if (EFI_ERROR (Status)) {
3073 goto Done;
3074 }
3075 //
3076 // Check MapExpression list is valid.
3077 //
3078 if (OpCode->MapExpressionList.ForwardLink == NULL) {
3079 Status = EFI_INVALID_PARAMETER;
3080 goto Done;
3081 }
3082 //
3083 // Go through map expression list.
3084 //
3085 SubExpressionLink = GetFirstNode(&OpCode->MapExpressionList);
3086 while (!IsNull (&OpCode->MapExpressionList, SubExpressionLink)) {
3087 SubExpression = FORM_EXPRESSION_FROM_LINK (SubExpressionLink);
3088 //
3089 // Evaluate the first expression in this pair.
3090 //
3091 Status = EvaluateExpression (FormSet, Form, SubExpression);
3092 if (EFI_ERROR (Status)) {
3093 goto Done;
3094 }
3095 //
3096 // Compare the expression value with current value
3097 //
3098 if (CompareHiiValue (&Data1, &SubExpression->Result, NULL) == 0) {
3099 //
3100 // Try get the map value.
3101 //
3102 SubExpressionLink = GetNextNode (&OpCode->MapExpressionList, SubExpressionLink);
3103 if (IsNull (&OpCode->MapExpressionList, SubExpressionLink)) {
3104 Status = EFI_INVALID_PARAMETER;
3105 goto Done;
3106 }
3107 SubExpression = FORM_EXPRESSION_FROM_LINK (SubExpressionLink);
3108 Status = EvaluateExpression (FormSet, Form, SubExpression);
3109 if (EFI_ERROR (Status)) {
3110 goto Done;
3111 }
3112 Value = &SubExpression->Result;
3113 break;
3114 }
3115 //
3116 // Skip the second expression on this pair.
3117 //
3118 SubExpressionLink = GetNextNode (&OpCode->MapExpressionList, SubExpressionLink);
3119 if (IsNull (&OpCode->MapExpressionList, SubExpressionLink)) {
3120 Status = EFI_INVALID_PARAMETER;
3121 goto Done;
3122 }
3123 //
3124 // Goto the first expression on next pair.
3125 //
3126 SubExpressionLink = GetNextNode (&OpCode->MapExpressionList, SubExpressionLink);
3127 }
3128
3129 //
3130 // No map value is found.
3131 //
3132 if (IsNull (&OpCode->MapExpressionList, SubExpressionLink)) {
3133 Value->Type = EFI_IFR_TYPE_UNDEFINED;
3134 Value->Value.u8 = 0;
3135 }
3136 break;
3137
3138 default:
3139 break;
3140 }
3141 if (EFI_ERROR (Status)) {
3142 goto Done;
3143 }
3144
3145 Status = PushExpression (Value);
3146 if (EFI_ERROR (Status)) {
3147 goto Done;
3148 }
3149 }
3150
3151 //
3152 // Pop the final result from expression stack
3153 //
3154 Value = &Data1;
3155 Status = PopExpression (Value);
3156 if (EFI_ERROR (Status)) {
3157 goto Done;
3158 }
3159
3160 //
3161 // After evaluating an expression, there should be only one value left on the expression stack
3162 //
3163 if (PopExpression (Value) != EFI_ACCESS_DENIED) {
3164 Status = EFI_INVALID_PARAMETER;
3165 }
3166
3167 Done:
3168 RestoreExpressionEvaluationStackOffset (StackOffset);
3169 if (!EFI_ERROR (Status)) {
3170 CopyMem (&Expression->Result, Value, sizeof (EFI_HII_VALUE));
3171 }
3172
3173 return Status;
3174 }
3175
3176 /**
3177 Return the result of the expression list. Check the expression list and
3178 return the highest priority express result.
3179 Priority: DisableIf > SuppressIf > GrayOutIf > FALSE
3180
3181 @param ExpList The input expression list.
3182 @param Evaluate Whether need to evaluate the expression first.
3183 @param FormSet FormSet associated with this expression.
3184 @param Form Form associated with this expression.
3185
3186 @retval EXPRESS_RESULT Return the higher priority express result.
3187 DisableIf > SuppressIf > GrayOutIf > FALSE
3188
3189 **/
3190 EXPRESS_RESULT
3191 EvaluateExpressionList (
3192 IN FORM_EXPRESSION_LIST *ExpList,
3193 IN BOOLEAN Evaluate,
3194 IN FORM_BROWSER_FORMSET *FormSet, OPTIONAL
3195 IN FORM_BROWSER_FORM *Form OPTIONAL
3196 )
3197 {
3198 UINTN Index;
3199 EXPRESS_RESULT ReturnVal;
3200 EXPRESS_RESULT CompareOne;
3201 EFI_STATUS Status;
3202
3203 if (ExpList == NULL) {
3204 return ExpressFalse;
3205 }
3206
3207 ASSERT(ExpList->Signature == FORM_EXPRESSION_LIST_SIGNATURE);
3208 Index = 0;
3209
3210 //
3211 // Check whether need to evaluate the expression first.
3212 //
3213 if (Evaluate) {
3214 while (ExpList->Count > Index) {
3215 Status = EvaluateExpression (FormSet, Form, ExpList->Expression[Index++]);
3216 if (EFI_ERROR (Status)) {
3217 return ExpressFalse;
3218 }
3219 }
3220 }
3221
3222 //
3223 // Run the list of expressions.
3224 //
3225 ReturnVal = ExpressFalse;
3226 for (Index = 0; Index < ExpList->Count; Index++) {
3227 if (ExpList->Expression[Index]->Result.Type == EFI_IFR_TYPE_BOOLEAN &&
3228 ExpList->Expression[Index]->Result.Value.b) {
3229 switch (ExpList->Expression[Index]->Type) {
3230 case EFI_HII_EXPRESSION_SUPPRESS_IF:
3231 CompareOne = ExpressSuppress;
3232 break;
3233
3234 case EFI_HII_EXPRESSION_GRAY_OUT_IF:
3235 CompareOne = ExpressGrayOut;
3236 break;
3237
3238 case EFI_HII_EXPRESSION_DISABLE_IF:
3239 CompareOne = ExpressDisable;
3240 break;
3241
3242 default:
3243 return ExpressFalse;
3244 }
3245
3246 ReturnVal = ReturnVal < CompareOne ? CompareOne : ReturnVal;
3247 }
3248 }
3249
3250 return ReturnVal;
3251 }