]>
Commit | Line | Data |
---|---|---|
93e3992d | 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); | |
36fe40c2 | 650 | Status = HexStringToBuf ((UINT8 *) &Result->Value.u64, &BufferSize, StringPtr + 2, NULL); |
93e3992d | 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])) { | |
ee17f9c1 | 862 | Result->Value.u64 = 0xFFFFFFFFFFFFFFFFULL; |
93e3992d | 863 | } else { |
864 | StringPtr = StrStr (String[1] + Base, String[0]); | |
ee17f9c1 | 865 | Result->Value.u64 = (StringPtr == NULL) ? 0xFFFFFFFFFFFFFFFFULL : (StringPtr - String[1]); |
93e3992d | 866 | } |
867 | ||
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 | } |