]> git.proxmox.com Git - mirror_edk2.git/blobdiff - MdeModulePkg/Universal/SetupBrowserDxe/Ui.c
Add code check to avoid access violation.
[mirror_edk2.git] / MdeModulePkg / Universal / SetupBrowserDxe / Ui.c
index 4dd439521e5b8408b5838d8f8079ffe9db8067ba..1c3a7f6ba441f54879fd2864b3208231b8b3091e 100644 (file)
@@ -1,7 +1,7 @@
 /** @file\r
 Utility functions for User Interface functions.\r
 \r
-Copyright (c) 2004 - 2011, Intel Corporation. All rights reserved.<BR>\r
+Copyright (c) 2004 - 2012, Intel Corporation. All rights reserved.<BR>\r
 This program and the accompanying materials\r
 are licensed and made available under the terms and conditions of the BSD License\r
 which accompanies this distribution.  The full text of the license may be found at\r
@@ -324,6 +324,102 @@ UiFreeRefreshList (
 }\r
 \r
 \r
+/**\r
+  Process option string for date/time opcode.\r
+\r
+  @param  MenuOption              Menu option point to date/time.\r
+  @param  OptionString            Option string input for process.\r
+  @param  AddOptCol               Whether need to update MenuOption->OptCol. \r
+\r
+**/\r
+VOID \r
+ProcessStringForDateTime (\r
+  UI_MENU_OPTION                  *MenuOption,\r
+  CHAR16                          *OptionString,\r
+  BOOLEAN                         AddOptCol\r
+  )\r
+{\r
+  UINTN Index;\r
+  UINTN Count;\r
+  FORM_BROWSER_STATEMENT          *Statement;\r
+\r
+  ASSERT (MenuOption != NULL && OptionString != NULL);\r
+  \r
+  Statement = MenuOption->ThisTag;\r
+  \r
+  //\r
+  // If leading spaces on OptionString - remove the spaces\r
+  //\r
+  for (Index = 0; OptionString[Index] == L' '; Index++) {\r
+    //\r
+    // Base on the blockspace to get the option column info.\r
+    //\r
+    if (AddOptCol) {\r
+      MenuOption->OptCol++;\r
+    }\r
+  }\r
+  \r
+  for (Count = 0; OptionString[Index] != CHAR_NULL; Index++) {\r
+    OptionString[Count] = OptionString[Index];\r
+    Count++;\r
+  }\r
+  OptionString[Count] = CHAR_NULL;\r
+  \r
+  //\r
+  // Enable to suppress field in the opcode base on the flag.\r
+  //\r
+  if (Statement->Operand == EFI_IFR_DATE_OP) {\r
+    //\r
+    // OptionString format is: <**:  **: ****>\r
+    //                        |month|day|year|\r
+    //                          4     3    5\r
+    //\r
+    if ((Statement->Flags & EFI_QF_DATE_MONTH_SUPPRESS) && (MenuOption->Sequence == 0)) {\r
+      //\r
+      // At this point, only "<**:" in the optionstring. \r
+      // Clean the day's ** field, after clean, the format is "<  :"\r
+      //\r
+      SetUnicodeMem (&OptionString[1], 2, L' ');\r
+    } else if ((Statement->Flags & EFI_QF_DATE_DAY_SUPPRESS) && (MenuOption->Sequence == 1)) {\r
+      //\r
+      // At this point, only "**:" in the optionstring. \r
+      // Clean the month's "**" field, after clean, the format is "  :"\r
+      //                \r
+      SetUnicodeMem (&OptionString[0], 2, L' ');\r
+    } else if ((Statement->Flags & EFI_QF_DATE_YEAR_SUPPRESS) && (MenuOption->Sequence == 2)) {\r
+      //\r
+      // At this point, only "****>" in the optionstring. \r
+      // Clean the year's "****" field, after clean, the format is "  >"\r
+      //                \r
+      SetUnicodeMem (&OptionString[0], 4, L' ');\r
+    }\r
+  } else if (Statement->Operand == EFI_IFR_TIME_OP) {\r
+    //\r
+    // OptionString format is: <**:  **:    **>\r
+    //                        |hour|minute|second|\r
+    //                          4     3      3\r
+    //\r
+    if ((Statement->Flags & QF_TIME_HOUR_SUPPRESS) && (MenuOption->Sequence == 0)) {\r
+      //\r
+      // At this point, only "<**:" in the optionstring. \r
+      // Clean the hour's ** field, after clean, the format is "<  :"\r
+      //\r
+      SetUnicodeMem (&OptionString[1], 2, L' ');\r
+    } else if ((Statement->Flags & QF_TIME_MINUTE_SUPPRESS) && (MenuOption->Sequence == 1)) {\r
+      //\r
+      // At this point, only "**:" in the optionstring. \r
+      // Clean the minute's "**" field, after clean, the format is "  :"\r
+      //                \r
+      SetUnicodeMem (&OptionString[0], 2, L' ');\r
+    } else if ((Statement->Flags & QF_TIME_SECOND_SUPPRESS) && (MenuOption->Sequence == 2)) {\r
+      //\r
+      // At this point, only "**>" in the optionstring. \r
+      // Clean the second's "**" field, after clean, the format is "  >"\r
+      //                \r
+      SetUnicodeMem (&OptionString[0], 2, L' ');\r
+    }\r
+  }\r
+}\r
 \r
 /**\r
   Refresh question.\r
@@ -336,7 +432,6 @@ RefreshQuestion (
   )\r
 {\r
   CHAR16                          *OptionString;\r
-  UINTN                           Index;\r
   EFI_STATUS                      Status;\r
   UI_MENU_SELECTION               *Selection;\r
   FORM_BROWSER_STATEMENT          *Question;\r
@@ -353,12 +448,6 @@ RefreshQuestion (
   ProcessOptions (Selection, MenuRefreshEntry->MenuOption, FALSE, &OptionString);\r
 \r
   if (OptionString != NULL) {\r
-    //\r
-    // If leading spaces on OptionString - remove the spaces\r
-    //\r
-    for (Index = 0; OptionString[Index] == L' '; Index++)\r
-      ;\r
-\r
     //\r
     // If old Text is longer than new string, need to clean the old string before paint the newer.\r
     // This option is no need for time/date opcode, because time/data opcode has fixed string length.\r
@@ -375,7 +464,8 @@ RefreshQuestion (
     }\r
 \r
     gST->ConOut->SetAttribute (gST->ConOut, MenuRefreshEntry->CurrentAttribute);\r
-    PrintStringAt (MenuRefreshEntry->CurrentColumn, MenuRefreshEntry->CurrentRow, &OptionString[Index]);\r
+    ProcessStringForDateTime(MenuRefreshEntry->MenuOption, OptionString, FALSE);\r
+    PrintStringAt (MenuRefreshEntry->CurrentColumn, MenuRefreshEntry->CurrentRow, OptionString);\r
     FreePool (OptionString);\r
   }\r
 \r
@@ -577,6 +667,7 @@ UiWaitForSingleEvent (
 \r
   @param  String                 String description for this option.\r
   @param  Handle                 Hii handle for the package list.\r
+  @param  Form                   The form this statement belong to.\r
   @param  Statement              Statement of this Menu Option.\r
   @param  NumberOfLines          Display lines for this Menu Option.\r
   @param  MenuItemCount          The index for this Option in the Menu.\r
@@ -588,6 +679,7 @@ UI_MENU_OPTION *
 UiAddMenuOption (\r
   IN CHAR16                  *String,\r
   IN EFI_HII_HANDLE          Handle,\r
+  IN FORM_BROWSER_FORM       *Form,\r
   IN FORM_BROWSER_STATEMENT  *Statement,\r
   IN UINT16                  NumberOfLines,\r
   IN UINT16                  MenuItemCount\r
@@ -639,10 +731,19 @@ UiAddMenuOption (
     }\r
     MenuOption->Sequence = Index;\r
 \r
-    if (Statement->GrayOutExpression != NULL) {\r
-      MenuOption->GrayOut = Statement->GrayOutExpression->Result.Value.b;\r
+    if (EvaluateExpressionList(Statement->Expression, FALSE, NULL, NULL) == ExpressGrayOut ) {\r
+      MenuOption->GrayOut = TRUE;\r
+    } else {\r
+      MenuOption->GrayOut = FALSE;\r
     }\r
 \r
+    //\r
+    // If the form or the question has the lock attribute, deal same as grayout.\r
+    //\r
+    if (Form->Locked || Statement->Locked) {\r
+      MenuOption->GrayOut = TRUE;\r
+    }\r
+    \r
     switch (Statement->Operand) {\r
     case EFI_IFR_ORDERED_LIST_OP:\r
     case EFI_IFR_ONE_OF_OP:\r
@@ -751,8 +852,6 @@ CreateDialog (
   ASSERT (TempString);\r
   ASSERT (BufferedString);\r
 \r
-  VA_START (Marker, KeyValue);\r
-\r
   //\r
   // Zero the outgoing buffer\r
   //\r
@@ -774,6 +873,8 @@ CreateDialog (
 \r
   LargestString = 0;\r
 \r
+  VA_START (Marker, KeyValue);\r
+\r
   //\r
   // Determine the largest string in the dialog box\r
   // Notice we are starting with 1 since String is the first string\r
@@ -1792,6 +1893,7 @@ ProcessGotoOpCode (
   )\r
 {\r
   CHAR16                          *StringPtr;\r
+  UINTN                           StringLen;\r
   UINTN                           BufferSize;\r
   EFI_DEVICE_PATH_PROTOCOL        *DevicePath;\r
   CHAR16                          TemStr[2];\r
@@ -1806,8 +1908,23 @@ ProcessGotoOpCode (
   \r
   Status = EFI_SUCCESS;\r
   UpdateFormInfo = TRUE;\r
+  StringPtr = NULL;\r
+  StringLen = 0;\r
 \r
+  //\r
+  // Prepare the device path check, get the device path info first.\r
+  //\r
   if (Statement->HiiValue.Value.ref.DevicePath != 0) {\r
+    StringPtr = GetToken (Statement->HiiValue.Value.ref.DevicePath, Selection->FormSet->HiiHandle);\r
+    if (StringPtr != NULL) {\r
+      StringLen = StrLen (StringPtr);\r
+    }\r
+  }\r
+\r
+  //\r
+  // Check whether the device path string is a valid string.\r
+  //\r
+  if (Statement->HiiValue.Value.ref.DevicePath != 0 && StringPtr != NULL && StringLen != 0) {\r
     if (Selection->Form->ModalForm) {\r
       return Status;\r
     }\r
@@ -1815,16 +1932,6 @@ ProcessGotoOpCode (
     // Goto another Hii Package list\r
     //\r
     Selection->Action = UI_ACTION_REFRESH_FORMSET;\r
-\r
-    StringPtr = GetToken (Statement->HiiValue.Value.ref.DevicePath, Selection->FormSet->HiiHandle);\r
-    if (StringPtr == NULL) {\r
-      //\r
-      // No device path string not found, exit\r
-      //\r
-      Selection->Action = UI_ACTION_EXIT;\r
-      Selection->Statement = NULL;\r
-      return Status;\r
-    }\r
     BufferSize = StrLen (StringPtr) / 2;\r
     DevicePath = AllocatePool (BufferSize);\r
     ASSERT (DevicePath != NULL);\r
@@ -1848,8 +1955,11 @@ ProcessGotoOpCode (
         DevicePathBuffer [Index/2] = (UINT8) ((DevicePathBuffer [Index/2] << 4) + DigitUint8);\r
       }\r
     }\r
+    FreePool (StringPtr);\r
 \r
     Selection->Handle = DevicePathToHiiHandle (DevicePath);\r
+    FreePool (DevicePath);\r
+\r
     if (Selection->Handle == NULL) {\r
       //\r
       // If target Hii Handle not found, exit\r
@@ -1859,9 +1969,6 @@ ProcessGotoOpCode (
       return Status;\r
     }\r
 \r
-    FreePool (StringPtr);\r
-    FreePool (DevicePath);\r
-\r
     CopyMem (&Selection->FormSetGuid,&Statement->HiiValue.Value.ref.FormSetGuid, sizeof (EFI_GUID));\r
     Selection->FormId = Statement->HiiValue.Value.ref.FormId;\r
     Selection->QuestionId = Statement->HiiValue.Value.ref.QuestionId;\r
@@ -1894,12 +2001,7 @@ ProcessGotoOpCode (
     RefForm = IdToForm (Selection->FormSet, Statement->HiiValue.Value.ref.FormId);\r
 \r
     if ((RefForm != NULL) && (RefForm->SuppressExpression != NULL)) {\r
-      Status = EvaluateExpression (Selection->FormSet, RefForm, RefForm->SuppressExpression);\r
-      if (EFI_ERROR (Status)) {\r
-        return Status;\r
-      }\r
-\r
-      if (RefForm->SuppressExpression->Result.Value.b) {\r
+      if (EvaluateExpressionList(RefForm->SuppressExpression, TRUE, Selection->FormSet, RefForm) != ExpressFalse) {\r
         //\r
         // Form is suppressed. \r
         //\r
@@ -1984,7 +2086,6 @@ UiDisplayMenu (
   UINTN                           BottomRow;\r
   UINTN                           OriginalRow;\r
   UINTN                           Index;\r
-  UINT32                          Count;\r
   UINT16                          Width;\r
   CHAR16                          *StringPtr;\r
   CHAR16                          *OptionString;\r
@@ -2226,19 +2327,7 @@ UiDisplayMenu (
 \r
           if (OptionString != NULL) {\r
             if (Statement->Operand == EFI_IFR_DATE_OP || Statement->Operand == EFI_IFR_TIME_OP) {\r
-              //\r
-              // If leading spaces on OptionString - remove the spaces\r
-              //\r
-              for (Index = 0; OptionString[Index] == L' '; Index++) {\r
-                MenuOption->OptCol++;\r
-              }\r
-\r
-              for (Count = 0; OptionString[Index] != CHAR_NULL; Index++) {\r
-                OptionString[Count] = OptionString[Index];\r
-                Count++;\r
-              }\r
-\r
-              OptionString[Count] = CHAR_NULL;\r
+              ProcessStringForDateTime(MenuOption, OptionString, TRUE);\r
             }\r
 \r
             Width       = (UINT16) gOptionBlockWidth;\r
@@ -2483,7 +2572,22 @@ UiDisplayMenu (
             SavedMenuOption = MENU_OPTION_FROM_LINK (Link);\r
           }\r
 \r
-          if (Link != NewPos || Index > BottomRow || (Link == NewPos && SavedMenuOption->Row + SavedMenuOption->Skip - 1 > BottomRow)) {\r
+          //\r
+          // Not find the selected menu in current show page.\r
+          // Have two case to enter this if:\r
+          // 1. Not find the menu at current page.\r
+          // 2. Find the menu in current page, but the menu shows at the bottom and not all info shows.\r
+          //    For case 2, has an exception: The menu can show more than one pages and now only this menu shows.\r
+          //\r
+          // Base on the selected menu will show at the bottom of the page,\r
+          // select the menu which will show at the top of the page.\r
+          //\r
+          if (Link != NewPos || Index > BottomRow || \r
+              (Link == NewPos && (SavedMenuOption->Row + SavedMenuOption->Skip - 1 > BottomRow) && (Link != TopOfScreen))) {\r
+            //\r
+            // Find the MenuOption which has the skip value for Date/Time opcode. \r
+            //\r
+            AdjustDateAndTimePosition(FALSE, &NewPos);\r
             //\r
             // NewPos is not in the current page, simply scroll page so that NewPos is in the end of the page\r
             //\r
@@ -2494,7 +2598,11 @@ UiDisplayMenu (
             if (SavedMenuOption->Row == 0) {\r
               UpdateOptionSkipLines (Selection, SavedMenuOption);\r
             }\r
-            \r
+\r
+            //\r
+            // Base on the selected menu will show at the bottome of next page, \r
+            // select the menu show at the top of the next page. \r
+            //\r
             Link    = NewPos;\r
             for (Index = TopRow + SavedMenuOption->Skip; Index <= BottomRow + 1; ) {            \r
               Link = Link->BackLink;\r
@@ -2502,16 +2610,31 @@ UiDisplayMenu (
               if (SavedMenuOption->Row == 0) {\r
                 UpdateOptionSkipLines (Selection, SavedMenuOption);\r
               }\r
-              Index     += SavedMenuOption->Skip;\r
+              Index += SavedMenuOption->Skip;\r
             }\r
-            \r
-            SkipValue = Index - BottomRow - 1;\r
-            if (SkipValue > 0 && SkipValue < (INTN) SavedMenuOption->Skip) {\r
-              TopOfScreen     = Link;\r
-              OldSkipValue    = SkipValue;\r
+\r
+            //\r
+            // Found the menu which will show at the top of the page.\r
+            //\r
+            if (Link == NewPos) {\r
+              //\r
+              // The menu can show more than one pages, just show the menu at the top of the page.\r
+              //\r
+              SkipValue    = 0;\r
+              TopOfScreen  = Link;\r
+              OldSkipValue = SkipValue;\r
             } else {\r
-              SkipValue       = 0;\r
-              TopOfScreen     = Link->ForwardLink;\r
+              //\r
+              // Check whether need to skip some line for menu shows at the top of the page.\r
+              //\r
+              SkipValue = Index - BottomRow - 1;\r
+              if (SkipValue > 0 && SkipValue < (INTN) SavedMenuOption->Skip) {\r
+                TopOfScreen     = Link;\r
+                OldSkipValue    = SkipValue;\r
+              } else {\r
+                SkipValue       = 0;\r
+                TopOfScreen     = Link->ForwardLink;\r
+              }\r
             }\r
 \r
             Repaint = TRUE;\r
@@ -2541,18 +2664,7 @@ UiDisplayMenu (
             if ((MenuOption->ThisTag->Operand == EFI_IFR_DATE_OP) ||\r
                 (MenuOption->ThisTag->Operand == EFI_IFR_TIME_OP)\r
                ) {\r
-              //\r
-              // If leading spaces on OptionString - remove the spaces\r
-              //\r
-              for (Index = 0; OptionString[Index] == L' '; Index++)\r
-                ;\r
-\r
-              for (Count = 0; OptionString[Index] != CHAR_NULL; Index++) {\r
-                OptionString[Count] = OptionString[Index];\r
-                Count++;\r
-              }\r
-\r
-              OptionString[Count] = CHAR_NULL;\r
+              ProcessStringForDateTime(MenuOption, OptionString, FALSE);\r
             }\r
 \r
             Width               = (UINT16) gOptionBlockWidth;\r
@@ -2651,18 +2763,7 @@ UiDisplayMenu (
         ProcessOptions (Selection, MenuOption, FALSE, &OptionString);\r
         if (OptionString != NULL) {\r
           if (Statement->Operand == EFI_IFR_DATE_OP || Statement->Operand == EFI_IFR_TIME_OP) {\r
-            //\r
-            // If leading spaces on OptionString - remove the spaces\r
-            //\r
-            for (Index = 0; OptionString[Index] == L' '; Index++)\r
-              ;\r
-\r
-            for (Count = 0; OptionString[Index] != CHAR_NULL; Index++) {\r
-              OptionString[Count] = OptionString[Index];\r
-              Count++;\r
-            }\r
-\r
-            OptionString[Count] = CHAR_NULL;\r
+            ProcessStringForDateTime(MenuOption, OptionString, FALSE);\r
           }\r
           Width               = (UINT16) gOptionBlockWidth;\r
 \r
@@ -2802,6 +2903,11 @@ UiDisplayMenu (
 \r
       switch (Key.UnicodeChar) {\r
       case CHAR_CARRIAGE_RETURN:\r
+        if(MenuOption->GrayOut || MenuOption->ReadOnly) {\r
+          ControlFlag = CfReadKey;\r
+          break;\r
+        }\r
+\r
         ScreenOperation = UiSelect;\r
         gDirection      = 0;\r
         break;\r
@@ -2816,7 +2922,7 @@ UiDisplayMenu (
         // If the screen has no menu items, and the user didn't select UiReset\r
         // ignore the selection and go back to reading keys.\r
         //\r
-        if(IsListEmpty (&gMenuOption)) {\r
+        if(IsListEmpty (&gMenuOption) || MenuOption->GrayOut || MenuOption->ReadOnly) {\r
           ControlFlag = CfReadKey;\r
           break;\r
         }\r
@@ -2869,7 +2975,7 @@ UiDisplayMenu (
           }\r
           \r
           ASSERT(MenuOption != NULL);\r
-          if (MenuOption->ThisTag->Operand == EFI_IFR_CHECKBOX_OP && !MenuOption->GrayOut) {\r
+          if (MenuOption->ThisTag->Operand == EFI_IFR_CHECKBOX_OP && !MenuOption->GrayOut && !MenuOption->ReadOnly) {\r
             ScreenOperation = UiSelect;\r
           }\r
         }\r