2. Added NULL pointer check before calling FreePool () to fix bugs when free memory. git-svn-id: https://edk2.svn.sourceforge.net/svnroot/edk2/trunk/edk2@2513 6f19259b-4bc3-4df7-8a09-765794883524
		
			
				
	
	
		
			1486 lines
		
	
	
		
			47 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
			
		
		
	
	
			1486 lines
		
	
	
		
			47 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
| /*++
 | |
| Copyright (c) 2006 - 2007, Intel Corporation
 | |
| All rights reserved. This program and the accompanying materials
 | |
| are licensed and made available under the terms and conditions of the BSD License
 | |
| which accompanies this distribution.  The full text of the license may be found at
 | |
| http://opensource.org/licenses/bsd-license.php
 | |
| 
 | |
| THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
 | |
| WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
 | |
| 
 | |
| Module Name:
 | |
|   Presentation.c
 | |
| 
 | |
| Abstract:
 | |
| 
 | |
|   Some presentation routines.
 | |
| 
 | |
| Revision History:
 | |
| 
 | |
| --*/
 | |
| 
 | |
| #include "Setup.h"
 | |
| #include "Ui.h"
 | |
| #include "Colors.h"
 | |
| 
 | |
| VOID
 | |
| ClearLines (
 | |
|   UINTN                                       LeftColumn,
 | |
|   UINTN                                       RightColumn,
 | |
|   UINTN                                       TopRow,
 | |
|   UINTN                                       BottomRow,
 | |
|   UINTN                                       TextAttribute
 | |
|   )
 | |
| {
 | |
|   CHAR16  *Buffer;
 | |
|   UINTN   Row;
 | |
| 
 | |
|   //
 | |
|   // For now, allocate an arbitrarily long buffer
 | |
|   //
 | |
|   Buffer = AllocateZeroPool (0x10000);
 | |
|   ASSERT (Buffer != NULL);
 | |
| 
 | |
|   //
 | |
|   // Set foreground and background as defined
 | |
|   //
 | |
|   gST->ConOut->SetAttribute (gST->ConOut, TextAttribute);
 | |
| 
 | |
|   //
 | |
|   // Much faster to buffer the long string instead of print it a character at a time
 | |
|   //
 | |
|   SetUnicodeMem (Buffer, RightColumn - LeftColumn, L' ');
 | |
| 
 | |
|   //
 | |
|   // Clear the desired area with the appropriate foreground/background
 | |
|   //
 | |
|   for (Row = TopRow; Row <= BottomRow; Row++) {
 | |
|     PrintStringAt (LeftColumn, Row, Buffer);
 | |
|   }
 | |
| 
 | |
|   gST->ConOut->SetCursorPosition (gST->ConOut, LeftColumn, TopRow);
 | |
| 
 | |
|   FreePool (Buffer);
 | |
|   return ;
 | |
| }
 | |
| 
 | |
| VOID
 | |
| NewStrCat (
 | |
|   CHAR16                                      *Destination,
 | |
|   CHAR16                                      *Source
 | |
|   )
 | |
| {
 | |
|   UINTN Length;
 | |
| 
 | |
|   for (Length = 0; Destination[Length] != 0; Length++)
 | |
|     ;
 | |
| 
 | |
|   //
 | |
|   // We now have the length of the original string
 | |
|   // We can safely assume for now that we are concatenating a narrow value to this string.
 | |
|   // For instance, the string is "XYZ" and cat'ing ">"
 | |
|   // If this assumption changes, we need to make this routine a bit more complex
 | |
|   //
 | |
|   Destination[Length] = (CHAR16) NARROW_CHAR;
 | |
|   Length++;
 | |
| 
 | |
|   StrCpy (Destination + Length, Source);
 | |
| }
 | |
| 
 | |
| UINTN
 | |
| GetStringWidth (
 | |
|   CHAR16                                      *String
 | |
|   )
 | |
| {
 | |
|   UINTN Index;
 | |
|   UINTN Count;
 | |
|   UINTN IncrementValue;
 | |
| 
 | |
|   Index           = 0;
 | |
|   Count           = 0;
 | |
|   IncrementValue  = 1;
 | |
| 
 | |
|   do {
 | |
|     //
 | |
|     // Advance to the null-terminator or to the first width directive
 | |
|     //
 | |
|     for (;
 | |
|          (String[Index] != NARROW_CHAR) && (String[Index] != WIDE_CHAR) && (String[Index] != 0);
 | |
|          Index++, Count = Count + IncrementValue
 | |
|         )
 | |
|       ;
 | |
| 
 | |
|     //
 | |
|     // We hit the null-terminator, we now have a count
 | |
|     //
 | |
|     if (String[Index] == 0) {
 | |
|       break;
 | |
|     }
 | |
|     //
 | |
|     // We encountered a narrow directive - strip it from the size calculation since it doesn't get printed
 | |
|     // and also set the flag that determines what we increment by.(if narrow, increment by 1, if wide increment by 2)
 | |
|     //
 | |
|     if (String[Index] == NARROW_CHAR) {
 | |
|       //
 | |
|       // Skip to the next character
 | |
|       //
 | |
|       Index++;
 | |
|       IncrementValue = 1;
 | |
|     } else {
 | |
|       //
 | |
|       // Skip to the next character
 | |
|       //
 | |
|       Index++;
 | |
|       IncrementValue = 2;
 | |
|     }
 | |
|   } while (String[Index] != 0);
 | |
| 
 | |
|   //
 | |
|   // Increment by one to include the null-terminator in the size
 | |
|   //
 | |
|   Count++;
 | |
| 
 | |
|   return Count * sizeof (CHAR16);
 | |
| }
 | |
| 
 | |
| VOID
 | |
| DisplayPageFrame (
 | |
|   VOID
 | |
|   )
 | |
