1 /** @file
2 Implementation for handling the User Interface option processing.
3 
4 
5 Copyright (c) 2004 - 2015, Intel Corporation. All rights reserved.<BR>
6 This program and the accompanying materials
7 are licensed and made available under the terms and conditions of the BSD License
8 which accompanies this distribution.  The full text of the license may be found at
9 http://opensource.org/licenses/bsd-license.php
10 
11 THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
12 WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
13 
14 **/
15 
16 #include "FormDisplay.h"
17 
18 #define MAX_TIME_OUT_LEN  0x10
19 
20 /**
21   Concatenate a narrow string to another string.
22 
23   @param Destination The destination string.
24   @param DestMax     The Max length of destination string.
25   @param Source      The source string. The string to be concatenated.
26                      to the end of Destination.
27 
28 **/
29 VOID
NewStrCat(IN OUT CHAR16 * Destination,IN UINTN DestMax,IN CHAR16 * Source)30 NewStrCat (
31   IN OUT CHAR16               *Destination,
32   IN     UINTN                DestMax,
33   IN     CHAR16               *Source
34   )
35 {
36   UINTN Length;
37 
38   for (Length = 0; Destination[Length] != 0; Length++)
39     ;
40 
41   //
42   // We now have the length of the original string
43   // We can safely assume for now that we are concatenating a narrow value to this string.
44   // For instance, the string is "XYZ" and cat'ing ">"
45   // If this assumption changes, we need to make this routine a bit more complex
46   //
47   Destination[Length] = NARROW_CHAR;
48   Length++;
49 
50   StrCpyS (Destination + Length, DestMax - Length, Source);
51 }
52 
53 /**
54   Get UINT64 type value.
55 
56   @param  Value                  Input Hii value.
57 
58   @retval UINT64                 Return the UINT64 type value.
59 
60 **/
61 UINT64
HiiValueToUINT64(IN EFI_HII_VALUE * Value)62 HiiValueToUINT64 (
63   IN EFI_HII_VALUE      *Value
64   )
65 {
66   UINT64  RetVal;
67 
68   RetVal = 0;
69 
70   switch (Value->Type) {
71   case EFI_IFR_TYPE_NUM_SIZE_8:
72     RetVal = Value->Value.u8;
73     break;
74 
75   case EFI_IFR_TYPE_NUM_SIZE_16:
76     RetVal = Value->Value.u16;
77     break;
78 
79   case EFI_IFR_TYPE_NUM_SIZE_32:
80     RetVal = Value->Value.u32;
81     break;
82 
83   case EFI_IFR_TYPE_BOOLEAN:
84     RetVal = Value->Value.b;
85     break;
86 
87   case EFI_IFR_TYPE_DATE:
88     RetVal = *(UINT64*) &Value->Value.date;
89     break;
90 
91   case EFI_IFR_TYPE_TIME:
92     RetVal = (*(UINT64*) &Value->Value.time) & 0xffffff;
93     break;
94 
95   default:
96     RetVal = Value->Value.u64;
97     break;
98   }
99 
100   return RetVal;
101 }
102 
103 /**
104   Check whether this value type can be transfer to EFI_IFR_TYPE_BUFFER type.
105 
106   EFI_IFR_TYPE_REF, EFI_IFR_TYPE_DATE and EFI_IFR_TYPE_TIME are converted to
107   EFI_IFR_TYPE_BUFFER when do the value compare.
108 
109   @param  Value                  Expression value to compare on.
110 
111   @retval TRUE                   This value type can be transter to EFI_IFR_TYPE_BUFFER type.
112   @retval FALSE                  This value type can't be transter to EFI_IFR_TYPE_BUFFER type.
113 
114 **/
115 BOOLEAN
IsTypeInBuffer(IN EFI_HII_VALUE * Value)116 IsTypeInBuffer (
117   IN  EFI_HII_VALUE   *Value
118   )
119 {
120   switch (Value->Type) {
121   case EFI_IFR_TYPE_BUFFER:
122   case EFI_IFR_TYPE_DATE:
123   case EFI_IFR_TYPE_TIME:
124   case EFI_IFR_TYPE_REF:
125     return TRUE;
126 
127   default:
128     return FALSE;
129   }
130 }
131 
132 /**
133   Check whether this value type can be transfer to EFI_IFR_TYPE_UINT64
134 
135   @param  Value                  Expression value to compare on.
136 
137   @retval TRUE                   This value type can be transter to EFI_IFR_TYPE_BUFFER type.
138   @retval FALSE                  This value type can't be transter to EFI_IFR_TYPE_BUFFER type.
139 
140 **/
141 BOOLEAN
IsTypeInUINT64(IN EFI_HII_VALUE * Value)142 IsTypeInUINT64 (
143   IN  EFI_HII_VALUE   *Value
144   )
145 {
146   switch (Value->Type) {
147   case EFI_IFR_TYPE_NUM_SIZE_8:
148   case EFI_IFR_TYPE_NUM_SIZE_16:
149   case EFI_IFR_TYPE_NUM_SIZE_32:
150   case EFI_IFR_TYPE_NUM_SIZE_64:
151   case EFI_IFR_TYPE_BOOLEAN:
152     return TRUE;
153 
154   default:
155     return FALSE;
156   }
157 }
158 
159 /**
160   Return the buffer length and buffer pointer for this value.
161 
162   EFI_IFR_TYPE_REF, EFI_IFR_TYPE_DATE and EFI_IFR_TYPE_TIME are converted to
163   EFI_IFR_TYPE_BUFFER when do the value compare.
164 
165   @param  Value                  Expression value to compare on.
166   @param  Buf                    Return the buffer pointer.
167   @param  BufLen                 Return the buffer length.
168 
169 **/
170 VOID
GetBufAndLenForValue(IN EFI_HII_VALUE * Value,OUT UINT8 ** Buf,OUT UINT16 * BufLen)171 GetBufAndLenForValue (
172   IN  EFI_HII_VALUE   *Value,
173   OUT UINT8           **Buf,
174   OUT UINT16          *BufLen
175   )
176 {
177   switch (Value->Type) {
178   case EFI_IFR_TYPE_BUFFER:
179     *Buf    = Value->Buffer;
180     *BufLen = Value->BufferLen;
181     break;
182 
183   case EFI_IFR_TYPE_DATE:
184     *Buf    = (UINT8 *) (&Value->Value.date);
185     *BufLen = (UINT16) sizeof (EFI_HII_DATE);
186     break;
187 
188   case EFI_IFR_TYPE_TIME:
189     *Buf    = (UINT8 *) (&Value->Value.time);
190     *BufLen = (UINT16) sizeof (EFI_HII_TIME);
191     break;
192 
193   case EFI_IFR_TYPE_REF:
194     *Buf    = (UINT8 *) (&Value->Value.ref);
195     *BufLen = (UINT16) sizeof (EFI_HII_REF);
196     break;
197 
198   default:
199     *Buf    = NULL;
200     *BufLen = 0;
201   }
202 }
203 
204 /**
205   Compare two Hii value.
206 
207   @param  Value1                 Expression value to compare on left-hand.
208   @param  Value2                 Expression value to compare on right-hand.
209   @param  Result                 Return value after compare.
210                                  retval 0                      Two operators equal.
211                                  return Positive value if Value1 is greater than Value2.
212                                  retval Negative value if Value1 is less than Value2.
213   @param  HiiHandle              Only required for string compare.
214 
215   @retval other                  Could not perform compare on two values.
216   @retval EFI_SUCCESS            Compare the value success.
217 
218 **/
219 EFI_STATUS
CompareHiiValue(IN EFI_HII_VALUE * Value1,IN EFI_HII_VALUE * Value2,OUT INTN * Result,IN EFI_HII_HANDLE HiiHandle OPTIONAL)220 CompareHiiValue (
221   IN  EFI_HII_VALUE   *Value1,
222   IN  EFI_HII_VALUE   *Value2,
223   OUT INTN            *Result,
224   IN  EFI_HII_HANDLE  HiiHandle OPTIONAL
225   )
226 {
227   INT64   Temp64;
228   CHAR16  *Str1;
229   CHAR16  *Str2;
230   UINTN   Len;
231   UINT8   *Buf1;
232   UINT16  Buf1Len;
233   UINT8   *Buf2;
234   UINT16  Buf2Len;
235 
236   if (Value1->Type == EFI_IFR_TYPE_STRING && Value2->Type == EFI_IFR_TYPE_STRING) {
237     if (Value1->Value.string == 0 || Value2->Value.string == 0) {
238       //
239       // StringId 0 is reserved
240       //
241       return EFI_INVALID_PARAMETER;
242     }
243 
244     if (Value1->Value.string == Value2->Value.string) {
245       *Result = 0;
246       return EFI_SUCCESS;
247     }
248 
249     Str1 = GetToken (Value1->Value.string, HiiHandle);
250     if (Str1 == NULL) {
251       //
252       // String not found
253       //
254       return EFI_NOT_FOUND;
255     }
256 
257     Str2 = GetToken (Value2->Value.string, HiiHandle);
258     if (Str2 == NULL) {
259       FreePool (Str1);
260       return EFI_NOT_FOUND;
261     }
262 
263     *Result = StrCmp (Str1, Str2);
264 
265     FreePool (Str1);
266     FreePool (Str2);
267 
268     return EFI_SUCCESS;
269   }
270 
271   //
272   // Take types(date, time, ref, buffer) as buffer
273   //
274   if (IsTypeInBuffer(Value1) && IsTypeInBuffer(Value2)) {
275     GetBufAndLenForValue(Value1, &Buf1, &Buf1Len);
276     GetBufAndLenForValue(Value2, &Buf2, &Buf2Len);
277 
278     Len = Buf1Len > Buf2Len ? Buf2Len : Buf1Len;
279     *Result = CompareMem (Buf1, Buf2, Len);
280     if ((*Result == 0) && (Buf1Len != Buf2Len)) {
281       //
282       // In this case, means base on samll number buffer, the data is same
283       // So which value has more data, which value is bigger.
284       //
285       *Result = Buf1Len > Buf2Len ? 1 : -1;
286     }
287     return EFI_SUCCESS;
288   }
289 
290   //
291   // Take remain types(integer, boolean, date/time) as integer
292   //
293   if (IsTypeInUINT64(Value1) && IsTypeInUINT64(Value2)) {
294     Temp64 = HiiValueToUINT64(Value1) - HiiValueToUINT64(Value2);
295     if (Temp64 > 0) {
296       *Result = 1;
297     } else if (Temp64 < 0) {
298       *Result = -1;
299     } else {
300       *Result = 0;
301     }
302     return EFI_SUCCESS;
303   }
304 
305   return EFI_UNSUPPORTED;
306 }
307 
308 /**
309   Search an Option of a Question by its value.
310 
311   @param  Question               The Question
312   @param  OptionValue            Value for Option to be searched.
313 
314   @retval Pointer                Pointer to the found Option.
315   @retval NULL                   Option not found.
316 
317 **/
318 DISPLAY_QUESTION_OPTION *
ValueToOption(IN FORM_DISPLAY_ENGINE_STATEMENT * Question,IN EFI_HII_VALUE * OptionValue)319 ValueToOption (
320   IN FORM_DISPLAY_ENGINE_STATEMENT   *Question,
321   IN EFI_HII_VALUE                   *OptionValue
322   )
323 {
324   LIST_ENTRY               *Link;
325   DISPLAY_QUESTION_OPTION  *Option;
326   INTN                     Result;
327   EFI_HII_VALUE            Value;
328 
329   Link = GetFirstNode (&Question->OptionListHead);
330   while (!IsNull (&Question->OptionListHead, Link)) {
331     Option = DISPLAY_QUESTION_OPTION_FROM_LINK (Link);
332 
333     ZeroMem (&Value, sizeof (EFI_HII_VALUE));
334     Value.Type = Option->OptionOpCode->Type;
335     CopyMem (&Value.Value, &Option->OptionOpCode->Value, Option->OptionOpCode->Header.Length - OFFSET_OF (EFI_IFR_ONE_OF_OPTION, Value));
336 
337     if ((CompareHiiValue (&Value, OptionValue, &Result, NULL) == EFI_SUCCESS) && (Result == 0)) {
338       return Option;
339     }
340 
341     Link = GetNextNode (&Question->OptionListHead, Link);
342   }
343 
344   return NULL;
345 }
346 
347 
348 /**
349   Return data element in an Array by its Index.
350 
351   @param  Array                  The data array.
352   @param  Type                   Type of the data in this array.
353   @param  Index                  Zero based index for data in this array.
354 
355   @retval Value                  The data to be returned
356 
357 **/
358 UINT64
GetArrayData(IN VOID * Array,IN UINT8 Type,IN UINTN Index)359 GetArrayData (
360   IN VOID                     *Array,
361   IN UINT8                    Type,
362   IN UINTN                    Index
363   )
364 {
365   UINT64 Data;
366 
367   ASSERT (Array != NULL);
368 
369   Data = 0;
370   switch (Type) {
371   case EFI_IFR_TYPE_NUM_SIZE_8:
372     Data = (UINT64) *(((UINT8 *) Array) + Index);
373     break;
374 
375   case EFI_IFR_TYPE_NUM_SIZE_16:
376     Data = (UINT64) *(((UINT16 *) Array) + Index);
377     break;
378 
379   case EFI_IFR_TYPE_NUM_SIZE_32:
380     Data = (UINT64) *(((UINT32 *) Array) + Index);
381     break;
382 
383   case EFI_IFR_TYPE_NUM_SIZE_64:
384     Data = (UINT64) *(((UINT64 *) Array) + Index);
385     break;
386 
387   default:
388     break;
389   }
390 
391   return Data;
392 }
393 
394 
395 /**
396   Set value of a data element in an Array by its Index.
397 
398   @param  Array                  The data array.
399   @param  Type                   Type of the data in this array.
400   @param  Index                  Zero based index for data in this array.
401   @param  Value                  The value to be set.
402 
403 **/
404 VOID
SetArrayData(IN VOID * Array,IN UINT8 Type,IN UINTN Index,IN UINT64 Value)405 SetArrayData (
406   IN VOID                     *Array,
407   IN UINT8                    Type,
408   IN UINTN                    Index,
409   IN UINT64                   Value
410   )
411 {
412 
413   ASSERT (Array != NULL);
414 
415   switch (Type) {
416   case EFI_IFR_TYPE_NUM_SIZE_8:
417     *(((UINT8 *) Array) + Index) = (UINT8) Value;
418     break;
419 
420   case EFI_IFR_TYPE_NUM_SIZE_16:
421     *(((UINT16 *) Array) + Index) = (UINT16) Value;
422     break;
423 
424   case EFI_IFR_TYPE_NUM_SIZE_32:
425     *(((UINT32 *) Array) + Index) = (UINT32) Value;
426     break;
427 
428   case EFI_IFR_TYPE_NUM_SIZE_64:
429     *(((UINT64 *) Array) + Index) = (UINT64) Value;
430     break;
431 
432   default:
433     break;
434   }
435 }
436 
437 /**
438   Check whether this value already in the array, if yes, return the index.
439 
440   @param  Array                  The data array.
441   @param  Type                   Type of the data in this array.
442   @param  Value                  The value to be find.
443   @param  Index                  The index in the array which has same value with Value.
444 
445   @retval   TRUE Found the value in the array.
446   @retval   FALSE Not found the value.
447 
448 **/
449 BOOLEAN
FindArrayData(IN VOID * Array,IN UINT8 Type,IN UINT64 Value,OUT UINTN * Index OPTIONAL)450 FindArrayData (
451   IN VOID                     *Array,
452   IN UINT8                    Type,
453   IN UINT64                   Value,
454   OUT UINTN                   *Index OPTIONAL
455   )
456 {
457   UINTN  Count;
458   UINT64 TmpValue;
459   UINT64 ValueComp;
460 
461   ASSERT (Array != NULL);
462 
463   Count    = 0;
464   TmpValue = 0;
465 
466   switch (Type) {
467   case EFI_IFR_TYPE_NUM_SIZE_8:
468     ValueComp = (UINT8) Value;
469     break;
470 
471   case EFI_IFR_TYPE_NUM_SIZE_16:
472     ValueComp = (UINT16) Value;
473     break;
474 
475   case EFI_IFR_TYPE_NUM_SIZE_32:
476     ValueComp = (UINT32) Value;
477     break;
478 
479   case EFI_IFR_TYPE_NUM_SIZE_64:
480     ValueComp = (UINT64) Value;
481     break;
482 
483   default:
484     ValueComp = 0;
485     break;
486   }
487 
488   while ((TmpValue = GetArrayData (Array, Type, Count)) != 0) {
489     if (ValueComp == TmpValue) {
490       if (Index != NULL) {
491         *Index = Count;
492       }
493       return TRUE;
494     }
495 
496     Count ++;
497   }
498 
499   return FALSE;
500 }
501 
502 /**
503   Print Question Value according to it's storage width and display attributes.
504 
505   @param  Question               The Question to be printed.
506   @param  FormattedNumber        Buffer for output string.
507   @param  BufferSize             The FormattedNumber buffer size in bytes.
508 
509   @retval EFI_SUCCESS            Print success.
510   @retval EFI_BUFFER_TOO_SMALL   Buffer size is not enough for formatted number.
511 
512 **/
513 EFI_STATUS
PrintFormattedNumber(IN FORM_DISPLAY_ENGINE_STATEMENT * Question,IN OUT CHAR16 * FormattedNumber,IN UINTN BufferSize)514 PrintFormattedNumber (
515   IN FORM_DISPLAY_ENGINE_STATEMENT   *Question,
516   IN OUT CHAR16               *FormattedNumber,
517   IN UINTN                    BufferSize
518   )
519 {
520   INT64          Value;
521   CHAR16         *Format;
522   EFI_HII_VALUE  *QuestionValue;
523   EFI_IFR_NUMERIC *NumericOp;
524 
525   if (BufferSize < (21 * sizeof (CHAR16))) {
526     return EFI_BUFFER_TOO_SMALL;
527   }
528 
529   QuestionValue = &Question->CurrentValue;
530   NumericOp     = (EFI_IFR_NUMERIC *) Question->OpCode;
531 
532   Value = (INT64) QuestionValue->Value.u64;
533   switch (NumericOp->Flags & EFI_IFR_DISPLAY) {
534   case EFI_IFR_DISPLAY_INT_DEC:
535     switch (QuestionValue->Type) {
536     case EFI_IFR_NUMERIC_SIZE_1:
537       Value = (INT64) ((INT8) QuestionValue->Value.u8);
538       break;
539 
540     case EFI_IFR_NUMERIC_SIZE_2:
541       Value = (INT64) ((INT16) QuestionValue->Value.u16);
542       break;
543 
544     case EFI_IFR_NUMERIC_SIZE_4:
545       Value = (INT64) ((INT32) QuestionValue->Value.u32);
546       break;
547 
548     case EFI_IFR_NUMERIC_SIZE_8:
549     default:
550       break;
551     }
552 
553     if (Value < 0) {
554       Value = -Value;
555       Format = L"-%ld";
556     } else {
557       Format = L"%ld";
558     }
559     break;
560 
561   case EFI_IFR_DISPLAY_UINT_DEC:
562     Format = L"%ld";
563     break;
564 
565   case EFI_IFR_DISPLAY_UINT_HEX:
566     Format = L"%lx";
567     break;
568 
569   default:
570     return EFI_UNSUPPORTED;
571   }
572 
573   UnicodeSPrint (FormattedNumber, BufferSize, Format, Value);
574 
575   return EFI_SUCCESS;
576 }
577 
578 
579 /**
580   Draw a pop up windows based on the dimension, number of lines and
581   strings specified.
582 
583   @param RequestedWidth  The width of the pop-up.
584   @param NumberOfLines   The number of lines.
585   @param Marker          The variable argument list for the list of string to be printed.
586 
587 **/
588 VOID
CreateSharedPopUp(IN UINTN RequestedWidth,IN UINTN NumberOfLines,IN VA_LIST Marker)589 CreateSharedPopUp (
590   IN  UINTN                       RequestedWidth,
591   IN  UINTN                       NumberOfLines,
592   IN  VA_LIST                     Marker
593   )
594 {
595   UINTN   Index;
596   UINTN   Count;
597   CHAR16  Character;
598   UINTN   Start;
599   UINTN   End;
600   UINTN   Top;
601   UINTN   Bottom;
602   CHAR16  *String;
603   UINTN   DimensionsWidth;
604   UINTN   DimensionsHeight;
605 
606   DimensionsWidth   = gStatementDimensions.RightColumn - gStatementDimensions.LeftColumn;
607   DimensionsHeight  = gStatementDimensions.BottomRow - gStatementDimensions.TopRow;
608 
609   gST->ConOut->SetAttribute (gST->ConOut, GetPopupColor ());
610 
611   if ((RequestedWidth + 2) > DimensionsWidth) {
612     RequestedWidth = DimensionsWidth - 2;
613   }
614 
615   //
616   // Subtract the PopUp width from total Columns, allow for one space extra on
617   // each end plus a border.
618   //
619   Start     = (DimensionsWidth - RequestedWidth - 2) / 2 + gStatementDimensions.LeftColumn + 1;
620   End       = Start + RequestedWidth + 1;
621 
622   Top       = ((DimensionsHeight - NumberOfLines - 2) / 2) + gStatementDimensions.TopRow - 1;
623   Bottom    = Top + NumberOfLines + 2;
624 
625   Character = BOXDRAW_DOWN_RIGHT;
626   PrintCharAt (Start, Top, Character);
627   Character = BOXDRAW_HORIZONTAL;
628   for (Index = Start; Index + 2 < End; Index++) {
629     PrintCharAt ((UINTN)-1, (UINTN)-1, Character);
630   }
631 
632   Character = BOXDRAW_DOWN_LEFT;
633   PrintCharAt ((UINTN)-1, (UINTN)-1, Character);
634   Character = BOXDRAW_VERTICAL;
635 
636   Count = 0;
637   for (Index = Top; Index + 2 < Bottom; Index++, Count++) {
638     String = VA_ARG (Marker, CHAR16*);
639 
640     //
641     // This will clear the background of the line - we never know who might have been
642     // here before us.  This differs from the next clear in that it used the non-reverse
643     // video for normal printing.
644     //
645     if (GetStringWidth (String) / 2 > 1) {
646       ClearLines (Start, End, Index + 1, Index + 1, GetPopupColor ());
647     }
648 
649     //
650     // Passing in a space results in the assumption that this is where typing will occur
651     //
652     if (String[0] == L' ') {
653       ClearLines (Start + 1, End - 1, Index + 1, Index + 1, GetPopupInverseColor ());
654     }
655 
656     //
657     // Passing in a NULL results in a blank space
658     //
659     if (String[0] == CHAR_NULL) {
660       ClearLines (Start, End, Index + 1, Index + 1, GetPopupColor ());
661     }
662 
663     PrintStringAt (
664       ((DimensionsWidth - GetStringWidth (String) / 2) / 2) + gStatementDimensions.LeftColumn + 1,
665       Index + 1,
666       String
667       );
668     gST->ConOut->SetAttribute (gST->ConOut, GetPopupColor ());
669     PrintCharAt (Start, Index + 1, Character);
670     PrintCharAt (End - 1, Index + 1, Character);
671   }
672 
673   Character = BOXDRAW_UP_RIGHT;
674   PrintCharAt (Start, Bottom - 1, Character);
675   Character = BOXDRAW_HORIZONTAL;
676   for (Index = Start; Index + 2 < End; Index++) {
677     PrintCharAt ((UINTN)-1, (UINTN)-1, Character);
678   }
679 
680   Character = BOXDRAW_UP_LEFT;
681   PrintCharAt ((UINTN)-1, (UINTN)-1, Character);
682 }
683 
684 /**
685   Draw a pop up windows based on the dimension, number of lines and
686   strings specified.
687 
688   @param RequestedWidth  The width of the pop-up.
689   @param NumberOfLines   The number of lines.
690   @param ...             A series of text strings that displayed in the pop-up.
691 
692 **/
693 VOID
694 EFIAPI
CreateMultiStringPopUp(IN UINTN RequestedWidth,IN UINTN NumberOfLines,...)695 CreateMultiStringPopUp (
696   IN  UINTN                       RequestedWidth,
697   IN  UINTN                       NumberOfLines,
698   ...
699   )
700 {
701   VA_LIST Marker;
702 
703   VA_START (Marker, NumberOfLines);
704 
705   CreateSharedPopUp (RequestedWidth, NumberOfLines, Marker);
706 
707   VA_END (Marker);
708 }
709 
710 /**
711   Process nothing.
712 
713   @param Event    The Event need to be process
714   @param Context  The context of the event.
715 
716 **/
717 VOID
718 EFIAPI
EmptyEventProcess(IN EFI_EVENT Event,IN VOID * Context)719 EmptyEventProcess (
720   IN  EFI_EVENT    Event,
721   IN  VOID         *Context
722   )
723 {
724 }
725 
726 /**
727   Process for the refresh interval statement.
728 
729   @param Event    The Event need to be process
730   @param Context  The context of the event.
731 
732 **/
733 VOID
734 EFIAPI
RefreshTimeOutProcess(IN EFI_EVENT Event,IN VOID * Context)735 RefreshTimeOutProcess (
736   IN  EFI_EVENT    Event,
737   IN  VOID         *Context
738   )
739 {
740   WARNING_IF_CONTEXT     *EventInfo;
741   CHAR16                 TimeOutString[MAX_TIME_OUT_LEN];
742 
743   EventInfo   = (WARNING_IF_CONTEXT *) Context;
744 
745   if (*(EventInfo->TimeOut) == 0) {
746     gBS->CloseEvent (Event);
747 
748     gBS->SignalEvent (EventInfo->SyncEvent);
749     return;
750   }
751 
752   UnicodeSPrint(TimeOutString, MAX_TIME_OUT_LEN, L"%d", *(EventInfo->TimeOut));
753 
754   CreateDialog (NULL, gEmptyString, EventInfo->ErrorInfo, gPressEnter, gEmptyString, TimeOutString, NULL);
755 
756   *(EventInfo->TimeOut) -= 1;
757 }
758 
759 /**
760   Display error message for invalid password.
761 
762 **/
763 VOID
PasswordInvalid(VOID)764 PasswordInvalid (
765   VOID
766   )
767 {
768   EFI_INPUT_KEY  Key;
769 
770   //
771   // Invalid password, prompt error message
772   //
773   do {
774     CreateDialog (&Key, gEmptyString, gPassowordInvalid, gPressEnter, gEmptyString, NULL);
775   } while (Key.UnicodeChar != CHAR_CARRIAGE_RETURN);
776 }
777 
778 /**
779   Process password op code.
780 
781   @param  MenuOption             The menu for current password op code.
782 
783   @retval EFI_SUCCESS            Question Option process success.
784   @retval Other                  Question Option process fail.
785 
786 **/
787 EFI_STATUS
PasswordProcess(IN UI_MENU_OPTION * MenuOption)788 PasswordProcess (
789   IN  UI_MENU_OPTION              *MenuOption
790   )
791 {
792   CHAR16                          *StringPtr;
793   CHAR16                          *TempString;
794   UINTN                           Maximum;
795   EFI_STATUS                      Status;
796   EFI_IFR_PASSWORD                *PasswordInfo;
797   FORM_DISPLAY_ENGINE_STATEMENT   *Question;
798   EFI_INPUT_KEY                   Key;
799 
800   Question     = MenuOption->ThisTag;
801   PasswordInfo = (EFI_IFR_PASSWORD *) Question->OpCode;
802   Maximum      = PasswordInfo->MaxSize;
803   Status       = EFI_SUCCESS;
804 
805   StringPtr = AllocateZeroPool ((Maximum + 1) * sizeof (CHAR16));
806   ASSERT (StringPtr);
807 
808   //
809   // Use a NULL password to test whether old password is required
810   //
811   *StringPtr = 0;
812   Status = Question->PasswordCheck (gFormData, Question, StringPtr);
813   if (Status == EFI_NOT_AVAILABLE_YET || Status == EFI_UNSUPPORTED) {
814     //
815     // Password can't be set now.
816     //
817     FreePool (StringPtr);
818     return EFI_SUCCESS;
819   }
820 
821   if (EFI_ERROR (Status)) {
822     //
823     // Old password exist, ask user for the old password
824     //
825     Status = ReadString (MenuOption, gPromptForPassword, StringPtr);
826     if (EFI_ERROR (Status)) {
827       FreePool (StringPtr);
828       return Status;
829     }
830 
831     //
832     // Check user input old password
833     //
834     Status = Question->PasswordCheck (gFormData, Question, StringPtr);
835     if (EFI_ERROR (Status)) {
836       if (Status == EFI_NOT_READY) {
837         //
838         // Typed in old password incorrect
839         //
840         PasswordInvalid ();
841       } else {
842         Status = EFI_SUCCESS;
843       }
844 
845       FreePool (StringPtr);
846       return Status;
847     }
848   }
849 
850   //
851   // Ask for new password
852   //
853   ZeroMem (StringPtr, (Maximum + 1) * sizeof (CHAR16));
854   Status = ReadString (MenuOption, gPromptForNewPassword, StringPtr);
855   if (EFI_ERROR (Status)) {
856     //
857     // Reset state machine for password
858     //
859     Question->PasswordCheck (gFormData, Question, NULL);
860     FreePool (StringPtr);
861     return Status;
862   }
863 
864   //
865   // Confirm new password
866   //
867   TempString = AllocateZeroPool ((Maximum + 1) * sizeof (CHAR16));
868   ASSERT (TempString);
869   Status = ReadString (MenuOption, gConfirmPassword, TempString);
870   if (EFI_ERROR (Status)) {
871     //
872     // Reset state machine for password
873     //
874     Question->PasswordCheck (gFormData, Question, NULL);
875     FreePool (StringPtr);
876     FreePool (TempString);
877     return Status;
878   }
879 
880   //
881   // Compare two typed-in new passwords
882   //
883   if (StrCmp (StringPtr, TempString) == 0) {
884     gUserInput->InputValue.Buffer = AllocateCopyPool (Question->CurrentValue.BufferLen, StringPtr);
885     gUserInput->InputValue.BufferLen = Question->CurrentValue.BufferLen;
886     gUserInput->InputValue.Type = Question->CurrentValue.Type;
887     gUserInput->InputValue.Value.string = HiiSetString(gFormData->HiiHandle, gUserInput->InputValue.Value.string, StringPtr, NULL);
888     FreePool (StringPtr);
889 
890     Status = EFI_SUCCESS;
891 
892     if (EFI_ERROR (Status)) {
893       //
894       // Reset state machine for password
895       //
896       Question->PasswordCheck (gFormData, Question, NULL);
897     }
898 
899     return Status;
900   } else {
901     //
902     // Reset state machine for password
903     //
904     Question->PasswordCheck (gFormData, Question, NULL);
905 
906     //
907     // Two password mismatch, prompt error message
908     //
909     do {
910       CreateDialog (&Key, gEmptyString, gConfirmError, gPressEnter, gEmptyString, NULL);
911     } while (Key.UnicodeChar != CHAR_CARRIAGE_RETURN);
912 
913     Status = EFI_INVALID_PARAMETER;
914   }
915 
916   FreePool (TempString);
917   FreePool (StringPtr);
918 
919   return Status;
920 }
921 
922 /**
923   Process a Question's Option (whether selected or un-selected).
924 
925   @param  MenuOption             The MenuOption for this Question.
926   @param  Selected               TRUE: if Question is selected.
927   @param  OptionString           Pointer of the Option String to be displayed.
928   @param  SkipErrorValue         Whether need to return when value without option for it.
929 
930   @retval EFI_SUCCESS            Question Option process success.
931   @retval Other                  Question Option process fail.
932 
933 **/
934 EFI_STATUS
ProcessOptions(IN UI_MENU_OPTION * MenuOption,IN BOOLEAN Selected,OUT CHAR16 ** OptionString,IN BOOLEAN SkipErrorValue)935 ProcessOptions (
936   IN  UI_MENU_OPTION              *MenuOption,
937   IN  BOOLEAN                     Selected,
938   OUT CHAR16                      **OptionString,
939   IN  BOOLEAN                     SkipErrorValue
940   )
941 {
942   EFI_STATUS                      Status;
943   CHAR16                          *StringPtr;
944   UINTN                           Index;
945   FORM_DISPLAY_ENGINE_STATEMENT   *Question;
946   CHAR16                          FormattedNumber[21];
947   UINT16                          Number;
948   CHAR16                          Character[2];
949   EFI_INPUT_KEY                   Key;
950   UINTN                           BufferSize;
951   DISPLAY_QUESTION_OPTION         *OneOfOption;
952   LIST_ENTRY                      *Link;
953   EFI_HII_VALUE                   HiiValue;
954   EFI_HII_VALUE                   *QuestionValue;
955   DISPLAY_QUESTION_OPTION         *Option;
956   UINTN                           Index2;
957   UINT8                           *ValueArray;
958   UINT8                           ValueType;
959   EFI_IFR_ORDERED_LIST            *OrderList;
960   BOOLEAN                         ValueInvalid;
961   UINTN                           MaxLen;
962 
963   Status        = EFI_SUCCESS;
964 
965   StringPtr     = NULL;
966   Character[1]  = L'\0';
967   *OptionString = NULL;
968   ValueInvalid  = FALSE;
969 
970   ZeroMem (FormattedNumber, 21 * sizeof (CHAR16));
971   BufferSize = (gOptionBlockWidth + 1) * 2 * gStatementDimensions.BottomRow;
972 
973   Question = MenuOption->ThisTag;
974   QuestionValue = &Question->CurrentValue;
975 
976   switch (Question->OpCode->OpCode) {
977   case EFI_IFR_ORDERED_LIST_OP:
978 
979     //
980     // Check whether there are Options of this OrderedList
981     //
982     if (IsListEmpty (&Question->OptionListHead)) {
983       break;
984     }
985 
986     OrderList = (EFI_IFR_ORDERED_LIST *) Question->OpCode;
987 
988     Link = GetFirstNode (&Question->OptionListHead);
989     OneOfOption = DISPLAY_QUESTION_OPTION_FROM_LINK (Link);
990 
991     ValueType =  OneOfOption->OptionOpCode->Type;
992     ValueArray = Question->CurrentValue.Buffer;
993 
994     if (Selected) {
995       //
996       // Go ask for input
997       //
998       Status = GetSelectionInputPopUp (MenuOption);
999     } else {
1000       //
1001       // We now know how many strings we will have, so we can allocate the
1002       // space required for the array or strings.
1003       //
1004       MaxLen = OrderList->MaxContainers * BufferSize / sizeof (CHAR16);
1005       *OptionString = AllocateZeroPool (MaxLen * sizeof (CHAR16));
1006       ASSERT (*OptionString);
1007 
1008       HiiValue.Type = ValueType;
1009       HiiValue.Value.u64 = 0;
1010       for (Index = 0; Index < OrderList->MaxContainers; Index++) {
1011         HiiValue.Value.u64 = GetArrayData (ValueArray, ValueType, Index);
1012         if (HiiValue.Value.u64 == 0) {
1013           //
1014           // Values for the options in ordered lists should never be a 0
1015           //
1016           break;
1017         }
1018 
1019         OneOfOption = ValueToOption (Question, &HiiValue);
1020         if (OneOfOption == NULL) {
1021           if (SkipErrorValue) {
1022             //
1023             // Just try to get the option string, skip the value which not has option.
1024             //
1025             continue;
1026           }
1027 
1028           //
1029           // Show error message
1030           //
1031           do {
1032             CreateDialog (&Key, gEmptyString, gOptionMismatch, gPressEnter, gEmptyString, NULL);
1033           } while (Key.UnicodeChar != CHAR_CARRIAGE_RETURN);
1034 
1035           //
1036           // The initial value of the orderedlist is invalid, force to be valid value
1037           // Exit current DisplayForm with new value.
1038           //
1039           gUserInput->SelectedStatement = Question;
1040           gMisMatch = TRUE;
1041           ValueArray = AllocateZeroPool (Question->CurrentValue.BufferLen);
1042           ASSERT (ValueArray != NULL);
1043           gUserInput->InputValue.Buffer    = ValueArray;
1044           gUserInput->InputValue.BufferLen = Question->CurrentValue.BufferLen;
1045           gUserInput->InputValue.Type      = Question->CurrentValue.Type;
1046 
1047           Link = GetFirstNode (&Question->OptionListHead);
1048           Index2 = 0;
1049           while (!IsNull (&Question->OptionListHead, Link) && Index2 < OrderList->MaxContainers) {
1050             Option = DISPLAY_QUESTION_OPTION_FROM_LINK (Link);
1051             Link = GetNextNode (&Question->OptionListHead, Link);
1052             SetArrayData (ValueArray, ValueType, Index2, Option->OptionOpCode->Value.u64);
1053             Index2++;
1054           }
1055           SetArrayData (ValueArray, ValueType, Index2, 0);
1056 
1057           FreePool (*OptionString);
1058           *OptionString = NULL;
1059           return EFI_NOT_FOUND;
1060         }
1061 
1062         Character[0] = LEFT_ONEOF_DELIMITER;
1063         NewStrCat (OptionString[0], MaxLen, Character);
1064         StringPtr = GetToken (OneOfOption->OptionOpCode->Option, gFormData->HiiHandle);
1065         ASSERT (StringPtr != NULL);
1066         NewStrCat (OptionString[0], MaxLen, StringPtr);
1067         Character[0] = RIGHT_ONEOF_DELIMITER;
1068         NewStrCat (OptionString[0], MaxLen, Character);
1069         Character[0] = CHAR_CARRIAGE_RETURN;
1070         NewStrCat (OptionString[0], MaxLen, Character);
1071         FreePool (StringPtr);
1072       }
1073 
1074       //
1075       // If valid option more than the max container, skip these options.
1076       //
1077       if (Index >= OrderList->MaxContainers) {
1078         break;
1079       }
1080 
1081       //
1082       // Search the other options, try to find the one not in the container.
1083       //
1084       Link = GetFirstNode (&Question->OptionListHead);
1085       while (!IsNull (&Question->OptionListHead, Link)) {
1086         OneOfOption = DISPLAY_QUESTION_OPTION_FROM_LINK (Link);
1087         Link = GetNextNode (&Question->OptionListHead, Link);
1088 
1089         if (FindArrayData (ValueArray, ValueType, OneOfOption->OptionOpCode->Value.u64, NULL)) {
1090           continue;
1091         }
1092 
1093         if (SkipErrorValue) {
1094           //
1095           // Not report error, just get the correct option string info.
1096           //
1097           Character[0] = LEFT_ONEOF_DELIMITER;
1098           NewStrCat (OptionString[0], MaxLen, Character);
1099           StringPtr = GetToken (OneOfOption->OptionOpCode->Option, gFormData->HiiHandle);
1100           ASSERT (StringPtr != NULL);
1101           NewStrCat (OptionString[0], MaxLen, StringPtr);
1102           Character[0] = RIGHT_ONEOF_DELIMITER;
1103           NewStrCat (OptionString[0], MaxLen, Character);
1104           Character[0] = CHAR_CARRIAGE_RETURN;
1105           NewStrCat (OptionString[0], MaxLen, Character);
1106           FreePool (StringPtr);
1107 
1108           continue;
1109         }
1110 
1111         if (!ValueInvalid) {
1112           ValueInvalid = TRUE;
1113           //
1114           // Show error message
1115           //
1116           do {
1117             CreateDialog (&Key, gEmptyString, gOptionMismatch, gPressEnter, gEmptyString, NULL);
1118           } while (Key.UnicodeChar != CHAR_CARRIAGE_RETURN);
1119 
1120           //
1121           // The initial value of the orderedlist is invalid, force to be valid value
1122           // Exit current DisplayForm with new value.
1123           //
1124           gUserInput->SelectedStatement = Question;
1125           gMisMatch = TRUE;
1126           ValueArray = AllocateCopyPool (Question->CurrentValue.BufferLen, Question->CurrentValue.Buffer);
1127           ASSERT (ValueArray != NULL);
1128           gUserInput->InputValue.Buffer    = ValueArray;
1129           gUserInput->InputValue.BufferLen = Question->CurrentValue.BufferLen;
1130           gUserInput->InputValue.Type      = Question->CurrentValue.Type;
1131         }
1132 
1133         SetArrayData (ValueArray, ValueType, Index++, OneOfOption->OptionOpCode->Value.u64);
1134       }
1135 
1136       if (ValueInvalid) {
1137         FreePool (*OptionString);
1138         *OptionString = NULL;
1139         return EFI_NOT_FOUND;
1140       }
1141     }
1142     break;
1143 
1144   case EFI_IFR_ONE_OF_OP:
1145     //
1146     // Check whether there are Options of this OneOf
1147     //
1148     if (IsListEmpty (&Question->OptionListHead)) {
1149       break;
1150     }
1151     if (Selected) {
1152       //
1153       // Go ask for input
1154       //
1155       Status = GetSelectionInputPopUp (MenuOption);
1156     } else {
1157       MaxLen = BufferSize / sizeof(CHAR16);
1158       *OptionString = AllocateZeroPool (BufferSize);
1159       ASSERT (*OptionString);
1160 
1161       OneOfOption = ValueToOption (Question, QuestionValue);
1162       if (OneOfOption == NULL) {
1163         if (SkipErrorValue) {
1164           //
1165           // Not report error, just get the correct option string info.
1166           //
1167           Link = GetFirstNode (&Question->OptionListHead);
1168           OneOfOption = DISPLAY_QUESTION_OPTION_FROM_LINK (Link);
1169         } else {
1170           //
1171           // Show error message
1172           //
1173           do {
1174             CreateDialog (&Key, gEmptyString, gOptionMismatch, gPressEnter, gEmptyString, NULL);
1175           } while (Key.UnicodeChar != CHAR_CARRIAGE_RETURN);
1176 
1177           //
1178           // Force the Question value to be valid
1179           // Exit current DisplayForm with new value.
1180           //
1181           Link = GetFirstNode (&Question->OptionListHead);
1182           Option = DISPLAY_QUESTION_OPTION_FROM_LINK (Link);
1183 
1184           gUserInput->InputValue.Type = Option->OptionOpCode->Type;
1185           switch (gUserInput->InputValue.Type) {
1186           case EFI_IFR_TYPE_NUM_SIZE_8:
1187             gUserInput->InputValue.Value.u8 = Option->OptionOpCode->Value.u8;
1188             break;
1189           case EFI_IFR_TYPE_NUM_SIZE_16:
1190             CopyMem (&gUserInput->InputValue.Value.u16, &Option->OptionOpCode->Value.u16, sizeof (UINT16));
1191             break;
1192           case EFI_IFR_TYPE_NUM_SIZE_32:
1193             CopyMem (&gUserInput->InputValue.Value.u32, &Option->OptionOpCode->Value.u32, sizeof (UINT32));
1194             break;
1195           case EFI_IFR_TYPE_NUM_SIZE_64:
1196             CopyMem (&gUserInput->InputValue.Value.u64, &Option->OptionOpCode->Value.u64, sizeof (UINT64));
1197             break;
1198           default:
1199             ASSERT (FALSE);
1200             break;
1201           }
1202           gUserInput->SelectedStatement = Question;
1203           gMisMatch = TRUE;
1204           FreePool (*OptionString);
1205           *OptionString = NULL;
1206           return EFI_NOT_FOUND;
1207         }
1208       }
1209 
1210       Character[0] = LEFT_ONEOF_DELIMITER;
1211       NewStrCat (OptionString[0], MaxLen, Character);
1212       StringPtr = GetToken (OneOfOption->OptionOpCode->Option, gFormData->HiiHandle);
1213       ASSERT (StringPtr != NULL);
1214       NewStrCat (OptionString[0], MaxLen, StringPtr);
1215       Character[0] = RIGHT_ONEOF_DELIMITER;
1216       NewStrCat (OptionString[0], MaxLen, Character);
1217 
1218       FreePool (StringPtr);
1219     }
1220     break;
1221 
1222   case EFI_IFR_CHECKBOX_OP:
1223     if (Selected) {
1224       //
1225       // Since this is a BOOLEAN operation, flip it upon selection
1226       //
1227       gUserInput->InputValue.Type    = QuestionValue->Type;
1228       gUserInput->InputValue.Value.b = (BOOLEAN) (QuestionValue->Value.b ? FALSE : TRUE);
1229 
1230       //
1231       // Perform inconsistent check
1232       //
1233       return EFI_SUCCESS;
1234     } else {
1235       *OptionString = AllocateZeroPool (BufferSize);
1236       ASSERT (*OptionString);
1237 
1238       *OptionString[0] = LEFT_CHECKBOX_DELIMITER;
1239 
1240       if (QuestionValue->Value.b) {
1241         *(OptionString[0] + 1) = CHECK_ON;
1242       } else {
1243         *(OptionString[0] + 1) = CHECK_OFF;
1244       }
1245       *(OptionString[0] + 2) = RIGHT_CHECKBOX_DELIMITER;
1246     }
1247     break;
1248 
1249   case EFI_IFR_NUMERIC_OP:
1250     if (Selected) {
1251       //
1252       // Go ask for input
1253       //
1254       Status = GetNumericInput (MenuOption);
1255     } else {
1256       *OptionString = AllocateZeroPool (BufferSize);
1257       ASSERT (*OptionString);
1258 
1259       *OptionString[0] = LEFT_NUMERIC_DELIMITER;
1260 
1261       //
1262       // Formatted print
1263       //
1264       PrintFormattedNumber (Question, FormattedNumber, 21 * sizeof (CHAR16));
1265       Number = (UINT16) GetStringWidth (FormattedNumber);
1266       CopyMem (OptionString[0] + 1, FormattedNumber, Number);
1267 
1268       *(OptionString[0] + Number / 2) = RIGHT_NUMERIC_DELIMITER;
1269     }
1270     break;
1271 
1272   case EFI_IFR_DATE_OP:
1273     if (Selected) {
1274       //
1275       // This is similar to numerics
1276       //
1277       Status = GetNumericInput (MenuOption);
1278     } else {
1279       *OptionString = AllocateZeroPool (BufferSize);
1280       ASSERT (*OptionString);
1281 
1282       switch (MenuOption->Sequence) {
1283       case 0:
1284         *OptionString[0] = LEFT_NUMERIC_DELIMITER;
1285         if (QuestionValue->Value.date.Month == 0xff){
1286           UnicodeSPrint (OptionString[0] + 1, 21 * sizeof (CHAR16), L"??");
1287         } else {
1288           UnicodeSPrint (OptionString[0] + 1, 21 * sizeof (CHAR16), L"%02d", QuestionValue->Value.date.Month);
1289         }
1290         *(OptionString[0] + 3) = DATE_SEPARATOR;
1291         break;
1292 
1293       case 1:
1294         SetUnicodeMem (OptionString[0], 4, L' ');
1295         if (QuestionValue->Value.date.Day == 0xff){
1296           UnicodeSPrint (OptionString[0] + 4, 21 * sizeof (CHAR16), L"??");
1297         } else {
1298           UnicodeSPrint (OptionString[0] + 4, 21 * sizeof (CHAR16), L"%02d", QuestionValue->Value.date.Day);
1299         }
1300         *(OptionString[0] + 6) = DATE_SEPARATOR;
1301         break;
1302 
1303       case 2:
1304         SetUnicodeMem (OptionString[0], 7, L' ');
1305         if (QuestionValue->Value.date.Year == 0xff){
1306           UnicodeSPrint (OptionString[0] + 7, 21 * sizeof (CHAR16), L"????");
1307         } else {
1308           UnicodeSPrint (OptionString[0] + 7, 21 * sizeof (CHAR16), L"%04d", QuestionValue->Value.date.Year);
1309         }
1310         *(OptionString[0] + 11) = RIGHT_NUMERIC_DELIMITER;
1311         break;
1312       }
1313     }
1314     break;
1315 
1316   case EFI_IFR_TIME_OP:
1317     if (Selected) {
1318       //
1319       // This is similar to numerics
1320       //
1321       Status = GetNumericInput (MenuOption);
1322     } else {
1323       *OptionString = AllocateZeroPool (BufferSize);
1324       ASSERT (*OptionString);
1325 
1326       switch (MenuOption->Sequence) {
1327       case 0:
1328         *OptionString[0] = LEFT_NUMERIC_DELIMITER;
1329         if (QuestionValue->Value.time.Hour == 0xff){
1330           UnicodeSPrint (OptionString[0] + 1, 21 * sizeof (CHAR16), L"??");
1331         } else {
1332           UnicodeSPrint (OptionString[0] + 1, 21 * sizeof (CHAR16), L"%02d", QuestionValue->Value.time.Hour);
1333         }
1334         *(OptionString[0] + 3) = TIME_SEPARATOR;
1335         break;
1336 
1337       case 1:
1338         SetUnicodeMem (OptionString[0], 4, L' ');
1339         if (QuestionValue->Value.time.Minute == 0xff){
1340           UnicodeSPrint (OptionString[0] + 4, 21 * sizeof (CHAR16), L"??");
1341         } else {
1342           UnicodeSPrint (OptionString[0] + 4, 21 * sizeof (CHAR16), L"%02d", QuestionValue->Value.time.Minute);
1343         }
1344         *(OptionString[0] + 6) = TIME_SEPARATOR;
1345         break;
1346 
1347       case 2:
1348         SetUnicodeMem (OptionString[0], 7, L' ');
1349         if (QuestionValue->Value.time.Second == 0xff){
1350           UnicodeSPrint (OptionString[0] + 7, 21 * sizeof (CHAR16), L"??");
1351         } else {
1352           UnicodeSPrint (OptionString[0] + 7, 21 * sizeof (CHAR16), L"%02d", QuestionValue->Value.time.Second);
1353         }
1354         *(OptionString[0] + 9) = RIGHT_NUMERIC_DELIMITER;
1355         break;
1356       }
1357     }
1358     break;
1359 
1360   case EFI_IFR_STRING_OP:
1361     if (Selected) {
1362       StringPtr = AllocateZeroPool (Question->CurrentValue.BufferLen + sizeof (CHAR16));
1363       ASSERT (StringPtr);
1364       CopyMem(StringPtr, Question->CurrentValue.Buffer, Question->CurrentValue.BufferLen);
1365 
1366       Status = ReadString (MenuOption, gPromptForData, StringPtr);
1367       if (EFI_ERROR (Status)) {
1368         FreePool (StringPtr);
1369         return Status;
1370       }
1371 
1372       gUserInput->InputValue.Buffer = AllocateCopyPool (Question->CurrentValue.BufferLen, StringPtr);
1373       gUserInput->InputValue.BufferLen = Question->CurrentValue.BufferLen;
1374       gUserInput->InputValue.Type = Question->CurrentValue.Type;
1375       gUserInput->InputValue.Value.string = HiiSetString(gFormData->HiiHandle, gUserInput->InputValue.Value.string, StringPtr, NULL);
1376       FreePool (StringPtr);
1377       return EFI_SUCCESS;
1378     } else {
1379       *OptionString = AllocateZeroPool (BufferSize);
1380       ASSERT (*OptionString);
1381 
1382       if (((CHAR16 *) Question->CurrentValue.Buffer)[0] == 0x0000) {
1383         *(OptionString[0]) = '_';
1384       } else {
1385         if (Question->CurrentValue.BufferLen < BufferSize) {
1386           BufferSize = Question->CurrentValue.BufferLen;
1387         }
1388         CopyMem (OptionString[0], (CHAR16 *) Question->CurrentValue.Buffer, BufferSize);
1389       }
1390     }
1391     break;
1392 
1393   case EFI_IFR_PASSWORD_OP:
1394     if (Selected) {
1395       Status = PasswordProcess (MenuOption);
1396     }
1397     break;
1398 
1399   default:
1400     break;
1401   }
1402 
1403   return Status;
1404 }
1405 
1406 
1407 /**
1408   Process the help string: Split StringPtr to several lines of strings stored in
1409   FormattedString and the glyph width of each line cannot exceed gHelpBlockWidth.
1410 
1411   @param  StringPtr              The entire help string.
1412   @param  FormattedString        The oupput formatted string.
1413   @param  EachLineWidth          The max string length of each line in the formatted string.
1414   @param  RowCount               TRUE: if Question is selected.
1415 
1416 **/
1417 UINTN
ProcessHelpString(IN CHAR16 * StringPtr,OUT CHAR16 ** FormattedString,OUT UINT16 * EachLineWidth,IN UINTN RowCount)1418 ProcessHelpString (
1419   IN  CHAR16  *StringPtr,
1420   OUT CHAR16  **FormattedString,
1421   OUT UINT16  *EachLineWidth,
1422   IN  UINTN   RowCount
1423   )
1424 {
1425   UINTN   Index;
1426   CHAR16  *OutputString;
1427   UINTN   TotalRowNum;
1428   UINTN   CheckedNum;
1429   UINT16  GlyphWidth;
1430   UINT16  LineWidth;
1431   UINT16  MaxStringLen;
1432   UINT16  StringLen;
1433 
1434   TotalRowNum    = 0;
1435   CheckedNum     = 0;
1436   GlyphWidth     = 1;
1437   Index          = 0;
1438   MaxStringLen   = 0;
1439   StringLen      = 0;
1440 
1441   //
1442   // Set default help string width.
1443   //
1444   LineWidth      = (UINT16) (gHelpBlockWidth - 1);
1445 
1446   //
1447   // Get row number of the String.
1448   //
1449   while ((StringLen = GetLineByWidth (StringPtr, LineWidth, &GlyphWidth, &Index, &OutputString)) != 0) {
1450     if (StringLen > MaxStringLen) {
1451       MaxStringLen = StringLen;
1452     }
1453 
1454     TotalRowNum ++;
1455     FreePool (OutputString);
1456   }
1457   *EachLineWidth = MaxStringLen;
1458 
1459   *FormattedString = AllocateZeroPool (TotalRowNum * MaxStringLen * sizeof (CHAR16));
1460   ASSERT (*FormattedString != NULL);
1461 
1462   //
1463   // Generate formatted help string array.
1464   //
1465   GlyphWidth  = 1;
1466   Index       = 0;
1467   while((StringLen = GetLineByWidth (StringPtr, LineWidth, &GlyphWidth, &Index, &OutputString)) != 0) {
1468     CopyMem (*FormattedString + CheckedNum * MaxStringLen, OutputString, StringLen * sizeof (CHAR16));
1469     CheckedNum ++;
1470     FreePool (OutputString);
1471   }
1472 
1473   return TotalRowNum;
1474 }
1475