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