+/**\r
+ Find HII Handle in the HII database associated with given form set guid.\r
+\r
+ If FormSetGuid is NULL, then ASSERT.\r
+\r
+ @param ComparingGuid FormSet Guid associated with the HII package list\r
+ handle.\r
+\r
+ @retval Handle HII package list Handle associated with the Device\r
+ Path.\r
+ @retval NULL Hii Package list handle is not found.\r
+\r
+**/\r
+EFI_HII_HANDLE\r
+FormSetGuidToHiiHandle (\r
+ EFI_GUID *ComparingGuid\r
+ )\r
+{\r
+ EFI_HII_HANDLE *HiiHandles;\r
+ UINTN Index;\r
+ EFI_HII_PACKAGE_LIST_HEADER *HiiPackageList;\r
+ UINTN BufferSize;\r
+ UINT32 Offset;\r
+ UINT32 Offset2;\r
+ UINT32 PackageListLength;\r
+ EFI_HII_PACKAGE_HEADER PackageHeader;\r
+ UINT8 *Package;\r
+ UINT8 *OpCodeData;\r
+ EFI_STATUS Status;\r
+ EFI_HII_HANDLE HiiHandle;\r
+\r
+ ASSERT (ComparingGuid != NULL);\r
+\r
+ HiiHandle = NULL;\r
+ //\r
+ // Get all the Hii handles\r
+ //\r
+ HiiHandles = HiiGetHiiHandles (NULL);\r
+ ASSERT (HiiHandles != NULL);\r
+\r
+ //\r
+ // Search for formset of each class type\r
+ //\r
+ for (Index = 0; HiiHandles[Index] != NULL; Index++) {\r
+ BufferSize = 0;\r
+ HiiPackageList = NULL;\r
+ Status = mHiiDatabase->ExportPackageLists (mHiiDatabase, HiiHandles[Index], &BufferSize, HiiPackageList);\r
+ if (Status == EFI_BUFFER_TOO_SMALL) {\r
+ HiiPackageList = AllocatePool (BufferSize);\r
+ ASSERT (HiiPackageList != NULL);\r
+\r
+ Status = mHiiDatabase->ExportPackageLists (mHiiDatabase, HiiHandles[Index], &BufferSize, HiiPackageList);\r
+ }\r
+ if (EFI_ERROR (Status) || HiiPackageList == NULL) {\r
+ return NULL;\r
+ }\r
+\r
+ //\r
+ // Get Form package from this HII package List\r
+ //\r
+ Offset = sizeof (EFI_HII_PACKAGE_LIST_HEADER);\r
+ Offset2 = 0;\r
+ CopyMem (&PackageListLength, &HiiPackageList->PackageLength, sizeof (UINT32)); \r
+\r
+ while (Offset < PackageListLength) {\r
+ Package = ((UINT8 *) HiiPackageList) + Offset;\r
+ CopyMem (&PackageHeader, Package, sizeof (EFI_HII_PACKAGE_HEADER));\r
+\r
+ if (PackageHeader.Type == EFI_HII_PACKAGE_FORMS) {\r
+ //\r
+ // Search FormSet in this Form Package\r
+ //\r
+ Offset2 = sizeof (EFI_HII_PACKAGE_HEADER);\r
+ while (Offset2 < PackageHeader.Length) {\r
+ OpCodeData = Package + Offset2;\r
+\r
+ if (((EFI_IFR_OP_HEADER *) OpCodeData)->OpCode == EFI_IFR_FORM_SET_OP) {\r
+ //\r
+ // Try to compare against formset GUID\r
+ //\r
+ if (CompareGuid (ComparingGuid, (EFI_GUID *)(OpCodeData + sizeof (EFI_IFR_OP_HEADER)))) {\r
+ HiiHandle = HiiHandles[Index];\r
+ break;\r
+ }\r
+ }\r
+\r
+ Offset2 += ((EFI_IFR_OP_HEADER *) OpCodeData)->Length;\r
+ }\r
+ }\r
+ if (HiiHandle != NULL) {\r
+ break;\r
+ }\r
+ Offset += PackageHeader.Length;\r
+ }\r
+ \r
+ FreePool (HiiPackageList);\r
+ if (HiiHandle != NULL) {\r
+ break;\r
+ }\r
+ }\r
+\r
+ FreePool (HiiHandles);\r
+\r
+ return HiiHandle;\r
+}\r
+\r
+/**\r
+ Process the goto op code, update the info in the selection structure.\r
+\r
+ @param Statement The statement belong to goto op code.\r
+ @param Selection The selection info.\r
+ @param Repaint Whether need to repaint the menu.\r
+ @param NewLine Whether need to create new line.\r
+\r
+ @retval EFI_SUCCESS The menu process successfully.\r
+ @return Other value if the process failed.\r
+**/\r
+EFI_STATUS\r
+ProcessGotoOpCode (\r
+ IN OUT FORM_BROWSER_STATEMENT *Statement,\r
+ IN OUT UI_MENU_SELECTION *Selection,\r
+ OUT BOOLEAN *Repaint,\r
+ OUT BOOLEAN *NewLine\r
+ )\r
+{\r
+ CHAR16 *StringPtr;\r
+ EFI_DEVICE_PATH_PROTOCOL *DevicePath;\r
+ FORM_BROWSER_FORM *RefForm;\r
+ EFI_INPUT_KEY Key;\r
+ EFI_STATUS Status;\r
+ UI_MENU_LIST *MenuList;\r
+ BOOLEAN UpdateFormInfo;\r
+ \r
+ Status = EFI_SUCCESS;\r
+ UpdateFormInfo = TRUE;\r
+ StringPtr = NULL;\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
+ }\r
+\r
+ //\r
+ // Check whether the device path string is a valid string.\r
+ //\r
+ if (Statement->HiiValue.Value.ref.DevicePath != 0 && StringPtr != NULL) {\r
+ if (Selection->Form->ModalForm) {\r
+ return Status;\r
+ }\r
+\r
+ //\r
+ // Goto another Hii Package list\r
+ //\r
+ if (mPathFromText != NULL) {\r
+ DevicePath = mPathFromText->ConvertTextToDevicePath(StringPtr);\r
+ if (DevicePath != NULL) {\r
+ Selection->Handle = DevicePathToHiiHandle (DevicePath);\r
+ FreePool (DevicePath);\r
+ }\r
+ FreePool (StringPtr);\r
+ } else {\r
+ //\r
+ // Not found the EFI_DEVICE_PATH_FROM_TEXT_PROTOCOL protocol.\r
+ //\r
+ do {\r
+ CreateDialog (4, TRUE, 0, NULL, &Key, gEmptyString, gProtocolNotFound, gPressEnter, gEmptyString);\r
+ } while (Key.UnicodeChar != CHAR_CARRIAGE_RETURN);\r
+ if (Repaint != NULL) {\r
+ *Repaint = TRUE;\r
+ }\r
+ FreePool (StringPtr);\r
+ return Status;\r
+ }\r
+\r
+ Selection->Action = UI_ACTION_REFRESH_FORMSET;\r
+ if (Selection->Handle == NULL) {\r
+ //\r
+ // If target Hii Handle not found, exit\r
+ //\r
+ Selection->Action = UI_ACTION_EXIT;\r
+ Selection->Statement = NULL;\r
+ return Status;\r
+ }\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
+ } else if (!CompareGuid (&Statement->HiiValue.Value.ref.FormSetGuid, &gZeroGuid)) {\r
+ if (Selection->Form->ModalForm) {\r
+ return Status;\r
+ } \r
+ //\r
+ // Goto another Formset, check for uncommitted data\r
+ //\r
+ Selection->Action = UI_ACTION_REFRESH_FORMSET;\r
+ \r
+ Selection->Handle = FormSetGuidToHiiHandle(&Statement->HiiValue.Value.ref.FormSetGuid);\r
+ if (Selection->Handle == NULL) {\r
+ //\r
+ // If target Hii Handle not found, exit\r
+ //\r
+ Selection->Action = UI_ACTION_EXIT;\r
+ Selection->Statement = NULL;\r
+ return Status;\r
+ } \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
+ } else if (Statement->HiiValue.Value.ref.FormId != 0) {\r
+ //\r
+ // Check whether target From is suppressed.\r
+ //\r
+ RefForm = IdToForm (Selection->FormSet, Statement->HiiValue.Value.ref.FormId);\r
+\r
+ if ((RefForm != NULL) && (RefForm->SuppressExpression != NULL)) {\r
+ if (EvaluateExpressionList(RefForm->SuppressExpression, TRUE, Selection->FormSet, RefForm) != ExpressFalse) {\r
+ //\r
+ // Form is suppressed. \r
+ //\r
+ do {\r
+ CreateDialog (4, TRUE, 0, NULL, &Key, gEmptyString, gFormSuppress, gPressEnter, gEmptyString);\r
+ } while (Key.UnicodeChar != CHAR_CARRIAGE_RETURN);\r
+ if (Repaint != NULL) {\r
+ *Repaint = TRUE;\r
+ }\r
+ return Status;\r
+ }\r
+ }\r
+\r
+ //\r
+ // Goto another form inside this formset,\r
+ //\r
+ Selection->Action = UI_ACTION_REFRESH_FORM;\r
+\r
+ Selection->FormId = Statement->HiiValue.Value.ref.FormId;\r
+ Selection->QuestionId = Statement->HiiValue.Value.ref.QuestionId;\r
+ } else if (Statement->HiiValue.Value.ref.QuestionId != 0) {\r
+ //\r
+ // Goto another Question\r
+ //\r
+ Selection->QuestionId = Statement->HiiValue.Value.ref.QuestionId;\r
+\r
+ if ((Statement->QuestionFlags & EFI_IFR_FLAG_CALLBACK) != 0) {\r
+ Selection->Action = UI_ACTION_REFRESH_FORM;\r
+ } else {\r
+ if (Repaint != NULL) {\r
+ *Repaint = TRUE;\r
+ }\r
+ if (NewLine != NULL) {\r
+ *NewLine = TRUE;\r
+ }\r
+ }\r
+ UpdateFormInfo = FALSE;\r
+ } else {\r
+ if ((Statement->QuestionFlags & EFI_IFR_FLAG_CALLBACK) != 0) {\r
+ Selection->Action = UI_ACTION_REFRESH_FORM;\r
+ }\r
+ UpdateFormInfo = FALSE;\r
+ }\r
+\r
+ if (UpdateFormInfo) {\r
+ //\r
+ // Link current form so that we can always go back when someone hits the ESC\r
+ //\r
+ MenuList = UiFindMenuList (&Selection->FormSetGuid, Selection->FormId);\r
+ if (MenuList == NULL && Selection->CurrentMenu != NULL) {\r
+ MenuList = UiAddMenuList (Selection->CurrentMenu, Selection->Handle, &Selection->FormSetGuid, Selection->FormId);\r
+ }\r
+ }\r
+\r
+ return Status;\r
+}\r
+\r