| {
 | |
|   UINTN             Index;
 | |
|   UINT8             Line;
 | |
|   UINT8             Alignment;
 | |
|   CHAR16            Character;
 | |
|   CHAR16            *Buffer;
 | |
|   CHAR16            *StrFrontPageBanner;
 | |
|   EFI_SCREEN_DESCRIPTOR LocalScreen;
 | |
|   UINTN             Row;
 | |
| 
 | |
|   ZeroMem (&LocalScreen, sizeof (EFI_SCREEN_DESCRIPTOR));
 | |
|   gST->ConOut->QueryMode (gST->ConOut, gST->ConOut->Mode->Mode, &LocalScreen.RightColumn, &LocalScreen.BottomRow);
 | |
|   ClearLines (0, LocalScreen.RightColumn, 0, LocalScreen.BottomRow, KEYHELP_BACKGROUND);
 | |
| 
 | |
|   CopyMem (&LocalScreen, &gScreenDimensions, sizeof (EFI_SCREEN_DESCRIPTOR));
 | |
| 
 | |
|   //
 | |
|   // For now, allocate an arbitrarily long buffer
 | |
|   //
 | |
|   Buffer = AllocateZeroPool (0x10000);
 | |
|   ASSERT (Buffer != NULL);
 | |
| 
 | |
|   Character = (CHAR16) BOXDRAW_HORIZONTAL;
 | |
| 
 | |
|   for (Index = 0; Index + 2 < (LocalScreen.RightColumn - LocalScreen.LeftColumn); Index++) {
 | |
|     Buffer[Index] = Character;
 | |
|   }
 | |
| 
 | |
|   if (gClassOfVfr == EFI_FRONT_PAGE_SUBCLASS) {
 | |
|     //
 | |
|     //    ClearLines(0, LocalScreen.RightColumn, 0, BANNER_HEIGHT-1, BANNER_TEXT | BANNER_BACKGROUND);
 | |
|     //
 | |
|     ClearLines (
 | |
|       LocalScreen.LeftColumn,
 | |
|       LocalScreen.RightColumn,
 | |
|       LocalScreen.TopRow,
 | |
|       FRONT_PAGE_HEADER_HEIGHT - 1 + LocalScreen.TopRow,
 | |
|       BANNER_TEXT | BANNER_BACKGROUND
 | |
|       );
 | |
|     //
 | |
|     //    for (Line = 0; Line < BANNER_HEIGHT; Line++) {
 | |
|     //
 | |
|     for (Line = (UINT8) LocalScreen.TopRow; Line < BANNER_HEIGHT + (UINT8) LocalScreen.TopRow; Line++) {
 | |
|       //
 | |
|       //      for (Alignment = 0; Alignment < BANNER_COLUMNS; Alignment++) {
 | |
|       //
 | |
|       for (Alignment = (UINT8) LocalScreen.LeftColumn;
 | |
|            Alignment < BANNER_COLUMNS + (UINT8) LocalScreen.LeftColumn;
 | |
|            Alignment++
 | |
|           ) {
 | |
|         if (BannerData->Banner[Line - (UINT8) LocalScreen.TopRow][Alignment - (UINT8) LocalScreen.LeftColumn] != 0x0000) {
 | |
|           StrFrontPageBanner = GetToken (
 | |
|                                 BannerData->Banner[Line - (UINT8) LocalScreen.TopRow][Alignment - (UINT8) LocalScreen.LeftColumn],
 | |
|                                 FrontPageHandle
 | |
|                                 );
 | |
|         } else {
 | |
|           continue;
 | |
|         }
 | |
| 
 | |
|         switch (Alignment - LocalScreen.LeftColumn) {
 | |
|         case 0:
 | |
|           //
 | |
|           // Handle left column
 | |
|           //
 | |
|           PrintStringAt (LocalScreen.LeftColumn, Line, StrFrontPageBanner);
 | |
|           break;
 | |
| 
 | |
|         case 1:
 | |
|           //
 | |
|           // Handle center column
 | |
|           //
 | |
|           PrintStringAt (
 | |
|             LocalScreen.LeftColumn + (LocalScreen.RightColumn - LocalScreen.LeftColumn) / 3,
 | |
|             Line,
 | |
|             StrFrontPageBanner
 | |
|             );
 | |
|           break;
 | |
| 
 | |
|         case 2:
 | |
|           //
 | |
|           // Handle right column
 | |
|           //
 | |
|           PrintStringAt (
 | |
|             LocalScreen.LeftColumn + (LocalScreen.RightColumn - LocalScreen.LeftColumn) * 2 / 3,
 | |
|             Line,
 | |
|             StrFrontPageBanner
 | |
|             );
 | |
|           break;
 | |
|         }
 | |
| 
 | |
|         FreePool (StrFrontPageBanner);
 | |
|       }
 | |
|     }
 | |
|   }
 | |
| 
 | |
|   ClearLines (
 | |
|     LocalScreen.LeftColumn,
 | |
|     LocalScreen.RightColumn,
 | |
|     LocalScreen.BottomRow - STATUS_BAR_HEIGHT - FOOTER_HEIGHT,
 | |
|     LocalScreen.BottomRow - STATUS_BAR_HEIGHT - 1,
 | |
|     KEYHELP_TEXT | KEYHELP_BACKGROUND
 | |
|     );
 | |
| 
 | |
|   if (gClassOfVfr != EFI_FRONT_PAGE_SUBCLASS) {
 | |
|     ClearLines (
 | |
|       LocalScreen.LeftColumn,
 | |
|       LocalScreen.RightColumn,
 | |
|       LocalScreen.TopRow,
 | |
|       LocalScreen.TopRow + NONE_FRONT_PAGE_HEADER_HEIGHT - 1,
 | |
|       TITLE_TEXT | TITLE_BACKGROUND
 | |
|       );
 | |
|     //
 | |
|     // Print Top border line
 | |
|     // +------------------------------------------------------------------------------+
 | |
|     // ?                                                                             ?
 | |
|     // +------------------------------------------------------------------------------+
 | |
|     //
 | |
|     Character = (CHAR16) BOXDRAW_DOWN_RIGHT;
 | |
| 
 | |
|     PrintChar (Character);
 | |
|     PrintString (Buffer);
 | |
| 
 | |
|     Character = (CHAR16) BOXDRAW_DOWN_LEFT;
 | |
|     PrintChar (Character);
 | |
| 
 | |
|     Character = (CHAR16) BOXDRAW_VERTICAL;
 | |
|     for (Row = LocalScreen.TopRow + 1; Row <= LocalScreen.TopRow + NONE_FRONT_PAGE_HEADER_HEIGHT - 2; Row++) {
 | |
|       PrintCharAt (LocalScreen.LeftColumn, Row, Character);
 | |
|       PrintCharAt (LocalScreen.RightColumn - 1, Row, Character);
 | |
|     }
 | |
| 
 | |
|     Character = (CHAR16) BOXDRAW_UP_RIGHT;
 | |
|     PrintCharAt (LocalScreen.LeftColumn, LocalScreen.TopRow + NONE_FRONT_PAGE_HEADER_HEIGHT - 1, Character);
 | |
|     PrintString (Buffer);
 | |
| 
 | |
|     Character = (CHAR16) BOXDRAW_UP_LEFT;
 | |
|     PrintChar (Character);
 | |
| 
 | |
|     if (gClassOfVfr == EFI_SETUP_APPLICATION_SUBCLASS) {
 | |
|       //
 | |
|       // Print Bottom border line
 | |
|       // +------------------------------------------------------------------------------+
 | |
|       // ?                                                                             ?
 | |
|       // +------------------------------------------------------------------------------+
 | |
|       //
 | |
|       Character = (CHAR16) BOXDRAW_DOWN_RIGHT;
 | |
|       PrintCharAt (LocalScreen.LeftColumn, LocalScreen.BottomRow - STATUS_BAR_HEIGHT - FOOTER_HEIGHT, Character);
 | |
| 
 | |
|       PrintString (Buffer);
 | |
| 
 | |
|       Character = (CHAR16) BOXDRAW_DOWN_LEFT;
 | |
|       PrintChar (Character);
 | |
|       Character = (CHAR16) BOXDRAW_VERTICAL;
 | |
|       for (Row = LocalScreen.BottomRow - STATUS_BAR_HEIGHT - FOOTER_HEIGHT + 1;
 | |
|            Row <= LocalScreen.BottomRow - STATUS_BAR_HEIGHT - 2;
 | |
|            Row++
 | |
|           ) {
 | |
|         PrintCharAt (LocalScreen.LeftColumn, Row, Character);
 | |
|         PrintCharAt (LocalScreen.RightColumn - 1, Row, Character);
 | |
|       }
 | |
| 
 | |
|       Character = (CHAR16) BOXDRAW_UP_RIGHT;
 | |
|       PrintCharAt (LocalScreen.LeftColumn, LocalScreen.BottomRow - STATUS_BAR_HEIGHT - 1, Character);
 | |
| 
 | |
|       PrintString (Buffer);
 | |
| 
 | |
|       Character = (CHAR16) BOXDRAW_UP_LEFT;
 | |
|       PrintChar (Character);
 | |
|     }
 | |
|   }
 | |
| 
 | |
|   FreePool (Buffer);
 | |
| 
 | |
| }
 | |
| 
 | |
| /*
 | |
| +------------------------------------------------------------------------------+
 | |
| ?F2=Previous Page                 Setup Page                                  ?
 | |
| +------------------------------------------------------------------------------+
 | |
| 
 | |
| 
 | |
| 
 | |
| 
 | |
| 
 | |
| 
 | |
| 
 | |
| 
 | |
| 
 | |
| 
 | |
| 
 | |
| 
 | |
| 
 | |
| 
 | |
| 
 | |
| 
 | |
| 
 | |
| +------------------------------------------------------------------------------+
 | |
| ?F1=Scroll Help                 F9=Reset to Defaults        F10=Save and Exit ?
 | |
| | ^"=Move Highlight          <Spacebar> Toggles Checkbox   Esc=Discard Changes |
 | |
| +------------------------------------------------------------------------------+
 | |
| */
 | |
| STATIC
 | |
| UI_MENU_OPTION *
 | |
| DisplayForm (
 | |
|   OUT UI_MENU_OPTION              *Selection,
 | |
|   IN  UINT16                      FormHandle,
 | |
|   IN  UINT16                      TitleToken,
 | |
|   IN  EFI_FORM_TAGS               FormTags,
 | |
|   IN  EFI_FILE_FORM_TAGS          *FileFormTagsHead,
 | |
|   IN  UINT8                       *CallbackData
 | |
|   )
 | |
