]> git.proxmox.com Git - mirror_edk2.git/blob - MdeModulePkg/Universal/SetupBrowserDxe/Expression.c
Update code to support VS2013 tool chain.
[mirror_edk2.git] / MdeModulePkg / Universal / SetupBrowserDxe / Expression.c
1 /** @file
2 Utility functions for expression evaluation.
3
4 Copyright (c) 2007 - 2014, 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, GetSetValueWithHiiDriver);
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 Check whether this value type can be transfer to EFI_IFR_TYPE_BUFFER type.
993
994 EFI_IFR_TYPE_REF, EFI_IFR_TYPE_DATE and EFI_IFR_TYPE_TIME are converted to
995 EFI_IFR_TYPE_BUFFER when do the value compare.
996
997 @param Value Expression value to compare on.
998
999 @retval TRUE This value type can be transter to EFI_IFR_TYPE_BUFFER type.
1000 @retval FALSE This value type can't be transter to EFI_IFR_TYPE_BUFFER type.
1001
1002 **/
1003 BOOLEAN
1004 IsTypeInBuffer (
1005 IN EFI_HII_VALUE *Value
1006 )
1007 {
1008 switch (Value->Type) {
1009 case EFI_IFR_TYPE_BUFFER:
1010 case EFI_IFR_TYPE_DATE:
1011 case EFI_IFR_TYPE_TIME:
1012 case EFI_IFR_TYPE_REF:
1013 return TRUE;
1014
1015 default:
1016 return FALSE;
1017 }
1018 }
1019
1020 /**
1021 Check whether this value type can be transfer to EFI_IFR_TYPE_UINT64
1022
1023 @param Value Expression value to compare on.
1024
1025 @retval TRUE This value type can be transter to EFI_IFR_TYPE_BUFFER type.
1026 @retval FALSE This value type can't be transter to EFI_IFR_TYPE_BUFFER type.
1027
1028 **/
1029 BOOLEAN
1030 IsTypeInUINT64 (
1031 IN EFI_HII_VALUE *Value
1032 )
1033 {
1034 switch (Value->Type) {
1035 case EFI_IFR_TYPE_NUM_SIZE_8:
1036 case EFI_IFR_TYPE_NUM_SIZE_16:
1037 case EFI_IFR_TYPE_NUM_SIZE_32:
1038 case EFI_IFR_TYPE_NUM_SIZE_64:
1039 case EFI_IFR_TYPE_BOOLEAN:
1040 return TRUE;
1041
1042 default:
1043 return FALSE;
1044 }
1045 }
1046
1047 /**
1048 Return the buffer length for this value.
1049
1050 EFI_IFR_TYPE_REF, EFI_IFR_TYPE_DATE and EFI_IFR_TYPE_TIME are converted to
1051 EFI_IFR_TYPE_BUFFER when do the value compare.
1052
1053 @param Value Expression value to compare on.
1054
1055 @retval BufLen Return the buffer length.
1056
1057 **/
1058 UINT16
1059 GetLengthForValue (
1060 IN EFI_HII_VALUE *Value
1061 )
1062 {
1063 switch (Value->Type) {
1064 case EFI_IFR_TYPE_BUFFER:
1065 return Value->BufferLen;
1066
1067 case EFI_IFR_TYPE_DATE:
1068 return (UINT16) sizeof (EFI_HII_DATE);
1069
1070 case EFI_IFR_TYPE_TIME:
1071 return (UINT16) sizeof (EFI_HII_TIME);
1072
1073 case EFI_IFR_TYPE_REF:
1074 return (UINT16) sizeof (EFI_HII_REF);
1075
1076 default:
1077 return 0;
1078 }
1079 }
1080
1081 /**
1082 Return the buffer pointer for this value.
1083
1084 EFI_IFR_TYPE_REF, EFI_IFR_TYPE_DATE and EFI_IFR_TYPE_TIME are converted to
1085 EFI_IFR_TYPE_BUFFER when do the value compare.
1086
1087 @param Value Expression value to compare on.
1088
1089 @retval Buf Return the buffer pointer.
1090
1091 **/
1092 UINT8 *
1093 GetBufferForValue (
1094 IN EFI_HII_VALUE *Value
1095 )
1096 {
1097 switch (Value->Type) {
1098 case EFI_IFR_TYPE_BUFFER:
1099 return Value->Buffer;
1100
1101 case EFI_IFR_TYPE_DATE:
1102 return (UINT8 *) (&Value->Value.date);
1103
1104 case EFI_IFR_TYPE_TIME:
1105 return (UINT8 *) (&Value->Value.time);
1106
1107 case EFI_IFR_TYPE_REF:
1108 return (UINT8 *) (&Value->Value.ref);
1109
1110 default:
1111 return NULL;
1112 }
1113 }
1114
1115 /**
1116 Evaluate opcode EFI_IFR_TO_STRING.
1117
1118 @param FormSet Formset which contains this opcode.
1119 @param Format String format in EFI_IFR_TO_STRING.
1120 @param Result Evaluation result for this opcode.
1121
1122 @retval EFI_SUCCESS Opcode evaluation success.
1123 @retval Other Opcode evaluation failed.
1124
1125 **/
1126 EFI_STATUS
1127 IfrToString (
1128 IN FORM_BROWSER_FORMSET *FormSet,
1129 IN UINT8 Format,
1130 OUT EFI_HII_VALUE *Result
1131 )
1132 {
1133 EFI_STATUS Status;
1134 EFI_HII_VALUE Value;
1135 CHAR16 *String;
1136 CHAR16 *PrintFormat;
1137 CHAR16 Buffer[MAXIMUM_VALUE_CHARACTERS];
1138 UINT8 *TmpBuf;
1139 UINT8 *SrcBuf;
1140 UINTN SrcLen;
1141 UINTN BufferSize;
1142
1143 Status = PopExpression (&Value);
1144 if (EFI_ERROR (Status)) {
1145 return Status;
1146 }
1147
1148 switch (Value.Type) {
1149 case EFI_IFR_TYPE_NUM_SIZE_8:
1150 case EFI_IFR_TYPE_NUM_SIZE_16:
1151 case EFI_IFR_TYPE_NUM_SIZE_32:
1152 case EFI_IFR_TYPE_NUM_SIZE_64:
1153 BufferSize = MAXIMUM_VALUE_CHARACTERS * sizeof (CHAR16);
1154 switch (Format) {
1155 case EFI_IFR_STRING_UNSIGNED_DEC:
1156 case EFI_IFR_STRING_SIGNED_DEC:
1157 PrintFormat = L"%ld";
1158 break;
1159
1160 case EFI_IFR_STRING_LOWERCASE_HEX:
1161 PrintFormat = L"%lx";
1162 break;
1163
1164 case EFI_IFR_STRING_UPPERCASE_HEX:
1165 PrintFormat = L"%lX";
1166 break;
1167
1168 default:
1169 Result->Type = EFI_IFR_TYPE_UNDEFINED;
1170 return EFI_SUCCESS;
1171 }
1172 UnicodeSPrint (Buffer, BufferSize, PrintFormat, Value.Value.u64);
1173 String = Buffer;
1174 break;
1175
1176 case EFI_IFR_TYPE_STRING:
1177 CopyMem (Result, &Value, sizeof (EFI_HII_VALUE));
1178 return EFI_SUCCESS;
1179
1180 case EFI_IFR_TYPE_BOOLEAN:
1181 String = (Value.Value.b) ? L"True" : L"False";
1182 break;
1183
1184 case EFI_IFR_TYPE_BUFFER:
1185 case EFI_IFR_TYPE_DATE:
1186 case EFI_IFR_TYPE_TIME:
1187 case EFI_IFR_TYPE_REF:
1188 //
1189 // + 3 is base on the unicode format, the length may be odd number,
1190 // so need 1 byte to align, also need 2 bytes for L'\0'.
1191 //
1192 if (Value.Type == EFI_IFR_TYPE_BUFFER) {
1193 SrcLen = Value.BufferLen;
1194 SrcBuf = Value.Buffer;
1195 } else {
1196 SrcBuf = GetBufferForValue(&Value);
1197 SrcLen = GetLengthForValue(&Value);
1198 }
1199
1200 TmpBuf = AllocateZeroPool (SrcLen + 3);
1201 ASSERT (TmpBuf != NULL);
1202 if (Format == EFI_IFR_STRING_ASCII) {
1203 CopyMem (TmpBuf, SrcBuf, SrcLen);
1204 PrintFormat = L"%a";
1205 } else {
1206 // Format == EFI_IFR_STRING_UNICODE
1207 CopyMem (TmpBuf, SrcBuf, SrcLen * sizeof (CHAR16));
1208 PrintFormat = L"%s";
1209 }
1210 UnicodeSPrint (Buffer, sizeof (Buffer), PrintFormat, TmpBuf);
1211 String = Buffer;
1212 FreePool (TmpBuf);
1213 if (Value.Type == EFI_IFR_TYPE_BUFFER) {
1214 FreePool (Value.Buffer);
1215 }
1216 break;
1217
1218 default:
1219 Result->Type = EFI_IFR_TYPE_UNDEFINED;
1220 return EFI_SUCCESS;
1221 }
1222
1223 Result->Type = EFI_IFR_TYPE_STRING;
1224 Result->Value.string = NewString (String, FormSet->HiiHandle);
1225 return EFI_SUCCESS;
1226 }
1227
1228
1229 /**
1230 Evaluate opcode EFI_IFR_TO_UINT.
1231
1232 @param FormSet Formset which contains this opcode.
1233 @param Result Evaluation result for this opcode.
1234
1235 @retval EFI_SUCCESS Opcode evaluation success.
1236 @retval Other Opcode evaluation failed.
1237
1238 **/
1239 EFI_STATUS
1240 IfrToUint (
1241 IN FORM_BROWSER_FORMSET *FormSet,
1242 OUT EFI_HII_VALUE *Result
1243 )
1244 {
1245 EFI_STATUS Status;
1246 EFI_HII_VALUE Value;
1247 CHAR16 *String;
1248 CHAR16 *StringPtr;
1249
1250 Status = PopExpression (&Value);
1251 if (EFI_ERROR (Status)) {
1252 return Status;
1253 }
1254
1255 if (Value.Type >= EFI_IFR_TYPE_OTHER && !IsTypeInBuffer(&Value)) {
1256 Result->Type = EFI_IFR_TYPE_UNDEFINED;
1257 return EFI_SUCCESS;
1258 }
1259
1260 Status = EFI_SUCCESS;
1261 if (Value.Type == EFI_IFR_TYPE_STRING) {
1262 String = GetToken (Value.Value.string, FormSet->HiiHandle);
1263 if (String == NULL) {
1264 return EFI_NOT_FOUND;
1265 }
1266
1267 IfrStrToUpper (String);
1268 StringPtr = StrStr (String, L"0X");
1269 if (StringPtr != NULL) {
1270 //
1271 // Hex string
1272 //
1273 Result->Value.u64 = StrHexToUint64 (String);
1274 } else {
1275 //
1276 // decimal string
1277 //
1278 Result->Value.u64 = StrDecimalToUint64 (String);
1279 }
1280 FreePool (String);
1281 } else if (IsTypeInBuffer(&Value)) {
1282 if (GetLengthForValue (&Value) > 8) {
1283 if (Value.Type == EFI_IFR_TYPE_BUFFER) {
1284 FreePool (Value.Buffer);
1285 }
1286 Result->Type = EFI_IFR_TYPE_UNDEFINED;
1287 return EFI_SUCCESS;
1288 }
1289 Result->Value.u64 = *(UINT64*) GetBufferForValue (&Value);
1290 if (Value.Type == EFI_IFR_TYPE_BUFFER) {
1291 FreePool (Value.Buffer);
1292 }
1293 } else {
1294 CopyMem (Result, &Value, sizeof (EFI_HII_VALUE));
1295 }
1296
1297 Result->Type = EFI_IFR_TYPE_NUM_SIZE_64;
1298 return Status;
1299 }
1300
1301
1302 /**
1303 Evaluate opcode EFI_IFR_CATENATE.
1304
1305 @param FormSet Formset which contains this opcode.
1306 @param Result Evaluation result for this opcode.
1307
1308 @retval EFI_SUCCESS Opcode evaluation success.
1309 @retval Other Opcode evaluation failed.
1310
1311 **/
1312 EFI_STATUS
1313 IfrCatenate (
1314 IN FORM_BROWSER_FORMSET *FormSet,
1315 OUT EFI_HII_VALUE *Result
1316 )
1317 {
1318 EFI_STATUS Status;
1319 EFI_HII_VALUE Value[2];
1320 CHAR16 *String[2];
1321 UINTN Index;
1322 CHAR16 *StringPtr;
1323 UINTN Size;
1324 UINT16 Length0;
1325 UINT16 Length1;
1326
1327 //
1328 // String[0] - The second string
1329 // String[1] - The first string
1330 //
1331 String[0] = NULL;
1332 String[1] = NULL;
1333 StringPtr = NULL;
1334 Status = EFI_SUCCESS;
1335 ZeroMem (Value, sizeof (Value));
1336
1337 Status = PopExpression (&Value[0]);
1338 if (EFI_ERROR (Status)) {
1339 goto Done;
1340 }
1341
1342 Status = PopExpression (&Value[1]);
1343 if (EFI_ERROR (Status)) {
1344 goto Done;
1345 }
1346
1347 for (Index = 0; Index < 2; Index++) {
1348 if (Value[Index].Type != EFI_IFR_TYPE_STRING && !IsTypeInBuffer(&Value[Index])) {
1349 Result->Type = EFI_IFR_TYPE_UNDEFINED;
1350 Status = EFI_SUCCESS;
1351 goto Done;
1352 }
1353
1354 if (Value[Index].Type == EFI_IFR_TYPE_STRING) {
1355 String[Index] = GetToken (Value[Index].Value.string, FormSet->HiiHandle);
1356 if (String[Index] == NULL) {
1357 Status = EFI_NOT_FOUND;
1358 goto Done;
1359 }
1360 }
1361 }
1362
1363 if (Value[0].Type == EFI_IFR_TYPE_STRING) {
1364 Size = StrSize (String[0]);
1365 StringPtr= AllocatePool (StrSize (String[1]) + Size);
1366 ASSERT (StringPtr != NULL);
1367 StrCpy (StringPtr, String[1]);
1368 StrCat (StringPtr, String[0]);
1369
1370 Result->Type = EFI_IFR_TYPE_STRING;
1371 Result->Value.string = NewString (StringPtr, FormSet->HiiHandle);
1372 } else {
1373 Result->Type = EFI_IFR_TYPE_BUFFER;
1374 Length0 = GetLengthForValue(&Value[0]);
1375 Length1 = GetLengthForValue(&Value[1]);
1376 Result->BufferLen = (UINT16) (Length0 + Length1);
1377
1378 Result->Buffer = AllocateZeroPool (Result->BufferLen);
1379 ASSERT (Result->Buffer != NULL);
1380
1381 CopyMem (Result->Buffer, GetBufferForValue(&Value[0]), Length0);
1382 CopyMem (&Result->Buffer[Length0], GetBufferForValue(&Value[1]), Length1);
1383 }
1384 Done:
1385 if (Value[0].Buffer != NULL) {
1386 FreePool (Value[0].Buffer);
1387 }
1388 if (Value[1].Buffer != NULL) {
1389 FreePool (Value[1].Buffer);
1390 }
1391 if (String[0] != NULL) {
1392 FreePool (String[0]);
1393 }
1394 if (String[1] != NULL) {
1395 FreePool (String[1]);
1396 }
1397 if (StringPtr != NULL) {
1398 FreePool (StringPtr);
1399 }
1400
1401 return Status;
1402 }
1403
1404
1405 /**
1406 Evaluate opcode EFI_IFR_MATCH.
1407
1408 @param FormSet Formset which contains this opcode.
1409 @param Result Evaluation result for this opcode.
1410
1411 @retval EFI_SUCCESS Opcode evaluation success.
1412 @retval Other Opcode evaluation failed.
1413
1414 **/
1415 EFI_STATUS
1416 IfrMatch (
1417 IN FORM_BROWSER_FORMSET *FormSet,
1418 OUT EFI_HII_VALUE *Result
1419 )
1420 {
1421 EFI_STATUS Status;
1422 EFI_HII_VALUE Value[2];
1423 CHAR16 *String[2];
1424 UINTN Index;
1425
1426 //
1427 // String[0] - The string to search
1428 // String[1] - pattern
1429 //
1430 String[0] = NULL;
1431 String[1] = NULL;
1432 Status = EFI_SUCCESS;
1433 ZeroMem (Value, sizeof (Value));
1434
1435 Status = PopExpression (&Value[0]);
1436 if (EFI_ERROR (Status)) {
1437 goto Done;
1438 }
1439
1440 Status = PopExpression (&Value[1]);
1441 if (EFI_ERROR (Status)) {
1442 goto Done;
1443 }
1444
1445 for (Index = 0; Index < 2; Index++) {
1446 if (Value[Index].Type != EFI_IFR_TYPE_STRING) {
1447 Result->Type = EFI_IFR_TYPE_UNDEFINED;
1448 Status = EFI_SUCCESS;
1449 goto Done;
1450 }
1451
1452 String[Index] = GetToken (Value[Index].Value.string, FormSet->HiiHandle);
1453 if (String [Index] == NULL) {
1454 Status = EFI_NOT_FOUND;
1455 goto Done;
1456 }
1457 }
1458
1459 Result->Type = EFI_IFR_TYPE_BOOLEAN;
1460 Result->Value.b = mUnicodeCollation->MetaiMatch (mUnicodeCollation, String[0], String[1]);
1461
1462 Done:
1463 if (String[0] != NULL) {
1464 FreePool (String[0]);
1465 }
1466 if (String[1] != NULL) {
1467 FreePool (String[1]);
1468 }
1469
1470 return Status;
1471 }
1472
1473
1474 /**
1475 Evaluate opcode EFI_IFR_FIND.
1476
1477 @param FormSet Formset which contains this opcode.
1478 @param Format Case sensitive or insensitive.
1479 @param Result Evaluation result for this opcode.
1480
1481 @retval EFI_SUCCESS Opcode evaluation success.
1482 @retval Other Opcode evaluation failed.
1483
1484 **/
1485 EFI_STATUS
1486 IfrFind (
1487 IN FORM_BROWSER_FORMSET *FormSet,
1488 IN UINT8 Format,
1489 OUT EFI_HII_VALUE *Result
1490 )
1491 {
1492 EFI_STATUS Status;
1493 EFI_HII_VALUE Value[3];
1494 CHAR16 *String[2];
1495 UINTN Base;
1496 CHAR16 *StringPtr;
1497 UINTN Index;
1498
1499 ZeroMem (Value, sizeof (Value));
1500
1501 if (Format > EFI_IFR_FF_CASE_INSENSITIVE) {
1502 return EFI_INVALID_PARAMETER;
1503 }
1504
1505 Status = PopExpression (&Value[0]);
1506 if (EFI_ERROR (Status)) {
1507 return Status;
1508 }
1509
1510 Status = PopExpression (&Value[1]);
1511 if (EFI_ERROR (Status)) {
1512 return Status;
1513 }
1514
1515 Status = PopExpression (&Value[2]);
1516 if (EFI_ERROR (Status)) {
1517 return Status;
1518 }
1519
1520 if (Value[0].Type > EFI_IFR_TYPE_NUM_SIZE_64) {
1521 Result->Type = EFI_IFR_TYPE_UNDEFINED;
1522 return EFI_SUCCESS;
1523 }
1524 Base = (UINTN) Value[0].Value.u64;
1525
1526 //
1527 // String[0] - sub-string
1528 // String[1] - The string to search
1529 //
1530 String[0] = NULL;
1531 String[1] = NULL;
1532 for (Index = 0; Index < 2; Index++) {
1533 if (Value[Index + 1].Type != EFI_IFR_TYPE_STRING) {
1534 Result->Type = EFI_IFR_TYPE_UNDEFINED;
1535 Status = EFI_SUCCESS;
1536 goto Done;
1537 }
1538
1539 String[Index] = GetToken (Value[Index + 1].Value.string, FormSet->HiiHandle);
1540 if (String[Index] == NULL) {
1541 Status = EFI_NOT_FOUND;
1542 goto Done;
1543 }
1544
1545 if (Format == EFI_IFR_FF_CASE_INSENSITIVE) {
1546 //
1547 // Case insensitive, convert both string to upper case
1548 //
1549 IfrStrToUpper (String[Index]);
1550 }
1551 }
1552
1553 Result->Type = EFI_IFR_TYPE_NUM_SIZE_64;
1554 if (Base >= StrLen (String[1])) {
1555 Result->Value.u64 = 0xFFFFFFFFFFFFFFFFULL;
1556 } else {
1557 StringPtr = StrStr (String[1] + Base, String[0]);
1558 Result->Value.u64 = (StringPtr == NULL) ? 0xFFFFFFFFFFFFFFFFULL : (StringPtr - String[1]);
1559 }
1560
1561 Done:
1562 if (String[0] != NULL) {
1563 FreePool (String[0]);
1564 }
1565 if (String[1] != NULL) {
1566 FreePool (String[1]);
1567 }
1568
1569 return Status;
1570 }
1571
1572
1573 /**
1574 Evaluate opcode EFI_IFR_MID.
1575
1576 @param FormSet Formset which contains this opcode.
1577 @param Result Evaluation result for this opcode.
1578
1579 @retval EFI_SUCCESS Opcode evaluation success.
1580 @retval Other Opcode evaluation failed.
1581
1582 **/
1583 EFI_STATUS
1584 IfrMid (
1585 IN FORM_BROWSER_FORMSET *FormSet,
1586 OUT EFI_HII_VALUE *Result
1587 )
1588 {
1589 EFI_STATUS Status;
1590 EFI_HII_VALUE Value[3];
1591 CHAR16 *String;
1592 UINTN Base;
1593 UINTN Length;
1594 CHAR16 *SubString;
1595 UINT16 BufferLen;
1596 UINT8 *Buffer;
1597
1598 ZeroMem (Value, sizeof (Value));
1599
1600 Status = PopExpression (&Value[0]);
1601 if (EFI_ERROR (Status)) {
1602 return Status;
1603 }
1604
1605 Status = PopExpression (&Value[1]);
1606 if (EFI_ERROR (Status)) {
1607 return Status;
1608 }
1609
1610 Status = PopExpression (&Value[2]);
1611 if (EFI_ERROR (Status)) {
1612 return Status;
1613 }
1614
1615 if (Value[0].Type > EFI_IFR_TYPE_NUM_SIZE_64) {
1616 Result->Type = EFI_IFR_TYPE_UNDEFINED;
1617 return EFI_SUCCESS;
1618 }
1619 Length = (UINTN) Value[0].Value.u64;
1620
1621 if (Value[1].Type > EFI_IFR_TYPE_NUM_SIZE_64) {
1622 Result->Type = EFI_IFR_TYPE_UNDEFINED;
1623 return EFI_SUCCESS;
1624 }
1625 Base = (UINTN) Value[1].Value.u64;
1626
1627 if (Value[2].Type != EFI_IFR_TYPE_STRING && !IsTypeInBuffer(&Value[2])) {
1628 Result->Type = EFI_IFR_TYPE_UNDEFINED;
1629 return EFI_SUCCESS;
1630 }
1631 if (Value[2].Type == EFI_IFR_TYPE_STRING) {
1632 String = GetToken (Value[2].Value.string, FormSet->HiiHandle);
1633 if (String == NULL) {
1634 return EFI_NOT_FOUND;
1635 }
1636
1637 if (Length == 0 || Base >= StrLen (String)) {
1638 SubString = gEmptyString;
1639 } else {
1640 SubString = String + Base;
1641 if ((Base + Length) < StrLen (String)) {
1642 SubString[Length] = L'\0';
1643 }
1644 }
1645
1646 Result->Type = EFI_IFR_TYPE_STRING;
1647 Result->Value.string = NewString (SubString, FormSet->HiiHandle);
1648
1649 FreePool (String);
1650 } else {
1651 BufferLen = GetLengthForValue (&Value[2]);
1652 Buffer = GetBufferForValue (&Value[2]);
1653
1654 Result->Type = EFI_IFR_TYPE_BUFFER;
1655 if (Length == 0 || Base >= BufferLen) {
1656 Result->BufferLen = 0;
1657 Result->Buffer = NULL;
1658 } else {
1659 Result->BufferLen = (UINT16)((BufferLen - Base) < Length ? (BufferLen - Base) : Length);
1660 Result->Buffer = AllocateZeroPool (Result->BufferLen);
1661 ASSERT (Result->Buffer != NULL);
1662 CopyMem (Result->Buffer, &Buffer[Base], Result->BufferLen);
1663 }
1664
1665 if (Value[2].Type == EFI_IFR_TYPE_BUFFER) {
1666 FreePool (Value[2].Buffer);
1667 }
1668 }
1669
1670 return Status;
1671 }
1672
1673
1674 /**
1675 Evaluate opcode EFI_IFR_TOKEN.
1676
1677 @param FormSet Formset which contains this opcode.
1678 @param Result Evaluation result for this opcode.
1679
1680 @retval EFI_SUCCESS Opcode evaluation success.
1681 @retval Other Opcode evaluation failed.
1682
1683 **/
1684 EFI_STATUS
1685 IfrToken (
1686 IN FORM_BROWSER_FORMSET *FormSet,
1687 OUT EFI_HII_VALUE *Result
1688 )
1689 {
1690 EFI_STATUS Status;
1691 EFI_HII_VALUE Value[3];
1692 CHAR16 *String[2];
1693 UINTN Count;
1694 CHAR16 *Delimiter;
1695 CHAR16 *SubString;
1696 CHAR16 *StringPtr;
1697 UINTN Index;
1698
1699 ZeroMem (Value, sizeof (Value));
1700
1701 Status = PopExpression (&Value[0]);
1702 if (EFI_ERROR (Status)) {
1703 return Status;
1704 }
1705
1706 Status = PopExpression (&Value[1]);
1707 if (EFI_ERROR (Status)) {
1708 return Status;
1709 }
1710
1711 Status = PopExpression (&Value[2]);
1712 if (EFI_ERROR (Status)) {
1713 return Status;
1714 }
1715
1716 if (Value[0].Type > EFI_IFR_TYPE_NUM_SIZE_64) {
1717 Result->Type = EFI_IFR_TYPE_UNDEFINED;
1718 return EFI_SUCCESS;
1719 }
1720 Count = (UINTN) Value[0].Value.u64;
1721
1722 //
1723 // String[0] - Delimiter
1724 // String[1] - The string to search
1725 //
1726 String[0] = NULL;
1727 String[1] = NULL;
1728 for (Index = 0; Index < 2; Index++) {
1729 if (Value[Index + 1].Type != EFI_IFR_TYPE_STRING) {
1730 Result->Type = EFI_IFR_TYPE_UNDEFINED;
1731 Status = EFI_SUCCESS;
1732 goto Done;
1733 }
1734
1735 String[Index] = GetToken (Value[Index + 1].Value.string, FormSet->HiiHandle);
1736 if (String[Index] == NULL) {
1737 Status = EFI_NOT_FOUND;
1738 goto Done;
1739 }
1740 }
1741
1742 Delimiter = String[0];
1743 SubString = String[1];
1744 while (Count > 0) {
1745 SubString = StrStr (SubString, Delimiter);
1746 if (SubString != NULL) {
1747 //
1748 // Skip over the delimiter
1749 //
1750 SubString = SubString + StrLen (Delimiter);
1751 } else {
1752 break;
1753 }
1754 Count--;
1755 }
1756
1757 if (SubString == NULL) {
1758 //
1759 // nth delimited sub-string not found, push an empty string
1760 //
1761 SubString = gEmptyString;
1762 } else {
1763 //
1764 // Put a NULL terminator for nth delimited sub-string
1765 //
1766 StringPtr = StrStr (SubString, Delimiter);
1767 if (StringPtr != NULL) {
1768 *StringPtr = L'\0';
1769 }
1770 }
1771
1772 Result->Type = EFI_IFR_TYPE_STRING;
1773 Result->Value.string = NewString (SubString, FormSet->HiiHandle);
1774
1775 Done:
1776 if (String[0] != NULL) {
1777 FreePool (String[0]);
1778 }
1779 if (String[1] != NULL) {
1780 FreePool (String[1]);
1781 }
1782
1783 return Status;
1784 }
1785
1786
1787 /**
1788 Evaluate opcode EFI_IFR_SPAN.
1789
1790 @param FormSet Formset which contains this opcode.
1791 @param Flags FIRST_MATCHING or FIRST_NON_MATCHING.
1792 @param Result Evaluation result for this opcode.
1793
1794 @retval EFI_SUCCESS Opcode evaluation success.
1795 @retval Other Opcode evaluation failed.
1796
1797 **/
1798 EFI_STATUS
1799 IfrSpan (
1800 IN FORM_BROWSER_FORMSET *FormSet,
1801 IN UINT8 Flags,
1802 OUT EFI_HII_VALUE *Result
1803 )
1804 {
1805 EFI_STATUS Status;
1806 EFI_HII_VALUE Value[3];
1807 CHAR16 *String[2];
1808 CHAR16 *Charset;
1809 UINTN Base;
1810 UINTN Index;
1811 CHAR16 *StringPtr;
1812 BOOLEAN Found;
1813
1814 ZeroMem (Value, sizeof (Value));
1815
1816 Status = PopExpression (&Value[0]);
1817 if (EFI_ERROR (Status)) {
1818 return Status;
1819 }
1820
1821 Status = PopExpression (&Value[1]);
1822 if (EFI_ERROR (Status)) {
1823 return Status;
1824 }
1825
1826 Status = PopExpression (&Value[2]);
1827 if (EFI_ERROR (Status)) {
1828 return Status;
1829 }
1830
1831 if (Value[0].Type > EFI_IFR_TYPE_NUM_SIZE_64) {
1832 Result->Type = EFI_IFR_TYPE_UNDEFINED;
1833 return EFI_SUCCESS;
1834 }
1835 Base = (UINTN) Value[0].Value.u64;
1836
1837 //
1838 // String[0] - Charset
1839 // String[1] - The string to search
1840 //
1841 String[0] = NULL;
1842 String[1] = NULL;
1843 for (Index = 0; Index < 2; Index++) {
1844 if (Value[Index + 1].Type != EFI_IFR_TYPE_STRING) {
1845 Result->Type = EFI_IFR_TYPE_UNDEFINED;
1846 Status = EFI_SUCCESS;
1847 goto Done;
1848 }
1849
1850 String[Index] = GetToken (Value[Index + 1].Value.string, FormSet->HiiHandle);
1851 if (String [Index] == NULL) {
1852 Status = EFI_NOT_FOUND;
1853 goto Done;
1854 }
1855 }
1856
1857 if (Base >= StrLen (String[1])) {
1858 Result->Type = EFI_IFR_TYPE_UNDEFINED;
1859 Status = EFI_SUCCESS;
1860 goto Done;
1861 }
1862
1863 Found = FALSE;
1864 StringPtr = String[1] + Base;
1865 Charset = String[0];
1866 while (*StringPtr != 0 && !Found) {
1867 Index = 0;
1868 while (Charset[Index] != 0) {
1869 if (*StringPtr >= Charset[Index] && *StringPtr <= Charset[Index + 1]) {
1870 if (Flags == EFI_IFR_FLAGS_FIRST_MATCHING) {
1871 Found = TRUE;
1872 break;
1873 }
1874 } else {
1875 if (Flags == EFI_IFR_FLAGS_FIRST_NON_MATCHING) {
1876 Found = TRUE;
1877 break;
1878 }
1879 }
1880 //
1881 // Skip characters pair representing low-end of a range and high-end of a range
1882 //
1883 Index += 2;
1884 }
1885
1886 if (!Found) {
1887 StringPtr++;
1888 }
1889 }
1890
1891 Result->Type = EFI_IFR_TYPE_NUM_SIZE_64;
1892 Result->Value.u64 = StringPtr - String[1];
1893
1894 Done:
1895 if (String[0] != NULL) {
1896 FreePool (String[0]);
1897 }
1898 if (String[1] != NULL) {
1899 FreePool (String[1]);
1900 }
1901
1902 return Status;
1903 }
1904
1905
1906 /**
1907 Zero extend integer/boolean/date/time to UINT64 for comparing.
1908
1909 @param Value HII Value to be converted.
1910
1911 **/
1912 VOID
1913 ExtendValueToU64 (
1914 IN EFI_HII_VALUE *Value
1915 )
1916 {
1917 UINT64 Temp;
1918
1919 Temp = 0;
1920 switch (Value->Type) {
1921 case EFI_IFR_TYPE_NUM_SIZE_8:
1922 Temp = Value->Value.u8;
1923 break;
1924
1925 case EFI_IFR_TYPE_NUM_SIZE_16:
1926 Temp = Value->Value.u16;
1927 break;
1928
1929 case EFI_IFR_TYPE_NUM_SIZE_32:
1930 Temp = Value->Value.u32;
1931 break;
1932
1933 case EFI_IFR_TYPE_BOOLEAN:
1934 Temp = Value->Value.b;
1935 break;
1936
1937 case EFI_IFR_TYPE_TIME:
1938 Temp = Value->Value.u32 & 0xffffff;
1939 break;
1940
1941 case EFI_IFR_TYPE_DATE:
1942 Temp = Value->Value.u32;
1943 break;
1944
1945 default:
1946 return;
1947 }
1948
1949 Value->Value.u64 = Temp;
1950 }
1951
1952 /**
1953 Get UINT64 type value.
1954
1955 @param Value Input Hii value.
1956
1957 @retval UINT64 Return the UINT64 type value.
1958
1959 **/
1960 UINT64
1961 HiiValueToUINT64 (
1962 IN EFI_HII_VALUE *Value
1963 )
1964 {
1965 UINT64 RetVal;
1966
1967 RetVal = 0;
1968
1969 switch (Value->Type) {
1970 case EFI_IFR_TYPE_NUM_SIZE_8:
1971 RetVal = Value->Value.u8;
1972 break;
1973
1974 case EFI_IFR_TYPE_NUM_SIZE_16:
1975 RetVal = Value->Value.u16;
1976 break;
1977
1978 case EFI_IFR_TYPE_NUM_SIZE_32:
1979 RetVal = Value->Value.u32;
1980 break;
1981
1982 case EFI_IFR_TYPE_BOOLEAN:
1983 RetVal = Value->Value.b;
1984 break;
1985
1986 case EFI_IFR_TYPE_DATE:
1987 RetVal = *(UINT64*) &Value->Value.date;
1988 break;
1989
1990 case EFI_IFR_TYPE_TIME:
1991 RetVal = (*(UINT64*) &Value->Value.time) & 0xffffff;
1992 break;
1993
1994 default:
1995 RetVal = Value->Value.u64;
1996 break;
1997 }
1998
1999 return RetVal;
2000 }
2001
2002 /**
2003 Compare two Hii value.
2004
2005 @param Value1 Expression value to compare on left-hand.
2006 @param Value2 Expression value to compare on right-hand.
2007 @param Result Return value after compare.
2008 retval 0 Two operators equal.
2009 return Positive value if Value1 is greater than Value2.
2010 retval Negative value if Value1 is less than Value2.
2011 @param HiiHandle Only required for string compare.
2012
2013 @retval other Could not perform compare on two values.
2014 @retval EFI_SUCCESS Compare the value success.
2015
2016 **/
2017 EFI_STATUS
2018 CompareHiiValue (
2019 IN EFI_HII_VALUE *Value1,
2020 IN EFI_HII_VALUE *Value2,
2021 OUT INTN *Result,
2022 IN EFI_HII_HANDLE HiiHandle OPTIONAL
2023 )
2024 {
2025 INT64 Temp64;
2026 CHAR16 *Str1;
2027 CHAR16 *Str2;
2028 UINTN Len;
2029 UINT8 *Buf1;
2030 UINT16 Buf1Len;
2031 UINT8 *Buf2;
2032 UINT16 Buf2Len;
2033
2034 if (Value1->Type == EFI_IFR_TYPE_STRING && Value2->Type == EFI_IFR_TYPE_STRING) {
2035 if (Value1->Value.string == 0 || Value2->Value.string == 0) {
2036 //
2037 // StringId 0 is reserved
2038 //
2039 return EFI_INVALID_PARAMETER;
2040 }
2041
2042 if (Value1->Value.string == Value2->Value.string) {
2043 *Result = 0;
2044 return EFI_SUCCESS;
2045 }
2046
2047 Str1 = GetToken (Value1->Value.string, HiiHandle);
2048 if (Str1 == NULL) {
2049 //
2050 // String not found
2051 //
2052 return EFI_NOT_FOUND;
2053 }
2054
2055 Str2 = GetToken (Value2->Value.string, HiiHandle);
2056 if (Str2 == NULL) {
2057 FreePool (Str1);
2058 return EFI_NOT_FOUND;
2059 }
2060
2061 *Result = StrCmp (Str1, Str2);
2062
2063 FreePool (Str1);
2064 FreePool (Str2);
2065
2066 return EFI_SUCCESS;
2067 }
2068
2069 //
2070 // Take types(date, time, ref, buffer) as buffer
2071 //
2072 if (IsTypeInBuffer(Value1) && IsTypeInBuffer(Value2)) {
2073 Buf1 = GetBufferForValue(Value1);
2074 Buf1Len = GetLengthForValue(Value1);
2075 Buf2 = GetBufferForValue(Value2);
2076 Buf2Len = GetLengthForValue(Value2);
2077
2078 Len = Buf1Len > Buf2Len ? Buf2Len : Buf1Len;
2079 *Result = CompareMem (Buf1, Buf2, Len);
2080 if ((*Result == 0) && (Buf1Len != Buf2Len)) {
2081 //
2082 // In this case, means base on samll number buffer, the data is same
2083 // So which value has more data, which value is bigger.
2084 //
2085 *Result = Buf1Len > Buf2Len ? 1 : -1;
2086 }
2087 return EFI_SUCCESS;
2088 }
2089
2090 //
2091 // Take types(integer, boolean) as integer
2092 //
2093 if (IsTypeInUINT64(Value1) && IsTypeInUINT64(Value2)) {
2094 Temp64 = HiiValueToUINT64(Value1) - HiiValueToUINT64(Value2);
2095 if (Temp64 > 0) {
2096 *Result = 1;
2097 } else if (Temp64 < 0) {
2098 *Result = -1;
2099 } else {
2100 *Result = 0;
2101 }
2102
2103 return EFI_SUCCESS;
2104 }
2105
2106 return EFI_UNSUPPORTED;
2107 }
2108
2109 /**
2110 Check if current user has the privilege specified by the permissions GUID.
2111
2112 @param[in] Guid A GUID specifying setup access permissions.
2113
2114 @retval TRUE Current user has the privilege.
2115 @retval FALSE Current user does not have the privilege.
2116 **/
2117 BOOLEAN
2118 CheckUserPrivilege (
2119 IN EFI_GUID *Guid
2120 )
2121 {
2122 EFI_STATUS Status;
2123 EFI_USER_PROFILE_HANDLE UserProfileHandle;
2124 EFI_USER_INFO_HANDLE UserInfoHandle;
2125 EFI_USER_INFO *UserInfo;
2126 EFI_GUID *UserPermissionsGuid;
2127 UINTN UserInfoSize;
2128 UINTN AccessControlDataSize;
2129 EFI_USER_INFO_ACCESS_CONTROL *AccessControl;
2130 UINTN RemainSize;
2131
2132 if (mUserManager == NULL) {
2133 Status = gBS->LocateProtocol (
2134 &gEfiUserManagerProtocolGuid,
2135 NULL,
2136 (VOID **) &mUserManager
2137 );
2138 if (EFI_ERROR (Status)) {
2139 ///
2140 /// If the system does not support user management, then it is assumed that
2141 /// all users have admin privilege and evaluation of each EFI_IFR_SECURITY
2142 /// op-code is always TRUE.
2143 ///
2144 return TRUE;
2145 }
2146 }
2147
2148 Status = mUserManager->Current (mUserManager, &UserProfileHandle);
2149 ASSERT_EFI_ERROR (Status);
2150
2151 ///
2152 /// Enumerate all user information of the current user profile
2153 /// to look for any EFI_USER_INFO_ACCESS_SETUP record.
2154 ///
2155
2156 for (UserInfoHandle = NULL;;) {
2157 Status = mUserManager->GetNextInfo (mUserManager, UserProfileHandle, &UserInfoHandle);
2158 if (EFI_ERROR (Status)) {
2159 break;
2160 }
2161
2162 UserInfoSize = 0;
2163 Status = mUserManager->GetInfo (mUserManager, UserProfileHandle, UserInfoHandle, NULL, &UserInfoSize);
2164 if (Status != EFI_BUFFER_TOO_SMALL) {
2165 continue;
2166 }
2167
2168 UserInfo = (EFI_USER_INFO *) AllocatePool (UserInfoSize);
2169 if (UserInfo == NULL) {
2170 break;
2171 }
2172
2173 Status = mUserManager->GetInfo (mUserManager, UserProfileHandle, UserInfoHandle, UserInfo, &UserInfoSize);
2174 if (EFI_ERROR (Status) ||
2175 UserInfo->InfoType != EFI_USER_INFO_ACCESS_POLICY_RECORD ||
2176 UserInfo->InfoSize <= sizeof (EFI_USER_INFO)) {
2177 FreePool (UserInfo);
2178 continue;
2179 }
2180
2181 RemainSize = UserInfo->InfoSize - sizeof (EFI_USER_INFO);
2182 AccessControl = (EFI_USER_INFO_ACCESS_CONTROL *)(UserInfo + 1);
2183 while (RemainSize >= sizeof (EFI_USER_INFO_ACCESS_CONTROL)) {
2184 if (RemainSize < AccessControl->Size || AccessControl->Size < sizeof (EFI_USER_INFO_ACCESS_CONTROL)) {
2185 break;
2186 }
2187 if (AccessControl->Type == EFI_USER_INFO_ACCESS_SETUP) {
2188 ///
2189 /// Check if current user has the privilege specified by the permissions GUID.
2190 ///
2191
2192 UserPermissionsGuid = (EFI_GUID *)(AccessControl + 1);
2193 AccessControlDataSize = AccessControl->Size - sizeof (EFI_USER_INFO_ACCESS_CONTROL);
2194 while (AccessControlDataSize >= sizeof (EFI_GUID)) {
2195 if (CompareGuid (Guid, UserPermissionsGuid)) {
2196 FreePool (UserInfo);
2197 return TRUE;
2198 }
2199 UserPermissionsGuid++;
2200 AccessControlDataSize -= sizeof (EFI_GUID);
2201 }
2202 }
2203 RemainSize -= AccessControl->Size;
2204 AccessControl = (EFI_USER_INFO_ACCESS_CONTROL *)((UINT8 *)AccessControl + AccessControl->Size);
2205 }
2206
2207 FreePool (UserInfo);
2208 }
2209 return FALSE;
2210 }
2211
2212 /**
2213 Get question value from the predefined formset.
2214
2215 @param DevicePath The driver's device path which produece the formset data.
2216 @param InputHiiHandle The hii handle associate with the formset data.
2217 @param FormSetGuid The formset guid which include the question.
2218 @param QuestionId The question id which need to get value from.
2219 @param Value The return data about question's value.
2220
2221 @retval TRUE Get the question value success.
2222 @retval FALSE Get the question value failed.
2223 **/
2224 BOOLEAN
2225 GetQuestionValueFromForm (
2226 IN EFI_DEVICE_PATH_PROTOCOL *DevicePath,
2227 IN EFI_HII_HANDLE InputHiiHandle,
2228 IN EFI_GUID *FormSetGuid,
2229 IN EFI_QUESTION_ID QuestionId,
2230 OUT EFI_HII_VALUE *Value
2231 )
2232 {
2233 EFI_STATUS Status;
2234 EFI_HII_HANDLE HiiHandle;
2235 FORM_BROWSER_STATEMENT *Question;
2236 FORM_BROWSER_FORMSET *FormSet;
2237 FORM_BROWSER_FORM *Form;
2238 BOOLEAN GetTheVal;
2239 LIST_ENTRY *Link;
2240
2241 //
2242 // The input parameter DevicePath or InputHiiHandle must have one valid input.
2243 //
2244 ASSERT ((DevicePath != NULL && InputHiiHandle == NULL) ||
2245 (DevicePath == NULL && InputHiiHandle != NULL) );
2246
2247 GetTheVal = TRUE;
2248 HiiHandle = NULL;
2249 Question = NULL;
2250 Form = NULL;
2251
2252 //
2253 // Get HiiHandle.
2254 //
2255 if (DevicePath != NULL) {
2256 HiiHandle = DevicePathToHiiHandle (DevicePath, FormSetGuid);
2257 if (HiiHandle == NULL) {
2258 return FALSE;
2259 }
2260 } else {
2261 HiiHandle = InputHiiHandle;
2262 }
2263 ASSERT (HiiHandle != NULL);
2264
2265 //
2266 // Get the formset data include this question.
2267 //
2268 FormSet = AllocateZeroPool (sizeof (FORM_BROWSER_FORMSET));
2269 ASSERT (FormSet != NULL);
2270 Status = InitializeFormSet(HiiHandle, FormSetGuid, FormSet);
2271 if (EFI_ERROR (Status)) {
2272 GetTheVal = FALSE;
2273 goto Done;
2274 }
2275
2276 //
2277 // Base on the Question Id to get the question info.
2278 //
2279 Question = IdToQuestion(FormSet, NULL, QuestionId);
2280 if (Question == NULL) {
2281 GetTheVal = FALSE;
2282 goto Done;
2283 }
2284
2285 //
2286 // Search form in the formset scope
2287 //
2288 Link = GetFirstNode (&FormSet->FormListHead);
2289 while (!IsNull (&FormSet->FormListHead, Link)) {
2290 Form = FORM_BROWSER_FORM_FROM_LINK (Link);
2291
2292 Question = IdToQuestion2 (Form, QuestionId);
2293 if (Question != NULL) {
2294 break;
2295 }
2296
2297 Link = GetNextNode (&FormSet->FormListHead, Link);
2298 Form = NULL;
2299 }
2300 ASSERT (Form != NULL);
2301
2302 //
2303 // Get the question value.
2304 //
2305 Status = GetQuestionValue(FormSet, Form, Question, GetSetValueWithHiiDriver);
2306 if (EFI_ERROR (Status)) {
2307 GetTheVal = FALSE;
2308 goto Done;
2309 }
2310
2311 CopyMem (Value, &Question->HiiValue, sizeof (EFI_HII_VALUE));
2312
2313 Done:
2314 //
2315 // Clean the formset structure and restore the global parameter.
2316 //
2317 if (FormSet != NULL) {
2318 DestroyFormSet (FormSet);
2319 }
2320
2321 return GetTheVal;
2322 }
2323
2324 /**
2325 Evaluate the result of a HII expression.
2326
2327 If Expression is NULL, then ASSERT.
2328
2329 @param FormSet FormSet associated with this expression.
2330 @param Form Form associated with this expression.
2331 @param Expression Expression to be evaluated.
2332
2333 @retval EFI_SUCCESS The expression evaluated successfuly
2334 @retval EFI_NOT_FOUND The Question which referenced by a QuestionId
2335 could not be found.
2336 @retval EFI_OUT_OF_RESOURCES There is not enough system memory to grow the
2337 stack.
2338 @retval EFI_ACCESS_DENIED The pop operation underflowed the stack
2339 @retval EFI_INVALID_PARAMETER Syntax error with the Expression
2340
2341 **/
2342 EFI_STATUS
2343 EvaluateExpression (
2344 IN FORM_BROWSER_FORMSET *FormSet,
2345 IN FORM_BROWSER_FORM *Form,
2346 IN OUT FORM_EXPRESSION *Expression
2347 )
2348 {
2349 EFI_STATUS Status;
2350 LIST_ENTRY *Link;
2351 EXPRESSION_OPCODE *OpCode;
2352 FORM_BROWSER_STATEMENT *Question;
2353 FORM_BROWSER_STATEMENT *Question2;
2354 UINT16 Index;
2355 EFI_HII_VALUE Data1;
2356 EFI_HII_VALUE Data2;
2357 EFI_HII_VALUE Data3;
2358 FORM_EXPRESSION *RuleExpression;
2359 EFI_HII_VALUE *Value;
2360 INTN Result;
2361 CHAR16 *StrPtr;
2362 CHAR16 *NameValue;
2363 UINT32 TempValue;
2364 LIST_ENTRY *SubExpressionLink;
2365 FORM_EXPRESSION *SubExpression;
2366 UINTN StackOffset;
2367 UINTN TempLength;
2368 CHAR16 TempStr[5];
2369 UINT8 DigitUint8;
2370 UINT8 *TempBuffer;
2371 EFI_TIME EfiTime;
2372 EFI_HII_VALUE QuestionVal;
2373 EFI_DEVICE_PATH_PROTOCOL *DevicePath;
2374
2375 StrPtr = NULL;
2376
2377 //
2378 // Save current stack offset.
2379 //
2380 StackOffset = SaveExpressionEvaluationStackOffset ();
2381
2382 ASSERT (Expression != NULL);
2383 Expression->Result.Type = EFI_IFR_TYPE_OTHER;
2384
2385 Link = GetFirstNode (&Expression->OpCodeListHead);
2386 while (!IsNull (&Expression->OpCodeListHead, Link)) {
2387 OpCode = EXPRESSION_OPCODE_FROM_LINK (Link);
2388
2389 Link = GetNextNode (&Expression->OpCodeListHead, Link);
2390
2391 ZeroMem (&Data1, sizeof (EFI_HII_VALUE));
2392 ZeroMem (&Data2, sizeof (EFI_HII_VALUE));
2393 ZeroMem (&Data3, sizeof (EFI_HII_VALUE));
2394
2395 Value = &Data3;
2396 Value->Type = EFI_IFR_TYPE_BOOLEAN;
2397 Status = EFI_SUCCESS;
2398
2399 switch (OpCode->Operand) {
2400 //
2401 // Built-in functions
2402 //
2403 case EFI_IFR_EQ_ID_VAL_OP:
2404 Question = IdToQuestion (FormSet, Form, OpCode->QuestionId);
2405 if (Question == NULL) {
2406 Value->Type = EFI_IFR_TYPE_UNDEFINED;
2407 break;
2408 }
2409
2410 Status = CompareHiiValue (&Question->HiiValue, &OpCode->Value, &Result, NULL);
2411 if (Status == EFI_UNSUPPORTED) {
2412 Status = EFI_SUCCESS;
2413 Value->Type = EFI_IFR_TYPE_UNDEFINED;
2414 break;
2415 }
2416
2417 if (EFI_ERROR (Status)) {
2418 goto Done;
2419 }
2420 Value->Value.b = (BOOLEAN) ((Result == 0) ? TRUE : FALSE);
2421 break;
2422
2423 case EFI_IFR_EQ_ID_ID_OP:
2424 Question = IdToQuestion (FormSet, Form, OpCode->QuestionId);
2425 if (Question == NULL) {
2426 Value->Type = EFI_IFR_TYPE_UNDEFINED;
2427 break;
2428 }
2429
2430 Question2 = IdToQuestion (FormSet, Form, OpCode->QuestionId2);
2431 if (Question2 == NULL) {
2432 Value->Type = EFI_IFR_TYPE_UNDEFINED;
2433 break;
2434 }
2435
2436 Status = CompareHiiValue (&Question->HiiValue, &Question2->HiiValue, &Result, FormSet->HiiHandle);
2437 if (Status == EFI_UNSUPPORTED) {
2438 Value->Type = EFI_IFR_TYPE_UNDEFINED;
2439 Status = EFI_SUCCESS;
2440 break;
2441 }
2442 if (EFI_ERROR (Status)) {
2443 goto Done;
2444 }
2445 Value->Value.b = (BOOLEAN) ((Result == 0) ? TRUE : FALSE);
2446 break;
2447
2448 case EFI_IFR_EQ_ID_VAL_LIST_OP:
2449 Question = IdToQuestion (FormSet, Form, OpCode->QuestionId);
2450 if (Question == NULL) {
2451 Value->Type = EFI_IFR_TYPE_UNDEFINED;
2452 break;
2453 }
2454
2455 Value->Value.b = FALSE;
2456 for (Index =0; Index < OpCode->ListLength; Index++) {
2457 if (Question->HiiValue.Value.u16 == OpCode->ValueList[Index]) {
2458 Value->Value.b = TRUE;
2459 break;
2460 }
2461 }
2462 break;
2463
2464 case EFI_IFR_DUP_OP:
2465 Status = PopExpression (Value);
2466 if (EFI_ERROR (Status)) {
2467 goto Done;
2468 }
2469
2470 Status = PushExpression (Value);
2471 break;
2472
2473 case EFI_IFR_QUESTION_REF1_OP:
2474 case EFI_IFR_THIS_OP:
2475 Question = IdToQuestion (FormSet, Form, OpCode->QuestionId);
2476 if (Question == NULL) {
2477 Status = EFI_NOT_FOUND;
2478 goto Done;
2479 }
2480
2481 Value = &Question->HiiValue;
2482 break;
2483
2484 case EFI_IFR_SECURITY_OP:
2485 Value->Value.b = CheckUserPrivilege (&OpCode->Guid);
2486 break;
2487
2488 case EFI_IFR_GET_OP:
2489 //
2490 // Get Value from VarStore buffer, EFI VarStore, Name/Value VarStore.
2491 //
2492 Value->Type = EFI_IFR_TYPE_UNDEFINED;
2493 Value->Value.u8 = 0;
2494 if (OpCode->VarStorage != NULL) {
2495 switch (OpCode->VarStorage->Type) {
2496 case EFI_HII_VARSTORE_BUFFER:
2497 case EFI_HII_VARSTORE_EFI_VARIABLE_BUFFER:
2498 //
2499 // Get value from Edit Buffer
2500 //
2501 Value->Type = OpCode->ValueType;
2502 CopyMem (&Value->Value, OpCode->VarStorage->EditBuffer + OpCode->VarStoreInfo.VarOffset, OpCode->ValueWidth);
2503 break;
2504 case EFI_HII_VARSTORE_NAME_VALUE:
2505 if (OpCode->ValueType != EFI_IFR_TYPE_STRING) {
2506 //
2507 // Get value from string except for STRING value.
2508 //
2509 Status = GetValueByName (OpCode->VarStorage, OpCode->ValueName, &StrPtr, GetSetValueWithEditBuffer);
2510 if (!EFI_ERROR (Status)) {
2511 ASSERT (StrPtr != NULL);
2512 TempLength = StrLen (StrPtr);
2513 if (OpCode->ValueWidth >= ((TempLength + 1) / 2)) {
2514 Value->Type = OpCode->ValueType;
2515 TempBuffer = (UINT8 *) &Value->Value;
2516 ZeroMem (TempStr, sizeof (TempStr));
2517 for (Index = 0; Index < TempLength; Index ++) {
2518 TempStr[0] = StrPtr[TempLength - Index - 1];
2519 DigitUint8 = (UINT8) StrHexToUint64 (TempStr);
2520 if ((Index & 1) == 0) {
2521 TempBuffer [Index/2] = DigitUint8;
2522 } else {
2523 TempBuffer [Index/2] = (UINT8) ((DigitUint8 << 4) + TempBuffer [Index/2]);
2524 }
2525 }
2526 }
2527 }
2528 }
2529 break;
2530 case EFI_HII_VARSTORE_EFI_VARIABLE:
2531 //
2532 // Get value from variable.
2533 //
2534 TempLength = OpCode->ValueWidth;
2535 Value->Type = OpCode->ValueType;
2536 Status = gRT->GetVariable (
2537 OpCode->ValueName,
2538 &OpCode->VarStorage->Guid,
2539 NULL,
2540 &TempLength,
2541 &Value->Value
2542 );
2543 if (EFI_ERROR (Status)) {
2544 Value->Type = EFI_IFR_TYPE_UNDEFINED;
2545 Value->Value.u8 = 0;
2546 }
2547 break;
2548 default:
2549 //
2550 // Not recognize storage.
2551 //
2552 Status = EFI_UNSUPPORTED;
2553 goto Done;
2554 }
2555 } else {
2556 //
2557 // For Time/Date Data
2558 //
2559 if (OpCode->ValueType != EFI_IFR_TYPE_DATE && OpCode->ValueType != EFI_IFR_TYPE_TIME) {
2560 //
2561 // Only support Data/Time data when storage doesn't exist.
2562 //
2563 Status = EFI_UNSUPPORTED;
2564 goto Done;
2565 }
2566 Status = gRT->GetTime (&EfiTime, NULL);
2567 if (!EFI_ERROR (Status)) {
2568 if (OpCode->ValueType == EFI_IFR_TYPE_DATE) {
2569 switch (OpCode->VarStoreInfo.VarOffset) {
2570 case 0x00:
2571 Value->Type = EFI_IFR_TYPE_NUM_SIZE_16;
2572 Value->Value.u16 = EfiTime.Year;
2573 break;
2574 case 0x02:
2575 Value->Type = EFI_IFR_TYPE_NUM_SIZE_8;
2576 Value->Value.u8 = EfiTime.Month;
2577 break;
2578 case 0x03:
2579 Value->Type = EFI_IFR_TYPE_NUM_SIZE_8;
2580 Value->Value.u8 = EfiTime.Day;
2581 break;
2582 default:
2583 //
2584 // Invalid Date field.
2585 //
2586 Status = EFI_INVALID_PARAMETER;
2587 goto Done;
2588 }
2589 } else {
2590 switch (OpCode->VarStoreInfo.VarOffset) {
2591 case 0x00:
2592 Value->Type = EFI_IFR_TYPE_NUM_SIZE_8;
2593 Value->Value.u8 = EfiTime.Hour;
2594 break;
2595 case 0x01:
2596 Value->Type = EFI_IFR_TYPE_NUM_SIZE_8;
2597 Value->Value.u8 = EfiTime.Minute;
2598 break;
2599 case 0x02:
2600 Value->Type = EFI_IFR_TYPE_NUM_SIZE_8;
2601 Value->Value.u8 = EfiTime.Second;
2602 break;
2603 default:
2604 //
2605 // Invalid Time field.
2606 //
2607 Status = EFI_INVALID_PARAMETER;
2608 goto Done;
2609 }
2610 }
2611 }
2612 }
2613
2614 break;
2615
2616 case EFI_IFR_QUESTION_REF3_OP:
2617 //
2618 // EFI_IFR_QUESTION_REF3
2619 // Pop an expression from the expression stack
2620 //
2621 Status = PopExpression (Value);
2622 if (EFI_ERROR (Status)) {
2623 goto Done;
2624 }
2625
2626 //
2627 // Validate the expression value
2628 //
2629 if ((Value->Type > EFI_IFR_TYPE_NUM_SIZE_64) || (Value->Value.u64 > 0xffff)) {
2630 Value->Type = EFI_IFR_TYPE_UNDEFINED;
2631 break;
2632 }
2633
2634 if (OpCode->DevicePath != 0) {
2635 Value->Type = EFI_IFR_TYPE_UNDEFINED;
2636
2637 StrPtr = GetToken (OpCode->DevicePath, FormSet->HiiHandle);
2638 if (StrPtr != NULL && mPathFromText != NULL) {
2639 DevicePath = mPathFromText->ConvertTextToDevicePath(StrPtr);
2640 if (DevicePath != NULL && GetQuestionValueFromForm(DevicePath, NULL, &OpCode->Guid, Value->Value.u16, &QuestionVal)) {
2641 Value = &QuestionVal;
2642 }
2643 if (DevicePath != NULL) {
2644 FreePool (DevicePath);
2645 }
2646 }
2647
2648 if (StrPtr != NULL) {
2649 FreePool (StrPtr);
2650 }
2651 } else if (CompareGuid (&OpCode->Guid, &gZeroGuid) != 0) {
2652 if (!GetQuestionValueFromForm(NULL, FormSet->HiiHandle, &OpCode->Guid, Value->Value.u16, &QuestionVal)){
2653 Value->Type = EFI_IFR_TYPE_UNDEFINED;
2654 break;
2655 }
2656 Value = &QuestionVal;
2657 } else {
2658 Question = IdToQuestion (FormSet, Form, Value->Value.u16);
2659 if (Question == NULL) {
2660 Value->Type = EFI_IFR_TYPE_UNDEFINED;
2661 break;
2662 }
2663
2664 //
2665 // push the questions' value on to the expression stack
2666 //
2667 Value = &Question->HiiValue;
2668 }
2669 break;
2670
2671 case EFI_IFR_RULE_REF_OP:
2672 //
2673 // Find expression for this rule
2674 //
2675 RuleExpression = RuleIdToExpression (Form, OpCode->RuleId);
2676 if (RuleExpression == NULL) {
2677 Value->Type = EFI_IFR_TYPE_UNDEFINED;
2678 break;
2679 }
2680
2681 //
2682 // Evaluate this rule expression
2683 //
2684 Status = EvaluateExpression (FormSet, Form, RuleExpression);
2685 if (EFI_ERROR (Status) || RuleExpression->Result.Type == EFI_IFR_TYPE_UNDEFINED) {
2686 Value->Type = EFI_IFR_TYPE_UNDEFINED;
2687 break;
2688 }
2689
2690 Value = &RuleExpression->Result;
2691 break;
2692
2693 case EFI_IFR_STRING_REF1_OP:
2694 Value->Type = EFI_IFR_TYPE_STRING;
2695 Value->Value.string = OpCode->Value.Value.string;
2696 break;
2697
2698 //
2699 // Constant
2700 //
2701 case EFI_IFR_TRUE_OP:
2702 case EFI_IFR_FALSE_OP:
2703 case EFI_IFR_ONE_OP:
2704 case EFI_IFR_ONES_OP:
2705 case EFI_IFR_UINT8_OP:
2706 case EFI_IFR_UINT16_OP:
2707 case EFI_IFR_UINT32_OP:
2708 case EFI_IFR_UINT64_OP:
2709 case EFI_IFR_UNDEFINED_OP:
2710 case EFI_IFR_VERSION_OP:
2711 case EFI_IFR_ZERO_OP:
2712 Value = &OpCode->Value;
2713 break;
2714
2715 //
2716 // unary-op
2717 //
2718 case EFI_IFR_LENGTH_OP:
2719 Status = PopExpression (Value);
2720 if (EFI_ERROR (Status)) {
2721 goto Done;
2722 }
2723 if (Value->Type != EFI_IFR_TYPE_STRING && !IsTypeInBuffer (Value)) {
2724 Value->Type = EFI_IFR_TYPE_UNDEFINED;
2725 break;
2726 }
2727
2728 if (Value->Type == EFI_IFR_TYPE_STRING) {
2729 StrPtr = GetToken (Value->Value.string, FormSet->HiiHandle);
2730 if (StrPtr == NULL) {
2731 Status = EFI_INVALID_PARAMETER;
2732 goto Done;
2733 }
2734
2735 Value->Type = EFI_IFR_TYPE_NUM_SIZE_64;
2736 Value->Value.u64 = StrLen (StrPtr);
2737 FreePool (StrPtr);
2738 } else {
2739 Value->Type = EFI_IFR_TYPE_NUM_SIZE_64;
2740 Value->Value.u64 = GetLengthForValue(Value);
2741 FreePool (Value->Buffer);
2742 }
2743 break;
2744
2745 case EFI_IFR_NOT_OP:
2746 Status = PopExpression (Value);
2747 if (EFI_ERROR (Status)) {
2748 goto Done;
2749 }
2750 if (Value->Type != EFI_IFR_TYPE_BOOLEAN) {
2751 Value->Type = EFI_IFR_TYPE_UNDEFINED;
2752 break;
2753 }
2754 Value->Value.b = (BOOLEAN) (!Value->Value.b);
2755 break;
2756
2757 case EFI_IFR_QUESTION_REF2_OP:
2758 //
2759 // Pop an expression from the expression stack
2760 //
2761 Status = PopExpression (Value);
2762 if (EFI_ERROR (Status)) {
2763 goto Done;
2764 }
2765
2766 //
2767 // Validate the expression value
2768 //
2769 if ((Value->Type > EFI_IFR_TYPE_NUM_SIZE_64) || (Value->Value.u64 > 0xffff)) {
2770 Value->Type = EFI_IFR_TYPE_UNDEFINED;
2771 break;
2772 }
2773
2774 Question = IdToQuestion (FormSet, Form, Value->Value.u16);
2775 if (Question == NULL) {
2776 Value->Type = EFI_IFR_TYPE_UNDEFINED;
2777 break;
2778 }
2779
2780 Value = &Question->HiiValue;
2781 break;
2782
2783 case EFI_IFR_STRING_REF2_OP:
2784 //
2785 // Pop an expression from the expression stack
2786 //
2787 Status = PopExpression (Value);
2788 if (EFI_ERROR (Status)) {
2789 goto Done;
2790 }
2791
2792 //
2793 // Validate the expression value
2794 //
2795 if ((Value->Type > EFI_IFR_TYPE_NUM_SIZE_64) || (Value->Value.u64 > 0xffff)) {
2796 Value->Type = EFI_IFR_TYPE_UNDEFINED;
2797 break;
2798 }
2799
2800 Value->Type = EFI_IFR_TYPE_STRING;
2801 StrPtr = GetToken (Value->Value.u16, FormSet->HiiHandle);
2802 if (StrPtr == NULL) {
2803 //
2804 // If String not exit, push an empty string
2805 //
2806 Value->Value.string = NewString (gEmptyString, FormSet->HiiHandle);
2807 } else {
2808 Index = (UINT16) Value->Value.u64;
2809 Value->Value.string = Index;
2810 FreePool (StrPtr);
2811 }
2812 break;
2813
2814 case EFI_IFR_TO_BOOLEAN_OP:
2815 //
2816 // Pop an expression from the expression stack
2817 //
2818 Status = PopExpression (Value);
2819 if (EFI_ERROR (Status)) {
2820 goto Done;
2821 }
2822
2823 //
2824 // Convert an expression to a Boolean
2825 //
2826 if (Value->Type <= EFI_IFR_TYPE_DATE) {
2827 //
2828 // When converting from an unsigned integer, zero will be converted to
2829 // FALSE and any other value will be converted to TRUE.
2830 //
2831 Value->Value.b = (BOOLEAN) (HiiValueToUINT64(Value) != 0);
2832
2833 Value->Type = EFI_IFR_TYPE_BOOLEAN;
2834 } else if (Value->Type == EFI_IFR_TYPE_STRING) {
2835 //
2836 // When converting from a string, if case-insensitive compare
2837 // with "true" is True, then push True. If a case-insensitive compare
2838 // with "false" is True, then push False. Otherwise, push Undefined.
2839 //
2840 StrPtr = GetToken (Value->Value.string, FormSet->HiiHandle);
2841 if (StrPtr == NULL) {
2842 Status = EFI_INVALID_PARAMETER;
2843 goto Done;
2844 }
2845
2846 IfrStrToUpper (StrPtr);
2847 if (StrCmp (StrPtr, L"TRUE") == 0){
2848 Value->Value.b = TRUE;
2849 Value->Type = EFI_IFR_TYPE_BOOLEAN;
2850 } else if (StrCmp (StrPtr, L"FALSE") == 0) {
2851 Value->Value.b = FALSE;
2852 Value->Type = EFI_IFR_TYPE_BOOLEAN;
2853 } else {
2854 Value->Type = EFI_IFR_TYPE_UNDEFINED;
2855 }
2856 FreePool (StrPtr);
2857 } else if (Value->Type == EFI_IFR_TYPE_BUFFER) {
2858 //
2859 // When converting from a buffer, if the buffer is all zeroes,
2860 // then push False. Otherwise push True.
2861 //
2862 for (Index =0; Index < Value->BufferLen; Index ++) {
2863 if (Value->Buffer[Index] != 0) {
2864 break;
2865 }
2866 }
2867
2868 if (Index >= Value->BufferLen) {
2869 Value->Value.b = FALSE;
2870 } else {
2871 Value->Value.b = TRUE;
2872 }
2873 Value->Type = EFI_IFR_TYPE_BOOLEAN;
2874 FreePool (Value->Buffer);
2875 }
2876 break;
2877
2878 case EFI_IFR_TO_STRING_OP:
2879 Status = IfrToString (FormSet, OpCode->Format, Value);
2880 break;
2881
2882 case EFI_IFR_TO_UINT_OP:
2883 Status = IfrToUint (FormSet, Value);
2884 break;
2885
2886 case EFI_IFR_TO_LOWER_OP:
2887 case EFI_IFR_TO_UPPER_OP:
2888 Status = InitializeUnicodeCollationProtocol ();
2889 if (EFI_ERROR (Status)) {
2890 goto Done;
2891 }
2892
2893 Status = PopExpression (Value);
2894 if (EFI_ERROR (Status)) {
2895 goto Done;
2896 }
2897
2898 if (Value->Type != EFI_IFR_TYPE_STRING) {
2899 Value->Type = EFI_IFR_TYPE_UNDEFINED;
2900 break;
2901 }
2902
2903 StrPtr = GetToken (Value->Value.string, FormSet->HiiHandle);
2904 if (StrPtr == NULL) {
2905 Status = EFI_NOT_FOUND;
2906 goto Done;
2907 }
2908
2909 if (OpCode->Operand == EFI_IFR_TO_LOWER_OP) {
2910 mUnicodeCollation->StrLwr (mUnicodeCollation, StrPtr);
2911 } else {
2912 mUnicodeCollation->StrUpr (mUnicodeCollation, StrPtr);
2913 }
2914 Value->Value.string = NewString (StrPtr, FormSet->HiiHandle);
2915 FreePool (StrPtr);
2916 break;
2917
2918 case EFI_IFR_BITWISE_NOT_OP:
2919 //
2920 // Pop an expression from the expression stack
2921 //
2922 Status = PopExpression (Value);
2923 if (EFI_ERROR (Status)) {
2924 goto Done;
2925 }
2926 if (Value->Type > EFI_IFR_TYPE_DATE) {
2927 Value->Type = EFI_IFR_TYPE_UNDEFINED;
2928 break;
2929 }
2930
2931 Value->Type = EFI_IFR_TYPE_NUM_SIZE_64;
2932 Value->Value.u64 = ~ HiiValueToUINT64(Value);
2933 break;
2934
2935 case EFI_IFR_SET_OP:
2936 //
2937 // Pop an expression from the expression stack
2938 //
2939 Status = PopExpression (Value);
2940 if (EFI_ERROR (Status)) {
2941 goto Done;
2942 }
2943 Data1.Type = EFI_IFR_TYPE_BOOLEAN;
2944 Data1.Value.b = FALSE;
2945 //
2946 // Set value to var storage buffer
2947 //
2948 if (OpCode->VarStorage != NULL) {
2949 switch (OpCode->VarStorage->Type) {
2950 case EFI_HII_VARSTORE_BUFFER:
2951 case EFI_HII_VARSTORE_EFI_VARIABLE_BUFFER:
2952 CopyMem (OpCode->VarStorage->EditBuffer + OpCode->VarStoreInfo.VarOffset, &Value->Value, OpCode->ValueWidth);
2953 Data1.Value.b = TRUE;
2954 break;
2955 case EFI_HII_VARSTORE_NAME_VALUE:
2956 if (OpCode->ValueType != EFI_IFR_TYPE_STRING) {
2957 NameValue = AllocateZeroPool ((OpCode->ValueWidth * 2 + 1) * sizeof (CHAR16));
2958 ASSERT (Value != NULL);
2959 //
2960 // Convert Buffer to Hex String
2961 //
2962 TempBuffer = (UINT8 *) &Value->Value + OpCode->ValueWidth - 1;
2963 StrPtr = NameValue;
2964 for (Index = 0; Index < OpCode->ValueWidth; Index ++, TempBuffer --) {
2965 StrPtr += UnicodeValueToString (StrPtr, PREFIX_ZERO | RADIX_HEX, *TempBuffer, 2);
2966 }
2967 Status = SetValueByName (OpCode->VarStorage, OpCode->ValueName, NameValue, GetSetValueWithEditBuffer, NULL);
2968 FreePool (NameValue);
2969 if (!EFI_ERROR (Status)) {
2970 Data1.Value.b = TRUE;
2971 }
2972 }
2973 break;
2974 case EFI_HII_VARSTORE_EFI_VARIABLE:
2975 Status = gRT->SetVariable (
2976 OpCode->ValueName,
2977 &OpCode->VarStorage->Guid,
2978 OpCode->VarStorage->Attributes,
2979 OpCode->ValueWidth,
2980 &Value->Value
2981 );
2982 if (!EFI_ERROR (Status)) {
2983 Data1.Value.b = TRUE;
2984 }
2985 break;
2986 default:
2987 //
2988 // Not recognize storage.
2989 //
2990 Status = EFI_UNSUPPORTED;
2991 goto Done;
2992 break;
2993 }
2994 } else {
2995 //
2996 // For Time/Date Data
2997 //
2998 if (OpCode->ValueType != EFI_IFR_TYPE_DATE && OpCode->ValueType != EFI_IFR_TYPE_TIME) {
2999 //
3000 // Only support Data/Time data when storage doesn't exist.
3001 //
3002 Status = EFI_UNSUPPORTED;
3003 goto Done;
3004 }
3005 Status = gRT->GetTime (&EfiTime, NULL);
3006 if (!EFI_ERROR (Status)) {
3007 if (OpCode->ValueType == EFI_IFR_TYPE_DATE) {
3008 switch (OpCode->VarStoreInfo.VarOffset) {
3009 case 0x00:
3010 EfiTime.Year = Value->Value.u16;
3011 break;
3012 case 0x02:
3013 EfiTime.Month = Value->Value.u8;
3014 break;
3015 case 0x03:
3016 EfiTime.Day = Value->Value.u8;
3017 break;
3018 default:
3019 //
3020 // Invalid Date field.
3021 //
3022 Status = EFI_INVALID_PARAMETER;
3023 goto Done;
3024 }
3025 } else {
3026 switch (OpCode->VarStoreInfo.VarOffset) {
3027 case 0x00:
3028 EfiTime.Hour = Value->Value.u8;
3029 break;
3030 case 0x01:
3031 EfiTime.Minute = Value->Value.u8;
3032 break;
3033 case 0x02:
3034 EfiTime.Second = Value->Value.u8;
3035 break;
3036 default:
3037 //
3038 // Invalid Time field.
3039 //
3040 Status = EFI_INVALID_PARAMETER;
3041 goto Done;
3042 }
3043 }
3044 Status = gRT->SetTime (&EfiTime);
3045 if (!EFI_ERROR (Status)) {
3046 Data1.Value.b = TRUE;
3047 }
3048 }
3049 }
3050 Value = &Data1;
3051 break;
3052
3053 //
3054 // binary-op
3055 //
3056 case EFI_IFR_ADD_OP:
3057 case EFI_IFR_SUBTRACT_OP:
3058 case EFI_IFR_MULTIPLY_OP:
3059 case EFI_IFR_DIVIDE_OP:
3060 case EFI_IFR_MODULO_OP:
3061 case EFI_IFR_BITWISE_AND_OP:
3062 case EFI_IFR_BITWISE_OR_OP:
3063 case EFI_IFR_SHIFT_LEFT_OP:
3064 case EFI_IFR_SHIFT_RIGHT_OP:
3065 //
3066 // Pop an expression from the expression stack
3067 //
3068 Status = PopExpression (&Data2);
3069 if (EFI_ERROR (Status)) {
3070 goto Done;
3071 }
3072
3073 //
3074 // Pop another expression from the expression stack
3075 //
3076 Status = PopExpression (&Data1);
3077 if (EFI_ERROR (Status)) {
3078 goto Done;
3079 }
3080
3081 if (Data2.Type > EFI_IFR_TYPE_DATE) {
3082 Value->Type = EFI_IFR_TYPE_UNDEFINED;
3083 break;
3084 }
3085
3086
3087 if (Data1.Type > EFI_IFR_TYPE_DATE) {
3088 Value->Type = EFI_IFR_TYPE_UNDEFINED;
3089 break;
3090 }
3091
3092 Value->Type = EFI_IFR_TYPE_NUM_SIZE_64;
3093
3094 switch (OpCode->Operand) {
3095 case EFI_IFR_ADD_OP:
3096 Value->Value.u64 = HiiValueToUINT64(&Data1) + HiiValueToUINT64(&Data2);
3097 break;
3098
3099 case EFI_IFR_SUBTRACT_OP:
3100 Value->Value.u64 = HiiValueToUINT64(&Data1) - HiiValueToUINT64(&Data2);
3101 break;
3102
3103 case EFI_IFR_MULTIPLY_OP:
3104 Value->Value.u64 = MultU64x32 (HiiValueToUINT64(&Data1), (UINT32) HiiValueToUINT64(&Data2));
3105 break;
3106
3107 case EFI_IFR_DIVIDE_OP:
3108 Value->Value.u64 = DivU64x32 (HiiValueToUINT64(&Data1), (UINT32) HiiValueToUINT64(&Data2));
3109 break;
3110
3111 case EFI_IFR_MODULO_OP:
3112 DivU64x32Remainder (HiiValueToUINT64(&Data1), (UINT32) HiiValueToUINT64(&Data2), &TempValue);
3113 Value->Value.u64 = TempValue;
3114 break;
3115
3116 case EFI_IFR_BITWISE_AND_OP:
3117 Value->Value.u64 = HiiValueToUINT64(&Data1) & HiiValueToUINT64(&Data2);
3118 break;
3119
3120 case EFI_IFR_BITWISE_OR_OP:
3121 Value->Value.u64 = HiiValueToUINT64(&Data1) | HiiValueToUINT64(&Data2);
3122 break;
3123
3124 case EFI_IFR_SHIFT_LEFT_OP:
3125 Value->Value.u64 = LShiftU64 (HiiValueToUINT64(&Data1), (UINTN) HiiValueToUINT64(&Data2));
3126 break;
3127
3128 case EFI_IFR_SHIFT_RIGHT_OP:
3129 Value->Value.u64 = RShiftU64 (HiiValueToUINT64(&Data1), (UINTN) HiiValueToUINT64(&Data2));
3130 break;
3131
3132 default:
3133 break;
3134 }
3135 break;
3136
3137 case EFI_IFR_AND_OP:
3138 case EFI_IFR_OR_OP:
3139 //
3140 // Two Boolean operator
3141 //
3142 Status = PopExpression (&Data2);
3143 if (EFI_ERROR (Status)) {
3144 goto Done;
3145 }
3146
3147 //
3148 // Pop another expression from the expression stack
3149 //
3150 Status = PopExpression (&Data1);
3151 if (EFI_ERROR (Status)) {
3152 goto Done;
3153 }
3154
3155 if (Data2.Type != EFI_IFR_TYPE_BOOLEAN) {
3156 Value->Type = EFI_IFR_TYPE_UNDEFINED;
3157 break;
3158 }
3159
3160 if (Data1.Type != EFI_IFR_TYPE_BOOLEAN) {
3161 Value->Type = EFI_IFR_TYPE_UNDEFINED;
3162 break;
3163 }
3164
3165 if (OpCode->Operand == EFI_IFR_AND_OP) {
3166 Value->Value.b = (BOOLEAN) (Data1.Value.b && Data2.Value.b);
3167 } else {
3168 Value->Value.b = (BOOLEAN) (Data1.Value.b || Data2.Value.b);
3169 }
3170 break;
3171
3172 case EFI_IFR_EQUAL_OP:
3173 case EFI_IFR_NOT_EQUAL_OP:
3174 case EFI_IFR_GREATER_EQUAL_OP:
3175 case EFI_IFR_GREATER_THAN_OP:
3176 case EFI_IFR_LESS_EQUAL_OP:
3177 case EFI_IFR_LESS_THAN_OP:
3178 //
3179 // Compare two integer, string, boolean or date/time
3180 //
3181 Status = PopExpression (&Data2);
3182 if (EFI_ERROR (Status)) {
3183 goto Done;
3184 }
3185
3186 //
3187 // Pop another expression from the expression stack
3188 //
3189 Status = PopExpression (&Data1);
3190 if (EFI_ERROR (Status)) {
3191 goto Done;
3192 }
3193
3194 if (Data2.Type > EFI_IFR_TYPE_BOOLEAN &&
3195 Data2.Type != EFI_IFR_TYPE_STRING &&
3196 !IsTypeInBuffer(&Data2)) {
3197 Value->Type = EFI_IFR_TYPE_UNDEFINED;
3198 break;
3199 }
3200
3201 if (Data1.Type > EFI_IFR_TYPE_BOOLEAN &&
3202 Data1.Type != EFI_IFR_TYPE_STRING &&
3203 !IsTypeInBuffer(&Data1)) {
3204 Value->Type = EFI_IFR_TYPE_UNDEFINED;
3205 break;
3206 }
3207
3208 Status = CompareHiiValue (&Data1, &Data2, &Result, FormSet->HiiHandle);
3209 if (Data1.Type == EFI_IFR_TYPE_BUFFER) {
3210 FreePool (Data1.Buffer);
3211 }
3212 if (Data2.Type == EFI_IFR_TYPE_BUFFER) {
3213 FreePool (Data2.Buffer);
3214 }
3215
3216 if (Status == EFI_UNSUPPORTED) {
3217 Value->Type = EFI_IFR_TYPE_UNDEFINED;
3218 Status = EFI_SUCCESS;
3219 break;
3220 }
3221
3222 if (EFI_ERROR (Status)) {
3223 goto Done;
3224 }
3225
3226 switch (OpCode->Operand) {
3227 case EFI_IFR_EQUAL_OP:
3228 Value->Value.b = (BOOLEAN) ((Result == 0) ? TRUE : FALSE);
3229 break;
3230
3231 case EFI_IFR_NOT_EQUAL_OP:
3232 Value->Value.b = (BOOLEAN) ((Result != 0) ? TRUE : FALSE);
3233 break;
3234
3235 case EFI_IFR_GREATER_EQUAL_OP:
3236 Value->Value.b = (BOOLEAN) ((Result >= 0) ? TRUE : FALSE);
3237 break;
3238
3239 case EFI_IFR_GREATER_THAN_OP:
3240 Value->Value.b = (BOOLEAN) ((Result > 0) ? TRUE : FALSE);
3241 break;
3242
3243 case EFI_IFR_LESS_EQUAL_OP:
3244 Value->Value.b = (BOOLEAN) ((Result <= 0) ? TRUE : FALSE);
3245 break;
3246
3247 case EFI_IFR_LESS_THAN_OP:
3248 Value->Value.b = (BOOLEAN) ((Result < 0) ? TRUE : FALSE);
3249 break;
3250
3251 default:
3252 break;
3253 }
3254 break;
3255
3256 case EFI_IFR_MATCH_OP:
3257 Status = InitializeUnicodeCollationProtocol ();
3258 if (EFI_ERROR (Status)) {
3259 goto Done;
3260 }
3261
3262 Status = IfrMatch (FormSet, Value);
3263 break;
3264
3265 case EFI_IFR_CATENATE_OP:
3266 Status = IfrCatenate (FormSet, Value);
3267 break;
3268
3269 //
3270 // ternary-op
3271 //
3272 case EFI_IFR_CONDITIONAL_OP:
3273 //
3274 // Pop third expression from the expression stack
3275 //
3276 Status = PopExpression (&Data3);
3277 if (EFI_ERROR (Status)) {
3278 goto Done;
3279 }
3280
3281 //
3282 // Pop second expression from the expression stack
3283 //
3284 Status = PopExpression (&Data2);
3285 if (EFI_ERROR (Status)) {
3286 goto Done;
3287 }
3288
3289 //
3290 // Pop first expression from the expression stack
3291 //
3292 Status = PopExpression (&Data1);
3293 if (EFI_ERROR (Status)) {
3294 goto Done;
3295 }
3296 if (Data1.Type != EFI_IFR_TYPE_BOOLEAN) {
3297 Value->Type = EFI_IFR_TYPE_UNDEFINED;
3298 break;
3299 }
3300
3301 if (Data1.Value.b) {
3302 Value = &Data3;
3303 } else {
3304 Value = &Data2;
3305 }
3306 break;
3307
3308 case EFI_IFR_FIND_OP:
3309 Status = IfrFind (FormSet, OpCode->Format, Value);
3310 break;
3311
3312 case EFI_IFR_MID_OP:
3313 Status = IfrMid (FormSet, Value);
3314 break;
3315
3316 case EFI_IFR_TOKEN_OP:
3317 Status = IfrToken (FormSet, Value);
3318 break;
3319
3320 case EFI_IFR_SPAN_OP:
3321 Status = IfrSpan (FormSet, OpCode->Flags, Value);
3322 break;
3323
3324 case EFI_IFR_MAP_OP:
3325 //
3326 // Pop the check value
3327 //
3328 Status = PopExpression (&Data1);
3329 if (EFI_ERROR (Status)) {
3330 goto Done;
3331 }
3332 //
3333 // Check MapExpression list is valid.
3334 //
3335 if (OpCode->MapExpressionList.ForwardLink == NULL) {
3336 Status = EFI_INVALID_PARAMETER;
3337 goto Done;
3338 }
3339 //
3340 // Go through map expression list.
3341 //
3342 SubExpressionLink = GetFirstNode(&OpCode->MapExpressionList);
3343 while (!IsNull (&OpCode->MapExpressionList, SubExpressionLink)) {
3344 SubExpression = FORM_EXPRESSION_FROM_LINK (SubExpressionLink);
3345 //
3346 // Evaluate the first expression in this pair.
3347 //
3348 Status = EvaluateExpression (FormSet, Form, SubExpression);
3349 if (EFI_ERROR (Status)) {
3350 goto Done;
3351 }
3352 //
3353 // Compare the expression value with current value
3354 //
3355 if ((CompareHiiValue (&Data1, &SubExpression->Result, &Result, NULL) == EFI_SUCCESS) && (Result == 0)) {
3356 //
3357 // Try get the map value.
3358 //
3359 SubExpressionLink = GetNextNode (&OpCode->MapExpressionList, SubExpressionLink);
3360 if (IsNull (&OpCode->MapExpressionList, SubExpressionLink)) {
3361 Status = EFI_INVALID_PARAMETER;
3362 goto Done;
3363 }
3364 SubExpression = FORM_EXPRESSION_FROM_LINK (SubExpressionLink);
3365 Status = EvaluateExpression (FormSet, Form, SubExpression);
3366 if (EFI_ERROR (Status)) {
3367 goto Done;
3368 }
3369 Value = &SubExpression->Result;
3370 break;
3371 }
3372 //
3373 // Skip the second expression on this pair.
3374 //
3375 SubExpressionLink = GetNextNode (&OpCode->MapExpressionList, SubExpressionLink);
3376 if (IsNull (&OpCode->MapExpressionList, SubExpressionLink)) {
3377 Status = EFI_INVALID_PARAMETER;
3378 goto Done;
3379 }
3380 //
3381 // Goto the first expression on next pair.
3382 //
3383 SubExpressionLink = GetNextNode (&OpCode->MapExpressionList, SubExpressionLink);
3384 }
3385
3386 //
3387 // No map value is found.
3388 //
3389 if (IsNull (&OpCode->MapExpressionList, SubExpressionLink)) {
3390 Value->Type = EFI_IFR_TYPE_UNDEFINED;
3391 Value->Value.u8 = 0;
3392 }
3393 break;
3394
3395 default:
3396 break;
3397 }
3398 if (EFI_ERROR (Status) || Value->Type == EFI_IFR_TYPE_UNDEFINED) {
3399 goto Done;
3400 }
3401
3402 Status = PushExpression (Value);
3403 if (EFI_ERROR (Status)) {
3404 goto Done;
3405 }
3406 }
3407
3408 //
3409 // Pop the final result from expression stack
3410 //
3411 Value = &Data1;
3412 Status = PopExpression (Value);
3413 if (EFI_ERROR (Status)) {
3414 goto Done;
3415 }
3416
3417 //
3418 // After evaluating an expression, there should be only one value left on the expression stack
3419 //
3420 if (PopExpression (Value) != EFI_ACCESS_DENIED) {
3421 Status = EFI_INVALID_PARAMETER;
3422 }
3423
3424 Done:
3425 RestoreExpressionEvaluationStackOffset (StackOffset);
3426 if (!EFI_ERROR (Status)) {
3427 CopyMem (&Expression->Result, Value, sizeof (EFI_HII_VALUE));
3428 }
3429
3430 return Status;
3431 }
3432
3433 /**
3434 Check whether the result is TRUE or FALSE.
3435
3436 For the EFI_HII_VALUE value type is numeric, return TRUE if the
3437 value is not 0.
3438
3439 @param Result Input the result data.
3440
3441 @retval TRUE The result is TRUE.
3442 @retval FALSE The result is FALSE.
3443
3444 **/
3445 BOOLEAN
3446 IsTrue (
3447 IN EFI_HII_VALUE *Result
3448 )
3449 {
3450 switch (Result->Type) {
3451 case EFI_IFR_TYPE_BOOLEAN:
3452 return Result->Value.b;
3453
3454 case EFI_IFR_TYPE_NUM_SIZE_8:
3455 return (BOOLEAN)(Result->Value.u8 != 0);
3456
3457 case EFI_IFR_TYPE_NUM_SIZE_16:
3458 return (BOOLEAN)(Result->Value.u16 != 0);
3459
3460 case EFI_IFR_TYPE_NUM_SIZE_32:
3461 return (BOOLEAN)(Result->Value.u32 != 0);
3462
3463 case EFI_IFR_TYPE_NUM_SIZE_64:
3464 return (BOOLEAN)(Result->Value.u64 != 0);
3465
3466 default:
3467 return FALSE;
3468 }
3469 }
3470
3471 /**
3472 Return the result of the expression list. Check the expression list and
3473 return the highest priority express result.
3474 Priority: DisableIf > SuppressIf > GrayOutIf > FALSE
3475
3476 @param ExpList The input expression list.
3477 @param Evaluate Whether need to evaluate the expression first.
3478 @param FormSet FormSet associated with this expression.
3479 @param Form Form associated with this expression.
3480
3481 @retval EXPRESS_RESULT Return the higher priority express result.
3482 DisableIf > SuppressIf > GrayOutIf > FALSE
3483
3484 **/
3485 EXPRESS_RESULT
3486 EvaluateExpressionList (
3487 IN FORM_EXPRESSION_LIST *ExpList,
3488 IN BOOLEAN Evaluate,
3489 IN FORM_BROWSER_FORMSET *FormSet, OPTIONAL
3490 IN FORM_BROWSER_FORM *Form OPTIONAL
3491 )
3492 {
3493 UINTN Index;
3494 EXPRESS_RESULT ReturnVal;
3495 EXPRESS_RESULT CompareOne;
3496 EFI_STATUS Status;
3497
3498 if (ExpList == NULL) {
3499 return ExpressFalse;
3500 }
3501
3502 ASSERT(ExpList->Signature == FORM_EXPRESSION_LIST_SIGNATURE);
3503 Index = 0;
3504
3505 //
3506 // Check whether need to evaluate the expression first.
3507 //
3508 if (Evaluate) {
3509 while (ExpList->Count > Index) {
3510 Status = EvaluateExpression (FormSet, Form, ExpList->Expression[Index++]);
3511 if (EFI_ERROR (Status)) {
3512 return ExpressFalse;
3513 }
3514 }
3515 }
3516
3517 //
3518 // Run the list of expressions.
3519 //
3520 ReturnVal = ExpressFalse;
3521 for (Index = 0; Index < ExpList->Count; Index++) {
3522 if (IsTrue (&ExpList->Expression[Index]->Result)) {
3523 switch (ExpList->Expression[Index]->Type) {
3524 case EFI_HII_EXPRESSION_SUPPRESS_IF:
3525 CompareOne = ExpressSuppress;
3526 break;
3527
3528 case EFI_HII_EXPRESSION_GRAY_OUT_IF:
3529 CompareOne = ExpressGrayOut;
3530 break;
3531
3532 case EFI_HII_EXPRESSION_DISABLE_IF:
3533 CompareOne = ExpressDisable;
3534 break;
3535
3536 default:
3537 return ExpressFalse;
3538 }
3539
3540 ReturnVal = ReturnVal < CompareOne ? CompareOne : ReturnVal;
3541 }
3542 }
3543
3544 return ReturnVal;
3545 }