Home | History | Annotate | Download | only in DisplayEngineDxe
      1 /** @file
      2 Implementation for handling the User Interface option processing.
      3 
      4 
      5 Copyright (c) 2004 - 2016, 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
     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
     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
    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
    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
    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
    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 *
    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
    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
    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
    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
    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
    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
    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
    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
    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
    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
    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     if (Status == EFI_UNSUPPORTED) {
    818       do {
    819         CreateDialog (&Key, gEmptyString, gPasswordUnsupported, gPressEnter, gEmptyString, NULL);
    820       } while (Key.UnicodeChar != CHAR_CARRIAGE_RETURN);
    821     }
    822     FreePool (StringPtr);
    823     return EFI_SUCCESS;
    824   }
    825 
    826   if (EFI_ERROR (Status)) {
    827     //
    828     // Old password exist, ask user for the old password
    829     //
    830     Status = ReadString (MenuOption, gPromptForPassword, StringPtr);
    831     if (EFI_ERROR (Status)) {
    832       FreePool (StringPtr);
    833       return Status;
    834     }
    835 
    836     //
    837     // Check user input old password
    838     //
    839     Status = Question->PasswordCheck (gFormData, Question, StringPtr);
    840     if (EFI_ERROR (Status)) {
    841       if (Status == EFI_NOT_READY) {
    842         //
    843         // Typed in old password incorrect
    844         //
    845         PasswordInvalid ();
    846       } else {
    847         Status = EFI_SUCCESS;
    848       }
    849 
    850       FreePool (StringPtr);
    851       return Status;
    852     }
    853   }
    854 
    855   //
    856   // Ask for new password
    857   //
    858   ZeroMem (StringPtr, (Maximum + 1) * sizeof (CHAR16));
    859   Status = ReadString (MenuOption, gPromptForNewPassword, StringPtr);
    860   if (EFI_ERROR (Status)) {
    861     //
    862     // Reset state machine for password
    863     //
    864     Question->PasswordCheck (gFormData, Question, NULL);
    865     FreePool (StringPtr);
    866     return Status;
    867   }
    868 
    869   //
    870   // Confirm new password
    871   //
    872   TempString = AllocateZeroPool ((Maximum + 1) * sizeof (CHAR16));
    873   ASSERT (TempString);
    874   Status = ReadString (MenuOption, gConfirmPassword, TempString);
    875   if (EFI_ERROR (Status)) {
    876     //
    877     // Reset state machine for password
    878     //
    879     Question->PasswordCheck (gFormData, Question, NULL);
    880     FreePool (StringPtr);
    881     FreePool (TempString);
    882     return Status;
    883   }
    884 
    885   //
    886   // Compare two typed-in new passwords
    887   //
    888   if (StrCmp (StringPtr, TempString) == 0) {
    889     gUserInput->InputValue.Buffer = AllocateCopyPool (Question->CurrentValue.BufferLen, StringPtr);
    890     gUserInput->InputValue.BufferLen = Question->CurrentValue.BufferLen;
    891     gUserInput->InputValue.Type = Question->CurrentValue.Type;
    892     gUserInput->InputValue.Value.string = HiiSetString(gFormData->HiiHandle, gUserInput->InputValue.Value.string, StringPtr, NULL);
    893 
    894     Status = EFI_SUCCESS;
    895   } else {
    896     //
    897     // Reset state machine for password
    898     //
    899     Question->PasswordCheck (gFormData, Question, NULL);
    900 
    901     //
    902     // Two password mismatch, prompt error message
    903     //
    904     do {
    905       CreateDialog (&Key, gEmptyString, gConfirmError, gPressEnter, gEmptyString, NULL);
    906     } while (Key.UnicodeChar != CHAR_CARRIAGE_RETURN);
    907 
    908     Status = EFI_INVALID_PARAMETER;
    909   }
    910   ZeroMem (TempString, (Maximum + 1) * sizeof (CHAR16));
    911   ZeroMem (StringPtr, (Maximum + 1) * sizeof (CHAR16));
    912   FreePool (TempString);
    913   FreePool (StringPtr);
    914 
    915   return Status;
    916 }
    917 
    918 /**
    919   Process a Question's Option (whether selected or un-selected).
    920 
    921   @param  MenuOption             The MenuOption for this Question.
    922   @param  Selected               TRUE: if Question is selected.
    923   @param  OptionString           Pointer of the Option String to be displayed.
    924   @param  SkipErrorValue         Whether need to return when value without option for it.
    925 
    926   @retval EFI_SUCCESS            Question Option process success.
    927   @retval Other                  Question Option process fail.
    928 
    929 **/
    930 EFI_STATUS
    931 ProcessOptions (
    932   IN  UI_MENU_OPTION              *MenuOption,
    933   IN  BOOLEAN                     Selected,
    934   OUT CHAR16                      **OptionString,
    935   IN  BOOLEAN                     SkipErrorValue
    936   )
    937 {
    938   EFI_STATUS                      Status;
    939   CHAR16                          *StringPtr;
    940   UINTN                           Index;
    941   FORM_DISPLAY_ENGINE_STATEMENT   *Question;
    942   CHAR16                          FormattedNumber[21];
    943   UINT16                          Number;
    944   CHAR16                          Character[2];
    945   EFI_INPUT_KEY                   Key;
    946   UINTN                           BufferSize;
    947   DISPLAY_QUESTION_OPTION         *OneOfOption;
    948   LIST_ENTRY                      *Link;
    949   EFI_HII_VALUE                   HiiValue;
    950   EFI_HII_VALUE                   *QuestionValue;
    951   DISPLAY_QUESTION_OPTION         *Option;
    952   UINTN                           Index2;
    953   UINT8                           *ValueArray;
    954   UINT8                           ValueType;
    955   EFI_IFR_ORDERED_LIST            *OrderList;
    956   BOOLEAN                         ValueInvalid;
    957   UINTN                           MaxLen;
    958 
    959   Status        = EFI_SUCCESS;
    960 
    961   StringPtr     = NULL;
    962   Character[1]  = L'\0';
    963   *OptionString = NULL;
    964   ValueInvalid  = FALSE;
    965 
    966   ZeroMem (FormattedNumber, 21 * sizeof (CHAR16));
    967   BufferSize = (gOptionBlockWidth + 1) * 2 * gStatementDimensions.BottomRow;
    968 
    969   Question = MenuOption->ThisTag;
    970   QuestionValue = &Question->CurrentValue;
    971 
    972   switch (Question->OpCode->OpCode) {
    973   case EFI_IFR_ORDERED_LIST_OP:
    974 
    975     //
    976     // Check whether there are Options of this OrderedList
    977     //
    978     if (IsListEmpty (&Question->OptionListHead)) {
    979       break;
    980     }
    981 
    982     OrderList = (EFI_IFR_ORDERED_LIST *) Question->OpCode;
    983 
    984     Link = GetFirstNode (&Question->OptionListHead);
    985     OneOfOption = DISPLAY_QUESTION_OPTION_FROM_LINK (Link);
    986 
    987     ValueType =  OneOfOption->OptionOpCode->Type;
    988     ValueArray = Question->CurrentValue.Buffer;
    989 
    990     if (Selected) {
    991       //
    992       // Go ask for input
    993       //
    994       Status = GetSelectionInputPopUp (MenuOption);
    995     } else {
    996       //
    997       // We now know how many strings we will have, so we can allocate the
    998       // space required for the array or strings.
    999       //
   1000       MaxLen = OrderList->MaxContainers * BufferSize / sizeof (CHAR16);
   1001       *OptionString = AllocateZeroPool (MaxLen * sizeof (CHAR16));
   1002       ASSERT (*OptionString);
   1003 
   1004       HiiValue.Type = ValueType;
   1005       HiiValue.Value.u64 = 0;
   1006       for (Index = 0; Index < OrderList->MaxContainers; Index++) {
   1007         HiiValue.Value.u64 = GetArrayData (ValueArray, ValueType, Index);
   1008         if (HiiValue.Value.u64 == 0) {
   1009           //
   1010           // Values for the options in ordered lists should never be a 0
   1011           //
   1012           break;
   1013         }
   1014 
   1015         OneOfOption = ValueToOption (Question, &HiiValue);
   1016         if (OneOfOption == NULL) {
   1017           if (SkipErrorValue) {
   1018             //
   1019             // Just try to get the option string, skip the value which not has option.
   1020             //
   1021             continue;
   1022           }
   1023 
   1024           //
   1025           // Show error message
   1026           //
   1027           do {
   1028             CreateDialog (&Key, gEmptyString, gOptionMismatch, gPressEnter, gEmptyString, NULL);
   1029           } while (Key.UnicodeChar != CHAR_CARRIAGE_RETURN);
   1030 
   1031           //
   1032           // The initial value of the orderedlist is invalid, force to be valid value
   1033           // Exit current DisplayForm with new value.
   1034           //
   1035           gUserInput->SelectedStatement = Question;
   1036           gMisMatch = TRUE;
   1037           ValueArray = AllocateZeroPool (Question->CurrentValue.BufferLen);
   1038           ASSERT (ValueArray != NULL);
   1039           gUserInput->InputValue.Buffer    = ValueArray;
   1040           gUserInput->InputValue.BufferLen = Question->CurrentValue.BufferLen;
   1041           gUserInput->InputValue.Type      = Question->CurrentValue.Type;
   1042 
   1043           Link = GetFirstNode (&Question->OptionListHead);
   1044           Index2 = 0;
   1045           while (!IsNull (&Question->OptionListHead, Link) && Index2 < OrderList->MaxContainers) {
   1046             Option = DISPLAY_QUESTION_OPTION_FROM_LINK (Link);
   1047             Link = GetNextNode (&Question->OptionListHead, Link);
   1048             SetArrayData (ValueArray, ValueType, Index2, Option->OptionOpCode->Value.u64);
   1049             Index2++;
   1050           }
   1051           SetArrayData (ValueArray, ValueType, Index2, 0);
   1052 
   1053           FreePool (*OptionString);
   1054           *OptionString = NULL;
   1055           return EFI_NOT_FOUND;
   1056         }
   1057 
   1058         Character[0] = LEFT_ONEOF_DELIMITER;
   1059         NewStrCat (OptionString[0], MaxLen, Character);
   1060         StringPtr = GetToken (OneOfOption->OptionOpCode->Option, gFormData->HiiHandle);
   1061         ASSERT (StringPtr != NULL);
   1062         NewStrCat (OptionString[0], MaxLen, StringPtr);
   1063         Character[0] = RIGHT_ONEOF_DELIMITER;
   1064         NewStrCat (OptionString[0], MaxLen, Character);
   1065         Character[0] = CHAR_CARRIAGE_RETURN;
   1066         NewStrCat (OptionString[0], MaxLen, Character);
   1067         FreePool (StringPtr);
   1068       }
   1069 
   1070       //
   1071       // If valid option more than the max container, skip these options.
   1072       //
   1073       if (Index >= OrderList->MaxContainers) {
   1074         break;
   1075       }
   1076 
   1077       //
   1078       // Search the other options, try to find the one not in the container.
   1079       //
   1080       Link = GetFirstNode (&Question->OptionListHead);
   1081       while (!IsNull (&Question->OptionListHead, Link)) {
   1082         OneOfOption = DISPLAY_QUESTION_OPTION_FROM_LINK (Link);
   1083         Link = GetNextNode (&Question->OptionListHead, Link);
   1084 
   1085         if (FindArrayData (ValueArray, ValueType, OneOfOption->OptionOpCode->Value.u64, NULL)) {
   1086           continue;
   1087         }
   1088 
   1089         if (SkipErrorValue) {
   1090           //
   1091           // Not report error, just get the correct option string info.
   1092           //
   1093           Character[0] = LEFT_ONEOF_DELIMITER;
   1094           NewStrCat (OptionString[0], MaxLen, Character);
   1095           StringPtr = GetToken (OneOfOption->OptionOpCode->Option, gFormData->HiiHandle);
   1096           ASSERT (StringPtr != NULL);
   1097           NewStrCat (OptionString[0], MaxLen, StringPtr);
   1098           Character[0] = RIGHT_ONEOF_DELIMITER;
   1099           NewStrCat (OptionString[0], MaxLen, Character);
   1100           Character[0] = CHAR_CARRIAGE_RETURN;
   1101           NewStrCat (OptionString[0], MaxLen, Character);
   1102           FreePool (StringPtr);
   1103 
   1104           continue;
   1105         }
   1106 
   1107         if (!ValueInvalid) {
   1108           ValueInvalid = TRUE;
   1109           //
   1110           // Show error message
   1111           //
   1112           do {
   1113             CreateDialog (&Key, gEmptyString, gOptionMismatch, gPressEnter, gEmptyString, NULL);
   1114           } while (Key.UnicodeChar != CHAR_CARRIAGE_RETURN);
   1115 
   1116           //
   1117           // The initial value of the orderedlist is invalid, force to be valid value
   1118           // Exit current DisplayForm with new value.
   1119           //
   1120           gUserInput->SelectedStatement = Question;
   1121           gMisMatch = TRUE;
   1122           ValueArray = AllocateCopyPool (Question->CurrentValue.BufferLen, Question->CurrentValue.Buffer);
   1123           ASSERT (ValueArray != NULL);
   1124           gUserInput->InputValue.Buffer    = ValueArray;
   1125           gUserInput->InputValue.BufferLen = Question->CurrentValue.BufferLen;
   1126           gUserInput->InputValue.Type      = Question->CurrentValue.Type;
   1127         }
   1128 
   1129         SetArrayData (ValueArray, ValueType, Index++, OneOfOption->OptionOpCode->Value.u64);
   1130       }
   1131 
   1132       if (ValueInvalid) {
   1133         FreePool (*OptionString);
   1134         *OptionString = NULL;
   1135         return EFI_NOT_FOUND;
   1136       }
   1137     }
   1138     break;
   1139 
   1140   case EFI_IFR_ONE_OF_OP:
   1141     //
   1142     // Check whether there are Options of this OneOf
   1143     //
   1144     if (IsListEmpty (&Question->OptionListHead)) {
   1145       break;
   1146     }
   1147     if (Selected) {
   1148       //
   1149       // Go ask for input
   1150       //
   1151       Status = GetSelectionInputPopUp (MenuOption);
   1152     } else {
   1153       MaxLen = BufferSize / sizeof(CHAR16);
   1154       *OptionString = AllocateZeroPool (BufferSize);
   1155       ASSERT (*OptionString);
   1156 
   1157       OneOfOption = ValueToOption (Question, QuestionValue);
   1158       if (OneOfOption == NULL) {
   1159         if (SkipErrorValue) {
   1160           //
   1161           // Not report error, just get the correct option string info.
   1162           //
   1163           Link = GetFirstNode (&Question->OptionListHead);
   1164           OneOfOption = DISPLAY_QUESTION_OPTION_FROM_LINK (Link);
   1165         } else {
   1166           //
   1167           // Show error message
   1168           //
   1169           do {
   1170             CreateDialog (&Key, gEmptyString, gOptionMismatch, gPressEnter, gEmptyString, NULL);
   1171           } while (Key.UnicodeChar != CHAR_CARRIAGE_RETURN);
   1172 
   1173           //
   1174           // Force the Question value to be valid
   1175           // Exit current DisplayForm with new value.
   1176           //
   1177           Link = GetFirstNode (&Question->OptionListHead);
   1178           Option = DISPLAY_QUESTION_OPTION_FROM_LINK (Link);
   1179 
   1180           gUserInput->InputValue.Type = Option->OptionOpCode->Type;
   1181           switch (gUserInput->InputValue.Type) {
   1182           case EFI_IFR_TYPE_NUM_SIZE_8:
   1183             gUserInput->InputValue.Value.u8 = Option->OptionOpCode->Value.u8;
   1184             break;
   1185           case EFI_IFR_TYPE_NUM_SIZE_16:
   1186             CopyMem (&gUserInput->InputValue.Value.u16, &Option->OptionOpCode->Value.u16, sizeof (UINT16));
   1187             break;
   1188           case EFI_IFR_TYPE_NUM_SIZE_32:
   1189             CopyMem (&gUserInput->InputValue.Value.u32, &Option->OptionOpCode->Value.u32, sizeof (UINT32));
   1190             break;
   1191           case EFI_IFR_TYPE_NUM_SIZE_64:
   1192             CopyMem (&gUserInput->InputValue.Value.u64, &Option->OptionOpCode->Value.u64, sizeof (UINT64));
   1193             break;
   1194           default:
   1195             ASSERT (FALSE);
   1196             break;
   1197           }
   1198           gUserInput->SelectedStatement = Question;
   1199           gMisMatch = TRUE;
   1200           FreePool (*OptionString);
   1201           *OptionString = NULL;
   1202           return EFI_NOT_FOUND;
   1203         }
   1204       }
   1205 
   1206       Character[0] = LEFT_ONEOF_DELIMITER;
   1207       NewStrCat (OptionString[0], MaxLen, Character);
   1208       StringPtr = GetToken (OneOfOption->OptionOpCode->Option, gFormData->HiiHandle);
   1209       ASSERT (StringPtr != NULL);
   1210       NewStrCat (OptionString[0], MaxLen, StringPtr);
   1211       Character[0] = RIGHT_ONEOF_DELIMITER;
   1212       NewStrCat (OptionString[0], MaxLen, Character);
   1213 
   1214       FreePool (StringPtr);
   1215     }
   1216     break;
   1217 
   1218   case EFI_IFR_CHECKBOX_OP:
   1219     if (Selected) {
   1220       //
   1221       // Since this is a BOOLEAN operation, flip it upon selection
   1222       //
   1223       gUserInput->InputValue.Type    = QuestionValue->Type;
   1224       gUserInput->InputValue.Value.b = (BOOLEAN) (QuestionValue->Value.b ? FALSE : TRUE);
   1225 
   1226       //
   1227       // Perform inconsistent check
   1228       //
   1229       return EFI_SUCCESS;
   1230     } else {
   1231       *OptionString = AllocateZeroPool (BufferSize);
   1232       ASSERT (*OptionString);
   1233 
   1234       *OptionString[0] = LEFT_CHECKBOX_DELIMITER;
   1235 
   1236       if (QuestionValue->Value.b) {
   1237         *(OptionString[0] + 1) = CHECK_ON;
   1238       } else {
   1239         *(OptionString[0] + 1) = CHECK_OFF;
   1240       }
   1241       *(OptionString[0] + 2) = RIGHT_CHECKBOX_DELIMITER;
   1242     }
   1243     break;
   1244 
   1245   case EFI_IFR_NUMERIC_OP:
   1246     if (Selected) {
   1247       //
   1248       // Go ask for input
   1249       //
   1250       Status = GetNumericInput (MenuOption);
   1251     } else {
   1252       *OptionString = AllocateZeroPool (BufferSize);
   1253       ASSERT (*OptionString);
   1254 
   1255       *OptionString[0] = LEFT_NUMERIC_DELIMITER;
   1256 
   1257       //
   1258       // Formatted print
   1259       //
   1260       PrintFormattedNumber (Question, FormattedNumber, 21 * sizeof (CHAR16));
   1261       Number = (UINT16) GetStringWidth (FormattedNumber);
   1262       CopyMem (OptionString[0] + 1, FormattedNumber, Number);
   1263 
   1264       *(OptionString[0] + Number / 2) = RIGHT_NUMERIC_DELIMITER;
   1265     }
   1266     break;
   1267 
   1268   case EFI_IFR_DATE_OP:
   1269     if (Selected) {
   1270       //
   1271       // This is similar to numerics
   1272       //
   1273       Status = GetNumericInput (MenuOption);
   1274     } else {
   1275       *OptionString = AllocateZeroPool (BufferSize);
   1276       ASSERT (*OptionString);
   1277 
   1278       switch (MenuOption->Sequence) {
   1279       case 0:
   1280         *OptionString[0] = LEFT_NUMERIC_DELIMITER;
   1281         if (QuestionValue->Value.date.Month == 0xff){
   1282           UnicodeSPrint (OptionString[0] + 1, 21 * sizeof (CHAR16), L"??");
   1283         } else {
   1284           UnicodeSPrint (OptionString[0] + 1, 21 * sizeof (CHAR16), L"%02d", QuestionValue->Value.date.Month);
   1285         }
   1286         *(OptionString[0] + 3) = DATE_SEPARATOR;
   1287         break;
   1288 
   1289       case 1:
   1290         SetUnicodeMem (OptionString[0], 4, L' ');
   1291         if (QuestionValue->Value.date.Day == 0xff){
   1292           UnicodeSPrint (OptionString[0] + 4, 21 * sizeof (CHAR16), L"??");
   1293         } else {
   1294           UnicodeSPrint (OptionString[0] + 4, 21 * sizeof (CHAR16), L"%02d", QuestionValue->Value.date.Day);
   1295         }
   1296         *(OptionString[0] + 6) = DATE_SEPARATOR;
   1297         break;
   1298 
   1299       case 2:
   1300         SetUnicodeMem (OptionString[0], 7, L' ');
   1301         if (QuestionValue->Value.date.Year == 0xff){
   1302           UnicodeSPrint (OptionString[0] + 7, 21 * sizeof (CHAR16), L"????");
   1303         } else {
   1304           UnicodeSPrint (OptionString[0] + 7, 21 * sizeof (CHAR16), L"%04d", QuestionValue->Value.date.Year);
   1305         }
   1306         *(OptionString[0] + 11) = RIGHT_NUMERIC_DELIMITER;
   1307         break;
   1308       }
   1309     }
   1310     break;
   1311 
   1312   case EFI_IFR_TIME_OP:
   1313     if (Selected) {
   1314       //
   1315       // This is similar to numerics
   1316       //
   1317       Status = GetNumericInput (MenuOption);
   1318     } else {
   1319       *OptionString = AllocateZeroPool (BufferSize);
   1320       ASSERT (*OptionString);
   1321 
   1322       switch (MenuOption->Sequence) {
   1323       case 0:
   1324         *OptionString[0] = LEFT_NUMERIC_DELIMITER;
   1325         if (QuestionValue->Value.time.Hour == 0xff){
   1326           UnicodeSPrint (OptionString[0] + 1, 21 * sizeof (CHAR16), L"??");
   1327         } else {
   1328           UnicodeSPrint (OptionString[0] + 1, 21 * sizeof (CHAR16), L"%02d", QuestionValue->Value.time.Hour);
   1329         }
   1330         *(OptionString[0] + 3) = TIME_SEPARATOR;
   1331         break;
   1332 
   1333       case 1:
   1334         SetUnicodeMem (OptionString[0], 4, L' ');
   1335         if (QuestionValue->Value.time.Minute == 0xff){
   1336           UnicodeSPrint (OptionString[0] + 4, 21 * sizeof (CHAR16), L"??");
   1337         } else {
   1338           UnicodeSPrint (OptionString[0] + 4, 21 * sizeof (CHAR16), L"%02d", QuestionValue->Value.time.Minute);
   1339         }
   1340         *(OptionString[0] + 6) = TIME_SEPARATOR;
   1341         break;
   1342 
   1343       case 2:
   1344         SetUnicodeMem (OptionString[0], 7, L' ');
   1345         if (QuestionValue->Value.time.Second == 0xff){
   1346           UnicodeSPrint (OptionString[0] + 7, 21 * sizeof (CHAR16), L"??");
   1347         } else {
   1348           UnicodeSPrint (OptionString[0] + 7, 21 * sizeof (CHAR16), L"%02d", QuestionValue->Value.time.Second);
   1349         }
   1350         *(OptionString[0] + 9) = RIGHT_NUMERIC_DELIMITER;
   1351         break;
   1352       }
   1353     }
   1354     break;
   1355 
   1356   case EFI_IFR_STRING_OP:
   1357     if (Selected) {
   1358       StringPtr = AllocateZeroPool (Question->CurrentValue.BufferLen + sizeof (CHAR16));
   1359       ASSERT (StringPtr);
   1360       CopyMem(StringPtr, Question->CurrentValue.Buffer, Question->CurrentValue.BufferLen);
   1361 
   1362       Status = ReadString (MenuOption, gPromptForData, StringPtr);
   1363       if (EFI_ERROR (Status)) {
   1364         FreePool (StringPtr);
   1365         return Status;
   1366       }
   1367 
   1368       gUserInput->InputValue.Buffer = AllocateCopyPool (Question->CurrentValue.BufferLen, StringPtr);
   1369       gUserInput->InputValue.BufferLen = Question->CurrentValue.BufferLen;
   1370       gUserInput->InputValue.Type = Question->CurrentValue.Type;
   1371       gUserInput->InputValue.Value.string = HiiSetString(gFormData->HiiHandle, gUserInput->InputValue.Value.string, StringPtr, NULL);
   1372       FreePool (StringPtr);
   1373       return EFI_SUCCESS;
   1374     } else {
   1375       *OptionString = AllocateZeroPool (BufferSize);
   1376       ASSERT (*OptionString);
   1377 
   1378       if (((CHAR16 *) Question->CurrentValue.Buffer)[0] == 0x0000) {
   1379         *(OptionString[0]) = '_';
   1380       } else {
   1381         if (Question->CurrentValue.BufferLen < BufferSize) {
   1382           BufferSize = Question->CurrentValue.BufferLen;
   1383         }
   1384         CopyMem (OptionString[0], (CHAR16 *) Question->CurrentValue.Buffer, BufferSize);
   1385       }
   1386     }
   1387     break;
   1388 
   1389   case EFI_IFR_PASSWORD_OP:
   1390     if (Selected) {
   1391       Status = PasswordProcess (MenuOption);
   1392     }
   1393     break;
   1394 
   1395   default:
   1396     break;
   1397   }
   1398 
   1399   return Status;
   1400 }
   1401 
   1402 
   1403 /**
   1404   Process the help string: Split StringPtr to several lines of strings stored in
   1405   FormattedString and the glyph width of each line cannot exceed gHelpBlockWidth.
   1406 
   1407   @param  StringPtr              The entire help string.
   1408   @param  FormattedString        The oupput formatted string.
   1409   @param  EachLineWidth          The max string length of each line in the formatted string.
   1410   @param  RowCount               TRUE: if Question is selected.
   1411 
   1412 **/
   1413 UINTN
   1414 ProcessHelpString (
   1415   IN  CHAR16  *StringPtr,
   1416   OUT CHAR16  **FormattedString,
   1417   OUT UINT16  *EachLineWidth,
   1418   IN  UINTN   RowCount
   1419   )
   1420 {
   1421   UINTN   Index;
   1422   CHAR16  *OutputString;
   1423   UINTN   TotalRowNum;
   1424   UINTN   CheckedNum;
   1425   UINT16  GlyphWidth;
   1426   UINT16  LineWidth;
   1427   UINT16  MaxStringLen;
   1428   UINT16  StringLen;
   1429 
   1430   TotalRowNum    = 0;
   1431   CheckedNum     = 0;
   1432   GlyphWidth     = 1;
   1433   Index          = 0;
   1434   MaxStringLen   = 0;
   1435   StringLen      = 0;
   1436 
   1437   //
   1438   // Set default help string width.
   1439   //
   1440   LineWidth      = (UINT16) (gHelpBlockWidth - 1);
   1441 
   1442   //
   1443   // Get row number of the String.
   1444   //
   1445   while ((StringLen = GetLineByWidth (StringPtr, LineWidth, &GlyphWidth, &Index, &OutputString)) != 0) {
   1446     if (StringLen > MaxStringLen) {
   1447       MaxStringLen = StringLen;
   1448     }
   1449 
   1450     TotalRowNum ++;
   1451     FreePool (OutputString);
   1452   }
   1453   *EachLineWidth = MaxStringLen;
   1454 
   1455   *FormattedString = AllocateZeroPool (TotalRowNum * MaxStringLen * sizeof (CHAR16));
   1456   ASSERT (*FormattedString != NULL);
   1457 
   1458   //
   1459   // Generate formatted help string array.
   1460   //
   1461   GlyphWidth  = 1;
   1462   Index       = 0;
   1463   while((StringLen = GetLineByWidth (StringPtr, LineWidth, &GlyphWidth, &Index, &OutputString)) != 0) {
   1464     CopyMem (*FormattedString + CheckedNum * MaxStringLen, OutputString, StringLen * sizeof (CHAR16));
   1465     CheckedNum ++;
   1466     FreePool (OutputString);
   1467   }
   1468 
   1469   return TotalRowNum;
   1470 }
   1471