| {
 | |
|   CHAR16              *StringPtr;
 | |
|   UINTN               Index;
 | |
|   UINTN               Count;
 | |
|   UINT16              MenuItemCount;
 | |
|   EFI_HII_HANDLE      Handle;
 | |
|   UINT16              FormId;
 | |
|   STRING_REF          String;
 | |
|   EFI_FILE_FORM_TAGS  *FileFormTags;
 | |
|   BOOLEAN             SuppressIf;
 | |
|   BOOLEAN             Suppress;
 | |
|   BOOLEAN             GrayOut;
 | |
|   BOOLEAN             Conditional;
 | |
|   EFI_SCREEN_DESCRIPTOR   LocalScreen;
 | |
|   UINT16              Width;
 | |
|   UINTN               ArrayEntry;
 | |
|   CHAR16              *OutputString;
 | |
| 
 | |
|   Handle        = Selection->Handle;
 | |
|   FormId        = 0;
 | |
|   String        = 0;
 | |
|   MenuItemCount = 0;
 | |
|   ArrayEntry    = 0;
 | |
|   OutputString  = NULL;
 | |
| 
 | |
|   CopyMem (&LocalScreen, &gScreenDimensions, sizeof (EFI_SCREEN_DESCRIPTOR));
 | |
| 
 | |
|   //
 | |
|   // If we hit a F2 (previous) we already nuked the menu and are simply carrying around what information we need
 | |
|   //
 | |
|   if (Selection->Previous) {
 | |
|     Selection->Previous = FALSE;
 | |
|   } else {
 | |
|     UiFreeMenu ();
 | |
|     UiInitMenu ();
 | |
|   }
 | |
| 
 | |
|   StringPtr = GetToken (TitleToken, Handle);
 | |
| 
 | |
|   if (gClassOfVfr != EFI_FRONT_PAGE_SUBCLASS) {
 | |
|     gST->ConOut->SetAttribute (gST->ConOut, TITLE_TEXT | TITLE_BACKGROUND);
 | |
|     PrintStringAt (
 | |
|       (LocalScreen.RightColumn + LocalScreen.LeftColumn - GetStringWidth (StringPtr) / 2) / 2,
 | |
|       LocalScreen.TopRow + 1,
 | |
|       StringPtr
 | |
|       );
 | |
|   }
 | |
| 
 | |
|   if (gClassOfVfr == EFI_SETUP_APPLICATION_SUBCLASS) {
 | |
|     gST->ConOut->SetAttribute (gST->ConOut, KEYHELP_TEXT | KEYHELP_BACKGROUND);
 | |
| 
 | |
|     //
 | |
|     // Display the infrastructure strings
 | |
|     //
 | |
|     if (!IsListEmpty (&gMenuList)) {
 | |
|       PrintStringAt (LocalScreen.LeftColumn + 2, LocalScreen.TopRow + 1, gFunctionTwoString);
 | |
|     }
 | |
| 
 | |
|     PrintStringAt (LocalScreen.LeftColumn + 2, LocalScreen.BottomRow - 4, gFunctionOneString);
 | |
|     PrintStringAt (
 | |
|       LocalScreen.LeftColumn + (LocalScreen.RightColumn - LocalScreen.LeftColumn) / 3,
 | |
|       LocalScreen.BottomRow - 4,
 | |
|       gFunctionNineString
 | |
|       );
 | |
|     PrintStringAt (
 | |
|       LocalScreen.LeftColumn + (LocalScreen.RightColumn - LocalScreen.LeftColumn) * 2 / 3,
 | |
|       LocalScreen.BottomRow - 4,
 | |
|       gFunctionTenString
 | |
|       );
 | |
|     PrintAt (LocalScreen.LeftColumn + 2, LocalScreen.BottomRow - 3, (CHAR16 *) L"%c%c%s", ARROW_UP, ARROW_DOWN, gMoveHighlight);
 | |
|     PrintStringAt (
 | |
|       LocalScreen.LeftColumn + (LocalScreen.RightColumn - LocalScreen.LeftColumn) / 3,
 | |
|       LocalScreen.BottomRow - 3,
 | |
|       gEscapeString
 | |
|       );
 | |
|   }
 | |
|   //
 | |
|   // Remove Buffer allocated for StringPtr after it has been used.
 | |
|   //
 | |
|   FreePool (StringPtr);
 | |
| 
 | |
|   for (Index = 0; FormTags.Tags[Index].Operand != EFI_IFR_END_FORM_OP; Index++) {
 | |
|     GrayOut       = FALSE;
 | |
|     Suppress      = FALSE;
 | |
|     SuppressIf    = FALSE;
 | |
|     Conditional   = FALSE;
 | |
|     FileFormTags  = FileFormTagsHead;
 | |
| 
 | |
|     if (FormTags.Tags[Index].Operand == EFI_IFR_FORM_OP) {
 | |
|       FormId = FormTags.Tags[Index].Id;
 | |
|     }
 | |
|     //
 | |
|     // This gives us visibility to the FileFormTags->NvRamMap to check things
 | |
|     // ActiveIfr is a global maintained by the menuing code to ensure that we
 | |
|     // are pointing to the correct formset's file data.
 | |
|     //
 | |
|     for (Count = 0; Count < gActiveIfr; Count++) {
 | |
|       FileFormTags = FileFormTags->NextFile;
 | |
|     }
 | |
|     //
 | |
|     //  GrayoutIf [SuppressIf]
 | |
|     //    <BOOLEANS>
 | |
|     //      OpCode(s)
 | |
|     //  EndIf
 | |
|     //
 | |
|     //  SuppressIf [GrayoutIf]
 | |
|     //    <BOOLEANS>
 | |
|     //      OpCode(s)
 | |
|     //  EndIf
 | |
|     //
 | |
|     Count = 0;
 | |
| 
 | |
|     do {
 | |
|       switch (FormTags.Tags[Index].Operand) {
 | |
|       case EFI_IFR_SUPPRESS_IF_OP:
 | |
|         SuppressIf = TRUE;
 | |
| 
 | |
|       case EFI_IFR_GRAYOUT_IF_OP:
 | |
| 
 | |
|         Conditional = TRUE;
 | |
| 
 | |
|         //
 | |
|         // Advance to the next op-code
 | |
|         //
 | |
|         Index++;
 | |
| 
 | |
|         //
 | |
|         // We are now pointing to the beginning of the consistency checking.  Let's fast forward
 | |
|         // through the AND/OR/NOT data to come up with some meaningful ID data.
 | |
|         //
 | |
|         for (;
 | |
|              FormTags.Tags[Index].Operand == EFI_IFR_AND_OP   ||
 | |
|              FormTags.Tags[Index].Operand == EFI_IFR_OR_OP    ||
 | |
|              FormTags.Tags[Index].Operand == EFI_IFR_GT_OP    ||
 | |
|              FormTags.Tags[Index].Operand == EFI_IFR_GE_OP    ||
 | |
|              FormTags.Tags[Index].Operand == EFI_IFR_NOT_OP;
 | |
|            Index++
 | |
|             )
 | |
|           ;
 | |
| 
 | |
|         //
 | |
|         // We need to walk through the consistency checks until we hit the end of the consistency
 | |
|         // FALSE means evaluate this single expression
 | |
|         // The ConsistencyId refers to which expression in the Consistency database to use
 | |
|         //
 | |
|         if (SuppressIf) {
 | |
|           Suppress = ValueIsNotValid (
 | |
|                       FALSE,
 | |
|                       FormTags.Tags[Index].ConsistencyId,
 | |
|                       &FormTags.Tags[Index],
 | |
|                       FileFormTags,
 | |
|                       &String
 | |
|                       );
 | |
|           SuppressIf = FALSE;
 | |
|         } else {
 | |
|           GrayOut = ValueIsNotValid (
 | |
|                       FALSE,
 | |
|                       FormTags.Tags[Index].ConsistencyId,
 | |
|                       &FormTags.Tags[Index],
 | |
|                       FileFormTags,
 | |
|                       &String
 | |
|                       );
 | |
|         }
 | |
|         //
 | |
|         // Advance to the end of the expression (Will land us at a grayoutif/suppressif or the op-code being affected)
 | |
|         //
 | |
|         for (;
 | |
|              FormTags.Tags[Index].Operand == EFI_IFR_EQ_ID_VAL_OP ||
 | |
|              FormTags.Tags[Index].Operand == EFI_IFR_EQ_VAR_VAL_OP ||
 | |
|              FormTags.Tags[Index].Operand == EFI_IFR_EQ_ID_ID_OP ||
 | |
|              FormTags.Tags[Index].Operand == EFI_IFR_EQ_ID_LIST_OP ||
 | |
|              FormTags.Tags[Index].Operand == EFI_IFR_NOT_OP ||
 | |
|              FormTags.Tags[Index].Operand == EFI_IFR_AND_OP ||
 | |
|              FormTags.Tags[Index].Operand == EFI_IFR_OR_OP ||
 | |
|              FormTags.Tags[Index].Operand == EFI_IFR_TRUE_OP ||
 | |
|              FormTags.Tags[Index].Operand == EFI_IFR_FALSE_OP ||
 | |
|              FormTags.Tags[Index].Operand == EFI_IFR_GT_OP    ||
 | |
|              FormTags.Tags[Index].Operand == EFI_IFR_GE_OP    ||
 | |
|              FormTags.Tags[Index].Operand == EFI_IFR_LABEL_OP;
 | |
|            Index++
 | |
|             )
 | |
|           ;
 | |
|         break;
 | |
| 
 | |
|       default:
 | |
|         goto GetOut;
 | |
|       }
 | |
|       //
 | |
|       // Do this two times (at most will see a suppress and grayout combination
 | |
|       //
 | |
|       Count++;
 | |
|     } while (Count < 2);
 | |
| 
 | |
| GetOut:
 | |
|     do {
 | |
|       if (GrayOut) {
 | |
|         FormTags.Tags[Index].GrayOut = TRUE;
 | |
|       } else {
 | |
|         FormTags.Tags[Index].GrayOut = FALSE;
 | |
|       }
 | |
|       if (Suppress && FormTags.Tags[Index].Operand == EFI_IFR_ONE_OF_OPTION_OP) {
 | |
|         //
 | |
|         // Only need .Suppress field when the tag is a one_of_option. For other cases, omit them directly.
 | |
|         //
 | |
|         FormTags.Tags[Index].Suppress = TRUE;
 | |
|       } else {
 | |
|         FormTags.Tags[Index].Suppress = FALSE;
 | |
|       }
 | |
| 
 | |
|       if ((
 | |
|             FormTags.Tags[Index].NumberOfLines > 0 ||
 | |
|             FormTags.Tags[Index].Operand == EFI_IFR_DATE_OP ||
 | |
|             FormTags.Tags[Index].Operand == EFI_IFR_TIME_OP
 | |
|           ) &&
 | |
|           !Suppress
 | |
|           ) {
 | |
| 
 | |
|         StringPtr = GetToken (FormTags.Tags[Index].Text, Handle);
 | |
| 
 | |
|         Width     = GetWidth (&FormTags.Tags[Index], Handle);
 | |
| 
 | |
|         //
 | |
|         // This data can be retrieved over and over again.  Therefore, reset to original values
 | |
|         // before processing otherwise things will start growing linearly
 | |
|         //
 | |
|         if (FormTags.Tags[Index].NumberOfLines > 1) {
 | |
|           FormTags.Tags[Index].NumberOfLines = 1;
 | |
|         }
 | |
| 
 | |
|         for (Count = 0; GetLineByWidth (StringPtr, Width, &ArrayEntry, &OutputString) != 0x0000;) {
 | |
|           //
 | |
|           // If there is more string to process print on the next row and increment the Skip value
 | |
|           //
 | |
|           if (StrLen (&StringPtr[ArrayEntry])) {
 | |
|             FormTags.Tags[Index].NumberOfLines++;
 | |
|           }
 | |
| 
 | |
|           FreePool (OutputString);
 | |
|         }
 | |
| 
 | |
|         ArrayEntry = 0;
 | |
| 
 | |
|         //
 | |
|         // We are NOT!! removing this StringPtr buffer via FreePool since it is being used in the menuoptions, we will do
 | |
|         // it in UiFreeMenu.
 | |
|         //
 | |
|         UiAddSubMenuOption (StringPtr, Handle, FormTags.Tags, Index, FormId, MenuItemCount);
 | |
|         MenuItemCount++;
 | |
|       }
 | |
|       //
 | |
|       // Keep processing menu entries based on the resultant suppress/grayout results until we hit an end-if
 | |
|       //
 | |
|       Index++;
 | |
|     } while (FormTags.Tags[Index].Operand != EFI_IFR_END_IF_OP && Conditional);
 | |
| 
 | |
|     //
 | |
|     // We advanced the index for the above conditional, rewind it to keep harmony with the for loop logic
 | |
|     //
 | |
|     Index--;
 | |
|   }
 | |
| 
 | |
|   Selection = UiDisplayMenu (TRUE, FileFormTagsHead, (EFI_IFR_DATA_ARRAY *) CallbackData);
 | |
| 
 | |
|   return Selection;
 | |
| }
 | |
