+/**\r
+ Remove the Request element from the Config Request.\r
+\r
+ @param Storage Pointer to the browser storage.\r
+ @param RequestElement The pointer to the Request element.\r
+\r
+**/\r
+VOID\r
+RemoveElement (\r
+ IN OUT BROWSER_STORAGE *Storage,\r
+ IN CHAR16 *RequestElement\r
+ )\r
+{\r
+ CHAR16 *NewStr;\r
+ CHAR16 *DestStr;\r
+\r
+ ASSERT (Storage->ConfigRequest != NULL && RequestElement != NULL);\r
+\r
+ NewStr = StrStr (Storage->ConfigRequest, RequestElement);\r
+\r
+ if (NewStr == NULL) {\r
+ return;\r
+ }\r
+\r
+ //\r
+ // Remove this element from this ConfigRequest.\r
+ //\r
+ DestStr = NewStr;\r
+ NewStr += StrLen (RequestElement);\r
+ CopyMem (DestStr, NewStr, StrSize (NewStr));\r
+ \r
+ Storage->SpareStrLen += StrLen (RequestElement); \r
+}\r
+\r
+/**\r
+ Adjust config request in storage, remove the request elements existed in the input ConfigRequest.\r
+\r
+ @param Storage Pointer to the browser storage.\r
+ @param ConfigRequest The pointer to the Request element.\r
+\r
+**/\r
+VOID\r
+RemoveConfigRequest (\r
+ BROWSER_STORAGE *Storage,\r
+ CHAR16 *ConfigRequest\r
+ )\r
+{\r
+ CHAR16 *RequestElement;\r
+ CHAR16 *NextRequestElement;\r
+ CHAR16 *SearchKey;\r
+\r
+ //\r
+ // No request element in it, just return.\r
+ //\r
+ if (ConfigRequest == NULL) {\r
+ return;\r
+ }\r
+\r
+ if (Storage->Type == EFI_HII_VARSTORE_NAME_VALUE) {\r
+ //\r
+ // "&Name1&Name2" section for EFI_HII_VARSTORE_NAME_VALUE storage\r
+ //\r
+ SearchKey = L"&";\r
+ } else {\r
+ //\r
+ // "&OFFSET=####&WIDTH=####" section for EFI_HII_VARSTORE_BUFFER storage\r
+ //\r
+ SearchKey = L"&OFFSET";\r
+ }\r
+\r
+ //\r
+ // Find SearchKey storage\r
+ //\r
+ if (Storage->Type == EFI_HII_VARSTORE_NAME_VALUE) {\r
+ RequestElement = StrStr (ConfigRequest, L"PATH");\r
+ ASSERT (RequestElement != NULL);\r
+ RequestElement = StrStr (RequestElement, SearchKey); \r
+ } else {\r
+ RequestElement = StrStr (ConfigRequest, SearchKey);\r
+ }\r
+\r
+ while (RequestElement != NULL) {\r
+ //\r
+ // +1 to avoid find header itself.\r
+ //\r
+ NextRequestElement = StrStr (RequestElement + 1, SearchKey);\r
+\r
+ //\r
+ // The last Request element in configRequest string.\r
+ //\r
+ if (NextRequestElement != NULL) {\r
+ //\r
+ // Replace "&" with '\0'.\r
+ //\r
+ *NextRequestElement = L'\0';\r
+ }\r
+\r
+ RemoveElement (Storage, RequestElement);\r
+\r
+ if (NextRequestElement != NULL) {\r
+ //\r
+ // Restore '&' with '\0' for later used.\r
+ //\r
+ *NextRequestElement = L'&';\r
+ }\r
+\r
+ RequestElement = NextRequestElement;\r
+ }\r
+\r
+ //\r
+ // If no request element remain, just remove the ConfigRequest string.\r
+ //\r
+ if (StrCmp (Storage->ConfigRequest, Storage->ConfigHdr) == 0) {\r
+ FreePool (Storage->ConfigRequest);\r
+ Storage->ConfigRequest = NULL;\r
+ Storage->SpareStrLen = 0;\r
+ }\r
+}\r
+\r
+/**\r
+ Base on the current formset info, clean the ConfigRequest string in browser storage.\r
+\r
+ @param FormSet Pointer of the FormSet\r
+\r
+**/\r
+VOID\r
+CleanBrowserStorage (\r
+ IN OUT FORM_BROWSER_FORMSET *FormSet\r
+ )\r
+{\r
+ LIST_ENTRY *Link;\r
+ FORMSET_STORAGE *Storage;\r
+ CHAR16 *ConfigRequest;\r
+\r
+ Link = GetFirstNode (&FormSet->StorageListHead);\r
+ while (!IsNull (&FormSet->StorageListHead, Link)) {\r
+ Storage = FORMSET_STORAGE_FROM_LINK (Link);\r
+ Link = GetNextNode (&FormSet->StorageListHead, Link);\r
+\r
+ if (Storage->BrowserStorage->Type == EFI_HII_VARSTORE_EFI_VARIABLE_BUFFER) {\r
+ if (Storage->ConfigRequest == NULL || Storage->BrowserStorage->ConfigRequest == NULL) {\r
+ continue;\r
+ }\r
+\r
+ ConfigRequest = FormSet->QuestionInited ? Storage->ConfigRequest : Storage->ConfigElements;\r
+ RemoveConfigRequest (Storage->BrowserStorage, ConfigRequest);\r
+ } else if (Storage->BrowserStorage->Type == EFI_HII_VARSTORE_BUFFER ||\r
+ Storage->BrowserStorage->Type == EFI_HII_VARSTORE_NAME_VALUE) {\r
+ if (Storage->BrowserStorage->ConfigRequest != NULL) { \r
+ FreePool (Storage->BrowserStorage->ConfigRequest);\r
+ }\r
+ Storage->BrowserStorage->Initialized = FALSE;\r
+ }\r
+ }\r
+}\r
+\r
+/**\r
+ Check whether current element in the ConfigReqeust string.\r
+\r
+ @param BrowserStorage Storage which includes ConfigReqeust.\r
+ @param RequestElement New element need to check.\r
+\r
+ @retval TRUE The Element is in the ConfigReqeust string.\r
+ @retval FALSE The Element not in the configReqeust String.\r
+\r
+**/\r
+BOOLEAN \r
+ElementValidation (\r
+ BROWSER_STORAGE *BrowserStorage,\r
+ CHAR16 *RequestElement\r
+ )\r
+{\r
+ return StrStr (BrowserStorage->ConfigRequest, RequestElement) != NULL ? TRUE : FALSE;\r
+}\r
+\r
+/**\r
+ Append the Request element to the Config Request.\r
+\r
+ @param ConfigRequest Current ConfigRequest info.\r
+ @param SpareStrLen Current remain free buffer for config reqeust.\r
+ @param RequestElement New Request element.\r
+\r
+**/\r
+VOID\r
+AppendConfigRequest (\r
+ IN OUT CHAR16 **ConfigRequest,\r
+ IN OUT UINTN *SpareStrLen,\r
+ IN CHAR16 *RequestElement\r
+ )\r
+{\r
+ CHAR16 *NewStr;\r
+ UINTN StringSize;\r
+ UINTN StrLength;\r
+\r
+ StrLength = StrLen (RequestElement);\r
+\r
+ //\r
+ // Append <RequestElement> to <ConfigRequest>\r
+ //\r
+ if (StrLength > *SpareStrLen) {\r
+ //\r
+ // Old String buffer is not sufficient for RequestElement, allocate a new one\r
+ //\r
+ StringSize = (*ConfigRequest != NULL) ? StrSize (*ConfigRequest) : sizeof (CHAR16);\r
+ NewStr = AllocateZeroPool (StringSize + CONFIG_REQUEST_STRING_INCREMENTAL * sizeof (CHAR16));\r
+ ASSERT (NewStr != NULL);\r
+\r
+ if (*ConfigRequest != NULL) {\r
+ CopyMem (NewStr, *ConfigRequest, StringSize);\r
+ FreePool (*ConfigRequest);\r
+ }\r
+ *ConfigRequest = NewStr;\r
+ *SpareStrLen = CONFIG_REQUEST_STRING_INCREMENTAL;\r
+ }\r
+\r
+ StrCat (*ConfigRequest, RequestElement);\r
+ *SpareStrLen -= StrLength;\r
+}\r
+\r
+/**\r
+ Adjust the config request info, remove the request elements which already in AllConfigRequest string.\r
+\r
+ @param Storage Form set Storage.\r
+\r
+ @retval TRUE Has element not covered by current used elements, need to continue to call ExtractConfig\r
+ @retval FALSE All elements covered by current used elements.\r
+\r
+**/\r
+BOOLEAN \r
+ConfigRequestAdjust (\r
+ IN FORMSET_STORAGE *Storage\r
+ )\r
+{\r
+ CHAR16 *RequestElement;\r
+ CHAR16 *NextRequestElement;\r
+ CHAR16 *RetBuf;\r
+ UINTN SpareBufLen;\r
+ CHAR16 *SearchKey;\r
+ BOOLEAN RetVal;\r
+\r
+ SpareBufLen = 0;\r
+ RetBuf = NULL;\r
+ RetVal = FALSE;\r
+\r
+ if (Storage->BrowserStorage->ConfigRequest == NULL) {\r
+ Storage->BrowserStorage->ConfigRequest = AllocateCopyPool (StrSize (Storage->ConfigRequest), Storage->ConfigRequest);\r
+ if (Storage->ConfigElements != NULL) {\r
+ FreePool (Storage->ConfigElements);\r
+ }\r
+ Storage->ConfigElements = AllocateCopyPool (StrSize (Storage->ConfigRequest), Storage->ConfigRequest);\r
+ return TRUE;\r
+ }\r
+\r
+ if (Storage->BrowserStorage->Type == EFI_HII_VARSTORE_NAME_VALUE) {\r
+ //\r
+ // "&Name1&Name2" section for EFI_HII_VARSTORE_NAME_VALUE storage\r
+ //\r
+ SearchKey = L"&";\r
+ } else {\r
+ //\r
+ // "&OFFSET=####&WIDTH=####" section for EFI_HII_VARSTORE_BUFFER storage\r
+ //\r
+ SearchKey = L"&OFFSET";\r
+ }\r
+\r
+ //\r
+ // Prepare the config header.\r
+ // \r
+ RetBuf = AllocateCopyPool(StrSize (Storage->BrowserStorage->ConfigHdr), Storage->BrowserStorage->ConfigHdr);\r
+ ASSERT (RetBuf != NULL);\r
+\r
+ //\r
+ // Find SearchKey storage\r
+ //\r
+ if (Storage->BrowserStorage->Type == EFI_HII_VARSTORE_NAME_VALUE) {\r
+ RequestElement = StrStr (Storage->ConfigRequest, L"PATH");\r
+ ASSERT (RequestElement != NULL);\r
+ RequestElement = StrStr (RequestElement, SearchKey); \r
+ } else {\r
+ RequestElement = StrStr (Storage->ConfigRequest, SearchKey);\r
+ }\r
+\r
+ while (RequestElement != NULL) {\r
+ //\r
+ // +1 to avoid find header itself.\r
+ //\r
+ NextRequestElement = StrStr (RequestElement + 1, SearchKey);\r
+\r
+ //\r
+ // The last Request element in configRequest string.\r
+ //\r
+ if (NextRequestElement != NULL) {\r
+ //\r
+ // Replace "&" with '\0'.\r
+ //\r
+ *NextRequestElement = L'\0';\r
+ }\r
+ \r
+ if (!ElementValidation (Storage->BrowserStorage, RequestElement)) {\r
+ //\r
+ // Add this element to the Storage->BrowserStorage->AllRequestElement.\r
+ //\r
+ AppendConfigRequest(&Storage->BrowserStorage->ConfigRequest, &Storage->BrowserStorage->SpareStrLen, RequestElement);\r
+ AppendConfigRequest (&RetBuf, &SpareBufLen, RequestElement);\r
+ RetVal = TRUE;\r
+ }\r
+\r
+ if (NextRequestElement != NULL) {\r
+ //\r
+ // Restore '&' with '\0' for later used.\r
+ //\r
+ *NextRequestElement = L'&';\r
+ }\r
+\r
+ RequestElement = NextRequestElement;\r
+ }\r
+\r
+ if (RetVal) {\r
+ if (Storage->ConfigElements != NULL) {\r
+ FreePool (Storage->ConfigElements);\r
+ }\r
+ Storage->ConfigElements = RetBuf;\r
+ } else {\r
+ FreePool (RetBuf);\r
+ }\r
+\r
+ return RetVal;\r
+}\r
+\r
+/**\r
+\r
+ Base on ConfigRequest info to get default value for current formset. \r
+\r
+ ConfigRequest info include the info about which questions in current formset need to \r
+ get default value. This function only get these questions default value.\r
+ \r
+ @param FormSet FormSet data structure.\r
+ @param Storage Storage need to update value.\r
+ @param ConfigRequest The config request string.\r
+\r
+**/\r
+VOID\r
+GetDefaultForFormset (\r
+ IN FORM_BROWSER_FORMSET *FormSet,\r
+ IN BROWSER_STORAGE *Storage,\r
+ IN CHAR16 *ConfigRequest\r
+ )\r
+{\r
+ UINT8 *BackUpBuf;\r
+ UINTN BufferSize;\r
+ LIST_ENTRY BackUpList;\r
+ NAME_VALUE_NODE *Node;\r
+ LIST_ENTRY *Link;\r
+ LIST_ENTRY *NodeLink;\r
+ NAME_VALUE_NODE *TmpNode;\r
+ EFI_STATUS Status;\r
+ EFI_STRING Progress;\r
+ EFI_STRING Result;\r
+\r
+ BackUpBuf = NULL;\r
+ InitializeListHead(&BackUpList);\r
+\r
+ //\r
+ // Back update the edit buffer.\r
+ // \r
+ if (Storage->Type == EFI_HII_VARSTORE_BUFFER || \r
+ (Storage->Type == EFI_HII_VARSTORE_EFI_VARIABLE_BUFFER)) {\r
+ BackUpBuf = AllocateCopyPool (Storage->Size, Storage->EditBuffer);\r
+ ASSERT (BackUpBuf != NULL);\r
+ } else if (Storage->Type == EFI_HII_VARSTORE_NAME_VALUE) {\r
+ Link = GetFirstNode (&Storage->NameValueListHead);\r
+ while (!IsNull (&Storage->NameValueListHead, Link)) {\r
+ Node = NAME_VALUE_NODE_FROM_LINK (Link);\r
+ Link = GetNextNode (&Storage->NameValueListHead, Link);\r
+\r
+ //\r
+ // Only back Node belong to this formset.\r
+ //\r
+ if (StrStr (Storage->ConfigRequest, Node->Name) == NULL) {\r
+ continue;\r
+ }\r
+\r
+ TmpNode = AllocateCopyPool (sizeof (NAME_VALUE_NODE), Node);\r
+ TmpNode->Name = AllocateCopyPool (StrSize(Node->Name) * sizeof (CHAR16), Node->Name);\r
+ TmpNode->EditValue = AllocateCopyPool (StrSize(Node->EditValue) * sizeof (CHAR16), Node->EditValue);\r
+\r
+ InsertTailList(&BackUpList, &TmpNode->Link);\r
+ }\r
+ }\r
+\r
+ //\r
+ // Get default value.\r
+ //\r
+ ExtractDefault (FormSet, NULL, EFI_HII_DEFAULT_CLASS_STANDARD, FormSetLevel, GetDefaultForStorage, Storage, TRUE);\r
+\r
+ //\r
+ // Update the question value based on the input ConfigRequest.\r
+ //\r
+ if (Storage->Type == EFI_HII_VARSTORE_BUFFER || \r
+ (Storage->Type == EFI_HII_VARSTORE_EFI_VARIABLE_BUFFER)) {\r
+ ASSERT (BackUpBuf != NULL);\r
+ BufferSize = Storage->Size;\r
+ Status = mHiiConfigRouting->BlockToConfig(\r
+ mHiiConfigRouting,\r
+ ConfigRequest,\r
+ Storage->EditBuffer,\r
+ BufferSize,\r
+ &Result,\r
+ &Progress\r
+ );\r
+ ASSERT_EFI_ERROR (Status);\r
+ \r
+ Status = mHiiConfigRouting->ConfigToBlock (\r
+ mHiiConfigRouting,\r
+ Result,\r
+ BackUpBuf,\r
+ &BufferSize,\r
+ &Progress\r
+ );\r
+ ASSERT_EFI_ERROR (Status);\r
+\r
+ if (Result != NULL) {\r
+ FreePool (Result);\r
+ }\r
+ \r
+ CopyMem (Storage->EditBuffer, BackUpBuf, Storage->Size);\r
+ FreePool (BackUpBuf);\r
+ } else if (Storage->Type == EFI_HII_VARSTORE_NAME_VALUE) {\r
+ //\r
+ // Update question value, only element in ConfigReqeust will be update.\r
+ //\r
+ Link = GetFirstNode (&BackUpList);\r
+ while (!IsNull (&BackUpList, Link)) {\r
+ Node = NAME_VALUE_NODE_FROM_LINK (Link);\r
+ Link = GetNextNode (&BackUpList, Link);\r
+\r
+ if (StrStr (ConfigRequest, Node->Name) != NULL) {\r
+ continue;\r
+ }\r
+\r
+ NodeLink = GetFirstNode (&Storage->NameValueListHead);\r
+ while (!IsNull (&Storage->NameValueListHead, NodeLink)) {\r
+ TmpNode = NAME_VALUE_NODE_FROM_LINK (NodeLink);\r
+ NodeLink = GetNextNode (&Storage->NameValueListHead, NodeLink);\r
+ \r
+ if (StrCmp (Node->Name, TmpNode->Name) != 0) {\r
+ continue;\r
+ }\r
+\r
+ FreePool (TmpNode->EditValue);\r
+ TmpNode->EditValue = AllocateCopyPool (StrSize(Node->EditValue) * sizeof (CHAR16), Node->EditValue);\r
+\r
+ RemoveEntryList (&Node->Link);\r
+ FreePool (Node->EditValue);\r
+ FreePool (Node->Name);\r
+ FreePool (Node);\r
+ }\r
+ }\r
+\r
+ //\r
+ // Restore the Name/Value node.\r
+ // \r
+ Link = GetFirstNode (&BackUpList);\r
+ while (!IsNull (&BackUpList, Link)) {\r
+ Node = NAME_VALUE_NODE_FROM_LINK (Link);\r
+ Link = GetNextNode (&BackUpList, Link);\r
+ \r
+ //\r
+ // Free this node.\r
+ //\r
+ RemoveEntryList (&Node->Link);\r
+ FreePool (Node->EditValue);\r
+ FreePool (Node->Name);\r
+ FreePool (Node);\r
+ }\r
+ }\r
+}\r
+\r