90fdc7462ffa17dfab6f7c41ce3615c5c1b0d02c
[efi/edk2/.git] / edk2 / MdeModulePkg / Universal / SetupBrowserDxe / Expression.c
1 /** @file\r
2 Utility functions for expression evaluation.\r
3 \r
4 Copyright (c) 2007 - 2010, Intel Corporation\r
5 All rights reserved. This program and the accompanying materials\r
6 are licensed and made available under the terms and conditions of the BSD License\r
7 which accompanies this distribution.  The full text of the license may be found at\r
8 http://opensource.org/licenses/bsd-license.php\r
9 \r
10 THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,\r
11 WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.\r
12 \r
13 **/\r
14 \r
15 #include "Setup.h"\r
16 \r
17 //\r
18 // Global stack used to evaluate boolean expresions\r
19 //\r
20 EFI_HII_VALUE *mOpCodeScopeStack = NULL;\r
21 EFI_HII_VALUE *mOpCodeScopeStackEnd = NULL;\r
22 EFI_HII_VALUE *mOpCodeScopeStackPointer = NULL;\r
23 \r
24 EFI_HII_VALUE *mExpressionEvaluationStack = NULL;\r
25 EFI_HII_VALUE *mExpressionEvaluationStackEnd = NULL;\r
26 EFI_HII_VALUE *mExpressionEvaluationStackPointer = NULL;\r
27 UINTN         mExpressionEvaluationStackOffset = 0;\r
28 \r
29 EFI_HII_VALUE *mCurrentExpressionStack = NULL;\r
30 EFI_HII_VALUE *mCurrentExpressionEnd = NULL;\r
31 EFI_HII_VALUE *mCurrentExpressionPointer = NULL;\r
32 \r
33 EFI_HII_VALUE *mMapExpressionListStack = NULL;\r
34 EFI_HII_VALUE *mMapExpressionListEnd = NULL;\r
35 EFI_HII_VALUE *mMapExpressionListPointer = NULL;\r
36 \r
37 //\r
38 // Unicode collation protocol interface\r
39 //\r
40 EFI_UNICODE_COLLATION_PROTOCOL *mUnicodeCollation = NULL;\r
41 EFI_USER_MANAGER_PROTOCOL      *mUserManager = NULL;\r
42 \r
43 /**\r
44   Grow size of the stack.\r
45 \r
46   This is an internal function.\r
47 \r
48   @param  Stack                  On input: old stack; On output: new stack\r
49   @param  StackPtr               On input: old stack pointer; On output: new stack\r
50                                  pointer\r
51   @param  StackEnd               On input: old stack end; On output: new stack end\r
52 \r
53   @retval EFI_SUCCESS            Grow stack success.\r
54   @retval EFI_OUT_OF_RESOURCES   No enough memory for stack space.\r
55 \r
56 **/\r
57 EFI_STATUS\r
58 GrowStack (\r
59   IN OUT EFI_HII_VALUE  **Stack,\r
60   IN OUT EFI_HII_VALUE  **StackPtr,\r
61   IN OUT EFI_HII_VALUE  **StackEnd\r
62   )\r
63 {\r
64   UINTN           Size;\r
65   EFI_HII_VALUE  *NewStack;\r
66 \r
67   Size = EXPRESSION_STACK_SIZE_INCREMENT;\r
68   if (*StackPtr != NULL) {\r
69     Size = Size + (*StackEnd - *Stack);\r
70   }\r
71 \r
72   NewStack = AllocatePool (Size * sizeof (EFI_HII_VALUE));\r
73   if (NewStack == NULL) {\r
74     return EFI_OUT_OF_RESOURCES;\r
75   }\r
76 \r
77   if (*StackPtr != NULL) {\r
78     //\r
79     // Copy from Old Stack to the New Stack\r
80     //\r
81     CopyMem (\r
82       NewStack,\r
83       *Stack,\r
84       (*StackEnd - *Stack) * sizeof (EFI_HII_VALUE)\r
85       );\r
86 \r
87     //\r
88     // Free The Old Stack\r
89     //\r
90     FreePool (*Stack);\r
91   }\r
92 \r
93   //\r
94   // Make the Stack pointer point to the old data in the new stack\r
95   //\r
96   *StackPtr = NewStack + (*StackPtr - *Stack);\r
97   *Stack    = NewStack;\r
98   *StackEnd = NewStack + Size;\r
99 \r
100   return EFI_SUCCESS;\r
101 }\r
102 \r
103 \r
104 /**\r
105   Push an element onto the Boolean Stack.\r
106 \r
107   @param  Stack                  On input: old stack; On output: new stack\r
108   @param  StackPtr               On input: old stack pointer; On output: new stack\r
109                                  pointer\r
110   @param  StackEnd               On input: old stack end; On output: new stack end\r
111   @param  Data                   Data to push.\r
112 \r
113   @retval EFI_SUCCESS            Push stack success.\r
114 \r
115 **/\r
116 EFI_STATUS\r
117 PushStack (\r
118   IN OUT EFI_HII_VALUE       **Stack,\r
119   IN OUT EFI_HII_VALUE       **StackPtr,\r
120   IN OUT EFI_HII_VALUE       **StackEnd,\r
121   IN EFI_HII_VALUE           *Data\r
122   )\r
123 {\r
124   EFI_STATUS  Status;\r
125 \r
126   //\r
127   // Check for a stack overflow condition\r
128   //\r
129   if (*StackPtr >= *StackEnd) {\r
130     //\r
131     // Grow the stack\r
132     //\r
133     Status = GrowStack (Stack, StackPtr, StackEnd);\r
134     if (EFI_ERROR (Status)) {\r
135       return Status;\r
136     }\r
137   }\r
138 \r
139   //\r
140   // Push the item onto the stack\r
141   //\r
142   CopyMem (*StackPtr, Data, sizeof (EFI_HII_VALUE));\r
143   *StackPtr = *StackPtr + 1;\r
144 \r
145   return EFI_SUCCESS;\r
146 }\r
147 \r
148 \r
149 /**\r
150   Pop an element from the stack.\r
151 \r
152   @param  Stack                  On input: old stack\r
153   @param  StackPtr               On input: old stack pointer; On output: new stack pointer\r
154   @param  Data                   Data to pop.\r
155 \r
156   @retval EFI_SUCCESS            The value was popped onto the stack.\r
157   @retval EFI_ACCESS_DENIED      The pop operation underflowed the stack\r
158 \r
159 **/\r
160 EFI_STATUS\r
161 PopStack (\r
162   IN  EFI_HII_VALUE          *Stack,\r
163   IN OUT EFI_HII_VALUE       **StackPtr,\r
164   OUT EFI_HII_VALUE          *Data\r
165   )\r
166 {\r
167   //\r
168   // Check for a stack underflow condition\r
169   //\r
170   if (*StackPtr == Stack) {\r
171     return EFI_ACCESS_DENIED;\r
172   }\r
173 \r
174   //\r
175   // Pop the item off the stack\r
176   //\r
177   *StackPtr = *StackPtr - 1;\r
178   CopyMem (Data, *StackPtr, sizeof (EFI_HII_VALUE));\r
179   return EFI_SUCCESS;\r
180 }\r
181 \r
182 \r
183 /**\r
184   Reset stack pointer to begin of the stack.\r
185 \r
186 **/\r
187 VOID\r
188 ResetCurrentExpressionStack (\r
189   VOID\r
190   )\r
191 {\r
192   mCurrentExpressionPointer = mCurrentExpressionStack;\r
193 }\r
194 \r
195 \r
196 /**\r
197   Push current expression onto the Stack\r
198 \r
199   @param  Pointer                Pointer to current expression.\r
200 \r
201   @retval EFI_SUCCESS            The value was pushed onto the stack.\r
202   @retval EFI_OUT_OF_RESOURCES   There is not enough system memory to grow the stack.\r
203 \r
204 **/\r
205 EFI_STATUS\r
206 PushCurrentExpression (\r
207   IN VOID  *Pointer\r
208   )\r
209 {\r
210   EFI_HII_VALUE  Data;\r
211 \r
212   Data.Type = EFI_IFR_TYPE_NUM_SIZE_64;\r
213   Data.Value.u64 = (UINT64) (UINTN) Pointer;\r
214 \r
215   return PushStack (\r
216     &mCurrentExpressionStack,\r
217     &mCurrentExpressionPointer,\r
218     &mCurrentExpressionEnd,\r
219     &Data\r
220     );\r
221 }\r
222 \r
223 \r
224 /**\r
225   Pop current expression from the Stack\r
226 \r
227   @param  Pointer                Pointer to current expression to be pop.\r
228 \r
229   @retval EFI_SUCCESS            The value was pushed onto the stack.\r
230   @retval EFI_OUT_OF_RESOURCES   There is not enough system memory to grow the stack.\r
231 \r
232 **/\r
233 EFI_STATUS\r
234 PopCurrentExpression (\r
235   OUT VOID    **Pointer\r
236   )\r
237 {\r
238   EFI_STATUS     Status;\r
239   EFI_HII_VALUE  Data;\r
240 \r
241   Status = PopStack (\r
242     mCurrentExpressionStack,\r
243     &mCurrentExpressionPointer,\r
244     &Data\r
245     );\r
246 \r
247   *Pointer = (VOID *) (UINTN) Data.Value.u64;\r
248 \r
249   return Status;\r
250 }\r
251 \r
252 /**\r
253   Reset stack pointer to begin of the stack.\r
254 \r
255 **/\r
256 VOID\r
257 ResetMapExpressionListStack (\r
258   VOID\r
259   )\r
260 {\r
261   mMapExpressionListPointer = mMapExpressionListStack;\r
262 }\r
263 \r
264 \r
265 /**\r
266   Push the list of map expression onto the Stack\r
267 \r
268   @param  Pointer                Pointer to the list of map expression to be pushed.\r
269 \r
270   @retval EFI_SUCCESS            The value was pushed onto the stack.\r
271   @retval EFI_OUT_OF_RESOURCES   There is not enough system memory to grow the stack.\r
272 \r
273 **/\r
274 EFI_STATUS\r
275 PushMapExpressionList (\r
276   IN VOID  *Pointer\r
277   )\r
278 {\r
279   EFI_HII_VALUE  Data;\r
280 \r
281   Data.Type = EFI_IFR_TYPE_NUM_SIZE_64;\r
282   Data.Value.u64 = (UINT64) (UINTN) Pointer;\r
283 \r
284   return PushStack (\r
285     &mMapExpressionListStack,\r
286     &mMapExpressionListPointer,\r
287     &mMapExpressionListEnd,\r
288     &Data\r
289     );\r
290 }\r
291 \r
292 \r
293 /**\r
294   Pop the list of map expression from the Stack\r
295 \r
296   @param  Pointer                Pointer to the list of map expression to be pop.\r
297 \r
298   @retval EFI_SUCCESS            The value was pushed onto the stack.\r
299   @retval EFI_OUT_OF_RESOURCES   There is not enough system memory to grow the stack.\r
300 \r
301 **/\r
302 EFI_STATUS\r
303 PopMapExpressionList (\r
304   OUT VOID    **Pointer\r
305   )\r
306 {\r
307   EFI_STATUS     Status;\r
308   EFI_HII_VALUE  Data;\r
309 \r
310   Status = PopStack (\r
311     mMapExpressionListStack,\r
312     &mMapExpressionListPointer,\r
313     &Data\r
314     );\r
315 \r
316   *Pointer = (VOID *) (UINTN) Data.Value.u64;\r
317 \r
318   return Status;\r
319 }\r
320 \r
321 /**\r
322   Reset stack pointer to begin of the stack.\r
323 \r
324 **/\r
325 VOID\r
326 ResetScopeStack (\r
327   VOID\r
328   )\r
329 {\r
330   mOpCodeScopeStackPointer = mOpCodeScopeStack;\r
331 }\r
332 \r
333 \r
334 /**\r
335   Push an Operand onto the Stack\r
336 \r
337   @param  Operand                Operand to push.\r
338 \r
339   @retval EFI_SUCCESS            The value was pushed onto the stack.\r
340   @retval EFI_OUT_OF_RESOURCES   There is not enough system memory to grow the\r
341                                  stack.\r
342 \r
343 **/\r
344 EFI_STATUS\r
345 PushScope (\r
346   IN UINT8   Operand\r
347   )\r
348 {\r
349   EFI_HII_VALUE  Data;\r
350 \r
351   Data.Type = EFI_IFR_TYPE_NUM_SIZE_8;\r
352   Data.Value.u8 = Operand;\r
353 \r
354   return PushStack (\r
355            &mOpCodeScopeStack,\r
356            &mOpCodeScopeStackPointer,\r
357            &mOpCodeScopeStackEnd,\r
358            &Data\r
359            );\r
360 }\r
361 \r
362 \r
363 /**\r
364   Pop an Operand from the Stack\r
365 \r
366   @param  Operand                Operand to pop.\r
367 \r
368   @retval EFI_SUCCESS            The value was pushed onto the stack.\r
369   @retval EFI_OUT_OF_RESOURCES   There is not enough system memory to grow the\r
370                                  stack.\r
371 \r
372 **/\r
373 EFI_STATUS\r
374 PopScope (\r
375   OUT UINT8     *Operand\r
376   )\r
377 {\r
378   EFI_STATUS     Status;\r
379   EFI_HII_VALUE  Data;\r
380 \r
381   Status = PopStack (\r
382              mOpCodeScopeStack,\r
383              &mOpCodeScopeStackPointer,\r
384              &Data\r
385              );\r
386 \r
387   *Operand = Data.Value.u8;\r
388 \r
389   return Status;\r
390 }\r
391 \r
392 \r
393 /**\r
394   Push an Expression value onto the Stack\r
395 \r
396   @param  Value                  Expression value to push.\r
397 \r
398   @retval EFI_SUCCESS            The value was pushed onto the stack.\r
399   @retval EFI_OUT_OF_RESOURCES   There is not enough system memory to grow the\r
400                                  stack.\r
401 \r
402 **/\r
403 EFI_STATUS\r
404 PushExpression (\r
405   IN EFI_HII_VALUE  *Value\r
406   )\r
407 {\r
408   return PushStack (\r
409            &mExpressionEvaluationStack,\r
410            &mExpressionEvaluationStackPointer,\r
411            &mExpressionEvaluationStackEnd,\r
412            Value\r
413            );\r
414 }\r
415 \r
416 \r
417 /**\r
418   Pop an Expression value from the stack.\r
419 \r
420   @param  Value                  Expression value to pop.\r
421 \r
422   @retval EFI_SUCCESS            The value was popped onto the stack.\r
423   @retval EFI_ACCESS_DENIED      The pop operation underflowed the stack\r
424 \r
425 **/\r
426 EFI_STATUS\r
427 PopExpression (\r
428   OUT EFI_HII_VALUE  *Value\r
429   )\r
430 {\r
431   return PopStack (\r
432            mExpressionEvaluationStack + mExpressionEvaluationStackOffset,\r
433            &mExpressionEvaluationStackPointer,\r
434            Value\r
435            );\r
436 }\r
437 \r
438 /**\r
439   Get current stack offset from stack start.\r
440 \r
441   @return Stack offset to stack start.\r
442 **/\r
443 UINTN\r
444 SaveExpressionEvaluationStackOffset (\r
445   )\r
446 {\r
447   UINTN TempStackOffset;\r
448   TempStackOffset = mExpressionEvaluationStackOffset;\r
449   mExpressionEvaluationStackOffset = mExpressionEvaluationStackPointer - mExpressionEvaluationStack;\r
450   return TempStackOffset;\r
451 }\r
452 \r
453 /**\r
454   Restore stack offset based on input stack offset\r
455 \r
456   @param  StackOffset  Offset to stack start.\r
457 \r
458 **/\r
459 VOID\r
460 RestoreExpressionEvaluationStackOffset (\r
461   UINTN StackOffset\r
462   )\r
463 {\r
464   mExpressionEvaluationStackOffset = StackOffset;\r
465 }\r
466 \r
467 /**\r
468   Get Form given its FormId.\r
469 \r
470   @param  FormSet                The formset which contains this form.\r
471   @param  FormId                 Id of this form.\r
472 \r
473   @retval Pointer                The form.\r
474   @retval NULL                   Specified Form is not found in the formset.\r
475 \r
476 **/\r
477 FORM_BROWSER_FORM *\r
478 IdToForm (\r
479   IN FORM_BROWSER_FORMSET  *FormSet,\r
480   IN UINT16                FormId\r
481 )\r
482 {\r
483   LIST_ENTRY         *Link;\r
484   FORM_BROWSER_FORM  *Form;\r
485 \r
486   Link = GetFirstNode (&FormSet->FormListHead);\r
487   while (!IsNull (&FormSet->FormListHead, Link)) {\r
488     Form = FORM_BROWSER_FORM_FROM_LINK (Link);\r
489 \r
490     if (Form->FormId == FormId) {\r
491       return Form;\r
492     }\r
493 \r
494     Link = GetNextNode (&FormSet->FormListHead, Link);\r
495   }\r
496 \r
497   return NULL;\r
498 }\r
499 \r
500 \r
501 /**\r
502   Search a Question in Form scope using its QuestionId.\r
503 \r
504   @param  Form                   The form which contains this Question.\r
505   @param  QuestionId             Id of this Question.\r
506 \r
507   @retval Pointer                The Question.\r
508   @retval NULL                   Specified Question not found in the form.\r
509 \r
510 **/\r
511 FORM_BROWSER_STATEMENT *\r
512 IdToQuestion2 (\r
513   IN FORM_BROWSER_FORM  *Form,\r
514   IN UINT16             QuestionId\r
515   )\r
516 {\r
517   LIST_ENTRY              *Link;\r
518   FORM_BROWSER_STATEMENT  *Question;\r
519 \r
520   if (QuestionId == 0) {\r
521     //\r
522     // The value of zero is reserved\r
523     //\r
524     return NULL;\r
525   }\r
526 \r
527   Link = GetFirstNode (&Form->StatementListHead);\r
528   while (!IsNull (&Form->StatementListHead, Link)) {\r
529     Question = FORM_BROWSER_STATEMENT_FROM_LINK (Link);\r
530 \r
531     if (Question->QuestionId == QuestionId) {\r
532       return Question;\r
533     }\r
534 \r
535     Link = GetNextNode (&Form->StatementListHead, Link);\r
536   }\r
537 \r
538   return NULL;\r
539 }\r
540 \r
541 \r
542 /**\r
543   Search a Question in Formset scope using its QuestionId.\r
544 \r
545   @param  FormSet                The formset which contains this form.\r
546   @param  Form                   The form which contains this Question.\r
547   @param  QuestionId             Id of this Question.\r
548 \r
549   @retval Pointer                The Question.\r
550   @retval NULL                   Specified Question not found in the form.\r
551 \r
552 **/\r
553 FORM_BROWSER_STATEMENT *\r
554 IdToQuestion (\r
555   IN FORM_BROWSER_FORMSET  *FormSet,\r
556   IN FORM_BROWSER_FORM     *Form,\r
557   IN UINT16                QuestionId\r
558   )\r
559 {\r
560   LIST_ENTRY              *Link;\r
561   FORM_BROWSER_STATEMENT  *Question;\r
562 \r
563   //\r
564   // Search in the form scope first\r
565   //\r
566   Question = IdToQuestion2 (Form, QuestionId);\r
567   if (Question != NULL) {\r
568     return Question;\r
569   }\r
570 \r
571   //\r
572   // Search in the formset scope\r
573   //\r
574   Link = GetFirstNode (&FormSet->FormListHead);\r
575   while (!IsNull (&FormSet->FormListHead, Link)) {\r
576     Form = FORM_BROWSER_FORM_FROM_LINK (Link);\r
577 \r
578     Question = IdToQuestion2 (Form, QuestionId);\r
579     if (Question != NULL) {\r
580       //\r
581       // EFI variable storage may be updated by Callback() asynchronous,\r
582       // to keep synchronous, always reload the Question Value.\r
583       //\r
584       if (Question->Storage->Type == EFI_HII_VARSTORE_EFI_VARIABLE) {\r
585         GetQuestionValue (FormSet, Form, Question, FALSE);\r
586       }\r
587 \r
588       return Question;\r
589     }\r
590 \r
591     Link = GetNextNode (&FormSet->FormListHead, Link);\r
592   }\r
593 \r
594   return NULL;\r
595 }\r
596 \r
597 \r
598 /**\r
599   Get Expression given its RuleId.\r
600 \r
601   @param  Form                   The form which contains this Expression.\r
602   @param  RuleId                 Id of this Expression.\r
603 \r
604   @retval Pointer                The Expression.\r
605   @retval NULL                   Specified Expression not found in the form.\r
606 \r
607 **/\r
608 FORM_EXPRESSION *\r
609 RuleIdToExpression (\r
610   IN FORM_BROWSER_FORM  *Form,\r
611   IN UINT8              RuleId\r
612   )\r
613 {\r
614   LIST_ENTRY       *Link;\r
615   FORM_EXPRESSION  *Expression;\r
616 \r
617   Link = GetFirstNode (&Form->ExpressionListHead);\r
618   while (!IsNull (&Form->ExpressionListHead, Link)) {\r
619     Expression = FORM_EXPRESSION_FROM_LINK (Link);\r
620 \r
621     if (Expression->Type == EFI_HII_EXPRESSION_RULE && Expression->RuleId == RuleId) {\r
622       return Expression;\r
623     }\r
624 \r
625     Link = GetNextNode (&Form->ExpressionListHead, Link);\r
626   }\r
627 \r
628   return NULL;\r
629 }\r
630 \r
631 \r
632 /**\r
633   Locate the Unicode Collation Protocol interface for later use.\r
634 \r
635   @retval EFI_SUCCESS            Protocol interface initialize success.\r
636   @retval Other                  Protocol interface initialize failed.\r
637 \r
638 **/\r
639 EFI_STATUS\r
640 InitializeUnicodeCollationProtocol (\r
641   VOID\r
642   )\r
643 {\r
644   EFI_STATUS  Status;\r
645 \r
646   if (mUnicodeCollation != NULL) {\r
647     return EFI_SUCCESS;\r
648   }\r
649 \r
650   //\r
651   // BUGBUG: Proper impelmentation is to locate all Unicode Collation Protocol\r
652   // instances first and then select one which support English language.\r
653   // Current implementation just pick the first instance.\r
654   //\r
655   Status = gBS->LocateProtocol (\r
656                   &gEfiUnicodeCollation2ProtocolGuid,\r
657                   NULL,\r
658                   (VOID **) &mUnicodeCollation\r
659                   );\r
660   return Status;\r
661 }\r
662 \r
663 /**\r
664   Convert the input Unicode character to upper.\r
665 \r
666   @param String  Th Unicode character to be converted.\r
667 \r
668 **/\r
669 VOID\r
670 IfrStrToUpper (\r
671   IN CHAR16                   *String\r
672   )\r
673 {\r
674   while (*String != 0) {\r
675     if ((*String >= 'a') && (*String <= 'z')) {\r
676       *String = (UINT16) ((*String) & ((UINT16) ~0x20));\r
677     }\r
678     String++;\r
679   }\r
680 }\r
681 \r
682 \r
683 /**\r
684   Evaluate opcode EFI_IFR_TO_STRING.\r
685 \r
686   @param  FormSet                Formset which contains this opcode.\r
687   @param  Format                 String format in EFI_IFR_TO_STRING.\r
688   @param  Result                 Evaluation result for this opcode.\r
689 \r
690   @retval EFI_SUCCESS            Opcode evaluation success.\r
691   @retval Other                  Opcode evaluation failed.\r
692 \r
693 **/\r
694 EFI_STATUS\r
695 IfrToString (\r
696   IN FORM_BROWSER_FORMSET  *FormSet,\r
697   IN UINT8                 Format,\r
698   OUT  EFI_HII_VALUE       *Result\r
699   )\r
700 {\r
701   EFI_STATUS     Status;\r
702   EFI_HII_VALUE  Value;\r
703   CHAR16         *String;\r
704   CHAR16         *PrintFormat;\r
705   CHAR16         Buffer[MAXIMUM_VALUE_CHARACTERS];\r
706   UINTN          BufferSize;\r
707 \r
708   Status = PopExpression (&Value);\r
709   if (EFI_ERROR (Status)) {\r
710     return Status;\r
711   }\r
712 \r
713   switch (Value.Type) {\r
714   case EFI_IFR_TYPE_NUM_SIZE_8:\r
715   case EFI_IFR_TYPE_NUM_SIZE_16:\r
716   case EFI_IFR_TYPE_NUM_SIZE_32:\r
717   case EFI_IFR_TYPE_NUM_SIZE_64:\r
718     BufferSize = MAXIMUM_VALUE_CHARACTERS * sizeof (CHAR16);\r
719     switch (Format) {\r
720     case EFI_IFR_STRING_UNSIGNED_DEC:\r
721     case EFI_IFR_STRING_SIGNED_DEC:\r
722       PrintFormat = L"%ld";\r
723       break;\r
724 \r
725     case EFI_IFR_STRING_LOWERCASE_HEX:\r
726       PrintFormat = L"%lx";\r
727       break;\r
728 \r
729     case EFI_IFR_STRING_UPPERCASE_HEX:\r
730       PrintFormat = L"%lX";\r
731       break;\r
732 \r
733     default:\r
734       return EFI_UNSUPPORTED;\r
735     }\r
736     UnicodeSPrint (Buffer, BufferSize, PrintFormat, Value.Value.u64);\r
737     String = Buffer;\r
738     break;\r
739 \r
740   case EFI_IFR_TYPE_STRING:\r
741     CopyMem (Result, &Value, sizeof (EFI_HII_VALUE));\r
742     return EFI_SUCCESS;\r
743 \r
744   case EFI_IFR_TYPE_BOOLEAN:\r
745     String = (Value.Value.b) ? L"True" : L"False";\r
746     break;\r
747 \r
748   default:\r
749     return EFI_UNSUPPORTED;\r
750   }\r
751 \r
752   Result->Type = EFI_IFR_TYPE_STRING;\r
753   Result->Value.string = NewString (String, FormSet->HiiHandle);\r
754   return EFI_SUCCESS;\r
755 }\r
756 \r
757 \r
758 /**\r
759   Evaluate opcode EFI_IFR_TO_UINT.\r
760 \r
761   @param  FormSet                Formset which contains this opcode.\r
762   @param  Result                 Evaluation result for this opcode.\r
763 \r
764   @retval EFI_SUCCESS            Opcode evaluation success.\r
765   @retval Other                  Opcode evaluation failed.\r
766 \r
767 **/\r
768 EFI_STATUS\r
769 IfrToUint (\r
770   IN FORM_BROWSER_FORMSET  *FormSet,\r
771   OUT  EFI_HII_VALUE       *Result\r
772   )\r
773 {\r
774   EFI_STATUS     Status;\r
775   EFI_HII_VALUE  Value;\r
776   CHAR16         *String;\r
777   CHAR16         *StringPtr;\r
778 \r
779   Status = PopExpression (&Value);\r
780   if (EFI_ERROR (Status)) {\r
781     return Status;\r
782   }\r
783 \r
784   if (Value.Type >= EFI_IFR_TYPE_OTHER) {\r
785     return EFI_UNSUPPORTED;\r
786   }\r
787 \r
788   Status = EFI_SUCCESS;\r
789   if (Value.Type == EFI_IFR_TYPE_STRING) {\r
790     String = GetToken (Value.Value.string, FormSet->HiiHandle);\r
791     if (String == NULL) {\r
792       return EFI_NOT_FOUND;\r
793     }\r
794 \r
795     IfrStrToUpper (String);\r
796     StringPtr = StrStr (String, L"0X");\r
797     if (StringPtr != NULL) {\r
798       //\r
799       // Hex string\r
800       //\r
801       Result->Value.u64 = StrHexToUint64 (String);\r
802     } else {\r
803       //\r
804       // decimal string\r
805       //\r
806       Result->Value.u64 = StrDecimalToUint64 (String);\r
807     }\r
808     FreePool (String);\r
809   } else {\r
810     CopyMem (Result, &Value, sizeof (EFI_HII_VALUE));\r
811   }\r
812 \r
813   Result->Type = EFI_IFR_TYPE_NUM_SIZE_64;\r
814   return Status;\r
815 }\r
816 \r
817 \r
818 /**\r
819   Evaluate opcode EFI_IFR_CATENATE.\r
820 \r
821   @param  FormSet                Formset which contains this opcode.\r
822   @param  Result                 Evaluation result for this opcode.\r
823 \r
824   @retval EFI_SUCCESS            Opcode evaluation success.\r
825   @retval Other                  Opcode evaluation failed.\r
826 \r
827 **/\r
828 EFI_STATUS\r
829 IfrCatenate (\r
830   IN FORM_BROWSER_FORMSET  *FormSet,\r
831   OUT  EFI_HII_VALUE       *Result\r
832   )\r
833 {\r
834   EFI_STATUS     Status;\r
835   EFI_HII_VALUE  Value;\r
836   CHAR16         *String[2];\r
837   UINTN          Index;\r
838   CHAR16         *StringPtr;\r
839   UINTN          Size;\r
840 \r
841   //\r
842   // String[0] - The second string\r
843   // String[1] - The first string\r
844   //\r
845   String[0] = NULL;\r
846   String[1] = NULL;\r
847   StringPtr = NULL;\r
848   Status = EFI_SUCCESS;\r
849 \r
850   for (Index = 0; Index < 2; Index++) {\r
851     Status = PopExpression (&Value);\r
852     if (EFI_ERROR (Status)) {\r
853       goto Done;\r
854     }\r
855 \r
856     if (Value.Type != EFI_IFR_TYPE_STRING) {\r
857       Status = EFI_UNSUPPORTED;\r
858       goto Done;\r
859     }\r
860 \r
861     String[Index] = GetToken (Value.Value.string, FormSet->HiiHandle);\r
862     if (String[Index] == NULL) {\r
863       Status = EFI_NOT_FOUND;\r
864       goto Done;\r
865     }\r
866   }\r
867 \r
868   Size = StrSize (String[0]);\r
869   StringPtr= AllocatePool (StrSize (String[1]) + Size);\r
870   ASSERT (StringPtr != NULL);\r
871   StrCpy (StringPtr, String[1]);\r
872   StrCat (StringPtr, String[0]);\r
873 \r
874   Result->Type = EFI_IFR_TYPE_STRING;\r
875   Result->Value.string = NewString (StringPtr, FormSet->HiiHandle);\r
876 \r
877 Done:\r
878   if (String[0] != NULL) {\r
879     FreePool (String[0]);\r
880   }\r
881   if (String[1] != NULL) {\r
882     FreePool (String[1]);\r
883   }\r
884   if (StringPtr != NULL) {\r
885     FreePool (StringPtr);\r
886   }\r
887 \r
888   return Status;\r
889 }\r
890 \r
891 \r
892 /**\r
893   Evaluate opcode EFI_IFR_MATCH.\r
894 \r
895   @param  FormSet                Formset which contains this opcode.\r
896   @param  Result                 Evaluation result for this opcode.\r
897 \r
898   @retval EFI_SUCCESS            Opcode evaluation success.\r
899   @retval Other                  Opcode evaluation failed.\r
900 \r
901 **/\r
902 EFI_STATUS\r
903 IfrMatch (\r
904   IN FORM_BROWSER_FORMSET  *FormSet,\r
905   OUT  EFI_HII_VALUE       *Result\r
906   )\r
907 {\r
908   EFI_STATUS     Status;\r
909   EFI_HII_VALUE  Value;\r
910   CHAR16         *String[2];\r
911   UINTN          Index;\r
912 \r
913   //\r
914   // String[0] - The string to search\r
915   // String[1] - pattern\r
916   //\r
917   String[0] = NULL;\r
918   String[1] = NULL;\r
919   Status = EFI_SUCCESS;\r
920   for (Index = 0; Index < 2; Index++) {\r
921     Status = PopExpression (&Value);\r
922     if (EFI_ERROR (Status)) {\r
923       goto Done;\r
924     }\r
925 \r
926     if (Value.Type != EFI_IFR_TYPE_STRING) {\r
927       Status = EFI_UNSUPPORTED;\r
928       goto Done;\r
929     }\r
930 \r
931     String[Index] = GetToken (Value.Value.string, FormSet->HiiHandle);\r
932     if (String [Index] == NULL) {\r
933       Status = EFI_NOT_FOUND;\r
934       goto Done;\r
935     }\r
936   }\r
937 \r
938   Result->Type = EFI_IFR_TYPE_BOOLEAN;\r
939   Result->Value.b = mUnicodeCollation->MetaiMatch (mUnicodeCollation, String[0], String[1]);\r
940 \r
941 Done:\r
942   if (String[0] != NULL) {\r
943     FreePool (String[0]);\r
944   }\r
945   if (String[1] != NULL) {\r
946     FreePool (String[1]);\r
947   }\r
948 \r
949   return Status;\r
950 }\r
951 \r
952 \r
953 /**\r
954   Evaluate opcode EFI_IFR_FIND.\r
955 \r
956   @param  FormSet                Formset which contains this opcode.\r
957   @param  Format                 Case sensitive or insensitive.\r
958   @param  Result                 Evaluation result for this opcode.\r
959 \r
960   @retval EFI_SUCCESS            Opcode evaluation success.\r
961   @retval Other                  Opcode evaluation failed.\r
962 \r
963 **/\r
964 EFI_STATUS\r
965 IfrFind (\r
966   IN FORM_BROWSER_FORMSET  *FormSet,\r
967   IN UINT8                 Format,\r
968   OUT  EFI_HII_VALUE       *Result\r
969   )\r
970 {\r
971   EFI_STATUS     Status;\r
972   EFI_HII_VALUE  Value;\r
973   CHAR16         *String[2];\r
974   UINTN          Base;\r
975   CHAR16         *StringPtr;\r
976   UINTN          Index;\r
977 \r
978   if (Format > EFI_IFR_FF_CASE_INSENSITIVE) {\r
979     return EFI_UNSUPPORTED;\r
980   }\r
981 \r
982   Status = PopExpression (&Value);\r
983   if (EFI_ERROR (Status)) {\r
984     return Status;\r
985   }\r
986   if (Value.Type > EFI_IFR_TYPE_NUM_SIZE_64) {\r
987     return EFI_UNSUPPORTED;\r
988   }\r
989   Base = (UINTN) Value.Value.u64;\r
990 \r
991   //\r
992   // String[0] - sub-string\r
993   // String[1] - The string to search\r
994   //\r
995   String[0] = NULL;\r
996   String[1] = NULL;\r
997   for (Index = 0; Index < 2; Index++) {\r
998     Status = PopExpression (&Value);\r
999     if (EFI_ERROR (Status)) {\r
1000       goto Done;\r
1001     }\r
1002 \r
1003     if (Value.Type != EFI_IFR_TYPE_STRING) {\r
1004       Status = EFI_UNSUPPORTED;\r
1005       goto Done;\r
1006     }\r
1007 \r
1008     String[Index] = GetToken (Value.Value.string, FormSet->HiiHandle);\r
1009     if (String[Index] == NULL) {\r
1010       Status = EFI_NOT_FOUND;\r
1011       goto Done;\r
1012     }\r
1013 \r
1014     if (Format == EFI_IFR_FF_CASE_INSENSITIVE) {\r
1015       //\r
1016       // Case insensitive, convert both string to upper case\r
1017       //\r
1018       IfrStrToUpper (String[Index]);\r
1019     }\r
1020   }\r
1021 \r
1022   Result->Type = EFI_IFR_TYPE_NUM_SIZE_64;\r
1023   if (Base >= StrLen (String[1])) {\r
1024     Result->Value.u64 = 0xFFFFFFFFFFFFFFFFULL;\r
1025   } else {\r
1026     StringPtr = StrStr (String[1] + Base, String[0]);\r
1027     Result->Value.u64 = (StringPtr == NULL) ? 0xFFFFFFFFFFFFFFFFULL : (StringPtr - String[1]);\r
1028   }\r
1029 \r
1030 Done:\r
1031   if (String[0] != NULL) {\r
1032     FreePool (String[0]);\r
1033   }\r
1034   if (String[1] != NULL) {\r
1035     FreePool (String[1]);\r
1036   }\r
1037 \r
1038   return Status;\r
1039 }\r
1040 \r
1041 \r
1042 /**\r
1043   Evaluate opcode EFI_IFR_MID.\r
1044 \r
1045   @param  FormSet                Formset which contains this opcode.\r
1046   @param  Result                 Evaluation result for this opcode.\r
1047 \r
1048   @retval EFI_SUCCESS            Opcode evaluation success.\r
1049   @retval Other                  Opcode evaluation failed.\r
1050 \r
1051 **/\r
1052 EFI_STATUS\r
1053 IfrMid (\r
1054   IN FORM_BROWSER_FORMSET  *FormSet,\r
1055   OUT  EFI_HII_VALUE       *Result\r
1056   )\r
1057 {\r
1058   EFI_STATUS     Status;\r
1059   EFI_HII_VALUE  Value;\r
1060   CHAR16         *String;\r
1061   UINTN          Base;\r
1062   UINTN          Length;\r
1063   CHAR16         *SubString;\r
1064 \r
1065   Status = PopExpression (&Value);\r
1066   if (EFI_ERROR (Status)) {\r
1067     return Status;\r
1068   }\r
1069   if (Value.Type > EFI_IFR_TYPE_NUM_SIZE_64) {\r
1070     return EFI_UNSUPPORTED;\r
1071   }\r
1072   Length = (UINTN) Value.Value.u64;\r
1073 \r
1074   Status = PopExpression (&Value);\r
1075   if (EFI_ERROR (Status)) {\r
1076     return Status;\r
1077   }\r
1078   if (Value.Type > EFI_IFR_TYPE_NUM_SIZE_64) {\r
1079     return EFI_UNSUPPORTED;\r
1080   }\r
1081   Base = (UINTN) Value.Value.u64;\r
1082 \r
1083   Status = PopExpression (&Value);\r
1084   if (EFI_ERROR (Status)) {\r
1085     return Status;\r
1086   }\r
1087   if (Value.Type != EFI_IFR_TYPE_STRING) {\r
1088     return EFI_UNSUPPORTED;\r
1089   }\r
1090   String = GetToken (Value.Value.string, FormSet->HiiHandle);\r
1091   if (String == NULL) {\r
1092     return EFI_NOT_FOUND;\r
1093   }\r
1094 \r
1095   if (Length == 0 || Base >= StrLen (String)) {\r
1096     SubString = gEmptyString;\r
1097   } else {\r
1098     SubString = String + Base;\r
1099     if ((Base + Length) < StrLen (String)) {\r
1100       SubString[Length] = L'\0';\r
1101     }\r
1102   }\r
1103 \r
1104   Result->Type = EFI_IFR_TYPE_STRING;\r
1105   Result->Value.string = NewString (SubString, FormSet->HiiHandle);\r
1106 \r
1107   FreePool (String);\r
1108 \r
1109   return Status;\r
1110 }\r
1111 \r
1112 \r
1113 /**\r
1114   Evaluate opcode EFI_IFR_TOKEN.\r
1115 \r
1116   @param  FormSet                Formset which contains this opcode.\r
1117   @param  Result                 Evaluation result for this opcode.\r
1118 \r
1119   @retval EFI_SUCCESS            Opcode evaluation success.\r
1120   @retval Other                  Opcode evaluation failed.\r
1121 \r
1122 **/\r
1123 EFI_STATUS\r
1124 IfrToken (\r
1125   IN FORM_BROWSER_FORMSET  *FormSet,\r
1126   OUT  EFI_HII_VALUE       *Result\r
1127   )\r
1128 {\r
1129   EFI_STATUS     Status;\r
1130   EFI_HII_VALUE  Value;\r
1131   CHAR16         *String[2];\r
1132   UINTN          Count;\r
1133   CHAR16         *Delimiter;\r
1134   CHAR16         *SubString;\r
1135   CHAR16         *StringPtr;\r
1136   UINTN          Index;\r
1137 \r
1138   Status = PopExpression (&Value);\r
1139   if (EFI_ERROR (Status)) {\r
1140     return Status;\r
1141   }\r
1142   if (Value.Type > EFI_IFR_TYPE_NUM_SIZE_64) {\r
1143     return EFI_UNSUPPORTED;\r
1144   }\r
1145   Count = (UINTN) Value.Value.u64;\r
1146 \r
1147   //\r
1148   // String[0] - Delimiter\r
1149   // String[1] - The string to search\r
1150   //\r
1151   String[0] = NULL;\r
1152   String[1] = NULL;\r
1153   for (Index = 0; Index < 2; Index++) {\r
1154     Status = PopExpression (&Value);\r
1155     if (EFI_ERROR (Status)) {\r
1156       goto Done;\r
1157     }\r
1158 \r
1159     if (Value.Type != EFI_IFR_TYPE_STRING) {\r
1160       Status = EFI_UNSUPPORTED;\r
1161       goto Done;\r
1162     }\r
1163 \r
1164     String[Index] = GetToken (Value.Value.string, FormSet->HiiHandle);\r
1165     if (String[Index] == NULL) {\r
1166       Status = EFI_NOT_FOUND;\r
1167       goto Done;\r
1168     }\r
1169   }\r
1170 \r
1171   Delimiter = String[0];\r
1172   SubString = String[1];\r
1173   while (Count > 0) {\r
1174     SubString = StrStr (SubString, Delimiter);\r
1175     if (SubString != NULL) {\r
1176       //\r
1177       // Skip over the delimiter\r
1178       //\r
1179       SubString = SubString + StrLen (Delimiter);\r
1180     } else {\r
1181       break;\r
1182     }\r
1183     Count--;\r
1184   }\r
1185 \r
1186   if (SubString == NULL) {\r
1187     //\r
1188     // nth delimited sub-string not found, push an empty string\r
1189     //\r
1190     SubString = gEmptyString;\r
1191   } else {\r
1192     //\r
1193     // Put a NULL terminator for nth delimited sub-string\r
1194     //\r
1195     StringPtr = StrStr (SubString, Delimiter);\r
1196     if (StringPtr != NULL) {\r
1197       *StringPtr = L'\0';\r
1198     }\r
1199   }\r
1200 \r
1201   Result->Type = EFI_IFR_TYPE_STRING;\r
1202   Result->Value.string = NewString (SubString, FormSet->HiiHandle);\r
1203 \r
1204 Done:\r
1205   if (String[0] != NULL) {\r
1206     FreePool (String[0]);\r
1207   }\r
1208   if (String[1] != NULL) {\r
1209     FreePool (String[1]);\r
1210   }\r
1211 \r
1212   return Status;\r
1213 }\r
1214 \r
1215 \r
1216 /**\r
1217   Evaluate opcode EFI_IFR_SPAN.\r
1218 \r
1219   @param  FormSet                Formset which contains this opcode.\r
1220   @param  Flags                  FIRST_MATCHING or FIRST_NON_MATCHING.\r
1221   @param  Result                 Evaluation result for this opcode.\r
1222 \r
1223   @retval EFI_SUCCESS            Opcode evaluation success.\r
1224   @retval Other                  Opcode evaluation failed.\r
1225 \r
1226 **/\r
1227 EFI_STATUS\r
1228 IfrSpan (\r
1229   IN FORM_BROWSER_FORMSET  *FormSet,\r
1230   IN UINT8                 Flags,\r
1231   OUT  EFI_HII_VALUE       *Result\r
1232   )\r
1233 {\r
1234   EFI_STATUS     Status;\r
1235   EFI_HII_VALUE  Value;\r
1236   CHAR16         *String[2];\r
1237   CHAR16         *Charset;\r
1238   UINTN          Base;\r
1239   UINTN          Index;\r
1240   CHAR16         *StringPtr;\r
1241   BOOLEAN        Found;\r
1242 \r
1243   Status = PopExpression (&Value);\r
1244   if (EFI_ERROR (Status)) {\r
1245     return Status;\r
1246   }\r
1247   if (Value.Type > EFI_IFR_TYPE_NUM_SIZE_64) {\r
1248     return EFI_UNSUPPORTED;\r
1249   }\r
1250   Base = (UINTN) Value.Value.u64;\r
1251 \r
1252   //\r
1253   // String[0] - Charset\r
1254   // String[1] - The string to search\r
1255   //\r
1256   String[0] = NULL;\r
1257   String[1] = NULL;\r
1258   for (Index = 0; Index < 2; Index++) {\r
1259     Status = PopExpression (&Value);\r
1260     if (EFI_ERROR (Status)) {\r
1261       goto Done;\r
1262     }\r
1263 \r
1264     if (Value.Type != EFI_IFR_TYPE_STRING) {\r
1265       Status = EFI_UNSUPPORTED;\r
1266       goto Done;\r
1267     }\r
1268 \r
1269     String[Index] = GetToken (Value.Value.string, FormSet->HiiHandle);\r
1270     if (String [Index] == NULL) {\r
1271       Status = EFI_NOT_FOUND;\r
1272       goto Done;\r
1273     }\r
1274   }\r
1275 \r
1276   if (Base >= StrLen (String[1])) {\r
1277     Status = EFI_UNSUPPORTED;\r
1278     goto Done;\r
1279   }\r
1280 \r
1281   Found = FALSE;\r
1282   StringPtr = String[1] + Base;\r
1283   Charset = String[0];\r
1284   while (*StringPtr != 0 && !Found) {\r
1285     Index = 0;\r
1286     while (Charset[Index] != 0) {\r
1287       if (*StringPtr >= Charset[Index] && *StringPtr <= Charset[Index + 1]) {\r
1288         if (Flags == EFI_IFR_FLAGS_FIRST_MATCHING) {\r
1289           Found = TRUE;\r
1290           break;\r
1291         }\r
1292       } else {\r
1293         if (Flags == EFI_IFR_FLAGS_FIRST_NON_MATCHING) {\r
1294           Found = TRUE;\r
1295           break;\r
1296         }\r
1297       }\r
1298       //\r
1299       // Skip characters pair representing low-end of a range and high-end of a range\r
1300       //\r
1301       Index += 2;\r
1302     }\r
1303 \r
1304     if (!Found) {\r
1305       StringPtr++;\r
1306     }\r
1307   }\r
1308 \r
1309   Result->Type = EFI_IFR_TYPE_NUM_SIZE_64;\r
1310   Result->Value.u64 = StringPtr - String[1];\r
1311 \r
1312 Done:\r
1313   if (String[0] != NULL) {\r
1314     FreePool (String[0]);\r
1315   }\r
1316   if (String[1] != NULL) {\r
1317     FreePool (String[1]);\r
1318   }\r
1319 \r
1320   return Status;\r
1321 }\r
1322 \r
1323 \r
1324 /**\r
1325   Zero extend integer/boolean/date/time to UINT64 for comparing.\r
1326 \r
1327   @param  Value                  HII Value to be converted.\r
1328 \r
1329 **/\r
1330 VOID\r
1331 ExtendValueToU64 (\r
1332   IN  EFI_HII_VALUE   *Value\r
1333   )\r
1334 {\r
1335   UINT64  Temp;\r
1336 \r
1337   Temp = 0;\r
1338   switch (Value->Type) {\r
1339   case EFI_IFR_TYPE_NUM_SIZE_8:\r
1340     Temp = Value->Value.u8;\r
1341     break;\r
1342 \r
1343   case EFI_IFR_TYPE_NUM_SIZE_16:\r
1344     Temp = Value->Value.u16;\r
1345     break;\r
1346 \r
1347   case EFI_IFR_TYPE_NUM_SIZE_32:\r
1348     Temp = Value->Value.u32;\r
1349     break;\r
1350 \r
1351   case EFI_IFR_TYPE_BOOLEAN:\r
1352     Temp = Value->Value.b;\r
1353     break;\r
1354 \r
1355   case EFI_IFR_TYPE_TIME:\r
1356     Temp = Value->Value.u32 & 0xffffff;\r
1357     break;\r
1358 \r
1359   case EFI_IFR_TYPE_DATE:\r
1360     Temp = Value->Value.u32;\r
1361     break;\r
1362 \r
1363   default:\r
1364     return;\r
1365   }\r
1366 \r
1367   Value->Value.u64 = Temp;\r
1368 }\r
1369 \r
1370 \r
1371 /**\r
1372   Compare two Hii value.\r
1373 \r
1374   @param  Value1                 Expression value to compare on left-hand.\r
1375   @param  Value2                 Expression value to compare on right-hand.\r
1376   @param  HiiHandle              Only required for string compare.\r
1377 \r
1378   @retval EFI_INVALID_PARAMETER  Could not perform compare on two values.\r
1379   @retval 0                      Two operators equal.\r
1380   @return Positive value if Value1 is greater than Value2.\r
1381   @retval Negative value if Value1 is less than Value2.\r
1382 \r
1383 **/\r
1384 INTN\r
1385 CompareHiiValue (\r
1386   IN  EFI_HII_VALUE   *Value1,\r
1387   IN  EFI_HII_VALUE   *Value2,\r
1388   IN  EFI_HII_HANDLE  HiiHandle OPTIONAL\r
1389   )\r
1390 {\r
1391   INTN    Result;\r
1392   INT64   Temp64;\r
1393   CHAR16  *Str1;\r
1394   CHAR16  *Str2;\r
1395 \r
1396   if (Value1->Type >= EFI_IFR_TYPE_OTHER || Value2->Type >= EFI_IFR_TYPE_OTHER ) {\r
1397     return EFI_INVALID_PARAMETER;\r
1398   }\r
1399 \r
1400   if (Value1->Type == EFI_IFR_TYPE_STRING || Value2->Type == EFI_IFR_TYPE_STRING ) {\r
1401     if (Value1->Type != Value2->Type) {\r
1402       //\r
1403       // Both Operator should be type of String\r
1404       //\r
1405       return EFI_INVALID_PARAMETER;\r
1406     }\r
1407 \r
1408     if (Value1->Value.string == 0 || Value2->Value.string == 0) {\r
1409       //\r
1410       // StringId 0 is reserved\r
1411       //\r
1412       return EFI_INVALID_PARAMETER;\r
1413     }\r
1414 \r
1415     if (Value1->Value.string == Value2->Value.string) {\r
1416       return 0;\r
1417     }\r
1418 \r
1419     Str1 = GetToken (Value1->Value.string, HiiHandle);\r
1420     if (Str1 == NULL) {\r
1421       //\r
1422       // String not found\r
1423       //\r
1424       return EFI_INVALID_PARAMETER;\r
1425     }\r
1426 \r
1427     Str2 = GetToken (Value2->Value.string, HiiHandle);\r
1428     if (Str2 == NULL) {\r
1429       FreePool (Str1);\r
1430       return EFI_INVALID_PARAMETER;\r
1431     }\r
1432 \r
1433     Result = StrCmp (Str1, Str2);\r
1434 \r
1435     FreePool (Str1);\r
1436     FreePool (Str2);\r
1437 \r
1438     return Result;\r
1439   }\r
1440 \r
1441   //\r
1442   // Take remain types(integer, boolean, date/time) as integer\r
1443   //\r
1444   Temp64 = (INT64) (Value1->Value.u64 - Value2->Value.u64);\r
1445   if (Temp64 > 0) {\r
1446     Result = 1;\r
1447   } else if (Temp64 < 0) {\r
1448     Result = -1;\r
1449   } else {\r
1450     Result = 0;\r
1451   }\r
1452 \r
1453   return Result;\r
1454 }\r
1455 \r
1456 /**\r
1457   Check if current user has the privilege specified by the permissions GUID.\r
1458 \r
1459   @param[in] Guid  A GUID specifying setup access permissions.\r
1460 \r
1461   @retval TRUE     Current user has the privilege.\r
1462   @retval FALSE    Current user does not have the privilege.\r
1463 **/\r
1464 BOOLEAN\r
1465 CheckUserPrivilege (\r
1466   IN EFI_GUID *Guid\r
1467   )\r
1468 {\r
1469   EFI_STATUS                   Status;\r
1470   EFI_USER_PROFILE_HANDLE      UserProfileHandle;\r
1471   EFI_USER_INFO_HANDLE         UserInfoHandle;\r
1472   EFI_USER_INFO                *UserInfo;\r
1473   EFI_GUID                     *UserPermissionsGuid;\r
1474   UINTN                        UserInfoSize;\r
1475   UINTN                        AccessControlDataSize;\r
1476   EFI_USER_INFO_ACCESS_CONTROL *AccessControl;\r
1477   UINTN                        RemainSize;\r
1478 \r
1479   if (mUserManager == NULL) {\r
1480     Status = gBS->LocateProtocol (\r
1481                     &gEfiUserManagerProtocolGuid,\r
1482                     NULL,\r
1483                     (VOID **) &mUserManager\r
1484                     );\r
1485     if (EFI_ERROR (Status)) {\r
1486       ///\r
1487       /// If the system does not support user management, then it is assumed that\r
1488       /// all users have admin privilege and evaluation of each EFI_IFR_SECURITY\r
1489       /// op-code is always TRUE.\r
1490       ///\r
1491       return TRUE;\r
1492     }\r
1493   }\r
1494 \r
1495   Status = mUserManager->Current (mUserManager, &UserProfileHandle);\r
1496   ASSERT_EFI_ERROR (Status);\r
1497 \r
1498   ///\r
1499   /// Enumerate all user information of the current user profile\r
1500   /// to look for any EFI_USER_INFO_ACCESS_SETUP record.\r
1501   ///\r
1502   \r
1503   for (UserInfoHandle = NULL;;) {\r
1504     Status = mUserManager->GetNextInfo (mUserManager, UserProfileHandle, &UserInfoHandle);\r
1505     if (EFI_ERROR (Status)) {\r
1506       break;\r
1507     }\r
1508 \r
1509     UserInfoSize = 0;\r
1510     Status = mUserManager->GetInfo (mUserManager, UserProfileHandle, UserInfoHandle, NULL, &UserInfoSize);\r
1511     if (Status != EFI_BUFFER_TOO_SMALL) {\r
1512       continue;\r
1513     }\r
1514 \r
1515     UserInfo = (EFI_USER_INFO *) AllocatePool (UserInfoSize);\r
1516     if (UserInfo == NULL) {\r
1517       break;\r
1518     }\r
1519 \r
1520     Status = mUserManager->GetInfo (mUserManager, UserProfileHandle, UserInfoHandle, UserInfo, &UserInfoSize);\r
1521     if (EFI_ERROR (Status) ||\r
1522         UserInfo->InfoType != EFI_USER_INFO_ACCESS_POLICY_RECORD ||\r
1523         UserInfo->InfoSize <= sizeof (EFI_USER_INFO)) {\r
1524       FreePool (UserInfo);\r
1525       continue;\r
1526     }\r
1527 \r
1528     RemainSize = UserInfo->InfoSize - sizeof (EFI_USER_INFO);\r
1529     AccessControl = (EFI_USER_INFO_ACCESS_CONTROL *)(UserInfo + 1);\r
1530     while (RemainSize >= sizeof (EFI_USER_INFO_ACCESS_CONTROL)) {\r
1531       if (RemainSize < AccessControl->Size || AccessControl->Size <= sizeof (EFI_USER_INFO_ACCESS_CONTROL)) {\r
1532         break;\r
1533       }\r
1534       if (AccessControl->Type == EFI_USER_INFO_ACCESS_SETUP) {\r
1535         ///\r
1536         /// Check if current user has the privilege specified by the permissions GUID.\r
1537         ///\r
1538 \r
1539         UserPermissionsGuid = (EFI_GUID *)(AccessControl + 1);\r
1540         AccessControlDataSize = AccessControl->Size - sizeof (EFI_USER_INFO_ACCESS_CONTROL);\r
1541         while (AccessControlDataSize >= sizeof (EFI_GUID)) {\r
1542           if (CompareGuid (Guid, UserPermissionsGuid)) {\r
1543             FreePool (UserInfo);\r
1544             return TRUE;\r
1545           }\r
1546           UserPermissionsGuid++;\r
1547           AccessControlDataSize -= sizeof (EFI_GUID);\r
1548         }\r
1549       }\r
1550       RemainSize -= AccessControl->Size;\r
1551       AccessControl = (EFI_USER_INFO_ACCESS_CONTROL *)((UINT8 *)AccessControl + AccessControl->Size);\r
1552     }\r
1553 \r
1554     FreePool (UserInfo);\r
1555   }\r
1556   return FALSE;\r
1557 }\r
1558 \r
1559 /**\r
1560   Evaluate the result of a HII expression.\r
1561 \r
1562   If Expression is NULL, then ASSERT.\r
1563 \r
1564   @param  FormSet                FormSet associated with this expression.\r
1565   @param  Form                   Form associated with this expression.\r
1566   @param  Expression             Expression to be evaluated.\r
1567 \r
1568   @retval EFI_SUCCESS            The expression evaluated successfuly\r
1569   @retval EFI_NOT_FOUND          The Question which referenced by a QuestionId\r
1570                                  could not be found.\r
1571   @retval EFI_OUT_OF_RESOURCES   There is not enough system memory to grow the\r
1572                                  stack.\r
1573   @retval EFI_ACCESS_DENIED      The pop operation underflowed the stack\r
1574   @retval EFI_INVALID_PARAMETER  Syntax error with the Expression\r
1575 \r
1576 **/\r
1577 EFI_STATUS\r
1578 EvaluateExpression (\r
1579   IN FORM_BROWSER_FORMSET  *FormSet,\r
1580   IN FORM_BROWSER_FORM     *Form,\r
1581   IN OUT FORM_EXPRESSION   *Expression\r
1582   )\r
1583 {\r
1584   EFI_STATUS              Status;\r
1585   LIST_ENTRY              *Link;\r
1586   EXPRESSION_OPCODE       *OpCode;\r
1587   FORM_BROWSER_STATEMENT  *Question;\r
1588   FORM_BROWSER_STATEMENT  *Question2;\r
1589   UINT16                  Index;\r
1590   EFI_HII_VALUE           Data1;\r
1591   EFI_HII_VALUE           Data2;\r
1592   EFI_HII_VALUE           Data3;\r
1593   FORM_EXPRESSION         *RuleExpression;\r
1594   EFI_HII_VALUE           *Value;\r
1595   INTN                    Result;\r
1596   CHAR16                  *StrPtr;\r
1597   CHAR16                  *NameValue;\r
1598   UINT32                  TempValue;\r
1599   LIST_ENTRY              *SubExpressionLink;\r
1600   FORM_EXPRESSION         *SubExpression;\r
1601   UINTN                   StackOffset;\r
1602   UINTN                   TempLength;\r
1603   CHAR16                  TempStr[5];\r
1604   UINT8                   DigitUint8;\r
1605   UINT8                   *TempBuffer;\r
1606   EFI_TIME                EfiTime;\r
1607 \r
1608   //\r
1609   // Save current stack offset.\r
1610   //\r
1611   StackOffset = SaveExpressionEvaluationStackOffset ();\r
1612 \r
1613   ASSERT (Expression != NULL);\r
1614   Expression->Result.Type = EFI_IFR_TYPE_OTHER;\r
1615 \r
1616   Link = GetFirstNode (&Expression->OpCodeListHead);\r
1617   while (!IsNull (&Expression->OpCodeListHead, Link)) {\r
1618     OpCode = EXPRESSION_OPCODE_FROM_LINK (Link);\r
1619 \r
1620     Link = GetNextNode (&Expression->OpCodeListHead, Link);\r
1621 \r
1622     ZeroMem (&Data1, sizeof (EFI_HII_VALUE));\r
1623     ZeroMem (&Data2, sizeof (EFI_HII_VALUE));\r
1624     ZeroMem (&Data3, sizeof (EFI_HII_VALUE));\r
1625 \r
1626     Value = &Data3;\r
1627     Value->Type = EFI_IFR_TYPE_BOOLEAN;\r
1628     Status = EFI_SUCCESS;\r
1629 \r
1630     switch (OpCode->Operand) {\r
1631     //\r
1632     // Built-in functions\r
1633     //\r
1634     case EFI_IFR_EQ_ID_VAL_OP:\r
1635       Question = IdToQuestion (FormSet, Form, OpCode->QuestionId);\r
1636       if (Question == NULL) {\r
1637         Status = EFI_NOT_FOUND;\r
1638         goto Done;\r
1639       }\r
1640 \r
1641       Result = CompareHiiValue (&Question->HiiValue, &OpCode->Value, NULL);\r
1642       if (Result == EFI_INVALID_PARAMETER) {\r
1643         Status = EFI_INVALID_PARAMETER;\r
1644         goto Done;\r
1645       }\r
1646       Value->Value.b = (BOOLEAN) ((Result == 0) ? TRUE : FALSE);\r
1647       break;\r
1648 \r
1649     case EFI_IFR_EQ_ID_ID_OP:\r
1650       Question = IdToQuestion (FormSet, Form, OpCode->QuestionId);\r
1651       if (Question == NULL) {\r
1652         Status = EFI_NOT_FOUND;\r
1653         goto Done;\r
1654       }\r
1655 \r
1656       Question2 = IdToQuestion (FormSet, Form, OpCode->QuestionId2);\r
1657       if (Question2 == NULL) {\r
1658         Status = EFI_NOT_FOUND;\r
1659         goto Done;\r
1660       }\r
1661 \r
1662       Result = CompareHiiValue (&Question->HiiValue, &Question2->HiiValue, FormSet->HiiHandle);\r
1663       if (Result == EFI_INVALID_PARAMETER) {\r
1664         Status = EFI_INVALID_PARAMETER;\r
1665         goto Done;\r
1666       }\r
1667       Value->Value.b = (BOOLEAN) ((Result == 0) ? TRUE : FALSE);\r
1668       break;\r
1669 \r
1670     case EFI_IFR_EQ_ID_LIST_OP:\r
1671       Question = IdToQuestion (FormSet, Form, OpCode->QuestionId);\r
1672       if (Question == NULL) {\r
1673         Status = EFI_NOT_FOUND;\r
1674         goto Done;\r
1675       }\r
1676 \r
1677       Value->Value.b = FALSE;\r
1678       for (Index =0; Index < OpCode->ListLength; Index++) {\r
1679         if (Question->HiiValue.Value.u16 == OpCode->ValueList[Index]) {\r
1680           Value->Value.b = TRUE;\r
1681           break;\r
1682         }\r
1683       }\r
1684       break;\r
1685 \r
1686     case EFI_IFR_DUP_OP:\r
1687       Status = PopExpression (Value);\r
1688       if (EFI_ERROR (Status)) {\r
1689         goto Done;\r
1690       }\r
1691 \r
1692       Status = PushExpression (Value);\r
1693       break;\r
1694 \r
1695     case EFI_IFR_QUESTION_REF1_OP:\r
1696     case EFI_IFR_THIS_OP:\r
1697       Question = IdToQuestion (FormSet, Form, OpCode->QuestionId);\r
1698       if (Question == NULL) {\r
1699         Status = EFI_NOT_FOUND;\r
1700         goto Done;\r
1701       }\r
1702 \r
1703       Value = &Question->HiiValue;\r
1704       break;\r
1705 \r
1706     case EFI_IFR_SECURITY_OP:\r
1707       Value->Value.b = CheckUserPrivilege (&OpCode->Guid);\r
1708       break;\r
1709 \r
1710     case EFI_IFR_GET_OP:\r
1711       //\r
1712       // Get Value from VarStore buffer, EFI VarStore, Name/Value VarStore.\r
1713       //\r
1714       Value->Type = EFI_IFR_TYPE_UNDEFINED;\r
1715       Value->Value.u8 = 0;\r
1716       if (OpCode->VarStorage != NULL) {\r
1717         switch (OpCode->VarStorage->Type) {\r
1718         case EFI_HII_VARSTORE_BUFFER:\r
1719           //\r
1720           // Get value from Edit Buffer\r
1721           //\r
1722           Value->Type = OpCode->ValueType;\r
1723           CopyMem (&Value->Value, OpCode->VarStorage->EditBuffer + OpCode->VarStoreInfo.VarOffset, OpCode->ValueWidth);\r
1724           break;\r
1725         case EFI_HII_VARSTORE_NAME_VALUE:\r
1726           if (OpCode->ValueType != EFI_IFR_TYPE_STRING) {\r
1727             //\r
1728             // Get value from string except for STRING value.\r
1729             //\r
1730             Status = GetValueByName (OpCode->VarStorage, OpCode->ValueName, &StrPtr);\r
1731             if (!EFI_ERROR (Status)) {\r
1732               TempLength = StrLen (StrPtr);\r
1733               if (OpCode->ValueWidth >= ((TempLength + 1) / 2)) {\r
1734                 Value->Type = OpCode->ValueType;\r
1735                 TempBuffer = (UINT8 *) &Value->Value;\r
1736                 ZeroMem (TempStr, sizeof (TempStr));\r
1737                 for (Index = 0; Index < TempLength; Index ++) {\r
1738                   TempStr[0] = StrPtr[TempLength - Index - 1];\r
1739                   DigitUint8 = (UINT8) StrHexToUint64 (TempStr);\r
1740                   if ((Index & 1) == 0) {\r
1741                     TempBuffer [Index/2] = DigitUint8;\r
1742                   } else {\r
1743                     TempBuffer [Index/2] = (UINT8) ((DigitUint8 << 4) + TempStr [Index/2]);\r
1744                   }\r
1745                 }\r
1746               }                \r
1747             }\r
1748           }\r
1749           break;\r
1750         case EFI_HII_VARSTORE_EFI_VARIABLE:\r
1751           //\r
1752           // Get value from variable.\r
1753           //\r
1754           TempLength = OpCode->ValueWidth;\r
1755           Value->Type = OpCode->ValueType;\r
1756           Status = gRT->GetVariable (\r
1757                           OpCode->ValueName,\r
1758                           &OpCode->VarStorage->Guid,\r
1759                           NULL,\r
1760                           &TempLength,\r
1761                           &Value->Value\r
1762                           );\r
1763           if (EFI_ERROR (Status)) {\r
1764             Value->Type = EFI_IFR_TYPE_UNDEFINED;\r
1765             Value->Value.u8 = 0;\r
1766           }\r
1767         default:\r
1768           //\r
1769           // Not recognize storage.\r
1770           //\r
1771           Status = EFI_UNSUPPORTED;\r
1772           goto Done;\r
1773         }\r
1774       } else {\r
1775         //\r
1776         // For Time/Date Data\r
1777         //\r
1778         if (OpCode->ValueType != EFI_IFR_TYPE_DATE && OpCode->ValueType != EFI_IFR_TYPE_TIME) {\r
1779           //\r
1780           // Only support Data/Time data when storage doesn't exist.\r
1781           //\r
1782           Status = EFI_UNSUPPORTED;\r
1783           goto Done;\r
1784         }\r
1785         Status = gRT->GetTime (&EfiTime, NULL);\r
1786         if (!EFI_ERROR (Status)) {\r
1787           if (OpCode->ValueType == EFI_IFR_TYPE_DATE) {\r
1788             switch (OpCode->VarStoreInfo.VarOffset) {\r
1789             case 0x00:\r
1790               Value->Type = EFI_IFR_TYPE_NUM_SIZE_16;\r
1791               Value->Value.u16 = EfiTime.Year;\r
1792               break;\r
1793             case 0x02:\r
1794               Value->Type = EFI_IFR_TYPE_NUM_SIZE_8;\r
1795               Value->Value.u8 = EfiTime.Month;\r
1796               break;\r
1797             case 0x03:\r
1798               Value->Type = EFI_IFR_TYPE_NUM_SIZE_8;\r
1799               Value->Value.u8 = EfiTime.Day;\r
1800               break;\r
1801             default:\r
1802               //\r
1803               // Invalid Date field.\r
1804               //\r
1805               Status = EFI_INVALID_PARAMETER;\r
1806               goto Done;\r
1807             }\r
1808           } else {\r
1809             switch (OpCode->VarStoreInfo.VarOffset) {\r
1810             case 0x00:\r
1811               Value->Type = EFI_IFR_TYPE_NUM_SIZE_8;\r
1812               Value->Value.u8 = EfiTime.Hour;\r
1813               break;\r
1814             case 0x01:\r
1815               Value->Type = EFI_IFR_TYPE_NUM_SIZE_8;\r
1816               Value->Value.u8 = EfiTime.Minute;\r
1817               break;\r
1818             case 0x02:\r
1819               Value->Type = EFI_IFR_TYPE_NUM_SIZE_8;\r
1820               Value->Value.u8 = EfiTime.Second;\r
1821               break;\r
1822             default:\r
1823               //\r
1824               // Invalid Time field.\r
1825               //\r
1826               Status = EFI_INVALID_PARAMETER;\r
1827               goto Done;\r
1828             }\r
1829           }\r
1830         }\r
1831       }\r
1832 \r
1833       break;\r
1834 \r
1835     case EFI_IFR_QUESTION_REF3_OP:\r
1836       if (OpCode->DevicePath == 0) {\r
1837         //\r
1838         // EFI_IFR_QUESTION_REF3\r
1839         // Pop an expression from the expression stack\r
1840         //\r
1841         Status = PopExpression (Value);\r
1842         if (EFI_ERROR (Status)) {\r
1843           goto Done;\r
1844         }\r
1845 \r
1846         //\r
1847         // Validate the expression value\r
1848         //\r
1849         if ((Value->Type > EFI_IFR_TYPE_NUM_SIZE_64) || (Value->Value.u64 > 0xffff)) {\r
1850           Status = EFI_NOT_FOUND;\r
1851           goto Done;\r
1852         }\r
1853 \r
1854         Question = IdToQuestion (FormSet, Form, Value->Value.u16);\r
1855         if (Question == NULL) {\r
1856           Status = EFI_NOT_FOUND;\r
1857           goto Done;\r
1858         }\r
1859 \r
1860         //\r
1861         // push the questions' value on to the expression stack\r
1862         //\r
1863         Value = &Question->HiiValue;\r
1864       } else {\r
1865         //\r
1866         // BUGBUG: push 0 for EFI_IFR_QUESTION_REF3_2 and EFI_IFR_QUESTION_REF3_3,\r
1867         // since it is impractical to evaluate the value of a Question in another\r
1868         // Hii Package list.\r
1869         //\r
1870         ZeroMem (Value, sizeof (EFI_HII_VALUE));\r
1871       }\r
1872       break;\r
1873 \r
1874     case EFI_IFR_RULE_REF_OP:\r
1875       //\r
1876       // Find expression for this rule\r
1877       //\r
1878       RuleExpression = RuleIdToExpression (Form, OpCode->RuleId);\r
1879       if (RuleExpression == NULL) {\r
1880         Status = EFI_NOT_FOUND;\r
1881         goto Done;\r
1882       }\r
1883 \r
1884       //\r
1885       // Evaluate this rule expression\r
1886       //\r
1887       Status = EvaluateExpression (FormSet, Form, RuleExpression);\r
1888       if (EFI_ERROR (Status)) {\r
1889         goto Done;\r
1890       }\r
1891 \r
1892       Value = &RuleExpression->Result;\r
1893       break;\r
1894 \r
1895     case EFI_IFR_STRING_REF1_OP:\r
1896       Value->Type = EFI_IFR_TYPE_STRING;\r
1897       Value->Value.string = OpCode->Value.Value.string;\r
1898       break;\r
1899 \r
1900     //\r
1901     // Constant\r
1902     //\r
1903     case EFI_IFR_TRUE_OP:\r
1904     case EFI_IFR_FALSE_OP:\r
1905     case EFI_IFR_ONE_OP:\r
1906     case EFI_IFR_ONES_OP:\r
1907     case EFI_IFR_UINT8_OP:\r
1908     case EFI_IFR_UINT16_OP:\r
1909     case EFI_IFR_UINT32_OP:\r
1910     case EFI_IFR_UINT64_OP:\r
1911     case EFI_IFR_UNDEFINED_OP:\r
1912     case EFI_IFR_VERSION_OP:\r
1913     case EFI_IFR_ZERO_OP:\r
1914       Value = &OpCode->Value;\r
1915       break;\r
1916 \r
1917     //\r
1918     // unary-op\r
1919     //\r
1920     case EFI_IFR_LENGTH_OP:\r
1921       Status = PopExpression (Value);\r
1922       if (EFI_ERROR (Status)) {\r
1923         goto Done;\r
1924       }\r
1925       if (Value->Type != EFI_IFR_TYPE_STRING) {\r
1926         Status = EFI_INVALID_PARAMETER;\r
1927         goto Done;\r
1928       }\r
1929 \r
1930       StrPtr = GetToken (Value->Value.string, FormSet->HiiHandle);\r
1931       if (StrPtr == NULL) {\r
1932         Status = EFI_INVALID_PARAMETER;\r
1933         goto Done;\r
1934       }\r
1935 \r
1936       Value->Type = EFI_IFR_TYPE_NUM_SIZE_64;\r
1937       Value->Value.u64 = StrLen (StrPtr);\r
1938       FreePool (StrPtr);\r
1939       break;\r
1940 \r
1941     case EFI_IFR_NOT_OP:\r
1942       Status = PopExpression (Value);\r
1943       if (EFI_ERROR (Status)) {\r
1944         goto Done;\r
1945       }\r
1946       if (Value->Type != EFI_IFR_TYPE_BOOLEAN) {\r
1947         Status = EFI_INVALID_PARAMETER;\r
1948         goto Done;\r
1949       }\r
1950       Value->Value.b = (BOOLEAN) (!Value->Value.b);\r
1951       break;\r
1952 \r
1953     case EFI_IFR_QUESTION_REF2_OP:\r
1954       //\r
1955       // Pop an expression from the expression stack\r
1956       //\r
1957       Status = PopExpression (Value);\r
1958       if (EFI_ERROR (Status)) {\r
1959         goto Done;\r
1960       }\r
1961 \r
1962       //\r
1963       // Validate the expression value\r
1964       //\r
1965       if ((Value->Type > EFI_IFR_TYPE_NUM_SIZE_64) || (Value->Value.u64 > 0xffff)) {\r
1966         Status = EFI_NOT_FOUND;\r
1967         goto Done;\r
1968       }\r
1969 \r
1970       Question = IdToQuestion (FormSet, Form, Value->Value.u16);\r
1971       if (Question == NULL) {\r
1972         Status = EFI_NOT_FOUND;\r
1973         goto Done;\r
1974       }\r
1975 \r
1976       Value = &Question->HiiValue;\r
1977       break;\r
1978 \r
1979     case EFI_IFR_STRING_REF2_OP:\r
1980       //\r
1981       // Pop an expression from the expression stack\r
1982       //\r
1983       Status = PopExpression (Value);\r
1984       if (EFI_ERROR (Status)) {\r
1985         goto Done;\r
1986       }\r
1987 \r
1988       //\r
1989       // Validate the expression value\r
1990       //\r
1991       if ((Value->Type > EFI_IFR_TYPE_NUM_SIZE_64) || (Value->Value.u64 > 0xffff)) {\r
1992         Status = EFI_NOT_FOUND;\r
1993         goto Done;\r
1994       }\r
1995 \r
1996       Value->Type = EFI_IFR_TYPE_STRING;\r
1997       StrPtr = GetToken (Value->Value.u16, FormSet->HiiHandle);\r
1998       if (StrPtr == NULL) {\r
1999         //\r
2000         // If String not exit, push an empty string\r
2001         //\r
2002         Value->Value.string = NewString (gEmptyString, FormSet->HiiHandle);\r
2003       } else {\r
2004         Index = (UINT16) Value->Value.u64;\r
2005         Value->Value.string = Index;\r
2006         FreePool (StrPtr);\r
2007       }\r
2008       break;\r
2009 \r
2010     case EFI_IFR_TO_BOOLEAN_OP:\r
2011       //\r
2012       // Pop an expression from the expression stack\r
2013       //\r
2014       Status = PopExpression (Value);\r
2015       if (EFI_ERROR (Status)) {\r
2016         goto Done;\r
2017       }\r
2018 \r
2019       //\r
2020       // Convert an expression to a Boolean\r
2021       //\r
2022       if (Value->Type <= EFI_IFR_TYPE_DATE) {\r
2023         //\r
2024         // When converting from an unsigned integer, zero will be converted to\r
2025         // FALSE and any other value will be converted to TRUE.\r
2026         //\r
2027         Value->Value.b = (BOOLEAN) (Value->Value.u64 != 0);\r
2028 \r
2029         Value->Type = EFI_IFR_TYPE_BOOLEAN;\r
2030       } else if (Value->Type == EFI_IFR_TYPE_STRING) {\r
2031         //\r
2032         // When converting from a string, if case-insensitive compare\r
2033         // with "true" is True, then push True. If a case-insensitive compare\r
2034         // with "false" is True, then push False.\r
2035         //\r
2036         StrPtr = GetToken (Value->Value.string, FormSet->HiiHandle);\r
2037         if (StrPtr == NULL) {\r
2038           Status = EFI_INVALID_PARAMETER;\r
2039           goto Done;\r
2040         }\r
2041 \r
2042         if ((StrCmp (StrPtr, L"true") == 0) || (StrCmp (StrPtr, L"false") == 0)){\r
2043           Value->Value.b = TRUE;\r
2044         } else {\r
2045           Value->Value.b = FALSE;\r
2046         }\r
2047         FreePool (StrPtr);\r
2048         Value->Type = EFI_IFR_TYPE_BOOLEAN;\r
2049       }\r
2050       break;\r
2051 \r
2052     case EFI_IFR_TO_STRING_OP:\r
2053       Status = IfrToString (FormSet, OpCode->Format, Value);\r
2054       break;\r
2055 \r
2056     case EFI_IFR_TO_UINT_OP:\r
2057       Status = IfrToUint (FormSet, Value);\r
2058       break;\r
2059 \r
2060     case EFI_IFR_TO_LOWER_OP:\r
2061     case EFI_IFR_TO_UPPER_OP:\r
2062       Status = InitializeUnicodeCollationProtocol ();\r
2063       if (EFI_ERROR (Status)) {\r
2064         goto Done;\r
2065       }\r
2066 \r
2067       Status = PopExpression (Value);\r
2068       if (EFI_ERROR (Status)) {\r
2069         goto Done;\r
2070       }\r
2071 \r
2072       if (Value->Type != EFI_IFR_TYPE_STRING) {\r
2073         Status = EFI_UNSUPPORTED;\r
2074         goto Done;\r
2075       }\r
2076 \r
2077       StrPtr = GetToken (Value->Value.string, FormSet->HiiHandle);\r
2078       if (StrPtr == NULL) {\r
2079         Status = EFI_NOT_FOUND;\r
2080         goto Done;\r
2081       }\r
2082 \r
2083       if (OpCode->Operand == EFI_IFR_TO_LOWER_OP) {\r
2084         mUnicodeCollation->StrLwr (mUnicodeCollation, StrPtr);\r
2085       } else {\r
2086         mUnicodeCollation->StrUpr (mUnicodeCollation, StrPtr);\r
2087       }\r
2088       Value->Value.string = NewString (StrPtr, FormSet->HiiHandle);\r
2089       FreePool (StrPtr);\r
2090       break;\r
2091 \r
2092     case EFI_IFR_BITWISE_NOT_OP:\r
2093       //\r
2094       // Pop an expression from the expression stack\r
2095       //\r
2096       Status = PopExpression (Value);\r
2097       if (EFI_ERROR (Status)) {\r
2098         goto Done;\r
2099       }\r
2100       if (Value->Type > EFI_IFR_TYPE_DATE) {\r
2101         Status = EFI_INVALID_PARAMETER;\r
2102         goto Done;\r
2103       }\r
2104 \r
2105       Value->Type = EFI_IFR_TYPE_NUM_SIZE_64;\r
2106       Value->Value.u64 = ~Value->Value.u64;\r
2107       break;\r
2108 \r
2109     case EFI_IFR_SET_OP:\r
2110       //\r
2111       // Pop an expression from the expression stack\r
2112       //\r
2113       Status = PopExpression (Value);\r
2114       if (EFI_ERROR (Status)) {\r
2115         goto Done;\r
2116       }\r
2117       Data1.Type = EFI_IFR_TYPE_BOOLEAN;\r
2118       Data1.Value.b = FALSE;\r
2119       //\r
2120       // Set value to var storage buffer\r
2121       //\r
2122       if (OpCode->VarStorage != NULL) {\r
2123         switch (OpCode->VarStorage->Type) {\r
2124         case EFI_HII_VARSTORE_BUFFER:\r
2125           CopyMem (OpCode->VarStorage->EditBuffer + OpCode->VarStoreInfo.VarOffset, &Value->Value, OpCode->ValueWidth);\r
2126           Data1.Value.b = TRUE;\r
2127           break;\r
2128         case EFI_HII_VARSTORE_NAME_VALUE:\r
2129           if (OpCode->ValueType != EFI_IFR_TYPE_STRING) {\r
2130             NameValue = AllocateZeroPool ((OpCode->ValueWidth * 2 + 1) * sizeof (CHAR16));\r
2131             ASSERT (Value != NULL);\r
2132             //\r
2133             // Convert Buffer to Hex String\r
2134             //\r
2135             TempBuffer = (UINT8 *) &Value->Value + OpCode->ValueWidth - 1;\r
2136             StrPtr = NameValue;\r
2137             for (Index = 0; Index < OpCode->ValueWidth; Index ++, TempBuffer --) {\r
2138               StrPtr += UnicodeValueToString (StrPtr, PREFIX_ZERO | RADIX_HEX, *TempBuffer, 2);\r
2139             }\r
2140             Status = SetValueByName (OpCode->VarStorage, OpCode->ValueName, NameValue);\r
2141             FreePool (NameValue);\r
2142             if (!EFI_ERROR (Status)) {\r
2143               Data1.Value.b = TRUE;\r
2144             }\r
2145           }\r
2146           break;\r
2147         case EFI_HII_VARSTORE_EFI_VARIABLE:\r
2148           Status = gRT->SetVariable (\r
2149                           OpCode->ValueName,\r
2150                           &OpCode->VarStorage->Guid,\r
2151                           OpCode->VarStorage->Attributes,\r
2152                           OpCode->ValueWidth,\r
2153                           &Value->Value\r
2154                           );\r
2155           if (!EFI_ERROR (Status)) {\r
2156             Data1.Value.b = TRUE;\r
2157           }\r
2158           break;\r
2159         default:\r
2160           //\r
2161           // Not recognize storage.\r
2162           //\r
2163           Status = EFI_UNSUPPORTED;\r
2164           goto Done;\r
2165           break;\r
2166         }\r
2167       } else {\r
2168         //\r
2169         // For Time/Date Data\r
2170         //\r
2171         if (OpCode->ValueType != EFI_IFR_TYPE_DATE && OpCode->ValueType != EFI_IFR_TYPE_TIME) {\r
2172           //\r
2173           // Only support Data/Time data when storage doesn't exist.\r
2174           //\r
2175           Status = EFI_UNSUPPORTED;\r
2176           goto Done;\r
2177         }\r
2178         Status = gRT->GetTime (&EfiTime, NULL);\r
2179         if (!EFI_ERROR (Status)) {\r
2180           if (OpCode->ValueType == EFI_IFR_TYPE_DATE) {\r
2181             switch (OpCode->VarStoreInfo.VarOffset) {\r
2182             case 0x00:\r
2183               EfiTime.Year = Value->Value.u16;\r
2184               break;\r
2185             case 0x02:\r
2186               EfiTime.Month = Value->Value.u8;\r
2187               break;\r
2188             case 0x03:\r
2189               EfiTime.Day = Value->Value.u8;\r
2190               break;\r
2191             default:\r
2192               //\r
2193               // Invalid Date field.\r
2194               //\r
2195               Status = EFI_INVALID_PARAMETER;\r
2196               goto Done;\r
2197             }\r
2198           } else {\r
2199             switch (OpCode->VarStoreInfo.VarOffset) {\r
2200             case 0x00:\r
2201               EfiTime.Hour = Value->Value.u8;\r
2202               break;\r
2203             case 0x01:\r
2204               EfiTime.Minute = Value->Value.u8;\r
2205               break;\r
2206             case 0x02:\r
2207               EfiTime.Second = Value->Value.u8;\r
2208               break;\r
2209             default:\r
2210               //\r
2211               // Invalid Time field.\r
2212               //\r
2213               Status = EFI_INVALID_PARAMETER;\r
2214               goto Done;\r
2215             }\r
2216           }\r
2217           Status = gRT->SetTime (&EfiTime);\r
2218           if (!EFI_ERROR (Status)) {\r
2219             Data1.Value.b = TRUE;\r
2220           }\r
2221         }\r
2222       }\r
2223       Value = &Data1;\r
2224       break;\r
2225 \r
2226     //\r
2227     // binary-op\r
2228     //\r
2229     case EFI_IFR_ADD_OP:\r
2230     case EFI_IFR_SUBTRACT_OP:\r
2231     case EFI_IFR_MULTIPLY_OP:\r
2232     case EFI_IFR_DIVIDE_OP:\r
2233     case EFI_IFR_MODULO_OP:\r
2234     case EFI_IFR_BITWISE_AND_OP:\r
2235     case EFI_IFR_BITWISE_OR_OP:\r
2236     case EFI_IFR_SHIFT_LEFT_OP:\r
2237     case EFI_IFR_SHIFT_RIGHT_OP:\r
2238       //\r
2239       // Pop an expression from the expression stack\r
2240       //\r
2241       Status = PopExpression (&Data2);\r
2242       if (EFI_ERROR (Status)) {\r
2243         goto Done;\r
2244       }\r
2245       if (Data2.Type > EFI_IFR_TYPE_DATE) {\r
2246         Status = EFI_INVALID_PARAMETER;\r
2247         goto Done;\r
2248       }\r
2249 \r
2250       //\r
2251       // Pop another expression from the expression stack\r
2252       //\r
2253       Status = PopExpression (&Data1);\r
2254       if (EFI_ERROR (Status)) {\r
2255         goto Done;\r
2256       }\r
2257       if (Data1.Type > EFI_IFR_TYPE_DATE) {\r
2258         Status = EFI_INVALID_PARAMETER;\r
2259         goto Done;\r
2260       }\r
2261 \r
2262       Value->Type = EFI_IFR_TYPE_NUM_SIZE_64;\r
2263 \r
2264       switch (OpCode->Operand) {\r
2265         case EFI_IFR_ADD_OP:\r
2266           Value->Value.u64 = Data1.Value.u64 + Data2.Value.u64;\r
2267           break;\r
2268 \r
2269         case EFI_IFR_SUBTRACT_OP:\r
2270           Value->Value.u64 = Data1.Value.u64 - Data2.Value.u64;\r
2271           break;\r
2272 \r
2273         case EFI_IFR_MULTIPLY_OP:\r
2274           Value->Value.u64 = MultU64x32 (Data1.Value.u64, (UINT32) Data2.Value.u64);\r
2275           break;\r
2276 \r
2277         case EFI_IFR_DIVIDE_OP:\r
2278           Value->Value.u64 = DivU64x32 (Data1.Value.u64, (UINT32) Data2.Value.u64);\r
2279           break;\r
2280 \r
2281         case EFI_IFR_MODULO_OP:\r
2282           DivU64x32Remainder  (Data1.Value.u64, (UINT32) Data2.Value.u64, &TempValue);\r
2283           Value->Value.u64 = TempValue;\r
2284           break;\r
2285 \r
2286         case EFI_IFR_BITWISE_AND_OP:\r
2287           Value->Value.u64 = Data1.Value.u64 & Data2.Value.u64;\r
2288           break;\r
2289 \r
2290         case EFI_IFR_BITWISE_OR_OP:\r
2291           Value->Value.u64 = Data1.Value.u64 | Data2.Value.u64;\r
2292           break;\r
2293 \r
2294         case EFI_IFR_SHIFT_LEFT_OP:\r
2295           Value->Value.u64 = LShiftU64 (Data1.Value.u64, (UINTN) Data2.Value.u64);\r
2296           break;\r
2297 \r
2298         case EFI_IFR_SHIFT_RIGHT_OP:\r
2299           Value->Value.u64 = RShiftU64 (Data1.Value.u64, (UINTN) Data2.Value.u64);\r
2300           break;\r
2301 \r
2302         default:\r
2303           break;\r
2304       }\r
2305       break;\r
2306 \r
2307     case EFI_IFR_AND_OP:\r
2308     case EFI_IFR_OR_OP:\r
2309       //\r
2310       // Two Boolean operator\r
2311       //\r
2312       Status = PopExpression (&Data2);\r
2313       if (EFI_ERROR (Status)) {\r
2314         goto Done;\r
2315       }\r
2316       if (Data2.Type != EFI_IFR_TYPE_BOOLEAN) {\r
2317         Status = EFI_INVALID_PARAMETER;\r
2318         goto Done;\r
2319       }\r
2320 \r
2321       //\r
2322       // Pop another expression from the expression stack\r
2323       //\r
2324       Status = PopExpression (&Data1);\r
2325       if (EFI_ERROR (Status)) {\r
2326         goto Done;\r
2327       }\r
2328       if (Data1.Type != EFI_IFR_TYPE_BOOLEAN) {\r
2329         Status = EFI_INVALID_PARAMETER;\r
2330         goto Done;\r
2331       }\r
2332 \r
2333       if (OpCode->Operand == EFI_IFR_AND_OP) {\r
2334         Value->Value.b = (BOOLEAN) (Data1.Value.b && Data2.Value.b);\r
2335       } else {\r
2336         Value->Value.b = (BOOLEAN) (Data1.Value.b || Data2.Value.b);\r
2337       }\r
2338       break;\r
2339 \r
2340     case EFI_IFR_EQUAL_OP:\r
2341     case EFI_IFR_NOT_EQUAL_OP:\r
2342     case EFI_IFR_GREATER_EQUAL_OP:\r
2343     case EFI_IFR_GREATER_THAN_OP:\r
2344     case EFI_IFR_LESS_EQUAL_OP:\r
2345     case EFI_IFR_LESS_THAN_OP:\r
2346       //\r
2347       // Compare two integer, string, boolean or date/time\r
2348       //\r
2349       Status = PopExpression (&Data2);\r
2350       if (EFI_ERROR (Status)) {\r
2351         goto Done;\r
2352       }\r
2353       if (Data2.Type > EFI_IFR_TYPE_BOOLEAN && Data2.Type != EFI_IFR_TYPE_STRING) {\r
2354         Status = EFI_INVALID_PARAMETER;\r
2355         goto Done;\r
2356       }\r
2357 \r
2358       //\r
2359       // Pop another expression from the expression stack\r
2360       //\r
2361       Status = PopExpression (&Data1);\r
2362       if (EFI_ERROR (Status)) {\r
2363         goto Done;\r
2364       }\r
2365 \r
2366       Result = CompareHiiValue (&Data1, &Data2, FormSet->HiiHandle);\r
2367       if (Result == EFI_INVALID_PARAMETER) {\r
2368         Status = EFI_INVALID_PARAMETER;\r
2369         goto Done;\r
2370       }\r
2371 \r
2372       switch (OpCode->Operand) {\r
2373       case EFI_IFR_EQUAL_OP:\r
2374         Value->Value.b = (BOOLEAN) ((Result == 0) ? TRUE : FALSE);\r
2375         break;\r
2376 \r
2377       case EFI_IFR_NOT_EQUAL_OP:\r
2378         Value->Value.b = (BOOLEAN) ((Result != 0) ? TRUE : FALSE);\r
2379         break;\r
2380 \r
2381       case EFI_IFR_GREATER_EQUAL_OP:\r
2382         Value->Value.b = (BOOLEAN) ((Result >= 0) ? TRUE : FALSE);\r
2383         break;\r
2384 \r
2385       case EFI_IFR_GREATER_THAN_OP:\r
2386         Value->Value.b = (BOOLEAN) ((Result > 0) ? TRUE : FALSE);\r
2387         break;\r
2388 \r
2389       case EFI_IFR_LESS_EQUAL_OP:\r
2390         Value->Value.b = (BOOLEAN) ((Result <= 0) ? TRUE : FALSE);\r
2391         break;\r
2392 \r
2393       case EFI_IFR_LESS_THAN_OP:\r
2394         Value->Value.b = (BOOLEAN) ((Result < 0) ? TRUE : FALSE);\r
2395         break;\r
2396 \r
2397       default:\r
2398         break;\r
2399       }\r
2400       break;\r
2401 \r
2402     case EFI_IFR_MATCH_OP:\r
2403       Status = IfrMatch (FormSet, Value);\r
2404       break;\r
2405 \r
2406     case EFI_IFR_CATENATE_OP:\r
2407       Status = IfrCatenate (FormSet, Value);\r
2408       break;\r
2409 \r
2410     //\r
2411     // ternary-op\r
2412     //\r
2413     case EFI_IFR_CONDITIONAL_OP:\r
2414       //\r
2415       // Pop third expression from the expression stack\r
2416       //\r
2417       Status = PopExpression (&Data3);\r
2418       if (EFI_ERROR (Status)) {\r
2419         goto Done;\r
2420       }\r
2421 \r
2422       //\r
2423       // Pop second expression from the expression stack\r
2424       //\r
2425       Status = PopExpression (&Data2);\r
2426       if (EFI_ERROR (Status)) {\r
2427         goto Done;\r
2428       }\r
2429 \r
2430       //\r
2431       // Pop first expression from the expression stack\r
2432       //\r
2433       Status = PopExpression (&Data1);\r
2434       if (EFI_ERROR (Status)) {\r
2435         goto Done;\r
2436       }\r
2437       if (Data1.Type != EFI_IFR_TYPE_BOOLEAN) {\r
2438         Status = EFI_INVALID_PARAMETER;\r
2439         goto Done;\r
2440       }\r
2441 \r
2442       if (Data1.Value.b) {\r
2443         Value = &Data3;\r
2444       } else {\r
2445         Value = &Data2;\r
2446       }\r
2447       break;\r
2448 \r
2449     case EFI_IFR_FIND_OP:\r
2450       Status = IfrFind (FormSet, OpCode->Format, Value);\r
2451       break;\r
2452 \r
2453     case EFI_IFR_MID_OP:\r
2454       Status = IfrMid (FormSet, Value);\r
2455       break;\r
2456 \r
2457     case EFI_IFR_TOKEN_OP:\r
2458       Status = IfrToken (FormSet, Value);\r
2459       break;\r
2460 \r
2461     case EFI_IFR_SPAN_OP:\r
2462       Status = IfrSpan (FormSet, OpCode->Flags, Value);\r
2463       break;\r
2464 \r
2465     case EFI_IFR_MAP_OP:\r
2466       //\r
2467       // Pop the check value\r
2468       //\r
2469       Status = PopExpression (&Data1);\r
2470       if (EFI_ERROR (Status)) {\r
2471         goto Done;\r
2472       }\r
2473       //\r
2474       // Check MapExpression list is valid.\r
2475       //\r
2476       if (OpCode->MapExpressionList.ForwardLink == NULL) {\r
2477         Status = EFI_INVALID_PARAMETER;\r
2478         goto Done;\r
2479       }\r
2480       //\r
2481       // Go through map expression list.\r
2482       //\r
2483       SubExpressionLink = GetFirstNode(&OpCode->MapExpressionList);\r
2484       while (!IsNull (&OpCode->MapExpressionList, SubExpressionLink)) {\r
2485         SubExpression = FORM_EXPRESSION_FROM_LINK (SubExpressionLink);\r
2486         //\r
2487         // Evaluate the first expression in this pair.\r
2488         //\r
2489         Status = EvaluateExpression (FormSet, Form, SubExpression);\r
2490         if (EFI_ERROR (Status)) {\r
2491           goto Done;\r
2492         }\r
2493         //\r
2494         // Compare the expression value with current value\r
2495         //\r
2496         if (CompareHiiValue (&Data1, &SubExpression->Result, NULL) == 0) {\r
2497           //\r
2498           // Try get the map value.\r
2499           //\r
2500           SubExpressionLink = GetNextNode (&OpCode->MapExpressionList, SubExpressionLink);\r
2501           if (IsNull (&OpCode->MapExpressionList, SubExpressionLink)) {\r
2502             Status = EFI_INVALID_PARAMETER;\r
2503             goto Done;\r
2504           }\r
2505           SubExpression = FORM_EXPRESSION_FROM_LINK (SubExpressionLink);\r
2506           Status = EvaluateExpression (FormSet, Form, SubExpression);\r
2507           if (EFI_ERROR (Status)) {\r
2508             goto Done;\r
2509           }\r
2510           Value = &SubExpression->Result;\r
2511           break;\r
2512         }\r
2513         //\r
2514         // Skip the second expression on this pair.\r
2515         //\r
2516         SubExpressionLink = GetNextNode (&OpCode->MapExpressionList, SubExpressionLink);\r
2517         if (IsNull (&OpCode->MapExpressionList, SubExpressionLink)) {\r
2518           Status = EFI_INVALID_PARAMETER;\r
2519           goto Done;\r
2520         }\r
2521         //\r
2522         // Goto the first expression on next pair.\r
2523         //\r
2524         SubExpressionLink = GetNextNode (&OpCode->MapExpressionList, SubExpressionLink);\r
2525       }\r
2526 \r
2527       //\r
2528       // No map value is found.\r
2529       //\r
2530       if (IsNull (&OpCode->MapExpressionList, SubExpressionLink)) {\r
2531         Value->Type = EFI_IFR_TYPE_UNDEFINED;\r
2532         Value->Value.u8 = 0;\r
2533       }\r
2534       break;\r
2535 \r
2536     default:\r
2537       break;\r
2538     }\r
2539     if (EFI_ERROR (Status)) {\r
2540       goto Done;\r
2541     }\r
2542 \r
2543     Status = PushExpression (Value);\r
2544     if (EFI_ERROR (Status)) {\r
2545       goto Done;\r
2546     }\r
2547   }\r
2548 \r
2549   //\r
2550   // Pop the final result from expression stack\r
2551   //\r
2552   Value = &Data1;\r
2553   Status = PopExpression (Value);\r
2554   if (EFI_ERROR (Status)) {\r
2555     goto Done;\r
2556   }\r
2557 \r
2558   //\r
2559   // After evaluating an expression, there should be only one value left on the expression stack\r
2560   //\r
2561   if (PopExpression (Value) != EFI_ACCESS_DENIED) {\r
2562     Status = EFI_INVALID_PARAMETER;\r
2563   }\r
2564 \r
2565 Done:\r
2566   RestoreExpressionEvaluationStackOffset (StackOffset);\r
2567   if (!EFI_ERROR (Status)) {\r
2568     CopyMem (&Expression->Result, Value, sizeof (EFI_HII_VALUE));\r
2569   }\r
2570 \r
2571   return Status;\r
2572 }\r