| 
 | |
| VOID
 | |
| InitializeBrowserStrings (
 | |
|   VOID
 | |
|   )
 | |
| {
 | |
|   gFunctionOneString    = GetToken (STRING_TOKEN (FUNCTION_ONE_STRING), gHiiHandle);
 | |
|   gFunctionTwoString    = GetToken (STRING_TOKEN (FUNCTION_TWO_STRING), gHiiHandle);
 | |
|   gFunctionNineString   = GetToken (STRING_TOKEN (FUNCTION_NINE_STRING), gHiiHandle);
 | |
|   gFunctionTenString    = GetToken (STRING_TOKEN (FUNCTION_TEN_STRING), gHiiHandle);
 | |
|   gEnterString          = GetToken (STRING_TOKEN (ENTER_STRING), gHiiHandle);
 | |
|   gEnterCommitString    = GetToken (STRING_TOKEN (ENTER_COMMIT_STRING), gHiiHandle);
 | |
|   gEscapeString         = GetToken (STRING_TOKEN (ESCAPE_STRING), gHiiHandle);
 | |
|   gMoveHighlight        = GetToken (STRING_TOKEN (MOVE_HIGHLIGHT), gHiiHandle);
 | |
|   gMakeSelection        = GetToken (STRING_TOKEN (MAKE_SELECTION), gHiiHandle);
 | |
|   gNumericInput         = GetToken (STRING_TOKEN (NUMERIC_INPUT), gHiiHandle);
 | |
|   gToggleCheckBox       = GetToken (STRING_TOKEN (TOGGLE_CHECK_BOX), gHiiHandle);
 | |
|   gPromptForPassword    = GetToken (STRING_TOKEN (PROMPT_FOR_PASSWORD), gHiiHandle);
 | |
|   gPromptForNewPassword = GetToken (STRING_TOKEN (PROMPT_FOR_NEW_PASSWORD), gHiiHandle);
 | |
|   gConfirmPassword      = GetToken (STRING_TOKEN (CONFIRM_PASSWORD), gHiiHandle);
 | |
|   gConfirmError         = GetToken (STRING_TOKEN (CONFIRM_ERROR), gHiiHandle);
 | |
|   gPressEnter           = GetToken (STRING_TOKEN (PRESS_ENTER), gHiiHandle);
 | |
|   gEmptyString          = GetToken (STRING_TOKEN (EMPTY_STRING), gHiiHandle);
 | |
|   gAreYouSure           = GetToken (STRING_TOKEN (ARE_YOU_SURE), gHiiHandle);
 | |
|   gYesResponse          = GetToken (STRING_TOKEN (ARE_YOU_SURE_YES), gHiiHandle);
 | |
|   gNoResponse           = GetToken (STRING_TOKEN (ARE_YOU_SURE_NO), gHiiHandle);
 | |
|   gMiniString           = GetToken (STRING_TOKEN (MINI_STRING), gHiiHandle);
 | |
|   gPlusString           = GetToken (STRING_TOKEN (PLUS_STRING), gHiiHandle);
 | |
|   gMinusString          = GetToken (STRING_TOKEN (MINUS_STRING), gHiiHandle);
 | |
|   gAdjustNumber         = GetToken (STRING_TOKEN (ADJUST_NUMBER), gHiiHandle);
 | |
|   return ;
 | |
| }
 | |
| 
 | |
| VOID
 | |
| UpdateKeyHelp (
 | |
|   IN  UI_MENU_OPTION              *Selection,
 | |
|   IN  BOOLEAN                     Selected
 | |
|   )
 | |
| /*++
 | |
| Routine Description:
 | |
|   Update key's help imformation
 | |
| 
 | |
| Arguments:
 | |
|   Selection C The form that current display
 | |
|   Selected C  Whether or not a tag be selected
 | |
| 
 | |
| Returns:
 | |
|   None
 | |
| --*/
 | |
