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