1 /** @file
2 
3   This library class defines a set of interfaces to customize Display module
4 
5 Copyright (c) 2013-2018, Intel Corporation. All rights reserved.<BR>
6 SPDX-License-Identifier: BSD-2-Clause-Patent
7 
8 **/
9 #include "CustomizedDisplayLibInternal.h"
10 
11 EFI_SCREEN_DESCRIPTOR         gScreenDimensions;
12 CHAR16                        *mLibUnknownString;
13 extern EFI_HII_HANDLE         mCDLStringPackHandle;
14 CHAR16                        *mSpaceBuffer;
15 #define SPACE_BUFFER_SIZE      1000
16 
17 //
18 // Browser Global Strings
19 //
20 CHAR16            *gEnterString;
21 CHAR16            *gEnterCommitString;
22 CHAR16            *gEnterEscapeString;
23 CHAR16            *gEscapeString;
24 CHAR16            *gMoveHighlight;
25 CHAR16            *gDecNumericInput;
26 CHAR16            *gHexNumericInput;
27 CHAR16            *gToggleCheckBox;
28 CHAR16            *gLibEmptyString;
29 CHAR16            *gAreYouSure;
30 CHAR16            *gYesResponse;
31 CHAR16            *gNoResponse;
32 CHAR16            *gPlusString;
33 CHAR16            *gMinusString;
34 CHAR16            *gAdjustNumber;
35 CHAR16            *gSaveChanges;
36 CHAR16            *gNvUpdateMessage;
37 CHAR16            *gInputErrorMessage;
38 
39 /**
40 
41   Print banner info for front page.
42 
43   @param[in]  FormData             Form Data to be shown in Page
44 
45 **/
46 VOID
PrintBannerInfo(IN FORM_DISPLAY_ENGINE_FORM * FormData)47 PrintBannerInfo (
48   IN FORM_DISPLAY_ENGINE_FORM       *FormData
49   )
50 {
51   UINT8                  Line;
52   UINT8                  Alignment;
53   CHAR16                 *StrFrontPageBanner;
54   UINT8                  RowIdx;
55   UINT8                  ColumnIdx;
56 
57   //
58   //    ClearLines(0, LocalScreen.RightColumn, 0, BANNER_HEIGHT-1, BANNER_TEXT | BANNER_BACKGROUND);
59   //
60   ClearLines (
61     gScreenDimensions.LeftColumn,
62     gScreenDimensions.RightColumn,
63     gScreenDimensions.TopRow,
64     FRONT_PAGE_HEADER_HEIGHT - 1 + gScreenDimensions.TopRow,
65     BANNER_TEXT | BANNER_BACKGROUND
66     );
67 
68   //
69   //    for (Line = 0; Line < BANNER_HEIGHT; Line++) {
70   //
71   for (Line = (UINT8) gScreenDimensions.TopRow; Line < BANNER_HEIGHT + (UINT8) gScreenDimensions.TopRow; Line++) {
72     //
73     //      for (Alignment = 0; Alignment < BANNER_COLUMNS; Alignment++) {
74     //
75     for (Alignment = (UINT8) gScreenDimensions.LeftColumn;
76          Alignment < BANNER_COLUMNS + (UINT8) gScreenDimensions.LeftColumn;
77          Alignment++
78         ) {
79       RowIdx    = (UINT8) (Line - (UINT8) gScreenDimensions.TopRow);
80       ColumnIdx = (UINT8) (Alignment - (UINT8) gScreenDimensions.LeftColumn);
81 
82       ASSERT (RowIdx < BANNER_HEIGHT && ColumnIdx < BANNER_COLUMNS);
83 
84       if (gBannerData!= NULL && gBannerData->Banner[RowIdx][ColumnIdx] != 0x0000) {
85         StrFrontPageBanner = LibGetToken (gBannerData->Banner[RowIdx][ColumnIdx], FormData->HiiHandle);
86       } else {
87         continue;
88       }
89 
90       switch (Alignment - gScreenDimensions.LeftColumn) {
91       case 0:
92         //
93         // Handle left column
94         //
95         PrintStringAt (gScreenDimensions.LeftColumn + BANNER_LEFT_COLUMN_INDENT, Line, StrFrontPageBanner);
96         break;
97 
98       case 1:
99         //
100         // Handle center column
101         //
102         PrintStringAt (
103           gScreenDimensions.LeftColumn + (gScreenDimensions.RightColumn - gScreenDimensions.LeftColumn) / 3,
104           Line,
105           StrFrontPageBanner
106           );
107         break;
108 
109       case 2:
110         //
111         // Handle right column
112         //
113         PrintStringAt (
114           gScreenDimensions.LeftColumn + (gScreenDimensions.RightColumn - gScreenDimensions.LeftColumn) * 2 / 3,
115           Line,
116           StrFrontPageBanner
117           );
118         break;
119       }
120 
121       FreePool (StrFrontPageBanner);
122     }
123   }
124 }
125 
126 /**
127   Print framework and form title for a page.
128 
129   @param[in]  FormData             Form Data to be shown in Page
130 **/
131 VOID
PrintFramework(IN FORM_DISPLAY_ENGINE_FORM * FormData)132 PrintFramework (
133   IN FORM_DISPLAY_ENGINE_FORM       *FormData
134   )
135 {
136   UINTN                  Index;
137   CHAR16                 Character;
138   CHAR16                 *Buffer;
139   UINTN                  Row;
140   CHAR16                 *TitleStr;
141   UINTN                  TitleColumn;
142 
143   if (gClassOfVfr != FORMSET_CLASS_PLATFORM_SETUP) {
144     //
145     // Only Setup page needs Framework
146     //
147     ClearLines (
148       gScreenDimensions.LeftColumn,
149       gScreenDimensions.RightColumn,
150       gScreenDimensions.BottomRow - STATUS_BAR_HEIGHT - gFooterHeight,
151       gScreenDimensions.BottomRow - STATUS_BAR_HEIGHT - 1,
152       KEYHELP_TEXT | KEYHELP_BACKGROUND
153       );
154     return;
155   }
156 
157   Buffer = AllocateZeroPool (0x10000);
158   ASSERT (Buffer != NULL);
159   Character = BOXDRAW_HORIZONTAL;
160   for (Index = 0; Index + 2 < (gScreenDimensions.RightColumn - gScreenDimensions.LeftColumn); Index++) {
161     Buffer[Index] = Character;
162   }
163 
164   //
165   // Print Top border line
166   // +------------------------------------------------------------------------------+
167   // ?                                                                             ?
168   // +------------------------------------------------------------------------------+
169   //
170   gST->ConOut->SetAttribute (gST->ConOut, TITLE_TEXT | TITLE_BACKGROUND);
171   Character = BOXDRAW_DOWN_RIGHT;
172 
173   PrintCharAt (gScreenDimensions.LeftColumn, gScreenDimensions.TopRow, Character);
174   PrintStringAt ((UINTN) -1, (UINTN) -1, Buffer);
175 
176   Character = BOXDRAW_DOWN_LEFT;
177   PrintCharAt ((UINTN) -1, (UINTN) -1, Character);
178 
179   Character = BOXDRAW_VERTICAL;
180   for (Row = gScreenDimensions.TopRow + 1; Row <= gScreenDimensions.TopRow + NONE_FRONT_PAGE_HEADER_HEIGHT - 2; Row++) {
181     PrintCharAt (gScreenDimensions.LeftColumn, Row, Character);
182     PrintCharAt (gScreenDimensions.RightColumn - 1, Row, Character);
183   }
184 
185   //
186   // Print Form Title
187   //
188   TitleStr = LibGetToken (FormData->FormTitle, FormData->HiiHandle);
189   ASSERT (TitleStr != NULL);
190   TitleColumn = (gScreenDimensions.RightColumn + gScreenDimensions.LeftColumn - LibGetStringWidth (TitleStr) / 2) / 2;
191   PrintStringAtWithWidth (gScreenDimensions.LeftColumn + 1, gScreenDimensions.TopRow + 1, gLibEmptyString, TitleColumn - gScreenDimensions.LeftColumn - 1);
192   PrintStringAtWithWidth (
193     TitleColumn,
194     gScreenDimensions.TopRow + 1,
195     TitleStr,
196     gScreenDimensions.RightColumn - 1 - TitleColumn
197     );
198   FreePool (TitleStr);
199 
200   Character = BOXDRAW_UP_RIGHT;
201   PrintCharAt (gScreenDimensions.LeftColumn, gScreenDimensions.TopRow + NONE_FRONT_PAGE_HEADER_HEIGHT - 1, Character);
202   PrintStringAt ((UINTN) -1, (UINTN) -1, Buffer);
203 
204   Character = BOXDRAW_UP_LEFT;
205   PrintCharAt ((UINTN) -1, (UINTN) -1, Character);
206 
207   //
208   // Print Bottom border line
209   // +------------------------------------------------------------------------------+
210   // ?                                                                             ?
211   // +------------------------------------------------------------------------------+
212   //
213   Character = BOXDRAW_DOWN_RIGHT;
214   PrintCharAt (gScreenDimensions.LeftColumn, gScreenDimensions.BottomRow - STATUS_BAR_HEIGHT - gFooterHeight, Character);
215 
216   PrintStringAt ((UINTN) -1, (UINTN) -1, Buffer);
217 
218   Character = BOXDRAW_DOWN_LEFT;
219   PrintCharAt ((UINTN) -1, (UINTN) -1, Character);
220   Character = BOXDRAW_VERTICAL;
221   for (Row = gScreenDimensions.BottomRow - STATUS_BAR_HEIGHT - gFooterHeight + 1;
222        Row <= gScreenDimensions.BottomRow - STATUS_BAR_HEIGHT - 2;
223        Row++
224       ) {
225     PrintCharAt (gScreenDimensions.LeftColumn, Row, Character);
226     PrintCharAt (gScreenDimensions.RightColumn - 1, Row, Character);
227   }
228 
229   Character = BOXDRAW_UP_RIGHT;
230   PrintCharAt (gScreenDimensions.LeftColumn, gScreenDimensions.BottomRow - STATUS_BAR_HEIGHT - 1, Character);
231 
232   PrintStringAt ((UINTN) -1, (UINTN) -1, Buffer);
233 
234   Character = BOXDRAW_UP_LEFT;
235   PrintCharAt ((UINTN) -1, (UINTN) -1, Character);
236 
237   FreePool (Buffer);
238 }
239 
240 /**
241   Process some op code which is not recognized by browser core.
242 
243   @param OpCodeData                  The pointer to the op code buffer.
244 
245   @return EFI_SUCCESS            Pass the statement success.
246 
247 **/
248 VOID
ProcessUserOpcode(IN EFI_IFR_OP_HEADER * OpCodeData)249 ProcessUserOpcode(
250   IN  EFI_IFR_OP_HEADER         *OpCodeData
251   )
252 {
253   EFI_GUID *   ClassGuid;
254   UINT8        ClassGuidNum;
255 
256   ClassGuid    = NULL;
257   ClassGuidNum = 0;
258 
259   switch (OpCodeData->OpCode) {
260     case EFI_IFR_FORM_SET_OP:
261       //
262       // process the statement outside of form,if it is formset op, get its formsetguid or classguid and compared with gFrontPageFormSetGuid
263       //
264       if (CompareMem (PcdGetPtr (PcdFrontPageFormSetGuid), &((EFI_IFR_FORM_SET *) OpCodeData)->Guid, sizeof (EFI_GUID)) == 0){
265         gClassOfVfr = FORMSET_CLASS_FRONT_PAGE;
266       } else{
267         ClassGuidNum = (UINT8)(((EFI_IFR_FORM_SET *)OpCodeData)->Flags & 0x3);
268         ClassGuid    = (EFI_GUID *)(VOID *)((UINT8 *)OpCodeData + sizeof (EFI_IFR_FORM_SET));
269         while (ClassGuidNum-- > 0){
270           if (CompareGuid((EFI_GUID*)PcdGetPtr (PcdFrontPageFormSetGuid),ClassGuid)){
271             gClassOfVfr = FORMSET_CLASS_FRONT_PAGE;
272             break;
273           }
274           ClassGuid ++;
275         }
276       }
277       break;
278 
279     case EFI_IFR_GUID_OP:
280       if (CompareGuid (&gEfiIfrTianoGuid, (EFI_GUID *)((CHAR8*) OpCodeData + sizeof (EFI_IFR_OP_HEADER)))) {
281         //
282         // Tiano specific GUIDed opcodes
283         //
284         switch (((EFI_IFR_GUID_LABEL *) OpCodeData)->ExtendOpCode) {
285         case EFI_IFR_EXTEND_OP_LABEL:
286           //
287           // just ignore label
288           //
289           break;
290 
291         case EFI_IFR_EXTEND_OP_BANNER:
292           //
293           // Only in front page form set, we care about the banner data.
294           //
295           if (gClassOfVfr == FORMSET_CLASS_FRONT_PAGE) {
296             //
297             // Initialize Driver private data
298             //
299             if (gBannerData == NULL) {
300               gBannerData = AllocateZeroPool (sizeof (BANNER_DATA));
301               ASSERT (gBannerData != NULL);
302             }
303 
304             CopyMem (
305               &gBannerData->Banner[((EFI_IFR_GUID_BANNER *) OpCodeData)->LineNumber][
306               ((EFI_IFR_GUID_BANNER *) OpCodeData)->Alignment],
307               &((EFI_IFR_GUID_BANNER *) OpCodeData)->Title,
308               sizeof (EFI_STRING_ID)
309               );
310           }
311           break;
312 
313         case EFI_IFR_EXTEND_OP_SUBCLASS:
314           if (((EFI_IFR_GUID_SUBCLASS *) OpCodeData)->SubClass == EFI_FRONT_PAGE_SUBCLASS) {
315             gClassOfVfr = FORMSET_CLASS_FRONT_PAGE;
316           }
317           break;
318 
319         default:
320           break;
321         }
322       }
323       break;
324 
325     default:
326       break;
327   }
328 }
329 
330 /**
331   Process some op codes which is out side of current form.
332 
333   @param FormData                Pointer to the form data.
334 
335   @return EFI_SUCCESS            Pass the statement success.
336 
337 **/
338 VOID
ProcessExternedOpcode(IN FORM_DISPLAY_ENGINE_FORM * FormData)339 ProcessExternedOpcode (
340   IN FORM_DISPLAY_ENGINE_FORM       *FormData
341   )
342 {
343   LIST_ENTRY                    *Link;
344   LIST_ENTRY                    *NestLink;
345   FORM_DISPLAY_ENGINE_STATEMENT *Statement;
346   FORM_DISPLAY_ENGINE_STATEMENT *NestStatement;
347 
348   Link = GetFirstNode (&FormData->StatementListOSF);
349   while (!IsNull (&FormData->StatementListOSF, Link)) {
350     Statement = FORM_DISPLAY_ENGINE_STATEMENT_FROM_LINK (Link);
351     Link = GetNextNode (&FormData->StatementListOSF, Link);
352 
353     ProcessUserOpcode(Statement->OpCode);
354   }
355 
356   Link = GetFirstNode (&FormData->StatementListHead);
357   while (!IsNull (&FormData->StatementListHead, Link)) {
358     Statement = FORM_DISPLAY_ENGINE_STATEMENT_FROM_LINK (Link);
359     Link = GetNextNode (&FormData->StatementListHead, Link);
360 
361     ProcessUserOpcode(Statement->OpCode);
362 
363     NestLink = GetFirstNode (&Statement->NestStatementList);
364     while (!IsNull (&Statement->NestStatementList, NestLink)) {
365       NestStatement = FORM_DISPLAY_ENGINE_STATEMENT_FROM_LINK (NestLink);
366       NestLink = GetNextNode (&Statement->NestStatementList, NestLink);
367 
368       ProcessUserOpcode(NestStatement->OpCode);
369     }
370 
371   }
372 }
373 
374 /**
375   Validate the input screen diemenstion info.
376 
377   @param  FormData               The input form data info.
378 
379   @return EFI_SUCCESS            The input screen info is acceptable.
380   @return EFI_INVALID_PARAMETER  The input screen info is not acceptable.
381 
382 **/
383 EFI_STATUS
ScreenDiemensionInfoValidate(IN FORM_DISPLAY_ENGINE_FORM * FormData)384 ScreenDiemensionInfoValidate (
385   IN FORM_DISPLAY_ENGINE_FORM       *FormData
386   )
387 {
388   LIST_ENTRY           *Link;
389   UINTN                Index;
390 
391   //
392   // Calculate total number of Register HotKeys.
393   //
394   Index = 0;
395   if (!IsListEmpty (&FormData->HotKeyListHead)){
396     Link  = GetFirstNode (&FormData->HotKeyListHead);
397     while (!IsNull (&FormData->HotKeyListHead, Link)) {
398       Link = GetNextNode (&FormData->HotKeyListHead, Link);
399       Index ++;
400     }
401   }
402 
403   //
404   // Show three HotKeys help information on one row.
405   //
406   gFooterHeight = FOOTER_HEIGHT + (Index / 3);
407 
408 
409   ZeroMem (&gScreenDimensions, sizeof (EFI_SCREEN_DESCRIPTOR));
410   gST->ConOut->QueryMode (
411                  gST->ConOut,
412                  gST->ConOut->Mode->Mode,
413                  &gScreenDimensions.RightColumn,
414                  &gScreenDimensions.BottomRow
415                  );
416 
417   //
418   // Check local dimension vs. global dimension.
419   //
420   if (FormData->ScreenDimensions != NULL) {
421     if ((gScreenDimensions.RightColumn < FormData->ScreenDimensions->RightColumn) ||
422         (gScreenDimensions.BottomRow < FormData->ScreenDimensions->BottomRow)
423         ) {
424       return EFI_INVALID_PARAMETER;
425     } else {
426       //
427       // Local dimension validation.
428       //
429       if ((FormData->ScreenDimensions->RightColumn > FormData->ScreenDimensions->LeftColumn) &&
430           (FormData->ScreenDimensions->BottomRow > FormData->ScreenDimensions->TopRow) &&
431           ((FormData->ScreenDimensions->RightColumn - FormData->ScreenDimensions->LeftColumn) > 2) &&
432           ((FormData->ScreenDimensions->BottomRow - FormData->ScreenDimensions->TopRow) > STATUS_BAR_HEIGHT +
433             FRONT_PAGE_HEADER_HEIGHT + gFooterHeight + 3)) {
434         CopyMem (&gScreenDimensions, (VOID *) FormData->ScreenDimensions, sizeof (EFI_SCREEN_DESCRIPTOR));
435       } else {
436         return EFI_INVALID_PARAMETER;
437       }
438     }
439   }
440 
441   return EFI_SUCCESS;
442 }
443 
444 /**
445   Get the string based on the StringId and HII Package List Handle.
446 
447   @param  Token                  The String's ID.
448   @param  HiiHandle              The package list in the HII database to search for
449                                  the specified string.
450 
451   @return The output string.
452 
453 **/
454 CHAR16 *
LibGetToken(IN EFI_STRING_ID Token,IN EFI_HII_HANDLE HiiHandle)455 LibGetToken (
456   IN  EFI_STRING_ID                Token,
457   IN  EFI_HII_HANDLE               HiiHandle
458   )
459 {
460   EFI_STRING  String;
461 
462   String = HiiGetString (HiiHandle, Token, NULL);
463   if (String == NULL) {
464     String = AllocateCopyPool (StrSize (mLibUnknownString), mLibUnknownString);
465     ASSERT (String != NULL);
466   }
467 
468   return (CHAR16 *) String;
469 }
470 
471 
472 /**
473   Count the storage space of a Unicode string.
474 
475   This function handles the Unicode string with NARROW_CHAR
476   and WIDE_CHAR control characters. NARROW_HCAR and WIDE_CHAR
477   does not count in the resultant output. If a WIDE_CHAR is
478   hit, then 2 Unicode character will consume an output storage
479   space with size of CHAR16 till a NARROW_CHAR is hit.
480 
481   If String is NULL, then ASSERT ().
482 
483   @param String          The input string to be counted.
484 
485   @return Storage space for the input string.
486 
487 **/
488 UINTN
LibGetStringWidth(IN CHAR16 * String)489 LibGetStringWidth (
490   IN CHAR16               *String
491   )
492 {
493   UINTN Index;
494   UINTN Count;
495   UINTN IncrementValue;
496 
497   ASSERT (String != NULL);
498   if (String == NULL) {
499     return 0;
500   }
501 
502   Index           = 0;
503   Count           = 0;
504   IncrementValue  = 1;
505 
506   do {
507     //
508     // Advance to the null-terminator or to the first width directive
509     //
510     for (;
511          (String[Index] != NARROW_CHAR) && (String[Index] != WIDE_CHAR) && (String[Index] != 0);
512          Index++, Count = Count + IncrementValue
513         )
514       ;
515 
516     //
517     // We hit the null-terminator, we now have a count
518     //
519     if (String[Index] == 0) {
520       break;
521     }
522     //
523     // We encountered a narrow directive - strip it from the size calculation since it doesn't get printed
524     // and also set the flag that determines what we increment by.(if narrow, increment by 1, if wide increment by 2)
525     //
526     if (String[Index] == NARROW_CHAR) {
527       //
528       // Skip to the next character
529       //
530       Index++;
531       IncrementValue = 1;
532     } else {
533       //
534       // Skip to the next character
535       //
536       Index++;
537       IncrementValue = 2;
538     }
539   } while (String[Index] != 0);
540 
541   //
542   // Increment by one to include the null-terminator in the size
543   //
544   Count++;
545 
546   return Count * sizeof (CHAR16);
547 }
548 
549 /**
550   Show all registered HotKey help strings on bottom Rows.
551 
552   @param FormData          The curent input form data info.
553   @param SetState          Set HotKey or Clear HotKey
554 
555 **/
556 VOID
PrintHotKeyHelpString(IN FORM_DISPLAY_ENGINE_FORM * FormData,IN BOOLEAN SetState)557 PrintHotKeyHelpString (
558   IN FORM_DISPLAY_ENGINE_FORM      *FormData,
559   IN BOOLEAN                       SetState
560   )
561 {
562   UINTN                  CurrentCol;
563   UINTN                  CurrentRow;
564   UINTN                  BottomRowOfHotKeyHelp;
565   UINTN                  ColumnIndexWidth;
566   UINTN                  ColumnWidth;
567   UINTN                  ColumnIndex;
568   UINTN                  Index;
569   EFI_SCREEN_DESCRIPTOR  LocalScreen;
570   LIST_ENTRY             *Link;
571   BROWSER_HOT_KEY        *HotKey;
572   CHAR16                 BakChar;
573   CHAR16                 *ColumnStr;
574 
575   CopyMem (&LocalScreen, &gScreenDimensions, sizeof (EFI_SCREEN_DESCRIPTOR));
576   ColumnWidth            = (LocalScreen.RightColumn - LocalScreen.LeftColumn) / 3;
577   BottomRowOfHotKeyHelp  = LocalScreen.BottomRow - STATUS_BAR_HEIGHT - 3;
578   ColumnStr              = gLibEmptyString;
579 
580   //
581   // Calculate total number of Register HotKeys.
582   //
583   Index = 0;
584   Link  = GetFirstNode (&FormData->HotKeyListHead);
585   while (!IsNull (&FormData->HotKeyListHead, Link)) {
586     HotKey = BROWSER_HOT_KEY_FROM_LINK (Link);
587     //
588     // Calculate help information Column and Row.
589     //
590     ColumnIndex = Index % 3;
591     if (ColumnIndex == 0) {
592       CurrentCol       = LocalScreen.LeftColumn + 2 * ColumnWidth;
593       ColumnIndexWidth = ColumnWidth - 1;
594     } else if (ColumnIndex == 1) {
595       CurrentCol       = LocalScreen.LeftColumn + ColumnWidth;
596       ColumnIndexWidth = ColumnWidth;
597     } else {
598       CurrentCol       = LocalScreen.LeftColumn + 2;
599       ColumnIndexWidth = ColumnWidth - 2;
600     }
601     CurrentRow = BottomRowOfHotKeyHelp - Index / 3;
602 
603     //
604     // Help string can't exceed ColumnWidth. One Row will show three Help information.
605     //
606     BakChar = L'\0';
607     if (StrLen (HotKey->HelpString) > ColumnIndexWidth) {
608       BakChar = HotKey->HelpString[ColumnIndexWidth];
609       HotKey->HelpString[ColumnIndexWidth] = L'\0';
610     }
611 
612     //
613     // Print HotKey help string on bottom Row.
614     //
615     if (SetState) {
616       ColumnStr = HotKey->HelpString;
617     }
618     PrintStringAtWithWidth (CurrentCol, CurrentRow, ColumnStr, ColumnIndexWidth);
619 
620     if (BakChar != L'\0') {
621       HotKey->HelpString[ColumnIndexWidth] = BakChar;
622     }
623     //
624     // Get Next Hot Key.
625     //
626     Link = GetNextNode (&FormData->HotKeyListHead, Link);
627     Index ++;
628   }
629 
630   if (SetState) {
631     //
632     // Clear KeyHelp
633     //
634     CurrentRow  = BottomRowOfHotKeyHelp - Index / 3;
635     ColumnIndex = Index % 3;
636     if (ColumnIndex == 0) {
637       CurrentCol       = LocalScreen.LeftColumn + 2 * ColumnWidth;
638       ColumnIndexWidth = ColumnWidth - 1;
639       ColumnIndex ++;
640       PrintStringAtWithWidth (CurrentCol, CurrentRow, gLibEmptyString, ColumnIndexWidth);
641     }
642     if (ColumnIndex == 1) {
643       CurrentCol       = LocalScreen.LeftColumn + ColumnWidth;
644       ColumnIndexWidth = ColumnWidth;
645       PrintStringAtWithWidth (CurrentCol, CurrentRow, gLibEmptyString, ColumnIndexWidth);
646     }
647   }
648 
649   return;
650 }
651 
652 /**
653   Get step info from numeric opcode.
654 
655   @param[in] OpCode     The input numeric op code.
656 
657   @return step info for this opcode.
658 **/
659 UINT64
LibGetFieldFromNum(IN EFI_IFR_OP_HEADER * OpCode)660 LibGetFieldFromNum (
661   IN  EFI_IFR_OP_HEADER     *OpCode
662   )
663 {
664   EFI_IFR_NUMERIC       *NumericOp;
665   UINT64                Step;
666 
667   NumericOp = (EFI_IFR_NUMERIC *) OpCode;
668 
669   switch (NumericOp->Flags & EFI_IFR_NUMERIC_SIZE) {
670   case EFI_IFR_NUMERIC_SIZE_1:
671     Step    = NumericOp->data.u8.Step;
672     break;
673 
674   case EFI_IFR_NUMERIC_SIZE_2:
675     Step    = NumericOp->data.u16.Step;
676     break;
677 
678   case EFI_IFR_NUMERIC_SIZE_4:
679     Step    = NumericOp->data.u32.Step;
680     break;
681 
682   case EFI_IFR_NUMERIC_SIZE_8:
683     Step    = NumericOp->data.u64.Step;
684     break;
685 
686   default:
687     Step = 0;
688     break;
689   }
690 
691   return Step;
692 }
693 
694 /**
695   Initialize the HII String Token to the correct values.
696 
697 **/
698 VOID
InitializeLibStrings(VOID)699 InitializeLibStrings (
700   VOID
701   )
702 {
703   mLibUnknownString        = L"!";
704 
705   gEnterString          = LibGetToken (STRING_TOKEN (ENTER_STRING), mCDLStringPackHandle);
706   gEnterCommitString    = LibGetToken (STRING_TOKEN (ENTER_COMMIT_STRING), mCDLStringPackHandle);
707   gEnterEscapeString    = LibGetToken (STRING_TOKEN (ENTER_ESCAPE_STRING), mCDLStringPackHandle);
708   gEscapeString         = LibGetToken (STRING_TOKEN (ESCAPE_STRING), mCDLStringPackHandle);
709   gMoveHighlight        = LibGetToken (STRING_TOKEN (MOVE_HIGHLIGHT), mCDLStringPackHandle);
710   gDecNumericInput      = LibGetToken (STRING_TOKEN (DEC_NUMERIC_INPUT), mCDLStringPackHandle);
711   gHexNumericInput      = LibGetToken (STRING_TOKEN (HEX_NUMERIC_INPUT), mCDLStringPackHandle);
712   gToggleCheckBox       = LibGetToken (STRING_TOKEN (TOGGLE_CHECK_BOX), mCDLStringPackHandle);
713 
714   gAreYouSure           = LibGetToken (STRING_TOKEN (ARE_YOU_SURE), mCDLStringPackHandle);
715   gYesResponse          = LibGetToken (STRING_TOKEN (ARE_YOU_SURE_YES), mCDLStringPackHandle);
716   gNoResponse           = LibGetToken (STRING_TOKEN (ARE_YOU_SURE_NO), mCDLStringPackHandle);
717   gPlusString           = LibGetToken (STRING_TOKEN (PLUS_STRING), mCDLStringPackHandle);
718   gMinusString          = LibGetToken (STRING_TOKEN (MINUS_STRING), mCDLStringPackHandle);
719   gAdjustNumber         = LibGetToken (STRING_TOKEN (ADJUST_NUMBER), mCDLStringPackHandle);
720   gSaveChanges          = LibGetToken (STRING_TOKEN (SAVE_CHANGES), mCDLStringPackHandle);
721 
722   gLibEmptyString       = LibGetToken (STRING_TOKEN (EMPTY_STRING), mCDLStringPackHandle);
723 
724   gNvUpdateMessage      = LibGetToken (STRING_TOKEN (NV_UPDATE_MESSAGE), mCDLStringPackHandle);
725   gInputErrorMessage    = LibGetToken (STRING_TOKEN (INPUT_ERROR_MESSAGE), mCDLStringPackHandle);
726 
727   //
728   // SpaceBuffer;
729   //
730   mSpaceBuffer = AllocatePool ((SPACE_BUFFER_SIZE + 1) * sizeof (CHAR16));
731   ASSERT (mSpaceBuffer != NULL);
732   LibSetUnicodeMem (mSpaceBuffer, SPACE_BUFFER_SIZE, L' ');
733   mSpaceBuffer[SPACE_BUFFER_SIZE] = L'\0';
734 }
735 
736 
737 /**
738   Free the HII String.
739 
740 **/
741 VOID
FreeLibStrings(VOID)742 FreeLibStrings (
743   VOID
744   )
745 {
746   FreePool (gEnterString);
747   FreePool (gEnterCommitString);
748   FreePool (gEnterEscapeString);
749   FreePool (gEscapeString);
750   FreePool (gMoveHighlight);
751   FreePool (gDecNumericInput);
752   FreePool (gHexNumericInput);
753   FreePool (gToggleCheckBox);
754 
755   FreePool (gAreYouSure);
756   FreePool (gYesResponse);
757   FreePool (gNoResponse);
758   FreePool (gPlusString);
759   FreePool (gMinusString);
760   FreePool (gAdjustNumber);
761   FreePool (gSaveChanges);
762 
763   FreePool (gLibEmptyString);
764 
765   FreePool (gNvUpdateMessage);
766   FreePool (gInputErrorMessage);
767 
768   FreePool (mSpaceBuffer);
769 }
770 
771 /**
772   Wait for a key to be pressed by user.
773 
774   @param Key         The key which is pressed by user.
775 
776   @retval EFI_SUCCESS The function always completed successfully.
777 
778 **/
779 EFI_STATUS
WaitForKeyStroke(OUT EFI_INPUT_KEY * Key)780 WaitForKeyStroke (
781   OUT  EFI_INPUT_KEY           *Key
782   )
783 {
784   EFI_STATUS  Status;
785   UINTN       Index;
786 
787   while (TRUE) {
788     Status = gST->ConIn->ReadKeyStroke (gST->ConIn, Key);
789     if (!EFI_ERROR (Status)) {
790       break;
791     }
792 
793     if (Status != EFI_NOT_READY) {
794       continue;
795     }
796 
797     gBS->WaitForEvent (1, &gST->ConIn->WaitForKey, &Index);
798   }
799   return Status;
800 }
801 
802 
803 /**
804   Set Buffer to Value for Size bytes.
805 
806   @param  Buffer                 Memory to set.
807   @param  Size                   Number of bytes to set
808   @param  Value                  Value of the set operation.
809 
810 **/
811 VOID
LibSetUnicodeMem(IN VOID * Buffer,IN UINTN Size,IN CHAR16 Value)812 LibSetUnicodeMem (
813   IN VOID   *Buffer,
814   IN UINTN  Size,
815   IN CHAR16 Value
816   )
817 {
818   CHAR16  *Ptr;
819 
820   Ptr = Buffer;
821   while ((Size--)  != 0) {
822     *(Ptr++) = Value;
823   }
824 }
825 
826 /**
827   The internal function prints to the EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL
828   protocol instance.
829 
830   @param Width           Width of string to be print.
831   @param Column          The position of the output string.
832   @param Row             The position of the output string.
833   @param Out             The EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL instance.
834   @param Fmt             The format string.
835   @param Args            The additional argument for the variables in the format string.
836 
837   @return Number of Unicode character printed.
838 
839 **/
840 UINTN
PrintInternal(IN UINTN Width,IN UINTN Column,IN UINTN Row,IN EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL * Out,IN CHAR16 * Fmt,IN VA_LIST Args)841 PrintInternal (
842   IN UINTN                            Width,
843   IN UINTN                            Column,
844   IN UINTN                            Row,
845   IN EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL  *Out,
846   IN CHAR16                           *Fmt,
847   IN VA_LIST                          Args
848   )
849 {
850   CHAR16  *Buffer;
851   CHAR16  *BackupBuffer;
852   UINTN   Index;
853   UINTN   PreviousIndex;
854   UINTN   Count;
855   UINTN   TotalCount;
856   UINTN   PrintWidth;
857   UINTN   CharWidth;
858 
859   //
860   // For now, allocate an arbitrarily long buffer
861   //
862   Buffer        = AllocateZeroPool (0x10000);
863   BackupBuffer  = AllocateZeroPool (0x10000);
864   ASSERT (Buffer);
865   ASSERT (BackupBuffer);
866 
867   if (Column != (UINTN) -1) {
868     Out->SetCursorPosition (Out, Column, Row);
869   }
870 
871   UnicodeVSPrint (Buffer, 0x10000, Fmt, Args);
872 
873   Out->Mode->Attribute = Out->Mode->Attribute & 0x7f;
874 
875   Out->SetAttribute (Out, Out->Mode->Attribute);
876 
877   Index         = 0;
878   PreviousIndex = 0;
879   Count         = 0;
880   TotalCount    = 0;
881   PrintWidth    = 0;
882   CharWidth     = 1;
883 
884   do {
885     for (; (Buffer[Index] != NARROW_CHAR) && (Buffer[Index] != WIDE_CHAR) && (Buffer[Index] != 0); Index++) {
886       BackupBuffer[Index] = Buffer[Index];
887     }
888 
889     if (Buffer[Index] == 0) {
890       break;
891     }
892 
893     //
894     // Print this out, we are about to switch widths
895     //
896     Out->OutputString (Out, &BackupBuffer[PreviousIndex]);
897     Count = StrLen (&BackupBuffer[PreviousIndex]);
898     PrintWidth += Count * CharWidth;
899     TotalCount += Count;
900 
901     //
902     // Preserve the current index + 1, since this is where we will start printing from next
903     //
904     PreviousIndex = Index + 1;
905 
906     //
907     // We are at a narrow or wide character directive.  Set attributes and strip it and print it
908     //
909     if (Buffer[Index] == NARROW_CHAR) {
910       //
911       // Preserve bits 0 - 6 and zero out the rest
912       //
913       Out->Mode->Attribute = Out->Mode->Attribute & 0x7f;
914       Out->SetAttribute (Out, Out->Mode->Attribute);
915       CharWidth = 1;
916     } else {
917       //
918       // Must be wide, set bit 7 ON
919       //
920       Out->Mode->Attribute = Out->Mode->Attribute | EFI_WIDE_ATTRIBUTE;
921       Out->SetAttribute (Out, Out->Mode->Attribute);
922       CharWidth = 2;
923     }
924 
925     Index++;
926 
927   } while (Buffer[Index] != 0);
928 
929   //
930   // We hit the end of the string - print it
931   //
932   Out->OutputString (Out, &BackupBuffer[PreviousIndex]);
933   Count = StrLen (&BackupBuffer[PreviousIndex]);
934   PrintWidth += Count * CharWidth;
935   TotalCount += Count;
936   if (PrintWidth < Width) {
937     Out->Mode->Attribute = Out->Mode->Attribute & 0x7f;
938     Out->SetAttribute (Out, Out->Mode->Attribute);
939     Out->OutputString (Out, &mSpaceBuffer[SPACE_BUFFER_SIZE - Width + PrintWidth]);
940   }
941 
942   FreePool (Buffer);
943   FreePool (BackupBuffer);
944   return TotalCount;
945 }
946 
947 /**
948   Prints a formatted unicode string to the default console, at
949   the supplied cursor position.
950 
951   @param  Width      Width of String to be printed.
952   @param  Column     The cursor position to print the string at.
953   @param  Row        The cursor position to print the string at.
954   @param  Fmt        Format string.
955   @param  ...        Variable argument list for format string.
956 
957   @return Length of string printed to the console
958 
959 **/
960 UINTN
961 EFIAPI
PrintAt(IN UINTN Width,IN UINTN Column,IN UINTN Row,IN CHAR16 * Fmt,...)962 PrintAt (
963   IN UINTN     Width,
964   IN UINTN     Column,
965   IN UINTN     Row,
966   IN CHAR16    *Fmt,
967   ...
968   )
969 {
970   VA_LIST Args;
971   UINTN   LengthOfPrinted;
972 
973   VA_START (Args, Fmt);
974   LengthOfPrinted = PrintInternal (Width, Column, Row, gST->ConOut, Fmt, Args);
975   VA_END (Args);
976   return LengthOfPrinted;
977 }
978 
979