| {
 | |
|   UINTN             SecCol;
 | |
|   UINTN             ThdCol;
 | |
|   UINTN             LeftColumnOfHelp;
 | |
|   UINTN             RightColumnOfHelp;
 | |
|   UINTN             TopRowOfHelp;
 | |
|   UINTN             BottomRowOfHelp;
 | |
|   UINTN             StartColumnOfHelp;
 | |
|   EFI_SCREEN_DESCRIPTOR LocalScreen;
 | |
| 
 | |
|   CopyMem (&LocalScreen, &gScreenDimensions, sizeof (EFI_SCREEN_DESCRIPTOR));
 | |
| 
 | |
|   SecCol            = LocalScreen.LeftColumn + (LocalScreen.RightColumn - LocalScreen.LeftColumn) / 3;
 | |
|   ThdCol            = LocalScreen.LeftColumn + (LocalScreen.RightColumn - LocalScreen.LeftColumn) * 2 / 3;
 | |
| 
 | |
|   StartColumnOfHelp = LocalScreen.LeftColumn + 2;
 | |
|   LeftColumnOfHelp  = LocalScreen.LeftColumn + 1;
 | |
|   RightColumnOfHelp = LocalScreen.RightColumn - 2;
 | |
|   TopRowOfHelp      = LocalScreen.BottomRow - 4;
 | |
|   BottomRowOfHelp   = LocalScreen.BottomRow - 3;
 | |
| 
 | |
|   if (gClassOfVfr == EFI_GENERAL_APPLICATION_SUBCLASS) {
 | |
|     return ;
 | |
|   }
 | |
| 
 | |
|   gST->ConOut->SetAttribute (gST->ConOut, KEYHELP_TEXT | KEYHELP_BACKGROUND);
 | |
| 
 | |
|   switch (Selection->ThisTag->Operand) {
 | |
|   case EFI_IFR_ORDERED_LIST_OP:
 | |
|   case EFI_IFR_ONE_OF_OP:
 | |
|   case EFI_IFR_NUMERIC_OP:
 | |
|   case EFI_IFR_TIME_OP:
 | |
|   case EFI_IFR_DATE_OP:
 | |
|     ClearLines (LeftColumnOfHelp, RightColumnOfHelp, TopRowOfHelp, BottomRowOfHelp, KEYHELP_TEXT | KEYHELP_BACKGROUND);
 | |
| 
 | |
|     if (!Selected) {
 | |
|       if (gClassOfVfr == EFI_SETUP_APPLICATION_SUBCLASS) {
 | |
|         PrintStringAt (StartColumnOfHelp, TopRowOfHelp, gFunctionOneString);
 | |
|         PrintStringAt (SecCol, TopRowOfHelp, gFunctionNineString);
 | |
|         PrintStringAt (ThdCol, TopRowOfHelp, gFunctionTenString);
 | |
|         PrintStringAt (ThdCol, BottomRowOfHelp, gEscapeString);
 | |
| 
 | |
|       }
 | |
| 
 | |
|       if ((Selection->ThisTag->Operand == EFI_IFR_DATE_OP) || (Selection->ThisTag->Operand == EFI_IFR_TIME_OP)) {
 | |
|         PrintAt (
 | |
|           StartColumnOfHelp,
 | |
|           BottomRowOfHelp,
 | |
|           (CHAR16 *) L"%c%c%c%c%s",
 | |
|           ARROW_UP,
 | |
|           ARROW_DOWN,
 | |
|           ARROW_RIGHT,
 | |
|           ARROW_LEFT,
 | |
|           gMoveHighlight
 | |
|           );
 | |
|         PrintStringAt (SecCol, BottomRowOfHelp, gAdjustNumber);
 | |
|       } else {
 | |
|         PrintAt (StartColumnOfHelp, BottomRowOfHelp, (CHAR16 *) L"%c%c%s", ARROW_UP, ARROW_DOWN, gMoveHighlight);
 | |
|         PrintStringAt (SecCol, BottomRowOfHelp, gEnterString);
 | |
|       }
 | |
|     } else {
 | |
|       PrintStringAt (SecCol, BottomRowOfHelp, gEnterCommitString);
 | |
| 
 | |
|       //
 | |
|       // If it is a selected numeric with manual input, display different message
 | |
|       //
 | |
|       if ((Selection->ThisTag->Operand == EFI_IFR_NUMERIC_OP) && (Selection->ThisTag->Step == 0)) {
 | |
|         PrintStringAt (SecCol, TopRowOfHelp, gNumericInput);
 | |
|       } else if (Selection->ThisTag->Operand != EFI_IFR_ORDERED_LIST_OP) {
 | |
|         PrintAt (StartColumnOfHelp, BottomRowOfHelp, L"%c%c%s", ARROW_UP, ARROW_DOWN, gMoveHighlight);
 | |
|       }
 | |
| 
 | |
|       if (Selection->ThisTag->Operand == EFI_IFR_ORDERED_LIST_OP) {
 | |
|         PrintStringAt (StartColumnOfHelp, TopRowOfHelp, gPlusString);
 | |
|         PrintStringAt (ThdCol, TopRowOfHelp, gMinusString);
 | |
|       }
 | |
| 
 | |
|       PrintStringAt (ThdCol, BottomRowOfHelp, gEscapeString);
 | |
|     }
 | |
|     break;
 | |
| 
 | |
|   case EFI_IFR_CHECKBOX_OP:
 | |
|     ClearLines (LeftColumnOfHelp, RightColumnOfHelp, TopRowOfHelp, BottomRowOfHelp, KEYHELP_TEXT | KEYHELP_BACKGROUND);
 | |
| 
 | |
|     if (gClassOfVfr == EFI_SETUP_APPLICATION_SUBCLASS) {
 | |
|       PrintStringAt (StartColumnOfHelp, TopRowOfHelp, gFunctionOneString);
 | |
|       PrintStringAt (SecCol, TopRowOfHelp, gFunctionNineString);
 | |
|       PrintStringAt (ThdCol, TopRowOfHelp, gFunctionTenString);
 | |
|       PrintStringAt (ThdCol, BottomRowOfHelp, gEscapeString);
 | |
|     }
 | |
| 
 | |
|     PrintAt (StartColumnOfHelp, BottomRowOfHelp, (CHAR16 *) L"%c%c%s", ARROW_UP, ARROW_DOWN, gMoveHighlight);
 | |
|     PrintStringAt (SecCol, BottomRowOfHelp, gToggleCheckBox);
 | |
|     break;
 | |
| 
 | |
|   case EFI_IFR_REF_OP:
 | |
|   case EFI_IFR_PASSWORD_OP:
 | |
|   case EFI_IFR_STRING_OP:
 | |
|     ClearLines (LeftColumnOfHelp, RightColumnOfHelp, TopRowOfHelp, BottomRowOfHelp, KEYHELP_TEXT | KEYHELP_BACKGROUND);
 | |
| 
 | |
|     if (!Selected) {
 | |
|       if (gClassOfVfr == EFI_SETUP_APPLICATION_SUBCLASS) {
 | |
|         PrintStringAt (StartColumnOfHelp, TopRowOfHelp, gFunctionOneString);
 | |
|         PrintStringAt (SecCol, TopRowOfHelp, gFunctionNineString);
 | |
|         PrintStringAt (ThdCol, TopRowOfHelp, gFunctionTenString);
 | |
|         PrintStringAt (ThdCol, BottomRowOfHelp, gEscapeString);
 | |
|       }
 | |
| 
 | |
|       PrintAt (StartColumnOfHelp, BottomRowOfHelp, (CHAR16 *) L"%c%c%s", ARROW_UP, ARROW_DOWN, gMoveHighlight);
 | |
|       PrintStringAt (SecCol, BottomRowOfHelp, gEnterString);
 | |
|     } else {
 | |
|       if (Selection->ThisTag->Operand != EFI_IFR_REF_OP) {
 | |
|         PrintStringAt (
 | |
|           (LocalScreen.RightColumn - GetStringWidth (gEnterCommitString) / 2) / 2,
 | |
|           BottomRowOfHelp,
 | |
|           gEnterCommitString
 | |
|           );
 | |
|         PrintStringAt (ThdCol, BottomRowOfHelp, gEscapeString);
 | |
|       }
 | |
|     }
 | |
|     break;
 | |
|   }
 | |
| 
 | |
| }
 | |
| 
 | |
| STATIC
 | |
| VOID
 | |
| ExtractFormHandle (
 | |
|   IN  UI_MENU_OPTION              *Selection,
 | |
|   IN  EFI_FILE_FORM_TAGS          *FileFormTagsHead,
 | |
|   IN  UINTN                       IdValue,
 | |
|   OUT UINT16                      *FormHandle,
 | |
|   OUT UINT16                      *TitleToken,
 | |
|   OUT EFI_FORM_TAGS               *FormTags
 | |
|   )
 | |
| {
 | |
|   UINTN               Index;
 | |
|   EFI_FILE_FORM_TAGS  *FileFormTags;
 | |
|   EFI_FORM_TAGS       LocalTags;
 | |
| 
 | |
|   FileFormTags = FileFormTagsHead;
 | |
| 
 | |
|   //
 | |
|   // Advance FileFormTags to the correct file's tag information.
 | |
|   // For instance, if Selection->IfrNumber is 3, that means the 4th
 | |
|   // file (0-based) in the FileFormTags linked-list contains the tag
 | |
|   // information.
 | |
|   //
 | |
|   for (Index = 0; Index < Selection->IfrNumber; Index++) {
 | |
|     FileFormTags = FileFormTags->NextFile;
 | |
|   }
 | |
| 
 | |
|   LocalTags = FileFormTags->FormTags;
 | |
| 
 | |
|   if (IdValue == 0) {
 | |
|     //
 | |
|     // Advance Index to the first FormOp tag information
 | |
|     //
 | |
|     for (Index = 0; FileFormTags->FormTags.Tags[Index].Operand != EFI_IFR_FORM_OP; Index++)
 | |
|       ;
 | |
|   } else {
 | |
|     //
 | |
|     // Advance Index to the FormOp with the correct ID value
 | |
|     //
 | |
|     for (; LocalTags.Next != NULL; LocalTags = *LocalTags.Next) {
 | |
|       for (Index = 0; LocalTags.Tags[Index].Operand != EFI_IFR_FORM_OP; Index++)
 | |
|         ;
 | |
|       if (LocalTags.Tags[Index].Id == IdValue) {
 | |
|         break;
 | |
|       }
 | |
|     }
 | |
|   }
 | |
|   //
 | |
|   // return the Form Id, Text, and the File's FormTags structure
 | |
|   //
 | |
|   *FormHandle = LocalTags.Tags[Index].Id;
 | |
|   *TitleToken = LocalTags.Tags[Index].Text;
 | |
|   *FormTags   = LocalTags;
 | |
|   return ;
 | |
| }
 | |
| 
 | |
| STATIC
 | |
| EFI_STATUS
 | |
| UpdateNewTagData (
 | |
|   IN  UINT8                                     *FormData,
 | |
|   IN  UINT16                                    ConsistencyId,
 | |
|   IN  UINT16                                    CurrentVariable,
 | |
|   IN  EFI_FORM_TAGS                             *FormTags,
 | |
|   OUT EFI_FILE_FORM_TAGS                        *FileFormTags
 | |
|   )
 | |
