Home | History | Annotate | Download | only in DisplayEngineDxe
      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
     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     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
    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
   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