]> git.proxmox.com Git - mirror_edk2.git/blob - MdeModulePkg/Universal/SetupBrowserDxe/Expression.c
730f51d435fdc51b205e38276af6a75aa0fd11e1
[mirror_edk2.git] / MdeModulePkg / Universal / SetupBrowserDxe / Expression.c
1 /** @file
2
3 Copyright (c) 2007, Intel Corporation
4 All rights reserved. This program and the accompanying materials
5 are licensed and made available under the terms and conditions of the BSD License
6 which accompanies this distribution. The full text of the license may be found at
7 http://opensource.org/licenses/bsd-license.php
8
9 THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
10 WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
11
12 Module Name:
13
14 Expression.c
15
16 Abstract:
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 //
29 EFI_HII_VALUE *mOpCodeScopeStack = NULL;
30 EFI_HII_VALUE *mOpCodeScopeStackEnd = NULL;
31 EFI_HII_VALUE *mOpCodeScopeStackPointer = NULL;
32
33 EFI_HII_VALUE *mExpressionEvaluationStack = NULL;
34 EFI_HII_VALUE *mExpressionEvaluationStackEnd = NULL;
35 EFI_HII_VALUE *mExpressionEvaluationStackPointer = NULL;
36
37 //
38 // Unicode collation protocol interface
39 //
40 EFI_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 **/
55 STATIC
56 EFI_STATUS
57 GrowStack (
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 **/
115 EFI_STATUS
116 PushStack (
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 **/
161 EFI_STATUS
162 PopStack (
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 **/
193 VOID
194 ResetScopeStack (
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 **/
212 EFI_STATUS
213 PushScope (
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 **/
241 EFI_STATUS
242 PopScope (
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 **/
270 VOID
271 ResetExpressionStack (
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 **/
289 EFI_STATUS
290 PushExpression (
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 **/
312 EFI_STATUS
313 PopExpression (
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 **/
336 FORM_BROWSER_FORM *
337 IdToForm (
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 **/
370 FORM_BROWSER_STATEMENT *
371 IdToQuestion2 (
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 **/
412 FORM_BROWSER_STATEMENT *
413 IdToQuestion (
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 **/
459 FORM_EXPRESSION *
460 RuleIdToExpression (
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 **/
492 EFI_STATUS
493 InitializeUnicodeCollationProtocol (
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
516 VOID
517 IfrStrToUpper (
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 **/
541 EFI_STATUS
542 IfrToString (
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 **/
615 EFI_STATUS
616 IfrToUint (
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 **/
676 EFI_STATUS
677 IfrCatenate (
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
725 Done:
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 **/
744 EFI_STATUS
745 IfrMatch (
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
783 Done:
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 **/
802 EFI_STATUS
803 IfrFind (
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])) {
862 Result->Value.u64 = 0xFFFFFFFFFFFFFFFFULL;
863 } else {
864 StringPtr = StrStr (String[1] + Base, String[0]);
865 Result->Value.u64 = (StringPtr == NULL) ? 0xFFFFFFFFFFFFFFFFULL : (StringPtr - String[1]);
866 }
867
868 Done:
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 **/
886 EFI_STATUS
887 IfrMid (
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 **/
957 EFI_STATUS
958 IfrToken (
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
1038 Done:
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 **/
1057 EFI_STATUS
1058 IfrSpan (
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
1142 Done:
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 **/
1158 VOID
1159 ExtendValueToU64 (
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 **/
1212 INTN
1213 CompareHiiValue (
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 **/
1301 EFI_STATUS
1302 EvaluateExpression (
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 }