| {
 | |
|   EFI_STATUS  Status;
 | |
|   UINT16      Index;
 | |
|   UINT16      QuestionIndex;
 | |
|   UINT16      NumberOfTags;
 | |
|   INT16       CurrTag;
 | |
|   UINT8       TagLength;
 | |
|   UINTN       Count;
 | |
|   BOOLEAN     Finished;
 | |
| 
 | |
|   //
 | |
|   // Initialize some Index variable and Status
 | |
|   //
 | |
|   Count         = 0;
 | |
|   QuestionIndex = 0;
 | |
|   NumberOfTags  = 1;
 | |
|   Index         = 0;
 | |
|   Status        = EFI_SUCCESS;
 | |
|   Finished      = FALSE;
 | |
| 
 | |
|   //
 | |
|   // Determine the number of tags for the first form
 | |
|   //
 | |
|   GetTagCount (&FormData[Index], &NumberOfTags);
 | |
| 
 | |
|   //
 | |
|   // Allocate memory for our tags on the first form
 | |
|   //
 | |
|   FormTags->Tags = AllocateZeroPool (NumberOfTags * sizeof (EFI_TAG));
 | |
|   ASSERT (FormTags->Tags != NULL);
 | |
| 
 | |
|   for (CurrTag = 0; FormData[Index] != EFI_IFR_END_FORM_SET_OP; CurrTag++) {
 | |
|     //
 | |
|     // Operand = IFR OpCode
 | |
|     //
 | |
|     FormTags->Tags[CurrTag].Operand = FormData[Index];
 | |
| 
 | |
|     //
 | |
|     // Assume for now 0 lines occupied by this OpCode
 | |
|     //
 | |
|     FormTags->Tags[CurrTag].NumberOfLines = 0;
 | |
| 
 | |
|     //
 | |
|     // Determine the length of the Tag so we can later skip to the next tag in the form
 | |
|     //
 | |
|     //
 | |
|     // get the length
 | |
|     //
 | |
|     TagLength = FormData[Index + 1];
 | |
|     //
 | |
|     // Operate on the Found OpCode
 | |
|     //
 | |
|     switch (FormData[Index]) {
 | |
| 
 | |
|     case EFI_IFR_FORM_OP:
 | |
|     case EFI_IFR_SUBTITLE_OP:
 | |
|     case EFI_IFR_TEXT_OP:
 | |
|     case EFI_IFR_REF_OP:
 | |
|       IfrToFormTag (FormData[Index], &FormTags->Tags[CurrTag], (VOID *) &FormData[Index], NULL);
 | |
|       break;
 | |
| 
 | |
|     case EFI_IFR_VARSTORE_SELECT_OP:
 | |
|       IfrToFormTag (FormData[Index], &FormTags->Tags[CurrTag], (VOID *) &FormData[Index], NULL);
 | |
|       CopyMem (&CurrentVariable, &((EFI_IFR_VARSTORE_SELECT *) &FormData[Index])->VarId, sizeof (UINT16));
 | |
|       break;
 | |
| 
 | |
|     case EFI_IFR_END_FORM_OP:
 | |
|       FormTags->Tags[CurrTag].Operand       = FormData[Index];
 | |
|       FormTags->Tags[CurrTag].NumberOfLines = 0;
 | |
| 
 | |
|       Finished = TRUE;
 | |
|       break;
 | |
| 
 | |
|     case EFI_IFR_ORDERED_LIST_OP:
 | |
|     case EFI_IFR_ONE_OF_OP:
 | |
|       GetQuestionHeader (&FormTags->Tags[CurrTag], FormData, Index, FileFormTags, CurrentVariable);
 | |
| 
 | |
|       //
 | |
|       // Store away the CurrTag since what follows will be the answer that we
 | |
|       // need to place into the appropriate location in the tag array
 | |
|       //
 | |
|       //
 | |
|       // record for setting default later
 | |
|       //
 | |
|       QuestionIndex = (UINT16) CurrTag;
 | |
|       break;
 | |
| 
 | |
|     case EFI_IFR_ONE_OF_OPTION_OP:
 | |
|       IfrToFormTag (FormData[Index], &FormTags->Tags[CurrTag], (VOID *) &FormData[Index], NULL);
 | |
|       FormTags->Tags[QuestionIndex].Key = ((EFI_IFR_ONE_OF_OPTION *) &FormData[Index])->Key;
 | |
|       FormTags->Tags[QuestionIndex].ResetRequired = (BOOLEAN) (FormTags->Tags[QuestionIndex].Flags & EFI_IFR_FLAG_RESET_REQUIRED);
 | |
|       break;
 | |
| 
 | |
|     case EFI_IFR_CHECKBOX_OP:
 | |
|       GetQuestionHeader (&FormTags->Tags[CurrTag], FormData, Index, FileFormTags, CurrentVariable);
 | |
|       IfrToFormTag (FormData[Index], &FormTags->Tags[CurrTag], (VOID *) &FormData[Index], NULL);
 | |
|       break;
 | |
| 
 | |
|     case EFI_IFR_NUMERIC_OP:
 | |
|       GetNumericHeader (&FormTags->Tags[CurrTag], FormData, Index, (UINT16) 1, FileFormTags, CurrentVariable);
 | |
|       IfrToFormTag (FormData[Index], &FormTags->Tags[CurrTag], (VOID *) &FormData[Index], NULL);
 | |
|       break;
 | |
| 
 | |
|     case EFI_IFR_DATE_OP:
 | |
|       //
 | |
|       // Date elements come in as a Year, Month, Day.  We need to process them as a country-based
 | |
|       // Order.  It is much easier to do it here than anywhere else.
 | |
|       //
 | |
|       // For US standards - we want Month/Day/Year, thus we advance "i" +1, +2, +0 while CurrTag is +0, +1, +2
 | |
|       //
 | |
|       GetNumericHeader (
 | |
|         &FormTags->Tags[CurrTag],
 | |
|         FormData,
 | |
|         (UINT16) (Index + TagLength),
 | |
|         (UINT16) 0,
 | |
|         FileFormTags,
 | |
|         CurrentVariable
 | |
|         );
 | |
| 
 | |
|       //
 | |
|       // The current language selected + the Date operand
 | |
|       //
 | |
|       FormTags->Tags[CurrTag + 1].Operand = FormData[Index];
 | |
|       GetNumericHeader (
 | |
|         &FormTags->Tags[CurrTag + 1],
 | |
|         FormData,
 | |
|         (UINT16) (Index + TagLength + FormData[Index + TagLength + 1]),
 | |
|         (UINT16) 0,
 | |
|         FileFormTags,
 | |
|         CurrentVariable
 | |
|         );
 | |
| 
 | |
|       //
 | |
|       // The current language selected + the Date operand
 | |
|       //
 | |
|       FormTags->Tags[CurrTag + 2].Operand = FormData[Index];
 | |
|       GetNumericHeader (&FormTags->Tags[CurrTag + 2], FormData, Index, (UINT16) 1, FileFormTags, CurrentVariable);
 | |
| 
 | |
|       CurrTag   = (INT16) (CurrTag + 2);
 | |
| 
 | |
|       Index     = (UINT16) (Index + TagLength);
 | |
|       //
 | |
|       // get the length
 | |
|       //
 | |
|       TagLength = FormData[Index + 1];
 | |
|       Index     = (UINT16) (Index + TagLength);
 | |
|       //
 | |
|       // get the length
 | |
|       //
 | |
|       TagLength = FormData[Index + 1];
 | |
|       break;
 | |
| 
 | |
|     case EFI_IFR_TIME_OP:
 | |
|       GetNumericHeader (&FormTags->Tags[CurrTag], FormData, Index, (UINT16) 0, FileFormTags, CurrentVariable);
 | |
| 
 | |
|       if (Count == 2) {
 | |
|         //
 | |
|         // Override the GetQuestionHeader information - date/time are treated very differently
 | |
|         //
 | |
|         FormTags->Tags[CurrTag].NumberOfLines = 1;
 | |
|         Count = 0;
 | |
|       } else {
 | |
|         //
 | |
|         // The premise is that every date/time op-code have 3 elements, the first 2 have 0 lines
 | |
|         // associated with them, and the third has 1 line to allow to space beyond the choice.
 | |
|         //
 | |
|         Count++;
 | |
|       }
 | |
|       break;
 | |
| 
 | |
|     case EFI_IFR_PASSWORD_OP:
 | |
|     case EFI_IFR_STRING_OP:
 | |
|       GetQuestionHeader (&FormTags->Tags[CurrTag], FormData, Index, FileFormTags, CurrentVariable);
 | |
|       IfrToFormTag (FormData[Index], &FormTags->Tags[CurrTag], (VOID *) &FormData[Index], NULL);
 | |
|       break;
 | |
| 
 | |
|     case EFI_IFR_INCONSISTENT_IF_OP:
 | |
|     case EFI_IFR_SUPPRESS_IF_OP:
 | |
|     case EFI_IFR_GRAYOUT_IF_OP:
 | |
|       ConsistencyId++;
 | |
|       break;
 | |
| 
 | |
|     case EFI_IFR_EQ_ID_VAL_OP:
 | |
|       IfrToFormTag (FormData[Index], &FormTags->Tags[CurrTag], (VOID *) &FormData[Index], NULL);
 | |
|       FormTags->Tags[CurrTag].ConsistencyId = ConsistencyId;
 | |
|       break;
 | |
| 
 | |
|     case EFI_IFR_EQ_VAR_VAL_OP:
 | |
|       IfrToFormTag (FormData[Index], &FormTags->Tags[CurrTag], (VOID *) &FormData[Index], NULL);
 | |
|       FormTags->Tags[CurrTag].ConsistencyId = ConsistencyId;
 | |
|       break;
 | |
| 
 | |
|     case EFI_IFR_EQ_ID_ID_OP:
 | |
|       IfrToFormTag (FormData[Index], &FormTags->Tags[CurrTag], (VOID *) &FormData[Index], NULL);
 | |
|       FormTags->Tags[CurrTag].ConsistencyId = ConsistencyId;
 | |
|       break;
 | |
| 
 | |
|     case EFI_IFR_AND_OP:
 | |
|     case EFI_IFR_OR_OP:
 | |
|     case EFI_IFR_NOT_OP:
 | |
|     case EFI_IFR_TRUE_OP:
 | |
|     case EFI_IFR_FALSE_OP:
 | |
|     case EFI_IFR_GT_OP:
 | |
|     case EFI_IFR_GE_OP:
 | |
|       FormTags->Tags[CurrTag].ConsistencyId = ConsistencyId;
 | |
|       break;
 | |
| 
 | |
|     case EFI_IFR_EQ_ID_LIST_OP:
 | |
|       IfrToFormTag (FormData[Index], &FormTags->Tags[CurrTag], (VOID *) &FormData[Index], NULL);
 | |
| 
 | |
|       FormTags->Tags[CurrTag].ConsistencyId = ConsistencyId;
 | |
|       break;
 | |
| 
 | |
|     default:
 | |
|       break;
 | |
|     }
 | |
|     //
 | |
|     // End of switch
 | |
|     //
 | |
|     if (Finished) {
 | |
|       break;
 | |
|     }
 | |
|     //
 | |
|     // Per spec., we ignore ops that we don't know how to deal with.  Skip to next tag
 | |
|     //
 | |
|     Index = (UINT16) (Index + TagLength);
 | |
|   }
 | |
|   //
 | |
|   // End of Index
 | |
|   //
 | |
|   return Status;
 | |
| }
 | |
