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