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