| 
 | |
| STATIC
 | |
| VOID
 | |
| ExtractDynamicFormHandle (
 | |
|   IN  UI_MENU_OPTION              *Selection,
 | |
|   IN  UINT8                       *CallbackData,
 | |
|   IN  EFI_FILE_FORM_TAGS          *FileFormTagsHead,
 | |
|   IN  UINTN                       IdValue,
 | |
|   OUT UINT16                      *FormHandle,
 | |
|   OUT UINT16                      *TitleToken,
 | |
|   OUT EFI_FORM_TAGS               *FormTags
 | |
|   )
 | |
| /*++
 | |
| 
 | |
| Routine Description:
 | |
| 
 | |
|   The function does the most of the works when the EFI_TAG that
 | |
|   user selects on is EFI_IFR_FLAG_INTERACTIVE or EFI_IFR_PASSWORD_OP:
 | |
|   invoke CallBack, update the new form data.
 | |
| 
 | |
| Arguments:
 | |
| 
 | |
|   Selection         - The current selection of the form.
 | |
|   CallbackData      - The pointer to host the data passed back by the callback function.
 | |
|   FileFormTagsHead  - Prompt string token of the one-of box
 | |
|   IdValue           - The current page number.
 | |
|   FormHandle        - Output the  the handle of the form.
 | |
|   TitleToken        - Output the  TitleToken of the new page.
 | |
|   FormTags          - Output the  FormFags of the new page.
 | |
| 
 | |
| Returns:
 | |
|   VOID
 | |
| 
 | |
| --*/
 | |
| {
 | |
|   UINTN                       Index;
 | |
|   UINTN                       BackupIndex;
 | |
|   EFI_FILE_FORM_TAGS          *FileFormTags;
 | |
|   EFI_FORM_TAGS               *LocalTags;
 | |
|   EFI_FORM_CALLBACK_PROTOCOL  *FormCallback;
 | |
|   EFI_STATUS                  Status;
 | |
|   UINTN                       Length;
 | |
|   UINT8                       *Buffer;
 | |
|   EFI_PHYSICAL_ADDRESS        CallbackHandle;
 | |
|   EFI_GUID                    TagGuid;
 | |
|   UINT16                      TargetPage;
 | |
|   EFI_HII_CALLBACK_PACKET     *Packet;
 | |
|   UINTN                       ScreenSize;
 | |
|   CHAR16                      NullCharacter;
 | |
|   EFI_INPUT_KEY               Key;
 | |
|   UINT16                      ConsistencyId;
 | |
|   UINT16                      CurrentVariable;
 | |
|   EFI_VARIABLE_DEFINITION     *VariableDefinition;
 | |
|   EFI_IFR_DATA_ENTRY          *DataEntry;
 | |
| 
 | |
|   VariableDefinition  = NULL;
 | |
|   NullCharacter       = CHAR_NULL;
 | |
| 
 | |
|   CurrentVariable     = 0;
 | |
|   FileFormTags        = FileFormTagsHead;
 | |
|   Length              = 0;
 | |
|   CallbackHandle      = 0;
 | |
|   TargetPage          = (UINT16) IdValue;
 | |
|   Packet              = NULL;
 | |
|   ConsistencyId       = 0;
 | |
| 
 | |
|   //
 | |
|   // Advance FileFormTags to the correct file's tag information.
 | |
|   // For instance, if Selection->IfrNumber is 3, that means the 4th
 | |
|   // file (0-based) in the FileFormTags linked-list contains the tag
 | |
|   // information.
 | |
|   //
 | |
|   for (Index = 0; Index < Selection->IfrNumber; Index++) {
 | |
|     FileFormTags = FileFormTags->NextFile;
 | |
|   }
 | |
| 
 | |
|   LocalTags = &FileFormTags->FormTags;
 | |
| 
 | |
|   //
 | |
|   // Advance Index to the FormOp with the correct ID value
 | |
|   //
 | |
|   for (; LocalTags->Next != NULL; LocalTags = LocalTags->Next) {
 | |
|     if ((LocalTags->Tags[0].CallbackHandle != 0) && (CallbackHandle == 0)) {
 | |
|       CallbackHandle = LocalTags->Tags[0].CallbackHandle;
 | |
|       CopyMem (&TagGuid, &LocalTags->Tags[0].GuidValue, sizeof (EFI_GUID));
 | |
|     }
 | |
| 
 | |
|     for (Index = 0; LocalTags->Tags[Index].Operand != EFI_IFR_FORM_OP; Index++)
 | |
|       ;
 | |
|     if (LocalTags->Tags[Index].Id == IdValue) {
 | |
|       break;
 | |
|     }
 | |
|   }
 | |
|   //
 | |
|   // If we are going to callback on a non-goto opcode, make sure we don't change pages
 | |
|   //
 | |
|   if (Selection->ThisTag->Operand != EFI_IFR_REF_OP) {
 | |
|     TargetPage = Selection->FormId;
 | |
|   }
 | |
|   //
 | |
|   // The first tag below should be the form op-code.  We need to store away the
 | |
|   // current variable setting to ensure if we have to reload the page, that we
 | |
|   // can correctly restore the values for the active variable
 | |
|   //
 | |
|   CurrentVariable = Selection->Tags[0].VariableNumber;
 | |
| 
 | |
|   //
 | |
|   // Remember that dynamic pages in an environment where all pages are not
 | |
|   // dynamic require us to call back to the user to give them an opportunity
 | |
|   // to register fresh information in the HII database so that we can extract it.
 | |
|   //
 | |
|   Status = gBS->HandleProtocol (
 | |
|                   (VOID *) (UINTN) CallbackHandle,
 | |
|                   &gEfiFormCallbackProtocolGuid,
 | |
|                   (VOID **) &FormCallback
 | |
|                   );
 | |
| 
 | |
|   if (EFI_ERROR (Status)) {
 | |
|     FreePool (LocalTags->Tags);
 | |
|     return ;
 | |
|   }
 | |
| 
 | |
|   ExtractRequestedNvMap (FileFormTags, CurrentVariable, &VariableDefinition);
 | |
| 
 | |
|   if (Selection->ThisTag->Flags & (EFI_IFR_FLAG_INTERACTIVE | EFI_IFR_FLAG_NV_ACCESS)) {
 | |
|     ((EFI_IFR_DATA_ARRAY *) CallbackData)->NvRamMap = VariableDefinition->NvRamMap;
 | |
|   } else {
 | |
|     ((EFI_IFR_DATA_ARRAY *) CallbackData)->NvRamMap = NULL;
 | |
|   }
 | |
| 
 | |
|   if ((FormCallback != NULL) && (FormCallback->Callback != NULL)) {
 | |
|     Status = FormCallback->Callback (
 | |
|                             FormCallback,
 | |
|                             Selection->ThisTag->Key,
 | |
|                             (EFI_IFR_DATA_ARRAY *) CallbackData,
 | |
|                             &Packet
 | |
|                             );
 | |
|   }
 | |
| 
 | |
|   if (EFI_ERROR (Status)) {
 | |
|     //
 | |
|     // Restore Previous Value
 | |
|     //
 | |
|     CopyMem (
 | |
|       &VariableDefinition->NvRamMap[Selection->ThisTag->StorageStart],
 | |
|       gPreviousValue,
 | |
|       Selection->ThisTag->StorageWidth
 | |
|       );
 | |
| 
 | |
|     if (Packet != NULL) {
 | |
|       //
 | |
|       // Upon error, we will likely receive a string to print out
 | |
|       //
 | |
|       ScreenSize = GetStringWidth (Packet->String) / 2;
 | |
| 
 | |
|       //
 | |
|       // Display error popup
 | |
|       //
 | |
|       CreatePopUp (ScreenSize, 3, &NullCharacter, Packet->String, &NullCharacter);
 | |
| 
 | |
|       do {
 | |
|         Status = WaitForKeyStroke (&Key);
 | |
|       } while (Key.UnicodeChar != CHAR_CARRIAGE_RETURN);
 | |
|     } else {
 | |
|       UpdateStatusBar (INPUT_ERROR, (UINT8) 0, TRUE);
 | |
|     }
 | |
| 
 | |
|   } else {
 | |
|     if (Packet != NULL) {
 | |
|       //
 | |
|       // We need to on a non-error, look in the outbound Packet for information and update the NVRAM
 | |
|       // location associated with the op-code specified there.  This is used on single op-code instances
 | |
|       // and not for when a hyperlink sent us a whole page of data.
 | |
|       //
 | |
|       DataEntry = (EFI_IFR_DATA_ENTRY *) (&Packet->DataArray + 1);
 | |
|       if (Packet->DataArray.EntryCount == 1) {
 | |
|         switch (DataEntry->OpCode) {
 | |
|         case EFI_IFR_STRING_OP:
 | |
|         case EFI_IFR_NUMERIC_OP:
 | |
|         case EFI_IFR_ORDERED_LIST_OP:
 | |
|         case EFI_IFR_ONE_OF_OP:
 | |
|         case EFI_IFR_CHECKBOX_OP:
 | |
|           CopyMem (
 | |
|             &VariableDefinition->NvRamMap[Selection->ThisTag->StorageStart],
 | |
|             &DataEntry->Data,
 | |
|             Selection->ThisTag->StorageWidth
 | |
|             );
 | |
|           break;
 | |
| 
 | |
|         case EFI_IFR_NV_ACCESS_COMMAND:
 | |
|           CopyMem (
 | |
|             &VariableDefinition->NvRamMap[((EFI_IFR_NV_DATA *) Packet)->QuestionId],
 | |
|             ((EFI_IFR_NV_DATA *) Packet) + 1,
 | |
|             ((EFI_IFR_NV_DATA *) Packet)->StorageWidth
 | |
|             );
 | |
|           break;
 | |
| 
 | |
|         }
 | |
| 
 | |
|         if (DataEntry->Flags & RESET_REQUIRED) {
 | |
|           gResetRequired = TRUE;
 | |
|         }
 | |
| 
 | |
|         if (DataEntry->Flags & EXIT_REQUIRED) {
 | |
|           gExitRequired = TRUE;
 | |
|         }
 | |
| 
 | |
|         if (DataEntry->Flags & SAVE_REQUIRED) {
 | |
|           gSaveRequired = TRUE;
 | |
|         }
 | |
| 
 | |
|         if (DataEntry->Flags & NV_CHANGED) {
 | |
|           gNvUpdateRequired = TRUE;
 | |
|         }
 | |
| 
 | |
|         if (DataEntry->Flags & NV_NOT_CHANGED) {
 | |
|           gNvUpdateRequired = FALSE;
 | |
|         }
 | |
|       }
 | |
|     }
 | |
|   }
 | |
| 
 | |
|   if (Packet != NULL) {
 | |
|     FreePool (Packet);
 | |
|   }
 | |
| 
 | |
|   for (BackupIndex = 0; LocalTags->Tags[BackupIndex].Operand != EFI_IFR_END_FORM_OP; BackupIndex++) {
 | |
|     switch (LocalTags->Tags[BackupIndex].Operand) {
 | |
|     case EFI_IFR_EQ_VAR_VAL_OP:
 | |
|     case EFI_IFR_EQ_ID_VAL_OP:
 | |
|     case EFI_IFR_EQ_ID_ID_OP:
 | |
|     case EFI_IFR_AND_OP:
 | |
|     case EFI_IFR_OR_OP:
 | |
|     case EFI_IFR_NOT_OP:
 | |
|     case EFI_IFR_TRUE_OP:
 | |
|     case EFI_IFR_FALSE_OP:
 | |
|     case EFI_IFR_GT_OP:
 | |
|     case EFI_IFR_GE_OP:
 | |
|     case EFI_IFR_EQ_ID_LIST_OP:
 | |
|       //
 | |
|       // If we encountered a ConsistencyId value, on this page they will be incremental
 | |
|       // So register the first value we encounter.  We will pass this in when we re-create this page
 | |
|       //
 | |
|       if ((LocalTags->Tags[BackupIndex].ConsistencyId != 0) && (ConsistencyId == 0)) {
 | |
|         ConsistencyId = (UINT16) (LocalTags->Tags[BackupIndex].ConsistencyId - 1);
 | |
|       }
 | |
|       break;
 | |
|     }
 | |
|   }
 | |
|   //
 | |
|   // Delete the buffer associated with previous dynamic page
 | |
|   // We will re-allocate a buffer....
 | |
|   //
 | |
|   FreePool (LocalTags->Tags);
 | |
| 
 | |
|   Length  = 0xF000;
 | |
|   Buffer  = AllocateZeroPool (Length);
 | |
|   ASSERT (Buffer != NULL);
 | |
| 
 | |
|   //
 | |
|   // Get the form that was updated by the callback
 | |
|   //
 | |
|   Hii->GetForms (
 | |
|         Hii,
 | |
|         Selection->Handle,
 | |
|         TargetPage,
 | |
|         &Length,
 | |
|         Buffer
 | |
|         );
 | |
| 
 | |
|   //
 | |
|   // Ok, we have the new page.....now we must purge the old page and re-allocate
 | |
|   // the tag page with the new data
 | |
|   //
 | |
|   UpdateNewTagData (
 | |
|     Buffer,
 | |
|     ConsistencyId,
 | |
|     CurrentVariable,
 | |
|     LocalTags,
 | |
|     FileFormTags
 | |
|     );
 | |
| 
 | |
|   //
 | |
|   // return the Form Id, Text, and the File's FormTags structure
 | |
|   //
 | |
|   *FormHandle                       = LocalTags->Tags[0].Id;
 | |
|   *TitleToken                       = LocalTags->Tags[0].Text;
 | |
|   *FormTags                         = *LocalTags;
 | |
| 
 | |
|   FormTags->Tags[0].CallbackHandle  = CallbackHandle;
 | |
|   CopyMem (&FormTags->Tags[0].GuidValue, &TagGuid, sizeof (EFI_GUID));
 | |
| 
 | |
|   return ;
 | |
| }
 | |
| 
 | |
| UI_MENU_OPTION *
 | |
| SetupBrowser (
 | |
|   IN  UI_MENU_OPTION              *Selection,
 | |
|   IN  BOOLEAN                     Callback,
 | |
|   IN  EFI_FILE_FORM_TAGS          *FileFormTagsHead,
 | |
|   IN  UINT8                       *CallbackData
 | |
|   )
 | |
| {
 | |
|   UINT16        FormHandle;
 | |
|   UINT16        TitleToken;
 | |
|   EFI_FORM_TAGS FormTags;
 | |
| 
 | |
|   gEntryNumber  = -1;
 | |
|   gLastOpr      = FALSE;
 | |
|   //
 | |
|   // Displays the Header and Footer borders
 | |
|   //
 | |
|   DisplayPageFrame ();
 | |
| 
 | |
|   //
 | |
|   // Id of 0 yields the getting of the top form whatever the ID is.  Usually the first form in the IFR
 | |
|   //
 | |
|   ExtractFormHandle (Selection, FileFormTagsHead, 0, &FormHandle, &TitleToken, &FormTags);
 | |
| 
 | |
|   Selection = DisplayForm (Selection, FormHandle, TitleToken, FormTags, FileFormTagsHead, CallbackData);
 | |
| 
 | |
|   //
 | |
|   // If selection is null use the former selection
 | |
|   //
 | |
|   if (Selection == NULL) {
 | |
|     return Selection;
 | |
|   }
 | |
| 
 | |
|   if (Callback) {
 | |
|     return Selection;
 | |
|   }
 | |
| 
 | |
|   while (Selection->Tags != NULL) {
 | |
|     if (Selection->Previous) {
 | |
|       ExtractFormHandle (Selection, FileFormTagsHead, Selection->FormId, &FormHandle, &TitleToken, &FormTags);
 | |
|     } else {
 | |
|       //
 | |
|       // True if a hyperlink/jump is selected
 | |
|       //
 | |
|       if (Selection->ThisTag->Operand == EFI_IFR_REF_OP && Selection->ThisTag->Id != 0x0000) {
 | |
|         if (Selection->ThisTag->Flags & EFI_IFR_FLAG_INTERACTIVE) {
 | |
|           ExtractDynamicFormHandle (
 | |
|             Selection,
 | |
|             CallbackData,
 | |
|             FileFormTagsHead,
 | |
|             Selection->ThisTag->Id,
 | |
|             &FormHandle,
 | |
|             &TitleToken,
 | |
|             &FormTags
 | |
|             );
 | |
|           goto DisplayPage;
 | |
|         } else {
 | |
|           ExtractFormHandle (Selection, FileFormTagsHead, Selection->ThisTag->Id, &FormHandle, &TitleToken, &FormTags);
 | |
|           goto DisplayPage;
 | |
|         }
 | |
|       }
 | |
| 
 | |
|       if ((Selection->ThisTag->Flags & EFI_IFR_FLAG_INTERACTIVE) &&
 | |
|           (Selection->ThisTag->Operand != EFI_IFR_PASSWORD_OP)
 | |
|           ) {
 | |
|         ExtractDynamicFormHandle (
 | |
|           Selection,
 | |
|           CallbackData,
 | |
|           FileFormTagsHead,
 | |
|           Selection->FormId,
 | |
|           &FormHandle,
 | |
|           &TitleToken,
 | |
|           &FormTags
 | |
|           );
 | |
|       } else {
 | |
|         ExtractFormHandle (Selection, FileFormTagsHead, Selection->FormId, &FormHandle, &TitleToken, &FormTags);
 | |
|       }
 | |
|     }
 | |
| 
 | |
| DisplayPage:
 | |
|     //
 | |
|     // Displays the Header and Footer borders
 | |
|     //
 | |
|     DisplayPageFrame ();
 | |
| 
 | |
|     Selection = DisplayForm (Selection, FormHandle, TitleToken, FormTags, FileFormTagsHead, CallbackData);
 | |
| 
 | |
|     if (Selection == NULL) {
 | |
|       break;
 | |
|     }
 | |
|   };
 | |
| 
 | |
|   return Selection;
 | |
| }
 |